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,
};
/// 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),
);
}
}
}

View File

@ -35,7 +35,7 @@ pub trait SingleInstructionAddAssign<Rhs = Self> {
///
/// # Safety
///
///
/// Please refer to the module-level documentation of [`self`].
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 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<T: num_traits::WrappingSub + Copy> SingleInstructionSubAssign<T> 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<T: core::ops::BitOr<Output = T> + Copy> SingleInstructionBitOrAssign<T> 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<T: core::ops::BitAnd<Output = T> + Copy> SingleInstructionBitAndAssign<T> 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<T: core::ops::BitXor<Output = T> + Copy> SingleInstructionBitXorAssign<T> 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<T: Copy> 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<T: Copy> 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) };
}
}