Jump to content

PDDREF:Using Advanced Bios (ABIOS)

From EDM2
Revision as of 03:56, 22 May 2025 by Martini (talk | contribs) (Calling Advanced BIOS Services)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Physical Device Driver Reference
  1. Introduction
  2. Physical Device Driver Overview
  3. Physical Device Driver Architecture and Structure
  4. OS/2 Physical Device Driver Operations
  5. OS/2 Physical Device Driver Design Issues
  6. Character Device Monitors
  7. Installation of External Loadable Device Drivers
  8. Physical Device Driver Strategy Commands
  9. Device Helper (DevHlp) Services
  10. Resource Management
  11. Linking Resource Manager Services
  12. Generic IOCtl Commands
Appendixes
OS/2 Version Compatibility Considerations
Running OS/2 Version 1.3 16-Bit PDDs on OS/2
Using Advanced Bios
Notices
Glossary

Physical device drivers that invoke Advanced BIOS (ABIOS) are commonly known as physical ABIOS device drivers. These device drivers use one of the following transfer conventions:

  • ABIOS Transfer Convention
  • Operating System Transfer Convention.

For the ABIOS Transfer Convention, the ABIOS common entry points are invoked to locate the specific start, interrupt, or timeout entry points for the requesting Logical ID.

For the Operating System Transfer Convention, the specific start, interrupt, or timeout entry points must be located and called for the requesting Logical ID. OS/2 internal device drivers use the Operating System Transfer Convention to invoke ABIOS services. User-written, installable device drivers can use either the ABIOS Transfer Convention or the Operating System Transfer Convention. Device Helper services (DevHlps) are provided for both calling conventions.

For performance reasons, ABIOS device drivers should call ABIOS services with processor interrupts enabled.

Device Driver Data Segment

OS/2 2.1 recommends that an ABIOS device driver use its data segment to contain the ABIOS request blocks and data transfer buffers. The device driver data segment is located in memory. The operating system guarantees addressability to the data segment, regardless of the processor mode (protected or real). The physical device driver assumes that the physical location of the device driver data segment will not move. This allows physical data transfers to take place to buffers within the data segment.

By using the data segment, the physical device driver can create logical addressability to these data areas (for ABIOS) in a mode-independent manner, and without interrupt disable time considerations. Physical data transfers to buffers outside of the device driver's data segment can take place if the buffer is locked. As an alternative method, if the buffer is passed on a DosRead or DosWrite file system call, the physical address can be converted to a GDT Selector and used in place of the virtual address. The file system guarantees to lock down any buffer passed on a DosRead or DosWrite API. Therefore, this alternative method increases performance by removing the need to double buffer the data.

Obtaining a Logical ID

During its initialization, an ABIOS device driver must obtain the Logical ID (LID) for its physical device. The allocation of a LID is managed by the operating system. This ensures that the physical device driver receives a unique LID for its device type. The operating system provides a DevHlp_LIDEntry to obtain the LID for a device driver. The DevHlp_GetLIDEntry finds the LID for the specified Device ID and allocates it to the calling device driver.

An ABIOS device driver maps its device name to a unit within a LID. It receives a DEINSTALL request for its device name. This implies a single unit of a LID. To honor the DEINSTALL request, it must relinquish the LID through use of the DevHlp_FreeLIDEntry at deinstall time.

Note
To release a LID means to release all units under that LID. For a LID that has multiple units, the physical device driver must discontinue support of all units under the LID. If multiple units correspond to multiple device headers in the device driver data segment, the device driver must note which device header corresponds to each unit in the DEINSTALL LID and discontinue support.

The operating system prohibits access the LID for system services. Operating system management of LID access is similar to the management of hardware interrupt levels or I/O ports.

Calling Advanced BIOS Services

For ABIOS device drivers that use the Operating System Transfer Convention, the DevHlp_ABIOSCall, is provided to invoke ABIOS with the correct mode-specific set of parameters. The physical device driver passes the ABIOS request block pointer, its LID, and the ABIOS primary function (start, interrupt, or timeout) to the DevHlp_ABIOSCall. This sets up the stack for the call to ABIOS and calls the ABIOS function.

For ABIOS device drivers that use the ABIOS Transfer Convention, the DevHlp_ABIOSCommonEntry, is provided to invoke the ABIOS Common Entry Points. The physical device driver passes the mode-specific pointer to the ABIOS request block and the ABIOS primary function (common start, common interrupt, or common timeout) to the DevHlp service. The DevHlp service sets up the stack and calls the requested ABIOS common entry point.

Note
The return code of the ABIOS function is in the ABIOS request block.

Mapping Device Names to LID

Having identified its LID and the number of devices or physical units the LID represents, the physical device driver must map each of its device names to a unit within the LID and must support all units under the LID. All physical device drivers are known to the operating system by device names, whether these names correspond to the ASCII string device name in the header for character device drivers or to the logical units (which correspond to drive letters) in the header for block device drivers.

For character device drivers using ABIOS, the device name represents a single device identified by the LID. When a character device driver has a single device driver header, its device name must be mapped to the first unit of the LID it obtained. If the character device driver has one device header but its LID had multiple units, the rest of the units are not used.

When a character device driver has multiple device driver headers, the operating system calls the strategy routine entry point for each header during device driver initialization:

  1. The first entry point called must map its device name to the first unit of the LID.
  2. The second entry point called must map its device name to the next unit of the LID.
  3. If the LID that was obtained by the first entry point has only one unit, the second entry point must obtain another LID and map its device name to the first unit of the second LID.
  4. The physical device driver must start with the first LID and consume all the units before going to the next LID.

For a block device driver, the number of units can be placed in the first byte. This is optional because the OS/2 operating system fills this field during device driver initialization. For block device drivers using ABIOS, the number of units is equivalent to the number of devices (or units) under the LID. The block device driver must obtain the necessary number of LID/units for the number of logical units it supports and must map the first logical unit to the first-LID/first-unit, the second logical unit to the next available LID/unit, and so forth.

Handling ABIOS Requests

Refer to #Writing a Physical Device Driver Using Advanced BIOS for information on handling requests to ABIOS. A physical device driver must assume that it owns all outstanding ABIOS request blocks for a given Logical ID. During interrupt-time processing, the physical device driver must call ABIOS for each outstanding request that is incomplete-waiting-on-interrupt. This is one of the reasons that a Logical ID is not shared among physical device drivers.

Writing a Physical Device Driver Using Advanced BIOS

To determine the basic structure of the physical device driver, certain design points must be identified:

  • The kind of device to be supported (character or block).
  • The nature of the I/O to the device - synchronous or staged, Program I/O (PIO), or Direct Memory Access (DMA).
A staged request can be staged on a time delay, staged on an interrupt, or both. Staged on a time delay means the operation waits for a specific length of time before the operation can be continued or is completed. Staged on an interrupt means the operation waits for an interrupt to occur.
PIO or DMA refers to the type of addressing required for data transfers. PIO is done using virtual addresses, which are also referred to as logical addresses, of the form: segment/selector:offset.
DMA is performed using physical addresses, which are 32-bit numbers, indicating the data transfer location in memory.
  • The maximum number of devices.
  • The maximum number of interrupt levels.

These items determine the nature of the physical device driver (that is, how the task-time and interrupt-time portions of the device driver relate to each other and which of the DevHlp services will be used for blocking, queueing, timers, and so forth). The type and number of devices generally indicate the logical device names (for example, COM1, LPT1) that the physical device driver supports:

  • A device type is identified by its ABIOS-architected Device ID.
  • A specific device is identified by a LID and unit number under that LID.
  • I/O to the device is performed by calling the ABIOS entry point (start, interrupt, or timeout) that corresponds to the particular LID.
  • Parameters are passed to an ABIOS service through a request block structure.
  • I/O requests can be synchronous (run to completion) or staged (run until blocked, waiting for an interrupt or time).
  • Staged requests can have well-defined time delays between certain stages.
  • Data transfers can use either physical addresses or virtual addresses.

Before using ABIOS services and during initialization, a physical device driver must identify every LID for which it will accept requests. To do this, the physical device driver uses the architected ABIOS Device ID for its device.

The physical device driver uses the DevHlp_GetLIDEntry to search through the ABIOS common data area looking for the LID that corresponds to the given Device ID. In general, by making repeated calls to GetLIDEntry and counting the number of units supported by each LID it obtains, the physical device driver determines how many supported devices are configured in the system. The physical device driver processes interrupts and requests for its maximum number of supported devices only. Any LID of the device driver's device type that is left over must be unclaimed so another physical device driver can support it.

A physical device driver knows which LID corresponds to a given logical device name (for example, COM1) because of the rule forcing the operating system logical device names to be in the same order as the LID entries for an associated Device ID. For example, assuming one unit per LID, an installable printer device driver supports LPT3 (the third printer) by locating the third LID that corresponds to the Device ID of the printer.

The physical device driver must determine which interrupt level each LID uses by using the ABIOS function Return LID Parameters. The device driver registers interrupt handler entry points for the interrupt levels that it supports with the DevHlp_SetIRQ. It keeps a list of every LID that corresponds to each interrupt handler.

Note
If the physical device driver supports multiple devices and the number of interrupt levels for those devices exceeds the number of supported interrupt levels, the device driver ignores any LID that it cannot support because too many different interrupt levels are required.

At task time, when the device driver strategy entry point for a given device header receives a request packet, the device driver knows which logical device name and LID (and unit number) correspond to that entry point.

The device driver strategy routine sets up an ABIOS request block and uses the DevHlp_ABIOSCall to invoke the Advanced BIOS START routine to begin the requested ABIOS function. ABIOS requires that the return code field, in the ABIOS request block, be initialized to FFFFH. ABIOS sets the return code to its appropriate value.

Note
Either portion of the device driver, the task-time strategy routine or the interrupt handler, can start an ABIOS request. For simplicity, the example uses the strategy routine as the caller of the Advanced BIOS START service.

Interrupt During START

If the request is staged on an interrupt, then ABIOS sets the return code appropriately only when the particular service is ready to be resumed through the Advanced BIOS interrupt routine. The device driver strategy routine must also set a flag to indicate whether a request has completed the Start request to the point at which the strategy routine interrogates the return code. This must be done to accommodate the case where the interrupt occurs after ABIOS updates the return code but before the device driver strategy routine interrogates the return code. In this case, the device driver interrupt handler is invoked by the interrupt and can take appropriate action on the request block, even though the device driver strategy routine has not completed processing the request block.

For example, if the strategy routine is expected to block the request until the interrupt occurs, but the interrupt handler is invoked before the strategy routine is able to block, the interrupt handler needs to flag the fact that the interrupt handler has already processed the request block. The strategy routine, when it gets control, should not check the return code in the request block. The starting routine does not have to block, because the request is already completed. It then sets up the request packet with the return information and returns the completed request to the kernel.

This example would be more complex if, when the strategy routine got control, the request was still incomplete (as would occur in a multistaged request). The strategy routine would ignore the return code because the request block would already be at a different stage than the start, but it might still have to block.

Interrupt After START

For a staged ABIOS request that must wait for the interrupt associated with the specified LID to occur after the request is started, the return code of the request is set to stage-on-interrupt by the ABIOS START function. This indicates that the request is incomplete. Several requests for this LID can start and can be waiting for the device interrupt. These incomplete requests are commonly referred to as outstanding requests for the LID.

Note: The request is considered to be an outstanding request for the LID even if the Start service has not returned control to the caller of the Start service.

A physical device driver does not assume that the return codes for an ABIOS request occur in any given order. The return code should always be checked to determine what actions to perform on the request block.

When the device driver interrupt handler is invoked by the device interrupt, it knows which LID is associated with the interrupt level. The interrupt handler must individually examine each LID associated with the interrupt level. For a LID, the interrupt handler must process all outstanding staged-on interrupt request blocks. That is, the interrupt handler is required by ABIOS to call the Advanced BIOS interrupt routine for every outstanding staged-on interrupt request block to completely process one LID. This includes a START request block in which the return code has been changed from FFFFH to stage-on interrupt, but the Start service has not yet returned control to its caller. If one of the request blocks for the LID caused the interrupt after the interrupt handler has called ABIOS with all the outstanding request blocks owned by this LID, the interrupt handler does not need to process any other LID associated with this interrupt level.

Advanced BIOS requires that physical device drivers adhere to the following rules for sharing interrupt levels:

ABIOS REQUEST BLOCK RULE
The interrupt handler for a particular LID, when invoked by the operating system, must call Advanced BIOS for each ABIOS request block that is stage-on-interrupt, even if one of the request blocks gets the return indicator that the interrupt belongs to it.
ABIOS EOI PLACEMENT RULE
The EOI must be issued after all ABIOS staged-on interrupt request blocks have been processed for the LID that owns the interrupt.
ABIOS LID IRQ RULE
Advanced BIOS defines only one interrupt level for each LID. If a physical device driver handles more than one LID on the same interrupt level, the physical device driver could choose to register only one interrupt handler for any LID on that level. In this case, the operating system calls the handler only once when the interrupt occurs. The handler must manage the processing of more than one LID in order to determine if it owns the interrupt processing for them. In this case, the device driver interrupt handler should be aware of the Fairness Criteria problem. A LID at the end of the interrupt handler's list does not get as much service as a very active LID at the front of the list.

If a given LID has no outstanding ABIOS request blocks, the physical device driver calls the Advanced BIOS Default Interrupt service for that LID. The Default Interrupt service resets the interrupt condition for that LID if the LID falsely caused the interrupt. It then returns to the device driver interrupt handler, indicating that the interrupt belonged to the LID.

If there is at least one outstanding ABIOS request block for a given LID, ABIOS automatically invokes the Default Interrupt service if the LID generates a false interrupt. The physical device driver must be able to process the false interrupt return code for any call to the ABIOS interrupt routine. This return code indicates that the interrupt belonged to the LID, was reset by ABIOS. The physical device driver is responsible for issuing the EOI and returning to the operating system as owning the interrupt.

The device driver interrupt handler can issue the EOI (through the DevHlp EOI function) only after completely processing the LID that owns the interrupt or after the LID's Default Interrupt service indicates that the LID's device caused the interrupt. The interrupt handler must process all outstanding requests under the LID that owns the interrupt, even after finding a request block that indicates that it caused the interrupt. The interrupt handler can stop processing any LID for this interrupt only when the interrupt is claimed by a LID, either by a request under the owning LID or by the owning LID's Default Interrupt service. Once the interrupt handler issues the EOI after completely processing a LID, another LID requesting service at the current interrupt level would create another interrupt. Once the EOI is issued, the interrupt handler can be re-entered at its entry point. If the interrupt handler is reentered, it must process every LID, including the one that is near completion or just completed.

In order to keep the pre-EOI processing time to a minimum, the interrupt handler should issue its EOI before it sets the return information in the operating system request packet or before it begins processing a request packet queued by the device driver strategy routine.

If the interrupt handler did not find any LID that claimed the given interrupt with a request block or by a Default Interrupt service, the interrupt handler must exit, indicating that the interrupt did not belong to it (that is, the interrupt was not caused by any LID that is owned by the physical device driver).

Eventually, the return code from ABIOS will show that the ABIOS request block is complete. The physical device driver can then clear the device driver request packet queue, take the next request packet, and try to start another ABIOS request block.

The physical device driver supports the timeout requirements of ABIOS with the DevHlp_SetTimer and the DevHlp_TickCount. Instead of counting every clock tick, the device driver uses TickCount to force its timer tick entry point to receive control as infrequently as possible. The design of the ABIOS TIMEOUT function is in one-second increments.

Spurious Interrupts

To handle a spurious interrupt in an edge-triggered interrupt environment, reset the interrupt at the 8259 interrupt controller (EOI), issue the global rearm if sharing interrupts, and enable processor interrupts. Generally, these actions would be taken by the last interrupt handler in the list of interrupt handlers.

To handle a spurious interrupt in a level-sensitive interrupt environment, reset the interrupt condition at the device, issue the EOI, and enable processor interrupts.

ABIOS provides the capability to reset a spurious interrupt at the device through the use of an Advanced BIOS default interrupt handler for the LID. The handler calls the ABIOS default interrupt handler for its LID if there are no outstanding incomplete-waiting-on-interrupt request blocks. The ABIOS default interrupt handler will indicate either that the interrupt condition was successfully reset or that the interrupt did not belong to the device referenced by the LID. If the ABIOS handler replies that the device was successfully reset, the interrupt handler must issue the EOI and return as owning the interrupt.

Where there are incomplete-waiting-on-interrupt request blocks outstanding, ABIOS keeps track of which interrupts are expected. It will automatically service a spurious interrupt when called by the interrupt handler. The handler must call ABIOS with every request block that is incomplete-waiting-on-interrupt for a LID, even if the first one returns an indication that it performed some processing. The handler must also be able to process the spurious interrupt return code from any one of these calls to the ABIOS interrupt service.

For a physical device driver directly interfaces to the device, it must check the device for the interrupt condition, even if the interrupt condition does not correspond to an outstanding I/O request. If the device had caused the spurious interrupt, the interrupt handler must reset the interrupting condition at the device, issue the EOI, and return as owning the interrupt.

Note
If the device causing the spurious interrupt in the level-sensitive interrupt environment is not identified and reset, the interrupt level will interrupt continuously. This is a feature of the 8259 interrupt controller operating in level-sensitive mode. If no device driver that is registered for an interrupting interrupt level claims the interrupt, the OS/2 interrupt manager is forced to disable the interrupt level at the 8259 interrupt controller because it cannot clear the interrupt at the device. If the interrupt is not disabled, the device will continue to generate spurious interrupts, the interrupt manager will continue to call all device drivers registered on the interrupt level, and all lower-priority interrupts will fail to be serviced.

Address Conversion Using DevHlp Services

To get a logical address to place in an ABIOS request block:

  1. Call PhysToVirt with ES:DI for the converted address.
  2. Store the converted address in the ABIOS request block.
  3. Call the ABIOS service.

For more information on interfaces to specific ABIOS functions, refer to the Personal System/2 and Personal Computer BIOS Interface Technical Reference.