Compare commits

..

2 Commits

Author SHA1 Message Date
c210a049cd chore: move mm into vspace 2024-03-23 16:45:24 +08:00
ac4a9bf6ec feat: add lib/cpio 2024-03-21 18:10:52 +08:00
24 changed files with 400 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;

50
lib/cpio/Cargo.lock generated Normal file
View 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
View 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
View 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

Binary file not shown.

BIN
lib/cpio/test_data/2.cpio Normal file

Binary file not shown.

Binary file not shown.

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;