rv64: boot into upper half
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "kernel-arch-riscv64"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
yggdrasil-abi.workspace = true
|
||||
kernel-arch-interface.workspace = true
|
||||
libk-mm-interface.workspace = true
|
||||
memtables.workspace = true
|
||||
device-api = { workspace = true, features = ["derive"] }
|
||||
|
||||
tock-registers.workspace = true
|
||||
bitflags.workspace = true
|
||||
static_assertions.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@@ -0,0 +1,54 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use kernel_arch_interface::{
|
||||
mem::{KernelTableManager, PhysicalMemoryAllocator},
|
||||
task::{TaskContext, UserContextInfo},
|
||||
};
|
||||
use libk_mm_interface::address::PhysicalAddress;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
pub struct TaskContextImpl<K, PA> {
|
||||
_pd: PhantomData<(K, PA)>,
|
||||
}
|
||||
|
||||
impl<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddress>>
|
||||
TaskContext<K, PA> for TaskContextImpl<K, PA>
|
||||
{
|
||||
const USER_STACK_EXTRA_ALIGN: usize = 0;
|
||||
const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;
|
||||
|
||||
fn user(context: UserContextInfo) -> Result<Self, Error> {
|
||||
let _ = context;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn kernel(entry: extern "C" fn(usize) -> !, arg: usize) -> Result<Self, Error> {
|
||||
let _ = entry;
|
||||
let _ = arg;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn set_thread_pointer(&self, tp: usize) {
|
||||
let _ = tp;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn align_stack_for_entry(sp: usize) -> usize {
|
||||
let _ = sp;
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn enter(&self) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn switch(&self, from: &Self) {
|
||||
let _ = from;
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn switch_and_drop(&self, thread: *const ()) {
|
||||
let _ = thread;
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
#![feature(decl_macro)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use device_api::interrupt::{LocalInterruptController, MessageInterruptController};
|
||||
use kernel_arch_interface::{
|
||||
cpu::{CpuImpl, IpiQueue},
|
||||
task::Scheduler,
|
||||
Architecture,
|
||||
};
|
||||
|
||||
pub mod mem;
|
||||
pub use mem::{KernelTableManagerImpl, ProcessAddressSpaceImpl};
|
||||
pub mod context;
|
||||
pub use context::TaskContextImpl;
|
||||
use registers::MSTATUS;
|
||||
use tock_registers::interfaces::{ReadWriteable, Readable};
|
||||
pub mod registers;
|
||||
|
||||
pub struct ArchitectureImpl;
|
||||
|
||||
impl Architecture for ArchitectureImpl {
|
||||
type PerCpuData = ();
|
||||
type CpuFeatures = ();
|
||||
type BreakpointType = u32;
|
||||
|
||||
const BREAKPOINT_VALUE: Self::BreakpointType = 0;
|
||||
|
||||
fn halt() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn set_local_cpu(cpu: *mut ()) {
|
||||
let _ = cpu;
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn local_cpu() -> *mut () {
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn init_local_cpu<S: Scheduler + 'static>(id: Option<u32>, data: Self::PerCpuData) {
|
||||
let _ = id;
|
||||
let _ = data;
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn init_ipi_queues(queues: Vec<IpiQueue<Self>>) {
|
||||
let _ = queues;
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn ipi_queue(cpu_id: u32) -> Option<&'static IpiQueue<Self>> {
|
||||
let _ = cpu_id;
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn set_interrupt_mask(mask: bool) -> bool {
|
||||
let old = Self::interrupt_mask();
|
||||
if mask {
|
||||
MSTATUS.modify(MSTATUS::MIE::CLEAR);
|
||||
} else {
|
||||
MSTATUS.modify(MSTATUS::MIE::SET);
|
||||
}
|
||||
old
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn interrupt_mask() -> bool {
|
||||
MSTATUS.matches_all(MSTATUS::MIE::SET)
|
||||
}
|
||||
|
||||
fn wait_for_interrupt() {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn cpu_count() -> usize {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn cpu_index<S: Scheduler + 'static>() -> u32 {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn cpu_enabled_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||
let _ = cpu;
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn cpu_available_features<S: Scheduler>(cpu: &CpuImpl<Self, S>) -> Option<&Self::CpuFeatures> {
|
||||
let _ = cpu;
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn local_interrupt_controller() -> Option<&'static dyn LocalInterruptController> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn message_interrupt_controller() -> Option<&'static dyn MessageInterruptController> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn idle_task() -> extern "C" fn(usize) -> ! {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use kernel_arch_interface::{
|
||||
mem::{DeviceMemoryAttributes, KernelTableManager, RawDeviceMemoryMapping},
|
||||
split_spinlock,
|
||||
};
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
process::ProcessAddressSpaceManager,
|
||||
table::{page_index, MapAttributes, TableAllocator},
|
||||
};
|
||||
use static_assertions::const_assert_eq;
|
||||
use table::{L1, L2};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
pub use memtables::riscv64::FixedTables;
|
||||
|
||||
pub mod table;
|
||||
|
||||
split_spinlock! {
|
||||
use crate::ArchitectureImpl;
|
||||
use crate::mem::FixedTables;
|
||||
use libk_mm_interface::KernelImageObject;
|
||||
|
||||
#[link_section = ".data.tables"]
|
||||
#[used]
|
||||
static KERNEL_TABLES: KernelImageObject<FixedTables> =
|
||||
unsafe { KernelImageObject::new(FixedTables::zeroed()) };
|
||||
}
|
||||
|
||||
pub const KERNEL_VIRT_OFFSET: usize = 0xFFFFFFF0_00000000;
|
||||
pub const KERNEL_PHYS_BASE: usize = 0x80000000;
|
||||
pub const SIGN_EXTEND_MASK: usize = 0xFFFFFFC0_00000000;
|
||||
|
||||
pub const KERNEL_START_L1I: usize = page_index::<L1>(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
||||
pub const KERNEL_L2I: usize = page_index::<L2>(KERNEL_VIRT_OFFSET + KERNEL_PHYS_BASE);
|
||||
const_assert_eq!(KERNEL_START_L1I, 450);
|
||||
const_assert_eq!(KERNEL_L2I, 0);
|
||||
|
||||
/// Any VAs above this one are sign-extended
|
||||
pub const USER_BOUNDARY: usize = 0x40_00000000;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct KernelTableManagerImpl;
|
||||
|
||||
pub struct ProcessAddressSpaceImpl<TA: TableAllocator> {
|
||||
_pd: PhantomData<TA>,
|
||||
}
|
||||
|
||||
impl KernelTableManager for KernelTableManagerImpl {
|
||||
fn virtualize(phys: u64) -> usize {
|
||||
let _ = phys;
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn physicalize(virt: usize) -> u64 {
|
||||
let _ = virt;
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn map_device_pages(
|
||||
base: u64,
|
||||
count: usize,
|
||||
attrs: DeviceMemoryAttributes,
|
||||
) -> Result<RawDeviceMemoryMapping<Self>, Error> {
|
||||
let _ = base;
|
||||
let _ = count;
|
||||
let _ = attrs;
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn unmap_device_pages(mapping: &RawDeviceMemoryMapping<Self>) {
|
||||
let _ = mapping;
|
||||
loop {}
|
||||
}
|
||||
|
||||
unsafe fn unmap_physical_address(virt: usize) {
|
||||
let _ = virt;
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceImpl<TA> {
|
||||
const LOWER_LIMIT_PFN: usize = 0;
|
||||
const UPPER_LIMIT_PFN: usize = 0;
|
||||
|
||||
fn new() -> Result<Self, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn map_page(
|
||||
&mut self,
|
||||
address: usize,
|
||||
physical: PhysicalAddress,
|
||||
flags: MapAttributes,
|
||||
) -> Result<(), Error> {
|
||||
let _ = address;
|
||||
let _ = physical;
|
||||
let _ = flags;
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn unmap_page(&mut self, address: usize) -> Result<PhysicalAddress, Error> {
|
||||
let _ = address;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn translate(&self, address: usize) -> Result<(PhysicalAddress, MapAttributes), Error> {
|
||||
let _ = address;
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn as_address_with_asid(&self) -> u64 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn clear(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
use core::{
|
||||
marker::PhantomData,
|
||||
ops::{Index, IndexMut},
|
||||
};
|
||||
|
||||
use bitflags::bitflags;
|
||||
use libk_mm_interface::{
|
||||
address::PhysicalAddress,
|
||||
pointer::{PhysicalRef, PhysicalRefMut},
|
||||
table::{EntryLevel, NextPageTable, NonTerminalEntryLevel, TableAllocator},
|
||||
};
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use super::KernelTableManagerImpl;
|
||||
|
||||
bitflags! {
|
||||
pub struct PageAttributes: u64 {
|
||||
const N = 1 << 63;
|
||||
/// Dirty bit
|
||||
const D = 1 << 7;
|
||||
/// Access bit
|
||||
const A = 1 << 6;
|
||||
/// Global mapping bit, implies all lower levels are also global
|
||||
const G = 1 << 5;
|
||||
/// U-mode access permission
|
||||
const U = 1 << 4;
|
||||
/// Execute permission
|
||||
const X = 1 << 3;
|
||||
/// Write permission
|
||||
const W = 1 << 2;
|
||||
/// Read-permission
|
||||
const R = 1 << 1;
|
||||
/// Valid bit
|
||||
const V = 1 << 0;
|
||||
}
|
||||
|
||||
// X W R Meaning
|
||||
// 0 0 0 Pointer to next level of page table
|
||||
// 0 0 1 Read-only page
|
||||
// 0 1 0 ---
|
||||
// 0 1 1 Read-write page
|
||||
// 1 0 0 Execute only
|
||||
// 1 0 1 Read-execute page
|
||||
// 1 1 0 ---
|
||||
// 1 1 1 Read-write-execute page
|
||||
}
|
||||
|
||||
/// L3 - entry is 4KiB
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct L3;
|
||||
/// L2 - entry is 2MiB
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct L2;
|
||||
/// L1 - entry is 1GiB
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct L1;
|
||||
|
||||
impl EntryLevel for L3 {
|
||||
const SHIFT: usize = 12;
|
||||
}
|
||||
|
||||
impl EntryLevel for L2 {
|
||||
const SHIFT: usize = 21;
|
||||
}
|
||||
|
||||
impl EntryLevel for L1 {
|
||||
const SHIFT: usize = 30;
|
||||
}
|
||||
|
||||
#[repr(C, align(0x1000))]
|
||||
pub struct PageTable<L: EntryLevel> {
|
||||
entries: [PageEntry<L>; 512],
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct PageEntry<L: EntryLevel>(u64, PhantomData<L>);
|
||||
|
||||
impl NonTerminalEntryLevel for L1 {
|
||||
type NextLevel = L2;
|
||||
}
|
||||
impl NonTerminalEntryLevel for L2 {
|
||||
type NextLevel = L3;
|
||||
}
|
||||
|
||||
impl<L: EntryLevel> PageTable<L> {
|
||||
pub const fn zeroed() -> Self {
|
||||
Self {
|
||||
entries: [PageEntry::INVALID; 512],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: EntryLevel> PageEntry<L> {
|
||||
pub const INVALID: Self = Self(0, PhantomData);
|
||||
|
||||
pub const fn is_present(&self) -> bool {
|
||||
self.0 & PageAttributes::V.bits() != 0
|
||||
}
|
||||
|
||||
pub fn attributes(self) -> PageAttributes {
|
||||
PageAttributes::from_bits_retain(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: NonTerminalEntryLevel + 'static> NextPageTable for PageTable<L> {
|
||||
type NextLevel = PageTable<L::NextLevel>;
|
||||
type TableRef = PhysicalRef<'static, PageTable<L::NextLevel>, KernelTableManagerImpl>;
|
||||
type TableRefMut = PhysicalRefMut<'static, PageTable<L::NextLevel>, KernelTableManagerImpl>;
|
||||
|
||||
fn get(&self, _index: usize) -> Option<Self::TableRef> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn get_mut(&mut self, _index: usize) -> Option<Self::TableRefMut> {
|
||||
loop {}
|
||||
}
|
||||
|
||||
fn get_mut_or_alloc<TA: TableAllocator>(
|
||||
&mut self,
|
||||
_index: usize,
|
||||
) -> Result<Self::TableRefMut, Error> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: NonTerminalEntryLevel> PageEntry<L> {
|
||||
pub fn block(address: PhysicalAddress, attrs: PageAttributes) -> Self {
|
||||
// TODO validate address alignment
|
||||
Self(
|
||||
(address.into_u64() >> 2) | (PageAttributes::R | PageAttributes::V | attrs).bits(),
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn table(address: PhysicalAddress, mut attrs: PageAttributes) -> Self {
|
||||
attrs.remove(PageAttributes::R | PageAttributes::W | PageAttributes::X);
|
||||
Self(
|
||||
(address.into_u64() >> 2) | (PageAttributes::V | attrs).bits(),
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl PageEntry<L3> {
|
||||
pub fn page(address: PhysicalAddress, attrs: PageAttributes) -> Self {
|
||||
Self(
|
||||
(address.into_u64() >> 2) | (PageAttributes::R | PageAttributes::V | attrs).bits(),
|
||||
PhantomData,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn as_page(&self) -> Option<PhysicalAddress> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: EntryLevel> Index<usize> for PageTable<L> {
|
||||
type Output = PageEntry<L>;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.entries[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: EntryLevel> IndexMut<usize> for PageTable<L> {
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.entries[index]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
macro impl_csr_read($struct:ident, $repr:ty, $reg:ident, $register:ty) {
|
||||
impl tock_registers::interfaces::Readable for $struct {
|
||||
type T = $repr;
|
||||
type R = $register;
|
||||
|
||||
#[inline]
|
||||
fn get(&self) -> $repr {
|
||||
let mut value: $repr;
|
||||
unsafe {
|
||||
core::arch::asm!(concat!("csrr {0}, ", stringify!($reg)), out(reg) value);
|
||||
}
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
macro impl_csr_write($struct:ident, $repr:ty, $reg:ident, $register:ty) {
|
||||
impl tock_registers::interfaces::Writeable for $struct {
|
||||
type T = $repr;
|
||||
type R = $register;
|
||||
|
||||
#[inline]
|
||||
fn set(&self, value: $repr) {
|
||||
unsafe {
|
||||
core::arch::asm!(concat!("csrw ", stringify!($reg), ", {0}"), in(reg) value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub mod misa {
|
||||
use tock_registers::{interfaces::Readable, register_bitfields};
|
||||
|
||||
use super::{impl_csr_read, impl_csr_write};
|
||||
|
||||
register_bitfields!(
|
||||
u64,
|
||||
pub MISA [
|
||||
A OFFSET(0) NUMBITS(1) [],
|
||||
C OFFSET(2) NUMBITS(1) [],
|
||||
D OFFSET(3) NUMBITS(1) [],
|
||||
E OFFSET(4) NUMBITS(1) [],
|
||||
F OFFSET(5) NUMBITS(1) [],
|
||||
H OFFSET(6) NUMBITS(1) [],
|
||||
I OFFSET(7) NUMBITS(1) [],
|
||||
M OFFSET(12) NUMBITS(1) [],
|
||||
Q OFFSET(16) NUMBITS(1) [],
|
||||
S OFFSET(17) NUMBITS(1) [],
|
||||
U OFFSET(18) NUMBITS(1) [],
|
||||
X OFFSET(23) NUMBITS(1) [],
|
||||
]
|
||||
);
|
||||
|
||||
pub struct Reg;
|
||||
|
||||
impl_csr_read!(Reg, u64, misa, MISA::Register);
|
||||
impl_csr_write!(Reg, u64, misa, MISA::Register);
|
||||
|
||||
impl Reg {
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.get() != 0
|
||||
}
|
||||
}
|
||||
|
||||
pub const MISA: Reg = Reg;
|
||||
}
|
||||
|
||||
pub mod mstatus {
|
||||
use tock_registers::register_bitfields;
|
||||
|
||||
use super::{impl_csr_read, impl_csr_write};
|
||||
|
||||
register_bitfields!(
|
||||
u64,
|
||||
pub MSTATUS [
|
||||
/// Interrupt enable for S-mode
|
||||
SIE OFFSET(1) NUMBITS(1) [],
|
||||
/// Interrupt enable for M-mode
|
||||
MIE OFFSET(3) NUMBITS(1) [],
|
||||
/// Stored SIE state on S-mode trap delegation
|
||||
SPIE OFFSET(5) NUMBITS(1) [],
|
||||
/// U-mode big endian
|
||||
UBE OFFSET(6) NUMBITS(1) [],
|
||||
/// TODO: something written here on trap to M-mode
|
||||
MPIE OFFSET(7) NUMBITS(1) [],
|
||||
/// TODO: something for nested traps
|
||||
SPP OFFSET(8) NUMBITS(1) [],
|
||||
/// Vector register dirty status
|
||||
VS OFFSET(9) NUMBITS(2) [],
|
||||
/// Original mode before being trapped into M-mode
|
||||
MPP OFFSET(11) NUMBITS(2) [
|
||||
U = 0,
|
||||
S = 1,
|
||||
M = 3
|
||||
],
|
||||
/// Float register dirty status
|
||||
FS OFFSET(13) NUMBITS(2) [],
|
||||
/// U-mode extension dirty status
|
||||
XS OFFSET(15) NUMBITS(2) [],
|
||||
/// Effective privilege mode at which loads and stores execute.
|
||||
///
|
||||
/// When MPRV = 0, loads and stores behave as normal
|
||||
/// MPRV = 1, loads/stores are translated and protected
|
||||
MPRV OFFSET(17) NUMBITS(1) [],
|
||||
/// Permit supervisor user memory access
|
||||
///
|
||||
/// When SUM = 0, S-mode access to pages accessible by U-mode will fault
|
||||
SUM OFFSET(18) NUMBITS(1) [],
|
||||
MXR OFFSET(19) NUMBITS(1) [],
|
||||
/// Trap virtual memory
|
||||
///
|
||||
/// When TVM = 1, attempts to read/write satp CSR, execute sfence.vma or sinval.vma
|
||||
/// in S-mode will raise an illegal instruction exception
|
||||
TVM OFFSET(20) NUMBITS(1) [],
|
||||
/// Timeout wait
|
||||
///
|
||||
/// When TW = 1, wfi executed in lower privilege level which does not complete
|
||||
/// within some implementation-specific timeout, raises an illegal
|
||||
/// instruction exception
|
||||
TW OFFSET(21) NUMBITS(1) [],
|
||||
TSR OFFSET(22) NUMBITS(1) [],
|
||||
/// U-mode XLEN value
|
||||
UXL OFFSET(32) NUMBITS(2) [],
|
||||
/// S-mode XLEN value
|
||||
SXL OFFSET(34) NUMBITS(2) [],
|
||||
/// S-mode big endian
|
||||
SBE OFFSET(36) NUMBITS(1) [],
|
||||
/// M-mode big endian
|
||||
MBE OFFSET(37) NUMBITS(1) [],
|
||||
SD OFFSET(63) NUMBITS(1) [],
|
||||
]
|
||||
);
|
||||
|
||||
pub struct Reg;
|
||||
|
||||
impl_csr_read!(Reg, u64, mstatus, MSTATUS::Register);
|
||||
impl_csr_write!(Reg, u64, mstatus, MSTATUS::Register);
|
||||
|
||||
pub const MSTATUS: Reg = Reg;
|
||||
}
|
||||
|
||||
pub mod mepc {
|
||||
use super::{impl_csr_read, impl_csr_write};
|
||||
|
||||
pub struct Reg;
|
||||
|
||||
impl_csr_read!(Reg, u64, mepc, ());
|
||||
impl_csr_write!(Reg, u64, mepc, ());
|
||||
|
||||
pub const MEPC: Reg = Reg;
|
||||
}
|
||||
|
||||
pub mod satp {
|
||||
use tock_registers::register_bitfields;
|
||||
|
||||
use super::{impl_csr_read, impl_csr_write};
|
||||
|
||||
register_bitfields!(
|
||||
u64,
|
||||
pub SATP [
|
||||
PPN OFFSET(0) NUMBITS(44) [],
|
||||
ASID OFFSET(44) NUMBITS(16) [],
|
||||
MODE OFFSET(60) NUMBITS(4) [
|
||||
Bare = 0,
|
||||
Sv39 = 8,
|
||||
Sv48 = 9,
|
||||
Sv57 = 10,
|
||||
Sv64 = 11,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
pub struct Reg;
|
||||
|
||||
impl_csr_read!(Reg, u64, satp, SATP::Register);
|
||||
impl_csr_write!(Reg, u64, satp, SATP::Register);
|
||||
|
||||
pub const SATP: Reg = Reg;
|
||||
}
|
||||
|
||||
pub use mepc::MEPC;
|
||||
pub use misa::MISA;
|
||||
pub use mstatus::MSTATUS;
|
||||
pub use satp::SATP;
|
||||
Reference in New Issue
Block a user