Revise safety comments in single_instr.rs

This commit is contained in:
Ruihan Li 2025-01-01 23:41:20 +08:00 committed by Tate, Hongliang Tian
parent 5651b93af0
commit c17a3eaa0b
2 changed files with 125 additions and 108 deletions

View File

@ -15,111 +15,113 @@ use crate::cpu::local::single_instr::{
SingleInstructionSubAssign, 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 { macro_rules! impl_numeric_single_instruction_for {
($([$typ: ty, $inout_type: ident, $register_format: expr])*) => {$( ($([$typ: ty, $inout_type: ident, $register_format: expr])*) => {$(
impl SingleInstructionAddAssign<$typ> for $typ { impl SingleInstructionAddAssign<$typ> for $typ {
unsafe fn add_assign(offset: *mut Self, val: Self) { unsafe fn add_assign(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY:
// 1. `gs` points to the CPU-local region (global invariant).
core::arch::asm!( // 2. `offset` represents the offset of a CPU-local variable
concat!("add gs:[{0}], {1", $register_format, "}"), // (upheld by the caller).
in(reg) offset, // 3. The variable is only accessible in the current CPU, is
in($inout_type) val, // a scalar, and is never borrowed, so it is valid to
options(nostack), // 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 { impl SingleInstructionSubAssign<$typ> for $typ {
unsafe fn sub_assign(offset: *mut Self, val: Self) { unsafe fn sub_assign(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("sub gs:[{0}], {1", $register_format, "}"), concat!("sub gs:[{0}], {1", $register_format, "}"),
in(reg) offset, in(reg) offset,
in($inout_type) val, in($inout_type) val,
options(nostack), options(nostack),
); );
}
} }
} }
impl SingleInstructionBitAndAssign<$typ> for $typ { impl SingleInstructionBitAndAssign<$typ> for $typ {
unsafe fn bitand_assign(offset: *mut Self, val: Self) { unsafe fn bitand_assign(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("and gs:[{0}], {1", $register_format, "}"), concat!("and gs:[{0}], {1", $register_format, "}"),
in(reg) offset, in(reg) offset,
in($inout_type) val, in($inout_type) val,
options(nostack), options(nostack),
); );
}
} }
} }
impl SingleInstructionBitOrAssign<$typ> for $typ { impl SingleInstructionBitOrAssign<$typ> for $typ {
unsafe fn bitor_assign(offset: *mut Self, val: Self) { unsafe fn bitor_assign(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("or gs:[{0}], {1", $register_format, "}"), concat!("or gs:[{0}], {1", $register_format, "}"),
in(reg) offset, in(reg) offset,
in($inout_type) val, in($inout_type) val,
options(nostack), options(nostack),
); );
}
} }
} }
impl SingleInstructionBitXorAssign<$typ> for $typ { impl SingleInstructionBitXorAssign<$typ> for $typ {
unsafe fn bitxor_assign(offset: *mut Self, val: Self) { unsafe fn bitxor_assign(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("xor gs:[{0}], {1", $register_format, "}"), concat!("xor gs:[{0}], {1", $register_format, "}"),
in(reg) offset, in(reg) offset,
in($inout_type) val, in($inout_type) val,
options(nostack), options(nostack),
); );
}
} }
} }
impl SingleInstructionLoad for $typ { impl SingleInstructionLoad for $typ {
unsafe fn load(offset: *const Self) -> Self { unsafe fn load(offset: *const Self) -> Self {
debug_assert_initialized!();
let val: Self; let val: Self;
core::arch::asm!( // SAFETY: Same as `add_assign`.
concat!("mov {0", $register_format, "}, gs:[{1}]"), unsafe {
out($inout_type) val, core::arch::asm!(
in(reg) offset, concat!("mov {0", $register_format, "}, gs:[{1}]"),
options(nostack, readonly), out($inout_type) val,
); in(reg) offset,
options(nostack, readonly),
);
}
val val
} }
} }
impl SingleInstructionStore for $typ { impl SingleInstructionStore for $typ {
unsafe fn store(offset: *mut Self, val: Self) { unsafe fn store(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("mov gs:[{0}], {1", $register_format, "}"), concat!("mov gs:[{0}], {1", $register_format, "}"),
in(reg) offset, in(reg) offset,
in($inout_type) val, in($inout_type) val,
options(nostack), options(nostack),
); );
}
} }
} }
@ -144,29 +146,31 @@ macro_rules! impl_generic_single_instruction_for {
impl<$gen_type $(, $more_gen_type)*> SingleInstructionLoad for $typ { impl<$gen_type $(, $more_gen_type)*> SingleInstructionLoad for $typ {
unsafe fn load(offset: *const Self) -> Self { unsafe fn load(offset: *const Self) -> Self {
debug_assert_initialized!();
let val: Self; let val: Self;
core::arch::asm!( // SAFETY: Same as `add_assign`.
concat!("mov {0}, gs:[{1}]"), unsafe {
out(reg) val, core::arch::asm!(
in(reg) offset, concat!("mov {0}, gs:[{1}]"),
options(nostack, readonly), out(reg) val,
); in(reg) offset,
options(nostack, readonly),
);
}
val val
} }
} }
impl<$gen_type $(, $more_gen_type)*> SingleInstructionStore for $typ { impl<$gen_type $(, $more_gen_type)*> SingleInstructionStore for $typ {
unsafe fn store(offset: *mut Self, val: Self) { unsafe fn store(offset: *mut Self, val: Self) {
debug_assert_initialized!(); // SAFETY: Same as `add_assign`.
unsafe {
core::arch::asm!( core::arch::asm!(
concat!("mov gs:[{0}], {1}"), concat!("mov gs:[{0}], {1}"),
in(reg) offset, in(reg) offset,
in(reg) val, in(reg) val,
options(nostack), options(nostack),
); );
}
} }
} }
)*} )*}
@ -184,15 +188,16 @@ impl_generic_single_instruction_for!(
impl SingleInstructionLoad for bool { impl SingleInstructionLoad for bool {
unsafe fn load(offset: *const Self) -> Self { unsafe fn load(offset: *const Self) -> Self {
debug_assert_initialized!();
let val: u8; let val: u8;
core::arch::asm!( // SAFETY: Same as `add_assign`.
"mov {0}, gs:[{1}]", unsafe {
out(reg_byte) val, core::arch::asm!(
in(reg) offset, "mov {0}, gs:[{1}]",
options(nostack, readonly), out(reg_byte) val,
); in(reg) offset,
options(nostack, readonly),
);
}
debug_assert!(val == 1 || val == 0); debug_assert!(val == 1 || val == 0);
val == 1 val == 1
} }
@ -200,14 +205,15 @@ impl SingleInstructionLoad for bool {
impl SingleInstructionStore for bool { impl SingleInstructionStore for bool {
unsafe fn store(offset: *mut Self, val: Self) { unsafe fn store(offset: *mut Self, val: Self) {
debug_assert_initialized!();
let val: u8 = if val { 1 } else { 0 }; let val: u8 = if val { 1 } else { 0 };
core::arch::asm!( // SAFETY: Same as `add_assign`.
"mov gs:[{0}], {1}", unsafe {
in(reg) offset, core::arch::asm!(
in(reg_byte) val, "mov gs:[{0}], {1}",
options(nostack), in(reg) offset,
); in(reg_byte) val,
options(nostack),
);
}
} }
} }

View File

@ -35,7 +35,7 @@ pub trait SingleInstructionAddAssign<Rhs = Self> {
/// ///
/// # Safety /// # Safety
/// ///
/// /// Please refer to the module-level documentation of [`self`].
unsafe fn add_assign(offset: *mut Self, rhs: Rhs); unsafe fn add_assign(offset: *mut Self, rhs: Rhs);
} }
@ -44,7 +44,12 @@ impl<T: num_traits::WrappingAdd + Copy> SingleInstructionAddAssign<T> for T {
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let addr = (base + offset as usize) as *mut Self; 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<T: num_traits::WrappingSub + Copy> SingleInstructionSubAssign<T> for T {
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let addr = (base + offset as usize) as *mut Self; 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<T: core::ops::BitOr<Output = T> + Copy> SingleInstructionBitOrAssign<T> for
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let addr = (base + offset as usize) as *mut Self; 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<T: core::ops::BitAnd<Output = T> + Copy> SingleInstructionBitAndAssign<T> f
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let addr = (base + offset as usize) as *mut Self; 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<T: core::ops::BitXor<Output = T> + Copy> SingleInstructionBitXorAssign<T> f
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let addr = (base + offset as usize) as *mut Self; 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<T: Copy> SingleInstructionLoad for T {
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let ptr = (base + offset as usize) as *const Self; let ptr = (base + offset as usize) as *const Self;
ptr.read() // SAFETY: Same as `add_assign`.
unsafe { ptr.read() }
} }
} }
@ -160,6 +170,7 @@ impl<T: Copy> SingleInstructionStore for T {
let _guard = crate::trap::disable_local(); let _guard = crate::trap::disable_local();
let base = crate::arch::cpu::local::get_base() as usize; let base = crate::arch::cpu::local::get_base() as usize;
let ptr = (base + offset as usize) as *mut Self; let ptr = (base + offset as usize) as *mut Self;
ptr.write(val); // SAFETY: Same as `add_assign`.
unsafe { ptr.write(val) };
} }
} }