Screen Version
School of Computer Science & Engineering
University of New South Wales

 Advanced Operating Systems 
 COMP9242 2004/S2 

M4: A Clock driver

In this milestone you will implement a clock driver, and the two timer-related system calls. The timer-related system calls must be implemented using your driver.



Although the kernel provides a SystemClock system call, for many purposes, e.g., benchmarking, a higher clock resolution is desired. The U4600 machines feature a chip which contains several high-frequency counters which can be used for a timer.

The Driver Interface

Your driver needs to export the interface specified in src/clock.h. There are the following functions:

Initialises the driver.
Registers the calling thread to receive an IPC message after a specified time interval (in microseconds, though actual wakeup resolution will depend on the timer resolution). Several registrations may be pending at any time.
Returns the current real-time clock value (microsecond accurate).
Stops operation of the driver. This will cancel any outstanding timer requests (by sending them a premature IPC indicating failure).

The interface is just an internal funciton call interface. You do not need to export this interface to the users. User programs will indirectly access the clock driver through the time and sleep syscalls.

The IPC message sent by the timer contains in MR0 a return code (TIMER_R_OK, TIMER_R_UINT, TIMER_R_CNCL) and in MR1 the present value of the real-time clock.

The U4600

U4600 archritecture This is a simplified block diagram of the U4600 boards. The GT chip is a PCI bridge. It acts to interface the CPU with the PCI bus as well as to memory. Full details of the GT chip can be found its reference manual [1].

The R4600 has 8 IRQ exceptions consisting of 2 "software IRQs", 5 external hardware IRQs, and 1 IRQ that can be configured via external logic to either the internal timer (which it is on the U4600) or another external IRQ.

GT Chip

Your main job is to learn how to program the GT chip to generate timer interrupts and how to write an L4 driver to handle these interrupts.

The GT chip contains four 24 bit timer/counters. For our purposes, we are only interested in the GT chip as our source of timer interrupts. You will only be using one of these timers. The GT's interrupt line is connected to CPU interrupt pin 3 (which corresponds to interrupt 5 when you take into account the two software interrupts).

There is an abundance of different devices and writing device drivers is usually seen as a very difficult task. This is true in a sense. However, programming a device is really just a matter of learning about its registers, what values to read and write to those registers and when to do it.

The minimal subset of the GT chip's functionality that you must understand and use is listed below (the numbers in parentheses are the offsets of the register addresses from the chip's base address). Refer to the reference manual for full(er) descriptions [1].

Again, this is only the minimal understanding that you need. For deeper understanding, you are encouraged to learn about the other registers and can even play with those as well.

NOTE: This section is deliberately kept short (e.g., we do not dictate which timer to use or in what mode to use it in). The idea is that you work things out for yourself and make your own design and implementation decisions. There are only two conditions that must be satisfied:

  1. You must use an interrupt generated from the GT chip.
  2. You must implement the driver interface described above.

Pistachio/MIPS Interrupts

The Pistachio/MIPS kernel exports specific interrupts to a user level interrupt handler via IPC. User level threads are associated with interrupts by the privileged task using the ThreadControl call. After that, any interrupts of the registered number will get sent as an IPC to the interrupt handler thread.

Refer to the L4Ka reference manual for further information on the interrupt registration and delivery protocol.

You are provided with a libdevice which simplifies the process of registering an interrupt handler. You can are free to either use libdevice or manually register for interrupts yourself.

Device Mappings

In Pistachio/MIPS, device registers are memory mapped. That is, hardware registers can be accessed via normal load/store operations to special addresses. To access device registers, you must first request the correct device mapping from sigma0.

Note that all accesses device registers must bypass the cache. When requesting device mappings from sigma0 you must specify that you want unchached mappings. Again using libdevice should simplify the task of obtaining device mappings.


Devices often use a different byte order than the CPU, so device drivers must generally deal with endianess, and your clock driver is no exception. Endianess refers to how indivdual bytes within a multi-byte word are addressed. The following two figures should illustrate how big and little endian works. In the figure the numbers refer to the relative addresses of the individual bytes.


The R4600 is big endian while all GT chip registers are little endian. Therefore, you will need to do some byte swapping when reading from and writing to the GT registers.


You may need to resolve some or all of these issues:


The file clock.h, as well as some other header files you might find useful, can be found here.


Should be able to show some test code that uses all the function specified in the driver interface.

You should also show some user level test code that uses the time_stamp and sleep system calls. You may find it useful to extend sosh to have a time and sleep command. The sleep implemention must use your clock driver.

Last modified: 31 Aug 2004.