From 496ccaaf750a4ec1c537c463eff56108e1cc0bb4 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Sun, 18 Apr 2021 19:01:54 +0200 Subject: Further cleanup * Bump x86_64 dep to version 0.1.14 * Rewrite LOCAL_APIC handling * Remove warnings --- kernel/Cargo.toml | 2 +- kernel/src/interrupts/apic.rs | 67 +++++++++++++++++++++-------- kernel/src/interrupts/exception_handlers.rs | 17 +++++--- kernel/src/interrupts/gdt.rs | 6 +-- kernel/src/interrupts/idt.rs | 2 +- kernel/src/interrupts/interrupt_handlers.rs | 8 ++-- kernel/src/io/panic_screen.rs | 3 +- kernel/src/io/serial.rs | 1 + kernel/src/io/vga_text.rs | 13 +++--- kernel/src/lib.rs | 14 ++++++ kernel/src/main.rs | 12 ++++-- kernel/src/testing/panic.rs | 1 + kernel/tests/boot.rs | 4 ++ kernel/tests/int3.rs | 8 +++- kernel/tests/stack_overflow.rs | 4 +- 15 files changed, 114 insertions(+), 48 deletions(-) diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index bce79cb..25bce57 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -17,7 +17,7 @@ harness = false testing_qemu = [] [dependencies] -x86_64 = "0.13" +x86_64 = "0.14" uart_16550 = "0.2.1" spin = "0.5" diff --git a/kernel/src/interrupts/apic.rs b/kernel/src/interrupts/apic.rs index 0e89943..836af20 100644 --- a/kernel/src/interrupts/apic.rs +++ b/kernel/src/interrupts/apic.rs @@ -1,8 +1,11 @@ +use core::sync::atomic::{AtomicU64, Ordering}; use x86_64::registers::model_specific::Msr; #[cfg(target_arch = "x86_64")] const APIC_FLAG: u64 = 0x0800; const APIC_BASE_MSR: u32 = 0x001b; +const CPU_COUNT: usize = 255; +const APIC_BASE_ADDR: u64 = 0xfee0_0000; // APIC constant register values const APIC_DISABLE: u32 = 0x0001_0000; @@ -20,8 +23,13 @@ pub fn is_apic() -> bool { info & (1 << 9) != 0 } -pub fn set_apic_base(v: u64) { - unsafe { Msr::new(APIC_BASE_MSR).write(v) } +pub fn cpu_id() -> u32 { + let mut info: u32; + unsafe { asm!("cpuid", inout("eax") 1 => _, out("ebx") info) } + if !is_x2apic() { + info >>= 24; + } + info } #[repr(C)] @@ -75,27 +83,48 @@ pub enum TimerDivideConfig { Div128 = 10, NoDivide = 11, } +const NONE_APIC: Option = None; -static mut LOCAL_APIC: Option = None; +static mut APIC_INIT: [Option; CPU_COUNT] = [NONE_APIC; CPU_COUNT]; -pub unsafe fn set_local_apic(apic: Apic) -> &'static mut Apic { - LOCAL_APIC = Some(apic); - LOCAL_APIC.as_mut().unwrap() +pub fn move_local_apic(v: u64) -> bool { + match get_local_apic() { + None => return false, + Some(apic) => apic.regs.store(v, Ordering::Release), + } + unsafe { Msr::new(APIC_BASE_MSR).write(v) }; + true } -pub unsafe fn get_local_apic() -> Option<&'static mut Apic> { - LOCAL_APIC.as_mut() +/// Tries to initialize the local apic at it's default location. +/// returns false if no apic is available +/// +/// # Safety +/// Calling this function in a running system might cause the loss of interrupts or other weird +/// behaviour +pub unsafe fn try_initialize_local_apic() -> &'static mut Option { + if is_apic() { + let cpu_id = cpu_id() as usize; + if APIC_INIT[cpu_id].is_none() { + APIC_INIT[cpu_id] = Some(Apic::from_base_apic(APIC_BASE_ADDR)); + Apic::disable_pic(); + } + APIC_INIT[cpu_id].as_mut().map(|x| x.initialize()); + } + get_local_apic() +} + +pub fn get_local_apic() -> &'static mut Option { + let cpu_id = cpu_id() as usize; + unsafe { &mut APIC_INIT[cpu_id] } } pub struct Apic { - regs: *mut [u32; 1024], + regs: AtomicU64, } impl Apic { - pub fn new() -> Option { - if !is_apic() { - return None; - } + fn initialize(&mut self) -> Self { Self::disable_pic(); let base_apic = unsafe { Msr::new(APIC_BASE_MSR).read() }; let mut apic = Self::from_base_apic(base_apic); @@ -118,28 +147,28 @@ impl Apic { apic.set(ApicRegister::SpuriousInterruptVec, 0x1ff); - Some(apic) + apic } - pub fn disable_pic() { + fn disable_pic() { unsafe { x86_64::instructions::port::PortWriteOnly::new(0xa1).write(0xffu8); x86_64::instructions::port::PortWriteOnly::new(0x21).write(0xffu8); } } - fn from_base_apic(base_apic: u64) -> Self { + const fn from_base_apic(base_apic: u64) -> Self { Self { - regs: ((base_apic) & 0xfffffffff << 12) as *mut [u32; 1024], + regs: AtomicU64::new((base_apic) & 0xfffffffff << 12), } } pub fn ptr(&self) -> *const u32 { - self.regs as *const u32 + self.regs.load(Ordering::Acquire) as *const u32 } fn ptr_mut(&mut self) -> *mut u32 { - self.regs as *mut u32 + self.regs.load(Ordering::SeqCst) as *mut u32 } pub fn get(&self, register: ApicRegister) -> u32 { diff --git a/kernel/src/interrupts/exception_handlers.rs b/kernel/src/interrupts/exception_handlers.rs index ce8f6c0..db081a7 100644 --- a/kernel/src/interrupts/exception_handlers.rs +++ b/kernel/src/interrupts/exception_handlers.rs @@ -15,6 +15,11 @@ macro_rules! exception_default { static mut EXPECTED_FAULT: InterruptType = InterruptType::None; +/// Set an exception that causes the kernel to exit with status success +/// This is used for testing +/// +/// # Safety +/// This function may only be called before executing any kernel code pub unsafe fn expect_fault(int: InterruptType) { if EXPECTED_FAULT == InterruptType::None { EXPECTED_FAULT = int; @@ -25,7 +30,7 @@ fn get_expected_fault() -> InterruptType { unsafe { EXPECTED_FAULT } } -pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStackFrame) { +pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: InterruptStackFrame) { match get_expected_fault() { InterruptType::Breakpoint => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( @@ -35,7 +40,7 @@ pub extern "x86-interrupt" fn breakpoint_handler(stack_frame: &mut InterruptStac } } -pub extern "x86-interrupt" fn div_zero_handler(stack_frame: &mut InterruptStackFrame) { +pub extern "x86-interrupt" fn div_zero_handler(stack_frame: InterruptStackFrame) { match get_expected_fault() { InterruptType::DivZero => qemu::exit_qemu(qemu::QemuExitCode::Success), _ => panic!( @@ -46,7 +51,7 @@ pub extern "x86-interrupt" fn div_zero_handler(stack_frame: &mut InterruptStackF } pub extern "x86-interrupt" fn general_protection_fault_handler( - stack_frame: &mut InterruptStackFrame, + stack_frame: InterruptStackFrame, error_code: u64, ) { match get_expected_fault() { @@ -60,7 +65,7 @@ pub extern "x86-interrupt" fn general_protection_fault_handler( } pub extern "x86-interrupt" fn page_fault_handler( - stack_frame: &mut InterruptStackFrame, + stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode, ) { use x86_64::registers::control::Cr2; @@ -78,7 +83,7 @@ pub extern "x86-interrupt" fn page_fault_handler( } pub extern "x86-interrupt" fn segment_not_present_handler( - stack_frame: &mut InterruptStackFrame, + stack_frame: InterruptStackFrame, error_code: u64, ) { match get_expected_fault() { @@ -92,7 +97,7 @@ pub extern "x86-interrupt" fn segment_not_present_handler( } pub extern "x86-interrupt" fn double_fault_handler( - stack_frame: &mut InterruptStackFrame, + stack_frame: InterruptStackFrame, _error_code: u64, // code is always zero ) -> ! { match get_expected_fault() { diff --git a/kernel/src/interrupts/gdt.rs b/kernel/src/interrupts/gdt.rs index d75ff68..c20eabe 100644 --- a/kernel/src/interrupts/gdt.rs +++ b/kernel/src/interrupts/gdt.rs @@ -14,16 +14,14 @@ lazy_static! { static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end + stack_start + STACK_SIZE }; tss.interrupt_stack_table[PAGE_FAULT_IST_INDEX as usize] = { const STACK_SIZE: usize = 4096 * 8; static mut STACK: [u8; STACK_SIZE] = [0; STACK_SIZE]; let stack_start = VirtAddr::from_ptr(unsafe { &STACK }); - let stack_end = stack_start + STACK_SIZE; - stack_end + stack_start + STACK_SIZE }; tss }; diff --git a/kernel/src/interrupts/idt.rs b/kernel/src/interrupts/idt.rs index 4e5dd77..6bc8149 100644 --- a/kernel/src/interrupts/idt.rs +++ b/kernel/src/interrupts/idt.rs @@ -34,7 +34,7 @@ lazy_static! { } pub extern "x86-interrupt" fn dummy_handler( - _stack_frame: &mut x86_64::structures::idt::InterruptStackFrame, + _stack_frame: x86_64::structures::idt::InterruptStackFrame, ) { panic!("unhandled interrupt recieved"); } diff --git a/kernel/src/interrupts/interrupt_handlers.rs b/kernel/src/interrupts/interrupt_handlers.rs index 831211b..8b3a7eb 100644 --- a/kernel/src/interrupts/interrupt_handlers.rs +++ b/kernel/src/interrupts/interrupt_handlers.rs @@ -2,18 +2,18 @@ use core::fmt::Write; use x86_64::structures::idt::InterruptStackFrame; use x86_64::structures::port; -pub extern "x86-interrupt" fn timer_handler(_stack_frame: &mut InterruptStackFrame) { +pub extern "x86-interrupt" fn timer_handler(_stack_frame: InterruptStackFrame) { crate::io::vga_text::OStream::new().print(b"Timer"); - if let Some(apic) = unsafe { super::apic::get_local_apic() } { + if let Some(apic) = super::apic::get_local_apic() { apic.end_of_interrupt() } } -pub extern "x86-interrupt" fn keyboard_handler(_stack_frame: &mut InterruptStackFrame) { +pub extern "x86-interrupt" fn keyboard_handler(_stack_frame: InterruptStackFrame) { let code: u8 = unsafe { port::PortRead::read_from_port(0x60) }; let _ = write!(crate::io::vga_text::OStream::new(), "{}", code); - if let Some(apic) = unsafe { super::apic::get_local_apic() } { + if let Some(apic) = super::apic::get_local_apic() { apic.end_of_interrupt() } } diff --git a/kernel/src/io/panic_screen.rs b/kernel/src/io/panic_screen.rs index 7b81676..35fe625 100644 --- a/kernel/src/io/panic_screen.rs +++ b/kernel/src/io/panic_screen.rs @@ -23,7 +23,8 @@ impl<'a> core::fmt::Write for TextBuffer<'a> { } else { let s = s.as_bytes(); (&mut self.dst[self.len..self.len + s.len()]).clone_from_slice(s); - Ok(self.len += s.len()) + self.len += s.len(); + Ok(()) } } } diff --git a/kernel/src/io/serial.rs b/kernel/src/io/serial.rs index 3f661e9..56bfbb3 100644 --- a/kernel/src/io/serial.rs +++ b/kernel/src/io/serial.rs @@ -12,6 +12,7 @@ lazy_static! { }; } +#[derive(Default)] pub struct SerialStream {} impl SerialStream { diff --git a/kernel/src/io/vga_text.rs b/kernel/src/io/vga_text.rs index 72c4d85..f9c15ad 100644 --- a/kernel/src/io/vga_text.rs +++ b/kernel/src/io/vga_text.rs @@ -27,12 +27,12 @@ pub const HEIGHT: usize = 25; pub struct CharState(pub u8); impl CharState { - pub fn from_colors(fg: Color, bg: Color) -> Self { + pub const fn from_colors(fg: Color, bg: Color) -> Self { Self((fg as u8) | ((bg as u8) << 4)) } pub fn set_fg(&mut self, fg: Color) { - self.0 = (self.0 & (HEIGHT as u8) - 10) | (fg as u8) + self.0 = (self.0 & ((HEIGHT as u8) - 10)) | (fg as u8) } pub fn set_bg(&mut self, bg: Color) { @@ -49,7 +49,7 @@ pub struct VgaChar { impl VgaChar { pub fn from_state_and_byte(state: CharState, byte: u8) -> Self { - Self { state, byte } + Self { byte, state } } } @@ -61,7 +61,7 @@ pub struct OStream { } impl OStream { - pub fn new() -> Self { + pub const fn new() -> Self { Self { pos: (0, 0), cursor: Self::at(0), @@ -70,7 +70,7 @@ impl OStream { } } - fn at(n: usize) -> *mut VgaChar { + const fn at(n: usize) -> *mut VgaChar { (0xb8000 + (n << 1)) as *mut VgaChar } @@ -172,6 +172,7 @@ impl OStream { impl core::fmt::Write for OStream { fn write_str(&mut self, s: &str) -> core::fmt::Result { - Ok(self.print(s.as_bytes())) + self.print(s.as_bytes()); + Ok(()) } } diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index f03ef36..a8be053 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -1,3 +1,4 @@ +#![allow(unused_attributes)] #![no_main] #![feature(custom_test_frameworks)] #![feature(abi_x86_interrupt)] @@ -21,6 +22,7 @@ pub use qemu::*; pub extern "C" fn _start() -> ! { init(); test_main(); + #[allow(clippy::empty_loop)] loop {} } @@ -33,4 +35,16 @@ fn panic(info: &core::panic::PanicInfo) -> ! { pub fn init() { interrupts::gdt::init(); interrupts::idt::init(); + let apic = unsafe { + interrupts::apic::try_initialize_local_apic() + .as_mut() + .expect("no APIC support") + }; + + apic.set_timer_interrupt_handler( + interrupts::apic::TimerDivideConfig::Div16, + interrupts::InterruptType::Timer, + ); + + x86_64::instructions::interrupts::enable(); } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 50b281f..017f4b9 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -19,8 +19,12 @@ extern "C" fn _start() -> ! { interrupts::gdt::init(); interrupts::idt::init(); - let apic = interrupts::apic::Apic::new().expect("no APIC support"); - let apic = unsafe { interrupts::apic::set_local_apic(apic) }; + loop {} + let apic = unsafe { + interrupts::apic::try_initialize_local_apic() + .as_mut() + .expect("no APIC support") + }; apic.set_timer_interrupt_handler( interrupts::apic::TimerDivideConfig::Div16, @@ -31,11 +35,13 @@ extern "C" fn _start() -> ! { let mut stdout = OStream::new(); stdout.print(b"apic initialisation complete\n"); - x86_64::instructions::interrupts::int3(); + //x86_64::instructions::interrupts::int3(); + stdout.print(b"foolete\n"); if cfg!(test) { qemu::exit_qemu(qemu::QemuExitCode::Success); } + #[allow(clippy::empty_loop)] loop {} } diff --git a/kernel/src/testing/panic.rs b/kernel/src/testing/panic.rs index 11469f2..7dad694 100644 --- a/kernel/src/testing/panic.rs +++ b/kernel/src/testing/panic.rs @@ -33,5 +33,6 @@ pub fn should_panic(_info: &PanicInfo) -> ! { pub fn panic(info: &PanicInfo) -> ! { interrupts::disable(); crate::io::panic_screen::show(info.message()); + #[allow(clippy::empty_loop)] loop {} } diff --git a/kernel/tests/boot.rs b/kernel/tests/boot.rs index 3a65ff6..c6c0de0 100644 --- a/kernel/tests/boot.rs +++ b/kernel/tests/boot.rs @@ -4,6 +4,7 @@ #![feature(panic_info_message)] #![test_runner(kernel::testing::serial_test_runner)] #![reexport_test_harness_main = "test_main"] +#![allow(unreachable_code)] #![no_std] use kernel; @@ -14,6 +15,7 @@ extern "C" fn _start() -> ! { kernel::init(); test_main(); + #[allow(clippy::empty_loop)] loop {} } @@ -25,6 +27,7 @@ fn boot() { #[test_case] fn poweroff() { qemu::exit_qemu(qemu::QemuExitCode::Success); + loop {} panic!("Qemu did not exit"); } @@ -33,5 +36,6 @@ fn poweroff() { #[no_mangle] extern "C" fn panic_handler(info: &core::panic::PanicInfo) -> ! { kernel::testing::serial_panic(info); + #[allow(clippy::empty_loop)] loop {} } diff --git a/kernel/tests/int3.rs b/kernel/tests/int3.rs index faa5b3d..ac0e5f0 100644 --- a/kernel/tests/int3.rs +++ b/kernel/tests/int3.rs @@ -1,12 +1,15 @@ #![no_main] #![feature(abi_x86_interrupt)] #![feature(panic_info_message)] +#![allow(unreachable_code)] +#![feature(custom_test_frameworks)] +#![test_runner(kernel::testing::serial_test_runner)] #![no_std] use kernel; use kernel::interrupts; use kernel::interrupts::exception_handlers; -use kernel::io::qemu; +use kernel::qemu; #[no_mangle] extern "C" fn _start() -> ! { @@ -15,6 +18,7 @@ extern "C" fn _start() -> ! { exception_handlers::expect_fault(interrupts::InterruptType::Breakpoint); } x86_64::instructions::interrupts::int3(); + panic!("BREAKPOINT not caught"); loop {} @@ -24,6 +28,6 @@ extern "C" fn _start() -> ! { #[panic_handler] #[no_mangle] extern "C" fn panic_handler(info: &core::panic::PanicInfo) -> ! { - kernel::testing::serial_should_panic(info); + kernel::testing::serial_panic(info); loop {} } diff --git a/kernel/tests/stack_overflow.rs b/kernel/tests/stack_overflow.rs index fc93376..9c4db19 100644 --- a/kernel/tests/stack_overflow.rs +++ b/kernel/tests/stack_overflow.rs @@ -2,12 +2,13 @@ #![feature(abi_x86_interrupt)] #![feature(panic_info_message)] #![no_std] +#![allow(unreachable_code)] use core::fmt::Write; use kernel; use kernel::interrupts; use kernel::interrupts::exception_handlers; -use kernel::io::qemu; +use kernel::qemu; #[no_mangle] extern "C" fn _start() -> ! { @@ -15,6 +16,7 @@ extern "C" fn _start() -> ! { unsafe { exception_handlers::expect_fault(interrupts::InterruptType::PageFault); } + qemu::exit_qemu(qemu::QemuExitCode::Success); _loop(0); panic!("PAGE_FAULT not caught"); loop {} -- cgit v1.2.3