Compare commits

..

No commits in common. "bf6297c5ace3952bbaed3b2083735eb97907f804" and "c013478d0bce15c38c179e18e487ecc697b07fa0" have entirely different histories.

27 changed files with 65 additions and 536 deletions

44
Cargo.lock generated
View File

@ -19,9 +19,9 @@ dependencies = [
[[package]]
name = "autocfg"
version = "1.3.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "bit_field"
@ -56,9 +56,9 @@ dependencies = [
[[package]]
name = "crc32fast"
version = "1.4.2"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3"
checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
dependencies = [
"cfg-if",
]
@ -69,12 +69,6 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
[[package]]
name = "elf"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
[[package]]
name = "embedded-hal"
version = "1.0.0"
@ -89,9 +83,9 @@ checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67"
[[package]]
name = "flate2"
version = "1.0.30"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"miniz_oxide",
@ -104,8 +98,6 @@ dependencies = [
"allocator",
"bitflags 2.5.0",
"cfg-if",
"cpio",
"elf",
"fdt",
"log",
"num-derive",
@ -122,9 +114,9 @@ dependencies = [
[[package]]
name = "lock_api"
version = "0.4.12"
version = "0.4.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
dependencies = [
"autocfg",
"scopeguard",
@ -138,9 +130,9 @@ checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "miniz_oxide"
version = "0.7.3"
version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
dependencies = [
"adler",
]
@ -158,18 +150,18 @@ dependencies = [
[[package]]
name = "num-traits"
version = "0.2.19"
version = "0.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
dependencies = [
"autocfg",
]
[[package]]
name = "proc-macro2"
version = "1.0.85"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
@ -204,9 +196,9 @@ dependencies = [
[[package]]
name = "rustversion"
version = "1.0.17"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
[[package]]
name = "sbi-rt"
@ -246,9 +238,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "2.0.66"
version = "2.0.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
dependencies = [
"proc-macro2",
"quote",

View File

@ -41,9 +41,6 @@ clippy:
cargo clippy -p utils
cargo clippy --no-deps $(CARGO_TARGET_ARGS) --manifest-path=kernel/Cargo.toml
fmt:
cargo fmt --all
test:
cargo test -p allocator
cargo test -p utils
@ -67,4 +64,4 @@ qemu: kernel
qemu-gdb: kernel
$(QEMU) $(QEMU_ARGS) -s -S
.PHONY: kernel clippy fmt test kernel-test-dump kernel-asm build-target clean qemu qemu-gdb
.PHONY: kernel clippy test kernel-test-dump kernel-asm build-target clean qemu qemu-gdb

View File

@ -20,15 +20,12 @@ riscv = []
"riscv.board.virt" = ["riscv.riscv64"]
[dependencies]
allocator = { path = "../lib/allocator" }
cpio = { path = "../lib/cpio" }
tracer = { path = "../lib/tracer" }
uapi = { path = "../uapi" }
allocator = { path = "../lib/allocator" }
utils = { path = "../lib/utils", default-features = false }
bitflags = "2.5"
cfg-if = "1.0"
elf = { version = "0.7", default-features = false }
fdt = "0.1"
log = "0.4"
num-derive = "0.4"

View File

@ -18,11 +18,7 @@ impl FrameWalker {
fn is_valid(&self) -> bool {
let fp_valid = unsafe { BSS_START.as_virt_addr() <= self.current_fp && self.current_fp < BSS_END.as_virt_addr() };
let pc_valid = unsafe { TEXT_START.as_virt_addr() <= self.current_pc && self.current_pc < TEXT_END.as_virt_addr() };
// pc might be 0xffff_ffff in the first frame
let first = self.current_pc == VirtAddr(usize::MAX);
fp_valid && (pc_valid || first)
fp_valid && pc_valid
}
pub fn new() -> Self {

View File

@ -34,7 +34,7 @@ unsafe extern "C" fn _start(hart_id: usize, fdt_addr: usize) -> ! {
ld t0, 0(t0)
# load and relocate registers
lla tp, TLS_START
lla tp, TSS_START
lla sp, {stack} + {stack_size}
add gp, gp, t0
add tp, tp, t0
@ -72,7 +72,7 @@ unsafe fn pre_main(hart_id: usize, fdt_addr: usize) {
setup_memory(fdt_addr);
setup_kernel_paging();
// TODO: on secondary cpu, we should copy existing kernel page table and TLS, then remap TLS
// TODO: on secondary cpu, we should copy existing kernel page table and TSS, then remap TSS
install_kernel_pagetable();
// after kernel paging, board level early console is broken (no address mapping)

View File

@ -22,8 +22,8 @@ extern "C" {
pub static BOOT_STACK_END: ExternSymbol;
pub static BSS_END: ExternSymbol;
pub static TLS_START: ExternSymbol;
pub static TLS_END: ExternSymbol;
pub static TSS_START: ExternSymbol;
pub static TSS_END: ExternSymbol;
pub static TDATA_START: ExternSymbol;
pub static TDATA_END: ExternSymbol;
@ -33,7 +33,6 @@ extern "C" {
}
pub const PAGE_SIZE: usize = 4 * KIB;
pub const PAGE_BITS: usize = PAGE_SIZE.ilog2() as usize;
pub const PAGE_LAYOUT: Layout = unsafe { Layout::from_size_align_unchecked(PAGE_SIZE, PAGE_SIZE) };
#[inline(always)]
@ -54,11 +53,6 @@ pub fn zero_bss() {
}
}
/* NOTE:
* `kernel_phys_to_virt` and `kernel_virt_to_phys` should only be used when interacting with `ExternSymbol`,
* for other cases, use `mmap_phys_to_virt` and `mmap_virt_to_phys` instead.
*/
pub unsafe fn kernel_phys_to_virt(phys: PhysAddr) -> VirtAddr {
VirtAddr(phys.as_usize() + KERNEL_OFFSET)
}

View File

@ -50,8 +50,8 @@ SECTIONS {
}
. = ALIGN(PAGE_SIZE);
.tls : AT(ADDR(.tls) - __kernel_offset) {
TLS_START = .;
.tss : AT(ADDR(.tss) - __kernel_offset) {
TSS_START = .;
. = ALIGN(8);
TDATA_START = .;
@ -63,10 +63,9 @@ SECTIONS {
*(.tbss .tbss.*)
TBSS_END = .;
TLS_END = .;
TSS_END = .;
}
. = TLS_END;
. = ALIGN(PAGE_SIZE);
KERNEL_END = .;

View File

@ -55,8 +55,8 @@ SECTIONS {
}
. = ALIGN(PAGE_SIZE);
.tls : AT(ADDR(.tls) - __kernel_offset) {
TLS_START = .;
.tss : AT(ADDR(.tss) - __kernel_offset) {
TSS_START = .;
. = ALIGN(8);
TDATA_START = .;
@ -68,10 +68,9 @@ SECTIONS {
*(.tbss .tbss.*)
TBSS_END = .;
TLS_END = .;
TSS_END = .;
}
. = TLS_END;
. = ALIGN(PAGE_SIZE);
KERNEL_END = .;

View File

@ -36,10 +36,7 @@ impl From<PTEFlags> for MapAttr {
if flags.contains(PTEFlags::USER_ACCESSIBLE) {
attr.insert(Self::USER_ACCESSIBLE);
}
if flags.contains(PTEFlags::VALID)
&& !flags.contains(PTEFlags::READABLE)
&& !flags.contains(PTEFlags::WRITABLE)
&& !flags.contains(PTEFlags::EXECUTABLE)
if flags.contains(PTEFlags::VALID) && !flags.contains(PTEFlags::READABLE | PTEFlags::WRITABLE | PTEFlags::EXECUTABLE)
{
attr.insert(Self::PAGE_TABLE);
}
@ -120,10 +117,6 @@ impl EntryOps for Entry {
self.0 = (self.0 & !PTEFlags::all().bits()) | flags.bits();
}
fn clear(&mut self) {
self.0 = 0;
}
fn is_valid(&self) -> bool {
self.0 & PTEFlags::VALID.bits() != 0
}

View File

@ -1,5 +1,5 @@
use super::{alloc_page, install_pagetable, map_range, RAM_ALLOCATOR};
use crate::{arch::layout::*, objects::*, vspace::*};
use crate::{arch::layout::*, vspace::*};
use log::{debug, info, trace};
use spin::Mutex;
use utils::{addr::*, size::*};
@ -10,6 +10,8 @@ use super::ALLOC_COUNT;
#[thread_local]
static KERNEL_PAGETABLE: Mutex<Option<Table<Level0>>> = Mutex::new(None);
pub const KERNEL_PAGETABLE_SIZE: usize = 3;
pub unsafe fn setup_memory(fdt_addr: usize) {
info!("Setting up memory");
let fdt = unsafe { fdt::Fdt::from_ptr(fdt_addr as *const u8).unwrap() };
@ -99,7 +101,7 @@ pub unsafe fn setup_memory(fdt_addr: usize) {
}
}
trace!("Memory setup complete, memory info:\n{:X?}", mem);
trace!("Memory setup complete, memory info:\n{:#x?}", mem);
}
pub unsafe fn setup_kernel_paging() {
@ -107,7 +109,7 @@ pub unsafe fn setup_kernel_paging() {
assert!(!is_kernel_pagetable_allocated(), "Kernel pagetable already allocated");
let root_pt = alloc_page();
let mut kernel_pt = Table::<Level0>::new(mmap_phys_to_virt(root_pt));
let mut kernel_pt = Table::<Level0>::new(root_pt.as_usize().into());
macro_rules! map_section {
(($($section:ident),+),$attr:expr) => {
@ -115,7 +117,7 @@ pub unsafe fn setup_kernel_paging() {
let start = concat_idents!($section, _START).as_virt_addr().align_down(PAGE_SIZE);
let end = concat_idents!($section, _END).as_virt_addr().align_up(PAGE_SIZE);
debug!("Mapping section {}:\t[{:?}, {:?}]", stringify!($section), start, end);
map_range(alloc_page, &mut kernel_pt, start, kernel_virt_to_phys(start), (end - start).as_usize(), $attr);
map_range(&mut kernel_pt, start, kernel_virt_to_phys(start), (end - start).as_usize(), $attr);
)+
};
}
@ -124,13 +126,12 @@ pub unsafe fn setup_kernel_paging() {
map_section!((RODATA), MapAttr::READABLE);
map_section!((DATA, BSS), MapAttr::READABLE | MapAttr::WRITABLE);
// TODO: every core must have a separate TLS section
map_section!((TLS), MapAttr::READABLE | MapAttr::WRITABLE);
// TODO: every core must have a separate TSS section
map_section!((TSS), MapAttr::READABLE | MapAttr::WRITABLE);
// map 4 GiB physical memory
// TODO: walk fdt to get all memory region? put it in driver init
map_range(
alloc_page,
&mut kernel_pt,
mmap_phys_to_virt(PhysAddr(0)),
PhysAddr(0),
@ -142,6 +143,7 @@ pub unsafe fn setup_kernel_paging() {
{
let count = ALLOC_COUNT.load(core::sync::atomic::Ordering::Acquire);
trace!("Kernel page table size: {:?}", count);
assert!(KERNEL_PAGETABLE_SIZE == count, "Kernel page table size mismatch");
}
*KERNEL_PAGETABLE.lock() = Some(kernel_pt);
@ -150,10 +152,10 @@ pub unsafe fn setup_kernel_paging() {
pub unsafe fn install_kernel_pagetable() {
info!("Setting up new kernel pagetable");
let vaddr = KERNEL_PAGETABLE.lock().as_ref().expect("No kernel pagetable found").vaddr();
let paddr = mmap_virt_to_phys(vaddr);
let kernel_pt = KERNEL_PAGETABLE.lock();
let kernel_pt = kernel_pt.as_ref().expect("No kernel pagetable found");
install_pagetable(paddr)
install_pagetable(kernel_pt)
}
#[inline]
@ -164,23 +166,5 @@ pub fn is_kernel_pagetable_allocated() -> bool {
unsafe fn map_kernel(from: VirtAddr, to: PhysAddr, size: usize, attr: MapAttr) {
let mut guard = KERNEL_PAGETABLE.lock();
let pt = guard.as_mut().unwrap();
map_range(alloc_page, pt, from, to, size, attr);
}
pub fn copy_kernel_pagetable(root: &CapEntry) {
let kernel_pt = KERNEL_PAGETABLE.lock();
let from = kernel_pt.as_ref().expect("No kernel pagetable found");
let mut root = TableCap::try_from(root).expect("Invalid vspace cap");
let to: Table<Level0> = root.as_object_mut();
for (i, (from, to)) in from.entries.iter().zip(to.entries.iter_mut()).enumerate() {
if !from.is_valid() {
to.clear();
continue;
}
to.set_attr(from.attr());
to.set_paddr(from.paddr());
}
map_range(pt, from, to, size, attr);
}

View File

@ -11,10 +11,6 @@ impl<'a, T: TableLevel> TableOps<'a, T> for Table<'a, T> {
}
}
fn vaddr(&self) -> VirtAddr {
VirtAddr::from(self.entries.as_ptr())
}
fn map(&mut self, from: VirtAddr, to: PhysAddr, attr: MapAttr) -> PageResult {
if !from.is_aligned(T::LEVEL_SIZE) || !to.is_aligned(PAGE_SIZE) {
return Err(PageError::NotAligned);

View File

@ -28,14 +28,7 @@ pub fn alloc_page() -> PhysAddr {
addr
}
pub fn map_range(
mut alloc: impl FnMut() -> PhysAddr,
pt: &mut Table<Level0>,
from: VirtAddr,
to: PhysAddr,
size: usize,
attr: MapAttr,
) {
pub fn map_range(pt: &mut Table<Level0>, from: VirtAddr, to: PhysAddr, size: usize, attr: MapAttr) {
let mut virt_start = from;
let mut phys_start = to;
let virt_end = from + size;
@ -63,7 +56,7 @@ pub fn map_range(
unsafe {
Table::<$level>::new(mmap_phys_to_virt(
$pt.lookup_mut($addr).map(|e| e.paddr()).unwrap_or_else(|| {
let page = alloc();
let page = alloc_page();
let addr = $addr.align_down(<$level as TableLevel>::PREVIOUS::LEVEL_SIZE);
debug!("Creating new pagetable:\t{:?} -> {:?}", addr, page);
$pt.map(addr, page, MapAttr::PAGE_TABLE).unwrap();
@ -96,7 +89,9 @@ fn page_table_mode() -> riscv::register::satp::Mode {
return riscv::register::satp::Mode::Sv57;
}
pub unsafe fn install_pagetable(addr: PhysAddr) {
riscv::register::satp::set(page_table_mode(), 0, addr.extract_ppn());
pub unsafe fn install_pagetable(pt: &Table<Level0>) {
let root_pt = PhysAddr::from(pt.entries.as_ptr());
riscv::register::satp::set(page_table_mode(), 0, root_pt.extract_ppn());
riscv::asm::sfence_vma_all();
}

View File

@ -15,9 +15,9 @@ fn panic(info: &PanicInfo) -> ! {
location.file(),
location.line(),
location.column(),
info.message(),
info.message().unwrap(),
),
None => error!("[lang] Panicked: {}", info.message()),
None => error!("[lang] Panicked: {}", info.message().unwrap()),
}
unsafe { dump_backtrace() };

View File

@ -27,7 +27,6 @@ mod lang;
mod logging;
mod objects;
mod plat;
mod root;
mod scheduler;
mod vspace;

View File

@ -75,7 +75,7 @@ impl Debug for CapEntry {
ObjectType::CNode => write!(f, "{:?}", CNodeCap::try_from(self)),
ObjectType::Frame => write!(f, "{:?}", FrameCap::try_from(self)),
ObjectType::Null => write!(f, "{:?}", NullCap::try_from(self)),
ObjectType::Table => write!(f, "{:?}", TableCap::try_from(self)),
ObjectType::PageTable => write!(f, "{:?}", TableCap::try_from(self)),
ObjectType::TCB => write!(f, "{:?}", TcbCap::try_from(self)),
ObjectType::Untyped => write!(f, "{:?}", UntypedCap::try_from(self)),
_ => write!(f, "UnknownCap"),

View File

@ -52,8 +52,10 @@ impl<'a> FrameCap<'a> {
const VM_RIGHT_MASK: usize = MASK!(Self::VM_RIGHT_BITS);
const VM_RIGHT_OFFSET: usize = 0;
pub fn mint(ptr: PhysAddr, size_bits: usize, attr: MapAttr, is_device: bool) -> RawCap {
debug_assert!(size_bits <= MASK!(Self::FRAME_SIZE_BITS)); // 1<<63
pub fn mint(ptr: PhysAddr, size: usize, attr: MapAttr, is_device: bool) -> RawCap {
let size_bits = size.ilog2() as usize;
debug_assert!(size_bits <= FrameCap::FRAME_SIZE_BITS);
assert!(size >= PAGE_SIZE);
let arg0 = 0
| ((attr.bits() & Self::VM_RIGHT_MASK) << Self::VM_RIGHT_OFFSET)

View File

@ -10,7 +10,7 @@ use utils::{addr::*, MASK};
/// TableObject is an object that represents a page table
pub struct TableObject([u8]);
impl KernelObject for TableObject {
const OBJ_TYPE: ObjectType = ObjectType::Table;
const OBJ_TYPE: ObjectType = ObjectType::PageTable;
}
/*
@ -40,7 +40,7 @@ impl<'a> TableCap<'a> {
const IS_MAPPED_OFFSET: usize = 0;
pub fn mint(ptr: PhysAddr) -> RawCap {
RawCap::new(0, 0, ptr, ObjectType::Table)
RawCap::new(0, 0, ptr, ObjectType::PageTable)
}
pub fn is_mapped(&self) -> bool {

View File

@ -1,8 +1,7 @@
use super::cap::RawCap;
use super::cnode::{CNodeCap, CNodeObject};
use super::null::NullCap;
use super::{Cap, FrameCap, KernelObject, TableCap, TcbCap};
use crate::vspace::MapAttr;
use super::{Cap, KernelObject};
use core::fmt::Debug;
use uapi::cap::ObjectType;
use uapi::error::{SysError, SysResult};
@ -55,7 +54,7 @@ impl UntypedCap<'_> {
});
}
pub fn is_device(&self) -> bool {
fn is_device(&self) -> bool {
(self.cte.cap.get().args[1] >> 6) & 1 == 1
}
@ -108,6 +107,7 @@ impl UntypedCap<'_> {
// Check whether we are handling device memory
if self.is_device() && obj_type != ObjectType::Frame && obj_type != ObjectType::Untyped {
// TODO: we might split frame into tera, giga, mega, kilo...
return Err(SysError::InvalidArgument);
}
@ -117,9 +117,6 @@ impl UntypedCap<'_> {
let new_cap = match obj_type {
ObjectType::Untyped => UntypedCap::mint(0, obj_type.bits(user_obj_bits), self.is_device(), addr),
ObjectType::CNode => CNodeCap::mint(user_obj_bits, 0, 0, addr),
ObjectType::TCB => TcbCap::mint(addr),
ObjectType::Table => TableCap::mint(addr),
ObjectType::Frame => FrameCap::mint(addr, user_obj_bits, MapAttr::empty(), self.is_device()),
// TODO: other object types
_ => return Err(SysError::InvalidArgument),
};

View File

@ -1,359 +0,0 @@
use crate::arch::layout::{mmap_phys_to_virt, mmap_virt_to_phys, PAGE_BITS, PAGE_SIZE};
use crate::arch::vspace::{copy_kernel_pagetable, map_range, RAM_ALLOCATOR};
use crate::objects::*;
use crate::vspace::*;
use core::{cmp::min, ops::Range};
use elf::{abi::*, endian::AnyEndian, ElfBytes};
use fdt::Fdt;
use log::{debug, trace};
use spin::Lazy;
use uapi::{cspace::CNodeSlot, error::SysError};
use utils::{addr::*, bin::prev_power_of_two};
const ROOT_CNODE_SIZE: usize = 128;
static mut ROOT_CNODE: Lazy<[CapEntry; ROOT_CNODE_SIZE]> =
Lazy::new(|| core::array::from_fn(|i| CapEntry::new(NullCap::mint())));
pub fn setup_root_server(fdt: &Fdt) {
// Root Server is using statically allocated ROOT_CNODE
// 1. Setup CNodeCap -> self reference
let cnode_entry = {
let radix_bits = ROOT_CNODE_SIZE.ilog2() as usize;
let guard_bits = 0;
let cap_guard = 0;
let ptr = unsafe { mmap_virt_to_phys(VirtAddr::from(ROOT_CNODE.as_ptr())) };
let cap = CNodeCap::mint(radix_bits, guard_bits, cap_guard, ptr);
CapEntry::new(cap)
};
let mut cnode = CNodeCap::try_from(&cnode_entry).unwrap();
let cnode_obj = cnode.as_object_mut();
cnode_obj[CNodeSlot::CNodeCap as usize] = cnode_entry.clone();
// 2. insert current free memory [CNodeSlot::UntypedCap, memory_idx)
let memory_idx = create_untyped_memory(cnode_obj);
// 3. insert device memory [memory_idx, device_idx)
let device_idx = create_untyped_device(cnode_obj, memory_idx, fdt);
// 4. create objects
create_objects(cnode_obj, device_idx);
// 5. load root server
let root_server_idx = load_root_server(cnode_obj, device_idx, fdt);
// 6. map other memory (fdt, initrd)
// 7. setup threads
}
fn create_untyped_memory(cnode_obj: &mut CNodeObject) -> usize {
let mut memory_idx = CNodeSlot::UntypedCap as usize;
let mut ram = RAM_ALLOCATOR.lock();
ram.blocks_mut()
.iter_mut()
.filter(|b| b.is_some())
.map(|b| b.take().unwrap())
.for_each(|b| {
let start = {
let start = b.start_addr();
let aligned = start.align_up(PAGE_SIZE);
if aligned != start {
debug!("[root] wasting memory: {:#x?} -> {:#x?}", start, aligned);
}
aligned
};
let bits = {
let size = b.size();
let aligned = align_down(size, PAGE_SIZE);
if aligned != size {
debug!("[root] wasting memory: {:#x?} -> {:#x?}", start + aligned, start + size);
}
if aligned != 0 {
aligned.ilog2() as usize
} else {
0
}
};
if bits == 0 {
return;
}
trace!(
"[root] creating untyped memory: {}: {:?} -> {:?}, slot #{}",
memory_idx,
start,
start + (1 << bits),
memory_idx
);
let cap = UntypedCap::mint(0, bits, false, start);
let cap_entry = CapEntry::new(cap);
cnode_obj[memory_idx] = cap_entry;
memory_idx += 1;
});
assert!(ram.blocks().iter().all(|b| b.is_none()));
memory_idx
}
fn create_untyped_device(cnode_obj: &mut CNodeObject, memory_idx: usize, fdt: &Fdt) -> usize {
let mut device_idx = memory_idx;
let memory = fdt.memory();
fdt.all_nodes().filter_map(|n| n.reg()).for_each(|r| {
r.filter(|r| r.size.is_some_and(|s| s > 0))
.filter(|r| {
memory.regions().all(|m| {
let m_start = m.starting_address as usize;
let m_end = m_start + m.size.unwrap();
let r_start = r.starting_address as usize;
let r_end = r_start + r.size.unwrap();
r_end <= m_start || m_end <= r_start
})
})
.for_each(|region| {
let start = PhysAddr::from(region.starting_address);
let size = region.size.unwrap();
let bits = size.next_power_of_two().ilog2() as usize;
if (1 << bits) > size {
debug!(
"[root] allocating more device memory: {:#x} -> {:#x}",
start + size,
start + (1 << bits)
);
}
trace!(
"[root] creating untyped device: {}: {:?} -> {:?}, slot #{}",
device_idx,
start,
start + (1 << bits),
device_idx
);
let cap = UntypedCap::mint(0, bits, true, start);
let cap_entry = CapEntry::new(cap);
cnode_obj[device_idx] = cap_entry;
device_idx += 1;
})
});
device_idx
}
fn alloc_objects<T: KernelObject + ?Sized>(
cnode_obj: &mut CNodeObject,
end_idx: usize,
user_obj_bits: usize,
range: Range<usize>,
) {
let untyped_start = CNodeSlot::UntypedCap as usize;
let (memory, slots) = {
let (prologue, remain) = cnode_obj.split_at_mut(untyped_start);
let (memory, epilogue) = remain.split_at_mut(end_idx - untyped_start);
match range {
r if r.end <= untyped_start => (memory, &mut prologue[r]),
r if r.start >= end_idx => (memory, &mut epilogue[(r.start - end_idx)..(r.end - end_idx)]),
_ => panic!("init: slot range overlaps with untyped memory"),
}
};
for untyped in memory {
let mut untyped = UntypedCap::try_from(&*untyped).expect("init: untyped cap is invalid");
if untyped.is_device() {
// all non-device memory are placed before device memory
break;
}
match untyped.retype(T::OBJ_TYPE, user_obj_bits, slots) {
Ok(()) => return,
Err(SysError::RangeError) => continue,
_ => panic!("init: retype failed"),
}
}
panic!("init: untyped memory is exhausted");
}
fn create_objects(cnode_obj: &mut CNodeObject, end_idx: usize) {
// tcb
{
let tcb_idx = CNodeSlot::TcbCap as usize;
trace!("[root] allocating tcb object at slot #{}", tcb_idx);
alloc_objects::<TcbObject>(cnode_obj, end_idx, 0, tcb_idx..tcb_idx + 1);
}
// vspace
{
// root
let vspace_idx = CNodeSlot::VSpaceCap as usize;
trace!("[root] allocating vspace object at slot #{}", vspace_idx);
alloc_objects::<TableObject>(cnode_obj, end_idx, PAGE_BITS, vspace_idx..vspace_idx + 1);
// copy pagetable
let root = &cnode_obj[vspace_idx];
copy_kernel_pagetable(root);
}
// bootinfo
{
let bootinfo_idx = CNodeSlot::BootInfoFrameCap as usize;
trace!("[root] allocating bootinfo object at slot #{}", bootinfo_idx);
alloc_objects::<FrameObject>(cnode_obj, end_idx, PAGE_BITS, bootinfo_idx..bootinfo_idx + 1);
}
}
fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> usize {
let table: Table<Level0> = TableCap::try_from(&cnode_obj[CNodeSlot::VSpaceCap as usize])
.unwrap()
.as_object_mut();
let mut rootfs = unsafe {
let chosen = fdt.find_node("/chosen").expect("/chosen is required");
let initrd_start = chosen
.properties()
.find(|n| n.name == "linux,initrd-start")
.expect("linux,initrd-start is required")
.as_usize()
.unwrap();
let initrd_end = chosen
.properties()
.find(|n| n.name == "linux,initrd-end")
.expect("linux,initrd-end is required")
.as_usize()
.unwrap();
let vaddr = mmap_phys_to_virt(PhysAddr(initrd_start));
let len = initrd_end - initrd_start;
let data = core::slice::from_raw_parts(vaddr.as_const_ptr(), len);
cpio::Reader::new(data)
};
let root_entry = rootfs
.find_map(|entry| {
if let Ok(entry) = entry {
if entry.filename().unwrap_or_default() == "root" {
return Some(entry);
}
}
None
})
.expect("init: root server not found");
let root_start = VirtAddr::from(root_entry.data().as_ptr());
let root_elf = ElfBytes::<AnyEndian>::minimal_parse(root_entry.data()).expect("init: invalid root server");
let mut nxt_slot = end_idx;
root_elf
.segments()
.expect("init: root server has no segments")
.iter()
.filter(|phdr| phdr.p_type == PT_LOAD)
.filter(|phdr| phdr.p_memsz > 0)
.for_each(|phdr| {
debug!(
"[initrd] loading segment:\t[{:#x?}, {:#x?}]",
phdr.p_vaddr,
phdr.p_vaddr + phdr.p_memsz
);
let seg_start = root_start + phdr.p_offset as usize;
let seg_addr = VirtAddr::from(phdr.p_vaddr);
// Currently, we only support loading segments that are aligned to PAGE_SIZE
assert!(seg_addr.is_aligned(PAGE_SIZE), "p_vaddr must be aligned");
assert!(phdr.p_align as usize == PAGE_SIZE, "p_align must be aligned");
assert!(is_aligned(phdr.p_memsz as usize, PAGE_SIZE), "p_memsz must be aligned");
debug_assert!(phdr.p_filesz <= phdr.p_memsz, "invalid ELF segment");
let copy = |offset: usize, dest: &mut [u8]| {
if offset > phdr.p_filesz as usize {
dest.fill(0);
} else {
let len = min(phdr.p_filesz as usize - offset, dest.len());
let src = &root_entry.data()[offset..offset + len];
dest[..len].copy_from_slice(src);
dest[len..].fill(0);
}
};
// allocate frames
let mut cur = 0;
while cur < phdr.p_memsz as usize {
let remain = phdr.p_memsz as usize - cur;
// calculate block size
let block_size = prev_power_of_two(remain as u64) as usize;
let block_bits = block_size.ilog2() as usize;
debug_assert!(block_size >= PAGE_SIZE);
// allocate frame
trace!("[initrd] allocating frame at slot #{}", nxt_slot);
alloc_objects::<FrameObject>(cnode_obj, end_idx, block_bits, nxt_slot..nxt_slot + 1);
nxt_slot += 1;
// copy data
let mut frame = FrameCap::try_from(&cnode_obj[nxt_slot - 1]).unwrap();
let mem = frame.as_object_mut();
copy(cur, mem);
// map frame to vspace
let root = &cnode_obj[CNodeSlot::VSpaceCap as usize];
let root_vaddr = TableCap::try_from(root).unwrap().as_object::<Level0>().vaddr();
let mut root = unsafe { Table::new(root_vaddr) }; // use unsafe to workaround borrow checker
let vaddr = seg_addr + cur;
let paddr = unsafe { mmap_virt_to_phys(VirtAddr::from(mem as *const _ as *const u8)) };
let attr = {
let mut attr = MapAttr::USER_ACCESSIBLE;
if phdr.p_flags & PF_X != 0 {
attr |= MapAttr::EXECUTABLE;
}
if phdr.p_flags & PF_W != 0 {
attr |= MapAttr::WRITABLE;
}
if phdr.p_flags & PF_R != 0 {
attr |= MapAttr::READABLE;
}
attr
};
let alloc_page = || {
trace!("[initrd] allocating pagetable at slot #{}", nxt_slot);
alloc_objects::<TableObject>(cnode_obj, end_idx, PAGE_BITS, nxt_slot..nxt_slot + 1);
nxt_slot += 1;
let page = &cnode_obj[nxt_slot - 1];
let page = TableCap::try_from(page).unwrap();
let table: Table<Level0> = page.as_object(); // Any level is fine
unsafe { mmap_virt_to_phys(table.vaddr()) }
};
map_range(alloc_page, &mut root, vaddr, paddr, block_size, attr);
// update pointer
cur += block_size;
}
});
nxt_slot
}

View File

@ -23,7 +23,6 @@ pub trait EntryOps: Clone + Copy + Debug {
fn set_paddr(&mut self, addr: PhysAddr);
fn set_attr(&mut self, attr: MapAttr);
fn clear(&mut self);
fn is_valid(&self) -> bool;
fn is_leaf(&self) -> bool;

View File

@ -5,7 +5,6 @@ pub trait TableOps<'a, T: TableLevel> {
/// # Safety
/// `location` must be a page-aligned virtual address and will not be dropped.
unsafe fn new(location: VirtAddr) -> Self;
fn vaddr(&self) -> VirtAddr;
// following methods only works at current level

View File

@ -423,19 +423,3 @@ impl Step for VirtAddr {
start.as_usize().checked_sub(count).map(VirtAddr)
}
}
impl PhysAddr {
/// # Safety
/// Only provided for the sake of completeness. Use `{mmap, kernel}_phys_to_virt` instead.
pub unsafe fn to_virt_addr(&self) -> VirtAddr {
VirtAddr(self.0)
}
}
impl VirtAddr {
/// # Safety
/// Only provided for the sake of completeness. Use `{mmap, kernel}_virt_to_phys` instead.
pub unsafe fn to_phys_addr(&self) -> PhysAddr {
PhysAddr(self.0)
}
}

View File

@ -4,9 +4,3 @@ macro_rules! MASK {
((1 << $bits) - 1)
};
}
pub const fn prev_power_of_two(n: u64) -> u64 {
// Taken from https://internals.rust-lang.org/t/add-prev-power-of-two/14281
let bit = 63 - (n | 1).leading_zeros();
(1 << bit) & n
}

View File

@ -1,17 +0,0 @@
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "Usage: $0 <ELF_FILE>"
exit 1
fi
ELF_FILE=$1
while IFS= read -r line; do
if [[ $line =~ PC:\ VirtAddr\((0x[0-9a-fA-F]+)\) ]]; then
addr=${BASH_REMATCH[1]}
func=$(addr2line -Cfpe "$ELF_FILE" "$addr")
line+=" $func"
fi
echo "$line"
done

View File

@ -7,7 +7,7 @@ pub enum ObjectType {
Reply = 4,
Notification = 5,
Frame = 6,
Table = 7,
PageTable = 7,
Interrupt = 8,
Untyped = 9,
}
@ -36,7 +36,7 @@ impl ObjectType {
ObjectType::Reply => 0, // TODO: fill it!
ObjectType::Notification => 0, // TODO: fill it!
ObjectType::Frame => user_obj_bits,
ObjectType::Table => user_obj_bits, // arch dependent page table size
ObjectType::PageTable => user_obj_bits, // arch dependent page table size
ObjectType::Interrupt => 0, // TODO: fill it!
ObjectType::Untyped => user_obj_bits,
}

View File

@ -1,10 +0,0 @@
#[derive(Clone, Copy, Debug, Eq, PartialEq, FromPrimitive, ToPrimitive)]
pub enum CNodeSlot {
NullCap = 0,
TcbCap,
CNodeCap,
VSpaceCap,
BootInfoFrameCap,
UntypedCap,
// IrqControlCap
}

View File

@ -5,7 +5,6 @@
extern crate num_derive;
pub mod cap;
pub mod cspace;
pub mod error;
pub mod fault;
pub mod syscall;