mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
2 Commits
daf96a0c64
...
c210a049cd
Author | SHA1 | Date | |
---|---|---|---|
c210a049cd | |||
ac4a9bf6ec |
114
kernel/Cargo.lock
generated
114
kernel/Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,5 @@ mod cpu;
|
||||
mod entry;
|
||||
pub mod layout;
|
||||
mod lowlevel;
|
||||
mod mm;
|
||||
mod timer;
|
||||
pub mod trap;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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>;
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
pub mod addr;
|
||||
mod bitmap;
|
||||
pub mod frame;
|
||||
mod freelist;
|
||||
pub mod page;
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
@ -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`
|
||||
|
19
kernel/src/utils/extern_addr.rs
Normal file
19
kernel/src/utils/extern_addr.rs
Normal 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())
|
||||
}
|
||||
}
|
@ -1 +1,2 @@
|
||||
pub mod extern_addr;
|
||||
pub mod function_name;
|
||||
|
50
lib/cpio/Cargo.lock
generated
Normal file
50
lib/cpio/Cargo.lock
generated
Normal file
@ -0,0 +1,50 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "cpio"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.28"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
9
lib/cpio/Cargo.toml
Normal file
9
lib/cpio/Cargo.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "cpio"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
flate2 = "1.0"
|
268
lib/cpio/src/lib.rs
Normal file
268
lib/cpio/src/lib.rs
Normal file
@ -0,0 +1,268 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
// reference: https://man.archlinux.org/man/cpio.5.en#New_ASCII_Format
|
||||
// Reference: https://github.com/jcreekmore/cpio-rs/blob/master/src/newc.rs
|
||||
|
||||
const HEADER_LEN: usize = 110;
|
||||
const MAGIC_NEW_ASCII: [u8; 6] = *b"070701";
|
||||
const MAGIC_NEW_CRC: [u8; 6] = *b"070702";
|
||||
const TRAILER_NAME: &str = "TRAILER!!!";
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Entry {
|
||||
magic: [u8; 6], // 070701 or 070702
|
||||
ino: [u8; 8],
|
||||
mode: [u8; 8],
|
||||
uid: [u8; 8],
|
||||
gid: [u8; 8],
|
||||
nlink: [u8; 8],
|
||||
mtime: [u8; 8],
|
||||
file_size: [u8; 8],
|
||||
dev_major: [u8; 8],
|
||||
dev_minor: [u8; 8],
|
||||
rdev_major: [u8; 8],
|
||||
rdev_minor: [u8; 8],
|
||||
name_size: [u8; 8],
|
||||
check: [u8; 8],
|
||||
filename: [u8], // pointer to index filename and following content
|
||||
}
|
||||
|
||||
pub enum CpioMagic {
|
||||
NewAscii,
|
||||
NewCRC,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CpioError {
|
||||
InvalidEntry,
|
||||
InvalidMagic,
|
||||
InvalidChecksum,
|
||||
InvalidFilename,
|
||||
}
|
||||
|
||||
pub struct Reader<'a> {
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
fn read_hex_u32(b: &[u8; 8]) -> u32 {
|
||||
let s = core::str::from_utf8(b).unwrap();
|
||||
u32::from_str_radix(s, 16).unwrap()
|
||||
}
|
||||
|
||||
fn pad(len: usize, align: usize) -> usize {
|
||||
(len + align - 1) & !(align - 1)
|
||||
}
|
||||
|
||||
impl Entry {
|
||||
pub fn magic(&self) -> Result<CpioMagic, CpioError> {
|
||||
match self.magic {
|
||||
MAGIC_NEW_ASCII => Ok(CpioMagic::NewAscii),
|
||||
MAGIC_NEW_CRC => Ok(CpioMagic::NewCRC),
|
||||
_ => Err(CpioError::InvalidMagic),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ino(&self) -> u32 {
|
||||
read_hex_u32(&self.ino)
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> u32 {
|
||||
read_hex_u32(&self.mode)
|
||||
}
|
||||
|
||||
pub fn uid(&self) -> u32 {
|
||||
read_hex_u32(&self.uid)
|
||||
}
|
||||
|
||||
pub fn gid(&self) -> u32 {
|
||||
read_hex_u32(&self.gid)
|
||||
}
|
||||
|
||||
pub fn nlink(&self) -> u32 {
|
||||
read_hex_u32(&self.nlink)
|
||||
}
|
||||
|
||||
pub fn mtime(&self) -> u32 {
|
||||
read_hex_u32(&self.mtime)
|
||||
}
|
||||
|
||||
pub fn file_size(&self) -> u32 {
|
||||
read_hex_u32(&self.file_size)
|
||||
}
|
||||
|
||||
pub fn dev_major(&self) -> u32 {
|
||||
read_hex_u32(&self.dev_major)
|
||||
}
|
||||
|
||||
pub fn dev_minor(&self) -> u32 {
|
||||
read_hex_u32(&self.dev_minor)
|
||||
}
|
||||
|
||||
pub fn rdev_major(&self) -> u32 {
|
||||
read_hex_u32(&self.rdev_major)
|
||||
}
|
||||
|
||||
pub fn rdev_minor(&self) -> u32 {
|
||||
read_hex_u32(&self.rdev_minor)
|
||||
}
|
||||
|
||||
pub fn name_size(&self) -> u32 {
|
||||
read_hex_u32(&self.name_size)
|
||||
}
|
||||
|
||||
pub fn check(&self) -> u32 {
|
||||
read_hex_u32(&self.check)
|
||||
}
|
||||
|
||||
pub fn filename(&self) -> Result<&str, CpioError> {
|
||||
let len = self.name_size() as usize;
|
||||
core::str::from_utf8(&self.filename[..len - 1]).map_err(|_| CpioError::InvalidFilename)
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
let len = HEADER_LEN + self.name_size() as usize;
|
||||
let bgn = pad(len, 4) - HEADER_LEN;
|
||||
let end = bgn + self.file_size() as usize;
|
||||
&self.filename[bgn..end]
|
||||
}
|
||||
|
||||
pub fn total_size(&self) -> usize {
|
||||
pad(HEADER_LEN + self.name_size() as usize, 4) + self.file_size() as usize
|
||||
}
|
||||
|
||||
pub fn is_trailer(&self) -> bool {
|
||||
self.filename().map(|s| s == TRAILER_NAME).unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_valid(&self) -> bool {
|
||||
self.magic()
|
||||
.map(|magic| match magic {
|
||||
CpioMagic::NewAscii => self.check() == 0,
|
||||
CpioMagic::NewCRC => {
|
||||
self.data()
|
||||
.iter()
|
||||
.map(|&b| b as u32)
|
||||
.fold(0, |acc: u32, x| acc.wrapping_add(x))
|
||||
== self.check()
|
||||
},
|
||||
})
|
||||
.unwrap_or(false)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Reader<'a> {
|
||||
pub fn new(data: &'a [u8]) -> Self {
|
||||
Reader { data }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Reader<'a> {
|
||||
type Item = Result<&'a Entry, CpioError>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.data.len() < HEADER_LEN {
|
||||
return None;
|
||||
}
|
||||
|
||||
let entry = unsafe { &*(self.data as *const _ as *const Entry) };
|
||||
let entry_size = pad(entry.total_size(), 4);
|
||||
|
||||
if entry_size > self.data.len() {
|
||||
return Some(Err(CpioError::InvalidEntry));
|
||||
}
|
||||
if entry.is_trailer() {
|
||||
return None;
|
||||
}
|
||||
if !entry.is_valid() {
|
||||
return Some(Err(CpioError::InvalidChecksum));
|
||||
}
|
||||
self.data = &self.data[entry_size..];
|
||||
Some(Ok(entry))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use flate2::read::GzDecoder;
|
||||
use std::fs;
|
||||
use std::io::Read;
|
||||
|
||||
#[test]
|
||||
fn test_read_hex_u32() {
|
||||
assert_eq!(read_hex_u32(&[b'0'; 8]), 0x00000000);
|
||||
assert_eq!(read_hex_u32(&[b'f'; 8]), 0xffffffff);
|
||||
assert_eq!(
|
||||
read_hex_u32(&[b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8']),
|
||||
0x12345678
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pad() {
|
||||
assert_eq!(pad(0, 4), 0);
|
||||
assert_eq!(pad(1, 4), 4);
|
||||
assert_eq!(pad(2, 4), 4);
|
||||
assert_eq!(pad(3, 4), 4);
|
||||
assert_eq!(pad(4, 4), 4);
|
||||
assert_eq!(pad(5, 4), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_simple() {
|
||||
let data = fs::read("test_data/1.cpio").unwrap();
|
||||
let reader = Reader::new(&data);
|
||||
|
||||
let mut match_count = 0;
|
||||
for entry in reader {
|
||||
let entry = entry.unwrap();
|
||||
if entry.filename().unwrap() == "hello.txt" {
|
||||
assert_eq!(entry.file_size(), 6);
|
||||
assert_eq!(entry.data(), b"hello\n");
|
||||
match_count |= 1;
|
||||
} else if entry.filename().unwrap() == "world/world.txt" {
|
||||
assert_eq!(entry.file_size(), 6);
|
||||
assert_eq!(entry.data(), b"world\n");
|
||||
match_count |= 2;
|
||||
}
|
||||
}
|
||||
assert_eq!(match_count, 1 | 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_checksum() {
|
||||
let data = fs::read("test_data/2.cpio").unwrap();
|
||||
let reader = Reader::new(&data);
|
||||
|
||||
let mut match_count = 0;
|
||||
for entry in reader {
|
||||
let entry = entry.unwrap();
|
||||
if entry.filename().unwrap() == "test.txt" {
|
||||
assert_eq!(entry.file_size(), 14);
|
||||
assert_eq!(entry.data(), b"Hello\nWorld\n!\n");
|
||||
match_count += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(match_count, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_file_large() {
|
||||
let data = fs::read("test_data/3.cpio.gz").unwrap();
|
||||
let mut decoder = GzDecoder::new(&data[..]);
|
||||
let mut data = Vec::with_capacity(1024 * 1024 * 1024);
|
||||
decoder.read_to_end(&mut data).unwrap();
|
||||
let reader = Reader::new(&data);
|
||||
|
||||
let mut match_count = 0;
|
||||
for entry in reader {
|
||||
let entry = entry.unwrap();
|
||||
if entry.filename().unwrap() == "32MiB.bin" {
|
||||
assert_eq!(entry.file_size(), 32 * 1024 * 1024);
|
||||
assert!(entry.data().iter().all(|&x| x == 42));
|
||||
match_count += 1;
|
||||
}
|
||||
}
|
||||
assert_eq!(match_count, 1);
|
||||
}
|
||||
}
|
BIN
lib/cpio/test_data/1.cpio
Normal file
BIN
lib/cpio/test_data/1.cpio
Normal file
Binary file not shown.
BIN
lib/cpio/test_data/2.cpio
Normal file
BIN
lib/cpio/test_data/2.cpio
Normal file
Binary file not shown.
BIN
lib/cpio/test_data/3.cpio.gz
Normal file
BIN
lib/cpio/test_data/3.cpio.gz
Normal file
Binary file not shown.
7
lib/vspace/Cargo.lock
generated
Normal file
7
lib/vspace/Cargo.lock
generated
Normal 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
6
lib/vspace/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "vspace"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
@ -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
3
lib/vspace/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
#![no_std]
|
||||
|
||||
pub mod addr;
|
Loading…
Reference in New Issue
Block a user