mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: root: initial root server setup logic
This commit is contained in:
parent
da05567fbf
commit
8fe47c5728
@ -20,8 +20,9 @@ riscv = []
|
||||
"riscv.board.virt" = ["riscv.riscv64"]
|
||||
|
||||
[dependencies]
|
||||
uapi = { path = "../uapi" }
|
||||
allocator = { path = "../lib/allocator" }
|
||||
tracer = { path = "../lib/tracer" }
|
||||
uapi = { path = "../uapi" }
|
||||
utils = { path = "../lib/utils", default-features = false }
|
||||
|
||||
bitflags = "2.5"
|
||||
|
@ -27,6 +27,7 @@ mod lang;
|
||||
mod logging;
|
||||
mod objects;
|
||||
mod plat;
|
||||
mod root;
|
||||
mod scheduler;
|
||||
mod vspace;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::cap::RawCap;
|
||||
use super::cnode::{CNodeCap, CNodeObject};
|
||||
use super::null::NullCap;
|
||||
use super::{Cap, KernelObject};
|
||||
use super::{Cap, KernelObject, TableCap, TcbCap};
|
||||
use core::fmt::Debug;
|
||||
use uapi::cap::ObjectType;
|
||||
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
|
||||
}
|
||||
|
||||
@ -117,6 +117,8 @@ 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),
|
||||
// TODO: other object types
|
||||
_ => return Err(SysError::InvalidArgument),
|
||||
};
|
||||
|
220
kernel/src/root.rs
Normal file
220
kernel/src/root.rs
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user