[VFS] Move victoria falls to rust. (Breaks voyageurs)

Move victoria falls to rust, which allows us to remove both the denali
and victoria falls C++ code. This disk driver appears to work properly
but has highlighted some instability in the voyageus xhci implementation
which now breaks.
This commit is contained in:
Drew Galbraith 2025-05-05 19:37:53 -07:00
parent f918966727
commit dc801786b1
37 changed files with 504 additions and 2065 deletions

1
rust/Cargo.lock generated
View File

@ -54,6 +54,7 @@ version = "0.1.0"
dependencies = [
"denali_client",
"mammoth",
"yellowstone-yunq",
]
[[package]]

View File

@ -1,31 +1,50 @@
use mammoth::{cap::Capability, zion::ZError};
use crate::{DenaliClient, DiskBlock, ReadRequest};
use crate::{DenaliClient, DiskBlock, ReadManyRequest, ReadRequest};
pub struct DiskReader {
client: DenaliClient,
disk_id: u64,
lba_offset: u64,
block_multiplier: u64,
}
impl DiskReader {
pub fn new(client: DenaliClient, disk_id: u64, lba_offset: u64) -> Self {
pub fn new(client: DenaliClient, disk_id: u64, lba_offset: u64, block_multiplier: u64) -> Self {
Self {
client,
disk_id,
lba_offset,
block_multiplier,
}
}
// TODO: Make yunq clients callable from a non-mutable reference so this can be called from
// shared ownership.
pub fn read(&mut self, lba: u64, cnt: u64) -> Result<Capability, ZError> {
let read_resp = self.client.read(&ReadRequest {
device_id: self.disk_id,
block: DiskBlock {
lba: self.lba_offset + lba,
size: cnt,
lba: self.lba_offset + (lba * self.block_multiplier),
size: cnt * self.block_multiplier,
},
})?;
Ok(Capability::take(read_resp.memory))
}
pub fn read_many(&mut self, blocks: &[DiskBlock]) -> Result<Capability, ZError> {
let read_resp = self.client.read_many(&ReadManyRequest {
device_id: self.disk_id,
blocks: blocks
.iter()
.map(|b| DiskBlock {
lba: self.lba_offset + (b.lba * self.block_multiplier),
size: b.size * self.block_multiplier,
})
.collect(),
})?;
Ok(Capability::take(read_resp.memory))
}
}

View File

@ -6,3 +6,4 @@ edition = "2024"
[dependencies]
denali_client = { path = "../../client/denali_client" }
mammoth = { path = "../../mammoth" }
yellowstone-yunq = { path = "../../yellowstone/" }

View File

@ -1,19 +1,284 @@
use denali_client::DiskReader;
use mammoth::mem::MemoryRegion;
use core::cmp::min;
use crate::types::Superblock;
use alloc::{collections::BTreeMap, string::String, vec::Vec};
use denali_client::{DenaliClient, DiskBlock, DiskReader, ReadRequest};
use mammoth::{cap::Capability, debug, mem::MemoryRegion, zion::ZError};
use yellowstone_yunq::DenaliInfo;
use crate::types::{BlockGroupDescriptor, DirEntry, Inode, Superblock};
pub struct FileInfo {
pub inode: u32,
pub name: String,
}
/// Ext2 Driver with the ability to read files and directories from the given disk.
///
/// Implementation based on the information available at
/// https://www.nongnu.org/ext2-doc/ext2.html
pub struct Ext2Driver {
reader: DiskReader,
superblock_region: MemoryRegion,
bgdt_region: MemoryRegion,
/// Cache of the memory regions for the inode tables available indexed by
/// the block_group number.
inode_table_map: Vec<Option<MemoryRegion>>,
/// Cache of inode_num to memory capability.
/// This is particularly important for directories so we
/// don't iterate over the disk each time.
inode_cache: BTreeMap<u32, Capability>,
}
impl Ext2Driver {
pub fn new(mut reader: DiskReader) -> Self {
let super_block_mem = MemoryRegion::from_cap(reader.read(2, 2).unwrap()).unwrap();
let super_block: &Superblock = super_block_mem.as_ref();
let inodes = super_block.inodes_count;
let magic = super_block.magic;
mammoth::debug!("Superblock ({:#x}): inodes: {:#x}", magic, inodes);
Self { reader }
pub fn new(denali_info: DenaliInfo) -> Self {
let mut client = DenaliClient::new(Capability::take(denali_info.denali_endpoint));
// Calculate the absolute offset and size of the superblock. It is located at
// offset 1024 of the partition and is 1024 bytes long. (Mostly extra
// reserved space).
// Ref: https://www.nongnu.org/ext2-doc/ext2.html#def-superblock
let abs_superblock_start = denali_info.lba_offset + 2;
let abs_superblock_size = 2; // TODO: This assumes 512 bytes sectors.
let superblock_region = MemoryRegion::from_cap(Capability::take(
client
.read(&ReadRequest {
device_id: denali_info.device_id,
block: DiskBlock {
lba: abs_superblock_start,
size: abs_superblock_size,
},
})
.unwrap()
.memory,
))
.unwrap();
let superblock: &Superblock = superblock_region.as_ref();
assert!(superblock.is_valid());
let mut reader = DiskReader::new(
client,
denali_info.device_id,
denali_info.lba_offset,
superblock.sectors_per_block(),
);
let bgdt_region = MemoryRegion::from_cap(
reader
.read(superblock.bgdt_block_num(), superblock.bgdt_block_size())
.unwrap(),
)
.unwrap();
let mut inode_table_map = Vec::new();
inode_table_map.resize_with(superblock.num_block_groups() as usize, || None);
Self {
reader,
superblock_region,
bgdt_region,
inode_table_map,
inode_cache: BTreeMap::new(),
}
}
fn superblock(&self) -> &Superblock {
self.superblock_region.as_ref()
}
fn bgdt(&self) -> &[BlockGroupDescriptor] {
self.bgdt_region.slice()
}
/// Updates the cached inode tables to contain the inode table for
/// a specific group.
fn populate_inode_table_if_none(&mut self, block_group_num: usize) {
if let None = self.inode_table_map[block_group_num] {
debug!(
"Cache MISS on inode table for block_group {}",
block_group_num
);
let inode_table = self.bgdt()[block_group_num].inode_table;
self.inode_table_map[block_group_num] = Some(
MemoryRegion::from_cap(
self.reader
.read(
inode_table as u64,
self.superblock().inode_table_block_size(),
)
.unwrap(),
)
.unwrap(),
);
} else {
debug!(
"Cache HIT on inode table for block_group {}",
block_group_num
);
}
}
pub fn get_inode(&mut self, inode_num: u32) -> Inode {
// See the following for a description of finding an inode.
// https://www.nongnu.org/ext2-doc/ext2.html#idm140660447281728
let block_group_num = (inode_num - 1) / self.superblock().inodes_per_group;
self.populate_inode_table_if_none(block_group_num as usize);
let region = self.inode_table_map[block_group_num as usize]
.as_ref()
.unwrap();
let local_index = (inode_num - 1) % self.superblock().inodes_per_group;
let offset = self.superblock().inode_size() * local_index as u64;
unsafe { region.raw_ptr_at_offset::<Inode>(offset).read().clone() }
}
fn get_blocks_from_single_indirect(&mut self, block_num: u64, num_blocks: usize) -> Vec<u32> {
assert!(num_blocks <= 256);
let single_indr_block_mem =
MemoryRegion::from_cap(self.reader.read(block_num, 1).unwrap()).unwrap();
single_indr_block_mem.slice()[..num_blocks].to_vec()
}
fn get_blocks_from_double_indirect(&mut self, block_num: u64, num_blocks: usize) -> Vec<u32> {
assert!(num_blocks > 0 && num_blocks <= (256 * 256));
let num_dbl_indr = ((num_blocks - 1) / 256) + 1;
let dbl_indr_block_mem =
MemoryRegion::from_cap(self.reader.read(block_num, 1).unwrap()).unwrap();
let dbl_indr_blocks: &[u32] = dbl_indr_block_mem.slice();
let mut blocks_to_read = Vec::new();
for i in 0..num_dbl_indr {
let num_blocks_in_single = min(num_blocks - (256 * i), 256);
blocks_to_read.append(
&mut self.get_blocks_from_single_indirect(
dbl_indr_blocks[i] as u64,
num_blocks_in_single,
),
);
}
blocks_to_read
}
fn run_len_compress_blocks(&self, blocks: Vec<u32>) -> Vec<DiskBlock> {
let mut curr_block = DiskBlock {
lba: blocks[0] as u64,
size: 1,
};
let mut iter = blocks.into_iter();
iter.next();
let mut blocks = Vec::new();
while let Some(block) = iter.next() {
if block as u64 == (curr_block.lba + curr_block.size) {
curr_block.size += 1;
} else {
blocks.push(curr_block.clone());
curr_block.lba = block as u64;
curr_block.size = 1;
}
}
blocks.push(curr_block);
blocks
}
fn read_inode(&mut self, _inode_num: u32, inode: Inode) -> Result<Capability, ZError> {
// TODO: Cache this method using _inode_num
// TODO: This assumes 512 byte sectors.
let real_block_cnt = (inode.blocks as u64 - 1) / (self.superblock().block_size() / 512) + 1;
if inode.block[14] != 0 {
debug!("Can't handle triply indirect inodes yet.");
return Err(ZError::UNIMPLEMENTED);
}
let mut blocks_to_read = Vec::new();
for i in 0..min(12, real_block_cnt) {
blocks_to_read.push(inode.block[i as usize])
}
// Singly indirect block.
if inode.block[12] != 0 {
let num_blocks = min(256, real_block_cnt - 12) as usize;
blocks_to_read.append(
&mut self.get_blocks_from_single_indirect(inode.block[12] as u64, num_blocks),
);
}
// Doubly indirect block.
if inode.block[13] != 0 {
let num_blocks = min(256 * 256, real_block_cnt - 268) as usize;
blocks_to_read.append(
&mut self.get_blocks_from_double_indirect(inode.block[13] as u64, num_blocks),
);
};
self.reader
.read_many(&self.run_len_compress_blocks(blocks_to_read))
}
fn read_inode_into_mem(
&mut self,
inode_num: u32,
inode: Inode,
) -> Result<MemoryRegion, ZError> {
if !self.inode_cache.contains_key(&inode_num) {
debug!("Cache MISS for inode_num: {}", inode_num);
let inode_cap = self.read_inode(inode_num, inode)?;
self.inode_cache.insert(inode_num, inode_cap);
} else {
debug!("Cache HIT for inode_num: {}", inode_num);
}
MemoryRegion::from_cap(self.inode_cache[&inode_num].duplicate(Capability::PERMS_ALL)?)
}
pub fn read_file(&mut self, inode_num: u32) -> Result<Capability, ZError> {
let inode = self.get_inode(inode_num);
if (inode.mode & 0x8000) == 0 {
debug!("Reading non file.");
return Err(ZError::INVALID_ARGUMENT);
}
self.read_inode(inode_num, inode)
}
pub fn read_directory(&mut self, inode_num: u32) -> Result<Vec<FileInfo>, ZError> {
let inode = self.get_inode(inode_num);
if (inode.mode & 0x4000) == 0 {
let mode = inode.mode;
debug!("Reading non directory. Inode {:?}, Mode {}", inode, mode);
return Err(ZError::INVALID_ARGUMENT);
}
let dir = self.read_inode_into_mem(inode_num, inode)?;
let mut file_names = Vec::new();
let mut offset = 0;
while offset < dir.size() {
let dir_ptr: DirEntry = unsafe { dir.raw_ptr_at_offset::<DirEntry>(offset).read() };
let name = dir_ptr.name;
let file_name: String =
String::from_utf8(name[..dir_ptr.name_len as usize].to_vec()).unwrap();
file_names.push(FileInfo {
inode: dir_ptr.inode,
name: file_name,
});
offset += dir_ptr.record_length as u64;
}
Ok(file_names)
}
}

View File

@ -1,3 +1,5 @@
/// Superblock structure.
/// https://www.nongnu.org/ext2-doc/ext2.html#superblock
#[repr(C, packed)]
pub struct Superblock {
pub inodes_count: u32,
@ -28,3 +30,95 @@ pub struct Superblock {
pub first_ino: u32,
pub inode_size: u16,
}
impl Superblock {
pub fn is_valid(&self) -> bool {
self.magic == 0xEF53
}
pub fn sectors_per_block(&self) -> u64 {
1 << (self.log_block_size + 1)
}
pub fn block_size(&self) -> u64 {
1024 << self.log_block_size
}
pub fn bgdt_block_num(&self) -> u64 {
if self.block_size() == 1024 { 2 } else { 1 }
}
pub fn bgdt_block_size(&self) -> u64 {
(self.num_block_groups() * (size_of::<BlockGroupDescriptor>() as u64) - 1)
/ self.block_size()
+ 1
}
pub fn num_block_groups(&self) -> u64 {
(((self.blocks_count - 1) / self.blocks_per_group) + 1) as u64
}
pub fn inode_size(&self) -> u64 {
if self.rev_level >= 1 {
self.inode_size as u64
} else {
const DEFAULT_INODE_SIZE: u64 = 0x80;
DEFAULT_INODE_SIZE
}
}
pub fn inode_table_block_size(&self) -> u64 {
(self.inode_size() * self.inodes_per_group as u64) / self.block_size()
}
}
#[repr(C, packed)]
#[derive(Debug)]
pub struct BlockGroupDescriptor {
pub block_bitmap: u32,
pub inode_bitmap: u32,
pub inode_table: u32,
pub free_blocks_count: u16,
pub free_inodes_count: u16,
pub used_dirs_count: u16,
reserved: [u8; 14],
}
const _: () = assert!(size_of::<BlockGroupDescriptor>() == 32);
#[repr(C, packed)]
#[derive(Clone, Debug)]
pub struct Inode {
pub mode: u16,
pub uid: u16,
pub size: u32,
pub atime: u32,
pub ctime: u32,
pub mtime: u32,
pub dtime: u32,
pub gid: u16,
pub links_count: u16,
pub blocks: u32,
pub flags: u32,
pub osd1: u32,
pub block: [u32; 15],
pub generation: u32,
pub file_acl: u32,
pub dir_acl: u32,
pub faddr: u32,
pub osd2: [u32; 3],
}
const _: () = assert!(size_of::<Inode>() == 128);
pub const EXT2_FT_FILE: u8 = 0x1;
pub const EXT2_FT_DIR: u8 = 0x2;
#[repr(C, packed)]
pub struct DirEntry {
pub inode: u32,
pub record_length: u16,
pub name_len: u8,
pub file_type: u8,
pub name: [u8; 256],
}

View File

@ -94,10 +94,21 @@ impl MemoryRegion {
}
}
pub fn raw_ptr_at_offset<T>(&self, offset: u64) -> *const T {
// TODO: Come up with a better safety check here.
// We can't use the size of T because it might not be sized.
assert!(offset + size_of::<T>() as u64 <= self.size);
(self.virt_addr + offset) as *const T
}
pub fn cap(&self) -> &Capability {
&self.mem_cap
}
pub fn size(&self) -> u64 {
self.size
}
pub fn duplicate(&self, offset: u64, length: u64) -> Result<Capability, ZError> {
syscall::memory_obj_duplicate(&self.mem_cap, offset, length)
}

View File

@ -1,9 +1,12 @@
#![no_std]
#![no_main]
use denali_client::{DenaliClient, DiskReader};
use ext2::Ext2Driver;
use mammoth::{cap::Capability, define_entry, zion::z_err_t};
use mammoth::{define_entry, zion::z_err_t};
use victoriafalls::{server::VictoriaFallsServerImpl, VFSServer};
use yellowstone_yunq::RegisterEndpointRequest;
use yunq::server::spawn_server_thread;
use yunq::server::YunqServer;
define_entry!();
@ -12,13 +15,21 @@ extern "C" fn main() -> z_err_t {
let yellowstone = yellowstone_yunq::from_init_endpoint();
let denali_info = yellowstone.get_denali().unwrap();
let client = DenaliClient::new(Capability::take(denali_info.denali_endpoint));
let driver = Ext2Driver::new(DiskReader::new(
client,
denali_info.device_id,
denali_info.lba_offset,
));
let driver = Ext2Driver::new(denali_info);
let vfs_server = VFSServer::new(VictoriaFallsServerImpl::new(driver)).unwrap();
let yellowstone = yellowstone_yunq::from_init_endpoint();
yellowstone
.register_endpoint(&RegisterEndpointRequest {
endpoint_name: "victoriafalls".into(),
endpoint_capability: vfs_server.create_client_cap().unwrap().release(),
})
.unwrap();
let server_thread = spawn_server_thread(vfs_server);
server_thread.join().unwrap();
0
}

View File

@ -6,6 +6,7 @@ include!(concat!(env!("OUT_DIR"), "/yunq.rs"));
pub mod dir;
pub mod file;
pub mod server;
static mut VFS_CLIENT: Option<VFSClient> = None;

View File

@ -0,0 +1,75 @@
use alloc::{string::String, vec::Vec};
use ext2::Ext2Driver;
use mammoth::{debug, zion::ZError};
use crate::{Directory, GetDirectoryRequest, OpenFileRequest, OpenFileResponse, VFSServerHandler};
pub struct VictoriaFallsServerImpl {
ext2_driver: Ext2Driver,
}
impl VictoriaFallsServerImpl {
pub fn new(ext2_driver: Ext2Driver) -> Self {
VictoriaFallsServerImpl { ext2_driver }
}
fn find_path_in_dir(&mut self, inode_num: u32, file_name: &str) -> Result<u32, ZError> {
let files = self.ext2_driver.read_directory(inode_num)?;
files
.iter()
.find(|fi| fi.name == file_name)
.map(|fi| fi.inode)
.ok_or(ZError::NOT_FOUND)
}
}
impl VFSServerHandler for VictoriaFallsServerImpl {
fn open_file(&mut self, req: OpenFileRequest) -> Result<OpenFileResponse, ZError> {
debug!("Reading {}", req.path);
let mut tokens = req.path.split('/');
if tokens.next() != Some("") {
debug!("Path must be absolute");
return Err(ZError::INVALID_ARGUMENT);
}
let mut inode_num = 2; // Start with root.
while let Some(path_token) = tokens.next() {
inode_num = self.find_path_in_dir(inode_num, path_token)?;
}
let inode = self.ext2_driver.get_inode(inode_num);
Ok(OpenFileResponse {
path: req.path,
memory: self.ext2_driver.read_file(inode_num)?.release(),
size: inode.size as u64,
})
}
fn get_directory(&mut self, req: GetDirectoryRequest) -> Result<Directory, ZError> {
debug!("Reading dir {}", req.path);
let mut tokens = req.path.split('/');
if tokens.next() != Some("") {
debug!("Path must be absolute");
return Err(ZError::INVALID_ARGUMENT);
}
let mut inode_num = 2; // Start with root.
while let Some(path_token) = tokens.next() {
inode_num = self.find_path_in_dir(inode_num, path_token)?;
}
let files: Vec<String> = self
.ext2_driver
.read_directory(inode_num)?
.into_iter()
.map(|fi| fi.name)
.collect();
Ok(Directory {
filenames: files.join(","),
})
}
}

View File

@ -41,7 +41,7 @@ cp zion/zion efi/
mkdir -p efi/sys
cp ../sysroot/bin/yellowstone efi/sys/yellowstone
cp ../sysroot/bin/denali efi/sys/denali
cp sys/victoriafalls/victoriafalls efi/sys/victoriafalls
cp ../sysroot/bin/victoriafalls efi/sys/victoriafalls
mkdir -p sysroot
mount "${dev}p2" sysroot/

View File

@ -1 +0,0 @@
yunq_gen(lib/denali lib denali)

View File

@ -1,27 +0,0 @@
interface Denali {
method Read(ReadRequest) -> (ReadResponse);
method ReadMany(ReadManyRequest) -> (ReadResponse);
}
message DiskBlock {
u64 lba;
u64 size;
}
message ReadRequest {
u64 device_id;
DiskBlock block;
}
message ReadManyRequest {
u64 device_id;
repeated DiskBlock blocks;
}
message ReadResponse {
u64 device_id;
u64 size;
capability memory;
}

View File

@ -1,100 +0,0 @@
// Generated file - DO NOT MODIFY
#include "denali.yunq.client.h"
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <mammoth/util/debug.h>
#include <zcall.h>
DenaliClient::~DenaliClient() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
glcr::Status DenaliClient::Read(const ReadRequest& request, ReadResponse& response) {
uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize;
const uint32_t kSentinel = 0xBEEFDEAD;
buffer_.WriteAt<uint32_t>(0, kSentinel);
buffer_.WriteAt<uint64_t>(8, 0);
cap_buffer_.Reset();
uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_);
buffer_.WriteAt<uint32_t>(4, 16 + length);
z_cap_t reply_port_cap;
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap));
// FIXME: Add a way to zero out the first buffer.
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr()));
if (buffer_.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidResponse("Got an invalid response from server.");
}
// Check Response Code.
RET_ERR(buffer_.At<uint64_t>(8));
yunq::MessageView resp_view(buffer_, 16);
RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_));
return glcr::OK;
}
glcr::Status DenaliClient::ReadMany(const ReadManyRequest& request, ReadResponse& response) {
uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize;
const uint32_t kSentinel = 0xBEEFDEAD;
buffer_.WriteAt<uint32_t>(0, kSentinel);
buffer_.WriteAt<uint64_t>(8, 1);
cap_buffer_.Reset();
uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_);
buffer_.WriteAt<uint32_t>(4, 16 + length);
z_cap_t reply_port_cap;
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap));
// FIXME: Add a way to zero out the first buffer.
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr()));
if (buffer_.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidResponse("Got an invalid response from server.");
}
// Check Response Code.
RET_ERR(buffer_.At<uint64_t>(8));
yunq::MessageView resp_view(buffer_, 16);
RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_));
return glcr::OK;
}

View File

@ -1,37 +0,0 @@
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/status/error.h>
#include <ztypes.h>
#include "denali.yunq.h"
class DenaliClient {
public:
DenaliClient(z_cap_t Denali_cap) : endpoint_(Denali_cap) {}
DenaliClient(const DenaliClient&) = delete;
DenaliClient(DenaliClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;};
~DenaliClient();
z_cap_t Capability() { return endpoint_; }
[[nodiscard]] glcr::Status Read(const ReadRequest& request, ReadResponse& response);
[[nodiscard]] glcr::Status ReadMany(const ReadManyRequest& request, ReadResponse& response);
private:
z_cap_t endpoint_;
uint64_t kBufferSize = 0x1000;
glcr::ByteBuffer buffer_{kBufferSize};
uint64_t kCapBufferSize = 0x10;
glcr::CapBuffer cap_buffer_{kCapBufferSize};
};

View File

@ -1,186 +0,0 @@
// Generated file -- DO NOT MODIFY.
#include "denali.yunq.h"
#include <yunq/message_view.h>
#include <yunq/serialize.h>
namespace {
const uint64_t header_size = 24; // 4x uint32, 1x uint64
struct ExtPointer {
uint32_t offset;
uint32_t length;
};
} // namespace
glcr::Status DiskBlock::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status DiskBlock::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status DiskBlock::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse lba.
ASSIGN_OR_RETURN(lba_, message.ReadField<uint64_t>(0));
// Parse size.
ASSIGN_OR_RETURN(size_, message.ReadField<uint64_t>(1));
return glcr::Status::Ok();
}
uint64_t DiskBlock::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 2);
return SerializeInternal(serializer);
}
uint64_t DiskBlock::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 2, caps);
return SerializeInternal(serializer);
}
uint64_t DiskBlock::SerializeInternal(yunq::Serializer& serializer) const {
// Write lba.
serializer.WriteField<uint64_t>(0, lba_);
// Write size.
serializer.WriteField<uint64_t>(1, size_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status ReadRequest::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status ReadRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status ReadRequest::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse device_id.
ASSIGN_OR_RETURN(device_id_, message.ReadField<uint64_t>(0));
// Parse block.
message.ReadMessage<DiskBlock>(1, block_);
return glcr::Status::Ok();
}
uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 2);
return SerializeInternal(serializer);
}
uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 2, caps);
return SerializeInternal(serializer);
}
uint64_t ReadRequest::SerializeInternal(yunq::Serializer& serializer) const {
// Write device_id.
serializer.WriteField<uint64_t>(0, device_id_);
// Write block.
serializer.WriteMessage<DiskBlock>(1, block_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status ReadManyRequest::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status ReadManyRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status ReadManyRequest::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse device_id.
ASSIGN_OR_RETURN(device_id_, message.ReadField<uint64_t>(0));
// Parse blocks.
message.ReadRepeatedMessage<DiskBlock>(1, blocks_);
return glcr::Status::Ok();
}
uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 2);
return SerializeInternal(serializer);
}
uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 2, caps);
return SerializeInternal(serializer);
}
uint64_t ReadManyRequest::SerializeInternal(yunq::Serializer& serializer) const {
// Write device_id.
serializer.WriteField<uint64_t>(0, device_id_);
// Write blocks.
serializer.WriteRepeatedMessage<DiskBlock>(1, blocks_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status ReadResponse::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
// Parse memory.
ASSIGN_OR_RETURN(memory_, message.ReadCapability(2));
return glcr::Status::Ok();
}
glcr::Status ReadResponse::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
// Parse memory.
ASSIGN_OR_RETURN(memory_, message.ReadCapability(2, caps));
return glcr::Status::Ok();
}
glcr::Status ReadResponse::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse device_id.
ASSIGN_OR_RETURN(device_id_, message.ReadField<uint64_t>(0));
// Parse size.
ASSIGN_OR_RETURN(size_, message.ReadField<uint64_t>(1));
// Parse memory.
return glcr::Status::Ok();
}
uint64_t ReadResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 3);
return SerializeInternal(serializer);
}
uint64_t ReadResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 3, caps);
return SerializeInternal(serializer);
}
uint64_t ReadResponse::SerializeInternal(yunq::Serializer& serializer) const {
// Write device_id.
serializer.WriteField<uint64_t>(0, device_id_);
// Write size.
serializer.WriteField<uint64_t>(1, size_);
// Write memory.
serializer.WriteCapability(2, memory_);
serializer.WriteHeader();
return serializer.size();
}

View File

@ -1,138 +0,0 @@
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/status/status.h>
#include <glacier/container/vector.h>
#include <glacier/string/string.h>
#include <yunq/message_view.h>
#include <yunq/serialize.h>
#include <ztypes.h>
class DiskBlock {
public:
DiskBlock() {}
// Delete copy and move until implemented.
DiskBlock(const DiskBlock&) = delete;
DiskBlock(DiskBlock&&) = default;
DiskBlock& operator=(DiskBlock&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const uint64_t& lba() const { return lba_; }
uint64_t& mutable_lba() { return lba_; }
void set_lba(const uint64_t& value) { lba_ = value; }
const uint64_t& size() const { return size_; }
uint64_t& mutable_size() { return size_; }
void set_size(const uint64_t& value) { size_ = value; }
private:
uint64_t lba_;
uint64_t size_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class ReadRequest {
public:
ReadRequest() {}
// Delete copy and move until implemented.
ReadRequest(const ReadRequest&) = delete;
ReadRequest(ReadRequest&&) = default;
ReadRequest& operator=(ReadRequest&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const uint64_t& device_id() const { return device_id_; }
uint64_t& mutable_device_id() { return device_id_; }
void set_device_id(const uint64_t& value) { device_id_ = value; }
const DiskBlock& block() const { return block_; }
DiskBlock& mutable_block() { return block_; }
private:
uint64_t device_id_;
DiskBlock block_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class ReadManyRequest {
public:
ReadManyRequest() {}
// Delete copy and move until implemented.
ReadManyRequest(const ReadManyRequest&) = delete;
ReadManyRequest(ReadManyRequest&&) = default;
ReadManyRequest& operator=(ReadManyRequest&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const uint64_t& device_id() const { return device_id_; }
uint64_t& mutable_device_id() { return device_id_; }
void set_device_id(const uint64_t& value) { device_id_ = value; }
const glcr::Vector<DiskBlock>& blocks() const { return blocks_; }
glcr::Vector<DiskBlock>& mutable_blocks() { return blocks_; }
void add_blocks(DiskBlock&& value) { blocks_.PushBack(glcr::Move(value)); }
private:
uint64_t device_id_;
glcr::Vector<DiskBlock> blocks_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class ReadResponse {
public:
ReadResponse() {}
// Delete copy and move until implemented.
ReadResponse(const ReadResponse&) = delete;
ReadResponse(ReadResponse&&) = default;
ReadResponse& operator=(ReadResponse&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const uint64_t& device_id() const { return device_id_; }
uint64_t& mutable_device_id() { return device_id_; }
void set_device_id(const uint64_t& value) { device_id_ = value; }
const uint64_t& size() const { return size_; }
uint64_t& mutable_size() { return size_; }
void set_size(const uint64_t& value) { size_ = value; }
const z_cap_t& memory() const { return memory_; }
z_cap_t& mutable_memory() { return memory_; }
void set_memory(const z_cap_t& value) { memory_ = value; }
private:
uint64_t device_id_;
uint64_t size_;
z_cap_t memory_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};

View File

@ -1,152 +0,0 @@
// Generated file -- DO NOT MODIFY.
#include "denali.yunq.server.h"
#include <mammoth/util/debug.h>
#include <zcall.h>
namespace {
const uint32_t kSentinel = 0xBEEFDEAD;
const uint32_t kHeaderSize = 0x10;
void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) {
buffer.WriteAt<uint32_t>(0, kSentinel);
buffer.WriteAt<uint32_t>(4, kHeaderSize);
buffer.WriteAt<uint64_t>(8, err);
}
void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) {
buffer.WriteAt<uint32_t>(0, kSentinel);
buffer.WriteAt<uint32_t>(4, kHeaderSize + message_length);
buffer.WriteAt<uint64_t>(8, glcr::OK);
}
} // namespace
void DenaliServerBaseThreadBootstrap(void* server_base) {
((DenaliServerBase*)server_base)->ServerThread();
}
DenaliServerBase::~DenaliServerBase() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
glcr::ErrorOr<z_cap_t> DenaliServerBase::CreateClientCap() {
uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
return client_cap;
}
glcr::ErrorOr<DenaliClient> DenaliServerBase::CreateClient() {
uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
return DenaliClient(client_cap);
}
Thread DenaliServerBase::RunServer() {
return Thread(DenaliServerBaseThreadBootstrap, this);
}
void DenaliServerBase::ServerThread() {
glcr::ByteBuffer recv_buffer(0x1000);
glcr::CapBuffer recv_cap(0x10);
glcr::ByteBuffer resp_buffer(0x1000);
glcr::CapBuffer resp_cap(0x10);
z_cap_t reply_port_cap;
while (true) {
uint64_t recv_cap_size = 0x10;
uint64_t recv_buf_size = 0x1000;
recv_cap.Reset();
glcr::ErrorCode recv_err = static_cast<glcr::ErrorCode>(ZEndpointRecv(endpoint_, &recv_buf_size, recv_buffer.RawPtr(), &recv_cap_size, recv_cap.RawPtr(), &reply_port_cap));
if (recv_err != glcr::OK) {
dbgln("Error in receive: {x}", recv_err);
continue;
}
uint64_t resp_length = 0;
glcr::ErrorCode reply_err = glcr::OK;
resp_cap.Reset();
glcr::Status err = HandleRequest(recv_buffer, recv_cap, resp_buffer, resp_length, resp_cap);
if (!err) {
WriteError(resp_buffer, err.code());
dbgln("Responding Error {}", err.message());
reply_err = static_cast<glcr::ErrorCode>(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr));
} else {
WriteHeader(resp_buffer, resp_length);
reply_err = static_cast<glcr::ErrorCode>(ZReplyPortSend(reply_port_cap, kHeaderSize + resp_length, resp_buffer.RawPtr(), resp_cap.UsedSlots(), resp_cap.RawPtr()));
}
if (reply_err != glcr::OK) {
dbgln("Error in reply: {x}", reply_err);
}
}
}
glcr::Status DenaliServerBase::HandleRequest(const glcr::ByteBuffer& request,
const glcr::CapBuffer& req_caps,
glcr::ByteBuffer& response, uint64_t& resp_length,
glcr::CapBuffer& resp_caps) {
if (request.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidArgument("Request Not Valid");
}
uint64_t method_select = request.At<uint64_t>(8);
switch(method_select) {
case 0: {
ReadRequest yunq_request;
yunq::MessageView request_view(request, kHeaderSize);
RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps));
ReadResponse yunq_response;
RETURN_ERROR(HandleRead(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
case 1: {
ReadManyRequest yunq_request;
yunq::MessageView request_view(request, kHeaderSize);
RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps));
ReadResponse yunq_response;
RETURN_ERROR(HandleReadMany(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
default: {
return glcr::Unimplemented("Method unimplemented by server.");
}
}
return glcr::Status::Ok();
}

View File

@ -1,50 +0,0 @@
// Generated File -- DO NOT MODIFY.
#pragma once
#include <glacier/status/error_or.h>
#include <glacier/status/status.h>
#include <mammoth/proc/thread.h>
#include <ztypes.h>
#include "denali.yunq.h"
#include "denali.yunq.client.h"
class DenaliServerBase {
public:
DenaliServerBase(z_cap_t Denali_cap) : endpoint_(Denali_cap) {}
DenaliServerBase(const DenaliServerBase&) = delete;
DenaliServerBase(DenaliServerBase&&) = delete;
virtual ~DenaliServerBase();
glcr::ErrorOr<z_cap_t> CreateClientCap();
glcr::ErrorOr<DenaliClient> CreateClient();
[[nodiscard]] Thread RunServer();
[[nodiscard]] virtual glcr::Status HandleRead(const ReadRequest&, ReadResponse&) = 0;
[[nodiscard]] virtual glcr::Status HandleReadMany(const ReadManyRequest&, ReadResponse&) = 0;
private:
z_cap_t endpoint_;
friend void DenaliServerBaseThreadBootstrap(void*);
void ServerThread();
[[nodiscard]] glcr::Status HandleRequest(const glcr::ByteBuffer& request, const glcr::CapBuffer& req_caps,
glcr::ByteBuffer& response, uint64_t& resp_length,
glcr::CapBuffer& resp_caps);
};

View File

@ -1,26 +0,0 @@
add_executable(victoriafalls
fs/ext2/ext2_block_reader.cpp
fs/ext2/ext2_driver.cpp
fs/ext2/inode_table.cpp
victoriafalls.cpp
victoriafalls_server.cpp
)
target_include_directories(victoriafalls
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(victoriafalls
denali_yunq
glacier
mammoth
victoriafalls_yunq
yellowstone_yunq
)
set_target_properties(victoriafalls PROPERTIES
COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}"
LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}"
)
yunq_gen(lib/victoriafalls lib victoriafalls)

View File

@ -1,76 +0,0 @@
#pragma once
#include <stdint.h>
struct Superblock {
uint32_t inodes_count;
uint32_t blocks_count;
uint32_t reserved_blocks_count;
uint32_t free_blocks_count;
uint32_t free_inodes_count;
uint32_t first_data_blok;
uint32_t log_block_size;
uint32_t log_frag_size;
uint32_t blocks_per_group;
uint32_t frags_per_group;
uint32_t inodes_per_group;
uint32_t mtime;
uint32_t wtime;
uint16_t mnt_count;
uint16_t max_mnt_count;
uint16_t magic;
uint16_t state;
uint16_t errors;
uint16_t minor_rev_level;
uint32_t lastcheck;
uint32_t checkinterval;
uint32_t creator_os;
uint32_t rev_level;
uint16_t def_resuid;
uint16_t def_resgid;
uint32_t first_ino;
uint16_t inode_size;
} __attribute__((__packed__));
struct BlockGroupDescriptor {
uint32_t block_bitmap;
uint32_t inode_bitmap;
uint32_t inode_table;
uint16_t free_blocks_count;
uint16_t free_inodes_count;
uint16_t used_dirs_count;
uint8_t reserved[14];
} __attribute__((__packed__));
struct Inode {
uint16_t mode;
uint16_t uid;
uint32_t size;
uint32_t atime;
uint32_t ctime;
uint32_t mtime;
uint32_t dtime;
uint16_t gid;
uint16_t links_count;
uint32_t blocks;
uint32_t flags;
uint32_t osd1;
uint32_t block[15];
uint32_t generation;
uint32_t file_acl;
uint32_t dir_acl;
uint32_t faddr;
uint32_t osd2[3];
} __attribute__((__packed__));
constexpr uint8_t kExt2FtUnknown = 0;
constexpr uint8_t kExt2FtFile = 1;
constexpr uint8_t kExt2FtDirectory = 2;
struct DirEntry {
uint32_t inode;
uint16_t record_length;
uint8_t name_len;
uint8_t file_type;
char name[256];
} __attribute__((__packed__));

View File

@ -1,117 +0,0 @@
#include "fs/ext2/ext2_block_reader.h"
#include <mammoth/util/debug.h>
glcr::ErrorOr<glcr::SharedPtr<Ext2BlockReader>> Ext2BlockReader::Init(
const yellowstone::DenaliInfo& denali_info) {
// Read 1024 bytes from 1024 offset.
// FIXME: Don't assume 512 byte sectors somehow.
DenaliClient client(denali_info.denali_endpoint());
ReadRequest req;
req.set_device_id(denali_info.device_id());
req.mutable_block().set_lba(denali_info.lba_offset() + 2);
req.mutable_block().set_size(2);
ReadResponse resp;
auto status = client.Read(req, resp);
if (!status.ok()) {
dbgln("Failed to read superblock: {}", status.message());
return status.code();
}
mmth::OwnedMemoryRegion superblock =
mmth::OwnedMemoryRegion::FromCapability(resp.memory());
return glcr::SharedPtr<Ext2BlockReader>(
new Ext2BlockReader(glcr::Move(client), denali_info.device_id(),
denali_info.lba_offset(), glcr::Move(superblock)));
}
Superblock* Ext2BlockReader::GetSuperblock() {
return reinterpret_cast<Superblock*>(super_block_region_.vaddr());
}
uint64_t Ext2BlockReader::SectorsPerBlock() {
return 1 << (GetSuperblock()->log_block_size + 1);
}
uint64_t Ext2BlockReader::BlockSize() {
return 1024 << (GetSuperblock()->log_block_size);
}
uint64_t Ext2BlockReader::NumberOfBlockGroups() {
return ((GetSuperblock()->blocks_count - 1) /
GetSuperblock()->blocks_per_group) +
1;
}
uint64_t Ext2BlockReader::BgdtBlockNum() {
return (BlockSize() == 1024) ? 2 : 1;
}
uint64_t Ext2BlockReader::BgdtBlockSize() {
return ((NumberOfBlockGroups() * sizeof(BlockGroupDescriptor) - 1) /
BlockSize()) +
1;
}
uint64_t Ext2BlockReader::InodeSize() {
constexpr uint64_t kDefaultInodeSize = 0x80;
return GetSuperblock()->rev_level >= 1 ? GetSuperblock()->inode_size
: kDefaultInodeSize;
}
uint64_t Ext2BlockReader::InodeTableBlockSize() {
return (InodeSize() * GetSuperblock()->inodes_per_group) / BlockSize();
}
glcr::ErrorOr<mmth::OwnedMemoryRegion> Ext2BlockReader::ReadBlock(
uint64_t block_number) {
return ReadBlocks(block_number, 1);
}
glcr::ErrorOr<mmth::OwnedMemoryRegion> Ext2BlockReader::ReadBlocks(
uint64_t block_number, uint64_t num_blocks) {
ReadRequest req;
req.set_device_id(device_id_);
req.mutable_block().set_lba(lba_offset_ + block_number * SectorsPerBlock());
req.mutable_block().set_size(num_blocks * SectorsPerBlock());
ReadResponse resp;
auto status = denali_.Read(req, resp);
if (!status.ok()) {
dbgln("Failed to read block: {}", status.code());
return status.code();
}
return mmth::OwnedMemoryRegion::FromCapability(resp.memory());
}
glcr::ErrorOr<mmth::OwnedMemoryRegion> Ext2BlockReader::ReadBlocks(
const glcr::Vector<uint64_t>& block_list) {
ReadManyRequest req;
req.set_device_id(device_id_);
for (uint64_t i = 0; i < block_list.size(); i++) {
uint64_t curr_start = lba_offset_ + block_list.at(i) * SectorsPerBlock();
uint64_t curr_run_len = 1;
while ((i + 1) < block_list.size() &&
block_list.at(i + 1) == block_list.at(i) + 1) {
i++;
curr_run_len++;
}
DiskBlock block;
block.set_lba(curr_start);
block.set_size(curr_run_len * SectorsPerBlock());
req.add_blocks(glcr::Move(block));
}
ReadResponse resp;
auto status = denali_.ReadMany(req, resp);
if (!status.ok()) {
dbgln("Failed to read blocks: {}", status.code());
return status.code();
}
return mmth::OwnedMemoryRegion::FromCapability(resp.memory());
}
Ext2BlockReader::Ext2BlockReader(DenaliClient&& denali, uint64_t device_id,
uint64_t lba_offset,
mmth::OwnedMemoryRegion&& super_block)
: denali_(glcr::Move(denali)),
device_id_(device_id),
lba_offset_(lba_offset),
super_block_region_(glcr::Move(super_block)) {}

View File

@ -1,49 +0,0 @@
#pragma once
#include <denali/denali.yunq.client.h>
#include <glacier/memory/shared_ptr.h>
#include <glacier/status/error_or.h>
#include <mammoth/util/memory_region.h>
#include <yellowstone/yellowstone.yunq.h>
#include "fs/ext2/ext2.h"
/* Simple Wrapper class around the denali client to translate blocks to sectors.
*
* By necessity contains the Ext Superblock (to make the translation
* calculation).
* */
class Ext2BlockReader {
public:
static glcr::ErrorOr<glcr::SharedPtr<Ext2BlockReader>> Init(
const yellowstone::DenaliInfo& denali_info);
// TODO: Consider creating a new class wrapper with these computations.
Superblock* GetSuperblock();
uint64_t BlockSize();
uint64_t NumberOfBlockGroups();
uint64_t BgdtBlockNum();
uint64_t BgdtBlockSize();
uint64_t InodeSize();
// FIXME: This probably needs to take into account the block group number
// because the last table will likely be smaller.
uint64_t InodeTableBlockSize();
glcr::ErrorOr<mmth::OwnedMemoryRegion> ReadBlock(uint64_t block_number);
glcr::ErrorOr<mmth::OwnedMemoryRegion> ReadBlocks(uint64_t block_number,
uint64_t num_blocks);
glcr::ErrorOr<mmth::OwnedMemoryRegion> ReadBlocks(
const glcr::Vector<uint64_t>& block_list);
private:
DenaliClient denali_;
uint64_t device_id_;
uint64_t lba_offset_;
mmth::OwnedMemoryRegion super_block_region_;
Ext2BlockReader(DenaliClient&& denali, uint64_t device_id,
uint64_t lba_offset, mmth::OwnedMemoryRegion&& super_block);
uint64_t SectorsPerBlock();
};

View File

@ -1,160 +0,0 @@
#include "fs/ext2/ext2_driver.h"
#include <glacier/string/string.h>
#include <mammoth/util/debug.h>
#define EXT2_DEBUG 0
glcr::ErrorOr<Ext2Driver> Ext2Driver::Init(
const yellowstone::DenaliInfo& denali_info) {
ASSIGN_OR_RETURN(glcr::SharedPtr<Ext2BlockReader> reader,
Ext2BlockReader::Init(glcr::Move(denali_info)));
ASSIGN_OR_RETURN(
mmth::OwnedMemoryRegion bgdt,
reader->ReadBlocks(reader->BgdtBlockNum(), reader->BgdtBlockSize()));
glcr::UniquePtr<InodeTable> inode_table(
new InodeTable(reader, glcr::Move(bgdt)));
return Ext2Driver(reader, glcr::Move(inode_table));
}
glcr::ErrorCode Ext2Driver::ProbePartition() {
Superblock* superblock = ext2_reader_->GetSuperblock();
if (superblock->magic != 0xEF53) {
dbgln("Invalid EXT2 magic code: {x}");
return glcr::INVALID_ARGUMENT;
}
#if EXT2_DEBUG
dbgln("Block size: 0x{x}", 1024 << superblock->log_block_size);
dbgln("Blocks: 0x{x} (0x{x} per group)", superblock->blocks_count,
superblock->blocks_per_group);
dbgln("Inodes: 0x{x} (0x{x} per group)", superblock->inodes_count,
superblock->inodes_per_group);
dbgln("Inode size: 0x{x}", superblock->inode_size);
dbgln("Mounts: 0x{x} out of 0x{x}", superblock->mnt_count,
superblock->max_mnt_count);
dbgln("State: {x}", superblock->state);
dbgln("Created by: {x}", superblock->creator_os);
#endif
return glcr::OK;
}
glcr::ErrorOr<Inode*> Ext2Driver::GetInode(uint32_t inode_number) {
return inode_table_->GetInode(inode_number);
}
glcr::ErrorOr<glcr::Vector<DirEntry>> Ext2Driver::ReadDirectory(
uint32_t inode_number) {
ASSIGN_OR_RETURN(Inode * inode, inode_table_->GetInode(inode_number));
if (!(inode->mode & 0x4000)) {
dbgln("Reading non directory.");
return glcr::INVALID_ARGUMENT;
}
ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion dir, ReadInode(inode_number, inode));
glcr::Vector<DirEntry> directory;
uint64_t addr = dir.vaddr();
while (addr < dir.vaddr() + ext2_reader_->BlockSize()) {
DirEntry* entry = reinterpret_cast<DirEntry*>(addr);
directory.PushBack(*entry);
glcr::StringView name(entry->name, entry->name_len);
#if EXT2_DEBUG
switch (entry->file_type) {
case kExt2FtFile:
dbgln("FILE (0x{x}): {}", entry->inode, name);
break;
case kExt2FtDirectory:
dbgln("DIR (0x{x}): {}", entry->inode, name);
break;
default:
dbgln("UNK (0x{x}): {}", entry->inode, name);
}
#endif
addr += entry->record_length;
}
return directory;
}
glcr::ErrorOr<mmth::OwnedMemoryRegion> Ext2Driver::ReadFile(
uint64_t inode_number) {
ASSIGN_OR_RETURN(Inode * inode, inode_table_->GetInode(inode_number));
if (!(inode->mode & 0x8000)) {
dbgln("Reading non file.");
return glcr::INVALID_ARGUMENT;
}
return ReadInode(inode_number, inode);
}
glcr::ErrorOr<mmth::OwnedMemoryRegion> Ext2Driver::ReadInode(uint64_t inode_num,
Inode* inode) {
if (inode_cache_.Contains(inode_num)) {
return inode_cache_.at(inode_num).Duplicate();
}
// This calculation is cursed.
uint64_t real_block_cnt =
(inode->blocks - 1) / (ext2_reader_->BlockSize() / 512) + 1;
if (inode->block[14]) {
dbgln("Can't handle triply-indirect blocks yet.");
return glcr::UNIMPLEMENTED;
}
mmth::OwnedMemoryRegion double_indirect_block;
if (inode->block[13]) {
ASSIGN_OR_RETURN(double_indirect_block,
ext2_reader_->ReadBlock(inode->block[13]));
}
mmth::OwnedMemoryRegion indirect_block;
if (inode->block[12]) {
ASSIGN_OR_RETURN(indirect_block, ext2_reader_->ReadBlock(inode->block[12]));
}
glcr::Vector<uint64_t> blocks_to_read;
for (uint64_t i = 0; i < 12 && i < real_block_cnt; i++) {
blocks_to_read.PushBack(inode->block[i]);
}
uint32_t* indr_block_array =
reinterpret_cast<uint32_t*>(indirect_block.vaddr());
for (uint64_t i = 12; i < 268 && i < real_block_cnt; i++) {
uint64_t offset = i - 12;
blocks_to_read.PushBack(indr_block_array[offset]);
}
uint32_t* dbl_indr_block_array =
reinterpret_cast<uint32_t*>(double_indirect_block.vaddr());
for (uint64_t i = 0; i < 256; i++) {
uint64_t block = 268 + (256 * i);
if (block >= real_block_cnt) {
break;
}
ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion single_indr_block,
ext2_reader_->ReadBlock(dbl_indr_block_array[i]));
uint32_t* single_indr_block_array =
reinterpret_cast<uint32_t*>(single_indr_block.vaddr());
for (uint64_t j = 0; j < 256; j++) {
uint64_t block_inner = block + j;
if (block_inner >= real_block_cnt) {
break;
}
if (single_indr_block_array[j] != 0) {
blocks_to_read.PushBack(single_indr_block_array[j]);
} else {
dbgln("WARN skipping 0 block in inode");
}
}
}
ASSIGN_OR_RETURN(auto inode_mem, ext2_reader_->ReadBlocks(blocks_to_read));
RET_ERR(inode_cache_.Insert(glcr::Move(inode_num), inode_mem.Duplicate()));
return inode_mem;
}

View File

@ -1,36 +0,0 @@
#pragma once
#include <glacier/container/hash_map.h>
#include <glacier/memory/move.h>
#include <glacier/memory/unique_ptr.h>
#include <yellowstone/yellowstone.yunq.h>
#include "fs/ext2/ext2.h"
#include "fs/ext2/ext2_block_reader.h"
#include "fs/ext2/inode_table.h"
class Ext2Driver {
public:
static glcr::ErrorOr<Ext2Driver> Init(
const yellowstone::DenaliInfo& denali_info);
glcr::ErrorCode ProbePartition();
glcr::ErrorOr<Inode*> GetInode(uint32_t inode_number);
glcr::ErrorOr<glcr::Vector<DirEntry>> ReadDirectory(uint32_t inode_number);
glcr::ErrorOr<mmth::OwnedMemoryRegion> ReadFile(uint64_t inode_number);
private:
glcr::SharedPtr<Ext2BlockReader> ext2_reader_;
glcr::UniquePtr<InodeTable> inode_table_;
glcr::HashMap<uint64_t, mmth::OwnedMemoryRegion> inode_cache_;
Ext2Driver(const glcr::SharedPtr<Ext2BlockReader>& reader,
glcr::UniquePtr<InodeTable> inode_table)
: ext2_reader_(reader), inode_table_(glcr::Move(inode_table)) {}
glcr::ErrorOr<mmth::OwnedMemoryRegion> ReadInode(uint64_t inode_num,
Inode* inode);
};

View File

@ -1,33 +0,0 @@
#include "fs/ext2/inode_table.h"
InodeTable::InodeTable(const glcr::SharedPtr<Ext2BlockReader>& reader,
mmth::OwnedMemoryRegion&& bgdt_region)
: ext2_reader_(reader),
bgdt_region_(glcr::Move(bgdt_region)),
bgdt_(reinterpret_cast<BlockGroupDescriptor*>(bgdt_region_.vaddr())) {
inode_tables_.Resize(ext2_reader_->NumberOfBlockGroups());
}
glcr::ErrorOr<Inode*> InodeTable::GetInode(uint32_t inode_num) {
uint64_t inodes_per_group = ext2_reader_->GetSuperblock()->inodes_per_group;
uint64_t block_group_num = (inode_num - 1) / inodes_per_group;
ASSIGN_OR_RETURN(Inode * root, GetRootOfInodeTable(block_group_num));
uint64_t local_index = (inode_num - 1) % inodes_per_group;
return reinterpret_cast<Inode*>(reinterpret_cast<uint64_t>(root) +
local_index * ext2_reader_->InodeSize());
}
glcr::ErrorOr<Inode*> InodeTable::GetRootOfInodeTable(
uint64_t block_group_num) {
if (block_group_num > ext2_reader_->NumberOfBlockGroups()) {
return glcr::INVALID_ARGUMENT;
}
if (!inode_tables_[block_group_num]) {
ASSIGN_OR_RETURN(
inode_tables_[block_group_num],
ext2_reader_->ReadBlocks(bgdt_[block_group_num].inode_table,
ext2_reader_->InodeTableBlockSize()));
}
return reinterpret_cast<Inode*>(inode_tables_[block_group_num].vaddr());
}

View File

@ -1,24 +0,0 @@
#pragma once
#include <glacier/container/vector.h>
#include <mammoth/util/memory_region.h>
#include <stdint.h>
#include "fs/ext2/ext2_block_reader.h"
class InodeTable {
public:
InodeTable(const glcr::SharedPtr<Ext2BlockReader>& driver,
mmth::OwnedMemoryRegion&& bgdt_region);
glcr::ErrorOr<Inode*> GetInode(uint32_t inode_num);
private:
glcr::SharedPtr<Ext2BlockReader> ext2_reader_;
mmth::OwnedMemoryRegion bgdt_region_;
BlockGroupDescriptor* bgdt_;
glcr::Vector<mmth::OwnedMemoryRegion> inode_tables_;
glcr::ErrorOr<Inode*> GetRootOfInodeTable(uint64_t block_group_num);
};

View File

@ -1,23 +0,0 @@
interface VFS {
method OpenFile(OpenFileRequest) -> (OpenFileResponse);
method GetDirectory(GetDirectoryRequest) -> (Directory);
}
message OpenFileRequest {
string path;
}
message OpenFileResponse {
string path;
u64 size;
capability memory;
}
message GetDirectoryRequest {
string path;
}
message Directory {
// , separated list of filenames until we have repeated strings.
string filenames;
}

View File

@ -1,100 +0,0 @@
// Generated file - DO NOT MODIFY
#include "victoriafalls.yunq.client.h"
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <mammoth/util/debug.h>
#include <zcall.h>
VFSClient::~VFSClient() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
glcr::Status VFSClient::OpenFile(const OpenFileRequest& request, OpenFileResponse& response) {
uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize;
const uint32_t kSentinel = 0xBEEFDEAD;
buffer_.WriteAt<uint32_t>(0, kSentinel);
buffer_.WriteAt<uint64_t>(8, 0);
cap_buffer_.Reset();
uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_);
buffer_.WriteAt<uint32_t>(4, 16 + length);
z_cap_t reply_port_cap;
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap));
// FIXME: Add a way to zero out the first buffer.
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr()));
if (buffer_.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidResponse("Got an invalid response from server.");
}
// Check Response Code.
RET_ERR(buffer_.At<uint64_t>(8));
yunq::MessageView resp_view(buffer_, 16);
RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_));
return glcr::OK;
}
glcr::Status VFSClient::GetDirectory(const GetDirectoryRequest& request, Directory& response) {
uint64_t buffer_size = kBufferSize;
uint64_t cap_size = kCapBufferSize;
const uint32_t kSentinel = 0xBEEFDEAD;
buffer_.WriteAt<uint32_t>(0, kSentinel);
buffer_.WriteAt<uint64_t>(8, 1);
cap_buffer_.Reset();
uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_);
buffer_.WriteAt<uint32_t>(4, 16 + length);
z_cap_t reply_port_cap;
RET_ERR(ZEndpointSend(endpoint_, 16 + length, buffer_.RawPtr(), cap_buffer_.UsedSlots(), cap_buffer_.RawPtr(), &reply_port_cap));
// FIXME: Add a way to zero out the first buffer.
RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr()));
if (buffer_.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidResponse("Got an invalid response from server.");
}
// Check Response Code.
RET_ERR(buffer_.At<uint64_t>(8));
yunq::MessageView resp_view(buffer_, 16);
RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_));
return glcr::OK;
}

View File

@ -1,37 +0,0 @@
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/status/error.h>
#include <ztypes.h>
#include "victoriafalls.yunq.h"
class VFSClient {
public:
VFSClient(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
VFSClient(const VFSClient&) = delete;
VFSClient(VFSClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;};
~VFSClient();
z_cap_t Capability() { return endpoint_; }
[[nodiscard]] glcr::Status OpenFile(const OpenFileRequest& request, OpenFileResponse& response);
[[nodiscard]] glcr::Status GetDirectory(const GetDirectoryRequest& request, Directory& response);
private:
z_cap_t endpoint_;
uint64_t kBufferSize = 0x1000;
glcr::ByteBuffer buffer_{kBufferSize};
uint64_t kCapBufferSize = 0x10;
glcr::CapBuffer cap_buffer_{kCapBufferSize};
};

View File

@ -1,173 +0,0 @@
// Generated file -- DO NOT MODIFY.
#include "victoriafalls.yunq.h"
#include <yunq/message_view.h>
#include <yunq/serialize.h>
namespace {
const uint64_t header_size = 24; // 4x uint32, 1x uint64
struct ExtPointer {
uint32_t offset;
uint32_t length;
};
} // namespace
glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status OpenFileRequest::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse path.
ASSIGN_OR_RETURN(path_, message.ReadField<glcr::String>(0));
return glcr::Status::Ok();
}
uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 1);
return SerializeInternal(serializer);
}
uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 1, caps);
return SerializeInternal(serializer);
}
uint64_t OpenFileRequest::SerializeInternal(yunq::Serializer& serializer) const {
// Write path.
serializer.WriteField<glcr::String>(0, path_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status OpenFileResponse::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
// Parse memory.
ASSIGN_OR_RETURN(memory_, message.ReadCapability(2));
return glcr::Status::Ok();
}
glcr::Status OpenFileResponse::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
// Parse memory.
ASSIGN_OR_RETURN(memory_, message.ReadCapability(2, caps));
return glcr::Status::Ok();
}
glcr::Status OpenFileResponse::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse path.
ASSIGN_OR_RETURN(path_, message.ReadField<glcr::String>(0));
// Parse size.
ASSIGN_OR_RETURN(size_, message.ReadField<uint64_t>(1));
// Parse memory.
return glcr::Status::Ok();
}
uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 3);
return SerializeInternal(serializer);
}
uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 3, caps);
return SerializeInternal(serializer);
}
uint64_t OpenFileResponse::SerializeInternal(yunq::Serializer& serializer) const {
// Write path.
serializer.WriteField<glcr::String>(0, path_);
// Write size.
serializer.WriteField<uint64_t>(1, size_);
// Write memory.
serializer.WriteCapability(2, memory_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status GetDirectoryRequest::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status GetDirectoryRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse path.
ASSIGN_OR_RETURN(path_, message.ReadField<glcr::String>(0));
return glcr::Status::Ok();
}
uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 1);
return SerializeInternal(serializer);
}
uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 1, caps);
return SerializeInternal(serializer);
}
uint64_t GetDirectoryRequest::SerializeInternal(yunq::Serializer& serializer) const {
// Write path.
serializer.WriteField<glcr::String>(0, path_);
serializer.WriteHeader();
return serializer.size();
}
glcr::Status Directory::ParseFromBytes(const yunq::MessageView& message) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status Directory::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) {
RETURN_ERROR(ParseFromBytesInternal(message));
return glcr::Status::Ok();
}
glcr::Status Directory::ParseFromBytesInternal(const yunq::MessageView& message) {
RETURN_ERROR(message.CheckHeader());
// Parse filenames.
ASSIGN_OR_RETURN(filenames_, message.ReadField<glcr::String>(0));
return glcr::Status::Ok();
}
uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const {
yunq::Serializer serializer(bytes, offset, 1);
return SerializeInternal(serializer);
}
uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const {
yunq::Serializer serializer(bytes, offset, 1, caps);
return SerializeInternal(serializer);
}
uint64_t Directory::SerializeInternal(yunq::Serializer& serializer) const {
// Write filenames.
serializer.WriteField<glcr::String>(0, filenames_);
serializer.WriteHeader();
return serializer.size();
}

View File

@ -1,124 +0,0 @@
// Generated file - DO NOT MODIFY
#pragma once
#include <glacier/buffer/byte_buffer.h>
#include <glacier/buffer/cap_buffer.h>
#include <glacier/status/status.h>
#include <glacier/container/vector.h>
#include <glacier/string/string.h>
#include <yunq/message_view.h>
#include <yunq/serialize.h>
#include <ztypes.h>
class OpenFileRequest {
public:
OpenFileRequest() {}
// Delete copy and move until implemented.
OpenFileRequest(const OpenFileRequest&) = delete;
OpenFileRequest(OpenFileRequest&&) = default;
OpenFileRequest& operator=(OpenFileRequest&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const glcr::String& path() const { return path_; }
glcr::String& mutable_path() { return path_; }
void set_path(const glcr::String& value) { path_ = value; }
private:
glcr::String path_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class OpenFileResponse {
public:
OpenFileResponse() {}
// Delete copy and move until implemented.
OpenFileResponse(const OpenFileResponse&) = delete;
OpenFileResponse(OpenFileResponse&&) = default;
OpenFileResponse& operator=(OpenFileResponse&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const glcr::String& path() const { return path_; }
glcr::String& mutable_path() { return path_; }
void set_path(const glcr::String& value) { path_ = value; }
const uint64_t& size() const { return size_; }
uint64_t& mutable_size() { return size_; }
void set_size(const uint64_t& value) { size_ = value; }
const z_cap_t& memory() const { return memory_; }
z_cap_t& mutable_memory() { return memory_; }
void set_memory(const z_cap_t& value) { memory_ = value; }
private:
glcr::String path_;
uint64_t size_;
z_cap_t memory_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class GetDirectoryRequest {
public:
GetDirectoryRequest() {}
// Delete copy and move until implemented.
GetDirectoryRequest(const GetDirectoryRequest&) = delete;
GetDirectoryRequest(GetDirectoryRequest&&) = default;
GetDirectoryRequest& operator=(GetDirectoryRequest&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const glcr::String& path() const { return path_; }
glcr::String& mutable_path() { return path_; }
void set_path(const glcr::String& value) { path_ = value; }
private:
glcr::String path_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};
class Directory {
public:
Directory() {}
// Delete copy and move until implemented.
Directory(const Directory&) = delete;
Directory(Directory&&) = default;
Directory& operator=(Directory&&) = default;
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message);
[[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&);
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const;
uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const;
const glcr::String& filenames() const { return filenames_; }
glcr::String& mutable_filenames() { return filenames_; }
void set_filenames(const glcr::String& value) { filenames_ = value; }
private:
glcr::String filenames_;
// Parses everything except for caps.
glcr::Status ParseFromBytesInternal(const yunq::MessageView& message);
uint64_t SerializeInternal(yunq::Serializer& serializer) const;
};

View File

@ -1,152 +0,0 @@
// Generated file -- DO NOT MODIFY.
#include "victoriafalls.yunq.server.h"
#include <mammoth/util/debug.h>
#include <zcall.h>
namespace {
const uint32_t kSentinel = 0xBEEFDEAD;
const uint32_t kHeaderSize = 0x10;
void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) {
buffer.WriteAt<uint32_t>(0, kSentinel);
buffer.WriteAt<uint32_t>(4, kHeaderSize);
buffer.WriteAt<uint64_t>(8, err);
}
void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) {
buffer.WriteAt<uint32_t>(0, kSentinel);
buffer.WriteAt<uint32_t>(4, kHeaderSize + message_length);
buffer.WriteAt<uint64_t>(8, glcr::OK);
}
} // namespace
void VFSServerBaseThreadBootstrap(void* server_base) {
((VFSServerBase*)server_base)->ServerThread();
}
VFSServerBase::~VFSServerBase() {
if (endpoint_ != 0) {
check(ZCapRelease(endpoint_));
}
}
glcr::ErrorOr<z_cap_t> VFSServerBase::CreateClientCap() {
uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
return client_cap;
}
glcr::ErrorOr<VFSClient> VFSServerBase::CreateClient() {
uint64_t client_cap;
RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap));
return VFSClient(client_cap);
}
Thread VFSServerBase::RunServer() {
return Thread(VFSServerBaseThreadBootstrap, this);
}
void VFSServerBase::ServerThread() {
glcr::ByteBuffer recv_buffer(0x1000);
glcr::CapBuffer recv_cap(0x10);
glcr::ByteBuffer resp_buffer(0x1000);
glcr::CapBuffer resp_cap(0x10);
z_cap_t reply_port_cap;
while (true) {
uint64_t recv_cap_size = 0x10;
uint64_t recv_buf_size = 0x1000;
recv_cap.Reset();
glcr::ErrorCode recv_err = static_cast<glcr::ErrorCode>(ZEndpointRecv(endpoint_, &recv_buf_size, recv_buffer.RawPtr(), &recv_cap_size, recv_cap.RawPtr(), &reply_port_cap));
if (recv_err != glcr::OK) {
dbgln("Error in receive: {x}", recv_err);
continue;
}
uint64_t resp_length = 0;
glcr::ErrorCode reply_err = glcr::OK;
resp_cap.Reset();
glcr::Status err = HandleRequest(recv_buffer, recv_cap, resp_buffer, resp_length, resp_cap);
if (!err) {
WriteError(resp_buffer, err.code());
dbgln("Responding Error {}", err.message());
reply_err = static_cast<glcr::ErrorCode>(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr));
} else {
WriteHeader(resp_buffer, resp_length);
reply_err = static_cast<glcr::ErrorCode>(ZReplyPortSend(reply_port_cap, kHeaderSize + resp_length, resp_buffer.RawPtr(), resp_cap.UsedSlots(), resp_cap.RawPtr()));
}
if (reply_err != glcr::OK) {
dbgln("Error in reply: {x}", reply_err);
}
}
}
glcr::Status VFSServerBase::HandleRequest(const glcr::ByteBuffer& request,
const glcr::CapBuffer& req_caps,
glcr::ByteBuffer& response, uint64_t& resp_length,
glcr::CapBuffer& resp_caps) {
if (request.At<uint32_t>(0) != kSentinel) {
return glcr::InvalidArgument("Request Not Valid");
}
uint64_t method_select = request.At<uint64_t>(8);
switch(method_select) {
case 0: {
OpenFileRequest yunq_request;
yunq::MessageView request_view(request, kHeaderSize);
RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps));
OpenFileResponse yunq_response;
RETURN_ERROR(HandleOpenFile(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
case 1: {
GetDirectoryRequest yunq_request;
yunq::MessageView request_view(request, kHeaderSize);
RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps));
Directory yunq_response;
RETURN_ERROR(HandleGetDirectory(yunq_request, yunq_response));
resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps);
break;
}
default: {
return glcr::Unimplemented("Method unimplemented by server.");
}
}
return glcr::Status::Ok();
}

View File

@ -1,50 +0,0 @@
// Generated File -- DO NOT MODIFY.
#pragma once
#include <glacier/status/error_or.h>
#include <glacier/status/status.h>
#include <mammoth/proc/thread.h>
#include <ztypes.h>
#include "victoriafalls.yunq.h"
#include "victoriafalls.yunq.client.h"
class VFSServerBase {
public:
VFSServerBase(z_cap_t VFS_cap) : endpoint_(VFS_cap) {}
VFSServerBase(const VFSServerBase&) = delete;
VFSServerBase(VFSServerBase&&) = delete;
virtual ~VFSServerBase();
glcr::ErrorOr<z_cap_t> CreateClientCap();
glcr::ErrorOr<VFSClient> CreateClient();
[[nodiscard]] Thread RunServer();
[[nodiscard]] virtual glcr::Status HandleOpenFile(const OpenFileRequest&, OpenFileResponse&) = 0;
[[nodiscard]] virtual glcr::Status HandleGetDirectory(const GetDirectoryRequest&, Directory&) = 0;
private:
z_cap_t endpoint_;
friend void VFSServerBaseThreadBootstrap(void*);
void ServerThread();
[[nodiscard]] glcr::Status HandleRequest(const glcr::ByteBuffer& request, const glcr::CapBuffer& req_caps,
glcr::ByteBuffer& response, uint64_t& resp_length,
glcr::CapBuffer& resp_caps);
};

View File

@ -1,35 +0,0 @@
#include <mammoth/util/debug.h>
#include <mammoth/util/init.h>
#include <yellowstone/yellowstone.yunq.client.h>
#include "fs/ext2/ext2_driver.h"
#include "victoriafalls_server.h"
using yellowstone::DenaliInfo;
using yellowstone::RegisterEndpointRequest;
using yellowstone::YellowstoneClient;
uint64_t main(uint64_t init_cap) {
ParseInitPort(init_cap);
dbgln("VFs Started");
YellowstoneClient yellowstone(gInitEndpointCap);
DenaliInfo denali_info;
check(yellowstone.GetDenali(denali_info));
ASSIGN_OR_RETURN(Ext2Driver ext2, Ext2Driver::Init(denali_info));
ASSIGN_OR_RETURN(auto server, VFSServer::Create(ext2));
Thread server_thread = server->RunServer();
RegisterEndpointRequest req;
req.set_endpoint_name("victoriafalls");
ASSIGN_OR_RETURN(auto client_cap, server->CreateClientCap());
req.set_endpoint_capability(client_cap);
check(yellowstone.RegisterEndpoint(req));
RET_ERR(server_thread.Join());
return 0;
}

View File

@ -1,109 +0,0 @@
#include "victoriafalls_server.h"
#include <glacier/string/str_split.h>
#include <mammoth/util/debug.h>
#include <zcall.h>
glcr::ErrorOr<glcr::UniquePtr<VFSServer>> VFSServer::Create(
Ext2Driver& driver) {
z_cap_t endpoint_cap;
RET_ERR(ZEndpointCreate(&endpoint_cap));
return glcr::UniquePtr<VFSServer>(new VFSServer(endpoint_cap, driver));
}
glcr::Status VFSServer::HandleOpenFile(const OpenFileRequest& request,
OpenFileResponse& response) {
auto path_tokens = glcr::StrSplit(request.path(), '/');
// Require all paths to be absolute rather than relative.
// If the path starts with '/' then the first token will be empty.
if (path_tokens.at(0) != "") {
return glcr::InvalidArgument("Open file supports only absolute paths.");
}
ASSIGN_OR_RETURN(auto files, driver_.ReadDirectory(2));
for (uint64_t i = 1; i < path_tokens.size() - 1; i++) {
bool found_token = false;
for (uint64_t j = 0; j < files.size() && !found_token; j++) {
if (path_tokens.at(i) ==
glcr::StringView(files.at(j).name, files.at(j).name_len)) {
ASSIGN_OR_RETURN(files, driver_.ReadDirectory(files.at(j).inode));
found_token = true;
}
}
if (!found_token) {
return glcr::NotFound(glcr::StrFormat("Directory '{}' not found.",
glcr::String(path_tokens.at(i))));
}
}
uint64_t inode_num;
mmth::OwnedMemoryRegion region;
for (uint64_t j = 0; j < files.size(); j++) {
if (path_tokens.at(path_tokens.size() - 1) ==
glcr::StringView(files.at(j).name, files.at(j).name_len)) {
inode_num = files.at(j).inode;
ASSIGN_OR_RETURN(region, driver_.ReadFile(files.at(j).inode));
break;
}
}
if (!region) {
return glcr::NotFound(
glcr::StrFormat("File '{}' not found.",
glcr::String(path_tokens.at(path_tokens.size() - 1))));
}
response.set_path(request.path());
// FIXME: There isn't really a reason we need to map the file into memory then
// duplicate the cap. In the future just get the cap from the read then pass
// it to the caller directly.
response.set_memory(region.DuplicateCap());
// TODO: Consider folding this up into the actual read call.
ASSIGN_OR_RETURN(Inode * inode, driver_.GetInode(inode_num));
// FIXME: This technically only sets the lower 32 bits.
response.set_size(inode->size);
return glcr::Status::Ok();
}
glcr::Status VFSServer::HandleGetDirectory(const GetDirectoryRequest& request,
Directory& response) {
auto path_tokens = glcr::StrSplit(request.path(), '/');
if (path_tokens.at(0) != "") {
return glcr::InvalidArgument("Get Directory only supports absolute path.");
}
// If there is a trailing slash we can get rid of the empty string.
if (path_tokens.at(path_tokens.size() - 1) == "") {
path_tokens.PopBack();
}
ASSIGN_OR_RETURN(auto files, driver_.ReadDirectory(2));
for (uint64_t i = 1; i < path_tokens.size(); i++) {
bool found_token = false;
for (uint64_t j = 0; j < files.size() && !found_token; j++) {
if (path_tokens.at(i) ==
glcr::StringView(files.at(j).name, files.at(j).name_len)) {
ASSIGN_OR_RETURN(files, driver_.ReadDirectory(files.at(j).inode));
found_token = true;
}
}
if (!found_token) {
return glcr::NotFound(glcr::StrFormat("Directory '{}' not found.",
glcr::String(path_tokens.at(i))));
}
}
glcr::VariableStringBuilder filelist;
for (const DirEntry& file : files) {
filelist.PushBack(glcr::StringView(file.name, file.name_len));
filelist.PushBack(',');
}
// Remove trailing comma.
if (filelist.size() > 0) {
filelist.DeleteLast();
}
response.set_filenames(filelist.ToString());
return glcr::Status::Ok();
}

View File

@ -1,24 +0,0 @@
#pragma once
#include <glacier/memory/unique_ptr.h>
#include "fs/ext2/ext2_driver.h"
#include "victoriafalls/victoriafalls.yunq.server.h"
class VFSServer : public VFSServerBase {
public:
static glcr::ErrorOr<glcr::UniquePtr<VFSServer>> Create(Ext2Driver& driver);
glcr::Status HandleOpenFile(const OpenFileRequest&,
OpenFileResponse&) override;
glcr::Status HandleGetDirectory(const GetDirectoryRequest&,
Directory&) override;
private:
// FIXME: Don't store this as a reference.
Ext2Driver& driver_;
VFSServer(z_cap_t endpoint_cap, Ext2Driver& driver)
: VFSServerBase(endpoint_cap), driver_(driver) {}
};

View File

@ -34,7 +34,7 @@ fn serialize_field(field: &Field) -> proc_macro2::TokenStream {
{
let rep_offset = next_extension;
let rep_len = self.#name.len() as u32;
next_extension = yunq::message::serialize_repeated(buf, next_extension as usize, &self.#name)? as u32;
next_extension = yunq::message::serialize_repeated(buf, offset + next_extension as usize, &self.#name)? as u32;
buf.write_at(yunq::message::field_offset(offset, #ind), rep_offset)?;
buf.write_at(yunq::message::field_offset(offset, #ind) + 4, rep_len)?;
@ -46,7 +46,7 @@ fn serialize_field(field: &Field) -> proc_macro2::TokenStream {
{
let rep_offset = next_extension;
let rep_len = self.#name.len() as u32;
next_extension = yunq::message::serialize_repeated_message(buf, next_extension as usize, &self.#name, caps)? as u32;
next_extension = yunq::message::serialize_repeated_message(buf, offset + next_extension as usize, &self.#name, caps)? as u32;
buf.write_at(yunq::message::field_offset(offset, #ind), rep_offset)?;
buf.write_at(yunq::message::field_offset(offset, #ind) + 4, rep_len)?;
@ -232,7 +232,7 @@ fn generate_message(message: &Message) -> TokenStream {
let serialize = generate_serialize(message);
let parse = generate_parse(message);
quote! {
#[derive(PartialEq, Eq)]
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct #name {
#(pub #field_names: #field_types),*
}