mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-10 22:06:48 +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,
|
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),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user