From 8c95e6627799386df5974151a0a4396fd69a1404 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 6 Dec 2023 23:29:08 -0800 Subject: [PATCH 001/186] [VictoriaFalls] Skipp reading blocks indexed at 0. --- sys/victoriafalls/fs/ext2/ext2_driver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.cpp b/sys/victoriafalls/fs/ext2/ext2_driver.cpp index 2202163..155c6c0 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_driver.cpp @@ -144,7 +144,11 @@ glcr::ErrorOr Ext2Driver::ReadFile( if (block_inner >= real_block_cnt) { break; } - blocks_to_read.PushBack(single_indr_block_array[j]); + if (single_indr_block_array[j] != 0) { + blocks_to_read.PushBack(single_indr_block_array[j]); + } else { + dbgln("WARN skipping 0 block in inode"); + } } } From ebe72af71679cf77f48b807eb80c8ad164357c2a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 6 Dec 2023 23:29:48 -0800 Subject: [PATCH 002/186] [Sys] Reduce debugging noise. --- sys/teton/framebuffer/psf.cpp | 4 ++++ sys/victoriafalls/fs/ext2/ext2_block_reader.cpp | 2 -- sys/victoriafalls/fs/ext2/ext2_driver.cpp | 8 +++++++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sys/teton/framebuffer/psf.cpp b/sys/teton/framebuffer/psf.cpp index 43714c6..1e8aaf2 100644 --- a/sys/teton/framebuffer/psf.cpp +++ b/sys/teton/framebuffer/psf.cpp @@ -3,6 +3,8 @@ #include #include +#define PSF_DEBUG 0 + namespace { const uint32_t kMagic = 0x864AB572; @@ -16,6 +18,7 @@ Psf::Psf(glcr::StringView path) } void Psf::DumpHeader() { +#if PSF_DEBUG dbgln("Magic: {x}", header_->magic); dbgln("Version: {x}", header_->version); dbgln("Header Sz: {x}", header_->headersize); @@ -24,6 +27,7 @@ void Psf::DumpHeader() { dbgln("Glyph Size: {x}", header_->bytesperglyph); dbgln("Height: {x}", header_->height); dbgln("Width: {x}", header_->width); +#endif } void Psf::EnsureValid() { diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp index 3262f48..d8a6006 100644 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp @@ -96,9 +96,7 @@ glcr::ErrorOr Ext2BlockReader::ReadBlocks( } req.add_lba(curr_start); req.add_sector_cnt(curr_run_len * SectorsPerBlock()); - dbgln("Read {x}, {x}", curr_start, curr_run_len * SectorsPerBlock()); } - dbgln("Read many: {x}", req.lba().size()); ReadResponse resp; auto status = denali_.ReadMany(req, resp); if (!status.ok()) { diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.cpp b/sys/victoriafalls/fs/ext2/ext2_driver.cpp index 155c6c0..9d90672 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_driver.cpp @@ -3,6 +3,8 @@ #include #include +#define EXT2_DEBUG 0 + glcr::ErrorOr Ext2Driver::Init( const yellowstone::DenaliInfo& denali_info) { ASSIGN_OR_RETURN(glcr::SharedPtr reader, @@ -23,6 +25,8 @@ glcr::ErrorCode Ext2Driver::ProbePartition() { 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, @@ -36,6 +40,7 @@ glcr::ErrorCode Ext2Driver::ProbePartition() { dbgln("State: {x}", superblock->state); dbgln("Created by: {x}", superblock->creator_os); +#endif return glcr::OK; } @@ -63,7 +68,6 @@ glcr::ErrorOr> Ext2Driver::ReadDirectory( glcr::Vector directory; for (uint64_t i = 0; i < real_block_cnt; i++) { - dbgln("Getting block {x}", inode->block[i]); ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion block, ext2_reader_->ReadBlock(inode->block[i])); uint64_t addr = block.vaddr(); @@ -71,6 +75,7 @@ glcr::ErrorOr> Ext2Driver::ReadDirectory( DirEntry* entry = reinterpret_cast(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); @@ -81,6 +86,7 @@ glcr::ErrorOr> Ext2Driver::ReadDirectory( default: dbgln("UNK (0x{x}): {}", entry->inode, name); } +#endif addr += entry->record_length; } } From 961389dee828b54423583ca882cfe505176b2019 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 7 Dec 2023 00:18:09 -0800 Subject: [PATCH 003/186] [Teton] Duplicate yellowstone cap before spawning processes. --- sys/teton/terminal.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sys/teton/terminal.cpp b/sys/teton/terminal.cpp index fda6396..c4d14c9 100644 --- a/sys/teton/terminal.cpp +++ b/sys/teton/terminal.cpp @@ -68,9 +68,14 @@ void Terminal::ExecuteCommand(const glcr::String& command) { } auto file = mmth::File::Open(tokens[1]); - // TODO: Wait until the process exits. - auto error_or_cap = mmth::SpawnProcessFromElfRegion( - (uint64_t)file.raw_ptr(), gInitEndpointCap); + z_cap_t endpoint; + if (ZCapDuplicate(gInitEndpointCap, kZionPerm_All, &endpoint) != glcr::OK) { + console_.WriteString("Couldn't duplicate yellowstone cap for spawn"); + return; + } + + auto error_or_cap = + mmth::SpawnProcessFromElfRegion((uint64_t)file.raw_ptr(), endpoint); if (!error_or_cap.ok()) { console_.WriteString( glcr::StrFormat("Error: {}\n", error_or_cap.error())); From 66e94ac41b6e4e5d8faac1c2cd3f8a3a9890c39f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 7 Dec 2023 00:18:33 -0800 Subject: [PATCH 004/186] [Glacier] Allow removing from an intrusive list. --- lib/glacier/container/intrusive_list.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/glacier/container/intrusive_list.h b/lib/glacier/container/intrusive_list.h index 8957a32..aef7b83 100644 --- a/lib/glacier/container/intrusive_list.h +++ b/lib/glacier/container/intrusive_list.h @@ -20,6 +20,8 @@ class IntrusiveList { void PushFront(const RefPtr& obj); void PushBack(const RefPtr& obj); + void Remove(const RefPtr& obj); + RefPtr PopFront(); RefPtr PopBack(); @@ -64,6 +66,29 @@ void IntrusiveList::PushBack(const RefPtr& obj) { back_ = obj; } +template +void IntrusiveList::Remove(const RefPtr& obj) { + if (!obj) { + return; + } + if (front_ == obj) { + front_ = obj->next_; + } + if (back_ == obj) { + back_ = obj->prev_; + } + if (obj->prev_) { + obj->prev_->next_ = obj->next_; + } + if (obj->next_) { + obj->next_->prev_ = obj->prev_; + } + + obj->prev_ = nullptr; + obj->next_ = nullptr; + size_--; +} + template RefPtr IntrusiveList::PopFront() { if (front_ == nullptr) { From 8adde27d9b2d2963332574592c324940b80013db Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 7 Dec 2023 00:19:17 -0800 Subject: [PATCH 005/186] [Zion] Add a thread sleep call. For now this can only sleep in increments of the scheduler quantum (currently 50ms). It also uses a somewhat ineffecient way of tracking the sleeping threads - it will scale linearly with the number of sleeping threads. --- usr/testbed/test.cpp | 3 +++ zion/include/zcall.h | 1 + zion/include/ztypes.h | 1 + zion/object/thread.h | 5 +++++ zion/scheduler/scheduler.cpp | 31 ++++++++++++++++++++++++++----- zion/scheduler/scheduler.h | 5 +++++ zion/syscall/syscall.cpp | 1 + zion/syscall/thread.cpp | 5 +++++ zion/syscall/thread.h | 1 + 9 files changed, 48 insertions(+), 5 deletions(-) diff --git a/usr/testbed/test.cpp b/usr/testbed/test.cpp index ef3f2eb..3f7f324 100644 --- a/usr/testbed/test.cpp +++ b/usr/testbed/test.cpp @@ -1,7 +1,10 @@ #include +#include uint64_t main(uint64_t init_port_cap) { dbgln("testbed"); + check(ZThreadSleep(2000)); + dbgln("testbed2"); return glcr::OK; } diff --git a/zion/include/zcall.h b/zion/include/zcall.h index efe5d16..c5f9ca6 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -17,6 +17,7 @@ SYS4(ThreadStart, z_cap_t, thread_cap, uint64_t, entry, uint64_t, arg1, uint64_t, arg2); SYS0(ThreadExit); SYS1(ThreadWait, z_cap_t, thread_cap); +SYS1(ThreadSleep, uint64_t, millis); SYS5(AddressSpaceMap, z_cap_t, vmas_cap, uint64_t, vmas_offset, z_cap_t, vmmo_cap, uint64_t, align, uint64_t*, vaddr); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index f25df71..490e0d7 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -19,6 +19,7 @@ const uint64_t kZionThreadCreate = 0x10; const uint64_t kZionThreadStart = 0x11; const uint64_t kZionThreadExit = 0x12; const uint64_t kZionThreadWait = 0x13; +const uint64_t kZionThreadSleep = 0x14; // Memory Calls const uint64_t kZionAddressSpaceMap = 0x21; diff --git a/zion/object/thread.h b/zion/object/thread.h index 53bee2b..6c32007 100644 --- a/zion/object/thread.h +++ b/zion/object/thread.h @@ -29,6 +29,7 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { RUNNING, RUNNABLE, BLOCKED, + SLEEPING, CLEANUP, FINISHED, }; @@ -69,6 +70,9 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { void Wait(); + void SetSleepTicks(uint64_t sleep_ticks) { sleep_ticks_ = sleep_ticks; } + bool DecrementSleepTicks() { return --sleep_ticks_ == 0; } + private: friend class glcr::MakeRefCountedFriend; Thread(Process& proc, uint64_t tid); @@ -79,6 +83,7 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { State state_ = CREATED; bool is_kernel_ = false; uint64_t user_stack_base_; + uint64_t sleep_ticks_; // Startup Context for the thread. uint64_t rip_; diff --git a/zion/scheduler/scheduler.cpp b/zion/scheduler/scheduler.cpp index 5d745c8..2a21d30 100644 --- a/zion/scheduler/scheduler.cpp +++ b/zion/scheduler/scheduler.cpp @@ -45,14 +45,11 @@ void Scheduler::Preempt() { return; } + DecrementSleepingThreads(); + ClearDeadThreadsFromFront(); asm volatile("cli"); - if (current_thread_ == sleep_thread_) { - // Sleep should never be preempted. (We should yield it if another thread - // becomes scheduleable). - return; - } if (runnable_threads_.size() == 0) { // Continue. @@ -102,9 +99,33 @@ void Scheduler::Yield() { SwapToCurrent(*prev); } +void Scheduler::Sleep(uint64_t millis) { + // FIXME: Improve resolution of sleep calls. + uint64_t ticks = (millis / 50) + 1; + current_thread_->SetSleepTicks(ticks); + current_thread_->SetState(Thread::SLEEPING); + sleeping_threads_.PushBack(current_thread_); + Yield(); +} + void Scheduler::ClearDeadThreadsFromFront() { while (runnable_threads_.size() > 0 && runnable_threads_.PeekFront()->IsDying()) { runnable_threads_.PopFront(); } } + +void Scheduler::DecrementSleepingThreads() { + auto thread = sleeping_threads_.PeekFront(); + while (thread) { + if (thread->DecrementSleepTicks()) { + auto thread_next = thread->next_; + sleeping_threads_.Remove(thread); + thread->SetState(Thread::RUNNABLE); + runnable_threads_.PushBack(thread); + thread = thread_next; + } else { + thread = thread->next_; + } + } +} diff --git a/zion/scheduler/scheduler.h b/zion/scheduler/scheduler.h index 823ded8..37aa0b9 100644 --- a/zion/scheduler/scheduler.h +++ b/zion/scheduler/scheduler.h @@ -23,18 +23,23 @@ class Scheduler { void Preempt(); void Yield(); + void Sleep(uint64_t millis); + private: bool enabled_ = false; glcr::RefPtr current_thread_; glcr::IntrusiveList runnable_threads_; + glcr::IntrusiveList sleeping_threads_; + glcr::RefPtr sleep_thread_; Scheduler(); void SwapToCurrent(Thread& prev); void ClearDeadThreadsFromFront(); + void DecrementSleepingThreads(); }; extern Scheduler* gScheduler; diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index ac260a5..70e9677 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -59,6 +59,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) { CASE(ThreadStart); CASE(ThreadExit); CASE(ThreadWait); + CASE(ThreadSleep); // syscall/address_space.h CASE(AddressSpaceMap); CASE(AddressSpaceUnmap); diff --git a/zion/syscall/thread.cpp b/zion/syscall/thread.cpp index 36ca2fe..19f212e 100644 --- a/zion/syscall/thread.cpp +++ b/zion/syscall/thread.cpp @@ -53,3 +53,8 @@ glcr::ErrorCode ThreadWait(ZThreadWaitReq* req) { thread->Wait(); return glcr::OK; } + +glcr::ErrorCode ThreadSleep(ZThreadSleepReq* req) { + gScheduler->Sleep(req->millis); + return glcr::OK; +} diff --git a/zion/syscall/thread.h b/zion/syscall/thread.h index 17cc288..4abd323 100644 --- a/zion/syscall/thread.h +++ b/zion/syscall/thread.h @@ -8,3 +8,4 @@ glcr::ErrorCode ThreadCreate(ZThreadCreateReq* req); glcr::ErrorCode ThreadStart(ZThreadStartReq* req); glcr::ErrorCode ThreadExit(ZThreadExitReq*); glcr::ErrorCode ThreadWait(ZThreadWaitReq* req); +glcr::ErrorCode ThreadSleep(ZThreadSleepReq* req); From c530921bdaa83ac5431d94efdf054816bd0c0481 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 7 Dec 2023 22:33:29 -0800 Subject: [PATCH 006/186] [Denali] Reset AHCI controller when starting denali. --- sys/denali/CMakeLists.txt | 2 +- sys/denali/ahci/ahci.h | 7 ++ .../{ahci_driver.cpp => ahci_controller.cpp} | 65 ++++++++++++------- .../ahci/{ahci_driver.h => ahci_controller.h} | 16 ++--- sys/denali/ahci/ahci_device.cpp | 50 +++++++------- sys/denali/denali.cpp | 4 +- sys/denali/denali_server.cpp | 2 +- sys/denali/denali_server.h | 8 +-- 8 files changed, 92 insertions(+), 62 deletions(-) rename sys/denali/ahci/{ahci_driver.cpp => ahci_controller.cpp} (75%) rename sys/denali/ahci/{ahci_driver.h => ahci_controller.h} (74%) diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index eab0515..ea177f3 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,6 +1,6 @@ add_executable(denali ahci/ahci_device.cpp - ahci/ahci_driver.cpp + ahci/ahci_controller.cpp ahci/command.cpp denali.cpp denali_server.cpp diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 5e275a5..9b71c45 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -37,6 +37,10 @@ struct PciMsiCap { uint16_t message_data; } __attribute__((packed)); +const uint32_t kGlobalHostControl_HW_Reset = 1; +const uint32_t kGlobalHostControl_AHCI_Enable = (1 << 31); +const uint32_t kGlobalHostControl_Interrupt_Enable = (1 << 1); + struct AhciHba { uint32_t capabilities; uint32_t global_host_control; @@ -51,6 +55,9 @@ struct AhciHba { uint32_t bohc; // 0x28, BIOS/OS handoff control and status } __attribute__((packed)); +const uint32_t kCommand_FIS_Receive_Enable = (1 << 4); +const uint32_t kCommand_Start = 1; + struct AhciPort { uint64_t command_list_base; uint64_t fis_base; diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_controller.cpp similarity index 75% rename from sys/denali/ahci/ahci_driver.cpp rename to sys/denali/ahci/ahci_controller.cpp index 64b340d..0c164e6 100644 --- a/sys/denali/ahci/ahci_driver.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -1,4 +1,4 @@ -#include "ahci/ahci_driver.h" +#include "ahci/ahci_controller.h" #include #include @@ -11,7 +11,7 @@ namespace { const uint64_t kGhc_InteruptEnable = 0x2; void interrupt_thread(void* void_driver) { - AhciDriver* driver = static_cast(void_driver); + AhciController* driver = static_cast(void_driver); driver->InterruptLoop(); @@ -20,31 +20,32 @@ void interrupt_thread(void* void_driver) { } // namespace -glcr::ErrorOr> AhciDriver::Init( +glcr::ErrorOr> AhciController::Init( mmth::OwnedMemoryRegion&& pci_region) { - glcr::UniquePtr driver(new AhciDriver(glcr::Move(pci_region))); - // RET_ERR(driver->LoadCapabilities()); + glcr::UniquePtr driver( + new AhciController(glcr::Move(pci_region))); RET_ERR(driver->LoadHbaRegisters()); - RET_ERR(driver->LoadDevices()); + driver->DumpCapabilities(); + RET_ERR(driver->ResetHba()); RET_ERR(driver->RegisterIrq()); - // driver->DumpCapabilities(); + RET_ERR(driver->LoadDevices()); // driver->DumpPorts(); return driver; } -glcr::ErrorOr AhciDriver::GetDevice(uint64_t id) { +glcr::ErrorOr AhciController::GetDevice(uint64_t id) { if (id >= 32) { return glcr::INVALID_ARGUMENT; } - if (devices_[id] != nullptr && !devices_[id]->IsInit()) { + if (devices_[id].empty()) { return glcr::NOT_FOUND; } - return devices_[id]; + return devices_[id].get(); } -void AhciDriver::DumpCapabilities() { +void AhciController::DumpCapabilities() { dbgln("AHCI Capabilities:"); uint32_t caps = ahci_hba_->capabilities; @@ -122,26 +123,25 @@ void AhciDriver::DumpCapabilities() { dbgln("Control {x}", ahci_hba_->global_host_control); } -void AhciDriver::DumpPorts() { +void AhciController::DumpPorts() { for (uint64_t i = 0; i < 6; i++) { - AhciDevice* dev = devices_[i]; - if (dev == nullptr || !dev->IsInit()) { + if (devices_[i].empty()) { continue; } dbgln(""); dbgln("Port {}:", i); - dev->DumpInfo(); + devices_[i]->DumpInfo(); } } -void AhciDriver::InterruptLoop() { +void AhciController::InterruptLoop() { dbgln("Starting interrupt loop"); while (true) { uint64_t bytes, caps; check(ZPortRecv(irq_port_cap_, &bytes, nullptr, &caps, nullptr)); for (uint64_t i = 0; i < 32; i++) { - if (devices_[i] != nullptr && devices_[i]->IsInit() && + if (!devices_[i].empty() && devices_[i]->IsInit() && (ahci_hba_->interrupt_status & (1 << i))) { devices_[i]->HandleIrq(); ahci_hba_->interrupt_status &= ~(1 << i); @@ -150,7 +150,7 @@ void AhciDriver::InterruptLoop() { } } -glcr::ErrorCode AhciDriver::LoadCapabilities() { +glcr::ErrorCode AhciController::LoadCapabilities() { if (!(pci_device_header_->status_reg & 0x10)) { dbgln("No caps!"); return glcr::FAILED_PRECONDITION; @@ -179,7 +179,7 @@ glcr::ErrorCode AhciDriver::LoadCapabilities() { return glcr::OK; } -glcr::ErrorCode AhciDriver::RegisterIrq() { +glcr::ErrorCode AhciController::RegisterIrq() { if (pci_device_header_->interrupt_pin == 0) { crash("Can't register IRQ without a pin num", glcr::INVALID_ARGUMENT); } @@ -205,7 +205,7 @@ glcr::ErrorCode AhciDriver::RegisterIrq() { return glcr::OK; } -glcr::ErrorCode AhciDriver::LoadHbaRegisters() { +glcr::ErrorCode AhciController::LoadHbaRegisters() { ahci_region_ = mmth::OwnedMemoryRegion ::DirectPhysical( pci_device_header_->abar, 0x1100); ahci_hba_ = reinterpret_cast(ahci_region_.vaddr()); @@ -215,15 +215,34 @@ glcr::ErrorCode AhciDriver::LoadHbaRegisters() { return glcr::OK; } -glcr::ErrorCode AhciDriver::LoadDevices() { - for (uint8_t i = 0; i < 32; i++) { +glcr::ErrorCode AhciController::ResetHba() { + ahci_hba_->global_host_control |= kGlobalHostControl_HW_Reset; + + // TODO: Consider sleeping here. + while (ahci_hba_->global_host_control & kGlobalHostControl_HW_Reset) { + continue; + } + + ahci_hba_->global_host_control |= kGlobalHostControl_AHCI_Enable; + + return static_cast(ZThreadSleep(50)); +} + +glcr::ErrorCode AhciController::LoadDevices() { + for (uint8_t i = 0; i <= num_ports_; i++) { if (!(ahci_hba_->port_implemented & (1 << i))) { - devices_[i] = nullptr; continue; } + uint64_t port_addr = reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); + AhciPort* port = reinterpret_cast(port_addr); + if ((port->sata_status & 0x103) != 0x103) { + continue; + } + devices_[i] = new AhciDevice(reinterpret_cast(port_addr)); + devices_[i]->DumpInfo(); } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_controller.h similarity index 74% rename from sys/denali/ahci/ahci_driver.h rename to sys/denali/ahci/ahci_controller.h index 0713861..ffb4774 100644 --- a/sys/denali/ahci/ahci_driver.h +++ b/sys/denali/ahci/ahci_controller.h @@ -8,9 +8,9 @@ #include "ahci/ahci.h" #include "ahci/ahci_device.h" -class AhciDriver { +class AhciController { public: - static glcr::ErrorOr> Init( + static glcr::ErrorOr> Init( mmth::OwnedMemoryRegion&& ahci_phys); glcr::ErrorCode RegisterIrq(); @@ -25,22 +25,22 @@ class AhciDriver { mmth::OwnedMemoryRegion pci_region_; PciDeviceHeader* pci_device_header_ = nullptr; mmth::OwnedMemoryRegion ahci_region_; - AhciHba* ahci_hba_ = nullptr; + volatile AhciHba* ahci_hba_ = nullptr; - // TODO: Allocate these dynamically. - AhciDevice* devices_[32]; + glcr::UniquePtr devices_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; - uint64_t num_ports_; - uint64_t num_commands_; + uint8_t num_ports_; + uint8_t num_commands_; glcr::ErrorCode LoadCapabilities(); glcr::ErrorCode LoadHbaRegisters(); + glcr::ErrorCode ResetHba(); glcr::ErrorCode LoadDevices(); - AhciDriver(mmth::OwnedMemoryRegion&& pci_region) + AhciController(mmth::OwnedMemoryRegion&& pci_region) : pci_region_(glcr::Move(pci_region)), pci_device_header_( reinterpret_cast(pci_region_.vaddr())) {} diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index 994f4db..b1627c2 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -6,7 +6,8 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { if ((port_struct_->sata_status & 0x103) != 0x103) { - return; + crash("Creating device on port without a device", + glcr::FAILED_PRECONDITION); } // 0x0-0x400 -> Command List @@ -22,35 +23,46 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { received_fis_ = reinterpret_cast(command_structures_.vaddr() + 0x400); port_struct_->fis_base = paddr + 0x400; + port_struct_->command |= kCommand_FIS_Receive_Enable; command_tables_ = reinterpret_cast(command_structures_.vaddr() + 0x500); for (uint64_t i = 0; i < 32; i++) { + // This leaves space for 2 prdt entries. command_list_->command_headers[i].command_table_base_addr = (paddr + 0x500) + (0x100 * i); + commands_[i] = nullptr; } port_struct_->interrupt_enable = 0xFFFFFFFF; - // Reset the CMD and FRE bits since we move these structures. - // FIXME: I think we need to poll these bits to make sure they become - // 0 before setting them back to one. - port_struct_->command &= ~(0x00000011); - port_struct_->command |= 0x00000011; + port_struct_->sata_error = -1; + port_struct_->command |= kCommand_Start; } glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { - command->PopulateFis(command_tables_->command_fis); - command->PopulatePrdt(command_tables_->prdt); + uint64_t slot; + for (slot = 0; slot < 32; slot++) { + if (commands_[slot] == nullptr) { + break; + } + } + if (slot == 32) { + dbgln("All slots full"); + return glcr::INTERNAL; + } + CommandTable* command_table = command_tables_ + slot; + command->PopulateFis(command_tables_[slot].command_fis); + command->PopulatePrdt(command_tables_[slot].prdt); - command_list_->command_headers[0].command = + command_list_->command_headers[slot].command = (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; - command_list_->command_headers[0].prd_table_length = 1; - command_list_->command_headers[0].prd_byte_count = 0; + command_list_->command_headers[slot].prd_table_length = 1; + command_list_->command_headers[slot].prd_byte_count = 0; - commands_[0] = command; + commands_[slot] = command; - commands_issued_ |= 1; - port_struct_->command_issue |= 1; + commands_issued_ |= 1 << slot; + port_struct_->command_issue |= 1 << slot; return glcr::OK; } @@ -61,17 +73,9 @@ void AhciDevice::DumpInfo() { dbgln("Command: {x}", port_struct_->command); dbgln("Signature: {x}", port_struct_->signature); dbgln("SATA status: {x}", port_struct_->sata_status); + dbgln("SATA error: {x}", port_struct_->sata_error); dbgln("Int status: {x}", port_struct_->interrupt_status); dbgln("Int enable: {x}", port_struct_->interrupt_enable); - - // Just dump one command info for now. - for (uint64_t i = 0; i < 32; i++) { - dbgln("Command Header: {}", i); - dbgln("Command {x}", command_list_->command_headers[i].command); - dbgln("PRD Len: {x}", command_list_->command_headers[i].prd_table_length); - dbgln("Command Table {x}", - command_list_->command_headers[i].command_table_base_addr); - } } void AhciDevice::HandleIrq() { diff --git a/sys/denali/denali.cpp b/sys/denali/denali.cpp index 4173651..ba25e9a 100644 --- a/sys/denali/denali.cpp +++ b/sys/denali/denali.cpp @@ -4,7 +4,7 @@ #include #include -#include "ahci/ahci_driver.h" +#include "ahci/ahci_controller.h" #include "denali_server.h" using yellowstone::AhciInfo; @@ -19,7 +19,7 @@ uint64_t main(uint64_t init_port_cap) { check(stub.GetAhciInfo(ahci)); mmth::OwnedMemoryRegion ahci_region = mmth::OwnedMemoryRegion::FromCapability(ahci.ahci_region()); - ASSIGN_OR_RETURN(auto driver, AhciDriver::Init(glcr::Move(ahci_region))); + ASSIGN_OR_RETURN(auto driver, AhciController::Init(glcr::Move(ahci_region))); ASSIGN_OR_RETURN(glcr::UniquePtr server, DenaliServer::Create(*driver)); diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 0c397c4..0d433a0 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -6,7 +6,7 @@ #include glcr::ErrorOr> DenaliServer::Create( - AhciDriver& driver) { + AhciController& driver) { z_cap_t cap; RET_ERR(ZEndpointCreate(&cap)); return glcr::UniquePtr(new DenaliServer(cap, driver)); diff --git a/sys/denali/denali_server.h b/sys/denali/denali_server.h index 483fabe..4e5b9dc 100644 --- a/sys/denali/denali_server.h +++ b/sys/denali/denali_server.h @@ -2,13 +2,13 @@ #include -#include "ahci/ahci_driver.h" +#include "ahci/ahci_controller.h" #include "lib/denali/denali.yunq.server.h" class DenaliServer : public DenaliServerBase { public: static glcr::ErrorOr> Create( - AhciDriver& driver); + AhciController& driver); glcr::Status HandleRead(const ReadRequest& req, ReadResponse& resp) override; glcr::Status HandleReadMany(const ReadManyRequest& req, @@ -18,8 +18,8 @@ class DenaliServer : public DenaliServerBase { static const uint64_t kBuffSize = 1024; uint8_t read_buffer_[kBuffSize]; - AhciDriver& driver_; + AhciController& driver_; - DenaliServer(z_cap_t endpoint_cap, AhciDriver& driver) + DenaliServer(z_cap_t endpoint_cap, AhciController& driver) : DenaliServerBase(endpoint_cap), driver_(driver) {} }; From 5a18d7d559b9dfbe93c09de9a29d38db89ae2383 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 7 Dec 2023 22:41:15 -0800 Subject: [PATCH 007/186] [Denali] Update HBA pointers to volatile. Store CommandList in arrayview. --- lib/glacier/container/array_view.h | 2 ++ sys/denali/ahci/ahci_controller.cpp | 6 ++++-- sys/denali/ahci/ahci_controller.h | 2 +- sys/denali/ahci/ahci_device.cpp | 14 +++++++------- sys/denali/ahci/ahci_device.h | 11 ++++++----- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/glacier/container/array_view.h b/lib/glacier/container/array_view.h index da16e9d..684d6ac 100644 --- a/lib/glacier/container/array_view.h +++ b/lib/glacier/container/array_view.h @@ -10,7 +10,9 @@ class ArrayView { ArrayView() : data_(nullptr), size_(0) {} ArrayView(const ArrayView&) = default; + ArrayView& operator=(const ArrayView&) = default; ArrayView(ArrayView&&) = default; + ArrayView& operator=(ArrayView&&) = default; ArrayView(T* data, uint64_t size) : data_(data), size_(size) {} diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index 0c164e6..d4f2968 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -155,10 +155,12 @@ glcr::ErrorCode AhciController::LoadCapabilities() { dbgln("No caps!"); return glcr::FAILED_PRECONDITION; } - uint8_t* base = reinterpret_cast(pci_device_header_); + volatile uint8_t* base = + reinterpret_cast(pci_device_header_); uint16_t offset = pci_device_header_->cap_ptr; do { - uint16_t* cap = reinterpret_cast(base + offset); + volatile uint16_t* cap = + reinterpret_cast(base + offset); switch (*cap & 0xFF) { case 0x01: dbgln("Power Management"); diff --git a/sys/denali/ahci/ahci_controller.h b/sys/denali/ahci/ahci_controller.h index ffb4774..69cb2cc 100644 --- a/sys/denali/ahci/ahci_controller.h +++ b/sys/denali/ahci/ahci_controller.h @@ -23,7 +23,7 @@ class AhciController { private: mmth::OwnedMemoryRegion pci_region_; - PciDeviceHeader* pci_device_header_ = nullptr; + volatile PciDeviceHeader* pci_device_header_ = nullptr; mmth::OwnedMemoryRegion ahci_region_; volatile AhciHba* ahci_hba_ = nullptr; diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index b1627c2..c12aa2b 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -25,8 +25,8 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { port_struct_->fis_base = paddr + 0x400; port_struct_->command |= kCommand_FIS_Receive_Enable; - command_tables_ = - reinterpret_cast(command_structures_.vaddr() + 0x500); + command_tables_ = glcr::ArrayView( + reinterpret_cast(command_structures_.vaddr() + 0x500), 32); for (uint64_t i = 0; i < 32; i++) { // This leaves space for 2 prdt entries. @@ -50,7 +50,6 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { dbgln("All slots full"); return glcr::INTERNAL; } - CommandTable* command_table = command_tables_ + slot; command->PopulateFis(command_tables_[slot].command_fis); command->PopulatePrdt(command_tables_[slot].prdt); @@ -61,8 +60,8 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { commands_[slot] = command; - commands_issued_ |= 1 << slot; - port_struct_->command_issue |= 1 << slot; + commands_issued_ |= (1 << slot); + port_struct_->command_issue |= (1 << slot); return glcr::OK; } @@ -96,7 +95,8 @@ void AhciDevice::HandleIrq() { // TODO: Do something with this information. if (int_status & 0x1) { // Device to host. - DeviceToHostRegisterFis& fis = received_fis_->device_to_host_register_fis; + volatile DeviceToHostRegisterFis& fis = + received_fis_->device_to_host_register_fis; if (fis.fis_type != FIS_TYPE_REG_D2H) { dbgln("BAD FIS TYPE (exp,act): {x}, {x}", static_cast(FIS_TYPE_REG_D2H), @@ -110,7 +110,7 @@ void AhciDevice::HandleIrq() { } if (int_status & 0x2) { // PIO. - PioSetupFis& fis = received_fis_->pio_set_fis; + volatile PioSetupFis& fis = received_fis_->pio_set_fis; if (fis.fis_type != FIS_TYPE_PIO_SETUP) { dbgln("BAD FIS TYPE (exp,act): {x}, {x}", static_cast(FIS_TYPE_PIO_SETUP), diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_device.h index bc4fc94..49c36fe 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_device.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -25,13 +26,13 @@ class AhciDevice { AhciDevice& operator=(const AhciDevice&) = delete; private: - AhciPort* port_struct_ = nullptr; + volatile AhciPort* port_struct_ = nullptr; mmth::OwnedMemoryRegion command_structures_; - CommandList* command_list_ = nullptr; - ReceivedFis* received_fis_ = nullptr; - CommandTable* command_tables_ = nullptr; + volatile CommandList* command_list_ = nullptr; + volatile ReceivedFis* received_fis_ = nullptr; + glcr::ArrayView command_tables_; Command* commands_[32]; - volatile uint32_t commands_issued_ = 0; + uint32_t commands_issued_ = 0; }; From b3bc1c44d7da60e56366e35e40d31a3742be0f06 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 11:11:20 -0800 Subject: [PATCH 008/186] [Denali] Refactore interrupt handling. --- sys/denali/ahci/ahci.h | 12 +++++ sys/denali/ahci/ahci_controller.cpp | 7 ++- sys/denali/ahci/ahci_device.cpp | 78 ++++++++++++++++++++--------- 3 files changed, 70 insertions(+), 27 deletions(-) diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 9b71c45..320b5fd 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -58,6 +58,12 @@ struct AhciHba { const uint32_t kCommand_FIS_Receive_Enable = (1 << 4); const uint32_t kCommand_Start = 1; +const uint32_t kInterrupt_D2H_FIS = 1; +const uint32_t kInterrupt_PIO_FIS = (1 << 1); +const uint32_t kInterrupt_DMA_FIS = (1 << 2); +const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3); +const uint32_t kInterrupt_Unknown_FIS = (1 << 4); + struct AhciPort { uint64_t command_list_base; uint64_t fis_base; @@ -237,7 +243,13 @@ struct DeviceToHostRegisterFis { uint32_t reserved3; } __attribute__((packed)); + struct SetDeviceBitsFis { + uint8_t fis_type; + uint8_t pmport_and_i; + uint8_t status; + uint8_t error; + uint32_t reserved; } __attribute__((packed)); struct ReceivedFis { diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index d4f2968..1ee5712 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -34,7 +34,7 @@ glcr::ErrorOr> AhciController::Init( } glcr::ErrorOr AhciController::GetDevice(uint64_t id) { - if (id >= 32) { + if (id >= num_ports_) { return glcr::INVALID_ARGUMENT; } @@ -140,9 +140,8 @@ void AhciController::InterruptLoop() { while (true) { uint64_t bytes, caps; check(ZPortRecv(irq_port_cap_, &bytes, nullptr, &caps, nullptr)); - for (uint64_t i = 0; i < 32; i++) { - if (!devices_[i].empty() && devices_[i]->IsInit() && - (ahci_hba_->interrupt_status & (1 << i))) { + for (uint64_t i = 0; i < num_ports_; i++) { + if (!devices_[i].empty() && (ahci_hba_->interrupt_status & (1 << i))) { devices_[i]->HandleIrq(); ahci_hba_->interrupt_status &= ~(1 << i); } diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index c12aa2b..40513ff 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -34,7 +34,9 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { (paddr + 0x500) + (0x100 * i); commands_[i] = nullptr; } - port_struct_->interrupt_enable = 0xFFFFFFFF; + port_struct_->interrupt_enable = + kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | + kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; port_struct_->sata_error = -1; port_struct_->command |= kCommand_Start; } @@ -77,48 +79,78 @@ void AhciDevice::DumpInfo() { dbgln("Int enable: {x}", port_struct_->interrupt_enable); } +bool CheckFisType(FIS_TYPE expected, uint8_t actual) { + if (expected == actual) { + return true; + } + dbgln("BAD FIS TYPE (exp,act): {x}, {x}", static_cast(expected), + static_cast(actual)); + return false; +} + void AhciDevice::HandleIrq() { uint32_t int_status = port_struct_->interrupt_status; - // FIXME: Probably only clear the interrupts we know how to handle. port_struct_->interrupt_status = int_status; - uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; - - // FIXME: Pass error codes to the callback. - for (uint64_t i = 0; i < 32; i++) { - if (commands_finished & (1 << i)) { - commands_issued_ &= ~(1 << i); - commands_[i]->SignalComplete(); - } - } - - // TODO: Do something with this information. - if (int_status & 0x1) { + bool has_error = false; + if (int_status & kInterrupt_D2H_FIS) { + dbgln("D2H Received"); // Device to host. volatile DeviceToHostRegisterFis& fis = received_fis_->device_to_host_register_fis; - if (fis.fis_type != FIS_TYPE_REG_D2H) { - dbgln("BAD FIS TYPE (exp,act): {x}, {x}", - static_cast(FIS_TYPE_REG_D2H), - static_cast(fis.fis_type)); + if (!CheckFisType(FIS_TYPE_REG_D2H, fis.fis_type)) { return; } if (fis.error) { dbgln("D2H err: {x}", fis.error); dbgln("status: {x}", fis.status); + has_error = true; } } - if (int_status & 0x2) { + if (int_status & kInterrupt_PIO_FIS) { + dbgln("PIO Received"); // PIO. volatile PioSetupFis& fis = received_fis_->pio_set_fis; - if (fis.fis_type != FIS_TYPE_PIO_SETUP) { - dbgln("BAD FIS TYPE (exp,act): {x}, {x}", - static_cast(FIS_TYPE_PIO_SETUP), - static_cast(fis.fis_type)); + if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { return; } if (fis.error) { dbgln("PIO err: {x}", fis.error); + dbgln("status: {x}", fis.status); + has_error = true; + } + } + if (int_status & kInterrupt_DMA_FIS) { + dbgln("DMA Received"); + volatile DmaFis& fis = received_fis_->dma_fis; + if (!CheckFisType(FIS_TYPE_DMA_SETUP, fis.fis_type)) { + return; + } + // TODO: Actually do something with this FIS. + } + if (int_status & kInterrupt_DeviceBits_FIS) { + dbgln("Device Bits Received"); + volatile SetDeviceBitsFis& fis = received_fis_->set_device_bits_fis; + if (!CheckFisType(FIS_TYPE_DEV_BITS, fis.fis_type)) { + return; + } + if (fis.error) { + dbgln("SetDeviceBits err: {x}", fis.error); + dbgln("status: {x}", fis.status); + has_error = true; + } + } + if (int_status & kInterrupt_Unknown_FIS) { + dbgln("Unknown FIS recieved, type: {x}", received_fis_->unknown_fis[0]); + } + uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; + + for (uint64_t i = 0; i < 32; i++) { + if (commands_finished & (1 << i)) { + commands_issued_ &= ~(1 << i); + // FIXME: Pass error codes to the callback. + commands_[i]->SignalComplete(); + commands_[i] = nullptr; } } } From 81469496d1bab589d2622cd04bc3aa6706220ad7 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:29:18 -0800 Subject: [PATCH 009/186] Add compile option to align stack for xmm usage. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae70f18..6f27e8d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_EXPORT_COMPILE_COMMANDS True) -set(BASE_COMPILE_FLAGS "-ffreestanding -fno-rtti -fno-exceptions") +set(BASE_COMPILE_FLAGS "-ffreestanding -fno-rtti -fno-exceptions -mincoming-stack-boundary=3") set(BASE_LINK_FLAGS "-nostdlib") add_subdirectory(zion) From d90c8eb1ef02dd6e37d1406c9f24ea732905d9f9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:30:08 -0800 Subject: [PATCH 010/186] [Denali] Add identify device command. --- sys/denali/CMakeLists.txt | 2 +- sys/denali/ahci/ahci.h | 6 ++- sys/denali/ahci/ahci_controller.cpp | 13 +++-- sys/denali/ahci/ahci_controller.h | 6 +-- .../ahci/{ahci_device.cpp => ahci_port.cpp} | 21 ++++---- .../ahci/{ahci_device.h => ahci_port.h} | 13 ++--- sys/denali/ahci/command.cpp | 52 +++++++++++++++---- sys/denali/ahci/command.h | 36 ++++++++++--- sys/denali/denali_server.cpp | 4 +- 9 files changed, 109 insertions(+), 44 deletions(-) rename sys/denali/ahci/{ahci_device.cpp => ahci_port.cpp} (88%) rename sys/denali/ahci/{ahci_device.h => ahci_port.h} (72%) diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index ea177f3..566ab17 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,6 +1,6 @@ add_executable(denali - ahci/ahci_device.cpp ahci/ahci_controller.cpp + ahci/ahci_port.cpp ahci/command.cpp denali.cpp denali_server.cpp diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h index 320b5fd..c927de7 100644 --- a/sys/denali/ahci/ahci.h +++ b/sys/denali/ahci/ahci.h @@ -64,7 +64,7 @@ const uint32_t kInterrupt_DMA_FIS = (1 << 2); const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3); const uint32_t kInterrupt_Unknown_FIS = (1 << 4); -struct AhciPort { +struct AhciPortHba { uint64_t command_list_base; uint64_t fis_base; uint32_t interrupt_status; @@ -190,6 +190,9 @@ struct PioSetupFis { uint8_t rsv4[2]; // Reserved } __attribute__((packed)); +const uint8_t kIdentifyDevice = 0xEC; +const uint8_t kDmaReadExt = 0x25; + struct HostToDeviceRegisterFis { uint8_t fis_type; // FIS_TYPE_REG_H2D uint8_t pmp_and_c; @@ -216,6 +219,7 @@ struct HostToDeviceRegisterFis { // DWORD 4 uint32_t reserved; // Reserved } __attribute__((packed)); + struct DeviceToHostRegisterFis { // DWORD 0 uint8_t fis_type; // FIS_TYPE_REG_D2H diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index 1ee5712..67c7079 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -33,7 +33,7 @@ glcr::ErrorOr> AhciController::Init( return driver; } -glcr::ErrorOr AhciController::GetDevice(uint64_t id) { +glcr::ErrorOr AhciController::GetDevice(uint64_t id) { if (id >= num_ports_) { return glcr::INVALID_ARGUMENT; } @@ -237,13 +237,18 @@ glcr::ErrorCode AhciController::LoadDevices() { uint64_t port_addr = reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); - AhciPort* port = reinterpret_cast(port_addr); + AhciPortHba* port = reinterpret_cast(port_addr); if ((port->sata_status & 0x103) != 0x103) { continue; } - devices_[i] = new AhciDevice(reinterpret_cast(port_addr)); - devices_[i]->DumpInfo(); + devices_[i] = new AhciPort(reinterpret_cast(port_addr)); + + if (devices_[i]->IsSata()) { + IdentifyDeviceCommand identify(devices_[i].get()); + devices_[i]->IssueCommand(&identify); + identify.WaitComplete(); + } } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_controller.h b/sys/denali/ahci/ahci_controller.h index 69cb2cc..69ca9da 100644 --- a/sys/denali/ahci/ahci_controller.h +++ b/sys/denali/ahci/ahci_controller.h @@ -6,7 +6,7 @@ #include #include "ahci/ahci.h" -#include "ahci/ahci_device.h" +#include "ahci/ahci_port.h" class AhciController { public: @@ -16,7 +16,7 @@ class AhciController { void InterruptLoop(); - glcr::ErrorOr GetDevice(uint64_t id); + glcr::ErrorOr GetDevice(uint64_t id); void DumpCapabilities(); void DumpPorts(); @@ -27,7 +27,7 @@ class AhciController { mmth::OwnedMemoryRegion ahci_region_; volatile AhciHba* ahci_hba_ = nullptr; - glcr::UniquePtr devices_[32]; + glcr::UniquePtr devices_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_port.cpp similarity index 88% rename from sys/denali/ahci/ahci_device.cpp rename to sys/denali/ahci/ahci_port.cpp index 40513ff..add488e 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -1,10 +1,10 @@ -#include "ahci/ahci_device.h" +#include "ahci/ahci_port.h" #include #include #include -AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { +AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { if ((port_struct_->sata_status & 0x103) != 0x103) { crash("Creating device on port without a device", glcr::FAILED_PRECONDITION); @@ -34,14 +34,14 @@ AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { (paddr + 0x500) + (0x100 * i); commands_[i] = nullptr; } - port_struct_->interrupt_enable = - kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | - kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; + port_struct_->interrupt_enable = 0xFFFFFFFF; + // kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | + // kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; port_struct_->sata_error = -1; port_struct_->command |= kCommand_Start; } -glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { +glcr::ErrorCode AhciPort::IssueCommand(Command* command) { uint64_t slot; for (slot = 0; slot < 32; slot++) { if (commands_[slot] == nullptr) { @@ -56,7 +56,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { command->PopulatePrdt(command_tables_[slot].prdt); command_list_->command_headers[slot].command = - (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F | (1 << 7); command_list_->command_headers[slot].prd_table_length = 1; command_list_->command_headers[slot].prd_byte_count = 0; @@ -68,7 +68,7 @@ glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { return glcr::OK; } -void AhciDevice::DumpInfo() { +void AhciPort::DumpInfo() { dbgln("Comlist: {x}", port_struct_->command_list_base); dbgln("FIS: {x}", port_struct_->fis_base); dbgln("Command: {x}", port_struct_->command); @@ -88,7 +88,7 @@ bool CheckFisType(FIS_TYPE expected, uint8_t actual) { return false; } -void AhciDevice::HandleIrq() { +void AhciPort::HandleIrq() { uint32_t int_status = port_struct_->interrupt_status; port_struct_->interrupt_status = int_status; @@ -103,7 +103,9 @@ void AhciDevice::HandleIrq() { } if (fis.error) { dbgln("D2H err: {x}", fis.error); + dbgln("status: {x}", fis.status); + dbgln("Error: {x}", port_struct_->sata_error); has_error = true; } } @@ -114,6 +116,7 @@ void AhciDevice::HandleIrq() { if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { return; } + dbgln("Count: {x} {x} {x}", fis.counth, fis.countl, fis.e_status); if (fis.error) { dbgln("PIO err: {x}", fis.error); dbgln("status: {x}", fis.status); diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_port.h similarity index 72% rename from sys/denali/ahci/ahci_device.h rename to sys/denali/ahci/ahci_port.h index 49c36fe..e7e1a75 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_port.h @@ -8,25 +8,26 @@ #include "ahci/ahci.h" #include "ahci/command.h" -class AhciDevice { +class AhciPort { public: - AhciDevice() {} + AhciPort() {} // Caller retains ownership of the pointer. - AhciDevice(AhciPort* port_struct); + AhciPort(AhciPortHba* port_struct); void DumpInfo(); + bool IsSata() { return port_struct_->signature == 0x101; } bool IsInit() { return port_struct_ != nullptr && command_structures_; } glcr::ErrorCode IssueCommand(Command* command); void HandleIrq(); - AhciDevice(const AhciDevice&) = delete; - AhciDevice& operator=(const AhciDevice&) = delete; + AhciPort(const AhciPort&) = delete; + AhciPort& operator=(const AhciPort&) = delete; private: - volatile AhciPort* port_struct_ = nullptr; + volatile AhciPortHba* port_struct_ = nullptr; mmth::OwnedMemoryRegion command_structures_; volatile CommandList* command_list_ = nullptr; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index eea4ad0..8a1d388 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -1,5 +1,7 @@ #include "ahci/command.h" +#include + #include "ahci/ahci.h" namespace { @@ -17,12 +19,46 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} +void Command::SignalComplete() { + OnComplete(); + callback_semaphore_.Signal(); +} +void Command::WaitComplete() { callback_semaphore_.Wait(); } + +void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) { + HostToDeviceRegisterFis fis __attribute__((aligned(16))){ + .fis_type = FIS_TYPE_REG_H2D, + .pmp_and_c = 0x80, + .command = kIdentifyDevice, + .device = 0, + }; + + memcpy(command_fis, &fis, sizeof(fis)); +} + +void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { + prdt[0].region_address = paddr_; + prdt[0].byte_count = 0x200 - 1; + dbgln("paddr: {x}", paddr_); + uint16_t* ident = reinterpret_cast(identify_.vaddr()); + dbgln("vaddr: {x}", identify_.vaddr()); + for (uint32_t i = 0; i < 256; i++) { + ident[i] = 0; + } +} + +void IdentifyDeviceCommand::OnComplete() { + uint16_t* ident = reinterpret_cast(identify_.vaddr()); + uint32_t* sector_size = reinterpret_cast(ident + 117); + dbgln("Sector size: {}", *sector_size); + uint64_t* lbas = reinterpret_cast(ident + 100); + dbgln("LBA Count: {}", *lbas); + // TODO tell the port its sector size. +} + DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t paddr) - : lba_(lba), - sector_cnt_(sector_cnt), - paddr_(paddr), - callback_semaphore_() {} + : lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {} DmaReadCommand::~DmaReadCommand() {} @@ -30,7 +66,7 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) { HostToDeviceRegisterFis fis{ .fis_type = FIS_TYPE_REG_H2D, .pmp_and_c = 0x80, - .command = 0x25, + .command = kDmaReadExt, .featurel = 0, .lba0 = static_cast(lba_ & 0xFF), @@ -50,14 +86,10 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) { .reserved = 0, }; - uint64_t bytes = sector_cnt_ * 512; - memcpy(command_fis, &fis, sizeof(fis)); } + void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { prdt[0].region_address = paddr_; prdt[0].byte_count = sector_cnt_ * 512; } - -void DmaReadCommand::SignalComplete() { callback_semaphore_.Signal(); } -void DmaReadCommand::WaitComplete() { callback_semaphore_.Wait(); } diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index 61fef58..b9a3c2d 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -1,17 +1,43 @@ #pragma once #include +#include #include #include "ahci/ahci.h" +class AhciPort; + class Command { public: + Command() = default; virtual ~Command(); virtual void PopulateFis(uint8_t* command_fis) = 0; virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; - virtual void WaitComplete() = 0; - virtual void SignalComplete() = 0; + void WaitComplete(); + void SignalComplete(); + + virtual void OnComplete() {} + + private: + // TODO: Make this owned by the device so that we don't have to create a new + // one with the kernel every time a command is issued. + mmth::Semaphore callback_semaphore_; +}; + +class IdentifyDeviceCommand : public Command { + public: + IdentifyDeviceCommand(AhciPort* port) : port_(port) {} + virtual void PopulateFis(uint8_t* command_fis) override; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; + + virtual void OnComplete() override; + + private: + AhciPort* port_; + uint64_t paddr_; + mmth::OwnedMemoryRegion identify_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_); }; class DmaReadCommand : public Command { @@ -23,14 +49,8 @@ class DmaReadCommand : public Command { void PopulateFis(uint8_t* command_fis) override; void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; - void WaitComplete() override; - void SignalComplete() override; - private: uint64_t lba_; uint64_t sector_cnt_; uint64_t paddr_; - // TODO: Make this owned by the device so that we don't have to create a new - // one with the kernel every time a command is issued. - mmth::Semaphore callback_semaphore_; }; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 0d433a0..db8eb0a 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -14,7 +14,7 @@ glcr::ErrorOr> DenaliServer::Create( glcr::Status DenaliServer::HandleRead(const ReadRequest& req, ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id())); + ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); uint64_t paddr; mmth::OwnedMemoryRegion region = @@ -33,7 +33,7 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciDevice * device, driver_.GetDevice(req.device_id())); + ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); if (req.lba().size() != req.sector_cnt().size()) { return glcr::InvalidArgument("LBA and Sector Cnt must be the same length."); From d7c1022b7fefaaddee69e35c1f91d1b0960370b5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:30:24 -0800 Subject: [PATCH 011/186] [Zion] Print RBP on GP Fault. --- zion/interrupt/interrupt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 8b6c114..861e806 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -113,7 +113,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) { dbgln("RIP: {x}", frame->rip); dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx, frame->rcx, frame->rdx); - dbgln("RSP: {x}", frame->rsp); + dbgln("RSP: {x}, RBP: {x}", frame->rsp, frame->rbp); StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { From 28a0f02b059b065f7382ef789b0f5cde2d8d4aba Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:43:29 -0800 Subject: [PATCH 012/186] [Denali] Move signaling out of the command class. --- sys/denali/ahci/ahci_controller.cpp | 8 ++------ sys/denali/ahci/ahci_port.cpp | 17 ++++++++++++++--- sys/denali/ahci/ahci_port.h | 7 ++++++- sys/denali/ahci/command.cpp | 6 ------ sys/denali/ahci/command.h | 11 +---------- sys/denali/denali_server.cpp | 9 ++++----- 6 files changed, 27 insertions(+), 31 deletions(-) diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index 67c7079..465b589 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -243,12 +243,8 @@ glcr::ErrorCode AhciController::LoadDevices() { } devices_[i] = new AhciPort(reinterpret_cast(port_addr)); - - if (devices_[i]->IsSata()) { - IdentifyDeviceCommand identify(devices_[i].get()); - devices_[i]->IssueCommand(&identify); - identify.WaitComplete(); - } + // TODO: Maybe continue to the next device if this fails. + RET_ERR(devices_[i]->Identify()); } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index add488e..8c4b754 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -28,6 +28,7 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { command_tables_ = glcr::ArrayView( reinterpret_cast(command_structures_.vaddr() + 0x500), 32); + command_signals_ = glcr::Array(32); for (uint64_t i = 0; i < 32; i++) { // This leaves space for 2 prdt entries. command_list_->command_headers[i].command_table_base_addr = @@ -41,7 +42,17 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { port_struct_->command |= kCommand_Start; } -glcr::ErrorCode AhciPort::IssueCommand(Command* command) { +glcr::ErrorCode AhciPort::Identify() { + if (IsSata()) { + IdentifyDeviceCommand identify(this); + ASSIGN_OR_RETURN(auto* sem, IssueCommand(&identify)); + sem->Wait(); + identify.OnComplete(); + } + return glcr::OK; +} + +glcr::ErrorOr AhciPort::IssueCommand(Command* command) { uint64_t slot; for (slot = 0; slot < 32; slot++) { if (commands_[slot] == nullptr) { @@ -65,7 +76,7 @@ glcr::ErrorCode AhciPort::IssueCommand(Command* command) { commands_issued_ |= (1 << slot); port_struct_->command_issue |= (1 << slot); - return glcr::OK; + return &command_signals_[slot]; } void AhciPort::DumpInfo() { @@ -152,7 +163,7 @@ void AhciPort::HandleIrq() { if (commands_finished & (1 << i)) { commands_issued_ &= ~(1 << i); // FIXME: Pass error codes to the callback. - commands_[i]->SignalComplete(); + command_signals_[i].Signal(); commands_[i] = nullptr; } } diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index e7e1a75..1a74975 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -1,7 +1,9 @@ #pragma once +#include #include #include +#include #include #include @@ -19,7 +21,9 @@ class AhciPort { bool IsSata() { return port_struct_->signature == 0x101; } bool IsInit() { return port_struct_ != nullptr && command_structures_; } - glcr::ErrorCode IssueCommand(Command* command); + glcr::ErrorCode Identify(); + + glcr::ErrorOr IssueCommand(Command* command); void HandleIrq(); @@ -35,5 +39,6 @@ class AhciPort { glcr::ArrayView command_tables_; Command* commands_[32]; + glcr::Array command_signals_; uint32_t commands_issued_ = 0; }; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index 8a1d388..57cc96a 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -19,12 +19,6 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} -void Command::SignalComplete() { - OnComplete(); - callback_semaphore_.Signal(); -} -void Command::WaitComplete() { callback_semaphore_.Wait(); } - void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) { HostToDeviceRegisterFis fis __attribute__((aligned(16))){ .fis_type = FIS_TYPE_REG_H2D, diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index b9a3c2d..e7c6442 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -14,15 +14,6 @@ class Command { virtual ~Command(); virtual void PopulateFis(uint8_t* command_fis) = 0; virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; - void WaitComplete(); - void SignalComplete(); - - virtual void OnComplete() {} - - private: - // TODO: Make this owned by the device so that we don't have to create a new - // one with the kernel every time a command is issued. - mmth::Semaphore callback_semaphore_; }; class IdentifyDeviceCommand : public Command { @@ -31,7 +22,7 @@ class IdentifyDeviceCommand : public Command { virtual void PopulateFis(uint8_t* command_fis) override; virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; - virtual void OnComplete() override; + void OnComplete(); private: AhciPort* port_; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index db8eb0a..0de18ff 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -21,9 +21,8 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, mmth::OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr); DmaReadCommand command(req.lba(), req.size(), paddr); - device->IssueCommand(&command); - - command.WaitComplete(); + ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(&command)); + semaphore->Wait(); resp.set_device_id(req.device_id()); resp.set_size(req.size()); @@ -51,8 +50,8 @@ glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, uint64_t lba = req.lba().at(i); uint64_t size = req.sector_cnt().at(i); DmaReadCommand command(lba, size, region_paddr); - device->IssueCommand(&command); - command.WaitComplete(); + ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(&command)); + semaphore->Wait(); region_paddr += size * 512; } From e71017070f7a034478319c52020c959aa287516e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 14:48:41 -0800 Subject: [PATCH 013/186] [Denali] No longer store Commands on the port. --- lib/mammoth/util/memory_region.h | 10 +++++----- sys/denali/ahci/ahci_port.cpp | 19 ++++++++----------- sys/denali/ahci/ahci_port.h | 3 +-- sys/denali/ahci/command.cpp | 8 ++++---- sys/denali/ahci/command.h | 12 ++++++------ sys/denali/denali_server.cpp | 4 ++-- 6 files changed, 26 insertions(+), 30 deletions(-) diff --git a/lib/mammoth/util/memory_region.h b/lib/mammoth/util/memory_region.h index 97d1cf6..7af7d6c 100644 --- a/lib/mammoth/util/memory_region.h +++ b/lib/mammoth/util/memory_region.h @@ -25,14 +25,14 @@ class OwnedMemoryRegion { static OwnedMemoryRegion ContiguousPhysical(uint64_t size, uint64_t* paddr); static OwnedMemoryRegion DirectPhysical(uint64_t paddr, uint64_t size); - uint64_t vaddr() { return vaddr_; } - uint64_t size() { return size_; } + uint64_t vaddr() const { return vaddr_; } + uint64_t size() const { return size_; } - z_cap_t cap() { return vmmo_cap_; } + z_cap_t cap() const { return vmmo_cap_; } z_cap_t DuplicateCap(); - bool empty() { return vmmo_cap_ != 0; } - explicit operator bool() { return vmmo_cap_ != 0; } + bool empty() const { return vmmo_cap_ == 0; } + explicit operator bool() const { return vmmo_cap_ != 0; } private: OwnedMemoryRegion(uint64_t vmmo_cap, uint64_t vaddr, uint64_t size) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index 8c4b754..fe148d6 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -28,12 +28,12 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { command_tables_ = glcr::ArrayView( reinterpret_cast(command_structures_.vaddr() + 0x500), 32); + commands_issued_ = 0; command_signals_ = glcr::Array(32); for (uint64_t i = 0; i < 32; i++) { // This leaves space for 2 prdt entries. command_list_->command_headers[i].command_table_base_addr = (paddr + 0x500) + (0x100 * i); - commands_[i] = nullptr; } port_struct_->interrupt_enable = 0xFFFFFFFF; // kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | @@ -45,17 +45,17 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { glcr::ErrorCode AhciPort::Identify() { if (IsSata()) { IdentifyDeviceCommand identify(this); - ASSIGN_OR_RETURN(auto* sem, IssueCommand(&identify)); + ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify)); sem->Wait(); identify.OnComplete(); } return glcr::OK; } -glcr::ErrorOr AhciPort::IssueCommand(Command* command) { +glcr::ErrorOr AhciPort::IssueCommand(const Command& command) { uint64_t slot; for (slot = 0; slot < 32; slot++) { - if (commands_[slot] == nullptr) { + if (!(commands_issued_ & (1 << slot))) { break; } } @@ -63,16 +63,14 @@ glcr::ErrorOr AhciPort::IssueCommand(Command* command) { dbgln("All slots full"); return glcr::INTERNAL; } - command->PopulateFis(command_tables_[slot].command_fis); - command->PopulatePrdt(command_tables_[slot].prdt); + command.PopulateFis(command_tables_[slot].command_fis); + command.PopulatePrdt(command_tables_[slot].prdt); command_list_->command_headers[slot].command = (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F | (1 << 7); command_list_->command_headers[slot].prd_table_length = 1; command_list_->command_headers[slot].prd_byte_count = 0; - commands_[slot] = command; - commands_issued_ |= (1 << slot); port_struct_->command_issue |= (1 << slot); @@ -161,10 +159,9 @@ void AhciPort::HandleIrq() { for (uint64_t i = 0; i < 32; i++) { if (commands_finished & (1 << i)) { - commands_issued_ &= ~(1 << i); - // FIXME: Pass error codes to the callback. + // TODO: Pass error codes to the callback. command_signals_[i].Signal(); - commands_[i] = nullptr; + commands_issued_ &= ~(1 << i); } } } diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index 1a74975..dc66de6 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -23,7 +23,7 @@ class AhciPort { glcr::ErrorCode Identify(); - glcr::ErrorOr IssueCommand(Command* command); + glcr::ErrorOr IssueCommand(const Command& command); void HandleIrq(); @@ -38,7 +38,6 @@ class AhciPort { volatile ReceivedFis* received_fis_ = nullptr; glcr::ArrayView command_tables_; - Command* commands_[32]; glcr::Array command_signals_; uint32_t commands_issued_ = 0; }; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index 57cc96a..61a5bb1 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -19,7 +19,7 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} -void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) { +void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) const { HostToDeviceRegisterFis fis __attribute__((aligned(16))){ .fis_type = FIS_TYPE_REG_H2D, .pmp_and_c = 0x80, @@ -30,7 +30,7 @@ void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) { memcpy(command_fis, &fis, sizeof(fis)); } -void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { +void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const { prdt[0].region_address = paddr_; prdt[0].byte_count = 0x200 - 1; dbgln("paddr: {x}", paddr_); @@ -56,7 +56,7 @@ DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, DmaReadCommand::~DmaReadCommand() {} -void DmaReadCommand::PopulateFis(uint8_t* command_fis) { +void DmaReadCommand::PopulateFis(uint8_t* command_fis) const { HostToDeviceRegisterFis fis{ .fis_type = FIS_TYPE_REG_H2D, .pmp_and_c = 0x80, @@ -83,7 +83,7 @@ void DmaReadCommand::PopulateFis(uint8_t* command_fis) { memcpy(command_fis, &fis, sizeof(fis)); } -void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) { +void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const { prdt[0].region_address = paddr_; prdt[0].byte_count = sector_cnt_ * 512; } diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index e7c6442..9c1e73f 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -12,15 +12,15 @@ class Command { public: Command() = default; virtual ~Command(); - virtual void PopulateFis(uint8_t* command_fis) = 0; - virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; + virtual void PopulateFis(uint8_t* command_fis) const = 0; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const = 0; }; class IdentifyDeviceCommand : public Command { public: IdentifyDeviceCommand(AhciPort* port) : port_(port) {} - virtual void PopulateFis(uint8_t* command_fis) override; - virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; + virtual void PopulateFis(uint8_t* command_fis) const override; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override; void OnComplete(); @@ -37,8 +37,8 @@ class DmaReadCommand : public Command { virtual ~DmaReadCommand() override; - void PopulateFis(uint8_t* command_fis) override; - void PopulatePrdt(PhysicalRegionDescriptor* prdt) override; + void PopulateFis(uint8_t* command_fis) const override; + void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override; private: uint64_t lba_; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 0de18ff..7945555 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -21,7 +21,7 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, mmth::OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr); DmaReadCommand command(req.lba(), req.size(), paddr); - ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(&command)); + ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(command)); semaphore->Wait(); resp.set_device_id(req.device_id()); @@ -50,7 +50,7 @@ glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, uint64_t lba = req.lba().at(i); uint64_t size = req.sector_cnt().at(i); DmaReadCommand command(lba, size, region_paddr); - ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(&command)); + ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(command)); semaphore->Wait(); region_paddr += size * 512; From 3e1da2bc90325f1ca9ff1643b49facd3f5cab625 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:05:43 -0800 Subject: [PATCH 014/186] [Denali] Add a simpler command method and use it to send identify. --- sys/denali/ahci/ahci_port.cpp | 70 ++++++++++++++++++++++++++++++++++- sys/denali/ahci/ahci_port.h | 1 + sys/denali/ahci/command.cpp | 31 ---------------- sys/denali/ahci/command.h | 22 ++++------- 4 files changed, 76 insertions(+), 48 deletions(-) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index fe148d6..a179515 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -44,10 +44,21 @@ AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { glcr::ErrorCode AhciPort::Identify() { if (IsSata()) { - IdentifyDeviceCommand identify(this); + CommandInfo identify{ + .command = kIdentifyDevice, + .lba = 0, + .sectors = 1, + .paddr = 0, + }; + auto region = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &identify.paddr); ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify)); sem->Wait(); - identify.OnComplete(); + uint16_t* ident = reinterpret_cast(region.vaddr()); + uint32_t* sector_size = reinterpret_cast(ident + 117); + dbgln("Sector size: {}", *sector_size); + uint64_t* lbas = reinterpret_cast(ident + 100); + dbgln("LBA Count: {}", *lbas); } return glcr::OK; } @@ -77,6 +88,61 @@ glcr::ErrorOr AhciPort::IssueCommand(const Command& command) { return &command_signals_[slot]; } +glcr::ErrorOr AhciPort::IssueCommand( + const CommandInfo& command) { + uint64_t slot; + for (slot = 0; slot < 32; slot++) { + if (!(commands_issued_ & (1 << slot))) { + break; + } + } + if (slot == 32) { + dbgln("All slots full"); + return glcr::INTERNAL; + } + + auto* fis = reinterpret_cast( + command_tables_[slot].command_fis); + *fis = HostToDeviceRegisterFis{ + .fis_type = FIS_TYPE_REG_H2D, + .pmp_and_c = 0x80, + .command = command.command, + .featurel = 0, + + .lba0 = static_cast(command.lba & 0xFF), + .lba1 = static_cast((command.lba >> 8) & 0xFF), + .lba2 = static_cast((command.lba >> 16) & 0xFF), + .device = (1 << 6), // ATA LBA Mode + + .lba3 = static_cast((command.lba >> 24) & 0xFF), + .lba4 = static_cast((command.lba >> 32) & 0xFF), + .lba5 = static_cast((command.lba >> 40) & 0xFF), + .featureh = 0, + + .count = command.sectors, + .icc = 0, + .control = 0, + + .reserved = 0, + }; + + command_tables_[slot].prdt[0].region_address = command.paddr; + command_tables_[slot].prdt[0].byte_count = 512 * command.sectors; + + command_list_->command_headers[slot].prd_table_length = 1; + command_list_->command_headers[slot].command = + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + // Set prefetch bit. + command_list_->command_headers[slot].command |= (1 << 7); + + // TODO: Synchronization-wise we need to ensure this is set in the same + // critical section as where we select a slot. + commands_issued_ |= (1 << slot); + port_struct_->command_issue |= (1 << slot); + + return &command_signals_[slot]; +} + void AhciPort::DumpInfo() { dbgln("Comlist: {x}", port_struct_->command_list_base); dbgln("FIS: {x}", port_struct_->fis_base); diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index dc66de6..646278e 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -24,6 +24,7 @@ class AhciPort { glcr::ErrorCode Identify(); glcr::ErrorOr IssueCommand(const Command& command); + glcr::ErrorOr IssueCommand(const CommandInfo& command); void HandleIrq(); diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp index 61a5bb1..e33d804 100644 --- a/sys/denali/ahci/command.cpp +++ b/sys/denali/ahci/command.cpp @@ -19,37 +19,6 @@ void* memcpy(void* dest, const void* src, uint64_t count) { Command::~Command() {} -void IdentifyDeviceCommand::PopulateFis(uint8_t* command_fis) const { - HostToDeviceRegisterFis fis __attribute__((aligned(16))){ - .fis_type = FIS_TYPE_REG_H2D, - .pmp_and_c = 0x80, - .command = kIdentifyDevice, - .device = 0, - }; - - memcpy(command_fis, &fis, sizeof(fis)); -} - -void IdentifyDeviceCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const { - prdt[0].region_address = paddr_; - prdt[0].byte_count = 0x200 - 1; - dbgln("paddr: {x}", paddr_); - uint16_t* ident = reinterpret_cast(identify_.vaddr()); - dbgln("vaddr: {x}", identify_.vaddr()); - for (uint32_t i = 0; i < 256; i++) { - ident[i] = 0; - } -} - -void IdentifyDeviceCommand::OnComplete() { - uint16_t* ident = reinterpret_cast(identify_.vaddr()); - uint32_t* sector_size = reinterpret_cast(ident + 117); - dbgln("Sector size: {}", *sector_size); - uint64_t* lbas = reinterpret_cast(ident + 100); - dbgln("LBA Count: {}", *lbas); - // TODO tell the port its sector size. -} - DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t paddr) : lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {} diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index 9c1e73f..447c4f4 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -8,6 +8,13 @@ class AhciPort; +struct CommandInfo { + uint8_t command; + uint64_t lba; + uint16_t sectors; + uint64_t paddr; +}; + class Command { public: Command() = default; @@ -16,21 +23,6 @@ class Command { virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const = 0; }; -class IdentifyDeviceCommand : public Command { - public: - IdentifyDeviceCommand(AhciPort* port) : port_(port) {} - virtual void PopulateFis(uint8_t* command_fis) const override; - virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override; - - void OnComplete(); - - private: - AhciPort* port_; - uint64_t paddr_; - mmth::OwnedMemoryRegion identify_ = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &paddr_); -}; - class DmaReadCommand : public Command { public: DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr); From 69ce3028fa613470fba2c18d7eb1b741fa918046 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:11:56 -0800 Subject: [PATCH 015/186] [Denali] Move AHCI read to internal method as well. --- sys/denali/CMakeLists.txt | 1 - sys/denali/ahci/ahci_port.cpp | 33 ++++++-------------- sys/denali/ahci/ahci_port.h | 7 +++-- sys/denali/ahci/command.cpp | 58 ----------------------------------- sys/denali/ahci/command.h | 29 ------------------ sys/denali/denali_server.cpp | 8 ++--- 6 files changed, 19 insertions(+), 117 deletions(-) delete mode 100644 sys/denali/ahci/command.cpp diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index 566ab17..739b625 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,7 +1,6 @@ add_executable(denali ahci/ahci_controller.cpp ahci/ahci_port.cpp - ahci/command.cpp denali.cpp denali_server.cpp ) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index a179515..e2cc974 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -63,29 +63,16 @@ glcr::ErrorCode AhciPort::Identify() { return glcr::OK; } -glcr::ErrorOr AhciPort::IssueCommand(const Command& command) { - uint64_t slot; - for (slot = 0; slot < 32; slot++) { - if (!(commands_issued_ & (1 << slot))) { - break; - } - } - if (slot == 32) { - dbgln("All slots full"); - return glcr::INTERNAL; - } - command.PopulateFis(command_tables_[slot].command_fis); - command.PopulatePrdt(command_tables_[slot].prdt); - - command_list_->command_headers[slot].command = - (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F | (1 << 7); - command_list_->command_headers[slot].prd_table_length = 1; - command_list_->command_headers[slot].prd_byte_count = 0; - - commands_issued_ |= (1 << slot); - port_struct_->command_issue |= (1 << slot); - - return &command_signals_[slot]; +glcr::ErrorOr AhciPort::IssueRead(uint64_t lba, + uint16_t sector_cnt, + uint64_t paddr) { + CommandInfo read{ + .command = kDmaReadExt, + .lba = lba, + .sectors = sector_cnt, + .paddr = paddr, + }; + return IssueCommand(read); } glcr::ErrorOr AhciPort::IssueCommand( diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index 646278e..a5e5f0e 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -23,8 +24,8 @@ class AhciPort { glcr::ErrorCode Identify(); - glcr::ErrorOr IssueCommand(const Command& command); - glcr::ErrorOr IssueCommand(const CommandInfo& command); + glcr::ErrorOr IssueRead(uint64_t lba, uint16_t sector_cnt, + uint64_t paddr); void HandleIrq(); @@ -41,4 +42,6 @@ class AhciPort { glcr::Array command_signals_; uint32_t commands_issued_ = 0; + + glcr::ErrorOr IssueCommand(const CommandInfo& command); }; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp deleted file mode 100644 index e33d804..0000000 --- a/sys/denali/ahci/command.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "ahci/command.h" - -#include - -#include "ahci/ahci.h" - -namespace { - -void* memcpy(void* dest, const void* src, uint64_t count) { - uint8_t* d = (uint8_t*)dest; - const uint8_t* s = (uint8_t*)src; - for (uint64_t i = 0; i < count; i++) { - d[i] = s[i]; - } - return dest; -} - -} // namespace - -Command::~Command() {} - -DmaReadCommand::DmaReadCommand(uint64_t lba, uint64_t sector_cnt, - uint64_t paddr) - : lba_(lba), sector_cnt_(sector_cnt), paddr_(paddr) {} - -DmaReadCommand::~DmaReadCommand() {} - -void DmaReadCommand::PopulateFis(uint8_t* command_fis) const { - HostToDeviceRegisterFis fis{ - .fis_type = FIS_TYPE_REG_H2D, - .pmp_and_c = 0x80, - .command = kDmaReadExt, - .featurel = 0, - - .lba0 = static_cast(lba_ & 0xFF), - .lba1 = static_cast((lba_ >> 8) & 0xFF), - .lba2 = static_cast((lba_ >> 16) & 0xFF), - .device = (1 << 6), // ATA LBA Mode - - .lba3 = static_cast((lba_ >> 24) & 0xFF), - .lba4 = static_cast((lba_ >> 32) & 0xFF), - .lba5 = static_cast((lba_ >> 40) & 0xFF), - .featureh = 0, - - .count = static_cast(sector_cnt_), - .icc = 0, - .control = 0, - - .reserved = 0, - }; - - memcpy(command_fis, &fis, sizeof(fis)); -} - -void DmaReadCommand::PopulatePrdt(PhysicalRegionDescriptor* prdt) const { - prdt[0].region_address = paddr_; - prdt[0].byte_count = sector_cnt_ * 512; -} diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h index 447c4f4..cf94c1b 100644 --- a/sys/denali/ahci/command.h +++ b/sys/denali/ahci/command.h @@ -1,39 +1,10 @@ #pragma once -#include -#include #include -#include "ahci/ahci.h" - -class AhciPort; - struct CommandInfo { uint8_t command; uint64_t lba; uint16_t sectors; uint64_t paddr; }; - -class Command { - public: - Command() = default; - virtual ~Command(); - virtual void PopulateFis(uint8_t* command_fis) const = 0; - virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) const = 0; -}; - -class DmaReadCommand : public Command { - public: - DmaReadCommand(uint64_t lba, uint64_t sector_cnt, uint64_t dest_paddr); - - virtual ~DmaReadCommand() override; - - void PopulateFis(uint8_t* command_fis) const override; - void PopulatePrdt(PhysicalRegionDescriptor* prdt) const override; - - private: - uint64_t lba_; - uint64_t sector_cnt_; - uint64_t paddr_; -}; diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 7945555..ef6d9d4 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -20,8 +20,8 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr); - DmaReadCommand command(req.lba(), req.size(), paddr); - ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(command)); + ASSIGN_OR_RETURN(auto semaphore, + device->IssueRead(req.lba(), req.size(), paddr)); semaphore->Wait(); resp.set_device_id(req.device_id()); @@ -49,8 +49,8 @@ glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, for (uint64_t i = 0; i < req.lba().size(); i++) { uint64_t lba = req.lba().at(i); uint64_t size = req.sector_cnt().at(i); - DmaReadCommand command(lba, size, region_paddr); - ASSIGN_OR_RETURN(auto semaphore, device->IssueCommand(command)); + ASSIGN_OR_RETURN(auto semaphore, + device->IssueRead(lba, size, region_paddr)); semaphore->Wait(); region_paddr += size * 512; From e308d8e12031ec77a0252e9b3ac80b451f494b65 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:14:52 -0800 Subject: [PATCH 016/186] [Denali] Rename devices to ports. --- sys/denali/ahci/ahci_controller.cpp | 20 ++++++++++---------- sys/denali/ahci/ahci_controller.h | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp index 465b589..96fc6e8 100644 --- a/sys/denali/ahci/ahci_controller.cpp +++ b/sys/denali/ahci/ahci_controller.cpp @@ -28,7 +28,7 @@ glcr::ErrorOr> AhciController::Init( driver->DumpCapabilities(); RET_ERR(driver->ResetHba()); RET_ERR(driver->RegisterIrq()); - RET_ERR(driver->LoadDevices()); + RET_ERR(driver->LoadPorts()); // driver->DumpPorts(); return driver; } @@ -38,11 +38,11 @@ glcr::ErrorOr AhciController::GetDevice(uint64_t id) { return glcr::INVALID_ARGUMENT; } - if (devices_[id].empty()) { + if (ports_[id].empty()) { return glcr::NOT_FOUND; } - return devices_[id].get(); + return ports_[id].get(); } void AhciController::DumpCapabilities() { @@ -125,13 +125,13 @@ void AhciController::DumpCapabilities() { void AhciController::DumpPorts() { for (uint64_t i = 0; i < 6; i++) { - if (devices_[i].empty()) { + if (ports_[i].empty()) { continue; } dbgln(""); dbgln("Port {}:", i); - devices_[i]->DumpInfo(); + ports_[i]->DumpInfo(); } } @@ -141,8 +141,8 @@ void AhciController::InterruptLoop() { uint64_t bytes, caps; check(ZPortRecv(irq_port_cap_, &bytes, nullptr, &caps, nullptr)); for (uint64_t i = 0; i < num_ports_; i++) { - if (!devices_[i].empty() && (ahci_hba_->interrupt_status & (1 << i))) { - devices_[i]->HandleIrq(); + if (!ports_[i].empty() && (ahci_hba_->interrupt_status & (1 << i))) { + ports_[i]->HandleIrq(); ahci_hba_->interrupt_status &= ~(1 << i); } } @@ -229,7 +229,7 @@ glcr::ErrorCode AhciController::ResetHba() { return static_cast(ZThreadSleep(50)); } -glcr::ErrorCode AhciController::LoadDevices() { +glcr::ErrorCode AhciController::LoadPorts() { for (uint8_t i = 0; i <= num_ports_; i++) { if (!(ahci_hba_->port_implemented & (1 << i))) { continue; @@ -242,9 +242,9 @@ glcr::ErrorCode AhciController::LoadDevices() { continue; } - devices_[i] = new AhciPort(reinterpret_cast(port_addr)); + ports_[i] = new AhciPort(reinterpret_cast(port_addr)); // TODO: Maybe continue to the next device if this fails. - RET_ERR(devices_[i]->Identify()); + RET_ERR(ports_[i]->Identify()); } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_controller.h b/sys/denali/ahci/ahci_controller.h index 69ca9da..fba32ef 100644 --- a/sys/denali/ahci/ahci_controller.h +++ b/sys/denali/ahci/ahci_controller.h @@ -27,7 +27,7 @@ class AhciController { mmth::OwnedMemoryRegion ahci_region_; volatile AhciHba* ahci_hba_ = nullptr; - glcr::UniquePtr devices_[32]; + glcr::UniquePtr ports_[32]; Thread irq_thread_; uint64_t irq_port_cap_ = 0; @@ -38,7 +38,7 @@ class AhciController { glcr::ErrorCode LoadCapabilities(); glcr::ErrorCode LoadHbaRegisters(); glcr::ErrorCode ResetHba(); - glcr::ErrorCode LoadDevices(); + glcr::ErrorCode LoadPorts(); AhciController(mmth::OwnedMemoryRegion&& pci_region) : pci_region_(glcr::Move(pci_region)), From 0375306f5ee321623ea8d2af517fe52db39301ea Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:25:44 -0800 Subject: [PATCH 017/186] [Denali] Record SATA device sector size and count. --- sys/denali/ahci/ahci_port.cpp | 18 ++++++++++++++---- sys/denali/ahci/ahci_port.h | 6 +++++- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index e2cc974..43579d8 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -55,10 +55,20 @@ glcr::ErrorCode AhciPort::Identify() { ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify)); sem->Wait(); uint16_t* ident = reinterpret_cast(region.vaddr()); - uint32_t* sector_size = reinterpret_cast(ident + 117); - dbgln("Sector size: {}", *sector_size); - uint64_t* lbas = reinterpret_cast(ident + 100); - dbgln("LBA Count: {}", *lbas); + if (ident[106] & (1 << 12)) { + sector_size_ = *reinterpret_cast(ident + 117); + } else { + sector_size_ = 512; + } + + if (ident[83] & (1 << 10)) { + lba_count_ = *reinterpret_cast(ident + 100); + } else { + lba_count_ = *reinterpret_cast(ident + 60); + } + dbgln("Sector size: {x}", sector_size_); + dbgln("LBA Count: {x}", lba_count_); + is_init_ = true; } return glcr::OK; } diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h index a5e5f0e..fc9b2df 100644 --- a/sys/denali/ahci/ahci_port.h +++ b/sys/denali/ahci/ahci_port.h @@ -20,7 +20,7 @@ class AhciPort { void DumpInfo(); bool IsSata() { return port_struct_->signature == 0x101; } - bool IsInit() { return port_struct_ != nullptr && command_structures_; } + bool IsInit() { return is_init_; } glcr::ErrorCode Identify(); @@ -43,5 +43,9 @@ class AhciPort { glcr::Array command_signals_; uint32_t commands_issued_ = 0; + bool is_init_ = false; + uint64_t lba_count_ = 0; + uint32_t sector_size_ = 0; + glcr::ErrorOr IssueCommand(const CommandInfo& command); }; From 21265e76edf4fa93b8ec1795da4bdd2fc70b79d9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 8 Dec 2023 15:27:32 -0800 Subject: [PATCH 018/186] [Denali] Reduce logging. --- sys/denali/ahci/ahci_port.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index 43579d8..888b714 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -166,8 +166,6 @@ void AhciPort::HandleIrq() { bool has_error = false; if (int_status & kInterrupt_D2H_FIS) { - dbgln("D2H Received"); - // Device to host. volatile DeviceToHostRegisterFis& fis = received_fis_->device_to_host_register_fis; if (!CheckFisType(FIS_TYPE_REG_D2H, fis.fis_type)) { @@ -182,13 +180,10 @@ void AhciPort::HandleIrq() { } } if (int_status & kInterrupt_PIO_FIS) { - dbgln("PIO Received"); - // PIO. volatile PioSetupFis& fis = received_fis_->pio_set_fis; if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { return; } - dbgln("Count: {x} {x} {x}", fis.counth, fis.countl, fis.e_status); if (fis.error) { dbgln("PIO err: {x}", fis.error); dbgln("status: {x}", fis.status); @@ -196,7 +191,6 @@ void AhciPort::HandleIrq() { } } if (int_status & kInterrupt_DMA_FIS) { - dbgln("DMA Received"); volatile DmaFis& fis = received_fis_->dma_fis; if (!CheckFisType(FIS_TYPE_DMA_SETUP, fis.fis_type)) { return; @@ -204,7 +198,6 @@ void AhciPort::HandleIrq() { // TODO: Actually do something with this FIS. } if (int_status & kInterrupt_DeviceBits_FIS) { - dbgln("Device Bits Received"); volatile SetDeviceBitsFis& fis = received_fis_->set_device_bits_fis; if (!CheckFisType(FIS_TYPE_DEV_BITS, fis.fis_type)) { return; From 83b0d9ab61c96570f3316ffa4f8df388cac3b6b6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 15:09:41 -0800 Subject: [PATCH 019/186] [Denali] Minor AHCI fixes --- sys/denali/ahci/ahci_port.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp index 888b714..21c0501 100644 --- a/sys/denali/ahci/ahci_port.cpp +++ b/sys/denali/ahci/ahci_port.cpp @@ -128,7 +128,7 @@ glcr::ErrorOr AhciPort::IssueCommand( command_list_->command_headers[slot].prd_table_length = 1; command_list_->command_headers[slot].command = - (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + (sizeof(HostToDeviceRegisterFis) / 4) & 0x1F; // Set prefetch bit. command_list_->command_headers[slot].command |= (1 << 7); @@ -171,7 +171,8 @@ void AhciPort::HandleIrq() { if (!CheckFisType(FIS_TYPE_REG_D2H, fis.fis_type)) { return; } - if (fis.error) { + // Check is init to avoid showing an error from the COMRESET operation. + if (fis.error && is_init_) { dbgln("D2H err: {x}", fis.error); dbgln("status: {x}", fis.status); From 09d902dfb57347aeaa94365fc4fb8874053808f1 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 16:09:37 -0800 Subject: [PATCH 020/186] [Glacier] Add a basic unit testing framework. --- .gitignore | 1 + CMakeLists.txt | 2 ++ lib/glacier/CMakeLists.txt | 4 ++++ lib/glacier/test/CMakeLists.txt | 8 ++++++++ lib/glacier/test/container/CMakeLists.txt | 4 ++++ lib/glacier/test/container/vector.cpp | 10 ++++++++++ scripts/test.sh | 14 ++++++++++++++ 7 files changed, 43 insertions(+) create mode 100644 lib/glacier/test/CMakeLists.txt create mode 100644 lib/glacier/test/container/CMakeLists.txt create mode 100644 lib/glacier/test/container/vector.cpp create mode 100755 scripts/test.sh diff --git a/.gitignore b/.gitignore index ae043f6..1425034 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ builddbg/ +test-bin/ __pycache__/ compile_commands.json diff --git a/CMakeLists.txt b/CMakeLists.txt index 6f27e8d..0a74759 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") project(AcadiaOS VERSION 0.0.1 LANGUAGES CXX ASM-ATT) +include(CTest) + set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_EXPORT_COMPILE_COMMANDS True) diff --git a/lib/glacier/CMakeLists.txt b/lib/glacier/CMakeLists.txt index e20b9c9..ef0489f 100644 --- a/lib/glacier/CMakeLists.txt +++ b/lib/glacier/CMakeLists.txt @@ -29,3 +29,7 @@ target_include_directories(glacier_kernel set_target_properties(glacier_kernel PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS} -mcmodel=kernel -mgeneral-regs-only") + +if (enable_testing) + add_subdirectory(test) +endif() diff --git a/lib/glacier/test/CMakeLists.txt b/lib/glacier/test/CMakeLists.txt new file mode 100644 index 0000000..f34214a --- /dev/null +++ b/lib/glacier/test/CMakeLists.txt @@ -0,0 +1,8 @@ +find_package(Catch2 3 REQUIRED) + +add_subdirectory(container) + +add_custom_target(build_test) +add_dependencies(build_test + glc_vec_test) + diff --git a/lib/glacier/test/container/CMakeLists.txt b/lib/glacier/test/container/CMakeLists.txt new file mode 100644 index 0000000..2fad536 --- /dev/null +++ b/lib/glacier/test/container/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(glc_vec_test vector.cpp) +target_link_libraries(glc_vec_test glacier Catch2::Catch2WithMain) +target_include_directories(glc_vec_test PRIVATE "../..") +add_test(NAME glc_vec_test COMMAND $) diff --git a/lib/glacier/test/container/vector.cpp b/lib/glacier/test/container/vector.cpp new file mode 100644 index 0000000..872d63f --- /dev/null +++ b/lib/glacier/test/container/vector.cpp @@ -0,0 +1,10 @@ +#include "container/vector.h" + +#include + +using namespace glcr; + +TEST_CASE("Build Vector", "[vector]") { + Vector v; + REQUIRE(v.size() == 0); +} diff --git a/scripts/test.sh b/scripts/test.sh new file mode 100755 index 0000000..45b0185 --- /dev/null +++ b/scripts/test.sh @@ -0,0 +1,14 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +pushd "$DIR/.." +cmake -B test-bin/ -G Ninja -D enable_testing=on +pushd test-bin/ +ninja build_test +ctest --output-on-failure +popd +popd + From 5f1053cf173ccef8207d12d63031fe16257b62bd Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 16:42:43 -0800 Subject: [PATCH 021/186] [Glacier] Add Vector tests with memory check. --- lib/glacier/test/CMakeLists.txt | 2 + lib/glacier/test/container/vector.cpp | 110 +++++++++++++++++++++++++- scripts/test.sh | 2 +- 3 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/glacier/test/CMakeLists.txt b/lib/glacier/test/CMakeLists.txt index f34214a..1396d3b 100644 --- a/lib/glacier/test/CMakeLists.txt +++ b/lib/glacier/test/CMakeLists.txt @@ -1,4 +1,6 @@ find_package(Catch2 3 REQUIRED) +find_program(MEMORYCHECK_COMMAND valgrind) +set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") add_subdirectory(container) diff --git a/lib/glacier/test/container/vector.cpp b/lib/glacier/test/container/vector.cpp index 872d63f..fc281d6 100644 --- a/lib/glacier/test/container/vector.cpp +++ b/lib/glacier/test/container/vector.cpp @@ -4,7 +4,115 @@ using namespace glcr; -TEST_CASE("Build Vector", "[vector]") { +TEST_CASE("Empty Vector", "[vector]") { Vector v; REQUIRE(v.size() == 0); + REQUIRE(v.empty()); +} + +TEST_CASE("Push/Pop Vector", "[vector]") { + Vector v; + v.PushBack(42); + REQUIRE(v.size() == 1); + REQUIRE(v.capacity() >= 1); + v.PushBack(33); + REQUIRE(v.size() == 2); + REQUIRE(v.capacity() >= 2); + + REQUIRE(v.at(0) == 42); + REQUIRE(v[0] == 42); + REQUIRE(v.at(1) == 33); + REQUIRE(v[1] == 33); + + REQUIRE(v.PopBack() == 33); + REQUIRE(v.size() == 1); + REQUIRE(v.PopBack() == 42); + REQUIRE(v.size() == 0); +} + +class ConstructRecorder { + public: + static uint64_t construct_cnt; + static uint64_t copy_cnt; + static uint64_t move_cnt; + ConstructRecorder() { construct_cnt++; } + ConstructRecorder(const ConstructRecorder&) { copy_cnt++; } + ConstructRecorder& operator=(const ConstructRecorder&) { + copy_cnt++; + return *this; + } + + ConstructRecorder(ConstructRecorder&&) { move_cnt++; } + ConstructRecorder& operator=(ConstructRecorder&&) { + move_cnt++; + return *this; + } + + static void Reset() { + construct_cnt = 0; + copy_cnt = 0; + move_cnt = 0; + } + + private: + uint64_t dummy_data = 0; +}; + +uint64_t ConstructRecorder::construct_cnt = 0; +uint64_t ConstructRecorder::copy_cnt = 0; +uint64_t ConstructRecorder::move_cnt = 0; + +TEST_CASE("Data-Type Construction", "[vector]") { + ConstructRecorder::Reset(); + Vector v; + + SECTION("Copy Insert") { + ConstructRecorder obj; + v.PushBack(obj); + // This is overfitted on the implementation which also default constructs + // the held objects when allocating a new backing array. + REQUIRE(ConstructRecorder::construct_cnt == 2); + REQUIRE(ConstructRecorder::copy_cnt == 1); + REQUIRE(ConstructRecorder::move_cnt == 0); + } + + SECTION("Move Insert") { + ConstructRecorder obj; + v.PushBack(glcr::Move(obj)); + // This is overfitted on the implementation which also default constructs + // the held objects when allocating a new backing array. + REQUIRE(ConstructRecorder::construct_cnt == 2); + REQUIRE(ConstructRecorder::copy_cnt == 0); + REQUIRE(ConstructRecorder::move_cnt == 1); + } + + SECTION("RValue Insert") { + v.PushBack({}); + // This is overfitted on the implementation which also default constructs + // the held objects when allocating a new backing array. + REQUIRE(ConstructRecorder::construct_cnt == 2); + REQUIRE(ConstructRecorder::copy_cnt == 0); + REQUIRE(ConstructRecorder::move_cnt == 1); + } + + SECTION("Emplace Insert") { + v.EmplaceBack(); + // This is overfitted on the implementation which also default constructs + // the held objects when allocating a new backing array. + REQUIRE(ConstructRecorder::construct_cnt == 2); + REQUIRE(ConstructRecorder::copy_cnt == 0); + REQUIRE(ConstructRecorder::move_cnt == 1); + } + + SECTION("PopBack Move") { + v.EmplaceBack(); + ConstructRecorder obj = v.PopBack(); + + // This is overfitted on the implementation which also default constructs + // the held objects when allocating a new backing array. + REQUIRE(ConstructRecorder::construct_cnt == 2); + REQUIRE(ConstructRecorder::copy_cnt == 0); + // 1 from emplace, 1 from pop. (No additional regular constructions). + REQUIRE(ConstructRecorder::move_cnt == 2); + } } diff --git a/scripts/test.sh b/scripts/test.sh index 45b0185..54a894e 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -8,7 +8,7 @@ pushd "$DIR/.." cmake -B test-bin/ -G Ninja -D enable_testing=on pushd test-bin/ ninja build_test -ctest --output-on-failure +ctest --output-on-failure -T memcheck popd popd From 1b18739403d464897bf70485bdcb36e606489be4 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 16:45:26 -0800 Subject: [PATCH 022/186] Separate memory testing script and only generate Cmake dir if necessary. --- scripts/test-mem.sh | 16 ++++++++++++++++ scripts/test.sh | 6 ++++-- 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100755 scripts/test-mem.sh diff --git a/scripts/test-mem.sh b/scripts/test-mem.sh new file mode 100755 index 0000000..3a0c5bf --- /dev/null +++ b/scripts/test-mem.sh @@ -0,0 +1,16 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +pushd "$DIR/.." +if [[ ! -e test-bin ]]; then + cmake -B test-bin/ -G Ninja -D enable_testing=on +fi +pushd test-bin/ +ninja build_test +ctest --output-on-failure -T memcheck +popd +popd + diff --git a/scripts/test.sh b/scripts/test.sh index 54a894e..55d68b7 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -5,10 +5,12 @@ set -e DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" pushd "$DIR/.." -cmake -B test-bin/ -G Ninja -D enable_testing=on +if [[ ! -e test-bin ]]; then + cmake -B test-bin/ -G Ninja -D enable_testing=on +fi pushd test-bin/ ninja build_test -ctest --output-on-failure -T memcheck +ctest --output-on-failure popd popd From 36a09f98c9411a7ef3e868b87bc3d62263af0fcd Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 16:50:27 -0800 Subject: [PATCH 023/186] [Glacier] Add a vector move contructor test. --- lib/glacier/test/container/vector.cpp | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/glacier/test/container/vector.cpp b/lib/glacier/test/container/vector.cpp index fc281d6..188a03b 100644 --- a/lib/glacier/test/container/vector.cpp +++ b/lib/glacier/test/container/vector.cpp @@ -116,3 +116,32 @@ TEST_CASE("Data-Type Construction", "[vector]") { REQUIRE(ConstructRecorder::move_cnt == 2); } } + +TEST_CASE("Vector Move", "[vector]") { + ConstructRecorder::Reset(); + + Vector v; + v.PushBack({}); + v.PushBack({}); + v.PushBack({}); + + uint64_t construct = ConstructRecorder::construct_cnt; + uint64_t copy = ConstructRecorder::copy_cnt; + uint64_t move = ConstructRecorder::move_cnt; + + Vector v2(glcr::Move(v)); + + REQUIRE(v2.size() == 3); + REQUIRE(v2.capacity() >= 3); + REQUIRE(ConstructRecorder::construct_cnt == construct); + REQUIRE(ConstructRecorder::copy_cnt == copy); + REQUIRE(ConstructRecorder::move_cnt == move); + + Vector v3 = glcr::Move(v2); + + REQUIRE(v3.size() == 3); + REQUIRE(v3.capacity() >= 3); + REQUIRE(ConstructRecorder::construct_cnt == construct); + REQUIRE(ConstructRecorder::copy_cnt == copy); + REQUIRE(ConstructRecorder::move_cnt == move); +} From c06d1741f31230bdd24e79d3f93c22552178f816 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 16:59:10 -0800 Subject: [PATCH 024/186] [Glacier] Add a vector iterator. --- lib/glacier/container/vector.h | 38 +++++++++++++++++++++++++++ lib/glacier/test/container/vector.cpp | 25 ++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/lib/glacier/container/vector.h b/lib/glacier/container/vector.h index afe6229..64e11b8 100644 --- a/lib/glacier/container/vector.h +++ b/lib/glacier/container/vector.h @@ -47,6 +47,44 @@ class Vector { T&& PopBack(); + // Forward Iter + class Iterator { + public: + Iterator(T* item, uint64_t size) : item_(item), size_(size) {} + + Iterator next() { + if (size_ <= 1) { + return {nullptr, 0}; + } + return {item_ + 1, size_ - 1}; + } + + Iterator& operator++() { + if (size_ <= 1) { + item_ = nullptr; + size_ = 0; + } else { + item_++; + size_--; + } + return *this; + } + + T& operator*() { return *item_; } + T* operator->() { return item_; } + bool operator==(const Iterator& other) { return item_ == other.item_; } + bool operator!=(const Iterator& other) { return item_ != other.item_; } + + private: + T* item_; + uint64_t size_; + }; + + Iterator begin() { return {data_, size_}; } + const Iterator begin() const { return {data_, size_}; } + Iterator end() { return {nullptr, 0}; } + const Iterator end() const { return {nullptr, 0}; } + private: T* data_; uint64_t size_; diff --git a/lib/glacier/test/container/vector.cpp b/lib/glacier/test/container/vector.cpp index 188a03b..4ec0d65 100644 --- a/lib/glacier/test/container/vector.cpp +++ b/lib/glacier/test/container/vector.cpp @@ -145,3 +145,28 @@ TEST_CASE("Vector Move", "[vector]") { REQUIRE(ConstructRecorder::copy_cnt == copy); REQUIRE(ConstructRecorder::move_cnt == move); } + +TEST_CASE("Vector Iterator", "[vector]") { + Vector v; + for (uint64_t i = 0; i < 100; i++) { + v.PushBack(42); + } + + SECTION("For Range Loop") { + uint64_t iters = 0; + for (uint64_t i : v) { + REQUIRE(i == 42); + iters++; + } + REQUIRE(iters == 100); + } + + SECTION("Raw Iter Loop") { + uint64_t iters = 0; + for (auto it = v.begin(); it != v.end(); ++it) { + REQUIRE(*it == 42); + iters++; + } + REQUIRE(iters == 100); + } +} From b2354ae3416c03ea093afa8dd0b1786b5ba577ac Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 17:13:35 -0800 Subject: [PATCH 025/186] Move many loops over glcr::Vector to range-based loops. --- lib/glacier/container/vector.h | 1 + lib/mammoth/file/file.cpp | 4 ++-- sys/denali/denali_server.cpp | 4 ++-- sys/teton/terminal.cpp | 5 ++--- sys/victoriafalls/victoriafalls_server.cpp | 4 ++-- sys/yellowstone/yellowstone.cpp | 7 +++---- zion/object/process.cpp | 12 ++++++------ 7 files changed, 18 insertions(+), 19 deletions(-) diff --git a/lib/glacier/container/vector.h b/lib/glacier/container/vector.h index 64e11b8..eafeb78 100644 --- a/lib/glacier/container/vector.h +++ b/lib/glacier/container/vector.h @@ -37,6 +37,7 @@ class Vector { // Setters. // FIXME: Handle downsizing. + // TODO: Rename this so it is clear that this only affects capacity. void Resize(uint64_t capacity); void PushBack(const T& item); diff --git a/lib/mammoth/file/file.cpp b/lib/mammoth/file/file.cpp index 7d2a9a7..b1c4e74 100644 --- a/lib/mammoth/file/file.cpp +++ b/lib/mammoth/file/file.cpp @@ -72,8 +72,8 @@ glcr::ErrorOr> ListDirectory(glcr::StringView path) { auto file_views = glcr::StrSplit(dir.filenames(), ','); glcr::Vector files; - for (uint64_t i = 0; i < file_views.size(); i++) { - files.PushBack(file_views[i]); + for (const auto& view : glcr::StrSplit(dir.filenames(), ',')) { + files.PushBack(view); } return files; } diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index ef6d9d4..ba99e3e 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -39,8 +39,8 @@ glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, } uint64_t sector_cnt = 0; - for (uint64_t i = 0; i < req.sector_cnt().size(); i++) { - sector_cnt += req.sector_cnt().at(i); + for (uint64_t cnt : req.sector_cnt()) { + sector_cnt += cnt; } uint64_t region_paddr; mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical( diff --git a/sys/teton/terminal.cpp b/sys/teton/terminal.cpp index c4d14c9..9adb28d 100644 --- a/sys/teton/terminal.cpp +++ b/sys/teton/terminal.cpp @@ -55,9 +55,8 @@ void Terminal::ExecuteCommand(const glcr::String& command) { if (!files_or.ok()) { console_.WriteString(glcr::StrFormat("Error: {}\n", files_or.error())); } else { - auto& files = files_or.value(); - for (uint64_t i = 0; i < files.size(); i++) { - console_.WriteString(files[i]); + for (const auto& file : files_or.value()) { + console_.WriteString(file); console_.WriteChar('\n'); } } diff --git a/sys/victoriafalls/victoriafalls_server.cpp b/sys/victoriafalls/victoriafalls_server.cpp index fbc5e42..c48be7b 100644 --- a/sys/victoriafalls/victoriafalls_server.cpp +++ b/sys/victoriafalls/victoriafalls_server.cpp @@ -94,8 +94,8 @@ glcr::Status VFSServer::HandleGetDirectory(const GetDirectoryRequest& request, } glcr::VariableStringBuilder filelist; - for (uint64_t i = 0; i < files.size(); i++) { - filelist.PushBack(glcr::StringView(files.at(i).name, files.at(i).name_len)); + for (const DirEntry& file : files) { + filelist.PushBack(glcr::StringView(file.name, file.name_len)); filelist.PushBack(','); } // Remove trailing comma. diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp index ced7332..5efc089 100644 --- a/sys/yellowstone/yellowstone.cpp +++ b/sys/yellowstone/yellowstone.cpp @@ -47,10 +47,9 @@ uint64_t main(uint64_t port_cap) { glcr::Vector files = glcr::StrSplit(init_file.as_str(), '\n'); - for (uint64_t i = 0; i < files.size(); i++) { - if (!files[i].empty()) { - mmth::File binary = - mmth::File::Open(glcr::StrFormat("/bin/{}", files[i])); + for (glcr::StringView& file : files) { + if (!file.empty()) { + mmth::File binary = mmth::File::Open(glcr::StrFormat("/bin/{}", file)); ASSIGN_OR_RETURN(client_cap, server->CreateClientCap()); auto error_or = mmth::SpawnProcessFromElfRegion( diff --git a/zion/object/process.cpp b/zion/object/process.cpp index 8f45086..6fde4f1 100644 --- a/zion/object/process.cpp +++ b/zion/object/process.cpp @@ -65,9 +65,9 @@ void Process::Exit(uint64_t exit_code) { state_ = CLEANUP; exit_code_ = exit_code; - for (uint64_t i = 0; i < threads_.size(); i++) { - if (!threads_[i]->IsDying()) { - threads_[i]->SetState(Thread::CLEANUP); + for (const auto& t : threads_) { + if (!t->IsDying()) { + t->SetState(Thread::CLEANUP); } } @@ -93,9 +93,9 @@ void Process::Cleanup() { } // 1. For each thread, call cleanup. - for (uint64_t i = 0; i < threads_.size(); i++) { - if (threads_[i]->GetState() == Thread::CLEANUP) { - threads_[i]->Cleanup(); + for (const auto& t : threads_) { + if (t->GetState() == Thread::CLEANUP) { + t->Cleanup(); } } From 66e7e95855e37b186d2ca6641a98b47ad317b92d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 17:32:06 -0800 Subject: [PATCH 026/186] [Glacier] Factor Vector iterator logic into standalone class. --- lib/glacier/container/array_iter.h | 40 ++++++++++++++++++++++++++++++ lib/glacier/container/vector.h | 34 ++----------------------- 2 files changed, 42 insertions(+), 32 deletions(-) create mode 100644 lib/glacier/container/array_iter.h diff --git a/lib/glacier/container/array_iter.h b/lib/glacier/container/array_iter.h new file mode 100644 index 0000000..195e9df --- /dev/null +++ b/lib/glacier/container/array_iter.h @@ -0,0 +1,40 @@ +#pragma once + +#include + +namespace glcr { + +template +class ArrayIterator { + public: + ArrayIterator(T* item, uint64_t size) : item_(item), size_(size) {} + + ArrayIterator next() { + if (size_ <= 1) { + return {nullptr, 0}; + } + return {item_ + 1, size_ - 1}; + } + + ArrayIterator& operator++() { + if (size_ <= 1) { + item_ = nullptr; + size_ = 0; + } else { + item_++; + size_--; + } + return *this; + } + + T& operator*() { return *item_; } + T* operator->() { return item_; } + bool operator==(const ArrayIterator& other) { return item_ == other.item_; } + bool operator!=(const ArrayIterator& other) { return item_ != other.item_; } + + private: + T* item_; + uint64_t size_; +}; + +} // namespace glcr diff --git a/lib/glacier/container/vector.h b/lib/glacier/container/vector.h index eafeb78..5544436 100644 --- a/lib/glacier/container/vector.h +++ b/lib/glacier/container/vector.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -48,38 +49,7 @@ class Vector { T&& PopBack(); - // Forward Iter - class Iterator { - public: - Iterator(T* item, uint64_t size) : item_(item), size_(size) {} - - Iterator next() { - if (size_ <= 1) { - return {nullptr, 0}; - } - return {item_ + 1, size_ - 1}; - } - - Iterator& operator++() { - if (size_ <= 1) { - item_ = nullptr; - size_ = 0; - } else { - item_++; - size_--; - } - return *this; - } - - T& operator*() { return *item_; } - T* operator->() { return item_; } - bool operator==(const Iterator& other) { return item_ == other.item_; } - bool operator!=(const Iterator& other) { return item_ != other.item_; } - - private: - T* item_; - uint64_t size_; - }; + typedef ArrayIterator Iterator; Iterator begin() { return {data_, size_}; } const Iterator begin() const { return {data_, size_}; } From 0a57d149b6f0adc00d68e624c520b8b4f8347091 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 17:39:31 -0800 Subject: [PATCH 027/186] [Glacier] Add iterator to Array and ArrayView. --- lib/glacier/container/array.h | 8 ++++++++ lib/glacier/container/array_view.h | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/glacier/container/array.h b/lib/glacier/container/array.h index 171550b..62f9f87 100644 --- a/lib/glacier/container/array.h +++ b/lib/glacier/container/array.h @@ -2,6 +2,7 @@ #include +#include "glacier/container/array_iter.h" #include "glacier/container/array_view.h" namespace glcr { @@ -37,6 +38,13 @@ class Array { uint64_t size() const { return size_; } bool empty() const { return size_ == 0; } + typedef ArrayIterator Iterator; + + Iterator begin() { return {data_, size_}; } + const Iterator begin() const { return {data_, size_}; } + Iterator end() { return {nullptr, 0}; } + const Iterator end() const { return {nullptr, 0}; } + private: T* data_; uint64_t size_; diff --git a/lib/glacier/container/array_view.h b/lib/glacier/container/array_view.h index 684d6ac..f4415e8 100644 --- a/lib/glacier/container/array_view.h +++ b/lib/glacier/container/array_view.h @@ -2,6 +2,8 @@ #include +#include "glacier/container/array_iter.h" + namespace glcr { template @@ -26,6 +28,23 @@ class ArrayView { uint64_t size() const { return size_; } bool empty() const { return size_; } + typedef ArrayIterator Iterator; + + Iterator begin() { + if (size_ == 0) { + return {nullptr, 0}; + } + return {data_, size_}; + } + const Iterator begin() const { + if (size_ == 0) { + return {nullptr, 0}; + } + return {data_, size_}; + } + Iterator end() { return {nullptr, 0}; } + const Iterator end() const { return {nullptr, 0}; } + private: T* data_; uint64_t size_; From 5eb72da9c8bc565c847d78ec4eccfb29dcb04587 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 17:39:55 -0800 Subject: [PATCH 028/186] Move glcr::Array & glcr::ArrayView loops to range-based. --- lib/glacier/container/hash_map.h | 3 +-- zion/object/memory_object.cpp | 10 +++++----- zion/syscall/ipc.cpp | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/glacier/container/hash_map.h b/lib/glacier/container/hash_map.h index 1390ab6..9d72b6f 100644 --- a/lib/glacier/container/hash_map.h +++ b/lib/glacier/container/hash_map.h @@ -194,8 +194,7 @@ template void HashMap::Resize(uint64_t new_size) { Array>> new_data(new_size); - for (uint64_t i = 0; i < data_.size(); i++) { - auto& ll = data_[i]; + for (auto& ll : data_) { while (!ll.empty()) { auto pair = ll.PopFront(); uint64_t hc = H()(pair.first()); diff --git a/zion/object/memory_object.cpp b/zion/object/memory_object.cpp index 552f22a..9938db6 100644 --- a/zion/object/memory_object.cpp +++ b/zion/object/memory_object.cpp @@ -47,16 +47,16 @@ VariableMemoryObject::VariableMemoryObject(uint64_t size) : size_(size) { // FIXME: Do this lazily. uint64_t num_pages = size_ / 0x1000; phys_page_list_ = glcr::Array(num_pages); - for (uint64_t i = 0; i < phys_page_list_.size(); i++) { - phys_page_list_[i] = 0; + for (uint64_t& page : phys_page_list_) { + page = 0; } } VariableMemoryObject::~VariableMemoryObject() { - for (uint64_t p = 0; p < phys_page_list_.size(); p++) { - if (phys_page_list_[p] != 0) { + for (uint64_t& page : phys_page_list_) { + if (page != 0) { // TODO: We may be able to do some sort of coalescing here. - phys_mem::FreePage(phys_page_list_[p]); + phys_mem::FreePage(page); } } } diff --git a/zion/syscall/ipc.cpp b/zion/syscall/ipc.cpp index a49e1ed..ab1051a 100644 --- a/zion/syscall/ipc.cpp +++ b/zion/syscall/ipc.cpp @@ -28,12 +28,12 @@ glcr::ErrorOr TranslateRequestToIpcMessage(const T& req) { glcr::ArrayView caps(req.caps, req.num_caps); message.caps.Resize(caps.size()); - for (uint64_t i = 0; i < caps.size(); i++) { + for (uint64_t capid : caps) { // FIXME: This would feel safer closer to the relevant syscall. // FIXME: Race conditions on get->check->release here. Would be better to // have that as a single call on the process. (This pattern repeats other // places too). - auto cap = gScheduler->CurrentProcess().GetCapability(caps[i]); + auto cap = gScheduler->CurrentProcess().GetCapability(capid); if (!cap) { return glcr::CAP_NOT_FOUND; } @@ -41,7 +41,7 @@ glcr::ErrorOr TranslateRequestToIpcMessage(const T& req) { return glcr::CAP_PERMISSION_DENIED; } message.caps.PushBack( - gScheduler->CurrentProcess().ReleaseCapability(caps[i])); + gScheduler->CurrentProcess().ReleaseCapability(capid)); } return message; From d74918409c9da9b9bb12654a8da76133c88f4d14 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 18:29:05 -0800 Subject: [PATCH 029/186] [VictoriaFallS] Refactor Ext2Driver to share inode reading code. --- sys/victoriafalls/fs/ext2/ext2_driver.cpp | 50 ++++++++++------------- sys/victoriafalls/fs/ext2/ext2_driver.h | 2 + 2 files changed, 23 insertions(+), 29 deletions(-) diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.cpp b/sys/victoriafalls/fs/ext2/ext2_driver.cpp index 9d90672..491ec80 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_driver.cpp @@ -56,39 +56,28 @@ glcr::ErrorOr> Ext2Driver::ReadDirectory( dbgln("Reading non directory."); return glcr::INVALID_ARGUMENT; } - - // This calculation is cursed. - uint64_t real_block_cnt = - (inode->blocks - 1) / (ext2_reader_->BlockSize() / 512) + 1; - - if (real_block_cnt > 12) { - dbgln("Cant handle indirect blocks yet"); - return glcr::FAILED_PRECONDITION; - } + ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion dir, ReadInode(inode)); glcr::Vector directory; - for (uint64_t i = 0; i < real_block_cnt; i++) { - ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion block, - ext2_reader_->ReadBlock(inode->block[i])); - uint64_t addr = block.vaddr(); - while (addr < block.vaddr() + ext2_reader_->BlockSize()) { - DirEntry* entry = reinterpret_cast(addr); - directory.PushBack(*entry); - glcr::StringView name(entry->name, entry->name_len); + + uint64_t addr = dir.vaddr(); + while (addr < dir.vaddr() + ext2_reader_->BlockSize()) { + DirEntry* entry = reinterpret_cast(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; + 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; } @@ -101,7 +90,10 @@ glcr::ErrorOr Ext2Driver::ReadFile( dbgln("Reading non file."); return glcr::INVALID_ARGUMENT; } + return ReadInode(inode); +} +glcr::ErrorOr Ext2Driver::ReadInode(Inode* inode) { // This calculation is cursed. uint64_t real_block_cnt = (inode->blocks - 1) / (ext2_reader_->BlockSize() / 512) + 1; diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.h b/sys/victoriafalls/fs/ext2/ext2_driver.h index b1b4100..e70ab84 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.h +++ b/sys/victoriafalls/fs/ext2/ext2_driver.h @@ -28,4 +28,6 @@ class Ext2Driver { Ext2Driver(const glcr::SharedPtr& reader, glcr::UniquePtr inode_table) : ext2_reader_(reader), inode_table_(glcr::Move(inode_table)) {} + + glcr::ErrorOr ReadInode(Inode* inode); }; From be392252a4fa8d6d1cd11fa135b2ca0a4809b4cd Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 18:29:29 -0800 Subject: [PATCH 030/186] [Glacier] Add HashMap move semantics. --- lib/glacier/container/hash_map.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/glacier/container/hash_map.h b/lib/glacier/container/hash_map.h index 9d72b6f..10d4aca 100644 --- a/lib/glacier/container/hash_map.h +++ b/lib/glacier/container/hash_map.h @@ -18,9 +18,8 @@ class HashMap { HashMap() = default; HashMap(const HashMap&) = delete; HashMap& operator=(const HashMap&) = delete; - // TODO: Implement Move. - HashMap(HashMap&&) = delete; - HashMap& operator=(HashMap&&) = delete; + HashMap(HashMap&&); + HashMap& operator=(HashMap&&); // Accessors. uint64_t size() { return size_; } @@ -63,6 +62,21 @@ class HashMap { void ResizeIfNecessary(); }; +template +HashMap::HashMap(HashMap&& other) { + data_ = glcr::Move(other.data_); + size_ = other.size_; + other.size_ = 0; +} + +template +HashMap& HashMap::operator=(HashMap&& other) { + data_ = glcr::Move(other.data_); + size_ = other.size_; + other.size_ = 0; + return *this; +} + template V& HashMap::at(const K& key) { uint64_t hc = H()(key); @@ -74,7 +88,8 @@ V& HashMap::at(const K& key) { } } // TODO: Add a failure mode here instead of constructing an object. - ll.PushFront({key, {}}); + K k2 = key; + ll.PushFront({glcr::Move(k2), {}}); return ll.PeekFront().second(); } From e7cc98a20c382125d76a60a1931cf0613c78ba78 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 18:29:45 -0800 Subject: [PATCH 031/186] [Mammoth] Add the ability to duplicate an owned memory region. --- lib/mammoth/util/memory_region.cpp | 4 ++++ lib/mammoth/util/memory_region.h | 1 + 2 files changed, 5 insertions(+) diff --git a/lib/mammoth/util/memory_region.cpp b/lib/mammoth/util/memory_region.cpp index a4989f2..caa9eb9 100644 --- a/lib/mammoth/util/memory_region.cpp +++ b/lib/mammoth/util/memory_region.cpp @@ -71,4 +71,8 @@ z_cap_t OwnedMemoryRegion::DuplicateCap() { return cap; } +OwnedMemoryRegion OwnedMemoryRegion::Duplicate() { + return OwnedMemoryRegion::FromCapability(DuplicateCap()); +} + } // namespace mmth diff --git a/lib/mammoth/util/memory_region.h b/lib/mammoth/util/memory_region.h index 7af7d6c..37c34b5 100644 --- a/lib/mammoth/util/memory_region.h +++ b/lib/mammoth/util/memory_region.h @@ -30,6 +30,7 @@ class OwnedMemoryRegion { z_cap_t cap() const { return vmmo_cap_; } z_cap_t DuplicateCap(); + OwnedMemoryRegion Duplicate(); bool empty() const { return vmmo_cap_ == 0; } explicit operator bool() const { return vmmo_cap_ != 0; } From 7b8528ea99037a3ef0b31e474ebc64d16317ed88 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 18:29:51 -0800 Subject: [PATCH 032/186] [VictoriaFallS] Cache the results of reading inodes. This reduces the number of reads when starting up the OS by ~30% (32-23 for a basic use case). In the future we should cache things using a BTree in the VFS but this is sufficient for now. --- sys/victoriafalls/fs/ext2/ext2_driver.cpp | 14 ++++++++++---- sys/victoriafalls/fs/ext2/ext2_driver.h | 5 ++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.cpp b/sys/victoriafalls/fs/ext2/ext2_driver.cpp index 491ec80..9483838 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_driver.cpp @@ -56,7 +56,7 @@ glcr::ErrorOr> Ext2Driver::ReadDirectory( dbgln("Reading non directory."); return glcr::INVALID_ARGUMENT; } - ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion dir, ReadInode(inode)); + ASSIGN_OR_RETURN(mmth::OwnedMemoryRegion dir, ReadInode(inode_number, inode)); glcr::Vector directory; @@ -90,10 +90,14 @@ glcr::ErrorOr Ext2Driver::ReadFile( dbgln("Reading non file."); return glcr::INVALID_ARGUMENT; } - return ReadInode(inode); + return ReadInode(inode_number, inode); } -glcr::ErrorOr Ext2Driver::ReadInode(Inode* inode) { +glcr::ErrorOr 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; @@ -150,5 +154,7 @@ glcr::ErrorOr Ext2Driver::ReadInode(Inode* inode) { } } - return ext2_reader_->ReadBlocks(blocks_to_read); + 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; } diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.h b/sys/victoriafalls/fs/ext2/ext2_driver.h index e70ab84..b3600cc 100644 --- a/sys/victoriafalls/fs/ext2/ext2_driver.h +++ b/sys/victoriafalls/fs/ext2/ext2_driver.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -24,10 +25,12 @@ class Ext2Driver { private: glcr::SharedPtr ext2_reader_; glcr::UniquePtr inode_table_; + glcr::HashMap inode_cache_; Ext2Driver(const glcr::SharedPtr& reader, glcr::UniquePtr inode_table) : ext2_reader_(reader), inode_table_(glcr::Move(inode_table)) {} - glcr::ErrorOr ReadInode(Inode* inode); + glcr::ErrorOr ReadInode(uint64_t inode_num, + Inode* inode); }; From 8a711266ef8ab00ee20d59784ce13954abdacb6e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 19:02:15 -0800 Subject: [PATCH 033/186] [Zion] Fix init program loader debugging. --- zion/loader/init_loader.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index 7e1f16a..285fc37 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -90,7 +90,8 @@ void DumpModules() { dbgln("[boot] Dumping bootloader modules."); for (uint64_t i = 0; i < resp.module_count; i++) { const limine_file& file = *resp.modules[i]; - dbgln(" {},{x},{}", file.path, file.address, file.size); + dbgln(" {},{x},{x}", glcr::String(file.path), (uint64_t)file.address, + file.size); } #endif } @@ -111,6 +112,8 @@ void WriteInitProgram(glcr::RefPtr port, glcr::String name, uint64_t id) { const limine_file& prog = GetInitProgram(name); glcr::RefPtr prog_vmmo = glcr::MakeRefCounted(prog.size); + // TODO: These seem to be page aligned we should just construct an object + // around them. prog_vmmo->CopyBytesToObject(reinterpret_cast(prog.address), prog.size); port->WriteKernel(id, MakeRefCounted(prog_vmmo)); @@ -121,6 +124,10 @@ glcr::ErrorCode WritePciVmmo(glcr::RefPtr port, uint64_t id) { auto vmmo = glcr::MakeRefCounted(config.base, config.offset); +#if K_INIT_DEBUG + dbgln("PCI Configuration found at: {x}:{x}", config.base, config.offset); +#endif + port->WriteKernel(id, MakeRefCounted(vmmo)); return glcr::OK; From 9e9ef21a3df27192b1fe5098e7e9dccadfbe1f4f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 19:27:57 -0800 Subject: [PATCH 034/186] [Yunq] POC for moving yunq parsing to a library. --- lib/yunq/CMakeLists.txt | 1 + lib/yunq/message_view.cpp | 19 +++++++ lib/yunq/message_view.h | 40 ++++++++++++++ sys/denali/lib/denali/denali.yunq.cpp | 20 ++++--- .../lib/victoriafalls/victoriafalls.yunq.cpp | 28 +++++----- .../lib/voyageurs/voyageurs.yunq.cpp | 4 +- .../lib/yellowstone/yellowstone.yunq.cpp | 55 ++++++++++--------- yunq/message.cpp.jinja | 17 ++---- 8 files changed, 125 insertions(+), 59 deletions(-) create mode 100644 lib/yunq/message_view.cpp create mode 100644 lib/yunq/message_view.h diff --git a/lib/yunq/CMakeLists.txt b/lib/yunq/CMakeLists.txt index dea897d..5fd7a31 100644 --- a/lib/yunq/CMakeLists.txt +++ b/lib/yunq/CMakeLists.txt @@ -1,4 +1,5 @@ set(yunq_files + message_view.cpp serialize.cpp ) diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp new file mode 100644 index 0000000..6567f73 --- /dev/null +++ b/lib/yunq/message_view.cpp @@ -0,0 +1,19 @@ +#include "message_view.h" + +namespace yunq { + +template <> +glcr::ErrorOr MessageView::ReadField(uint64_t field_index) { + return buffer_.At(field_offset(field_index)); +} + +template <> +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index) { + ExtensionPointer ptr = + buffer_.At(field_offset(field_index)); + + return buffer_.StringAt(offset_ + ptr.offset, ptr.length); +} + +} // namespace yunq diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h new file mode 100644 index 0000000..ca68acf --- /dev/null +++ b/lib/yunq/message_view.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +namespace yunq { + +const uint64_t kHeaderSize = 24; // 4x uint32, 1x uint64 + +struct ExtensionPointer { + uint32_t offset; + uint32_t length; +}; + +class MessageView { + public: + MessageView(const glcr::ByteBuffer& buffer, uint64_t offset) + : buffer_(buffer), offset_(offset) {} + + // TODO: Implement glcr::StatusOr + template + glcr::ErrorOr ReadField(uint64_t field_index); + + private: + const glcr::ByteBuffer& buffer_; + uint64_t offset_; + + uint64_t field_offset(uint64_t field_index) { + return offset_ + kHeaderSize + (8 * field_index); + } +}; + +template <> +glcr::ErrorOr MessageView::ReadField(uint64_t field_index); + +template <> +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index); + +} // namespace yunq diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 0f6646b..eaf9f6c 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -1,6 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "denali.yunq.h" +#include #include @@ -26,12 +27,14 @@ glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t glcr::Status ReadRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse device_id. - set_device_id(bytes.At(offset + header_size + (8 * 0))); + ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); // Parse lba. - set_lba(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(lba_, view.ReadField(1)); // Parse size. - set_size(bytes.At(offset + header_size + (8 * 2))); + ASSIGN_OR_RETURN(size_, view.ReadField(2)); return glcr::Status::Ok(); } @@ -80,8 +83,10 @@ glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint glcr::Status ReadManyRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse device_id. - set_device_id(bytes.At(offset + header_size + (8 * 0))); + ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); // Parse lba. auto lba_pointer = bytes.At(offset + header_size + (8 * 1)); @@ -201,12 +206,13 @@ glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_ glcr::Status ReadResponse::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse device_id. - set_device_id(bytes.At(offset + header_size + (8 * 0))); + ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); // Parse size. - set_size(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(size_, view.ReadField(1)); // Parse memory. - // Skip Cap. return glcr::Status::Ok(); } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index 44c50b0..46f8899 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -1,6 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "victoriafalls.yunq.h" +#include #include @@ -26,10 +27,10 @@ glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint glcr::Status OpenFileRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse path. - auto path_pointer = bytes.At(offset + header_size + (8 * 0)); - set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse path. + ASSIGN_OR_RETURN(path_, view.ReadField(0)); return glcr::Status::Ok(); } @@ -95,14 +96,13 @@ glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uin glcr::Status OpenFileResponse::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse path. - auto path_pointer = bytes.At(offset + header_size + (8 * 0)); - set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse path. + ASSIGN_OR_RETURN(path_, view.ReadField(0)); // Parse size. - set_size(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(size_, view.ReadField(1)); // Parse memory. - // Skip Cap. return glcr::Status::Ok(); } @@ -171,10 +171,10 @@ glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse path. - auto path_pointer = bytes.At(offset + header_size + (8 * 0)); - set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse path. + ASSIGN_OR_RETURN(path_, view.ReadField(0)); return glcr::Status::Ok(); } @@ -233,10 +233,10 @@ glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t o glcr::Status Directory::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse filenames. - auto filenames_pointer = bytes.At(offset + header_size + (8 * 0)); - set_filenames(bytes.StringAt(offset + filenames_pointer.offset, filenames_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse filenames. + ASSIGN_OR_RETURN(filenames_, view.ReadField(0)); return glcr::Status::Ok(); } diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 3adfc57..563b0f6 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -1,6 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "voyageurs.yunq.h" +#include #include @@ -33,8 +34,9 @@ glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uin glcr::Status KeyboardListener::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse port_capability. - // Skip Cap. return glcr::Status::Ok(); } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 6b78856..3a5dc65 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -1,6 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "yellowstone.yunq.h" +#include #include @@ -35,12 +36,11 @@ glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& byt glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse endpoint_name. - auto endpoint_name_pointer = bytes.At(offset + header_size + (8 * 0)); - set_endpoint_name(bytes.StringAt(offset + endpoint_name_pointer.offset, endpoint_name_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse endpoint_name. + ASSIGN_OR_RETURN(endpoint_name_, view.ReadField(0)); // Parse endpoint_capability. - // Skip Cap. return glcr::Status::Ok(); } @@ -105,10 +105,10 @@ glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, u glcr::Status GetEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - // Parse endpoint_name. - auto endpoint_name_pointer = bytes.At(offset + header_size + (8 * 0)); - set_endpoint_name(bytes.StringAt(offset + endpoint_name_pointer.offset, endpoint_name_pointer.length)); + yunq::MessageView view(bytes, offset); + // Parse endpoint_name. + ASSIGN_OR_RETURN(endpoint_name_, view.ReadField(0)); return glcr::Status::Ok(); } @@ -174,8 +174,9 @@ glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of glcr::Status Endpoint::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse endpoint. - // Skip Cap. return glcr::Status::Ok(); } @@ -225,10 +226,11 @@ glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of glcr::Status AhciInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse ahci_region. - // Skip Cap. // Parse region_length. - set_region_length(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(region_length_, view.ReadField(1)); return glcr::Status::Ok(); } @@ -275,30 +277,32 @@ glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint glcr::Status FramebufferInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse address_phys. - set_address_phys(bytes.At(offset + header_size + (8 * 0))); + ASSIGN_OR_RETURN(address_phys_, view.ReadField(0)); // Parse width. - set_width(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(width_, view.ReadField(1)); // Parse height. - set_height(bytes.At(offset + header_size + (8 * 2))); + ASSIGN_OR_RETURN(height_, view.ReadField(2)); // Parse pitch. - set_pitch(bytes.At(offset + header_size + (8 * 3))); + ASSIGN_OR_RETURN(pitch_, view.ReadField(3)); // Parse bpp. - set_bpp(bytes.At(offset + header_size + (8 * 4))); + ASSIGN_OR_RETURN(bpp_, view.ReadField(4)); // Parse memory_model. - set_memory_model(bytes.At(offset + header_size + (8 * 5))); + ASSIGN_OR_RETURN(memory_model_, view.ReadField(5)); // Parse red_mask_size. - set_red_mask_size(bytes.At(offset + header_size + (8 * 6))); + ASSIGN_OR_RETURN(red_mask_size_, view.ReadField(6)); // Parse red_mask_shift. - set_red_mask_shift(bytes.At(offset + header_size + (8 * 7))); + ASSIGN_OR_RETURN(red_mask_shift_, view.ReadField(7)); // Parse green_mask_size. - set_green_mask_size(bytes.At(offset + header_size + (8 * 8))); + ASSIGN_OR_RETURN(green_mask_size_, view.ReadField(8)); // Parse green_mask_shift. - set_green_mask_shift(bytes.At(offset + header_size + (8 * 9))); + ASSIGN_OR_RETURN(green_mask_shift_, view.ReadField(9)); // Parse blue_mask_size. - set_blue_mask_size(bytes.At(offset + header_size + (8 * 10))); + ASSIGN_OR_RETURN(blue_mask_size_, view.ReadField(10)); // Parse blue_mask_shift. - set_blue_mask_shift(bytes.At(offset + header_size + (8 * 11))); + ASSIGN_OR_RETURN(blue_mask_shift_, view.ReadField(11)); return glcr::Status::Ok(); } @@ -390,12 +394,13 @@ glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t glcr::Status DenaliInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + + yunq::MessageView view(bytes, offset); // Parse denali_endpoint. - // Skip Cap. // Parse device_id. - set_device_id(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(device_id_, view.ReadField(1)); // Parse lba_offset. - set_lba_offset(bytes.At(offset + header_size + (8 * 2))); + ASSIGN_OR_RETURN(lba_offset_, view.ReadField(2)); return glcr::Status::Ok(); } diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 30f5556..42da094 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -1,6 +1,7 @@ // Generated file -- DO NOT MODIFY. #include "{{file}}.h" +#include #include {% if package != None %} @@ -48,21 +49,13 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin glcr::Status {{message.name}}::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + yunq::MessageView view(bytes, offset); + {%- for field in message.fields %} // Parse {{field.name}}. {%- if not field.repeated %} -{%- if field.type == Type.U64 %} - set_{{field.name}}(bytes.At(offset + header_size + (8 * {{loop.index0}}))); -{%- elif field.type == Type.I64 %} - set_{{field.name}}(bytes.At(offset + header_size + (8 * {{loop.index0}}))); -{%- elif field.type == Type.STRING %} - auto {{field.name}}_pointer = bytes.At(offset + header_size + (8 * {{loop.index0}})); - - set_{{field.name}}(bytes.StringAt(offset + {{field.name}}_pointer.offset, {{field.name}}_pointer.length)); -{%- elif field.type == Type.CAPABILITY %} - // Skip Cap. -{%- else %} - // TODO: Unimplemented parsing {{field.type}} +{%- if field.type != Type.CAPABILITY %} + ASSIGN_OR_RETURN({{field.name}}_, view.ReadField<{{field.cpp_type()}}>({{loop.index0}})); {%- endif %} {%- else %} auto {{field.name}}_pointer = bytes.At(offset + header_size + (8 * {{loop.index0}})); From 30b220b2fb153bc1b02cd893c5b4456fe6285d7d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 19:36:24 -0800 Subject: [PATCH 035/186] [Yunq] Move repeated field parsing to the yunq library. --- lib/yunq/message_view.cpp | 15 +++++++++++++++ lib/yunq/message_view.h | 8 ++++++++ sys/denali/lib/denali/denali.yunq.cpp | 18 ++---------------- yunq/message.cpp.jinja | 17 ++++++----------- 4 files changed, 31 insertions(+), 27 deletions(-) diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp index 6567f73..071e756 100644 --- a/lib/yunq/message_view.cpp +++ b/lib/yunq/message_view.cpp @@ -16,4 +16,19 @@ glcr::ErrorOr MessageView::ReadField( return buffer_.StringAt(offset_ + ptr.offset, ptr.length); } +template <> +glcr::ErrorOr> MessageView::ReadRepeated( + uint64_t field_index) { + ExtensionPointer pointer = + buffer_.At(field_offset(field_index)); + + glcr::Vector v; + v.Resize(pointer.length / sizeof(uint64_t)); + for (uint64_t i = offset_ + pointer.offset; + i < offset_ + pointer.offset + pointer.length; i += sizeof(uint64_t)) { + v.PushBack(buffer_.At(i)); + } + return v; +} + } // namespace yunq diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index ca68acf..24bdcc8 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace yunq { @@ -21,6 +22,9 @@ class MessageView { template glcr::ErrorOr ReadField(uint64_t field_index); + template + glcr::ErrorOr> ReadRepeated(uint64_t field_index); + private: const glcr::ByteBuffer& buffer_; uint64_t offset_; @@ -37,4 +41,8 @@ template <> glcr::ErrorOr MessageView::ReadField( uint64_t field_index); +template <> +glcr::ErrorOr> MessageView::ReadRepeated( + uint64_t field_index); + } // namespace yunq diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index eaf9f6c..66db996 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -88,24 +88,10 @@ glcr::Status ReadManyRequest::ParseFromBytesInternal(const glcr::ByteBuffer& byt // Parse device_id. ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); // Parse lba. - auto lba_pointer = bytes.At(offset + header_size + (8 * 1)); - - lba_.Resize(lba_pointer.length / sizeof(uint64_t)); - for (uint64_t i = offset + lba_pointer.offset; - i < offset + lba_pointer.offset + lba_pointer.length; - i += sizeof(uint64_t)) { - lba_.PushBack(bytes.At(i)); - } + ASSIGN_OR_RETURN(lba_, view.ReadRepeated(1)); // Parse sector_cnt. - auto sector_cnt_pointer = bytes.At(offset + header_size + (8 * 2)); - - sector_cnt_.Resize(sector_cnt_pointer.length / sizeof(uint64_t)); - for (uint64_t i = offset + sector_cnt_pointer.offset; - i < offset + sector_cnt_pointer.offset + sector_cnt_pointer.length; - i += sizeof(uint64_t)) { - sector_cnt_.PushBack(bytes.At(i)); - } + ASSIGN_OR_RETURN(sector_cnt_, view.ReadRepeated(2)); return glcr::Status::Ok(); diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 42da094..b736a6f 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -53,20 +53,15 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const glcr::ByteBuffer& by {%- for field in message.fields %} // Parse {{field.name}}. -{%- if not field.repeated %} {%- if field.type != Type.CAPABILITY %} - ASSIGN_OR_RETURN({{field.name}}_, view.ReadField<{{field.cpp_type()}}>({{loop.index0}})); -{%- endif %} -{%- else %} - auto {{field.name}}_pointer = bytes.At(offset + header_size + (8 * {{loop.index0}})); - {{field.name}}_.Resize({{field.name}}_pointer.length / sizeof({{field.cpp_type()}})); - for (uint64_t i = offset + {{field.name}}_pointer.offset; - i < offset + {{field.name}}_pointer.offset + {{field.name}}_pointer.length; - i += sizeof({{field.cpp_type()}})) { - {{field.name}}_.PushBack(bytes.At<{{field.cpp_type()}}>(i)); - } +{%- if not field.repeated %} + ASSIGN_OR_RETURN({{field.name}}_, view.ReadField<{{field.cpp_type()}}>({{loop.index0}})); +{%- else %} + ASSIGN_OR_RETURN({{field.name}}_, view.ReadRepeated<{{field.cpp_type()}}>({{loop.index0}})); {% endif %} + +{%- endif %} {%- endfor %} return glcr::Status::Ok(); From 0e6aa532a100337864dde15ffcf21ad34a377d44 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 19:51:18 -0800 Subject: [PATCH 036/186] [Yunq] Move MessageView higher in call stack. --- lib/yunq/message_view.cpp | 24 +++- lib/yunq/message_view.h | 24 +++- lib/yunq/serialize.cpp | 11 -- lib/yunq/serialize.h | 3 - sys/denali/lib/denali/denali.yunq.cpp | 52 ++++----- sys/denali/lib/denali/denali.yunq.h | 7 +- .../lib/victoriafalls/victoriafalls.yunq.cpp | 58 +++++----- .../lib/victoriafalls/victoriafalls.yunq.h | 9 +- .../lib/voyageurs/voyageurs.yunq.cpp | 12 +- sys/voyageurs/lib/voyageurs/voyageurs.yunq.h | 3 +- .../lib/yellowstone/yellowstone.yunq.cpp | 106 +++++++++--------- .../lib/yellowstone/yellowstone.yunq.h | 13 ++- yunq/message.cpp.jinja | 16 +-- yunq/message.h.jinja | 3 +- 14 files changed, 181 insertions(+), 160 deletions(-) diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp index 071e756..9cf2881 100644 --- a/lib/yunq/message_view.cpp +++ b/lib/yunq/message_view.cpp @@ -2,14 +2,32 @@ namespace yunq { +namespace { + +const uint64_t kIdentByte = 0x33441122; + +} // namespace + +glcr::Status MessageView::CheckHeader() const { + if (buffer_.At(offset_ + 0) != kIdentByte) { + return glcr::InvalidArgument("Trying to parse an invalid yunq message."); + } + // TODO: Parse core size. + // TODO: Parse extension size. + // TODO: Check CRC32 + // TODO: Parse options. + return glcr::Status::Ok(); +} + template <> -glcr::ErrorOr MessageView::ReadField(uint64_t field_index) { +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index) const { return buffer_.At(field_offset(field_index)); } template <> glcr::ErrorOr MessageView::ReadField( - uint64_t field_index) { + uint64_t field_index) const { ExtensionPointer ptr = buffer_.At(field_offset(field_index)); @@ -18,7 +36,7 @@ glcr::ErrorOr MessageView::ReadField( template <> glcr::ErrorOr> MessageView::ReadRepeated( - uint64_t field_index) { + uint64_t field_index) const { ExtensionPointer pointer = buffer_.At(field_offset(field_index)); diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index 24bdcc8..ee5aea1 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -3,11 +3,20 @@ #include #include #include +#include namespace yunq { const uint64_t kHeaderSize = 24; // 4x uint32, 1x uint64 +struct MessageHeader { + uint32_t ident; + uint32_t core_length; + uint32_t length; + uint32_t crc32; + uint64_t options; +} __attribute__((packed)); + struct ExtensionPointer { uint32_t offset; uint32_t length; @@ -18,31 +27,34 @@ class MessageView { MessageView(const glcr::ByteBuffer& buffer, uint64_t offset) : buffer_(buffer), offset_(offset) {} + [[nodiscard]] glcr::Status CheckHeader() const; + // TODO: Implement glcr::StatusOr template - glcr::ErrorOr ReadField(uint64_t field_index); + glcr::ErrorOr ReadField(uint64_t field_index) const; template - glcr::ErrorOr> ReadRepeated(uint64_t field_index); + glcr::ErrorOr> ReadRepeated(uint64_t field_index) const; private: const glcr::ByteBuffer& buffer_; uint64_t offset_; - uint64_t field_offset(uint64_t field_index) { + uint64_t field_offset(uint64_t field_index) const { return offset_ + kHeaderSize + (8 * field_index); } }; template <> -glcr::ErrorOr MessageView::ReadField(uint64_t field_index); +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index) const; template <> glcr::ErrorOr MessageView::ReadField( - uint64_t field_index); + uint64_t field_index) const; template <> glcr::ErrorOr> MessageView::ReadRepeated( - uint64_t field_index); + uint64_t field_index) const; } // namespace yunq diff --git a/lib/yunq/serialize.cpp b/lib/yunq/serialize.cpp index afaad06..749063b 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -7,17 +7,6 @@ const uint64_t kIdentByte = 0x33441122; } // namespace -glcr::Status CheckHeader(const glcr::ByteBuffer& buffer, uint64_t offset) { - if (buffer.At(offset + 0) != kIdentByte) { - return glcr::InvalidArgument("Trying to parse an invalid yunq message."); - } - // TODO: Parse core size. - // TODO: Parse extension size. - // TODO: Check CRC32 - // TODO: Parse options. - return glcr::Status::Ok(); -} - void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size) { bytes.WriteAt(offset + 0, kIdentByte); diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index 2e90779..cdb76c1 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -5,9 +5,6 @@ namespace yunq { -[[nodiscard]] glcr::Status CheckHeader(const glcr::ByteBuffer& buffer, - uint64_t offset); - void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size); diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 66db996..b142571 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -16,25 +16,25 @@ struct ExtPointer { } // namespace glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status ReadRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status ReadRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse device_id. - ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); + ASSIGN_OR_RETURN(device_id_, message.ReadField(0)); // Parse lba. - ASSIGN_OR_RETURN(lba_, view.ReadField(1)); + ASSIGN_OR_RETURN(lba_, message.ReadField(1)); // Parse size. - ASSIGN_OR_RETURN(size_, view.ReadField(2)); + ASSIGN_OR_RETURN(size_, message.ReadField(2)); return glcr::Status::Ok(); } @@ -72,26 +72,26 @@ uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, return next_extension; } glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status ReadManyRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status ReadManyRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse device_id. - ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); + ASSIGN_OR_RETURN(device_id_, message.ReadField(0)); // Parse lba. - ASSIGN_OR_RETURN(lba_, view.ReadRepeated(1)); + ASSIGN_OR_RETURN(lba_, message.ReadRepeated(1)); // Parse sector_cnt. - ASSIGN_OR_RETURN(sector_cnt_, view.ReadRepeated(2)); + ASSIGN_OR_RETURN(sector_cnt_, message.ReadRepeated(2)); return glcr::Status::Ok(); @@ -174,7 +174,8 @@ uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_memory(0); @@ -182,7 +183,8 @@ glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_ } glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); @@ -190,14 +192,12 @@ glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_ return glcr::Status::Ok(); } -glcr::Status ReadResponse::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status ReadResponse::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse device_id. - ASSIGN_OR_RETURN(device_id_, view.ReadField(0)); + ASSIGN_OR_RETURN(device_id_, message.ReadField(0)); // Parse size. - ASSIGN_OR_RETURN(size_, view.ReadField(1)); + ASSIGN_OR_RETURN(size_, message.ReadField(1)); // Parse memory. return glcr::Status::Ok(); diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h index 414c807..3e5973f 100644 --- a/sys/denali/lib/denali/denali.yunq.h +++ b/sys/denali/lib/denali/denali.yunq.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -33,7 +34,7 @@ class ReadRequest { uint64_t size_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class ReadManyRequest { public: @@ -59,7 +60,7 @@ class ReadManyRequest { glcr::Vector sector_cnt_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class ReadResponse { public: @@ -85,6 +86,6 @@ class ReadResponse { z_cap_t memory_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index 46f8899..e0b91cb 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -16,21 +16,21 @@ struct ExtPointer { } // namespace glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status OpenFileRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status OpenFileRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse path. - ASSIGN_OR_RETURN(path_, view.ReadField(0)); + ASSIGN_OR_RETURN(path_, message.ReadField(0)); return glcr::Status::Ok(); } @@ -78,7 +78,8 @@ uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_memory(0); @@ -86,7 +87,8 @@ glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uin } glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); @@ -94,14 +96,12 @@ glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uin return glcr::Status::Ok(); } -glcr::Status OpenFileResponse::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status OpenFileResponse::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse path. - ASSIGN_OR_RETURN(path_, view.ReadField(0)); + ASSIGN_OR_RETURN(path_, message.ReadField(0)); // Parse size. - ASSIGN_OR_RETURN(size_, view.ReadField(1)); + ASSIGN_OR_RETURN(size_, message.ReadField(1)); // Parse memory. return glcr::Status::Ok(); @@ -160,21 +160,21 @@ uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of return next_extension; } glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse path. - ASSIGN_OR_RETURN(path_, view.ReadField(0)); + ASSIGN_OR_RETURN(path_, message.ReadField(0)); return glcr::Status::Ok(); } @@ -222,21 +222,21 @@ uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t return next_extension; } glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status Directory::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status Directory::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse filenames. - ASSIGN_OR_RETURN(filenames_, view.ReadField(0)); + ASSIGN_OR_RETURN(filenames_, message.ReadField(0)); return glcr::Status::Ok(); } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h index 7549408..0b54d3b 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -27,7 +28,7 @@ class OpenFileRequest { glcr::String path_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class OpenFileResponse { public: @@ -53,7 +54,7 @@ class OpenFileResponse { z_cap_t memory_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class GetDirectoryRequest { public: @@ -73,7 +74,7 @@ class GetDirectoryRequest { glcr::String path_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class Directory { public: @@ -93,6 +94,6 @@ class Directory { glcr::String filenames_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 563b0f6..576c32d 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -16,7 +16,8 @@ struct ExtPointer { } // namespace glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_port_capability(0); @@ -24,7 +25,8 @@ glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uin } glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. uint64_t port_capability_ptr = bytes.At(offset + header_size + (8 * 0)); @@ -32,10 +34,8 @@ glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uin return glcr::Status::Ok(); } -glcr::Status KeyboardListener::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status KeyboardListener::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse port_capability. return glcr::Status::Ok(); diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h index da5c585..7abc356 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -27,6 +28,6 @@ class KeyboardListener { z_cap_t port_capability_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 3a5dc65..54d707f 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -18,7 +18,8 @@ struct ExtPointer { } // namespace glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_endpoint_capability(0); @@ -26,7 +27,8 @@ glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& byt } glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. uint64_t endpoint_capability_ptr = bytes.At(offset + header_size + (8 * 1)); @@ -34,12 +36,10 @@ glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& byt return glcr::Status::Ok(); } -glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse endpoint_name. - ASSIGN_OR_RETURN(endpoint_name_, view.ReadField(0)); + ASSIGN_OR_RETURN(endpoint_name_, message.ReadField(0)); // Parse endpoint_capability. return glcr::Status::Ok(); @@ -94,21 +94,21 @@ uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint return next_extension; } glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status GetEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status GetEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse endpoint_name. - ASSIGN_OR_RETURN(endpoint_name_, view.ReadField(0)); + ASSIGN_OR_RETURN(endpoint_name_, message.ReadField(0)); return glcr::Status::Ok(); } @@ -156,7 +156,8 @@ uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t return next_extension; } glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_endpoint(0); @@ -164,7 +165,8 @@ glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of } glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. uint64_t endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); @@ -172,10 +174,8 @@ glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of return glcr::Status::Ok(); } -glcr::Status Endpoint::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status Endpoint::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse endpoint. return glcr::Status::Ok(); @@ -208,7 +208,8 @@ uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, gl return next_extension; } glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_ahci_region(0); @@ -216,7 +217,8 @@ glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of } glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. uint64_t ahci_region_ptr = bytes.At(offset + header_size + (8 * 0)); @@ -224,13 +226,11 @@ glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of return glcr::Status::Ok(); } -glcr::Status AhciInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status AhciInfo::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse ahci_region. // Parse region_length. - ASSIGN_OR_RETURN(region_length_, view.ReadField(1)); + ASSIGN_OR_RETURN(region_length_, message.ReadField(1)); return glcr::Status::Ok(); } @@ -266,43 +266,43 @@ uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, gl return next_extension; } glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status FramebufferInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status FramebufferInfo::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse address_phys. - ASSIGN_OR_RETURN(address_phys_, view.ReadField(0)); + ASSIGN_OR_RETURN(address_phys_, message.ReadField(0)); // Parse width. - ASSIGN_OR_RETURN(width_, view.ReadField(1)); + ASSIGN_OR_RETURN(width_, message.ReadField(1)); // Parse height. - ASSIGN_OR_RETURN(height_, view.ReadField(2)); + ASSIGN_OR_RETURN(height_, message.ReadField(2)); // Parse pitch. - ASSIGN_OR_RETURN(pitch_, view.ReadField(3)); + ASSIGN_OR_RETURN(pitch_, message.ReadField(3)); // Parse bpp. - ASSIGN_OR_RETURN(bpp_, view.ReadField(4)); + ASSIGN_OR_RETURN(bpp_, message.ReadField(4)); // Parse memory_model. - ASSIGN_OR_RETURN(memory_model_, view.ReadField(5)); + ASSIGN_OR_RETURN(memory_model_, message.ReadField(5)); // Parse red_mask_size. - ASSIGN_OR_RETURN(red_mask_size_, view.ReadField(6)); + ASSIGN_OR_RETURN(red_mask_size_, message.ReadField(6)); // Parse red_mask_shift. - ASSIGN_OR_RETURN(red_mask_shift_, view.ReadField(7)); + ASSIGN_OR_RETURN(red_mask_shift_, message.ReadField(7)); // Parse green_mask_size. - ASSIGN_OR_RETURN(green_mask_size_, view.ReadField(8)); + ASSIGN_OR_RETURN(green_mask_size_, message.ReadField(8)); // Parse green_mask_shift. - ASSIGN_OR_RETURN(green_mask_shift_, view.ReadField(9)); + ASSIGN_OR_RETURN(green_mask_shift_, message.ReadField(9)); // Parse blue_mask_size. - ASSIGN_OR_RETURN(blue_mask_size_, view.ReadField(10)); + ASSIGN_OR_RETURN(blue_mask_size_, message.ReadField(10)); // Parse blue_mask_shift. - ASSIGN_OR_RETURN(blue_mask_shift_, view.ReadField(11)); + ASSIGN_OR_RETURN(blue_mask_shift_, message.ReadField(11)); return glcr::Status::Ok(); } @@ -376,7 +376,8 @@ uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. // FIXME: Implement in-buffer capabilities for inprocess serialization. set_denali_endpoint(0); @@ -384,7 +385,8 @@ glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t } glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. uint64_t denali_endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); @@ -392,15 +394,13 @@ glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t return glcr::Status::Ok(); } -glcr::Status DenaliInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status DenaliInfo::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse denali_endpoint. // Parse device_id. - ASSIGN_OR_RETURN(device_id_, view.ReadField(1)); + ASSIGN_OR_RETURN(device_id_, message.ReadField(1)); // Parse lba_offset. - ASSIGN_OR_RETURN(lba_offset_, view.ReadField(2)); + ASSIGN_OR_RETURN(lba_offset_, message.ReadField(2)); return glcr::Status::Ok(); } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index 3fb2f88..01af62b 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -32,7 +33,7 @@ class RegisterEndpointRequest { z_cap_t endpoint_capability_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class GetEndpointRequest { public: @@ -52,7 +53,7 @@ class GetEndpointRequest { glcr::String endpoint_name_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class Endpoint { public: @@ -72,7 +73,7 @@ class Endpoint { z_cap_t endpoint_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class AhciInfo { public: @@ -95,7 +96,7 @@ class AhciInfo { uint64_t region_length_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class FramebufferInfo { public: @@ -148,7 +149,7 @@ class FramebufferInfo { uint64_t blue_mask_shift_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; class DenaliInfo { public: @@ -174,7 +175,7 @@ class DenaliInfo { uint64_t lba_offset_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index b736a6f..0c4f002 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -20,7 +20,8 @@ struct ExtPointer { {%- for message in messages %} glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} @@ -33,7 +34,8 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin } glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + yunq::MessageView message(bytes, offset); + RETURN_ERROR(ParseFromBytesInternal(message)); {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} @@ -46,19 +48,17 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin return glcr::Status::Ok(); } -glcr::Status {{message.name}}::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - RETURN_ERROR(yunq::CheckHeader(bytes, offset)); - - yunq::MessageView view(bytes, offset); +glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); {%- for field in message.fields %} // Parse {{field.name}}. {%- if field.type != Type.CAPABILITY %} {%- if not field.repeated %} - ASSIGN_OR_RETURN({{field.name}}_, view.ReadField<{{field.cpp_type()}}>({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadField<{{field.cpp_type()}}>({{loop.index0}})); {%- else %} - ASSIGN_OR_RETURN({{field.name}}_, view.ReadRepeated<{{field.cpp_type()}}>({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeated<{{field.cpp_type()}}>({{loop.index0}})); {% endif %} {%- endif %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index cf15b59..e98cfb5 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -6,6 +6,7 @@ #include #include #include +#include #include {% if package != None %} @@ -45,7 +46,7 @@ class {{message.name}} { {%- endfor %} // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); }; {%- endfor %} From 75d84a0fa5f2f9b93814b70a3aaa1be112dd4273 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 19:59:36 -0800 Subject: [PATCH 037/186] [Yunq] Read capabilities using the parsing library. --- lib/yunq/message_view.cpp | 10 +++++++ lib/yunq/message_view.h | 5 ++++ sys/denali/lib/denali/denali.yunq.cpp | 7 ++--- .../lib/victoriafalls/victoriafalls.yunq.cpp | 7 ++--- .../lib/voyageurs/voyageurs.yunq.cpp | 7 ++--- .../lib/yellowstone/yellowstone.yunq.cpp | 28 ++++++------------- yunq/message.cpp.jinja | 17 +++++++---- 7 files changed, 41 insertions(+), 40 deletions(-) diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp index 9cf2881..5e74430 100644 --- a/lib/yunq/message_view.cpp +++ b/lib/yunq/message_view.cpp @@ -49,4 +49,14 @@ glcr::ErrorOr> MessageView::ReadRepeated( return v; } +glcr::ErrorOr MessageView::ReadCapability( + uint64_t field_index) const { + return buffer_.At(field_offset(field_index)); +} + +glcr::ErrorOr MessageView::ReadCapability( + uint64_t field_index, const glcr::CapBuffer& caps) const { + uint64_t offset = buffer_.At(field_offset(field_index)); + return caps.At(offset); +} } // namespace yunq diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index ee5aea1..85c5fb6 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -36,6 +37,10 @@ class MessageView { template glcr::ErrorOr> ReadRepeated(uint64_t field_index) const; + glcr::ErrorOr ReadCapability(uint64_t field_index) const; + glcr::ErrorOr ReadCapability(uint64_t field_index, + const glcr::CapBuffer& caps) const; + private: const glcr::ByteBuffer& buffer_; uint64_t offset_; diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index b142571..9a56e3a 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -177,8 +177,7 @@ glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_ yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_memory(0); + ASSIGN_OR_RETURN(memory_, message.ReadCapability(2)); return glcr::Status::Ok(); } @@ -186,9 +185,7 @@ glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_ yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. - uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); - - set_memory(caps.At(memory_ptr)); + ASSIGN_OR_RETURN(memory_, message.ReadCapability(2, caps)); return glcr::Status::Ok(); } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index e0b91cb..5bf0b5d 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -81,8 +81,7 @@ glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uin yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_memory(0); + ASSIGN_OR_RETURN(memory_, message.ReadCapability(2)); return glcr::Status::Ok(); } @@ -90,9 +89,7 @@ glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uin yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse memory. - uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); - - set_memory(caps.At(memory_ptr)); + ASSIGN_OR_RETURN(memory_, message.ReadCapability(2, caps)); return glcr::Status::Ok(); } diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 576c32d..1214c2f 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -19,8 +19,7 @@ glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uin yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_port_capability(0); + ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0)); return glcr::Status::Ok(); } @@ -28,9 +27,7 @@ glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uin yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. - uint64_t port_capability_ptr = bytes.At(offset + header_size + (8 * 0)); - - set_port_capability(caps.At(port_capability_ptr)); + ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0, caps)); return glcr::Status::Ok(); } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 54d707f..ec2dffa 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -21,8 +21,7 @@ glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& byt yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_endpoint_capability(0); + ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1)); return glcr::Status::Ok(); } @@ -30,9 +29,7 @@ glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& byt yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. - uint64_t endpoint_capability_ptr = bytes.At(offset + header_size + (8 * 1)); - - set_endpoint_capability(caps.At(endpoint_capability_ptr)); + ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1, caps)); return glcr::Status::Ok(); } @@ -159,8 +156,7 @@ glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_endpoint(0); + ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0)); return glcr::Status::Ok(); } @@ -168,9 +164,7 @@ glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. - uint64_t endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); - - set_endpoint(caps.At(endpoint_ptr)); + ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0, caps)); return glcr::Status::Ok(); } @@ -211,8 +205,7 @@ glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_ahci_region(0); + ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0)); return glcr::Status::Ok(); } @@ -220,9 +213,7 @@ glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t of yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. - uint64_t ahci_region_ptr = bytes.At(offset + header_size + (8 * 0)); - - set_ahci_region(caps.At(ahci_region_ptr)); + ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0, caps)); return glcr::Status::Ok(); } @@ -379,8 +370,7 @@ glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_denali_endpoint(0); + ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0)); return glcr::Status::Ok(); } @@ -388,9 +378,7 @@ glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t yunq::MessageView message(bytes, offset); RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. - uint64_t denali_endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); - - set_denali_endpoint(caps.At(denali_endpoint_ptr)); + ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0, caps)); return glcr::Status::Ok(); } diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 0c4f002..67919e9 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -25,9 +25,13 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} +{%- if not field.repeated %} // Parse {{field.name}}. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_{{field.name}}(0); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{loop.index0}})); + {%- else %} + // Parse {{field.name}}. + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{loop.index0}})); + {%- endif %} {%- endif %} {%- endfor %} return glcr::Status::Ok(); @@ -39,10 +43,13 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} +{%- if not field.repeated %} // Parse {{field.name}}. - uint64_t {{field.name}}_ptr = bytes.At(offset + header_size + (8 * {{loop.index0}})); - - set_{{field.name}}(caps.At({{field.name}}_ptr)); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{loop.index0}}, caps)); + {%- else %} + // Parse {{field.name}}. + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{loop.index0}}, caps)); + {%- endif %} {%- endif %} {%- endfor %} return glcr::Status::Ok(); From 0135d8d844f92ba5fc9b13a62f9356131b5904ca Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:03:34 -0800 Subject: [PATCH 038/186] [Yunq] Accept a message view on message parsing. --- sys/denali/lib/denali/denali.yunq.client.cpp | 6 ++-- sys/denali/lib/denali/denali.yunq.cpp | 18 ++++------ sys/denali/lib/denali/denali.yunq.h | 12 +++---- sys/denali/lib/denali/denali.yunq.server.cpp | 6 ++-- .../victoriafalls.yunq.client.cpp | 6 ++-- .../lib/victoriafalls/victoriafalls.yunq.cpp | 24 +++++-------- .../lib/victoriafalls/victoriafalls.yunq.h | 16 ++++----- .../victoriafalls.yunq.server.cpp | 6 ++-- .../lib/voyageurs/voyageurs.yunq.cpp | 6 ++-- sys/voyageurs/lib/voyageurs/voyageurs.yunq.h | 4 +-- .../lib/voyageurs/voyageurs.yunq.server.cpp | 3 +- .../yellowstone/yellowstone.yunq.client.cpp | 12 ++++--- .../lib/yellowstone/yellowstone.yunq.cpp | 36 +++++++------------ .../lib/yellowstone/yellowstone.yunq.h | 24 ++++++------- .../yellowstone/yellowstone.yunq.server.cpp | 6 ++-- yunq/client.cpp.jinja | 3 +- yunq/message.cpp.jinja | 6 ++-- yunq/message.h.jinja | 4 +-- yunq/server.cpp.jinja | 3 +- 19 files changed, 94 insertions(+), 107 deletions(-) diff --git a/sys/denali/lib/denali/denali.yunq.client.cpp b/sys/denali/lib/denali/denali.yunq.client.cpp index af49317..09e6f6a 100644 --- a/sys/denali/lib/denali/denali.yunq.client.cpp +++ b/sys/denali/lib/denali/denali.yunq.client.cpp @@ -48,7 +48,8 @@ glcr::Status DenaliClient::Read(const ReadRequest& request, ReadResponse& respon RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; @@ -87,7 +88,8 @@ glcr::Status DenaliClient::ReadMany(const ReadManyRequest& request, ReadResponse RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 9a56e3a..ffdc39a 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -15,14 +15,12 @@ struct ExtPointer { }; } // namespace -glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status ReadRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status ReadRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -71,14 +69,12 @@ uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, return next_extension; } -glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status ReadManyRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status ReadManyRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -173,16 +169,14 @@ uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } -glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +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 glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +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)); diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h index 3e5973f..a32d782 100644 --- a/sys/denali/lib/denali/denali.yunq.h +++ b/sys/denali/lib/denali/denali.yunq.h @@ -17,8 +17,8 @@ class ReadRequest { ReadRequest(const ReadRequest&) = delete; ReadRequest(ReadRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -43,8 +43,8 @@ class ReadManyRequest { ReadManyRequest(const ReadManyRequest&) = delete; ReadManyRequest(ReadManyRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -69,8 +69,8 @@ class ReadResponse { ReadResponse(const ReadResponse&) = delete; ReadResponse(ReadResponse&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } diff --git a/sys/denali/lib/denali/denali.yunq.server.cpp b/sys/denali/lib/denali/denali.yunq.server.cpp index 9f9764e..4fe21f5 100644 --- a/sys/denali/lib/denali/denali.yunq.server.cpp +++ b/sys/denali/lib/denali/denali.yunq.server.cpp @@ -104,7 +104,8 @@ glcr::Status DenaliServerBase::HandleRequest(const glcr::ByteBuffer& request, ReadRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); @@ -124,7 +125,8 @@ glcr::Status DenaliServerBase::HandleRequest(const glcr::ByteBuffer& request, ReadManyRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp index aa289d2..dec023a 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp @@ -48,7 +48,8 @@ glcr::Status VFSClient::OpenFile(const OpenFileRequest& request, OpenFileRespons RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; @@ -87,7 +88,8 @@ glcr::Status VFSClient::GetDirectory(const GetDirectoryRequest& request, Directo RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index 5bf0b5d..0c0d70b 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -15,14 +15,12 @@ struct ExtPointer { }; } // namespace -glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -77,16 +75,14 @@ uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } -glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +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 glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +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)); @@ -156,14 +152,12 @@ uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t of return next_extension; } -glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status GetDirectoryRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status GetDirectoryRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -218,14 +212,12 @@ uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t return next_extension; } -glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status Directory::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status Directory::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h index 0b54d3b..5a294fc 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -17,8 +17,8 @@ class OpenFileRequest { OpenFileRequest(const OpenFileRequest&) = delete; OpenFileRequest(OpenFileRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -37,8 +37,8 @@ class OpenFileResponse { OpenFileResponse(const OpenFileResponse&) = delete; OpenFileResponse(OpenFileResponse&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -63,8 +63,8 @@ class GetDirectoryRequest { GetDirectoryRequest(const GetDirectoryRequest&) = delete; GetDirectoryRequest(GetDirectoryRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -83,8 +83,8 @@ class Directory { Directory(const Directory&) = delete; Directory(Directory&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp index 85a8a73..f5e7061 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp @@ -104,7 +104,8 @@ glcr::Status VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, OpenFileRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); @@ -124,7 +125,8 @@ glcr::Status VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, GetDirectoryRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 1214c2f..863a0d9 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -15,16 +15,14 @@ struct ExtPointer { }; } // namespace -glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status KeyboardListener::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0)); return glcr::Status::Ok(); } -glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status KeyboardListener::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse port_capability. ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0, caps)); diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h index 7abc356..727b31b 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -17,8 +17,8 @@ class KeyboardListener { KeyboardListener(const KeyboardListener&) = delete; KeyboardListener(KeyboardListener&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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 z_cap_t& port_capability() const { return port_capability_; } diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp index f8376dc..80fa141 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp @@ -104,7 +104,8 @@ glcr::Status VoyageursServerBase::HandleRequest(const glcr::ByteBuffer& request, KeyboardListener yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp index d7baf54..03352e1 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp @@ -87,7 +87,8 @@ glcr::Status YellowstoneClient::GetEndpoint(const GetEndpointRequest& request, E RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; @@ -126,7 +127,8 @@ glcr::Status YellowstoneClient::GetAhciInfo(AhciInfo& response) { RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; @@ -165,7 +167,8 @@ glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; @@ -204,7 +207,8 @@ glcr::Status YellowstoneClient::GetDenali(DenaliInfo& response) { RET_ERR(buffer_.At(8)); - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index ec2dffa..0b21546 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -17,16 +17,14 @@ struct ExtPointer { }; } // namespace -glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status RegisterEndpointRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1)); return glcr::Status::Ok(); } -glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status RegisterEndpointRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint_capability. ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1, caps)); @@ -90,14 +88,12 @@ uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint return next_extension; } -glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status GetEndpointRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status GetEndpointRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -152,16 +148,14 @@ uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t return next_extension; } -glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status Endpoint::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0)); return glcr::Status::Ok(); } -glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status Endpoint::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse endpoint. ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0, caps)); @@ -201,16 +195,14 @@ uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, gl return next_extension; } -glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status AhciInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0)); return glcr::Status::Ok(); } -glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status AhciInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse ahci_region. ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0, caps)); @@ -256,14 +248,12 @@ uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, gl return next_extension; } -glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status FramebufferInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } -glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status FramebufferInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); } @@ -366,16 +356,14 @@ uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t off return next_extension; } -glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status DenaliInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0)); return glcr::Status::Ok(); } -glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status DenaliInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); // Parse denali_endpoint. ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0, caps)); diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index 01af62b..c69b5a2 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -19,8 +19,8 @@ class RegisterEndpointRequest { RegisterEndpointRequest(const RegisterEndpointRequest&) = delete; RegisterEndpointRequest(RegisterEndpointRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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& endpoint_name() const { return endpoint_name_; } @@ -42,8 +42,8 @@ class GetEndpointRequest { GetEndpointRequest(const GetEndpointRequest&) = delete; GetEndpointRequest(GetEndpointRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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& endpoint_name() const { return endpoint_name_; } @@ -62,8 +62,8 @@ class Endpoint { Endpoint(const Endpoint&) = delete; Endpoint(Endpoint&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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 z_cap_t& endpoint() const { return endpoint_; } @@ -82,8 +82,8 @@ class AhciInfo { AhciInfo(const AhciInfo&) = delete; AhciInfo(AhciInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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 z_cap_t& ahci_region() const { return ahci_region_; } @@ -105,8 +105,8 @@ class FramebufferInfo { FramebufferInfo(const FramebufferInfo&) = delete; FramebufferInfo(FramebufferInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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& address_phys() const { return address_phys_; } @@ -158,8 +158,8 @@ class DenaliInfo { DenaliInfo(const DenaliInfo&) = delete; DenaliInfo(DenaliInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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 z_cap_t& denali_endpoint() const { return denali_endpoint_; } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp index c0205ae..d410658 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp @@ -106,7 +106,8 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques RegisterEndpointRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); @@ -124,7 +125,8 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques GetEndpointRequest yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); diff --git a/yunq/client.cpp.jinja b/yunq/client.cpp.jinja index 0643ad6..63721e0 100644 --- a/yunq/client.cpp.jinja +++ b/yunq/client.cpp.jinja @@ -56,7 +56,8 @@ glcr::Status {{interface.name}}Client::{{method.name}}(const {{method.request}}& RET_ERR(buffer_.At(8)); {% if method.response != None %} - RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); {% endif %} return glcr::OK; diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 67919e9..403188e 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -19,8 +19,7 @@ struct ExtPointer { } // namespace {%- for message in messages %} -glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - yunq::MessageView message(bytes, offset); +glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); {%- for field in message.fields %} @@ -37,8 +36,7 @@ glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uin return glcr::Status::Ok(); } -glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - yunq::MessageView message(bytes, offset); +glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { RETURN_ERROR(ParseFromBytesInternal(message)); {%- for field in message.fields %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index e98cfb5..79d47cd 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -21,8 +21,8 @@ class {{message.name}} { {{message.name}}(const {{message.name}}&) = delete; {{message.name}}({{message.name}}&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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; diff --git a/yunq/server.cpp.jinja b/yunq/server.cpp.jinja index 6f8a712..734166d 100644 --- a/yunq/server.cpp.jinja +++ b/yunq/server.cpp.jinja @@ -107,7 +107,8 @@ glcr::Status {{interface.name}}ServerBase::HandleRequest(const glcr::ByteBuffer& {% if method.request != None %} {{method.request}} yunq_request; - RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); {% endif %} {% if method.response != None %} From 7ec4f696a80cda1afb4b68dcf357da6c70bbf87f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:36:41 -0800 Subject: [PATCH 039/186] [Yunq] Move serialization to yunq library. --- lib/yunq/message_view.h | 17 +- lib/yunq/serialize.cpp | 38 ++- lib/yunq/serialize.h | 77 +++++- lib/yunq/yunq.h | 22 ++ sys/denali/lib/denali/denali.yunq.cpp | 133 +++------- .../lib/victoriafalls/victoriafalls.yunq.cpp | 166 +++---------- .../lib/voyageurs/voyageurs.yunq.cpp | 23 +- .../lib/yellowstone/yellowstone.yunq.cpp | 230 ++++++------------ yunq/message.cpp.jinja | 96 ++------ 9 files changed, 316 insertions(+), 486 deletions(-) create mode 100644 lib/yunq/yunq.h diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index 85c5fb6..996ba8f 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -6,23 +6,10 @@ #include #include +#include "yunq/yunq.h" + namespace yunq { -const uint64_t kHeaderSize = 24; // 4x uint32, 1x uint64 - -struct MessageHeader { - uint32_t ident; - uint32_t core_length; - uint32_t length; - uint32_t crc32; - uint64_t options; -} __attribute__((packed)); - -struct ExtensionPointer { - uint32_t offset; - uint32_t length; -}; - class MessageView { public: MessageView(const glcr::ByteBuffer& buffer, uint64_t offset) diff --git a/lib/yunq/serialize.cpp b/lib/yunq/serialize.cpp index 749063b..6522ab3 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -7,12 +7,38 @@ const uint64_t kIdentByte = 0x33441122; } // namespace -void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, - uint32_t extension_size) { - bytes.WriteAt(offset + 0, kIdentByte); - bytes.WriteAt(offset + 4, core_size); - bytes.WriteAt(offset + 8, extension_size); - bytes.WriteAt(offset + 12, 0); // TODO: Calculate CRC32. +void Serializer::WriteHeader() { + buffer_.WriteAt(offset_ + 0, kIdentByte); + buffer_.WriteAt(offset_ + 4, core_size_); + buffer_.WriteAt(offset_ + 8, next_extension_); + buffer_.WriteAt(offset_ + 12, 0); // TODO: Calculate CRC32. } +template <> +void Serializer::WriteField(uint64_t field_index, + const glcr::String& value) { + ExtensionPointer ptr{ + .offset = (uint32_t)next_extension_, + // FIXME: Check downcast of str length. + .length = (uint32_t)value.length(), + }; + + buffer_.WriteStringAt(offset_ + next_extension_, value); + next_extension_ += ptr.length; + + buffer_.WriteAt(field_offset(field_index), ptr); +} + +void Serializer::WriteCapability(uint64_t field_index, uint64_t value) { + if (caps_) { + buffer_.WriteAt(field_offset(field_index), next_cap_); + caps_.value().get().WriteAt(next_cap_++, value); + } else { + WriteField(field_index, value); + } +} + +void Serializer::WriteRepeatedCapability(uint64_t field_index, + const glcr::Vector& value) {} + } // namespace yunq diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index cdb76c1..ae6a77b 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -1,11 +1,84 @@ #pragma once #include +#include +#include +#include +#include #include +#include "yunq/yunq.h" + namespace yunq { -void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, - uint32_t extension_size); +class Serializer { + public: + Serializer(glcr::ByteBuffer& bytes, uint64_t offset, uint64_t num_fields) + : buffer_(bytes), + offset_(offset), + next_extension_(kHeaderSize + (8 * num_fields)), + core_size_(next_extension_), + caps_() {} + Serializer(glcr::ByteBuffer& bytes, uint64_t offset, uint64_t num_fields, + glcr::CapBuffer& caps) + : buffer_(bytes), + offset_(offset), + next_extension_(kHeaderSize + (8 * num_fields)), + core_size_(next_extension_), + caps_(caps) {} + + template + void WriteField(uint64_t field_index, const T& value); + + template + void WriteRepeated(uint64_t field_index, const glcr::Vector& value); + + void WriteCapability(uint64_t field_index, uint64_t value); + + void WriteRepeatedCapability(uint64_t field_index, + const glcr::Vector& value); + + void WriteHeader(); + + uint64_t size() const { return next_extension_; } + + private: + glcr::ByteBuffer& buffer_; + uint64_t offset_; + uint64_t next_extension_; + uint64_t core_size_; + uint64_t next_cap_ = 0; + glcr::Optional> caps_; + + uint64_t field_offset(uint64_t field_index) const { + return offset_ + kHeaderSize + (8 * field_index); + } +}; + +template +void Serializer::WriteField(uint64_t field_index, const T& value) { + buffer_.WriteAt(field_offset(field_index), value); +} + +template <> +void Serializer::WriteField(uint64_t field_index, + const glcr::String& value); + +template +void Serializer::WriteRepeated(uint64_t field_index, + const glcr::Vector& value) { + ExtensionPointer ptr{ + .offset = (uint32_t)next_extension_, + .length = (uint32_t)(value.size() * sizeof(T)), + }; + + next_extension_ += ptr.length; + buffer_.WriteAt(field_offset(field_index), ptr); + + for (uint64_t i = 0; i < value.size(); i++) { + uint32_t ext_offset = offset_ + ptr.offset + (i * sizeof(T)); + buffer_.WriteAt(ext_offset, value.at(i)); + } +} } // namespace yunq diff --git a/lib/yunq/yunq.h b/lib/yunq/yunq.h new file mode 100644 index 0000000..3a33a8c --- /dev/null +++ b/lib/yunq/yunq.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace yunq { + +struct MessageHeader { + uint32_t ident; + uint32_t core_length; + uint32_t length; + uint32_t crc32; + uint64_t options; +} __attribute__((packed)); + +const uint64_t kHeaderSize = 24; // 4x uint32, 1x uint64 + +struct ExtensionPointer { + uint32_t offset; + uint32_t length; +}; + +} // namespace yunq diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index ffdc39a..329db3d 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -38,36 +38,31 @@ glcr::Status ReadRequest::ParseFromBytesInternal(const yunq::MessageView& messag } uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 3); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write lba. - bytes.WriteAt(offset + header_size + (8 * 1), lba()); + serializer.WriteField(1, lba_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 2), size()); + serializer.WriteField(2, size_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write lba. - bytes.WriteAt(offset + header_size + (8 * 1), lba()); + serializer.WriteField(1, lba_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 2), size()); + serializer.WriteField(2, size_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status ReadManyRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -94,80 +89,31 @@ glcr::Status ReadManyRequest::ParseFromBytesInternal(const yunq::MessageView& me } uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 3); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write lba. - ExtPointer lba_ptr{ - .offset = next_extension, - .length = (uint32_t)(lba().size() * sizeof(uint64_t)), - }; - - next_extension += lba_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 1), lba_ptr); - - for (uint64_t i = 0; i < lba().size(); i++) { - uint32_t ext_offset = offset + lba_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, lba().at(i)); - } + serializer.WriteRepeated(1, lba_); // Write sector_cnt. - ExtPointer sector_cnt_ptr{ - .offset = next_extension, - .length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)), - }; + serializer.WriteRepeated(2, sector_cnt_); - next_extension += sector_cnt_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 2), sector_cnt_ptr); + serializer.WriteHeader(); - for (uint64_t i = 0; i < sector_cnt().size(); i++) { - uint32_t ext_offset = offset + sector_cnt_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, sector_cnt().at(i)); - } - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write lba. - ExtPointer lba_ptr{ - .offset = next_extension, - .length = (uint32_t)(lba().size() * sizeof(uint64_t)), - }; - - next_extension += lba_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 1), lba_ptr); - - for (uint64_t i = 0; i < lba().size(); i++) { - uint32_t ext_offset = offset + lba_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, lba().at(i)); - } + serializer.WriteRepeated(1, lba_); // Write sector_cnt. - ExtPointer sector_cnt_ptr{ - .offset = next_extension, - .length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)), - }; + serializer.WriteRepeated(2, sector_cnt_); - next_extension += sector_cnt_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 2), sector_cnt_ptr); + serializer.WriteHeader(); - for (uint64_t i = 0; i < sector_cnt().size(); i++) { - uint32_t ext_offset = offset + sector_cnt_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, sector_cnt().at(i)); - } - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } glcr::Status ReadResponse::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -195,37 +141,30 @@ glcr::Status ReadResponse::ParseFromBytesInternal(const yunq::MessageView& messa } uint64_t ReadResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 3); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 1), size()); + serializer.WriteField(1, size_); // Write memory. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 2), 0); + serializer.WriteCapability(2, memory_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t ReadResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + serializer.WriteField(0, device_id_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 1), size()); + serializer.WriteField(1, size_); // Write memory. - caps.WriteAt(next_cap, memory()); - bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + serializer.WriteCapability(2, memory_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index 0c0d70b..a529810 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -34,46 +34,23 @@ glcr::Status OpenFileRequest::ParseFromBytesInternal(const yunq::MessageView& me } uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; + serializer.WriteField(0, path_); - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; + serializer.WriteField(0, path_); - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } glcr::Status OpenFileResponse::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -101,56 +78,31 @@ glcr::Status OpenFileResponse::ParseFromBytesInternal(const yunq::MessageView& m } uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 3); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + serializer.WriteField(0, path_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 1), size()); + serializer.WriteField(1, size_); // Write memory. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 2), 0); + serializer.WriteCapability(2, memory_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + serializer.WriteField(0, path_); // Write size. - bytes.WriteAt(offset + header_size + (8 * 1), size()); + serializer.WriteField(1, size_); // Write memory. - caps.WriteAt(next_cap, memory()); - bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + serializer.WriteCapability(2, memory_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status GetDirectoryRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -171,46 +123,23 @@ glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const yunq::MessageView } uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; + serializer.WriteField(0, path_); - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; + serializer.WriteField(0, path_); - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } glcr::Status Directory::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -231,45 +160,22 @@ glcr::Status Directory::ParseFromBytesInternal(const yunq::MessageView& message) } uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write filenames. - ExtPointer filenames_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)filenames().length(), - }; + serializer.WriteField(0, filenames_); - bytes.WriteStringAt(offset + next_extension, filenames()); - next_extension += filenames_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), filenames_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write filenames. - ExtPointer filenames_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)filenames().length(), - }; + serializer.WriteField(0, filenames_); - bytes.WriteStringAt(offset + next_extension, filenames()); - next_extension += filenames_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), filenames_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 863a0d9..9a69f66 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -37,29 +37,22 @@ glcr::Status KeyboardListener::ParseFromBytesInternal(const yunq::MessageView& m } uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write port_capability. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 0), 0); + serializer.WriteCapability(0, port_capability_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write port_capability. - caps.WriteAt(next_cap, port_capability()); - bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); + serializer.WriteCapability(0, port_capability_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 0b21546..33a5f0d 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -41,52 +41,27 @@ glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const yunq::Message } uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 2); // Write endpoint_name. - ExtPointer endpoint_name_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)endpoint_name().length(), - }; - - bytes.WriteStringAt(offset + next_extension, endpoint_name()); - next_extension += endpoint_name_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), endpoint_name_ptr); + serializer.WriteField(0, endpoint_name_); // Write endpoint_capability. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 1), 0); + serializer.WriteCapability(1, endpoint_capability_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 2, caps); // Write endpoint_name. - ExtPointer endpoint_name_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)endpoint_name().length(), - }; - - bytes.WriteStringAt(offset + next_extension, endpoint_name()); - next_extension += endpoint_name_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), endpoint_name_ptr); + serializer.WriteField(0, endpoint_name_); // Write endpoint_capability. - caps.WriteAt(next_cap, endpoint_capability()); - bytes.WriteAt(offset + header_size + (8 * 1), next_cap++); + serializer.WriteCapability(1, endpoint_capability_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status GetEndpointRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -107,46 +82,23 @@ glcr::Status GetEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& } uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write endpoint_name. - ExtPointer endpoint_name_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)endpoint_name().length(), - }; + serializer.WriteField(0, endpoint_name_); - bytes.WriteStringAt(offset + next_extension, endpoint_name()); - next_extension += endpoint_name_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), endpoint_name_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write endpoint_name. - ExtPointer endpoint_name_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)endpoint_name().length(), - }; + serializer.WriteField(0, endpoint_name_); - bytes.WriteStringAt(offset + next_extension, endpoint_name()); - next_extension += endpoint_name_ptr.length; + serializer.WriteHeader(); - bytes.WriteAt(offset + header_size + (8 * 0), endpoint_name_ptr); - - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } glcr::Status Endpoint::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -170,30 +122,23 @@ glcr::Status Endpoint::ParseFromBytesInternal(const yunq::MessageView& message) } uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 1); // Write endpoint. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 0), 0); + serializer.WriteCapability(0, endpoint_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 1; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 1, caps); // Write endpoint. - caps.WriteAt(next_cap, endpoint()); - bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); + serializer.WriteCapability(0, endpoint_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status AhciInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -219,34 +164,27 @@ glcr::Status AhciInfo::ParseFromBytesInternal(const yunq::MessageView& message) } uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 2); // Write ahci_region. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 0), 0); + serializer.WriteCapability(0, ahci_region_); // Write region_length. - bytes.WriteAt(offset + header_size + (8 * 1), region_length()); + serializer.WriteField(1, region_length_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 2, caps); // Write ahci_region. - caps.WriteAt(next_cap, ahci_region()); - bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); + serializer.WriteCapability(0, ahci_region_); // Write region_length. - bytes.WriteAt(offset + header_size + (8 * 1), region_length()); + serializer.WriteField(1, region_length_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status FramebufferInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -289,72 +227,67 @@ glcr::Status FramebufferInfo::ParseFromBytesInternal(const yunq::MessageView& me } uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 12; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 12); // Write address_phys. - bytes.WriteAt(offset + header_size + (8 * 0), address_phys()); + serializer.WriteField(0, address_phys_); // Write width. - bytes.WriteAt(offset + header_size + (8 * 1), width()); + serializer.WriteField(1, width_); // Write height. - bytes.WriteAt(offset + header_size + (8 * 2), height()); + serializer.WriteField(2, height_); // Write pitch. - bytes.WriteAt(offset + header_size + (8 * 3), pitch()); + serializer.WriteField(3, pitch_); // Write bpp. - bytes.WriteAt(offset + header_size + (8 * 4), bpp()); + serializer.WriteField(4, bpp_); // Write memory_model. - bytes.WriteAt(offset + header_size + (8 * 5), memory_model()); + serializer.WriteField(5, memory_model_); // Write red_mask_size. - bytes.WriteAt(offset + header_size + (8 * 6), red_mask_size()); + serializer.WriteField(6, red_mask_size_); // Write red_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 7), red_mask_shift()); + serializer.WriteField(7, red_mask_shift_); // Write green_mask_size. - bytes.WriteAt(offset + header_size + (8 * 8), green_mask_size()); + serializer.WriteField(8, green_mask_size_); // Write green_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 9), green_mask_shift()); + serializer.WriteField(9, green_mask_shift_); // Write blue_mask_size. - bytes.WriteAt(offset + header_size + (8 * 10), blue_mask_size()); + serializer.WriteField(10, blue_mask_size_); // Write blue_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 11), blue_mask_shift()); + serializer.WriteField(11, blue_mask_shift_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 12; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 12, caps); // Write address_phys. - bytes.WriteAt(offset + header_size + (8 * 0), address_phys()); + serializer.WriteField(0, address_phys_); // Write width. - bytes.WriteAt(offset + header_size + (8 * 1), width()); + serializer.WriteField(1, width_); // Write height. - bytes.WriteAt(offset + header_size + (8 * 2), height()); + serializer.WriteField(2, height_); // Write pitch. - bytes.WriteAt(offset + header_size + (8 * 3), pitch()); + serializer.WriteField(3, pitch_); // Write bpp. - bytes.WriteAt(offset + header_size + (8 * 4), bpp()); + serializer.WriteField(4, bpp_); // Write memory_model. - bytes.WriteAt(offset + header_size + (8 * 5), memory_model()); + serializer.WriteField(5, memory_model_); // Write red_mask_size. - bytes.WriteAt(offset + header_size + (8 * 6), red_mask_size()); + serializer.WriteField(6, red_mask_size_); // Write red_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 7), red_mask_shift()); + serializer.WriteField(7, red_mask_shift_); // Write green_mask_size. - bytes.WriteAt(offset + header_size + (8 * 8), green_mask_size()); + serializer.WriteField(8, green_mask_size_); // Write green_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 9), green_mask_shift()); + serializer.WriteField(9, green_mask_shift_); // Write blue_mask_size. - bytes.WriteAt(offset + header_size + (8 * 10), blue_mask_size()); + serializer.WriteField(10, blue_mask_size_); // Write blue_mask_shift. - bytes.WriteAt(offset + header_size + (8 * 11), blue_mask_shift()); + serializer.WriteField(11, blue_mask_shift_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } glcr::Status DenaliInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); @@ -382,38 +315,31 @@ glcr::Status DenaliInfo::ParseFromBytesInternal(const yunq::MessageView& message } uint64_t DenaliInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; + yunq::Serializer serializer(bytes, offset, 3); // Write denali_endpoint. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 0), 0); + serializer.WriteCapability(0, denali_endpoint_); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 1), device_id()); + serializer.WriteField(1, device_id_); // Write lba_offset. - bytes.WriteAt(offset + header_size + (8 * 2), lba_offset()); + serializer.WriteField(2, lba_offset_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t DenaliInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); // Write denali_endpoint. - caps.WriteAt(next_cap, denali_endpoint()); - bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); + serializer.WriteCapability(0, denali_endpoint_); // Write device_id. - bytes.WriteAt(offset + header_size + (8 * 1), device_id()); + serializer.WriteField(1, device_id_); // Write lba_offset. - bytes.WriteAt(offset + header_size + (8 * 2), lba_offset()); + serializer.WriteField(2, lba_offset_); - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 403188e..7666bf4 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -73,105 +73,63 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& m } uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * {{ message.fields | length }}; - const uint32_t core_size = next_extension; - + yunq::Serializer serializer(bytes, offset, {{ message.fields | length }}); + {%- for field in message.fields %} // Write {{field.name}}. {%- if not field.repeated %} -{%- if field.type == Type.U64 %} - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); -{%- elif field.type == Type.I64 %} - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); -{%- elif field.type == Type.STRING %} - ExtPointer {{field.name}}_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t){{field.name}}().length(), - }; - bytes.WriteStringAt(offset + next_extension, {{field.name}}()); - next_extension += {{field.name}}_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); -{%- elif field.type == Type.CAPABILITY %} - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), 0); +{%- if field.type != Type.CAPABILITY %} + serializer.WriteField<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); {%- else %} - // TODO: Unimplemented serialization {{field.type}} + serializer.WriteCapability({{loop.index0}}, {{field.name}}_); {%- endif %} + {%- else %} - ExtPointer {{field.name}}_ptr{ - .offset = next_extension, - .length = (uint32_t)({{field.name}}().size() * sizeof({{field.cpp_type()}})), - }; - next_extension += {{field.name}}_ptr.length; - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); +{%- if field.type != Type.CAPABILITY %} + serializer.WriteRepeated<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); +{%- else %} + serializer.WriteRepeatedCapability({{loop.index0}}, {{field.name}}_); +{%- endif %} - for (uint64_t i = 0; i < {{field.name}}().size(); i++) { - uint32_t ext_offset = offset + {{field.name}}_ptr.offset + (i * sizeof({{field.cpp_type()}})); - bytes.WriteAt<{{field.cpp_type()}}>(ext_offset, {{field.name}}().at(i)); - } {%- endif %} {%- endfor %} - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * {{ message.fields | length}}; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; - + yunq::Serializer serializer(bytes, offset, {{ message.fields | length }}, caps); + {%- for field in message.fields %} // Write {{field.name}}. {%- if not field.repeated %} -{%- if field.type == Type.U64 %} - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); -{%- elif field.type == Type.I64 %} - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}()); -{%- elif field.type == Type.STRING %} - ExtPointer {{field.name}}_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t){{field.name}}().length(), - }; - bytes.WriteStringAt(offset + next_extension, {{field.name}}()); - next_extension += {{field.name}}_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); -{%- elif field.type == Type.CAPABILITY %} - caps.WriteAt(next_cap, {{field.name}}()); - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), next_cap++); +{%- if field.type != Type.CAPABILITY %} + serializer.WriteField<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); {%- else %} - // TODO: Unimplemented serialization {{field.type}} + serializer.WriteCapability({{loop.index0}}, {{field.name}}_); {%- endif %} + {%- else %} - ExtPointer {{field.name}}_ptr{ - .offset = next_extension, - .length = (uint32_t)({{field.name}}().size() * sizeof({{field.cpp_type()}})), - }; - next_extension += {{field.name}}_ptr.length; - bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); +{%- if field.type != Type.CAPABILITY %} + serializer.WriteRepeated<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); +{%- else %} + serializer.WriteRepeatedCapability({{loop.index0}}, {{field.name}}_); +{%- endif %} - for (uint64_t i = 0; i < {{field.name}}().size(); i++) { - uint32_t ext_offset = offset + {{field.name}}_ptr.offset + (i * sizeof({{field.cpp_type()}})); - bytes.WriteAt<{{field.cpp_type()}}>(ext_offset, {{field.name}}().at(i)); - } {%- endif %} {%- endfor %} - // The next extension pointer is the length of the message. - yunq::WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } + {%- endfor %} {% if package != None %} From a71d5e9d249f4f66304637cf364a02dbaf84f91c Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:41:51 -0800 Subject: [PATCH 040/186] [Yunq] Explicitly specialize serialization template functions. While this may end up with some duplicated code, it helps avoid accidentally generating code for a type that we didn't intend to. This will help in the future because we will get a linker error rather than wonky runtime behavior. --- lib/yunq/serialize.cpp | 23 +++++++++++++++++++++++ lib/yunq/serialize.h | 26 ++++++-------------------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/yunq/serialize.cpp b/lib/yunq/serialize.cpp index 6522ab3..188685a 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -14,6 +14,12 @@ void Serializer::WriteHeader() { buffer_.WriteAt(offset_ + 12, 0); // TODO: Calculate CRC32. } +template <> +void Serializer::WriteField(uint64_t field_index, + const uint64_t& value) { + buffer_.WriteAt(field_offset(field_index), value); +} + template <> void Serializer::WriteField(uint64_t field_index, const glcr::String& value) { @@ -29,6 +35,23 @@ void Serializer::WriteField(uint64_t field_index, buffer_.WriteAt(field_offset(field_index), ptr); } +template <> +void Serializer::WriteRepeated(uint64_t field_index, + const glcr::Vector& value) { + ExtensionPointer ptr{ + .offset = (uint32_t)next_extension_, + .length = (uint32_t)(value.size() * sizeof(uint64_t)), + }; + + next_extension_ += ptr.length; + buffer_.WriteAt(field_offset(field_index), ptr); + + for (uint64_t i = 0; i < value.size(); i++) { + uint32_t ext_offset = offset_ + ptr.offset + (i * sizeof(uint64_t)); + buffer_.WriteAt(ext_offset, value.at(i)); + } +} + void Serializer::WriteCapability(uint64_t field_index, uint64_t value) { if (caps_) { buffer_.WriteAt(field_offset(field_index), next_cap_); diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index ae6a77b..68f9775 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -55,30 +55,16 @@ class Serializer { } }; -template -void Serializer::WriteField(uint64_t field_index, const T& value) { - buffer_.WriteAt(field_offset(field_index), value); -} +template <> +void Serializer::WriteField(uint64_t field_index, + const uint64_t& value); template <> void Serializer::WriteField(uint64_t field_index, const glcr::String& value); -template -void Serializer::WriteRepeated(uint64_t field_index, - const glcr::Vector& value) { - ExtensionPointer ptr{ - .offset = (uint32_t)next_extension_, - .length = (uint32_t)(value.size() * sizeof(T)), - }; - - next_extension_ += ptr.length; - buffer_.WriteAt(field_offset(field_index), ptr); - - for (uint64_t i = 0; i < value.size(); i++) { - uint32_t ext_offset = offset_ + ptr.offset + (i * sizeof(T)); - buffer_.WriteAt(ext_offset, value.at(i)); - } -} +template <> +void Serializer::WriteRepeated(uint64_t field_index, + const glcr::Vector& value); } // namespace yunq From 984d8b143ed35619ff30a41abcd78cc1078ac807 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:47:39 -0800 Subject: [PATCH 041/186] [Yunq] Move message parser to shared internal function. --- sys/denali/lib/denali/denali.yunq.cpp | 45 +++------ sys/denali/lib/denali/denali.yunq.h | 7 ++ .../lib/victoriafalls/victoriafalls.yunq.cpp | 48 ++++------ .../lib/victoriafalls/victoriafalls.yunq.h | 9 ++ .../lib/voyageurs/voyageurs.yunq.cpp | 11 +-- sys/voyageurs/lib/voyageurs/voyageurs.yunq.h | 3 + .../lib/yellowstone/yellowstone.yunq.cpp | 96 ++++++------------- .../lib/yellowstone/yellowstone.yunq.h | 13 +++ yunq/message.cpp.jinja | 29 +----- yunq/message.h.jinja | 3 + 10 files changed, 109 insertions(+), 155 deletions(-) diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 329db3d..5ba2a69 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -39,20 +39,15 @@ glcr::Status ReadRequest::ParseFromBytesInternal(const yunq::MessageView& messag uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 3); - // Write device_id. - serializer.WriteField(0, device_id_); - // Write lba. - serializer.WriteField(1, lba_); - // Write size. - serializer.WriteField(2, size_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 3, caps); + return SerializeInternal(serializer); +} + +uint64_t ReadRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write device_id. serializer.WriteField(0, device_id_); // Write lba. @@ -90,20 +85,15 @@ glcr::Status ReadManyRequest::ParseFromBytesInternal(const yunq::MessageView& me uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 3); - // Write device_id. - serializer.WriteField(0, device_id_); - // Write lba. - serializer.WriteRepeated(1, lba_); - // Write sector_cnt. - serializer.WriteRepeated(2, sector_cnt_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 3, caps); + return SerializeInternal(serializer); +} + +uint64_t ReadManyRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write device_id. serializer.WriteField(0, device_id_); // Write lba. @@ -142,20 +132,15 @@ glcr::Status ReadResponse::ParseFromBytesInternal(const yunq::MessageView& messa uint64_t ReadResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 3); - // Write device_id. - serializer.WriteField(0, device_id_); - // Write size. - serializer.WriteField(1, size_); - // Write memory. - serializer.WriteCapability(2, memory_); - - serializer.WriteHeader(); - - return serializer.size(); + 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(0, device_id_); // Write size. diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h index a32d782..d4b093c 100644 --- a/sys/denali/lib/denali/denali.yunq.h +++ b/sys/denali/lib/denali/denali.yunq.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -35,6 +36,8 @@ class ReadRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class ReadManyRequest { public: @@ -61,6 +64,8 @@ class ReadManyRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class ReadResponse { public: @@ -87,5 +92,7 @@ class ReadResponse { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp index a529810..21fea87 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -35,16 +35,15 @@ glcr::Status OpenFileRequest::ParseFromBytesInternal(const yunq::MessageView& me uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write path. - serializer.WriteField(0, path_); - - serializer.WriteHeader(); - - return serializer.size(); + 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(0, path_); @@ -79,20 +78,15 @@ glcr::Status OpenFileResponse::ParseFromBytesInternal(const yunq::MessageView& m uint64_t OpenFileResponse::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 3); - // Write path. - serializer.WriteField(0, path_); - // Write size. - serializer.WriteField(1, size_); - // Write memory. - serializer.WriteCapability(2, memory_); - - serializer.WriteHeader(); - - return serializer.size(); + 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(0, path_); // Write size. @@ -124,16 +118,15 @@ glcr::Status GetDirectoryRequest::ParseFromBytesInternal(const yunq::MessageView uint64_t GetDirectoryRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write path. - serializer.WriteField(0, path_); - - serializer.WriteHeader(); - - return serializer.size(); + 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(0, path_); @@ -161,16 +154,15 @@ glcr::Status Directory::ParseFromBytesInternal(const yunq::MessageView& message) uint64_t Directory::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write filenames. - serializer.WriteField(0, filenames_); - - serializer.WriteHeader(); - - return serializer.size(); + 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(0, filenames_); diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h index 5a294fc..aaf87c9 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -29,6 +30,8 @@ class OpenFileRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class OpenFileResponse { public: @@ -55,6 +58,8 @@ class OpenFileResponse { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class GetDirectoryRequest { public: @@ -75,6 +80,8 @@ class GetDirectoryRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class Directory { public: @@ -95,5 +102,7 @@ class Directory { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 9a69f66..1ad84f2 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -38,16 +38,15 @@ glcr::Status KeyboardListener::ParseFromBytesInternal(const yunq::MessageView& m uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write port_capability. - serializer.WriteCapability(0, port_capability_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t KeyboardListener::SerializeInternal(yunq::Serializer& serializer) const { // Write port_capability. serializer.WriteCapability(0, port_capability_); diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h index 727b31b..2b2c618 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -29,5 +30,7 @@ class KeyboardListener { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 33a5f0d..78827d7 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -42,18 +42,15 @@ glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const yunq::Message uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 2); - // Write endpoint_name. - serializer.WriteField(0, endpoint_name_); - // Write endpoint_capability. - serializer.WriteCapability(1, endpoint_capability_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 2, caps); + return SerializeInternal(serializer); +} + +uint64_t RegisterEndpointRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write endpoint_name. serializer.WriteField(0, endpoint_name_); // Write endpoint_capability. @@ -83,16 +80,15 @@ glcr::Status GetEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write endpoint_name. - serializer.WriteField(0, endpoint_name_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t GetEndpointRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write endpoint_name. serializer.WriteField(0, endpoint_name_); @@ -123,16 +119,15 @@ glcr::Status Endpoint::ParseFromBytesInternal(const yunq::MessageView& message) uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 1); - // Write endpoint. - serializer.WriteCapability(0, endpoint_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t Endpoint::SerializeInternal(yunq::Serializer& serializer) const { // Write endpoint. serializer.WriteCapability(0, endpoint_); @@ -165,18 +160,15 @@ glcr::Status AhciInfo::ParseFromBytesInternal(const yunq::MessageView& message) uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 2); - // Write ahci_region. - serializer.WriteCapability(0, ahci_region_); - // Write region_length. - serializer.WriteField(1, region_length_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 2, caps); + return SerializeInternal(serializer); +} + +uint64_t AhciInfo::SerializeInternal(yunq::Serializer& serializer) const { // Write ahci_region. serializer.WriteCapability(0, ahci_region_); // Write region_length. @@ -228,38 +220,15 @@ glcr::Status FramebufferInfo::ParseFromBytesInternal(const yunq::MessageView& me uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 12); - // Write address_phys. - serializer.WriteField(0, address_phys_); - // Write width. - serializer.WriteField(1, width_); - // Write height. - serializer.WriteField(2, height_); - // Write pitch. - serializer.WriteField(3, pitch_); - // Write bpp. - serializer.WriteField(4, bpp_); - // Write memory_model. - serializer.WriteField(5, memory_model_); - // Write red_mask_size. - serializer.WriteField(6, red_mask_size_); - // Write red_mask_shift. - serializer.WriteField(7, red_mask_shift_); - // Write green_mask_size. - serializer.WriteField(8, green_mask_size_); - // Write green_mask_shift. - serializer.WriteField(9, green_mask_shift_); - // Write blue_mask_size. - serializer.WriteField(10, blue_mask_size_); - // Write blue_mask_shift. - serializer.WriteField(11, blue_mask_shift_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 12, caps); + return SerializeInternal(serializer); +} + +uint64_t FramebufferInfo::SerializeInternal(yunq::Serializer& serializer) const { // Write address_phys. serializer.WriteField(0, address_phys_); // Write width. @@ -316,20 +285,15 @@ glcr::Status DenaliInfo::ParseFromBytesInternal(const yunq::MessageView& message uint64_t DenaliInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, 3); - // Write denali_endpoint. - serializer.WriteCapability(0, denali_endpoint_); - // Write device_id. - serializer.WriteField(1, device_id_); - // Write lba_offset. - serializer.WriteField(2, lba_offset_); - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t DenaliInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, 3, caps); + return SerializeInternal(serializer); +} + +uint64_t DenaliInfo::SerializeInternal(yunq::Serializer& serializer) const { // Write denali_endpoint. serializer.WriteCapability(0, denali_endpoint_); // Write device_id. diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index c69b5a2..93f05e8 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -34,6 +35,8 @@ class RegisterEndpointRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class GetEndpointRequest { public: @@ -54,6 +57,8 @@ class GetEndpointRequest { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class Endpoint { public: @@ -74,6 +79,8 @@ class Endpoint { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class AhciInfo { public: @@ -97,6 +104,8 @@ class AhciInfo { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class FramebufferInfo { public: @@ -150,6 +159,8 @@ class FramebufferInfo { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class DenaliInfo { public: @@ -176,6 +187,8 @@ class DenaliInfo { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 7666bf4..dba366a 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -74,36 +74,15 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& m uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { yunq::Serializer serializer(bytes, offset, {{ message.fields | length }}); - -{%- for field in message.fields %} - // Write {{field.name}}. -{%- if not field.repeated %} - -{%- if field.type != Type.CAPABILITY %} - serializer.WriteField<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); -{%- else %} - serializer.WriteCapability({{loop.index0}}, {{field.name}}_); -{%- endif %} - -{%- else %} - -{%- if field.type != Type.CAPABILITY %} - serializer.WriteRepeated<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); -{%- else %} - serializer.WriteRepeatedCapability({{loop.index0}}, {{field.name}}_); -{%- endif %} - -{%- endif %} -{%- endfor %} - - serializer.WriteHeader(); - - return serializer.size(); + return SerializeInternal(serializer); } uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { yunq::Serializer serializer(bytes, offset, {{ message.fields | length }}, caps); + return SerializeInternal(serializer); +} +uint64_t {{message.name}}::SerializeInternal(yunq::Serializer& serializer) const { {%- for field in message.fields %} // Write {{field.name}}. {%- if not field.repeated %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index 79d47cd..814ce81 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -7,6 +7,7 @@ #include #include #include +#include #include {% if package != None %} @@ -47,6 +48,8 @@ class {{message.name}} { // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; {%- endfor %} From ee341fa739a3f70402e32452054be401c8e62d8a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:53:31 -0800 Subject: [PATCH 042/186] Draft 0.1.1 release notes added with work so far. --- RELEASES.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 3c5bb6f..7b19818 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,5 +1,24 @@ # Releases +## AcadiaOS 0.1.1 (WIP) + +### Denali + +- AHCI Driver can use more than one command slot. +- Resets AHCI Controller on start. +- Uses IDENTIFY DEVICE to get sector size. + +### Glacier + +- Unit Testing setup for Host Machine +- Unit Tests for: Vector +- Added Iterators for: Vector, Array, ArrayView +- HashMap Move Semantics + +### Yunq + +- Moved message parsing/serialization to shared library. + ## AcadiaOS 0.1.0 (2023-12-08) This marks the first release of AcadiaOS! There is very little user functionality currently but a From 3b91819a4beff4c17e8b4a0527484d58b56070f9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 20:59:20 -0800 Subject: [PATCH 043/186] [Yunq] Move message fields to a numbering scheme set by the parser. --- yunq/message.cpp.jinja | 20 ++++++++++---------- yunq/parser.py | 4 ++++ 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index dba366a..4a3e599 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -26,10 +26,10 @@ glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message) {%- if field.type == Type.CAPABILITY %} {%- if not field.repeated %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{field.number}})); {%- else %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{field.number}})); {%- endif %} {%- endif %} {%- endfor %} @@ -43,10 +43,10 @@ glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message, {%- if field.type == Type.CAPABILITY %} {%- if not field.repeated %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{loop.index0}}, caps)); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{field.number}}, caps)); {%- else %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{loop.index0}}, caps)); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{field.number}}, caps)); {%- endif %} {%- endif %} {%- endfor %} @@ -61,9 +61,9 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& m {%- if field.type != Type.CAPABILITY %} {%- if not field.repeated %} - ASSIGN_OR_RETURN({{field.name}}_, message.ReadField<{{field.cpp_type()}}>({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadField<{{field.cpp_type()}}>({{field.number}})); {%- else %} - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeated<{{field.cpp_type()}}>({{loop.index0}})); + ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeated<{{field.cpp_type()}}>({{field.number}})); {% endif %} {%- endif %} @@ -88,17 +88,17 @@ uint64_t {{message.name}}::SerializeInternal(yunq::Serializer& serializer) const {%- if not field.repeated %} {%- if field.type != Type.CAPABILITY %} - serializer.WriteField<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); + serializer.WriteField<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {%- else %} - serializer.WriteCapability({{loop.index0}}, {{field.name}}_); + serializer.WriteCapability({{field.number}}, {{field.name}}_); {%- endif %} {%- else %} {%- if field.type != Type.CAPABILITY %} - serializer.WriteRepeated<{{field.cpp_type()}}>({{loop.index0}}, {{field.name}}_); + serializer.WriteRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {%- else %} - serializer.WriteRepeatedCapability({{loop.index0}}, {{field.name}}_); + serializer.WriteRepeatedCapability({{field.number}}, {{field.name}}_); {%- endif %} {%- endif %} diff --git a/yunq/parser.py b/yunq/parser.py index d9c3eaa..5507880 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -17,6 +17,7 @@ class LexemeType(Enum): ARROW = 7 SEMICOLON = 8 DOT = 9 + EQUALS = 10 class Lexeme(): @@ -266,8 +267,11 @@ class Parser(): fields: list[Field] = [] field_names = set() + next_field_num = 0 while self.peektype() != LexemeType.RIGHT_BRACE: f = self.field() + f.number = next_field_num + next_field_num += 1 if f.name in field_names: sys.exit("Field %s declared twice on %s" % (f.name, name)) field_names.add(f.name) From 9e12531651c14eba5dcddb6863a7cde834036a12 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 21:00:51 -0800 Subject: [PATCH 044/186] [Yunq] Move method numbers to a scheme set by the parser. --- yunq/client.cpp.jinja | 2 +- yunq/parser.py | 3 +++ yunq/server.cpp.jinja | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/yunq/client.cpp.jinja b/yunq/client.cpp.jinja index 63721e0..e4e8102 100644 --- a/yunq/client.cpp.jinja +++ b/yunq/client.cpp.jinja @@ -31,7 +31,7 @@ glcr::Status {{interface.name}}Client::{{method.name}}(const {{method.request}}& const uint32_t kSentinel = 0xBEEFDEAD; buffer_.WriteAt(0, kSentinel); - buffer_.WriteAt(8, {{loop.index0}}); + buffer_.WriteAt(8, {{method.number}}); cap_buffer_.Reset(); {% if method.request == None %} diff --git a/yunq/parser.py b/yunq/parser.py index 5507880..403f27b 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -215,8 +215,11 @@ class Parser(): methods: list[Method] = [] method_names = set() + next_method_number = 0 while self.peektype() != LexemeType.RIGHT_BRACE: m = self.method() + m.number = next_method_number + next_method_number += 1 if m.name in method_names: sys.exit("Method %s declared twice on %s" % (m.name, name)) method_names.add(m.name) diff --git a/yunq/server.cpp.jinja b/yunq/server.cpp.jinja index 734166d..bee46b5 100644 --- a/yunq/server.cpp.jinja +++ b/yunq/server.cpp.jinja @@ -103,7 +103,7 @@ glcr::Status {{interface.name}}ServerBase::HandleRequest(const glcr::ByteBuffer& switch(method_select) { {%- for method in interface.methods %} - case {{loop.index0}}: { + case {{method.number}}: { {% if method.request != None %} {{method.request}} yunq_request; From a48d63a66494538b4b55f98e9cb63d7d1f35439e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 21:32:08 -0800 Subject: [PATCH 045/186] [Yunq] Add support for nested fields in messages. --- lib/yunq/message_view.h | 12 ++ lib/yunq/serialize.h | 23 ++ sys/denali/denali_server.cpp | 11 +- sys/denali/lib/denali/denali.yunq | 9 +- sys/denali/lib/denali/denali.yunq.cpp | 56 ++++- sys/denali/lib/denali/denali.yunq.h | 36 +++- .../fs/ext2/ext2_block_reader.cpp | 8 +- sys/yellowstone/hw/gpt.cpp | 8 +- yunq/example/example.yunq.client.cpp | 7 +- yunq/example/example.yunq.client.h | 2 +- yunq/example/example.yunq.cpp | 200 +++++------------- yunq/example/example.yunq.h | 19 +- yunq/example/example.yunq.server.cpp | 26 +-- yunq/example/example.yunq.server.h | 9 +- yunq/message.cpp.jinja | 18 +- yunq/message.h.jinja | 8 + yunq/parser.py | 23 +- yunq/yunq.py | 1 + 18 files changed, 257 insertions(+), 219 deletions(-) diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index 996ba8f..069c00c 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -28,6 +28,9 @@ class MessageView { glcr::ErrorOr ReadCapability(uint64_t field_index, const glcr::CapBuffer& caps) const; + template + glcr::Status ReadMessage(uint64_t field_index, T& message) const; + private: const glcr::ByteBuffer& buffer_; uint64_t offset_; @@ -49,4 +52,13 @@ template <> glcr::ErrorOr> MessageView::ReadRepeated( uint64_t field_index) const; +template +glcr::Status MessageView::ReadMessage(uint64_t field_index, T& message) const { + ExtensionPointer ptr = + buffer_.At(field_offset(field_index)); + + MessageView subview(buffer_, offset_ + ptr.offset); + return message.ParseFromBytes(subview); +} + } // namespace yunq diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index 68f9775..ac0b2ff 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -38,6 +38,9 @@ class Serializer { void WriteRepeatedCapability(uint64_t field_index, const glcr::Vector& value); + template + void WriteMessage(uint64_t field_index, const T& value); + void WriteHeader(); uint64_t size() const { return next_extension_; } @@ -67,4 +70,24 @@ template <> void Serializer::WriteRepeated(uint64_t field_index, const glcr::Vector& value); +template +void Serializer::WriteMessage(uint64_t field_index, const T& value) { + uint64_t length = 0; + if (caps_) { + length = value.SerializeToBytes(buffer_, offset_ + next_extension_, + caps_.value().get()); + } else { + length = value.SerializeToBytes(buffer_, offset_ + next_extension_); + } + + ExtensionPointer ptr{ + .offset = (uint32_t)next_extension_, + .length = (uint32_t)length, + }; + + next_extension_ += length; + + buffer_.WriteAt(field_offset(field_index), ptr); +} + } // namespace yunq diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index ba99e3e..1b3cbc7 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -17,15 +17,16 @@ glcr::Status DenaliServer::HandleRead(const ReadRequest& req, ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); uint64_t paddr; - mmth::OwnedMemoryRegion region = - mmth::OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr); + mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical( + req.block().size() * 512, &paddr); - ASSIGN_OR_RETURN(auto semaphore, - device->IssueRead(req.lba(), req.size(), paddr)); + ASSIGN_OR_RETURN( + auto semaphore, + device->IssueRead(req.block().lba(), req.block().size(), paddr)); semaphore->Wait(); resp.set_device_id(req.device_id()); - resp.set_size(req.size()); + resp.set_size(req.block().size()); resp.set_memory(region.DuplicateCap()); return glcr::Status::Ok(); } diff --git a/sys/denali/lib/denali/denali.yunq b/sys/denali/lib/denali/denali.yunq index 340861b..cc3225b 100644 --- a/sys/denali/lib/denali/denali.yunq +++ b/sys/denali/lib/denali/denali.yunq @@ -3,12 +3,17 @@ interface Denali { method ReadMany(ReadManyRequest) -> (ReadResponse); } -message ReadRequest { - u64 device_id; +message DiskBlock { u64 lba; u64 size; } +message ReadRequest { + u64 device_id; + DiskBlock block; +} + + message ReadManyRequest { u64 device_id; // FIXME: Add repeated message fields. diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 5ba2a69..81e82f0 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -15,6 +15,46 @@ struct ExtPointer { }; } // 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(0)); + // Parse size. + ASSIGN_OR_RETURN(size_, message.ReadField(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(0, lba_); + // Write size. + serializer.WriteField(1, size_); + + serializer.WriteHeader(); + + return serializer.size(); +} glcr::Status ReadRequest::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); @@ -29,31 +69,27 @@ glcr::Status ReadRequest::ParseFromBytesInternal(const yunq::MessageView& messag RETURN_ERROR(message.CheckHeader()); // Parse device_id. ASSIGN_OR_RETURN(device_id_, message.ReadField(0)); - // Parse lba. - ASSIGN_OR_RETURN(lba_, message.ReadField(1)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(2)); + // Parse block. + message.ReadMessage(1, block_); return glcr::Status::Ok(); } uint64_t ReadRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 3); + 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, 3, caps); + yunq::Serializer serializer(bytes, offset, 2, caps); return SerializeInternal(serializer); } uint64_t ReadRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write device_id. serializer.WriteField(0, device_id_); - // Write lba. - serializer.WriteField(1, lba_); - // Write size. - serializer.WriteField(2, size_); + // Write block. + serializer.WriteMessage(1, block_); serializer.WriteHeader(); diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h index d4b093c..2707234 100644 --- a/sys/denali/lib/denali/denali.yunq.h +++ b/sys/denali/lib/denali/denali.yunq.h @@ -11,6 +11,31 @@ #include +class DiskBlock { + public: + DiskBlock() {} + // Delete copy and move until implemented. + DiskBlock(const DiskBlock&) = delete; + DiskBlock(DiskBlock&&) = delete; + + [[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_; } + void set_lba(const uint64_t& value) { lba_ = value; } + const uint64_t& size() const { 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() {} @@ -23,16 +48,13 @@ class ReadRequest { 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_; } - void set_device_id(const uint64_t& value) { device_id_ = value; } - const uint64_t& lba() const { return lba_; } - void set_lba(const uint64_t& value) { lba_ = value; } - const uint64_t& size() const { return size_; } - void set_size(const uint64_t& value) { size_ = value; } + 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_; - uint64_t lba_; - uint64_t size_; + DiskBlock block_; // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp index d8a6006..9de13f8 100644 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp @@ -9,8 +9,8 @@ glcr::ErrorOr> Ext2BlockReader::Init( DenaliClient client(denali_info.denali_endpoint()); ReadRequest req; req.set_device_id(denali_info.device_id()); - req.set_lba(denali_info.lba_offset() + 2); - req.set_size(2); + 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()) { @@ -71,8 +71,8 @@ glcr::ErrorOr Ext2BlockReader::ReadBlocks( uint64_t block_number, uint64_t num_blocks) { ReadRequest req; req.set_device_id(device_id_); - req.set_lba(lba_offset_ + block_number * SectorsPerBlock()); - req.set_size(num_blocks * SectorsPerBlock()); + 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()) { diff --git a/sys/yellowstone/hw/gpt.cpp b/sys/yellowstone/hw/gpt.cpp index b4eddc7..43704cd 100644 --- a/sys/yellowstone/hw/gpt.cpp +++ b/sys/yellowstone/hw/gpt.cpp @@ -59,8 +59,8 @@ GptReader::GptReader(glcr::UniquePtr denali) glcr::Status GptReader::ParsePartitionTables() { ReadRequest req; req.set_device_id(0); - req.set_lba(0); - req.set_size(2); + req.mutable_block().set_lba(0); + req.mutable_block().set_size(2); ReadResponse resp; RETURN_ERROR(denali_->Read(req, resp)); mmth::OwnedMemoryRegion lba_1_and_2 = @@ -102,8 +102,8 @@ glcr::Status GptReader::ParsePartitionTables() { #endif req.set_device_id(0); - req.set_lba(header->lba_partition_entries); - req.set_size(num_blocks); + req.mutable_block().set_lba(header->lba_partition_entries); + req.mutable_block().set_size(num_blocks); RETURN_ERROR(denali_->Read(req, resp)); mmth::OwnedMemoryRegion part_table = mmth::OwnedMemoryRegion::FromCapability(resp.memory()); diff --git a/yunq/example/example.yunq.client.cpp b/yunq/example/example.yunq.client.cpp index 1d3dd21..406e895 100644 --- a/yunq/example/example.yunq.client.cpp +++ b/yunq/example/example.yunq.client.cpp @@ -20,7 +20,7 @@ VFSClient::~VFSClient() { -glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response) { +glcr::Status VFSClient::open(const OpenFileRequest& request, File& response) { uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -43,14 +43,15 @@ glcr::ErrorCode VFSClient::open(const OpenFileRequest& request, File& response) RET_ERR(ZReplyPortRecv(reply_port_cap, &buffer_size, buffer_.RawPtr(), &cap_size, cap_buffer_.RawPtr())); if (buffer_.At(0) != kSentinel) { - return glcr::INVALID_RESPONSE; + return glcr::InvalidResponse("Got an invalid response from server."); } // Check Response Code. RET_ERR(buffer_.At(8)); - response.ParseFromBytes(buffer_, 16, cap_buffer_); + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); return glcr::OK; diff --git a/yunq/example/example.yunq.client.h b/yunq/example/example.yunq.client.h index d9fdb3c..826d920 100644 --- a/yunq/example/example.yunq.client.h +++ b/yunq/example/example.yunq.client.h @@ -22,7 +22,7 @@ class VFSClient { - [[nodiscard]] glcr::ErrorCode open(const OpenFileRequest& request, File& response); + [[nodiscard]] glcr::Status open(const OpenFileRequest& request, File& response); private: diff --git a/yunq/example/example.yunq.cpp b/yunq/example/example.yunq.cpp index 1211542..4033cfc 100644 --- a/yunq/example/example.yunq.cpp +++ b/yunq/example/example.yunq.cpp @@ -1,6 +1,9 @@ // Generated file -- DO NOT MODIFY. #include "example.yunq.h" +#include +#include + namespace srv::file { @@ -13,197 +16,94 @@ struct ExtPointer { uint32_t length; }; -void CheckHeader(const glcr::ByteBuffer& bytes) { - // TODO: Check ident. - // TODO: Parse core size. - // TODO: Parse extension size. - // TODO: Check CRC32 - // TODO: Parse options. -} - -void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, uint32_t extension_size) { - bytes.WriteAt(offset + 0, 0xDEADBEEF); // TODO: Chose a more unique ident sequence. - bytes.WriteAt(offset + 4, core_size); - bytes.WriteAt(offset + 8, extension_size); - bytes.WriteAt(offset + 12, 0); // TODO: Calculate CRC32. - bytes.WriteAt(offset + 16, 0); // TODO: Add options. -} - } // namespace -void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - ParseFromBytesInternal(bytes, offset); +glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); } -void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - ParseFromBytesInternal(bytes, offset); +glcr::Status OpenFileRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); } -void OpenFileRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - CheckHeader(bytes); +glcr::Status OpenFileRequest::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse path. - auto path_pointer = bytes.At(offset + header_size + (8 * 0)); - - set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + ASSIGN_OR_RETURN(path_, message.ReadField(0)); // Parse options. - auto options_pointer = bytes.At(offset + header_size + (8 * 1)); - - options_.Resize(options_pointer.length / sizeof(uint64_t)); - for (uint64_t i = offset + options_pointer.offset; - i < offset + options_pointer.offset + options_pointer.length; - i += sizeof(uint64_t)) { - options_.PushBack(bytes.At(i)); - } + ASSIGN_OR_RETURN(options_, message.ReadRepeated(1)); + return glcr::Status::Ok(); } uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; - // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - // Write options. - ExtPointer options_ptr{ - .offset = next_extension, - .length = (uint32_t)(options().size() * sizeof(uint64_t)), - }; - - next_extension += options_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 1), options_ptr); - - for (uint64_t i = 0; i < options().size(); i++) { - uint32_t ext_offset = offset + options_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, options().at(i)); - } - - // The next extension pointer is the length of the message. - WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + yunq::Serializer serializer(bytes, offset, 2); + return SerializeInternal(serializer); } uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 2; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 2, caps); + return SerializeInternal(serializer); +} + +uint64_t OpenFileRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + serializer.WriteField(0, path_); // Write options. - ExtPointer options_ptr{ - .offset = next_extension, - .length = (uint32_t)(options().size() * sizeof(uint64_t)), - }; + serializer.WriteRepeated(1, options_); - next_extension += options_ptr.length; - bytes.WriteAt(offset + header_size + (8 * 1), options_ptr); + serializer.WriteHeader(); - for (uint64_t i = 0; i < options().size(); i++) { - uint32_t ext_offset = offset + options_ptr.offset + (i * sizeof(uint64_t)); - bytes.WriteAt(ext_offset, options().at(i)); - } - - // The next extension pointer is the length of the message. - WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + return serializer.size(); } -void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { - ParseFromBytesInternal(bytes, offset); +glcr::Status File::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse mem_cap. - // FIXME: Implement in-buffer capabilities for inprocess serialization. - set_mem_cap(0); + ASSIGN_OR_RETURN(mem_cap_, message.ReadCapability(2)); + return glcr::Status::Ok(); } -void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { - ParseFromBytesInternal(bytes, offset); +glcr::Status File::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); // Parse mem_cap. - uint64_t mem_cap_ptr = bytes.At(offset + header_size + (8 * 2)); - - set_mem_cap(caps.At(mem_cap_ptr)); + ASSIGN_OR_RETURN(mem_cap_, message.ReadCapability(2, caps)); + return glcr::Status::Ok(); } -void File::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { - CheckHeader(bytes); +glcr::Status File::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); // Parse path. - auto path_pointer = bytes.At(offset + header_size + (8 * 0)); - - set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + ASSIGN_OR_RETURN(path_, message.ReadField(0)); // Parse attrs. - set_attrs(bytes.At(offset + header_size + (8 * 1))); + ASSIGN_OR_RETURN(attrs_, message.ReadField(1)); // Parse mem_cap. - // Skip Cap. + return glcr::Status::Ok(); } uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); - // Write attrs. - bytes.WriteAt(offset + header_size + (8 * 1), attrs()); - // Write mem_cap. - // FIXME: Implement inbuffer capabilities. - bytes.WriteAt(offset + header_size + (8 * 2), 0); - - // The next extension pointer is the length of the message. - WriteHeader(bytes, offset, core_size, next_extension); - - return next_extension; + yunq::Serializer serializer(bytes, offset, 3); + return SerializeInternal(serializer); } uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - uint32_t next_extension = header_size + 8 * 3; - const uint32_t core_size = next_extension; - uint64_t next_cap = 0; + yunq::Serializer serializer(bytes, offset, 3, caps); + return SerializeInternal(serializer); +} + +uint64_t File::SerializeInternal(yunq::Serializer& serializer) const { // Write path. - ExtPointer path_ptr{ - .offset = next_extension, - // FIXME: Check downcast of str length. - .length = (uint32_t)path().length(), - }; - - bytes.WriteStringAt(offset + next_extension, path()); - next_extension += path_ptr.length; - - bytes.WriteAt(offset + header_size + (8 * 0), path_ptr); + serializer.WriteField(0, path_); // Write attrs. - bytes.WriteAt(offset + header_size + (8 * 1), attrs()); + serializer.WriteField(1, attrs_); // Write mem_cap. - caps.WriteAt(next_cap, mem_cap()); - bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + serializer.WriteCapability(2, mem_cap_); - // The next extension pointer is the length of the message. - WriteHeader(bytes, offset, core_size, next_extension); + serializer.WriteHeader(); - return next_extension; + return serializer.size(); } diff --git a/yunq/example/example.yunq.h b/yunq/example/example.yunq.h index 1b9176e..112ddab 100644 --- a/yunq/example/example.yunq.h +++ b/yunq/example/example.yunq.h @@ -3,8 +3,11 @@ #include #include +#include #include #include +#include +#include #include @@ -17,8 +20,8 @@ class OpenFileRequest { OpenFileRequest(const OpenFileRequest&) = delete; OpenFileRequest(OpenFileRequest&&) = delete; - void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -31,7 +34,9 @@ class OpenFileRequest { glcr::Vector options_; // Parses everything except for caps. - void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; class File { public: @@ -40,8 +45,8 @@ class File { File(const File&) = delete; File(File&&) = delete; - void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); - void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); + [[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_; } @@ -57,7 +62,9 @@ class File { z_cap_t mem_cap_; // Parses everything except for caps. - void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; diff --git a/yunq/example/example.yunq.server.cpp b/yunq/example/example.yunq.server.cpp index 555c8d7..5c3b84c 100644 --- a/yunq/example/example.yunq.server.cpp +++ b/yunq/example/example.yunq.server.cpp @@ -75,9 +75,10 @@ void VFSServerBase::ServerThread() { glcr::ErrorCode reply_err = glcr::OK; resp_cap.Reset(); - glcr::ErrorCode err = HandleRequest(recv_buffer, recv_cap, resp_buffer, resp_length, resp_cap); - if (err != glcr::OK) { - WriteError(resp_buffer, err); + 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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); } else { WriteHeader(resp_buffer, resp_length); @@ -90,12 +91,12 @@ void VFSServerBase::ServerThread() { } -glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, - const glcr::CapBuffer& req_caps, - glcr::ByteBuffer& response, uint64_t& resp_length, - glcr::CapBuffer& resp_caps) { +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(0) != kSentinel) { - return glcr::INVALID_ARGUMENT; + return glcr::InvalidArgument("Request Not Valid"); } uint64_t method_select = request.At(8); @@ -105,7 +106,8 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, OpenFileRequest yunq_request; - yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + yunq::MessageView request_view(request, kHeaderSize); + RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); @@ -113,7 +115,7 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, - RET_ERR(Handleopen(yunq_request, yunq_response)); + RETURN_ERROR(Handleopen(yunq_request, yunq_response)); @@ -122,10 +124,10 @@ glcr::ErrorCode VFSServerBase::HandleRequest(const glcr::ByteBuffer& request, break; } default: { - return glcr::UNIMPLEMENTED; + return glcr::Unimplemented("Method unimplemented by server."); } } - return glcr::OK; + return glcr::Status::Ok(); } diff --git a/yunq/example/example.yunq.server.h b/yunq/example/example.yunq.server.h index e1cb556..646e669 100644 --- a/yunq/example/example.yunq.server.h +++ b/yunq/example/example.yunq.server.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include #include @@ -28,7 +29,7 @@ class VFSServerBase { - [[nodiscard]] virtual glcr::ErrorCode Handleopen(const OpenFileRequest&, File&) = 0; + [[nodiscard]] virtual glcr::Status Handleopen(const OpenFileRequest&, File&) = 0; @@ -38,9 +39,9 @@ class VFSServerBase { friend void VFSServerBaseThreadBootstrap(void*); void ServerThread(); - [[nodiscard]] glcr::ErrorCode HandleRequest(const glcr::ByteBuffer& request, const glcr::CapBuffer& req_caps, - glcr::ByteBuffer& response, uint64_t& resp_length, - glcr::CapBuffer& resp_caps); + [[nodiscard]] glcr::Status HandleRequest(const glcr::ByteBuffer& request, const glcr::CapBuffer& req_caps, + glcr::ByteBuffer& response, uint64_t& resp_length, + glcr::CapBuffer& resp_caps); }; diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index 4a3e599..cf96c8c 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -58,7 +58,15 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& m {%- for field in message.fields %} // Parse {{field.name}}. -{%- if field.type != Type.CAPABILITY %} +{%- if field.type == Type.MESSAGE %} + +{%- if not field.repeated %} + message.ReadMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); +{%- else %} + message.ReadMessageRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); +{% endif %} + +{%- elif field.type != Type.CAPABILITY %} {%- if not field.repeated %} ASSIGN_OR_RETURN({{field.name}}_, message.ReadField<{{field.cpp_type()}}>({{field.number}})); @@ -87,10 +95,12 @@ uint64_t {{message.name}}::SerializeInternal(yunq::Serializer& serializer) const // Write {{field.name}}. {%- if not field.repeated %} -{%- if field.type != Type.CAPABILITY %} - serializer.WriteField<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); -{%- else %} +{%- if field.type == Type.MESSAGE %} + serializer.WriteMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); +{%- elif field.type == Type.CAPABILITY %} serializer.WriteCapability({{field.number}}, {{field.name}}_); +{%- else %} + serializer.WriteField<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {%- endif %} {%- else %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index 814ce81..5274771 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -28,6 +28,12 @@ class {{message.name}} { uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; {%- for field in message.fields %} + {%- if field.type == Type.MESSAGE %} + const {{field.cpp_type()}}& {{field.name}}() const { return {{field.name}}_; } + {{field.cpp_type()}}& mutable_{{field.name}}() { return {{field.name}}_; } + + {%- else %} + {%- if not field.repeated %} const {{field.cpp_type()}}& {{field.name}}() const { return {{field.name}}_; } void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; } @@ -35,6 +41,8 @@ class {{message.name}} { const glcr::Vector<{{field.cpp_type()}}>& {{field.name}}() const { return {{field.name}}_; } void add_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_.PushBack(value); } {%- endif %} + + {%- endif %} {%- endfor %} private: diff --git a/yunq/parser.py b/yunq/parser.py index 403f27b..c3ec971 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -106,6 +106,7 @@ class Type(Enum): STRING = 3 BYTES = 4 CAPABILITY = 5 + MESSAGE = 6 type_str_dict = { "u64": Type.U64, @@ -124,12 +125,18 @@ type_to_cppstr = { } class Field(): - def __init__(self, fieldtype: Type, name: str, repeated = False): - self.type = fieldtype + def __init__(self, field_type_str: str, name: str, repeated = False): + if field_type_str in type_str_dict.keys(): + self.type = type_str_dict[field_type_str] + else: + self.type = Type.MESSAGE + self.type_str = field_type_str self.name = name self.repeated = repeated def cpp_type(self): + if self.type == Type.MESSAGE: + return self.type_str return type_to_cppstr[self.type] class Message(): @@ -293,14 +300,10 @@ class Parser(): if field_type_str == "repeated": repeated = True field_type_str = self.consume_identifier() - - if field_type_str not in type_str_dict.keys(): - sys.exit("Expected type got '%s'" % field_type_str) - field_type = type_str_dict[field_type_str] name = self.consume_identifier() self.consume_check(LexemeType.SEMICOLON) - return Field(field_type, name, repeated) + return Field(field_type_str, name, repeated) def type_check(decls: list[Decl]): if sum(1 for decl in decls if type(decl) is Package) > 1: @@ -320,6 +323,12 @@ def type_check(decls: list[Decl]): sys.exit("Response type '%s' for '%s.%s' does not exist" % (method.response, decl.name, method.name)) if type(name_dict[method.response]) is not Message: sys.exit("Response type '%s' for '%s.%s' should be a message" % (method.response, decl.name, method.name)) + elif type(decl) is Message: + for field in decl.fields: + if field.type == Type.MESSAGE: + if field.type_str not in name_dict.keys(): + sys.exit("Field type '%s' for field '%s' in message '%s' not found." % + (field.type_str, field.name, decl.name)) def print_ast(decls: list[Decl]): for decl in decls: diff --git a/yunq/yunq.py b/yunq/yunq.py index c217e19..743f08c 100755 --- a/yunq/yunq.py +++ b/yunq/yunq.py @@ -34,6 +34,7 @@ def main(): jinja_env = Environment(loader=FileSystemLoader(pathlib.Path(__file__).parent.resolve())) message_header_tmpl = jinja_env.get_template("message.h.jinja") + message_header_tmpl.globals['Type'] = Type with open(filename + '.h', mode='w') as f: message_header = message_header_tmpl.render(messages=messages, package=package) f.write(message_header) From 05f2403dc2374ac7b5f13fb2cb9a7de38742fb9e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 22:09:24 -0800 Subject: [PATCH 046/186] [Mammoth] Allow allocating slightly more memory. --- lib/mammoth/util/new.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mammoth/util/new.cpp b/lib/mammoth/util/new.cpp index 9e9c2a5..3357d1e 100644 --- a/lib/mammoth/util/new.cpp +++ b/lib/mammoth/util/new.cpp @@ -12,7 +12,7 @@ class PageAllocator { public: static uint64_t AllocatePagePair() { uint64_t mem_cap; - check(ZMemoryObjectCreate(0x2000, &mem_cap)); + check(ZMemoryObjectCreate(0x4000, &mem_cap)); uint64_t vaddr; check(ZAddressSpaceMap(gSelfVmasCap, 0, mem_cap, /* align= */ 0x2000, @@ -60,8 +60,8 @@ class BuddyAllocator { void* Allocate(uint64_t size) { check(ZMutexLock(mutex_cap_)); - if (size > (0x2000 - sizeof(BuddySlot))) { - crash("Can't allocate greater than one page", glcr::UNIMPLEMENTED); + if (size > (0x4000 - sizeof(BuddySlot))) { + crash("Can't allocate greater than four pages", glcr::UNIMPLEMENTED); } if (free_front_ == nullptr) { AddPage(); From 9c860dd6a4616f5fec4a1368c963e0fe61358c7b Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 11 Jan 2024 22:09:42 -0800 Subject: [PATCH 047/186] [Yunq] Add support for repeated nested fields --- lib/glacier/container/vector.h | 6 ++ lib/yunq/message_view.cpp | 4 ++ lib/yunq/message_view.h | 23 +++++++ lib/yunq/serialize.h | 31 ++++++++++ sys/denali/denali_server.cpp | 19 +++--- sys/denali/lib/denali/denali.yunq | 5 +- sys/denali/lib/denali/denali.yunq.cpp | 17 ++---- sys/denali/lib/denali/denali.yunq.h | 40 +++++++++---- .../fs/ext2/ext2_block_reader.cpp | 6 +- .../lib/victoriafalls/victoriafalls.yunq.h | 24 ++++++-- sys/voyageurs/lib/voyageurs/voyageurs.yunq.h | 5 +- .../lib/yellowstone/yellowstone.yunq.h | 60 +++++++++++++++++-- yunq/message.cpp.jinja | 10 ++-- yunq/message.h.jinja | 18 ++++-- 14 files changed, 207 insertions(+), 61 deletions(-) diff --git a/lib/glacier/container/vector.h b/lib/glacier/container/vector.h index 5544436..b4b994c 100644 --- a/lib/glacier/container/vector.h +++ b/lib/glacier/container/vector.h @@ -47,6 +47,7 @@ class Vector { template void EmplaceBack(Args&&... args); + T& PeekBack(); T&& PopBack(); typedef ArrayIterator Iterator; @@ -130,6 +131,11 @@ void Vector::EmplaceBack(Args&&... args) { data_[size_++] = T(args...); } +template +T& Vector::PeekBack() { + return data_[size_ - 1]; +} + template T&& Vector::PopBack() { size_--; diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp index 5e74430..960f8c4 100644 --- a/lib/yunq/message_view.cpp +++ b/lib/yunq/message_view.cpp @@ -19,6 +19,10 @@ glcr::Status MessageView::CheckHeader() const { return glcr::Status::Ok(); } +uint32_t MessageView::MessageLength() const { + return buffer_.At(offset_ + 8); +} + template <> glcr::ErrorOr MessageView::ReadField( uint64_t field_index) const { diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index 069c00c..78a11ea 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -16,6 +16,7 @@ class MessageView { : buffer_(buffer), offset_(offset) {} [[nodiscard]] glcr::Status CheckHeader() const; + uint32_t MessageLength() const; // TODO: Implement glcr::StatusOr template @@ -31,6 +32,10 @@ class MessageView { template glcr::Status ReadMessage(uint64_t field_index, T& message) const; + template + glcr::Status ReadRepeatedMessage(uint64_t field_index, + glcr::Vector& messages) const; + private: const glcr::ByteBuffer& buffer_; uint64_t offset_; @@ -61,4 +66,22 @@ glcr::Status MessageView::ReadMessage(uint64_t field_index, T& message) const { return message.ParseFromBytes(subview); } +template +glcr::Status MessageView::ReadRepeatedMessage(uint64_t field_index, + glcr::Vector& messages) const { + ExtensionPointer ptr = + buffer_.At(field_offset(field_index)); + + uint64_t ext_offset = ptr.offset; + + while (ext_offset < ptr.offset + ptr.length) { + MessageView subview(buffer_, offset_ + ext_offset); + messages.EmplaceBack(); + RETURN_ERROR(messages.PeekBack().ParseFromBytes(subview)); + ext_offset += subview.MessageLength(); + } + + return glcr::Status::Ok(); +} + } // namespace yunq diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index ac0b2ff..b19ea4b 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -41,6 +41,9 @@ class Serializer { template void WriteMessage(uint64_t field_index, const T& value); + template + void WriteRepeatedMessage(uint64_t field_index, const glcr::Vector& value); + void WriteHeader(); uint64_t size() const { return next_extension_; } @@ -90,4 +93,32 @@ void Serializer::WriteMessage(uint64_t field_index, const T& value) { buffer_.WriteAt(field_offset(field_index), ptr); } +template +void Serializer::WriteRepeatedMessage(uint64_t field_index, + const glcr::Vector& value) { + uint64_t next_offset = next_extension_; + uint64_t length = 0; + + for (T& message : value) { + uint64_t msg_length = 0; + if (caps_) { + msg_length = message.SerializeToBytes(buffer_, offset_ + next_offset, + caps_.value().get()); + } else { + msg_length = message.SerializeToBytes(buffer_, offset_ + next_offset); + } + length += msg_length; + next_offset += msg_length; + } + + ExtensionPointer ptr{ + .offset = (uint32_t)next_extension_, + .length = (uint32_t)length, + }; + + next_extension_ += length; + + buffer_.WriteAt(field_offset(field_index), ptr); +} + } // namespace yunq diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp index 1b3cbc7..c245bec 100644 --- a/sys/denali/denali_server.cpp +++ b/sys/denali/denali_server.cpp @@ -35,26 +35,21 @@ glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, ReadResponse& resp) { ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); - if (req.lba().size() != req.sector_cnt().size()) { - return glcr::InvalidArgument("LBA and Sector Cnt must be the same length."); - } - uint64_t sector_cnt = 0; - for (uint64_t cnt : req.sector_cnt()) { - sector_cnt += cnt; + for (auto& block : req.blocks()) { + sector_cnt += block.size(); } uint64_t region_paddr; mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical( sector_cnt * 512, ®ion_paddr); - for (uint64_t i = 0; i < req.lba().size(); i++) { - uint64_t lba = req.lba().at(i); - uint64_t size = req.sector_cnt().at(i); - ASSIGN_OR_RETURN(auto semaphore, - device->IssueRead(lba, size, region_paddr)); + for (auto& block : req.blocks()) { + ASSIGN_OR_RETURN( + auto semaphore, + device->IssueRead(block.lba(), block.size(), region_paddr)); semaphore->Wait(); - region_paddr += size * 512; + region_paddr += block.size() * 512; } resp.set_device_id(req.device_id()); diff --git a/sys/denali/lib/denali/denali.yunq b/sys/denali/lib/denali/denali.yunq index cc3225b..450870c 100644 --- a/sys/denali/lib/denali/denali.yunq +++ b/sys/denali/lib/denali/denali.yunq @@ -16,10 +16,7 @@ message ReadRequest { message ReadManyRequest { u64 device_id; - // FIXME: Add repeated message fields. - // Must be the same length. - repeated u64 lba; - repeated u64 sector_cnt; + repeated DiskBlock blocks; } message ReadResponse { diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp index 81e82f0..de259cc 100644 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -109,33 +109,28 @@ glcr::Status ReadManyRequest::ParseFromBytesInternal(const yunq::MessageView& me RETURN_ERROR(message.CheckHeader()); // Parse device_id. ASSIGN_OR_RETURN(device_id_, message.ReadField(0)); - // Parse lba. - ASSIGN_OR_RETURN(lba_, message.ReadRepeated(1)); - - // Parse sector_cnt. - ASSIGN_OR_RETURN(sector_cnt_, message.ReadRepeated(2)); + // Parse blocks. + message.ReadRepeatedMessage(1, blocks_); return glcr::Status::Ok(); } uint64_t ReadManyRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 3); + 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, 3, caps); + yunq::Serializer serializer(bytes, offset, 2, caps); return SerializeInternal(serializer); } uint64_t ReadManyRequest::SerializeInternal(yunq::Serializer& serializer) const { // Write device_id. serializer.WriteField(0, device_id_); - // Write lba. - serializer.WriteRepeated(1, lba_); - // Write sector_cnt. - serializer.WriteRepeated(2, sector_cnt_); + // Write blocks. + serializer.WriteRepeatedMessage(1, blocks_); serializer.WriteHeader(); diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h index 2707234..7874c91 100644 --- a/sys/denali/lib/denali/denali.yunq.h +++ b/sys/denali/lib/denali/denali.yunq.h @@ -16,15 +16,20 @@ class DiskBlock { DiskBlock() {} // Delete copy and move until implemented. DiskBlock(const DiskBlock&) = delete; - DiskBlock(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: @@ -41,14 +46,18 @@ class ReadRequest { ReadRequest() {} // Delete copy and move until implemented. ReadRequest(const ReadRequest&) = delete; - ReadRequest(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_; } - void set_device_id(const uint64_t& value) { device_id_ = value; } + 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_; } @@ -66,23 +75,25 @@ class ReadManyRequest { ReadManyRequest() {} // Delete copy and move until implemented. ReadManyRequest(const ReadManyRequest&) = delete; - ReadManyRequest(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& lba() const { return lba_; } - void add_lba(const uint64_t& value) { lba_.PushBack(value); } - const glcr::Vector& sector_cnt() const { return sector_cnt_; } - void add_sector_cnt(const uint64_t& value) { sector_cnt_.PushBack(value); } + + const glcr::Vector& blocks() const { return blocks_; } + glcr::Vector& mutable_blocks() { return blocks_; } + void add_blocks(DiskBlock&& value) { blocks_.PushBack(glcr::Move(value)); } private: uint64_t device_id_; - glcr::Vector lba_; - glcr::Vector sector_cnt_; + glcr::Vector blocks_; // Parses everything except for caps. glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); @@ -94,17 +105,24 @@ class ReadResponse { ReadResponse() {} // Delete copy and move until implemented. ReadResponse(const ReadResponse&) = delete; - ReadResponse(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: diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp index 9de13f8..80308c6 100644 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp @@ -94,8 +94,10 @@ glcr::ErrorOr Ext2BlockReader::ReadBlocks( i++; curr_run_len++; } - req.add_lba(curr_start); - req.add_sector_cnt(curr_run_len * SectorsPerBlock()); + 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); diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h index aaf87c9..52daf7a 100644 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -16,13 +16,16 @@ class OpenFileRequest { OpenFileRequest() {} // Delete copy and move until implemented. OpenFileRequest(const OpenFileRequest&) = delete; - OpenFileRequest(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: @@ -38,17 +41,24 @@ class OpenFileResponse { OpenFileResponse() {} // Delete copy and move until implemented. OpenFileResponse(const OpenFileResponse&) = delete; - OpenFileResponse(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: @@ -66,13 +76,16 @@ class GetDirectoryRequest { GetDirectoryRequest() {} // Delete copy and move until implemented. GetDirectoryRequest(const GetDirectoryRequest&) = delete; - GetDirectoryRequest(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: @@ -88,13 +101,16 @@ class Directory { Directory() {} // Delete copy and move until implemented. Directory(const Directory&) = delete; - Directory(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: diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h index 2b2c618..af8eca1 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -16,13 +16,16 @@ class KeyboardListener { KeyboardListener() {} // Delete copy and move until implemented. KeyboardListener(const KeyboardListener&) = delete; - KeyboardListener(KeyboardListener&&) = delete; + KeyboardListener(KeyboardListener&&) = default; + KeyboardListener& operator=(KeyboardListener&&) = 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 z_cap_t& port_capability() const { return port_capability_; } + z_cap_t& mutable_port_capability() { return port_capability_; } void set_port_capability(const z_cap_t& value) { port_capability_ = value; } private: diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index 93f05e8..fff090e 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -18,15 +18,20 @@ class RegisterEndpointRequest { RegisterEndpointRequest() {} // Delete copy and move until implemented. RegisterEndpointRequest(const RegisterEndpointRequest&) = delete; - RegisterEndpointRequest(RegisterEndpointRequest&&) = delete; + RegisterEndpointRequest(RegisterEndpointRequest&&) = default; + RegisterEndpointRequest& operator=(RegisterEndpointRequest&&) = 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& endpoint_name() const { return endpoint_name_; } + glcr::String& mutable_endpoint_name() { return endpoint_name_; } void set_endpoint_name(const glcr::String& value) { endpoint_name_ = value; } + const z_cap_t& endpoint_capability() const { return endpoint_capability_; } + z_cap_t& mutable_endpoint_capability() { return endpoint_capability_; } void set_endpoint_capability(const z_cap_t& value) { endpoint_capability_ = value; } private: @@ -43,13 +48,16 @@ class GetEndpointRequest { GetEndpointRequest() {} // Delete copy and move until implemented. GetEndpointRequest(const GetEndpointRequest&) = delete; - GetEndpointRequest(GetEndpointRequest&&) = delete; + GetEndpointRequest(GetEndpointRequest&&) = default; + GetEndpointRequest& operator=(GetEndpointRequest&&) = 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& endpoint_name() const { return endpoint_name_; } + glcr::String& mutable_endpoint_name() { return endpoint_name_; } void set_endpoint_name(const glcr::String& value) { endpoint_name_ = value; } private: @@ -65,13 +73,16 @@ class Endpoint { Endpoint() {} // Delete copy and move until implemented. Endpoint(const Endpoint&) = delete; - Endpoint(Endpoint&&) = delete; + Endpoint(Endpoint&&) = default; + Endpoint& operator=(Endpoint&&) = 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 z_cap_t& endpoint() const { return endpoint_; } + z_cap_t& mutable_endpoint() { return endpoint_; } void set_endpoint(const z_cap_t& value) { endpoint_ = value; } private: @@ -87,15 +98,20 @@ class AhciInfo { AhciInfo() {} // Delete copy and move until implemented. AhciInfo(const AhciInfo&) = delete; - AhciInfo(AhciInfo&&) = delete; + AhciInfo(AhciInfo&&) = default; + AhciInfo& operator=(AhciInfo&&) = 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 z_cap_t& ahci_region() const { return ahci_region_; } + z_cap_t& mutable_ahci_region() { return ahci_region_; } void set_ahci_region(const z_cap_t& value) { ahci_region_ = value; } + const uint64_t& region_length() const { return region_length_; } + uint64_t& mutable_region_length() { return region_length_; } void set_region_length(const uint64_t& value) { region_length_ = value; } private: @@ -112,35 +128,60 @@ class FramebufferInfo { FramebufferInfo() {} // Delete copy and move until implemented. FramebufferInfo(const FramebufferInfo&) = delete; - FramebufferInfo(FramebufferInfo&&) = delete; + FramebufferInfo(FramebufferInfo&&) = default; + FramebufferInfo& operator=(FramebufferInfo&&) = 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& address_phys() const { return address_phys_; } + uint64_t& mutable_address_phys() { return address_phys_; } void set_address_phys(const uint64_t& value) { address_phys_ = value; } + const uint64_t& width() const { return width_; } + uint64_t& mutable_width() { return width_; } void set_width(const uint64_t& value) { width_ = value; } + const uint64_t& height() const { return height_; } + uint64_t& mutable_height() { return height_; } void set_height(const uint64_t& value) { height_ = value; } + const uint64_t& pitch() const { return pitch_; } + uint64_t& mutable_pitch() { return pitch_; } void set_pitch(const uint64_t& value) { pitch_ = value; } + const uint64_t& bpp() const { return bpp_; } + uint64_t& mutable_bpp() { return bpp_; } void set_bpp(const uint64_t& value) { bpp_ = value; } + const uint64_t& memory_model() const { return memory_model_; } + uint64_t& mutable_memory_model() { return memory_model_; } void set_memory_model(const uint64_t& value) { memory_model_ = value; } + const uint64_t& red_mask_size() const { return red_mask_size_; } + uint64_t& mutable_red_mask_size() { return red_mask_size_; } void set_red_mask_size(const uint64_t& value) { red_mask_size_ = value; } + const uint64_t& red_mask_shift() const { return red_mask_shift_; } + uint64_t& mutable_red_mask_shift() { return red_mask_shift_; } void set_red_mask_shift(const uint64_t& value) { red_mask_shift_ = value; } + const uint64_t& green_mask_size() const { return green_mask_size_; } + uint64_t& mutable_green_mask_size() { return green_mask_size_; } void set_green_mask_size(const uint64_t& value) { green_mask_size_ = value; } + const uint64_t& green_mask_shift() const { return green_mask_shift_; } + uint64_t& mutable_green_mask_shift() { return green_mask_shift_; } void set_green_mask_shift(const uint64_t& value) { green_mask_shift_ = value; } + const uint64_t& blue_mask_size() const { return blue_mask_size_; } + uint64_t& mutable_blue_mask_size() { return blue_mask_size_; } void set_blue_mask_size(const uint64_t& value) { blue_mask_size_ = value; } + const uint64_t& blue_mask_shift() const { return blue_mask_shift_; } + uint64_t& mutable_blue_mask_shift() { return blue_mask_shift_; } void set_blue_mask_shift(const uint64_t& value) { blue_mask_shift_ = value; } private: @@ -167,17 +208,24 @@ class DenaliInfo { DenaliInfo() {} // Delete copy and move until implemented. DenaliInfo(const DenaliInfo&) = delete; - DenaliInfo(DenaliInfo&&) = delete; + DenaliInfo(DenaliInfo&&) = default; + DenaliInfo& operator=(DenaliInfo&&) = 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 z_cap_t& denali_endpoint() const { return denali_endpoint_; } + z_cap_t& mutable_denali_endpoint() { return denali_endpoint_; } void set_denali_endpoint(const z_cap_t& value) { denali_endpoint_ = value; } + 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& lba_offset() const { return lba_offset_; } + uint64_t& mutable_lba_offset() { return lba_offset_; } void set_lba_offset(const uint64_t& value) { lba_offset_ = value; } private: diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index cf96c8c..d58c707 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -63,7 +63,7 @@ glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& m {%- if not field.repeated %} message.ReadMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {%- else %} - message.ReadMessageRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); + message.ReadRepeatedMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {% endif %} {%- elif field.type != Type.CAPABILITY %} @@ -105,10 +105,12 @@ uint64_t {{message.name}}::SerializeInternal(yunq::Serializer& serializer) const {%- else %} -{%- if field.type != Type.CAPABILITY %} - serializer.WriteRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); -{%- else %} +{%- if field.type == Type.MESSAGE %} + serializer.WriteRepeatedMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); +{%- elif field.type != Type.CAPABILITY %} serializer.WriteRepeatedCapability({{field.number}}, {{field.name}}_); +{%- else %} + serializer.WriteRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); {%- endif %} {%- endif %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index 5274771..2cca2c2 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -20,7 +20,8 @@ class {{message.name}} { {{message.name}}() {} // Delete copy and move until implemented. {{message.name}}(const {{message.name}}&) = delete; - {{message.name}}({{message.name}}&&) = delete; + {{message.name}}({{message.name}}&&) = default; + {{message.name}}& operator=({{message.name}}&&) = default; [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); @@ -28,19 +29,24 @@ class {{message.name}} { uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; {%- for field in message.fields %} - {%- if field.type == Type.MESSAGE %} + {%- if not field.repeated %} + const {{field.cpp_type()}}& {{field.name}}() const { return {{field.name}}_; } {{field.cpp_type()}}& mutable_{{field.name}}() { return {{field.name}}_; } + {%- if field.type != Type.MESSAGE %} + void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; } + {%- endif %} + {%- else %} - {%- if not field.repeated %} - const {{field.cpp_type()}}& {{field.name}}() const { return {{field.name}}_; } - void set_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_ = value; } - {%- else %} const glcr::Vector<{{field.cpp_type()}}>& {{field.name}}() const { return {{field.name}}_; } + glcr::Vector<{{field.cpp_type()}}>& mutable_{{field.name}}() { return {{field.name}}_; } + + {%- if field.type != Type.MESSAGE %} void add_{{field.name}}(const {{field.cpp_type()}}& value) { {{field.name}}_.PushBack(value); } {%- endif %} + void add_{{field.name}}({{field.cpp_type()}}&& value) { {{field.name}}_.PushBack(glcr::Move(value)); } {%- endif %} {%- endfor %} From fecaa387b0d2258ed24d14d87323f3ded9bf3b37 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 16 Jan 2024 18:58:03 -0800 Subject: [PATCH 048/186] [Yunq] Add a basic yunq test into libyunq. --- CMakeLists.txt | 12 +- lib/glacier/test/CMakeLists.txt | 8 - lib/glacier/test/container/CMakeLists.txt | 4 + lib/yunq/CMakeLists.txt | 4 + lib/yunq/test/CMakeLists.txt | 42 +++++ lib/yunq/test/example/example.yunq | 5 + lib/yunq/test/example/example.yunq.cpp | 58 ++++++ lib/yunq/test/example/example.yunq.h | 43 +++++ lib/yunq/test/yunq_test.cpp | 23 +++ sys/denali/lib/denali/denali.yunq.client.cpp | 100 ---------- sys/denali/lib/denali/denali.yunq.cpp | 186 ------------------- sys/denali/lib/denali/denali.yunq.server.cpp | 152 --------------- yunq/CMakeLists.txt | 1 + yunq/example/example.yunq | 16 -- yunq/example/example.yunq.client.cpp | 64 ------- yunq/example/example.yunq.client.h | 37 ---- yunq/example/example.yunq.cpp | 110 ----------- yunq/example/example.yunq.h | 71 ------- yunq/example/example.yunq.server.cpp | 135 -------------- yunq/example/example.yunq.server.h | 50 ----- zion/CMakeLists.txt | 4 - 21 files changed, 189 insertions(+), 936 deletions(-) create mode 100644 lib/yunq/test/CMakeLists.txt create mode 100644 lib/yunq/test/example/example.yunq create mode 100644 lib/yunq/test/example/example.yunq.cpp create mode 100644 lib/yunq/test/example/example.yunq.h create mode 100644 lib/yunq/test/yunq_test.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.client.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.server.cpp delete mode 100644 yunq/example/example.yunq delete mode 100644 yunq/example/example.yunq.client.cpp delete mode 100644 yunq/example/example.yunq.client.h delete mode 100644 yunq/example/example.yunq.cpp delete mode 100644 yunq/example/example.yunq.h delete mode 100644 yunq/example/example.yunq.server.cpp delete mode 100644 yunq/example/example.yunq.server.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a74759..7332fe2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,6 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") project(AcadiaOS VERSION 0.0.1 LANGUAGES CXX ASM-ATT) -include(CTest) - set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_EXPORT_COMPILE_COMMANDS True) @@ -14,8 +12,16 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS True) set(BASE_COMPILE_FLAGS "-ffreestanding -fno-rtti -fno-exceptions -mincoming-stack-boundary=3") set(BASE_LINK_FLAGS "-nostdlib") +if (enable_testing) + include(CTest) + find_package(Catch2 3 REQUIRED) + find_program(MEMORYCHECK_COMMAND valgrind) + set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") + add_custom_target(build_test) +endif() + add_subdirectory(zion) -add_subdirectory(lib) add_subdirectory(yunq) +add_subdirectory(lib) add_subdirectory(usr) add_subdirectory(sys) diff --git a/lib/glacier/test/CMakeLists.txt b/lib/glacier/test/CMakeLists.txt index 1396d3b..c3701f7 100644 --- a/lib/glacier/test/CMakeLists.txt +++ b/lib/glacier/test/CMakeLists.txt @@ -1,10 +1,2 @@ -find_package(Catch2 3 REQUIRED) -find_program(MEMORYCHECK_COMMAND valgrind) -set(MEMORYCHECK_COMMAND_OPTIONS "--trace-children=yes --leak-check=full") - add_subdirectory(container) -add_custom_target(build_test) -add_dependencies(build_test - glc_vec_test) - diff --git a/lib/glacier/test/container/CMakeLists.txt b/lib/glacier/test/container/CMakeLists.txt index 2fad536..f5488ab 100644 --- a/lib/glacier/test/container/CMakeLists.txt +++ b/lib/glacier/test/container/CMakeLists.txt @@ -2,3 +2,7 @@ add_executable(glc_vec_test vector.cpp) target_link_libraries(glc_vec_test glacier Catch2::Catch2WithMain) target_include_directories(glc_vec_test PRIVATE "../..") add_test(NAME glc_vec_test COMMAND $) + +add_dependencies(build_test + glc_vec_test) + diff --git a/lib/yunq/CMakeLists.txt b/lib/yunq/CMakeLists.txt index 5fd7a31..2c87371 100644 --- a/lib/yunq/CMakeLists.txt +++ b/lib/yunq/CMakeLists.txt @@ -16,3 +16,7 @@ target_include_directories(yunq set_target_properties(yunq PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}") + +if (enable_testing) + add_subdirectory(test) +endif() diff --git a/lib/yunq/test/CMakeLists.txt b/lib/yunq/test/CMakeLists.txt new file mode 100644 index 0000000..c66b271 --- /dev/null +++ b/lib/yunq/test/CMakeLists.txt @@ -0,0 +1,42 @@ +add_executable(yunq_test yunq_test.cpp) + +add_dependencies(yunq_test + example_yunq) + +target_link_libraries(yunq_test + Catch2::Catch2WithMain + example_yunq) + +target_include_directories(yunq_test PRIVATE "." "../../../zion/include") + +add_test(NAME yunq_test COMMAND $) + +add_dependencies(build_test + yunq_test) + + +# Build the yunq manualy rather than using the generator +# because we don't want to link against mammoth and overrite new. +set(target example_yunq) +add_library(example_yunq + ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq.cpp + ) + +target_include_directories(example_yunq + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/example" + ) + +target_link_libraries(${target} + glacier + yunq + zion_stub +) + +set(PYTHON "${CMAKE_SOURCE_DIR}/yunq/venv/bin/python") +set(YUNQ "${CMAKE_SOURCE_DIR}/yunq/yunq.py") + +add_custom_command( + OUTPUT example/example.yunq.cpp + COMMAND ${PYTHON} ${YUNQ} ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq +) diff --git a/lib/yunq/test/example/example.yunq b/lib/yunq/test/example/example.yunq new file mode 100644 index 0000000..eaf2a9f --- /dev/null +++ b/lib/yunq/test/example/example.yunq @@ -0,0 +1,5 @@ +package ex; + +message Basic { + u64 field; +} diff --git a/lib/yunq/test/example/example.yunq.cpp b/lib/yunq/test/example/example.yunq.cpp new file mode 100644 index 0000000..7b5733e --- /dev/null +++ b/lib/yunq/test/example/example.yunq.cpp @@ -0,0 +1,58 @@ +// Generated file -- DO NOT MODIFY. +#include "example.yunq.h" + +#include +#include + + +namespace ex { + +namespace { + +const uint64_t header_size = 24; // 4x uint32, 1x uint64 + +struct ExtPointer { + uint32_t offset; + uint32_t length; +}; + +} // namespace +glcr::Status Basic::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Basic::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Basic::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); + // Parse field. + ASSIGN_OR_RETURN(field_, message.ReadField(0)); + + return glcr::Status::Ok(); +} + +uint64_t Basic::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + yunq::Serializer serializer(bytes, offset, 1); + return SerializeInternal(serializer); +} + +uint64_t Basic::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t Basic::SerializeInternal(yunq::Serializer& serializer) const { + // Write field. + serializer.WriteField(0, field_); + + serializer.WriteHeader(); + + return serializer.size(); +} + + +} // namepace ex diff --git a/lib/yunq/test/example/example.yunq.h b/lib/yunq/test/example/example.yunq.h new file mode 100644 index 0000000..bbaab36 --- /dev/null +++ b/lib/yunq/test/example/example.yunq.h @@ -0,0 +1,43 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace ex { + +class Basic { + public: + Basic() {} + // Delete copy and move until implemented. + Basic(const Basic&) = delete; + Basic(Basic&&) = default; + Basic& operator=(Basic&&) = 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& field() const { return field_; } + uint64_t& mutable_field() { return field_; } + void set_field(const uint64_t& value) { field_ = value; } + + private: + uint64_t field_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; +}; + + +} // namepace ex diff --git a/lib/yunq/test/yunq_test.cpp b/lib/yunq/test/yunq_test.cpp new file mode 100644 index 0000000..126fdef --- /dev/null +++ b/lib/yunq/test/yunq_test.cpp @@ -0,0 +1,23 @@ +#include + +#include "example/example.yunq.h" + +TEST_CASE("Basic Setter/Getter", "[yunq]") { + ex::Basic b; + b.set_field(1); + REQUIRE(b.field() == 1); +} + +TEST_CASE("Basic serialization", "[yunq]") { + ex::Basic a; + a.set_field(1); + + glcr::ByteBuffer buf(1024); + a.SerializeToBytes(buf, 0); + + ex::Basic b; + yunq::MessageView v(buf, 0); + REQUIRE(b.ParseFromBytes(v).ok() == true); + + REQUIRE(b.field() == 1); +} diff --git a/sys/denali/lib/denali/denali.yunq.client.cpp b/sys/denali/lib/denali/denali.yunq.client.cpp deleted file mode 100644 index 09e6f6a..0000000 --- a/sys/denali/lib/denali/denali.yunq.client.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Generated file - DO NOT MODIFY -#include "denali.yunq.client.h" - -#include -#include -#include -#include - - - - -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(0, kSentinel); - buffer_.WriteAt(8, 0); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(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(0, kSentinel); - buffer_.WriteAt(8, 1); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(8)); - - - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); - - - return glcr::OK; -} - - - - diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp deleted file mode 100644 index de259cc..0000000 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "denali.yunq.h" - -#include -#include - - -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(0)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(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(0, lba_); - // Write size. - serializer.WriteField(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(0)); - // Parse block. - message.ReadMessage(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(0, device_id_); - // Write block. - serializer.WriteMessage(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(0)); - // Parse blocks. - message.ReadRepeatedMessage(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(0, device_id_); - // Write blocks. - serializer.WriteRepeatedMessage(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(0)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(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(0, device_id_); - // Write size. - serializer.WriteField(1, size_); - // Write memory. - serializer.WriteCapability(2, memory_); - - serializer.WriteHeader(); - - return serializer.size(); -} - diff --git a/sys/denali/lib/denali/denali.yunq.server.cpp b/sys/denali/lib/denali/denali.yunq.server.cpp deleted file mode 100644 index 4fe21f5..0000000 --- a/sys/denali/lib/denali/denali.yunq.server.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "denali.yunq.server.h" - -#include -#include - - -namespace { - -const uint32_t kSentinel = 0xBEEFDEAD; -const uint32_t kHeaderSize = 0x10; - -void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize); - buffer.WriteAt(8, err); -} - -void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize + message_length); - buffer.WriteAt(8, glcr::OK); -} - -} // namespace - - - -void DenaliServerBaseThreadBootstrap(void* server_base) { - ((DenaliServerBase*)server_base)->ServerThread(); -} - -DenaliServerBase::~DenaliServerBase() { - if (endpoint_ != 0) { - check(ZCapRelease(endpoint_)); - } -} - -glcr::ErrorOr DenaliServerBase::CreateClientCap() { - uint64_t client_cap; - RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); - return client_cap; -} - -glcr::ErrorOr 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(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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); - } else { - WriteHeader(resp_buffer, resp_length); - reply_err = static_cast(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(0) != kSentinel) { - return glcr::InvalidArgument("Request Not Valid"); - } - - uint64_t method_select = request.At(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(); -} - - diff --git a/yunq/CMakeLists.txt b/yunq/CMakeLists.txt index 271476d..df824b8 100644 --- a/yunq/CMakeLists.txt +++ b/yunq/CMakeLists.txt @@ -19,6 +19,7 @@ macro(yunq_gen dir include_dir name) mammoth glacier yunq + zion_stub ) set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" diff --git a/yunq/example/example.yunq b/yunq/example/example.yunq deleted file mode 100644 index f286199..0000000 --- a/yunq/example/example.yunq +++ /dev/null @@ -1,16 +0,0 @@ -package srv.file; - -interface VFS { - method open (OpenFileRequest) -> (File); -} - -message OpenFileRequest { - string path; - repeated u64 options; -} - -message File { - string path; - u64 attrs; - capability mem_cap; -} diff --git a/yunq/example/example.yunq.client.cpp b/yunq/example/example.yunq.client.cpp deleted file mode 100644 index 406e895..0000000 --- a/yunq/example/example.yunq.client.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Generated file - DO NOT MODIFY -#include "example.yunq.client.h" - -#include -#include -#include -#include - - -namespace srv::file { - - - -VFSClient::~VFSClient() { - if (endpoint_ != 0) { - check(ZCapRelease(endpoint_)); - } -} - - - - -glcr::Status VFSClient::open(const OpenFileRequest& request, File& response) { - - uint64_t buffer_size = kBufferSize; - uint64_t cap_size = kCapBufferSize; - - const uint32_t kSentinel = 0xBEEFDEAD; - buffer_.WriteAt(0, kSentinel); - buffer_.WriteAt(8, 0); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(8)); - - - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); - - - return glcr::OK; -} - - - - - -} // namepace srv::file diff --git a/yunq/example/example.yunq.client.h b/yunq/example/example.yunq.client.h deleted file mode 100644 index 826d920..0000000 --- a/yunq/example/example.yunq.client.h +++ /dev/null @@ -1,37 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include - -#include "example.yunq.h" - - -namespace srv::file { - -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 open(const OpenFileRequest& request, File& response); - - - private: - z_cap_t endpoint_; - uint64_t kBufferSize = 0x1000; - glcr::ByteBuffer buffer_{kBufferSize}; - uint64_t kCapBufferSize = 0x10; - glcr::CapBuffer cap_buffer_{kCapBufferSize}; -}; - - -} // namepace srv::file diff --git a/yunq/example/example.yunq.cpp b/yunq/example/example.yunq.cpp deleted file mode 100644 index 4033cfc..0000000 --- a/yunq/example/example.yunq.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "example.yunq.h" - -#include -#include - - -namespace srv::file { - -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(0)); - // Parse options. - ASSIGN_OR_RETURN(options_, message.ReadRepeated(1)); - - - return glcr::Status::Ok(); -} - -uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 2); - return SerializeInternal(serializer); -} - -uint64_t OpenFileRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - yunq::Serializer serializer(bytes, offset, 2, caps); - return SerializeInternal(serializer); -} - -uint64_t OpenFileRequest::SerializeInternal(yunq::Serializer& serializer) const { - // Write path. - serializer.WriteField(0, path_); - // Write options. - serializer.WriteRepeated(1, options_); - - serializer.WriteHeader(); - - return serializer.size(); -} -glcr::Status File::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); - // Parse mem_cap. - ASSIGN_OR_RETURN(mem_cap_, message.ReadCapability(2)); - return glcr::Status::Ok(); -} - -glcr::Status File::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); - // Parse mem_cap. - ASSIGN_OR_RETURN(mem_cap_, message.ReadCapability(2, caps)); - return glcr::Status::Ok(); -} - -glcr::Status File::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); - // Parse path. - ASSIGN_OR_RETURN(path_, message.ReadField(0)); - // Parse attrs. - ASSIGN_OR_RETURN(attrs_, message.ReadField(1)); - // Parse mem_cap. - - return glcr::Status::Ok(); -} - -uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 3); - return SerializeInternal(serializer); -} - -uint64_t File::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { - yunq::Serializer serializer(bytes, offset, 3, caps); - return SerializeInternal(serializer); -} - -uint64_t File::SerializeInternal(yunq::Serializer& serializer) const { - // Write path. - serializer.WriteField(0, path_); - // Write attrs. - serializer.WriteField(1, attrs_); - // Write mem_cap. - serializer.WriteCapability(2, mem_cap_); - - serializer.WriteHeader(); - - return serializer.size(); -} - - -} // namepace srv::file diff --git a/yunq/example/example.yunq.h b/yunq/example/example.yunq.h deleted file mode 100644 index 112ddab..0000000 --- a/yunq/example/example.yunq.h +++ /dev/null @@ -1,71 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - - -namespace srv::file { - -class OpenFileRequest { - public: - OpenFileRequest() {} - // Delete copy and move until implemented. - OpenFileRequest(const OpenFileRequest&) = delete; - OpenFileRequest(OpenFileRequest&&) = delete; - - [[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_; } - void set_path(const glcr::String& value) { path_ = value; } - const glcr::Vector& options() const { return options_; } - void add_options(const uint64_t& value) { options_.PushBack(value); } - - private: - glcr::String path_; - glcr::Vector options_; - - // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; -}; -class File { - public: - File() {} - // Delete copy and move until implemented. - File(const File&) = delete; - File(File&&) = delete; - - [[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_; } - void set_path(const glcr::String& value) { path_ = value; } - const uint64_t& attrs() const { return attrs_; } - void set_attrs(const uint64_t& value) { attrs_ = value; } - const z_cap_t& mem_cap() const { return mem_cap_; } - void set_mem_cap(const z_cap_t& value) { mem_cap_ = value; } - - private: - glcr::String path_; - uint64_t attrs_; - z_cap_t mem_cap_; - - // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; -}; - - -} // namepace srv::file diff --git a/yunq/example/example.yunq.server.cpp b/yunq/example/example.yunq.server.cpp deleted file mode 100644 index 5c3b84c..0000000 --- a/yunq/example/example.yunq.server.cpp +++ /dev/null @@ -1,135 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "example.yunq.server.h" - -#include -#include - - -namespace srv::file { - -namespace { - -const uint32_t kSentinel = 0xBEEFDEAD; -const uint32_t kHeaderSize = 0x10; - -void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize); - buffer.WriteAt(8, err); -} - -void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize + message_length); - buffer.WriteAt(8, glcr::OK); -} - -} // namespace - - - -void VFSServerBaseThreadBootstrap(void* server_base) { - ((VFSServerBase*)server_base)->ServerThread(); -} - -VFSServerBase::~VFSServerBase() { - if (endpoint_ != 0) { - check(ZCapRelease(endpoint_)); - } -} - -glcr::ErrorOr VFSServerBase::CreateClientCap() { - uint64_t client_cap; - RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); - return client_cap; -} - -glcr::ErrorOr 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(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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); - } else { - WriteHeader(resp_buffer, resp_length); - reply_err = static_cast(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(0) != kSentinel) { - return glcr::InvalidArgument("Request Not Valid"); - } - - uint64_t method_select = request.At(8); - - switch(method_select) { - case 0: { - - - OpenFileRequest yunq_request; - yunq::MessageView request_view(request, kHeaderSize); - RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); - - - - File yunq_response; - - - - RETURN_ERROR(Handleopen(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(); -} - - - -} // namepace srv::file diff --git a/yunq/example/example.yunq.server.h b/yunq/example/example.yunq.server.h deleted file mode 100644 index 646e669..0000000 --- a/yunq/example/example.yunq.server.h +++ /dev/null @@ -1,50 +0,0 @@ -// Generated File -- DO NOT MODIFY. -#pragma once - -#include -#include -#include -#include - -#include "example.yunq.h" -#include "example.yunq.client.h" - - -namespace srv::file { - - - - -class VFSServerBase { - public: - VFSServerBase(z_cap_t VFS_cap) : endpoint_(VFS_cap) {} - VFSServerBase(const VFSServerBase&) = delete; - VFSServerBase(VFSServerBase&&) = delete; - virtual ~VFSServerBase(); - - glcr::ErrorOr CreateClientCap(); - glcr::ErrorOr CreateClient(); - - [[nodiscard]] Thread RunServer(); - - - - [[nodiscard]] virtual glcr::Status Handleopen(const OpenFileRequest&, File&) = 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); -}; - - - - -} // namepace srv::file diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 2e63927..e42ee29 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -99,7 +99,3 @@ add_library(zion_stub STATIC target_include_directories(zion_stub PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) - -set_target_properties(zion_stub - PROPERTIES - COMPILE_FLAGS "${_Z_COMPILE_FLAGS}") From e83720e67ca3c6d2729cd91616172152c4ee4070 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 13:56:22 -0800 Subject: [PATCH 049/186] [Yunq] Only generate client and server files if an interface exists. --- yunq/yunq.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/yunq/yunq.py b/yunq/yunq.py index 743f08c..ad6e944 100755 --- a/yunq/yunq.py +++ b/yunq/yunq.py @@ -45,6 +45,9 @@ def main(): message_impl = message_impl_tmpl.render(file=filebase, messages=messages, package=package) f.write(message_impl) + if len(interfaces) == 0: + return + client_header_tmpl = jinja_env.get_template("client.h.jinja") with open(filename + '.client.h', mode='w') as f: client_header = client_header_tmpl.render(file=filebase, interfaces=interfaces, package=package) From a1f0197e83f29fd1c559221907b6ed773a0fa244 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 13:57:02 -0800 Subject: [PATCH 050/186] [Yunq] Add parse/serialize for i64 field along with tests. --- lib/yunq/message_view.cpp | 6 ++ lib/yunq/message_view.h | 4 ++ lib/yunq/serialize.cpp | 6 ++ lib/yunq/serialize.h | 5 +- lib/yunq/test/CMakeLists.txt | 4 +- lib/yunq/test/example/example.yunq | 10 ++++ lib/yunq/test/example/example.yunq.cpp | 83 ++++++++++++++++++++++++++ lib/yunq/test/example/example.yunq.h | 60 +++++++++++++++++++ lib/yunq/test/yunq_test.cpp | 11 ++++ 9 files changed, 187 insertions(+), 2 deletions(-) diff --git a/lib/yunq/message_view.cpp b/lib/yunq/message_view.cpp index 960f8c4..4a3b7df 100644 --- a/lib/yunq/message_view.cpp +++ b/lib/yunq/message_view.cpp @@ -29,6 +29,12 @@ glcr::ErrorOr MessageView::ReadField( return buffer_.At(field_offset(field_index)); } +template <> +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index) const { + return buffer_.At(field_offset(field_index)); +} + template <> glcr::ErrorOr MessageView::ReadField( uint64_t field_index) const { diff --git a/lib/yunq/message_view.h b/lib/yunq/message_view.h index 78a11ea..4be5535 100644 --- a/lib/yunq/message_view.h +++ b/lib/yunq/message_view.h @@ -49,6 +49,10 @@ template <> glcr::ErrorOr MessageView::ReadField( uint64_t field_index) const; +template <> +glcr::ErrorOr MessageView::ReadField( + uint64_t field_index) const; + template <> glcr::ErrorOr MessageView::ReadField( uint64_t field_index) const; diff --git a/lib/yunq/serialize.cpp b/lib/yunq/serialize.cpp index 188685a..7b7852d 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -20,6 +20,12 @@ void Serializer::WriteField(uint64_t field_index, buffer_.WriteAt(field_offset(field_index), value); } +template <> +void Serializer::WriteField(uint64_t field_index, + const int64_t& value) { + buffer_.WriteAt(field_offset(field_index), value); +} + template <> void Serializer::WriteField(uint64_t field_index, const glcr::String& value) { diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index b19ea4b..b0c84c3 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -26,7 +26,6 @@ class Serializer { next_extension_(kHeaderSize + (8 * num_fields)), core_size_(next_extension_), caps_(caps) {} - template void WriteField(uint64_t field_index, const T& value); @@ -65,6 +64,10 @@ template <> void Serializer::WriteField(uint64_t field_index, const uint64_t& value); +template <> +void Serializer::WriteField(uint64_t field_index, + const int64_t& value); + template <> void Serializer::WriteField(uint64_t field_index, const glcr::String& value); diff --git a/lib/yunq/test/CMakeLists.txt b/lib/yunq/test/CMakeLists.txt index c66b271..f05d41c 100644 --- a/lib/yunq/test/CMakeLists.txt +++ b/lib/yunq/test/CMakeLists.txt @@ -36,7 +36,9 @@ set(PYTHON "${CMAKE_SOURCE_DIR}/yunq/venv/bin/python") set(YUNQ "${CMAKE_SOURCE_DIR}/yunq/yunq.py") add_custom_command( - OUTPUT example/example.yunq.cpp + OUTPUT + ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq.h COMMAND ${PYTHON} ${YUNQ} ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/example/example.yunq ) diff --git a/lib/yunq/test/example/example.yunq b/lib/yunq/test/example/example.yunq index eaf2a9f..e6a27cd 100644 --- a/lib/yunq/test/example/example.yunq +++ b/lib/yunq/test/example/example.yunq @@ -3,3 +3,13 @@ package ex; message Basic { u64 field; } + +message Types { + u64 unsigned_int; + i64 signed_int; + string str; +} + +message Cap { + capability cap; +} diff --git a/lib/yunq/test/example/example.yunq.cpp b/lib/yunq/test/example/example.yunq.cpp index 7b5733e..745d8fa 100644 --- a/lib/yunq/test/example/example.yunq.cpp +++ b/lib/yunq/test/example/example.yunq.cpp @@ -53,6 +53,89 @@ uint64_t Basic::SerializeInternal(yunq::Serializer& serializer) const { return serializer.size(); } +glcr::Status Types::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Types::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Types::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); + // Parse unsigned_int. + ASSIGN_OR_RETURN(unsigned_int_, message.ReadField(0)); + // Parse signed_int. + ASSIGN_OR_RETURN(signed_int_, message.ReadField(1)); + // Parse str. + ASSIGN_OR_RETURN(str_, message.ReadField(2)); + + return glcr::Status::Ok(); +} + +uint64_t Types::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + yunq::Serializer serializer(bytes, offset, 3); + return SerializeInternal(serializer); +} + +uint64_t Types::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + yunq::Serializer serializer(bytes, offset, 3, caps); + return SerializeInternal(serializer); +} + +uint64_t Types::SerializeInternal(yunq::Serializer& serializer) const { + // Write unsigned_int. + serializer.WriteField(0, unsigned_int_); + // Write signed_int. + serializer.WriteField(1, signed_int_); + // Write str. + serializer.WriteField(2, str_); + + serializer.WriteHeader(); + + return serializer.size(); +} +glcr::Status Cap::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + // Parse cap. + ASSIGN_OR_RETURN(cap_, message.ReadCapability(0)); + return glcr::Status::Ok(); +} + +glcr::Status Cap::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + // Parse cap. + ASSIGN_OR_RETURN(cap_, message.ReadCapability(0, caps)); + return glcr::Status::Ok(); +} + +glcr::Status Cap::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); + // Parse cap. + + return glcr::Status::Ok(); +} + +uint64_t Cap::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + yunq::Serializer serializer(bytes, offset, 1); + return SerializeInternal(serializer); +} + +uint64_t Cap::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t Cap::SerializeInternal(yunq::Serializer& serializer) const { + // Write cap. + serializer.WriteCapability(0, cap_); + + serializer.WriteHeader(); + + return serializer.size(); +} } // namepace ex diff --git a/lib/yunq/test/example/example.yunq.h b/lib/yunq/test/example/example.yunq.h index bbaab36..363a3f3 100644 --- a/lib/yunq/test/example/example.yunq.h +++ b/lib/yunq/test/example/example.yunq.h @@ -38,6 +38,66 @@ class Basic { uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; +class Types { + public: + Types() {} + // Delete copy and move until implemented. + Types(const Types&) = delete; + Types(Types&&) = default; + Types& operator=(Types&&) = 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& unsigned_int() const { return unsigned_int_; } + uint64_t& mutable_unsigned_int() { return unsigned_int_; } + void set_unsigned_int(const uint64_t& value) { unsigned_int_ = value; } + + const int64_t& signed_int() const { return signed_int_; } + int64_t& mutable_signed_int() { return signed_int_; } + void set_signed_int(const int64_t& value) { signed_int_ = value; } + + const glcr::String& str() const { return str_; } + glcr::String& mutable_str() { return str_; } + void set_str(const glcr::String& value) { str_ = value; } + + private: + uint64_t unsigned_int_; + int64_t signed_int_; + glcr::String str_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; +}; +class Cap { + public: + Cap() {} + // Delete copy and move until implemented. + Cap(const Cap&) = delete; + Cap(Cap&&) = default; + Cap& operator=(Cap&&) = 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 z_cap_t& cap() const { return cap_; } + z_cap_t& mutable_cap() { return cap_; } + void set_cap(const z_cap_t& value) { cap_ = value; } + + private: + z_cap_t cap_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; +}; } // namepace ex diff --git a/lib/yunq/test/yunq_test.cpp b/lib/yunq/test/yunq_test.cpp index 126fdef..d2e79a5 100644 --- a/lib/yunq/test/yunq_test.cpp +++ b/lib/yunq/test/yunq_test.cpp @@ -21,3 +21,14 @@ TEST_CASE("Basic serialization", "[yunq]") { REQUIRE(b.field() == 1); } + +TEST_CASE("Types Setter/Getter", "[yunq]") { + ex::Types t; + t.set_unsigned_int(1); + t.set_signed_int(-1); + t.set_str("test"); + + REQUIRE(t.unsigned_int() == 1); + REQUIRE(t.signed_int() == -1); + REQUIRE(t.str() == "test"); +} From cd1304beaea15d8ea2484205afb3b2a10f56b5b9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:12:46 -0800 Subject: [PATCH 051/186] [Denali] Add back accidentally deleted files. --- sys/denali/lib/denali/denali.yunq.client.cpp | 100 ++++++++++ sys/denali/lib/denali/denali.yunq.cpp | 186 +++++++++++++++++++ sys/denali/lib/denali/denali.yunq.server.cpp | 152 +++++++++++++++ zion/CMakeLists.txt | 7 + 4 files changed, 445 insertions(+) create mode 100644 sys/denali/lib/denali/denali.yunq.client.cpp create mode 100644 sys/denali/lib/denali/denali.yunq.cpp create mode 100644 sys/denali/lib/denali/denali.yunq.server.cpp diff --git a/sys/denali/lib/denali/denali.yunq.client.cpp b/sys/denali/lib/denali/denali.yunq.client.cpp new file mode 100644 index 0000000..09e6f6a --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.client.cpp @@ -0,0 +1,100 @@ +// Generated file - DO NOT MODIFY +#include "denali.yunq.client.h" + +#include +#include +#include +#include + + + + +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(0, kSentinel); + buffer_.WriteAt(8, 0); + + cap_buffer_.Reset(); + + uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); + + + buffer_.WriteAt(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(0) != kSentinel) { + return glcr::InvalidResponse("Got an invalid response from server."); + } + + // Check Response Code. + RET_ERR(buffer_.At(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(0, kSentinel); + buffer_.WriteAt(8, 1); + + cap_buffer_.Reset(); + + uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); + + + buffer_.WriteAt(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(0) != kSentinel) { + return glcr::InvalidResponse("Got an invalid response from server."); + } + + // Check Response Code. + RET_ERR(buffer_.At(8)); + + + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + + + return glcr::OK; +} + + + + diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp new file mode 100644 index 0000000..de259cc --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -0,0 +1,186 @@ +// Generated file -- DO NOT MODIFY. +#include "denali.yunq.h" + +#include +#include + + +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(0)); + // Parse size. + ASSIGN_OR_RETURN(size_, message.ReadField(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(0, lba_); + // Write size. + serializer.WriteField(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(0)); + // Parse block. + message.ReadMessage(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(0, device_id_); + // Write block. + serializer.WriteMessage(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(0)); + // Parse blocks. + message.ReadRepeatedMessage(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(0, device_id_); + // Write blocks. + serializer.WriteRepeatedMessage(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(0)); + // Parse size. + ASSIGN_OR_RETURN(size_, message.ReadField(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(0, device_id_); + // Write size. + serializer.WriteField(1, size_); + // Write memory. + serializer.WriteCapability(2, memory_); + + serializer.WriteHeader(); + + return serializer.size(); +} + diff --git a/sys/denali/lib/denali/denali.yunq.server.cpp b/sys/denali/lib/denali/denali.yunq.server.cpp new file mode 100644 index 0000000..4fe21f5 --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.server.cpp @@ -0,0 +1,152 @@ +// Generated file -- DO NOT MODIFY. +#include "denali.yunq.server.h" + +#include +#include + + +namespace { + +const uint32_t kSentinel = 0xBEEFDEAD; +const uint32_t kHeaderSize = 0x10; + +void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) { + buffer.WriteAt(0, kSentinel); + buffer.WriteAt(4, kHeaderSize); + buffer.WriteAt(8, err); +} + +void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) { + buffer.WriteAt(0, kSentinel); + buffer.WriteAt(4, kHeaderSize + message_length); + buffer.WriteAt(8, glcr::OK); +} + +} // namespace + + + +void DenaliServerBaseThreadBootstrap(void* server_base) { + ((DenaliServerBase*)server_base)->ServerThread(); +} + +DenaliServerBase::~DenaliServerBase() { + if (endpoint_ != 0) { + check(ZCapRelease(endpoint_)); + } +} + +glcr::ErrorOr DenaliServerBase::CreateClientCap() { + uint64_t client_cap; + RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); + return client_cap; +} + +glcr::ErrorOr 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(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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); + } else { + WriteHeader(resp_buffer, resp_length); + reply_err = static_cast(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(0) != kSentinel) { + return glcr::InvalidArgument("Request Not Valid"); + } + + uint64_t method_select = request.At(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(); +} + + diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index e42ee29..598a3de 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -99,3 +99,10 @@ add_library(zion_stub STATIC target_include_directories(zion_stub PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) + +set_target_properties(zion_stub + PROPERTIES + COMPILE_FLAGS "${BASE_COMPILE_FLAGS} -nostdlib -c" + LINK_FLAGS "${BASE_LINK_FLAGS} -nostartfiles -static -lgcc" + ) + From 3114ac110a24250e7bf4a8ef2243b88f45c34237 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:14:33 -0800 Subject: [PATCH 052/186] [Glacier] Fix string memory deletion (thanks valgrind)../scripts/qemu.sh --- lib/glacier/string/string.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/glacier/string/string.cpp b/lib/glacier/string/string.cpp index e0a5b67..a2b6db3 100644 --- a/lib/glacier/string/string.cpp +++ b/lib/glacier/string/string.cpp @@ -32,7 +32,7 @@ String::String(const String& other) : String(other.cstr_, other.length_) {} String& String::operator=(const String& other) { if (cstr_) { - delete cstr_; + delete[] cstr_; } length_ = other.length_; cstr_ = new char[length_ + 1]; @@ -51,7 +51,7 @@ String::String(String&& other) : cstr_(other.cstr_), length_(other.length_) { String& String::operator=(String&& other) { if (cstr_) { - delete cstr_; + delete[] cstr_; } cstr_ = other.cstr_; length_ = other.length_; @@ -64,7 +64,7 @@ String& String::operator=(String&& other) { String::~String() { if (cstr_) { - delete cstr_; + delete[] cstr_; } } From a98e66ac475aca632e61ab88238bfe74d8b91307 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:15:53 -0800 Subject: [PATCH 053/186] [Yunq] Add serialization tests for Types message. --- lib/yunq/test/CMakeLists.txt | 2 +- lib/yunq/test/yunq_test.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/yunq/test/CMakeLists.txt b/lib/yunq/test/CMakeLists.txt index f05d41c..d33b8e2 100644 --- a/lib/yunq/test/CMakeLists.txt +++ b/lib/yunq/test/CMakeLists.txt @@ -15,7 +15,7 @@ add_dependencies(build_test yunq_test) -# Build the yunq manualy rather than using the generator +# Build the yunq manually rather than using the generator # because we don't want to link against mammoth and overrite new. set(target example_yunq) add_library(example_yunq diff --git a/lib/yunq/test/yunq_test.cpp b/lib/yunq/test/yunq_test.cpp index d2e79a5..ade34d9 100644 --- a/lib/yunq/test/yunq_test.cpp +++ b/lib/yunq/test/yunq_test.cpp @@ -32,3 +32,21 @@ TEST_CASE("Types Setter/Getter", "[yunq]") { REQUIRE(t.signed_int() == -1); REQUIRE(t.str() == "test"); } + +TEST_CASE("Types Serialization", "[yunq]") { + ex::Types a; + a.set_unsigned_int(1); + a.set_signed_int(-1); + a.set_str("test"); + + glcr::ByteBuffer buf(1024); + a.SerializeToBytes(buf, 0); + + ex::Types b; + yunq::MessageView v(buf, 0); + REQUIRE(b.ParseFromBytes(v).ok() == true); + + REQUIRE(b.unsigned_int() == 1); + REQUIRE(b.signed_int() == -1); + REQUIRE(b.str() == "test"); +} From 01e10fb47e654bb2f552c70de1486a0dafa720d2 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:25:54 -0800 Subject: [PATCH 054/186] Set asm att compiler to gcc in the test environment. --- scripts/test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test.sh b/scripts/test.sh index 55d68b7..ec1b1eb 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -6,7 +6,7 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" pushd "$DIR/.." if [[ ! -e test-bin ]]; then - cmake -B test-bin/ -G Ninja -D enable_testing=on + cmake -B test-bin/ -G Ninja -D enable_testing=on -D CMAKE_ASM-ATT_COMPILER=gcc fi pushd test-bin/ ninja build_test From 9222f59da33150629f8d42cefde46b15d430936f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:31:52 -0800 Subject: [PATCH 055/186] [Yunq] Add tests for capability serialization. --- lib/yunq/test/yunq_test.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/yunq/test/yunq_test.cpp b/lib/yunq/test/yunq_test.cpp index ade34d9..675a7f2 100644 --- a/lib/yunq/test/yunq_test.cpp +++ b/lib/yunq/test/yunq_test.cpp @@ -50,3 +50,39 @@ TEST_CASE("Types Serialization", "[yunq]") { REQUIRE(b.signed_int() == -1); REQUIRE(b.str() == "test"); } + +TEST_CASE("Cap Setter/Getter", "[yunq]") { + ex::Cap c; + c.set_cap(1234); + + REQUIRE(c.cap() == 1234); +} + +TEST_CASE("Cap Serialization Inline", "[yunq]") { + ex::Cap a; + a.set_cap(1234); + + glcr::ByteBuffer buf(1024); + a.SerializeToBytes(buf, 0); + + ex::Cap b; + yunq::MessageView v(buf, 0); + REQUIRE(b.ParseFromBytes(v).ok() == true); + + REQUIRE(b.cap() == 1234); +} + +TEST_CASE("Cap Serialization Sidebuffer", "[yunq]") { + ex::Cap a; + a.set_cap(1234); + + glcr::ByteBuffer buf(1024); + glcr::CapBuffer caps(1); + a.SerializeToBytes(buf, 0, caps); + + ex::Cap b; + yunq::MessageView v(buf, 0); + REQUIRE(b.ParseFromBytes(v, caps).ok() == true); + + REQUIRE(b.cap() == 1234); +} From 65e9fa17677da1293b26c644814a6931cde044e5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 14:56:32 -0800 Subject: [PATCH 056/186] Update asm compiler for test-mem as well. --- scripts/test-mem.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-mem.sh b/scripts/test-mem.sh index 3a0c5bf..046c120 100755 --- a/scripts/test-mem.sh +++ b/scripts/test-mem.sh @@ -6,7 +6,7 @@ DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" pushd "$DIR/.." if [[ ! -e test-bin ]]; then - cmake -B test-bin/ -G Ninja -D enable_testing=on + cmake -B test-bin/ -G Ninja -D enable_testing=on -D CMAKE_ASM-ATT_COMPILER=gcc fi pushd test-bin/ ninja build_test From 27c39d05e82a5007bb895a83cb8fa3f601160476 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 17 Jan 2024 15:15:55 -0800 Subject: [PATCH 057/186] [Yunq] Add basic test for repeated fields. --- lib/yunq/test/example/example.yunq | 4 +++ lib/yunq/test/example/example.yunq.cpp | 37 ++++++++++++++++++++++++++ lib/yunq/test/example/example.yunq.h | 26 ++++++++++++++++++ lib/yunq/test/yunq_test.cpp | 12 +++++++++ yunq/message.cpp.jinja | 2 +- 5 files changed, 80 insertions(+), 1 deletion(-) diff --git a/lib/yunq/test/example/example.yunq b/lib/yunq/test/example/example.yunq index e6a27cd..7e7c927 100644 --- a/lib/yunq/test/example/example.yunq +++ b/lib/yunq/test/example/example.yunq @@ -13,3 +13,7 @@ message Types { message Cap { capability cap; } + +message Repeated { + repeated u64 unsigned_ints; +} diff --git a/lib/yunq/test/example/example.yunq.cpp b/lib/yunq/test/example/example.yunq.cpp index 745d8fa..08cbd0f 100644 --- a/lib/yunq/test/example/example.yunq.cpp +++ b/lib/yunq/test/example/example.yunq.cpp @@ -136,6 +136,43 @@ uint64_t Cap::SerializeInternal(yunq::Serializer& serializer) const { return serializer.size(); } +glcr::Status Repeated::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Repeated::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + return glcr::Status::Ok(); +} + +glcr::Status Repeated::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); + // Parse unsigned_ints. + ASSIGN_OR_RETURN(unsigned_ints_, message.ReadRepeated(0)); + + + return glcr::Status::Ok(); +} + +uint64_t Repeated::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + yunq::Serializer serializer(bytes, offset, 1); + return SerializeInternal(serializer); +} + +uint64_t Repeated::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + yunq::Serializer serializer(bytes, offset, 1, caps); + return SerializeInternal(serializer); +} + +uint64_t Repeated::SerializeInternal(yunq::Serializer& serializer) const { + // Write unsigned_ints. + serializer.WriteRepeated(0, unsigned_ints_); + + serializer.WriteHeader(); + + return serializer.size(); +} } // namepace ex diff --git a/lib/yunq/test/example/example.yunq.h b/lib/yunq/test/example/example.yunq.h index 363a3f3..83232e5 100644 --- a/lib/yunq/test/example/example.yunq.h +++ b/lib/yunq/test/example/example.yunq.h @@ -98,6 +98,32 @@ class Cap { uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; +class Repeated { + public: + Repeated() {} + // Delete copy and move until implemented. + Repeated(const Repeated&) = delete; + Repeated(Repeated&&) = default; + Repeated& operator=(Repeated&&) = 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::Vector& unsigned_ints() const { return unsigned_ints_; } + glcr::Vector& mutable_unsigned_ints() { return unsigned_ints_; } + void add_unsigned_ints(const uint64_t& value) { unsigned_ints_.PushBack(value); } + void add_unsigned_ints(uint64_t&& value) { unsigned_ints_.PushBack(glcr::Move(value)); } + + private: + glcr::Vector unsigned_ints_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; +}; } // namepace ex diff --git a/lib/yunq/test/yunq_test.cpp b/lib/yunq/test/yunq_test.cpp index 675a7f2..d22a846 100644 --- a/lib/yunq/test/yunq_test.cpp +++ b/lib/yunq/test/yunq_test.cpp @@ -86,3 +86,15 @@ TEST_CASE("Cap Serialization Sidebuffer", "[yunq]") { REQUIRE(b.cap() == 1234); } + +TEST_CASE("Repeated Setter/Getter", "[yunq]") { + ex::Repeated r; + r.mutable_unsigned_ints().PushBack(1); + r.add_unsigned_ints(2); + uint64_t c = 3; + r.add_unsigned_ints(glcr::Move(c)); + + REQUIRE(r.unsigned_ints()[0] == 1); + REQUIRE(r.unsigned_ints()[1] == 2); + REQUIRE(r.unsigned_ints()[2] == 3); +} diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index d58c707..b5e36b9 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -107,7 +107,7 @@ uint64_t {{message.name}}::SerializeInternal(yunq::Serializer& serializer) const {%- if field.type == Type.MESSAGE %} serializer.WriteRepeatedMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); -{%- elif field.type != Type.CAPABILITY %} +{%- elif field.type == Type.CAPABILITY %} serializer.WriteRepeatedCapability({{field.number}}, {{field.name}}_); {%- else %} serializer.WriteRepeated<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); From 3bacfea1830da807546faec15af0cef840497ff5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 6 Feb 2024 20:49:43 -0800 Subject: [PATCH 058/186] [Yellowstone] Add method to get XHCI configuration space. --- sys/yellowstone/hw/pcie.cpp | 17 ++++++- sys/yellowstone/hw/pcie.h | 2 + .../lib/yellowstone/yellowstone.yunq | 6 +++ .../yellowstone/yellowstone.yunq.client.cpp | 44 ++++++++++++++++++- .../lib/yellowstone/yellowstone.yunq.client.h | 4 ++ .../lib/yellowstone/yellowstone.yunq.cpp | 43 ++++++++++++++++++ .../lib/yellowstone/yellowstone.yunq.h | 30 +++++++++++++ .../yellowstone/yellowstone.yunq.server.cpp | 19 +++++++- .../lib/yellowstone/yellowstone.yunq.server.h | 4 ++ sys/yellowstone/yellowstone_server.cpp | 6 +++ sys/yellowstone/yellowstone_server.h | 1 + 11 files changed, 172 insertions(+), 4 deletions(-) diff --git a/sys/yellowstone/hw/pcie.cpp b/sys/yellowstone/hw/pcie.cpp index 08a2e7b..ebec187 100644 --- a/sys/yellowstone/hw/pcie.cpp +++ b/sys/yellowstone/hw/pcie.cpp @@ -4,7 +4,7 @@ #include #include -#define PCI_DEBUG 0 +#define PCI_DEBUG 1 namespace { @@ -32,6 +32,13 @@ z_cap_t PciReader::GetAhciVmmo() { return new_cap; } +z_cap_t PciReader::GetXhciVmmo() { + uint64_t new_cap; + check(ZMemoryObjectDuplicate(gBootPciVmmoCap, xhci_device_offset_, + kPcieConfigurationSize, &new_cap)); + return new_cap; +} + void PciReader::FunctionDump(uint64_t base, uint64_t bus, uint64_t dev, uint64_t fun) { PciDeviceHeader* hdr = PciHeader(base, bus, dev, fun); @@ -55,6 +62,14 @@ void PciReader::FunctionDump(uint64_t base, uint64_t bus, uint64_t dev, #endif achi_device_offset_ = reinterpret_cast(hdr) - base; } + + if (hdr->class_code == 0xC && hdr->subclass == 0x3) { + if (hdr->prog_interface == 0x30) { + xhci_device_offset_ = reinterpret_cast(hdr) - base; + } else { + dbgln("WARN: Non-XHCI USB Controller found"); + } + } } void PciReader::DeviceDump(uint64_t base, uint64_t bus, uint64_t dev) { diff --git a/sys/yellowstone/hw/pcie.h b/sys/yellowstone/hw/pcie.h index d9e5778..6b73b31 100644 --- a/sys/yellowstone/hw/pcie.h +++ b/sys/yellowstone/hw/pcie.h @@ -28,11 +28,13 @@ class PciReader { PciReader(); z_cap_t GetAhciVmmo(); + z_cap_t GetXhciVmmo(); private: PciDeviceHeader* header_; uint64_t achi_device_offset_ = 0; + uint64_t xhci_device_offset_ = 0; void PciDump(uint64_t vaddr); void BusDump(uint64_t base, uint64_t bus); diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq b/sys/yellowstone/lib/yellowstone/yellowstone.yunq index 95b3dfb..3bf9d9d 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq @@ -4,6 +4,7 @@ interface Yellowstone { method RegisterEndpoint(RegisterEndpointRequest) -> (); method GetEndpoint(GetEndpointRequest) -> (Endpoint); method GetAhciInfo() -> (AhciInfo); + method GetXhciInfo() -> (XhciInfo); method GetFramebufferInfo() -> (FramebufferInfo); method GetDenali() -> (DenaliInfo); } @@ -26,6 +27,11 @@ message AhciInfo { u64 region_length; } +message XhciInfo { + capability xhci_region; + u64 region_length; +} + message FramebufferInfo { u64 address_phys; u64 width; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp index 03352e1..05f451c 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp @@ -137,7 +137,7 @@ glcr::Status YellowstoneClient::GetAhciInfo(AhciInfo& response) { -glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { +glcr::Status YellowstoneClient::GetXhciInfo(XhciInfo& response) { uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -177,7 +177,7 @@ glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { -glcr::Status YellowstoneClient::GetDenali(DenaliInfo& response) { +glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -217,5 +217,45 @@ glcr::Status YellowstoneClient::GetDenali(DenaliInfo& response) { +glcr::Status YellowstoneClient::GetDenali(DenaliInfo& response) { + + uint64_t buffer_size = kBufferSize; + uint64_t cap_size = kCapBufferSize; + + const uint32_t kSentinel = 0xBEEFDEAD; + buffer_.WriteAt(0, kSentinel); + buffer_.WriteAt(8, 5); + + cap_buffer_.Reset(); + + uint64_t length = 0; + + + buffer_.WriteAt(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(0) != kSentinel) { + return glcr::InvalidResponse("Got an invalid response from server."); + } + + // Check Response Code. + RET_ERR(buffer_.At(8)); + + + yunq::MessageView resp_view(buffer_, 16); + RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + + + return glcr::OK; +} + + + + } // namepace yellowstone diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h index 1793f69..afe8619 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h @@ -34,6 +34,10 @@ class YellowstoneClient { + [[nodiscard]] glcr::Status GetXhciInfo(XhciInfo& response); + + + [[nodiscard]] glcr::Status GetFramebufferInfo(FramebufferInfo& response); diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp index 78827d7..1134546 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -178,6 +178,49 @@ uint64_t AhciInfo::SerializeInternal(yunq::Serializer& serializer) const { return serializer.size(); } +glcr::Status XhciInfo::ParseFromBytes(const yunq::MessageView& message) { + RETURN_ERROR(ParseFromBytesInternal(message)); + // Parse xhci_region. + ASSIGN_OR_RETURN(xhci_region_, message.ReadCapability(0)); + return glcr::Status::Ok(); +} + +glcr::Status XhciInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(message)); + // Parse xhci_region. + ASSIGN_OR_RETURN(xhci_region_, message.ReadCapability(0, caps)); + return glcr::Status::Ok(); +} + +glcr::Status XhciInfo::ParseFromBytesInternal(const yunq::MessageView& message) { + RETURN_ERROR(message.CheckHeader()); + // Parse xhci_region. + // Parse region_length. + ASSIGN_OR_RETURN(region_length_, message.ReadField(1)); + + return glcr::Status::Ok(); +} + +uint64_t XhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + yunq::Serializer serializer(bytes, offset, 2); + return SerializeInternal(serializer); +} + +uint64_t XhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + yunq::Serializer serializer(bytes, offset, 2, caps); + return SerializeInternal(serializer); +} + +uint64_t XhciInfo::SerializeInternal(yunq::Serializer& serializer) const { + // Write xhci_region. + serializer.WriteCapability(0, xhci_region_); + // Write region_length. + serializer.WriteField(1, region_length_); + + serializer.WriteHeader(); + + return serializer.size(); +} glcr::Status FramebufferInfo::ParseFromBytes(const yunq::MessageView& message) { RETURN_ERROR(ParseFromBytesInternal(message)); return glcr::Status::Ok(); diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index fff090e..8130d35 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -123,6 +123,36 @@ class AhciInfo { uint64_t SerializeInternal(yunq::Serializer& serializer) const; }; +class XhciInfo { + public: + XhciInfo() {} + // Delete copy and move until implemented. + XhciInfo(const XhciInfo&) = delete; + XhciInfo(XhciInfo&&) = default; + XhciInfo& operator=(XhciInfo&&) = 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 z_cap_t& xhci_region() const { return xhci_region_; } + z_cap_t& mutable_xhci_region() { return xhci_region_; } + void set_xhci_region(const z_cap_t& value) { xhci_region_ = value; } + + const uint64_t& region_length() const { return region_length_; } + uint64_t& mutable_region_length() { return region_length_; } + void set_region_length(const uint64_t& value) { region_length_ = value; } + + private: + z_cap_t xhci_region_; + uint64_t region_length_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); + + uint64_t SerializeInternal(yunq::Serializer& serializer) const; +}; class FramebufferInfo { public: FramebufferInfo() {} diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp index d410658..5d8c670 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp @@ -164,6 +164,23 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques + XhciInfo yunq_response; + + + + RETURN_ERROR(HandleGetXhciInfo(yunq_response)); + + + + resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); + + break; + } + case 4: { + + + + FramebufferInfo yunq_response; @@ -176,7 +193,7 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques break; } - case 4: { + case 5: { diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h index b725140..bdaa1fb 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h @@ -41,6 +41,10 @@ class YellowstoneServerBase { + [[nodiscard]] virtual glcr::Status HandleGetXhciInfo(XhciInfo&) = 0; + + + [[nodiscard]] virtual glcr::Status HandleGetFramebufferInfo(FramebufferInfo&) = 0; diff --git a/sys/yellowstone/yellowstone_server.cpp b/sys/yellowstone/yellowstone_server.cpp index e4e05d6..999adfb 100644 --- a/sys/yellowstone/yellowstone_server.cpp +++ b/sys/yellowstone/yellowstone_server.cpp @@ -52,6 +52,12 @@ glcr::Status YellowstoneServer::HandleGetAhciInfo(AhciInfo& info) { return glcr::Status::Ok(); } +glcr::Status YellowstoneServer::HandleGetXhciInfo(XhciInfo& info) { + info.set_xhci_region(pci_reader_.GetXhciVmmo()); + info.set_region_length(kPcieConfigurationSize); + return glcr::Status::Ok(); +} + glcr::Status YellowstoneServer::HandleGetFramebufferInfo( FramebufferInfo& info) { // FIXME: Don't do this for each request. diff --git a/sys/yellowstone/yellowstone_server.h b/sys/yellowstone/yellowstone_server.h index 6866001..c9bf99b 100644 --- a/sys/yellowstone/yellowstone_server.h +++ b/sys/yellowstone/yellowstone_server.h @@ -17,6 +17,7 @@ class YellowstoneServer : public YellowstoneServerBase { static glcr::ErrorOr> Create(); glcr::Status HandleGetAhciInfo(AhciInfo&) override; + glcr::Status HandleGetXhciInfo(XhciInfo&) override; glcr::Status HandleGetFramebufferInfo(FramebufferInfo&) override; glcr::Status HandleGetDenali(DenaliInfo&) override; glcr::Status HandleRegisterEndpoint(const RegisterEndpointRequest&) override; From 2228b5b52e64efa2242a9f7edc9c9b0b0cc29309 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 6 Feb 2024 20:51:16 -0800 Subject: [PATCH 059/186] [Voyageurs] First Pass XHCI Controller, resets the controller. --- scripts/qemu.sh | 2 +- sys/voyageurs/CMakeLists.txt | 1 + sys/voyageurs/voyageurs.cpp | 7 +- sys/voyageurs/xhci/xhci.h | 128 ++++++++++++++++++++ sys/voyageurs/xhci/xhci_driver.cpp | 186 +++++++++++++++++++++++++++++ sys/voyageurs/xhci/xhci_driver.h | 51 ++++++++ 6 files changed, 372 insertions(+), 3 deletions(-) create mode 100644 sys/voyageurs/xhci/xhci.h create mode 100644 sys/voyageurs/xhci/xhci_driver.cpp create mode 100644 sys/voyageurs/xhci/xhci_driver.h diff --git a/scripts/qemu.sh b/scripts/qemu.sh index b2ea1cc..c3c6526 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -20,7 +20,7 @@ if [[ $1 == "debug" ]]; then fi # Use machine q35 to access PCI devices. -qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img ${QEMU_ARGS} +qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 popd # Extra options to add to this script in the future. diff --git a/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt index 10a3754..6dc7fce 100644 --- a/sys/voyageurs/CMakeLists.txt +++ b/sys/voyageurs/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(voyageurs keyboard/keyboard_driver.cpp + xhci/xhci_driver.cpp voyageurs_server.cpp voyageurs.cpp) diff --git a/sys/voyageurs/voyageurs.cpp b/sys/voyageurs/voyageurs.cpp index f3d375f..00e3d0f 100644 --- a/sys/voyageurs/voyageurs.cpp +++ b/sys/voyageurs/voyageurs.cpp @@ -5,6 +5,7 @@ #include "keyboard/keyboard_driver.h" #include "voyageurs_server.h" +#include "xhci/xhci_driver.h" using yellowstone::RegisterEndpointRequest; using yellowstone::YellowstoneClient; @@ -12,6 +13,10 @@ using yellowstone::YellowstoneClient; uint64_t main(uint64_t init_port) { ParseInitPort(init_port); + YellowstoneClient yellowstone(gInitEndpointCap); + + ASSIGN_OR_RETURN(XhciDriver xhci, XhciDriver::InitiateDriver(yellowstone)); + dbgln("Initializing PS/2 Driver."); KeyboardDriver driver; @@ -24,8 +29,6 @@ uint64_t main(uint64_t init_port) { Thread server_thread = server->RunServer(); - YellowstoneClient yellowstone(gInitEndpointCap); - RegisterEndpointRequest req; req.set_endpoint_name("voyageurs"); ASSIGN_OR_RETURN(z_cap_t client_cap, server->CreateClientCap()); diff --git a/sys/voyageurs/xhci/xhci.h b/sys/voyageurs/xhci/xhci.h new file mode 100644 index 0000000..73b9f03 --- /dev/null +++ b/sys/voyageurs/xhci/xhci.h @@ -0,0 +1,128 @@ +#pragma once + +#include + +// TODO: Move to shared lib for denali and voyageurs. +struct PciDeviceHeader { + uint16_t vendor_id; + uint16_t device_id; + uint16_t command_reg; + uint16_t status_reg; + uint8_t revision; + uint8_t prog_interface; + uint8_t subclass; + uint8_t class_code; + uint8_t cache_line_size; + uint8_t latency_timer; + uint8_t header_type; + uint8_t bist; + uint32_t bars[5]; + uint32_t abar; + uint32_t reserved0; + uint32_t subsystem_id; + uint32_t expansion_rom; + uint8_t cap_ptr; + uint8_t reserved1[7]; + uint8_t interrupt_line; + uint8_t interrupt_pin; + uint8_t min_grant; + uint8_t max_latency; +} __attribute__((packed)); + +struct XhciCapabilities { + // NOTE: In qemu access these addresses at anything other than a 32bit offset + // seems to give bogus values so we group the fields more than necessary. + uint32_t length_and_version; + uint32_t hcs_params_1; + uint32_t hcs_params_2; + uint32_t hcs_params_3; + uint16_t capabilites; + uint16_t ext_capabilities_pointer; + uint32_t doorbell_offset; + uint32_t runtime_offset; + uint32_t capabilities2; +} __attribute__((packed)); + +struct XhciOperational { + uint32_t usb_command; + uint32_t usb_status; + uint32_t page_size; + uint32_t reserved; + uint32_t reserved2; + uint32_t device_notification_control; + uint64_t command_ring_control; + uint64_t reserved3; + uint64_t reserved4; + uint64_t device_context_base; + uint32_t configure; +} __attribute__((packed)); + +struct XhciInterrupter { + uint32_t management; + uint32_t moderation; + uint32_t event_ring_segment_table_size; + uint32_t reserved; + uint64_t event_ring_segment_table_base_address; + uint64_t event_ring_dequeue_pointer; +} __attribute__((packed)); + +struct XhciRuntime { + uint32_t microframe_index; + uint32_t reserved1; + uint64_t reserved2; + uint64_t reserved3; + uint64_t reserved4; + XhciInterrupter interrupters[1024]; + +} __attribute__((packed)); + +struct XhciPort { + uint32_t status_and_control; + uint32_t power_management; + uint32_t link_info; + uint32_t lpm_control; +} __attribute__((packed)); + +struct XhciSlotContext { + uint32_t route_speed_entries; + uint32_t latency_port_number; + uint32_t parent_and_interrupt; + uint32_t address_and_state; + uint64_t reserved1; + uint64_t reserved2; +} __attribute__((packed)); + +struct XhciEndpointContext { + uint32_t state; + uint32_t error_and_type; + uint64_t tr_dequeue_ptr; + uint32_t average_trb_length; + uint32_t reserved1; + uint64_t reserved2; +} __attribute__((packed)); + +struct XhciDeviceContext { + XhciSlotContext slot_context; + XhciEndpointContext endpoint_contexts[31]; +} __attribute__((packed)); + +struct XhciCommandTrb { + uint64_t reserved1; + uint32_t reserved2; + uint16_t type_and_cycle; + uint16_t slot_type; +} __attribute__((packed)); + +struct XhciLinkTrb { + uint64_t link_address; + uint32_t interrupter_target; + uint16_t type_and_cycle; + uint16_t reserved; +} __attribute__((packed)); + +struct XhciEventRingSegmentTableEntry { + uint64_t ring_segment_base; + uint16_t ring_segment_size; + uint16_t reserved1; + uint32_t reserved2; +} __attribute__((packed)); diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp new file mode 100644 index 0000000..eb449d1 --- /dev/null +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -0,0 +1,186 @@ +#include "xhci/xhci_driver.h" + +#include +#include +#include +#include + +#include "xhci/xhci.h" + +glcr::ErrorOr XhciDriver::InitiateDriver( + yellowstone::YellowstoneClient& yellowstone) { + yellowstone::XhciInfo info; + check(yellowstone.GetXhciInfo(info)); + + mmth::OwnedMemoryRegion pci_region = + mmth::OwnedMemoryRegion::FromCapability(info.mutable_xhci_region()); + XhciDriver driver(glcr::Move(pci_region)); + driver.ParseMmioStructures(); + driver.DumpDebugInfo(); + driver.FreeExistingMemoryStructures(); + driver.ResetController(); + dbgln("XHCI CONTROLLER RESET"); + driver.DumpDebugInfo(); + check(ZThreadSleep(100)); + driver.DumpDebugInfo(); + return driver; +} + +void XhciDriver::DumpDebugInfo() { + dbgln("Code: {x} {x} {x}", pci_device_header_->class_code, + pci_device_header_->subclass, pci_device_header_->prog_interface); + + dbgln("BAR: {x}", pci_device_header_->bars[0] & ~0xFFF); + dbgln("In P: {x} L: {x}", pci_device_header_->interrupt_pin, + pci_device_header_->interrupt_line); + + dbgln("Cap length: {x}", capabilities_->length_and_version & 0xFF); + dbgln("XHCI Version: {x}", + (capabilities_->length_and_version & 0xFFFF0000) >> 16); + dbgln("Max Slots: {x}", capabilities_->hcs_params_1 & 0xFF); + dbgln("Max Interrupters: {x}", (capabilities_->hcs_params_1 & 0x3FF00) >> 8); + uint64_t max_ports = (capabilities_->hcs_params_1 & 0xFF00'0000) >> 24; + dbgln("Params 2: {x}", capabilities_->hcs_params_2); + dbgln("Params 3: {x}", capabilities_->hcs_params_3); + dbgln("Max Ports: {x}", max_ports); + dbgln("Capabilities: {x}", capabilities_->capabilites); + dbgln("Doorbell: {x}", capabilities_->doorbell_offset); + dbgln("Runtime: {x}", capabilities_->runtime_offset); + + dbgln("Op cmd: {x} sts: {x}", operational_->usb_command, + operational_->usb_status); + dbgln("Page size: {x}", operational_->page_size); + dbgln("Device Context Base Array: {x}", operational_->device_context_base); + dbgln("Command Ring Control: {x}", operational_->command_ring_control); + dbgln("Config: {x}", operational_->configure); + + for (uint64_t i = 0; i < max_ports; i++) { + XhciPort* port = reinterpret_cast( + reinterpret_cast(operational_) + 0x400 + (0x10 * i)); + port->status_and_control &= ~0x10000; + dbgln("Port {x}: {x}", i, port->status_and_control); + if ((port->status_and_control & 0x3) == 0x1) { + dbgln("Resetting: {x}", i); + port->status_and_control |= 0x10; + } + } + + dbgln("Int 0 ES: {x}", + runtime_->interrupters[0].event_ring_segment_table_base_address); +} + +XhciDriver::XhciDriver(mmth::OwnedMemoryRegion&& pci_space) + : pci_region_(glcr::Move(pci_space)) {} + +glcr::ErrorCode XhciDriver::ParseMmioStructures() { + pci_device_header_ = reinterpret_cast(pci_region_.vaddr()); + + // TODO: Officially determine the size of this memory. + mmio_regions_ = mmth::OwnedMemoryRegion::DirectPhysical( + pci_device_header_->bars[0] & ~0xFFF, 0x3000); + + capabilities_ = reinterpret_cast(mmio_regions_.vaddr()); + + uint64_t op_base = + mmio_regions_.vaddr() + (capabilities_->length_and_version & 0xFF); + operational_ = reinterpret_cast(op_base); + + runtime_ = reinterpret_cast(mmio_regions_.vaddr() + + capabilities_->runtime_offset); + + return glcr::OK; +} + +glcr::ErrorCode XhciDriver::ResetController() { + // Host Controller Reset + operational_->usb_command |= 0x2; + + while (operational_->usb_command & 0x2) { + dbgln("Waiting Reset"); + RET_ERR(ZThreadSleep(50)); + } + + while (operational_->usb_command & (0x1 << 11)) { + dbgln("Waiting controller ready"); + RET_ERR(ZThreadSleep(50)); + } + + InitiateCommandRing(); + InitiateDeviceContextBaseArray(); + InitiateEventRingSegmentTable(); + + // Run the controller. + operational_->usb_command |= 0x1; + + return glcr::OK; +} + +glcr::ErrorCode XhciDriver::InitiateCommandRing() { + uint64_t command_ring_phys; + command_ring_mem_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &command_ring_phys); + command_trb_ = reinterpret_cast(command_ring_mem_.vaddr()); + + uint64_t number_trbs = 0x1000 / sizeof(XhciCommandTrb); + + // Point the end of the command ring back to the start. + auto* link_trb = + reinterpret_cast(command_trb_ + number_trbs - 1); + link_trb->link_address = command_ring_phys; + // TODO: Cleaner interface for specifying a command type. + link_trb->type_and_cycle = 0x6 << 10; + + operational_->command_ring_control = command_ring_phys; + + return glcr::OK; +} + +glcr::ErrorCode XhciDriver::InitiateDeviceContextBaseArray() { + uint64_t dcba_phys; + device_context_base_array_mem_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &dcba_phys); + device_context_base_array_ = + reinterpret_cast(device_context_base_array_mem_.vaddr()); + + operational_->device_context_base = dcba_phys; + + uint64_t max_slots = (0x1000 / sizeof(uint64_t)) - 1; + + if (max_slots > (capabilities_->hcs_params_1 & 0xFF)) { + max_slots = capabilities_->hcs_params_1 & 0xFF; + } + operational_->configure = + (operational_->configure & ~0xFF) | (max_slots & 0xFF); + + // TODO: Initialize scratchpad if that is needed by the controller. + + return glcr::OK; +} + +glcr::ErrorCode XhciDriver::InitiateEventRingSegmentTable() { + uint64_t erst_phys; + event_ring_segment_table_mem_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &erst_phys); + + event_ring_segment_table_ = reinterpret_cast( + event_ring_segment_table_mem_.vaddr()); + + uint64_t ers_phys; + event_ring_segment_mem_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &ers_phys); + uint64_t ers_size = 0x1000 / sizeof(XhciCommandTrb); + + event_ring_segment_ = + reinterpret_cast(event_ring_segment_mem_.vaddr()); + + event_ring_segment_table_[0].ring_segment_base = ers_phys; + event_ring_segment_table_[0].ring_segment_size = ers_size & 0xFFFF; + + runtime_->interrupters[0].event_ring_segment_table_base_address = erst_phys; + runtime_->interrupters[0].event_ring_dequeue_pointer = erst_phys; + runtime_->interrupters[0].event_ring_segment_table_size = 1; + // Enable interrupts. + runtime_->interrupters[0].management |= 0x2; + operational_->usb_command |= 0x4; + return glcr::OK; +} diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h new file mode 100644 index 0000000..d263fc9 --- /dev/null +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include +#include + +#include "xhci/xhci.h" + +class XhciDriver { + public: + static glcr::ErrorOr InitiateDriver( + yellowstone::YellowstoneClient& yellowstone); + + void DumpDebugInfo(); + + private: + // MMIO Structures. + mmth::OwnedMemoryRegion pci_region_; + PciDeviceHeader* pci_device_header_; + + mmth::OwnedMemoryRegion mmio_regions_; + XhciCapabilities* capabilities_; + XhciOperational* operational_; + // TODO: Extended Capabilities. + XhciRuntime* runtime_; + // TODO: Doorbell Array. + + // Host Memory Regions. + mmth::OwnedMemoryRegion command_ring_mem_; + XhciCommandTrb* command_trb_; + + mmth::OwnedMemoryRegion device_context_base_array_mem_; + uint64_t* device_context_base_array_; + + mmth::OwnedMemoryRegion event_ring_segment_table_mem_; + XhciEventRingSegmentTableEntry* event_ring_segment_table_; + + mmth::OwnedMemoryRegion event_ring_segment_mem_; + XhciCommandTrb* event_ring_segment_; + + XhciDriver(mmth::OwnedMemoryRegion&& pci_space); + + glcr::ErrorCode ParseMmioStructures(); + glcr::ErrorCode FreeExistingMemoryStructures() { return glcr::OK; } + + glcr::ErrorCode ResetController(); + + glcr::ErrorCode InitiateCommandRing(); + glcr::ErrorCode InitiateDeviceContextBaseArray(); + glcr::ErrorCode InitiateEventRingSegmentTable(); +}; From b41784b93859ffb3c369aebfe00e7a5b3fbe4ba8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 13 Feb 2024 19:39:55 -0800 Subject: [PATCH 060/186] [Voyageurs] Create an abstraction for managing TRBs. --- sys/voyageurs/CMakeLists.txt | 2 ++ sys/voyageurs/xhci/trb.cpp | 10 ++++++++++ sys/voyageurs/xhci/trb.h | 5 +++++ sys/voyageurs/xhci/trb_ring.cpp | 24 ++++++++++++++++++++++++ sys/voyageurs/xhci/trb_ring.h | 26 ++++++++++++++++++++++++++ sys/voyageurs/xhci/xhci.h | 15 ++++----------- sys/voyageurs/xhci/xhci_driver.cpp | 29 ++++------------------------- sys/voyageurs/xhci/xhci_driver.h | 7 +++---- 8 files changed, 78 insertions(+), 40 deletions(-) create mode 100644 sys/voyageurs/xhci/trb.cpp create mode 100644 sys/voyageurs/xhci/trb.h create mode 100644 sys/voyageurs/xhci/trb_ring.cpp create mode 100644 sys/voyageurs/xhci/trb_ring.h diff --git a/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt index 6dc7fce..8ef1302 100644 --- a/sys/voyageurs/CMakeLists.txt +++ b/sys/voyageurs/CMakeLists.txt @@ -1,5 +1,7 @@ add_executable(voyageurs keyboard/keyboard_driver.cpp + xhci/trb.cpp + xhci/trb_ring.cpp xhci/xhci_driver.cpp voyageurs_server.cpp voyageurs.cpp) diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp new file mode 100644 index 0000000..f11c093 --- /dev/null +++ b/sys/voyageurs/xhci/trb.cpp @@ -0,0 +1,10 @@ +#include "xhci/trb.h" + +XhciTrb CreateLinkTrb(uint64_t physical_address) { + return { + .parameter = physical_address, + .status = 0, + .type_and_cycle = 6 << 10, + .control = 0, + }; +} diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h new file mode 100644 index 0000000..333f883 --- /dev/null +++ b/sys/voyageurs/xhci/trb.h @@ -0,0 +1,5 @@ +#pragma once + +#include "xhci/xhci.h" + +XhciTrb CreateLinkTrb(uint64_t physical_address); diff --git a/sys/voyageurs/xhci/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp new file mode 100644 index 0000000..0e1eb66 --- /dev/null +++ b/sys/voyageurs/xhci/trb_ring.cpp @@ -0,0 +1,24 @@ +#include "xhci/trb_ring.h" + +#include + +#include "xhci/trb.h" + +TrbRing::TrbRing() { + uint64_t number_trbs = 0x1000 / sizeof(XhciTrb); + page_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &phys_address_); + trb_list_ = glcr::ArrayView( + reinterpret_cast(page_.vaddr()), number_trbs); + + // Point the end of the command ring back to the start. + trb_list_[trb_list_.size() - 1] = CreateLinkTrb(phys_address_); +} + +void TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { + uint64_t ptr = enqueue_ptr_++; + if (enqueue_ptr_ == trb_list_.size()) { + crash("Not implemented: queue wrapping", glcr::UNIMPLEMENTED); + } + + trb_list_[ptr] = trb; +} diff --git a/sys/voyageurs/xhci/trb_ring.h b/sys/voyageurs/xhci/trb_ring.h new file mode 100644 index 0000000..8682fdb --- /dev/null +++ b/sys/voyageurs/xhci/trb_ring.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +#include "xhci/xhci.h" + +class TrbRing { + public: + TrbRing(); + + uint64_t PhysicalAddress() { return phys_address_; } + + protected: + uint64_t phys_address_; + mmth::OwnedMemoryRegion page_; + glcr::ArrayView trb_list_; +}; + +class TrbRingWriter : public TrbRing { + public: + void EnqueueTrb(const XhciTrb& trb); + + private: + uint64_t enqueue_ptr_ = 0; +}; diff --git a/sys/voyageurs/xhci/xhci.h b/sys/voyageurs/xhci/xhci.h index 73b9f03..8a18469 100644 --- a/sys/voyageurs/xhci/xhci.h +++ b/sys/voyageurs/xhci/xhci.h @@ -106,18 +106,11 @@ struct XhciDeviceContext { XhciEndpointContext endpoint_contexts[31]; } __attribute__((packed)); -struct XhciCommandTrb { - uint64_t reserved1; - uint32_t reserved2; +struct XhciTrb { + uint64_t parameter; + uint32_t status; uint16_t type_and_cycle; - uint16_t slot_type; -} __attribute__((packed)); - -struct XhciLinkTrb { - uint64_t link_address; - uint32_t interrupter_target; - uint16_t type_and_cycle; - uint16_t reserved; + uint16_t control; } __attribute__((packed)); struct XhciEventRingSegmentTableEntry { diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index eb449d1..f9a87b3 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -116,22 +116,7 @@ glcr::ErrorCode XhciDriver::ResetController() { } glcr::ErrorCode XhciDriver::InitiateCommandRing() { - uint64_t command_ring_phys; - command_ring_mem_ = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &command_ring_phys); - command_trb_ = reinterpret_cast(command_ring_mem_.vaddr()); - - uint64_t number_trbs = 0x1000 / sizeof(XhciCommandTrb); - - // Point the end of the command ring back to the start. - auto* link_trb = - reinterpret_cast(command_trb_ + number_trbs - 1); - link_trb->link_address = command_ring_phys; - // TODO: Cleaner interface for specifying a command type. - link_trb->type_and_cycle = 0x6 << 10; - - operational_->command_ring_control = command_ring_phys; - + operational_->command_ring_control = command_ring_.PhysicalAddress(); return glcr::OK; } @@ -165,15 +150,9 @@ glcr::ErrorCode XhciDriver::InitiateEventRingSegmentTable() { event_ring_segment_table_ = reinterpret_cast( event_ring_segment_table_mem_.vaddr()); - uint64_t ers_phys; - event_ring_segment_mem_ = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &ers_phys); - uint64_t ers_size = 0x1000 / sizeof(XhciCommandTrb); - - event_ring_segment_ = - reinterpret_cast(event_ring_segment_mem_.vaddr()); - - event_ring_segment_table_[0].ring_segment_base = ers_phys; + uint64_t ers_size = 0x1000 / sizeof(XhciTrb); + event_ring_segment_table_[0].ring_segment_base = + event_ring_.PhysicalAddress(); event_ring_segment_table_[0].ring_segment_size = ers_size & 0xFFFF; runtime_->interrupters[0].event_ring_segment_table_base_address = erst_phys; diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h index d263fc9..0d05b01 100644 --- a/sys/voyageurs/xhci/xhci_driver.h +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -4,6 +4,7 @@ #include #include +#include "xhci/trb_ring.h" #include "xhci/xhci.h" class XhciDriver { @@ -26,8 +27,7 @@ class XhciDriver { // TODO: Doorbell Array. // Host Memory Regions. - mmth::OwnedMemoryRegion command_ring_mem_; - XhciCommandTrb* command_trb_; + TrbRingWriter command_ring_; mmth::OwnedMemoryRegion device_context_base_array_mem_; uint64_t* device_context_base_array_; @@ -35,8 +35,7 @@ class XhciDriver { mmth::OwnedMemoryRegion event_ring_segment_table_mem_; XhciEventRingSegmentTableEntry* event_ring_segment_table_; - mmth::OwnedMemoryRegion event_ring_segment_mem_; - XhciCommandTrb* event_ring_segment_; + TrbRing event_ring_; XhciDriver(mmth::OwnedMemoryRegion&& pci_space); From 4cb0b0b2ae61da8f64f01770c10c8c90d8be13a0 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 22 Feb 2024 13:25:49 -0800 Subject: [PATCH 061/186] [Voyageurs] XHCI Event Segment working with polling. --- sys/voyageurs/voyageurs.cpp | 2 +- sys/voyageurs/xhci/trb.cpp | 39 ++++++++++- sys/voyageurs/xhci/trb.h | 3 + sys/voyageurs/xhci/trb_ring.cpp | 12 ++++ sys/voyageurs/xhci/trb_ring.h | 12 ++++ sys/voyageurs/xhci/xhci.h | 3 + sys/voyageurs/xhci/xhci_driver.cpp | 106 +++++++++++++++++++++++++---- sys/voyageurs/xhci/xhci_driver.h | 25 +++++-- 8 files changed, 181 insertions(+), 21 deletions(-) diff --git a/sys/voyageurs/voyageurs.cpp b/sys/voyageurs/voyageurs.cpp index 00e3d0f..660f2b5 100644 --- a/sys/voyageurs/voyageurs.cpp +++ b/sys/voyageurs/voyageurs.cpp @@ -15,7 +15,7 @@ uint64_t main(uint64_t init_port) { YellowstoneClient yellowstone(gInitEndpointCap); - ASSIGN_OR_RETURN(XhciDriver xhci, XhciDriver::InitiateDriver(yellowstone)); + ASSIGN_OR_RETURN(auto xhci, XhciDriver::InitiateDriver(yellowstone)); dbgln("Initializing PS/2 Driver."); KeyboardDriver driver; diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp index f11c093..61323fe 100644 --- a/sys/voyageurs/xhci/trb.cpp +++ b/sys/voyageurs/xhci/trb.cpp @@ -1,10 +1,47 @@ #include "xhci/trb.h" +constexpr uint8_t kTrb_Normal = 1; +constexpr uint8_t kTrb_SetupStage = 2; +constexpr uint8_t kTrb_DataStage = 3; +constexpr uint8_t kTrb_StatusStage = 4; +constexpr uint8_t kTrb_Isoch = 5; +constexpr uint8_t kTrb_Link = 6; +constexpr uint8_t kTrb_EventData = 7; +constexpr uint8_t kTrb_NoOp = 8; +constexpr uint8_t kTrb_EnableSlot = 9; +constexpr uint8_t kTrb_DisableSlot = 10; +constexpr uint8_t kTrb_NoOpCommand = 23; + +constexpr uint8_t kTrb_TypeOffset = 10; + +constexpr uint8_t kTrb_Cycle = 1; + XhciTrb CreateLinkTrb(uint64_t physical_address) { return { .parameter = physical_address, .status = 0, - .type_and_cycle = 6 << 10, + .type_and_cycle = kTrb_Link << kTrb_TypeOffset, + .control = 0, + }; +} + +XhciTrb CreateEnableSlotTrb() { + return { + .parameter = 0, + .status = 0, + // FIXME: Accept Cycle Bit as a parameter. + .type_and_cycle = kTrb_EnableSlot << kTrb_TypeOffset | kTrb_Cycle, + // FIXME: Specify slot type if necessary. (XHCI Table 7-9)? + .control = 0, + }; +} + +XhciTrb CreateNoOpCommandTrb() { + return { + .parameter = 0, + .status = 0, + // FIXME: Accept Cycle Bit as a parameter. + .type_and_cycle = kTrb_NoOpCommand << kTrb_TypeOffset | kTrb_Cycle, .control = 0, }; } diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h index 333f883..22abc22 100644 --- a/sys/voyageurs/xhci/trb.h +++ b/sys/voyageurs/xhci/trb.h @@ -3,3 +3,6 @@ #include "xhci/xhci.h" XhciTrb CreateLinkTrb(uint64_t physical_address); + +XhciTrb CreateEnableSlotTrb(); +XhciTrb CreateNoOpCommandTrb(); diff --git a/sys/voyageurs/xhci/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp index 0e1eb66..c578412 100644 --- a/sys/voyageurs/xhci/trb_ring.cpp +++ b/sys/voyageurs/xhci/trb_ring.cpp @@ -7,6 +7,12 @@ TrbRing::TrbRing() { uint64_t number_trbs = 0x1000 / sizeof(XhciTrb); page_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &phys_address_); + + // Zero out data. + uint64_t* page_ptr = reinterpret_cast(page_.vaddr()); + for (uint64_t i = 0; i < 0x1000 / sizeof(uint64_t); i++) { + page_ptr[i] = 0; + } trb_list_ = glcr::ArrayView( reinterpret_cast(page_.vaddr()), number_trbs); @@ -22,3 +28,9 @@ void TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { trb_list_[ptr] = trb; } + +bool TrbRingReader::HasNext() { + return (trb_list_[dequeue_ptr_].type_and_cycle & 0x1) == cycle_bit_; +} + +XhciTrb TrbRingReader::Read() { return trb_list_[dequeue_ptr_++]; } diff --git a/sys/voyageurs/xhci/trb_ring.h b/sys/voyageurs/xhci/trb_ring.h index 8682fdb..3d6c998 100644 --- a/sys/voyageurs/xhci/trb_ring.h +++ b/sys/voyageurs/xhci/trb_ring.h @@ -24,3 +24,15 @@ class TrbRingWriter : public TrbRing { private: uint64_t enqueue_ptr_ = 0; }; + +class TrbRingReader : public TrbRing { + public: + bool HasNext(); + XhciTrb Read(); + + uint64_t DequeuePtr() { return phys_address_ + dequeue_ptr_; } + + private: + uint64_t dequeue_ptr_ = 0; + uint8_t cycle_bit_ = 1; +}; diff --git a/sys/voyageurs/xhci/xhci.h b/sys/voyageurs/xhci/xhci.h index 8a18469..2593ff3 100644 --- a/sys/voyageurs/xhci/xhci.h +++ b/sys/voyageurs/xhci/xhci.h @@ -73,7 +73,10 @@ struct XhciRuntime { uint64_t reserved3; uint64_t reserved4; XhciInterrupter interrupters[1024]; +} __attribute__((packed)); +struct XhciDoorbells { + uint32_t doorbell[256]; } __attribute__((packed)); struct XhciPort { diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index f9a87b3..56babdf 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -1,29 +1,67 @@ #include "xhci/xhci_driver.h" -#include #include #include #include +#include "xhci/trb.h" #include "xhci/xhci.h" -glcr::ErrorOr XhciDriver::InitiateDriver( +void interrupt_thread(void* void_driver) { + XhciDriver* driver = static_cast(void_driver); + + driver->InterruptLoop(); + + crash("Driver returned from interrupt loop", glcr::INTERNAL); +} + +glcr::ErrorOr> XhciDriver::InitiateDriver( yellowstone::YellowstoneClient& yellowstone) { yellowstone::XhciInfo info; check(yellowstone.GetXhciInfo(info)); mmth::OwnedMemoryRegion pci_region = mmth::OwnedMemoryRegion::FromCapability(info.mutable_xhci_region()); - XhciDriver driver(glcr::Move(pci_region)); - driver.ParseMmioStructures(); - driver.DumpDebugInfo(); - driver.FreeExistingMemoryStructures(); - driver.ResetController(); + // Have to make this a heap object so that the reference passed to the + // interrupt loop remains valid. + glcr::UniquePtr driver(new XhciDriver(glcr::Move(pci_region))); + driver->ParseMmioStructures(); + driver->FreeExistingMemoryStructures(); + driver->ResetController(); + driver->StartInterruptThread(); dbgln("XHCI CONTROLLER RESET"); - driver.DumpDebugInfo(); - check(ZThreadSleep(100)); - driver.DumpDebugInfo(); - return driver; + driver->NoOpCommand(); + driver->InitiateDevices(); + return glcr::Move(driver); +} + +void XhciDriver::InterruptLoop() { + while (true) { + while ((runtime_->interrupters[0].management & 0x1) != 0x1) { + check(ZThreadSleep(50)); + } + while (event_ring_.HasNext()) { + XhciTrb trb = event_ring_.Read(); + uint16_t type = trb.type_and_cycle >> 10; + switch (type) { + case 33: + dbgln("Command Completion Event. {x}", trb.parameter); + break; + case 34: + dbgln("Port Status Change Event, enabling slot."); + command_ring_.EnqueueTrb(CreateEnableSlotTrb()); + doorbells_->doorbell[0] = 0; + break; + default: + dbgln("Unknown TRB Type {x} received.", type); + break; + } + } + + runtime_->interrupters[0].event_ring_dequeue_pointer = + event_ring_.DequeuePtr() | 0x8; + runtime_->interrupters[0].management |= 0x1; + } } void XhciDriver::DumpDebugInfo() { @@ -62,6 +100,7 @@ void XhciDriver::DumpDebugInfo() { if ((port->status_and_control & 0x3) == 0x1) { dbgln("Resetting: {x}", i); port->status_and_control |= 0x10; + doorbells_->doorbell[0] = 0; } } @@ -88,10 +127,22 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() { runtime_ = reinterpret_cast(mmio_regions_.vaddr() + capabilities_->runtime_offset); + doorbells_ = reinterpret_cast(mmio_regions_.vaddr() + + capabilities_->doorbell_offset); + return glcr::OK; } glcr::ErrorCode XhciDriver::ResetController() { + // Stop the Host Controller. + // FIXME: Do this before freeing existing structures. + operational_->usb_command &= ~0x1; + + while ((operational_->usb_status & 0x1) != 0x1) { + dbgln("Waiting XHCI Halt."); + RET_ERR(ZThreadSleep(50)); + } + // Host Controller Reset operational_->usb_command |= 0x2; @@ -115,8 +166,13 @@ glcr::ErrorCode XhciDriver::ResetController() { return glcr::OK; } +void XhciDriver::StartInterruptThread() { + interrupt_thread_ = Thread(interrupt_thread, this); +} + glcr::ErrorCode XhciDriver::InitiateCommandRing() { operational_->command_ring_control = command_ring_.PhysicalAddress(); + dbgln("CRC: {x}", operational_->command_ring_control); return glcr::OK; } @@ -155,11 +211,35 @@ glcr::ErrorCode XhciDriver::InitiateEventRingSegmentTable() { event_ring_.PhysicalAddress(); event_ring_segment_table_[0].ring_segment_size = ers_size & 0xFFFF; - runtime_->interrupters[0].event_ring_segment_table_base_address = erst_phys; - runtime_->interrupters[0].event_ring_dequeue_pointer = erst_phys; + runtime_->interrupters[0].event_ring_dequeue_pointer = + event_ring_.PhysicalAddress() | 0x8; runtime_->interrupters[0].event_ring_segment_table_size = 1; + runtime_->interrupters[0].event_ring_segment_table_base_address = erst_phys; + // Enable interrupts. runtime_->interrupters[0].management |= 0x2; + runtime_->interrupters[0].moderation = 4000; operational_->usb_command |= 0x4; return glcr::OK; } + +glcr::ErrorCode XhciDriver::InitiateDevices() { + uint64_t max_ports = (capabilities_->hcs_params_1 & 0xFF00'0000) >> 24; + for (uint64_t i = 0; i < max_ports; i++) { + XhciPort* port = reinterpret_cast( + reinterpret_cast(operational_) + 0x400 + (0x10 * i)); + port->status_and_control &= ~0x10000; + dbgln("Port {x}: {x}", i, port->status_and_control); + if ((port->status_and_control & 0x3) == 0x1) { + dbgln("Resetting: {x}", i); + port->status_and_control |= 0x10; + } + } + return glcr::OK; +} + +glcr::ErrorCode XhciDriver::NoOpCommand() { + command_ring_.EnqueueTrb(CreateNoOpCommandTrb()); + doorbells_->doorbell[0] = 0; + return glcr::OK; +} diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h index 0d05b01..c4efede 100644 --- a/sys/voyageurs/xhci/xhci_driver.h +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -1,6 +1,8 @@ #pragma once +#include #include +#include #include #include @@ -9,22 +11,27 @@ class XhciDriver { public: - static glcr::ErrorOr InitiateDriver( + static glcr::ErrorOr> InitiateDriver( yellowstone::YellowstoneClient& yellowstone); + XhciDriver(const XhciDriver&) = delete; + XhciDriver(XhciDriver&&) = default; + void DumpDebugInfo(); + void InterruptLoop(); + private: // MMIO Structures. mmth::OwnedMemoryRegion pci_region_; PciDeviceHeader* pci_device_header_; mmth::OwnedMemoryRegion mmio_regions_; - XhciCapabilities* capabilities_; - XhciOperational* operational_; + volatile XhciCapabilities* capabilities_; + volatile XhciOperational* operational_; // TODO: Extended Capabilities. - XhciRuntime* runtime_; - // TODO: Doorbell Array. + volatile XhciRuntime* runtime_; + volatile XhciDoorbells* doorbells_; // Host Memory Regions. TrbRingWriter command_ring_; @@ -35,7 +42,8 @@ class XhciDriver { mmth::OwnedMemoryRegion event_ring_segment_table_mem_; XhciEventRingSegmentTableEntry* event_ring_segment_table_; - TrbRing event_ring_; + TrbRingReader event_ring_; + Thread interrupt_thread_; XhciDriver(mmth::OwnedMemoryRegion&& pci_space); @@ -43,8 +51,13 @@ class XhciDriver { glcr::ErrorCode FreeExistingMemoryStructures() { return glcr::OK; } glcr::ErrorCode ResetController(); + void StartInterruptThread(); glcr::ErrorCode InitiateCommandRing(); glcr::ErrorCode InitiateDeviceContextBaseArray(); glcr::ErrorCode InitiateEventRingSegmentTable(); + + glcr::ErrorCode InitiateDevices(); + + glcr::ErrorCode NoOpCommand(); }; From dd2687a59ae9486b22d302dd83ed4d48eb853968 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 22 Feb 2024 13:33:02 -0800 Subject: [PATCH 062/186] [Voyageurs] Additional logging about command completion events. --- sys/voyageurs/xhci/xhci_driver.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index 56babdf..4881925 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -45,10 +45,15 @@ void XhciDriver::InterruptLoop() { uint16_t type = trb.type_and_cycle >> 10; switch (type) { case 33: - dbgln("Command Completion Event. {x}", trb.parameter); + dbgln( + "Command Completion Event. TRB Ptr: {x}, Status: {x}, Param: {x} " + "Slot ID: {x}", + trb.parameter, trb.status >> 24, trb.status & 0xFFFFFF, + trb.control >> 8); break; case 34: - dbgln("Port Status Change Event, enabling slot."); + dbgln("Port Status Change Event on Port {x}, enabling slot.", + ((trb.parameter >> 24) & 0xFF) - 1); command_ring_.EnqueueTrb(CreateEnableSlotTrb()); doorbells_->doorbell[0] = 0; break; @@ -172,7 +177,6 @@ void XhciDriver::StartInterruptThread() { glcr::ErrorCode XhciDriver::InitiateCommandRing() { operational_->command_ring_control = command_ring_.PhysicalAddress(); - dbgln("CRC: {x}", operational_->command_ring_control); return glcr::OK; } From 8e78950ac723394b15c5fd9b2b8d41eda628e787 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 22 Feb 2024 18:16:08 -0800 Subject: [PATCH 063/186] [Voyageurs] Send AddressDevice Command to move port to 'Addressed' State. --- sys/voyageurs/CMakeLists.txt | 1 + sys/voyageurs/xhci/device_slot.cpp | 47 ++++++++++++++++++++++ sys/voyageurs/xhci/device_slot.h | 37 ++++++++++++++++++ sys/voyageurs/xhci/trb.cpp | 45 ++++++++++++++-------- sys/voyageurs/xhci/trb.h | 26 +++++++++++++ sys/voyageurs/xhci/trb_ring.cpp | 9 +++++ sys/voyageurs/xhci/trb_ring.h | 1 + sys/voyageurs/xhci/xhci.h | 33 ++++++++++++---- sys/voyageurs/xhci/xhci_driver.cpp | 62 +++++++++++++++++++++++++----- sys/voyageurs/xhci/xhci_driver.h | 8 ++++ 10 files changed, 236 insertions(+), 33 deletions(-) create mode 100644 sys/voyageurs/xhci/device_slot.cpp create mode 100644 sys/voyageurs/xhci/device_slot.h diff --git a/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt index 8ef1302..3c74de6 100644 --- a/sys/voyageurs/CMakeLists.txt +++ b/sys/voyageurs/CMakeLists.txt @@ -1,5 +1,6 @@ add_executable(voyageurs keyboard/keyboard_driver.cpp + xhci/device_slot.cpp xhci/trb.cpp xhci/trb_ring.cpp xhci/xhci_driver.cpp diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp new file mode 100644 index 0000000..35b8b87 --- /dev/null +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -0,0 +1,47 @@ +#include "xhci/device_slot.h" + +#include "xhci/trb.h" + +void DeviceSlot::EnableAndInitializeDataStructures(uint8_t slot_index, + uint64_t* output_context) { + enabled_ = true; + slot_index_ = slot_index; + + context_memory_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &context_phys_); + + device_context_ = + reinterpret_cast(context_memory_.vaddr()); + *output_context = context_phys_; + input_context_ = reinterpret_cast(context_memory_.vaddr() + + kInputSlotContextOffset); + + control_endpoint_transfer_trb_ = glcr::MakeUnique(); +} + +XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port, + uint32_t route_string, + uint16_t max_packet_size) { + // Initialize Slot Context and Endpoint 0 Context. + input_context_->input.add_contexts = 0x3; + // Set context_entries to 1. XHCI 4.3.3 + input_context_->slot_context.route_speed_entries = (0x1 << 27) | route_string; + input_context_->slot_context.latency_port_number = root_port << 16; + + // Initialize Control Endpoint. + input_context_->endpoint_contexts[0].state = 0; + constexpr uint16_t kCerr = 0x3 << 1; + constexpr uint16_t kTypeControl = 0x4 << 3; + input_context_->endpoint_contexts[0].error_and_type = + kCerr | kTypeControl | (max_packet_size << 16); + + input_context_->endpoint_contexts[0].tr_dequeue_ptr = + control_endpoint_transfer_trb_->PhysicalAddress() | 0x1; + + return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset, + slot_index_); +} + +uint8_t DeviceSlot::State() { + return device_context_->slot_context.address_and_state >> 27; +} diff --git a/sys/voyageurs/xhci/device_slot.h b/sys/voyageurs/xhci/device_slot.h new file mode 100644 index 0000000..d014021 --- /dev/null +++ b/sys/voyageurs/xhci/device_slot.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include "xhci/trb_ring.h" +#include "xhci/xhci.h" + +class DeviceSlot { + public: + DeviceSlot() = default; + DeviceSlot(const DeviceSlot&) = delete; + DeviceSlot(DeviceSlot&&) = delete; + + void EnableAndInitializeDataStructures(uint8_t slot_index_, + uint64_t* output_context); + + XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string, + uint16_t max_packet_size); + + uint8_t State(); + + private: + bool enabled_ = false; + + uint8_t slot_index_ = 0; + + uint64_t context_phys_ = 0; + mmth::OwnedMemoryRegion context_memory_; + + static constexpr uint64_t kInputSlotContextOffset = 0x400; + + XhciDeviceContext* device_context_; + XhciInputContext* input_context_; + + glcr::UniquePtr control_endpoint_transfer_trb_; +}; diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp index 61323fe..ebd3883 100644 --- a/sys/voyageurs/xhci/trb.cpp +++ b/sys/voyageurs/xhci/trb.cpp @@ -1,26 +1,27 @@ #include "xhci/trb.h" -constexpr uint8_t kTrb_Normal = 1; -constexpr uint8_t kTrb_SetupStage = 2; -constexpr uint8_t kTrb_DataStage = 3; -constexpr uint8_t kTrb_StatusStage = 4; -constexpr uint8_t kTrb_Isoch = 5; -constexpr uint8_t kTrb_Link = 6; -constexpr uint8_t kTrb_EventData = 7; -constexpr uint8_t kTrb_NoOp = 8; -constexpr uint8_t kTrb_EnableSlot = 9; -constexpr uint8_t kTrb_DisableSlot = 10; -constexpr uint8_t kTrb_NoOpCommand = 23; - constexpr uint8_t kTrb_TypeOffset = 10; -constexpr uint8_t kTrb_Cycle = 1; +constexpr uint16_t kTrb_Cycle = 1; +constexpr uint16_t kTrb_BSR = (1 << 9); + +namespace { + +uint16_t TypeToInt(TrbType type) { + return static_cast(type) << kTrb_TypeOffset; +} + +} // namespace + +TrbType GetType(const XhciTrb& trb) { + return TrbType(trb.type_and_cycle >> kTrb_TypeOffset); +} XhciTrb CreateLinkTrb(uint64_t physical_address) { return { .parameter = physical_address, .status = 0, - .type_and_cycle = kTrb_Link << kTrb_TypeOffset, + .type_and_cycle = TypeToInt(TrbType::Link), .control = 0, }; } @@ -30,18 +31,30 @@ XhciTrb CreateEnableSlotTrb() { .parameter = 0, .status = 0, // FIXME: Accept Cycle Bit as a parameter. - .type_and_cycle = kTrb_EnableSlot << kTrb_TypeOffset | kTrb_Cycle, + .type_and_cycle = (uint16_t)(TypeToInt(TrbType::EnableSlot) | kTrb_Cycle), // FIXME: Specify slot type if necessary. (XHCI Table 7-9)? .control = 0, }; } +XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id) { + return { + .parameter = input_context, + .status = 0, + // Always cycle the device straight to addressed. + .type_and_cycle = + (uint16_t)(TypeToInt(TrbType::AddressDevice) | kTrb_Cycle), + .control = (uint16_t)(slot_id << 8), + }; +} + XhciTrb CreateNoOpCommandTrb() { return { .parameter = 0, .status = 0, // FIXME: Accept Cycle Bit as a parameter. - .type_and_cycle = kTrb_NoOpCommand << kTrb_TypeOffset | kTrb_Cycle, + .type_and_cycle = + (uint16_t)(TypeToInt(TrbType::NoOpCommand) | kTrb_Cycle), .control = 0, }; } diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h index 22abc22..c02286c 100644 --- a/sys/voyageurs/xhci/trb.h +++ b/sys/voyageurs/xhci/trb.h @@ -2,7 +2,33 @@ #include "xhci/xhci.h" +enum class TrbType : uint8_t { + Reserved = 0, + + // Transfers + Normal = 1, + SetupStage = 2, + DataStage = 3, + StatusStage = 4, + Isoch = 5, + Link = 6, + EventData = 7, + NoOp = 8, + + // Commands + EnableSlot = 9, + AddressDevice = 11, + NoOpCommand = 23, + + // Events + CommandCompletion = 33, + PortStatusChange = 34, +}; + +TrbType GetType(const XhciTrb& trb); + XhciTrb CreateLinkTrb(uint64_t physical_address); XhciTrb CreateEnableSlotTrb(); +XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id); XhciTrb CreateNoOpCommandTrb(); diff --git a/sys/voyageurs/xhci/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp index c578412..8965b90 100644 --- a/sys/voyageurs/xhci/trb_ring.cpp +++ b/sys/voyageurs/xhci/trb_ring.cpp @@ -20,6 +20,15 @@ TrbRing::TrbRing() { trb_list_[trb_list_.size() - 1] = CreateLinkTrb(phys_address_); } +XhciTrb TrbRing::GetTrbFromPhysical(uint64_t address) { + uint64_t offset = address - phys_address_; + if (offset >= 0x1000) { + crash("Invalid offset in GetTrbFromPhysical", glcr::INVALID_ARGUMENT); + } + offset /= sizeof(XhciTrb); + return trb_list_[offset]; +} + void TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { uint64_t ptr = enqueue_ptr_++; if (enqueue_ptr_ == trb_list_.size()) { diff --git a/sys/voyageurs/xhci/trb_ring.h b/sys/voyageurs/xhci/trb_ring.h index 3d6c998..5c88ce1 100644 --- a/sys/voyageurs/xhci/trb_ring.h +++ b/sys/voyageurs/xhci/trb_ring.h @@ -10,6 +10,7 @@ class TrbRing { TrbRing(); uint64_t PhysicalAddress() { return phys_address_; } + XhciTrb GetTrbFromPhysical(uint64_t address); protected: uint64_t phys_address_; diff --git a/sys/voyageurs/xhci/xhci.h b/sys/voyageurs/xhci/xhci.h index 2593ff3..2304249 100644 --- a/sys/voyageurs/xhci/xhci.h +++ b/sys/voyageurs/xhci/xhci.h @@ -43,6 +43,13 @@ struct XhciCapabilities { uint32_t capabilities2; } __attribute__((packed)); +struct XhciPort { + uint32_t status_and_control; + uint32_t power_management; + uint32_t link_info; + uint32_t lpm_control; +} __attribute__((packed)); + struct XhciOperational { uint32_t usb_command; uint32_t usb_status; @@ -55,6 +62,7 @@ struct XhciOperational { uint64_t reserved4; uint64_t device_context_base; uint32_t configure; + XhciPort ports[255]; } __attribute__((packed)); struct XhciInterrupter { @@ -79,13 +87,6 @@ struct XhciDoorbells { uint32_t doorbell[256]; } __attribute__((packed)); -struct XhciPort { - uint32_t status_and_control; - uint32_t power_management; - uint32_t link_info; - uint32_t lpm_control; -} __attribute__((packed)); - struct XhciSlotContext { uint32_t route_speed_entries; uint32_t latency_port_number; @@ -109,6 +110,24 @@ struct XhciDeviceContext { XhciEndpointContext endpoint_contexts[31]; } __attribute__((packed)); +struct XhciInputControlContext { + uint32_t drop_contexts; + uint32_t add_contexts; + uint64_t reserved1; + uint64_t reserved2; + uint32_t reserved3; + uint8_t configuration_value; + uint8_t interface_number; + uint8_t alternate_setting; + uint8_t reserved4; +} __attribute__((packed)); + +struct XhciInputContext { + XhciInputControlContext input; + XhciSlotContext slot_context; + XhciEndpointContext endpoint_contexts[31]; +} __attribute__((packed)); + struct XhciTrb { uint64_t parameter; uint32_t status; diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index 4881925..ff0a11d 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -42,23 +42,18 @@ void XhciDriver::InterruptLoop() { } while (event_ring_.HasNext()) { XhciTrb trb = event_ring_.Read(); - uint16_t type = trb.type_and_cycle >> 10; - switch (type) { - case 33: - dbgln( - "Command Completion Event. TRB Ptr: {x}, Status: {x}, Param: {x} " - "Slot ID: {x}", - trb.parameter, trb.status >> 24, trb.status & 0xFFFFFF, - trb.control >> 8); + switch (GetType(trb)) { + case TrbType::CommandCompletion: + HandleCommandCompletion(trb); break; - case 34: + case TrbType::PortStatusChange: dbgln("Port Status Change Event on Port {x}, enabling slot.", ((trb.parameter >> 24) & 0xFF) - 1); command_ring_.EnqueueTrb(CreateEnableSlotTrb()); doorbells_->doorbell[0] = 0; break; default: - dbgln("Unknown TRB Type {x} received.", type); + dbgln("Unknown TRB Type {x} received.", (uint8_t)GetType(trb)); break; } } @@ -125,6 +120,9 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() { capabilities_ = reinterpret_cast(mmio_regions_.vaddr()); + uint8_t max_device_slots = capabilities_->hcs_params_1 & 0xFF; + devices_ = glcr::Array(max_device_slots); + uint64_t op_base = mmio_regions_.vaddr() + (capabilities_->length_and_version & 0xFF); operational_ = reinterpret_cast(op_base); @@ -247,3 +245,47 @@ glcr::ErrorCode XhciDriver::NoOpCommand() { doorbells_->doorbell[0] = 0; return glcr::OK; } + +void XhciDriver::HandleCommandCompletion( + const XhciTrb& command_completion_trb) { + uint8_t status = command_completion_trb.status >> 24; + if (status != 1) { + dbgln("Command Completion Status: {x}", command_completion_trb.status); + check(glcr::INTERNAL); + } + + XhciTrb orig_trb = + command_ring_.GetTrbFromPhysical(command_completion_trb.parameter); + uint8_t slot = command_completion_trb.control >> 8; + switch (GetType(orig_trb)) { + case TrbType::EnableSlot: + dbgln("Slot Enabled: {x}", slot); + InitializeSlot(slot); + break; + case TrbType::AddressDevice: + dbgln("Device Addressed: {x}", slot); + dbgln("State: {x}", devices_[slot - 1].State()); + break; + case TrbType::NoOpCommand: + dbgln("No-op Command Completed"); + break; + default: + dbgln("Unhandled Command Completion Type: {x}", + (uint8_t)(GetType(orig_trb))); + } +} + +void XhciDriver::InitializeSlot(uint8_t slot_index) { + // TODO: Consider making this array one longer and ignore the first value. + devices_[slot_index - 1].EnableAndInitializeDataStructures( + slot_index, &(device_context_base_array_[slot_index])); + XhciPort* port = + reinterpret_cast(reinterpret_cast(operational_) + + 0x400 + (0x10 * (slot_index - 1))); + uint8_t port_speed = (port->status_and_control >> 10) & 0xF; + uint8_t max_packet_size = 8; + XhciTrb address_device = devices_[slot_index - 1].CreateAddressDeviceCommand( + 0x5, 0, max_packet_size); + command_ring_.EnqueueTrb(address_device); + doorbells_->doorbell[0] = 0; +} diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h index c4efede..8033f2b 100644 --- a/sys/voyageurs/xhci/xhci_driver.h +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -1,11 +1,13 @@ #pragma once +#include #include #include #include #include #include +#include "xhci/device_slot.h" #include "xhci/trb_ring.h" #include "xhci/xhci.h" @@ -45,6 +47,8 @@ class XhciDriver { TrbRingReader event_ring_; Thread interrupt_thread_; + glcr::Array devices_; + XhciDriver(mmth::OwnedMemoryRegion&& pci_space); glcr::ErrorCode ParseMmioStructures(); @@ -60,4 +64,8 @@ class XhciDriver { glcr::ErrorCode InitiateDevices(); glcr::ErrorCode NoOpCommand(); + + void HandleCommandCompletion(const XhciTrb& command_completion_trb); + + void InitializeSlot(uint8_t slot_index); }; From 3d7e911045d854321a87b8a122c14a90182490aa Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 23 Feb 2024 08:19:38 -0800 Subject: [PATCH 064/186] [Voyageurs] Set LinkTrb Toggle Cycle bit. --- sys/voyageurs/xhci/trb.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp index ebd3883..09743fc 100644 --- a/sys/voyageurs/xhci/trb.cpp +++ b/sys/voyageurs/xhci/trb.cpp @@ -3,6 +3,7 @@ constexpr uint8_t kTrb_TypeOffset = 10; constexpr uint16_t kTrb_Cycle = 1; +constexpr uint16_t kTrb_ToggleCycle = (1 << 1); constexpr uint16_t kTrb_BSR = (1 << 9); namespace { @@ -21,7 +22,7 @@ XhciTrb CreateLinkTrb(uint64_t physical_address) { return { .parameter = physical_address, .status = 0, - .type_and_cycle = TypeToInt(TrbType::Link), + .type_and_cycle = (uint16_t)(TypeToInt(TrbType::Link) | kTrb_ToggleCycle), .control = 0, }; } From b0b7e2faff58397568a8b364ad2776021168c9e6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 23 Feb 2024 11:42:10 -0800 Subject: [PATCH 065/186] [Voyageurs] Send GetDescriptor command to the device. --- sys/voyageurs/xhci/control_command.h | 69 ++++++++++++++++++++++++++++ sys/voyageurs/xhci/descriptors.h | 36 +++++++++++++++ sys/voyageurs/xhci/device_slot.cpp | 22 ++++++++- sys/voyageurs/xhci/device_slot.h | 30 +++++++++++- sys/voyageurs/xhci/trb.h | 1 + sys/voyageurs/xhci/trb_ring.cpp | 3 +- sys/voyageurs/xhci/trb_ring.h | 2 +- sys/voyageurs/xhci/xhci_driver.cpp | 34 +++++++++++++- sys/voyageurs/xhci/xhci_driver.h | 1 + 9 files changed, 192 insertions(+), 6 deletions(-) create mode 100644 sys/voyageurs/xhci/control_command.h create mode 100644 sys/voyageurs/xhci/descriptors.h diff --git a/sys/voyageurs/xhci/control_command.h b/sys/voyageurs/xhci/control_command.h new file mode 100644 index 0000000..d615e42 --- /dev/null +++ b/sys/voyageurs/xhci/control_command.h @@ -0,0 +1,69 @@ +#pragma once + +#include +#include +#include + +#include "xhci/descriptors.h" +#include "xhci/xhci.h" + +template +class ReadControlCommand { + public: + ReadControlCommand() { + output_mem_ = + mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &output_phys_); + } + + XhciTrb SetupTrb() { + uint64_t request_type = RequestConstants::RequestType(); + uint64_t request = RequestConstants::Request() << 8; + uint64_t value = RequestConstants::Value() << 16; + // TODO: May need to be non-0 for string descriptors. + uint64_t index = (uint64_t)0 << 32; + uint64_t length = sizeof(Output) << 48; + return { + .parameter = request_type | request | value | index | length, + .status = 8, + .type_and_cycle = 1 | (1 << 5) | (1 << 6) | (2 << 10), + // IN Data Stage + .control = 3, + }; + } + + XhciTrb DataTrb() { + return { + .parameter = output_phys_, + .status = sizeof(Output), + .type_and_cycle = 1 | (1 << 5) | (3 << 10), + .control = 1, + }; + } + + XhciTrb StatusTrb() { + return { + .parameter = 0, + .status = 0, + .type_and_cycle = 1 | (1 << 5) | (4 << 10), + .control = 0, + }; + } + + Output* AwaitResult() { + if (!is_complete_) { + semaphore_->Wait(); + } + is_complete_ = true; + return reinterpret_cast(output_mem_.vaddr()); + } + + glcr::SharedPtr CompletionSemaphore() { return semaphore_; } + + private: + uint64_t output_phys_; + mmth::OwnedMemoryRegion output_mem_; + + bool is_complete_ = false; + glcr::SharedPtr semaphore_ = + glcr::MakeShared(); +}; diff --git a/sys/voyageurs/xhci/descriptors.h b/sys/voyageurs/xhci/descriptors.h new file mode 100644 index 0000000..f54eb7e --- /dev/null +++ b/sys/voyageurs/xhci/descriptors.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +template +class RequestConstants { + public: + static uint8_t RequestType(); + static uint8_t Request(); + static uint16_t Value(); +}; + +struct DeviceDescriptor { + uint8_t length; + uint8_t type; + uint16_t usb_spec; + uint8_t device_class; + uint8_t device_subclass; + uint8_t device_protocol; + uint8_t max_packet_size_exp; + uint16_t vendor_id; + uint16_t product_id; + uint16_t device_release; + uint8_t manufacturer_string_index; + uint8_t product_string_index; + uint8_t serial_string_index; + uint8_t num_configurations; +} __attribute__((packed)); + +template <> +class RequestConstants { + public: + static uint8_t RequestType() { return 0x80; } + static uint8_t Request() { return 0x6; }; + static uint16_t Value() { return 0x100; }; +}; diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp index 35b8b87..e69d537 100644 --- a/sys/voyageurs/xhci/device_slot.cpp +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -1,11 +1,15 @@ #include "xhci/device_slot.h" +#include +#include + #include "xhci/trb.h" -void DeviceSlot::EnableAndInitializeDataStructures(uint8_t slot_index, - uint64_t* output_context) { +void DeviceSlot::EnableAndInitializeDataStructures( + uint8_t slot_index, uint64_t* output_context, volatile uint32_t* doorbell) { enabled_ = true; slot_index_ = slot_index; + doorbell_ = doorbell; context_memory_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &context_phys_); @@ -45,3 +49,17 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port, uint8_t DeviceSlot::State() { return device_context_->slot_context.address_and_state >> 27; } + +void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) { + if (endpoint_index != 1) { + crash("Transfer complete on non control endpoint", glcr::UNIMPLEMENTED); + } + + if (!control_completion_sempahores_.Contains(trb_phys)) { + // Skip this if we don't have a semaphore for it (Setup and Transfer Trbs). + return; + } + + control_completion_sempahores_.at(trb_phys)->Signal(); + check(control_completion_sempahores_.Delete(trb_phys)); +} diff --git a/sys/voyageurs/xhci/device_slot.h b/sys/voyageurs/xhci/device_slot.h index d014021..749b243 100644 --- a/sys/voyageurs/xhci/device_slot.h +++ b/sys/voyageurs/xhci/device_slot.h @@ -1,8 +1,13 @@ #pragma once +#include +#include #include +#include +#include #include +#include "xhci/control_command.h" #include "xhci/trb_ring.h" #include "xhci/xhci.h" @@ -13,17 +18,25 @@ class DeviceSlot { DeviceSlot(DeviceSlot&&) = delete; void EnableAndInitializeDataStructures(uint8_t slot_index_, - uint64_t* output_context); + uint64_t* output_context, + volatile uint32_t* doorbell); XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string, uint16_t max_packet_size); + // Caller must keep the command in scope until it completes. + template + void ExecuteReadControlCommand(ReadControlCommand& command); + + void TransferComplete(uint8_t endpoint_index, uint64_t trb_phys); + uint8_t State(); private: bool enabled_ = false; uint8_t slot_index_ = 0; + volatile uint32_t* doorbell_ = nullptr; uint64_t context_phys_ = 0; mmth::OwnedMemoryRegion context_memory_; @@ -34,4 +47,19 @@ class DeviceSlot { XhciInputContext* input_context_; glcr::UniquePtr control_endpoint_transfer_trb_; + glcr::HashMap> + control_completion_sempahores_; }; + +template +void DeviceSlot::ExecuteReadControlCommand(ReadControlCommand& command) { + control_endpoint_transfer_trb_->EnqueueTrb(command.SetupTrb()); + control_endpoint_transfer_trb_->EnqueueTrb(command.DataTrb()); + uint64_t last_phys = + control_endpoint_transfer_trb_->EnqueueTrb(command.StatusTrb()); + // Ring the control endpoint doorbell. + *doorbell_ = 1; + + check(control_completion_sempahores_.Insert(last_phys, + command.CompletionSemaphore())); +} diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h index c02286c..a02982a 100644 --- a/sys/voyageurs/xhci/trb.h +++ b/sys/voyageurs/xhci/trb.h @@ -21,6 +21,7 @@ enum class TrbType : uint8_t { NoOpCommand = 23, // Events + Transfer = 32, CommandCompletion = 33, PortStatusChange = 34, }; diff --git a/sys/voyageurs/xhci/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp index 8965b90..4189727 100644 --- a/sys/voyageurs/xhci/trb_ring.cpp +++ b/sys/voyageurs/xhci/trb_ring.cpp @@ -29,13 +29,14 @@ XhciTrb TrbRing::GetTrbFromPhysical(uint64_t address) { return trb_list_[offset]; } -void TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { +uint64_t TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { uint64_t ptr = enqueue_ptr_++; if (enqueue_ptr_ == trb_list_.size()) { crash("Not implemented: queue wrapping", glcr::UNIMPLEMENTED); } trb_list_[ptr] = trb; + return phys_address_ + (ptr * sizeof(uint64_t)); } bool TrbRingReader::HasNext() { diff --git a/sys/voyageurs/xhci/trb_ring.h b/sys/voyageurs/xhci/trb_ring.h index 5c88ce1..c2d0668 100644 --- a/sys/voyageurs/xhci/trb_ring.h +++ b/sys/voyageurs/xhci/trb_ring.h @@ -20,7 +20,7 @@ class TrbRing { class TrbRingWriter : public TrbRing { public: - void EnqueueTrb(const XhciTrb& trb); + uint64_t EnqueueTrb(const XhciTrb& trb); private: uint64_t enqueue_ptr_ = 0; diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index ff0a11d..8f21eaf 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -1,9 +1,11 @@ #include "xhci/xhci_driver.h" +#include #include #include #include +#include "xhci/descriptors.h" #include "xhci/trb.h" #include "xhci/xhci.h" @@ -15,6 +17,22 @@ void interrupt_thread(void* void_driver) { crash("Driver returned from interrupt loop", glcr::INTERNAL); } +void configure_device(void* void_device_slot) { + DeviceSlot* device_slot = static_cast(void_device_slot); + + dbgln("Configuring device"); + + ReadControlCommand command; + + device_slot->ExecuteReadControlCommand(command); + + DeviceDescriptor* descriptor = command.AwaitResult(); + + dbgln("Descriptor Type {x}, ({x})", descriptor->type, descriptor->usb_spec); + dbgln("Device Class/Sub/Protocol: {x}/{x}/{x}", descriptor->device_class, + descriptor->device_subclass, descriptor->device_protocol); +} + glcr::ErrorOr> XhciDriver::InitiateDriver( yellowstone::YellowstoneClient& yellowstone) { yellowstone::XhciInfo info; @@ -43,6 +61,9 @@ void XhciDriver::InterruptLoop() { while (event_ring_.HasNext()) { XhciTrb trb = event_ring_.Read(); switch (GetType(trb)) { + case TrbType::Transfer: + HandleTransferCompletion(trb); + break; case TrbType::CommandCompletion: HandleCommandCompletion(trb); break; @@ -52,6 +73,7 @@ void XhciDriver::InterruptLoop() { command_ring_.EnqueueTrb(CreateEnableSlotTrb()); doorbells_->doorbell[0] = 0; break; + default: dbgln("Unknown TRB Type {x} received.", (uint8_t)GetType(trb)); break; @@ -132,6 +154,7 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() { doorbells_ = reinterpret_cast(mmio_regions_.vaddr() + capabilities_->doorbell_offset); + dbgln("Doorbells: {x}", (uint64_t)doorbells_); return glcr::OK; } @@ -265,6 +288,7 @@ void XhciDriver::HandleCommandCompletion( case TrbType::AddressDevice: dbgln("Device Addressed: {x}", slot); dbgln("State: {x}", devices_[slot - 1].State()); + Thread(configure_device, &devices_[slot - 1]); break; case TrbType::NoOpCommand: dbgln("No-op Command Completed"); @@ -275,10 +299,18 @@ void XhciDriver::HandleCommandCompletion( } } +void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) { + uint8_t slot_id = transfer_event_trb.control >> 8; + uint8_t endpoint_id = transfer_event_trb.control & 0x1F; + uint64_t trb_phys = transfer_event_trb.parameter; + devices_[slot_id - 1].TransferComplete(endpoint_id, trb_phys); +} + void XhciDriver::InitializeSlot(uint8_t slot_index) { // TODO: Consider making this array one longer and ignore the first value. devices_[slot_index - 1].EnableAndInitializeDataStructures( - slot_index, &(device_context_base_array_[slot_index])); + slot_index, &(device_context_base_array_[slot_index]), + &doorbells_->doorbell[slot_index]); XhciPort* port = reinterpret_cast(reinterpret_cast(operational_) + 0x400 + (0x10 * (slot_index - 1))); diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h index 8033f2b..3beb293 100644 --- a/sys/voyageurs/xhci/xhci_driver.h +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -66,6 +66,7 @@ class XhciDriver { glcr::ErrorCode NoOpCommand(); void HandleCommandCompletion(const XhciTrb& command_completion_trb); + void HandleTransferCompletion(const XhciTrb& transfer_event_trb); void InitializeSlot(uint8_t slot_index); }; From 39b6d32d86b0755b9862e7adf7b700adfd8717e9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 23 Feb 2024 14:46:28 -0800 Subject: [PATCH 066/186] [Voyageurs] Fix offset for physical trb address. --- sys/voyageurs/xhci/trb_ring.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/voyageurs/xhci/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp index 4189727..f251a63 100644 --- a/sys/voyageurs/xhci/trb_ring.cpp +++ b/sys/voyageurs/xhci/trb_ring.cpp @@ -36,7 +36,7 @@ uint64_t TrbRingWriter::EnqueueTrb(const XhciTrb& trb) { } trb_list_[ptr] = trb; - return phys_address_ + (ptr * sizeof(uint64_t)); + return phys_address_ + (ptr * sizeof(XhciTrb)); } bool TrbRingReader::HasNext() { From af69415d4df767f5498d4698c6d6ed3c7b5e8fe4 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 08:25:22 -0800 Subject: [PATCH 067/186] [Voyageurs] Get Configuration from USB device. --- sys/voyageurs/xhci/control_command.h | 4 +-- sys/voyageurs/xhci/descriptors.h | 41 ++++++++++++++++++++++++++ sys/voyageurs/xhci/xhci_driver.cpp | 44 ++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 2 deletions(-) diff --git a/sys/voyageurs/xhci/control_command.h b/sys/voyageurs/xhci/control_command.h index d615e42..9cc05cd 100644 --- a/sys/voyageurs/xhci/control_command.h +++ b/sys/voyageurs/xhci/control_command.h @@ -21,7 +21,7 @@ class ReadControlCommand { uint64_t value = RequestConstants::Value() << 16; // TODO: May need to be non-0 for string descriptors. uint64_t index = (uint64_t)0 << 32; - uint64_t length = sizeof(Output) << 48; + uint64_t length = (uint64_t)0x1000 << 48; return { .parameter = request_type | request | value | index | length, .status = 8, @@ -34,7 +34,7 @@ class ReadControlCommand { XhciTrb DataTrb() { return { .parameter = output_phys_, - .status = sizeof(Output), + .status = 0x1000, .type_and_cycle = 1 | (1 << 5) | (3 << 10), .control = 1, }; diff --git a/sys/voyageurs/xhci/descriptors.h b/sys/voyageurs/xhci/descriptors.h index f54eb7e..8aec53b 100644 --- a/sys/voyageurs/xhci/descriptors.h +++ b/sys/voyageurs/xhci/descriptors.h @@ -34,3 +34,44 @@ class RequestConstants { static uint8_t Request() { return 0x6; }; static uint16_t Value() { return 0x100; }; }; + +struct ConfigurationDescriptor { + uint8_t length; + uint8_t type; + uint16_t total_length; + uint8_t num_interfaces; + uint8_t configuration_value; + uint8_t configuration_string_index; + uint8_t attributes; + uint8_t max_power; +} __attribute__((packed)); + +template <> +class RequestConstants { + public: + static uint8_t RequestType() { return 0x80; } + static uint8_t Request() { return 0x6; } + // TODO: Consider getting other description indexes. + static uint16_t Value() { return 0x200; } +}; + +struct InterfaceDescriptor { + uint8_t length; + uint8_t type; + uint8_t interface_number; + uint8_t alternate_setting; + uint8_t num_endpoints; + uint8_t interface_class; + uint8_t interface_subclass; + uint8_t interface_protocol; + uint8_t interfact_string_index; +} __attribute__((packed)); + +struct EndpointDescriptor { + uint8_t length; + uint8_t type; + uint8_t endpoint_address; + uint8_t attributes; + uint16_t max_packet_size; + uint8_t interval; +} __attribute__((packed)); diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index 8f21eaf..ba7bafa 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -31,6 +31,45 @@ void configure_device(void* void_device_slot) { dbgln("Descriptor Type {x}, ({x})", descriptor->type, descriptor->usb_spec); dbgln("Device Class/Sub/Protocol: {x}/{x}/{x}", descriptor->device_class, descriptor->device_subclass, descriptor->device_protocol); + dbgln("Num Configurations: {}", descriptor->num_configurations); + + ReadControlCommand config_command; + + device_slot->ExecuteReadControlCommand(config_command); + + ConfigurationDescriptor* config_descriptor = config_command.AwaitResult(); + + dbgln("Configuration Value: {x}", config_descriptor->configuration_value); + dbgln("Num Interfaces: {x}", config_descriptor->num_interfaces); + dbgln("Size: {x}, Total Length: {x}", config_descriptor->length, + config_descriptor->total_length); + + uint64_t next_vaddr = + reinterpret_cast(config_descriptor) + config_descriptor->length; + for (auto i = config_descriptor->num_interfaces; i > 0; i--) { + InterfaceDescriptor* interface = + reinterpret_cast(next_vaddr); + dbgln("Interface: {x}", interface->interface_number); + dbgln("Interface Class/Sub/Protocol: {x}/{x}/{x}", + interface->interface_class, interface->interface_subclass, + interface->interface_protocol); + dbgln("Num Endpoints: {x}", interface->num_endpoints); + + next_vaddr += interface->length; + for (auto j = interface->num_endpoints; j > 0; j--) { + EndpointDescriptor* endpoint = + reinterpret_cast(next_vaddr); + if (endpoint->type != 5) { + dbgln("Descriptor type {x}, skipping", endpoint->type); + j++; + next_vaddr += endpoint->length; + continue; + } + dbgln("Endpoint Addr: {x}", endpoint->endpoint_address); + dbgln("Endpoint Attr: {x}", endpoint->attributes); + next_vaddr += endpoint->length; + } + } } glcr::ErrorOr> XhciDriver::InitiateDriver( @@ -300,6 +339,11 @@ void XhciDriver::HandleCommandCompletion( } void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) { + uint8_t status = transfer_event_trb.status >> 24; + if (status != 1 && status != 0xD) { + dbgln("Unexpected Status {x}", status); + return; + } uint8_t slot_id = transfer_event_trb.control >> 8; uint8_t endpoint_id = transfer_event_trb.control & 0x1F; uint64_t trb_phys = transfer_event_trb.parameter; From 2cc9c89051f35a7bf2154b1d948ab9796ad3c185 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 09:23:58 -0800 Subject: [PATCH 068/186] [Voyageurs] Send ConfigureEndpointCommand to device. --- sys/voyageurs/xhci/device_slot.cpp | 31 +++++++++++++++++++++++++++++- sys/voyageurs/xhci/device_slot.h | 13 ++++++++++++- sys/voyageurs/xhci/trb.cpp | 11 +++++++++++ sys/voyageurs/xhci/trb.h | 2 ++ sys/voyageurs/xhci/xhci_driver.cpp | 21 +++++++++++++++++++- sys/voyageurs/xhci/xhci_driver.h | 2 ++ 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp index e69d537..413b10b 100644 --- a/sys/voyageurs/xhci/device_slot.cpp +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -4,10 +4,13 @@ #include #include "xhci/trb.h" +#include "xhci/xhci_driver.h" void DeviceSlot::EnableAndInitializeDataStructures( - uint8_t slot_index, uint64_t* output_context, volatile uint32_t* doorbell) { + XhciDriver* driver, uint8_t slot_index, uint64_t* output_context, + volatile uint32_t* doorbell) { enabled_ = true; + xhci_driver_ = driver; slot_index_ = slot_index; doorbell_ = doorbell; @@ -63,3 +66,29 @@ void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) { control_completion_sempahores_.at(trb_phys)->Signal(); check(control_completion_sempahores_.Delete(trb_phys)); } + +mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) { + input_context_->input.add_contexts = (0x1 << 3) | 0x1; + input_context_->input.configuration_value = config_value; + // TODO: Maybe don't hardcode this. + input_context_->input.interface_number = 0; + + input_context_->slot_context.route_speed_entries &= 0xFFFFFF; + + // TODO: Don't hardcode this. + uint8_t max_endpoint = 0x3; + input_context_->slot_context.route_speed_entries |= (max_endpoint << 27); + + // TODO: Dont' hardcode this. + other_endpoint_transfer_trb_ = glcr::MakeUnique(); + input_context_->endpoint_contexts[2].tr_dequeue_ptr = + other_endpoint_transfer_trb_->PhysicalAddress() | 0x1; + + xhci_driver_->IssueCommand(CreateConfigureEndpointCommand( + context_phys_ + kInputSlotContextOffset, slot_index_)); + return configure_device_semaphore_; +} + +void DeviceSlot::SignalConfigureDeviceCompleted() { + configure_device_semaphore_.Signal(); +} diff --git a/sys/voyageurs/xhci/device_slot.h b/sys/voyageurs/xhci/device_slot.h index 749b243..2e3a1cf 100644 --- a/sys/voyageurs/xhci/device_slot.h +++ b/sys/voyageurs/xhci/device_slot.h @@ -11,19 +11,25 @@ #include "xhci/trb_ring.h" #include "xhci/xhci.h" +class XhciDriver; + class DeviceSlot { public: DeviceSlot() = default; DeviceSlot(const DeviceSlot&) = delete; DeviceSlot(DeviceSlot&&) = delete; - void EnableAndInitializeDataStructures(uint8_t slot_index_, + void EnableAndInitializeDataStructures(XhciDriver* driver, + uint8_t slot_index_, uint64_t* output_context, volatile uint32_t* doorbell); XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string, uint16_t max_packet_size); + mmth::Semaphore IssueConfigureDeviceCommand(uint8_t config_value); + void SignalConfigureDeviceCompleted(); + // Caller must keep the command in scope until it completes. template void ExecuteReadControlCommand(ReadControlCommand& command); @@ -35,6 +41,7 @@ class DeviceSlot { private: bool enabled_ = false; + XhciDriver* xhci_driver_; uint8_t slot_index_ = 0; volatile uint32_t* doorbell_ = nullptr; @@ -49,6 +56,10 @@ class DeviceSlot { glcr::UniquePtr control_endpoint_transfer_trb_; glcr::HashMap> control_completion_sempahores_; + + mmth::Semaphore configure_device_semaphore_; + + glcr::UniquePtr other_endpoint_transfer_trb_; }; template diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp index 09743fc..039ac2f 100644 --- a/sys/voyageurs/xhci/trb.cpp +++ b/sys/voyageurs/xhci/trb.cpp @@ -49,6 +49,17 @@ XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id) { }; } +XhciTrb CreateConfigureEndpointCommand(uint64_t input_context, + uint8_t slot_id) { + return { + .parameter = input_context, + .status = 0, + .type_and_cycle = + (uint16_t)(TypeToInt(TrbType::ConfigureEndpoint) | kTrb_Cycle), + .control = (uint16_t)(slot_id << 8), + }; +} + XhciTrb CreateNoOpCommandTrb() { return { .parameter = 0, diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h index a02982a..9fbba5a 100644 --- a/sys/voyageurs/xhci/trb.h +++ b/sys/voyageurs/xhci/trb.h @@ -18,6 +18,7 @@ enum class TrbType : uint8_t { // Commands EnableSlot = 9, AddressDevice = 11, + ConfigureEndpoint = 12, NoOpCommand = 23, // Events @@ -32,4 +33,5 @@ XhciTrb CreateLinkTrb(uint64_t physical_address); XhciTrb CreateEnableSlotTrb(); XhciTrb CreateAddressDeviceCommand(uint64_t input_context, uint8_t slot_id); +XhciTrb CreateConfigureEndpointCommand(uint64_t input_context, uint8_t slot_id); XhciTrb CreateNoOpCommandTrb(); diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index ba7bafa..a37eb64 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -70,6 +70,15 @@ void configure_device(void* void_device_slot) { next_vaddr += endpoint->length; } } + + dbgln("---- Configuring with configuration: {x}", + config_descriptor->configuration_value); + + device_slot + ->IssueConfigureDeviceCommand(config_descriptor->configuration_value) + .Wait(); + + dbgln("Configured!"); } glcr::ErrorOr> XhciDriver::InitiateDriver( @@ -169,6 +178,11 @@ void XhciDriver::DumpDebugInfo() { runtime_->interrupters[0].event_ring_segment_table_base_address); } +void XhciDriver::IssueCommand(const XhciTrb& command) { + command_ring_.EnqueueTrb(command); + doorbells_->doorbell[0] = 0; +} + XhciDriver::XhciDriver(mmth::OwnedMemoryRegion&& pci_space) : pci_region_(glcr::Move(pci_space)) {} @@ -329,6 +343,11 @@ void XhciDriver::HandleCommandCompletion( dbgln("State: {x}", devices_[slot - 1].State()); Thread(configure_device, &devices_[slot - 1]); break; + case TrbType::ConfigureEndpoint: + dbgln("Device COnfigured: {x}", slot); + dbgln("State: {x}", devices_[slot - 1].State()); + devices_[slot - 1].SignalConfigureDeviceCompleted(); + break; case TrbType::NoOpCommand: dbgln("No-op Command Completed"); break; @@ -353,7 +372,7 @@ void XhciDriver::HandleTransferCompletion(const XhciTrb& transfer_event_trb) { void XhciDriver::InitializeSlot(uint8_t slot_index) { // TODO: Consider making this array one longer and ignore the first value. devices_[slot_index - 1].EnableAndInitializeDataStructures( - slot_index, &(device_context_base_array_[slot_index]), + this, slot_index, &(device_context_base_array_[slot_index]), &doorbells_->doorbell[slot_index]); XhciPort* port = reinterpret_cast(reinterpret_cast(operational_) + diff --git a/sys/voyageurs/xhci/xhci_driver.h b/sys/voyageurs/xhci/xhci_driver.h index 3beb293..2b70715 100644 --- a/sys/voyageurs/xhci/xhci_driver.h +++ b/sys/voyageurs/xhci/xhci_driver.h @@ -23,6 +23,8 @@ class XhciDriver { void InterruptLoop(); + void IssueCommand(const XhciTrb& command); + private: // MMIO Structures. mmth::OwnedMemoryRegion pci_region_; From c5f81952553e972db40283938d46ac2f02cd2a56 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 14:18:11 -0800 Subject: [PATCH 069/186] [Voyageurs] Receive keypress information from the usb keyboard. --- sys/voyageurs/CMakeLists.txt | 1 + sys/voyageurs/xhci/device_slot.cpp | 19 ++++++++++++++---- sys/voyageurs/xhci/device_slot.h | 3 ++- sys/voyageurs/xhci/endpoint.cpp | 31 ++++++++++++++++++++++++++++++ sys/voyageurs/xhci/endpoint.h | 26 +++++++++++++++++++++++++ sys/voyageurs/xhci/xhci_driver.cpp | 2 ++ 6 files changed, 77 insertions(+), 5 deletions(-) create mode 100644 sys/voyageurs/xhci/endpoint.cpp create mode 100644 sys/voyageurs/xhci/endpoint.h diff --git a/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt index 3c74de6..75a852c 100644 --- a/sys/voyageurs/CMakeLists.txt +++ b/sys/voyageurs/CMakeLists.txt @@ -1,6 +1,7 @@ add_executable(voyageurs keyboard/keyboard_driver.cpp xhci/device_slot.cpp + xhci/endpoint.cpp xhci/trb.cpp xhci/trb_ring.cpp xhci/xhci_driver.cpp diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp index 413b10b..ba6f29a 100644 --- a/sys/voyageurs/xhci/device_slot.cpp +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -45,6 +45,8 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port, input_context_->endpoint_contexts[0].tr_dequeue_ptr = control_endpoint_transfer_trb_->PhysicalAddress() | 0x1; + endpoints_ = glcr::Array(32); + return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset, slot_index_); } @@ -54,8 +56,19 @@ uint8_t DeviceSlot::State() { } void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) { + if (endpoint_index >= 32) { + dbgln("ERROR: Received transfer for invalid endpoint {x}", endpoint_index); + return; + } + if (endpoint_index != 1) { - crash("Transfer complete on non control endpoint", glcr::UNIMPLEMENTED); + if (!endpoints_[endpoint_index].Enabled()) { + dbgln("ERROR: XHCI received transfer for disabled endpoint {x}", + endpoint_index); + return; + } + endpoints_[endpoint_index].TransferComplete(trb_phys); + return; } if (!control_completion_sempahores_.Contains(trb_phys)) { @@ -80,9 +93,7 @@ mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) { input_context_->slot_context.route_speed_entries |= (max_endpoint << 27); // TODO: Dont' hardcode this. - other_endpoint_transfer_trb_ = glcr::MakeUnique(); - input_context_->endpoint_contexts[2].tr_dequeue_ptr = - other_endpoint_transfer_trb_->PhysicalAddress() | 0x1; + endpoints_[3].Initialize(input_context_->endpoint_contexts + 2); xhci_driver_->IssueCommand(CreateConfigureEndpointCommand( context_phys_ + kInputSlotContextOffset, slot_index_)); diff --git a/sys/voyageurs/xhci/device_slot.h b/sys/voyageurs/xhci/device_slot.h index 2e3a1cf..b228ba7 100644 --- a/sys/voyageurs/xhci/device_slot.h +++ b/sys/voyageurs/xhci/device_slot.h @@ -8,6 +8,7 @@ #include #include "xhci/control_command.h" +#include "xhci/endpoint.h" #include "xhci/trb_ring.h" #include "xhci/xhci.h" @@ -59,7 +60,7 @@ class DeviceSlot { mmth::Semaphore configure_device_semaphore_; - glcr::UniquePtr other_endpoint_transfer_trb_; + glcr::Array endpoints_; }; template diff --git a/sys/voyageurs/xhci/endpoint.cpp b/sys/voyageurs/xhci/endpoint.cpp new file mode 100644 index 0000000..a1149f0 --- /dev/null +++ b/sys/voyageurs/xhci/endpoint.cpp @@ -0,0 +1,31 @@ +#include "xhci/endpoint.h" + +#include + +void Endpoint::Initialize(XhciEndpointContext* context) { + enabled_ = true; + context_ = context; + + trb_ring_ = glcr::MakeUnique(); + recv_mem_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &recv_phys_); + + context_->tr_dequeue_ptr = trb_ring_->PhysicalAddress() | 1; + + context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16); + trb_ring_->EnqueueTrb({ + .parameter = recv_phys_, + .status = 8, + .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), + .control = 0, + }); +} + +void Endpoint::TransferComplete(uint64_t trb_phys) { + dbgln("Data: {x}", *(uint64_t*)recv_mem_.vaddr()); + trb_ring_->EnqueueTrb({ + .parameter = recv_phys_, + .status = 8, + .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), + .control = 0, + }); +} diff --git a/sys/voyageurs/xhci/endpoint.h b/sys/voyageurs/xhci/endpoint.h new file mode 100644 index 0000000..25b0a45 --- /dev/null +++ b/sys/voyageurs/xhci/endpoint.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "xhci/trb_ring.h" +#include "xhci/xhci.h" + +class Endpoint { + public: + Endpoint() {} + + void Initialize(XhciEndpointContext* context); + + bool Enabled() { return enabled_; } + + void TransferComplete(uint64_t trb_phys); + + private: + bool enabled_ = false; + + XhciEndpointContext* context_ = nullptr; + glcr::UniquePtr trb_ring_; + + uint64_t recv_phys_; + mmth::OwnedMemoryRegion recv_mem_; +}; diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index a37eb64..78f6d70 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -205,6 +205,8 @@ glcr::ErrorCode XhciDriver::ParseMmioStructures() { runtime_ = reinterpret_cast(mmio_regions_.vaddr() + capabilities_->runtime_offset); + dbgln("INTTTT: {x}", (uint64_t)runtime_->interrupters); + doorbells_ = reinterpret_cast(mmio_regions_.vaddr() + capabilities_->doorbell_offset); dbgln("Doorbells: {x}", (uint64_t)doorbells_); From e6b232851e16590c3d79cc411c431fa0bb0723ff Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 14:23:14 -0800 Subject: [PATCH 070/186] [Voyageurs] Add 10 trbs to the queue to handle rapid keypresses. --- sys/voyageurs/xhci/endpoint.cpp | 22 ++++++++++++++-------- sys/voyageurs/xhci/endpoint.h | 1 + 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sys/voyageurs/xhci/endpoint.cpp b/sys/voyageurs/xhci/endpoint.cpp index a1149f0..b08d6ed 100644 --- a/sys/voyageurs/xhci/endpoint.cpp +++ b/sys/voyageurs/xhci/endpoint.cpp @@ -12,20 +12,26 @@ void Endpoint::Initialize(XhciEndpointContext* context) { context_->tr_dequeue_ptr = trb_ring_->PhysicalAddress() | 1; context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16); - trb_ring_->EnqueueTrb({ - .parameter = recv_phys_, - .status = 8, - .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), - .control = 0, - }); + for (uint64_t i = 0; i < 10; i++) { + trb_ring_->EnqueueTrb({ + .parameter = recv_phys_ + offset_, + .status = 8, + .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), + .control = 0, + }); + offset_ += 8; + } } void Endpoint::TransferComplete(uint64_t trb_phys) { - dbgln("Data: {x}", *(uint64_t*)recv_mem_.vaddr()); + uint64_t phys_offset = + (trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb); + dbgln("Data: {x}", *((uint64_t*)recv_mem_.vaddr() + phys_offset)); trb_ring_->EnqueueTrb({ - .parameter = recv_phys_, + .parameter = recv_phys_ + offset_, .status = 8, .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), .control = 0, }); + offset_ += 8; } diff --git a/sys/voyageurs/xhci/endpoint.h b/sys/voyageurs/xhci/endpoint.h index 25b0a45..920620a 100644 --- a/sys/voyageurs/xhci/endpoint.h +++ b/sys/voyageurs/xhci/endpoint.h @@ -23,4 +23,5 @@ class Endpoint { uint64_t recv_phys_; mmth::OwnedMemoryRegion recv_mem_; + uint64_t offset_ = 0; }; From 3c1e435e048e01f7f28ede00ffa4b596f8123141 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 14:31:14 -0800 Subject: [PATCH 071/186] [Voyageurs] Move NormalTrb generation into helper func. --- sys/voyageurs/xhci/endpoint.cpp | 16 ++++------------ sys/voyageurs/xhci/trb.cpp | 12 ++++++++++++ sys/voyageurs/xhci/trb.h | 1 + 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/sys/voyageurs/xhci/endpoint.cpp b/sys/voyageurs/xhci/endpoint.cpp index b08d6ed..3cfb568 100644 --- a/sys/voyageurs/xhci/endpoint.cpp +++ b/sys/voyageurs/xhci/endpoint.cpp @@ -2,6 +2,8 @@ #include +#include "xhci/trb.h" + void Endpoint::Initialize(XhciEndpointContext* context) { enabled_ = true; context_ = context; @@ -13,12 +15,7 @@ void Endpoint::Initialize(XhciEndpointContext* context) { context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16); for (uint64_t i = 0; i < 10; i++) { - trb_ring_->EnqueueTrb({ - .parameter = recv_phys_ + offset_, - .status = 8, - .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), - .control = 0, - }); + trb_ring_->EnqueueTrb(CreateNormalTrb(recv_phys_ + offset_, 8)); offset_ += 8; } } @@ -27,11 +24,6 @@ void Endpoint::TransferComplete(uint64_t trb_phys) { uint64_t phys_offset = (trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb); dbgln("Data: {x}", *((uint64_t*)recv_mem_.vaddr() + phys_offset)); - trb_ring_->EnqueueTrb({ - .parameter = recv_phys_ + offset_, - .status = 8, - .type_and_cycle = 1 | (1 << 2) | (1 << 5) | (1 << 10), - .control = 0, - }); + trb_ring_->EnqueueTrb(CreateNormalTrb(recv_phys_ + offset_, 8)); offset_ += 8; } diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp index 039ac2f..7fca204 100644 --- a/sys/voyageurs/xhci/trb.cpp +++ b/sys/voyageurs/xhci/trb.cpp @@ -4,6 +4,8 @@ constexpr uint8_t kTrb_TypeOffset = 10; constexpr uint16_t kTrb_Cycle = 1; constexpr uint16_t kTrb_ToggleCycle = (1 << 1); +constexpr uint16_t kTrb_InterruptShortPacket = (1 << 2); +constexpr uint16_t kTrb_Interrupt = (1 << 5); constexpr uint16_t kTrb_BSR = (1 << 9); namespace { @@ -18,6 +20,16 @@ TrbType GetType(const XhciTrb& trb) { return TrbType(trb.type_and_cycle >> kTrb_TypeOffset); } +XhciTrb CreateNormalTrb(uint64_t physical_address, uint8_t size) { + return { + .parameter = physical_address, + .status = size, + .type_and_cycle = (uint16_t)(TypeToInt(TrbType::Normal) | kTrb_Cycle | + kTrb_Interrupt | kTrb_InterruptShortPacket), + .control = 0, + }; +} + XhciTrb CreateLinkTrb(uint64_t physical_address) { return { .parameter = physical_address, diff --git a/sys/voyageurs/xhci/trb.h b/sys/voyageurs/xhci/trb.h index 9fbba5a..f7fee03 100644 --- a/sys/voyageurs/xhci/trb.h +++ b/sys/voyageurs/xhci/trb.h @@ -29,6 +29,7 @@ enum class TrbType : uint8_t { TrbType GetType(const XhciTrb& trb); +XhciTrb CreateNormalTrb(uint64_t physical_address, uint8_t size); XhciTrb CreateLinkTrb(uint64_t physical_address); XhciTrb CreateEnableSlotTrb(); From 02d4f8c80e5e167e3a9bfa7fb0f6aeb5bb546e81 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 14:59:33 -0800 Subject: [PATCH 072/186] [Voyageurs] Send USB keypress data to the keyboard driver. --- lib/mammoth/ipc/port_client.cpp | 5 +++ lib/mammoth/ipc/port_client.h | 4 +- sys/voyageurs/keyboard/keyboard_driver.cpp | 49 ++++++++++++++++++---- sys/voyageurs/keyboard/keyboard_driver.h | 9 +++- sys/voyageurs/voyageurs.cpp | 5 +-- sys/voyageurs/xhci/device_slot.cpp | 6 ++- sys/voyageurs/xhci/device_slot.h | 3 +- sys/voyageurs/xhci/endpoint.cpp | 7 +++- sys/voyageurs/xhci/endpoint.h | 6 ++- sys/voyageurs/xhci/xhci_driver.cpp | 5 ++- 10 files changed, 79 insertions(+), 20 deletions(-) diff --git a/lib/mammoth/ipc/port_client.cpp b/lib/mammoth/ipc/port_client.cpp index 3c9f909..8bf1156 100644 --- a/lib/mammoth/ipc/port_client.cpp +++ b/lib/mammoth/ipc/port_client.cpp @@ -19,4 +19,9 @@ glcr::ErrorCode PortClient::WriteByte(uint8_t byte) { return static_cast( ZPortSend(port_cap_, 1, &byte, 0, nullptr)); } + +glcr::ErrorCode PortClient::Write(uint64_t data) { + return static_cast( + ZPortSend(port_cap_, 8, &data, 0, nullptr)); +} } // namespace mmth diff --git a/lib/mammoth/ipc/port_client.h b/lib/mammoth/ipc/port_client.h index 80571a3..c4fc222 100644 --- a/lib/mammoth/ipc/port_client.h +++ b/lib/mammoth/ipc/port_client.h @@ -10,6 +10,7 @@ namespace mmth { class PortClient { public: PortClient() {} + PortClient(z_cap_t port_cap); static PortClient AdoptPort(z_cap_t port_cap); template @@ -18,6 +19,7 @@ class PortClient { glcr::ErrorCode WriteString(glcr::String str, z_cap_t cap); glcr::ErrorCode WriteByte(uint8_t byte); + glcr::ErrorCode Write(uint64_t data); z_cap_t cap() { return port_cap_; } @@ -25,8 +27,6 @@ class PortClient { private: z_cap_t port_cap_ = 0; - - PortClient(z_cap_t port_cap); }; template diff --git a/sys/voyageurs/keyboard/keyboard_driver.cpp b/sys/voyageurs/keyboard/keyboard_driver.cpp index f96a3ad..43f921f 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.cpp +++ b/sys/voyageurs/keyboard/keyboard_driver.cpp @@ -2,13 +2,24 @@ #include +namespace { + +KeyboardDriver* gKeyboardDriver = nullptr; + +} + void InterruptEnter(void* void_keyboard) { KeyboardDriver* keyboard = static_cast(void_keyboard); keyboard->InterruptLoop(); } -KeyboardDriver::KeyboardDriver() { check(ZIrqRegister(kZIrqKbd, &irq_cap_)); } +KeyboardDriver::KeyboardDriver() { + check(ZPortCreate(&port_cap_)); + gKeyboardDriver = this; +} + +z_cap_t KeyboardDriver::GetPortCap() { return gKeyboardDriver->port_cap_; } void KeyboardDriver::RegisterListener(uint64_t port_cap) { listeners_.PushFront(mmth::PortClient::AdoptPort(port_cap)); @@ -21,13 +32,37 @@ Thread KeyboardDriver::StartInterruptLoop() { void KeyboardDriver::InterruptLoop() { dbgln("Interrupt"); while (true) { - uint8_t scancode; - uint64_t num_bytes = 1; + uint64_t scancode; + uint64_t num_bytes = 8; uint64_t num_caps = 0; - check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr)); + check(ZPortRecv(port_cap_, &num_bytes, &scancode, &num_caps, nullptr)); - for (mmth::PortClient& client : listeners_) { - client.WriteByte(scancode); - } + ProcessInput(scancode); + } +} + +void KeyboardDriver::ProcessInput(uint64_t input) { + uint64_t new_bitmap = 0; + for (uint8_t i = 2; i < 8; i++) { + uint8_t code = (input >> (8 * i)) & 0xFF; + if (code == 0) { + break; + } + if (code >= 64) { + dbgln("Skipping keycode: {x}", code); + } + uint64_t bit = 1 << code; + new_bitmap |= bit; + if ((bitmap_ & bit) != bit) { + SendKeypress(code); + } + } + bitmap_ = new_bitmap; +} + +void KeyboardDriver::SendKeypress(uint8_t scancode) { + dbgln("{x}", scancode); + for (mmth::PortClient& client : listeners_) { + client.WriteByte(scancode); } } diff --git a/sys/voyageurs/keyboard/keyboard_driver.h b/sys/voyageurs/keyboard/keyboard_driver.h index b38af0e..84715e1 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.h +++ b/sys/voyageurs/keyboard/keyboard_driver.h @@ -11,12 +11,19 @@ class KeyboardDriver { KeyboardDriver(const KeyboardDriver&) = delete; KeyboardDriver(KeyboardDriver&&) = delete; + static z_cap_t GetPortCap(); + void RegisterListener(uint64_t port_cap); Thread StartInterruptLoop(); void InterruptLoop(); private: - z_cap_t irq_cap_; + z_cap_t port_cap_; glcr::LinkedList listeners_; + + uint64_t bitmap_ = 0; + + void ProcessInput(uint64_t input); + void SendKeypress(uint8_t scancode); }; diff --git a/sys/voyageurs/voyageurs.cpp b/sys/voyageurs/voyageurs.cpp index 660f2b5..663d972 100644 --- a/sys/voyageurs/voyageurs.cpp +++ b/sys/voyageurs/voyageurs.cpp @@ -15,11 +15,10 @@ uint64_t main(uint64_t init_port) { YellowstoneClient yellowstone(gInitEndpointCap); - ASSIGN_OR_RETURN(auto xhci, XhciDriver::InitiateDriver(yellowstone)); - - dbgln("Initializing PS/2 Driver."); KeyboardDriver driver; + ASSIGN_OR_RETURN(auto xhci, XhciDriver::InitiateDriver(yellowstone)); + dbgln("Starting PS/2 Thread."); Thread keyboard_thread = driver.StartInterruptLoop(); diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp index ba6f29a..e9fc3b4 100644 --- a/sys/voyageurs/xhci/device_slot.cpp +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -80,7 +80,8 @@ void DeviceSlot::TransferComplete(uint8_t endpoint_index, uint64_t trb_phys) { check(control_completion_sempahores_.Delete(trb_phys)); } -mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) { +mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand( + uint8_t config_value, glcr::UniquePtr client) { input_context_->input.add_contexts = (0x1 << 3) | 0x1; input_context_->input.configuration_value = config_value; // TODO: Maybe don't hardcode this. @@ -93,7 +94,8 @@ mmth::Semaphore DeviceSlot::IssueConfigureDeviceCommand(uint8_t config_value) { input_context_->slot_context.route_speed_entries |= (max_endpoint << 27); // TODO: Dont' hardcode this. - endpoints_[3].Initialize(input_context_->endpoint_contexts + 2); + endpoints_[3].Initialize(input_context_->endpoint_contexts + 2, + glcr::Move(client)); xhci_driver_->IssueCommand(CreateConfigureEndpointCommand( context_phys_ + kInputSlotContextOffset, slot_index_)); diff --git a/sys/voyageurs/xhci/device_slot.h b/sys/voyageurs/xhci/device_slot.h index b228ba7..473d1c5 100644 --- a/sys/voyageurs/xhci/device_slot.h +++ b/sys/voyageurs/xhci/device_slot.h @@ -28,7 +28,8 @@ class DeviceSlot { XhciTrb CreateAddressDeviceCommand(uint8_t root_port, uint32_t route_string, uint16_t max_packet_size); - mmth::Semaphore IssueConfigureDeviceCommand(uint8_t config_value); + mmth::Semaphore IssueConfigureDeviceCommand( + uint8_t config_value, glcr::UniquePtr client); void SignalConfigureDeviceCompleted(); // Caller must keep the command in scope until it completes. diff --git a/sys/voyageurs/xhci/endpoint.cpp b/sys/voyageurs/xhci/endpoint.cpp index 3cfb568..6583953 100644 --- a/sys/voyageurs/xhci/endpoint.cpp +++ b/sys/voyageurs/xhci/endpoint.cpp @@ -4,9 +4,11 @@ #include "xhci/trb.h" -void Endpoint::Initialize(XhciEndpointContext* context) { +void Endpoint::Initialize(XhciEndpointContext* context, + glcr::UniquePtr client) { enabled_ = true; context_ = context; + client_ = glcr::Move(client); trb_ring_ = glcr::MakeUnique(); recv_mem_ = mmth::OwnedMemoryRegion::ContiguousPhysical(0x1000, &recv_phys_); @@ -23,7 +25,8 @@ void Endpoint::Initialize(XhciEndpointContext* context) { void Endpoint::TransferComplete(uint64_t trb_phys) { uint64_t phys_offset = (trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb); - dbgln("Data: {x}", *((uint64_t*)recv_mem_.vaddr() + phys_offset)); + uint64_t data = *((uint64_t*)recv_mem_.vaddr() + phys_offset); + client_->Write(data); trb_ring_->EnqueueTrb(CreateNormalTrb(recv_phys_ + offset_, 8)); offset_ += 8; } diff --git a/sys/voyageurs/xhci/endpoint.h b/sys/voyageurs/xhci/endpoint.h index 920620a..fd4a4d0 100644 --- a/sys/voyageurs/xhci/endpoint.h +++ b/sys/voyageurs/xhci/endpoint.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "xhci/trb_ring.h" #include "xhci/xhci.h" @@ -9,7 +10,8 @@ class Endpoint { public: Endpoint() {} - void Initialize(XhciEndpointContext* context); + void Initialize(XhciEndpointContext* context, + glcr::UniquePtr client); bool Enabled() { return enabled_; } @@ -24,4 +26,6 @@ class Endpoint { uint64_t recv_phys_; mmth::OwnedMemoryRegion recv_mem_; uint64_t offset_ = 0; + + glcr::UniquePtr client_; }; diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index 78f6d70..ce1a128 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -5,6 +5,7 @@ #include #include +#include "keyboard/keyboard_driver.h" #include "xhci/descriptors.h" #include "xhci/trb.h" #include "xhci/xhci.h" @@ -75,7 +76,9 @@ void configure_device(void* void_device_slot) { config_descriptor->configuration_value); device_slot - ->IssueConfigureDeviceCommand(config_descriptor->configuration_value) + ->IssueConfigureDeviceCommand( + config_descriptor->configuration_value, + glcr::MakeUnique(KeyboardDriver::GetPortCap())) .Wait(); dbgln("Configured!"); From 8fb55f56b6fcf2f7627330785ed540c5ea0834fc Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 15:12:21 -0800 Subject: [PATCH 073/186] [Yellowstone] Start teton after voyageurs is available. --- sys/yellowstone/yellowstone.cpp | 4 ++++ sys/yellowstone/yellowstone_server.cpp | 4 ++++ sys/yellowstone/yellowstone_server.h | 2 ++ 3 files changed, 10 insertions(+) diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp index 5efc089..2c85a99 100644 --- a/sys/yellowstone/yellowstone.cpp +++ b/sys/yellowstone/yellowstone.cpp @@ -49,6 +49,10 @@ uint64_t main(uint64_t port_cap) { for (glcr::StringView& file : files) { if (!file.empty()) { + // TODO: Implement startup dependencies. + if (file == "teton") { + server->WaitVoyageursRegistered(); + } mmth::File binary = mmth::File::Open(glcr::StrFormat("/bin/{}", file)); ASSIGN_OR_RETURN(client_cap, server->CreateClientCap()); diff --git a/sys/yellowstone/yellowstone_server.cpp b/sys/yellowstone/yellowstone_server.cpp index 999adfb..1c6af61 100644 --- a/sys/yellowstone/yellowstone_server.cpp +++ b/sys/yellowstone/yellowstone_server.cpp @@ -113,6 +113,8 @@ glcr::Status YellowstoneServer::HandleRegisterEndpoint( // transmit to other processes. mmth::SetVfsCap(req.endpoint_capability()); has_victoriafalls_semaphore_.Signal(); + } else if (req.endpoint_name() == "voyageurs") { + has_voyageurs_.Signal(); } else { dbgln("[WARN] Got endpoint cap type: {}", req.endpoint_name().cstr()); } @@ -138,4 +140,6 @@ void YellowstoneServer::WaitVictoriaFallsRegistered() { has_victoriafalls_semaphore_.Wait(); } +void YellowstoneServer::WaitVoyageursRegistered() { has_voyageurs_.Wait(); } + } // namespace yellowstone diff --git a/sys/yellowstone/yellowstone_server.h b/sys/yellowstone/yellowstone_server.h index c9bf99b..ac67fa7 100644 --- a/sys/yellowstone/yellowstone_server.h +++ b/sys/yellowstone/yellowstone_server.h @@ -25,6 +25,7 @@ class YellowstoneServer : public YellowstoneServerBase { void WaitDenaliRegistered(); void WaitVictoriaFallsRegistered(); + void WaitVoyageursRegistered(); private: glcr::HashMap endpoint_map_; @@ -37,6 +38,7 @@ class YellowstoneServer : public YellowstoneServerBase { mmth::Semaphore has_denali_semaphore_; mmth::Semaphore has_victoriafalls_semaphore_; + mmth::Semaphore has_voyageurs_; YellowstoneServer(z_cap_t endpoint_cap); }; From a9351b222dfa6c3dc3e376a1a10b59b73f0fb2da Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 15:12:44 -0800 Subject: [PATCH 074/186] [Mammoth] Change scancodes to USB codes. --- lib/mammoth/input/keyboard.cpp | 206 ++++++++++++++++----------------- 1 file changed, 99 insertions(+), 107 deletions(-) diff --git a/lib/mammoth/input/keyboard.cpp b/lib/mammoth/input/keyboard.cpp index 77b4858..bd2d905 100644 --- a/lib/mammoth/input/keyboard.cpp +++ b/lib/mammoth/input/keyboard.cpp @@ -157,118 +157,110 @@ Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) { } switch (scancode) { - case 0x01: - return kEsc; - case 0x02: - return k1; - case 0x03: - return k2; case 0x04: - return k3; - case 0x05: - return k4; - case 0x06: - return k5; - case 0x07: - return k6; - case 0x08: - return k7; - case 0x09: - return k8; - case 0x0A: - return k9; - case 0x0B: - return k0; - case 0x0C: - return kMinus; - case 0x0D: - return kEquals; - case 0x0E: - return kBackspace; - case 0x0F: - return kTab; - case 0x10: - return kQ; - case 0x11: - return kW; - case 0x12: - return kE; - case 0x13: - return kR; - case 0x14: - return kT; - case 0x15: - return kY; - case 0x16: - return kU; - case 0x17: - return kI; - case 0x18: - return kO; - case 0x19: - return kP; - case 0x1A: - return kLBrace; - case 0x1B: - return kRBrace; - case 0x1C: - return kEnter; - case 0x1D: - return kLCtrl; - case 0x1E: return kA; - case 0x1F: - return kS; - case 0x20: - return kD; - case 0x21: - return kF; - case 0x22: - return kG; - case 0x23: - return kH; - case 0x24: - return kJ; - case 0x25: - return kK; - case 0x26: - return kL; - case 0x27: - return kSemicolon; - case 0x28: - return kQuote; - case 0x29: - return kBacktick; - case 0x2A: - return kLShift; - case 0x2B: - return kBSlash; - case 0x2C: - return kZ; - case 0x2D: - return kX; - case 0x2E: - return kC; - case 0x2F: - return kV; - case 0x30: + case 0x05: return kB; - case 0x31: - return kN; - case 0x32: + case 0x06: + return kC; + case 0x07: + return kD; + case 0x08: + return kE; + case 0x09: + return kF; + case 0x0A: + return kG; + case 0x0B: + return kH; + case 0x0C: + return kI; + case 0x0D: + return kJ; + case 0x0E: + return kK; + case 0x0F: + return kL; + case 0x10: return kM; - case 0x33: - return kComma; - case 0x34: - return kPeriod; - case 0x35: - return kFSlash; - case 0x36: - return kRShift; - case 0x38: - return kLAlt; - case 0x39: + case 0x11: + return kN; + case 0x12: + return kO; + case 0x13: + return kP; + case 0x14: + return kQ; + case 0x15: + return kR; + case 0x16: + return kS; + case 0x17: + return kT; + case 0x18: + return kU; + case 0x19: + return kV; + case 0x1A: + return kW; + case 0x1B: + return kX; + case 0x1C: + return kY; + case 0x1D: + return kZ; + case 0x1E: + return k1; + case 0x1F: + return k2; + case 0x20: + return k3; + case 0x21: + return k4; + case 0x22: + return k5; + case 0x23: + return k6; + case 0x24: + return k7; + case 0x25: + return k8; + case 0x26: + return k9; + case 0x27: + return k0; + case 0x28: + return kEnter; + case 0x29: + return kEsc; + case 0x2A: + return kBackspace; + case 0x2B: + return kTab; + case 0x2C: return kSpace; + case 0x2D: + return kMinus; + case 0x2E: + return kEquals; + case 0x2F: + return kLBrace; + case 0x30: + return kRBrace; + case 0x31: + return kBSlash; + case 0x33: + return kSemicolon; + case 0x34: + return kQuote; + case 0x35: + return kBacktick; + case 0x36: + return kComma; + case 0x38: + return kPeriod; + case 0x39: + return kEsc; // Capslock } dbgln("Unknown scancode {x}", scancode); From 844f55c7d0f55542efd73574ea13a18d29167f84 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 24 Feb 2024 15:25:00 -0800 Subject: [PATCH 075/186] [Mammoth/Voyageurs] Add shift modifiers for scancodes. --- lib/mammoth/input/keyboard.cpp | 127 +++++++-------------- lib/mammoth/input/keyboard.h | 20 +--- lib/mammoth/ipc/port_client.cpp | 5 + lib/mammoth/ipc/port_client.h | 1 + lib/mammoth/ipc/port_server.cpp | 8 ++ lib/mammoth/ipc/port_server.h | 1 + sys/voyageurs/keyboard/keyboard_driver.cpp | 8 +- sys/voyageurs/keyboard/keyboard_driver.h | 2 +- 8 files changed, 65 insertions(+), 107 deletions(-) diff --git a/lib/mammoth/input/keyboard.cpp b/lib/mammoth/input/keyboard.cpp index bd2d905..f0ab639 100644 --- a/lib/mammoth/input/keyboard.cpp +++ b/lib/mammoth/input/keyboard.cpp @@ -55,71 +55,54 @@ Thread KeyboardListenerBase::Listen() { void KeyboardListenerBase::ListenLoop() { while (true) { - auto scancode_or = server_.RecvChar(); + auto scancode_or = server_.RecvUint16(); if (!scancode_or.ok()) { check(scancode_or.error()); } - uint8_t scancode = scancode_or.value(); + uint16_t scancode = scancode_or.value(); - if (scancode == 0xE0) { - extended_on_ = true; - continue; - } - - Keycode k = ScancodeToKeycode(scancode); - Action a = ScancodeToAction(scancode); - HandleKeycode(k, a); + Keycode k = ScancodeToKeycode(scancode & 0xFF); + uint8_t modifiers = (scancode >> 8) & 0xFF; + HandleKeycode(k, modifiers); } } -void KeyboardListenerBase::HandleKeycode(Keycode code, Action action) { +void KeyboardListenerBase::HandleKeycode(Keycode code, uint8_t modifiers) { char c = '\0'; - if (action == kPressed) { - if (code >= kA && code <= kZ) { - if (IsShift()) { - const char* alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - c = alpha[code - kA]; + if (code >= kA && code <= kZ) { + if (IsShift(modifiers)) { + const char* alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + c = alpha[code - kA]; - } else { - const char* alpha = "abcdefghijklmnopqrstuvwxyz"; - c = alpha[code - kA]; - } - } else if (code >= k1 && code <= k0) { - if (IsShift()) { - const char* num = "!@#$%^&*()"; - c = num[code - k1]; - } else { - const char* num = "1234567890"; - c = num[code - k1]; - } - } else if (code >= kMinus && code <= kBacktick) { - if (IsShift()) { - const char* sym = "_+{}|?:\"<>~"; - c = sym[code - kMinus]; - } else { - const char* sym = "-=[]\\/;',.`"; - c = sym[code - kMinus]; - } - } else if (code == kEnter) { - c = '\n'; - } else if (code == kSpace) { - c = ' '; - } else if (code == kTab) { - c = '\t'; - } else if (code == kBackspace) { - c = '\b'; - } else if (code == kLShift) { - lshift_ = true; - } else if (code == kRShift) { - rshift_ = true; + } else { + const char* alpha = "abcdefghijklmnopqrstuvwxyz"; + c = alpha[code - kA]; } - } else if (action == kReleased) { - if (code == kLShift) { - lshift_ = false; - } else if (code == kRShift) { - rshift_ = false; + } else if (code >= k1 && code <= k0) { + if (IsShift(modifiers)) { + const char* num = "!@#$%^&*()"; + c = num[code - k1]; + } else { + const char* num = "1234567890"; + c = num[code - k1]; } + } else if (code >= kMinus && code <= kBacktick) { + if (IsShift(modifiers)) { + const char* sym = "_+{}|?:\"<>~"; + c = sym[code - kMinus]; + } else { + const char* sym = "-=[]\\/;',.`"; + c = sym[code - kMinus]; + } + } else if (code == kEnter) { + c = '\n'; + } else if (code == kSpace) { + c = ' '; + } else if (code == kTab) { + c = '\t'; + } else if (code == kBackspace) { + c = '\b'; } if (c != '\0') { @@ -127,35 +110,7 @@ void KeyboardListenerBase::HandleKeycode(Keycode code, Action action) { } } -Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) { - // Cancel out the released bit. - scancode &= 0x7F; - if (extended_on_) { - extended_on_ = false; - - switch (scancode) { - case 0x1D: - return kRCtrl; - case 0x38: - return kRAlt; - case 0x48: - return kUp; - case 0x4B: - return kLeft; - case 0x4D: - return kRight; - case 0x50: - return kDown; - case 0x53: - return kDelete; - case 0x5B: - return kSuper; - } - dbgln("Unknown extended scancode {x}", scancode); - - return kUnknownKeycode; - } - +Keycode KeyboardListenerBase::ScancodeToKeycode(uint16_t scancode) { switch (scancode) { case 0x04: return kA; @@ -257,8 +212,10 @@ Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) { return kBacktick; case 0x36: return kComma; - case 0x38: + case 0x37: return kPeriod; + case 0x38: + return kFSlash; case 0x39: return kEsc; // Capslock } @@ -268,8 +225,4 @@ Keycode KeyboardListenerBase::ScancodeToKeycode(uint8_t scancode) { return kUnknownKeycode; } -Action KeyboardListenerBase::ScancodeToAction(uint8_t scancode) { - return (scancode & 0x80) ? kReleased : kPressed; -} - } // namespace mmth diff --git a/lib/mammoth/input/keyboard.h b/lib/mammoth/input/keyboard.h index cba2d18..5dfa50b 100644 --- a/lib/mammoth/input/keyboard.h +++ b/lib/mammoth/input/keyboard.h @@ -78,12 +78,6 @@ enum Keycode { kRight = 0x5B, }; -enum Action { - kUnknownAction, - kPressed, - kReleased, -}; - class KeyboardListenerBase { public: KeyboardListenerBase(); @@ -99,7 +93,7 @@ class KeyboardListenerBase { // Override this to recieve all raw keycodes. By default // this function will try to translate each keycode into // a printable character and call HandleCharacter. - virtual void HandleKeycode(Keycode code, Action action); + virtual void HandleKeycode(Keycode code, uint8_t modifiers); // This function is called by the default HandleKeycode // implementation if you do not override it. If it recieves @@ -109,15 +103,11 @@ class KeyboardListenerBase { private: PortServer server_; - bool extended_on_ = false; + Keycode ScancodeToKeycode(uint16_t scancode); - bool lshift_ = false; - bool rshift_ = false; - - Keycode ScancodeToKeycode(uint8_t scancode); - Action ScancodeToAction(uint8_t scancode); - - bool IsShift() { return lshift_ || rshift_; } + bool IsShift(uint8_t modifiers) { + return (modifiers & 0x2) || (modifiers & 0x20); + } }; } // namespace mmth diff --git a/lib/mammoth/ipc/port_client.cpp b/lib/mammoth/ipc/port_client.cpp index 8bf1156..db6c60f 100644 --- a/lib/mammoth/ipc/port_client.cpp +++ b/lib/mammoth/ipc/port_client.cpp @@ -20,6 +20,11 @@ glcr::ErrorCode PortClient::WriteByte(uint8_t byte) { ZPortSend(port_cap_, 1, &byte, 0, nullptr)); } +glcr::ErrorCode PortClient::Write(uint16_t data) { + return static_cast( + ZPortSend(port_cap_, 2, &data, 0, nullptr)); +} + glcr::ErrorCode PortClient::Write(uint64_t data) { return static_cast( ZPortSend(port_cap_, 8, &data, 0, nullptr)); diff --git a/lib/mammoth/ipc/port_client.h b/lib/mammoth/ipc/port_client.h index c4fc222..a633357 100644 --- a/lib/mammoth/ipc/port_client.h +++ b/lib/mammoth/ipc/port_client.h @@ -19,6 +19,7 @@ class PortClient { glcr::ErrorCode WriteString(glcr::String str, z_cap_t cap); glcr::ErrorCode WriteByte(uint8_t byte); + glcr::ErrorCode Write(uint16_t data); glcr::ErrorCode Write(uint64_t data); z_cap_t cap() { return port_cap_; } diff --git a/lib/mammoth/ipc/port_server.cpp b/lib/mammoth/ipc/port_server.cpp index 4643143..f81e3b8 100644 --- a/lib/mammoth/ipc/port_server.cpp +++ b/lib/mammoth/ipc/port_server.cpp @@ -55,4 +55,12 @@ glcr::ErrorOr PortServer::RecvChar() { return byte; } +glcr::ErrorOr PortServer::RecvUint16() { + uint64_t bytes = 2; + uint64_t caps = 0; + uint16_t data; + RET_ERR(ZPortRecv(port_cap_, &bytes, &data, &caps, nullptr)); + return data; +} + } // namespace mmth diff --git a/lib/mammoth/ipc/port_server.h b/lib/mammoth/ipc/port_server.h index 9e46599..acc5430 100644 --- a/lib/mammoth/ipc/port_server.h +++ b/lib/mammoth/ipc/port_server.h @@ -19,6 +19,7 @@ class PortServer { glcr::ErrorCode PollForIntCap(uint64_t* msg, uint64_t* cap); glcr::ErrorOr RecvChar(); + glcr::ErrorOr RecvUint16(); z_cap_t cap() { return port_cap_; } diff --git a/sys/voyageurs/keyboard/keyboard_driver.cpp b/sys/voyageurs/keyboard/keyboard_driver.cpp index 43f921f..fc4f1d1 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.cpp +++ b/sys/voyageurs/keyboard/keyboard_driver.cpp @@ -42,6 +42,7 @@ void KeyboardDriver::InterruptLoop() { } void KeyboardDriver::ProcessInput(uint64_t input) { + uint16_t modifiers = (input & 0xFF) << 8; uint64_t new_bitmap = 0; for (uint8_t i = 2; i < 8; i++) { uint8_t code = (input >> (8 * i)) & 0xFF; @@ -54,15 +55,14 @@ void KeyboardDriver::ProcessInput(uint64_t input) { uint64_t bit = 1 << code; new_bitmap |= bit; if ((bitmap_ & bit) != bit) { - SendKeypress(code); + SendKeypress(modifiers | code); } } bitmap_ = new_bitmap; } -void KeyboardDriver::SendKeypress(uint8_t scancode) { - dbgln("{x}", scancode); +void KeyboardDriver::SendKeypress(uint16_t scancode) { for (mmth::PortClient& client : listeners_) { - client.WriteByte(scancode); + client.Write(scancode); } } diff --git a/sys/voyageurs/keyboard/keyboard_driver.h b/sys/voyageurs/keyboard/keyboard_driver.h index 84715e1..54dee91 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.h +++ b/sys/voyageurs/keyboard/keyboard_driver.h @@ -25,5 +25,5 @@ class KeyboardDriver { uint64_t bitmap_ = 0; void ProcessInput(uint64_t input); - void SendKeypress(uint8_t scancode); + void SendKeypress(uint16_t scancode); }; From b0048b0a4fbe6a7d8a9307e4b9280fca839808b6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 8 Jun 2024 15:47:58 -0700 Subject: [PATCH 076/186] Barebones rust example working in user space. Requires manually copying the executable over to the image. --- .gitignore | 3 + lib/mammoth/proc/process.cpp | 14 +- rust/.cargo/config.toml | 6 + rust/Cargo.lock | 14 + rust/Cargo.toml | 14 + rust/lib/mammoth/Cargo.toml | 8 + rust/lib/mammoth/build.rs | 18 + rust/lib/mammoth/src/bindings.rs | 571 +++++++++++++++++++++++++++++++ rust/lib/mammoth/src/lib.rs | 28 ++ rust/rust-toolchain.toml | 2 + rust/usr/testbed/Cargo.toml | 7 + rust/usr/testbed/src/main.rs | 10 + rust/x86_64-acadia-os.json | 13 + 13 files changed, 707 insertions(+), 1 deletion(-) create mode 100644 rust/.cargo/config.toml create mode 100644 rust/Cargo.lock create mode 100644 rust/Cargo.toml create mode 100644 rust/lib/mammoth/Cargo.toml create mode 100644 rust/lib/mammoth/build.rs create mode 100644 rust/lib/mammoth/src/bindings.rs create mode 100644 rust/lib/mammoth/src/lib.rs create mode 100644 rust/rust-toolchain.toml create mode 100644 rust/usr/testbed/Cargo.toml create mode 100644 rust/usr/testbed/src/main.rs create mode 100644 rust/x86_64-acadia-os.json diff --git a/.gitignore b/.gitignore index 1425034..c073262 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ compile_commands.json sysroot/bin sysroot/usr/bin + +rust/target +yunq/venv diff --git a/lib/mammoth/proc/process.cpp b/lib/mammoth/proc/process.cpp index c7a79e5..ec25ec0 100644 --- a/lib/mammoth/proc/process.cpp +++ b/lib/mammoth/proc/process.cpp @@ -69,7 +69,14 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) { reinterpret_cast(base + header->phoff); for (uint64_t i = 0; i < header->phnum; i++) { Elf64ProgramHeader& program = programs[i]; + if (program.type != 1) { + // Only load loadable types. + // TODO: This may break if the stack is far away? + continue; + } #if MAM_PROC_DEBUG + dbgln(glcr::StrFormat("Program:\n\tType: {}\n\tFlags: {}\n\t", program.type, + program.flags)); dbgln("Create mem object"); #endif uint64_t page_offset = program.vaddr & 0xFFF; @@ -93,7 +100,8 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) { memcpy(base + program.offset, program.filesz, vaddr + page_offset); #if MAM_PROC_DEBUG - dbgln("Map Foreign"); + dbgln(glcr::StrFormat("Map Foreign: {x} {x} {x}", + program.vaddr - page_offset, size, vaddr)); #endif check(ZAddressSpaceMap(as_cap, program.vaddr - page_offset, mem_cap, 0, &vaddr)); @@ -124,6 +132,10 @@ glcr::ErrorOr SpawnProcessFromElfRegion(uint64_t program, uint64_t entry_point = LoadElfProgram(program, as_cap); + if (entry_point == 0) { + crash("Entry Point == 0", glcr::INTERNAL); + } + #if MAM_PROC_DEBUG dbgln("Thread Create"); #endif diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml new file mode 100644 index 0000000..b935b9b --- /dev/null +++ b/rust/.cargo/config.toml @@ -0,0 +1,6 @@ +[unstable] +build-std-features = ["compiler-builtins-mem"] +build-std = ["core", "compiler_builtins"] + +[build] +target = "x86_64-acadia-os.json" diff --git a/rust/Cargo.lock b/rust/Cargo.lock new file mode 100644 index 0000000..9ccd58d --- /dev/null +++ b/rust/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "mammoth" +version = "0.1.0" + +[[package]] +name = "testbed" +version = "0.1.0" +dependencies = [ + "mammoth", +] diff --git a/rust/Cargo.toml b/rust/Cargo.toml new file mode 100644 index 0000000..b1ec6be --- /dev/null +++ b/rust/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] + +members = [ + "lib/mammoth", "usr/testbed", +] + +# the profile used for `cargo build` +[profile.dev] +panic = "abort" # disable stack unwinding on panic + +# the profile used for `cargo build --release` +[profile.release] +panic = "abort" # disable stack unwinding on panic + diff --git a/rust/lib/mammoth/Cargo.toml b/rust/lib/mammoth/Cargo.toml new file mode 100644 index 0000000..5caf191 --- /dev/null +++ b/rust/lib/mammoth/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "mammoth" +version = "0.1.0" +edition = "2021" + +[dependencies] + +[build-dependencies] diff --git a/rust/lib/mammoth/build.rs b/rust/lib/mammoth/build.rs new file mode 100644 index 0000000..6797dfb --- /dev/null +++ b/rust/lib/mammoth/build.rs @@ -0,0 +1,18 @@ +use std::env; + +fn main() { + let mut curr_directory = env::current_dir().unwrap(); + println!("{:?}", curr_directory); + assert!(curr_directory.pop()); + assert!(curr_directory.pop()); + assert!(curr_directory.pop()); + + curr_directory.push("builddbg"); + curr_directory.push("zion"); + + println!( + "cargo:rustc-link-search={}", + curr_directory.to_str().unwrap() + ); + println!("cargo:rustc-link-lib=zion_stub"); +} diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs new file mode 100644 index 0000000..24556e8 --- /dev/null +++ b/rust/lib/mammoth/src/bindings.rs @@ -0,0 +1,571 @@ +/* automatically generated by rust-bindgen 0.69.4 */ + +pub const _STDINT_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _ISOC95_SOURCE: u32 = 1; +pub const _ISOC99_SOURCE: u32 = 1; +pub const _ISOC11_SOURCE: u32 = 1; +pub const _ISOC2X_SOURCE: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const _XOPEN_SOURCE: u32 = 700; +pub const _XOPEN_SOURCE_EXTENDED: u32 = 1; +pub const _LARGEFILE64_SOURCE: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const _DYNAMIC_STACK_SIZE_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC2X: u32 = 1; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_ISOCXX11: u32 = 1; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const __USE_XOPEN: u32 = 1; +pub const __USE_XOPEN_EXTENDED: u32 = 1; +pub const __USE_UNIX98: u32 = 1; +pub const _LARGEFILE_SOURCE: u32 = 1; +pub const __USE_XOPEN2K8XSI: u32 = 1; +pub const __USE_XOPEN2KXSI: u32 = 1; +pub const __USE_LARGEFILE: u32 = 1; +pub const __USE_LARGEFILE64: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __TIMESIZE: u32 = 64; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_DYNAMIC_STACK_SIZE: u32 = 1; +pub const __USE_GNU: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const __GLIBC_USE_C2X_STRTOL: u32 = 1; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_60559_BFP__: u32 = 201404; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 39; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 0; +pub const __GLIBC_USE_LIB_EXT2: u32 = 1; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 1; +pub const __GLIBC_USE_IEC_60559_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 1; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 1; +pub const _BITS_TYPES_H: u32 = 1; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const _BITS_STDINT_LEAST_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub const INT8_WIDTH: u32 = 8; +pub const UINT8_WIDTH: u32 = 8; +pub const INT16_WIDTH: u32 = 16; +pub const UINT16_WIDTH: u32 = 16; +pub const INT32_WIDTH: u32 = 32; +pub const UINT32_WIDTH: u32 = 32; +pub const INT64_WIDTH: u32 = 64; +pub const UINT64_WIDTH: u32 = 64; +pub const INT_LEAST8_WIDTH: u32 = 8; +pub const UINT_LEAST8_WIDTH: u32 = 8; +pub const INT_LEAST16_WIDTH: u32 = 16; +pub const UINT_LEAST16_WIDTH: u32 = 16; +pub const INT_LEAST32_WIDTH: u32 = 32; +pub const UINT_LEAST32_WIDTH: u32 = 32; +pub const INT_LEAST64_WIDTH: u32 = 64; +pub const UINT_LEAST64_WIDTH: u32 = 64; +pub const INT_FAST8_WIDTH: u32 = 8; +pub const UINT_FAST8_WIDTH: u32 = 8; +pub const INT_FAST16_WIDTH: u32 = 64; +pub const UINT_FAST16_WIDTH: u32 = 64; +pub const INT_FAST32_WIDTH: u32 = 64; +pub const UINT_FAST32_WIDTH: u32 = 64; +pub const INT_FAST64_WIDTH: u32 = 64; +pub const UINT_FAST64_WIDTH: u32 = 64; +pub const INTPTR_WIDTH: u32 = 64; +pub const UINTPTR_WIDTH: u32 = 64; +pub const INTMAX_WIDTH: u32 = 64; +pub const UINTMAX_WIDTH: u32 = 64; +pub const PTRDIFF_WIDTH: u32 = 64; +pub const SIG_ATOMIC_WIDTH: u32 = 32; +pub const SIZE_WIDTH: u32 = 64; +pub const WCHAR_WIDTH: u32 = 32; +pub const WINT_WIDTH: u32 = 32; +pub type __u_char = ::core::ffi::c_uchar; +pub type __u_short = ::core::ffi::c_ushort; +pub type __u_int = ::core::ffi::c_uint; +pub type __u_long = ::core::ffi::c_ulong; +pub type __int8_t = ::core::ffi::c_schar; +pub type __uint8_t = ::core::ffi::c_uchar; +pub type __int16_t = ::core::ffi::c_short; +pub type __uint16_t = ::core::ffi::c_ushort; +pub type __int32_t = ::core::ffi::c_int; +pub type __uint32_t = ::core::ffi::c_uint; +pub type __int64_t = ::core::ffi::c_long; +pub type __uint64_t = ::core::ffi::c_ulong; +pub type __int_least8_t = __int8_t; +pub type __uint_least8_t = __uint8_t; +pub type __int_least16_t = __int16_t; +pub type __uint_least16_t = __uint16_t; +pub type __int_least32_t = __int32_t; +pub type __uint_least32_t = __uint32_t; +pub type __int_least64_t = __int64_t; +pub type __uint_least64_t = __uint64_t; +pub type __quad_t = ::core::ffi::c_long; +pub type __u_quad_t = ::core::ffi::c_ulong; +pub type __intmax_t = ::core::ffi::c_long; +pub type __uintmax_t = ::core::ffi::c_ulong; +pub type __dev_t = ::core::ffi::c_ulong; +pub type __uid_t = ::core::ffi::c_uint; +pub type __gid_t = ::core::ffi::c_uint; +pub type __ino_t = ::core::ffi::c_ulong; +pub type __ino64_t = ::core::ffi::c_ulong; +pub type __mode_t = ::core::ffi::c_uint; +pub type __nlink_t = ::core::ffi::c_ulong; +pub type __off_t = ::core::ffi::c_long; +pub type __off64_t = ::core::ffi::c_long; +pub type __pid_t = ::core::ffi::c_int; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct __fsid_t { + pub __val: [::core::ffi::c_int; 2usize], +} +pub type __clock_t = ::core::ffi::c_long; +pub type __rlim_t = ::core::ffi::c_ulong; +pub type __rlim64_t = ::core::ffi::c_ulong; +pub type __id_t = ::core::ffi::c_uint; +pub type __time_t = ::core::ffi::c_long; +pub type __useconds_t = ::core::ffi::c_uint; +pub type __suseconds_t = ::core::ffi::c_long; +pub type __suseconds64_t = ::core::ffi::c_long; +pub type __daddr_t = ::core::ffi::c_int; +pub type __key_t = ::core::ffi::c_int; +pub type __clockid_t = ::core::ffi::c_int; +pub type __timer_t = *mut ::core::ffi::c_void; +pub type __blksize_t = ::core::ffi::c_long; +pub type __blkcnt_t = ::core::ffi::c_long; +pub type __blkcnt64_t = ::core::ffi::c_long; +pub type __fsblkcnt_t = ::core::ffi::c_ulong; +pub type __fsblkcnt64_t = ::core::ffi::c_ulong; +pub type __fsfilcnt_t = ::core::ffi::c_ulong; +pub type __fsfilcnt64_t = ::core::ffi::c_ulong; +pub type __fsword_t = ::core::ffi::c_long; +pub type __ssize_t = ::core::ffi::c_long; +pub type __syscall_slong_t = ::core::ffi::c_long; +pub type __syscall_ulong_t = ::core::ffi::c_ulong; +pub type __loff_t = __off64_t; +pub type __caddr_t = *mut ::core::ffi::c_char; +pub type __intptr_t = ::core::ffi::c_long; +pub type __socklen_t = ::core::ffi::c_uint; +pub type __sig_atomic_t = ::core::ffi::c_int; +pub type int_least8_t = __int_least8_t; +pub type int_least16_t = __int_least16_t; +pub type int_least32_t = __int_least32_t; +pub type int_least64_t = __int_least64_t; +pub type uint_least8_t = __uint_least8_t; +pub type uint_least16_t = __uint_least16_t; +pub type uint_least32_t = __uint_least32_t; +pub type uint_least64_t = __uint_least64_t; +pub type int_fast8_t = ::core::ffi::c_schar; +pub type int_fast16_t = ::core::ffi::c_long; +pub type int_fast32_t = ::core::ffi::c_long; +pub type int_fast64_t = ::core::ffi::c_long; +pub type uint_fast8_t = ::core::ffi::c_uchar; +pub type uint_fast16_t = ::core::ffi::c_ulong; +pub type uint_fast32_t = ::core::ffi::c_ulong; +pub type uint_fast64_t = ::core::ffi::c_ulong; +pub type intmax_t = __intmax_t; +pub type uintmax_t = __uintmax_t; +pub type z_err_t = u64; +pub const kZionProcessExit: u64 = 1; +pub const kZionProcessSpawn: u64 = 2; +pub const kZionProcessWait: u64 = 3; +pub const kZionThreadCreate: u64 = 16; +pub const kZionThreadStart: u64 = 17; +pub const kZionThreadExit: u64 = 18; +pub const kZionThreadWait: u64 = 19; +pub const kZionThreadSleep: u64 = 20; +pub const kZionAddressSpaceMap: u64 = 33; +pub const kZionAddressSpaceUnmap: u64 = 34; +pub const kZionMemoryObjectCreate: u64 = 48; +pub const kZionMemoryObjectCreatePhysical: u64 = 49; +pub const kZionMemoryObjectCreateContiguous: u64 = 50; +pub const kZionMemoryObjectDuplicate: u64 = 56; +pub const kZionMemoryObjectInspect: u64 = 57; +pub const kZionChannelCreate: u64 = 64; +pub const kZionChannelSend: u64 = 65; +pub const kZionChannelRecv: u64 = 66; +pub const kZionChannelSendRecv: u64 = 67; +pub const kZionPortCreate: u64 = 80; +pub const kZionPortSend: u64 = 81; +pub const kZionPortRecv: u64 = 82; +pub const kZionPortPoll: u64 = 83; +pub const kZionIrqRegister: u64 = 88; +pub const kZionEndpointCreate: u64 = 96; +pub const kZionEndpointSend: u64 = 97; +pub const kZionEndpointRecv: u64 = 98; +pub const kZionReplyPortSend: u64 = 99; +pub const kZionReplyPortRecv: u64 = 100; +pub const kZionEndpointCall: u64 = 101; +pub const kZionCapDuplicate: u64 = 112; +pub const kZionCapRelease: u64 = 113; +pub const kZionMutexCreate: u64 = 128; +pub const kZionMutexLock: u64 = 129; +pub const kZionMutexRelease: u64 = 130; +pub const kZionSemaphoreCreate: u64 = 131; +pub const kZionSemaphoreWait: u64 = 132; +pub const kZionSemaphoreSignal: u64 = 133; +pub const kZionDebug: u64 = 65536; +pub const kZIrqKbd: u64 = 34; +pub const kZIrqPci1: u64 = 48; +pub const kZIrqPci2: u64 = 49; +pub const kZIrqPci3: u64 = 50; +pub const kZIrqPci4: u64 = 51; +pub type z_cap_t = u64; +pub type z_perm_t = u64; +pub const kZionInvalidCapability: u64 = 0; +pub const kZionPerm_Write: u64 = 1; +pub const kZionPerm_Read: u64 = 2; +pub const kZionPerm_Transmit: u64 = 16; +pub const kZionPerm_Duplicate: u64 = 32; +pub const kZionPerm_SpawnProcess: u64 = 256; +pub const kZionPerm_SpawnThread: u64 = 512; +pub const kZionPerm_Lock: u64 = 256; +pub const kZionPerm_Release: u64 = 512; +pub const kZionPerm_Wait: u64 = 256; +pub const kZionPerm_Signal: u64 = 512; +pub const kZionPerm_None: z_perm_t = 0; +pub const kZionPerm_All: z_perm_t = 18446744073709551615; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZFramebufferInfo { + pub address_phys: u64, + pub width: u64, + pub height: u64, + pub pitch: u64, + pub bpp: u16, + pub memory_model: u8, + pub red_mask_size: u8, + pub red_mask_shift: u8, + pub green_mask_size: u8, + pub green_mask_shift: u8, + pub blue_mask_size: u8, + pub blue_mask_shift: u8, +} +extern "C" { + #[link_name = "\u{1}_Z8SysCall1mPKv"] + pub fn SysCall1(code: u64, req: *const ::core::ffi::c_void) -> z_err_t; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZProcessExitReq { + pub code: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZProcessSpawnReq { + pub proc_cap: z_cap_t, + pub bootstrap_cap: z_cap_t, + pub new_proc_cap: *mut z_cap_t, + pub new_vmas_cap: *mut z_cap_t, + pub new_bootstrap_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZProcessWaitReq { + pub proc_cap: z_cap_t, + pub exit_code: *mut z_err_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZThreadCreateReq { + pub proc_cap: z_cap_t, + pub thread_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZThreadStartReq { + pub thread_cap: z_cap_t, + pub entry: u64, + pub arg1: u64, + pub arg2: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZThreadExitReq { + pub _address: u8, +} +extern "C" { + #[link_name = "\u{1}_Z11ZThreadExitv"] + pub fn ZThreadExit() -> z_err_t; +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZThreadWaitReq { + pub thread_cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZThreadSleepReq { + pub millis: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZAddressSpaceMapReq { + pub vmas_cap: z_cap_t, + pub vmas_offset: u64, + pub vmmo_cap: z_cap_t, + pub align: u64, + pub vaddr: *mut u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZAddressSpaceUnmapReq { + pub vmas_cap: z_cap_t, + pub lower_addr: u64, + pub upper_addr: u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMemoryObjectCreateReq { + pub size: u64, + pub vmmo_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMemoryObjectCreatePhysicalReq { + pub paddr: u64, + pub size: u64, + pub vmmo_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMemoryObjectCreateContiguousReq { + pub size: u64, + pub vmmo_cap: *mut z_cap_t, + pub paddr: *mut u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMemoryObjectDuplicateReq { + pub vmmo_cap: z_cap_t, + pub base_offset: u64, + pub length: u64, + pub new_vmmo_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMemoryObjectInspectReq { + pub vmmo_cap: z_cap_t, + pub size: *mut u64, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZChannelCreateReq { + pub channel1: *mut z_cap_t, + pub channel2: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZChannelSendReq { + pub chan_cap: z_cap_t, + pub num_bytes: u64, + pub data: *const ::core::ffi::c_void, + pub num_caps: u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZChannelRecvReq { + pub chan_cap: z_cap_t, + pub num_bytes: *mut u64, + pub data: *mut ::core::ffi::c_void, + pub num_caps: *mut u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPortCreateReq { + pub port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPortSendReq { + pub port_cap: z_cap_t, + pub num_bytes: u64, + pub data: *const ::core::ffi::c_void, + pub num_caps: u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPortRecvReq { + pub port_cap: z_cap_t, + pub num_bytes: *mut u64, + pub data: *mut ::core::ffi::c_void, + pub num_caps: *mut u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPortPollReq { + pub port_cap: z_cap_t, + pub num_bytes: *mut u64, + pub data: *mut ::core::ffi::c_void, + pub num_caps: *mut u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZIrqRegisterReq { + pub irq_num: u64, + pub port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZEndpointCreateReq { + pub endpoint_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZEndpointSendReq { + pub endpoint_cap: z_cap_t, + pub num_bytes: u64, + pub data: *const ::core::ffi::c_void, + pub num_caps: u64, + pub caps: *const z_cap_t, + pub reply_port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZEndpointRecvReq { + pub endpoint_cap: z_cap_t, + pub num_bytes: *mut u64, + pub data: *mut ::core::ffi::c_void, + pub num_caps: *mut u64, + pub caps: *mut z_cap_t, + pub reply_port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZReplyPortSendReq { + pub reply_port_cap: z_cap_t, + pub num_bytes: u64, + pub data: *const ::core::ffi::c_void, + pub num_caps: u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZReplyPortRecvReq { + pub reply_port_cap: z_cap_t, + pub num_bytes: *mut u64, + pub data: *mut ::core::ffi::c_void, + pub num_caps: *mut u64, + pub caps: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZCapDuplicateReq { + pub cap_in: z_cap_t, + pub perm_mask: z_perm_t, + pub cap_out: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZCapReleaseReq { + pub cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMutexCreateReq { + pub mutex_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMutexLockReq { + pub mutex_cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZMutexReleaseReq { + pub mutex_cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZSemaphoreCreateReq { + pub semaphore_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZSemaphoreWaitReq { + pub semaphore_cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZSemaphoreSignalReq { + pub semaphore_cap: z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZDebugReq { + pub message: *const ::core::ffi::c_char, + pub size: u64, +} diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs new file mode 100644 index 0000000..be5f1e6 --- /dev/null +++ b/rust/lib/mammoth/src/lib.rs @@ -0,0 +1,28 @@ +#![no_std] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +use core::ffi::c_void; +use core::panic::PanicInfo; + +include!("bindings.rs"); + +fn syscall(id: u64, req: &T) -> u64 { + unsafe { SysCall1(id, req as *const T as *const c_void) } +} + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + let req = ZProcessExitReq { code: 1 }; + syscall(kZionProcessExit, &req); + unreachable!() +} + +pub fn debug(msg: &str) { + let req = ZDebugReq { + message: msg.as_ptr() as *const i8, + size: msg.len() as u64, + }; + syscall(kZionDebug, &req); +} diff --git a/rust/rust-toolchain.toml b/rust/rust-toolchain.toml new file mode 100644 index 0000000..5d56faf --- /dev/null +++ b/rust/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml new file mode 100644 index 0000000..999e3eb --- /dev/null +++ b/rust/usr/testbed/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "testbed" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../../lib/mammoth" } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs new file mode 100644 index 0000000..e06f819 --- /dev/null +++ b/rust/usr/testbed/src/main.rs @@ -0,0 +1,10 @@ +#![no_std] +#![no_main] + +use mammoth::debug; + +#[no_mangle] +pub extern "C" fn _start() -> ! { + debug("Test!"); + panic!() +} diff --git a/rust/x86_64-acadia-os.json b/rust/x86_64-acadia-os.json new file mode 100644 index 0000000..6e6dec1 --- /dev/null +++ b/rust/x86_64-acadia-os.json @@ -0,0 +1,13 @@ +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort" +} From 5b1debde54017d6adfa512c6b7caafc3ecdc54b7 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 8 Jun 2024 15:58:16 -0700 Subject: [PATCH 077/186] Automatically rebuild a rust file when running qemu. --- .gitignore | 2 +- scripts/qemu.sh | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index c073262..e8346ca 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ __pycache__/ compile_commands.json sysroot/bin -sysroot/usr/bin +sysroot/usr rust/target yunq/venv diff --git a/scripts/qemu.sh b/scripts/qemu.sh index c3c6526..1fc4eb9 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -12,6 +12,13 @@ pushd $BUILD_DIR ninja ninja install +export CARGO_INSTALL_ROOT="${DIR}/../sysroot/usr/" + +# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml +pushd "${DIR}/../rust" +cargo install --force --path "${DIR}/../rust/usr/testbed/" +popd + sudo sh ${DIR}/build_image.sh disk.img QEMU_ARGS= From 1cda0537580129a74765e480e131f879221a68f7 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 11 Jun 2024 13:01:58 -0700 Subject: [PATCH 078/186] Create a first pass at a rust parser for the yunq language. --- .gitignore | 1 + yunq/rust/Cargo.lock | 237 ++++++++++++++++++++++++++++++++ yunq/rust/Cargo.toml | 7 + yunq/rust/src/lexer.rs | 225 ++++++++++++++++++++++++++++++ yunq/rust/src/main.rs | 30 ++++ yunq/rust/src/parser.rs | 293 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 793 insertions(+) create mode 100644 yunq/rust/Cargo.lock create mode 100644 yunq/rust/Cargo.toml create mode 100644 yunq/rust/src/lexer.rs create mode 100644 yunq/rust/src/main.rs create mode 100644 yunq/rust/src/parser.rs diff --git a/.gitignore b/.gitignore index e8346ca..9e8c8ee 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ sysroot/usr rust/target yunq/venv +yunq/rust/target diff --git a/yunq/rust/Cargo.lock b/yunq/rust/Cargo.lock new file mode 100644 index 0000000..7d49b6b --- /dev/null +++ b/yunq/rust/Cargo.lock @@ -0,0 +1,237 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "clap" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "yunq" +version = "0.1.0" +dependencies = [ + "clap", +] diff --git a/yunq/rust/Cargo.toml b/yunq/rust/Cargo.toml new file mode 100644 index 0000000..2f9645f --- /dev/null +++ b/yunq/rust/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "yunq" +version = "0.1.0" +edition = "2021" + +[dependencies] +clap = { version = "4.5.7", features = ["derive"] } diff --git a/yunq/rust/src/lexer.rs b/yunq/rust/src/lexer.rs new file mode 100644 index 0000000..81eab06 --- /dev/null +++ b/yunq/rust/src/lexer.rs @@ -0,0 +1,225 @@ +#[derive(Debug, PartialEq)] +pub enum TokenType { + EndOfFile, + Name, + LeftBrace, + RightBrace, + LeftParen, + RightParen, + Arrow, + Semicolon, + Dot, + Equals, +} + +#[derive(Debug)] +pub struct Token { + pub token_type: TokenType, + line: usize, + start: usize, + end: usize, + pub chars: String, +} + +impl std::fmt::Display for Token { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "'{}' at line {} position {} ", + self.chars, self.line, self.start + ) + } +} + +pub fn lex_input(input: &str) -> Result, String> { + let mut index = 0; + let mut position = 0; + let mut line = 1; + + let mut tokens = Vec::new(); + + let mut chars = input.chars().peekable(); + loop { + match chars.next() { + Some(c) => { + position += 1; + match c { + '\n' => { + position = 0; + line += 1; + } + ' ' | '\t' | '\r' => {} + '/' => { + match chars.next() { + Some('/') => { + index += 1; + // TODO: Add a consume until function. + loop { + match chars.next() { + Some('\n') => { + index += 1; + position = 0; + line += 1; + break; + } + Some(_) => { + index += 1; + } + None => break, + + } + + } + } + _ => { + return Err(format!("Unexpected token '/' at line {} position {}", line, position)); + } + + } + } + '{' => tokens.push(Token{ + token_type: TokenType::LeftBrace, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + '}' => tokens.push(Token{ + token_type: TokenType::RightBrace, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + '(' => tokens.push(Token{ + token_type: TokenType::LeftParen, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + ')' => tokens.push(Token{ + token_type: TokenType::RightParen, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + ';' => tokens.push(Token{ + token_type: TokenType::Semicolon, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + '.' => tokens.push(Token{ + token_type: TokenType::Dot, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + '=' => tokens.push(Token{ + token_type: TokenType::Equals, + line, + start: position, + end: position + 1, + chars: input[index..index+1].to_string(), + + }), + '-' => match chars.next() { + Some('>') => { + position += 1; + tokens.push(Token{ + token_type: TokenType::Arrow, + line, + start: position - 1, + end: position + 1, + chars: input[index..index+1].to_string(), + }); + index += 1; + } + Some(c) => return Err(format!("Expected > to follow - (to form arrow '->') on line {} at position {}. But got '{}'", line, position + 1, c)), + None => return Err(format!("Expected > to follow - but got end of input instead on line {} position {}", line, position)) + }, + 'a'..='z' | 'A'..='Z' => { + let name_start = index; + let pos_start = position; + loop { + match chars.peek() { + Some(c) => { + match c { + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => { + position += 1; + chars.next(); + index += 1; + }, + '\n' => { + chars.next(); + tokens.push(Token{ + token_type: TokenType::Name, + line, + start: pos_start, + end: position + 1, + chars: input[name_start..index+1].to_string(), + }); + position = 0; + index += 1; + line += 1; + break; + }, + _ => { + tokens.push(Token{ + token_type: TokenType::Name, + line, + start: pos_start, + end: position + 1, + chars: input[name_start..index+1].to_string() + }); + break; + }, + } + } + None => { + tokens.push(Token{ + token_type: TokenType::Name, + line, + start: pos_start, + end: position + 1, + chars: input[name_start..index].to_string(), + }); + break; + } + } + } + }, + _ => { + return Err(format!( + "Unexpected token on line {} character {}: {}", + line, position, c + )) + } + } + } + None => { + tokens.push(Token { + token_type: TokenType::EndOfFile, + line, + start: position, + end: position, + chars: "EOF".to_string(), + }); + break; + } + } + index += 1; + } + + Ok(tokens) +} diff --git a/yunq/rust/src/main.rs b/yunq/rust/src/main.rs new file mode 100644 index 0000000..0fb7c97 --- /dev/null +++ b/yunq/rust/src/main.rs @@ -0,0 +1,30 @@ +mod lexer; +mod parser; + +use std::error::Error; +use std::fs::read_to_string; + +use clap::Parser; + +#[derive(Parser)] +#[command(about)] +struct Args { + // The .yunq file to parse + #[arg(short, long)] + input_path: String, +} + +fn main() -> Result<(), Box> { + let args = Args::parse(); + let input = read_to_string(args.input_path)?; + let tokens = lexer::lex_input(&input)?; + + let mut ast_parser = parser::Parser::new(&tokens); + ast_parser.parse_ast()?; + + for decl in ast_parser.ast() { + println!("{:?}", decl); + } + + Ok(()) +} diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs new file mode 100644 index 0000000..d2ad3d2 --- /dev/null +++ b/yunq/rust/src/parser.rs @@ -0,0 +1,293 @@ +use std::fmt::Debug; +use std::fmt::Display; + +use crate::lexer::Token; +use crate::lexer::TokenType; + +pub enum Type { + U64, + I64, + Message(String), +} + +impl Display for Type { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + match self { + Type::U64 => "u64", + Type::I64 => "i64", + Type::Message(s) => s, + } + ) + } +} + +impl TryFrom<&String> for Type { + type Error = String; + + fn try_from(value: &String) -> Result { + match value.as_str() { + "u64" => Ok(Type::U64), + "i64" => Ok(Type::I64), + _ => Ok(Type::Message(value.clone())), + } + } +} + +pub struct Field { + field_type: Type, + name: String, + number: u64, + repeated: bool, +} + +pub struct Message { + name: String, + fields: Vec, +} + +pub struct Method { + name: String, + number: u64, + request: Option, + response: Option, +} + +impl Debug for Method { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let request_str = match &self.request { + Some(s) => format!("({})", s), + None => "()".to_string(), + }; + let response_str = match &self.response { + Some(s) => format!("({})", s), + None => "()".to_string(), + }; + + write!( + f, + "{}: {}: {} -> {}", + self.number, self.name, request_str, response_str + ) + } +} + +pub struct Interface { + name: String, + methods: Vec, +} + +pub enum Decl { + Message(Message), + Interface(Interface), + Package(Vec), +} + +impl Debug for Decl { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Decl::Message(m) => { + writeln!(f, "Message {}", m.name)?; + for field in &m.fields { + let typestr = if field.repeated { + format!("repeated {}", field.field_type) + } else { + field.field_type.to_string() + }; + writeln!(f, "\t{}: {} ({})", field.number, field.name, typestr)?; + } + } + Decl::Interface(i) => { + writeln!(f, "Interface {}", i.name)?; + for method in &i.methods { + writeln!(f, "\t{:?}", method)?; + } + } + Decl::Package(p) => { + writeln!(f, "Package {};", p.join("."))?; + } + } + Ok(()) + } +} + +pub struct Parser<'a> { + tokens: &'a Vec, + current_index: usize, + ast: Vec, +} + +impl<'a> Parser<'a> { + pub fn new(tokens: &'a Vec) -> Self { + Self { + tokens, + current_index: 0, + ast: Vec::new(), + } + } + + fn next_type_is(&self, tok_type: TokenType) -> bool { + self.current_index < self.tokens.len() + && self.tokens[self.current_index].token_type == tok_type + } + + fn consume_token<'b>(&'b mut self) -> &'b Token { + if self.current_index >= self.tokens.len() { + panic!("Consumed tokens past end of input.") + } + + let t = &self.tokens[self.current_index]; + self.current_index += 1; + t + } + + fn consume_token_type<'b>(&'b mut self, t: TokenType) -> Result<&'b Token, String> { + let token = self.consume_token(); + if token.token_type == t { + Ok(token) + } else { + Err(format!("Expected {:?} but found {}", t, token)) + } + } + + fn consume_identifier<'b>(&'b mut self) -> Result<&'b Token, String> { + self.consume_token_type(TokenType::Name) + } + + fn consume_keyword<'b>(&'b mut self, keyword: &str) -> Result<&'b Token, String> { + let token = self.consume_token_type(TokenType::Name)?; + if token.chars != keyword { + Err(format!("Expected '{}' but got {}", keyword, token)) + } else { + Ok(token) + } + } + + fn package(&mut self) -> Result { + // 'package' was consumed by decl. + let mut package_names = vec![self.consume_identifier()?.chars.clone()]; + while self.next_type_is(TokenType::Dot) { + self.consume_token_type(TokenType::Dot)?; + package_names.push(self.consume_identifier()?.chars.clone()); + } + self.consume_token_type(TokenType::Semicolon)?; + Ok(Decl::Package(package_names)) + } + + fn field(&mut self, number: u64) -> Result { + let mut type_identifier = self.consume_identifier()?; + let mut repeated = false; + if type_identifier.chars == "repeated" { + repeated = true; + type_identifier = self.consume_identifier()?; + } + + let parsed_type = Type::try_from(&type_identifier.chars) + .map_err(|err| format!("{}: {}", err, type_identifier))?; + let name_identifier = self.consume_identifier()?.chars.clone(); + + self.consume_token_type(TokenType::Semicolon)?; + + Ok(Field { + field_type: parsed_type, + name: name_identifier, + number, + repeated, + }) + } + + fn message(&mut self) -> Result { + // 'message' was consumed by decl. + let name = self.consume_identifier()?.chars.clone(); + + self.consume_token_type(TokenType::LeftBrace)?; + + let mut fields = Vec::new(); + let mut next_field_number = 0; + while !self.next_type_is(TokenType::RightBrace) { + fields.push(self.field(next_field_number)?); + next_field_number += 1; + } + + self.consume_token_type(TokenType::RightBrace)?; + + Ok(Decl::Message(Message { name, fields })) + } + + fn method(&mut self, number: u64) -> Result { + self.consume_keyword("method")?; + + let name = self.consume_identifier()?.chars.clone(); + + self.consume_token_type(TokenType::LeftParen)?; + let request = if self.next_type_is(TokenType::Name) { + Some(self.consume_identifier()?.chars.clone()) + } else { + None + }; + self.consume_token_type(TokenType::RightParen)?; + + self.consume_token_type(TokenType::Arrow)?; + + self.consume_token_type(TokenType::LeftParen)?; + let response = if self.next_type_is(TokenType::Name) { + Some(self.consume_identifier()?.chars.clone()) + } else { + None + }; + self.consume_token_type(TokenType::RightParen)?; + + self.consume_token_type(TokenType::Semicolon)?; + + Ok(Method { + name, + request, + response, + number, + }) + } + + fn interface(&mut self) -> Result { + let name = self.consume_identifier()?.chars.clone(); + + self.consume_token_type(TokenType::LeftBrace)?; + + let mut methods = Vec::new(); + let mut next_method_number = 0; + while !self.next_type_is(TokenType::RightBrace) { + methods.push(self.method(next_method_number)?); + next_method_number += 1; + } + + self.consume_token_type(TokenType::RightBrace)?; + + Ok(Decl::Interface(Interface { name, methods })) + } + + fn decl(&mut self) -> Result { + let token = self.consume_identifier()?; + match token.chars.as_str() { + "package" => self.package(), + "message" => self.message(), + "interface" => self.interface(), + _ => Err(format!( + "Expected one of 'package', 'message', or 'interface' but got {}", + token + )), + } + } + + pub fn parse_ast(&mut self) -> Result<(), String> { + while !self.next_type_is(TokenType::EndOfFile) { + let decl = self.decl()?; + self.ast.push(decl); + } + Ok(()) + } + + pub fn ast(&'a mut self) -> &'a Vec { + &self.ast + } +} From 12fb84cfadc4714b0de00de694833d089e5b3fe8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 11 Jun 2024 13:32:28 -0700 Subject: [PATCH 079/186] [Yunq] Add typechecking to rust implementation. --- yunq/rust/src/main.rs | 1 + yunq/rust/src/parser.rs | 109 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/yunq/rust/src/main.rs b/yunq/rust/src/main.rs index 0fb7c97..b5ae3a0 100644 --- a/yunq/rust/src/main.rs +++ b/yunq/rust/src/main.rs @@ -21,6 +21,7 @@ fn main() -> Result<(), Box> { let mut ast_parser = parser::Parser::new(&tokens); ast_parser.parse_ast()?; + ast_parser.type_check()?; for decl in ast_parser.ast() { println!("{:?}", decl); diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index d2ad3d2..6dd3a18 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -1,12 +1,18 @@ +use std::collections::HashMap; +use std::collections::HashSet; use std::fmt::Debug; use std::fmt::Display; use crate::lexer::Token; use crate::lexer::TokenType; +#[derive(Clone)] pub enum Type { U64, I64, + String, + Bytes, + Capability, Message(String), } @@ -18,6 +24,9 @@ impl Display for Type { match self { Type::U64 => "u64", Type::I64 => "i64", + Type::String => "string", + Type::Bytes => "bytes", + Type::Capability => "cap", Type::Message(s) => s, } ) @@ -31,11 +40,15 @@ impl TryFrom<&String> for Type { match value.as_str() { "u64" => Ok(Type::U64), "i64" => Ok(Type::I64), + "string" => Ok(Type::String), + "bytes" => Ok(Type::Bytes), + "capability" => Ok(Type::Capability), _ => Ok(Type::Message(value.clone())), } } } +#[derive(Clone)] pub struct Field { field_type: Type, name: String, @@ -43,6 +56,7 @@ pub struct Field { repeated: bool, } +#[derive(Clone)] pub struct Message { name: String, fields: Vec, @@ -117,6 +131,7 @@ pub struct Parser<'a> { tokens: &'a Vec, current_index: usize, ast: Vec, + type_map: HashMap, } impl<'a> Parser<'a> { @@ -125,6 +140,7 @@ impl<'a> Parser<'a> { tokens, current_index: 0, ast: Vec::new(), + type_map: HashMap::new(), } } @@ -290,4 +306,97 @@ impl<'a> Parser<'a> { pub fn ast(&'a mut self) -> &'a Vec { &self.ast } + + fn ensure_message_and_interface_names_unique(&mut self) -> Result<(), String> { + let mut names = HashSet::new(); + for decl in &self.ast { + match decl { + Decl::Message(m) => { + if names.contains(&m.name) { + // TODO: Keep token information for a better error message here. + return Err(format!("Duplicate name {}", m.name)); + }; + names.insert(m.name.clone()); + self.type_map.insert(m.name.clone(), m.clone()); + } + Decl::Interface(i) => { + if names.contains(&i.name) { + // TODO: Keep token information for a better error message here. + return Err(format!("Duplicate name {}", i.name)); + }; + names.insert(i.name.clone()); + } + _ => {} + } + } + Ok(()) + } + + fn type_check_message(&self, message: &Message) -> Result<(), String> { + let mut field_names = HashSet::new(); + + for field in &message.fields { + if field_names.contains(&field.name) { + return Err(format!( + "Field name '{}' used twice in message '{}'", + field.name, message.name + )); + } + field_names.insert(field.name.clone()); + + if let Type::Message(name) = &field.field_type { + if !self.type_map.contains_key(name) { + return Err(format!( + "Unknown type '{}' on field '{}' in message '{}'", + name, field.name, message.name + )); + } + } + } + Ok(()) + } + + fn type_check_interface(&self, interface: &Interface) -> Result<(), String> { + let mut method_names = HashSet::new(); + + for method in &interface.methods { + if method_names.contains(&method.name) { + return Err(format!( + "Method name '{}' used twice in interface '{}'", + method.name, interface.name + )); + } + method_names.insert(method.name.clone()); + + if let Some(name) = &method.request { + if !self.type_map.contains_key(name) { + return Err(format!( + "Unknown request type '{}' on method '{}' in interface '{}'", + name, method.name, interface.name + )); + } + } + if let Some(name) = &method.response { + if !self.type_map.contains_key(name) { + return Err(format!( + "Unknown response type '{}' on method '{}' in interface '{}'", + name, method.name, interface.name + )); + } + } + } + Ok(()) + } + + pub fn type_check(&mut self) -> Result<(), String> { + self.ensure_message_and_interface_names_unique()?; + for decl in &self.ast { + match decl { + Decl::Message(m) => self.type_check_message(m)?, + Decl::Interface(i) => self.type_check_interface(i)?, + _ => {} + } + } + Ok(()) + } } From d6833be0ad5d1567757c45225d4f81965c054aad Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 11 Jun 2024 15:11:56 -0700 Subject: [PATCH 080/186] [Yunq] Codegen example for yunq implementation. --- yunq/rust/Cargo.lock | 35 ++++++++++++++++++++++++++ yunq/rust/Cargo.toml | 1 + yunq/rust/src/codegen.rs | 53 ++++++++++++++++++++++++++++++++++++++++ yunq/rust/src/main.rs | 3 +++ yunq/rust/src/parser.rs | 35 +++++++++++++++++--------- 5 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 yunq/rust/src/codegen.rs diff --git a/yunq/rust/Cargo.lock b/yunq/rust/Cargo.lock index 7d49b6b..d5f212d 100644 --- a/yunq/rust/Cargo.lock +++ b/yunq/rust/Cargo.lock @@ -97,6 +97,28 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +[[package]] +name = "genco" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afac3cbb14db69ac9fef9cdb60d8a87e39a7a527f85a81a923436efa40ad42c6" +dependencies = [ + "genco-macros", + "relative-path", + "smallvec", +] + +[[package]] +name = "genco-macros" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "heck" version = "0.5.0" @@ -127,6 +149,18 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + [[package]] name = "strsim" version = "0.11.1" @@ -234,4 +268,5 @@ name = "yunq" version = "0.1.0" dependencies = [ "clap", + "genco", ] diff --git a/yunq/rust/Cargo.toml b/yunq/rust/Cargo.toml index 2f9645f..8c0c88a 100644 --- a/yunq/rust/Cargo.toml +++ b/yunq/rust/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] clap = { version = "4.5.7", features = ["derive"] } +genco = { version = "0.17.9" } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs new file mode 100644 index 0000000..cf07f24 --- /dev/null +++ b/yunq/rust/src/codegen.rs @@ -0,0 +1,53 @@ +use crate::parser::{Decl, Field, Interface, Message}; +use genco::fmt; +use genco::fmt::FmtWriter; +use genco::prelude::quote_fn; +use genco::prelude::quote_in; +use genco::prelude::rust; +use genco::prelude::FormatInto; +use genco::prelude::Rust; + +pub fn generate_field_def<'a>(field: &'a Field) -> impl FormatInto + 'a { + quote_fn!( + $(field.name.clone()): $(field.field_type.rust_type()), + ) +} + +pub fn generate_message_code<'a>(message: &'a Message) -> impl FormatInto + 'a { + quote_fn!( + struct $(&message.name) {$['\r'] + $(for field in &message.fields => + $[' ']$(generate_field_def(field))$['\r'] + )}$['\n'] + + impl $(&message.name) {$['\r'] + jjj + + }$['\n'] + ) +} + +pub fn generate_code(ast: &Vec) -> Result { + let mut tokens = rust::Tokens::new(); + + for decl in ast { + match decl { + Decl::Message(message) => quote_in!(tokens => $(generate_message_code(message))), + _ => {} + } + } + + let mut w = FmtWriter::new(String::new()); + + let fmt = fmt::Config::from_lang::() + .with_indentation(fmt::Indentation::Space(4)) + .with_newline("\n"); + + let config = rust::Config::default() + // Prettier imports and use. + .with_default_import(rust::ImportMode::Qualified); + + tokens.format_file(&mut w.as_formatter(&fmt), &config)?; + + Ok(w.into_inner()) +} diff --git a/yunq/rust/src/main.rs b/yunq/rust/src/main.rs index b5ae3a0..c9fc119 100644 --- a/yunq/rust/src/main.rs +++ b/yunq/rust/src/main.rs @@ -1,3 +1,4 @@ +mod codegen; mod lexer; mod parser; @@ -27,5 +28,7 @@ fn main() -> Result<(), Box> { println!("{:?}", decl); } + println!("{}", codegen::generate_code(ast_parser.ast())?); + Ok(()) } diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index 6dd3a18..85d7263 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -16,6 +16,19 @@ pub enum Type { Message(String), } +impl Type { + pub fn rust_type(&self) -> &str { + match self { + Type::U64 => "u64", + Type::I64 => "i64", + Type::String => "String", + Type::Bytes => "Vec", + Type::Capability => "u64", + Type::Message(s) => s, + } + } +} + impl Display for Type { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -50,23 +63,23 @@ impl TryFrom<&String> for Type { #[derive(Clone)] pub struct Field { - field_type: Type, - name: String, - number: u64, - repeated: bool, + pub field_type: Type, + pub name: String, + pub number: u64, + pub repeated: bool, } #[derive(Clone)] pub struct Message { - name: String, - fields: Vec, + pub name: String, + pub fields: Vec, } pub struct Method { - name: String, - number: u64, - request: Option, - response: Option, + pub name: String, + pub number: u64, + pub request: Option, + pub response: Option, } impl Debug for Method { @@ -303,7 +316,7 @@ impl<'a> Parser<'a> { Ok(()) } - pub fn ast(&'a mut self) -> &'a Vec { + pub fn ast(&'a self) -> &'a Vec { &self.ast } From 40a50e8d00059821d40264425da23570ada27d11 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 26 Jul 2024 14:44:05 -0700 Subject: [PATCH 081/186] Add entrypoint to rust mammoth. --- rust/lib/mammoth/Cargo.toml | 3 ++ rust/lib/mammoth/src/bindings.rs | 2 ++ rust/lib/mammoth/src/lib.rs | 62 ++++++++++++++++++++++++++++++-- rust/usr/testbed/src/main.rs | 10 ++++-- sys/yellowstone/hw/gpt.cpp | 5 +-- 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/rust/lib/mammoth/Cargo.toml b/rust/lib/mammoth/Cargo.toml index 5caf191..4577b56 100644 --- a/rust/lib/mammoth/Cargo.toml +++ b/rust/lib/mammoth/Cargo.toml @@ -3,6 +3,9 @@ name = "mammoth" version = "0.1.0" edition = "2021" +[lib] +name = "mammoth" + [dependencies] [build-dependencies] diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index 24556e8..31568ef 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -1,5 +1,7 @@ /* automatically generated by rust-bindgen 0.69.4 */ +pub type zcap = u64; + pub const _STDINT_H: u32 = 1; pub const _FEATURES_H: u32 = 1; pub const _ISOC95_SOURCE: u32 = 1; diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index be5f1e6..863d06d 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -8,13 +8,14 @@ use core::panic::PanicInfo; include!("bindings.rs"); -fn syscall(id: u64, req: &T) -> u64 { +pub fn syscall(id: u64, req: &T) -> u64 { unsafe { SysCall1(id, req as *const T as *const c_void) } } #[panic_handler] fn panic(_info: &PanicInfo) -> ! { - let req = ZProcessExitReq { code: 1 }; + // Internal error. + let req = ZProcessExitReq { code: 0x100 }; syscall(kZionProcessExit, &req); unreachable!() } @@ -26,3 +27,60 @@ pub fn debug(msg: &str) { }; syscall(kZionDebug, &req); } + +// From /zion/include/ztypes.h +const Z_INIT_SELF_PROC: u64 = 0x4000_0000; +const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; +const Z_INIT_ENDPOINT: u64 = 0x4100_0000; + +static mut SELF_PROC_CAP: zcap = 0; +static mut SELF_VMAS_CAP: zcap = 0; +static mut INIT_ENDPOINT: zcap = 0; + +pub fn parse_init_port(port_cap: zcap) { + loop { + let mut num_bytes: u64 = 8; + let mut init_sig: u64 = 0; + let mut caps: [u64; 1] = [0]; + let mut num_caps: u64 = 1; + + let req = ZPortPollReq { + port_cap, + num_bytes: &mut num_bytes as *mut u64, + data: &mut init_sig as *mut u64 as *mut c_void, + caps: &mut caps as *mut u64, + num_caps: &mut num_caps as *mut u64, + }; + let resp = syscall(kZionPortPoll, &req); + if resp != 0 { + break; + } + unsafe { + match init_sig { + Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], + Z_INIT_SELF_VMAS => SELF_VMAS_CAP = caps[0], + Z_INIT_ENDPOINT => INIT_ENDPOINT = caps[0], + _ => debug("Unknown Cap in Init"), + } + } + } +} + +#[macro_export] +macro_rules! define_entry { + () => { + #[no_mangle] + pub extern "C" fn _start(init_port: mammoth::zcap) -> ! { + extern "C" { + fn main() -> z_err_t; + } + mammoth::parse_init_port(init_port); + unsafe { + let err = main(); + let req = mammoth::ZProcessExitReq { code: err }; + mammoth::syscall(mammoth::kZionProcessExit, &req); + } + unreachable!() + } + }; +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index e06f819..53a54fe 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -2,9 +2,13 @@ #![no_main] use mammoth::debug; +use mammoth::define_entry; +use mammoth::z_err_t; + +define_entry!(); #[no_mangle] -pub extern "C" fn _start() -> ! { - debug("Test!"); - panic!() +pub extern "C" fn main() -> z_err_t { + debug("Testing!"); + 0 } diff --git a/sys/yellowstone/hw/gpt.cpp b/sys/yellowstone/hw/gpt.cpp index 43704cd..a7b2bb3 100644 --- a/sys/yellowstone/hw/gpt.cpp +++ b/sys/yellowstone/hw/gpt.cpp @@ -72,9 +72,10 @@ glcr::Status GptReader::ParsePartitionTables() { } MbrPartition* first_partition = reinterpret_cast(lba_1_and_2.vaddr() + 0x1BE); + if (first_partition->boot_indicator != 0) { - return glcr::FailedPrecondition(glcr::StrFormat( - "Boot indicator set: {}", first_partition->boot_indicator)); + // FIXME: This shouldn't be set but I can't figure out why it is. + dbgln("WARN: Boot indicator set: {}", first_partition->boot_indicator); } if (first_partition->os_type != 0xEE) { return glcr::FailedPrecondition( From 32ccbedb7a686038b35e8876c7dedadb26dd2c7d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 26 Jul 2024 15:20:21 -0700 Subject: [PATCH 082/186] Basic allocations in rust user-space. --- rust/.cargo/config.toml | 2 +- rust/Cargo.lock | 43 +++++++++++++++++++++++++++++++ rust/lib/mammoth/Cargo.toml | 1 + rust/lib/mammoth/src/lib.rs | 45 ++++++++++----------------------- rust/lib/mammoth/src/mem.rs | 31 +++++++++++++++++++++++ rust/lib/mammoth/src/syscall.rs | 31 +++++++++++++++++++++++ rust/usr/testbed/src/main.rs | 9 +++++-- 7 files changed, 127 insertions(+), 35 deletions(-) create mode 100644 rust/lib/mammoth/src/mem.rs create mode 100644 rust/lib/mammoth/src/syscall.rs diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml index b935b9b..220a396 100644 --- a/rust/.cargo/config.toml +++ b/rust/.cargo/config.toml @@ -1,6 +1,6 @@ [unstable] build-std-features = ["compiler-builtins-mem"] -build-std = ["core", "compiler_builtins"] +build-std = ["core", "compiler_builtins", "alloc"] [build] target = "x86_64-acadia-os.json" diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 9ccd58d..f0b3f19 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,9 +2,52 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "linked_list_allocator" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afa463f5405ee81cdb9cc2baf37e08ec7e4c8209442b5d72c04cfb2cd6e6286" +dependencies = [ + "spinning_top", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "mammoth" version = "0.1.0" +dependencies = [ + "linked_list_allocator", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "spinning_top" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +dependencies = [ + "lock_api", +] [[package]] name = "testbed" diff --git a/rust/lib/mammoth/Cargo.toml b/rust/lib/mammoth/Cargo.toml index 4577b56..f14c35d 100644 --- a/rust/lib/mammoth/Cargo.toml +++ b/rust/lib/mammoth/Cargo.toml @@ -7,5 +7,6 @@ edition = "2021" name = "mammoth" [dependencies] +linked_list_allocator = "0.10.5" [build-dependencies] diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 863d06d..7878923 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -4,54 +4,34 @@ #![allow(non_snake_case)] use core::ffi::c_void; -use core::panic::PanicInfo; -include!("bindings.rs"); - -pub fn syscall(id: u64, req: &T) -> u64 { - unsafe { SysCall1(id, req as *const T as *const c_void) } -} - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - // Internal error. - let req = ZProcessExitReq { code: 0x100 }; - syscall(kZionProcessExit, &req); - unreachable!() -} - -pub fn debug(msg: &str) { - let req = ZDebugReq { - message: msg.as_ptr() as *const i8, - size: msg.len() as u64, - }; - syscall(kZionDebug, &req); -} +pub mod mem; +pub mod syscall; // From /zion/include/ztypes.h const Z_INIT_SELF_PROC: u64 = 0x4000_0000; const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; const Z_INIT_ENDPOINT: u64 = 0x4100_0000; -static mut SELF_PROC_CAP: zcap = 0; -static mut SELF_VMAS_CAP: zcap = 0; -static mut INIT_ENDPOINT: zcap = 0; +static mut SELF_PROC_CAP: syscall::zcap = 0; +static mut SELF_VMAS_CAP: syscall::zcap = 0; +static mut INIT_ENDPOINT: syscall::zcap = 0; -pub fn parse_init_port(port_cap: zcap) { +pub fn parse_init_port(port_cap: syscall::zcap) { loop { let mut num_bytes: u64 = 8; let mut init_sig: u64 = 0; let mut caps: [u64; 1] = [0]; let mut num_caps: u64 = 1; - let req = ZPortPollReq { + let req = syscall::ZPortPollReq { port_cap, num_bytes: &mut num_bytes as *mut u64, data: &mut init_sig as *mut u64 as *mut c_void, caps: &mut caps as *mut u64, num_caps: &mut num_caps as *mut u64, }; - let resp = syscall(kZionPortPoll, &req); + let resp = syscall::syscall(syscall::kZionPortPoll, &req); if resp != 0 { break; } @@ -60,7 +40,7 @@ pub fn parse_init_port(port_cap: zcap) { Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], Z_INIT_SELF_VMAS => SELF_VMAS_CAP = caps[0], Z_INIT_ENDPOINT => INIT_ENDPOINT = caps[0], - _ => debug("Unknown Cap in Init"), + _ => syscall::debug("Unknown Cap in Init"), } } } @@ -70,15 +50,16 @@ pub fn parse_init_port(port_cap: zcap) { macro_rules! define_entry { () => { #[no_mangle] - pub extern "C" fn _start(init_port: mammoth::zcap) -> ! { + pub extern "C" fn _start(init_port: mammoth::syscall::zcap) -> ! { extern "C" { fn main() -> z_err_t; } mammoth::parse_init_port(init_port); + mammoth::mem::init_heap(); unsafe { let err = main(); - let req = mammoth::ZProcessExitReq { code: err }; - mammoth::syscall(mammoth::kZionProcessExit, &req); + let req = mammoth::syscall::ZProcessExitReq { code: err }; + mammoth::syscall::syscall(mammoth::syscall::kZionProcessExit, &req); } unreachable!() } diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs new file mode 100644 index 0000000..12b3832 --- /dev/null +++ b/rust/lib/mammoth/src/mem.rs @@ -0,0 +1,31 @@ +use crate::syscall; +use crate::SELF_VMAS_CAP; +use linked_list_allocator::LockedHeap; + +#[global_allocator] +static ALLOCATOR: LockedHeap = LockedHeap::empty(); + +pub fn init_heap() { + // 1 MiB + let size = 0x10_0000; + let mut vmmo_cap = 0; + let obj_req = syscall::ZMemoryObjectCreateReq { + size, + vmmo_cap: &mut vmmo_cap as *mut u64, + }; + syscall::checked_syscall(syscall::kZionMemoryObjectCreate, &obj_req); + + unsafe { + let mut vaddr: u64 = 0; + let vmas_req = syscall::ZAddressSpaceMapReq { + vmmo_cap, + vmas_cap: SELF_VMAS_CAP, + align: 0x2000, + vaddr: &mut vaddr as *mut u64, + vmas_offset: 0, + }; + + syscall::checked_syscall(syscall::kZionAddressSpaceMap, &vmas_req); + ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs new file mode 100644 index 0000000..030edc1 --- /dev/null +++ b/rust/lib/mammoth/src/syscall.rs @@ -0,0 +1,31 @@ +use core::ffi::c_void; +use core::panic::PanicInfo; + +include!("bindings.rs"); + +pub fn syscall(id: u64, req: &T) -> u64 { + unsafe { SysCall1(id, req as *const T as *const c_void) } +} + +pub fn checked_syscall(id: u64, req: &T) { + if syscall(id, req) != 0 { + debug("Bad syscall response."); + panic!(); + } +} + +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + // Internal error. + let req = ZProcessExitReq { code: 0x100 }; + syscall(kZionProcessExit, &req); + unreachable!() +} + +pub fn debug(msg: &str) { + let req = ZDebugReq { + message: msg.as_ptr() as *const i8, + size: msg.len() as u64, + }; + syscall(kZionDebug, &req); +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 53a54fe..3804002 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -1,14 +1,19 @@ #![no_std] #![no_main] -use mammoth::debug; +extern crate alloc; + +use alloc::boxed::Box; use mammoth::define_entry; -use mammoth::z_err_t; +use mammoth::syscall::debug; +use mammoth::syscall::z_err_t; define_entry!(); #[no_mangle] pub extern "C" fn main() -> z_err_t { debug("Testing!"); + let x = Box::new("Heap str"); + debug(&x); 0 } From e310eee4682162c4d102d09fd01ec1193ee6afa0 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 26 Jul 2024 15:57:10 -0700 Subject: [PATCH 083/186] Add method for formatting strings. --- rust/lib/mammoth/src/syscall.rs | 50 +++++++++++++++++++++++++++++++++ rust/usr/testbed/src/main.rs | 2 ++ 2 files changed, 52 insertions(+) diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 030edc1..768a85f 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -1,4 +1,9 @@ +extern crate alloc; + +use alloc::string::String; +use alloc::vec::Vec; use core::ffi::c_void; +use core::fmt; use core::panic::PanicInfo; include!("bindings.rs"); @@ -29,3 +34,48 @@ pub fn debug(msg: &str) { }; syscall(kZionDebug, &req); } + +pub struct Writer { + int_vec: Vec, +} + +impl Writer { + pub fn new() -> Self { + Self { + int_vec: Vec::new(), + } + } +} + +impl Into for Writer { + fn into(self) -> String { + String::from_utf8(self.int_vec).expect("Failed to convert") + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.bytes() { + self.int_vec.push(c); + } + fmt::Result::Ok(()) + } +} + +#[macro_export] +macro_rules! debug { + () => { + debug(""); + }; + ($fmt:literal) => { + debug($fmt); + }; + ($fmt:literal, $($val:expr),+) => {{ + use core::fmt::Write as _; + use alloc::string::String; + let mut w = mammoth::syscall::Writer::new(); + write!(&mut w, $fmt, $($val),*).expect("Failed to format"); + let s: String = w.into(); + debug(&s); + }}; +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 3804002..d771249 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -4,6 +4,7 @@ extern crate alloc; use alloc::boxed::Box; +use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; use mammoth::syscall::z_err_t; @@ -15,5 +16,6 @@ pub extern "C" fn main() -> z_err_t { debug("Testing!"); let x = Box::new("Heap str"); debug(&x); + debug!("Formatted {}", "string"); 0 } From 51d40f6db694cba162c0d19f6ffc48098862d0d3 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 26 Jul 2024 16:31:57 -0700 Subject: [PATCH 084/186] Return result type from syscall and format info on panic. --- rust/lib/mammoth/src/lib.rs | 4 +- rust/lib/mammoth/src/mem.rs | 9 +++- rust/lib/mammoth/src/syscall.rs | 84 +++++++++++++++++++++++++++++---- rust/usr/testbed/src/main.rs | 8 ++++ 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 7878923..d55a2a1 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -32,7 +32,7 @@ pub fn parse_init_port(port_cap: syscall::zcap) { num_caps: &mut num_caps as *mut u64, }; let resp = syscall::syscall(syscall::kZionPortPoll, &req); - if resp != 0 { + if let Err(_) = resp { break; } unsafe { @@ -59,7 +59,7 @@ macro_rules! define_entry { unsafe { let err = main(); let req = mammoth::syscall::ZProcessExitReq { code: err }; - mammoth::syscall::syscall(mammoth::syscall::kZionProcessExit, &req); + let _ = mammoth::syscall::syscall(mammoth::syscall::kZionProcessExit, &req); } unreachable!() } diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 12b3832..74bb1c4 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -5,6 +5,8 @@ use linked_list_allocator::LockedHeap; #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); +pub static mut CAN_ALLOC: bool = false; + pub fn init_heap() { // 1 MiB let size = 0x10_0000; @@ -13,7 +15,8 @@ pub fn init_heap() { size, vmmo_cap: &mut vmmo_cap as *mut u64, }; - syscall::checked_syscall(syscall::kZionMemoryObjectCreate, &obj_req); + syscall::syscall(syscall::kZionMemoryObjectCreate, &obj_req) + .expect("Failed to create memory object"); unsafe { let mut vaddr: u64 = 0; @@ -25,7 +28,9 @@ pub fn init_heap() { vmas_offset: 0, }; - syscall::checked_syscall(syscall::kZionAddressSpaceMap, &vmas_req); + syscall::syscall(syscall::kZionAddressSpaceMap, &vmas_req) + .expect("Failed to map memory object"); ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); + CAN_ALLOC = true; } } diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 768a85f..3c7b912 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -8,22 +8,84 @@ use core::panic::PanicInfo; include!("bindings.rs"); -pub fn syscall(id: u64, req: &T) -> u64 { - unsafe { SysCall1(id, req as *const T as *const c_void) } +pub enum ZError { + UNKNOWN = 0x0, + // First set of error codes generally indicate user errors. + INVALID_ARGUMENT = 0x1, + NOT_FOUND = 0x2, + PERMISSION_DENIED = 0x3, + NULL_PTR = 0x4, + EMPTY = 0x5, + ALREADY_EXISTS = 0x6, + BUFFER_SIZE = 0x7, + FAILED_PRECONDITION = 0x8, + + // Second set of error codes generally indicate service errors. + INTERNAL = 0x100, + UNIMPLEMENTED = 0x101, + EXHAUSTED = 0x102, + INVALID_RESPONSE = 0x103, + + // Kernel specific error codes (relating to capabilities). + CAP_NOT_FOUND = 0x1000, + CAP_WRONG_TYPE = 0x1001, + CAP_PERMISSION_DENIED = 0x1002, } -pub fn checked_syscall(id: u64, req: &T) { - if syscall(id, req) != 0 { - debug("Bad syscall response."); - panic!(); +impl From for ZError { + fn from(value: u64) -> Self { + match value { + 0x1 => ZError::INVALID_ARGUMENT, + 0x2 => ZError::NOT_FOUND, + 0x3 => ZError::PERMISSION_DENIED, + 0x4 => ZError::NULL_PTR, + 0x5 => ZError::EMPTY, + 0x6 => ZError::ALREADY_EXISTS, + 0x7 => ZError::BUFFER_SIZE, + 0x8 => ZError::FAILED_PRECONDITION, + + 0x100 => ZError::INTERNAL, + 0x101 => ZError::UNIMPLEMENTED, + 0x102 => ZError::EXHAUSTED, + 0x103 => ZError::INVALID_RESPONSE, + + 0x1000 => ZError::CAP_NOT_FOUND, + 0x1001 => ZError::CAP_WRONG_TYPE, + 0x1002 => ZError::CAP_PERMISSION_DENIED, + _ => ZError::UNKNOWN, + } } } +impl fmt::Debug for ZError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("ZError") + } +} + +#[must_use] +pub fn syscall(id: u64, req: &T) -> Result<(), ZError> { + unsafe { + let resp = SysCall1(id, req as *const T as *const c_void); + if resp != 0 { + return Err(ZError::from(resp)); + } + } + Ok(()) +} + #[panic_handler] -fn panic(_info: &PanicInfo) -> ! { +fn panic(info: &PanicInfo) -> ! { + unsafe { + if crate::mem::CAN_ALLOC { + crate::debug!("Panic occured: {}", info); + } else { + debug("Panic occured before heap initialized.") + } + } // Internal error. let req = ZProcessExitReq { code: 0x100 }; - syscall(kZionProcessExit, &req); + let _ = syscall(kZionProcessExit, &req); unreachable!() } @@ -32,7 +94,7 @@ pub fn debug(msg: &str) { message: msg.as_ptr() as *const i8, size: msg.len() as u64, }; - syscall(kZionDebug, &req); + syscall(kZionDebug, &req).expect("Failed to write"); } pub struct Writer { @@ -73,7 +135,9 @@ macro_rules! debug { ($fmt:literal, $($val:expr),+) => {{ use core::fmt::Write as _; use alloc::string::String; - let mut w = mammoth::syscall::Writer::new(); + // TODO: Find a way to do this so we don't have to import writer. + // We can't fully qualify this if we want to use it in this crate. + let mut w = Writer::new(); write!(&mut w, $fmt, $($val),*).expect("Failed to format"); let s: String = w.into(); debug(&s); diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index d771249..0452781 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -8,6 +8,7 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; use mammoth::syscall::z_err_t; +use mammoth::syscall::Writer; define_entry!(); @@ -17,5 +18,12 @@ pub extern "C" fn main() -> z_err_t { let x = Box::new("Heap str"); debug(&x); debug!("Formatted {}", "string"); + let mut vmmo_cap: u64 = 0; + let obj_req = mammoth::syscall::ZMemoryObjectCreateReq { + size: 0, + vmmo_cap: &mut vmmo_cap as *mut u64, + }; + mammoth::syscall::syscall(mammoth::syscall::kZionMemoryObjectCreate, &obj_req) + .expect("Failed to create memory object"); 0 } From 3eea4d811aa7a052c2d9e934e0ec147ef3c95d2a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 26 Jul 2024 23:36:07 -0700 Subject: [PATCH 085/186] Example yunq implementation for one Yellowstone endpoint. --- rust/Cargo.lock | 8 +++ rust/Cargo.toml | 2 +- rust/lib/mammoth/src/lib.rs | 2 +- rust/lib/mammoth/src/syscall.rs | 13 +++- rust/lib/yunq/Cargo.toml | 7 ++ rust/lib/yunq/src/buffer.rs | 60 +++++++++++++++++ rust/lib/yunq/src/client.rs | 60 +++++++++++++++++ rust/lib/yunq/src/lib.rs | 113 ++++++++++++++++++++++++++++++++ rust/lib/yunq/src/message.rs | 23 +++++++ rust/usr/testbed/Cargo.toml | 1 + rust/usr/testbed/src/main.rs | 15 +++++ 11 files changed, 301 insertions(+), 3 deletions(-) create mode 100644 rust/lib/yunq/Cargo.toml create mode 100644 rust/lib/yunq/src/buffer.rs create mode 100644 rust/lib/yunq/src/client.rs create mode 100644 rust/lib/yunq/src/lib.rs create mode 100644 rust/lib/yunq/src/message.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f0b3f19..85502d3 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -52,6 +52,14 @@ dependencies = [ [[package]] name = "testbed" version = "0.1.0" +dependencies = [ + "mammoth", + "yunq", +] + +[[package]] +name = "yunq" +version = "0.1.0" dependencies = [ "mammoth", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b1ec6be..0eb17a7 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "lib/mammoth", "usr/testbed", + "lib/mammoth", "lib/yunq", "usr/testbed", ] # the profile used for `cargo build` diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index d55a2a1..3d8b7da 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -15,7 +15,7 @@ const Z_INIT_ENDPOINT: u64 = 0x4100_0000; static mut SELF_PROC_CAP: syscall::zcap = 0; static mut SELF_VMAS_CAP: syscall::zcap = 0; -static mut INIT_ENDPOINT: syscall::zcap = 0; +pub static mut INIT_ENDPOINT: syscall::zcap = 0; pub fn parse_init_port(port_cap: syscall::zcap) { loop { diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 3c7b912..9f16f13 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -59,7 +59,18 @@ impl From for ZError { impl fmt::Debug for ZError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("ZError") + let str = match self { + ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT", + ZError::BUFFER_SIZE => "BUFFER_SIZE", + ZError::INTERNAL => "INTERNAL", + ZError::UNIMPLEMENTED => "UNIMPLEMENTED", + ZError::INVALID_RESPONSE => "INVALID_RESPONSE", + ZError::CAP_NOT_FOUND => "CAP_NOT_FOUND", + ZError::CAP_WRONG_TYPE => "CAP_WRONG_TYPE", + ZError::CAP_PERMISSION_DENIED => "CAP_PERMISSION_DENIED", + _ => "ZError", + }; + f.write_str(str) } } diff --git a/rust/lib/yunq/Cargo.toml b/rust/lib/yunq/Cargo.toml new file mode 100644 index 0000000..cdb0249 --- /dev/null +++ b/rust/lib/yunq/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "yunq" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = {path = "../mammoth"} diff --git a/rust/lib/yunq/src/buffer.rs b/rust/lib/yunq/src/buffer.rs new file mode 100644 index 0000000..a070901 --- /dev/null +++ b/rust/lib/yunq/src/buffer.rs @@ -0,0 +1,60 @@ +use alloc::boxed::Box; +use mammoth::syscall::ZError; + +pub struct ByteBuffer { + buffer: Box<[u8; N]>, +} + +impl ByteBuffer { + pub fn new() -> Self { + Self { + buffer: Box::new([0; N]), + } + } + pub fn size(&self) -> u64 { + N as u64 + } + + pub fn raw_ptr(&self) -> *const u8 { + self.buffer.as_ptr() + } + + pub fn mut_ptr(&mut self) -> *mut u8 { + self.buffer.as_mut_ptr() + } + + pub fn write_at(&mut self, offset: usize, obj: T) -> Result<(), ZError> { + if (size_of::() + offset) > N { + return Err(ZError::BUFFER_SIZE); + } + unsafe { + *(self.buffer[offset..].as_mut_ptr() as *mut T) = obj; + } + Ok(()) + } + + pub fn write_str_at(&mut self, offset: usize, s: &str) -> Result<(), ZError> { + if (s.len() + offset) > N { + return Err(ZError::BUFFER_SIZE); + } + for i in 0..s.len() { + self.buffer[offset + i] = s.as_bytes()[i]; + } + Ok(()) + } + + pub fn at(&self, offset: usize) -> Result { + if (size_of::() + offset) > N { + return Err(ZError::BUFFER_SIZE); + } + unsafe { Ok(*(self.buffer[offset..].as_ptr() as *const T)) } + } + + pub fn str_at(&self, offset: usize, len: usize) -> Result<&str, ZError> { + if (len + offset) > N { + return Err(ZError::BUFFER_SIZE); + } + Ok(alloc::str::from_utf8(&self.buffer[offset..offset + len]) + .map_err(|_| ZError::INVALID_ARGUMENT)?) + } +} diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs new file mode 100644 index 0000000..51795ed --- /dev/null +++ b/rust/lib/yunq/src/client.rs @@ -0,0 +1,60 @@ +use crate::buffer::ByteBuffer; +use crate::message::YunqMessage; +use alloc::vec::Vec; +use core::ffi::c_void; +use mammoth::syscall::z_cap_t; +use mammoth::syscall::ZError; + +const SENTINEL: u32 = 0xBEEFDEAD; + +pub fn call_endpoint( + req: &Req, + byte_buffer: &mut ByteBuffer, + endpoint_cap: z_cap_t, +) -> Result { + byte_buffer.write_at(0, SENTINEL)?; + byte_buffer.write_at(8, 1 as u64)?; + + let mut cap_buffer = Vec::new(); + + let length = req.serialize(byte_buffer, 16, &mut cap_buffer)?; + + byte_buffer.write_at(4, (16 + length) as u32)?; + + let mut reply_port_cap: u64 = 0; + let send_req = mammoth::syscall::ZEndpointSendReq { + caps: cap_buffer.as_ptr(), + num_caps: cap_buffer.len() as u64, + endpoint_cap, + data: byte_buffer.raw_ptr() as *const c_void, + num_bytes: 16 + length as u64, + reply_port_cap: &mut reply_port_cap as *mut z_cap_t, + }; + + mammoth::syscall::syscall(mammoth::syscall::kZionEndpointSend, &send_req)?; + // FIXME: Add a way to zero out the byte buffer. + + let mut buffer_size = byte_buffer.size(); + let mut num_caps: u64 = 10; + cap_buffer = vec![0; num_caps as usize]; + let recv_req = mammoth::syscall::ZReplyPortRecvReq { + reply_port_cap, + caps: cap_buffer.as_mut_ptr(), + num_caps: &mut num_caps as *mut u64, + data: byte_buffer.mut_ptr() as *mut c_void, + num_bytes: &mut buffer_size as *mut u64, + }; + + mammoth::syscall::syscall(mammoth::syscall::kZionReplyPortRecv, &recv_req)?; + + if byte_buffer.at::(0)? != SENTINEL { + return Err(ZError::INVALID_RESPONSE); + } + + let resp_code: u64 = byte_buffer.at(8)?; + if resp_code != 0 { + return Err(ZError::from(resp_code)); + } + + Ok(Resp::parse(&byte_buffer, 16, &cap_buffer)?) +} diff --git a/rust/lib/yunq/src/lib.rs b/rust/lib/yunq/src/lib.rs new file mode 100644 index 0000000..900cfd7 --- /dev/null +++ b/rust/lib/yunq/src/lib.rs @@ -0,0 +1,113 @@ +#![no_std] + +#[macro_use] +extern crate alloc; + +mod buffer; +mod client; +mod message; + +use alloc::string::String; +use alloc::vec::Vec; +pub use buffer::ByteBuffer; +use mammoth::syscall::z_cap_t; +use mammoth::syscall::ZError; +pub use message::YunqMessage; + +const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 + +pub struct GetEndpointRequest { + pub endpoint_name: String, +} + +impl YunqMessage for GetEndpointRequest { + fn serialize( + &self, + buf: &mut buffer::ByteBuffer, + offset: usize, + _caps: &mut Vec, + ) -> Result { + let core_size: u32 = (MESSAGE_HEADER_SIZE + 8 * 1) as u32; + let mut next_extension = core_size; + + let endpoint_name_offset = next_extension; + let endpoint_name_length = self.endpoint_name.len() as u32; + + buf.write_str_at(offset + next_extension as usize, &self.endpoint_name)?; + next_extension += endpoint_name_length; + + buf.write_at(field_offset(offset, 0), endpoint_name_offset)?; + buf.write_at(field_offset(offset, 0) + 4, endpoint_name_length)?; + + buf.write_at(offset + 0, message::MESSAGE_IDENT)?; + buf.write_at(offset + 4, core_size)?; + buf.write_at(offset + 8, next_extension)?; + buf.write_at(offset + 12, 0 as u32)?; + Ok(next_extension as usize) + } + + fn parse( + _buf: &ByteBuffer, + _offset: usize, + _caps: &Vec, + ) -> Result + where + Self: Sized, + { + todo!() + } +} + +pub struct Endpoint { + pub endpoint: z_cap_t, +} + +fn field_offset(offset: usize, field_index: usize) -> usize { + offset + MESSAGE_HEADER_SIZE + (8 * field_index) +} + +impl YunqMessage for Endpoint { + fn parse( + buf: &ByteBuffer, + offset: usize, + caps: &Vec, + ) -> Result { + if buf.at::(offset + 0)? != message::MESSAGE_IDENT { + return Err(ZError::INVALID_ARGUMENT); + } + // TODO: Parse core size. + // TODO: Parse extension size. + // TODO: Check CRC32 + // TODO: Parse options. + + let endpoint_ptr = buf.at::(field_offset(offset, 0))?; + let endpoint = caps[endpoint_ptr as usize]; + Ok(Endpoint { endpoint }) + } + + fn serialize( + &self, + _buf: &mut buffer::ByteBuffer, + _offset: usize, + _caps: &mut Vec, + ) -> Result { + todo!() + } +} + +pub struct YellowstoneClient { + endpoint_cap: z_cap_t, + byte_buffer: ByteBuffer<0x1000>, +} + +impl YellowstoneClient { + pub fn new(endpoint_cap: z_cap_t) -> Self { + Self { + endpoint_cap, + byte_buffer: ByteBuffer::new(), + } + } + pub fn get_endpoint(&mut self, req: &GetEndpointRequest) -> Result { + client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + } +} diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs new file mode 100644 index 0000000..82b2c42 --- /dev/null +++ b/rust/lib/yunq/src/message.rs @@ -0,0 +1,23 @@ +use crate::buffer::ByteBuffer; +use alloc::vec::Vec; +use mammoth::syscall::z_cap_t; +use mammoth::syscall::ZError; + +pub const MESSAGE_IDENT: u32 = 0x33441122; + +pub trait YunqMessage { + fn parse( + buf: &ByteBuffer, + offset: usize, + caps: &Vec, + ) -> Result + where + Self: Sized; + + fn serialize( + &self, + buf: &mut ByteBuffer, + offset: usize, + caps: &mut Vec, + ) -> Result; +} diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml index 999e3eb..65e5146 100644 --- a/rust/usr/testbed/Cargo.toml +++ b/rust/usr/testbed/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } +yunq = { path = "../../lib/yunq" } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 0452781..ab46cf9 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -4,6 +4,7 @@ extern crate alloc; use alloc::boxed::Box; +use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; @@ -25,5 +26,19 @@ pub extern "C" fn main() -> z_err_t { }; mammoth::syscall::syscall(mammoth::syscall::kZionMemoryObjectCreate, &obj_req) .expect("Failed to create memory object"); + + let mut yellowstone; + unsafe { + yellowstone = yunq::YellowstoneClient::new(mammoth::INIT_ENDPOINT); + } + + let endpoint = yellowstone + .get_endpoint(&yunq::GetEndpointRequest { + endpoint_name: "denali".to_string(), + }) + .expect("Failed to get endpoint"); + + debug!("Got endpoint w/ cap: {:#x}", endpoint.endpoint); + 0 } From ccd13fecf1f6302d365012b7fe334e18bca0d87b Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 27 Jul 2024 08:36:56 -0700 Subject: [PATCH 086/186] Use in macro. --- rust/lib/mammoth/src/syscall.rs | 4 +--- rust/usr/testbed/src/main.rs | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 9f16f13..ec8fe9d 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -146,9 +146,7 @@ macro_rules! debug { ($fmt:literal, $($val:expr),+) => {{ use core::fmt::Write as _; use alloc::string::String; - // TODO: Find a way to do this so we don't have to import writer. - // We can't fully qualify this if we want to use it in this crate. - let mut w = Writer::new(); + let mut w = $crate::syscall::Writer::new(); write!(&mut w, $fmt, $($val),*).expect("Failed to format"); let s: String = w.into(); debug(&s); diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index ab46cf9..ce34571 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -9,7 +9,6 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; use mammoth::syscall::z_err_t; -use mammoth::syscall::Writer; define_entry!(); From 8f35d38e937c086ea717c100e1ebdabaf2d85afe Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 27 Jul 2024 18:30:17 -0700 Subject: [PATCH 087/186] Add macros to derive message serializations. --- rust/Cargo.lock | 54 +++++++++++ rust/Cargo.toml | 2 +- rust/lib/yellowstone/Cargo.toml | 10 ++ rust/lib/yellowstone/src/lib.rs | 38 ++++++++ rust/lib/yunq-derive/Cargo.toml | 12 +++ rust/lib/yunq-derive/src/lib.rs | 156 ++++++++++++++++++++++++++++++++ rust/lib/yunq/Cargo.toml | 1 + rust/lib/yunq/src/lib.rs | 106 +--------------------- rust/lib/yunq/src/message.rs | 5 + rust/usr/testbed/Cargo.toml | 2 +- rust/usr/testbed/src/main.rs | 6 +- 11 files changed, 284 insertions(+), 108 deletions(-) create mode 100644 rust/lib/yellowstone/Cargo.toml create mode 100644 rust/lib/yellowstone/src/lib.rs create mode 100644 rust/lib/yunq-derive/Cargo.toml create mode 100644 rust/lib/yunq-derive/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 85502d3..52c6fef 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -34,6 +34,24 @@ dependencies = [ "linked_list_allocator", ] +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -49,12 +67,38 @@ dependencies = [ "lock_api", ] +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "testbed" version = "0.1.0" +dependencies = [ + "mammoth", + "yellowstone", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "yellowstone" +version = "0.1.0" dependencies = [ "mammoth", "yunq", + "yunq-derive", ] [[package]] @@ -62,4 +106,14 @@ name = "yunq" version = "0.1.0" dependencies = [ "mammoth", + "yunq-derive", +] + +[[package]] +name = "yunq-derive" +version = "0.1.0" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0eb17a7..f35d122 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "lib/mammoth", "lib/yunq", "usr/testbed", + "lib/mammoth", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "usr/testbed", ] # the profile used for `cargo build` diff --git a/rust/lib/yellowstone/Cargo.toml b/rust/lib/yellowstone/Cargo.toml new file mode 100644 index 0000000..c464a9e --- /dev/null +++ b/rust/lib/yellowstone/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "yellowstone" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth" } +yunq = {path = "../yunq"} +yunq-derive = {path = "../yunq-derive"} + diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs new file mode 100644 index 0000000..d5e025f --- /dev/null +++ b/rust/lib/yellowstone/src/lib.rs @@ -0,0 +1,38 @@ +#![no_std] + +extern crate alloc; + +use alloc::string::String; +use alloc::string::ToString; +use mammoth::syscall::z_cap_t; +use mammoth::syscall::ZError; +use yunq::ByteBuffer; +use yunq::YunqMessage; +use yunq_derive::YunqMessage; + +#[derive(YunqMessage)] +pub struct GetEndpointRequest { + pub endpoint_name: String, +} + +#[derive(YunqMessage)] +pub struct Endpoint { + pub endpoint: z_cap_t, +} + +pub struct YellowstoneClient { + endpoint_cap: z_cap_t, + byte_buffer: ByteBuffer<0x1000>, +} + +impl YellowstoneClient { + pub fn new(endpoint_cap: z_cap_t) -> Self { + Self { + endpoint_cap, + byte_buffer: ByteBuffer::new(), + } + } + pub fn get_endpoint(&mut self, req: &GetEndpointRequest) -> Result { + yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + } +} diff --git a/rust/lib/yunq-derive/Cargo.toml b/rust/lib/yunq-derive/Cargo.toml new file mode 100644 index 0000000..c17a506 --- /dev/null +++ b/rust/lib/yunq-derive/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "yunq-derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "1.0", features = ["full", "extra-traits", "printing"] } diff --git a/rust/lib/yunq-derive/src/lib.rs b/rust/lib/yunq-derive/src/lib.rs new file mode 100644 index 0000000..8311244 --- /dev/null +++ b/rust/lib/yunq-derive/src/lib.rs @@ -0,0 +1,156 @@ +use proc_macro::{self, TokenStream}; +use quote::{quote, ToTokens}; +use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident, Path, Type, TypePath}; + +fn serialize_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStream { + if path.is_ident("String") { + quote! { + { + let str_offset = next_extension; + let str_length = self.#name.len() as u32; + + buf.write_str_at(offset + next_extension as usize, &self.#name)?; + next_extension += str_length; + + buf.write_at(yunq::message::field_offset(offset, #ind), str_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, str_length)?; + } + + } + } else if path.is_ident("z_cap_t") { + quote! { + { + let cap_ind = caps.len(); + caps.push(self.#name); + + buf.write_at(yunq::message::field_offset(offset, #ind), cap_ind as u64)?; + } + } + } else { + panic!( + "Serialization not implemented for: {}", + path.to_token_stream() + ) + } +} + +fn parse_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStream { + if path.is_ident("String") { + quote! { + let #name = { + let str_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; + let str_length = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; + + buf.str_at(offset + str_offset as usize, str_length as usize)?.to_string() + }; + } + } else if path.is_ident("z_cap_t") { + quote! { + let #name = { + let cap_ind = buf.at::(yunq::message::field_offset(offset, #ind))?; + caps[cap_ind as usize] + }; + } + } else { + panic!("Parsing not implemented for: {}", path.into_token_stream()); + } +} + +fn field_names(name: &Ident, _ind: usize, _path: &Path) -> proc_macro2::TokenStream { + quote! { #name } +} + +fn apply_to_struct_fields(input: &DeriveInput, func: fn(&Ident, usize, &Path) -> T) -> Vec { + match &input.data { + Data::Struct(DataStruct { + fields: Fields::Named(fields), + .. + }) => fields + .named + .iter() + .enumerate() + .map(|(ind, field)| match &field.ty { + Type::Path(TypePath { path, .. }) => { + func(&field.ident.as_ref().unwrap(), ind, path) + } + _ => { + panic!("Unrecognized type: {:?}", field) + } + }) + .collect(), + _ => { + panic!("Unrecognized input (Expected Struct): {:?}", input.data) + } + } +} + +#[proc_macro_derive(YunqMessage)] +pub fn derive_client(input_tokens: TokenStream) -> TokenStream { + let input: DeriveInput = parse_macro_input!(input_tokens); + let ident = input.ident.clone(); + + let prelude = quote! { + impl YunqMessage for #ident + }; + + let num_fields = apply_to_struct_fields(&input, |_, _, _| ()).len(); + + let serializers = apply_to_struct_fields(&input, serialize_field); + let serialize = quote! { + fn serialize( + &self, + buf: &mut yunq::ByteBuffer, + offset: usize, + caps: &mut alloc::vec::Vec, + ) -> Result { + let num_fields = #num_fields; + let core_size: u32 = (yunq::message::MESSAGE_HEADER_SIZE + 8 * num_fields) as u32; + let mut next_extension = core_size; + + #(#serializers)* + + buf.write_at(offset + 0, yunq::message::MESSAGE_IDENT)?; + buf.write_at(offset + 4, core_size)?; + buf.write_at(offset + 8, next_extension)?; + buf.write_at(offset + 12, 0 as u32)?; + Ok(next_extension as usize) + } + }; + + let field_names = apply_to_struct_fields(&input, field_names); + let parsers = apply_to_struct_fields(&input, parse_field); + let parse = quote! { + fn parse( + buf: &yunq::ByteBuffer, + offset: usize, + caps: &alloc::vec::Vec, + ) -> Result + where + Self: Sized, + { + if buf.at::(offset + 0)? != yunq::message::MESSAGE_IDENT { + return Err(ZError::INVALID_ARGUMENT); + } + // TODO: Parse core size. + // TODO: Parse extension size. + // TODO: Check CRC32 + // TODO: Parse options. + + #(#parsers)* + + Ok(Self { + #(#field_names),* + }) + + } + }; + + let output = quote! { + #prelude { + #serialize + + #parse + } + }; + output.into() +} diff --git a/rust/lib/yunq/Cargo.toml b/rust/lib/yunq/Cargo.toml index cdb0249..f442771 100644 --- a/rust/lib/yunq/Cargo.toml +++ b/rust/lib/yunq/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] mammoth = {path = "../mammoth"} +yunq-derive = {path = "../yunq-derive"} diff --git a/rust/lib/yunq/src/lib.rs b/rust/lib/yunq/src/lib.rs index 900cfd7..515760b 100644 --- a/rust/lib/yunq/src/lib.rs +++ b/rust/lib/yunq/src/lib.rs @@ -4,110 +4,8 @@ extern crate alloc; mod buffer; -mod client; -mod message; +pub mod client; +pub mod message; -use alloc::string::String; -use alloc::vec::Vec; pub use buffer::ByteBuffer; -use mammoth::syscall::z_cap_t; -use mammoth::syscall::ZError; pub use message::YunqMessage; - -const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 - -pub struct GetEndpointRequest { - pub endpoint_name: String, -} - -impl YunqMessage for GetEndpointRequest { - fn serialize( - &self, - buf: &mut buffer::ByteBuffer, - offset: usize, - _caps: &mut Vec, - ) -> Result { - let core_size: u32 = (MESSAGE_HEADER_SIZE + 8 * 1) as u32; - let mut next_extension = core_size; - - let endpoint_name_offset = next_extension; - let endpoint_name_length = self.endpoint_name.len() as u32; - - buf.write_str_at(offset + next_extension as usize, &self.endpoint_name)?; - next_extension += endpoint_name_length; - - buf.write_at(field_offset(offset, 0), endpoint_name_offset)?; - buf.write_at(field_offset(offset, 0) + 4, endpoint_name_length)?; - - buf.write_at(offset + 0, message::MESSAGE_IDENT)?; - buf.write_at(offset + 4, core_size)?; - buf.write_at(offset + 8, next_extension)?; - buf.write_at(offset + 12, 0 as u32)?; - Ok(next_extension as usize) - } - - fn parse( - _buf: &ByteBuffer, - _offset: usize, - _caps: &Vec, - ) -> Result - where - Self: Sized, - { - todo!() - } -} - -pub struct Endpoint { - pub endpoint: z_cap_t, -} - -fn field_offset(offset: usize, field_index: usize) -> usize { - offset + MESSAGE_HEADER_SIZE + (8 * field_index) -} - -impl YunqMessage for Endpoint { - fn parse( - buf: &ByteBuffer, - offset: usize, - caps: &Vec, - ) -> Result { - if buf.at::(offset + 0)? != message::MESSAGE_IDENT { - return Err(ZError::INVALID_ARGUMENT); - } - // TODO: Parse core size. - // TODO: Parse extension size. - // TODO: Check CRC32 - // TODO: Parse options. - - let endpoint_ptr = buf.at::(field_offset(offset, 0))?; - let endpoint = caps[endpoint_ptr as usize]; - Ok(Endpoint { endpoint }) - } - - fn serialize( - &self, - _buf: &mut buffer::ByteBuffer, - _offset: usize, - _caps: &mut Vec, - ) -> Result { - todo!() - } -} - -pub struct YellowstoneClient { - endpoint_cap: z_cap_t, - byte_buffer: ByteBuffer<0x1000>, -} - -impl YellowstoneClient { - pub fn new(endpoint_cap: z_cap_t) -> Self { - Self { - endpoint_cap, - byte_buffer: ByteBuffer::new(), - } - } - pub fn get_endpoint(&mut self, req: &GetEndpointRequest) -> Result { - client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) - } -} diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 82b2c42..e114343 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -4,6 +4,11 @@ use mammoth::syscall::z_cap_t; use mammoth::syscall::ZError; pub const MESSAGE_IDENT: u32 = 0x33441122; +pub const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 + +pub fn field_offset(offset: usize, field_index: usize) -> usize { + offset + MESSAGE_HEADER_SIZE + (8 * field_index) +} pub trait YunqMessage { fn parse( diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml index 65e5146..66b00a9 100644 --- a/rust/usr/testbed/Cargo.toml +++ b/rust/usr/testbed/Cargo.toml @@ -5,4 +5,4 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -yunq = { path = "../../lib/yunq" } +yellowstone = { path = "../../lib/yellowstone" } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index ce34571..79f9e2e 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -9,6 +9,8 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; use mammoth::syscall::z_err_t; +use yellowstone::GetEndpointRequest; +use yellowstone::YellowstoneClient; define_entry!(); @@ -28,11 +30,11 @@ pub extern "C" fn main() -> z_err_t { let mut yellowstone; unsafe { - yellowstone = yunq::YellowstoneClient::new(mammoth::INIT_ENDPOINT); + yellowstone = YellowstoneClient::new(mammoth::INIT_ENDPOINT); } let endpoint = yellowstone - .get_endpoint(&yunq::GetEndpointRequest { + .get_endpoint(&GetEndpointRequest { endpoint_name: "denali".to_string(), }) .expect("Failed to get endpoint"); From 2cbf871d09c2db98b05be72ed509be8d825e30bc Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 27 Jul 2024 20:23:03 -0700 Subject: [PATCH 088/186] Add codegen for new rust yunq parser. --- rust/lib/yellowstone/src/lib.rs | 81 ++++++++++++++-- rust/lib/yunq-derive/src/lib.rs | 10 ++ rust/lib/yunq/src/message.rs | 24 +++++ yunq/rust/Cargo.lock | 59 ++++++------ yunq/rust/Cargo.toml | 6 +- yunq/rust/src/codegen.rs | 157 ++++++++++++++++++++++---------- yunq/rust/src/main.rs | 14 +-- yunq/rust/src/parser.rs | 6 +- 8 files changed, 261 insertions(+), 96 deletions(-) diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs index d5e025f..5e255b3 100644 --- a/rust/lib/yellowstone/src/lib.rs +++ b/rust/lib/yellowstone/src/lib.rs @@ -1,7 +1,5 @@ #![no_std] - extern crate alloc; - use alloc::string::String; use alloc::string::ToString; use mammoth::syscall::z_cap_t; @@ -9,22 +7,54 @@ use mammoth::syscall::ZError; use yunq::ByteBuffer; use yunq::YunqMessage; use yunq_derive::YunqMessage; - +#[derive(YunqMessage)] +pub struct RegisterEndpointRequest { + pub endpoint_name: String, + pub endpoint_capability: z_cap_t, +} #[derive(YunqMessage)] pub struct GetEndpointRequest { pub endpoint_name: String, } - #[derive(YunqMessage)] pub struct Endpoint { pub endpoint: z_cap_t, } - +#[derive(YunqMessage)] +pub struct AhciInfo { + pub ahci_region: z_cap_t, + pub region_length: u64, +} +#[derive(YunqMessage)] +pub struct XhciInfo { + pub xhci_region: z_cap_t, + pub region_length: u64, +} +#[derive(YunqMessage)] +pub struct FramebufferInfo { + pub address_phys: u64, + pub width: u64, + pub height: u64, + pub pitch: u64, + pub bpp: u64, + pub memory_model: u64, + pub red_mask_size: u64, + pub red_mask_shift: u64, + pub green_mask_size: u64, + pub green_mask_shift: u64, + pub blue_mask_size: u64, + pub blue_mask_shift: u64, +} +#[derive(YunqMessage)] +pub struct DenaliInfo { + pub denali_endpoint: z_cap_t, + pub device_id: u64, + pub lba_offset: u64, +} pub struct YellowstoneClient { endpoint_cap: z_cap_t, byte_buffer: ByteBuffer<0x1000>, } - impl YellowstoneClient { pub fn new(endpoint_cap: z_cap_t) -> Self { Self { @@ -32,7 +62,44 @@ impl YellowstoneClient { byte_buffer: ByteBuffer::new(), } } - pub fn get_endpoint(&mut self, req: &GetEndpointRequest) -> Result { + pub fn register_endpoint( + &mut self, + req: &RegisterEndpointRequest, + ) -> Result { yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) } + pub fn get_endpoint( + &mut self, + req: &GetEndpointRequest, + ) -> Result { + yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + } + pub fn get_ahci_info(&mut self) -> Result { + yunq::client::call_endpoint( + &yunq::message::Empty {}, + &mut self.byte_buffer, + self.endpoint_cap, + ) + } + pub fn get_xhci_info(&mut self) -> Result { + yunq::client::call_endpoint( + &yunq::message::Empty {}, + &mut self.byte_buffer, + self.endpoint_cap, + ) + } + pub fn get_framebuffer_info(&mut self) -> Result { + yunq::client::call_endpoint( + &yunq::message::Empty {}, + &mut self.byte_buffer, + self.endpoint_cap, + ) + } + pub fn get_denali(&mut self) -> Result { + yunq::client::call_endpoint( + &yunq::message::Empty {}, + &mut self.byte_buffer, + self.endpoint_cap, + ) + } } diff --git a/rust/lib/yunq-derive/src/lib.rs b/rust/lib/yunq-derive/src/lib.rs index 8311244..cf72f4a 100644 --- a/rust/lib/yunq-derive/src/lib.rs +++ b/rust/lib/yunq-derive/src/lib.rs @@ -26,6 +26,12 @@ fn serialize_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenS buf.write_at(yunq::message::field_offset(offset, #ind), cap_ind as u64)?; } } + } else if path.is_ident("u64") { + quote! { + { + buf.write_at(yunq::message::field_offset(offset, #ind), self.#name as u64)?; + } + } } else { panic!( "Serialization not implemented for: {}", @@ -51,6 +57,10 @@ fn parse_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStrea caps[cap_ind as usize] }; } + } else if path.is_ident("u64") { + quote! { + let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; + } } else { panic!("Parsing not implemented for: {}", path.into_token_stream()); } diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index e114343..3369cba 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -26,3 +26,27 @@ pub trait YunqMessage { caps: &mut Vec, ) -> Result; } + +pub struct Empty {} + +impl YunqMessage for Empty { + fn parse( + buf: &ByteBuffer, + offset: usize, + caps: &Vec, + ) -> Result + where + Self: Sized, + { + todo!() + } + + fn serialize( + &self, + buf: &mut ByteBuffer, + offset: usize, + caps: &mut Vec, + ) -> Result { + todo!() + } +} diff --git a/yunq/rust/Cargo.lock b/yunq/rust/Cargo.lock index d5f212d..145ddd8 100644 --- a/yunq/rust/Cargo.lock +++ b/yunq/rust/Cargo.lock @@ -98,25 +98,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] -name = "genco" -version = "0.17.9" +name = "convert_case" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afac3cbb14db69ac9fef9cdb60d8a87e39a7a527f85a81a923436efa40ad42c6" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" dependencies = [ - "genco-macros", - "relative-path", - "smallvec", -] - -[[package]] -name = "genco-macros" -version = "0.17.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "553630feadf7b76442b0849fd25fdf89b860d933623aec9693fed19af0400c78" -dependencies = [ - "proc-macro2", - "quote", - "syn", + "unicode-segmentation", ] [[package]] @@ -131,6 +118,16 @@ version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.85" @@ -149,18 +146,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "relative-path" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - [[package]] name = "strsim" version = "0.11.1" @@ -169,9 +154,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "syn" -version = "2.0.66" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", @@ -184,6 +169,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "utf8parse" version = "0.2.2" @@ -268,5 +259,9 @@ name = "yunq" version = "0.1.0" dependencies = [ "clap", - "genco", + "convert_case", + "prettyplease", + "proc-macro2", + "quote", + "syn", ] diff --git a/yunq/rust/Cargo.toml b/yunq/rust/Cargo.toml index 8c0c88a..2550596 100644 --- a/yunq/rust/Cargo.toml +++ b/yunq/rust/Cargo.toml @@ -5,4 +5,8 @@ edition = "2021" [dependencies] clap = { version = "4.5.7", features = ["derive"] } -genco = { version = "0.17.9" } +convert_case = "0.6.0" +prettyplease = "0.2.20" +proc-macro2 = { version = "1.0" } +quote = { version = "1.0" } +syn = "2.0.72" diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index cf07f24..2b2ca34 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -1,53 +1,116 @@ -use crate::parser::{Decl, Field, Interface, Message}; -use genco::fmt; -use genco::fmt::FmtWriter; -use genco::prelude::quote_fn; -use genco::prelude::quote_in; -use genco::prelude::rust; -use genco::prelude::FormatInto; -use genco::prelude::Rust; +use crate::parser::{Decl, Interface, Message, Method}; +use convert_case::{Case, Casing}; +use proc_macro2::Ident; +use proc_macro2::Span; +use proc_macro2::TokenStream; +use quote::quote; -pub fn generate_field_def<'a>(field: &'a Field) -> impl FormatInto + 'a { - quote_fn!( - $(field.name.clone()): $(field.field_type.rust_type()), - ) +fn ident(s: &str) -> Ident { + Ident::new(s, Span::call_site()) } -pub fn generate_message_code<'a>(message: &'a Message) -> impl FormatInto + 'a { - quote_fn!( - struct $(&message.name) {$['\r'] - $(for field in &message.fields => - $[' ']$(generate_field_def(field))$['\r'] - )}$['\n'] - - impl $(&message.name) {$['\r'] - jjj - - }$['\n'] - ) -} - -pub fn generate_code(ast: &Vec) -> Result { - let mut tokens = rust::Tokens::new(); - - for decl in ast { - match decl { - Decl::Message(message) => quote_in!(tokens => $(generate_message_code(message))), - _ => {} +fn generate_message(message: &Message) -> TokenStream { + let name = ident(&message.name); + let field_names = message.fields.iter().map(|f| ident(&f.name)); + let field_types = message + .fields + .iter() + .map(|f| Ident::new(f.field_type.rust_type(), Span::call_site())); + quote! { + #[derive(YunqMessage)] + pub struct #name { + #(pub #field_names: #field_types),* } + } - - let mut w = FmtWriter::new(String::new()); - - let fmt = fmt::Config::from_lang::() - .with_indentation(fmt::Indentation::Space(4)) - .with_newline("\n"); - - let config = rust::Config::default() - // Prettier imports and use. - .with_default_import(rust::ImportMode::Qualified); - - tokens.format_file(&mut w.as_formatter(&fmt), &config)?; - - Ok(w.into_inner()) +} + +fn generate_method(method: &Method) -> TokenStream { + let name = ident(&method.name.to_case(Case::Snake)); + let maybe_req = method.request.clone().map(|r| ident(&r)); + let maybe_resp = method.response.clone().map(|r| ident(&r)); + match (maybe_req, maybe_resp) { + (Some(req), Some(resp)) => quote! { + pub fn #name (&mut self, req: & #req) -> Result<#resp, ZError> { + yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + } + }, + (Some(req), None) => quote! { + pub fn #name (&mut self, req: & #req) -> Result { + yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + } + }, + (None, Some(resp)) => quote! { + pub fn #name (&mut self) -> Result<#resp, ZError> { + yunq::client::call_endpoint(&yunq::message::Empty{}, &mut self.byte_buffer, self.endpoint_cap) + } + }, + _ => unreachable!(), + } +} + +fn generate_interface(interface: &Interface) -> TokenStream { + let client_name = interface.name.clone() + "Client"; + let name = ident(&client_name); + let methods = interface.methods.iter().map(|m| generate_method(&m)); + quote! { + pub struct #name { + endpoint_cap: z_cap_t, + byte_buffer: ByteBuffer<0x1000>, + } + + impl #name { + pub fn new(endpoint_cap: z_cap_t) -> Self { + Self { + endpoint_cap, + byte_buffer: ByteBuffer::new(), + } + } + #(#methods)* + } + + } +} + +pub fn generate_code(ast: &Vec) -> String { + let prelude = quote! { + #![no_std] + + extern crate alloc; + + use alloc::string::String; + use alloc::string::ToString; + use mammoth::syscall::z_cap_t; + use mammoth::syscall::ZError; + use yunq::ByteBuffer; + use yunq::YunqMessage; + use yunq_derive::YunqMessage; + }; + + let message_decls = ast + .iter() + .filter_map(|decl| match decl { + Decl::Message(m) => Some(m), + _ => None, + }) + .map(|message| generate_message(&message)); + + let interface_decls = ast + .iter() + .filter_map(|decl| match decl { + Decl::Interface(i) => Some(i), + _ => None, + }) + .map(|interface| generate_interface(&interface)); + + let output = quote! { + #prelude + + #(#message_decls)* + + #(#interface_decls)* + } + .to_string(); + + prettyplease::unparse(&syn::parse_file(&output).unwrap()) } diff --git a/yunq/rust/src/main.rs b/yunq/rust/src/main.rs index c9fc119..21ece22 100644 --- a/yunq/rust/src/main.rs +++ b/yunq/rust/src/main.rs @@ -3,7 +3,7 @@ mod lexer; mod parser; use std::error::Error; -use std::fs::read_to_string; +use std::fs; use clap::Parser; @@ -13,22 +13,24 @@ struct Args { // The .yunq file to parse #[arg(short, long)] input_path: String, + + // The .rs file to generate + #[arg(short, long)] + output_path: String, } fn main() -> Result<(), Box> { let args = Args::parse(); - let input = read_to_string(args.input_path)?; + let input = fs::read_to_string(args.input_path)?; let tokens = lexer::lex_input(&input)?; let mut ast_parser = parser::Parser::new(&tokens); ast_parser.parse_ast()?; ast_parser.type_check()?; - for decl in ast_parser.ast() { - println!("{:?}", decl); - } + let code = codegen::generate_code(ast_parser.ast()); - println!("{}", codegen::generate_code(ast_parser.ast())?); + fs::write(args.output_path, code)?; Ok(()) } diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index 85d7263..f116fb9 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -23,7 +23,7 @@ impl Type { Type::I64 => "i64", Type::String => "String", Type::Bytes => "Vec", - Type::Capability => "u64", + Type::Capability => "z_cap_t", Type::Message(s) => s, } } @@ -102,8 +102,8 @@ impl Debug for Method { } pub struct Interface { - name: String, - methods: Vec, + pub name: String, + pub methods: Vec, } pub enum Decl { From 370ba9ae40a064ebca7886958e137469d1c14119 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 14:32:50 -0700 Subject: [PATCH 089/186] Hacky auto build for rust yunq. --- rust/lib/yellowstone/build.rs | 18 ++++++ rust/lib/yellowstone/src/lib.rs | 108 ++------------------------------ yunq/rust/src/codegen.rs | 1 - 3 files changed, 22 insertions(+), 105 deletions(-) create mode 100644 rust/lib/yellowstone/build.rs diff --git a/rust/lib/yellowstone/build.rs b/rust/lib/yellowstone/build.rs new file mode 100644 index 0000000..a072a3a --- /dev/null +++ b/rust/lib/yellowstone/build.rs @@ -0,0 +1,18 @@ +use std::process::Command; + +fn main() { + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + + let status = Command::new("cargo") + .current_dir("../../../yunq/rust") + .arg("run") + .arg("--") + .arg("--input-path") + .arg("../../sys/yellowstone/lib/yellowstone/yellowstone.yunq") + .arg("--output-path") + .arg(out) + .status() + .expect("Failed to start execution"); + + assert!(status.success()); +} diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs index 5e255b3..3cec9d6 100644 --- a/rust/lib/yellowstone/src/lib.rs +++ b/rust/lib/yellowstone/src/lib.rs @@ -1,105 +1,5 @@ #![no_std] -extern crate alloc; -use alloc::string::String; -use alloc::string::ToString; -use mammoth::syscall::z_cap_t; -use mammoth::syscall::ZError; -use yunq::ByteBuffer; -use yunq::YunqMessage; -use yunq_derive::YunqMessage; -#[derive(YunqMessage)] -pub struct RegisterEndpointRequest { - pub endpoint_name: String, - pub endpoint_capability: z_cap_t, -} -#[derive(YunqMessage)] -pub struct GetEndpointRequest { - pub endpoint_name: String, -} -#[derive(YunqMessage)] -pub struct Endpoint { - pub endpoint: z_cap_t, -} -#[derive(YunqMessage)] -pub struct AhciInfo { - pub ahci_region: z_cap_t, - pub region_length: u64, -} -#[derive(YunqMessage)] -pub struct XhciInfo { - pub xhci_region: z_cap_t, - pub region_length: u64, -} -#[derive(YunqMessage)] -pub struct FramebufferInfo { - pub address_phys: u64, - pub width: u64, - pub height: u64, - pub pitch: u64, - pub bpp: u64, - pub memory_model: u64, - pub red_mask_size: u64, - pub red_mask_shift: u64, - pub green_mask_size: u64, - pub green_mask_shift: u64, - pub blue_mask_size: u64, - pub blue_mask_shift: u64, -} -#[derive(YunqMessage)] -pub struct DenaliInfo { - pub denali_endpoint: z_cap_t, - pub device_id: u64, - pub lba_offset: u64, -} -pub struct YellowstoneClient { - endpoint_cap: z_cap_t, - byte_buffer: ByteBuffer<0x1000>, -} -impl YellowstoneClient { - pub fn new(endpoint_cap: z_cap_t) -> Self { - Self { - endpoint_cap, - byte_buffer: ByteBuffer::new(), - } - } - pub fn register_endpoint( - &mut self, - req: &RegisterEndpointRequest, - ) -> Result { - yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) - } - pub fn get_endpoint( - &mut self, - req: &GetEndpointRequest, - ) -> Result { - yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) - } - pub fn get_ahci_info(&mut self) -> Result { - yunq::client::call_endpoint( - &yunq::message::Empty {}, - &mut self.byte_buffer, - self.endpoint_cap, - ) - } - pub fn get_xhci_info(&mut self) -> Result { - yunq::client::call_endpoint( - &yunq::message::Empty {}, - &mut self.byte_buffer, - self.endpoint_cap, - ) - } - pub fn get_framebuffer_info(&mut self) -> Result { - yunq::client::call_endpoint( - &yunq::message::Empty {}, - &mut self.byte_buffer, - self.endpoint_cap, - ) - } - pub fn get_denali(&mut self) -> Result { - yunq::client::call_endpoint( - &yunq::message::Empty {}, - &mut self.byte_buffer, - self.endpoint_cap, - ) - } -} + +use core::include; + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 2b2ca34..0051047 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -74,7 +74,6 @@ fn generate_interface(interface: &Interface) -> TokenStream { pub fn generate_code(ast: &Vec) -> String { let prelude = quote! { - #![no_std] extern crate alloc; From 1e073d50607cff3518628b21cecee9d142ef8e3b Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 18:08:34 -0700 Subject: [PATCH 090/186] Split yunq compliation to library and use it in build process. --- rust/Cargo.lock | 50 ++++++++++++++++++++++++++++++++- rust/lib/yellowstone/Cargo.toml | 3 ++ rust/lib/yellowstone/build.rs | 24 +++++++--------- yunq/rust/Cargo.lock | 2 +- yunq/rust/Cargo.toml | 12 ++++++-- yunq/rust/src/lib.rs | 15 ++++++++++ yunq/rust/src/main.rs | 11 +------- 7 files changed, 89 insertions(+), 28 deletions(-) create mode 100644 yunq/rust/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 52c6fef..837436a 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,6 +8,15 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -34,6 +43,16 @@ dependencies = [ "linked_list_allocator", ] +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.72", +] + [[package]] name = "proc-macro2" version = "1.0.86" @@ -78,6 +97,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "testbed" version = "0.1.0" @@ -92,6 +122,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "yellowstone" version = "0.1.0" @@ -99,6 +135,7 @@ dependencies = [ "mammoth", "yunq", "yunq-derive", + "yunqc", ] [[package]] @@ -115,5 +152,16 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "yunqc" +version = "0.1.0" +dependencies = [ + "convert_case", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.72", ] diff --git a/rust/lib/yellowstone/Cargo.toml b/rust/lib/yellowstone/Cargo.toml index c464a9e..59ea732 100644 --- a/rust/lib/yellowstone/Cargo.toml +++ b/rust/lib/yellowstone/Cargo.toml @@ -8,3 +8,6 @@ mammoth = { path = "../mammoth" } yunq = {path = "../yunq"} yunq-derive = {path = "../yunq-derive"} +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + diff --git a/rust/lib/yellowstone/build.rs b/rust/lib/yellowstone/build.rs index a072a3a..24472ac 100644 --- a/rust/lib/yellowstone/build.rs +++ b/rust/lib/yellowstone/build.rs @@ -1,18 +1,14 @@ -use std::process::Command; +use std::fs; fn main() { + let input_file = "../../../sys/yellowstone/lib/yellowstone/yellowstone.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; - - let status = Command::new("cargo") - .current_dir("../../../yunq/rust") - .arg("run") - .arg("--") - .arg("--input-path") - .arg("../../sys/yellowstone/lib/yellowstone/yellowstone.yunq") - .arg("--output-path") - .arg(out) - .status() - .expect("Failed to start execution"); - - assert!(status.success()); + fs::write(out, code).expect("Failed to write generated code."); } diff --git a/yunq/rust/Cargo.lock b/yunq/rust/Cargo.lock index 145ddd8..cfaa503 100644 --- a/yunq/rust/Cargo.lock +++ b/yunq/rust/Cargo.lock @@ -255,7 +255,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "yunq" +name = "yunqc" version = "0.1.0" dependencies = [ "clap", diff --git a/yunq/rust/Cargo.toml b/yunq/rust/Cargo.toml index 2550596..a972f93 100644 --- a/yunq/rust/Cargo.toml +++ b/yunq/rust/Cargo.toml @@ -1,12 +1,20 @@ [package] -name = "yunq" +name = "yunqc" version = "0.1.0" edition = "2021" [dependencies] -clap = { version = "4.5.7", features = ["derive"] } convert_case = "0.6.0" prettyplease = "0.2.20" proc-macro2 = { version = "1.0" } quote = { version = "1.0" } syn = "2.0.72" + +clap = { version = "4.5.7", features = ["derive"], optional = true} + +[features] +build-binary = ["clap"] + +[[bin]] +name = "yunqc" +required-features = ["build-binary"] diff --git a/yunq/rust/src/lib.rs b/yunq/rust/src/lib.rs new file mode 100644 index 0000000..07ecdb9 --- /dev/null +++ b/yunq/rust/src/lib.rs @@ -0,0 +1,15 @@ +mod codegen; +mod lexer; +mod parser; + +use std::error::Error; + +pub fn codegen(input: &str) -> Result> { + let tokens = lexer::lex_input(input)?; + + let mut ast_parser = parser::Parser::new(&tokens); + ast_parser.parse_ast()?; + ast_parser.type_check()?; + + Ok(codegen::generate_code(ast_parser.ast())) +} diff --git a/yunq/rust/src/main.rs b/yunq/rust/src/main.rs index 21ece22..a835985 100644 --- a/yunq/rust/src/main.rs +++ b/yunq/rust/src/main.rs @@ -1,7 +1,3 @@ -mod codegen; -mod lexer; -mod parser; - use std::error::Error; use std::fs; @@ -22,13 +18,8 @@ struct Args { fn main() -> Result<(), Box> { let args = Args::parse(); let input = fs::read_to_string(args.input_path)?; - let tokens = lexer::lex_input(&input)?; - let mut ast_parser = parser::Parser::new(&tokens); - ast_parser.parse_ast()?; - ast_parser.type_check()?; - - let code = codegen::generate_code(ast_parser.ast()); + let code = yunqc::codegen(&input)?; fs::write(args.output_path, code)?; From 19144f7be94420cb85a2b6fc6ee11f112c681099 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 18:14:18 -0700 Subject: [PATCH 091/186] Fix rust compiler warnings. --- rust/Cargo.toml | 1 + rust/lib/yunq/src/message.rs | 12 ++++++------ yunq/rust/src/lexer.rs | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index f35d122..4898b85 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -3,6 +3,7 @@ members = [ "lib/mammoth", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "usr/testbed", ] +resolver = "2" # the profile used for `cargo build` [profile.dev] diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 3369cba..357ec36 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -31,9 +31,9 @@ pub struct Empty {} impl YunqMessage for Empty { fn parse( - buf: &ByteBuffer, - offset: usize, - caps: &Vec, + _buf: &ByteBuffer, + _offset: usize, + _caps: &Vec, ) -> Result where Self: Sized, @@ -43,9 +43,9 @@ impl YunqMessage for Empty { fn serialize( &self, - buf: &mut ByteBuffer, - offset: usize, - caps: &mut Vec, + _buf: &mut ByteBuffer, + _offset: usize, + _caps: &mut Vec, ) -> Result { todo!() } diff --git a/yunq/rust/src/lexer.rs b/yunq/rust/src/lexer.rs index 81eab06..666c1f5 100644 --- a/yunq/rust/src/lexer.rs +++ b/yunq/rust/src/lexer.rs @@ -13,6 +13,7 @@ pub enum TokenType { } #[derive(Debug)] +#[allow(dead_code)] pub struct Token { pub token_type: TokenType, line: usize, From d5a5041c4b1b1da4e15d65fd720e6c984cf5b790 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 19:02:03 -0700 Subject: [PATCH 092/186] Add multithreading to rust code. --- rust/lib/mammoth/src/bindings.rs | 4 +-- rust/lib/mammoth/src/lib.rs | 4 +++ rust/lib/mammoth/src/syscall.rs | 6 ++-- rust/lib/mammoth/src/thread.rs | 60 ++++++++++++++++++++++++++++++++ rust/usr/testbed/src/main.rs | 8 +++++ 5 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 rust/lib/mammoth/src/thread.rs diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index 31568ef..6fdfc13 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -351,9 +351,7 @@ pub struct ZThreadStartReq { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct ZThreadExitReq { - pub _address: u8, -} +pub struct ZThreadExitReq {} extern "C" { #[link_name = "\u{1}_Z11ZThreadExitv"] pub fn ZThreadExit() -> z_err_t; diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 3d8b7da..38564fd 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -3,10 +3,14 @@ #![allow(non_camel_case_types)] #![allow(non_snake_case)] +extern crate alloc; + use core::ffi::c_void; pub mod mem; +#[macro_use] pub mod syscall; +pub mod thread; // From /zion/include/ztypes.h const Z_INIT_SELF_PROC: u64 = 0x4000_0000; diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index ec8fe9d..8db78f6 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -138,10 +138,10 @@ impl fmt::Write for Writer { #[macro_export] macro_rules! debug { () => { - debug(""); + $crate::syscall::debug(""); }; ($fmt:literal) => { - debug($fmt); + $crate::syscall::debug($fmt); }; ($fmt:literal, $($val:expr),+) => {{ use core::fmt::Write as _; @@ -149,6 +149,6 @@ macro_rules! debug { let mut w = $crate::syscall::Writer::new(); write!(&mut w, $fmt, $($val),*).expect("Failed to format"); let s: String = w.into(); - debug(&s); + $crate::syscall::debug(&s); }}; } diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs new file mode 100644 index 0000000..04c0366 --- /dev/null +++ b/rust/lib/mammoth/src/thread.rs @@ -0,0 +1,60 @@ +use crate::syscall; +use crate::syscall::z_cap_t; + +use core::ffi::c_void; + +pub type ThreadEntry = fn(*const c_void) -> (); + +#[no_mangle] +extern "C" fn entry_point(entry_ptr: *const ThreadEntry, arg1: *const c_void) -> ! { + debug!("Entry {:#p} arg1 {:#x}", entry_ptr, arg1 as u64); + let entry = unsafe { *entry_ptr }; + + entry(arg1); + + let _ = syscall::syscall(syscall::kZionThreadExit, &syscall::ZThreadExitReq {}); + + unreachable!(); +} + +// TODO: Add a Drop implementation that kills this thread and drops its capability. +pub struct Thread<'a> { + cap: z_cap_t, + // This field only exists to ensure that the entry reference will outlive the thread object + // itself. + _entry: &'a ThreadEntry, +} + +impl<'a> Thread<'a> { + pub fn spawn(entry: &'a ThreadEntry, arg1: *const c_void) -> Self { + let mut cap: z_cap_t = 0; + let req = syscall::ZThreadCreateReq { + proc_cap: unsafe { crate::SELF_PROC_CAP }, + thread_cap: &mut cap as *mut z_cap_t, + }; + + syscall::syscall(syscall::kZionThreadCreate, &req).expect("Failed to create thread."); + + syscall::syscall( + syscall::kZionThreadStart, + &syscall::ZThreadStartReq { + thread_cap: cap, + entry: entry_point as u64, + arg1: entry as *const ThreadEntry as u64, + arg2: arg1 as u64, + }, + ) + .expect("Failed to start thread."); + + Self { cap, _entry: entry } + } + + pub fn join(&self) -> Result<(), syscall::ZError> { + syscall::syscall( + syscall::kZionThreadWait, + &syscall::ZThreadWaitReq { + thread_cap: self.cap, + }, + ) + } +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 79f9e2e..1b16921 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -9,6 +9,7 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; use mammoth::syscall::z_err_t; +use mammoth::thread; use yellowstone::GetEndpointRequest; use yellowstone::YellowstoneClient; @@ -41,5 +42,12 @@ pub extern "C" fn main() -> z_err_t { debug!("Got endpoint w/ cap: {:#x}", endpoint.endpoint); + let e: thread::ThreadEntry = |_| { + debug!("Testing 1 2 3"); + }; + let t = thread::Thread::spawn(&e, core::ptr::null()); + + t.join().expect("Failed to wait."); + 0 } From d35e8d253f705c1942fe1a9ada36841a8e2b056d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 19:26:23 -0700 Subject: [PATCH 093/186] Reorganize mammoth lib in rust. --- rust/lib/mammoth/src/init.rs | 42 ++++++++++ rust/lib/mammoth/src/lib.rs | 66 ++-------------- rust/lib/mammoth/src/macros.rs | 67 ++++++++++++++++ rust/lib/mammoth/src/mem.rs | 11 +-- rust/lib/mammoth/src/syscall.rs | 131 ++------------------------------ rust/lib/mammoth/src/thread.rs | 21 ++--- rust/lib/mammoth/src/zion.rs | 69 +++++++++++++++++ rust/lib/yunq/src/buffer.rs | 2 +- rust/lib/yunq/src/client.rs | 12 +-- rust/lib/yunq/src/message.rs | 4 +- rust/usr/testbed/src/main.rs | 8 +- yunq/rust/src/codegen.rs | 4 +- 12 files changed, 223 insertions(+), 214 deletions(-) create mode 100644 rust/lib/mammoth/src/init.rs create mode 100644 rust/lib/mammoth/src/macros.rs create mode 100644 rust/lib/mammoth/src/zion.rs diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs new file mode 100644 index 0000000..a20aa76 --- /dev/null +++ b/rust/lib/mammoth/src/init.rs @@ -0,0 +1,42 @@ +use crate::syscall; +use crate::zion; +use crate::zion::z_cap_t; +use core::ffi::c_void; + +// From /zion/include/ztypes.h +const Z_INIT_SELF_PROC: u64 = 0x4000_0000; +const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; +const Z_INIT_ENDPOINT: u64 = 0x4100_0000; + +pub static mut SELF_PROC_CAP: z_cap_t = 0; +pub static mut SELF_VMAS_CAP: z_cap_t = 0; +pub static mut INIT_ENDPOINT: z_cap_t = 0; + +pub fn parse_init_port(port_cap: z_cap_t) { + loop { + let mut num_bytes: u64 = 8; + let mut init_sig: u64 = 0; + let mut caps: [u64; 1] = [0]; + let mut num_caps: u64 = 1; + + let req = zion::ZPortPollReq { + port_cap, + num_bytes: &mut num_bytes as *mut u64, + data: &mut init_sig as *mut u64 as *mut c_void, + caps: &mut caps as *mut u64, + num_caps: &mut num_caps as *mut u64, + }; + let resp = syscall::syscall(zion::kZionPortPoll, &req); + if let Err(_) = resp { + break; + } + unsafe { + match init_sig { + Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], + Z_INIT_SELF_VMAS => SELF_VMAS_CAP = caps[0], + Z_INIT_ENDPOINT => INIT_ENDPOINT = caps[0], + _ => syscall::debug("Unknown Cap in Init"), + } + } + } +} diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 38564fd..3cc833d 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -5,67 +5,11 @@ extern crate alloc; -use core::ffi::c_void; - -pub mod mem; #[macro_use] +pub mod macros; + +pub mod init; +pub mod mem; pub mod syscall; pub mod thread; - -// From /zion/include/ztypes.h -const Z_INIT_SELF_PROC: u64 = 0x4000_0000; -const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; -const Z_INIT_ENDPOINT: u64 = 0x4100_0000; - -static mut SELF_PROC_CAP: syscall::zcap = 0; -static mut SELF_VMAS_CAP: syscall::zcap = 0; -pub static mut INIT_ENDPOINT: syscall::zcap = 0; - -pub fn parse_init_port(port_cap: syscall::zcap) { - loop { - let mut num_bytes: u64 = 8; - let mut init_sig: u64 = 0; - let mut caps: [u64; 1] = [0]; - let mut num_caps: u64 = 1; - - let req = syscall::ZPortPollReq { - port_cap, - num_bytes: &mut num_bytes as *mut u64, - data: &mut init_sig as *mut u64 as *mut c_void, - caps: &mut caps as *mut u64, - num_caps: &mut num_caps as *mut u64, - }; - let resp = syscall::syscall(syscall::kZionPortPoll, &req); - if let Err(_) = resp { - break; - } - unsafe { - match init_sig { - Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], - Z_INIT_SELF_VMAS => SELF_VMAS_CAP = caps[0], - Z_INIT_ENDPOINT => INIT_ENDPOINT = caps[0], - _ => syscall::debug("Unknown Cap in Init"), - } - } - } -} - -#[macro_export] -macro_rules! define_entry { - () => { - #[no_mangle] - pub extern "C" fn _start(init_port: mammoth::syscall::zcap) -> ! { - extern "C" { - fn main() -> z_err_t; - } - mammoth::parse_init_port(init_port); - mammoth::mem::init_heap(); - unsafe { - let err = main(); - let req = mammoth::syscall::ZProcessExitReq { code: err }; - let _ = mammoth::syscall::syscall(mammoth::syscall::kZionProcessExit, &req); - } - unreachable!() - } - }; -} +pub mod zion; diff --git a/rust/lib/mammoth/src/macros.rs b/rust/lib/mammoth/src/macros.rs new file mode 100644 index 0000000..8313961 --- /dev/null +++ b/rust/lib/mammoth/src/macros.rs @@ -0,0 +1,67 @@ +use alloc::string::String; +use alloc::vec::Vec; +use core::fmt; + +pub struct Writer { + int_vec: Vec, +} + +impl Writer { + pub fn new() -> Self { + Self { + int_vec: Vec::new(), + } + } +} + +impl Into for Writer { + fn into(self) -> String { + String::from_utf8(self.int_vec).expect("Failed to convert") + } +} + +impl fmt::Write for Writer { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.bytes() { + self.int_vec.push(c); + } + fmt::Result::Ok(()) + } +} + +#[macro_export] +macro_rules! debug { + () => { + $crate::syscall::debug(""); + }; + ($fmt:literal) => { + $crate::syscall::debug($fmt); + }; + ($fmt:literal, $($val:expr),+) => {{ + use core::fmt::Write as _; + let mut w = $crate::macros::Writer::new(); + write!(&mut w, $fmt, $($val),*).expect("Failed to format"); + let s: alloc::string::String = w.into(); + $crate::syscall::debug(&s); + }}; +} + +#[macro_export] +macro_rules! define_entry { + () => { + #[no_mangle] + pub extern "C" fn _start(init_port: mammoth::zion::z_cap_t) -> ! { + extern "C" { + fn main() -> z_err_t; + } + mammoth::init::parse_init_port(init_port); + mammoth::mem::init_heap(); + unsafe { + let err = main(); + let req = mammoth::zion::ZProcessExitReq { code: err }; + let _ = mammoth::syscall::syscall(mammoth::zion::kZionProcessExit, &req); + } + unreachable!() + } + }; +} diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 74bb1c4..dac6aa0 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -1,5 +1,6 @@ +use crate::init::SELF_VMAS_CAP; use crate::syscall; -use crate::SELF_VMAS_CAP; +use crate::zion; use linked_list_allocator::LockedHeap; #[global_allocator] @@ -11,16 +12,16 @@ pub fn init_heap() { // 1 MiB let size = 0x10_0000; let mut vmmo_cap = 0; - let obj_req = syscall::ZMemoryObjectCreateReq { + let obj_req = zion::ZMemoryObjectCreateReq { size, vmmo_cap: &mut vmmo_cap as *mut u64, }; - syscall::syscall(syscall::kZionMemoryObjectCreate, &obj_req) + syscall::syscall(zion::kZionMemoryObjectCreate, &obj_req) .expect("Failed to create memory object"); unsafe { let mut vaddr: u64 = 0; - let vmas_req = syscall::ZAddressSpaceMapReq { + let vmas_req = zion::ZAddressSpaceMapReq { vmmo_cap, vmas_cap: SELF_VMAS_CAP, align: 0x2000, @@ -28,7 +29,7 @@ pub fn init_heap() { vmas_offset: 0, }; - syscall::syscall(syscall::kZionAddressSpaceMap, &vmas_req) + syscall::syscall(zion::kZionAddressSpaceMap, &vmas_req) .expect("Failed to map memory object"); ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); CAN_ALLOC = true; diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 8db78f6..d46bea0 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -1,85 +1,15 @@ extern crate alloc; -use alloc::string::String; -use alloc::vec::Vec; +use crate::zion; use core::ffi::c_void; -use core::fmt; use core::panic::PanicInfo; -include!("bindings.rs"); - -pub enum ZError { - UNKNOWN = 0x0, - // First set of error codes generally indicate user errors. - INVALID_ARGUMENT = 0x1, - NOT_FOUND = 0x2, - PERMISSION_DENIED = 0x3, - NULL_PTR = 0x4, - EMPTY = 0x5, - ALREADY_EXISTS = 0x6, - BUFFER_SIZE = 0x7, - FAILED_PRECONDITION = 0x8, - - // Second set of error codes generally indicate service errors. - INTERNAL = 0x100, - UNIMPLEMENTED = 0x101, - EXHAUSTED = 0x102, - INVALID_RESPONSE = 0x103, - - // Kernel specific error codes (relating to capabilities). - CAP_NOT_FOUND = 0x1000, - CAP_WRONG_TYPE = 0x1001, - CAP_PERMISSION_DENIED = 0x1002, -} - -impl From for ZError { - fn from(value: u64) -> Self { - match value { - 0x1 => ZError::INVALID_ARGUMENT, - 0x2 => ZError::NOT_FOUND, - 0x3 => ZError::PERMISSION_DENIED, - 0x4 => ZError::NULL_PTR, - 0x5 => ZError::EMPTY, - 0x6 => ZError::ALREADY_EXISTS, - 0x7 => ZError::BUFFER_SIZE, - 0x8 => ZError::FAILED_PRECONDITION, - - 0x100 => ZError::INTERNAL, - 0x101 => ZError::UNIMPLEMENTED, - 0x102 => ZError::EXHAUSTED, - 0x103 => ZError::INVALID_RESPONSE, - - 0x1000 => ZError::CAP_NOT_FOUND, - 0x1001 => ZError::CAP_WRONG_TYPE, - 0x1002 => ZError::CAP_PERMISSION_DENIED, - _ => ZError::UNKNOWN, - } - } -} - -impl fmt::Debug for ZError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let str = match self { - ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT", - ZError::BUFFER_SIZE => "BUFFER_SIZE", - ZError::INTERNAL => "INTERNAL", - ZError::UNIMPLEMENTED => "UNIMPLEMENTED", - ZError::INVALID_RESPONSE => "INVALID_RESPONSE", - ZError::CAP_NOT_FOUND => "CAP_NOT_FOUND", - ZError::CAP_WRONG_TYPE => "CAP_WRONG_TYPE", - ZError::CAP_PERMISSION_DENIED => "CAP_PERMISSION_DENIED", - _ => "ZError", - }; - f.write_str(str) - } -} - #[must_use] -pub fn syscall(id: u64, req: &T) -> Result<(), ZError> { +pub fn syscall(id: u64, req: &T) -> Result<(), zion::ZError> { unsafe { - let resp = SysCall1(id, req as *const T as *const c_void); + let resp = zion::SysCall1(id, req as *const T as *const c_void); if resp != 0 { - return Err(ZError::from(resp)); + return Err(zion::ZError::from(resp)); } } Ok(()) @@ -95,60 +25,15 @@ fn panic(info: &PanicInfo) -> ! { } } // Internal error. - let req = ZProcessExitReq { code: 0x100 }; - let _ = syscall(kZionProcessExit, &req); + let req = zion::ZProcessExitReq { code: 0x100 }; + let _ = syscall(zion::kZionProcessExit, &req); unreachable!() } pub fn debug(msg: &str) { - let req = ZDebugReq { + let req = zion::ZDebugReq { message: msg.as_ptr() as *const i8, size: msg.len() as u64, }; - syscall(kZionDebug, &req).expect("Failed to write"); -} - -pub struct Writer { - int_vec: Vec, -} - -impl Writer { - pub fn new() -> Self { - Self { - int_vec: Vec::new(), - } - } -} - -impl Into for Writer { - fn into(self) -> String { - String::from_utf8(self.int_vec).expect("Failed to convert") - } -} - -impl fmt::Write for Writer { - fn write_str(&mut self, s: &str) -> fmt::Result { - for c in s.bytes() { - self.int_vec.push(c); - } - fmt::Result::Ok(()) - } -} - -#[macro_export] -macro_rules! debug { - () => { - $crate::syscall::debug(""); - }; - ($fmt:literal) => { - $crate::syscall::debug($fmt); - }; - ($fmt:literal, $($val:expr),+) => {{ - use core::fmt::Write as _; - use alloc::string::String; - let mut w = $crate::syscall::Writer::new(); - write!(&mut w, $fmt, $($val),*).expect("Failed to format"); - let s: String = w.into(); - $crate::syscall::debug(&s); - }}; + syscall(zion::kZionDebug, &req).expect("Failed to write"); } diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 04c0366..d596c20 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -1,5 +1,6 @@ use crate::syscall; -use crate::syscall::z_cap_t; +use crate::zion; +use crate::zion::z_cap_t; use core::ffi::c_void; @@ -12,7 +13,7 @@ extern "C" fn entry_point(entry_ptr: *const ThreadEntry, arg1: *const c_void) -> entry(arg1); - let _ = syscall::syscall(syscall::kZionThreadExit, &syscall::ZThreadExitReq {}); + let _ = syscall::syscall(zion::kZionThreadExit, &zion::ZThreadExitReq {}); unreachable!(); } @@ -28,16 +29,16 @@ pub struct Thread<'a> { impl<'a> Thread<'a> { pub fn spawn(entry: &'a ThreadEntry, arg1: *const c_void) -> Self { let mut cap: z_cap_t = 0; - let req = syscall::ZThreadCreateReq { - proc_cap: unsafe { crate::SELF_PROC_CAP }, + let req = zion::ZThreadCreateReq { + proc_cap: unsafe { crate::init::SELF_PROC_CAP }, thread_cap: &mut cap as *mut z_cap_t, }; - syscall::syscall(syscall::kZionThreadCreate, &req).expect("Failed to create thread."); + syscall::syscall(zion::kZionThreadCreate, &req).expect("Failed to create thread."); syscall::syscall( - syscall::kZionThreadStart, - &syscall::ZThreadStartReq { + zion::kZionThreadStart, + &zion::ZThreadStartReq { thread_cap: cap, entry: entry_point as u64, arg1: entry as *const ThreadEntry as u64, @@ -49,10 +50,10 @@ impl<'a> Thread<'a> { Self { cap, _entry: entry } } - pub fn join(&self) -> Result<(), syscall::ZError> { + pub fn join(&self) -> Result<(), zion::ZError> { syscall::syscall( - syscall::kZionThreadWait, - &syscall::ZThreadWaitReq { + zion::kZionThreadWait, + &zion::ZThreadWaitReq { thread_cap: self.cap, }, ) diff --git a/rust/lib/mammoth/src/zion.rs b/rust/lib/mammoth/src/zion.rs new file mode 100644 index 0000000..1bcadd2 --- /dev/null +++ b/rust/lib/mammoth/src/zion.rs @@ -0,0 +1,69 @@ +include!("bindings.rs"); + +use core::fmt; + +pub enum ZError { + UNKNOWN = 0x0, + // First set of error codes generally indicate user errors. + INVALID_ARGUMENT = 0x1, + NOT_FOUND = 0x2, + PERMISSION_DENIED = 0x3, + NULL_PTR = 0x4, + EMPTY = 0x5, + ALREADY_EXISTS = 0x6, + BUFFER_SIZE = 0x7, + FAILED_PRECONDITION = 0x8, + + // Second set of error codes generally indicate service errors. + INTERNAL = 0x100, + UNIMPLEMENTED = 0x101, + EXHAUSTED = 0x102, + INVALID_RESPONSE = 0x103, + + // Kernel specific error codes (relating to capabilities). + CAP_NOT_FOUND = 0x1000, + CAP_WRONG_TYPE = 0x1001, + CAP_PERMISSION_DENIED = 0x1002, +} + +impl From for ZError { + fn from(value: u64) -> Self { + match value { + 0x1 => ZError::INVALID_ARGUMENT, + 0x2 => ZError::NOT_FOUND, + 0x3 => ZError::PERMISSION_DENIED, + 0x4 => ZError::NULL_PTR, + 0x5 => ZError::EMPTY, + 0x6 => ZError::ALREADY_EXISTS, + 0x7 => ZError::BUFFER_SIZE, + 0x8 => ZError::FAILED_PRECONDITION, + + 0x100 => ZError::INTERNAL, + 0x101 => ZError::UNIMPLEMENTED, + 0x102 => ZError::EXHAUSTED, + 0x103 => ZError::INVALID_RESPONSE, + + 0x1000 => ZError::CAP_NOT_FOUND, + 0x1001 => ZError::CAP_WRONG_TYPE, + 0x1002 => ZError::CAP_PERMISSION_DENIED, + _ => ZError::UNKNOWN, + } + } +} + +impl fmt::Debug for ZError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let str = match self { + ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT", + ZError::BUFFER_SIZE => "BUFFER_SIZE", + ZError::INTERNAL => "INTERNAL", + ZError::UNIMPLEMENTED => "UNIMPLEMENTED", + ZError::INVALID_RESPONSE => "INVALID_RESPONSE", + ZError::CAP_NOT_FOUND => "CAP_NOT_FOUND", + ZError::CAP_WRONG_TYPE => "CAP_WRONG_TYPE", + ZError::CAP_PERMISSION_DENIED => "CAP_PERMISSION_DENIED", + _ => "ZError", + }; + f.write_str(str) + } +} diff --git a/rust/lib/yunq/src/buffer.rs b/rust/lib/yunq/src/buffer.rs index a070901..5c13c76 100644 --- a/rust/lib/yunq/src/buffer.rs +++ b/rust/lib/yunq/src/buffer.rs @@ -1,5 +1,5 @@ use alloc::boxed::Box; -use mammoth::syscall::ZError; +use mammoth::zion::ZError; pub struct ByteBuffer { buffer: Box<[u8; N]>, diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index 51795ed..dbe4657 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -2,8 +2,8 @@ use crate::buffer::ByteBuffer; use crate::message::YunqMessage; use alloc::vec::Vec; use core::ffi::c_void; -use mammoth::syscall::z_cap_t; -use mammoth::syscall::ZError; +use mammoth::zion::z_cap_t; +use mammoth::zion::ZError; const SENTINEL: u32 = 0xBEEFDEAD; @@ -22,7 +22,7 @@ pub fn call_endpoint( byte_buffer.write_at(4, (16 + length) as u32)?; let mut reply_port_cap: u64 = 0; - let send_req = mammoth::syscall::ZEndpointSendReq { + let send_req = mammoth::zion::ZEndpointSendReq { caps: cap_buffer.as_ptr(), num_caps: cap_buffer.len() as u64, endpoint_cap, @@ -31,13 +31,13 @@ pub fn call_endpoint( reply_port_cap: &mut reply_port_cap as *mut z_cap_t, }; - mammoth::syscall::syscall(mammoth::syscall::kZionEndpointSend, &send_req)?; + mammoth::syscall::syscall(mammoth::zion::kZionEndpointSend, &send_req)?; // FIXME: Add a way to zero out the byte buffer. let mut buffer_size = byte_buffer.size(); let mut num_caps: u64 = 10; cap_buffer = vec![0; num_caps as usize]; - let recv_req = mammoth::syscall::ZReplyPortRecvReq { + let recv_req = mammoth::zion::ZReplyPortRecvReq { reply_port_cap, caps: cap_buffer.as_mut_ptr(), num_caps: &mut num_caps as *mut u64, @@ -45,7 +45,7 @@ pub fn call_endpoint( num_bytes: &mut buffer_size as *mut u64, }; - mammoth::syscall::syscall(mammoth::syscall::kZionReplyPortRecv, &recv_req)?; + mammoth::syscall::syscall(mammoth::zion::kZionReplyPortRecv, &recv_req)?; if byte_buffer.at::(0)? != SENTINEL { return Err(ZError::INVALID_RESPONSE); diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 357ec36..daab90f 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -1,7 +1,7 @@ use crate::buffer::ByteBuffer; use alloc::vec::Vec; -use mammoth::syscall::z_cap_t; -use mammoth::syscall::ZError; +use mammoth::zion::z_cap_t; +use mammoth::zion::ZError; pub const MESSAGE_IDENT: u32 = 0x33441122; pub const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 1b16921..b612523 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -8,8 +8,8 @@ use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; use mammoth::syscall::debug; -use mammoth::syscall::z_err_t; use mammoth::thread; +use mammoth::zion::z_err_t; use yellowstone::GetEndpointRequest; use yellowstone::YellowstoneClient; @@ -22,16 +22,16 @@ pub extern "C" fn main() -> z_err_t { debug(&x); debug!("Formatted {}", "string"); let mut vmmo_cap: u64 = 0; - let obj_req = mammoth::syscall::ZMemoryObjectCreateReq { + let obj_req = mammoth::zion::ZMemoryObjectCreateReq { size: 0, vmmo_cap: &mut vmmo_cap as *mut u64, }; - mammoth::syscall::syscall(mammoth::syscall::kZionMemoryObjectCreate, &obj_req) + mammoth::syscall::syscall(mammoth::zion::kZionMemoryObjectCreate, &obj_req) .expect("Failed to create memory object"); let mut yellowstone; unsafe { - yellowstone = YellowstoneClient::new(mammoth::INIT_ENDPOINT); + yellowstone = YellowstoneClient::new(mammoth::init::INIT_ENDPOINT); } let endpoint = yellowstone diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 0051047..e20f6b5 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -79,8 +79,8 @@ pub fn generate_code(ast: &Vec) -> String { use alloc::string::String; use alloc::string::ToString; - use mammoth::syscall::z_cap_t; - use mammoth::syscall::ZError; + use mammoth::zion::z_cap_t; + use mammoth::zion::ZError; use yunq::ByteBuffer; use yunq::YunqMessage; use yunq_derive::YunqMessage; From 4d94bc0ea892d960aa893b948fe7041276b63841 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 19:29:23 -0700 Subject: [PATCH 094/186] Make unsafe more limited in memory initialization. --- rust/lib/mammoth/src/mem.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index dac6aa0..6f49415 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -19,18 +19,17 @@ pub fn init_heap() { syscall::syscall(zion::kZionMemoryObjectCreate, &obj_req) .expect("Failed to create memory object"); - unsafe { - let mut vaddr: u64 = 0; - let vmas_req = zion::ZAddressSpaceMapReq { - vmmo_cap, - vmas_cap: SELF_VMAS_CAP, - align: 0x2000, - vaddr: &mut vaddr as *mut u64, - vmas_offset: 0, - }; + let mut vaddr: u64 = 0; + let vmas_req = zion::ZAddressSpaceMapReq { + vmmo_cap, + vmas_cap: unsafe { SELF_VMAS_CAP }, + align: 0x2000, + vaddr: &mut vaddr as *mut u64, + vmas_offset: 0, + }; - syscall::syscall(zion::kZionAddressSpaceMap, &vmas_req) - .expect("Failed to map memory object"); + syscall::syscall(zion::kZionAddressSpaceMap, &vmas_req).expect("Failed to map memory object"); + unsafe { ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); CAN_ALLOC = true; } From 612a5ac57254b3feaca7d2a4dddb0f95a7479db0 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 19:30:31 -0700 Subject: [PATCH 095/186] Remove unused zcap --- rust/lib/mammoth/src/bindings.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index 6fdfc13..aaffeb5 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -1,7 +1,5 @@ /* automatically generated by rust-bindgen 0.69.4 */ -pub type zcap = u64; - pub const _STDINT_H: u32 = 1; pub const _FEATURES_H: u32 = 1; pub const _ISOC95_SOURCE: u32 = 1; From ca67da16e665e088cc1acf8bef1599a6e641e1c2 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 19:48:05 -0700 Subject: [PATCH 096/186] [Mammoth] Move thread syscalls to wrappers. --- rust/lib/mammoth/src/syscall.rs | 37 ++++++++++++++++++++++++++- rust/lib/mammoth/src/thread.rs | 44 ++++++++++----------------------- rust/usr/testbed/src/main.rs | 16 ++---------- 3 files changed, 51 insertions(+), 46 deletions(-) diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index d46bea0..aa0fc5b 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -1,11 +1,13 @@ extern crate alloc; use crate::zion; +use crate::zion::z_cap_t; +use crate::zion::ZError; use core::ffi::c_void; use core::panic::PanicInfo; #[must_use] -pub fn syscall(id: u64, req: &T) -> Result<(), zion::ZError> { +pub fn syscall(id: u64, req: &T) -> Result<(), ZError> { unsafe { let resp = zion::SysCall1(id, req as *const T as *const c_void); if resp != 0 { @@ -37,3 +39,36 @@ pub fn debug(msg: &str) { }; syscall(zion::kZionDebug, &req).expect("Failed to write"); } + +pub fn thread_create(proc_cap: z_cap_t) -> Result { + let mut cap = 0; + syscall( + zion::kZionThreadCreate, + &zion::ZThreadCreateReq { + proc_cap, + thread_cap: &mut cap as *mut z_cap_t, + }, + )?; + Ok(cap) +} + +pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Result<(), ZError> { + syscall( + zion::kZionThreadStart, + &zion::ZThreadStartReq { + thread_cap, + entry, + arg1, + arg2, + }, + ) +} + +pub fn thread_wait(thread_cap: z_cap_t) -> Result<(), ZError> { + syscall(zion::kZionThreadWait, &zion::ZThreadWaitReq { thread_cap }) +} + +pub fn thread_exit() -> ! { + let _ = syscall(zion::kZionThreadExit, &zion::ZThreadExitReq {}); + unreachable!(); +} diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index d596c20..1ddc85d 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -7,17 +7,13 @@ use core::ffi::c_void; pub type ThreadEntry = fn(*const c_void) -> (); #[no_mangle] -extern "C" fn entry_point(entry_ptr: *const ThreadEntry, arg1: *const c_void) -> ! { - debug!("Entry {:#p} arg1 {:#x}", entry_ptr, arg1 as u64); +extern "C" fn internal_entry_point(entry_ptr: *const ThreadEntry, arg1: *const c_void) -> ! { let entry = unsafe { *entry_ptr }; entry(arg1); - let _ = syscall::syscall(zion::kZionThreadExit, &zion::ZThreadExitReq {}); - - unreachable!(); + syscall::thread_exit() } - // TODO: Add a Drop implementation that kills this thread and drops its capability. pub struct Thread<'a> { cap: z_cap_t, @@ -27,35 +23,21 @@ pub struct Thread<'a> { } impl<'a> Thread<'a> { - pub fn spawn(entry: &'a ThreadEntry, arg1: *const c_void) -> Self { - let mut cap: z_cap_t = 0; - let req = zion::ZThreadCreateReq { - proc_cap: unsafe { crate::init::SELF_PROC_CAP }, - thread_cap: &mut cap as *mut z_cap_t, - }; + pub fn spawn(entry: &'a ThreadEntry, arg1: *const c_void) -> Result { + let proc_cap = unsafe { crate::init::SELF_PROC_CAP }; + let cap = syscall::thread_create(proc_cap)?; - syscall::syscall(zion::kZionThreadCreate, &req).expect("Failed to create thread."); + syscall::thread_start( + cap, + internal_entry_point as u64, + entry as *const ThreadEntry as u64, + arg1 as u64, + )?; - syscall::syscall( - zion::kZionThreadStart, - &zion::ZThreadStartReq { - thread_cap: cap, - entry: entry_point as u64, - arg1: entry as *const ThreadEntry as u64, - arg2: arg1 as u64, - }, - ) - .expect("Failed to start thread."); - - Self { cap, _entry: entry } + Ok(Self { cap, _entry: entry }) } pub fn join(&self) -> Result<(), zion::ZError> { - syscall::syscall( - zion::kZionThreadWait, - &zion::ZThreadWaitReq { - thread_cap: self.cap, - }, - ) + syscall::thread_wait(self.cap) } } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index b612523..661c98b 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -3,11 +3,9 @@ extern crate alloc; -use alloc::boxed::Box; use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; -use mammoth::syscall::debug; use mammoth::thread; use mammoth::zion::z_err_t; use yellowstone::GetEndpointRequest; @@ -17,17 +15,7 @@ define_entry!(); #[no_mangle] pub extern "C" fn main() -> z_err_t { - debug("Testing!"); - let x = Box::new("Heap str"); - debug(&x); - debug!("Formatted {}", "string"); - let mut vmmo_cap: u64 = 0; - let obj_req = mammoth::zion::ZMemoryObjectCreateReq { - size: 0, - vmmo_cap: &mut vmmo_cap as *mut u64, - }; - mammoth::syscall::syscall(mammoth::zion::kZionMemoryObjectCreate, &obj_req) - .expect("Failed to create memory object"); + debug!("Testing!"); let mut yellowstone; unsafe { @@ -45,7 +33,7 @@ pub extern "C" fn main() -> z_err_t { let e: thread::ThreadEntry = |_| { debug!("Testing 1 2 3"); }; - let t = thread::Thread::spawn(&e, core::ptr::null()); + let t = thread::Thread::spawn(&e, core::ptr::null()).expect("Failed to spawn thread"); t.join().expect("Failed to wait."); From 5705f8d2ab39583947d962a307707d5b0e4fc887 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 20:10:32 -0700 Subject: [PATCH 097/186] Move more syscall usages to helper functions. --- rust/lib/mammoth/src/init.rs | 18 ++++---------- rust/lib/mammoth/src/mem.rs | 22 ++--------------- rust/lib/mammoth/src/syscall.rs | 43 +++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs index a20aa76..27dede9 100644 --- a/rust/lib/mammoth/src/init.rs +++ b/rust/lib/mammoth/src/init.rs @@ -1,7 +1,5 @@ use crate::syscall; -use crate::zion; use crate::zion::z_cap_t; -use core::ffi::c_void; // From /zion/include/ztypes.h const Z_INIT_SELF_PROC: u64 = 0x4000_0000; @@ -14,22 +12,16 @@ pub static mut INIT_ENDPOINT: z_cap_t = 0; pub fn parse_init_port(port_cap: z_cap_t) { loop { - let mut num_bytes: u64 = 8; - let mut init_sig: u64 = 0; + let mut bytes: [u8; 8] = [0; 8]; let mut caps: [u64; 1] = [0]; - let mut num_caps: u64 = 1; - let req = zion::ZPortPollReq { - port_cap, - num_bytes: &mut num_bytes as *mut u64, - data: &mut init_sig as *mut u64 as *mut c_void, - caps: &mut caps as *mut u64, - num_caps: &mut num_caps as *mut u64, - }; - let resp = syscall::syscall(zion::kZionPortPoll, &req); + let resp = syscall::port_poll(port_cap, &mut bytes, &mut caps); if let Err(_) = resp { break; } + + let init_sig = u64::from_le_bytes(bytes); + unsafe { match init_sig { Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 6f49415..750365d 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -1,6 +1,4 @@ -use crate::init::SELF_VMAS_CAP; use crate::syscall; -use crate::zion; use linked_list_allocator::LockedHeap; #[global_allocator] @@ -11,24 +9,8 @@ pub static mut CAN_ALLOC: bool = false; pub fn init_heap() { // 1 MiB let size = 0x10_0000; - let mut vmmo_cap = 0; - let obj_req = zion::ZMemoryObjectCreateReq { - size, - vmmo_cap: &mut vmmo_cap as *mut u64, - }; - syscall::syscall(zion::kZionMemoryObjectCreate, &obj_req) - .expect("Failed to create memory object"); - - let mut vaddr: u64 = 0; - let vmas_req = zion::ZAddressSpaceMapReq { - vmmo_cap, - vmas_cap: unsafe { SELF_VMAS_CAP }, - align: 0x2000, - vaddr: &mut vaddr as *mut u64, - vmas_offset: 0, - }; - - syscall::syscall(zion::kZionAddressSpaceMap, &vmas_req).expect("Failed to map memory object"); + let vmmo_cap = syscall::memory_object_create(size).expect("Failed to create memory object"); + let vaddr = syscall::address_space_map(vmmo_cap).expect("Failed to map memory object"); unsafe { ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); CAN_ALLOC = true; diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index aa0fc5b..799d467 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -72,3 +72,46 @@ pub fn thread_exit() -> ! { let _ = syscall(zion::kZionThreadExit, &zion::ZThreadExitReq {}); unreachable!(); } + +pub fn memory_object_create(size: u64) -> Result { + let mut vmmo_cap = 0; + let obj_req = zion::ZMemoryObjectCreateReq { + size, + vmmo_cap: &mut vmmo_cap as *mut u64, + }; + syscall(zion::kZionMemoryObjectCreate, &obj_req)?; + Ok(vmmo_cap) +} + +pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { + let mut vaddr: u64 = 0; + // FIXME: Allow caller to pass these options. + let vmas_req = zion::ZAddressSpaceMapReq { + vmmo_cap, + vmas_cap: unsafe { crate::init::SELF_VMAS_CAP }, + align: 0x2000, + vaddr: &mut vaddr as *mut u64, + vmas_offset: 0, + }; + + syscall(zion::kZionAddressSpaceMap, &vmas_req)?; + Ok(vaddr) +} + +pub fn port_poll( + port_cap: z_cap_t, + bytes: &mut [u8], + caps: &mut [u64], +) -> Result<(u64, u64), ZError> { + let mut num_bytes = bytes.len() as u64; + let mut num_caps = caps.len() as u64; + let req = zion::ZPortPollReq { + port_cap, + data: bytes.as_mut_ptr() as *mut c_void, + num_bytes: &mut num_bytes as *mut u64, + caps: caps.as_mut_ptr(), + num_caps: &mut num_caps as *mut u64, + }; + syscall(zion::kZionPortPoll, &req)?; + Ok((num_bytes, num_caps)) +} From c2f9f5388b69a4866486132c29bef79d5eaf5221 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 20:54:52 -0700 Subject: [PATCH 098/186] Move yunq client to use syscall helpers. --- rust/lib/mammoth/src/syscall.rs | 40 +++++++++++++++++++++++++++++++++ rust/lib/yunq/src/buffer.rs | 8 +++---- rust/lib/yunq/src/client.rs | 30 ++++++++----------------- 3 files changed, 53 insertions(+), 25 deletions(-) diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 799d467..3d029bc 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -115,3 +115,43 @@ pub fn port_poll( syscall(zion::kZionPortPoll, &req)?; Ok((num_bytes, num_caps)) } + +pub fn endpoint_send( + endpoint_cap: z_cap_t, + bytes: &[u8], + caps: &[z_cap_t], +) -> Result { + let mut reply_port_cap: u64 = 0; + let send_req = zion::ZEndpointSendReq { + caps: caps.as_ptr(), + num_caps: caps.len() as u64, + endpoint_cap, + data: bytes.as_ptr() as *const c_void, + num_bytes: bytes.len() as u64, + reply_port_cap: &mut reply_port_cap as *mut z_cap_t, + }; + + syscall(zion::kZionEndpointSend, &send_req)?; + + Ok(reply_port_cap) +} + +pub fn reply_port_recv( + reply_port_cap: z_cap_t, + bytes: &mut [u8], + caps: &mut [z_cap_t], +) -> Result<(u64, u64), ZError> { + let mut num_bytes = bytes.len() as u64; + let mut num_caps = caps.len() as u64; + let recv_req = zion::ZReplyPortRecvReq { + reply_port_cap, + caps: caps.as_mut_ptr(), + num_caps: &mut num_caps as *mut u64, + data: bytes.as_mut_ptr() as *mut c_void, + num_bytes: &mut num_bytes as *mut u64, + }; + + syscall(zion::kZionReplyPortRecv, &recv_req)?; + + Ok((num_bytes, num_caps)) +} diff --git a/rust/lib/yunq/src/buffer.rs b/rust/lib/yunq/src/buffer.rs index 5c13c76..c3b0b18 100644 --- a/rust/lib/yunq/src/buffer.rs +++ b/rust/lib/yunq/src/buffer.rs @@ -15,12 +15,12 @@ impl ByteBuffer { N as u64 } - pub fn raw_ptr(&self) -> *const u8 { - self.buffer.as_ptr() + pub fn slice(&self, len: usize) -> &[u8] { + &self.buffer[..len] } - pub fn mut_ptr(&mut self) -> *mut u8 { - self.buffer.as_mut_ptr() + pub fn mut_slice(&mut self) -> &mut [u8] { + &mut self.buffer[..] } pub fn write_at(&mut self, offset: usize, obj: T) -> Result<(), ZError> { diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index dbe4657..f8ff367 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -1,7 +1,6 @@ use crate::buffer::ByteBuffer; use crate::message::YunqMessage; use alloc::vec::Vec; -use core::ffi::c_void; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; @@ -21,31 +20,20 @@ pub fn call_endpoint( byte_buffer.write_at(4, (16 + length) as u32)?; - let mut reply_port_cap: u64 = 0; - let send_req = mammoth::zion::ZEndpointSendReq { - caps: cap_buffer.as_ptr(), - num_caps: cap_buffer.len() as u64, + let reply_port_cap = mammoth::syscall::endpoint_send( endpoint_cap, - data: byte_buffer.raw_ptr() as *const c_void, - num_bytes: 16 + length as u64, - reply_port_cap: &mut reply_port_cap as *mut z_cap_t, - }; + byte_buffer.slice(16 + length), + cap_buffer.as_slice(), + )?; - mammoth::syscall::syscall(mammoth::zion::kZionEndpointSend, &send_req)?; // FIXME: Add a way to zero out the byte buffer. - let mut buffer_size = byte_buffer.size(); - let mut num_caps: u64 = 10; - cap_buffer = vec![0; num_caps as usize]; - let recv_req = mammoth::zion::ZReplyPortRecvReq { + cap_buffer = vec![0; 10]; + mammoth::syscall::reply_port_recv( reply_port_cap, - caps: cap_buffer.as_mut_ptr(), - num_caps: &mut num_caps as *mut u64, - data: byte_buffer.mut_ptr() as *mut c_void, - num_bytes: &mut buffer_size as *mut u64, - }; - - mammoth::syscall::syscall(mammoth::zion::kZionReplyPortRecv, &recv_req)?; + byte_buffer.mut_slice(), + cap_buffer.as_mut_slice(), + )?; if byte_buffer.at::(0)? != SENTINEL { return Err(ZError::INVALID_RESPONSE); From d4f60f4942924869e3cd343500c65974b3b01291 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 28 Jul 2024 21:01:00 -0700 Subject: [PATCH 099/186] Moved process exit to syscall helper. Final call moved so syscall is private now. Also cleans up the macro a fair bit. --- rust/lib/mammoth/src/macros.rs | 19 +++++++------------ rust/lib/mammoth/src/syscall.rs | 8 +++++++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/rust/lib/mammoth/src/macros.rs b/rust/lib/mammoth/src/macros.rs index 8313961..c977a91 100644 --- a/rust/lib/mammoth/src/macros.rs +++ b/rust/lib/mammoth/src/macros.rs @@ -50,18 +50,13 @@ macro_rules! debug { macro_rules! define_entry { () => { #[no_mangle] - pub extern "C" fn _start(init_port: mammoth::zion::z_cap_t) -> ! { - extern "C" { - fn main() -> z_err_t; - } - mammoth::init::parse_init_port(init_port); - mammoth::mem::init_heap(); - unsafe { - let err = main(); - let req = mammoth::zion::ZProcessExitReq { code: err }; - let _ = mammoth::syscall::syscall(mammoth::zion::kZionProcessExit, &req); - } - unreachable!() + pub extern "C" fn _start(init_port: $crate::zion::z_cap_t) -> ! { + $crate::init::parse_init_port(init_port); + $crate::mem::init_heap(); + + let resp = main(); + + $crate::syscall::process_exit(resp); } }; } diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 3d029bc..0346e7f 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -7,7 +7,7 @@ use core::ffi::c_void; use core::panic::PanicInfo; #[must_use] -pub fn syscall(id: u64, req: &T) -> Result<(), ZError> { +fn syscall(id: u64, req: &T) -> Result<(), ZError> { unsafe { let resp = zion::SysCall1(id, req as *const T as *const c_void); if resp != 0 { @@ -40,6 +40,12 @@ pub fn debug(msg: &str) { syscall(zion::kZionDebug, &req).expect("Failed to write"); } +pub fn process_exit(code: u64) -> ! { + let _ = syscall(zion::kZionProcessExit, &zion::ZProcessExitReq { code }); + + unreachable!() +} + pub fn thread_create(proc_cap: z_cap_t) -> Result { let mut cap = 0; syscall( From e41f58c714e262eec604de88940ea8709192df0e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 30 Jul 2024 14:33:19 -0700 Subject: [PATCH 100/186] Use method number in rust yunq client. --- rust/lib/yunq/src/client.rs | 3 ++- yunq/rust/src/codegen.rs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index f8ff367..68241e2 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -7,12 +7,13 @@ use mammoth::zion::ZError; const SENTINEL: u32 = 0xBEEFDEAD; pub fn call_endpoint( + request_id: u64, req: &Req, byte_buffer: &mut ByteBuffer, endpoint_cap: z_cap_t, ) -> Result { byte_buffer.write_at(0, SENTINEL)?; - byte_buffer.write_at(8, 1 as u64)?; + byte_buffer.write_at(8, request_id as u64)?; let mut cap_buffer = Vec::new(); diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index e20f6b5..1f4bc64 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -26,23 +26,24 @@ fn generate_message(message: &Message) -> TokenStream { } fn generate_method(method: &Method) -> TokenStream { + let id = proc_macro2::Literal::u64_suffixed(method.number); let name = ident(&method.name.to_case(Case::Snake)); let maybe_req = method.request.clone().map(|r| ident(&r)); let maybe_resp = method.response.clone().map(|r| ident(&r)); match (maybe_req, maybe_resp) { (Some(req), Some(resp)) => quote! { pub fn #name (&mut self, req: & #req) -> Result<#resp, ZError> { - yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, self.endpoint_cap) } }, (Some(req), None) => quote! { pub fn #name (&mut self, req: & #req) -> Result { - yunq::client::call_endpoint(req, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, self.endpoint_cap) } }, (None, Some(resp)) => quote! { pub fn #name (&mut self) -> Result<#resp, ZError> { - yunq::client::call_endpoint(&yunq::message::Empty{}, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, &yunq::message::Empty{}, &mut self.byte_buffer, self.endpoint_cap) } }, _ => unreachable!(), From 6ae111dc66dbcc09aba2feff4545a9815c8fbe82 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 30 Jul 2024 15:13:34 -0700 Subject: [PATCH 101/186] Move request/response serialization to YunqMessage trait. --- rust/lib/yunq/src/client.rs | 21 ++------------------- rust/lib/yunq/src/message.rs | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index 68241e2..de8cada 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -4,22 +4,14 @@ use alloc::vec::Vec; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; -const SENTINEL: u32 = 0xBEEFDEAD; - pub fn call_endpoint( request_id: u64, req: &Req, byte_buffer: &mut ByteBuffer, endpoint_cap: z_cap_t, ) -> Result { - byte_buffer.write_at(0, SENTINEL)?; - byte_buffer.write_at(8, request_id as u64)?; - let mut cap_buffer = Vec::new(); - - let length = req.serialize(byte_buffer, 16, &mut cap_buffer)?; - - byte_buffer.write_at(4, (16 + length) as u32)?; + let length = req.serialize_as_request(request_id, byte_buffer, &mut cap_buffer)?; let reply_port_cap = mammoth::syscall::endpoint_send( endpoint_cap, @@ -36,14 +28,5 @@ pub fn call_endpoint( cap_buffer.as_mut_slice(), )?; - if byte_buffer.at::(0)? != SENTINEL { - return Err(ZError::INVALID_RESPONSE); - } - - let resp_code: u64 = byte_buffer.at(8)?; - if resp_code != 0 { - return Err(ZError::from(resp_code)); - } - - Ok(Resp::parse(&byte_buffer, 16, &cap_buffer)?) + Ok(Resp::parse_from_request(&byte_buffer, &cap_buffer)?) } diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index daab90f..73b37e4 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -4,6 +4,7 @@ use mammoth::zion::z_cap_t; use mammoth::zion::ZError; pub const MESSAGE_IDENT: u32 = 0x33441122; +const SENTINEL: u32 = 0xBEEFDEAD; pub const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 pub fn field_offset(offset: usize, field_index: usize) -> usize { @@ -19,12 +20,47 @@ pub trait YunqMessage { where Self: Sized; + fn parse_from_request( + buf: &ByteBuffer, + caps: &Vec, + ) -> Result + where + Self: Sized, + { + if buf.at::(0)? != SENTINEL { + return Err(ZError::INVALID_RESPONSE); + } + + let resp_code: u64 = buf.at(8)?; + if resp_code != 0 { + return Err(ZError::from(resp_code)); + } + + Ok(Self::parse(&buf, 16, &caps)?) + } + fn serialize( &self, buf: &mut ByteBuffer, offset: usize, caps: &mut Vec, ) -> Result; + + fn serialize_as_request( + &self, + request_id: u64, + buf: &mut ByteBuffer, + caps: &mut Vec, + ) -> Result { + buf.write_at(0, SENTINEL)?; + buf.write_at(8, request_id as u64)?; + + let length = self.serialize(buf, 16, caps)?; + + buf.write_at(4, (16 + length) as u32)?; + + Ok(length + 16) + } } pub struct Empty {} From dbc4e7e2ad421176d5badbe503c906e10c8ec1a9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 30 Jul 2024 15:49:14 -0700 Subject: [PATCH 102/186] Remove panic abort from Cargo.toml (it is set by the arch json). --- rust/Cargo.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 4898b85..b27a0fb 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -5,11 +5,3 @@ members = [ ] resolver = "2" -# the profile used for `cargo build` -[profile.dev] -panic = "abort" # disable stack unwinding on panic - -# the profile used for `cargo build --release` -[profile.release] -panic = "abort" # disable stack unwinding on panic - From 76f8795a469b821a1bd21cd330d353a7ee89d9e2 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 31 Jul 2024 19:59:46 -0700 Subject: [PATCH 103/186] Implement yunq server in rust. --- rust/Cargo.lock | 1 + rust/lib/mammoth/src/bindings.rs | 2 +- rust/lib/mammoth/src/syscall.rs | 56 +++++++++++++- rust/lib/mammoth/src/thread.rs | 21 ++--- rust/lib/yunq/src/client.rs | 6 ++ rust/lib/yunq/src/lib.rs | 1 + rust/lib/yunq/src/message.rs | 17 ++-- rust/lib/yunq/src/server.rs | 46 +++++++++++ rust/usr/testbed/Cargo.toml | 1 + rust/usr/testbed/src/main.rs | 53 ++++++++++++- yunq/rust/src/codegen.rs | 129 ++++++++++++++++++++++++++++++- zion/include/zcall.h | 2 +- 12 files changed, 312 insertions(+), 23 deletions(-) create mode 100644 rust/lib/yunq/src/server.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 837436a..3f089b0 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -114,6 +114,7 @@ version = "0.1.0" dependencies = [ "mammoth", "yellowstone", + "yunq", ] [[package]] diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index aaffeb5..16309b3 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -508,7 +508,7 @@ pub struct ZReplyPortSendReq { pub num_bytes: u64, pub data: *const ::core::ffi::c_void, pub num_caps: u64, - pub caps: *mut z_cap_t, + pub caps: *const z_cap_t, } #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 0346e7f..86765af 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -122,6 +122,17 @@ pub fn port_poll( Ok((num_bytes, num_caps)) } +pub fn endpoint_create() -> Result { + let mut endpoint_cap: z_cap_t = 0; + syscall( + zion::kZionEndpointCreate, + &zion::ZEndpointCreateReq { + endpoint_cap: &mut endpoint_cap, + }, + )?; + Ok(endpoint_cap) +} + pub fn endpoint_send( endpoint_cap: z_cap_t, bytes: &[u8], @@ -134,7 +145,7 @@ pub fn endpoint_send( endpoint_cap, data: bytes.as_ptr() as *const c_void, num_bytes: bytes.len() as u64, - reply_port_cap: &mut reply_port_cap as *mut z_cap_t, + reply_port_cap: &mut reply_port_cap, }; syscall(zion::kZionEndpointSend, &send_req)?; @@ -142,6 +153,45 @@ pub fn endpoint_send( Ok(reply_port_cap) } +pub fn endpoint_recv( + endpoint_cap: z_cap_t, + bytes: &mut [u8], + caps: &mut [z_cap_t], +) -> Result<(u64, u64, z_cap_t), ZError> { + let mut num_bytes = bytes.len() as u64; + let mut num_caps = caps.len() as u64; + let mut reply_port_cap = 0; + let recv_req = zion::ZEndpointRecvReq { + endpoint_cap, + data: bytes.as_mut_ptr() as *mut c_void, + num_bytes: &mut num_bytes, + caps: caps.as_mut_ptr(), + num_caps: &mut num_caps, + reply_port_cap: &mut reply_port_cap, + }; + + syscall(zion::kZionEndpointRecv, &recv_req)?; + + Ok((num_bytes, num_caps, reply_port_cap)) +} + +pub fn reply_port_send( + reply_port_cap: z_cap_t, + bytes: &[u8], + caps: &[z_cap_t], +) -> Result<(), ZError> { + syscall( + zion::kZionReplyPortSend, + &zion::ZReplyPortSendReq { + reply_port_cap, + data: bytes.as_ptr() as *const c_void, + num_bytes: bytes.len() as u64, + caps: caps.as_ptr(), + num_caps: caps.len() as u64, + }, + ) +} + pub fn reply_port_recv( reply_port_cap: z_cap_t, bytes: &mut [u8], @@ -152,9 +202,9 @@ pub fn reply_port_recv( let recv_req = zion::ZReplyPortRecvReq { reply_port_cap, caps: caps.as_mut_ptr(), - num_caps: &mut num_caps as *mut u64, + num_caps: &mut num_caps, data: bytes.as_mut_ptr() as *mut c_void, - num_bytes: &mut num_bytes as *mut u64, + num_bytes: &mut num_bytes, }; syscall(zion::kZionReplyPortRecv, &recv_req)?; diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 1ddc85d..92fd086 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -2,39 +2,40 @@ use crate::syscall; use crate::zion; use crate::zion::z_cap_t; +use alloc::boxed::Box; use core::ffi::c_void; pub type ThreadEntry = fn(*const c_void) -> (); #[no_mangle] -extern "C" fn internal_entry_point(entry_ptr: *const ThreadEntry, arg1: *const c_void) -> ! { - let entry = unsafe { *entry_ptr }; +extern "C" fn internal_entry_point(thread_ptr: *const Thread, arg1: *const c_void) -> ! { + let thread: &Thread = unsafe { thread_ptr.as_ref().expect("Failed to unwrap thread ref") }; - entry(arg1); + (thread.entry)(arg1); syscall::thread_exit() } // TODO: Add a Drop implementation that kills this thread and drops its capability. -pub struct Thread<'a> { +pub struct Thread { cap: z_cap_t, // This field only exists to ensure that the entry reference will outlive the thread object // itself. - _entry: &'a ThreadEntry, + entry: ThreadEntry, } -impl<'a> Thread<'a> { - pub fn spawn(entry: &'a ThreadEntry, arg1: *const c_void) -> Result { +impl Thread { + pub fn spawn(entry: ThreadEntry, arg1: *const c_void) -> Result, zion::ZError> { let proc_cap = unsafe { crate::init::SELF_PROC_CAP }; let cap = syscall::thread_create(proc_cap)?; - + let thread = Box::new(Self { cap, entry }); syscall::thread_start( cap, internal_entry_point as u64, - entry as *const ThreadEntry as u64, + thread.as_ref() as *const Thread as u64, arg1 as u64, )?; - Ok(Self { cap, _entry: entry }) + Ok(thread) } pub fn join(&self) -> Result<(), zion::ZError> { diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index de8cada..ad3a761 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -28,5 +28,11 @@ pub fn call_endpoint( cap_buffer.as_mut_slice(), )?; + let resp_code: u64 = byte_buffer.at(8)?; + + if resp_code != 0 { + return Err(ZError::from(resp_code)); + } + Ok(Resp::parse_from_request(&byte_buffer, &cap_buffer)?) } diff --git a/rust/lib/yunq/src/lib.rs b/rust/lib/yunq/src/lib.rs index 515760b..93166ac 100644 --- a/rust/lib/yunq/src/lib.rs +++ b/rust/lib/yunq/src/lib.rs @@ -6,6 +6,7 @@ extern crate alloc; mod buffer; pub mod client; pub mod message; +pub mod server; pub use buffer::ByteBuffer; pub use message::YunqMessage; diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 73b37e4..7b84b8d 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -4,13 +4,23 @@ use mammoth::zion::z_cap_t; use mammoth::zion::ZError; pub const MESSAGE_IDENT: u32 = 0x33441122; -const SENTINEL: u32 = 0xBEEFDEAD; pub const MESSAGE_HEADER_SIZE: usize = 24; // 4x uint32, 1x uint64 +const SENTINEL: u32 = 0xBEEFDEAD; +const SERIALIZE_HEADER_SIZE: u32 = 0x10; pub fn field_offset(offset: usize, field_index: usize) -> usize { offset + MESSAGE_HEADER_SIZE + (8 * field_index) } +pub fn serialize_error(buf: &mut ByteBuffer, err: ZError) { + buf.write_at(0, SENTINEL) + .expect("Failed to serialize SENTINEL"); + buf.write_at(4, SERIALIZE_HEADER_SIZE) + .expect("Failed to serialize size"); + buf.write_at(8, err as u64) + .expect("Failed to serialize error"); +} + pub trait YunqMessage { fn parse( buf: &ByteBuffer, @@ -31,11 +41,6 @@ pub trait YunqMessage { return Err(ZError::INVALID_RESPONSE); } - let resp_code: u64 = buf.at(8)?; - if resp_code != 0 { - return Err(ZError::from(resp_code)); - } - Ok(Self::parse(&buf, 16, &caps)?) } diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs new file mode 100644 index 0000000..c8c4f36 --- /dev/null +++ b/rust/lib/yunq/src/server.rs @@ -0,0 +1,46 @@ +use crate::buffer::ByteBuffer; +use alloc::vec::Vec; +use mammoth::syscall; +use mammoth::zion::z_cap_t; +use mammoth::zion::ZError; + +pub trait YunqServer { + fn server_loop(&self) { + loop { + let mut byte_buffer = ByteBuffer::<1024>::new(); + let mut cap_buffer = vec![0; 10]; + let (_, _, reply_port_cap) = syscall::endpoint_recv( + self.endpoint_cap(), + byte_buffer.mut_slice(), + &mut cap_buffer, + ) + .expect("Failed to call endpoint recv"); + + let method = byte_buffer + .at::(8) + .expect("Failed to access request length."); + let resp = self.handle_request(method, &mut byte_buffer, &mut cap_buffer); + match resp { + Ok(resp_len) => syscall::reply_port_send( + reply_port_cap, + byte_buffer.slice(resp_len), + &cap_buffer, + ) + .expect("Failed to reply"), + Err(err) => { + crate::message::serialize_error(&mut byte_buffer, err); + syscall::reply_port_send(reply_port_cap, &byte_buffer.slice(0x10), &[]) + .expect("Failed to reply w/ error") + } + } + } + } + + fn endpoint_cap(&self) -> z_cap_t; + fn handle_request( + &self, + method_number: u64, + byte_buffer: &mut ByteBuffer<1024>, + cap_buffer: &mut Vec, + ) -> Result; +} diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml index 66b00a9..7934e6c 100644 --- a/rust/usr/testbed/Cargo.toml +++ b/rust/usr/testbed/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } yellowstone = { path = "../../lib/yellowstone" } +yunq = { path = "../../lib/yunq" } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 661c98b..1b27a05 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -8,11 +8,46 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::thread; use mammoth::zion::z_err_t; +use mammoth::zion::ZError; use yellowstone::GetEndpointRequest; use yellowstone::YellowstoneClient; +use yellowstone::YellowstoneServer; +use yunq::server::YunqServer; define_entry!(); +struct YellowstoneImpl {} + +impl yellowstone::YellowstoneServerHandler for YellowstoneImpl { + fn register_endpoint(&self, req: &yellowstone::RegisterEndpointRequest) -> Result<(), ZError> { + debug!("{}", req.endpoint_name); + Ok(()) + } + + fn get_endpoint(&self, req: &GetEndpointRequest) -> Result { + debug!("{}", req.endpoint_name); + Ok(yellowstone::Endpoint { + endpoint: unsafe { mammoth::init::SELF_PROC_CAP }, + }) + } + + fn get_ahci_info(&self) -> Result { + todo!() + } + + fn get_xhci_info(&self) -> Result { + todo!() + } + + fn get_framebuffer_info(&self) -> Result { + todo!() + } + + fn get_denali(&self) -> Result { + todo!() + } +} + #[no_mangle] pub extern "C" fn main() -> z_err_t { debug!("Testing!"); @@ -33,9 +68,25 @@ pub extern "C" fn main() -> z_err_t { let e: thread::ThreadEntry = |_| { debug!("Testing 1 2 3"); }; - let t = thread::Thread::spawn(&e, core::ptr::null()).expect("Failed to spawn thread"); + let t = thread::Thread::spawn(e, core::ptr::null()).expect("Failed to spawn thread"); t.join().expect("Failed to wait."); + let server = YellowstoneServer::new(YellowstoneImpl {}).expect("Failed to create server"); + + let mut yellowstone = YellowstoneClient::new(server.endpoint_cap()); + + let t = server.run_server().expect("Failed to start server"); + + let endpoint = yellowstone + .get_endpoint(&GetEndpointRequest { + endpoint_name: "test".to_string(), + }) + .expect("Failed to get endpoint"); + + debug!("{:#x}", endpoint.endpoint); + + t.join().expect("Failed to wait"); + 0 } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 1f4bc64..31f61e4 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -50,7 +50,7 @@ fn generate_method(method: &Method) -> TokenStream { } } -fn generate_interface(interface: &Interface) -> TokenStream { +fn generate_client(interface: &Interface) -> TokenStream { let client_name = interface.name.clone() + "Client"; let name = ident(&client_name); let methods = interface.methods.iter().map(|m| generate_method(&m)); @@ -73,17 +73,144 @@ fn generate_interface(interface: &Interface) -> TokenStream { } } +fn generate_server_case(method: &Method) -> TokenStream { + let id = proc_macro2::Literal::u64_suffixed(method.number); + let name = ident(&method.name.to_case(Case::Snake)); + let maybe_req = method.request.clone().map(|r| ident(&r)); + let maybe_resp = method.response.clone().map(|r| ident(&r)); + match (maybe_req, maybe_resp) { + (Some(req), Some(_)) => quote! { + #id => { + let req = #req::parse_from_request(byte_buffer, cap_buffer)?; + let resp = self.handler.#name(&req)?; + cap_buffer.resize(0, 0); + let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; + Ok(resp_len) + }, + }, + (Some(req), None) => quote! { + #id => { + let req = #req::parse_from_request(byte_buffer, cap_buffer)?; + self.handler.#name(&req)?; + cap_buffer.resize(0, 0); + // TODO: Implement serialization for EmptyMessage so this is less hacky. + yunq::message::serialize_error(byte_buffer, ZError::from(0)); + Ok(0x10) + }, + }, + (None, Some(_)) => quote! { + #id => { + let resp = self.handler.#name()?; + cap_buffer.resize(0, 0); + let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; + Ok(resp_len) + }, + }, + _ => unreachable!(), + } +} + +fn generate_server_method(method: &Method) -> TokenStream { + let name = ident(&method.name.to_case(Case::Snake)); + let maybe_req = method.request.clone().map(|r| ident(&r)); + let maybe_resp = method.response.clone().map(|r| ident(&r)); + match (maybe_req, maybe_resp) { + (Some(req), Some(resp)) => quote! { + fn #name (&self, req: & #req) -> Result<#resp, ZError>; + }, + (Some(req), None) => quote! { + fn #name (&self, req: & #req) -> Result<(), ZError>; + }, + (None, Some(resp)) => quote! { + fn #name (&self) -> Result<#resp, ZError>; + }, + _ => unreachable!(), + } +} + +fn generate_server(interface: &Interface) -> TokenStream { + let server_name = ident(&(interface.name.clone() + "Server")); + let server_trait = ident(&(interface.name.clone() + "ServerHandler")); + let server_trait_methods = interface.methods.iter().map(|m| generate_server_method(&m)); + let server_match_cases = interface.methods.iter().map(|m| generate_server_case(&m)); + quote! { + pub trait #server_trait { + #(#server_trait_methods)* + } + + pub struct #server_name { + endpoint_cap: z_cap_t, + handler: T + } + + impl #server_name { + pub fn new(handler: T) -> Result { + Ok(Self { + endpoint_cap: syscall::endpoint_create()?, + handler, + }) + } + + pub fn run_server(&self) -> Result, ZError> { + let thread_entry = |server_ptr: *const c_void| { + let server = unsafe { (server_ptr as *const #server_name).as_ref().expect("Failed to convert to server") }; + server.server_loop(); + }; + thread::Thread::spawn( + thread_entry, + self as *const Self as *const core::ffi::c_void, + ) + } + } + + impl yunq::server::YunqServer for #server_name { + fn endpoint_cap(&self) -> z_cap_t { + self.endpoint_cap + } + + fn handle_request( + &self, + method_number: u64, + byte_buffer: &mut ByteBuffer<1024>, + cap_buffer: &mut Vec, + ) -> Result { + match method_number { + #(#server_match_cases)* + + _ => Err(ZError::UNIMPLEMENTED) + } + } + } + } +} + +fn generate_interface(interface: &Interface) -> TokenStream { + let client = generate_client(interface); + let server = generate_server(interface); + quote! { + #client + + #server + } +} + pub fn generate_code(ast: &Vec) -> String { let prelude = quote! { extern crate alloc; + use alloc::boxed::Box; use alloc::string::String; use alloc::string::ToString; + use alloc::vec::Vec; + use core::ffi::c_void; + use mammoth::syscall; + use mammoth::thread; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; use yunq::ByteBuffer; use yunq::YunqMessage; + use yunq::server::YunqServer; use yunq_derive::YunqMessage; }; diff --git a/zion/include/zcall.h b/zion/include/zcall.h index c5f9ca6..31e45df 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -56,7 +56,7 @@ SYS6(EndpointSend, z_cap_t, endpoint_cap, uint64_t, num_bytes, const void*, SYS6(EndpointRecv, z_cap_t, endpoint_cap, uint64_t*, num_bytes, void*, data, uint64_t*, num_caps, z_cap_t*, caps, z_cap_t*, reply_port_cap); SYS5(ReplyPortSend, z_cap_t, reply_port_cap, uint64_t, num_bytes, const void*, - data, uint64_t, num_caps, z_cap_t*, caps); + data, uint64_t, num_caps, const z_cap_t*, caps); SYS5(ReplyPortRecv, z_cap_t, reply_port_cap, uint64_t*, num_bytes, void*, data, uint64_t*, num_caps, z_cap_t*, caps); From 18e512cf1f9c9bfe95b4e3ad4f53b0fa792fcb6c Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 12 Aug 2024 11:35:54 -0700 Subject: [PATCH 104/186] [Teton] Move console/shell to rust. WIP --- .gitignore | 2 + rust/Cargo.lock | 20 +++++++++ rust/Cargo.toml | 2 +- rust/lib/mammoth/src/mem.rs | 56 +++++++++++++++++++++++ rust/lib/mammoth/src/syscall.rs | 40 +++++++++++++++++ rust/lib/victoriafalls/Cargo.toml | 15 +++++++ rust/lib/victoriafalls/build.rs | 14 ++++++ rust/lib/victoriafalls/src/file.rs | 42 ++++++++++++++++++ rust/lib/victoriafalls/src/lib.rs | 7 +++ rust/lib/yellowstone/src/lib.rs | 14 ++++++ rust/lib/yunq/src/message.rs | 4 +- rust/sys/teton/Cargo.toml | 9 ++++ rust/sys/teton/src/console.rs | 18 ++++++++ rust/sys/teton/src/framebuffer.rs | 38 ++++++++++++++++ rust/sys/teton/src/main.rs | 50 +++++++++++++++++++++ rust/sys/teton/src/psf.rs | 71 ++++++++++++++++++++++++++++++ scripts/qemu.sh | 12 ++++- 17 files changed, 409 insertions(+), 5 deletions(-) create mode 100644 rust/lib/victoriafalls/Cargo.toml create mode 100644 rust/lib/victoriafalls/build.rs create mode 100644 rust/lib/victoriafalls/src/file.rs create mode 100644 rust/lib/victoriafalls/src/lib.rs create mode 100644 rust/sys/teton/Cargo.toml create mode 100644 rust/sys/teton/src/console.rs create mode 100644 rust/sys/teton/src/framebuffer.rs create mode 100644 rust/sys/teton/src/main.rs create mode 100644 rust/sys/teton/src/psf.rs diff --git a/.gitignore b/.gitignore index 9e8c8ee..10c91f1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,8 @@ compile_commands.json sysroot/bin sysroot/usr +sysroot/.crates.toml +sysroot/.crates2.json rust/target yunq/venv diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3f089b0..840f030 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -117,6 +117,15 @@ dependencies = [ "yunq", ] +[[package]] +name = "teton" +version = "0.1.0" +dependencies = [ + "mammoth", + "victoriafalls", + "yellowstone", +] + [[package]] name = "unicode-ident" version = "1.0.12" @@ -129,6 +138,17 @@ version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +[[package]] +name = "victoriafalls" +version = "0.1.0" +dependencies = [ + "mammoth", + "yellowstone", + "yunq", + "yunq-derive", + "yunqc", +] + [[package]] name = "yellowstone" version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b27a0fb..eb3c943 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "lib/mammoth", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "usr/testbed", + "lib/mammoth", "lib/victoriafalls", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 750365d..dd1834c 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -1,4 +1,6 @@ use crate::syscall; +use crate::zion::{z_cap_t, ZError}; +use alloc::slice; use linked_list_allocator::LockedHeap; #[global_allocator] @@ -16,3 +18,57 @@ pub fn init_heap() { CAN_ALLOC = true; } } + +pub struct MemoryRegion { + mem_cap: z_cap_t, + virt_addr: u64, + size: u64, +} + +impl MemoryRegion { + pub fn direct_physical(paddr: u64, size: u64) -> Result { + let mem_cap = syscall::memory_object_direct_physical(paddr, size)?; + let virt_addr = syscall::address_space_map(mem_cap)?; + Ok(Self { + mem_cap, + virt_addr, + size, + }) + } + + pub fn from_cap(mem_cap: z_cap_t) -> Result { + let virt_addr = syscall::address_space_map(mem_cap)?; + let size = syscall::memory_object_inspect(mem_cap)?; + Ok(Self { + mem_cap, + virt_addr, + size, + }) + } + + pub fn slice(&self) -> &[T] { + unsafe { + slice::from_raw_parts( + self.virt_addr as *const T, + self.size as usize / size_of::(), + ) + } + } + + pub fn mut_slice(&self) -> &mut [T] { + unsafe { + slice::from_raw_parts_mut( + self.virt_addr as *mut T, + self.size as usize / size_of::(), + ) + } + } +} + +impl Drop for MemoryRegion { + fn drop(&mut self) { + syscall::address_space_unmap(self.virt_addr, self.virt_addr + self.size) + .expect("Failed to unmap memory"); + syscall::cap_release(self.mem_cap).expect("Failed to release memory cap"); + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 86765af..a41b761 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -89,6 +89,31 @@ pub fn memory_object_create(size: u64) -> Result { Ok(vmmo_cap) } +pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result { + let mut vmmo_cap = 0; + syscall( + zion::kZionMemoryObjectCreatePhysical, + &zion::ZMemoryObjectCreatePhysicalReq { + paddr, + size, + vmmo_cap: &mut vmmo_cap, + }, + )?; + Ok(vmmo_cap) +} + +pub fn memory_object_inspect(mem_cap: z_cap_t) -> Result { + let mut mem_size = 0; + syscall( + zion::kZionMemoryObjectInspect, + &zion::ZMemoryObjectInspectReq { + vmmo_cap: mem_cap, + size: &mut mem_size, + }, + )?; + Ok(mem_size) +} + pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { let mut vaddr: u64 = 0; // FIXME: Allow caller to pass these options. @@ -104,6 +129,17 @@ pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { Ok(vaddr) } +pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZError> { + syscall( + zion::kZionAddressSpaceUnmap, + &zion::ZAddressSpaceUnmapReq { + vmas_cap: unsafe { crate::init::SELF_VMAS_CAP }, + lower_addr, + upper_addr, + }, + ) +} + pub fn port_poll( port_cap: z_cap_t, bytes: &mut [u8], @@ -211,3 +247,7 @@ pub fn reply_port_recv( Ok((num_bytes, num_caps)) } + +pub fn cap_release(cap: z_cap_t) -> Result<(), ZError> { + syscall(zion::kZionCapRelease, &zion::ZCapReleaseReq { cap }) +} diff --git a/rust/lib/victoriafalls/Cargo.toml b/rust/lib/victoriafalls/Cargo.toml new file mode 100644 index 0000000..7f3566b --- /dev/null +++ b/rust/lib/victoriafalls/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "victoriafalls" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth" } +yellowstone = { path = "../yellowstone" } +yunq = {path = "../yunq"} +yunq-derive = {path = "../yunq-derive"} + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + + diff --git a/rust/lib/victoriafalls/build.rs b/rust/lib/victoriafalls/build.rs new file mode 100644 index 0000000..7e2d7d5 --- /dev/null +++ b/rust/lib/victoriafalls/build.rs @@ -0,0 +1,14 @@ +use std::fs; + +fn main() { + let input_file = "../../../sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + fs::write(out, code).expect("Failed to write generated code."); +} diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs new file mode 100644 index 0000000..ec6b190 --- /dev/null +++ b/rust/lib/victoriafalls/src/file.rs @@ -0,0 +1,42 @@ +use crate::OpenFileRequest; +use crate::VFSClient; +use alloc::string::ToString; +use mammoth::zion::ZError; + +static mut VFS_CLIENT: Option = None; + +fn get_client() -> &'static mut VFSClient { + unsafe { + if let None = VFS_CLIENT { + let endpoint_cap = yellowstone::from_init_endpoint() + .get_endpoint(&yellowstone::GetEndpointRequest { + endpoint_name: "victoriafalls".to_string(), + }) + .expect("Failed to get VFS endpoint"); + + VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint)); + } + VFS_CLIENT.as_mut().unwrap() + } +} + +pub struct File { + memory: mammoth::mem::MemoryRegion, +} + +impl File { + pub fn open(path: &str) -> Result { + let vfs = get_client(); + let resp = vfs.open_file(&OpenFileRequest { + path: path.to_string(), + })?; + + Ok(Self { + memory: mammoth::mem::MemoryRegion::from_cap(resp.memory)?, + }) + } + + pub fn slice(&self, offset: usize, len: usize) -> &[u8] { + &self.memory.slice()[offset..offset + len] + } +} diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/lib/victoriafalls/src/lib.rs new file mode 100644 index 0000000..e35a8ef --- /dev/null +++ b/rust/lib/victoriafalls/src/lib.rs @@ -0,0 +1,7 @@ +#![no_std] + +use core::include; + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +pub mod file; diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs index 3cec9d6..0fc673f 100644 --- a/rust/lib/yellowstone/src/lib.rs +++ b/rust/lib/yellowstone/src/lib.rs @@ -3,3 +3,17 @@ use core::include; include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +use mammoth::init::INIT_ENDPOINT; + +static mut YELLOWSTONE_INIT: Option = None; + +pub fn from_init_endpoint() -> &'static mut YellowstoneClient { + unsafe { + if let None = YELLOWSTONE_INIT { + YELLOWSTONE_INIT = Some(YellowstoneClient::new(INIT_ENDPOINT)); + } + + YELLOWSTONE_INIT.as_mut().unwrap() + } +} diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 7b84b8d..44ca368 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -79,7 +79,7 @@ impl YunqMessage for Empty { where Self: Sized, { - todo!() + Ok(Self {}) } fn serialize( @@ -88,6 +88,6 @@ impl YunqMessage for Empty { _offset: usize, _caps: &mut Vec, ) -> Result { - todo!() + Ok(0) } } diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml new file mode 100644 index 0000000..2b897ce --- /dev/null +++ b/rust/sys/teton/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "teton" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../../lib/mammoth" } +victoriafalls = { path = "../../lib/victoriafalls" } +yellowstone = { path = "../../lib/yellowstone" } diff --git a/rust/sys/teton/src/console.rs b/rust/sys/teton/src/console.rs new file mode 100644 index 0000000..c6e0ccb --- /dev/null +++ b/rust/sys/teton/src/console.rs @@ -0,0 +1,18 @@ +use crate::framebuffer::Framebuffer; +use crate::psf::Psf; + +pub struct Console { + framebuffer: Framebuffer, + psf: Psf, +} + +impl Console { + pub fn new(framebuffer: Framebuffer, psf: Psf) -> Self { + Self { framebuffer, psf } + } + + pub fn write_char(&self, c: char) { + let glyph = self.psf.glyph(c as u32); + self.framebuffer.draw_glyph(glyph, 0, 0) + } +} diff --git a/rust/sys/teton/src/framebuffer.rs b/rust/sys/teton/src/framebuffer.rs new file mode 100644 index 0000000..268c573 --- /dev/null +++ b/rust/sys/teton/src/framebuffer.rs @@ -0,0 +1,38 @@ +use mammoth::{mem::MemoryRegion, zion::ZError}; +use yellowstone::FramebufferInfo; + +pub struct Framebuffer { + fb_info: FramebufferInfo, + memory_region: MemoryRegion, +} + +impl Framebuffer { + pub fn from_info(fb_info: FramebufferInfo) -> Result { + let size = fb_info.height * fb_info.pitch; + let memory_region = MemoryRegion::direct_physical(fb_info.address_phys, size)?; + Ok(Self { + fb_info, + memory_region, + }) + } + + fn draw_pixel(&self, row: u32, col: u32, pixel: u32) { + let index = row * (self.fb_info.pitch as u32 / 4) + col; + self.memory_region.mut_slice()[index as usize] = pixel; + } + + pub fn draw_glyph(&self, glyph: &[u8], row: u32, col: u32) { + let gl_width = 8; + let gl_height = 16; + + for r in 0..gl_height { + for c in 0..gl_width { + if ((glyph[r] >> c) % 2) == 1 { + self.draw_pixel(row + (r as u32), col + (gl_width - c - 1), 0xFFFFFFFF); + } else { + self.draw_pixel(row + (r as u32), col + (gl_width - c - 1), 0); + } + } + } + } +} diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs new file mode 100644 index 0000000..5599784 --- /dev/null +++ b/rust/sys/teton/src/main.rs @@ -0,0 +1,50 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +mod console; +mod framebuffer; +mod psf; + +use mammoth::{debug, define_entry, zion::z_err_t}; + +define_entry!(); + +#[no_mangle] +extern "C" fn main() -> z_err_t { + debug!("Teton Starting"); + + let yellowstone = yellowstone::from_init_endpoint(); + let framebuffer_info = yellowstone + .get_framebuffer_info() + .expect("Failed to get framebuffer info."); + + debug!( + "FB addr {:#x}, bpp {}, width {} , height {}, pitch {}", + framebuffer_info.address_phys, + framebuffer_info.bpp, + framebuffer_info.width, + framebuffer_info.height, + framebuffer_info.pitch + ); + + let framebuffer = framebuffer::Framebuffer::from_info(framebuffer_info) + .expect("Failed to create framebuffer"); + + let psf = psf::Psf::new("/default8x16.psfu").expect("Failed to open font file."); + let console = console::Console::new(framebuffer, psf); + console.write_char('>'); + + /* + + Terminal terminal(console); + terminal.Register(); + + Thread lthread = terminal.Listen(); + + check(lthread.Join()); + */ + + 0 +} diff --git a/rust/sys/teton/src/psf.rs b/rust/sys/teton/src/psf.rs new file mode 100644 index 0000000..6be3da5 --- /dev/null +++ b/rust/sys/teton/src/psf.rs @@ -0,0 +1,71 @@ +use mammoth::debug; +use mammoth::zion::ZError; +use victoriafalls::file::File; + +const MAGIC_HEADER: u32 = 0x864AB572; + +#[repr(C)] +struct PsfHeader { + magic: u32, /* magic bytes to identify PSF */ + version: u32, /* zero */ + headersize: u32, /* offset of bitmaps in file, 32 */ + flags: u32, /* 0 if there's no unicode table */ + numglyph: u32, /* number of glyphs */ + bytes_per_glyph: u32, /* size of each glyph */ + height: u32, /* height in pixels */ + width: u32, /* width in pixels */ +} + +pub struct Psf { + file: File, + header: &'static PsfHeader, +} + +impl Psf { + pub fn new(path: &str) -> Result { + let file = File::open(&path)?; + + let header = file + .slice(0, core::mem::size_of::()) + .as_ptr() + .cast(); + let psf = Self { + file, + header: unsafe { &*header }, + }; + + psf.validate()?; + + Ok(psf) + } + + fn validate(&self) -> Result<(), ZError> { + if self.header.magic != MAGIC_HEADER { + debug!("PSF: Magic value: {:x}", self.header.magic); + return Err(ZError::INVALID_ARGUMENT); + } + + if self.header.version != 0 { + debug!("PSF non-zero version"); + return Err(ZError::INVALID_ARGUMENT); + } + + if self.header.height != 0x10 { + debug!("PSF height other than 16 not handled"); + return Err(ZError::UNIMPLEMENTED); + } + + if self.header.width != 0x8 { + debug!("PSF width other than 8 not handled"); + return Err(ZError::UNIMPLEMENTED); + } + Ok(()) + } + + pub fn glyph(&self, index: u32) -> &[u8] { + let offset: usize = + (self.header.headersize + (index * self.header.bytes_per_glyph)) as usize; + let len: usize = self.header.bytes_per_glyph as usize; + &self.file.slice(offset, len) + } +} diff --git a/scripts/qemu.sh b/scripts/qemu.sh index 1fc4eb9..0ae6b41 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -12,11 +12,19 @@ pushd $BUILD_DIR ninja ninja install -export CARGO_INSTALL_ROOT="${DIR}/../sysroot/usr/" +CARGO_USR_ROOT="${DIR}/../sysroot/usr/" +CARGO_SYS_ROOT="${DIR}/../sysroot/" # Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml pushd "${DIR}/../rust" -cargo install --force --path "${DIR}/../rust/usr/testbed/" + +for BIN in ${DIR}/../rust/usr/*/; do + cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT +done + +for BIN in ${DIR}/../rust/sys/*/; do + cargo install --force --path "${BIN}" --root $CARGO_SYS_ROOT +done popd sudo sh ${DIR}/build_image.sh disk.img From f04e7208110779070d9016479368e048b0171724 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 13 Aug 2024 19:55:44 -0700 Subject: [PATCH 105/186] Typing in terminal is now supported in rust teton. --- rust/Cargo.lock | 12 ++ rust/Cargo.toml | 2 +- rust/lib/mammoth/src/lib.rs | 1 + rust/lib/mammoth/src/port.rs | 42 +++++ rust/lib/mammoth/src/syscall.rs | 44 +++++ rust/lib/voyageurs/Cargo.toml | 14 ++ rust/lib/voyageurs/build.rs | 14 ++ rust/lib/voyageurs/src/lib.rs | 8 + rust/lib/voyageurs/src/listener.rs | 262 +++++++++++++++++++++++++++++ rust/sys/teton/Cargo.toml | 1 + rust/sys/teton/src/console.rs | 49 +++++- rust/sys/teton/src/framebuffer.rs | 8 + rust/sys/teton/src/main.rs | 19 ++- rust/sys/teton/src/psf.rs | 8 + rust/sys/teton/src/terminal.rs | 18 ++ 15 files changed, 489 insertions(+), 13 deletions(-) create mode 100644 rust/lib/mammoth/src/port.rs create mode 100644 rust/lib/voyageurs/Cargo.toml create mode 100644 rust/lib/voyageurs/build.rs create mode 100644 rust/lib/voyageurs/src/lib.rs create mode 100644 rust/lib/voyageurs/src/listener.rs create mode 100644 rust/sys/teton/src/terminal.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 840f030..c1a17bd 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -123,6 +123,7 @@ version = "0.1.0" dependencies = [ "mammoth", "victoriafalls", + "voyageurs", "yellowstone", ] @@ -149,6 +150,17 @@ dependencies = [ "yunqc", ] +[[package]] +name = "voyageurs" +version = "0.1.0" +dependencies = [ + "mammoth", + "yellowstone", + "yunq", + "yunq-derive", + "yunqc", +] + [[package]] name = "yellowstone" version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index eb3c943..24f2adc 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "lib/mammoth", "lib/victoriafalls", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "usr/testbed", + "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 3cc833d..f58e774 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -10,6 +10,7 @@ pub mod macros; pub mod init; pub mod mem; +pub mod port; pub mod syscall; pub mod thread; pub mod zion; diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs new file mode 100644 index 0000000..bd25405 --- /dev/null +++ b/rust/lib/mammoth/src/port.rs @@ -0,0 +1,42 @@ +use crate::syscall::{cap_duplicate, cap_release, port_create, port_recv}; +use crate::zion::{kZionPerm_Read, z_cap_t, ZError}; + +pub struct PortServer { + port_cap: z_cap_t, +} + +impl PortServer { + pub fn new() -> Result { + Ok(Self { + port_cap: port_create()?, + }) + } + + pub fn create_client_cap(&self) -> Result { + cap_duplicate(self.port_cap, !kZionPerm_Read) + } + + pub fn recv_byte(&self) -> Result { + let mut caps: [z_cap_t; 0] = []; + let mut bytes: [u8; 1] = [0]; + + port_recv(self.port_cap, &mut bytes, &mut caps)?; + + Ok(bytes[0]) + } + + pub fn recv_u16(&self) -> Result { + let mut caps: [z_cap_t; 0] = []; + let mut bytes: [u8; 2] = [0; 2]; + + port_recv(self.port_cap, &mut bytes, &mut caps)?; + + Ok(u16::from_le_bytes(bytes)) + } +} + +impl Drop for PortServer { + fn drop(&mut self) { + cap_release(self.port_cap).expect("Failed to release port cap"); + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index a41b761..d0ea030 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -140,6 +140,37 @@ pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZErro ) } +pub fn port_create() -> Result { + let mut port_cap = 0; + syscall( + zion::kZionPortCreate, + &zion::ZPortCreateReq { + port_cap: &mut port_cap, + }, + )?; + Ok(port_cap) +} + +pub fn port_recv( + port_cap: z_cap_t, + bytes: &mut [u8], + caps: &mut [u64], +) -> Result<(u64, u64), ZError> { + let mut num_bytes = bytes.len() as u64; + let mut num_caps = caps.len() as u64; + syscall( + zion::kZionPortRecv, + &zion::ZPortRecvReq { + port_cap, + data: bytes.as_mut_ptr() as *mut c_void, + num_bytes: &mut num_bytes as *mut u64, + caps: caps.as_mut_ptr(), + num_caps: &mut num_caps as *mut u64, + }, + )?; + Ok((num_bytes, num_caps)) +} + pub fn port_poll( port_cap: z_cap_t, bytes: &mut [u8], @@ -248,6 +279,19 @@ pub fn reply_port_recv( Ok((num_bytes, num_caps)) } +pub fn cap_duplicate(cap: z_cap_t, perm_mask: u64) -> Result { + let mut new_cap = 0; + syscall( + zion::kZionCapDuplicate, + &zion::ZCapDuplicateReq { + cap_in: cap, + perm_mask, + cap_out: &mut new_cap, + }, + )?; + Ok(new_cap) +} + pub fn cap_release(cap: z_cap_t) -> Result<(), ZError> { syscall(zion::kZionCapRelease, &zion::ZCapReleaseReq { cap }) } diff --git a/rust/lib/voyageurs/Cargo.toml b/rust/lib/voyageurs/Cargo.toml new file mode 100644 index 0000000..a007692 --- /dev/null +++ b/rust/lib/voyageurs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "voyageurs" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth" } +yellowstone = { path = "../yellowstone" } +yunq = {path = "../yunq"} +yunq-derive = {path = "../yunq-derive"} + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + diff --git a/rust/lib/voyageurs/build.rs b/rust/lib/voyageurs/build.rs new file mode 100644 index 0000000..52b5dfc --- /dev/null +++ b/rust/lib/voyageurs/build.rs @@ -0,0 +1,14 @@ +use std::fs; + +fn main() { + let input_file = "../../../sys/voyageurs/lib/voyageurs/voyageurs.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + fs::write(out, code).expect("Failed to write generated code."); +} diff --git a/rust/lib/voyageurs/src/lib.rs b/rust/lib/voyageurs/src/lib.rs new file mode 100644 index 0000000..e92646c --- /dev/null +++ b/rust/lib/voyageurs/src/lib.rs @@ -0,0 +1,8 @@ +#![no_std] +#![feature(box_into_inner)] + +use core::include; + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +pub mod listener; diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs new file mode 100644 index 0000000..a64626e --- /dev/null +++ b/rust/lib/voyageurs/src/listener.rs @@ -0,0 +1,262 @@ +use core::cell::RefCell; + +use alloc::boxed::Box; +use alloc::rc::Rc; +use alloc::string::ToString; +use mammoth::port::PortServer; +use mammoth::thread::Thread; +use mammoth::zion::ZError; + +#[repr(u8)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +enum Keycode { + UnknownKeycode = 0x0, + + A = 0x1, + B = 0x2, + C = 0x3, + D = 0x4, + E = 0x5, + F = 0x6, + G = 0x7, + H = 0x8, + I = 0x9, + J = 0xA, + K = 0xB, + L = 0xC, + M = 0xD, + N = 0xE, + O = 0xF, + P = 0x10, + Q = 0x11, + R = 0x12, + S = 0x13, + T = 0x14, + U = 0x15, + V = 0x16, + W = 0x17, + X = 0x18, + Y = 0x19, + Z = 0x1A, + + NUM1 = 0x20, + NUM2 = 0x21, + NUM3 = 0x22, + NUM4 = 0x23, + NUM5 = 0x24, + NUM6 = 0x25, + NUM7 = 0x26, + NUM8 = 0x27, + NUM9 = 0x28, + NUM0 = 0x29, + + Space = 0x30, + Enter = 0x31, + Tab = 0x32, + Backspace = 0x33, + Delete = 0x34, + + Minus = 0x40, + Equals = 0x41, + LBrace = 0x42, + RBrace = 0x43, + BSlash = 0x44, + FSlash = 0x45, + Semicolon = 0x46, + Quote = 0x47, + Comma = 0x48, + Period = 0x49, + Backtick = 0x4A, + + LShift = 0x50, + RShift = 0x51, + LCtrl = 0x52, + RCtrl = 0x53, + LAlt = 0x54, + RAlt = 0x55, + Super = 0x56, + Esc = 0x57, + Up = 0x58, + Down = 0x59, + Left = 0x5A, + Right = 0x5B, +} + +impl Keycode { + fn from_scancode(scancode: u16) -> Self { + match scancode as u8 { + 0x04 => Keycode::A, + 0x05 => Keycode::B, + 0x06 => Keycode::C, + 0x07 => Keycode::D, + 0x08 => Keycode::E, + 0x09 => Keycode::F, + 0x0A => Keycode::G, + 0x0B => Keycode::H, + 0x0C => Keycode::I, + 0x0D => Keycode::J, + 0x0E => Keycode::K, + 0x0F => Keycode::L, + 0x10 => Keycode::M, + 0x11 => Keycode::N, + 0x12 => Keycode::O, + 0x13 => Keycode::P, + 0x14 => Keycode::Q, + 0x15 => Keycode::R, + 0x16 => Keycode::S, + 0x17 => Keycode::T, + 0x18 => Keycode::U, + 0x19 => Keycode::V, + 0x1A => Keycode::W, + 0x1B => Keycode::X, + 0x1C => Keycode::Y, + 0x1D => Keycode::Z, + 0x1E => Keycode::NUM1, + 0x1F => Keycode::NUM2, + 0x20 => Keycode::NUM3, + 0x21 => Keycode::NUM4, + 0x22 => Keycode::NUM5, + 0x23 => Keycode::NUM6, + 0x24 => Keycode::NUM7, + 0x25 => Keycode::NUM8, + 0x26 => Keycode::NUM9, + 0x27 => Keycode::NUM0, + 0x28 => Keycode::Enter, + 0x29 => Keycode::Esc, + 0x2A => Keycode::Backspace, + 0x2B => Keycode::Tab, + 0x2C => Keycode::Space, + 0x2D => Keycode::Minus, + 0x2E => Keycode::Equals, + 0x2F => Keycode::LBrace, + 0x30 => Keycode::RBrace, + 0x31 => Keycode::BSlash, + 0x33 => Keycode::Semicolon, + 0x34 => Keycode::Quote, + 0x35 => Keycode::Backtick, + 0x36 => Keycode::Comma, + 0x37 => Keycode::Period, + 0x38 => Keycode::FSlash, + 0x39 => Keycode::Esc, + _ => Keycode::UnknownKeycode, + } + } +} + +struct Modifiers(u8); + +impl Modifiers { + fn from_scancode(scancode: u16) -> Self { + Self((scancode >> 8) as u8) + } + + fn is_shift(&self) -> bool { + ((self.0 & 0x20) == 0x20) || ((self.0 & 0x2) == 0x2) + } +} + +fn into_char(keycode: Keycode, modifiers: Modifiers) -> char { + match keycode { + k if (Keycode::A..=Keycode::Z).contains(&k) => { + if modifiers.is_shift() { + let chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + chars.as_bytes()[k as usize - Keycode::A as usize] as char + } else { + let chars = "abcdefghijklmnopqrstuvwxyz"; + chars.as_bytes()[k as usize - Keycode::A as usize] as char + } + } + k if (Keycode::NUM1..=Keycode::NUM0).contains(&k) => { + if modifiers.is_shift() { + let chars = "!@#$%^&*()"; + chars.as_bytes()[k as usize - Keycode::NUM1 as usize] as char + } else { + let chars = "12345687890"; + chars.as_bytes()[k as usize - Keycode::NUM1 as usize] as char + } + } + k if (Keycode::Minus..=Keycode::Backtick).contains(&k) => { + if modifiers.is_shift() { + let chars = "_+{}|?:\"<>~"; + chars.as_bytes()[k as usize - Keycode::Minus as usize] as char + } else { + let chars = "-=[]\\/;',.`"; + chars.as_bytes()[k as usize - Keycode::Minus as usize] as char + } + } + Keycode::Enter => '\n', + Keycode::Space => ' ', + Keycode::Tab => '\t', + Keycode::Backspace => '\x08', + _ => '\0', + } +} + +pub trait KeyboardHandler { + fn handle_char(&mut self, c: char); +} + +pub struct KeyboardListener { + listen_port: PortServer, + listen_thread: Option>, + handler: Rc>, +} + +impl KeyboardListener { + pub fn new(handler: Rc>) -> Result, ZError> { + let mut listnr = Box::new(Self { + listen_port: PortServer::new()?, + listen_thread: None, + handler, + }); + + let voyageur_endpoint = yellowstone::from_init_endpoint() + .get_endpoint(&yellowstone::GetEndpointRequest { + endpoint_name: "voyageurs".to_string(), + })? + .endpoint; + + let mut voyageur_client = crate::VoyageursClient::new(voyageur_endpoint); + + voyageur_client.register_keyboard_listener(&crate::KeyboardListener { + port_capability: listnr.listen_port.create_client_cap()?, + })?; + + let thread_entry = |self_raw| { + let listener = unsafe { + (self_raw as *mut KeyboardListener) + .as_mut() + .expect("Failed to convert to keyboard listener") + }; + listener.listen_loop(); + }; + + listnr.listen_thread = Some(Thread::spawn( + thread_entry, + &*listnr as *const Self as *const core::ffi::c_void, + )?); + + Ok(listnr) + } + + fn listen_loop(&mut self) { + loop { + let scancode = self + .listen_port + .recv_u16() + .expect("Failed to recieve scancode"); + + let keycode = Keycode::from_scancode(scancode); + let modifiers = Modifiers::from_scancode(scancode); + + self.handler + .as_ref() + .borrow_mut() + .handle_char(into_char(keycode, modifiers)) + } + } + + pub fn join(&self) -> Result<(), ZError> { + self.listen_thread.as_ref().unwrap().join() + } +} diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml index 2b897ce..a355119 100644 --- a/rust/sys/teton/Cargo.toml +++ b/rust/sys/teton/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } victoriafalls = { path = "../../lib/victoriafalls" } +voyageurs = { path = "../../lib/voyageurs" } yellowstone = { path = "../../lib/yellowstone" } diff --git a/rust/sys/teton/src/console.rs b/rust/sys/teton/src/console.rs index c6e0ccb..e90e841 100644 --- a/rust/sys/teton/src/console.rs +++ b/rust/sys/teton/src/console.rs @@ -4,15 +4,56 @@ use crate::psf::Psf; pub struct Console { framebuffer: Framebuffer, psf: Psf, + row: u32, + col: u32, } impl Console { pub fn new(framebuffer: Framebuffer, psf: Psf) -> Self { - Self { framebuffer, psf } + Self { + framebuffer, + psf, + row: 0, + col: 0, + } } - pub fn write_char(&self, c: char) { - let glyph = self.psf.glyph(c as u32); - self.framebuffer.draw_glyph(glyph, 0, 0) + fn incr_cursor(&mut self) { + self.col += 1; + if self.col >= self.cols() { + self.col = 0; + self.row += 1; + } + + if self.row >= self.rows() { + panic!("Scroll unimplemented") + } + } + + pub fn write_char(&mut self, chr: char) { + if chr == '\x08' { + // Backspace. + if self.col > 1 { + self.col -= 1; + self.write_char(' '); + self.col -= 1; + } + return; + } + let glyph = self.psf.glyph(chr as u32); + self.framebuffer.draw_glyph( + glyph, + self.row * (self.psf.height() + 1), + self.col * (self.psf.width() + 1), + ); + self.incr_cursor() + } + + fn cols(&self) -> u32 { + self.framebuffer.width() / (self.psf.width() + 1) + } + + fn rows(&self) -> u32 { + self.framebuffer.height() / (self.psf.height() + 1) } } diff --git a/rust/sys/teton/src/framebuffer.rs b/rust/sys/teton/src/framebuffer.rs index 268c573..856b0c1 100644 --- a/rust/sys/teton/src/framebuffer.rs +++ b/rust/sys/teton/src/framebuffer.rs @@ -35,4 +35,12 @@ impl Framebuffer { } } } + + pub fn width(&self) -> u32 { + self.fb_info.width as u32 + } + + pub fn height(&self) -> u32 { + self.fb_info.height as u32 + } } diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs index 5599784..73765a5 100644 --- a/rust/sys/teton/src/main.rs +++ b/rust/sys/teton/src/main.rs @@ -6,8 +6,13 @@ extern crate alloc; mod console; mod framebuffer; mod psf; +mod terminal; +use core::cell::RefCell; + +use alloc::rc::Rc; use mammoth::{debug, define_entry, zion::z_err_t}; +use voyageurs::listener::KeyboardListener; define_entry!(); @@ -33,18 +38,16 @@ extern "C" fn main() -> z_err_t { .expect("Failed to create framebuffer"); let psf = psf::Psf::new("/default8x16.psfu").expect("Failed to open font file."); - let console = console::Console::new(framebuffer, psf); + let mut console = console::Console::new(framebuffer, psf); console.write_char('>'); - /* + let terminal = Rc::new(RefCell::new(terminal::Terminal::new(console))); - Terminal terminal(console); - terminal.Register(); + let kb_listener = KeyboardListener::new(terminal).expect("Failed to create keyboard listener"); - Thread lthread = terminal.Listen(); - - check(lthread.Join()); - */ + kb_listener + .join() + .expect("Failed to wait on keyboard listener"); 0 } diff --git a/rust/sys/teton/src/psf.rs b/rust/sys/teton/src/psf.rs index 6be3da5..f27aba4 100644 --- a/rust/sys/teton/src/psf.rs +++ b/rust/sys/teton/src/psf.rs @@ -68,4 +68,12 @@ impl Psf { let len: usize = self.header.bytes_per_glyph as usize; &self.file.slice(offset, len) } + + pub fn width(&self) -> u32 { + self.header.width + } + + pub fn height(&self) -> u32 { + self.header.height + } } diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs new file mode 100644 index 0000000..436fd48 --- /dev/null +++ b/rust/sys/teton/src/terminal.rs @@ -0,0 +1,18 @@ +use crate::console::Console; +use voyageurs::listener::KeyboardHandler; + +pub struct Terminal { + console: Console, +} + +impl KeyboardHandler for Terminal { + fn handle_char(&mut self, c: char) { + self.console.write_char(c) + } +} + +impl Terminal { + pub fn new(console: Console) -> Self { + Self { console } + } +} From c155247f1d48981119bcb1d539644c6c3e2445f0 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 14 Aug 2024 07:49:06 -0700 Subject: [PATCH 106/186] [Teton] Terminal now owns the command str. --- rust/sys/teton/src/console.rs | 43 +++++------------- rust/sys/teton/src/main.rs | 4 +- rust/sys/teton/src/terminal.rs | 80 +++++++++++++++++++++++++++++++++- 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/rust/sys/teton/src/console.rs b/rust/sys/teton/src/console.rs index e90e841..2e282dc 100644 --- a/rust/sys/teton/src/console.rs +++ b/rust/sys/teton/src/console.rs @@ -4,56 +4,33 @@ use crate::psf::Psf; pub struct Console { framebuffer: Framebuffer, psf: Psf, - row: u32, - col: u32, } impl Console { pub fn new(framebuffer: Framebuffer, psf: Psf) -> Self { - Self { - framebuffer, - psf, - row: 0, - col: 0, - } + Self { framebuffer, psf } } - fn incr_cursor(&mut self) { - self.col += 1; - if self.col >= self.cols() { - self.col = 0; - self.row += 1; + pub fn write_char(&mut self, chr: char, row: u32, col: u32) { + if row >= self.rows() { + panic!("Write at row {}, max is {}", row, self.rows()) } - - if self.row >= self.rows() { - panic!("Scroll unimplemented") - } - } - - pub fn write_char(&mut self, chr: char) { - if chr == '\x08' { - // Backspace. - if self.col > 1 { - self.col -= 1; - self.write_char(' '); - self.col -= 1; - } - return; + if col >= self.cols() { + panic!("Write at col {}, max is {}", col, self.cols()) } let glyph = self.psf.glyph(chr as u32); self.framebuffer.draw_glyph( glyph, - self.row * (self.psf.height() + 1), - self.col * (self.psf.width() + 1), + row * (self.psf.height() + 1), + col * (self.psf.width() + 1), ); - self.incr_cursor() } - fn cols(&self) -> u32 { + pub fn cols(&self) -> u32 { self.framebuffer.width() / (self.psf.width() + 1) } - fn rows(&self) -> u32 { + pub fn rows(&self) -> u32 { self.framebuffer.height() / (self.psf.height() + 1) } } diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs index 73765a5..b1866d2 100644 --- a/rust/sys/teton/src/main.rs +++ b/rust/sys/teton/src/main.rs @@ -38,9 +38,7 @@ extern "C" fn main() -> z_err_t { .expect("Failed to create framebuffer"); let psf = psf::Psf::new("/default8x16.psfu").expect("Failed to open font file."); - let mut console = console::Console::new(framebuffer, psf); - console.write_char('>'); - + let console = console::Console::new(framebuffer, psf); let terminal = Rc::new(RefCell::new(terminal::Terminal::new(console))); let kb_listener = KeyboardListener::new(terminal).expect("Failed to create keyboard listener"); diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 436fd48..1823de7 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -1,18 +1,94 @@ +use core::str::Split; + use crate::console::Console; +use alloc::{ + format, + string::{String, ToString}, +}; use voyageurs::listener::KeyboardHandler; pub struct Terminal { console: Console, + curr_cmd: String, + cwd: String, + row: u32, } impl KeyboardHandler for Terminal { fn handle_char(&mut self, c: char) { - self.console.write_char(c) + let mut should_execute = false; + match c { + '\x08' => { + let mut chars = self.curr_cmd.chars(); + chars.next_back(); // Pop last char. + self.curr_cmd = chars.collect(); + } + '\n' => should_execute = true, + _ => self.curr_cmd.push(c), + } + self.rewrite_command(); + if should_execute { + self.execute_command(); + self.rewrite_command(); + } } } impl Terminal { pub fn new(console: Console) -> Self { - Self { console } + let mut term = Self { + console, + curr_cmd: String::new(), + cwd: "/".to_string(), + row: 0, + }; + term.rewrite_command(); + term + } + + fn rewrite_command(&mut self) { + self.console.write_char('>', self.row, 0); + + let mut col = 1; + for c in self.curr_cmd.chars() { + self.console.write_char(c, self.row, col); + col += 1; + } + + // Hacky way to properly backspace. + // FIXME: This won't work once we have line wrapping. + self.console.write_char(' ', self.row, col) + } + + fn write_line(&mut self, line: &str) { + let mut col = 0; + for c in line.chars() { + self.console.write_char(c, self.row, col); + col += 1; + } + + self.row += 1 + } + + fn execute_command(&mut self) { + self.row += 1; + + let curr_cmd = self.curr_cmd.clone(); + let mut tokens = curr_cmd.split(' '); + + match tokens.next() { + None => {} + Some(command) => self.execute_command_parsed(command, tokens), + } + + self.curr_cmd.clear() + } + + fn execute_command_parsed(&mut self, cmd: &str, _args: Split<'_, char>) { + match cmd { + "help" => self.write_line("Available commands are 'pwd', 'ls', 'cd', and 'exec'"), + "pwd" => self.write_line(&self.cwd.clone()), + _ => self.write_line(&format!("Unrecognized command: {}", cmd)), + } } } From f5a27156d2ea44f60581f6e879443252bd334559 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 14 Aug 2024 08:47:29 -0700 Subject: [PATCH 107/186] [Teton] Add ls and cd commands to rust impl. --- rust/lib/victoriafalls/src/dir.rs | 27 +++++++++++++++++++++++++++ rust/lib/victoriafalls/src/file.rs | 20 +------------------- rust/lib/victoriafalls/src/lib.rs | 18 ++++++++++++++++++ rust/sys/teton/src/terminal.rs | 26 +++++++++++++++++++++++++- 4 files changed, 71 insertions(+), 20 deletions(-) create mode 100644 rust/lib/victoriafalls/src/dir.rs diff --git a/rust/lib/victoriafalls/src/dir.rs b/rust/lib/victoriafalls/src/dir.rs new file mode 100644 index 0000000..fb6efeb --- /dev/null +++ b/rust/lib/victoriafalls/src/dir.rs @@ -0,0 +1,27 @@ +use alloc::{ + string::{String, ToString as _}, + vec::Vec, +}; +use mammoth::zion::ZError; + +pub fn exists(path: &str) -> Result { + let vfs = crate::get_client(); + let result = vfs.get_directory(&crate::GetDirectoryRequest { + path: path.to_string(), + }); + + match result { + Ok(_) => Ok(true), + Err(ZError::NOT_FOUND) => Ok(false), + Err(e) => Err(e), + } +} + +pub fn ls(path: &str) -> Result, ZError> { + let vfs = crate::get_client(); + let result = vfs.get_directory(&crate::GetDirectoryRequest { + path: path.to_string(), + })?; + + Ok(result.filenames.split(',').map(|s| s.to_string()).collect()) +} diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs index ec6b190..2f37990 100644 --- a/rust/lib/victoriafalls/src/file.rs +++ b/rust/lib/victoriafalls/src/file.rs @@ -1,32 +1,14 @@ use crate::OpenFileRequest; -use crate::VFSClient; use alloc::string::ToString; use mammoth::zion::ZError; -static mut VFS_CLIENT: Option = None; - -fn get_client() -> &'static mut VFSClient { - unsafe { - if let None = VFS_CLIENT { - let endpoint_cap = yellowstone::from_init_endpoint() - .get_endpoint(&yellowstone::GetEndpointRequest { - endpoint_name: "victoriafalls".to_string(), - }) - .expect("Failed to get VFS endpoint"); - - VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint)); - } - VFS_CLIENT.as_mut().unwrap() - } -} - pub struct File { memory: mammoth::mem::MemoryRegion, } impl File { pub fn open(path: &str) -> Result { - let vfs = get_client(); + let vfs = crate::get_client(); let resp = vfs.open_file(&OpenFileRequest { path: path.to_string(), })?; diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/lib/victoriafalls/src/lib.rs index e35a8ef..b1532a9 100644 --- a/rust/lib/victoriafalls/src/lib.rs +++ b/rust/lib/victoriafalls/src/lib.rs @@ -4,4 +4,22 @@ use core::include; include!(concat!(env!("OUT_DIR"), "/yunq.rs")); +pub mod dir; pub mod file; + +static mut VFS_CLIENT: Option = None; + +fn get_client() -> &'static mut VFSClient { + unsafe { + if let None = VFS_CLIENT { + let endpoint_cap = yellowstone::from_init_endpoint() + .get_endpoint(&yellowstone::GetEndpointRequest { + endpoint_name: "victoriafalls".to_string(), + }) + .expect("Failed to get VFS endpoint"); + + VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint)); + } + VFS_CLIENT.as_mut().unwrap() + } +} diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 1823de7..4ecdc28 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -5,6 +5,7 @@ use alloc::{ format, string::{String, ToString}, }; +use victoriafalls::dir; use voyageurs::listener::KeyboardHandler; pub struct Terminal { @@ -84,10 +85,33 @@ impl Terminal { self.curr_cmd.clear() } - fn execute_command_parsed(&mut self, cmd: &str, _args: Split<'_, char>) { + fn execute_command_parsed(&mut self, cmd: &str, mut args: Split<'_, char>) { + // TODO: Check that no extraneous params are provided. match cmd { "help" => self.write_line("Available commands are 'pwd', 'ls', 'cd', and 'exec'"), "pwd" => self.write_line(&self.cwd.clone()), + "cd" => match args.next() { + None => self.write_line("Specify a directory"), + Some(directory) => match dir::exists(directory) { + Ok(true) => self.cwd = directory.to_string(), + Ok(false) => self.write_line(&format!("Directory not found: {}", directory)), + Err(e) => self.write_line(&format!("Error stating directory {:?}", e)), + }, + }, + "ls" => { + let use_dir = match args.next() { + None => self.cwd.clone(), + Some(d) => d.to_string(), + }; + match dir::ls(&use_dir) { + Err(e) => self.write_line(&format!("Error reading directory {:?}", e)), + Ok(files) => { + for file in files { + self.write_line(&file); + } + } + } + } _ => self.write_line(&format!("Unrecognized command: {}", cmd)), } } From 71431189c9c3900d93ae55967c14fd0f8bfd5b2e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 12:53:25 -0700 Subject: [PATCH 108/186] [Zion] Ensure memory alignment of large allocations. --- zion/memory/kernel_heap.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/zion/memory/kernel_heap.cpp b/zion/memory/kernel_heap.cpp index 6ad518a..68b9b24 100644 --- a/zion/memory/kernel_heap.cpp +++ b/zion/memory/kernel_heap.cpp @@ -91,6 +91,11 @@ void* KernelHeap::Allocate(uint64_t size) { uint64_t address = next_addr_; alloc_count_ += 1; next_addr_ += size; + + // Ensure alingment for these pointers. + if (next_addr_ & 0x7) { + next_addr_ = (next_addr_ & ~0x7) + 0x8; + } return reinterpret_cast(address); } From 8206e671cdb4e621648c5dd7989a581c3df4db20 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 12:54:09 -0700 Subject: [PATCH 109/186] [Zion] Add extra message for when unmap fails. --- zion/lib/memory_mapping_tree.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zion/lib/memory_mapping_tree.cpp b/zion/lib/memory_mapping_tree.cpp index 91259ff..d4b2dac 100644 --- a/zion/lib/memory_mapping_tree.cpp +++ b/zion/lib/memory_mapping_tree.cpp @@ -45,11 +45,15 @@ glcr::ErrorCode MemoryMappingTree::FreeMemoryRange(uint64_t vaddr_base, } auto predecessor_or = mapping_tree_.Predecessor(vaddr_base); if (predecessor_or && predecessor_or.value().get().vaddr_limit > vaddr_base) { + dbgln("Free memory Predecessor check failed: {x} > {x}", + predecessor_or.value().get().vaddr_limit, vaddr_base); return glcr::FAILED_PRECONDITION; } auto last_predecessor_or = mapping_tree_.Predecessor(vaddr_limit); if (last_predecessor_or && last_predecessor_or.value().get().vaddr_limit > vaddr_limit) { + dbgln("Free memory Last Predecessor check failed: {x} > {x}", + last_predecessor_or.value().get().vaddr_limit, vaddr_limit); return glcr::FAILED_PRECONDITION; } From 006f9f8ac57b709d003ce05533536ba0399df723 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 12:55:13 -0700 Subject: [PATCH 110/186] [Teton] Exec process in rust. --- rust/lib/mammoth/src/elf.rs | 343 +++++++++++++++++++++++++++++ rust/lib/mammoth/src/init.rs | 6 +- rust/lib/mammoth/src/lib.rs | 1 + rust/lib/mammoth/src/mem.rs | 22 +- rust/lib/mammoth/src/port.rs | 28 +++ rust/lib/mammoth/src/syscall.rs | 70 ++++++ rust/lib/mammoth/src/zion.rs | 6 + rust/lib/victoriafalls/src/file.rs | 4 +- rust/sys/teton/src/psf.rs | 5 +- rust/sys/teton/src/terminal.rs | 13 ++ rust/usr/testbed/src/main.rs | 51 ----- 11 files changed, 488 insertions(+), 61 deletions(-) create mode 100644 rust/lib/mammoth/src/elf.rs diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs new file mode 100644 index 0000000..af7bd74 --- /dev/null +++ b/rust/lib/mammoth/src/elf.rs @@ -0,0 +1,343 @@ +use crate::debug; +use crate::init; +use crate::syscall; +use crate::zion::z_cap_t; +use crate::zion::ZError; + +use alloc::fmt::Debug; + +const ELF_MAGIC: u32 = 0x464C457F; + +const ELF_IDENT_32BIT: u8 = 0x1; +const ELF_IDENT_64BIT: u8 = 0x2; + +const ELF_ENDIAN_LITTLE: u8 = 0x1; +const ELF_ENDIAN_BIG: u8 = 0x2; + +const ELF_VERSION_CURRENT: u8 = 0x1; + +const ELF_ABI_SYSV: u8 = 0x0; +const ELF_ABI_LINUX: u8 = 0x3; + +const ELF_FILE_RELOC: u16 = 0x1; +const ELF_FILE_EXEC: u16 = 0x2; +const ELF_FILE_DYN: u16 = 0x3; +const ELF_FILE_CORE: u16 = 0x4; + +const ELF_MACH_X86: u16 = 0x3; +const ELF_MACH_AMD64: u16 = 0x3e; + +#[repr(C, packed(1))] +// Header spec from wikipedia: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#ELF_header +struct Elf64Header { + // 0x7F454C46 (0x7F followed by 'ELF') + magic: u32, + + // 1 for 32 bit, 2 for 64 bit. + elf_class: u8, + + // 1 for little, 2 for big. + endianess: u8, + + // Current version is 1. + ident_version: u8, + + // Target OS abi. + abi: u8, + abi_version: u8, + + ident_padding: [u8; 7], + + file_type: u16, + machine: u16, + version: u32, + entry: u64, + program_header_offset: u64, + section_header_offset: u64, + flags: u32, + header_size: u16, + program_header_entry_size: u16, + program_header_count: u16, + section_header_entry_size: u16, + section_header_entry_number: u16, + section_header_str_index: u16, +} + +impl Debug for Elf64Header { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let magic = self.magic; + let elf_class = match self.elf_class { + ELF_IDENT_32BIT => "32 bit", + ELF_IDENT_64BIT => "64 bit", + _ => "Unknown", + }; + let endianess = match self.endianess { + ELF_ENDIAN_LITTLE => "Little", + ELF_ENDIAN_BIG => "Big", + _ => "Unknown", + }; + + let ident_version = self.ident_version; + let version = self.version; + + f.write_fmt(format_args!( + "ELF Header Magic: {:#x}, Class: {}, Endianess: {}, Version (ident): {}, Version: {}\n", + magic, elf_class, endianess, ident_version, version, + ))?; + + let abi = match self.abi { + ELF_ABI_SYSV => "SYSV", + ELF_ABI_LINUX => "Linux", + _ => "Unknown", + }; + let abi_version = self.abi_version; + + f.write_fmt(format_args!("\tABI: {}, Version: {}\n", abi, abi_version))?; + + let file_type = match self.file_type { + ELF_FILE_EXEC => "Executable", + ELF_FILE_RELOC => "Relocatable", + ELF_FILE_DYN => "Shared Obj", + ELF_FILE_CORE => "Core file", + _ => "Unknown", + }; + + let machine = match self.machine { + ELF_MACH_X86 => "x86 (32bit)", + ELF_MACH_AMD64 => "x86-64", + _ => "Unknown", + }; + + let entry_point = self.entry; + + f.write_fmt(format_args!( + "\tFile type: {}, Machine Arch: {}, Entry point {:#x}", + file_type, machine, entry_point + )) + } +} + +fn validate_header(elf_header: &Elf64Header) -> Result<(), ZError> { + if elf_header.magic != ELF_MAGIC { + let magic = elf_header.magic; + debug!( + "Elf header incorrect got {:#x} expected {:#x}", + magic, ELF_MAGIC + ); + return Err(ZError::INVALID_ARGUMENT); + } + + if elf_header.elf_class != ELF_IDENT_64BIT { + let class = elf_header.elf_class; + debug!( + "Elf class must be {} for 64 bit, got: {}", + ELF_IDENT_64BIT, class + ); + return Err(ZError::INVALID_ARGUMENT); + } + + if elf_header.endianess != ELF_ENDIAN_LITTLE { + let endianess = elf_header.endianess; + debug!( + "Elf endianess must be {} for little, got: {}", + ELF_ENDIAN_LITTLE, endianess + ); + return Err(ZError::INVALID_ARGUMENT); + } + + if elf_header.ident_version != ELF_VERSION_CURRENT { + let version = elf_header.ident_version; + debug!( + "Elf version (ident) must be {}, got: {}", + ELF_VERSION_CURRENT, version + ); + return Err(ZError::INVALID_ARGUMENT); + } + + if elf_header.file_type != ELF_FILE_EXEC { + let file_type = elf_header.file_type; + debug!( + "Elf file type must be {} for executable, got {:x}", + ELF_FILE_EXEC, file_type + ); + return Err(ZError::INVALID_ARGUMENT); + } + + Ok(()) +} + +const ELF_PROG_NULL: u32 = 0x0; +const ELF_PROG_LOAD: u32 = 0x1; +const ELF_PROG_DYNAMIC: u32 = 0x2; +const ELF_PROG_INTERP: u32 = 0x3; +const ELF_PROG_NOTE: u32 = 0x4; +const ELF_PROG_SHLIB: u32 = 0x5; +const ELF_PROG_PTHDR: u32 = 0x6; +const ELF_PROG_THREAD_LOCAL: u32 = 0x7; + +// Stack unwind tables. +const ELF_PROG_GNU_EH_FRAME: u32 = 0x6474e550; +const ELF_PROG_GNU_STACK: u32 = 0x6474e551; +const ELF_PROG_GNU_RELRO: u32 = 0x6474e552; + +#[repr(C, packed(1))] +struct Elf64ProgramHeader { + prog_type: u32, + flags: u32, + offset: u64, + vaddr: u64, + paddr: u64, + file_size: u64, + mem_size: u64, + align: u64, +} + +impl Debug for Elf64ProgramHeader { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + let prog_type = match self.prog_type { + ELF_PROG_NULL => "NULL", + ELF_PROG_LOAD => "LOAD", + ELF_PROG_DYNAMIC => "DYNAMIC", + ELF_PROG_INTERP => "INTERP", + ELF_PROG_NOTE => "NOTE", + ELF_PROG_SHLIB => "SHARED LIB", + ELF_PROG_PTHDR => "PROG TABLE HEADER", + ELF_PROG_THREAD_LOCAL => "THREAD LOCAL", + ELF_PROG_GNU_EH_FRAME => "GNU EH FRAME", + ELF_PROG_GNU_RELRO => "GNU RELOCATABLE", + ELF_PROG_GNU_STACK => "GNU STACK", + _ => "UNKNOWN", + }; + + let offset = self.offset; + let vaddr = self.vaddr; + let paddr = self.paddr; + let file_size = self.file_size; + let mem_size = self.mem_size; + let align = self.align; + f.write_fmt(format_args!( + "Type: {}, offset: {:#x}, vaddr: {:#x}, paddr: {:#x}, file_size: {:#x}, mem_size: {:#x}, align: {:#x}", + prog_type, offset, vaddr, paddr, file_size, mem_size, align + )) + } +} + +fn load_program_segment( + prog_header: &Elf64ProgramHeader, + file: &[u8], + vmas: z_cap_t, +) -> Result<(), ZError> { + debug!("{:?}", prog_header); + match prog_header.prog_type { + ELF_PROG_NULL + | ELF_PROG_NOTE + | ELF_PROG_PTHDR + | ELF_PROG_GNU_STACK + | ELF_PROG_GNU_RELRO + | ELF_PROG_GNU_EH_FRAME => Ok(()), + ELF_PROG_LOAD => { + let page_offset = prog_header.vaddr & 0xFFF; + let mem_size = page_offset + prog_header.mem_size; + + let mem_object = crate::mem::MemoryRegion::new(mem_size)?; + + for i in mem_object.mut_slice() { + *i = 0; + } + + let file_start = prog_header.offset as usize; + let file_end = file_start + prog_header.file_size as usize; + let from_slice = &file[file_start..file_end]; + + let mem_start = page_offset as usize; + let mem_end = mem_start + (prog_header.file_size as usize); + let to_slice: &mut [u8] = &mut mem_object.mut_slice()[mem_start..mem_end]; + + to_slice.copy_from_slice(from_slice); + + let vaddr = prog_header.vaddr - page_offset; + syscall::address_space_map_external(vmas, mem_object.cap(), vaddr) + } + ELF_PROG_DYNAMIC => { + debug!("Unimplemented dynamic elf sections."); + Err(ZError::UNIMPLEMENTED) + } + ELF_PROG_INTERP => { + debug!("Unimplemented interpreter elf sections."); + Err(ZError::UNIMPLEMENTED) + } + ELF_PROG_SHLIB => { + debug!("Unimplemented shared lib elf sections."); + Err(ZError::UNIMPLEMENTED) + } + ELF_PROG_THREAD_LOCAL => { + debug!("Unimplemented thread local elf sections."); + Err(ZError::UNIMPLEMENTED) + } + _ => { + let prog_type = prog_header.prog_type; + debug!("Unknown elf program header type: {:#x}", prog_type); + Err(ZError::UNKNOWN) + } + } +} + +fn load_elf_program(elf_file: &[u8], vmas: z_cap_t) -> Result { + assert!(elf_file.len() > size_of::()); + let header: &Elf64Header = unsafe { + elf_file + .as_ptr() + .cast::() + .as_ref() + .ok_or(ZError::NULL_PTR)? + }; + debug!("{:?}", header); + validate_header(header)?; + + for prog_ind in 0..header.program_header_count { + let prog_header_offset = header.program_header_offset + + ((prog_ind as u64) * (header.program_header_entry_size as u64)); + let prog_header_end = prog_header_offset + header.program_header_entry_size as u64; + let prog_header_slice = &elf_file[prog_header_offset as usize..prog_header_end as usize]; + let prog_header: &Elf64ProgramHeader = unsafe { + prog_header_slice + .as_ptr() + .cast::() + .as_ref() + .ok_or(ZError::NULL_PTR)? + }; + + load_program_segment(prog_header, elf_file, vmas)?; + } + Ok(header.entry) +} + +pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { + let self_cap = unsafe { init::SELF_PROC_CAP }; + let port_cap = syscall::port_create()?; + let port_cap_dup = syscall::cap_duplicate(port_cap, u64::MAX)?; + + let (new_proc_cap, new_as_cap, foreign_port_id) = + syscall::process_spawn(self_cap, port_cap_dup)?; + + let entry_point = load_elf_program(elf_file, new_as_cap)?; + + let port = crate::port::PortClient::take_from(port_cap); + + port.write_u64_and_cap( + crate::init::Z_INIT_SELF_PROC, + syscall::cap_duplicate(new_proc_cap, u64::MAX)?, + )?; + port.write_u64_and_cap(crate::init::Z_INIT_SELF_VMAS, new_as_cap)?; + port.write_u64_and_cap( + crate::init::Z_INIT_ENDPOINT, + syscall::cap_duplicate(unsafe { crate::init::INIT_ENDPOINT }, u64::MAX)?, + )?; + + let thread_cap = syscall::thread_create(new_proc_cap)?; + syscall::thread_start(thread_cap, entry_point, foreign_port_id, 0)?; + + syscall::cap_release(thread_cap)?; + + Ok(new_proc_cap) +} diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs index 27dede9..752a446 100644 --- a/rust/lib/mammoth/src/init.rs +++ b/rust/lib/mammoth/src/init.rs @@ -2,9 +2,9 @@ use crate::syscall; use crate::zion::z_cap_t; // From /zion/include/ztypes.h -const Z_INIT_SELF_PROC: u64 = 0x4000_0000; -const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; -const Z_INIT_ENDPOINT: u64 = 0x4100_0000; +pub const Z_INIT_SELF_PROC: u64 = 0x4000_0000; +pub const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; +pub const Z_INIT_ENDPOINT: u64 = 0x4100_0000; pub static mut SELF_PROC_CAP: z_cap_t = 0; pub static mut SELF_VMAS_CAP: z_cap_t = 0; diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index f58e774..7f8d665 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -8,6 +8,7 @@ extern crate alloc; #[macro_use] pub mod macros; +pub mod elf; pub mod init; pub mod mem; pub mod port; diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index dd1834c..96653d7 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -46,6 +46,16 @@ impl MemoryRegion { }) } + pub fn new(size: u64) -> Result { + let mem_cap = syscall::memory_object_create(size)?; + let virt_addr = syscall::address_space_map(mem_cap)?; + Ok(Self { + mem_cap, + virt_addr, + size, + }) + } + pub fn slice(&self) -> &[T] { unsafe { slice::from_raw_parts( @@ -63,12 +73,20 @@ impl MemoryRegion { ) } } + + pub fn cap(&self) -> z_cap_t { + self.mem_cap + } } impl Drop for MemoryRegion { fn drop(&mut self) { - syscall::address_space_unmap(self.virt_addr, self.virt_addr + self.size) - .expect("Failed to unmap memory"); + // FIXME: We shouldn't have to do this manual adjustment. + let mut max = self.virt_addr + self.size; + if (max & 0xFFF) != 0 { + max += 0x1000 - (max & 0xFFF); + } + syscall::address_space_unmap(self.virt_addr, max).expect("Failed to unmap memory"); syscall::cap_release(self.mem_cap).expect("Failed to release memory cap"); } } diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs index bd25405..854b8d8 100644 --- a/rust/lib/mammoth/src/port.rs +++ b/rust/lib/mammoth/src/port.rs @@ -40,3 +40,31 @@ impl Drop for PortServer { cap_release(self.port_cap).expect("Failed to release port cap"); } } + +pub struct PortClient { + port_cap: z_cap_t, +} + +impl PortClient { + pub fn take_from(port_cap: z_cap_t) -> Self { + Self { port_cap } + } + + pub fn copy_from(port_cap: z_cap_t) -> Result { + Ok(Self { + port_cap: cap_duplicate(port_cap, u64::MAX)?, + }) + } + + #[warn(unused_results)] + pub fn write_u64_and_cap(&self, bytes: u64, cap: z_cap_t) -> Result<(), ZError> { + let mut caps: [z_cap_t; 1] = [cap]; + crate::syscall::port_send(self.port_cap, &bytes.to_le_bytes(), &mut caps) + } +} + +impl Drop for PortClient { + fn drop(&mut self) { + cap_release(self.port_cap).expect("Failed to release port cap"); + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index d0ea030..09c1c6e 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -40,12 +40,46 @@ pub fn debug(msg: &str) { syscall(zion::kZionDebug, &req).expect("Failed to write"); } +pub fn process_spawn( + proc_cap: z_cap_t, + bootstrap_cap: z_cap_t, +) -> Result<(z_cap_t, z_cap_t, z_cap_t), ZError> { + let mut new_proc_cap = 0; + let mut new_as_cap = 0; + let mut new_bootstrap_cap = 0; + + syscall( + zion::kZionProcessSpawn, + &zion::ZProcessSpawnReq { + proc_cap, + bootstrap_cap, + new_proc_cap: &mut new_proc_cap, + new_vmas_cap: &mut new_as_cap, + new_bootstrap_cap: &mut new_bootstrap_cap, + }, + )?; + + Ok((new_proc_cap, new_as_cap, new_bootstrap_cap)) +} + pub fn process_exit(code: u64) -> ! { let _ = syscall(zion::kZionProcessExit, &zion::ZProcessExitReq { code }); unreachable!() } +pub fn process_wait(proc_cap: z_cap_t) -> Result { + let mut err_code = 0; + syscall( + zion::kZionProcessWait, + &zion::ZProcessWaitReq { + proc_cap, + exit_code: &mut err_code, + }, + )?; + Ok(err_code) +} + pub fn thread_create(proc_cap: z_cap_t) -> Result { let mut cap = 0; syscall( @@ -58,6 +92,10 @@ pub fn thread_create(proc_cap: z_cap_t) -> Result { Ok(cap) } +pub fn thread_sleep(millis: u64) -> Result<(), ZError> { + syscall(zion::kZionThreadSleep, &zion::ZThreadSleepReq { millis }) +} + pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Result<(), ZError> { syscall( zion::kZionThreadStart, @@ -129,6 +167,24 @@ pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { Ok(vaddr) } +pub fn address_space_map_external( + vmas_cap: z_cap_t, + vmmo_cap: z_cap_t, + vaddr: u64, +) -> Result<(), ZError> { + let mut vaddr_throw: u64 = 0; + let vmas_req = zion::ZAddressSpaceMapReq { + vmmo_cap, + vmas_cap, + align: 0, + vaddr: &mut vaddr_throw as *mut u64, + vmas_offset: vaddr, + }; + + syscall(zion::kZionAddressSpaceMap, &vmas_req)?; + Ok(()) +} + pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZError> { syscall( zion::kZionAddressSpaceUnmap, @@ -151,6 +207,20 @@ pub fn port_create() -> Result { Ok(port_cap) } +pub fn port_send(port_cap: z_cap_t, bytes: &[u8], caps: &mut [z_cap_t]) -> Result<(), ZError> { + syscall( + zion::kZionPortSend, + &zion::ZPortSendReq { + port_cap, + num_bytes: bytes.len() as u64, + data: bytes.as_ptr() as *const c_void, + num_caps: caps.len() as u64, + // FIXME: This shouldn't need to be mutable. + caps: caps.as_mut_ptr(), + }, + ) +} + pub fn port_recv( port_cap: z_cap_t, bytes: &mut [u8], diff --git a/rust/lib/mammoth/src/zion.rs b/rust/lib/mammoth/src/zion.rs index 1bcadd2..9aa3a69 100644 --- a/rust/lib/mammoth/src/zion.rs +++ b/rust/lib/mammoth/src/zion.rs @@ -55,7 +55,13 @@ impl fmt::Debug for ZError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let str = match self { ZError::INVALID_ARGUMENT => "INVALID_ARGUMENT", + ZError::NOT_FOUND => "NOT_FOUND", + ZError::PERMISSION_DENIED => "PERMISSION_DENIED", + ZError::NULL_PTR => "NULL_PTR", + ZError::EMPTY => "EMPTY", + ZError::ALREADY_EXISTS => "ALREADY_EXISTS", ZError::BUFFER_SIZE => "BUFFER_SIZE", + ZError::FAILED_PRECONDITION => "FAILED_PRECONDITION", ZError::INTERNAL => "INTERNAL", ZError::UNIMPLEMENTED => "UNIMPLEMENTED", ZError::INVALID_RESPONSE => "INVALID_RESPONSE", diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs index 2f37990..4877a09 100644 --- a/rust/lib/victoriafalls/src/file.rs +++ b/rust/lib/victoriafalls/src/file.rs @@ -18,7 +18,7 @@ impl File { }) } - pub fn slice(&self, offset: usize, len: usize) -> &[u8] { - &self.memory.slice()[offset..offset + len] + pub fn slice(&self) -> &[u8] { + self.memory.slice() } } diff --git a/rust/sys/teton/src/psf.rs b/rust/sys/teton/src/psf.rs index f27aba4..f6a75a6 100644 --- a/rust/sys/teton/src/psf.rs +++ b/rust/sys/teton/src/psf.rs @@ -25,8 +25,7 @@ impl Psf { pub fn new(path: &str) -> Result { let file = File::open(&path)?; - let header = file - .slice(0, core::mem::size_of::()) + let header = file.slice()[0..core::mem::size_of::()] .as_ptr() .cast(); let psf = Self { @@ -66,7 +65,7 @@ impl Psf { let offset: usize = (self.header.headersize + (index * self.header.bytes_per_glyph)) as usize; let len: usize = self.header.bytes_per_glyph as usize; - &self.file.slice(offset, len) + &self.file.slice()[offset..offset + len] } pub fn width(&self) -> u32 { diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 4ecdc28..0ce7a53 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -112,6 +112,19 @@ impl Terminal { } } } + "exec" => match args.next() { + None => self.write_line("Specify a program"), + Some(prog) => { + let file = victoriafalls::file::File::open(prog).expect("Failed to open file"); + let proc_cap = mammoth::elf::spawn_process_from_elf(file.slice()) + .expect("Faield to spawn process"); + + let exit_code = mammoth::syscall::process_wait(proc_cap) + .expect("Failed to wait on process."); + + self.write_line(&format!("Process exit code: {}", exit_code)); + } + }, _ => self.write_line(&format!("Unrecognized command: {}", cmd)), } } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 1b27a05..0e994b5 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -8,46 +8,11 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::thread; use mammoth::zion::z_err_t; -use mammoth::zion::ZError; use yellowstone::GetEndpointRequest; use yellowstone::YellowstoneClient; -use yellowstone::YellowstoneServer; -use yunq::server::YunqServer; define_entry!(); -struct YellowstoneImpl {} - -impl yellowstone::YellowstoneServerHandler for YellowstoneImpl { - fn register_endpoint(&self, req: &yellowstone::RegisterEndpointRequest) -> Result<(), ZError> { - debug!("{}", req.endpoint_name); - Ok(()) - } - - fn get_endpoint(&self, req: &GetEndpointRequest) -> Result { - debug!("{}", req.endpoint_name); - Ok(yellowstone::Endpoint { - endpoint: unsafe { mammoth::init::SELF_PROC_CAP }, - }) - } - - fn get_ahci_info(&self) -> Result { - todo!() - } - - fn get_xhci_info(&self) -> Result { - todo!() - } - - fn get_framebuffer_info(&self) -> Result { - todo!() - } - - fn get_denali(&self) -> Result { - todo!() - } -} - #[no_mangle] pub extern "C" fn main() -> z_err_t { debug!("Testing!"); @@ -72,21 +37,5 @@ pub extern "C" fn main() -> z_err_t { t.join().expect("Failed to wait."); - let server = YellowstoneServer::new(YellowstoneImpl {}).expect("Failed to create server"); - - let mut yellowstone = YellowstoneClient::new(server.endpoint_cap()); - - let t = server.run_server().expect("Failed to start server"); - - let endpoint = yellowstone - .get_endpoint(&GetEndpointRequest { - endpoint_name: "test".to_string(), - }) - .expect("Failed to get endpoint"); - - debug!("{:#x}", endpoint.endpoint); - - t.join().expect("Failed to wait"); - 0 } From c6dbc395aa726bbdad2ea13c481da3122676d623 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 12:56:30 -0700 Subject: [PATCH 111/186] [Teton] Remove old C++ implementation. --- sys/CMakeLists.txt | 1 - sys/teton/CMakeLists.txt | 26 -------- sys/teton/framebuffer/console.cpp | 54 --------------- sys/teton/framebuffer/console.h | 26 -------- sys/teton/framebuffer/framebuffer.cpp | 29 -------- sys/teton/framebuffer/framebuffer.h | 25 ------- sys/teton/framebuffer/psf.cpp | 50 -------------- sys/teton/framebuffer/psf.h | 37 ----------- sys/teton/terminal.cpp | 96 --------------------------- sys/teton/terminal.h | 19 ------ sys/teton/teton.cpp | 48 -------------- 11 files changed, 411 deletions(-) delete mode 100644 sys/teton/CMakeLists.txt delete mode 100644 sys/teton/framebuffer/console.cpp delete mode 100644 sys/teton/framebuffer/console.h delete mode 100644 sys/teton/framebuffer/framebuffer.cpp delete mode 100644 sys/teton/framebuffer/framebuffer.h delete mode 100644 sys/teton/framebuffer/psf.cpp delete mode 100644 sys/teton/framebuffer/psf.h delete mode 100644 sys/teton/terminal.cpp delete mode 100644 sys/teton/terminal.h delete mode 100644 sys/teton/teton.cpp diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index e2eb139..3f4f9ca 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -1,7 +1,6 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_subdirectory(denali) -add_subdirectory(teton) add_subdirectory(victoriafalls) add_subdirectory(voyageurs) add_subdirectory(yellowstone) diff --git a/sys/teton/CMakeLists.txt b/sys/teton/CMakeLists.txt deleted file mode 100644 index 19a6706..0000000 --- a/sys/teton/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -add_executable(teton - framebuffer/console.cpp - framebuffer/framebuffer.cpp - framebuffer/psf.cpp - terminal.cpp - teton.cpp - ) - -target_include_directories(teton - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - "${CMAKE_CURRENT_SOURCE_DIR}/include") - -target_link_libraries(teton - glacier - mammoth - victoriafalls_yunq - voyageurs_yunq - yellowstone_yunq - ) - -set_target_properties(teton PROPERTIES - COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" - LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" - ) - -install(TARGETS teton) diff --git a/sys/teton/framebuffer/console.cpp b/sys/teton/framebuffer/console.cpp deleted file mode 100644 index 7e0a02e..0000000 --- a/sys/teton/framebuffer/console.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "framebuffer/console.h" - -#include - -void Console::WriteChar(char c) { - if (c == '\n') { - CursorReturn(); - return; - } - if (c == '\t') { - WriteString(" "); - return; - } - if (c == '\b') { - cursor_pos_--; - WriteChar(' '); - cursor_pos_--; - return; - } - - uint64_t row = cursor_pos_ / cols(); - if (row >= rows()) { - crash("Unimplemented console scroll.", glcr::UNIMPLEMENTED); - } - uint64_t fb_row = row * (psf_.height() + 1); - uint64_t col = cursor_pos_ % cols(); - uint64_t fb_col = col * (psf_.width() + 1); - - uint8_t* glyph = psf_.glyph(c); - - for (uint32_t r = fb_row; r < fb_row + psf_.height(); r++) { - for (uint32_t j = fb_col; j < fb_col + psf_.width(); j++) { - uint8_t glyph_offset = psf_.width() - (j - fb_col) - 1; - if ((glyph[r - fb_row] & (1 << glyph_offset))) { - framebuf_.DrawPixel(r, j, 0xFFFFFFF); - } else { - framebuf_.DrawPixel(r, j, 0); - } - } - } - - cursor_pos_++; -} - -void Console::WriteString(glcr::StringView str) { - for (uint64_t i = 0; i < str.size(); i++) { - WriteChar(str[i]); - } -} - -void Console::CursorReturn() { - cursor_pos_ -= cursor_pos_ % cols(); - cursor_pos_ += cols(); -} diff --git a/sys/teton/framebuffer/console.h b/sys/teton/framebuffer/console.h deleted file mode 100644 index 9afd2f4..0000000 --- a/sys/teton/framebuffer/console.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include - -#include "framebuffer/framebuffer.h" -#include "framebuffer/psf.h" - -class Console { - public: - explicit Console(Framebuffer& fb, Psf& psf) : framebuf_(fb), psf_(psf) {} - - void WriteChar(char c); - void WriteString(glcr::StringView str); - - uint32_t rows() { return framebuf_.height() / (psf_.height() + 1); } - uint32_t cols() { return framebuf_.width() / (psf_.width() + 1); } - - private: - // TODO: Don't store a reference here. - Framebuffer& framebuf_; - Psf& psf_; - uint64_t cursor_pos_ = 0; - - void CursorIncr(); - void CursorReturn(); -}; diff --git a/sys/teton/framebuffer/framebuffer.cpp b/sys/teton/framebuffer/framebuffer.cpp deleted file mode 100644 index 5960c84..0000000 --- a/sys/teton/framebuffer/framebuffer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "framebuffer/framebuffer.h" - -Framebuffer::Framebuffer(const yellowstone::FramebufferInfo& info) - : fb_info_(info), cursor_pos_(0) { - uint64_t buff_size_bytes = fb_info_.height() * fb_info_.pitch(); - fb_memory_ = mmth::OwnedMemoryRegion::DirectPhysical(fb_info_.address_phys(), - buff_size_bytes); - fb_ = reinterpret_cast(fb_memory_.vaddr()); -} - -void Framebuffer::DrawPixel(uint32_t row, uint32_t col, uint32_t pixel) { - // Div by 4 because pitch is in bytes and fb_ is a 32bit array. - fb_[(row * fb_info_.pitch() / 4) + col] = pixel; -} - -void Framebuffer::DrawGlyph(uint8_t* glyph) { - uint32_t gl_width = 8; - uint32_t gl_height = 16; - - for (uint8_t r = 0; r < gl_height; r++) { - for (uint8_t c = 0; c < gl_width; c++) { - if (((glyph[r] >> c) % 2) == 1) { - DrawPixel(r, gl_width - c - 1, 0xFFFF'FFFF); - } else { - DrawPixel(r, gl_width - c - 1, 0); - } - } - } -}; diff --git a/sys/teton/framebuffer/framebuffer.h b/sys/teton/framebuffer/framebuffer.h deleted file mode 100644 index d6db590..0000000 --- a/sys/teton/framebuffer/framebuffer.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -class Framebuffer { - public: - Framebuffer(const yellowstone::FramebufferInfo& info); - - void DrawPixel(uint32_t row, uint32_t col, uint32_t pixel); - - void DrawGlyph(uint8_t* glyph); - - uint64_t width() { return fb_info_.width(); } - uint64_t height() { return fb_info_.height(); } - - private: - // FIXME: Implement Yunq copy or move so we - // don't have to store a reference here. - const yellowstone::FramebufferInfo& fb_info_; - - mmth::OwnedMemoryRegion fb_memory_; - uint32_t* fb_; - uint32_t cursor_pos_; -}; diff --git a/sys/teton/framebuffer/psf.cpp b/sys/teton/framebuffer/psf.cpp deleted file mode 100644 index 1e8aaf2..0000000 --- a/sys/teton/framebuffer/psf.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "framebuffer/psf.h" - -#include -#include - -#define PSF_DEBUG 0 - -namespace { - -const uint32_t kMagic = 0x864AB572; - -} - -Psf::Psf(glcr::StringView path) - : psf_file_(mmth::File::Open(path)), - header_(reinterpret_cast(psf_file_.raw_ptr())) { - EnsureValid(); -} - -void Psf::DumpHeader() { -#if PSF_DEBUG - dbgln("Magic: {x}", header_->magic); - dbgln("Version: {x}", header_->version); - dbgln("Header Sz: {x}", header_->headersize); - dbgln("Flags: {x}", header_->flags); - dbgln("Length: {x}", header_->numglyph); - dbgln("Glyph Size: {x}", header_->bytesperglyph); - dbgln("Height: {x}", header_->height); - dbgln("Width: {x}", header_->width); -#endif -} - -void Psf::EnsureValid() { - if (header_->magic != kMagic) { - dbgln("PSF: Magic value: {x}", header_->magic); - crash("PSF: Invalid magic value", glcr::INVALID_ARGUMENT); - } - - if (header_->version != 0) { - crash("PSF non-zero version", glcr::INVALID_ARGUMENT); - } - - if (header_->height != 0x10) { - crash("PSF height other than 16 not handled", glcr::UNIMPLEMENTED); - } - - if (header_->width != 0x8) { - crash("PSF width other than 8 not handled", glcr::UNIMPLEMENTED); - } -} diff --git a/sys/teton/framebuffer/psf.h b/sys/teton/framebuffer/psf.h deleted file mode 100644 index bfa890d..0000000 --- a/sys/teton/framebuffer/psf.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -struct PsfHeader { - uint32_t magic; /* magic bytes to identify PSF */ - uint32_t version; /* zero */ - uint32_t headersize; /* offset of bitmaps in file, 32 */ - uint32_t flags; /* 0 if there's no unicode table */ - uint32_t numglyph; /* number of glyphs */ - uint32_t bytesperglyph; /* size of each glyph */ - uint32_t height; /* height in pixels */ - uint32_t width; /* width in pixels */ -}; - -class Psf { - public: - Psf(glcr::StringView path); - - void DumpHeader(); - - uint32_t size() { return header_->numglyph; } - uint32_t width() { return header_->width; } - uint32_t height() { return header_->height; } - - uint8_t* glyph(uint32_t index) { - return reinterpret_cast(psf_file_.byte_ptr() + - header_->headersize + - (index * header_->bytesperglyph)); - } - - private: - mmth::File psf_file_; - PsfHeader* header_; - - void EnsureValid(); -}; diff --git a/sys/teton/terminal.cpp b/sys/teton/terminal.cpp deleted file mode 100644 index 9adb28d..0000000 --- a/sys/teton/terminal.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "terminal.h" - -#include -#include -#include -#include -#include -#include - -void Terminal::HandleCharacter(char c) { - console_.WriteChar(c); - if (c == '\n') { - glcr::String str = current_command_.ToString(); - ExecuteCommand(str); - current_command_.Reset(); - } else if (c == '\b') { - current_command_.DeleteLast(); - } else { - current_command_.PushBack(c); - } -} - -void Terminal::ExecuteCommand(const glcr::String& command) { - auto tokens = glcr::StrSplit(command, ' '); - if (tokens.size() == 0) { - console_.WriteChar('>'); - return; - } - glcr::StringView cmd = tokens[0]; - if (cmd == "help") { - console_.WriteString("Available Commands: pwd cd ls\n"); - } else if (cmd == "pwd") { - console_.WriteString(cwd_); - console_.WriteChar('\n'); - } else if (cmd == "cd") { - if (tokens.size() != 2) { - console_.WriteString("Provide an absolute path.\n>"); - return; - } - auto files_or = mmth::ListDirectory(tokens[1]); - if (files_or.ok()) { - cwd_ = tokens[1]; - } else { - console_.WriteString(glcr::StrFormat("Error: {}\n", files_or.error())); - } - - } else if (cmd == "ls") { - glcr::StringView directory; - if (tokens.size() > 1) { - directory = tokens[1]; - } else { - directory = cwd_; - } - auto files_or = mmth::ListDirectory(directory); - if (!files_or.ok()) { - console_.WriteString(glcr::StrFormat("Error: {}\n", files_or.error())); - } else { - for (const auto& file : files_or.value()) { - console_.WriteString(file); - console_.WriteChar('\n'); - } - } - } else if (cmd == "exec") { - if (tokens.size() != 2) { - console_.WriteString("Provide the name of an executable.\n>"); - return; - } - auto file = mmth::File::Open(tokens[1]); - - z_cap_t endpoint; - if (ZCapDuplicate(gInitEndpointCap, kZionPerm_All, &endpoint) != glcr::OK) { - console_.WriteString("Couldn't duplicate yellowstone cap for spawn"); - return; - } - - auto error_or_cap = - mmth::SpawnProcessFromElfRegion((uint64_t)file.raw_ptr(), endpoint); - if (!error_or_cap.ok()) { - console_.WriteString( - glcr::StrFormat("Error: {}\n", error_or_cap.error())); - return; - } - uint64_t err_code; - check(ZProcessWait(error_or_cap.value(), &err_code)); - if (err_code != 0) { - console_.WriteString(glcr::StrFormat( - "Process Error: {}\n", static_cast(err_code))); - } - - } else { - console_.WriteString("Unknown command: "); - console_.WriteString(command); - console_.WriteChar('\n'); - } - console_.WriteChar('>'); -} diff --git a/sys/teton/terminal.h b/sys/teton/terminal.h deleted file mode 100644 index 71408a2..0000000 --- a/sys/teton/terminal.h +++ /dev/null @@ -1,19 +0,0 @@ -#include -#include - -#include "framebuffer/console.h" - -class Terminal : public mmth::KeyboardListenerBase { - public: - Terminal(Console& c) : mmth::KeyboardListenerBase(), console_(c) {} - - virtual void HandleCharacter(char c) override; - - void ExecuteCommand(const glcr::String& command); - - private: - Console& console_; - glcr::VariableStringBuilder current_command_; - - glcr::String cwd_ = "/"; -}; diff --git a/sys/teton/teton.cpp b/sys/teton/teton.cpp deleted file mode 100644 index f89c689..0000000 --- a/sys/teton/teton.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include -#include -#include -#include -#include - -#include "framebuffer/console.h" -#include "framebuffer/framebuffer.h" -#include "framebuffer/psf.h" -#include "terminal.h" - -using yellowstone::FramebufferInfo; -using yellowstone::YellowstoneClient; - -uint64_t main(uint64_t init_port) { - ParseInitPort(init_port); - - dbgln("Teton Starting"); - - // 1. Set up framebuffer. - YellowstoneClient client(gInitEndpointCap); - - FramebufferInfo framebuffer; - check(client.GetFramebufferInfo(framebuffer)); - dbgln("FB addr {x}, bpp {}, width {} , height {}, pitch {}", - framebuffer.address_phys(), framebuffer.bpp(), framebuffer.width(), - framebuffer.height(), framebuffer.pitch()); - - Framebuffer fbuf(framebuffer); - - // 2. Parse a font file. - - Psf psf("/default8x16.psfu"); - psf.DumpHeader(); - - // 3. Write a line to the screen. - Console console(fbuf, psf); - console.WriteChar('>'); - - Terminal terminal(console); - terminal.Register(); - - Thread lthread = terminal.Listen(); - - check(lthread.Join()); - - return glcr::OK; -} From 19a8ab41d41feee9138fb25dcedc65733fd82921 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 17:14:30 -0700 Subject: [PATCH 112/186] [Zion] Make sure result of ValidateCapability is used. --- rust/lib/mammoth/src/elf.rs | 2 +- zion/capability/capability.h | 6 +++++- zion/syscall/ipc.cpp | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs index af7bd74..aa4daf9 100644 --- a/rust/lib/mammoth/src/elf.rs +++ b/rust/lib/mammoth/src/elf.rs @@ -331,7 +331,7 @@ pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { port.write_u64_and_cap(crate::init::Z_INIT_SELF_VMAS, new_as_cap)?; port.write_u64_and_cap( crate::init::Z_INIT_ENDPOINT, - syscall::cap_duplicate(unsafe { crate::init::INIT_ENDPOINT }, u64::MAX)?, + self_cap.duplicate(Capability::PERMS_ALL)?, )?; let thread_cap = syscall::thread_create(new_proc_cap)?; diff --git a/zion/capability/capability.h b/zion/capability/capability.h index 6a20183..96911c7 100644 --- a/zion/capability/capability.h +++ b/zion/capability/capability.h @@ -5,6 +5,7 @@ #include #include +#include "debug/debug.h" #include "include/ztypes.h" #include "object/kernel_object.h" @@ -42,7 +43,10 @@ class Capability : public glcr::RefCounted { template glcr::RefPtr Capability::obj() { if (obj_->TypeTag() != KernelObjectTag::type) { - return nullptr; + uint64_t type = KernelObjectTag::type; + dbgln("Mismatched type tag returning nullptr."); + dbgln("Expected {x} got {x}", type, obj_->TypeTag()); + panic("Unhandled obj type mismatch"); } return StaticCastRefPtr(obj_); } diff --git a/zion/syscall/ipc.cpp b/zion/syscall/ipc.cpp index ab1051a..98e6a49 100644 --- a/zion/syscall/ipc.cpp +++ b/zion/syscall/ipc.cpp @@ -175,7 +175,7 @@ glcr::ErrorCode EndpointSend(ZEndpointSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto endpoint_cap = proc.GetCapability(req->endpoint_cap); - ValidateCapability(endpoint_cap, kZionPerm_Write); + RET_ERR(ValidateCapability(endpoint_cap, kZionPerm_Write)); auto endpoint = endpoint_cap->obj(); auto reply_port = ReplyPort::Create(); @@ -191,7 +191,7 @@ glcr::ErrorCode EndpointRecv(ZEndpointRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto endpoint_cap = proc.GetCapability(req->endpoint_cap); - ValidateCapability(endpoint_cap, kZionPerm_Read); + RET_ERR(ValidateCapability(endpoint_cap, kZionPerm_Read)); auto endpoint = endpoint_cap->obj(); ASSIGN_OR_RETURN(IpcMessage msg, @@ -202,7 +202,7 @@ glcr::ErrorCode EndpointRecv(ZEndpointRecvReq* req) { glcr::ErrorCode ReplyPortSend(ZReplyPortSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto reply_port_cap = proc.GetCapability(req->reply_port_cap); - ValidateCapability(reply_port_cap, kZionPerm_Read); + RET_ERR(ValidateCapability(reply_port_cap, kZionPerm_Read)); auto reply_port = reply_port_cap->obj(); ASSIGN_OR_RETURN(IpcMessage message, TranslateRequestToIpcMessage(*req)); @@ -212,7 +212,7 @@ glcr::ErrorCode ReplyPortRecv(ZReplyPortRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto reply_port_cap = proc.GetCapability(req->reply_port_cap); - ValidateCapability(reply_port_cap, kZionPerm_Read); + RET_ERR(ValidateCapability(reply_port_cap, kZionPerm_Read)); auto reply_port = reply_port_cap->obj(); ASSIGN_OR_RETURN(IpcMessage msg, From 7e68c1b641558f1af743db0be4f9adf64e5ead7d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 17:15:33 -0700 Subject: [PATCH 113/186] Add a rust user-space Capability struct. This is a thin wrapper around a capability ptr that releases the capability when it is done and prevents copying/cloning it. To get a copy a caller must explicitly use duplicate. --- rust/lib/mammoth/src/cap.rs | 48 ++++++++++ rust/lib/mammoth/src/cap_syscall.rs | 31 +++++++ rust/lib/mammoth/src/elf.rs | 28 +++--- rust/lib/mammoth/src/init.rs | 4 +- rust/lib/mammoth/src/lib.rs | 2 + rust/lib/mammoth/src/mem.rs | 22 ++--- rust/lib/mammoth/src/port.rs | 41 +++------ rust/lib/mammoth/src/syscall.rs | 132 ++++++++++++++-------------- rust/lib/mammoth/src/thread.rs | 12 +-- rust/lib/victoriafalls/src/file.rs | 4 +- rust/lib/victoriafalls/src/lib.rs | 2 +- rust/lib/voyageurs/src/listener.rs | 3 +- rust/lib/yellowstone/src/lib.rs | 2 +- rust/lib/yunq/src/client.rs | 4 +- rust/lib/yunq/src/server.rs | 3 +- rust/sys/teton/src/terminal.rs | 4 +- rust/usr/testbed/src/main.rs | 8 +- yunq/rust/src/codegen.rs | 17 ++-- 18 files changed, 215 insertions(+), 152 deletions(-) create mode 100644 rust/lib/mammoth/src/cap.rs create mode 100644 rust/lib/mammoth/src/cap_syscall.rs diff --git a/rust/lib/mammoth/src/cap.rs b/rust/lib/mammoth/src/cap.rs new file mode 100644 index 0000000..29f3d47 --- /dev/null +++ b/rust/lib/mammoth/src/cap.rs @@ -0,0 +1,48 @@ +use crate::cap_syscall; +use crate::zion::{z_cap_t, ZError}; + +pub struct Capability { + cap: z_cap_t, +} + +impl Capability { + pub fn take(cap: z_cap_t) -> Self { + Self { cap } + } + + pub fn take_copy(cap: z_cap_t) -> Result { + Ok(Self::take(cap_syscall::cap_duplicate( + cap, + Self::PERMS_ALL, + )?)) + } + + pub fn raw(&self) -> z_cap_t { + self.cap + } + + pub fn release(mut self) -> z_cap_t { + let cap = self.cap; + self.cap = 0; + cap + } + + pub const PERMS_ALL: u64 = u64::MAX; + pub fn duplicate(&self, perm_mask: u64) -> Result { + Ok(Self::take(cap_syscall::cap_duplicate(self.cap, perm_mask)?)) + } +} + +impl Drop for Capability { + fn drop(&mut self) { + if self.cap != 0 { + if let Err(e) = cap_syscall::cap_release(self.cap) { + crate::debug!( + "WARN: error during cap release for cap {:#x}: {:?}", + self.cap, + e + ); + } + } + } +} diff --git a/rust/lib/mammoth/src/cap_syscall.rs b/rust/lib/mammoth/src/cap_syscall.rs new file mode 100644 index 0000000..eb9567a --- /dev/null +++ b/rust/lib/mammoth/src/cap_syscall.rs @@ -0,0 +1,31 @@ +use core::ffi::c_void; + +use crate::zion::{self, z_cap_t, ZError}; + +#[must_use] +fn syscall(id: u64, req: &T) -> Result<(), ZError> { + unsafe { + let resp = zion::SysCall1(id, req as *const T as *const c_void); + if resp != 0 { + return Err(zion::ZError::from(resp)); + } + } + Ok(()) +} + +pub fn cap_duplicate(cap: z_cap_t, perm_mask: u64) -> Result { + let mut new_cap = 0; + syscall( + zion::kZionCapDuplicate, + &zion::ZCapDuplicateReq { + cap_in: cap, + perm_mask, + cap_out: &mut new_cap, + }, + )?; + Ok(new_cap) +} + +pub fn cap_release(cap: z_cap_t) -> Result<(), ZError> { + syscall(zion::kZionCapRelease, &zion::ZCapReleaseReq { cap }) +} diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs index aa4daf9..321063d 100644 --- a/rust/lib/mammoth/src/elf.rs +++ b/rust/lib/mammoth/src/elf.rs @@ -1,7 +1,7 @@ +use crate::cap::Capability; use crate::debug; use crate::init; use crate::syscall; -use crate::zion::z_cap_t; use crate::zion::ZError; use alloc::fmt::Debug; @@ -225,7 +225,7 @@ impl Debug for Elf64ProgramHeader { fn load_program_segment( prog_header: &Elf64ProgramHeader, file: &[u8], - vmas: z_cap_t, + vmas: &Capability, ) -> Result<(), ZError> { debug!("{:?}", prog_header); match prog_header.prog_type { @@ -282,7 +282,7 @@ fn load_program_segment( } } -fn load_elf_program(elf_file: &[u8], vmas: z_cap_t) -> Result { +fn load_elf_program(elf_file: &[u8], vmas: &Capability) -> Result { assert!(elf_file.len() > size_of::()); let header: &Elf64Header = unsafe { elf_file @@ -312,32 +312,28 @@ fn load_elf_program(elf_file: &[u8], vmas: z_cap_t) -> Result { Ok(header.entry) } -pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { - let self_cap = unsafe { init::SELF_PROC_CAP }; +pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { + let self_cap = Capability::take_copy(unsafe { init::SELF_PROC_CAP })?; let port_cap = syscall::port_create()?; - let port_cap_dup = syscall::cap_duplicate(port_cap, u64::MAX)?; let (new_proc_cap, new_as_cap, foreign_port_id) = - syscall::process_spawn(self_cap, port_cap_dup)?; + syscall::process_spawn(&self_cap, port_cap.duplicate(Capability::PERMS_ALL)?)?; - let entry_point = load_elf_program(elf_file, new_as_cap)?; + let entry_point = load_elf_program(elf_file, &new_as_cap)?; let port = crate::port::PortClient::take_from(port_cap); port.write_u64_and_cap( crate::init::Z_INIT_SELF_PROC, - syscall::cap_duplicate(new_proc_cap, u64::MAX)?, + new_proc_cap.duplicate(Capability::PERMS_ALL)?, )?; port.write_u64_and_cap(crate::init::Z_INIT_SELF_VMAS, new_as_cap)?; - port.write_u64_and_cap( - crate::init::Z_INIT_ENDPOINT, - self_cap.duplicate(Capability::PERMS_ALL)?, - )?; + let yellowstone = Capability::take_copy(unsafe { crate::init::INIT_ENDPOINT })?; + port.write_u64_and_cap(crate::init::Z_INIT_ENDPOINT, yellowstone)?; - let thread_cap = syscall::thread_create(new_proc_cap)?; - syscall::thread_start(thread_cap, entry_point, foreign_port_id, 0)?; + let thread_cap = syscall::thread_create(&new_proc_cap)?; - syscall::cap_release(thread_cap)?; + syscall::thread_start(&thread_cap, entry_point, foreign_port_id, 0)?; Ok(new_proc_cap) } diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs index 752a446..a03eed7 100644 --- a/rust/lib/mammoth/src/init.rs +++ b/rust/lib/mammoth/src/init.rs @@ -1,3 +1,4 @@ +use crate::cap::Capability; use crate::syscall; use crate::zion::z_cap_t; @@ -11,11 +12,12 @@ pub static mut SELF_VMAS_CAP: z_cap_t = 0; pub static mut INIT_ENDPOINT: z_cap_t = 0; pub fn parse_init_port(port_cap: z_cap_t) { + let init_port = Capability::take(port_cap); loop { let mut bytes: [u8; 8] = [0; 8]; let mut caps: [u64; 1] = [0]; - let resp = syscall::port_poll(port_cap, &mut bytes, &mut caps); + let resp = syscall::port_poll(&init_port, &mut bytes, &mut caps); if let Err(_) = resp { break; } diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index 7f8d665..b0891a6 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -8,6 +8,8 @@ extern crate alloc; #[macro_use] pub mod macros; +pub mod cap; +mod cap_syscall; pub mod elf; pub mod init; pub mod mem; diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 96653d7..5f58904 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -1,5 +1,6 @@ +use crate::cap::Capability; use crate::syscall; -use crate::zion::{z_cap_t, ZError}; +use crate::zion::ZError; use alloc::slice; use linked_list_allocator::LockedHeap; @@ -12,7 +13,7 @@ pub fn init_heap() { // 1 MiB let size = 0x10_0000; let vmmo_cap = syscall::memory_object_create(size).expect("Failed to create memory object"); - let vaddr = syscall::address_space_map(vmmo_cap).expect("Failed to map memory object"); + let vaddr = syscall::address_space_map(&vmmo_cap).expect("Failed to map memory object"); unsafe { ALLOCATOR.lock().init(vaddr as *mut u8, size as usize); CAN_ALLOC = true; @@ -20,7 +21,7 @@ pub fn init_heap() { } pub struct MemoryRegion { - mem_cap: z_cap_t, + mem_cap: Capability, virt_addr: u64, size: u64, } @@ -28,7 +29,7 @@ pub struct MemoryRegion { impl MemoryRegion { pub fn direct_physical(paddr: u64, size: u64) -> Result { let mem_cap = syscall::memory_object_direct_physical(paddr, size)?; - let virt_addr = syscall::address_space_map(mem_cap)?; + let virt_addr = syscall::address_space_map(&mem_cap)?; Ok(Self { mem_cap, virt_addr, @@ -36,9 +37,9 @@ impl MemoryRegion { }) } - pub fn from_cap(mem_cap: z_cap_t) -> Result { - let virt_addr = syscall::address_space_map(mem_cap)?; - let size = syscall::memory_object_inspect(mem_cap)?; + pub fn from_cap(mem_cap: Capability) -> Result { + let virt_addr = syscall::address_space_map(&mem_cap)?; + let size = syscall::memory_object_inspect(&mem_cap)?; Ok(Self { mem_cap, virt_addr, @@ -48,7 +49,7 @@ impl MemoryRegion { pub fn new(size: u64) -> Result { let mem_cap = syscall::memory_object_create(size)?; - let virt_addr = syscall::address_space_map(mem_cap)?; + let virt_addr = syscall::address_space_map(&mem_cap)?; Ok(Self { mem_cap, virt_addr, @@ -74,8 +75,8 @@ impl MemoryRegion { } } - pub fn cap(&self) -> z_cap_t { - self.mem_cap + pub fn cap(&self) -> &Capability { + &self.mem_cap } } @@ -87,6 +88,5 @@ impl Drop for MemoryRegion { max += 0x1000 - (max & 0xFFF); } syscall::address_space_unmap(self.virt_addr, max).expect("Failed to unmap memory"); - syscall::cap_release(self.mem_cap).expect("Failed to release memory cap"); } } diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs index 854b8d8..8a86518 100644 --- a/rust/lib/mammoth/src/port.rs +++ b/rust/lib/mammoth/src/port.rs @@ -1,8 +1,9 @@ -use crate::syscall::{cap_duplicate, cap_release, port_create, port_recv}; +use crate::cap::Capability; +use crate::syscall::{port_create, port_recv}; use crate::zion::{kZionPerm_Read, z_cap_t, ZError}; pub struct PortServer { - port_cap: z_cap_t, + port_cap: Capability, } impl PortServer { @@ -13,14 +14,16 @@ impl PortServer { } pub fn create_client_cap(&self) -> Result { - cap_duplicate(self.port_cap, !kZionPerm_Read) + self.port_cap + .duplicate(!kZionPerm_Read) + .map(|c| c.release()) } pub fn recv_byte(&self) -> Result { let mut caps: [z_cap_t; 0] = []; let mut bytes: [u8; 1] = [0]; - port_recv(self.port_cap, &mut bytes, &mut caps)?; + port_recv(&self.port_cap, &mut bytes, &mut caps)?; Ok(bytes[0]) } @@ -29,42 +32,24 @@ impl PortServer { let mut caps: [z_cap_t; 0] = []; let mut bytes: [u8; 2] = [0; 2]; - port_recv(self.port_cap, &mut bytes, &mut caps)?; + port_recv(&self.port_cap, &mut bytes, &mut caps)?; Ok(u16::from_le_bytes(bytes)) } } -impl Drop for PortServer { - fn drop(&mut self) { - cap_release(self.port_cap).expect("Failed to release port cap"); - } -} - pub struct PortClient { - port_cap: z_cap_t, + port_cap: Capability, } impl PortClient { - pub fn take_from(port_cap: z_cap_t) -> Self { + pub fn take_from(port_cap: Capability) -> Self { Self { port_cap } } - pub fn copy_from(port_cap: z_cap_t) -> Result { - Ok(Self { - port_cap: cap_duplicate(port_cap, u64::MAX)?, - }) - } - #[warn(unused_results)] - pub fn write_u64_and_cap(&self, bytes: u64, cap: z_cap_t) -> Result<(), ZError> { - let mut caps: [z_cap_t; 1] = [cap]; - crate::syscall::port_send(self.port_cap, &bytes.to_le_bytes(), &mut caps) - } -} - -impl Drop for PortClient { - fn drop(&mut self) { - cap_release(self.port_cap).expect("Failed to release port cap"); + pub fn write_u64_and_cap(&self, bytes: u64, cap: Capability) -> Result<(), ZError> { + let mut caps: [z_cap_t; 1] = [cap.release()]; + crate::syscall::port_send(&self.port_cap, &bytes.to_le_bytes(), &mut caps) } } diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 09c1c6e..1c2d892 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -1,5 +1,6 @@ extern crate alloc; +use crate::cap::Capability; use crate::zion; use crate::zion::z_cap_t; use crate::zion::ZError; @@ -41,9 +42,9 @@ pub fn debug(msg: &str) { } pub fn process_spawn( - proc_cap: z_cap_t, - bootstrap_cap: z_cap_t, -) -> Result<(z_cap_t, z_cap_t, z_cap_t), ZError> { + proc_cap: &Capability, + bootstrap_cap: Capability, +) -> Result<(Capability, Capability, u64), ZError> { let mut new_proc_cap = 0; let mut new_as_cap = 0; let mut new_bootstrap_cap = 0; @@ -51,15 +52,19 @@ pub fn process_spawn( syscall( zion::kZionProcessSpawn, &zion::ZProcessSpawnReq { - proc_cap, - bootstrap_cap, + proc_cap: proc_cap.raw(), + bootstrap_cap: bootstrap_cap.release(), new_proc_cap: &mut new_proc_cap, new_vmas_cap: &mut new_as_cap, new_bootstrap_cap: &mut new_bootstrap_cap, }, )?; - Ok((new_proc_cap, new_as_cap, new_bootstrap_cap)) + Ok(( + Capability::take(new_proc_cap), + Capability::take(new_as_cap), + new_bootstrap_cap, + )) } pub fn process_exit(code: u64) -> ! { @@ -68,39 +73,44 @@ pub fn process_exit(code: u64) -> ! { unreachable!() } -pub fn process_wait(proc_cap: z_cap_t) -> Result { +pub fn process_wait(proc_cap: &Capability) -> Result { let mut err_code = 0; syscall( zion::kZionProcessWait, &zion::ZProcessWaitReq { - proc_cap, + proc_cap: proc_cap.raw(), exit_code: &mut err_code, }, )?; Ok(err_code) } -pub fn thread_create(proc_cap: z_cap_t) -> Result { +pub fn thread_create(proc_cap: &Capability) -> Result { let mut cap = 0; syscall( zion::kZionThreadCreate, &zion::ZThreadCreateReq { - proc_cap, - thread_cap: &mut cap as *mut z_cap_t, + proc_cap: proc_cap.raw(), + thread_cap: &mut cap, }, )?; - Ok(cap) + Ok(Capability::take(cap)) } pub fn thread_sleep(millis: u64) -> Result<(), ZError> { syscall(zion::kZionThreadSleep, &zion::ZThreadSleepReq { millis }) } -pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Result<(), ZError> { +pub fn thread_start( + thread_cap: &Capability, + entry: u64, + arg1: u64, + arg2: u64, +) -> Result<(), ZError> { syscall( zion::kZionThreadStart, &zion::ZThreadStartReq { - thread_cap, + thread_cap: thread_cap.raw(), entry, arg1, arg2, @@ -108,8 +118,13 @@ pub fn thread_start(thread_cap: z_cap_t, entry: u64, arg1: u64, arg2: u64) -> Re ) } -pub fn thread_wait(thread_cap: z_cap_t) -> Result<(), ZError> { - syscall(zion::kZionThreadWait, &zion::ZThreadWaitReq { thread_cap }) +pub fn thread_wait(thread_cap: &Capability) -> Result<(), ZError> { + syscall( + zion::kZionThreadWait, + &zion::ZThreadWaitReq { + thread_cap: thread_cap.raw(), + }, + ) } pub fn thread_exit() -> ! { @@ -117,17 +132,17 @@ pub fn thread_exit() -> ! { unreachable!(); } -pub fn memory_object_create(size: u64) -> Result { +pub fn memory_object_create(size: u64) -> Result { let mut vmmo_cap = 0; let obj_req = zion::ZMemoryObjectCreateReq { size, vmmo_cap: &mut vmmo_cap as *mut u64, }; syscall(zion::kZionMemoryObjectCreate, &obj_req)?; - Ok(vmmo_cap) + Ok(Capability::take(vmmo_cap)) } -pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result { +pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result { let mut vmmo_cap = 0; syscall( zion::kZionMemoryObjectCreatePhysical, @@ -137,26 +152,26 @@ pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result Result { +pub fn memory_object_inspect(mem_cap: &Capability) -> Result { let mut mem_size = 0; syscall( zion::kZionMemoryObjectInspect, &zion::ZMemoryObjectInspectReq { - vmmo_cap: mem_cap, + vmmo_cap: mem_cap.raw(), size: &mut mem_size, }, )?; Ok(mem_size) } -pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { +pub fn address_space_map(vmmo_cap: &Capability) -> Result { let mut vaddr: u64 = 0; // FIXME: Allow caller to pass these options. let vmas_req = zion::ZAddressSpaceMapReq { - vmmo_cap, + vmmo_cap: vmmo_cap.raw(), vmas_cap: unsafe { crate::init::SELF_VMAS_CAP }, align: 0x2000, vaddr: &mut vaddr as *mut u64, @@ -168,14 +183,14 @@ pub fn address_space_map(vmmo_cap: z_cap_t) -> Result { } pub fn address_space_map_external( - vmas_cap: z_cap_t, - vmmo_cap: z_cap_t, + vmas_cap: &Capability, + vmmo_cap: &Capability, vaddr: u64, ) -> Result<(), ZError> { let mut vaddr_throw: u64 = 0; let vmas_req = zion::ZAddressSpaceMapReq { - vmmo_cap, - vmas_cap, + vmas_cap: vmas_cap.raw(), + vmmo_cap: vmmo_cap.raw(), align: 0, vaddr: &mut vaddr_throw as *mut u64, vmas_offset: vaddr, @@ -196,7 +211,7 @@ pub fn address_space_unmap(lower_addr: u64, upper_addr: u64) -> Result<(), ZErro ) } -pub fn port_create() -> Result { +pub fn port_create() -> Result { let mut port_cap = 0; syscall( zion::kZionPortCreate, @@ -204,14 +219,14 @@ pub fn port_create() -> Result { port_cap: &mut port_cap, }, )?; - Ok(port_cap) + Ok(Capability::take(port_cap)) } -pub fn port_send(port_cap: z_cap_t, bytes: &[u8], caps: &mut [z_cap_t]) -> Result<(), ZError> { +pub fn port_send(port_cap: &Capability, bytes: &[u8], caps: &mut [z_cap_t]) -> Result<(), ZError> { syscall( zion::kZionPortSend, &zion::ZPortSendReq { - port_cap, + port_cap: port_cap.raw(), num_bytes: bytes.len() as u64, data: bytes.as_ptr() as *const c_void, num_caps: caps.len() as u64, @@ -222,7 +237,7 @@ pub fn port_send(port_cap: z_cap_t, bytes: &[u8], caps: &mut [z_cap_t]) -> Resul } pub fn port_recv( - port_cap: z_cap_t, + port_cap: &Capability, bytes: &mut [u8], caps: &mut [u64], ) -> Result<(u64, u64), ZError> { @@ -231,7 +246,7 @@ pub fn port_recv( syscall( zion::kZionPortRecv, &zion::ZPortRecvReq { - port_cap, + port_cap: port_cap.raw(), data: bytes.as_mut_ptr() as *mut c_void, num_bytes: &mut num_bytes as *mut u64, caps: caps.as_mut_ptr(), @@ -242,14 +257,14 @@ pub fn port_recv( } pub fn port_poll( - port_cap: z_cap_t, + port_cap: &Capability, bytes: &mut [u8], caps: &mut [u64], ) -> Result<(u64, u64), ZError> { let mut num_bytes = bytes.len() as u64; let mut num_caps = caps.len() as u64; let req = zion::ZPortPollReq { - port_cap, + port_cap: port_cap.raw(), data: bytes.as_mut_ptr() as *mut c_void, num_bytes: &mut num_bytes as *mut u64, caps: caps.as_mut_ptr(), @@ -259,7 +274,7 @@ pub fn port_poll( Ok((num_bytes, num_caps)) } -pub fn endpoint_create() -> Result { +pub fn endpoint_create() -> Result { let mut endpoint_cap: z_cap_t = 0; syscall( zion::kZionEndpointCreate, @@ -267,19 +282,19 @@ pub fn endpoint_create() -> Result { endpoint_cap: &mut endpoint_cap, }, )?; - Ok(endpoint_cap) + Ok(Capability::take(endpoint_cap)) } pub fn endpoint_send( - endpoint_cap: z_cap_t, + endpoint_cap: &Capability, bytes: &[u8], caps: &[z_cap_t], -) -> Result { +) -> Result { let mut reply_port_cap: u64 = 0; let send_req = zion::ZEndpointSendReq { caps: caps.as_ptr(), num_caps: caps.len() as u64, - endpoint_cap, + endpoint_cap: endpoint_cap.raw(), data: bytes.as_ptr() as *const c_void, num_bytes: bytes.len() as u64, reply_port_cap: &mut reply_port_cap, @@ -287,19 +302,19 @@ pub fn endpoint_send( syscall(zion::kZionEndpointSend, &send_req)?; - Ok(reply_port_cap) + Ok(Capability::take(reply_port_cap)) } pub fn endpoint_recv( - endpoint_cap: z_cap_t, + endpoint_cap: &Capability, bytes: &mut [u8], caps: &mut [z_cap_t], -) -> Result<(u64, u64, z_cap_t), ZError> { +) -> Result<(u64, u64, Capability), ZError> { let mut num_bytes = bytes.len() as u64; let mut num_caps = caps.len() as u64; let mut reply_port_cap = 0; let recv_req = zion::ZEndpointRecvReq { - endpoint_cap, + endpoint_cap: endpoint_cap.raw(), data: bytes.as_mut_ptr() as *mut c_void, num_bytes: &mut num_bytes, caps: caps.as_mut_ptr(), @@ -309,18 +324,18 @@ pub fn endpoint_recv( syscall(zion::kZionEndpointRecv, &recv_req)?; - Ok((num_bytes, num_caps, reply_port_cap)) + Ok((num_bytes, num_caps, Capability::take(reply_port_cap))) } pub fn reply_port_send( - reply_port_cap: z_cap_t, + reply_port_cap: Capability, bytes: &[u8], caps: &[z_cap_t], ) -> Result<(), ZError> { syscall( zion::kZionReplyPortSend, &zion::ZReplyPortSendReq { - reply_port_cap, + reply_port_cap: reply_port_cap.raw(), data: bytes.as_ptr() as *const c_void, num_bytes: bytes.len() as u64, caps: caps.as_ptr(), @@ -330,14 +345,14 @@ pub fn reply_port_send( } pub fn reply_port_recv( - reply_port_cap: z_cap_t, + reply_port_cap: Capability, bytes: &mut [u8], caps: &mut [z_cap_t], ) -> Result<(u64, u64), ZError> { let mut num_bytes = bytes.len() as u64; let mut num_caps = caps.len() as u64; let recv_req = zion::ZReplyPortRecvReq { - reply_port_cap, + reply_port_cap: reply_port_cap.raw(), caps: caps.as_mut_ptr(), num_caps: &mut num_caps, data: bytes.as_mut_ptr() as *mut c_void, @@ -348,20 +363,3 @@ pub fn reply_port_recv( Ok((num_bytes, num_caps)) } - -pub fn cap_duplicate(cap: z_cap_t, perm_mask: u64) -> Result { - let mut new_cap = 0; - syscall( - zion::kZionCapDuplicate, - &zion::ZCapDuplicateReq { - cap_in: cap, - perm_mask, - cap_out: &mut new_cap, - }, - )?; - Ok(new_cap) -} - -pub fn cap_release(cap: z_cap_t) -> Result<(), ZError> { - syscall(zion::kZionCapRelease, &zion::ZCapReleaseReq { cap }) -} diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 92fd086..9d2e688 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -1,6 +1,6 @@ +use crate::cap::Capability; use crate::syscall; use crate::zion; -use crate::zion::z_cap_t; use alloc::boxed::Box; use core::ffi::c_void; @@ -17,7 +17,7 @@ extern "C" fn internal_entry_point(thread_ptr: *const Thread, arg1: *const c_voi } // TODO: Add a Drop implementation that kills this thread and drops its capability. pub struct Thread { - cap: z_cap_t, + cap: Capability, // This field only exists to ensure that the entry reference will outlive the thread object // itself. entry: ThreadEntry, @@ -25,11 +25,11 @@ pub struct Thread { impl Thread { pub fn spawn(entry: ThreadEntry, arg1: *const c_void) -> Result, zion::ZError> { - let proc_cap = unsafe { crate::init::SELF_PROC_CAP }; - let cap = syscall::thread_create(proc_cap)?; + let proc_cap = Capability::take_copy(unsafe { crate::init::SELF_PROC_CAP })?; + let cap = syscall::thread_create(&proc_cap)?; let thread = Box::new(Self { cap, entry }); syscall::thread_start( - cap, + &thread.cap, internal_entry_point as u64, thread.as_ref() as *const Thread as u64, arg1 as u64, @@ -39,6 +39,6 @@ impl Thread { } pub fn join(&self) -> Result<(), zion::ZError> { - syscall::thread_wait(self.cap) + syscall::thread_wait(&self.cap) } } diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs index 4877a09..619c4c7 100644 --- a/rust/lib/victoriafalls/src/file.rs +++ b/rust/lib/victoriafalls/src/file.rs @@ -1,6 +1,6 @@ use crate::OpenFileRequest; use alloc::string::ToString; -use mammoth::zion::ZError; +use mammoth::{cap::Capability, zion::ZError}; pub struct File { memory: mammoth::mem::MemoryRegion, @@ -14,7 +14,7 @@ impl File { })?; Ok(Self { - memory: mammoth::mem::MemoryRegion::from_cap(resp.memory)?, + memory: mammoth::mem::MemoryRegion::from_cap(Capability::take(resp.memory))?, }) } diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/lib/victoriafalls/src/lib.rs index b1532a9..6248bc5 100644 --- a/rust/lib/victoriafalls/src/lib.rs +++ b/rust/lib/victoriafalls/src/lib.rs @@ -18,7 +18,7 @@ fn get_client() -> &'static mut VFSClient { }) .expect("Failed to get VFS endpoint"); - VFS_CLIENT = Some(VFSClient::new(endpoint_cap.endpoint)); + VFS_CLIENT = Some(VFSClient::new(Capability::take(endpoint_cap.endpoint))); } VFS_CLIENT.as_mut().unwrap() } diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs index a64626e..b340ed3 100644 --- a/rust/lib/voyageurs/src/listener.rs +++ b/rust/lib/voyageurs/src/listener.rs @@ -3,6 +3,7 @@ use core::cell::RefCell; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::string::ToString; +use mammoth::cap::Capability; use mammoth::port::PortServer; use mammoth::thread::Thread; use mammoth::zion::ZError; @@ -216,7 +217,7 @@ impl KeyboardListener { })? .endpoint; - let mut voyageur_client = crate::VoyageursClient::new(voyageur_endpoint); + let mut voyageur_client = crate::VoyageursClient::new(Capability::take(voyageur_endpoint)); voyageur_client.register_keyboard_listener(&crate::KeyboardListener { port_capability: listnr.listen_port.create_client_cap()?, diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs index 0fc673f..76659ef 100644 --- a/rust/lib/yellowstone/src/lib.rs +++ b/rust/lib/yellowstone/src/lib.rs @@ -11,7 +11,7 @@ static mut YELLOWSTONE_INIT: Option = None; pub fn from_init_endpoint() -> &'static mut YellowstoneClient { unsafe { if let None = YELLOWSTONE_INIT { - YELLOWSTONE_INIT = Some(YellowstoneClient::new(INIT_ENDPOINT)); + YELLOWSTONE_INIT = Some(YellowstoneClient::new(Capability::take(INIT_ENDPOINT))); } YELLOWSTONE_INIT.as_mut().unwrap() diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index ad3a761..e90698e 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -1,14 +1,14 @@ use crate::buffer::ByteBuffer; use crate::message::YunqMessage; use alloc::vec::Vec; -use mammoth::zion::z_cap_t; +use mammoth::cap::Capability; use mammoth::zion::ZError; pub fn call_endpoint( request_id: u64, req: &Req, byte_buffer: &mut ByteBuffer, - endpoint_cap: z_cap_t, + endpoint_cap: &Capability, ) -> Result { let mut cap_buffer = Vec::new(); let length = req.serialize_as_request(request_id, byte_buffer, &mut cap_buffer)?; diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index c8c4f36..9616d6e 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -1,5 +1,6 @@ use crate::buffer::ByteBuffer; use alloc::vec::Vec; +use mammoth::cap::Capability; use mammoth::syscall; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; @@ -36,7 +37,7 @@ pub trait YunqServer { } } - fn endpoint_cap(&self) -> z_cap_t; + fn endpoint_cap(&self) -> &Capability; fn handle_request( &self, method_number: u64, diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 0ce7a53..5c7d314 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -117,9 +117,9 @@ impl Terminal { Some(prog) => { let file = victoriafalls::file::File::open(prog).expect("Failed to open file"); let proc_cap = mammoth::elf::spawn_process_from_elf(file.slice()) - .expect("Faield to spawn process"); + .expect("Failed to spawn process"); - let exit_code = mammoth::syscall::process_wait(proc_cap) + let exit_code = mammoth::syscall::process_wait(&proc_cap) .expect("Failed to wait on process."); self.write_line(&format!("Process exit code: {}", exit_code)); diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 0e994b5..9b6ad6b 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -9,7 +9,6 @@ use mammoth::define_entry; use mammoth::thread; use mammoth::zion::z_err_t; use yellowstone::GetEndpointRequest; -use yellowstone::YellowstoneClient; define_entry!(); @@ -17,10 +16,9 @@ define_entry!(); pub extern "C" fn main() -> z_err_t { debug!("Testing!"); - let mut yellowstone; - unsafe { - yellowstone = YellowstoneClient::new(mammoth::init::INIT_ENDPOINT); - } + let yellowstone = yellowstone::from_init_endpoint(); + + debug!("Get endpoint"); let endpoint = yellowstone .get_endpoint(&GetEndpointRequest { diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 31f61e4..34477cf 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -33,17 +33,17 @@ fn generate_method(method: &Method) -> TokenStream { match (maybe_req, maybe_resp) { (Some(req), Some(resp)) => quote! { pub fn #name (&mut self, req: & #req) -> Result<#resp, ZError> { - yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, &self.endpoint_cap) } }, (Some(req), None) => quote! { pub fn #name (&mut self, req: & #req) -> Result { - yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, req, &mut self.byte_buffer, &self.endpoint_cap) } }, (None, Some(resp)) => quote! { pub fn #name (&mut self) -> Result<#resp, ZError> { - yunq::client::call_endpoint(#id, &yunq::message::Empty{}, &mut self.byte_buffer, self.endpoint_cap) + yunq::client::call_endpoint(#id, &yunq::message::Empty{}, &mut self.byte_buffer, &self.endpoint_cap) } }, _ => unreachable!(), @@ -56,12 +56,12 @@ fn generate_client(interface: &Interface) -> TokenStream { let methods = interface.methods.iter().map(|m| generate_method(&m)); quote! { pub struct #name { - endpoint_cap: z_cap_t, + endpoint_cap: Capability, byte_buffer: ByteBuffer<0x1000>, } impl #name { - pub fn new(endpoint_cap: z_cap_t) -> Self { + pub fn new(endpoint_cap: Capability) -> Self { Self { endpoint_cap, byte_buffer: ByteBuffer::new(), @@ -139,7 +139,7 @@ fn generate_server(interface: &Interface) -> TokenStream { } pub struct #server_name { - endpoint_cap: z_cap_t, + endpoint_cap: Capability, handler: T } @@ -164,8 +164,8 @@ fn generate_server(interface: &Interface) -> TokenStream { } impl yunq::server::YunqServer for #server_name { - fn endpoint_cap(&self) -> z_cap_t { - self.endpoint_cap + fn endpoint_cap(&self) -> &Capability { + &self.endpoint_cap } fn handle_request( @@ -206,6 +206,7 @@ pub fn generate_code(ast: &Vec) -> String { use core::ffi::c_void; use mammoth::syscall; use mammoth::thread; + use mammoth::cap::Capability; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; use yunq::ByteBuffer; From 7825d1861a3bfb74a777a705f6b1195fa31b2fd4 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 17:49:06 -0700 Subject: [PATCH 114/186] [Zion] Check right permission for reply port send. --- zion/syscall/ipc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zion/syscall/ipc.cpp b/zion/syscall/ipc.cpp index 98e6a49..021695c 100644 --- a/zion/syscall/ipc.cpp +++ b/zion/syscall/ipc.cpp @@ -202,7 +202,7 @@ glcr::ErrorCode EndpointRecv(ZEndpointRecvReq* req) { glcr::ErrorCode ReplyPortSend(ZReplyPortSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto reply_port_cap = proc.GetCapability(req->reply_port_cap); - RET_ERR(ValidateCapability(reply_port_cap, kZionPerm_Read)); + RET_ERR(ValidateCapability(reply_port_cap, kZionPerm_Write)); auto reply_port = reply_port_cap->obj(); ASSIGN_OR_RETURN(IpcMessage message, TranslateRequestToIpcMessage(*req)); From 52f530f8c19ae248480d4b42f945083cbee0b80e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 20:18:03 -0700 Subject: [PATCH 115/186] Add yunq support for nested messages. --- rust/lib/yunq-derive/src/lib.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/rust/lib/yunq-derive/src/lib.rs b/rust/lib/yunq-derive/src/lib.rs index cf72f4a..d1652e0 100644 --- a/rust/lib/yunq-derive/src/lib.rs +++ b/rust/lib/yunq-derive/src/lib.rs @@ -33,10 +33,16 @@ fn serialize_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenS } } } else { - panic!( - "Serialization not implemented for: {}", - path.to_token_stream() - ) + quote! { + { + let msg_offset = next_extension; + let msg_length = self.#name.serialize(buf, offset + next_extension as usize, caps)? as u32; + next_extension += msg_length; + + buf.write_at(yunq::message::field_offset(offset, #ind), msg_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, msg_length)?; + } + } } } @@ -62,7 +68,13 @@ fn parse_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStrea let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; } } else { - panic!("Parsing not implemented for: {}", path.into_token_stream()); + quote! { + let #name = { + let msg_offset = buf.at::(yunq::message::field_offset(offset, #ind))? as usize; + + #path::parse(buf, offset + msg_offset, caps)? + }; + } } } From f551cc88cd67e03dbeca16f0dbd7c9e6e61fb929 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 20:18:25 -0700 Subject: [PATCH 116/186] [Yunq] Allow creating a client cap. --- rust/lib/yunq/src/server.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index 9616d6e..0a7d77e 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -38,6 +38,11 @@ pub trait YunqServer { } fn endpoint_cap(&self) -> &Capability; + + fn create_client_cap(&self) -> Result { + self.endpoint_cap() + .duplicate(!mammoth::zion::kZionPerm_Read) + } fn handle_request( &self, method_number: u64, From 0aa4a1f5f16888f1955be8ae1c509f1a969c74a8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 20:18:54 -0700 Subject: [PATCH 117/186] [Zion] Allow loading from an offset program segment. --- zion/loader/init_loader.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index 285fc37..b05c70a 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -13,7 +13,7 @@ #include "scheduler/process_manager.h" #include "scheduler/scheduler.h" -#define K_INIT_DEBUG 0 +#define K_INIT_DEBUG 1 namespace { @@ -67,6 +67,9 @@ uint64_t LoadElfProgram(Process& dest_proc, uint64_t base, uint64_t offset) { reinterpret_cast(base + header->phoff); for (uint64_t i = 0; i < header->phnum; i++) { Elf64ProgramHeader& program = programs[i]; + if (program.type != 1) { + continue; + } #if K_INIT_DEBUG dbgln( "prog: type: {}, flags: {}, offset: {}\n vaddr: {x}, paddr: {x}\n " @@ -74,12 +77,19 @@ uint64_t LoadElfProgram(Process& dest_proc, uint64_t base, uint64_t offset) { program.type, program.flags, program.offset, program.vaddr, program.paddr, program.filesz, program.memsz, program.align); #endif - auto mem_obj = glcr::MakeRefCounted(program.memsz); - mem_obj->CopyBytesToObject(base + program.offset, program.filesz); - PANIC_ON_ERR( - dest_proc.vmas()->MapInMemoryObject( - program.vaddr, glcr::StaticCastRefPtr(mem_obj)), - "Couldn't map in init program."); + uint64_t page_offset = program.vaddr & 0xFFF; + auto mem_obj = + glcr::MakeRefCounted(program.memsz + page_offset); + + // Super hacky but if we adjust the offsets to handle a non-aligned page. + mem_obj->CopyBytesToObject(base + program.offset - page_offset, + program.filesz + page_offset); + auto map_res = dest_proc.vmas()->MapInMemoryObject( + program.vaddr - page_offset, + glcr::StaticCastRefPtr(mem_obj)); + if (map_res != glcr::OK) { + panic("Couldn't map in init program {}", map_res); + } } return header->entry; } From c9b484089e7272f25841d46ef097dc25e1da37e3 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 20:19:45 -0700 Subject: [PATCH 118/186] [Yellowstone] Wireframe for moving yellowstone to rust. --- rust/Cargo.lock | 30 +++++++++++++--- rust/Cargo.toml | 4 +-- rust/lib/denali/Cargo.toml | 12 +++++++ rust/lib/denali/build.rs | 14 ++++++++ rust/lib/denali/src/lib.rs | 5 +++ rust/lib/mammoth/src/elf.rs | 15 +++++--- rust/lib/mammoth/src/init.rs | 14 ++++++++ rust/lib/mammoth/src/lib.rs | 1 + rust/lib/mammoth/src/sync.rs | 19 ++++++++++ rust/lib/mammoth/src/syscall.rs | 30 ++++++++++++++++ rust/lib/victoriafalls/Cargo.toml | 2 +- rust/lib/victoriafalls/src/lib.rs | 4 +-- rust/lib/voyageurs/Cargo.toml | 2 +- rust/lib/voyageurs/src/listener.rs | 4 +-- rust/lib/yellowstone/Cargo.toml | 2 +- rust/sys/teton/Cargo.toml | 2 +- rust/sys/teton/src/framebuffer.rs | 2 +- rust/sys/teton/src/main.rs | 2 +- rust/sys/yellowstone/Cargo.toml | 12 +++++++ rust/sys/yellowstone/src/main.rs | 48 +++++++++++++++++++++++++ rust/sys/yellowstone/src/server.rs | 58 ++++++++++++++++++++++++++++++ rust/usr/testbed/Cargo.toml | 2 +- rust/usr/testbed/src/main.rs | 4 +-- scripts/build_image.sh | 2 +- 24 files changed, 265 insertions(+), 25 deletions(-) create mode 100644 rust/lib/denali/Cargo.toml create mode 100644 rust/lib/denali/build.rs create mode 100644 rust/lib/denali/src/lib.rs create mode 100644 rust/lib/mammoth/src/sync.rs create mode 100644 rust/sys/yellowstone/Cargo.toml create mode 100644 rust/sys/yellowstone/src/main.rs create mode 100644 rust/sys/yellowstone/src/server.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c1a17bd..2874dee 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -17,6 +17,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "denali" +version = "0.1.0" +dependencies = [ + "mammoth", + "yunq", + "yunq-derive", + "yunqc", +] + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -113,7 +123,7 @@ name = "testbed" version = "0.1.0" dependencies = [ "mammoth", - "yellowstone", + "yellowstone-yunq", "yunq", ] @@ -124,7 +134,7 @@ dependencies = [ "mammoth", "victoriafalls", "voyageurs", - "yellowstone", + "yellowstone-yunq", ] [[package]] @@ -144,7 +154,7 @@ name = "victoriafalls" version = "0.1.0" dependencies = [ "mammoth", - "yellowstone", + "yellowstone-yunq", "yunq", "yunq-derive", "yunqc", @@ -155,7 +165,7 @@ name = "voyageurs" version = "0.1.0" dependencies = [ "mammoth", - "yellowstone", + "yellowstone-yunq", "yunq", "yunq-derive", "yunqc", @@ -164,6 +174,18 @@ dependencies = [ [[package]] name = "yellowstone" version = "0.1.0" +dependencies = [ + "denali", + "mammoth", + "victoriafalls", + "voyageurs", + "yellowstone-yunq", + "yunq", +] + +[[package]] +name = "yellowstone-yunq" +version = "0.1.0" dependencies = [ "mammoth", "yunq", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 24f2adc..589f7ad 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] -members = [ - "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "usr/testbed", +members = [ "lib/denali", + "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "sys/yellowstone", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/denali/Cargo.toml b/rust/lib/denali/Cargo.toml new file mode 100644 index 0000000..e05782f --- /dev/null +++ b/rust/lib/denali/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "denali" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth" } +yunq = {path = "../yunq"} +yunq-derive = {path = "../yunq-derive"} + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} diff --git a/rust/lib/denali/build.rs b/rust/lib/denali/build.rs new file mode 100644 index 0000000..d5ac830 --- /dev/null +++ b/rust/lib/denali/build.rs @@ -0,0 +1,14 @@ +use std::fs; + +fn main() { + let input_file = "../../../sys/denali/lib/denali/denali.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + fs::write(out, code).expect("Failed to write generated code."); +} diff --git a/rust/lib/denali/src/lib.rs b/rust/lib/denali/src/lib.rs new file mode 100644 index 0000000..3cec9d6 --- /dev/null +++ b/rust/lib/denali/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +use core::include; + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs index 321063d..2b8638f 100644 --- a/rust/lib/mammoth/src/elf.rs +++ b/rust/lib/mammoth/src/elf.rs @@ -13,9 +13,7 @@ const ELF_IDENT_64BIT: u8 = 0x2; const ELF_ENDIAN_LITTLE: u8 = 0x1; const ELF_ENDIAN_BIG: u8 = 0x2; - const ELF_VERSION_CURRENT: u8 = 0x1; - const ELF_ABI_SYSV: u8 = 0x0; const ELF_ABI_LINUX: u8 = 0x3; @@ -312,7 +310,10 @@ fn load_elf_program(elf_file: &[u8], vmas: &Capability) -> Result { Ok(header.entry) } -pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { +pub fn spawn_process_from_elf_and_init( + elf_file: &[u8], + init_cap: Capability, +) -> Result { let self_cap = Capability::take_copy(unsafe { init::SELF_PROC_CAP })?; let port_cap = syscall::port_create()?; @@ -328,8 +329,7 @@ pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { new_proc_cap.duplicate(Capability::PERMS_ALL)?, )?; port.write_u64_and_cap(crate::init::Z_INIT_SELF_VMAS, new_as_cap)?; - let yellowstone = Capability::take_copy(unsafe { crate::init::INIT_ENDPOINT })?; - port.write_u64_and_cap(crate::init::Z_INIT_ENDPOINT, yellowstone)?; + port.write_u64_and_cap(crate::init::Z_INIT_ENDPOINT, init_cap)?; let thread_cap = syscall::thread_create(&new_proc_cap)?; @@ -337,3 +337,8 @@ pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { Ok(new_proc_cap) } + +pub fn spawn_process_from_elf(elf_file: &[u8]) -> Result { + let yellowstone = Capability::take_copy(unsafe { crate::init::INIT_ENDPOINT })?; + spawn_process_from_elf_and_init(elf_file, yellowstone) +} diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs index a03eed7..556cf24 100644 --- a/rust/lib/mammoth/src/init.rs +++ b/rust/lib/mammoth/src/init.rs @@ -6,11 +6,21 @@ use crate::zion::z_cap_t; pub const Z_INIT_SELF_PROC: u64 = 0x4000_0000; pub const Z_INIT_SELF_VMAS: u64 = 0x4000_0001; pub const Z_INIT_ENDPOINT: u64 = 0x4100_0000; +const Z_BOOT_DENALI_VMMO: u64 = 0x4200_0000; +const Z_BOOT_VICTORIA_FALLS_VMMO: u64 = 0x4200_0001; +const Z_BOOT_PCI_VMMO: u64 = 0x4200_0002; +const Z_BOOT_FRAMEBUFFER_INFO_VMMO: u64 = 0x4200_0003; pub static mut SELF_PROC_CAP: z_cap_t = 0; pub static mut SELF_VMAS_CAP: z_cap_t = 0; pub static mut INIT_ENDPOINT: z_cap_t = 0; +// Boot capabilities, are generally only passed to yellowstone. +pub static mut BOOT_DENALI_VMMO: z_cap_t = 0; +pub static mut BOOT_VICTORIA_FALLS_VMMO: z_cap_t = 0; +pub static mut BOOT_PCI_VMMO: z_cap_t = 0; +pub static mut BOOT_FRAMEBUFFER_INFO_VMMO: z_cap_t = 0; + pub fn parse_init_port(port_cap: z_cap_t) { let init_port = Capability::take(port_cap); loop { @@ -29,6 +39,10 @@ pub fn parse_init_port(port_cap: z_cap_t) { Z_INIT_SELF_PROC => SELF_PROC_CAP = caps[0], Z_INIT_SELF_VMAS => SELF_VMAS_CAP = caps[0], Z_INIT_ENDPOINT => INIT_ENDPOINT = caps[0], + Z_BOOT_DENALI_VMMO => BOOT_DENALI_VMMO = caps[0], + Z_BOOT_VICTORIA_FALLS_VMMO => BOOT_VICTORIA_FALLS_VMMO = caps[0], + Z_BOOT_PCI_VMMO => BOOT_PCI_VMMO = caps[0], + Z_BOOT_FRAMEBUFFER_INFO_VMMO => BOOT_FRAMEBUFFER_INFO_VMMO = caps[0], _ => syscall::debug("Unknown Cap in Init"), } } diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index b0891a6..cf5d3f0 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -14,6 +14,7 @@ pub mod elf; pub mod init; pub mod mem; pub mod port; +pub mod sync; pub mod syscall; pub mod thread; pub mod zion; diff --git a/rust/lib/mammoth/src/sync.rs b/rust/lib/mammoth/src/sync.rs new file mode 100644 index 0000000..8d80f17 --- /dev/null +++ b/rust/lib/mammoth/src/sync.rs @@ -0,0 +1,19 @@ +use crate::{cap::Capability, syscall, zion::ZError}; + +pub struct Semaphore { + cap: Capability, +} + +impl Semaphore { + pub fn new() -> Result { + syscall::semaphore_create().map(|cap| Self { cap }) + } + + pub fn wait(&self) -> Result<(), ZError> { + syscall::semaphone_wait(&self.cap) + } + + pub fn signal(&self) -> Result<(), ZError> { + syscall::semaphone_signal(&self.cap) + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 1c2d892..3d3635a 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -363,3 +363,33 @@ pub fn reply_port_recv( Ok((num_bytes, num_caps)) } + +pub fn semaphore_create() -> Result { + let mut sem_cap: z_cap_t = 0; + syscall( + zion::kZionSemaphoreCreate, + &zion::ZSemaphoreCreateReq { + semaphore_cap: &mut sem_cap, + }, + )?; + + Ok(Capability::take(sem_cap)) +} + +pub fn semaphone_signal(sem_cap: &Capability) -> Result<(), ZError> { + syscall( + zion::kZionSemaphoreSignal, + &zion::ZSemaphoreSignalReq { + semaphore_cap: sem_cap.raw(), + }, + ) +} + +pub fn semaphone_wait(sem_cap: &Capability) -> Result<(), ZError> { + syscall( + zion::kZionSemaphoreWait, + &zion::ZSemaphoreWaitReq { + semaphore_cap: sem_cap.raw(), + }, + ) +} diff --git a/rust/lib/victoriafalls/Cargo.toml b/rust/lib/victoriafalls/Cargo.toml index 7f3566b..aeb0bf1 100644 --- a/rust/lib/victoriafalls/Cargo.toml +++ b/rust/lib/victoriafalls/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] mammoth = { path = "../mammoth" } -yellowstone = { path = "../yellowstone" } +yellowstone-yunq = { path = "../yellowstone" } yunq = {path = "../yunq"} yunq-derive = {path = "../yunq-derive"} diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/lib/victoriafalls/src/lib.rs index 6248bc5..f6887c4 100644 --- a/rust/lib/victoriafalls/src/lib.rs +++ b/rust/lib/victoriafalls/src/lib.rs @@ -12,8 +12,8 @@ static mut VFS_CLIENT: Option = None; fn get_client() -> &'static mut VFSClient { unsafe { if let None = VFS_CLIENT { - let endpoint_cap = yellowstone::from_init_endpoint() - .get_endpoint(&yellowstone::GetEndpointRequest { + let endpoint_cap = yellowstone_yunq::from_init_endpoint() + .get_endpoint(&yellowstone_yunq::GetEndpointRequest { endpoint_name: "victoriafalls".to_string(), }) .expect("Failed to get VFS endpoint"); diff --git a/rust/lib/voyageurs/Cargo.toml b/rust/lib/voyageurs/Cargo.toml index a007692..b396220 100644 --- a/rust/lib/voyageurs/Cargo.toml +++ b/rust/lib/voyageurs/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] mammoth = { path = "../mammoth" } -yellowstone = { path = "../yellowstone" } +yellowstone-yunq = { path = "../yellowstone" } yunq = {path = "../yunq"} yunq-derive = {path = "../yunq-derive"} diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs index b340ed3..78a4f4a 100644 --- a/rust/lib/voyageurs/src/listener.rs +++ b/rust/lib/voyageurs/src/listener.rs @@ -211,8 +211,8 @@ impl KeyboardListener { handler, }); - let voyageur_endpoint = yellowstone::from_init_endpoint() - .get_endpoint(&yellowstone::GetEndpointRequest { + let voyageur_endpoint = yellowstone_yunq::from_init_endpoint() + .get_endpoint(&yellowstone_yunq::GetEndpointRequest { endpoint_name: "voyageurs".to_string(), })? .endpoint; diff --git a/rust/lib/yellowstone/Cargo.toml b/rust/lib/yellowstone/Cargo.toml index 59ea732..c9a6299 100644 --- a/rust/lib/yellowstone/Cargo.toml +++ b/rust/lib/yellowstone/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "yellowstone" +name = "yellowstone-yunq" version = "0.1.0" edition = "2021" diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml index a355119..1bcda15 100644 --- a/rust/sys/teton/Cargo.toml +++ b/rust/sys/teton/Cargo.toml @@ -7,4 +7,4 @@ edition = "2021" mammoth = { path = "../../lib/mammoth" } victoriafalls = { path = "../../lib/victoriafalls" } voyageurs = { path = "../../lib/voyageurs" } -yellowstone = { path = "../../lib/yellowstone" } +yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/teton/src/framebuffer.rs b/rust/sys/teton/src/framebuffer.rs index 856b0c1..dad4099 100644 --- a/rust/sys/teton/src/framebuffer.rs +++ b/rust/sys/teton/src/framebuffer.rs @@ -1,5 +1,5 @@ use mammoth::{mem::MemoryRegion, zion::ZError}; -use yellowstone::FramebufferInfo; +use yellowstone_yunq::FramebufferInfo; pub struct Framebuffer { fb_info: FramebufferInfo, diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs index b1866d2..5cec4fb 100644 --- a/rust/sys/teton/src/main.rs +++ b/rust/sys/teton/src/main.rs @@ -20,7 +20,7 @@ define_entry!(); extern "C" fn main() -> z_err_t { debug!("Teton Starting"); - let yellowstone = yellowstone::from_init_endpoint(); + let yellowstone = yellowstone_yunq::from_init_endpoint(); let framebuffer_info = yellowstone .get_framebuffer_info() .expect("Failed to get framebuffer info."); diff --git a/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml new file mode 100644 index 0000000..57e52b8 --- /dev/null +++ b/rust/sys/yellowstone/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "yellowstone" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../../lib/mammoth" } +denali = { path = "../../lib/denali" } +victoriafalls = { path = "../../lib/victoriafalls" } +voyageurs = { path = "../../lib/voyageurs" } +yellowstone-yunq = { path = "../../lib/yellowstone" } +yunq = { path = "../../lib/yunq" } diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs new file mode 100644 index 0000000..f416168 --- /dev/null +++ b/rust/sys/yellowstone/src/main.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +use mammoth::{ + cap::Capability, + define_entry, elf, + zion::{kZionPerm_Read, z_cap_t, z_err_t, ZError}, +}; +use yellowstone_yunq::YellowstoneServer; +use yunq::server::YunqServer; + +mod server; + +define_entry!(); + +fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZError> { + let region = mammoth::mem::MemoryRegion::from_cap(Capability::take(vmmo_cap))?; + elf::spawn_process_from_elf_and_init(region.slice(), server_cap)?; + Ok(()) +} + +#[no_mangle] +extern "C" fn main() -> z_err_t { + let context = alloc::rc::Rc::new( + server::YellowstoneServerContext::new().expect("Failed to create yellowstone context"), + ); + let handler = server::YellowstoneServerImpl::new(context.clone()); + let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); + + let server_thread = server.run_server().expect("Failed to run server"); + + spawn_from_vmmo( + unsafe { mammoth::init::BOOT_DENALI_VMMO }, + server + .create_client_cap() + .expect("Failed to create client cap for denali"), + ) + .expect("Failed to spawn denali"); + + context.wait_denali().expect("Failed to wait for denali"); + + mammoth::debug!("Denali registered."); + + server_thread.join().expect("Failed to join thread"); + 0 +} diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs new file mode 100644 index 0000000..d3da021 --- /dev/null +++ b/rust/sys/yellowstone/src/server.rs @@ -0,0 +1,58 @@ +use alloc::rc::Rc; +use mammoth::zion::ZError; +use yellowstone_yunq::{ + AhciInfo, DenaliInfo, Endpoint, FramebufferInfo, GetEndpointRequest, RegisterEndpointRequest, + XhciInfo, YellowstoneServerHandler, +}; + +pub struct YellowstoneServerContext { + denali_semaphore: mammoth::sync::Semaphore, +} + +impl YellowstoneServerContext { + pub fn new() -> Result { + Ok(Self { + denali_semaphore: mammoth::sync::Semaphore::new()?, + }) + } + + pub fn wait_denali(&self) -> Result<(), ZError> { + self.denali_semaphore.wait() + } +} + +pub struct YellowstoneServerImpl { + context: Rc, +} + +impl YellowstoneServerImpl { + pub fn new(context: Rc) -> Self { + Self { context } + } +} + +impl YellowstoneServerHandler for YellowstoneServerImpl { + fn register_endpoint(&self, req: &RegisterEndpointRequest) -> Result<(), ZError> { + todo!() + } + + fn get_endpoint(&self, req: &GetEndpointRequest) -> Result { + todo!() + } + + fn get_ahci_info(&self) -> Result { + todo!() + } + + fn get_xhci_info(&self) -> Result { + todo!() + } + + fn get_framebuffer_info(&self) -> Result { + todo!() + } + + fn get_denali(&self) -> Result { + todo!() + } +} diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml index 7934e6c..aff88d2 100644 --- a/rust/usr/testbed/Cargo.toml +++ b/rust/usr/testbed/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -yellowstone = { path = "../../lib/yellowstone" } +yellowstone-yunq = { path = "../../lib/yellowstone" } yunq = { path = "../../lib/yunq" } diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 9b6ad6b..a6a5ca0 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -8,7 +8,7 @@ use mammoth::debug; use mammoth::define_entry; use mammoth::thread; use mammoth::zion::z_err_t; -use yellowstone::GetEndpointRequest; +use yellowstone_yunq::GetEndpointRequest; define_entry!(); @@ -16,7 +16,7 @@ define_entry!(); pub extern "C" fn main() -> z_err_t { debug!("Testing!"); - let yellowstone = yellowstone::from_init_endpoint(); + let yellowstone = yellowstone_yunq::from_init_endpoint(); debug!("Get endpoint"); diff --git a/scripts/build_image.sh b/scripts/build_image.sh index e26074f..826bdd4 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -39,7 +39,7 @@ cp /usr/share/limine/limine-bios.sys efi/ cp ../zion/boot/limine.cfg efi/ cp zion/zion efi/ mkdir -p efi/sys -cp sys/yellowstone/yellowstone efi/sys/yellowstone +cp ../sysroot/bin/yellowstone efi/sys/yellowstone cp sys/denali/denali efi/sys/denali cp sys/victoriafalls/victoriafalls efi/sys/victoriafalls From e90018b42e20bfd070a04d7e9d7bffc0d412092a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 21:54:30 -0700 Subject: [PATCH 119/186] [Yellowstone] Allow registering denali. --- rust/lib/mammoth/src/mem.rs | 4 + rust/lib/mammoth/src/syscall.rs | 18 +++++ rust/lib/yunq/src/server.rs | 4 +- rust/sys/yellowstone/src/main.rs | 10 ++- rust/sys/yellowstone/src/pci.rs | 122 +++++++++++++++++++++++++++++ rust/sys/yellowstone/src/server.rs | 49 ++++++++---- yunq/rust/src/codegen.rs | 14 ++-- 7 files changed, 195 insertions(+), 26 deletions(-) create mode 100644 rust/sys/yellowstone/src/pci.rs diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 5f58904..89037c5 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -78,6 +78,10 @@ impl MemoryRegion { pub fn cap(&self) -> &Capability { &self.mem_cap } + + pub fn duplicate(&self, offset: u64, length: u64) -> Result { + syscall::memory_obj_duplicate(&self.mem_cap, offset, length) + } } impl Drop for MemoryRegion { diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 3d3635a..2ffaca5 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -167,6 +167,24 @@ pub fn memory_object_inspect(mem_cap: &Capability) -> Result { Ok(mem_size) } +pub fn memory_obj_duplicate( + mem_cap: &Capability, + base_offset: u64, + length: u64, +) -> Result { + let mut new_cap = 0; + syscall( + zion::kZionMemoryObjectDuplicate, + &zion::ZMemoryObjectDuplicateReq { + vmmo_cap: mem_cap.raw(), + base_offset, + length, + new_vmmo_cap: &mut new_cap, + }, + )?; + Ok(Capability::take(new_cap)) +} + pub fn address_space_map(vmmo_cap: &Capability) -> Result { let mut vaddr: u64 = 0; // FIXME: Allow caller to pass these options. diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index 0a7d77e..49d7276 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -6,7 +6,7 @@ use mammoth::zion::z_cap_t; use mammoth::zion::ZError; pub trait YunqServer { - fn server_loop(&self) { + fn server_loop(&mut self) { loop { let mut byte_buffer = ByteBuffer::<1024>::new(); let mut cap_buffer = vec![0; 10]; @@ -44,7 +44,7 @@ pub trait YunqServer { .duplicate(!mammoth::zion::kZionPerm_Read) } fn handle_request( - &self, + &mut self, method_number: u64, byte_buffer: &mut ByteBuffer<1024>, cap_buffer: &mut Vec, diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index f416168..6bbb339 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -6,11 +6,14 @@ extern crate alloc; use mammoth::{ cap::Capability, define_entry, elf, - zion::{kZionPerm_Read, z_cap_t, z_err_t, ZError}, + init::BOOT_PCI_VMMO, + mem::MemoryRegion, + zion::{z_cap_t, z_err_t, ZError}, }; use yellowstone_yunq::YellowstoneServer; use yunq::server::YunqServer; +mod pci; mod server; define_entry!(); @@ -23,8 +26,11 @@ fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZErr #[no_mangle] extern "C" fn main() -> z_err_t { + let pci_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_PCI_VMMO })) + .expect("Failed to create PCI region"); let context = alloc::rc::Rc::new( - server::YellowstoneServerContext::new().expect("Failed to create yellowstone context"), + server::YellowstoneServerContext::new(pci_region) + .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs new file mode 100644 index 0000000..b7b4116 --- /dev/null +++ b/rust/sys/yellowstone/src/pci.rs @@ -0,0 +1,122 @@ +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; + +pub struct PciReader { + memory_region: MemoryRegion, +} + +type DevPredicate = fn(u8, u8, u8) -> bool; + +impl PciReader { + pub fn new(memory_region: MemoryRegion) -> Self { + Self { memory_region } + } + + pub fn get_ahci_region(&self) -> Result { + match self.probe_pci(|class, _, _| class == 0x1) { + Some(m) => Ok(m), + None => Err(ZError::NOT_FOUND), + } + } + + fn probe_pci(&self, pred: DevPredicate) -> Option { + let base_header = self.pci_header(0, 0, 0); + if (base_header.header_type & 0x80) == 0 { + if let Some(dev) = self.probe_bus(pred, 0) { + return Some(dev); + } + } else { + for fun in 0..8 { + let fun_hdr = self.pci_header(0, 0, fun); + if fun_hdr.vendor_id != 0xFFFF { + if let Some(dev) = self.probe_bus(pred, fun) { + return Some(dev); + } + } + } + } + None + } + + fn probe_bus(&self, pred: DevPredicate, bus: u8) -> Option { + for dev in 0..0x20 { + if let Some(dev) = self.probe_device(pred, bus, dev) { + return Some(dev); + } + } + None + } + + fn probe_device(&self, pred: DevPredicate, bus: u8, dev: u8) -> Option { + let device_base_header = self.pci_header(bus, dev, 0); + if device_base_header.vendor_id == 0xFFFF { + return None; + } + + if let Some(dev) = self.probe_function(pred, bus, dev, 0) { + return Some(dev); + } + + if (device_base_header.header_type & 0x80) != 0 { + for fun in 1..8 { + if let Some(dev) = self.probe_function(pred, bus, dev, fun) { + return Some(dev); + } + } + } + None + } + + fn probe_function(&self, pred: DevPredicate, bus: u8, dev: u8, fun: u8) -> Option { + let function_header = self.pci_header(bus, dev, fun); + + mammoth::debug!( + "PCI Function: {:#x} {:#x} {:#x}", + function_header.class_code, + function_header.subclass, + function_header.prog_interface + ); + + if pred( + function_header.class_code, + function_header.subclass, + function_header.prog_interface, + ) { + mammoth::debug!("Found!"); + let offset = pci_header_offset(bus, dev, fun); + Some( + self.memory_region + .duplicate(offset as u64, 0x1000) + .expect("Failed to duplicate PCI cap"), + ) + } else { + None + } + } + + fn pci_header(&self, bus: u8, dev: u8, fun: u8) -> &PciHeader { + let offset = pci_header_offset(bus, dev, fun); + let header_slice: &[u8] = + &self.memory_region.slice()[offset..offset + size_of::()]; + unsafe { header_slice.as_ptr().cast::().as_ref().unwrap() } + } +} + +#[repr(C, packed)] +struct PciHeader { + vendor_id: u16, + device_id: u16, + command_reg: u16, + status_reg: u16, + revision: u8, + prog_interface: u8, + subclass: u8, + class_code: u8, + cache_line_size: u8, + latency_timer: u8, + header_type: u8, + bist: u8, +} + +fn pci_header_offset(bus: u8, dev: u8, fun: u8) -> usize { + ((bus as usize) << 20) | ((dev as usize) << 15) | ((fun as usize) << 12) +} diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index d3da021..037fb57 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,18 +1,23 @@ use alloc::rc::Rc; -use mammoth::zion::ZError; +use alloc::{collections::BTreeMap, string::String}; +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; use yellowstone_yunq::{ AhciInfo, DenaliInfo, Endpoint, FramebufferInfo, GetEndpointRequest, RegisterEndpointRequest, XhciInfo, YellowstoneServerHandler, }; +use crate::pci::PciReader; + pub struct YellowstoneServerContext { denali_semaphore: mammoth::sync::Semaphore, + pci_reader: PciReader, } impl YellowstoneServerContext { - pub fn new() -> Result { + pub fn new(pci_region: MemoryRegion) -> Result { Ok(Self { denali_semaphore: mammoth::sync::Semaphore::new()?, + pci_reader: PciReader::new(pci_region), }) } @@ -23,36 +28,50 @@ impl YellowstoneServerContext { pub struct YellowstoneServerImpl { context: Rc, + service_map: BTreeMap, } impl YellowstoneServerImpl { pub fn new(context: Rc) -> Self { - Self { context } + Self { + context, + service_map: BTreeMap::new(), + } } } impl YellowstoneServerHandler for YellowstoneServerImpl { - fn register_endpoint(&self, req: &RegisterEndpointRequest) -> Result<(), ZError> { + fn register_endpoint(&mut self, req: RegisterEndpointRequest) -> Result<(), ZError> { + let signal_denali = req.endpoint_name == "denali"; + self.service_map + .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); + + if signal_denali { + self.context.denali_semaphore.signal()? + } + Ok(()) + } + + fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { todo!() } - fn get_endpoint(&self, req: &GetEndpointRequest) -> Result { + fn get_ahci_info(&mut self) -> Result { + Ok(AhciInfo { + ahci_region: self.context.pci_reader.get_ahci_region()?.release(), + region_length: 0x1000, + }) + } + + fn get_xhci_info(&mut self) -> Result { todo!() } - fn get_ahci_info(&self) -> Result { + fn get_framebuffer_info(&mut self) -> Result { todo!() } - fn get_xhci_info(&self) -> Result { - todo!() - } - - fn get_framebuffer_info(&self) -> Result { - todo!() - } - - fn get_denali(&self) -> Result { + fn get_denali(&mut self) -> Result { todo!() } } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 34477cf..71e493e 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -82,7 +82,7 @@ fn generate_server_case(method: &Method) -> TokenStream { (Some(req), Some(_)) => quote! { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; - let resp = self.handler.#name(&req)?; + let resp = self.handler.#name(req)?; cap_buffer.resize(0, 0); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) @@ -91,7 +91,7 @@ fn generate_server_case(method: &Method) -> TokenStream { (Some(req), None) => quote! { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; - self.handler.#name(&req)?; + self.handler.#name(req)?; cap_buffer.resize(0, 0); // TODO: Implement serialization for EmptyMessage so this is less hacky. yunq::message::serialize_error(byte_buffer, ZError::from(0)); @@ -116,13 +116,13 @@ fn generate_server_method(method: &Method) -> TokenStream { let maybe_resp = method.response.clone().map(|r| ident(&r)); match (maybe_req, maybe_resp) { (Some(req), Some(resp)) => quote! { - fn #name (&self, req: & #req) -> Result<#resp, ZError>; + fn #name (&mut self, req: #req) -> Result<#resp, ZError>; }, (Some(req), None) => quote! { - fn #name (&self, req: & #req) -> Result<(), ZError>; + fn #name (&mut self, req: #req) -> Result<(), ZError>; }, (None, Some(resp)) => quote! { - fn #name (&self) -> Result<#resp, ZError>; + fn #name (&mut self) -> Result<#resp, ZError>; }, _ => unreachable!(), } @@ -153,7 +153,7 @@ fn generate_server(interface: &Interface) -> TokenStream { pub fn run_server(&self) -> Result, ZError> { let thread_entry = |server_ptr: *const c_void| { - let server = unsafe { (server_ptr as *const #server_name).as_ref().expect("Failed to convert to server") }; + let server = unsafe { (server_ptr as *mut #server_name).as_mut().expect("Failed to convert to server") }; server.server_loop(); }; thread::Thread::spawn( @@ -169,7 +169,7 @@ fn generate_server(interface: &Interface) -> TokenStream { } fn handle_request( - &self, + &mut self, method_number: u64, byte_buffer: &mut ByteBuffer<1024>, cap_buffer: &mut Vec, From 090441ad04ec9d19d44ae9e218b66ee588717323 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 17 Aug 2024 22:05:52 -0700 Subject: [PATCH 120/186] [Yellowstone] Spawn VFS and handle GetEndpoint. --- rust/sys/yellowstone/src/main.rs | 10 +++++++++- rust/sys/yellowstone/src/server.rs | 18 +++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index 6bbb339..2a62a1a 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -46,9 +46,17 @@ extern "C" fn main() -> z_err_t { .expect("Failed to spawn denali"); context.wait_denali().expect("Failed to wait for denali"); - mammoth::debug!("Denali registered."); + spawn_from_vmmo( + unsafe { mammoth::init::BOOT_VICTORIA_FALLS_VMMO }, + server.create_client_cap().unwrap(), + ) + .expect("Failed to spawn victoriafalls"); + + context.wait_victoria_falls().unwrap(); + mammoth::debug!("VFS Registered"); + server_thread.join().expect("Failed to join thread"); 0 } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 037fb57..8af4673 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -10,6 +10,7 @@ use crate::pci::PciReader; pub struct YellowstoneServerContext { denali_semaphore: mammoth::sync::Semaphore, + victoria_falls_semaphore: mammoth::sync::Semaphore, pci_reader: PciReader, } @@ -17,6 +18,7 @@ impl YellowstoneServerContext { pub fn new(pci_region: MemoryRegion) -> Result { Ok(Self { denali_semaphore: mammoth::sync::Semaphore::new()?, + victoria_falls_semaphore: mammoth::sync::Semaphore::new()?, pci_reader: PciReader::new(pci_region), }) } @@ -24,6 +26,10 @@ impl YellowstoneServerContext { pub fn wait_denali(&self) -> Result<(), ZError> { self.denali_semaphore.wait() } + + pub fn wait_victoria_falls(&self) -> Result<(), ZError> { + self.victoria_falls_semaphore.wait() + } } pub struct YellowstoneServerImpl { @@ -43,17 +49,27 @@ impl YellowstoneServerImpl { impl YellowstoneServerHandler for YellowstoneServerImpl { fn register_endpoint(&mut self, req: RegisterEndpointRequest) -> Result<(), ZError> { let signal_denali = req.endpoint_name == "denali"; + let signal_vfs = req.endpoint_name == "victoriafalls"; + self.service_map .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); if signal_denali { self.context.denali_semaphore.signal()? } + if signal_vfs { + self.context.victoria_falls_semaphore.signal()? + } Ok(()) } fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { - todo!() + match self.service_map.get(&req.endpoint_name) { + Some(cap) => Ok(Endpoint { + endpoint: cap.duplicate(Capability::PERMS_ALL)?.release(), + }), + None => Err(ZError::NOT_FOUND), + } } fn get_ahci_info(&mut self) -> Result { From b880c11ac7fa95ae7e0244be7fc87e83ebc715dd Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 Aug 2024 11:36:25 -0700 Subject: [PATCH 121/186] [Yellowstone] add ability to read GPT. --- rust/sys/yellowstone/src/gpt.rs | 138 +++++++++++++++++++++++++++++ rust/sys/yellowstone/src/main.rs | 1 + rust/sys/yellowstone/src/server.rs | 15 +++- 3 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 rust/sys/yellowstone/src/gpt.rs diff --git a/rust/sys/yellowstone/src/gpt.rs b/rust/sys/yellowstone/src/gpt.rs new file mode 100644 index 0000000..950baf9 --- /dev/null +++ b/rust/sys/yellowstone/src/gpt.rs @@ -0,0 +1,138 @@ +use denali::DenaliClient; +use mammoth::{cap::Capability, zion::ZError}; + +const MBR_SIG: u16 = 0xAA55; + +const GPT_OS_TYPE: u8 = 0xEE; + +#[repr(C, packed)] +struct MbrPartition { + boot_indicator: u8, + starting_chs: [u8; 3], + os_type: u8, + ending_chs: [u8; 3], + starting_lba: u32, + ending_lba: u32, +} + +#[repr(C, packed)] +struct PartitionHeader { + signature: u64, + revision: u32, + header_size: u32, + crc_32: u32, + reserved: u32, + lba_self: u64, + lba_mirror: u64, + lba_min: u64, + lba_max: u64, + guid_low: u64, + guid_high: u64, + lba_partition_entries: u64, + num_partitions: u32, + partition_entry_size: u32, + partition_entry_crc32: u32, +} + +#[repr(C, packed)] +struct PartitionEntry { + type_guid_low: u64, + type_guid_high: u64, + part_guid_low: u64, + part_guid_high: u64, + lba_start: u64, + lba_end: u64, + attrs: u64, + partition_name: [u8; 72], +} + +pub fn read_gpt(mut denali: DenaliClient) -> Result { + let resp = denali.read(&denali::ReadRequest { + device_id: 0, + block: denali::DiskBlock { lba: 0, size: 2 }, + })?; + + let first_lbas = mammoth::mem::MemoryRegion::from_cap(Capability::take(resp.memory))?; + + let maybe_mbr_sig = u16::from_le_bytes(first_lbas.slice()[0x1FE..0x200].try_into().unwrap()); + + if maybe_mbr_sig != MBR_SIG { + mammoth::debug!("MBR Sig {:#x} does not match {:#x}", maybe_mbr_sig, MBR_SIG); + return Err(ZError::FAILED_PRECONDITION); + } + + let mbr = unsafe { + first_lbas.slice::()[0x1BE..] + .as_ptr() + .cast::() + .as_ref() + .unwrap() + }; + + if mbr.os_type != GPT_OS_TYPE { + let os_type = mbr.os_type; + mammoth::debug!( + "MBR OS Type: {:#x} does not match GPT ({:#x})", + os_type, + GPT_OS_TYPE + ); + } + + let gpt_header = unsafe { + first_lbas.slice::()[512..] + .as_ptr() + .cast::() + .as_ref() + .unwrap() + }; + + let num_partitions = gpt_header.num_partitions; + let partition_entry_size = gpt_header.partition_entry_size; + let lba_partition_entries = gpt_header.lba_partition_entries; + let num_blocks = (num_partitions * partition_entry_size).div_ceil(512) as u64; + + mammoth::debug!( + "Reading partition table from LBA {}, {} entries of size {} equals {} blocks.", + lba_partition_entries, + num_partitions, + partition_entry_size, + num_blocks + ); + + let resp = denali.read(&denali::ReadRequest { + device_id: 0, + block: denali::DiskBlock { + lba: lba_partition_entries, + size: num_blocks, + }, + })?; + + let partition_table = mammoth::mem::MemoryRegion::from_cap(Capability::take(resp.memory))?; + + for ind in 0..num_partitions { + let offset = (ind * partition_entry_size) as usize; + let limit = offset + (partition_entry_size as usize); + + let partition_entry = unsafe { + partition_table.slice::()[offset..limit] + .as_ptr() + .cast::() + .as_ref() + .unwrap() + }; + + if partition_entry.type_guid_low == 0 && partition_entry.type_guid_high == 0 { + continue; + } + + const LFS_DATA_LOW: u64 = 0x477284830fc63daf; + const LFS_DATA_HIGH: u64 = 0xe47d47d8693d798e; + if partition_entry.type_guid_low == LFS_DATA_LOW + && partition_entry.type_guid_high == LFS_DATA_HIGH + { + return Ok(partition_entry.lba_start); + } + } + + Err(ZError::NOT_FOUND) +} diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index 2a62a1a..d3c84d1 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -13,6 +13,7 @@ use mammoth::{ use yellowstone_yunq::YellowstoneServer; use yunq::server::YunqServer; +mod gpt; mod pci; mod server; diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 8af4673..63a9d23 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -88,6 +88,19 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { } fn get_denali(&mut self) -> Result { - todo!() + match self.service_map.get("denali") { + Some(ep_cap) => crate::gpt::read_gpt(denali::DenaliClient::new( + ep_cap.duplicate(Capability::PERMS_ALL).unwrap(), + )) + .map(|lba| DenaliInfo { + denali_endpoint: ep_cap.duplicate(Capability::PERMS_ALL).unwrap().release(), + device_id: 0, + lba_offset: lba, + }), + None => { + mammoth::debug!("Denali not yet registered"); + Err(ZError::FAILED_PRECONDITION) + } + } } } From 8d3f77e648cc728f652d72bd9976a79819cb4884 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 Aug 2024 11:57:00 -0700 Subject: [PATCH 122/186] [Yellowstone] Read init file from disk. --- rust/lib/victoriafalls/src/file.rs | 4 +++- rust/lib/victoriafalls/src/lib.rs | 4 ++++ rust/sys/yellowstone/src/main.rs | 15 +++++++++++++++ rust/sys/yellowstone/src/server.rs | 8 ++++++-- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs index 619c4c7..2c09f53 100644 --- a/rust/lib/victoriafalls/src/file.rs +++ b/rust/lib/victoriafalls/src/file.rs @@ -4,6 +4,7 @@ use mammoth::{cap::Capability, zion::ZError}; pub struct File { memory: mammoth::mem::MemoryRegion, + len: usize, } impl File { @@ -15,10 +16,11 @@ impl File { Ok(Self { memory: mammoth::mem::MemoryRegion::from_cap(Capability::take(resp.memory))?, + len: resp.size as usize, }) } pub fn slice(&self) -> &[u8] { - self.memory.slice() + &self.memory.slice()[..self.len] } } diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/lib/victoriafalls/src/lib.rs index f6887c4..a397f36 100644 --- a/rust/lib/victoriafalls/src/lib.rs +++ b/rust/lib/victoriafalls/src/lib.rs @@ -23,3 +23,7 @@ fn get_client() -> &'static mut VFSClient { VFS_CLIENT.as_mut().unwrap() } } + +pub fn set_client(client: VFSClient) { + unsafe { VFS_CLIENT = Some(client) }; +} diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index d3c84d1..46a6c49 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -3,6 +3,7 @@ extern crate alloc; +use alloc::vec::Vec; use mammoth::{ cap::Capability, define_entry, elf, @@ -58,6 +59,20 @@ extern "C" fn main() -> z_err_t { context.wait_victoria_falls().unwrap(); mammoth::debug!("VFS Registered"); + let file = victoriafalls::file::File::open("/init.txt").unwrap(); + + let init_files: Vec<_> = core::str::from_utf8(file.slice()) + .unwrap() + .trim() + .split('\n') + .collect(); + + mammoth::debug!("Init files: {:?}", init_files); + + for bin_name in init_files { + let path = "/bin/" + bin_name; + } + server_thread.join().expect("Failed to join thread"); 0 } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 63a9d23..ef33146 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,6 +1,7 @@ use alloc::rc::Rc; use alloc::{collections::BTreeMap, string::String}; use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; +use victoriafalls::VFSClient; use yellowstone_yunq::{ AhciInfo, DenaliInfo, Endpoint, FramebufferInfo, GetEndpointRequest, RegisterEndpointRequest, XhciInfo, YellowstoneServerHandler, @@ -51,14 +52,17 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { let signal_denali = req.endpoint_name == "denali"; let signal_vfs = req.endpoint_name == "victoriafalls"; + let raw_cap = req.endpoint_capability; + self.service_map .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); if signal_denali { - self.context.denali_semaphore.signal()? + self.context.denali_semaphore.signal()?; } if signal_vfs { - self.context.victoria_falls_semaphore.signal()? + self.context.victoria_falls_semaphore.signal()?; + victoriafalls::set_client(VFSClient::new(Capability::take_copy(raw_cap).unwrap())); } Ok(()) } From bbb44be96e89c4d88fed593eecc8f9aecf703532 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 Aug 2024 12:26:15 -0700 Subject: [PATCH 123/186] [Victoriafalls] Add file access to underlying memory. --- rust/lib/victoriafalls/src/file.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/lib/victoriafalls/src/file.rs index 2c09f53..feb8eec 100644 --- a/rust/lib/victoriafalls/src/file.rs +++ b/rust/lib/victoriafalls/src/file.rs @@ -1,9 +1,9 @@ use crate::OpenFileRequest; use alloc::string::ToString; -use mammoth::{cap::Capability, zion::ZError}; +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; pub struct File { - memory: mammoth::mem::MemoryRegion, + memory: MemoryRegion, len: usize, } @@ -23,4 +23,8 @@ impl File { pub fn slice(&self) -> &[u8] { &self.memory.slice()[..self.len] } + + pub fn memory(&self) -> &MemoryRegion { + &self.memory + } } From d58cbed0df84a695dacfe51fb346d00db221d51a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 Aug 2024 12:27:16 -0700 Subject: [PATCH 124/186] [Yellowstone] Allow teton/voyageurs to fully spawn. --- rust/sys/yellowstone/src/main.rs | 31 +++++++--- rust/sys/yellowstone/src/pci.rs | 9 +++ rust/sys/yellowstone/src/server.rs | 94 ++++++++++++++++++++---------- 3 files changed, 95 insertions(+), 39 deletions(-) diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index 46a6c49..18e386f 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -3,11 +3,11 @@ extern crate alloc; -use alloc::vec::Vec; +use alloc::{string::ToString, vec::Vec}; use mammoth::{ cap::Capability, define_entry, elf, - init::BOOT_PCI_VMMO, + init::{BOOT_FRAMEBUFFER_INFO_VMMO, BOOT_PCI_VMMO}, mem::MemoryRegion, zion::{z_cap_t, z_err_t, ZError}, }; @@ -20,9 +20,17 @@ mod server; define_entry!(); +fn spawn_from_mem_region( + mem_region: &mammoth::mem::MemoryRegion, + server_cap: Capability, +) -> Result<(), ZError> { + elf::spawn_process_from_elf_and_init(mem_region.slice(), server_cap)?; + Ok(()) +} + fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZError> { let region = mammoth::mem::MemoryRegion::from_cap(Capability::take(vmmo_cap))?; - elf::spawn_process_from_elf_and_init(region.slice(), server_cap)?; + spawn_from_mem_region(®ion, server_cap)?; Ok(()) } @@ -30,8 +38,10 @@ fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZErr extern "C" fn main() -> z_err_t { let pci_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_PCI_VMMO })) .expect("Failed to create PCI region"); + let fb_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_FRAMEBUFFER_INFO_VMMO })) + .expect("Failed to create Framebuffer region"); let context = alloc::rc::Rc::new( - server::YellowstoneServerContext::new(pci_region) + server::YellowstoneServerContext::new(pci_region, fb_region) .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); @@ -47,7 +57,7 @@ extern "C" fn main() -> z_err_t { ) .expect("Failed to spawn denali"); - context.wait_denali().expect("Failed to wait for denali"); + context.wait("denali").expect("Failed to wait for denali"); mammoth::debug!("Denali registered."); spawn_from_vmmo( @@ -56,7 +66,7 @@ extern "C" fn main() -> z_err_t { ) .expect("Failed to spawn victoriafalls"); - context.wait_victoria_falls().unwrap(); + context.wait("victoriafalls").unwrap(); mammoth::debug!("VFS Registered"); let file = victoriafalls::file::File::open("/init.txt").unwrap(); @@ -70,7 +80,14 @@ extern "C" fn main() -> z_err_t { mammoth::debug!("Init files: {:?}", init_files); for bin_name in init_files { - let path = "/bin/" + bin_name; + // FIXME implement dependencies. + if bin_name == "teton" { + context.wait("voyageurs").unwrap(); + } + let path = "/bin/".to_string() + bin_name; + + let bin_file = victoriafalls::file::File::open(&path).unwrap(); + spawn_from_mem_region(bin_file.memory(), server.create_client_cap().unwrap()).unwrap(); } server_thread.join().expect("Failed to join thread"); diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs index b7b4116..e421f74 100644 --- a/rust/sys/yellowstone/src/pci.rs +++ b/rust/sys/yellowstone/src/pci.rs @@ -18,6 +18,15 @@ impl PciReader { } } + pub fn get_xhci_region(&self) -> Result { + match self.probe_pci(|class, subclass, prog_interface| { + class == 0xC && subclass == 0x3 && prog_interface == 0x30 + }) { + Some(m) => Ok(m), + None => Err(ZError::NOT_FOUND), + } + } + fn probe_pci(&self, pred: DevPredicate) -> Option { let base_header = self.pci_header(0, 0, 0); if (base_header.header_type & 0x80) == 0 { diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index ef33146..5a8ce9c 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,3 +1,5 @@ +use core::cell::RefCell; + use alloc::rc::Rc; use alloc::{collections::BTreeMap, string::String}; use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; @@ -10,65 +12,90 @@ use yellowstone_yunq::{ use crate::pci::PciReader; pub struct YellowstoneServerContext { - denali_semaphore: mammoth::sync::Semaphore, - victoria_falls_semaphore: mammoth::sync::Semaphore, + registration_semaphore: mammoth::sync::Semaphore, pci_reader: PciReader, + framebuffer_info_region: MemoryRegion, + service_map: RefCell>, } impl YellowstoneServerContext { - pub fn new(pci_region: MemoryRegion) -> Result { + fn framebuffer_info(&self) -> yellowstone_yunq::FramebufferInfo { + let fb_info: &mammoth::zion::ZFramebufferInfo = unsafe { + self.framebuffer_info_region + .slice::() + .as_ptr() + .cast::() + .as_ref() + .unwrap() + }; + + yellowstone_yunq::FramebufferInfo { + address_phys: fb_info.address_phys, + width: fb_info.width, + height: fb_info.height, + pitch: fb_info.pitch, + bpp: fb_info.bpp as u64, + memory_model: fb_info.memory_model as u64, + red_mask_size: fb_info.red_mask_size as u64, + red_mask_shift: fb_info.red_mask_shift as u64, + blue_mask_size: fb_info.blue_mask_size as u64, + blue_mask_shift: fb_info.blue_mask_shift as u64, + green_mask_size: fb_info.green_mask_size as u64, + green_mask_shift: fb_info.green_mask_shift as u64, + } + } +} + +impl YellowstoneServerContext { + pub fn new(pci_region: MemoryRegion, fb_region: MemoryRegion) -> Result { Ok(Self { - denali_semaphore: mammoth::sync::Semaphore::new()?, - victoria_falls_semaphore: mammoth::sync::Semaphore::new()?, + registration_semaphore: mammoth::sync::Semaphore::new()?, pci_reader: PciReader::new(pci_region), + framebuffer_info_region: fb_region, + service_map: BTreeMap::new().into(), }) } - pub fn wait_denali(&self) -> Result<(), ZError> { - self.denali_semaphore.wait() - } - - pub fn wait_victoria_falls(&self) -> Result<(), ZError> { - self.victoria_falls_semaphore.wait() + pub fn wait(&self, service: &str) -> Result<(), ZError> { + loop { + match self.service_map.borrow().get(service) { + Some(_) => return Ok(()), + None => {} + } + self.registration_semaphore.wait().unwrap(); + } } } pub struct YellowstoneServerImpl { context: Rc, - service_map: BTreeMap, } impl YellowstoneServerImpl { pub fn new(context: Rc) -> Self { - Self { - context, - service_map: BTreeMap::new(), - } + Self { context } } } impl YellowstoneServerHandler for YellowstoneServerImpl { fn register_endpoint(&mut self, req: RegisterEndpointRequest) -> Result<(), ZError> { - let signal_denali = req.endpoint_name == "denali"; - let signal_vfs = req.endpoint_name == "victoriafalls"; + if req.endpoint_name == "victoriafalls" { + victoriafalls::set_client(VFSClient::new( + Capability::take_copy(req.endpoint_capability).unwrap(), + )); + } - let raw_cap = req.endpoint_capability; - - self.service_map + self.context + .service_map + .borrow_mut() .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); - if signal_denali { - self.context.denali_semaphore.signal()?; - } - if signal_vfs { - self.context.victoria_falls_semaphore.signal()?; - victoriafalls::set_client(VFSClient::new(Capability::take_copy(raw_cap).unwrap())); - } + self.context.registration_semaphore.signal()?; Ok(()) } fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { - match self.service_map.get(&req.endpoint_name) { + match self.context.service_map.borrow().get(&req.endpoint_name) { Some(cap) => Ok(Endpoint { endpoint: cap.duplicate(Capability::PERMS_ALL)?.release(), }), @@ -84,15 +111,18 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { } fn get_xhci_info(&mut self) -> Result { - todo!() + Ok(XhciInfo { + xhci_region: self.context.pci_reader.get_xhci_region()?.release(), + region_length: 0x1000, + }) } fn get_framebuffer_info(&mut self) -> Result { - todo!() + Ok(self.context.framebuffer_info()) } fn get_denali(&mut self) -> Result { - match self.service_map.get("denali") { + match self.context.service_map.borrow().get("denali") { Some(ep_cap) => crate::gpt::read_gpt(denali::DenaliClient::new( ep_cap.duplicate(Capability::PERMS_ALL).unwrap(), )) From c1db6cb11f62379ee9a61424ea4d4be85528f3ae Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 Aug 2024 12:45:53 -0700 Subject: [PATCH 125/186] [Yellowstone][Mammoth] Delete unused cpp code. --- lib/mammoth/CMakeLists.txt | 7 - lib/mammoth/file/file.cpp | 81 --------- lib/mammoth/file/file.h | 38 ----- lib/mammoth/input/keyboard.cpp | 228 ------------------------- lib/mammoth/input/keyboard.h | 113 ------------ lib/mammoth/ipc/channel.cpp | 60 ------- lib/mammoth/ipc/channel.h | 51 ------ lib/mammoth/ipc/endpoint_client.cpp | 9 - lib/mammoth/ipc/endpoint_client.h | 69 -------- lib/mammoth/ipc/endpoint_server.cpp | 45 ----- lib/mammoth/ipc/endpoint_server.h | 39 ----- lib/mammoth/ipc/request_context.h | 32 ---- lib/mammoth/proc/process.cpp | 159 ----------------- lib/mammoth/proc/process.h | 12 -- lib/mammoth/sync/mutex.cpp | 31 ---- lib/mammoth/sync/mutex.h | 25 --- sys/yellowstone/CMakeLists.txt | 23 --- sys/yellowstone/hw/gpt.cpp | 134 --------------- sys/yellowstone/hw/gpt.h | 20 --- sys/yellowstone/hw/pcie.cpp | 110 ------------ sys/yellowstone/hw/pcie.h | 43 ----- sys/yellowstone/yellowstone.cpp | 70 -------- sys/yellowstone/yellowstone_server.cpp | 145 ---------------- sys/yellowstone/yellowstone_server.h | 46 ----- 24 files changed, 1590 deletions(-) delete mode 100644 lib/mammoth/file/file.cpp delete mode 100644 lib/mammoth/file/file.h delete mode 100644 lib/mammoth/input/keyboard.cpp delete mode 100644 lib/mammoth/input/keyboard.h delete mode 100644 lib/mammoth/ipc/channel.cpp delete mode 100644 lib/mammoth/ipc/channel.h delete mode 100644 lib/mammoth/ipc/endpoint_client.cpp delete mode 100644 lib/mammoth/ipc/endpoint_client.h delete mode 100644 lib/mammoth/ipc/endpoint_server.cpp delete mode 100644 lib/mammoth/ipc/endpoint_server.h delete mode 100644 lib/mammoth/ipc/request_context.h delete mode 100644 lib/mammoth/proc/process.cpp delete mode 100644 lib/mammoth/proc/process.h delete mode 100644 lib/mammoth/sync/mutex.cpp delete mode 100644 lib/mammoth/sync/mutex.h delete mode 100644 sys/yellowstone/hw/gpt.cpp delete mode 100644 sys/yellowstone/hw/gpt.h delete mode 100644 sys/yellowstone/hw/pcie.cpp delete mode 100644 sys/yellowstone/hw/pcie.h delete mode 100644 sys/yellowstone/yellowstone.cpp delete mode 100644 sys/yellowstone/yellowstone_server.cpp delete mode 100644 sys/yellowstone/yellowstone_server.h diff --git a/lib/mammoth/CMakeLists.txt b/lib/mammoth/CMakeLists.txt index ea431ab..fa2bf6b 100644 --- a/lib/mammoth/CMakeLists.txt +++ b/lib/mammoth/CMakeLists.txt @@ -1,14 +1,7 @@ add_library(mammoth STATIC - file/file.cpp - input/keyboard.cpp - ipc/channel.cpp - ipc/endpoint_client.cpp - ipc/endpoint_server.cpp ipc/port_client.cpp ipc/port_server.cpp - proc/process.cpp proc/thread.cpp - sync/mutex.cpp sync/semaphore.cpp util/debug.cpp util/init.cpp diff --git a/lib/mammoth/file/file.cpp b/lib/mammoth/file/file.cpp deleted file mode 100644 index b1c4e74..0000000 --- a/lib/mammoth/file/file.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "file/file.h" - -#include -#include -#include -#include -#include - -#include "util/debug.h" - -namespace mmth { -namespace { - -using yellowstone::Endpoint; -using yellowstone::GetEndpointRequest; -using yellowstone::YellowstoneClient; - -VFSClient* gVfsClient = nullptr; - -void GetVfsClientIfNeeded() { - if (gVfsClient == nullptr) { - // TODO: Add an unowned client so we don't have to duplicate this cap every - // time. - uint64_t dup_cap; - check(ZCapDuplicate(gInitEndpointCap, kZionPerm_All, &dup_cap)); - YellowstoneClient client(dup_cap); - - GetEndpointRequest yreq; - yreq.set_endpoint_name("victoriafalls"); - Endpoint yresp; - check(client.GetEndpoint(yreq, yresp)); - - gVfsClient = new VFSClient(yresp.endpoint()); - } -} - -} // namespace - -void SetVfsCap(z_cap_t vfs_cap) { gVfsClient = new VFSClient(vfs_cap); } - -File File::Open(glcr::StringView path) { - GetVfsClientIfNeeded(); - - OpenFileRequest req; - req.set_path(path); - OpenFileResponse resp; - check(gVfsClient->OpenFile(req, resp)); - - return File(OwnedMemoryRegion::FromCapability(resp.memory()), resp.size()); -} - -glcr::StringView File::as_str() { - return glcr::StringView((char*)raw_ptr(), size_); -} - -void* File::raw_ptr() { return reinterpret_cast(file_data_.vaddr()); } -uint8_t* File::byte_ptr() { - return reinterpret_cast(file_data_.vaddr()); -} - -glcr::ErrorOr> ListDirectory(glcr::StringView path) { - GetVfsClientIfNeeded(); - - GetDirectoryRequest req; - req.set_path(path); - Directory dir; - auto status = gVfsClient->GetDirectory(req, dir); - if (!status.ok()) { - dbgln("Error in getting directory: {}", status.message()); - return status.code(); - } - - auto file_views = glcr::StrSplit(dir.filenames(), ','); - glcr::Vector files; - for (const auto& view : glcr::StrSplit(dir.filenames(), ',')) { - files.PushBack(view); - } - return files; -} - -} // namespace mmth diff --git a/lib/mammoth/file/file.h b/lib/mammoth/file/file.h deleted file mode 100644 index 7b55f2e..0000000 --- a/lib/mammoth/file/file.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "mammoth/util/memory_region.h" - -namespace mmth { - -// Intended for use in yellowstone since it already has the VFS cap. -void SetVfsCap(z_cap_t vfs_cap); - -class File { - public: - static File Open(glcr::StringView path); - - uint64_t size() { return size_; } - - glcr::StringView as_str(); - - void* raw_ptr(); - uint8_t* byte_ptr(); - - private: - OwnedMemoryRegion file_data_; - uint64_t size_; - - File(OwnedMemoryRegion&& file, uint64_t size) - : file_data_(glcr::Move(file)), size_(size) {} -}; - -// TODO: Move this to a separate file. -glcr::ErrorOr> ListDirectory(glcr::StringView path); - -} // namespace mmth diff --git a/lib/mammoth/input/keyboard.cpp b/lib/mammoth/input/keyboard.cpp deleted file mode 100644 index f0ab639..0000000 --- a/lib/mammoth/input/keyboard.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include "input/keyboard.h" - -#include -#include -#include - -#include "util/debug.h" - -namespace mmth { -namespace { - -using yellowstone::Endpoint; -using yellowstone::GetEndpointRequest; -using yellowstone::YellowstoneClient; - -void KeyboardListenerEntry(void* keyboard_base) { - reinterpret_cast(keyboard_base)->ListenLoop(); -} - -} // namespace - -KeyboardListenerBase::KeyboardListenerBase() { - auto server_or = PortServer::Create(); - if (!server_or) { - crash("Failed to create server", server_or.error()); - } - server_ = server_or.value(); -} - -void KeyboardListenerBase::Register() { - uint64_t dup_cap; - check(ZCapDuplicate(gInitEndpointCap, kZionPerm_All, &dup_cap)); - YellowstoneClient client(dup_cap); - - GetEndpointRequest req; - req.set_endpoint_name("voyageurs"); - Endpoint endpt; - check(client.GetEndpoint(req, endpt)); - - VoyageursClient vclient(endpt.endpoint()); - KeyboardListener listn; - - // TODO: Create a "ASSIGN_OR_CRASH" macro to simplify this. - auto client_or = server_.CreateClient(); - if (!client_or.ok()) { - crash("Failed to create client", client_or.error()); - } - listn.set_port_capability(client_or.value().cap()); - check(vclient.RegisterKeyboardListener(listn)); -} - -Thread KeyboardListenerBase::Listen() { - return Thread(KeyboardListenerEntry, this); -} - -void KeyboardListenerBase::ListenLoop() { - while (true) { - auto scancode_or = server_.RecvUint16(); - if (!scancode_or.ok()) { - check(scancode_or.error()); - } - uint16_t scancode = scancode_or.value(); - - Keycode k = ScancodeToKeycode(scancode & 0xFF); - uint8_t modifiers = (scancode >> 8) & 0xFF; - HandleKeycode(k, modifiers); - } -} - -void KeyboardListenerBase::HandleKeycode(Keycode code, uint8_t modifiers) { - char c = '\0'; - - if (code >= kA && code <= kZ) { - if (IsShift(modifiers)) { - const char* alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - c = alpha[code - kA]; - - } else { - const char* alpha = "abcdefghijklmnopqrstuvwxyz"; - c = alpha[code - kA]; - } - } else if (code >= k1 && code <= k0) { - if (IsShift(modifiers)) { - const char* num = "!@#$%^&*()"; - c = num[code - k1]; - } else { - const char* num = "1234567890"; - c = num[code - k1]; - } - } else if (code >= kMinus && code <= kBacktick) { - if (IsShift(modifiers)) { - const char* sym = "_+{}|?:\"<>~"; - c = sym[code - kMinus]; - } else { - const char* sym = "-=[]\\/;',.`"; - c = sym[code - kMinus]; - } - } else if (code == kEnter) { - c = '\n'; - } else if (code == kSpace) { - c = ' '; - } else if (code == kTab) { - c = '\t'; - } else if (code == kBackspace) { - c = '\b'; - } - - if (c != '\0') { - HandleCharacter(c); - } -} - -Keycode KeyboardListenerBase::ScancodeToKeycode(uint16_t scancode) { - switch (scancode) { - case 0x04: - return kA; - case 0x05: - return kB; - case 0x06: - return kC; - case 0x07: - return kD; - case 0x08: - return kE; - case 0x09: - return kF; - case 0x0A: - return kG; - case 0x0B: - return kH; - case 0x0C: - return kI; - case 0x0D: - return kJ; - case 0x0E: - return kK; - case 0x0F: - return kL; - case 0x10: - return kM; - case 0x11: - return kN; - case 0x12: - return kO; - case 0x13: - return kP; - case 0x14: - return kQ; - case 0x15: - return kR; - case 0x16: - return kS; - case 0x17: - return kT; - case 0x18: - return kU; - case 0x19: - return kV; - case 0x1A: - return kW; - case 0x1B: - return kX; - case 0x1C: - return kY; - case 0x1D: - return kZ; - case 0x1E: - return k1; - case 0x1F: - return k2; - case 0x20: - return k3; - case 0x21: - return k4; - case 0x22: - return k5; - case 0x23: - return k6; - case 0x24: - return k7; - case 0x25: - return k8; - case 0x26: - return k9; - case 0x27: - return k0; - case 0x28: - return kEnter; - case 0x29: - return kEsc; - case 0x2A: - return kBackspace; - case 0x2B: - return kTab; - case 0x2C: - return kSpace; - case 0x2D: - return kMinus; - case 0x2E: - return kEquals; - case 0x2F: - return kLBrace; - case 0x30: - return kRBrace; - case 0x31: - return kBSlash; - case 0x33: - return kSemicolon; - case 0x34: - return kQuote; - case 0x35: - return kBacktick; - case 0x36: - return kComma; - case 0x37: - return kPeriod; - case 0x38: - return kFSlash; - case 0x39: - return kEsc; // Capslock - } - - dbgln("Unknown scancode {x}", scancode); - - return kUnknownKeycode; -} - -} // namespace mmth diff --git a/lib/mammoth/input/keyboard.h b/lib/mammoth/input/keyboard.h deleted file mode 100644 index 5dfa50b..0000000 --- a/lib/mammoth/input/keyboard.h +++ /dev/null @@ -1,113 +0,0 @@ -#pragma once - -#include "mammoth/ipc/port_server.h" -#include "mammoth/proc/thread.h" - -namespace mmth { - -enum Keycode { - kUnknownKeycode = 0x0, - - kA = 0x1, - kB = 0x2, - kC = 0x3, - kD = 0x4, - kE = 0x5, - kF = 0x6, - kG = 0x7, - kH = 0x8, - kI = 0x9, - kJ = 0xA, - kK = 0xB, - kL = 0xC, - kM = 0xD, - kN = 0xE, - kO = 0xF, - kP = 0x10, - kQ = 0x11, - kR = 0x12, - kS = 0x13, - kT = 0x14, - kU = 0x15, - kV = 0x16, - kW = 0x17, - kX = 0x18, - kY = 0x19, - kZ = 0x1A, - - k1 = 0x20, - k2 = 0x21, - k3 = 0x22, - k4 = 0x23, - k5 = 0x24, - k6 = 0x25, - k7 = 0x26, - k8 = 0x27, - k9 = 0x28, - k0 = 0x29, - - kSpace = 0x30, - kEnter = 0x31, - kTab = 0x32, - kBackspace = 0x33, - kDelete = 0x34, - - kMinus = 0x40, - kEquals = 0x41, - kLBrace = 0x42, - kRBrace = 0x43, - kBSlash = 0x44, - kFSlash = 0x45, - kSemicolon = 0x46, - kQuote = 0x47, - kComma = 0x48, - kPeriod = 0x49, - kBacktick = 0x4A, - - kLShift = 0x50, - kRShift = 0x51, - kLCtrl = 0x52, - kRCtrl = 0x53, - kLAlt = 0x54, - kRAlt = 0x55, - kSuper = 0x56, - kEsc = 0x57, - kUp = 0x58, - kDown = 0x59, - kLeft = 0x5A, - kRight = 0x5B, -}; - -class KeyboardListenerBase { - public: - KeyboardListenerBase(); - KeyboardListenerBase(const KeyboardListenerBase&) = delete; - KeyboardListenerBase(KeyboardListenerBase&&) = delete; - - void Register(); - - Thread Listen(); - - void ListenLoop(); - - // Override this to recieve all raw keycodes. By default - // this function will try to translate each keycode into - // a printable character and call HandleCharacter. - virtual void HandleKeycode(Keycode code, uint8_t modifiers); - - // This function is called by the default HandleKeycode - // implementation if you do not override it. If it recieves - // input that corresponds to a printable character it will - virtual void HandleCharacter(char c){}; - - private: - PortServer server_; - - Keycode ScancodeToKeycode(uint16_t scancode); - - bool IsShift(uint8_t modifiers) { - return (modifiers & 0x2) || (modifiers & 0x20); - } -}; - -} // namespace mmth diff --git a/lib/mammoth/ipc/channel.cpp b/lib/mammoth/ipc/channel.cpp deleted file mode 100644 index a014bfd..0000000 --- a/lib/mammoth/ipc/channel.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "ipc/channel.h" - -#include - -#include "util/debug.h" - -namespace mmth { -namespace { - -uint64_t strlen(const char* ptr) { - uint64_t len = 0; - while (*ptr != '\0') { - len++; - ptr++; - } - return len; -} - -} // namespace - -void Channel::adopt_cap(uint64_t id) { - if (chan_cap_ != 0) { - crash("Adopting over channel.", glcr::ALREADY_EXISTS); - } - chan_cap_ = id; -} -z_cap_t Channel::release_cap() { - z_cap_t cap = chan_cap_; - chan_cap_ = 0; - return cap; -} - -z_cap_t Channel::cap() { return chan_cap_; } - -z_err_t Channel::WriteStr(const char* msg) { - if (!chan_cap_) { - return glcr::NULL_PTR; - } - return ZChannelSend(chan_cap_, strlen(msg), msg, 0, nullptr); -} - -z_err_t Channel::ReadStr(char* buffer, uint64_t* size) { - if (!chan_cap_) { - return glcr::NULL_PTR; - } - uint64_t num_caps = 0; - return ZChannelRecv(chan_cap_, size, reinterpret_cast(buffer), - &num_caps, nullptr); -} - -z_err_t CreateChannels(Channel& c1, Channel& c2) { - z_cap_t chan1, chan2; - RET_ERR(ZChannelCreate(&chan1, &chan2)); - - c1.adopt_cap(chan1); - c2.adopt_cap(chan2); - return glcr::OK; -} - -} // namespace mmth diff --git a/lib/mammoth/ipc/channel.h b/lib/mammoth/ipc/channel.h deleted file mode 100644 index f290d92..0000000 --- a/lib/mammoth/ipc/channel.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace mmth { - -class Channel { - public: - Channel() {} - void adopt_cap(uint64_t id); - z_cap_t release_cap(); - z_cap_t cap(); - - z_err_t WriteStr(const char* msg); - z_err_t ReadStr(char* buffer, uint64_t* size); - - template - z_err_t WriteStruct(T*); - - template - z_err_t ReadStructAndCap(T*, uint64_t*); - - // FIXME: Close channel here. - ~Channel() {} - - private: - z_cap_t chan_cap_ = 0; -}; - -uint64_t CreateChannels(Channel& c1, Channel& c2); - -template -z_err_t Channel::WriteStruct(T* obj) { - return ZChannelSend(chan_cap_, sizeof(T), obj, 0, nullptr); -} - -template -z_err_t Channel::ReadStructAndCap(T* obj, uint64_t* cap) { - uint64_t num_bytes = sizeof(T); - uint64_t num_caps = 1; - RET_ERR(ZChannelRecv(chan_cap_, &num_bytes, obj, &num_caps, cap)); - - if (num_caps != 1 || num_bytes != sizeof(T)) { - return glcr::FAILED_PRECONDITION; - } - return glcr::OK; -} - -} // namespace mmth diff --git a/lib/mammoth/ipc/endpoint_client.cpp b/lib/mammoth/ipc/endpoint_client.cpp deleted file mode 100644 index 33c50cf..0000000 --- a/lib/mammoth/ipc/endpoint_client.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "ipc/endpoint_server.h" - -namespace mmth { - -glcr::UniquePtr EndpointClient::AdoptEndpoint(z_cap_t cap) { - return glcr::UniquePtr(new EndpointClient(cap)); -} - -} // namespace mmth diff --git a/lib/mammoth/ipc/endpoint_client.h b/lib/mammoth/ipc/endpoint_client.h deleted file mode 100644 index 41227b1..0000000 --- a/lib/mammoth/ipc/endpoint_client.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace mmth { - -class EndpointClient { - public: - EndpointClient() = delete; - EndpointClient(const EndpointClient&) = delete; - EndpointClient& operator=(const EndpointClient&) = delete; - - static glcr::UniquePtr AdoptEndpoint(z_cap_t cap); - - template - glcr::ErrorOr> CallEndpointGetCap(const Req& req); - - template - glcr::ErrorOr CallEndpoint(const Req& req); - - z_cap_t GetCap() const { return cap_; } - - private: - EndpointClient(uint64_t cap) : cap_(cap) {} - z_cap_t cap_; -}; - -template -glcr::ErrorOr> EndpointClient::CallEndpointGetCap( - const Req& req) { - uint64_t reply_port_cap; - RET_ERR(ZEndpointSend(cap_, sizeof(Req), &req, 0, nullptr, &reply_port_cap)); - - Resp resp; - z_cap_t cap = 0; - uint64_t num_caps = 1; - uint64_t num_bytes = sizeof(Resp); - RET_ERR(ZReplyPortRecv(reply_port_cap, &num_bytes, &resp, &num_caps, &cap)); - - if (num_bytes != sizeof(resp) || num_caps != 1) { - return glcr::FAILED_PRECONDITION; - } - - return glcr::Pair{resp, cap}; -} - -template -glcr::ErrorOr EndpointClient::CallEndpoint(const Req& req) { - uint64_t reply_port_cap; - RET_ERR(ZEndpointSend(cap_, sizeof(Req), &req, 0, nullptr, &reply_port_cap)); - - Resp resp; - uint64_t num_bytes = sizeof(Resp); - uint64_t num_caps = 0; - RET_ERR( - ZReplyPortRecv(reply_port_cap, &num_bytes, &resp, &num_caps, nullptr)); - - if (num_bytes != sizeof(resp)) { - return glcr::FAILED_PRECONDITION; - } - - return resp; -} - -} // namespace mmth diff --git a/lib/mammoth/ipc/endpoint_server.cpp b/lib/mammoth/ipc/endpoint_server.cpp deleted file mode 100644 index 823c5f0..0000000 --- a/lib/mammoth/ipc/endpoint_server.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "ipc/endpoint_server.h" - -#include "util/debug.h" - -namespace mmth { -// Declared as friend in EndpointServer. -void EndpointServerThreadBootstrap(void* endpoint_server) { - reinterpret_cast(endpoint_server)->ServerThread(); -} - -glcr::ErrorOr> EndpointServer::CreateClient() { - uint64_t client_cap; - RET_ERR(ZCapDuplicate(endpoint_cap_, ~(kZionPerm_Read), &client_cap)); - return EndpointClient::AdoptEndpoint(client_cap); -} - -Thread EndpointServer::RunServer() { - return Thread(EndpointServerThreadBootstrap, this); -} - -void EndpointServer::ServerThread() { - while (true) { - uint64_t message_size = kBufferSize; - uint64_t reply_port_cap = 0; - uint64_t num_caps = 0; - glcr::ErrorCode err = static_cast( - ZEndpointRecv(endpoint_cap_, &message_size, recieve_buffer_, &num_caps, - nullptr, &reply_port_cap)); - if (err != glcr::OK) { - dbgln("Error in receive: {x}", err); - continue; - } - - RequestContext request(recieve_buffer_, message_size); - ResponseContext response(reply_port_cap); - // FIXME: Consider pumping these errors into the response as well. - check(HandleRequest(request, response)); - if (!response.HasWritten()) { - dbgln("Returning without having written a response. Req type {x}", - request.request_id()); - } - } -} - -} // namespace mmth diff --git a/lib/mammoth/ipc/endpoint_server.h b/lib/mammoth/ipc/endpoint_server.h deleted file mode 100644 index 7ce438d..0000000 --- a/lib/mammoth/ipc/endpoint_server.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "mammoth/ipc/endpoint_client.h" -#include "mammoth/ipc/request_context.h" -#include "mammoth/ipc/response_context.h" -#include "mammoth/proc/thread.h" - -namespace mmth { -class EndpointServer { - public: - EndpointServer() = delete; - EndpointServer(const EndpointServer&) = delete; - EndpointServer& operator=(const EndpointServer&) = delete; - - glcr::ErrorOr> CreateClient(); - - Thread RunServer(); - - virtual glcr::ErrorCode HandleRequest(RequestContext& request, - ResponseContext& response) = 0; - - protected: - EndpointServer(z_cap_t cap) : endpoint_cap_(cap) {} - - private: - z_cap_t endpoint_cap_; - - static const uint64_t kBufferSize = 1024; - uint8_t recieve_buffer_[kBufferSize]; - - friend void EndpointServerThreadBootstrap(void* endpoint_server); - void ServerThread(); -}; - -} // namespace mmth diff --git a/lib/mammoth/ipc/request_context.h b/lib/mammoth/ipc/request_context.h deleted file mode 100644 index 0f8ca96..0000000 --- a/lib/mammoth/ipc/request_context.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include - -class RequestContext { - public: - RequestContext(void* buffer, uint64_t buffer_length) - : buffer_(buffer), buffer_length_(buffer_length) { - if (buffer_length_ < sizeof(uint64_t)) { - request_id_ = -1; - } else { - request_id_ = *reinterpret_cast(buffer); - } - } - - uint64_t request_id() { return request_id_; } - - template - glcr::ErrorCode As(T** arg) { - if (buffer_length_ < sizeof(T)) { - return glcr::INVALID_ARGUMENT; - } - *arg = reinterpret_cast(buffer_); - return glcr::OK; - } - - private: - uint64_t request_id_; - void* buffer_; - uint64_t buffer_length_; -}; diff --git a/lib/mammoth/proc/process.cpp b/lib/mammoth/proc/process.cpp deleted file mode 100644 index ec25ec0..0000000 --- a/lib/mammoth/proc/process.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "proc/process.h" - -#include -#include - -#include "ipc/endpoint_server.h" -#include "ipc/port_client.h" -#include "ipc/port_server.h" -#include "util/debug.h" -#include "util/init.h" - -#define MAM_PROC_DEBUG 0 - -namespace mmth { -namespace { - -typedef struct { - char ident[16]; - uint16_t type; - uint16_t machine; - uint32_t version; - uint64_t entry; - uint64_t phoff; - uint64_t shoff; - uint32_t flags; - uint16_t ehsize; - uint16_t phentsize; - uint16_t phnum; - uint16_t shentsize; - uint16_t shnum; - uint16_t shstrndx; -} Elf64Header; - -typedef struct { - uint32_t name; - uint32_t type; - uint64_t flags; - uint64_t addr; - uint64_t offset; - uint64_t size; - uint32_t link; - uint32_t info; - uint64_t addralign; - uint64_t entsize; -} Elf64SectionHeader; - -typedef struct { - uint32_t type; - uint32_t flags; - uint64_t offset; - uint64_t vaddr; - uint64_t paddr; - uint64_t filesz; - uint64_t memsz; - uint64_t align; -} Elf64ProgramHeader; - -void memcpy(uint64_t base, uint64_t len, uint64_t dest) { - uint8_t* srcptr = reinterpret_cast(base); - uint8_t* destptr = reinterpret_cast(dest); - for (uint64_t i = 0; i < len; i++) { - destptr[i] = srcptr[i]; - } -} - -uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) { - Elf64Header* header = reinterpret_cast(base); - Elf64ProgramHeader* programs = - reinterpret_cast(base + header->phoff); - for (uint64_t i = 0; i < header->phnum; i++) { - Elf64ProgramHeader& program = programs[i]; - if (program.type != 1) { - // Only load loadable types. - // TODO: This may break if the stack is far away? - continue; - } -#if MAM_PROC_DEBUG - dbgln(glcr::StrFormat("Program:\n\tType: {}\n\tFlags: {}\n\t", program.type, - program.flags)); - dbgln("Create mem object"); -#endif - uint64_t page_offset = program.vaddr & 0xFFF; - uint64_t mem_cap; - uint64_t size = page_offset + program.memsz; - check(ZMemoryObjectCreate(size, &mem_cap)); - -#if MAM_PROC_DEBUG - dbgln("Map Local"); -#endif - uint64_t vaddr; - check(ZAddressSpaceMap(gSelfVmasCap, 0, mem_cap, 0, &vaddr)); - uint8_t* offset = reinterpret_cast(vaddr); - for (uint64_t j = 0; j < size; j++) { - offset[j] = 0; - } - -#if MAM_PROC_DEBUG - dbgln("Copy"); -#endif - memcpy(base + program.offset, program.filesz, vaddr + page_offset); - -#if MAM_PROC_DEBUG - dbgln(glcr::StrFormat("Map Foreign: {x} {x} {x}", - program.vaddr - page_offset, size, vaddr)); -#endif - check(ZAddressSpaceMap(as_cap, program.vaddr - page_offset, mem_cap, 0, - &vaddr)); - } - return header->entry; -} - -} // namespace - -glcr::ErrorOr SpawnProcessFromElfRegion(uint64_t program, - z_cap_t yellowstone_client) { - uint64_t proc_cap; - uint64_t as_cap; - uint64_t foreign_port_id; - uint64_t port_cap; - -#if MAM_PROC_DEBUG - dbgln("Port Create"); -#endif - ASSIGN_OR_RETURN(PortServer server, PortServer::Create()); - ASSIGN_OR_RETURN(PortClient pclient, server.CreateClient()); - -#if MAM_PROC_DEBUG - dbgln("Spawn"); -#endif - RET_ERR(ZProcessSpawn(gSelfProcCap, server.cap(), &proc_cap, &as_cap, - &foreign_port_id)); - - uint64_t entry_point = LoadElfProgram(program, as_cap); - - if (entry_point == 0) { - crash("Entry Point == 0", glcr::INTERNAL); - } - -#if MAM_PROC_DEBUG - dbgln("Thread Create"); -#endif - uint64_t thread_cap; - RET_ERR(ZThreadCreate(proc_cap, &thread_cap)); - - uint64_t dup_proc_cap; - RET_ERR(ZCapDuplicate(proc_cap, kZionPerm_All, &dup_proc_cap)); - RET_ERR(pclient.WriteMessage(Z_INIT_SELF_PROC, dup_proc_cap)); - RET_ERR(pclient.WriteMessage(Z_INIT_SELF_VMAS, as_cap)); - RET_ERR(pclient.WriteMessage(Z_INIT_ENDPOINT, yellowstone_client)); - -#if MAM_PROC_DEBUG - dbgln("Thread start"); -#endif - RET_ERR(ZThreadStart(thread_cap, entry_point, foreign_port_id, 0)); - - return proc_cap; -} - -} // namespace mmth diff --git a/lib/mammoth/proc/process.h b/lib/mammoth/proc/process.h deleted file mode 100644 index c5a0ef4..0000000 --- a/lib/mammoth/proc/process.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace mmth { - -glcr::ErrorOr SpawnProcessFromElfRegion(uint64_t program, - z_cap_t yellowstone_client); - -} // namespace mmth diff --git a/lib/mammoth/sync/mutex.cpp b/lib/mammoth/sync/mutex.cpp deleted file mode 100644 index 9b134ed..0000000 --- a/lib/mammoth/sync/mutex.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "sync/mutex.h" - -#include - -namespace mmth { - -Mutex::Mutex(Mutex&& other) : mutex_cap_(other.mutex_cap_) { - other.mutex_cap_ = 0; -} - -Mutex& Mutex::operator=(Mutex&& other) { - // TODO: Release existing mutex if it exists. - mutex_cap_ = other.mutex_cap_; - other.mutex_cap_ = 0; - return *this; -} - -glcr::ErrorOr Mutex::Create() { - z_cap_t mutex_cap; - RET_ERR(ZMutexCreate(&mutex_cap)); - return Mutex(mutex_cap); -} - -glcr::ErrorCode Mutex::Lock() { - return static_cast(ZMutexLock(mutex_cap_)); -} -glcr::ErrorCode Mutex::Release() { - return static_cast(ZMutexRelease(mutex_cap_)); -} - -} // namespace mmth diff --git a/lib/mammoth/sync/mutex.h b/lib/mammoth/sync/mutex.h deleted file mode 100644 index ee77394..0000000 --- a/lib/mammoth/sync/mutex.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include -#include - -namespace mmth { - -class Mutex { - public: - Mutex(const Mutex&) = delete; - Mutex(Mutex&&); - Mutex& operator=(Mutex&&); - - static glcr::ErrorOr Create(); - - glcr::ErrorCode Lock(); - glcr::ErrorCode Release(); - - private: - z_cap_t mutex_cap_; - - Mutex(z_cap_t mutex_cap) : mutex_cap_(mutex_cap) {} -}; - -} // namespace mmth diff --git a/sys/yellowstone/CMakeLists.txt b/sys/yellowstone/CMakeLists.txt index 22f7444..12936d3 100644 --- a/sys/yellowstone/CMakeLists.txt +++ b/sys/yellowstone/CMakeLists.txt @@ -1,25 +1,2 @@ -add_executable(yellowstone - hw/gpt.cpp - hw/pcie.cpp - yellowstone.cpp - yellowstone_server.cpp - ) - -target_include_directories(yellowstone - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - -target_link_libraries(yellowstone - denali_yunq - mammoth - glacier - victoriafalls_yunq - yellowstone_yunq - ) - -set_target_properties(yellowstone PROPERTIES - COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" - LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" - ) - yunq_gen(lib/yellowstone lib yellowstone) diff --git a/sys/yellowstone/hw/gpt.cpp b/sys/yellowstone/hw/gpt.cpp deleted file mode 100644 index a7b2bb3..0000000 --- a/sys/yellowstone/hw/gpt.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "hw/gpt.h" - -#include -#include -#include -#include -#include - -#define GPT_DEBUG 0 - -const uint64_t kSectorSize = 512; - -const uint64_t kGptPartitionSignature = 0x54524150'20494645; - -const uint64_t kLfsDataLow = 0x477284830fc63daf; -const uint64_t kLfsDataHigh = 0xe47d47d8693d798e; - -struct MbrPartition { - uint8_t boot_indicator; - uint8_t starting_chs[3]; - uint8_t os_type; - uint8_t ending_chs[3]; - uint32_t starting_lba; - uint32_t ending_lba; -} __attribute__((packed)); - -struct ParititionHeader { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc_32; - uint32_t reserved; - uint64_t lba_self; - uint64_t lba_mirror; - uint64_t lba_min; - uint64_t lba_max; - uint64_t guid_low; - uint64_t guid_high; - uint64_t lba_partition_entries; - uint32_t num_partitions; - uint32_t parition_entry_size; - uint32_t partition_entry_crc32; -} __attribute__((packed)); - -struct PartitionEntry { - uint64_t type_guid_low; - uint64_t type_guid_high; - uint64_t part_guid_low; - uint64_t part_guid_high; - uint64_t lba_start; - uint64_t lba_end; - uint64_t attributes; - char partition_name[72]; -} __attribute__((packed)); - -GptReader::GptReader(glcr::UniquePtr denali) - : denali_(glcr::Move(denali)) {} - -glcr::Status GptReader::ParsePartitionTables() { - ReadRequest req; - req.set_device_id(0); - req.mutable_block().set_lba(0); - req.mutable_block().set_size(2); - ReadResponse resp; - RETURN_ERROR(denali_->Read(req, resp)); - mmth::OwnedMemoryRegion lba_1_and_2 = - mmth::OwnedMemoryRegion::FromCapability(resp.memory()); - uint16_t* mbr_sig = reinterpret_cast(lba_1_and_2.vaddr() + 0x1FE); - if (*mbr_sig != 0xAA55) { - return glcr::FailedPrecondition( - glcr::StrFormat("Invalid MBR Sig: {x}", *mbr_sig)); - } - MbrPartition* first_partition = - reinterpret_cast(lba_1_and_2.vaddr() + 0x1BE); - - if (first_partition->boot_indicator != 0) { - // FIXME: This shouldn't be set but I can't figure out why it is. - dbgln("WARN: Boot indicator set: {}", first_partition->boot_indicator); - } - if (first_partition->os_type != 0xEE) { - return glcr::FailedPrecondition( - glcr::StrFormat("Incorrect OS type: {x}", first_partition->os_type)); - } -#if GPT_DEBUG - dbgln("LBAs: ({x}, {x})", first_partition->starting_lba, - first_partition->ending_lba); -#endif - - // FIXME: Don't hardcode sector size. - ParititionHeader* header = - reinterpret_cast(lba_1_and_2.vaddr() + 512); - - uint64_t num_partitions = header->num_partitions; - uint64_t entry_size = header->parition_entry_size; - uint64_t num_blocks = (num_partitions * entry_size) / 512; - -#if GPT_DEBUG - dbgln("signature {}", header->signature); - dbgln("lba_partition_entries {x}", header->lba_partition_entries); - dbgln("num_partitions: {x}", num_partitions); - dbgln("partition_entry_size: {x}", entry_size); - dbgln("Num blocks: {x}", num_blocks); -#endif - - req.set_device_id(0); - req.mutable_block().set_lba(header->lba_partition_entries); - req.mutable_block().set_size(num_blocks); - RETURN_ERROR(denali_->Read(req, resp)); - mmth::OwnedMemoryRegion part_table = - mmth::OwnedMemoryRegion::FromCapability(resp.memory()); - for (uint64_t i = 0; i < num_partitions; i++) { - PartitionEntry* entry = reinterpret_cast( - part_table.vaddr() + (i * entry_size)); - if (entry->type_guid_low != 0 || entry->type_guid_high != 0) { -#if GPT_DEBUG - dbgln("Entry {}", i); - dbgln("T Guid: {x}-{x}", entry->type_guid_high, entry->type_guid_low); - dbgln("P Guid: {x}-{x}", entry->part_guid_high, entry->part_guid_low); - dbgln("LBA: {x}, {x}", entry->lba_start, entry->lba_end); - dbgln("Attrs: {x}", entry->attributes); -#endif - // For now we hardcode these values to the type that is - // created in our setup script. - // FIXME: Set up our own root partition type guid at some - // point. - if (entry->type_guid_low == kLfsDataLow && - entry->type_guid_high == kLfsDataHigh) { - primary_partition_lba_ = entry->lba_start; - } - } - } - - return glcr::Status::Ok(); -} diff --git a/sys/yellowstone/hw/gpt.h b/sys/yellowstone/hw/gpt.h deleted file mode 100644 index 4ce95d3..0000000 --- a/sys/yellowstone/hw/gpt.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -class GptReader { - public: - GptReader(glcr::UniquePtr denali); - - glcr::Status ParsePartitionTables(); - - uint64_t GetPrimaryPartitionLba() { return primary_partition_lba_; } - - private: - glcr::UniquePtr denali_; - uint64_t primary_partition_lba_; -}; diff --git a/sys/yellowstone/hw/pcie.cpp b/sys/yellowstone/hw/pcie.cpp deleted file mode 100644 index ebec187..0000000 --- a/sys/yellowstone/hw/pcie.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "hw/pcie.h" - -#include -#include -#include - -#define PCI_DEBUG 1 - -namespace { - -PciDeviceHeader* PciHeader(uint64_t base, uint64_t bus, uint64_t dev, - uint64_t fun) { - return reinterpret_cast(base + (bus << 20) + (dev << 15) + - (fun << 12)); -} - -} // namespace - -PciReader::PciReader() { - uint64_t vaddr; - check(ZAddressSpaceMap(gSelfVmasCap, 0, gBootPciVmmoCap, 0, &vaddr)); - - PciDump(vaddr); - - header_ = PciHeader(vaddr, 0, 0, 0); -} - -z_cap_t PciReader::GetAhciVmmo() { - uint64_t new_cap; - check(ZMemoryObjectDuplicate(gBootPciVmmoCap, achi_device_offset_, - kPcieConfigurationSize, &new_cap)); - return new_cap; -} - -z_cap_t PciReader::GetXhciVmmo() { - uint64_t new_cap; - check(ZMemoryObjectDuplicate(gBootPciVmmoCap, xhci_device_offset_, - kPcieConfigurationSize, &new_cap)); - return new_cap; -} - -void PciReader::FunctionDump(uint64_t base, uint64_t bus, uint64_t dev, - uint64_t fun) { - PciDeviceHeader* hdr = PciHeader(base, bus, dev, fun); - if (hdr->vendor_id == 0xFFFF) { - return; - } -#if PCI_DEBUG - dbgln( - "[{}.{}.{}] (Vendor, Device): ({x}, {x}), (Type, Class, Sub, PIF): ({}, " - "{x}, {x}, {x})", - bus, dev, fun, hdr->vendor_id, hdr->device_id, hdr->header_type, - hdr->class_code, hdr->subclass, hdr->prog_interface); -#endif - - if ((hdr->class_code == 0x6) && (hdr->subclass == 0x4)) { - dbgln("FIXME: Handle PCI to PCI bridge."); - } - if (hdr->class_code == 0x1) { -#if PCI_DEBUG - dbgln("SATA Device at: {x}", reinterpret_cast(hdr) - base); -#endif - achi_device_offset_ = reinterpret_cast(hdr) - base; - } - - if (hdr->class_code == 0xC && hdr->subclass == 0x3) { - if (hdr->prog_interface == 0x30) { - xhci_device_offset_ = reinterpret_cast(hdr) - base; - } else { - dbgln("WARN: Non-XHCI USB Controller found"); - } - } -} - -void PciReader::DeviceDump(uint64_t base, uint64_t bus, uint64_t dev) { - PciDeviceHeader* hdr = PciHeader(base, bus, dev, 0); - if (hdr->vendor_id == 0xFFFF) { - return; - } - - FunctionDump(base, bus, dev, 0); - - // Device is multifunction. - if (hdr->header_type & 0x80) { - for (uint64_t f = 1; f < 0x8; f++) { - FunctionDump(base, bus, dev, f); - } - } -} - -void PciReader::BusDump(uint64_t base, uint64_t bus) { - for (uint64_t dev = 0; dev < 0x20; dev++) { - DeviceDump(base, bus, dev); - } -} - -void PciReader::PciDump(uint64_t base) { - PciDeviceHeader* hdr = PciHeader(base, 0, 0, 0); - if ((hdr->header_type & 0x80) == 0) { - // Single bus system. - BusDump(base, 0); - } else { - for (uint64_t f = 0; f < 8; f++) { - PciDeviceHeader* f_hdr = PciHeader(base, 0, 0, f); - if (f_hdr->vendor_id != 0xFFFF) { - BusDump(base, f); - } - } - } -} diff --git a/sys/yellowstone/hw/pcie.h b/sys/yellowstone/hw/pcie.h deleted file mode 100644 index 6b73b31..0000000 --- a/sys/yellowstone/hw/pcie.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include -#include - -struct PciDeviceHeader { - uint16_t vendor_id; - uint16_t device_id; - uint16_t command_reg; - uint16_t status_reg; - uint8_t revision; - uint8_t prog_interface; - uint8_t subclass; - uint8_t class_code; - uint8_t cache_line_size; - uint8_t latency_timer; - uint8_t header_type; - uint8_t bist; -} __attribute__((packed)); - -// TODO: Figure out if it safe to hardcode this. -// For the memory mapped access to PCI, it may be true that -// each configuration item is always the size of a single page. -const uint64_t kPcieConfigurationSize = 0x1000; - -class PciReader { - public: - PciReader(); - - z_cap_t GetAhciVmmo(); - z_cap_t GetXhciVmmo(); - - private: - PciDeviceHeader* header_; - - uint64_t achi_device_offset_ = 0; - uint64_t xhci_device_offset_ = 0; - - void PciDump(uint64_t vaddr); - void BusDump(uint64_t base, uint64_t bus); - void DeviceDump(uint64_t base, uint64_t bus, uint64_t dev); - void FunctionDump(uint64_t base, uint64_t bus, uint64_t dev, uint64_t fun); -}; diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp deleted file mode 100644 index 2c85a99..0000000 --- a/sys/yellowstone/yellowstone.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hw/gpt.h" -#include "hw/pcie.h" -#include "yellowstone_server.h" - -glcr::ErrorCode SpawnProcess(z_cap_t vmmo_cap, z_cap_t yellowstone_cap) { - mmth::OwnedMemoryRegion region = - mmth::OwnedMemoryRegion::FromCapability(vmmo_cap); - auto error_or = - mmth::SpawnProcessFromElfRegion(region.vaddr(), yellowstone_cap); - if (error_or.ok()) { - return glcr::OK; - } - return error_or.error(); -} - -uint64_t main(uint64_t port_cap) { - check(ParseInitPort(port_cap)); - dbgln("Yellowstone Initializing."); - - ASSIGN_OR_RETURN(auto server, yellowstone::YellowstoneServer::Create()); - Thread server_thread = server->RunServer(); - - ASSIGN_OR_RETURN(uint64_t client_cap, server->CreateClientCap()); - check(SpawnProcess(gBootDenaliVmmoCap, client_cap)); - - server->WaitDenaliRegistered(); - - ASSIGN_OR_RETURN(client_cap, server->CreateClientCap()); - check(SpawnProcess(gBootVictoriaFallsVmmoCap, client_cap)); - - server->WaitVictoriaFallsRegistered(); - - dbgln("VFS Available."); - - mmth::File init_file = mmth::File::Open("/init.txt"); - - glcr::Vector files = - glcr::StrSplit(init_file.as_str(), '\n'); - - for (glcr::StringView& file : files) { - if (!file.empty()) { - // TODO: Implement startup dependencies. - if (file == "teton") { - server->WaitVoyageursRegistered(); - } - mmth::File binary = mmth::File::Open(glcr::StrFormat("/bin/{}", file)); - - ASSIGN_OR_RETURN(client_cap, server->CreateClientCap()); - auto error_or = mmth::SpawnProcessFromElfRegion( - (uint64_t)binary.raw_ptr(), client_cap); - if (!error_or.ok()) { - check(error_or.error()); - } - } - } - - check(server_thread.Join()); - dbgln("Yellowstone Finished Successfully."); - return 0; -} diff --git a/sys/yellowstone/yellowstone_server.cpp b/sys/yellowstone/yellowstone_server.cpp deleted file mode 100644 index 1c6af61..0000000 --- a/sys/yellowstone/yellowstone_server.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "yellowstone_server.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "hw/gpt.h" -#include "hw/pcie.h" - -namespace yellowstone { -namespace { - -struct PartitionInfo { - uint64_t device_id; - uint64_t partition_lba; -}; - -glcr::ErrorOr HandleDenaliRegistration(z_cap_t endpoint_cap) { - GptReader reader( - glcr::UniquePtr(new DenaliClient(endpoint_cap))); - - auto status = reader.ParsePartitionTables(); - if (!status.ok()) { - dbgln("GPT Reader: {}", status.message()); - return status.code(); - } - - return PartitionInfo{.device_id = 0, - .partition_lba = reader.GetPrimaryPartitionLba()}; -} - -} // namespace - -glcr::ErrorOr> YellowstoneServer::Create() { - z_cap_t endpoint_cap; - RET_ERR(ZEndpointCreate(&endpoint_cap)); - - return glcr::UniquePtr( - new YellowstoneServer(endpoint_cap)); -} - -YellowstoneServer::YellowstoneServer(z_cap_t endpoint_cap) - : YellowstoneServerBase(endpoint_cap) {} - -glcr::Status YellowstoneServer::HandleGetAhciInfo(AhciInfo& info) { - info.set_ahci_region(pci_reader_.GetAhciVmmo()); - info.set_region_length(kPcieConfigurationSize); - return glcr::Status::Ok(); -} - -glcr::Status YellowstoneServer::HandleGetXhciInfo(XhciInfo& info) { - info.set_xhci_region(pci_reader_.GetXhciVmmo()); - info.set_region_length(kPcieConfigurationSize); - return glcr::Status::Ok(); -} - -glcr::Status YellowstoneServer::HandleGetFramebufferInfo( - FramebufferInfo& info) { - // FIXME: Don't do this for each request. - mmth::OwnedMemoryRegion region = - mmth::OwnedMemoryRegion::FromCapability(gBootFramebufferVmmoCap); - ZFramebufferInfo* fb = reinterpret_cast(region.vaddr()); - - info.set_address_phys(fb->address_phys); - info.set_width(fb->width); - info.set_height(fb->height); - info.set_pitch(fb->pitch); - info.set_bpp(fb->bpp); - info.set_memory_model(fb->memory_model); - info.set_red_mask_size(fb->red_mask_size); - info.set_red_mask_shift(fb->red_mask_shift); - info.set_green_mask_size(fb->green_mask_size); - info.set_green_mask_shift(fb->green_mask_shift); - info.set_blue_mask_size(fb->blue_mask_size); - info.set_blue_mask_shift(fb->blue_mask_shift); - - return glcr::Status::Ok(); -} - -glcr::Status YellowstoneServer::HandleGetDenali(DenaliInfo& info) { - if (!endpoint_map_.Contains("denali")) { - return glcr::NotFound("Denali Capability Not registered"); - } - z_cap_t new_denali; - check(ZCapDuplicate(endpoint_map_.at("denali"), kZionPerm_All, &new_denali)); - info.set_denali_endpoint(new_denali); - info.set_device_id(device_id_); - info.set_lba_offset(lba_offset_); - return glcr::Status::Ok(); -} - -glcr::Status YellowstoneServer::HandleRegisterEndpoint( - const RegisterEndpointRequest& req) { - dbgln("Registering {}.", req.endpoint_name().view()); - check(endpoint_map_.Insert(req.endpoint_name(), req.endpoint_capability())); - if (req.endpoint_name() == "denali") { - z_cap_t dup_cap; - check(ZCapDuplicate(req.endpoint_capability(), kZionPerm_All, &dup_cap)); - auto part_info_or = HandleDenaliRegistration(dup_cap); - if (!part_info_or.ok()) { - check(part_info_or.error()); - } - device_id_ = part_info_or.value().device_id; - lba_offset_ = part_info_or.value().partition_lba; - - has_denali_semaphore_.Signal(); - } else if (req.endpoint_name() == "victoriafalls") { - // FIXME: Probably make a separate copy for use within yellowstone vs - // transmit to other processes. - mmth::SetVfsCap(req.endpoint_capability()); - has_victoriafalls_semaphore_.Signal(); - } else if (req.endpoint_name() == "voyageurs") { - has_voyageurs_.Signal(); - } else { - dbgln("[WARN] Got endpoint cap type: {}", req.endpoint_name().cstr()); - } - return glcr::Status::Ok(); -} - -glcr::Status YellowstoneServer::HandleGetEndpoint(const GetEndpointRequest& req, - Endpoint& resp) { - if (!endpoint_map_.Contains(req.endpoint_name())) { - return glcr::NotFound( - glcr::StrFormat("Endpoint '{}' not found.", req.endpoint_name())); - } - z_cap_t cap = endpoint_map_.at(req.endpoint_name()); - z_cap_t new_cap; - check(ZCapDuplicate(cap, kZionPerm_All, &new_cap)); - resp.set_endpoint(new_cap); - return glcr::Status::Ok(); -} - -void YellowstoneServer::WaitDenaliRegistered() { has_denali_semaphore_.Wait(); } - -void YellowstoneServer::WaitVictoriaFallsRegistered() { - has_victoriafalls_semaphore_.Wait(); -} - -void YellowstoneServer::WaitVoyageursRegistered() { has_voyageurs_.Wait(); } - -} // namespace yellowstone diff --git a/sys/yellowstone/yellowstone_server.h b/sys/yellowstone/yellowstone_server.h deleted file mode 100644 index ac67fa7..0000000 --- a/sys/yellowstone/yellowstone_server.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "hw/pcie.h" -#include "lib/yellowstone/yellowstone.yunq.server.h" - -namespace yellowstone { - -class YellowstoneServer : public YellowstoneServerBase { - public: - static glcr::ErrorOr> Create(); - - glcr::Status HandleGetAhciInfo(AhciInfo&) override; - glcr::Status HandleGetXhciInfo(XhciInfo&) override; - glcr::Status HandleGetFramebufferInfo(FramebufferInfo&) override; - glcr::Status HandleGetDenali(DenaliInfo&) override; - glcr::Status HandleRegisterEndpoint(const RegisterEndpointRequest&) override; - glcr::Status HandleGetEndpoint(const GetEndpointRequest&, Endpoint&) override; - - void WaitDenaliRegistered(); - void WaitVictoriaFallsRegistered(); - void WaitVoyageursRegistered(); - - private: - glcr::HashMap endpoint_map_; - - uint64_t device_id_ = 0; - uint64_t lba_offset_ = 0; - glcr::SharedPtr vfs_client_; - - PciReader pci_reader_; - - mmth::Semaphore has_denali_semaphore_; - mmth::Semaphore has_victoriafalls_semaphore_; - mmth::Semaphore has_voyageurs_; - - YellowstoneServer(z_cap_t endpoint_cap); -}; - -} // namespace yellowstone From 4ee8dc924c4dedcd7f92788569245e77db99c71d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 29 Aug 2024 21:27:27 -0700 Subject: [PATCH 126/186] Add a uniq test module for yunq in rust. --- lib/yunq/test/example/example.yunq | 6 +-- rust/.cargo/config.toml | 3 ++ rust/Cargo.lock | 10 +++++ rust/Cargo.toml | 2 +- rust/lib/mammoth/Cargo.toml | 4 +- rust/lib/mammoth/src/mem.rs | 4 ++ rust/lib/mammoth/src/syscall.rs | 3 ++ rust/lib/yunq-derive/src/lib.rs | 12 +++++- rust/lib/yunq-test/Cargo.toml | 14 +++++++ rust/lib/yunq-test/build.rs | 14 +++++++ rust/lib/yunq-test/src/lib.rs | 62 ++++++++++++++++++++++++++++++ rust/lib/yunq/Cargo.toml | 6 ++- yunq/rust/src/codegen.rs | 2 +- 13 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 rust/lib/yunq-test/Cargo.toml create mode 100644 rust/lib/yunq-test/build.rs create mode 100644 rust/lib/yunq-test/src/lib.rs diff --git a/lib/yunq/test/example/example.yunq b/lib/yunq/test/example/example.yunq index 7e7c927..a3c9e59 100644 --- a/lib/yunq/test/example/example.yunq +++ b/lib/yunq/test/example/example.yunq @@ -1,13 +1,9 @@ package ex; message Basic { - u64 field; -} - -message Types { u64 unsigned_int; i64 signed_int; - string str; + string strn; } message Cap { diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml index 220a396..6e70044 100644 --- a/rust/.cargo/config.toml +++ b/rust/.cargo/config.toml @@ -4,3 +4,6 @@ build-std = ["core", "compiler_builtins", "alloc"] [build] target = "x86_64-acadia-os.json" + +[alias] +test_pc = "test --target=x86_64-unknown-linux-gnu -Z build-std=std --lib" diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 2874dee..f9d9be5 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -210,6 +210,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "yunq-test" +version = "0.1.0" +dependencies = [ + "mammoth", + "yunq", + "yunq-derive", + "yunqc", +] + [[package]] name = "yunqc" version = "0.1.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 589f7ad..b6db314 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "lib/denali", - "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "sys/teton", "sys/yellowstone", "usr/testbed", + "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "lib/yunq-test", "sys/teton", "sys/yellowstone", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/mammoth/Cargo.toml b/rust/lib/mammoth/Cargo.toml index f14c35d..b8fd6ef 100644 --- a/rust/lib/mammoth/Cargo.toml +++ b/rust/lib/mammoth/Cargo.toml @@ -9,4 +9,6 @@ name = "mammoth" [dependencies] linked_list_allocator = "0.10.5" -[build-dependencies] +[features] +hosted = [] +default = ["hosted"] diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 89037c5..cef5dd6 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -2,13 +2,17 @@ use crate::cap::Capability; use crate::syscall; use crate::zion::ZError; use alloc::slice; + +#[cfg(feature = "hosted")] use linked_list_allocator::LockedHeap; +#[cfg(feature = "hosted")] #[global_allocator] static ALLOCATOR: LockedHeap = LockedHeap::empty(); pub static mut CAN_ALLOC: bool = false; +#[cfg(feature = "hosted")] pub fn init_heap() { // 1 MiB let size = 0x10_0000; diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 2ffaca5..5b83756 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -5,6 +5,8 @@ use crate::zion; use crate::zion::z_cap_t; use crate::zion::ZError; use core::ffi::c_void; + +#[cfg(feature = "hosted")] use core::panic::PanicInfo; #[must_use] @@ -18,6 +20,7 @@ fn syscall(id: u64, req: &T) -> Result<(), ZError> { Ok(()) } +#[cfg(feature = "hosted")] #[panic_handler] fn panic(info: &PanicInfo) -> ! { unsafe { diff --git a/rust/lib/yunq-derive/src/lib.rs b/rust/lib/yunq-derive/src/lib.rs index d1652e0..bf99f3b 100644 --- a/rust/lib/yunq-derive/src/lib.rs +++ b/rust/lib/yunq-derive/src/lib.rs @@ -29,7 +29,13 @@ fn serialize_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenS } else if path.is_ident("u64") { quote! { { - buf.write_at(yunq::message::field_offset(offset, #ind), self.#name as u64)?; + buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; + } + } + } else if path.is_ident("i64") { + quote! { + { + buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; } } } else { @@ -67,6 +73,10 @@ fn parse_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStrea quote! { let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; } + } else if path.is_ident("i64") { + quote! { + let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; + } } else { quote! { let #name = { diff --git a/rust/lib/yunq-test/Cargo.toml b/rust/lib/yunq-test/Cargo.toml new file mode 100644 index 0000000..8d550ce --- /dev/null +++ b/rust/lib/yunq-test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "yunq-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../mammoth", default-features = false} +yunq = {path = "../yunq", default-features = false} +yunq-derive = {path = "../yunq-derive"} + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + +[dev-dependencies] diff --git a/rust/lib/yunq-test/build.rs b/rust/lib/yunq-test/build.rs new file mode 100644 index 0000000..ef1bf8d --- /dev/null +++ b/rust/lib/yunq-test/build.rs @@ -0,0 +1,14 @@ +use std::fs; + +fn main() { + let input_file = "../../../lib/yunq/test/example/example.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + fs::write(out, code).expect("Failed to write generated code."); +} diff --git a/rust/lib/yunq-test/src/lib.rs b/rust/lib/yunq-test/src/lib.rs new file mode 100644 index 0000000..dd2b5be --- /dev/null +++ b/rust/lib/yunq-test/src/lib.rs @@ -0,0 +1,62 @@ +#![no_std] + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +#[cfg(test)] +mod tests { + use super::*; + + extern crate std; + use std::vec; + + #[test] + fn basic_serialization() -> Result<(), ZError> { + let basic = Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + basic.serialize(&mut buf, 0, &mut caps)?; + + let parsed = Basic::parse(&buf, 0, &caps)?; + + assert!(parsed == basic); + + Ok(()) + } + + #[test] + fn basic_serialization_as_request() -> Result<(), ZError> { + let basic = Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + let req_id = 12; + basic.serialize_as_request(req_id, &mut buf, &mut caps)?; + + assert!(buf.at::(8)? == req_id); + + let parsed = Basic::parse_from_request(&buf, &caps)?; + + assert!(parsed == basic); + Ok(()) + } + + #[test] + fn capability_serialization() -> Result<(), ZError> { + let cap_id = 100; + let cap = Cap { cap: cap_id }; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + cap.serialize(&mut buf, 0, &mut caps)?; + + assert!(caps.len() == 1); + assert!(caps[0] == cap_id); + + let parsed = Cap::parse(&buf, 0, &caps)?; + + assert!(parsed == cap); + + Ok(()) + } +} diff --git a/rust/lib/yunq/Cargo.toml b/rust/lib/yunq/Cargo.toml index f442771..2a75596 100644 --- a/rust/lib/yunq/Cargo.toml +++ b/rust/lib/yunq/Cargo.toml @@ -4,5 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] -mammoth = {path = "../mammoth"} +mammoth = {path = "../mammoth", default-features = false} yunq-derive = {path = "../yunq-derive"} + +[features] +default = ["hosted"] +hosted = ["mammoth/hosted"] diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 71e493e..928ec58 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -17,7 +17,7 @@ fn generate_message(message: &Message) -> TokenStream { .iter() .map(|f| Ident::new(f.field_type.rust_type(), Span::call_site())); quote! { - #[derive(YunqMessage)] + #[derive(YunqMessage, PartialEq, Eq)] pub struct #name { #(pub #field_names: #field_types),* } From f94f56f9ecbc110c289f8063b5d42d0e47a4e995 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 29 Aug 2024 23:29:58 -0700 Subject: [PATCH 127/186] [Yunq] Create repeated field implementations in rust. --- rust/Cargo.lock | 30 +--- rust/Cargo.toml | 2 +- rust/lib/denali/Cargo.toml | 1 - rust/lib/victoriafalls/Cargo.toml | 1 - rust/lib/voyageurs/Cargo.toml | 1 - rust/lib/yellowstone/Cargo.toml | 1 - rust/lib/yunq-derive/Cargo.toml | 12 -- rust/lib/yunq-derive/src/lib.rs | 188 ---------------------- rust/lib/yunq-test/Cargo.toml | 2 - rust/lib/yunq-test/src/lib.rs | 18 +++ rust/lib/yunq/Cargo.toml | 1 - rust/lib/yunq/src/message.rs | 51 ++++++ yunq/rust/src/codegen.rs | 259 ++++++++++++++++++++++++++++-- yunq/rust/src/parser.rs | 49 +++--- 14 files changed, 347 insertions(+), 269 deletions(-) delete mode 100644 rust/lib/yunq-derive/Cargo.toml delete mode 100644 rust/lib/yunq-derive/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f9d9be5..37a5cd7 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -23,7 +23,6 @@ version = "0.1.0" dependencies = [ "mammoth", "yunq", - "yunq-derive", "yunqc", ] @@ -60,7 +59,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.72", + "syn", ] [[package]] @@ -96,17 +95,6 @@ dependencies = [ "lock_api", ] -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.72" @@ -156,7 +144,6 @@ dependencies = [ "mammoth", "yellowstone-yunq", "yunq", - "yunq-derive", "yunqc", ] @@ -167,7 +154,6 @@ dependencies = [ "mammoth", "yellowstone-yunq", "yunq", - "yunq-derive", "yunqc", ] @@ -189,7 +175,6 @@ version = "0.1.0" dependencies = [ "mammoth", "yunq", - "yunq-derive", "yunqc", ] @@ -198,16 +183,6 @@ name = "yunq" version = "0.1.0" dependencies = [ "mammoth", - "yunq-derive", -] - -[[package]] -name = "yunq-derive" -version = "0.1.0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", ] [[package]] @@ -216,7 +191,6 @@ version = "0.1.0" dependencies = [ "mammoth", "yunq", - "yunq-derive", "yunqc", ] @@ -228,5 +202,5 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.72", + "syn", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index b6db314..c357206 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "lib/denali", - "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-derive", "lib/yunq-test", "sys/teton", "sys/yellowstone", "usr/testbed", + "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-test", "sys/teton", "sys/yellowstone", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/denali/Cargo.toml b/rust/lib/denali/Cargo.toml index e05782f..2993024 100644 --- a/rust/lib/denali/Cargo.toml +++ b/rust/lib/denali/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] mammoth = { path = "../mammoth" } yunq = {path = "../yunq"} -yunq-derive = {path = "../yunq-derive"} [build-dependencies] yunqc = {path = "../../../yunq/rust"} diff --git a/rust/lib/victoriafalls/Cargo.toml b/rust/lib/victoriafalls/Cargo.toml index aeb0bf1..6aeae9e 100644 --- a/rust/lib/victoriafalls/Cargo.toml +++ b/rust/lib/victoriafalls/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" mammoth = { path = "../mammoth" } yellowstone-yunq = { path = "../yellowstone" } yunq = {path = "../yunq"} -yunq-derive = {path = "../yunq-derive"} [build-dependencies] yunqc = {path = "../../../yunq/rust"} diff --git a/rust/lib/voyageurs/Cargo.toml b/rust/lib/voyageurs/Cargo.toml index b396220..e011e0c 100644 --- a/rust/lib/voyageurs/Cargo.toml +++ b/rust/lib/voyageurs/Cargo.toml @@ -7,7 +7,6 @@ edition = "2021" mammoth = { path = "../mammoth" } yellowstone-yunq = { path = "../yellowstone" } yunq = {path = "../yunq"} -yunq-derive = {path = "../yunq-derive"} [build-dependencies] yunqc = {path = "../../../yunq/rust"} diff --git a/rust/lib/yellowstone/Cargo.toml b/rust/lib/yellowstone/Cargo.toml index c9a6299..74c80c4 100644 --- a/rust/lib/yellowstone/Cargo.toml +++ b/rust/lib/yellowstone/Cargo.toml @@ -6,7 +6,6 @@ edition = "2021" [dependencies] mammoth = { path = "../mammoth" } yunq = {path = "../yunq"} -yunq-derive = {path = "../yunq-derive"} [build-dependencies] yunqc = {path = "../../../yunq/rust"} diff --git a/rust/lib/yunq-derive/Cargo.toml b/rust/lib/yunq-derive/Cargo.toml deleted file mode 100644 index c17a506..0000000 --- a/rust/lib/yunq-derive/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "yunq-derive" -version = "0.1.0" -edition = "2021" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "1.0", features = ["full", "extra-traits", "printing"] } diff --git a/rust/lib/yunq-derive/src/lib.rs b/rust/lib/yunq-derive/src/lib.rs deleted file mode 100644 index bf99f3b..0000000 --- a/rust/lib/yunq-derive/src/lib.rs +++ /dev/null @@ -1,188 +0,0 @@ -use proc_macro::{self, TokenStream}; -use quote::{quote, ToTokens}; -use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields, Ident, Path, Type, TypePath}; - -fn serialize_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStream { - if path.is_ident("String") { - quote! { - { - let str_offset = next_extension; - let str_length = self.#name.len() as u32; - - buf.write_str_at(offset + next_extension as usize, &self.#name)?; - next_extension += str_length; - - buf.write_at(yunq::message::field_offset(offset, #ind), str_offset)?; - buf.write_at(yunq::message::field_offset(offset, #ind) + 4, str_length)?; - } - - } - } else if path.is_ident("z_cap_t") { - quote! { - { - let cap_ind = caps.len(); - caps.push(self.#name); - - buf.write_at(yunq::message::field_offset(offset, #ind), cap_ind as u64)?; - } - } - } else if path.is_ident("u64") { - quote! { - { - buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; - } - } - } else if path.is_ident("i64") { - quote! { - { - buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; - } - } - } else { - quote! { - { - let msg_offset = next_extension; - let msg_length = self.#name.serialize(buf, offset + next_extension as usize, caps)? as u32; - next_extension += msg_length; - - buf.write_at(yunq::message::field_offset(offset, #ind), msg_offset)?; - buf.write_at(yunq::message::field_offset(offset, #ind) + 4, msg_length)?; - } - } - } -} - -fn parse_field(name: &Ident, ind: usize, path: &Path) -> proc_macro2::TokenStream { - if path.is_ident("String") { - quote! { - let #name = { - let str_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; - let str_length = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; - - buf.str_at(offset + str_offset as usize, str_length as usize)?.to_string() - }; - } - } else if path.is_ident("z_cap_t") { - quote! { - let #name = { - let cap_ind = buf.at::(yunq::message::field_offset(offset, #ind))?; - caps[cap_ind as usize] - }; - } - } else if path.is_ident("u64") { - quote! { - let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; - } - } else if path.is_ident("i64") { - quote! { - let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; - } - } else { - quote! { - let #name = { - let msg_offset = buf.at::(yunq::message::field_offset(offset, #ind))? as usize; - - #path::parse(buf, offset + msg_offset, caps)? - }; - } - } -} - -fn field_names(name: &Ident, _ind: usize, _path: &Path) -> proc_macro2::TokenStream { - quote! { #name } -} - -fn apply_to_struct_fields(input: &DeriveInput, func: fn(&Ident, usize, &Path) -> T) -> Vec { - match &input.data { - Data::Struct(DataStruct { - fields: Fields::Named(fields), - .. - }) => fields - .named - .iter() - .enumerate() - .map(|(ind, field)| match &field.ty { - Type::Path(TypePath { path, .. }) => { - func(&field.ident.as_ref().unwrap(), ind, path) - } - _ => { - panic!("Unrecognized type: {:?}", field) - } - }) - .collect(), - _ => { - panic!("Unrecognized input (Expected Struct): {:?}", input.data) - } - } -} - -#[proc_macro_derive(YunqMessage)] -pub fn derive_client(input_tokens: TokenStream) -> TokenStream { - let input: DeriveInput = parse_macro_input!(input_tokens); - let ident = input.ident.clone(); - - let prelude = quote! { - impl YunqMessage for #ident - }; - - let num_fields = apply_to_struct_fields(&input, |_, _, _| ()).len(); - - let serializers = apply_to_struct_fields(&input, serialize_field); - let serialize = quote! { - fn serialize( - &self, - buf: &mut yunq::ByteBuffer, - offset: usize, - caps: &mut alloc::vec::Vec, - ) -> Result { - let num_fields = #num_fields; - let core_size: u32 = (yunq::message::MESSAGE_HEADER_SIZE + 8 * num_fields) as u32; - let mut next_extension = core_size; - - #(#serializers)* - - buf.write_at(offset + 0, yunq::message::MESSAGE_IDENT)?; - buf.write_at(offset + 4, core_size)?; - buf.write_at(offset + 8, next_extension)?; - buf.write_at(offset + 12, 0 as u32)?; - Ok(next_extension as usize) - } - }; - - let field_names = apply_to_struct_fields(&input, field_names); - let parsers = apply_to_struct_fields(&input, parse_field); - let parse = quote! { - fn parse( - buf: &yunq::ByteBuffer, - offset: usize, - caps: &alloc::vec::Vec, - ) -> Result - where - Self: Sized, - { - if buf.at::(offset + 0)? != yunq::message::MESSAGE_IDENT { - return Err(ZError::INVALID_ARGUMENT); - } - // TODO: Parse core size. - // TODO: Parse extension size. - // TODO: Check CRC32 - // TODO: Parse options. - - #(#parsers)* - - Ok(Self { - #(#field_names),* - }) - - } - }; - - let output = quote! { - #prelude { - #serialize - - #parse - } - }; - output.into() -} diff --git a/rust/lib/yunq-test/Cargo.toml b/rust/lib/yunq-test/Cargo.toml index 8d550ce..4a4591d 100644 --- a/rust/lib/yunq-test/Cargo.toml +++ b/rust/lib/yunq-test/Cargo.toml @@ -6,9 +6,7 @@ edition = "2021" [dependencies] mammoth = { path = "../mammoth", default-features = false} yunq = {path = "../yunq", default-features = false} -yunq-derive = {path = "../yunq-derive"} [build-dependencies] yunqc = {path = "../../../yunq/rust"} -[dev-dependencies] diff --git a/rust/lib/yunq-test/src/lib.rs b/rust/lib/yunq-test/src/lib.rs index dd2b5be..58825a6 100644 --- a/rust/lib/yunq-test/src/lib.rs +++ b/rust/lib/yunq-test/src/lib.rs @@ -7,6 +7,7 @@ mod tests { use super::*; extern crate std; + use std::println; use std::vec; #[test] @@ -59,4 +60,21 @@ mod tests { Ok(()) } + + #[test] + fn repeated_serialization() -> Result<(), ZError> { + let rep = Repeated { unsigned_ints: vec![0, 1, 3],}; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + rep.serialize(&mut buf, 0, &mut caps)?; + + let parsed = Repeated::parse(&buf, 0, &caps)?; + + println!("{:?}", parsed.unsigned_ints); + + assert!(parsed == rep); + + Ok(()) + } } diff --git a/rust/lib/yunq/Cargo.toml b/rust/lib/yunq/Cargo.toml index 2a75596..d5c3db0 100644 --- a/rust/lib/yunq/Cargo.toml +++ b/rust/lib/yunq/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] mammoth = {path = "../mammoth", default-features = false} -yunq-derive = {path = "../yunq-derive"} [features] default = ["hosted"] diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index 44ca368..eb5dfc6 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -12,6 +12,57 @@ pub fn field_offset(offset: usize, field_index: usize) -> usize { offset + MESSAGE_HEADER_SIZE + (8 * field_index) } +pub fn parse_repeated( + buf: &ByteBuffer, + offset: usize, + len: usize, +) -> Result, ZError> { + let mut repeated = Vec::new(); + for i in 0..len { + repeated.push(buf.at::(offset + (i * size_of::()))?); + } + Ok(repeated) +} + +pub fn parse_repeated_message( + buf: &ByteBuffer, + mut offset: usize, + len: usize, + caps: &Vec, +) -> Result, ZError> { + let mut repeated = Vec::new(); + for _ in 0..len { + // FIXME: This is a bad way to get the length. + let msg_len = buf.at::(offset + 8)? as usize; + repeated.push(T::parse(buf, offset, caps)?); + offset += msg_len; + } + Ok(repeated) +} + +pub fn serialize_repeated( + buf: &mut ByteBuffer, + offset: usize, + data: &Vec, +) -> Result { + for i in 0..data.len() { + buf.write_at(offset + (i * size_of::()), data[i])?; + } + Ok(offset + (data.len() * size_of::())) +} + +pub fn serialize_repeated_message( + buf: &mut ByteBuffer, + mut offset: usize, + data: &Vec, + caps: &mut Vec, +) -> Result { + for item in data { + offset = item.serialize(buf, offset, caps)?; + } + Ok(offset) +} + pub fn serialize_error(buf: &mut ByteBuffer, err: ZError) { buf.write_at(0, SENTINEL) .expect("Failed to serialize SENTINEL"); diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 928ec58..00d2a64 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -1,4 +1,5 @@ -use crate::parser::{Decl, Interface, Message, Method}; +use crate::parser::{Decl, Interface, Message, Method, Type}; +use crate::parser::{Field, FieldType}; use convert_case::{Case, Casing}; use proc_macro2::Ident; use proc_macro2::Span; @@ -9,19 +10,237 @@ fn ident(s: &str) -> Ident { Ident::new(s, Span::call_site()) } +fn to_path(field_type: &FieldType) -> TokenStream { + let rust_type = ident(&field_type.inner_type.rust_type()); + if field_type.repeated { + quote! { + Vec::<#rust_type> + } + } else { + quote! { + #rust_type + } + } +} + +fn serialize_field(field: &Field) -> proc_macro2::TokenStream { + let ind = field.number as usize; + let name = ident(&field.name); + if field.field_type.repeated { + match &field.field_type.inner_type { + Type::String => unimplemented!(), + Type::Capability => unimplemented!(), + Type::U64 => quote! { + { + 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; + + buf.write_at(yunq::message::field_offset(offset, #ind), rep_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, rep_len)?; + } + }, + Type::I64 => unimplemented!(), + Type::Bytes => unimplemented!(), + Type::Message(_) => quote! { + { + 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; + + buf.write_at(yunq::message::field_offset(offset, #ind), rep_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, rep_len)?; + } + }, + } + } else { + match &field.field_type.inner_type { + Type::String => quote! { + { + let str_offset = next_extension; + let str_length = self.#name.len() as u32; + + buf.write_str_at(offset + next_extension as usize, &self.#name)?; + next_extension += str_length; + + buf.write_at(yunq::message::field_offset(offset, #ind), str_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, str_length)?; + } + }, + Type::Capability => quote! { + { + let cap_ind = caps.len(); + caps.push(self.#name); + + buf.write_at(yunq::message::field_offset(offset, #ind), cap_ind as u64)?; + } + }, + Type::U64 => quote! { + { + buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; + } + }, + Type::I64 => quote! { + { + buf.write_at(yunq::message::field_offset(offset, #ind), self.#name)?; + } + }, + Type::Message(_) => quote! { + { + let msg_offset = next_extension; + let msg_length = self.#name.serialize(buf, offset + next_extension as usize, caps)? as u32; + next_extension += msg_length; + + buf.write_at(yunq::message::field_offset(offset, #ind), msg_offset)?; + buf.write_at(yunq::message::field_offset(offset, #ind) + 4, msg_length)?; + } + }, + Type::Bytes => unimplemented!(), + } + } +} + +fn parse_field(field: &Field) -> TokenStream { + let ind = field.number as usize; + let name = ident(&field.name); + if field.field_type.repeated { + match &field.field_type.inner_type { + Type::String => unimplemented!(), + Type::Capability => unimplemented!(), + Type::U64 => quote! { + let #name = { + let rep_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; + let rep_len = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; + + yunq::message::parse_repeated(buf, rep_offset as usize, rep_len as usize)? + }; + }, + Type::I64 => unimplemented!(), + Type::Bytes => unimplemented!(), + Type::Message(_s) => quote! { + let #name = { + let rep_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; + let rep_len = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; + + yunq::message::parse_repeated_message(buf, rep_offset as usize, rep_len as usize, &caps)? + }; + }, + } + } else { + match &field.field_type.inner_type { + Type::String => quote! { + let #name = { + let str_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; + let str_length = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; + + buf.str_at(offset + str_offset as usize, str_length as usize)?.to_string() + }; + }, + Type::Capability => quote! { + let #name = { + let cap_ind = buf.at::(yunq::message::field_offset(offset, #ind))?; + caps[cap_ind as usize] + }; + }, + Type::U64 => quote! { + let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; + }, + Type::I64 => quote! { + let #name = buf.at::(yunq::message::field_offset(offset, #ind))?; + }, + Type::Bytes => { + unimplemented!(); + } + Type::Message(s) => { + let m_type = ident(&s); + quote! { + let #name = { + let msg_offset = buf.at::(yunq::message::field_offset(offset, #ind))? as usize; + + #m_type::parse(buf, offset + msg_offset, caps)? + }; + } + } + } + } +} + +fn generate_serialize(message: &Message) -> TokenStream { + let num_fields = message.fields.len(); + let serializers = message.fields.iter().map(serialize_field); + quote! { + #[allow(unused_variables)] // caps may be unused. + fn serialize( + &self, + buf: &mut yunq::ByteBuffer, + offset: usize, + caps: &mut alloc::vec::Vec, + ) -> Result { + let num_fields = #num_fields; + let core_size: u32 = (yunq::message::MESSAGE_HEADER_SIZE + 8 * num_fields) as u32; + #[allow(unused_mut)] + let mut next_extension = core_size; + + #(#serializers)* + + buf.write_at(offset + 0, yunq::message::MESSAGE_IDENT)?; + buf.write_at(offset + 4, core_size)?; + buf.write_at(offset + 8, next_extension)?; + buf.write_at(offset + 12, 0 as u32)?; + Ok(next_extension as usize) + } + } +} + +fn generate_parse(message: &Message) -> TokenStream { + let field_names = message.fields.iter().map(|field| ident(&field.name)); + let parsers = message.fields.iter().map(parse_field); + quote! { + #[allow(unused_variables)] // caps may be unused. + fn parse( + buf: &yunq::ByteBuffer, + offset: usize, + caps: &alloc::vec::Vec, + ) -> Result + where + Self: Sized, + { + if buf.at::(offset + 0)? != yunq::message::MESSAGE_IDENT { + return Err(ZError::INVALID_ARGUMENT); + } + // TODO: Parse core size. + // TODO: Parse extension size. + // TODO: Check CRC32 + // TODO: Parse options. + + #(#parsers)* + + Ok(Self { + #(#field_names),* + }) + + } + } +} + fn generate_message(message: &Message) -> TokenStream { let name = ident(&message.name); let field_names = message.fields.iter().map(|f| ident(&f.name)); - let field_types = message - .fields - .iter() - .map(|f| Ident::new(f.field_type.rust_type(), Span::call_site())); + let field_types = message.fields.iter().map(|f| to_path(&f.field_type)); + + let serialize = generate_serialize(message); + let parse = generate_parse(message); quote! { - #[derive(YunqMessage, PartialEq, Eq)] + #[derive(PartialEq, Eq)] pub struct #name { #(pub #field_names: #field_types),* } + impl YunqMessage for #name { + #serialize + + #parse + } } } @@ -199,20 +418,29 @@ pub fn generate_code(ast: &Vec) -> String { extern crate alloc; - use alloc::boxed::Box; use alloc::string::String; use alloc::string::ToString; use alloc::vec::Vec; - use core::ffi::c_void; - use mammoth::syscall; - use mammoth::thread; - use mammoth::cap::Capability; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; use yunq::ByteBuffer; use yunq::YunqMessage; + + + // Used only by modules with an interface. + #[allow(unused_imports)] + use alloc::boxed::Box; + #[allow(unused_imports)] + use core::ffi::c_void; + #[allow(unused_imports)] + use mammoth::cap::Capability; + #[allow(unused_imports)] + use mammoth::syscall; + #[allow(unused_imports)] + use mammoth::thread; + #[allow(unused_imports)] use yunq::server::YunqServer; - use yunq_derive::YunqMessage; + }; let message_decls = ast @@ -240,5 +468,10 @@ pub fn generate_code(ast: &Vec) -> String { } .to_string(); - prettyplease::unparse(&syn::parse_file(&output).unwrap()) + let tokens = syn::parse_file(&output).unwrap_or_else(|e| { + println!("{}", output); + panic!("{}", e); + }); + + prettyplease::unparse(&tokens) } diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index f116fb9..07841f8 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -17,24 +17,33 @@ pub enum Type { } impl Type { - pub fn rust_type(&self) -> &str { + pub fn rust_type(&self) -> String { match self { - Type::U64 => "u64", - Type::I64 => "i64", - Type::String => "String", - Type::Bytes => "Vec", - Type::Capability => "z_cap_t", - Type::Message(s) => s, + Type::U64 => "u64".to_string(), + Type::I64 => "i64".to_string(), + Type::String => "String".to_string(), + Type::Bytes => "Vec".to_string(), + Type::Capability => "z_cap_t".to_string(), + Type::Message(s) => s.clone(), } } } -impl Display for Type { +#[derive(Clone)] +pub struct FieldType { + pub repeated: bool, + pub inner_type: Type, +} + +impl Display for FieldType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + if self.repeated { + write!(f, "repeated ")?; + } write!( f, "{}", - match self { + match &self.inner_type { Type::U64 => "u64", Type::I64 => "i64", Type::String => "string", @@ -63,10 +72,9 @@ impl TryFrom<&String> for Type { #[derive(Clone)] pub struct Field { - pub field_type: Type, + pub field_type: FieldType, pub name: String, pub number: u64, - pub repeated: bool, } #[derive(Clone)] @@ -118,12 +126,11 @@ impl Debug for Decl { Decl::Message(m) => { writeln!(f, "Message {}", m.name)?; for field in &m.fields { - let typestr = if field.repeated { - format!("repeated {}", field.field_type) - } else { - field.field_type.to_string() - }; - writeln!(f, "\t{}: {} ({})", field.number, field.name, typestr)?; + writeln!( + f, + "\t{}: {} ({})", + field.number, field.name, field.field_type + )?; } } Decl::Interface(i) => { @@ -220,10 +227,12 @@ impl<'a> Parser<'a> { self.consume_token_type(TokenType::Semicolon)?; Ok(Field { - field_type: parsed_type, + field_type: FieldType { + inner_type: parsed_type, + repeated, + }, name: name_identifier, number, - repeated, }) } @@ -357,7 +366,7 @@ impl<'a> Parser<'a> { } field_names.insert(field.name.clone()); - if let Type::Message(name) = &field.field_type { + if let Type::Message(name) = &field.field_type.inner_type { if !self.type_map.contains_key(name) { return Err(format!( "Unknown type '{}' on field '{}' in message '{}'", From 72e5d8c618507d95ff4bc61be3447fc03d39e3b7 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 29 Aug 2024 23:39:30 -0700 Subject: [PATCH 128/186] [Yunq] Rust tests for nested messages. --- lib/yunq/test/example/example.yunq | 12 ++++++++ rust/lib/yunq-test/src/lib.rs | 45 ++++++++++++++++++++++++++++-- rust/lib/yunq/src/message.rs | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/lib/yunq/test/example/example.yunq b/lib/yunq/test/example/example.yunq index a3c9e59..7b11e08 100644 --- a/lib/yunq/test/example/example.yunq +++ b/lib/yunq/test/example/example.yunq @@ -13,3 +13,15 @@ message Cap { message Repeated { repeated u64 unsigned_ints; } + + +message Nested { + Basic basic; + Cap cap1; + Cap cap2; +} + +message RepeatedNested { + repeated Basic basics; + repeated Cap caps; +} diff --git a/rust/lib/yunq-test/src/lib.rs b/rust/lib/yunq-test/src/lib.rs index 58825a6..1a3c3ec 100644 --- a/rust/lib/yunq-test/src/lib.rs +++ b/rust/lib/yunq-test/src/lib.rs @@ -71,10 +71,51 @@ mod tests { let parsed = Repeated::parse(&buf, 0, &caps)?; - println!("{:?}", parsed.unsigned_ints); - assert!(parsed == rep); Ok(()) } + + #[test] + fn nested_serialization() -> Result<(), ZError> { + let nested = Nested { + basic: Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }, + cap1: Cap { cap: 37}, + cap2: Cap { cap: 39}, + }; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + nested.serialize(&mut buf, 0, &mut caps)?; + + let parsed = Nested::parse(&buf, 0, &caps)?; + + + assert!(parsed == nested); + + Ok(()) + } + + #[test] + fn repeated_nested_serialization() -> Result<(), ZError> { + let nested = RepeatedNested { + basics: vec![Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string(),}, + Basic { unsigned_int: 21, signed_int: -8, strn: "def".to_string(), },], + caps: vec![Cap{ cap: 123}, Cap {cap: 12343}], + }; + + let mut buf = ByteBuffer::<1024>::new(); + let mut caps = Vec::new(); + nested.serialize(&mut buf, 0, &mut caps)?; + + let parsed = RepeatedNested::parse(&buf, 0, &caps)?; + + + assert!(parsed == nested); + + + Ok(()) + } + + } diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index eb5dfc6..d1fc6a5 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -58,7 +58,7 @@ pub fn serialize_repeated_message( caps: &mut Vec, ) -> Result { for item in data { - offset = item.serialize(buf, offset, caps)?; + offset += item.serialize(buf, offset, caps)?; } Ok(offset) } From 51478e7ccf74cb4aa6b4dd28acb2881ed41cdce5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 30 Aug 2024 00:38:15 -0700 Subject: [PATCH 129/186] [Denali] Begin porting to rust. --- rust/Cargo.lock | 1 + rust/Cargo.toml | 4 +-- rust/lib/denali/Cargo.toml | 11 ------ rust/sys/denali/Cargo.toml | 21 +++++++++++ rust/{lib => sys}/denali/build.rs | 0 rust/sys/denali/src/ahci/controller.rs | 49 ++++++++++++++++++++++++++ rust/sys/denali/src/ahci/mod.rs | 3 ++ rust/sys/denali/src/bin/denali.rs | 29 +++++++++++++++ rust/{lib => sys}/denali/src/lib.rs | 2 ++ rust/sys/yellowstone/Cargo.toml | 2 +- scripts/build_image.sh | 2 +- scripts/qemu.sh | 2 +- 12 files changed, 110 insertions(+), 16 deletions(-) delete mode 100644 rust/lib/denali/Cargo.toml create mode 100644 rust/sys/denali/Cargo.toml rename rust/{lib => sys}/denali/build.rs (100%) create mode 100644 rust/sys/denali/src/ahci/controller.rs create mode 100644 rust/sys/denali/src/ahci/mod.rs create mode 100644 rust/sys/denali/src/bin/denali.rs rename rust/{lib => sys}/denali/src/lib.rs (84%) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 37a5cd7..c7d4f7b 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -22,6 +22,7 @@ name = "denali" version = "0.1.0" dependencies = [ "mammoth", + "yellowstone-yunq", "yunq", "yunqc", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index c357206..258b494 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] -members = [ "lib/denali", - "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-test", "sys/teton", "sys/yellowstone", "usr/testbed", +members = [ + "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-test", "sys/denali", "sys/teton", "sys/yellowstone", "usr/testbed", ] resolver = "2" diff --git a/rust/lib/denali/Cargo.toml b/rust/lib/denali/Cargo.toml deleted file mode 100644 index 2993024..0000000 --- a/rust/lib/denali/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "denali" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../mammoth" } -yunq = {path = "../yunq"} - -[build-dependencies] -yunqc = {path = "../../../yunq/rust"} diff --git a/rust/sys/denali/Cargo.toml b/rust/sys/denali/Cargo.toml new file mode 100644 index 0000000..6cb7992 --- /dev/null +++ b/rust/sys/denali/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "denali" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../../lib/mammoth" } +yunq = {path = "../../lib/yunq"} + +yellowstone-yunq = { path = "../../lib/yellowstone", optional = true } + +[[bin]] +name = "denali" +required-features = ["binary"] + +[build-dependencies] +yunqc = {path = "../../../yunq/rust"} + +[features] +default = ["binary"] +binary = ["dep:yellowstone-yunq"] diff --git a/rust/lib/denali/build.rs b/rust/sys/denali/build.rs similarity index 100% rename from rust/lib/denali/build.rs rename to rust/sys/denali/build.rs diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs new file mode 100644 index 0000000..cf02c60 --- /dev/null +++ b/rust/sys/denali/src/ahci/controller.rs @@ -0,0 +1,49 @@ +use mammoth::mem::MemoryRegion; + +#[repr(C, packed)] +pub struct PciDeviceHeader { + pub vendor_id: u16, + pub device_id: u16, + pub command_reg: u16, + pub status_reg: u16, + pub revision: u8, + pub prog_interface: u8, + pub subclass: u8, + pub class_code: u8, + pub cache_line_size: u8, + pub latency_timer: u8, + pub header_type: u8, + pub bist: u8, + pub bars: [u32; 5], + pub abar: u32, + pub reserved0: u32, + pub subsystem_id: u32, + pub expansion_rom: u16, + pub cap_ptr: u8, + pub reserved1: [u8; 7], + pub interrupt_line: u8, + pub interrupt_pin: u8, + pub min_grant: u8, + pub max_latency: u8, +} + +pub struct AhciController { + pci_memory: MemoryRegion, +} + +impl AhciController { + pub fn new(pci_memory: MemoryRegion) -> Self { + Self { pci_memory } + } + + pub fn pci_header(&self) -> &mut PciDeviceHeader { + unsafe { + self.pci_memory + .mut_slice::() + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + } + } +} diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs new file mode 100644 index 0000000..db456be --- /dev/null +++ b/rust/sys/denali/src/ahci/mod.rs @@ -0,0 +1,3 @@ +mod controller; + +pub use controller::AhciController; diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs new file mode 100644 index 0000000..b685b5d --- /dev/null +++ b/rust/sys/denali/src/bin/denali.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] + +extern crate alloc; + +use mammoth::{define_entry, zion::z_err_t}; + +use denali::ahci::AhciController; + +define_entry!(); + +#[no_mangle] +extern "C" fn main() -> z_err_t { + mammoth::debug!("IN Denali!"); + + let yellowstone = yellowstone_yunq::from_init_endpoint(); + + let ahci_info = yellowstone + .get_ahci_info() + .expect("Failed to get ahci info"); + + let ahci_controller = AhciController::new( + mammoth::mem::MemoryRegion::from_cap(mammoth::cap::Capability::take(ahci_info.ahci_region)) + .unwrap(), + ); + + mammoth::debug!("AHCI ABAR {:#x}", ahci_controller.pci_header().abar as u64); + 0 +} diff --git a/rust/lib/denali/src/lib.rs b/rust/sys/denali/src/lib.rs similarity index 84% rename from rust/lib/denali/src/lib.rs rename to rust/sys/denali/src/lib.rs index 3cec9d6..ee83829 100644 --- a/rust/lib/denali/src/lib.rs +++ b/rust/sys/denali/src/lib.rs @@ -3,3 +3,5 @@ use core::include; include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +pub mod ahci; diff --git a/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml index 57e52b8..5e165e8 100644 --- a/rust/sys/yellowstone/Cargo.toml +++ b/rust/sys/yellowstone/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -denali = { path = "../../lib/denali" } +denali = { path = "../../sys/denali", default-features = false} victoriafalls = { path = "../../lib/victoriafalls" } voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 826bdd4..f715102 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -40,7 +40,7 @@ cp ../zion/boot/limine.cfg efi/ cp zion/zion efi/ mkdir -p efi/sys cp ../sysroot/bin/yellowstone efi/sys/yellowstone -cp sys/denali/denali efi/sys/denali +cp ../sysroot/bin/denali efi/sys/denali cp sys/victoriafalls/victoriafalls efi/sys/victoriafalls mkdir -p sysroot diff --git a/scripts/qemu.sh b/scripts/qemu.sh index 0ae6b41..40bf1c7 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -23,7 +23,7 @@ for BIN in ${DIR}/../rust/usr/*/; do done for BIN in ${DIR}/../rust/sys/*/; do - cargo install --force --path "${BIN}" --root $CARGO_SYS_ROOT + cargo install --all-features --force --path "${BIN}" --root $CARGO_SYS_ROOT done popd From 8dfd57b411674570b6a1fe4046c2f3d33a6d0f49 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 30 Aug 2024 00:49:33 -0700 Subject: [PATCH 130/186] Clean up rust unused warnings. --- rust/lib/voyageurs/src/listener.rs | 1 + yunq/rust/src/codegen.rs | 56 ++++++++++++++++++++++-------- yunq/rust/src/parser.rs | 2 +- 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs index 78a4f4a..3f82095 100644 --- a/rust/lib/voyageurs/src/listener.rs +++ b/rust/lib/voyageurs/src/listener.rs @@ -9,6 +9,7 @@ use mammoth::thread::Thread; use mammoth::zion::ZError; #[repr(u8)] +#[allow(dead_code)] #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] enum Keycode { UnknownKeycode = 0x0, diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 00d2a64..53560a6 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -413,33 +413,59 @@ fn generate_interface(interface: &Interface) -> TokenStream { } } +fn any_strings(ast: &Vec) -> bool { + ast.iter() + .filter_map(|decl| match decl { + Decl::Message(m) => Some(m), + _ => None, + }) + .flat_map(|message| message.fields.iter()) + .any(|field| field.field_type.inner_type == Type::String) +} + +fn any_interfaces(ast: &Vec) -> bool { + ast.iter().any(|decl| match decl { + Decl::Interface(_) => true, + _ => false, + }) +} + pub fn generate_code(ast: &Vec) -> String { + let str_imports = if any_strings(ast) { + quote! { + use alloc::string::String; + use alloc::string::ToString; + } + } else { + quote! {} + }; + + let interface_imports = if any_interfaces(ast) { + quote! { + use alloc::boxed::Box; + use core::ffi::c_void; + use mammoth::cap::Capability; + use mammoth::syscall; + use mammoth::thread; + use yunq::server::YunqServer; + } + } else { + quote! {} + }; + let prelude = quote! { extern crate alloc; - use alloc::string::String; - use alloc::string::ToString; use alloc::vec::Vec; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; use yunq::ByteBuffer; use yunq::YunqMessage; + #str_imports - // Used only by modules with an interface. - #[allow(unused_imports)] - use alloc::boxed::Box; - #[allow(unused_imports)] - use core::ffi::c_void; - #[allow(unused_imports)] - use mammoth::cap::Capability; - #[allow(unused_imports)] - use mammoth::syscall; - #[allow(unused_imports)] - use mammoth::thread; - #[allow(unused_imports)] - use yunq::server::YunqServer; + #interface_imports }; diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index 07841f8..fc9ac19 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -6,7 +6,7 @@ use std::fmt::Display; use crate::lexer::Token; use crate::lexer::TokenType; -#[derive(Clone)] +#[derive(Clone, PartialEq)] pub enum Type { U64, I64, From 67546664ed34414fbd16d799c117147997c56e0a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 30 Aug 2024 17:09:27 -0700 Subject: [PATCH 131/186] Move to bitfield structs for AHCI info. --- rust/.cargo/config.toml | 1 + rust/Cargo.lock | 12 ++ rust/sys/denali/Cargo.toml | 1 + rust/sys/denali/src/ahci/controller.rs | 190 ++++++++++++++++++++++++- rust/sys/denali/src/bin/denali.rs | 1 + 5 files changed, 202 insertions(+), 3 deletions(-) diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml index 6e70044..c2174c1 100644 --- a/rust/.cargo/config.toml +++ b/rust/.cargo/config.toml @@ -7,3 +7,4 @@ target = "x86_64-acadia-os.json" [alias] test_pc = "test --target=x86_64-unknown-linux-gnu -Z build-std=std --lib" + diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c7d4f7b..e2a667e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -8,6 +8,17 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +[[package]] +name = "bitfield-struct" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de05f8756f1c68937349406d4632ae96ae35901019b5e59c508d9c38c64715fb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "convert_case" version = "0.6.0" @@ -21,6 +32,7 @@ dependencies = [ name = "denali" version = "0.1.0" dependencies = [ + "bitfield-struct", "mammoth", "yellowstone-yunq", "yunq", diff --git a/rust/sys/denali/Cargo.toml b/rust/sys/denali/Cargo.toml index 6cb7992..d618354 100644 --- a/rust/sys/denali/Cargo.toml +++ b/rust/sys/denali/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +bitfield-struct = "0.8.0" mammoth = { path = "../../lib/mammoth" } yunq = {path = "../../lib/yunq"} diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index cf02c60..abde094 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,5 +1,7 @@ use mammoth::mem::MemoryRegion; +use bitfield_struct::bitfield; + #[repr(C, packed)] pub struct PciDeviceHeader { pub vendor_id: u16, @@ -16,24 +18,195 @@ pub struct PciDeviceHeader { pub bist: u8, pub bars: [u32; 5], pub abar: u32, - pub reserved0: u32, + __: u32, pub subsystem_id: u32, pub expansion_rom: u16, pub cap_ptr: u8, - pub reserved1: [u8; 7], + ___: [u8; 7], pub interrupt_line: u8, pub interrupt_pin: u8, pub min_grant: u8, pub max_latency: u8, } +const fn increment(val: u8) -> u8 { + val + 1 +} + +#[derive(Debug, PartialEq, Eq)] +#[repr(u8)] +enum InterfaceSpeedSupport { + Reserved = 0b0000, + // 1.5 Gbps + Gen1 = 0b0001, + // 3 Gbps + Gen2 = 0b0010, + // 6 Gbps + Gen3 = 0b0011, + Unknown = 0b1111, +} + +impl InterfaceSpeedSupport { + const fn from_bits(value: u8) -> Self { + match value { + 0b0000 => Self::Reserved, + 0b0001 => Self::Gen1, + 0b0010 => Self::Gen2, + 0b0011 => Self::Gen3, + _ => Self::Unknown, + } + } +} + +#[bitfield(u32)] +pub struct AhciCapabilities { + #[bits(5, access = RO, from = increment)] + num_ports: u8, + + #[bits(access = RO)] + supports_external_sata: bool, + + #[bits(access = RO)] + enclosure_management_supported: bool, + + #[bits(access = RO)] + command_completed_coalescing_supported: bool, + + #[bits(5, access = RO, from = increment)] + num_commands: u8, + + #[bits(access = RO)] + partial_state_capable: bool, + + #[bits(access = RO)] + slumber_state_capable: bool, + + #[bits(access = RO)] + pio_multiple_drq_block: bool, + + #[bits(access = RO)] + fis_based_switching_supported: bool, + + #[bits(access = RO)] + supports_port_multiplier: bool, + + #[bits(access = RO)] + supports_ahci_mode_only: bool, + + __: bool, + + #[bits(4, access = RO)] + interface_speed_support: InterfaceSpeedSupport, + + #[bits(access = RO)] + supports_command_list_override: bool, + + #[bits(access = RO)] + supports_activity_led: bool, + + #[bits(access = RO)] + supports_aggressive_link_power_management: bool, + + #[bits(access = RO)] + supports_staggered_spin_up: bool, + + #[bits(access = RO)] + supports_mechanical_presence_switch: bool, + + #[bits(access = RO)] + supports_snotification_register: bool, + + #[bits(access = RO)] + supports_native_command_queueing: bool, + + #[bits(access = RO)] + supports_64_bit_addressing: bool, +} + +#[bitfield(u32)] +pub struct AhciGlobalControl { + hba_reset: bool, + interrupt_enable: bool, + + #[bits(access = RO)] + msi_revert_to_single_message: bool, + + #[bits(28)] + __: u32, + + ahci_enable: bool, +} + +#[bitfield(u32)] +pub struct AhciCapabilitiesExtended { + #[bits(access = RO)] + bios_os_handoff: bool, + + #[bits(access = RO)] + nvmhci_present: bool, + + #[bits(access = RO)] + automatic_partial_to_slumber_transitions: bool, + + #[bits(access = RO)] + supports_device_sleep: bool, + + #[bits(access = RO)] + supports_aggressive_device_sleep_management: bool, + + #[bits(27)] + __: u32, +} + +#[bitfield(u32)] +pub struct AhciBiosHandoffControl { + bios_owned_semaphore: bool, + os_owned_semaphore: bool, + smi_on_os_ownership_change_enable: bool, + os_ownership_change: bool, + bios_busy: bool, + + #[bits(27)] + __: u32, +} + +#[derive(Debug)] +#[repr(C, packed)] +pub struct AhciHba { + pub capabilities: AhciCapabilities, + global_host_control: AhciGlobalControl, + interrupt_status: u32, + port_implemented: u32, + version: u32, + ccc_ctl: u32, // 0x14, Command completion coalescing control + ccc_pts: u32, // 0x18, Command completion coalescing ports + em_loc: u32, // 0x1C, Enclosure management location + em_ctl: u32, // 0x20, Enclosure management control + capabilities_ext: AhciCapabilitiesExtended, + bohc: AhciBiosHandoffControl, +} + pub struct AhciController { pci_memory: MemoryRegion, + hba_memory: MemoryRegion, } impl AhciController { pub fn new(pci_memory: MemoryRegion) -> Self { - Self { pci_memory } + let pci_device_header = unsafe { + pci_memory + .mut_slice::() + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + }; + let hba_memory = + MemoryRegion::direct_physical(pci_device_header.abar as u64, 0x1100).unwrap(); + Self { + pci_memory, + hba_memory, + } } pub fn pci_header(&self) -> &mut PciDeviceHeader { @@ -46,4 +219,15 @@ impl AhciController { .unwrap() } } + + pub fn ahci_hba(&self) -> &mut AhciHba { + unsafe { + self.hba_memory + .mut_slice::() + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + } + } } diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index b685b5d..b4860f6 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -25,5 +25,6 @@ extern "C" fn main() -> z_err_t { ); mammoth::debug!("AHCI ABAR {:#x}", ahci_controller.pci_header().abar as u64); + mammoth::debug!("AHCI Capabilities: {:?}", ahci_controller.ahci_hba()); 0 } From 7d4c882f2ba57436e19b3688f1e44ba2b005e8ab Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 30 Aug 2024 23:45:56 -0700 Subject: [PATCH 132/186] [Denali] Added AHCI Port HBA Definitions. --- rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/ahci/port.rs | 397 +++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 rust/sys/denali/src/ahci/port.rs diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index db456be..de3958b 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -1,3 +1,4 @@ mod controller; +mod port; pub use controller::AhciController; diff --git a/rust/sys/denali/src/ahci/port.rs b/rust/sys/denali/src/ahci/port.rs new file mode 100644 index 0000000..7b1e10e --- /dev/null +++ b/rust/sys/denali/src/ahci/port.rs @@ -0,0 +1,397 @@ +#[bitfield(u32)] +struct AhciPortInterruptStatus { + device_to_host_register_fis_interrupt: bool, + pio_setup_fis_interrupt: bool, + dma_setup_fis_interrupt: bool, + set_device_bits_interrupt: bool, + #[bits(access = RO)] + unknown_fis_interrupt: bool, + descriptor_prossed: bool, + #[bits(access = RO)] + port_connect_change_status: bool, + device_mechanical_presence_status: bool, + + #[bits(14)] + __: u32, + + #[bits(access = RO)] + phy_rdy_change_status: bool, + incorrect_port_multiplier_status: bool, + overflow_status: bool, + + __: bool, + interface_non_fatal_error_status: bool, + interface_fatal_error_status: bool, + host_bus_data_error_status: bool, + host_bus_fatal_error_status: bool, + task_file_error_status: bool, + cold_port_detect_status: bool, +} + +#[bitfield(u32)] +struct AhciPortInterruptEnable { + device_to_host_register_fis_enable: bool, + pio_setup_fis_enable: bool, + dma_setup_fis_enable: bool, + set_device_bits_fis_enable: bool, + unknown_fis_enable: bool, + descriptor_processed_enable: bool, + port_change_enable: bool, + device_mechanical_presence_enable: bool, + + #[bits(14)] + __: u32, + + phy_rdy_change_enable: bool, + incorrect_port_multiplier_enable: bool, + overflow_enable: bool, + + __: bool, + + interface_non_fatal_error_enable: bool, + interface_fatal_error_enable: bool, + host_bus_data_error_enable: bool, + host_bust_fatal_error_enable: bool, + task_file_error_enable: bool, + cold_presence_detect_enable: bool, +} + +#[repr(u8)] +#[derive(Debug)] +enum InterfaceCommunicationControl { + NoOpOrIdle = 0x0, + Active = 0x1, + Partial = 0x2, + Slumber = 0x6, + DevSleep = 0x8, + Unknown = 0xF, +} + +impl InterfaceCommunicationControl { + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoOpOrIdle, + 0x1 => Self::Active, + 0x2 => Self::Partial, + 0x6 => Self::Slumber, + 0x8 => Self::DevSleep, + _ => Self::Unknown, + } + } + + const fn into_bits(self) -> u8 { + self as _ + } +} + +#[bitfield(u32)] +struct AhciPortCommandAndStatus { + start: bool, + spin_up_device: bool, + power_on_device: bool, + command_list_overide: bool, + fis_recieve_enable: bool, + + #[bits(3)] + __: u8, + + #[bits(5, access = RO)] + current_command_slot: u8, + + #[bits(access = RO)] + mechanical_presence_switch_state: bool, + #[bits(access = RO)] + fis_receive_running: bool, + #[bits(access = RO)] + command_list_running: bool, + #[bits(access = RO)] + cold_presence_state: bool, + port_multipler_attached: bool, + #[bits(access = RO)] + hot_plug_capable_port: bool, + #[bits(access = RO)] + mechanical_presence_switch_attached_to_port: bool, + #[bits(access = RO)] + cold_presence_detection: bool, + #[bits(access = RO)] + external_sata_port: bool, + #[bits(access = RO)] + fis_base_switch_capable: bool, + automatic_partial_to_slumber_transitions_enable: bool, + device_is_atapi: bool, + drive_led_on_atapi_enable: bool, + aggressive_power_link_management_enable: bool, + aggressive_slumber_partial: bool, + + #[bits(4)] + interface_communication_control: InterfaceCommunicationControl, +} + +#[bitfield(u32)] +struct AhciPortTaskFileData { + #[bits(access = RO)] + err_status: bool, + #[bits(2, access = RO)] + command_specific_status_lo: u8, + #[bits(access = RO)] + data_transfer_requested: bool, + #[bits(3, access = RO)] + command_specific_status_hi: u8, + #[bits(access = RO)] + busy_status: bool, + + #[bits(8, access = RO)] + error: u8, + + #[bits(16)] + __: u16, +} + +#[derive(Debug)] +#[repr(u8)] +enum AhciDeviceDetection { + NoDevice = 0x0, + NoCommunication = 0x1, + CommunicationEstablished = 0x3, + OfflineMode = 0x4, + Unknown = 0xF, +} + +impl AhciDeviceDetection { + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoDevice, + 0x1 => Self::NoCommunication, + 0x3 => Self::CommunicationEstablished, + 0x4 => Self::OfflineMode, + _ => Self::Unknown, + } + } +} + +#[derive(Debug)] +#[repr(u8)] +enum AhciCurrentInterfaceSpeed { + NoDevice = 0x0, + Gen1 = 0x1, + Gen2 = 0x2, + Gen3 = 0x3, + Unknown = 0xF, +} + +impl AhciCurrentInterfaceSpeed { + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoDevice, + 0x1 => Self::Gen1, + 0x2 => Self::Gen2, + 0x3 => Self::Gen3, + _ => Self::Unknown, + } + } +} + +#[derive(Debug)] +#[repr(u8)] +enum AhciInterfacePowerManagement { + NoDevice = 0x0, + Active = 0x1, + PartialPower = 0x2, + Slumber = 0x6, + DevSleep = 0x8, + Unknown = 0xF, +} + +impl AhciInterfacePowerManagement { + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoDevice, + 0x1 => Self::Active, + 0x2 => Self::PartialPower, + 0x6 => Self::Slumber, + 0x8 => Self::DevSleep, + _ => Self::Unknown, + } + } +} + +#[bitfield(u32)] +struct AhciSataStatus { + #[bits(4, access = RO)] + device_detection: AhciDeviceDetection, + + #[bits(4, access = RO)] + current_interface_speed: AhciCurrentInterfaceSpeed, + + #[bits(4, access = RO)] + interface_power_management: AhciInterfacePowerManagement, + + #[bits(20)] + __: u32, +} + +#[derive(Debug)] +#[repr(u8)] +enum AhciDeviceDetectionInitialization { + NoDevice = 0x0, + PerformInterfaceCommunicationInitializationSequence = 0x1, + DisableSata = 0x4, + Unknown = 0xF, +} + +impl AhciDeviceDetectionInitialization { + const fn into_bits(self) -> u8 { + self as _ + } + + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoDevice, + 0x1 => Self::PerformInterfaceCommunicationInitializationSequence, + 0x4 => Self::DisableSata, + _ => Self::Unknown, + } + } +} + +#[derive(Debug)] +#[repr(u8)] +enum AhciSpeedAllowed { + NoRestrictions = 0x0, + LimitGen1 = 0x1, + LimitGen2 = 0x2, + LimitGen3 = 0x3, + Unknown = 0xF, +} + +impl AhciSpeedAllowed { + const fn into_bits(self) -> u8 { + self as _ + } + + const fn from_bits(value: u8) -> Self { + match value { + 0x0 => Self::NoRestrictions, + 0x1 => Self::LimitGen1, + 0x2 => Self::LimitGen2, + 0x3 => Self::LimitGen3, + _ => Self::Unknown, + } + } +} + +#[bitfield(u32)] +struct AhciSataControl { + #[bits(4)] + device_detection_initialization: AhciDeviceDetectionInitialization, + + #[bits(4)] + speed_allowed: AhciSpeedAllowed, + + partial_transition_disabled: bool, + slumber_transition_disabled: bool, + devsleep_transition_disabled: bool, + + __: bool, + + #[bits(20)] + __: u32, +} + +#[bitfield(u32)] +struct AhciSataError { + recovered_data_integrity_error: bool, + recovered_communications_error: bool, + + #[bits(6)] + __: u8, + + transient_data_integrity_error: bool, + persisten_communication_or_data_integrity_error: bool, + protocol_error: bool, + internal_error: bool, + + #[bits(4)] + __: u8, + + phy_ready_change: bool, + phy_internal_error: bool, + comm_wake: bool, + decode_error: bool, + __: bool, + crc_error: bool, + handshake_error: bool, + link_sequence_error: bool, + transport_state_transition_error: bool, + uknown_fis_type: bool, + exchanged: bool, + + #[bits(5)] + __: u8, +} + +#[bitfield(u32)] +struct AhciFisBasedSwitchingControl { + enable: bool, + device_error_clear: bool, + + #[bits(access = RO)] + single_device_error: bool, + + #[bits(5)] + __: u8, + + #[bits(4)] + device_to_issue: u8, + + #[bits(4, access = RO)] + active_device_optimization: u8, + + #[bits(4, access = RO)] + device_with_error: u8, + + #[bits(12)] + __: u16, +} + +#[bitfield(u32)] +struct AhciDeviceSleep { + aggressive_device_sleep_enable: bool, + + #[bits(access = RO)] + device_sleep_present: bool, + + device_sleep_exit_timeout: u8, + + #[bits(5)] + minimum_device_sleep_assertion_time: u8, + + #[bits(10)] + device_sleep_idle_timeout: u16, + + #[bits(4)] + dito_multiplier: u8, + + #[bits(3)] + __: u8, +} + +#[repr(C, packed)] +struct AhciPortHba { + command_list_base: u64, + fis_base: u64, + interrupt_status: AhciPortInterruptStatus, + interrupt_enable: AhciPortInterruptEnable, + command: AhciPortCommandAndStatus, + __: u32, + task_file_data: AhciPortTaskFileData, + signature: u32, + sata_status: AhciSataStatus, + sata_control: AhciSataControl, + sata_error: AhciSataError, + sata_active: u32, + command_issue: u32, + sata_notification: u32, + fis_based_switching_ctl: AhciFisBasedSwitchingControl, + device_sleep: AhciDeviceSleep, +} From df79233bbbc122b1dc47c76094a5bdd6920f1105 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 10 Sep 2024 01:12:32 -0700 Subject: [PATCH 133/186] [Denali] Reset HBA and iterate over ports. --- rust/lib/mammoth/src/port.rs | 4 + rust/lib/mammoth/src/syscall.rs | 12 ++ rust/sys/denali/src/ahci/controller.rs | 272 ++++++++++--------------- rust/sys/denali/src/ahci/hba.rs | 158 ++++++++++++++ rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/ahci/port.rs | 4 +- 6 files changed, 289 insertions(+), 162 deletions(-) create mode 100644 rust/sys/denali/src/ahci/hba.rs diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs index 8a86518..1972fcd 100644 --- a/rust/lib/mammoth/src/port.rs +++ b/rust/lib/mammoth/src/port.rs @@ -13,6 +13,10 @@ impl PortServer { }) } + pub fn from_cap(port_cap: Capability) -> Self { + Self { port_cap } + } + pub fn create_client_cap(&self) -> Result { self.port_cap .duplicate(!kZionPerm_Read) diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 5b83756..cfec2f1 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -295,6 +295,18 @@ pub fn port_poll( Ok((num_bytes, num_caps)) } +pub fn register_irq(irq_num: u64) -> Result { + let mut port_cap: z_cap_t = 0; + syscall( + zion::kZionIrqRegister, + &zion::ZIrqRegisterReq { + irq_num, + port_cap: &mut port_cap, + }, + )?; + Ok(Capability::take(port_cap)) +} + pub fn endpoint_create() -> Result { let mut endpoint_cap: z_cap_t = 0; syscall( diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index abde094..71bdc70 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,7 +1,11 @@ -use mammoth::mem::MemoryRegion; +use alloc::boxed::Box; +use core::{ffi::c_void, mem::MaybeUninit}; -use bitfield_struct::bitfield; +use mammoth::{mem::MemoryRegion, thread::Thread, zion::ZError}; +use super::{hba::AhciHba, port::AhciPortHba}; + +#[derive(Debug)] #[repr(C, packed)] pub struct PciDeviceHeader { pub vendor_id: u16, @@ -20,7 +24,7 @@ pub struct PciDeviceHeader { pub abar: u32, __: u32, pub subsystem_id: u32, - pub expansion_rom: u16, + pub expansion_rom: u32, pub cap_ptr: u8, ___: [u8; 7], pub interrupt_line: u8, @@ -29,166 +33,12 @@ pub struct PciDeviceHeader { pub max_latency: u8, } -const fn increment(val: u8) -> u8 { - val + 1 -} - -#[derive(Debug, PartialEq, Eq)] -#[repr(u8)] -enum InterfaceSpeedSupport { - Reserved = 0b0000, - // 1.5 Gbps - Gen1 = 0b0001, - // 3 Gbps - Gen2 = 0b0010, - // 6 Gbps - Gen3 = 0b0011, - Unknown = 0b1111, -} - -impl InterfaceSpeedSupport { - const fn from_bits(value: u8) -> Self { - match value { - 0b0000 => Self::Reserved, - 0b0001 => Self::Gen1, - 0b0010 => Self::Gen2, - 0b0011 => Self::Gen3, - _ => Self::Unknown, - } - } -} - -#[bitfield(u32)] -pub struct AhciCapabilities { - #[bits(5, access = RO, from = increment)] - num_ports: u8, - - #[bits(access = RO)] - supports_external_sata: bool, - - #[bits(access = RO)] - enclosure_management_supported: bool, - - #[bits(access = RO)] - command_completed_coalescing_supported: bool, - - #[bits(5, access = RO, from = increment)] - num_commands: u8, - - #[bits(access = RO)] - partial_state_capable: bool, - - #[bits(access = RO)] - slumber_state_capable: bool, - - #[bits(access = RO)] - pio_multiple_drq_block: bool, - - #[bits(access = RO)] - fis_based_switching_supported: bool, - - #[bits(access = RO)] - supports_port_multiplier: bool, - - #[bits(access = RO)] - supports_ahci_mode_only: bool, - - __: bool, - - #[bits(4, access = RO)] - interface_speed_support: InterfaceSpeedSupport, - - #[bits(access = RO)] - supports_command_list_override: bool, - - #[bits(access = RO)] - supports_activity_led: bool, - - #[bits(access = RO)] - supports_aggressive_link_power_management: bool, - - #[bits(access = RO)] - supports_staggered_spin_up: bool, - - #[bits(access = RO)] - supports_mechanical_presence_switch: bool, - - #[bits(access = RO)] - supports_snotification_register: bool, - - #[bits(access = RO)] - supports_native_command_queueing: bool, - - #[bits(access = RO)] - supports_64_bit_addressing: bool, -} - -#[bitfield(u32)] -pub struct AhciGlobalControl { - hba_reset: bool, - interrupt_enable: bool, - - #[bits(access = RO)] - msi_revert_to_single_message: bool, - - #[bits(28)] - __: u32, - - ahci_enable: bool, -} - -#[bitfield(u32)] -pub struct AhciCapabilitiesExtended { - #[bits(access = RO)] - bios_os_handoff: bool, - - #[bits(access = RO)] - nvmhci_present: bool, - - #[bits(access = RO)] - automatic_partial_to_slumber_transitions: bool, - - #[bits(access = RO)] - supports_device_sleep: bool, - - #[bits(access = RO)] - supports_aggressive_device_sleep_management: bool, - - #[bits(27)] - __: u32, -} - -#[bitfield(u32)] -pub struct AhciBiosHandoffControl { - bios_owned_semaphore: bool, - os_owned_semaphore: bool, - smi_on_os_ownership_change_enable: bool, - os_ownership_change: bool, - bios_busy: bool, - - #[bits(27)] - __: u32, -} - -#[derive(Debug)] -#[repr(C, packed)] -pub struct AhciHba { - pub capabilities: AhciCapabilities, - global_host_control: AhciGlobalControl, - interrupt_status: u32, - port_implemented: u32, - version: u32, - ccc_ctl: u32, // 0x14, Command completion coalescing control - ccc_pts: u32, // 0x18, Command completion coalescing ports - em_loc: u32, // 0x1C, Enclosure management location - em_ctl: u32, // 0x20, Enclosure management control - capabilities_ext: AhciCapabilitiesExtended, - bohc: AhciBiosHandoffControl, -} - pub struct AhciController { pci_memory: MemoryRegion, hba_memory: MemoryRegion, + irq_port: Option, + irq_thread: Option>, + ports: [Option>; 32], } impl AhciController { @@ -203,9 +53,97 @@ impl AhciController { }; let hba_memory = MemoryRegion::direct_physical(pci_device_header.abar as u64, 0x1100).unwrap(); - Self { + let mut controller = Self { pci_memory, hba_memory, + irq_port: None, + irq_thread: None, + ports: [const { None }; 32], + }; + mammoth::debug!("{:?}", controller.pci_header()); + controller.init(); + controller + } + + fn init(&mut self) { + self.ahci_hba().global_host_control.with_hba_reset(true); + + loop { + if !self.ahci_hba().global_host_control.hba_reset() { + break; + } + } + + self.ahci_hba().global_host_control.with_ahci_enable(true); + + mammoth::syscall::thread_sleep(50).unwrap(); + + self.register_irq(); + + self.init_ports(); + } + + fn run_server(&self) -> Result, ZError> { + let thread_entry = |server_ptr: *const c_void| { + let server = unsafe { + (server_ptr as *mut Self) + .as_mut() + .expect("Failed to convert to server") + }; + server.irq_loop(); + }; + Thread::spawn( + thread_entry, + self as *const Self as *const core::ffi::c_void, + ) + } + + fn register_irq(&mut self) { + let irq_num = match self.pci_header().interrupt_pin { + 1 => mammoth::zion::kZIrqPci1, + 2 => mammoth::zion::kZIrqPci2, + 3 => mammoth::zion::kZIrqPci3, + 4 => mammoth::zion::kZIrqPci4, + _ => panic!( + "Unrecognized pci interrupt pin {}", + self.pci_header().interrupt_pin + ), + }; + self.irq_port = Some(mammoth::port::PortServer::from_cap( + mammoth::syscall::register_irq(irq_num).unwrap(), + )); + + self.irq_thread = Some(self.run_server().unwrap()); + + self.ahci_hba() + .global_host_control + .with_interrupt_enable(true); + } + + fn irq_loop(&self) {} + + fn init_ports(&mut self) { + for i in 0..(self.ahci_hba().capabilities.num_ports() as usize) { + let port_index = 1 << i; + if (self.ahci_hba().port_implemented & port_index) != port_index { + mammoth::debug!("Skipping port {}, not implemented", i); + continue; + } + + let port_offset: usize = 0x100 + (0x80 * i); + let port_size = size_of::(); + let port_limit = port_offset + port_size; + let port = unsafe { + self.hba_memory.mut_slice::()[port_offset..port_limit] + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + }; + + self.ports[i] = Some(PortController::new(port)); + self.ports[i].as_ref().unwrap().identify(); + mammoth::debug!("Identifying port {}", i); } } @@ -231,3 +169,15 @@ impl AhciController { } } } + +struct PortController<'a> { + ahci_port_hba: &'a AhciPortHba, +} + +impl<'a> PortController<'a> { + fn new(ahci_port_hba: &'a AhciPortHba) -> Self { + Self { ahci_port_hba } + } + + pub fn identify(&self) {} +} diff --git a/rust/sys/denali/src/ahci/hba.rs b/rust/sys/denali/src/ahci/hba.rs new file mode 100644 index 0000000..f9dbde9 --- /dev/null +++ b/rust/sys/denali/src/ahci/hba.rs @@ -0,0 +1,158 @@ +use bitfield_struct::bitfield; + +const fn increment(val: u8) -> u8 { + val + 1 +} + +#[derive(Debug, PartialEq, Eq)] +#[repr(u8)] +enum InterfaceSpeedSupport { + Reserved = 0b0000, + // 1.5 Gbps + Gen1 = 0b0001, + // 3 Gbps + Gen2 = 0b0010, + // 6 Gbps + Gen3 = 0b0011, + Unknown = 0b1111, +} + +impl InterfaceSpeedSupport { + const fn from_bits(value: u8) -> Self { + match value { + 0b0000 => Self::Reserved, + 0b0001 => Self::Gen1, + 0b0010 => Self::Gen2, + 0b0011 => Self::Gen3, + _ => Self::Unknown, + } + } +} + +#[bitfield(u32)] +pub struct AhciCapabilities { + #[bits(5, access = RO, from = increment)] + pub num_ports: u8, + + #[bits(access = RO)] + supports_external_sata: bool, + + #[bits(access = RO)] + enclosure_management_supported: bool, + + #[bits(access = RO)] + command_completed_coalescing_supported: bool, + + #[bits(5, access = RO, from = increment)] + num_commands: u8, + + #[bits(access = RO)] + partial_state_capable: bool, + + #[bits(access = RO)] + slumber_state_capable: bool, + + #[bits(access = RO)] + pio_multiple_drq_block: bool, + + #[bits(access = RO)] + fis_based_switching_supported: bool, + + #[bits(access = RO)] + supports_port_multiplier: bool, + + #[bits(access = RO)] + supports_ahci_mode_only: bool, + + __: bool, + + #[bits(4, access = RO)] + interface_speed_support: InterfaceSpeedSupport, + + #[bits(access = RO)] + supports_command_list_override: bool, + + #[bits(access = RO)] + supports_activity_led: bool, + + #[bits(access = RO)] + supports_aggressive_link_power_management: bool, + + #[bits(access = RO)] + supports_staggered_spin_up: bool, + + #[bits(access = RO)] + supports_mechanical_presence_switch: bool, + + #[bits(access = RO)] + supports_snotification_register: bool, + + #[bits(access = RO)] + supports_native_command_queueing: bool, + + #[bits(access = RO)] + supports_64_bit_addressing: bool, +} + +#[bitfield(u32)] +pub struct AhciGlobalControl { + pub hba_reset: bool, + pub interrupt_enable: bool, + + #[bits(access = RO)] + pub msi_revert_to_single_message: bool, + + #[bits(28)] + __: u32, + + pub ahci_enable: bool, +} + +#[bitfield(u32)] +pub struct AhciCapabilitiesExtended { + #[bits(access = RO)] + bios_os_handoff: bool, + + #[bits(access = RO)] + nvmhci_present: bool, + + #[bits(access = RO)] + automatic_partial_to_slumber_transitions: bool, + + #[bits(access = RO)] + supports_device_sleep: bool, + + #[bits(access = RO)] + supports_aggressive_device_sleep_management: bool, + + #[bits(27)] + __: u32, +} + +#[bitfield(u32)] +pub struct AhciBiosHandoffControl { + bios_owned_semaphore: bool, + os_owned_semaphore: bool, + smi_on_os_ownership_change_enable: bool, + os_ownership_change: bool, + bios_busy: bool, + + #[bits(27)] + __: u32, +} + +#[derive(Debug)] +#[repr(C)] +pub struct AhciHba { + pub capabilities: AhciCapabilities, + pub global_host_control: AhciGlobalControl, + pub interrupt_status: u32, + pub port_implemented: u32, + pub version: u32, + pub ccc_ctl: u32, // 0x14, Command completion coalescing control + pub ccc_pts: u32, // 0x18, Command completion coalescing ports + pub em_loc: u32, // 0x1C, Enclosure management location + pub em_ctl: u32, // 0x20, Enclosure management control + pub capabilities_ext: AhciCapabilitiesExtended, + pub bohc: AhciBiosHandoffControl, +} diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index de3958b..36a1d0f 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -1,4 +1,5 @@ mod controller; +mod hba; mod port; pub use controller::AhciController; diff --git a/rust/sys/denali/src/ahci/port.rs b/rust/sys/denali/src/ahci/port.rs index 7b1e10e..773bdde 100644 --- a/rust/sys/denali/src/ahci/port.rs +++ b/rust/sys/denali/src/ahci/port.rs @@ -1,3 +1,5 @@ +use bitfield_struct::bitfield; + #[bitfield(u32)] struct AhciPortInterruptStatus { device_to_host_register_fis_interrupt: bool, @@ -377,7 +379,7 @@ struct AhciDeviceSleep { } #[repr(C, packed)] -struct AhciPortHba { +pub struct AhciPortHba { command_list_base: u64, fis_base: u64, interrupt_status: AhciPortInterruptStatus, From d94f61511b64e9c7be8bf4e276660502b0ec81c6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 2 Oct 2024 23:59:50 -0700 Subject: [PATCH 134/186] [Denali] Interrupts working in rust. --- rust/lib/mammoth/src/mem.rs | 13 ++ rust/lib/mammoth/src/port.rs | 9 + rust/lib/mammoth/src/syscall.rs | 15 ++ rust/sys/denali/src/ahci/command.rs | 264 +++++++++++++++++++++++++ rust/sys/denali/src/ahci/controller.rs | 257 ++++++++++++++++++++++-- rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/ahci/port.rs | 214 ++++++++++---------- rust/sys/denali/src/bin/denali.rs | 4 +- 8 files changed, 654 insertions(+), 123 deletions(-) create mode 100644 rust/sys/denali/src/ahci/command.rs diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index cef5dd6..6e7817c 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -41,6 +41,19 @@ impl MemoryRegion { }) } + pub fn contiguous_physical(size: u64) -> Result<(Self, u64), ZError> { + let (mem_cap, paddr) = syscall::memory_object_contiguous_physical(size)?; + let virt_addr = syscall::address_space_map(&mem_cap)?; + Ok(( + Self { + mem_cap, + virt_addr, + size, + }, + paddr, + )) + } + pub fn from_cap(mem_cap: Capability) -> Result { let virt_addr = syscall::address_space_map(&mem_cap)?; let size = syscall::memory_object_inspect(&mem_cap)?; diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs index 1972fcd..34bddb1 100644 --- a/rust/lib/mammoth/src/port.rs +++ b/rust/lib/mammoth/src/port.rs @@ -40,6 +40,15 @@ impl PortServer { Ok(u16::from_le_bytes(bytes)) } + + pub fn recv_null(&self) -> Result<(), ZError> { + let mut caps: [z_cap_t; 0] = []; + let mut bytes: [u8; 0] = []; + + port_recv(&self.port_cap, &mut bytes, &mut caps)?; + + Ok(()) + } } pub struct PortClient { diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index cfec2f1..565a2c1 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -158,6 +158,21 @@ pub fn memory_object_direct_physical(paddr: u64, size: u64) -> Result Result<(Capability, u64), ZError> { + let mut vmmo_cap = 0; + let mut paddr = 0; + syscall( + zion::kZionMemoryObjectCreateContiguous, + &zion::ZMemoryObjectCreateContiguousReq { + size, + paddr: &mut paddr, + vmmo_cap: &mut vmmo_cap, + }, + )?; + + Ok((Capability::take(vmmo_cap), paddr)) +} + pub fn memory_object_inspect(mem_cap: &Capability) -> Result { let mut mem_size = 0; syscall( diff --git a/rust/sys/denali/src/ahci/command.rs b/rust/sys/denali/src/ahci/command.rs new file mode 100644 index 0000000..5870587 --- /dev/null +++ b/rust/sys/denali/src/ahci/command.rs @@ -0,0 +1,264 @@ +#[derive(Debug)] +#[repr(C, packed)] +pub struct CommandHeader { + pub command: u16, + pub prd_table_length: u16, + pub prd_byte_count: u32, + pub command_table_base_addr: u64, + __: u64, + ___: u64, +} + +pub type CommandList = [CommandHeader; 32]; + +#[allow(dead_code)] +#[derive(Clone, Copy, Debug, PartialEq)] +#[repr(u8)] +pub enum FisType { + RegisterHostToDevice = 0x27, // Register FIS - host to device + RegisterDeviceToHost = 0x34, // Register FIS - device to host + DmaActivate = 0x39, // DMA activate FIS - device to host + DmaSetup = 0x41, // DMA setup FIS - bidirectional + Data = 0x46, // Data FIS - bidirectional + BistActivate = 0x58, // BIST activate FIS - bidirectional + PioSetup = 0x5F, // PIO setup FIS - device to host + SetDeviceBits = 0xA1, // Set device bits FIS - device to host + Unknown = 0x0, +} + +#[allow(dead_code)] +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct DmaFis { + // DWORD 0 + fis_type: u8, // FIS_TYPE_DMA_SETUP + pmport_dia: u8, // Port multiplier + + __: u16, // Reserved + + // DWORD 1&2 + dma_buffer_id: u64, // DMA Buffer Identifier. Used to Identify DMA buffer + // in host memory. SATA Spec says host specific and not + // in Spec. Trying AHCI spec might work. + + // DWORD 3 + ___: u32, + + // DWORD 4 + dma_buffer_offest: u32, // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + transfer_count: u32, // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + ____: u32, // Reserved +} + +const _: () = assert!(size_of::() == 28); + +#[allow(dead_code)] +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct PioSetupFis { + // DWORD 0 + fis_type: FisType, // FIS_TYPE_PIO_SETUP + + pmport_di: u8, // Port multiplier + + status: u8, // Status register + error: u8, // Error register + + // DWORD 1 + lba0: u8, // LBA low register, 7:0 + lba1: u8, // LBA mid register, 15:8 + lba2: u8, // LBA high register, 23:16 + device: u8, // Device register + + // DWORD 2 + lba3: u8, // LBA register, 31:24 + lba4: u8, // LBA register, 39:32 + lba5: u8, // LBA register, 47:40 + __: u8, // Reserved + + // DWORD 3 + countl: u8, // Count register, 7:0 + counth: u8, // Count register, 15:8 + ___: u8, // Reserved + e_status: u8, // New value of status register + + // DWORD 4 + tc: u16, // Transfer count + ____: u16, // Reserved +} + +const _: () = assert!(size_of::() == 20); + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum SataCommand { + IdentifyDevice = 0xEC, + DmaReadExt = 0x25, +} + +#[allow(dead_code)] // Read by memory. +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct HostToDeviceRegisterFis { + fis_type: FisType, // FIS_TYPE_REG_H2D + pmp_and_c: u8, + command: SataCommand, // Command register + featurel: u8, // Feature register, 7:0 + + // DWORD 1 + lba0: u8, // LBA low register, 7:0 + lba1: u8, // LBA mid register, 15:8 + lba2: u8, // LBA high register, 23:16 + device: u8, // Device register + + // DWORD 2 + lba3: u8, // LBA register, 31:24 + lba4: u8, // LBA register, 39:32 + lba5: u8, // LBA register, 47:40 + featureh: u8, // Feature register, 15:8 + + // DWORD 3 + count: u16, + icc: u8, // Isochronous command completion + control: u8, // Control register + + // DWORD 4 + reserved: u32, // Reserved +} + +const _: () = assert!(size_of::() == 20); + +impl HostToDeviceRegisterFis { + pub fn new_command(command: SataCommand, lba: u64, sectors: u16) -> Self { + Self { + fis_type: FisType::RegisterHostToDevice, + pmp_and_c: 0x80, // Set command bit + command, + featurel: 0, + + lba0: (lba & 0xFF) as u8, + lba1: ((lba >> 8) & 0xFF) as u8, + lba2: ((lba >> 16) & 0xFF) as u8, + device: (1 << 6), // ATA LBA Mode + + lba3: ((lba >> 24) & 0xFF) as u8, + lba4: ((lba >> 32) & 0xFF) as u8, + lba5: ((lba >> 40) & 0xFF) as u8, + featureh: 0, + + count: sectors, + icc: 0, + control: 0, + + reserved: 0, + } + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct DeviceToHostRegisterFis { + // DWORD 0 + pub fis_type: FisType, // FIS_TYPE_REG_D2H + + pub pmport_and_i: u8, + + pub status: u8, // Status register + pub error: u8, // Error register + + // DWORD 1 + pub lba0: u8, // LBA low register, 7:0 + pub lba1: u8, // LBA mid register, 15:8 + pub lba2: u8, // LBA high register, 23:16 + pub device: u8, // Device register + + // DWORD 2 + pub lba3: u8, // LBA register, 31:24 + pub lba4: u8, // LBA register, 39:32 + pub lba5: u8, // LBA register, 47:40 + __: u8, + + // DWORD 3 + pub count: u16, + ___: u16, + + ____: u32, +} + +const _: () = assert!(size_of::() == 20); + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct SetDeviceBitsFis { + fis_type: FisType, + pmport_and_i: u8, + status: u8, + error: u8, + reserved: u32, +} + +const _: () = assert!(size_of::() == 8); + +#[derive(Debug)] +#[repr(C, packed)] +pub struct ReceivedFis { + pub dma_fis: DmaFis, + __: u32, + + pub pio_set_fis: PioSetupFis, + ___: [u8; 12], + + pub device_to_host_register_fis: DeviceToHostRegisterFis, + ____: u32, + + pub set_device_bits_fis: SetDeviceBitsFis, + + pub unknown_fis: [u8; 64], +} + +const _: () = assert!(size_of::() == 0xA0); + +#[derive(Copy, Clone)] +#[repr(C)] +pub union CommandFis { + pub host_to_device: HostToDeviceRegisterFis, + + // Used to ensure the repr is + pub __: [u8; 64], +} + +const _: () = assert!(size_of::() == 0x40); + +impl core::fmt::Debug for CommandFis { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_fmt(format_args!("{:?}", unsafe { self.host_to_device })) + } +} + +#[derive(Copy, Clone, Debug)] +#[repr(C, packed)] +pub struct PhysicalRegionDescriptor { + pub region_address: u64, + __: u32, + // bit 0 must be one. + // 21:0 is byte count + // 31 is Interrupt on Completion + pub byte_count: u32, +} + +const _: () = assert!(size_of::() == 0x10); + +#[derive(Debug)] +#[repr(C, packed)] +pub struct CommandTable { + pub command_fis: CommandFis, + pub atapi_command: [u8; 0x10], + __: [u8; 0x30], + pub prdt: [PhysicalRegionDescriptor; 8], +} + +const _: () = assert!(size_of::() == 0x100); diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 71bdc70..b0c3c3e 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,9 +1,21 @@ use alloc::boxed::Box; -use core::{ffi::c_void, mem::MaybeUninit}; +use alloc::rc::Rc; +use core::ffi::c_void; use mammoth::{mem::MemoryRegion, thread::Thread, zion::ZError}; -use super::{hba::AhciHba, port::AhciPortHba}; +use crate::ahci::command::FisType; +use crate::ahci::port::{ + AhciDeviceDetection, AhciInterfacePowerManagement, AhciPortInterruptStatus, +}; + +use super::command::{ + CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand, +}; +use super::{ + hba::AhciHba, + port::{AhciPortHba, AhciPortInterruptEnable, AhciSataError}, +}; #[derive(Debug)] #[repr(C, packed)] @@ -60,13 +72,18 @@ impl AhciController { irq_thread: None, ports: [const { None }; 32], }; - mammoth::debug!("{:?}", controller.pci_header()); controller.init(); controller } + pub fn join(&self) -> Result<(), ZError> { + self.irq_thread.as_ref().unwrap().join() + } + fn init(&mut self) { - self.ahci_hba().global_host_control.with_hba_reset(true); + self.ahci_hba().global_host_control.set_hba_reset(true); + + mammoth::syscall::thread_sleep(50).unwrap(); loop { if !self.ahci_hba().global_host_control.hba_reset() { @@ -74,13 +91,13 @@ impl AhciController { } } - self.ahci_hba().global_host_control.with_ahci_enable(true); + self.ahci_hba().global_host_control.set_ahci_enable(true); mammoth::syscall::thread_sleep(50).unwrap(); self.register_irq(); - self.init_ports(); + self.init_ports().unwrap(); } fn run_server(&self) -> Result, ZError> { @@ -117,12 +134,26 @@ impl AhciController { self.ahci_hba() .global_host_control - .with_interrupt_enable(true); + .set_interrupt_enable(true); } - fn irq_loop(&self) {} + fn irq_loop(&mut self) { + loop { + self.irq_port.as_ref().unwrap().recv_null().unwrap(); - fn init_ports(&mut self) { + for i in 0..self.ahci_hba().capabilities.num_ports() { + let int_offset = 1 << i; + if (self.ahci_hba().interrupt_status & int_offset) == int_offset { + if let Some(port) = &mut self.ports[i as usize] { + port.handle_interrupt(); + self.ahci_hba().interrupt_status &= !int_offset; + } + } + } + } + } + + fn init_ports(&mut self) -> Result<(), ZError> { for i in 0..(self.ahci_hba().capabilities.num_ports() as usize) { let port_index = 1 << i; if (self.ahci_hba().port_implemented & port_index) != port_index { @@ -141,10 +172,23 @@ impl AhciController { .unwrap() }; - self.ports[i] = Some(PortController::new(port)); - self.ports[i].as_ref().unwrap().identify(); - mammoth::debug!("Identifying port {}", i); + let sata_status = port.sata_status; + if (sata_status.device_detection() != AhciDeviceDetection::CommunicationEstablished) + || (sata_status.interface_power_management() + != AhciInterfacePowerManagement::Active) + { + mammoth::debug!( + "Skipping port {}, no communcation. Status: {:?}", + i, + sata_status + ); + continue; + } + + self.ports[i] = Some(PortController::new(port)?); + self.ports[i].as_mut().unwrap().identify()?; } + Ok(()) } pub fn pci_header(&self) -> &mut PciDeviceHeader { @@ -170,14 +214,195 @@ impl AhciController { } } +struct Command { + command: SataCommand, + lba: u64, + sector_cnt: u16, + paddr: u64, + + #[allow(dead_code)] // We need to own this even if we never access it. + memory_region: MemoryRegion, +} + +impl Command { + pub fn identify() -> Result { + let (memory_region, paddr) = MemoryRegion::contiguous_physical(512)?; + + Ok(Self { + command: SataCommand::IdentifyDevice, + lba: 0, + sector_cnt: 1, + paddr, + memory_region, + }) + } +} + +impl From<&Command> for HostToDeviceRegisterFis { + fn from(val: &Command) -> Self { + HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt) + } +} + struct PortController<'a> { - ahci_port_hba: &'a AhciPortHba, + ahci_port_hba: &'a mut AhciPortHba, + command_slots: [Option>; 32], + command_structures: MemoryRegion, + command_paddr: u64, } impl<'a> PortController<'a> { - fn new(ahci_port_hba: &'a AhciPortHba) -> Self { - Self { ahci_port_hba } + fn new(ahci_port_hba: &'a mut AhciPortHba) -> Result { + let sata_status = ahci_port_hba.sata_status; + assert_eq!( + sata_status.device_detection(), + AhciDeviceDetection::CommunicationEstablished + ); + assert_eq!( + sata_status.interface_power_management(), + AhciInterfacePowerManagement::Active, + ); + let (command_structures, command_paddr) = MemoryRegion::contiguous_physical(0x2500)?; + ahci_port_hba.command_list_base = command_paddr; + ahci_port_hba.fis_base = command_paddr + 0x400; + + ahci_port_hba.interrupt_enable = AhciPortInterruptEnable::from_bits(0xFFFF_FFFF); + // Overwrite all errors. + ahci_port_hba.sata_error = AhciSataError::from_bits(0xFFFF_FFFF); + + let command = ahci_port_hba.command; + ahci_port_hba.command = command.with_fis_recieve_enable(true).with_start(true); + + let mut controller = Self { + ahci_port_hba, + command_slots: [const { None }; 32], + command_structures, + command_paddr, + }; + + // This leaves space for 8 prdt entries. + for i in 0..32 { + controller.command_list()[i].command_table_base_addr = + (command_paddr + 0x500) + (0x100 * (i as u64)); + } + + Ok(controller) } - pub fn identify(&self) {} + pub fn identify(&mut self) -> Result<(), ZError> { + if self.ahci_port_hba.signature == 0x101 { + self.issue_command(Rc::from(Command::identify()?))?; + } else { + let sig = self.ahci_port_hba.signature; + mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); + } + Ok(()) + } + + fn issue_command(&mut self, command: Rc) -> Result<(), ZError> { + let slot = self.select_slot()?; + self.command_slots[slot] = Some(command.clone()); + + self.command_tables()[slot].command_fis.host_to_device = command.clone().as_ref().into(); + + self.command_tables()[slot].prdt[0].region_address = command.paddr; + self.command_tables()[slot].prdt[0].byte_count = 512 * (command.sector_cnt as u32); + + self.command_list()[slot].prd_table_length = 1; + + self.command_list()[slot].command = + (size_of::() as u16 / 4) & 0x1F; + self.command_list()[slot].command |= 1 << 7; + self.ahci_port_hba.command_issue |= 1 << slot; + Ok(()) + } + + fn select_slot(&self) -> Result { + for i in 0..self.command_slots.len() { + match self.command_slots[i] { + None => return Ok(i), + _ => {} + } + } + return Err(ZError::EXHAUSTED); + } + + fn command_list(&mut self) -> &mut CommandList { + unsafe { + self.command_structures + .mut_slice::() + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + } + } + + fn recieved_fis(&mut self) -> &mut ReceivedFis { + unsafe { + self.command_structures.mut_slice::()[0x400..] + .as_mut_ptr() + .cast::() + .as_mut() + .unwrap() + } + } + + fn command_tables(&mut self) -> &mut [CommandTable; 32] { + unsafe { + self.command_structures.mut_slice::()[0x500..] + .as_mut_ptr() + .cast::<[CommandTable; 32]>() + .as_mut() + .unwrap() + } + } + + fn handle_interrupt(&mut self) { + let int_status = self.ahci_port_hba.interrupt_status; + if int_status.device_to_host_register_fis_interrupt() { + assert_eq!( + self.recieved_fis().device_to_host_register_fis.fis_type as u8, + FisType::RegisterDeviceToHost as u8 + ); + if self.recieved_fis().device_to_host_register_fis.error != 0 { + mammoth::debug!( + "D2H err: {:#0x}", + self.recieved_fis().device_to_host_register_fis.error + ); + + mammoth::debug!( + "Status: {:#0x}", + self.recieved_fis().device_to_host_register_fis.status + ); + } + + self.ahci_port_hba.interrupt_status = + AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true); + } + if int_status.pio_setup_fis_interrupt() { + self.ahci_port_hba.interrupt_status = + AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true); + } + + for i in 0..32 { + let int_offset = 1 << i; + + // If there is no longer a command issued on a slot and we have something in + // the command list we know that this is the command that finished. + // FIXME: This could cause a race condition when issuing a command if a different + // interrupt triggers between us setting the command in the command slot and + // actually issuing the command. + if (self.ahci_port_hba.command_issue & int_offset) != int_offset { + if let Some(_) = &self.command_slots[i] { + self.finish_command(i); + self.command_slots[i] = None; + } + } + } + } + + fn finish_command(&self, slot: usize) { + mammoth::debug!("Finishing command in slot {}", slot); + } } diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index 36a1d0f..ba0ede2 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -1,3 +1,4 @@ +mod command; mod controller; mod hba; mod port; diff --git a/rust/sys/denali/src/ahci/port.rs b/rust/sys/denali/src/ahci/port.rs index 773bdde..d209791 100644 --- a/rust/sys/denali/src/ahci/port.rs +++ b/rust/sys/denali/src/ahci/port.rs @@ -1,61 +1,61 @@ use bitfield_struct::bitfield; #[bitfield(u32)] -struct AhciPortInterruptStatus { - device_to_host_register_fis_interrupt: bool, - pio_setup_fis_interrupt: bool, - dma_setup_fis_interrupt: bool, - set_device_bits_interrupt: bool, +pub struct AhciPortInterruptStatus { + pub device_to_host_register_fis_interrupt: bool, + pub pio_setup_fis_interrupt: bool, + pub dma_setup_fis_interrupt: bool, + pub set_device_bits_interrupt: bool, #[bits(access = RO)] - unknown_fis_interrupt: bool, - descriptor_prossed: bool, + pub unknown_fis_interrupt: bool, + pub descriptor_prossed: bool, #[bits(access = RO)] - port_connect_change_status: bool, - device_mechanical_presence_status: bool, + pub port_connect_change_status: bool, + pub device_mechanical_presence_status: bool, #[bits(14)] __: u32, #[bits(access = RO)] - phy_rdy_change_status: bool, - incorrect_port_multiplier_status: bool, - overflow_status: bool, + pub phy_rdy_change_status: bool, + pub incorrect_port_multiplier_status: bool, + pub overflow_status: bool, __: bool, - interface_non_fatal_error_status: bool, - interface_fatal_error_status: bool, - host_bus_data_error_status: bool, - host_bus_fatal_error_status: bool, - task_file_error_status: bool, - cold_port_detect_status: bool, + pub interface_non_fatal_error_status: bool, + pub interface_fatal_error_status: bool, + pub host_bus_data_error_status: bool, + pub host_bus_fatal_error_status: bool, + pub task_file_error_status: bool, + pub cold_port_detect_status: bool, } #[bitfield(u32)] -struct AhciPortInterruptEnable { - device_to_host_register_fis_enable: bool, - pio_setup_fis_enable: bool, - dma_setup_fis_enable: bool, - set_device_bits_fis_enable: bool, - unknown_fis_enable: bool, - descriptor_processed_enable: bool, - port_change_enable: bool, - device_mechanical_presence_enable: bool, +pub struct AhciPortInterruptEnable { + pub device_to_host_register_fis_enable: bool, + pub pio_setup_fis_enable: bool, + pub dma_setup_fis_enable: bool, + pub set_device_bits_fis_enable: bool, + pub unknown_fis_enable: bool, + pub descriptor_processed_enable: bool, + pub port_change_enable: bool, + pub device_mechanical_presence_enable: bool, #[bits(14)] __: u32, - phy_rdy_change_enable: bool, - incorrect_port_multiplier_enable: bool, - overflow_enable: bool, + pub phy_rdy_change_enable: bool, + pub incorrect_port_multiplier_enable: bool, + pub overflow_enable: bool, __: bool, - interface_non_fatal_error_enable: bool, - interface_fatal_error_enable: bool, - host_bus_data_error_enable: bool, - host_bust_fatal_error_enable: bool, - task_file_error_enable: bool, - cold_presence_detect_enable: bool, + pub interface_non_fatal_error_enable: bool, + pub interface_fatal_error_enable: bool, + pub host_bus_data_error_enable: bool, + pub host_bust_fatal_error_enable: bool, + pub task_file_error_enable: bool, + pub cold_presence_detect_enable: bool, } #[repr(u8)] @@ -87,50 +87,50 @@ impl InterfaceCommunicationControl { } #[bitfield(u32)] -struct AhciPortCommandAndStatus { - start: bool, - spin_up_device: bool, - power_on_device: bool, - command_list_overide: bool, - fis_recieve_enable: bool, +pub struct AhciPortCommandAndStatus { + pub start: bool, + pub spin_up_device: bool, + pub power_on_device: bool, + pub command_list_overide: bool, + pub fis_recieve_enable: bool, #[bits(3)] __: u8, #[bits(5, access = RO)] - current_command_slot: u8, + pub current_command_slot: u8, #[bits(access = RO)] - mechanical_presence_switch_state: bool, + pub mechanical_presence_switch_state: bool, #[bits(access = RO)] - fis_receive_running: bool, + pub fis_receive_running: bool, #[bits(access = RO)] - command_list_running: bool, + pub command_list_running: bool, #[bits(access = RO)] - cold_presence_state: bool, - port_multipler_attached: bool, + pub cold_presence_state: bool, + pub port_multipler_attached: bool, #[bits(access = RO)] - hot_plug_capable_port: bool, + pub hot_plug_capable_port: bool, #[bits(access = RO)] - mechanical_presence_switch_attached_to_port: bool, + pub mechanical_presence_switch_attached_to_port: bool, #[bits(access = RO)] - cold_presence_detection: bool, + pub cold_presence_detection: bool, #[bits(access = RO)] - external_sata_port: bool, + pub external_sata_port: bool, #[bits(access = RO)] - fis_base_switch_capable: bool, - automatic_partial_to_slumber_transitions_enable: bool, - device_is_atapi: bool, - drive_led_on_atapi_enable: bool, - aggressive_power_link_management_enable: bool, - aggressive_slumber_partial: bool, + pub fis_base_switch_capable: bool, + pub automatic_partial_to_slumber_transitions_enable: bool, + pub device_is_atapi: bool, + pub drive_led_on_atapi_enable: bool, + pub aggressive_power_link_management_enable: bool, + pub aggressive_slumber_partial: bool, #[bits(4)] - interface_communication_control: InterfaceCommunicationControl, + pub interface_communication_control: InterfaceCommunicationControl, } #[bitfield(u32)] -struct AhciPortTaskFileData { +pub struct AhciPortTaskFileData { #[bits(access = RO)] err_status: bool, #[bits(2, access = RO)] @@ -149,9 +149,9 @@ struct AhciPortTaskFileData { __: u16, } -#[derive(Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] -enum AhciDeviceDetection { +pub enum AhciDeviceDetection { NoDevice = 0x0, NoCommunication = 0x1, CommunicationEstablished = 0x3, @@ -171,9 +171,9 @@ impl AhciDeviceDetection { } } -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] #[repr(u8)] -enum AhciCurrentInterfaceSpeed { +pub enum AhciCurrentInterfaceSpeed { NoDevice = 0x0, Gen1 = 0x1, Gen2 = 0x2, @@ -193,9 +193,9 @@ impl AhciCurrentInterfaceSpeed { } } -#[derive(Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] #[repr(u8)] -enum AhciInterfacePowerManagement { +pub enum AhciInterfacePowerManagement { NoDevice = 0x0, Active = 0x1, PartialPower = 0x2, @@ -218,15 +218,16 @@ impl AhciInterfacePowerManagement { } #[bitfield(u32)] -struct AhciSataStatus { +#[derive(PartialEq)] +pub struct AhciSataStatus { #[bits(4, access = RO)] - device_detection: AhciDeviceDetection, + pub device_detection: AhciDeviceDetection, #[bits(4, access = RO)] - current_interface_speed: AhciCurrentInterfaceSpeed, + pub current_interface_speed: AhciCurrentInterfaceSpeed, #[bits(4, access = RO)] - interface_power_management: AhciInterfacePowerManagement, + pub interface_power_management: AhciInterfacePowerManagement, #[bits(20)] __: u32, @@ -283,7 +284,7 @@ impl AhciSpeedAllowed { } #[bitfield(u32)] -struct AhciSataControl { +pub struct AhciSataControl { #[bits(4)] device_detection_initialization: AhciDeviceDetectionInitialization, @@ -301,39 +302,39 @@ struct AhciSataControl { } #[bitfield(u32)] -struct AhciSataError { - recovered_data_integrity_error: bool, - recovered_communications_error: bool, +pub struct AhciSataError { + pub recovered_data_integrity_error: bool, + pub recovered_communications_error: bool, #[bits(6)] __: u8, - transient_data_integrity_error: bool, - persisten_communication_or_data_integrity_error: bool, - protocol_error: bool, - internal_error: bool, + pub transient_data_integrity_error: bool, + pub persisten_communication_or_data_integrity_error: bool, + pub protocol_error: bool, + pub internal_error: bool, #[bits(4)] __: u8, - phy_ready_change: bool, - phy_internal_error: bool, - comm_wake: bool, - decode_error: bool, + pub phy_ready_change: bool, + pub phy_internal_error: bool, + pub comm_wake: bool, + pub decode_error: bool, __: bool, - crc_error: bool, - handshake_error: bool, - link_sequence_error: bool, - transport_state_transition_error: bool, - uknown_fis_type: bool, - exchanged: bool, + pub crc_error: bool, + pub handshake_error: bool, + pub link_sequence_error: bool, + pub transport_state_transition_error: bool, + pub uknown_fis_type: bool, + pub exchanged: bool, #[bits(5)] __: u8, } #[bitfield(u32)] -struct AhciFisBasedSwitchingControl { +pub struct AhciFisBasedSwitchingControl { enable: bool, device_error_clear: bool, @@ -357,7 +358,7 @@ struct AhciFisBasedSwitchingControl { } #[bitfield(u32)] -struct AhciDeviceSleep { +pub struct AhciDeviceSleep { aggressive_device_sleep_enable: bool, #[bits(access = RO)] @@ -378,22 +379,25 @@ struct AhciDeviceSleep { __: u8, } +#[derive(Debug)] #[repr(C, packed)] pub struct AhciPortHba { - command_list_base: u64, - fis_base: u64, - interrupt_status: AhciPortInterruptStatus, - interrupt_enable: AhciPortInterruptEnable, - command: AhciPortCommandAndStatus, + pub command_list_base: u64, + pub fis_base: u64, + pub interrupt_status: AhciPortInterruptStatus, + pub interrupt_enable: AhciPortInterruptEnable, + pub command: AhciPortCommandAndStatus, __: u32, - task_file_data: AhciPortTaskFileData, - signature: u32, - sata_status: AhciSataStatus, - sata_control: AhciSataControl, - sata_error: AhciSataError, - sata_active: u32, - command_issue: u32, - sata_notification: u32, - fis_based_switching_ctl: AhciFisBasedSwitchingControl, - device_sleep: AhciDeviceSleep, + pub task_file_data: AhciPortTaskFileData, + pub signature: u32, + pub sata_status: AhciSataStatus, + pub sata_control: AhciSataControl, + pub sata_error: AhciSataError, + pub sata_active: u32, + pub command_issue: u32, + pub sata_notification: u32, + pub fis_based_switching_ctl: AhciFisBasedSwitchingControl, + pub device_sleep: AhciDeviceSleep, } + +const _: () = assert!(size_of::() == 0x48); diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index b4860f6..080fafe 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -24,7 +24,7 @@ extern "C" fn main() -> z_err_t { .unwrap(), ); - mammoth::debug!("AHCI ABAR {:#x}", ahci_controller.pci_header().abar as u64); - mammoth::debug!("AHCI Capabilities: {:?}", ahci_controller.ahci_hba()); + ahci_controller.join().unwrap(); + 0 } From 14585c005c459a0194d2a50f9556c45e42c0e9d8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 3 Oct 2024 21:25:37 -0700 Subject: [PATCH 135/186] Parse information out of identify command. --- rust/sys/denali/src/ahci/controller.rs | 35 ++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index b0c3c3e..bfe52b0 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -222,10 +222,12 @@ struct Command { #[allow(dead_code)] // We need to own this even if we never access it. memory_region: MemoryRegion, + + callback: fn(&Self) -> (), } impl Command { - pub fn identify() -> Result { + pub fn identify(callback: fn(&Self) -> ()) -> Result { let (memory_region, paddr) = MemoryRegion::contiguous_physical(512)?; Ok(Self { @@ -234,8 +236,13 @@ impl Command { sector_cnt: 1, paddr, memory_region, + callback, }) } + + pub fn callback(&self) { + (self.callback)(self); + } } impl From<&Command> for HostToDeviceRegisterFis { @@ -248,7 +255,6 @@ struct PortController<'a> { ahci_port_hba: &'a mut AhciPortHba, command_slots: [Option>; 32], command_structures: MemoryRegion, - command_paddr: u64, } impl<'a> PortController<'a> { @@ -277,7 +283,6 @@ impl<'a> PortController<'a> { ahci_port_hba, command_slots: [const { None }; 32], command_structures, - command_paddr, }; // This leaves space for 8 prdt entries. @@ -291,7 +296,27 @@ impl<'a> PortController<'a> { pub fn identify(&mut self) -> Result<(), ZError> { if self.ahci_port_hba.signature == 0x101 { - self.issue_command(Rc::from(Command::identify()?))?; + let callback = |c: &Command| { + mammoth::debug!("TESTING"); + let ident = c.memory_region.slice::(); + let sector_size = if ident[106] & (1 << 12) != 0 { + ident[117] as u32 | ((ident[118] as u32) << 16) + } else { + 512 + }; + + let lba_count = if ident[83] & (1 << 10) != 0 { + ident[100] as u64 + | (ident[101] as u64) << 16 + | (ident[102] as u64) << 32 + | (ident[103] as u64) << 48 + } else { + (ident[60] as u64 | (ident[61] as u64) << 16) as u64 + }; + mammoth::debug!("Sector size: {:#0x}", sector_size); + mammoth::debug!("LBA Count: {:#0x}", lba_count); + }; + self.issue_command(Rc::from(Command::identify(callback)?))?; } else { let sig = self.ahci_port_hba.signature; mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); @@ -403,6 +428,6 @@ impl<'a> PortController<'a> { } fn finish_command(&self, slot: usize) { - mammoth::debug!("Finishing command in slot {}", slot); + self.command_slots[slot].as_ref().unwrap().callback() } } From 9da38d608a1ae51823571de2bf35dc074e1aa41e Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 25 Jan 2025 21:49:28 -0800 Subject: [PATCH 136/186] Add thread spawn with proper trait checks. --- rust/lib/mammoth/src/thread.rs | 40 ++++++++++++++++++++++++++++++++++ rust/usr/testbed/src/main.rs | 18 +++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 9d2e688..8f74b59 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -42,3 +42,43 @@ impl Thread { syscall::thread_wait(&self.cap) } } + +pub struct JoinHandle { + cap: Capability, +} + +impl JoinHandle { + pub fn join(&self) -> Result<(), zion::ZError> { + syscall::thread_wait(&self.cap) + } +} + +#[no_mangle] +extern "C" fn entry_point(func: *mut c_void) -> ! { + unsafe { + Box::from_raw(func as *mut Box)(); + } + + syscall::thread_exit() +} + +pub fn spawn(f: F) -> JoinHandle +where + F: FnOnce() + Send + 'static, +{ + // This is very tricky. + // If we have been passed a closure that doesn't capture + // anything it will be 0 size and creating a Box of it + // will create a pointer with address 0x1. + // So we create this "main" closure that captures f to get around this. + // Also somehow having the explicit type annotation here is important. + let main: Box = Box::new(move || { + f(); + }); + let raw_main = Box::into_raw(Box::new(main)); + let proc_cap = Capability::take_copy(unsafe { crate::init::SELF_PROC_CAP }).unwrap(); + let cap = syscall::thread_create(&proc_cap).unwrap(); + syscall::thread_start(&cap, entry_point as u64, raw_main as u64, 0).unwrap(); + + JoinHandle { cap } +} diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index a6a5ca0..91a1913 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -3,6 +3,7 @@ extern crate alloc; +use alloc::boxed::Box; use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; @@ -12,6 +13,10 @@ use yellowstone_yunq::GetEndpointRequest; define_entry!(); +pub fn testthread() { + debug!("Testing 1, 8 ,9"); +} + #[no_mangle] pub extern "C" fn main() -> z_err_t { debug!("Testing!"); @@ -28,11 +33,24 @@ pub extern "C" fn main() -> z_err_t { debug!("Got endpoint w/ cap: {:#x}", endpoint.endpoint); + let a = Box::new(1); + let b = Box::new(1); + debug!("Addrs: {:p} {:p}", a, b); + let e: thread::ThreadEntry = |_| { debug!("Testing 1 2 3"); }; let t = thread::Thread::spawn(e, core::ptr::null()).expect("Failed to spawn thread"); + t.join().expect("Failed to wait."); + let x = Box::new(|| 1); + debug!("Addr: {:p}", x); + debug!("Addr: {:p}", &x); + + let t = thread::spawn(testthread); + t.join().expect("Failed to wait."); + + let t = thread::spawn(|| debug!("Testing 4, 5, 6")); t.join().expect("Failed to wait."); 0 From 71c6003905e9c0f04e95a0a3f8092146f684fb35 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 25 Jan 2025 23:16:27 -0800 Subject: [PATCH 137/186] Move teton to use new thread spawning. --- rust/lib/voyageurs/src/listener.rs | 100 +++++++++-------------------- rust/sys/teton/src/main.rs | 9 +-- 2 files changed, 34 insertions(+), 75 deletions(-) diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs index 3f82095..1912b88 100644 --- a/rust/lib/voyageurs/src/listener.rs +++ b/rust/lib/voyageurs/src/listener.rs @@ -1,12 +1,7 @@ -use core::cell::RefCell; - -use alloc::boxed::Box; -use alloc::rc::Rc; use alloc::string::ToString; use mammoth::cap::Capability; use mammoth::port::PortServer; -use mammoth::thread::Thread; -use mammoth::zion::ZError; +use mammoth::thread; #[repr(u8)] #[allow(dead_code)] @@ -198,67 +193,34 @@ pub trait KeyboardHandler { fn handle_char(&mut self, c: char); } -pub struct KeyboardListener { - listen_port: PortServer, - listen_thread: Option>, - handler: Rc>, -} - -impl KeyboardListener { - pub fn new(handler: Rc>) -> Result, ZError> { - let mut listnr = Box::new(Self { - listen_port: PortServer::new()?, - listen_thread: None, - handler, - }); - - let voyageur_endpoint = yellowstone_yunq::from_init_endpoint() - .get_endpoint(&yellowstone_yunq::GetEndpointRequest { - endpoint_name: "voyageurs".to_string(), - })? - .endpoint; - - let mut voyageur_client = crate::VoyageursClient::new(Capability::take(voyageur_endpoint)); - - voyageur_client.register_keyboard_listener(&crate::KeyboardListener { - port_capability: listnr.listen_port.create_client_cap()?, - })?; - - let thread_entry = |self_raw| { - let listener = unsafe { - (self_raw as *mut KeyboardListener) - .as_mut() - .expect("Failed to convert to keyboard listener") - }; - listener.listen_loop(); - }; - - listnr.listen_thread = Some(Thread::spawn( - thread_entry, - &*listnr as *const Self as *const core::ffi::c_void, - )?); - - Ok(listnr) - } - - fn listen_loop(&mut self) { - loop { - let scancode = self - .listen_port - .recv_u16() - .expect("Failed to recieve scancode"); - - let keycode = Keycode::from_scancode(scancode); - let modifiers = Modifiers::from_scancode(scancode); - - self.handler - .as_ref() - .borrow_mut() - .handle_char(into_char(keycode, modifiers)) - } - } - - pub fn join(&self) -> Result<(), ZError> { - self.listen_thread.as_ref().unwrap().join() - } +pub fn spawn_keyboard_listener(mut handler: T) -> thread::JoinHandle +where + T: KeyboardHandler + Send + 'static, +{ + let listen_port = PortServer::new().unwrap(); + let voyageur_endpoint = yellowstone_yunq::from_init_endpoint() + .get_endpoint(&yellowstone_yunq::GetEndpointRequest { + endpoint_name: "voyageurs".to_string(), + }) + .unwrap() + .endpoint; + + let mut voyageur_client = crate::VoyageursClient::new(Capability::take(voyageur_endpoint)); + + voyageur_client + .register_keyboard_listener(&crate::KeyboardListener { + port_capability: listen_port.create_client_cap().unwrap(), + }) + .unwrap(); + + let listen_thread = move || loop { + let scancode = listen_port.recv_u16().expect("Failed to recieve scancode"); + + let keycode = Keycode::from_scancode(scancode); + let modifiers = Modifiers::from_scancode(scancode); + + handler.handle_char(into_char(keycode, modifiers)) + }; + + thread::spawn(listen_thread) } diff --git a/rust/sys/teton/src/main.rs b/rust/sys/teton/src/main.rs index 5cec4fb..982beb7 100644 --- a/rust/sys/teton/src/main.rs +++ b/rust/sys/teton/src/main.rs @@ -8,11 +8,8 @@ mod framebuffer; mod psf; mod terminal; -use core::cell::RefCell; - -use alloc::rc::Rc; use mammoth::{debug, define_entry, zion::z_err_t}; -use voyageurs::listener::KeyboardListener; +use voyageurs::listener; define_entry!(); @@ -39,9 +36,9 @@ extern "C" fn main() -> z_err_t { let psf = psf::Psf::new("/default8x16.psfu").expect("Failed to open font file."); let console = console::Console::new(framebuffer, psf); - let terminal = Rc::new(RefCell::new(terminal::Terminal::new(console))); + let terminal = terminal::Terminal::new(console); - let kb_listener = KeyboardListener::new(terminal).expect("Failed to create keyboard listener"); + let kb_listener = listener::spawn_keyboard_listener(terminal); kb_listener .join() From d1b5720abd83dbb1f0e771400db0078036cabd01 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 25 Jan 2025 23:17:45 -0800 Subject: [PATCH 138/186] Add a Mutex implementation. --- rust/lib/mammoth/src/sync.rs | 53 +++++++++++++++++++++++++++++++++ rust/lib/mammoth/src/syscall.rs | 30 +++++++++++++++++++ 2 files changed, 83 insertions(+) diff --git a/rust/lib/mammoth/src/sync.rs b/rust/lib/mammoth/src/sync.rs index 8d80f17..0ee5fea 100644 --- a/rust/lib/mammoth/src/sync.rs +++ b/rust/lib/mammoth/src/sync.rs @@ -1,3 +1,7 @@ +use core::cell::UnsafeCell; +use core::ops::Deref; +use core::ops::DerefMut; + use crate::{cap::Capability, syscall, zion::ZError}; pub struct Semaphore { @@ -17,3 +21,52 @@ impl Semaphore { syscall::semaphone_signal(&self.cap) } } + +pub struct Mutex { + cap: Capability, + data: UnsafeCell, +} + +unsafe impl Sync for Mutex where T: Send {} + +pub struct MutexGuard<'a, T> { + mutex: &'a Mutex, +} + +unsafe impl Send for MutexGuard<'_, T> where T: Send {} +unsafe impl Sync for MutexGuard<'_, T> where T: Sync {} + +impl Deref for MutexGuard<'_, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.mutex.data.get() } + } +} + +impl DerefMut for MutexGuard<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.mutex.data.get() } + } +} + +impl Mutex { + pub fn new(data: T) -> Mutex { + Mutex { + cap: syscall::mutex_create().unwrap(), + data: UnsafeCell::new(data), + } + } + + pub fn lock(&self) -> MutexGuard { + syscall::mutex_lock(&self.cap).unwrap(); + + MutexGuard { mutex: self } + } +} + +impl Drop for MutexGuard<'_, T> { + fn drop(&mut self) { + syscall::mutex_release(&self.mutex.cap).unwrap(); + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 565a2c1..31acd94 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -412,6 +412,36 @@ pub fn reply_port_recv( Ok((num_bytes, num_caps)) } +pub fn mutex_create() -> Result { + let mut mutex_cap: z_cap_t = 0; + syscall( + zion::kZionMutexCreate, + &zion::ZMutexCreateReq { + mutex_cap: &mut mutex_cap, + }, + )?; + + Ok(Capability::take(mutex_cap)) +} + +pub fn mutex_lock(mutex_cap: &Capability) -> Result<(), ZError> { + syscall( + zion::kZionMutexLock, + &zion::ZMutexLockReq { + mutex_cap: mutex_cap.raw(), + }, + ) +} + +pub fn mutex_release(mutex_cap: &Capability) -> Result<(), ZError> { + syscall( + zion::kZionMutexRelease, + &zion::ZMutexReleaseReq { + mutex_cap: mutex_cap.raw(), + }, + ) +} + pub fn semaphore_create() -> Result { let mut sem_cap: z_cap_t = 0; syscall( From c4613cf87f843fa2b68110e8111326041a53738f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 25 Jan 2025 23:26:01 -0800 Subject: [PATCH 139/186] Move to new limine format. --- scripts/build_image.sh | 2 +- zion/boot/limine.cfg | 11 ----------- zion/boot/limine.conf | 11 +++++++++++ 3 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 zion/boot/limine.cfg create mode 100644 zion/boot/limine.conf diff --git a/scripts/build_image.sh b/scripts/build_image.sh index f715102..ed8b082 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -36,7 +36,7 @@ mount "${dev}p1" efi/ mkdir -p efi/EFI/BOOT cp /usr/share/limine/BOOTX64.EFI efi/EFI/BOOT cp /usr/share/limine/limine-bios.sys efi/ -cp ../zion/boot/limine.cfg efi/ +cp ../zion/boot/limine.conf efi/ cp zion/zion efi/ mkdir -p efi/sys cp ../sysroot/bin/yellowstone efi/sys/yellowstone diff --git a/zion/boot/limine.cfg b/zion/boot/limine.cfg deleted file mode 100644 index 0d3a965..0000000 --- a/zion/boot/limine.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Needs to be copied into the EFI partition of the drive. - -TIMEOUT=0 - -:AcadiaOS - PROTOCOL=limine - - KERNEL_PATH=boot:///zion - MODULE_PATH=boot:///sys/yellowstone - MODULE_PATH=boot:///sys/denali - MODULE_PATH=boot:///sys/victoriafalls diff --git a/zion/boot/limine.conf b/zion/boot/limine.conf new file mode 100644 index 0000000..718e5c3 --- /dev/null +++ b/zion/boot/limine.conf @@ -0,0 +1,11 @@ +# Needs to be copied into the EFI partition of the drive. + +timeout: 0 + +/AcadiaOS +protocol: limine + +kernel_path: boot():/zion +module_path: boot():/sys/yellowstone +module_path: boot():/sys/denali +module_path: boot():/sys/victoriafalls From 79e1ea279132e8e9daf09cbf4771d9a56349f325 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 25 Jan 2025 23:48:53 -0800 Subject: [PATCH 140/186] Move denali to new thread spawn --- rust/sys/denali/src/ahci/controller.rs | 86 ++++++++++---------------- rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/bin/denali.rs | 12 ++-- 3 files changed, 42 insertions(+), 57 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index bfe52b0..a5ac3ca 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,6 +1,8 @@ use alloc::boxed::Box; -use alloc::rc::Rc; +use alloc::sync::Arc; use core::ffi::c_void; +use mammoth::sync::Mutex; +use mammoth::thread; use mammoth::{mem::MemoryRegion, thread::Thread, zion::ZError}; @@ -48,8 +50,6 @@ pub struct PciDeviceHeader { pub struct AhciController { pci_memory: MemoryRegion, hba_memory: MemoryRegion, - irq_port: Option, - irq_thread: Option>, ports: [Option>; 32], } @@ -68,18 +68,12 @@ impl AhciController { let mut controller = Self { pci_memory, hba_memory, - irq_port: None, - irq_thread: None, ports: [const { None }; 32], }; controller.init(); controller } - pub fn join(&self) -> Result<(), ZError> { - self.irq_thread.as_ref().unwrap().join() - } - fn init(&mut self) { self.ahci_hba().global_host_control.set_hba_reset(true); @@ -95,28 +89,11 @@ impl AhciController { mammoth::syscall::thread_sleep(50).unwrap(); - self.register_irq(); - self.init_ports().unwrap(); } - fn run_server(&self) -> Result, ZError> { - let thread_entry = |server_ptr: *const c_void| { - let server = unsafe { - (server_ptr as *mut Self) - .as_mut() - .expect("Failed to convert to server") - }; - server.irq_loop(); - }; - Thread::spawn( - thread_entry, - self as *const Self as *const core::ffi::c_void, - ) - } - - fn register_irq(&mut self) { - let irq_num = match self.pci_header().interrupt_pin { + fn irq_num(&self) -> u64 { + match self.pci_header().interrupt_pin { 1 => mammoth::zion::kZIrqPci1, 2 => mammoth::zion::kZIrqPci2, 3 => mammoth::zion::kZIrqPci3, @@ -125,29 +102,16 @@ impl AhciController { "Unrecognized pci interrupt pin {}", self.pci_header().interrupt_pin ), - }; - self.irq_port = Some(mammoth::port::PortServer::from_cap( - mammoth::syscall::register_irq(irq_num).unwrap(), - )); - - self.irq_thread = Some(self.run_server().unwrap()); - - self.ahci_hba() - .global_host_control - .set_interrupt_enable(true); + } } - fn irq_loop(&mut self) { - loop { - self.irq_port.as_ref().unwrap().recv_null().unwrap(); - - for i in 0..self.ahci_hba().capabilities.num_ports() { - let int_offset = 1 << i; - if (self.ahci_hba().interrupt_status & int_offset) == int_offset { - if let Some(port) = &mut self.ports[i as usize] { - port.handle_interrupt(); - self.ahci_hba().interrupt_status &= !int_offset; - } + fn handle_irq(&mut self) { + for i in 0..self.ahci_hba().capabilities.num_ports() { + let int_offset = 1 << i; + if (self.ahci_hba().interrupt_status & int_offset) == int_offset { + if let Some(port) = &mut self.ports[i as usize] { + port.handle_interrupt(); + self.ahci_hba().interrupt_status &= !int_offset; } } } @@ -214,6 +178,24 @@ impl AhciController { } } +pub fn spawn_irq_thread(controller: Arc>) -> thread::JoinHandle { + let irq_thread = move || { + let irq_num = controller.lock().irq_num(); + let irq_port = + mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap()); + controller + .lock() + .ahci_hba() + .global_host_control + .set_interrupt_enable(true); + loop { + irq_port.recv_null().unwrap(); + controller.lock().handle_irq(); + } + }; + thread::spawn(irq_thread) +} + struct Command { command: SataCommand, lba: u64, @@ -253,7 +235,7 @@ impl From<&Command> for HostToDeviceRegisterFis { struct PortController<'a> { ahci_port_hba: &'a mut AhciPortHba, - command_slots: [Option>; 32], + command_slots: [Option>; 32], command_structures: MemoryRegion, } @@ -316,7 +298,7 @@ impl<'a> PortController<'a> { mammoth::debug!("Sector size: {:#0x}", sector_size); mammoth::debug!("LBA Count: {:#0x}", lba_count); }; - self.issue_command(Rc::from(Command::identify(callback)?))?; + self.issue_command(Arc::from(Command::identify(callback)?))?; } else { let sig = self.ahci_port_hba.signature; mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); @@ -324,7 +306,7 @@ impl<'a> PortController<'a> { Ok(()) } - fn issue_command(&mut self, command: Rc) -> Result<(), ZError> { + fn issue_command(&mut self, command: Arc) -> Result<(), ZError> { let slot = self.select_slot()?; self.command_slots[slot] = Some(command.clone()); diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index ba0ede2..2fec39b 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -3,4 +3,5 @@ mod controller; mod hba; mod port; +pub use controller::spawn_irq_thread; pub use controller::AhciController; diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index 080fafe..ef4be28 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -3,9 +3,10 @@ extern crate alloc; -use mammoth::{define_entry, zion::z_err_t}; +use alloc::sync::Arc; +use mammoth::{define_entry, sync::Mutex, zion::z_err_t}; -use denali::ahci::AhciController; +use denali::ahci::{spawn_irq_thread, AhciController}; define_entry!(); @@ -19,12 +20,13 @@ extern "C" fn main() -> z_err_t { .get_ahci_info() .expect("Failed to get ahci info"); - let ahci_controller = AhciController::new( + let ahci_controller = Arc::new(Mutex::new(AhciController::new( mammoth::mem::MemoryRegion::from_cap(mammoth::cap::Capability::take(ahci_info.ahci_region)) .unwrap(), - ); + ))); - ahci_controller.join().unwrap(); + let thread = spawn_irq_thread(ahci_controller.clone()); + thread.join(); 0 } From d777b8f4ab1dec131248c87a5dded8a66912dc37 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 26 Jan 2025 00:05:55 -0800 Subject: [PATCH 141/186] Move yunq to new thread spawn and remove old one. --- rust/lib/mammoth/src/thread.rs | 38 -------------------------- rust/lib/yunq/src/server.rs | 9 ++++++ rust/sys/denali/src/ahci/controller.rs | 4 +-- rust/sys/yellowstone/src/main.rs | 23 +++++++++------- rust/sys/yellowstone/src/server.rs | 18 ++++++------ rust/usr/testbed/src/main.rs | 6 ---- yunq/rust/src/codegen.rs | 11 -------- 7 files changed, 33 insertions(+), 76 deletions(-) diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 8f74b59..99032be 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -5,44 +5,6 @@ use crate::zion; use alloc::boxed::Box; use core::ffi::c_void; -pub type ThreadEntry = fn(*const c_void) -> (); - -#[no_mangle] -extern "C" fn internal_entry_point(thread_ptr: *const Thread, arg1: *const c_void) -> ! { - let thread: &Thread = unsafe { thread_ptr.as_ref().expect("Failed to unwrap thread ref") }; - - (thread.entry)(arg1); - - syscall::thread_exit() -} -// TODO: Add a Drop implementation that kills this thread and drops its capability. -pub struct Thread { - cap: Capability, - // This field only exists to ensure that the entry reference will outlive the thread object - // itself. - entry: ThreadEntry, -} - -impl Thread { - pub fn spawn(entry: ThreadEntry, arg1: *const c_void) -> Result, zion::ZError> { - let proc_cap = Capability::take_copy(unsafe { crate::init::SELF_PROC_CAP })?; - let cap = syscall::thread_create(&proc_cap)?; - let thread = Box::new(Self { cap, entry }); - syscall::thread_start( - &thread.cap, - internal_entry_point as u64, - thread.as_ref() as *const Thread as u64, - arg1 as u64, - )?; - - Ok(thread) - } - - pub fn join(&self) -> Result<(), zion::ZError> { - syscall::thread_wait(&self.cap) - } -} - pub struct JoinHandle { cap: Capability, } diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index 49d7276..dcfd03c 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -2,6 +2,8 @@ use crate::buffer::ByteBuffer; use alloc::vec::Vec; use mammoth::cap::Capability; use mammoth::syscall; +use mammoth::thread; +use mammoth::thread::JoinHandle; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; @@ -50,3 +52,10 @@ pub trait YunqServer { cap_buffer: &mut Vec, ) -> Result; } + +pub fn spawn_server_thread(mut server: T) -> JoinHandle +where + T: YunqServer + Send + 'static, +{ + thread::spawn(move || server.server_loop()) +} diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index a5ac3ca..a9c998d 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,10 +1,8 @@ -use alloc::boxed::Box; use alloc::sync::Arc; -use core::ffi::c_void; use mammoth::sync::Mutex; use mammoth::thread; -use mammoth::{mem::MemoryRegion, thread::Thread, zion::ZError}; +use mammoth::{mem::MemoryRegion, zion::ZError}; use crate::ahci::command::FisType; use crate::ahci::port::{ diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index 18e386f..dbe8c2e 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -3,16 +3,16 @@ extern crate alloc; -use alloc::{string::ToString, vec::Vec}; +use alloc::{string::ToString, sync::Arc, vec::Vec}; use mammoth::{ cap::Capability, define_entry, elf, init::{BOOT_FRAMEBUFFER_INFO_VMMO, BOOT_PCI_VMMO}, mem::MemoryRegion, - zion::{z_cap_t, z_err_t, ZError}, + zion::{kZionPerm_All, z_cap_t, z_err_t, ZError}, }; use yellowstone_yunq::YellowstoneServer; -use yunq::server::YunqServer; +use yunq::server::{spawn_server_thread, YunqServer}; mod gpt; mod pci; @@ -40,20 +40,19 @@ extern "C" fn main() -> z_err_t { .expect("Failed to create PCI region"); let fb_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_FRAMEBUFFER_INFO_VMMO })) .expect("Failed to create Framebuffer region"); - let context = alloc::rc::Rc::new( + let context = Arc::new( server::YellowstoneServerContext::new(pci_region, fb_region) .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); - let server_thread = server.run_server().expect("Failed to run server"); + let client_cap = server.create_client_cap().unwrap(); + let server_thread = spawn_server_thread(server); spawn_from_vmmo( unsafe { mammoth::init::BOOT_DENALI_VMMO }, - server - .create_client_cap() - .expect("Failed to create client cap for denali"), + client_cap.duplicate(kZionPerm_All).unwrap(), ) .expect("Failed to spawn denali"); @@ -62,7 +61,7 @@ extern "C" fn main() -> z_err_t { spawn_from_vmmo( unsafe { mammoth::init::BOOT_VICTORIA_FALLS_VMMO }, - server.create_client_cap().unwrap(), + client_cap.duplicate(kZionPerm_All).unwrap(), ) .expect("Failed to spawn victoriafalls"); @@ -87,7 +86,11 @@ extern "C" fn main() -> z_err_t { let path = "/bin/".to_string() + bin_name; let bin_file = victoriafalls::file::File::open(&path).unwrap(); - spawn_from_mem_region(bin_file.memory(), server.create_client_cap().unwrap()).unwrap(); + spawn_from_mem_region( + bin_file.memory(), + client_cap.duplicate(kZionPerm_All).unwrap(), + ) + .unwrap(); } server_thread.join().expect("Failed to join thread"); diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 5a8ce9c..7daea1f 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,7 +1,9 @@ use core::cell::RefCell; use alloc::rc::Rc; +use alloc::sync::Arc; use alloc::{collections::BTreeMap, string::String}; +use mammoth::sync::Mutex; use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; use victoriafalls::VFSClient; use yellowstone_yunq::{ @@ -15,7 +17,7 @@ pub struct YellowstoneServerContext { registration_semaphore: mammoth::sync::Semaphore, pci_reader: PciReader, framebuffer_info_region: MemoryRegion, - service_map: RefCell>, + service_map: Mutex>, } impl YellowstoneServerContext { @@ -52,13 +54,13 @@ impl YellowstoneServerContext { registration_semaphore: mammoth::sync::Semaphore::new()?, pci_reader: PciReader::new(pci_region), framebuffer_info_region: fb_region, - service_map: BTreeMap::new().into(), + service_map: Mutex::new(BTreeMap::new()), }) } pub fn wait(&self, service: &str) -> Result<(), ZError> { loop { - match self.service_map.borrow().get(service) { + match self.service_map.lock().get(service) { Some(_) => return Ok(()), None => {} } @@ -68,11 +70,11 @@ impl YellowstoneServerContext { } pub struct YellowstoneServerImpl { - context: Rc, + context: Arc, } impl YellowstoneServerImpl { - pub fn new(context: Rc) -> Self { + pub fn new(context: Arc) -> Self { Self { context } } } @@ -87,7 +89,7 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { self.context .service_map - .borrow_mut() + .lock() .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); self.context.registration_semaphore.signal()?; @@ -95,7 +97,7 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { } fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { - match self.context.service_map.borrow().get(&req.endpoint_name) { + match self.context.service_map.lock().get(&req.endpoint_name) { Some(cap) => Ok(Endpoint { endpoint: cap.duplicate(Capability::PERMS_ALL)?.release(), }), @@ -122,7 +124,7 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { } fn get_denali(&mut self) -> Result { - match self.context.service_map.borrow().get("denali") { + match self.context.service_map.lock().get("denali") { Some(ep_cap) => crate::gpt::read_gpt(denali::DenaliClient::new( ep_cap.duplicate(Capability::PERMS_ALL).unwrap(), )) diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index 91a1913..c782312 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -37,12 +37,6 @@ pub extern "C" fn main() -> z_err_t { let b = Box::new(1); debug!("Addrs: {:p} {:p}", a, b); - let e: thread::ThreadEntry = |_| { - debug!("Testing 1 2 3"); - }; - let t = thread::Thread::spawn(e, core::ptr::null()).expect("Failed to spawn thread"); - t.join().expect("Failed to wait."); - let x = Box::new(|| 1); debug!("Addr: {:p}", x); debug!("Addr: {:p}", &x); diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 53560a6..01bf96b 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -369,17 +369,6 @@ fn generate_server(interface: &Interface) -> TokenStream { handler, }) } - - pub fn run_server(&self) -> Result, ZError> { - let thread_entry = |server_ptr: *const c_void| { - let server = unsafe { (server_ptr as *mut #server_name).as_mut().expect("Failed to convert to server") }; - server.server_loop(); - }; - thread::Thread::spawn( - thread_entry, - self as *const Self as *const core::ffi::c_void, - ) - } } impl yunq::server::YunqServer for #server_name { From ab75085f3250e3e8f35b949032e742f1bea70bec Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 26 Jan 2025 09:35:23 -0800 Subject: [PATCH 142/186] Fix cargo warnings in userland. --- rust/sys/denali/src/bin/denali.rs | 2 +- rust/sys/yellowstone/src/server.rs | 3 --- yunq/rust/src/codegen.rs | 4 ---- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index ef4be28..a5f0e68 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -27,6 +27,6 @@ extern "C" fn main() -> z_err_t { let thread = spawn_irq_thread(ahci_controller.clone()); - thread.join(); + thread.join().expect("Failed to wait on irq thread."); 0 } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 7daea1f..8ec36b8 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -1,6 +1,3 @@ -use core::cell::RefCell; - -use alloc::rc::Rc; use alloc::sync::Arc; use alloc::{collections::BTreeMap, string::String}; use mammoth::sync::Mutex; diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 01bf96b..9682e23 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -431,12 +431,8 @@ pub fn generate_code(ast: &Vec) -> String { let interface_imports = if any_interfaces(ast) { quote! { - use alloc::boxed::Box; - use core::ffi::c_void; use mammoth::cap::Capability; use mammoth::syscall; - use mammoth::thread; - use yunq::server::YunqServer; } } else { quote! {} From df19ee0f54c7ed34388deed50278a8904d9ff6a5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 26 Jan 2025 09:42:01 -0800 Subject: [PATCH 143/186] Fix clippy messages in yunq compiler. --- yunq/rust/src/codegen.rs | 23 ++++++++++------------- yunq/rust/src/parser.rs | 6 +++--- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 9682e23..94769f2 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -152,7 +152,7 @@ fn parse_field(field: &Field) -> TokenStream { unimplemented!(); } Type::Message(s) => { - let m_type = ident(&s); + let m_type = ident(s); quote! { let #name = { let msg_offset = buf.at::(yunq::message::field_offset(offset, #ind))? as usize; @@ -272,7 +272,7 @@ fn generate_method(method: &Method) -> TokenStream { fn generate_client(interface: &Interface) -> TokenStream { let client_name = interface.name.clone() + "Client"; let name = ident(&client_name); - let methods = interface.methods.iter().map(|m| generate_method(&m)); + let methods = interface.methods.iter().map(generate_method); quote! { pub struct #name { endpoint_cap: Capability, @@ -350,8 +350,8 @@ fn generate_server_method(method: &Method) -> TokenStream { fn generate_server(interface: &Interface) -> TokenStream { let server_name = ident(&(interface.name.clone() + "Server")); let server_trait = ident(&(interface.name.clone() + "ServerHandler")); - let server_trait_methods = interface.methods.iter().map(|m| generate_server_method(&m)); - let server_match_cases = interface.methods.iter().map(|m| generate_server_case(&m)); + let server_trait_methods = interface.methods.iter().map(generate_server_method); + let server_match_cases = interface.methods.iter().map(generate_server_case); quote! { pub trait #server_trait { #(#server_trait_methods)* @@ -402,7 +402,7 @@ fn generate_interface(interface: &Interface) -> TokenStream { } } -fn any_strings(ast: &Vec) -> bool { +fn any_strings(ast: &[Decl]) -> bool { ast.iter() .filter_map(|decl| match decl { Decl::Message(m) => Some(m), @@ -412,14 +412,11 @@ fn any_strings(ast: &Vec) -> bool { .any(|field| field.field_type.inner_type == Type::String) } -fn any_interfaces(ast: &Vec) -> bool { - ast.iter().any(|decl| match decl { - Decl::Interface(_) => true, - _ => false, - }) +fn any_interfaces(ast: &[Decl]) -> bool { + ast.iter().any(|decl| matches!(decl, Decl::Interface(_))) } -pub fn generate_code(ast: &Vec) -> String { +pub fn generate_code(ast: &[Decl]) -> String { let str_imports = if any_strings(ast) { quote! { use alloc::string::String; @@ -460,7 +457,7 @@ pub fn generate_code(ast: &Vec) -> String { Decl::Message(m) => Some(m), _ => None, }) - .map(|message| generate_message(&message)); + .map(generate_message); let interface_decls = ast .iter() @@ -468,7 +465,7 @@ pub fn generate_code(ast: &Vec) -> String { Decl::Interface(i) => Some(i), _ => None, }) - .map(|interface| generate_interface(&interface)); + .map(generate_interface); let output = quote! { #prelude diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs index fc9ac19..3ea7e2b 100644 --- a/yunq/rust/src/parser.rs +++ b/yunq/rust/src/parser.rs @@ -169,7 +169,7 @@ impl<'a> Parser<'a> { && self.tokens[self.current_index].token_type == tok_type } - fn consume_token<'b>(&'b mut self) -> &'b Token { + fn consume_token(&mut self) -> &Token { if self.current_index >= self.tokens.len() { panic!("Consumed tokens past end of input.") } @@ -179,7 +179,7 @@ impl<'a> Parser<'a> { t } - fn consume_token_type<'b>(&'b mut self, t: TokenType) -> Result<&'b Token, String> { + fn consume_token_type(&mut self, t: TokenType) -> Result<&Token, String> { let token = self.consume_token(); if token.token_type == t { Ok(token) @@ -188,7 +188,7 @@ impl<'a> Parser<'a> { } } - fn consume_identifier<'b>(&'b mut self) -> Result<&'b Token, String> { + fn consume_identifier(&mut self) -> Result<&Token, String> { self.consume_token_type(TokenType::Name) } From 6814c26708dec41e318d8b30a7835c9e7135f312 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 26 Jan 2025 17:52:31 -0800 Subject: [PATCH 144/186] Store sector size and count on the AhciPortController. --- rust/sys/denali/src/ahci/controller.rs | 35 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index a9c998d..6abf744 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,3 +1,6 @@ +use core::ops::DerefMut; + +use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::sync::Mutex; use mammoth::thread; @@ -203,11 +206,11 @@ struct Command { #[allow(dead_code)] // We need to own this even if we never access it. memory_region: MemoryRegion, - callback: fn(&Self) -> (), + callback_internal: Box, } impl Command { - pub fn identify(callback: fn(&Self) -> ()) -> Result { + pub fn identify(callback: Box) -> Result { let (memory_region, paddr) = MemoryRegion::contiguous_physical(512)?; Ok(Self { @@ -216,12 +219,12 @@ impl Command { sector_cnt: 1, paddr, memory_region, - callback, + callback_internal: callback, }) } pub fn callback(&self) { - (self.callback)(self); + (self.callback_internal)(self); } } @@ -235,6 +238,10 @@ struct PortController<'a> { ahci_port_hba: &'a mut AhciPortHba, command_slots: [Option>; 32], command_structures: MemoryRegion, + + // FIXME: These should probably be something like a OnceCell (or OnceLock). + sector_size: Arc>>, + sector_cnt: Arc>>, } impl<'a> PortController<'a> { @@ -263,6 +270,8 @@ impl<'a> PortController<'a> { ahci_port_hba, command_slots: [const { None }; 32], command_structures, + sector_size: Arc::new(Mutex::new(None)), + sector_cnt: Arc::new(Mutex::new(None)), }; // This leaves space for 8 prdt entries. @@ -276,10 +285,12 @@ impl<'a> PortController<'a> { pub fn identify(&mut self) -> Result<(), ZError> { if self.ahci_port_hba.signature == 0x101 { - let callback = |c: &Command| { + let sector_size = self.sector_size.clone(); + let sector_cnt = self.sector_cnt.clone(); + let callback = move |c: &Command| { mammoth::debug!("TESTING"); let ident = c.memory_region.slice::(); - let sector_size = if ident[106] & (1 << 12) != 0 { + let new_sector_size = if ident[106] & (1 << 12) != 0 { ident[117] as u32 | ((ident[118] as u32) << 16) } else { 512 @@ -291,12 +302,18 @@ impl<'a> PortController<'a> { | (ident[102] as u64) << 32 | (ident[103] as u64) << 48 } else { - (ident[60] as u64 | (ident[61] as u64) << 16) as u64 + ident[60] as u64 | (ident[61] as u64) << 16 }; - mammoth::debug!("Sector size: {:#0x}", sector_size); + mammoth::debug!("Sector size: {:#0x}", new_sector_size); mammoth::debug!("LBA Count: {:#0x}", lba_count); + + let _ = sector_size + .lock() + .deref_mut() + .insert(new_sector_size as u64); + let _ = sector_cnt.lock().deref_mut().insert(lba_count as u64); }; - self.issue_command(Arc::from(Command::identify(callback)?))?; + self.issue_command(Arc::from(Command::identify(Box::new(callback))?))?; } else { let sig = self.ahci_port_hba.signature; mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); From 34bd3b80d301a21e9d2e46531d259c5d3b3f8a30 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 27 Jan 2025 23:26:54 -0800 Subject: [PATCH 145/186] Created a basic async runtime. --- rust/lib/mammoth/src/lib.rs | 1 + rust/lib/mammoth/src/task/mod.rs | 125 +++++++++++++++++++++++++++++++ rust/usr/testbed/src/main.rs | 24 ++++++ 3 files changed, 150 insertions(+) create mode 100644 rust/lib/mammoth/src/task/mod.rs diff --git a/rust/lib/mammoth/src/lib.rs b/rust/lib/mammoth/src/lib.rs index cf5d3f0..2058a6b 100644 --- a/rust/lib/mammoth/src/lib.rs +++ b/rust/lib/mammoth/src/lib.rs @@ -16,5 +16,6 @@ pub mod mem; pub mod port; pub mod sync; pub mod syscall; +pub mod task; pub mod thread; pub mod zion; diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs new file mode 100644 index 0000000..0b23a67 --- /dev/null +++ b/rust/lib/mammoth/src/task/mod.rs @@ -0,0 +1,125 @@ +use core::{ + future::Future, + pin::Pin, + sync::atomic::{AtomicU64, Ordering}, + task::{Context, Poll, Waker}, +}; + +use alloc::{ + boxed::Box, + collections::{BTreeMap, VecDeque}, + sync::Arc, + task::Wake, +}; + +use crate::{sync::Mutex, syscall}; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +struct TaskId(u64); + +impl TaskId { + pub fn new() -> TaskId { + static NEXT_ID: AtomicU64 = AtomicU64::new(0); + TaskId(NEXT_ID.fetch_add(1, Ordering::Relaxed)) + } +} + +pub struct Task { + id: TaskId, + // FIXME: This only needs to be sync because of the CURRENT_EXECUTOR + // needing to be shared between threads. + future: Pin + Sync>>, +} + +impl Task { + pub fn new(future: impl Future + Sync + 'static) -> Task { + Task { + id: TaskId::new(), + future: Box::pin(future), + } + } + + pub fn poll(&mut self, context: &mut Context) -> Poll<()> { + self.future.as_mut().poll(context) + } +} + +struct TaskWaker { + task_id: TaskId, + task_queue: Arc>>, +} + +impl TaskWaker { + fn new(task_id: TaskId, task_queue: Arc>>) -> Waker { + Waker::from(Arc::new(TaskWaker { + task_id, + task_queue, + })) + } + fn wake_task(&self) { + self.task_queue.lock().push_back(self.task_id); + } +} + +impl Wake for TaskWaker { + fn wake(self: Arc) { + self.wake_task(); + } + + fn wake_by_ref(self: &Arc) { + self.wake_task(); + } +} + +pub struct Executor { + tasks: BTreeMap, + // TODO: Consider a better datastructure for this. + task_queue: Arc>>, + waker_cache: BTreeMap, +} + +impl Executor { + pub fn new() -> Executor { + Executor { + tasks: BTreeMap::new(), + task_queue: Arc::new(Mutex::new(VecDeque::new())), + waker_cache: BTreeMap::new(), + } + } + + pub fn spawn(&mut self, task: Task) { + let task_id = task.id; + if self.tasks.insert(task_id, task).is_some() { + panic!("Task is already existed in executor map"); + } + self.task_queue.lock().push_back(task_id); + } + + fn run_ready_tasks(&mut self) { + while let Some(task_id) = self.task_queue.lock().pop_front() { + let task = self.tasks.get_mut(&task_id).unwrap(); + let waker = self + .waker_cache + .entry(task_id) + .or_insert_with(|| TaskWaker::new(task_id, self.task_queue.clone())); + let mut ctx = Context::from_waker(waker); + match task.poll(&mut ctx) { + Poll::Ready(()) => { + self.tasks.remove(&task_id); + self.waker_cache.remove(&task_id); + } + Poll::Pending => {} + }; + } + } + + pub fn run(&mut self) { + loop { + self.run_ready_tasks(); + // TODO: We need some sort of semaphore wait here. + syscall::thread_sleep(50).unwrap(); + } + } +} + +static CURRENT_EXECUTOR: Option = None; diff --git a/rust/usr/testbed/src/main.rs b/rust/usr/testbed/src/main.rs index c782312..2ea144b 100644 --- a/rust/usr/testbed/src/main.rs +++ b/rust/usr/testbed/src/main.rs @@ -7,6 +7,8 @@ use alloc::boxed::Box; use alloc::string::ToString; use mammoth::debug; use mammoth::define_entry; +use mammoth::task::Executor; +use mammoth::task::Task; use mammoth::thread; use mammoth::zion::z_err_t; use yellowstone_yunq::GetEndpointRequest; @@ -17,6 +19,22 @@ pub fn testthread() { debug!("Testing 1, 8 ,9"); } +async fn inner_async() { + debug!("Inner Async executed"); +} + +async fn test_async() { + debug!("Async executed"); + + let i = inner_async(); + + debug!("inner async created"); + + i.await; + + debug!("inner async returned"); +} + #[no_mangle] pub extern "C" fn main() -> z_err_t { debug!("Testing!"); @@ -47,5 +65,11 @@ pub extern "C" fn main() -> z_err_t { let t = thread::spawn(|| debug!("Testing 4, 5, 6")); t.join().expect("Failed to wait."); + let mut executor = Executor::new(); + + executor.spawn(Task::new(test_async())); + + executor.run(); + 0 } From 741b605a1c35a17a7aca8a16479fd2a2bfe29bbb Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 31 Jan 2025 18:03:04 -0800 Subject: [PATCH 146/186] Move init implementation into hba and introduce volatile. --- rust/lib/mammoth/src/mem.rs | 41 +++++++++++++++++++++++ rust/sys/denali/src/ahci/controller.rs | 30 +++++++---------- rust/sys/denali/src/ahci/hba.rs | 45 +++++++++++++++++++------- 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 6e7817c..6cf662d 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -2,6 +2,8 @@ use crate::cap::Capability; use crate::syscall; use crate::zion::ZError; use alloc::slice; +use core::fmt::Debug; +use core::ptr::{addr_of, addr_of_mut}; #[cfg(feature = "hosted")] use linked_list_allocator::LockedHeap; @@ -111,3 +113,42 @@ impl Drop for MemoryRegion { syscall::address_space_unmap(self.virt_addr, max).expect("Failed to unmap memory"); } } + +pub struct Volatile { + /// TODO: This should maybe be MaybeUninit. + data: T, +} + +impl Volatile { + pub fn read(&self) -> T + where + T: Copy, + { + unsafe { addr_of!(self.data).cast::().read_volatile() } + } + + pub fn write(&mut self, data: T) { + unsafe { + addr_of_mut!(self.data).cast::().write_volatile(data); + } + } + + pub fn update(&mut self, func: F) + where + T: Copy, + F: Fn(&mut T), + { + let mut data = self.read(); + func(&mut data); + self.write(data); + } +} + +impl Debug for Volatile +where + T: Debug + Copy, +{ + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.read()) + } +} diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 6abf744..07783c8 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -76,19 +76,7 @@ impl AhciController { } fn init(&mut self) { - self.ahci_hba().global_host_control.set_hba_reset(true); - - mammoth::syscall::thread_sleep(50).unwrap(); - - loop { - if !self.ahci_hba().global_host_control.hba_reset() { - break; - } - } - - self.ahci_hba().global_host_control.set_ahci_enable(true); - - mammoth::syscall::thread_sleep(50).unwrap(); + self.ahci_hba().init(); self.init_ports().unwrap(); } @@ -107,21 +95,23 @@ impl AhciController { } fn handle_irq(&mut self) { - for i in 0..self.ahci_hba().capabilities.num_ports() { + for i in 0..self.ahci_hba().capabilities.read().num_ports() { let int_offset = 1 << i; - if (self.ahci_hba().interrupt_status & int_offset) == int_offset { + if (self.ahci_hba().interrupt_status.read() & int_offset) == int_offset { if let Some(port) = &mut self.ports[i as usize] { port.handle_interrupt(); - self.ahci_hba().interrupt_status &= !int_offset; + self.ahci_hba().interrupt_status.update(|is| { + *is &= !int_offset; + }); } } } } fn init_ports(&mut self) -> Result<(), ZError> { - for i in 0..(self.ahci_hba().capabilities.num_ports() as usize) { + for i in 0..(self.ahci_hba().capabilities.read().num_ports() as usize) { let port_index = 1 << i; - if (self.ahci_hba().port_implemented & port_index) != port_index { + if (self.ahci_hba().port_implemented.read() & port_index) != port_index { mammoth::debug!("Skipping port {}, not implemented", i); continue; } @@ -188,7 +178,9 @@ pub fn spawn_irq_thread(controller: Arc>) -> thread::JoinH .lock() .ahci_hba() .global_host_control - .set_interrupt_enable(true); + .update(|ghc| { + ghc.set_interrupt_enable(true); + }); loop { irq_port.recv_null().unwrap(); controller.lock().handle_irq(); diff --git a/rust/sys/denali/src/ahci/hba.rs b/rust/sys/denali/src/ahci/hba.rs index f9dbde9..2cfdc63 100644 --- a/rust/sys/denali/src/ahci/hba.rs +++ b/rust/sys/denali/src/ahci/hba.rs @@ -1,4 +1,5 @@ use bitfield_struct::bitfield; +use mammoth::mem::Volatile; const fn increment(val: u8) -> u8 { val + 1 @@ -144,15 +145,37 @@ pub struct AhciBiosHandoffControl { #[derive(Debug)] #[repr(C)] pub struct AhciHba { - pub capabilities: AhciCapabilities, - pub global_host_control: AhciGlobalControl, - pub interrupt_status: u32, - pub port_implemented: u32, - pub version: u32, - pub ccc_ctl: u32, // 0x14, Command completion coalescing control - pub ccc_pts: u32, // 0x18, Command completion coalescing ports - pub em_loc: u32, // 0x1C, Enclosure management location - pub em_ctl: u32, // 0x20, Enclosure management control - pub capabilities_ext: AhciCapabilitiesExtended, - pub bohc: AhciBiosHandoffControl, + pub capabilities: Volatile, + pub global_host_control: Volatile, + pub interrupt_status: Volatile, + pub port_implemented: Volatile, + pub version: Volatile, + pub ccc_ctl: Volatile, // 0x14, Command completion coalescing control + pub ccc_pts: Volatile, // 0x18, Command completion coalescing ports + pub em_loc: Volatile, // 0x1C, Enclosure management location + pub em_ctl: Volatile, // 0x20, Enclosure management control + pub capabilities_ext: Volatile, + pub bohc: Volatile, +} + +impl AhciHba { + pub fn init(&mut self) { + self.global_host_control.update(|ghc| { + ghc.set_hba_reset(true); + }); + + mammoth::syscall::thread_sleep(50).unwrap(); + + loop { + if !self.global_host_control.read().hba_reset() { + break; + } + } + + self.global_host_control.update(|ghc| { + ghc.set_ahci_enable(true); + }); + + mammoth::syscall::thread_sleep(50).unwrap(); + } } From 0024e38412aa6f6c36842a184c65f516a0808a91 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 31 Jan 2025 20:52:14 -0800 Subject: [PATCH 147/186] Move AHCI Port to use volatile. --- rust/sys/denali/src/ahci/controller.rs | 41 +++++----------- rust/sys/denali/src/ahci/port.rs | 66 +++++++++++++++++++------- 2 files changed, 62 insertions(+), 45 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 07783c8..0f166bd 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -127,7 +127,7 @@ impl AhciController { .unwrap() }; - let sata_status = port.sata_status; + let sata_status = port.sata_status.read(); if (sata_status.device_detection() != AhciDeviceDetection::CommunicationEstablished) || (sata_status.interface_power_management() != AhciInterfacePowerManagement::Active) @@ -238,25 +238,8 @@ struct PortController<'a> { impl<'a> PortController<'a> { fn new(ahci_port_hba: &'a mut AhciPortHba) -> Result { - let sata_status = ahci_port_hba.sata_status; - assert_eq!( - sata_status.device_detection(), - AhciDeviceDetection::CommunicationEstablished - ); - assert_eq!( - sata_status.interface_power_management(), - AhciInterfacePowerManagement::Active, - ); let (command_structures, command_paddr) = MemoryRegion::contiguous_physical(0x2500)?; - ahci_port_hba.command_list_base = command_paddr; - ahci_port_hba.fis_base = command_paddr + 0x400; - - ahci_port_hba.interrupt_enable = AhciPortInterruptEnable::from_bits(0xFFFF_FFFF); - // Overwrite all errors. - ahci_port_hba.sata_error = AhciSataError::from_bits(0xFFFF_FFFF); - - let command = ahci_port_hba.command; - ahci_port_hba.command = command.with_fis_recieve_enable(true).with_start(true); + ahci_port_hba.init(command_paddr, command_paddr + 0x400); let mut controller = Self { ahci_port_hba, @@ -276,7 +259,7 @@ impl<'a> PortController<'a> { } pub fn identify(&mut self) -> Result<(), ZError> { - if self.ahci_port_hba.signature == 0x101 { + if self.ahci_port_hba.signature.read() == 0x101 { let sector_size = self.sector_size.clone(); let sector_cnt = self.sector_cnt.clone(); let callback = move |c: &Command| { @@ -307,7 +290,7 @@ impl<'a> PortController<'a> { }; self.issue_command(Arc::from(Command::identify(Box::new(callback))?))?; } else { - let sig = self.ahci_port_hba.signature; + let sig = self.ahci_port_hba.signature.read(); mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); } Ok(()) @@ -327,7 +310,7 @@ impl<'a> PortController<'a> { self.command_list()[slot].command = (size_of::() as u16 / 4) & 0x1F; self.command_list()[slot].command |= 1 << 7; - self.ahci_port_hba.command_issue |= 1 << slot; + self.ahci_port_hba.issue_command(slot); Ok(()) } @@ -373,7 +356,7 @@ impl<'a> PortController<'a> { } fn handle_interrupt(&mut self) { - let int_status = self.ahci_port_hba.interrupt_status; + let int_status = self.ahci_port_hba.interrupt_status.read(); if int_status.device_to_host_register_fis_interrupt() { assert_eq!( self.recieved_fis().device_to_host_register_fis.fis_type as u8, @@ -391,12 +374,14 @@ impl<'a> PortController<'a> { ); } - self.ahci_port_hba.interrupt_status = - AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true); + self.ahci_port_hba.interrupt_status.write( + AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true), + ); } if int_status.pio_setup_fis_interrupt() { - self.ahci_port_hba.interrupt_status = - AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true); + self.ahci_port_hba + .interrupt_status + .write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true)); } for i in 0..32 { @@ -407,7 +392,7 @@ impl<'a> PortController<'a> { // FIXME: This could cause a race condition when issuing a command if a different // interrupt triggers between us setting the command in the command slot and // actually issuing the command. - if (self.ahci_port_hba.command_issue & int_offset) != int_offset { + if (self.ahci_port_hba.command_issue.read() & int_offset) != int_offset { if let Some(_) = &self.command_slots[i] { self.finish_command(i); self.command_slots[i] = None; diff --git a/rust/sys/denali/src/ahci/port.rs b/rust/sys/denali/src/ahci/port.rs index d209791..e32abc5 100644 --- a/rust/sys/denali/src/ahci/port.rs +++ b/rust/sys/denali/src/ahci/port.rs @@ -1,4 +1,5 @@ use bitfield_struct::bitfield; +use mammoth::mem::Volatile; #[bitfield(u32)] pub struct AhciPortInterruptStatus { @@ -380,24 +381,55 @@ pub struct AhciDeviceSleep { } #[derive(Debug)] -#[repr(C, packed)] +#[repr(C)] pub struct AhciPortHba { - pub command_list_base: u64, - pub fis_base: u64, - pub interrupt_status: AhciPortInterruptStatus, - pub interrupt_enable: AhciPortInterruptEnable, - pub command: AhciPortCommandAndStatus, - __: u32, - pub task_file_data: AhciPortTaskFileData, - pub signature: u32, - pub sata_status: AhciSataStatus, - pub sata_control: AhciSataControl, - pub sata_error: AhciSataError, - pub sata_active: u32, - pub command_issue: u32, - pub sata_notification: u32, - pub fis_based_switching_ctl: AhciFisBasedSwitchingControl, - pub device_sleep: AhciDeviceSleep, + pub command_list_base: Volatile, + pub fis_base: Volatile, + pub interrupt_status: Volatile, + pub interrupt_enable: Volatile, + pub command: Volatile, + __: Volatile, + pub task_file_data: Volatile, + pub signature: Volatile, + pub sata_status: Volatile, + pub sata_control: Volatile, + pub sata_error: Volatile, + pub sata_active: Volatile, + pub command_issue: Volatile, + pub sata_notification: Volatile, + pub fis_based_switching_ctl: Volatile, + pub device_sleep: Volatile, } const _: () = assert!(size_of::() == 0x48); + +impl AhciPortHba { + pub fn init(&mut self, command_list_phys: u64, fis_phys: u64) { + let sata_status = self.sata_status.read(); + assert_eq!( + sata_status.device_detection(), + AhciDeviceDetection::CommunicationEstablished + ); + assert_eq!( + sata_status.interface_power_management(), + AhciInterfacePowerManagement::Active, + ); + + self.command_list_base.write(command_list_phys); + self.fis_base.write(fis_phys); + + self.interrupt_enable + .write(AhciPortInterruptEnable::from_bits(0xFFFF_FFFF)); + // Overwrite all errors. + self.sata_error.write(AhciSataError::from_bits(0xFFFF_FFFF)); + + self.command.update(|command| { + *command = command.with_fis_recieve_enable(true).with_start(true); + }); + } + + pub fn issue_command(&mut self, slot: usize) { + assert!(slot < 32); + self.command_issue.update(|ci| *ci |= 1 << slot); + } +} From 04effd44f82e4999a44a2921ce7372b6b25c30a1 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 31 Jan 2025 21:23:42 -0800 Subject: [PATCH 148/186] Move Ahci Port Controller to hold raw references. --- rust/lib/mammoth/src/mem.rs | 7 ++ rust/sys/denali/src/ahci/controller.rs | 106 ++++++++++--------------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 6cf662d..3b634af 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -152,3 +152,10 @@ where write!(f, "{:?}", self.read()) } } + +pub fn map_physical_and_leak(size: u64) -> (u64, u64) { + let (mem_cap, paddr) = syscall::memory_object_contiguous_physical(size).unwrap(); + let vaddr = syscall::address_space_map(&mem_cap).unwrap(); + mem_cap.release(); + (vaddr, paddr) +} diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 0f166bd..20dda6e 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -3,7 +3,7 @@ use core::ops::DerefMut; use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::sync::Mutex; -use mammoth::thread; +use mammoth::{mem, thread}; use mammoth::{mem::MemoryRegion, zion::ZError}; @@ -15,10 +15,7 @@ use crate::ahci::port::{ use super::command::{ CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand, }; -use super::{ - hba::AhciHba, - port::{AhciPortHba, AhciPortInterruptEnable, AhciSataError}, -}; +use super::{hba::AhciHba, port::AhciPortHba}; #[derive(Debug)] #[repr(C, packed)] @@ -51,7 +48,7 @@ pub struct PciDeviceHeader { pub struct AhciController { pci_memory: MemoryRegion, hba_memory: MemoryRegion, - ports: [Option>; 32], + ports: [Option; 32], } impl AhciController { @@ -140,7 +137,7 @@ impl AhciController { continue; } - self.ports[i] = Some(PortController::new(port)?); + self.ports[i] = Some(PortController::new(port)); self.ports[i].as_mut().unwrap().identify()?; } Ok(()) @@ -226,36 +223,51 @@ impl From<&Command> for HostToDeviceRegisterFis { } } -struct PortController<'a> { - ahci_port_hba: &'a mut AhciPortHba, +struct PortController { + ahci_port_hba: &'static mut AhciPortHba, + command_list: &'static mut CommandList, + received_fis: &'static mut ReceivedFis, + command_tables: &'static mut [CommandTable; 32], + command_slots: [Option>; 32], - command_structures: MemoryRegion, // FIXME: These should probably be something like a OnceCell (or OnceLock). sector_size: Arc>>, sector_cnt: Arc>>, } -impl<'a> PortController<'a> { - fn new(ahci_port_hba: &'a mut AhciPortHba) -> Result { - let (command_structures, command_paddr) = MemoryRegion::contiguous_physical(0x2500)?; +impl PortController { + fn new(ahci_port_hba: &'static mut AhciPortHba) -> Self { + let (command_vaddr, command_paddr) = mem::map_physical_and_leak(0x2500); ahci_port_hba.init(command_paddr, command_paddr + 0x400); - let mut controller = Self { - ahci_port_hba, - command_slots: [const { None }; 32], - command_structures, - sector_size: Arc::new(Mutex::new(None)), - sector_cnt: Arc::new(Mutex::new(None)), + let command_list = unsafe { (command_vaddr as *mut CommandList).as_mut().unwrap() }; + let received_fis = unsafe { + ((command_vaddr + 0x400) as *mut ReceivedFis) + .as_mut() + .unwrap() + }; + let command_tables = unsafe { + ((command_vaddr + 0x500) as *mut [CommandTable; 32]) + .as_mut() + .unwrap() }; // This leaves space for 8 prdt entries. for i in 0..32 { - controller.command_list()[i].command_table_base_addr = + command_list[i].command_table_base_addr = (command_paddr + 0x500) + (0x100 * (i as u64)); } - Ok(controller) + Self { + ahci_port_hba, + command_list, + received_fis, + command_tables, + command_slots: [const { None }; 32], + sector_size: Arc::new(Mutex::new(None)), + sector_cnt: Arc::new(Mutex::new(None)), + } } pub fn identify(&mut self) -> Result<(), ZError> { @@ -300,16 +312,15 @@ impl<'a> PortController<'a> { let slot = self.select_slot()?; self.command_slots[slot] = Some(command.clone()); - self.command_tables()[slot].command_fis.host_to_device = command.clone().as_ref().into(); + self.command_tables[slot].command_fis.host_to_device = command.clone().as_ref().into(); - self.command_tables()[slot].prdt[0].region_address = command.paddr; - self.command_tables()[slot].prdt[0].byte_count = 512 * (command.sector_cnt as u32); + self.command_tables[slot].prdt[0].region_address = command.paddr; + self.command_tables[slot].prdt[0].byte_count = 512 * (command.sector_cnt as u32); - self.command_list()[slot].prd_table_length = 1; + self.command_list[slot].prd_table_length = 1; - self.command_list()[slot].command = - (size_of::() as u16 / 4) & 0x1F; - self.command_list()[slot].command |= 1 << 7; + self.command_list[slot].command = (size_of::() as u16 / 4) & 0x1F; + self.command_list[slot].command |= 1 << 7; self.ahci_port_hba.issue_command(slot); Ok(()) } @@ -324,53 +335,22 @@ impl<'a> PortController<'a> { return Err(ZError::EXHAUSTED); } - fn command_list(&mut self) -> &mut CommandList { - unsafe { - self.command_structures - .mut_slice::() - .as_mut_ptr() - .cast::() - .as_mut() - .unwrap() - } - } - - fn recieved_fis(&mut self) -> &mut ReceivedFis { - unsafe { - self.command_structures.mut_slice::()[0x400..] - .as_mut_ptr() - .cast::() - .as_mut() - .unwrap() - } - } - - fn command_tables(&mut self) -> &mut [CommandTable; 32] { - unsafe { - self.command_structures.mut_slice::()[0x500..] - .as_mut_ptr() - .cast::<[CommandTable; 32]>() - .as_mut() - .unwrap() - } - } - fn handle_interrupt(&mut self) { let int_status = self.ahci_port_hba.interrupt_status.read(); if int_status.device_to_host_register_fis_interrupt() { assert_eq!( - self.recieved_fis().device_to_host_register_fis.fis_type as u8, + self.received_fis.device_to_host_register_fis.fis_type as u8, FisType::RegisterDeviceToHost as u8 ); - if self.recieved_fis().device_to_host_register_fis.error != 0 { + if self.received_fis.device_to_host_register_fis.error != 0 { mammoth::debug!( "D2H err: {:#0x}", - self.recieved_fis().device_to_host_register_fis.error + self.received_fis.device_to_host_register_fis.error ); mammoth::debug!( "Status: {:#0x}", - self.recieved_fis().device_to_host_register_fis.status + self.received_fis.device_to_host_register_fis.status ); } From 017367c4de1a0f5be3fe93952ff6584391d6dd9c Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 31 Jan 2025 21:38:06 -0800 Subject: [PATCH 149/186] Store ahci hba and pci device header as mut references --- rust/lib/mammoth/src/mem.rs | 13 +++++ rust/sys/denali/src/ahci/controller.rs | 81 ++++++++------------------ rust/sys/denali/src/bin/denali.rs | 3 +- 3 files changed, 38 insertions(+), 59 deletions(-) diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 3b634af..ea4a070 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -153,6 +153,19 @@ where } } +pub fn map_cap_and_leak(mem_cap: Capability) -> u64 { + let vaddr = syscall::address_space_map(&mem_cap).unwrap(); + mem_cap.release(); + vaddr +} + +pub fn map_direct_physical_and_leak(paddr: u64, size: u64) -> u64 { + let mem_cap = syscall::memory_object_direct_physical(paddr, size).unwrap(); + let vaddr = syscall::address_space_map(&mem_cap).unwrap(); + mem_cap.release(); + vaddr +} + pub fn map_physical_and_leak(size: u64) -> (u64, u64) { let (mem_cap, paddr) = syscall::memory_object_contiguous_physical(size).unwrap(); let vaddr = syscall::address_space_map(&mem_cap).unwrap(); diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 20dda6e..6ccd32e 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,7 +1,9 @@ use core::ops::DerefMut; +use core::ptr::addr_of_mut; use alloc::boxed::Box; use alloc::sync::Arc; +use mammoth::cap::Capability; use mammoth::sync::Mutex; use mammoth::{mem, thread}; @@ -46,26 +48,21 @@ pub struct PciDeviceHeader { } pub struct AhciController { - pci_memory: MemoryRegion, - hba_memory: MemoryRegion, + pci_header: &'static mut PciDeviceHeader, + hba: &'static mut AhciHba, ports: [Option; 32], } impl AhciController { - pub fn new(pci_memory: MemoryRegion) -> Self { - let pci_device_header = unsafe { - pci_memory - .mut_slice::() - .as_mut_ptr() - .cast::() - .as_mut() - .unwrap() - }; - let hba_memory = - MemoryRegion::direct_physical(pci_device_header.abar as u64, 0x1100).unwrap(); + pub fn new(pci_memory: Capability) -> Self { + let pci_vaddr = mem::map_cap_and_leak(pci_memory); + let pci_header = unsafe { (pci_vaddr as *mut PciDeviceHeader).as_mut().unwrap() }; + + let hba_vaddr = mem::map_direct_physical_and_leak(pci_header.abar as u64, 0x1100); + let hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() }; let mut controller = Self { - pci_memory, - hba_memory, + pci_header, + hba, ports: [const { None }; 32], }; controller.init(); @@ -73,31 +70,31 @@ impl AhciController { } fn init(&mut self) { - self.ahci_hba().init(); + self.hba.init(); self.init_ports().unwrap(); } fn irq_num(&self) -> u64 { - match self.pci_header().interrupt_pin { + match self.pci_header.interrupt_pin { 1 => mammoth::zion::kZIrqPci1, 2 => mammoth::zion::kZIrqPci2, 3 => mammoth::zion::kZIrqPci3, 4 => mammoth::zion::kZIrqPci4, _ => panic!( "Unrecognized pci interrupt pin {}", - self.pci_header().interrupt_pin + self.pci_header.interrupt_pin ), } } fn handle_irq(&mut self) { - for i in 0..self.ahci_hba().capabilities.read().num_ports() { + for i in 0..self.hba.capabilities.read().num_ports() { let int_offset = 1 << i; - if (self.ahci_hba().interrupt_status.read() & int_offset) == int_offset { + if (self.hba.interrupt_status.read() & int_offset) == int_offset { if let Some(port) = &mut self.ports[i as usize] { port.handle_interrupt(); - self.ahci_hba().interrupt_status.update(|is| { + self.hba.interrupt_status.update(|is| { *is &= !int_offset; }); } @@ -106,20 +103,16 @@ impl AhciController { } fn init_ports(&mut self) -> Result<(), ZError> { - for i in 0..(self.ahci_hba().capabilities.read().num_ports() as usize) { + for i in 0..(self.hba.capabilities.read().num_ports() as usize) { let port_index = 1 << i; - if (self.ahci_hba().port_implemented.read() & port_index) != port_index { + if (self.hba.port_implemented.read() & port_index) != port_index { mammoth::debug!("Skipping port {}, not implemented", i); continue; } let port_offset: usize = 0x100 + (0x80 * i); - let port_size = size_of::(); - let port_limit = port_offset + port_size; let port = unsafe { - self.hba_memory.mut_slice::()[port_offset..port_limit] - .as_mut_ptr() - .cast::() + (((self.hba as *mut _ as usize) + port_offset) as *mut AhciPortHba) .as_mut() .unwrap() }; @@ -142,28 +135,6 @@ impl AhciController { } Ok(()) } - - pub fn pci_header(&self) -> &mut PciDeviceHeader { - unsafe { - self.pci_memory - .mut_slice::() - .as_mut_ptr() - .cast::() - .as_mut() - .unwrap() - } - } - - pub fn ahci_hba(&self) -> &mut AhciHba { - unsafe { - self.hba_memory - .mut_slice::() - .as_mut_ptr() - .cast::() - .as_mut() - .unwrap() - } - } } pub fn spawn_irq_thread(controller: Arc>) -> thread::JoinHandle { @@ -171,13 +142,9 @@ pub fn spawn_irq_thread(controller: Arc>) -> thread::JoinH let irq_num = controller.lock().irq_num(); let irq_port = mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap()); - controller - .lock() - .ahci_hba() - .global_host_control - .update(|ghc| { - ghc.set_interrupt_enable(true); - }); + controller.lock().hba.global_host_control.update(|ghc| { + ghc.set_interrupt_enable(true); + }); loop { irq_port.recv_null().unwrap(); controller.lock().handle_irq(); diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index a5f0e68..a25a8fd 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -21,8 +21,7 @@ extern "C" fn main() -> z_err_t { .expect("Failed to get ahci info"); let ahci_controller = Arc::new(Mutex::new(AhciController::new( - mammoth::mem::MemoryRegion::from_cap(mammoth::cap::Capability::take(ahci_info.ahci_region)) - .unwrap(), + mammoth::cap::Capability::take(ahci_info.ahci_region), ))); let thread = spawn_irq_thread(ahci_controller.clone()); From c97d39c36b79fdbbf416cb1840e58e8080c8e2d3 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 31 Jan 2025 22:07:33 -0800 Subject: [PATCH 150/186] Make handle interrupt non-mutable in ahci controller. --- rust/sys/denali/src/ahci/controller.rs | 81 ++++++++++++++------------ rust/sys/denali/src/bin/denali.rs | 4 +- 2 files changed, 45 insertions(+), 40 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 6ccd32e..6869c63 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -49,8 +49,9 @@ pub struct PciDeviceHeader { pub struct AhciController { pci_header: &'static mut PciDeviceHeader, - hba: &'static mut AhciHba, + hba: Mutex<&'static mut AhciHba>, ports: [Option; 32], + hba_vaddr: u64, } impl AhciController { @@ -62,15 +63,16 @@ impl AhciController { let hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() }; let mut controller = Self { pci_header, - hba, + hba: Mutex::new(hba), ports: [const { None }; 32], + hba_vaddr, }; controller.init(); controller } fn init(&mut self) { - self.hba.init(); + self.hba.lock().init(); self.init_ports().unwrap(); } @@ -88,13 +90,14 @@ impl AhciController { } } - fn handle_irq(&mut self) { - for i in 0..self.hba.capabilities.read().num_ports() { + fn handle_irq(&self) { + let mut hba = self.hba.lock(); + for i in 0..hba.capabilities.read().num_ports() { let int_offset = 1 << i; - if (self.hba.interrupt_status.read() & int_offset) == int_offset { - if let Some(port) = &mut self.ports[i as usize] { + if (hba.interrupt_status.read() & int_offset) == int_offset { + if let Some(port) = &self.ports[i as usize] { port.handle_interrupt(); - self.hba.interrupt_status.update(|is| { + hba.interrupt_status.update(|is| { *is &= !int_offset; }); } @@ -103,16 +106,17 @@ impl AhciController { } fn init_ports(&mut self) -> Result<(), ZError> { - for i in 0..(self.hba.capabilities.read().num_ports() as usize) { + let hba = self.hba.lock(); + for i in 0..(hba.capabilities.read().num_ports() as usize) { let port_index = 1 << i; - if (self.hba.port_implemented.read() & port_index) != port_index { + if (hba.port_implemented.read() & port_index) != port_index { mammoth::debug!("Skipping port {}, not implemented", i); continue; } let port_offset: usize = 0x100 + (0x80 * i); let port = unsafe { - (((self.hba as *mut _ as usize) + port_offset) as *mut AhciPortHba) + ((self.hba_vaddr as usize + port_offset) as *mut AhciPortHba) .as_mut() .unwrap() }; @@ -137,17 +141,17 @@ impl AhciController { } } -pub fn spawn_irq_thread(controller: Arc>) -> thread::JoinHandle { +pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { let irq_thread = move || { - let irq_num = controller.lock().irq_num(); + let irq_num = controller.irq_num(); let irq_port = mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap()); - controller.lock().hba.global_host_control.update(|ghc| { + controller.hba.lock().global_host_control.update(|ghc| { ghc.set_interrupt_enable(true); }); loop { irq_port.recv_null().unwrap(); - controller.lock().handle_irq(); + controller.handle_irq(); } }; thread::spawn(irq_thread) @@ -191,12 +195,12 @@ impl From<&Command> for HostToDeviceRegisterFis { } struct PortController { - ahci_port_hba: &'static mut AhciPortHba, + ahci_port_hba: Mutex<&'static mut AhciPortHba>, command_list: &'static mut CommandList, received_fis: &'static mut ReceivedFis, command_tables: &'static mut [CommandTable; 32], - command_slots: [Option>; 32], + command_slots: Mutex<[Option>; 32]>, // FIXME: These should probably be something like a OnceCell (or OnceLock). sector_size: Arc>>, @@ -227,18 +231,19 @@ impl PortController { } Self { - ahci_port_hba, + ahci_port_hba: Mutex::new(ahci_port_hba), command_list, received_fis, command_tables, - command_slots: [const { None }; 32], + command_slots: Mutex::new([const { None }; 32]), sector_size: Arc::new(Mutex::new(None)), sector_cnt: Arc::new(Mutex::new(None)), } } pub fn identify(&mut self) -> Result<(), ZError> { - if self.ahci_port_hba.signature.read() == 0x101 { + let sig = self.ahci_port_hba.lock().signature.read(); + if sig == 0x101 { let sector_size = self.sector_size.clone(); let sector_cnt = self.sector_cnt.clone(); let callback = move |c: &Command| { @@ -265,11 +270,10 @@ impl PortController { .lock() .deref_mut() .insert(new_sector_size as u64); - let _ = sector_cnt.lock().deref_mut().insert(lba_count as u64); + let _ = sector_cnt.lock().deref_mut().insert(lba_count); }; self.issue_command(Arc::from(Command::identify(Box::new(callback))?))?; } else { - let sig = self.ahci_port_hba.signature.read(); mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); } Ok(()) @@ -277,7 +281,7 @@ impl PortController { fn issue_command(&mut self, command: Arc) -> Result<(), ZError> { let slot = self.select_slot()?; - self.command_slots[slot] = Some(command.clone()); + self.command_slots.lock()[slot] = Some(command.clone()); self.command_tables[slot].command_fis.host_to_device = command.clone().as_ref().into(); @@ -288,22 +292,22 @@ impl PortController { self.command_list[slot].command = (size_of::() as u16 / 4) & 0x1F; self.command_list[slot].command |= 1 << 7; - self.ahci_port_hba.issue_command(slot); + self.ahci_port_hba.lock().issue_command(slot); Ok(()) } fn select_slot(&self) -> Result { - for i in 0..self.command_slots.len() { - match self.command_slots[i] { - None => return Ok(i), - _ => {} + let slots = self.command_slots.lock(); + for i in 0..slots.len() { + if slots[i].is_none() { + return Ok(i); } } - return Err(ZError::EXHAUSTED); + Err(ZError::EXHAUSTED) } - fn handle_interrupt(&mut self) { - let int_status = self.ahci_port_hba.interrupt_status.read(); + fn handle_interrupt(&self) { + let int_status = self.ahci_port_hba.lock().interrupt_status.read(); if int_status.device_to_host_register_fis_interrupt() { assert_eq!( self.received_fis.device_to_host_register_fis.fis_type as u8, @@ -321,12 +325,13 @@ impl PortController { ); } - self.ahci_port_hba.interrupt_status.write( + self.ahci_port_hba.lock().interrupt_status.write( AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true), ); } if int_status.pio_setup_fis_interrupt() { self.ahci_port_hba + .lock() .interrupt_status .write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true)); } @@ -339,16 +344,16 @@ impl PortController { // FIXME: This could cause a race condition when issuing a command if a different // interrupt triggers between us setting the command in the command slot and // actually issuing the command. - if (self.ahci_port_hba.command_issue.read() & int_offset) != int_offset { - if let Some(_) = &self.command_slots[i] { - self.finish_command(i); - self.command_slots[i] = None; - } + if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset + && self.command_slots.lock()[i].is_some() + { + self.finish_command(i); + self.command_slots.lock()[i] = None; } } } fn finish_command(&self, slot: usize) { - self.command_slots[slot].as_ref().unwrap().callback() + self.command_slots.lock()[slot].as_ref().unwrap().callback() } } diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index a25a8fd..5c2370e 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -20,8 +20,8 @@ extern "C" fn main() -> z_err_t { .get_ahci_info() .expect("Failed to get ahci info"); - let ahci_controller = Arc::new(Mutex::new(AhciController::new( - mammoth::cap::Capability::take(ahci_info.ahci_region), + let ahci_controller = Arc::new(AhciController::new(mammoth::cap::Capability::take( + ahci_info.ahci_region, ))); let thread = spawn_irq_thread(ahci_controller.clone()); From caa1b9c952a10ab4568e5966a69c1dd870912554 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 01:29:26 -0800 Subject: [PATCH 151/186] Move AHCI controller to async. --- rust/sys/denali/src/ahci/controller.rs | 302 +++++++++++++++---------- rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/bin/denali.rs | 15 +- 3 files changed, 191 insertions(+), 127 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 6869c63..5c6849a 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,7 +1,10 @@ +use core::array; +use core::future::Future; +use core::ops::Deref; use core::ops::DerefMut; -use core::ptr::addr_of_mut; +use core::pin::Pin; +use core::task::{Context, Poll, Waker}; -use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::cap::Capability; use mammoth::sync::Mutex; @@ -73,8 +76,36 @@ impl AhciController { fn init(&mut self) { self.hba.lock().init(); + let hba = self.hba.lock(); + for i in 0..(hba.capabilities.read().num_ports() as usize) { + let port_index = 1 << i; + if (hba.port_implemented.read() & port_index) != port_index { + mammoth::debug!("Skipping port {}, not implemented", i); + continue; + } - self.init_ports().unwrap(); + let port_offset: usize = 0x100 + (0x80 * i); + let port = unsafe { + ((self.hba_vaddr as usize + port_offset) as *mut AhciPortHba) + .as_mut() + .unwrap() + }; + + let sata_status = port.sata_status.read(); + if (sata_status.device_detection() != AhciDeviceDetection::CommunicationEstablished) + || (sata_status.interface_power_management() + != AhciInterfacePowerManagement::Active) + { + mammoth::debug!( + "Skipping port {}, no communcation. Status: {:?}", + i, + sata_status + ); + continue; + } + + self.ports[i] = Some(PortController::new(port)); + } } fn irq_num(&self) -> u64 { @@ -105,37 +136,36 @@ impl AhciController { } } - fn init_ports(&mut self) -> Result<(), ZError> { - let hba = self.hba.lock(); - for i in 0..(hba.capabilities.read().num_ports() as usize) { - let port_index = 1 << i; - if (hba.port_implemented.read() & port_index) != port_index { - mammoth::debug!("Skipping port {}, not implemented", i); - continue; + pub async fn identify_ports(&self) -> Result<(), ZError> { + for port in self.ports.iter().flatten() { + let sig = port.get_signature(); + if sig == 0x101 { + let command = Command::identify()?; + mammoth::debug!("IDENT!"); + port.issue_command(&command)?.await; + let ident = command.memory_region.slice::(); + let new_sector_size = if ident[106] & (1 << 12) != 0 { + ident[117] as u32 | ((ident[118] as u32) << 16) + } else { + 512 + }; + + let lba_count = if ident[83] & (1 << 10) != 0 { + ident[100] as u64 + | (ident[101] as u64) << 16 + | (ident[102] as u64) << 32 + | (ident[103] as u64) << 48 + } else { + ident[60] as u64 | (ident[61] as u64) << 16 + }; + mammoth::debug!("Sector size: {:#0x}", new_sector_size); + mammoth::debug!("LBA Count: {:#0x}", lba_count); + + //self.sector_size = Some(new_sector_size as u64); + //self.sector_cnt = Some(lba_count); + } else { + mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); } - - let port_offset: usize = 0x100 + (0x80 * i); - let port = unsafe { - ((self.hba_vaddr as usize + port_offset) as *mut AhciPortHba) - .as_mut() - .unwrap() - }; - - let sata_status = port.sata_status.read(); - if (sata_status.device_detection() != AhciDeviceDetection::CommunicationEstablished) - || (sata_status.interface_power_management() - != AhciInterfacePowerManagement::Active) - { - mammoth::debug!( - "Skipping port {}, no communcation. Status: {:?}", - i, - sata_status - ); - continue; - } - - self.ports[i] = Some(PortController::new(port)); - self.ports[i].as_mut().unwrap().identify()?; } Ok(()) } @@ -151,12 +181,57 @@ pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { }); loop { irq_port.recv_null().unwrap(); + mammoth::debug!("Interrupt!"); controller.handle_irq(); } }; thread::spawn(irq_thread) } +pub async fn identify_ports(controller: Arc) { + controller.identify_ports().await.unwrap(); +} + +enum CommandStatus { + Empty, + NotSent, + Pending(Waker), + Complete, +} + +struct CommandFuture { + status: Arc>, +} + +impl CommandFuture { + fn new(status: Arc>) -> Self { + Self { status } + } +} + +impl Drop for CommandFuture { + fn drop(&mut self) { + *self.status.lock() = CommandStatus::Empty; + } +} + +impl Future for CommandFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let mut status = self.deref_mut().status.lock(); + match status.deref() { + CommandStatus::NotSent => { + *status = CommandStatus::Pending(cx.waker().clone()); + Poll::Pending + } + CommandStatus::Pending(_) => Poll::Pending, + CommandStatus::Complete => Poll::Ready(()), + CommandStatus::Empty => panic!("Polling empty command slot"), + } + } +} + struct Command { command: SataCommand, lba: u64, @@ -165,12 +240,10 @@ struct Command { #[allow(dead_code)] // We need to own this even if we never access it. memory_region: MemoryRegion, - - callback_internal: Box, } impl Command { - pub fn identify(callback: Box) -> Result { + pub fn identify() -> Result { let (memory_region, paddr) = MemoryRegion::contiguous_physical(512)?; Ok(Self { @@ -179,13 +252,8 @@ impl Command { sector_cnt: 1, paddr, memory_region, - callback_internal: callback, }) } - - pub fn callback(&self) { - (self.callback_internal)(self); - } } impl From<&Command> for HostToDeviceRegisterFis { @@ -194,17 +262,17 @@ impl From<&Command> for HostToDeviceRegisterFis { } } -struct PortController { - ahci_port_hba: Mutex<&'static mut AhciPortHba>, +struct CommandStructures { command_list: &'static mut CommandList, received_fis: &'static mut ReceivedFis, command_tables: &'static mut [CommandTable; 32], +} - command_slots: Mutex<[Option>; 32]>, +struct PortController { + ahci_port_hba: Mutex<&'static mut AhciPortHba>, + command_structures: Mutex, - // FIXME: These should probably be something like a OnceCell (or OnceLock). - sector_size: Arc>>, - sector_cnt: Arc>>, + command_slots: [Arc>; 32], } impl PortController { @@ -230,76 +298,57 @@ impl PortController { (command_paddr + 0x500) + (0x100 * (i as u64)); } + let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty))); + Self { ahci_port_hba: Mutex::new(ahci_port_hba), - command_list, - received_fis, - command_tables, - command_slots: Mutex::new([const { None }; 32]), - sector_size: Arc::new(Mutex::new(None)), - sector_cnt: Arc::new(Mutex::new(None)), + command_structures: Mutex::new(CommandStructures { + command_list, + received_fis, + command_tables, + }), + command_slots, } } - pub fn identify(&mut self) -> Result<(), ZError> { - let sig = self.ahci_port_hba.lock().signature.read(); - if sig == 0x101 { - let sector_size = self.sector_size.clone(); - let sector_cnt = self.sector_cnt.clone(); - let callback = move |c: &Command| { - mammoth::debug!("TESTING"); - let ident = c.memory_region.slice::(); - let new_sector_size = if ident[106] & (1 << 12) != 0 { - ident[117] as u32 | ((ident[118] as u32) << 16) - } else { - 512 - }; - - let lba_count = if ident[83] & (1 << 10) != 0 { - ident[100] as u64 - | (ident[101] as u64) << 16 - | (ident[102] as u64) << 32 - | (ident[103] as u64) << 48 - } else { - ident[60] as u64 | (ident[61] as u64) << 16 - }; - mammoth::debug!("Sector size: {:#0x}", new_sector_size); - mammoth::debug!("LBA Count: {:#0x}", lba_count); - - let _ = sector_size - .lock() - .deref_mut() - .insert(new_sector_size as u64); - let _ = sector_cnt.lock().deref_mut().insert(lba_count); - }; - self.issue_command(Arc::from(Command::identify(Box::new(callback))?))?; - } else { - mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); - } - Ok(()) + fn get_signature(&self) -> u32 { + self.ahci_port_hba.lock().signature.read() } - fn issue_command(&mut self, command: Arc) -> Result<(), ZError> { + fn issue_command(&self, command: &Command) -> Result { let slot = self.select_slot()?; - self.command_slots.lock()[slot] = Some(command.clone()); + let command_slot = self.command_slots[slot].clone(); + let future = CommandFuture::new(command_slot); - self.command_tables[slot].command_fis.host_to_device = command.clone().as_ref().into(); + let mut command_structures = self.command_structures.lock(); - self.command_tables[slot].prdt[0].region_address = command.paddr; - self.command_tables[slot].prdt[0].byte_count = 512 * (command.sector_cnt as u32); + command_structures.command_tables[slot] + .command_fis + .host_to_device = command.into(); - self.command_list[slot].prd_table_length = 1; + command_structures.command_tables[slot].prdt[0].region_address = command.paddr; + command_structures.command_tables[slot].prdt[0].byte_count = + 512 * (command.sector_cnt as u32); - self.command_list[slot].command = (size_of::() as u16 / 4) & 0x1F; - self.command_list[slot].command |= 1 << 7; + command_structures.command_list[slot].prd_table_length = 1; + + command_structures.command_list[slot].command = + (size_of::() as u16 / 4) & 0x1F; + command_structures.command_list[slot].command |= 1 << 7; + + // FIXME: This is technically a poor future implementation since it starts work before it + // is polled. self.ahci_port_hba.lock().issue_command(slot); - Ok(()) + + Ok(future) } fn select_slot(&self) -> Result { - let slots = self.command_slots.lock(); - for i in 0..slots.len() { - if slots[i].is_none() { + // TODO: We have a race condition here. + for i in 0..self.command_slots.len() { + let mut slot = self.command_slots[i].lock(); + if matches!(*slot, CommandStatus::Empty) { + *slot = CommandStatus::NotSent; return Ok(i); } } @@ -309,20 +358,18 @@ impl PortController { fn handle_interrupt(&self) { let int_status = self.ahci_port_hba.lock().interrupt_status.read(); if int_status.device_to_host_register_fis_interrupt() { + let received_fis = self + .command_structures + .lock() + .received_fis + .device_to_host_register_fis; assert_eq!( - self.received_fis.device_to_host_register_fis.fis_type as u8, + received_fis.fis_type as u8, FisType::RegisterDeviceToHost as u8 ); - if self.received_fis.device_to_host_register_fis.error != 0 { - mammoth::debug!( - "D2H err: {:#0x}", - self.received_fis.device_to_host_register_fis.error - ); - - mammoth::debug!( - "Status: {:#0x}", - self.received_fis.device_to_host_register_fis.status - ); + if received_fis.error != 0 { + mammoth::debug!("D2H err: {:#0x}", received_fis.error); + mammoth::debug!("Status: {:#0x}", received_fis.status); } self.ahci_port_hba.lock().interrupt_status.write( @@ -340,20 +387,25 @@ impl PortController { let int_offset = 1 << i; // If there is no longer a command issued on a slot and we have something in - // the command list we know that this is the command that finished. - // FIXME: This could cause a race condition when issuing a command if a different - // interrupt triggers between us setting the command in the command slot and - // actually issuing the command. - if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset - && self.command_slots.lock()[i].is_some() - { - self.finish_command(i); - self.command_slots.lock()[i] = None; + // the command list that is pending we know that this is the command that finished. + if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset { + let mut command_status = self.command_slots[i].lock(); + let mut did_complete = false; + match command_status.deref() { + CommandStatus::NotSent => { + did_complete = true; + } + CommandStatus::Pending(ref waker) => { + waker.wake_by_ref(); + did_complete = true; + } + _ => {} + } + + if did_complete { + *command_status = CommandStatus::Complete; + } } } } - - fn finish_command(&self, slot: usize) { - self.command_slots.lock()[slot].as_ref().unwrap().callback() - } } diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index 2fec39b..e91e29c 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -3,5 +3,6 @@ mod controller; mod hba; mod port; +pub use controller::identify_ports; pub use controller::spawn_irq_thread; pub use controller::AhciController; diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index 5c2370e..5adafc0 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -4,9 +4,14 @@ extern crate alloc; use alloc::sync::Arc; -use mammoth::{define_entry, sync::Mutex, zion::z_err_t}; +use mammoth::{ + define_entry, + sync::Mutex, + task::{Executor, Task}, + zion::z_err_t, +}; -use denali::ahci::{spawn_irq_thread, AhciController}; +use denali::ahci::{identify_ports, spawn_irq_thread, AhciController}; define_entry!(); @@ -24,8 +29,14 @@ extern "C" fn main() -> z_err_t { ahci_info.ahci_region, ))); + let mut executor = Executor::new(); + + executor.spawn(Task::new(identify_ports(ahci_controller.clone()))); + let thread = spawn_irq_thread(ahci_controller.clone()); + executor.run(); + thread.join().expect("Failed to wait on irq thread."); 0 } From b270c7c9aa2035f98448f978cadab2a5db6d0c6f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 01:37:51 -0800 Subject: [PATCH 152/186] Only trigger future on poll in controller. --- rust/sys/denali/src/ahci/controller.rs | 40 ++++++++++++++------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 5c6849a..4453e13 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -5,6 +5,7 @@ use core::ops::DerefMut; use core::pin::Pin; use core::task::{Context, Poll, Waker}; +use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::cap::Capability; use mammoth::sync::Mutex; @@ -201,11 +202,12 @@ enum CommandStatus { struct CommandFuture { status: Arc>, + trigger: Box, } impl CommandFuture { - fn new(status: Arc>) -> Self { - Self { status } + fn new(status: Arc>, trigger: Box) -> Self { + Self { status, trigger } } } @@ -219,10 +221,12 @@ impl Future for CommandFuture { type Output = (); fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let mut status = self.deref_mut().status.lock(); + let s = self.deref_mut(); + let mut status = s.status.lock(); match status.deref() { CommandStatus::NotSent => { *status = CommandStatus::Pending(cx.waker().clone()); + (s.trigger)(); Poll::Pending } CommandStatus::Pending(_) => Poll::Pending, @@ -269,7 +273,7 @@ struct CommandStructures { } struct PortController { - ahci_port_hba: Mutex<&'static mut AhciPortHba>, + ahci_port_hba: Arc>, command_structures: Mutex, command_slots: [Arc>; 32], @@ -301,7 +305,7 @@ impl PortController { let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty))); Self { - ahci_port_hba: Mutex::new(ahci_port_hba), + ahci_port_hba: Arc::new(Mutex::new(ahci_port_hba)), command_structures: Mutex::new(CommandStructures { command_list, received_fis, @@ -318,7 +322,15 @@ impl PortController { fn issue_command(&self, command: &Command) -> Result { let slot = self.select_slot()?; let command_slot = self.command_slots[slot].clone(); - let future = CommandFuture::new(command_slot); + + let ahci_port_hba_clone = self.ahci_port_hba.clone(); + let slot_clone = slot; + let future = CommandFuture::new( + command_slot, + Box::new(move || { + ahci_port_hba_clone.lock().issue_command(slot_clone); + }), + ); let mut command_structures = self.command_structures.lock(); @@ -336,10 +348,6 @@ impl PortController { (size_of::() as u16 / 4) & 0x1F; command_structures.command_list[slot].command |= 1 << 7; - // FIXME: This is technically a poor future implementation since it starts work before it - // is polled. - self.ahci_port_hba.lock().issue_command(slot); - Ok(future) } @@ -391,15 +399,9 @@ impl PortController { if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset { let mut command_status = self.command_slots[i].lock(); let mut did_complete = false; - match command_status.deref() { - CommandStatus::NotSent => { - did_complete = true; - } - CommandStatus::Pending(ref waker) => { - waker.wake_by_ref(); - did_complete = true; - } - _ => {} + if let CommandStatus::Pending(ref waker) = command_status.deref() { + waker.wake_by_ref(); + did_complete = true; } if did_complete { From 10e536acabf7b6f874491adbe00ee6f674a4f9e8 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 11:25:37 -0800 Subject: [PATCH 153/186] Add an async server implementation for Yunq. --- rust/lib/yunq/src/server.rs | 84 +++++++++++++++++++++++++++++ yunq/rust/src/codegen.rs | 104 ++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index dcfd03c..57b844a 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -1,7 +1,13 @@ +use core::future::Future; + use crate::buffer::ByteBuffer; +use alloc::sync::Arc; use alloc::vec::Vec; use mammoth::cap::Capability; +use mammoth::sync::Mutex; use mammoth::syscall; +use mammoth::task::Executor; +use mammoth::task::Task; use mammoth::thread; use mammoth::thread::JoinHandle; use mammoth::zion::z_cap_t; @@ -59,3 +65,81 @@ where { thread::spawn(move || server.server_loop()) } + +pub trait AsyncYunqServer +where + Self: Send + Sync + 'static, +{ + fn server_loop(self: Arc, executor: Arc>) { + loop { + let mut byte_buffer = ByteBuffer::<1024>::new(); + let mut cap_buffer = vec![0; 10]; + let (_, _, reply_port_cap) = syscall::endpoint_recv( + self.endpoint_cap(), + byte_buffer.mut_slice(), + &mut cap_buffer, + ) + .expect("Failed to call endpoint recv"); + + let method = byte_buffer + .at::(8) + .expect("Failed to access request length."); + let self_clone = self.clone(); + executor.lock().spawn(Task::new((async move || { + self_clone + .handle_request_and_response(method, byte_buffer, cap_buffer, reply_port_cap) + .await; + })())); + } + } + + fn handle_request_and_response( + &self, + method: u64, + mut byte_buffer: ByteBuffer<1024>, + mut cap_buffer: Vec, + reply_port_cap: Capability, + ) -> impl Future + Sync { + async move { + let resp = self + .handle_request(method, &mut byte_buffer, &mut cap_buffer) + .await; + + match resp { + Ok(resp_len) => syscall::reply_port_send( + reply_port_cap, + byte_buffer.slice(resp_len), + &cap_buffer, + ) + .expect("Failed to reply"), + Err(err) => { + crate::message::serialize_error(&mut byte_buffer, err); + syscall::reply_port_send(reply_port_cap, &byte_buffer.slice(0x10), &[]) + .expect("Failed to reply w/ error") + } + } + + () + } + } + + fn endpoint_cap(&self) -> &Capability; + + fn create_client_cap(&self) -> Result { + self.endpoint_cap() + .duplicate(!mammoth::zion::kZionPerm_Read) + } + fn handle_request( + &self, + method_number: u64, + byte_buffer: &mut ByteBuffer<1024>, + cap_buffer: &mut Vec, + ) -> impl Future> + Sync; +} + +pub fn spawn_async_server_thread(server: Arc, executor: Arc>) +where + T: AsyncYunqServer + Send + Sync + 'static, +{ + server.server_loop(executor); +} diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 94769f2..b022a33 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -392,13 +392,116 @@ fn generate_server(interface: &Interface) -> TokenStream { } } +fn generate_async_server_case(method: &Method) -> TokenStream { + let id = proc_macro2::Literal::u64_suffixed(method.number); + let name = ident(&method.name.to_case(Case::Snake)); + let maybe_req = method.request.clone().map(|r| ident(&r)); + let maybe_resp = method.response.clone().map(|r| ident(&r)); + match (maybe_req, maybe_resp) { + (Some(req), Some(_)) => quote! { + #id => { + let req = #req::parse_from_request(byte_buffer, cap_buffer)?; + let resp = self.handler.#name(req).await?; + cap_buffer.resize(0, 0); + let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; + Ok(resp_len) + }, + }, + (Some(req), None) => quote! { + #id => { + let req = #req::parse_from_request(byte_buffer, cap_buffer)?; + self.handler.#name(req).await?; + cap_buffer.resize(0, 0); + // TODO: Implement serialization for EmptyMessage so this is less hacky. + yunq::message::serialize_error(byte_buffer, ZError::from(0)); + Ok(0x10) + }, + }, + (None, Some(_)) => quote! { + #id => { + let resp = self.handler.#name().await?; + cap_buffer.resize(0, 0); + let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; + Ok(resp_len) + }, + }, + _ => unreachable!(), + } +} + +fn generate_async_server_method(method: &Method) -> TokenStream { + let name = ident(&method.name.to_case(Case::Snake)); + let maybe_req = method.request.clone().map(|r| ident(&r)); + let maybe_resp = method.response.clone().map(|r| ident(&r)); + match (maybe_req, maybe_resp) { + (Some(req), Some(resp)) => quote! { + fn #name (&self, req: #req) -> impl Future> + Sync; + }, + (Some(req), None) => quote! { + fn #name (&self, req: #req) -> impl Future> + Sync; + }, + (None, Some(resp)) => quote! { + fn #name (&self) -> impl Future> + Sync; + }, + _ => unreachable!(), + } +} + +fn generate_async_server(interface: &Interface) -> TokenStream { + let server_name = ident(&(String::from("Async") + &interface.name.clone() + "Server")); + let server_trait = ident(&(String::from("Async") + &interface.name.clone() + "ServerHandler")); + let server_trait_methods = interface.methods.iter().map(generate_async_server_method); + let server_match_cases = interface.methods.iter().map(generate_async_server_case); + quote! { + pub trait #server_trait { + #(#server_trait_methods)* + } + + pub struct #server_name { + endpoint_cap: Capability, + handler: T + } + + impl #server_name { + pub fn new(handler: T) -> Result { + Ok(Self { + endpoint_cap: syscall::endpoint_create()?, + handler, + }) + } + } + + impl yunq::server::AsyncYunqServer for #server_name { + fn endpoint_cap(&self) -> &Capability { + &self.endpoint_cap + } + + async fn handle_request( + &self, + method_number: u64, + byte_buffer: &mut ByteBuffer<1024>, + cap_buffer: &mut Vec, + ) -> Result { + match method_number { + #(#server_match_cases)* + + _ => Err(ZError::UNIMPLEMENTED) + } + } + } + } +} + fn generate_interface(interface: &Interface) -> TokenStream { let client = generate_client(interface); let server = generate_server(interface); + let async_server = generate_async_server(interface); quote! { #client #server + + #async_server } } @@ -428,6 +531,7 @@ pub fn generate_code(ast: &[Decl]) -> String { let interface_imports = if any_interfaces(ast) { quote! { + use core::future::Future; use mammoth::cap::Capability; use mammoth::syscall; } From a5cdd23f0bf673addb80e4a565205e0648ec2e34 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 12:11:59 -0800 Subject: [PATCH 154/186] Run denali server thread. --- rust/lib/mammoth/src/task/mod.rs | 4 +-- rust/lib/yunq/src/server.rs | 10 +++--- rust/sys/denali/src/ahci/controller.rs | 49 +++++++++++++++++++++----- rust/sys/denali/src/ahci/mod.rs | 1 + rust/sys/denali/src/bin/denali.rs | 20 ++++++++--- rust/sys/denali/src/denali_server.rs | 38 ++++++++++++++++++++ rust/sys/denali/src/lib.rs | 1 + 7 files changed, 104 insertions(+), 19 deletions(-) create mode 100644 rust/sys/denali/src/denali_server.rs diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs index 0b23a67..aeba68b 100644 --- a/rust/lib/mammoth/src/task/mod.rs +++ b/rust/lib/mammoth/src/task/mod.rs @@ -28,11 +28,11 @@ pub struct Task { id: TaskId, // FIXME: This only needs to be sync because of the CURRENT_EXECUTOR // needing to be shared between threads. - future: Pin + Sync>>, + future: Pin + Sync + Send>>, } impl Task { - pub fn new(future: impl Future + Sync + 'static) -> Task { + pub fn new(future: impl Future + Sync + Send + 'static) -> Task { Task { id: TaskId::new(), future: Box::pin(future), diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index 57b844a..b4e3340 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -99,7 +99,7 @@ where mut byte_buffer: ByteBuffer<1024>, mut cap_buffer: Vec, reply_port_cap: Capability, - ) -> impl Future + Sync { + ) -> impl Future + Sync + Send { async move { let resp = self .handle_request(method, &mut byte_buffer, &mut cap_buffer) @@ -134,12 +134,14 @@ where method_number: u64, byte_buffer: &mut ByteBuffer<1024>, cap_buffer: &mut Vec, - ) -> impl Future> + Sync; + ) -> impl Future> + Sync + Send; } -pub fn spawn_async_server_thread(server: Arc, executor: Arc>) +pub fn spawn_async_server_thread(server: Arc, executor: Arc>) -> JoinHandle where T: AsyncYunqServer + Send + Sync + 'static, { - server.server_loop(executor); + thread::spawn(move || { + server.server_loop(executor); + }) } diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 4453e13..e4f5e97 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -9,6 +9,7 @@ use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::cap::Capability; use mammoth::sync::Mutex; +use mammoth::syscall; use mammoth::{mem, thread}; use mammoth::{mem::MemoryRegion, zion::ZError}; @@ -141,10 +142,12 @@ impl AhciController { for port in self.ports.iter().flatten() { let sig = port.get_signature(); if sig == 0x101 { - let command = Command::identify()?; + let mut command = Command::identify()?; mammoth::debug!("IDENT!"); port.issue_command(&command)?.await; - let ident = command.memory_region.slice::(); + let memory_region = + MemoryRegion::from_cap(Capability::take(command.release_mem_cap()))?; + let ident = memory_region.slice::(); let new_sector_size = if ident[106] & (1 << 12) != 0 { ident[117] as u32 | ((ident[118] as u32) << 16) } else { @@ -170,6 +173,18 @@ impl AhciController { } Ok(()) } + + pub async fn issue_command(&self, port_num: usize, command: &Command) -> Result<(), ZError> { + assert!(port_num < 32); + + self.ports[port_num] + .as_ref() + .ok_or(ZError::INVALID_ARGUMENT)? + .issue_command(command)? + .await; + + Ok(()) + } } pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { @@ -202,11 +217,11 @@ enum CommandStatus { struct CommandFuture { status: Arc>, - trigger: Box, + trigger: Box, } impl CommandFuture { - fn new(status: Arc>, trigger: Box) -> Self { + fn new(status: Arc>, trigger: Box) -> Self { Self { status, trigger } } } @@ -236,28 +251,44 @@ impl Future for CommandFuture { } } -struct Command { +pub struct Command { command: SataCommand, lba: u64, sector_cnt: u16, paddr: u64, - #[allow(dead_code)] // We need to own this even if we never access it. - memory_region: MemoryRegion, + memory_region: Option, } impl Command { pub fn identify() -> Result { - let (memory_region, paddr) = MemoryRegion::contiguous_physical(512)?; + let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?; Ok(Self { command: SataCommand::IdentifyDevice, lba: 0, sector_cnt: 1, paddr, - memory_region, + memory_region: Some(memory_region), }) } + + pub fn read(lba: u64, lba_count: u16) -> Result { + let (memory_region, paddr) = + syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?; + + Ok(Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr, + memory_region: Some(memory_region), + }) + } + + pub fn release_mem_cap(&mut self) -> u64 { + self.memory_region.take().unwrap().release() + } } impl From<&Command> for HostToDeviceRegisterFis { diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index e91e29c..a38f81f 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -6,3 +6,4 @@ mod port; pub use controller::identify_ports; pub use controller::spawn_irq_thread; pub use controller::AhciController; +pub use controller::Command; diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index 5adafc0..ee84990 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -11,7 +11,8 @@ use mammoth::{ zion::z_err_t, }; -use denali::ahci::{identify_ports, spawn_irq_thread, AhciController}; +use denali::ahci::{self, identify_ports, spawn_irq_thread, AhciController}; +use denali::{denali_server::DenaliServerImpl, AsyncDenaliServer}; define_entry!(); @@ -29,14 +30,25 @@ extern "C" fn main() -> z_err_t { ahci_info.ahci_region, ))); - let mut executor = Executor::new(); + let executor = Arc::new(Mutex::new(Executor::new())); - executor.spawn(Task::new(identify_ports(ahci_controller.clone()))); + executor + .clone() + .lock() + .spawn(Task::new(identify_ports(ahci_controller.clone()))); let thread = spawn_irq_thread(ahci_controller.clone()); - executor.run(); + let denali_server = + Arc::new(AsyncDenaliServer::new(DenaliServerImpl::new(ahci_controller.clone())).unwrap()); + + let server_thread = yunq::server::spawn_async_server_thread(denali_server, executor.clone()); + + executor.clone().lock().run(); thread.join().expect("Failed to wait on irq thread."); + server_thread + .join() + .expect("Failed to wait on server thread."); 0 } diff --git a/rust/sys/denali/src/denali_server.rs b/rust/sys/denali/src/denali_server.rs new file mode 100644 index 0000000..ebea567 --- /dev/null +++ b/rust/sys/denali/src/denali_server.rs @@ -0,0 +1,38 @@ +use alloc::sync::Arc; +use mammoth::zion::ZError; + +use crate::{ + ahci::{AhciController, Command}, + AsyncDenaliServerHandler, ReadManyRequest, ReadRequest, ReadResponse, +}; + +pub struct DenaliServerImpl { + ahci_controller: Arc, +} + +impl DenaliServerImpl { + pub fn new(controller: Arc) -> Self { + DenaliServerImpl { + ahci_controller: controller, + } + } +} + +impl AsyncDenaliServerHandler for DenaliServerImpl { + async fn read(&self, req: ReadRequest) -> Result { + let mut command = Command::read(req.block.lba, req.block.size as u16)?; + self.ahci_controller + .issue_command(req.device_id as usize, &command) + .await?; + + Ok(ReadResponse { + device_id: req.device_id, + size: req.block.size, + memory: command.release_mem_cap(), + }) + } + + async fn read_many(&self, req: ReadManyRequest) -> Result { + Err(ZError::UNIMPLEMENTED) + } +} diff --git a/rust/sys/denali/src/lib.rs b/rust/sys/denali/src/lib.rs index ee83829..0d06e8b 100644 --- a/rust/sys/denali/src/lib.rs +++ b/rust/sys/denali/src/lib.rs @@ -5,3 +5,4 @@ use core::include; include!(concat!(env!("OUT_DIR"), "/yunq.rs")); pub mod ahci; +pub mod denali_server; From 6f0dfa8719558c68116e22ab0ce54e1cfa14a675 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 13:09:42 -0800 Subject: [PATCH 155/186] Register denali on yellowstone, handle read requests. --- rust/lib/mammoth/src/task/mod.rs | 41 ++++++++++++++++++++------ rust/lib/yunq/src/server.rs | 11 ++++--- rust/sys/denali/src/ahci/controller.rs | 1 - rust/sys/denali/src/bin/denali.rs | 17 +++++++++-- rust/sys/denali/src/denali_server.rs | 2 +- yunq/rust/src/codegen.rs | 6 ++-- 6 files changed, 56 insertions(+), 22 deletions(-) diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs index aeba68b..4d8e8d1 100644 --- a/rust/lib/mammoth/src/task/mod.rs +++ b/rust/lib/mammoth/src/task/mod.rs @@ -26,9 +26,7 @@ impl TaskId { pub struct Task { id: TaskId, - // FIXME: This only needs to be sync because of the CURRENT_EXECUTOR - // needing to be shared between threads. - future: Pin + Sync + Send>>, + future: Pin + Send>>, } impl Task { @@ -72,7 +70,7 @@ impl Wake for TaskWaker { } pub struct Executor { - tasks: BTreeMap, + tasks: Arc>>, // TODO: Consider a better datastructure for this. task_queue: Arc>>, waker_cache: BTreeMap, @@ -81,7 +79,7 @@ pub struct Executor { impl Executor { pub fn new() -> Executor { Executor { - tasks: BTreeMap::new(), + tasks: Arc::new(Mutex::new(BTreeMap::new())), task_queue: Arc::new(Mutex::new(VecDeque::new())), waker_cache: BTreeMap::new(), } @@ -89,7 +87,7 @@ impl Executor { pub fn spawn(&mut self, task: Task) { let task_id = task.id; - if self.tasks.insert(task_id, task).is_some() { + if self.tasks.lock().insert(task_id, task).is_some() { panic!("Task is already existed in executor map"); } self.task_queue.lock().push_back(task_id); @@ -97,7 +95,8 @@ impl Executor { fn run_ready_tasks(&mut self) { while let Some(task_id) = self.task_queue.lock().pop_front() { - let task = self.tasks.get_mut(&task_id).unwrap(); + let mut tasks = self.tasks.lock(); + let task = tasks.get_mut(&task_id).unwrap(); let waker = self .waker_cache .entry(task_id) @@ -105,7 +104,7 @@ impl Executor { let mut ctx = Context::from_waker(waker); match task.poll(&mut ctx) { Poll::Ready(()) => { - self.tasks.remove(&task_id); + tasks.remove(&task_id); self.waker_cache.remove(&task_id); } Poll::Pending => {} @@ -120,6 +119,30 @@ impl Executor { syscall::thread_sleep(50).unwrap(); } } + + pub fn new_spawner(&self) -> Spawner { + Spawner::new(self.tasks.clone(), self.task_queue.clone()) + } } -static CURRENT_EXECUTOR: Option = None; +pub struct Spawner { + tasks: Arc>>, + task_queue: Arc>>, +} + +impl Spawner { + fn new( + tasks: Arc>>, + task_queue: Arc>>, + ) -> Self { + Spawner { tasks, task_queue } + } + + pub fn spawn(&self, task: Task) { + let task_id = task.id; + if self.tasks.lock().insert(task_id, task).is_some() { + panic!("Task is already existed in executor map"); + } + self.task_queue.lock().push_back(task_id); + } +} diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index b4e3340..a5ded0b 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -4,9 +4,8 @@ use crate::buffer::ByteBuffer; use alloc::sync::Arc; use alloc::vec::Vec; use mammoth::cap::Capability; -use mammoth::sync::Mutex; use mammoth::syscall; -use mammoth::task::Executor; +use mammoth::task::Spawner; use mammoth::task::Task; use mammoth::thread; use mammoth::thread::JoinHandle; @@ -70,7 +69,7 @@ pub trait AsyncYunqServer where Self: Send + Sync + 'static, { - fn server_loop(self: Arc, executor: Arc>) { + fn server_loop(self: Arc, spawner: Spawner) { loop { let mut byte_buffer = ByteBuffer::<1024>::new(); let mut cap_buffer = vec![0; 10]; @@ -85,7 +84,7 @@ where .at::(8) .expect("Failed to access request length."); let self_clone = self.clone(); - executor.lock().spawn(Task::new((async move || { + spawner.spawn(Task::new((async move || { self_clone .handle_request_and_response(method, byte_buffer, cap_buffer, reply_port_cap) .await; @@ -137,11 +136,11 @@ where ) -> impl Future> + Sync + Send; } -pub fn spawn_async_server_thread(server: Arc, executor: Arc>) -> JoinHandle +pub fn spawn_async_server_thread(server: Arc, spawner: Spawner) -> JoinHandle where T: AsyncYunqServer + Send + Sync + 'static, { thread::spawn(move || { - server.server_loop(executor); + server.server_loop(spawner); }) } diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index e4f5e97..6a46440 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -197,7 +197,6 @@ pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { }); loop { irq_port.recv_null().unwrap(); - mammoth::debug!("Interrupt!"); controller.handle_irq(); } }; diff --git a/rust/sys/denali/src/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs index ee84990..0e831d3 100644 --- a/rust/sys/denali/src/bin/denali.rs +++ b/rust/sys/denali/src/bin/denali.rs @@ -11,8 +11,10 @@ use mammoth::{ zion::z_err_t, }; -use denali::ahci::{self, identify_ports, spawn_irq_thread, AhciController}; +use denali::ahci::{identify_ports, spawn_irq_thread, AhciController}; use denali::{denali_server::DenaliServerImpl, AsyncDenaliServer}; +use yellowstone_yunq::RegisterEndpointRequest; +use yunq::server::AsyncYunqServer; define_entry!(); @@ -42,7 +44,18 @@ extern "C" fn main() -> z_err_t { let denali_server = Arc::new(AsyncDenaliServer::new(DenaliServerImpl::new(ahci_controller.clone())).unwrap()); - let server_thread = yunq::server::spawn_async_server_thread(denali_server, executor.clone()); + let server_thread = yunq::server::spawn_async_server_thread( + denali_server.clone(), + executor.lock().new_spawner(), + ); + + let yellowstone = yellowstone_yunq::from_init_endpoint(); + yellowstone + .register_endpoint(&RegisterEndpointRequest { + endpoint_name: "denali".into(), + endpoint_capability: denali_server.create_client_cap().unwrap().release(), + }) + .unwrap(); executor.clone().lock().run(); diff --git a/rust/sys/denali/src/denali_server.rs b/rust/sys/denali/src/denali_server.rs index ebea567..a48cace 100644 --- a/rust/sys/denali/src/denali_server.rs +++ b/rust/sys/denali/src/denali_server.rs @@ -32,7 +32,7 @@ impl AsyncDenaliServerHandler for DenaliServerImpl { }) } - async fn read_many(&self, req: ReadManyRequest) -> Result { + async fn read_many(&self, _req: ReadManyRequest) -> Result { Err(ZError::UNIMPLEMENTED) } } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index b022a33..d80ef67 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -435,13 +435,13 @@ fn generate_async_server_method(method: &Method) -> TokenStream { let maybe_resp = method.response.clone().map(|r| ident(&r)); match (maybe_req, maybe_resp) { (Some(req), Some(resp)) => quote! { - fn #name (&self, req: #req) -> impl Future> + Sync; + fn #name (&self, req: #req) -> impl Future> + Sync + Send; }, (Some(req), None) => quote! { - fn #name (&self, req: #req) -> impl Future> + Sync; + fn #name (&self, req: #req) -> impl Future> + Sync + Send; }, (None, Some(resp)) => quote! { - fn #name (&self) -> impl Future> + Sync; + fn #name (&self) -> impl Future> + Sync + Send; }, _ => unreachable!(), } From c4dfa624fa3ea128572f6cfcda56b559143d7796 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:07:57 -0800 Subject: [PATCH 156/186] Fix repeated parsing in rust yunq. --- yunq/rust/src/codegen.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index d80ef67..237414b 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -112,7 +112,7 @@ fn parse_field(field: &Field) -> TokenStream { let rep_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; let rep_len = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; - yunq::message::parse_repeated(buf, rep_offset as usize, rep_len as usize)? + yunq::message::parse_repeated(buf, offset + rep_offset as usize, rep_len as usize)? }; }, Type::I64 => unimplemented!(), @@ -122,7 +122,7 @@ fn parse_field(field: &Field) -> TokenStream { let rep_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; let rep_len = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; - yunq::message::parse_repeated_message(buf, rep_offset as usize, rep_len as usize, &caps)? + yunq::message::parse_repeated_message(buf, offset + rep_offset as usize, rep_len as usize, &caps)? }; }, } @@ -206,6 +206,7 @@ fn generate_parse(message: &Message) -> TokenStream { Self: Sized, { if buf.at::(offset + 0)? != yunq::message::MESSAGE_IDENT { + mammoth::debug!("Expected IDENT at offest {:#x}, got {:#x}", offset, buf.at::(offset)?); return Err(ZError::INVALID_ARGUMENT); } // TODO: Parse core size. From 00f24249876636dd47adbd486560b331209f1415 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:08:35 -0800 Subject: [PATCH 157/186] Fix repeated message serialization in cpp yunq. --- lib/yunq/serialize.cpp | 2 +- lib/yunq/serialize.h | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/yunq/serialize.cpp b/lib/yunq/serialize.cpp index 7b7852d..9d58ac8 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -3,7 +3,7 @@ namespace yunq { namespace { -const uint64_t kIdentByte = 0x33441122; +const uint32_t kIdentByte = 0x33441122; } // namespace diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index b0c84c3..170917f 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -100,7 +100,7 @@ template void Serializer::WriteRepeatedMessage(uint64_t field_index, const glcr::Vector& value) { uint64_t next_offset = next_extension_; - uint64_t length = 0; + uint64_t length = value.size(); for (T& message : value) { uint64_t msg_length = 0; @@ -110,7 +110,6 @@ void Serializer::WriteRepeatedMessage(uint64_t field_index, } else { msg_length = message.SerializeToBytes(buffer_, offset_ + next_offset); } - length += msg_length; next_offset += msg_length; } @@ -119,7 +118,7 @@ void Serializer::WriteRepeatedMessage(uint64_t field_index, .length = (uint32_t)length, }; - next_extension_ += length; + next_extension_ = next_offset; buffer_.WriteAt(field_offset(field_index), ptr); } From 5ec05f9a88e7dda62ccdfbd5b8e68234a522ccff Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:08:59 -0800 Subject: [PATCH 158/186] Improve error message in victoriafalls ext2 reader. --- sys/victoriafalls/fs/ext2/ext2_block_reader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp index 80308c6..4e8a08e 100644 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp @@ -76,7 +76,7 @@ glcr::ErrorOr Ext2BlockReader::ReadBlocks( ReadResponse resp; auto status = denali_.Read(req, resp); if (!status.ok()) { - dbgln("Failed to read blocks: {}", status.message()); + dbgln("Failed to read block: {}", status.code()); return status.code(); } return mmth::OwnedMemoryRegion::FromCapability(resp.memory()); @@ -102,7 +102,7 @@ glcr::ErrorOr Ext2BlockReader::ReadBlocks( ReadResponse resp; auto status = denali_.ReadMany(req, resp); if (!status.ok()) { - dbgln("Failed to read blocks: {}", status.message()); + dbgln("Failed to read blocks: {}", status.code()); return status.code(); } return mmth::OwnedMemoryRegion::FromCapability(resp.memory()); From 49c3ff8499900d56ade16430dbdc88987e6dda65 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:09:28 -0800 Subject: [PATCH 159/186] Implement read_many for denali. --- rust/sys/denali/src/ahci/controller.rs | 10 +++++++++ rust/sys/denali/src/denali_server.rs | 29 +++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 6a46440..1508574 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -285,6 +285,16 @@ impl Command { }) } + pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self { + Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr: paddr, + memory_region: None, + } + } + pub fn release_mem_cap(&mut self) -> u64 { self.memory_region.take().unwrap().release() } diff --git a/rust/sys/denali/src/denali_server.rs b/rust/sys/denali/src/denali_server.rs index a48cace..54bc7a0 100644 --- a/rust/sys/denali/src/denali_server.rs +++ b/rust/sys/denali/src/denali_server.rs @@ -1,5 +1,5 @@ use alloc::sync::Arc; -use mammoth::zion::ZError; +use mammoth::{syscall, zion::ZError}; use crate::{ ahci::{AhciController, Command}, @@ -32,7 +32,30 @@ impl AsyncDenaliServerHandler for DenaliServerImpl { }) } - async fn read_many(&self, _req: ReadManyRequest) -> Result { - Err(ZError::UNIMPLEMENTED) + async fn read_many(&self, req: ReadManyRequest) -> Result { + let total_sector_cnt = req.blocks.iter().map(|b| b.size).sum(); + + // FIXME: Don't hardcode this. + let sector_size = 512; + + let (mem_cap, mut paddr) = + syscall::memory_object_contiguous_physical(sector_size * total_sector_cnt)?; + + for block in req.blocks { + let command = Command::read_manual(block.lba, block.size as u16, paddr); + + // TODO: We should actually be able to read all of these in parallel. + self.ahci_controller + .issue_command(req.device_id as usize, &command) + .await; + + paddr += block.size * sector_size; + } + + Ok(ReadResponse { + device_id: req.device_id, + size: total_sector_cnt, + memory: mem_cap.release(), + }) } } From feb7c8e839b348e4383902365101f2b7ebdef2f5 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:29:08 -0800 Subject: [PATCH 160/186] Increase scheduler frequency. --- zion/interrupt/apic_timer.cpp | 2 +- zion/interrupt/interrupt.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/zion/interrupt/apic_timer.cpp b/zion/interrupt/apic_timer.cpp index 9fbbaf6..8a78329 100644 --- a/zion/interrupt/apic_timer.cpp +++ b/zion/interrupt/apic_timer.cpp @@ -4,7 +4,7 @@ #include "interrupt/apic.h" #include "interrupt/timer.h" -const uint32_t kScheduleFrequency = 20; +const uint32_t kScheduleFrequency = 100; ApicTimer* gApicTimer = nullptr; void ApicTimer::Init() { diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 861e806..2c3692d 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -186,12 +186,12 @@ uint64_t cnt = 0; extern "C" void isr_apic_timer(); extern "C" void interrupt_apic_timer(InterruptFrame*) { cnt++; - if (cnt % 20 == 0) { + if (cnt % 100 == 0) { if (cnt == 20) { KernelHeap::DumpDebugData(); phys_mem::DumpPhysicalMemoryUsage(); } - dbgln("timer: {}s", cnt * 50 / 1000); + dbgln("timer: {}s", cnt * 10 / 1000); } gApic->SignalEOI(); gScheduler->Preempt(); From faa71d08c500f2b2ca1d62cbe6f783ff6051d388 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:29:38 -0800 Subject: [PATCH 161/186] Reduce wait in async executor. --- rust/lib/mammoth/src/task/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs index 4d8e8d1..44aab69 100644 --- a/rust/lib/mammoth/src/task/mod.rs +++ b/rust/lib/mammoth/src/task/mod.rs @@ -116,7 +116,7 @@ impl Executor { loop { self.run_ready_tasks(); // TODO: We need some sort of semaphore wait here. - syscall::thread_sleep(50).unwrap(); + syscall::thread_sleep(10).unwrap(); } } From 440de700f9bee4d69d1f168fd152d074aec6eafa Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:32:05 -0800 Subject: [PATCH 162/186] Remove denali cpp executable. --- sys/denali/CMakeLists.txt | 23 --- sys/denali/ahci/ahci.h | 271 ---------------------------- sys/denali/ahci/ahci_controller.cpp | 250 ------------------------- sys/denali/ahci/ahci_controller.h | 47 ----- sys/denali/ahci/ahci_port.cpp | 224 ----------------------- sys/denali/ahci/ahci_port.h | 51 ------ sys/denali/ahci/command.h | 10 - sys/denali/denali.cpp | 37 ---- sys/denali/denali_server.cpp | 59 ------ sys/denali/denali_server.h | 25 --- 10 files changed, 997 deletions(-) delete mode 100644 sys/denali/ahci/ahci.h delete mode 100644 sys/denali/ahci/ahci_controller.cpp delete mode 100644 sys/denali/ahci/ahci_controller.h delete mode 100644 sys/denali/ahci/ahci_port.cpp delete mode 100644 sys/denali/ahci/ahci_port.h delete mode 100644 sys/denali/ahci/command.h delete mode 100644 sys/denali/denali.cpp delete mode 100644 sys/denali/denali_server.cpp delete mode 100644 sys/denali/denali_server.h diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index 739b625..86fd4de 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,24 +1 @@ -add_executable(denali - ahci/ahci_controller.cpp - ahci/ahci_port.cpp - denali.cpp - denali_server.cpp - ) - - -target_include_directories(denali - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) - -target_link_libraries(denali - denali_yunq - glacier - mammoth - yellowstone_yunq - ) - -set_target_properties(denali PROPERTIES - COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" - LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" - ) - yunq_gen(lib/denali lib denali) diff --git a/sys/denali/ahci/ahci.h b/sys/denali/ahci/ahci.h deleted file mode 100644 index c927de7..0000000 --- a/sys/denali/ahci/ahci.h +++ /dev/null @@ -1,271 +0,0 @@ -#pragma once - -#include - -struct PciDeviceHeader { - uint16_t vendor_id; - uint16_t device_id; - uint16_t command_reg; - uint16_t status_reg; - uint8_t revision; - uint8_t prog_interface; - uint8_t subclass; - uint8_t class_code; - uint8_t cache_line_size; - uint8_t latency_timer; - uint8_t header_type; - uint8_t bist; - uint32_t bars[5]; - uint32_t abar; - uint32_t reserved0; - uint32_t subsystem_id; - uint32_t expansion_rom; - uint8_t cap_ptr; - uint8_t reserved1[7]; - uint8_t interrupt_line; - uint8_t interrupt_pin; - uint8_t min_grant; - uint8_t max_latency; -} __attribute__((packed)); - -struct PciMsiCap { - uint8_t cap_id; - uint8_t next_offset; - uint8_t message_control; - uint8_t reserved; - uint64_t message_address; - uint16_t message_data; -} __attribute__((packed)); - -const uint32_t kGlobalHostControl_HW_Reset = 1; -const uint32_t kGlobalHostControl_AHCI_Enable = (1 << 31); -const uint32_t kGlobalHostControl_Interrupt_Enable = (1 << 1); - -struct AhciHba { - uint32_t capabilities; - uint32_t global_host_control; - uint32_t interrupt_status; - uint32_t port_implemented; - uint32_t version; - uint32_t ccc_ctl; // 0x14, Command completion coalescing control - uint32_t ccc_pts; // 0x18, Command completion coalescing ports - uint32_t em_loc; // 0x1C, Enclosure management location - uint32_t em_ctl; // 0x20, Enclosure management control - uint32_t capabilities_ext; - uint32_t bohc; // 0x28, BIOS/OS handoff control and status -} __attribute__((packed)); - -const uint32_t kCommand_FIS_Receive_Enable = (1 << 4); -const uint32_t kCommand_Start = 1; - -const uint32_t kInterrupt_D2H_FIS = 1; -const uint32_t kInterrupt_PIO_FIS = (1 << 1); -const uint32_t kInterrupt_DMA_FIS = (1 << 2); -const uint32_t kInterrupt_DeviceBits_FIS = (1 << 3); -const uint32_t kInterrupt_Unknown_FIS = (1 << 4); - -struct AhciPortHba { - uint64_t command_list_base; - uint64_t fis_base; - uint32_t interrupt_status; - uint32_t interrupt_enable; - uint32_t command; - uint32_t reserved; - uint32_t task_file_data; - uint32_t signature; - uint32_t sata_status; - uint32_t sata_control; - uint32_t sata_error; - uint32_t sata_active; - uint32_t command_issue; - uint32_t sata_notification; - uint32_t fis_based_switching_ctl; - uint32_t device_sleep; -} __attribute__((packed)); - -struct CommandHeader { - uint16_t command; - uint16_t prd_table_length; - uint32_t prd_byte_count; - uint64_t command_table_base_addr; - uint64_t reserved1; - uint64_t reserved2; -} __attribute__((packed)); - -struct CommandList { - CommandHeader command_headers[32]; -} __attribute__((packed)); - -struct PhysicalRegionDescriptor { - uint64_t region_address; - uint32_t reserved; - // bit 0 must be one. - // 21:0 is byte count - // 31 is Interrupt on Completion - uint32_t byte_count; -} __attribute__((packed)); - -struct CommandTable { - uint8_t command_fis[64]; - uint8_t atapi_command[16]; - uint8_t reserved[48]; - PhysicalRegionDescriptor prdt[8]; -} __attribute__((packed)); - -typedef enum { - FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device - FIS_TYPE_REG_D2H = 0x34, // Register FIS - device to host - FIS_TYPE_DMA_ACT = 0x39, // DMA activate FIS - device to host - FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional - FIS_TYPE_DATA = 0x46, // Data FIS - bidirectional - FIS_TYPE_BIST = 0x58, // BIST activate FIS - bidirectional - FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host - FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host -} FIS_TYPE; - -struct DmaFis { - // DWORD 0 - uint8_t fis_type; // FIS_TYPE_DMA_SETUP - - uint8_t pmport : 4; // Port multiplier - uint8_t rsv0 : 1; // Reserved - uint8_t d : 1; // Data transfer direction, 1 - device to host - uint8_t i : 1; // Interrupt bit - uint8_t a : 1; // Auto-activate. Specifies if DMA Activate FIS is needed - - uint8_t rsved[2]; // Reserved - - // DWORD 1&2 - - uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer - // in host memory. SATA Spec says host specific and not - // in Spec. Trying AHCI spec might work. - - // DWORD 3 - uint32_t rsvd; // More reserved - - // DWORD 4 - uint32_t DMAbufOffset; // Byte offset into buffer. First 2 bits must be 0 - - // DWORD 5 - uint32_t TransferCount; // Number of bytes to transfer. Bit 0 must be 0 - - // DWORD 6 - uint32_t resvd; // Reserved -} __attribute__((packed)); - -struct PioSetupFis { - // DWORD 0 - uint8_t fis_type; // FIS_TYPE_PIO_SETUP - - uint8_t pmport : 4; // Port multiplier - uint8_t rsv0 : 1; // Reserved - uint8_t d : 1; // Data transfer direction, 1 - device to host - uint8_t i : 1; // Interrupt bit - uint8_t rsv1 : 1; - - uint8_t status; // Status register - uint8_t error; // Error register - - // DWORD 1 - uint8_t lba0; // LBA low register, 7:0 - uint8_t lba1; // LBA mid register, 15:8 - uint8_t lba2; // LBA high register, 23:16 - uint8_t device; // Device register - - // DWORD 2 - uint8_t lba3; // LBA register, 31:24 - uint8_t lba4; // LBA register, 39:32 - uint8_t lba5; // LBA register, 47:40 - uint8_t rsv2; // Reserved - - // DWORD 3 - uint8_t countl; // Count register, 7:0 - uint8_t counth; // Count register, 15:8 - uint8_t rsv3; // Reserved - uint8_t e_status; // New value of status register - - // DWORD 4 - uint16_t tc; // Transfer count - uint8_t rsv4[2]; // Reserved -} __attribute__((packed)); - -const uint8_t kIdentifyDevice = 0xEC; -const uint8_t kDmaReadExt = 0x25; - -struct HostToDeviceRegisterFis { - uint8_t fis_type; // FIS_TYPE_REG_H2D - uint8_t pmp_and_c; - uint8_t command; // Command register - uint8_t featurel; // Feature register, 7:0 - - // DWORD 1 - uint8_t lba0; // LBA low register, 7:0 - uint8_t lba1; // LBA mid register, 15:8 - uint8_t lba2; // LBA high register, 23:16 - uint8_t device; // Device register - - // DWORD 2 - uint8_t lba3; // LBA register, 31:24 - uint8_t lba4; // LBA register, 39:32 - uint8_t lba5; // LBA register, 47:40 - uint8_t featureh; // Feature register, 15:8 - - // DWORD 3 - uint16_t count; - uint8_t icc; // Isochronous command completion - uint8_t control; // Control register - - // DWORD 4 - uint32_t reserved; // Reserved -} __attribute__((packed)); - -struct DeviceToHostRegisterFis { - // DWORD 0 - uint8_t fis_type; // FIS_TYPE_REG_D2H - - uint8_t pmport_and_i; - - uint8_t status; // Status register - uint8_t error; // Error register - - // DWORD 1 - uint8_t lba0; // LBA low register, 7:0 - uint8_t lba1; // LBA mid register, 15:8 - uint8_t lba2; // LBA high register, 23:16 - uint8_t device; // Device register - - // DWORD 2 - uint8_t lba3; // LBA register, 31:24 - uint8_t lba4; // LBA register, 39:32 - uint8_t lba5; // LBA register, 47:40 - uint8_t reserved1; - - // DWORD 3 - uint16_t count; - uint16_t reserved2; - - uint32_t reserved3; -} __attribute__((packed)); - -struct SetDeviceBitsFis { - uint8_t fis_type; - uint8_t pmport_and_i; - uint8_t status; - uint8_t error; - uint32_t reserved; -} __attribute__((packed)); - -struct ReceivedFis { - DmaFis dma_fis; - uint32_t reserved0; - - PioSetupFis pio_set_fis; - uint32_t reserved1[3]; - - DeviceToHostRegisterFis device_to_host_register_fis; - uint32_t reserved2; - - SetDeviceBitsFis set_device_bits_fis; - uint8_t unknown_fis[64]; -} __attribute__((packed)); diff --git a/sys/denali/ahci/ahci_controller.cpp b/sys/denali/ahci/ahci_controller.cpp deleted file mode 100644 index 96fc6e8..0000000 --- a/sys/denali/ahci/ahci_controller.cpp +++ /dev/null @@ -1,250 +0,0 @@ -#include "ahci/ahci_controller.h" - -#include -#include -#include -#include -#include - -namespace { - -const uint64_t kGhc_InteruptEnable = 0x2; - -void interrupt_thread(void* void_driver) { - AhciController* driver = static_cast(void_driver); - - driver->InterruptLoop(); - - crash("Driver returned from interrupt loop", glcr::INTERNAL); -} - -} // namespace - -glcr::ErrorOr> AhciController::Init( - mmth::OwnedMemoryRegion&& pci_region) { - glcr::UniquePtr driver( - new AhciController(glcr::Move(pci_region))); - RET_ERR(driver->LoadHbaRegisters()); - driver->DumpCapabilities(); - RET_ERR(driver->ResetHba()); - RET_ERR(driver->RegisterIrq()); - RET_ERR(driver->LoadPorts()); - // driver->DumpPorts(); - return driver; -} - -glcr::ErrorOr AhciController::GetDevice(uint64_t id) { - if (id >= num_ports_) { - return glcr::INVALID_ARGUMENT; - } - - if (ports_[id].empty()) { - return glcr::NOT_FOUND; - } - - return ports_[id].get(); -} - -void AhciController::DumpCapabilities() { - dbgln("AHCI Capabilities:"); - uint32_t caps = ahci_hba_->capabilities; - - if (caps & 0x20) { - dbgln("External SATA"); - } - if (caps & 0x40) { - dbgln("Enclosure Management"); - } - if (caps & 0x80) { - dbgln("Command Completion Coalescing"); - } - if (caps & 0x2000) { - dbgln("Partial State Capable"); - } - if (caps & 0x4000) { - dbgln("Slumber state capable"); - } - if (caps & 0x8000) { - dbgln("PIO Multiple DRQ Block"); - } - if (caps & 0x1'0000) { - dbgln("FIS-Based Switching"); - } - if (caps & 0x2'0000) { - dbgln("Port Multiplier"); - } - if (caps & 0x4'0000) { - dbgln("AHCI mode only"); - } - dbgln("Speed support: {}", (caps & 0xF0'0000) >> 20); - if (caps & 0x100'0000) { - dbgln("Command list override"); - } - if (caps & 0x200'0000) { - dbgln("Activity LED"); - } - if (caps & 0x400'0000) { - dbgln("Aggresive link power management"); - } - if (caps & 0x800'0000) { - dbgln("Staggered spin up"); - } - if (caps & 0x1000'0000) { - dbgln("Mechanical Switch Presence"); - } - if (caps & 0x2000'0000) { - dbgln("SNotification Register"); - } - if (caps & 0x4000'0000) { - dbgln("Native Command Queueing"); - } - if (caps & 0x8000'0000) { - dbgln("64bit Addressing"); - } - - // Secondary. - caps = ahci_hba_->capabilities_ext; - if (caps & 0x1) { - dbgln("BIOS/OS handoff"); - } - if (caps & 0x2) { - dbgln("NVMHCI Present"); - } - if (caps & 0x4) { - dbgln("Auto partial to slumber tranisitions"); - } - if (caps & 0x8) { - dbgln("Device sleep"); - } - if (caps & 0x10) { - dbgln("Aggressive device sleep management"); - } - - dbgln("Control {x}", ahci_hba_->global_host_control); -} - -void AhciController::DumpPorts() { - for (uint64_t i = 0; i < 6; i++) { - if (ports_[i].empty()) { - continue; - } - - dbgln(""); - dbgln("Port {}:", i); - ports_[i]->DumpInfo(); - } -} - -void AhciController::InterruptLoop() { - dbgln("Starting interrupt loop"); - while (true) { - uint64_t bytes, caps; - check(ZPortRecv(irq_port_cap_, &bytes, nullptr, &caps, nullptr)); - for (uint64_t i = 0; i < num_ports_; i++) { - if (!ports_[i].empty() && (ahci_hba_->interrupt_status & (1 << i))) { - ports_[i]->HandleIrq(); - ahci_hba_->interrupt_status &= ~(1 << i); - } - } - } -} - -glcr::ErrorCode AhciController::LoadCapabilities() { - if (!(pci_device_header_->status_reg & 0x10)) { - dbgln("No caps!"); - return glcr::FAILED_PRECONDITION; - } - volatile uint8_t* base = - reinterpret_cast(pci_device_header_); - uint16_t offset = pci_device_header_->cap_ptr; - do { - volatile uint16_t* cap = - reinterpret_cast(base + offset); - switch (*cap & 0xFF) { - case 0x01: - dbgln("Power Management"); - break; - case 0x05: - dbgln("MSI"); - break; - case 0x12: - dbgln("SATA"); - break; - default: - dbgln("Unrecognized cap"); - break; - } - - offset = (*cap & 0xFF00) >> 8; - } while (offset); - return glcr::OK; -} - -glcr::ErrorCode AhciController::RegisterIrq() { - if (pci_device_header_->interrupt_pin == 0) { - crash("Can't register IRQ without a pin num", glcr::INVALID_ARGUMENT); - } - uint64_t irq_num = 0; - switch (pci_device_header_->interrupt_pin) { - case 1: - irq_num = kZIrqPci1; - break; - case 2: - irq_num = kZIrqPci2; - break; - case 3: - irq_num = kZIrqPci3; - break; - case 4: - irq_num = kZIrqPci4; - break; - } - - RET_ERR(ZIrqRegister(irq_num, &irq_port_cap_)); - irq_thread_ = Thread(interrupt_thread, this); - ahci_hba_->global_host_control |= kGhc_InteruptEnable; - return glcr::OK; -} - -glcr::ErrorCode AhciController::LoadHbaRegisters() { - ahci_region_ = mmth::OwnedMemoryRegion ::DirectPhysical( - pci_device_header_->abar, 0x1100); - ahci_hba_ = reinterpret_cast(ahci_region_.vaddr()); - num_ports_ = (ahci_hba_->capabilities & 0x1F) + 1; - num_commands_ = ((ahci_hba_->capabilities & 0x1F00) >> 8) + 1; - - return glcr::OK; -} - -glcr::ErrorCode AhciController::ResetHba() { - ahci_hba_->global_host_control |= kGlobalHostControl_HW_Reset; - - // TODO: Consider sleeping here. - while (ahci_hba_->global_host_control & kGlobalHostControl_HW_Reset) { - continue; - } - - ahci_hba_->global_host_control |= kGlobalHostControl_AHCI_Enable; - - return static_cast(ZThreadSleep(50)); -} - -glcr::ErrorCode AhciController::LoadPorts() { - for (uint8_t i = 0; i <= num_ports_; i++) { - if (!(ahci_hba_->port_implemented & (1 << i))) { - continue; - } - - uint64_t port_addr = - reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); - AhciPortHba* port = reinterpret_cast(port_addr); - if ((port->sata_status & 0x103) != 0x103) { - continue; - } - - ports_[i] = new AhciPort(reinterpret_cast(port_addr)); - // TODO: Maybe continue to the next device if this fails. - RET_ERR(ports_[i]->Identify()); - } - return glcr::OK; -} diff --git a/sys/denali/ahci/ahci_controller.h b/sys/denali/ahci/ahci_controller.h deleted file mode 100644 index fba32ef..0000000 --- a/sys/denali/ahci/ahci_controller.h +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "ahci/ahci.h" -#include "ahci/ahci_port.h" - -class AhciController { - public: - static glcr::ErrorOr> Init( - mmth::OwnedMemoryRegion&& ahci_phys); - glcr::ErrorCode RegisterIrq(); - - void InterruptLoop(); - - glcr::ErrorOr GetDevice(uint64_t id); - - void DumpCapabilities(); - void DumpPorts(); - - private: - mmth::OwnedMemoryRegion pci_region_; - volatile PciDeviceHeader* pci_device_header_ = nullptr; - mmth::OwnedMemoryRegion ahci_region_; - volatile AhciHba* ahci_hba_ = nullptr; - - glcr::UniquePtr ports_[32]; - - Thread irq_thread_; - uint64_t irq_port_cap_ = 0; - - uint8_t num_ports_; - uint8_t num_commands_; - - glcr::ErrorCode LoadCapabilities(); - glcr::ErrorCode LoadHbaRegisters(); - glcr::ErrorCode ResetHba(); - glcr::ErrorCode LoadPorts(); - - AhciController(mmth::OwnedMemoryRegion&& pci_region) - : pci_region_(glcr::Move(pci_region)), - pci_device_header_( - reinterpret_cast(pci_region_.vaddr())) {} -}; diff --git a/sys/denali/ahci/ahci_port.cpp b/sys/denali/ahci/ahci_port.cpp deleted file mode 100644 index 21c0501..0000000 --- a/sys/denali/ahci/ahci_port.cpp +++ /dev/null @@ -1,224 +0,0 @@ -#include "ahci/ahci_port.h" - -#include -#include -#include - -AhciPort::AhciPort(AhciPortHba* port) : port_struct_(port) { - if ((port_struct_->sata_status & 0x103) != 0x103) { - crash("Creating device on port without a device", - glcr::FAILED_PRECONDITION); - } - - // 0x0-0x400 -> Command List - // 0x400-0x500 -> Received FIS - // 0x500-0x2500 -> Command Tables (0x100 each) (Max PRDT Length is 8 for now) - uint64_t paddr; - command_structures_ = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x2500, &paddr); - - command_list_ = reinterpret_cast(command_structures_.vaddr()); - port_struct_->command_list_base = paddr; - - received_fis_ = - reinterpret_cast(command_structures_.vaddr() + 0x400); - port_struct_->fis_base = paddr + 0x400; - port_struct_->command |= kCommand_FIS_Receive_Enable; - - command_tables_ = glcr::ArrayView( - reinterpret_cast(command_structures_.vaddr() + 0x500), 32); - - commands_issued_ = 0; - command_signals_ = glcr::Array(32); - for (uint64_t i = 0; i < 32; i++) { - // This leaves space for 2 prdt entries. - command_list_->command_headers[i].command_table_base_addr = - (paddr + 0x500) + (0x100 * i); - } - port_struct_->interrupt_enable = 0xFFFFFFFF; - // kInterrupt_D2H_FIS | kInterrupt_PIO_FIS | kInterrupt_DMA_FIS | - // kInterrupt_DeviceBits_FIS | kInterrupt_Unknown_FIS; - port_struct_->sata_error = -1; - port_struct_->command |= kCommand_Start; -} - -glcr::ErrorCode AhciPort::Identify() { - if (IsSata()) { - CommandInfo identify{ - .command = kIdentifyDevice, - .lba = 0, - .sectors = 1, - .paddr = 0, - }; - auto region = - mmth::OwnedMemoryRegion::ContiguousPhysical(0x200, &identify.paddr); - ASSIGN_OR_RETURN(auto* sem, IssueCommand(identify)); - sem->Wait(); - uint16_t* ident = reinterpret_cast(region.vaddr()); - if (ident[106] & (1 << 12)) { - sector_size_ = *reinterpret_cast(ident + 117); - } else { - sector_size_ = 512; - } - - if (ident[83] & (1 << 10)) { - lba_count_ = *reinterpret_cast(ident + 100); - } else { - lba_count_ = *reinterpret_cast(ident + 60); - } - dbgln("Sector size: {x}", sector_size_); - dbgln("LBA Count: {x}", lba_count_); - is_init_ = true; - } - return glcr::OK; -} - -glcr::ErrorOr AhciPort::IssueRead(uint64_t lba, - uint16_t sector_cnt, - uint64_t paddr) { - CommandInfo read{ - .command = kDmaReadExt, - .lba = lba, - .sectors = sector_cnt, - .paddr = paddr, - }; - return IssueCommand(read); -} - -glcr::ErrorOr AhciPort::IssueCommand( - const CommandInfo& command) { - uint64_t slot; - for (slot = 0; slot < 32; slot++) { - if (!(commands_issued_ & (1 << slot))) { - break; - } - } - if (slot == 32) { - dbgln("All slots full"); - return glcr::INTERNAL; - } - - auto* fis = reinterpret_cast( - command_tables_[slot].command_fis); - *fis = HostToDeviceRegisterFis{ - .fis_type = FIS_TYPE_REG_H2D, - .pmp_and_c = 0x80, - .command = command.command, - .featurel = 0, - - .lba0 = static_cast(command.lba & 0xFF), - .lba1 = static_cast((command.lba >> 8) & 0xFF), - .lba2 = static_cast((command.lba >> 16) & 0xFF), - .device = (1 << 6), // ATA LBA Mode - - .lba3 = static_cast((command.lba >> 24) & 0xFF), - .lba4 = static_cast((command.lba >> 32) & 0xFF), - .lba5 = static_cast((command.lba >> 40) & 0xFF), - .featureh = 0, - - .count = command.sectors, - .icc = 0, - .control = 0, - - .reserved = 0, - }; - - command_tables_[slot].prdt[0].region_address = command.paddr; - command_tables_[slot].prdt[0].byte_count = 512 * command.sectors; - - command_list_->command_headers[slot].prd_table_length = 1; - command_list_->command_headers[slot].command = - (sizeof(HostToDeviceRegisterFis) / 4) & 0x1F; - // Set prefetch bit. - command_list_->command_headers[slot].command |= (1 << 7); - - // TODO: Synchronization-wise we need to ensure this is set in the same - // critical section as where we select a slot. - commands_issued_ |= (1 << slot); - port_struct_->command_issue |= (1 << slot); - - return &command_signals_[slot]; -} - -void AhciPort::DumpInfo() { - dbgln("Comlist: {x}", port_struct_->command_list_base); - dbgln("FIS: {x}", port_struct_->fis_base); - dbgln("Command: {x}", port_struct_->command); - dbgln("Signature: {x}", port_struct_->signature); - dbgln("SATA status: {x}", port_struct_->sata_status); - dbgln("SATA error: {x}", port_struct_->sata_error); - dbgln("Int status: {x}", port_struct_->interrupt_status); - dbgln("Int enable: {x}", port_struct_->interrupt_enable); -} - -bool CheckFisType(FIS_TYPE expected, uint8_t actual) { - if (expected == actual) { - return true; - } - dbgln("BAD FIS TYPE (exp,act): {x}, {x}", static_cast(expected), - static_cast(actual)); - return false; -} - -void AhciPort::HandleIrq() { - uint32_t int_status = port_struct_->interrupt_status; - port_struct_->interrupt_status = int_status; - - bool has_error = false; - if (int_status & kInterrupt_D2H_FIS) { - volatile DeviceToHostRegisterFis& fis = - received_fis_->device_to_host_register_fis; - if (!CheckFisType(FIS_TYPE_REG_D2H, fis.fis_type)) { - return; - } - // Check is init to avoid showing an error from the COMRESET operation. - if (fis.error && is_init_) { - dbgln("D2H err: {x}", fis.error); - - dbgln("status: {x}", fis.status); - dbgln("Error: {x}", port_struct_->sata_error); - has_error = true; - } - } - if (int_status & kInterrupt_PIO_FIS) { - volatile PioSetupFis& fis = received_fis_->pio_set_fis; - if (!CheckFisType(FIS_TYPE_PIO_SETUP, fis.fis_type)) { - return; - } - if (fis.error) { - dbgln("PIO err: {x}", fis.error); - dbgln("status: {x}", fis.status); - has_error = true; - } - } - if (int_status & kInterrupt_DMA_FIS) { - volatile DmaFis& fis = received_fis_->dma_fis; - if (!CheckFisType(FIS_TYPE_DMA_SETUP, fis.fis_type)) { - return; - } - // TODO: Actually do something with this FIS. - } - if (int_status & kInterrupt_DeviceBits_FIS) { - volatile SetDeviceBitsFis& fis = received_fis_->set_device_bits_fis; - if (!CheckFisType(FIS_TYPE_DEV_BITS, fis.fis_type)) { - return; - } - if (fis.error) { - dbgln("SetDeviceBits err: {x}", fis.error); - dbgln("status: {x}", fis.status); - has_error = true; - } - } - if (int_status & kInterrupt_Unknown_FIS) { - dbgln("Unknown FIS recieved, type: {x}", received_fis_->unknown_fis[0]); - } - uint32_t commands_finished = commands_issued_ & ~port_struct_->command_issue; - - for (uint64_t i = 0; i < 32; i++) { - if (commands_finished & (1 << i)) { - // TODO: Pass error codes to the callback. - command_signals_[i].Signal(); - commands_issued_ &= ~(1 << i); - } - } -} diff --git a/sys/denali/ahci/ahci_port.h b/sys/denali/ahci/ahci_port.h deleted file mode 100644 index fc9b2df..0000000 --- a/sys/denali/ahci/ahci_port.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include "ahci/ahci.h" -#include "ahci/command.h" - -class AhciPort { - public: - AhciPort() {} - // Caller retains ownership of the pointer. - AhciPort(AhciPortHba* port_struct); - - void DumpInfo(); - - bool IsSata() { return port_struct_->signature == 0x101; } - bool IsInit() { return is_init_; } - - glcr::ErrorCode Identify(); - - glcr::ErrorOr IssueRead(uint64_t lba, uint16_t sector_cnt, - uint64_t paddr); - - void HandleIrq(); - - AhciPort(const AhciPort&) = delete; - AhciPort& operator=(const AhciPort&) = delete; - - private: - volatile AhciPortHba* port_struct_ = nullptr; - mmth::OwnedMemoryRegion command_structures_; - - volatile CommandList* command_list_ = nullptr; - volatile ReceivedFis* received_fis_ = nullptr; - glcr::ArrayView command_tables_; - - glcr::Array command_signals_; - uint32_t commands_issued_ = 0; - - bool is_init_ = false; - uint64_t lba_count_ = 0; - uint32_t sector_size_ = 0; - - glcr::ErrorOr IssueCommand(const CommandInfo& command); -}; diff --git a/sys/denali/ahci/command.h b/sys/denali/ahci/command.h deleted file mode 100644 index cf94c1b..0000000 --- a/sys/denali/ahci/command.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include - -struct CommandInfo { - uint8_t command; - uint64_t lba; - uint16_t sectors; - uint64_t paddr; -}; diff --git a/sys/denali/denali.cpp b/sys/denali/denali.cpp deleted file mode 100644 index ba25e9a..0000000 --- a/sys/denali/denali.cpp +++ /dev/null @@ -1,37 +0,0 @@ - -#include -#include -#include -#include - -#include "ahci/ahci_controller.h" -#include "denali_server.h" - -using yellowstone::AhciInfo; -using yellowstone::RegisterEndpointRequest; -using yellowstone::YellowstoneClient; - -uint64_t main(uint64_t init_port_cap) { - check(ParseInitPort(init_port_cap)); - - YellowstoneClient stub(gInitEndpointCap); - AhciInfo ahci; - check(stub.GetAhciInfo(ahci)); - mmth::OwnedMemoryRegion ahci_region = - mmth::OwnedMemoryRegion::FromCapability(ahci.ahci_region()); - ASSIGN_OR_RETURN(auto driver, AhciController::Init(glcr::Move(ahci_region))); - - ASSIGN_OR_RETURN(glcr::UniquePtr server, - DenaliServer::Create(*driver)); - - Thread server_thread = server->RunServer(); - - RegisterEndpointRequest req; - req.set_endpoint_name("denali"); - ASSIGN_OR_RETURN(z_cap_t client_cap, server->CreateClientCap()); - req.set_endpoint_capability(client_cap); - check(stub.RegisterEndpoint(req)); - - check(server_thread.Join()); - return 0; -} diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp deleted file mode 100644 index c245bec..0000000 --- a/sys/denali/denali_server.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include "denali_server.h" - -#include -#include -#include -#include - -glcr::ErrorOr> DenaliServer::Create( - AhciController& driver) { - z_cap_t cap; - RET_ERR(ZEndpointCreate(&cap)); - return glcr::UniquePtr(new DenaliServer(cap, driver)); -} - -glcr::Status DenaliServer::HandleRead(const ReadRequest& req, - ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); - - uint64_t paddr; - mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical( - req.block().size() * 512, &paddr); - - ASSIGN_OR_RETURN( - auto semaphore, - device->IssueRead(req.block().lba(), req.block().size(), paddr)); - semaphore->Wait(); - - resp.set_device_id(req.device_id()); - resp.set_size(req.block().size()); - resp.set_memory(region.DuplicateCap()); - return glcr::Status::Ok(); -} - -glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, - ReadResponse& resp) { - ASSIGN_OR_RETURN(AhciPort * device, driver_.GetDevice(req.device_id())); - - uint64_t sector_cnt = 0; - for (auto& block : req.blocks()) { - sector_cnt += block.size(); - } - uint64_t region_paddr; - mmth::OwnedMemoryRegion region = mmth::OwnedMemoryRegion::ContiguousPhysical( - sector_cnt * 512, ®ion_paddr); - - for (auto& block : req.blocks()) { - ASSIGN_OR_RETURN( - auto semaphore, - device->IssueRead(block.lba(), block.size(), region_paddr)); - semaphore->Wait(); - - region_paddr += block.size() * 512; - } - - resp.set_device_id(req.device_id()); - resp.set_size(sector_cnt); - resp.set_memory(region.DuplicateCap()); - return glcr::Status::Ok(); -} diff --git a/sys/denali/denali_server.h b/sys/denali/denali_server.h deleted file mode 100644 index 4e5b9dc..0000000 --- a/sys/denali/denali_server.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include "ahci/ahci_controller.h" -#include "lib/denali/denali.yunq.server.h" - -class DenaliServer : public DenaliServerBase { - public: - static glcr::ErrorOr> Create( - AhciController& driver); - - glcr::Status HandleRead(const ReadRequest& req, ReadResponse& resp) override; - glcr::Status HandleReadMany(const ReadManyRequest& req, - ReadResponse& resp) override; - - private: - static const uint64_t kBuffSize = 1024; - uint8_t read_buffer_[kBuffSize]; - - AhciController& driver_; - - DenaliServer(z_cap_t endpoint_cap, AhciController& driver) - : DenaliServerBase(endpoint_cap), driver_(driver) {} -}; From 15a5e210ef92dcea500ec2c88f14c785235c5fe1 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:42:45 -0800 Subject: [PATCH 163/186] Move port controller to separate file. --- rust/sys/denali/src/ahci/controller.rs | 277 +------------------- rust/sys/denali/src/ahci/mod.rs | 3 +- rust/sys/denali/src/ahci/port_controller.rs | 265 +++++++++++++++++++ rust/sys/denali/src/denali_server.rs | 2 +- 4 files changed, 279 insertions(+), 268 deletions(-) create mode 100644 rust/sys/denali/src/ahci/port_controller.rs diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 1508574..d0656a6 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -1,28 +1,18 @@ -use core::array; -use core::future::Future; -use core::ops::Deref; -use core::ops::DerefMut; -use core::pin::Pin; -use core::task::{Context, Poll, Waker}; - -use alloc::boxed::Box; use alloc::sync::Arc; -use mammoth::cap::Capability; -use mammoth::sync::Mutex; -use mammoth::syscall; -use mammoth::{mem, thread}; - -use mammoth::{mem::MemoryRegion, zion::ZError}; - -use crate::ahci::command::FisType; -use crate::ahci::port::{ - AhciDeviceDetection, AhciInterfacePowerManagement, AhciPortInterruptStatus, +use mammoth::{ + cap::Capability, + mem::{self, MemoryRegion}, + sync::Mutex, + thread, + zion::ZError, }; -use super::command::{ - CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand, +use crate::ahci::{ + port::{AhciDeviceDetection, AhciInterfacePowerManagement}, + port_controller::Command, }; -use super::{hba::AhciHba, port::AhciPortHba}; + +use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController}; #[derive(Debug)] #[repr(C, packed)] @@ -206,248 +196,3 @@ pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { pub async fn identify_ports(controller: Arc) { controller.identify_ports().await.unwrap(); } - -enum CommandStatus { - Empty, - NotSent, - Pending(Waker), - Complete, -} - -struct CommandFuture { - status: Arc>, - trigger: Box, -} - -impl CommandFuture { - fn new(status: Arc>, trigger: Box) -> Self { - Self { status, trigger } - } -} - -impl Drop for CommandFuture { - fn drop(&mut self) { - *self.status.lock() = CommandStatus::Empty; - } -} - -impl Future for CommandFuture { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let s = self.deref_mut(); - let mut status = s.status.lock(); - match status.deref() { - CommandStatus::NotSent => { - *status = CommandStatus::Pending(cx.waker().clone()); - (s.trigger)(); - Poll::Pending - } - CommandStatus::Pending(_) => Poll::Pending, - CommandStatus::Complete => Poll::Ready(()), - CommandStatus::Empty => panic!("Polling empty command slot"), - } - } -} - -pub struct Command { - command: SataCommand, - lba: u64, - sector_cnt: u16, - paddr: u64, - - memory_region: Option, -} - -impl Command { - pub fn identify() -> Result { - let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?; - - Ok(Self { - command: SataCommand::IdentifyDevice, - lba: 0, - sector_cnt: 1, - paddr, - memory_region: Some(memory_region), - }) - } - - pub fn read(lba: u64, lba_count: u16) -> Result { - let (memory_region, paddr) = - syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?; - - Ok(Self { - command: SataCommand::DmaReadExt, - lba, - sector_cnt: lba_count, - paddr, - memory_region: Some(memory_region), - }) - } - - pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self { - Self { - command: SataCommand::DmaReadExt, - lba, - sector_cnt: lba_count, - paddr: paddr, - memory_region: None, - } - } - - pub fn release_mem_cap(&mut self) -> u64 { - self.memory_region.take().unwrap().release() - } -} - -impl From<&Command> for HostToDeviceRegisterFis { - fn from(val: &Command) -> Self { - HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt) - } -} - -struct CommandStructures { - command_list: &'static mut CommandList, - received_fis: &'static mut ReceivedFis, - command_tables: &'static mut [CommandTable; 32], -} - -struct PortController { - ahci_port_hba: Arc>, - command_structures: Mutex, - - command_slots: [Arc>; 32], -} - -impl PortController { - fn new(ahci_port_hba: &'static mut AhciPortHba) -> Self { - let (command_vaddr, command_paddr) = mem::map_physical_and_leak(0x2500); - ahci_port_hba.init(command_paddr, command_paddr + 0x400); - - let command_list = unsafe { (command_vaddr as *mut CommandList).as_mut().unwrap() }; - let received_fis = unsafe { - ((command_vaddr + 0x400) as *mut ReceivedFis) - .as_mut() - .unwrap() - }; - let command_tables = unsafe { - ((command_vaddr + 0x500) as *mut [CommandTable; 32]) - .as_mut() - .unwrap() - }; - - // This leaves space for 8 prdt entries. - for i in 0..32 { - command_list[i].command_table_base_addr = - (command_paddr + 0x500) + (0x100 * (i as u64)); - } - - let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty))); - - Self { - ahci_port_hba: Arc::new(Mutex::new(ahci_port_hba)), - command_structures: Mutex::new(CommandStructures { - command_list, - received_fis, - command_tables, - }), - command_slots, - } - } - - fn get_signature(&self) -> u32 { - self.ahci_port_hba.lock().signature.read() - } - - fn issue_command(&self, command: &Command) -> Result { - let slot = self.select_slot()?; - let command_slot = self.command_slots[slot].clone(); - - let ahci_port_hba_clone = self.ahci_port_hba.clone(); - let slot_clone = slot; - let future = CommandFuture::new( - command_slot, - Box::new(move || { - ahci_port_hba_clone.lock().issue_command(slot_clone); - }), - ); - - let mut command_structures = self.command_structures.lock(); - - command_structures.command_tables[slot] - .command_fis - .host_to_device = command.into(); - - command_structures.command_tables[slot].prdt[0].region_address = command.paddr; - command_structures.command_tables[slot].prdt[0].byte_count = - 512 * (command.sector_cnt as u32); - - command_structures.command_list[slot].prd_table_length = 1; - - command_structures.command_list[slot].command = - (size_of::() as u16 / 4) & 0x1F; - command_structures.command_list[slot].command |= 1 << 7; - - Ok(future) - } - - fn select_slot(&self) -> Result { - // TODO: We have a race condition here. - for i in 0..self.command_slots.len() { - let mut slot = self.command_slots[i].lock(); - if matches!(*slot, CommandStatus::Empty) { - *slot = CommandStatus::NotSent; - return Ok(i); - } - } - Err(ZError::EXHAUSTED) - } - - fn handle_interrupt(&self) { - let int_status = self.ahci_port_hba.lock().interrupt_status.read(); - if int_status.device_to_host_register_fis_interrupt() { - let received_fis = self - .command_structures - .lock() - .received_fis - .device_to_host_register_fis; - assert_eq!( - received_fis.fis_type as u8, - FisType::RegisterDeviceToHost as u8 - ); - if received_fis.error != 0 { - mammoth::debug!("D2H err: {:#0x}", received_fis.error); - mammoth::debug!("Status: {:#0x}", received_fis.status); - } - - self.ahci_port_hba.lock().interrupt_status.write( - AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true), - ); - } - if int_status.pio_setup_fis_interrupt() { - self.ahci_port_hba - .lock() - .interrupt_status - .write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true)); - } - - for i in 0..32 { - let int_offset = 1 << i; - - // If there is no longer a command issued on a slot and we have something in - // the command list that is pending we know that this is the command that finished. - if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset { - let mut command_status = self.command_slots[i].lock(); - let mut did_complete = false; - if let CommandStatus::Pending(ref waker) = command_status.deref() { - waker.wake_by_ref(); - did_complete = true; - } - - if did_complete { - *command_status = CommandStatus::Complete; - } - } - } - } -} diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index a38f81f..f154971 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -2,8 +2,9 @@ mod command; mod controller; mod hba; mod port; +mod port_controller; pub use controller::identify_ports; pub use controller::spawn_irq_thread; pub use controller::AhciController; -pub use controller::Command; +pub use port_controller::Command; diff --git a/rust/sys/denali/src/ahci/port_controller.rs b/rust/sys/denali/src/ahci/port_controller.rs new file mode 100644 index 0000000..47ce356 --- /dev/null +++ b/rust/sys/denali/src/ahci/port_controller.rs @@ -0,0 +1,265 @@ +use core::{ + array, + future::Future, + ops::Deref, + ops::DerefMut, + pin::Pin, + task::{Context, Poll, Waker}, +}; + +use alloc::boxed::Box; +use alloc::sync::Arc; +use mammoth::{cap::Capability, mem, sync::Mutex, syscall, zion::ZError}; + +use crate::ahci::command::FisType; +use crate::ahci::port::AhciPortInterruptStatus; + +use super::command::{ + CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand, +}; +use super::port::AhciPortHba; + +enum CommandStatus { + Empty, + NotSent, + Pending(Waker), + Complete, +} + +pub struct CommandFuture { + status: Arc>, + trigger: Box, +} + +impl CommandFuture { + fn new(status: Arc>, trigger: Box) -> Self { + Self { status, trigger } + } +} + +impl Drop for CommandFuture { + fn drop(&mut self) { + *self.status.lock() = CommandStatus::Empty; + } +} + +impl Future for CommandFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let s = self.deref_mut(); + let mut status = s.status.lock(); + match status.deref() { + CommandStatus::NotSent => { + *status = CommandStatus::Pending(cx.waker().clone()); + (s.trigger)(); + Poll::Pending + } + CommandStatus::Pending(_) => Poll::Pending, + CommandStatus::Complete => Poll::Ready(()), + CommandStatus::Empty => panic!("Polling empty command slot"), + } + } +} + +pub struct Command { + command: SataCommand, + lba: u64, + sector_cnt: u16, + paddr: u64, + + memory_region: Option, +} + +impl Command { + pub fn identify() -> Result { + let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?; + + Ok(Self { + command: SataCommand::IdentifyDevice, + lba: 0, + sector_cnt: 1, + paddr, + memory_region: Some(memory_region), + }) + } + + pub fn read(lba: u64, lba_count: u16) -> Result { + let (memory_region, paddr) = + syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?; + + Ok(Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr, + memory_region: Some(memory_region), + }) + } + + pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self { + Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr: paddr, + memory_region: None, + } + } + + pub fn release_mem_cap(&mut self) -> u64 { + self.memory_region.take().unwrap().release() + } +} + +impl From<&Command> for HostToDeviceRegisterFis { + fn from(val: &Command) -> Self { + HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt) + } +} + +struct CommandStructures { + command_list: &'static mut CommandList, + received_fis: &'static mut ReceivedFis, + command_tables: &'static mut [CommandTable; 32], +} + +pub struct PortController { + ahci_port_hba: Arc>, + command_structures: Mutex, + + command_slots: [Arc>; 32], +} + +impl PortController { + pub fn new(ahci_port_hba: &'static mut AhciPortHba) -> Self { + let (command_vaddr, command_paddr) = mem::map_physical_and_leak(0x2500); + ahci_port_hba.init(command_paddr, command_paddr + 0x400); + + let command_list = unsafe { (command_vaddr as *mut CommandList).as_mut().unwrap() }; + let received_fis = unsafe { + ((command_vaddr + 0x400) as *mut ReceivedFis) + .as_mut() + .unwrap() + }; + let command_tables = unsafe { + ((command_vaddr + 0x500) as *mut [CommandTable; 32]) + .as_mut() + .unwrap() + }; + + // This leaves space for 8 prdt entries. + for i in 0..32 { + command_list[i].command_table_base_addr = + (command_paddr + 0x500) + (0x100 * (i as u64)); + } + + let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty))); + + Self { + ahci_port_hba: Arc::new(Mutex::new(ahci_port_hba)), + command_structures: Mutex::new(CommandStructures { + command_list, + received_fis, + command_tables, + }), + command_slots, + } + } + + pub fn get_signature(&self) -> u32 { + self.ahci_port_hba.lock().signature.read() + } + + pub fn issue_command(&self, command: &Command) -> Result { + let slot = self.select_slot()?; + let command_slot = self.command_slots[slot].clone(); + + let ahci_port_hba_clone = self.ahci_port_hba.clone(); + let slot_clone = slot; + let future = CommandFuture::new( + command_slot, + Box::new(move || { + ahci_port_hba_clone.lock().issue_command(slot_clone); + }), + ); + + let mut command_structures = self.command_structures.lock(); + + command_structures.command_tables[slot] + .command_fis + .host_to_device = command.into(); + + command_structures.command_tables[slot].prdt[0].region_address = command.paddr; + command_structures.command_tables[slot].prdt[0].byte_count = + 512 * (command.sector_cnt as u32); + + command_structures.command_list[slot].prd_table_length = 1; + + command_structures.command_list[slot].command = + (size_of::() as u16 / 4) & 0x1F; + command_structures.command_list[slot].command |= 1 << 7; + + Ok(future) + } + + fn select_slot(&self) -> Result { + // TODO: We have a race condition here. + for i in 0..self.command_slots.len() { + let mut slot = self.command_slots[i].lock(); + if matches!(*slot, CommandStatus::Empty) { + *slot = CommandStatus::NotSent; + return Ok(i); + } + } + Err(ZError::EXHAUSTED) + } + + pub fn handle_interrupt(&self) { + let int_status = self.ahci_port_hba.lock().interrupt_status.read(); + if int_status.device_to_host_register_fis_interrupt() { + let received_fis = self + .command_structures + .lock() + .received_fis + .device_to_host_register_fis; + assert_eq!( + received_fis.fis_type as u8, + FisType::RegisterDeviceToHost as u8 + ); + if received_fis.error != 0 { + mammoth::debug!("D2H err: {:#0x}", received_fis.error); + mammoth::debug!("Status: {:#0x}", received_fis.status); + } + + self.ahci_port_hba.lock().interrupt_status.write( + AhciPortInterruptStatus::new().with_device_to_host_register_fis_interrupt(true), + ); + } + if int_status.pio_setup_fis_interrupt() { + self.ahci_port_hba + .lock() + .interrupt_status + .write(AhciPortInterruptStatus::new().with_pio_setup_fis_interrupt(true)); + } + + for i in 0..32 { + let int_offset = 1 << i; + + // If there is no longer a command issued on a slot and we have something in + // the command list that is pending we know that this is the command that finished. + if (self.ahci_port_hba.lock().command_issue.read() & int_offset) != int_offset { + let mut command_status = self.command_slots[i].lock(); + let mut did_complete = false; + if let CommandStatus::Pending(ref waker) = command_status.deref() { + waker.wake_by_ref(); + did_complete = true; + } + + if did_complete { + *command_status = CommandStatus::Complete; + } + } + } + } +} diff --git a/rust/sys/denali/src/denali_server.rs b/rust/sys/denali/src/denali_server.rs index 54bc7a0..511ff0f 100644 --- a/rust/sys/denali/src/denali_server.rs +++ b/rust/sys/denali/src/denali_server.rs @@ -47,7 +47,7 @@ impl AsyncDenaliServerHandler for DenaliServerImpl { // TODO: We should actually be able to read all of these in parallel. self.ahci_controller .issue_command(req.device_id as usize, &command) - .await; + .await?; paddr += block.size * sector_size; } From 4efeca661e5570835049080b917961ddf3f31194 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:44:03 -0800 Subject: [PATCH 164/186] Move command.rs to ahci_command.rs --- rust/sys/denali/src/ahci/{command.rs => ahci_command.rs} | 0 rust/sys/denali/src/ahci/mod.rs | 2 +- rust/sys/denali/src/ahci/port_controller.rs | 9 +++++---- 3 files changed, 6 insertions(+), 5 deletions(-) rename rust/sys/denali/src/ahci/{command.rs => ahci_command.rs} (100%) diff --git a/rust/sys/denali/src/ahci/command.rs b/rust/sys/denali/src/ahci/ahci_command.rs similarity index 100% rename from rust/sys/denali/src/ahci/command.rs rename to rust/sys/denali/src/ahci/ahci_command.rs diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index f154971..8200d8e 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -1,4 +1,4 @@ -mod command; +mod ahci_command; mod controller; mod hba; mod port; diff --git a/rust/sys/denali/src/ahci/port_controller.rs b/rust/sys/denali/src/ahci/port_controller.rs index 47ce356..5b42543 100644 --- a/rust/sys/denali/src/ahci/port_controller.rs +++ b/rust/sys/denali/src/ahci/port_controller.rs @@ -11,13 +11,14 @@ use alloc::boxed::Box; use alloc::sync::Arc; use mammoth::{cap::Capability, mem, sync::Mutex, syscall, zion::ZError}; -use crate::ahci::command::FisType; use crate::ahci::port::AhciPortInterruptStatus; -use super::command::{ - CommandList, CommandTable, HostToDeviceRegisterFis, ReceivedFis, SataCommand, +use super::{ + ahci_command::{ + CommandList, CommandTable, FisType, HostToDeviceRegisterFis, ReceivedFis, SataCommand, + }, + port::AhciPortHba, }; -use super::port::AhciPortHba; enum CommandStatus { Empty, From e34540b77edd44fed125132e625d4e718a448a30 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 1 Feb 2025 14:49:41 -0800 Subject: [PATCH 165/186] Move command into its own file. --- rust/sys/denali/src/ahci/command.rs | 112 ++++++++++++++++++ rust/sys/denali/src/ahci/controller.rs | 2 +- rust/sys/denali/src/ahci/mod.rs | 3 +- rust/sys/denali/src/ahci/port_controller.rs | 120 ++------------------ 4 files changed, 122 insertions(+), 115 deletions(-) create mode 100644 rust/sys/denali/src/ahci/command.rs diff --git a/rust/sys/denali/src/ahci/command.rs b/rust/sys/denali/src/ahci/command.rs new file mode 100644 index 0000000..947082e --- /dev/null +++ b/rust/sys/denali/src/ahci/command.rs @@ -0,0 +1,112 @@ +use core::{ + future::Future, + ops::Deref, + ops::DerefMut, + pin::Pin, + task::{Context, Poll, Waker}, +}; + +use alloc::boxed::Box; +use alloc::sync::Arc; +use mammoth::{cap::Capability, sync::Mutex, syscall, zion::ZError}; + +use super::ahci_command::{HostToDeviceRegisterFis, SataCommand}; + +pub enum CommandStatus { + Empty, + NotSent, + Pending(Waker), + Complete, +} + +pub struct CommandFuture { + status: Arc>, + trigger: Box, +} + +impl CommandFuture { + pub fn new(status: Arc>, trigger: Box) -> Self { + Self { status, trigger } + } +} + +impl Drop for CommandFuture { + fn drop(&mut self) { + *self.status.lock() = CommandStatus::Empty; + } +} + +impl Future for CommandFuture { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let s = self.deref_mut(); + let mut status = s.status.lock(); + match status.deref() { + CommandStatus::NotSent => { + *status = CommandStatus::Pending(cx.waker().clone()); + (s.trigger)(); + Poll::Pending + } + CommandStatus::Pending(_) => Poll::Pending, + CommandStatus::Complete => Poll::Ready(()), + CommandStatus::Empty => panic!("Polling empty command slot"), + } + } +} + +pub struct Command { + pub command: SataCommand, + pub lba: u64, + pub sector_cnt: u16, + pub paddr: u64, + + memory_region: Option, +} + +impl Command { + pub fn identify() -> Result { + let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?; + + Ok(Self { + command: SataCommand::IdentifyDevice, + lba: 0, + sector_cnt: 1, + paddr, + memory_region: Some(memory_region), + }) + } + + pub fn read(lba: u64, lba_count: u16) -> Result { + let (memory_region, paddr) = + syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?; + + Ok(Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr, + memory_region: Some(memory_region), + }) + } + + pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self { + Self { + command: SataCommand::DmaReadExt, + lba, + sector_cnt: lba_count, + paddr: paddr, + memory_region: None, + } + } + + pub fn release_mem_cap(&mut self) -> u64 { + self.memory_region.take().unwrap().release() + } +} + +impl From<&Command> for HostToDeviceRegisterFis { + fn from(val: &Command) -> Self { + HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt) + } +} diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index d0656a6..059f3a7 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -9,7 +9,7 @@ use mammoth::{ use crate::ahci::{ port::{AhciDeviceDetection, AhciInterfacePowerManagement}, - port_controller::Command, + Command, }; use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController}; diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs index 8200d8e..f98bcf2 100644 --- a/rust/sys/denali/src/ahci/mod.rs +++ b/rust/sys/denali/src/ahci/mod.rs @@ -1,10 +1,11 @@ mod ahci_command; +mod command; mod controller; mod hba; mod port; mod port_controller; +pub use command::Command; pub use controller::identify_ports; pub use controller::spawn_irq_thread; pub use controller::AhciController; -pub use port_controller::Command; diff --git a/rust/sys/denali/src/ahci/port_controller.rs b/rust/sys/denali/src/ahci/port_controller.rs index 5b42543..556e8f7 100644 --- a/rust/sys/denali/src/ahci/port_controller.rs +++ b/rust/sys/denali/src/ahci/port_controller.rs @@ -1,124 +1,18 @@ -use core::{ - array, - future::Future, - ops::Deref, - ops::DerefMut, - pin::Pin, - task::{Context, Poll, Waker}, -}; +use core::array; +use core::ops::Deref; -use alloc::boxed::Box; -use alloc::sync::Arc; -use mammoth::{cap::Capability, mem, sync::Mutex, syscall, zion::ZError}; +use alloc::{boxed::Box, sync::Arc}; +use mammoth::{mem, sync::Mutex, zion::ZError}; use crate::ahci::port::AhciPortInterruptStatus; use super::{ - ahci_command::{ - CommandList, CommandTable, FisType, HostToDeviceRegisterFis, ReceivedFis, SataCommand, - }, + ahci_command::{CommandList, CommandTable, FisType, HostToDeviceRegisterFis, ReceivedFis}, + command::{CommandFuture, CommandStatus}, port::AhciPortHba, + Command, }; -enum CommandStatus { - Empty, - NotSent, - Pending(Waker), - Complete, -} - -pub struct CommandFuture { - status: Arc>, - trigger: Box, -} - -impl CommandFuture { - fn new(status: Arc>, trigger: Box) -> Self { - Self { status, trigger } - } -} - -impl Drop for CommandFuture { - fn drop(&mut self) { - *self.status.lock() = CommandStatus::Empty; - } -} - -impl Future for CommandFuture { - type Output = (); - - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - let s = self.deref_mut(); - let mut status = s.status.lock(); - match status.deref() { - CommandStatus::NotSent => { - *status = CommandStatus::Pending(cx.waker().clone()); - (s.trigger)(); - Poll::Pending - } - CommandStatus::Pending(_) => Poll::Pending, - CommandStatus::Complete => Poll::Ready(()), - CommandStatus::Empty => panic!("Polling empty command slot"), - } - } -} - -pub struct Command { - command: SataCommand, - lba: u64, - sector_cnt: u16, - paddr: u64, - - memory_region: Option, -} - -impl Command { - pub fn identify() -> Result { - let (memory_region, paddr) = syscall::memory_object_contiguous_physical(512)?; - - Ok(Self { - command: SataCommand::IdentifyDevice, - lba: 0, - sector_cnt: 1, - paddr, - memory_region: Some(memory_region), - }) - } - - pub fn read(lba: u64, lba_count: u16) -> Result { - let (memory_region, paddr) = - syscall::memory_object_contiguous_physical(512 * (lba_count as u64))?; - - Ok(Self { - command: SataCommand::DmaReadExt, - lba, - sector_cnt: lba_count, - paddr, - memory_region: Some(memory_region), - }) - } - - pub fn read_manual(lba: u64, lba_count: u16, paddr: u64) -> Self { - Self { - command: SataCommand::DmaReadExt, - lba, - sector_cnt: lba_count, - paddr: paddr, - memory_region: None, - } - } - - pub fn release_mem_cap(&mut self) -> u64 { - self.memory_region.take().unwrap().release() - } -} - -impl From<&Command> for HostToDeviceRegisterFis { - fn from(val: &Command) -> Self { - HostToDeviceRegisterFis::new_command(val.command, val.lba, val.sector_cnt) - } -} - struct CommandStructures { command_list: &'static mut CommandList, received_fis: &'static mut ReceivedFis, From 9452e6c705674ce6194b5b3f99b69bdbffd98ddc Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 7 Feb 2025 17:50:39 -0800 Subject: [PATCH 166/186] [Denali] Assert sector size is 512. --- rust/sys/denali/src/ahci/controller.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index 059f3a7..f62645d 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -155,8 +155,13 @@ impl AhciController { mammoth::debug!("Sector size: {:#0x}", new_sector_size); mammoth::debug!("LBA Count: {:#0x}", lba_count); - //self.sector_size = Some(new_sector_size as u64); - //self.sector_cnt = Some(lba_count); + // We hardcode assumptions about sector size in a few places, better to panic if we + // are wrong. + assert_eq!( + new_sector_size, 512, + "Sector size {} differs from 512.", + new_sector_size + ); } else { mammoth::debug!("Skipping non-sata sig: {:#0x}", sig); } From c8f84ec352aa23b6425b94ff9c99d1f12d2780e0 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 7 Feb 2025 18:05:38 -0800 Subject: [PATCH 167/186] Moved victoriafalls to sys dir in rust. --- rust/Cargo.toml | 12 ++++++++++-- rust/lib/victoriafalls/Cargo.toml | 14 -------------- rust/sys/teton/Cargo.toml | 2 +- rust/sys/victoriafalls/Cargo.toml | 15 +++++++++++++++ rust/{lib => sys}/victoriafalls/build.rs | 0 rust/sys/victoriafalls/src/bin/victoriafalls.rs | 11 +++++++++++ rust/{lib => sys}/victoriafalls/src/dir.rs | 0 rust/{lib => sys}/victoriafalls/src/file.rs | 0 rust/{lib => sys}/victoriafalls/src/lib.rs | 0 rust/sys/yellowstone/Cargo.toml | 4 ++-- 10 files changed, 39 insertions(+), 19 deletions(-) delete mode 100644 rust/lib/victoriafalls/Cargo.toml create mode 100644 rust/sys/victoriafalls/Cargo.toml rename rust/{lib => sys}/victoriafalls/build.rs (100%) create mode 100644 rust/sys/victoriafalls/src/bin/victoriafalls.rs rename rust/{lib => sys}/victoriafalls/src/dir.rs (100%) rename rust/{lib => sys}/victoriafalls/src/file.rs (100%) rename rust/{lib => sys}/victoriafalls/src/lib.rs (100%) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 258b494..0b2a592 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,15 @@ [workspace] members = [ - "lib/mammoth", "lib/victoriafalls", "lib/voyageurs", "lib/yellowstone", "lib/yunq", "lib/yunq-test", "sys/denali", "sys/teton", "sys/yellowstone", "usr/testbed", + "lib/mammoth", + "lib/voyageurs", + "lib/yellowstone", + "lib/yunq", + "lib/yunq-test", + "sys/denali", + "sys/teton", + "sys/victoriafalls", + "sys/yellowstone", + "usr/testbed", ] resolver = "2" - diff --git a/rust/lib/victoriafalls/Cargo.toml b/rust/lib/victoriafalls/Cargo.toml deleted file mode 100644 index 6aeae9e..0000000 --- a/rust/lib/victoriafalls/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "victoriafalls" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../mammoth" } -yellowstone-yunq = { path = "../yellowstone" } -yunq = {path = "../yunq"} - -[build-dependencies] -yunqc = {path = "../../../yunq/rust"} - - diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml index 1bcda15..baa787a 100644 --- a/rust/sys/teton/Cargo.toml +++ b/rust/sys/teton/Cargo.toml @@ -5,6 +5,6 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -victoriafalls = { path = "../../lib/victoriafalls" } +victoriafalls = { path = "../victoriafalls" } voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/victoriafalls/Cargo.toml b/rust/sys/victoriafalls/Cargo.toml new file mode 100644 index 0000000..3c2b75f --- /dev/null +++ b/rust/sys/victoriafalls/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "victoriafalls" +version = "0.1.0" +edition = "2021" + +[dependencies] +mammoth = { path = "../../lib/mammoth" } +yellowstone-yunq = { path = "../../lib/yellowstone" } +yunq = { path = "../../lib/yunq" } + +[build-dependencies] +yunqc = { path = "../../../yunq/rust" } + +[[bin]] +name = "victoriafalls" diff --git a/rust/lib/victoriafalls/build.rs b/rust/sys/victoriafalls/build.rs similarity index 100% rename from rust/lib/victoriafalls/build.rs rename to rust/sys/victoriafalls/build.rs diff --git a/rust/sys/victoriafalls/src/bin/victoriafalls.rs b/rust/sys/victoriafalls/src/bin/victoriafalls.rs new file mode 100644 index 0000000..7c9c8e8 --- /dev/null +++ b/rust/sys/victoriafalls/src/bin/victoriafalls.rs @@ -0,0 +1,11 @@ +#![no_std] +#![no_main] + +use mammoth::{define_entry, zion::z_err_t}; + +define_entry!(); + +#[no_mangle] +extern "C" fn main() -> z_err_t { + 0 +} diff --git a/rust/lib/victoriafalls/src/dir.rs b/rust/sys/victoriafalls/src/dir.rs similarity index 100% rename from rust/lib/victoriafalls/src/dir.rs rename to rust/sys/victoriafalls/src/dir.rs diff --git a/rust/lib/victoriafalls/src/file.rs b/rust/sys/victoriafalls/src/file.rs similarity index 100% rename from rust/lib/victoriafalls/src/file.rs rename to rust/sys/victoriafalls/src/file.rs diff --git a/rust/lib/victoriafalls/src/lib.rs b/rust/sys/victoriafalls/src/lib.rs similarity index 100% rename from rust/lib/victoriafalls/src/lib.rs rename to rust/sys/victoriafalls/src/lib.rs diff --git a/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml index 5e165e8..f321b62 100644 --- a/rust/sys/yellowstone/Cargo.toml +++ b/rust/sys/yellowstone/Cargo.toml @@ -5,8 +5,8 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -denali = { path = "../../sys/denali", default-features = false} -victoriafalls = { path = "../../lib/victoriafalls" } +denali = { path = "../denali", default-features = false } +victoriafalls = { path = "../victoriafalls" } voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } yunq = { path = "../../lib/yunq" } From 59efb1659a536c4efc6833b42002883b7db7a04f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 7 Feb 2025 18:24:48 -0800 Subject: [PATCH 168/186] Move denali client to separate lib. --- rust/Cargo.lock | 13 +++++++++++-- rust/Cargo.toml | 1 + rust/lib/client/denali_client/Cargo.toml | 11 +++++++++++ rust/lib/client/denali_client/build.rs | 14 ++++++++++++++ rust/lib/client/denali_client/src/lib.rs | 5 +++++ rust/sys/denali/Cargo.toml | 12 +++--------- rust/sys/victoriafalls/src/bin/victoriafalls.rs | 4 ++++ rust/sys/yellowstone/Cargo.toml | 2 +- rust/sys/yellowstone/src/gpt.rs | 10 +++++----- rust/sys/yellowstone/src/server.rs | 2 +- 10 files changed, 56 insertions(+), 18 deletions(-) create mode 100644 rust/lib/client/denali_client/Cargo.toml create mode 100644 rust/lib/client/denali_client/build.rs create mode 100644 rust/lib/client/denali_client/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e2a667e..c3a5f0e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "autocfg" @@ -39,6 +39,15 @@ dependencies = [ "yunqc", ] +[[package]] +name = "denali_client" +version = "0.1.0" +dependencies = [ + "mammoth", + "yunq", + "yunqc", +] + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -174,7 +183,7 @@ dependencies = [ name = "yellowstone" version = "0.1.0" dependencies = [ - "denali", + "denali_client", "mammoth", "victoriafalls", "voyageurs", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0b2a592..0d4b7ca 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ + "lib/client/denali_client", "lib/mammoth", "lib/voyageurs", "lib/yellowstone", diff --git a/rust/lib/client/denali_client/Cargo.toml b/rust/lib/client/denali_client/Cargo.toml new file mode 100644 index 0000000..625a2d5 --- /dev/null +++ b/rust/lib/client/denali_client/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "denali_client" +version = "0.1.0" +edition = "2024" + +[dependencies] +mammoth = { path = "../../mammoth" } +yunq = { path = "../../yunq" } + +[build-dependencies] +yunqc = { path = "../../../../yunq/rust" } diff --git a/rust/lib/client/denali_client/build.rs b/rust/lib/client/denali_client/build.rs new file mode 100644 index 0000000..67e593c --- /dev/null +++ b/rust/lib/client/denali_client/build.rs @@ -0,0 +1,14 @@ +use std::fs; + +fn main() { + let input_file = "../../../../sys/denali/lib/denali/denali.yunq"; + + println!("cargo::rerun-if-changed={input_file}"); + + let input = fs::read_to_string(input_file).expect("Failed to read input file"); + + let code = yunqc::codegen(&input).expect("Failed to generate yunq code."); + + let out = std::env::var("OUT_DIR").unwrap() + "/yunq.rs"; + fs::write(out, code).expect("Failed to write generated code."); +} diff --git a/rust/lib/client/denali_client/src/lib.rs b/rust/lib/client/denali_client/src/lib.rs new file mode 100644 index 0000000..3cec9d6 --- /dev/null +++ b/rust/lib/client/denali_client/src/lib.rs @@ -0,0 +1,5 @@ +#![no_std] + +use core::include; + +include!(concat!(env!("OUT_DIR"), "/yunq.rs")); diff --git a/rust/sys/denali/Cargo.toml b/rust/sys/denali/Cargo.toml index d618354..dcb3cd0 100644 --- a/rust/sys/denali/Cargo.toml +++ b/rust/sys/denali/Cargo.toml @@ -6,17 +6,11 @@ edition = "2021" [dependencies] bitfield-struct = "0.8.0" mammoth = { path = "../../lib/mammoth" } -yunq = {path = "../../lib/yunq"} - -yellowstone-yunq = { path = "../../lib/yellowstone", optional = true } +yunq = { path = "../../lib/yunq" } +yellowstone-yunq = { path = "../../lib/yellowstone" } [[bin]] name = "denali" -required-features = ["binary"] [build-dependencies] -yunqc = {path = "../../../yunq/rust"} - -[features] -default = ["binary"] -binary = ["dep:yellowstone-yunq"] +yunqc = { path = "../../../yunq/rust" } diff --git a/rust/sys/victoriafalls/src/bin/victoriafalls.rs b/rust/sys/victoriafalls/src/bin/victoriafalls.rs index 7c9c8e8..4d19ddd 100644 --- a/rust/sys/victoriafalls/src/bin/victoriafalls.rs +++ b/rust/sys/victoriafalls/src/bin/victoriafalls.rs @@ -7,5 +7,9 @@ define_entry!(); #[no_mangle] extern "C" fn main() -> z_err_t { + let yellowstone = yellowstone_yunq::from_init_endpoint(); + + let denali = yellowstone.get_denali().unwrap(); + 0 } diff --git a/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml index f321b62..6a89d4d 100644 --- a/rust/sys/yellowstone/Cargo.toml +++ b/rust/sys/yellowstone/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] mammoth = { path = "../../lib/mammoth" } -denali = { path = "../denali", default-features = false } +denali_client = { path = "../../lib/client/denali_client" } victoriafalls = { path = "../victoriafalls" } voyageurs = { path = "../../lib/voyageurs" } yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/yellowstone/src/gpt.rs b/rust/sys/yellowstone/src/gpt.rs index 950baf9..87bf3ce 100644 --- a/rust/sys/yellowstone/src/gpt.rs +++ b/rust/sys/yellowstone/src/gpt.rs @@ -1,4 +1,4 @@ -use denali::DenaliClient; +use denali_client::DenaliClient; use mammoth::{cap::Capability, zion::ZError}; const MBR_SIG: u16 = 0xAA55; @@ -47,9 +47,9 @@ struct PartitionEntry { } pub fn read_gpt(mut denali: DenaliClient) -> Result { - let resp = denali.read(&denali::ReadRequest { + let resp = denali.read(&denali_client::ReadRequest { device_id: 0, - block: denali::DiskBlock { lba: 0, size: 2 }, + block: denali_client::DiskBlock { lba: 0, size: 2 }, })?; let first_lbas = mammoth::mem::MemoryRegion::from_cap(Capability::take(resp.memory))?; @@ -99,9 +99,9 @@ pub fn read_gpt(mut denali: DenaliClient) -> Result { num_blocks ); - let resp = denali.read(&denali::ReadRequest { + let resp = denali.read(&denali_client::ReadRequest { device_id: 0, - block: denali::DiskBlock { + block: denali_client::DiskBlock { lba: lba_partition_entries, size: num_blocks, }, diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 8ec36b8..8cc4a4b 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -122,7 +122,7 @@ impl YellowstoneServerHandler for YellowstoneServerImpl { fn get_denali(&mut self) -> Result { match self.context.service_map.lock().get("denali") { - Some(ep_cap) => crate::gpt::read_gpt(denali::DenaliClient::new( + Some(ep_cap) => crate::gpt::read_gpt(denali_client::DenaliClient::new( ep_cap.duplicate(Capability::PERMS_ALL).unwrap(), )) .map(|lba| DenaliInfo { From a806e41af0360680f9a0dace6cd61f56a23553e3 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Fri, 7 Feb 2025 18:59:00 -0800 Subject: [PATCH 169/186] [VFS] Skeleton for moving victoria falls to rust. --- rust/Cargo.lock | 10 ++++++ rust/Cargo.toml | 2 +- .../client/denali_client/src/disk_reader.rs | 31 +++++++++++++++++++ rust/lib/client/denali_client/src/lib.rs | 4 +++ rust/lib/fs/ext2/Cargo.toml | 8 +++++ rust/lib/fs/ext2/src/ext2_driver.rs | 19 ++++++++++++ rust/lib/fs/ext2/src/lib.rs | 8 +++++ rust/lib/fs/ext2/src/types.rs | 30 ++++++++++++++++++ rust/lib/mammoth/src/mem.rs | 6 ++++ rust/sys/victoriafalls/Cargo.toml | 2 ++ .../victoriafalls/src/bin/victoriafalls.rs | 13 ++++++-- 11 files changed, 130 insertions(+), 3 deletions(-) create mode 100644 rust/lib/client/denali_client/src/disk_reader.rs create mode 100644 rust/lib/fs/ext2/Cargo.toml create mode 100644 rust/lib/fs/ext2/src/ext2_driver.rs create mode 100644 rust/lib/fs/ext2/src/lib.rs create mode 100644 rust/lib/fs/ext2/src/types.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index c3a5f0e..6083562 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -48,6 +48,14 @@ dependencies = [ "yunqc", ] +[[package]] +name = "ext2" +version = "0.1.0" +dependencies = [ + "denali_client", + "mammoth", +] + [[package]] name = "linked_list_allocator" version = "0.10.5" @@ -163,6 +171,8 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" name = "victoriafalls" version = "0.1.0" dependencies = [ + "denali_client", + "ext2", "mammoth", "yellowstone-yunq", "yunq", diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 0d4b7ca..1e43df4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ - "lib/client/denali_client", + "lib/client/denali_client", "lib/fs/ext2", "lib/mammoth", "lib/voyageurs", "lib/yellowstone", diff --git a/rust/lib/client/denali_client/src/disk_reader.rs b/rust/lib/client/denali_client/src/disk_reader.rs new file mode 100644 index 0000000..2d9a6a8 --- /dev/null +++ b/rust/lib/client/denali_client/src/disk_reader.rs @@ -0,0 +1,31 @@ +use mammoth::{cap::Capability, zion::ZError}; + +use crate::{DenaliClient, DiskBlock, ReadRequest}; + +pub struct DiskReader { + client: DenaliClient, + disk_id: u64, + lba_offset: u64, +} + +impl DiskReader { + pub fn new(client: DenaliClient, disk_id: u64, lba_offset: u64) -> Self { + Self { + client, + disk_id, + lba_offset, + } + } + + pub fn read(&mut self, lba: u64, cnt: u64) -> Result { + let read_resp = self.client.read(&ReadRequest { + device_id: self.disk_id, + block: DiskBlock { + lba: self.lba_offset + lba, + size: cnt, + }, + })?; + + Ok(Capability::take(read_resp.memory)) + } +} diff --git a/rust/lib/client/denali_client/src/lib.rs b/rust/lib/client/denali_client/src/lib.rs index 3cec9d6..72dfc10 100644 --- a/rust/lib/client/denali_client/src/lib.rs +++ b/rust/lib/client/denali_client/src/lib.rs @@ -3,3 +3,7 @@ use core::include; include!(concat!(env!("OUT_DIR"), "/yunq.rs")); + +mod disk_reader; + +pub use disk_reader::DiskReader; diff --git a/rust/lib/fs/ext2/Cargo.toml b/rust/lib/fs/ext2/Cargo.toml new file mode 100644 index 0000000..631197a --- /dev/null +++ b/rust/lib/fs/ext2/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "ext2" +version = "0.1.0" +edition = "2024" + +[dependencies] +denali_client = { path = "../../client/denali_client" } +mammoth = { path = "../../mammoth" } diff --git a/rust/lib/fs/ext2/src/ext2_driver.rs b/rust/lib/fs/ext2/src/ext2_driver.rs new file mode 100644 index 0000000..5354dd3 --- /dev/null +++ b/rust/lib/fs/ext2/src/ext2_driver.rs @@ -0,0 +1,19 @@ +use denali_client::DiskReader; +use mammoth::mem::MemoryRegion; + +use crate::types::Superblock; + +pub struct Ext2Driver { + reader: DiskReader, +} + +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 } + } +} diff --git a/rust/lib/fs/ext2/src/lib.rs b/rust/lib/fs/ext2/src/lib.rs new file mode 100644 index 0000000..40d9458 --- /dev/null +++ b/rust/lib/fs/ext2/src/lib.rs @@ -0,0 +1,8 @@ +#![no_std] + +extern crate alloc; + +mod ext2_driver; +mod types; + +pub use ext2_driver::Ext2Driver; diff --git a/rust/lib/fs/ext2/src/types.rs b/rust/lib/fs/ext2/src/types.rs new file mode 100644 index 0000000..e01b545 --- /dev/null +++ b/rust/lib/fs/ext2/src/types.rs @@ -0,0 +1,30 @@ +#[repr(C, packed)] +pub struct Superblock { + pub inodes_count: u32, + pub blocks_count: u32, + pub reserved_blocks_count: u32, + pub free_blocks_count: u32, + pub free_inodes_count: u32, + pub first_data_blok: u32, + pub log_block_size: u32, + pub log_frag_size: u32, + pub blocks_per_group: u32, + pub frags_per_group: u32, + pub inodes_per_group: u32, + pub mtime: u32, + pub wtime: u32, + pub mnt_count: u16, + pub max_mnt_count: u16, + pub magic: u16, + pub state: u16, + pub errors: u16, + pub minor_rev_level: u16, + pub lastcheck: u32, + pub checkinterval: u32, + pub creator_os: u32, + pub rev_level: u32, + pub def_resuid: u16, + pub def_resgid: u16, + pub first_ino: u32, + pub inode_size: u16, +} diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index ea4a070..0beb262 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -103,6 +103,12 @@ impl MemoryRegion { } } +impl AsRef for MemoryRegion { + fn as_ref(&self) -> &T { + unsafe { (self.virt_addr as *const T).as_ref().unwrap() } + } +} + impl Drop for MemoryRegion { fn drop(&mut self) { // FIXME: We shouldn't have to do this manual adjustment. diff --git a/rust/sys/victoriafalls/Cargo.toml b/rust/sys/victoriafalls/Cargo.toml index 3c2b75f..5464a78 100644 --- a/rust/sys/victoriafalls/Cargo.toml +++ b/rust/sys/victoriafalls/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" mammoth = { path = "../../lib/mammoth" } yellowstone-yunq = { path = "../../lib/yellowstone" } yunq = { path = "../../lib/yunq" } +denali_client = { path = "../../lib/client/denali_client" } +ext2 = { path = "../../lib/fs/ext2" } [build-dependencies] yunqc = { path = "../../../yunq/rust" } diff --git a/rust/sys/victoriafalls/src/bin/victoriafalls.rs b/rust/sys/victoriafalls/src/bin/victoriafalls.rs index 4d19ddd..f8fef0f 100644 --- a/rust/sys/victoriafalls/src/bin/victoriafalls.rs +++ b/rust/sys/victoriafalls/src/bin/victoriafalls.rs @@ -1,7 +1,9 @@ #![no_std] #![no_main] -use mammoth::{define_entry, zion::z_err_t}; +use denali_client::{DenaliClient, DiskReader}; +use ext2::Ext2Driver; +use mammoth::{cap::Capability, define_entry, zion::z_err_t}; define_entry!(); @@ -9,7 +11,14 @@ define_entry!(); extern "C" fn main() -> z_err_t { let yellowstone = yellowstone_yunq::from_init_endpoint(); - let denali = yellowstone.get_denali().unwrap(); + 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, + )); 0 } From 6e9dc0838c1318c70b5fbbe3f972236332b55b32 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 3 May 2025 14:44:55 -0700 Subject: [PATCH 170/186] Bump cmake version. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7332fe2..e99a91c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.2) +cmake_minimum_required(VERSION 3.5) # Set because our cross compiler can't do dynamic linking? set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") From 26ff82cf54c8faaa69804536de6442e82c280722 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 3 May 2025 14:48:42 -0700 Subject: [PATCH 171/186] Add ccls cache to gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 10c91f1..a74dbf9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ builddbg/ test-bin/ __pycache__/ +.ccls-cache/ compile_commands.json sysroot/bin From f918966727b096fc764c637c688d0715a22b960d Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sat, 3 May 2025 14:54:03 -0700 Subject: [PATCH 172/186] [Zion] Don't try to set state on dying threads in cleanup. --- zion/object/thread.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zion/object/thread.cpp b/zion/object/thread.cpp index 701792c..a1a1d47 100644 --- a/zion/object/thread.cpp +++ b/zion/object/thread.cpp @@ -120,8 +120,10 @@ void Thread::Cleanup() { // 2. Unblock waiting threads. while (blocked_threads_.size() != 0) { auto thread = blocked_threads_.PopFront(); - thread->SetState(Thread::RUNNABLE); - gScheduler->Enqueue(thread); + if (!thread->IsDying()) { + thread->SetState(Thread::RUNNABLE); + gScheduler->Enqueue(thread); + } } // 3. Release Kernel Stack From dc801786b16b3930704df7f6bd2d72ee99238760 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 5 May 2025 19:37:53 -0700 Subject: [PATCH 173/186] [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. --- rust/Cargo.lock | 1 + .../client/denali_client/src/disk_reader.rs | 27 +- rust/lib/fs/ext2/Cargo.toml | 1 + rust/lib/fs/ext2/src/ext2_driver.rs | 285 +++++++++++++++++- rust/lib/fs/ext2/src/types.rs | 94 ++++++ rust/lib/mammoth/src/mem.rs | 11 + .../victoriafalls/src/bin/victoriafalls.rs | 27 +- rust/sys/victoriafalls/src/lib.rs | 1 + rust/sys/victoriafalls/src/server.rs | 75 +++++ scripts/build_image.sh | 2 +- sys/denali/CMakeLists.txt | 1 - sys/denali/lib/denali/denali.yunq | 27 -- sys/denali/lib/denali/denali.yunq.client.cpp | 100 ------ sys/denali/lib/denali/denali.yunq.client.h | 37 --- sys/denali/lib/denali/denali.yunq.cpp | 186 ------------ sys/denali/lib/denali/denali.yunq.h | 138 --------- sys/denali/lib/denali/denali.yunq.server.cpp | 152 ---------- sys/denali/lib/denali/denali.yunq.server.h | 50 --- sys/victoriafalls/CMakeLists.txt | 26 -- sys/victoriafalls/fs/ext2/ext2.h | 76 ----- .../fs/ext2/ext2_block_reader.cpp | 117 ------- sys/victoriafalls/fs/ext2/ext2_block_reader.h | 49 --- sys/victoriafalls/fs/ext2/ext2_driver.cpp | 160 ---------- sys/victoriafalls/fs/ext2/ext2_driver.h | 36 --- sys/victoriafalls/fs/ext2/inode_table.cpp | 33 -- sys/victoriafalls/fs/ext2/inode_table.h | 24 -- .../lib/victoriafalls/victoriafalls.yunq | 23 -- .../victoriafalls.yunq.client.cpp | 100 ------ .../victoriafalls/victoriafalls.yunq.client.h | 37 --- .../lib/victoriafalls/victoriafalls.yunq.cpp | 173 ----------- .../lib/victoriafalls/victoriafalls.yunq.h | 124 -------- .../victoriafalls.yunq.server.cpp | 152 ---------- .../victoriafalls/victoriafalls.yunq.server.h | 50 --- sys/victoriafalls/victoriafalls.cpp | 35 --- sys/victoriafalls/victoriafalls_server.cpp | 109 ------- sys/victoriafalls/victoriafalls_server.h | 24 -- yunq/rust/src/codegen.rs | 6 +- 37 files changed, 504 insertions(+), 2065 deletions(-) create mode 100644 rust/sys/victoriafalls/src/server.rs delete mode 100644 sys/denali/CMakeLists.txt delete mode 100644 sys/denali/lib/denali/denali.yunq delete mode 100644 sys/denali/lib/denali/denali.yunq.client.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.client.h delete mode 100644 sys/denali/lib/denali/denali.yunq.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.h delete mode 100644 sys/denali/lib/denali/denali.yunq.server.cpp delete mode 100644 sys/denali/lib/denali/denali.yunq.server.h delete mode 100644 sys/victoriafalls/CMakeLists.txt delete mode 100644 sys/victoriafalls/fs/ext2/ext2.h delete mode 100644 sys/victoriafalls/fs/ext2/ext2_block_reader.cpp delete mode 100644 sys/victoriafalls/fs/ext2/ext2_block_reader.h delete mode 100644 sys/victoriafalls/fs/ext2/ext2_driver.cpp delete mode 100644 sys/victoriafalls/fs/ext2/ext2_driver.h delete mode 100644 sys/victoriafalls/fs/ext2/inode_table.cpp delete mode 100644 sys/victoriafalls/fs/ext2/inode_table.h delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp delete mode 100644 sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h delete mode 100644 sys/victoriafalls/victoriafalls.cpp delete mode 100644 sys/victoriafalls/victoriafalls_server.cpp delete mode 100644 sys/victoriafalls/victoriafalls_server.h diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 6083562..982c6db 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -54,6 +54,7 @@ version = "0.1.0" dependencies = [ "denali_client", "mammoth", + "yellowstone-yunq", ] [[package]] diff --git a/rust/lib/client/denali_client/src/disk_reader.rs b/rust/lib/client/denali_client/src/disk_reader.rs index 2d9a6a8..0283d29 100644 --- a/rust/lib/client/denali_client/src/disk_reader.rs +++ b/rust/lib/client/denali_client/src/disk_reader.rs @@ -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 { 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 { + 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)) + } } diff --git a/rust/lib/fs/ext2/Cargo.toml b/rust/lib/fs/ext2/Cargo.toml index 631197a..17c6f3f 100644 --- a/rust/lib/fs/ext2/Cargo.toml +++ b/rust/lib/fs/ext2/Cargo.toml @@ -6,3 +6,4 @@ edition = "2024" [dependencies] denali_client = { path = "../../client/denali_client" } mammoth = { path = "../../mammoth" } +yellowstone-yunq = { path = "../../yellowstone/" } diff --git a/rust/lib/fs/ext2/src/ext2_driver.rs b/rust/lib/fs/ext2/src/ext2_driver.rs index 5354dd3..96bb858 100644 --- a/rust/lib/fs/ext2/src/ext2_driver.rs +++ b/rust/lib/fs/ext2/src/ext2_driver.rs @@ -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>, + + /// 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, } 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::(offset).read().clone() } + } + + fn get_blocks_from_single_indirect(&mut self, block_num: u64, num_blocks: usize) -> Vec { + 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 { + 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) -> Vec { + 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 { + // 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 { + 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 { + 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, 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::(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) } } diff --git a/rust/lib/fs/ext2/src/types.rs b/rust/lib/fs/ext2/src/types.rs index e01b545..7aa3d2b 100644 --- a/rust/lib/fs/ext2/src/types.rs +++ b/rust/lib/fs/ext2/src/types.rs @@ -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::() 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::() == 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::() == 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], +} diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 0beb262..4b6d674 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -94,10 +94,21 @@ impl MemoryRegion { } } + pub fn raw_ptr_at_offset(&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::() 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 { syscall::memory_obj_duplicate(&self.mem_cap, offset, length) } diff --git a/rust/sys/victoriafalls/src/bin/victoriafalls.rs b/rust/sys/victoriafalls/src/bin/victoriafalls.rs index f8fef0f..770b238 100644 --- a/rust/sys/victoriafalls/src/bin/victoriafalls.rs +++ b/rust/sys/victoriafalls/src/bin/victoriafalls.rs @@ -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 } diff --git a/rust/sys/victoriafalls/src/lib.rs b/rust/sys/victoriafalls/src/lib.rs index a397f36..b7b9ca3 100644 --- a/rust/sys/victoriafalls/src/lib.rs +++ b/rust/sys/victoriafalls/src/lib.rs @@ -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 = None; diff --git a/rust/sys/victoriafalls/src/server.rs b/rust/sys/victoriafalls/src/server.rs new file mode 100644 index 0000000..0c2edb8 --- /dev/null +++ b/rust/sys/victoriafalls/src/server.rs @@ -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 { + 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 { + 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 { + 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 = self + .ext2_driver + .read_directory(inode_num)? + .into_iter() + .map(|fi| fi.name) + .collect(); + + Ok(Directory { + filenames: files.join(","), + }) + } +} diff --git a/scripts/build_image.sh b/scripts/build_image.sh index ed8b082..8500427 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -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/ diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt deleted file mode 100644 index 86fd4de..0000000 --- a/sys/denali/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -yunq_gen(lib/denali lib denali) diff --git a/sys/denali/lib/denali/denali.yunq b/sys/denali/lib/denali/denali.yunq deleted file mode 100644 index 450870c..0000000 --- a/sys/denali/lib/denali/denali.yunq +++ /dev/null @@ -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; -} - diff --git a/sys/denali/lib/denali/denali.yunq.client.cpp b/sys/denali/lib/denali/denali.yunq.client.cpp deleted file mode 100644 index 09e6f6a..0000000 --- a/sys/denali/lib/denali/denali.yunq.client.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Generated file - DO NOT MODIFY -#include "denali.yunq.client.h" - -#include -#include -#include -#include - - - - -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(0, kSentinel); - buffer_.WriteAt(8, 0); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(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(0, kSentinel); - buffer_.WriteAt(8, 1); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(8)); - - - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); - - - return glcr::OK; -} - - - - diff --git a/sys/denali/lib/denali/denali.yunq.client.h b/sys/denali/lib/denali/denali.yunq.client.h deleted file mode 100644 index 46fd28d..0000000 --- a/sys/denali/lib/denali/denali.yunq.client.h +++ /dev/null @@ -1,37 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include - -#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}; -}; - diff --git a/sys/denali/lib/denali/denali.yunq.cpp b/sys/denali/lib/denali/denali.yunq.cpp deleted file mode 100644 index de259cc..0000000 --- a/sys/denali/lib/denali/denali.yunq.cpp +++ /dev/null @@ -1,186 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "denali.yunq.h" - -#include -#include - - -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(0)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(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(0, lba_); - // Write size. - serializer.WriteField(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(0)); - // Parse block. - message.ReadMessage(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(0, device_id_); - // Write block. - serializer.WriteMessage(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(0)); - // Parse blocks. - message.ReadRepeatedMessage(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(0, device_id_); - // Write blocks. - serializer.WriteRepeatedMessage(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(0)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(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(0, device_id_); - // Write size. - serializer.WriteField(1, size_); - // Write memory. - serializer.WriteCapability(2, memory_); - - serializer.WriteHeader(); - - return serializer.size(); -} - diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h deleted file mode 100644 index 7874c91..0000000 --- a/sys/denali/lib/denali/denali.yunq.h +++ /dev/null @@ -1,138 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - - -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& blocks() const { return blocks_; } - glcr::Vector& mutable_blocks() { return blocks_; } - void add_blocks(DiskBlock&& value) { blocks_.PushBack(glcr::Move(value)); } - - private: - uint64_t device_id_; - glcr::Vector 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; -}; - diff --git a/sys/denali/lib/denali/denali.yunq.server.cpp b/sys/denali/lib/denali/denali.yunq.server.cpp deleted file mode 100644 index 4fe21f5..0000000 --- a/sys/denali/lib/denali/denali.yunq.server.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "denali.yunq.server.h" - -#include -#include - - -namespace { - -const uint32_t kSentinel = 0xBEEFDEAD; -const uint32_t kHeaderSize = 0x10; - -void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize); - buffer.WriteAt(8, err); -} - -void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize + message_length); - buffer.WriteAt(8, glcr::OK); -} - -} // namespace - - - -void DenaliServerBaseThreadBootstrap(void* server_base) { - ((DenaliServerBase*)server_base)->ServerThread(); -} - -DenaliServerBase::~DenaliServerBase() { - if (endpoint_ != 0) { - check(ZCapRelease(endpoint_)); - } -} - -glcr::ErrorOr DenaliServerBase::CreateClientCap() { - uint64_t client_cap; - RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); - return client_cap; -} - -glcr::ErrorOr 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(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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); - } else { - WriteHeader(resp_buffer, resp_length); - reply_err = static_cast(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(0) != kSentinel) { - return glcr::InvalidArgument("Request Not Valid"); - } - - uint64_t method_select = request.At(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(); -} - - diff --git a/sys/denali/lib/denali/denali.yunq.server.h b/sys/denali/lib/denali/denali.yunq.server.h deleted file mode 100644 index 5dc12e3..0000000 --- a/sys/denali/lib/denali/denali.yunq.server.h +++ /dev/null @@ -1,50 +0,0 @@ -// Generated File -- DO NOT MODIFY. -#pragma once - -#include -#include -#include -#include - -#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 CreateClientCap(); - glcr::ErrorOr 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); -}; - - - diff --git a/sys/victoriafalls/CMakeLists.txt b/sys/victoriafalls/CMakeLists.txt deleted file mode 100644 index 964bbab..0000000 --- a/sys/victoriafalls/CMakeLists.txt +++ /dev/null @@ -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) diff --git a/sys/victoriafalls/fs/ext2/ext2.h b/sys/victoriafalls/fs/ext2/ext2.h deleted file mode 100644 index 8a3ab2a..0000000 --- a/sys/victoriafalls/fs/ext2/ext2.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include - -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__)); diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp deleted file mode 100644 index 4e8a08e..0000000 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include "fs/ext2/ext2_block_reader.h" - -#include - -glcr::ErrorOr> 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( - new Ext2BlockReader(glcr::Move(client), denali_info.device_id(), - denali_info.lba_offset(), glcr::Move(superblock))); -} - -Superblock* Ext2BlockReader::GetSuperblock() { - return reinterpret_cast(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 Ext2BlockReader::ReadBlock( - uint64_t block_number) { - return ReadBlocks(block_number, 1); -} -glcr::ErrorOr 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 Ext2BlockReader::ReadBlocks( - const glcr::Vector& 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)) {} diff --git a/sys/victoriafalls/fs/ext2/ext2_block_reader.h b/sys/victoriafalls/fs/ext2/ext2_block_reader.h deleted file mode 100644 index aa49fba..0000000 --- a/sys/victoriafalls/fs/ext2/ext2_block_reader.h +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#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> 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 ReadBlock(uint64_t block_number); - glcr::ErrorOr ReadBlocks(uint64_t block_number, - uint64_t num_blocks); - - glcr::ErrorOr ReadBlocks( - const glcr::Vector& 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(); -}; diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.cpp b/sys/victoriafalls/fs/ext2/ext2_driver.cpp deleted file mode 100644 index 9483838..0000000 --- a/sys/victoriafalls/fs/ext2/ext2_driver.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "fs/ext2/ext2_driver.h" - -#include -#include - -#define EXT2_DEBUG 0 - -glcr::ErrorOr Ext2Driver::Init( - const yellowstone::DenaliInfo& denali_info) { - ASSIGN_OR_RETURN(glcr::SharedPtr reader, - Ext2BlockReader::Init(glcr::Move(denali_info))); - - ASSIGN_OR_RETURN( - mmth::OwnedMemoryRegion bgdt, - reader->ReadBlocks(reader->BgdtBlockNum(), reader->BgdtBlockSize())); - glcr::UniquePtr 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 Ext2Driver::GetInode(uint32_t inode_number) { - return inode_table_->GetInode(inode_number); -} - -glcr::ErrorOr> 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 directory; - - uint64_t addr = dir.vaddr(); - while (addr < dir.vaddr() + ext2_reader_->BlockSize()) { - DirEntry* entry = reinterpret_cast(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 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 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 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(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(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(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; -} diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.h b/sys/victoriafalls/fs/ext2/ext2_driver.h deleted file mode 100644 index b3600cc..0000000 --- a/sys/victoriafalls/fs/ext2/ext2_driver.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "fs/ext2/ext2.h" -#include "fs/ext2/ext2_block_reader.h" -#include "fs/ext2/inode_table.h" - -class Ext2Driver { - public: - static glcr::ErrorOr Init( - const yellowstone::DenaliInfo& denali_info); - - glcr::ErrorCode ProbePartition(); - - glcr::ErrorOr GetInode(uint32_t inode_number); - - glcr::ErrorOr> ReadDirectory(uint32_t inode_number); - - glcr::ErrorOr ReadFile(uint64_t inode_number); - - private: - glcr::SharedPtr ext2_reader_; - glcr::UniquePtr inode_table_; - glcr::HashMap inode_cache_; - - Ext2Driver(const glcr::SharedPtr& reader, - glcr::UniquePtr inode_table) - : ext2_reader_(reader), inode_table_(glcr::Move(inode_table)) {} - - glcr::ErrorOr ReadInode(uint64_t inode_num, - Inode* inode); -}; diff --git a/sys/victoriafalls/fs/ext2/inode_table.cpp b/sys/victoriafalls/fs/ext2/inode_table.cpp deleted file mode 100644 index 12bab0f..0000000 --- a/sys/victoriafalls/fs/ext2/inode_table.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "fs/ext2/inode_table.h" - -InodeTable::InodeTable(const glcr::SharedPtr& reader, - mmth::OwnedMemoryRegion&& bgdt_region) - : ext2_reader_(reader), - bgdt_region_(glcr::Move(bgdt_region)), - bgdt_(reinterpret_cast(bgdt_region_.vaddr())) { - inode_tables_.Resize(ext2_reader_->NumberOfBlockGroups()); -} - -glcr::ErrorOr 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(reinterpret_cast(root) + - local_index * ext2_reader_->InodeSize()); -} - -glcr::ErrorOr 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_tables_[block_group_num].vaddr()); -} diff --git a/sys/victoriafalls/fs/ext2/inode_table.h b/sys/victoriafalls/fs/ext2/inode_table.h deleted file mode 100644 index 18bb36d..0000000 --- a/sys/victoriafalls/fs/ext2/inode_table.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "fs/ext2/ext2_block_reader.h" - -class InodeTable { - public: - InodeTable(const glcr::SharedPtr& driver, - mmth::OwnedMemoryRegion&& bgdt_region); - - glcr::ErrorOr GetInode(uint32_t inode_num); - - private: - glcr::SharedPtr ext2_reader_; - mmth::OwnedMemoryRegion bgdt_region_; - BlockGroupDescriptor* bgdt_; - - glcr::Vector inode_tables_; - - glcr::ErrorOr GetRootOfInodeTable(uint64_t block_group_num); -}; diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq deleted file mode 100644 index 5da582e..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq +++ /dev/null @@ -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; -} diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp deleted file mode 100644 index dec023a..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Generated file - DO NOT MODIFY -#include "victoriafalls.yunq.client.h" - -#include -#include -#include -#include - - - - -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(0, kSentinel); - buffer_.WriteAt(8, 0); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(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(0, kSentinel); - buffer_.WriteAt(8, 1); - - cap_buffer_.Reset(); - - uint64_t length = request.SerializeToBytes(buffer_, /*offset=*/16, cap_buffer_); - - - buffer_.WriteAt(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(0) != kSentinel) { - return glcr::InvalidResponse("Got an invalid response from server."); - } - - // Check Response Code. - RET_ERR(buffer_.At(8)); - - - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); - - - return glcr::OK; -} - - - - diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h deleted file mode 100644 index 35dab56..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h +++ /dev/null @@ -1,37 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include - -#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}; -}; - diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp deleted file mode 100644 index 21fea87..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp +++ /dev/null @@ -1,173 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "victoriafalls.yunq.h" - -#include -#include - - -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(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(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(0)); - // Parse size. - ASSIGN_OR_RETURN(size_, message.ReadField(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(0, path_); - // Write size. - serializer.WriteField(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(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(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(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(0, filenames_); - - serializer.WriteHeader(); - - return serializer.size(); -} - diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h deleted file mode 100644 index 52daf7a..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h +++ /dev/null @@ -1,124 +0,0 @@ -// Generated file - DO NOT MODIFY -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - - -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; -}; - diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp deleted file mode 100644 index f5e7061..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp +++ /dev/null @@ -1,152 +0,0 @@ -// Generated file -- DO NOT MODIFY. -#include "victoriafalls.yunq.server.h" - -#include -#include - - -namespace { - -const uint32_t kSentinel = 0xBEEFDEAD; -const uint32_t kHeaderSize = 0x10; - -void WriteError(glcr::ByteBuffer& buffer, glcr::ErrorCode err) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize); - buffer.WriteAt(8, err); -} - -void WriteHeader(glcr::ByteBuffer& buffer, uint64_t message_length) { - buffer.WriteAt(0, kSentinel); - buffer.WriteAt(4, kHeaderSize + message_length); - buffer.WriteAt(8, glcr::OK); -} - -} // namespace - - - -void VFSServerBaseThreadBootstrap(void* server_base) { - ((VFSServerBase*)server_base)->ServerThread(); -} - -VFSServerBase::~VFSServerBase() { - if (endpoint_ != 0) { - check(ZCapRelease(endpoint_)); - } -} - -glcr::ErrorOr VFSServerBase::CreateClientCap() { - uint64_t client_cap; - RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); - return client_cap; -} - -glcr::ErrorOr 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(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(ZReplyPortSend(reply_port_cap, kHeaderSize, resp_buffer.RawPtr(), 0, nullptr)); - } else { - WriteHeader(resp_buffer, resp_length); - reply_err = static_cast(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(0) != kSentinel) { - return glcr::InvalidArgument("Request Not Valid"); - } - - uint64_t method_select = request.At(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(); -} - - diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h deleted file mode 100644 index bf91f66..0000000 --- a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h +++ /dev/null @@ -1,50 +0,0 @@ -// Generated File -- DO NOT MODIFY. -#pragma once - -#include -#include -#include -#include - -#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 CreateClientCap(); - glcr::ErrorOr 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); -}; - - - diff --git a/sys/victoriafalls/victoriafalls.cpp b/sys/victoriafalls/victoriafalls.cpp deleted file mode 100644 index 56ee383..0000000 --- a/sys/victoriafalls/victoriafalls.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include -#include -#include - -#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; -} diff --git a/sys/victoriafalls/victoriafalls_server.cpp b/sys/victoriafalls/victoriafalls_server.cpp deleted file mode 100644 index c48be7b..0000000 --- a/sys/victoriafalls/victoriafalls_server.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "victoriafalls_server.h" - -#include -#include -#include - -glcr::ErrorOr> VFSServer::Create( - Ext2Driver& driver) { - z_cap_t endpoint_cap; - RET_ERR(ZEndpointCreate(&endpoint_cap)); - return glcr::UniquePtr(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(); -} diff --git a/sys/victoriafalls/victoriafalls_server.h b/sys/victoriafalls/victoriafalls_server.h deleted file mode 100644 index 8716093..0000000 --- a/sys/victoriafalls/victoriafalls_server.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include - -#include "fs/ext2/ext2_driver.h" -#include "victoriafalls/victoriafalls.yunq.server.h" - -class VFSServer : public VFSServerBase { - public: - static glcr::ErrorOr> 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) {} -}; diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 237414b..7eefb66 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -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),* } From c645405ca8a9260eda46fb10d9f7c57c93f50359 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 5 May 2025 21:04:42 -0700 Subject: [PATCH 174/186] Fix build after removing a bunch of stuff. --- lib/mammoth/CMakeLists.txt | 1 - rust/lib/client/denali_client/build.rs | 2 +- rust/sys/denali/build.rs | 2 +- rust/sys/denali/denali.yunq | 28 +++++++++++++++++++++++ rust/sys/victoriafalls/build.rs | 2 +- rust/sys/victoriafalls/victoriafalls.yunq | 24 +++++++++++++++++++ sys/CMakeLists.txt | 2 -- 7 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 rust/sys/denali/denali.yunq create mode 100644 rust/sys/victoriafalls/victoriafalls.yunq diff --git a/lib/mammoth/CMakeLists.txt b/lib/mammoth/CMakeLists.txt index fa2bf6b..5ceed59 100644 --- a/lib/mammoth/CMakeLists.txt +++ b/lib/mammoth/CMakeLists.txt @@ -17,7 +17,6 @@ target_include_directories(mammoth target_link_libraries(mammoth glacier - victoriafalls_yunq yellowstone_yunq voyageurs_yunq zion_stub diff --git a/rust/lib/client/denali_client/build.rs b/rust/lib/client/denali_client/build.rs index 67e593c..f5228b3 100644 --- a/rust/lib/client/denali_client/build.rs +++ b/rust/lib/client/denali_client/build.rs @@ -1,7 +1,7 @@ use std::fs; fn main() { - let input_file = "../../../../sys/denali/lib/denali/denali.yunq"; + let input_file = "../../../sys/denali/denali.yunq"; println!("cargo::rerun-if-changed={input_file}"); diff --git a/rust/sys/denali/build.rs b/rust/sys/denali/build.rs index d5ac830..a57b29c 100644 --- a/rust/sys/denali/build.rs +++ b/rust/sys/denali/build.rs @@ -1,7 +1,7 @@ use std::fs; fn main() { - let input_file = "../../../sys/denali/lib/denali/denali.yunq"; + let input_file = "denali.yunq"; println!("cargo::rerun-if-changed={input_file}"); diff --git a/rust/sys/denali/denali.yunq b/rust/sys/denali/denali.yunq new file mode 100644 index 0000000..8348968 --- /dev/null +++ b/rust/sys/denali/denali.yunq @@ -0,0 +1,28 @@ +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; +} + + diff --git a/rust/sys/victoriafalls/build.rs b/rust/sys/victoriafalls/build.rs index 7e2d7d5..ad812f3 100644 --- a/rust/sys/victoriafalls/build.rs +++ b/rust/sys/victoriafalls/build.rs @@ -1,7 +1,7 @@ use std::fs; fn main() { - let input_file = "../../../sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq"; + let input_file = "victoriafalls.yunq"; println!("cargo::rerun-if-changed={input_file}"); diff --git a/rust/sys/victoriafalls/victoriafalls.yunq b/rust/sys/victoriafalls/victoriafalls.yunq new file mode 100644 index 0000000..1cc0d45 --- /dev/null +++ b/rust/sys/victoriafalls/victoriafalls.yunq @@ -0,0 +1,24 @@ +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; +} + diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 3f4f9ca..b6fe722 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -1,7 +1,5 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") -add_subdirectory(denali) -add_subdirectory(victoriafalls) add_subdirectory(voyageurs) add_subdirectory(yellowstone) From f26fd731166223d053ae572f6aa1b3c61075f67c Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 5 May 2025 23:13:59 -0700 Subject: [PATCH 175/186] [Zion][Denali] Move to MSI for AHCI devices. This will allow us to properly do interrupts for XHCI devices in the future. Also move PCI device header parsing to a shared library. Get rid of the old irq register format which supplied an irq number and instead pass the appropriate irq number back out to the caller. --- rust/Cargo.lock | 9 ++ rust/Cargo.toml | 2 +- rust/lib/mammoth/src/bindings.rs | 7 + rust/lib/mammoth/src/mem.rs | 6 + rust/lib/mammoth/src/syscall.rs | 11 +- rust/lib/pci/Cargo.toml | 8 ++ rust/lib/pci/src/device.rs | 89 ++++++++++++ rust/lib/pci/src/header.rs | 180 +++++++++++++++++++++++++ rust/lib/pci/src/lib.rs | 8 ++ rust/sys/denali/Cargo.toml | 1 + rust/sys/denali/src/ahci/controller.rs | 57 ++------ zion/include/zcall.h | 2 +- zion/include/ztypes.h | 2 +- zion/interrupt/apic.cpp | 17 --- zion/interrupt/driver_manager.cpp | 20 ++- zion/interrupt/driver_manager.h | 7 +- zion/interrupt/interrupt.cpp | 48 +++---- zion/interrupt/interrupt_enter.s | 10 +- zion/syscall/ipc.cpp | 7 +- zion/syscall/ipc.h | 2 +- zion/syscall/syscall.cpp | 2 +- 21 files changed, 371 insertions(+), 124 deletions(-) create mode 100644 rust/lib/pci/Cargo.toml create mode 100644 rust/lib/pci/src/device.rs create mode 100644 rust/lib/pci/src/header.rs create mode 100644 rust/lib/pci/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 982c6db..f20f302 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -34,6 +34,7 @@ version = "0.1.0" dependencies = [ "bitfield-struct", "mammoth", + "pci", "yellowstone-yunq", "yunq", "yunqc", @@ -83,6 +84,14 @@ dependencies = [ "linked_list_allocator", ] +[[package]] +name = "pci" +version = "0.1.0" +dependencies = [ + "bitfield-struct", + "mammoth", +] + [[package]] name = "prettyplease" version = "0.2.20" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1e43df4..f1886f6 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -2,7 +2,7 @@ members = [ "lib/client/denali_client", "lib/fs/ext2", - "lib/mammoth", + "lib/mammoth", "lib/pci", "lib/voyageurs", "lib/yellowstone", "lib/yunq", diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index 16309b3..c26dba3 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -258,6 +258,7 @@ pub const kZionPortSend: u64 = 81; pub const kZionPortRecv: u64 = 82; pub const kZionPortPoll: u64 = 83; pub const kZionIrqRegister: u64 = 88; +pub const kZionMsiIrqRegister: u64 = 89; pub const kZionEndpointCreate: u64 = 96; pub const kZionEndpointSend: u64 = 97; pub const kZionEndpointRecv: u64 = 98; @@ -478,6 +479,12 @@ pub struct ZIrqRegisterReq { } #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct ZMsiIrqRegisterReq { + pub irq_num: *mut u64, + pub port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct ZEndpointCreateReq { pub endpoint_cap: *mut z_cap_t, } diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 4b6d674..8d5af40 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -120,6 +120,12 @@ impl AsRef for MemoryRegion { } } +impl AsMut for MemoryRegion { + fn as_mut(&mut self) -> &mut T { + unsafe { (self.virt_addr as *mut T).as_mut().unwrap() } + } +} + impl Drop for MemoryRegion { fn drop(&mut self) { // FIXME: We shouldn't have to do this manual adjustment. diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 31acd94..2691458 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -310,16 +310,17 @@ pub fn port_poll( Ok((num_bytes, num_caps)) } -pub fn register_irq(irq_num: u64) -> Result { +pub fn register_msi_irq() -> Result<(Capability, u64), ZError> { + let mut irq_num: u64 = 0; let mut port_cap: z_cap_t = 0; syscall( - zion::kZionIrqRegister, - &zion::ZIrqRegisterReq { - irq_num, + zion::kZionMsiIrqRegister, + &zion::ZMsiIrqRegisterReq { + irq_num: &mut irq_num as *mut u64, port_cap: &mut port_cap, }, )?; - Ok(Capability::take(port_cap)) + Ok((Capability::take(port_cap), irq_num)) } pub fn endpoint_create() -> Result { diff --git a/rust/lib/pci/Cargo.toml b/rust/lib/pci/Cargo.toml new file mode 100644 index 0000000..f47f8b1 --- /dev/null +++ b/rust/lib/pci/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pci" +version = "0.1.0" +edition = "2024" + +[dependencies] +bitfield-struct = "0.8.0" +mammoth = {path = "../mammoth/"} diff --git a/rust/lib/pci/src/device.rs b/rust/lib/pci/src/device.rs new file mode 100644 index 0000000..a00eb7e --- /dev/null +++ b/rust/lib/pci/src/device.rs @@ -0,0 +1,89 @@ +use alloc::vec::Vec; +use mammoth::{cap::Capability, mem::MemoryRegion, syscall, zion::ZError}; + +use crate::header::{ + PciCapabilityPointer, PciDeviceHeader, PciHeaderType, PciMsiCapability, PciMsiControl, + get_header_type, +}; + +pub struct PciDevice { + memory_region: MemoryRegion, +} + +impl PciDevice { + pub fn from(mut memory_region: MemoryRegion) -> Result { + match get_header_type(&memory_region)? { + PciHeaderType::Device => {} + t => { + mammoth::debug!("Invalid header type: {:?}", t); + return Err(ZError::INVALID_ARGUMENT); + } + } + Ok(Self { memory_region }) + } + + pub fn from_cap(capability: Capability) -> Result { + Self::from(MemoryRegion::from_cap(capability)?) + } + + pub fn header(&self) -> &PciDeviceHeader { + self.memory_region.as_ref() + } + + pub fn get_capability_list(&self) -> Result, ZError> { + let status = self.header().status; + if !status.capability_list() { + return Err(ZError::NOT_FOUND); + } + + let mut cap_offset = self.header().capability_ptr; + + let mut cap_vec = Vec::new(); + while cap_offset != 0 { + let cap_ptr: &PciCapabilityPointer = unsafe { + self.memory_region + .raw_ptr_at_offset::(cap_offset as u64) + .as_ref() + .unwrap() + }; + cap_vec.push(cap_ptr); + cap_offset = cap_ptr.next_cap_offset; + } + + Ok(cap_vec) + } + + pub fn register_msi(&mut self) -> Result { + let caps = self.get_capability_list()?; + const MSI_CAP_ID: u8 = 0x05; + let msi_cap: &PciCapabilityPointer = caps + .iter() + .find(|cp| cp.cap_id == MSI_CAP_ID) + .ok_or(ZError::NOT_FOUND)?; + + let msi_cap = unsafe { + ((msi_cap as *const PciCapabilityPointer) as *mut PciMsiCapability) + .as_mut() + .unwrap() + }; + + mammoth::debug!("MSI Cap: {:#x?}", msi_cap); + + let control = msi_cap.msi_control; + assert!(control.capable_address_64()); + assert!(control.multi_message_capable() == 0); + + // FIXME: These probably need to be volatile writes. + let header: &mut PciDeviceHeader = self.memory_region.as_mut(); + header.command = header.command.with_interrupt_disable(true); + msi_cap.msi_control = control.with_msi_enable(true); + msi_cap.msi_addr_lower = 0xFEE00000; + msi_cap.msi_addr_upper_or_data = 0x0; + + let (cap, irq_num) = syscall::register_msi_irq()?; + + msi_cap.msi_data_if_64 = irq_num as u32; + + Ok(cap) + } +} diff --git a/rust/lib/pci/src/header.rs b/rust/lib/pci/src/header.rs new file mode 100644 index 0000000..ff2a144 --- /dev/null +++ b/rust/lib/pci/src/header.rs @@ -0,0 +1,180 @@ +use bitfield_struct::bitfield; +use mammoth::{mem::MemoryRegion, zion::ZError}; + +#[bitfield(u16)] +pub struct PciCommand { + io_space_enable: bool, + memory_space_enable: bool, + bus_master_enable: bool, + + #[bits(access=RO)] + special_cycles_enable: bool, + + #[bits(access=RO)] + memory_write_and_invalidate_enable: bool, + + #[bits(access=RO)] + vga_pallette_snoop_enable: bool, + + parity_error_response_enable: bool, + + #[bits(access=RO)] + wait_cycle_enable: bool, + + serr_enable: bool, + + fast_back_to_back_enable: bool, + + /// Parity is reversed here, set to true to disable. + /// Does not affect MSI. + pub interrupt_disable: bool, + + #[bits(5)] + __: u8, +} + +#[bitfield(u16)] +pub struct PciStatus { + #[bits(3)] + __: u8, + + #[bits(access=RO)] + pub interrupt_status: bool, + #[bits(access=RO)] + pub capability_list: bool, + #[bits(access=RO)] + pub capable_of_66mhz: bool, + + ___: bool, + + #[bits(access=RO)] + pub fast_back_to_back_capabale: bool, + + /// Write 1 to clear + pub master_data_parity_error: bool, + + #[bits(2, access=RO)] + pub devsel_timing: u8, + + /// Write 1 to clear + pub signaled_target_abort: bool, + /// Write 1 to clear + pub received_target_abort: bool, + /// Write 1 to clear + pub received_master_abort: bool, + /// Write 1 to clear + pub signaled_system_erro: bool, + /// Write 1 to clear + pub detected_parity_error: bool, +} + +/// Header definitions from https://wiki.osdev.org/PCI +#[repr(C, packed)] +#[derive(Debug)] +pub struct HeaderShared { + pub vendor_id: u16, + pub device_id: u16, + pub command: PciCommand, + pub status: PciStatus, + pub revision_id: u8, + pub prog_if: u8, + pub subclass: u8, + pub class_code: u8, + pub cache_line_size: u8, + pub latency_timer: u8, + pub header_type: u8, + bist: u8, +} + +const _: () = assert!(size_of::() == 16); + +#[repr(C, packed)] +#[derive(Debug)] +pub struct PciDeviceHeader { + pub vendor_id: u16, + pub device_id: u16, + pub command: PciCommand, + pub status: PciStatus, + pub revision_id: u8, + pub prog_if: u8, + pub subclass: u8, + pub class_code: u8, + pub cache_line_size: u8, + pub latency_timer: u8, + pub header_type: u8, + bist: u8, + pub bars: [u32; 6], + pub cardbus_cis_ptr: u32, + pub subsystem_vendor_id: u16, + pub subsystem_id: u16, + pub expansion_rom_address: u32, + pub capability_ptr: u8, + __: [u8; 7], + pub interrupt_line: u8, + pub interrupt_pin: u8, + pub min_grant: u8, + pub max_latency: u8, +} + +const _: () = assert!(size_of::() == 0x40); + +#[repr(C, packed)] +#[derive(Debug)] +pub struct PciCapabilityPointer { + pub cap_id: u8, + pub next_cap_offset: u8, +} + +#[bitfield(u16)] +pub struct PciMsiControl { + pub msi_enable: bool, + #[bits(3, access=RO)] + pub multi_message_capable: u8, + #[bits(3)] + pub multi_message_enable: u8, + + #[bits(access=RO)] + pub capable_address_64: bool, + + #[bits(access=RO)] + pub per_vector_masking: bool, + + #[bits(7)] + __: u8, +} + +#[repr(C, packed)] +#[derive(Debug)] +pub struct PciMsiCapability { + pub cap_id: u8, + pub next_cap_offset: u8, + pub msi_control: PciMsiControl, + pub msi_addr_lower: u32, + pub msi_addr_upper_or_data: u32, + pub msi_data_if_64: u32, + pub mask: u32, + pub pending: u32, +} + +#[derive(Debug)] +pub enum PciHeaderType { + Device, + PciBridge, + CardBusBridge, +} + +pub fn get_header_type(memory_region: &MemoryRegion) -> Result { + let shared: &HeaderShared = memory_region.as_ref(); + // The only reference I can find to the high bit here is at + // https://www.khoury.northeastern.edu/~pjd/cs7680/homework/pci-enumeration.html + // > Header Type: bit 7 (0x80) indicates whether it is a multi-function device, + match shared.header_type & (!0x80) { + 0x0 => Ok(PciHeaderType::Device), + 0x1 => Ok(PciHeaderType::PciBridge), + 0x2 => Ok(PciHeaderType::CardBusBridge), + _ => { + mammoth::debug!("Unknown pci header type: {:#x}", shared.header_type); + Err(ZError::INVALID_ARGUMENT) + } + } +} diff --git a/rust/lib/pci/src/lib.rs b/rust/lib/pci/src/lib.rs new file mode 100644 index 0000000..44e141a --- /dev/null +++ b/rust/lib/pci/src/lib.rs @@ -0,0 +1,8 @@ +#![no_std] + +extern crate alloc; + +mod device; +mod header; + +pub use device::PciDevice; diff --git a/rust/sys/denali/Cargo.toml b/rust/sys/denali/Cargo.toml index dcb3cd0..ad19780 100644 --- a/rust/sys/denali/Cargo.toml +++ b/rust/sys/denali/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] bitfield-struct = "0.8.0" mammoth = { path = "../../lib/mammoth" } +pci = { path = "../../lib/pci" } yunq = { path = "../../lib/yunq" } yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/denali/src/ahci/controller.rs b/rust/sys/denali/src/ahci/controller.rs index f62645d..2a402f0 100644 --- a/rust/sys/denali/src/ahci/controller.rs +++ b/rust/sys/denali/src/ahci/controller.rs @@ -6,6 +6,7 @@ use mammoth::{ thread, zion::ZError, }; +use pci::PciDevice; use crate::ahci::{ port::{AhciDeviceDetection, AhciInterfacePowerManagement}, @@ -14,36 +15,8 @@ use crate::ahci::{ use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController}; -#[derive(Debug)] -#[repr(C, packed)] -pub struct PciDeviceHeader { - pub vendor_id: u16, - pub device_id: u16, - pub command_reg: u16, - pub status_reg: u16, - pub revision: u8, - pub prog_interface: u8, - pub subclass: u8, - pub class_code: u8, - pub cache_line_size: u8, - pub latency_timer: u8, - pub header_type: u8, - pub bist: u8, - pub bars: [u32; 5], - pub abar: u32, - __: u32, - pub subsystem_id: u32, - pub expansion_rom: u32, - pub cap_ptr: u8, - ___: [u8; 7], - pub interrupt_line: u8, - pub interrupt_pin: u8, - pub min_grant: u8, - pub max_latency: u8, -} - pub struct AhciController { - pci_header: &'static mut PciDeviceHeader, + pci_device: Mutex, hba: Mutex<&'static mut AhciHba>, ports: [Option; 32], hba_vaddr: u64, @@ -51,13 +24,13 @@ pub struct AhciController { impl AhciController { pub fn new(pci_memory: Capability) -> Self { - let pci_vaddr = mem::map_cap_and_leak(pci_memory); - let pci_header = unsafe { (pci_vaddr as *mut PciDeviceHeader).as_mut().unwrap() }; + let pci_device = PciDevice::from_cap(pci_memory).unwrap(); - let hba_vaddr = mem::map_direct_physical_and_leak(pci_header.abar as u64, 0x1100); + let hba_vaddr = + mem::map_direct_physical_and_leak(pci_device.header().bars[5] as u64, 0x1100); let hba = unsafe { (hba_vaddr as *mut AhciHba).as_mut().unwrap() }; let mut controller = Self { - pci_header, + pci_device: Mutex::new(pci_device), hba: Mutex::new(hba), ports: [const { None }; 32], hba_vaddr, @@ -100,17 +73,8 @@ impl AhciController { } } - fn irq_num(&self) -> u64 { - match self.pci_header.interrupt_pin { - 1 => mammoth::zion::kZIrqPci1, - 2 => mammoth::zion::kZIrqPci2, - 3 => mammoth::zion::kZIrqPci3, - 4 => mammoth::zion::kZIrqPci4, - _ => panic!( - "Unrecognized pci interrupt pin {}", - self.pci_header.interrupt_pin - ), - } + fn register_irq(&self) -> Result { + self.pci_device.lock().register_msi() } fn handle_irq(&self) { @@ -184,9 +148,8 @@ impl AhciController { pub fn spawn_irq_thread(controller: Arc) -> thread::JoinHandle { let irq_thread = move || { - let irq_num = controller.irq_num(); - let irq_port = - mammoth::port::PortServer::from_cap(mammoth::syscall::register_irq(irq_num).unwrap()); + let irq_port_cap = controller.register_irq().unwrap(); + let irq_port = mammoth::port::PortServer::from_cap(irq_port_cap); controller.hba.lock().global_host_control.update(|ghc| { ghc.set_interrupt_enable(true); }); diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 31e45df..6092037 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -48,7 +48,7 @@ SYS5(PortRecv, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*, SYS5(PortPoll, z_cap_t, port_cap, uint64_t*, num_bytes, void*, data, uint64_t*, num_caps, z_cap_t*, caps); -SYS2(IrqRegister, uint64_t, irq_num, z_cap_t*, port_cap); +SYS2(MsiIrqRegister, uint64_t*, irq_num, z_cap_t*, port_cap); SYS1(EndpointCreate, z_cap_t*, endpoint_cap); SYS6(EndpointSend, z_cap_t, endpoint_cap, uint64_t, num_bytes, const void*, diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index 490e0d7..b60db9c 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -43,7 +43,7 @@ const uint64_t kZionPortSend = 0x51; const uint64_t kZionPortRecv = 0x52; const uint64_t kZionPortPoll = 0x53; -const uint64_t kZionIrqRegister = 0x58; +const uint64_t kZionMsiIrqRegister = 0x59; const uint64_t kZionEndpointCreate = 0x60; const uint64_t kZionEndpointSend = 0x61; diff --git a/zion/interrupt/apic.cpp b/zion/interrupt/apic.cpp index 927edfd..66d7e0c 100644 --- a/zion/interrupt/apic.cpp +++ b/zion/interrupt/apic.cpp @@ -136,23 +136,6 @@ Apic::Apic(const ApicConfiguration& config) // FIXME: Get this offset from ACPI. SetIoDoubleReg(0x14, 0x20 | APIC_MASK); - // Map Keyboard - SetIoDoubleReg(0x12, 0x22); - - // For now set these based on the presets in the following spec. - // http://web.archive.org/web/20161130153145/http://download.intel.com/design/chipsets/datashts/29056601.pdf - // FIXME: However in the future we should likely use the MADT for legacy - // interrupts and AML for PCI etc. - // PCI Line 1-4 - // FIXME: These should be level triggered according to spec I believe - // but because we handle the interrupt outside of the kernel it is tricky - // to wait to send the end of interrupt message. - // Because of this leave them as edge triggered and send EOI immediately. - SetIoDoubleReg(0x30, 0x30); - SetIoDoubleReg(0x32, 0x31); - SetIoDoubleReg(0x34, 0x32); - SetIoDoubleReg(0x36, 0x33); - DumpInfo(); } diff --git a/zion/interrupt/driver_manager.cpp b/zion/interrupt/driver_manager.cpp index 67e78fc..3aa2bc5 100644 --- a/zion/interrupt/driver_manager.cpp +++ b/zion/interrupt/driver_manager.cpp @@ -9,18 +9,24 @@ DriverManager& DriverManager::Get() { return *gDriverManager; } DriverManager::DriverManager() { gDriverManager = this; } void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) { - if (!driver_map_.Contains(irq_num)) { + if (irq_num < IRQ_OFFSET) { + dbgln("WARN IRQ {x} below min offset {x}", irq_num, IRQ_OFFSET); + } + uint64_t offset = irq_num - IRQ_OFFSET; + if (offset >= driver_list_.size()) { dbgln("WARN IRQ for {x} with no registered driver", irq_num); return; } - driver_map_.at(irq_num)->Send(glcr::Move(message)); + driver_list_[offset]->Send(glcr::Move(message)); } -glcr::ErrorCode DriverManager::RegisterListener(uint64_t irq_num, - glcr::RefPtr port) { - if (driver_map_.Contains(irq_num)) { - return glcr::ALREADY_EXISTS; +glcr::ErrorOr DriverManager::RegisterListener( + glcr::RefPtr port) { + if (driver_list_.size() + IRQ_OFFSET >= 0xFF) { + return glcr::EXHAUSTED; } - return driver_map_.Insert(irq_num, port); + uint8_t offset = (driver_list_.size() + IRQ_OFFSET); + driver_list_.PushBack(port); + return offset; } diff --git a/zion/interrupt/driver_manager.h b/zion/interrupt/driver_manager.h index db205c8..3fb897f 100644 --- a/zion/interrupt/driver_manager.h +++ b/zion/interrupt/driver_manager.h @@ -15,9 +15,10 @@ class DriverManager { void WriteMessage(uint64_t irq_num, IpcMessage&& message); - [[nodiscard]] glcr::ErrorCode RegisterListener(uint64_t irq_num, - glcr::RefPtr port); + [[nodiscard]] glcr::ErrorOr RegisterListener( + glcr::RefPtr port); private: - glcr::HashMap> driver_map_; + const uint64_t IRQ_OFFSET = 0x60; + glcr::Vector> driver_list_; }; diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 2c3692d..7858e88 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -109,7 +109,7 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) { } else { dbgln("GDT"); } - dbgln("Index: {}", err >> 3); + dbgln("Index: {} ({x})", err >> 3, err >> 3); dbgln("RIP: {x}", frame->rip); dbgln("RAX: {x}, RBX: {x}, RCX: {x}, RDX: {x}", frame->rax, frame->rbx, frame->rcx, frame->rdx); @@ -197,40 +197,27 @@ extern "C" void interrupt_apic_timer(InterruptFrame*) { gScheduler->Preempt(); } -extern "C" void isr_keyboard(); -extern "C" void interrupt_keyboard(InterruptFrame*) { - glcr::Array data(1); - data[0] = inb(0x60); - IpcMessage msg{.data = glcr::Move(data)}; - DriverManager::Get().WriteMessage(kZIrqKbd, glcr::Move(msg)); - +extern "C" void isr_60(); +extern "C" void interrupt_60(InterruptFrame*) { + DriverManager::Get().WriteMessage(0x60, {}); gApic->SignalEOI(); } -extern "C" void isr_pci1(); -extern "C" void interrupt_pci1(InterruptFrame*) { - DriverManager::Get().WriteMessage(kZIrqPci1, {}); +extern "C" void isr_61(); +extern "C" void interrupt_61(InterruptFrame*) { + DriverManager::Get().WriteMessage(0x61, {}); gApic->SignalEOI(); } -extern "C" void isr_pci2(); -extern "C" void interrupt_pci2(InterruptFrame*) { - DriverManager::Get().WriteMessage(kZIrqPci2, {}); - dbgln("Interrupt PCI line 2"); +extern "C" void isr_62(); +extern "C" void interrupt_62(InterruptFrame*) { + DriverManager::Get().WriteMessage(0x62, {}); gApic->SignalEOI(); } -extern "C" void isr_pci3(); -extern "C" void interrupt_pci3(InterruptFrame*) { - DriverManager::Get().WriteMessage(kZIrqPci3, {}); - dbgln("Interrupt PCI line 3"); - gApic->SignalEOI(); -} - -extern "C" void isr_pci4(); -extern "C" void interrupt_pci4(InterruptFrame*) { - DriverManager::Get().WriteMessage(kZIrqPci4, {}); - dbgln("Interrupt PCI line 4"); +extern "C" void isr_63(); +extern "C" void interrupt_63(InterruptFrame*) { + DriverManager::Get().WriteMessage(0x63, {}); gApic->SignalEOI(); } @@ -243,12 +230,11 @@ void InitIdt() { gIdt[0x20] = CreateDescriptor(isr_timer); gIdt[0x21] = CreateDescriptor(isr_apic_timer); - gIdt[0x22] = CreateDescriptor(isr_keyboard); - gIdt[0x30] = CreateDescriptor(isr_pci1); - gIdt[0x31] = CreateDescriptor(isr_pci2); - gIdt[0x32] = CreateDescriptor(isr_pci3); - gIdt[0x33] = CreateDescriptor(isr_pci4); + gIdt[0x60] = CreateDescriptor(isr_60); + gIdt[0x61] = CreateDescriptor(isr_61); + gIdt[0x62] = CreateDescriptor(isr_62); + gIdt[0x63] = CreateDescriptor(isr_63); InterruptDescriptorTablePointer idtp{ .size = sizeof(gIdt), diff --git a/zion/interrupt/interrupt_enter.s b/zion/interrupt/interrupt_enter.s index db02a22..167d631 100644 --- a/zion/interrupt/interrupt_enter.s +++ b/zion/interrupt/interrupt_enter.s @@ -63,10 +63,8 @@ isr_handler fpe_fault isr_handler timer isr_handler apic_timer -isr_handler keyboard - -isr_handler pci1 -isr_handler pci2 -isr_handler pci3 -isr_handler pci4 +isr_handler 60 +isr_handler 61 +isr_handler 62 +isr_handler 63 diff --git a/zion/syscall/ipc.cpp b/zion/syscall/ipc.cpp index 021695c..55c0799 100644 --- a/zion/syscall/ipc.cpp +++ b/zion/syscall/ipc.cpp @@ -156,13 +156,14 @@ glcr::ErrorCode PortPoll(ZPortPollReq* req) { return TranslateIpcMessageToResponse(msg, req); } -glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) { +glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req) { auto& proc = gScheduler->CurrentProcess(); - glcr::RefPtr port = glcr::MakeRefCounted(); *req->port_cap = proc.AddNewCapability(port); - return DriverManager::Get().RegisterListener(req->irq_num, port); + ASSIGN_OR_RETURN(*req->irq_num, DriverManager::Get().RegisterListener(port)); + + return glcr::OK; } glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req) { diff --git a/zion/syscall/ipc.h b/zion/syscall/ipc.h index 4a3ae97..9b0f072 100644 --- a/zion/syscall/ipc.h +++ b/zion/syscall/ipc.h @@ -12,7 +12,7 @@ glcr::ErrorCode PortCreate(ZPortCreateReq* req); glcr::ErrorCode PortSend(ZPortSendReq* req); glcr::ErrorCode PortRecv(ZPortRecvReq* req); glcr::ErrorCode PortPoll(ZPortPollReq* req); -glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req); +glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req); glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req); glcr::ErrorCode EndpointSend(ZEndpointSendReq* req); diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 70e9677..096c931 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -77,7 +77,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) { CASE(PortSend); CASE(PortRecv); CASE(PortPoll); - CASE(IrqRegister); + CASE(MsiIrqRegister); CASE(EndpointCreate); CASE(EndpointSend); CASE(EndpointRecv); From 93d1299bd992255fcbcb87aab3ab5ba5985692dc Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Mon, 5 May 2025 23:20:25 -0700 Subject: [PATCH 176/186] [PCI] Improved MSI Comments for my future self. --- rust/lib/pci/src/device.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/rust/lib/pci/src/device.rs b/rust/lib/pci/src/device.rs index a00eb7e..ab1b25d 100644 --- a/rust/lib/pci/src/device.rs +++ b/rust/lib/pci/src/device.rs @@ -67,21 +67,30 @@ impl PciDevice { .unwrap() }; - mammoth::debug!("MSI Cap: {:#x?}", msi_cap); - let control = msi_cap.msi_control; - assert!(control.capable_address_64()); - assert!(control.multi_message_capable() == 0); + assert!( + control.capable_address_64(), + "We don't handle the non-64bit case for MSI yet." + ); + assert!( + control.multi_message_capable() == 0, + "We don't yet handle multi-message capable devices." + ); // FIXME: These probably need to be volatile writes. let header: &mut PciDeviceHeader = self.memory_region.as_mut(); header.command = header.command.with_interrupt_disable(true); msi_cap.msi_control = control.with_msi_enable(true); + + // For setting addr and data field, see intel ref + // Vol 3. Section 11.11 + // TODO: This is hardcoded to APIC 0 currently. msi_cap.msi_addr_lower = 0xFEE00000; msi_cap.msi_addr_upper_or_data = 0x0; let (cap, irq_num) = syscall::register_msi_irq()?; + // TODO: Do we need to set the specific level triggering options for this? msi_cap.msi_data_if_64 = irq_num as u32; Ok(cap) From 5a20c23569171f9e5ee718cd97970f98261490f6 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 6 May 2025 22:22:02 -0700 Subject: [PATCH 177/186] First pass at getting Acadia running under bochs. - Create a bochs build script. - Properly configure COM1 --- .bochsrc | 12 +++++++++++ .gitignore | 3 +++ scripts/bochs.sh | 19 ++++++++++++++++ scripts/build.sh | 32 +++++++++++++++++++++++++++ scripts/build_image.sh | 48 ++++++++++++++++++++++++----------------- scripts/qemu.sh | 23 +++----------------- zion/debug/debug.cpp | 49 ++++++++++++++++++++++++++++++++++++++++++ zion/debug/debug.h | 6 ++++++ zion/zion.cpp | 1 + 9 files changed, 153 insertions(+), 40 deletions(-) create mode 100644 .bochsrc create mode 100755 scripts/bochs.sh create mode 100755 scripts/build.sh diff --git a/.bochsrc b/.bochsrc new file mode 100644 index 0000000..1757d33 --- /dev/null +++ b/.bochsrc @@ -0,0 +1,12 @@ +megs: 1024 +ata0-master: type=disk, path=builddbg/disk.img, mode=flat, cylinders=512, heads=16, spt=50 +display_library: sdl2, options="gui_debug" +boot: disk +com1: enabled=1, mode=file, dev=serial.out, baud=9600, parity=none, bits=8, stopbits=1 +cpu: model=corei7_sandy_bridge_2600k +pci: enabled=1, chipset=i440bx +log: bochs.log +# TODO: Make this portable, by building bochs locally. +romimage: file=/home/drew/opt/bochs/share/bochs/BIOS-bochs-latest +vgaromimage: file=/home/drew/opt/bochs/share/bochs/VGABIOS-lgpl-latest.bin +vga: extension=vbe diff --git a/.gitignore b/.gitignore index a74dbf9..7e2de93 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,9 @@ __pycache__/ .ccls-cache/ compile_commands.json +bochs.log +serial.out + sysroot/bin sysroot/usr sysroot/.crates.toml diff --git a/scripts/bochs.sh b/scripts/bochs.sh new file mode 100755 index 0000000..9a0d982 --- /dev/null +++ b/scripts/bochs.sh @@ -0,0 +1,19 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +BUILD_DIR="${DIR}/../builddbg" + +bash ${DIR}/build.sh +sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img + +BOCHS_ARGS= +if [[ $1 == "debug" ]]; then + BOCHS_ARGS+="--dbg" +fi + +# TODO Make this portable, build bochs as a part of toolchain? +~/opt/bochs/bin/bochs + diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..9b64905 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,32 @@ +#! /bin/bash + +set -e + +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo $DIR + +BUILD_DIR="${DIR}/../builddbg" + +pushd $BUILD_DIR +ninja +ninja install + +CARGO_USR_ROOT="${DIR}/../sysroot/usr/" +CARGO_SYS_ROOT="${DIR}/../sysroot/" + +# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml +pushd "${DIR}/../rust" + +for BIN in ${DIR}/../rust/usr/*/; do + cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT +done + +for BIN in ${DIR}/../rust/sys/*/; do + cargo install --all-features --force --path "${BIN}" --root $CARGO_SYS_ROOT +done +popd + +popd + + diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 8500427..2fd5867 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -1,7 +1,11 @@ -#!/us +#! /bin/bash set -e +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +REPO_ROOT="$SCRIPT_DIR/.." +BUILD_DIR="$REPO_ROOT/builddbg" + if [[ $# -ne 1 ]]; then echo "Must specify disk image name." fi @@ -15,11 +19,14 @@ if [ -z "$dev" ]; then fi echo "Loopback device: ${dev}" +EFI_DIR="$BUILD_DIR/efi" +SYSROOT="$BUILD_DIR/sysroot" + cleanup() { - umount efi - rm -rf efi - umount sysroot - rm -rf sysroot + umount $EFI_DIR + rm -rf $EFI_DIR + umount $SYSROOT + rm -rf $SYSROOT losetup -d $dev } trap cleanup EXIT @@ -30,22 +37,23 @@ mke2fs "${dev}p2" limine bios-install "${dev}" -mkdir -p efi/ -mount "${dev}p1" efi/ -mkdir -p efi/EFI/BOOT -cp /usr/share/limine/BOOTX64.EFI efi/EFI/BOOT -cp /usr/share/limine/limine-bios.sys efi/ -cp ../zion/boot/limine.conf efi/ -cp zion/zion efi/ -mkdir -p efi/sys -cp ../sysroot/bin/yellowstone efi/sys/yellowstone -cp ../sysroot/bin/denali efi/sys/denali -cp ../sysroot/bin/victoriafalls efi/sys/victoriafalls +mkdir -p $EFI_DIR +mount "${dev}p1" $EFI_DIR -mkdir -p sysroot -mount "${dev}p2" sysroot/ -rsync -a ../sysroot . -ls sysroot/ +mkdir -p $EFI_DIR/EFI/BOOT +cp /usr/share/limine/BOOTX64.EFI $EFI_DIR/EFI/BOOT +cp /usr/share/limine/limine-bios.sys $EFI_DIR +cp $REPO_ROOT/zion/boot/limine.conf $EFI_DIR/ +cp $BUILD_DIR/zion/zion $EFI_DIR/ +mkdir -p $EFI_DIR/sys +cp $REPO_ROOT/sysroot/bin/yellowstone $EFI_DIR/sys/yellowstone +cp $REPO_ROOT/sysroot/bin/denali $EFI_DIR/sys/denali +cp $REPO_ROOT/sysroot/bin/victoriafalls $EFI_DIR/sys/victoriafalls + +mkdir -p $SYSROOT +mount "${dev}p2" $SYSROOT +rsync -a "$REPO_ROOT/sysroot" $BUILD_DIR +ls $SYSROOT chown drew:drew $1 diff --git a/scripts/qemu.sh b/scripts/qemu.sh index 40bf1c7..22d6f98 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -8,26 +8,9 @@ echo $DIR BUILD_DIR="${DIR}/../builddbg" -pushd $BUILD_DIR -ninja -ninja install -CARGO_USR_ROOT="${DIR}/../sysroot/usr/" -CARGO_SYS_ROOT="${DIR}/../sysroot/" - -# Need to pushd so rustup gets the toolchain from rust/rust_toolchain.toml -pushd "${DIR}/../rust" - -for BIN in ${DIR}/../rust/usr/*/; do - cargo install --force --path "${BIN}" --root $CARGO_USR_ROOT -done - -for BIN in ${DIR}/../rust/sys/*/; do - cargo install --all-features --force --path "${BIN}" --root $CARGO_SYS_ROOT -done -popd - -sudo sh ${DIR}/build_image.sh disk.img +bash ${DIR}/build.sh +sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img QEMU_ARGS= if [[ $1 == "debug" ]]; then @@ -35,7 +18,7 @@ if [[ $1 == "debug" ]]; then fi # Use machine q35 to access PCI devices. -qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 +qemu-system-x86_64 -machine q35 -d guest_errors -m 1G -serial stdio -hda ${BUILD_DIR}/disk.img ${QEMU_ARGS} -device nec-usb-xhci,id=xhci -device usb-kbd,bus=xhci.0 popd # Extra options to add to this script in the future. diff --git a/zion/debug/debug.cpp b/zion/debug/debug.cpp index a2929d9..096443a 100644 --- a/zion/debug/debug.cpp +++ b/zion/debug/debug.cpp @@ -39,3 +39,52 @@ void dbgln(const glcr::StringView& str) { dbg(str); dbg("\n"); } + +namespace { + +// Helper function to write a byte to a specified COM1 register offset +void write_serial_port(uint16_t offset, uint8_t value) { + outb(COM1 + offset, value); +} + +// Helper function to read a byte from a specified COM1 register offset +uint8_t read_serial_port(uint16_t offset) { return inb(COM1 + offset); } + +} // namespace + +namespace serial { + +// Function to initialize the serial port with a given baud rate +void initialize(uint32_t baud_rate) { + // Disable interrupts + write_serial_port(1, 0x00); + + // Enable DLAB (Divisor Latch Access Bit) in Line Control Register (LCR) + write_serial_port(3, read_serial_port(3) | 0x80); + + // Calculate the divisor + // Baud rate = 115200 / divisor (approximately) + uint16_t divisor = 115200 / baud_rate; + + // Set the low byte of the divisor + write_serial_port(0, divisor & 0xFF); + + // Set the high byte of the divisor + write_serial_port(1, (divisor >> 8) & 0xFF); + + // Clear DLAB and set data bits, stop bits, and parity + // 8 data bits, 1 stop bit, no parity + write_serial_port(3, 0x03); // 00000011b + + // Enable FIFO, clear buffers, set trigger level (e.g., 1 byte) + write_serial_port(2, 0xC7); // 11000111b + + // Enable IRQs (optional, for interrupt-driven communication) + // write_serial_port(1, 0x01); + + // Set Modem Control Register (MCR) + // Enable RTS, DTR, OUT1, OUT2, loopback off, IRQs enabled + write_serial_port(4, 0x0B); // 00001011b +} + +} // namespace serial diff --git a/zion/debug/debug.h b/zion/debug/debug.h index 63b0d0e..d3a6fd4 100644 --- a/zion/debug/debug.h +++ b/zion/debug/debug.h @@ -37,3 +37,9 @@ void panic(const char* str, Args&&... args) { #define UNREACHABLE \ panic("Unreachable {}, {}", glcr::StringView(__FILE__), __LINE__); \ __builtin_unreachable(); + +namespace serial { + +void initialize(uint32_t baud_rate); + +} diff --git a/zion/zion.cpp b/zion/zion.cpp index fe9e497..b2ee2e7 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -20,6 +20,7 @@ #include "syscall/syscall.h" extern "C" void zion() { + serial::initialize(9600); dbgln("[boot] Init GDT & IDT."); InitGdt(); InitIdt(); From 0dfa6008ecdfde502bdb13fad69ba0c575ec3752 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Tue, 6 May 2025 22:26:00 -0700 Subject: [PATCH 178/186] Enable bochs terminal output. --- .bochsrc | 1 + scripts/bochs.sh | 2 +- zion/debug/debug.cpp | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.bochsrc b/.bochsrc index 1757d33..2e7d283 100644 --- a/.bochsrc +++ b/.bochsrc @@ -10,3 +10,4 @@ log: bochs.log romimage: file=/home/drew/opt/bochs/share/bochs/BIOS-bochs-latest vgaromimage: file=/home/drew/opt/bochs/share/bochs/VGABIOS-lgpl-latest.bin vga: extension=vbe +port_e9_hack: enabled=1 diff --git a/scripts/bochs.sh b/scripts/bochs.sh index 9a0d982..be2c781 100755 --- a/scripts/bochs.sh +++ b/scripts/bochs.sh @@ -15,5 +15,5 @@ if [[ $1 == "debug" ]]; then fi # TODO Make this portable, build bochs as a part of toolchain? -~/opt/bochs/bin/bochs +~/opt/bochs/bin/bochs $BOCHS_ARGS -q diff --git a/zion/debug/debug.cpp b/zion/debug/debug.cpp index 096443a..7d10174 100644 --- a/zion/debug/debug.cpp +++ b/zion/debug/debug.cpp @@ -5,14 +5,18 @@ #define COM1 0x3f8 +#define BOCHS_DBG 1 + namespace { bool is_transmit_empty() { return (inb(COM1 + 5) & 0x20) != 0; } void dbgputchar(char c) { - while (!is_transmit_empty()) - ; + while (!is_transmit_empty()); outb(COM1, c); +#if BOCHS_DBG + outb(0xe9, c); +#endif } void dbg(const glcr::StringView& str) { From fff3d8927cbd5f327d920eb94356ca6146d67e4f Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 May 2025 01:41:16 -0700 Subject: [PATCH 179/186] Fix bochs debugging argument. --- scripts/bochs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bochs.sh b/scripts/bochs.sh index be2c781..52180e8 100755 --- a/scripts/bochs.sh +++ b/scripts/bochs.sh @@ -11,7 +11,7 @@ sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img BOCHS_ARGS= if [[ $1 == "debug" ]]; then - BOCHS_ARGS+="--dbg" + BOCHS_ARGS+="-dbg" fi # TODO Make this portable, build bochs as a part of toolchain? From f2c2cff98a63316e0f3cf30b7c99a1ce92d75feb Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 May 2025 01:41:27 -0700 Subject: [PATCH 180/186] Enable bochs magic breakpoint. --- .bochsrc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.bochsrc b/.bochsrc index 2e7d283..5a417a9 100644 --- a/.bochsrc +++ b/.bochsrc @@ -11,3 +11,5 @@ romimage: file=/home/drew/opt/bochs/share/bochs/BIOS-bochs-latest vgaromimage: file=/home/drew/opt/bochs/share/bochs/VGABIOS-lgpl-latest.bin vga: extension=vbe port_e9_hack: enabled=1 +# Breaks on XCHGW %BX, %BX +magic_break: enabled=1 From b67763324850ecdbb2873325c463f2c2e24506e4 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 May 2025 01:44:09 -0700 Subject: [PATCH 181/186] [Zion][Yellowstone] First pass at adding PCI ioport access. --- rust/lib/mammoth/build.rs | 7 ++ rust/lib/mammoth/src/bindings.rs | 196 ++++++----------------------- rust/lib/mammoth/src/syscall.rs | 22 ++++ rust/sys/yellowstone/src/main.rs | 9 +- rust/sys/yellowstone/src/pci.rs | 103 ++++++++++----- rust/sys/yellowstone/src/server.rs | 6 +- zion/CMakeLists.txt | 2 + zion/common/port.h | 10 ++ zion/include/zcall.h | 11 ++ zion/include/ztypes.h | 5 + zion/loader/init_loader.cpp | 5 +- zion/object/kernel_object.h | 4 + zion/object/pci_port.cpp | 46 +++++++ zion/object/pci_port.h | 60 +++++++++ zion/syscall/pci.cpp | 44 +++++++ zion/syscall/pci.h | 6 + 16 files changed, 337 insertions(+), 199 deletions(-) create mode 100644 zion/object/pci_port.cpp create mode 100644 zion/object/pci_port.h create mode 100644 zion/syscall/pci.cpp create mode 100644 zion/syscall/pci.h diff --git a/rust/lib/mammoth/build.rs b/rust/lib/mammoth/build.rs index 6797dfb..a5c5067 100644 --- a/rust/lib/mammoth/build.rs +++ b/rust/lib/mammoth/build.rs @@ -15,4 +15,11 @@ fn main() { curr_directory.to_str().unwrap() ); println!("cargo:rustc-link-lib=zion_stub"); + + // Trying to recreate bindings? + // Run the following commands + // gcc -E zion/include/zcall.h > /tmp/expanded.h + // bindgen --verbose --use-core --no-layout-tests /tmp/expanded.h -o rust/lib/mammoth/src/bindings.rs -- -x c++ + // + // Then go fix the ThreadExit struct. } diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index c26dba3..1db1f3a 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -1,153 +1,5 @@ /* automatically generated by rust-bindgen 0.69.4 */ -pub const _STDINT_H: u32 = 1; -pub const _FEATURES_H: u32 = 1; -pub const _ISOC95_SOURCE: u32 = 1; -pub const _ISOC99_SOURCE: u32 = 1; -pub const _ISOC11_SOURCE: u32 = 1; -pub const _ISOC2X_SOURCE: u32 = 1; -pub const _POSIX_SOURCE: u32 = 1; -pub const _POSIX_C_SOURCE: u32 = 200809; -pub const _XOPEN_SOURCE: u32 = 700; -pub const _XOPEN_SOURCE_EXTENDED: u32 = 1; -pub const _LARGEFILE64_SOURCE: u32 = 1; -pub const _DEFAULT_SOURCE: u32 = 1; -pub const _ATFILE_SOURCE: u32 = 1; -pub const _DYNAMIC_STACK_SIZE_SOURCE: u32 = 1; -pub const __GLIBC_USE_ISOC2X: u32 = 1; -pub const __USE_ISOC11: u32 = 1; -pub const __USE_ISOC99: u32 = 1; -pub const __USE_ISOC95: u32 = 1; -pub const __USE_ISOCXX11: u32 = 1; -pub const __USE_POSIX: u32 = 1; -pub const __USE_POSIX2: u32 = 1; -pub const __USE_POSIX199309: u32 = 1; -pub const __USE_POSIX199506: u32 = 1; -pub const __USE_XOPEN2K: u32 = 1; -pub const __USE_XOPEN2K8: u32 = 1; -pub const __USE_XOPEN: u32 = 1; -pub const __USE_XOPEN_EXTENDED: u32 = 1; -pub const __USE_UNIX98: u32 = 1; -pub const _LARGEFILE_SOURCE: u32 = 1; -pub const __USE_XOPEN2K8XSI: u32 = 1; -pub const __USE_XOPEN2KXSI: u32 = 1; -pub const __USE_LARGEFILE: u32 = 1; -pub const __USE_LARGEFILE64: u32 = 1; -pub const __WORDSIZE: u32 = 64; -pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; -pub const __SYSCALL_WORDSIZE: u32 = 64; -pub const __TIMESIZE: u32 = 64; -pub const __USE_MISC: u32 = 1; -pub const __USE_ATFILE: u32 = 1; -pub const __USE_DYNAMIC_STACK_SIZE: u32 = 1; -pub const __USE_GNU: u32 = 1; -pub const __USE_FORTIFY_LEVEL: u32 = 0; -pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; -pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; -pub const __GLIBC_USE_C2X_STRTOL: u32 = 1; -pub const _STDC_PREDEF_H: u32 = 1; -pub const __STDC_IEC_559__: u32 = 1; -pub const __STDC_IEC_60559_BFP__: u32 = 201404; -pub const __STDC_IEC_559_COMPLEX__: u32 = 1; -pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; -pub const __STDC_ISO_10646__: u32 = 201706; -pub const __GNU_LIBRARY__: u32 = 6; -pub const __GLIBC__: u32 = 2; -pub const __GLIBC_MINOR__: u32 = 39; -pub const _SYS_CDEFS_H: u32 = 1; -pub const __glibc_c99_flexarr_available: u32 = 1; -pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; -pub const __HAVE_GENERIC_SELECTION: u32 = 0; -pub const __GLIBC_USE_LIB_EXT2: u32 = 1; -pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 1; -pub const __GLIBC_USE_IEC_60559_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 1; -pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 1; -pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 1; -pub const _BITS_TYPES_H: u32 = 1; -pub const _BITS_TYPESIZES_H: u32 = 1; -pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; -pub const __INO_T_MATCHES_INO64_T: u32 = 1; -pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; -pub const __STATFS_MATCHES_STATFS64: u32 = 1; -pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; -pub const __FD_SETSIZE: u32 = 1024; -pub const _BITS_TIME64_H: u32 = 1; -pub const _BITS_WCHAR_H: u32 = 1; -pub const _BITS_STDINT_INTN_H: u32 = 1; -pub const _BITS_STDINT_UINTN_H: u32 = 1; -pub const _BITS_STDINT_LEAST_H: u32 = 1; -pub const INT8_MIN: i32 = -128; -pub const INT16_MIN: i32 = -32768; -pub const INT32_MIN: i32 = -2147483648; -pub const INT8_MAX: u32 = 127; -pub const INT16_MAX: u32 = 32767; -pub const INT32_MAX: u32 = 2147483647; -pub const UINT8_MAX: u32 = 255; -pub const UINT16_MAX: u32 = 65535; -pub const UINT32_MAX: u32 = 4294967295; -pub const INT_LEAST8_MIN: i32 = -128; -pub const INT_LEAST16_MIN: i32 = -32768; -pub const INT_LEAST32_MIN: i32 = -2147483648; -pub const INT_LEAST8_MAX: u32 = 127; -pub const INT_LEAST16_MAX: u32 = 32767; -pub const INT_LEAST32_MAX: u32 = 2147483647; -pub const UINT_LEAST8_MAX: u32 = 255; -pub const UINT_LEAST16_MAX: u32 = 65535; -pub const UINT_LEAST32_MAX: u32 = 4294967295; -pub const INT_FAST8_MIN: i32 = -128; -pub const INT_FAST16_MIN: i64 = -9223372036854775808; -pub const INT_FAST32_MIN: i64 = -9223372036854775808; -pub const INT_FAST8_MAX: u32 = 127; -pub const INT_FAST16_MAX: u64 = 9223372036854775807; -pub const INT_FAST32_MAX: u64 = 9223372036854775807; -pub const UINT_FAST8_MAX: u32 = 255; -pub const UINT_FAST16_MAX: i32 = -1; -pub const UINT_FAST32_MAX: i32 = -1; -pub const INTPTR_MIN: i64 = -9223372036854775808; -pub const INTPTR_MAX: u64 = 9223372036854775807; -pub const UINTPTR_MAX: i32 = -1; -pub const PTRDIFF_MIN: i64 = -9223372036854775808; -pub const PTRDIFF_MAX: u64 = 9223372036854775807; -pub const SIG_ATOMIC_MIN: i32 = -2147483648; -pub const SIG_ATOMIC_MAX: u32 = 2147483647; -pub const SIZE_MAX: i32 = -1; -pub const WINT_MIN: u32 = 0; -pub const WINT_MAX: u32 = 4294967295; -pub const INT8_WIDTH: u32 = 8; -pub const UINT8_WIDTH: u32 = 8; -pub const INT16_WIDTH: u32 = 16; -pub const UINT16_WIDTH: u32 = 16; -pub const INT32_WIDTH: u32 = 32; -pub const UINT32_WIDTH: u32 = 32; -pub const INT64_WIDTH: u32 = 64; -pub const UINT64_WIDTH: u32 = 64; -pub const INT_LEAST8_WIDTH: u32 = 8; -pub const UINT_LEAST8_WIDTH: u32 = 8; -pub const INT_LEAST16_WIDTH: u32 = 16; -pub const UINT_LEAST16_WIDTH: u32 = 16; -pub const INT_LEAST32_WIDTH: u32 = 32; -pub const UINT_LEAST32_WIDTH: u32 = 32; -pub const INT_LEAST64_WIDTH: u32 = 64; -pub const UINT_LEAST64_WIDTH: u32 = 64; -pub const INT_FAST8_WIDTH: u32 = 8; -pub const UINT_FAST8_WIDTH: u32 = 8; -pub const INT_FAST16_WIDTH: u32 = 64; -pub const UINT_FAST16_WIDTH: u32 = 64; -pub const INT_FAST32_WIDTH: u32 = 64; -pub const UINT_FAST32_WIDTH: u32 = 64; -pub const INT_FAST64_WIDTH: u32 = 64; -pub const UINT_FAST64_WIDTH: u32 = 64; -pub const INTPTR_WIDTH: u32 = 64; -pub const UINTPTR_WIDTH: u32 = 64; -pub const INTMAX_WIDTH: u32 = 64; -pub const UINTMAX_WIDTH: u32 = 64; -pub const PTRDIFF_WIDTH: u32 = 64; -pub const SIG_ATOMIC_WIDTH: u32 = 32; -pub const SIZE_WIDTH: u32 = 64; -pub const WCHAR_WIDTH: u32 = 32; -pub const WINT_WIDTH: u32 = 32; pub type __u_char = ::core::ffi::c_uchar; pub type __u_short = ::core::ffi::c_ushort; pub type __u_int = ::core::ffi::c_uint; @@ -257,7 +109,6 @@ pub const kZionPortCreate: u64 = 80; pub const kZionPortSend: u64 = 81; pub const kZionPortRecv: u64 = 82; pub const kZionPortPoll: u64 = 83; -pub const kZionIrqRegister: u64 = 88; pub const kZionMsiIrqRegister: u64 = 89; pub const kZionEndpointCreate: u64 = 96; pub const kZionEndpointSend: u64 = 97; @@ -274,6 +125,10 @@ pub const kZionSemaphoreCreate: u64 = 131; pub const kZionSemaphoreWait: u64 = 132; pub const kZionSemaphoreSignal: u64 = 133; pub const kZionDebug: u64 = 65536; +pub const kZionPciRead: u64 = 69632; +pub const kZionPciCreateBound: u64 = 69633; +pub const kZionPciReadBound: u64 = 69634; +pub const kZionPciWriteBound: u64 = 69635; pub const kZIrqKbd: u64 = 34; pub const kZIrqPci1: u64 = 48; pub const kZIrqPci2: u64 = 49; @@ -351,10 +206,6 @@ pub struct ZThreadStartReq { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadExitReq {} -extern "C" { - #[link_name = "\u{1}_Z11ZThreadExitv"] - pub fn ZThreadExit() -> z_err_t; -} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadWaitReq { @@ -473,12 +324,6 @@ pub struct ZPortPollReq { } #[repr(C)] #[derive(Debug, Copy, Clone)] -pub struct ZIrqRegisterReq { - pub irq_num: u64, - pub port_cap: *mut z_cap_t, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct ZMsiIrqRegisterReq { pub irq_num: *mut u64, pub port_cap: *mut z_cap_t, @@ -574,3 +419,36 @@ pub struct ZDebugReq { pub message: *const ::core::ffi::c_char, pub size: u64, } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciReadReq { + pub pci_cap: z_cap_t, + pub bus: u8, + pub slot: u8, + pub func: u8, + pub offset: u8, + pub output: *mut u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciCreateBoundReq { + pub pci_cap: z_cap_t, + pub bus: u8, + pub slot: u8, + pub func: u8, + pub new_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciReadBoundReq { + pub pci_cap: z_cap_t, + pub offset: u8, + pub data: *mut u32, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct ZPciWriteBoundReq { + pub pci_cap: z_cap_t, + pub offset: u8, + pub data: u32, +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 2691458..21833f2 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -472,3 +472,25 @@ pub fn semaphone_wait(sem_cap: &Capability) -> Result<(), ZError> { }, ) } + +pub fn pci_read( + pci_cap: &Capability, + bus: u8, + slot: u8, + func: u8, + offset: u8, +) -> Result { + let mut data: u32 = 0; + syscall( + zion::kZionPciRead, + &zion::ZPciReadReq { + pci_cap: pci_cap.raw(), + bus, + slot, + func, + offset, + output: &mut data as *mut u32, + }, + )?; + Ok(data) +} diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index dbe8c2e..fa3dda1 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -36,13 +36,14 @@ fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZErr #[no_mangle] extern "C" fn main() -> z_err_t { - let pci_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_PCI_VMMO })) - .expect("Failed to create PCI region"); let fb_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_FRAMEBUFFER_INFO_VMMO })) .expect("Failed to create Framebuffer region"); let context = Arc::new( - server::YellowstoneServerContext::new(pci_region, fb_region) - .expect("Failed to create yellowstone context"), + server::YellowstoneServerContext::new( + Capability::take(unsafe { BOOT_PCI_VMMO }), + fb_region, + ) + .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs index e421f74..1520b2e 100644 --- a/rust/sys/yellowstone/src/pci.rs +++ b/rust/sys/yellowstone/src/pci.rs @@ -1,14 +1,29 @@ -use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; +use mammoth::{ + cap::Capability, + mem::MemoryRegion, + syscall, + zion::{kZionPerm_All, ZError}, +}; + +enum PciType { + Port(Capability), + Memory(MemoryRegion), +} pub struct PciReader { - memory_region: MemoryRegion, + internal_type: PciType, } type DevPredicate = fn(u8, u8, u8) -> bool; impl PciReader { - pub fn new(memory_region: MemoryRegion) -> Self { - Self { memory_region } + pub fn new(capability: Capability) -> Self { + let internal_type = + match MemoryRegion::from_cap(capability.duplicate(kZionPerm_All).unwrap()) { + Ok(mem) => PciType::Memory(mem), + Err(_) => PciType::Port(capability), + }; + Self { internal_type } } pub fn get_ahci_region(&self) -> Result { @@ -28,15 +43,13 @@ impl PciReader { } fn probe_pci(&self, pred: DevPredicate) -> Option { - let base_header = self.pci_header(0, 0, 0); - if (base_header.header_type & 0x80) == 0 { + if (self.header_type(0, 0, 0) & 0x80) == 0 { if let Some(dev) = self.probe_bus(pred, 0) { return Some(dev); } } else { for fun in 0..8 { - let fun_hdr = self.pci_header(0, 0, fun); - if fun_hdr.vendor_id != 0xFFFF { + if self.vendor_id(0, 0, fun) != 0xFFFF { if let Some(dev) = self.probe_bus(pred, fun) { return Some(dev); } @@ -56,8 +69,7 @@ impl PciReader { } fn probe_device(&self, pred: DevPredicate, bus: u8, dev: u8) -> Option { - let device_base_header = self.pci_header(bus, dev, 0); - if device_base_header.vendor_id == 0xFFFF { + if self.vendor_id(bus, dev, 0) == 0xFFFF { return None; } @@ -65,7 +77,7 @@ impl PciReader { return Some(dev); } - if (device_base_header.header_type & 0x80) != 0 { + if (self.header_type(bus, dev, 0) & 0x80) != 0 { for fun in 1..8 { if let Some(dev) = self.probe_function(pred, bus, dev, fun) { return Some(dev); @@ -76,37 +88,66 @@ impl PciReader { } fn probe_function(&self, pred: DevPredicate, bus: u8, dev: u8, fun: u8) -> Option { - let function_header = self.pci_header(bus, dev, fun); + let (class, subclass, prog_interface) = self.class_codes(bus, dev, fun); mammoth::debug!( "PCI Function: {:#x} {:#x} {:#x}", - function_header.class_code, - function_header.subclass, - function_header.prog_interface + class, + subclass, + prog_interface ); - if pred( - function_header.class_code, - function_header.subclass, - function_header.prog_interface, - ) { + if pred(class, subclass, prog_interface) { mammoth::debug!("Found!"); - let offset = pci_header_offset(bus, dev, fun); - Some( - self.memory_region - .duplicate(offset as u64, 0x1000) - .expect("Failed to duplicate PCI cap"), - ) + Some(self.create_cap(bus, dev, fun)) } else { None } } - fn pci_header(&self, bus: u8, dev: u8, fun: u8) -> &PciHeader { - let offset = pci_header_offset(bus, dev, fun); - let header_slice: &[u8] = - &self.memory_region.slice()[offset..offset + size_of::()]; - unsafe { header_slice.as_ptr().cast::().as_ref().unwrap() } + fn header_type(&self, bus: u8, dev: u8, fun: u8) -> u8 { + let data = self.read_at(bus, dev, fun, 0xC); + + ((data >> 16) & 0xFF) as u8 + } + + fn vendor_id(&self, bus: u8, dev: u8, fun: u8) -> u16 { + let data = self.read_at(bus, dev, fun, 0); + + (data & 0xFFFF) as u16 + } + + fn class_codes(&self, bus: u8, dev: u8, fun: u8) -> (u8, u8, u8) { + let data = self.read_at(bus, dev, fun, 0x8); + + let class = (data >> 24) as u8; + let subclass = ((data >> 16) & 0xFF) as u8; + let prog_if = ((data >> 8) & 0xFF) as u8; + + (class, subclass, prog_if) + } + + fn read_at(&self, bus: u8, dev: u8, fun: u8, off: u8) -> u32 { + match &self.internal_type { + PciType::Memory(region) => { + let offset = pci_header_offset(bus, dev, fun); + let header_slice: &[u32] = ®ion.slice()[offset..offset + size_of::()]; + header_slice[(off >> 2) as usize] + } + PciType::Port(pci_cap) => syscall::pci_read(pci_cap, bus, dev, fun, off).unwrap(), + } + } + + fn create_cap(&self, bus: u8, dev: u8, fun: u8) -> Capability { + match &self.internal_type { + PciType::Memory(region) => { + let offset = pci_header_offset(bus, dev, fun); + region + .duplicate(offset as u64, 0x1000) + .expect("Failed to duplicate PCI cap") + } + PciType::Port(_pci_cap) => todo!(), + } } } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 8cc4a4b..d2f1327 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -43,13 +43,11 @@ impl YellowstoneServerContext { green_mask_shift: fb_info.green_mask_shift as u64, } } -} -impl YellowstoneServerContext { - pub fn new(pci_region: MemoryRegion, fb_region: MemoryRegion) -> Result { + pub fn new(pci_cap: Capability, fb_region: MemoryRegion) -> Result { Ok(Self { registration_semaphore: mammoth::sync::Semaphore::new()?, - pci_reader: PciReader::new(pci_region), + pci_reader: PciReader::new(pci_cap), framebuffer_info_region: fb_region, service_map: Mutex::new(BTreeMap::new()), }) diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 598a3de..a485758 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -30,6 +30,7 @@ add_executable(zion object/ipc_object.cpp object/memory_object.cpp object/mutex.cpp + object/pci_port.cpp object/port.cpp object/process.cpp object/reply_port.cpp @@ -45,6 +46,7 @@ add_executable(zion syscall/debug.cpp syscall/ipc.cpp syscall/memory_object.cpp + syscall/pci.cpp syscall/process.cpp syscall/synchronization.cpp syscall/syscall.cpp diff --git a/zion/common/port.h b/zion/common/port.h index 4919ff4..c3cfaea 100644 --- a/zion/common/port.h +++ b/zion/common/port.h @@ -11,3 +11,13 @@ static inline uint8_t inb(uint16_t port) { static inline void outb(uint16_t port, uint8_t value) { asm volatile("outb %0, %1" ::"a"(value), "Nd"(port)); } + +static inline uint32_t inl(uint16_t port) { + uint32_t result; + asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); + return result; +} + +static inline void outl(uint16_t port, uint32_t value) { + asm volatile("outl %0, %1" ::"a"(value), "Nd"(port)); +} diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 6092037..26b69dd 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -71,3 +71,14 @@ SYS1(SemaphoreWait, z_cap_t, semaphore_cap); SYS1(SemaphoreSignal, z_cap_t, semaphore_cap); SYS2(Debug, const char*, message, uint64_t, size); + +// TODO: These should be handled with a more generic user-space interface. +// To be honest we could just have an inl and outl interface that is provided to +// yellowstone and the extra ipc load would be a good stress test of our +// performance +SYS6(PciRead, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, func, + uint8_t, offset, uint32_t*, output); +SYS5(PciCreateBound, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, + func, z_cap_t*, new_cap); +SYS3(PciReadBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t*, data); +SYS3(PciWriteBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t, data); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index b60db9c..046966e 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -67,6 +67,11 @@ const uint64_t kZionSemaphoreSignal = 0x85; // Debugging Calls. const uint64_t kZionDebug = 0x1'0000; +const uint64_t kZionPciRead = 0x1'1000; +const uint64_t kZionPciCreateBound = 0x1'1001; +const uint64_t kZionPciReadBound = 0x1'1002; +const uint64_t kZionPciWriteBound = 0x1'1003; + // Irq Types const uint64_t kZIrqKbd = 0x22; const uint64_t kZIrqPci1 = 0x30; diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index b05c70a..8926880 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -8,6 +8,7 @@ #include "debug/debug.h" #include "include/zcall.h" #include "memory/paging_util.h" +#include "object/pci_port.h" #include "object/process.h" #include "object/thread.h" #include "scheduler/process_manager.h" @@ -187,7 +188,9 @@ void LoadInitProgram() { WriteFramebufferVmmo(port); if (WritePciVmmo(port, Z_BOOT_PCI_VMMO) != glcr::OK) { - panic("Failed to provide PCI info to init."); + dbgln("Failed to find PCIe space, creating PCI IO Port Cap"); + auto pci_port = PciPort::Create(); + port->WriteKernel(Z_BOOT_PCI_VMMO, MakeRefCounted(pci_port)); } // Start process. diff --git a/zion/object/kernel_object.h b/zion/object/kernel_object.h index 2bdd477..ced8ba9 100644 --- a/zion/object/kernel_object.h +++ b/zion/object/kernel_object.h @@ -16,6 +16,10 @@ class KernelObject : public glcr::RefCounted { REPLY_PORT = 0x8, MUTEX = 0x9, SEMAPHORE = 0x10, + + // Temporary. + PCI_CAP = 0x100, + PCI_BOUND_CAP = 0x101, }; virtual uint64_t TypeTag() = 0; diff --git a/zion/object/pci_port.cpp b/zion/object/pci_port.cpp new file mode 100644 index 0000000..1daef76 --- /dev/null +++ b/zion/object/pci_port.cpp @@ -0,0 +1,46 @@ +#include "object/pci_port.h" + +#include "common/port.h" + +namespace { + +const uint16_t PCI_ADDR_PORT = 0xCF8; +const uint16_t PCI_DATA_PORT = 0xCFC; + +uint32_t AddressOf(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { + uint32_t lbus = (uint32_t)bus; + uint32_t lslot = (uint32_t)slot; + uint32_t lfunc = (uint32_t)func; + + return (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | + (offset & 0xFC) | ((uint32_t)0x80000000)); +} + +uint32_t PciReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset) { + uint32_t address = AddressOf(bus, slot, func, offset); + outl(PCI_ADDR_PORT, address); + return inl(PCI_DATA_PORT); +} + +void PciWriteAtOffset(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, + uint32_t word) { + uint32_t address = AddressOf(bus, slot, func, offset); + outl(PCI_ADDR_PORT, address); + outl(PCI_DATA_PORT, word); +} + +} // namespace + +uint32_t PciPort::ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset) { + return PciReadAtOffset(bus, slot, func, offset); +} + +uint32_t PciPortBound::Read(uint8_t offset) { + return PciReadAtOffset(bus_, slot_, func_, offset); +} + +void PciPortBound::Write(uint8_t offset, uint32_t data) { + PciWriteAtOffset(bus_, slot_, func_, offset, data); +} diff --git a/zion/object/pci_port.h b/zion/object/pci_port.h new file mode 100644 index 0000000..6287f31 --- /dev/null +++ b/zion/object/pci_port.h @@ -0,0 +1,60 @@ +#include + +#include "include/ztypes.h" +#include "object/kernel_object.h" + +class PciPort; +class PciPortBound; + +template <> +struct KernelObjectTag { + static const uint64_t type = KernelObject::PCI_CAP; +}; + +class PciPort : public KernelObject { + public: + static uint64_t DefaultPermissions() { + return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate | + kZionPerm_Transmit; + } + + uint64_t TypeTag() override { return KernelObject::PCI_CAP; } + + static glcr::RefPtr Create() { return glcr::AdoptPtr(new PciPort); } + + uint32_t ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, + uint8_t offset); + + private: + PciPort() {} +}; + +template <> +struct KernelObjectTag { + static const uint64_t type = KernelObject::PCI_BOUND_CAP; +}; + +class PciPortBound : public KernelObject { + public: + static uint64_t DefaultPermissions() { + return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate; + } + + uint64_t TypeTag() override { return KernelObject::PCI_BOUND_CAP; } + + static glcr::RefPtr Create(uint8_t bus, uint8_t slot, + uint8_t func) { + return glcr::AdoptPtr(new PciPortBound(bus, slot, func)); + } + + uint32_t Read(uint8_t offset); + void Write(uint8_t offset, uint32_t data); + + private: + PciPortBound(uint8_t bus, uint8_t slot, uint8_t func) + : bus_(bus), slot_(slot), func_(func) {} + + uint8_t bus_; + uint8_t slot_; + uint8_t func_; +}; diff --git a/zion/syscall/pci.cpp b/zion/syscall/pci.cpp new file mode 100644 index 0000000..1a1c7bc --- /dev/null +++ b/zion/syscall/pci.cpp @@ -0,0 +1,44 @@ +#include "syscall/pci.h" + +#include "object/pci_port.h" +#include "scheduler/scheduler.h" + +z_err_t PciRead(ZPciReadReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); + + *req->output = pci_cap->obj()->ReadAtOffset(req->bus, req->slot, + req->func, req->offset); + + return glcr::OK; +} + +z_err_t PciCreateBound(ZPciCreateBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Duplicate)); + + *req->new_cap = curr_proc.AddNewCapability( + PciPortBound::Create(req->bus, req->slot, req->func)); + return glcr::OK; +} + +z_err_t PciReadBound(ZPciReadBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); + + *req->data = pci_cap->obj()->Read(req->offset); + + return glcr::OK; +} +z_err_t PciWriteBound(ZPciWriteBoundReq* req) { + auto& curr_proc = gScheduler->CurrentProcess(); + auto pci_cap = curr_proc.GetCapability(req->pci_cap); + RET_ERR(ValidateCapability(pci_cap, kZionPerm_Write)); + + pci_cap->obj()->Write(req->offset, req->data); + + return glcr::OK; +} diff --git a/zion/syscall/pci.h b/zion/syscall/pci.h new file mode 100644 index 0000000..f31680b --- /dev/null +++ b/zion/syscall/pci.h @@ -0,0 +1,6 @@ +#include "include/zcall.h" + +z_err_t PciRead(ZPciReadReq* req); +z_err_t PciCreateBound(ZPciCreateBoundReq* req); +z_err_t PciReadBound(ZPciReadBoundReq* req); +z_err_t PciWriteBound(ZPciWriteBoundReq* req); From b51d5966d413216ab695fd07324f0c9cd4a363b9 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Wed, 7 May 2025 01:45:46 -0700 Subject: [PATCH 182/186] [Zion] Zero-out thread fx_data_ on creation. --- zion/object/thread.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/zion/object/thread.cpp b/zion/object/thread.cpp index a1a1d47..fea38f9 100644 --- a/zion/object/thread.cpp +++ b/zion/object/thread.cpp @@ -51,6 +51,9 @@ Thread::Thread(Process& proc, uint64_t tid) if (reinterpret_cast(fx_data_) & 0x8) { fx_data_ += 8; } + for (uint16_t i = 0; i < 512; i++) { + fx_data_[i] = 0; + } } uint64_t Thread::pid() const { return process_.id(); } From bddf26b6454051b85c6e9f5fd58da0d4c444b4ff Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 8 May 2025 00:33:58 -0700 Subject: [PATCH 183/186] Revert "[Zion][Yellowstone] First pass at adding PCI ioport access." This reverts commit b67763324850ecdbb2873325c463f2c2e24506e4. --- rust/lib/mammoth/build.rs | 7 -- rust/lib/mammoth/src/bindings.rs | 196 +++++++++++++++++++++++------ rust/lib/mammoth/src/syscall.rs | 22 ---- rust/sys/yellowstone/src/main.rs | 9 +- rust/sys/yellowstone/src/pci.rs | 103 +++++---------- rust/sys/yellowstone/src/server.rs | 6 +- zion/CMakeLists.txt | 2 - zion/common/port.h | 10 -- zion/include/zcall.h | 11 -- zion/include/ztypes.h | 5 - zion/loader/init_loader.cpp | 5 +- zion/object/kernel_object.h | 4 - zion/object/pci_port.cpp | 46 ------- zion/object/pci_port.h | 60 --------- zion/syscall/pci.cpp | 44 ------- zion/syscall/pci.h | 6 - 16 files changed, 199 insertions(+), 337 deletions(-) delete mode 100644 zion/object/pci_port.cpp delete mode 100644 zion/object/pci_port.h delete mode 100644 zion/syscall/pci.cpp delete mode 100644 zion/syscall/pci.h diff --git a/rust/lib/mammoth/build.rs b/rust/lib/mammoth/build.rs index a5c5067..6797dfb 100644 --- a/rust/lib/mammoth/build.rs +++ b/rust/lib/mammoth/build.rs @@ -15,11 +15,4 @@ fn main() { curr_directory.to_str().unwrap() ); println!("cargo:rustc-link-lib=zion_stub"); - - // Trying to recreate bindings? - // Run the following commands - // gcc -E zion/include/zcall.h > /tmp/expanded.h - // bindgen --verbose --use-core --no-layout-tests /tmp/expanded.h -o rust/lib/mammoth/src/bindings.rs -- -x c++ - // - // Then go fix the ThreadExit struct. } diff --git a/rust/lib/mammoth/src/bindings.rs b/rust/lib/mammoth/src/bindings.rs index 1db1f3a..c26dba3 100644 --- a/rust/lib/mammoth/src/bindings.rs +++ b/rust/lib/mammoth/src/bindings.rs @@ -1,5 +1,153 @@ /* automatically generated by rust-bindgen 0.69.4 */ +pub const _STDINT_H: u32 = 1; +pub const _FEATURES_H: u32 = 1; +pub const _ISOC95_SOURCE: u32 = 1; +pub const _ISOC99_SOURCE: u32 = 1; +pub const _ISOC11_SOURCE: u32 = 1; +pub const _ISOC2X_SOURCE: u32 = 1; +pub const _POSIX_SOURCE: u32 = 1; +pub const _POSIX_C_SOURCE: u32 = 200809; +pub const _XOPEN_SOURCE: u32 = 700; +pub const _XOPEN_SOURCE_EXTENDED: u32 = 1; +pub const _LARGEFILE64_SOURCE: u32 = 1; +pub const _DEFAULT_SOURCE: u32 = 1; +pub const _ATFILE_SOURCE: u32 = 1; +pub const _DYNAMIC_STACK_SIZE_SOURCE: u32 = 1; +pub const __GLIBC_USE_ISOC2X: u32 = 1; +pub const __USE_ISOC11: u32 = 1; +pub const __USE_ISOC99: u32 = 1; +pub const __USE_ISOC95: u32 = 1; +pub const __USE_ISOCXX11: u32 = 1; +pub const __USE_POSIX: u32 = 1; +pub const __USE_POSIX2: u32 = 1; +pub const __USE_POSIX199309: u32 = 1; +pub const __USE_POSIX199506: u32 = 1; +pub const __USE_XOPEN2K: u32 = 1; +pub const __USE_XOPEN2K8: u32 = 1; +pub const __USE_XOPEN: u32 = 1; +pub const __USE_XOPEN_EXTENDED: u32 = 1; +pub const __USE_UNIX98: u32 = 1; +pub const _LARGEFILE_SOURCE: u32 = 1; +pub const __USE_XOPEN2K8XSI: u32 = 1; +pub const __USE_XOPEN2KXSI: u32 = 1; +pub const __USE_LARGEFILE: u32 = 1; +pub const __USE_LARGEFILE64: u32 = 1; +pub const __WORDSIZE: u32 = 64; +pub const __WORDSIZE_TIME64_COMPAT32: u32 = 1; +pub const __SYSCALL_WORDSIZE: u32 = 64; +pub const __TIMESIZE: u32 = 64; +pub const __USE_MISC: u32 = 1; +pub const __USE_ATFILE: u32 = 1; +pub const __USE_DYNAMIC_STACK_SIZE: u32 = 1; +pub const __USE_GNU: u32 = 1; +pub const __USE_FORTIFY_LEVEL: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_GETS: u32 = 0; +pub const __GLIBC_USE_DEPRECATED_SCANF: u32 = 0; +pub const __GLIBC_USE_C2X_STRTOL: u32 = 1; +pub const _STDC_PREDEF_H: u32 = 1; +pub const __STDC_IEC_559__: u32 = 1; +pub const __STDC_IEC_60559_BFP__: u32 = 201404; +pub const __STDC_IEC_559_COMPLEX__: u32 = 1; +pub const __STDC_IEC_60559_COMPLEX__: u32 = 201404; +pub const __STDC_ISO_10646__: u32 = 201706; +pub const __GNU_LIBRARY__: u32 = 6; +pub const __GLIBC__: u32 = 2; +pub const __GLIBC_MINOR__: u32 = 39; +pub const _SYS_CDEFS_H: u32 = 1; +pub const __glibc_c99_flexarr_available: u32 = 1; +pub const __LDOUBLE_REDIRECTS_TO_FLOAT128_ABI: u32 = 0; +pub const __HAVE_GENERIC_SELECTION: u32 = 0; +pub const __GLIBC_USE_LIB_EXT2: u32 = 1; +pub const __GLIBC_USE_IEC_60559_BFP_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_BFP_EXT_C2X: u32 = 1; +pub const __GLIBC_USE_IEC_60559_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT: u32 = 1; +pub const __GLIBC_USE_IEC_60559_FUNCS_EXT_C2X: u32 = 1; +pub const __GLIBC_USE_IEC_60559_TYPES_EXT: u32 = 1; +pub const _BITS_TYPES_H: u32 = 1; +pub const _BITS_TYPESIZES_H: u32 = 1; +pub const __OFF_T_MATCHES_OFF64_T: u32 = 1; +pub const __INO_T_MATCHES_INO64_T: u32 = 1; +pub const __RLIM_T_MATCHES_RLIM64_T: u32 = 1; +pub const __STATFS_MATCHES_STATFS64: u32 = 1; +pub const __KERNEL_OLD_TIMEVAL_MATCHES_TIMEVAL64: u32 = 1; +pub const __FD_SETSIZE: u32 = 1024; +pub const _BITS_TIME64_H: u32 = 1; +pub const _BITS_WCHAR_H: u32 = 1; +pub const _BITS_STDINT_INTN_H: u32 = 1; +pub const _BITS_STDINT_UINTN_H: u32 = 1; +pub const _BITS_STDINT_LEAST_H: u32 = 1; +pub const INT8_MIN: i32 = -128; +pub const INT16_MIN: i32 = -32768; +pub const INT32_MIN: i32 = -2147483648; +pub const INT8_MAX: u32 = 127; +pub const INT16_MAX: u32 = 32767; +pub const INT32_MAX: u32 = 2147483647; +pub const UINT8_MAX: u32 = 255; +pub const UINT16_MAX: u32 = 65535; +pub const UINT32_MAX: u32 = 4294967295; +pub const INT_LEAST8_MIN: i32 = -128; +pub const INT_LEAST16_MIN: i32 = -32768; +pub const INT_LEAST32_MIN: i32 = -2147483648; +pub const INT_LEAST8_MAX: u32 = 127; +pub const INT_LEAST16_MAX: u32 = 32767; +pub const INT_LEAST32_MAX: u32 = 2147483647; +pub const UINT_LEAST8_MAX: u32 = 255; +pub const UINT_LEAST16_MAX: u32 = 65535; +pub const UINT_LEAST32_MAX: u32 = 4294967295; +pub const INT_FAST8_MIN: i32 = -128; +pub const INT_FAST16_MIN: i64 = -9223372036854775808; +pub const INT_FAST32_MIN: i64 = -9223372036854775808; +pub const INT_FAST8_MAX: u32 = 127; +pub const INT_FAST16_MAX: u64 = 9223372036854775807; +pub const INT_FAST32_MAX: u64 = 9223372036854775807; +pub const UINT_FAST8_MAX: u32 = 255; +pub const UINT_FAST16_MAX: i32 = -1; +pub const UINT_FAST32_MAX: i32 = -1; +pub const INTPTR_MIN: i64 = -9223372036854775808; +pub const INTPTR_MAX: u64 = 9223372036854775807; +pub const UINTPTR_MAX: i32 = -1; +pub const PTRDIFF_MIN: i64 = -9223372036854775808; +pub const PTRDIFF_MAX: u64 = 9223372036854775807; +pub const SIG_ATOMIC_MIN: i32 = -2147483648; +pub const SIG_ATOMIC_MAX: u32 = 2147483647; +pub const SIZE_MAX: i32 = -1; +pub const WINT_MIN: u32 = 0; +pub const WINT_MAX: u32 = 4294967295; +pub const INT8_WIDTH: u32 = 8; +pub const UINT8_WIDTH: u32 = 8; +pub const INT16_WIDTH: u32 = 16; +pub const UINT16_WIDTH: u32 = 16; +pub const INT32_WIDTH: u32 = 32; +pub const UINT32_WIDTH: u32 = 32; +pub const INT64_WIDTH: u32 = 64; +pub const UINT64_WIDTH: u32 = 64; +pub const INT_LEAST8_WIDTH: u32 = 8; +pub const UINT_LEAST8_WIDTH: u32 = 8; +pub const INT_LEAST16_WIDTH: u32 = 16; +pub const UINT_LEAST16_WIDTH: u32 = 16; +pub const INT_LEAST32_WIDTH: u32 = 32; +pub const UINT_LEAST32_WIDTH: u32 = 32; +pub const INT_LEAST64_WIDTH: u32 = 64; +pub const UINT_LEAST64_WIDTH: u32 = 64; +pub const INT_FAST8_WIDTH: u32 = 8; +pub const UINT_FAST8_WIDTH: u32 = 8; +pub const INT_FAST16_WIDTH: u32 = 64; +pub const UINT_FAST16_WIDTH: u32 = 64; +pub const INT_FAST32_WIDTH: u32 = 64; +pub const UINT_FAST32_WIDTH: u32 = 64; +pub const INT_FAST64_WIDTH: u32 = 64; +pub const UINT_FAST64_WIDTH: u32 = 64; +pub const INTPTR_WIDTH: u32 = 64; +pub const UINTPTR_WIDTH: u32 = 64; +pub const INTMAX_WIDTH: u32 = 64; +pub const UINTMAX_WIDTH: u32 = 64; +pub const PTRDIFF_WIDTH: u32 = 64; +pub const SIG_ATOMIC_WIDTH: u32 = 32; +pub const SIZE_WIDTH: u32 = 64; +pub const WCHAR_WIDTH: u32 = 32; +pub const WINT_WIDTH: u32 = 32; pub type __u_char = ::core::ffi::c_uchar; pub type __u_short = ::core::ffi::c_ushort; pub type __u_int = ::core::ffi::c_uint; @@ -109,6 +257,7 @@ pub const kZionPortCreate: u64 = 80; pub const kZionPortSend: u64 = 81; pub const kZionPortRecv: u64 = 82; pub const kZionPortPoll: u64 = 83; +pub const kZionIrqRegister: u64 = 88; pub const kZionMsiIrqRegister: u64 = 89; pub const kZionEndpointCreate: u64 = 96; pub const kZionEndpointSend: u64 = 97; @@ -125,10 +274,6 @@ pub const kZionSemaphoreCreate: u64 = 131; pub const kZionSemaphoreWait: u64 = 132; pub const kZionSemaphoreSignal: u64 = 133; pub const kZionDebug: u64 = 65536; -pub const kZionPciRead: u64 = 69632; -pub const kZionPciCreateBound: u64 = 69633; -pub const kZionPciReadBound: u64 = 69634; -pub const kZionPciWriteBound: u64 = 69635; pub const kZIrqKbd: u64 = 34; pub const kZIrqPci1: u64 = 48; pub const kZIrqPci2: u64 = 49; @@ -206,6 +351,10 @@ pub struct ZThreadStartReq { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadExitReq {} +extern "C" { + #[link_name = "\u{1}_Z11ZThreadExitv"] + pub fn ZThreadExit() -> z_err_t; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct ZThreadWaitReq { @@ -324,6 +473,12 @@ pub struct ZPortPollReq { } #[repr(C)] #[derive(Debug, Copy, Clone)] +pub struct ZIrqRegisterReq { + pub irq_num: u64, + pub port_cap: *mut z_cap_t, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] pub struct ZMsiIrqRegisterReq { pub irq_num: *mut u64, pub port_cap: *mut z_cap_t, @@ -419,36 +574,3 @@ pub struct ZDebugReq { pub message: *const ::core::ffi::c_char, pub size: u64, } -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ZPciReadReq { - pub pci_cap: z_cap_t, - pub bus: u8, - pub slot: u8, - pub func: u8, - pub offset: u8, - pub output: *mut u32, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ZPciCreateBoundReq { - pub pci_cap: z_cap_t, - pub bus: u8, - pub slot: u8, - pub func: u8, - pub new_cap: *mut z_cap_t, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ZPciReadBoundReq { - pub pci_cap: z_cap_t, - pub offset: u8, - pub data: *mut u32, -} -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct ZPciWriteBoundReq { - pub pci_cap: z_cap_t, - pub offset: u8, - pub data: u32, -} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 21833f2..2691458 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -472,25 +472,3 @@ pub fn semaphone_wait(sem_cap: &Capability) -> Result<(), ZError> { }, ) } - -pub fn pci_read( - pci_cap: &Capability, - bus: u8, - slot: u8, - func: u8, - offset: u8, -) -> Result { - let mut data: u32 = 0; - syscall( - zion::kZionPciRead, - &zion::ZPciReadReq { - pci_cap: pci_cap.raw(), - bus, - slot, - func, - offset, - output: &mut data as *mut u32, - }, - )?; - Ok(data) -} diff --git a/rust/sys/yellowstone/src/main.rs b/rust/sys/yellowstone/src/main.rs index fa3dda1..dbe8c2e 100644 --- a/rust/sys/yellowstone/src/main.rs +++ b/rust/sys/yellowstone/src/main.rs @@ -36,14 +36,13 @@ fn spawn_from_vmmo(vmmo_cap: z_cap_t, server_cap: Capability) -> Result<(), ZErr #[no_mangle] extern "C" fn main() -> z_err_t { + let pci_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_PCI_VMMO })) + .expect("Failed to create PCI region"); let fb_region = MemoryRegion::from_cap(Capability::take(unsafe { BOOT_FRAMEBUFFER_INFO_VMMO })) .expect("Failed to create Framebuffer region"); let context = Arc::new( - server::YellowstoneServerContext::new( - Capability::take(unsafe { BOOT_PCI_VMMO }), - fb_region, - ) - .expect("Failed to create yellowstone context"), + server::YellowstoneServerContext::new(pci_region, fb_region) + .expect("Failed to create yellowstone context"), ); let handler = server::YellowstoneServerImpl::new(context.clone()); let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone server"); diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs index 1520b2e..e421f74 100644 --- a/rust/sys/yellowstone/src/pci.rs +++ b/rust/sys/yellowstone/src/pci.rs @@ -1,29 +1,14 @@ -use mammoth::{ - cap::Capability, - mem::MemoryRegion, - syscall, - zion::{kZionPerm_All, ZError}, -}; - -enum PciType { - Port(Capability), - Memory(MemoryRegion), -} +use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; pub struct PciReader { - internal_type: PciType, + memory_region: MemoryRegion, } type DevPredicate = fn(u8, u8, u8) -> bool; impl PciReader { - pub fn new(capability: Capability) -> Self { - let internal_type = - match MemoryRegion::from_cap(capability.duplicate(kZionPerm_All).unwrap()) { - Ok(mem) => PciType::Memory(mem), - Err(_) => PciType::Port(capability), - }; - Self { internal_type } + pub fn new(memory_region: MemoryRegion) -> Self { + Self { memory_region } } pub fn get_ahci_region(&self) -> Result { @@ -43,13 +28,15 @@ impl PciReader { } fn probe_pci(&self, pred: DevPredicate) -> Option { - if (self.header_type(0, 0, 0) & 0x80) == 0 { + let base_header = self.pci_header(0, 0, 0); + if (base_header.header_type & 0x80) == 0 { if let Some(dev) = self.probe_bus(pred, 0) { return Some(dev); } } else { for fun in 0..8 { - if self.vendor_id(0, 0, fun) != 0xFFFF { + let fun_hdr = self.pci_header(0, 0, fun); + if fun_hdr.vendor_id != 0xFFFF { if let Some(dev) = self.probe_bus(pred, fun) { return Some(dev); } @@ -69,7 +56,8 @@ impl PciReader { } fn probe_device(&self, pred: DevPredicate, bus: u8, dev: u8) -> Option { - if self.vendor_id(bus, dev, 0) == 0xFFFF { + let device_base_header = self.pci_header(bus, dev, 0); + if device_base_header.vendor_id == 0xFFFF { return None; } @@ -77,7 +65,7 @@ impl PciReader { return Some(dev); } - if (self.header_type(bus, dev, 0) & 0x80) != 0 { + if (device_base_header.header_type & 0x80) != 0 { for fun in 1..8 { if let Some(dev) = self.probe_function(pred, bus, dev, fun) { return Some(dev); @@ -88,66 +76,37 @@ impl PciReader { } fn probe_function(&self, pred: DevPredicate, bus: u8, dev: u8, fun: u8) -> Option { - let (class, subclass, prog_interface) = self.class_codes(bus, dev, fun); + let function_header = self.pci_header(bus, dev, fun); mammoth::debug!( "PCI Function: {:#x} {:#x} {:#x}", - class, - subclass, - prog_interface + function_header.class_code, + function_header.subclass, + function_header.prog_interface ); - if pred(class, subclass, prog_interface) { + if pred( + function_header.class_code, + function_header.subclass, + function_header.prog_interface, + ) { mammoth::debug!("Found!"); - Some(self.create_cap(bus, dev, fun)) + let offset = pci_header_offset(bus, dev, fun); + Some( + self.memory_region + .duplicate(offset as u64, 0x1000) + .expect("Failed to duplicate PCI cap"), + ) } else { None } } - fn header_type(&self, bus: u8, dev: u8, fun: u8) -> u8 { - let data = self.read_at(bus, dev, fun, 0xC); - - ((data >> 16) & 0xFF) as u8 - } - - fn vendor_id(&self, bus: u8, dev: u8, fun: u8) -> u16 { - let data = self.read_at(bus, dev, fun, 0); - - (data & 0xFFFF) as u16 - } - - fn class_codes(&self, bus: u8, dev: u8, fun: u8) -> (u8, u8, u8) { - let data = self.read_at(bus, dev, fun, 0x8); - - let class = (data >> 24) as u8; - let subclass = ((data >> 16) & 0xFF) as u8; - let prog_if = ((data >> 8) & 0xFF) as u8; - - (class, subclass, prog_if) - } - - fn read_at(&self, bus: u8, dev: u8, fun: u8, off: u8) -> u32 { - match &self.internal_type { - PciType::Memory(region) => { - let offset = pci_header_offset(bus, dev, fun); - let header_slice: &[u32] = ®ion.slice()[offset..offset + size_of::()]; - header_slice[(off >> 2) as usize] - } - PciType::Port(pci_cap) => syscall::pci_read(pci_cap, bus, dev, fun, off).unwrap(), - } - } - - fn create_cap(&self, bus: u8, dev: u8, fun: u8) -> Capability { - match &self.internal_type { - PciType::Memory(region) => { - let offset = pci_header_offset(bus, dev, fun); - region - .duplicate(offset as u64, 0x1000) - .expect("Failed to duplicate PCI cap") - } - PciType::Port(_pci_cap) => todo!(), - } + fn pci_header(&self, bus: u8, dev: u8, fun: u8) -> &PciHeader { + let offset = pci_header_offset(bus, dev, fun); + let header_slice: &[u8] = + &self.memory_region.slice()[offset..offset + size_of::()]; + unsafe { header_slice.as_ptr().cast::().as_ref().unwrap() } } } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index d2f1327..8cc4a4b 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -43,11 +43,13 @@ impl YellowstoneServerContext { green_mask_shift: fb_info.green_mask_shift as u64, } } +} - pub fn new(pci_cap: Capability, fb_region: MemoryRegion) -> Result { +impl YellowstoneServerContext { + pub fn new(pci_region: MemoryRegion, fb_region: MemoryRegion) -> Result { Ok(Self { registration_semaphore: mammoth::sync::Semaphore::new()?, - pci_reader: PciReader::new(pci_cap), + pci_reader: PciReader::new(pci_region), framebuffer_info_region: fb_region, service_map: Mutex::new(BTreeMap::new()), }) diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index a485758..598a3de 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -30,7 +30,6 @@ add_executable(zion object/ipc_object.cpp object/memory_object.cpp object/mutex.cpp - object/pci_port.cpp object/port.cpp object/process.cpp object/reply_port.cpp @@ -46,7 +45,6 @@ add_executable(zion syscall/debug.cpp syscall/ipc.cpp syscall/memory_object.cpp - syscall/pci.cpp syscall/process.cpp syscall/synchronization.cpp syscall/syscall.cpp diff --git a/zion/common/port.h b/zion/common/port.h index c3cfaea..4919ff4 100644 --- a/zion/common/port.h +++ b/zion/common/port.h @@ -11,13 +11,3 @@ static inline uint8_t inb(uint16_t port) { static inline void outb(uint16_t port, uint8_t value) { asm volatile("outb %0, %1" ::"a"(value), "Nd"(port)); } - -static inline uint32_t inl(uint16_t port) { - uint32_t result; - asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port)); - return result; -} - -static inline void outl(uint16_t port, uint32_t value) { - asm volatile("outl %0, %1" ::"a"(value), "Nd"(port)); -} diff --git a/zion/include/zcall.h b/zion/include/zcall.h index 26b69dd..6092037 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -71,14 +71,3 @@ SYS1(SemaphoreWait, z_cap_t, semaphore_cap); SYS1(SemaphoreSignal, z_cap_t, semaphore_cap); SYS2(Debug, const char*, message, uint64_t, size); - -// TODO: These should be handled with a more generic user-space interface. -// To be honest we could just have an inl and outl interface that is provided to -// yellowstone and the extra ipc load would be a good stress test of our -// performance -SYS6(PciRead, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, func, - uint8_t, offset, uint32_t*, output); -SYS5(PciCreateBound, z_cap_t, pci_cap, uint8_t, bus, uint8_t, slot, uint8_t, - func, z_cap_t*, new_cap); -SYS3(PciReadBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t*, data); -SYS3(PciWriteBound, z_cap_t, pci_cap, uint8_t, offset, uint32_t, data); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index 046966e..b60db9c 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -67,11 +67,6 @@ const uint64_t kZionSemaphoreSignal = 0x85; // Debugging Calls. const uint64_t kZionDebug = 0x1'0000; -const uint64_t kZionPciRead = 0x1'1000; -const uint64_t kZionPciCreateBound = 0x1'1001; -const uint64_t kZionPciReadBound = 0x1'1002; -const uint64_t kZionPciWriteBound = 0x1'1003; - // Irq Types const uint64_t kZIrqKbd = 0x22; const uint64_t kZIrqPci1 = 0x30; diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index 8926880..b05c70a 100644 --- a/zion/loader/init_loader.cpp +++ b/zion/loader/init_loader.cpp @@ -8,7 +8,6 @@ #include "debug/debug.h" #include "include/zcall.h" #include "memory/paging_util.h" -#include "object/pci_port.h" #include "object/process.h" #include "object/thread.h" #include "scheduler/process_manager.h" @@ -188,9 +187,7 @@ void LoadInitProgram() { WriteFramebufferVmmo(port); if (WritePciVmmo(port, Z_BOOT_PCI_VMMO) != glcr::OK) { - dbgln("Failed to find PCIe space, creating PCI IO Port Cap"); - auto pci_port = PciPort::Create(); - port->WriteKernel(Z_BOOT_PCI_VMMO, MakeRefCounted(pci_port)); + panic("Failed to provide PCI info to init."); } // Start process. diff --git a/zion/object/kernel_object.h b/zion/object/kernel_object.h index ced8ba9..2bdd477 100644 --- a/zion/object/kernel_object.h +++ b/zion/object/kernel_object.h @@ -16,10 +16,6 @@ class KernelObject : public glcr::RefCounted { REPLY_PORT = 0x8, MUTEX = 0x9, SEMAPHORE = 0x10, - - // Temporary. - PCI_CAP = 0x100, - PCI_BOUND_CAP = 0x101, }; virtual uint64_t TypeTag() = 0; diff --git a/zion/object/pci_port.cpp b/zion/object/pci_port.cpp deleted file mode 100644 index 1daef76..0000000 --- a/zion/object/pci_port.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "object/pci_port.h" - -#include "common/port.h" - -namespace { - -const uint16_t PCI_ADDR_PORT = 0xCF8; -const uint16_t PCI_DATA_PORT = 0xCFC; - -uint32_t AddressOf(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset) { - uint32_t lbus = (uint32_t)bus; - uint32_t lslot = (uint32_t)slot; - uint32_t lfunc = (uint32_t)func; - - return (uint32_t)((lbus << 16) | (lslot << 11) | (lfunc << 8) | - (offset & 0xFC) | ((uint32_t)0x80000000)); -} - -uint32_t PciReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, - uint8_t offset) { - uint32_t address = AddressOf(bus, slot, func, offset); - outl(PCI_ADDR_PORT, address); - return inl(PCI_DATA_PORT); -} - -void PciWriteAtOffset(uint8_t bus, uint8_t slot, uint8_t func, uint8_t offset, - uint32_t word) { - uint32_t address = AddressOf(bus, slot, func, offset); - outl(PCI_ADDR_PORT, address); - outl(PCI_DATA_PORT, word); -} - -} // namespace - -uint32_t PciPort::ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, - uint8_t offset) { - return PciReadAtOffset(bus, slot, func, offset); -} - -uint32_t PciPortBound::Read(uint8_t offset) { - return PciReadAtOffset(bus_, slot_, func_, offset); -} - -void PciPortBound::Write(uint8_t offset, uint32_t data) { - PciWriteAtOffset(bus_, slot_, func_, offset, data); -} diff --git a/zion/object/pci_port.h b/zion/object/pci_port.h deleted file mode 100644 index 6287f31..0000000 --- a/zion/object/pci_port.h +++ /dev/null @@ -1,60 +0,0 @@ -#include - -#include "include/ztypes.h" -#include "object/kernel_object.h" - -class PciPort; -class PciPortBound; - -template <> -struct KernelObjectTag { - static const uint64_t type = KernelObject::PCI_CAP; -}; - -class PciPort : public KernelObject { - public: - static uint64_t DefaultPermissions() { - return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate | - kZionPerm_Transmit; - } - - uint64_t TypeTag() override { return KernelObject::PCI_CAP; } - - static glcr::RefPtr Create() { return glcr::AdoptPtr(new PciPort); } - - uint32_t ReadAtOffset(uint8_t bus, uint8_t slot, uint8_t func, - uint8_t offset); - - private: - PciPort() {} -}; - -template <> -struct KernelObjectTag { - static const uint64_t type = KernelObject::PCI_BOUND_CAP; -}; - -class PciPortBound : public KernelObject { - public: - static uint64_t DefaultPermissions() { - return kZionPerm_Write | kZionPerm_Read | kZionPerm_Duplicate; - } - - uint64_t TypeTag() override { return KernelObject::PCI_BOUND_CAP; } - - static glcr::RefPtr Create(uint8_t bus, uint8_t slot, - uint8_t func) { - return glcr::AdoptPtr(new PciPortBound(bus, slot, func)); - } - - uint32_t Read(uint8_t offset); - void Write(uint8_t offset, uint32_t data); - - private: - PciPortBound(uint8_t bus, uint8_t slot, uint8_t func) - : bus_(bus), slot_(slot), func_(func) {} - - uint8_t bus_; - uint8_t slot_; - uint8_t func_; -}; diff --git a/zion/syscall/pci.cpp b/zion/syscall/pci.cpp deleted file mode 100644 index 1a1c7bc..0000000 --- a/zion/syscall/pci.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "syscall/pci.h" - -#include "object/pci_port.h" -#include "scheduler/scheduler.h" - -z_err_t PciRead(ZPciReadReq* req) { - auto& curr_proc = gScheduler->CurrentProcess(); - auto pci_cap = curr_proc.GetCapability(req->pci_cap); - RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); - - *req->output = pci_cap->obj()->ReadAtOffset(req->bus, req->slot, - req->func, req->offset); - - return glcr::OK; -} - -z_err_t PciCreateBound(ZPciCreateBoundReq* req) { - auto& curr_proc = gScheduler->CurrentProcess(); - auto pci_cap = curr_proc.GetCapability(req->pci_cap); - RET_ERR(ValidateCapability(pci_cap, kZionPerm_Duplicate)); - - *req->new_cap = curr_proc.AddNewCapability( - PciPortBound::Create(req->bus, req->slot, req->func)); - return glcr::OK; -} - -z_err_t PciReadBound(ZPciReadBoundReq* req) { - auto& curr_proc = gScheduler->CurrentProcess(); - auto pci_cap = curr_proc.GetCapability(req->pci_cap); - RET_ERR(ValidateCapability(pci_cap, kZionPerm_Read)); - - *req->data = pci_cap->obj()->Read(req->offset); - - return glcr::OK; -} -z_err_t PciWriteBound(ZPciWriteBoundReq* req) { - auto& curr_proc = gScheduler->CurrentProcess(); - auto pci_cap = curr_proc.GetCapability(req->pci_cap); - RET_ERR(ValidateCapability(pci_cap, kZionPerm_Write)); - - pci_cap->obj()->Write(req->offset, req->data); - - return glcr::OK; -} diff --git a/zion/syscall/pci.h b/zion/syscall/pci.h deleted file mode 100644 index f31680b..0000000 --- a/zion/syscall/pci.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "include/zcall.h" - -z_err_t PciRead(ZPciReadReq* req); -z_err_t PciCreateBound(ZPciCreateBoundReq* req); -z_err_t PciReadBound(ZPciReadBoundReq* req); -z_err_t PciWriteBound(ZPciWriteBoundReq* req); From 2258135cfccd3bd605e9c19c5e6659a005d6dc4a Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Thu, 8 May 2025 00:34:40 -0700 Subject: [PATCH 184/186] [voyageurs] Zero-out command structures before passing them to XHCI. This fixes two XHCI driver issues. --- sys/voyageurs/xhci/device_slot.cpp | 1 + sys/voyageurs/xhci/xhci_driver.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/sys/voyageurs/xhci/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp index e9fc3b4..1634f7c 100644 --- a/sys/voyageurs/xhci/device_slot.cpp +++ b/sys/voyageurs/xhci/device_slot.cpp @@ -31,6 +31,7 @@ XhciTrb DeviceSlot::CreateAddressDeviceCommand(uint8_t root_port, uint16_t max_packet_size) { // Initialize Slot Context and Endpoint 0 Context. input_context_->input.add_contexts = 0x3; + input_context_->input.drop_contexts = 0; // Set context_entries to 1. XHCI 4.3.3 input_context_->slot_context.route_speed_entries = (0x1 << 27) | route_string; input_context_->slot_context.latency_port_number = root_port << 16; diff --git a/sys/voyageurs/xhci/xhci_driver.cpp b/sys/voyageurs/xhci/xhci_driver.cpp index ce1a128..4eedce0 100644 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ b/sys/voyageurs/xhci/xhci_driver.cpp @@ -293,6 +293,8 @@ glcr::ErrorCode XhciDriver::InitiateEventRingSegmentTable() { event_ring_segment_table_[0].ring_segment_base = event_ring_.PhysicalAddress(); event_ring_segment_table_[0].ring_segment_size = ers_size & 0xFFFF; + event_ring_segment_table_[0].reserved1 = 0; + event_ring_segment_table_[0].reserved2 = 0; runtime_->interrupters[0].event_ring_dequeue_pointer = event_ring_.PhysicalAddress() | 0x8; From 311755c8126e0503e98255585aa79f8eaa95e5b1 Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 18 May 2025 19:11:52 -0700 Subject: [PATCH 185/186] Fix build image. --- rust-toolchain.toml | 3 +++ rust/rust-toolchain.toml | 2 -- rust/x86_64-acadia-os.json | 4 ++-- scripts/build_image.sh | 10 +++++----- 4 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 rust-toolchain.toml delete mode 100644 rust/rust-toolchain.toml diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000..66768f4 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2025-10-02" +components = ["rustfmt", "rust-analyzer"] diff --git a/rust/rust-toolchain.toml b/rust/rust-toolchain.toml deleted file mode 100644 index 5d56faf..0000000 --- a/rust/rust-toolchain.toml +++ /dev/null @@ -1,2 +0,0 @@ -[toolchain] -channel = "nightly" diff --git a/rust/x86_64-acadia-os.json b/rust/x86_64-acadia-os.json index 6e6dec1..1060335 100644 --- a/rust/x86_64-acadia-os.json +++ b/rust/x86_64-acadia-os.json @@ -3,8 +3,8 @@ "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", "arch": "x86_64", "target-endian": "little", - "target-pointer-width": "64", - "target-c-int-width": "32", + "target-pointer-width": 64, + "target-c-int-width": 32, "os": "none", "executables": true, "linker-flavor": "ld.lld", diff --git a/scripts/build_image.sh b/scripts/build_image.sh index 2fd5867..9b39927 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -31,15 +31,15 @@ cleanup() { } trap cleanup EXIT -parted -s $dev mklabel gpt mkpart EFI fat32 1MiB 10MiB mkpart ext2 10MiB 100% set 1 esp on -mkfs.fat -F 12 "${dev}p1" -mke2fs "${dev}p2" +parted -s $dev mklabel gpt mkpart BIOS ext2 1MiB 2MiB mkpart EFI fat32 2MiB 11MiB mkpart ext2 11MiB 100% set 1 bios_grub on set 2 esp on +mkfs.fat -F 12 "${dev}p2" +mke2fs "${dev}p3" limine bios-install "${dev}" mkdir -p $EFI_DIR -mount "${dev}p1" $EFI_DIR +mount "${dev}p2" $EFI_DIR mkdir -p $EFI_DIR/EFI/BOOT cp /usr/share/limine/BOOTX64.EFI $EFI_DIR/EFI/BOOT @@ -52,7 +52,7 @@ cp $REPO_ROOT/sysroot/bin/denali $EFI_DIR/sys/denali cp $REPO_ROOT/sysroot/bin/victoriafalls $EFI_DIR/sys/victoriafalls mkdir -p $SYSROOT -mount "${dev}p2" $SYSROOT +mount "${dev}p3" $SYSROOT rsync -a "$REPO_ROOT/sysroot" $BUILD_DIR ls $SYSROOT From 1a48911745d48f9f7207ab63ff6a84fe8703e35b Mon Sep 17 00:00:00 2001 From: Drew Galbraith Date: Sun, 14 Dec 2025 09:02:59 +0000 Subject: [PATCH 186/186] Add rust lint CI job. (#9) Additionally fix the many lint errors that are occurring. (or disable them). Reviewed-on: https://git.tiramisu.one/drew/acadia/pulls/9 Co-authored-by: Drew Galbraith Co-committed-by: Drew Galbraith --- .forgejo/workflows/ci.yml | 42 +++++++++++++++ rust-toolchain.toml | 2 +- rust/lib/fs/ext2/src/ext2_driver.rs | 14 +++-- rust/lib/fs/ext2/src/types.rs | 2 + rust/lib/mammoth/src/cap_syscall.rs | 1 - rust/lib/mammoth/src/elf.rs | 3 +- rust/lib/mammoth/src/init.rs | 2 +- rust/lib/mammoth/src/macros.rs | 11 ++-- rust/lib/mammoth/src/mem.rs | 2 +- rust/lib/mammoth/src/sync.rs | 13 ++++- rust/lib/mammoth/src/syscall.rs | 1 - rust/lib/mammoth/src/task/mod.rs | 11 ++-- rust/lib/mammoth/src/thread.rs | 2 +- rust/lib/pci/src/device.rs | 5 +- rust/lib/voyageurs/src/listener.rs | 4 +- rust/lib/yellowstone/src/lib.rs | 4 +- rust/lib/yunq-test/src/lib.rs | 57 ++++++++++++++------- rust/lib/yunq/src/buffer.rs | 15 ++++-- rust/lib/yunq/src/client.rs | 2 +- rust/lib/yunq/src/message.rs | 22 ++++---- rust/lib/yunq/src/server.rs | 12 ++--- rust/sys/denali/src/ahci/command.rs | 2 +- rust/sys/denali/src/ahci/port_controller.rs | 5 +- rust/sys/teton/src/framebuffer.rs | 5 +- rust/sys/teton/src/psf.rs | 2 +- rust/sys/teton/src/terminal.rs | 6 +-- rust/sys/victoriafalls/src/lib.rs | 4 +- rust/sys/victoriafalls/src/server.rs | 4 +- rust/sys/yellowstone/src/server.rs | 5 +- yunq/rust/src/codegen.rs | 25 ++++----- 30 files changed, 177 insertions(+), 108 deletions(-) create mode 100644 .forgejo/workflows/ci.yml diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml new file mode 100644 index 0000000..bf7a604 --- /dev/null +++ b/.forgejo/workflows/ci.yml @@ -0,0 +1,42 @@ +name: Check + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + # Should speed up builds. + CARGO_INCREMENTAL: 0 + # Should reduce the size of ./target to improve cache load/store. + CARGO_PROFILE_TEST_DEBUG: 0 + +jobs: + check: + name: Check Rust + runs-on: docker + + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Install Rust + uses: https://codeberg.org/wackbyte/rust-toolchain@trunk + with: + toolchain: nightly-2025-10-02 + components: rustfmt, clippy, rust-src + - name: Cache + uses: https://github.com/Swatinem/rust-cache@v2 + with: + # Don't cache ~/.cargo/bin since we restore the cache after we install things there + cache-bin: "false" + workspaces: "backend" + - name: "Check Format" + run: cargo fmt --check + working-directory: rust + - name: "Lint" + run: | + rustup component add clippy + cargo clippy --locked -- -D warnings + working-directory: rust diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 66768f4..f7acab6 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] channel = "nightly-2025-10-02" -components = ["rustfmt", "rust-analyzer"] +components = ["rustfmt", "rust-analyzer", "clippy", "rust-src"] diff --git a/rust/lib/fs/ext2/src/ext2_driver.rs b/rust/lib/fs/ext2/src/ext2_driver.rs index 96bb858..0997b62 100644 --- a/rust/lib/fs/ext2/src/ext2_driver.rs +++ b/rust/lib/fs/ext2/src/ext2_driver.rs @@ -94,7 +94,7 @@ impl Ext2Driver { /// 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] { + if self.inode_table_map[block_group_num].is_none() { debug!( "Cache MISS on inode table for block_group {}", block_group_num @@ -148,17 +148,15 @@ impl Ext2Driver { 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 dbl_indr_blocks: &[u32] = &dbl_indr_block_mem.slice()[0..num_dbl_indr]; let mut blocks_to_read = Vec::new(); - for i in 0..num_dbl_indr { + for (i, dbl_indr_block) in dbl_indr_blocks.iter().enumerate() { 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, - ), + &mut self + .get_blocks_from_single_indirect(*dbl_indr_block as u64, num_blocks_in_single), ); } @@ -176,7 +174,7 @@ impl Ext2Driver { let mut blocks = Vec::new(); - while let Some(block) = iter.next() { + for block in iter { if block as u64 == (curr_block.lba + curr_block.size) { curr_block.size += 1; } else { diff --git a/rust/lib/fs/ext2/src/types.rs b/rust/lib/fs/ext2/src/types.rs index 7aa3d2b..fd1f59b 100644 --- a/rust/lib/fs/ext2/src/types.rs +++ b/rust/lib/fs/ext2/src/types.rs @@ -111,7 +111,9 @@ pub struct Inode { const _: () = assert!(size_of::() == 128); +#[allow(dead_code)] pub const EXT2_FT_FILE: u8 = 0x1; +#[allow(dead_code)] pub const EXT2_FT_DIR: u8 = 0x2; #[repr(C, packed)] diff --git a/rust/lib/mammoth/src/cap_syscall.rs b/rust/lib/mammoth/src/cap_syscall.rs index eb9567a..b820bdc 100644 --- a/rust/lib/mammoth/src/cap_syscall.rs +++ b/rust/lib/mammoth/src/cap_syscall.rs @@ -2,7 +2,6 @@ use core::ffi::c_void; use crate::zion::{self, z_cap_t, ZError}; -#[must_use] fn syscall(id: u64, req: &T) -> Result<(), ZError> { unsafe { let resp = zion::SysCall1(id, req as *const T as *const c_void); diff --git a/rust/lib/mammoth/src/elf.rs b/rust/lib/mammoth/src/elf.rs index 2b8638f..96807d2 100644 --- a/rust/lib/mammoth/src/elf.rs +++ b/rust/lib/mammoth/src/elf.rs @@ -1,5 +1,4 @@ use crate::cap::Capability; -use crate::debug; use crate::init; use crate::syscall; use crate::zion::ZError; @@ -237,7 +236,7 @@ fn load_program_segment( let page_offset = prog_header.vaddr & 0xFFF; let mem_size = page_offset + prog_header.mem_size; - let mem_object = crate::mem::MemoryRegion::new(mem_size)?; + let mut mem_object = crate::mem::MemoryRegion::new(mem_size)?; for i in mem_object.mut_slice() { *i = 0; diff --git a/rust/lib/mammoth/src/init.rs b/rust/lib/mammoth/src/init.rs index 556cf24..c190ad1 100644 --- a/rust/lib/mammoth/src/init.rs +++ b/rust/lib/mammoth/src/init.rs @@ -28,7 +28,7 @@ pub fn parse_init_port(port_cap: z_cap_t) { let mut caps: [u64; 1] = [0]; let resp = syscall::port_poll(&init_port, &mut bytes, &mut caps); - if let Err(_) = resp { + if resp.is_err() { break; } diff --git a/rust/lib/mammoth/src/macros.rs b/rust/lib/mammoth/src/macros.rs index c977a91..3fc64c5 100644 --- a/rust/lib/mammoth/src/macros.rs +++ b/rust/lib/mammoth/src/macros.rs @@ -2,21 +2,20 @@ use alloc::string::String; use alloc::vec::Vec; use core::fmt; +#[derive(Default)] pub struct Writer { int_vec: Vec, } impl Writer { pub fn new() -> Self { - Self { - int_vec: Vec::new(), - } + Writer::default() } } -impl Into for Writer { - fn into(self) -> String { - String::from_utf8(self.int_vec).expect("Failed to convert") +impl From for String { + fn from(value: Writer) -> Self { + String::from_utf8(value.int_vec).expect("Failed to convert") } } diff --git a/rust/lib/mammoth/src/mem.rs b/rust/lib/mammoth/src/mem.rs index 8d5af40..90183ec 100644 --- a/rust/lib/mammoth/src/mem.rs +++ b/rust/lib/mammoth/src/mem.rs @@ -85,7 +85,7 @@ impl MemoryRegion { } } - pub fn mut_slice(&self) -> &mut [T] { + pub fn mut_slice(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut( self.virt_addr as *mut T, diff --git a/rust/lib/mammoth/src/sync.rs b/rust/lib/mammoth/src/sync.rs index 0ee5fea..f435e32 100644 --- a/rust/lib/mammoth/src/sync.rs +++ b/rust/lib/mammoth/src/sync.rs @@ -50,7 +50,7 @@ impl DerefMut for MutexGuard<'_, T> { } } -impl Mutex { +impl<'a, T> Mutex { pub fn new(data: T) -> Mutex { Mutex { cap: syscall::mutex_create().unwrap(), @@ -58,7 +58,7 @@ impl Mutex { } } - pub fn lock(&self) -> MutexGuard { + pub fn lock(&'a self) -> MutexGuard<'a, T> { syscall::mutex_lock(&self.cap).unwrap(); MutexGuard { mutex: self } @@ -70,3 +70,12 @@ impl Drop for MutexGuard<'_, T> { syscall::mutex_release(&self.mutex.cap).unwrap(); } } + +impl Default for Mutex +where + T: Default, +{ + fn default() -> Self { + Self::new(T::default()) + } +} diff --git a/rust/lib/mammoth/src/syscall.rs b/rust/lib/mammoth/src/syscall.rs index 2691458..bab76ca 100644 --- a/rust/lib/mammoth/src/syscall.rs +++ b/rust/lib/mammoth/src/syscall.rs @@ -9,7 +9,6 @@ use core::ffi::c_void; #[cfg(feature = "hosted")] use core::panic::PanicInfo; -#[must_use] fn syscall(id: u64, req: &T) -> Result<(), ZError> { unsafe { let resp = zion::SysCall1(id, req as *const T as *const c_void); diff --git a/rust/lib/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs index 44aab69..ec25afa 100644 --- a/rust/lib/mammoth/src/task/mod.rs +++ b/rust/lib/mammoth/src/task/mod.rs @@ -48,7 +48,7 @@ struct TaskWaker { } impl TaskWaker { - fn new(task_id: TaskId, task_queue: Arc>>) -> Waker { + fn create_waker(task_id: TaskId, task_queue: Arc>>) -> Waker { Waker::from(Arc::new(TaskWaker { task_id, task_queue, @@ -69,6 +69,7 @@ impl Wake for TaskWaker { } } +#[derive(Default)] pub struct Executor { tasks: Arc>>, // TODO: Consider a better datastructure for this. @@ -78,11 +79,7 @@ pub struct Executor { impl Executor { pub fn new() -> Executor { - Executor { - tasks: Arc::new(Mutex::new(BTreeMap::new())), - task_queue: Arc::new(Mutex::new(VecDeque::new())), - waker_cache: BTreeMap::new(), - } + Executor::default() } pub fn spawn(&mut self, task: Task) { @@ -100,7 +97,7 @@ impl Executor { let waker = self .waker_cache .entry(task_id) - .or_insert_with(|| TaskWaker::new(task_id, self.task_queue.clone())); + .or_insert_with(|| TaskWaker::create_waker(task_id, self.task_queue.clone())); let mut ctx = Context::from_waker(waker); match task.poll(&mut ctx) { Poll::Ready(()) => { diff --git a/rust/lib/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs index 99032be..aeb4b27 100644 --- a/rust/lib/mammoth/src/thread.rs +++ b/rust/lib/mammoth/src/thread.rs @@ -40,7 +40,7 @@ where let raw_main = Box::into_raw(Box::new(main)); let proc_cap = Capability::take_copy(unsafe { crate::init::SELF_PROC_CAP }).unwrap(); let cap = syscall::thread_create(&proc_cap).unwrap(); - syscall::thread_start(&cap, entry_point as u64, raw_main as u64, 0).unwrap(); + syscall::thread_start(&cap, entry_point as usize as u64, raw_main as u64, 0).unwrap(); JoinHandle { cap } } diff --git a/rust/lib/pci/src/device.rs b/rust/lib/pci/src/device.rs index ab1b25d..e65e3da 100644 --- a/rust/lib/pci/src/device.rs +++ b/rust/lib/pci/src/device.rs @@ -2,8 +2,7 @@ use alloc::vec::Vec; use mammoth::{cap::Capability, mem::MemoryRegion, syscall, zion::ZError}; use crate::header::{ - PciCapabilityPointer, PciDeviceHeader, PciHeaderType, PciMsiCapability, PciMsiControl, - get_header_type, + PciCapabilityPointer, PciDeviceHeader, PciHeaderType, PciMsiCapability, get_header_type, }; pub struct PciDevice { @@ -11,7 +10,7 @@ pub struct PciDevice { } impl PciDevice { - pub fn from(mut memory_region: MemoryRegion) -> Result { + pub fn from(memory_region: MemoryRegion) -> Result { match get_header_type(&memory_region)? { PciHeaderType::Device => {} t => { diff --git a/rust/lib/voyageurs/src/listener.rs b/rust/lib/voyageurs/src/listener.rs index 1912b88..89e40b6 100644 --- a/rust/lib/voyageurs/src/listener.rs +++ b/rust/lib/voyageurs/src/listener.rs @@ -7,7 +7,7 @@ use mammoth::thread; #[allow(dead_code)] #[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] enum Keycode { - UnknownKeycode = 0x0, + Unknown = 0x0, A = 0x1, B = 0x2, @@ -135,7 +135,7 @@ impl Keycode { 0x37 => Keycode::Period, 0x38 => Keycode::FSlash, 0x39 => Keycode::Esc, - _ => Keycode::UnknownKeycode, + _ => Keycode::Unknown, } } } diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs index 76659ef..ffdc267 100644 --- a/rust/lib/yellowstone/src/lib.rs +++ b/rust/lib/yellowstone/src/lib.rs @@ -10,10 +10,12 @@ static mut YELLOWSTONE_INIT: Option = None; pub fn from_init_endpoint() -> &'static mut YellowstoneClient { unsafe { - if let None = YELLOWSTONE_INIT { + #[allow(static_mut_refs)] + if YELLOWSTONE_INIT.is_none() { YELLOWSTONE_INIT = Some(YellowstoneClient::new(Capability::take(INIT_ENDPOINT))); } + #[allow(static_mut_refs)] YELLOWSTONE_INIT.as_mut().unwrap() } } diff --git a/rust/lib/yunq-test/src/lib.rs b/rust/lib/yunq-test/src/lib.rs index 1a3c3ec..9af3d55 100644 --- a/rust/lib/yunq-test/src/lib.rs +++ b/rust/lib/yunq-test/src/lib.rs @@ -12,7 +12,11 @@ mod tests { #[test] fn basic_serialization() -> Result<(), ZError> { - let basic = Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }; + let basic = Basic { + unsigned_int: 82, + signed_int: -1234, + strn: "abc".to_string(), + }; let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); @@ -27,13 +31,17 @@ mod tests { #[test] fn basic_serialization_as_request() -> Result<(), ZError> { - let basic = Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }; + let basic = Basic { + unsigned_int: 82, + signed_int: -1234, + strn: "abc".to_string(), + }; let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); let req_id = 12; basic.serialize_as_request(req_id, &mut buf, &mut caps)?; - + assert!(buf.at::(8)? == req_id); let parsed = Basic::parse_from_request(&buf, &caps)?; @@ -50,7 +58,7 @@ mod tests { let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); cap.serialize(&mut buf, 0, &mut caps)?; - + assert!(caps.len() == 1); assert!(caps[0] == cap_id); @@ -63,12 +71,14 @@ mod tests { #[test] fn repeated_serialization() -> Result<(), ZError> { - let rep = Repeated { unsigned_ints: vec![0, 1, 3],}; + let rep = Repeated { + unsigned_ints: vec![0, 1, 3], + }; let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); rep.serialize(&mut buf, 0, &mut caps)?; - + let parsed = Repeated::parse(&buf, 0, &caps)?; assert!(parsed == rep); @@ -79,17 +89,20 @@ mod tests { #[test] fn nested_serialization() -> Result<(), ZError> { let nested = Nested { - basic: Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string() }, - cap1: Cap { cap: 37}, - cap2: Cap { cap: 39}, + basic: Basic { + unsigned_int: 82, + signed_int: -1234, + strn: "abc".to_string(), + }, + cap1: Cap { cap: 37 }, + cap2: Cap { cap: 39 }, }; let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); nested.serialize(&mut buf, 0, &mut caps)?; - - let parsed = Nested::parse(&buf, 0, &caps)?; + let parsed = Nested::parse(&buf, 0, &caps)?; assert!(parsed == nested); @@ -99,23 +112,29 @@ mod tests { #[test] fn repeated_nested_serialization() -> Result<(), ZError> { let nested = RepeatedNested { - basics: vec![Basic { unsigned_int: 82, signed_int: -1234, strn: "abc".to_string(),}, - Basic { unsigned_int: 21, signed_int: -8, strn: "def".to_string(), },], - caps: vec![Cap{ cap: 123}, Cap {cap: 12343}], + basics: vec![ + Basic { + unsigned_int: 82, + signed_int: -1234, + strn: "abc".to_string(), + }, + Basic { + unsigned_int: 21, + signed_int: -8, + strn: "def".to_string(), + }, + ], + caps: vec![Cap { cap: 123 }, Cap { cap: 12343 }], }; let mut buf = ByteBuffer::<1024>::new(); let mut caps = Vec::new(); nested.serialize(&mut buf, 0, &mut caps)?; - - let parsed = RepeatedNested::parse(&buf, 0, &caps)?; + let parsed = RepeatedNested::parse(&buf, 0, &caps)?; assert!(parsed == nested); - Ok(()) } - - } diff --git a/rust/lib/yunq/src/buffer.rs b/rust/lib/yunq/src/buffer.rs index c3b0b18..7966337 100644 --- a/rust/lib/yunq/src/buffer.rs +++ b/rust/lib/yunq/src/buffer.rs @@ -5,12 +5,19 @@ pub struct ByteBuffer { buffer: Box<[u8; N]>, } -impl ByteBuffer { - pub fn new() -> Self { +impl Default for ByteBuffer { + fn default() -> Self { Self { buffer: Box::new([0; N]), } } +} + +impl ByteBuffer { + pub fn new() -> Self { + ByteBuffer::default() + } + pub fn size(&self) -> u64 { N as u64 } @@ -54,7 +61,7 @@ impl ByteBuffer { if (len + offset) > N { return Err(ZError::BUFFER_SIZE); } - Ok(alloc::str::from_utf8(&self.buffer[offset..offset + len]) - .map_err(|_| ZError::INVALID_ARGUMENT)?) + alloc::str::from_utf8(&self.buffer[offset..offset + len]) + .map_err(|_| ZError::INVALID_ARGUMENT) } } diff --git a/rust/lib/yunq/src/client.rs b/rust/lib/yunq/src/client.rs index e90698e..c4c45b8 100644 --- a/rust/lib/yunq/src/client.rs +++ b/rust/lib/yunq/src/client.rs @@ -34,5 +34,5 @@ pub fn call_endpoint( return Err(ZError::from(resp_code)); } - Ok(Resp::parse_from_request(&byte_buffer, &cap_buffer)?) + Resp::parse_from_request(byte_buffer, &cap_buffer) } diff --git a/rust/lib/yunq/src/message.rs b/rust/lib/yunq/src/message.rs index d1fc6a5..568916f 100644 --- a/rust/lib/yunq/src/message.rs +++ b/rust/lib/yunq/src/message.rs @@ -28,7 +28,7 @@ pub fn parse_repeated_message( buf: &ByteBuffer, mut offset: usize, len: usize, - caps: &Vec, + caps: &[z_cap_t], ) -> Result, ZError> { let mut repeated = Vec::new(); for _ in 0..len { @@ -43,18 +43,18 @@ pub fn parse_repeated_message( pub fn serialize_repeated( buf: &mut ByteBuffer, offset: usize, - data: &Vec, + data: &[T], ) -> Result { - for i in 0..data.len() { - buf.write_at(offset + (i * size_of::()), data[i])?; + for (i, val) in data.iter().enumerate() { + buf.write_at(offset + (i * size_of::()), val)?; } - Ok(offset + (data.len() * size_of::())) + Ok(offset + size_of_val(data)) } pub fn serialize_repeated_message( buf: &mut ByteBuffer, mut offset: usize, - data: &Vec, + data: &[T], caps: &mut Vec, ) -> Result { for item in data { @@ -76,14 +76,14 @@ pub trait YunqMessage { fn parse( buf: &ByteBuffer, offset: usize, - caps: &Vec, + caps: &[z_cap_t], ) -> Result where Self: Sized; fn parse_from_request( buf: &ByteBuffer, - caps: &Vec, + caps: &[z_cap_t], ) -> Result where Self: Sized, @@ -92,7 +92,7 @@ pub trait YunqMessage { return Err(ZError::INVALID_RESPONSE); } - Ok(Self::parse(&buf, 16, &caps)?) + Self::parse(buf, 16, caps) } fn serialize( @@ -109,7 +109,7 @@ pub trait YunqMessage { caps: &mut Vec, ) -> Result { buf.write_at(0, SENTINEL)?; - buf.write_at(8, request_id as u64)?; + buf.write_at(8, request_id)?; let length = self.serialize(buf, 16, caps)?; @@ -125,7 +125,7 @@ impl YunqMessage for Empty { fn parse( _buf: &ByteBuffer, _offset: usize, - _caps: &Vec, + _caps: &[z_cap_t], ) -> Result where Self: Sized, diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs index a5ded0b..cdfe418 100644 --- a/rust/lib/yunq/src/server.rs +++ b/rust/lib/yunq/src/server.rs @@ -37,7 +37,7 @@ pub trait YunqServer { .expect("Failed to reply"), Err(err) => { crate::message::serialize_error(&mut byte_buffer, err); - syscall::reply_port_send(reply_port_cap, &byte_buffer.slice(0x10), &[]) + syscall::reply_port_send(reply_port_cap, byte_buffer.slice(0x10), &[]) .expect("Failed to reply w/ error") } } @@ -84,11 +84,11 @@ where .at::(8) .expect("Failed to access request length."); let self_clone = self.clone(); - spawner.spawn(Task::new((async move || { + spawner.spawn(Task::new(async move { self_clone .handle_request_and_response(method, byte_buffer, cap_buffer, reply_port_cap) - .await; - })())); + .await + })); } } @@ -113,12 +113,10 @@ where .expect("Failed to reply"), Err(err) => { crate::message::serialize_error(&mut byte_buffer, err); - syscall::reply_port_send(reply_port_cap, &byte_buffer.slice(0x10), &[]) + syscall::reply_port_send(reply_port_cap, byte_buffer.slice(0x10), &[]) .expect("Failed to reply w/ error") } } - - () } } diff --git a/rust/sys/denali/src/ahci/command.rs b/rust/sys/denali/src/ahci/command.rs index 947082e..c827bb1 100644 --- a/rust/sys/denali/src/ahci/command.rs +++ b/rust/sys/denali/src/ahci/command.rs @@ -95,7 +95,7 @@ impl Command { command: SataCommand::DmaReadExt, lba, sector_cnt: lba_count, - paddr: paddr, + paddr, memory_region: None, } } diff --git a/rust/sys/denali/src/ahci/port_controller.rs b/rust/sys/denali/src/ahci/port_controller.rs index 556e8f7..42dfa00 100644 --- a/rust/sys/denali/src/ahci/port_controller.rs +++ b/rust/sys/denali/src/ahci/port_controller.rs @@ -44,9 +44,8 @@ impl PortController { }; // This leaves space for 8 prdt entries. - for i in 0..32 { - command_list[i].command_table_base_addr = - (command_paddr + 0x500) + (0x100 * (i as u64)); + for (i, header) in command_list.iter_mut().enumerate() { + header.command_table_base_addr = (command_paddr + 0x500) + (0x100 * (i as u64)); } let command_slots = array::from_fn(|_| Arc::new(Mutex::new(CommandStatus::Empty))); diff --git a/rust/sys/teton/src/framebuffer.rs b/rust/sys/teton/src/framebuffer.rs index dad4099..f083367 100644 --- a/rust/sys/teton/src/framebuffer.rs +++ b/rust/sys/teton/src/framebuffer.rs @@ -16,15 +16,16 @@ impl Framebuffer { }) } - fn draw_pixel(&self, row: u32, col: u32, pixel: u32) { + fn draw_pixel(&mut self, row: u32, col: u32, pixel: u32) { let index = row * (self.fb_info.pitch as u32 / 4) + col; self.memory_region.mut_slice()[index as usize] = pixel; } - pub fn draw_glyph(&self, glyph: &[u8], row: u32, col: u32) { + pub fn draw_glyph(&mut self, glyph: &[u8], row: u32, col: u32) { let gl_width = 8; let gl_height = 16; + #[allow(clippy::needless_range_loop)] for r in 0..gl_height { for c in 0..gl_width { if ((glyph[r] >> c) % 2) == 1 { diff --git a/rust/sys/teton/src/psf.rs b/rust/sys/teton/src/psf.rs index f6a75a6..3f99f65 100644 --- a/rust/sys/teton/src/psf.rs +++ b/rust/sys/teton/src/psf.rs @@ -23,7 +23,7 @@ pub struct Psf { impl Psf { pub fn new(path: &str) -> Result { - let file = File::open(&path)?; + let file = File::open(path)?; let header = file.slice()[0..core::mem::size_of::()] .as_ptr() diff --git a/rust/sys/teton/src/terminal.rs b/rust/sys/teton/src/terminal.rs index 5c7d314..f8a9e0f 100644 --- a/rust/sys/teton/src/terminal.rs +++ b/rust/sys/teton/src/terminal.rs @@ -62,10 +62,8 @@ impl Terminal { } fn write_line(&mut self, line: &str) { - let mut col = 0; - for c in line.chars() { - self.console.write_char(c, self.row, col); - col += 1; + for (col, c) in line.chars().enumerate() { + self.console.write_char(c, self.row, col as u32); } self.row += 1 diff --git a/rust/sys/victoriafalls/src/lib.rs b/rust/sys/victoriafalls/src/lib.rs index b7b9ca3..a213a8b 100644 --- a/rust/sys/victoriafalls/src/lib.rs +++ b/rust/sys/victoriafalls/src/lib.rs @@ -12,7 +12,8 @@ static mut VFS_CLIENT: Option = None; fn get_client() -> &'static mut VFSClient { unsafe { - if let None = VFS_CLIENT { + #[allow(static_mut_refs)] + if VFS_CLIENT.is_none() { let endpoint_cap = yellowstone_yunq::from_init_endpoint() .get_endpoint(&yellowstone_yunq::GetEndpointRequest { endpoint_name: "victoriafalls".to_string(), @@ -21,6 +22,7 @@ fn get_client() -> &'static mut VFSClient { VFS_CLIENT = Some(VFSClient::new(Capability::take(endpoint_cap.endpoint))); } + #[allow(static_mut_refs)] VFS_CLIENT.as_mut().unwrap() } } diff --git a/rust/sys/victoriafalls/src/server.rs b/rust/sys/victoriafalls/src/server.rs index 0c2edb8..a901ea9 100644 --- a/rust/sys/victoriafalls/src/server.rs +++ b/rust/sys/victoriafalls/src/server.rs @@ -35,7 +35,7 @@ impl VFSServerHandler for VictoriaFallsServerImpl { let mut inode_num = 2; // Start with root. - while let Some(path_token) = tokens.next() { + for path_token in tokens { inode_num = self.find_path_in_dir(inode_num, path_token)?; } @@ -57,7 +57,7 @@ impl VFSServerHandler for VictoriaFallsServerImpl { let mut inode_num = 2; // Start with root. - while let Some(path_token) = tokens.next() { + for path_token in tokens { inode_num = self.find_path_in_dir(inode_num, path_token)?; } diff --git a/rust/sys/yellowstone/src/server.rs b/rust/sys/yellowstone/src/server.rs index 8cc4a4b..a6d5fa1 100644 --- a/rust/sys/yellowstone/src/server.rs +++ b/rust/sys/yellowstone/src/server.rs @@ -57,9 +57,8 @@ impl YellowstoneServerContext { pub fn wait(&self, service: &str) -> Result<(), ZError> { loop { - match self.service_map.lock().get(service) { - Some(_) => return Ok(()), - None => {} + if self.service_map.lock().get(service).is_some() { + return Ok(()); } self.registration_semaphore.wait().unwrap(); } diff --git a/yunq/rust/src/codegen.rs b/yunq/rust/src/codegen.rs index 7eefb66..9462f4b 100644 --- a/yunq/rust/src/codegen.rs +++ b/yunq/rust/src/codegen.rs @@ -122,7 +122,7 @@ fn parse_field(field: &Field) -> TokenStream { let rep_offset = buf.at::(yunq::message::field_offset(offset, #ind))?; let rep_len = buf.at::(yunq::message::field_offset(offset, #ind) + 4)?; - yunq::message::parse_repeated_message(buf, offset + rep_offset as usize, rep_len as usize, &caps)? + yunq::message::parse_repeated_message(buf, offset + rep_offset as usize, rep_len as usize, caps)? }; }, } @@ -174,7 +174,7 @@ fn generate_serialize(message: &Message) -> TokenStream { &self, buf: &mut yunq::ByteBuffer, offset: usize, - caps: &mut alloc::vec::Vec, + caps: &mut Vec, ) -> Result { let num_fields = #num_fields; let core_size: u32 = (yunq::message::MESSAGE_HEADER_SIZE + 8 * num_fields) as u32; @@ -183,10 +183,10 @@ fn generate_serialize(message: &Message) -> TokenStream { #(#serializers)* - buf.write_at(offset + 0, yunq::message::MESSAGE_IDENT)?; + buf.write_at(offset, yunq::message::MESSAGE_IDENT)?; buf.write_at(offset + 4, core_size)?; buf.write_at(offset + 8, next_extension)?; - buf.write_at(offset + 12, 0 as u32)?; + buf.write_at(offset + 12, 0_u32)?; Ok(next_extension as usize) } } @@ -200,12 +200,12 @@ fn generate_parse(message: &Message) -> TokenStream { fn parse( buf: &yunq::ByteBuffer, offset: usize, - caps: &alloc::vec::Vec, + caps: &[z_cap_t], ) -> Result where Self: Sized, { - if buf.at::(offset + 0)? != yunq::message::MESSAGE_IDENT { + if buf.at::(offset)? != yunq::message::MESSAGE_IDENT { mammoth::debug!("Expected IDENT at offest {:#x}, got {:#x}", offset, buf.at::(offset)?); return Err(ZError::INVALID_ARGUMENT); } @@ -303,7 +303,7 @@ fn generate_server_case(method: &Method) -> TokenStream { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; let resp = self.handler.#name(req)?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) }, @@ -312,7 +312,7 @@ fn generate_server_case(method: &Method) -> TokenStream { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; self.handler.#name(req)?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); // TODO: Implement serialization for EmptyMessage so this is less hacky. yunq::message::serialize_error(byte_buffer, ZError::from(0)); Ok(0x10) @@ -321,7 +321,7 @@ fn generate_server_case(method: &Method) -> TokenStream { (None, Some(_)) => quote! { #id => { let resp = self.handler.#name()?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) }, @@ -403,7 +403,7 @@ fn generate_async_server_case(method: &Method) -> TokenStream { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; let resp = self.handler.#name(req).await?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) }, @@ -412,7 +412,7 @@ fn generate_async_server_case(method: &Method) -> TokenStream { #id => { let req = #req::parse_from_request(byte_buffer, cap_buffer)?; self.handler.#name(req).await?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); // TODO: Implement serialization for EmptyMessage so this is less hacky. yunq::message::serialize_error(byte_buffer, ZError::from(0)); Ok(0x10) @@ -421,7 +421,7 @@ fn generate_async_server_case(method: &Method) -> TokenStream { (None, Some(_)) => quote! { #id => { let resp = self.handler.#name().await?; - cap_buffer.resize(0, 0); + cap_buffer.clear(); let resp_len = resp.serialize_as_request(0, byte_buffer, cap_buffer)?; Ok(resp_len) }, @@ -547,6 +547,7 @@ pub fn generate_code(ast: &[Decl]) -> String { use alloc::vec::Vec; use mammoth::zion::z_cap_t; use mammoth::zion::ZError; + #[allow(unused_imports)] use yunq::ByteBuffer; use yunq::YunqMessage;