From c9a7d501b2e4cecf9635aa4a56a536ff058f8bf9 Mon Sep 17 00:00:00 2001 From: Ruihan Li Date: Fri, 18 Apr 2025 12:29:26 +0800 Subject: [PATCH] Rewrite `trap/idt.rs` --- ostd/src/arch/x86/trap/idt.rs | 87 +++++++++++++++++++++-------------- ostd/src/arch/x86/trap/mod.rs | 2 +- 2 files changed, 54 insertions(+), 35 deletions(-) diff --git a/ostd/src/arch/x86/trap/idt.rs b/ostd/src/arch/x86/trap/idt.rs index bb3a584d..ed367dc6 100644 --- a/ostd/src/arch/x86/trap/idt.rs +++ b/ostd/src/arch/x86/trap/idt.rs @@ -1,47 +1,66 @@ -// SPDX-License-Identifier: MPL-2.0 OR MIT -// -// The original source code is from [trapframe-rs](https://github.com/rcore-os/trapframe-rs), -// which is released under the following license: -// -// SPDX-License-Identifier: MIT -// -// Copyright (c) 2020 - 2024 Runji Wang -// -// We make the following new changes: -// * Include `trap.S` in this file and remove unused function `sidt`. -// * Link `VECTORS` to `trap_handler_table` defined in `trap.S`. -// -// These changes are released under the following license: -// // SPDX-License-Identifier: MPL-2.0 -//! Configure Interrupt Descriptor Table (GDT). +//! Configure the Interrupt Descriptor Table (IDT). use alloc::boxed::Box; use core::arch::global_asm; +use spin::Once; use x86_64::{ - structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable}, - PrivilegeLevel, + instructions::tables::lidt, + structures::{idt::Entry, DescriptorTablePointer}, + PrivilegeLevel, VirtAddr, }; global_asm!(include_str!("trap.S")); -pub fn init() { - extern "C" { - #[link_name = "trap_handler_table"] - static VECTORS: [HandlerFunc; 256]; - } +const NUM_INTERRUPTS: usize = 256; - let idt = Box::leak(Box::new(InterruptDescriptorTable::new())); - let entries: &'static mut [Entry; 256] = - unsafe { core::mem::transmute_copy(&idt) }; - for i in 0..256 { - let opt = unsafe { entries[i].set_handler_fn(VECTORS[i]) }; - // Enable user space `int3` and `into`. - if i == 3 || i == 4 { - opt.set_privilege_level(PrivilegeLevel::Ring3); - } - } - idt.load(); +extern "C" { + #[link_name = "trap_handler_table"] + static VECTORS: [usize; NUM_INTERRUPTS]; +} + +static GLOBAL_IDT: Once<&'static [Entry<()>]> = Once::new(); + +/// Initializes and loads the IDT. +/// +/// The caller should only call this method once in the boot context for each available processor. +/// This is not a safety requirement, however, because calling this method again will do nothing +/// more than load the same IDT. +pub(super) fn init() { + let idt = *GLOBAL_IDT.call_once(|| { + let idt = Box::leak(Box::new([const { Entry::missing() }; NUM_INTERRUPTS])); + + // SAFETY: The vector array is properly initialized, lives for `'static`, and will never be + // mutated. So it's always fine to create an immutable borrow to it. + let vectors = unsafe { &VECTORS }; + + // Initialize the IDT entries. + for (intr_no, &handler) in vectors.iter().enumerate() { + let handler = VirtAddr::new(handler as u64); + + let entry = &mut idt[intr_no]; + // SAFETY: The handler defined in `trap.S` has a correct signature to handle the + // corresponding exception or interrupt. + let opt = unsafe { entry.set_handler_addr(handler) }; + + // Enable `int3` and `into` in the userspace. + if intr_no == 3 || intr_no == 4 { + opt.set_privilege_level(PrivilegeLevel::Ring3); + } + } + + idt + }); + + let idtr = DescriptorTablePointer { + limit: (core::mem::size_of_val(idt) - 1) as u16, + base: VirtAddr::new(idt.as_ptr().addr() as u64), + }; + // SAFETY: The IDT is valid to load because: + // - It lives for `'static`. + // - It contains correct entries at correct indexes: all handlers are defined in `trap.S` with + // correct handler signatures. + unsafe { lidt(&idtr) }; } diff --git a/ostd/src/arch/x86/trap/mod.rs b/ostd/src/arch/x86/trap/mod.rs index 8031ab90..37cfce98 100644 --- a/ostd/src/arch/x86/trap/mod.rs +++ b/ostd/src/arch/x86/trap/mod.rs @@ -107,7 +107,7 @@ pub struct TrapFrame { /// This function will: /// - Switch to a new, CPU-local [GDT]. /// - Switch to a new, CPU-local [TSS]. -/// - Switch to a new, CPU-local [IDT]. +/// - Switch to a new, global [IDT]. /// - Enable the [`syscall`] instruction. /// /// [GDT]: https://wiki.osdev.org/GDT