home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Developer CD v1.2
/
amidev_cd_12.iso
/
reference
/
amiga_mail_vol1
/
bootexpcon
/
kickauto1.3
< prev
next >
Wrap
Text File
|
1990-01-26
|
25KB
|
531 lines
(c) Copyright 1989 Commodore-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)); }
}
}
}