diff --git a/Cargo.lock b/Cargo.lock index 13033dd..7554574 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,7 @@ dependencies = [ "display-server", "driver-framebuffer-virtio", "server-framework", + "types", "userspace", "userspace-rt", ] @@ -84,6 +85,7 @@ version = "0.1.0" dependencies = [ "hw-virtio", "port-block-device", + "types", ] [[package]] @@ -91,6 +93,7 @@ name = "driver-framebuffer-mock" version = "0.1.0" dependencies = [ "port-framebuffer", + "types", ] [[package]] @@ -99,12 +102,14 @@ version = "0.1.0" dependencies = [ "hw-virtio", "port-framebuffer", + "types", ] [[package]] name = "echo" version = "0.1.0" dependencies = [ + "types", "userspace", "userspace-rt", ] @@ -131,6 +136,9 @@ dependencies = [ [[package]] name = "hw-virtio" version = "0.1.0" +dependencies = [ + "types", +] [[package]] name = "init" @@ -217,6 +225,9 @@ version = "0.1.0" [[package]] name = "port-framebuffer" version = "0.1.0" +dependencies = [ + "types", +] [[package]] name = "port-input-device" diff --git a/crates/adapter-riscv/src/devices/gpu_setup.rs b/crates/adapter-riscv/src/devices/gpu_setup.rs index 9fa0598..8b21a13 100644 --- a/crates/adapter-riscv/src/devices/gpu_setup.rs +++ b/crates/adapter-riscv/src/devices/gpu_setup.rs @@ -8,10 +8,10 @@ const VQUEUE_VA: usize = 0x21000; const CMDBUF_VA: usize = 0x23000; const PHYSINFO_VA: usize = 0x24000; const FB_VA: usize = 0x100000; -const FB_WIDTH: u32 = 640; -const FB_HEIGHT: u32 = 480; +const FB_WIDTH: types::display::Dimension = types::display::Dimension::new(640); +const FB_HEIGHT: types::display::Dimension = types::display::Dimension::new(480); 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) { 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.add(1), (cmd_phys + 512) 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(4), FB_HEIGHT as u64); + core::ptr::write_volatile(info.add(3), FB_WIDTH.raw() as u64); + core::ptr::write_volatile(info.add(4), FB_HEIGHT.raw() as u64); } gpu.init_device(vq_phys); diff --git a/crates/adapter-riscv/src/hw/virtio_blk.rs b/crates/adapter-riscv/src/hw/virtio_blk.rs index 17aa1ec..14c40aa 100644 --- a/crates/adapter-riscv/src/hw/virtio_blk.rs +++ b/crates/adapter-riscv/src/hw/virtio_blk.rs @@ -1,6 +1,7 @@ use hw_virtio::mmio::{self, DirectMmio}; use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE}; use hw_virtio::block::{self, DmaAddrs}; +use types::address::{PhysicalAddress, VirtualAddress}; const SECTOR_SIZE: usize = 512; @@ -31,12 +32,12 @@ impl VirtioBlk { let dma = unsafe { DmaAddrs { - header_pa: core::ptr::addr_of!(REQ_HEADER) as u64, - header_va: core::ptr::addr_of_mut!(REQ_HEADER) as usize, - status_pa: core::ptr::addr_of!(REQ_STATUS) as u64, - status_va: core::ptr::addr_of_mut!(REQ_STATUS) as usize, - data_pa: core::ptr::addr_of!(SECTOR_BUF) as u64, - data_va: core::ptr::addr_of_mut!(SECTOR_BUF) as usize, + header_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(REQ_HEADER) as usize), + header_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(REQ_HEADER) as usize), + status_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(REQ_STATUS) as usize), + status_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(REQ_STATUS) as usize), + data_pa: PhysicalAddress::from_raw(core::ptr::addr_of!(SECTOR_BUF) as usize), + data_va: VirtualAddress::from_raw(core::ptr::addr_of_mut!(SECTOR_BUF) as usize), } }; diff --git a/crates/adapter-riscv/src/hw/virtio_gpu.rs b/crates/adapter-riscv/src/hw/virtio_gpu.rs index af06ce1..eadc4c0 100644 --- a/crates/adapter-riscv/src/hw/virtio_gpu.rs +++ b/crates/adapter-riscv/src/hw/virtio_gpu.rs @@ -1,6 +1,8 @@ use hw_virtio::mmio::{self, DirectMmio}; use hw_virtio::queue::{QueueAddrs, VirtioQueue, QUEUE_SIZE}; use hw_virtio::gpu::{self, GpuDmaAddrs}; +use types::address::{PhysicalAddress, VirtualAddress}; +use types::display::Dimension; pub struct VirtioGpu { mmio: DirectMmio, @@ -20,15 +22,15 @@ impl VirtioGpu { 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 dma = GpuDmaAddrs { - cmd_pa: cmd_phys as u64, - cmd_va: cmd_phys, - resp_pa: (cmd_phys + 512) as u64, + cmd_pa: PhysicalAddress::from_raw(cmd_phys), + cmd_va: VirtualAddress::from_raw(cmd_phys), + resp_pa: PhysicalAddress::from_raw(cmd_phys + 512), }; 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); } } diff --git a/crates/apps/echo/Cargo.toml b/crates/apps/echo/Cargo.toml index 34002fb..c919ae8 100644 --- a/crates/apps/echo/Cargo.toml +++ b/crates/apps/echo/Cargo.toml @@ -9,5 +9,6 @@ test = false bench = false [dependencies] +types = { workspace = true } userspace = { workspace = true } userspace-rt = { workspace = true } diff --git a/crates/apps/echo/src/main.rs b/crates/apps/echo/src/main.rs index 02b1302..edd03d7 100644 --- a/crates/apps/echo/src/main.rs +++ b/crates/apps/echo/src/main.rs @@ -3,14 +3,13 @@ extern crate userspace_rt; +use types::bounded::CapSlot; use userspace::syscall; #[unsafe(no_mangle)] extern "C" fn main() { - // Cap slot 0 = endpoint cap (granted by adapter at boot) - let ep: usize = 0; + let ep = CapSlot::new(0).unwrap(); - // Receive a message, echo it back with word0 incremented let (w0, w1, w2, w3) = syscall::receive(ep); syscall::send(ep, w0.wrapping_add(1), w1, w2, w3); diff --git a/crates/apps/snake/src/main.rs b/crates/apps/snake/src/main.rs index c39c775..dd741b1 100644 --- a/crates/apps/snake/src/main.rs +++ b/crates/apps/snake/src/main.rs @@ -5,11 +5,13 @@ extern crate userspace_rt; use snake::game::{Direction, GameState, Snake}; use snake::renderer::{render, RenderCommand}; +use types::bounded::CapSlot; +use types::time::Ticks; use userspace_rt::syscall; -const DISPLAY_EP: usize = 0; -const INPUT_EP: usize = 1; -const TICK_DELAY: usize = 2_000_000; +fn display_ep() -> CapSlot { CapSlot::new(0).unwrap() } +fn input_ep() -> CapSlot { CapSlot::new(1).unwrap() } +const TICK_DELAY: u64 = 2_000_000; const MAX_RENDER_COMMANDS: usize = 192; #[unsafe(no_mangle)] @@ -33,8 +35,8 @@ extern "C" fn main() { } fn handle_input(snake: &mut Snake) { - let _ = syscall::send(INPUT_EP, 0, 0, 0, 0); - let (tag, kind, _, _) = syscall::receive(INPUT_EP); + let _ = syscall::send(input_ep(), 0, 0, 0, 0); + let (tag, kind, _, _) = syscall::receive(input_ep()); if tag == 1 { match kind { @@ -48,25 +50,25 @@ fn handle_input(snake: &mut Snake) { } fn send_render_commands(commands: &[RenderCommand], count: usize) { - let _ = syscall::send(DISPLAY_EP, 1, 0, 0, 0); - let _ = syscall::receive(DISPLAY_EP); + let _ = syscall::send(display_ep(), 1, 0, 0, 0); + let _ = syscall::receive(display_ep()); for i in 0..count { let cmd = &commands[i]; let xy = cmd.x as usize | ((cmd.y 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::receive(DISPLAY_EP); + let _ = syscall::send(display_ep(), 0, xy, wh, cmd.color as usize); + let _ = syscall::receive(display_ep()); } - let _ = syscall::send(DISPLAY_EP, 2, 0, 0, 0); - let _ = syscall::receive(DISPLAY_EP); + let _ = syscall::send(display_ep(), 2, 0, 0, 0); + let _ = syscall::receive(display_ep()); } fn wait_tick() { let start = syscall::get_time(); - let deadline = start + TICK_DELAY; - while syscall::get_time() < deadline { + let deadline = Ticks::from_raw(start.raw() + TICK_DELAY); + while syscall::get_time().raw() < deadline.raw() { syscall::yield_now(); } } diff --git a/crates/bins/display-qemu/Cargo.toml b/crates/bins/display-qemu/Cargo.toml index 9a49984..a4e7dbe 100644 --- a/crates/bins/display-qemu/Cargo.toml +++ b/crates/bins/display-qemu/Cargo.toml @@ -9,6 +9,7 @@ test = false bench = false [dependencies] +types = { workspace = true } userspace-rt = { workspace = true } userspace = { workspace = true } server-framework = { workspace = true } diff --git a/crates/bins/display-qemu/src/main.rs b/crates/bins/display-qemu/src/main.rs index dee2f07..271f5ea 100644 --- a/crates/bins/display-qemu/src/main.rs +++ b/crates/bins/display-qemu/src/main.rs @@ -4,11 +4,13 @@ extern crate userspace_rt; use driver_framebuffer_virtio::VirtioFramebuffer; +use types::bounded::CapSlot; #[unsafe(no_mangle)] extern "C" fn main() { let fb = VirtioFramebuffer::new(); 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(); } } diff --git a/crates/drivers/block/virtio/Cargo.toml b/crates/drivers/block/virtio/Cargo.toml index bd76394..157c343 100644 --- a/crates/drivers/block/virtio/Cargo.toml +++ b/crates/drivers/block/virtio/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] port-block-device = { workspace = true } hw-virtio = { workspace = true } +types = { workspace = true } diff --git a/crates/drivers/block/virtio/src/lib.rs b/crates/drivers/block/virtio/src/lib.rs index b502525..e3327df 100644 --- a/crates/drivers/block/virtio/src/lib.rs +++ b/crates/drivers/block/virtio/src/lib.rs @@ -4,6 +4,7 @@ use hw_virtio::mmio::MmioAccess; use hw_virtio::queue::{QueueAddrs, VirtioQueue}; use hw_virtio::block::{self, DmaAddrs}; use port_block_device::{BlockDevice, SectorId}; +use types::address::{PhysicalAddress, VirtualAddress}; const MMIO_BASE: usize = 0x20000; const VQUEUE_VA: usize = 0x21000; @@ -35,19 +36,19 @@ impl VirtioBlockDevice { let (hdr_pa, status_pa, data_pa) = unsafe { let p = PHYSINFO_VA as *const u64; ( - core::ptr::read_volatile(p), - core::ptr::read_volatile(p.add(1)), - core::ptr::read_volatile(p.add(2)), + core::ptr::read_volatile(p) as usize, + core::ptr::read_volatile(p.add(1)) as usize, + core::ptr::read_volatile(p.add(2)) as usize, ) }; let dma = DmaAddrs { - header_pa: hdr_pa, - header_va: REQ_HDR_VA, - status_pa, - status_va: REQ_HDR_VA + 16, - data_pa, - data_va: REQ_HDR_VA + 32, + header_pa: PhysicalAddress::from_raw(hdr_pa), + header_va: VirtualAddress::from_raw(REQ_HDR_VA), + status_pa: PhysicalAddress::from_raw(status_pa), + status_va: VirtualAddress::from_raw(REQ_HDR_VA + 16), + data_pa: PhysicalAddress::from_raw(data_pa), + data_va: VirtualAddress::from_raw(REQ_HDR_VA + 32), }; Self { mmio: UserMmio, queue, dma } diff --git a/crates/drivers/framebuffer/mock/Cargo.toml b/crates/drivers/framebuffer/mock/Cargo.toml index 26fe110..df8d689 100644 --- a/crates/drivers/framebuffer/mock/Cargo.toml +++ b/crates/drivers/framebuffer/mock/Cargo.toml @@ -5,3 +5,4 @@ edition = "2024" [dependencies] port-framebuffer = { workspace = true } +types = { workspace = true } diff --git a/crates/drivers/framebuffer/mock/src/lib.rs b/crates/drivers/framebuffer/mock/src/lib.rs index 2511143..2775ca3 100644 --- a/crates/drivers/framebuffer/mock/src/lib.rs +++ b/crates/drivers/framebuffer/mock/src/lib.rs @@ -1,21 +1,22 @@ #![no_std] use port_framebuffer::Framebuffer; +use types::display::{Color, Dimension, ScreenCoord}; pub struct MockFramebuffer { - width: u16, - height: u16, - pixels: [(u16, u16, u32); 4096], + width: Dimension, + height: Dimension, + pixels: [(ScreenCoord, ScreenCoord, Color); 4096], pixel_count: usize, flushed: bool, } impl MockFramebuffer { - pub fn new(width: u16, height: u16) -> Self { + pub fn new(width: Dimension, height: Dimension) -> Self { Self { width, height, - pixels: [(0, 0, 0); 4096], + pixels: [(ScreenCoord::new(0), ScreenCoord::new(0), Color::from_raw(0)); 4096], pixel_count: 0, flushed: false, } @@ -29,31 +30,31 @@ impl MockFramebuffer { 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] } } impl Framebuffer for MockFramebuffer { - fn width(&self) -> u16 { self.width } - fn height(&self) -> u16 { self.height } + fn width(&self) -> Dimension { self.width } + 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() { self.pixels[self.pixel_count] = (x, y, color); self.pixel_count += 1; } } - fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32) { - for dy in 0..h { - for dx in 0..w { - self.write_pixel(x + dx, y + dy, color); + fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: 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) { self.pixel_count = 0; } diff --git a/crates/drivers/framebuffer/virtio/Cargo.toml b/crates/drivers/framebuffer/virtio/Cargo.toml index bb8d5fe..14feaf9 100644 --- a/crates/drivers/framebuffer/virtio/Cargo.toml +++ b/crates/drivers/framebuffer/virtio/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] port-framebuffer = { workspace = true } hw-virtio = { workspace = true } +types = { workspace = true } diff --git a/crates/drivers/framebuffer/virtio/src/lib.rs b/crates/drivers/framebuffer/virtio/src/lib.rs index ada8977..5249aad 100644 --- a/crates/drivers/framebuffer/virtio/src/lib.rs +++ b/crates/drivers/framebuffer/virtio/src/lib.rs @@ -4,6 +4,8 @@ use hw_virtio::mmio::MmioAccess; use hw_virtio::queue::{QueueAddrs, VirtioQueue}; use hw_virtio::gpu::{self, GpuDmaAddrs}; use port_framebuffer::Framebuffer; +use types::address::{PhysicalAddress, VirtualAddress}; +use types::display::{Color, Dimension, ScreenCoord}; const GPU_MMIO_VA: usize = 0x20000; const VQUEUE_VA: usize = 0x21000; @@ -24,8 +26,8 @@ impl MmioAccess for GpuMmio { } struct PhysInfo { - cmd_pa: u64, - resp_pa: u64, + cmd_pa: PhysicalAddress, + resp_pa: PhysicalAddress, width: u16, height: u16, } @@ -34,8 +36,8 @@ fn read_phys_info() -> PhysInfo { unsafe { let p = PHYSINFO_VA as *const u64; PhysInfo { - cmd_pa: core::ptr::read_volatile(p), - resp_pa: core::ptr::read_volatile(p.add(1)), + cmd_pa: PhysicalAddress::from_raw(core::ptr::read_volatile(p) as usize), + resp_pa: PhysicalAddress::from_raw(core::ptr::read_volatile(p.add(1)) as usize), width: core::ptr::read_volatile(p.add(3)) as u16, height: core::ptr::read_volatile(p.add(4)) as u16, } @@ -46,50 +48,56 @@ pub struct VirtioFramebuffer { mmio: GpuMmio, queue: VirtioQueue, dma: GpuDmaAddrs, - width: u16, - height: u16, + width: Dimension, + height: Dimension, stride: usize, } impl VirtioFramebuffer { pub fn new() -> Self { 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; Self { mmio: GpuMmio, queue: VirtioQueue::new(QueueAddrs::from_base(VQUEUE_VA)), - dma: GpuDmaAddrs { cmd_pa: phys.cmd_pa, cmd_va: CMDBUF_VA, resp_pa: phys.resp_pa }, - width: phys.width, - height: phys.height, + dma: GpuDmaAddrs { cmd_pa: phys.cmd_pa, cmd_va: VirtualAddress::from_raw(CMDBUF_VA), resp_pa: phys.resp_pa }, + width, + height, stride, } } } impl Framebuffer for VirtioFramebuffer { - fn width(&self) -> u16 { self.width } - fn height(&self) -> u16 { self.height } + fn width(&self) -> Dimension { self.width } + fn height(&self) -> Dimension { self.height } - fn write_pixel(&mut self, x: u16, y: u16, color: u32) { - if x >= self.width || y >= self.height { return; } - let offset = (y as usize) * self.stride + (x as usize) * FB_BPP; - unsafe { core::ptr::write_volatile((FB_VA + offset) as *mut u32, color); } + fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color) { + if x.raw() >= self.width.raw() || y.raw() >= self.height.raw() { return; } + 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.raw()); } } - fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32) { - for dy in 0..h { for dx in 0..w { self.write_pixel(x + dx, y + dy, color); } } + fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: 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) { - let total = self.width as usize * self.height as usize; + fn clear(&mut self, color: Color) { + let total = self.width.raw() as usize * self.height.raw() as usize; 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) { - let w = self.width as u32; - let h = self.height as u32; + let w = self.width.raw() 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::resource_flush(&self.mmio, &self.queue, &self.dma, 1, 0, 0, w, h); } diff --git a/crates/hw-virtio/Cargo.toml b/crates/hw-virtio/Cargo.toml index 824735f..68a1251 100644 --- a/crates/hw-virtio/Cargo.toml +++ b/crates/hw-virtio/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +types = { workspace = true } diff --git a/crates/hw-virtio/src/block.rs b/crates/hw-virtio/src/block.rs index 5de4bda..d8dfb3a 100644 --- a/crates/hw-virtio/src/block.rs +++ b/crates/hw-virtio/src/block.rs @@ -1,5 +1,6 @@ use crate::mmio::MmioAccess; use crate::queue::{Descriptor, VirtioQueue}; +use types::address::{PhysicalAddress, VirtualAddress}; const SECTOR_SIZE: usize = 512; @@ -11,12 +12,12 @@ pub struct BlockReqHeader { } pub struct DmaAddrs { - pub header_pa: u64, - pub header_va: usize, - pub status_pa: u64, - pub status_va: usize, - pub data_pa: u64, - pub data_va: usize, + pub header_pa: PhysicalAddress, + pub header_va: VirtualAddress, + pub status_pa: PhysicalAddress, + pub status_va: VirtualAddress, + pub data_pa: PhysicalAddress, + pub data_va: VirtualAddress, } pub fn read_sector( @@ -29,28 +30,28 @@ pub fn read_sector( if buf.len() < SECTOR_SIZE { return false; } 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).reserved, 0); 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 = [ - Descriptor { addr: dma.header_pa, len: 16, writable: false }, - Descriptor { addr: dma.data_pa, len: SECTOR_SIZE as u32, writable: true }, - Descriptor { addr: dma.status_pa, len: 1, writable: true }, + Descriptor { addr: dma.header_pa.raw() as u64, len: 16, writable: false }, + Descriptor { addr: dma.data_pa.raw() as u64, len: SECTOR_SIZE as u32, writable: true }, + Descriptor { addr: dma.status_pa.raw() as u64, len: 1, writable: true }, ]; 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 dma.data_va != buf.as_ptr() as usize { + if dma.data_va.raw() != buf.as_ptr() as usize { unsafe { core::ptr::copy_nonoverlapping( - dma.data_va as *const u8, + dma.data_va.raw() as *const u8, buf.as_mut_ptr(), SECTOR_SIZE, ); diff --git a/crates/hw-virtio/src/gpu.rs b/crates/hw-virtio/src/gpu.rs index d96515d..95ebb1c 100644 --- a/crates/hw-virtio/src/gpu.rs +++ b/crates/hw-virtio/src/gpu.rs @@ -1,42 +1,44 @@ use crate::mmio::MmioAccess; use crate::queue::{Descriptor, VirtioQueue}; +use types::address::{PhysicalAddress, VirtualAddress}; +use types::display::Dimension; pub struct GpuDmaAddrs { - pub cmd_pa: u64, - pub cmd_va: usize, - pub resp_pa: u64, + pub cmd_pa: PhysicalAddress, + pub cmd_va: VirtualAddress, + 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); 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(28) as *mut u32, 1); // B8G8R8A8_UNORM - core::ptr::write_volatile(p.add(32) as *mut u32, width); - core::ptr::write_volatile(p.add(36) as *mut u32, height); + 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.raw() as u32); } 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); 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(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); } 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); unsafe { - let p = dma.cmd_va as *mut u8; - core::ptr::write_volatile(p.add(32) as *mut u32, width); - core::ptr::write_volatile(p.add(36) as *mut u32, height); + let p = dma.cmd_va.raw() as *mut u8; + 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.raw() as u32); core::ptr::write_volatile(p.add(40) as *mut u32, scanout_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) { write_cmd_header(dma.cmd_va, 0x0105); 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(28) as *mut u32, y); 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) { write_cmd_header(dma.cmd_va, 0x0106); 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(28) as *mut u32, y); 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); } -fn write_cmd_header(cmd_va: usize, cmd_type: u32) { +fn write_cmd_header(cmd_va: VirtualAddress, cmd_type: u32) { 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_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) { let descs = [ - Descriptor { addr: dma.cmd_pa, len: cmd_len, writable: false }, - Descriptor { addr: dma.resp_pa, len: 24, writable: true }, + Descriptor { addr: dma.cmd_pa.raw() as u64, len: cmd_len, writable: false }, + Descriptor { addr: dma.resp_pa.raw() as u64, len: 24, writable: true }, ]; queue.submit(mmio, &descs); } diff --git a/crates/init/src/lib.rs b/crates/init/src/lib.rs index 7282680..fd8f4ab 100644 --- a/crates/init/src/lib.rs +++ b/crates/init/src/lib.rs @@ -1,15 +1,18 @@ #![no_std] +use types::address::{EntryPoint, StackPointer, VirtualAddress}; +use types::bounded::{CapSlot, PageCount}; +use types::permission::{Permission, PermissionSet}; use userspace::syscall; const PAGE_SIZE: usize = 4096; 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 CMD_READ_FILE: usize = 1; -const CREATE_CAP: usize = 0; -const STORAGE_EP_CAP: usize = 2; +fn create_cap() -> CapSlot { CapSlot::new(0).unwrap() } +fn storage_ep() -> CapSlot { CapSlot::new(2).unwrap() } fn debug_print(s: &[u8]) { 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); } } - syscall::send(STORAGE_EP_CAP, CMD_READ_FILE, filename.len(), 0, 0); - let (file_size, _, _, _) = syscall::receive(STORAGE_EP_CAP); + syscall::send(storage_ep(), CMD_READ_FILE, filename.len(), 0, 0); + let (file_size, _, _, _) = syscall::receive(storage_ep()); file_size } struct LoadedProcess { - process_cap: usize, - entry_point: usize, + process_cap: CapSlot, + entry_point: EntryPoint, } fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option { @@ -65,11 +68,7 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option { Err(_) => return None, }; - let process_cap = syscall::create_process(CREATE_CAP); - if process_cap == usize::MAX { - debug_print(b"create_process failed\n"); - return None; - } + let process_cap = syscall::create_process(create_cap())?; for segment in elf_info.segments() { let page_start = segment.vaddr & !0xFFF; @@ -77,13 +76,10 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option { let total_size = offset_in_page + segment.mem_size; let seg_pages = (total_size + PAGE_SIZE - 1) / PAGE_SIZE; - let local_va = syscall::request_pages(seg_pages); - if local_va == usize::MAX { - debug_print(b"request_pages failed\n"); - return None; - } + let page_count = PageCount::new(seg_pages as u16)?; + let local_va = syscall::request_pages(page_count)?; - let local_ptr = local_va as *mut u8; + let local_ptr = local_va.raw() as *mut u8; unsafe { 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 { } for p in 0..seg_pages { - let src_page = local_va + p * PAGE_SIZE; - let dst_page = page_start + p * PAGE_SIZE; + let src_page = VirtualAddress::from_raw(local_va.raw() + 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); } } for i in 0..USER_STACK_PAGES { - let stack_va = syscall::request_pages(1); - if stack_va == usize::MAX { return None; } - let dst = USER_STACK_TOP - (USER_STACK_PAGES - i) * PAGE_SIZE; + let page_count = PageCount::new(1)?; + let stack_va = syscall::request_pages(page_count)?; + let dst = VirtualAddress::from_raw(USER_CODE_BASE - (USER_STACK_PAGES - i) * PAGE_SIZE); syscall::map_page(process_cap, stack_va, dst, false); } Some(LoadedProcess { 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], } -// display is loaded by the adapter (needs GPU MMIO access) const SERVERS: &[ServerInfo] = &[ ServerInfo { filename: b"input.elf", name: b"input" }, 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; 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"); + let ipc_perms = PermissionSet::empty() + .with(Permission::Read) + .with(Permission::Execute); + for server in SERVERS { debug_print(b"init: loading "); debug_print(server.name); @@ -156,13 +155,13 @@ pub fn run(shared_buf_va: usize) -> ! { } }; - let ep_cap = syscall::create_endpoint(); - let read_execute: usize = (1 << 0) | (1 << 2); - syscall::delegate(ep_cap, loaded.process_cap, read_execute); - syscall::spawn_thread_in(loaded.process_cap, loaded.entry_point, USER_STACK_TOP); + if let Some(ep_cap) = syscall::create_endpoint() { + syscall::delegate(ep_cap, loaded.process_cap, ipc_perms); + syscall::spawn_thread_in(loaded.process_cap, loaded.entry_point, USER_STACK_TOP); + } debug_print(b"ok (entry="); - debug_hex(loaded.entry_point); + debug_hex(loaded.entry_point.raw()); debug_print(b")\n"); } diff --git a/crates/ports/framebuffer/Cargo.toml b/crates/ports/framebuffer/Cargo.toml index 9d547a6..e365b21 100644 --- a/crates/ports/framebuffer/Cargo.toml +++ b/crates/ports/framebuffer/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +types = { workspace = true } diff --git a/crates/ports/framebuffer/src/lib.rs b/crates/ports/framebuffer/src/lib.rs index c79c048..2c66128 100644 --- a/crates/ports/framebuffer/src/lib.rs +++ b/crates/ports/framebuffer/src/lib.rs @@ -1,10 +1,12 @@ #![no_std] +use types::display::{Color, Dimension, ScreenCoord}; + pub trait Framebuffer { - fn width(&self) -> u16; - fn height(&self) -> u16; - fn write_pixel(&mut self, x: u16, y: u16, color: u32); - fn fill_rect(&mut self, x: u16, y: u16, w: u16, h: u16, color: u32); - fn clear(&mut self, color: u32); + fn width(&self) -> Dimension; + fn height(&self) -> Dimension; + fn write_pixel(&mut self, x: ScreenCoord, y: ScreenCoord, color: Color); + fn fill_rect(&mut self, x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color); + fn clear(&mut self, color: Color); fn flush(&mut self); } diff --git a/crates/server-framework/src/async_syscall/mod.rs b/crates/server-framework/src/async_syscall/mod.rs index eff4465..c9e90b8 100644 --- a/crates/server-framework/src/async_syscall/mod.rs +++ b/crates/server-framework/src/async_syscall/mod.rs @@ -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) } -pub async fn receive(endpoint: usize) -> (usize, usize, usize, usize) { +pub async fn receive(endpoint: CapSlot) -> (usize, usize, usize, usize) { userspace::syscall::receive(endpoint) } -pub async fn wait_for_interrupt(irq: usize) { +pub async fn wait_for_interrupt(_irq: CapSlot) { userspace::syscall::yield_now(); } -pub async fn acknowledge_interrupt(irq: usize) { - let _ = irq; +pub async fn acknowledge_interrupt(_irq: CapSlot) { } diff --git a/crates/server-framework/src/server/mod.rs b/crates/server-framework/src/server/mod.rs index 2c10ce2..0e02968 100644 --- a/crates/server-framework/src/server/mod.rs +++ b/crates/server-framework/src/server/mod.rs @@ -2,6 +2,7 @@ mod tests; use crate::codec::{Decode, Encode}; +use types::bounded::CapSlot; pub trait Server { type Request: Decode; @@ -9,7 +10,7 @@ pub trait Server { fn handle(&mut self, request: Self::Request) -> Self::Response; - fn run(&mut self, endpoint: usize) { + fn run(&mut self, endpoint: CapSlot) { loop { let words = userspace::syscall::receive(endpoint); 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(server: &mut S, endpoint: usize) { +pub fn serve(server: &mut S, endpoint: CapSlot) { server.run(endpoint); } diff --git a/crates/servers/display-server/src/protocol.rs b/crates/servers/display-server/src/protocol.rs index bc50326..700715d 100644 --- a/crates/servers/display-server/src/protocol.rs +++ b/crates/servers/display-server/src/protocol.rs @@ -1,9 +1,10 @@ use server_framework::{Decode, Encode}; +use types::display::{Color, Dimension, ScreenCoord}; #[derive(Debug, PartialEq)] pub enum DisplayRequest { - DrawRect { x: u16, y: u16, w: u16, h: u16, color: u32 }, - Clear { color: u32 }, + DrawRect { x: ScreenCoord, y: ScreenCoord, w: Dimension, h: Dimension, color: Color }, + Clear { color: Color }, Flush, GetDimensions, } @@ -11,7 +12,7 @@ pub enum DisplayRequest { #[derive(Debug, PartialEq)] pub enum DisplayResponse { Ok, - Dimensions { width: u16, height: u16 }, + Dimensions { width: Dimension, height: Dimension }, Error, } @@ -19,11 +20,11 @@ impl Encode for DisplayRequest { fn encode(&self) -> [usize; 4] { match self { DisplayRequest::DrawRect { x, y, w, h, color } => { - let xy = (*x as usize) | ((*y as usize) << 16); - let wh = (*w as usize) | ((*h as usize) << 16); - [0, xy, wh, *color as usize] + let xy = (x.raw() as usize) | ((y.raw() as usize) << 16); + let wh = (w.raw() as usize) | ((h.raw() as usize) << 16); + [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::GetDimensions => [3, 0, 0, 0], } @@ -34,14 +35,14 @@ impl Decode for DisplayRequest { fn decode(words: [usize; 4]) -> Option { match words[0] { 0 => { - let x = (words[1] & 0xFFFF) as u16; - let y = ((words[1] >> 16) & 0xFFFF) as u16; - let w = (words[2] & 0xFFFF) as u16; - let h = ((words[2] >> 16) & 0xFFFF) as u16; - let color = words[3] as u32; + let x = ScreenCoord::new((words[1] & 0xFFFF) as u16); + let y = ScreenCoord::new(((words[1] >> 16) & 0xFFFF) as u16); + let w = Dimension::new((words[2] & 0xFFFF) as u16); + let h = Dimension::new(((words[2] >> 16) & 0xFFFF) as u16); + let color = Color::from_raw(words[3] as u32); 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), 3 => Some(DisplayRequest::GetDimensions), _ => None, @@ -54,7 +55,7 @@ impl Encode for DisplayResponse { match self { DisplayResponse::Ok => [0, 0, 0, 0], 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], } @@ -66,8 +67,8 @@ impl Decode for DisplayResponse { match words[0] { 0 => Some(DisplayResponse::Ok), 1 => Some(DisplayResponse::Dimensions { - width: words[1] as u16, - height: words[2] as u16, + width: Dimension::new(words[1] as u16), + height: Dimension::new(words[2] as u16), }), 2 => Some(DisplayResponse::Error), _ => None, diff --git a/crates/servers/display-server/src/tests/protocol.rs b/crates/servers/display-server/src/tests/protocol.rs index fcb1c7d..1dd4e59 100644 --- a/crates/servers/display-server/src/tests/protocol.rs +++ b/crates/servers/display-server/src/tests/protocol.rs @@ -1,14 +1,15 @@ use crate::protocol::{DisplayRequest, DisplayResponse}; use server_framework::{Decode, Encode}; +use types::display::{Color, Dimension, ScreenCoord}; #[test] fn draw_rect_roundtrip() { let req = DisplayRequest::DrawRect { - x: 10, - y: 20, - w: 100, - h: 50, - color: 0xFF0000, + x: ScreenCoord::new(10), + y: ScreenCoord::new(20), + w: Dimension::new(100), + h: Dimension::new(50), + color: Color::from_raw(0xFF0000), }; let words = req.encode(); let decoded = DisplayRequest::decode(words).unwrap(); @@ -17,7 +18,7 @@ fn draw_rect_roundtrip() { #[test] fn clear_roundtrip() { - let req = DisplayRequest::Clear { color: 0x00FF00 }; + let req = DisplayRequest::Clear { color: Color::from_raw(0x00FF00) }; let words = req.encode(); let decoded = DisplayRequest::decode(words).unwrap(); assert_eq!(decoded, req); @@ -40,8 +41,8 @@ fn get_dimensions_roundtrip() { #[test] fn dimensions_response_roundtrip() { let resp = DisplayResponse::Dimensions { - width: 320, - height: 240, + width: Dimension::new(320), + height: Dimension::new(240), }; let words = resp.encode(); let decoded = DisplayResponse::decode(words).unwrap(); diff --git a/crates/servers/display-server/src/tests/server.rs b/crates/servers/display-server/src/tests/server.rs index 3d87eb9..63cac28 100644 --- a/crates/servers/display-server/src/tests/server.rs +++ b/crates/servers/display-server/src/tests/server.rs @@ -2,20 +2,21 @@ use driver_framebuffer_mock::MockFramebuffer; use crate::protocol::{DisplayRequest, DisplayResponse}; use crate::server::DisplayServer; use server_framework::Server; +use types::display::{Color, Dimension, ScreenCoord}; fn test_server() -> DisplayServer { - DisplayServer::new(MockFramebuffer::new(320, 240)) + DisplayServer::new(MockFramebuffer::new(Dimension::new(320), Dimension::new(240))) } #[test] fn draw_rect_writes_pixels() { let mut server = test_server(); let resp = server.handle(DisplayRequest::DrawRect { - x: 0, - y: 0, - w: 4, - h: 3, - color: 0xFF, + x: ScreenCoord::new(0), + y: ScreenCoord::new(0), + w: Dimension::new(4), + h: Dimension::new(3), + color: Color::from_raw(0xFF), }); assert_eq!(resp, DisplayResponse::Ok); assert_eq!(server.framebuffer().pixel_count(), 12); @@ -25,13 +26,13 @@ fn draw_rect_writes_pixels() { fn clear_resets_pixels() { let mut server = test_server(); server.handle(DisplayRequest::DrawRect { - x: 0, - y: 0, - w: 10, - h: 10, - color: 0xFF, + x: ScreenCoord::new(0), + y: ScreenCoord::new(0), + w: Dimension::new(10), + h: Dimension::new(10), + 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); } @@ -50,8 +51,8 @@ fn get_dimensions_returns_size() { assert_eq!( resp, DisplayResponse::Dimensions { - width: 320, - height: 240 + width: Dimension::new(320), + height: Dimension::new(240), } ); } @@ -60,16 +61,16 @@ fn get_dimensions_returns_size() { fn draw_rect_correct_pixel_positions() { let mut server = test_server(); server.handle(DisplayRequest::DrawRect { - x: 5, - y: 10, - w: 2, - h: 2, - color: 0xAB, + x: ScreenCoord::new(5), + y: ScreenCoord::new(10), + w: Dimension::new(2), + h: Dimension::new(2), + color: Color::from_raw(0xAB), }); let fb = server.framebuffer(); assert_eq!(fb.pixel_count(), 4); - assert_eq!(fb.pixel_at(0), (5, 10, 0xAB)); - assert_eq!(fb.pixel_at(1), (6, 10, 0xAB)); - assert_eq!(fb.pixel_at(2), (5, 11, 0xAB)); - assert_eq!(fb.pixel_at(3), (6, 11, 0xAB)); + assert_eq!(fb.pixel_at(0), (ScreenCoord::new(5), ScreenCoord::new(10), Color::from_raw(0xAB))); + assert_eq!(fb.pixel_at(1), (ScreenCoord::new(6), ScreenCoord::new(10), Color::from_raw(0xAB))); + assert_eq!(fb.pixel_at(2), (ScreenCoord::new(5), ScreenCoord::new(11), Color::from_raw(0xAB))); + assert_eq!(fb.pixel_at(3), (ScreenCoord::new(6), ScreenCoord::new(11), Color::from_raw(0xAB))); } diff --git a/crates/servers/input-server/src/lib.rs b/crates/servers/input-server/src/lib.rs index 4347493..d16f26d 100644 --- a/crates/servers/input-server/src/lib.rs +++ b/crates/servers/input-server/src/lib.rs @@ -16,6 +16,7 @@ pub fn run() -> ! { let device = adapters::mock::MockInputDevice::new(); 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(); } } diff --git a/crates/servers/log-server/src/lib.rs b/crates/servers/log-server/src/lib.rs index aef65c5..6a2873c 100644 --- a/crates/servers/log-server/src/lib.rs +++ b/crates/servers/log-server/src/lib.rs @@ -9,6 +9,7 @@ mod tests; pub fn run() -> ! { 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(); } } diff --git a/crates/servers/permission-manager/src/lib.rs b/crates/servers/permission-manager/src/lib.rs index 93f1df0..462d863 100644 --- a/crates/servers/permission-manager/src/lib.rs +++ b/crates/servers/permission-manager/src/lib.rs @@ -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(); } } diff --git a/crates/servers/permission-manager/src/protocol.rs b/crates/servers/permission-manager/src/protocol.rs index 3f387f7..541877f 100644 --- a/crates/servers/permission-manager/src/protocol.rs +++ b/crates/servers/permission-manager/src/protocol.rs @@ -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 { 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, } diff --git a/crates/servers/permission-manager/src/server.rs b/crates/servers/permission-manager/src/server.rs index f09e9cb..7f7d925 100644 --- a/crates/servers/permission-manager/src/server.rs +++ b/crates/servers/permission-manager/src/server.rs @@ -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); } diff --git a/crates/servers/permission-manager/src/tests/protocol.rs b/crates/servers/permission-manager/src/tests/protocol.rs index f0cd095..72dad7c 100644 --- a/crates/servers/permission-manager/src/tests/protocol.rs +++ b/crates/servers/permission-manager/src/tests/protocol.rs @@ -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)); } } diff --git a/crates/servers/permission-manager/src/tests/server.rs b/crates/servers/permission-manager/src/tests/server.rs index 4c7c1bd..c558829 100644 --- a/crates/servers/permission-manager/src/tests/server.rs +++ b/crates/servers/permission-manager/src/tests/server.rs @@ -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); diff --git a/crates/servers/session-server/src/lib.rs b/crates/servers/session-server/src/lib.rs index eb3426c..06de752 100644 --- a/crates/servers/session-server/src/lib.rs +++ b/crates/servers/session-server/src/lib.rs @@ -8,8 +8,10 @@ pub mod server; mod tests; 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"); - 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(); } } diff --git a/crates/servers/session-server/src/server.rs b/crates/servers/session-server/src/server.rs index 81a02e9..1a5700d 100644 --- a/crates/servers/session-server/src/server.rs +++ b/crates/servers/session-server/src/server.rs @@ -1,4 +1,6 @@ use server_framework::Server; +use types::bounded::CapSlot; +use types::id::ProcessId; use crate::protocol::{AppId, SessionRequest, SessionResponse}; @@ -14,7 +16,7 @@ pub struct AppEntry { #[derive(Clone, Copy)] struct RunningApp { app: AppId, - pid: u16, + pid: ProcessId, } pub struct SessionServer { @@ -22,21 +24,17 @@ pub struct SessionServer { app_count: usize, running: [Option; MAX_APPS], active: Option, - create_cap: usize, - display_cap: usize, - input_cap: usize, + create_cap: CapSlot, } impl SessionServer { - pub fn new(create_cap: usize, display_cap: usize, input_cap: usize) -> Self { + pub fn new(create_cap: CapSlot) -> Self { Self { apps: [const { None }; MAX_APPS], app_count: 0, running: [const { None }; MAX_APPS], active: None, create_cap, - display_cap, - input_cap, } } @@ -74,9 +72,13 @@ impl SessionServer { 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); SessionResponse::Launched { app } @@ -85,8 +87,7 @@ impl SessionServer { fn kill_app(&mut self, app: AppId) -> SessionResponse { let idx = app.raw() as usize; match self.running[idx].take() { - Some(running) => { - let _ = running.pid; + Some(_running) => { if self.active == Some(app) { self.active = None; } diff --git a/crates/servers/session-server/src/tests/server.rs b/crates/servers/session-server/src/tests/server.rs index 9e5033c..06cb882 100644 --- a/crates/servers/session-server/src/tests/server.rs +++ b/crates/servers/session-server/src/tests/server.rs @@ -3,7 +3,8 @@ use crate::server::SessionServer; use server_framework::Server; 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("clock", "/apps/clock.elf"); s diff --git a/crates/servers/storage-server/src/lib.rs b/crates/servers/storage-server/src/lib.rs index d453a23..ca383b9 100644 --- a/crates/servers/storage-server/src/lib.rs +++ b/crates/servers/storage-server/src/lib.rs @@ -38,7 +38,7 @@ pub fn run() -> ! { let mut fat16 = fat16.unwrap(); debug_print(b"storage: FAT16 mounted\n"); - let ep: usize = 0; + let ep = types::bounded::CapSlot::new(0).unwrap(); loop { let (w0, w1, _w2, _w3) = syscall::receive(ep); diff --git a/crates/types/src/display.rs b/crates/types/src/display.rs new file mode 100644 index 0000000..387567b --- /dev/null +++ b/crates/types/src/display.rs @@ -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 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 } +} diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 3bf7f23..2009857 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -2,6 +2,7 @@ pub mod address; pub mod bounded; +pub mod display; pub mod generation; pub mod id; pub mod macros; diff --git a/crates/types/src/permission.rs b/crates/types/src/permission.rs index ae19036..5d3acb0 100644 --- a/crates/types/src/permission.rs +++ b/crates/types/src/permission.rs @@ -44,4 +44,8 @@ impl PermissionSet { pub fn from_bits(bits: u8) -> Self { PermissionSet(bits) } + + pub fn bits(&self) -> u8 { + self.0 + } } diff --git a/crates/userspace/src/allocator/mod.rs b/crates/userspace/src/allocator/mod.rs index 2e1c0fa..2b5cd8a 100644 --- a/crates/userspace/src/allocator/mod.rs +++ b/crates/userspace/src/allocator/mod.rs @@ -47,14 +47,18 @@ impl AllocatorInner { return ptr::null_mut(); } - let page_addr = crate::syscall::request_pages(1); - if page_addr == usize::MAX { - return ptr::null_mut(); - } + let count = match types::bounded::PageCount::new(1) { + Some(c) => c, + 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; - page_addr as *mut u8 + va.raw() as *mut u8 } fn alloc_from_free_list(&mut self, size: usize, align: usize) -> *mut u8 { diff --git a/crates/userspace/src/syscall.rs b/crates/userspace/src/syscall.rs index 715fb17..1299eb6 100644 --- a/crates/userspace/src/syscall.rs +++ b/crates/userspace/src/syscall.rs @@ -1,5 +1,10 @@ use crate::arch; 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() -> ! { arch::syscall0(SYS_EXIT); @@ -15,63 +20,66 @@ pub fn yield_now() { 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() -> ! { arch::syscall0(SYS_HALT); loop {} } -pub fn send(endpoint: usize, w0: usize, w1: usize, w2: usize, w3: usize) -> usize { - arch::syscall5(SYS_SEND, endpoint, w0, w1, w2, w3) +pub fn get_time() -> Ticks { + Ticks::from_raw(arch::syscall0(SYS_GET_TIME) as u64) } -pub fn receive(endpoint: usize) -> (usize, usize, usize, usize) { - arch::syscall_receive(SYS_RECEIVE, endpoint) +pub fn get_process_id() -> ProcessId { + ProcessId::from_raw(arch::syscall0(SYS_GET_PROCESS_ID) as u16) } -pub fn create_endpoint() -> usize { - arch::syscall0(SYS_CREATE_ENDPOINT) +pub fn create_process(create_cap: CapSlot) -> Option { + 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 { + 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 { + 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) { 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) -}