next up previous
Next: Some Tricky Problems Up: Multiple Passes of the Previous: Multiple Passes of the

Introduction

One of the most basic tasks of an operating system is managing hardware resources. This includes directly controlling the hardware and providing interfaces to the hardware for application software. Logical functions of hardware resources are commonly called devices, and the software that controls a specific device is called a device driver. Devices may also use lower-level resources to interface to the rest of the system (examples include I/O ports, a memory-mapped I/O window, or interrupt signals). In some cases a device may provide lower-level resources for use by other devices. An example of this would be an interrupt controller which provides interrupt lines to other devices.

There is a wide assortment of hardware devices which require a correspondingly wide assortment of device drivers. To make it easier to write device drivers, operating systems typically provide a device driver framework. This framework might organize devices into a structure and/or name space. It also usually provides abstractions for managing the lower-level resources used by a device.

At its inception, FreeBSD inherited the ``old-config'' device driver framework from 4.2BSD [2]. This device driver framework suffered from the limitation that the knowledge of every device in a system was compiled into the kernel. Changing the hardware in a system required recompiling the kernel to update its configuration table or to add and remove drivers.

Hardware, however, was becoming more dynamic and intelligent. Some newer buses such as PCI and ISA Plug'n'Play provided mechanisms to enumerate devices on the bus. Other buses such as PCCard also supported adding and remove devices at run-time.

Although FreeBSD had extended ``old-config'' to add device entries for self-identifying buses such as PCI, new device drivers could not always be loaded into the system after boot. Instead, each bus driver had to provide its own infrastructure to manage this. The PCI bus driver did not support it at all. The PCCard bus driver did support loading drivers, however, it required a userland daemon to assign drivers to devices. This was problematic as the knowledge about which devices a driver supported was not contained in the driver itself but required patching a separate global config file.

In FreeBSD 3.0, a new device driver framework called ``new-bus'' [1] was developed as part of the port to the Alpha architecture. This framework was ported to the i386 architecture in FreeBSD 4.0 and has been used on all FreeBSD architecture ports since. One of the key differences between ``new-bus'' and ``old-config'' is that with ``new-bus'' the kernel no longer contains a compiled-in list of static devices. Instead, devices on non-self-enumerating buses such as ISA are described by meta-data that is separate from the kernel. Secondly, in ``new-bus'' devices are organized into a hierarchical tree. Each node in the tree is represented by an object of type device_t. This allows ``new-bus'' to better handle dynamic devices.

Prior to ``new-bus'', each bus supported by FreeBSD was statically compiled into the the kernel. In the configure function called during boot, the kernel would call a function to probe all the devices for a specific type of bus. The PCI probe routine was responsible for walking the entire PCI device tree, for example. It attached drivers to PCI devices by scanning each PCI bus sequentially. After the PCI probe had finished, the ISA probe routine was called, etc.

In ``new-bus'', any buses or bridges in the system are treated as device objects in addition to tree leaves. For example, in ``new-bus'' each PCI bus device is responsible for scanning all of its child devices. Also, bridge devices create appropriate child bus devices. For many device related requests such as resource allocation, requests by a device are passed up the device tree hierarchy. This provides a simple way for buses and bridges to operate on requests from children device. For example, routing PCI INTx interrupts for devices behind one or more PCI-PCI bridges can require routing interrupts across each PCI-PCI bridge in different ways [3]. A top-down approach such as in ``old-config'' would require that the PCI support code know all the possible methods for routing an INTx interrupt as well as which method to use for a given bridge. In ``new-bus'', however, different PCI-PCI bridge drivers implement different routing methods and the bridge driver is only responsible for routing interrupts across itself. This allows a routing request to walk up the tree using different routing methods via different bridge drivers until it is satisfied.


next up previous
Next: Some Tricky Problems Up: Multiple Passes of the Previous: Multiple Passes of the