mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
No commits in common. "41208c1e15eeffdf5f92af4b0a9655e134a22516" and "93c4d3c5fbbcb2ea811155b55cfc50b464ea29a3" have entirely different histories.
41208c1e15
...
93c4d3c5fb
3
Makefile
3
Makefile
@ -31,8 +31,7 @@ QEMU = qemu-system-$(ARCH)
|
|||||||
QEMU_ARGS = -nographic -serial mon:stdio -smp 1
|
QEMU_ARGS = -nographic -serial mon:stdio -smp 1
|
||||||
QEMU_ARGS += -machine virt # TODO: override by $(BOARD)
|
QEMU_ARGS += -machine virt # TODO: override by $(BOARD)
|
||||||
QEMU_ARGS += -kernel target/$(BUILD_TARGET)/$(MODE)/kernel
|
QEMU_ARGS += -kernel target/$(BUILD_TARGET)/$(MODE)/kernel
|
||||||
QEMU_ARGS += -initrd root/init.cpio
|
QEMU_ARGS += -initrd build/init.cpio
|
||||||
QEMU_ARGS += -append "loglevel=4"
|
|
||||||
|
|
||||||
kernel:
|
kernel:
|
||||||
env RUSTFLAGS="$(RUSTFLAGS)" cargo build --bin kernel $(CARGO_BUILD_ARGS)
|
env RUSTFLAGS="$(RUSTFLAGS)" cargo build --bin kernel $(CARGO_BUILD_ARGS)
|
||||||
|
@ -121,10 +121,6 @@ impl TrapContextOps for TrapContext {
|
|||||||
assert!(index < 8, "TrapContext set_reg index out of range");
|
assert!(index < 8, "TrapContext set_reg index out of range");
|
||||||
self.gprs[index + 9] = value;
|
self.gprs[index + 9] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_pc(&mut self, value: usize) {
|
|
||||||
self.sepc = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -106,7 +106,7 @@ pub unsafe fn setup_kernel_paging() {
|
|||||||
info!("Setting up kernel paging");
|
info!("Setting up kernel paging");
|
||||||
assert!(!is_kernel_pagetable_allocated(), "Kernel pagetable already allocated");
|
assert!(!is_kernel_pagetable_allocated(), "Kernel pagetable already allocated");
|
||||||
|
|
||||||
let root_pt = alloc_page(VirtAddr(0));
|
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(mmap_phys_to_virt(root_pt));
|
||||||
|
|
||||||
macro_rules! map_section {
|
macro_rules! map_section {
|
||||||
|
@ -16,7 +16,7 @@ fn alloc_callback() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(debug_assertions, tracer::trace_callback(log = true, callback = alloc_callback))]
|
#[cfg_attr(debug_assertions, tracer::trace_callback(log = true, callback = alloc_callback))]
|
||||||
pub fn alloc_page(_mapped_addr: VirtAddr) -> PhysAddr {
|
pub fn alloc_page() -> PhysAddr {
|
||||||
let addr = RAM_ALLOCATOR.lock().alloc(PAGE_LAYOUT).expect("Failed to allocate page");
|
let addr = RAM_ALLOCATOR.lock().alloc(PAGE_LAYOUT).expect("Failed to allocate page");
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -29,7 +29,7 @@ pub fn alloc_page(_mapped_addr: VirtAddr) -> PhysAddr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_range(
|
pub fn map_range(
|
||||||
mut alloc: impl FnMut(VirtAddr) -> PhysAddr,
|
mut alloc: impl FnMut() -> PhysAddr,
|
||||||
pt: &mut Table<Level0>,
|
pt: &mut Table<Level0>,
|
||||||
from: VirtAddr,
|
from: VirtAddr,
|
||||||
to: PhysAddr,
|
to: PhysAddr,
|
||||||
@ -63,8 +63,8 @@ pub fn map_range(
|
|||||||
unsafe {
|
unsafe {
|
||||||
Table::<$level>::new(mmap_phys_to_virt(
|
Table::<$level>::new(mmap_phys_to_virt(
|
||||||
$pt.lookup_mut($addr).map(|e| e.paddr()).unwrap_or_else(|| {
|
$pt.lookup_mut($addr).map(|e| e.paddr()).unwrap_or_else(|| {
|
||||||
|
let page = alloc();
|
||||||
let addr = $addr.align_down(<$level as TableLevel>::PREVIOUS::LEVEL_SIZE);
|
let addr = $addr.align_down(<$level as TableLevel>::PREVIOUS::LEVEL_SIZE);
|
||||||
let page = alloc(addr);
|
|
||||||
debug!("Creating new pagetable:\t{:?} -> {:?}", addr, page);
|
debug!("Creating new pagetable:\t{:?} -> {:?}", addr, page);
|
||||||
$pt.map(addr, page, MapAttr::PAGE_TABLE).unwrap();
|
$pt.map(addr, page, MapAttr::PAGE_TABLE).unwrap();
|
||||||
page
|
page
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
use crate::logging::set_log_level;
|
|
||||||
use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver, CONSOLE};
|
use crate::plat::console::{set_console, ConsoleDevice, ConsoleDriver, CONSOLE};
|
||||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
use crate::plat::lowlevel::{Hardware, LowLevel};
|
||||||
use crate::plat::timer::{Timer, TimerOps};
|
use crate::plat::timer::{Timer, TimerOps};
|
||||||
use crate::plat::trap::{Trap, TrapOps};
|
use crate::plat::trap::{Trap, TrapOps};
|
||||||
use crate::root::setup_root_server;
|
|
||||||
use crate::scheduler::{IDLE_THREAD, SCHEDULER};
|
use crate::scheduler::{IDLE_THREAD, SCHEDULER};
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
@ -21,9 +19,7 @@ pub fn rust_main() -> ! {
|
|||||||
|
|
||||||
N_CPUS.store(fdt.cpus().count(), Ordering::Release);
|
N_CPUS.store(fdt.cpus().count(), Ordering::Release);
|
||||||
|
|
||||||
set_log_level(&fdt);
|
|
||||||
setup_console(&fdt);
|
setup_console(&fdt);
|
||||||
|
|
||||||
info!("Kernel Started");
|
info!("Kernel Started");
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -32,16 +28,33 @@ pub fn rust_main() -> ! {
|
|||||||
crate::test_main();
|
crate::test_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: setup and start scheduler
|
||||||
|
|
||||||
|
// --- some dummy tests ---
|
||||||
|
|
||||||
Trap::init();
|
Trap::init();
|
||||||
Timer::init();
|
Timer::init();
|
||||||
|
|
||||||
SCHEDULER.init();
|
SCHEDULER.init();
|
||||||
SCHEDULER.add(&IDLE_THREAD);
|
SCHEDULER.add(&IDLE_THREAD);
|
||||||
|
|
||||||
setup_root_server(&fdt);
|
|
||||||
|
|
||||||
SCHEDULER.schedule();
|
SCHEDULER.schedule();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let data = CONSOLE.lock().try_read();
|
||||||
|
match data {
|
||||||
|
Some(ch) => {
|
||||||
|
debug!("Key: {}", ch as char);
|
||||||
|
if ch == b'q' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- end ---
|
||||||
|
|
||||||
error!("[rust_main] Should not reach here! Maybe scheduler is not working?");
|
error!("[rust_main] Should not reach here! Maybe scheduler is not working?");
|
||||||
Hardware::shutdown(true);
|
Hardware::shutdown(true);
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,13 @@ use crate::plat::console::CONSOLE;
|
|||||||
use crate::{entry::HART_ID, plat::timer::CURRENT_TICK};
|
use crate::{entry::HART_ID, plat::timer::CURRENT_TICK};
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::Ordering;
|
||||||
use fdt::Fdt;
|
|
||||||
use log::{LevelFilter, Log, Metadata, Record};
|
use log::{LevelFilter, Log, Metadata, Record};
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! print {
|
macro_rules! print {
|
||||||
($($arg:tt)*) => {{
|
($($arg:tt)*) => {{
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use $crate::plat::console::CONSOLE;
|
use crate::plat::console::CONSOLE;
|
||||||
CONSOLE.lock().write_fmt(format_args!($($arg)*)).unwrap();
|
CONSOLE.lock().write_fmt(format_args!($($arg)*)).unwrap();
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
@ -60,34 +59,6 @@ impl Log for SimpleLogger {
|
|||||||
pub fn init() {
|
pub fn init() {
|
||||||
log::set_logger(&SimpleLogger).unwrap();
|
log::set_logger(&SimpleLogger).unwrap();
|
||||||
|
|
||||||
// Always log everything before the FDT is parsed
|
// TODO: get log level from boot env
|
||||||
log::set_max_level(LevelFilter::Trace);
|
log::set_max_level(LevelFilter::Trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_log_level(fdt: &Fdt) {
|
|
||||||
const UNKNOWN_LEVEL: usize = 5;
|
|
||||||
|
|
||||||
let log_level = fdt
|
|
||||||
.chosen()
|
|
||||||
.bootargs()
|
|
||||||
.map(|args| args.split_ascii_whitespace())
|
|
||||||
.map(|args| args.filter(|arg| arg.starts_with("loglevel=")))
|
|
||||||
.map(|args| args.map(|arg| arg["loglevel=".len()..].parse::<usize>()))
|
|
||||||
.and_then(|args| args.last())
|
|
||||||
.map(|level| level.unwrap_or(UNKNOWN_LEVEL))
|
|
||||||
.unwrap_or(UNKNOWN_LEVEL);
|
|
||||||
|
|
||||||
let level = match log_level {
|
|
||||||
0 => LevelFilter::Error,
|
|
||||||
1 => LevelFilter::Warn,
|
|
||||||
2 => LevelFilter::Info,
|
|
||||||
3 => LevelFilter::Debug,
|
|
||||||
4 => LevelFilter::Trace,
|
|
||||||
#[cfg(debug_assertions)]
|
|
||||||
_ => LevelFilter::Trace,
|
|
||||||
#[cfg(not(debug_assertions))]
|
|
||||||
_ => LevelFilter::Error,
|
|
||||||
};
|
|
||||||
|
|
||||||
log::set_max_level(level);
|
|
||||||
}
|
|
||||||
|
@ -2,7 +2,8 @@ use crate::arch::{layout::mmap_phys_to_virt, trap::TrapContext, vspace::*};
|
|||||||
use crate::{objects::*, plat::trap::TrapContextOps, vspace::*};
|
use crate::{objects::*, plat::trap::TrapContextOps, vspace::*};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use uapi::{cap::ObjectType, error::SysResult, fault::*, syscall::*};
|
use log::debug;
|
||||||
|
use uapi::{cap::ObjectType, error::SysResult, fault::Fault, syscall::MessageInfo};
|
||||||
use utils::{
|
use utils::{
|
||||||
addr::*,
|
addr::*,
|
||||||
linked_list::{Link, LinkHelper},
|
linked_list::{Link, LinkHelper},
|
||||||
@ -59,19 +60,6 @@ impl TcbObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_cspace(&mut self, cspace: CapEntry) {
|
|
||||||
CNodeCap::try_from(&cspace).expect("set_cspace: invalid cap");
|
|
||||||
self.cspace = cspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_vspace(&mut self, vspace: CapEntry) {
|
|
||||||
let cap = TableCap::try_from(&vspace).expect("set_vspace: invalid cap");
|
|
||||||
cap.set_mapped(true);
|
|
||||||
cap.set_mapped_asid(self.tid);
|
|
||||||
cap.set_mapped_vaddr(VirtAddr(0));
|
|
||||||
self.vspace = vspace;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn configure_idle_thread(&mut self) {
|
pub fn configure_idle_thread(&mut self) {
|
||||||
self.trapframe.configure_idle_thread();
|
self.trapframe.configure_idle_thread();
|
||||||
self.vspace = CapEntry::new(TableCap::mint(unsafe { get_current_pagetable().paddr() }));
|
self.vspace = CapEntry::new(TableCap::mint(unsafe { get_current_pagetable().paddr() }));
|
||||||
|
@ -16,5 +16,4 @@ pub trait TrapContextOps {
|
|||||||
|
|
||||||
fn get_reg(&self, index: usize) -> usize;
|
fn get_reg(&self, index: usize) -> usize;
|
||||||
fn set_reg(&mut self, index: usize, value: usize);
|
fn set_reg(&mut self, index: usize, value: usize);
|
||||||
fn set_pc(&mut self, value: usize);
|
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,16 @@
|
|||||||
use crate::arch::layout::{mmap_phys_to_virt, mmap_virt_to_phys, PAGE_BITS, PAGE_SIZE};
|
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::arch::vspace::{copy_kernel_pagetable, map_range, RAM_ALLOCATOR};
|
||||||
use crate::arch::FDT;
|
|
||||||
use crate::objects::*;
|
use crate::objects::*;
|
||||||
use crate::plat::trap::TrapContextOps;
|
|
||||||
use crate::scheduler::SCHEDULER;
|
|
||||||
use crate::vspace::*;
|
use crate::vspace::*;
|
||||||
use core::{cmp::min, ops::Range, sync::atomic::Ordering};
|
use core::{cmp::min, ops::Range};
|
||||||
use elf::{abi::*, endian::AnyEndian, ElfBytes};
|
use elf::{abi::*, endian::AnyEndian, ElfBytes};
|
||||||
use fdt::Fdt;
|
use fdt::Fdt;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use spin::Lazy;
|
use spin::Lazy;
|
||||||
use uapi::{consts::*, cspace::CNodeSlot, error::SysError};
|
use uapi::{cspace::CNodeSlot, error::SysError};
|
||||||
use utils::{addr::*, bin::prev_power_of_two};
|
use utils::{addr::*, bin::prev_power_of_two};
|
||||||
|
|
||||||
const ROOT_ASID: usize = 1;
|
|
||||||
const ROOT_CNODE_SIZE: usize = 128;
|
const ROOT_CNODE_SIZE: usize = 128;
|
||||||
|
|
||||||
static mut ROOT_CNODE: Lazy<[CapEntry; ROOT_CNODE_SIZE]> =
|
static mut ROOT_CNODE: Lazy<[CapEntry; ROOT_CNODE_SIZE]> =
|
||||||
Lazy::new(|| core::array::from_fn(|_| CapEntry::new(NullCap::mint())));
|
Lazy::new(|| core::array::from_fn(|_| CapEntry::new(NullCap::mint())));
|
||||||
|
|
||||||
@ -35,32 +30,25 @@ pub fn setup_root_server(fdt: &Fdt) {
|
|||||||
let cnode_obj = cnode.as_object_mut();
|
let cnode_obj = cnode.as_object_mut();
|
||||||
cnode_obj[CNodeSlot::CNodeCap as usize] = cnode_entry.clone();
|
cnode_obj[CNodeSlot::CNodeCap as usize] = cnode_entry.clone();
|
||||||
|
|
||||||
let mut free_idx = CNodeSlot::UntypedCap as usize;
|
// 2. insert current free memory [CNodeSlot::UntypedCap, memory_idx)
|
||||||
|
let memory_idx = create_untyped_memory(cnode_obj);
|
||||||
|
|
||||||
// 2. insert current free memory
|
// 3. insert device memory [memory_idx, device_idx)
|
||||||
create_untyped_memory(cnode_obj, &mut free_idx);
|
let device_idx = create_untyped_device(cnode_obj, memory_idx, fdt);
|
||||||
|
|
||||||
// 3. insert device memory
|
|
||||||
create_untyped_device(cnode_obj, &mut free_idx, fdt);
|
|
||||||
|
|
||||||
// 4. create objects
|
// 4. create objects
|
||||||
create_objects(cnode_obj, &mut free_idx, &cnode_entry);
|
create_objects(cnode_obj, device_idx);
|
||||||
|
|
||||||
// 5. load root server
|
// 5. load root server
|
||||||
load_root_server(cnode_obj, &mut free_idx, fdt);
|
let root_server_idx = load_root_server(cnode_obj, device_idx, fdt);
|
||||||
|
|
||||||
// 6. map other memory (fdt, initrd)
|
// 6. map other memory (fdt, initrd)
|
||||||
map_misc(cnode_obj, &mut free_idx, fdt);
|
|
||||||
|
|
||||||
// 7. insert into scheduler
|
// 7. setup threads
|
||||||
SCHEDULER.add(
|
|
||||||
TcbCap::try_from(&cnode_obj[CNodeSlot::TcbCap as usize])
|
|
||||||
.unwrap()
|
|
||||||
.as_object_mut(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_untyped_memory(cnode_obj: &mut CNodeObject, free_idx: &mut usize) {
|
fn create_untyped_memory(cnode_obj: &mut CNodeObject) -> usize {
|
||||||
|
let mut memory_idx = CNodeSlot::UntypedCap as usize;
|
||||||
let mut ram = RAM_ALLOCATOR.lock();
|
let mut ram = RAM_ALLOCATOR.lock();
|
||||||
ram.blocks_mut()
|
ram.blocks_mut()
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -99,22 +87,25 @@ fn create_untyped_memory(cnode_obj: &mut CNodeObject, free_idx: &mut usize) {
|
|||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"[root] creating untyped memory: {}: {:?} -> {:?}, slot #{}",
|
"[root] creating untyped memory: {}: {:?} -> {:?}, slot #{}",
|
||||||
free_idx,
|
memory_idx,
|
||||||
start,
|
start,
|
||||||
start + (1 << bits),
|
start + (1 << bits),
|
||||||
free_idx
|
memory_idx
|
||||||
);
|
);
|
||||||
|
|
||||||
let cap = UntypedCap::mint(0, bits, false, start);
|
let cap = UntypedCap::mint(0, bits, false, start);
|
||||||
let cap_entry = CapEntry::new(cap);
|
let cap_entry = CapEntry::new(cap);
|
||||||
cnode_obj[*free_idx] = cap_entry;
|
cnode_obj[memory_idx] = cap_entry;
|
||||||
*free_idx += 1;
|
memory_idx += 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
assert!(ram.blocks().iter().all(|b| b.is_none()));
|
assert!(ram.blocks().iter().all(|b| b.is_none()));
|
||||||
|
|
||||||
|
memory_idx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_untyped_device(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt) {
|
fn create_untyped_device(cnode_obj: &mut CNodeObject, memory_idx: usize, fdt: &Fdt) -> usize {
|
||||||
|
let mut device_idx = memory_idx;
|
||||||
let memory = fdt.memory();
|
let memory = fdt.memory();
|
||||||
|
|
||||||
fdt.all_nodes().filter_map(|n| n.reg()).for_each(|r| {
|
fdt.all_nodes().filter_map(|n| n.reg()).for_each(|r| {
|
||||||
@ -143,23 +134,25 @@ fn create_untyped_device(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt:
|
|||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"[root] creating untyped device: {}: {:?} -> {:?}, slot #{}",
|
"[root] creating untyped device: {}: {:?} -> {:?}, slot #{}",
|
||||||
free_idx,
|
device_idx,
|
||||||
start,
|
start,
|
||||||
start + (1 << bits),
|
start + (1 << bits),
|
||||||
free_idx
|
device_idx
|
||||||
);
|
);
|
||||||
|
|
||||||
let cap = UntypedCap::mint(0, bits, true, start);
|
let cap = UntypedCap::mint(0, bits, true, start);
|
||||||
let cap_entry = CapEntry::new(cap);
|
let cap_entry = CapEntry::new(cap);
|
||||||
cnode_obj[*free_idx] = cap_entry;
|
cnode_obj[device_idx] = cap_entry;
|
||||||
*free_idx += 1;
|
device_idx += 1;
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
device_idx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_objects<T: KernelObject + ?Sized>(
|
fn alloc_objects<T: KernelObject + ?Sized>(
|
||||||
cnode_obj: &mut CNodeObject,
|
cnode_obj: &mut CNodeObject,
|
||||||
free_idx: usize,
|
end_idx: usize,
|
||||||
user_obj_bits: usize,
|
user_obj_bits: usize,
|
||||||
range: Range<usize>,
|
range: Range<usize>,
|
||||||
) {
|
) {
|
||||||
@ -167,12 +160,12 @@ fn alloc_objects<T: KernelObject + ?Sized>(
|
|||||||
|
|
||||||
let (memory, slots) = {
|
let (memory, slots) = {
|
||||||
let (prologue, remain) = cnode_obj.split_at_mut(untyped_start);
|
let (prologue, remain) = cnode_obj.split_at_mut(untyped_start);
|
||||||
let (memory, epilogue) = remain.split_at_mut(free_idx - untyped_start);
|
let (memory, epilogue) = remain.split_at_mut(end_idx - untyped_start);
|
||||||
|
|
||||||
match range {
|
match range {
|
||||||
r if r.end <= untyped_start => (memory, &mut prologue[r]),
|
r if r.end <= untyped_start => (memory, &mut prologue[r]),
|
||||||
r if r.start >= free_idx => (memory, &mut epilogue[(r.start - free_idx)..(r.end - free_idx)]),
|
r if r.start >= end_idx => (memory, &mut epilogue[(r.start - end_idx)..(r.end - end_idx)]),
|
||||||
_ => panic!("init: slot range overlaps with allocated objects"),
|
_ => panic!("init: slot range overlaps with untyped memory"),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,74 +187,44 @@ fn alloc_objects<T: KernelObject + ?Sized>(
|
|||||||
panic!("init: untyped memory is exhausted");
|
panic!("init: untyped memory is exhausted");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_objects(cnode_obj: &mut CNodeObject, free_idx: &mut usize, cnode_entry: &CapEntry) {
|
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
|
// vspace
|
||||||
{
|
{
|
||||||
// root
|
// root
|
||||||
let vspace_idx = CNodeSlot::VSpaceCap as usize;
|
let vspace_idx = CNodeSlot::VSpaceCap as usize;
|
||||||
trace!("[root] allocating vspace object at slot #{}", vspace_idx);
|
trace!("[root] allocating vspace object at slot #{}", vspace_idx);
|
||||||
alloc_objects::<TableObject>(cnode_obj, *free_idx, PAGE_BITS, vspace_idx..vspace_idx + 1);
|
alloc_objects::<TableObject>(cnode_obj, end_idx, PAGE_BITS, vspace_idx..vspace_idx + 1);
|
||||||
|
|
||||||
// copy pagetable
|
// copy pagetable
|
||||||
let root = &cnode_obj[vspace_idx];
|
let root = &cnode_obj[vspace_idx];
|
||||||
copy_kernel_pagetable(root);
|
copy_kernel_pagetable(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// tcb
|
// bootinfo
|
||||||
{
|
{
|
||||||
let tcb_idx = CNodeSlot::TcbCap as usize;
|
let bootinfo_idx = CNodeSlot::BootInfoFrameCap as usize;
|
||||||
trace!("[root] allocating tcb object at slot #{}", tcb_idx);
|
trace!("[root] allocating bootinfo object at slot #{}", bootinfo_idx);
|
||||||
alloc_objects::<TcbObject>(cnode_obj, *free_idx, 0, tcb_idx..tcb_idx + 1);
|
alloc_objects::<FrameObject>(cnode_obj, end_idx, PAGE_BITS, bootinfo_idx..bootinfo_idx + 1);
|
||||||
|
|
||||||
let tcb = &cnode_obj[CNodeSlot::TcbCap as usize];
|
|
||||||
let vspace = &cnode_obj[CNodeSlot::VSpaceCap as usize];
|
|
||||||
|
|
||||||
let mut tcb_cap = TcbCap::try_from(tcb).unwrap();
|
|
||||||
let tcb = tcb_cap.as_object_mut();
|
|
||||||
|
|
||||||
*tcb = TcbObject::new();
|
|
||||||
assert!(tcb.tid() == ROOT_ASID, "init: root tcb tid is invalid");
|
|
||||||
|
|
||||||
tcb.set_cspace(cnode_entry.clone());
|
|
||||||
tcb.set_vspace(vspace.clone());
|
|
||||||
tcb.set_state(tcb::ThreadState::Idle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! get_root_table {
|
fn load_root_server(cnode_obj: &mut CNodeObject, end_idx: usize, fdt: &Fdt) -> usize {
|
||||||
($cnode_obj:expr) => {{
|
let mut table = {
|
||||||
let root = &$cnode_obj[CNodeSlot::VSpaceCap as usize];
|
let root = &cnode_obj[CNodeSlot::VSpaceCap as usize];
|
||||||
let root_vaddr = TableCap::try_from(root).unwrap().as_object::<Level0>().vaddr();
|
let root_vaddr = TableCap::try_from(root).unwrap().as_object::<Level0>().vaddr();
|
||||||
|
|
||||||
// use unsafe to workaround borrow checker
|
// use unsafe to workaround borrow checker
|
||||||
unsafe { Table::new(root_vaddr) }
|
unsafe { Table::new(root_vaddr) }
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: figure out a better way to create a `load_page` function for `map_range`
|
|
||||||
macro_rules! create_load_page {
|
|
||||||
($cnode_obj:expr, $free_idx:expr) => {
|
|
||||||
|mapped_addr| {
|
|
||||||
trace!("[root] allocating pagetable at slot #{}", $free_idx);
|
|
||||||
|
|
||||||
alloc_objects::<TableObject>($cnode_obj, *$free_idx, PAGE_BITS, *$free_idx..*$free_idx + 1);
|
|
||||||
*$free_idx += 1;
|
|
||||||
|
|
||||||
let page = &$cnode_obj[*$free_idx - 1];
|
|
||||||
let page = TableCap::try_from(page).unwrap();
|
|
||||||
|
|
||||||
page.set_mapped(true);
|
|
||||||
page.set_mapped_asid(ROOT_ASID);
|
|
||||||
page.set_mapped_vaddr(mapped_addr);
|
|
||||||
|
|
||||||
let table: Table<Level0> = page.as_object(); // Any level is fine
|
|
||||||
|
|
||||||
table.paddr()
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
fn get_rootfs(fdt: &Fdt) -> cpio::Reader<'static> {
|
let mut rootfs = unsafe {
|
||||||
let chosen = fdt.find_node("/chosen").expect("/chosen is required");
|
let chosen = fdt.find_node("/chosen").expect("/chosen is required");
|
||||||
|
|
||||||
let initrd_start = chosen
|
let initrd_start = chosen
|
||||||
@ -278,17 +241,13 @@ fn get_rootfs(fdt: &Fdt) -> cpio::Reader<'static> {
|
|||||||
.as_usize()
|
.as_usize()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let vaddr = unsafe { mmap_phys_to_virt(PhysAddr(initrd_start)) };
|
let vaddr = mmap_phys_to_virt(PhysAddr(initrd_start));
|
||||||
let len = initrd_end - initrd_start;
|
let len = initrd_end - initrd_start;
|
||||||
|
|
||||||
let data = unsafe { core::slice::from_raw_parts(vaddr.as_const_ptr(), len) };
|
let data = core::slice::from_raw_parts(vaddr.as_const_ptr(), len);
|
||||||
cpio::Reader::new(data)
|
cpio::Reader::new(data)
|
||||||
}
|
};
|
||||||
|
|
||||||
fn load_root_server(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt) {
|
|
||||||
let mut table = get_root_table!(cnode_obj);
|
|
||||||
|
|
||||||
let mut rootfs = get_rootfs(fdt);
|
|
||||||
let root_entry = rootfs
|
let root_entry = rootfs
|
||||||
.find_map(|entry| {
|
.find_map(|entry| {
|
||||||
if let Ok(entry) = entry {
|
if let Ok(entry) = entry {
|
||||||
@ -302,6 +261,7 @@ fn load_root_server(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt
|
|||||||
|
|
||||||
let root_elf = ElfBytes::<AnyEndian>::minimal_parse(root_entry.data()).expect("init: invalid root server");
|
let root_elf = ElfBytes::<AnyEndian>::minimal_parse(root_entry.data()).expect("init: invalid root server");
|
||||||
|
|
||||||
|
let mut nxt_slot = end_idx;
|
||||||
root_elf
|
root_elf
|
||||||
.segments()
|
.segments()
|
||||||
.expect("init: root server has no segments")
|
.expect("init: root server has no segments")
|
||||||
@ -346,16 +306,16 @@ fn load_root_server(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt
|
|||||||
debug_assert!(block_size >= PAGE_SIZE);
|
debug_assert!(block_size >= PAGE_SIZE);
|
||||||
|
|
||||||
// allocate frame
|
// allocate frame
|
||||||
trace!("[initrd] allocating frame at slot #{}", free_idx);
|
trace!("[initrd] allocating frame at slot #{}", nxt_slot);
|
||||||
alloc_objects::<FrameObject>(cnode_obj, *free_idx, block_bits, *free_idx..*free_idx + 1);
|
alloc_objects::<FrameObject>(cnode_obj, end_idx, block_bits, nxt_slot..nxt_slot + 1);
|
||||||
*free_idx += 1;
|
nxt_slot += 1;
|
||||||
|
|
||||||
// copy data
|
// copy data
|
||||||
let mut frame = FrameCap::try_from(&cnode_obj[*free_idx - 1]).unwrap();
|
let mut frame = FrameCap::try_from(&cnode_obj[nxt_slot - 1]).unwrap();
|
||||||
let mem = frame.as_object_mut();
|
let mem = frame.as_object_mut();
|
||||||
copy(cur, mem);
|
copy(cur, mem);
|
||||||
|
|
||||||
// map attributes
|
// map frame to vspace
|
||||||
let vaddr = seg_addr + cur;
|
let vaddr = seg_addr + cur;
|
||||||
let paddr = unsafe { mmap_virt_to_phys(VirtAddr::from(mem as *const _ as *const u8)) };
|
let paddr = unsafe { mmap_virt_to_phys(VirtAddr::from(mem as *const _ as *const u8)) };
|
||||||
let attr = {
|
let attr = {
|
||||||
@ -374,12 +334,19 @@ fn load_root_server(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt
|
|||||||
attr
|
attr
|
||||||
};
|
};
|
||||||
|
|
||||||
// manually set frame object
|
let alloc_page = || {
|
||||||
frame.set_mapped_asid(ROOT_ASID);
|
trace!("[initrd] allocating pagetable at slot #{}", nxt_slot);
|
||||||
frame.set_mapped_vaddr(vaddr);
|
|
||||||
|
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 to vspace
|
|
||||||
let alloc_page = create_load_page!(cnode_obj, free_idx);
|
|
||||||
map_range(alloc_page, &mut table, vaddr, paddr, block_size, attr);
|
map_range(alloc_page, &mut table, vaddr, paddr, block_size, attr);
|
||||||
|
|
||||||
// update pointer
|
// update pointer
|
||||||
@ -387,40 +354,5 @@ fn load_root_server(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut tcb_cap = TcbCap::try_from(&cnode_obj[CNodeSlot::TcbCap as usize]).unwrap();
|
nxt_slot
|
||||||
let tcb = tcb_cap.as_object_mut();
|
|
||||||
tcb.trapframe.set_pc(root_elf.ehdr.e_entry as usize);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_misc(cnode_obj: &mut CNodeObject, free_idx: &mut usize, fdt: &Fdt) {
|
|
||||||
// NOTE: there are no FrameObjects referencing these memory regions
|
|
||||||
|
|
||||||
let mut table = get_root_table!(cnode_obj);
|
|
||||||
let attr = MapAttr::USER_ACCESSIBLE | MapAttr::READABLE;
|
|
||||||
|
|
||||||
// map fdt
|
|
||||||
{
|
|
||||||
assert!(fdt.total_size() < ROOT_FDT_MAX_SIZE, "init: fdt is too large");
|
|
||||||
|
|
||||||
let fdt_vaddr = FDT.load(Ordering::Relaxed);
|
|
||||||
let fdt_vaddr = VirtAddr::from(fdt_vaddr);
|
|
||||||
let fdt_paddr = unsafe { mmap_virt_to_phys(fdt_vaddr) };
|
|
||||||
let fdt_size = align_up(fdt.total_size(), PAGE_SIZE);
|
|
||||||
|
|
||||||
let alloc_page = create_load_page!(cnode_obj, free_idx);
|
|
||||||
map_range(alloc_page, &mut table, ROOT_FDT_ADDR, fdt_paddr, fdt_size, attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
// map rootfs
|
|
||||||
{
|
|
||||||
let rootfs = get_rootfs(fdt);
|
|
||||||
assert!(rootfs.data().len() < ROOT_INITRD_MAX_SIZE, "init: initrd is too large");
|
|
||||||
|
|
||||||
let initrd_vaddr = VirtAddr::from(rootfs.data().as_ptr());
|
|
||||||
let initrd_paddr = unsafe { mmap_virt_to_phys(initrd_vaddr) };
|
|
||||||
let initrd_size = align_up(rootfs.data().len(), PAGE_SIZE);
|
|
||||||
|
|
||||||
let alloc_page = create_load_page!(cnode_obj, free_idx);
|
|
||||||
map_range(alloc_page, &mut table, ROOT_INITRD_ADDR, initrd_paddr, initrd_size, attr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -166,10 +166,6 @@ impl<'a> Reader<'a> {
|
|||||||
pub fn new(data: &'a [u8]) -> Self {
|
pub fn new(data: &'a [u8]) -> Self {
|
||||||
Reader { data }
|
Reader { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn data(&self) -> &'a [u8] {
|
|
||||||
self.data
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Reader<'a> {
|
impl<'a> Iterator for Reader<'a> {
|
||||||
|
3
root/.gitignore
vendored
3
root/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
*.cpio
|
|
||||||
*.o
|
|
||||||
root
|
|
@ -1,21 +0,0 @@
|
|||||||
AS = riscv64-elf-as
|
|
||||||
LD = riscv64-elf-ld
|
|
||||||
|
|
||||||
ASFLAGS += -march=rv64imac -mabi=lp64
|
|
||||||
|
|
||||||
.PHONY: all clean
|
|
||||||
|
|
||||||
all: init.cpio
|
|
||||||
|
|
||||||
%.o: %.S
|
|
||||||
$(AS) $(ASFLAGS) -c $< -o $@
|
|
||||||
|
|
||||||
root: root.o
|
|
||||||
$(LD) -Tlink.ld $^ -o $@
|
|
||||||
|
|
||||||
init.cpio: root
|
|
||||||
find . -type f -not -name "*.cpio" | cpio -ov -H crc > init.cpio
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f *.o root
|
|
||||||
rm -f init.cpio
|
|
16
root/link.ld
16
root/link.ld
@ -1,16 +0,0 @@
|
|||||||
OUTPUT_ARCH(riscv)
|
|
||||||
ENTRY(_start)
|
|
||||||
|
|
||||||
PHDRS {
|
|
||||||
text PT_LOAD FLAGS (5);
|
|
||||||
rodata PT_LOAD FLAGS (4);
|
|
||||||
data PT_LOAD FLAGS (6);
|
|
||||||
}
|
|
||||||
|
|
||||||
SECTIONS {
|
|
||||||
. = 0x400000;
|
|
||||||
.text : { *(.text .text.* ); . = ALIGN(4096); } : text
|
|
||||||
.rodata : { *(.rodata .rodata.*); . = ALIGN(4096); } : rodata
|
|
||||||
.data : { *(.data .data.* ); . = ALIGN(4096); } : data
|
|
||||||
.bss : { *(.bss .bss.* ); . = ALIGN(4096); } : data
|
|
||||||
}
|
|
19
root/root.S
19
root/root.S
@ -1,19 +0,0 @@
|
|||||||
.macro syscall msg ptr
|
|
||||||
li a0, \msg
|
|
||||||
li a1, \ptr
|
|
||||||
ecall
|
|
||||||
.endm
|
|
||||||
|
|
||||||
.text
|
|
||||||
.global _start
|
|
||||||
_start:
|
|
||||||
la t0, msg
|
|
||||||
.loop:
|
|
||||||
lb a2, 0(t0)
|
|
||||||
beqz a2, _start # print forever
|
|
||||||
syscall (1<<12 | 1), 1 # see uapi/syscall.rs
|
|
||||||
addi t0, t0, 1
|
|
||||||
j .loop
|
|
||||||
|
|
||||||
.data
|
|
||||||
msg : .string "Hello, world!\n\0"
|
|
@ -1,9 +0,0 @@
|
|||||||
use utils::{addr::VirtAddr, size::MIB};
|
|
||||||
|
|
||||||
pub const ROOT_FDT_ADDR: VirtAddr = VirtAddr(0xfbf0_0000);
|
|
||||||
pub const ROOT_FDT_MAX_SIZE: usize = 1 * MIB;
|
|
||||||
pub const ROOT_FDT_MAX_BITS: usize = ROOT_FDT_MAX_SIZE.ilog2() as usize;
|
|
||||||
|
|
||||||
pub const ROOT_INITRD_ADDR: VirtAddr = VirtAddr(0xfc00_0000);
|
|
||||||
pub const ROOT_INITRD_MAX_SIZE: usize = 64 * MIB;
|
|
||||||
pub const ROOT_INITRD_MAX_BITS: usize = ROOT_INITRD_MAX_SIZE.ilog2() as usize;
|
|
@ -4,6 +4,7 @@ pub enum CNodeSlot {
|
|||||||
TcbCap,
|
TcbCap,
|
||||||
CNodeCap,
|
CNodeCap,
|
||||||
VSpaceCap,
|
VSpaceCap,
|
||||||
|
BootInfoFrameCap,
|
||||||
UntypedCap,
|
UntypedCap,
|
||||||
// IrqControlCap
|
// IrqControlCap
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
extern crate num_derive;
|
extern crate num_derive;
|
||||||
|
|
||||||
pub mod cap;
|
pub mod cap;
|
||||||
pub mod consts;
|
|
||||||
pub mod cspace;
|
pub mod cspace;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod fault;
|
pub mod fault;
|
||||||
|
Loading…
Reference in New Issue
Block a user