asterinas/src/kxos-frame/src/cpu.rs

272 lines
7.5 KiB
Rust

//! CPU.
use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame};
/// Defines a CPU-local variable.
#[macro_export]
macro_rules! cpu_local {
() => {
todo!()
};
}
/// Returns the number of CPUs.
pub fn num_cpus() -> u32 {
todo!()
}
/// Returns the ID of this CPU.
pub fn this_cpu() -> u32 {
todo!()
}
/// Cpu context, including both general-purpose registers and floating-point registers.
#[derive(Clone, Default, Copy)]
#[repr(C)]
pub struct CpuContext {
pub gp_regs: GpRegs,
pub fs_base: u64,
pub fp_regs: FpRegs,
pub trap_information: Option<TrapInformation>,
}
#[derive(Clone, Default, Copy)]
#[repr(C)]
pub struct TrapInformation {
pub cr2: u64,
pub id: u64,
pub err: u64,
pub cs: u64,
pub ss: u64,
}
/// The general-purpose registers of CPU.
#[derive(Clone, Copy, Debug, Default)]
#[repr(C)]
pub struct GpRegs {
pub r8: u64,
pub r9: u64,
pub r10: u64,
pub r11: u64,
pub r12: u64,
pub r13: u64,
pub r14: u64,
pub r15: u64,
pub rdi: u64,
pub rsi: u64,
pub rbp: u64,
pub rbx: u64,
pub rdx: u64,
pub rax: u64,
pub rcx: u64,
pub rsp: u64,
pub rip: u64,
pub rflag: u64,
}
impl From<SyscallFrame> for CpuContext {
fn from(syscall: SyscallFrame) -> Self {
Self {
gp_regs: GpRegs {
r8: syscall.caller.r8,
r9: syscall.caller.r9,
r10: syscall.caller.r10,
r11: syscall.caller.r11,
r12: syscall.callee.r12,
r13: syscall.callee.r13,
r14: syscall.callee.r14,
r15: syscall.callee.r15,
rdi: syscall.caller.rdi,
rsi: syscall.caller.rsi,
rbp: syscall.callee.rbp,
rbx: syscall.callee.rbx,
rdx: syscall.caller.rdx,
rax: syscall.caller.rax,
rcx: syscall.caller.rcx,
rsp: syscall.callee.rsp,
rip: syscall.caller.rcx,
rflag: 0,
},
fs_base: 0,
fp_regs: FpRegs::default(),
trap_information: None,
}
}
}
impl Into<SyscallFrame> for CpuContext {
fn into(self) -> SyscallFrame {
SyscallFrame {
caller: CallerRegs {
rax: self.gp_regs.rax,
rcx: self.gp_regs.rcx,
rdx: self.gp_regs.rdx,
rsi: self.gp_regs.rsi,
rdi: self.gp_regs.rdi,
r8: self.gp_regs.r8,
r9: self.gp_regs.r9,
r10: self.gp_regs.r10,
r11: self.gp_regs.r11,
},
callee: CalleeRegs {
rsp: self.gp_regs.rsp,
rbx: self.gp_regs.rbx,
rbp: self.gp_regs.rbp,
r12: self.gp_regs.r12,
r13: self.gp_regs.r13,
r14: self.gp_regs.r14,
r15: self.gp_regs.r15,
},
}
}
}
impl From<TrapFrame> for CpuContext {
fn from(trap: TrapFrame) -> Self {
Self {
gp_regs: GpRegs {
r8: trap.caller.r8,
r9: trap.caller.r9,
r10: trap.caller.r10,
r11: trap.caller.r11,
r12: trap.callee.r12,
r13: trap.callee.r13,
r14: trap.callee.r14,
r15: trap.callee.r15,
rdi: trap.caller.rdi,
rsi: trap.caller.rsi,
rbp: trap.callee.rbp,
rbx: trap.callee.rbx,
rdx: trap.caller.rdx,
rax: trap.caller.rax,
rcx: trap.caller.rcx,
rsp: trap.rsp,
rip: trap.rip,
rflag: trap.rflags,
},
fs_base: 0,
fp_regs: FpRegs::default(),
trap_information: Some(TrapInformation {
cr2: trap.cr2,
id: trap.id,
err: trap.err,
cs: trap.cs,
ss: trap.ss,
}),
}
}
}
impl Into<TrapFrame> for CpuContext {
fn into(self) -> TrapFrame {
let trap_information = self.trap_information.unwrap();
TrapFrame {
caller: CallerRegs {
rax: self.gp_regs.rax,
rcx: self.gp_regs.rcx,
rdx: self.gp_regs.rdx,
rsi: self.gp_regs.rsi,
rdi: self.gp_regs.rdi,
r8: self.gp_regs.r8,
r9: self.gp_regs.r9,
r10: self.gp_regs.r10,
r11: self.gp_regs.r11,
},
callee: CalleeRegs {
rsp: self.gp_regs.rsp,
rbx: self.gp_regs.rbx,
rbp: self.gp_regs.rbp,
r12: self.gp_regs.r12,
r13: self.gp_regs.r13,
r14: self.gp_regs.r14,
r15: self.gp_regs.r15,
},
id: trap_information.id,
err: trap_information.err,
cr2: trap_information.cr2,
rip: self.gp_regs.rip,
cs: trap_information.cs,
rflags: self.gp_regs.rflag,
rsp: self.gp_regs.rsp,
ss: trap_information.ss,
}
}
}
/// The floating-point state of CPU.
#[derive(Clone, Copy)]
#[repr(C)]
pub struct FpRegs {
//buf: Aligned<A16, [u8; 512]>,
is_valid: bool,
}
impl FpRegs {
/// Create a new instance.
///
/// Note that a newly-created instance's floating point state is not
/// initialized, thus considered invalid (i.e., `self.is_valid() == false`).
pub fn new() -> Self {
//let buf = Aligned(unsafe { MaybeUninit::uninit().assume_init() });
//let is_valid = false;
//Self { buf, is_valid }
Self { is_valid: false }
// todo!("import aligned")
}
/// Save CPU's current floating pointer states into this instance.
pub fn save(&mut self) {
// unsafe {
// _fxsave(self.buf.as_mut_ptr() as *mut u8);
// }
self.is_valid = true;
}
/// Save the floating state given by a slice of u8.
///
/// After calling this method, the state of the instance will be considered valid.
///
/// # Safety
///
/// It is the caller's responsibility to ensure that the source slice contains
/// data that is in xsave/xrstor format. The slice must have a length of 512 bytes.
pub unsafe fn save_from_slice(&mut self, src: &[u8]) {
//(&mut self.buf).copy_from_slice(src);
//self.is_valid = true;
}
/// Returns whether the instance can contains data in valid xsave/xrstor format.
pub fn is_valid(&self) -> bool {
self.is_valid
}
/// Clear the state of the instance.
///
/// This method does not reset the underlying buffer that contains the floating
/// point state; it only marks the buffer __invalid__.
pub fn clear(&mut self) {
self.is_valid = false;
}
/// Restore CPU's CPU floating pointer states from this instance.
///
/// Panic. If the current state is invalid, the method will panic.
pub fn restore(&self) {
assert!(self.is_valid);
//unsafe { _fxrstor(self.buf.as_ptr()) };
}
/// Returns the floating point state as a slice.
///
/// Note that the slice may contain garbage if `self.is_valid() == false`.
pub fn as_slice(&self) -> &[u8] {
//&*self.buf
todo!()
}
}
impl Default for FpRegs {
fn default() -> Self {
Self::new()
}
}