Writing Device Drivers
只搜寻这本书
以 PDF 格式下载本书

Overview of the SunOS Kernel

1

This chapter provides an overview of the SunOS kernel. It covers concepts of particular importance to device driver writers, including general kernel structure and function, kernel and user threads, relevant aspects of the virtual memory (VM) system, and the Solaris 2.x DDI/DKI.

What is the Kernel?

The SunOS kernel is a program that manages system resources. It insulates applications from the hardware, and provides them with essential system services such as input/output (I/O) management, virtual memory and scheduling. The kernel consists of object modules that are dynamically loaded into memory when needed. The main part of the kernel is contained in the file /kernel/unix.
The kernel provides a set of interfaces for applications to use called system calls. System calls are documented in the Solaris 2.4 Reference Manual AnswerBook (see Intro(2)). The function of some system calls is to invoke a device driver to perform I/O.
Device drivers are kernel modules, which normally reside in the hierarchy /kernel or /usr/kernel. See Chapter 12, "Loading and Unloading Drivers," for the details of compiling and installing device drivers.

Multithreading

In most UNIX systems, the process is the unit of execution. In SunOS 5.x, a thread is the unit of execution. A thread is a sequence of instructions executed within a program. A process consists of one or more threads. There are two types of threads: application threads, which run in user space, and kernel threads, which run in kernel space.
The kernel is multithreaded (MT). Many kernel threads can be running kernel code, and may be doing so concurrently on a multiprocessor (MP) machine. Kernel threads may also be preempted by other kernel threads at any time. This is a departure from the traditional UNIX model where only one process can be running kernel code at any one time, and that process is not preemptable (though it is interruptible).
The multithreading of the kernel imposes some additional restrictions on the device drivers. For more information on multithreading considerations, see Chapter 4, "Multithreading" and Appendix B, "Advanced Topics."

Virtual Memory

A complete overview of the SunOS virtual memory (VM) system is far beyond the scope of this book, but two virtual memory terms of special importance are used when discussing device drivers: virtual addresses and address spaces.

Virtual Addresses

A virtual address is an address that is mapped by the memory management unit (MMU) to a physical hardware address. All addresses accessed directly by the driver are kernel virtual addresses; they refer to the kernel address space.

Address Spaces

An address space is a set of virtual address segments, each of which is a contiguous range of virtual addresses. Each user process has an address space called the user address space. The kernel has its own address space called the kernel address space.

Special Files

In UNIX, devices are treated as files. They are represented in the file system by special files. These files are advertised by the device driver and maintained by the drvconfig(1M) program. Special files commonly reside in the /devices directory hierarchy.
Special files may be of type block or character. The type indicates which kind of device driver operates the device.
Associated with each special file is a device number. This consists of a major number and a minor number. The major number identifies the device driver associated with the special file. The minor number is created and used by the device driver to further identify the special file. Usually, the minor number is an encoding that identifies the device the driver should access and the type of access to perform. The minor number, for example, could identify a tape device requiring backup and also specify whether the tape needs to be rewound when the backup operation completes.

Dynamic Loading of Kernel Modules

Kernel modules are loaded dynamically as references are made to them. For example, when a device special file is opened (see open(2)), the corresponding driver is loaded if it is not already in memory. Device drivers must provide support for dynamic loading. See Chapter 5, "Autoconfiguration," for more details about the loadable module interface.

Overview of the Solaris 2.x DDI/DKI

In System V Release 4 (SVR4), the interface between device drivers and the rest of the UNIX kernel has been standardized and documented in Section 9 of the of the Solaris 2.4 Reference Manual AnswerBook. The reference manual documents driver entry points, driver-callable functions and kernel data structures used by device drivers. These interfaces, known collectively as the Solaris 2.x Device Driver Interface/Driver-Kernel Interface (Solaris 2.x DDI/DKI), are divided into the following subdivisions:
  • Device Driver Interface/Driver Kernel Interface (DDI/DKI)

    Includes architecture-independent interfaces supported on all implementations of System V Release 4 (SVR4).

  • Solaris DDI

    Includes architecture-independent interfaces specific to Solaris.

  • Solaris SPARC DDI

    Includes SPARC Instruction Set Architecture (ISA) interfaces specific to Solaris.

  • Solaris x86 DDI

    Includes x86 Instruction Set Architecture (ISA) interfaces specific to Solaris.

  • Device Kernel Interface (DKI).

    Includes DKI-only architecture-independent interfaces specific to SVR4. These interfaces may not be supported in future releases of System V. Only two interfaces belong to this group: segmap(9E) and hat_getkpfnum(9F).

The Solaris 2.x DDI/DKI, like its SVR4 counterpart, is intended to standardize and document all interfaces between device drivers and the kernel. In addition, the Solaris 2.x DDI/DKI is designed to allow source compatibility for drivers on any SunOS 5.x-based machine, regardless of the processor architecture (such as SPARC or x86). It is also intended to provide binary compatibility for drivers running on any SunOS 5.x-based processor, regardless of the specific platform architecture (sun4, sun4c, sun4d, sun4e, Sun4m, i86pc). Drivers using only kernel facilities that are part of the Solaris 2.x DDI/DKI are known as Solaris 2.x DDI/DKI-compliant device drivers.
The Solaris 2.x DDI/DKI allows platform-independent device drivers to be written for SunOS 5.x based machines. These "shrink-wrapped" (binary compatible) drivers allow third-party hardware and software to be more easily integrated into SunOS 5.x based machines. The Solaris 2.x DDI/DKI is designed to be architecture independent and allow the same driver to work across a diverse set of machine architectures.
Platform independence is accomplished in the design of DDI portions of the Solaris 2.x DDI/DKI. The following main areas are addressed:
  • Interrupt handling.
  • Accessing the device space from the kernel or a user process (register mapping and memory mapping).
  • Accessing kernel or user process space from the device (DMA services).
  • Managing device properties.

Device Tree

Architectural independence is achieved in the Solaris 2.x DDI/DKI through a layered approach implemented as a tree structure. Each node in the tree structure is described by a device-information structure. Standard device drivers and their devices are associated with leaf nodes. These drivers are called leaf drivers. Bus drivers are associated with bus nexus nodes and are called bus nexus drivers. This book documents writing leaf drivers only. Figure 1-1 illustrates possible device tree configurations.

图形

Figure 1-1

The topmost node in the device tree is called the root node. The tree structure creates a parent-child relationship between nodes. This parent-child relationship is the key to architectural independence. When a leaf or bus nexus driver requires a service that is architecturally dependent in nature, it requests its parent to provide the service.
The intermediate nodes in the tree are generally associated with buses, such as the SBus, SCSI, and EISA busses. These nodes are called bus nexus nodes and the drivers associated with them are called bus nexus drivers. Bus nexus drivers encapsulate the architectural dependencies associated with a particular bus. This manual does not document writing bus nexus drivers.
This approach allows drivers to function regardless of the architecture of the machine or the processor. In all of the architectural configurations in Figure 1-1, the xyz driver can be source compatible and it can be binary compatible if the system uses the same Instruction Set Architecture.
Additionally, in Figure 1-1, the bus nexus driver associated with the SBus-to-VMEbus adapter card handles all of the architectural dependencies of the interface. The xyz driver only needs to know that it is connected to a VMEbus.

Example Device Tree

In this example, the system builds a tree structure that contains information about the devices connected to the machine at boot time. The system uses this information to build a node for each device and to create a dependency tree.
Figure 1-2 illustrates two device trees that might be created for particular SPARCstation and x86 machines.

图形

Figure 1-2

Each node is given a name by the kernel internally, which is not necessarily the same name that applications use.
Associated with each leaf or bus nexus node may be a driver. Each device driver has associated with it a device operations structure (see dev_ops(9S)) that defines the operations that the device driver can perform. The device
operations structure contains function pointers for generic operations such as identify(9E) and attach(9E). It also contains a pointer to operations specific to bus nexus drivers and a pointer to operations specific to leaf drivers.
The SPARCstation in Figure 1-2 has several on-board devices and a number of SBus devices. On-board, it has some serial chips (zs), a floppy drive (fd) and an audio device. These on-board devices are children of the root node. On the SBus, it has a frame buffer (cgthree), an ethernet interface (le) and a SCSI host adapter (esp). These devices are represented as children of the SBus node. Finally, there are two disk devices (sd) connected to the SCSI host adapter, and these are represented as leaf nodes on the SCSI host adapter.
The x86 device tree has an ISA bus, which has a network device (smc), an asynchronous communication device (asy) and a SCSI host adapter (aha). As in the SPARCstation example, these devices are represented as children of their physical parent, which in this case is the ISA bus node. The SCSI host adapter also has two children, a disk (cmdk) and a tape (cmtp).
The x86 device tree also shows the pseudo bus nexus node. This node is the parent of all pseudo device drivers (drivers without hardware).
The prtconf(1M) and sysdef(1M) commands display the internal device tree. The /devices hierarchy is the external representation of the device tree; ls(1) can be used to view it.