[wip] Split kernel objects by type into actual entities
This commit is contained in:
parent
5f7ecca625
commit
3940352be1
|
@ -0,0 +1,82 @@
|
|||
// Syscalls (kernel API)
|
||||
trait API {
|
||||
fn send(cap: Cap, msg_info: MessageInfo);
|
||||
// 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 call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
fn reply(msg_info: MessageInfo);
|
||||
fn nb_send(dest: Cap, msg_info: MessageInfo);
|
||||
// As Recv but invoke `reply` first.
|
||||
fn reply_recv(
|
||||
src: Cap,
|
||||
reply: Cap,
|
||||
msg_info: MessageInfo,
|
||||
) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
// 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_recv(src: Cap) -> Result<(MessageInfo, Option<&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>)>;
|
||||
// As per Recv, but donation not possible.
|
||||
fn wait(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
fn r#yield();
|
||||
// Plus some debugging calls...
|
||||
}
|
||||
|
||||
struct Nucleus {}
|
||||
|
||||
impl API for Nucleus {
|
||||
fn send(cap: _, msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn recv(src: _, reply: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn call(cap: _, msg_info: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn reply(msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send(dest: _, msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn reply_recv(src: _, reply: _, msg_info: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send_recv(dest: _, msg_info: _, src: _, reply: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_recv(src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send_wait(cap: _, msg_info: _, src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn wait(src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn r#yield() {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ pub use self::caps::*;
|
|||
#[cfg(feature = "jtag")]
|
||||
pub mod jtag;
|
||||
pub mod memory;
|
||||
pub mod objects;
|
||||
pub mod traps;
|
||||
|
||||
/// Loop forever in sleep mode.
|
||||
|
|
|
@ -1,465 +0,0 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
// The basic services Vesper provides are as follows:
|
||||
//
|
||||
// * _Threads_ are an abstraction of CPU execution that supports running software;
|
||||
// * _Address spaces_ are virtual memory spaces that each contain an application.
|
||||
// Applications are limited to accessing memory in their address space;
|
||||
// * _Inter-process communication (IPC)_ via endpoints allows threads to communicate using
|
||||
// message passing;
|
||||
// * _Events_ provide a non-blocking signalling mechanism similar to counting semaphores;
|
||||
// * _Device primitives_ allow device drivers to be implemented as unprivileged applications.
|
||||
// The kernel exports hardware device interrupts via IPC messages; and
|
||||
// * _Capability spaces_ store capabilities (i.e., access rights) to kernel services along with
|
||||
// their book-keeping information.
|
||||
|
||||
//================
|
||||
// Kernel objects
|
||||
//================
|
||||
|
||||
register_bitfields! {
|
||||
u128,
|
||||
Endpoint [
|
||||
QueueHead OFFSET(0) NUMBITS(64) [],
|
||||
QueueTail OFFSET(80) NUMBITS(46) [],
|
||||
State OFFSET(126) NUMBITS(2) [
|
||||
Idle = 00b,
|
||||
Send = 01b,
|
||||
Recv = 10b,
|
||||
],
|
||||
],
|
||||
}
|
||||
|
||||
// @todo replace with Event
|
||||
register_bitfields! {
|
||||
u256,
|
||||
Notification [
|
||||
BoundTCB OFFSET(16) NUMBITS(48) [],
|
||||
MsgId OFFSET(64) NUMBITS(64) [],
|
||||
|
||||
QueueHead OFFSET(144) NUMBITS(48) [],
|
||||
QueueTail OFFSET(192) NUMBITS(48) [],
|
||||
State OFFSET(254) NUMBITS(2) [
|
||||
Idle = 00b,
|
||||
Waiting = 01b,
|
||||
Active = 10b,
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
// TCB (Thread)
|
||||
// +--VirtSpace
|
||||
// +--CapSpace
|
||||
|
||||
enum MemoryKind {
|
||||
General,
|
||||
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> .. }
|
||||
|
||||
// MMU
|
||||
|
||||
// ActivePageTable (--> impl VirtSpace for ActivePageTable etc...)
|
||||
// * translate(VirtAddr)->PhysAddr
|
||||
// * translate_page(Page)->PhysAddr
|
||||
// * map_to(Page, PhysFrame, Flags, FrameAllocator)->()
|
||||
// * map(Page, Flags, FrameAllocator)->()
|
||||
// * identity_map(PhysFrame, Flags, FrameAllocator)->()
|
||||
// * 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>;///??
|
||||
}
|
||||
|
||||
// ARM AArch64 processors have a four-level page-table structure, where the
|
||||
// VirtSpace is realised as a PageGlobalDirectory. All paging structures are
|
||||
// indexed by 9 bits of the virtual address.
|
||||
|
||||
// AArch64 page hierarchy:
|
||||
//
|
||||
// PageGlobalDirectory (L0) -- aka VirtSpace
|
||||
// +--PageUpperDirectory (L1)
|
||||
// +--Page<Size1GiB> -- aka HugePage
|
||||
// | or
|
||||
// +--PageDirectory (L2)
|
||||
// +--Page<Size2MiB> -- aka LargePage
|
||||
// | or
|
||||
// +--PageTable (L3)
|
||||
// +--Page<Size4KiB> -- aka Page
|
||||
|
||||
|
||||
/// Cache data management.
|
||||
trait PageCacheManagement {
|
||||
/// Cleans the data cache out to RAM.
|
||||
/// The start and end are relative to the page being serviced.
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Clean and invalidates the cache range within the given page.
|
||||
/// The range will be flushed out to RAM. The start and end are relative
|
||||
/// to the page being serviced.
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Invalidates the cache range within the given page.
|
||||
/// The start and end are relative to the page being serviced and should
|
||||
/// be aligned to a cache line boundary where possible. An additional
|
||||
/// clean is performed on the outer cache lines if the start and end are
|
||||
/// not aligned, to clean out the bytes between the requested and
|
||||
/// the cache line boundary.
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Cleans data lines to point of unification, invalidates
|
||||
/// corresponding instruction lines to point of unification, then
|
||||
/// invalidates branch predictors.
|
||||
/// The start and end are relative to the page being serviced.
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
}
|
||||
|
||||
// ARM
|
||||
// mod aarch64 {
|
||||
|
||||
struct Page {}
|
||||
|
||||
impl Page {
|
||||
// VirtSpace-like interface.
|
||||
/// Get the physical address of the underlying frame.
|
||||
fn get_address() -> Result<PhysAddr> { 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 unmap() -> Result<()> { todo!() }
|
||||
// MMIO space.
|
||||
fn map_io(iospace: IoSpace/*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()> { todo!() }
|
||||
}
|
||||
|
||||
impl PageCacheManagement for Page {
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// ARM
|
||||
// L3 tables
|
||||
struct PageTable {}
|
||||
|
||||
impl PageTable {
|
||||
fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
|
||||
fn unmap() -> Result<()> { todo!() }
|
||||
}
|
||||
|
||||
// AArch64 - probably just impl some Mapping trait for these "structs"?
|
||||
// L2 table
|
||||
struct PageDirectory {}
|
||||
|
||||
impl PageDirectory {
|
||||
fn map(pud: PageUpperDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
|
||||
fn unmap() -> Result<()> { todo!() }
|
||||
}
|
||||
|
||||
// L1 table
|
||||
struct PageUpperDirectory {}
|
||||
|
||||
impl PageUpperDirectory {
|
||||
fn map(pgd: PageGlobalDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
|
||||
fn unmap() -> Result<()> { todo!() }
|
||||
}
|
||||
|
||||
// L0 table
|
||||
struct PageGlobalDirectory {
|
||||
// @todo should also impl VirtSpace to be able to map shit?
|
||||
// or the Page's impl will do this?
|
||||
}
|
||||
|
||||
impl PageCacheManagement for PageGlobalDirectory {
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> ! { todo!() }
|
||||
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
// implemented for x86 and arm
|
||||
trait ASIDPool {
|
||||
fn assign(virt_space: VirtSpace/*Cap*/) -> Result<()>;
|
||||
}
|
||||
|
||||
// implemented for x86 and arm
|
||||
trait ASIDControl {
|
||||
fn make_pool(untyped: Untyped, target_cap_space_cap: CapNodeRootedPath) -> Result<()>;
|
||||
}
|
||||
|
||||
// Allocation details
|
||||
|
||||
// 1. should be possible to map non-SAS style
|
||||
// 2. should be easy to map SAS style
|
||||
// 3. should not allocate any memory dynamically
|
||||
// ^ problem with the above API is FrameAllocator
|
||||
// ^ clients should supply their own memory for frames... from FrameCaps
|
||||
|
||||
|
||||
// https://github.com/seL4/seL4_libs/tree/master/libsel4allocman
|
||||
|
||||
// Allocation overview
|
||||
|
||||
// Allocation is complex due to the circular dependencies that exist on allocating resources. These dependencies are loosely described as
|
||||
|
||||
// Capability slots: Allocated from untypeds, book kept in memory.
|
||||
// Untypeds / other objects (including frame objects): Allocated from other untypeds, into capability slots, book kept in memory.
|
||||
// memory: Requires frame object.
|
||||
|
||||
// Other seL4-like kernel objects and their interfaces:
|
||||
|
||||
trait Thread {
|
||||
// Effectively, SetSpace followed by SetIPCBuffer.
|
||||
fn configure(fault_endpoint: CapNode, cap_space_root: CapNode, cap_space_root_data: CapNodeConfig, virt_space_root: CapNode, virt_space_root_data: ??, ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>;
|
||||
fn set_space(fault_endpoint: CapNode, cap_space_root: CapNode, cap_space_root_data: CapNodeConfig, virt_space_root: CapNode, virt_space_root_data: ??) -> Result<()>;
|
||||
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<()>;
|
||||
fn suspend() -> Result<()>;
|
||||
fn resume() -> Result<()>;
|
||||
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<()>;
|
||||
fn bind_notification(notification: CapNode) -> Result<()>;
|
||||
fn unbind_notification() -> 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<()>;
|
||||
fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> 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 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 {
|
||||
fn configure(fault_endpoint: _, cap_space_root: _, cap_space_root_data: _, virt_space_root: _, ipc_buffer_frame: _, ipc_buffer_offset: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_space(fault_endpoint: _, cap_space_root: _, cap_space_root_data: _, virt_space_root: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn configure_single_stepping(bp_num: u16, _: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_breakpoint(bp_num: u16) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_breakpoint(bp_num: u16, bp: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unset_breakpoint(bp_num: u16) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn suspend() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn resume() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn copy_registers(source: TCB, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &_) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn bind_notification(notification: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unbind_notification() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_priority(authority: TCB, priority: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_mc_priority(authority: TCB, mcp: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_sched_params(authority: TCB, mcp: u32, priority: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_affinity(affinity: u64) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_ipc_buffer(ipc_buffer_frame: _, ipc_buffer_offset: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_tls_base(tls_base: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_ept_root(eptpml: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
impl KernelObject for TCB {
|
||||
const SIZE_BITS: usize = 12;
|
||||
}
|
||||
|
||||
trait Notification {
|
||||
fn signal(dest: Cap);
|
||||
fn wait(src: Cap) -> Result<Option<&Badge>>;
|
||||
fn poll(cap: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
}
|
||||
|
||||
trait IRQHandler {
|
||||
fn set_notification(notification: CapNode) -> Result<()>;
|
||||
fn ack() -> Result<()>;
|
||||
fn clear() -> Result<()>;
|
||||
}
|
||||
|
||||
trait IRQControl {
|
||||
fn get(irq: u32, dest: CapNodeRootedPath) -> Result<()>;
|
||||
// ARM?
|
||||
fn get_trigger();
|
||||
fn get_trigger_core();
|
||||
}
|
||||
|
||||
// Syscalls (kernel API)
|
||||
trait API {
|
||||
fn send(cap: Cap, msg_info: MessageInfo);
|
||||
// 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 call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
fn reply(msg_info: MessageInfo);
|
||||
fn nb_send(dest: Cap, msg_info: MessageInfo);
|
||||
// As Recv but invoke `reply` first.
|
||||
fn reply_recv(src: Cap, reply: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
// 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_recv(src: Cap) -> Result<(MessageInfo, Option<&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>)>;
|
||||
// As per Recv, but donation not possible.
|
||||
fn wait(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
fn r#yield();
|
||||
// Plus some debugging calls...
|
||||
}
|
||||
|
||||
struct Nucleus {}
|
||||
|
||||
impl API for Nucleus {
|
||||
fn send(cap: _, msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn recv(src: _, reply: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn call(cap: _, msg_info: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn reply(msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send(dest: _, msg_info: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn reply_recv(src: _, reply: _, msg_info: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send_recv(dest: _, msg_info: _, src: _, reply: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_recv(src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn nb_send_wait(cap: _, msg_info: _, src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn wait(src: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn r#yield() {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
trait DomainSet {
|
||||
// ??
|
||||
fn set(domain: Dom, thread: TCB);
|
||||
}
|
||||
|
||||
// Virtualisation
|
||||
// ARM
|
||||
trait VCPU {
|
||||
fn inject_irq(virq: u16, priority: u8, group: u8, index: u8) -> Result<()>;
|
||||
fn read_registers();
|
||||
fn write_registers();
|
||||
fn set_tcb();
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// implemented for x86 and arm
|
||||
trait ASIDControl {
|
||||
fn make_pool(untyped: Untyped, target_cap_space_cap: CapNodeRootedPath) -> Result<()>;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// implemented for x86 and arm
|
||||
trait ASIDPool {
|
||||
fn assign(virt_space: VirtSpace /*Cap*/) -> Result<()>;
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
mod asid_control;
|
||||
mod asid_pool;
|
||||
mod page;
|
||||
mod page_directory;
|
||||
mod page_global_directory;
|
||||
mod page_table;
|
||||
mod page_upper_directory;
|
||||
|
||||
// Allocation details
|
||||
|
||||
// 1. should be possible to map non-SAS style
|
||||
// 2. should be easy to map SAS style
|
||||
// 3. should not allocate any memory dynamically
|
||||
// ^ problem with the above API is FrameAllocator
|
||||
// ^ clients should supply their own memory for frames... from FrameCaps
|
||||
|
||||
// https://github.com/seL4/seL4_libs/tree/master/libsel4allocman
|
||||
|
||||
// Allocation overview
|
||||
|
||||
// Allocation is complex due to the circular dependencies that exist on allocating resources. These dependencies are loosely described as
|
||||
|
||||
// Capability slots: Allocated from untypeds, book kept in memory.
|
||||
// Untypeds / other objects (including frame objects): Allocated from other untypeds, into capability slots, book kept in memory.
|
||||
// memory: Requires frame object.
|
||||
|
||||
//=============================================================================
|
||||
|
||||
// ActivePageTable (--> impl VirtSpace for ActivePageTable etc...)
|
||||
// * translate(VirtAddr)->PhysAddr
|
||||
// * translate_page(Page)->PhysAddr
|
||||
// * map_to(Page, PhysFrame, Flags, FrameAllocator)->()
|
||||
// * map(Page, Flags, FrameAllocator)->()
|
||||
// * identity_map(PhysFrame, Flags, FrameAllocator)->()
|
||||
// * 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>;///??
|
||||
}
|
||||
|
||||
// ARM AArch64 processors have a four-level page-table structure, where the
|
||||
// VirtSpace is realised as a PageGlobalDirectory. All paging structures are
|
||||
// indexed by 9 bits of the virtual address.
|
||||
|
||||
// AArch64 page hierarchy:
|
||||
//
|
||||
// PageGlobalDirectory (L0) -- aka VirtSpace
|
||||
// +--PageUpperDirectory (L1)
|
||||
// +--Page<Size1GiB> -- aka HugePage
|
||||
// | or
|
||||
// +--PageDirectory (L2)
|
||||
// +--Page<Size2MiB> -- aka LargePage
|
||||
// | or
|
||||
// +--PageTable (L3)
|
||||
// +--Page<Size4KiB> -- aka Page
|
||||
|
||||
|
||||
/// Cache data management.
|
||||
trait PageCacheManagement {
|
||||
/// Cleans the data cache out to RAM.
|
||||
/// The start and end are relative to the page being serviced.
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Clean and invalidates the cache range within the given page.
|
||||
/// The range will be flushed out to RAM. The start and end are relative
|
||||
/// to the page being serviced.
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Invalidates the cache range within the given page.
|
||||
/// The start and end are relative to the page being serviced and should
|
||||
/// be aligned to a cache line boundary where possible. An additional
|
||||
/// clean is performed on the outer cache lines if the start and end are
|
||||
/// not aligned, to clean out the bytes between the requested and
|
||||
/// the cache line boundary.
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
/// Cleans data lines to point of unification, invalidates
|
||||
/// corresponding instruction lines to point of unification, then
|
||||
/// invalidates branch predictors.
|
||||
/// The start and end are relative to the page being serviced.
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> Result<()>;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
struct Page {}
|
||||
|
||||
impl Page {
|
||||
// VirtSpace-like interface.
|
||||
/// Get the physical address of the underlying frame.
|
||||
fn get_address() -> Result<PhysAddr> {
|
||||
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 unmap() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
// MMIO space.
|
||||
fn map_io(iospace: IoSpace /*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl PageCacheManagement for Page {
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> _ {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// probably just impl some Mapping trait for these "structs"?
|
||||
|
||||
// L2 table
|
||||
struct PageDirectory {}
|
||||
|
||||
impl PageDirectory {
|
||||
fn map(
|
||||
pud: PageUpperDirectory, /*Cap*/
|
||||
vaddr: VirtAddr,
|
||||
attr: VMAttributes,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
fn unmap() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// L0 table
|
||||
struct PageGlobalDirectory {
|
||||
// @todo should also impl VirtSpace to be able to map shit?
|
||||
// or the Page's impl will do this?
|
||||
}
|
||||
|
||||
impl PageCacheManagement for PageGlobalDirectory {
|
||||
fn clean_data(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn invalidate_data(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> ! {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// L3 tables
|
||||
struct PageTable {}
|
||||
|
||||
impl PageTable {
|
||||
fn map(virt_space: VirtSpace /*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
fn unmap() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// L1 table
|
||||
struct PageUpperDirectory {}
|
||||
|
||||
impl PageUpperDirectory {
|
||||
fn map(
|
||||
pgd: PageGlobalDirectory, /*Cap*/
|
||||
vaddr: VirtAddr,
|
||||
attr: VMAttributes,
|
||||
) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
fn unmap() -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ mod caps;
|
|||
mod devices;
|
||||
mod macros;
|
||||
mod mm;
|
||||
mod objects;
|
||||
mod panic;
|
||||
mod platform;
|
||||
#[cfg(feature = "qemu")]
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
struct CapNode {}
|
||||
|
||||
impl super::KernelObject for CapNode {
|
||||
fn size_bits() -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn invoke() {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
register_bitfields! {
|
||||
u128,
|
||||
Endpoint [
|
||||
QueueHead OFFSET(0) NUMBITS(64) [],
|
||||
QueueTail OFFSET(80) NUMBITS(46) [],
|
||||
State OFFSET(126) NUMBITS(2) [
|
||||
Idle = 00b,
|
||||
Send = 01b,
|
||||
Recv = 10b,
|
||||
],
|
||||
],
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
trait IRQControl {
|
||||
fn get(irq: u32, dest: CapNodeRootedPath) -> Result<()>;
|
||||
// ARM specific?
|
||||
fn get_trigger();
|
||||
fn get_trigger_core();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
trait IRQHandler {
|
||||
fn set_notification(notification: CapNode) -> Result<()>;
|
||||
fn ack() -> Result<()>;
|
||||
fn clear() -> Result<()>;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
pub(crate) trait KernelObject {
|
||||
fn size_bits() -> usize;
|
||||
fn invoke();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// The basic services Vesper provides are as follows:
|
||||
//
|
||||
// * _Threads_ are an abstraction of CPU execution that supports running software;
|
||||
// * _Address spaces_ are virtual memory spaces that each contain an application.
|
||||
// Applications are limited to accessing memory in their address space;
|
||||
// * _Inter-process communication (IPC)_ via endpoints allows threads to communicate using
|
||||
// message passing;
|
||||
// * _Events_ provide a non-blocking signalling mechanism similar to counting semaphores;
|
||||
// * _Device primitives_ allow device drivers to be implemented as unprivileged applications.
|
||||
// The kernel exports hardware device interrupts via IPC messages; and
|
||||
// * _Capability spaces_ store capabilities (i.e., access rights) to kernel services along with
|
||||
// their book-keeping information.
|
||||
|
||||
pub mod kernel_object;
|
||||
pub mod untyped;
|
||||
|
||||
pub use kernel_object::KernelObject;
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
// @todo replace with Event
|
||||
register_bitfields! {
|
||||
u128,
|
||||
Notification [
|
||||
BoundTCB OFFSET(16) NUMBITS(48) [],
|
||||
MsgId OFFSET(64) NUMBITS(64) [],
|
||||
],
|
||||
NotificationQueue [
|
||||
QueueHead OFFSET(16) NUMBITS(48) [],
|
||||
QueueTail OFFSET(64) NUMBITS(48) [],
|
||||
State OFFSET(126) NUMBITS(2) [
|
||||
Idle = 00b,
|
||||
Waiting = 01b,
|
||||
Active = 10b,
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
trait Notification {
|
||||
fn signal(dest: Cap);
|
||||
fn wait(src: Cap) -> Result<Option<&Badge>>;
|
||||
fn poll(cap: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
struct Thread {}
|
||||
|
||||
impl super::KernelObject for Thread {}
|
||||
|
||||
|
||||
trait Thread {
|
||||
// Effectively, SetSpace followed by SetIPCBuffer.
|
||||
fn configure(fault_endpoint: CapNode, cap_space_root: CapNode, cap_space_root_data: CapNodeConfig, virt_space_root: CapNode, virt_space_root_data: ??, ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> Result<()>;
|
||||
fn set_space(fault_endpoint: CapNode, cap_space_root: CapNode, cap_space_root_data: CapNodeConfig, virt_space_root: CapNode, virt_space_root_data: ??) -> Result<()>;
|
||||
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<()>;
|
||||
fn suspend() -> Result<()>;
|
||||
fn resume() -> Result<()>;
|
||||
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<()>;
|
||||
fn bind_notification(notification: CapNode) -> Result<()>;
|
||||
fn unbind_notification() -> 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<()>;
|
||||
fn set_ipc_buffer(ipc_buffer_frame: CapNode, ipc_buffer_offset: usize) -> 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 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 {
|
||||
fn configure(fault_endpoint: _, cap_space_root: _, cap_space_root_data: _, virt_space_root: _, ipc_buffer_frame: _, ipc_buffer_offset: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_space(fault_endpoint: _, cap_space_root: _, cap_space_root_data: _, virt_space_root: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn configure_single_stepping(bp_num: u16, _: _) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_breakpoint(bp_num: u16) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_breakpoint(bp_num: u16, bp: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unset_breakpoint(bp_num: u16) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn suspend() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn resume() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn copy_registers(source: TCB, suspend_source: bool, resume_target: bool, transfer_frame_regs: bool, transfer_integer_regs: bool, arch_flags: u8) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn read_registers(suspend_source: bool, arch_flags: u8, num_regs: u16, register_context: &mut _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn write_registers(resume_target: bool, arch_flags: u8, num_regs: u16, register_context: &_) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn bind_notification(notification: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unbind_notification() -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_priority(authority: TCB, priority: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_mc_priority(authority: TCB, mcp: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_sched_params(authority: TCB, mcp: u32, priority: u32) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_affinity(affinity: u64) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_ipc_buffer(ipc_buffer_frame: _, ipc_buffer_offset: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_tls_base(tls_base: usize) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_ept_root(eptpml: _) -> _ {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl KernelObject for TCB {
|
||||
const SIZE_BITS: usize = 12;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: BlueOak-1.0.0
|
||||
*/
|
||||
|
||||
pub(crate) struct Untyped {}
|
||||
|
||||
impl super::KernelObject for Untyped {
|
||||
fn size_bits() -> usize {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn invoke() {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Untyped {
|
||||
fn retype() {}
|
||||
}
|
||||
|
||||
enum MemoryKind {
|
||||
General,
|
||||
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> .. }
|
Loading…
Reference in New Issue