Rewrite trap/idt.rs

This commit is contained in:
Ruihan Li 2025-04-18 12:29:26 +08:00 committed by Tate, Hongliang Tian
parent 8c30b4b942
commit c9a7d501b2
2 changed files with 54 additions and 35 deletions

View File

@ -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 // SPDX-License-Identifier: MPL-2.0
//! Configure Interrupt Descriptor Table (GDT). //! Configure the Interrupt Descriptor Table (IDT).
use alloc::boxed::Box; use alloc::boxed::Box;
use core::arch::global_asm; use core::arch::global_asm;
use spin::Once;
use x86_64::{ use x86_64::{
structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable}, instructions::tables::lidt,
PrivilegeLevel, structures::{idt::Entry, DescriptorTablePointer},
PrivilegeLevel, VirtAddr,
}; };
global_asm!(include_str!("trap.S")); global_asm!(include_str!("trap.S"));
pub fn init() { const NUM_INTERRUPTS: usize = 256;
extern "C" {
#[link_name = "trap_handler_table"]
static VECTORS: [HandlerFunc; 256];
}
let idt = Box::leak(Box::new(InterruptDescriptorTable::new())); extern "C" {
let entries: &'static mut [Entry<HandlerFunc>; 256] = #[link_name = "trap_handler_table"]
unsafe { core::mem::transmute_copy(&idt) }; static VECTORS: [usize; NUM_INTERRUPTS];
for i in 0..256 { }
let opt = unsafe { entries[i].set_handler_fn(VECTORS[i]) };
// Enable user space `int3` and `into`. static GLOBAL_IDT: Once<&'static [Entry<()>]> = Once::new();
if i == 3 || i == 4 {
/// 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); opt.set_privilege_level(PrivilegeLevel::Ring3);
} }
} }
idt.load();
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) };
} }

View File

@ -107,7 +107,7 @@ pub struct TrapFrame {
/// This function will: /// This function will:
/// - Switch to a new, CPU-local [GDT]. /// - Switch to a new, CPU-local [GDT].
/// - Switch to a new, CPU-local [TSS]. /// - Switch to a new, CPU-local [TSS].
/// - Switch to a new, CPU-local [IDT]. /// - Switch to a new, global [IDT].
/// - Enable the [`syscall`] instruction. /// - Enable the [`syscall`] instruction.
/// ///
/// [GDT]: https://wiki.osdev.org/GDT /// [GDT]: https://wiki.osdev.org/GDT