[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
|
//! Arch-specific kernel ABI decodes syscall invocations and calls API functions to perform actual
|
||||||
//! operations.
|
//! 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)
|
// Syscalls (kernel API)
|
||||||
trait API {
|
trait API {
|
||||||
// Three below (send, nb_send, call) are "invocation" syscalls.
|
// Three below (send, nb_send, call) are "invocation" syscalls.
|
||||||
fn send(cap: Cap, msg_info: MessageInfo);
|
// fn send(cap: Cap, msg_info: MessageInfo);
|
||||||
fn nb_send(dest: Cap, msg_info: MessageInfo);
|
// fn nb_send(dest: Cap, msg_info: MessageInfo);
|
||||||
fn call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>;
|
// fn call(cap: Cap, msg_info: MessageInfo) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||||
// Wait for message, when it is received,
|
// Wait for message, when it is received,
|
||||||
// return object Badge and block caller on `reply`.
|
// return object Badge and block caller on `reply`.
|
||||||
fn recv(src: Cap, reply: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
// fn recv(src: Cap, reply: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||||
fn reply(msg_info: MessageInfo);
|
// fn reply(msg_info: MessageInfo);
|
||||||
// As Recv but invoke `reply` first.
|
// As Recv but invoke `reply` first.
|
||||||
fn reply_recv(
|
// fn reply_recv(
|
||||||
src: Cap,
|
// src: Cap,
|
||||||
reply: Cap,
|
// reply: Cap,
|
||||||
msg_info: MessageInfo,
|
// msg_info: MessageInfo,
|
||||||
) -> Result<(MessageInfo, Option<&Badge>)>;
|
// ) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||||
fn nb_recv(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
// fn nb_recv(src: Cap) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||||
fn r#yield();
|
// fn r#yield();
|
||||||
// -- end of default seL4 syscall list --
|
// -- end of default seL4 syscall list --
|
||||||
// As ReplyRecv but invoke `dest` not `reply`.
|
// As ReplyRecv but invoke `dest` not `reply`.
|
||||||
fn nb_send_recv(
|
// fn nb_send_recv(
|
||||||
dest: Cap,
|
// dest: Cap,
|
||||||
msg_info: MessageInfo,
|
// msg_info: MessageInfo,
|
||||||
src: Cap,
|
// src: Cap,
|
||||||
reply: Cap,
|
// reply: Cap,
|
||||||
) -> Result<(MessageInfo, Options<&Badge>)>;
|
// ) -> Result<(MessageInfo, Options<&Badge>)>;
|
||||||
// As NBSendRecv, with no reply. Donation is not possible.
|
// As NBSendRecv, with no reply. Donation is not possible.
|
||||||
fn nb_send_wait(
|
// fn nb_send_wait(
|
||||||
cap: Cap,
|
// cap: Cap,
|
||||||
msg_info: MessageInfo,
|
// msg_info: MessageInfo,
|
||||||
src: Cap,
|
// src: Cap,
|
||||||
) -> Result<(MessageInfo, Option<&Badge>)>;
|
// ) -> Result<(MessageInfo, Option<&Badge>)>;
|
||||||
// As per Recv, but donation not possible.
|
// 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...
|
// Plus some debugging calls...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,29 +183,31 @@ fn handle_invocation(is_call: bool, is_blocking: bool) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_receive(is_blocking: bool) {
|
fn handle_receive(is_blocking: bool) -> Result<()> {
|
||||||
let endpoint_cap_ptr = KernelCurrentThread.get_register(capRegister);
|
let endpoint_cap_ptr = KernelCurrentThread.get_register(capRegister);
|
||||||
|
|
||||||
let result = KernelCurrentThread.lookup_cap(endpoint_cap_ptr);
|
let result = KernelCurrentThread.lookup_cap(endpoint_cap_ptr);
|
||||||
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
KernelCurrentFault = Fault_CapFault::new(endpoint_cap_ptr, true);
|
// KernelCurrentFault = Fault_CapFault::new(endpoint_cap_ptr, true);
|
||||||
handle_fault(KernelCurrentThread);
|
handle_fault(KernelCurrentThread);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
match result.cap.get_type() {
|
match result.capability.get_type() {
|
||||||
endpoint => ,
|
endpoint => Ok(()),
|
||||||
notification => ,
|
notification => Ok(()),
|
||||||
_ => fault,
|
_ => Ok(()), //fault,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_reply() {
|
fn handle_reply() {
|
||||||
let caller_slot = KernelCurrentThread.get_caller_slot();
|
let caller_slot = KernelCurrentThread.get_caller_slot();
|
||||||
let caller_cap = caller_slot.capability;
|
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() {
|
match caller_cap.get_type() {
|
||||||
ReplyCap::Type.value => {
|
reply_cap => {
|
||||||
// if (cap_reply_cap_get_capReplyMaster(callerCap)) {
|
// if (cap_reply_cap_get_capReplyMaster(callerCap)) {
|
||||||
// break;
|
// 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__);
|
// if(!(caller != ksCurThread)) _assert_fail("caller must not be the current thread", "src/api/syscall.c", 313, __FUNCTION__);
|
||||||
// do_reply_transfer(ksCurThread, caller, callerSlot);
|
// 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());
|
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(())
|
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()
|
//handleSyscall(syscall) in the slowpath()
|
||||||
// these are expressed in terms of
|
// these are expressed in terms of
|
||||||
// handleInvocation(bool isCall, bool isBlocking)
|
// handleInvocation(bool isCall, bool isBlocking)
|
||||||
|
@ -352,7 +315,7 @@ impl TCB {
|
||||||
// Call and ReplyRecv have fastpath handlers
|
// Call and ReplyRecv have fastpath handlers
|
||||||
// the rest goes through slowpath
|
// 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;
|
struct Scheduler;
|
||||||
|
|
||||||
|
@ -384,13 +347,13 @@ impl Scheduler {
|
||||||
|
|
||||||
fn activate_thread() {}
|
fn activate_thread() {}
|
||||||
|
|
||||||
fn dequeue(thread: &mut TCB);
|
fn dequeue(thread: &mut TCB) {}
|
||||||
fn append(thread: &mut TCB);
|
fn append(thread: &mut TCB) {}
|
||||||
fn reschedule_required();
|
fn reschedule_required() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Nucleus {}
|
struct Nucleus {}
|
||||||
|
|
||||||
impl API for Nucleus {
|
// impl API for Nucleus {
|
||||||
//...
|
//...
|
||||||
}
|
// }
|
||||||
|
|
|
@ -14,4 +14,4 @@
|
||||||
/// Implements C ABI to easily parse passed in parameters.
|
/// Implements C ABI to easily parse passed in parameters.
|
||||||
/// @todo Move this to aarch64-specific part.
|
/// @todo Move this to aarch64-specific part.
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
extern "C" pub(crate) syscall_entry() {}
|
extern "C" pub(crate) syscall_entry(syscall_no: u64) {}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
arch::memory::{PhysAddr, VirtAddr, ASID},
|
||||||
capdef,
|
capdef,
|
||||||
caps::{CapError, Capability},
|
caps::{CapError, Capability},
|
||||||
},
|
},
|
||||||
|
@ -37,19 +38,19 @@ capdef! { PageDirectory }
|
||||||
//=====================
|
//=====================
|
||||||
|
|
||||||
impl PageDirectoryCapability {
|
impl PageDirectoryCapability {
|
||||||
pub(crate) fn base_address() -> PhysAddr {
|
pub(crate) fn base_address(&self) -> PhysAddr {
|
||||||
PhysAddr::new(self.0.read(PageDirectoryCap::BasePtr))
|
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
|
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))
|
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)
|
self.0.read(PageDirectoryCap::MappedASID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
arch::memory::{PhysAddr, VirtAddr, ASID},
|
||||||
capdef,
|
capdef,
|
||||||
caps::{CapError, Capability},
|
caps::{CapError, Capability},
|
||||||
},
|
},
|
||||||
|
@ -36,19 +37,18 @@ capdef! { PageGlobalDirectory }
|
||||||
//=====================
|
//=====================
|
||||||
|
|
||||||
impl PageGlobalDirectoryCapability {
|
impl PageGlobalDirectoryCapability {
|
||||||
pub(crate) fn base_address() -> PhysAddr {
|
pub(crate) fn base_address(&self) -> PhysAddr {
|
||||||
PhysAddr::new(self.0.read(PageGlobalDirectoryCap::BasePtr))
|
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
|
self.0.read(PageGlobalDirectoryCap::IsMapped) == 1
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn mapped_address() -> VirtAddr {
|
// Global directory does not give access to mapped addresses,
|
||||||
VirtAddr::new(self.0.read(PageGlobalDirectoryCap::MappedAddress))
|
// 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)
|
self.0.read(PageGlobalDirectoryCap::MappedASID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
arch::memory::{PhysAddr, VirtAddr, ASID},
|
||||||
capdef,
|
capdef,
|
||||||
caps::{CapError, Capability},
|
caps::{CapError, Capability},
|
||||||
},
|
},
|
||||||
|
@ -37,19 +38,19 @@ capdef! { PageTable }
|
||||||
//=====================
|
//=====================
|
||||||
|
|
||||||
impl PageTableCapability {
|
impl PageTableCapability {
|
||||||
pub(crate) fn base_address() -> PhysAddr {
|
pub(crate) fn base_address(&self) -> PhysAddr {
|
||||||
PhysAddr::new(self.0.read(PageTableCap::BasePtr))
|
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
|
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))
|
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)
|
self.0.read(PageTableCap::MappedASID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub mod mmu;
|
||||||
|
|
||||||
pub use addr::PhysAddr;
|
pub use addr::PhysAddr;
|
||||||
pub use addr::VirtAddr;
|
pub use addr::VirtAddr;
|
||||||
|
pub use addr::ASID;
|
||||||
|
|
||||||
// aarch64 granules and page sizes howto:
|
// aarch64 granules and page sizes howto:
|
||||||
// https://stackoverflow.com/questions/34269185/simultaneous-existence-of-different-sized-pages-on-aarch64
|
// 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 objects;
|
||||||
pub mod traps;
|
pub mod traps;
|
||||||
|
|
||||||
|
pub(crate) use objects::thread::user_stack_trace;
|
||||||
|
|
||||||
/// Loop forever in sleep mode.
|
/// Loop forever in sleep mode.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn endless_sleep() -> ! {
|
pub fn endless_sleep() -> ! {
|
||||||
|
|
|
@ -5,5 +5,5 @@
|
||||||
|
|
||||||
// implemented for x86 and arm
|
// implemented for x86 and arm
|
||||||
trait ASIDControl {
|
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
|
// implemented for x86 and arm
|
||||||
trait ASIDPool {
|
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>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::memory::{PhysAddr, VirtAddr};
|
||||||
|
|
||||||
mod asid_control;
|
mod asid_control;
|
||||||
mod asid_pool;
|
mod asid_pool;
|
||||||
mod page;
|
mod page;
|
||||||
|
@ -10,6 +12,7 @@ mod page_directory;
|
||||||
mod page_global_directory;
|
mod page_global_directory;
|
||||||
mod page_table;
|
mod page_table;
|
||||||
mod page_upper_directory;
|
mod page_upper_directory;
|
||||||
|
pub(crate) mod thread;
|
||||||
|
|
||||||
// Allocation details
|
// Allocation details
|
||||||
|
|
||||||
|
@ -40,10 +43,21 @@ mod page_upper_directory;
|
||||||
// * unmap(Page, FrameAllocator)->()
|
// * unmap(Page, FrameAllocator)->()
|
||||||
|
|
||||||
trait VirtSpace {
|
trait VirtSpace {
|
||||||
fn map(virt_space: VirtSpace/*Cap*/, vaddr: VirtAddr, rights: CapRights, attr: VMAttributes) -> Result<()>; /// ??
|
fn map_to(
|
||||||
fn unmap() -> Result<()>; /// ??
|
virt_space: VirtSpace, /*Cap*/
|
||||||
fn remap(virt_space: VirtSpace/*Cap*/, rights: CapRights, attr: VMAttributes) -> Result<()>; /// ??
|
vaddr: VirtAddr,
|
||||||
fn get_address() -> Result<PhysAddr>;///??
|
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
|
// ARM AArch64 processors have a four-level page-table structure, where the
|
||||||
|
@ -62,7 +76,6 @@ trait VirtSpace {
|
||||||
// +--PageTable (L3)
|
// +--PageTable (L3)
|
||||||
// +--Page<Size4KiB> -- aka Page
|
// +--Page<Size4KiB> -- aka Page
|
||||||
|
|
||||||
|
|
||||||
/// Cache data management.
|
/// Cache data management.
|
||||||
trait PageCacheManagement {
|
trait PageCacheManagement {
|
||||||
/// Cleans the data cache out to RAM.
|
/// Cleans the data cache out to RAM.
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::arch::{
|
||||||
|
memory::{PhysAddr, VirtAddr},
|
||||||
|
objects::PageCacheManagement,
|
||||||
|
};
|
||||||
|
|
||||||
struct Page {}
|
struct Page {}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
|
@ -11,29 +16,29 @@ impl Page {
|
||||||
fn get_address() -> Result<PhysAddr> {
|
fn get_address() -> Result<PhysAddr> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
fn map(
|
// fn map(
|
||||||
virt_space: VirtSpace, /*Cap*/
|
// virt_space: VirtSpace, /*Cap*/
|
||||||
vaddr: VirtAddr,
|
// vaddr: VirtAddr,
|
||||||
rights: CapRights,
|
// rights: CapRights,
|
||||||
attr: VMAttributes,
|
// attr: VMAttributes,
|
||||||
) -> Result<()> {
|
// ) -> Result<()> {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
/// Changes the permissions of an existing mapping.
|
/// Changes the permissions of an existing mapping.
|
||||||
fn remap(
|
// fn remap(
|
||||||
virt_space: VirtSpace, /*Cap*/
|
// virt_space: VirtSpace, /*Cap*/
|
||||||
rights: CapRights,
|
// rights: CapRights,
|
||||||
attr: VMAttributes,
|
// attr: VMAttributes,
|
||||||
) -> Result<()> {
|
// ) -> Result<()> {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
fn unmap() -> Result<()> {
|
fn unmap() -> Result<()> {
|
||||||
todo!()
|
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!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PageCacheManagement for Page {
|
impl PageCacheManagement for Page {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::memory::{mmu::PageUpperDirectory, VirtAddr};
|
||||||
|
|
||||||
// probably just impl some Mapping trait for these "structs"?
|
// probably just impl some Mapping trait for these "structs"?
|
||||||
|
|
||||||
// L2 table
|
// L2 table
|
||||||
|
@ -12,7 +14,7 @@ impl PageDirectory {
|
||||||
fn map(
|
fn map(
|
||||||
pud: PageUpperDirectory, /*Cap*/
|
pud: PageUpperDirectory, /*Cap*/
|
||||||
vaddr: VirtAddr,
|
vaddr: VirtAddr,
|
||||||
attr: VMAttributes,
|
attr: u32, //VMAttributes,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::arch::{memory::PhysAddr, objects::PageCacheManagement};
|
||||||
|
|
||||||
// L0 table
|
// L0 table
|
||||||
struct PageGlobalDirectory {
|
struct PageGlobalDirectory {
|
||||||
// @todo should also impl VirtSpace to be able to map shit?
|
// @todo should also impl VirtSpace to be able to map shit?
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
struct PageTable {}
|
struct PageTable {}
|
||||||
|
|
||||||
impl PageTable {
|
impl PageTable {
|
||||||
fn map(virt_space: VirtSpace /*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> {
|
// fn map_to(virt_space: VirtSpace /*Cap*/, vaddr: VirtAddr, attr: VMAttributes) -> Result<()> {
|
||||||
todo!()
|
// todo!()
|
||||||
}
|
// }
|
||||||
fn unmap() -> Result<()> {
|
fn unmap() -> Result<()> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use crate::memory::{mmu::PageGlobalDirectory, VirtAddr};
|
||||||
|
|
||||||
// L1 table
|
// L1 table
|
||||||
struct PageUpperDirectory {}
|
struct PageUpperDirectory {}
|
||||||
|
|
||||||
|
@ -10,7 +12,7 @@ impl PageUpperDirectory {
|
||||||
fn map(
|
fn map(
|
||||||
pgd: PageGlobalDirectory, /*Cap*/
|
pgd: PageGlobalDirectory, /*Cap*/
|
||||||
vaddr: VirtAddr,
|
vaddr: VirtAddr,
|
||||||
attr: VMAttributes,
|
attr: u32, //VMAttributes,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
todo!()
|
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>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#[cfg(target_arch = "aarch64")]
|
cfg_if::cfg_if! {
|
||||||
|
if #[cfg(target_arch = "aarch64")] {
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod aarch64;
|
pub mod aarch64;
|
||||||
#[cfg(target_arch = "aarch64")]
|
|
||||||
pub use self::aarch64::*;
|
pub use self::aarch64::*;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use crate::caps::Capability;
|
use crate::caps::Capability;
|
||||||
|
use snafu::Snafu;
|
||||||
use {super::derivation_tree::DerivationTreeNode, /*crate::memory::PhysAddr,*/ core::fmt};
|
use {super::derivation_tree::DerivationTreeNode, /*crate::memory::PhysAddr,*/ core::fmt};
|
||||||
|
|
||||||
// * Capability slots: 16 bytes of memory per slot (exactly one capability). --?
|
// * Capability slots: 16 bytes of memory per slot (exactly one capability). --?
|
||||||
|
@ -153,7 +154,7 @@ type CapPath = u64;
|
||||||
enum LookupFault {
|
enum LookupFault {
|
||||||
InvalidRoot,
|
InvalidRoot,
|
||||||
GuardMismatch,
|
GuardMismatch,
|
||||||
DepthMismatch(usize, usize),
|
DepthMismatch { expected: usize, actual: usize },
|
||||||
NoResolvedBits,
|
NoResolvedBits,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,7 +164,7 @@ pub(crate) fn resolve_address_bits(
|
||||||
capptr: CapPath, // CapPtr = u64, aka CapPath
|
capptr: CapPath, // CapPtr = u64, aka CapPath
|
||||||
n_bits: usize,
|
n_bits: usize,
|
||||||
) -> Result<(Slot, BitsRemaining), LookupFault> {
|
) -> Result<(Slot, BitsRemaining), LookupFault> {
|
||||||
if node_cap.type() != CapNodeCapability {
|
if node_cap.get_type() != CapNodeCapability {
|
||||||
return Err(LookupFault::InvalidRoot);
|
return Err(LookupFault::InvalidRoot);
|
||||||
}
|
}
|
||||||
let mut n_bits = n_bits;
|
let mut n_bits = n_bits;
|
||||||
|
@ -179,14 +180,17 @@ pub(crate) fn resolve_address_bits(
|
||||||
|
|
||||||
let cap_guard = node_cap.guard();
|
let cap_guard = node_cap.guard();
|
||||||
// @todo common code to extract guard_bits from an int?
|
// @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 {
|
if guard_bits > n_bits || guard != cap_guard {
|
||||||
return Err(LookupFault::GuardMismatch);
|
return Err(LookupFault::GuardMismatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
if level_bits > n_bits {
|
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);
|
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;
|
n_bits -= level_bits;
|
||||||
node_cap = slot.capability;
|
node_cap = slot.capability;
|
||||||
|
|
||||||
if node_cap.type() != CapNodeCapability {
|
if node_cap.get_type() != CapNodeCapability {
|
||||||
return Ok((slot, n_bits));
|
return Ok((slot, n_bits));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,13 +34,16 @@ mod endpoint_cap;
|
||||||
mod irq_control_cap;
|
mod irq_control_cap;
|
||||||
mod irq_handler_cap;
|
mod irq_handler_cap;
|
||||||
mod notification_cap;
|
mod notification_cap;
|
||||||
mod null_cap;
|
pub mod null_cap;
|
||||||
mod reply_cap;
|
pub mod reply_cap;
|
||||||
mod resume_cap;
|
mod resume_cap;
|
||||||
mod thread_cap;
|
mod thread_cap;
|
||||||
mod untyped_cap;
|
mod untyped_cap;
|
||||||
mod zombie_cap;
|
mod zombie_cap;
|
||||||
|
|
||||||
|
pub use null_cap::NullCapability;
|
||||||
|
pub use reply_cap::ReplyCapability;
|
||||||
|
|
||||||
/// Opaque capability object, manipulated by the kernel.
|
/// Opaque capability object, manipulated by the kernel.
|
||||||
pub trait Capability {
|
pub trait Capability {
|
||||||
///
|
///
|
||||||
|
@ -70,6 +73,9 @@ macro_rules! capdef {
|
||||||
paste! {
|
paste! {
|
||||||
#[doc = "Wrapper representing `" $name "Capability`."]
|
#[doc = "Wrapper representing `" $name "Capability`."]
|
||||||
pub struct [<$name Capability>](LocalRegisterCopy<u128, [<$name Cap>]::Register>);
|
pub struct [<$name Capability>](LocalRegisterCopy<u128, [<$name Cap>]::Register>);
|
||||||
|
impl [<$name Capability>] {
|
||||||
|
type Type = [<$name Cap>]::Register;
|
||||||
|
}
|
||||||
impl Capability for [<$name Capability>] {
|
impl Capability for [<$name Capability>] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_u128(&self) -> u128 {
|
fn as_u128(&self) -> u128 {
|
||||||
|
|
|
@ -36,6 +36,7 @@ use architecture_not_supported_sorry;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
pub use arch::*;
|
pub use arch::*;
|
||||||
|
mod api;
|
||||||
mod caps;
|
mod caps;
|
||||||
mod devices;
|
mod devices;
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -363,4 +364,9 @@ mod main_tests {
|
||||||
fn test_data_abort_trap() {
|
fn test_data_abort_trap() {
|
||||||
check_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
|
// * _Capability spaces_ store capabilities (i.e., access rights) to kernel services along with
|
||||||
// their book-keeping information.
|
// their book-keeping information.
|
||||||
|
|
||||||
pub mod kernel_object;
|
pub mod nucleus_object;
|
||||||
|
pub mod thread;
|
||||||
pub mod untyped;
|
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>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pub(crate) trait KernelObject {
|
pub(crate) trait NucleusObject {
|
||||||
fn size_bits() -> usize;
|
fn size_bits() -> usize;
|
||||||
fn invoke();
|
fn invoke();
|
||||||
}
|
}
|
|
@ -3,51 +3,135 @@
|
||||||
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
* Copyright (c) Berkus Decker <berkus+vesper@metta.systems>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
trait Thread {
|
use crate::{arch, arch::memory::VirtAddr};
|
||||||
// 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
|
// trait Thread {
|
||||||
// fn set_tls_base(tls_base: usize) -> Result<()>;
|
// // Configuration
|
||||||
// virtualized - x86-specific
|
// // Effectively, SetSpace followed by SetIPCBuffer.
|
||||||
// fn set_ept_root(eptpml: X86::EPTPML4) -> Result<()>;
|
// 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<()>;
|
||||||
// @todo <<SchedContext>>
|
// // Debugging tools
|
||||||
|
// fn configure_single_stepping(bp_num: u16, num_insns): Result<SingleStepping>;
|
||||||
// struct Thread {}
|
// fn get_breakpoint(bp_num: u16) -> Result<BreakpointInfo>;
|
||||||
struct TCB {
|
// fn set_breakpoint(bp_num: u16, bp: BreakpointInfo) -> Result<()>;
|
||||||
capability: u128, // should actually be a CapPath here - this is the argument to
|
// fn unset_breakpoint(bp_num: u16) -> Result<()>;
|
||||||
// Thread.read_registers(cap, ... call for example.
|
// // Scheduling
|
||||||
}
|
// fn suspend() -> Result<()>;
|
||||||
|
// fn resume() -> Result<()>;
|
||||||
impl Thread for TCB {
|
// 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 Thread {}
|
||||||
impl super::KernelObject for TCB {
|
impl super::KernelObject for TCB {
|
||||||
const SIZE_BITS: usize = 12;
|
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>
|
* 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 {}
|
pub(crate) struct Untyped {}
|
||||||
|
|
||||||
impl super::KernelObject for Untyped {
|
impl super::NucleusObject for Untyped {
|
||||||
fn size_bits() -> usize {
|
fn size_bits() -> usize {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
@ -15,8 +23,22 @@ impl super::KernelObject for Untyped {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Snafu)]
|
||||||
|
enum RetypeError {
|
||||||
|
Whatever,
|
||||||
|
}
|
||||||
|
|
||||||
impl Untyped {
|
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 {
|
enum MemoryKind {
|
||||||
|
@ -24,21 +46,5 @@ enum MemoryKind {
|
||||||
Device,
|
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
|
// with GATs
|
||||||
// trait Retyped { type Result = CapTable::<T> .. }
|
// trait Retyped { type Result = CapTable::<T> .. }
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
pub fn syscall(number: u64) {
|
pub fn syscall(_number: u64) {
|
||||||
asm!("svc #1234")
|
unsafe { asm!("svc #1234") }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
|
#![no_std]
|
||||||
|
#![feature(asm)]
|
||||||
|
|
||||||
pub mod arch;
|
pub mod arch;
|
||||||
|
|
||||||
pub use arch::syscall;
|
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 {
|
pub enum SysCall {
|
||||||
Send,
|
Send,
|
||||||
NBSend,
|
NBSend,
|
||||||
|
@ -11,6 +17,16 @@ pub enum SysCall {
|
||||||
ReplyRecv,
|
ReplyRecv,
|
||||||
NBRecv,
|
NBRecv,
|
||||||
Yield,
|
Yield,
|
||||||
|
#[cfg(debug)]
|
||||||
|
DebugPutChar,
|
||||||
|
#[cfg(debug)]
|
||||||
|
DebugHalt,
|
||||||
|
#[cfg(debug)]
|
||||||
|
DebugSnapshot,
|
||||||
|
#[cfg(debug)]
|
||||||
|
DebugCapIdentify,
|
||||||
|
#[cfg(debug)]
|
||||||
|
DebugNameThread,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[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