mirror of
https://github.com/LearningOS/rust-based-os-comp2022.git
synced 2026-07-16 11:32:56 +08:00
add ci contents
This commit is contained in:
211
ci-user/riscv/src/addr/gpax4.rs
Normal file
211
ci-user/riscv/src/addr/gpax4.rs
Normal file
@@ -0,0 +1,211 @@
|
||||
use super::*;
|
||||
use bit_field::BitField;
|
||||
use core::convert::TryInto;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct GPAddrSv32X4(u64);
|
||||
|
||||
impl Address for GPAddrSv32X4 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..34) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
GPAddrSv32X4((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualAddress for GPAddrSv32X4 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL2 for GPAddrSv32X4 {
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(22..34) as usize
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..22) as usize
|
||||
}
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize, offset: usize) -> Self {
|
||||
let p2_index = p2_index as u64;
|
||||
let p1_index = p1_index as u64;
|
||||
let offset = offset as u64;
|
||||
assert!(p2_index.get_bits(12..) == 0, "p2_index exceeding 12 bits");
|
||||
assert!(p1_index.get_bits(10..) == 0, "p1_index exceeding 10 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
GPAddrSv32X4::new_u64((p2_index << 22) | (p1_index << 12) | offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for GPAddrSv32X4 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(34..64) == 0,
|
||||
"Sv32x4 does not allow pa 34..64!=0"
|
||||
);
|
||||
GPAddrSv32X4(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct GPAddrSv39X4(u64);
|
||||
|
||||
impl Address for GPAddrSv39X4 {
|
||||
fn new(addr: usize) -> Self {
|
||||
GPAddrSv39X4(addr.try_into().unwrap())
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..41) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
GPAddrSv39X4((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualAddress for GPAddrSv39X4 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL3 for GPAddrSv39X4 {
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.get_bits(30..41) as usize
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(21..30) as usize
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..21) as usize
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self {
|
||||
let p3_index = p3_index as u64;
|
||||
let p2_index = p2_index as u64;
|
||||
let p1_index = p1_index as u64;
|
||||
let offset = offset as u64;
|
||||
assert!(p3_index.get_bits(11..) == 0, "p3_index exceeding 11 bits");
|
||||
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
|
||||
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
GPAddrSv39X4::new_u64(
|
||||
(p3_index << 12 << 9 << 9) | (p2_index << 12 << 9) | (p1_index << 12) | offset,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for GPAddrSv39X4 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(41..64) == 0,
|
||||
"Sv39x4 does not allow pa 41..64!=0"
|
||||
);
|
||||
GPAddrSv39X4(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct GPAddrSv48X4(u64);
|
||||
|
||||
impl Address for GPAddrSv48X4 {
|
||||
fn new(addr: usize) -> Self {
|
||||
GPAddrSv48X4(addr.try_into().unwrap())
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..50) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
GPAddrSv48X4((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl VirtualAddress for GPAddrSv48X4 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL4 for GPAddrSv48X4 {
|
||||
fn p4_index(&self) -> usize {
|
||||
self.0.get_bits(39..50) as usize
|
||||
}
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.get_bits(30..39) as usize
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(21..30) as usize
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..21) as usize
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self {
|
||||
let p4_index = p4_index as u64;
|
||||
let p3_index = p3_index as u64;
|
||||
let p2_index = p2_index as u64;
|
||||
let p1_index = p1_index as u64;
|
||||
let offset = offset as u64;
|
||||
assert!(p4_index.get_bits(11..) == 0, "p4_index exceeding 11 bits");
|
||||
assert!(p3_index.get_bits(9..) == 0, "p3_index exceeding 9 bits");
|
||||
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
|
||||
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
GPAddrSv48X4::new_u64(
|
||||
(p4_index << 12 << 9 << 9 << 9)
|
||||
| (p3_index << 12 << 9 << 9)
|
||||
| (p2_index << 12 << 9)
|
||||
| (p1_index << 12)
|
||||
| offset,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for GPAddrSv48X4 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(50..64) == 0,
|
||||
"Sv48x4 does not allow pa 50..64!=0"
|
||||
);
|
||||
GPAddrSv48X4(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
98
ci-user/riscv/src/addr/mod.rs
Normal file
98
ci-user/riscv/src/addr/mod.rs
Normal file
@@ -0,0 +1,98 @@
|
||||
pub trait Address: core::fmt::Debug + Copy + Clone + PartialEq + Eq + PartialOrd + Ord {
|
||||
fn new(addr: usize) -> Self;
|
||||
fn page_number(&self) -> usize;
|
||||
fn page_offset(&self) -> usize;
|
||||
fn to_4k_aligned(&self) -> Self;
|
||||
fn as_usize(&self) -> usize;
|
||||
}
|
||||
|
||||
pub trait VirtualAddress: Address {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T;
|
||||
}
|
||||
|
||||
pub trait AddressX32: Address {
|
||||
fn new_u32(addr: u32) -> Self;
|
||||
fn as_u32(&self) -> u32;
|
||||
}
|
||||
pub trait AddressX64: Address {
|
||||
fn new_u64(addr: u64) -> Self;
|
||||
fn as_u64(&self) -> u64;
|
||||
}
|
||||
|
||||
pub trait PhysicalAddress: AddressX64 {}
|
||||
|
||||
pub trait AddressL3: Address {
|
||||
fn p3_index(&self) -> usize;
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait AddressL4: Address {
|
||||
fn p4_index(&self) -> usize;
|
||||
fn p3_index(&self) -> usize;
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait AddressL2: Address {
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize, offset: usize) -> Self;
|
||||
}
|
||||
pub mod gpax4;
|
||||
pub mod page;
|
||||
pub mod sv32;
|
||||
pub mod sv39;
|
||||
pub mod sv48;
|
||||
|
||||
pub use self::gpax4::*;
|
||||
pub use self::page::*;
|
||||
pub use self::sv32::*;
|
||||
pub use self::sv39::*;
|
||||
pub use self::sv48::*;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! use_sv32 {
|
||||
() => {
|
||||
pub type VirtAddr = VirtAddrSv32;
|
||||
pub type PhysAddr = PhysAddrSv32;
|
||||
pub type Page = PageWith<VirtAddr>;
|
||||
pub type Frame = FrameWith<PhysAddr>;
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! use_sv39 {
|
||||
() => {
|
||||
pub type VirtAddr = VirtAddrSv39;
|
||||
pub type PhysAddr = PhysAddrSv39;
|
||||
pub type Page = PageWith<VirtAddr>;
|
||||
pub type Frame = FrameWith<PhysAddr>;
|
||||
};
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! use_sv48 {
|
||||
() => {
|
||||
pub type VirtAddr = VirtAddrSv48;
|
||||
pub type PhysAddr = PhysAddrSv48;
|
||||
pub type Page = PageWith<VirtAddr>;
|
||||
pub type Frame = FrameWith<PhysAddr>;
|
||||
};
|
||||
}
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
use_sv48!();
|
||||
|
||||
#[cfg(target_arch = "riscv32")]
|
||||
use_sv32!();
|
||||
174
ci-user/riscv/src/addr/page.rs
Normal file
174
ci-user/riscv/src/addr/page.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
pub use super::*;
|
||||
pub use bit_field::BitField;
|
||||
|
||||
pub trait PageWithL4 {
|
||||
fn p4_index(&self) -> usize;
|
||||
fn p3_index(&self) -> usize;
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
) -> Self;
|
||||
}
|
||||
|
||||
pub trait PageWithL3 {
|
||||
fn p3_index(&self) -> usize;
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(p3_index: usize, p2_index: usize, p1_index: usize) -> Self;
|
||||
}
|
||||
|
||||
pub trait PageWithL2 {
|
||||
fn p2_index(&self) -> usize;
|
||||
fn p1_index(&self) -> usize;
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PageWith<T: VirtualAddress>(T);
|
||||
|
||||
impl<T: AddressL4 + VirtualAddress> PageWithL4 for PageWith<T> {
|
||||
fn p4_index(&self) -> usize {
|
||||
self.0.p4_index()
|
||||
}
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.p3_index()
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
) -> Self {
|
||||
PageWith::of_addr(T::from_page_table_indices(
|
||||
p4_index, p3_index, p2_index, p1_index, 0,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl<T: AddressL3 + VirtualAddress> PageWithL3 for PageWith<T> {
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.p3_index()
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(p3_index: usize, p2_index: usize, p1_index: usize) -> Self {
|
||||
PageWith::of_addr(T::from_page_table_indices(p3_index, p2_index, p1_index, 0))
|
||||
}
|
||||
}
|
||||
impl<T: AddressL2 + VirtualAddress> PageWithL2 for PageWith<T> {
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize) -> Self {
|
||||
PageWith::of_addr(T::from_page_table_indices(p2_index, p1_index, 0))
|
||||
}
|
||||
}
|
||||
impl<T: VirtualAddress> PageWith<T> {
|
||||
pub fn of_addr(addr: T) -> Self {
|
||||
PageWith(addr.to_4k_aligned())
|
||||
}
|
||||
|
||||
pub fn of_vpn(vpn: usize) -> Self {
|
||||
PageWith(T::new(vpn << 12))
|
||||
}
|
||||
|
||||
pub fn start_address(&self) -> T {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
pub fn number(&self) -> usize {
|
||||
self.0.page_number()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FrameWith<T: PhysicalAddress>(T);
|
||||
|
||||
impl<T: AddressL4 + PhysicalAddress> PageWithL4 for FrameWith<T> {
|
||||
fn p4_index(&self) -> usize {
|
||||
self.0.p4_index()
|
||||
}
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.p3_index()
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
) -> Self {
|
||||
FrameWith::of_addr(T::from_page_table_indices(
|
||||
p4_index, p3_index, p2_index, p1_index, 0,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl<T: AddressL3 + PhysicalAddress> PageWithL3 for FrameWith<T> {
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.p3_index()
|
||||
}
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(p3_index: usize, p2_index: usize, p1_index: usize) -> Self {
|
||||
FrameWith::of_addr(T::from_page_table_indices(p3_index, p2_index, p1_index, 0))
|
||||
}
|
||||
}
|
||||
impl<T: AddressL2 + PhysicalAddress> PageWithL2 for FrameWith<T> {
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.p2_index()
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.p1_index()
|
||||
}
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize) -> Self {
|
||||
FrameWith::of_addr(T::from_page_table_indices(p2_index, p1_index, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PhysicalAddress> FrameWith<T> {
|
||||
pub fn of_addr(addr: T) -> Self {
|
||||
FrameWith(addr.to_4k_aligned())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn of_ppn(ppn: usize) -> Self {
|
||||
FrameWith(T::new_u64((ppn as u64) << 12))
|
||||
}
|
||||
|
||||
pub fn start_address(&self) -> T {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
pub fn number(&self) -> usize {
|
||||
self.0.page_number()
|
||||
}
|
||||
|
||||
pub unsafe fn as_kernel_mut<'a, 'b, U>(&'a self, linear_offset: u64) -> &'b mut U {
|
||||
&mut *(((self.0).as_u64() + linear_offset) as *mut U)
|
||||
}
|
||||
}
|
||||
91
ci-user/riscv/src/addr/sv32.rs
Normal file
91
ci-user/riscv/src/addr/sv32.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use super::*;
|
||||
use bit_field::BitField;
|
||||
use core::convert::TryInto;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct VirtAddrSv32(u32);
|
||||
impl Address for VirtAddrSv32 {
|
||||
fn new(addr: usize) -> Self {
|
||||
VirtAddrSv32(addr.try_into().unwrap())
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..32) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
VirtAddrSv32((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
impl VirtualAddress for VirtAddrSv32 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL2 for VirtAddrSv32 {
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(22..32) as usize
|
||||
}
|
||||
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..22) as usize
|
||||
}
|
||||
fn from_page_table_indices(p2_index: usize, p1_index: usize, offset: usize) -> Self {
|
||||
assert!(p2_index.get_bits(10..) == 0, "p2_index exceeding 10 bits");
|
||||
assert!(p1_index.get_bits(10..) == 0, "p1_index exceeding 10 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
VirtAddrSv32::new((p2_index << 22) | (p1_index << 12) | offset)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX32 for VirtAddrSv32 {
|
||||
fn new_u32(addr: u32) -> Self {
|
||||
VirtAddrSv32(addr)
|
||||
}
|
||||
fn as_u32(&self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PhysAddrSv32(u64);
|
||||
impl Address for PhysAddrSv32 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
assert!(
|
||||
self.0.get_bits(32..34) == 0,
|
||||
"Downcasting an Sv32 pa >4GB (32..34!=0) will cause address loss."
|
||||
);
|
||||
self.0 as usize
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..34) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
PhysAddrSv32((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for PhysAddrSv32 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(34..64) == 0,
|
||||
"Sv32 does not allow pa 34..64!=0"
|
||||
);
|
||||
PhysAddrSv32(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PhysicalAddress for PhysAddrSv32 {}
|
||||
115
ci-user/riscv/src/addr/sv39.rs
Normal file
115
ci-user/riscv/src/addr/sv39.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use super::*;
|
||||
use bit_field::BitField;
|
||||
use core::convert::TryInto;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct VirtAddrSv39(u64);
|
||||
|
||||
impl VirtualAddress for VirtAddrSv39 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
impl Address for VirtAddrSv39 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0.try_into().unwrap()
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..39).try_into().unwrap()
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
VirtAddrSv39((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL3 for VirtAddrSv39 {
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.get_bits(30..39) as usize
|
||||
}
|
||||
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(21..30) as usize
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..21) as usize
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self {
|
||||
let p3_index = p3_index as u64;
|
||||
let p2_index = p2_index as u64;
|
||||
let p1_index = p1_index as u64;
|
||||
let offset = offset as u64;
|
||||
assert!(p3_index.get_bits(11..) == 0, "p3_index exceeding 11 bits");
|
||||
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
|
||||
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
let mut addr =
|
||||
(p3_index << 12 << 9 << 9) | (p2_index << 12 << 9) | (p1_index << 12) | offset;
|
||||
if addr.get_bit(38) {
|
||||
addr.set_bits(39..64, (1 << (64 - 39)) - 1);
|
||||
} else {
|
||||
addr.set_bits(39..64, 0x0000);
|
||||
}
|
||||
VirtAddrSv39::new_u64(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PhysAddrSv39(u64);
|
||||
impl Address for PhysAddrSv39 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0.try_into().unwrap()
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..56) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
PhysAddrSv39((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for VirtAddrSv39 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
if addr.get_bit(38) {
|
||||
assert!(
|
||||
addr.get_bits(39..64) == (1 << (64 - 39)) - 1,
|
||||
"va 39..64 is not sext"
|
||||
);
|
||||
} else {
|
||||
assert!(addr.get_bits(39..64) == 0x0000, "va 39..64 is not sext");
|
||||
}
|
||||
VirtAddrSv39(addr as u64)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl AddressX64 for PhysAddrSv39 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(56..64) == 0,
|
||||
"Sv39 does not allow pa 56..64!=0"
|
||||
);
|
||||
PhysAddrSv39(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PhysicalAddress for PhysAddrSv39 {}
|
||||
125
ci-user/riscv/src/addr/sv48.rs
Normal file
125
ci-user/riscv/src/addr/sv48.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use super::*;
|
||||
use bit_field::BitField;
|
||||
use core::convert::TryInto;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct VirtAddrSv48(u64);
|
||||
|
||||
impl VirtualAddress for VirtAddrSv48 {
|
||||
unsafe fn as_mut<'a, 'b, T>(&'a self) -> &'b mut T {
|
||||
&mut *(self.0 as *mut T)
|
||||
}
|
||||
}
|
||||
impl Address for VirtAddrSv48 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0.try_into().unwrap()
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..48).try_into().unwrap()
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
VirtAddrSv48((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressL4 for VirtAddrSv48 {
|
||||
fn p4_index(&self) -> usize {
|
||||
self.0.get_bits(39..48) as usize
|
||||
}
|
||||
|
||||
fn p3_index(&self) -> usize {
|
||||
self.0.get_bits(30..39) as usize
|
||||
}
|
||||
|
||||
fn p2_index(&self) -> usize {
|
||||
self.0.get_bits(21..30) as usize
|
||||
}
|
||||
fn p1_index(&self) -> usize {
|
||||
self.0.get_bits(12..21) as usize
|
||||
}
|
||||
fn from_page_table_indices(
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
p1_index: usize,
|
||||
offset: usize,
|
||||
) -> Self {
|
||||
let p4_index = p4_index as u64;
|
||||
let p3_index = p3_index as u64;
|
||||
let p2_index = p2_index as u64;
|
||||
let p1_index = p1_index as u64;
|
||||
let offset = offset as u64;
|
||||
assert!(p4_index.get_bits(9..) == 0, "p4_index exceeding 9 bits");
|
||||
assert!(p3_index.get_bits(9..) == 0, "p3_index exceeding 9 bits");
|
||||
assert!(p2_index.get_bits(9..) == 0, "p2_index exceeding 9 bits");
|
||||
assert!(p1_index.get_bits(9..) == 0, "p1_index exceeding 9 bits");
|
||||
assert!(offset.get_bits(12..) == 0, "offset exceeding 12 bits");
|
||||
let mut addr = (p4_index << 12 << 9 << 9 << 9)
|
||||
| (p3_index << 12 << 9 << 9)
|
||||
| (p2_index << 12 << 9)
|
||||
| (p1_index << 12)
|
||||
| offset;
|
||||
if addr.get_bit(47) {
|
||||
addr.set_bits(48..64, (1 << (64 - 48)) - 1);
|
||||
} else {
|
||||
addr.set_bits(48..64, 0x0000);
|
||||
}
|
||||
VirtAddrSv48::new_u64(addr)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct PhysAddrSv48(u64);
|
||||
impl Address for PhysAddrSv48 {
|
||||
fn new(addr: usize) -> Self {
|
||||
Self::new_u64(addr as u64)
|
||||
}
|
||||
fn as_usize(&self) -> usize {
|
||||
self.0.try_into().unwrap()
|
||||
}
|
||||
fn page_number(&self) -> usize {
|
||||
self.0.get_bits(12..56) as usize
|
||||
}
|
||||
fn page_offset(&self) -> usize {
|
||||
self.0.get_bits(0..12) as usize
|
||||
}
|
||||
fn to_4k_aligned(&self) -> Self {
|
||||
PhysAddrSv48((self.0 >> 12) << 12)
|
||||
}
|
||||
}
|
||||
|
||||
impl AddressX64 for VirtAddrSv48 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
if addr.get_bit(47) {
|
||||
assert!(
|
||||
addr.get_bits(48..64) == (1 << (64 - 48)) - 1,
|
||||
"va 48..64 is not sext"
|
||||
);
|
||||
} else {
|
||||
assert!(addr.get_bits(48..64) == 0x0000, "va 48..64 is not sext");
|
||||
}
|
||||
VirtAddrSv48(addr as u64)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
impl AddressX64 for PhysAddrSv48 {
|
||||
fn new_u64(addr: u64) -> Self {
|
||||
assert!(
|
||||
addr.get_bits(56..64) == 0,
|
||||
"Sv48 does not allow pa 56..64!=0"
|
||||
);
|
||||
PhysAddrSv48(addr)
|
||||
}
|
||||
fn as_u64(&self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PhysicalAddress for PhysAddrSv48 {}
|
||||
152
ci-user/riscv/src/asm.rs
Normal file
152
ci-user/riscv/src/asm.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
//! Assembly instructions
|
||||
|
||||
macro_rules! instruction {
|
||||
($(#[$attr:meta])*, $fnname:ident, $asm:expr, $asm_fn:ident) => (
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $fnname() {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!($asm),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn();
|
||||
}
|
||||
|
||||
$asm_fn();
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
instruction!(
|
||||
/// `EBREAK` instruction wrapper
|
||||
///
|
||||
/// Generates a breakpoint exception.
|
||||
, ebreak, "ebreak", __ebreak);
|
||||
instruction!(
|
||||
/// `WFI` instruction wrapper
|
||||
///
|
||||
/// Provides a hint to the implementation that the current hart can be stalled until an interrupt might need servicing.
|
||||
/// The WFI instruction is just a hint, and a legal implementation is to implement WFI as a NOP.
|
||||
, wfi, "wfi", __wfi);
|
||||
instruction!(
|
||||
/// `SFENCE.VMA` instruction wrapper (all address spaces and page table levels)
|
||||
///
|
||||
/// Synchronizes updates to in-memory memory-management data structures with current execution.
|
||||
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
|
||||
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
|
||||
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
|
||||
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
|
||||
, sfence_vma_all, "sfence.vma", __sfence_vma_all);
|
||||
|
||||
/// `SFENCE.VMA` instruction wrapper
|
||||
///
|
||||
/// Synchronizes updates to in-memory memory-management data structures with current execution.
|
||||
/// Instruction execution causes implicit reads and writes to these data structures; however, these implicit references
|
||||
/// are ordinarily not ordered with respect to loads and stores in the instruction stream.
|
||||
/// Executing an `SFENCE.VMA` instruction guarantees that any stores in the instruction stream prior to the
|
||||
/// `SFENCE.VMA` are ordered before all implicit references subsequent to the `SFENCE.VMA`.
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn sfence_vma(asid: usize, addr: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("sfence.vma {0}, {1}", in(reg) asid, in(reg) addr),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn __sfence_vma(asid: usize, addr: usize);
|
||||
}
|
||||
|
||||
__sfence_vma(asid, addr);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
mod hypervisor_extension {
|
||||
// Generating instructions for Hypervisor extension.
|
||||
// There are two kinds of instructions: rs1/rs2 type and rs1/rd type.
|
||||
// Also special register handling is required before LLVM could generate inline assembly for extended instructions.
|
||||
macro_rules! instruction_hypervisor_extension {
|
||||
(RS1_RS2, $(#[$attr:meta])*, $fnname:ident, $asm:expr, $asm_fn:ident) => (
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn $fnname(rs1: usize, rs2: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
// Since LLVM does not recognize the two registers, we assume they are placed in a0 and a1, correspondingly.
|
||||
() => asm!($asm, in("x10") rs1, in("x11") rs2),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(rs1: usize, rs2: usize);
|
||||
}
|
||||
|
||||
$asm_fn(rs1, rs2);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
);
|
||||
(RS1_RD, $(#[$attr:meta])*, $fnname:ident, $asm:expr, $asm_fn:ident) => (
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
pub unsafe fn $fnname(rs1: usize)->usize {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => {
|
||||
let mut result : usize;
|
||||
asm!($asm, inlateout("x10") rs1 => result);
|
||||
return result;
|
||||
}
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(rs1: usize)->usize;
|
||||
}
|
||||
|
||||
return $asm_fn(rs1);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hfence_gvma,".word 1656029299",__hfence_gvma);
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hfence_vvma,".word 582287475",__hfence_vvma);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_b,".word 1610958195",__hlv_b);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_bu,".word 1612006771",__hlv_bu);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_h,".word 1678067059",__hlv_h);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_hu,".word 1679115635",__hlv_hu);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlvx_hu,".word 1681212787",__hlvx_hu);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_w,".word 1745175923",__hlv_w);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlvx_wu,".word 1748321651",__hlvx_wu);
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hsv_b,".word 1656045683",__hsv_b);
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hsv_h,".word 1723154547",__hsv_h);
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hsv_w,".word 1790263411",__hsv_w);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_wu,".word 1746224499",__hlv_wu);
|
||||
instruction_hypervisor_extension!(RS1_RD,,hlv_d,".word 1812284787",__hlv_d);
|
||||
instruction_hypervisor_extension!(RS1_RS2,,hsv_d,".word 1857372275",__hsv_d);
|
||||
}
|
||||
|
||||
pub use self::hypervisor_extension::*;
|
||||
58
ci-user/riscv/src/interrupt.rs
Normal file
58
ci-user/riscv/src/interrupt.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
//! Interrupts
|
||||
|
||||
// NOTE: Adapted from cortex-m/src/interrupt.rs
|
||||
pub use bare_metal::{CriticalSection, Mutex, Nr};
|
||||
use register::mstatus;
|
||||
|
||||
/// Disables all interrupts
|
||||
#[inline]
|
||||
pub unsafe fn disable() {
|
||||
match () {
|
||||
#[cfg(riscv)]
|
||||
() => mstatus::clear_mie(),
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enables all the interrupts
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - Do not call this function inside an `interrupt::free` critical section
|
||||
#[inline]
|
||||
pub unsafe fn enable() {
|
||||
match () {
|
||||
#[cfg(riscv)]
|
||||
() => mstatus::set_mie(),
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Execute closure `f` in an interrupt-free context.
|
||||
///
|
||||
/// This as also known as a "critical section".
|
||||
pub fn free<F, R>(f: F) -> R
|
||||
where
|
||||
F: FnOnce(&CriticalSection) -> R,
|
||||
{
|
||||
let mstatus = mstatus::read();
|
||||
|
||||
// disable interrupts
|
||||
unsafe {
|
||||
disable();
|
||||
}
|
||||
|
||||
let r = f(unsafe { &CriticalSection::new() });
|
||||
|
||||
// If the interrupts were active before our `disable` call, then re-enable
|
||||
// them. Otherwise, keep them disabled
|
||||
if mstatus.mie() {
|
||||
unsafe {
|
||||
enable();
|
||||
}
|
||||
}
|
||||
|
||||
r
|
||||
}
|
||||
27
ci-user/riscv/src/lib.rs
Normal file
27
ci-user/riscv/src/lib.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
//! Low level access to RISC-V processors
|
||||
//!
|
||||
//! # Minimum Supported Rust Version (MSRV)
|
||||
//!
|
||||
//! This crate is guaranteed to compile on stable Rust 1.42 and up. It *might*
|
||||
//! compile with older versions but that may change in any new patch release.
|
||||
//!
|
||||
//! # Features
|
||||
//!
|
||||
//! This crate provides:
|
||||
//!
|
||||
//! - Access to core registers like `mstatus` or `mcause`.
|
||||
//! - Interrupt manipulation mechanisms.
|
||||
//! - Wrappers around assembly instructions like `WFI`.
|
||||
|
||||
#![no_std]
|
||||
#![cfg_attr(feature = "inline-asm", feature(asm))]
|
||||
extern crate bare_metal;
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate bit_field;
|
||||
|
||||
pub mod addr;
|
||||
pub mod asm;
|
||||
pub mod interrupt;
|
||||
pub mod paging;
|
||||
pub mod register;
|
||||
40
ci-user/riscv/src/paging/frame_alloc.rs
Normal file
40
ci-user/riscv/src/paging/frame_alloc.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
//! Traits for abstracting away frame allocation and deallocation.
|
||||
|
||||
use addr::*;
|
||||
/// A trait for types that can allocate a frame of memory.
|
||||
pub trait FrameAllocatorFor<P: PhysicalAddress> {
|
||||
/// Allocate a frame of the appropriate size and return it if possible.
|
||||
fn alloc(&mut self) -> Option<FrameWith<P>>;
|
||||
}
|
||||
|
||||
/// A trait for types that can deallocate a frame of memory.
|
||||
pub trait FrameDeallocatorFor<P: PhysicalAddress> {
|
||||
/// Deallocate the given frame of memory.
|
||||
fn dealloc(&mut self, frame: FrameWith<P>);
|
||||
}
|
||||
|
||||
/// Polyfill for default use cases.
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
pub trait FrameAllocator {
|
||||
fn alloc(&mut self) -> Option<Frame>;
|
||||
}
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
pub trait FrameDeallocator {
|
||||
fn dealloc(&mut self, frame: Frame);
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
impl<T: FrameAllocator> FrameAllocatorFor<PhysAddr> for T {
|
||||
#[inline]
|
||||
fn alloc(&mut self) -> Option<Frame> {
|
||||
FrameAllocator::alloc(self)
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
|
||||
impl<T: FrameDeallocator> FrameDeallocatorFor<PhysAddr> for T {
|
||||
#[inline]
|
||||
fn dealloc(&mut self, frame: Frame) {
|
||||
FrameDeallocator::dealloc(self, frame)
|
||||
}
|
||||
}
|
||||
136
ci-user/riscv/src/paging/mapper.rs
Normal file
136
ci-user/riscv/src/paging/mapper.rs
Normal file
@@ -0,0 +1,136 @@
|
||||
use super::frame_alloc::*;
|
||||
use super::page_table::*;
|
||||
use addr::*;
|
||||
|
||||
pub trait Mapper {
|
||||
type P: PhysicalAddress;
|
||||
type V: VirtualAddress;
|
||||
type MapperFlush: MapperFlushable;
|
||||
type Entry: PTE;
|
||||
|
||||
/// Creates a new mapping in the page table.
|
||||
///
|
||||
/// This function might need additional physical frames to create new page tables. These
|
||||
/// frames are allocated from the `allocator` argument. At most three frames are required.
|
||||
fn map_to(
|
||||
&mut self,
|
||||
page: PageWith<Self::V>,
|
||||
frame: FrameWith<Self::P>,
|
||||
flags: PageTableFlags,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<Self::MapperFlush, MapToError>;
|
||||
|
||||
/// Removes a mapping from the page table and returns the frame that used to be mapped.
|
||||
///
|
||||
/// Note that no page tables or pages are deallocated.
|
||||
fn unmap(
|
||||
&mut self,
|
||||
page: PageWith<Self::V>,
|
||||
) -> Result<(FrameWith<Self::P>, Self::MapperFlush), UnmapError<<Self as Mapper>::P>>;
|
||||
|
||||
/// Get the reference of the specified `page` entry
|
||||
fn ref_entry(&mut self, page: PageWith<Self::V>) -> Result<&mut Self::Entry, FlagUpdateError>;
|
||||
|
||||
/// Updates the flags of an existing mapping.
|
||||
fn update_flags(
|
||||
&mut self,
|
||||
page: PageWith<Self::V>,
|
||||
flags: PageTableFlags,
|
||||
) -> Result<Self::MapperFlush, FlagUpdateError> {
|
||||
self.ref_entry(page).map(|e| {
|
||||
e.set(e.frame::<Self::P>(), flags);
|
||||
Self::MapperFlush::new(page)
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the frame that the specified page is mapped to.
|
||||
fn translate_page(&mut self, page: PageWith<Self::V>) -> Option<FrameWith<Self::P>> {
|
||||
match self.ref_entry(page) {
|
||||
Ok(e) => {
|
||||
if e.is_unused() {
|
||||
None
|
||||
} else {
|
||||
Some(e.frame())
|
||||
}
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps the given frame to the virtual page with the same address.
|
||||
fn identity_map(
|
||||
&mut self,
|
||||
frame: FrameWith<Self::P>,
|
||||
flags: PageTableFlags,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<Self::MapperFlush, MapToError> {
|
||||
let page = PageWith::of_addr(Self::V::new(frame.start_address().as_usize()));
|
||||
self.map_to(page, frame, flags, allocator)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MapperFlushable {
|
||||
/// Create a new flush promise
|
||||
fn new<T: VirtualAddress>(page: PageWith<T>) -> Self;
|
||||
/// Flush the page from the TLB to ensure that the newest mapping is used.
|
||||
fn flush(self);
|
||||
/// Don't flush the TLB and silence the “must be used” warning.
|
||||
fn ignore(self);
|
||||
}
|
||||
|
||||
#[must_use = "Page Table changes must be flushed or ignored."]
|
||||
pub struct MapperFlush(usize);
|
||||
|
||||
impl MapperFlushable for MapperFlush {
|
||||
fn new<T: VirtualAddress>(page: PageWith<T>) -> Self {
|
||||
MapperFlush(page.start_address().as_usize())
|
||||
}
|
||||
fn flush(self) {
|
||||
unsafe {
|
||||
crate::asm::sfence_vma(0, self.0);
|
||||
}
|
||||
}
|
||||
fn ignore(self) {}
|
||||
}
|
||||
|
||||
/// This error is returned from `map_to` and similar methods.
|
||||
#[derive(Debug)]
|
||||
pub enum MapToError {
|
||||
/// An additional frame was needed for the mapping process, but the frame allocator
|
||||
/// returned `None`.
|
||||
FrameAllocationFailed,
|
||||
/// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
|
||||
/// given page is part of an already mapped huge page.
|
||||
ParentEntryHugePage,
|
||||
/// The given page is already mapped to a physical frame.
|
||||
PageAlreadyMapped,
|
||||
}
|
||||
|
||||
/// An error indicating that an `unmap` call failed.
|
||||
#[derive(Debug)]
|
||||
pub enum UnmapError<P: PhysicalAddress> {
|
||||
/// An upper level page table entry has the `HUGE_PAGE` flag set, which means that the
|
||||
/// given page is part of a huge page and can't be freed individually.
|
||||
ParentEntryHugePage,
|
||||
/// The given page is not mapped to a physical frame.
|
||||
PageNotMapped,
|
||||
/// The page table entry for the given page points to an invalid physical address.
|
||||
InvalidFrameAddress(P),
|
||||
}
|
||||
|
||||
/// An error indicating that an `update_flags` call failed.
|
||||
#[derive(Debug)]
|
||||
pub enum FlagUpdateError {
|
||||
/// The given page is not mapped to a physical frame.
|
||||
PageNotMapped,
|
||||
}
|
||||
|
||||
pub trait MapperExt {
|
||||
type Page;
|
||||
type Frame;
|
||||
}
|
||||
|
||||
impl<T: Mapper> MapperExt for T {
|
||||
type Page = PageWith<<T as Mapper>::V>;
|
||||
type Frame = FrameWith<<T as Mapper>::P>;
|
||||
}
|
||||
13
ci-user/riscv/src/paging/mod.rs
Normal file
13
ci-user/riscv/src/paging/mod.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
mod frame_alloc;
|
||||
mod mapper;
|
||||
mod multi_level;
|
||||
mod multi_level_x4;
|
||||
mod page_table;
|
||||
mod page_table_x4;
|
||||
|
||||
pub use self::frame_alloc::*;
|
||||
pub use self::mapper::*;
|
||||
pub use self::multi_level::*;
|
||||
pub use self::multi_level_x4::*;
|
||||
pub use self::page_table::*;
|
||||
pub use self::page_table_x4::*;
|
||||
354
ci-user/riscv/src/paging/multi_level.rs
Normal file
354
ci-user/riscv/src/paging/multi_level.rs
Normal file
@@ -0,0 +1,354 @@
|
||||
use super::frame_alloc::*;
|
||||
use super::mapper::*;
|
||||
use super::page_table::{PageTableFlags as F, *};
|
||||
use crate::addr::*;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// This struct is a two level page table with `Mapper` trait implemented.
|
||||
pub struct Rv32PageTableWith<'a, V: VirtualAddress + AddressL2, FL: MapperFlushable> {
|
||||
root_table: &'a mut PageTableX32,
|
||||
linear_offset: u64, // VA = PA + linear_offset
|
||||
phantom: PhantomData<(V, FL)>,
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL2, FL: MapperFlushable> Rv32PageTableWith<'a, V, FL> {
|
||||
pub fn new(table: &'a mut PageTableX32, linear_offset: usize) -> Self {
|
||||
Rv32PageTableWith {
|
||||
root_table: table,
|
||||
linear_offset: linear_offset as u64,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_p1_if_not_exist(
|
||||
&mut self,
|
||||
p2_index: usize,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<&mut PageTableX32, MapToError> {
|
||||
if self.root_table[p2_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
self.root_table[p2_index].set(frame.clone(), F::VALID);
|
||||
let p1_table: &mut PageTableX32 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p1_table.zero();
|
||||
Ok(p1_table)
|
||||
} else {
|
||||
let frame = self.root_table[p2_index].frame::<PhysAddrSv32>();
|
||||
let p1_table: &mut PageTableX32 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(p1_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL2, FL: MapperFlushable> Mapper
|
||||
for Rv32PageTableWith<'a, V, FL>
|
||||
{
|
||||
type P = PhysAddrSv32;
|
||||
type V = V;
|
||||
type MapperFlush = FL;
|
||||
type Entry = PageTableEntryX32;
|
||||
fn map_to(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
frame: <Self as MapperExt>::Frame,
|
||||
flags: PageTableFlags,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<Self::MapperFlush, MapToError> {
|
||||
let p1_table = self.create_p1_if_not_exist(page.p2_index(), allocator)?;
|
||||
if !p1_table[page.p1_index()].is_unused() {
|
||||
return Err(MapToError::PageAlreadyMapped);
|
||||
}
|
||||
p1_table[page.p1_index()].set(frame, flags);
|
||||
Ok(Self::MapperFlush::new(page))
|
||||
}
|
||||
|
||||
fn unmap(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<(<Self as MapperExt>::Frame, Self::MapperFlush), UnmapError<<Self as Mapper>::P>>
|
||||
{
|
||||
if self.root_table[page.p2_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p1_frame = self.root_table[page.p2_index()].frame::<PhysAddrSv32>();
|
||||
let p1_table: &mut PageTableX32 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
let p1_entry = &mut p1_table[page.p1_index()];
|
||||
if !p1_entry.flags().contains(F::VALID) {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let frame = p1_entry.frame();
|
||||
p1_entry.set_unused();
|
||||
Ok((frame, Self::MapperFlush::new(page)))
|
||||
}
|
||||
|
||||
fn ref_entry(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<&mut PageTableEntryX32, FlagUpdateError> {
|
||||
if self.root_table[page.p2_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
let p1_frame = self.root_table[page.p2_index()].frame::<PhysAddrSv32>();
|
||||
let p1_table: &mut PageTableX32 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(&mut p1_table[page.p1_index()])
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct is a three level page table with `Mapper` trait implemented.
|
||||
|
||||
pub struct Rv39PageTableWith<'a, V: VirtualAddress + AddressL3, FL: MapperFlushable> {
|
||||
root_table: &'a mut PageTableX64,
|
||||
linear_offset: u64, // VA = PA + linear_offset
|
||||
phantom: PhantomData<(V, FL)>,
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL3, FL: MapperFlushable> Rv39PageTableWith<'a, V, FL> {
|
||||
pub fn new(table: &'a mut PageTableX64, linear_offset: usize) -> Self {
|
||||
Rv39PageTableWith {
|
||||
root_table: table,
|
||||
linear_offset: linear_offset as u64,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_p1_if_not_exist(
|
||||
&mut self,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<&mut PageTableX64, MapToError> {
|
||||
let p2_table = if self.root_table[p3_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
self.root_table[p3_index].set(frame.clone(), F::VALID);
|
||||
let p2_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p2_table.zero();
|
||||
p2_table
|
||||
} else {
|
||||
let frame = self.root_table[p3_index].frame::<PhysAddrSv39>();
|
||||
unsafe { frame.as_kernel_mut(self.linear_offset) }
|
||||
};
|
||||
if p2_table[p2_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
p2_table[p2_index].set(frame.clone(), F::VALID);
|
||||
let p1_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p1_table.zero();
|
||||
Ok(p1_table)
|
||||
} else {
|
||||
let frame = p2_table[p2_index].frame::<PhysAddrSv39>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(p1_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL3, FL: MapperFlushable> Mapper
|
||||
for Rv39PageTableWith<'a, V, FL>
|
||||
{
|
||||
type P = PhysAddrSv39;
|
||||
type V = V;
|
||||
type MapperFlush = FL;
|
||||
type Entry = PageTableEntryX64;
|
||||
fn map_to(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
frame: <Self as MapperExt>::Frame,
|
||||
flags: PageTableFlags,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<Self::MapperFlush, MapToError> {
|
||||
let p1_table = self.create_p1_if_not_exist(page.p3_index(), page.p2_index(), allocator)?;
|
||||
if !p1_table[page.p1_index()].is_unused() {
|
||||
return Err(MapToError::PageAlreadyMapped);
|
||||
}
|
||||
p1_table[page.p1_index()].set(frame, flags);
|
||||
Ok(Self::MapperFlush::new(page))
|
||||
}
|
||||
|
||||
fn unmap(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<(<Self as MapperExt>::Frame, Self::MapperFlush), UnmapError<<Self as Mapper>::P>>
|
||||
{
|
||||
if self.root_table[page.p3_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p2_frame = self.root_table[page.p3_index()].frame::<PhysAddrSv39>();
|
||||
let p2_table: &mut PageTableX64 = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
|
||||
|
||||
if p2_table[page.p2_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p1_frame = p2_table[page.p2_index()].frame::<PhysAddrSv39>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
let p1_entry = &mut p1_table[page.p1_index()];
|
||||
if !p1_entry.flags().contains(F::VALID) {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let frame = p1_entry.frame();
|
||||
p1_entry.set_unused();
|
||||
Ok((frame, Self::MapperFlush::new(page)))
|
||||
}
|
||||
|
||||
fn ref_entry(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<&mut PageTableEntryX64, FlagUpdateError> {
|
||||
if self.root_table[page.p3_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
let p2_frame = self.root_table[page.p3_index()].frame::<PhysAddrSv39>();
|
||||
let p2_table: &mut PageTableX64 = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
|
||||
if p2_table[page.p2_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
|
||||
let p1_frame = p2_table[page.p2_index()].frame::<PhysAddrSv39>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(&mut p1_table[page.p1_index()])
|
||||
}
|
||||
}
|
||||
|
||||
/// This struct is a four level page table with `Mapper` trait implemented.
|
||||
|
||||
pub struct Rv48PageTableWith<'a, V: VirtualAddress + AddressL4, FL: MapperFlushable> {
|
||||
root_table: &'a mut PageTableX64,
|
||||
linear_offset: u64, // VA = PA + linear_offset
|
||||
phantom: PhantomData<(V, FL)>,
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL4, FL: MapperFlushable> Rv48PageTableWith<'a, V, FL> {
|
||||
pub fn new(table: &'a mut PageTableX64, linear_offset: usize) -> Self {
|
||||
Rv48PageTableWith {
|
||||
root_table: table,
|
||||
linear_offset: linear_offset as u64,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn create_p1_if_not_exist(
|
||||
&mut self,
|
||||
p4_index: usize,
|
||||
p3_index: usize,
|
||||
p2_index: usize,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<&mut PageTableX64, MapToError> {
|
||||
let p3_table = if self.root_table[p4_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
self.root_table[p4_index].set(frame.clone(), F::VALID);
|
||||
let p3_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p3_table.zero();
|
||||
p3_table
|
||||
} else {
|
||||
let frame = self.root_table[p4_index].frame::<PhysAddrSv48>();
|
||||
unsafe { frame.as_kernel_mut(self.linear_offset) }
|
||||
};
|
||||
|
||||
let p2_table = if p3_table[p3_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
p3_table[p3_index].set(frame.clone(), F::VALID);
|
||||
let p2_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p2_table.zero();
|
||||
p2_table
|
||||
} else {
|
||||
let frame = p3_table[p3_index].frame::<PhysAddrSv48>();
|
||||
unsafe { frame.as_kernel_mut(self.linear_offset) }
|
||||
};
|
||||
|
||||
if p2_table[p2_index].is_unused() {
|
||||
let frame = allocator.alloc().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
p2_table[p2_index].set(frame.clone(), F::VALID);
|
||||
let p1_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
p1_table.zero();
|
||||
Ok(p1_table)
|
||||
} else {
|
||||
let frame = p2_table[p2_index].frame::<PhysAddrSv48>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(p1_table)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, V: VirtualAddress + AddressL4, FL: MapperFlushable> Mapper
|
||||
for Rv48PageTableWith<'a, V, FL>
|
||||
{
|
||||
type P = PhysAddrSv48;
|
||||
type V = V;
|
||||
type MapperFlush = FL;
|
||||
type Entry = PageTableEntryX64;
|
||||
fn map_to(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
frame: <Self as MapperExt>::Frame,
|
||||
flags: PageTableFlags,
|
||||
allocator: &mut impl FrameAllocatorFor<<Self as Mapper>::P>,
|
||||
) -> Result<Self::MapperFlush, MapToError> {
|
||||
let p1_table = self.create_p1_if_not_exist(
|
||||
page.p4_index(),
|
||||
page.p3_index(),
|
||||
page.p2_index(),
|
||||
allocator,
|
||||
)?;
|
||||
if !p1_table[page.p1_index()].is_unused() {
|
||||
return Err(MapToError::PageAlreadyMapped);
|
||||
}
|
||||
p1_table[page.p1_index()].set(frame, flags);
|
||||
Ok(Self::MapperFlush::new(page))
|
||||
}
|
||||
|
||||
fn unmap(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<(<Self as MapperExt>::Frame, Self::MapperFlush), UnmapError<<Self as Mapper>::P>>
|
||||
{
|
||||
if self.root_table[page.p4_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p3_frame = self.root_table[page.p4_index()].frame::<PhysAddrSv48>();
|
||||
let p3_table: &mut PageTableX64 = unsafe { p3_frame.as_kernel_mut(self.linear_offset) };
|
||||
|
||||
if p3_table[page.p3_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p2_frame = p3_table[page.p3_index()].frame::<PhysAddrSv48>();
|
||||
let p2_table: &mut PageTableX64 = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
|
||||
|
||||
if p2_table[page.p2_index()].is_unused() {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let p1_frame = p2_table[page.p2_index()].frame::<PhysAddrSv48>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
let p1_entry = &mut p1_table[page.p1_index()];
|
||||
if !p1_entry.flags().contains(F::VALID) {
|
||||
return Err(UnmapError::PageNotMapped);
|
||||
}
|
||||
let frame = p1_entry.frame::<PhysAddrSv48>();
|
||||
p1_entry.set_unused();
|
||||
Ok((frame, Self::MapperFlush::new(page)))
|
||||
}
|
||||
|
||||
fn ref_entry(
|
||||
&mut self,
|
||||
page: <Self as MapperExt>::Page,
|
||||
) -> Result<&mut PageTableEntryX64, FlagUpdateError> {
|
||||
if self.root_table[page.p4_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
let p3_frame = self.root_table[page.p4_index()].frame::<PhysAddrSv48>();
|
||||
let p3_table: &mut PageTableX64 = unsafe { p3_frame.as_kernel_mut(self.linear_offset) };
|
||||
|
||||
if p3_table[page.p3_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
let p2_frame = p3_table[page.p3_index()].frame::<PhysAddrSv48>();
|
||||
let p2_table: &mut PageTableX64 = unsafe { p2_frame.as_kernel_mut(self.linear_offset) };
|
||||
if p2_table[page.p2_index()].is_unused() {
|
||||
return Err(FlagUpdateError::PageNotMapped);
|
||||
}
|
||||
|
||||
let p1_frame = p2_table[page.p2_index()].frame::<PhysAddrSv48>();
|
||||
let p1_table: &mut PageTableX64 = unsafe { p1_frame.as_kernel_mut(self.linear_offset) };
|
||||
Ok(&mut p1_table[page.p1_index()])
|
||||
}
|
||||
}
|
||||
|
||||
pub type Rv32PageTable<'a> = Rv32PageTableWith<'a, VirtAddrSv32, MapperFlush>;
|
||||
pub type Rv39PageTable<'a> = Rv39PageTableWith<'a, VirtAddrSv39, MapperFlush>;
|
||||
pub type Rv48PageTable<'a> = Rv48PageTableWith<'a, VirtAddrSv48, MapperFlush>;
|
||||
42
ci-user/riscv/src/paging/multi_level_x4.rs
Normal file
42
ci-user/riscv/src/paging/multi_level_x4.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use crate::addr::*;
|
||||
use crate::asm::{hfence_gvma, hfence_vvma};
|
||||
use crate::paging::mapper::MapperFlushable;
|
||||
use crate::paging::multi_level::Rv32PageTableWith;
|
||||
use crate::paging::multi_level::{Rv39PageTableWith, Rv48PageTableWith};
|
||||
|
||||
#[must_use = "Guest Physical Address Table changes must be flushed or ignored."]
|
||||
pub struct MapperFlushGPA(usize);
|
||||
|
||||
impl MapperFlushable for MapperFlushGPA {
|
||||
fn new<T: VirtualAddress>(page: PageWith<T>) -> Self {
|
||||
MapperFlushGPA(page.start_address().as_usize())
|
||||
}
|
||||
fn flush(self) {
|
||||
unsafe {
|
||||
hfence_gvma(self.0, 0);
|
||||
}
|
||||
}
|
||||
fn ignore(self) {}
|
||||
}
|
||||
|
||||
#[must_use = "Guest Page Table changes must be flushed or ignored."]
|
||||
pub struct MapperFlushGPT(usize);
|
||||
|
||||
impl MapperFlushable for MapperFlushGPT {
|
||||
fn new<T: VirtualAddress>(page: PageWith<T>) -> Self {
|
||||
MapperFlushGPT(page.start_address().as_usize())
|
||||
}
|
||||
fn flush(self) {
|
||||
unsafe {
|
||||
hfence_vvma(self.0, 0);
|
||||
}
|
||||
}
|
||||
fn ignore(self) {}
|
||||
}
|
||||
|
||||
pub type Rv32PageTableX4<'a> = Rv32PageTableWith<'a, GPAddrSv32X4, MapperFlushGPA>;
|
||||
pub type Rv39PageTableX4<'a> = Rv39PageTableWith<'a, GPAddrSv39X4, MapperFlushGPA>;
|
||||
pub type Rv48PageTableX4<'a> = Rv48PageTableWith<'a, GPAddrSv48X4, MapperFlushGPA>;
|
||||
pub type Rv32PageTableGuest<'a> = Rv32PageTableWith<'a, VirtAddrSv32, MapperFlushGPT>;
|
||||
pub type Rv39PageTableGuest<'a> = Rv39PageTableWith<'a, VirtAddrSv39, MapperFlushGPT>;
|
||||
pub type Rv48PageTableGuest<'a> = Rv48PageTableWith<'a, VirtAddrSv48, MapperFlushGPT>;
|
||||
252
ci-user/riscv/src/paging/page_table.rs
Normal file
252
ci-user/riscv/src/paging/page_table.rs
Normal file
@@ -0,0 +1,252 @@
|
||||
use addr::*;
|
||||
use core::convert::TryInto;
|
||||
use core::fmt::{Debug, Error, Formatter};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Index, IndexMut};
|
||||
|
||||
pub type Entries32 = [PageTableEntryX32; RV32_ENTRY_COUNT];
|
||||
pub type Entries64 = [PageTableEntryX64; RV64_ENTRY_COUNT];
|
||||
|
||||
// To avoid const generic.
|
||||
pub trait PTEIterableSlice<T> {
|
||||
fn to_pte_slice<'a>(&'a self) -> &'a [T];
|
||||
fn to_pte_slice_mut<'a>(&'a mut self) -> &'a mut [T];
|
||||
fn pte_index(&self, index: usize) -> &T;
|
||||
fn pte_index_mut(&mut self, index: usize) -> &mut T;
|
||||
}
|
||||
|
||||
impl PTEIterableSlice<PageTableEntryX32> for Entries32 {
|
||||
fn to_pte_slice(&self) -> &[PageTableEntryX32] {
|
||||
self
|
||||
}
|
||||
fn to_pte_slice_mut(&mut self) -> &mut [PageTableEntryX32] {
|
||||
self
|
||||
}
|
||||
fn pte_index(&self, index: usize) -> &PageTableEntryX32 {
|
||||
&self[index]
|
||||
}
|
||||
fn pte_index_mut(&mut self, index: usize) -> &mut PageTableEntryX32 {
|
||||
&mut self[index]
|
||||
}
|
||||
}
|
||||
impl PTEIterableSlice<PageTableEntryX64> for Entries64 {
|
||||
fn to_pte_slice(&self) -> &[PageTableEntryX64] {
|
||||
self
|
||||
}
|
||||
fn to_pte_slice_mut(&mut self) -> &mut [PageTableEntryX64] {
|
||||
self
|
||||
}
|
||||
fn pte_index(&self, index: usize) -> &PageTableEntryX64 {
|
||||
&self[index]
|
||||
}
|
||||
fn pte_index_mut(&mut self, index: usize) -> &mut PageTableEntryX64 {
|
||||
&mut self[index]
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct PageTableWith<T: PTEIterableSlice<E>, E: PTE> {
|
||||
entries: T,
|
||||
phantom: PhantomData<E>,
|
||||
}
|
||||
|
||||
impl<T: PTEIterableSlice<E>, E: PTE> PageTableWith<T, E> {
|
||||
/// Clears all entries.
|
||||
pub fn zero(&mut self) {
|
||||
for entry in self.entries.to_pte_slice_mut().iter_mut() {
|
||||
entry.set_unused();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PTEIterableSlice<E>, E: PTE> Index<usize> for PageTableWith<T, E> {
|
||||
type Output = E;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
self.entries.pte_index(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PTEIterableSlice<E>, E: PTE> IndexMut<usize> for PageTableWith<T, E> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
self.entries.pte_index_mut(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PTEIterableSlice<E>, E: PTE + Debug> Debug for PageTableWith<T, E> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
f.debug_map()
|
||||
.entries(
|
||||
self.entries
|
||||
.to_pte_slice()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|p| !p.1.is_unused()),
|
||||
)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PTE {
|
||||
fn is_unused(&self) -> bool;
|
||||
fn set_unused(&mut self);
|
||||
fn flags(&self) -> PageTableFlags;
|
||||
fn ppn(&self) -> usize;
|
||||
fn ppn_u64(&self) -> u64;
|
||||
fn addr<T: PhysicalAddress>(&self) -> T;
|
||||
fn frame<T: PhysicalAddress>(&self) -> FrameWith<T>;
|
||||
fn set<T: PhysicalAddress>(&mut self, frame: FrameWith<T>, flags: PageTableFlags);
|
||||
fn flags_mut(&mut self) -> &mut PageTableFlags;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct PageTableEntryX32(u32);
|
||||
|
||||
impl PTE for PageTableEntryX32 {
|
||||
fn is_unused(&self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
fn set_unused(&mut self) {
|
||||
self.0 = 0;
|
||||
}
|
||||
fn flags(&self) -> PageTableFlags {
|
||||
PageTableFlags::from_bits_truncate(self.0 as usize)
|
||||
}
|
||||
fn ppn(&self) -> usize {
|
||||
self.ppn_u64().try_into().unwrap()
|
||||
}
|
||||
fn ppn_u64(&self) -> u64 {
|
||||
(self.0 >> 10) as u64
|
||||
}
|
||||
fn addr<T: PhysicalAddress>(&self) -> T {
|
||||
T::new_u64((self.ppn() as u64) << 12)
|
||||
}
|
||||
fn frame<T: PhysicalAddress>(&self) -> FrameWith<T> {
|
||||
FrameWith::of_addr(self.addr())
|
||||
}
|
||||
fn set<T: PhysicalAddress>(&mut self, frame: FrameWith<T>, mut flags: PageTableFlags) {
|
||||
// U540 will raise page fault when accessing page with A=0 or D=0
|
||||
flags |= EF::ACCESSED | EF::DIRTY;
|
||||
self.0 = ((frame.number() << 10) | flags.bits()) as u32;
|
||||
}
|
||||
fn flags_mut(&mut self) -> &mut PageTableFlags {
|
||||
unsafe { &mut *(self as *mut _ as *mut PageTableFlags) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PageTableEntryX32 {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
f.debug_struct("PageTableEntryX32")
|
||||
.field("frame", &self.frame::<PhysAddrSv32>())
|
||||
.field("flags", &self.flags())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct PageTableEntryX64(u64);
|
||||
|
||||
impl PTE for PageTableEntryX64 {
|
||||
fn is_unused(&self) -> bool {
|
||||
self.0 == 0
|
||||
}
|
||||
fn set_unused(&mut self) {
|
||||
self.0 = 0;
|
||||
}
|
||||
fn flags(&self) -> PageTableFlags {
|
||||
PageTableFlags::from_bits_truncate(self.0 as usize)
|
||||
}
|
||||
fn ppn(&self) -> usize {
|
||||
self.ppn_u64().try_into().unwrap()
|
||||
}
|
||||
fn ppn_u64(&self) -> u64 {
|
||||
(self.0 >> 10) as u64
|
||||
}
|
||||
fn addr<T: PhysicalAddress>(&self) -> T {
|
||||
T::new_u64((self.ppn() as u64) << 12)
|
||||
}
|
||||
fn frame<T: PhysicalAddress>(&self) -> FrameWith<T> {
|
||||
FrameWith::of_addr(self.addr())
|
||||
}
|
||||
fn set<T: PhysicalAddress>(&mut self, frame: FrameWith<T>, mut flags: PageTableFlags) {
|
||||
// U540 will raise page fault when accessing page with A=0 or D=0
|
||||
flags |= EF::ACCESSED | EF::DIRTY;
|
||||
self.0 = ((frame.number() << 10) | flags.bits()) as u64;
|
||||
}
|
||||
fn flags_mut(&mut self) -> &mut PageTableFlags {
|
||||
unsafe { &mut *(self as *mut _ as *mut PageTableFlags) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PageTableEntryX64Printer<'a, P: PhysicalAddress>(
|
||||
&'a PageTableEntryX64,
|
||||
PhantomData<*const P>,
|
||||
);
|
||||
|
||||
impl<'a, P: PhysicalAddress> Debug for PageTableEntryX64Printer<'a, P> {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
f.debug_struct("PageTableEntryX64")
|
||||
.field("frame", &self.0.frame::<P>())
|
||||
.field("flags", &self.0.flags())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl PageTableEntryX64 {
|
||||
pub fn debug_sv39<'a>(&'a self) -> PageTableEntryX64Printer<'a, PhysAddrSv39> {
|
||||
PageTableEntryX64Printer(self, PhantomData)
|
||||
}
|
||||
pub fn debug_sv48<'a>(&'a self) -> PageTableEntryX64Printer<'a, PhysAddrSv48> {
|
||||
PageTableEntryX64Printer(self, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for PageTableEntryX64 {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
|
||||
self.debug_sv48().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
pub const RV64_ENTRY_COUNT: usize = 1 << 9;
|
||||
pub const RV32_ENTRY_COUNT: usize = 1 << 10;
|
||||
#[cfg(riscv64)]
|
||||
pub const ENTRY_COUNT: usize = RV64_ENTRY_COUNT;
|
||||
#[cfg(riscv32)]
|
||||
pub const ENTRY_COUNT: usize = RV32_ENTRY_COUNT;
|
||||
#[cfg(riscv64)]
|
||||
pub type PageTableEntry = PageTableEntryX64;
|
||||
#[cfg(riscv32)]
|
||||
pub type PageTableEntry = PageTableEntryX32;
|
||||
#[cfg(riscv64)]
|
||||
pub type Entries = Entries64;
|
||||
#[cfg(riscv32)]
|
||||
pub type Entries = Entries32;
|
||||
#[cfg(not(any(riscv32, riscv64)))]
|
||||
pub const ENTRY_COUNT: usize = 1 << 0;
|
||||
#[cfg(not(any(riscv32, riscv64)))]
|
||||
pub type Entries = Entries64;
|
||||
|
||||
pub type PageTableX32 = PageTableWith<Entries32, PageTableEntryX32>;
|
||||
pub type PageTableX64 = PageTableWith<Entries64, PageTableEntryX64>;
|
||||
#[cfg(riscv64)]
|
||||
pub type PageTable = PageTableX64;
|
||||
#[cfg(riscv32)]
|
||||
pub type PageTable = PageTableX32;
|
||||
bitflags! {
|
||||
/// Possible flags for a page table entry.
|
||||
pub struct PageTableFlags: usize {
|
||||
const VALID = 1 << 0;
|
||||
const READABLE = 1 << 1;
|
||||
const WRITABLE = 1 << 2;
|
||||
const EXECUTABLE = 1 << 3;
|
||||
const USER = 1 << 4;
|
||||
const GLOBAL = 1 << 5;
|
||||
const ACCESSED = 1 << 6;
|
||||
const DIRTY = 1 << 7;
|
||||
const RESERVED1 = 1 << 8;
|
||||
const RESERVED2 = 1 << 9;
|
||||
}
|
||||
}
|
||||
|
||||
type EF = PageTableFlags;
|
||||
44
ci-user/riscv/src/paging/page_table_x4.rs
Normal file
44
ci-user/riscv/src/paging/page_table_x4.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
/// This file is for Hypervisor-related x4 page tables, including Sv32x4, Sv39x4 and Sv48x4.
|
||||
/// In fact, these x4 page tables are Phys-to-Phys page tables from GPAs to real PAs.
|
||||
use super::page_table::{
|
||||
PTEIterableSlice, PageTableEntryX32, PageTableEntryX64, PageTableWith, RV32_ENTRY_COUNT,
|
||||
RV64_ENTRY_COUNT,
|
||||
};
|
||||
|
||||
// The root page table is 4 times larger.
|
||||
pub const RV32_X4_ENTRY_COUNT: usize = RV32_ENTRY_COUNT << 2;
|
||||
pub const RV64_X4_ENTRY_COUNT: usize = RV64_ENTRY_COUNT << 2;
|
||||
|
||||
pub type Entries32X4 = [PageTableEntryX32; RV32_X4_ENTRY_COUNT];
|
||||
pub type Entries64X4 = [PageTableEntryX64; RV64_X4_ENTRY_COUNT];
|
||||
|
||||
impl PTEIterableSlice<PageTableEntryX32> for Entries32X4 {
|
||||
fn to_pte_slice(&self) -> &[PageTableEntryX32] {
|
||||
self
|
||||
}
|
||||
fn to_pte_slice_mut(&mut self) -> &mut [PageTableEntryX32] {
|
||||
self
|
||||
}
|
||||
fn pte_index(&self, index: usize) -> &PageTableEntryX32 {
|
||||
&self[index]
|
||||
}
|
||||
fn pte_index_mut(&mut self, index: usize) -> &mut PageTableEntryX32 {
|
||||
&mut self[index]
|
||||
}
|
||||
}
|
||||
impl PTEIterableSlice<PageTableEntryX64> for Entries64X4 {
|
||||
fn to_pte_slice(&self) -> &[PageTableEntryX64] {
|
||||
self
|
||||
}
|
||||
fn to_pte_slice_mut(&mut self) -> &mut [PageTableEntryX64] {
|
||||
self
|
||||
}
|
||||
fn pte_index(&self, index: usize) -> &PageTableEntryX64 {
|
||||
&self[index]
|
||||
}
|
||||
fn pte_index_mut(&mut self, index: usize) -> &mut PageTableEntryX64 {
|
||||
&mut self[index]
|
||||
}
|
||||
}
|
||||
pub type PageTable32X4 = PageTableWith<Entries32X4, PageTableEntryX32>;
|
||||
pub type PageTable64X4 = PageTableWith<Entries64X4, PageTableEntryX64>;
|
||||
134
ci-user/riscv/src/register/fcsr.rs
Normal file
134
ci-user/riscv/src/register/fcsr.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
//! Floating-point control and status register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// Floating-point control and status register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct FCSR {
|
||||
bits: u32,
|
||||
}
|
||||
|
||||
/// Accrued Exception Flags
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Flags(u32);
|
||||
|
||||
/// Accrued Exception Flag
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Flag {
|
||||
/// Inexact
|
||||
NX = 0b00001,
|
||||
|
||||
/// Underflow
|
||||
UF = 0b00010,
|
||||
|
||||
/// Overflow
|
||||
OF = 0b00100,
|
||||
|
||||
/// Divide by Zero
|
||||
DZ = 0b01000,
|
||||
|
||||
/// Invalid Operation
|
||||
NV = 0b10000,
|
||||
}
|
||||
|
||||
impl Flags {
|
||||
/// Inexact
|
||||
#[inline]
|
||||
pub fn nx(&self) -> bool {
|
||||
self.0.get_bit(0)
|
||||
}
|
||||
|
||||
/// Underflow
|
||||
#[inline]
|
||||
pub fn uf(&self) -> bool {
|
||||
self.0.get_bit(1)
|
||||
}
|
||||
|
||||
/// Overflow
|
||||
#[inline]
|
||||
pub fn of(&self) -> bool {
|
||||
self.0.get_bit(2)
|
||||
}
|
||||
|
||||
/// Divide by Zero
|
||||
#[inline]
|
||||
pub fn dz(&self) -> bool {
|
||||
self.0.get_bit(3)
|
||||
}
|
||||
|
||||
/// Invalid Operation
|
||||
#[inline]
|
||||
pub fn nv(&self) -> bool {
|
||||
self.0.get_bit(4)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounding Mode
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum RoundingMode {
|
||||
RoundToNearestEven = 0b000,
|
||||
RoundTowardsZero = 0b001,
|
||||
RoundDown = 0b010,
|
||||
RoundUp = 0b011,
|
||||
RoundToNearestMaxMagnitude = 0b100,
|
||||
Invalid = 0b111,
|
||||
}
|
||||
|
||||
impl FCSR {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> u32 {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Accrued Exception Flags
|
||||
#[inline]
|
||||
pub fn fflags(&self) -> Flags {
|
||||
Flags(self.bits.get_bits(0..5))
|
||||
}
|
||||
|
||||
/// Rounding Mode
|
||||
#[inline]
|
||||
pub fn frm(&self) -> RoundingMode {
|
||||
match self.bits.get_bits(5..8) {
|
||||
0b000 => RoundingMode::RoundToNearestEven,
|
||||
0b001 => RoundingMode::RoundTowardsZero,
|
||||
0b010 => RoundingMode::RoundDown,
|
||||
0b011 => RoundingMode::RoundUp,
|
||||
0b100 => RoundingMode::RoundToNearestMaxMagnitude,
|
||||
_ => RoundingMode::Invalid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0x003, __read_fcsr);
|
||||
write_csr!(0x003, __write_fcsr);
|
||||
clear!(0x003, __clear_fcsr);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> FCSR {
|
||||
FCSR {
|
||||
bits: unsafe { _read() as u32 },
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn set_rounding_mode(frm: RoundingMode) {
|
||||
let old = read();
|
||||
let bits = ((frm as u32) << 5) | old.fflags().0;
|
||||
_write(bits as usize);
|
||||
}
|
||||
|
||||
/// Resets `fflags` field bits
|
||||
#[inline]
|
||||
pub unsafe fn clear_flags() {
|
||||
let mask = 0b11111;
|
||||
_clear(mask);
|
||||
}
|
||||
|
||||
/// Resets `fflags` field bit
|
||||
#[inline]
|
||||
pub unsafe fn clear_flag(flag: Flag) {
|
||||
_clear(flag as usize);
|
||||
}
|
||||
82
ci-user/riscv/src/register/hpmcounterx.rs
Normal file
82
ci-user/riscv/src/register/hpmcounterx.rs
Normal file
@@ -0,0 +1,82 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Performance-monitoring counter
|
||||
pub mod $csrl {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
read_composite_csr!(super::$csrh::read(), read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! regh {
|
||||
(
|
||||
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Upper 32 bits of performance-monitoring counter (RV32I only)
|
||||
pub mod $csrh {
|
||||
read_csr_as_usize_rv32!($addr, $readf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0xC03, hpmcounter3, hpmcounter3h, __read_hpmcounter3, __write_hpmcounter3);
|
||||
reg!(0xC04, hpmcounter4, hpmcounter4h, __read_hpmcounter4, __write_hpmcounter4);
|
||||
reg!(0xC05, hpmcounter5, hpmcounter5h, __read_hpmcounter5, __write_hpmcounter5);
|
||||
reg!(0xC06, hpmcounter6, hpmcounter6h, __read_hpmcounter6, __write_hpmcounter6);
|
||||
reg!(0xC07, hpmcounter7, hpmcounter7h, __read_hpmcounter7, __write_hpmcounter7);
|
||||
reg!(0xC08, hpmcounter8, hpmcounter8h, __read_hpmcounter8, __write_hpmcounter8);
|
||||
reg!(0xC09, hpmcounter9, hpmcounter9h, __read_hpmcounter9, __write_hpmcounter9);
|
||||
reg!(0xC0A, hpmcounter10, hpmcounter10h, __read_hpmcounter10, __write_hpmcounter10);
|
||||
reg!(0xC0B, hpmcounter11, hpmcounter11h, __read_hpmcounter11, __write_hpmcounter11);
|
||||
reg!(0xC0C, hpmcounter12, hpmcounter12h, __read_hpmcounter12, __write_hpmcounter12);
|
||||
reg!(0xC0D, hpmcounter13, hpmcounter13h, __read_hpmcounter13, __write_hpmcounter13);
|
||||
reg!(0xC0E, hpmcounter14, hpmcounter14h, __read_hpmcounter14, __write_hpmcounter14);
|
||||
reg!(0xC0F, hpmcounter15, hpmcounter15h, __read_hpmcounter15, __write_hpmcounter15);
|
||||
reg!(0xC10, hpmcounter16, hpmcounter16h, __read_hpmcounter16, __write_hpmcounter16);
|
||||
reg!(0xC11, hpmcounter17, hpmcounter17h, __read_hpmcounter17, __write_hpmcounter17);
|
||||
reg!(0xC12, hpmcounter18, hpmcounter18h, __read_hpmcounter18, __write_hpmcounter18);
|
||||
reg!(0xC13, hpmcounter19, hpmcounter19h, __read_hpmcounter19, __write_hpmcounter19);
|
||||
reg!(0xC14, hpmcounter20, hpmcounter20h, __read_hpmcounter20, __write_hpmcounter20);
|
||||
reg!(0xC15, hpmcounter21, hpmcounter21h, __read_hpmcounter21, __write_hpmcounter21);
|
||||
reg!(0xC16, hpmcounter22, hpmcounter22h, __read_hpmcounter22, __write_hpmcounter22);
|
||||
reg!(0xC17, hpmcounter23, hpmcounter23h, __read_hpmcounter23, __write_hpmcounter23);
|
||||
reg!(0xC18, hpmcounter24, hpmcounter24h, __read_hpmcounter24, __write_hpmcounter24);
|
||||
reg!(0xC19, hpmcounter25, hpmcounter25h, __read_hpmcounter25, __write_hpmcounter25);
|
||||
reg!(0xC1A, hpmcounter26, hpmcounter26h, __read_hpmcounter26, __write_hpmcounter26);
|
||||
reg!(0xC1B, hpmcounter27, hpmcounter27h, __read_hpmcounter27, __write_hpmcounter27);
|
||||
reg!(0xC1C, hpmcounter28, hpmcounter28h, __read_hpmcounter28, __write_hpmcounter28);
|
||||
reg!(0xC1D, hpmcounter29, hpmcounter29h, __read_hpmcounter29, __write_hpmcounter29);
|
||||
reg!(0xC1E, hpmcounter30, hpmcounter30h, __read_hpmcounter30, __write_hpmcounter30);
|
||||
reg!(0xC1F, hpmcounter31, hpmcounter31h, __read_hpmcounter31, __write_hpmcounter31);
|
||||
|
||||
regh!(0xC83, hpmcounter3h, __read_hpmcounter3h, __write_hpmcounter3h);
|
||||
regh!(0xC84, hpmcounter4h, __read_hpmcounter4h, __write_hpmcounter4h);
|
||||
regh!(0xC85, hpmcounter5h, __read_hpmcounter5h, __write_hpmcounter5h);
|
||||
regh!(0xC86, hpmcounter6h, __read_hpmcounter6h, __write_hpmcounter6h);
|
||||
regh!(0xC87, hpmcounter7h, __read_hpmcounter7h, __write_hpmcounter7h);
|
||||
regh!(0xC88, hpmcounter8h, __read_hpmcounter8h, __write_hpmcounter8h);
|
||||
regh!(0xC89, hpmcounter9h, __read_hpmcounter9h, __write_hpmcounter9h);
|
||||
regh!(0xC8A, hpmcounter10h, __read_hpmcounter10h, __write_hpmcounter10h);
|
||||
regh!(0xC8B, hpmcounter11h, __read_hpmcounter11h, __write_hpmcounter11h);
|
||||
regh!(0xC8C, hpmcounter12h, __read_hpmcounter12h, __write_hpmcounter12h);
|
||||
regh!(0xC8D, hpmcounter13h, __read_hpmcounter13h, __write_hpmcounter13h);
|
||||
regh!(0xC8E, hpmcounter14h, __read_hpmcounter14h, __write_hpmcounter14h);
|
||||
regh!(0xC8F, hpmcounter15h, __read_hpmcounter15h, __write_hpmcounter15h);
|
||||
regh!(0xC90, hpmcounter16h, __read_hpmcounter16h, __write_hpmcounter16h);
|
||||
regh!(0xC91, hpmcounter17h, __read_hpmcounter17h, __write_hpmcounter17h);
|
||||
regh!(0xC92, hpmcounter18h, __read_hpmcounter18h, __write_hpmcounter18h);
|
||||
regh!(0xC93, hpmcounter19h, __read_hpmcounter19h, __write_hpmcounter19h);
|
||||
regh!(0xC94, hpmcounter20h, __read_hpmcounter20h, __write_hpmcounter20h);
|
||||
regh!(0xC95, hpmcounter21h, __read_hpmcounter21h, __write_hpmcounter21h);
|
||||
regh!(0xC96, hpmcounter22h, __read_hpmcounter22h, __write_hpmcounter22h);
|
||||
regh!(0xC97, hpmcounter23h, __read_hpmcounter23h, __write_hpmcounter23h);
|
||||
regh!(0xC98, hpmcounter24h, __read_hpmcounter24h, __write_hpmcounter24h);
|
||||
regh!(0xC99, hpmcounter25h, __read_hpmcounter25h, __write_hpmcounter25h);
|
||||
regh!(0xC9A, hpmcounter26h, __read_hpmcounter26h, __write_hpmcounter26h);
|
||||
regh!(0xC9B, hpmcounter27h, __read_hpmcounter27h, __write_hpmcounter27h);
|
||||
regh!(0xC9C, hpmcounter28h, __read_hpmcounter28h, __write_hpmcounter28h);
|
||||
regh!(0xC9D, hpmcounter29h, __read_hpmcounter29h, __write_hpmcounter29h);
|
||||
regh!(0xC9E, hpmcounter30h, __read_hpmcounter30h, __write_hpmcounter30h);
|
||||
regh!(0xC9F, hpmcounter31h, __read_hpmcounter31h, __write_hpmcounter31h);
|
||||
413
ci-user/riscv/src/register/hypervisorx64/hcounteren.rs
Normal file
413
ci-user/riscv/src/register/hypervisorx64/hcounteren.rs
Normal file
@@ -0,0 +1,413 @@
|
||||
//! Hypervisor Guest External Interrupt Pending Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hcounteren {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hcounteren {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hcounteren { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn cy(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_cy(&mut self, val: bool) {
|
||||
self.bits.set_bit(0, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn tm(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_tm(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn ir(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ir(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm3(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm3(&mut self, val: bool) {
|
||||
self.bits.set_bit(3, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm4(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm4(&mut self, val: bool) {
|
||||
self.bits.set_bit(4, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm5(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm5(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm6(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm6(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm7(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm7(&mut self, val: bool) {
|
||||
self.bits.set_bit(7, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm8(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm8(&mut self, val: bool) {
|
||||
self.bits.set_bit(8, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm9(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm9(&mut self, val: bool) {
|
||||
self.bits.set_bit(9, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm10(&self) -> bool {
|
||||
self.bits.get_bit(10)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm10(&mut self, val: bool) {
|
||||
self.bits.set_bit(10, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm11(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm11(&mut self, val: bool) {
|
||||
self.bits.set_bit(11, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm12(&self) -> bool {
|
||||
self.bits.get_bit(12)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm12(&mut self, val: bool) {
|
||||
self.bits.set_bit(12, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm13(&self) -> bool {
|
||||
self.bits.get_bit(13)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm13(&mut self, val: bool) {
|
||||
self.bits.set_bit(13, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm14(&self) -> bool {
|
||||
self.bits.get_bit(14)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm14(&mut self, val: bool) {
|
||||
self.bits.set_bit(14, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm15(&self) -> bool {
|
||||
self.bits.get_bit(15)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm15(&mut self, val: bool) {
|
||||
self.bits.set_bit(15, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm16(&self) -> bool {
|
||||
self.bits.get_bit(16)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm16(&mut self, val: bool) {
|
||||
self.bits.set_bit(16, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm17(&self) -> bool {
|
||||
self.bits.get_bit(17)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm17(&mut self, val: bool) {
|
||||
self.bits.set_bit(17, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm18(&self) -> bool {
|
||||
self.bits.get_bit(18)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm18(&mut self, val: bool) {
|
||||
self.bits.set_bit(18, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm19(&self) -> bool {
|
||||
self.bits.get_bit(19)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm19(&mut self, val: bool) {
|
||||
self.bits.set_bit(19, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm20(&self) -> bool {
|
||||
self.bits.get_bit(20)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm20(&mut self, val: bool) {
|
||||
self.bits.set_bit(20, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm21(&self) -> bool {
|
||||
self.bits.get_bit(21)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm21(&mut self, val: bool) {
|
||||
self.bits.set_bit(21, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm22(&self) -> bool {
|
||||
self.bits.get_bit(22)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm22(&mut self, val: bool) {
|
||||
self.bits.set_bit(22, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm23(&self) -> bool {
|
||||
self.bits.get_bit(23)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm23(&mut self, val: bool) {
|
||||
self.bits.set_bit(23, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm24(&self) -> bool {
|
||||
self.bits.get_bit(24)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm24(&mut self, val: bool) {
|
||||
self.bits.set_bit(24, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm25(&self) -> bool {
|
||||
self.bits.get_bit(25)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm25(&mut self, val: bool) {
|
||||
self.bits.set_bit(25, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm26(&self) -> bool {
|
||||
self.bits.get_bit(26)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm26(&mut self, val: bool) {
|
||||
self.bits.set_bit(26, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm27(&self) -> bool {
|
||||
self.bits.get_bit(27)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm27(&mut self, val: bool) {
|
||||
self.bits.set_bit(27, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm28(&self) -> bool {
|
||||
self.bits.get_bit(28)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm28(&mut self, val: bool) {
|
||||
self.bits.set_bit(28, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm29(&self) -> bool {
|
||||
self.bits.get_bit(29)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm29(&mut self, val: bool) {
|
||||
self.bits.set_bit(29, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm30(&self) -> bool {
|
||||
self.bits.get_bit(30)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm30(&mut self, val: bool) {
|
||||
self.bits.set_bit(30, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn hpm31(&self) -> bool {
|
||||
self.bits.get_bit(31)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hpm31(&mut self, val: bool) {
|
||||
self.bits.set_bit(31, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hcounteren, 3602, __read_hcounteren);
|
||||
write_csr!(3602, __write_hcounteren);
|
||||
set!(3602, __set_hcounteren);
|
||||
clear!(3602, __clear_hcounteren);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_cy, clear_cy, 1 << 0);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_tm, clear_tm, 1 << 1);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_ir, clear_ir, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm3, clear_hpm3, 1 << 3);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm4, clear_hpm4, 1 << 4);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm5, clear_hpm5, 1 << 5);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm6, clear_hpm6, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm7, clear_hpm7, 1 << 7);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm8, clear_hpm8, 1 << 8);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm9, clear_hpm9, 1 << 9);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm10, clear_hpm10, 1 << 10);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm11, clear_hpm11, 1 << 11);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm12, clear_hpm12, 1 << 12);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm13, clear_hpm13, 1 << 13);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm14, clear_hpm14, 1 << 14);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm15, clear_hpm15, 1 << 15);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm16, clear_hpm16, 1 << 16);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm17, clear_hpm17, 1 << 17);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm18, clear_hpm18, 1 << 18);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm19, clear_hpm19, 1 << 19);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm20, clear_hpm20, 1 << 20);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm21, clear_hpm21, 1 << 21);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm22, clear_hpm22, 1 << 22);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm23, clear_hpm23, 1 << 23);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm24, clear_hpm24, 1 << 24);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm25, clear_hpm25, 1 << 25);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm26, clear_hpm26, 1 << 26);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm27, clear_hpm27, 1 << 27);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm28, clear_hpm28, 1 << 28);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm29, clear_hpm29, 1 << 29);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm30, clear_hpm30, 1 << 30);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_hpm31, clear_hpm31, 1 << 31);
|
||||
|
||||
// enums
|
||||
173
ci-user/riscv/src/register/hypervisorx64/hedeleg.rs
Normal file
173
ci-user/riscv/src/register/hypervisorx64/hedeleg.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
//! Hypervisor Exception Delegation Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hedeleg {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hedeleg {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hedeleg { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Instruction address misaligned
|
||||
#[inline]
|
||||
pub fn ex0(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex0(&mut self, val: bool) {
|
||||
self.bits.set_bit(0, val);
|
||||
}
|
||||
/// Instruction access fault
|
||||
#[inline]
|
||||
pub fn ex1(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex1(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
/// Illegal instruction
|
||||
#[inline]
|
||||
pub fn ex2(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex2(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
/// Breakpoint
|
||||
#[inline]
|
||||
pub fn ex3(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex3(&mut self, val: bool) {
|
||||
self.bits.set_bit(3, val);
|
||||
}
|
||||
/// Load address misaligned
|
||||
#[inline]
|
||||
pub fn ex4(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex4(&mut self, val: bool) {
|
||||
self.bits.set_bit(4, val);
|
||||
}
|
||||
/// Load access fault
|
||||
#[inline]
|
||||
pub fn ex5(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex5(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
/// Store/AMO address misaligned
|
||||
#[inline]
|
||||
pub fn ex6(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex6(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// Store/AMO access fault
|
||||
#[inline]
|
||||
pub fn ex7(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex7(&mut self, val: bool) {
|
||||
self.bits.set_bit(7, val);
|
||||
}
|
||||
/// Environment call from U-mode or VU-mode
|
||||
#[inline]
|
||||
pub fn ex8(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex8(&mut self, val: bool) {
|
||||
self.bits.set_bit(8, val);
|
||||
}
|
||||
/// Instruction page fault
|
||||
#[inline]
|
||||
pub fn ex12(&self) -> bool {
|
||||
self.bits.get_bit(12)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex12(&mut self, val: bool) {
|
||||
self.bits.set_bit(12, val);
|
||||
}
|
||||
/// Load page fault
|
||||
#[inline]
|
||||
pub fn ex13(&self) -> bool {
|
||||
self.bits.get_bit(13)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex13(&mut self, val: bool) {
|
||||
self.bits.set_bit(13, val);
|
||||
}
|
||||
/// Store/AMO page fault
|
||||
#[inline]
|
||||
pub fn ex15(&self) -> bool {
|
||||
self.bits.get_bit(15)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ex15(&mut self, val: bool) {
|
||||
self.bits.set_bit(15, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hedeleg, 1538, __read_hedeleg);
|
||||
write_csr!(1538, __write_hedeleg);
|
||||
set!(1538, __set_hedeleg);
|
||||
clear!(1538, __clear_hedeleg);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Instruction address misaligned
|
||||
, set_ex0, clear_ex0, 1 << 0);
|
||||
set_clear_csr!(
|
||||
///Instruction access fault
|
||||
, set_ex1, clear_ex1, 1 << 1);
|
||||
set_clear_csr!(
|
||||
///Illegal instruction
|
||||
, set_ex2, clear_ex2, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///Breakpoint
|
||||
, set_ex3, clear_ex3, 1 << 3);
|
||||
set_clear_csr!(
|
||||
///Load address misaligned
|
||||
, set_ex4, clear_ex4, 1 << 4);
|
||||
set_clear_csr!(
|
||||
///Load access fault
|
||||
, set_ex5, clear_ex5, 1 << 5);
|
||||
set_clear_csr!(
|
||||
///Store/AMO address misaligned
|
||||
, set_ex6, clear_ex6, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///Store/AMO access fault
|
||||
, set_ex7, clear_ex7, 1 << 7);
|
||||
set_clear_csr!(
|
||||
///Environment call from U-mode or VU-mode
|
||||
, set_ex8, clear_ex8, 1 << 8);
|
||||
set_clear_csr!(
|
||||
///Instruction page fault
|
||||
, set_ex12, clear_ex12, 1 << 12);
|
||||
set_clear_csr!(
|
||||
///Load page fault
|
||||
, set_ex13, clear_ex13, 1 << 13);
|
||||
set_clear_csr!(
|
||||
///Store/AMO page fault
|
||||
, set_ex15, clear_ex15, 1 << 15);
|
||||
|
||||
// enums
|
||||
73
ci-user/riscv/src/register/hypervisorx64/hgatp.rs
Normal file
73
ci-user/riscv/src/register/hypervisorx64/hgatp.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
//! Hypervisor Guest Address Translation and Protection Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hgatp {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hgatp {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hgatp { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Guest address translation mode.
|
||||
#[inline]
|
||||
pub fn mode(&self) -> HgatpValues {
|
||||
HgatpValues::from(self.bits.get_bits(60..64))
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_mode(&mut self, val: HgatpValues) {
|
||||
self.bits.set_bits(60..64, val as usize);
|
||||
}
|
||||
/// Virtual machine ID.
|
||||
#[inline]
|
||||
pub fn vmid(&self) -> usize {
|
||||
self.bits.get_bits(44..58)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vmid(&mut self, val: usize) {
|
||||
self.bits.set_bits(44..58, val);
|
||||
}
|
||||
/// Physical Page Number for root page table.
|
||||
#[inline]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..44)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ppn(&mut self, val: usize) {
|
||||
self.bits.set_bits(0..44, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hgatp, 1664, __read_hgatp);
|
||||
write_csr!(1664, __write_hgatp);
|
||||
set!(1664, __set_hgatp);
|
||||
clear!(1664, __clear_hgatp);
|
||||
// bit ops
|
||||
|
||||
// enums
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(usize)]
|
||||
pub enum HgatpValues {
|
||||
Bare = 0,
|
||||
Sv39x4 = 8,
|
||||
Sv48x4 = 9,
|
||||
}
|
||||
impl HgatpValues {
|
||||
fn from(x: usize) -> Self {
|
||||
match x {
|
||||
0 => Self::Bare,
|
||||
8 => Self::Sv39x4,
|
||||
9 => Self::Sv48x4,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
3
ci-user/riscv/src/register/hypervisorx64/hgeie.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/hgeie.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Hypervisor Guest External Interrupt Enable Register.
|
||||
read_csr_as_usize!(1543, __read_hgeie);
|
||||
write_csr_as_usize!(1543, __write_hgeie);
|
||||
3
ci-user/riscv/src/register/hypervisorx64/hgeip.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/hgeip.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Hypervisor Guest External Interrupt Pending Register.
|
||||
read_csr_as_usize!(3602, __read_hgeip);
|
||||
write_csr_as_usize!(3602, __write_hgeip);
|
||||
65
ci-user/riscv/src/register/hypervisorx64/hideleg.rs
Normal file
65
ci-user/riscv/src/register/hypervisorx64/hideleg.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! Hypervisor Interrupt Delegation Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hideleg {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hideleg {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hideleg { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn sip(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sip(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn tip(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_tip(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn eip(&self) -> bool {
|
||||
self.bits.get_bit(10)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_eip(&mut self, val: bool) {
|
||||
self.bits.set_bit(10, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hideleg, 1539, __read_hideleg);
|
||||
write_csr!(1539, __write_hideleg);
|
||||
set!(1539, __set_hideleg);
|
||||
clear!(1539, __clear_hideleg);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_sip, clear_sip, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_tip, clear_tip, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_eip, clear_eip, 1 << 10);
|
||||
|
||||
// enums
|
||||
77
ci-user/riscv/src/register/hypervisorx64/hie.rs
Normal file
77
ci-user/riscv/src/register/hypervisorx64/hie.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
//! Hypervisor Interrupt Enable Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hie {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hie {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hie { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn vssie(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vssie(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn vstie(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vstie(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn vseie(&self) -> bool {
|
||||
self.bits.get_bit(10)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vseie(&mut self, val: bool) {
|
||||
self.bits.set_bit(10, val);
|
||||
}
|
||||
/// Guest External Interrupt
|
||||
#[inline]
|
||||
pub fn sgeie(&self) -> bool {
|
||||
self.bits.get_bit(12)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sgeie(&mut self, val: bool) {
|
||||
self.bits.set_bit(12, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hie, 1540, __read_hie);
|
||||
write_csr!(1540, __write_hie);
|
||||
set!(1540, __set_hie);
|
||||
clear!(1540, __clear_hie);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_vssie, clear_vssie, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_vstie, clear_vstie, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_vseie, clear_vseie, 1 << 10);
|
||||
set_clear_csr!(
|
||||
///Guest External Interrupt
|
||||
, set_sgeie, clear_sgeie, 1 << 12);
|
||||
|
||||
// enums
|
||||
77
ci-user/riscv/src/register/hypervisorx64/hip.rs
Normal file
77
ci-user/riscv/src/register/hypervisorx64/hip.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
//! Hypervisor Interrupt Pending Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hip {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hip {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hip { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn vssip(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vssip(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn vstip(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vstip(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn vseip(&self) -> bool {
|
||||
self.bits.get_bit(10)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vseip(&mut self, val: bool) {
|
||||
self.bits.set_bit(10, val);
|
||||
}
|
||||
/// Guest External Interrupt
|
||||
#[inline]
|
||||
pub fn sgeip(&self) -> bool {
|
||||
self.bits.get_bit(12)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sgeip(&mut self, val: bool) {
|
||||
self.bits.set_bit(12, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hip, 1604, __read_hip);
|
||||
write_csr!(1604, __write_hip);
|
||||
set!(1604, __set_hip);
|
||||
clear!(1604, __clear_hip);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_vssip, clear_vssip, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_vstip, clear_vstip, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_vseip, clear_vseip, 1 << 10);
|
||||
set_clear_csr!(
|
||||
///Guest External Interrupt
|
||||
, set_sgeip, clear_sgeip, 1 << 12);
|
||||
|
||||
// enums
|
||||
160
ci-user/riscv/src/register/hypervisorx64/hstatus.rs
Normal file
160
ci-user/riscv/src/register/hypervisorx64/hstatus.rs
Normal file
@@ -0,0 +1,160 @@
|
||||
//! HStatus Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hstatus {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hstatus {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hstatus { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Effective XLEN for VM.
|
||||
#[inline]
|
||||
pub fn vsxl(&self) -> VsxlValues {
|
||||
VsxlValues::from(self.bits.get_bits(32..34))
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vsxl(&mut self, val: VsxlValues) {
|
||||
self.bits.set_bits(32..34, val as usize);
|
||||
}
|
||||
/// TSR for VM.
|
||||
#[inline]
|
||||
pub fn vtsr(&self) -> bool {
|
||||
self.bits.get_bit(22)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vtsr(&mut self, val: bool) {
|
||||
self.bits.set_bit(22, val);
|
||||
}
|
||||
/// TW for VM.
|
||||
#[inline]
|
||||
pub fn vtw(&self) -> bool {
|
||||
self.bits.get_bit(21)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vtw(&mut self, val: bool) {
|
||||
self.bits.set_bit(21, val);
|
||||
}
|
||||
/// TVM for VM.
|
||||
#[inline]
|
||||
pub fn vtvm(&self) -> bool {
|
||||
self.bits.get_bit(20)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vtvm(&mut self, val: bool) {
|
||||
self.bits.set_bit(20, val);
|
||||
}
|
||||
/// Virtual Guest External Interrupt Number.
|
||||
#[inline]
|
||||
pub fn vgein(&self) -> usize {
|
||||
self.bits.get_bits(12..18)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vgein(&mut self, val: usize) {
|
||||
self.bits.set_bits(12..18, val);
|
||||
}
|
||||
/// Hypervisor User mode.
|
||||
#[inline]
|
||||
pub fn hu(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_hu(&mut self, val: bool) {
|
||||
self.bits.set_bit(9, val);
|
||||
}
|
||||
/// Supervisor Previous Virtual Privilege.
|
||||
#[inline]
|
||||
pub fn spvp(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_spvp(&mut self, val: bool) {
|
||||
self.bits.set_bit(8, val);
|
||||
}
|
||||
/// Supervisor Previous Virtualization mode.
|
||||
#[inline]
|
||||
pub fn spv(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_spv(&mut self, val: bool) {
|
||||
self.bits.set_bit(7, val);
|
||||
}
|
||||
/// Guest Virtual Address.
|
||||
#[inline]
|
||||
pub fn gva(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_gva(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// VS access endianness.
|
||||
#[inline]
|
||||
pub fn vsbe(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vsbe(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hstatus, 1536, __read_hstatus);
|
||||
write_csr!(1536, __write_hstatus);
|
||||
set!(1536, __set_hstatus);
|
||||
clear!(1536, __clear_hstatus);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///TSR for VM.
|
||||
, set_vtsr, clear_vtsr, 1 << 22);
|
||||
set_clear_csr!(
|
||||
///TW for VM.
|
||||
, set_vtw, clear_vtw, 1 << 21);
|
||||
set_clear_csr!(
|
||||
///TVM for VM.
|
||||
, set_vtvm, clear_vtvm, 1 << 20);
|
||||
set_clear_csr!(
|
||||
///Hypervisor User mode.
|
||||
, set_hu, clear_hu, 1 << 9);
|
||||
set_clear_csr!(
|
||||
///Supervisor Previous Virtual Privilege.
|
||||
, set_spvp, clear_spvp, 1 << 8);
|
||||
set_clear_csr!(
|
||||
///Supervisor Previous Virtualization mode.
|
||||
, set_spv, clear_spv, 1 << 7);
|
||||
set_clear_csr!(
|
||||
///Guest Virtual Address.
|
||||
, set_gva, clear_gva, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///VS access endianness.
|
||||
, set_vsbe, clear_vsbe, 1 << 5);
|
||||
|
||||
// enums
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(usize)]
|
||||
pub enum VsxlValues {
|
||||
Vsxl32 = 1,
|
||||
Vsxl64 = 2,
|
||||
Vsxl128 = 3,
|
||||
}
|
||||
impl VsxlValues {
|
||||
fn from(x: usize) -> Self {
|
||||
match x {
|
||||
1 => Self::Vsxl32,
|
||||
2 => Self::Vsxl64,
|
||||
3 => Self::Vsxl128,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
4
ci-user/riscv/src/register/hypervisorx64/htimedelta.rs
Normal file
4
ci-user/riscv/src/register/hypervisorx64/htimedelta.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! Hypervisor Time Delta Register.
|
||||
read_composite_csr!(super::htimedeltah::read(), read());
|
||||
read_csr_as_usize!(1541, __read_htimedelta);
|
||||
write_csr_as_usize!(1541, __write_htimedelta);
|
||||
3
ci-user/riscv/src/register/hypervisorx64/htimedeltah.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/htimedeltah.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Hypervisor Time Delta Register.
|
||||
read_csr_as_usize!(1557, __read_htimedeltah);
|
||||
write_csr_as_usize!(1557, __write_htimedeltah);
|
||||
3
ci-user/riscv/src/register/hypervisorx64/htinst.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/htinst.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Hypervisor Trap Instruction Register.
|
||||
read_csr_as_usize!(1610, __read_htinst);
|
||||
write_csr_as_usize!(1610, __write_htinst);
|
||||
3
ci-user/riscv/src/register/hypervisorx64/htval.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/htval.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Hypervisor Trap Value Register.
|
||||
read_csr_as_usize!(1603, __read_htval);
|
||||
write_csr_as_usize!(1603, __write_htval);
|
||||
65
ci-user/riscv/src/register/hypervisorx64/hvip.rs
Normal file
65
ci-user/riscv/src/register/hypervisorx64/hvip.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! Hypervisor Virtual Interrupt Pending Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Hvip {
|
||||
bits: usize,
|
||||
}
|
||||
impl Hvip {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Hvip { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn vssip(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vssip(&mut self, val: bool) {
|
||||
self.bits.set_bit(2, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn vstip(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vstip(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn vseip(&self) -> bool {
|
||||
self.bits.get_bit(10)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_vseip(&mut self, val: bool) {
|
||||
self.bits.set_bit(10, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Hvip, 1605, __read_hvip);
|
||||
write_csr!(1605, __write_hvip);
|
||||
set!(1605, __set_hvip);
|
||||
clear!(1605, __clear_hvip);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_vssip, clear_vssip, 1 << 2);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_vstip, clear_vstip, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_vseip, clear_vseip, 1 << 10);
|
||||
|
||||
// enums
|
||||
23
ci-user/riscv/src/register/hypervisorx64/mod.rs
Normal file
23
ci-user/riscv/src/register/hypervisorx64/mod.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
pub mod hcounteren;
|
||||
pub mod hedeleg;
|
||||
pub mod hgatp;
|
||||
pub mod hgeie;
|
||||
pub mod hgeip;
|
||||
pub mod hideleg;
|
||||
pub mod hie;
|
||||
pub mod hip;
|
||||
pub mod hstatus;
|
||||
pub mod htimedelta;
|
||||
pub mod htimedeltah;
|
||||
pub mod htinst;
|
||||
pub mod htval;
|
||||
pub mod hvip;
|
||||
pub mod vsatp;
|
||||
pub mod vscause;
|
||||
pub mod vsepc;
|
||||
pub mod vsie;
|
||||
pub mod vsip;
|
||||
pub mod vsscratch;
|
||||
pub mod vsstatus;
|
||||
pub mod vstval;
|
||||
pub mod vstvec;
|
||||
73
ci-user/riscv/src/register/hypervisorx64/vsatp.rs
Normal file
73
ci-user/riscv/src/register/hypervisorx64/vsatp.rs
Normal file
@@ -0,0 +1,73 @@
|
||||
//! Virtual Supervisor Guest Address Translation and Protection Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vsatp {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vsatp {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vsatp { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Guest address translation mode.
|
||||
#[inline]
|
||||
pub fn mode(&self) -> HgatpValues {
|
||||
HgatpValues::from(self.bits.get_bits(60..64))
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_mode(&mut self, val: HgatpValues) {
|
||||
self.bits.set_bits(60..64, val as usize);
|
||||
}
|
||||
/// ASID.
|
||||
#[inline]
|
||||
pub fn asid(&self) -> usize {
|
||||
self.bits.get_bits(44..60)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_asid(&mut self, val: usize) {
|
||||
self.bits.set_bits(44..60, val);
|
||||
}
|
||||
/// Physical Page Number for root page table.
|
||||
#[inline]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..44)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ppn(&mut self, val: usize) {
|
||||
self.bits.set_bits(0..44, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vsatp, 640, __read_vsatp);
|
||||
write_csr!(640, __write_vsatp);
|
||||
set!(640, __set_vsatp);
|
||||
clear!(640, __clear_vsatp);
|
||||
// bit ops
|
||||
|
||||
// enums
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(usize)]
|
||||
pub enum HgatpValues {
|
||||
Bare = 0,
|
||||
Sv39x4 = 8,
|
||||
Sv48x4 = 9,
|
||||
}
|
||||
impl HgatpValues {
|
||||
fn from(x: usize) -> Self {
|
||||
match x {
|
||||
0 => Self::Bare,
|
||||
8 => Self::Sv39x4,
|
||||
9 => Self::Sv48x4,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
50
ci-user/riscv/src/register/hypervisorx64/vscause.rs
Normal file
50
ci-user/riscv/src/register/hypervisorx64/vscause.rs
Normal file
@@ -0,0 +1,50 @@
|
||||
//! Virtual Supervisor Cause Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vscause {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vscause {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vscause { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Is cause interrupt.
|
||||
#[inline]
|
||||
pub fn interrupt(&self) -> bool {
|
||||
self.bits.get_bit(63)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_interrupt(&mut self, val: bool) {
|
||||
self.bits.set_bit(63, val);
|
||||
}
|
||||
/// Exception code
|
||||
#[inline]
|
||||
pub fn code(&self) -> usize {
|
||||
self.bits.get_bits(0..63)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_code(&mut self, val: usize) {
|
||||
self.bits.set_bits(0..63, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vscause, 578, __read_vscause);
|
||||
write_csr!(578, __write_vscause);
|
||||
set!(578, __set_vscause);
|
||||
clear!(578, __clear_vscause);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Is cause interrupt.
|
||||
, set_interrupt, clear_interrupt, 1 << 63);
|
||||
|
||||
// enums
|
||||
3
ci-user/riscv/src/register/hypervisorx64/vsepc.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/vsepc.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Virtual Supervisor Exception Program Counter.
|
||||
read_csr_as_usize!(577, __read_vsepc);
|
||||
write_csr_as_usize!(577, __write_vsepc);
|
||||
65
ci-user/riscv/src/register/hypervisorx64/vsie.rs
Normal file
65
ci-user/riscv/src/register/hypervisorx64/vsie.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! Virtual Supevisor Interrupt Enable Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vsie {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vsie {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vsie { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn ssie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ssie(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn stie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_stie(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn seie(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_seie(&mut self, val: bool) {
|
||||
self.bits.set_bit(9, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vsie, 516, __read_vsie);
|
||||
write_csr!(516, __write_vsie);
|
||||
set!(516, __set_vsie);
|
||||
clear!(516, __clear_vsie);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_ssie, clear_ssie, 1 << 1);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_stie, clear_stie, 1 << 5);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_seie, clear_seie, 1 << 9);
|
||||
|
||||
// enums
|
||||
65
ci-user/riscv/src/register/hypervisorx64/vsip.rs
Normal file
65
ci-user/riscv/src/register/hypervisorx64/vsip.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
//! Virtual Supevisor Interrupt Pending Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vsip {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vsip {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vsip { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
/// Software Interrupt
|
||||
#[inline]
|
||||
pub fn ssip(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ssip(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
/// Timer Interrupt
|
||||
#[inline]
|
||||
pub fn stip(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_stip(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
/// External Interrupt
|
||||
#[inline]
|
||||
pub fn seip(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_seip(&mut self, val: bool) {
|
||||
self.bits.set_bit(9, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vsip, 580, __read_vsip);
|
||||
write_csr!(580, __write_vsip);
|
||||
set!(580, __set_vsip);
|
||||
clear!(580, __clear_vsip);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///Software Interrupt
|
||||
, set_ssip, clear_ssip, 1 << 1);
|
||||
set_clear_csr!(
|
||||
///Timer Interrupt
|
||||
, set_stip, clear_stip, 1 << 5);
|
||||
set_clear_csr!(
|
||||
///External Interrupt
|
||||
, set_seip, clear_seip, 1 << 9);
|
||||
|
||||
// enums
|
||||
3
ci-user/riscv/src/register/hypervisorx64/vsscratch.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/vsscratch.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Virtual Supervisor Scratch Register.
|
||||
read_csr_as_usize!(576, __read_vsscratch);
|
||||
write_csr_as_usize!(576, __write_vsscratch);
|
||||
154
ci-user/riscv/src/register/hypervisorx64/vsstatus.rs
Normal file
154
ci-user/riscv/src/register/hypervisorx64/vsstatus.rs
Normal file
@@ -0,0 +1,154 @@
|
||||
//! Hypervisor Guest External Interrupt Pending Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vsstatus {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vsstatus {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vsstatus { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn sd(&self) -> usize {
|
||||
self.bits.get_bits(60..64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sd(&mut self, val: usize) {
|
||||
self.bits.set_bits(60..64, val);
|
||||
}
|
||||
/// Effective User XLEN.
|
||||
#[inline]
|
||||
pub fn uxl(&self) -> UxlValues {
|
||||
UxlValues::from(self.bits.get_bits(32..34))
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_uxl(&mut self, val: UxlValues) {
|
||||
self.bits.set_bits(32..34, val as usize);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn mxr(&self) -> bool {
|
||||
self.bits.get_bit(19)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_mxr(&mut self, val: bool) {
|
||||
self.bits.set_bit(19, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn sum(&self) -> bool {
|
||||
self.bits.get_bit(18)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sum(&mut self, val: bool) {
|
||||
self.bits.set_bit(18, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn xs(&self) -> usize {
|
||||
self.bits.get_bits(15..17)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_xs(&mut self, val: usize) {
|
||||
self.bits.set_bits(15..17, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn fs(&self) -> usize {
|
||||
self.bits.get_bits(13..15)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_fs(&mut self, val: usize) {
|
||||
self.bits.set_bits(13..15, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn spp(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_spp(&mut self, val: bool) {
|
||||
self.bits.set_bit(8, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn ube(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_ube(&mut self, val: bool) {
|
||||
self.bits.set_bit(6, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn spie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_spie(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn sie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_sie(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vsstatus, 512, __read_vsstatus);
|
||||
write_csr!(512, __write_vsstatus);
|
||||
set!(512, __set_vsstatus);
|
||||
clear!(512, __clear_vsstatus);
|
||||
// bit ops
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_mxr, clear_mxr, 1 << 19);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_sum, clear_sum, 1 << 18);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_spp, clear_spp, 1 << 8);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_ube, clear_ube, 1 << 6);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_spie, clear_spie, 1 << 5);
|
||||
set_clear_csr!(
|
||||
///
|
||||
, set_sie, clear_sie, 1 << 1);
|
||||
|
||||
// enums
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[repr(usize)]
|
||||
pub enum UxlValues {
|
||||
Uxl32 = 1,
|
||||
Uxl64 = 2,
|
||||
Uxl128 = 3,
|
||||
}
|
||||
impl UxlValues {
|
||||
fn from(x: usize) -> Self {
|
||||
match x {
|
||||
1 => Self::Uxl32,
|
||||
2 => Self::Uxl64,
|
||||
3 => Self::Uxl128,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
3
ci-user/riscv/src/register/hypervisorx64/vstval.rs
Normal file
3
ci-user/riscv/src/register/hypervisorx64/vstval.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! Virtual Supervisor Trap Value Register.
|
||||
read_csr_as_usize!(579, __read_vstval);
|
||||
write_csr_as_usize!(579, __write_vstval);
|
||||
47
ci-user/riscv/src/register/hypervisorx64/vstvec.rs
Normal file
47
ci-user/riscv/src/register/hypervisorx64/vstvec.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! Virtual Supervisor Trap Vector Base Address Register.
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct Vstvec {
|
||||
bits: usize,
|
||||
}
|
||||
impl Vstvec {
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
return self.bits;
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_bits(x: usize) -> Self {
|
||||
return Vstvec { bits: x };
|
||||
}
|
||||
#[inline]
|
||||
pub unsafe fn write(&self) {
|
||||
_write(self.bits);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn base(&self) -> usize {
|
||||
self.bits.get_bits(2..64)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_base(&mut self, val: usize) {
|
||||
self.bits.set_bits(2..64, val);
|
||||
}
|
||||
///
|
||||
#[inline]
|
||||
pub fn mode(&self) -> usize {
|
||||
self.bits.get_bits(0..2)
|
||||
}
|
||||
#[inline]
|
||||
pub fn set_mode(&mut self, val: usize) {
|
||||
self.bits.set_bits(0..2, val);
|
||||
}
|
||||
}
|
||||
read_csr_as!(Vstvec, 517, __read_vstvec);
|
||||
write_csr!(517, __write_vstvec);
|
||||
set!(517, __set_vstvec);
|
||||
clear!(517, __clear_vstvec);
|
||||
// bit ops
|
||||
|
||||
// enums
|
||||
272
ci-user/riscv/src/register/macros.rs
Normal file
272
ci-user/riscv/src/register/macros.rs
Normal file
@@ -0,0 +1,272 @@
|
||||
macro_rules! read_csr {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => {
|
||||
let r: usize;
|
||||
asm!("csrrs {0}, {1}, x0", out(reg) r, const $csr_number);
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn() -> usize;
|
||||
}
|
||||
|
||||
$asm_fn()
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
unsafe fn _read() -> usize {
|
||||
match () {
|
||||
#[cfg(all(riscv32, feature = "inline-asm"))]
|
||||
() => {
|
||||
let r: usize;
|
||||
asm!("csrrs {0}, {1}, x0", out(reg) r, const $csr_number);
|
||||
r
|
||||
}
|
||||
|
||||
#[cfg(all(riscv32, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn() -> usize;
|
||||
}
|
||||
|
||||
$asm_fn()
|
||||
}
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as {
|
||||
($register:ident, $csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> $register {
|
||||
$register {
|
||||
bits: unsafe { _read() },
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as_usize {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
unsafe { _read() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! read_csr_as_usize_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
read_csr_rv32!($csr_number, $asm_fn);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> usize {
|
||||
unsafe { _read() }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _write(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrw x0, {1}, {0}", in(reg) bits, const $csr_number),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _write(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv32, feature = "inline-asm"))]
|
||||
() => asm!("csrrw x0, {1}, {0}", in(reg) bits, const $csr_number),
|
||||
|
||||
#[cfg(all(riscv32, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_as_usize {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
write_csr!($csr_number, $asm_fn);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe { _write(bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! write_csr_as_usize_rv32 {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
write_csr_rv32!($csr_number, $asm_fn);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub fn write(bits: usize) {
|
||||
unsafe { _write(bits) }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Set the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _set(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrs x0, {1}, {0}", in(reg) bits, const $csr_number),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! clear {
|
||||
($csr_number:expr, $asm_fn: ident) => {
|
||||
/// Clear the CSR
|
||||
#[inline]
|
||||
#[allow(unused_variables)]
|
||||
unsafe fn _clear(bits: usize) {
|
||||
match () {
|
||||
#[cfg(all(riscv, feature = "inline-asm"))]
|
||||
() => asm!("csrrc x0, {1}, {0}", in(reg) bits, const $csr_number),
|
||||
|
||||
#[cfg(all(riscv, not(feature = "inline-asm")))]
|
||||
() => {
|
||||
extern "C" {
|
||||
fn $asm_fn(bits: usize);
|
||||
}
|
||||
|
||||
$asm_fn(bits);
|
||||
}
|
||||
|
||||
#[cfg(not(riscv))]
|
||||
() => unimplemented!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_csr {
|
||||
($(#[$attr:meta])*, $set_field:ident, $e:expr) => {
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $set_field() {
|
||||
_set($e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! clear_csr {
|
||||
($(#[$attr:meta])*, $clear_field:ident, $e:expr) => {
|
||||
$(#[$attr])*
|
||||
#[inline]
|
||||
pub unsafe fn $clear_field() {
|
||||
_clear($e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! set_clear_csr {
|
||||
($(#[$attr:meta])*, $set_field:ident, $clear_field:ident, $e:expr) => {
|
||||
set_csr!($(#[$attr])*, $set_field, $e);
|
||||
clear_csr!($(#[$attr])*, $clear_field, $e);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! read_composite_csr {
|
||||
($hi:expr, $lo:expr) => {
|
||||
/// Reads the CSR as a 64-bit value
|
||||
#[inline]
|
||||
pub fn read64() -> u64 {
|
||||
match () {
|
||||
#[cfg(riscv32)]
|
||||
() => loop {
|
||||
let hi = $hi;
|
||||
let lo = $lo;
|
||||
if hi == $hi {
|
||||
return ((hi as u64) << 32) | lo as u64;
|
||||
}
|
||||
},
|
||||
|
||||
#[cfg(not(riscv32))]
|
||||
() => $lo as u64,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
27
ci-user/riscv/src/register/marchid.rs
Normal file
27
ci-user/riscv/src/register/marchid.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
//! marchid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// marchid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Marchid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Marchid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_marchid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Marchid> {
|
||||
let r = unsafe { _read() };
|
||||
// When marchid is hardwired to zero it means that the marchid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Marchid { bits })
|
||||
}
|
||||
138
ci-user/riscv/src/register/mcause.rs
Normal file
138
ci-user/riscv/src/register/mcause.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
//! mcause register
|
||||
|
||||
/// mcause register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mcause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Trap {
|
||||
Interrupt(Interrupt),
|
||||
Exception(Exception),
|
||||
}
|
||||
|
||||
/// Interrupt
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Interrupt {
|
||||
UserSoft,
|
||||
SupervisorSoft,
|
||||
MachineSoft,
|
||||
UserTimer,
|
||||
SupervisorTimer,
|
||||
MachineTimer,
|
||||
UserExternal,
|
||||
SupervisorExternal,
|
||||
MachineExternal,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Exception
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum Exception {
|
||||
InstructionMisaligned,
|
||||
InstructionFault,
|
||||
IllegalInstruction,
|
||||
Breakpoint,
|
||||
LoadMisaligned,
|
||||
LoadFault,
|
||||
StoreMisaligned,
|
||||
StoreFault,
|
||||
UserEnvCall,
|
||||
SupervisorEnvCall,
|
||||
MachineEnvCall,
|
||||
InstructionPageFault,
|
||||
LoadPageFault,
|
||||
StorePageFault,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Interrupt::UserSoft,
|
||||
1 => Interrupt::SupervisorSoft,
|
||||
3 => Interrupt::MachineSoft,
|
||||
4 => Interrupt::UserTimer,
|
||||
5 => Interrupt::SupervisorTimer,
|
||||
7 => Interrupt::MachineTimer,
|
||||
8 => Interrupt::UserExternal,
|
||||
9 => Interrupt::SupervisorExternal,
|
||||
11 => Interrupt::MachineExternal,
|
||||
_ => Interrupt::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Exception {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Exception::InstructionMisaligned,
|
||||
1 => Exception::InstructionFault,
|
||||
2 => Exception::IllegalInstruction,
|
||||
3 => Exception::Breakpoint,
|
||||
4 => Exception::LoadMisaligned,
|
||||
5 => Exception::LoadFault,
|
||||
6 => Exception::StoreMisaligned,
|
||||
7 => Exception::StoreFault,
|
||||
8 => Exception::UserEnvCall,
|
||||
9 => Exception::SupervisorEnvCall,
|
||||
11 => Exception::MachineEnvCall,
|
||||
12 => Exception::InstructionPageFault,
|
||||
13 => Exception::LoadPageFault,
|
||||
15 => Exception::StorePageFault,
|
||||
_ => Exception::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Mcause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the code field
|
||||
pub fn code(&self) -> usize {
|
||||
match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => self.bits & !(1 << 31),
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => self.bits & !(1 << 63),
|
||||
#[cfg(target_pointer_width = "128")]
|
||||
() => self.bits & !(1 << 127),
|
||||
}
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[inline]
|
||||
pub fn cause(&self) -> Trap {
|
||||
if self.is_interrupt() {
|
||||
Trap::Interrupt(Interrupt::from(self.code()))
|
||||
} else {
|
||||
Trap::Exception(Exception::from(self.code()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an interrupt.
|
||||
#[inline]
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => self.bits & (1 << 31) == 1 << 31,
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => self.bits & (1 << 63) == 1 << 63,
|
||||
#[cfg(target_pointer_width = "128")]
|
||||
() => self.bits & (1 << 127) == 1 << 127,
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an exception.
|
||||
#[inline]
|
||||
pub fn is_exception(&self) -> bool {
|
||||
!self.is_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mcause, 0x342, __read_mcause);
|
||||
4
ci-user/riscv/src/register/mcycle.rs
Normal file
4
ci-user/riscv/src/register/mcycle.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! mcycle register
|
||||
|
||||
read_csr_as_usize!(0xB00, __read_mcycle);
|
||||
read_composite_csr!(super::mcycleh::read(), read());
|
||||
3
ci-user/riscv/src/register/mcycleh.rs
Normal file
3
ci-user/riscv/src/register/mcycleh.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! mcycleh register
|
||||
|
||||
read_csr_as_usize_rv32!(0xB80, __read_mcycleh);
|
||||
148
ci-user/riscv/src/register/medeleg.rs
Normal file
148
ci-user/riscv/src/register/medeleg.rs
Normal file
@@ -0,0 +1,148 @@
|
||||
//! medeleg register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// medeleg register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Medeleg {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Medeleg {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Instruction Address Misaligned Delegate
|
||||
#[inline]
|
||||
pub fn instruction_misaligned(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Instruction Access Fault Delegate
|
||||
#[inline]
|
||||
pub fn instruction_fault(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Illegal Instruction Delegate
|
||||
#[inline]
|
||||
pub fn illegal_instruction(&self) -> bool {
|
||||
self.bits.get_bit(2)
|
||||
}
|
||||
|
||||
/// Breakpoint Delegate
|
||||
#[inline]
|
||||
pub fn breakpoint(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// Load Address Misaligned Delegate
|
||||
#[inline]
|
||||
pub fn load_misaligned(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Load Access Fault Delegate
|
||||
#[inline]
|
||||
pub fn load_fault(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Store/AMO Address Misaligned Delegate
|
||||
#[inline]
|
||||
pub fn store_misaligned(&self) -> bool {
|
||||
self.bits.get_bit(6)
|
||||
}
|
||||
|
||||
/// Store/AMO Access Fault Delegate
|
||||
#[inline]
|
||||
pub fn store_fault(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// Environment Call from U-mode Delegate
|
||||
#[inline]
|
||||
pub fn user_env_call(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Environment Call from S-mode Delegate
|
||||
#[inline]
|
||||
pub fn supervisor_env_call(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
|
||||
/// Environment Call from M-mode Delegate
|
||||
#[inline]
|
||||
pub fn machine_env_call(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
|
||||
/// Instruction Page Fault Delegate
|
||||
#[inline]
|
||||
pub fn instruction_page_fault(&self) -> bool {
|
||||
self.bits.get_bit(12)
|
||||
}
|
||||
|
||||
/// Load Page Fault Delegate
|
||||
#[inline]
|
||||
pub fn load_page_fault(&self) -> bool {
|
||||
self.bits.get_bit(13)
|
||||
}
|
||||
|
||||
/// Store/AMO Page Fault Delegate
|
||||
#[inline]
|
||||
pub fn store_page_fault(&self) -> bool {
|
||||
self.bits.get_bit(15)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Medeleg, 0x302, __read_medeleg);
|
||||
set!(0x302, __set_medeleg);
|
||||
clear!(0x302, __clear_medeleg);
|
||||
|
||||
set_clear_csr!(
|
||||
/// Instruction Address Misaligned Delegate
|
||||
, set_instruction_misaligned, clear_instruction_misaligned, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Instruction Access Fault Delegate
|
||||
, set_instruction_fault, clear_instruction_fault, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// Illegal Instruction Delegate
|
||||
, set_illegal_instruction, clear_illegal_instruction, 1 << 2);
|
||||
set_clear_csr!(
|
||||
/// Breakpoint Delegate
|
||||
, set_breakpoint, clear_breakpoint, 1 << 3);
|
||||
set_clear_csr!(
|
||||
/// Load Address Misaligned Delegate
|
||||
, set_load_misaligned, clear_load_misaligned, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Load Access Fault Delegate
|
||||
, set_load_fault, clear_load_fault, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Store/AMO Address Misaligned Delegate
|
||||
, set_store_misaligned, clear_store_misaligned, 1 << 6);
|
||||
set_clear_csr!(
|
||||
/// Store/AMO Access fault
|
||||
, set_store_fault, clear_store_fault, 1 << 7);
|
||||
set_clear_csr!(
|
||||
/// Environment Call from U-mode Delegate
|
||||
, set_user_env_call, clear_user_env_call, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Environment Call from S-mode Delegate
|
||||
, set_supervisor_env_call, clear_supervisor_env_call, 1 << 9);
|
||||
set_clear_csr!(
|
||||
/// Environment Call from M-mode Delegate
|
||||
, set_machine_env_call, clear_machine_env_call, 1 << 11);
|
||||
set_clear_csr!(
|
||||
/// Instruction Page Fault Delegate
|
||||
, set_instruction_page_fault, clear_instruction_page_fault, 1 << 12);
|
||||
set_clear_csr!(
|
||||
/// Load Page Fault Delegate
|
||||
, set_load_page_fault, clear_load_page_fault, 1 << 13);
|
||||
set_clear_csr!(
|
||||
/// Store/AMO Page Fault Delegate
|
||||
, set_store_page_fault, clear_store_page_fault, 1 << 15);
|
||||
4
ci-user/riscv/src/register/mepc.rs
Normal file
4
ci-user/riscv/src/register/mepc.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! mepc register
|
||||
|
||||
read_csr_as_usize!(0x341, __read_mepc);
|
||||
write_csr_as_usize!(0x341, __write_mepc);
|
||||
3
ci-user/riscv/src/register/mhartid.rs
Normal file
3
ci-user/riscv/src/register/mhartid.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! mhartid register
|
||||
|
||||
read_csr_as_usize!(0xf14, __read_mhartid);
|
||||
84
ci-user/riscv/src/register/mhpmcounterx.rs
Normal file
84
ci-user/riscv/src/register/mhpmcounterx.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csrl:ident, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Machine performance-monitoring counter
|
||||
pub mod $csrl {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
read_composite_csr!(super::$csrh::read(), read());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! regh {
|
||||
(
|
||||
$addr:expr, $csrh:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Upper 32 bits of machine performance-monitoring counter (RV32I only)
|
||||
pub mod $csrh {
|
||||
read_csr_as_usize_rv32!($addr, $readf);
|
||||
write_csr_as_usize_rv32!($addr, $writef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reg!(0xB03, mhpmcounter3, mhpmcounter3h, __read_mhpmcounter3, __write_mhpmcounter3);
|
||||
reg!(0xB04, mhpmcounter4, mhpmcounter4h, __read_mhpmcounter4, __write_mhpmcounter4);
|
||||
reg!(0xB05, mhpmcounter5, mhpmcounter5h, __read_mhpmcounter5, __write_mhpmcounter5);
|
||||
reg!(0xB06, mhpmcounter6, mhpmcounter6h, __read_mhpmcounter6, __write_mhpmcounter6);
|
||||
reg!(0xB07, mhpmcounter7, mhpmcounter7h, __read_mhpmcounter7, __write_mhpmcounter7);
|
||||
reg!(0xB08, mhpmcounter8, mhpmcounter8h, __read_mhpmcounter8, __write_mhpmcounter8);
|
||||
reg!(0xB09, mhpmcounter9, mhpmcounter9h, __read_mhpmcounter9, __write_mhpmcounter9);
|
||||
reg!(0xB0A, mhpmcounter10, mhpmcounter10h, __read_mhpmcounter10, __write_mhpmcounter10);
|
||||
reg!(0xB0B, mhpmcounter11, mhpmcounter11h, __read_mhpmcounter11, __write_mhpmcounter11);
|
||||
reg!(0xB0C, mhpmcounter12, mhpmcounter12h, __read_mhpmcounter12, __write_mhpmcounter12);
|
||||
reg!(0xB0D, mhpmcounter13, mhpmcounter13h, __read_mhpmcounter13, __write_mhpmcounter13);
|
||||
reg!(0xB0E, mhpmcounter14, mhpmcounter14h, __read_mhpmcounter14, __write_mhpmcounter14);
|
||||
reg!(0xB0F, mhpmcounter15, mhpmcounter15h, __read_mhpmcounter15, __write_mhpmcounter15);
|
||||
reg!(0xB10, mhpmcounter16, mhpmcounter16h, __read_mhpmcounter16, __write_mhpmcounter16);
|
||||
reg!(0xB11, mhpmcounter17, mhpmcounter17h, __read_mhpmcounter17, __write_mhpmcounter17);
|
||||
reg!(0xB12, mhpmcounter18, mhpmcounter18h, __read_mhpmcounter18, __write_mhpmcounter18);
|
||||
reg!(0xB13, mhpmcounter19, mhpmcounter19h, __read_mhpmcounter19, __write_mhpmcounter19);
|
||||
reg!(0xB14, mhpmcounter20, mhpmcounter20h, __read_mhpmcounter20, __write_mhpmcounter20);
|
||||
reg!(0xB15, mhpmcounter21, mhpmcounter21h, __read_mhpmcounter21, __write_mhpmcounter21);
|
||||
reg!(0xB16, mhpmcounter22, mhpmcounter22h, __read_mhpmcounter22, __write_mhpmcounter22);
|
||||
reg!(0xB17, mhpmcounter23, mhpmcounter23h, __read_mhpmcounter23, __write_mhpmcounter23);
|
||||
reg!(0xB18, mhpmcounter24, mhpmcounter24h, __read_mhpmcounter24, __write_mhpmcounter24);
|
||||
reg!(0xB19, mhpmcounter25, mhpmcounter25h, __read_mhpmcounter25, __write_mhpmcounter25);
|
||||
reg!(0xB1A, mhpmcounter26, mhpmcounter26h, __read_mhpmcounter26, __write_mhpmcounter26);
|
||||
reg!(0xB1B, mhpmcounter27, mhpmcounter27h, __read_mhpmcounter27, __write_mhpmcounter27);
|
||||
reg!(0xB1C, mhpmcounter28, mhpmcounter28h, __read_mhpmcounter28, __write_mhpmcounter28);
|
||||
reg!(0xB1D, mhpmcounter29, mhpmcounter29h, __read_mhpmcounter29, __write_mhpmcounter29);
|
||||
reg!(0xB1E, mhpmcounter30, mhpmcounter30h, __read_mhpmcounter30, __write_mhpmcounter30);
|
||||
reg!(0xB1F, mhpmcounter31, mhpmcounter31h, __read_mhpmcounter31, __write_mhpmcounter31);
|
||||
|
||||
regh!(0xB83, mhpmcounter3h, __read_mhpmcounter3h, __write_mhpmcounter3h);
|
||||
regh!(0xB84, mhpmcounter4h, __read_mhpmcounter4h, __write_mhpmcounter4h);
|
||||
regh!(0xB85, mhpmcounter5h, __read_mhpmcounter5h, __write_mhpmcounter5h);
|
||||
regh!(0xB86, mhpmcounter6h, __read_mhpmcounter6h, __write_mhpmcounter6h);
|
||||
regh!(0xB87, mhpmcounter7h, __read_mhpmcounter7h, __write_mhpmcounter7h);
|
||||
regh!(0xB88, mhpmcounter8h, __read_mhpmcounter8h, __write_mhpmcounter8h);
|
||||
regh!(0xB89, mhpmcounter9h, __read_mhpmcounter9h, __write_mhpmcounter9h);
|
||||
regh!(0xB8A, mhpmcounter10h, __read_mhpmcounter10h, __write_mhpmcounter10h);
|
||||
regh!(0xB8B, mhpmcounter11h, __read_mhpmcounter11h, __write_mhpmcounter11h);
|
||||
regh!(0xB8C, mhpmcounter12h, __read_mhpmcounter12h, __write_mhpmcounter12h);
|
||||
regh!(0xB8D, mhpmcounter13h, __read_mhpmcounter13h, __write_mhpmcounter13h);
|
||||
regh!(0xB8E, mhpmcounter14h, __read_mhpmcounter14h, __write_mhpmcounter14h);
|
||||
regh!(0xB8F, mhpmcounter15h, __read_mhpmcounter15h, __write_mhpmcounter15h);
|
||||
regh!(0xB90, mhpmcounter16h, __read_mhpmcounter16h, __write_mhpmcounter16h);
|
||||
regh!(0xB91, mhpmcounter17h, __read_mhpmcounter17h, __write_mhpmcounter17h);
|
||||
regh!(0xB92, mhpmcounter18h, __read_mhpmcounter18h, __write_mhpmcounter18h);
|
||||
regh!(0xB93, mhpmcounter19h, __read_mhpmcounter19h, __write_mhpmcounter19h);
|
||||
regh!(0xB94, mhpmcounter20h, __read_mhpmcounter20h, __write_mhpmcounter20h);
|
||||
regh!(0xB95, mhpmcounter21h, __read_mhpmcounter21h, __write_mhpmcounter21h);
|
||||
regh!(0xB96, mhpmcounter22h, __read_mhpmcounter22h, __write_mhpmcounter22h);
|
||||
regh!(0xB97, mhpmcounter23h, __read_mhpmcounter23h, __write_mhpmcounter23h);
|
||||
regh!(0xB98, mhpmcounter24h, __read_mhpmcounter24h, __write_mhpmcounter24h);
|
||||
regh!(0xB99, mhpmcounter25h, __read_mhpmcounter25h, __write_mhpmcounter25h);
|
||||
regh!(0xB9A, mhpmcounter26h, __read_mhpmcounter26h, __write_mhpmcounter26h);
|
||||
regh!(0xB9B, mhpmcounter27h, __read_mhpmcounter27h, __write_mhpmcounter27h);
|
||||
regh!(0xB9C, mhpmcounter28h, __read_mhpmcounter28h, __write_mhpmcounter28h);
|
||||
regh!(0xB9D, mhpmcounter29h, __read_mhpmcounter29h, __write_mhpmcounter29h);
|
||||
regh!(0xB9E, mhpmcounter30h, __read_mhpmcounter30h, __write_mhpmcounter30h);
|
||||
regh!(0xB9F, mhpmcounter31h, __read_mhpmcounter31h, __write_mhpmcounter31h);
|
||||
41
ci-user/riscv/src/register/mhpmeventx.rs
Normal file
41
ci-user/riscv/src/register/mhpmeventx.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csr:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Machine performance-monitoring event selector
|
||||
pub mod $csr {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
reg!(0x323, mhpmevent3, __read_mhpmevent3, __write_mhpmevent3);
|
||||
reg!(0x324, mhpmevent4, __read_mhpmevent4, __write_mhpmevent4);
|
||||
reg!(0x325, mhpmevent5, __read_mhpmevent5, __write_mhpmevent5);
|
||||
reg!(0x326, mhpmevent6, __read_mhpmevent6, __write_mhpmevent6);
|
||||
reg!(0x327, mhpmevent7, __read_mhpmevent7, __write_mhpmevent7);
|
||||
reg!(0x328, mhpmevent8, __read_mhpmevent8, __write_mhpmevent8);
|
||||
reg!(0x329, mhpmevent9, __read_mhpmevent9, __write_mhpmevent9);
|
||||
reg!(0x32A, mhpmevent10, __read_mhpmevent10, __write_mhpmevent10);
|
||||
reg!(0x32B, mhpmevent11, __read_mhpmevent11, __write_mhpmevent11);
|
||||
reg!(0x32C, mhpmevent12, __read_mhpmevent12, __write_mhpmevent12);
|
||||
reg!(0x32D, mhpmevent13, __read_mhpmevent13, __write_mhpmevent13);
|
||||
reg!(0x32E, mhpmevent14, __read_mhpmevent14, __write_mhpmevent14);
|
||||
reg!(0x32F, mhpmevent15, __read_mhpmevent15, __write_mhpmevent15);
|
||||
reg!(0x330, mhpmevent16, __read_mhpmevent16, __write_mhpmevent16);
|
||||
reg!(0x331, mhpmevent17, __read_mhpmevent17, __write_mhpmevent17);
|
||||
reg!(0x332, mhpmevent18, __read_mhpmevent18, __write_mhpmevent18);
|
||||
reg!(0x333, mhpmevent19, __read_mhpmevent19, __write_mhpmevent19);
|
||||
reg!(0x334, mhpmevent20, __read_mhpmevent20, __write_mhpmevent20);
|
||||
reg!(0x335, mhpmevent21, __read_mhpmevent21, __write_mhpmevent21);
|
||||
reg!(0x336, mhpmevent22, __read_mhpmevent22, __write_mhpmevent22);
|
||||
reg!(0x337, mhpmevent23, __read_mhpmevent23, __write_mhpmevent23);
|
||||
reg!(0x338, mhpmevent24, __read_mhpmevent24, __write_mhpmevent24);
|
||||
reg!(0x339, mhpmevent25, __read_mhpmevent25, __write_mhpmevent25);
|
||||
reg!(0x33A, mhpmevent26, __read_mhpmevent26, __write_mhpmevent26);
|
||||
reg!(0x33B, mhpmevent27, __read_mhpmevent27, __write_mhpmevent27);
|
||||
reg!(0x33C, mhpmevent28, __read_mhpmevent28, __write_mhpmevent28);
|
||||
reg!(0x33D, mhpmevent29, __read_mhpmevent29, __write_mhpmevent29);
|
||||
reg!(0x33E, mhpmevent30, __read_mhpmevent30, __write_mhpmevent30);
|
||||
reg!(0x33F, mhpmevent31, __read_mhpmevent31, __write_mhpmevent31);
|
||||
76
ci-user/riscv/src/register/mideleg.rs
Normal file
76
ci-user/riscv/src/register/mideleg.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
//! mideleg register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// mideleg register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mideleg {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Mideleg {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// User External Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Delegate
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mideleg, 0x303, __read_mideleg);
|
||||
set!(0x303, __set_mideleg);
|
||||
clear!(0x303, __clear_mideleg);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Delegate
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Delegate
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Delegate
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Delegate
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Delegate
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Delegate
|
||||
, set_sext, clear_sext, 1 << 9);
|
||||
103
ci-user/riscv/src/register/mie.rs
Normal file
103
ci-user/riscv/src/register/mie.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
//! mie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// mie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Mie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn msoft(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mtimer(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
|
||||
/// Machine External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mext(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mie, 0x304, __read_mie);
|
||||
set!(0x304, __set_mie);
|
||||
clear!(0x304, __clear_mie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Enable
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// Machine Software Interrupt Enable
|
||||
, set_msoft, clear_msoft, 1 << 3);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Machine Timer Interrupt Enable
|
||||
, set_mtimer, clear_mtimer, 1 << 7);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Enable
|
||||
, set_sext, clear_sext, 1 << 9);
|
||||
set_clear_csr!(
|
||||
/// Machine External Interrupt Enable
|
||||
, set_mext, clear_mext, 1 << 11);
|
||||
27
ci-user/riscv/src/register/mimpid.rs
Normal file
27
ci-user/riscv/src/register/mimpid.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
//! mimpid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// mimpid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mimpid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Mimpid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_mimpid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Mimpid> {
|
||||
let r = unsafe { _read() };
|
||||
// When mimpid is hardwired to zero it means that the mimpid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Mimpid { bits })
|
||||
}
|
||||
4
ci-user/riscv/src/register/minstret.rs
Normal file
4
ci-user/riscv/src/register/minstret.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! minstret register
|
||||
|
||||
read_csr_as_usize!(0xB02, __read_minstret);
|
||||
read_composite_csr!(super::minstreth::read(), read());
|
||||
3
ci-user/riscv/src/register/minstreth.rs
Normal file
3
ci-user/riscv/src/register/minstreth.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! minstreth register
|
||||
|
||||
read_csr_as_usize_rv32!(0xB82, __read_minstreth);
|
||||
100
ci-user/riscv/src/register/mip.rs
Normal file
100
ci-user/riscv/src/register/mip.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
//! mip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// mip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Mip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn msoft(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn mtimer(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
|
||||
/// Machine External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn mext(&self) -> bool {
|
||||
self.bits.get_bit(11)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mip, 0x344, __read_mip);
|
||||
set!(0x344, __set_mip);
|
||||
clear!(0x344, __clear_mip);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Pending
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Pending
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// Machine Software Interrupt Pending
|
||||
, set_msoft, clear_msoft, 1 << 3);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Pending
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Pending
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Machine Timer Interrupt Pending
|
||||
, set_mtimer, clear_mtimer, 1 << 7);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Pending
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Pending
|
||||
, set_sext, clear_sext, 1 << 9);
|
||||
60
ci-user/riscv/src/register/misa.rs
Normal file
60
ci-user/riscv/src/register/misa.rs
Normal file
@@ -0,0 +1,60 @@
|
||||
//! misa register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// misa register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Misa {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
/// Machine XLEN
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MXL {
|
||||
XLEN32,
|
||||
XLEN64,
|
||||
XLEN128,
|
||||
}
|
||||
|
||||
impl Misa {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
|
||||
/// Returns the machine xlen.
|
||||
pub fn mxl(&self) -> MXL {
|
||||
let value = match () {
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
() => (self.bits() >> 30) as u8,
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
() => (self.bits() >> 62) as u8,
|
||||
};
|
||||
match value {
|
||||
1 => MXL::XLEN32,
|
||||
2 => MXL::XLEN64,
|
||||
3 => MXL::XLEN128,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns true when the atomic extension is implemented.
|
||||
pub fn has_extension(&self, extension: char) -> bool {
|
||||
let bit = extension as u8 - 65;
|
||||
if bit > 25 {
|
||||
return false;
|
||||
}
|
||||
self.bits() & (1 << bit) == (1 << bit)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0x301, __read_misa);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Misa> {
|
||||
let r = unsafe { _read() };
|
||||
// When misa is hardwired to zero it means that the misa csr
|
||||
// isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Misa { bits })
|
||||
}
|
||||
104
ci-user/riscv/src/register/mod.rs
Normal file
104
ci-user/riscv/src/register/mod.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
//! RISC-V CSR's
|
||||
//!
|
||||
//! The following registers are not available on 64-bit implementations.
|
||||
//!
|
||||
//! - cycleh
|
||||
//! - timeh
|
||||
//! - instreth
|
||||
//! - hpmcounter[3-31]h
|
||||
//! - mcycleh
|
||||
//! - minstreth
|
||||
//! - mhpmcounter[3-31]h
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
// User Trap Setup
|
||||
pub mod uie;
|
||||
pub mod ustatus;
|
||||
pub mod utvec;
|
||||
|
||||
// User Trap Handling
|
||||
pub mod ucause;
|
||||
pub mod uepc;
|
||||
pub mod uip;
|
||||
pub mod uscratch;
|
||||
pub mod utval;
|
||||
|
||||
// User Floating-Point CSRs
|
||||
// TODO: frm, fflags
|
||||
pub mod fcsr;
|
||||
|
||||
// User Counter/Timers
|
||||
// TODO: cycle[h], instret[h]
|
||||
pub mod time;
|
||||
#[rustfmt::skip] // long macro use
|
||||
mod hpmcounterx;
|
||||
pub use self::hpmcounterx::*;
|
||||
pub mod timeh;
|
||||
|
||||
// Supervisor Trap Setup
|
||||
// TODO: sedeleg, sideleg
|
||||
pub mod sie;
|
||||
pub mod sstatus;
|
||||
pub mod stvec;
|
||||
// TODO: scounteren
|
||||
|
||||
// Supervisor Trap Handling
|
||||
pub mod scause;
|
||||
pub mod sepc;
|
||||
pub mod sip;
|
||||
pub mod sscratch;
|
||||
pub mod stval;
|
||||
|
||||
// Supervisor Protection and Translation
|
||||
pub mod satp;
|
||||
|
||||
// Machine Information Registers
|
||||
pub mod marchid;
|
||||
pub mod mhartid;
|
||||
pub mod mimpid;
|
||||
pub mod mvendorid;
|
||||
|
||||
// Machine Trap Setup
|
||||
pub mod medeleg;
|
||||
pub mod mideleg;
|
||||
pub mod mie;
|
||||
pub mod misa;
|
||||
pub mod mstatus;
|
||||
pub mod mtvec;
|
||||
// TODO: mcounteren
|
||||
|
||||
// Machine Trap Handling
|
||||
pub mod mcause;
|
||||
pub mod mepc;
|
||||
pub mod mip;
|
||||
pub mod mscratch;
|
||||
pub mod mtval;
|
||||
|
||||
// Machine Protection and Translation
|
||||
mod pmpcfgx;
|
||||
pub use self::pmpcfgx::*;
|
||||
mod pmpaddrx;
|
||||
pub use self::pmpaddrx::*;
|
||||
|
||||
// Machine Counter/Timers
|
||||
pub mod mcycle;
|
||||
#[rustfmt::skip] // long macro use
|
||||
mod mhpmcounterx;
|
||||
pub mod minstret;
|
||||
pub use self::mhpmcounterx::*;
|
||||
pub mod mcycleh;
|
||||
pub mod minstreth;
|
||||
|
||||
// Machine Counter Setup
|
||||
mod mhpmeventx;
|
||||
pub use self::mhpmeventx::*;
|
||||
|
||||
// TODO: Debug/Trace Registers (shared with Debug Mode)
|
||||
|
||||
// TODO: Debug Mode Registers
|
||||
|
||||
// Hypervisor Extension Registers
|
||||
mod hypervisorx64;
|
||||
pub use self::hypervisorx64::*;
|
||||
4
ci-user/riscv/src/register/mscratch.rs
Normal file
4
ci-user/riscv/src/register/mscratch.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! mscratch register
|
||||
|
||||
read_csr_as_usize!(0x340, __read_mscratch);
|
||||
write_csr_as_usize!(0x340, __write_mscratch);
|
||||
214
ci-user/riscv/src/register/mstatus.rs
Normal file
214
ci-user/riscv/src/register/mstatus.rs
Normal file
@@ -0,0 +1,214 @@
|
||||
//! mstatus register
|
||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
|
||||
/// mstatus register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mstatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Additional extension state
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum XS {
|
||||
/// All off
|
||||
AllOff = 0,
|
||||
|
||||
/// None dirty or clean, some on
|
||||
NoneDirtyOrClean = 1,
|
||||
|
||||
/// None dirty, some clean
|
||||
NoneDirtySomeClean = 2,
|
||||
|
||||
/// Some dirty
|
||||
SomeDirty = 3,
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum FS {
|
||||
Off = 0,
|
||||
Initial = 1,
|
||||
Clean = 2,
|
||||
Dirty = 3,
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum MPP {
|
||||
Machine = 3,
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SPP {
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
impl Mstatus {
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// Machine Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mie(&self) -> bool {
|
||||
self.bits.get_bit(3)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn spie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Machine Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn mpie(&self) -> bool {
|
||||
self.bits.get_bit(7)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn spp(&self) -> SPP {
|
||||
match self.bits.get_bit(8) {
|
||||
true => SPP::Supervisor,
|
||||
false => SPP::User,
|
||||
}
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn mpp(&self) -> MPP {
|
||||
match self.bits.get_bits(11..13) {
|
||||
0b00 => MPP::User,
|
||||
0b01 => MPP::Supervisor,
|
||||
0b11 => MPP::Machine,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_mpie(&mut self, val: bool) {
|
||||
self.bits.set_bit(7, val);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_mie(&mut self, val: bool) {
|
||||
self.bits.set_bit(3, val);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_mpp(&mut self, val: MPP) {
|
||||
self.bits.set_bits(11..13, val as usize);
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
///
|
||||
/// Encodes the status of the floating-point unit,
|
||||
/// including the CSR `fcsr` and floating-point data registers `f0–f31`.
|
||||
#[inline]
|
||||
pub fn fs(&self) -> FS {
|
||||
match self.bits.get_bits(13..15) {
|
||||
0b00 => FS::Off,
|
||||
0b01 => FS::Initial,
|
||||
0b10 => FS::Clean,
|
||||
0b11 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Additional extension state
|
||||
///
|
||||
/// Encodes the status of additional user-mode extensions and associated state.
|
||||
#[inline]
|
||||
pub fn xs(&self) -> XS {
|
||||
match self.bits.get_bits(15..17) {
|
||||
0b00 => XS::AllOff,
|
||||
0b01 => XS::NoneDirtyOrClean,
|
||||
0b10 => XS::NoneDirtySomeClean,
|
||||
0b11 => XS::SomeDirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether either the FS field or XS field
|
||||
/// signals the presence of some dirty state
|
||||
#[inline]
|
||||
pub fn sd(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mstatus, 0x300, __read_mstatus);
|
||||
write_csr!(0x300, __write_mstatus);
|
||||
set!(0x300, __set_mstatus);
|
||||
clear!(0x300, __clear_mstatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
|
||||
set_clear_csr!(
|
||||
/// Supervisor Interrupt Enable
|
||||
, set_sie, clear_sie, 1 << 1);
|
||||
|
||||
set_clear_csr!(
|
||||
/// Machine Interrupt Enable
|
||||
, set_mie, clear_mie, 1 << 3);
|
||||
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
||||
|
||||
set_csr!(
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
, set_spie, 1 << 5);
|
||||
|
||||
set_csr!(
|
||||
/// Machine Previous Interrupt Enable
|
||||
, set_mpie, 1 << 7);
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub unsafe fn set_spp(spp: SPP) {
|
||||
match spp {
|
||||
SPP::Supervisor => _set(1 << 8),
|
||||
SPP::User => _clear(1 << 8),
|
||||
}
|
||||
}
|
||||
|
||||
/// Machine Previous Privilege Mode
|
||||
#[inline]
|
||||
pub unsafe fn set_mpp(mpp: MPP) {
|
||||
let mut value = _read();
|
||||
value.set_bits(11..13, mpp as usize);
|
||||
_write(value);
|
||||
}
|
||||
|
||||
/// Floating-point extension state
|
||||
#[inline]
|
||||
pub unsafe fn set_fs(fs: FS) {
|
||||
let mut value = _read();
|
||||
value.set_bits(13..15, fs as usize);
|
||||
_write(value);
|
||||
}
|
||||
3
ci-user/riscv/src/register/mtval.rs
Normal file
3
ci-user/riscv/src/register/mtval.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! mtval register
|
||||
|
||||
read_csr_as_usize!(0x343, __read_mtval);
|
||||
47
ci-user/riscv/src/register/mtvec.rs
Normal file
47
ci-user/riscv/src/register/mtvec.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! mtvec register
|
||||
|
||||
/// mtvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mtvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum TrapMode {
|
||||
Direct = 0,
|
||||
Vectored = 1,
|
||||
}
|
||||
|
||||
impl Mtvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> Option<TrapMode> {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => Some(TrapMode::Direct),
|
||||
1 => Some(TrapMode::Vectored),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Mtvec, 0x305, __read_mtvec);
|
||||
|
||||
write_csr!(0x305, __write_mtvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
let bits = addr + mode as usize;
|
||||
_write(bits);
|
||||
}
|
||||
32
ci-user/riscv/src/register/mvendorid.rs
Normal file
32
ci-user/riscv/src/register/mvendorid.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
//! mvendorid register
|
||||
|
||||
use core::num::NonZeroUsize;
|
||||
|
||||
/// mvendorid register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Mvendorid {
|
||||
bits: NonZeroUsize,
|
||||
}
|
||||
|
||||
impl Mvendorid {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits.get()
|
||||
}
|
||||
|
||||
/// Returns the JEDEC manufacturer ID
|
||||
pub fn jedec_manufacturer(&self) -> usize {
|
||||
self.bits() >> 7
|
||||
}
|
||||
}
|
||||
|
||||
read_csr!(0xF11, __read_mvendorid);
|
||||
|
||||
/// Reads the CSR
|
||||
#[inline]
|
||||
pub fn read() -> Option<Mvendorid> {
|
||||
let r = unsafe { _read() };
|
||||
// When mvendorid is hardwired to zero it means that the mvendorid
|
||||
// csr isn't implemented.
|
||||
NonZeroUsize::new(r).map(|bits| Mvendorid { bits })
|
||||
}
|
||||
28
ci-user/riscv/src/register/pmpaddrx.rs
Normal file
28
ci-user/riscv/src/register/pmpaddrx.rs
Normal file
@@ -0,0 +1,28 @@
|
||||
macro_rules! reg {
|
||||
(
|
||||
$addr:expr, $csr:ident, $readf:ident, $writef:ident
|
||||
) => {
|
||||
/// Physical memory protection address register
|
||||
pub mod $csr {
|
||||
read_csr_as_usize!($addr, $readf);
|
||||
write_csr_as_usize!($addr, $writef);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
reg!(0x3B0, pmpaddr0, __read_pmpaddr0, __write_pmpaddr0);
|
||||
reg!(0x3B1, pmpaddr1, __read_pmpaddr1, __write_pmpaddr1);
|
||||
reg!(0x3B2, pmpaddr2, __read_pmpaddr2, __write_pmpaddr2);
|
||||
reg!(0x3B3, pmpaddr3, __read_pmpaddr3, __write_pmpaddr3);
|
||||
reg!(0x3B4, pmpaddr4, __read_pmpaddr4, __write_pmpaddr4);
|
||||
reg!(0x3B5, pmpaddr5, __read_pmpaddr5, __write_pmpaddr5);
|
||||
reg!(0x3B6, pmpaddr6, __read_pmpaddr6, __write_pmpaddr6);
|
||||
reg!(0x3B7, pmpaddr7, __read_pmpaddr7, __write_pmpaddr7);
|
||||
reg!(0x3B8, pmpaddr8, __read_pmpaddr8, __write_pmpaddr8);
|
||||
reg!(0x3B9, pmpaddr9, __read_pmpaddr9, __write_pmpaddr9);
|
||||
reg!(0x3BA, pmpaddr10, __read_pmpaddr10, __write_pmpaddr10);
|
||||
reg!(0x3BB, pmpaddr11, __read_pmpaddr11, __write_pmpaddr11);
|
||||
reg!(0x3BC, pmpaddr12, __read_pmpaddr12, __write_pmpaddr12);
|
||||
reg!(0x3BD, pmpaddr13, __read_pmpaddr13, __write_pmpaddr13);
|
||||
reg!(0x3BE, pmpaddr14, __read_pmpaddr14, __write_pmpaddr14);
|
||||
reg!(0x3BF, pmpaddr15, __read_pmpaddr15, __write_pmpaddr15);
|
||||
23
ci-user/riscv/src/register/pmpcfgx.rs
Normal file
23
ci-user/riscv/src/register/pmpcfgx.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
/// Physical memory protection configuration
|
||||
pub mod pmpcfg0 {
|
||||
read_csr_as_usize!(0x3A0, __read_pmpcfg0);
|
||||
write_csr_as_usize!(0x3A0, __write_pmpcfg0);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration, RV32 only
|
||||
pub mod pmpcfg1 {
|
||||
read_csr_as_usize_rv32!(0x3A1, __read_pmpcfg1);
|
||||
write_csr_as_usize_rv32!(0x3A1, __write_pmpcfg1);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration
|
||||
pub mod pmpcfg2 {
|
||||
read_csr_as_usize!(0x3A2, __read_pmpcfg2);
|
||||
write_csr_as_usize!(0x3A2, __write_pmpcfg2);
|
||||
}
|
||||
|
||||
/// Physical memory protection configuration, RV32 only
|
||||
pub mod pmpcfg3 {
|
||||
read_csr_as_usize_rv32!(0x3A3, __read_pmpcfg3);
|
||||
write_csr_as_usize_rv32!(0x3A3, __write_pmpcfg3);
|
||||
}
|
||||
119
ci-user/riscv/src/register/satp.rs
Normal file
119
ci-user/riscv/src/register/satp.rs
Normal file
@@ -0,0 +1,119 @@
|
||||
//! satp register
|
||||
|
||||
#[cfg(riscv)]
|
||||
use addr::Frame;
|
||||
#[cfg(riscv)]
|
||||
use bit_field::BitField;
|
||||
|
||||
/// satp register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Satp {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Satp {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Current address-translation scheme
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn mode(&self) -> Mode {
|
||||
match self.bits.get_bit(31) {
|
||||
false => Mode::Bare,
|
||||
true => Mode::Sv32,
|
||||
}
|
||||
}
|
||||
|
||||
/// Current address-translation scheme
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn mode(&self) -> Mode {
|
||||
match self.bits.get_bits(60..64) {
|
||||
0 => Mode::Bare,
|
||||
8 => Mode::Sv39,
|
||||
9 => Mode::Sv48,
|
||||
10 => Mode::Sv57,
|
||||
11 => Mode::Sv64,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Address space identifier
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn asid(&self) -> usize {
|
||||
self.bits.get_bits(22..31)
|
||||
}
|
||||
|
||||
/// Address space identifier
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn asid(&self) -> usize {
|
||||
self.bits.get_bits(44..60)
|
||||
}
|
||||
|
||||
/// Physical page number
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..22)
|
||||
}
|
||||
|
||||
/// Physical page number
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub fn ppn(&self) -> usize {
|
||||
self.bits.get_bits(0..44)
|
||||
}
|
||||
|
||||
/// Physical frame
|
||||
#[inline]
|
||||
#[cfg(riscv)]
|
||||
pub fn frame(&self) -> Frame {
|
||||
Frame::of_ppn(self.ppn())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(riscv32)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Mode {
|
||||
Bare = 0,
|
||||
Sv32 = 1,
|
||||
}
|
||||
|
||||
#[cfg(riscv64)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum Mode {
|
||||
Bare = 0,
|
||||
Sv39 = 8,
|
||||
Sv48 = 9,
|
||||
Sv57 = 10,
|
||||
Sv64 = 11,
|
||||
}
|
||||
|
||||
read_csr_as!(Satp, 0x180, __read_satp);
|
||||
write_csr_as_usize!(0x180, __write_satp);
|
||||
|
||||
#[inline]
|
||||
#[cfg(riscv32)]
|
||||
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||
let mut bits = 0usize;
|
||||
bits.set_bits(31..32, mode as usize);
|
||||
bits.set_bits(22..31, asid);
|
||||
bits.set_bits(0..22, ppn);
|
||||
_write(bits);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(riscv64)]
|
||||
pub unsafe fn set(mode: Mode, asid: usize, ppn: usize) {
|
||||
let mut bits = 0usize;
|
||||
bits.set_bits(60..64, mode as usize);
|
||||
bits.set_bits(44..60, asid);
|
||||
bits.set_bits(0..44, ppn);
|
||||
_write(bits);
|
||||
}
|
||||
133
ci-user/riscv/src/register/scause.rs
Normal file
133
ci-user/riscv/src/register/scause.rs
Normal file
@@ -0,0 +1,133 @@
|
||||
//! scause register
|
||||
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
|
||||
/// scause register
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Scause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Trap {
|
||||
Interrupt(Interrupt),
|
||||
Exception(Exception),
|
||||
}
|
||||
|
||||
/// Interrupt
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Interrupt {
|
||||
UserSoft,
|
||||
VirtualSupervisorSoft,
|
||||
SupervisorSoft,
|
||||
UserTimer,
|
||||
VirtualSupervisorTimer,
|
||||
SupervisorTimer,
|
||||
UserExternal,
|
||||
VirtualSupervisorExternal,
|
||||
SupervisorExternal,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
/// Exception
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum Exception {
|
||||
InstructionMisaligned,
|
||||
InstructionFault,
|
||||
IllegalInstruction,
|
||||
Breakpoint,
|
||||
LoadFault,
|
||||
StoreMisaligned,
|
||||
StoreFault,
|
||||
UserEnvCall,
|
||||
VirtualSupervisorEnvCall,
|
||||
InstructionPageFault,
|
||||
LoadPageFault,
|
||||
StorePageFault,
|
||||
InstructionGuestPageFault,
|
||||
LoadGuestPageFault,
|
||||
VirtualInstruction,
|
||||
StoreGuestPageFault,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Interrupt::UserSoft,
|
||||
1 => Interrupt::SupervisorSoft,
|
||||
2 => Interrupt::VirtualSupervisorSoft,
|
||||
4 => Interrupt::UserTimer,
|
||||
5 => Interrupt::SupervisorTimer,
|
||||
6 => Interrupt::VirtualSupervisorTimer,
|
||||
8 => Interrupt::UserExternal,
|
||||
9 => Interrupt::SupervisorExternal,
|
||||
10 => Interrupt::VirtualSupervisorExternal,
|
||||
_ => Interrupt::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Exception {
|
||||
pub fn from(nr: usize) -> Self {
|
||||
match nr {
|
||||
0 => Exception::InstructionMisaligned,
|
||||
1 => Exception::InstructionFault,
|
||||
2 => Exception::IllegalInstruction,
|
||||
3 => Exception::Breakpoint,
|
||||
5 => Exception::LoadFault,
|
||||
6 => Exception::StoreMisaligned,
|
||||
7 => Exception::StoreFault,
|
||||
8 => Exception::UserEnvCall,
|
||||
10 => Exception::VirtualSupervisorEnvCall,
|
||||
12 => Exception::InstructionPageFault,
|
||||
13 => Exception::LoadPageFault,
|
||||
15 => Exception::StorePageFault,
|
||||
20 => Exception::InstructionGuestPageFault,
|
||||
21 => Exception::LoadGuestPageFault,
|
||||
22 => Exception::VirtualInstruction,
|
||||
23 => Exception::StoreGuestPageFault,
|
||||
_ => Exception::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the code field
|
||||
pub fn code(&self) -> usize {
|
||||
let bit = 1 << (size_of::<usize>() * 8 - 1);
|
||||
self.bits & !bit
|
||||
}
|
||||
|
||||
/// Trap Cause
|
||||
#[inline]
|
||||
pub fn cause(&self) -> Trap {
|
||||
if self.is_interrupt() {
|
||||
Trap::Interrupt(Interrupt::from(self.code()))
|
||||
} else {
|
||||
Trap::Exception(Exception::from(self.code()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Is trap cause an interrupt.
|
||||
#[inline]
|
||||
pub fn is_interrupt(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
|
||||
/// Is trap cause an exception.
|
||||
#[inline]
|
||||
pub fn is_exception(&self) -> bool {
|
||||
!self.is_interrupt()
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Scause, 0x142, __read_scause);
|
||||
4
ci-user/riscv/src/register/sepc.rs
Normal file
4
ci-user/riscv/src/register/sepc.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! sepc register
|
||||
|
||||
read_csr_as_usize!(0x141, __read_sepc);
|
||||
write_csr_as_usize!(0x141, __write_sepc);
|
||||
76
ci-user/riscv/src/register/sie.rs
Normal file
76
ci-user/riscv/src/register/sie.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
//! sie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// sie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Sie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sie, 0x104, __read_sie);
|
||||
set!(0x104, __set_sie);
|
||||
clear!(0x104, __clear_sie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Software Interrupt Enable
|
||||
, set_ssoft, clear_ssoft, 1 << 1);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Timer Interrupt Enable
|
||||
, set_stimer, clear_stimer, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
set_clear_csr!(
|
||||
/// Supervisor External Interrupt Enable
|
||||
, set_sext, clear_sext, 1 << 9);
|
||||
55
ci-user/riscv/src/register/sip.rs
Normal file
55
ci-user/riscv/src/register/sip.rs
Normal file
@@ -0,0 +1,55 @@
|
||||
//! sip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// sip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Sip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn ssoft(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn stimer(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
|
||||
/// Supervisor External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn sext(&self) -> bool {
|
||||
self.bits.get_bit(9)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sip, 0x144, __read_sip);
|
||||
4
ci-user/riscv/src/register/sscratch.rs
Normal file
4
ci-user/riscv/src/register/sscratch.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! sscratch register
|
||||
|
||||
read_csr_as_usize!(0x140, __read_sscratch);
|
||||
write_csr_as_usize!(0x140, __write_sscratch);
|
||||
161
ci-user/riscv/src/register/sstatus.rs
Normal file
161
ci-user/riscv/src/register/sstatus.rs
Normal file
@@ -0,0 +1,161 @@
|
||||
//! sstatus register
|
||||
|
||||
pub use super::mstatus::FS;
|
||||
use bit_field::BitField;
|
||||
use core::mem::size_of;
|
||||
|
||||
/// Supervisor Status Register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Sstatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum SPP {
|
||||
Supervisor = 1,
|
||||
User = 0,
|
||||
}
|
||||
|
||||
impl Sstatus {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// Supervisor Interrupt Enable
|
||||
#[inline]
|
||||
pub fn sie(&self) -> bool {
|
||||
self.bits.get_bit(1)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn spie(&self) -> bool {
|
||||
self.bits.get_bit(5)
|
||||
}
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
pub fn spp(&self) -> SPP {
|
||||
match self.bits.get_bit(8) {
|
||||
true => SPP::Supervisor,
|
||||
false => SPP::User,
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of the floating-point unit
|
||||
#[inline]
|
||||
pub fn fs(&self) -> FS {
|
||||
match self.bits.get_bits(13..15) {
|
||||
0 => FS::Off,
|
||||
1 => FS::Initial,
|
||||
2 => FS::Clean,
|
||||
3 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of additional user-mode extensions
|
||||
/// and associated state
|
||||
#[inline]
|
||||
pub fn xs(&self) -> FS {
|
||||
match self.bits.get_bits(15..17) {
|
||||
0 => FS::Off,
|
||||
1 => FS::Initial,
|
||||
2 => FS::Clean,
|
||||
3 => FS::Dirty,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Permit Supervisor User Memory access
|
||||
#[inline]
|
||||
pub fn sum(&self) -> bool {
|
||||
self.bits.get_bit(18)
|
||||
}
|
||||
|
||||
/// Make eXecutable Readable
|
||||
#[inline]
|
||||
pub fn mxr(&self) -> bool {
|
||||
self.bits.get_bit(19)
|
||||
}
|
||||
|
||||
/// Whether either the FS field or XS field
|
||||
/// signals the presence of some dirty state
|
||||
#[inline]
|
||||
pub fn sd(&self) -> bool {
|
||||
self.bits.get_bit(size_of::<usize>() * 8 - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_spie(&mut self, val: bool) {
|
||||
self.bits.set_bit(5, val);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_sie(&mut self, val: bool) {
|
||||
self.bits.set_bit(1, val);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_spp(&mut self, val: SPP) {
|
||||
self.bits.set_bit(8, val == SPP::Supervisor);
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Sstatus, 0x100, __read_sstatus);
|
||||
write_csr!(0x100, __write_sstatus);
|
||||
set!(0x100, __set_sstatus);
|
||||
clear!(0x100, __clear_sstatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// Supervisor Interrupt Enable
|
||||
, set_sie, clear_sie, 1 << 1);
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
||||
set_csr!(
|
||||
/// Supervisor Previous Interrupt Enable
|
||||
, set_spie, 1 << 5);
|
||||
set_clear_csr!(
|
||||
/// Make eXecutable Readable
|
||||
, set_mxr, clear_mxr, 1 << 19);
|
||||
set_clear_csr!(
|
||||
/// Permit Supervisor User Memory access
|
||||
, set_sum, clear_sum, 1 << 18);
|
||||
|
||||
/// Supervisor Previous Privilege Mode
|
||||
#[inline]
|
||||
#[cfg(riscv)]
|
||||
pub unsafe fn set_spp(spp: SPP) {
|
||||
match spp {
|
||||
SPP::Supervisor => _set(1 << 8),
|
||||
SPP::User => _clear(1 << 8),
|
||||
}
|
||||
}
|
||||
|
||||
/// The status of the floating-point unit
|
||||
#[inline]
|
||||
#[cfg(riscv)]
|
||||
pub unsafe fn set_fs(fs: FS) {
|
||||
let mut value = _read();
|
||||
value.set_bits(13..15, fs as usize);
|
||||
_write(value);
|
||||
}
|
||||
3
ci-user/riscv/src/register/stval.rs
Normal file
3
ci-user/riscv/src/register/stval.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! stval register
|
||||
|
||||
read_csr_as_usize!(0x143, __read_stval);
|
||||
40
ci-user/riscv/src/register/stvec.rs
Normal file
40
ci-user/riscv/src/register/stvec.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
//! stvec register
|
||||
|
||||
pub use crate::register::mtvec::TrapMode;
|
||||
|
||||
/// stvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Stvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Stvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> Option<TrapMode> {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => Some(TrapMode::Direct),
|
||||
1 => Some(TrapMode::Vectored),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Stvec, 0x105, __read_stvec);
|
||||
write_csr!(0x105, __write_stvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
_write(addr + mode as usize);
|
||||
}
|
||||
4
ci-user/riscv/src/register/time.rs
Normal file
4
ci-user/riscv/src/register/time.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! time register
|
||||
|
||||
read_csr_as_usize!(0xC01, __read_time);
|
||||
read_composite_csr!(super::timeh::read(), read());
|
||||
3
ci-user/riscv/src/register/timeh.rs
Normal file
3
ci-user/riscv/src/register/timeh.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! timeh register
|
||||
|
||||
read_csr_as_usize_rv32!(0xC81, __read_timeh);
|
||||
17
ci-user/riscv/src/register/ucause.rs
Normal file
17
ci-user/riscv/src/register/ucause.rs
Normal file
@@ -0,0 +1,17 @@
|
||||
//! ucause register
|
||||
|
||||
/// ucause register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Ucause {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Ucause {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Ucause, 0x042, __read_ucause);
|
||||
4
ci-user/riscv/src/register/uepc.rs
Normal file
4
ci-user/riscv/src/register/uepc.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! uepc register
|
||||
|
||||
read_csr_as_usize!(0x041, __read_uepc);
|
||||
write_csr_as_usize!(0x041, __write_uepc);
|
||||
49
ci-user/riscv/src/register/uie.rs
Normal file
49
ci-user/riscv/src/register/uie.rs
Normal file
@@ -0,0 +1,49 @@
|
||||
//! uie register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// uie register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Uie {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Uie {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Enable
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Enable
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// User External Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Uie, 0x004, __read_uie);
|
||||
set!(0x004, __set_uie);
|
||||
clear!(0x004, __clear_uie);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Software Interrupt Enable
|
||||
, set_usoft, clear_usoft, 1 << 0);
|
||||
set_clear_csr!(
|
||||
/// User Timer Interrupt Enable
|
||||
, set_utimer, clear_utimer, 1 << 4);
|
||||
set_clear_csr!(
|
||||
/// User External Interrupt Enable
|
||||
, set_uext, clear_uext, 1 << 8);
|
||||
37
ci-user/riscv/src/register/uip.rs
Normal file
37
ci-user/riscv/src/register/uip.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
//! uip register
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// uip register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Uip {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Uip {
|
||||
/// Returns the contents of the register as raw bits
|
||||
#[inline]
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// User Software Interrupt Pending
|
||||
#[inline]
|
||||
pub fn usoft(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Timer Interrupt Pending
|
||||
#[inline]
|
||||
pub fn utimer(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
|
||||
/// User External Interrupt Pending
|
||||
#[inline]
|
||||
pub fn uext(&self) -> bool {
|
||||
self.bits.get_bit(8)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Uip, 0x044, __read_uip);
|
||||
4
ci-user/riscv/src/register/uscratch.rs
Normal file
4
ci-user/riscv/src/register/uscratch.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
//! uscratch register
|
||||
|
||||
read_csr_as_usize!(0x040, __read_uscratch);
|
||||
write_csr_as_usize!(0x040, __write_uscratch);
|
||||
37
ci-user/riscv/src/register/ustatus.rs
Normal file
37
ci-user/riscv/src/register/ustatus.rs
Normal file
@@ -0,0 +1,37 @@
|
||||
//! ustatus register
|
||||
// TODO: Virtualization, Memory Privilege and Extension Context Fields
|
||||
|
||||
use bit_field::BitField;
|
||||
|
||||
/// ustatus register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Ustatus {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Ustatus {
|
||||
/// User Interrupt Enable
|
||||
#[inline]
|
||||
pub fn uie(&self) -> bool {
|
||||
self.bits.get_bit(0)
|
||||
}
|
||||
|
||||
/// User Previous Interrupt Enable
|
||||
#[inline]
|
||||
pub fn upie(&self) -> bool {
|
||||
self.bits.get_bit(4)
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Ustatus, 0x000, __read_ustatus);
|
||||
write_csr!(0x000, __write_ustatus);
|
||||
set!(0x000, __set_ustatus);
|
||||
clear!(0x000, __clear_ustatus);
|
||||
|
||||
set_clear_csr!(
|
||||
/// User Interrupt Enable
|
||||
, set_uie, clear_uie, 1 << 0);
|
||||
|
||||
set_csr!(
|
||||
/// User Previous Interrupt Enable
|
||||
, set_upie, 1 << 4);
|
||||
3
ci-user/riscv/src/register/utval.rs
Normal file
3
ci-user/riscv/src/register/utval.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
//! utval register
|
||||
|
||||
read_csr_as_usize!(0x043, __read_utval);
|
||||
40
ci-user/riscv/src/register/utvec.rs
Normal file
40
ci-user/riscv/src/register/utvec.rs
Normal file
@@ -0,0 +1,40 @@
|
||||
//! stvec register
|
||||
|
||||
pub use crate::register::mtvec::TrapMode;
|
||||
|
||||
/// stvec register
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Utvec {
|
||||
bits: usize,
|
||||
}
|
||||
|
||||
impl Utvec {
|
||||
/// Returns the contents of the register as raw bits
|
||||
pub fn bits(&self) -> usize {
|
||||
self.bits
|
||||
}
|
||||
|
||||
/// Returns the trap-vector base-address
|
||||
pub fn address(&self) -> usize {
|
||||
self.bits - (self.bits & 0b11)
|
||||
}
|
||||
|
||||
/// Returns the trap-vector mode
|
||||
pub fn trap_mode(&self) -> Option<TrapMode> {
|
||||
let mode = self.bits & 0b11;
|
||||
match mode {
|
||||
0 => Some(TrapMode::Direct),
|
||||
1 => Some(TrapMode::Vectored),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
read_csr_as!(Utvec, 0x005, __read_utvec);
|
||||
write_csr!(0x005, __write_utvec);
|
||||
|
||||
/// Writes the CSR
|
||||
#[inline]
|
||||
pub unsafe fn write(addr: usize, mode: TrapMode) {
|
||||
_write(addr + mode as usize);
|
||||
}
|
||||
Reference in New Issue
Block a user