feat(kernel): shared ABI decoder+proofs, no-panic gate, syscall storm, kani on shrunk kernel
This commit is contained in:
@@ -144,152 +144,18 @@ pub fn set_kernel_stack(kernel_sp: usize) {
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes the syscall in `frame`, or `None` for an unknown number or an
|
||||
/// argument that is not representable (e.g. a slot out of range).
|
||||
fn decode_syscall(frame: &TrapFrame) -> Option<domain::syscall::Syscall> {
|
||||
use domain::message::Message;
|
||||
use domain::syscall::Syscall;
|
||||
use types::address::{DataRef, EntryPoint, StackPointer, VirtualAddress};
|
||||
use types::badge::Badge;
|
||||
use types::bounded::{CapSlot, PageCount};
|
||||
use types::permission::PermissionSet;
|
||||
use types::syscall_abi::*;
|
||||
|
||||
let nr = frame.regs[17]; // a7
|
||||
let a = |i: usize| frame.regs[10 + i];
|
||||
let slot = |i: usize| CapSlot::new(u8::try_from(a(i)).ok()?);
|
||||
let message = || -> Option<Message> {
|
||||
let msg = Message::from_words([a(1), a(2), a(3), a(4)]);
|
||||
Some(match a(5) {
|
||||
NONE => msg,
|
||||
_ => msg.with_cap(slot(5)?),
|
||||
})
|
||||
};
|
||||
|
||||
Some(match nr {
|
||||
SYS_EXIT => Syscall::Exit,
|
||||
SYS_HALT => Syscall::Halt,
|
||||
SYS_EXIT_THREAD => Syscall::ExitThread,
|
||||
SYS_YIELD => Syscall::Yield,
|
||||
SYS_GET_TIME => Syscall::GetTime,
|
||||
SYS_GET_PROCESS_ID => Syscall::GetProcessId,
|
||||
SYS_SEND => Syscall::Send {
|
||||
endpoint: slot(0)?,
|
||||
message: message()?,
|
||||
},
|
||||
SYS_CALL => Syscall::Call {
|
||||
endpoint: slot(0)?,
|
||||
message: message()?,
|
||||
},
|
||||
SYS_RECEIVE => Syscall::Receive { endpoint: slot(0)? },
|
||||
SYS_REPLY => Syscall::Reply {
|
||||
message: message()?,
|
||||
},
|
||||
SYS_REPLY_RECV => Syscall::ReplyRecv {
|
||||
endpoint: slot(0)?,
|
||||
message: message()?,
|
||||
},
|
||||
SYS_DELEGATE => Syscall::Delegate {
|
||||
slot: slot(0)?,
|
||||
to_endpoint: slot(1)?,
|
||||
permissions: PermissionSet::from_bits(u8::try_from(a(2)).ok()?),
|
||||
},
|
||||
SYS_MINT => Syscall::Mint {
|
||||
slot: slot(0)?,
|
||||
badge: Badge::new(a(1)),
|
||||
permissions: PermissionSet::from_bits(u8::try_from(a(2)).ok()?),
|
||||
},
|
||||
SYS_CREATE_NOTIFICATION => Syscall::CreateNotification,
|
||||
SYS_SIGNAL => Syscall::Signal {
|
||||
notification: slot(0)?,
|
||||
},
|
||||
SYS_WAIT => Syscall::Wait {
|
||||
notification: slot(0)?,
|
||||
},
|
||||
SYS_POLL => Syscall::Poll {
|
||||
notification: slot(0)?,
|
||||
},
|
||||
SYS_BIND_NOTIFICATION => Syscall::BindNotification {
|
||||
notification: slot(0)?,
|
||||
},
|
||||
SYS_SET_IRQ_NOTIFICATION => Syscall::SetIrqNotification {
|
||||
irq: slot(0)?,
|
||||
notification: slot(1)?,
|
||||
},
|
||||
SYS_ACKNOWLEDGE_INTERRUPT => Syscall::AcknowledgeInterrupt { irq: slot(0)? },
|
||||
SYS_CREATE_PROCESS => Syscall::CreateProcess {
|
||||
create_cap: slot(0)?,
|
||||
image: DataRef::empty(),
|
||||
},
|
||||
SYS_KILL => Syscall::Kill { process: slot(0)? },
|
||||
SYS_REVOKE => Syscall::Revoke { slot: slot(0)? },
|
||||
SYS_DROP_CAP => Syscall::DropCap { slot: slot(0)? },
|
||||
SYS_SPAWN_THREAD => Syscall::SpawnThread {
|
||||
entry: EntryPoint::from_raw(a(0)),
|
||||
stack: StackPointer::from_raw(a(1)),
|
||||
},
|
||||
SYS_REQUEST_PAGES => Syscall::RequestPages {
|
||||
count: PageCount::new(u16::try_from(a(0)).ok()?)?,
|
||||
},
|
||||
SYS_RELEASE_PAGES => Syscall::ReleasePages {
|
||||
addr: VirtualAddress::from_raw(a(0)),
|
||||
count: PageCount::new(u16::try_from(a(1)).ok()?)?,
|
||||
},
|
||||
SYS_SPAWN_THREAD_IN => Syscall::SpawnThreadIn {
|
||||
process: slot(0)?,
|
||||
entry: EntryPoint::from_raw(a(1)),
|
||||
stack: StackPointer::from_raw(a(2)),
|
||||
},
|
||||
SYS_CREATE_ENDPOINT => Syscall::CreateEndpoint,
|
||||
SYS_CREATE_REGION => Syscall::CreateRegion {
|
||||
pages: PageCount::new(u16::try_from(a(0)).ok()?)?,
|
||||
},
|
||||
SYS_MAP_REGION => Syscall::MapRegion {
|
||||
region: slot(0)?,
|
||||
va: VirtualAddress::from_raw(a(1)),
|
||||
perms: match a(2) {
|
||||
PERMS_READ_ONLY => types::mapping::PagePerms::ReadOnly,
|
||||
PERMS_READ_WRITE => types::mapping::PagePerms::ReadWrite,
|
||||
PERMS_READ_EXECUTE => types::mapping::PagePerms::ReadExecute,
|
||||
_ => return None,
|
||||
},
|
||||
},
|
||||
SYS_DEBUG_PUTCHAR => Syscall::DebugPutchar { byte: a(0) as u8 },
|
||||
SYS_MAP_PAGE => Syscall::MapPage {
|
||||
process: slot(0)?,
|
||||
src_va: VirtualAddress::from_raw(a(1)),
|
||||
dst_va: VirtualAddress::from_raw(a(2)),
|
||||
executable: a(3) != 0,
|
||||
},
|
||||
_ => return None,
|
||||
})
|
||||
fn args(frame: &TrapFrame) -> [usize; 6] {
|
||||
let mut a = [0usize; 6];
|
||||
a.copy_from_slice(&frame.regs[10..16]);
|
||||
a
|
||||
}
|
||||
|
||||
/// Writes a completed syscall's result per the register ABI: status in
|
||||
/// `a0`, results in `a1..`.
|
||||
fn write_result(frame: &mut TrapFrame, result: &kernel::SyscallResult) {
|
||||
use kernel::SyscallResult;
|
||||
use kernel::syscall::DeliveryKind;
|
||||
use types::syscall_abi::{KIND_CALL, KIND_MESSAGE, KIND_SIGNAL, NONE};
|
||||
fn set_results(frame: &mut TrapFrame, regs: [usize; 8]) {
|
||||
frame.regs[10..18].copy_from_slice(®s);
|
||||
}
|
||||
|
||||
let r = &mut frame.regs;
|
||||
r[10] = 0;
|
||||
match result {
|
||||
SyscallResult::Ok => {}
|
||||
SyscallResult::Value(v) => r[11] = *v,
|
||||
SyscallResult::Slot(s) => r[11] = s.value() as usize,
|
||||
SyscallResult::Received(d) => {
|
||||
r[11] = d.badge;
|
||||
r[12..16].copy_from_slice(&d.words);
|
||||
r[16] = d.cap.map_or(NONE, |s| s.value() as usize);
|
||||
r[17] = match d.kind {
|
||||
DeliveryKind::Message => KIND_MESSAGE,
|
||||
DeliveryKind::Call => KIND_CALL,
|
||||
DeliveryKind::Signal => KIND_SIGNAL,
|
||||
};
|
||||
}
|
||||
SyscallResult::Error(e) => r[10] = kernel::syscall::error_code(e) as usize,
|
||||
}
|
||||
fn write_result(frame: &mut TrapFrame, result: &kernel::SyscallResult) {
|
||||
set_results(frame, kernel::abi::encode(result));
|
||||
}
|
||||
|
||||
fn save_frame_to_context(frame: &TrapFrame, ctx: &mut domain::thread::SavedContext) {
|
||||
@@ -424,8 +290,8 @@ fn handle_exception(frame: &mut TrapFrame, scause: usize) {
|
||||
CAUSE_ECALL_U => {
|
||||
frame.sepc += 4;
|
||||
|
||||
let Some(syscall) = decode_syscall(frame) else {
|
||||
frame.regs[10] = types::syscall_abi::ErrorCode::UnknownSyscall as usize;
|
||||
let Some(syscall) = kernel::abi::decode(frame.regs[17], &args(frame)) else {
|
||||
set_results(frame, kernel::abi::unknown_syscall());
|
||||
return;
|
||||
};
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user