diff --git a/ostd/src/arch/x86/cpu/local.rs b/ostd/src/arch/x86/cpu/local.rs index 1d8ebfc28..6610b16e1 100644 --- a/ostd/src/arch/x86/cpu/local.rs +++ b/ostd/src/arch/x86/cpu/local.rs @@ -15,111 +15,113 @@ use crate::cpu::local::single_instr::{ SingleInstructionSubAssign, }; -/// 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 { - () => { - // The compiler may think that [`super::get_base`] has side effects - // so it may not be optimized out. We make sure that it will be - // conditionally compiled only in debug builds. - #[cfg(debug_assertions)] - debug_assert_ne!(get_base(), 0); - }; -} - macro_rules! impl_numeric_single_instruction_for { ($([$typ: ty, $inout_type: ident, $register_format: expr])*) => {$( impl SingleInstructionAddAssign<$typ> for $typ { unsafe fn add_assign(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("add gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: + // 1. `gs` points to the CPU-local region (global invariant). + // 2. `offset` represents the offset of a CPU-local variable + // (upheld by the caller). + // 3. The variable is only accessible in the current CPU, is + // a scalar, and is never borrowed, so it is valid to + // read/write using a single instruction (upheld by the + // caller). + unsafe { + core::arch::asm!( + concat!("add gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } impl SingleInstructionSubAssign<$typ> for $typ { unsafe fn sub_assign(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("sub gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("sub gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } impl SingleInstructionBitAndAssign<$typ> for $typ { unsafe fn bitand_assign(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("and gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("and gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } impl SingleInstructionBitOrAssign<$typ> for $typ { unsafe fn bitor_assign(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("or gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("or gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } impl SingleInstructionBitXorAssign<$typ> for $typ { unsafe fn bitxor_assign(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("xor gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("xor gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } impl SingleInstructionLoad for $typ { unsafe fn load(offset: *const Self) -> Self { - debug_assert_initialized!(); - let val: Self; - core::arch::asm!( - concat!("mov {0", $register_format, "}, gs:[{1}]"), - out($inout_type) val, - in(reg) offset, - options(nostack, readonly), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("mov {0", $register_format, "}, gs:[{1}]"), + out($inout_type) val, + in(reg) offset, + options(nostack, readonly), + ); + } val } } impl SingleInstructionStore for $typ { unsafe fn store(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("mov gs:[{0}], {1", $register_format, "}"), - in(reg) offset, - in($inout_type) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("mov gs:[{0}], {1", $register_format, "}"), + in(reg) offset, + in($inout_type) val, + options(nostack), + ); + } } } @@ -144,29 +146,31 @@ macro_rules! impl_generic_single_instruction_for { impl<$gen_type $(, $more_gen_type)*> SingleInstructionLoad for $typ { unsafe fn load(offset: *const Self) -> Self { - debug_assert_initialized!(); - let val: Self; - core::arch::asm!( - concat!("mov {0}, gs:[{1}]"), - out(reg) val, - in(reg) offset, - options(nostack, readonly), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("mov {0}, gs:[{1}]"), + out(reg) val, + in(reg) offset, + options(nostack, readonly), + ); + } val } } impl<$gen_type $(, $more_gen_type)*> SingleInstructionStore for $typ { unsafe fn store(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - - core::arch::asm!( - concat!("mov gs:[{0}], {1}"), - in(reg) offset, - in(reg) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + concat!("mov gs:[{0}], {1}"), + in(reg) offset, + in(reg) val, + options(nostack), + ); + } } } )*} @@ -184,15 +188,16 @@ impl_generic_single_instruction_for!( impl SingleInstructionLoad for bool { unsafe fn load(offset: *const Self) -> Self { - debug_assert_initialized!(); - let val: u8; - core::arch::asm!( - "mov {0}, gs:[{1}]", - out(reg_byte) val, - in(reg) offset, - options(nostack, readonly), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + "mov {0}, gs:[{1}]", + out(reg_byte) val, + in(reg) offset, + options(nostack, readonly), + ); + } debug_assert!(val == 1 || val == 0); val == 1 } @@ -200,14 +205,15 @@ impl SingleInstructionLoad for bool { impl SingleInstructionStore for bool { unsafe fn store(offset: *mut Self, val: Self) { - debug_assert_initialized!(); - let val: u8 = if val { 1 } else { 0 }; - core::arch::asm!( - "mov gs:[{0}], {1}", - in(reg) offset, - in(reg_byte) val, - options(nostack), - ); + // SAFETY: Same as `add_assign`. + unsafe { + core::arch::asm!( + "mov gs:[{0}], {1}", + in(reg) offset, + in(reg_byte) val, + options(nostack), + ); + } } } diff --git a/ostd/src/cpu/local/single_instr.rs b/ostd/src/cpu/local/single_instr.rs index 1ac436c0b..f61bc6315 100644 --- a/ostd/src/cpu/local/single_instr.rs +++ b/ostd/src/cpu/local/single_instr.rs @@ -35,7 +35,7 @@ pub trait SingleInstructionAddAssign { /// /// # Safety /// - /// + /// Please refer to the module-level documentation of [`self`]. unsafe fn add_assign(offset: *mut Self, rhs: Rhs); } @@ -44,7 +44,12 @@ impl SingleInstructionAddAssign for T { let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let addr = (base + offset as usize) as *mut Self; - addr.write(addr.read().wrapping_add(&rhs)); + // SAFETY: + // 1. `addr` represents the address of a CPU-local variable. + // 2. The variable is only accessible in the current CPU, is + // `Copy`, and is is never borrowed, so it is valid to + // read/write. + unsafe { addr.write(addr.read().wrapping_add(&rhs)) }; } } @@ -65,7 +70,8 @@ impl SingleInstructionSubAssign for T { let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let addr = (base + offset as usize) as *mut Self; - addr.write(addr.read().wrapping_sub(&rhs)); + // SAFETY: Same as `add_assign`. + unsafe { addr.write(addr.read().wrapping_sub(&rhs)) }; } } @@ -84,7 +90,8 @@ impl + Copy> SingleInstructionBitOrAssign for let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let addr = (base + offset as usize) as *mut Self; - addr.write(addr.read() | rhs); + // SAFETY: Same as `add_assign`. + unsafe { addr.write(addr.read() | rhs) }; } } @@ -103,7 +110,8 @@ impl + Copy> SingleInstructionBitAndAssign f let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let addr = (base + offset as usize) as *mut Self; - addr.write(addr.read() & rhs); + // SAFETY: Same as `add_assign`. + unsafe { addr.write(addr.read() & rhs) }; } } @@ -122,7 +130,8 @@ impl + Copy> SingleInstructionBitXorAssign f let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let addr = (base + offset as usize) as *mut Self; - addr.write(addr.read() ^ rhs); + // SAFETY: Same as `add_assign`. + unsafe { addr.write(addr.read() ^ rhs) }; } } @@ -141,7 +150,8 @@ impl SingleInstructionLoad for T { let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let ptr = (base + offset as usize) as *const Self; - ptr.read() + // SAFETY: Same as `add_assign`. + unsafe { ptr.read() } } } @@ -160,6 +170,7 @@ impl SingleInstructionStore for T { let _guard = crate::trap::disable_local(); let base = crate::arch::cpu::local::get_base() as usize; let ptr = (base + offset as usize) as *mut Self; - ptr.write(val); + // SAFETY: Same as `add_assign`. + unsafe { ptr.write(val) }; } }