#[cfg(kernel_tls)]
pub use super::asm::{read_thread_pointer, write_thread_pointer};
pub use super::{
context::{ExtendedState, FxsaveArea, UserXstate},
entry_state::CpuEntryState,
msr::Msr,
};
#[inline]
pub unsafe fn write_gs_base(base: usize) {
unsafe { x86::msr::wrmsr(x86::msr::IA32_GS_BASE, base as u64) };
}
#[inline(always)]
pub unsafe fn read_gs_u32<const OFFSET: usize>() -> u32 {
let value;
unsafe {
core::arch::asm!(
"mov {value:e}, dword ptr gs:[{offset}]",
value = out(reg) value,
offset = const OFFSET,
options(nostack, preserves_flags, readonly),
);
}
value
}
#[inline(always)]
pub unsafe fn read_gs_usize<const OFFSET: usize>() -> usize {
let value;
unsafe {
core::arch::asm!(
"mov {value}, qword ptr gs:[{offset}]",
value = out(reg) value,
offset = const OFFSET,
options(nostack, preserves_flags, readonly),
);
}
value
}
#[inline(always)]
pub unsafe fn increment_gs_u32<const OFFSET: usize>() {
unsafe {
core::arch::asm!(
"inc dword ptr gs:[{offset}]",
offset = const OFFSET,
options(nostack),
);
}
}
#[inline(always)]
pub unsafe fn decrement_gs_u32<const OFFSET: usize>() {
unsafe {
core::arch::asm!(
"dec dword ptr gs:[{offset}]",
offset = const OFFSET,
options(nostack),
);
}
}
#[inline(always)]
pub unsafe fn compare_exchange_gs_u32<const OFFSET: usize>(current: u32, next: u32) -> u32 {
let observed;
unsafe {
core::arch::asm!(
"cmpxchg dword ptr gs:[{offset}], {next:e}",
offset = const OFFSET,
next = in(reg) next,
inout("eax") current => observed,
options(nostack),
);
}
observed
}
#[repr(C)]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct GeneralRegisters {
pub rax: u64,
pub rcx: u64,
pub rdx: u64,
pub rbx: u64,
pub rbp: u64,
pub rsi: u64,
pub rdi: u64,
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
}
impl GeneralRegisters {
pub fn get_reg_of_index(&self, index: u8) -> u64 {
match index {
0 => self.rax,
1 => self.rcx,
2 => self.rdx,
3 => self.rbx,
5 => self.rbp,
6 => self.rsi,
7 => self.rdi,
8 => self.r8,
9 => self.r9,
10 => self.r10,
11 => self.r11,
12 => self.r12,
13 => self.r13,
14 => self.r14,
15 => self.r15,
_ => {
panic!("Illegal index of GeneralRegisters {}", index);
}
}
}
pub fn set_reg_of_index(&mut self, index: u8, value: u64) {
match index {
0 => self.rax = value,
1 => self.rcx = value,
2 => self.rdx = value,
3 => self.rbx = value,
5 => self.rbp = value,
6 => self.rsi = value,
7 => self.rdi = value,
8 => self.r8 = value,
9 => self.r9 = value,
10 => self.r10 = value,
11 => self.r11 = value,
12 => self.r12 = value,
13 => self.r13 = value,
14 => self.r14 = value,
15 => self.r15 = value,
_ => {
panic!("Illegal index of GeneralRegisters {}", index);
}
}
}
pub fn get_edx_eax(&self) -> u64 {
(self.edx() as u64) << 32 | self.eax() as u64
}
}
macro_rules! register_accessors {
(
$get:ident,
$set:ident,
$field:ident,
$ty:ty,
$shift:literal,
$mask:expr,
$zero_extend:literal
) => {
#[doc = concat!("Reads the `", stringify!($get), "` subregister.")]
pub const fn $get(&self) -> $ty {
(self.$field >> $shift) as $ty
}
#[doc = concat!("Writes `", stringify!($get), "` using x86 subregister semantics.")]
pub const fn $set(&mut self, value: $ty) {
if $zero_extend {
self.$field = value as u64;
} else {
self.$field =
(self.$field & !(($mask as u64) << $shift)) | ((value as u64) << $shift);
}
}
};
}
impl GeneralRegisters {
register_accessors!(eax, set_eax, rax, u32, 0, u32::MAX, true);
register_accessors!(ecx, set_ecx, rcx, u32, 0, u32::MAX, true);
register_accessors!(edx, set_edx, rdx, u32, 0, u32::MAX, true);
register_accessors!(ebx, set_ebx, rbx, u32, 0, u32::MAX, true);
register_accessors!(ebp, set_ebp, rbp, u32, 0, u32::MAX, true);
register_accessors!(esi, set_esi, rsi, u32, 0, u32::MAX, true);
register_accessors!(edi, set_edi, rdi, u32, 0, u32::MAX, true);
register_accessors!(r8d, set_r8d, r8, u32, 0, u32::MAX, true);
register_accessors!(r9d, set_r9d, r9, u32, 0, u32::MAX, true);
register_accessors!(r10d, set_r10d, r10, u32, 0, u32::MAX, true);
register_accessors!(r11d, set_r11d, r11, u32, 0, u32::MAX, true);
register_accessors!(r12d, set_r12d, r12, u32, 0, u32::MAX, true);
register_accessors!(r13d, set_r13d, r13, u32, 0, u32::MAX, true);
register_accessors!(r14d, set_r14d, r14, u32, 0, u32::MAX, true);
register_accessors!(r15d, set_r15d, r15, u32, 0, u32::MAX, true);
register_accessors!(ax, set_ax, rax, u16, 0, u16::MAX, false);
register_accessors!(cx, set_cx, rcx, u16, 0, u16::MAX, false);
register_accessors!(dx, set_dx, rdx, u16, 0, u16::MAX, false);
register_accessors!(bx, set_bx, rbx, u16, 0, u16::MAX, false);
register_accessors!(bp, set_bp, rbp, u16, 0, u16::MAX, false);
register_accessors!(si, set_si, rsi, u16, 0, u16::MAX, false);
register_accessors!(di, set_di, rdi, u16, 0, u16::MAX, false);
register_accessors!(r8w, set_r8w, r8, u16, 0, u16::MAX, false);
register_accessors!(r9w, set_r9w, r9, u16, 0, u16::MAX, false);
register_accessors!(r10w, set_r10w, r10, u16, 0, u16::MAX, false);
register_accessors!(r11w, set_r11w, r11, u16, 0, u16::MAX, false);
register_accessors!(r12w, set_r12w, r12, u16, 0, u16::MAX, false);
register_accessors!(r13w, set_r13w, r13, u16, 0, u16::MAX, false);
register_accessors!(r14w, set_r14w, r14, u16, 0, u16::MAX, false);
register_accessors!(r15w, set_r15w, r15, u16, 0, u16::MAX, false);
register_accessors!(al, set_al, rax, u8, 0, u8::MAX, false);
register_accessors!(cl, set_cl, rcx, u8, 0, u8::MAX, false);
register_accessors!(dl, set_dl, rdx, u8, 0, u8::MAX, false);
register_accessors!(bl, set_bl, rbx, u8, 0, u8::MAX, false);
register_accessors!(bpl, set_bpl, rbp, u8, 0, u8::MAX, false);
register_accessors!(sil, set_sil, rsi, u8, 0, u8::MAX, false);
register_accessors!(dil, set_dil, rdi, u8, 0, u8::MAX, false);
register_accessors!(r8b, set_r8b, r8, u8, 0, u8::MAX, false);
register_accessors!(r9b, set_r9b, r9, u8, 0, u8::MAX, false);
register_accessors!(r10b, set_r10b, r10, u8, 0, u8::MAX, false);
register_accessors!(r11b, set_r11b, r11, u8, 0, u8::MAX, false);
register_accessors!(r12b, set_r12b, r12, u8, 0, u8::MAX, false);
register_accessors!(r13b, set_r13b, r13, u8, 0, u8::MAX, false);
register_accessors!(r14b, set_r14b, r14, u8, 0, u8::MAX, false);
register_accessors!(r15b, set_r15b, r15, u8, 0, u8::MAX, false);
register_accessors!(ah, set_ah, rax, u8, 8, u8::MAX, false);
register_accessors!(ch, set_ch, rcx, u8, 8, u8::MAX, false);
register_accessors!(dh, set_dh, rdx, u8, 8, u8::MAX, false);
register_accessors!(bh, set_bh, rbx, u8, 8, u8::MAX, false);
}