[wip] caps work

This commit is contained in:
Berkus Decker 2020-12-04 02:05:19 +02:00
parent babd5caaab
commit 42f0efcba9
2 changed files with 177 additions and 25 deletions

View File

@ -425,6 +425,16 @@ impl UntypedCapability {
} }
} }
// Endpoints support all 10 IPC variants (see COMP9242 slides by Gernot)
impl EndpointCapability {}
// Notifications support NBSend (Signal), Wait and NBWait (Poll) (see COMP9242 slides by Gernot)
// Other objects support only Call() (see COMP9242 slides by Gernot)
// Appear as (kernel-implemented) servers
// • Each has a kernel-defined protocol
// • operations encoded in message tag
// • parameters passed in message words
// • Mostly hidden behind “syscall” wrappers
// * Capability slots: 16 bytes of memory per slot (exactly one capability). --? // * Capability slots: 16 bytes of memory per slot (exactly one capability). --?
// CapNode describes `a given number of capability slots` with `a given guard` // CapNode describes `a given number of capability slots` with `a given guard`
// of `a given guard size` bits. // of `a given guard size` bits.
@ -505,6 +515,16 @@ pub enum DerivationTreeError {
InvalidPrev, InvalidPrev,
} }
// In seL4, the MDB is stored as a doubly-linked list, representing the **preorder-DFS** through
// the hierarchy of capabilities. This data structure allows easy insertion of a capability
// given its immediate ancestor or a copy, and easy checking for existence of copies and descendants.
// But when no relations are known beforehand, finding the position to place a new capability
// requires a O(n) linear scan through the list, as does finding ancestors and descendants
// of a capability given just the capabilitys value. This operation is performed in
// the non-preemptable kernel, creating a scheduling hole that is problematic for real-time applications.
// To reduce the complexity of operations described above, we replace the MDBs linked list with
// a more suitable search data structure.
// -- nevill-master-thesis Using Capabilities for OS Resource Management
impl DerivationTreeNode { impl DerivationTreeNode {
fn empty() -> Self { fn empty() -> Self {
Self(LocalRegisterCopy::new(0)) Self(LocalRegisterCopy::new(0))
@ -594,11 +614,13 @@ impl CapTableEntry {
} }
} }
// @note src and dest are swapped here, compared to seL4 api
/* /*
struct CapNodePath { struct CapNodePath {
index: u32, /// Index contains `depth` lowermost bits of the path.
depth: u32, index: u64,
/// Depth specifies the remaining amount of bits left to traverse in the path.
/// Once depth reaches zero, the selected CapNode slot is the final target.
depth: usize,
} }
struct CapNodeRootedPath { struct CapNodeRootedPath {
@ -608,19 +630,22 @@ struct CapNodeRootedPath {
// @todo just use CapNodeCap // @todo just use CapNodeCap
//struct CapNodeConfig { <-- for each CapTable we would need these.. //struct CapNodeConfig { <-- for each CapTable we would need these..
// guard: u32, // guard: u64,
// guard_size: u32, // guard_bits: usize,
//} //}
// @note src and dest are swapped here, compared to seL4 api
impl CapNode { impl CapNode {
// Derives a capability into a new, less powerful one, with potentially added Badge.
fn mint( fn mint(
src: CapNodeRootedPath, src: CapNodeRootedPath, // can be just CapNodePath since it's relative (is it?) to this CapNode.
dest: CapNodePath, dest: CapNodePath,
rights: CapRights, rights: CapRights,
badge: Badge, badge: Badge,
) -> Result<(), CapError> { ) -> Result<(), CapError> {
unimplemented!(); unimplemented!();
} }
// [wip] is copy a derivation too?
fn copy(src: CapNodeRootedPath, dest: CapNodePath, rights: CapRights) -> Result<(), CapError> { fn copy(src: CapNodeRootedPath, dest: CapNodePath, rights: CapRights) -> Result<(), CapError> {
unimplemented!(); unimplemented!();
} }
@ -645,7 +670,7 @@ impl CapNode {
fn revoke(path: CapNodePath) -> Result<(), CapError> { fn revoke(path: CapNodePath) -> Result<(), CapError> {
unimplemented!(); unimplemented!();
} }
fn save_caller(r#where: CapNodePath) -> Result<(), CapError> { fn save_caller(r#where: CapNodePath) -> Result<(), CapError> { // save_reply_cap() in sel4
unimplemented!(); unimplemented!();
} }
fn cancel_badged_sends(path: CapNodePath) -> Result<(), CapError> { fn cancel_badged_sends(path: CapNodePath) -> Result<(), CapError> {

View File

@ -61,6 +61,8 @@ enum MemoryKind {
// Boot code reserves kernel memory and initial mapping allocations (4 pages probably - on rpi3? should be platform-dependent). // 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. // 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 { trait Untyped {
// Uses T::SIZE_BITS to properly size the resulting object // Uses T::SIZE_BITS to properly size the resulting object
// in some cases size_bits must be passed as argument though... // in some cases size_bits must be passed as argument though...
@ -135,13 +137,13 @@ struct Page {}
impl Page { impl Page {
// VirtSpace-like interface. // VirtSpace-like interface.
/// Get the physical address of the underlying frame. /// Get the physical address of the underlying frame.
fn get_address() -> Result<PhysAddr>; fn get_address() -> Result<PhysAddr> { todo!() }
fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, rights: CapRights, attr: VMAttributes) -> Result<()>; fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, rights: CapRights, attr: VMAttributes) -> Result<()> { todo!() }
/// Changes the permissions of an existing mapping. /// Changes the permissions of an existing mapping.
fn remap(virt_space: VirtSpace/*Cap*/, rights: CapRights, attr: VMAttributes) -> Result<()>; fn remap(virt_space: VirtSpace/*Cap*/, rights: CapRights, attr: VMAttributes) -> Result<()> { todo!() }
fn unmap() -> Result<()>; fn unmap() -> Result<()> { todo!() }
// MMIO space. // MMIO space.
fn map_io(iospace: IoSpace/*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()>; fn map_io(iospace: IoSpace/*Cap*/, rights: CapRights, ioaddr: VirtAddr) -> Result<()> { todo!() }
} }
impl PageCacheManagement for Page { impl PageCacheManagement for Page {
@ -167,8 +169,8 @@ impl PageCacheManagement for Page {
struct PageTable {} struct PageTable {}
impl PageTable { impl PageTable {
fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()>; fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
fn unmap() -> Result<()>; fn unmap() -> Result<()> { todo!() }
} }
// AArch64 - probably just impl some Mapping trait for these "structs"? // AArch64 - probably just impl some Mapping trait for these "structs"?
@ -176,16 +178,16 @@ impl PageTable {
struct PageDirectory {} struct PageDirectory {}
impl PageDirectory { impl PageDirectory {
fn map(pud: PageUpperDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()>; fn map(pud: PageUpperDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
fn unmap() -> Result<()>; fn unmap() -> Result<()> { todo!() }
} }
// L1 table // L1 table
struct PageUpperDirectory {} struct PageUpperDirectory {}
impl PageUpperDirectory { impl PageUpperDirectory {
fn map(pgd: PageGlobalDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()>; fn map(pgd: PageGlobalDirectory/*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> { todo!() }
fn unmap() -> Result<()>; fn unmap() -> Result<()> { todo!() }
} }
// L0 table // L0 table
@ -195,17 +197,17 @@ struct PageGlobalDirectory {
} }
impl PageCacheManagement for PageGlobalDirectory { impl PageCacheManagement for PageGlobalDirectory {
fn clean_data(start_offset: usize, end_offset: usize) -> _ { fn clean_data(start_offset: usize, end_offset: usize) -> ! {
todo!() todo!()
} }
fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> _ { fn clean_invalidate_data(start_offset: usize, end_offset: usize) -> ! {
todo!() todo!()
} }
fn 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) -> _ { fn unify_instruction_cache(start_offset: usize, end_offset: usize) -> ! {
todo!() todo!()
} }
} }
@ -274,7 +276,87 @@ struct TCB {
// Thread.read_registers(cap, ... call for example. // Thread.read_registers(cap, ... call for example.
} }
impl Thread for TCB {} 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 { impl KernelObject for TCB {
const SIZE_BITS: usize = 12; const SIZE_BITS: usize = 12;
} }
@ -320,8 +402,53 @@ trait API {
// Plus some debugging calls... // Plus some debugging calls...
} }
struct Kernel {} // Nucleus, actually... struct Nucleus {}
impl API for Kernel {}
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 { trait DomainSet {
// ?? // ??