refactor: apply newtypes throughout userspace API and display types

Every syscall stub now uses proper types from types/ — CapSlot,
EntryPoint, StackPointer, VirtualAddress, PageCount, ProcessId,
PermissionSet, Ticks. The compiler prevents swapping entry/stack,
passing a ProcessId where a CapSlot is expected, or using an
address as a page count.

New display types in types/display.rs:
  - Color(u32) with rgb() constructor
  - ScreenCoord(u16) for x/y positions
  - Dimension(u16) for width/height

Updated throughout:
  - userspace/syscall.rs: all params typed, returns Option instead
    of sentinel usize::MAX
  - server-framework: endpoint param is CapSlot
  - port-framebuffer: trait uses Color, ScreenCoord, Dimension
  - hw-virtio: DmaAddrs uses PhysicalAddress/VirtualAddress,
    GPU commands use Dimension
  - All servers, drivers, bins, apps updated for new signatures
  - permission-manager: process field uses ProcessId
  - PermissionSet: added bits() accessor

89 tests pass, full QEMU boot verified.
This commit is contained in:
2026-10-18 13:45:40 +02:00
parent 3a0395453b
commit 7c7e3b8748
42 changed files with 416 additions and 307 deletions

View File

@@ -9,6 +9,7 @@ mod tests;
pub fn run() -> ! {
let mut srv = server::PermissionManager::new();
server_framework::serve(&mut srv, 0);
let ep = types::bounded::CapSlot::new(0).unwrap();
server_framework::serve(&mut srv, ep);
loop { userspace::syscall::yield_now(); }
}

View File

@@ -46,10 +46,10 @@ impl CapabilityKind {
#[derive(Debug, PartialEq)]
pub enum PermissionRequest {
RequestCapability { process: u16, kind: CapabilityKind },
RevokeCapability { process: u16, kind: CapabilityKind },
CheckCapability { process: u16, kind: CapabilityKind },
ListGranted { process: u16 },
RequestCapability { process: types::id::ProcessId, kind: CapabilityKind },
RevokeCapability { process: types::id::ProcessId, kind: CapabilityKind },
CheckCapability { process: types::id::ProcessId, kind: CapabilityKind },
ListGranted { process: types::id::ProcessId },
}
#[derive(Debug, PartialEq)]
@@ -66,16 +66,16 @@ impl Encode for PermissionRequest {
fn encode(&self) -> [usize; 4] {
match self {
PermissionRequest::RequestCapability { process, kind } => {
[0, *process as usize, kind.index(), 0]
[0, process.raw() as usize, kind.index(), 0]
}
PermissionRequest::RevokeCapability { process, kind } => {
[1, *process as usize, kind.index(), 0]
[1, process.raw() as usize, kind.index(), 0]
}
PermissionRequest::CheckCapability { process, kind } => {
[2, *process as usize, kind.index(), 0]
[2, process.raw() as usize, kind.index(), 0]
}
PermissionRequest::ListGranted { process } => {
[3, *process as usize, 0, 0]
[3, process.raw() as usize, 0, 0]
}
}
}
@@ -85,19 +85,19 @@ impl Decode for PermissionRequest {
fn decode(words: [usize; 4]) -> Option<Self> {
match words[0] {
0 => Some(PermissionRequest::RequestCapability {
process: words[1] as u16,
process: types::id::ProcessId::from_raw(words[1] as u16),
kind: CapabilityKind::from_index(words[2])?,
}),
1 => Some(PermissionRequest::RevokeCapability {
process: words[1] as u16,
process: types::id::ProcessId::from_raw(words[1] as u16),
kind: CapabilityKind::from_index(words[2])?,
}),
2 => Some(PermissionRequest::CheckCapability {
process: words[1] as u16,
process: types::id::ProcessId::from_raw(words[1] as u16),
kind: CapabilityKind::from_index(words[2])?,
}),
3 => Some(PermissionRequest::ListGranted {
process: words[1] as u16,
process: types::id::ProcessId::from_raw(words[1] as u16),
}),
_ => None,
}

View File

@@ -1,4 +1,5 @@
use server_framework::Server;
use types::id::ProcessId;
use crate::protocol::{CapabilityKind, PermissionRequest, PermissionResponse};
@@ -16,8 +17,8 @@ impl PermissionManager {
}
}
fn granted_bits(&self, process: u16) -> u16 {
let idx = process as usize;
fn granted_bits(&self, process: ProcessId) -> u16 {
let idx = process.raw() as usize;
if idx >= MAX_PROCESSES {
return 0;
}
@@ -38,7 +39,7 @@ impl Server for PermissionManager {
fn handle(&mut self, request: PermissionRequest) -> PermissionResponse {
match request {
PermissionRequest::RequestCapability { process, kind } => {
let idx = process as usize;
let idx = process.raw() as usize;
if idx >= MAX_PROCESSES {
return PermissionResponse::Denied;
}
@@ -46,7 +47,7 @@ impl Server for PermissionManager {
PermissionResponse::Granted
}
PermissionRequest::RevokeCapability { process, kind } => {
let idx = process as usize;
let idx = process.raw() as usize;
if idx >= MAX_PROCESSES {
return PermissionResponse::Denied;
}
@@ -54,7 +55,7 @@ impl Server for PermissionManager {
PermissionResponse::Revoked
}
PermissionRequest::CheckCapability { process, kind } => {
let idx = process as usize;
let idx = process.raw() as usize;
if idx >= MAX_PROCESSES {
return PermissionResponse::HasCapability(false);
}

View File

@@ -1,27 +1,30 @@
use crate::protocol::*;
use server_framework::{Decode, Encode};
use types::id::ProcessId;
fn pid(v: u16) -> ProcessId { ProcessId::from_raw(v) }
#[test]
fn request_capability_roundtrip() {
let req = PermissionRequest::RequestCapability { process: 5, kind: CapabilityKind::Camera };
let req = PermissionRequest::RequestCapability { process: pid(5), kind: CapabilityKind::Camera };
assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
}
#[test]
fn revoke_capability_roundtrip() {
let req = PermissionRequest::RevokeCapability { process: 3, kind: CapabilityKind::Network };
let req = PermissionRequest::RevokeCapability { process: pid(3), kind: CapabilityKind::Network };
assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
}
#[test]
fn check_capability_roundtrip() {
let req = PermissionRequest::CheckCapability { process: 1, kind: CapabilityKind::Storage };
let req = PermissionRequest::CheckCapability { process: pid(1), kind: CapabilityKind::Storage };
assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
}
#[test]
fn list_granted_roundtrip() {
let req = PermissionRequest::ListGranted { process: 7 };
let req = PermissionRequest::ListGranted { process: pid(7) };
assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
}
@@ -33,7 +36,7 @@ fn all_kinds_roundtrip() {
CapabilityKind::Network, CapabilityKind::Gps, CapabilityKind::Bluetooth,
];
for kind in kinds {
let req = PermissionRequest::RequestCapability { process: 0, kind };
let req = PermissionRequest::RequestCapability { process: pid(0), kind };
assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
}
}

View File

@@ -1,12 +1,15 @@
use crate::protocol::*;
use crate::server::PermissionManager;
use server_framework::Server;
use types::id::ProcessId;
fn pid(v: u16) -> ProcessId { ProcessId::from_raw(v) }
#[test]
fn new_manager_has_no_grants() {
let mut mgr = PermissionManager::new();
let resp = mgr.handle(PermissionRequest::CheckCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Camera,
});
assert_eq!(resp, PermissionResponse::HasCapability(false));
@@ -16,11 +19,11 @@ fn new_manager_has_no_grants() {
fn grant_then_check() {
let mut mgr = PermissionManager::new();
mgr.handle(PermissionRequest::RequestCapability {
process: 1,
process: pid(1),
kind: CapabilityKind::Network,
});
let resp = mgr.handle(PermissionRequest::CheckCapability {
process: 1,
process: pid(1),
kind: CapabilityKind::Network,
});
assert_eq!(resp, PermissionResponse::HasCapability(true));
@@ -30,11 +33,11 @@ fn grant_then_check() {
fn grant_does_not_affect_other_process() {
let mut mgr = PermissionManager::new();
mgr.handle(PermissionRequest::RequestCapability {
process: 1,
process: pid(1),
kind: CapabilityKind::Camera,
});
let resp = mgr.handle(PermissionRequest::CheckCapability {
process: 2,
process: pid(2),
kind: CapabilityKind::Camera,
});
assert_eq!(resp, PermissionResponse::HasCapability(false));
@@ -44,15 +47,15 @@ fn grant_does_not_affect_other_process() {
fn revoke_removes_grant() {
let mut mgr = PermissionManager::new();
mgr.handle(PermissionRequest::RequestCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Storage,
});
mgr.handle(PermissionRequest::RevokeCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Storage,
});
let resp = mgr.handle(PermissionRequest::CheckCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Storage,
});
assert_eq!(resp, PermissionResponse::HasCapability(false));
@@ -62,15 +65,14 @@ fn revoke_removes_grant() {
fn list_granted_returns_bitfield() {
let mut mgr = PermissionManager::new();
mgr.handle(PermissionRequest::RequestCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Display,
});
mgr.handle(PermissionRequest::RequestCapability {
process: 0,
process: pid(0),
kind: CapabilityKind::Network,
});
let resp = mgr.handle(PermissionRequest::ListGranted { process: 0 });
// Display=bit 0, Network=bit 6 → 0b1000001 = 65
let resp = mgr.handle(PermissionRequest::ListGranted { process: pid(0) });
assert_eq!(resp, PermissionResponse::GrantedList(0b1000001));
}
@@ -78,7 +80,7 @@ fn list_granted_returns_bitfield() {
fn out_of_range_process_denied() {
let mut mgr = PermissionManager::new();
let resp = mgr.handle(PermissionRequest::RequestCapability {
process: 999,
process: pid(999),
kind: CapabilityKind::Camera,
});
assert_eq!(resp, PermissionResponse::Denied);