OS2LDR and OS2KRNL -- The Secret Handshake
Written by David C. Zimmerli
In my article Inside the OS/2 Kernel, I plodded through the initialization steps of the OS2LDR module as revealed on the debug terminal during system boot-up. In this article, I want to take a more structural view of OS2LDR, focusing especially on the interface between OS2LDR and OS2KRNL. To my knowledge, this interface, including about 50 "Dos Helper" functions, has never before been documented or even mentioned in any public materials.
I. The Conundrum
To recap briefly my earlier study: at OS/2 system initialization, the OS2LDR module, running in real mode, sets up the PIC chips, sets the PIT timer chips, queries the BIOS for hardware configuration data, reads various CMOS and ROM information, and finally loads (i.e., reads in and applies fixups to) OS2KRNL and transfers control to it at its start address, syiInitializeOS2.
This knowledge solves the problem of interpreting all the magic incantations pouring across the debug terminal during system start-up, but it also raises an important conceptual question: Why does the loader do all this? Shouldn't the loader just load the kernel, give it control, and go away? Why not let the kernel handle communicating with the BIOS, initializing the peripheral chips, and tweaking the system ports to produce a nicely tuned, smoothly humming operating system?
The plot thickens when we discover that, after initialization, the "bottom layer" of protected mode interrupt handling code-- the instructions to which the IDT points directly-- consists of code from OS2LDR! How is it that a piece of the kernel loader module survives in the fully initialized system, well after it should no longer be needed? And what in carnation does protected mode interrupt handling have to do with real mode kernel loading?
II. OS2LDR: More than just a Kernel Loader
It turns out that OS2LDR is much more than a loader for OS2KRNL. It also incorporates a library of about 50 call-back functions, known internally as "Dos Helper" functions, which the kernel uses both during and after initialization to talk to the PC hardware. This library, it seems, is the beginning of an attempt to insulate the core functions of the kernel-- task management, memory management, semaphore handling, and so on-- from the "bare metal" of the PC architecture-- the knowledge of which ports control which peripheral chips, how the BIOS data area is laid out, and the like. To those of you who have read the book on OS/2 for the PowerPC, this concept should start to sound familiar. Can you say "micro-kernel"?
In what follows I will attempt to document the "Dos Helper" functions. These presumably get their name from the fact that they help the kernel implement the Dos* API calls, or support CP-DOS, as the kernel used to be called. They are intended only for use by OS2KRNL, and of course must not be confused with the DevHelp, Virtual DevHelp, or FSHelp APIs.
III. The Interface Details
When OS2LDR passes control to OS2KRNL, it passes a pointer (in SS:BX) to a structure which I will call muKServiceStruct. Its layout is as follows:
The Arena Info Table lists all memory objects that have been set up by OS2LDR, including all the kernel segments, the mini-FSD (i.e. OS2BOOT), OS2DUMP, OS2LDR itself, and empty arenas which are available for applications and device drivers. It is an array of structs of length 16h having the following layout:
And the "DosHelp function table" has the following layout:
The Dos Helper functions can be separated into three categories: (1) those which are called during the real mode phase of system initialization, (2) those which are called during the protected mode phase of system initialization, and (3) those which can be called at any time after entering protected mode. The first group are addressed with real mode segment 9400 (for example; the exact value depends on the size of OS2LDR and the amount of real mode memory installed); the second group with code selector 0110h and data selector 0118h; and the third group with code selector 0100h and data selector 0108h.
Here is the interface for OS/2 2.1:
The interface for OS/2 Warp 3.0 adds 3 new functions, bringing the total to 55. In a future article I hope to document these new functions as well as the interface for Warp 4.
Of course, all the usual caveats apply here about the use of undocumented interfaces. However, this information should be a useful starting point for anyone wishing to write a custom loader-- or a custom kernel for that matter.
I welcome comments and questions about this article. Please email firstname.lastname@example.org.
Copyright © 1999, David C. Zimmerli. All rights reserved.