A flat model device driver for OS/2:Chapter 2. - Review of Related Literature

From EDM2
Jump to: navigation, search

Chapter 2. - Review of Related Literature

Requirements

During boot, the system will enumerate the system hardware to determine the current configuration. The current configuration will be compared to the last good configuration from the persistent store. If the information is different, the appropriate event mechanism will be started (This technology is nothing new. IBM made this a standard part of its Micro Channel bus architecture some 10 years ago. The current configuration was stored in EEPROM and compared each time the system was booted). If the boot process is successful, the old configuration information should be backed up to a file, and the new configuration should become the current configuration. The system should always keep a known good configuration in the event of a system crash or corruption of the configuration persistent store. If a corrupt configuration file is encountered during boot, the user should be given the choice of using the last known good configuration or loading a new configuration from a file on floppy disk or hard disk. This operation is already performed by many popular operating systems such as Windows NT.

The device driver model will support the ability to be dynamically loaded, configured, and removed, and the system should automatically scan the machine to determine if any devices have been added or removed (Shanley, 1995). The system should attempt to detect legacy devices as well as enumerating Plug and Play devices, PCI devices, and devices on other bus types such as Universal Serial Bus (USB). A good example of how this is performed can be observed in Windows 95.

In addition to detecting devices and bus types at boot time, a system-based configuration manager or “sniffer” will be periodically run. Many of these devices support hot (power on) insertion and removal, so that perhaps every five to ten seconds or so, the configuration manager will attempt to determine if a new device has been inserted or an existing device removed. If the system detects that a new device has been installed, it looks up the configuration information for that device in the system’s device configuration table. If the configuration information is located, the configuration manager attempts to find and load the device driver associated with the device, and calls the initialization section of the device driver to perform its configuration process. If the device configuration information is not found in the system’s configuration table, the user is prompted to insert a diskette or path information to where the configuration information is located. The appropriate data is copied to the system’s persistent store, and the configuration process begun. If the configuration process fails, the device driver is unloaded, and any resources claimed so far are automatically released (This may not always be possible as some resources may be locked by the system).

Some devices cause immediate detection events, such as the insertion or removal of a PCMCIA card. Upon insertion of a PCMCIA card, the configuration data is read from tuples located in the PCMCIA card and compared with the persistent registry data (Mori, 1994). If the configuration information for the card already exists, the system loads the necessary driver and calls the driver’s initialization code. The initialization code then configures the card using the configuration manager. Our proposed model supports older 16-bit PC cards as well as 32-bit CardBus PCI implementations (Anderson & Shanley, 1995). CardBus adapters can allocate 32-bit flat memory in any region of the PC memory address space.

The system registry must be able to support legacy devices whose resources are configurable only through jumpers or switches, or via a proprietary programming sequence (Kelsey, 1995). Some older devices require the booting of a MS-DOS diskette to download software to the adapter or configure the adapter’s resources such as interrupt level, memory mapped address, DMA channels, or port addresses. The system registry utility is used to examine and manually enter the resources required by the legacy device. If the user attempts to claim a resource that is already in use, the request is refused (We expect that this function will have the capability to be overridden, as it is possible to share resources between mutually aware device drivers). In some cases, it will be necessary to write a “sniffer” that is specific to the particular device.

Addressing

Wherever possible, the system should avoid thunks. In particular, converting or thunking 32-bit addresses to 16-bit addresses are difficult to implement because the 32-bit pointer can cross 64KB boundaries (Deitel & Kogan, 1992). To avoid unnecessary thunks, the device driver interface should be implemented in 32-bit code, not thunked to their 16-bit counterpart. This will certainly cause the size of the kernel to grow, but the increased performance should more than make up for the larger kernel size or execution time. In a resource-constrained environment, it may be appealing to simply insert thunks for the 32-bit APIs. While this will save initial coding work, we believe it will have a significant impact on system performance.

Legacy Support

Although the system should provide seamless, flat-model interfaces to services and data structures, a few exceptions must be provided for. One of these exceptions is the support of scatter-gather lists for those devices that export only 24 address lines. Some SCSI adapters require that they perform reads and writes to certain physical addresses. Because the adapter recognizes only 24 bits of address, those physical addresses must reside below the 16MB boundary. Another exception to the exclusive use of 32-bit pointers is the use of Direct Memory Access, or DMA. The DMA hardware in most systems is a holdout of the ISA bus architecture, and is thus limited to 24 bits of address. Adapters that perform DMA reads and writes must use data buffers that are below the 16MB boundary. If the application is running above the 16MB boundary, the system must provide the ability to copy the data from the buffer below the 16MB boundary to the application’s buffer in high memory. The device driver interface should do this transparently via a device driver service.

Current OS/2 segmented device drivers contain at least one code segment and one data segment, and are loaded in low physical memory (Deitel & Kogan, 1995). The new kernel must allow the new 32-bit device drivers to be loaded anywhere in physical memory, and not restrict them to any particular region (This has always been a limitation for OS/2 as the amount of low physical memory is fixed. Loading several large drivers could cause low memory to be exhausted, prohibiting new drivers from being loaded). In addition, the current 16-bit driver model restricts interrupt and timer handlers to the first code segment. Our proposal assumes that no such limitation will exist. The system should have the maximum flexibility in choosing how to distribute interrupt requests and should support Advanced Priority Interrupt Controller (APIC) if present (Anderson & Shanley, 1995).

The new device driver model should support a symmetric multiprocessor (SMP) configuration. Writing a device driver for an MP system requires care, just as it requires care to write an application for a multiprocessor system. Global variables should be avoided wherever possible (IBM, 1993), and platform-specific APIs for low-level access should be called rather than accessing the hardware directly. Although there may be some performance gain in bypassing the published hardware interfaces, the result will be code that runs on one particular platform but not another. Proper operation in an MP system requires serialized access to hardware and software resources. Manipulating hardware directly could cause these serialization functions to be ineffective, and introduce intermittent bugs and system failures that would be nearly impossible to locate. Race conditions are normal in an MP system. A thread blocked on one processor can be restarted on another processor or swapped out to disk at the system’s discretion. Failing to adhere to the correct procedures could cause the system to become unstable and ultimately fail. All functions and subroutines for the new driver model shall be made MP safe.

Extreme care must be exercised when using global variables. Since device driver operations usually happen asynchronously, a condition might occur where two routines or functions attempt to access the global variable at the same time. Normally, global variables accessed by an application are protected by some type of semaphore mechanism to prevent this from happening. However, the device driver operates in kernel mode of the processor, and the semaphore functions are not available in kernel mode. One reason for this is that the OS/2 driver, while in kernel mode, is interruptible but not preemptible. While the OS/2 device driver is running it can be interrupted by an external device interrupt but it can not be suspended in favor of another higher priority device driver. This means that while the OS/2 device driver is executing, no other system service or program can be running.

The use of global variables becomes even more critical when the device driver is operating in a system with multiple processors. If a device driver becomes blocked on one processor, it can be restarted on another processor when a particular event occurs. OS/2 solves this by reflecting all interrupts to CPU0, while Windows NT uses a ring-0 semaphore mechanism called a spin-lock. Our proposal suggests a design where the device driver uses an object-oriented strategy by eliminating most global variables and encapsulating the variables inside functions. Real encapsulation is not possible at the driver level since we do not actually create an object in the traditional sense, but the function will access global variables that only the particular function is aware of. Since only one thread of the driver code can be executing at a time, this method provides serialized access to those variables. We believe that by adopting this strategy, all device drivers will be inherently MP-safe, providing they follow all the other guidelines for safe MP operation.