StuBS
Loading...
Searching...
No Matches
Assignment 2: Interrupts

StuBS needs simple interrupt handling, e.g. for the keyboard. To configure the interrupts, StuBS will support the Advanced Programmable Interrupt Controller.

A driver for an interrupt-driven device like the Keyboard inherits from Gate, defining the interface. The Plugbox stores the mapping from interrupt vectors to Gate objects and gets queried by the interrupt_handler during interrupt handling.

However, to allow interrupts from external devices you have to configure them in the IOAPIC during initialization. The low level part of the interrupt_handler, including the entry functions, setting up the IDT and LAPIC, as well as helper functions (e.g., to enable/disable interrupts on the current core), are already implemented.

dot_a2.png
Map of important classes for the second assignment

Learning Objectives

  • Handling of asynchronous events
  • Problems and protection of critical sections

Configuring I/O APIC

Modern PCs usually support xAPIC, having up to 24 external devices connected to the I/O APIC (you can even have multiple I/O APICs – although StuBS only supports the first one), with a local APIC integrated in each core and all connected via the APIC bus.

During the boot process, interrupts are masked (i.e., disabled) for each core and the I/O APIC. Implement the functions in IOAPIC to initialize the IOAPIC and configure interrupts from external sources. To test your implementation, you can configure (high level triggered: IOAPIC::HIGH & IOAPIC::LEVEL) and enable interrupts from the keyboard (using APIC::getIOAPICSlot with APIC::KEYBOARD). The interrupt vector table has already been initialized by the startup code, so that the interrupt_handler() should C-function will be executed with appropriate arguments when an interrupt, like a key press or release, occurs! However, since the characters are not fetched by the PS2Controller, you will continuously receive the interrupt until you empty the keyboard buffer by reading its content using either PS2Controller::fetch() or PS2Controller::drainBuffer().

Depending on the environment, it may also be necessary to empty the keyboard buffer completely before reactivating interrupts.

Hints

  • During the handling of an interrupt, you don't need to worry about unwanted interrupts. They are disabled on the corresponding core when handling starts, and not enabled until the interrupt_handler() returns (and the interrupt_entry() function exits the handling using the assembler statement iret [interrupt return]).
  • Obviously, interrupt handling will only work if StuBS is running. As soon as it leaves the main() function, it returns to kernel_init(), which disables interrupts and stops the current core by calling Core::die() – an operating system should not suddenly stop 😉. In MPStuBS this also applies to main_ap(), which is executed by the application processors.
  • To make your life easier, we provide an implementation of the Local APIC. In addition, the startup code ensures that the LAPIC is in a well defined state, hence the interrupt handling should already work if you implement the functions in IOAPIC correctly.
  • According to the specification (see ISDMv3, 10.8.5 Signaling Interrupt Servicing Completion) it is necessary to confirm the processing of each interrupt (EOI). To do this, call LAPIC::endOfInterrupt() in the interrupt_handler.

Further Reading

Managing Devices with the Plugbox

Now you need to make sure that each device driver's interrupt service routine is called once the corresponding interrupt fires. The Plugbox should be used to manage those driver objects, providing a pointer to a Gate object for each registered interrupt vector. Gate is an abstract class that describes the interface of all interrupt handling drivers.

Initially, all indices (vectors) of the Plugbox should point to a (global) device driver object which – as the name implies – should cause the kernel to panic if an unknown interrupt fires.

Keyboard Device Driver

Write the Keyboard device driver which implements the Gate interface and should be registered to handle the interrupts triggered by the keyboard. For now, after each keystroke, the corresponding characters should be displayed on the screen. Allocate one line of your screen to display these characters. The key combination Ctrl-Alt-Delete should trigger a system reboot.

You can reuse the PS2Controller implementation of assignment 1 to query for the Key, however, you have to adjust the function PS2Controller::fetch(Key&) to the changed situation.

Test Application (+ Locks)

Adapt your test program to the interrupt processing.

OOStuBS

Implement a test program in Application::action(), which is called from main(). This should infinitely generate output (for example, an increasing number) at a fixed position of the main output window kout (using TextStream::setPos()).

With the keyboard driver implemented as described above, pressing keys will jumble the application's output. Think about what is happening, why it is happening, and avoid the problem using functions provided by the Core namespace (or its subnamespaces) – while still using the kout object for the Keyboard device.

MPStuBS

Implement a test program in Application::action() similar to OOStuBS, but create an instance for each core, which is then called in main() and main_ap() respectively. The output of each instance should be in a distinct but fixed line in kout. On the first execution, you'll see that the multi-core system does not even need interrupts to mess up the output (Think about why that is the case). To avoid this problem, the methods provided by Core alone are not enough. Therefore, you have to write a Spinlock (or Ticketlock) in order to synchronize parallel control flows. Think about what must be considered when using locks and what problems can occur.

Further Reading: Mutual exclusion (mutex)