home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989-1999 Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either expressed or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
-
- V1.3 KICKSTART AND AUTOBOOT
-
- by Bart Whitbrook
-
-
- The V1.3 Kickstart allows devices other than DF0: to serve as the
- Amiga system boot device. The purpose of this article is to show how
- you may implement your own autoboot device in a system-compatible
- fashion.
-
-
- Features
-
- Kickstart V1.3 is an incremental kickstart release. It is designed
- to maintain V1.2 compatability throughout, while adding autoboot from
- ROM-based expansion devices to the operating system.
-
- Automatic boot from any ROM-equipped expansion board is accomplished
- at cold-start time, before the DOS exists. This facility makes it
- possible to automatically boot from a hard disk without any floppy
- disks inserted. Likewise, it is possible to automatically boot from any
- device which supports the ROM protocol, such as nfs: over ethernet.
-
- Autoboot is implemented with the addition of the "romboot.library"
- to the ROM resident list, as well as conservative changes to the
- expansion.library, the dos.library and the strap.library. These
- changes have been carefully considered to be compatible with V1.2
- (release 33.180) so that developers should not have to recompile
- their code for software compatability. Without autoboot hardware,
- the V1.3 system will behave the same as the V1.2 release.
-
- Romboot.library functions are private at this time and are not
- needed by those developing autoboot expansion devices or drivers for
- such devices.
-
-
-
-
-
- Changes Since V1.2 Release (33.180)
- -----------------------------------
-
- Seven kickstart modules have changed since the release of KS_33.180:
-
- 1) expansion34.1 -- functional change (internal only)
- 2) graphics34.1 -- size change (no functional changes)
- 3) strap34.1 -- functional change (internal only)
- 4) romboot34.1 -- new module added to support autoboot
- 5) wb34.1 -- size change (no functional changes)
- 6) dos34.1 -- functional change (internal only)
- 7) intuition34.1 -- functional change (extended preferences only)
-
- Six include files have changed since the release of KS_33.180:
-
- 8) exec/nodes.h -- a new define added
- 9) exec/node.i -- a new define added
- 10) libraries/expansionbase.h -- now public
- 11) libraries/expansionbase.i -- now public
- 12) libraries/romboot_base.h -- a newly created include file
- 13) libraries/romboot_base.i -- a newly created include file
- 14) intuition/intuition.h -- split off preferences.h and screens.h
- 15) intuition/intuition.i -- split off preferences.i and screens.i
- 16) intuition/screen.h -- new include (was part of intuition.h)
- 17) intuition/screen.i -- new include (was part of intuition.i)
- 18) intuition/preferences.h -- new include (was part of intuition.h)
- 19) intuition/preferences.i -- new include (was part of intuition.i)
-
- Two library files have changed since the release of KS_33.180
-
- 20) amiga.lib -- addition of romboot.library
- 21) rom.lib -- addition of romboot.library
-
-
-
- How Auto Boot Works
- -------------------
-
- At system reboot time, and after exec is initialized, the expansion
- initialization procedure is called. As each expansion board in the
- system is configured, the expansion initialization routine checks to see
- whether this board has a valid ROM area associated with it. If such a
- ROM exists, its image is then copied into RAM memory. This ROM "image"
- contains rom/diagnostic routines, a driver associated with this expansion
- board, and the board's bootstrap routine to actually boot the appropriate
- operating system (normally, AmigaDOS).
-
- Once the ROM image is copied into RAM, the config routine calls
- the rom/diagnostic vector of the board to perform any patching and/or
- relocation of the ROM image to reflect its new location in RAM. This
- whole process is repeated for each auto-config board in the system.
-
- After the config routine, the other Resident Modules, except strap,
- are initialized (graphics, intuition, etc.). Now, a new V1.3 module,
- romboot, is called upon to create the romboot.library.
-
- During its initialization phase, the romboot.library searches
- through the ROM "images" for valid romtags. When a valid romtag is
- found, its rt_Init() function is called, to start up the driver
- associated with this board. If the driver is able to startup
- successfully, the driver will enqueue a node on the expansion.library's
- eb_MountList (see libraries/expansionbase.h).
-
- Finally, the Resident Module strap is initialized. Strap first
- checks to see if there is a valid boot disk in the internal drive, DF0:.
- If there is, strap overrides the autoboot and boots from DF0: instead.
-
- If there is no valid boot disk in DF0:, strap will try to autoboot
- by calling the romboot.library routine RomBoot(). For each appropriate
- node on the eb_Mountlist, RomBoot() will locate and execute the
- bootstrap routine for the board located in the associated ROM "image".
- If the board's bootstrap routine is successful, the system will come up
- using the board as the default boot device.
-
- If the autoboot fails, or if there are no appropriate nodes on the
- eb_MountList, strap will ask for the user to insert a valid Workbench
- disk, and will loop until its request is satisfied.
-
-
-
- The Details of Autoboot
- -----------------------
-
- AT EXPANSION CONFIGURATION TIME:
-
- As part of its initialization, the expansion.library auto-configs
- all the appropriate hardware boards in the system.
-
- When your auto-config hardware board is configured by the expansion
- initialization routine, its ExpansionRom structure is copied into the
- ExpansionRom subfield of a ConfigDev structure (see figure 1). This
- ConfigDev structure will be linked to the expansion.library as part
- of the eb_BoardList.
-
- AFTER the board is configured, the er_Type field of its ExpansionRom
- structure is checked (see figure 2). The DIAGVALID bit set declares
- that there is a valid DiagArea (you know, a rom/diagnostic area) on this
- board.
-
- If there is a valid DiagArea, expansion next tests the er_InitDiagVec
- vector in its copy of the ExpansionRom structure. This offset is added
- to the base address of the configured board; the resulting address points
- to the start of this board's DiagArea. Now expansion knows that there is
- a DiagArea and where it is.
-
- Next, expansion tests the first byte (see figure 3) of the DiagArea
- structure to determine if the CONFIGTIME bit is set. If this bit
- is set, it checks the da_BootPoint offset vector to make sure that a
- valid bootstrap routine exists. If so, expansion copies da_Size bytes
- into RAM memory, beginning at DiagArea and continuing until the entire
- DiagArea is copied into memory.
-
- The copy will start with the DiagArea structure itself, and typically
- include a rom/diagnostic routine, a device driver, and the board's
- bootstrap routine. The copy will be made either nibblewise, bytewise,
- or wordwise, according to the BUSWIDTH subfield of da_Config (see
- figure 4). Note that the da_BootPoint offset MUST BE NON-NULL, OR ELSE
- NO COPY WILL OCCUR.
-
- Now the ROM "image" exists in RAM memory. Expansion stores the
- ULONG address of that "image" in the UBYTES er_Reserved0c, 0d, 0e and 0f.
- The address is stored with the most significant byte in er_Reserved0c,
- the next to most significant byte in er_Reserved0d, the next to least
- significant byte in er_Reserved0e, and the least significant byte
- in er_Reserved0f (see figure 5).
-
- Expansion finally checks the da_DiagPoint offset vector, and if valid
- executes the rom/diagnostic routine contained as part of the ROM "image".
- This diagnostic routine is responsible for "patching" the ROM image so
- that required absolute addresses are relocated to reflect the actual
- location of the code, as well as performing any diagnostic functions
- essential to the operation of its associated auto-config board (see
- figure 6).
-
- Your rom/diagnostic routine should return a non-zero value to
- indicate success; otherwise the ROM "image" will be unloaded from
- memory, and its address will be replaced with NULL bytes in locations
- er_Reserved0c, 0d, 0e and 0f.
-
- Now that the ROM "image" has been copied into RAM, validated, and
- linked to board's ConfigDev structure, the expansion module is free to
- configure all other boards on the eb_BoardList.
-
-
- NEXT, OTHER RESIDENT MODULES ARE INITIALIZED:
-
- Currently, all Resident Modules (excepting strap) have a priority of
- zero or above. The new romboot Resident Module has a priority level of
- -40. The strap module has priority -60. This means that Romboot will
- be initialized after all other modules but before the (boot)strap module.
-
-
- NOW, THE ROMBOOT.LIBRARY IS INITIALIZED:
-
- As part of the initialization procedure for the romboot.library,
- a search is made of the expansion eb_BoardList (which contains a
- ConfigDev structure for each of the auto-config hardware boards).
- If the cd_Flags specify CONFIGME and the er_Type specifies DIAGVALID,
- the romboot device will do three things:
-
- First, it will bind the address of the current ConfigDev to the
- eb_CurrentBinding structure (see expansion.library/SetCurrentBinding).
-
- Second, it will check the DiagArea's da_Config flag to make sure that
- the CONFIGTIME bit is set.
-
- Third, it will search the ROM "image" associated with this hardware
- board for a valid Resident structure (exec/resident.h); and, if one is
- located, will call InitResident() on it, passing a NULL segment list
- pointer as part of the call.
-
-
- NOW, THIS BOARD'S DEVICE DRIVER IS INITIALIZED:
-
- The Resident structure associated with this board's device driver
- (which has now been "patched" by the rom/diagnostic routine) should
- follow standard system conventions in initializing the device driver
- provided in the bootroms. This driver should obtain the address of its
- associated ConfigDev structure via the expansion eb_CurrentBinding
- structure (see figure 7).
-
- Once the driver is initialized, it is responsible for some further
- steps. One, it must clear the CONFIGME bit in the cd_Flags of its
- ConfigDev structure , so that the system knows not to configure this
- device again if binddrivers is run after bootstrap. Two, for this
- device to be bootable, the driver must create a BootNode structure,
- and link this BootNode onto the expansion eb_MountList.
-
- The BootNode structure (see libraries/romboot_base.h) contains a Node of
- the "new" type NT_BOOTNODE (see exec/nodes.h). The driver MUST initialize
- the bn_DeviceNode field to point to the ConfigDev structure which it has
- obtained via the GetCurrentBinding() call. The bn_Flags subfield
- is currently unused and should be initialized to NULL.
-
- When the DOS is initialized later, it will attempt to boot from
- the first BootNode on the eb_MountList. The eb_MountList is a priority
- sorted List, with nodes of the highest priority a the head of the List.
- For this reason, the device driver must Enqueue() a BootNode onto the
- List using the exec.library/Enqueue.
-
- In the case of an autoboot of AmigaDOS, the BootNode must be linked
- to a DeviceNode of the AmigaDOS type (see libraries/filehandler.h), which
- the driver can create via the expansion.library/MakeDosNode call.
- When the DOS "wakes up",it will attempt to boot from this DeviceNode.
-
- Note: DOS, in this context, means "device operating system".
- Typically this means AmigaDOS, although there is nothing
- to prevent a system boot from another OS (UNIX, MS-DOS.
- <boot via nfs:>, ETC.).
-
- When the romboot.library is finished setting up all the rom "images"
- of all the boards in the system, the Resident Module strap takes over.
-
-
- EXECUTION PASSES TO STRAP:
-
- This is where all your hard work pays off.
-
- If there is NO boot disk in the internal floppy drive, strap will
- call the function romboot.library/RomBoot(). This routine performs the
- autoboot. It will examine the eb_MountList; find the highest priority
- BootNode structure at the head of the List; validate the BootNode;
- determine which ConfigDev on the eb_BootList is associated with this
- BootNode; find its DiagArea; and call its da_BootPoint function in the
- ROM "image" to bootstrap the appropriate DOS. This call, if successful,
- should not return.
-
- Otherwise, if a boot disk IS in the internal floppy drive, the strap
- will Enqueue() a BootNode on the eb_MountList for DF0: at the "suggested"
- priority (see autodoc for expansion.library/AddDosNode). Strap will then
- open AmigaDOS, overriding the autoboot. AmigaDOS will boot from the
- highest priority node on the eb_MountList which should, in this case, be
- DF0:. Thus, games and other "bootable" floppy disks will still be able
- to obtain the system for their own use.
-
- In the event that there is NO boot disk in the internal floppy drive
- AND there are no ROM bootable devices on the auto-configuration chain,
- the system does the normal thing, asking the user to insert a WorkBench
- disk, and waiting until its request is satisfied before proceeding.
-
-
-
-
-
- ------------------------------------------------------------------------
- Figure 1: the ConfigDev structure
- ------------------------------------------------------------------------
-
- struct ConfigDev
- {
- struct Node cd_Node;
- UBYTE cd_Flags;
- UBYTE cd_Pad;
- struct ExpansionRom cd_Rom; /* image of ExpansionRom */
- APTR cd_BoardAddr; /* for this ConfigDevice */
- APTR cd_BoardSize;
- UWORD cd_SlotAddr;
- UWORD cd_SlotSize;
- APTR cd_Driver;
- struct ConfigDev *cd_NextCD;
- ULONG cd_Unused[4];
- };
-
- ------------------------------------------------------------------------
- Figure 2: the ExpansionRom structure
- ------------------------------------------------------------------------
-
- struct ExpansionRom
- {
- UBYTE er_Type; /* <-- if ERTB_DIAGVALID set */
- UBYTE er_Product;
- UBYTE er_Flags;
- UBYTE er_Reserved03;
- UWORD er_Manufacturer;
- ULONG er_SerialNumber;
- UWORD er_InitDiagVec; /* <-- then er_InitDiagVec */
- UBYTE er_Reserved0c; /* is added to cd_BoardAddr */
- UBYTE er_Reserved0d; /* and points to DiagArea */
- UBYTE er_Reserved0e; /* ( see figure 3 ) */
- UBYTE er_Reserved0f;
- };
-
-
- ------------------------------------------------------------------------
- Figure 3: the DiagArea structure
- ------------------------------------------------------------------------
-
- struct DiagArea
- {
- UBYTE da_Config; /* <-- if DAC_CONFIGTIME is set */
- UBYTE da_Flags;
- UWORD da_Size; /* <-- then da_Size bytes will */
- UWORD da_DiagPoint; /* be copied into RAM */
- UWORD da_BootPoint; /* ( see figure 4 ) */
- UWORD da_Name;
- UWORD da_Reserved01;
- UWORD da_Reserved02;
- };
-
-
- ------------------------------------------------------------------------
- Figure 4: the RAM copy of the DiagArea structure
- ------------------------------------------------------------------------
-
- DiagArea: copy in RAM
- ( see figure 5 )
-
- +-> CCFF ; da_Config, da_Flags <-----+ <-----+ <-----+
- | SIZE ; da_Size | | |
- S DIAG ; da_DiagPoint N B D
- I BOOT ; da_BootPoint A O I
- Z NAME ; da_Name M O A
- E 0000 ; da_Reserved01 E T G
- | 0000 ; da_Reserved02 | | |
- | | | |
- | nnnn ; DiagArea + da_Name <+-----+ | |
- | nnnn ; name | |
- | nnnn ; name | |
- | nnnn ; name | |
- | nnnn ; name | |
- | | |
- | bbbb ; DiagArea + da_bootPoint <---------+ |
- | bbbb ; boot |
- | bbbb ; boot |
- | bbbb ; boot |
- | bbbb ; boot |
- | bbbb ; boot |
- | bbbb ; boot |
- | bbbb ; boot |
- | |
- | dddd ; DiagArea + da_DiagPoint <-----------------+
- | dddd ; diag
- | dddd ; diag
- | dddd ; diag
- | dddd ; diag
- | dddd ; diag
- | dddd ; diag
- | dddd ; diag
- |
- +-> last ; DiagArea + da_Size
-
-
- ------------------------------------------------------------------------
- Figure 5: where the pointer to the RAM copy is kept
- ------------------------------------------------------------------------
-
- struct ConfigDev
- {
- struct Node cd_Node;
- UBYTE cd_Flags;
- UBYTE cd_Pad;
- struct ExpansionRom {
- UBYTE er_Type;
- UBYTE er_Product;
- UBYTE er_Flags;
- UBYTE er_Reserved03;
- UWORD er_Manufacturer;
- ULONG er_SerialNumber;
- UWORD er_InitDiagVec;
- UBYTE er_Reserved0c; /* <-- address of RAM copy of */
- UBYTE er_Reserved0d; /* DiagArea is stored by */
- UBYTE er_Reserved0e; /* expansion.library in */
- UBYTE er_Reserved0f; /* these four bytes in the */
- } cd_Rom; /* image of ExpansionRom */
- APTR cd_BoardAddr; /* for this ConfigDevice */
- APTR cd_BoardSize;
- UWORD cd_SlotAddr;
- UWORD cd_SlotSize;
- APTR cd_Driver;
- struct ConfigDev *cd_NextCD;
- ULONG cd_Unused[4];
- };
-
-
- ------------------------------------------------------------------------
- Figure 6: DiagArea Initialization and Relocation
- ------------------------------------------------------------------------
-
- ( this figure omits several important steps )
- ( involved in error checking and relocation )
- ( of variables in the resident structure!!! )
- ( in this example the Init routine will be )
- ( executed directly from the wordwide ROMS )
-
- DiagArea: dc.b (DAC_WORDWIDE+DAC_CONFIGTIME)
- dc.b (NULL)
- dc.w (End-DiagArea)
- dc.w (DiagPoint-DiagArea)
- dc.w (BootPoint-DiagArea)
- dc.w (Name-DiagArea)
- dc.w (NULL)
- dc.w (NULL)
-
- Resident: dc.w RTC_MATCHWORD ; UWORD RT_MATCHWORD
- rt_Match: dc.l Resident ; APTR RT_MATCHTAG
- rt_End: dc.l End ; APTR RT_ENDSKIP
- dc.b RTW_COLDSTART ; UBYTE RT_FLAGS
- dc.b VERSION ; UBYTE RT_VERSION
- dc.b NT_DEVICE ; UBYTE RT_TYPE
- dc.b 20 ; BYTE RT_PRI
- rt_Name: dc.l Name ; APTR RT_NAME
- rt_ID: dc.l Name ; APTR RT_IDSTRING
- rt_Init: dc.l Init ; APTR RT_INIT == offset from ROM base
-
- Name: dc.b 'AutoBoot',0 ; our own Name string
-
- DosName: DOSNAME ; macro definition of DOS library name
- ds.w 0 ; word align code
-
- BootPoint: lea DosName(PC),A1
- jsr _LVOFindResident(A6) ; find the DOS resident tag
- move.l d0,a0 ; in order to bootstrap
- move.l RT_INIT(A0),A0 ; set vector to DOS INIT
- jsr (a0) ; and initialize DOS
- rts
-
- DiagPoint: movem.l a1,-(sp) ; a0 == pointer to boardbase
- lea rt_Init(pc),a1 ; relocate address of Init routine
- move.l (a1),d0 ; get long offset from ROM origin
- add.l a0,d0 ; add the boardbase to the offset
- move.l d0,(a1) ; and replace offset with absolute
- movem.l (sp)+,a1 ; restore scratch register
- moveq.l #1,d0 ; indicate "success"
- rts
-
- End: end
-
-
- ------------------------------------------------------------------------
- Figure 7: Adding a DOS BootNode to the eb_MountList
- ------------------------------------------------------------------------
-
- char execName[] = "trackdisk.device"; char dosName[] = "DF1";
- ULONG parmPkt[] = /* a 3.5" amiga format floppy drive */
- { (ULONG) dosName,
- (ULONG) execName,
- 1, /* unit number */
- 0, /* OpenDevice flags */
- 12, /* table upper bound */
- 512>>2, /* # longwords in a block */
- 0, /* sector origin */
- 2, /* number of surfaces */
- 1, /* secs per logical block */
- 11, /* secs per track */
- 2, /* reserved blocks -- 2 boot blocks */
- 0, /* unused */
- 0, /* interleave */
- 0, /* lower cylinder */
- 79, /* upper cylinder */
- 5, /* number of buffers */
- 3 /* type of memory */ };
-
- Init()
- {
- struct ExpansionBase *eb = OpenLibrary("expansion.library",V1_POINT_3);
-
- if(eb)
- {
- struct BootNode *bn =
- AllocMem(sizeof(struct BootNode),MEMF_PUBLIC|MEMF_CLEAR);
-
- if(bn)
- {
- struct DeviceNode *dosnode = MakeDosNode( parmPkt );
-
- if(dosnode)
- {
- struct CurrentBinding curbind;
-
- GetCurrentBinding(&curbind, sizeof(struct CurrentBinding));
- bn->bn_Node.ln_Type = NT_BOOTNODE;
- bn->bn_Node.ln_Pri = 5;
- bn->bn_Node.ln_Name = curbind.cb_ConfigDev;
- bn->bn_Flags = NULL;
- bn->bn_DeviceNode = dosnode;
-
- Enqueue(&eb->MountList,bn);
-
- } else { FreeMem(bn,sizeof(struct BootNode)); }
- }
- }
- }
-
-
-