From b594552f236012b72eb50b67947ad8f88fbbc057 Mon Sep 17 00:00:00 2001 From: Berkus Decker Date: Mon, 4 Jan 2021 03:36:33 +0200 Subject: [PATCH] [wip] compile fixes -- to split --- nucleus/src/api.rs | 135 +++++--------- nucleus/src/arch/aarch64/abi.rs | 2 +- .../arch/aarch64/caps/page_directory_cap.rs | 9 +- .../aarch64/caps/page_global_directory_cap.rs | 12 +- .../src/arch/aarch64/caps/page_table_cap.rs | 9 +- nucleus/src/arch/aarch64/memory/mod.rs | 1 + nucleus/src/arch/aarch64/mod.rs | 2 + .../src/arch/aarch64/objects/asid_control.rs | 2 +- nucleus/src/arch/aarch64/objects/asid_pool.rs | 2 +- nucleus/src/arch/aarch64/objects/mod.rs | 23 ++- nucleus/src/arch/aarch64/objects/page.rs | 41 +++-- .../arch/aarch64/objects/page_directory.rs | 4 +- .../aarch64/objects/page_global_directory.rs | 2 + .../src/arch/aarch64/objects/page_table.rs | 6 +- .../aarch64/objects/page_upper_directory.rs | 4 +- nucleus/src/arch/aarch64/objects/thread.rs | 11 ++ nucleus/src/arch/mod.rs | 12 +- nucleus/src/caps/captable.rs | 14 +- nucleus/src/caps/mod.rs | 10 +- nucleus/src/main.rs | 6 + nucleus/src/objects/mod.rs | 5 +- .../{kernel_object.rs => nucleus_object.rs} | 2 +- nucleus/src/objects/thread.rs | 168 +++++++++++++----- nucleus/src/objects/untyped.rs | 42 +++-- vesper-user/src/arch/aarch64/syscall.rs | 4 +- vesper-user/src/lib.rs | 16 ++ vesper-user/src/objects/thread.rs | 46 +++++ 27 files changed, 382 insertions(+), 208 deletions(-) create mode 100644 nucleus/src/arch/aarch64/objects/thread.rs rename nucleus/src/objects/{kernel_object.rs => nucleus_object.rs} (82%) create mode 100644 vesper-user/src/objects/thread.rs diff --git a/nucleus/src/api.rs b/nucleus/src/api.rs index 7b2d416..9f92844 100644 --- a/nucleus/src/api.rs +++ b/nucleus/src/api.rs @@ -8,42 +8,50 @@ //! Arch-specific kernel ABI decodes syscall invocations and calls API functions to perform actual //! operations. -use vesper_user::SysCall as SysCall; +use { + vesper_user::SysCall as SysCall, + crate::println, + snafu::Snafu, + crate::arch, + crate::arch::memory::{PhysAddr, VirtAddr}, + crate::objects::thread::ThreadState, + crate::caps::{ReplyCapability, NullCapability}, +}; // Syscalls (kernel API) trait API { // Three below (send, nb_send, call) are "invocation" syscalls. - fn send(cap: Cap, msg_info: MessageInfo); - fn nb_send(dest: Cap, msg_info: MessageInfo); - fn call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>; + // fn send(cap: Cap, msg_info: MessageInfo); + // fn nb_send(dest: Cap, msg_info: MessageInfo); + // fn call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>; // Wait for message, when it is received, // return object Badge and block caller on `reply`. - fn recv(src: Cap, reply: Cap) -> Result<(MessageInfo, Option<&Badge>)>; - fn reply(msg_info: MessageInfo); + // fn recv(src: Cap, reply: Cap) -> Result<(MessageInfo, Option<&Badge>)>; + // fn reply(msg_info: MessageInfo); // As Recv but invoke `reply` first. - fn reply_recv( - src: Cap, - reply: Cap, - msg_info: MessageInfo, - ) -> Result<(MessageInfo, Option<&Badge>)>; - fn nb_recv(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>; - fn r#yield(); + // fn reply_recv( + // src: Cap, + // reply: Cap, + // msg_info: MessageInfo, + // ) -> Result<(MessageInfo, Option<&Badge>)>; + // fn nb_recv(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>; + // fn r#yield(); // -- end of default seL4 syscall list -- // As ReplyRecv but invoke `dest` not `reply`. - fn nb_send_recv( - dest: Cap, - msg_info: MessageInfo, - src: Cap, - reply: Cap, - ) -> Result<(MessageInfo, Options<&Badge>)>; + // fn nb_send_recv( + // dest: Cap, + // msg_info: MessageInfo, + // src: Cap, + // reply: Cap, + // ) -> Result<(MessageInfo, Options<&Badge>)>; // As NBSendRecv, with no reply. Donation is not possible. - fn nb_send_wait( - cap: Cap, - msg_info: MessageInfo, - src: Cap, - ) -> Result<(MessageInfo, Option<&Badge>)>; + // fn nb_send_wait( + // cap: Cap, + // msg_info: MessageInfo, + // src: Cap, + // ) -> Result<(MessageInfo, Option<&Badge>)>; // As per Recv, but donation not possible. - fn wait(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>; + // fn wait(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>; // Plus some debugging calls... } @@ -175,29 +183,31 @@ fn handle_invocation(is_call: bool, is_blocking: bool) -> Result<()> { Ok(()) } -fn handle_receive(is_blocking: bool) { +fn handle_receive(is_blocking: bool) -> Result<()> { let endpoint_cap_ptr = KernelCurrentThread.get_register(capRegister); let result = KernelCurrentThread.lookup_cap(endpoint_cap_ptr); if result.is_err() { - KernelCurrentFault = Fault_CapFault::new(endpoint_cap_ptr, true); + // KernelCurrentFault = Fault_CapFault::new(endpoint_cap_ptr, true); handle_fault(KernelCurrentThread); return Ok(()); } - match result.cap.get_type() { - endpoint => , - notification => , - _ => fault, + match result.capability.get_type() { + endpoint => Ok(()), + notification => Ok(()), + _ => Ok(()), //fault, } } fn handle_reply() { let caller_slot = KernelCurrentThread.get_caller_slot(); let caller_cap = caller_slot.capability; + const reply_cap = ReplyCapability::Type::Type.value; + const null_cap = NullCapability::Type::Type.value; match caller_cap.get_type() { - ReplyCap::Type.value => { + reply_cap => { // if (cap_reply_cap_get_capReplyMaster(callerCap)) { // break; // } @@ -205,7 +215,7 @@ fn handle_reply() { // if(!(caller != ksCurThread)) _assert_fail("caller must not be the current thread", "src/api/syscall.c", 313, __FUNCTION__); // do_reply_transfer(ksCurThread, caller, callerSlot); }, - NullCap::Type.value => { + null_cap => { println!("<>", KernelCurrentThread, KernelCurrentThread.name, KernelCurrentThread.get_restart_pc()); }, _ => { @@ -293,53 +303,6 @@ fn handle_interrupt_entry() -> Result<()> { Ok(()) } -/* TCB: size 64 bytes + sizeof(arch_tcb_t) (aligned to nearest power of 2) */ -struct TCB { - arch_tcb: arch::TCB, - state: ThreadState, // 12 bytes? - /* Notification that this TCB is bound to. If this is set, when this TCB waits on - * any sync endpoint, it may receive a signal from a Notification object. - * 4 bytes*/ - // notification_t *tcbBoundNotification; - fault: Fault, // 8 bytes? - lookup_failure: LookupFault, // 8 bytes - /* Domain, 1 byte (packed to 4) */ - domain: Domain, - /* maximum controlled priorioty, 1 byte (packed to 4) */ - mcp: Priority, - /* Priority, 1 byte (packed to 4) */ - priority: Priority, - /* Timeslice remaining, 4 bytes */ - time_slice: u32, - /* Capability pointer to thread fault handler, 4 bytes */ - fault_handler: CapPath, - /* userland virtual address of thread IPC buffer, 4 bytes */ - ipc_buffer: VirtAddr, - /* Previous and next pointers for scheduler queues , 8 bytes */ - sched_next: *mut TCB, - sched_prev: *mut TCB, - /* Previous and next pointers for endpoint and notification queues, 8 bytes */ - ep_next: *mut TCB, - ep_prev: *mut TCB, - /* Use any remaining space for a thread name */ - name: &str, -} - -impl TCB { - fn get_register(...) {} - fn lookup_cap_and_slot() -> Result<()> {} - fn get_restart_pc() {} - fn lookup_ipc_buffer(some: bool) {} - fn lookup_extra_caps() -> Result<()> {} - fn get_state() -> ThreadState {} - fn set_state(state: ThreadState) {} - - fn get_caller_slot() -> Slot {} - fn send_fault_ipc(&self) {} - - fn replyFromKernel_success_empty() {} - fn replyFromKernel_error() {} -} //handleSyscall(syscall) in the slowpath() // these are expressed in terms of // handleInvocation(bool isCall, bool isBlocking) @@ -352,7 +315,7 @@ impl TCB { // Call and ReplyRecv have fastpath handlers // the rest goes through slowpath -// c_handle_syscall called directly from SWI vector entry +// c_handle_syscall called directly from SVC vector entry struct Scheduler; @@ -384,13 +347,13 @@ impl Scheduler { fn activate_thread() {} - fn dequeue(thread: &mut TCB); - fn append(thread: &mut TCB); - fn reschedule_required(); + fn dequeue(thread: &mut TCB) {} + fn append(thread: &mut TCB) {} + fn reschedule_required() {} } struct Nucleus {} -impl API for Nucleus { +// impl API for Nucleus { //... -} +// } diff --git a/nucleus/src/arch/aarch64/abi.rs b/nucleus/src/arch/aarch64/abi.rs index c2fc422..79a834c 100644 --- a/nucleus/src/arch/aarch64/abi.rs +++ b/nucleus/src/arch/aarch64/abi.rs @@ -14,4 +14,4 @@ /// Implements C ABI to easily parse passed in parameters. /// @todo Move this to aarch64-specific part. #[no_mangle] -extern "C" pub(crate) syscall_entry() {} +extern "C" pub(crate) syscall_entry(syscall_no: u64) {} diff --git a/nucleus/src/arch/aarch64/caps/page_directory_cap.rs b/nucleus/src/arch/aarch64/caps/page_directory_cap.rs index c34550a..79809b1 100644 --- a/nucleus/src/arch/aarch64/caps/page_directory_cap.rs +++ b/nucleus/src/arch/aarch64/caps/page_directory_cap.rs @@ -5,6 +5,7 @@ use { crate::{ + arch::memory::{PhysAddr, VirtAddr, ASID}, capdef, caps::{CapError, Capability}, }, @@ -37,19 +38,19 @@ capdef! { PageDirectory } //===================== impl PageDirectoryCapability { - pub(crate) fn base_address() -> PhysAddr { + pub(crate) fn base_address(&self) -> PhysAddr { PhysAddr::new(self.0.read(PageDirectoryCap::BasePtr)) } - pub(crate) fn is_mapped() -> bool { + pub(crate) fn is_mapped(&self) -> bool { self.0.read(PageDirectoryCap::IsMapped) == 1 } - pub(crate) fn mapped_address() -> VirtAddr { + pub(crate) fn mapped_address(&self) -> VirtAddr { VirtAddr::new(self.0.read(PageDirectoryCap::MappedAddress)) } - pub(crate) fn mapped_asid() -> ASID { + pub(crate) fn mapped_asid(&self) -> ASID { self.0.read(PageDirectoryCap::MappedASID) } } diff --git a/nucleus/src/arch/aarch64/caps/page_global_directory_cap.rs b/nucleus/src/arch/aarch64/caps/page_global_directory_cap.rs index 665cd03..c2f0623 100644 --- a/nucleus/src/arch/aarch64/caps/page_global_directory_cap.rs +++ b/nucleus/src/arch/aarch64/caps/page_global_directory_cap.rs @@ -5,6 +5,7 @@ use { crate::{ + arch::memory::{PhysAddr, VirtAddr, ASID}, capdef, caps::{CapError, Capability}, }, @@ -36,19 +37,18 @@ capdef! { PageGlobalDirectory } //===================== impl PageGlobalDirectoryCapability { - pub(crate) fn base_address() -> PhysAddr { + pub(crate) fn base_address(&self) -> PhysAddr { PhysAddr::new(self.0.read(PageGlobalDirectoryCap::BasePtr)) } - pub(crate) fn is_mapped() -> bool { + pub(crate) fn is_mapped(&self) -> bool { self.0.read(PageGlobalDirectoryCap::IsMapped) == 1 } - pub(crate) fn mapped_address() -> VirtAddr { - VirtAddr::new(self.0.read(PageGlobalDirectoryCap::MappedAddress)) - } + // Global directory does not give access to mapped addresses, + // instead, it links to lower page directory levels. - pub(crate) fn mapped_asid() -> ASID { + pub(crate) fn mapped_asid(&self) -> ASID { self.0.read(PageGlobalDirectoryCap::MappedASID) } } diff --git a/nucleus/src/arch/aarch64/caps/page_table_cap.rs b/nucleus/src/arch/aarch64/caps/page_table_cap.rs index 1bece2b..e4432b3 100644 --- a/nucleus/src/arch/aarch64/caps/page_table_cap.rs +++ b/nucleus/src/arch/aarch64/caps/page_table_cap.rs @@ -5,6 +5,7 @@ use { crate::{ + arch::memory::{PhysAddr, VirtAddr, ASID}, capdef, caps::{CapError, Capability}, }, @@ -37,19 +38,19 @@ capdef! { PageTable } //===================== impl PageTableCapability { - pub(crate) fn base_address() -> PhysAddr { + pub(crate) fn base_address(&self) -> PhysAddr { PhysAddr::new(self.0.read(PageTableCap::BasePtr)) } - pub(crate) fn is_mapped() -> bool { + pub(crate) fn is_mapped(&self) -> bool { self.0.read(PageTableCap::IsMapped) == 1 } - pub(crate) fn mapped_address() -> VirtAddr { + pub(crate) fn mapped_address(&self) -> VirtAddr { VirtAddr::new(self.0.read(PageTableCap::MappedAddress)) } - pub(crate) fn mapped_asid() -> ASID { + pub(crate) fn mapped_asid(&self) -> ASID { self.0.read(PageTableCap::MappedASID) } } diff --git a/nucleus/src/arch/aarch64/memory/mod.rs b/nucleus/src/arch/aarch64/memory/mod.rs index 5e9dd12..8338e81 100644 --- a/nucleus/src/arch/aarch64/memory/mod.rs +++ b/nucleus/src/arch/aarch64/memory/mod.rs @@ -16,6 +16,7 @@ pub mod mmu; pub use addr::PhysAddr; pub use addr::VirtAddr; +pub use addr::ASID; // aarch64 granules and page sizes howto: // https://stackoverflow.com/questions/34269185/simultaneous-existence-of-different-sized-pages-on-aarch64 diff --git a/nucleus/src/arch/aarch64/mod.rs b/nucleus/src/arch/aarch64/mod.rs index f090d37..e7c0ad5 100644 --- a/nucleus/src/arch/aarch64/mod.rs +++ b/nucleus/src/arch/aarch64/mod.rs @@ -16,6 +16,8 @@ pub mod memory; pub mod objects; pub mod traps; +pub(crate) use objects::thread::user_stack_trace; + /// Loop forever in sleep mode. #[inline] pub fn endless_sleep() -> ! { diff --git a/nucleus/src/arch/aarch64/objects/asid_control.rs b/nucleus/src/arch/aarch64/objects/asid_control.rs index d2fb341..3d545ad 100644 --- a/nucleus/src/arch/aarch64/objects/asid_control.rs +++ b/nucleus/src/arch/aarch64/objects/asid_control.rs @@ -5,5 +5,5 @@ // implemented for x86 and arm trait ASIDControl { - fn make_pool(untyped: Untyped, target_cap_space_cap: CapNodeRootedPath) -> Result<()>; + // fn make_pool(untyped: Untyped, target_cap_space_cap: CapNodeRootedPath) -> Result<()>; } diff --git a/nucleus/src/arch/aarch64/objects/asid_pool.rs b/nucleus/src/arch/aarch64/objects/asid_pool.rs index 68835ab..bdd4749 100644 --- a/nucleus/src/arch/aarch64/objects/asid_pool.rs +++ b/nucleus/src/arch/aarch64/objects/asid_pool.rs @@ -5,5 +5,5 @@ // implemented for x86 and arm trait ASIDPool { - fn assign(virt_space: VirtSpace /*Cap*/) -> Result<()>; + // fn assign(virt_space: VirtSpace /*Cap*/) -> Result<()>; } diff --git a/nucleus/src/arch/aarch64/objects/mod.rs b/nucleus/src/arch/aarch64/objects/mod.rs index 439d862..e991f3c 100644 --- a/nucleus/src/arch/aarch64/objects/mod.rs +++ b/nucleus/src/arch/aarch64/objects/mod.rs @@ -3,6 +3,8 @@ * Copyright (c) Berkus Decker */ +use crate::memory::{PhysAddr, VirtAddr}; + mod asid_control; mod asid_pool; mod page; @@ -10,6 +12,7 @@ mod page_directory; mod page_global_directory; mod page_table; mod page_upper_directory; +pub(crate) mod thread; // Allocation details @@ -40,10 +43,21 @@ mod page_upper_directory; // * unmap(Page, FrameAllocator)->() trait VirtSpace { - fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, rights: CapRights, attr: VMAttributes) -> Result<()>; /// ?? - fn unmap() -> Result<()>; /// ?? - fn remap(virt_space: VirtSpace/*Cap*/, rights: CapRights, attr: VMAttributes) -> Result<()>; /// ?? - fn get_address() -> Result;///?? + fn map_to( + virt_space: VirtSpace, /*Cap*/ + vaddr: VirtAddr, + rights: u32, //CapRights, + attr: u32, //VMAttributes, + ) -> Result<()>; + /// ?? + fn unmap() -> Result<()>; // ?? + fn remap( + virt_space: VirtSpace, /*Cap*/ + rights: u32, //CapRights, + attr: u32, //VMAttributes, + ) -> Result<()>; + /// ?? + fn get_address() -> Result; //?? } // ARM AArch64 processors have a four-level page-table structure, where the @@ -62,7 +76,6 @@ trait VirtSpace { // +--PageTable (L3) // +--Page -- aka Page - /// Cache data management. trait PageCacheManagement { /// Cleans the data cache out to RAM. diff --git a/nucleus/src/arch/aarch64/objects/page.rs b/nucleus/src/arch/aarch64/objects/page.rs index b15e302..a73ab15 100644 --- a/nucleus/src/arch/aarch64/objects/page.rs +++ b/nucleus/src/arch/aarch64/objects/page.rs @@ -3,6 +3,11 @@ * Copyright (c) Berkus Decker */ +use crate::arch::{ + memory::{PhysAddr, VirtAddr}, + objects::PageCacheManagement, +}; + struct Page {} impl Page { @@ -11,29 +16,29 @@ impl Page { fn get_address() -> Result { todo!() } - fn map( - virt_space: VirtSpace, /*Cap*/ - vaddr: VirtAddr, - rights: CapRights, - attr: VMAttributes, - ) -> Result<()> { - todo!() - } + // fn map( + // virt_space: VirtSpace, /*Cap*/ + // vaddr: VirtAddr, + // rights: CapRights, + // attr: VMAttributes, + // ) -> Result<()> { + // todo!() + // } /// Changes the permissions of an existing mapping. - fn remap( - virt_space: VirtSpace, /*Cap*/ - rights: CapRights, - attr: VMAttributes, - ) -> Result<()> { - todo!() - } + // fn remap( + // virt_space: VirtSpace, /*Cap*/ + // rights: CapRights, + // attr: VMAttributes, + // ) -> Result<()> { + // todo!() + // } fn unmap() -> Result<()> { todo!() } // MMIO space. - fn map_io(iospace: IoSpace /*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()> { - todo!() - } + // fn map_io(iospace: IoSpace /*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()> { + // todo!() + // } } impl PageCacheManagement for Page { diff --git a/nucleus/src/arch/aarch64/objects/page_directory.rs b/nucleus/src/arch/aarch64/objects/page_directory.rs index 2896921..c52188d 100644 --- a/nucleus/src/arch/aarch64/objects/page_directory.rs +++ b/nucleus/src/arch/aarch64/objects/page_directory.rs @@ -3,6 +3,8 @@ * Copyright (c) Berkus Decker */ +use crate::memory::{mmu::PageUpperDirectory, VirtAddr}; + // probably just impl some Mapping trait for these "structs"? // L2 table @@ -12,7 +14,7 @@ impl PageDirectory { fn map( pud: PageUpperDirectory, /*Cap*/ vaddr: VirtAddr, - attr: VMAttributes, + attr: u32, //VMAttributes, ) -> Result<()> { todo!() } diff --git a/nucleus/src/arch/aarch64/objects/page_global_directory.rs b/nucleus/src/arch/aarch64/objects/page_global_directory.rs index 8a2b1ef..03a1f60 100644 --- a/nucleus/src/arch/aarch64/objects/page_global_directory.rs +++ b/nucleus/src/arch/aarch64/objects/page_global_directory.rs @@ -3,6 +3,8 @@ * Copyright (c) Berkus Decker */ +use crate::arch::{memory::PhysAddr, objects::PageCacheManagement}; + // L0 table struct PageGlobalDirectory { // @todo should also impl VirtSpace to be able to map shit? diff --git a/nucleus/src/arch/aarch64/objects/page_table.rs b/nucleus/src/arch/aarch64/objects/page_table.rs index 814edcd..4102dd2 100644 --- a/nucleus/src/arch/aarch64/objects/page_table.rs +++ b/nucleus/src/arch/aarch64/objects/page_table.rs @@ -7,9 +7,9 @@ struct PageTable {} impl PageTable { - fn map(virt_space: VirtSpace /*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { - todo!() - } + // fn map_to(virt_space: VirtSpace /*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { + // todo!() + // } fn unmap() -> Result<()> { todo!() } diff --git a/nucleus/src/arch/aarch64/objects/page_upper_directory.rs b/nucleus/src/arch/aarch64/objects/page_upper_directory.rs index f9203bf..b38d815 100644 --- a/nucleus/src/arch/aarch64/objects/page_upper_directory.rs +++ b/nucleus/src/arch/aarch64/objects/page_upper_directory.rs @@ -3,6 +3,8 @@ * Copyright (c) Berkus Decker */ +use crate::memory::{mmu::PageGlobalDirectory, VirtAddr}; + // L1 table struct PageUpperDirectory {} @@ -10,7 +12,7 @@ impl PageUpperDirectory { fn map( pgd: PageGlobalDirectory, /*Cap*/ vaddr: VirtAddr, - attr: VMAttributes, + attr: u32, //VMAttributes, ) -> Result<()> { todo!() } diff --git a/nucleus/src/arch/aarch64/objects/thread.rs b/nucleus/src/arch/aarch64/objects/thread.rs new file mode 100644 index 0000000..f6543df --- /dev/null +++ b/nucleus/src/arch/aarch64/objects/thread.rs @@ -0,0 +1,11 @@ +//! Arch-specific part of the TCB + +struct UserContext { + registers: [u64; 32], +} + +pub(crate) struct TCB { + register_context: UserContext, +} + +pub(crate) fn user_stack_trace(thread: &TCB) {} diff --git a/nucleus/src/arch/mod.rs b/nucleus/src/arch/mod.rs index aeec869..de8dd2a 100644 --- a/nucleus/src/arch/mod.rs +++ b/nucleus/src/arch/mod.rs @@ -3,8 +3,10 @@ * Copyright (c) Berkus Decker */ -#[cfg(target_arch = "aarch64")] -#[macro_use] -pub mod aarch64; -#[cfg(target_arch = "aarch64")] -pub use self::aarch64::*; +cfg_if::cfg_if! { + if #[cfg(target_arch = "aarch64")] { + #[macro_use] + pub mod aarch64; + pub use self::aarch64::*; + } +} diff --git a/nucleus/src/caps/captable.rs b/nucleus/src/caps/captable.rs index f6ca154..a0dcfca 100644 --- a/nucleus/src/caps/captable.rs +++ b/nucleus/src/caps/captable.rs @@ -4,6 +4,7 @@ */ use crate::caps::Capability; +use snafu::Snafu; use {super::derivation_tree::DerivationTreeNode, /*crate::memory::PhysAddr,*/ core::fmt}; // * Capability slots: 16 bytes of memory per slot (exactly one capability). --? @@ -153,7 +154,7 @@ type CapPath = u64; enum LookupFault { InvalidRoot, GuardMismatch, - DepthMismatch(usize, usize), + DepthMismatch { expected: usize, actual: usize }, NoResolvedBits, } @@ -163,7 +164,7 @@ pub(crate) fn resolve_address_bits( capptr: CapPath, // CapPtr = u64, aka CapPath n_bits: usize, ) -> Result<(Slot, BitsRemaining), LookupFault> { - if node_cap.type() != CapNodeCapability { + if node_cap.get_type() != CapNodeCapability { return Err(LookupFault::InvalidRoot); } let mut n_bits = n_bits; @@ -179,14 +180,17 @@ pub(crate) fn resolve_address_bits( let cap_guard = node_cap.guard(); // @todo common code to extract guard_bits from an int? - let guard = (capptr >> std::min(n_bits - guard_bits, 63)) & ((1 << guard_bits) - 1); + let guard = (capptr >> core::min(n_bits - guard_bits, 63)) & ((1 << guard_bits) - 1); if guard_bits > n_bits || guard != cap_guard { return Err(LookupFault::GuardMismatch); } if level_bits > n_bits { - return Err(LookupFault::DepthMismatch(level_bits, n_bits)); + return Err(LookupFault::DepthMismatch { + expected: level_bits, + actual: n_bits, + }); } let offset = (capptr >> (n_bits - level_bits)) & ((1 << radix_bits) - 1); @@ -200,7 +204,7 @@ pub(crate) fn resolve_address_bits( n_bits -= level_bits; node_cap = slot.capability; - if node_cap.type() != CapNodeCapability { + if node_cap.get_type() != CapNodeCapability { return Ok((slot, n_bits)); } } diff --git a/nucleus/src/caps/mod.rs b/nucleus/src/caps/mod.rs index 204dd2f..08093f3 100644 --- a/nucleus/src/caps/mod.rs +++ b/nucleus/src/caps/mod.rs @@ -34,13 +34,16 @@ mod endpoint_cap; mod irq_control_cap; mod irq_handler_cap; mod notification_cap; -mod null_cap; -mod reply_cap; +pub mod null_cap; +pub mod reply_cap; mod resume_cap; mod thread_cap; mod untyped_cap; mod zombie_cap; +pub use null_cap::NullCapability; +pub use reply_cap::ReplyCapability; + /// Opaque capability object, manipulated by the kernel. pub trait Capability { /// @@ -70,6 +73,9 @@ macro_rules! capdef { paste! { #[doc = "Wrapper representing `" $name "Capability`."] pub struct [<$name Capability>](LocalRegisterCopy]::Register>); + impl [<$name Capability>] { + type Type = [<$name Cap>]::Register; + } impl Capability for [<$name Capability>] { #[inline] fn as_u128(&self) -> u128 { diff --git a/nucleus/src/main.rs b/nucleus/src/main.rs index 4bee691..14630fe 100644 --- a/nucleus/src/main.rs +++ b/nucleus/src/main.rs @@ -36,6 +36,7 @@ use architecture_not_supported_sorry; #[macro_use] pub mod arch; pub use arch::*; +mod api; mod caps; mod devices; mod macros; @@ -363,4 +364,9 @@ mod main_tests { fn test_data_abort_trap() { check_data_abort_trap() } + + #[test_case] + fn test_user_thread_syscall() { + // To test syscall from user-space we need to construct a user-space thread and switch to it + } } diff --git a/nucleus/src/objects/mod.rs b/nucleus/src/objects/mod.rs index 7b766bf..9b766e4 100644 --- a/nucleus/src/objects/mod.rs +++ b/nucleus/src/objects/mod.rs @@ -16,7 +16,8 @@ // * _Capability spaces_ store capabilities (i.e., access rights) to kernel services along with // their book-keeping information. -pub mod kernel_object; +pub mod nucleus_object; +pub mod thread; pub mod untyped; -pub use kernel_object::KernelObject; +pub(crate) use nucleus_object::NucleusObject; diff --git a/nucleus/src/objects/kernel_object.rs b/nucleus/src/objects/nucleus_object.rs similarity index 82% rename from nucleus/src/objects/kernel_object.rs rename to nucleus/src/objects/nucleus_object.rs index 25f00a5..be280a1 100644 --- a/nucleus/src/objects/kernel_object.rs +++ b/nucleus/src/objects/nucleus_object.rs @@ -3,7 +3,7 @@ * Copyright (c) Berkus Decker */ -pub(crate) trait KernelObject { +pub(crate) trait NucleusObject { fn size_bits() -> usize; fn invoke(); } diff --git a/nucleus/src/objects/thread.rs b/nucleus/src/objects/thread.rs index c37d1c9..65d621e 100644 --- a/nucleus/src/objects/thread.rs +++ b/nucleus/src/objects/thread.rs @@ -3,51 +3,135 @@ * Copyright (c) Berkus Decker */ -trait Thread { - // Configuration - // Effectively, SetSpace followed by SetIPCBuffer. - fn configure(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: (), ipc_buffer_frame: Cap, ipc_buffer_offset: usize) -> Result<()>; - fn set_space(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: ()) -> Result<()>; - fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>; - // Debugging tools - fn configure_single_stepping(bp_num: u16, num_insns): Result; - fn get_breakpoint(bp_num: u16) -> Result; - fn set_breakpoint(bp_num: u16, bp: BreakpointInfo) -> Result<()>; - fn unset_breakpoint(bp_num: u16) -> Result<()>; - // Scheduling - fn suspend() -> Result<()>; - fn resume() -> Result<()>; - fn set_priority(authority: TCB/*Cap*/, priority: u32) -> Result<()>; - fn set_mc_priority(authority: TCB/*Cap*/, mcp: u32) -> Result<()>; - fn set_sched_params(authority: TCB/*Cap*/, mcp: u32, priority: u32) -> Result<()>; - fn set_affinity(affinity: u64) -> Result<()>; - // TCB configuration - fn copy_registers(source: TCB/*Cap*/, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> Result<()>; - fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut ArchRegisterContext) -> Result<()>; - fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &ArchRegisterContext) -> Result<()>; - // Notifications - fn bind_notification(notification: CapNode) -> Result<()>; - fn unbind_notification() -> Result<()>; +use crate::{arch, arch::memory::VirtAddr}; - // Arch-specific - // fn set_tls_base(tls_base: usize) -> Result<()>; - // virtualized - x86-specific - // fn set_ept_root(eptpml: X86::EPTPML4) -> Result<()>; -} - -// @todo <> - -// struct Thread {} -struct TCB { - capability: u128, // should actually be a CapPath here - this is the argument to - // Thread.read_registers(cap, ... call for example. -} - -impl Thread for TCB { - // ... -} +// trait Thread { +// // Configuration +// // Effectively, SetSpace followed by SetIPCBuffer. +// fn configure(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: (), ipc_buffer_frame: Cap, ipc_buffer_offset: usize) -> Result<()>; +// fn set_space(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: ()) -> Result<()>; +// fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>; +// // Debugging tools +// fn configure_single_stepping(bp_num: u16, num_insns): Result; +// fn get_breakpoint(bp_num: u16) -> Result; +// fn set_breakpoint(bp_num: u16, bp: BreakpointInfo) -> Result<()>; +// fn unset_breakpoint(bp_num: u16) -> Result<()>; +// // Scheduling +// fn suspend() -> Result<()>; +// fn resume() -> Result<()>; +// fn set_priority(authority: TCB/*Cap*/, priority: u32) -> Result<()>; +// fn set_mc_priority(authority: TCB/*Cap*/, mcp: u32) -> Result<()>; +// fn set_sched_params(authority: TCB/*Cap*/, mcp: u32, priority: u32) -> Result<()>; +// fn set_affinity(affinity: u64) -> Result<()>; +// // TCB configuration +// fn copy_registers(source: TCB/*Cap*/, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> Result<()>; +// fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut ArchRegisterContext) -> Result<()>; +// fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &ArchRegisterContext) -> Result<()>; +// // Notifications +// fn bind_notification(notification: CapNode) -> Result<()>; +// fn unbind_notification() -> Result<()>; +// +// // Arch-specific +// // fn set_tls_base(tls_base: usize) -> Result<()>; +// // virtualized - x86-specific +// // fn set_ept_root(eptpml: X86::EPTPML4) -> Result<()>; +// } +// +// // @todo <> +// +// // struct Thread {} +// struct TCB { +// capability: u128, // should actually be a CapPath here - this is the argument to +// // Thread.read_registers(cap, ... call for example. +// } +// +// impl Thread for TCB { +// // ... +// } // impl super::KernelObject for Thread {} impl super::KernelObject for TCB { const SIZE_BITS: usize = 12; } + +// -- from actual code parts in api.rs + +/* TCB: size 64 bytes + sizeof(arch_tcb_t) (aligned to nearest power of 2) */ +struct TCB { + arch_specific: arch::objects::TCB, + state: ThreadState, // 12 bytes? + /* Notification that this TCB is bound to. If this is set, when this TCB waits on + * any sync endpoint, it may receive a signal from a Notification object. + * 4 bytes*/ + // notification_t *tcbBoundNotification; + fault: Fault, // 8 bytes? + lookup_failure: LookupFault, // 8 bytes + /* Domain, 1 byte (packed to 4) */ + domain: Domain, + /* maximum controlled priorioty, 1 byte (packed to 4) */ + mcp: Priority, + /* Priority, 1 byte (packed to 4) */ + priority: Priority, + /* Timeslice remaining, 4 bytes */ + time_slice: u32, + /* Capability pointer to thread fault handler, 8 bytes */ + fault_handler: CapPath, + /* userland virtual address of thread IPC buffer, 8 bytes */ + ipc_buffer: VirtAddr, + /* Previous and next pointers for scheduler queues , 8+8 bytes */ + sched_next: *mut TCB, + sched_prev: *mut TCB, + /* Previous and next pointers for endpoint and notification queues, 8+8 bytes */ + ep_next: *mut TCB, + ep_prev: *mut TCB, + /* Use any remaining space for a thread name */ + name: &str, + // name_storage: [u8],// add SIZE_BITS calculations for length of storage in here somewhere +} + +pub(crate) enum ThreadState { + Inactive, + Restart, +} + +impl TCB { + fn get_register(&self, register_index: usize) { + self.arch_tcb.register_context.registers[register_index] + } + fn lookup_cap_and_slot() -> Result<()> {} + fn get_restart_pc() {} + fn lookup_ipc_buffer(some: bool) {} + fn lookup_extra_caps() -> Result<()> {} + fn get_state() -> ThreadState {} + fn set_state(state: ThreadState) {} + + fn get_caller_slot() -> Slot {} + fn send_fault_ipc(&self) {} + + fn replyFromKernel_success_empty() {} + fn replyFromKernel_error() {} + // // Configuration + // // Effectively, SetSpace followed by SetIPCBuffer. + // fn configure(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: (), ipc_buffer_frame: Cap, ipc_buffer_offset: usize) -> Result<()>; + // fn set_space(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: ()) -> Result<()>; + // fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>; + // // Debugging tools + // fn configure_single_stepping(bp_num: u16, num_insns): Result; + // fn get_breakpoint(bp_num: u16) -> Result; + // fn set_breakpoint(bp_num: u16, bp: BreakpointInfo) -> Result<()>; + // fn unset_breakpoint(bp_num: u16) -> Result<()>; + // // Scheduling + // fn suspend() -> Result<()>; + // fn resume() -> Result<()>; + // fn set_priority(authority: TCB/*Cap*/, priority: u32) -> Result<()>; + // fn set_mc_priority(authority: TCB/*Cap*/, mcp: u32) -> Result<()>; + // fn set_sched_params(authority: TCB/*Cap*/, mcp: u32, priority: u32) -> Result<()>; + // fn set_affinity(affinity: u64) -> Result<()>; + // // TCB configuration + // fn copy_registers(source: TCB/*Cap*/, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> Result<()>; + // fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut ArchRegisterContext) -> Result<()>; + // fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &ArchRegisterContext) -> Result<()>; + // // Notifications + // fn bind_notification(notification: CapNode) -> Result<()>; + // fn unbind_notification() -> Result<()>; +} diff --git a/nucleus/src/objects/untyped.rs b/nucleus/src/objects/untyped.rs index b3b0569..c5c64d9 100644 --- a/nucleus/src/objects/untyped.rs +++ b/nucleus/src/objects/untyped.rs @@ -3,9 +3,17 @@ * Copyright (c) Berkus Decker */ +use snafu::Snafu; + +// The source of all available memory, device or general. +// Boot code reserves kernel memory and initial mapping allocations (4 pages probably - on rpi3? should be platform-dependent). +// The rest is converted to untypeds with appropriate kind and given away to start thread. + +// Untyped.retype() derives cap to a typed cap (derivation tree must be maintained) + pub(crate) struct Untyped {} -impl super::KernelObject for Untyped { +impl super::NucleusObject for Untyped { fn size_bits() -> usize { unimplemented!() } @@ -15,8 +23,22 @@ impl super::KernelObject for Untyped { } } +#[derive(Debug, Snafu)] +enum RetypeError { + Whatever, +} + impl Untyped { - fn retype() {} + // Uses T::SIZE_BITS to properly size the resulting object + // in some cases size_bits must be passed as argument though... + // @todo return an array of caps? + fn retype( + target_cap: CapNodeRootedPath, + target_cap_offset: usize, + num_objects: usize, + ) -> Result { + Err(RetypeError::Whatever) + } } enum MemoryKind { @@ -24,21 +46,5 @@ enum MemoryKind { Device, } -// The source of all available memory, device or general. -// Boot code reserves kernel memory and initial mapping allocations (4 pages probably - on rpi3? should be platform-dependent). -// The rest is converted to untypeds with appropriate kind and given away to start thread. - -// Untyped.retype() derives cap to a typed cap (derivation tree must be maintained) - -trait Untyped { - // Uses T::SIZE_BITS to properly size the resulting object - // in some cases size_bits must be passed as argument though... - fn retype( - target_cap: CapNodeRootedPath, - target_cap_offset: usize, - num_objects: usize, - ) -> Result; // @todo return an array of caps? -} - // with GATs // trait Retyped { type Result = CapTable:: .. } diff --git a/vesper-user/src/arch/aarch64/syscall.rs b/vesper-user/src/arch/aarch64/syscall.rs index 5e4aace..06b367f 100644 --- a/vesper-user/src/arch/aarch64/syscall.rs +++ b/vesper-user/src/arch/aarch64/syscall.rs @@ -1,3 +1,3 @@ -pub fn syscall(number: u64) { - asm!("svc #1234") +pub fn syscall(_number: u64) { + unsafe { asm!("svc #1234") } } diff --git a/vesper-user/src/lib.rs b/vesper-user/src/lib.rs index a1e29d7..8702c9c 100644 --- a/vesper-user/src/lib.rs +++ b/vesper-user/src/lib.rs @@ -1,7 +1,13 @@ +#![no_std] +#![feature(asm)] + pub mod arch; pub use arch::syscall; +// @todo make this use numeric constants for ABI compat +// but to keep this interface simpler, enum-to-numeric remapping will be implemented inside of the +// syscall() fn. pub enum SysCall { Send, NBSend, @@ -11,6 +17,16 @@ pub enum SysCall { ReplyRecv, NBRecv, Yield, + #[cfg(debug)] + DebugPutChar, + #[cfg(debug)] + DebugHalt, + #[cfg(debug)] + DebugSnapshot, + #[cfg(debug)] + DebugCapIdentify, + #[cfg(debug)] + DebugNameThread, } #[cfg(test)] diff --git a/vesper-user/src/objects/thread.rs b/vesper-user/src/objects/thread.rs new file mode 100644 index 0000000..0f7fde0 --- /dev/null +++ b/vesper-user/src/objects/thread.rs @@ -0,0 +1,46 @@ +// This is probably what a user-space look of the capabilities should look like? Like direct access +// to some kernel objects via possible invocations. +// Some of these functions are probably kernel-space only and so should be removed from user-side interface. +trait Thread { + // Configuration + // Effectively, SetSpace followed by SetIPCBuffer. + fn configure(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: (), ipc_buffer_frame: Cap, ipc_buffer_offset: usize) -> Result<()>; + fn set_space(fault_endpoint: Cap, cap_space_root: Cap, cap_space_root_data: CapNodeConfig, virt_space_root: Cap, virt_space_root_data: ()) -> Result<()>; + fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>; + // Debugging tools + fn configure_single_stepping(bp_num: u16, num_insns): Result; + fn get_breakpoint(bp_num: u16) -> Result; + fn set_breakpoint(bp_num: u16, bp: BreakpointInfo) -> Result<()>; + fn unset_breakpoint(bp_num: u16) -> Result<()>; + // Scheduling + fn suspend() -> Result<()>; + fn resume() -> Result<()>; + fn set_priority(authority: TCB/*Cap*/, priority: u32) -> Result<()>; + fn set_mc_priority(authority: TCB/*Cap*/, mcp: u32) -> Result<()>; + fn set_sched_params(authority: TCB/*Cap*/, mcp: u32, priority: u32) -> Result<()>; + fn set_affinity(affinity: u64) -> Result<()>; + // TCB configuration + fn copy_registers(source: TCB/*Cap*/, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> Result<()>; + fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut ArchRegisterContext) -> Result<()>; + fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &ArchRegisterContext) -> Result<()>; + // Notifications + fn bind_notification(notification: CapNode) -> Result<()>; + fn unbind_notification() -> Result<()>; + + // Arch-specific + // fn set_tls_base(tls_base: usize) -> Result<()>; + // virtualized - x86-specific + // fn set_ept_root(eptpml: X86::EPTPML4) -> Result<()>; +} + +// @todo <> + +// struct Thread {} +struct TCB { + capability: u128, // should actually be a CapPath here - this is the argument to + // Thread.read_registers(cap, ... call for example. +} + +impl Thread for TCB { + // ... +}