A flat model device driver for OS/2:Chapter 3. - Methodology

Approach
Our approach involved the conversion of three specific device drivers from 16-bit to 32-bit. We felt that this was the best method, as we would have an existing model against which to verify our results and benchmark performance. Complete program listings of the three device drivers before and after conversion can be found in Appendix A.

Method and Database of Study
To validate our proposed design, we converted three existing 16-bit device drivers to the new 32-bit design. Because our design requires several other changes to the OS/2 kernel that may not be finished at the time we will be ready to begin testing, we were forced to simulate some operations in software. We built a software simulator that calls the device driver functions and executes as much code as possible. To monitor execution time, we took a snapshot of the millisecond timer upon entry into the device driver and another snapshot when exiting. While we could not test every execution path, this data did give us a general idea of execution time. While this was certainly not an optimal solution, it was possible to test the basic architecture of our design and compare some results with older 16-bit device drivers.

Validity of Data
Since we used three actual device drivers for our conversion, we believe the data contained herein to be valid, at least for these three cases. Since many components were not finished or installed at the time of our study, it was impossible to guarantee that we had uncovered all of the problems associated with the conversion. We have attempted to point out these unknown issues throughout this document, and have summarized them in Chapter 5.

Originality and Limitations of Data
Since the concept outlined in this document has never been attempted, data associated with the proposal has never been collected. While some general concepts, such as decreased performance and larger executable size are generally known and accepted, the actual application of those concepts in our proposal has not been previously documented.

It would have been easy to start with an entirely new device driver model, but this would render existing device drivers useless. The challenge is to provide an enhanced architecture while still maintaining backward compatibility with the hundreds of current OS/2 device drivers. This proposal suggests an architecture for the OS/2 base device driver model only. OS/2 uses several other types of device drivers, but most have already been converted to 32-bit models so they are not covered here.

Summary
The object file format of the device driver is the same as a DLL, so we loaded the device driver as a DLL for testing purposes. It was impossible to test real timer or device interrupts, since interrupts are only available in ring 0 and the DLL loads at ring 2. The simulator made calls to the timer and interrupt handlers to test their correct operation. We encountered several problems and oversights with our initial design during the preliminary testing process. Some of these problems caused us to revise our design, and others required further system changes.

One concern that had been expressed to us is the fear that our design would cause the size of the installed imaged to grow very large. Indeed, our past experience had shown that converting 16-bit code to 32-bit code resulted in large increases in executable code size, sometimes in excess of 100 percent. We took no extra steps to optimize the executable size by changing the way we wrote the code to insure the comparisons with the 16-bit executables were valid.

During our testing, we noted the size increases for our new drivers and support software. They are discussed in detail later in Chapter 5. Existing 16-bit device drivers primarily use 16-bit selectors and 16-bit offsets to form 32-bit addresses. Address and pointer conversions in 16-bit mode are very fast, especially when the memory range is equal to or less than 64KB. We expected that direct addressing using 32-bit pointers would be faster, especially since we could utilize the native block moves in the Intel processor. Our results are summarized in Chapter 5.

Drivers frequently create 32-bit alias pointers which point to other areas in memory, such as user buffers or memory-mapped areas of a device. The driver calls a system function to map a 16 or 32-bit physical address to a virtual or user virtual address. During this conversion, the system allocates a 32-bit selector from the pool of 32-bit selectors. Since OS/2 was designed to handle both 16-bit applications and 32-bit applications, we were unsure if the current pool of selectors available for allocation would be large enough, or contained enough 32-bit selectors to accommodate our new design. We wrote some test code to determine the number of selectors necessary.

In OS/2, application programs do not call device drivers directly. Instead, they call a system API that in turn calls the device driver through an established interface. This interface performs initial parameter validation and provides the ring transition from user mode to kernel mode and back. The communication medium between the APIs and the device driver is called the Request Packet. The request packet contains the operation code and parameters associated with the request such as pointers and data. OS/2 allocates a limited number of request packets, based on the available memory in the system heap space, so we were unsure that that OS/2 was allocating enough space for the packets. We later concluded that the system should provide up to 512 16-bit packets and 512 32-bit packets to insure that enough packets were available for even the largest number of devices.

In OS/2, the device header structure contains pointers to functions located in the device driver. It is a static structure created at compile and link time, and provides entry points for the initialization and strategy sections of the device driver. In the current implementation of OS/2, these pointers are kept only as 16-bit offsets since the driver model is 16-bit. With a flat model, these pointers will become 32-bit flat addresses. Programs or system components that need to call the device driver functions do so by locating the address of those functions from the driver’s header information. These system components need to be changed to refer to the address values correctly. We will insert a special bit in the device header to indicate the driver is a new flat model driver, and that addresses should be assumed to be linear.

The request packet contains pointers to buffers and data items that are located in the application program address space. Even though the driver is a 32-bit implementation, it is possible that the application that needs to access the device driver is still 16-bit. The system and device driver will allow these programs to be used by transparently handling any address conversions or address mapping.