chore: move mm into vspace

This commit is contained in:
Paul Pan 2024-03-23 16:45:24 +08:00
parent ac4a9bf6ec
commit c210a049cd
18 changed files with 73 additions and 474 deletions

114
kernel/Cargo.lock generated
View File

@ -6,7 +6,7 @@ version = 3
name = "api"
version = "0.1.0"
dependencies = [
"num-derive 0.4.2",
"num-derive",
"num-traits",
]
@ -30,9 +30,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "cfg-if"
@ -53,50 +53,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
[[package]]
name = "endian-type-rs"
version = "0.1.4"
name = "fdt"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6419a5c75e40011b9fe0174db3fe24006ab122fbe1b7e9cc5974b338a755c76"
[[package]]
name = "fallible-iterator"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
[[package]]
name = "fdt-rs"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "581d3afdd654deb68c19fcbe4bc411910cc64067d4a13d8637bda7722cb9c2ea"
dependencies = [
"endian-type-rs",
"fallible-iterator",
"memoffset",
"num-derive 0.3.3",
"num-traits",
"rustc_version",
"static_assertions",
"unsafe_unwrap",
]
checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "kernel"
version = "0.1.0"
dependencies = [
"api",
"bitflags 2.4.2",
"bitflags 2.5.0",
"cfg-if",
"fdt-rs",
"fdt",
"lazy_static",
"log",
"num-derive 0.4.2",
"num-derive",
"num-traits",
"riscv",
"sbi-rt",
"spin 0.9.8",
"static_assertions",
"uart_16550",
"vspace",
]
[[package]]
@ -120,29 +99,9 @@ dependencies = [
[[package]]
name = "log"
version = "0.4.20"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "memoffset"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa"
dependencies = [
"autocfg",
]
[[package]]
name = "num-derive"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "num-derive"
@ -152,7 +111,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.50",
"syn",
]
[[package]]
@ -166,9 +125,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
@ -201,15 +160,6 @@ dependencies = [
"embedded-hal",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "rustversion"
version = "1.0.14"
@ -237,21 +187,6 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "spin"
version = "0.5.2"
@ -275,20 +210,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.109"
version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [
"proc-macro2",
"quote",
@ -313,10 +237,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "unsafe_unwrap"
name = "vspace"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1230ec65f13e0f9b28d789da20d2d419511893ea9dac2c1f4ef67b8b14e5da80"
[[package]]
name = "x86"

View File

@ -28,10 +28,11 @@ lto = "thin"
[dependencies]
api = { path = "../api" }
vspace = { path = "../lib/vspace" }
bitflags = "2.4.2"
cfg-if = "1.0.0"
fdt-rs = { version = "0.4.5", default-features = false }
fdt = "0.1"
lazy_static = { version = "1.4.0", features = ["spin_no_std"] }
log = "0.4"
num-derive = "0.4"

View File

@ -1,7 +1,6 @@
pub use super::mm::page::PAGE_SIZE;
pub const KERNEL_MEM_START: usize = 0x8030_0000;
use crate::utils::extern_addr::ExternSymbol;
extern "C" {
static __kernel_end: u8;
static __kernel_start: ExternSymbol;
static __kernel_end: ExternSymbol;
}

View File

@ -4,19 +4,16 @@ ENTRY(_start)
BASE_ADDRESS = 0x80200000;
PAGE_SIZE = 0x1000;
MEMORY {
DRAM : ORIGIN = BASE_ADDRESS, LENGTH = 16M
}
SECTIONS {
. = BASE_ADDRESS;
__kernel_start = .;
.text : {
__text_start = .;
*(.text.entry)
*(.text .text.*)
__text_end = .;
} > DRAM
}
.rodata : {
. = ALIGN(8);
@ -24,7 +21,7 @@ SECTIONS {
*(.rodata .rodata.*)
*(.srodata .srodata.*)
__rodata_end = .;
} > DRAM
}
.data : {
. = ALIGN(8);
@ -32,7 +29,7 @@ SECTIONS {
*(.data .data.*)
*(.sdata .sdata.*)
__data_end = .;
} > DRAM
}
.bss : {
. = ALIGN(8);
@ -43,12 +40,13 @@ SECTIONS {
*(.bss .bss.*)
*(.sbss .sbss.*)
__bss_end = .;
} > DRAM
/DISCARD/ : {
*(.eh_frame)
}
. = ALIGN(PAGE_SIZE);
__kernel_end = .;
/DISCARD/ : {
*(.eh_frame_hdr)
*(.eh_frame)
}
}

View File

@ -16,6 +16,5 @@ mod cpu;
mod entry;
pub mod layout;
mod lowlevel;
mod mm;
mod timer;
pub mod trap;

View File

@ -3,6 +3,7 @@
#![no_main]
// Features
#![feature(asm_const)]
#![feature(extern_types)]
#![feature(let_chains)]
#![feature(naked_functions)]
#![feature(panic_info_message)]
@ -24,9 +25,6 @@ pub mod lang;
// entrypoint
pub mod entry;
// page table
pub mod mm;
// plat
pub mod plat;

View File

@ -1,115 +0,0 @@
pub trait BitmapOps: Copy + Clone {
const CAPACITY: usize;
const DEFAULT: Self;
// a workaround for const fn new()
fn alloc(&mut self) -> Option<usize>;
fn dealloc(&mut self, index: usize);
}
const BITS_PER_LEVEL: usize = 32;
#[derive(Copy, Clone)]
pub struct Bitmap32(u32);
impl BitmapOps for Bitmap32 {
const CAPACITY: usize = u32::BITS as usize;
const DEFAULT: Self = Self(0);
fn alloc(&mut self) -> Option<usize> {
// fast-path
let i = self.0.trailing_zeros() as usize;
if i > 0 {
self.0 |= 1u32 << (i - 1);
return Some(i - 1);
}
// check full
if self.0 == u32::MAX {
return None;
}
// slow-path
for i in (0..BITS_PER_LEVEL).rev() {
if self.0 & (1 << i) == 0 {
self.0 |= 1 << i;
return Some(i);
}
}
None
}
fn dealloc(&mut self, index: usize) {
if index < BITS_PER_LEVEL {
self.0 &= !(1 << index);
}
}
}
#[derive(Copy, Clone)]
pub struct Bitmap<B: BitmapOps> {
bits: u32,
next: [B; BITS_PER_LEVEL],
}
impl<B: BitmapOps> BitmapOps for Bitmap<B> {
const CAPACITY: usize = BITS_PER_LEVEL * B::CAPACITY;
const DEFAULT: Self = Self {
bits: 0,
next: [B::DEFAULT; BITS_PER_LEVEL],
};
fn alloc(&mut self) -> Option<usize> {
if self.bits == u32::MAX {
return None;
}
// fast-path
loop {
let i = self.bits.leading_zeros() as usize;
if i == 0 {
break;
}
if let Some(index) = self.alloc_index(i - 1) {
return Some(index);
}
}
// slow-path
for i in (0..BITS_PER_LEVEL).rev() {
if self.bits & (1 << i) == 0 {
if let Some(index) = self.alloc_index(i) {
return Some(index);
}
}
}
None
}
fn dealloc(&mut self, index: usize) {
let i = index / B::CAPACITY;
if i < BITS_PER_LEVEL {
self.next[i].dealloc(index % B::CAPACITY);
self.bits &= !(1 << i);
}
}
}
impl<B: BitmapOps> Bitmap<B> {
fn alloc_index(&mut self, i: usize) -> Option<usize> {
if let Some(sub) = self.next[i].alloc() {
return Some(i * B::CAPACITY + sub);
}
self.bits |= 1 << i;
None
}
}
#[allow(unused)]
pub type Bitmap1K = Bitmap<Bitmap32>;
#[allow(unused)]
pub type Bitmap32K = Bitmap<Bitmap1K>;
#[allow(unused)]
pub type Bitmap1M = Bitmap<Bitmap32K>;

View File

@ -1,84 +0,0 @@
use cfg_if::cfg_if;
use log::trace;
use spin::mutex::SpinMutex;
use crate::arch::layout::*;
use crate::mm::addr::{AddressOps, PhysAddr};
cfg_if! {
if #[cfg(feature = "frame_bitmap")] {
use crate::mm::bitmap::{Bitmap1K, BitmapOps};
// 1k * 4k = 4MB, currently enough for kernel data
static ALLOCATOR: SpinMutex<Bitmap1K> = SpinMutex::new(Bitmap1K::DEFAULT);
} else { // fallback to freelist
use lazy_static::lazy_static;
use crate::mm::freelist::FreeList;
lazy_static! {
static ref ALLOCATOR: SpinMutex<FreeList> = {
let mut list = FreeList::new();
for i in 0..1024 {
let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START);
list.push(addr.into());
}
SpinMutex::new(list)
};
}
}
}
pub struct FrameAllocator;
impl FrameAllocator {
pub fn alloc(&self) -> Option<PhysAddr> {
cfg_if! {
if #[cfg(feature = "frame_bitmap")] {
let addr = ALLOCATOR
.lock()
.alloc()
.map(|i| PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START));
} else {
let addr = ALLOCATOR.lock().pop().map(|addr| addr.into());
}
}
trace!("[mm/frame] alloc frame: {:?}", addr);
#[cfg(debug_assertions)]
fill_page(addr, 0xaa);
addr
}
pub fn dealloc(&self, addr: PhysAddr) {
debug_assert!(addr.is_aligned(PAGE_SIZE));
debug_assert!(addr.as_usize() >= KERNEL_MEM_START);
trace!("[mm/frame] dealloc frame: {:?}", addr);
#[cfg(debug_assertions)]
fill_page(Some(addr), 0x55);
cfg_if! {
if #[cfg(feature = "frame_bitmap")] {
ALLOCATOR
.lock()
.dealloc((addr.as_usize() - KERNEL_MEM_START) / PAGE_SIZE);
} else {
ALLOCATOR.lock().push(addr.into());
}
}
}
}
fn fill_page(addr: Option<PhysAddr>, val: u8) {
unsafe {
// fill with val
if let Some(addr) = addr {
core::ptr::write_bytes(addr.as_usize() as *mut u8, val, PAGE_SIZE);
}
}
}

View File

@ -1,94 +0,0 @@
use core::num::NonZeroUsize;
pub struct FreeList {
next: Option<NonZeroUsize>,
}
impl FreeList {
pub const fn new() -> Self {
Self { next: None }
}
pub fn push(&mut self, ptr: NonZeroUsize) {
unsafe {
let raw: *mut usize = ptr.get() as *mut usize;
*raw = self.next.map_or(0, |next| next.get());
}
self.next = Some(ptr);
}
pub fn pop(&mut self) -> Option<NonZeroUsize> {
let popped = self.next.take();
if let Some(next) = popped {
let raw: *const usize = next.get() as *const usize;
self.next = NonZeroUsize::new(unsafe { *raw });
}
popped
}
}
#[cfg(test)]
mod tests {
use crate::arch::layout::{KERNEL_MEM_START, PAGE_SIZE};
use crate::mm::addr::PhysAddr;
use super::*;
#[test_case]
fn test_freelist_serial() {
let mut list = FreeList::new();
for i in 0..1024 {
let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START);
list.push(addr.into());
}
for i in 0..1024 {
let addr: Option<PhysAddr> = list.pop().map(|addr| addr.into());
let expected = PhysAddr((1023 - i) * PAGE_SIZE + KERNEL_MEM_START);
assert_eq!(addr, Some(expected));
}
let addr: Option<PhysAddr> = list.pop().map(|addr| addr.into());
assert_eq!(addr, None);
for i in 0..1024 {
let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START);
list.push(addr.into());
}
}
#[test_case]
fn test_freelist_complex() {
let mut list = FreeList::new();
for i in 0..1024 {
let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START);
list.push(addr.into());
}
// pop 2 with 1 push
let mut cnt = 0;
for i in 0..1024 + 512 + 256 + 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 + 1 {
let addr: Option<PhysAddr> = list.pop().map(|addr| addr.into());
let expected = PhysAddr((1023 - cnt) * PAGE_SIZE + KERNEL_MEM_START);
assert_eq!(addr, Some(expected));
if i % 2 == 0 {
list.push(addr.unwrap().into());
} else {
cnt += 1;
}
}
let addr: Option<PhysAddr> = list.pop().map(|addr| addr.into());
assert_eq!(addr, None);
assert_eq!(cnt, 1024);
for i in 0..1024 {
let addr = PhysAddr((i * PAGE_SIZE) + KERNEL_MEM_START);
list.push(addr.into());
}
}
}

View File

@ -1,5 +0,0 @@
pub mod addr;
mod bitmap;
pub mod frame;
mod freelist;
pub mod page;

View File

@ -1,55 +0,0 @@
use core::marker::PhantomData;
use bitflags::bitflags;
use crate::mm::addr::{AddressOps, PhysAddr, VirtAddr};
#[derive(Debug)]
pub enum PagingError {
AddressNotAligned,
}
bitflags! {
pub struct MapAttr: usize {
const READABLE = 1 << 1;
const WRITABLE = 1 << 2;
const EXECUTABLE = 1 << 3;
const USER_ACCESSIBLE = 1 << 4;
}
}
pub trait PageTableEntry {
fn new_page(paddr: PhysAddr, attr: MapAttr) -> Self;
fn new_table(paddr: PhysAddr) -> Self;
fn addr(&self) -> PhysAddr;
fn attr(&self) -> MapAttr;
fn set_addr(&mut self, addr: PhysAddr);
fn set_attr(&mut self, attr: MapAttr);
fn is_valid(&self) -> bool;
}
pub trait PageSize {
// Arch should implement this
// For example, 4KiB / 2MiB / 1GiB in sv39
const SIZE: usize;
}
pub struct Page<S: PageSize> {
start_address: VirtAddr,
size: PhantomData<S>,
}
impl<S: PageSize> Page<S> {
pub const SIZE: usize = S::SIZE;
pub fn new(addr: VirtAddr) -> Self {
Self {
start_address: addr.align_down(Self::SIZE),
size: PhantomData,
}
}
}

View File

@ -21,7 +21,6 @@ use core::marker::PhantomData;
pub mod cap;
pub mod null;
pub mod untyped;
/// Cap is the high-level wrapper of RawCap, it's a typed reference to RawCap (which is untyped in Rust)
/// For the typed objects, we should bound it with an empty traits `KernelObject`

View File

@ -0,0 +1,19 @@
use vspace::addr::PhysAddr;
extern "C" {
pub type ExternSymbol;
}
impl ExternSymbol {
pub fn as_ptr(&'static self) -> *const u8 {
self as *const Self as *const u8
}
pub fn as_usize(&'static self) -> usize {
self.as_ptr() as usize
}
pub fn as_phys_addr(&'static self) -> PhysAddr {
PhysAddr::from(self.as_usize())
}
}

View File

@ -1 +1,2 @@
pub mod extern_addr;
pub mod function_name;

7
lib/vspace/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "vspace"
version = "0.1.0"

6
lib/vspace/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "vspace"
version = "0.1.0"
edition = "2021"
[dependencies]

View File

@ -1,7 +1,7 @@
use core::fmt::{Debug, Display, Formatter, LowerHex, Result, UpperHex};
use core::hash::Hash;
use core::num::NonZeroUsize;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::fmt::*;
use core::hash::*;
use core::num::*;
use core::ops::*;
#[inline(always)]
pub fn align_up(addr: usize, align: usize) -> usize {

3
lib/vspace/src/lib.rs Normal file
View File

@ -0,0 +1,3 @@
#![no_std]
pub mod addr;