diff --git a/Cargo.lock b/Cargo.lock index 36eb00da..0486f5cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -852,7 +852,7 @@ dependencies = [ "uart_16550", "uefi", "uefi-services", - "x86_64 0.14.11", + "x86_64", "xmas-elf 0.8.0", ] @@ -1090,11 +1090,10 @@ dependencies = [ "spin 0.9.8", "static_assertions", "tdx-guest", - "trapframe", "unwinding", "volatile", "x86", - "x86_64 0.14.11", + "x86_64", "xarray", ] @@ -1267,15 +1266,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "raw-cpuid" -version = "11.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e29830cbb1290e404f24c73af91c5d8d631ce7e128691e9477556b540cd01ecd" -dependencies = [ - "bitflags 2.6.0", -] - [[package]] name = "rle-decode-fast" version = "1.0.3" @@ -1437,8 +1427,8 @@ dependencies = [ "bitflags 1.3.2", "iced-x86", "lazy_static", - "raw-cpuid 10.7.0", - "x86_64 0.14.11", + "raw-cpuid", + "x86_64", ] [[package]] @@ -1512,16 +1502,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "trapframe" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "105000258ba41c463b63403c9341c55a298f35f6137b1cca08c10f0409ef8d3a" -dependencies = [ - "raw-cpuid 11.0.2", - "x86_64 0.15.1", -] - [[package]] name = "typeflags" version = "0.1.0" @@ -1714,7 +1694,7 @@ checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" dependencies = [ "bit_field", "bitflags 1.3.2", - "raw-cpuid 10.7.0", + "raw-cpuid", ] [[package]] @@ -1729,18 +1709,6 @@ dependencies = [ "volatile", ] -[[package]] -name = "x86_64" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc79523af8abf92fb1a970c3e086c5a343f6bcc1a0eb890f575cbb3b45743df" -dependencies = [ - "bit_field", - "bitflags 2.6.0", - "rustversion", - "volatile", -] - [[package]] name = "xarray" version = "0.1.0" diff --git a/kernel/src/syscall/arch_prctl.rs b/kernel/src/syscall/arch_prctl.rs index fbd84bfb..72d1d387 100644 --- a/kernel/src/syscall/arch_prctl.rs +++ b/kernel/src/syscall/arch_prctl.rs @@ -3,7 +3,7 @@ use ostd::cpu::UserContext; use super::SyscallReturn; -use crate::{cpu::LinuxAbi, prelude::*}; +use crate::prelude::*; #[allow(non_camel_case_types)] #[repr(u64)] @@ -18,7 +18,7 @@ pub enum ArchPrctlCode { pub fn sys_arch_prctl( code: u64, addr: u64, - _ctx: &Context, + ctx: &Context, user_ctx: &mut UserContext, ) -> Result { let arch_prctl_code = ArchPrctlCode::try_from(code)?; @@ -26,17 +26,24 @@ pub fn sys_arch_prctl( "arch_prctl_code: {:?}, addr = 0x{:x}", arch_prctl_code, addr ); - let res = do_arch_prctl(arch_prctl_code, addr, user_ctx).unwrap(); + let res = do_arch_prctl(arch_prctl_code, addr, ctx, user_ctx).unwrap(); Ok(SyscallReturn::Return(res as _)) } -pub fn do_arch_prctl(code: ArchPrctlCode, addr: u64, ctx: &mut UserContext) -> Result { +pub fn do_arch_prctl( + code: ArchPrctlCode, + addr: u64, + ctx: &Context, + user_ctx: &mut UserContext, +) -> Result { match code { ArchPrctlCode::ARCH_SET_FS => { - ctx.set_tls_pointer(addr as usize); + ctx.task.set_tls_pointer(addr as usize); + user_ctx.set_tls_pointer(addr as usize); + user_ctx.activate_tls_pointer(); Ok(0) } - ArchPrctlCode::ARCH_GET_FS => Ok(ctx.tls_pointer() as u64), + ArchPrctlCode::ARCH_GET_FS => Ok(user_ctx.tls_pointer() as u64), ArchPrctlCode::ARCH_GET_GS | ArchPrctlCode::ARCH_SET_GS => { return_errno_with_message!(Errno::EINVAL, "GS cannot be accessed from the user space") } diff --git a/kernel/src/syscall/execve.rs b/kernel/src/syscall/execve.rs index dc4566c3..19926e81 100644 --- a/kernel/src/syscall/execve.rs +++ b/kernel/src/syscall/execve.rs @@ -5,7 +5,6 @@ use ostd::{cpu::UserContext, user::UserContextApi}; use super::{constants::*, SyscallReturn}; use crate::{ - cpu::LinuxAbi, fs::{ file_table::FileDesc, fs_resolver::{FsPath, AT_FDCWD}, diff --git a/osdk/src/base_crate/x86_64.ld.template b/osdk/src/base_crate/x86_64.ld.template index 59775408..07b4bd5d 100644 --- a/osdk/src/base_crate/x86_64.ld.template +++ b/osdk/src/base_crate/x86_64.ld.template @@ -117,11 +117,17 @@ SECTIONS # processor, while it would be copied to other dynamically allocated memory # areas for the application processors. . = ALIGN(4096); - .cpu_local : AT(ADDR(.cpu_local) - KERNEL_VMA) { - __cpu_local_start = .; - KEEP(*(SORT(.cpu_local))) - __cpu_local_end = .; + __cpu_local_start = .; + # Make sure that cpu_local_tss is right at the beginning of CPU local area, + # which stores the task state segment in x86_64 architecture, so that + # when trap from ring3 to ring0, CPU can switch stack correctly. + .cpu_local_tss : AT(ADDR(.cpu_local_tss) - KERNEL_VMA) { + *(.cpu_local_tss) } + .cpu_local : AT(ADDR(.cpu_local) - KERNEL_VMA) { + KEEP(*(SORT(.cpu_local))) + } + __cpu_local_end = .; .bss : AT(ADDR(.bss) - KERNEL_VMA) { __bss = .; diff --git a/ostd/Cargo.toml b/ostd/Cargo.toml index cafe33c8..135eeba9 100644 --- a/ostd/Cargo.toml +++ b/ostd/Cargo.toml @@ -39,7 +39,6 @@ owo-colors = { version = "3", optional = true } ostd-pod = { git = "https://github.com/asterinas/ostd-pod", rev = "c4644be", version = "0.1.1" } spin = "0.9.4" static_assertions = "1.1.0" -trapframe = "0.10.0" unwinding = { version = "0.2.2", default-features = false, features = ["fde-gnu-eh-frame-hdr", "hide-trace", "panic", "personality", "unwinder"] } volatile = { version = "0.4.5", features = ["unstable"] } xarray = { git = "https://github.com/asterinas/xarray", version = "0.1.0" } diff --git a/ostd/src/arch/x86/cpu/local.rs b/ostd/src/arch/x86/cpu/local.rs index b5a64732..209deee9 100644 --- a/ostd/src/arch/x86/cpu/local.rs +++ b/ostd/src/arch/x86/cpu/local.rs @@ -2,25 +2,25 @@ //! Architecture dependent CPU-local information utilities. -use x86_64::registers::segmentation::{Segment64, FS}; +use x86_64::registers::segmentation::{Segment64, GS}; -/// Sets the base address for the CPU local storage by writing to the FS base model-specific register. +/// Sets the base address for the CPU local storage by writing to the GS base model-specific register. /// This operation is marked as `unsafe` because it directly interfaces with low-level CPU registers. /// /// # Safety /// -/// - This function is safe to call provided that the FS register is dedicated entirely for CPU local storage +/// - This function is safe to call provided that the GS register is dedicated entirely for CPU local storage /// and is not concurrently accessed for other purposes. /// - The caller must ensure that `addr` is a valid address and properly aligned, as required by the CPU. /// - This function should only be called in contexts where the CPU is in a state to accept such changes, /// such as during processor initialization. pub(crate) unsafe fn set_base(addr: u64) { - FS::write_base(x86_64::addr::VirtAddr::new(addr)); + GS::write_base(x86_64::addr::VirtAddr::new(addr)); } -/// Gets the base address for the CPU local storage by reading the FS base model-specific register. +/// Gets the base address for the CPU local storage by reading the GS base model-specific register. pub(crate) fn get_base() -> u64 { - FS::read_base().as_u64() + GS::read_base().as_u64() } use crate::cpu::local::single_instr::{ @@ -29,7 +29,7 @@ use crate::cpu::local::single_instr::{ SingleInstructionSubAssign, }; -/// The GDT ensures that the FS segment is initialized to zero on boot. +/// The GDT ensures that the GS segment is initialized to zero on boot. /// This assertion checks that the base address has been set. macro_rules! debug_assert_initialized { () => { @@ -49,7 +49,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("add fs:[{0}], {1", $register_format, "}"), + concat!("add gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -62,7 +62,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("sub fs:[{0}], {1", $register_format, "}"), + concat!("sub gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -75,7 +75,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("and fs:[{0}], {1", $register_format, "}"), + concat!("and gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -88,7 +88,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("or fs:[{0}], {1", $register_format, "}"), + concat!("or gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -101,7 +101,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("xor fs:[{0}], {1", $register_format, "}"), + concat!("xor gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -115,7 +115,7 @@ macro_rules! impl_numeric_single_instruction_for { let val: Self; core::arch::asm!( - concat!("mov {0", $register_format, "}, fs:[{1}]"), + concat!("mov {0", $register_format, "}, gs:[{1}]"), out($inout_type) val, in(reg) offset, options(nostack, readonly), @@ -129,7 +129,7 @@ macro_rules! impl_numeric_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("mov fs:[{0}], {1", $register_format, "}"), + concat!("mov gs:[{0}], {1", $register_format, "}"), in(reg) offset, in($inout_type) val, options(nostack), @@ -162,7 +162,7 @@ macro_rules! impl_generic_single_instruction_for { let val: Self; core::arch::asm!( - concat!("mov {0}, fs:[{1}]"), + concat!("mov {0}, gs:[{1}]"), out(reg) val, in(reg) offset, options(nostack, readonly), @@ -176,7 +176,7 @@ macro_rules! impl_generic_single_instruction_for { debug_assert_initialized!(); core::arch::asm!( - concat!("mov fs:[{0}], {1}"), + concat!("mov gs:[{0}], {1}"), in(reg) offset, in(reg) val, options(nostack), @@ -202,7 +202,7 @@ impl SingleInstructionLoad for bool { let val: u8; core::arch::asm!( - "mov {0}, fs:[{1}]", + "mov {0}, gs:[{1}]", out(reg_byte) val, in(reg) offset, options(nostack, readonly), @@ -218,7 +218,7 @@ impl SingleInstructionStore for bool { let val: u8 = if val { 1 } else { 0 }; core::arch::asm!( - "mov fs:[{0}], {1}", + "mov gs:[{0}], {1}", in(reg) offset, in(reg_byte) val, options(nostack), diff --git a/ostd/src/arch/x86/cpu/mod.rs b/ostd/src/arch/x86/cpu/mod.rs index 15042f97..1c2411a9 100644 --- a/ostd/src/arch/x86/cpu/mod.rs +++ b/ostd/src/arch/x86/cpu/mod.rs @@ -12,10 +12,11 @@ use core::{ use bitflags::bitflags; use cfg_if::cfg_if; use log::debug; -pub use trapframe::GeneralRegs as RawGeneralRegs; -use trapframe::UserContext as RawUserContext; +use x86::bits64::segmentation::wrfsbase; use x86_64::registers::rflags::RFlags; +pub use super::trap::GeneralRegs as RawGeneralRegs; +use super::trap::{TrapFrame, UserContext as RawUserContext}; use crate::{ task::scheduler, trap::call_irq_callback_functions, @@ -76,6 +77,27 @@ impl UserContext { pub fn fp_regs_mut(&mut self) -> &mut FpRegs { &mut self.fp_regs } + + /// Sets thread-local storage pointer. + pub fn set_tls_pointer(&mut self, tls: usize) { + self.set_fsbase(tls) + } + + /// Gets thread-local storage pointer. + pub fn tls_pointer(&self) -> usize { + self.fsbase() + } + + /// Activates thread-local storage pointer on the current CPU. + /// + /// # Safety + /// + /// The method by itself is safe because the value of the TLS register won't affect kernel code. + /// But if the user relies on the TLS pointer, make sure that the pointer is correctly set when + /// entering the user space. + pub fn activate_tls_pointer(&self) { + unsafe { wrfsbase(self.fsbase() as u64) } + } } impl UserContextApiInternal for UserContext { @@ -135,8 +157,8 @@ impl UserContextApiInternal for UserContext { return_reason } - fn as_trap_frame(&self) -> trapframe::TrapFrame { - trapframe::TrapFrame { + fn as_trap_frame(&self) -> TrapFrame { + TrapFrame { rax: self.user_context.general.rax, rbx: self.user_context.general.rbx, rcx: self.user_context.general.rcx, diff --git a/ostd/src/arch/x86/iommu/fault.rs b/ostd/src/arch/x86/iommu/fault.rs index 7b5dc86b..c976e84d 100644 --- a/ostd/src/arch/x86/iommu/fault.rs +++ b/ostd/src/arch/x86/iommu/fault.rs @@ -9,11 +9,13 @@ use core::fmt::Debug; use bitflags::bitflags; use log::info; use spin::Once; -use trapframe::TrapFrame; use volatile::{access::ReadWrite, Volatile}; use super::registers::Capability; -use crate::{mm::Vaddr, trap::IrqLine}; +use crate::{ + mm::Vaddr, + trap::{IrqLine, TrapFrame}, +}; #[derive(Debug)] pub struct FaultEventRegisters { diff --git a/ostd/src/arch/x86/irq.rs b/ostd/src/arch/x86/irq.rs index e3dbd329..2d6b1611 100644 --- a/ostd/src/arch/x86/irq.rs +++ b/ostd/src/arch/x86/irq.rs @@ -8,10 +8,12 @@ use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec}; use id_alloc::IdAlloc; use spin::Once; -use trapframe::TrapFrame; use x86_64::registers::rflags::{self, RFlags}; -use crate::sync::{Mutex, PreemptDisabled, SpinLock, SpinLockGuard}; +use crate::{ + sync::{Mutex, PreemptDisabled, SpinLock, SpinLockGuard}, + trap::TrapFrame, +}; /// The global allocator for software defined IRQ lines. pub(crate) static IRQ_ALLOCATOR: Once> = Once::new(); diff --git a/ostd/src/arch/x86/kernel/tsc.rs b/ostd/src/arch/x86/kernel/tsc.rs index f0780668..cb991a85 100644 --- a/ostd/src/arch/x86/kernel/tsc.rs +++ b/ostd/src/arch/x86/kernel/tsc.rs @@ -8,7 +8,6 @@ use core::{ }; use log::info; -use trapframe::TrapFrame; use x86::cpuid::cpuid; use crate::{ @@ -16,7 +15,7 @@ use crate::{ pit::{self, OperatingMode}, TIMER_FREQ, }, - trap::IrqLine, + trap::{IrqLine, TrapFrame}, }; /// The frequency of TSC(Hz) diff --git a/ostd/src/arch/x86/mod.rs b/ostd/src/arch/x86/mod.rs index 21cd13b9..a929bb90 100644 --- a/ostd/src/arch/x86/mod.rs +++ b/ostd/src/arch/x86/mod.rs @@ -60,6 +60,10 @@ pub(crate) fn check_tdx_init() { } pub(crate) fn init_on_bsp() { + // SAFETY: this function is only called once on BSP. + unsafe { + crate::arch::trap::init(true); + } irq::init(); kernel::acpi::init(); diff --git a/ostd/src/arch/x86/serial.rs b/ostd/src/arch/x86/serial.rs index 9d4226ab..0e8484f2 100644 --- a/ostd/src/arch/x86/serial.rs +++ b/ostd/src/arch/x86/serial.rs @@ -10,10 +10,12 @@ use core::fmt::Write; use log::debug; use spin::Once; -use trapframe::TrapFrame; use super::{device::serial::SerialPort, kernel::IO_APIC}; -use crate::{sync::SpinLock, trap::IrqLine}; +use crate::{ + sync::SpinLock, + trap::{IrqLine, TrapFrame}, +}; /// Prints the formatted arguments to the standard output using the serial port. #[inline] diff --git a/ostd/src/arch/x86/task/mod.rs b/ostd/src/arch/x86/task/mod.rs index b0ec910d..08033355 100644 --- a/ostd/src/arch/x86/task/mod.rs +++ b/ostd/src/arch/x86/task/mod.rs @@ -11,6 +11,7 @@ core::arch::global_asm!(include_str!("switch.S")); pub(crate) struct TaskContext { pub regs: CalleeRegs, pub rip: usize, + pub fsbase: usize, } impl TaskContext { @@ -18,8 +19,19 @@ impl TaskContext { Self { regs: CalleeRegs::new(), rip: 0, + fsbase: 0, } } + + /// Sets thread-local storage pointer. + pub fn set_tls_pointer(&mut self, tls: usize) { + self.fsbase = tls; + } + + /// Gets thread-local storage pointer. + pub fn tls_pointer(&self) -> usize { + self.fsbase + } } /// Callee-saved registers. diff --git a/ostd/src/arch/x86/task/switch.S b/ostd/src/arch/x86/task/switch.S index 15203921..8ee326bb 100644 --- a/ostd/src/arch/x86/task/switch.S +++ b/ostd/src/arch/x86/task/switch.S @@ -14,7 +14,11 @@ context_switch: # (cur: *mut TaskContext, nxt: *TaskContext) mov [rdi + 32], r13 mov [rdi + 40], r14 mov [rdi + 48], r15 + rdfsbase r15 + mov [rdi + 64], r15 # Restore nxt's registers + mov r15, [rsi + 64] + wrfsbase r15 mov rsp, [rsi + 0] mov rbx, [rsi + 8] mov rbp, [rsi + 16] diff --git a/ostd/src/arch/x86/tdx_guest.rs b/ostd/src/arch/x86/tdx_guest.rs index 53561410..ef19ac3f 100644 --- a/ostd/src/arch/x86/tdx_guest.rs +++ b/ostd/src/arch/x86/tdx_guest.rs @@ -2,7 +2,6 @@ use log::warn; use tdx_guest::{tdcall::accept_page, tdvmcall::map_gpa, TdxTrapFrame}; -use trapframe::TrapFrame; use crate::{ mm::{ @@ -13,6 +12,7 @@ use crate::{ PAGE_SIZE, }, prelude::Paddr, + trap::TrapFrame, }; const SHARED_BIT: u8 = 51; diff --git a/ostd/src/arch/x86/timer/apic.rs b/ostd/src/arch/x86/timer/apic.rs index a6fdc060..8a7b8f35 100644 --- a/ostd/src/arch/x86/timer/apic.rs +++ b/ostd/src/arch/x86/timer/apic.rs @@ -10,7 +10,6 @@ use core::{ use log::info; use spin::Once; -use trapframe::TrapFrame; use x86::{ cpuid::cpuid, msr::{wrmsr, IA32_TSC_DEADLINE}, @@ -26,7 +25,7 @@ use crate::{ tsc::TSC_FREQ, }, }, - trap::IrqLine, + trap::{IrqLine, TrapFrame}, }; /// Initializes APIC with tsc deadline mode or periodic mode. diff --git a/ostd/src/arch/x86/timer/mod.rs b/ostd/src/arch/x86/timer/mod.rs index de78f0e1..2efc3a73 100644 --- a/ostd/src/arch/x86/timer/mod.rs +++ b/ostd/src/arch/x86/timer/mod.rs @@ -12,13 +12,12 @@ use core::{cell::RefCell, sync::atomic::Ordering}; pub use jiffies::Jiffies; use spin::Once; -use trapframe::TrapFrame; use self::apic::APIC_TIMER_CALLBACK; use crate::{ arch::x86::kernel, cpu_local, - trap::{self, IrqLine}, + trap::{self, IrqLine, TrapFrame}, }; /// The timer frequency (Hz). Here we choose 1000Hz since 1000Hz is easier for unit conversion and diff --git a/ostd/src/arch/x86/trap/gdt.rs b/ostd/src/arch/x86/trap/gdt.rs new file mode 100644 index 00000000..9511dd48 --- /dev/null +++ b/ostd/src/arch/x86/trap/gdt.rs @@ -0,0 +1,120 @@ +// 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: +// * Link TaskStateSegment to .cpu_local area. +// * Init TaskStateSegment on bsp/ap respectively. +// +// These changes are released under the following license: +// +// SPDX-License-Identifier: MPL-2.0 + +//! Configure Global Descriptor Table (GDT). + +use alloc::{boxed::Box, vec::Vec}; +use core::cell::SyncUnsafeCell; + +use x86_64::{ + instructions::tables::{lgdt, load_tss, sgdt}, + registers::{ + model_specific::Star, + segmentation::{Segment64, GS}, + }, + structures::{ + gdt::{Descriptor, SegmentSelector}, + tss::TaskStateSegment, + DescriptorTablePointer, + }, + PrivilegeLevel, VirtAddr, +}; + +/// Init TSS & GDT. +pub unsafe fn init(on_bsp: bool) { + // Allocate stack for trap from user, set the stack top to TSS, + // so that when trap from ring3 to ring0, CPU can switch stack correctly. + let tss = if on_bsp { + init_local_tss_on_bsp() + } else { + init_local_tss_on_ap() + }; + + let (tss0, tss1) = match Descriptor::tss_segment(tss) { + Descriptor::SystemSegment(tss0, tss1) => (tss0, tss1), + _ => unreachable!(), + }; + // FIXME: the segment limit assumed by x86_64 does not include the I/O port bitmap. + + // Get current GDT. + let gdtp = sgdt(); + let entry_count = (gdtp.limit + 1) as usize / size_of::(); + let old_gdt = core::slice::from_raw_parts(gdtp.base.as_ptr::(), entry_count); + + // Allocate new GDT with 7 more entries. + // + // NOTICE: for fast syscall: + // STAR[47:32] = K_CS = K_SS - 8 + // STAR[63:48] = U_CS32 = U_SS32 - 8 = U_CS - 16 + let mut gdt = Vec::from(old_gdt); + gdt.extend([tss0, tss1, KCODE64, KDATA64, UCODE32, UDATA32, UCODE64].iter()); + let gdt = Vec::leak(gdt); + + // Load new GDT and TSS. + lgdt(&DescriptorTablePointer { + limit: gdt.len() as u16 * 8 - 1, + base: VirtAddr::new(gdt.as_ptr() as _), + }); + load_tss(SegmentSelector::new( + entry_count as u16, + PrivilegeLevel::Ring0, + )); + + let sysret = SegmentSelector::new(entry_count as u16 + 4, PrivilegeLevel::Ring3).0; + let syscall = SegmentSelector::new(entry_count as u16 + 2, PrivilegeLevel::Ring0).0; + Star::write_raw(sysret, syscall); + + USER_SS = sysret + 8; + USER_CS = sysret + 16; +} + +// The linker script ensure that cpu_local_tss section is right +// at the beginning of cpu_local area, so that gsbase (offset zero) +// points to LOCAL_TSS. +#[allow(dead_code)] +#[link_section = ".cpu_local_tss"] +static LOCAL_TSS: SyncUnsafeCell = SyncUnsafeCell::new(TaskStateSegment::new()); + +unsafe fn init_local_tss_on_bsp() -> &'static TaskStateSegment { + let tss_ptr = LOCAL_TSS.get(); + + let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000; + (*tss_ptr).privilege_stack_table[0] = VirtAddr::new(trap_stack_top); + &*tss_ptr +} + +unsafe fn init_local_tss_on_ap() -> &'static TaskStateSegment { + let gs_base = GS::read_base().as_u64(); + let tss_ptr = gs_base as *mut TaskStateSegment; + + let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000; + (*tss_ptr).privilege_stack_table[0] = VirtAddr::new(trap_stack_top); + &*tss_ptr +} + +#[no_mangle] +static mut USER_SS: u16 = 0; +#[no_mangle] +static mut USER_CS: u16 = 0; + +const KCODE64: u64 = 0x00209800_00000000; // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE +const UCODE64: u64 = 0x0020F800_00000000; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE +const KDATA64: u64 = 0x00009200_00000000; // DATA_WRITABLE | USER_SEGMENT | PRESENT +#[allow(dead_code)] +const UDATA64: u64 = 0x0000F200_00000000; // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT +const UCODE32: u64 = 0x00cffa00_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT +const UDATA32: u64 = 0x00cff200_0000ffff; // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT diff --git a/ostd/src/arch/x86/trap/idt.rs b/ostd/src/arch/x86/trap/idt.rs new file mode 100644 index 00000000..bb3a584d --- /dev/null +++ b/ostd/src/arch/x86/trap/idt.rs @@ -0,0 +1,47 @@ +// 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). + +use alloc::boxed::Box; +use core::arch::global_asm; + +use x86_64::{ + structures::idt::{Entry, HandlerFunc, InterruptDescriptorTable}, + PrivilegeLevel, +}; + +global_asm!(include_str!("trap.S")); + +pub fn init() { + extern "C" { + #[link_name = "trap_handler_table"] + static VECTORS: [HandlerFunc; 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(); +} diff --git a/ostd/src/arch/x86/trap.rs b/ostd/src/arch/x86/trap/mod.rs similarity index 59% rename from ostd/src/arch/x86/trap.rs rename to ostd/src/arch/x86/trap/mod.rs index c99a66c4..45484578 100644 --- a/ostd/src/arch/x86/trap.rs +++ b/ostd/src/arch/x86/trap/mod.rs @@ -1,11 +1,28 @@ +// 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: +// * Implement the `trap_handler` of Asterinas. +// +// These changes are released under the following license: +// // SPDX-License-Identifier: MPL-2.0 //! Handles trap. +mod gdt; +mod idt; +mod syscall; + use align_ext::AlignExt; use cfg_if::cfg_if; use log::debug; -use trapframe::TrapFrame; use super::ex_table::ExTable; use crate::{ @@ -31,6 +48,168 @@ cpu_local_cell! { static IS_KERNEL_INTERRUPTED: bool = false; } +/// Trap frame of kernel interrupt +/// +/// # Trap handler +/// +/// You need to define a handler function like this: +/// +/// ``` +/// #[no_mangle] +/// extern "sysv64" fn trap_handler(tf: &mut TrapFrame) { +/// match tf.trap_num { +/// 3 => { +/// println!("TRAP: BreakPoint"); +/// tf.rip += 1; +/// } +/// _ => panic!("TRAP: {:#x?}", tf), +/// } +/// } +/// ``` +#[derive(Debug, Default, Clone, Copy)] +#[repr(C)] +#[allow(missing_docs)] +pub struct TrapFrame { + // Pushed by 'trap.S' + pub rax: usize, + pub rbx: usize, + pub rcx: usize, + pub rdx: usize, + pub rsi: usize, + pub rdi: usize, + pub rbp: usize, + pub rsp: usize, + pub r8: usize, + pub r9: usize, + pub r10: usize, + pub r11: usize, + pub r12: usize, + pub r13: usize, + pub r14: usize, + pub r15: usize, + pub _pad: usize, + + pub trap_num: usize, + pub error_code: usize, + + // Pushed by CPU + pub rip: usize, + pub cs: usize, + pub rflags: usize, +} + +/// Initialize interrupt handling on x86_64. +/// +/// # Safety +/// +/// This function will: +/// +/// - Disable interrupt. +/// - Switch to a new [GDT], extend 7 more entries from the current one. +/// - Switch to a new [TSS], `GSBASE` pointer to its base address. +/// - Switch to a new [IDT], override the current one. +/// - Enable [`syscall`] instruction. +/// - set `EFER::SYSTEM_CALL_EXTENSIONS` +/// +/// [GDT]: https://wiki.osdev.org/GDT +/// [IDT]: https://wiki.osdev.org/IDT +/// [TSS]: https://wiki.osdev.org/Task_State_Segment +/// [`syscall`]: https://www.felixcloutier.com/x86/syscall +/// +#[cfg(any(target_os = "none", target_os = "uefi"))] +pub unsafe fn init(on_bsp: bool) { + x86_64::instructions::interrupts::disable(); + gdt::init(on_bsp); + idt::init(); + syscall::init(); +} + +/// User space context. +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[repr(C)] +#[allow(missing_docs)] +pub struct UserContext { + pub general: GeneralRegs, + pub trap_num: usize, + pub error_code: usize, +} + +/// General registers. +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq)] +#[repr(C)] +#[allow(missing_docs)] +pub struct GeneralRegs { + pub rax: usize, + pub rbx: usize, + pub rcx: usize, + pub rdx: usize, + pub rsi: usize, + pub rdi: usize, + pub rbp: usize, + pub rsp: usize, + pub r8: usize, + pub r9: usize, + pub r10: usize, + pub r11: usize, + pub r12: usize, + pub r13: usize, + pub r14: usize, + pub r15: usize, + pub rip: usize, + pub rflags: usize, + pub fsbase: usize, + pub gsbase: usize, +} + +impl UserContext { + /// Get number of syscall. + pub fn get_syscall_num(&self) -> usize { + self.general.rax + } + + /// Get return value of syscall. + pub fn get_syscall_ret(&self) -> usize { + self.general.rax + } + + /// Set return value of syscall. + pub fn set_syscall_ret(&mut self, ret: usize) { + self.general.rax = ret; + } + + /// Get syscall args. + pub fn get_syscall_args(&self) -> [usize; 6] { + [ + self.general.rdi, + self.general.rsi, + self.general.rdx, + self.general.r10, + self.general.r8, + self.general.r9, + ] + } + + /// Set instruction pointer. + pub fn set_ip(&mut self, ip: usize) { + self.general.rip = ip; + } + + /// Set stack pointer. + pub fn set_sp(&mut self, sp: usize) { + self.general.rsp = sp; + } + + /// Get stack pointer. + pub fn get_sp(&self) -> usize { + self.general.rsp + } + + /// Set thread-local storage pointer. + pub fn set_tls(&mut self, tls: usize) { + self.general.fsbase = tls; + } +} + /// Returns true if this function is called within the context of an IRQ handler /// and the IRQ occurs while the CPU is executing in the kernel mode. /// Otherwise, it returns false. @@ -38,7 +217,7 @@ pub fn is_kernel_interrupted() -> bool { IS_KERNEL_INTERRUPTED.load() } -/// Only from kernel +/// Handle traps (only from kernel). #[no_mangle] extern "sysv64" fn trap_handler(f: &mut TrapFrame) { if CpuException::is_cpu_exception(f.trap_num as u16) { diff --git a/ostd/src/arch/x86/trap/syscall.S b/ostd/src/arch/x86/trap/syscall.S new file mode 100644 index 00000000..7aefb36b --- /dev/null +++ b/ostd/src/arch/x86/trap/syscall.S @@ -0,0 +1,140 @@ +/* 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: + * * Skip saving/restoring the fsgsbase registers. + * + * These changes are released under the following license: + * + * SPDX-License-Identifier: MPL-2.0 + */ + +.text + # extern "sysv64" fn syscall_return(&mut GeneralRegs) +.global syscall_return +syscall_return: + # disable interrupt + cli + + # save callee-saved registers + push r15 + push r14 + push r13 + push r12 + push rbp + push rbx + + push rdi # keep rsp 16 bytes align + mov gs:4, rsp # store kernel rsp -> TSS.sp0 + mov rsp, rdi # set rsp -> GeneralRegs + + # restore user gsbase + swapgs + + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + pop rdi + pop rbp + pop r8 # skip rsp + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + # rip + # rflags + # fsbase + # gsbase + # trap_num + # error_code + + # determain sysret or iret + cmp dword ptr [rsp + 4*8], 0x100 # syscall? + je sysret +iret: + # construct trap frame + push [USER_SS] # push ss + push [rsp - 8*8] # push rsp + push [rsp + 3*8] # push rflags + push [USER_CS] # push cs + push [rsp + 4*8] # push rip + + iretq + +sysret: + pop rcx # rcx = rip + pop r11 # r11 = rflags + mov rsp, [rsp - 11*8] # load rsp + + sysretq + + # sysretq instruction do: + # - load cs, ss + # - load rflags <- r11 + # - load rip <- rcx + +.global syscall_entry +syscall_entry: + # syscall instruction do: + # - load cs + # - store rflags -> r11 + # - mask rflags + # - store rip -> rcx + # - load rip + + swapgs # swap in kernel gs + mov gs:12, rsp # store user rsp -> scratch at TSS.sp1 + mov rsp, gs:4 # load kernel rsp <- TSS.sp0 + pop rsp # load rsp -> GeneralRegs + add rsp, 21*8 # rsp -> error code of GeneralRegs + + push 0x100 # push trap_num + sub rsp, 16 # skip fsbase, gsbase + # push general registers + push r11 # push rflags + push rcx # push rip + +.global trap_syscall_entry +trap_syscall_entry: + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + push gs:12 # push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + # restore callee-saved registers + mov rsp, gs:4 # load kernel rsp <- TSS.sp0 + pop rbx + + pop rbx + pop rbp + pop r12 + pop r13 + pop r14 + pop r15 + + # go back to Rust + ret diff --git a/ostd/src/arch/x86/trap/syscall.rs b/ostd/src/arch/x86/trap/syscall.rs new file mode 100644 index 00000000..bdf79400 --- /dev/null +++ b/ostd/src/arch/x86/trap/syscall.rs @@ -0,0 +1,101 @@ +// 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: +// * Revise some comments. +// +// These changes are released under the following license: +// +// SPDX-License-Identifier: MPL-2.0 + +//! Configure fast syscall. + +use core::arch::global_asm; + +use x86::cpuid::CpuId; +use x86_64::{ + registers::{ + control::{Cr4, Cr4Flags}, + model_specific::{Efer, EferFlags, LStar, SFMask}, + rflags::RFlags, + }, + VirtAddr, +}; + +use super::UserContext; + +global_asm!(include_str!("syscall.S")); + +pub fn init() { + let cpuid = CpuId::new(); + unsafe { + // Enable `syscall` instruction. + assert!(cpuid + .get_extended_processor_and_feature_identifiers() + .unwrap() + .has_syscall_sysret()); + Efer::update(|efer| { + efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS); + }); + + // Enable `FSGSBASE` instructions. + assert!(cpuid.get_extended_feature_info().unwrap().has_fsgsbase()); + Cr4::update(|cr4| { + cr4.insert(Cr4Flags::FSGSBASE); + }); + + // Flags to clear on syscall. + // Copy from Linux 5.0, TF|DF|IF|IOPL|AC|NT + const RFLAGS_MASK: u64 = 0x47700; + + LStar::write(VirtAddr::new(syscall_entry as usize as u64)); + SFMask::write(RFlags::from_bits(RFLAGS_MASK).unwrap()); + } +} + +extern "sysv64" { + fn syscall_entry(); + fn syscall_return(regs: &mut UserContext); +} + +impl UserContext { + /// Go to user space with the context, and come back when a trap occurs. + /// + /// On return, the context will be reset to the status before the trap. + /// Trap reason and error code will be placed at `trap_num` and `error_code`. + /// + /// If the trap was triggered by `syscall` instruction, the `trap_num` will be set to `0x100`. + /// + /// If `trap_num` is `0x100`, it will go user by `sysret` (`rcx` and `r11` are dropped), + /// otherwise it will use `iret`. + /// + /// # Example + /// ```no_run + /// use trapframe::{UserContext, GeneralRegs}; + /// + /// // init user space context + /// let mut context = UserContext { + /// general: GeneralRegs { + /// rip: 0x1000, + /// rsp: 0x10000, + /// ..Default::default() + /// }, + /// ..Default::default() + /// }; + /// // go to user + /// context.run(); + /// // back from user + /// println!("back from user: {:#x?}", context); + /// ``` + pub fn run(&mut self) { + unsafe { + syscall_return(self); + } + } +} diff --git a/ostd/src/arch/x86/trap/trap.S b/ostd/src/arch/x86/trap/trap.S new file mode 100644 index 00000000..19cbfe85 --- /dev/null +++ b/ostd/src/arch/x86/trap/trap.S @@ -0,0 +1,149 @@ +/* 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: + * * Add the `trap_handler_table`. + * + * These changes are released under the following license: + * + * SPDX-License-Identifier: MPL-2.0 + */ + +.equ NUM_INT, 256 + +.altmacro +.macro DEF_HANDLER, i +.Ltrap_handler_\i: +.if \i == 8 || (\i >= 10 && \i <= 14) || \i == 17 + # error code pushed by CPU + push \i # interrupt vector + jmp trap_common +.else + push 0 # fill in error code in TrapFrame + push \i # interrupt vector + jmp trap_common +.endif +.endm + +.section .text +_trap_handlers: +.set i, 0 +.rept NUM_INT + DEF_HANDLER %i + .set i, i + 1 +.endr + +.macro DEF_TABLE_ENTRY, i + .quad .Ltrap_handler_\i +.endm + +.section .rodata +.global trap_handler_table +trap_handler_table: +.set i, 0 +.rept NUM_INT + DEF_TABLE_ENTRY %i + .set i, i + 1 +.endr + +.section .text +.global trap_common +trap_common: + push rax + mov ax, [rsp + 4*8] # load cs + and ax, 0x3 # test + jz __from_kernel # continue trap + +__from_user: + /* + kernel stack: + - ptr to GeneralRegs + - ss + - rsp + - rflags + - cs + - rip + - error code + - trap num + - rax + */ + swapgs # swap in kernel gs + mov rax, [rsp + 6*8] # rax = user rsp + mov gs:12, rax # store user rsp -> scratch at TSS.sp1 + + mov rsp, [rsp + 8*8] # load rsp -> GeneralRegs + add rsp, 22*8 # rsp -> top of GeneralRegs + mov rax, gs:4 # rax = kernel stack + + # push trap_num, error_code + push [rax - 6*8] # push error_code + push [rax - 7*8] # push trap_num + sub rsp, 16 # skip fsbase, gsbase + # push general registers + push [rax - 3*8] # push rflags + push [rax - 5*8] # push rip + mov rax, [rax - 8*8] # pop rax + jmp trap_syscall_entry + +__from_kernel: + /* + kernel stack: + - rflags + - cs + - rip + - error code + - trap num + - rax + */ + pop rax + push 0 + push r15 + push r14 + push r13 + push r12 + push r11 + push r10 + push r9 + push r8 + lea r8, [rsp + 13*8] + push r8 # push rsp + push rbp + push rdi + push rsi + push rdx + push rcx + push rbx + push rax + + mov rdi, rsp + call trap_handler + +.global trap_return +trap_return: + pop rax + pop rbx + pop rcx + pop rdx + pop rsi + pop rdi + pop rbp + pop r8 # skip rsp + pop r8 + pop r9 + pop r10 + pop r11 + pop r12 + pop r13 + pop r14 + pop r15 + + # skip padding, trap_num, error_code + add rsp, 24 + + iretq diff --git a/ostd/src/boot/smp.rs b/ostd/src/boot/smp.rs index ef722663..41808fa6 100644 --- a/ostd/src/boot/smp.rs +++ b/ostd/src/boot/smp.rs @@ -121,7 +121,7 @@ fn ap_early_entry(local_apic_id: u32) -> ! { // SAFETY: this function is only called once on this AP. unsafe { - trapframe::init(); + crate::arch::trap::init(false); } // SAFETY: this function is only called once on this AP, after the BSP has diff --git a/ostd/src/lib.rs b/ostd/src/lib.rs index d2a12c52..7cc1ad60 100644 --- a/ostd/src/lib.rs +++ b/ostd/src/lib.rs @@ -18,6 +18,7 @@ #![feature(panic_info_message)] #![feature(ptr_sub_ptr)] #![feature(strict_provenance)] +#![feature(sync_unsafe_cell)] // The `generic_const_exprs` feature is incomplete however required for the page table // const generic implementation. We are using this feature in a conservative manner. #![allow(incomplete_features)] @@ -87,7 +88,6 @@ pub unsafe fn init() { mm::kspace::init_kernel_page_table(mm::init_page_meta()); mm::misc_init(); - trapframe::init(); // SAFETY: This function is called only once in the entire system. unsafe { trap::softirq::init() }; arch::init_on_bsp(); diff --git a/ostd/src/task/mod.rs b/ostd/src/task/mod.rs index e99da2ba..9220887b 100644 --- a/ostd/src/task/mod.rs +++ b/ostd/src/task/mod.rs @@ -32,6 +32,7 @@ pub struct Task { user_space: Option>, ctx: UnsafeCell, /// kernel stack, note that the top is SyscallFrame/TrapFrame + #[allow(dead_code)] kstack: KernelStack, schedule_info: TaskScheduleInfo, @@ -53,6 +54,22 @@ impl Task { &self.ctx } + /// Sets thread-local storage pointer. + pub fn set_tls_pointer(&self, tls: usize) { + let ctx_ptr = self.ctx.get(); + + // SAFETY: it's safe to set user tls pointer in kernel context. + unsafe { (*ctx_ptr).set_tls_pointer(tls) } + } + + /// Gets thread-local storage pointer. + pub fn tls_pointer(&self) -> usize { + let ctx_ptr = self.ctx.get(); + + // SAFETY: it's safe to get user tls pointer in kernel context. + unsafe { (*ctx_ptr).tls_pointer() } + } + /// Yields execution so that another task may be scheduled. /// /// Note that this method cannot be simply named "yield" as the name is @@ -176,21 +193,14 @@ impl TaskOptions { current_task.exit(); } - let mut new_task = Task { - func: self.func.unwrap(), - data: self.data.unwrap(), - user_space: self.user_space, - ctx: UnsafeCell::new(TaskContext::default()), - kstack: KernelStack::new_with_guard_page()?, - schedule_info: TaskScheduleInfo { - cpu: AtomicCpuId::default(), - priority: self.priority, - cpu_affinity: self.cpu_affinity, - }, - }; + let kstack = KernelStack::new_with_guard_page()?; - let ctx = new_task.ctx.get_mut(); - ctx.set_instruction_pointer(kernel_task_entry as usize); + let mut ctx = UnsafeCell::new(TaskContext::default()); + if let Some(user_space) = self.user_space.as_ref() { + ctx.get_mut().set_tls_pointer(user_space.tls_pointer()); + }; + ctx.get_mut() + .set_instruction_pointer(kernel_task_entry as usize); // We should reserve space for the return address in the stack, otherwise // we will write across the page boundary due to the implementation of // the context switch. @@ -199,7 +209,21 @@ impl TaskOptions { // to at least 16 bytes. And a larger alignment is needed if larger arguments // are passed to the function. The `kernel_task_entry` function does not // have any arguments, so we only need to align the stack pointer to 16 bytes. - ctx.set_stack_pointer(crate::mm::paddr_to_vaddr(new_task.kstack.end_paddr() - 16)); + ctx.get_mut() + .set_stack_pointer(crate::mm::paddr_to_vaddr(kstack.end_paddr() - 16)); + + let new_task = Task { + func: self.func.unwrap(), + data: self.data.unwrap(), + user_space: self.user_space, + ctx, + kstack, + schedule_info: TaskScheduleInfo { + cpu: AtomicCpuId::default(), + priority: self.priority, + cpu_affinity: self.cpu_affinity, + }, + }; Ok(new_task) } diff --git a/ostd/src/trap/handler.rs b/ostd/src/trap/handler.rs index 3f359f70..70bb5e01 100644 --- a/ostd/src/trap/handler.rs +++ b/ostd/src/trap/handler.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: MPL-2.0 -use trapframe::TrapFrame; - -use crate::{arch::irq::IRQ_LIST, cpu_local_cell}; +use crate::{arch::irq::IRQ_LIST, cpu_local_cell, trap::TrapFrame}; pub(crate) fn call_irq_callback_functions(trap_frame: &TrapFrame, irq_number: usize) { // For x86 CPUs, interrupts are not re-entrant. Local interrupts will be disabled when diff --git a/ostd/src/trap/irq.rs b/ostd/src/trap/irq.rs index 2d3935bf..d2f8f339 100644 --- a/ostd/src/trap/irq.rs +++ b/ostd/src/trap/irq.rs @@ -4,11 +4,10 @@ use core::fmt::Debug; -use trapframe::TrapFrame; - use crate::{ arch::irq::{self, IrqCallbackHandle, IRQ_ALLOCATOR}, prelude::*, + trap::TrapFrame, Error, }; diff --git a/ostd/src/trap/mod.rs b/ostd/src/trap/mod.rs index 3c99972b..1470a04d 100644 --- a/ostd/src/trap/mod.rs +++ b/ostd/src/trap/mod.rs @@ -8,7 +8,7 @@ pub mod softirq; pub use handler::in_interrupt_context; pub use softirq::SoftIrqLine; -pub use trapframe::TrapFrame; pub(crate) use self::handler::call_irq_callback_functions; pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqCallbackFunction, IrqLine}; +pub use crate::arch::trap::TrapFrame; diff --git a/ostd/src/user.rs b/ostd/src/user.rs index 6543f5d5..25760107 100644 --- a/ostd/src/user.rs +++ b/ostd/src/user.rs @@ -4,9 +4,7 @@ //! User space. -use trapframe::TrapFrame; - -use crate::{cpu::UserContext, mm::VmSpace, prelude::*, task::Task}; +use crate::{cpu::UserContext, mm::VmSpace, prelude::*, task::Task, trap::TrapFrame}; /// A user space. /// @@ -47,6 +45,16 @@ impl UserSpace { pub fn user_mode(&self) -> UserMode<'_> { todo!() } + + /// Sets thread-local storage pointer. + pub fn set_tls_pointer(&mut self, tls: usize) { + self.init_ctx.set_tls_pointer(tls) + } + + /// Gets thread-local storage pointer. + pub fn tls_pointer(&self) -> usize { + self.init_ctx.tls_pointer() + } } /// Specific architectures need to implement this trait. This should only used in [`UserMode`]