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:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,6 @@ test = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
types = { workspace = true }
|
||||
userspace = { workspace = true }
|
||||
userspace-rt = { workspace = true }
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ test = false
|
||||
bench = false
|
||||
|
||||
[dependencies]
|
||||
types = { workspace = true }
|
||||
userspace-rt = { workspace = true }
|
||||
userspace = { workspace = true }
|
||||
server-framework = { workspace = true }
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
|
||||
@@ -6,3 +6,4 @@ edition = "2024"
|
||||
[dependencies]
|
||||
port-block-device = { workspace = true }
|
||||
hw-virtio = { workspace = true }
|
||||
types = { workspace = true }
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -5,3 +5,4 @@ edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
port-framebuffer = { workspace = true }
|
||||
types = { workspace = true }
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,3 +6,4 @@ edition = "2024"
|
||||
[dependencies]
|
||||
port-framebuffer = { workspace = true }
|
||||
hw-virtio = { workspace = true }
|
||||
types = { workspace = true }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -4,3 +4,4 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
types = { workspace = true }
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<LoadedProcess> {
|
||||
@@ -65,11 +68,7 @@ fn load_binary(shared_buf: *mut u8, filename: &[u8]) -> Option<LoadedProcess> {
|
||||
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<LoadedProcess> {
|
||||
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<LoadedProcess> {
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
@@ -4,3 +4,4 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
types = { workspace = true }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
}
|
||||
|
||||
@@ -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<S: Server>(server: &mut S, endpoint: usize) {
|
||||
pub fn serve<S: Server>(server: &mut S, endpoint: CapSlot) {
|
||||
server.run(endpoint);
|
||||
}
|
||||
|
||||
@@ -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<Self> {
|
||||
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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<MockFramebuffer> {
|
||||
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)));
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ impl CapabilityKind {
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PermissionRequest {
|
||||
RequestCapability { process: u16, kind: CapabilityKind },
|
||||
RevokeCapability { process: u16, kind: CapabilityKind },
|
||||
CheckCapability { process: u16, kind: CapabilityKind },
|
||||
ListGranted { process: u16 },
|
||||
RequestCapability { process: types::id::ProcessId, kind: CapabilityKind },
|
||||
RevokeCapability { process: types::id::ProcessId, kind: CapabilityKind },
|
||||
CheckCapability { process: types::id::ProcessId, kind: CapabilityKind },
|
||||
ListGranted { process: types::id::ProcessId },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
@@ -66,16 +66,16 @@ impl Encode for PermissionRequest {
|
||||
fn encode(&self) -> [usize; 4] {
|
||||
match self {
|
||||
PermissionRequest::RequestCapability { process, kind } => {
|
||||
[0, *process as usize, kind.index(), 0]
|
||||
[0, process.raw() as usize, kind.index(), 0]
|
||||
}
|
||||
PermissionRequest::RevokeCapability { process, kind } => {
|
||||
[1, *process as usize, kind.index(), 0]
|
||||
[1, process.raw() as usize, kind.index(), 0]
|
||||
}
|
||||
PermissionRequest::CheckCapability { process, kind } => {
|
||||
[2, *process as usize, kind.index(), 0]
|
||||
[2, process.raw() as usize, kind.index(), 0]
|
||||
}
|
||||
PermissionRequest::ListGranted { process } => {
|
||||
[3, *process as usize, 0, 0]
|
||||
[3, process.raw() as usize, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,19 +85,19 @@ impl Decode for PermissionRequest {
|
||||
fn decode(words: [usize; 4]) -> Option<Self> {
|
||||
match words[0] {
|
||||
0 => Some(PermissionRequest::RequestCapability {
|
||||
process: words[1] as u16,
|
||||
process: types::id::ProcessId::from_raw(words[1] as u16),
|
||||
kind: CapabilityKind::from_index(words[2])?,
|
||||
}),
|
||||
1 => Some(PermissionRequest::RevokeCapability {
|
||||
process: words[1] as u16,
|
||||
process: types::id::ProcessId::from_raw(words[1] as u16),
|
||||
kind: CapabilityKind::from_index(words[2])?,
|
||||
}),
|
||||
2 => Some(PermissionRequest::CheckCapability {
|
||||
process: words[1] as u16,
|
||||
process: types::id::ProcessId::from_raw(words[1] as u16),
|
||||
kind: CapabilityKind::from_index(words[2])?,
|
||||
}),
|
||||
3 => Some(PermissionRequest::ListGranted {
|
||||
process: words[1] as u16,
|
||||
process: types::id::ProcessId::from_raw(words[1] as u16),
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(); }
|
||||
}
|
||||
|
||||
@@ -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<RunningApp>; MAX_APPS],
|
||||
active: Option<AppId>,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
36
crates/types/src/display.rs
Normal file
36
crates/types/src/display.rs
Normal 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 }
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
pub mod address;
|
||||
pub mod bounded;
|
||||
pub mod display;
|
||||
pub mod generation;
|
||||
pub mod id;
|
||||
pub mod macros;
|
||||
|
||||
@@ -44,4 +44,8 @@ impl PermissionSet {
|
||||
pub fn from_bits(bits: u8) -> Self {
|
||||
PermissionSet(bits)
|
||||
}
|
||||
|
||||
pub fn bits(&self) -> u8 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<CapSlot> {
|
||||
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) {
|
||||
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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user