This chapter provides an overview of the SunOS kernel and the manner in which it represents devices as nodes in a device tree. It covers general kernel structure and function, and the Solaris 7 Device Driver Interface/Driver Kernel Interface (DDI/DKI). In addition, driver binding to device nodes is discussed in relation to both specific and generic device names.
The SunOS kernel is a program that manages system resources. It insulates applications from the system 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 kernel provides a set of interfaces for applications to use called system calls. System calls are documented in the Solaris 2.7 Reference Manual (see Intro(2)). The function of some system calls is to invoke a device driver to perform I/O. Device drivers are loadable modules that insulate the kernel from device hardware and manage data transfers.
The remainder of this book discusses the specifics of device drivers. For details on compiling and installing a device driver, see Chapter 15, Loading and Unloading Drivers. The following sections provide additional high-level information on the SunOS operating system.
In most UNIX systems, the process is the unit of execution. In the SunOS 5.7 system, 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 pre-empted by other kernel threads at any time. This is a departure from the traditional UNIX model where only one process can run kernel code at any one time, and that process is not pre-emptable (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, Multithreadingand Appendix G, Advanced Topics.
A complete overview of the SunOS virtual memory (VM) system is beyond the scope of this book, but two virtual memory terms of special importance are used when discussing device drivers: virtual address and address space.
Virtual address - A virtual address is an address that is mapped by the memory management unit (MMU) to a physical hardware address. All addresses directly accessible by the driver are kernel virtual addresses; they refer to the kernel address space.
Address space - 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.
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 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 is complete.
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.
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.7 Reference Manual. 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 7 Device Driver Interface/Driver Kernel Interface (Solaris 7 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 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 7 DDI/DKI, like its SVR4 counterpart, is intended to standardize and document all interfaces between device drivers and the kernel. In addition, the Solaris 7 DDI/DKI is designed to allow source compatibility for drivers on any SunOS 5.7-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.7-based processor, regardless of the specific platform architecture (sun4c, sun4d, sun4m, sun4u, i86pc). Drivers using only kernel facilities that are part of the Solaris 7 DDI/DKI are known as Solaris 7 DDI/DKI-compliant device drivers.
The Solaris 7 DDI/DKI allows platform-independent device drivers to be written for SunOS 5.7-based machines. These shrink-wrapped (binary compatible) drivers allow third-party hardware and software to be more easily integrated into SunOS 5.7-based machines. The Solaris 7 DDI/DKI is designed to be architecture independent and enable 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 7 DDI/DKI. The following main areas are addressed:
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
The kernel uses a tree structure to represent various physical machine configurations. 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 manual documents writing leaf drivers and one type of nexus driver, a SCSI host bus adapter (HBA) driver. This manual does not document any other type of bus nexus driver. Figure 1-1 illustrates two possible device tree configurations.
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 PCI buses. 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 approach enables drivers to function regardless of the architecture of the machine or the processor. The xyz driver, for example, is source compatible with the architectural configurations shown in Figure 1-1; 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 PCI-to-SBus adapter card handles all of the architectural dependencies of the interface. The xyz driver only needs to determine that it is connected to an SBus.
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 create a dependency tree with bus nexus nodes and leaf nodes.
Figure 1-2 illustrates a sample device tree for a frame buffer (SUNW,ffb), a pseudo bus nexus node, and several PCI devices associated with a PCI bus nexus node.
In Figure 1-2, the SUNW,ffb leaf node represents a system frame buffer. The pseudo bus nexus node is the parent node of any pseudo device drivers (drivers without hardware). The PCI bus nexus node is the parent node for the following children:
ebus--the ebus bus nexus node
hme--the Ethernet driver
glm--the SCSI host bus adapter (HBA) nexus node
The ebus nexus node is both the child of the PCI bus nexus node and the parent node of the following leaf nodes: fdthree (a floppy disk device), SUNW,CS4231 (an audio device) and se (a serial device). The Ethernet driver (hme) is a leaf node and therefore has no children. The SCSI HBA node (glm) has a number of disk devices as leaf nodes.
Associated with each leaf or bus nexus node may be a device driver. Each 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 getinfo(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 device tree can be displayed in two ways:
The prtconf(1M) command displays all of the device nodes in the device tree.
The /devices hierarchy is a representation of the device tree; use ls(1) to view it.
/devices displays only devices that have drivers configured into the system. prtconf(1M) shows all device nodes regardless of whether a driver for the device exists on the system or not.
SUNW,Ultra-1 ... pci, instance #0 ebus, instance #0 auxio (driver not attached) power (driver not attached) SUNW,pll (driver not attached) sc (driver not attached) se, instance #0 su, instance #0 su, instance #1 ecpp (driver not attached) fdthree (driver not attached) eeprom (driver not attached) flashprom (driver not attached) SUNW,CS4231 (driver not attached) network, instance #0 scsi, instance #0 disk (driver not attached) tape (driver not attached) sd, instance #0 sd, instance #1 (driver not attached) sd, instance #2 (driver not attached) sd, instance #3 (driver not attached) sd, instance #4 (driver not attached) sd, instance #5 (driver not attached) .... pci, instance #1 SUNW,UltraSPARC-II (driver not attached) SUNW,ffb (driver not attached) pseudo, instance #0
The /devices hierarchy provides a name space that represents the device tree. Following is an abbreviated listing of the /devices name space. The sample output corresponds to the example device tree and prtconf(1M) output shown previously.
/devices /devices/pseudo /devices/SUNW,ffb@1e,0:ffb0 /devices/pci@1f,4000/ebus@1 /devices/pci@1f,4000/scsi@3 /devices/pci@1f,4000/scsi@3:devctl /devices/pci@1f,4000/ebus@1/ecpp@14,3043bc:ecpp0 /devices/pci@1f,4000/ebus@1/se@14,400000:0,hdlc /devices/pci@1f,4000/ebus@1/se@14,400000:1,hdlc /devices/pci@1f,4000/ebus@1/se@14,400000:a /devices/pci@1f,4000/ebus@1/se@14,400000:a,cu /devices/pci@1f,4000/ebus@1/se@14,400000:b /devices/pci@1f,4000/ebus@1/se@14,400000:b,cu /devices/pci@1f,4000/ebus@1/SUNW,CS4231@14,200000:sound,audio /devices/pci@1f,4000/ebus@1/SUNW,CS4231@14,200000:sound,audioctl /devices/pci@1f,4000/scsi@3/sd@0,0:a /devices/pci@1f,4000/scsi@3/sd@0,0:a,raw
Binding a driver to a device node refers to the process by which the system selects a driver to manage a particular device. The driver binding name is the name that links a driver to a unique device node in the device information tree. For each device in the device tree, the system chooses a driver from a list of drivers.
Each device node has a name property associated with it. This property may be derived either from an external agent such as the PROM during system boot or from a driver.conf file. In either case, the name property represents the node name assigned to a device in the device tree.
A device node may also have a compatible property associated with it. The compatible property (if it exists) contains an ordered list of one or more possible driver names for the device.
The system uses both the name and the compatible properties to select a driver for the device. If the compatible property exists, the system first attempts to match the contents of the compatible property to a driver on the system. The compatible property is simply a list of possible driver names from which the system can determine the specific driver binding name for the device.
Beginning with the first driver name on the compatible property list, the system attempts to match the driver name to a known driver on the system. It processes each entry on the list until either a match is found or the end of the list is reached.
If the contents of either the name property or the compatible property match a driver on the system, then that driver is bound to the device node. If no match is found, no driver is bound to the device node.
Some devices with a compatible property use a generic device name as the value for the name property. Generic device names describe the function of a device without actually identifying a specific driver for the device. For example, a SCSI host bus adapter may have a generic device name of scsi. An Ethernet device may have a generic device name of ethernet.
The compatible property allows the system to determine alternate driver names (like glm for scsi HBA device drivers or hme for ethernet device drivers) for devices with a generic device name.
Devices with generic device names must supply a compatible property.
For a complete description of generic device names, see the IEEE 1275 Open Firmware Boot Standard.
For the device node with a specific device name, the driver binding name SUNW,ffb is the same name as the device node name.
For the device node with the generic device name display, the driver binding name SUNW,ffb is the first name on the compatible property driver list that matches a driver on the system driver list. In this case, display is a generic device name for frame buffers.