#[cfg(kernel_tls)]
pub use super::asm::{read_thread_pointer, write_thread_pointer};
pub use super::{
asm::{enable_fp, enable_lasx, enable_lsx},
fp::FpuState,
};
pub const KSAVE_KSP: usize = 0;
pub const KSAVE_T0: usize = 1;
pub const KSAVE_T1: usize = 2;
pub const KSAVE_PERCPU: usize = 3;
pub const HOST_PERCPU_KS: usize = KSAVE_PERCPU;
pub const HOST_VCPU_KS: usize = 4;
pub const HOST_VCPU_TMP_KS: usize = 5;
#[inline]
pub fn read_tp() -> usize {
let value;
unsafe { core::arch::asm!("move {}, $tp", out(reg) value, options(nostack)) };
value
}
#[inline]
pub unsafe fn write_tp(value: usize) {
unsafe { core::arch::asm!("move $tp, {}", in(reg) value, options(nostack)) };
}
#[inline]
pub fn read_cpu_anchor() -> (usize, usize) {
let base;
let shadow;
unsafe {
core::arch::asm!(
"move {base}, $r21",
"csrrd {shadow}, {scratch}",
base = out(reg) base,
shadow = out(reg) shadow,
scratch = const 0x30 + KSAVE_PERCPU,
options(nostack),
);
}
(base, shadow)
}
#[inline]
pub unsafe fn write_cpu_anchor(value: usize) {
unsafe {
core::arch::asm!(
"csrwr {shadow}, {scratch}",
"move $r21, {base}",
shadow = inout(reg) value => _,
base = in(reg) value,
scratch = const 0x30 + KSAVE_PERCPU,
options(nostack),
);
}
}
#[inline]
pub unsafe fn read_csr<const CSR: u16>() -> usize {
let value;
unsafe {
core::arch::asm!("csrrd {}, {}", out(reg) value, const CSR, options(nostack));
}
value
}
#[inline]
pub unsafe fn read_guest_csr<const CSR: usize>() -> usize {
let value;
unsafe {
core::arch::asm!("gcsrrd {}, {}", out(reg) value, const CSR, options(nostack));
}
value
}
#[inline]
pub unsafe fn write_csr<const CSR: u16>(value: usize) {
unsafe {
core::arch::asm!("csrwr {}, {}", inout(reg) value => _, const CSR, options(nostack));
}
}
#[inline]
pub unsafe fn write_guest_csr<const CSR: usize>(value: usize) {
unsafe {
core::arch::asm!("gcsrwr {}, {}", inout(reg) value => _, const CSR, options(nostack));
}
}
#[inline]
pub unsafe fn read_iocsr8(address: usize) -> u8 {
let value: usize;
unsafe {
core::arch::asm!("iocsrrd.b {}, {}", out(reg) value, in(reg) address, options(nostack));
}
value as u8
}
#[inline]
pub unsafe fn write_iocsr8(address: usize, value: u8) {
unsafe {
core::arch::asm!("iocsrwr.b {}, {}", in(reg) value as usize, in(reg) address, options(nostack));
}
}
#[inline]
pub unsafe fn read_iocsr16(address: usize) -> u16 {
let value: usize;
unsafe {
core::arch::asm!("iocsrrd.h {}, {}", out(reg) value, in(reg) address, options(nostack));
}
value as u16
}
#[inline]
pub unsafe fn write_iocsr16(address: usize, value: u16) {
unsafe {
core::arch::asm!("iocsrwr.h {}, {}", in(reg) value as usize, in(reg) address, options(nostack));
}
}
#[inline]
pub unsafe fn read_iocsr32(address: usize) -> u32 {
let value: usize;
unsafe {
core::arch::asm!("iocsrrd.w {}, {}", out(reg) value, in(reg) address, options(nostack));
}
value as u32
}
#[inline]
pub unsafe fn write_iocsr32(address: usize, value: u32) {
unsafe {
core::arch::asm!("iocsrwr.w {}, {}", in(reg) value as usize, in(reg) address, options(nostack));
}
}
#[inline]
pub unsafe fn read_iocsr64(address: usize) -> u64 {
let value: usize;
unsafe {
core::arch::asm!("iocsrrd.d {}, {}", out(reg) value, in(reg) address, options(nostack));
}
value as u64
}
#[inline]
pub unsafe fn write_iocsr64(address: usize, value: u64) {
unsafe {
core::arch::asm!("iocsrwr.d {}, {}", in(reg) value as usize, in(reg) address, options(nostack));
}
}
#[repr(C)]
#[derive(Debug, Default, Clone, Copy)]
pub struct GeneralRegisters {
pub zero: usize,
pub ra: usize,
pub tp: usize,
pub sp: usize,
pub a0: usize,
pub a1: usize,
pub a2: usize,
pub a3: usize,
pub a4: usize,
pub a5: usize,
pub a6: usize,
pub a7: usize,
pub t0: usize,
pub t1: usize,
pub t2: usize,
pub t3: usize,
pub t4: usize,
pub t5: usize,
pub t6: usize,
pub t7: usize,
pub t8: usize,
pub u0: usize,
pub fp: usize,
pub s0: usize,
pub s1: usize,
pub s2: usize,
pub s3: usize,
pub s4: usize,
pub s5: usize,
pub s6: usize,
pub s7: usize,
pub s8: usize,
}
impl core::ops::Index<usize> for GeneralRegisters {
type Output = usize;
fn index(&self, index: usize) -> &usize {
match index {
0 => &self.zero,
1 => &self.ra,
2 => &self.tp,
3 => &self.sp,
4 => &self.a0,
5 => &self.a1,
6 => &self.a2,
7 => &self.a3,
8 => &self.a4,
9 => &self.a5,
10 => &self.a6,
11 => &self.a7,
12 => &self.t0,
13 => &self.t1,
14 => &self.t2,
15 => &self.t3,
16 => &self.t4,
17 => &self.t5,
18 => &self.t6,
19 => &self.t7,
20 => &self.t8,
21 => &self.u0,
22 => &self.fp,
23 => &self.s0,
24 => &self.s1,
25 => &self.s2,
26 => &self.s3,
27 => &self.s4,
28 => &self.s5,
29 => &self.s6,
30 => &self.s7,
31 => &self.s8,
_ => panic!("invalid general-purpose register index {index}"),
}
}
}
impl core::ops::IndexMut<usize> for GeneralRegisters {
fn index_mut(&mut self, index: usize) -> &mut usize {
match index {
0 => &mut self.zero,
1 => &mut self.ra,
2 => &mut self.tp,
3 => &mut self.sp,
4 => &mut self.a0,
5 => &mut self.a1,
6 => &mut self.a2,
7 => &mut self.a3,
8 => &mut self.a4,
9 => &mut self.a5,
10 => &mut self.a6,
11 => &mut self.a7,
12 => &mut self.t0,
13 => &mut self.t1,
14 => &mut self.t2,
15 => &mut self.t3,
16 => &mut self.t4,
17 => &mut self.t5,
18 => &mut self.t6,
19 => &mut self.t7,
20 => &mut self.t8,
21 => &mut self.u0,
22 => &mut self.fp,
23 => &mut self.s0,
24 => &mut self.s1,
25 => &mut self.s2,
26 => &mut self.s3,
27 => &mut self.s4,
28 => &mut self.s5,
29 => &mut self.s6,
30 => &mut self.s7,
31 => &mut self.s8,
_ => panic!("invalid general-purpose register index {index}"),
}
}
}