mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
Compare commits
6 Commits
e6abb50f86
...
93df10c5a2
Author | SHA1 | Date | |
---|---|---|---|
93df10c5a2 | |||
95dc7144c6 | |||
5ea8a56611 | |||
18240fec26 | |||
067a7996b4 | |||
4647d1fd2a |
25
.vscode/launch.json
vendored
Normal file
25
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug",
|
||||||
|
"preLaunchTask": "build test",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/target/test_exe",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "/usr/bin/gdb-multiarch",
|
||||||
|
"miDebuggerServerAddress": "localhost:1234",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "set output-radix 16"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
2
.vscode/prepare_test.sh
vendored
Executable file
2
.vscode/prepare_test.sh
vendored
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cargo xtask test --arch=riscv64 --dump 2>/dev/null | jq -r '[inputs] | map(select(has("executable")) | .executable) | last' | xargs -I{} cp {} target/test_exe
|
11
.vscode/tasks.json
vendored
Normal file
11
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"label": "build test",
|
||||||
|
"command": "./.vscode/prepare_test.sh",
|
||||||
|
"problemMatcher": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -20,6 +20,8 @@ impl Default for ObjectType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ObjectType {
|
impl ObjectType {
|
||||||
|
const CNODE_BITS: usize = 6;
|
||||||
|
|
||||||
pub const fn size(&self, user_obj_bits: usize) -> usize {
|
pub const fn size(&self, user_obj_bits: usize) -> usize {
|
||||||
1 << self.bits(user_obj_bits)
|
1 << self.bits(user_obj_bits)
|
||||||
}
|
}
|
||||||
@ -28,7 +30,7 @@ impl ObjectType {
|
|||||||
#![rustfmt::skip]
|
#![rustfmt::skip]
|
||||||
match self {
|
match self {
|
||||||
ObjectType::Null => 0, // TODO: fill it!
|
ObjectType::Null => 0, // TODO: fill it!
|
||||||
ObjectType::CNode => 0, // TODO: fill it!
|
ObjectType::CNode => Self::CNODE_BITS + user_obj_bits,
|
||||||
ObjectType::TCB => 0, // TODO: fill it!
|
ObjectType::TCB => 0, // TODO: fill it!
|
||||||
ObjectType::SchedCtx => 0, // TODO: fill it!
|
ObjectType::SchedCtx => 0, // TODO: fill it!
|
||||||
ObjectType::Endpoint => 0, // TODO: fill it!
|
ObjectType::Endpoint => 0, // TODO: fill it!
|
||||||
|
66
kernel/src/arch/riscv/backtrace.rs
Normal file
66
kernel/src/arch/riscv/backtrace.rs
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
use super::layout::{BSS_END, BSS_START, TEXT_END, TEXT_START};
|
||||||
|
use crate::plat::backtrace::FrameWalker;
|
||||||
|
use vspace::addr::{AddressOps, VirtAddr};
|
||||||
|
|
||||||
|
impl FrameWalker {
|
||||||
|
fn read_fp() -> usize {
|
||||||
|
let fp;
|
||||||
|
unsafe { core::arch::asm!("mv {}, fp", out(reg) fp) }
|
||||||
|
fp
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_ra() -> usize {
|
||||||
|
let ra;
|
||||||
|
unsafe { core::arch::asm!("mv {}, ra", out(reg) ra) }
|
||||||
|
ra
|
||||||
|
}
|
||||||
|
|
||||||
|
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() };
|
||||||
|
fp_valid && pc_valid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new() -> Self {
|
||||||
|
// current_{fp, pc} is deliberately missed for printing
|
||||||
|
Self {
|
||||||
|
current_fp: VirtAddr::from(FrameWalker::read_fp()),
|
||||||
|
current_pc: VirtAddr::from(FrameWalker::read_ra()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for crate::plat::backtrace::FrameWalker {
|
||||||
|
type Item = Self;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
/*
|
||||||
|
* Prologue like this:
|
||||||
|
* > addi sp,sp,-16
|
||||||
|
* > sd ra,8(sp)
|
||||||
|
* > sd s0,0(sp)
|
||||||
|
* > addi s0,sp,16
|
||||||
|
*
|
||||||
|
* Epilogue like this:
|
||||||
|
* > ld ra,8(sp)
|
||||||
|
* > ld s0,0(sp)
|
||||||
|
* > addi sp,sp,16
|
||||||
|
* > jr ra
|
||||||
|
*
|
||||||
|
* prev_fp = *(current_fp - 16)
|
||||||
|
* prev_pc = *(current_fp - 8)
|
||||||
|
*/
|
||||||
|
|
||||||
|
if !self.is_valid() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_fp = unsafe { *self.current_fp.as_const_ptr::<usize>().offset(-2) };
|
||||||
|
let prev_pc = unsafe { *self.current_fp.as_const_ptr::<usize>().offset(-1) };
|
||||||
|
|
||||||
|
self.current_fp = VirtAddr::from(prev_fp);
|
||||||
|
self.current_pc = VirtAddr::from(prev_pc);
|
||||||
|
|
||||||
|
Some(*self)
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod backtrace;
|
||||||
mod entry;
|
mod entry;
|
||||||
pub mod layout;
|
pub mod layout;
|
||||||
mod lowlevel;
|
mod lowlevel;
|
||||||
|
@ -12,7 +12,7 @@ use vspace::paging::*;
|
|||||||
#[thread_local]
|
#[thread_local]
|
||||||
static KERNEL_PAGETABLE: Mutex<Option<&mut Table>> = Mutex::new(None);
|
static KERNEL_PAGETABLE: Mutex<Option<&mut Table>> = Mutex::new(None);
|
||||||
|
|
||||||
static KERNEL_ALLOCATOR: Mutex<RamBlock<8>> = Mutex::new(RamBlock::new());
|
pub static KERNEL_ALLOCATOR: Mutex<RamBlock<8>> = Mutex::new(RamBlock::new());
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn alloc_page() -> PhysAddr {
|
fn alloc_page() -> PhysAddr {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
use crate::plat::{
|
||||||
|
backtrace::dump_backtrace,
|
||||||
|
lowlevel::{Hardware, LowLevel},
|
||||||
|
};
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use crate::plat::lowlevel::{Hardware, LowLevel};
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(info: &PanicInfo) -> ! {
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
error!("Kernel panic!");
|
error!("Kernel panic!");
|
||||||
@ -19,5 +20,7 @@ fn panic(info: &PanicInfo) -> ! {
|
|||||||
None => error!("[lang] Panicked: {}", info.message().unwrap()),
|
None => error!("[lang] Panicked: {}", info.message().unwrap()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe { dump_backtrace() };
|
||||||
|
|
||||||
Hardware::shutdown(true);
|
Hardware::shutdown(true);
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
|
use crate::objects::null::NullCap;
|
||||||
use api::cap::ObjectType;
|
use api::cap::ObjectType;
|
||||||
use core::{cell::Cell, ptr::NonNull};
|
use core::{cell::Cell, ptr::NonNull};
|
||||||
use vspace::addr::PhysAddr;
|
use vspace::addr::PhysAddr;
|
||||||
|
|
||||||
/// RawCap is the specific implementation of capability which stores in CNode
|
/// RawCap is the specific implementation of capability which stores in CNode
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default, PartialEq, Eq)]
|
||||||
pub struct RawCap {
|
pub struct RawCap {
|
||||||
// TODO: this could be an enum, figure out a way to do this
|
// TODO: this could be an enum, figure out a way to do this
|
||||||
/// args: in vanilla seL4 implementation, a cap use two 64-bit words to store all information,
|
/// args: in vanilla seL4 implementation, a cap use two 64-bit words to store all information,
|
||||||
@ -15,6 +16,8 @@ pub struct RawCap {
|
|||||||
pub ptr: PhysAddr,
|
pub ptr: PhysAddr,
|
||||||
/// cap_type: every capability links to one specific object
|
/// cap_type: every capability links to one specific object
|
||||||
pub cap_type: ObjectType,
|
pub cap_type: ObjectType,
|
||||||
|
/// _padding: padding to align the size of RawCap to power of 2
|
||||||
|
pub _padding: [usize; 2],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawCap {
|
impl RawCap {
|
||||||
@ -23,6 +26,7 @@ impl RawCap {
|
|||||||
args: [arg0, arg1],
|
args: [arg0, arg1],
|
||||||
ptr,
|
ptr,
|
||||||
cap_type,
|
cap_type,
|
||||||
|
_padding: [0, 0],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,11 +37,14 @@ pub struct Link {
|
|||||||
pub next: Option<NonNull<CapEntry>>,
|
pub next: Option<NonNull<CapEntry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct CapEntry {
|
pub struct CapEntry {
|
||||||
pub cap: Cell<RawCap>,
|
pub cap: Cell<RawCap>,
|
||||||
pub link: Cell<Link>,
|
pub link: Cell<Link>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const_assert_eq!(core::mem::size_of::<CapEntry>(), ObjectType::CNode.size(0));
|
||||||
|
|
||||||
impl CapEntry {
|
impl CapEntry {
|
||||||
pub fn new(cap: RawCap) -> Self {
|
pub fn new(cap: RawCap) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -47,7 +54,7 @@ impl CapEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(&mut self) {
|
pub fn init(&mut self) {
|
||||||
self.cap = Cell::new(RawCap::default());
|
self.cap = Cell::new(NullCap::mint());
|
||||||
self.link = Cell::new(Link::default());
|
self.link = Cell::new(Link::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,3 +74,9 @@ impl CapEntry {
|
|||||||
self.link.get_mut().next = next;
|
self.link.get_mut().next = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<RawCap> for CapEntry {
|
||||||
|
fn from(value: RawCap) -> Self {
|
||||||
|
Self::new(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -75,21 +75,21 @@ impl<'a> CNodeCap<'a> {
|
|||||||
1 << self.radix()
|
1 << self.radix()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_object(&self) -> &CNodeObject {
|
pub fn as_object(&self) -> &CNodeObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
||||||
core::slice::from_raw_parts(virt.as_const_ptr(), self.length())
|
core::slice::from_raw_parts(virt.as_const_ptr(), self.length())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_object_mut(&mut self) -> &mut CNodeObject {
|
pub fn as_object_mut(&mut self) -> &mut CNodeObject {
|
||||||
unsafe {
|
unsafe {
|
||||||
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
let virt = mmap_phys_to_virt(self.cte.cap.get().ptr);
|
||||||
core::slice::from_raw_parts_mut(virt.as_mut_ptr(), self.length())
|
core::slice::from_raw_parts_mut(virt.as_mut_ptr(), self.length())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&CapEntry, CapFault> {
|
pub fn resolve_address_bits(&self, cap_ptr: usize, n_bits: usize) -> Result<&CapEntry, CapFault> {
|
||||||
let mut bits_remaining = n_bits;
|
let mut bits_remaining = n_bits;
|
||||||
let mut slot = self.cte;
|
let mut slot = self.cte;
|
||||||
|
|
||||||
@ -133,3 +133,153 @@ impl<'a> CNodeCap<'a> {
|
|||||||
Ok(slot)
|
Ok(slot)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::arch::vspace::KERNEL_ALLOCATOR;
|
||||||
|
use crate::objects::cap::CapEntry;
|
||||||
|
use crate::objects::null::NullCap;
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_cnode_resolve() {
|
||||||
|
let create_cnode = |radix: usize, guard_size: usize, guard: usize| {
|
||||||
|
let size = ObjectType::CNode.size(radix);
|
||||||
|
let layout = Layout::from_size_align(size, 1).unwrap();
|
||||||
|
let ptr = KERNEL_ALLOCATOR.lock().alloc(layout).unwrap();
|
||||||
|
let raw = CNodeCap::mint(radix, guard_size, guard, ptr);
|
||||||
|
CapEntry::new(raw)
|
||||||
|
};
|
||||||
|
|
||||||
|
let cte1 = create_cnode(4, 4, 0b1001);
|
||||||
|
let cte2 = create_cnode(3, 4, 0b0110);
|
||||||
|
let cte3 = create_cnode(2, 4, 0b1010);
|
||||||
|
|
||||||
|
let mut cnode1 = CNodeCap::try_from(&cte1).unwrap();
|
||||||
|
let mut cnode2 = CNodeCap::try_from(&cte2).unwrap();
|
||||||
|
let mut cnode3 = CNodeCap::try_from(&cte3).unwrap();
|
||||||
|
|
||||||
|
cnode1.as_object_mut()[6] = cte2.clone();
|
||||||
|
cnode2.as_object_mut()[1] = cte3.clone();
|
||||||
|
cnode3.as_object_mut()[2] = NullCap::mint().into();
|
||||||
|
cnode3.as_object_mut()[2].cap.update(|mut cap| {
|
||||||
|
cap.args[0] = 0xdeadbeef;
|
||||||
|
cap.args[1] = 0xaa55aa55;
|
||||||
|
cap
|
||||||
|
});
|
||||||
|
|
||||||
|
{
|
||||||
|
// cte2.clone() cte3.clone() should not modify cte itself
|
||||||
|
info!("Testing whether RawCap and Cap held the same cap");
|
||||||
|
assert!(cnode2.cte.cap.get() == cte2.cap.get());
|
||||||
|
assert!(cnode3.cte.cap.get() == cte3.cap.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
let root = cnode1;
|
||||||
|
|
||||||
|
/* Layout:
|
||||||
|
* cnode1: 2^4 slots, 4 bits guard, guard value is 0b1001
|
||||||
|
* cnode2: 2^3 slots, 4 bits guard, guard value is 0b0110
|
||||||
|
* cnode3: 2^2 slots, 4 bits guard, guard value is 0b1010
|
||||||
|
*
|
||||||
|
* root -----> | cnode1 |
|
||||||
|
* 0: | ...... | addr = 0b1001_0110
|
||||||
|
* 6: | cnode2 | -----------------> | cnode2 |
|
||||||
|
* 15: | ...... | 0: | ...... | addr = 0b0110_001
|
||||||
|
* guard: | 0b1001 | 1: | cnode3 | ----------------> | cnode3 |
|
||||||
|
* 7: | ...... | 0: | ...... |
|
||||||
|
* guard: | 0b0110 | 2: | target | addr = 0b1010_10
|
||||||
|
* 3: | ...... |
|
||||||
|
* guard: | 0b1010 |
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
// resolve to cte2
|
||||||
|
// * cnode2 addr = 0b1001_0110 = 0x96
|
||||||
|
// * cnode2 length = 8
|
||||||
|
info!("Testing resolve to cte2");
|
||||||
|
let target = root.resolve_address_bits(0x96, 8).unwrap();
|
||||||
|
assert!(target.cap.get() == cte2.cap.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// resolve to cte3
|
||||||
|
// * cnode3 addr = 0b1001_0110_0110_001 = 0x4b31
|
||||||
|
// * cnode3 length = 15
|
||||||
|
info!("Testing resolve to cte3");
|
||||||
|
let target = root.resolve_address_bits(0x4b31, 15).unwrap();
|
||||||
|
assert!(target.cap.get() == cte3.cap.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// resolve to target
|
||||||
|
// * target addr = 0b1001_0110_0110_001_1010_10 = 0x12cc6a
|
||||||
|
// * target length = 21
|
||||||
|
info!("Testing resolve to target");
|
||||||
|
let target = root.resolve_address_bits(0x12cc6a, 21).unwrap();
|
||||||
|
assert!(target.cap.get().args[0] == 0xdeadbeef);
|
||||||
|
assert!(target.cap.get().args[1] == 0xaa55aa55);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// level_bits > bits_remaining
|
||||||
|
info!("Testing invalid depth (1)");
|
||||||
|
let result = root.resolve_address_bits(0x96, 8 - 1);
|
||||||
|
match result {
|
||||||
|
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||||
|
assert_eq!(bits_found, 8);
|
||||||
|
assert_eq!(bits_left, 7);
|
||||||
|
},
|
||||||
|
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// level_bits > bits_remaining
|
||||||
|
info!("Testing invalid depth (2)");
|
||||||
|
let result = root.resolve_address_bits(0x4b31 >> 1, 15 - 1);
|
||||||
|
match result {
|
||||||
|
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||||
|
assert_eq!(bits_found, 7);
|
||||||
|
assert_eq!(bits_left, 6);
|
||||||
|
},
|
||||||
|
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// guard mismatch
|
||||||
|
// orig: 0b1001_0110_0110_001 = 0x4b31
|
||||||
|
// mod: 0b1001_0110_1110_001 = 0x4b71
|
||||||
|
info!("Testing guard mismatch");
|
||||||
|
let result = root.resolve_address_bits(0x4b71, 15);
|
||||||
|
match result {
|
||||||
|
Err(CapFault::GuardMismatch {
|
||||||
|
bits_left,
|
||||||
|
guard_found,
|
||||||
|
guard_size,
|
||||||
|
}) => {
|
||||||
|
assert_eq!(bits_left, 7);
|
||||||
|
assert_eq!(guard_found, 0b0110);
|
||||||
|
assert_eq!(guard_size, 4);
|
||||||
|
},
|
||||||
|
_ => panic!("not returning CapFault::GuardMismatch"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// extra bits
|
||||||
|
info!("Testing extra bits");
|
||||||
|
let result = root.resolve_address_bits(0x96 << 1, 8 + 1);
|
||||||
|
match result {
|
||||||
|
Err(CapFault::DepthMismatch { bits_found, bits_left }) => {
|
||||||
|
assert_eq!(bits_found, 7);
|
||||||
|
assert_eq!(bits_left, 1);
|
||||||
|
},
|
||||||
|
_ => panic!("not returning CapFault::DepthMismatch"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -89,7 +89,7 @@ impl UntypedCap<'_> {
|
|||||||
slots
|
slots
|
||||||
.iter()
|
.iter()
|
||||||
.any(|cte| NullCap::try_from(cte).is_err())
|
.any(|cte| NullCap::try_from(cte).is_err())
|
||||||
.then_ok((), SysError::CapTypeMismatch)?;
|
.else_ok((), SysError::CapTypeMismatch)?;
|
||||||
|
|
||||||
// Start allocating from free_offset
|
// Start allocating from free_offset
|
||||||
// Notice: in vallina seL4, it will check whether there are child nodes,
|
// Notice: in vallina seL4, it will check whether there are child nodes,
|
||||||
@ -130,3 +130,100 @@ impl UntypedCap<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::{arch::vspace::KERNEL_ALLOCATOR, objects::cap::CapEntry};
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use log::info;
|
||||||
|
|
||||||
|
fn alloc_mem(size: usize) -> PhysAddr {
|
||||||
|
assert!(size.is_power_of_two());
|
||||||
|
let layout = Layout::from_size_align(size, 1).unwrap();
|
||||||
|
KERNEL_ALLOCATOR.lock().alloc(layout).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_untyped_cte(size: usize, is_device: bool) -> CapEntry {
|
||||||
|
let ptr = alloc_mem(size);
|
||||||
|
let raw = UntypedCap::mint(0, size.ilog2() as usize, is_device, ptr);
|
||||||
|
CapEntry::new(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_cnode_cte(size: usize, guard_size: usize, guard: usize) -> CapEntry {
|
||||||
|
let ptr = alloc_mem(size);
|
||||||
|
let radix = size.ilog2() as usize - ObjectType::CNode.bits(0);
|
||||||
|
let raw = CNodeCap::mint(radix, guard_size, guard, ptr);
|
||||||
|
CapEntry::new(raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_untyped_retype_cnode() {
|
||||||
|
// create untyped
|
||||||
|
let untyped_cte = create_untyped_cte(4 * ObjectType::CNode.size(2), false); // 4 cnode (4 entries each)
|
||||||
|
let mut untyped = UntypedCap::try_from(&untyped_cte).unwrap();
|
||||||
|
|
||||||
|
// create root cnode
|
||||||
|
let cnode_cte = create_cnode_cte(ObjectType::CNode.size(4), 3, 0b110); // 1 cnode (16 entries)
|
||||||
|
let mut cnode = CNodeCap::try_from(&cnode_cte).unwrap();
|
||||||
|
|
||||||
|
// slots
|
||||||
|
let slots = cnode.as_object_mut();
|
||||||
|
|
||||||
|
// retype untyped to cnode
|
||||||
|
info!("Retyping to ObjectType::CNode");
|
||||||
|
untyped.retype(ObjectType::CNode, 2, &mut slots[1..2]).unwrap();
|
||||||
|
untyped.retype(ObjectType::CNode, 2, &mut slots[9..12]).unwrap();
|
||||||
|
|
||||||
|
// check untyped
|
||||||
|
info!("Checking remain space in untyped");
|
||||||
|
assert_eq!(untyped.free_offset(), untyped.block_size());
|
||||||
|
assert!(untyped.retype(ObjectType::CNode, 1, &mut slots[0..1]).is_err());
|
||||||
|
|
||||||
|
// check cnode
|
||||||
|
info!("Checking retyped cnode length");
|
||||||
|
for addr in [1, 9, 10, 11] {
|
||||||
|
let cte = cnode.resolve_address_bits(0b110_0000 | addr, 7).unwrap();
|
||||||
|
let cap = CNodeCap::try_from(cte).unwrap();
|
||||||
|
let len = cap.as_object().len();
|
||||||
|
assert_eq!(len, 4);
|
||||||
|
}
|
||||||
|
info!("Make sure other cnodes are not modified");
|
||||||
|
for addr in 0..16 {
|
||||||
|
if [1, 9, 10, 11].contains(&addr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let cte = cnode.resolve_address_bits(0b110_0000 | addr, 7).unwrap();
|
||||||
|
NullCap::try_from(cte).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test_case]
|
||||||
|
fn test_untyped_retype_device_err() {
|
||||||
|
// create untyped
|
||||||
|
let untyped_cte = create_untyped_cte(ObjectType::CNode.size(1), true);
|
||||||
|
let mut untyped = UntypedCap::try_from(&untyped_cte).unwrap();
|
||||||
|
|
||||||
|
// create root cnode
|
||||||
|
let cnode_cte = create_cnode_cte(ObjectType::CNode.size(1), 3, 0b110);
|
||||||
|
let mut cnode = CNodeCap::try_from(&cnode_cte).unwrap();
|
||||||
|
|
||||||
|
// slots
|
||||||
|
let slots = cnode.as_object_mut();
|
||||||
|
|
||||||
|
// allocate fail
|
||||||
|
info!("Retyping to ObjectType::CNode with device memory");
|
||||||
|
untyped
|
||||||
|
.retype(ObjectType::CNode, 1, &mut slots[0..1])
|
||||||
|
.is_err()
|
||||||
|
.then_ok((), ())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// nothing should be changed
|
||||||
|
info!("Make sure nothing is changed");
|
||||||
|
assert_eq!(untyped.free_offset(), 0);
|
||||||
|
NullCap::try_from(&slots[0]).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: more tests
|
||||||
|
}
|
||||||
|
26
kernel/src/plat/backtrace.rs
Normal file
26
kernel/src/plat/backtrace.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use log::error;
|
||||||
|
use vspace::addr::VirtAddr;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct FrameWalker {
|
||||||
|
pub current_fp: VirtAddr,
|
||||||
|
pub current_pc: VirtAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn dump_backtrace() {
|
||||||
|
let mut depth = 0;
|
||||||
|
|
||||||
|
error!("Dumping stack trace ...");
|
||||||
|
|
||||||
|
let walker = FrameWalker::new();
|
||||||
|
for frame in walker {
|
||||||
|
error!("#{:02} PC: {:#x?} FP: {:#x?}", depth, frame.current_pc, frame.current_fp);
|
||||||
|
depth += 1;
|
||||||
|
if depth >= 100 {
|
||||||
|
error!("Backtrace is too deep, aborting ...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error!("Backtrace complete");
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
pub mod backtrace;
|
||||||
pub mod console;
|
pub mod console;
|
||||||
pub mod lowlevel;
|
pub mod lowlevel;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
|
@ -19,8 +19,12 @@ impl Arch {
|
|||||||
"-Zbuild-std=core,compiler_builtins,alloc",
|
"-Zbuild-std=core,compiler_builtins,alloc",
|
||||||
"-Zbuild-std-features=compiler-builtins-mem",
|
"-Zbuild-std-features=compiler-builtins-mem",
|
||||||
];
|
];
|
||||||
const FLAGS_RELOCATION: [&'static str; 3] =
|
const FLAGS_RELOCATION: [&'static str; 4] = [
|
||||||
["-Crelocation-model=static", "-Ccode-model=medium", "-Ctarget-feature=+relax"];
|
"-Crelocation-model=static",
|
||||||
|
"-Ccode-model=medium",
|
||||||
|
"-Ctarget-feature=+relax",
|
||||||
|
"-Cforce-frame-pointers=yes",
|
||||||
|
];
|
||||||
|
|
||||||
pub fn cargo_args(&self, test: bool) -> Vec<String> {
|
pub fn cargo_args(&self, test: bool) -> Vec<String> {
|
||||||
let mut args: Vec<String> = Vec::new();
|
let mut args: Vec<String> = Vec::new();
|
||||||
@ -47,12 +51,6 @@ impl Arch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bits(&self) -> u32 {
|
|
||||||
match self {
|
|
||||||
Arch::RISCV64 => 64,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn board_arch_name(&self) -> String {
|
pub fn board_arch_name(&self) -> String {
|
||||||
"riscv".to_string()
|
"riscv".to_string()
|
||||||
}
|
}
|
||||||
|
@ -6,16 +6,32 @@ use xshell::cmd;
|
|||||||
pub struct Test {
|
pub struct Test {
|
||||||
#[command(flatten)]
|
#[command(flatten)]
|
||||||
pub artifact: Artifact,
|
pub artifact: Artifact,
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
pub debug: bool,
|
||||||
|
#[arg(long, default_value_t = false)]
|
||||||
|
pub dump: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Test {
|
impl Test {
|
||||||
pub fn run(&self) -> anyhow::Result<()> {
|
pub fn run(&self) -> anyhow::Result<()> {
|
||||||
let sh = crate::shell()?;
|
let sh = crate::shell()?;
|
||||||
|
|
||||||
|
let mut extra_args: Vec<&str> = Vec::new();
|
||||||
|
if self.debug && !self.dump {
|
||||||
|
extra_args.push("--");
|
||||||
|
extra_args.push("-s");
|
||||||
|
extra_args.push("-S");
|
||||||
|
}
|
||||||
|
if self.dump {
|
||||||
|
extra_args.push("--no-run");
|
||||||
|
extra_args.push("--message-format=json")
|
||||||
|
}
|
||||||
|
|
||||||
cmd!(sh, "cargo test")
|
cmd!(sh, "cargo test")
|
||||||
.env("CARGO_ENCODED_RUSTFLAGS", self.artifact.rust_flags()?.join("\x1f"))
|
.env("CARGO_ENCODED_RUSTFLAGS", self.artifact.rust_flags()?.join("\x1f"))
|
||||||
.args(["--bin", "kernel"])
|
.args(["--bin", "kernel"])
|
||||||
.args(self.artifact.cargo_args(true)?)
|
.args(self.artifact.cargo_args(true)?)
|
||||||
|
.args(extra_args)
|
||||||
.run()?;
|
.run()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
Reference in New Issue
Block a user