[wip] compile fixes -- to split

This commit is contained in:
Berkus Decker 2021-01-04 03:36:33 +02:00
parent 0e1c0e45f7
commit b594552f23
27 changed files with 382 additions and 208 deletions

View File

@ -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 {
//...
}
// }

View File

@ -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) {}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -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

View File

@ -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() -> ! {

View File

@ -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<()>;
}

View File

@ -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<()>;
}

View File

@ -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.

View File

@ -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 {

View File

@ -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!()
}

View File

@ -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?

View File

@ -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!()
}

View File

@ -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!()
}

View File

@ -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) {}

View File

@ -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::*;
}
}

View File

@ -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));
}
}

View File

@ -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 {

View File

@ -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
}
}

View File

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

View File

@ -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();
}

View File

@ -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<()>;
}

View File

@ -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> .. }

View File

@ -1,3 +1,3 @@
pub fn syscall(number: u64) {
asm!("svc #1234")
pub fn syscall(_number: u64) {
unsafe { asm!("svc #1234") }
}

View File

@ -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)]

View File

@ -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 {
// ...
}