feat(storage): full file protocol over per-client shared region (badged clients, owned handles, clamped lengths, ReadOnly on unwritable disk); init loads via libkos::fs; drop boot shared buffer
This commit is contained in:
@@ -13,19 +13,33 @@ pub mod server;
|
||||
mod tests;
|
||||
|
||||
use libkos::syscall;
|
||||
use types::address::VirtualAddress;
|
||||
use types::bounded::{CapSlot, PageCount};
|
||||
use types::mapping::PagePerms;
|
||||
|
||||
const CMD_READ_FILE: usize = 1;
|
||||
const SHARED_BUF_VA: usize = 0x30000;
|
||||
const SHARED_BUF_SIZE: usize = 64 * 1024;
|
||||
/// Client buffers sit high in storage's window, clear of its heap.
|
||||
const BUFFERS_VA: usize = 0x0100_0000;
|
||||
|
||||
fn shared_buf() -> &'static mut [u8] {
|
||||
unsafe { core::slice::from_raw_parts_mut(SHARED_BUF_VA as *mut u8, SHARED_BUF_SIZE) }
|
||||
/// Each client's buffer is a fresh region, mapped here and handed to the
|
||||
/// client, which maps the same pages in its own space.
|
||||
struct RegionBuffers;
|
||||
|
||||
impl server::Buffers for RegionBuffers {
|
||||
fn create(&mut self, client: usize) -> Option<(&'static mut [u8], Option<CapSlot>)> {
|
||||
let va = BUFFERS_VA + client * protocol::BUFFER_SIZE;
|
||||
let region = syscall::create_region(PageCount::new(protocol::BUFFER_PAGES as u16)?).ok()?;
|
||||
syscall::map_region(region, VirtualAddress::from_raw(va), PagePerms::ReadWrite).ok()?;
|
||||
// SAFETY: the region is mapped read-write at `va` for as long as
|
||||
// the server holds `region`, which it never drops.
|
||||
let buf = unsafe { core::slice::from_raw_parts_mut(va as *mut u8, protocol::BUFFER_SIZE) };
|
||||
Some((buf, Some(region)))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> ! {
|
||||
libkos::println!("storage: started");
|
||||
|
||||
let ep = types::bounded::CapSlot::new(0).unwrap();
|
||||
let ep = CapSlot::new(0).unwrap();
|
||||
// Init hands over the disk before asking for anything.
|
||||
let Some(device) = libkos::device::receive_device(ep)
|
||||
.mmio
|
||||
@@ -34,72 +48,11 @@ pub fn run() -> ! {
|
||||
libkos::println!("storage: no block device, exiting");
|
||||
syscall::exit();
|
||||
};
|
||||
let fat16 = fs::fat16::Fat16::mount(device);
|
||||
if fat16.is_none() {
|
||||
let Some(fat16) = fs::fat16::Fat16::mount(device) else {
|
||||
libkos::println!("storage: FAT16 mount failed, exiting");
|
||||
syscall::exit();
|
||||
}
|
||||
let mut fat16 = fat16.unwrap();
|
||||
libkos::println!("storage: FAT16 mounted");
|
||||
|
||||
|
||||
let mut next = syscall::receive_msg(ep);
|
||||
loop {
|
||||
let message = match next {
|
||||
Ok(m) => m,
|
||||
Err(e) => {
|
||||
libkos::println!("storage: endpoint unusable ({:?}), exiting", e);
|
||||
syscall::exit();
|
||||
}
|
||||
};
|
||||
let [w0, w1, _, _] = message.words();
|
||||
let reply = match w0 {
|
||||
CMD_READ_FILE => {
|
||||
let filename_len = w1;
|
||||
let buf = shared_buf();
|
||||
let filename_len = filename_len.min(buf.len());
|
||||
|
||||
let mut name_buf = [0u8; 32];
|
||||
let name_len = filename_len.min(32);
|
||||
name_buf[..name_len].copy_from_slice(&buf[..name_len]);
|
||||
|
||||
let name = core::str::from_utf8(&name_buf[..name_len]).unwrap_or("?");
|
||||
libkos::print!("storage: read {}...", name);
|
||||
|
||||
let file_size = read_entire_file(&mut fat16, &name_buf[..name_len], buf);
|
||||
|
||||
if file_size > 0 {
|
||||
libkos::println!("ok");
|
||||
} else {
|
||||
libkos::println!("NOT FOUND");
|
||||
}
|
||||
|
||||
[file_size, 0, 0, 0]
|
||||
}
|
||||
_ => [0, 0, 0, 0],
|
||||
};
|
||||
next = match message {
|
||||
syscall::Received::Call { .. } => syscall::reply_recv(ep, reply, None),
|
||||
_ => syscall::receive_msg(ep),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn read_entire_file<B: port_block_device::BlockDevice>(
|
||||
fat: &mut fs::fat16::Fat16<B>,
|
||||
filename: &[u8],
|
||||
out: &mut [u8],
|
||||
) -> usize {
|
||||
use filesystem::FileSystem;
|
||||
|
||||
let handle = match fat.open(filename) {
|
||||
Some(h) => h,
|
||||
None => return 0,
|
||||
};
|
||||
|
||||
let size = fat.file_size(handle).unwrap_or(0);
|
||||
let to_read = size.min(out.len());
|
||||
let read = fat.read(handle, &mut out[..to_read]).unwrap_or(0);
|
||||
fat.close(handle);
|
||||
read
|
||||
libkos::println!("storage: FAT16 mounted");
|
||||
let mut srv = server::StorageServer::new(fat16, RegionBuffers);
|
||||
server_framework::serve(&mut srv, ep)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user