interrupts

This commit is contained in:
charlesbvll 2021-07-22 12:25:39 +02:00
parent 50fcf59a29
commit de86827da5
8 changed files with 102 additions and 15 deletions

10
Cargo.lock generated
View File

@ -29,12 +29,22 @@ dependencies = [
"spin", "spin",
] ]
[[package]]
name = "pic8259"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08cc920d83ee33c0f9b73aa441e75468bf2d10c959a3eb6260cf720b05ac91a1"
dependencies = [
"x86_64",
]
[[package]] [[package]]
name = "rust_os" name = "rust_os"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bootloader", "bootloader",
"lazy_static", "lazy_static",
"pic8259",
"spin", "spin",
"uart_16550", "uart_16550",
"volatile 0.2.7", "volatile 0.2.7",

View File

@ -9,6 +9,7 @@ volatile = "0.2.6"
spin = "0.5.2" spin = "0.5.2"
x86_64 = "0.14.2" x86_64 = "0.14.2"
uart_16550 = "0.2.0" uart_16550 = "0.2.0"
pic8259 = "0.10.1"
[dependencies.lazy_static] [dependencies.lazy_static]
version = "1.0" version = "1.0"

View File

@ -36,12 +36,12 @@ struct Selectors {
} }
pub fn init() { pub fn init() {
use x86_64::instructions::segmentation::set_cs; use x86_64::instructions::segmentation::{CS, Segment};
use x86_64::instructions::tables::load_tss; use x86_64::instructions::tables::load_tss;
GDT.0.load(); GDT.0.load();
unsafe { unsafe {
set_cs(GDT.1.code_selector); CS::set_reg(GDT.1.code_selector);
load_tss(GDT.1.tss_selector); load_tss(GDT.1.tss_selector);
} }
} }

View File

@ -1,5 +1,6 @@
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame}; use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame};
use crate::println; use crate::println;
use crate::print;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use crate::gdt; use crate::gdt;
@ -10,9 +11,12 @@ lazy_static! {
idt.breakpoint.set_handler_fn(breakpoint_handler); idt.breakpoint.set_handler_fn(breakpoint_handler);
unsafe { unsafe {
idt.double_fault.set_handler_fn(double_fault_handler) idt.double_fault.set_handler_fn(double_fault_handler)
.set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX); // new .set_stack_index(gdt::DOUBLE_FAULT_IST_INDEX);
} }
idt[InterruptIndex::Timer.as_usize()]
.set_handler_fn(timer_interrupt_handler);
idt[InterruptIndex::Keyboard.as_usize()]
.set_handler_fn(keyboard_interrupt_handler);
idt idt
}; };
} }
@ -23,6 +27,27 @@ extern "x86-interrupt" fn double_fault_handler(
panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame); panic!("EXCEPTION: DOUBLE FAULT\n{:#?}", stack_frame);
} }
extern "x86-interrupt" fn timer_interrupt_handler(
_stack_frame: InterruptStackFrame)
{
print!(".");
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Timer.as_u8());
}
}
extern "x86-interrupt" fn keyboard_interrupt_handler(
_stack_frame: InterruptStackFrame)
{
print!("k");
unsafe {
PICS.lock()
.notify_end_of_interrupt(InterruptIndex::Keyboard.as_u8());
}
}
pub fn init_idt() { pub fn init_idt() {
IDT.load(); IDT.load();
} }
@ -36,4 +61,30 @@ extern "x86-interrupt" fn breakpoint_handler(
stack_frame: InterruptStackFrame) stack_frame: InterruptStackFrame)
{ {
println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame); println!("EXCEPTION: BREAKPOINT\n{:#?}", stack_frame);
}
use pic8259::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) });
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum InterruptIndex {
Timer = PIC_1_OFFSET,
Keyboard,
}
impl InterruptIndex {
fn as_u8(self) -> u8 {
self as u8
}
fn as_usize(self) -> usize {
usize::from(self.as_u8())
}
} }

View File

@ -39,12 +39,14 @@ pub fn test_panic_handler(info: &PanicInfo) -> ! {
serial_println!("[failed]\n"); serial_println!("[failed]\n");
serial_println!("Error: {}\n", info); serial_println!("Error: {}\n", info);
exit_qemu(QemuExitCode::Failed); exit_qemu(QemuExitCode::Failed);
loop {} hlt_loop();
} }
pub fn init() { pub fn init() {
gdt::init(); gdt::init();
interrupts::init_idt(); interrupts::init_idt();
unsafe { interrupts::PICS.lock().initialize() };
x86_64::instructions::interrupts::enable();
} }
#[cfg(test)] #[cfg(test)]
@ -52,7 +54,7 @@ pub fn init() {
pub extern "C" fn _start() -> ! { pub extern "C" fn _start() -> ! {
init(); // new init(); // new
test_main(); test_main();
loop {} hlt_loop();
} }
#[cfg(test)] #[cfg(test)]
@ -75,4 +77,10 @@ pub fn exit_qemu(exit_code: QemuExitCode) {
let mut port = Port::new(0xf4); let mut port = Port::new(0xf4);
port.write(exit_code as u32); port.write(exit_code as u32);
} }
}
pub fn hlt_loop() -> ! {
loop {
x86_64::instructions::hlt();
}
} }

View File

@ -18,7 +18,7 @@ pub extern "C" fn _start() -> ! {
test_main(); test_main();
println!("It did not crash!"); println!("It did not crash!");
loop {} rust_os::hlt_loop();
} }
/// This function is called on panic. /// This function is called on panic.
@ -26,7 +26,7 @@ pub extern "C" fn _start() -> ! {
#[panic_handler] #[panic_handler]
fn panic(info: &PanicInfo) -> ! { fn panic(info: &PanicInfo) -> ! {
println!("{}", info); println!("{}", info);
loop {} rust_os::hlt_loop();
} }
#[cfg(test)] #[cfg(test)]

View File

@ -13,7 +13,14 @@ lazy_static! {
#[doc(hidden)] #[doc(hidden)]
pub fn _print(args: ::core::fmt::Arguments) { pub fn _print(args: ::core::fmt::Arguments) {
use core::fmt::Write; use core::fmt::Write;
SERIAL1.lock().write_fmt(args).expect("Printing to serial failed"); use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
SERIAL1
.lock()
.write_fmt(args)
.expect("Printing to serial failed");
});
} }
/// Prints to the host through the serial interface. /// Prints to the host through the serial interface.

View File

@ -142,7 +142,11 @@ macro_rules! println {
#[doc(hidden)] #[doc(hidden)]
pub fn _print(args: fmt::Arguments) { pub fn _print(args: fmt::Arguments) {
use core::fmt::Write; use core::fmt::Write;
WRITER.lock().write_fmt(args).unwrap(); use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
WRITER.lock().write_fmt(args).unwrap();
});
} }
#[test_case] #[test_case]
@ -159,10 +163,16 @@ fn test_println_many() {
#[test_case] #[test_case]
fn test_println_output() { fn test_println_output() {
use core::fmt::Write;
use x86_64::instructions::interrupts;
let s = "Some test string that fits on a single line"; let s = "Some test string that fits on a single line";
println!("{}", s); interrupts::without_interrupts(|| {
for (i, c) in s.chars().enumerate() { let mut writer = WRITER.lock();
let screen_char = WRITER.lock().buffer.chars[BUFFER_HEIGHT - 2][i].read(); writeln!(writer, "\n{}", s).expect("writeln failed");
assert_eq!(char::from(screen_char.ascii_character), c); for (i, c) in s.chars().enumerate() {
} let screen_char = writer.buffer.chars[BUFFER_HEIGHT - 2][i].read();
assert_eq!(char::from(screen_char.ascii_character), c);
}
});
} }