- CHAPTER 3 -
The Basic Input/Output System (BIOS) is responsible for
the lowest level of communications between the operating system
and hardware devices. This chapter will document the operating
system functions of the BIOS and other system level operations.
Upon a cold or warm boot, microprocessors in the 680x0 series
load the initial supervisor stack pointer from the first longword
in memory ($0) and begin execution at the PC found in the second
longword ($4). The location this points to is the base initialization
point for Atari computers.
Every Atari computer follows a predefined set of steps to accomplish
system initialization. The following illustrates these steps leaving
out some hardware initialization which is specific to the particular
computer line (ST, TT, Falcon, etc.).
The Interrupt Priority Level (IPL) is set to 7 and the OS switches
to supervisor mode.
A RESET instruction is executed to reset external hardware devices.
The presence of a diagnostic cartridge is determined. If one
is inserted, it is JMP'ed to with a return address in register
A6.
If running on a 68030, the CACR, VBR, TC, TT0, and TT1 registers
are initialized.
If a floating-point coprocessor is present it is initialized.
If the memvalid ($420), memval2 ($43A), and memval3
($51A) system variables are all valid, a warm boot is assumed
and the memory controller is initialized with the value from memcntrl
($424).
The initial color palette registers are loaded and the screen
base is initialized to $100000.
Memory is sized if it wasn't from a previous reset.
Magic numbers are stored in low memory to indicate the successful
sizing and initialization of memory.
System variables and the cookie jar are initialized.
The BIOS initialization point is executed.
Installed cartridges of type 2 are executed.
The screen resolution is programmed.
Installed cartridges of type 0 are executed.
Interrupts are enabled by lowering the IPL to 3.
Installed cartridges of type 1 are executed.
The GEMDOS initialization point is executed.
On systems running TOS 2.06 or TOS 3.06 and above,
the Fuji logo is displayed and a memory test and hard disk spin-up
sequence is executed.
If at least one floppy drive is attached to the system, the first
sector of the first floppy drive is loaded, and if executable,
it is called.
If at least one hard disk or other media is attached to the system,
the first sector of each is loaded in succession until one with
an executable sector is found or each has been tried.
If a hard disk sector was found that was executable, it is executed.
The text cursor is enabled.
All "\AUTO\*.PRG" files found on the boot disk are
executed.
If _cmdload ($482) is 0 then an environment string is
created and the AES is launched, otherwise "\COMMAND.PRG"
is loaded.
If the AES ever terminates, the system is reset and system
initialization begins again.
The address of the start of operating system is stored in the
system variable _sysbase ($4F2). The beginning of the operating
system contains a table with contents as follows:
BIOS
Overview
System Startup
OS Header
|
| Contents |
---|---|---|
|
| os_entry: BRA to reset hander (shadowed at $0). |
|
| os_version: TOS version number. The high byte is the major revision number, and the low byte is the minor revision number. |
|
| reseth: Pointer to the system reset handler. |
|
| os_beg: Base address of the OS (same as _sysbase). |
|
| os_end: Address of the first byte of RAM not used by the operating system. |
|
| os_rsv1: Reserved |
|
| os_magic: Pointer to the GEM Memory Usage Parameter Block (MUPB). See below for more information. |
|
| os_date: Date of system build ($YYYYMMDD). |
|
| os_conf: OS Configuration Bits. See below for more information. |
|
| os_dosdate: GEMDOS format date of system build. |
|
| p_root: Pointer to a system variable containing the address of the GEMDOS memory pool structure. This entry is available as of TOS 1.2. The location pointed to by this value should never be modified by an application. |
|
| p_kbshift: Pointer to a system variable which contains the address of the system keyboard shift state variable. See below for more information. This entry is available as of TOS 1.02. This location should never be modified by an application. |
|
| p_run: Pointer to a system variable which contains the address of the currently executing GEMDOS process. See below for more information. This entry is available as of TOS 1.02. The information pointed to by this variable should never be modified by an application. |
|
| p_rsv2: Reserved |
Some versions of AHDI (the Atari Hard Disk Interface) contain
a bug which copies the system header to RAM and then corrupts
some portions of it. The following 'C' structure definition defines
the OSHEADER structure. The function GetROMSysbase() can
be used to return an OSHEADER pointer to the code in ROM.
GetROMSysbase() will execute properly in either user or supervisor
mode.
typedef struct _osheader
{
UWORD os_entry;
UWORD os_version;
VOID *reseth;
struct _osheader *os_beg;
char *os_end;
char *os_rsv1;
char *os_magic;
LONG os_date;
UWORD os_conf;
UWORD os_dosdate;
/* Available as of TOS 1.02 */
char **p_root;
char **p_kbshift;
char **p_run;
char *p_rsv2;
} OSHEADER;
#define _sysbase ((OSHEADER **)0x4F2)
OSHEADER *
GetROMSysbase( VOID )
{
OSHEADER *osret;
char *savesp = (Super(SUP_INQUIRE) ? NULL : Super(SUP_SET));
osret = (*_sysbase)->os_beg;
if( savesp )
Super( savesp );
return osret;
}
OS Configuration Bits
| Country |
---|---|
| USA |
| Germany |
| France |
| United Kingdom |
| Spain |
| Italy |
| Sweden |
| Switzerland (French) |
| Switzerland (German) |
| Turkey |
| Finland |
| Norway |
| Denmark |
| Saudi Arabia |
| Holland |
| Czechoslovakia |
| Hungary |
| All countries are supported. As of TOS 4.0 the OS is compiled with text for all languages and switches between them based on the country code stored in non-volatile RAM. Use the '_AKP' cookie to determine the actual language in use. |
The pointer at offset $14 in the OS header points to the GEM
Memory Usage Parameter Block which is defined as follows:
GEM is only launched at system startup if gem_magic
is $87654321. The XBIOS call Puntaes() also uses
this information to restart the operating system after clearing
GEM (only if disk-based). It verifies that gem_magic
was valid and that GEM was in RAM, then it modifies gem_magic
and restarts the operating system.
The OS header entry p_kbshift provides a method of reading
the state of the keyboard shift state variables more quickly than
with Kbshift(). This header entry did not exist in TOS
1.0. The following code provides an acceptable method for accessing
this variable in all TOS versions:
The OS header entry _p_run is used to locate the
of the basepage of the currently running process. This entry has
only existed as of TOS 1.02 and should never be modified.
The following routine returns the address of the basepage of the
currently running process in all versions of TOS:
The 'Cookie Jar' is a structure in memory containing entries called
'cookies' which are placed in the 'jar' by the operating system
or Terminate and Stay Resident (TSR) applications. Applications
can test for the presence of a cookie to determine the presence
of a hardware device or system feature.
The location of the cookie jar is determined by the address contained
in the system variable _p_cookies ($5A0). If no cookie
jar has been allocated yet, this entry will contain NULL
(0).
The variable _p_cookies points to multiple COOKIE
structures as defined below:
The structure member cookie contains a value that hopefully
uniquely identifies the cookie. cookie values are 4-byte
packed longword identifiers (often a 4 letter ASCII code word).
Entries with the high byte equal to $5F, the underscore character,
are reserved for use by Atari.
The structure member value may contain any value meaningful
to an application or no value at all. In some cases a cookie won't
have a meaningful value and its presence simply signals the existence
of another process or system feature. TSR's often use value
to store a pointer to an internal structure. The operating system
uses cookies to signal the availability of hardware devices or
system features.
The end of the cookie jar is signaled with a final entry with
the value for cookie equaling NULL. The value
entry for this final cookie contains the number of entries possible
without reallocating the jar.
The following code may be used to find a cookie in the cookie
jar. It returns 0 if an error occurred or 1 if successful. If
p_value is non-NULL on entry, the address it points
to will be filled in with the value of the cookie.
Only TSR programs should place cookies in the cookie jar. The
cookie these programs place should either signal a function provided
by the TSR or the presence of an expansion device. A CPX, desk
accessory, or standard application should not place cookies in
the jar.
To place a cookie, the TSR must first locate the current location
of the cookie jar. It is possible that a cookie jar does not exist
( _p_cookies == 0 ). In that case, a new
jar should be allocated.
In most instances, the cookie jar should be allocated in increments
of 8 slots (though it is not a requirement). In addition, if the
process installs a new cookie jar in a TOS version lower
than 1.06 it is also the processes responsibility to remove it
upon a warm reset. Calling the following code after installing
the cookie jar for the first time will ensure that the cookie
jar pointer is properly reset on a warm boot.
After determining the location of the cookie jar, the application
should search for the first empty slot in the jar by looking for
a NULL in the cookie field of a slot. Next, the
application must determine if this is the last slot in the jar
by comparing the entry in the value field of the current
cookie to the number of the actual slot you are comparing. For
instance, if you have found NULL as the value for cookie
in slot 16 and value is equal to 16, the jar is full and
must be reallocated.
If the slot found is not the last one, the application can simply
copy the current slot to the next slot and insert its own cookie.
If the jar must be reallocated, you should allocate enough memory
to increase the size of the cookie jar, copy the old entries to
the new jar, insert your entry as the last cookie in the jar,
and finally terminate the jar with a cookie containing a NULL
and the new number of slots you have allocated.
Though not mentioned previously, it is also advisable to ensure
that your cookie isn't already in the jar before placing it to
avoid two cookies for multiple executions of the same application
to appear.
As of TOS 1.06, the operating system will place several
cookies in the cookie jar to inform applications of certain operating
system and hardware capabilities as follows:
GEM Memory Usage Parameter Block
typedef struct
{
/* $87654321 if GEM present */
LONG gem_magic;
/* End address of OS RAM usage */
LONG gem_end;
/* Execution address of GEM */
LONG gem_entry;
} MUPB;
Keyboard Shift State Variable
#define Kbstate *p_kbshift
char *p_kbshift;
VOID
init_kbshift( VOID )
{
/* See above for GetROMSysbase() definition. */
OSHEADER *os = GetROMSysbase();
if ( os->os_version == 0x0100)
p_kbshift = (char *)0xE1BL;
else
p_kbshift = *(char **)os->p_kbshift;
}
Currently Running Process
#define SPAIN 4
typedef long PID
PID *
get_run()
{
OSHEADER *os = GetROMSysbase();
if(os->os_version < 0x0102)
{
if(( os->os_conf >> 1 ) == SPAIN)
return (PID *)0x873C;
else
return (PID *)0x602C;
}
else
return (PID *)(os->p_run);
}
The Cookie Jar
Overview
Structure
typedef struct
{
LONG cookie;
LONG value;
} COOKIE;
Searching for a Cookie
WORD
getcookie( target, p_value )
LONG target;
LONG *p_value;
{
char *oldssp;
COOKIE *cookie_ptr;
oldssp = (Super(SUP_INQUIRE) ? NULL : Super(1L));
cookie_ptr = *(COOKIE **)0x5A0;
if(oldssp)
Super( oldssp );
if(cookie_ptr != NULL)
{
do
{
if(cookie_ptr->cookie == target)
{
if(p_value != NULL)
*p_value = cookie_ptr->value;
return 1;
}
} while((cookie_ptr++)->cookie != 0L);
}
return 0;
}
Placing a Cookie
RESMAGIC equ $31415926
_resvalid equ $426
_resvector equ $42A
_p_cookies equ $5A0
.globl _unjar
_unjar: move.l _resvalid,valsave
move.l _resvector,vecsave
move.l #reshand,_resvector
move.l #RESMAGIC,_resvalid
rts
reshand: clr.l _p_cookies
move.l vecsave,_resvector
move.l valsave,_resvalid
jmp (a6)
.bss
vecsave: .ds.l 1
valsave .ds.l 1
System Cookies
| value |
---|---|
| The low WORD of the CPU cookie contains a number representing the processor installed in the system as follows: Value Processor
0 68000 10 68010 20 68020 30 68030 |
| This cookie represents the revision of the video shifter present. The low WORD represents the minor revision number and the high WORD represents the major revision number. Currently valid values are: Major Minor Shifter
0 0 ST 1 0 STe 2 0 TT030 3 0 Falcon030 |
| This cookie identifies the presence of floating-point math capabilities in the system. A non-zero low WORD indicates the presence of software floating point support (no specific values have yet been assigned). The high WORD indicates the type of coprocessor currently connected to the system as follows: Value Meaning
0 No FPU is installed. 1 SFP004 2 68881 or 68882 3 68881 or 68882 and SFP004 4 68881 5 68881 and SFP004 6 68882 7 68882 and SFP004 8 68040 Internal 9 68040 Internal and SFP004 |
| This cookie indicates the capability of the currently connected floppy drive. The lowest three bytes is a code indicating the origin of the unit ('ATC' is an Atari unit). The upper byte is a value indicating the highest density floppy present as follows: Value Density
0 360 Kb/ 720 Kb 1 1.44 Mb 2 2.88 Mb |
| This cookie contains a bitmap of sound features available to the system as follows: Bit Feature
0 GI Sound Chip (PSG) 1 Stereo 8-bit Playback 2 DMA Record (w/XBIOS) 3 16-bit CODEC 4 DSP |
| This cookie indicates the machine type with the major revision number in the high WORD and the minor revision number in the low WORD as follows: Major Minor Shifter
0 0 ST 1 0 STe 1 8 ST Book 1 16 Mega STe 2 0 TT030 3 0 Falcon030 |
| On machines that contain internal configuration dip switches, this value specifies their positions as a bitmap. Dip switches are generally used to indicate the presence of additional hardware which will be represented by other cookies. |
| This cookie is present when alternative RAM is present. It points to a 64k buffer that may be used by DMA device drivers to transfer memory between alternative RAM and ST RAM for DMA operations. |
| The presence of this cookie indicates that file and record locking extensions to GEMDOS exist. The value field is a version number currently undefined. |
| This cookie indicates the presence of networking software. The cookie value points to a structure which gives manufacturer and version information as follows:
struct netinfo { LONG publisher; LONG version; }; |
| This cookie defines the currently configured date and time format, Bits #0-7 contain the ASCII code of the date separator. Bits #8-11 contain a value indicating the date display format as follows: Value Meaning
0 MM-DD-YY 1 DD-MM-YY 2 YY-MM-DD 3 YY-DD-MMBits #12-15 contain a value indicating the time format as follows: Value Meaning 0 12 hour 1 24 hourNote: The value of this cookie does not affect any of the internal time functions. It is intended for informational use by applications only. |
| This cookie indicates the presence of an Advanced Keyboard Processor. The high word of this cookie is currently reserved. The low word indicates the language currently used by TOS for keyboard interpretation and alerts. See the explanation for the country code in the OS header earlier in this chapter for valid values.If this cookie is present on TOS 5.0 and higher then the system supports soft-loaded keyboard tables. |
| This cookie indicates the presence of FSM or SpeedoGDOS. Its value field is a pointer to a structure as follows:typedef struct
{ LONG gdos_type; UWORD version; WORD quality; } GDOS_INFO;The gdos_type field determines the variety of GDOS. '_FSM' represents Imagen font-based FSM whereas '_SPD' represents Bitstream font-based FSM. version specifies the current GDOS version.quality determines the output quality of v_updwk(). The default setting is QUAL_DEFAULT (0xFFFF) which causes the driver to use the setting last set in the driver configuration accessory or CPX. This default setting may be overridden by placing a value of QUAL_DRAFT (0x0000) or QUAL_FINAL (0x0001) at this location. The quality setting should be restored to QUAL_DEFAULT at the end of each print job. |
| This cookie indicates the presence of System Audio Manager and the XBIOS extensions it provides. The value field is currently reserved for internal use. |
| This cookie indicates the presence of MiNT (MultiTOS) and its value field is the current version number (ex: MiNT 1.02 has a value field of 0x00000102). |
The BIOS provides access to six default devices (numbered 0-5). In addition, TOS 2.00 provides the ability to add extra devices with the XBIOS Bconmap() function (see the XBIOS overview for more information). Device assignments higher than device five are dependent upon the machine and any third-party enhancements. The following list indicates the device assignments which remain constant:
Name |
|
| Meaning |
---|---|---|---|
DEV_PRINTER |
|
|
Centronics Parallel Port |
DEV_AUX |
|
|
Default Serial Device (this device number could actually refer to any serial device connected to the system depending on which was mapped with Bconmap() ) |
DEV_CON |
|
|
Console (screen device) |
DEV_MIDI |
|
|
MIDI Ports |
DEV_IKBD |
|
|
Intelligent Keyboard Controller |
DEV_RAW |
|
|
Console (no interpretation) |
Two methods are provided for outputting characters to the screen.
Output via BIOS device #2 subjects character codes to interpretation.
Codes such as a carriage return (ASCII 13), line feed (ASCII 10),
TAB (ASCII 9), CTRL-G (ASCII 7), and ESCAPE (ASCII 27) are interpreted
as special cases and handled specially.
Output via BIOS device #5 causes all characters to be output
literally to the screen without interpretation.
The Atari console device contains emulation code compatible with
the VT52 standard. Special escapes may be used to manipulate the
cursor and create text effects.
To send an escape sequence, one of the following codes (and possibly
additional characters) must be sent following the ESCAPE character
(ASCII 27):
The Console Device
The VT-52 Emulator
|
| Effect |
---|---|---|
|
| Move the cursor up one line. If the cursor is on the top line this does nothing. |
|
| Move the cursor down one line. If the cursor is on the bottom line this does nothing. |
|
| Move the cursor right one line. If the cursor is on the far right of the screen this does nothing. |
|
| Move the cursor left one line. If the cursor is on the far left of the screen this does nothing. |
|
| Clear the screen and place the cursor at the upper-left corner. |
|
| Move the cursor to the upper-left corner of the screen. |
|
| Move the cursor up one line. If the cursor is on the top line, the screen scrolls down one line. |
|
| Erase the screen downwards from the current position of the cursor. |
|
| Clear the current line to the right from the cursor position. |
|
| Insert a line by scrolling all lines at the cursor position down one line. |
|
| Delete the current line and scroll lines below the cursor position up one line. |
|
| Position the cursor at the coordinates given by the following two codes. The screen starts with coordinates ( 32, 32 ) at the upper-left of the screen. Coordinates should be presented in reverse order, Y and then X. |
|
| This code is followed by a character from which the lowest four bits determine a new text foreground color. |
|
| This code is followed by a character from which the lowest four bits determine a new text background color. |
|
| Erase the screen from the upper-left to the current cursor position. |
|
| Enable the cursor. |
|
| Disable the cursor. |
|
| Save the current cursor position. (Only implemented as of TOS 1.02) |
|
| Restore the current cursor position. (Only implemented as of TOS 1.02) |
|
| Erase the current line and place the cursor at the far left. |
|
| Erase the current line from the far left to the current cursor position. |
|
| Enable inverse video. |
|
| Disable inverse video. |
|
| Enable line wrap. |
|
| Disable line wrap. |
The BIOS function Mediach() returns the current
media-change status of the drive specified. This state is used
to determine if a disk has been changed in removable media drives
(floppies, removable hard drives, etc.
The Getbpb() incorrectly resets the media change state.
Failure to properly reset this state after calling Getbpb()
can cause data loss. The function _mediach(), shown below,
forces the Mediach() function to return a 'definitely changed'
state and should always be called after calling Getbpb()
on removable media drives.
Shortly after a warm boot the OS will jump to the address contained
in the system variable resvector ($42A) if the value in
the system variable resvalid ($426) contains the magic
number $31415926. The OS will supply a return address to this
code segment in register A6 but the subroutine must not utilize
the stack as neither stack pointer will be valid.
If your process needs to do cleanup in the event of a warm reset
(see "Placing a Cookie" earlier in this chapter) the
following code installs a user routine to accomplish this.
As of TOS 1.06, the OS jumps through the address contained
in the system variable bell_hook ($5AC) to ring the system
bell. It is possible for a custom routine to hook into this vector
to alter the bell sound. The user routine may modify registers
D0-D2/A0-A2 and may chain to the old bell handler if desired.
It is also safe to make BIOS and XBIOS calls following
the procedure for calling from an interrupt (when not running
under MultiTOS). The routine should either jump to the
old handler or execute an RTS statement.
Similar to the system bell vector, another vector is called each
time a keyclick sound is generated. This vector is stored in system
variable kcl_hook ($5B0) and is entered with the keycode
(not the ASCII code) of the key struck in the low byte of D0.
Registers D1-D2/A0-A2 may be modified, however, all other registers
including D0 must be maintained. The replacement handler may either
chain to a new handler or RTS.
Applications may install custom routines which are called during
every vertical blank (approx. 50-72 times per second). The OS
performs several operations during the vertical blank as follows:
The system variable _frclock is incremented.
The system variable vblsem is tested. If 0, the vertical
blank handler exits immediately.
All registers are saved.
The system variable _vbclock is incremented.
If the system is currently in a high resolution video mode and
a low-resolution monitor is detected, the video resolution is
adjusted and the vector found at system variable swv_vec
is called.
The text cursor blink routine is called.
If a new palette has been selected since the last vertical blank,
it is loaded.
If a new screen base address has been selected since the last
vertical blank, it is selected.
Each of the "deferred" vertical blank routine handlers
is called.
If the system variable prt_cnt is greater than -1, the
vector at system variable scr_dump is called.
Saved registers are restored and processing continues.
To install a routine to be called as a "deferred" vertical
blank handler, you must inspect the list of handler vectors at
vblqueue for a NULL slot, replace it with your vector
and initialize the next slot to NULL. The system variable
nvbls indicates the number of slots pointed to by vblqueue.
If the vertical blank handler list is filled, you may allocate
a new area, copy the old list of handlers with your handler, and
update the pointer vblqueue and nvbls.
Many applications that add functionality to the system do so by
'hooking' themselves into one or more interrupt or pass-through
vectors (usually with Setexc()). Most vector handlers work
by executing the relevant code when the interrupt is called and
then calling the original vector handler. When several applications
handle one vector, a vector 'chain' is created. This chain makes
it difficult for debuggers or the process itself to 'unhook' itself
from the chain.
The XBRA protocol was designed so that processes that wish to
be able to unhook themselves may and so that debuggers can trace
the 'chain' of vector handlers. Following the protocal is simple.
Prior to the first instruction of the vector handler, insert three
longwords into the application as follows:
The following code example shows how to correctly use the XBRA
protocol in a routine designed to supplement the 680x0 TRAP #1
vector (GEMDOS):
The following 'C' function is an example of how to use the XBRA
protocol to unhook a vector handler from the XBRA chain. This
function will only work if all installed vector handlers follow
the XBRA protocol. It takes a Setexc() vector number and
an XBRA application id cookie as a parameter. It returns the address
of the routine that was unhooked or 0L if unsuccessful.
BIOS system functions are called via the TRAP #13 exception.
Function arguments are pushed onto the current stack (user or
supervisor) in reverse order followed by the function opcode.
The calling application is responsible for correctly resetting
the stack pointer after the call.
The BIOS may utilize registers D0-D2 and A0-A2 as scratch
registers and their contents should not be depended upon at the
completion of a call. In addition, the function opcode placed
on the stack will be modified. The BIOS places return codes in D0.
The following example for Bconout() illustrates calling
the BIOS from assembly language:
A 'C' binding for a generic BIOS handler would be as follows:
With the above code, you could easily design a 'C' macro to add
BIOS calls to your compiler as in the following example
for Bconout():
The BIOS is re-entrant to three levels, however there is
no error checking performed so interrupt handlers should avoid
intense BIOS usage. In addition, no disk or printer usage
should be attempted from the system timer interrupt, critical
error, or process-terminate handlers.
The BIOS and XBIOS are the only two OS sub-systems
which can be called from an interrupt handler. Precisely one
interrupt handler at a time may use the BIOS as shown in
the following code segment:
This method is not valid under MultiTOS.
/*
* _mediach(): force the media 'changed' state on a removable drive.
*
* Usage: errcode = _mediach( devno ) - returns 1 if an error occurs
*
* Inputs: devno - (0 = 'A:', 1 = 'B:', etc...)
*
*/
.globl _mediach
_mediach:
move.w 4(sp),d0
move.w d0,mydev
add.b #'A',d0
move.b d0,fspec ; Set drive spec for search
loop:
clr.l -(sp) ; Get supervisor mode, leave old SSP
move.w #$20,-(sp) ; and "Super" function code on stack.
trap #1
addq.l #6,sp
move.l d0,-(sp)
move.w #$20,-(sp)
move.l $472,oldgetbpb
move.l $47e,oldmediach
move.l $476,oldrwabs
move.l #newgetbpb,$472
move.l #newmediach,$47e
move.l #newrwabs,$476
; Fopen a file on that drive
move.w #0,-(sp)
move.l #fspec,-(sp)
move.w #$3d,-(sp)
trap #1
addq.l #8,sp
; Fclose the handle
tst.l d0
bmi.s noclose
move.w d0,-(sp)
move.w #$3e,-(sp)
trap #1
addq.l #4,sp
noclose:
moveq #0,d7
cmp.l #newgetbpb,$472 ; still installed?
bne.s done
move.l oldgetbpb,$472 ; Error, restore vectors.
move.l oldmediach,$47e
move.l oldrwabs,$476
trap #1 ; go back to user mode
addq.l #6,sp ; restore sp
moveq.l #1,d0 ; 1 = Error
rts
done:
trap #1 ; go back to user mode
addq.l #6,sp ; from stack left above
clr.l d0 ; No Error
rts
/*
* New Getbpb()...if it's the target device, uninstall vectors.
* In any case, call normal Getbpb().
*/
newgetbpb:
move.w mydev,d0
cmp.w 4(sp),d0
bne.s dooldg
move.l oldgetbpb,$472 ; Got target device so uninstall.
move.l oldmediach,$47e
move.l oldrwabs,$476
dooldg: move.l oldgetbpb,a0 ; Go to real Getbpb()
jmp (a0)
/*
* New Mediach()...if it's the target device, return 2. Else call old.
*/
newmediach:
move.w mydev,d0
cmp.w 4(sp),d0
bne.s dooldm
moveq.l #2,d0 ; Target device, return 2
rts
dooldm:
move.l oldmediach,a0 ; Call old
jmp (a0)
/*
* New Rwabs()...if it's the target device, return E_CHG (-14)
*/
newrwabs:
move.w mydev,d0
cmp.w 4(sp),d0
bne.s dooldr
moveq.l #-14,d0
rts
dooldr:
move.l oldrwabs,a0
jmp (a0)
.data
fspec: dc.b "X:\\X",0
mydev: ds.w 1
oldgetbpb: ds.l 1
oldmediach: ds.l 1
oldrwabs: ds.l 1
.end
BIOS Vectors
Reset Vector
_resvalid equ $426
_resvector equ $42A
RESMAGIC equ $31415926
.text
installres:
move.l _resvalid,oldvalid
move.l _resvector,oldvector
move.l #myresvec,_resvector
move.l #RESMAGIC,_resvalid
rts
myresvec:
*
* Insert user code here
*
move.l oldvector,_resvector
move.l oldvalid,_resvalid
jmp (a6)
.bss
oldvector: ds.l 1
oldvalid: ds.l 1
.end
System Bell Vector
System Keyclick Vector
Deferred Vertical Blank Handlers
The XBRA Protocol
instl_trap1:
move.l #my_trap1,-(sp)
move.w #VEC_GEMDOS,-(sp)
move.w #Setexc,-(sp)
trap #13
addq.l #8,sp
move.l d0,old_handler
rts
DC.L 'XBRA'
DC.L 'SDS1' ; Put your cookie here
old_handler DC.L 0
my_trap1:
movem.l d2-d7/a2-a6,-(sp)
;
; Your TRAP #1 handler goes here.
;
movem.l (sp)+,d2-d7/a2-a6
move.l old_handler,-(sp) ; Fake a return
rts ; to old code.
typedef struct xbra
{
LONG xbra_id;
LONG app_id;
VOID (*oldvec)();
} XBRA;
LONG
unhook_xbra( WORD vecnum, LONG app_id )
{
XBRA *rx;
LONG vecadr, *stepadr, lret = 0L;
char *savessp;
vecadr = Setexc( vecnum, VEC_INQUIRE );
rx = (XBRA *)(vecadr - sizeof( XBRA ));
/* Set supervisor mode for search just in case. */
savessp = Super( SUP_SET );
/* Special Case: Vector to remove is first in chain. */
if( rx->xbra_id == 'XBRA' && rx->app_id == app_id )
{
Setexc( vecnum, rx->oldvec );
return vecadr;
}
stepadr = (LONG *)&rx->oldvec;
rx = (XBRA *)((LONG)rx->oldvec - sizeof( XBRA ));
while( rx->xbra_id == 'XBRA' )
{
if( rx->app_id == app_id )
{
*stepadr = lret = (LONG)rx->oldvec;
break;
}
stepadr = (LONG *)&rx->oldvec;
rx = (XBRA *)((LONG)rx->oldvec - sizeof( XBRA ));
}
Super( savessp );
return lret;
}
BIOS Function Calling Procedure
move.w #char,-(sp)
move.w #dev,-(sp)
move.w #$03,-(sp)
trap #13
addq.l #6,sp
_bios:
; Save the return code from the stack
move.l (sp)+,trp13ret
trap #13
move.l trp13ret,-(sp)
rts
.bss
trp13ret:
.ds.l 1
#define Bconout( a ) bios( 0x02, a )
Calling the BIOS from an Interrupt
savptr equ $4A2
savamt equ $23*2
myhandler:
sub.l #savamt,savptr
; BIOS calls may be performed here
add.l #savamt,savptr
rte ; (or rts?)