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

11
Cargo.lock generated
View File

@@ -57,6 +57,7 @@ dependencies = [
"display-server", "display-server",
"driver-framebuffer-virtio", "driver-framebuffer-virtio",
"server-framework", "server-framework",
"types",
"userspace", "userspace",
"userspace-rt", "userspace-rt",
] ]
@@ -84,6 +85,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"hw-virtio", "hw-virtio",
"port-block-device", "port-block-device",
"types",
] ]
[[package]] [[package]]
@@ -91,6 +93,7 @@ name = "driver-framebuffer-mock"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"port-framebuffer", "port-framebuffer",
"types",
] ]
[[package]] [[package]]
@@ -99,12 +102,14 @@ version = "0.1.0"
dependencies = [ dependencies = [
"hw-virtio", "hw-virtio",
"port-framebuffer", "port-framebuffer",
"types",
] ]
[[package]] [[package]]
name = "echo" name = "echo"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"types",
"userspace", "userspace",
"userspace-rt", "userspace-rt",
] ]
@@ -131,6 +136,9 @@ dependencies = [
[[package]] [[package]]
name = "hw-virtio" name = "hw-virtio"
version = "0.1.0" version = "0.1.0"
dependencies = [
"types",
]
[[package]] [[package]]
name = "init" name = "init"
@@ -217,6 +225,9 @@ version = "0.1.0"
[[package]] [[package]]
name = "port-framebuffer" name = "port-framebuffer"
version = "0.1.0" version = "0.1.0"
dependencies = [
"types",
]
[[package]] [[package]]
name = "port-input-device" name = "port-input-device"

View File

@@ -8,10 +8,10 @@ const VQUEUE_VA: usize = 0x21000;
const CMDBUF_VA: usize = 0x23000; const CMDBUF_VA: usize = 0x23000;
const PHYSINFO_VA: usize = 0x24000; const PHYSINFO_VA: usize = 0x24000;
const FB_VA: usize = 0x100000; const FB_VA: usize = 0x100000;
const FB_WIDTH: u32 = 640; const FB_WIDTH: types::display::Dimension = types::display::Dimension::new(640);
const FB_HEIGHT: u32 = 480; const FB_HEIGHT: types::display::Dimension = types::display::Dimension::new(480);
const FB_BPP: usize = 4; const FB_BPP: usize = 4;
const FB_PAGES: usize = (FB_WIDTH as usize * FB_HEIGHT as usize * FB_BPP + 4095) / 4096; const FB_PAGES: usize = (FB_WIDTH.raw() as usize * FB_HEIGHT.raw() as usize * FB_BPP + 4095) / 4096;
pub fn configure(uart: &Uart, display_pid: ProcessId) { pub fn configure(uart: &Uart, display_pid: ProcessId) {
let gpu = match VirtioGpu::probe() { let gpu = match VirtioGpu::probe() {
@@ -43,8 +43,8 @@ pub fn configure(uart: &Uart, display_pid: ProcessId) {
core::ptr::write_volatile(info, cmd_phys as u64); core::ptr::write_volatile(info, cmd_phys as u64);
core::ptr::write_volatile(info.add(1), (cmd_phys + 512) as u64); core::ptr::write_volatile(info.add(1), (cmd_phys + 512) as u64);
core::ptr::write_volatile(info.add(2), fb_phys as u64); core::ptr::write_volatile(info.add(2), fb_phys as u64);
core::ptr::write_volatile(info.add(3), FB_WIDTH as u64); core::ptr::write_volatile(info.add(3), FB_WIDTH.raw() as u64);
core::ptr::write_volatile(info.add(4), FB_HEIGHT as u64); core::ptr::write_volatile(info.add(4), FB_HEIGHT.raw() as u64);
} }
gpu.init_device(vq_phys); gpu.init_device(vq_phys);

View File

@@ -1,6 +1,7 @@
use hw_virtio::mmio::{self, DirectMmio}; use hw_virtio::mmio::{self, DirectMmio};
use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE}; use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE};
use hw_virtio::block::{self, DmaAddrs}; use hw_virtio::block::{self, DmaAddrs};
use types::address::{PhysicalAddress, VirtualAddress};
const SECTOR_SIZE: usize = 512; const SECTOR_SIZE: usize = 512;
@@ -31,12 +32,12 @@ impl VirtioBlk {
let dma = unsafe { let dma = unsafe {
DmaAddrs { DmaAddrs {
header_pa: core::ptr::addr_of!(REQ_HEADER) as u64, header_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(REQ_HEADER) as usize),
header_va: core::ptr::addr_of_mut!(REQ_HEADER) as usize, header_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(REQ_HEADER) as usize),
status_pa: core::ptr::addr_of!(REQ_STATUS) as u64, status_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(REQ_STATUS) as usize),
status_va: core::ptr::addr_of_mut!(REQ_STATUS) as usize, status_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(REQ_STATUS) as usize),
data_pa: core::ptr::addr_of!(SECTOR_BUF) as u64, data_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(SECTOR_BUF) as usize),
data_va: core::ptr::addr_of_mut!(SECTOR_BUF) as usize, data_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(SECTOR_BUF) as usize),
} }
}; };

View File

@@ -1,6 +1,8 @@
use hw_virtio::mmio::{self, DirectMmio}; use hw_virtio::mmio::{self, DirectMmio};
use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE}; use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE};
use hw_virtio::gpu::{self, GpuDmaAddrs}; use hw_virtio::gpu::{self, GpuDmaAddrs};
use types::address::{PhysicalAddress, VirtualAddress};
use types::display::Dimension;
pub struct VirtioGpu { pub struct VirtioGpu {
mmio: DirectMmio, mmio: DirectMmio,
@@ -20,15 +22,15 @@ impl VirtioGpu {
mmio::init_legacy_device(&self.mmio, vqueue_phys, QUEUE_SIZE as u32); mmio::init_legacy_device(&self.mmio, vqueue_phys, QUEUE_SIZE as u32);
} }
pub fn setup_framebuffer(&self, cmd_phys: usize, vq_phys: usize, fb_phys: usize, width: u32, height: u32) { pub fn setup_framebuffer(&self, cmd_phys: usize, vq_phys: usize, fb_phys: usize, width: Dimension, height: Dimension) {
let queue = VirtioQueue::new(QueueAddrs::from_base(vq_phys)); let queue = VirtioQueue::new(QueueAddrs::from_base(vq_phys));
let dma = GpuDmaAddrs { let dma = GpuDmaAddrs {
cmd_pa: cmd_phys as u64, cmd_pa: PhysicalAddress::from_raw(cmd_phys),
cmd_va: cmd_phys, cmd_va: VirtualAddress::from_raw(cmd_phys),
resp_pa: (cmd_phys + 512) as u64, resp_pa: PhysicalAddress::from_raw(cmd_phys + 512),
}; };
gpu::create_2d(&self.mmio, &queue, &dma, 1, width, height); gpu::create_2d(&self.mmio, &queue, &dma, 1, width, height);
gpu::attach_backing(&self.mmio, &queue, &dma, 1, fb_phys as u64, width * height * 4); gpu::attach_backing(&self.mmio, &queue, &dma, 1, PhysicalAddress::from_raw(fb_phys), width.raw() as u32 * height.raw() as u32 * 4);
gpu::set_scanout(&self.mmio, &queue, &dma, 0, 1, width, height); gpu::set_scanout(&self.mmio, &queue, &dma, 0, 1, width, height);
} }
} }

View File

@@ -9,5 +9,6 @@ test = false
bench = false bench = false
[dependencies] [dependencies]
types = { workspace = true }
userspace = { workspace = true } userspace = { workspace = true }
userspace-rt = { workspace = true } userspace-rt = { workspace = true }

View File

@@ -3,14 +3,13 @@
extern crate userspace_rt; extern crate userspace_rt;
use types::bounded::CapSlot;
use userspace::syscall; use userspace::syscall;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn main() { extern "C" fn main() {
// Cap slot 0 = endpoint cap (granted by adapter at boot) let ep = CapSlot::new(0).unwrap();
let ep: usize = 0;
// Receive a message, echo it back with word0 incremented
let (w0, w1, w2, w3) = syscall::receive(ep); let (w0, w1, w2, w3) = syscall::receive(ep);
syscall::send(ep, w0.wrapping_add(1), w1, w2, w3); syscall::send(ep, w0.wrapping_add(1), w1, w2, w3);

View File

@@ -5,11 +5,13 @@ extern crate userspace_rt;
use snake::game::{Direction, GameState, Snake}; use snake::game::{Direction, GameState, Snake};
use snake::renderer::{render, RenderCommand}; use snake::renderer::{render, RenderCommand};
use types::bounded::CapSlot;
use types::time::Ticks;
use userspace_rt::syscall; use userspace_rt::syscall;
const DISPLAY_EP: usize = 0; fn display_ep() -> CapSlot { CapSlot::new(0).unwrap() }
const INPUT_EP: usize = 1; fn input_ep() -> CapSlot { CapSlot::new(1).unwrap() }
const TICK_DELAY: usize = 2_000_000; const TICK_DELAY: u64 = 2_000_000;
const MAX_RENDER_COMMANDS: usize = 192; const MAX_RENDER_COMMANDS: usize = 192;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
@@ -33,8 +35,8 @@ extern "C" fn main() {
} }
fn handle_input(snake: &mut Snake) { fn handle_input(snake: &mut Snake) {
let _ = syscall::send(INPUT_EP, 0, 0, 0, 0); let _ = syscall::send(input_ep(), 0, 0, 0, 0);
let (tag, kind, _, _) = syscall::receive(INPUT_EP); let (tag, kind, _, _) = syscall::receive(input_ep());
if tag == 1 { if tag == 1 {
match kind { match kind {
@@ -48,25 +50,25 @@ fn handle_input(snake: &mut Snake) {
} }
fn send_render_commands(commands: &[RenderCommand], count: usize) { fn send_render_commands(commands: &[RenderCommand], count: usize) {
let _ = syscall::send(DISPLAY_EP, 1, 0, 0, 0); let _ = syscall::send(display_ep(), 1, 0, 0, 0);
let _ = syscall::receive(DISPLAY_EP); let _ = syscall::receive(display_ep());
for i in 0..count { for i in 0..count {
let cmd = &commands[i]; let cmd = &commands[i];
let xy = cmd.x as usize | ((cmd.y as usize) << 16); let xy = cmd.x as usize | ((cmd.y as usize) << 16);
let wh = cmd.w as usize | ((cmd.h as usize) << 16); let wh = cmd.w as usize | ((cmd.h as usize) << 16);
let _ = syscall::send(DISPLAY_EP, 0, xy, wh, cmd.color as usize); let _ = syscall::send(display_ep(), 0, xy, wh, cmd.color as usize);
let _ = syscall::receive(DISPLAY_EP); let _ = syscall::receive(display_ep());
} }
let _ = syscall::send(DISPLAY_EP, 2, 0, 0, 0); let _ = syscall::send(display_ep(), 2, 0, 0, 0);
let _ = syscall::receive(DISPLAY_EP); let _ = syscall::receive(display_ep());
} }
fn wait_tick() { fn wait_tick() {
let start = syscall::get_time(); let start = syscall::get_time();
let deadline = start + TICK_DELAY; let deadline = Ticks::from_raw(start.raw() + TICK_DELAY);
while syscall::get_time() < deadline { while syscall::get_time().raw() < deadline.raw() {
syscall::yield_now(); syscall::yield_now();
} }
} }

View File

@@ -9,6 +9,7 @@ test = false
bench = false bench = false
[dependencies] [dependencies]
types = { workspace = true }
userspace-rt = { workspace = true } userspace-rt = { workspace = true }
userspace = { workspace = true } userspace = { workspace = true }
server-framework = { workspace = true } server-framework = { workspace = true }

View File

@@ -4,11 +4,13 @@
extern crate userspace_rt; extern crate userspace_rt;
use driver_framebuffer_virtio::VirtioFramebuffer; use driver_framebuffer_virtio::VirtioFramebuffer;
use types::bounded::CapSlot;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
extern "C" fn main() { extern "C" fn main() {
let fb = VirtioFramebuffer::new(); let fb = VirtioFramebuffer::new();
let mut srv = display_server::server::DisplayServer::new(fb); let mut srv = display_server::server::DisplayServer::new(fb);
server_framework::serve(&mut srv, 0); let ep = CapSlot::new(0).unwrap();
server_framework::serve(&mut srv, ep);
loop { userspace::syscall::yield_now(); } loop { userspace::syscall::yield_now(); }
} }

View File

@@ -6,3 +6,4 @@ edition = "2024"
[dependencies] [dependencies]
port-block-device = { workspace = true } port-block-device = { workspace = true }
hw-virtio = { workspace = true } hw-virtio = { workspace = true }
types = { workspace = true }

View File

@@ -4,6 +4,7 @@ use hw_virtio::mmio::MmioAccess;
use hw_virtio::queue::{QueueAddrs, VirtioQueue}; use hw_virtio::queue::{QueueAddrs, VirtioQueue};
use hw_virtio::block::{self, DmaAddrs}; use hw_virtio::block::{self, DmaAddrs};
use port_block_device::{BlockDevice, SectorId}; use port_block_device::{BlockDevice, SectorId};
use types::address::{PhysicalAddress, VirtualAddress};
const MMIO_BASE: usize = 0x20000; const MMIO_BASE: usize = 0x20000;
const VQUEUE_VA: usize = 0x21000; const VQUEUE_VA: usize = 0x21000;
@@ -35,19 +36,19 @@ impl VirtioBlockDevice {
let (hdr_pa, status_pa, data_pa) = unsafe { let (hdr_pa, status_pa, data_pa) = unsafe {
let p = PHYSINFO_VA as *const u64; let p = PHYSINFO_VA as *const u64;
( (
core::ptr::read_volatile(p), core::ptr::read_volatile(p) as usize,
core::ptr::read_volatile(p.add(1)), core::ptr::read_volatile(p.add(1)) as usize,
core::ptr::read_volatile(p.add(2)), core::ptr::read_volatile(p.add(2)) as usize,
) )
}; };
let dma = DmaAddrs { let dma = DmaAddrs {
header_pa: hdr_pa, header_pa: PhysicalAddress::from_raw(hdr_pa),
header_va: REQ_HDR_VA, header_va: VirtualAddress::from_raw(REQ_HDR_VA),
status_pa, status_pa: PhysicalAddress::from_raw(status_pa),
status_va: REQ_HDR_VA + 16, status_va: VirtualAddress::from_raw(REQ_HDR_VA + 16),
data_pa, data_pa: PhysicalAddress::from_raw(data_pa),
data_va: REQ_HDR_VA + 32, data_va: VirtualAddress::from_raw(REQ_HDR_VA + 32),
}; };
Self { mmio: UserMmio, queue, dma } Self { mmio: UserMmio, queue, dma }

View File

@@ -5,3 +5,4 @@ edition = "2024"
[dependencies] [dependencies]
port-framebuffer = { workspace = true } port-framebuffer = { workspace = true }
types = { workspace = true }

View File

@@ -1,21 +1,22 @@
#![no_std] #![no_std]
use port_framebuffer::Framebuffer; use port_framebuffer::Framebuffer;
use types::display::{Color, Dimension, ScreenCoord};
pub struct MockFramebuffer { pub struct MockFramebuffer {
width: u16, width: Dimension,
height: u16, height: Dimension,
pixels: [(u16, u16, u32); 4096], pixels: [(ScreenCoord, ScreenCoord, Color); 4096],
pixel_count: usize, pixel_count: usize,
flushed: bool, flushed: bool,
} }
impl MockFramebuffer { impl MockFramebuffer {
pub fn new(width: u16, height: u16) -> Self { pub fn new(width: Dimension, height: Dimension) -> Self {
Self { Self {
width, width,
height, height,
pixels: [(0, 0, 0); 4096], pixels: [(ScreenCoord::new(0), ScreenCoord::new(0), Color::from_raw(0)); 4096],
pixel_count: 0, pixel_count: 0,
flushed: false, flushed: false,
} }
@@ -29,31 +30,31 @@ impl MockFramebuffer {
self.flushed self.flushed
} }
pub fn pixel_at(&self, index: usize) -> (u16, u16, u32) { pub fn pixel_at(&self, index: usize) -> (ScreenCoord, ScreenCoord, Color) {
self.pixels[index] self.pixels[index]
} }
} }
impl Framebuffer for MockFramebuffer { impl Framebuffer for MockFramebuffer {
fn width(&self) -> u16 { self.width } fn width(&self) -> Dimension { self.width }
fn height(&self) -> u16 { self.height } fn height(&self) -> Dimension { self.height }
fn write_pixel(&mut self, x: u16, y: u16, color: u32) { fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) {
if self.pixel_count < self.pixels.len() { if self.pixel_count < self.pixels.len() {
self.pixels[self.pixel_count] = (x, y, color); self.pixels[self.pixel_count] = (x, y, color);
self.pixel_count += 1; self.pixel_count += 1;
} }
} }
fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32) { fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
for dy in 0..h { for dy in 0..h.raw() {
for dx in 0..w { for dx in 0..w.raw() {
self.write_pixel(x + dx, y + dy, color); self.write_pixel(ScreenCoord::new(x.raw() + dx), ScreenCoord::new(y.raw() + dy), color);
} }
} }
} }
fn clear(&mut self, _color: u32) { fn clear(&mut self, _color: Color) {
self.pixel_count = 0; self.pixel_count = 0;
} }

View File

@@ -6,3 +6,4 @@ edition = "2024"
[dependencies] [dependencies]
port-framebuffer = { workspace = true } port-framebuffer = { workspace = true }
hw-virtio = { workspace = true } hw-virtio = { workspace = true }
types = { workspace = true }

View File

@@ -4,6 +4,8 @@ use hw_virtio::mmio::MmioAccess;
use hw_virtio::queue::{QueueAddrs, VirtioQueue}; use hw_virtio::queue::{QueueAddrs, VirtioQueue};
use hw_virtio::gpu::{self, GpuDmaAddrs}; use hw_virtio::gpu::{self, GpuDmaAddrs};
use port_framebuffer::Framebuffer; use port_framebuffer::Framebuffer;
use types::address::{PhysicalAddress, VirtualAddress};
use types::display::{Color, Dimension, ScreenCoord};
const GPU_MMIO_VA: usize = 0x20000; const GPU_MMIO_VA: usize = 0x20000;
const VQUEUE_VA: usize = 0x21000; const VQUEUE_VA: usize = 0x21000;
@@ -24,8 +26,8 @@ impl MmioAccess for GpuMmio {
} }
struct PhysInfo { struct PhysInfo {
cmd_pa: u64, cmd_pa: PhysicalAddress,
resp_pa: u64, resp_pa: PhysicalAddress,
width: u16, width: u16,
height: u16, height: u16,
} }
@@ -34,8 +36,8 @@ fn read_phys_info() -> PhysInfo {
unsafe { unsafe {
let p = PHYSINFO_VA as *const u64; let p = PHYSINFO_VA as *const u64;
PhysInfo { PhysInfo {
cmd_pa: core::ptr::read_volatile(p), cmd_pa: PhysicalAddress::from_raw(core::ptr::read_volatile(p) as usize),
resp_pa: core::ptr::read_volatile(p.add(1)), resp_pa: PhysicalAddress::from_raw(core::ptr::read_volatile(p.add(1)) as usize),
width: core::ptr::read_volatile(p.add(3)) as u16, width: core::ptr::read_volatile(p.add(3)) as u16,
height: core::ptr::read_volatile(p.add(4)) as u16, height: core::ptr::read_volatile(p.add(4)) as u16,
} }
@@ -46,50 +48,56 @@ pub struct VirtioFramebuffer {
mmio: GpuMmio, mmio: GpuMmio,
queue: VirtioQueue, queue: VirtioQueue,
dma: GpuDmaAddrs, dma: GpuDmaAddrs,
width: u16, width: Dimension,
height: u16, height: Dimension,
stride: usize, stride: usize,
} }
impl VirtioFramebuffer { impl VirtioFramebuffer {
pub fn new() -> Self { pub fn new() -> Self {
let phys = read_phys_info(); let phys = read_phys_info();
let width = Dimension::new(phys.width);
let height = Dimension::new(phys.height);
let stride = phys.width as usize * FB_BPP; let stride = phys.width as usize * FB_BPP;
Self { Self {
mmio: GpuMmio, mmio: GpuMmio,
queue: VirtioQueue::new(QueueAddrs::from_base(VQUEUE_VA)), queue: VirtioQueue::new(QueueAddrs::from_base(VQUEUE_VA)),
dma: GpuDmaAddrs { cmd_pa: phys.cmd_pa, cmd_va: CMDBUF_VA, resp_pa: phys.resp_pa }, dma: GpuDmaAddrs { cmd_pa: phys.cmd_pa, cmd_va: VirtualAddress::from_raw(CMDBUF_VA), resp_pa: phys.resp_pa },
width: phys.width, width,
height: phys.height, height,
stride, stride,
} }
} }
} }
impl Framebuffer for VirtioFramebuffer { impl Framebuffer for VirtioFramebuffer {
fn width(&self) -> u16 { self.width } fn width(&self) -> Dimension { self.width }
fn height(&self) -> u16 { self.height } fn height(&self) -> Dimension { self.height }
fn write_pixel(&mut self, x: u16, y: u16, color: u32) { fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) {
if x >= self.width || y >= self.height { return; } if x.raw() >= self.width.raw() || y.raw() >= self.height.raw() { return; }
let offset = (y as usize) * self.stride + (x as usize) * FB_BPP; let offset = (y.raw() as usize) * self.stride + (x.raw() as usize) * FB_BPP;
unsafe { core::ptr::write_volatile((FB_VA + offset) as *mut u32, color); } unsafe { core::ptr::write_volatile((FB_VA + offset) as *mut u32, color.raw()); }
} }
fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32) { fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color) {
for dy in 0..h { for dx in 0..w { self.write_pixel(x + dx, y + dy, color); } } for dy in 0..h.raw() {
for dx in 0..w.raw() {
self.write_pixel(ScreenCoord::new(x.raw() + dx), ScreenCoord::new(y.raw() + dy), color);
}
}
} }
fn clear(&mut self, color: u32) { fn clear(&mut self, color: Color) {
let total = self.width as usize * self.height as usize; let total = self.width.raw() as usize * self.height.raw() as usize;
for i in 0..total { for i in 0..total {
unsafe { core::ptr::write_volatile((FB_VA as *mut u32).add(i), color); } unsafe { core::ptr::write_volatile((FB_VA as *mut u32).add(i), color.raw()); }
} }
} }
fn flush(&mut self) { fn flush(&mut self) {
let w = self.width as u32; let w = self.width.raw() as u32;
let h = self.height as u32; let h = self.height.raw() as u32;
gpu::transfer_to_host(&self.mmio, &self.queue, &self.dma, 1, 0, 0, w, h); gpu::transfer_to_host(&self.mmio, &self.queue, &self.dma, 1, 0, 0, w, h);
gpu::resource_flush(&self.mmio, &self.queue, &self.dma, 1, 0, 0, w, h); gpu::resource_flush(&self.mmio, &self.queue, &self.dma, 1, 0, 0, w, h);
} }

View File

@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
types = { workspace = true }

View File

@@ -1,5 +1,6 @@
use crate::mmio::MmioAccess; use crate::mmio::MmioAccess;
use crate::queue::{Descriptor, VirtioQueue}; use crate::queue::{Descriptor, VirtioQueue};
use types::address::{PhysicalAddress, VirtualAddress};
const SECTOR_SIZE: usize = 512; const SECTOR_SIZE: usize = 512;
@@ -11,12 +12,12 @@ pub struct BlockReqHeader {
} }
pub struct DmaAddrs { pub struct DmaAddrs {
pub header_pa: u64, pub header_pa: PhysicalAddress,
pub header_va: usize, pub header_va: VirtualAddress,
pub status_pa: u64, pub status_pa: PhysicalAddress,
pub status_va: usize, pub status_va: VirtualAddress,
pub data_pa: u64, pub data_pa: PhysicalAddress,
pub data_va: usize, pub data_va: VirtualAddress,
} }
pub fn read_sector( pub fn read_sector(
@@ -29,28 +30,28 @@ pub fn read_sector(
if buf.len() < SECTOR_SIZE { return false; } if buf.len() < SECTOR_SIZE { return false; }
unsafe { unsafe {
let hdr = dma.header_va as *mut BlockReqHeader; let hdr = dma.header_va.raw() as *mut BlockReqHeader;
core::ptr::write_volatile(&raw mut (*hdr).req_type, 0); core::ptr::write_volatile(&raw mut (*hdr).req_type, 0);
core::ptr::write_volatile(&raw mut (*hdr).reserved, 0); core::ptr::write_volatile(&raw mut (*hdr).reserved, 0);
core::ptr::write_volatile(&raw mut (*hdr).sector, sector as u64); core::ptr::write_volatile(&raw mut (*hdr).sector, sector as u64);
core::ptr::write_volatile(dma.status_va as *mut u8, 0xFF); core::ptr::write_volatile(dma.status_va.raw() as *mut u8, 0xFF);
} }
let descs = [ let descs = [
Descriptor { addr: dma.header_pa, len: 16, writable: false }, Descriptor { addr: dma.header_pa.raw() as u64, len: 16, writable: false },
Descriptor { addr: dma.data_pa, len: SECTOR_SIZE as u32, writable: true }, Descriptor { addr: dma.data_pa.raw() as u64, len: SECTOR_SIZE as u32, writable: true },
Descriptor { addr: dma.status_pa, len: 1, writable: true }, Descriptor { addr: dma.status_pa.raw() as u64, len: 1, writable: true },
]; ];
if !queue.submit(mmio, &descs) { return false; } if !queue.submit(mmio, &descs) { return false; }
let status = unsafe { core::ptr::read_volatile(dma.status_va as *const u8) }; let status = unsafe { core::ptr::read_volatile(dma.status_va.raw() as *const u8) };
if status != 0 { return false; } if status != 0 { return false; }
if dma.data_va != buf.as_ptr() as usize { if dma.data_va.raw() != buf.as_ptr() as usize {
unsafe { unsafe {
core::ptr::copy_nonoverlapping( core::ptr::copy_nonoverlapping(
dma.data_va as *const u8, dma.data_va.raw() as *const u8,
buf.as_mut_ptr(), buf.as_mut_ptr(),
SECTOR_SIZE, SECTOR_SIZE,
); );

View File

@@ -1,42 +1,44 @@
use crate::mmio::MmioAccess; use crate::mmio::MmioAccess;
use crate::queue::{Descriptor, VirtioQueue}; use crate::queue::{Descriptor, VirtioQueue};
use types::address::{PhysicalAddress, VirtualAddress};
use types::display::Dimension;
pub struct GpuDmaAddrs { pub struct GpuDmaAddrs {
pub cmd_pa: u64, pub cmd_pa: PhysicalAddress,
pub cmd_va: usize, pub cmd_va: VirtualAddress,
pub resp_pa: u64, pub resp_pa: PhysicalAddress,
} }
pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: u32, height: u32) { pub fn create_2d(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, width: Dimension, height: Dimension) {
write_cmd_header(dma.cmd_va, 0x0101); write_cmd_header(dma.cmd_va, 0x0101);
unsafe { unsafe {
let p = dma.cmd_va as *mut u8; let p = dma.cmd_va.raw() as *mut u8;
core::ptr::write_volatile(p.add(24) as *mut u32, resource_id); core::ptr::write_volatile(p.add(24) as *mut u32, resource_id);
core::ptr::write_volatile(p.add(28) as *mut u32, 1); // B8G8R8A8_UNORM core::ptr::write_volatile(p.add(28) as *mut u32, 1); // B8G8R8A8_UNORM
core::ptr::write_volatile(p.add(32) as *mut u32, width); core::ptr::write_volatile(p.add(32) as *mut u32, width.raw() as u32);
core::ptr::write_volatile(p.add(36) as *mut u32, height); core::ptr::write_volatile(p.add(36) as *mut u32, height.raw() as u32);
} }
submit_cmd(mmio, queue, dma, 40); submit_cmd(mmio, queue, dma, 40);
} }
pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: u64, fb_size: u32) { pub fn attach_backing(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, fb_pa: PhysicalAddress, fb_size: u32) {
write_cmd_header(dma.cmd_va, 0x0104); write_cmd_header(dma.cmd_va, 0x0104);
unsafe { unsafe {
let p = dma.cmd_va as *mut u8; let p = dma.cmd_va.raw() as *mut u8;
core::ptr::write_volatile(p.add(24) as *mut u32, resource_id); core::ptr::write_volatile(p.add(24) as *mut u32, resource_id);
core::ptr::write_volatile(p.add(28) as *mut u32, 1); core::ptr::write_volatile(p.add(28) as *mut u32, 1);
core::ptr::write_volatile(p.add(32) as *mut u64, fb_pa); core::ptr::write_volatile(p.add(32) as *mut u64, fb_pa.raw() as u64);
core::ptr::write_volatile(p.add(40) as *mut u32, fb_size); core::ptr::write_volatile(p.add(40) as *mut u32, fb_size);
} }
submit_cmd(mmio, queue, dma, 48); submit_cmd(mmio, queue, dma, 48);
} }
pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, scanout_id: u32, resource_id: u32, width: u32, height: u32) { pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, scanout_id: u32, resource_id: u32, width: Dimension, height: Dimension) {
write_cmd_header(dma.cmd_va, 0x0103); write_cmd_header(dma.cmd_va, 0x0103);
unsafe { unsafe {
let p = dma.cmd_va as *mut u8; let p = dma.cmd_va.raw() as *mut u8;
core::ptr::write_volatile(p.add(32) as *mut u32, width); core::ptr::write_volatile(p.add(32) as *mut u32, width.raw() as u32);
core::ptr::write_volatile(p.add(36) as *mut u32, height); core::ptr::write_volatile(p.add(36) as *mut u32, height.raw() as u32);
core::ptr::write_volatile(p.add(40) as *mut u32, scanout_id); core::ptr::write_volatile(p.add(40) as *mut u32, scanout_id);
core::ptr::write_volatile(p.add(44) as *mut u32, resource_id); core::ptr::write_volatile(p.add(44) as *mut u32, resource_id);
} }
@@ -46,7 +48,7 @@ pub fn set_scanout(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddr
pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) { pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) {
write_cmd_header(dma.cmd_va, 0x0105); write_cmd_header(dma.cmd_va, 0x0105);
unsafe { unsafe {
let p = dma.cmd_va as *mut u8; let p = dma.cmd_va.raw() as *mut u8;
core::ptr::write_volatile(p.add(24) as *mut u32, x); core::ptr::write_volatile(p.add(24) as *mut u32, x);
core::ptr::write_volatile(p.add(28) as *mut u32, y); core::ptr::write_volatile(p.add(28) as *mut u32, y);
core::ptr::write_volatile(p.add(32) as *mut u32, w); core::ptr::write_volatile(p.add(32) as *mut u32, w);
@@ -60,7 +62,7 @@ pub fn transfer_to_host(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDm
pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) { pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, resource_id: u32, x: u32, y: u32, w: u32, h: u32) {
write_cmd_header(dma.cmd_va, 0x0106); write_cmd_header(dma.cmd_va, 0x0106);
unsafe { unsafe {
let p = dma.cmd_va as *mut u8; let p = dma.cmd_va.raw() as *mut u8;
core::ptr::write_volatile(p.add(24) as *mut u32, x); core::ptr::write_volatile(p.add(24) as *mut u32, x);
core::ptr::write_volatile(p.add(28) as *mut u32, y); core::ptr::write_volatile(p.add(28) as *mut u32, y);
core::ptr::write_volatile(p.add(32) as *mut u32, w); core::ptr::write_volatile(p.add(32) as *mut u32, w);
@@ -70,9 +72,9 @@ pub fn resource_flush(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaA
submit_cmd(mmio, queue, dma, 48); submit_cmd(mmio, queue, dma, 48);
} }
fn write_cmd_header(cmd_va: usize, cmd_type: u32) { fn write_cmd_header(cmd_va: VirtualAddress, cmd_type: u32) {
unsafe { unsafe {
let p = cmd_va as *mut u8; let p = cmd_va.raw() as *mut u8;
core::ptr::write_bytes(p, 0, 512); core::ptr::write_bytes(p, 0, 512);
core::ptr::write_volatile(p as *mut u32, cmd_type); core::ptr::write_volatile(p as *mut u32, cmd_type);
} }
@@ -80,8 +82,8 @@ fn write_cmd_header(cmd_va: usize, cmd_type: u32) {
fn submit_cmd(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, cmd_len: u32) { fn submit_cmd(mmio: &impl MmioAccess, queue: &VirtioQueue, dma: &GpuDmaAddrs, cmd_len: u32) {
let descs = [ let descs = [
Descriptor { addr: dma.cmd_pa, len: cmd_len, writable: false }, Descriptor { addr: dma.cmd_pa.raw() as u64, len: cmd_len, writable: false },
Descriptor { addr: dma.resp_pa, len: 24, writable: true }, Descriptor { addr: dma.resp_pa.raw() as u64, len: 24, writable: true },
]; ];
queue.submit(mmio, &descs); queue.submit(mmio, &descs);
} }

View File

@@ -1,15 +1,18 @@
#![no_std] #![no_std]
use types::address::{EntryPoint, StackPointer, VirtualAddress};
use types::bounded::{CapSlot, PageCount};
use types::permission::{Permission, PermissionSet};
use userspace::syscall; use userspace::syscall;
const PAGE_SIZE: usize = 4096; const PAGE_SIZE: usize = 4096;
const USER_CODE_BASE: usize = 0x10000; const USER_CODE_BASE: usize = 0x10000;
const USER_STACK_TOP: usize = USER_CODE_BASE; const USER_STACK_TOP: StackPointer = StackPointer::from_raw(USER_CODE_BASE);
const USER_STACK_PAGES: usize = 4; const USER_STACK_PAGES: usize = 4;
const CMD_READ_FILE: usize = 1; const CMD_READ_FILE: usize = 1;
const CREATE_CAP: usize = 0; fn create_cap() -> CapSlot { CapSlot::new(0).unwrap() }
const STORAGE_EP_CAP: usize = 2; fn storage_ep() -> CapSlot { CapSlot::new(2).unwrap() }
fn debug_print(s: &[u8]) { fn debug_print(s: &[u8]) {
for &b in s { for &b in s {
@@ -43,14 +46,14 @@ fn request_file(shared_buf: *mut u8, filename: &[u8]) -> usize {
core::ptr::write_volatile(shared_buf.add(i), b); core::ptr::write_volatile(shared_buf.add(i), b);
} }
} }
syscall::send(STORAGE_EP_CAP, CMD_READ_FILE, filename.len(), 0, 0); syscall::send(storage_ep(), CMD_READ_FILE, filename.len(), 0, 0);
let (file_size, _, _, _) = syscall::receive(STORAGE_EP_CAP); let (file_size, _, _, _) = syscall::receive(storage_ep());
file_size file_size
} }
struct LoadedProcess { struct LoadedProcess {
process_cap: usize, process_cap: CapSlot,
entry_point: usize, entry_point: EntryPoint,
} }
fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> { fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> {
@@ -65,11 +68,7 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> {
Err(_) => return None, Err(_) => return None,
}; };
let process_cap = syscall::create_process(CREATE_CAP); let process_cap = syscall::create_process(create_cap())?;
if process_cap == usize::MAX {
debug_print(b"create_process failed\n");
return None;
}
for segment in elf_info.segments() { for segment in elf_info.segments() {
let page_start = segment.vaddr & !0xFFF; let page_start = segment.vaddr & !0xFFF;
@@ -77,13 +76,10 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> {
let total_size = offset_in_page + segment.mem_size; let total_size = offset_in_page + segment.mem_size;
let seg_pages = (total_size + PAGE_SIZE - 1) / PAGE_SIZE; let seg_pages = (total_size + PAGE_SIZE - 1) / PAGE_SIZE;
let local_va = syscall::request_pages(seg_pages); let page_count = PageCount::new(seg_pages as u16)?;
if local_va == usize::MAX { let local_va = syscall::request_pages(page_count)?;
debug_print(b"request_pages failed\n");
return None;
}
let local_ptr = local_va as *mut u8; let local_ptr = local_va.raw() as *mut u8;
unsafe { unsafe {
core::ptr::write_bytes(local_ptr, 0, seg_pages * PAGE_SIZE); core::ptr::write_bytes(local_ptr, 0, seg_pages * PAGE_SIZE);
} }
@@ -103,22 +99,22 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> {
} }
for p in 0..seg_pages { for p in 0..seg_pages {
let src_page = local_va + p * PAGE_SIZE; let src_page = VirtualAddress::from_raw(local_va.raw() + p * PAGE_SIZE);
let dst_page = page_start + p * PAGE_SIZE; let dst_page = VirtualAddress::from_raw(page_start + p * PAGE_SIZE);
syscall::map_page(process_cap, src_page, dst_page, segment.flags.execute); syscall::map_page(process_cap, src_page, dst_page, segment.flags.execute);
} }
} }
for i in 0..USER_STACK_PAGES { for i in 0..USER_STACK_PAGES {
let stack_va = syscall::request_pages(1); let page_count = PageCount::new(1)?;
if stack_va == usize::MAX { return None; } let stack_va = syscall::request_pages(page_count)?;
let dst = USER_STACK_TOP - (USER_STACK_PAGES - i) * PAGE_SIZE; let dst = VirtualAddress::from_raw(USER_CODE_BASE - (USER_STACK_PAGES - i) * PAGE_SIZE);
syscall::map_page(process_cap, stack_va, dst, false); syscall::map_page(process_cap, stack_va, dst, false);
} }
Some(LoadedProcess { Some(LoadedProcess {
process_cap, process_cap,
entry_point: elf_info.entry_point, entry_point: EntryPoint::from_raw(elf_info.entry_point),
}) })
} }
@@ -127,7 +123,6 @@ struct ServerInfo {
name: &'static [u8], name: &'static [u8],
} }
// display is loaded by the adapter (needs GPU MMIO access)
const SERVERS: &[ServerInfo] = &[ const SERVERS: &[ServerInfo] = &[
ServerInfo { filename: b"input.elf", name: b"input" }, ServerInfo { filename: b"input.elf", name: b"input" },
ServerInfo { filename: b"log.elf", name: b"log" }, ServerInfo { filename: b"log.elf", name: b"log" },
@@ -140,9 +135,13 @@ pub fn run(shared_buf_va: usize) -> ! {
let shared_buf = shared_buf_va as *mut u8; let shared_buf = shared_buf_va as *mut u8;
debug_print(b"init: started (pid="); debug_print(b"init: started (pid=");
debug_hex(syscall::get_process_id()); debug_hex(syscall::get_process_id().raw() as usize);
debug_print(b")\n"); debug_print(b")\n");
let ipc_perms = PermissionSet::empty()
.with(Permission::Read)
.with(Permission::Execute);
for server in SERVERS { for server in SERVERS {
debug_print(b"init: loading "); debug_print(b"init: loading ");
debug_print(server.name); debug_print(server.name);
@@ -156,13 +155,13 @@ pub fn run(shared_buf_va: usize) -> ! {
} }
}; };
let ep_cap = syscall::create_endpoint(); if let Some(ep_cap) = syscall::create_endpoint() {
let read_execute: usize = (1 << 0) | (1 << 2); syscall::delegate(ep_cap, loaded.process_cap, ipc_perms);
syscall::delegate(ep_cap, loaded.process_cap, read_execute);
syscall::spawn_thread_in(loaded.process_cap, loaded.entry_point, USER_STACK_TOP); syscall::spawn_thread_in(loaded.process_cap, loaded.entry_point, USER_STACK_TOP);
}
debug_print(b"ok (entry="); debug_print(b"ok (entry=");
debug_hex(loaded.entry_point); debug_hex(loaded.entry_point.raw());
debug_print(b")\n"); debug_print(b")\n");
} }

View File

@@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
types = { workspace = true }

View File

@@ -1,10 +1,12 @@
#![no_std] #![no_std]
use types::display::{Color, Dimension, ScreenCoord};
pub trait Framebuffer { pub trait Framebuffer {
fn width(&self) -> u16; fn width(&self) -> Dimension;
fn height(&self) -> u16; fn height(&self) -> Dimension;
fn write_pixel(&mut self, x: u16, y: u16, color: u32); fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color);
fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32); fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color);
fn clear(&mut self, color: u32); fn clear(&mut self, color: Color);
fn flush(&mut self); fn flush(&mut self);
} }

View File

@@ -1,15 +1,16 @@
pub async fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize { use types::bounded::CapSlot;
pub async fn send(endpoint: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
userspace::syscall::send(endpoint, w0, w1, w2, w3) userspace::syscall::send(endpoint, w0, w1, w2, w3)
} }
pub async fn receive(endpoint: usize) -> (usize, usize, usize, usize) { pub async fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) {
userspace::syscall::receive(endpoint) userspace::syscall::receive(endpoint)
} }
pub async fn wait_for_interrupt(irq: usize) { pub async fn wait_for_interrupt(_irq: CapSlot) {
userspace::syscall::yield_now(); userspace::syscall::yield_now();
} }
pub async fn acknowledge_interrupt(irq: usize) { pub async fn acknowledge_interrupt(_irq: CapSlot) {
let _ = irq;
} }

View File

@@ -2,6 +2,7 @@
mod tests; mod tests;
use crate::codec::{Decode, Encode}; use crate::codec::{Decode, Encode};
use types::bounded::CapSlot;
pub trait Server { pub trait Server {
type Request: Decode; type Request: Decode;
@@ -9,7 +10,7 @@ pub trait Server {
fn handle(&mut self, request: Self::Request) -> Self::Response; fn handle(&mut self, request: Self::Request) -> Self::Response;
fn run(&mut self, endpoint: usize) { fn run(&mut self, endpoint: CapSlot) {
loop { loop {
let words = userspace::syscall::receive(endpoint); let words = userspace::syscall::receive(endpoint);
if let Some(request) = Self::Request::decode([words.0, words.1, words.2, words.3]) { if let Some(request) = Self::Request::decode([words.0, words.1, words.2, words.3]) {
@@ -21,6 +22,6 @@ pub trait Server {
} }
} }
pub fn serve<S: Server>(server: &mut S, endpoint: usize) { pub fn serve<S: Server>(server: &mut S, endpoint: CapSlot) {
server.run(endpoint); server.run(endpoint);
} }

View File

@@ -1,9 +1,10 @@
use server_framework::{Decode, Encode}; use server_framework::{Decode, Encode};
use types::display::{Color, Dimension, ScreenCoord};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DisplayRequest { pub enum DisplayRequest {
DrawRect { x: u16, y: u16, w: u16, h: u16, color: u32 }, DrawRect { x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color },
Clear { color: u32 }, Clear { color: Color },
Flush, Flush,
GetDimensions, GetDimensions,
} }
@@ -11,7 +12,7 @@ pub enum DisplayRequest {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum DisplayResponse { pub enum DisplayResponse {
Ok, Ok,
Dimensions { width: u16, height: u16 }, Dimensions { width: Dimension, height: Dimension },
Error, Error,
} }
@@ -19,11 +20,11 @@ impl Encode for DisplayRequest {
fn encode(&self) -> [usize; 4] { fn encode(&self) -> [usize; 4] {
match self { match self {
DisplayRequest::DrawRect { x, y, w, h, color } => { DisplayRequest::DrawRect { x, y, w, h, color } => {
let xy = (*x as usize) | ((*y as usize) << 16); let xy = (x.raw() as usize) | ((y.raw() as usize) << 16);
let wh = (*w as usize) | ((*h as usize) << 16); let wh = (w.raw() as usize) | ((h.raw() as usize) << 16);
[0, xy, wh, *color as usize] [0, xy, wh, color.raw() as usize]
} }
DisplayRequest::Clear { color } => [1, *color as usize, 0, 0], DisplayRequest::Clear { color } => [1, color.raw() as usize, 0, 0],
DisplayRequest::Flush => [2, 0, 0, 0], DisplayRequest::Flush => [2, 0, 0, 0],
DisplayRequest::GetDimensions => [3, 0, 0, 0], DisplayRequest::GetDimensions => [3, 0, 0, 0],
} }
@@ -34,14 +35,14 @@ impl Decode for DisplayRequest {
fn decode(words: [usize; 4]) -> Option<Self> { fn decode(words: [usize; 4]) -> Option<Self> {
match words[0] { match words[0] {
0 => { 0 => {
let x = (words[1] & 0xFFFF) as u16; let x = ScreenCoord::new((words[1] & 0xFFFF) as u16);
let y = ((words[1] >> 16) & 0xFFFF) as u16; let y = ScreenCoord::new(((words[1] >> 16) & 0xFFFF) as u16);
let w = (words[2] & 0xFFFF) as u16; let w = Dimension::new((words[2] & 0xFFFF) as u16);
let h = ((words[2] >> 16) & 0xFFFF) as u16; let h = Dimension::new(((words[2] >> 16) & 0xFFFF) as u16);
let color = words[3] as u32; let color = Color::from_raw(words[3] as u32);
Some(DisplayRequest::DrawRect { x, y, w, h, color }) Some(DisplayRequest::DrawRect { x, y, w, h, color })
} }
1 => Some(DisplayRequest::Clear { color: words[1] as u32 }), 1 => Some(DisplayRequest::Clear { color: Color::from_raw(words[1] as u32) }),
2 => Some(DisplayRequest::Flush), 2 => Some(DisplayRequest::Flush),
3 => Some(DisplayRequest::GetDimensions), 3 => Some(DisplayRequest::GetDimensions),
_ => None, _ => None,
@@ -54,7 +55,7 @@ impl Encode for DisplayResponse {
match self { match self {
DisplayResponse::Ok => [0, 0, 0, 0], DisplayResponse::Ok => [0, 0, 0, 0],
DisplayResponse::Dimensions { width, height } => { DisplayResponse::Dimensions { width, height } => {
[1, *width as usize, *height as usize, 0] [1, width.raw() as usize, height.raw() as usize, 0]
} }
DisplayResponse::Error => [2, 0, 0, 0], DisplayResponse::Error => [2, 0, 0, 0],
} }
@@ -66,8 +67,8 @@ impl Decode for DisplayResponse {
match words[0] { match words[0] {
0 => Some(DisplayResponse::Ok), 0 => Some(DisplayResponse::Ok),
1 => Some(DisplayResponse::Dimensions { 1 => Some(DisplayResponse::Dimensions {
width: words[1] as u16, width: Dimension::new(words[1] as u16),
height: words[2] as u16, height: Dimension::new(words[2] as u16),
}), }),
2 => Some(DisplayResponse::Error), 2 => Some(DisplayResponse::Error),
_ => None, _ => None,

View File

@@ -1,14 +1,15 @@
use crate::protocol::{DisplayRequest, DisplayResponse}; use crate::protocol::{DisplayRequest, DisplayResponse};
use server_framework::{Decode, Encode}; use server_framework::{Decode, Encode};
use types::display::{Color, Dimension, ScreenCoord};
#[test] #[test]
fn draw_rect_roundtrip() { fn draw_rect_roundtrip() {
let req = DisplayRequest::DrawRect { let req = DisplayRequest::DrawRect {
x: 10, x: ScreenCoord::new(10),
y: 20, y: ScreenCoord::new(20),
w: 100, w: Dimension::new(100),
h: 50, h: Dimension::new(50),
color: 0xFF0000, color: Color::from_raw(0xFF0000),
}; };
let words = req.encode(); let words = req.encode();
let decoded = DisplayRequest::decode(words).unwrap(); let decoded = DisplayRequest::decode(words).unwrap();
@@ -17,7 +18,7 @@ fn draw_rect_roundtrip() {
#[test] #[test]
fn clear_roundtrip() { fn clear_roundtrip() {
let req = DisplayRequest::Clear { color: 0x00FF00 }; let req = DisplayRequest::Clear { color: Color::from_raw(0x00FF00) };
let words = req.encode(); let words = req.encode();
let decoded = DisplayRequest::decode(words).unwrap(); let decoded = DisplayRequest::decode(words).unwrap();
assert_eq!(decoded, req); assert_eq!(decoded, req);
@@ -40,8 +41,8 @@ fn get_dimensions_roundtrip() {
#[test] #[test]
fn dimensions_response_roundtrip() { fn dimensions_response_roundtrip() {
let resp = DisplayResponse::Dimensions { let resp = DisplayResponse::Dimensions {
width: 320, width: Dimension::new(320),
height: 240, height: Dimension::new(240),
}; };
let words = resp.encode(); let words = resp.encode();
let decoded = DisplayResponse::decode(words).unwrap(); let decoded = DisplayResponse::decode(words).unwrap();

View File

@@ -2,20 +2,21 @@ use driver_framebuffer_mock::MockFramebuffer;
use crate::protocol::{DisplayRequest, DisplayResponse}; use crate::protocol::{DisplayRequest, DisplayResponse};
use crate::server::DisplayServer; use crate::server::DisplayServer;
use server_framework::Server; use server_framework::Server;
use types::display::{Color, Dimension, ScreenCoord};
fn test_server() -> DisplayServer<MockFramebuffer> { fn test_server() -> DisplayServer<MockFramebuffer> {
DisplayServer::new(MockFramebuffer::new(320, 240)) DisplayServer::new(MockFramebuffer::new(Dimension::new(320), Dimension::new(240)))
} }
#[test] #[test]
fn draw_rect_writes_pixels() { fn draw_rect_writes_pixels() {
let mut server = test_server(); let mut server = test_server();
let resp = server.handle(DisplayRequest::DrawRect { let resp = server.handle(DisplayRequest::DrawRect {
x: 0, x: ScreenCoord::new(0),
y: 0, y: ScreenCoord::new(0),
w: 4, w: Dimension::new(4),
h: 3, h: Dimension::new(3),
color: 0xFF, color: Color::from_raw(0xFF),
}); });
assert_eq!(resp, DisplayResponse::Ok); assert_eq!(resp, DisplayResponse::Ok);
assert_eq!(server.framebuffer().pixel_count(), 12); assert_eq!(server.framebuffer().pixel_count(), 12);
@@ -25,13 +26,13 @@ fn draw_rect_writes_pixels() {
fn clear_resets_pixels() { fn clear_resets_pixels() {
let mut server = test_server(); let mut server = test_server();
server.handle(DisplayRequest::DrawRect { server.handle(DisplayRequest::DrawRect {
x: 0, x: ScreenCoord::new(0),
y: 0, y: ScreenCoord::new(0),
w: 10, w: Dimension::new(10),
h: 10, h: Dimension::new(10),
color: 0xFF, color: Color::from_raw(0xFF),
}); });
server.handle(DisplayRequest::Clear { color: 0 }); server.handle(DisplayRequest::Clear { color: Color::from_raw(0) });
assert_eq!(server.framebuffer().pixel_count(), 0); assert_eq!(server.framebuffer().pixel_count(), 0);
} }
@@ -50,8 +51,8 @@ fn get_dimensions_returns_size() {
assert_eq!( assert_eq!(
resp, resp,
DisplayResponse::Dimensions { DisplayResponse::Dimensions {
width: 320, width: Dimension::new(320),
height: 240 height: Dimension::new(240),
} }
); );
} }
@@ -60,16 +61,16 @@ fn get_dimensions_returns_size() {
fn draw_rect_correct_pixel_positions() { fn draw_rect_correct_pixel_positions() {
let mut server = test_server(); let mut server = test_server();
server.handle(DisplayRequest::DrawRect { server.handle(DisplayRequest::DrawRect {
x: 5, x: ScreenCoord::new(5),
y: 10, y: ScreenCoord::new(10),
w: 2, w: Dimension::new(2),
h: 2, h: Dimension::new(2),
color: 0xAB, color: Color::from_raw(0xAB),
}); });
let fb = server.framebuffer(); let fb = server.framebuffer();
assert_eq!(fb.pixel_count(), 4); assert_eq!(fb.pixel_count(), 4);
assert_eq!(fb.pixel_at(0), (5, 10, 0xAB)); assert_eq!(fb.pixel_at(0), (ScreenCoord::new(5), ScreenCoord::new(10), Color::from_raw(0xAB)));
assert_eq!(fb.pixel_at(1), (6, 10, 0xAB)); assert_eq!(fb.pixel_at(1), (ScreenCoord::new(6), ScreenCoord::new(10), Color::from_raw(0xAB)));
assert_eq!(fb.pixel_at(2), (5, 11, 0xAB)); assert_eq!(fb.pixel_at(2), (ScreenCoord::new(5), ScreenCoord::new(11), Color::from_raw(0xAB)));
assert_eq!(fb.pixel_at(3), (6, 11, 0xAB)); assert_eq!(fb.pixel_at(3), (ScreenCoord::new(6), ScreenCoord::new(11), Color::from_raw(0xAB)));
} }

View File

@@ -16,6 +16,7 @@ pub fn run() -> ! {
let device = adapters::mock::MockInputDevice::new(); let device = adapters::mock::MockInputDevice::new();
let mut srv = server::InputServer::new(device); let mut srv = server::InputServer::new(device);
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(); } loop { userspace::syscall::yield_now(); }
} }

View File

@@ -9,6 +9,7 @@ mod tests;
pub fn run() -> ! { pub fn run() -> ! {
let mut srv = server::LogServer::new(); let mut srv = server::LogServer::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(); } loop { userspace::syscall::yield_now(); }
} }

View File

@@ -9,6 +9,7 @@ mod tests;
pub fn run() -> ! { pub fn run() -> ! {
let mut srv = server::PermissionManager::new(); 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(); } loop { userspace::syscall::yield_now(); }
} }

View File

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

View File

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

View File

@@ -1,27 +1,30 @@
use crate::protocol::*; use crate::protocol::*;
use server_framework::{Decode, Encode}; use server_framework::{Decode, Encode};
use types::id::ProcessId;
fn pid(v: u16) -> ProcessId { ProcessId::from_raw(v) }
#[test] #[test]
fn request_capability_roundtrip() { 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)); assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
} }
#[test] #[test]
fn revoke_capability_roundtrip() { 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)); assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
} }
#[test] #[test]
fn check_capability_roundtrip() { 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)); assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
} }
#[test] #[test]
fn list_granted_roundtrip() { 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)); assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
} }
@@ -33,7 +36,7 @@ fn all_kinds_roundtrip() {
CapabilityKind::Network, CapabilityKind::Gps, CapabilityKind::Bluetooth, CapabilityKind::Network, CapabilityKind::Gps, CapabilityKind::Bluetooth,
]; ];
for kind in kinds { 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)); assert_eq!(PermissionRequest::decode(req.encode()), Some(req));
} }
} }

View File

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

View File

@@ -8,8 +8,10 @@ pub mod server;
mod tests; mod tests;
pub fn run() -> ! { pub fn run() -> ! {
let mut srv = server::SessionServer::new(0, 0, 0); let create_cap = types::bounded::CapSlot::new(0).unwrap();
let mut srv = server::SessionServer::new(create_cap);
srv.register_app("snake", "/apps/snake.elf"); srv.register_app("snake", "/apps/snake.elf");
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(); } loop { userspace::syscall::yield_now(); }
} }

View File

@@ -1,4 +1,6 @@
use server_framework::Server; use server_framework::Server;
use types::bounded::CapSlot;
use types::id::ProcessId;
use crate::protocol::{AppId, SessionRequest, SessionResponse}; use crate::protocol::{AppId, SessionRequest, SessionResponse};
@@ -14,7 +16,7 @@ pub struct AppEntry {
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
struct RunningApp { struct RunningApp {
app: AppId, app: AppId,
pid: u16, pid: ProcessId,
} }
pub struct SessionServer { pub struct SessionServer {
@@ -22,21 +24,17 @@ pub struct SessionServer {
app_count: usize, app_count: usize,
running: [Option<RunningApp>; MAX_APPS], running: [Option<RunningApp>; MAX_APPS],
active: Option<AppId>, active: Option<AppId>,
create_cap: usize, create_cap: CapSlot,
display_cap: usize,
input_cap: usize,
} }
impl SessionServer { impl SessionServer {
pub fn new(create_cap: usize, display_cap: usize, input_cap: usize) -> Self { pub fn new(create_cap: CapSlot) -> Self {
Self { Self {
apps: [const { None }; MAX_APPS], apps: [const { None }; MAX_APPS],
app_count: 0, app_count: 0,
running: [const { None }; MAX_APPS], running: [const { None }; MAX_APPS],
active: None, active: None,
create_cap, create_cap,
display_cap,
input_cap,
} }
} }
@@ -74,9 +72,13 @@ impl SessionServer {
None => return SessionResponse::NotFound, None => return SessionResponse::NotFound,
}; };
let pid = userspace::syscall::create_process(self.create_cap); let process_cap = match userspace::syscall::create_process(self.create_cap) {
Some(cap) => cap,
None => return SessionResponse::Error,
};
self.running[idx] = Some(RunningApp { app, pid: pid as u16 }); let pid = ProcessId::from_raw(process_cap.value() as u16);
self.running[idx] = Some(RunningApp { app, pid });
self.active = Some(app); self.active = Some(app);
SessionResponse::Launched { app } SessionResponse::Launched { app }
@@ -85,8 +87,7 @@ impl SessionServer {
fn kill_app(&mut self, app: AppId) -> SessionResponse { fn kill_app(&mut self, app: AppId) -> SessionResponse {
let idx = app.raw() as usize; let idx = app.raw() as usize;
match self.running[idx].take() { match self.running[idx].take() {
Some(running) => { Some(_running) => {
let _ = running.pid;
if self.active == Some(app) { if self.active == Some(app) {
self.active = None; self.active = None;
} }

View File

@@ -3,7 +3,8 @@ use crate::server::SessionServer;
use server_framework::Server; use server_framework::Server;
fn test_server() -> SessionServer { fn test_server() -> SessionServer {
let mut s = SessionServer::new(0, 0, 0); let cap = types::bounded::CapSlot::new(0).unwrap();
let mut s = SessionServer::new(cap);
s.register_app("snake", "/apps/snake.elf"); s.register_app("snake", "/apps/snake.elf");
s.register_app("clock", "/apps/clock.elf"); s.register_app("clock", "/apps/clock.elf");
s s

View File

@@ -38,7 +38,7 @@ pub fn run() -> ! {
let mut fat16 = fat16.unwrap(); let mut fat16 = fat16.unwrap();
debug_print(b"storage: FAT16 mounted\n"); debug_print(b"storage: FAT16 mounted\n");
let ep: usize = 0; let ep = types::bounded::CapSlot::new(0).unwrap();
loop { loop {
let (w0, w1, _w2, _w3) = syscall::receive(ep); let (w0, w1, _w2, _w3) = syscall::receive(ep);

View File

@@ -0,0 +1,36 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Color(u32);
impl Color {
pub const fn from_raw(v: u32) -> Self { Self(v) }
pub const fn raw(&self) -> u32 { self.0 }
pub const fn rgb(r: u8, g: u8, b: u8) -> Self {
Self(((r as u32) << 16) | ((g as u32) << 8) | (b as u32) | 0xFF000000)
}
pub const fn rgba(r: u8, g: u8, b: u8, a: u8) -> Self {
Self(((a as u32) << 24) | ((r as u32) << 16) | ((g as u32) << 8) | (b as u32))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ScreenCoord(u16);
impl ScreenCoord {
pub const fn new(v: u16) -> Self { Self(v) }
pub const fn raw(&self) -> u16 { self.0 }
}
impl core::ops::Add<Dimension> for ScreenCoord {
type Output = Self;
fn add(self, rhs: Dimension) -> Self { Self(self.0 + rhs.0) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Dimension(u16);
impl Dimension {
pub const fn new(v: u16) -> Self { Self(v) }
pub const fn raw(&self) -> u16 { self.0 }
}

View File

@@ -2,6 +2,7 @@
pub mod address; pub mod address;
pub mod bounded; pub mod bounded;
pub mod display;
pub mod generation; pub mod generation;
pub mod id; pub mod id;
pub mod macros; pub mod macros;

View File

@@ -44,4 +44,8 @@ impl PermissionSet {
pub fn from_bits(bits: u8) -> Self { pub fn from_bits(bits: u8) -> Self {
PermissionSet(bits) PermissionSet(bits)
} }
pub fn bits(&self) -> u8 {
self.0
}
} }

View File

@@ -47,14 +47,18 @@ impl AllocatorInner {
return ptr::null_mut(); return ptr::null_mut();
} }
let page_addr = crate::syscall::request_pages(1); let count = match types::bounded::PageCount::new(1) {
if page_addr == usize::MAX { Some(c) => c,
return ptr::null_mut(); None => return ptr::null_mut(),
} };
let va = match crate::syscall::request_pages(count) {
Some(va) => va,
None => return ptr::null_mut(),
};
self.pages[self.page_count] = page_addr; self.pages[self.page_count] = va.raw();
self.page_count += 1; self.page_count += 1;
page_addr as *mut u8 va.raw() as *mut u8
} }
fn alloc_from_free_list(&mut self, size: usize, align: usize) -> *mut u8 { fn alloc_from_free_list(&mut self, size: usize, align: usize) -> *mut u8 {

View File

@@ -1,5 +1,10 @@
use crate::arch; use crate::arch;
use types::syscall_abi::*; use types::syscall_abi::*;
use types::address::{EntryPoint, StackPointer, VirtualAddress};
use types::bounded::{CapSlot, PageCount};
use types::id::ProcessId;
use types::permission::PermissionSet;
use types::time::Ticks;
pub fn exit() -> ! { pub fn exit() -> ! {
arch::syscall0(SYS_EXIT); arch::syscall0(SYS_EXIT);
@@ -15,63 +20,66 @@ pub fn yield_now() {
arch::syscall0(SYS_YIELD); arch::syscall0(SYS_YIELD);
} }
pub fn get_time() -> usize {
arch::syscall0(SYS_GET_TIME)
}
pub fn get_process_id() -> usize {
arch::syscall0(SYS_GET_PROCESS_ID)
}
pub fn spawn_thread(entry: usize, stack: usize) -> usize {
arch::syscall2(SYS_SPAWN_THREAD, entry, stack)
}
pub fn request_pages(count: usize) -> usize {
arch::syscall1(SYS_REQUEST_PAGES, count)
}
pub fn create_process(create_cap: usize) -> usize {
arch::syscall1(SYS_CREATE_PROCESS, create_cap)
}
pub fn kill(process_cap: usize) -> usize {
arch::syscall1(SYS_KILL, process_cap)
}
pub fn delegate(slot: usize, to: usize, permissions: usize) -> usize {
arch::syscall3(SYS_DELEGATE, slot, to, permissions)
}
pub fn revoke(slot: usize) -> usize {
arch::syscall1(SYS_REVOKE, slot)
}
pub fn halt() -> ! { pub fn halt() -> ! {
arch::syscall0(SYS_HALT); arch::syscall0(SYS_HALT);
loop {} loop {}
} }
pub fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize { pub fn get_time() -> Ticks {
arch::syscall5(SYS_SEND, endpoint, w0, w1, w2, w3) Ticks::from_raw(arch::syscall0(SYS_GET_TIME) as u64)
} }
pub fn receive(endpoint: usize) -> (usize, usize, usize, usize) { pub fn get_process_id() -> ProcessId {
arch::syscall_receive(SYS_RECEIVE, endpoint) ProcessId::from_raw(arch::syscall0(SYS_GET_PROCESS_ID) as u16)
} }
pub fn create_endpoint() -> usize { pub fn create_process(create_cap: CapSlot) -> Option<CapSlot> {
arch::syscall0(SYS_CREATE_ENDPOINT) let r = arch::syscall1(SYS_CREATE_PROCESS, create_cap.value() as usize);
if r == usize::MAX { None } else { CapSlot::new(r as u8) }
}
pub fn create_endpoint() -> Option<CapSlot> {
let r = arch::syscall0(SYS_CREATE_ENDPOINT);
if r == usize::MAX { None } else { CapSlot::new(r as u8) }
}
pub fn spawn_thread(entry: EntryPoint, stack: StackPointer) -> usize {
arch::syscall2(SYS_SPAWN_THREAD, entry.raw(), stack.raw())
}
pub fn spawn_thread_in(process_cap: CapSlot, entry: EntryPoint, stack: StackPointer) -> usize {
arch::syscall3(SYS_SPAWN_THREAD_IN, process_cap.value() as usize, entry.raw(), stack.raw())
}
pub fn request_pages(count: PageCount) -> Option<VirtualAddress> {
let r = arch::syscall1(SYS_REQUEST_PAGES, count.value() as usize);
if r == usize::MAX { None } else { Some(VirtualAddress::from_raw(r)) }
}
pub fn map_page(process_cap: CapSlot, src_va: VirtualAddress, dst_va: VirtualAddress, executable: bool) -> bool {
arch::syscall4(SYS_MAP_PAGE, process_cap.value() as usize, src_va.raw(), dst_va.raw(), executable as usize) == 0
}
pub fn send(endpoint: CapSlot, w0: usize, w1: usize, w2: usize, w3: usize) -> usize {
arch::syscall5(SYS_SEND, endpoint.value() as usize, w0, w1, w2, w3)
}
pub fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) {
arch::syscall_receive(SYS_RECEIVE, endpoint.value() as usize)
}
pub fn delegate(slot: CapSlot, to: CapSlot, permissions: PermissionSet) -> bool {
arch::syscall3(SYS_DELEGATE, slot.value() as usize, to.value() as usize, permissions.bits() as usize) == 0
}
pub fn kill(process_cap: CapSlot) -> bool {
arch::syscall1(SYS_KILL, process_cap.value() as usize) == 0
}
pub fn revoke(slot: CapSlot) -> bool {
arch::syscall1(SYS_REVOKE, slot.value() as usize) == 0
} }
pub fn debug_putchar(byte: u8) { pub fn debug_putchar(byte: u8) {
arch::syscall1(SYS_DEBUG_PUTCHAR, byte as usize); arch::syscall1(SYS_DEBUG_PUTCHAR, byte as usize);
} }
pub fn map_page(process_cap: usize, src_va: usize, dst_va: usize, executable: bool) -> usize {
arch::syscall4(SYS_MAP_PAGE, process_cap, src_va, dst_va, executable as usize)
}
pub fn spawn_thread_in(process_cap: usize, entry: usize, stack: usize) -> usize {
arch::syscall3(SYS_SPAWN_THREAD_IN, process_cap, entry, stack)
}