summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDennis Kobert <dennis@kobert.dev>2021-04-18 19:01:54 +0200
committerDennis Kobert <dennis@kobert.dev>2021-04-18 19:01:54 +0200
commit496ccaaf750a4ec1c537c463eff56108e1cc0bb4 (patch)
treef0ccffc3fd823cc4016c29d45408c033c973e5d5
parent8b810a009f8d29ba61a3c377fdeac06a3bbb151d (diff)
Further cleanupfurther-cleanup
* Bump x86_64 dep to version 0.1.14 * Rewrite LOCAL_APIC handling * Remove warnings
-rw-r--r--kernel/Cargo.toml2
-rw-r--r--kernel/src/interrupts/apic.rs67
-rw-r--r--kernel/src/interrupts/exception_handlers.rs17
-rw-r--r--kernel/src/interrupts/gdt.rs6
-rw-r--r--kernel/src/interrupts/idt.rs2
-rw-r--r--kernel/src/interrupts/interrupt_handlers.rs8
-rw-r--r--kernel/src/io/panic_screen.rs3
-rw-r--r--kernel/src/io/serial.rs1
-rw-r--r--kernel/src/io/vga_text.rs13
-rw-r--r--kernel/src/lib.rs14
-rw-r--r--kernel/src/main.rs12
-rw-r--r--kernel/src/testing/panic.rs1
-rw-r--r--kernel/tests/boot.rs4
-rw-r--r--kernel/tests/int3.rs8
-rw-r--r--kernel/tests/stack_overflow.rs4
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<Apic> = None;
-static mut LOCAL_APIC: Option<Apic> = None;
+static mut APIC_INIT: [Option<Apic>; 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<Apic> {
+ 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<Apic> {
+ 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<Self> {
- 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 {}