Copyright (c) Hyperion Entertainment and contributors.
Difference between revisions of "Expansion Library"
Steven Solie (talk | contribs) |
m (Added code review request) |
||
(33 intermediate revisions by one other user not shown) | |||
Line 1: | Line 1: | ||
+ | {{NeedUpdate}}{{CodeReview}} |
||
== Expansion Library == |
== Expansion Library == |
||
Line 7: | Line 8: | ||
The Amiga AUTOCONFIG protocol is designed to allow the dynamic assignment of available address space to expansion boards, eliminating the need for user configuration via jumpers. Such expansion boards include memory boards, hard disk controllers, network interfaces, and other special purpose expansion devices. Some expansion devices, such as RAM boards, require no special driver software. Other types of expansion devices may use a disk-loaded driver from the "DEVS:" or "SYS:Expansion drawer", or an on-board ROM driver (for example, a self-booting hard disk controller). |
The Amiga AUTOCONFIG protocol is designed to allow the dynamic assignment of available address space to expansion boards, eliminating the need for user configuration via jumpers. Such expansion boards include memory boards, hard disk controllers, network interfaces, and other special purpose expansion devices. Some expansion devices, such as RAM boards, require no special driver software. Other types of expansion devices may use a disk-loaded driver from the "DEVS:" or "SYS:Expansion drawer", or an on-board ROM driver (for example, a self-booting hard disk controller). |
||
− | This |
+ | This article will concentrate on the software and driver side of Zorro expansion devices, using a Zorro-II device as an example. Zorro-III devices have additional identifying bits and memory size options which are described in the Zorro-III hardware documentation. For more information on Zorro-II and Zorro-III expansion hardware, see the "Zorro Expansion Bus" appendix of the ''Amiga Hardware Reference Manual, 3rd Edition''. For additional information specific to Zorro-II boards, see the ''A500/A2000 Technical Reference Manual''. |
− | AUTOCONFIG occurs whenever the Amiga is powered on or reset. During early system initialization, expansion.library identifies the expansion boards that are installed in the Amiga and dynamically assigns an appropriate address range for each board to reside at. During this AUTOCONFIG process, each expansion board first appears in turn at $ |
+ | AUTOCONFIG occurs whenever the Amiga is powered on or reset. During early system initialization, expansion.library identifies the expansion boards that are installed in the Amiga and dynamically assigns an appropriate address range for each board to reside at. During this AUTOCONFIG process, each expansion board first appears in turn at $E80000 (Zorro-II) or $FF000000 (Zorro-III), presenting readable identification information, generally in a PAL or a ROM, at the beginning of the board. The identification includes the size of the board, its address space preferences, type of board (memory or other), and a unique [[Amiga_Hardware_Manufacturer_ID_Registry|Hardware Manufacturer Number]] assigned by the AmigaOS development team. |
The unique Hardware Manufacturer number, in combination with a vendor-supplied product number, provides a way for boards to be identified and for disk-based drivers to be matched with expansion boards. All expansion boards for the Amiga must implement the AUTOCONFIG protocol. |
The unique Hardware Manufacturer number, in combination with a vendor-supplied product number, provides a way for boards to be identified and for disk-based drivers to be matched with expansion boards. All expansion boards for the Amiga must implement the AUTOCONFIG protocol. |
||
Line 19: | Line 20: | ||
Descriptions of all configured boards are kept in a private ExpansionBase list of ConfigDev structures. A board's identification information is stored in the ExpansionRom sub-structure contained within the ConfigDev structure. Applications can examine individual or all ConfigDev structures with the expansion.library function FindConfigDev(). |
Descriptions of all configured boards are kept in a private ExpansionBase list of ConfigDev structures. A board's identification information is stored in the ExpansionRom sub-structure contained within the ConfigDev structure. Applications can examine individual or all ConfigDev structures with the expansion.library function FindConfigDev(). |
||
− | The ConfigDev structure is defined in <libraries/configvars.h |
+ | The ConfigDev structure is defined in <libraries/configvars.h>: |
+ | <syntaxhighlight> |
||
− | <pre> |
||
struct ConfigDev { |
struct ConfigDev { |
||
struct Node cd_Node; |
struct Node cd_Node; |
||
Line 41: | Line 42: | ||
#define CDF_SHUTUP 0x01 |
#define CDF_SHUTUP 0x01 |
||
#define CDF_CONFIGME 0x02 |
#define CDF_CONFIGME 0x02 |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
− | The ExpansionRom structure within ConfigDev contains the board identification information that is read from the board's PAL or ROM at expansion time. The actual onboard identification information of a Zorro |
+ | The ExpansionRom structure within ConfigDev contains the board identification information that is read from the board's PAL or ROM at expansion time. The actual onboard identification information of a Zorro-II board appears in the high nibbles of the first $40 words at the start of the board. Except for the first nibble pair ($00/$02) which when combined form er_Type, the information is stored in inverted ("ones-complement") format where binary 1's are represented as 0's and 0's are represented as 1's. The expansion.library reads the nibbles of expansion information from the board, un-inverts them (except for $00/$02 er_Type which is already un-inverted), and combines them to form the elements of the ExpansionRom structure. |
− | The ExpansionRom structure is defined in <libraries/configregs.h |
+ | The ExpansionRom structure is defined in <libraries/configregs.h>: |
+ | <syntaxhighlight> |
||
− | <pre> |
||
struct ExpansionRom { /* First 16 bytes of the expansion ROM */ |
struct ExpansionRom { /* First 16 bytes of the expansion ROM */ |
||
UBYTE er_Type; /* Board type, size and flags */ |
UBYTE er_Type; /* Board type, size and flags */ |
||
Line 53: | Line 54: | ||
UBYTE er_Flags; /* Flags */ |
UBYTE er_Flags; /* Flags */ |
||
UBYTE er_Reserved03; /* Must be zero ($ff inverted) */ |
UBYTE er_Reserved03; /* Must be zero ($ff inverted) */ |
||
− | UWORD er_Manufacturer; /* Unique ID,ASSIGNED BY |
+ | UWORD er_Manufacturer; /* Unique ID,ASSIGNED BY AmigaOS development team */ |
ULONG er_SerialNumber; /* Available for use by manufacturer */ |
ULONG er_SerialNumber; /* Available for use by manufacturer */ |
||
UWORD er_InitDiagVec; /* Offset to optional "DiagArea" structure */ |
UWORD er_InitDiagVec; /* Offset to optional "DiagArea" structure */ |
||
Line 61: | Line 62: | ||
UBYTE er_Reserved0f; |
UBYTE er_Reserved0f; |
||
}; |
}; |
||
+ | </syntaxhighlight> |
||
− | </pre> |
||
=== Simple Expansion Library Example === |
=== Simple Expansion Library Example === |
||
Line 159: | Line 160: | ||
== Expansion Board Drivers == |
== Expansion Board Drivers == |
||
− | The Amiga operating system contains support for matching up disk-based drivers with AUTOCONFIG boards. Though such drivers are commonly Exec devices, this is not required. The driver may, for instance, be an Exec library or task. |
+ | The Amiga operating system contains support for matching up disk-based drivers with AUTOCONFIG boards. Though such drivers are commonly Exec devices, this is not required. The driver may, for instance, be an Exec library or task. The system software also supports the initialization of onboard ROM driver software. |
=== Disk Based Drivers === |
=== Disk Based Drivers === |
||
− | Disk-based expansion board drivers and their icons are generally placed in the |
+ | Disk-based expansion board drivers and their icons are generally placed in the "SYS:Expansion" drawer of the user's "SYS:" disk or partition. The icon Tool Type field must contain the unique Hardware Manufacturer number, and the Product number of the expansion board(s) the driver is written for. (For more about icon Tool Type fields refer to [[Icon_Library|Icon Library]].) |
− | The |
+ | The "BindDrivers" command issued during the disk startup-sequence attempts to match disk-based drivers with their expansion boards. To do this, "BindDrivers" looks in the Tool Types field of all icon files in "SYS:Expansion". If the Tool Type "PRODUCT" is found in the icon, then this is an icon file for a driver. "BindDrivers" will then attempt to match the manufacturer and product number in this PRODUCT Tool Type with those of a board that was configured at expansion time. |
For example, suppose you are manufacturer #1019. You have two products, #1 and #2 which both use the same driver. The icon for your driver for these two products would have a Tool Type set to "PRODUCT=1019/1|1019/2". This means: I am an icon for a driver that works with product number 1 or 2 from manufacturer 1019, now bind me. Spaces are not legal. Here are two other examples: |
For example, suppose you are manufacturer #1019. You have two products, #1 and #2 which both use the same driver. The icon for your driver for these two products would have a Tool Type set to "PRODUCT=1019/1|1019/2". This means: I am an icon for a driver that works with product number 1 or 2 from manufacturer 1019, now bind me. Spaces are not legal. Here are two other examples: |
||
+ | {| class="wikitable" |
||
− | <table> |
||
+ | | PRODUCT=1208/11 |
||
− | <tbody> |
||
+ | | is the Tool Type for a driver for product 11 from manufacturer number 1208. |
||
− | <tr class="odd"> |
||
+ | |- |
||
− | <td align="left">PRODUCT=1208/11</td> |
||
+ | | PRODUCT=1017 |
||
− | <td align="left">is the Tool Type for a driver for product</td> |
||
+ | | is the Tool Type for a driver for any product from manufacturer number 1017. |
||
− | </tr> |
||
+ | |} |
||
− | <tr class="even"> |
||
− | <td align="left"></td> |
||
− | <td align="left">11 from manufacturer number 1208.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left"></td> |
||
− | <td align="left"></td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">PRODUCT=1017</td> |
||
− | <td align="left">is the Tool Type for a driver for any</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left"></td> |
||
− | <td align="left">product from manufacturer number 1017.</td> |
||
− | </tr> |
||
− | </tbody> |
||
− | </table> |
||
If a matching board is found for the disk-based driver, the driver code is loaded and then initialized with the Exec InitResident() function. From within its initialization code, the driver can get information about the board it is bound to by calling the expansion.library function GetCurrentBinding(). This function will provide the driver with a copy of a CurrentBinding structure, including a pointer to a ConfigDev structure (possibly linked to additional ConfigDevs via the cd_NextCD field) of the expansion board(s) that matched the manufacturer and product IDs. |
If a matching board is found for the disk-based driver, the driver code is loaded and then initialized with the Exec InitResident() function. From within its initialization code, the driver can get information about the board it is bound to by calling the expansion.library function GetCurrentBinding(). This function will provide the driver with a copy of a CurrentBinding structure, including a pointer to a ConfigDev structure (possibly linked to additional ConfigDevs via the cd_NextCD field) of the expansion board(s) that matched the manufacturer and product IDs. |
||
+ | <pre> |
||
− | |||
+ | /* this structure is used by GetCurrentBinding() and SetCurrentBinding() */ |
||
− | |||
− | |||
− | |||
− | <pre>/* this structure is used by GetCurrentBinding() and SetCurrentBinding() */ |
||
struct CurrentBinding { |
struct CurrentBinding { |
||
struct ConfigDev *cb_ConfigDev; /* first configdev in chain */ |
struct ConfigDev *cb_ConfigDev; /* first configdev in chain */ |
||
Line 206: | Line 187: | ||
UBYTE * cb_ProductString; /* product # string */ |
UBYTE * cb_ProductString; /* product # string */ |
||
UBYTE ** cb_ToolTypes; /* tooltypes from disk object */ |
UBYTE ** cb_ToolTypes; /* tooltypes from disk object */ |
||
− | }; |
+ | }; |
+ | </pre> |
||
− | GetCurrentBinding() |
||
− | allows the driver to find out the base address and other information about its board(s). The driver must unset the CONFIGME bit in the cd_Flags field of the ConfigDev structure for each board it intends to drive, and record the |
+ | GetCurrentBinding() allows the driver to find out the base address and other information about its board(s). The driver must unset the CONFIGME bit in the cd_Flags field of the ConfigDev structure for each board it intends to drive, and record the driver's Exec node pointer in the cd_Driver structure. This node should contain the LN_NAME and LN_TYPE (i.e., NT_DEVICE, NT_TASK, etc.) of the driver. |
− | + | {{Note|title=Important Note|text=The GetCurrentBinding() function, and driver binding in general, must be bracketed by an ObtainConfigBinding() and ReleaseConfigBinding() semaphore. The "BindDrivers" command obtains this semaphore and performs a SetCurrentBinding() before calling InitResident(), allowing the driver to simply do a GetCurrentBinding().}} |
|
+ | Full source code for a disk-based Expansion or "DEVS:" sample device driver may be found in [[Example_Device|Example Device]]. Autodocs for expansion.library functions may be found in the SDK. |
||
− | |||
− | |||
− | Full source code for a disk-based Expansion or ‚ÄúDEVS:‚Äù sample device driver may be found in the ''Amiga ROM Kernel Reference Manual: Devices''. Autodocs for expansion.library functions may be found in the ''Amiga ROM Kernel Reference Manual: Includes and Autodocs''. |
||
=== Expansion Drivers and DOS === |
=== Expansion Drivers and DOS === |
||
+ | Two other expansion.library functions commonly used by expansion board drivers are MakeDosNode() and AddDosNode(). These functions allow a driver to create and add a DOS device node (for example "DH0:") to the system. AddBootNode() can be used to add an autobooting DOS device node. |
||
+ | MakeDosNode() requires an initialized structure of environment information for creating a DOS device node. The format of the function is: |
||
+ | <pre> |
||
− | Two other expansion.library functions commonly used by expansion board drivers are MakeDosNode() and AddDosNode(). These functions allow a driver to create and add a DOS device node (for example ‚ÄúDH0:‚Äù) to the system. A new function, AddBootNode(), is also available in Release 2 (V36 and later versions of the OS) that can be used to add an autobooting DOS device node. |
||
+ | struct DeviceNode *deviceNode = MakeDosNode(parameterPkt); |
||
+ | </pre> |
||
+ | The parameterPkt argument is a pointer to an initialized packet of environment parameters. |
||
− | MakeDosNode() |
||
− | |||
− | requires an initialized structure of environment information for creating a DOS device node. The format of the function is: |
||
− | |||
− | <pre>struct DeviceNode *deviceNode = MakeDosNode(parameterPkt);</pre> |
||
− | The parameterPkt argument is a pointer (passed in A0 from assembler) to an initialized packet of environment parameters. |
||
The parameter packet for MakeDosNode() consists of four longwords followed by a DosEnvec structure: |
The parameter packet for MakeDosNode() consists of four longwords followed by a DosEnvec structure: |
||
+ | <pre> |
||
− | |||
+ | ;----------------------------------------------------------------------- |
||
− | |||
− | <pre>;----------------------------------------------------------------------- |
||
; |
; |
||
; Layout of parameter packet for MakeDosNode |
; Layout of parameter packet for MakeDosNode |
||
Line 270: | Line 247: | ||
ULONG de_Mask ; Address Mask to block out certain memory |
ULONG de_Mask ; Address Mask to block out certain memory |
||
LONG de_BootPri ; Boot priority for autoboot |
LONG de_BootPri ; Boot priority for autoboot |
||
− | ULONG de_DosType ; ASCII (HEX) string showing |
+ | ULONG de_DosType ; ASCII (HEX) string showing file system type; |
− | ; 0X444F5300 is old |
+ | ; 0X444F5300 is old file system, |
; 0X444F5301 is fast file system |
; 0X444F5301 is fast file system |
||
ULONG de_Baud ; Baud rate for serial handler |
ULONG de_Baud ; Baud rate for serial handler |
||
− | ULONG de_Control ; Control word for handler/ |
+ | ULONG de_Control ; Control word for handler/file system |
− | ; (used as |
+ | ; (used as file system/handler desires) |
ULONG de_BootBlocks ; Number of blocks containing boot code |
ULONG de_BootBlocks ; Number of blocks containing boot code |
||
− | ; (for non-AmigaDOS |
+ | ; (for non-AmigaDOS file systems) |
− | LABEL DosEnvec_SIZEOF |
+ | LABEL DosEnvec_SIZEOF |
+ | </pre> |
||
− | After making a DOS device node, drivers (except for autoboot drivers) use AddDosNode(deviceNode) to add their node to the system. Autoboot drivers will instead use the new Release 2 expansion.library AddBootNode() function (if running under V36 or higher) or the Exec Enqueue() function (if running under pre-V36) to add a BootNode to the ExpansionBase.eb_MountList. |
||
+ | |||
+ | After making a DOS device node, drivers (except for autoboot drivers) use AddDosNode(deviceNode) to add their node to the system. Autoboot drivers will instead use the AddBootNode() function to add a BootNode to the ExpansionBase.eb_MountList. |
||
=== ROM Based and Autoboot Drivers === |
=== ROM Based and Autoboot Drivers === |
||
+ | The system software supports the initialization of ROM drivers residing on expansion peripherals, including the ability for drivers to provide a DOS node which the system can boot from. This feature is known as ''Autoboot''. |
||
+ | Automatic boot from a ROM-equipped expansion board is accomplished before DOS is initialized. 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, even allowing the initialization of a disk operating system other than the Amiga's dos.library. ROM-based drivers contain several special entry points that are called at different stages of system initialization. These three stages are known as '''DIAG''', '''ROMTAG INIT''' and '''BOOT'''. |
||
− | |||
− | Since 1.3, the system software supports the initialization of ROM drivers residing on expansion peripherals, including the ability for drivers to provide a DOS node which the system can boot from. This feature is known as ''Autoboot''. |
||
− | |||
− | Automatic boot from a ROM-equipped expansion board is accomplished before DOS is initialized. 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, even allowing the initialization of a disk operating system other than the Amiga‚Äôs dos.library. ROM-based drivers contain several special entry points that are called at different stages of system initialization. These three stages are known as '''DIAG''', '''ROMTAG INIT''' and '''BOOT'''. |
||
==== Events At DIAG Time ==== |
==== Events At DIAG Time ==== |
||
− | When your AUTOCONFIG hardware board is configured by the expansion initialization routine, its ExpansionRom structure is copied into the ExpansionRom subfield of a ConfigDev structure. This ConfigDev structure will be linked to the expansion. |
+ | When your AUTOCONFIG hardware board is configured by the expansion initialization routine, its ExpansionRom structure is copied into the ExpansionRom subfield of a ConfigDev structure. This ConfigDev structure will be linked to the expansion.library's private list of configured boards. |
− | After the board is configured, the er_Type field of its ExpansionRom structure is checked. The DIAGVALID bit set declares that there is a valid DiagArea (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 |
+ | After the board is configured, the er_Type field of its ExpansionRom structure is checked. The DIAGVALID bit set declares that there is a valid DiagArea (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. |
+ | <syntaxhighlight> |
||
− | <pre>struct ExpansionRom |
||
+ | struct ExpansionRom |
||
{ |
{ |
||
− | UBYTE er_Type; /* |
+ | UBYTE er_Type; /* <-- if ERTB_DIAGVALID set */ |
UBYTE er_Product; |
UBYTE er_Product; |
||
UBYTE er_Flags; |
UBYTE er_Flags; |
||
Line 303: | Line 281: | ||
UWORD er_Manufacturer; |
UWORD er_Manufacturer; |
||
ULONG er_SerialNumber; |
ULONG er_SerialNumber; |
||
− | UWORD er_InitDiagVec; /* |
+ | UWORD er_InitDiagVec; /* <-- then er_InitDiagVec */ |
UBYTE er_Reserved0c; /* is added to cd_BoardAddr */ |
UBYTE er_Reserved0c; /* is added to cd_BoardAddr */ |
||
UBYTE er_Reserved0d; /* and points to DiagArea */ |
UBYTE er_Reserved0d; /* and points to DiagArea */ |
||
UBYTE er_Reserved0e; |
UBYTE er_Reserved0e; |
||
UBYTE er_Reserved0f; |
UBYTE er_Reserved0f; |
||
− | }; |
+ | }; |
+ | </syntaxhighlight> |
||
− | Now expansion knows that there is a DiagArea, and knows where it is. |
||
− | |||
+ | Now expansion knows that there is a DiagArea, and knows where it is. |
||
+ | <syntaxhighlight> |
||
− | <pre>struct DiagArea |
||
+ | struct DiagArea |
||
{ |
{ |
||
− | UBYTE da_Config; /* |
+ | UBYTE da_Config; /* <-- if DAC_CONFIGTIME is set */ |
UBYTE da_Flags; |
UBYTE da_Flags; |
||
− | UWORD da_Size; /* |
+ | UWORD da_Size; /* <-- then da_Size bytes will */ |
UWORD da_DiagPoint; /* be copied into RAM */ |
UWORD da_DiagPoint; /* be copied into RAM */ |
||
UWORD da_BootPoint; |
UWORD da_BootPoint; |
||
Line 334: | Line 313: | ||
#define DAC_NEVER 0x00 /* obvious */ |
#define DAC_NEVER 0x00 /* obvious */ |
||
#define DAC_CONFIGTIME 0x10 /* call da_BootPoint when first |
#define DAC_CONFIGTIME 0x10 /* call da_BootPoint when first |
||
− | + | configuring the device */ |
|
− | #define DAC_BINDTIME 0x20 /* run when binding drivers to boards */ |
+ | #define DAC_BINDTIME 0x20 /* run when binding drivers to boards */ |
+ | </syntaxhighlight> |
||
− | |||
Next, expansion tests the first byte 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, starting at beginning of the DiagArea structure. |
Next, expansion tests the first byte 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, starting at beginning of the DiagArea structure. |
||
Line 343: | Line 322: | ||
The copy will be made either nibblewise, or wordwise, according to the BUSWIDTH subfield of da_Config. Note that the da_BootPoint offset must be non-NULL, or else no copy will occur. |
The copy will be made either nibblewise, or wordwise, according to the BUSWIDTH subfield of da_Config. Note that the da_BootPoint offset must be non-NULL, or else no copy will occur. |
||
− | |||
− | <sub>b</sub>oxNote:Under 1.3, DAC_BYTEWIDE is not supported. Byte wide ROMs must use DAC_NIBBLEWIDE and drivers must supply additional code to re-copy their DiagArea. |
||
The following illustrates an example Diag copy area, and specifies the various fields which should be coded as relative offsets for later patching by your DiagPoint routine. |
The following illustrates an example Diag copy area, and specifies the various fields which should be coded as relative offsets for later patching by your DiagPoint routine. |
||
+ | <pre> |
||
− | |||
+ | Example DiagArea Copy in RAM |
||
− | |||
− | <pre> Example DiagArea Copy in RAM |
||
DiagStart: ; a struct DiagArea |
DiagStart: ; a struct DiagArea |
||
Line 383: | Line 359: | ||
ssss ; other name, ID, and library name strings |
ssss ; other name, ID, and library name strings |
||
... |
... |
||
− | EndCopy: |
+ | EndCopy: |
+ | </pre> |
||
− | 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 ‚Äì i.e., it is stored as a longword at the address er_Reserved0c. |
||
+ | 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 – i.e., it is stored as a longword at the address er_Reserved0c. |
||
− | 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 code and strings, as well as performing any diagnostic functions essential to the operation of its associated AUTOCONFIG board. The structures which require patching are located within the copy area so that they can be patched at this time. Patching is required because many of the structures involved require absolute pointers to such things as name strings and code, but the absolute locations of the board and the RAM copy area are not known when code the structures. |
||
+ | 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 code and strings, as well as performing any diagnostic functions essential to the operation of its associated AUTOCONFIG board. The structures which require patching are located within the copy area so that they can be patched at this time. Patching is required because many of the structures involved require absolute pointers to such things as name strings and code, but the absolute locations of the board and the RAM copy area are not known when code the structures. |
||
− | The patching may be accomplished by coding pointers which require absolute addresses instead as relative offsets from either the start of the DiagArea structure, or the start of the board‚Äôs ROM (depending on whether the final absolute pointer will point to a RAM or ROM location). The Diag routine is passed both the actual base address of the board, and the address of the Diag copy area in RAM. The routine can then patch the structures in the Diag copy area by adding the appropriate address to resolve each pointer. |
||
+ | |||
+ | The patching may be accomplished by coding pointers which require absolute addresses instead as relative offsets from either the start of the DiagArea structure, or the start of the board's ROM (depending on whether the final absolute pointer will point to a RAM or ROM location). The Diag routine is passed both the actual base address of the board, and the address of the Diag copy area in RAM. The routine can then patch the structures in the Diag copy area by adding the appropriate address to resolve each pointer. |
||
Example DiagArea and Diag patching routine: |
Example DiagArea and Diag patching routine: |
||
+ | <pre> |
||
− | |||
+ | ** |
||
− | |||
− | <pre>** |
||
** Sample autoboot code fragment |
** Sample autoboot code fragment |
||
** |
** |
||
Line 670: | Line 647: | ||
; Rest of your position-independent device code goes here. |
; Rest of your position-independent device code goes here. |
||
− | END |
+ | END |
+ | </pre> |
||
− | Your da_DiagPoint 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 utility.library‚Äôs private list of boards. |
||
+ | Your da_DiagPoint 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. |
||
− | It may help to see just how a card‚Äôs ROM AUTOCONFIG information corresponds to the ExpansionRom structure. This chart shows the contents of on-card memory for a fictional expansion card. Note that the ExpansionRom.Flags field ($3F in addresses $08/$0A below) is shown interpreted in its inverted form of $3F. Once the value is uninverted to become $C0, you should use the #defines in <libraries/configregs.h> to interpret it. |
||
+ | 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 utility.library's private list of boards. |
||
+ | It may help to see just how a card's ROM AUTOCONFIG information corresponds to the ExpansionRom structure. This chart shows the contents of on-card memory for a fictional expansion card. Note that the ExpansionRom.Flags field ($3F in addresses $08/$0A below) is shown interpreted in its inverted form of $3F. Once the value is uninverted to become $C0, you should use the #defines in <libraries/configregs.h> to interpret it. |
||
− | + | Sample Zorro-II AUTOCONFIG ROM Information Viewed as a Hex Dump |
|
+ | <pre> |
||
− | <pre> FLAG AND FIELD DEFINITIONS THIS BOARD |
||
+ | FLAG AND FIELD DEFINITIONS THIS BOARD |
||
----------------------------------------------------------------- |
----------------------------------------------------------------- |
||
Line 701: | Line 679: | ||
/ / \ \ / / \ \ Rom Vector=~$FF7F=$80 |
/ / \ \ / / \ \ Rom Vector=~$FF7F=$80 |
||
0020: F000F000 F000E000 F000F000 7000F000 from board base |
0020: F000F000 F000E000 F000F000 7000F000 from board base |
||
− | ----------------------------------------------------------------- |
+ | ----------------------------------------------------------------- |
+ | </pre> |
||
+ | |||
The AUTOCONFIG information from the above card would appear as follows in an ExpansionRom structure: |
The AUTOCONFIG information from the above card would appear as follows in an ExpansionRom structure: |
||
+ | {| class="wikitable" |
||
− | <table> |
||
+ | ! Nibble Pairs |
||
− | <tbody> |
||
+ | ! ExpansionRom Field |
||
− | <tr class="odd"> |
||
+ | ! Value |
||
− | <td align="left">'''Nibble Pairs'''</td> |
||
+ | |- |
||
− | <td align="left">'''ExpansionRom Field'''</td> |
||
+ | | 00/02 |
||
− | <td align="left">'''Value'''</td> |
||
+ | | er_Type |
||
− | </tr> |
||
+ | | $D3 |
||
− | <tr class="even"> |
||
+ | |- |
||
− | <td align="left">00/02</td> |
||
+ | | 04/06 |
||
− | <td align="left">er_Type</td> |
||
+ | | er_Product |
||
− | <td align="left">$D3</td> |
||
+ | | $01 = 1 |
||
− | </tr> |
||
+ | |- |
||
− | <tr class="odd"> |
||
+ | | 08/0A |
||
− | <td align="left">04/06</td> |
||
+ | | er_Flags |
||
− | <td align="left">er_Product</td> |
||
+ | | $C0 |
||
− | <td align="left">$01 = 1</td> |
||
+ | |- |
||
− | </tr> |
||
+ | | 10/12 and 14/16 |
||
− | <tr class="even"> |
||
+ | | er_Manufacturer |
||
− | <td align="left">08/0A</td> |
||
+ | | $07DB = 2011 |
||
− | <td align="left">er_Flags</td> |
||
+ | |- |
||
− | <td align="left">$C0</td> |
||
+ | | 18/1A thru 24/26 |
||
− | </tr> |
||
+ | | er_SerialNumber |
||
− | <tr class="odd"> |
||
+ | | $00250001 |
||
− | <td align="left">10/12 and 14/16</td> |
||
+ | |- |
||
− | <td align="left">er_Manufacturer</td> |
||
+ | | 28/2A and 2C/2E |
||
− | <td align="left">$07DB = 2011</td> |
||
+ | | er_InitDiagVec |
||
− | </tr> |
||
+ | | $0080 |
||
− | <tr class="even"> |
||
+ | |} |
||
− | <td align="left">18/1A thru 24/26</td> |
||
− | <td align="left">er_SerialNumber</td> |
||
− | <td align="left">$00250001</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">28/2A and 2C/2E</td> |
||
− | <td align="left">er_InitDiagVec</td> |
||
− | <td align="left">$0080</td> |
||
− | </tr> |
||
− | </tbody> |
||
− | </table> |
||
If a card contains a ROM driver (Rom Vector valid), and the vector is at offset $80 (as in this example) the DiagArea structure will appear at offset $0080 from the base address of the board. This example card’s Resident structure (romtag) directly follows its DiagArea structure. |
If a card contains a ROM driver (Rom Vector valid), and the vector is at offset $80 (as in this example) the DiagArea structure will appear at offset $0080 from the base address of the board. This example card’s Resident structure (romtag) directly follows its DiagArea structure. |
||
+ | <pre> |
||
− | <pre> WORDWIDE+CONFIGTIME ROMTAG |
||
+ | WORDWIDE+CONFIGTIME ROMTAG |
||
\ flags DiagPt Devname starts |
\ flags DiagPt Devname starts |
||
\ \ DAsize / BootPt / here DiagPt, BootPt, |
\ \ DAsize / BootPt / here DiagPt, BootPt, |
||
Line 760: | Line 731: | ||
IDstring InitEntry coded relative, |
IDstring InitEntry coded relative, |
||
00A0: 00000033 00000116 patched at Diag |
00A0: 00000033 00000116 patched at Diag |
||
− | ----------------------------------------------------------------- |
+ | ----------------------------------------------------------------- |
+ | </pre> |
||
+ | |||
==== Events At ROMTAG INIT Time ==== |
==== Events At ROMTAG INIT Time ==== |
||
− | Next, most resident system modules (for example graphics) are initialized. As part of the system initialization procedure a search is made of the expansion. |
+ | Next, most resident system modules (for example graphics) are initialized. As part of the system initialization procedure a search is made of the expansion.library's private list of boards (which contains a ConfigDev structure for each of the AUTOCONFIG hardware boards). If the cd_Flags specify CONFIGME and the er_Type specifies DIAGVALID, the system initialization will do three things: |
− | First, it will set the current ConfigDev as the ''current binding'' (see the expansion.library SetCurrentBinding() function). Second, it will check the |
+ | First, it will set the current ConfigDev as the ''current binding'' (see the expansion.library SetCurrentBinding() function). 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. |
− | Next, the |
+ | Next, the 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 boot ROMs. This driver should obtain the address of its associated ConfigDev structure via GetCurrentBinding(). |
− | Once the driver is initialized, it is responsible for some further steps. 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 |
+ | Once the driver is initialized, it is responsible for some further steps. 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. Also, though it is not currently mandatory, the driver should place a pointer to its Exec node in the cd_Driver field of the ConfigDev structure. This will generally be a device (NT_DEVICE) node. And for this device to be bootable, the driver must create a BootNode structure, and link this BootNode onto the expansion.library's eb_MountList. |
The BootNode structure (see <libraries/expansionbase.h>) contains a Node of the new type NT_BOOTNODE (see <exec/nodes.h>). The driver ''must'' initialize the ln_Name 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. The bn_DeviceNode must be initialized to point to the DosNode for the device. |
The BootNode structure (see <libraries/expansionbase.h>) contains a Node of the new type NT_BOOTNODE (see <exec/nodes.h>). The driver ''must'' initialize the ln_Name 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. The bn_DeviceNode must be initialized to point to the DosNode for the device. |
||
Line 775: | Line 748: | ||
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 at the head of the List. For this reason, the device driver must enqueue a BootNode onto the list using the Exec library function Enqueue(). |
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 at the head of the List. For this reason, the device driver must enqueue a BootNode onto the list using the Exec library function 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() function call. When the DOS |
+ | <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() function call. When the DOS "wakes up", it will attempt to boot from this DeviceNode. |
==== Events At BOOT Time ==== |
==== Events At BOOT Time ==== |
||
− | If there is no boot disk in the internal floppy drive, the system strap module will call a routine to perform 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 is associated with this BootNode; find its DiagArea; and call its da_BootPoint function in the ROM |
+ | If there is no boot disk in the internal floppy drive, the system strap module will call a routine to perform 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 is associated with this BootNode; find its DiagArea; and call its da_BootPoint function in the ROM "image" to bootstrap the appropriate DOS. Generally, the BootPoint code of a ROM driver will perform the same function as the boot code installed on a floppy disk, i.e., it will FindResident() the dos.library, and jump to its RT_INIT vector. The da_BootPoint call, if successful, should not return. |
− | If a boot disk ''is'' in the internal floppy drive, the system strap will Enqueue() a BootNode on the eb_MountList for |
+ | If a boot disk ''is'' in the internal floppy drive, the system strap will Enqueue() a BootNode on the eb_MountList for "DF0:" at the suggested priority (see the Autodoc for the expansion.library AddDosNode() function). 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 autoconfiguration chain, the system does the normal thing, asking the user to insert a Workbench disk, and waiting until its request is satisfied before proceeding. |
In the event that there is no boot disk in the internal floppy drive ''and'' there are no ROM bootable devices on the autoconfiguration chain, the system does the normal thing, asking the user to insert a Workbench disk, and waiting until its request is satisfied before proceeding. |
||
− | === RigidDiskBlock and Alternate |
+ | === RigidDiskBlock and Alternate File Systems === |
+ | Through the use of RigidDiskBlock information and the FileSystem.resource, it is possible for an autoboot driver to have access to enough information to mount all of its device partitions and even load alternate file systems for use with these partitions. |
||
+ | The RigidDiskBlock specification (also known as "hardblocks") defines blocks of data that exist on a hard disk to describe that disk. These blocks are created or modified with an installation utility (such as the hard drive ''Prep'' utility for the ''A2090A'' ST506/SCSI controller card) provided by the disk controller manufacturer, and they are read and used by the device driver ROM (or expansion) code. They are not generally accessible to the user as they do not appear on any DOS device. The blocks are tagged with a unique identifier, checksummed, and linked together. |
||
− | |||
− | Through the use of RigidDiskBlock information and the FileSystem.resource, it is possible for an autoboot driver to have access to enough information to mount all of its device partitions and even load alternate filesystems for use with these partitions. |
||
− | |||
− | The RigidDiskBlock specification (also known as ‚Äúhardblocks‚Äù) defines blocks of data that exist on a hard disk to describe that disk. These blocks are created or modified with an installation utility (such as the hard drive ''Prep'' utility for the ''A2090A'' ST506/SCSI controller card) provided by the disk controller manufacturer, and they are read and used by the device driver ROM (or expansion) code. They are not generally accessible to the user as they do not appear on any DOS device. The blocks are tagged with a unique identifier, checksummed, and linked together. |
||
The five block types currently defined are RigidDiskBlock, BadBlockBlock, PartitionBlock, FileSysHeaderBlock, and LoadSegBlock. |
The five block types currently defined are RigidDiskBlock, BadBlockBlock, PartitionBlock, FileSysHeaderBlock, and LoadSegBlock. |
||
Line 803: | Line 774: | ||
The drive initialization description blocks are LoadSegBlocks that are loaded at boot time to perform drive-specific initialization. They are called with both C-style parameters on the stack, and assembler parameters in registers as follows: |
The drive initialization description blocks are LoadSegBlocks that are loaded at boot time to perform drive-specific initialization. They are called with both C-style parameters on the stack, and assembler parameters in registers as follows: |
||
+ | <pre> |
||
− | <pre>d0 = DriveInit(lun, rdb, ior) (d0/a0/a1)</pre> |
||
+ | d0 = DriveInit(lun, rdb, ior) (d0/a0/a1) |
||
+ | </pre> |
||
+ | |||
where lun is the SCSI logical unit number (needed to construct SCSI commands), rdb is a pointer to a memory copy of the RigidDiskBlock (which should not be altered), and ior is a standard IO request block that can be used to access the drive with synchronous DoIO() calls. |
where lun is the SCSI logical unit number (needed to construct SCSI commands), rdb is a pointer to a memory copy of the RigidDiskBlock (which should not be altered), and ior is a standard IO request block that can be used to access the drive with synchronous DoIO() calls. |
||
Line 810: | Line 784: | ||
The FileSysHeaderBlock entries contain code for alternate file handlers to be used by partitions. There are several strategies that can be used to determine which of them to load. The most robust would scan all drives for those that are both required by partitions and have the highest fhb_Version, and load those. Whatever method is used, the loaded file handlers are added to the Exec resource FileSystem.resource, where they are used as needed to mount disk partitions. |
The FileSysHeaderBlock entries contain code for alternate file handlers to be used by partitions. There are several strategies that can be used to determine which of them to load. The most robust would scan all drives for those that are both required by partitions and have the highest fhb_Version, and load those. Whatever method is used, the loaded file handlers are added to the Exec resource FileSystem.resource, where they are used as needed to mount disk partitions. |
||
− | The PartitionBlock entries contains most of the data necessary to add each partition to the system. They replace the Mount and |
+ | The PartitionBlock entries contains most of the data necessary to add each partition to the system. They replace the Mount and "DEVS:MountList" mechanism for adding these partitions. The only items required by the expansion.library MakeDosNode() function which are not in this partition block are the Exec device name and unit, which is expected to be known by driver reading this information. The file system to be used is specified in the pb_Environment. If it is not the default file system (i.e., "DOS\0" or "DOS\1"), the node created by MakeDosNode() is modified as specified in a FileSystem.resource's FileSysEntry before adding it to the DOS list. |
− | Only 512 byte blocks were supported by the pre-V36 file system, but this proposal was forward-looking by making the block size explicit, and by using only the first 256 bytes for all blocks but the LoadSeg and BadBlock data. Under the present |
+ | Only 512 byte blocks were supported by the pre-V36 file system, but this proposal was forward-looking by making the block size explicit, and by using only the first 256 bytes for all blocks but the LoadSeg and BadBlock data. Under the present file system, this allows using drives formatted with sectors 256 bytes or larger (i.e., 256, 512, 1024, etc). LoadSeg and BadBlock data use whatever space is available in a sector. |
==== RigidDiskBlock ==== |
==== RigidDiskBlock ==== |
||
Line 818: | Line 792: | ||
This is the current specification for the RigidDiskBlock: |
This is the current specification for the RigidDiskBlock: |
||
+ | ; rdb_ID |
||
+ | : Set to "RDSK". |
||
+ | ; rdb_SummedLongs |
||
+ | : Set to 64. |
||
+ | ; rdb_ChkSum |
||
− | Set to ‚ÄôRDSK‚Äô. |
||
+ | : Block checksum (longword sum to zero). |
||
+ | ; rdb_HostID |
||
− | Set to 64. |
||
+ | : SCSI Target ID of host. |
||
+ | : This is the initiator ID of the creator of this RigidDiskBlock. It is intended that modification of the RigidDiskBlock, or of any of the blocks pointed to by it, by another initiator (other than the one specified here) be allowed only after a suitable warning. The user is then expected to perform an audio lock out ("Hey, is anyone else setting up SCSI stuff on this bus?"). The rdb_HostID may become something other than the initiator ID when connected to a real network: that is an area for future standardization. |
||
− | Block checksum (longword sum to zero). |
||
+ | ; rdb_BlockBytes |
||
− | SCSI Target ID of host. |
||
+ | : Size of disk blocks. |
||
+ | : Present file system supports 256, 512, 1024, etc. |
||
− | This is the initiator ID of the creator of this RigidDiskBlock. It is intended that modification of the RigidDiskBlock, or of any of the blocks pointed to by it, by another initiator (other than the one specified here) be allowed only after a suitable warning. The user is then expected to perform an audio lock out (‚ÄúHey, is anyone else setting up SCSI stuff on this bus?‚Äù). The rdb_HostID may become something other than the initiator ID when connected to a real network: that is an area for future standardization. |
||
+ | ; rdb_Flags |
||
− | Size of disk blocks. |
||
+ | : Long word of flags: |
||
+ | :; RDBF._LAST |
||
− | Under pre-V36 filesystem, this must be 512 for a disk with any AmigaDOS partitions on it. Present filesystem supports 256, 512, 1024, etc. |
||
+ | :: No disks exist to be configured after this one on this controller (SCSI bus). |
||
+ | :; RDBF._LASTLUN |
||
− | Long word of flags: |
||
+ | :: No LUNs exist to be configured greater than this one at this SCSI Target ID. |
||
+ | :; RDBF._LASTTID |
||
− | No disks exist to be configured after this one on this controller (SCSI bus). |
||
+ | :: No Target IDs exist to be configured greater than this one on this SCSI bus. |
||
+ | :; RDBF._NORESELECT |
||
− | No LUNs exist to be configured greater than this one at this SCSI Target ID. |
||
+ | :: Don't bother trying to perform reselection when talking to this drive. |
||
+ | :; RDBF._DISKID |
||
− | No Target IDs exist to be configured greater than this one on this SCSI bus. |
||
+ | :: rdb_Disk... identification variables below contain valid data. |
||
+ | :; RDBF._CTRLRID |
||
− | Don‚Äôt bother trying to perform reselection when talking to this drive. |
||
+ | :: rdb_Controller... identification variables below contain valid data. |
||
+ | :; RDBF._SYNCH |
||
− | rdb_Disk |
||
+ | :: Drive supports scsi synchronous mode; '''can be dangerous to use if it doesn't!''' |
||
+ | These fields point to other blocks on the disk which are not a part of any file system. All block pointers referred to are block numbers on the drive. |
||
− | ... identification variables below contain valid data. |
||
+ | ; rdb_BadBlockList |
||
− | rdb_Controller |
||
+ | : Optional bad block list. A singly linked list of blocks of type PartitionBlock. |
||
+ | ; rdb_PartitionList |
||
− | ... identification variables below contain valid data. |
||
+ | : Optional first partition block. A singly linked list of blocks of type PartitionBlock. |
||
+ | ; rdb_FileSysHeaderList |
||
− | Drive supports scsi synchronous mode; '''can be dangerous to use if it doesn‚Äôt!''' |
||
+ | : Optional file system header block. A singly linked list of blocks of type FileSysHeaderBlock. |
||
+ | ; rdb_DriveInit |
||
− | These fields point to other blocks on the disk which are not a part of any filesystem. All block pointers referred to are block numbers on the drive. |
||
+ | : Optional drive-specific init code. A singly linked list of blocks of type LoadSegBlock containing initialization code. Called as DriveInit(lun,rdb,ior)(d0/a0/a1). |
||
+ | ; rdb_Reserved1[6] |
||
− | Optional bad block list. |
||
+ | : Set to $FFFFFFFFs. |
||
− | |||
+ | : These are reserved for future block lists. Since NULL for block lists is $FFFFFFFF, these reserved entries must be set to $FFFFFFFF. |
||
− | A singly linked list of blocks of type PartitionBlock. |
||
− | |||
− | Optional first partition block. |
||
− | |||
− | A singly linked list of blocks of type PartitionBlock. |
||
− | |||
− | Optional file system header block. |
||
− | |||
− | A singly linked list of blocks of type FileSysHeaderBlock. |
||
− | |||
− | Optional drive-specific init code. |
||
− | |||
− | A singly linked list of blocks of type LoadSegBlock containing initialization code. Called as DriveInit(lun,rdb,ior)(d0/a0/a1). |
||
− | |||
− | Set to $FFFF¬†FFFFs. |
||
− | |||
− | These are reserved for future block lists. Since NULL for block lists is $FFFF¬†FFFF, these reserved entries must be set to $FFFF¬†FFFF. |
||
These fields describe the physical layout of the drive. |
These fields describe the physical layout of the drive. |
||
+ | ; rdb_Cylinders |
||
− | Number of drive cylinders. |
||
+ | : Number of drive cylinders. |
||
+ | ; rdb_Sectors |
||
− | Sectors per track. |
||
+ | : Sectors per track. |
||
+ | ; rdb_Heads |
||
− | Number of drive heads. |
||
+ | : Number of drive heads. |
||
+ | ; rdb_Interleave |
||
− | Interleave. |
||
+ | : Interleave. |
||
+ | : This drive interleave is independent from, and unknown to, the DOS’s understanding of interleave as set in the partition's environment vector. |
||
+ | ; rdb_Park |
||
− | This drive interleave is independent from, and unknown to, the DOS‚Äôs understanding of interleave as set in the partition‚Äôs environment vector. |
||
+ | : Landing zone cylinder. |
||
+ | ; rdb_Reserved2[3] |
||
− | Landing zone cylinder. |
||
+ | : Set to zeros. |
||
− | |||
− | Set to zeros. |
||
These fields are intended for ST506 disks. They are generally unused for SCSI devices and set to zero. |
These fields are intended for ST506 disks. They are generally unused for SCSI devices and set to zero. |
||
+ | ; rdb_WritePreComp |
||
− | Starting cylinder: write precompensation. |
||
+ | : Starting cylinder: write precompensation. |
||
− | |||
− | Starting cylinder: reduced write current. |
||
− | |||
− | Drive step rate. |
||
− | |||
− | Set to zeros. |
||
− | |||
− | These fields are used while partitions are set up to constrain the partitionable area and help describe the relationship between the drive‚Äôs logical and physical layout. |
||
+ | ; rdb_ReducedWrite |
||
− | Low block of the range allocated for blocks described here. Replacement blocks for bad blocks may also live in this range. |
||
+ | : Starting cylinder: reduced write current. |
||
+ | ; rdb_StepRate |
||
− | High block of this range (inclusive). |
||
+ | : Drive step rate. |
||
+ | ; rdb_Reserved3[5] |
||
− | Low cylinder of partitionable disk area. |
||
+ | : Set to zeros. |
||
+ | These fields are used while partitions are set up to constrain the partitionable area and help describe the relationship between the drive's logical and physical layout. |
||
− | Blocks described by this include file will generally be found in cylinders below this one. |
||
+ | ; rdb_RDBlocksLo |
||
− | High cylinder of partitionable data area. |
||
+ | : Low block of the range allocated for blocks described here. Replacement blocks for bad blocks may also live in this range. |
||
+ | ; rdb_RDBlocksHi |
||
− | Usually rdb_Cylinders-1. |
||
+ | : High block of this range (inclusive). |
||
+ | ; rdb_LoCylinder |
||
− | Number of blocks available per cylinder. |
||
+ | : Low cylinder of partitionable disk area. |
||
+ | : Blocks described by this include file will generally be found in cylinders below this one. |
||
+ | ; rdb_HiCylinder |
||
− | This may be rdb_Sectors<math>\times</math>rdb_Heads, but a SCSI disk that, for example, reserves one block per cylinder for bad block mapping would use rdb_Sectors<math>\times</math>rdb_Heads-1. |
||
+ | : High cylinder of partitionable data area. |
||
+ | : Usually rdb_Cylinders-1. |
||
+ | ; rdb_CylBlocks |
||
− | Number of seconds to wait before parking drive heads automatically. If zero, this feature is not desired. |
||
+ | : Number of blocks available per cylinder. |
||
+ | : This may be rdb_Sectors*rdb_Heads, but a SCSI disk that, for example, reserves one block per cylinder for bad block mapping would use rdb_Sectors*rdb_Heads-1. |
||
+ | ; rdb_AutoParkSeconds |
||
− | Highest block used by these drive definitions. |
||
+ | : Number of seconds to wait before parking drive heads automatically. If zero, this feature is not desired. |
||
+ | ; rdb_HighRDSKBlock |
||
− | Must be less than or equal to rdb_RDBBlocksHi. All replacements for bad blocks should be between rdb_HighRDSKBlock+1 and rdb_RDBBlocksHi (inclusive). |
||
+ | : Highest block used by these drive definitions. |
||
+ | : Must be less than or equal to rdb_RDBBlocksHi. All replacements for bad blocks should be between rdb_HighRDSKBlock+1 and rdb_RDBBlocksHi (inclusive). |
||
+ | ; rdb_Reserved4 |
||
− | Set to zeros. |
||
+ | : Set to zeros. |
||
These fields are of the form available from a SCSI Identify command. Their purpose is to help the user identify the disk during setup. Entries exist for both controller and disk for non-embedded SCSI disks. |
These fields are of the form available from a SCSI Identify command. Their purpose is to help the user identify the disk during setup. Entries exist for both controller and disk for non-embedded SCSI disks. |
||
+ | ; rdb_DiskVendor |
||
− | Vendor name of the disk. |
||
+ | : Vendor name of the disk. |
||
+ | ; rdb_DiskProduct |
||
− | Product name of the disk. |
||
+ | : Product name of the disk. |
||
+ | ; rdb_DiskRevision |
||
− | Revision code of the disk. |
||
+ | : Revision code of the disk. |
||
+ | ; rdb_ControllerVendor |
||
− | Vendor name of the disk controller. |
||
+ | : Vendor name of the disk controller. |
||
+ | ; rdb_ControllerProduct |
||
− | Product name of the disk controller. |
||
+ | : Product name of the disk controller. |
||
+ | ; rdb_ControllerRevision |
||
− | Revision code of the disk controller. |
||
+ | : Revision code of the disk controller. |
||
+ | ; rdb_Reserved5[10] |
||
− | Set to zeros. |
||
+ | : Set to zeros. |
||
==== BadBlockBlock ==== |
==== BadBlockBlock ==== |
||
− | This is the current specification for the BadBlockBlock. The end of data occurs when bbb_Next is NULL ($ |
+ | This is the current specification for the BadBlockBlock. The end of data occurs when bbb_Next is NULL ($FFFFFFFF), and the summed data is exhausted. |
+ | ; bbb_ID |
||
− | Set to ‚ÄôBADB‚Äô. |
||
+ | : Set to "BADB". |
||
+ | ; bbb_SummedLongs |
||
− | Size of this checksummed structure. |
||
+ | : Size of this checksummed structure. |
||
+ | : Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, and can be from 6 to rdb_BlockBytes/4. The latter is the best size for all blocks other than the last one. |
||
+ | ; bbb_ChkSum |
||
− | Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, and can be from 6 to rdb_BlockBytes/4. The latter is the best size for all blocks other than the last one. |
||
+ | : Block checksum (longword sum to zero). |
||
+ | ; bbb_HostID |
||
− | Block checksum (longword sum to zero). |
||
+ | : SCSI Target ID of host. |
||
+ | : This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion) |
||
+ | ; bbb_Next |
||
− | SCSI Target ID of host. |
||
+ | : Block number of the next BadBlockBlock. |
||
+ | ; bbb_Reserved |
||
− | This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion) |
||
+ | : Set to zeros. |
||
+ | ; bbb_BlockPairs[61] |
||
− | Block number of the next BadBlockBlock. |
||
+ | : Pairs of block remapping information. |
||
− | |||
+ | : The data starts here and continues as long as indicated by bbb_SummedLongs-6: e.g. if bbb_SummedLongs is 128 (512 bytes), 61 pairs are described here. |
||
− | Set to zeros. |
||
− | |||
− | ] |
||
− | |||
− | Pairs of block remapping information. |
||
− | |||
− | The data starts here and continues as long as indicated by bbb_SummedLongs-6: e.g. if bbb_SummedLongs is 128 (512 bytes), 61 pairs are described here. |
||
==== PartitionBlock ==== |
==== PartitionBlock ==== |
||
− | This is the current specification for the PartitionBlock. Note that while reading these blocks you may encounter partitions that are not to be mounted because the pb_HostID does not match, or because the pb_DriveName is in use and no fallback strategy exists, or because PBFF_NOMOUNT is set, or because the proper |
+ | This is the current specification for the PartitionBlock. Note that while reading these blocks you may encounter partitions that are not to be mounted because the pb_HostID does not match, or because the pb_DriveName is in use and no fallback strategy exists, or because PBFF_NOMOUNT is set, or because the proper file system cannot be found. Some partitions may be mounted but not be bootable because PBFF_BOOTABLE is not set. |
− | |||
− | Set to ‚ÄôPART‚Äô. |
||
− | |||
− | Set to 64. |
||
− | |||
− | Block checksum (longword sum to zero). |
||
+ | ; pb_ID |
||
− | SCSI Target ID of host. |
||
+ | : Set to "PART". |
||
+ | ; pb_SummedLongs |
||
− | This describes the initiator ID for the owner of this partition. (see rdb_HostID discussion) |
||
+ | : Set to 64. |
||
+ | ; pb_ChkSum |
||
− | Block number of the next PartitionBlock. |
||
+ | : Block checksum (longword sum to zero). |
||
+ | ; pb_HostID |
||
− | See below for defines: |
||
+ | : SCSI Target ID of host. |
||
+ | : This describes the initiator ID for the owner of this partition. (see rdb_HostID discussion) |
||
+ | ; pb_Next |
||
− | This partition is intended to be bootable (e.g. expected directories and files exist). |
||
+ | : Block number of the next PartitionBlock. |
||
+ | ; pb_Flags |
||
− | This partition description is to reserve space on the disk without mounting it. It may be manually mounted later. |
||
+ | : See below for defines: |
||
+ | :; PBF._BOOTABLE |
||
+ | :: This partition is intended to be bootable (e.g. expected directories and files exist). |
||
+ | :; PBF._NOMOUNT |
||
+ | :: This partition description is to reserve space on the disk without mounting it. It may be manually mounted later. |
||
+ | ; pb_Reserved1[2] |
||
− | Set to zeros. |
||
+ | : Set to zeros. |
||
+ | ; pb_DevFlags |
||
− | Preferred flags for OpenDevice(). |
||
+ | : Preferred flags for OpenDevice(). |
||
+ | ; pb_DriveName |
||
− | Preferred DOS device name: BSTR form This name is not to be used if it is already in use. |
||
+ | : Preferred DOS device name: BSTR form This name is not to be used if it is already in use. |
||
Note that pb_Reserved2 will always be at least 4 longwords so that the RAM image of this record may be converted to the parameter packet to the expansion.library function MakeDosNode(). |
Note that pb_Reserved2 will always be at least 4 longwords so that the RAM image of this record may be converted to the parameter packet to the expansion.library function MakeDosNode(). |
||
+ | ; pb_Reserved2[15] |
||
− | Filler to make 32 longwords so far. |
||
+ | : Filler to make 32 longwords so far. |
||
− | The specification of the location of the partition is one of the components of the environment, below. If possible, describe the partition in a manner that tells the DOS about the physical layout of the partition: specifically, where the cylinder boundaries are. This allows the |
+ | The specification of the location of the partition is one of the components of the environment, below. If possible, describe the partition in a manner that tells the DOS about the physical layout of the partition: specifically, where the cylinder boundaries are. This allows the file system's smart block allocation strategy to work. |
+ | ; pb_Environment[17] |
||
− | Environment vector for this partition containing: |
||
+ | : Environment vector for this partition containing: |
||
+ | :; de_TableSize |
||
− | Size of environment vector. |
||
+ | :: Size of environment vector. |
||
+ | :; de_SizeBlock |
||
− | Set to 128 (for 512 bytes/logical block). |
||
+ | :: Set to 128 (for 512 bytes/logical block). |
||
+ | :; de_SecOrg |
||
− | Set to 0. |
||
+ | :: Set to 0. |
||
+ | :; de_Surfaces |
||
− | Number of heads (see layout discussion). |
||
+ | :: Number of heads (see layout discussion). |
||
+ | :; de_SectorPerBlock |
||
− | Set to 1. |
||
+ | :: Set to 1. |
||
+ | :; de_BlocksPerTrack |
||
− | Blocks per track (see layout discussion). |
||
+ | :: Blocks per track (see layout discussion). |
||
+ | :; de_Reserved |
||
− | DOS reserved blocks at start of partition. |
||
+ | :: DOS reserved blocks at start of partition. |
||
+ | :: Must be > 1; 2 blocks are recommended. |
||
+ | :; de_PreAlloc |
||
− | Must be <math>\ge</math> 1; 2 blocks are recommended. |
||
+ | :: DOS reserved blocks at end of partition. |
||
+ | :: Valid only for file system type "DOS\1" (the fast file system). Zero otherwise. |
||
+ | :; de_Interleave |
||
− | DOS reserved blocks at end of partition. |
||
+ | :: DOS interleave. |
||
+ | :: Valid only for file system type "DOS\0" (the old file system). Zero otherwise. |
||
+ | :; de_LowCyl |
||
− | Valid only for filesystem type ‚ÄôDOS<math>\backslash</math>1‚Äô (the fast file system). Zero otherwise. |
||
+ | :: Starting cylinder. |
||
+ | :; de_HighCyl |
||
− | DOS interleave. |
||
+ | :: Max cylinder. |
||
+ | :; de_NumBuffers |
||
− | Valid only for filesystem type ‚ÄôDOS<math>\backslash</math>0‚Äô (the old file system). Zero otherwise. |
||
+ | :: Initial number of DOS buffers. |
||
+ | :; de_BufMemType |
||
− | Starting cylinder. |
||
+ | :: Type of mem to allocate for buffers. |
||
+ | :: The second argument to AllocMem(). |
||
+ | :; de_MaxTransfer |
||
− | Max cylinder. |
||
+ | :: Max number of bytes to transfer at a time. Drivers should be written to handle requests of any length. |
||
+ | :; de_Mask |
||
− | Initial number of DOS buffers. |
||
+ | :: Address mask to block out certain memory. |
||
+ | :: Normally $00FFFFFF for DMA devices. |
||
+ | :; de_BootPri |
||
− | Type of mem to allocate for buffers. |
||
+ | :: Boot priority for autoboot. |
||
+ | :: Suggested value: zero. Keep less than five, so it won't override a boot floppy. |
||
+ | :; de_DosType |
||
− | The second argument to AllocMem(). |
||
+ | :: ASCII string showing fil esystem type; |
||
+ | :: "DOS\0" ($444F5300) is old file system |
||
+ | :: "DOS\1" ($444F5301) is fast file system |
||
+ | :: "UNI(anything)" is a Unix partition |
||
+ | ; pb_EReserved[15] |
||
− | Max number of bytes to transfer at a time. Drivers should be written to handle requests of any length. |
||
+ | : Reserved for future environment vector. |
||
− | |||
− | Address mask to block out certain memory. |
||
− | |||
− | Normally $00FF¬†FFFF for DMA devices. |
||
− | |||
− | Boot priority for autoboot. |
||
− | |||
− | Suggested value: zero. Keep less than five, so it won‚Äôt override a boot floppy. |
||
− | |||
− | ASCII string showing filesystem type; |
||
− | |||
− | ‚ÄôDOS<math>\backslash</math>0‚Äô ($444F5300) is old filesystem, ‚ÄôDOS<math>\backslash</math>1‚Äô ($444F5301) is fast file system. ‚ÄôUNI''(anything)''‚Äô is a Unix partition. |
||
− | |||
− | Reserved for future environment vector. |
||
==== FileSysHeaderBlock ==== |
==== FileSysHeaderBlock ==== |
||
Line 1,060: | Line 1,082: | ||
The current specification for the FileSysHeaderBlock follows. |
The current specification for the FileSysHeaderBlock follows. |
||
+ | ; fhb_ID |
||
− | Set to ‚ÄôFSHD‚Äô. |
||
+ | : Set to "FSHD". |
||
+ | ; fhb_SummedLongs |
||
− | Set to 64. |
||
+ | : Set to 64. |
||
+ | ; fhb_ChkSum |
||
− | Block checksum (long word sum to zero). |
||
+ | : Block checksum (long word sum to zero). |
||
+ | ; fhb_HostID |
||
− | SCSI Target ID of host. |
||
+ | : SCSI Target ID of host. |
||
+ | : This describes the initiator ID for the creator of this block. (see rdb_HostID discussion) |
||
+ | ; fhb_Next |
||
− | This describes the initiator ID for the creator of this block. (see rdb_HostID discussion) |
||
+ | : Block number of next FileSysHeaderBlock. |
||
+ | ; fhb_Flags |
||
− | Block number of next FileSysHeaderBlock. |
||
+ | : See below for defines. |
||
+ | ; fhb_Reserved1[2] |
||
− | See below for defines. |
||
+ | : Set to zero. |
||
− | |||
− | Set to zero. |
||
The following information is used to construct a FileSysEntry node in the FileSystem.resource. |
The following information is used to construct a FileSysEntry node in the FileSystem.resource. |
||
+ | ; fhb_DosType |
||
− | File system description. |
||
+ | : File system description. |
||
+ | : This is matched with a partition environment's de_DosType entry. |
||
+ | ; fhb_Version |
||
− | This is matched with a partition environment‚Äôs de_DosType entry. |
||
+ | : Release version of this load image. |
||
+ | : Usually, upper 16 bits hold version number, lower 16 bits hold revision number. |
||
+ | ; fhb_PatchFlags |
||
− | Release version of this load image. |
||
+ | : Patch flags. |
||
+ | : These are bits set for those of the following that need to be substituted into a standard device node for this file system, lsb first: e.g. 0x180 to substitute SegList & GlobalVec |
||
+ | ; fhb_Type |
||
− | Usually, upper 16 bits hold version number, lower 16 bits hold revision number. |
||
+ | : Device node type: zero. |
||
+ | ; fhb_Task |
||
− | Patch flags. |
||
+ | : Standard DOS "task" field: zero. |
||
+ | ; fhb_Lock |
||
− | These are bits set for those of the following that need to be substituted into a standard device node for this file system, lsb first: e.g. 0x180 to substitute SegList & GlobalVec |
||
+ | : Not used for devices: zero. |
||
+ | ; fhb_Handler |
||
− | Device node type: zero. |
||
+ | : File name to loadseg: zero placeholder. |
||
+ | ; fhb_StackSize |
||
− | Standard DOS ‚Äútask‚Äù field: zero. |
||
+ | : Stack size to use when starting task. |
||
+ | ; fhb_Priority |
||
− | Not used for devices: zero. |
||
+ | : Task priority when starting task. |
||
+ | ; fhb_Startup |
||
− | File name to loadseg: zero placeholder. |
||
+ | : Startup message: zero placeholder. |
||
+ | ; fhb_SegListBlocks |
||
− | Stack size to use when starting task. |
||
+ | : First of linked list of LoadSegBlocks: |
||
+ | : Note that if the fhb_PatchFlags bit for this entry is set (bit 7), the blocks pointed to by this entry must be LoadSeg'd and the resulting BPTR put in the FileSysEntry node. |
||
+ | ; fhb_GlobalVec |
||
− | Task priority when starting task. |
||
+ | : BCPL global vector when starting task Zero or -1. |
||
+ | ; fhb_Reserved2[23] |
||
− | Startup message: zero placeholder. |
||
+ | : (Those reserved by fhb_PatchFlags) |
||
+ | ; fhb_Reserved3[21] |
||
− | First of linked list of LoadSegBlocks: |
||
+ | : Set to zero. |
||
− | |||
− | Note that if the fhb_PatchFlags bit for this entry is set (bit 7), the blocks pointed to by this entry must be LoadSeg‚Äôd and the resulting BPTR put in the FileSysEntry node. |
||
− | |||
− | BCPL global vector when starting task Zero or -1. |
||
− | |||
− | (Those reserved by fhb_PatchFlags) |
||
− | |||
− | Set to zero. |
||
==== LoadSegBlock ==== |
==== LoadSegBlock ==== |
||
Line 1,118: | Line 1,156: | ||
This is the current specification of the LoadSegBlock. The end of data occurs when lsb_Next is NULL ($FFFF FFFF), and the summed data is exhausted. |
This is the current specification of the LoadSegBlock. The end of data occurs when lsb_Next is NULL ($FFFF FFFF), and the summed data is exhausted. |
||
+ | ; lsb_ID |
||
− | Set to ‚ÄôLSEG‚Äô. |
||
+ | : Set to "LSEG". |
||
+ | ; lsb_SummedLongs |
||
− | Size of this checksummed structure. |
||
+ | : Size of this checksummed structure. |
||
+ | : Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, like bbb_SummedLongs. |
||
+ | ; lsb_ChkSum |
||
− | Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, like bbb_SummedLongs. |
||
+ | : Block checksum (longword sum to zero). |
||
+ | ; lsb_HostID |
||
− | Block checksum (longword sum to zero). |
||
+ | : SCSI Target ID of host. |
||
+ | : This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion) |
||
+ | ; lsb_Next |
||
− | SCSI Target ID of host. |
||
+ | : Block number of the next LoadSegBlock. |
||
+ | ; lsb_LoadData |
||
− | This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion) |
||
+ | : Data for "loadseg". |
||
+ | : The data starts here and continues as long as indicated by lsb_SummedLongs - 5: e.g. if lsb_SummedLongs is 128 (ie. for 512 byte blocks), 123 longs of data are valid here. |
||
+ | ==== filesysres.h ==== |
||
− | Block number of the next LoadSegBlock. |
||
+ | The FileSysResource is created by the first code that needs to use it. It is added to the resource list for others to use. (Checking and creation should be performed while Forbid() is in effect). The resource is created by the system early on in the initialization sequence. |
||
− | Data for ‚Äúloadseg‚Äù. |
||
+ | '''FileSysResource''' |
||
− | The data starts here and continues as long as indicated by lsb_SummedLongs-5: e.g. if lsb_SummedLongs is 128 (ie. for 512 byte blocks), 123 longs of data are valid here. |
||
+ | ; fsr_Node |
||
− | ==== filesysres.h and .i ==== |
||
+ | : On resource list with the name "FileSystem.resource". |
||
+ | ; fsr_Creator |
||
− | The FileSysResource is created by the first code that needs to use it. It is added to the resource list for others to use. (Checking and creation should be performed while Forbid() is in effect). Under Release 2 the resource is created by the system early on in the initialization sequence. Under 1.3 it is the responsibility of the first RDB driver to create it. |
||
+ | : Name of creator of this resource. |
||
+ | ; fsr_FileSysEntries |
||
− | On resource list with the name ‚ÄúFileSystem.resource‚Äù. |
||
+ | : List of FileSysEntry structs. |
||
+ | '''FileSysEntry''' |
||
− | Name of creator of this resource. |
||
+ | ; fse_Node |
||
− | List of FileSysEntry structs. |
||
+ | : On fsr_FileSysEntries list; ln_Name is of creator of this entry. |
||
+ | ; fse_DosType |
||
− | On fsr_FileSysEntries list; ln_Name is of creator of this entry. |
||
+ | : DosType of this file system. |
||
+ | ; fse_Version |
||
− | DosType of this file system. |
||
+ | : Release version of this file system. |
||
+ | : Usually, upper 16 bits hold version number, lower 16 bits hold revision number. |
||
− | Release version of this file system. |
||
+ | ; fse_PatchFlags |
||
− | Usually, upper 16 bits hold version number, lower 16 bits hold revision number. |
||
+ | : Bits set for those of the following that need to be substituted into a standard device node for this file system: e.g. $180 for substitute SegList & GlobalVec. |
||
+ | ; fse_Type |
||
− | Bits set for those of the following that need to be substituted into a standard device node for this file system: e.g. $180 for substitute SegList & GlobalVec. |
||
+ | : Device node type: zero. |
||
+ | ; fse_Task |
||
− | Device node type: zero. |
||
+ | : Standard DOS "task" field. |
||
+ | ; fse_Lock |
||
− | Standard DOS ‚Äútask‚Äù field. |
||
+ | : Not used for devices: zero. |
||
+ | ; fse_Handler |
||
− | Not used for devices: zero. |
||
+ | : File name to loadseg (if SegList is NULL). |
||
+ | ; fse_StackSize |
||
− | File name to loadseg (if SegList is NULL). |
||
+ | : Stack size to use when starting task. |
||
+ | ; fse_Priority |
||
− | Stack size to use when starting task. |
||
+ | : Task priority when starting task. |
||
+ | ; fse_Startup |
||
− | Task priority when starting task. |
||
+ | : Startup message: FileSysStartupMsg for disks. |
||
+ | ; fse_SegList |
||
− | Startup message: FileSysStartupMsg for disks. |
||
+ | : Segment of code to run to start new task. |
||
+ | ; fse_GlobalVec |
||
− | Segment of code to run to start new task. |
||
+ | : BCPL global vector when starting task. |
||
− | |||
− | BCPL global vector when starting task. |
||
No more entries need exist than those implied by fse_PatchFlags, so entries do not have a fixed size. |
No more entries need exist than those implied by fse_PatchFlags, so entries do not have a fixed size. |
||
− | For additional information on initializing and booting a Rigid Disk Block |
+ | For additional information on initializing and booting a Rigid Disk Block file system device, see the [[SCSI_Device|SCSI Device]]. Writers of drivers for expansion devices that perform their own DMA (direct memory access) should consult the Exec chapters and Autodocs for information on processor cache control functions including CachePreDMA() and CachePostDMA(). |
− | See the following include files |
+ | See the following include files for additional notes and related structures: <libraries/configvers.h>, <libraries/configregs.h>, <devices/hardblocks.h>, <resources/filesysres.h> and <libraries/filehandler.h>. |
== Function Reference == |
== Function Reference == |
||
+ | The following are brief descriptions of the expansion library functions that are useful for expansion device drivers and related applications. See the SDK for the complete descriptions of all the expansion library functions. |
||
+ | {| class="wikitable" |
||
− | |||
+ | ! Function |
||
− | The following are brief descriptions of the expansion library functions that are useful for expansion device drivers and related applications. See the ''Amiga ROM Kernel Reference Manual: Includes and Autodocs'' for the complete descriptions of all the expansion library functions. |
||
+ | ! Description |
||
− | |||
+ | |- |
||
− | [h] Expansion Library Functions |
||
+ | | FindConfigDev() |
||
− | |||
+ | | Returns a pointer to the ConfigDev structure of a given expansion device. |
||
− | <table> |
||
+ | |- |
||
− | <thead> |
||
+ | | MakeDosNode() |
||
− | <tr class="header"> |
||
+ | | Creates the DOS device node for disk and similar expansion devices. |
||
− | <th align="left">'''Function'''</th> |
||
+ | |- |
||
− | <th align="left">'''Description'''</th> |
||
+ | | AddDosNode() |
||
− | </tr> |
||
+ | | Adds a DOS device node to the system. |
||
− | </thead> |
||
+ | |- |
||
− | <tbody> |
||
+ | | AddBootNode() |
||
− | <tr class="odd"> |
||
+ | | Adds an autobooting DOS device node to the system. |
||
− | <td align="left">FindConfigDev()</td> |
||
+ | |- |
||
− | <td align="left">Returns a pointer to the ConfigDev structure of a</td> |
||
+ | | GetCurrentBinding() |
||
− | </tr> |
||
+ | | Returns a pointer to the CurrentBinding structure of a given device. |
||
− | <tr class="even"> |
||
+ | |- |
||
− | <td align="left"></td> |
||
+ | | SetCurrentBinding() |
||
− | <td align="left">given expansion device.</td> |
||
+ | | Set up for reading the CurrentBinding with GetCurrentBinding(). |
||
− | </tr> |
||
+ | |- |
||
− | <tr class="odd"> |
||
+ | | ObtainCurrentBinding() |
||
− | <td align="left">MakeDosNode()</td> |
||
+ | | Protect the ConfigDev structure with a semaphore. |
||
− | <td align="left">Creates the DOS device node for disk and similar</td> |
||
+ | |- |
||
− | </tr> |
||
+ | | ReleaseCurrentBinding() |
||
− | <tr class="even"> |
||
+ | | Release a semaphore on ConfigDev set up with ObtainCurrentBinding(). |
||
− | <td align="left"></td> |
||
+ | |} |
||
− | <td align="left">expansion devices.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">AddDosNode()</td> |
||
− | <td align="left">Adds a DOS device node to the system.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">AddBootNode()</td> |
||
− | <td align="left">Adds an autobooting DOS device node to the</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left"></td> |
||
− | <td align="left">system (V36).</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">GetCurrentBinding()</td> |
||
− | <td align="left">Returns a pointer to the CurrentBinding structure</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left"></td> |
||
− | <td align="left">of a given device.</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">SetCurrentBinding()</td> |
||
− | <td align="left">Set up for reading the CurrentBinding with</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left"></td> |
||
− | <td align="left">GetCurrentBinding().</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left">ObtainCurrentBinding()</td> |
||
− | <td align="left">Protect the ConfigDev structure with a semaphore.</td> |
||
− | </tr> |
||
− | <tr class="odd"> |
||
− | <td align="left">ReleaseCurrentBinding()</td> |
||
− | <td align="left">Release a semaphore on ConfigDev set up</td> |
||
− | </tr> |
||
− | <tr class="even"> |
||
− | <td align="left"></td> |
||
− | <td align="left">with ObtainCurrentBinding().</td> |
||
− | </tr> |
||
− | </tbody> |
||
− | </table> |
Latest revision as of 14:58, 20 September 2018
This page is not yet fully updated to AmigaOS 4.x some of the information contained here may not be applicable in part or totally. |
Code samples on this page are not yet updated to AmigaOS 4.x some of them may be obsolete or incompatible with AmigaOS 4.x. |
Contents
Expansion Library
Amiga RAM expansion boards and other expansion bus peripherals are designed to reside at dynamically assigned address spaces within the system. The configuration and initialization of these expansion peripherals is performed by the expansion.library.
AUTOCONFIG
The Amiga AUTOCONFIG protocol is designed to allow the dynamic assignment of available address space to expansion boards, eliminating the need for user configuration via jumpers. Such expansion boards include memory boards, hard disk controllers, network interfaces, and other special purpose expansion devices. Some expansion devices, such as RAM boards, require no special driver software. Other types of expansion devices may use a disk-loaded driver from the "DEVS:" or "SYS:Expansion drawer", or an on-board ROM driver (for example, a self-booting hard disk controller).
This article will concentrate on the software and driver side of Zorro expansion devices, using a Zorro-II device as an example. Zorro-III devices have additional identifying bits and memory size options which are described in the Zorro-III hardware documentation. For more information on Zorro-II and Zorro-III expansion hardware, see the "Zorro Expansion Bus" appendix of the Amiga Hardware Reference Manual, 3rd Edition. For additional information specific to Zorro-II boards, see the A500/A2000 Technical Reference Manual.
AUTOCONFIG occurs whenever the Amiga is powered on or reset. During early system initialization, expansion.library identifies the expansion boards that are installed in the Amiga and dynamically assigns an appropriate address range for each board to reside at. During this AUTOCONFIG process, each expansion board first appears in turn at $E80000 (Zorro-II) or $FF000000 (Zorro-III), presenting readable identification information, generally in a PAL or a ROM, at the beginning of the board. The identification includes the size of the board, its address space preferences, type of board (memory or other), and a unique Hardware Manufacturer Number assigned by the AmigaOS development team.
The unique Hardware Manufacturer number, in combination with a vendor-supplied product number, provides a way for boards to be identified and for disk-based drivers to be matched with expansion boards. All expansion boards for the Amiga must implement the AUTOCONFIG protocol.
The Expansion Sequence
During system initialization, expansion.library configures each expansion peripheral in turn by examining its identification information and assigning it an appropriate address space. If the board is a RAM board, it can be added to the system memory list to make the RAM available for allocation by system tasks.
Descriptions of all configured boards are kept in a private ExpansionBase list of ConfigDev structures. A board's identification information is stored in the ExpansionRom sub-structure contained within the ConfigDev structure. Applications can examine individual or all ConfigDev structures with the expansion.library function FindConfigDev().
The ConfigDev structure is defined in <libraries/configvars.h>:
struct ConfigDev { struct Node cd_Node; UBYTE cd_Flags; /* (read/write) */ UBYTE cd_Pad; /* reserved */ struct ExpansionRom cd_Rom; /* copy of board's expansion ROM */ APTR cd_BoardAddr; /* where in memory the board was placed */ ULONG cd_BoardSize; /* size of board in bytes */ UWORD cd_SlotAddr; /* which slot number (PRIVATE) */ UWORD cd_SlotSize; /* number of slots (PRIVATE) */ APTR cd_Driver; /* pointer to node of driver */ struct ConfigDev *cd_NextCD; /* linked list of drivers to config */ ULONG cd_Unused[4]; /* for whatever the driver wants */ }; /* cd_Flags */ #define CDB_SHUTUP 0 /* this board has been shut up */ #define CDB_CONFIGME 1 /* this board needs a driver to claim it */ #define CDF_SHUTUP 0x01 #define CDF_CONFIGME 0x02
The ExpansionRom structure within ConfigDev contains the board identification information that is read from the board's PAL or ROM at expansion time. The actual onboard identification information of a Zorro-II board appears in the high nibbles of the first $40 words at the start of the board. Except for the first nibble pair ($00/$02) which when combined form er_Type, the information is stored in inverted ("ones-complement") format where binary 1's are represented as 0's and 0's are represented as 1's. The expansion.library reads the nibbles of expansion information from the board, un-inverts them (except for $00/$02 er_Type which is already un-inverted), and combines them to form the elements of the ExpansionRom structure.
The ExpansionRom structure is defined in <libraries/configregs.h>:
struct ExpansionRom { /* First 16 bytes of the expansion ROM */ UBYTE er_Type; /* Board type, size and flags */ UBYTE er_Product; /* Product number, assigned by manufacturer */ UBYTE er_Flags; /* Flags */ UBYTE er_Reserved03; /* Must be zero ($ff inverted) */ UWORD er_Manufacturer; /* Unique ID,ASSIGNED BY AmigaOS development team */ ULONG er_SerialNumber; /* Available for use by manufacturer */ UWORD er_InitDiagVec; /* Offset to optional "DiagArea" structure */ UBYTE er_Reserved0c; UBYTE er_Reserved0d; UBYTE er_Reserved0e; UBYTE er_Reserved0f; };
Simple Expansion Library Example
The following example uses FindConfigDev() to print out information about all of the configured expansion peripherals in the system. FindConfigDev() searches the system's list of ConfigDev structures and returns a pointer to the ConfigDev structure matching a specified board:
newconfigdev = struct ConfigDev *FindConfigDev( struct ConfigDev *oldconfigdev, LONG manufacturer, LONG product )
The oldconfigdev argument may be set to NULL to begin searching at the top of the system list or, if it points to a valid ConfigDev, searching will begin after that entry in the system list. The manufacturer and product arguments can be set to search for a specific manufacturer and product by number, or, if these are set to -1, the function will match any board.
;/* findboards.c - Execute me to compile me with SAS C 5.10 LC -b1 -cfistq -v -y -j73 findboards.c Blink FROM LIB:c.o,findboards.o TO findboards LIBRARY LIB:LC.lib,LIB:Amiga.lib quit */ #include <exec/types.h> #include <exec/memory.h> #include <libraries/dos.h> #include <libraries/configvars.h> #include <clib/exec_protos.h> #include <clib/expansion_protos.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif struct Library *ExpansionBase = NULL; void main(int argc, char **argv) { struct ConfigDev *myCD; UWORD m,i; UBYTE p,f,t; if((ExpansionBase=OpenLibrary("expansion.library",0L))==NULL) exit(RETURN_FAIL); /*--------------------------------------------------*/ /* FindConfigDev(oldConfigDev,manufacturer,product) */ /* oldConfigDev = NULL for the top of the list */ /* manufacturer = -1 for any manufacturer */ /* product = -1 for any product */ /*--------------------------------------------------*/ myCD = NULL; while(myCD=FindConfigDev(myCD,-1L,-1L)) /* search for all ConfigDevs */ { printf("\n---ConfigDev structure found at location $%lx---\n",myCD); /* These values were read directly from the board at expansion time */ printf("Board ID (ExpansionRom) information:\n"); t = myCD->cd_Rom.er_Type; m = myCD->cd_Rom.er_Manufacturer; p = myCD->cd_Rom.er_Product; f = myCD->cd_Rom.er_Flags; i = myCD->cd_Rom.er_InitDiagVec; printf("er_Manufacturer =%d=$%04x=(~$%4x)\n",m,m,(UWORD)~m); printf("er_Product =%d=$%02x=(~$%2x)\n",p,p,(UBYTE)~p); printf("er_Type =$%02x",myCD->cd_Rom.er_Type); if(myCD->cd_Rom.er_Type & ERTF_MEMLIST) printf(" (Adds memory to free list)\n"); else printf("\n"); printf("er_Flags =$%02x=(~$%2x)\n",f,(UBYTE)~f); printf("er_InitDiagVec =$%04x=(~$%4x)\n",i,(UWORD)~i); /* These values are generated when the AUTOCONFIG(tm) software * relocates the board */ printf("Configuration (ConfigDev) information:\n"); printf("cd_BoardAddr =$%lx\n",myCD->cd_BoardAddr); printf("cd_BoardSize =$%lx (%ldK)\n", myCD->cd_BoardSize,((ULONG)myCD->cd_BoardSize)/1024); printf("cd_Flags =$%x",myCD->cd_Flags); if(myCD->cd_Flags & CDF_CONFIGME) printf("\n"); else printf(" (driver clears CONFIGME bit)\n"); } CloseLibrary(ExpansionBase); }
Expansion Board Drivers
The Amiga operating system contains support for matching up disk-based drivers with AUTOCONFIG boards. Though such drivers are commonly Exec devices, this is not required. The driver may, for instance, be an Exec library or task. The system software also supports the initialization of onboard ROM driver software.
Disk Based Drivers
Disk-based expansion board drivers and their icons are generally placed in the "SYS:Expansion" drawer of the user's "SYS:" disk or partition. The icon Tool Type field must contain the unique Hardware Manufacturer number, and the Product number of the expansion board(s) the driver is written for. (For more about icon Tool Type fields refer to Icon Library.)
The "BindDrivers" command issued during the disk startup-sequence attempts to match disk-based drivers with their expansion boards. To do this, "BindDrivers" looks in the Tool Types field of all icon files in "SYS:Expansion". If the Tool Type "PRODUCT" is found in the icon, then this is an icon file for a driver. "BindDrivers" will then attempt to match the manufacturer and product number in this PRODUCT Tool Type with those of a board that was configured at expansion time.
For example, suppose you are manufacturer #1019. You have two products, #1 and #2 which both use the same driver. The icon for your driver for these two products would have a Tool Type set to "PRODUCT=1019/1|1019/2". This means: I am an icon for a driver that works with product number 1 or 2 from manufacturer 1019, now bind me. Spaces are not legal. Here are two other examples:
PRODUCT=1208/11 | is the Tool Type for a driver for product 11 from manufacturer number 1208. |
PRODUCT=1017 | is the Tool Type for a driver for any product from manufacturer number 1017. |
If a matching board is found for the disk-based driver, the driver code is loaded and then initialized with the Exec InitResident() function. From within its initialization code, the driver can get information about the board it is bound to by calling the expansion.library function GetCurrentBinding(). This function will provide the driver with a copy of a CurrentBinding structure, including a pointer to a ConfigDev structure (possibly linked to additional ConfigDevs via the cd_NextCD field) of the expansion board(s) that matched the manufacturer and product IDs.
/* this structure is used by GetCurrentBinding() and SetCurrentBinding() */ struct CurrentBinding { struct ConfigDev *cb_ConfigDev; /* first configdev in chain */ UBYTE * cb_FileName; /* file name of driver */ UBYTE * cb_ProductString; /* product # string */ UBYTE ** cb_ToolTypes; /* tooltypes from disk object */ };
GetCurrentBinding() allows the driver to find out the base address and other information about its board(s). The driver must unset the CONFIGME bit in the cd_Flags field of the ConfigDev structure for each board it intends to drive, and record the driver's Exec node pointer in the cd_Driver structure. This node should contain the LN_NAME and LN_TYPE (i.e., NT_DEVICE, NT_TASK, etc.) of the driver.
Important Note |
---|
The GetCurrentBinding() function, and driver binding in general, must be bracketed by an ObtainConfigBinding() and ReleaseConfigBinding() semaphore. The "BindDrivers" command obtains this semaphore and performs a SetCurrentBinding() before calling InitResident(), allowing the driver to simply do a GetCurrentBinding(). |
Full source code for a disk-based Expansion or "DEVS:" sample device driver may be found in Example Device. Autodocs for expansion.library functions may be found in the SDK.
Expansion Drivers and DOS
Two other expansion.library functions commonly used by expansion board drivers are MakeDosNode() and AddDosNode(). These functions allow a driver to create and add a DOS device node (for example "DH0:") to the system. AddBootNode() can be used to add an autobooting DOS device node.
MakeDosNode() requires an initialized structure of environment information for creating a DOS device node. The format of the function is:
struct DeviceNode *deviceNode = MakeDosNode(parameterPkt);
The parameterPkt argument is a pointer to an initialized packet of environment parameters.
The parameter packet for MakeDosNode() consists of four longwords followed by a DosEnvec structure:
;----------------------------------------------------------------------- ; ; Layout of parameter packet for MakeDosNode ; ;----------------------------------------------------------------------- * The packet for MakeDosNode starts with the following four * longwords, directly followed by a DosEnvec structure. APTR dosName ; Points to a DOS device name (ex. 'RAM1',0) APTR execName ; Points to device driver name (ex. 'ram.device',0) ULONG unit ; Unit number ULONG flags ; OpenDevice flags * The DosEnvec disk "environment" is a longword array that describes the * disk geometry. It is variable sized, with the length at the beginning. * Here are the constants for a standard geometry. * See libraries/filehandler.i for additional notes. STRUCTURE DosEnvec,0 ULONG de_TableSize ; Size of Environment vector ULONG de_SizeBlock ; in longwords: standard value is 128 ULONG de_SecOrg ; not used; must be 0 ULONG de_Surfaces ; # of heads (surfaces). drive specific ULONG de_SectorPerBlock ; not used; must be 1 ULONG de_BlocksPerTrack ; blocks per track. drive specific ULONG de_Reserved ; DOS reserved blocks at start of partition. ULONG de_PreAlloc ; DOS reserved blocks at end of partition ULONG de_Interleave ; usually 0 ULONG de_LowCyl ; starting cylinder. typically 0 ULONG de_HighCyl ; max cylinder. drive specific ULONG de_NumBuffers ; Initial # DOS of buffers. ULONG de_BufMemType ; type of mem to allocate for buffers ULONG de_MaxTransfer ; Max number of bytes to transfer at a time ULONG de_Mask ; Address Mask to block out certain memory LONG de_BootPri ; Boot priority for autoboot ULONG de_DosType ; ASCII (HEX) string showing file system type; ; 0X444F5300 is old file system, ; 0X444F5301 is fast file system ULONG de_Baud ; Baud rate for serial handler ULONG de_Control ; Control word for handler/file system ; (used as file system/handler desires) ULONG de_BootBlocks ; Number of blocks containing boot code ; (for non-AmigaDOS file systems) LABEL DosEnvec_SIZEOF
After making a DOS device node, drivers (except for autoboot drivers) use AddDosNode(deviceNode) to add their node to the system. Autoboot drivers will instead use the AddBootNode() function to add a BootNode to the ExpansionBase.eb_MountList.
ROM Based and Autoboot Drivers
The system software supports the initialization of ROM drivers residing on expansion peripherals, including the ability for drivers to provide a DOS node which the system can boot from. This feature is known as Autoboot.
Automatic boot from a ROM-equipped expansion board is accomplished before DOS is initialized. 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, even allowing the initialization of a disk operating system other than the Amiga's dos.library. ROM-based drivers contain several special entry points that are called at different stages of system initialization. These three stages are known as DIAG, ROMTAG INIT and BOOT.
Events At DIAG Time
When your AUTOCONFIG hardware board is configured by the expansion initialization routine, its ExpansionRom structure is copied into the ExpansionRom subfield of a ConfigDev structure. This ConfigDev structure will be linked to the expansion.library's private list of configured boards.
After the board is configured, the er_Type field of its ExpansionRom structure is checked. The DIAGVALID bit set declares that there is a valid DiagArea (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.
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; UBYTE er_Reserved0f; };
Now expansion knows that there is a DiagArea, and knows where it is.
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; UWORD da_Name; UWORD da_Reserved01; UWORD da_Reserved02; }; /* da_Config definitions */ #define DAC_BUSWIDTH 0xC0 /* two bits for bus width */ #define DAC_NIBBLEWIDE 0x00 #define DAC_BYTEWIDE 0x40 /* invalid for 1.3 - see note below */ #define DAC_WORDWIDE 0x80 #define DAC_BOOTTIME 0x30 /* two bits for when to boot */ #define DAC_NEVER 0x00 /* obvious */ #define DAC_CONFIGTIME 0x10 /* call da_BootPoint when first configuring the device */ #define DAC_BINDTIME 0x20 /* run when binding drivers to boards */
Next, expansion tests the first byte 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, starting at beginning of the DiagArea structure.
The copy will include the DiagArea structure itself, and typically will also include the da_DiagPoint ROM/diagnostic routine, a Resident structure (romtag), a device driver (or at least the device initialization tables or structures which need patching), and the da_BootPoint routine. In addition, the BootNode and parameter packet for MakeDosNode() may be included in the copy area for Diag-time patching. Strings such as DOS and Exec device names, library names, and the romtag ID string may also be included in the copy area so that both position-independent ROM code and position-independent routines in the copy area may reference them PC relative.
The copy will be made either nibblewise, or wordwise, according to the BUSWIDTH subfield of da_Config. Note that the da_BootPoint offset must be non-NULL, or else no copy will occur.
The following illustrates an example Diag copy area, and specifies the various fields which should be coded as relative offsets for later patching by your DiagPoint routine.
Example DiagArea Copy in RAM DiagStart: ; a struct DiagArea CCFF ; da_Config, da_Flags SIZE ; da_Size - coded as EndCopy-DiagStart DIAG ; da_DiagPoint - coded as DiagEntry-DiagStart BOOT ; da_BootPoint - coded as BootEntry-DiagStart NAME ; da_Name - coded as DevName-DiagStart 0000 ; da_Reserved01 - Above fields above are supposed 0000 ; da_Reserved02 to be relative. No patching needed Romtag: rrrr ; a struct Resident (``Romtag'') ... RT_MATCHTAG, RT_ENDSKIP, RT_NAME and RT_IDSTRING ... addresses are coded relatively as label-DiagStart. ... The RT_INIT vector is coded as a relative offset ... from the start of the ROM. DiagEntry patches these. DevName: ssss..0 ; The name string for the exec device IdString: iiii..0 ; The ID string for the Romtag BootEntry: BBBB ; Boot-time code ... DiagEntry: DDDD ; Diag-time code (position independent) ... When called, performs patching of the relative- coded addresses which need to be absolute. OtherData: dddd ; Device node or structs/tables (patch names, vectors) bbbb ; BootNode (patch ln_Name and bn_DeviceNode) pppp ; MakeDosNode packet (patch dos and exec names) ssss ; other name, ID, and library name strings ... EndCopy:
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 – i.e., it is stored as a longword at the address er_Reserved0c.
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 code and strings, as well as performing any diagnostic functions essential to the operation of its associated AUTOCONFIG board. The structures which require patching are located within the copy area so that they can be patched at this time. Patching is required because many of the structures involved require absolute pointers to such things as name strings and code, but the absolute locations of the board and the RAM copy area are not known when code the structures.
The patching may be accomplished by coding pointers which require absolute addresses instead as relative offsets from either the start of the DiagArea structure, or the start of the board's ROM (depending on whether the final absolute pointer will point to a RAM or ROM location). The Diag routine is passed both the actual base address of the board, and the address of the Diag copy area in RAM. The routine can then patch the structures in the Diag copy area by adding the appropriate address to resolve each pointer.
Example DiagArea and Diag patching routine:
** ** Sample autoboot code fragment ** ** These are the calling conventions for the Diag routine ** ** A7 -- points to at least 2K of stack ** A6 -- ExecBase ** A5 -- ExpansionBase ** A3 -- your board's ConfigDev structure ** A2 -- Base of diag/init area that was copied ** A0 -- Base of your board ** ** Your Diag routine should return a non-zero value in D0 for success. ** If this value is NULL, then the diag/init area that was copied ** will be returned to the free memory pool. ** INCLUDE "exec/types.i" INCLUDE "exec/nodes.i" INCLUDE "exec/resident.i" INCLUDE "libraries/configvars.i" ; LVO's resolved by linking with library amiga.lib XREF _LVOFindResident ROMINFO EQU 1 ROMOFFS EQU $0 * ROMINFO defines whether you want the AUTOCONFIG information in * the beginning of your ROM (set to 0 if you instead have PALS * providing the AUTOCONFIG information instead) * * ROMOFFS is the offset from your board base where your ROMs appear. * Your ROMs might appear at offset 0 and contain your AUTOCONFIG * information in the high nibbles of the first $40 words ($80 bytes). * Or, your autoconfig ID information may be in a PAL, with your * ROMs possibly being addressed at some offset (for example $2000) * from your board base. This ROMOFFS constant will be used as an * additional offset from your configured board address when patching * structures which require absolute pointers to ROM code or data. *----- We'll store Version and Revision in serial number VERSION EQU 37 ; also the high word of serial number REVISION EQU 1 ; also the low word of serial number * See the Amiga Hardware Manual for more info. MANUF_ID EQU 2011 ; CBM assigned (2011 for hackers only) PRODUCT_ID EQU 1 ; Manufacturer picks product ID BOARDSIZE EQU $40000 ; How much address space board decodes SIZE_FLAG EQU 3 ; Autoconfig 3-bit flag for BOARDSIZE ; 0=$800000(8meg) 4=$80000(512K) ; 1=$10000(64K) 5=$100000(1meg) ; 2=$20000(128K) 6=$200000(2meg) ; 3=$40000(256K) 7=$400000(4meg) CODE ******* RomStart *************************************************** ********************************************************************** RomStart: IFGT ROMINFO ; ; ExpansionRom structure ; ; Note - If you implement your ExpansionRom and ExpansionControl ; with PALS, then you can comment out everything until DiagStart: ; (ie. Make ROMID EQU 0) * ; High nibbles of first two words ($00,$02) are er_Type (not inverted) ; er_Type dc.w $D000 ; 11xx normal board type ; xx0x not in memory free list ; xxx1 Diag valid (has driver) dc.w (SIZE_FLAG<<12)&$7000 ; 0xxx not chained ; xnnn flags board size * ; High nibbles of next two words are er_Product * ; These are inverted (~), as are all other words except $40 and $42 ; er_Product dc.w (~(PRODUCT_ID<<8))&$f000,(~(PRODUCT_ID<<12))&$f000 ; er_Flags dc.w (~$C000)&$f000 ; ~1xxx board is moveable ; ~x1xx board can't be shut up dc.w (~0)&$f000 ; dc.w (~0)&$f000,(~0)&$f000 ; er_Reserved03 ; er_Manufacturer dc.w (~(MANUF_ID))&$f000,(~(MANUF_ID<<4))&$f000 dc.w (~(MANUF_ID<<8))&$f000,(~(MANUF_ID<<12))&$f000 ; er_SerialNumber dc.w (~(VERSION))&$f000,(~(VERSION<<4))&$f000 dc.w (~(VERSION<<8))&$f000,(~(VERSION<<12))&$f000 dc.w (~(REVISION))&$f000,(~(REVISION<<4))&$f000 dc.w (~(REVISION<<8))&$f000,(~(REVISION<<12))&$f000 ; er_InitDiagVec dc.w (~((DiagStart-RomStart)))&$f000 dc.w (~((DiagStart-RomStart)<<4))&$f000 dc.w (~((DiagStart-RomStart)<<8))&$f000 dc.w (~((DiagStart-RomStart)<<12))&$f000 dc.w (~0)&$f000,(~0)&$f000 ; er_Reserved0c dc.w (~0)&$f000,(~0)&$f000 ; er_Reserved0d dc.w (~0)&$f000,(~0)&$f000 ; er_Reserved0e dc.w (~0)&$f000,(~0)&$f000 ; er_Reserved0f IFNE *-RomStart-$40 FAIL "ExpansionRom structure not the right size" ENDC ;Note: nibbles $40 and $42 are not to be inverted dc.w (0)&$f000,(0)&$f000 ; ec_Interrupt (no interrupts) dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved11 dc.w (~0)&$f000,(~0)&$f000 ; ec_BaseAddress (write only) dc.w (~0)&$f000,(~0)&$f000 ; ec_Shutup (write only) dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved14 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved15 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved16 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved17 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved18 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved19 dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1a dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1b dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1c dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1d dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1e dc.w (~0)&$f000,(~0)&$f000 ; ec_Reserved1f IFNE *-RomStart-$80 FAIL "Expansion Control structure not the right size" ENDC ENDC ;ROMINFO ******* DiagStart ************************************************** DiagStart: ; This is the DiagArea structure whose relative offset from ; your board base appears as the Init Diag vector in your ; autoconfig ID information. This structure is designed ; to use all relative pointers (no patching needed). dc.b DAC_WORDWIDE+DAC_CONFIGTIME ; da_Config dc.b 0 ; da_Flags dc.w EndCopy-DiagStart ; da_Size dc.w DiagEntry-DiagStart ; da_DiagPoint dc.w BootEntry-DiagStart ; da_BootPoint dc.w DevName-DiagStart ; da_Name dc.w 0 ; da_Reserved01 dc.w 0 ; da_Reserved02 ******* Resident Structure ***************************************** Romtag: dc.w RTC_MATCHWORD ; UWORD RT_MATCHWORD rt_Match: dc.l Romtag-DiagStart ; APTR RT_MATCHTAG rt_End: dc.l EndCopy-DiagStart ; 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 DevName-DiagStart ; APTR RT_NAME rt_Id: dc.l IdString-DiagStart ; APTR RT_IDSTRING rt_Init: dc.l Init-RomStart ; APTR RT_INIT ******* Strings referenced in Diag Copy area ************************ DevName: dc.b 'abc.device',0 ; Name string IdString dc.b 'abc ',48+VERSION,'.',48+REVISION ; Id string DosName: dc.b 'dos.library',0 ; DOS library name DosDevName: dc.b 'ABC',0 ; dos device name for MakeDosNode() ; (dos device will be ABC:) ds.w 0 ; word align ******* DiagEntry ************************************************** ********************************************************************** * * success = DiagEntry(BoardBase,DiagCopy, configDev) * d0 a0 a2 a3 * * Called by expansion architecture to relocate any pointers * in the copied diagnostic area. We will patch the romtag. * If you have pre-coded your MakeDosNode packet, BootNode, * or device initialization structures, they would also need * to be within this copy area, and patched by this routine. * ********************************************************************** DiagEntry: lea patchTable-RomStart(a0),a1 ; find patch table adda.l #ROMOFFS,a1 ; adjusting for ROMOFFS * Patch relative pointers to labels within DiagCopy area * by adding Diag RAM copy address. These pointers were coded as * long relative offsets from base of the DiagArea structure. * dpatches: move.l a2,d1 ;d1=base of ram Diag copy dloop: move.w (a1)+,d0 ;d0=word offs. into Diag needing patch bmi.s bpatches ;-1 is end of word patch offset table add.l d1,0(a2,d0.w) ;add DiagCopy addr to coded rel. offset bra.s dloop * Patches relative pointers to labels within the ROM by adding * the board base address + ROMOFFS. These pointers were coded as * long relative offsets from RomStart. * bpatches: move.l a0,d1 ;d1 = board base address add.l #ROMOFFS,d1 ;add offset to where your ROMs are rloop: move.w (a1)+,d0 ;d0=word offs. into Diag needing patch bmi.s endpatches ;-1 is end of patch offset table add.l d1,0(a2,d0.w) ;add ROM address to coded relative offset bra.s rloop endpatches: moveq.l #1,d0 ; indicate "success" rts ******* BootEntry ************************************************** ********************************************************************** BootEntry: lea DosName(PC),a1 ; 'dos.library',0 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 * * End of the Diag copy area which is copied to RAM * EndCopy: ************************************************************************* ************************************************************************* * * Beginning of ROM driver code and data that is accessed only in * the ROM space. This must all be position-independent. * patchTable: * Word offsets into Diag area where pointers need Diag copy address added dc.w rt_Match-DiagStart dc.w rt_End-DiagStart dc.w rt_Name-DiagStart dc.w rt_Id-DiagStart dc.w -1 * Word offsets into Diag area where pointers need boardbase+ROMOFFS added dc.w rt_Init-DiagStart dc.w -1 ******* Romtag InitEntry ********************************************** ************************************************************************* Init: ; After Diag patching, our romtag will point to this ; routine in ROM so that it can be called at Resident ; initialization time. ; This routine will be similar to a normal expansion device ; initialization routine, but will MakeDosNode then set up a ; BootNode, and Enqueue() on eb_MountList. ; rts ; Rest of your position-independent device code goes here. END
Your da_DiagPoint 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 utility.library's private list of boards.
It may help to see just how a card's ROM AUTOCONFIG information corresponds to the ExpansionRom structure. This chart shows the contents of on-card memory for a fictional expansion card. Note that the ExpansionRom.Flags field ($3F in addresses $08/$0A below) is shown interpreted in its inverted form of $3F. Once the value is uninverted to become $C0, you should use the #defines in <libraries/configregs.h> to interpret it.
Sample Zorro-II AUTOCONFIG ROM Information Viewed as a Hex Dump
FLAG AND FIELD DEFINITIONS THIS BOARD ----------------------------------------------------------------- 1xxx chained 11 = Normal type x111 size Don't addmem 000=8meg,001=64K,010=128K,etc. ROM Vector Valid 11xx type / 1xxx nopref Not chained xx1x addmem / x1xx canshut Size 256K xxx1 ROM / xx11 reserved Product#=~$FE=1 \ / ~Prod# / Flags=~$3F=$C0 \ / / \ / res. reserved Prefer exp space 0000: D0003000 F000E000 3000F000 F000F000 Can't be shut up ----------------------------------------------------------------- ~Manufacturer# ~HiWord Serial# Manu#=~$F824=$7DB=2011 / / \ \ / / \ \ HiSer=~$FFDA=$0025=37 0010: F0008000 20004000 F000F000 D000A000 ----------------------------------------------------------------- ~LoWord Serial# ~Rom Vector LoSer=~$FFFE=$0001=1 / / \ \ / / \ \ Rom Vector=~$FF7F=$80 0020: F000F000 F000E000 F000F000 7000F000 from board base -----------------------------------------------------------------
The AUTOCONFIG information from the above card would appear as follows in an ExpansionRom structure:
Nibble Pairs | ExpansionRom Field | Value |
---|---|---|
00/02 | er_Type | $D3 |
04/06 | er_Product | $01 = 1 |
08/0A | er_Flags | $C0 |
10/12 and 14/16 | er_Manufacturer | $07DB = 2011 |
18/1A thru 24/26 | er_SerialNumber | $00250001 |
28/2A and 2C/2E | er_InitDiagVec | $0080 |
If a card contains a ROM driver (Rom Vector valid), and the vector is at offset $80 (as in this example) the DiagArea structure will appear at offset $0080 from the base address of the board. This example card’s Resident structure (romtag) directly follows its DiagArea structure.
WORDWIDE+CONFIGTIME ROMTAG \ flags DiagPt Devname starts \ \ DAsize / BootPt / here DiagPt, BootPt, \ \ /\ /\ /\ /\ res. res. /\ DevName relative 0080: 90000088 004A0076 00280000 00004AFC to Diag struct ----------------------------------------------------------------- COLDSTART NT_DEVICE backptr,endskip, \ ver /priority and DevName coded backptr endskip \ \ / / DevName relative, patched 0090: 0000000E 00000088 01250314 00000028 at Diag time ----------------------------------------------------------------- ID and InitEntry IDstring InitEntry coded relative, 00A0: 00000033 00000116 patched at Diag -----------------------------------------------------------------
Events At ROMTAG INIT Time
Next, most resident system modules (for example graphics) are initialized. As part of the system initialization procedure a search is made of the expansion.library's private list of boards (which contains a ConfigDev structure for each of the AUTOCONFIG hardware boards). If the cd_Flags specify CONFIGME and the er_Type specifies DIAGVALID, the system initialization will do three things:
First, it will set the current ConfigDev as the current binding (see the expansion.library SetCurrentBinding() function). 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.
Next, the 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 boot ROMs. This driver should obtain the address of its associated ConfigDev structure via GetCurrentBinding().
Once the driver is initialized, it is responsible for some further steps. 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. Also, though it is not currently mandatory, the driver should place a pointer to its Exec node in the cd_Driver field of the ConfigDev structure. This will generally be a device (NT_DEVICE) node. And for this device to be bootable, the driver must create a BootNode structure, and link this BootNode onto the expansion.library's eb_MountList.
The BootNode structure (see <libraries/expansionbase.h>) contains a Node of the new type NT_BOOTNODE (see <exec/nodes.h>). The driver must initialize the ln_Name 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. The bn_DeviceNode must be initialized to point to the DosNode for the device.
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 at the head of the List. For this reason, the device driver must enqueue a BootNode onto the list using the Exec library function 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() function call. When the DOS "wakes up", it will attempt to boot from this DeviceNode.
Events At BOOT Time
If there is no boot disk in the internal floppy drive, the system strap module will call a routine to perform 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 is associated with this BootNode; find its DiagArea; and call its da_BootPoint function in the ROM "image" to bootstrap the appropriate DOS. Generally, the BootPoint code of a ROM driver will perform the same function as the boot code installed on a floppy disk, i.e., it will FindResident() the dos.library, and jump to its RT_INIT vector. The da_BootPoint call, if successful, should not return.
If a boot disk is in the internal floppy drive, the system strap will Enqueue() a BootNode on the eb_MountList for "DF0:" at the suggested priority (see the Autodoc for the expansion.library AddDosNode() function). 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 autoconfiguration chain, the system does the normal thing, asking the user to insert a Workbench disk, and waiting until its request is satisfied before proceeding.
RigidDiskBlock and Alternate File Systems
Through the use of RigidDiskBlock information and the FileSystem.resource, it is possible for an autoboot driver to have access to enough information to mount all of its device partitions and even load alternate file systems for use with these partitions.
The RigidDiskBlock specification (also known as "hardblocks") defines blocks of data that exist on a hard disk to describe that disk. These blocks are created or modified with an installation utility (such as the hard drive Prep utility for the A2090A ST506/SCSI controller card) provided by the disk controller manufacturer, and they are read and used by the device driver ROM (or expansion) code. They are not generally accessible to the user as they do not appear on any DOS device. The blocks are tagged with a unique identifier, checksummed, and linked together.
The five block types currently defined are RigidDiskBlock, BadBlockBlock, PartitionBlock, FileSysHeaderBlock, and LoadSegBlock.
The root of these blocks is the RigidDiskBlock. The RigidDiskBlock must exist on the disk within the first RDB_LOCATION_LIMIT (16) blocks. This inhibits the use of the first cylinder(s) in an AmigaDOS partition: although it is strictly possible to store the RigidDiskBlock data in the reserved area of a partition, this practice is discouraged since the reserved blocks of a partition are overwritten by Format, Install, DiskCopy, etc. The recommended disk layout, then, is to use the first cylinder(s) to store all the drive data specified by these blocks: i.e. partition descriptions, file system load images, drive bad block maps, spare blocks, etc. This allocation range is described in the RigidDiskBlock.
The RigidDiskBlock contains basic information about the configuration of the drive: number and size of blocks, tracks, and cylinders, as well as other relevant information. The RigidDiskBlock points to bad block, partition, file system and drive initialization description blocks.
The BadBlockBlock list contains a series of bad-block/good-block pairs. Each block contains as many as will fit in a physical sector on the drive. These mappings are to be handled by the driver on read and write requests.
The drive initialization description blocks are LoadSegBlocks that are loaded at boot time to perform drive-specific initialization. They are called with both C-style parameters on the stack, and assembler parameters in registers as follows:
d0 = DriveInit(lun, rdb, ior) (d0/a0/a1)
where lun is the SCSI logical unit number (needed to construct SCSI commands), rdb is a pointer to a memory copy of the RigidDiskBlock (which should not be altered), and ior is a standard IO request block that can be used to access the drive with synchronous DoIO() calls.
The result of DriveInit() is either -1, 0, or 1. A -1 signifies that an error occurred and drive initialization cannot continue. A 0 (zero) result reports success. In cases -1 and 0, the code is unloaded. A result of 1 reports success, and causes the code to be kept loaded. Furthermore, this resident code will be called whenever a reset is detected on the SCSI bus.
The FileSysHeaderBlock entries contain code for alternate file handlers to be used by partitions. There are several strategies that can be used to determine which of them to load. The most robust would scan all drives for those that are both required by partitions and have the highest fhb_Version, and load those. Whatever method is used, the loaded file handlers are added to the Exec resource FileSystem.resource, where they are used as needed to mount disk partitions.
The PartitionBlock entries contains most of the data necessary to add each partition to the system. They replace the Mount and "DEVS:MountList" mechanism for adding these partitions. The only items required by the expansion.library MakeDosNode() function which are not in this partition block are the Exec device name and unit, which is expected to be known by driver reading this information. The file system to be used is specified in the pb_Environment. If it is not the default file system (i.e., "DOS\0" or "DOS\1"), the node created by MakeDosNode() is modified as specified in a FileSystem.resource's FileSysEntry before adding it to the DOS list.
Only 512 byte blocks were supported by the pre-V36 file system, but this proposal was forward-looking by making the block size explicit, and by using only the first 256 bytes for all blocks but the LoadSeg and BadBlock data. Under the present file system, this allows using drives formatted with sectors 256 bytes or larger (i.e., 256, 512, 1024, etc). LoadSeg and BadBlock data use whatever space is available in a sector.
RigidDiskBlock
This is the current specification for the RigidDiskBlock:
- rdb_ID
- Set to "RDSK".
- rdb_SummedLongs
- Set to 64.
- rdb_ChkSum
- Block checksum (longword sum to zero).
- rdb_HostID
- SCSI Target ID of host.
- This is the initiator ID of the creator of this RigidDiskBlock. It is intended that modification of the RigidDiskBlock, or of any of the blocks pointed to by it, by another initiator (other than the one specified here) be allowed only after a suitable warning. The user is then expected to perform an audio lock out ("Hey, is anyone else setting up SCSI stuff on this bus?"). The rdb_HostID may become something other than the initiator ID when connected to a real network: that is an area for future standardization.
- rdb_BlockBytes
- Size of disk blocks.
- Present file system supports 256, 512, 1024, etc.
- rdb_Flags
- Long word of flags:
- RDBF._LAST
- No disks exist to be configured after this one on this controller (SCSI bus).
- RDBF._LASTLUN
- No LUNs exist to be configured greater than this one at this SCSI Target ID.
- RDBF._LASTTID
- No Target IDs exist to be configured greater than this one on this SCSI bus.
- RDBF._NORESELECT
- Don't bother trying to perform reselection when talking to this drive.
- RDBF._DISKID
- rdb_Disk... identification variables below contain valid data.
- RDBF._CTRLRID
- rdb_Controller... identification variables below contain valid data.
- RDBF._SYNCH
- Drive supports scsi synchronous mode; can be dangerous to use if it doesn't!
These fields point to other blocks on the disk which are not a part of any file system. All block pointers referred to are block numbers on the drive.
- rdb_BadBlockList
- Optional bad block list. A singly linked list of blocks of type PartitionBlock.
- rdb_PartitionList
- Optional first partition block. A singly linked list of blocks of type PartitionBlock.
- rdb_FileSysHeaderList
- Optional file system header block. A singly linked list of blocks of type FileSysHeaderBlock.
- rdb_DriveInit
- Optional drive-specific init code. A singly linked list of blocks of type LoadSegBlock containing initialization code. Called as DriveInit(lun,rdb,ior)(d0/a0/a1).
- rdb_Reserved1[6]
- Set to $FFFFFFFFs.
- These are reserved for future block lists. Since NULL for block lists is $FFFFFFFF, these reserved entries must be set to $FFFFFFFF.
These fields describe the physical layout of the drive.
- rdb_Cylinders
- Number of drive cylinders.
- rdb_Sectors
- Sectors per track.
- rdb_Heads
- Number of drive heads.
- rdb_Interleave
- Interleave.
- This drive interleave is independent from, and unknown to, the DOS’s understanding of interleave as set in the partition's environment vector.
- rdb_Park
- Landing zone cylinder.
- rdb_Reserved2[3]
- Set to zeros.
These fields are intended for ST506 disks. They are generally unused for SCSI devices and set to zero.
- rdb_WritePreComp
- Starting cylinder: write precompensation.
- rdb_ReducedWrite
- Starting cylinder: reduced write current.
- rdb_StepRate
- Drive step rate.
- rdb_Reserved3[5]
- Set to zeros.
These fields are used while partitions are set up to constrain the partitionable area and help describe the relationship between the drive's logical and physical layout.
- rdb_RDBlocksLo
- Low block of the range allocated for blocks described here. Replacement blocks for bad blocks may also live in this range.
- rdb_RDBlocksHi
- High block of this range (inclusive).
- rdb_LoCylinder
- Low cylinder of partitionable disk area.
- Blocks described by this include file will generally be found in cylinders below this one.
- rdb_HiCylinder
- High cylinder of partitionable data area.
- Usually rdb_Cylinders-1.
- rdb_CylBlocks
- Number of blocks available per cylinder.
- This may be rdb_Sectors*rdb_Heads, but a SCSI disk that, for example, reserves one block per cylinder for bad block mapping would use rdb_Sectors*rdb_Heads-1.
- rdb_AutoParkSeconds
- Number of seconds to wait before parking drive heads automatically. If zero, this feature is not desired.
- rdb_HighRDSKBlock
- Highest block used by these drive definitions.
- Must be less than or equal to rdb_RDBBlocksHi. All replacements for bad blocks should be between rdb_HighRDSKBlock+1 and rdb_RDBBlocksHi (inclusive).
- rdb_Reserved4
- Set to zeros.
These fields are of the form available from a SCSI Identify command. Their purpose is to help the user identify the disk during setup. Entries exist for both controller and disk for non-embedded SCSI disks.
- rdb_DiskVendor
- Vendor name of the disk.
- rdb_DiskProduct
- Product name of the disk.
- rdb_DiskRevision
- Revision code of the disk.
- rdb_ControllerVendor
- Vendor name of the disk controller.
- rdb_ControllerProduct
- Product name of the disk controller.
- rdb_ControllerRevision
- Revision code of the disk controller.
- rdb_Reserved5[10]
- Set to zeros.
BadBlockBlock
This is the current specification for the BadBlockBlock. The end of data occurs when bbb_Next is NULL ($FFFFFFFF), and the summed data is exhausted.
- bbb_ID
- Set to "BADB".
- bbb_SummedLongs
- Size of this checksummed structure.
- Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, and can be from 6 to rdb_BlockBytes/4. The latter is the best size for all blocks other than the last one.
- bbb_ChkSum
- Block checksum (longword sum to zero).
- bbb_HostID
- SCSI Target ID of host.
- This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion)
- bbb_Next
- Block number of the next BadBlockBlock.
- bbb_Reserved
- Set to zeros.
- bbb_BlockPairs[61]
- Pairs of block remapping information.
- The data starts here and continues as long as indicated by bbb_SummedLongs-6: e.g. if bbb_SummedLongs is 128 (512 bytes), 61 pairs are described here.
PartitionBlock
This is the current specification for the PartitionBlock. Note that while reading these blocks you may encounter partitions that are not to be mounted because the pb_HostID does not match, or because the pb_DriveName is in use and no fallback strategy exists, or because PBFF_NOMOUNT is set, or because the proper file system cannot be found. Some partitions may be mounted but not be bootable because PBFF_BOOTABLE is not set.
- pb_ID
- Set to "PART".
- pb_SummedLongs
- Set to 64.
- pb_ChkSum
- Block checksum (longword sum to zero).
- pb_HostID
- SCSI Target ID of host.
- This describes the initiator ID for the owner of this partition. (see rdb_HostID discussion)
- pb_Next
- Block number of the next PartitionBlock.
- pb_Flags
- See below for defines:
- PBF._BOOTABLE
- This partition is intended to be bootable (e.g. expected directories and files exist).
- PBF._NOMOUNT
- This partition description is to reserve space on the disk without mounting it. It may be manually mounted later.
- pb_Reserved1[2]
- Set to zeros.
- pb_DevFlags
- Preferred flags for OpenDevice().
- pb_DriveName
- Preferred DOS device name: BSTR form This name is not to be used if it is already in use.
Note that pb_Reserved2 will always be at least 4 longwords so that the RAM image of this record may be converted to the parameter packet to the expansion.library function MakeDosNode().
- pb_Reserved2[15]
- Filler to make 32 longwords so far.
The specification of the location of the partition is one of the components of the environment, below. If possible, describe the partition in a manner that tells the DOS about the physical layout of the partition: specifically, where the cylinder boundaries are. This allows the file system's smart block allocation strategy to work.
- pb_Environment[17]
- Environment vector for this partition containing:
- de_TableSize
- Size of environment vector.
- de_SizeBlock
- Set to 128 (for 512 bytes/logical block).
- de_SecOrg
- Set to 0.
- de_Surfaces
- Number of heads (see layout discussion).
- de_SectorPerBlock
- Set to 1.
- de_BlocksPerTrack
- Blocks per track (see layout discussion).
- de_Reserved
- DOS reserved blocks at start of partition.
- Must be > 1; 2 blocks are recommended.
- de_PreAlloc
- DOS reserved blocks at end of partition.
- Valid only for file system type "DOS\1" (the fast file system). Zero otherwise.
- de_Interleave
- DOS interleave.
- Valid only for file system type "DOS\0" (the old file system). Zero otherwise.
- de_LowCyl
- Starting cylinder.
- de_HighCyl
- Max cylinder.
- de_NumBuffers
- Initial number of DOS buffers.
- de_BufMemType
- Type of mem to allocate for buffers.
- The second argument to AllocMem().
- de_MaxTransfer
- Max number of bytes to transfer at a time. Drivers should be written to handle requests of any length.
- de_Mask
- Address mask to block out certain memory.
- Normally $00FFFFFF for DMA devices.
- de_BootPri
- Boot priority for autoboot.
- Suggested value: zero. Keep less than five, so it won't override a boot floppy.
- de_DosType
- ASCII string showing fil esystem type;
- "DOS\0" ($444F5300) is old file system
- "DOS\1" ($444F5301) is fast file system
- "UNI(anything)" is a Unix partition
- pb_EReserved[15]
- Reserved for future environment vector.
FileSysHeaderBlock
The current specification for the FileSysHeaderBlock follows.
- fhb_ID
- Set to "FSHD".
- fhb_SummedLongs
- Set to 64.
- fhb_ChkSum
- Block checksum (long word sum to zero).
- fhb_HostID
- SCSI Target ID of host.
- This describes the initiator ID for the creator of this block. (see rdb_HostID discussion)
- fhb_Next
- Block number of next FileSysHeaderBlock.
- fhb_Flags
- See below for defines.
- fhb_Reserved1[2]
- Set to zero.
The following information is used to construct a FileSysEntry node in the FileSystem.resource.
- fhb_DosType
- File system description.
- This is matched with a partition environment's de_DosType entry.
- fhb_Version
- Release version of this load image.
- Usually, upper 16 bits hold version number, lower 16 bits hold revision number.
- fhb_PatchFlags
- Patch flags.
- These are bits set for those of the following that need to be substituted into a standard device node for this file system, lsb first: e.g. 0x180 to substitute SegList & GlobalVec
- fhb_Type
- Device node type: zero.
- fhb_Task
- Standard DOS "task" field: zero.
- fhb_Lock
- Not used for devices: zero.
- fhb_Handler
- File name to loadseg: zero placeholder.
- fhb_StackSize
- Stack size to use when starting task.
- fhb_Priority
- Task priority when starting task.
- fhb_Startup
- Startup message: zero placeholder.
- fhb_SegListBlocks
- First of linked list of LoadSegBlocks:
- Note that if the fhb_PatchFlags bit for this entry is set (bit 7), the blocks pointed to by this entry must be LoadSeg'd and the resulting BPTR put in the FileSysEntry node.
- fhb_GlobalVec
- BCPL global vector when starting task Zero or -1.
- fhb_Reserved2[23]
- (Those reserved by fhb_PatchFlags)
- fhb_Reserved3[21]
- Set to zero.
LoadSegBlock
This is the current specification of the LoadSegBlock. The end of data occurs when lsb_Next is NULL ($FFFF FFFF), and the summed data is exhausted.
- lsb_ID
- Set to "LSEG".
- lsb_SummedLongs
- Size of this checksummed structure.
- Note that this is not 64 like most of the other structures. This is the number of valid longs in this image, like bbb_SummedLongs.
- lsb_ChkSum
- Block checksum (longword sum to zero).
- lsb_HostID
- SCSI Target ID of host.
- This describes the initiator ID for the creator of these blocks. (see rdb_HostID discussion)
- lsb_Next
- Block number of the next LoadSegBlock.
- lsb_LoadData
- Data for "loadseg".
- The data starts here and continues as long as indicated by lsb_SummedLongs - 5: e.g. if lsb_SummedLongs is 128 (ie. for 512 byte blocks), 123 longs of data are valid here.
filesysres.h
The FileSysResource is created by the first code that needs to use it. It is added to the resource list for others to use. (Checking and creation should be performed while Forbid() is in effect). The resource is created by the system early on in the initialization sequence.
FileSysResource
- fsr_Node
- On resource list with the name "FileSystem.resource".
- fsr_Creator
- Name of creator of this resource.
- fsr_FileSysEntries
- List of FileSysEntry structs.
FileSysEntry
- fse_Node
- On fsr_FileSysEntries list; ln_Name is of creator of this entry.
- fse_DosType
- DosType of this file system.
- fse_Version
- Release version of this file system.
- Usually, upper 16 bits hold version number, lower 16 bits hold revision number.
- fse_PatchFlags
- Bits set for those of the following that need to be substituted into a standard device node for this file system: e.g. $180 for substitute SegList & GlobalVec.
- fse_Type
- Device node type: zero.
- fse_Task
- Standard DOS "task" field.
- fse_Lock
- Not used for devices: zero.
- fse_Handler
- File name to loadseg (if SegList is NULL).
- fse_StackSize
- Stack size to use when starting task.
- fse_Priority
- Task priority when starting task.
- fse_Startup
- Startup message: FileSysStartupMsg for disks.
- fse_SegList
- Segment of code to run to start new task.
- fse_GlobalVec
- BCPL global vector when starting task.
No more entries need exist than those implied by fse_PatchFlags, so entries do not have a fixed size.
For additional information on initializing and booting a Rigid Disk Block file system device, see the SCSI Device. Writers of drivers for expansion devices that perform their own DMA (direct memory access) should consult the Exec chapters and Autodocs for information on processor cache control functions including CachePreDMA() and CachePostDMA().
See the following include files for additional notes and related structures: <libraries/configvers.h>, <libraries/configregs.h>, <devices/hardblocks.h>, <resources/filesysres.h> and <libraries/filehandler.h>.
Function Reference
The following are brief descriptions of the expansion library functions that are useful for expansion device drivers and related applications. See the SDK for the complete descriptions of all the expansion library functions.
Function | Description |
---|---|
FindConfigDev() | Returns a pointer to the ConfigDev structure of a given expansion device. |
MakeDosNode() | Creates the DOS device node for disk and similar expansion devices. |
AddDosNode() | Adds a DOS device node to the system. |
AddBootNode() | Adds an autobooting DOS device node to the system. |
GetCurrentBinding() | Returns a pointer to the CurrentBinding structure of a given device. |
SetCurrentBinding() | Set up for reading the CurrentBinding with GetCurrentBinding(). |
ObtainCurrentBinding() | Protect the ConfigDev structure with a semaphore. |
ReleaseCurrentBinding() | Release a semaphore on ConfigDev set up with ObtainCurrentBinding(). |