From b84c5822df6bf79b0fc9d146a93e58d9cba6cde1 Mon Sep 17 00:00:00 2001 From: Philipp Oppermann Date: Sat, 28 May 2016 15:22:18 +0200 Subject: [PATCH] Create interrupt module with IDT submodule --- Cargo.toml | 5 +- src/interrupts/idt.rs | 103 ++++++++++++++++++++++++++++++++++++++++++ src/interrupts/mod.rs | 1 + src/lib.rs | 3 ++ 4 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 src/interrupts/idt.rs create mode 100644 src/interrupts/mod.rs diff --git a/Cargo.toml b/Cargo.toml index d0cb6f3c..a5503538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,10 +4,11 @@ name = "blog_os" version = "0.1.0" [dependencies] +bit_field = "0.1.0" +bitflags = "0.7.0" once = "0.2.1" rlibc = "0.1.4" spin = "0.3.4" -bitflags = "0.7.0" [dependencies.hole_list_allocator] path = "libs/hole_list_allocator" @@ -17,7 +18,7 @@ git = "https://github.com/phil-opp/multiboot2-elf64" [dependencies.x86] default-features = false -version = "0.6.0" +version = "0.7.0" [lib] crate-type = ["staticlib"] diff --git a/src/interrupts/idt.rs b/src/interrupts/idt.rs new file mode 100644 index 00000000..ea7c41cd --- /dev/null +++ b/src/interrupts/idt.rs @@ -0,0 +1,103 @@ +use x86::segmentation::{self, SegmentSelector}; + +pub struct Idt([Entry; 16]); + +impl Idt { + pub fn new() -> Idt { + Idt([Entry::missing(); 16]) + } + + pub fn set_handler(&mut self, entry: u8, handler: HandlerFunc) -> &mut EntryOptions { + self.0[entry as usize] = Entry::new(segmentation::cs(), handler); + &mut self.0[entry as usize].options + } + + pub fn load(&'static self) { + use x86::dtables::{DescriptorTablePointer, lidt}; + use core::mem::size_of; + + let ptr = DescriptorTablePointer { + base: self as *const _ as u64, + limit: (size_of::() - 1) as u16, + }; + + unsafe { lidt(&ptr) }; + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct Entry { + pointer_low: u16, + gdt_selector: SegmentSelector, + options: EntryOptions, + pointer_middle: u16, + pointer_high: u32, + reserved: u32, +} + +type HandlerFunc = extern "C" fn() -> !; + +impl Entry { + fn new(gdt_selector: SegmentSelector, handler: HandlerFunc) -> Self { + let pointer = handler as u64; + Entry { + gdt_selector: gdt_selector, + pointer_low: pointer as u16, + pointer_middle: (pointer >> 16) as u16, + pointer_high: (pointer >> 32) as u32, + options: EntryOptions::new(), + reserved: 0, + } + } + + fn missing() -> Self { + Entry { + gdt_selector: SegmentSelector::new(0), + pointer_low: 0, + pointer_middle: 0, + pointer_high: 0, + options: EntryOptions::minimal(), + reserved: 0, + } + } +} + +use bit_field::BitField; + +#[derive(Debug, Clone, Copy)] +pub struct EntryOptions(BitField); + +impl EntryOptions { + fn minimal() -> Self { + let mut options = BitField::new(0); + options.set_range(9..12, 0b111); // 'must-be-one' bits + EntryOptions(options) + } + + fn new() -> Self { + let mut options = Self::minimal(); + options.set_present(true).disable_interrupts(true); + options + } + + fn set_present(&mut self, present: bool) -> &mut Self { + self.0.set_bit(15, present); + self + } + + fn disable_interrupts(&mut self, disable: bool) -> &mut Self { + self.0.set_bit(8, !disable); + self + } + + fn set_privilege_level(&mut self, dpl: u16) -> &mut Self { + self.0.set_range(13..15, dpl); + self + } + + fn set_stack_index(&mut self, index: u16) -> &mut Self { + self.0.set_range(0..3, index); + self + } +} diff --git a/src/interrupts/mod.rs b/src/interrupts/mod.rs new file mode 100644 index 00000000..e640a3f1 --- /dev/null +++ b/src/interrupts/mod.rs @@ -0,0 +1 @@ +mod idt; diff --git a/src/lib.rs b/src/lib.rs index 9b131ead..d0512afd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,6 +20,7 @@ extern crate bitflags; extern crate x86; #[macro_use] extern crate once; +extern crate bit_field; extern crate hole_list_allocator; extern crate alloc; @@ -30,6 +31,8 @@ extern crate collections; mod vga_buffer; mod memory; +mod interrupts; + #[no_mangle] pub extern "C" fn rust_main(multiboot_information_address: usize) { // ATTENTION: we have a very small stack and no guard page