mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Revise safety comments in single_instr.rs
This commit is contained in:
parent
5651b93af0
commit
c17a3eaa0b
@ -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),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) };
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user