Skip to content

Commit

Permalink
Merge pull request #473 hardware-interrupts
Browse files Browse the repository at this point in the history
  • Loading branch information
phil-opp committed Oct 15, 2018
2 parents 164e9a8 + a08ba0b commit 0212ca4
Show file tree
Hide file tree
Showing 9 changed files with 58 additions and 22 deletions.
38 changes: 27 additions & 11 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ spin = "0.4.6"
volatile = "0.2.3"
uart_16550 = "0.1.0"
x86_64 = "0.2.8"
pic8259_simple = "0.1.1"

[dependencies.lazy_static]
version = "1.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ pub mod interrupts;

// in src/interrupts.rs

use pic8259::ChainedPics;
use pic8259_simple::ChainedPics;
use spin;

pub const PIC_1_OFFSET: u8 = 32;
Expand Down Expand Up @@ -165,7 +165,7 @@ pub extern "C" fn _start() -> ! {

The `interrupts::enable` function of the `x86_64` crate executes the special `sti` instruction (“set interrupts”) to enable external interrupts. When we try `bootimage run` now, we see that a double fault occurs:

TODO screenshot
![QEMU printing `EXCEPTION: DOUBLE FAULT` because of hardware timer](qemu-hardware-timer-double-fault.png)

The reason for this double fault is that the hardware timer (the [Intel 8253] to be exact) is enabled by default, so we start receiving timer interrupts as soon as we enable interrupts. Since we didn't define a handler function for it yet, our double fault handler is invoked.

Expand Down Expand Up @@ -208,7 +208,7 @@ We introduce a `TIMER_INTERRUPT_ID` constant to keep things organized. Our `time

In our timer interrupt handler, we print a dot to the screen. As the timer interrupt happens periodically, we would expect to see a dot appearing on each timer tick. However, when we run it we see that only a single dot is printed:

TODO screenshot
![QEMU printing only a single dot for hardware timer](qemu-single-dot-printed.png)

### End of Interrupt

Expand All @@ -233,7 +233,7 @@ We need to be careful to use the correct interrupt vector number, otherwise we c

When we now execute `bootimage run` we see dots periodically appearing on the screen:

TODO screenshot gif
![QEMU printing consequtive dots showing the hardware timer](qemu-hardware-timer-dots.gif)

### Configuring The Timer

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/interrupts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use pic8259_simple::ChainedPics;
use spin;

pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;

pub static PICS: spin::Mutex<ChainedPics> =
spin::Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });

pub const TIMER_INTERRUPT_ID: u8 = PIC_1_OFFSET;
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern crate spin;
extern crate volatile;
#[macro_use]
extern crate lazy_static;
extern crate pic8259_simple;
extern crate uart_16550;
extern crate x86_64;

Expand All @@ -14,6 +15,7 @@ extern crate array_init;
extern crate std;

pub mod gdt;
pub mod interrupts;
pub mod serial;
pub mod vga_buffer;

Expand Down
21 changes: 14 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern crate x86_64;
extern crate lazy_static;

use core::panic::PanicInfo;
use blog_os::interrupts::{self, PICS};

/// This function is the entry point, since the linker looks for a function
/// named `_start` by default.
Expand All @@ -20,13 +21,8 @@ pub extern "C" fn _start() -> ! {

blog_os::gdt::init();
init_idt();

fn stack_overflow() {
stack_overflow(); // for each recursion, the return address is pushed
}

// trigger a stack overflow
stack_overflow();
unsafe { PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();

println!("It did not crash!");
loop {}
Expand All @@ -52,6 +48,9 @@ lazy_static! {
.set_stack_index(blog_os::gdt::DOUBLE_FAULT_IST_INDEX);
}

let timer_interrupt_id = usize::from(interrupts::TIMER_INTERRUPT_ID);
idt[timer_interrupt_id].set_handler_fn(timer_interrupt_handler);

idt
};
}
Expand All @@ -71,3 +70,11 @@ extern "x86-interrupt" fn double_fault_handler(
println!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
loop {}
}

extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: &mut ExceptionStackFrame) {
print!(".");
unsafe {
PICS.lock()
.notify_end_of_interrupt(interrupts::TIMER_INTERRUPT_ID)
}
}

0 comments on commit 0212ca4

Please sign in to comment.