Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simple bitmap page allocator #33

Merged
merged 1 commit into from
Feb 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 0 additions & 57 deletions aarch64/src/kalloc.rs

This file was deleted.

27 changes: 7 additions & 20 deletions aarch64/src/kmem.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use port::mem::PhysAddr;

use crate::{param::KZERO, vm::Page4K};
use core::{mem, slice};
use crate::param::KZERO;
use port::mem::{PhysAddr, PhysRange};

// These map to definitions in kernel.ld
extern "C" {
Expand Down Expand Up @@ -52,20 +50,9 @@ 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] {
let ustart = pstart.addr();
let uend = pend.addr();
const PAGE_SIZE: usize = mem::size_of::<Page4K>();
assert_eq!(ustart % PAGE_SIZE, 0, "page_slice_mut: unaligned start page");
assert_eq!(uend % PAGE_SIZE, 0, "page_slice_mut: unaligned end page");
assert!(ustart < uend, "page_slice_mut: bad range");

let len = (uend - ustart) / PAGE_SIZE;
unsafe { slice::from_raw_parts_mut(ustart as *mut Page4K, len) }
}

pub fn early_pages() -> &'static mut [Page4K] {
let early_start = early_pagetables_addr() as *mut Page4K;
let early_end = eearly_pagetables_addr() as *mut Page4K;
unsafe { page_slice_mut(early_start, early_end) }
pub fn early_pages_range() -> PhysRange {
PhysRange::new(
from_virt_to_physaddr(early_pagetables_addr()),
from_virt_to_physaddr(eearly_pagetables_addr()),
)
}
10 changes: 5 additions & 5 deletions aarch64/src/mailbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use core::mem;
use core::mem::MaybeUninit;
use port::fdt::DeviceTree;
use port::mcslock::{Lock, LockNode};
use port::mem::VirtRange;
use port::mem::{PhysAddr, PhysRange, VirtRange};

const MBOX_READ: usize = 0x00;
const MBOX_STATUS: usize = 0x18;
Expand Down Expand Up @@ -191,7 +191,7 @@ pub struct MemoryInfo {
pub end: u32,
}

pub fn get_arm_memory() -> MemoryInfo {
pub fn get_arm_memory() -> PhysRange {
let tags = Tag::<EmptyRequest> {
tag_id0: TagId::GetArmMemory,
tag_buffer_size0: 12,
Expand All @@ -204,10 +204,10 @@ pub fn get_arm_memory() -> MemoryInfo {
let size = res.size;
let end = start + size;

MemoryInfo { start, size, end }
PhysRange::new(PhysAddr::new(start as u64), PhysAddr::new(end as u64))
}

pub fn get_vc_memory() -> MemoryInfo {
pub fn get_vc_memory() -> PhysRange {
let tags = Tag::<EmptyRequest> {
tag_id0: TagId::GetVcMemory,
tag_buffer_size0: 12,
Expand All @@ -220,7 +220,7 @@ pub fn get_vc_memory() -> MemoryInfo {
let size = res.size;
let end = start + size;

MemoryInfo { start, size, end }
PhysRange::new(PhysAddr::new(start as u64), PhysAddr::new(end as u64))
}

pub fn get_firmware_revision() -> u32 {
Expand Down
28 changes: 17 additions & 11 deletions aarch64/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
#![feature(alloc_error_handler)]
#![feature(asm_const)]
#![feature(core_intrinsics)]
#![feature(inline_const)]
#![feature(stdsimd)]
#![feature(strict_provenance)]
#![forbid(unsafe_op_in_unsafe_fn)]

mod devcons;
mod io;
mod kalloc;
mod kmem;
mod mailbox;
mod pagealloc;
mod param;
mod registers;
mod trap;
Expand All @@ -39,7 +40,7 @@ unsafe fn print_memory_range(name: &str, start: &*const c_void, end: &*const c_v
let start = start as *const _ as u64;
let end = end as *const _ as u64;
let size = end - start;
println!(" {name}{start:#x}-{end:#x} ({size:#x})");
println!(" {name}{start:#x}..{end:#x} ({size:#x})");
}

fn print_binary_sections() {
Expand Down Expand Up @@ -67,12 +68,17 @@ fn print_binary_sections() {
}
}

fn print_physical_memory_map() {
fn print_memory_info() {
println!("Physical memory map:");
let mailbox::MemoryInfo { start, size, end } = mailbox::get_arm_memory();
println!(" Memory:\t{start:#018x}-{end:#018x} ({size:#x})");
let mailbox::MemoryInfo { start, size, end } = mailbox::get_vc_memory();
println!(" Video:\t{start:#018x}-{end:#018x} ({size:#x})");
let arm_mem = mailbox::get_arm_memory();
println!(" Memory:\t{arm_mem} ({:#x})", arm_mem.size());
let vc_mem = mailbox::get_vc_memory();
println!(" Video:\t{vc_mem} ({:#x})", vc_mem.size());

println!("Memory usage::");
let (used, total) = pagealloc::usage_bytes();
println!(" Used:\t\t{used:#016x}");
println!(" Total:\t{total:#016x}");
}

// https://github.com/raspberrypi/documentation/blob/develop/documentation/asciidoc/computers/raspberry-pi/revision-codes.adoc
Expand Down Expand Up @@ -121,15 +127,15 @@ pub extern "C" fn main9(dtb_va: usize) {

// Map address space accurately using rust VM code to manage page tables
unsafe {
kalloc::free_pages(kmem::early_pages());

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::init(&mut *ptr::addr_of_mut!(KPGTBL), dtb_range, mailbox::get_arm_memory());
vm::switch(&*ptr::addr_of!(KPGTBL));
}

// From this point we can use the global allocator

print_binary_sections();
print_physical_memory_map();
print_memory_info();
print_board_info();

kernel_root().print_recursive_tables();
Expand Down
73 changes: 73 additions & 0 deletions aarch64/src/pagealloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/// This module acts as an interface between the portable allocator and the
/// arch-specific use of it.
///
/// The page allocator is constructed and finalised in a number of phases:
/// 1. `init_page_allocator` to create a fixed size allocator assuming everything
/// is in use except a small number of statically defined pages available for
/// setting up the initial page tables.
/// 2. `free_unused_ranges` to mark available ranges as the inverse of the
/// physical memory map within the bounds of the available memory.
use crate::kmem;
use crate::kmem::physaddr_as_ptr_mut;
use crate::vm::Page4K;
use port::bitmapalloc::BitmapPageAlloc;
use port::bitmapalloc::BitmapPageAllocError;
use port::mem::PhysRange;
use port::{
mcslock::{Lock, LockNode},
mem::PAGE_SIZE_4K,
};

/// Set up bitmap page allocator assuming everything is allocated.
static PAGE_ALLOC: Lock<BitmapPageAlloc<16, PAGE_SIZE_4K>> = Lock::new(
"page_alloc",
const { BitmapPageAlloc::<16, PAGE_SIZE_4K>::new_all_allocated(PAGE_SIZE_4K) },
);

/// The bitmap allocator has all pages marked as allocated initially. We'll
/// add some pages (mark free) to allow us to set up the page tables and build
/// a memory map. Once the memory map has been build, we can mark all the unused
/// space as available. This allows us to use only one page allocator throughout.
pub fn init_page_allocator() {
let node = LockNode::new();
let mut lock = PAGE_ALLOC.lock(&node);
let page_alloc = &mut *lock;

let early_pages_range = kmem::early_pages_range();
if let Err(err) = page_alloc.mark_free(&early_pages_range) {
panic!("Couldn't mark early pages free: range: {} err: {:?}", early_pages_range, err);
}
}

/// Free unused pages in mem that aren't covered by the memory map. Assumes
/// that custom_map is sorted.
pub fn free_unused_ranges<'a>(
available_mem: &PhysRange,
used_ranges: impl Iterator<Item = &'a PhysRange>,
) -> Result<(), BitmapPageAllocError> {
let node = LockNode::new();
let mut lock = PAGE_ALLOC.lock(&node);
let page_alloc = &mut *lock;

page_alloc.free_unused_ranges(available_mem, used_ranges)
}

/// Try to allocate a page
pub fn allocate() -> Result<&'static mut Page4K, BitmapPageAllocError> {
let node = LockNode::new();
let mut lock = PAGE_ALLOC.lock(&node);
let page_alloc = &mut *lock;

match page_alloc.allocate() {
Ok(page_pa) => Ok(unsafe { &mut *physaddr_as_ptr_mut::<Page4K>(page_pa) }),
Err(err) => Err(err),
}
}

/// Return a tuple of (bytes used, total bytes available) based on the page allocator.
pub fn usage_bytes() -> (usize, usize) {
let node = LockNode::new();
let mut lock = PAGE_ALLOC.lock(&node);
let page_alloc = &mut *lock;
page_alloc.usage_bytes()
}
1 change: 0 additions & 1 deletion aarch64/src/uartmini.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::registers::{
/// MiniUart is assigned to UART1 on the Raspberry Pi. It is easier to use with
/// real hardware, as it requires no additional configuration. Conversely, it's
/// harded to use with QEMU, as it can't be used with the `nographic` switch.
#[allow(dead_code)]
pub struct MiniUart {
pub gpio_range: VirtRange,
pub aux_range: VirtRange,
Expand Down
Loading
Loading