UP
 
EROS Web
 
Developer Documentation
 
Programmer's Guide
 

Kernel Configuration

D R A F T

 
 

This note is still a work in progress.

Configuring a kernel consists of deciding which options, drivers and subsystems to include, which specific devices to define, and establishing values for some key kernel parameters. This note describes how the configuration process works in EROS.

1. Introduction

Configuring a kernel is complex and painful. Certain devices do not autoconfigure gracefully at all. Others configure fine, but can only be included if a supporting option is enabled. Different machines have different CPU's, and in some cases it is appropriate to build a kernel with CPU-specific dependencies. Knowing that the kernel will be run on a Pentium Pro as opposed to a Pentium makes a significant difference in how code is generated in a few critical paths. Certain kernel files are not required unless the corresponding option has been enabled. Sometimes it is desirable to build multiple variants on the kernel simultaneously.n

The BSD 4.4 kernel has a flexible configuration system, but it is extremely obscure. For the most part, this obscurity is caused by two factors:

  • Nobody has bothered to document it properly, so it is hard to understand what it does.

  • The BSD kernel design was predicated on the assumption that controllers cannot be automatically identified and configured by the kernel. While there remain exceptional controllers, this is no longer true for most architectures.

What is required is a configuration system that can describe the drivers and options to be included, and where required the specific device instances to be created.

The current EROS configuration utility is a prototype, and is implemented in python. This has proven convenient for experimentation, but has negative impacts on the syntax of the configuration input files. I expect at some point to re-implement the configuration file parser using the kjParser package. If necessary, I'll go to a yacc grammar, but that has its own problems; most notably it requires tools to be compiled prior to the kernel build. The current build assumes that only a standard UNIX environment is required to start the kernel build, and I am reluctant to start another bootstrap directory hierarchy.

2. Configuration Output

Before describing what the configuration input looks like, it's probably worth describing what the result of a successful configuration is. Obviously, a successful configuration recognizes the devices that are present -- or at least the present devices that are supported by this kernel. In addition, however, a configuration should yield an equipment tree that describes how these devices are hooked together. As an example, here is the actual hardware configuration of the main EROS development machine:

root
 |
 +-- mainboard 0 (bus)
 |   |
 |   +-- memory                   (device)
 |   +-- pic1                     (device)
 |   +-- pic2                     (device)
 |   +-- dma1                     (device)
 |   +-- dma2                     (device)
 |   +-- rtc                      (ctrlr)
 |   +-- kbd                      (ctrlr)
 |   +-- timer                    (ctrlr)
 |   +-- npu                      (device)
 |   +-- tty0                     (ctrlr)
 |   +-- tty1                     (ctrlr)
 |   +-- fd0                      (ctrlr)
 |       |
 |       +-- fd0.0                (device)
 |
 +-- Intel 82439HX Triton II      (bridge)
     |
     +-- pci0                     (bus)
         |
         +-- vga(S3)              (device)
         +-- net0 (3c905)         (ctrlr)
         +-- scsi0 (aic7871)      (bus)
         |   |
         |   +-- sd0.0            (device)
         |       Quantum Maverick 540S Rev 0905
         |
         +-- Intel 82371SB Natoma (bridge)
             |
             +-- isa0             (bus)
             |   |
             |   +-- 3c509        (ctrlr)
             |
	     +-- ide0             (bus)
	     |   |
	     |   +-- ide0.0       (device)
	     |   |   Quantum Fireball TM3840A, FwRev A6B.2400
	     |   |
	     |   +-- ide0.1       (device)
	     |       Quantum Fireball 1280a, FwRev=A63.0E00
	     |
	     +-- ide1             (bus)
	         |
	         +-- ide1.0       (device)
	         |   Maxtor 88400D8, FwRev=NAVX171F
	         |
	         +-- ide1.1       (device)
	             ATAPI CD-ROM

The goal of the configuration process is to build something that closely approximates this tree. In practice, the configuration mechanism gets pretty close to building the tree as described, but in one area we have cheated: the primary disk interface.

For the sake of BIOS compatibility, the PC architecture provides for an I/O register interface to the primary hard disk controller. If this controller is a floppy, RLL, ST506, ESDI, or IDE controller, then it speaks primarily through this interface (possibly using supporting DMA logic if it sits on a PCI bus), and its presence is detected through the register interface.

For SCSI controllers this presents a problem: we would like to know that the device in question is a SCSI device and speak to it accordingly.

To address this, all of the floppy, RLL, ST506, ESDI, and IDE cases are described as "block devices" in the configuration description. Because block devices are configured after SCSI devices, the legacy register interface will prevail only if the controller has not already been detected as a SCSI controller. If a block device is present, the configuration procss makes a half-hearted attempt to attach the controller to the right bus if it is able to detect it. Failing that, the controller will appear as a mainboard device.

At present, the EROS kernel performs device configuration without actually building the device tree, because doing so was not essential for my thesis work. The description above reflects where the implementation should go, and will when I get a chance to make it so.

2. Configuration File

The configuration file must accomplish four things:

  1. Identify the machine type, the processor implementations to be supported, and the bus types to be included.

  2. Define the options to be included in the constructed kernel, if any. If necessary, defining those options that are specific to this machine.

  3. Define the drivers the devices that should be configured into the kernel, and how they are hooked into the bus hierarchy. If necessary, this also describes any appropriate constraints on the probe logic.

  4. Specifying the files that will be compiled into the kernel on the basis of the included options and devices.

2.1 Describing the Machine, CPU, and Bus Types

The supported machines and their associated cpu types are known to the configuration utility. Currently supported machines and CPUs are:

Machine CPU Types
pc i386, i486, pentium, ppro

In the most complete machine definition for the PC, the supported machine and CPU types are described by the lines:

    include("../../../config.common")
    	
    machine("pc")       # basic machine category
    
    cpu("i386")         # ensure that each of these
    cpu("i486")         # processor types is supported
    cpu("pentium")
    cpu("ppro")
    
    bus(BT_PCI)         # handle machines including
    #bus(BT_EISA)       # these bus types
    bus(BT_ISA)
    #bus(BT_SCSI)
    #bus(BT_USB)
    	

The EISA bus is not supported at present, and likely never will be. SCSI and USB support has not yet been implemented.

2.2 Architecture-Specific Options

The PC provides a machine-specific kernel feature that is supported in a number of source files: small address spaces. Since this option is not general to all processors, it must be defined as an option for the PC family:

    defoption("small_spaces")
    	

Having defined the options, the configuration file now specifies which options are to be included in this configuration:

    option("ddb")
    option("small_spaces")
    option("inet")
    #option("npx")
    #option("scsi")
    	

The set of machine-independent options is defined in the config.common file, included at the head of the configuration file.

2.3 Describe Configuration Templates

Having described the options supported and the options selected, the next step is to identify the driver templates to be included in this kernel. For each driver, the associated bus type must be identified, and the probe restrictions, if any, must be described. The commands for doing this are the base_template(), pci_template(), scsi_template(), isa_template(), eisa_template(), and usb_template() statements. In addition, the basic kernel threads are configured here. An abbreviated configuration file is shown below:

    #############################################
    #
    # Kernel threads
    #
    #############################################
    
    base_template("checker")
    base_template("idler")
    base_template("twiddler")
    
    #############################################
    # NPX "device" is always present if option
    # NPX is enabled, but in that case may be
    # implemented in software.  This template
    # lets us autoconfigure the emulation code
    # if the NPX unit is not present.
    #############################################
    if isoption("npx"):
       base_template("npx")
    
    # RAM Disk pseudo-device:
    base_template("ramdisk")
    base_template("todclock")
    
    #############################################
    #
    # Devices associated with the main board
    #
    #############################################
    
    isa_template("kbd")
    
    base_template("ide")
    
    #############################################
    #
    # Network controllers:
    #
    #############################################
    
    pci_template("3c59x")
    	

2.4 Files to be Included

Based on the specified machine type, the configuration script examines the contents of a separate file describing how the kernel is to be compiled. For the machine 'pc', the file examined if files.pc. This configuration file contains a series of file(...) statements, that take one of two forms:

    file("arch/i486/device/net_3c59x.cxx")
    file("ddb/db_access.cxx", ddb)
    	

More generally, the optional second argument can be any boolean expression. Option names (such as 'ddb') may be used as though they were boolean variables. Device configuration can be tested using ifdevice, as in

    file("arch/i486/device/net_3c59x.cxx", ifdevice("3c59x"))
    	

2.5 Probe Controls

The following is implemented, but unused and untested.

Handling probe controls is more than a bit ugly. Basically, what we need is a vector of values indicating the I/O ports, interrupt lines, and memory address to probe. These are specified by writing a list into the template description:

    base_template("ide", mem=[0xc8000, 0xd8000],
    	      irq = [ 5, 7 ], port = [ 0x230, 0x250 ])
    	

(Note that the example numbers are randomly selected). Since in some cases there is exactly one legal IRQ value (usually coprocessors), a single IRQ value can be provided as an integer.

Allocating storage for a list for every device is prohibitive, so all such lists are merged into a single vector of integers, with entries separated by the distinguished value '-1'. A device that should be probed for at I/O ports 5 and 10 and memory addresses 0xc8000 and 0xd8000 would generate the following entries in the probe vectors:

    int io_probe_vec[] = { ....., 5, 10, -1, .... };
    int mem_probe_vec[] = { ....., 0xc8000, 0xd8000, -1, .... };
    	

The device structure contains an int* pointer into this vector, whose value is zero if there is no device probe restriction. If a device should not be probed at all, it should have a probe descriptor vector whose values are all -1.

Interrupt options are handled a bit differently, as IRQ probing can be done by provoking an interrupt. Instead, every device instance template holds an unsigned value that is a bit-vector describing which interrupts are acceptable.


Copyright 1998 by Jonathan Shapiro. All rights reserved. For terms of redistribution, see the GNU General Public License