Kernel Initialization

A brief view of kernel initialization

Important file(s):

Two categories of initializations:

Local APIC (advanced programmable interrupt controller) -- per cpu

IOAPIC -- only once

Other per-CPU initialization:

read more in main.c

Device driver and xv6's vfs: console

Linux (Unix) uses a major:minor pair to specify a device. The numbers are only meaningful at runtime.

To show a list of devices on your Linux: ls -al /dev

Example, tty0, tty1, ... all has the same #major, but different #minor

Similarly, In xv6, the major number is used to select the driver API (read, write, ioctl, etc.).

file.c:devsw is a statically-allocated table of NDEV entries. There can be at most NDEV types of drivers in xv6.

Read the readi() and writei() functions in fs.c. When performing read/write operations on an inode, the kernel will check if this is a device file. If yes, the appropriate driver function will be selected and called.

writei():

devsw[ip->major].write(ip, src, off, n);

UNIX has a famous "everything is a file" philosophy. As it says, almost everything in the system, including real file and "fake" files are linked into one root file system. This explains why the driver code is mingled with the file system code.

Initialization:

console.c:consoleinit()

The console driver is statically assigned a major number CONSOLE (1). The kernel registers the console driver on the devsw table.

init.c: the first process "init" creates a device file "console", with major=1.

After this, when the "console" file is opened and is read/written, the driver functions in console.c will be invoked to handle the read/write request.

Now you know that adding a new driver to xv6 is quite easy. It's somehow more complex in Linux. 

Extended reading:

The IDE hard disk driver (ide.c)

https://wiki.osdev.org/ATA_PIO_Mode#Registers this explains the io ports.

https://wiki.osdev.org/ATA_PIO_Mode#x86_Directions this shows some programming examples.

ideinit():

iderw():

idestart():

ideintr():

About the queue(s):