feat: root: initial root server setup logic

This commit is contained in:
Paul Pan 2024-06-14 15:36:55 +08:00
parent da05567fbf
commit 8fe47c5728
4 changed files with 227 additions and 3 deletions

View File

@ -20,8 +20,9 @@ riscv = []
"riscv.board.virt" = ["riscv.riscv64"] "riscv.board.virt" = ["riscv.riscv64"]
[dependencies] [dependencies]
uapi = { path = "../uapi" }
allocator = { path = "../lib/allocator" } allocator = { path = "../lib/allocator" }
tracer = { path = "../lib/tracer" }
uapi = { path = "../uapi" }
utils = { path = "../lib/utils", default-features = false } utils = { path = "../lib/utils", default-features = false }
bitflags = "2.5" bitflags = "2.5"

View File

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

View File

@ -1,7 +1,7 @@
use super::cap::RawCap; use super::cap::RawCap;
use super::cnode::{CNodeCap, CNodeObject}; use super::cnode::{CNodeCap, CNodeObject};
use super::null::NullCap; use super::null::NullCap;
use super::{Cap, KernelObject}; use super::{Cap, KernelObject, TableCap, TcbCap};
use core::fmt::Debug; use core::fmt::Debug;
use uapi::cap::ObjectType; use uapi::cap::ObjectType;
use uapi::error::{SysError, SysResult}; use uapi::error::{SysError, SysResult};
@ -54,7 +54,7 @@ impl UntypedCap<'_> {
}); });
} }
fn is_device(&self) -> bool { pub fn is_device(&self) -> bool {
(self.cte.cap.get().args[1] >> 6) & 1 == 1 (self.cte.cap.get().args[1] >> 6) & 1 == 1
} }
@ -117,6 +117,8 @@ impl UntypedCap<'_> {
let new_cap = match obj_type { let new_cap = match obj_type {
ObjectType::Untyped => UntypedCap::mint(0, obj_type.bits(user_obj_bits), self.is_device(), addr), 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::CNode => CNodeCap::mint(user_obj_bits, 0, 0, addr),
ObjectType::TCB => TcbCap::mint(addr),
ObjectType::Table => TableCap::mint(addr),
// TODO: other object types // TODO: other object types
_ => return Err(SysError::InvalidArgument), _ => return Err(SysError::InvalidArgument),
}; };

220
kernel/src/root.rs Normal file
View File

@ -0,0 +1,220 @@
use crate::arch::layout::{mmap_phys_to_virt, mmap_virt_to_phys, PAGE_SIZE};
use crate::arch::vspace::{KERNEL_PAGETABLE_SIZE, RAM_ALLOCATOR};
use crate::objects::*;
use crate::vspace::*;
use core::ops::Range;
use elf::{abi::PT_LOAD, endian::AnyEndian, ElfBytes};
use fdt::Fdt;
use log::{debug, trace};
use spin::Lazy;
use uapi::cspace::CNodeSlot;
use uapi::error::SysError;
use utils::addr::*;
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, fdt, memory_idx);
// 4. create objects
let free_idx = create_objects(cnode_obj, device_idx);
// 5. load root server
// 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: {}: {:?} -> {:?}",
memory_idx,
start,
start + (1 << bits)
);
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, fdt: &Fdt, memory_idx: usize) -> 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: {}: {:?} -> {:?}",
device_idx,
start,
start + (1 << bits)
);
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 create_objects(cnode_obj: &mut CNodeObject, end_idx: usize) -> usize {
fn alloc<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");
}
let mut free_idx = end_idx;
// tcb
{
trace!("[root] allocating tcb object");
let tcb_idx = CNodeSlot::TcbCap as usize;
alloc::<TcbObject>(cnode_obj, end_idx, 0, tcb_idx..tcb_idx + 1);
}
// vspace
{
trace!("[root] allocating vspace object");
let pagetable_bits = PAGE_SIZE.ilog2() as usize;
// root
let vspace_idx = CNodeSlot::VSpaceCap as usize;
alloc::<TableObject>(cnode_obj, end_idx, pagetable_bits, vspace_idx..vspace_idx + 1);
if KERNEL_PAGETABLE_SIZE > 1 {
// remaining pagetables
let range = free_idx..(free_idx + KERNEL_PAGETABLE_SIZE - 1);
alloc::<TableObject>(cnode_obj, end_idx, pagetable_bits, range);
free_idx += KERNEL_PAGETABLE_SIZE - 1;
}
todo!("copy pagetables");
}
// bootinfo?
free_idx
}