Skip to content

Commit

Permalink
Move PhysAddr and PhysRange to port
Browse files Browse the repository at this point in the history
Signed-off-by: Graham MacDonald <[email protected]>
  • Loading branch information
gmacd committed Jan 31, 2024
1 parent e176e4f commit 1d30c10
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 169 deletions.
7 changes: 5 additions & 2 deletions aarch64/src/kalloc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use crate::vm::{Page4K, PAGE_SIZE_4K};
use crate::vm::Page4K;
use core::ptr;
use port::mcslock::{Lock, LockNode};
use port::{
mcslock::{Lock, LockNode},
mem::PAGE_SIZE_4K,
};

static FREE_LIST: Lock<FreeList> = Lock::new("kmem", FreeList { next: None });

Expand Down
155 changes: 10 additions & 145 deletions aarch64/src/kmem.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
use port::fdt::RegBlock;
use port::mem::PhysAddr;

use crate::{param::KZERO, vm::Page4K};
use core::{
fmt,
iter::{Step, StepBy},
mem,
ops::{self, Range},
slice,
};
use core::{mem, slice};

// These map to definitions in kernel.ld
extern "C" {
Expand Down Expand Up @@ -42,119 +36,20 @@ pub fn eearly_pagetables_addr() -> usize {
unsafe { eearly_pagetables.as_ptr().addr() }
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
#[repr(transparent)]
pub struct PhysAddr(u64);

impl PhysAddr {
pub const fn new(value: u64) -> Self {
PhysAddr(value)
}

pub const fn addr(&self) -> u64 {
self.0
}

pub const fn as_virt(&self) -> usize {
(self.0 as usize).wrapping_add(KZERO)
}

pub fn from_virt(a: usize) -> Self {
Self((a - KZERO) as u64)
}

pub fn from_ptr<T>(a: *const T) -> Self {
Self::from_virt(a.addr())
}

pub const fn as_ptr_mut<T>(&self) -> *mut T {
self.as_virt() as *mut T
}

pub const fn round_up(&self, step: u64) -> PhysAddr {
PhysAddr((self.0 + step - 1) & !(step - 1))
}

pub const fn round_down(&self, step: u64) -> PhysAddr {
PhysAddr(self.0 & !(step - 1))
}
pub const fn physaddr_as_virt(pa: PhysAddr) -> usize {
(pa.addr() as usize).wrapping_add(KZERO)
}

impl ops::Add<u64> for PhysAddr {
type Output = PhysAddr;

fn add(self, offset: u64) -> PhysAddr {
PhysAddr(self.0 + offset)
}
pub const fn physaddr_as_ptr_mut<T>(pa: PhysAddr) -> *mut T {
physaddr_as_virt(pa) as *mut T
}

/// Note that this implementation will round down the startpa and round up the endpa
impl Step for PhysAddr {
fn steps_between(&startpa: &Self, &endpa: &Self) -> Option<usize> {
if startpa.0 <= endpa.0 {
match endpa.0.checked_sub(startpa.0) {
Some(result) => usize::try_from(result).ok(),
None => None,
}
} else {
None
}
}

fn forward_checked(startpa: Self, count: usize) -> Option<Self> {
startpa.0.checked_add(count as u64).map(PhysAddr)
}

fn backward_checked(startpa: Self, count: usize) -> Option<Self> {
startpa.0.checked_sub(count as u64).map(PhysAddr)
}
pub const fn from_virt_to_physaddr(va: usize) -> PhysAddr {
PhysAddr::new((va - KZERO) as u64)
}

impl fmt::Debug for PhysAddr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "PhysAddr({:#016x})", self.0)?;
Ok(())
}
}

pub struct PhysRange(pub Range<PhysAddr>);

impl PhysRange {
pub fn with_len(start: u64, len: usize) -> Self {
Self(PhysAddr(start)..PhysAddr(start + len as u64))
}

#[allow(dead_code)]
pub fn offset_addr(&self, offset: u64) -> Option<PhysAddr> {
let addr = self.0.start + offset;
if self.0.contains(&addr) {
Some(addr)
} else {
None
}
}

pub fn start(&self) -> PhysAddr {
self.0.start
}

pub fn end(&self) -> PhysAddr {
self.0.end
}

pub fn step_by_rounded(&self, step_size: usize) -> StepBy<Range<PhysAddr>> {
let startpa = self.start().round_down(step_size as u64);
let endpa = self.end().round_up(step_size as u64);
(startpa..endpa).step_by(step_size)
}
}

impl From<&RegBlock> for PhysRange {
fn from(r: &RegBlock) -> Self {
let start = PhysAddr(r.addr);
let end = start + r.len.unwrap_or(0);
PhysRange(start..end)
}
pub fn from_ptr_to_physaddr<T>(a: *const T) -> PhysAddr {
from_virt_to_physaddr(a.addr())
}

unsafe fn page_slice_mut<'a>(pstart: *mut Page4K, pend: *mut Page4K) -> &'a mut [Page4K] {
Expand All @@ -174,33 +69,3 @@ pub fn early_pages() -> &'static mut [Page4K] {
let early_end = eearly_pagetables_addr() as *mut Page4K;
unsafe { page_slice_mut(early_start, early_end) }
}

#[cfg(test)]
mod tests {
use super::*;
use crate::vm;

#[test]
fn physaddr_step() {
let range = PhysRange(PhysAddr::new(4096)..PhysAddr::new(4096 * 3));
let pas = range.step_by_rounded(vm::PAGE_SIZE_4K).collect::<Vec<PhysAddr>>();
assert_eq!(pas, [PhysAddr::new(4096), PhysAddr::new(4096 * 2)]);
}

#[test]
fn physaddr_step_rounds_up_and_down() {
// Start should round down to 8192
// End should round up to 16384
let range = PhysRange(PhysAddr::new(9000)..PhysAddr::new(5000 * 3));
let pas = range.step_by_rounded(vm::PAGE_SIZE_4K).collect::<Vec<PhysAddr>>();
assert_eq!(pas, [PhysAddr::new(4096 * 2), PhysAddr::new(4096 * 3)]);
}

#[test]
fn physaddr_step_2m() {
let range =
PhysRange(PhysAddr::new(0x3f000000)..PhysAddr::new(0x3f000000 + 4 * 1024 * 1024));
let pas = range.step_by_rounded(vm::PAGE_SIZE_2M).collect::<Vec<PhysAddr>>();
assert_eq!(pas, [PhysAddr::new(0x3f000000), PhysAddr::new(0x3f000000 + 2 * 1024 * 1024)]);
}
}
6 changes: 3 additions & 3 deletions aarch64/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#![feature(asm_const)]
#![feature(core_intrinsics)]
#![feature(stdsimd)]
#![feature(step_trait)]
#![feature(strict_provenance)]
#![forbid(unsafe_op_in_unsafe_fn)]

Expand All @@ -22,11 +21,12 @@ mod uartmini;
mod uartpl011;
mod vm;

use crate::kmem::{PhysAddr, PhysRange};
use crate::kmem::from_virt_to_physaddr;
use crate::vm::kernel_root;
use core::ffi::c_void;
use core::ptr;
use port::fdt::DeviceTree;
use port::mem::PhysRange;
use port::println;
use vm::PageTable;

Expand Down Expand Up @@ -123,7 +123,7 @@ pub extern "C" fn main9(dtb_va: usize) {
unsafe {
kalloc::free_pages(kmem::early_pages());

let dtb_range = PhysRange::with_len(PhysAddr::from_virt(dtb_va).addr(), dt.size());
let dtb_range = PhysRange::with_len(from_virt_to_physaddr(dtb_va).addr(), dt.size());
vm::init(&dt, &mut *ptr::addr_of_mut!(KPGTBL), dtb_range);
vm::switch(&*ptr::addr_of!(KPGTBL));
}
Expand Down
2 changes: 1 addition & 1 deletion aarch64/src/registers.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#![allow(non_upper_case_globals)]

use crate::{kmem::PhysRange, vm::PAGE_SIZE_2M};
use bitstruct::bitstruct;
use core::fmt;
use num_enum::TryFromPrimitive;
use port::mem::{PhysRange, PAGE_SIZE_2M};

// GPIO registers
pub const GPFSEL1: usize = 0x04; // GPIO function select register 1
Expand Down
3 changes: 2 additions & 1 deletion aarch64/src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

extern crate alloc;

use crate::kmem::physaddr_as_virt;
use crate::registers::rpi_mmio;
use crate::uartmini::MiniUart;
use alloc::alloc::{GlobalAlloc, Layout};
Expand All @@ -16,7 +17,7 @@ use port::mem::VirtRange;
// - Add support for raspi4
#[panic_handler]
pub fn panic(info: &PanicInfo) -> ! {
let mmio = rpi_mmio().expect("mmio base detect failed").start().as_virt();
let mmio = physaddr_as_virt(rpi_mmio().expect("mmio base detect failed").start());

let gpio_range = VirtRange::with_len(mmio + 0x200000, 0xb4);
let aux_range = VirtRange::with_len(mmio + 0x215000, 0x8);
Expand Down
34 changes: 18 additions & 16 deletions aarch64/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,24 @@

use crate::{
kalloc,
kmem::{ebss_addr, erodata_addr, etext_addr, text_addr, PhysAddr, PhysRange},
kmem::{
ebss_addr, erodata_addr, etext_addr, from_ptr_to_physaddr, from_virt_to_physaddr,
physaddr_as_ptr_mut, physaddr_as_virt, text_addr,
},
registers::rpi_mmio,
};
use bitstruct::bitstruct;
use core::fmt;
use core::ptr::write_volatile;
use num_enum::{FromPrimitive, IntoPrimitive};
use port::fdt::DeviceTree;
use port::{
fdt::DeviceTree,
mem::{PhysAddr, PhysRange, PAGE_SIZE_1G, PAGE_SIZE_2M, PAGE_SIZE_4K},
};

#[cfg(not(test))]
use port::println;

pub const PAGE_SIZE_4K: usize = 4 << 10;
pub const PAGE_SIZE_2M: usize = 2 << 20;
pub const PAGE_SIZE_1G: usize = 1 << 30;

#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PageSize {
Expand Down Expand Up @@ -162,7 +164,7 @@ impl Entry {
}

fn virt_page_addr(self) -> usize {
self.phys_page_addr().as_virt()
physaddr_as_virt(self.phys_page_addr())
}

fn table(self, level: Level) -> bool {
Expand Down Expand Up @@ -312,7 +314,7 @@ impl Table {
// Create a new page table and write the entry into the parent table
let table = Self::alloc_pagetable()?;
entry = Entry::rw_kernel_data()
.with_phys_addr(PhysAddr::from_ptr(table))
.with_phys_addr(from_ptr_to_physaddr(table))
.with_page_or_table(true);
unsafe {
write_volatile(&mut self.entries[index], entry);
Expand Down Expand Up @@ -358,7 +360,7 @@ impl PageTable {
// TODO Only do this if self != kernel_root()
let old_recursive_entry = kernel_root().entries[511];
let temp_recursive_entry = Entry::rw_kernel_data()
.with_phys_addr(PhysAddr::from_ptr(self))
.with_phys_addr(from_ptr_to_physaddr(self))
.with_page_or_table(true);

unsafe {
Expand Down Expand Up @@ -413,7 +415,7 @@ impl PageTable {
let mut startva = None;
let mut endva = 0;
for pa in range.step_by_rounded(page_size.size()) {
let va = pa.as_virt();
let va = physaddr_as_virt(pa);
self.map_to(entry.with_phys_addr(pa), va, page_size)?;
startva.get_or_insert(va);
endva = va + page_size.size();
Expand Down Expand Up @@ -479,7 +481,7 @@ pub unsafe fn init(_dt: &DeviceTree, kpage_table: &mut PageTable, dtb_range: Phy
// Write the recursive entry
unsafe {
let entry = Entry::rw_kernel_data()
.with_phys_addr(PhysAddr::from_ptr(kpage_table))
.with_phys_addr(from_ptr_to_physaddr(kpage_table))
.with_page_or_table(true);
write_volatile(&mut kpage_table.entries[511], entry);
}
Expand All @@ -490,13 +492,13 @@ pub unsafe fn init(_dt: &DeviceTree, kpage_table: &mut PageTable, dtb_range: Phy
// in depth!
let custom_map = {
let text_range =
PhysRange(PhysAddr::from_virt(text_addr())..PhysAddr::from_virt(etext_addr()));
PhysRange(from_virt_to_physaddr(text_addr())..from_virt_to_physaddr(etext_addr()));
let data_range = PhysRange::with_len(
PhysAddr::from_virt(etext_addr()).addr(),
from_virt_to_physaddr(etext_addr()).addr(),
erodata_addr() - etext_addr(),
);
let bss_range = PhysRange::with_len(
PhysAddr::from_virt(erodata_addr()).addr(),
from_virt_to_physaddr(erodata_addr()).addr(),
ebss_addr() - erodata_addr(),
);

Expand Down Expand Up @@ -549,7 +551,7 @@ fn ttbr1_el1() -> u64 {
pub unsafe fn switch(kpage_table: &PageTable) {
#[cfg(not(test))]
unsafe {
let pt_phys = PhysAddr::from_ptr(kpage_table).addr();
let pt_phys = from_ptr_to_physaddr(kpage_table).addr();
// https://forum.osdev.org/viewtopic.php?t=36412&p=303237
core::arch::asm!(
"msr ttbr1_el1, {pt_phys}",
Expand Down Expand Up @@ -577,7 +579,7 @@ pub unsafe fn invalidate_all_tlb_entries() {

/// Return the root kernel page table
pub fn kernel_root() -> &'static mut PageTable {
unsafe { &mut *PhysAddr::new(ttbr1_el1()).as_ptr_mut::<PageTable>() }
unsafe { &mut *physaddr_as_ptr_mut::<PageTable>(PhysAddr::new(ttbr1_el1())) }
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions port/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(clippy::upper_case_acronyms)]
#![cfg_attr(not(any(test)), no_std)]
#![feature(maybe_uninit_slice)]
#![feature(step_trait)]
#![forbid(unsafe_op_in_unsafe_fn)]

pub mod dat;
Expand Down
Loading

0 comments on commit 1d30c10

Please sign in to comment.