[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

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) {}
};