[wip] compile fixes -- to split
This commit is contained in:
parent
0e1c0e45f7
commit
b594552f23
|
@ -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!("<<vesper[T{} \"{}\" @{}]: Attempted reply operation when no reply capability present.>>", 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 {
|
||||
//...
|
||||
}
|
||||
// }
|
||||
|
|
|
@ -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) {}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() -> ! {
|
||||
|
|
|
@ -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<()>;
|
||||
}
|
||||
|
|
|
@ -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<()>;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
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<PhysAddr>;///??
|
||||
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<PhysAddr>; //??
|
||||
}
|
||||
|
||||
// ARM AArch64 processors have a four-level page-table structure, where the
|
||||
|
@ -62,7 +76,6 @@ trait VirtSpace {
|
|||
// +--PageTable (L3)
|
||||
// +--Page<Size4KiB> -- aka Page
|
||||
|
||||
|
||||
/// Cache data management.
|
||||
trait PageCacheManagement {
|
||||
/// Cleans the data cache out to RAM.
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
use crate::arch::{
|
||||
memory::{PhysAddr, VirtAddr},
|
||||
objects::PageCacheManagement,
|
||||
};
|
||||
|
||||
struct Page {}
|
||||
|
||||
impl Page {
|
||||
|
@ -11,29 +16,29 @@ impl Page {
|
|||
fn get_address() -> Result<PhysAddr> {
|
||||
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 {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
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!()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
use crate::arch::{memory::PhysAddr, objects::PageCacheManagement};
|
||||
|
||||
// L0 table
|
||||
struct PageGlobalDirectory {
|
||||
// @todo should also impl VirtSpace to be able to map shit?
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
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!()
|
||||
}
|
||||
|
|
|
@ -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) {}
|
|
@ -3,8 +3,10 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
#[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::*;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<u128, [<$name Cap>]::Register>);
|
||||
impl [<$name Capability>] {
|
||||
type Type = [<$name Cap>]::Register;
|
||||
}
|
||||
impl Capability for [<$name Capability>] {
|
||||
#[inline]
|
||||
fn as_u128(&self) -> u128 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
pub(crate) trait KernelObject {
|
||||
pub(crate) trait NucleusObject {
|
||||
fn size_bits() -> usize;
|
||||
fn invoke();
|
||||
}
|
|
@ -3,51 +3,135 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
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<SingleStepping>;
|
||||
fn get_breakpoint(bp_num: u16) -> Result<BreakpointInfo>;
|
||||
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 <<SchedContext>>
|
||||
|
||||
// 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<SingleStepping>;
|
||||
// fn get_breakpoint(bp_num: u16) -> Result<BreakpointInfo>;
|
||||
// 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 <<SchedContext>>
|
||||
//
|
||||
// // 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<SingleStepping>;
|
||||
// fn get_breakpoint(bp_num: u16) -> Result<BreakpointInfo>;
|
||||
// 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<()>;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,17 @@
|
|||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||
*/
|
||||
|
||||
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<T: NucleusObject>(
|
||||
target_cap: CapNodeRootedPath,
|
||||
target_cap_offset: usize,
|
||||
num_objects: usize,
|
||||
) -> Result<CapSlice, RetypeError> {
|
||||
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<T: NucleusObject>(
|
||||
target_cap: CapNodeRootedPath,
|
||||
target_cap_offset: usize,
|
||||
num_objects: usize,
|
||||
) -> Result<CapSlice>; // @todo return an array of caps?
|
||||
}
|
||||
|
||||
// with GATs
|
||||
// trait Retyped { type Result = CapTable::<T> .. }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
pub fn syscall(number: u64) {
|
||||
asm!("svc #1234")
|
||||
pub fn syscall(_number: u64) {
|
||||
unsafe { asm!("svc #1234") }
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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<SingleStepping>;
|
||||
fn get_breakpoint(bp_num: u16) -> Result<BreakpointInfo>;
|
||||
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 <<SchedContext>>
|
||||
|
||||
// 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 {
|
||||
// ...
|
||||
}
|
Loading…
Reference in New Issue