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"]
|
"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"
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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
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