diff --git a/.gitignore b/.gitignore index 173ea40..e7c664c 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ Cargo.lock # MSVC Windows builds of rustc generate these, which store debugging information *.pdb .devenv + +# Vim swap files +*.swp diff --git a/Cargo.toml b/Cargo.toml index b6deba5..a287a6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,4 @@ authors = ["Théo Abel ", "Nathan Dandrimont Result; + fn is_mmu_equivalent_to(&self, other: &Self) -> bool; } /// Represents a page table entry with an address and flags. /// It holds the mapping between a virtual address of a page and the address of a physical frame. /// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, /// address space or process ID information, amongst others. -pub trait PageTableEntry { +pub trait PageTableEntryTrait { type Address: hash::Hash + Eq + Default; type Flags: hash::Hash + Eq + Default; + type Size: hash::Hash + Eq + Default; fn is_dirty(&self) -> bool; fn is_accessed(&self) -> bool; @@ -117,12 +119,36 @@ pub trait PageTableEntry { /// It is a data structure used in a virtual memory system to manage the mapping between virtual addresses and physical addresses. /// It is used to translate virtual addresses to physical addresses and to manage the memory permissions of the pages. /// It is also used to store additional information about the pages, such as the status of the page, the address space or process ID, amongst others. -pub trait PageTable { - type Entries: hash::Hash + Eq + Default + PageTableEntry; +pub trait PageTableTrait { + type Entries: hash::Hash + Eq + Default + PageTableEntryTrait; // fn apply_on_entries(function: FnMut(PageTableEntry) -> Vec ) -> ? // FIXME: to be defined, but is it necessary? } +/// Represents a generic page table entry. +/// It holds the mapping between a virtual address of a page and the address of a physical frame. +/// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, +/// address space or process ID information, amongst others. +#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] +pub struct PageTableEntry { + pub address: A, + pub flags: F, + pub size: S, +} + +/// Represents a generic page table. +/// A page table is the data structure used by a virtual memory system in a computer operating system to store the mapping between virtual addresses and physical addresses. +pub struct PageTable { + /// Physical address of the page table + pub address: A, + /// Size of the page table + pub size: A, + /// Entries in the page table + pub entries: Vec>, + /// Number of levels in the page table + pub levels: u8, +} + /// Enumerates types of supported machines. /// This enum is used to specify the type of machine that is being parsed. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] @@ -176,4 +202,21 @@ impl Machine { outfolder, }) } + + pub fn resolve_spaces(&mut self) -> Result<&mut Self> { + todo!() + } +} + +pub trait MMU { + type Address: hash::Hash + Eq + Default; + type Flags: hash::Hash + Eq + Default; + type Size: hash::Hash + Eq + Default; + + fn classify_entry< + T: PageTableEntryTrait
, + >( + &self, + entry: T, + ) -> Result; } diff --git a/src/architecture/riscv.rs b/src/architecture/riscv.rs index 74444c1..40eeec6 100644 --- a/src/architecture/riscv.rs +++ b/src/architecture/riscv.rs @@ -1,6 +1,9 @@ -use super::generic::{CPURegister as CPURegisterTrait, PageTableEntry as PageTableEntryTrait}; +use super::generic::{ + CPURegister as CPURegisterTrait, PageTable, PageTableEntry, PageTableEntryTrait, +}; use anyhow::Result; +use bitfield::bitfield; use serde::{Deserialize, Serialize}; /// Represents a RISC-V CPU register associated with a value. @@ -15,6 +18,11 @@ impl CPURegisterTrait for CPURegister { fn is_valid(&self) -> Result { todo!() } + + #[allow(unused_variables)] + fn is_mmu_equivalent_to(&self, other: &Self) -> bool { + todo!() + } } impl CPURegister { @@ -23,56 +31,164 @@ impl CPURegister { } } -/// Represents a RISC-V page table entry. -/// It holds the mapping between a virtual address of a page and the address of a physical frame. -/// There is also auxiliary information about the page such as a present bit, a dirty or modified bit, -/// address space or process ID information, amongst others. -#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd)] -pub struct PageTableEntry { - pub address: u64, - pub flags: u64, +bitfield! { + /// Represents a RISC-V SV32 page table entry flags. + /// The flags are used to determine the permissions of a page, or some other attributes. + /// This is baed on the RISC-V Sv39 page table entry flags. + /// All fields are read-only. + #[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] + pub struct PTE32Flags(u32); + + pub read, _: 1; + pub write, _: 2; + pub exec, _: 3; + pub supervisor, _: 4; + pub global, _: 5; + pub accessed, _: 6; + pub dirty, _: 7; +} + +bitfield! { + /// Represents a RISC-V SV39 and SV48 page table entry flags. + /// The flags are used to determine the permissions of a page, or some other attributes. + /// This is baed on the RISC-V Sv39 page table entry flags. + /// All fields are read-only. + #[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] + pub struct PTE64Flags(u64); + + pub read, _: 1; + pub write, _: 2; + pub exec, _: 3; + pub supervisor, _: 4; + pub global, _: 5; + pub accessed, _: 6; + pub dirty, _: 7; +} + +/// Represents a RISC-V SV32 page table entry size. +#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] +pub enum PTE32Size { + /// 4 bytes + #[default] + PTP32, + /// 4KB, 1024 * 4 bytes + PTE4KB, + /// 4MB, 1024 * 1024 * 4 bytes + PTE4MB, } -impl PageTableEntry { - pub fn new(address: u64, flags: u64) -> Self { - Self { address, flags } +/// Represents a RISC-V SV39 and SV48 page table entry size. +#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq, Ord, PartialOrd, Default)] +pub enum PTE64Size { + /// 8 bytes + #[default] + PTP64, + /// 4KB, 512 * 8 bytes + PTE4KB, + /// 2MB, 256 * 8 bytes + PTE2MB, + /// 1GB, 128 * 8 bytes + PTE1GB, + /// 512GB, 64 * 8 bytes + /// This is only available in Sv48 + PTE512GB, +} + +impl PageTableEntry { + pub fn new(address: u32, flags: u32, size: PTE32Size) -> Self { + let flags = PTE32Flags(flags); + Self { + address, + flags, + size, + } } pub fn is_supervisor(&self) -> bool { - todo!() + self.flags.supervisor() } } -impl PageTableEntryTrait for PageTableEntry { +impl PageTableEntryTrait for PageTableEntry { + type Address = u32; + type Flags = PTE32Flags; + type Size = PTE32Size; + + fn is_dirty(&self) -> bool { + self.flags.dirty() + } + + fn is_accessed(&self) -> bool { + self.flags.accessed() + } + + fn is_global(&self) -> bool { + self.flags.global() + } + + fn is_readable(&self) -> bool { + self.flags.read() + } + + fn is_writable(&self) -> bool { + self.flags.write() + } + + fn is_executable(&self) -> bool { + self.flags.exec() + } +} + +impl PageTableEntry { + pub fn new(address: u64, flags: u64, size: PTE64Size) -> Self { + let flags = PTE64Flags(flags); + Self { + address, + flags, + size, + } + } + + pub fn is_supervisor(&self) -> bool { + self.flags.supervisor() + } +} + +impl PageTableEntryTrait for PageTableEntry { type Address = u64; - type Flags = u64; + type Flags = PTE64Flags; + type Size = PTE64Size; - // FIXME: Implement the following methods fn is_dirty(&self) -> bool { - todo!() + self.flags.dirty() } fn is_accessed(&self) -> bool { - todo!() + self.flags.accessed() } fn is_global(&self) -> bool { - todo!() + self.flags.global() } fn is_readable(&self) -> bool { - todo!() + self.flags.read() } fn is_writable(&self) -> bool { - todo!() + self.flags.write() } fn is_executable(&self) -> bool { - todo!() + self.flags.exec() } } +/// Represents a RISC-V SV32 page table. +pub type PageTable32 = PageTable; +/// Represents a RISC-V SV39 and SV48 page table. +pub type PageTable64 = PageTable; + /// Enumerates RISC-V MMU modes. /// The MMU modes are used to determine the number of bits used for virtual and physical addresses. /// The modes are named after the number of bits used for the virtual address space. @@ -109,3 +225,8 @@ impl MMU { Self { mode } } } + +/// Represents a MMU that uses a radix tree. +pub struct MMURadixTree32 { + pub nb_radix_levels: u8, +}