PSD related information from the SMP Programming Addendum

1.0 Platform Specific Drivers (PSDs)

In OS/2 Warp Server for SMP, all of the platform specific code has been removed from the operating system, and placed into a Platform Specific Driver. These drivers provide an abstraction layer for the underlying hardware by allowing the operating system to call generic functions to perform platform-specific operations without worrying about the actual hardware implementation. This allows OS/2 Warp Server for SMP to support new MP hardware platforms without modifying the operating system.

PSDs are 32-bit flat DLLs specified in CONFIG.SYS by using the PSD= keyword , and must conform to the 8.3 file naming convention (e.g. PSD=BELIZE.PSD). They cannot contain either drive or path information because OS/2 cannot process such information at the stage of the startup sequence when the PSD statements are processed. The root directory of the startup partition is first searched for the specified file name, followed by the \OS2 directory of the startup partition. If drive or path information is included in a PSD statement, an error is generated.

PSD parameters may be specified after the PSD’s name, and may be a maximum of 1024 characters long. The parameter string is not interpreted or parsed by OS/2, but is passed verbatim as an ASCIIZ string when the PSD’s Install function is invoked.

If multiple PSD statements are encountered, OS/2 will load each PSD in the order listed in CONFIG.SYS, and call the PSD’s install function. The first PSD which successfully installs will be the one OS/2 uses.

PSD statements are processed before BASEDEV, IFS, and DEVICE statements.

2.0 Platform Specific Driver Architecture and Structure

The PSD operates in three contexts (modes): Kernel, Interrupt, and Init.

2.1 Kernel Mode

The OS/2 kernel calls the PSD for task-time operations, that is, it will execute as a thread within a process. Kernel mode is also referred to as the task context.

2.2 Interrupt Mode

The OS/2 kernel calls the PSD for interrupt-time operations. Interrupt time is a generic term that refers to executing code as a result of a hardware interrupt. The code does not execute as a thread belonging to a process.

2.3 Init Mode

The PSD is currently being used for system initialization. A limited set of PSD helps are available for use.

PSDs may contain multiple code and data objects. All objects will be fixed (not-swappable or movable) in low physical memory, with virtual addresses in the system arena. Objects are loaded in low physical memory to facilitate the use of real mode or bi-modal code. All objects default to permanent, which means that they remain in the system after initialization is completed. The SEGMENTS directive and the IOPL option in the linker DEF file should be used to mark those objects that are not to be kept after initialization.

The multitasking/multiprocessing environment of OS/2 Warp Server for SMP dictates that the PSD must be capable of handling multiple requests simultaneously. This means that global variables should be used sparingly. Upon PSD installation, the kernel passes a pointer to a small area of processor local memory (PLMA) which the PSD developer can use to store variables. This PLMA area is currently 256 bytes in size. IBM reserves the right to increase the size of this area in future releases of OS/2, though the minimum available will always be 256 bytes. The size of the PLMA is passed in the same structure as the pointer to the PLMA from the PSDINSTALL export.

PSD developers must be aware of the effects of the calls they make, because there is no guarantee that if an operation is started on a processor, and execution blocks, that the operation will continue on the same processor. OS/2 does not preempt a thread in the PSD, but it may block as a result of using a PSD help, or it may be interrupted by a hardware interrupt.

PSDs can register an interrupt handler for any given IRQ level using the SET_IRQ PSD help. These interrupt handlers are guaranteed to be called before any device driver’s interrupt handler. If the PSD’s interrupt handler returns NO_ERROR, the interrupt manager will assume the interrupt has been handled, it will end the interrupt. If a -1 is returned, the interrupt manager will assume that the interrupt has not been handled, and will call each device driver which has a registered interrupt handler for that particular level until one claims the interrupt. If the interrupt is unclaimed, the IRQ level will be masked off.

All PSDs must use the SET_IRQ PSD help to indicate which IRQ level they will be using for inter-processor interrupts (IPI). If the PSD’s IPI IRQ level is shared, it must register a handler which detects if the IRQ is an IPI or another interrupt. The handler must return NO_ERROR if the interrupt was caused by an IPI, otherwise it returns a -1. If the IPI IRQ level is unique, an interrupt handler need not be installed but SET_IRQ must still be used to indicate which is the IPI IRQ level.

The kernel will save the state of all the registers (except EAX) around calls to the PSD functions. All the functions will run at Ring 0. Upon invocation, SS, DS, and ES will be flat. The PSD functions must conform to the C calling convention. They receive parameters on the stack (4 bytes per parameter), and must return a return code in EAX.

The PSD functions have been split into three categories:

  • Functions that the PSD must have for OS/2 to operate (required functions)
  • Functions that the PSD does not need to have (optional functions)
  • Functions that the PSD must have for OS/2 to use multiple processors (MP functions).

The kernel provides default handling for some of the PSD functions. PSD functions can also chain to a kernel default handler by returning a -1 return code. If a return code other than -1 is returned by a PSD function, the default handler will not get called. The PSD function glossary later in this chapter details the categories of all the functions, as well as any default handlers they may have.

The PSD developer makes functions available to OS/2 by using the EXPORTS statement in the module definition (DEF) file. All functions should be exported using upper case with no leading underscores (_). An example is shown below.

LIBRARY TESTPSD
 
  EXPORTS
     PSD_INSTALL   = _Install
     PSD_DEINSTALL = _DeInstall

Note: Needs updating with Open Watcom instructions.

The initial CS and EIP in the PSD’s executable image is ignored. The image should also not contain a stack object. OS/2 allocates a per-processor PSD stack and sets SS and ESP correctly before invoking any of the PSD functions.

PSDs should be written in flat 32-bit code, using C, and must be linked as a LIBRARY.

OS/2 invokes all PSD functions in protect mode, but there is also a PSD help which allows the PSD developer to call a PSD function in real mode.

OS/2 services are provided through the PSD help interface. Access to these services are obtained upon PSD installation. PSD helpers preserve all registers except EAX.

All the definitions (e.g. defines, structures, etc.) that are required for building a PSD are in the header file PSD.H.

3.0 OS/2 Initialization

OS/2 requires a PSD for system initialization. The system will display an error message if a valid PSD for the current platform cannot be installed.

The following is a list of steps, in the order in which they occur, that are executed after a PSD is installed. If any step does not complete successfully, the system initialization process will stop, and a fatal error message will be displayed.

  1. After a PSD is successfully installed, its Init function is invoked. This function is used to allocate and initialize any resources that the PSD may require, as well as initializing the state of the hardware.
  2. The kernel determines the number of usable processors on the current platform by using the PSD_GET_NUM_OF_PROCS function.
  3. The kernel allocates all resources required to support the additional processors. This step determines what to allocate based on the results of the previous step.
  4. The PSD’s processor initialization function is invoked on the current processor (CPU0).
  5. An MP daemon is created for CPU0. An MP daemon is a thread that never goes away, which is used for MP operations by a specific processor.
  6. An MP daemon is created for the next logical processor.
  7. The PSD’s start processor call is invoked to start the next logical processor. The PSD should only start the specified processor, and then return (see the PSD_START_PROC function for more detail). The started processor will spin in a tight loop waiting for a variable to be cleared. This variable is referred to as the processor initialization real mode spinlock.
  8. Upon return from the PSD’s start processor call, the processor initialization real mode spinlock is cleared.
  9. CPU0 will spin in a tight loop waiting for a variable to be cleared. This variable is referred to as the CPU0 spinlock.
  10. The started processor continues execution of the kernel’s real mode processor initialization code now that processor’s initialization real mode spinlock has been cleared.
  11. The started processor sets up all protect mode and paging information, and switches into protect mode with paging enabled.
  12. Up to this point, the started processor has been running on a small processor initialization stack (It has not been running as an OS/2 thread). The current context is switched to that of this processors MP daemon.
  13. OS/2 calls the PSD’s processor initialization function for the current processor.
  14. The PSD indicates that the processor has been initialized.
  15. The started processor will spin in a tight loop waiting for a variable to be cleared. This variable is referred to as the processor initialization protect mode spinlock.
  16. The CPU0 spinlock is cleared.
  17. System initialization continues on CPU0 now that its spinlock has been cleared.
  18. Steps 6, through 17 are repeated until all processors have been started.
  19. The rest of system initialization continues normally, on CPU0.
  20. After the system is fully initialized, the processor initialization protect mode spinlock is cleared. This allows CPU1 through CPU-N to start executing code.

Original posted: 10/10/2009