diff --git a/.bochsrc b/.bochsrc deleted file mode 100644 index 5a417a9..0000000 --- a/.bochsrc +++ /dev/null @@ -1,15 +0,0 @@ -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 -port_e9_hack: enabled=1 -# Breaks on XCHGW %BX, %BX -magic_break: enabled=1 diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml deleted file mode 100644 index bf7a604..0000000 --- a/.forgejo/workflows/ci.yml +++ /dev/null @@ -1,42 +0,0 @@ -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/.gitignore b/.gitignore index 7e2de93..ae043f6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,6 @@ builddbg/ -test-bin/ __pycache__/ -.ccls-cache/ compile_commands.json -bochs.log -serial.out - sysroot/bin -sysroot/usr -sysroot/.crates.toml -sysroot/.crates2.json - -rust/target -yunq/venv -yunq/rust/target +sysroot/usr/bin diff --git a/CMakeLists.txt b/CMakeLists.txt index e99a91c..ae70f18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.2) # Set because our cross compiler can't do dynamic linking? set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") @@ -9,19 +9,11 @@ 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 -mincoming-stack-boundary=3") +set(BASE_COMPILE_FLAGS "-ffreestanding -fno-rtti -fno-exceptions") 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(yunq) add_subdirectory(lib) +add_subdirectory(yunq) add_subdirectory(usr) add_subdirectory(sys) diff --git a/RELEASES.md b/RELEASES.md index 7b19818..3c5bb6f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,24 +1,5 @@ # 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 diff --git a/lib/glacier/CMakeLists.txt b/lib/glacier/CMakeLists.txt index ef0489f..e20b9c9 100644 --- a/lib/glacier/CMakeLists.txt +++ b/lib/glacier/CMakeLists.txt @@ -29,7 +29,3 @@ 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/container/array.h b/lib/glacier/container/array.h index 62f9f87..171550b 100644 --- a/lib/glacier/container/array.h +++ b/lib/glacier/container/array.h @@ -2,7 +2,6 @@ #include -#include "glacier/container/array_iter.h" #include "glacier/container/array_view.h" namespace glcr { @@ -38,13 +37,6 @@ 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_iter.h b/lib/glacier/container/array_iter.h deleted file mode 100644 index 195e9df..0000000 --- a/lib/glacier/container/array_iter.h +++ /dev/null @@ -1,40 +0,0 @@ -#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/array_view.h b/lib/glacier/container/array_view.h index f4415e8..da16e9d 100644 --- a/lib/glacier/container/array_view.h +++ b/lib/glacier/container/array_view.h @@ -2,8 +2,6 @@ #include -#include "glacier/container/array_iter.h" - namespace glcr { template @@ -12,9 +10,7 @@ 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) {} @@ -28,23 +24,6 @@ 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_; diff --git a/lib/glacier/container/hash_map.h b/lib/glacier/container/hash_map.h index 10d4aca..1390ab6 100644 --- a/lib/glacier/container/hash_map.h +++ b/lib/glacier/container/hash_map.h @@ -18,8 +18,9 @@ class HashMap { HashMap() = default; HashMap(const HashMap&) = delete; HashMap& operator=(const HashMap&) = delete; - HashMap(HashMap&&); - HashMap& operator=(HashMap&&); + // TODO: Implement Move. + HashMap(HashMap&&) = delete; + HashMap& operator=(HashMap&&) = delete; // Accessors. uint64_t size() { return size_; } @@ -62,21 +63,6 @@ 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); @@ -88,8 +74,7 @@ V& HashMap::at(const K& key) { } } // TODO: Add a failure mode here instead of constructing an object. - K k2 = key; - ll.PushFront({glcr::Move(k2), {}}); + ll.PushFront({key, {}}); return ll.PeekFront().second(); } @@ -209,7 +194,8 @@ template void HashMap::Resize(uint64_t new_size) { Array>> new_data(new_size); - for (auto& ll : data_) { + for (uint64_t i = 0; i < data_.size(); i++) { + auto& ll = data_[i]; while (!ll.empty()) { auto pair = ll.PopFront(); uint64_t hc = H()(pair.first()); diff --git a/lib/glacier/container/intrusive_list.h b/lib/glacier/container/intrusive_list.h index aef7b83..8957a32 100644 --- a/lib/glacier/container/intrusive_list.h +++ b/lib/glacier/container/intrusive_list.h @@ -20,8 +20,6 @@ class IntrusiveList { void PushFront(const RefPtr& obj); void PushBack(const RefPtr& obj); - void Remove(const RefPtr& obj); - RefPtr PopFront(); RefPtr PopBack(); @@ -66,29 +64,6 @@ 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) { diff --git a/lib/glacier/container/vector.h b/lib/glacier/container/vector.h index b4b994c..afe6229 100644 --- a/lib/glacier/container/vector.h +++ b/lib/glacier/container/vector.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -38,7 +37,6 @@ 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); @@ -47,16 +45,8 @@ class Vector { template void EmplaceBack(Args&&... args); - T& PeekBack(); T&& PopBack(); - 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_; @@ -131,11 +121,6 @@ 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/glacier/string/string.cpp b/lib/glacier/string/string.cpp index a2b6db3..e0a5b67 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_; } } diff --git a/lib/glacier/test/CMakeLists.txt b/lib/glacier/test/CMakeLists.txt deleted file mode 100644 index c3701f7..0000000 --- a/lib/glacier/test/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(container) - diff --git a/lib/glacier/test/container/CMakeLists.txt b/lib/glacier/test/container/CMakeLists.txt deleted file mode 100644 index f5488ab..0000000 --- a/lib/glacier/test/container/CMakeLists.txt +++ /dev/null @@ -1,8 +0,0 @@ -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/glacier/test/container/vector.cpp b/lib/glacier/test/container/vector.cpp deleted file mode 100644 index 4ec0d65..0000000 --- a/lib/glacier/test/container/vector.cpp +++ /dev/null @@ -1,172 +0,0 @@ -#include "container/vector.h" - -#include - -using namespace glcr; - -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); - } -} - -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); -} - -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); - } -} diff --git a/lib/mammoth/CMakeLists.txt b/lib/mammoth/CMakeLists.txt index 5ceed59..ea431ab 100644 --- a/lib/mammoth/CMakeLists.txt +++ b/lib/mammoth/CMakeLists.txt @@ -1,7 +1,14 @@ 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 @@ -17,6 +24,7 @@ target_include_directories(mammoth target_link_libraries(mammoth glacier + victoriafalls_yunq yellowstone_yunq voyageurs_yunq zion_stub diff --git a/lib/mammoth/file/file.cpp b/lib/mammoth/file/file.cpp new file mode 100644 index 0000000..7d2a9a7 --- /dev/null +++ b/lib/mammoth/file/file.cpp @@ -0,0 +1,81 @@ +#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 (uint64_t i = 0; i < file_views.size(); i++) { + files.PushBack(file_views[i]); + } + return files; +} + +} // namespace mmth diff --git a/lib/mammoth/file/file.h b/lib/mammoth/file/file.h new file mode 100644 index 0000000..7b55f2e --- /dev/null +++ b/lib/mammoth/file/file.h @@ -0,0 +1,38 @@ +#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 new file mode 100644 index 0000000..77b4858 --- /dev/null +++ b/lib/mammoth/input/keyboard.cpp @@ -0,0 +1,283 @@ +#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_.RecvChar(); + if (!scancode_or.ok()) { + check(scancode_or.error()); + } + uint8_t scancode = scancode_or.value(); + + if (scancode == 0xE0) { + extended_on_ = true; + continue; + } + + Keycode k = ScancodeToKeycode(scancode); + Action a = ScancodeToAction(scancode); + HandleKeycode(k, a); + } +} + +void KeyboardListenerBase::HandleKeycode(Keycode code, Action action) { + char c = '\0'; + + if (action == kPressed) { + if (code >= kA && code <= kZ) { + if (IsShift()) { + 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 if (action == kReleased) { + if (code == kLShift) { + lshift_ = false; + } else if (code == kRShift) { + rshift_ = false; + } + } + + if (c != '\0') { + HandleCharacter(c); + } +} + +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; + } + + 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: + return kB; + case 0x31: + return kN; + case 0x32: + return kM; + case 0x33: + return kComma; + case 0x34: + return kPeriod; + case 0x35: + return kFSlash; + case 0x36: + return kRShift; + case 0x38: + return kLAlt; + case 0x39: + return kSpace; + } + + dbgln("Unknown scancode {x}", 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 new file mode 100644 index 0000000..cba2d18 --- /dev/null +++ b/lib/mammoth/input/keyboard.h @@ -0,0 +1,123 @@ +#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, +}; + +enum Action { + kUnknownAction, + kPressed, + kReleased, +}; + +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, Action action); + + // 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_; + + bool extended_on_ = false; + + bool lshift_ = false; + bool rshift_ = false; + + Keycode ScancodeToKeycode(uint8_t scancode); + Action ScancodeToAction(uint8_t scancode); + + bool IsShift() { return lshift_ || rshift_; } +}; + +} // namespace mmth diff --git a/lib/mammoth/ipc/channel.cpp b/lib/mammoth/ipc/channel.cpp new file mode 100644 index 0000000..a014bfd --- /dev/null +++ b/lib/mammoth/ipc/channel.cpp @@ -0,0 +1,60 @@ +#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 new file mode 100644 index 0000000..f290d92 --- /dev/null +++ b/lib/mammoth/ipc/channel.h @@ -0,0 +1,51 @@ +#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 new file mode 100644 index 0000000..33c50cf --- /dev/null +++ b/lib/mammoth/ipc/endpoint_client.cpp @@ -0,0 +1,9 @@ +#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 new file mode 100644 index 0000000..41227b1 --- /dev/null +++ b/lib/mammoth/ipc/endpoint_client.h @@ -0,0 +1,69 @@ +#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 new file mode 100644 index 0000000..823c5f0 --- /dev/null +++ b/lib/mammoth/ipc/endpoint_server.cpp @@ -0,0 +1,45 @@ +#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 new file mode 100644 index 0000000..7ce438d --- /dev/null +++ b/lib/mammoth/ipc/endpoint_server.h @@ -0,0 +1,39 @@ +#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/port_client.cpp b/lib/mammoth/ipc/port_client.cpp index db6c60f..3c9f909 100644 --- a/lib/mammoth/ipc/port_client.cpp +++ b/lib/mammoth/ipc/port_client.cpp @@ -19,14 +19,4 @@ glcr::ErrorCode PortClient::WriteByte(uint8_t byte) { return static_cast( 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)); -} } // namespace mmth diff --git a/lib/mammoth/ipc/port_client.h b/lib/mammoth/ipc/port_client.h index a633357..80571a3 100644 --- a/lib/mammoth/ipc/port_client.h +++ b/lib/mammoth/ipc/port_client.h @@ -10,7 +10,6 @@ namespace mmth { class PortClient { public: PortClient() {} - PortClient(z_cap_t port_cap); static PortClient AdoptPort(z_cap_t port_cap); template @@ -19,8 +18,6 @@ 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_; } @@ -28,6 +25,8 @@ class PortClient { private: z_cap_t port_cap_ = 0; + + PortClient(z_cap_t port_cap); }; template diff --git a/lib/mammoth/ipc/port_server.cpp b/lib/mammoth/ipc/port_server.cpp index f81e3b8..4643143 100644 --- a/lib/mammoth/ipc/port_server.cpp +++ b/lib/mammoth/ipc/port_server.cpp @@ -55,12 +55,4 @@ 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 acc5430..9e46599 100644 --- a/lib/mammoth/ipc/port_server.h +++ b/lib/mammoth/ipc/port_server.h @@ -19,7 +19,6 @@ 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/lib/mammoth/ipc/request_context.h b/lib/mammoth/ipc/request_context.h new file mode 100644 index 0000000..0f8ca96 --- /dev/null +++ b/lib/mammoth/ipc/request_context.h @@ -0,0 +1,32 @@ +#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 new file mode 100644 index 0000000..c7a79e5 --- /dev/null +++ b/lib/mammoth/proc/process.cpp @@ -0,0 +1,147 @@ +#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 MAM_PROC_DEBUG + 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("Map Foreign"); +#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 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 new file mode 100644 index 0000000..c5a0ef4 --- /dev/null +++ b/lib/mammoth/proc/process.h @@ -0,0 +1,12 @@ +#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 new file mode 100644 index 0000000..9b134ed --- /dev/null +++ b/lib/mammoth/sync/mutex.cpp @@ -0,0 +1,31 @@ +#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 new file mode 100644 index 0000000..ee77394 --- /dev/null +++ b/lib/mammoth/sync/mutex.h @@ -0,0 +1,25 @@ +#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/lib/mammoth/util/memory_region.cpp b/lib/mammoth/util/memory_region.cpp index caa9eb9..a4989f2 100644 --- a/lib/mammoth/util/memory_region.cpp +++ b/lib/mammoth/util/memory_region.cpp @@ -71,8 +71,4 @@ 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 37c34b5..97d1cf6 100644 --- a/lib/mammoth/util/memory_region.h +++ b/lib/mammoth/util/memory_region.h @@ -25,15 +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() const { return vaddr_; } - uint64_t size() const { return size_; } + uint64_t vaddr() { return vaddr_; } + uint64_t size() { return size_; } - z_cap_t cap() const { return vmmo_cap_; } + z_cap_t cap() { return vmmo_cap_; } z_cap_t DuplicateCap(); - OwnedMemoryRegion Duplicate(); - bool empty() const { return vmmo_cap_ == 0; } - explicit operator bool() const { return vmmo_cap_ != 0; } + bool empty() { return vmmo_cap_ != 0; } + explicit operator bool() { return vmmo_cap_ != 0; } private: OwnedMemoryRegion(uint64_t vmmo_cap, uint64_t vaddr, uint64_t size) diff --git a/lib/mammoth/util/new.cpp b/lib/mammoth/util/new.cpp index 3357d1e..9e9c2a5 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(0x4000, &mem_cap)); + check(ZMemoryObjectCreate(0x2000, &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 > (0x4000 - sizeof(BuddySlot))) { - crash("Can't allocate greater than four pages", glcr::UNIMPLEMENTED); + if (size > (0x2000 - sizeof(BuddySlot))) { + crash("Can't allocate greater than one page", glcr::UNIMPLEMENTED); } if (free_front_ == nullptr) { AddPage(); diff --git a/lib/yunq/CMakeLists.txt b/lib/yunq/CMakeLists.txt index 2c87371..dea897d 100644 --- a/lib/yunq/CMakeLists.txt +++ b/lib/yunq/CMakeLists.txt @@ -1,5 +1,4 @@ set(yunq_files - message_view.cpp serialize.cpp ) @@ -16,7 +15,3 @@ 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/message_view.cpp b/lib/yunq/message_view.cpp deleted file mode 100644 index 4a3b7df..0000000 --- a/lib/yunq/message_view.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include "message_view.h" - -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(); -} - -uint32_t MessageView::MessageLength() const { - return buffer_.At(offset_ + 8); -} - -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 { - return buffer_.At(field_offset(field_index)); -} - -template <> -glcr::ErrorOr MessageView::ReadField( - uint64_t field_index) const { - ExtensionPointer ptr = - buffer_.At(field_offset(field_index)); - - return buffer_.StringAt(offset_ + ptr.offset, ptr.length); -} - -template <> -glcr::ErrorOr> MessageView::ReadRepeated( - uint64_t field_index) const { - 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; -} - -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 deleted file mode 100644 index 4be5535..0000000 --- a/lib/yunq/message_view.h +++ /dev/null @@ -1,91 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "yunq/yunq.h" - -namespace yunq { - -class MessageView { - public: - MessageView(const glcr::ByteBuffer& buffer, uint64_t offset) - : buffer_(buffer), offset_(offset) {} - - [[nodiscard]] glcr::Status CheckHeader() const; - uint32_t MessageLength() const; - - // TODO: Implement glcr::StatusOr - template - glcr::ErrorOr ReadField(uint64_t field_index) const; - - 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; - - 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_; - - uint64_t field_offset(uint64_t field_index) const { - return offset_ + kHeaderSize + (8 * field_index); - } -}; - -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; - -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); -} - -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.cpp b/lib/yunq/serialize.cpp index 9d58ac8..afaad06 100644 --- a/lib/yunq/serialize.cpp +++ b/lib/yunq/serialize.cpp @@ -3,71 +3,27 @@ namespace yunq { namespace { -const uint32_t kIdentByte = 0x33441122; +const uint64_t kIdentByte = 0x33441122; } // namespace -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 uint64_t& value) { - 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) { - 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); -} - -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)); +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 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 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::WriteRepeatedCapability(uint64_t field_index, - const glcr::Vector& value) {} - } // namespace yunq diff --git a/lib/yunq/serialize.h b/lib/yunq/serialize.h index 170917f..2e90779 100644 --- a/lib/yunq/serialize.h +++ b/lib/yunq/serialize.h @@ -1,126 +1,14 @@ #pragma once #include -#include -#include -#include -#include #include -#include "yunq/yunq.h" - namespace yunq { -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); +[[nodiscard]] glcr::Status CheckHeader(const glcr::ByteBuffer& buffer, + uint64_t offset); - 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); - - 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_; } - - 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 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); - -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); -} - -template -void Serializer::WriteRepeatedMessage(uint64_t field_index, - const glcr::Vector& value) { - uint64_t next_offset = next_extension_; - uint64_t length = value.size(); - - 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); - } - next_offset += msg_length; - } - - ExtensionPointer ptr{ - .offset = (uint32_t)next_extension_, - .length = (uint32_t)length, - }; - - next_extension_ = next_offset; - - buffer_.WriteAt(field_offset(field_index), ptr); -} +void WriteHeader(glcr::ByteBuffer& bytes, uint64_t offset, uint32_t core_size, + uint32_t extension_size); } // namespace yunq diff --git a/lib/yunq/test/CMakeLists.txt b/lib/yunq/test/CMakeLists.txt deleted file mode 100644 index d33b8e2..0000000 --- a/lib/yunq/test/CMakeLists.txt +++ /dev/null @@ -1,44 +0,0 @@ -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 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 - ${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 - ${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 deleted file mode 100644 index 7b11e08..0000000 --- a/lib/yunq/test/example/example.yunq +++ /dev/null @@ -1,27 +0,0 @@ -package ex; - -message Basic { - u64 unsigned_int; - i64 signed_int; - string strn; -} - -message Cap { - capability 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/lib/yunq/test/example/example.yunq.cpp b/lib/yunq/test/example/example.yunq.cpp deleted file mode 100644 index 08cbd0f..0000000 --- a/lib/yunq/test/example/example.yunq.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// 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(); -} -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(); -} -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 deleted file mode 100644 index 83232e5..0000000 --- a/lib/yunq/test/example/example.yunq.h +++ /dev/null @@ -1,129 +0,0 @@ -// 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; -}; -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; -}; -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 deleted file mode 100644 index d22a846..0000000 --- a/lib/yunq/test/yunq_test.cpp +++ /dev/null @@ -1,100 +0,0 @@ -#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); -} - -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"); -} - -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"); -} - -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); -} - -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/lib/yunq/yunq.h b/lib/yunq/yunq.h deleted file mode 100644 index 3a33a8c..0000000 --- a/lib/yunq/yunq.h +++ /dev/null @@ -1,22 +0,0 @@ -#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/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index f7acab6..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "nightly-2025-10-02" -components = ["rustfmt", "rust-analyzer", "clippy", "rust-src"] diff --git a/rust/.cargo/config.toml b/rust/.cargo/config.toml deleted file mode 100644 index c2174c1..0000000 --- a/rust/.cargo/config.toml +++ /dev/null @@ -1,10 +0,0 @@ -[unstable] -build-std-features = ["compiler-builtins-mem"] -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 deleted file mode 100644 index f20f302..0000000 --- a/rust/Cargo.lock +++ /dev/null @@ -1,248 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "autocfg" -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" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "denali" -version = "0.1.0" -dependencies = [ - "bitfield-struct", - "mammoth", - "pci", - "yellowstone-yunq", - "yunq", - "yunqc", -] - -[[package]] -name = "denali_client" -version = "0.1.0" -dependencies = [ - "mammoth", - "yunq", - "yunqc", -] - -[[package]] -name = "ext2" -version = "0.1.0" -dependencies = [ - "denali_client", - "mammoth", - "yellowstone-yunq", -] - -[[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 = "pci" -version = "0.1.0" -dependencies = [ - "bitfield-struct", - "mammoth", -] - -[[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.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" -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 = "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" -dependencies = [ - "mammoth", - "yellowstone-yunq", - "yunq", -] - -[[package]] -name = "teton" -version = "0.1.0" -dependencies = [ - "mammoth", - "victoriafalls", - "voyageurs", - "yellowstone-yunq", -] - -[[package]] -name = "unicode-ident" -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 = "victoriafalls" -version = "0.1.0" -dependencies = [ - "denali_client", - "ext2", - "mammoth", - "yellowstone-yunq", - "yunq", - "yunqc", -] - -[[package]] -name = "voyageurs" -version = "0.1.0" -dependencies = [ - "mammoth", - "yellowstone-yunq", - "yunq", - "yunqc", -] - -[[package]] -name = "yellowstone" -version = "0.1.0" -dependencies = [ - "denali_client", - "mammoth", - "victoriafalls", - "voyageurs", - "yellowstone-yunq", - "yunq", -] - -[[package]] -name = "yellowstone-yunq" -version = "0.1.0" -dependencies = [ - "mammoth", - "yunq", - "yunqc", -] - -[[package]] -name = "yunq" -version = "0.1.0" -dependencies = [ - "mammoth", -] - -[[package]] -name = "yunq-test" -version = "0.1.0" -dependencies = [ - "mammoth", - "yunq", - "yunqc", -] - -[[package]] -name = "yunqc" -version = "0.1.0" -dependencies = [ - "convert_case", - "prettyplease", - "proc-macro2", - "quote", - "syn", -] diff --git a/rust/Cargo.toml b/rust/Cargo.toml deleted file mode 100644 index f1886f6..0000000 --- a/rust/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[workspace] - -members = [ - "lib/client/denali_client", "lib/fs/ext2", - "lib/mammoth", "lib/pci", - "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/client/denali_client/Cargo.toml b/rust/lib/client/denali_client/Cargo.toml deleted file mode 100644 index 625a2d5..0000000 --- a/rust/lib/client/denali_client/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[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 deleted file mode 100644 index f5228b3..0000000 --- a/rust/lib/client/denali_client/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::fs; - -fn main() { - let input_file = "../../../sys/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/disk_reader.rs b/rust/lib/client/denali_client/src/disk_reader.rs deleted file mode 100644 index 0283d29..0000000 --- a/rust/lib/client/denali_client/src/disk_reader.rs +++ /dev/null @@ -1,50 +0,0 @@ -use mammoth::{cap::Capability, zion::ZError}; - -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, 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 * 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/client/denali_client/src/lib.rs b/rust/lib/client/denali_client/src/lib.rs deleted file mode 100644 index 72dfc10..0000000 --- a/rust/lib/client/denali_client/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_std] - -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 deleted file mode 100644 index 17c6f3f..0000000 --- a/rust/lib/fs/ext2/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "ext2" -version = "0.1.0" -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 deleted file mode 100644 index 0997b62..0000000 --- a/rust/lib/fs/ext2/src/ext2_driver.rs +++ /dev/null @@ -1,282 +0,0 @@ -use core::cmp::min; - -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(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 self.inode_table_map[block_group_num].is_none() { - 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()[0..num_dbl_indr]; - - let mut blocks_to_read = Vec::new(); - - 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_block 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(); - - for block in iter { - 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/lib.rs b/rust/lib/fs/ext2/src/lib.rs deleted file mode 100644 index 40d9458..0000000 --- a/rust/lib/fs/ext2/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![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 deleted file mode 100644 index fd1f59b..0000000 --- a/rust/lib/fs/ext2/src/types.rs +++ /dev/null @@ -1,126 +0,0 @@ -/// Superblock structure. -/// https://www.nongnu.org/ext2-doc/ext2.html#superblock -#[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, -} - -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); - -#[allow(dead_code)] -pub const EXT2_FT_FILE: u8 = 0x1; -#[allow(dead_code)] -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/Cargo.toml b/rust/lib/mammoth/Cargo.toml deleted file mode 100644 index b8fd6ef..0000000 --- a/rust/lib/mammoth/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "mammoth" -version = "0.1.0" -edition = "2021" - -[lib] -name = "mammoth" - -[dependencies] -linked_list_allocator = "0.10.5" - -[features] -hosted = [] -default = ["hosted"] diff --git a/rust/lib/mammoth/build.rs b/rust/lib/mammoth/build.rs deleted file mode 100644 index 6797dfb..0000000 --- a/rust/lib/mammoth/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index c26dba3..0000000 --- a/rust/lib/mammoth/src/bindings.rs +++ /dev/null @@ -1,576 +0,0 @@ -/* 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 kZionMsiIrqRegister: u64 = 89; -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 {} -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 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, -} -#[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: *const 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/cap.rs b/rust/lib/mammoth/src/cap.rs deleted file mode 100644 index 29f3d47..0000000 --- a/rust/lib/mammoth/src/cap.rs +++ /dev/null @@ -1,48 +0,0 @@ -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 deleted file mode 100644 index b820bdc..0000000 --- a/rust/lib/mammoth/src/cap_syscall.rs +++ /dev/null @@ -1,30 +0,0 @@ -use core::ffi::c_void; - -use crate::zion::{self, z_cap_t, 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 { - 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 deleted file mode 100644 index 96807d2..0000000 --- a/rust/lib/mammoth/src/elf.rs +++ /dev/null @@ -1,343 +0,0 @@ -use crate::cap::Capability; -use crate::init; -use crate::syscall; -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: &Capability, -) -> 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 mut 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: &Capability) -> 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_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()?; - - let (new_proc_cap, new_as_cap, foreign_port_id) = - syscall::process_spawn(&self_cap, port_cap.duplicate(Capability::PERMS_ALL)?)?; - - 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, - 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, init_cap)?; - - let thread_cap = syscall::thread_create(&new_proc_cap)?; - - syscall::thread_start(&thread_cap, entry_point, foreign_port_id, 0)?; - - 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 deleted file mode 100644 index c190ad1..0000000 --- a/rust/lib/mammoth/src/init.rs +++ /dev/null @@ -1,50 +0,0 @@ -use crate::cap::Capability; -use crate::syscall; -use crate::zion::z_cap_t; - -// From /zion/include/ztypes.h -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 { - let mut bytes: [u8; 8] = [0; 8]; - let mut caps: [u64; 1] = [0]; - - let resp = syscall::port_poll(&init_port, &mut bytes, &mut caps); - if resp.is_err() { - break; - } - - let init_sig = u64::from_le_bytes(bytes); - - 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], - 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 deleted file mode 100644 index 2058a6b..0000000 --- a/rust/lib/mammoth/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_std] -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] - -extern crate alloc; - -#[macro_use] -pub mod macros; - -pub mod cap; -mod cap_syscall; -pub mod elf; -pub mod init; -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/macros.rs b/rust/lib/mammoth/src/macros.rs deleted file mode 100644 index 3fc64c5..0000000 --- a/rust/lib/mammoth/src/macros.rs +++ /dev/null @@ -1,61 +0,0 @@ -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 { - Writer::default() - } -} - -impl From for String { - fn from(value: Writer) -> Self { - String::from_utf8(value.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: $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/mem.rs b/rust/lib/mammoth/src/mem.rs deleted file mode 100644 index 90183ec..0000000 --- a/rust/lib/mammoth/src/mem.rs +++ /dev/null @@ -1,197 +0,0 @@ -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; - -#[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; - 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; - } -} - -pub struct MemoryRegion { - mem_cap: Capability, - 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 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)?; - Ok(Self { - mem_cap, - virt_addr, - size, - }) - } - - 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( - self.virt_addr as *const T, - self.size as usize / size_of::(), - ) - } - } - - pub fn mut_slice(&mut self) -> &mut [T] { - unsafe { - slice::from_raw_parts_mut( - self.virt_addr as *mut T, - self.size as usize / size_of::(), - ) - } - } - - 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) - } -} - -impl AsRef for MemoryRegion { - fn as_ref(&self) -> &T { - unsafe { (self.virt_addr as *const T).as_ref().unwrap() } - } -} - -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. - 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"); - } -} - -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()) - } -} - -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(); - mem_cap.release(); - (vaddr, paddr) -} diff --git a/rust/lib/mammoth/src/port.rs b/rust/lib/mammoth/src/port.rs deleted file mode 100644 index 34bddb1..0000000 --- a/rust/lib/mammoth/src/port.rs +++ /dev/null @@ -1,68 +0,0 @@ -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: Capability, -} - -impl PortServer { - pub fn new() -> Result { - Ok(Self { - port_cap: port_create()?, - }) - } - - pub fn from_cap(port_cap: Capability) -> Self { - Self { port_cap } - } - - pub fn create_client_cap(&self) -> Result { - 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)?; - - 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)) - } - - 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 { - port_cap: Capability, -} - -impl PortClient { - pub fn take_from(port_cap: Capability) -> Self { - Self { port_cap } - } - - #[warn(unused_results)] - 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/sync.rs b/rust/lib/mammoth/src/sync.rs deleted file mode 100644 index f435e32..0000000 --- a/rust/lib/mammoth/src/sync.rs +++ /dev/null @@ -1,81 +0,0 @@ -use core::cell::UnsafeCell; -use core::ops::Deref; -use core::ops::DerefMut; - -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) - } -} - -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<'a, T> Mutex { - pub fn new(data: T) -> Mutex { - Mutex { - cap: syscall::mutex_create().unwrap(), - data: UnsafeCell::new(data), - } - } - - pub fn lock(&'a self) -> MutexGuard<'a, T> { - 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(); - } -} - -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 deleted file mode 100644 index bab76ca..0000000 --- a/rust/lib/mammoth/src/syscall.rs +++ /dev/null @@ -1,473 +0,0 @@ -extern crate alloc; - -use crate::cap::Capability; -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; - -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(()) -} - -#[cfg(feature = "hosted")] -#[panic_handler] -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 = zion::ZProcessExitReq { code: 0x100 }; - let _ = syscall(zion::kZionProcessExit, &req); - unreachable!() -} - -pub fn debug(msg: &str) { - let req = zion::ZDebugReq { - message: msg.as_ptr() as *const i8, - size: msg.len() as u64, - }; - syscall(zion::kZionDebug, &req).expect("Failed to write"); -} - -pub fn process_spawn( - 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; - - syscall( - zion::kZionProcessSpawn, - &zion::ZProcessSpawnReq { - 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(( - Capability::take(new_proc_cap), - Capability::take(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: &Capability) -> Result { - let mut err_code = 0; - syscall( - zion::kZionProcessWait, - &zion::ZProcessWaitReq { - proc_cap: proc_cap.raw(), - exit_code: &mut err_code, - }, - )?; - Ok(err_code) -} - -pub fn thread_create(proc_cap: &Capability) -> Result { - let mut cap = 0; - syscall( - zion::kZionThreadCreate, - &zion::ZThreadCreateReq { - proc_cap: proc_cap.raw(), - thread_cap: &mut 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: &Capability, - entry: u64, - arg1: u64, - arg2: u64, -) -> Result<(), ZError> { - syscall( - zion::kZionThreadStart, - &zion::ZThreadStartReq { - thread_cap: thread_cap.raw(), - entry, - arg1, - arg2, - }, - ) -} - -pub fn thread_wait(thread_cap: &Capability) -> Result<(), ZError> { - syscall( - zion::kZionThreadWait, - &zion::ZThreadWaitReq { - thread_cap: thread_cap.raw(), - }, - ) -} - -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(Capability::take(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(Capability::take(vmmo_cap)) -} - -pub fn memory_object_contiguous_physical(size: u64) -> 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( - zion::kZionMemoryObjectInspect, - &zion::ZMemoryObjectInspectReq { - vmmo_cap: mem_cap.raw(), - size: &mut mem_size, - }, - )?; - 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. - let vmas_req = zion::ZAddressSpaceMapReq { - vmmo_cap: vmmo_cap.raw(), - 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 address_space_map_external( - vmas_cap: &Capability, - vmmo_cap: &Capability, - vaddr: u64, -) -> Result<(), ZError> { - let mut vaddr_throw: u64 = 0; - let vmas_req = zion::ZAddressSpaceMapReq { - vmas_cap: vmas_cap.raw(), - vmmo_cap: vmmo_cap.raw(), - 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, - &zion::ZAddressSpaceUnmapReq { - vmas_cap: unsafe { crate::init::SELF_VMAS_CAP }, - lower_addr, - upper_addr, - }, - ) -} - -pub fn port_create() -> Result { - let mut port_cap = 0; - syscall( - zion::kZionPortCreate, - &zion::ZPortCreateReq { - port_cap: &mut port_cap, - }, - )?; - Ok(Capability::take(port_cap)) -} - -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.raw(), - 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: &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; - syscall( - zion::kZionPortRecv, - &zion::ZPortRecvReq { - 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(), - num_caps: &mut num_caps as *mut u64, - }, - )?; - Ok((num_bytes, num_caps)) -} - -pub fn port_poll( - 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.raw(), - 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)) -} - -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::kZionMsiIrqRegister, - &zion::ZMsiIrqRegisterReq { - irq_num: &mut irq_num as *mut u64, - port_cap: &mut port_cap, - }, - )?; - Ok((Capability::take(port_cap), irq_num)) -} - -pub fn endpoint_create() -> Result { - let mut endpoint_cap: z_cap_t = 0; - syscall( - zion::kZionEndpointCreate, - &zion::ZEndpointCreateReq { - endpoint_cap: &mut endpoint_cap, - }, - )?; - Ok(Capability::take(endpoint_cap)) -} - -pub fn endpoint_send( - endpoint_cap: &Capability, - 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: endpoint_cap.raw(), - data: bytes.as_ptr() as *const c_void, - num_bytes: bytes.len() as u64, - reply_port_cap: &mut reply_port_cap, - }; - - syscall(zion::kZionEndpointSend, &send_req)?; - - Ok(Capability::take(reply_port_cap)) -} - -pub fn endpoint_recv( - endpoint_cap: &Capability, - bytes: &mut [u8], - caps: &mut [z_cap_t], -) -> 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.raw(), - 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, Capability::take(reply_port_cap))) -} - -pub fn reply_port_send( - reply_port_cap: Capability, - bytes: &[u8], - caps: &[z_cap_t], -) -> Result<(), ZError> { - syscall( - zion::kZionReplyPortSend, - &zion::ZReplyPortSendReq { - 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(), - num_caps: caps.len() as u64, - }, - ) -} - -pub fn reply_port_recv( - 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.raw(), - caps: caps.as_mut_ptr(), - num_caps: &mut num_caps, - data: bytes.as_mut_ptr() as *mut c_void, - num_bytes: &mut num_bytes, - }; - - syscall(zion::kZionReplyPortRecv, &recv_req)?; - - 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( - 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/mammoth/src/task/mod.rs b/rust/lib/mammoth/src/task/mod.rs deleted file mode 100644 index ec25afa..0000000 --- a/rust/lib/mammoth/src/task/mod.rs +++ /dev/null @@ -1,145 +0,0 @@ -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, - future: Pin + Send>>, -} - -impl Task { - pub fn new(future: impl Future + Sync + Send + '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 create_waker(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(); - } -} - -#[derive(Default)] -pub struct Executor { - tasks: Arc>>, - // TODO: Consider a better datastructure for this. - task_queue: Arc>>, - waker_cache: BTreeMap, -} - -impl Executor { - pub fn new() -> Executor { - Executor::default() - } - - pub fn spawn(&mut 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); - } - - fn run_ready_tasks(&mut self) { - while let Some(task_id) = self.task_queue.lock().pop_front() { - let mut tasks = self.tasks.lock(); - let task = tasks.get_mut(&task_id).unwrap(); - let waker = self - .waker_cache - .entry(task_id) - .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(()) => { - 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(10).unwrap(); - } - } - - pub fn new_spawner(&self) -> Spawner { - Spawner::new(self.tasks.clone(), self.task_queue.clone()) - } -} - -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/mammoth/src/thread.rs b/rust/lib/mammoth/src/thread.rs deleted file mode 100644 index aeb4b27..0000000 --- a/rust/lib/mammoth/src/thread.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::cap::Capability; -use crate::syscall; -use crate::zion; - -use alloc::boxed::Box; -use core::ffi::c_void; - -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 usize as u64, raw_main as u64, 0).unwrap(); - - JoinHandle { cap } -} diff --git a/rust/lib/mammoth/src/zion.rs b/rust/lib/mammoth/src/zion.rs deleted file mode 100644 index 9aa3a69..0000000 --- a/rust/lib/mammoth/src/zion.rs +++ /dev/null @@ -1,75 +0,0 @@ -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::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", - 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/pci/Cargo.toml b/rust/lib/pci/Cargo.toml deleted file mode 100644 index f47f8b1..0000000 --- a/rust/lib/pci/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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 deleted file mode 100644 index e65e3da..0000000 --- a/rust/lib/pci/src/device.rs +++ /dev/null @@ -1,97 +0,0 @@ -use alloc::vec::Vec; -use mammoth::{cap::Capability, mem::MemoryRegion, syscall, zion::ZError}; - -use crate::header::{ - PciCapabilityPointer, PciDeviceHeader, PciHeaderType, PciMsiCapability, get_header_type, -}; - -pub struct PciDevice { - memory_region: MemoryRegion, -} - -impl PciDevice { - pub fn from(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() - }; - - let control = msi_cap.msi_control; - 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) - } -} diff --git a/rust/lib/pci/src/header.rs b/rust/lib/pci/src/header.rs deleted file mode 100644 index ff2a144..0000000 --- a/rust/lib/pci/src/header.rs +++ /dev/null @@ -1,180 +0,0 @@ -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 deleted file mode 100644 index 44e141a..0000000 --- a/rust/lib/pci/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![no_std] - -extern crate alloc; - -mod device; -mod header; - -pub use device::PciDevice; diff --git a/rust/lib/voyageurs/Cargo.toml b/rust/lib/voyageurs/Cargo.toml deleted file mode 100644 index e011e0c..0000000 --- a/rust/lib/voyageurs/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "voyageurs" -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/lib/voyageurs/build.rs b/rust/lib/voyageurs/build.rs deleted file mode 100644 index 52b5dfc..0000000 --- a/rust/lib/voyageurs/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index e92646c..0000000 --- a/rust/lib/voyageurs/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![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 deleted file mode 100644 index 89e40b6..0000000 --- a/rust/lib/voyageurs/src/listener.rs +++ /dev/null @@ -1,226 +0,0 @@ -use alloc::string::ToString; -use mammoth::cap::Capability; -use mammoth::port::PortServer; -use mammoth::thread; - -#[repr(u8)] -#[allow(dead_code)] -#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] -enum Keycode { - Unknown = 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::Unknown, - } - } -} - -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 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/lib/yellowstone/Cargo.toml b/rust/lib/yellowstone/Cargo.toml deleted file mode 100644 index 74c80c4..0000000 --- a/rust/lib/yellowstone/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "yellowstone-yunq" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../mammoth" } -yunq = {path = "../yunq"} - -[build-dependencies] -yunqc = {path = "../../../yunq/rust"} - diff --git a/rust/lib/yellowstone/build.rs b/rust/lib/yellowstone/build.rs deleted file mode 100644 index 24472ac..0000000 --- a/rust/lib/yellowstone/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -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"; - fs::write(out, code).expect("Failed to write generated code."); -} diff --git a/rust/lib/yellowstone/src/lib.rs b/rust/lib/yellowstone/src/lib.rs deleted file mode 100644 index ffdc267..0000000 --- a/rust/lib/yellowstone/src/lib.rs +++ /dev/null @@ -1,21 +0,0 @@ -#![no_std] - -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 { - #[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/Cargo.toml b/rust/lib/yunq-test/Cargo.toml deleted file mode 100644 index 4a4591d..0000000 --- a/rust/lib/yunq-test/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "yunq-test" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../mammoth", default-features = false} -yunq = {path = "../yunq", default-features = false} - -[build-dependencies] -yunqc = {path = "../../../yunq/rust"} - diff --git a/rust/lib/yunq-test/build.rs b/rust/lib/yunq-test/build.rs deleted file mode 100644 index ef1bf8d..0000000 --- a/rust/lib/yunq-test/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -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 deleted file mode 100644 index 9af3d55..0000000 --- a/rust/lib/yunq-test/src/lib.rs +++ /dev/null @@ -1,140 +0,0 @@ -#![no_std] - -include!(concat!(env!("OUT_DIR"), "/yunq.rs")); - -#[cfg(test)] -mod tests { - use super::*; - - extern crate std; - use std::println; - 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(()) - } - - #[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)?; - - 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/Cargo.toml b/rust/lib/yunq/Cargo.toml deleted file mode 100644 index d5c3db0..0000000 --- a/rust/lib/yunq/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "yunq" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = {path = "../mammoth", default-features = false} - -[features] -default = ["hosted"] -hosted = ["mammoth/hosted"] diff --git a/rust/lib/yunq/src/buffer.rs b/rust/lib/yunq/src/buffer.rs deleted file mode 100644 index 7966337..0000000 --- a/rust/lib/yunq/src/buffer.rs +++ /dev/null @@ -1,67 +0,0 @@ -use alloc::boxed::Box; -use mammoth::zion::ZError; - -pub struct ByteBuffer { - buffer: Box<[u8; N]>, -} - -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 - } - - pub fn slice(&self, len: usize) -> &[u8] { - &self.buffer[..len] - } - - pub fn mut_slice(&mut self) -> &mut [u8] { - &mut self.buffer[..] - } - - 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); - } - 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 deleted file mode 100644 index c4c45b8..0000000 --- a/rust/lib/yunq/src/client.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::buffer::ByteBuffer; -use crate::message::YunqMessage; -use alloc::vec::Vec; -use mammoth::cap::Capability; -use mammoth::zion::ZError; - -pub fn call_endpoint( - request_id: u64, - req: &Req, - byte_buffer: &mut ByteBuffer, - endpoint_cap: &Capability, -) -> Result { - let mut cap_buffer = Vec::new(); - let length = req.serialize_as_request(request_id, byte_buffer, &mut cap_buffer)?; - - let reply_port_cap = mammoth::syscall::endpoint_send( - endpoint_cap, - byte_buffer.slice(16 + length), - cap_buffer.as_slice(), - )?; - - // FIXME: Add a way to zero out the byte buffer. - - cap_buffer = vec![0; 10]; - mammoth::syscall::reply_port_recv( - reply_port_cap, - byte_buffer.mut_slice(), - cap_buffer.as_mut_slice(), - )?; - - let resp_code: u64 = byte_buffer.at(8)?; - - if resp_code != 0 { - return Err(ZError::from(resp_code)); - } - - Resp::parse_from_request(byte_buffer, &cap_buffer) -} diff --git a/rust/lib/yunq/src/lib.rs b/rust/lib/yunq/src/lib.rs deleted file mode 100644 index 93166ac..0000000 --- a/rust/lib/yunq/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![no_std] - -#[macro_use] -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 deleted file mode 100644 index 568916f..0000000 --- a/rust/lib/yunq/src/message.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::buffer::ByteBuffer; -use alloc::vec::Vec; -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 -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 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: &[z_cap_t], -) -> 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: &[T], -) -> Result { - for (i, val) in data.iter().enumerate() { - buf.write_at(offset + (i * size_of::()), val)?; - } - Ok(offset + size_of_val(data)) -} - -pub fn serialize_repeated_message( - buf: &mut ByteBuffer, - mut offset: usize, - data: &[T], - 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"); - 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, - offset: usize, - caps: &[z_cap_t], - ) -> Result - where - Self: Sized; - - fn parse_from_request( - buf: &ByteBuffer, - caps: &[z_cap_t], - ) -> Result - where - Self: Sized, - { - if buf.at::(0)? != SENTINEL { - return Err(ZError::INVALID_RESPONSE); - } - - 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)?; - - let length = self.serialize(buf, 16, caps)?; - - buf.write_at(4, (16 + length) as u32)?; - - Ok(length + 16) - } -} - -pub struct Empty {} - -impl YunqMessage for Empty { - fn parse( - _buf: &ByteBuffer, - _offset: usize, - _caps: &[z_cap_t], - ) -> Result - where - Self: Sized, - { - Ok(Self {}) - } - - fn serialize( - &self, - _buf: &mut ByteBuffer, - _offset: usize, - _caps: &mut Vec, - ) -> Result { - Ok(0) - } -} diff --git a/rust/lib/yunq/src/server.rs b/rust/lib/yunq/src/server.rs deleted file mode 100644 index cdfe418..0000000 --- a/rust/lib/yunq/src/server.rs +++ /dev/null @@ -1,144 +0,0 @@ -use core::future::Future; - -use crate::buffer::ByteBuffer; -use alloc::sync::Arc; -use alloc::vec::Vec; -use mammoth::cap::Capability; -use mammoth::syscall; -use mammoth::task::Spawner; -use mammoth::task::Task; -use mammoth::thread; -use mammoth::thread::JoinHandle; -use mammoth::zion::z_cap_t; -use mammoth::zion::ZError; - -pub trait YunqServer { - fn server_loop(&mut 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) -> &Capability; - - fn create_client_cap(&self) -> Result { - self.endpoint_cap() - .duplicate(!mammoth::zion::kZionPerm_Read) - } - fn handle_request( - &mut self, - method_number: u64, - byte_buffer: &mut ByteBuffer<1024>, - 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()) -} - -pub trait AsyncYunqServer -where - Self: Send + Sync + 'static, -{ - fn server_loop(self: Arc, spawner: Spawner) { - 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(); - spawner.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 + Send { - 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 + Send; -} - -pub fn spawn_async_server_thread(server: Arc, spawner: Spawner) -> JoinHandle -where - T: AsyncYunqServer + Send + Sync + 'static, -{ - thread::spawn(move || { - server.server_loop(spawner); - }) -} diff --git a/rust/sys/denali/Cargo.toml b/rust/sys/denali/Cargo.toml deleted file mode 100644 index ad19780..0000000 --- a/rust/sys/denali/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "denali" -version = "0.1.0" -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" } - -[[bin]] -name = "denali" - -[build-dependencies] -yunqc = { path = "../../../yunq/rust" } diff --git a/rust/sys/denali/build.rs b/rust/sys/denali/build.rs deleted file mode 100644 index a57b29c..0000000 --- a/rust/sys/denali/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::fs; - -fn main() { - let input_file = "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/sys/denali/src/ahci/ahci_command.rs b/rust/sys/denali/src/ahci/ahci_command.rs deleted file mode 100644 index 5870587..0000000 --- a/rust/sys/denali/src/ahci/ahci_command.rs +++ /dev/null @@ -1,264 +0,0 @@ -#[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/command.rs b/rust/sys/denali/src/ahci/command.rs deleted file mode 100644 index c827bb1..0000000 --- a/rust/sys/denali/src/ahci/command.rs +++ /dev/null @@ -1,112 +0,0 @@ -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, - 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 deleted file mode 100644 index 2a402f0..0000000 --- a/rust/sys/denali/src/ahci/controller.rs +++ /dev/null @@ -1,166 +0,0 @@ -use alloc::sync::Arc; -use mammoth::{ - cap::Capability, - mem::{self, MemoryRegion}, - sync::Mutex, - thread, - zion::ZError, -}; -use pci::PciDevice; - -use crate::ahci::{ - port::{AhciDeviceDetection, AhciInterfacePowerManagement}, - Command, -}; - -use super::{hba::AhciHba, port::AhciPortHba, port_controller::PortController}; - -pub struct AhciController { - pci_device: Mutex, - hba: Mutex<&'static mut AhciHba>, - ports: [Option; 32], - hba_vaddr: u64, -} - -impl AhciController { - pub fn new(pci_memory: Capability) -> Self { - let pci_device = PciDevice::from_cap(pci_memory).unwrap(); - - 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_device: Mutex::new(pci_device), - hba: Mutex::new(hba), - ports: [const { None }; 32], - hba_vaddr, - }; - controller.init(); - controller - } - - 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; - } - - 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 register_irq(&self) -> Result { - self.pci_device.lock().register_msi() - } - - 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 (hba.interrupt_status.read() & int_offset) == int_offset { - if let Some(port) = &self.ports[i as usize] { - port.handle_interrupt(); - hba.interrupt_status.update(|is| { - *is &= !int_offset; - }); - } - } - } - } - - pub async fn identify_ports(&self) -> Result<(), ZError> { - for port in self.ports.iter().flatten() { - let sig = port.get_signature(); - if sig == 0x101 { - let mut command = Command::identify()?; - mammoth::debug!("IDENT!"); - port.issue_command(&command)?.await; - 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 { - 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); - - // 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); - } - } - 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 { - let irq_thread = move || { - 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); - }); - loop { - irq_port.recv_null().unwrap(); - controller.handle_irq(); - } - }; - thread::spawn(irq_thread) -} - -pub async fn identify_ports(controller: Arc) { - controller.identify_ports().await.unwrap(); -} diff --git a/rust/sys/denali/src/ahci/hba.rs b/rust/sys/denali/src/ahci/hba.rs deleted file mode 100644 index 2cfdc63..0000000 --- a/rust/sys/denali/src/ahci/hba.rs +++ /dev/null @@ -1,181 +0,0 @@ -use bitfield_struct::bitfield; -use mammoth::mem::Volatile; - -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: 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(); - } -} diff --git a/rust/sys/denali/src/ahci/mod.rs b/rust/sys/denali/src/ahci/mod.rs deleted file mode 100644 index f98bcf2..0000000 --- a/rust/sys/denali/src/ahci/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -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; diff --git a/rust/sys/denali/src/ahci/port.rs b/rust/sys/denali/src/ahci/port.rs deleted file mode 100644 index e32abc5..0000000 --- a/rust/sys/denali/src/ahci/port.rs +++ /dev/null @@ -1,435 +0,0 @@ -use bitfield_struct::bitfield; -use mammoth::mem::Volatile; - -#[bitfield(u32)] -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)] - pub unknown_fis_interrupt: bool, - pub descriptor_prossed: bool, - #[bits(access = RO)] - pub port_connect_change_status: bool, - pub device_mechanical_presence_status: bool, - - #[bits(14)] - __: u32, - - #[bits(access = RO)] - pub phy_rdy_change_status: bool, - pub incorrect_port_multiplier_status: bool, - pub overflow_status: bool, - - __: 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)] -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, - - pub phy_rdy_change_enable: bool, - pub incorrect_port_multiplier_enable: bool, - pub overflow_enable: bool, - - __: 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)] -#[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)] -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)] - pub current_command_slot: u8, - - #[bits(access = RO)] - pub mechanical_presence_switch_state: bool, - #[bits(access = RO)] - pub fis_receive_running: bool, - #[bits(access = RO)] - pub command_list_running: bool, - #[bits(access = RO)] - pub cold_presence_state: bool, - pub port_multipler_attached: bool, - #[bits(access = RO)] - pub hot_plug_capable_port: bool, - #[bits(access = RO)] - pub mechanical_presence_switch_attached_to_port: bool, - #[bits(access = RO)] - pub cold_presence_detection: bool, - #[bits(access = RO)] - pub external_sata_port: bool, - #[bits(access = RO)] - 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)] - pub interface_communication_control: InterfaceCommunicationControl, -} - -#[bitfield(u32)] -pub 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(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub 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(Copy, Clone, Debug)] -#[repr(u8)] -pub 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(Copy, Clone, Debug, PartialEq)] -#[repr(u8)] -pub 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)] -#[derive(PartialEq)] -pub struct AhciSataStatus { - #[bits(4, access = RO)] - pub device_detection: AhciDeviceDetection, - - #[bits(4, access = RO)] - pub current_interface_speed: AhciCurrentInterfaceSpeed, - - #[bits(4, access = RO)] - pub 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)] -pub 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)] -pub struct AhciSataError { - pub recovered_data_integrity_error: bool, - pub recovered_communications_error: bool, - - #[bits(6)] - __: u8, - - 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, - - pub phy_ready_change: bool, - pub phy_internal_error: bool, - pub comm_wake: bool, - pub decode_error: bool, - __: 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)] -pub 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)] -pub 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, -} - -#[derive(Debug)] -#[repr(C)] -pub struct AhciPortHba { - 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); - } -} diff --git a/rust/sys/denali/src/ahci/port_controller.rs b/rust/sys/denali/src/ahci/port_controller.rs deleted file mode 100644 index 42dfa00..0000000 --- a/rust/sys/denali/src/ahci/port_controller.rs +++ /dev/null @@ -1,159 +0,0 @@ -use core::array; -use core::ops::Deref; - -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}, - command::{CommandFuture, CommandStatus}, - port::AhciPortHba, - Command, -}; - -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, 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))); - - 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/bin/denali.rs b/rust/sys/denali/src/bin/denali.rs deleted file mode 100644 index 0e831d3..0000000 --- a/rust/sys/denali/src/bin/denali.rs +++ /dev/null @@ -1,67 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -use alloc::sync::Arc; -use mammoth::{ - define_entry, - sync::Mutex, - task::{Executor, Task}, - zion::z_err_t, -}; - -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!(); - -#[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 = Arc::new(AhciController::new(mammoth::cap::Capability::take( - ahci_info.ahci_region, - ))); - - let executor = Arc::new(Mutex::new(Executor::new())); - - executor - .clone() - .lock() - .spawn(Task::new(identify_ports(ahci_controller.clone()))); - - let thread = spawn_irq_thread(ahci_controller.clone()); - - let denali_server = - Arc::new(AsyncDenaliServer::new(DenaliServerImpl::new(ahci_controller.clone())).unwrap()); - - 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(); - - 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 deleted file mode 100644 index 511ff0f..0000000 --- a/rust/sys/denali/src/denali_server.rs +++ /dev/null @@ -1,61 +0,0 @@ -use alloc::sync::Arc; -use mammoth::{syscall, 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 { - 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(), - }) - } -} diff --git a/rust/sys/denali/src/lib.rs b/rust/sys/denali/src/lib.rs deleted file mode 100644 index 0d06e8b..0000000 --- a/rust/sys/denali/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![no_std] - -use core::include; - -include!(concat!(env!("OUT_DIR"), "/yunq.rs")); - -pub mod ahci; -pub mod denali_server; diff --git a/rust/sys/teton/Cargo.toml b/rust/sys/teton/Cargo.toml deleted file mode 100644 index baa787a..0000000 --- a/rust/sys/teton/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -name = "teton" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../../lib/mammoth" } -victoriafalls = { path = "../victoriafalls" } -voyageurs = { path = "../../lib/voyageurs" } -yellowstone-yunq = { path = "../../lib/yellowstone" } diff --git a/rust/sys/teton/src/console.rs b/rust/sys/teton/src/console.rs deleted file mode 100644 index 2e282dc..0000000 --- a/rust/sys/teton/src/console.rs +++ /dev/null @@ -1,36 +0,0 @@ -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(&mut self, chr: char, row: u32, col: u32) { - if row >= self.rows() { - panic!("Write at row {}, max is {}", row, self.rows()) - } - 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, - row * (self.psf.height() + 1), - col * (self.psf.width() + 1), - ); - } - - pub fn cols(&self) -> u32 { - self.framebuffer.width() / (self.psf.width() + 1) - } - - pub 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 deleted file mode 100644 index f083367..0000000 --- a/rust/sys/teton/src/framebuffer.rs +++ /dev/null @@ -1,47 +0,0 @@ -use mammoth::{mem::MemoryRegion, zion::ZError}; -use yellowstone_yunq::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(&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(&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 { - 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); - } - } - } - } - - 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 deleted file mode 100644 index 982beb7..0000000 --- a/rust/sys/teton/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -mod console; -mod framebuffer; -mod psf; -mod terminal; - -use mammoth::{debug, define_entry, zion::z_err_t}; -use voyageurs::listener; - -define_entry!(); - -#[no_mangle] -extern "C" fn main() -> z_err_t { - debug!("Teton Starting"); - - let yellowstone = yellowstone_yunq::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); - let terminal = terminal::Terminal::new(console); - - let kb_listener = listener::spawn_keyboard_listener(terminal); - - 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 deleted file mode 100644 index 3f99f65..0000000 --- a/rust/sys/teton/src/psf.rs +++ /dev/null @@ -1,78 +0,0 @@ -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..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 deleted file mode 100644 index f8a9e0f..0000000 --- a/rust/sys/teton/src/terminal.rs +++ /dev/null @@ -1,129 +0,0 @@ -use core::str::Split; - -use crate::console::Console; -use alloc::{ - format, - string::{String, ToString}, -}; -use victoriafalls::dir; -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) { - 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 { - 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) { - for (col, c) in line.chars().enumerate() { - self.console.write_char(c, self.row, col as u32); - } - - 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, 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); - } - } - } - } - "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("Failed 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/sys/victoriafalls/Cargo.toml b/rust/sys/victoriafalls/Cargo.toml deleted file mode 100644 index 5464a78..0000000 --- a/rust/sys/victoriafalls/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "victoriafalls" -version = "0.1.0" -edition = "2021" - -[dependencies] -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" } - -[[bin]] -name = "victoriafalls" diff --git a/rust/sys/victoriafalls/build.rs b/rust/sys/victoriafalls/build.rs deleted file mode 100644 index ad812f3..0000000 --- a/rust/sys/victoriafalls/build.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::fs; - -fn main() { - let input_file = "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/sys/victoriafalls/src/bin/victoriafalls.rs b/rust/sys/victoriafalls/src/bin/victoriafalls.rs deleted file mode 100644 index 770b238..0000000 --- a/rust/sys/victoriafalls/src/bin/victoriafalls.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![no_std] -#![no_main] - -use ext2::Ext2Driver; -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!(); - -#[no_mangle] -extern "C" fn main() -> z_err_t { - let yellowstone = yellowstone_yunq::from_init_endpoint(); - - let denali_info = yellowstone.get_denali().unwrap(); - - 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/dir.rs b/rust/sys/victoriafalls/src/dir.rs deleted file mode 100644 index fb6efeb..0000000 --- a/rust/sys/victoriafalls/src/dir.rs +++ /dev/null @@ -1,27 +0,0 @@ -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/sys/victoriafalls/src/file.rs b/rust/sys/victoriafalls/src/file.rs deleted file mode 100644 index feb8eec..0000000 --- a/rust/sys/victoriafalls/src/file.rs +++ /dev/null @@ -1,30 +0,0 @@ -use crate::OpenFileRequest; -use alloc::string::ToString; -use mammoth::{cap::Capability, mem::MemoryRegion, zion::ZError}; - -pub struct File { - memory: MemoryRegion, - len: usize, -} - -impl File { - pub fn open(path: &str) -> Result { - let vfs = crate::get_client(); - let resp = vfs.open_file(&OpenFileRequest { - path: path.to_string(), - })?; - - 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.len] - } - - pub fn memory(&self) -> &MemoryRegion { - &self.memory - } -} diff --git a/rust/sys/victoriafalls/src/lib.rs b/rust/sys/victoriafalls/src/lib.rs deleted file mode 100644 index a213a8b..0000000 --- a/rust/sys/victoriafalls/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![no_std] - -use core::include; - -include!(concat!(env!("OUT_DIR"), "/yunq.rs")); - -pub mod dir; -pub mod file; -pub mod server; - -static mut VFS_CLIENT: Option = None; - -fn get_client() -> &'static mut VFSClient { - unsafe { - #[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(), - }) - .expect("Failed to get VFS endpoint"); - - VFS_CLIENT = Some(VFSClient::new(Capability::take(endpoint_cap.endpoint))); - } - #[allow(static_mut_refs)] - VFS_CLIENT.as_mut().unwrap() - } -} - -pub fn set_client(client: VFSClient) { - unsafe { VFS_CLIENT = Some(client) }; -} diff --git a/rust/sys/victoriafalls/src/server.rs b/rust/sys/victoriafalls/src/server.rs deleted file mode 100644 index a901ea9..0000000 --- a/rust/sys/victoriafalls/src/server.rs +++ /dev/null @@ -1,75 +0,0 @@ -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. - - for path_token in tokens { - 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. - - for path_token in tokens { - 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/rust/sys/yellowstone/Cargo.toml b/rust/sys/yellowstone/Cargo.toml deleted file mode 100644 index 6a89d4d..0000000 --- a/rust/sys/yellowstone/Cargo.toml +++ /dev/null @@ -1,12 +0,0 @@ -[package] -name = "yellowstone" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../../lib/mammoth" } -denali_client = { path = "../../lib/client/denali_client" } -victoriafalls = { path = "../victoriafalls" } -voyageurs = { path = "../../lib/voyageurs" } -yellowstone-yunq = { path = "../../lib/yellowstone" } -yunq = { path = "../../lib/yunq" } diff --git a/rust/sys/yellowstone/src/gpt.rs b/rust/sys/yellowstone/src/gpt.rs deleted file mode 100644 index 87bf3ce..0000000 --- a/rust/sys/yellowstone/src/gpt.rs +++ /dev/null @@ -1,138 +0,0 @@ -use denali_client::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_client::ReadRequest { - device_id: 0, - block: denali_client::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_client::ReadRequest { - device_id: 0, - block: denali_client::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 deleted file mode 100644 index dbe8c2e..0000000 --- a/rust/sys/yellowstone/src/main.rs +++ /dev/null @@ -1,98 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -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::{kZionPerm_All, z_cap_t, z_err_t, ZError}, -}; -use yellowstone_yunq::YellowstoneServer; -use yunq::server::{spawn_server_thread, YunqServer}; - -mod gpt; -mod pci; -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))?; - spawn_from_mem_region(®ion, server_cap)?; - Ok(()) -} - -#[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"), - ); - let handler = server::YellowstoneServerImpl::new(context.clone()); - let server = YellowstoneServer::new(handler).expect("Couldn't create yellowstone 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 }, - client_cap.duplicate(kZionPerm_All).unwrap(), - ) - .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 }, - client_cap.duplicate(kZionPerm_All).unwrap(), - ) - .expect("Failed to spawn victoriafalls"); - - context.wait("victoriafalls").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 { - // 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(), - client_cap.duplicate(kZionPerm_All).unwrap(), - ) - .unwrap(); - } - - server_thread.join().expect("Failed to join thread"); - 0 -} diff --git a/rust/sys/yellowstone/src/pci.rs b/rust/sys/yellowstone/src/pci.rs deleted file mode 100644 index e421f74..0000000 --- a/rust/sys/yellowstone/src/pci.rs +++ /dev/null @@ -1,131 +0,0 @@ -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), - } - } - - 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 { - 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 deleted file mode 100644 index a6d5fa1..0000000 --- a/rust/sys/yellowstone/src/server.rs +++ /dev/null @@ -1,138 +0,0 @@ -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::{ - AhciInfo, DenaliInfo, Endpoint, FramebufferInfo, GetEndpointRequest, RegisterEndpointRequest, - XhciInfo, YellowstoneServerHandler, -}; - -use crate::pci::PciReader; - -pub struct YellowstoneServerContext { - registration_semaphore: mammoth::sync::Semaphore, - pci_reader: PciReader, - framebuffer_info_region: MemoryRegion, - service_map: Mutex>, -} - -impl YellowstoneServerContext { - 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 { - registration_semaphore: mammoth::sync::Semaphore::new()?, - pci_reader: PciReader::new(pci_region), - framebuffer_info_region: fb_region, - service_map: Mutex::new(BTreeMap::new()), - }) - } - - pub fn wait(&self, service: &str) -> Result<(), ZError> { - loop { - if self.service_map.lock().get(service).is_some() { - return Ok(()); - } - self.registration_semaphore.wait().unwrap(); - } - } -} - -pub struct YellowstoneServerImpl { - context: Arc, -} - -impl YellowstoneServerImpl { - pub fn new(context: Arc) -> Self { - Self { context } - } -} - -impl YellowstoneServerHandler for YellowstoneServerImpl { - fn register_endpoint(&mut self, req: RegisterEndpointRequest) -> Result<(), ZError> { - if req.endpoint_name == "victoriafalls" { - victoriafalls::set_client(VFSClient::new( - Capability::take_copy(req.endpoint_capability).unwrap(), - )); - } - - self.context - .service_map - .lock() - .insert(req.endpoint_name, Capability::take(req.endpoint_capability)); - - self.context.registration_semaphore.signal()?; - Ok(()) - } - - fn get_endpoint(&mut self, req: GetEndpointRequest) -> Result { - match self.context.service_map.lock().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 { - Ok(AhciInfo { - ahci_region: self.context.pci_reader.get_ahci_region()?.release(), - region_length: 0x1000, - }) - } - - fn get_xhci_info(&mut self) -> Result { - Ok(XhciInfo { - xhci_region: self.context.pci_reader.get_xhci_region()?.release(), - region_length: 0x1000, - }) - } - - fn get_framebuffer_info(&mut self) -> Result { - Ok(self.context.framebuffer_info()) - } - - fn get_denali(&mut self) -> Result { - match self.context.service_map.lock().get("denali") { - Some(ep_cap) => crate::gpt::read_gpt(denali_client::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) - } - } - } -} diff --git a/rust/usr/testbed/Cargo.toml b/rust/usr/testbed/Cargo.toml deleted file mode 100644 index aff88d2..0000000 --- a/rust/usr/testbed/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "testbed" -version = "0.1.0" -edition = "2021" - -[dependencies] -mammoth = { path = "../../lib/mammoth" } -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 deleted file mode 100644 index 2ea144b..0000000 --- a/rust/usr/testbed/src/main.rs +++ /dev/null @@ -1,75 +0,0 @@ -#![no_std] -#![no_main] - -extern crate alloc; - -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; - -define_entry!(); - -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!"); - - let yellowstone = yellowstone_yunq::from_init_endpoint(); - - debug!("Get endpoint"); - - let endpoint = yellowstone - .get_endpoint(&GetEndpointRequest { - endpoint_name: "denali".to_string(), - }) - .expect("Failed to get endpoint"); - - 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 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."); - - let mut executor = Executor::new(); - - executor.spawn(Task::new(test_async())); - - executor.run(); - - 0 -} diff --git a/rust/x86_64-acadia-os.json b/rust/x86_64-acadia-os.json deleted file mode 100644 index 1060335..0000000 --- a/rust/x86_64-acadia-os.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "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" -} diff --git a/scripts/bochs.sh b/scripts/bochs.sh deleted file mode 100755 index 52180e8..0000000 --- a/scripts/bochs.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /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 $BOCHS_ARGS -q - diff --git a/scripts/build.sh b/scripts/build.sh deleted file mode 100755 index 9b64905..0000000 --- a/scripts/build.sh +++ /dev/null @@ -1,32 +0,0 @@ -#! /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 9b39927..e26074f 100644 --- a/scripts/build_image.sh +++ b/scripts/build_image.sh @@ -1,11 +1,7 @@ -#! /bin/bash +#!/us 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 @@ -19,41 +15,37 @@ if [ -z "$dev" ]; then fi echo "Loopback device: ${dev}" -EFI_DIR="$BUILD_DIR/efi" -SYSROOT="$BUILD_DIR/sysroot" - cleanup() { - umount $EFI_DIR - rm -rf $EFI_DIR - umount $SYSROOT - rm -rf $SYSROOT + umount efi + rm -rf efi + umount sysroot + rm -rf sysroot losetup -d $dev } trap cleanup EXIT -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" +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" limine bios-install "${dev}" +mkdir -p efi/ +mount "${dev}p1" efi/ -mkdir -p $EFI_DIR -mount "${dev}p2" $EFI_DIR +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/zion efi/ +mkdir -p efi/sys +cp sys/yellowstone/yellowstone efi/sys/yellowstone +cp sys/denali/denali efi/sys/denali +cp sys/victoriafalls/victoriafalls efi/sys/victoriafalls -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}p3" $SYSROOT -rsync -a "$REPO_ROOT/sysroot" $BUILD_DIR -ls $SYSROOT +mkdir -p sysroot +mount "${dev}p2" sysroot/ +rsync -a ../sysroot . +ls sysroot/ chown drew:drew $1 diff --git a/scripts/qemu.sh b/scripts/qemu.sh index 22d6f98..b2ea1cc 100755 --- a/scripts/qemu.sh +++ b/scripts/qemu.sh @@ -8,9 +8,11 @@ echo $DIR BUILD_DIR="${DIR}/../builddbg" +pushd $BUILD_DIR +ninja +ninja install -bash ${DIR}/build.sh -sudo sh ${DIR}/build_image.sh ${BUILD_DIR}/disk.img +sudo sh ${DIR}/build_image.sh disk.img QEMU_ARGS= if [[ $1 == "debug" ]]; then @@ -18,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 ${BUILD_DIR}/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 disk.img ${QEMU_ARGS} popd # Extra options to add to this script in the future. diff --git a/scripts/test-mem.sh b/scripts/test-mem.sh deleted file mode 100755 index 046c120..0000000 --- a/scripts/test-mem.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /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 -D CMAKE_ASM-ATT_COMPILER=gcc -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 deleted file mode 100755 index ec1b1eb..0000000 --- a/scripts/test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#! /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 -D CMAKE_ASM-ATT_COMPILER=gcc -fi -pushd test-bin/ -ninja build_test -ctest --output-on-failure -popd -popd - diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index b6fe722..e2eb139 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -1,5 +1,8 @@ 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/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt new file mode 100644 index 0000000..eab0515 --- /dev/null +++ b/sys/denali/CMakeLists.txt @@ -0,0 +1,25 @@ +add_executable(denali + ahci/ahci_device.cpp + ahci/ahci_driver.cpp + ahci/command.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 new file mode 100644 index 0000000..5e275a5 --- /dev/null +++ b/sys/denali/ahci/ahci.h @@ -0,0 +1,248 @@ +#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)); + +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)); + +struct AhciPort { + 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)); + +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 { +} __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_device.cpp b/sys/denali/ahci/ahci_device.cpp new file mode 100644 index 0000000..994f4db --- /dev/null +++ b/sys/denali/ahci/ahci_device.cpp @@ -0,0 +1,120 @@ +#include "ahci/ahci_device.h" + +#include +#include +#include + +AhciDevice::AhciDevice(AhciPort* port) : port_struct_(port) { + if ((port_struct_->sata_status & 0x103) != 0x103) { + return; + } + + // 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; + + command_tables_ = + reinterpret_cast(command_structures_.vaddr() + 0x500); + + for (uint64_t i = 0; i < 32; i++) { + command_list_->command_headers[i].command_table_base_addr = + (paddr + 0x500) + (0x100 * i); + } + 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; +} + +glcr::ErrorCode AhciDevice::IssueCommand(Command* command) { + command->PopulateFis(command_tables_->command_fis); + command->PopulatePrdt(command_tables_->prdt); + + command_list_->command_headers[0].command = + (sizeof(HostToDeviceRegisterFis) / 2) & 0x1F; + command_list_->command_headers[0].prd_table_length = 1; + command_list_->command_headers[0].prd_byte_count = 0; + + commands_[0] = command; + + commands_issued_ |= 1; + port_struct_->command_issue |= 1; + + return glcr::OK; +} + +void AhciDevice::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("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() { + 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) { + // Device to host. + 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)); + return; + } + if (fis.error) { + dbgln("D2H err: {x}", fis.error); + dbgln("status: {x}", fis.status); + } + } + if (int_status & 0x2) { + // PIO. + 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)); + return; + } + if (fis.error) { + dbgln("PIO err: {x}", fis.error); + } + } +} diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_device.h new file mode 100644 index 0000000..bc4fc94 --- /dev/null +++ b/sys/denali/ahci/ahci_device.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +#include "ahci/ahci.h" +#include "ahci/command.h" + +class AhciDevice { + public: + AhciDevice() {} + // Caller retains ownership of the pointer. + AhciDevice(AhciPort* port_struct); + + void DumpInfo(); + + bool IsInit() { return port_struct_ != nullptr && command_structures_; } + + glcr::ErrorCode IssueCommand(Command* command); + + void HandleIrq(); + + AhciDevice(const AhciDevice&) = delete; + AhciDevice& operator=(const AhciDevice&) = delete; + + private: + AhciPort* port_struct_ = nullptr; + mmth::OwnedMemoryRegion command_structures_; + + CommandList* command_list_ = nullptr; + ReceivedFis* received_fis_ = nullptr; + CommandTable* command_tables_ = nullptr; + + Command* commands_[32]; + volatile uint32_t commands_issued_ = 0; +}; diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_driver.cpp new file mode 100644 index 0000000..64b340d --- /dev/null +++ b/sys/denali/ahci/ahci_driver.cpp @@ -0,0 +1,229 @@ +#include "ahci/ahci_driver.h" + +#include +#include +#include +#include +#include + +namespace { + +const uint64_t kGhc_InteruptEnable = 0x2; + +void interrupt_thread(void* void_driver) { + AhciDriver* driver = static_cast(void_driver); + + driver->InterruptLoop(); + + crash("Driver returned from interrupt loop", glcr::INTERNAL); +} + +} // namespace + +glcr::ErrorOr> AhciDriver::Init( + mmth::OwnedMemoryRegion&& pci_region) { + glcr::UniquePtr driver(new AhciDriver(glcr::Move(pci_region))); + // RET_ERR(driver->LoadCapabilities()); + RET_ERR(driver->LoadHbaRegisters()); + RET_ERR(driver->LoadDevices()); + RET_ERR(driver->RegisterIrq()); + // driver->DumpCapabilities(); + // driver->DumpPorts(); + return driver; +} + +glcr::ErrorOr AhciDriver::GetDevice(uint64_t id) { + if (id >= 32) { + return glcr::INVALID_ARGUMENT; + } + + if (devices_[id] != nullptr && !devices_[id]->IsInit()) { + return glcr::NOT_FOUND; + } + + return devices_[id]; +} + +void AhciDriver::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 AhciDriver::DumpPorts() { + for (uint64_t i = 0; i < 6; i++) { + AhciDevice* dev = devices_[i]; + if (dev == nullptr || !dev->IsInit()) { + continue; + } + + dbgln(""); + dbgln("Port {}:", i); + dev->DumpInfo(); + } +} + +void AhciDriver::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() && + (ahci_hba_->interrupt_status & (1 << i))) { + devices_[i]->HandleIrq(); + ahci_hba_->interrupt_status &= ~(1 << i); + } + } + } +} + +glcr::ErrorCode AhciDriver::LoadCapabilities() { + if (!(pci_device_header_->status_reg & 0x10)) { + dbgln("No caps!"); + return glcr::FAILED_PRECONDITION; + } + uint8_t* base = reinterpret_cast(pci_device_header_); + uint16_t offset = pci_device_header_->cap_ptr; + do { + 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 AhciDriver::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 AhciDriver::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 AhciDriver::LoadDevices() { + for (uint8_t i = 0; i < 32; i++) { + if (!(ahci_hba_->port_implemented & (1 << i))) { + devices_[i] = nullptr; + continue; + } + uint64_t port_addr = + reinterpret_cast(ahci_hba_) + 0x100 + (0x80 * i); + devices_[i] = new AhciDevice(reinterpret_cast(port_addr)); + } + return glcr::OK; +} diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_driver.h new file mode 100644 index 0000000..0713861 --- /dev/null +++ b/sys/denali/ahci/ahci_driver.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include +#include +#include + +#include "ahci/ahci.h" +#include "ahci/ahci_device.h" + +class AhciDriver { + 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_; + PciDeviceHeader* pci_device_header_ = nullptr; + mmth::OwnedMemoryRegion ahci_region_; + AhciHba* ahci_hba_ = nullptr; + + // TODO: Allocate these dynamically. + AhciDevice* devices_[32]; + + Thread irq_thread_; + uint64_t irq_port_cap_ = 0; + + uint64_t num_ports_; + uint64_t num_commands_; + + glcr::ErrorCode LoadCapabilities(); + glcr::ErrorCode LoadHbaRegisters(); + glcr::ErrorCode LoadDevices(); + + AhciDriver(mmth::OwnedMemoryRegion&& pci_region) + : pci_region_(glcr::Move(pci_region)), + pci_device_header_( + reinterpret_cast(pci_region_.vaddr())) {} +}; diff --git a/sys/denali/ahci/command.cpp b/sys/denali/ahci/command.cpp new file mode 100644 index 0000000..eea4ad0 --- /dev/null +++ b/sys/denali/ahci/command.cpp @@ -0,0 +1,63 @@ +#include "ahci/command.h" + +#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), + callback_semaphore_() {} + +DmaReadCommand::~DmaReadCommand() {} + +void DmaReadCommand::PopulateFis(uint8_t* command_fis) { + HostToDeviceRegisterFis fis{ + .fis_type = FIS_TYPE_REG_H2D, + .pmp_and_c = 0x80, + .command = 0x25, + .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, + }; + + 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 new file mode 100644 index 0000000..61fef58 --- /dev/null +++ b/sys/denali/ahci/command.h @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include "ahci/ahci.h" + +class Command { + public: + virtual ~Command(); + virtual void PopulateFis(uint8_t* command_fis) = 0; + virtual void PopulatePrdt(PhysicalRegionDescriptor* prdt) = 0; + virtual void WaitComplete() = 0; + virtual void SignalComplete() = 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) 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.cpp b/sys/denali/denali.cpp new file mode 100644 index 0000000..4173651 --- /dev/null +++ b/sys/denali/denali.cpp @@ -0,0 +1,37 @@ + +#include +#include +#include +#include + +#include "ahci/ahci_driver.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, AhciDriver::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 new file mode 100644 index 0000000..0c397c4 --- /dev/null +++ b/sys/denali/denali_server.cpp @@ -0,0 +1,64 @@ +#include "denali_server.h" + +#include +#include +#include +#include + +glcr::ErrorOr> DenaliServer::Create( + AhciDriver& 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(AhciDevice * device, driver_.GetDevice(req.device_id())); + + uint64_t paddr; + mmth::OwnedMemoryRegion region = + mmth::OwnedMemoryRegion::ContiguousPhysical(req.size() * 512, &paddr); + + DmaReadCommand command(req.lba(), req.size(), paddr); + device->IssueCommand(&command); + + command.WaitComplete(); + + resp.set_device_id(req.device_id()); + resp.set_size(req.size()); + resp.set_memory(region.DuplicateCap()); + return glcr::Status::Ok(); +} + +glcr::Status DenaliServer::HandleReadMany(const ReadManyRequest& req, + ReadResponse& resp) { + ASSIGN_OR_RETURN(AhciDevice * 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 i = 0; i < req.sector_cnt().size(); i++) { + sector_cnt += req.sector_cnt().at(i); + } + 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); + DmaReadCommand command(lba, size, region_paddr); + device->IssueCommand(&command); + command.WaitComplete(); + + region_paddr += 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 new file mode 100644 index 0000000..483fabe --- /dev/null +++ b/sys/denali/denali_server.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "ahci/ahci_driver.h" +#include "lib/denali/denali.yunq.server.h" + +class DenaliServer : public DenaliServerBase { + public: + static glcr::ErrorOr> Create( + AhciDriver& 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]; + + AhciDriver& driver_; + + DenaliServer(z_cap_t endpoint_cap, AhciDriver& driver) + : DenaliServerBase(endpoint_cap), driver_(driver) {} +}; diff --git a/rust/sys/denali/denali.yunq b/sys/denali/lib/denali/denali.yunq similarity index 72% rename from rust/sys/denali/denali.yunq rename to sys/denali/lib/denali/denali.yunq index 8348968..340861b 100644 --- a/rust/sys/denali/denali.yunq +++ b/sys/denali/lib/denali/denali.yunq @@ -3,20 +3,18 @@ interface Denali { method ReadMany(ReadManyRequest) -> (ReadResponse); } -message DiskBlock { +message ReadRequest { + u64 device_id; u64 lba; u64 size; } -message ReadRequest { - u64 device_id; - DiskBlock block; -} - - message ReadManyRequest { u64 device_id; - repeated DiskBlock blocks; + // FIXME: Add repeated message fields. + // Must be the same length. + repeated u64 lba; + repeated u64 sector_cnt; } message ReadResponse { @@ -25,4 +23,3 @@ message ReadResponse { capability memory; } - 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..af49317 --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.client.cpp @@ -0,0 +1,98 @@ +// 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)); + + + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, 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)); + + + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, 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 new file mode 100644 index 0000000..46fd28d --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.client.h @@ -0,0 +1,37 @@ +// 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 new file mode 100644 index 0000000..0f6646b --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.cpp @@ -0,0 +1,248 @@ +// Generated file -- DO NOT MODIFY. +#include "denali.yunq.h" + +#include + + +namespace { + +const uint64_t header_size = 24; // 4x uint32, 1x uint64 + +struct ExtPointer { + uint32_t offset; + uint32_t length; +}; + +} // namespace +glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status ReadRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status ReadRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + // Parse device_id. + set_device_id(bytes.At(offset + header_size + (8 * 0))); + // Parse lba. + set_lba(bytes.At(offset + header_size + (8 * 1))); + // Parse size. + set_size(bytes.At(offset + header_size + (8 * 2))); + + return glcr::Status::Ok(); +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + // Write lba. + bytes.WriteAt(offset + header_size + (8 * 1), lba()); + // Write size. + bytes.WriteAt(offset + header_size + (8 * 2), size()); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + // Write lba. + bytes.WriteAt(offset + header_size + (8 * 1), lba()); + // Write size. + bytes.WriteAt(offset + header_size + (8 * 2), size()); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status ReadManyRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status ReadManyRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + // Parse device_id. + set_device_id(bytes.At(offset + header_size + (8 * 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)); + } + + // 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)); + } + + + return glcr::Status::Ok(); +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 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)); + } + // Write sector_cnt. + ExtPointer sector_cnt_ptr{ + .offset = next_extension, + .length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)), + }; + + next_extension += sector_cnt_ptr.length; + bytes.WriteAt(offset + header_size + (8 * 2), sector_cnt_ptr); + + 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; +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 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)); + } + // Write sector_cnt. + ExtPointer sector_cnt_ptr{ + .offset = next_extension, + .length = (uint32_t)(sector_cnt().size() * sizeof(uint64_t)), + }; + + next_extension += sector_cnt_ptr.length; + bytes.WriteAt(offset + header_size + (8 * 2), sector_cnt_ptr); + + 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; +} +glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + // Parse memory. + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_memory(0); + return glcr::Status::Ok(); +} + +glcr::Status ReadResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + // Parse memory. + uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); + + set_memory(caps.At(memory_ptr)); + return glcr::Status::Ok(); +} + +glcr::Status ReadResponse::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); + // Parse device_id. + set_device_id(bytes.At(offset + header_size + (8 * 0))); + // Parse size. + set_size(bytes.At(offset + header_size + (8 * 1))); + // Parse memory. + // Skip Cap. + + return glcr::Status::Ok(); +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + // Write size. + bytes.WriteAt(offset + header_size + (8 * 1), size()); + // Write memory. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 2), 0); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +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; + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 0), device_id()); + // Write size. + bytes.WriteAt(offset + header_size + (8 * 1), size()); + // Write memory. + caps.WriteAt(next_cap, memory()); + bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + diff --git a/sys/denali/lib/denali/denali.yunq.h b/sys/denali/lib/denali/denali.yunq.h new file mode 100644 index 0000000..414c807 --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.h @@ -0,0 +1,90 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#include +#include +#include +#include +#include +#include + + +class ReadRequest { + public: + ReadRequest() {} + // Delete copy and move until implemented. + 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&); + 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; } + + private: + uint64_t device_id_; + uint64_t lba_; + uint64_t size_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class ReadManyRequest { + public: + ReadManyRequest() {} + // Delete copy and move until implemented. + 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&); + 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 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); } + + private: + uint64_t device_id_; + glcr::Vector lba_; + glcr::Vector sector_cnt_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class ReadResponse { + public: + ReadResponse() {} + // Delete copy and move until implemented. + 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&); + 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& size() const { return size_; } + void set_size(const uint64_t& value) { size_ = value; } + const z_cap_t& memory() const { 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 glcr::ByteBuffer&, uint64_t offset); +}; + 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..9f9764e --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.server.cpp @@ -0,0 +1,150 @@ +// 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; + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, 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; + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, 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 new file mode 100644 index 0000000..5dc12e3 --- /dev/null +++ b/sys/denali/lib/denali/denali.yunq.server.h @@ -0,0 +1,50 @@ +// 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/teton/CMakeLists.txt b/sys/teton/CMakeLists.txt new file mode 100644 index 0000000..19a6706 --- /dev/null +++ b/sys/teton/CMakeLists.txt @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..7e0a02e --- /dev/null +++ b/sys/teton/framebuffer/console.cpp @@ -0,0 +1,54 @@ +#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 new file mode 100644 index 0000000..9afd2f4 --- /dev/null +++ b/sys/teton/framebuffer/console.h @@ -0,0 +1,26 @@ +#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 new file mode 100644 index 0000000..5960c84 --- /dev/null +++ b/sys/teton/framebuffer/framebuffer.cpp @@ -0,0 +1,29 @@ +#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 new file mode 100644 index 0000000..d6db590 --- /dev/null +++ b/sys/teton/framebuffer/framebuffer.h @@ -0,0 +1,25 @@ +#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 new file mode 100644 index 0000000..43714c6 --- /dev/null +++ b/sys/teton/framebuffer/psf.cpp @@ -0,0 +1,46 @@ +#include "framebuffer/psf.h" + +#include +#include + +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() { + 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); +} + +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 new file mode 100644 index 0000000..bfa890d --- /dev/null +++ b/sys/teton/framebuffer/psf.h @@ -0,0 +1,37 @@ +#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 new file mode 100644 index 0000000..fda6396 --- /dev/null +++ b/sys/teton/terminal.cpp @@ -0,0 +1,92 @@ +#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 { + auto& files = files_or.value(); + for (uint64_t i = 0; i < files.size(); i++) { + console_.WriteString(files[i]); + 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]); + + // TODO: Wait until the process exits. + auto error_or_cap = mmth::SpawnProcessFromElfRegion( + (uint64_t)file.raw_ptr(), gInitEndpointCap); + 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 new file mode 100644 index 0000000..71408a2 --- /dev/null +++ b/sys/teton/terminal.h @@ -0,0 +1,19 @@ +#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 new file mode 100644 index 0000000..f89c689 --- /dev/null +++ b/sys/teton/teton.cpp @@ -0,0 +1,48 @@ +#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; +} diff --git a/sys/victoriafalls/CMakeLists.txt b/sys/victoriafalls/CMakeLists.txt new file mode 100644 index 0000000..964bbab --- /dev/null +++ b/sys/victoriafalls/CMakeLists.txt @@ -0,0 +1,26 @@ +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 new file mode 100644 index 0000000..8a3ab2a --- /dev/null +++ b/sys/victoriafalls/fs/ext2/ext2.h @@ -0,0 +1,76 @@ +#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 new file mode 100644 index 0000000..3262f48 --- /dev/null +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.cpp @@ -0,0 +1,117 @@ +#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.set_lba(denali_info.lba_offset() + 2); + req.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.set_lba(lba_offset_ + block_number * SectorsPerBlock()); + req.set_size(num_blocks * SectorsPerBlock()); + ReadResponse resp; + auto status = denali_.Read(req, resp); + if (!status.ok()) { + dbgln("Failed to read blocks: {}", status.message()); + 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++; + } + 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()) { + dbgln("Failed to read blocks: {}", status.message()); + 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 new file mode 100644 index 0000000..aa49fba --- /dev/null +++ b/sys/victoriafalls/fs/ext2/ext2_block_reader.h @@ -0,0 +1,49 @@ +#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 new file mode 100644 index 0000000..2202163 --- /dev/null +++ b/sys/victoriafalls/fs/ext2/ext2_driver.cpp @@ -0,0 +1,152 @@ +#include "fs/ext2/ext2_driver.h" + +#include +#include + +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; + } + 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); + + 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; + } + + // 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; + } + + 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(); + while (addr < block.vaddr() + ext2_reader_->BlockSize()) { + DirEntry* entry = reinterpret_cast(addr); + directory.PushBack(*entry); + glcr::StringView name(entry->name, entry->name_len); + 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); + } + 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; + } + + // 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; + } + blocks_to_read.PushBack(single_indr_block_array[j]); + } + } + + return ext2_reader_->ReadBlocks(blocks_to_read); +} diff --git a/sys/victoriafalls/fs/ext2/ext2_driver.h b/sys/victoriafalls/fs/ext2/ext2_driver.h new file mode 100644 index 0000000..b1b4100 --- /dev/null +++ b/sys/victoriafalls/fs/ext2/ext2_driver.h @@ -0,0 +1,31 @@ +#pragma once + +#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_; + + Ext2Driver(const glcr::SharedPtr& reader, + glcr::UniquePtr inode_table) + : ext2_reader_(reader), inode_table_(glcr::Move(inode_table)) {} +}; diff --git a/sys/victoriafalls/fs/ext2/inode_table.cpp b/sys/victoriafalls/fs/ext2/inode_table.cpp new file mode 100644 index 0000000..12bab0f --- /dev/null +++ b/sys/victoriafalls/fs/ext2/inode_table.cpp @@ -0,0 +1,33 @@ +#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 new file mode 100644 index 0000000..18bb36d --- /dev/null +++ b/sys/victoriafalls/fs/ext2/inode_table.h @@ -0,0 +1,24 @@ +#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/rust/sys/victoriafalls/victoriafalls.yunq b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq similarity index 99% rename from rust/sys/victoriafalls/victoriafalls.yunq rename to sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq index 1cc0d45..5da582e 100644 --- a/rust/sys/victoriafalls/victoriafalls.yunq +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq @@ -21,4 +21,3 @@ 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 new file mode 100644 index 0000000..aa289d2 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.cpp @@ -0,0 +1,98 @@ +// 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)); + + + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, 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)); + + + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, 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 new file mode 100644 index 0000000..35dab56 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.client.h @@ -0,0 +1,37 @@ +// 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 new file mode 100644 index 0000000..44c50b0 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.cpp @@ -0,0 +1,286 @@ +// Generated file -- DO NOT MODIFY. +#include "victoriafalls.yunq.h" + +#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 glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +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)); + + return glcr::Status::Ok(); +} + +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; + // 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); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +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; + // 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); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + // Parse memory. + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_memory(0); + return glcr::Status::Ok(); +} + +glcr::Status OpenFileResponse::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + // Parse memory. + uint64_t memory_ptr = bytes.At(offset + header_size + (8 * 2)); + + set_memory(caps.At(memory_ptr)); + return glcr::Status::Ok(); +} + +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)); + // Parse size. + set_size(bytes.At(offset + header_size + (8 * 1))); + // Parse memory. + // Skip Cap. + + return glcr::Status::Ok(); +} + +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; + // 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 size. + bytes.WriteAt(offset + header_size + (8 * 1), size()); + // Write memory. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 2), 0); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +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; + // 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 size. + bytes.WriteAt(offset + header_size + (8 * 1), size()); + // Write memory. + caps.WriteAt(next_cap, memory()); + bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status GetDirectoryRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +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)); + + return glcr::Status::Ok(); +} + +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; + // 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); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +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; + // 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); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +glcr::Status Directory::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); + return glcr::Status::Ok(); +} + +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)); + + return glcr::Status::Ok(); +} + +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; + // Write filenames. + ExtPointer filenames_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)filenames().length(), + }; + + bytes.WriteStringAt(offset + next_extension, filenames()); + next_extension += filenames_ptr.length; + + 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; +} + +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; + // Write filenames. + ExtPointer filenames_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)filenames().length(), + }; + + bytes.WriteStringAt(offset + next_extension, filenames()); + next_extension += filenames_ptr.length; + + 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; +} + diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h new file mode 100644 index 0000000..7549408 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.h @@ -0,0 +1,98 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#include +#include +#include +#include +#include +#include + + +class OpenFileRequest { + public: + OpenFileRequest() {} + // Delete copy and move until implemented. + 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&); + 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; } + + private: + glcr::String path_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class OpenFileResponse { + public: + OpenFileResponse() {} + // Delete copy and move until implemented. + 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&); + 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& size() const { return size_; } + void set_size(const uint64_t& value) { size_ = value; } + const z_cap_t& memory() const { 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 glcr::ByteBuffer&, uint64_t offset); +}; +class GetDirectoryRequest { + public: + GetDirectoryRequest() {} + // Delete copy and move until implemented. + 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&); + 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; } + + private: + glcr::String path_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class Directory { + public: + Directory() {} + // Delete copy and move until implemented. + 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&); + 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_; } + void set_filenames(const glcr::String& value) { filenames_ = value; } + + private: + glcr::String filenames_; + + // Parses everything except for caps. + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; + diff --git a/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp new file mode 100644 index 0000000..85a8a73 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.cpp @@ -0,0 +1,150 @@ +// 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; + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, 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; + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, 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 new file mode 100644 index 0000000..bf91f66 --- /dev/null +++ b/sys/victoriafalls/lib/victoriafalls/victoriafalls.yunq.server.h @@ -0,0 +1,50 @@ +// 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 new file mode 100644 index 0000000..56ee383 --- /dev/null +++ b/sys/victoriafalls/victoriafalls.cpp @@ -0,0 +1,35 @@ +#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 new file mode 100644 index 0000000..fbc5e42 --- /dev/null +++ b/sys/victoriafalls/victoriafalls_server.cpp @@ -0,0 +1,109 @@ +#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 (uint64_t i = 0; i < files.size(); i++) { + filelist.PushBack(glcr::StringView(files.at(i).name, files.at(i).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 new file mode 100644 index 0000000..8716093 --- /dev/null +++ b/sys/victoriafalls/victoriafalls_server.h @@ -0,0 +1,24 @@ +#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/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt index 75a852c..10a3754 100644 --- a/sys/voyageurs/CMakeLists.txt +++ b/sys/voyageurs/CMakeLists.txt @@ -1,10 +1,5 @@ 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 voyageurs_server.cpp voyageurs.cpp) diff --git a/sys/voyageurs/keyboard/keyboard_driver.cpp b/sys/voyageurs/keyboard/keyboard_driver.cpp index fc4f1d1..f96a3ad 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.cpp +++ b/sys/voyageurs/keyboard/keyboard_driver.cpp @@ -2,24 +2,13 @@ #include -namespace { - -KeyboardDriver* gKeyboardDriver = nullptr; - -} - void InterruptEnter(void* void_keyboard) { KeyboardDriver* keyboard = static_cast(void_keyboard); keyboard->InterruptLoop(); } -KeyboardDriver::KeyboardDriver() { - check(ZPortCreate(&port_cap_)); - gKeyboardDriver = this; -} - -z_cap_t KeyboardDriver::GetPortCap() { return gKeyboardDriver->port_cap_; } +KeyboardDriver::KeyboardDriver() { check(ZIrqRegister(kZIrqKbd, &irq_cap_)); } void KeyboardDriver::RegisterListener(uint64_t port_cap) { listeners_.PushFront(mmth::PortClient::AdoptPort(port_cap)); @@ -32,37 +21,13 @@ Thread KeyboardDriver::StartInterruptLoop() { void KeyboardDriver::InterruptLoop() { dbgln("Interrupt"); while (true) { - uint64_t scancode; - uint64_t num_bytes = 8; + uint8_t scancode; + uint64_t num_bytes = 1; uint64_t num_caps = 0; - check(ZPortRecv(port_cap_, &num_bytes, &scancode, &num_caps, nullptr)); + check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr)); - ProcessInput(scancode); - } -} - -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; - 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(modifiers | code); + for (mmth::PortClient& client : listeners_) { + client.WriteByte(scancode); } } - bitmap_ = new_bitmap; -} - -void KeyboardDriver::SendKeypress(uint16_t scancode) { - for (mmth::PortClient& client : listeners_) { - client.Write(scancode); - } } diff --git a/sys/voyageurs/keyboard/keyboard_driver.h b/sys/voyageurs/keyboard/keyboard_driver.h index 54dee91..b38af0e 100644 --- a/sys/voyageurs/keyboard/keyboard_driver.h +++ b/sys/voyageurs/keyboard/keyboard_driver.h @@ -11,19 +11,12 @@ 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 port_cap_; + z_cap_t irq_cap_; glcr::LinkedList listeners_; - - uint64_t bitmap_ = 0; - - void ProcessInput(uint64_t input); - void SendKeypress(uint16_t scancode); }; diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp index 1ad84f2..3adfc57 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -1,7 +1,6 @@ // Generated file -- DO NOT MODIFY. #include "voyageurs.yunq.h" -#include #include @@ -15,43 +14,55 @@ struct ExtPointer { }; } // namespace -glcr::Status KeyboardListener::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse port_capability. - ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0)); + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_port_capability(0); return glcr::Status::Ok(); } -glcr::Status KeyboardListener::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse port_capability. - ASSIGN_OR_RETURN(port_capability_, message.ReadCapability(0, caps)); + uint64_t port_capability_ptr = bytes.At(offset + header_size + (8 * 0)); + + set_port_capability(caps.At(port_capability_ptr)); return glcr::Status::Ok(); } -glcr::Status KeyboardListener::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status KeyboardListener::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse port_capability. + // Skip Cap. return glcr::Status::Ok(); } uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 1); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // Write port_capability. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 0), 0); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write port_capability. - serializer.WriteCapability(0, port_capability_); + caps.WriteAt(next_cap, port_capability()); + bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h index af8eca1..da5c585 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include @@ -16,24 +14,19 @@ class KeyboardListener { KeyboardListener() {} // Delete copy and move until implemented. KeyboardListener(const KeyboardListener&) = delete; - KeyboardListener(KeyboardListener&&) = default; - KeyboardListener& operator=(KeyboardListener&&) = default; + KeyboardListener(KeyboardListener&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: z_cap_t port_capability_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp index 80fa141..f8376dc 100644 --- a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp @@ -104,8 +104,7 @@ glcr::Status VoyageursServerBase::HandleRequest(const glcr::ByteBuffer& request, KeyboardListener yunq_request; - yunq::MessageView request_view(request, kHeaderSize); - RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); diff --git a/sys/voyageurs/voyageurs.cpp b/sys/voyageurs/voyageurs.cpp index 663d972..f3d375f 100644 --- a/sys/voyageurs/voyageurs.cpp +++ b/sys/voyageurs/voyageurs.cpp @@ -5,7 +5,6 @@ #include "keyboard/keyboard_driver.h" #include "voyageurs_server.h" -#include "xhci/xhci_driver.h" using yellowstone::RegisterEndpointRequest; using yellowstone::YellowstoneClient; @@ -13,12 +12,9 @@ using yellowstone::YellowstoneClient; uint64_t main(uint64_t init_port) { ParseInitPort(init_port); - YellowstoneClient yellowstone(gInitEndpointCap); - + 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(); @@ -28,6 +24,8 @@ 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/control_command.h b/sys/voyageurs/xhci/control_command.h deleted file mode 100644 index 9cc05cd..0000000 --- a/sys/voyageurs/xhci/control_command.h +++ /dev/null @@ -1,69 +0,0 @@ -#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 = (uint64_t)0x1000 << 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 = 0x1000, - .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 deleted file mode 100644 index 8aec53b..0000000 --- a/sys/voyageurs/xhci/descriptors.h +++ /dev/null @@ -1,77 +0,0 @@ -#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; }; -}; - -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/device_slot.cpp b/sys/voyageurs/xhci/device_slot.cpp deleted file mode 100644 index 1634f7c..0000000 --- a/sys/voyageurs/xhci/device_slot.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "xhci/device_slot.h" - -#include -#include - -#include "xhci/trb.h" -#include "xhci/xhci_driver.h" - -void DeviceSlot::EnableAndInitializeDataStructures( - 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; - - 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; - 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; - - // 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; - - endpoints_ = glcr::Array(32); - - return ::CreateAddressDeviceCommand(context_phys_ + kInputSlotContextOffset, - slot_index_); -} - -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 >= 32) { - dbgln("ERROR: Received transfer for invalid endpoint {x}", endpoint_index); - return; - } - - if (endpoint_index != 1) { - 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)) { - // 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)); -} - -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. - 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. - endpoints_[3].Initialize(input_context_->endpoint_contexts + 2, - glcr::Move(client)); - - 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 deleted file mode 100644 index 473d1c5..0000000 --- a/sys/voyageurs/xhci/device_slot.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "xhci/control_command.h" -#include "xhci/endpoint.h" -#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(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, glcr::UniquePtr client); - void SignalConfigureDeviceCompleted(); - - // 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; - - XhciDriver* xhci_driver_; - uint8_t slot_index_ = 0; - volatile uint32_t* doorbell_ = nullptr; - - 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_; - glcr::HashMap> - control_completion_sempahores_; - - mmth::Semaphore configure_device_semaphore_; - - glcr::Array endpoints_; -}; - -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/endpoint.cpp b/sys/voyageurs/xhci/endpoint.cpp deleted file mode 100644 index 6583953..0000000 --- a/sys/voyageurs/xhci/endpoint.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "xhci/endpoint.h" - -#include - -#include "xhci/trb.h" - -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_); - - context_->tr_dequeue_ptr = trb_ring_->PhysicalAddress() | 1; - - context_->error_and_type = (0x3 << 1) | (0x7 << 3) | (0x8 << 16); - for (uint64_t i = 0; i < 10; i++) { - trb_ring_->EnqueueTrb(CreateNormalTrb(recv_phys_ + offset_, 8)); - offset_ += 8; - } -} - -void Endpoint::TransferComplete(uint64_t trb_phys) { - uint64_t phys_offset = - (trb_phys - trb_ring_->PhysicalAddress()) / sizeof(XhciTrb); - 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 deleted file mode 100644 index fd4a4d0..0000000 --- a/sys/voyageurs/xhci/endpoint.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#include -#include - -#include "xhci/trb_ring.h" -#include "xhci/xhci.h" - -class Endpoint { - public: - Endpoint() {} - - void Initialize(XhciEndpointContext* context, - glcr::UniquePtr client); - - 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_; - uint64_t offset_ = 0; - - glcr::UniquePtr client_; -}; diff --git a/sys/voyageurs/xhci/trb.cpp b/sys/voyageurs/xhci/trb.cpp deleted file mode 100644 index 7fca204..0000000 --- a/sys/voyageurs/xhci/trb.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "xhci/trb.h" - -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 { - -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 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, - .status = 0, - .type_and_cycle = (uint16_t)(TypeToInt(TrbType::Link) | kTrb_ToggleCycle), - .control = 0, - }; -} - -XhciTrb CreateEnableSlotTrb() { - return { - .parameter = 0, - .status = 0, - // FIXME: Accept Cycle Bit as a parameter. - .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 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, - .status = 0, - // FIXME: Accept Cycle Bit as a parameter. - .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 deleted file mode 100644 index f7fee03..0000000 --- a/sys/voyageurs/xhci/trb.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once - -#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, - ConfigureEndpoint = 12, - NoOpCommand = 23, - - // Events - Transfer = 32, - CommandCompletion = 33, - PortStatusChange = 34, -}; - -TrbType GetType(const XhciTrb& trb); - -XhciTrb CreateNormalTrb(uint64_t physical_address, uint8_t size); -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/trb_ring.cpp b/sys/voyageurs/xhci/trb_ring.cpp deleted file mode 100644 index f251a63..0000000 --- a/sys/voyageurs/xhci/trb_ring.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#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_); - - // 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); - - // Point the end of the command ring back to the start. - 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]; -} - -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(XhciTrb)); -} - -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 deleted file mode 100644 index c2d0668..0000000 --- a/sys/voyageurs/xhci/trb_ring.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include -#include - -#include "xhci/xhci.h" - -class TrbRing { - public: - TrbRing(); - - uint64_t PhysicalAddress() { return phys_address_; } - XhciTrb GetTrbFromPhysical(uint64_t address); - - protected: - uint64_t phys_address_; - mmth::OwnedMemoryRegion page_; - glcr::ArrayView trb_list_; -}; - -class TrbRingWriter : public TrbRing { - public: - uint64_t EnqueueTrb(const XhciTrb& trb); - - 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 deleted file mode 100644 index 2304249..0000000 --- a/sys/voyageurs/xhci/xhci.h +++ /dev/null @@ -1,143 +0,0 @@ -#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 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; - 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; - XhciPort ports[255]; -} __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 XhciDoorbells { - uint32_t doorbell[256]; -} __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 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; - uint16_t type_and_cycle; - uint16_t control; -} __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 deleted file mode 100644 index 4eedce0..0000000 --- a/sys/voyageurs/xhci/xhci_driver.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#include "xhci/xhci_driver.h" - -#include -#include -#include -#include - -#include "keyboard/keyboard_driver.h" -#include "xhci/descriptors.h" -#include "xhci/trb.h" -#include "xhci/xhci.h" - -void interrupt_thread(void* void_driver) { - XhciDriver* driver = static_cast(void_driver); - - driver->InterruptLoop(); - - 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); - 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; - } - } - - dbgln("---- Configuring with configuration: {x}", - config_descriptor->configuration_value); - - device_slot - ->IssueConfigureDeviceCommand( - config_descriptor->configuration_value, - glcr::MakeUnique(KeyboardDriver::GetPortCap())) - .Wait(); - - dbgln("Configured!"); -} - -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()); - // 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->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(); - switch (GetType(trb)) { - case TrbType::Transfer: - HandleTransferCompletion(trb); - break; - case TrbType::CommandCompletion: - HandleCommandCompletion(trb); - break; - 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.", (uint8_t)GetType(trb)); - break; - } - } - - runtime_->interrupters[0].event_ring_dequeue_pointer = - event_ring_.DequeuePtr() | 0x8; - runtime_->interrupters[0].management |= 0x1; - } -} - -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; - doorbells_->doorbell[0] = 0; - } - } - - dbgln("Int 0 ES: {x}", - 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)) {} - -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()); - - 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); - - 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_); - - 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; - - 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; -} - -void XhciDriver::StartInterruptThread() { - interrupt_thread_ = Thread(interrupt_thread, this); -} - -glcr::ErrorCode XhciDriver::InitiateCommandRing() { - operational_->command_ring_control = command_ring_.PhysicalAddress(); - 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_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; - 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; - 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; -} - -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()); - 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; - default: - dbgln("Unhandled Command Completion Type: {x}", - (uint8_t)(GetType(orig_trb))); - } -} - -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; - 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( - this, slot_index, &(device_context_base_array_[slot_index]), - &doorbells_->doorbell[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 deleted file mode 100644 index 2b70715..0000000 --- a/sys/voyageurs/xhci/xhci_driver.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "xhci/device_slot.h" -#include "xhci/trb_ring.h" -#include "xhci/xhci.h" - -class XhciDriver { - public: - static glcr::ErrorOr> InitiateDriver( - yellowstone::YellowstoneClient& yellowstone); - - XhciDriver(const XhciDriver&) = delete; - XhciDriver(XhciDriver&&) = default; - - void DumpDebugInfo(); - - void InterruptLoop(); - - void IssueCommand(const XhciTrb& command); - - private: - // MMIO Structures. - mmth::OwnedMemoryRegion pci_region_; - PciDeviceHeader* pci_device_header_; - - mmth::OwnedMemoryRegion mmio_regions_; - volatile XhciCapabilities* capabilities_; - volatile XhciOperational* operational_; - // TODO: Extended Capabilities. - volatile XhciRuntime* runtime_; - volatile XhciDoorbells* doorbells_; - - // Host Memory Regions. - TrbRingWriter command_ring_; - - 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_; - - TrbRingReader event_ring_; - Thread interrupt_thread_; - - glcr::Array devices_; - - XhciDriver(mmth::OwnedMemoryRegion&& pci_space); - - glcr::ErrorCode ParseMmioStructures(); - 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(); - - void HandleCommandCompletion(const XhciTrb& command_completion_trb); - void HandleTransferCompletion(const XhciTrb& transfer_event_trb); - - void InitializeSlot(uint8_t slot_index); -}; diff --git a/sys/yellowstone/CMakeLists.txt b/sys/yellowstone/CMakeLists.txt index 12936d3..22f7444 100644 --- a/sys/yellowstone/CMakeLists.txt +++ b/sys/yellowstone/CMakeLists.txt @@ -1,2 +1,25 @@ +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 new file mode 100644 index 0000000..b4eddc7 --- /dev/null +++ b/sys/yellowstone/hw/gpt.cpp @@ -0,0 +1,133 @@ +#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.set_lba(0); + req.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) { + return glcr::FailedPrecondition(glcr::StrFormat( + "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.set_lba(header->lba_partition_entries); + req.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 new file mode 100644 index 0000000..4ce95d3 --- /dev/null +++ b/sys/yellowstone/hw/gpt.h @@ -0,0 +1,20 @@ +#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 new file mode 100644 index 0000000..08a2e7b --- /dev/null +++ b/sys/yellowstone/hw/pcie.cpp @@ -0,0 +1,95 @@ +#include "hw/pcie.h" + +#include +#include +#include + +#define PCI_DEBUG 0 + +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; +} + +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; + } +} + +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 new file mode 100644 index 0000000..d9e5778 --- /dev/null +++ b/sys/yellowstone/hw/pcie.h @@ -0,0 +1,41 @@ +#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(); + + private: + PciDeviceHeader* header_; + + uint64_t achi_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/lib/yellowstone/yellowstone.yunq b/sys/yellowstone/lib/yellowstone/yellowstone.yunq index 3bf9d9d..95b3dfb 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq @@ -4,7 +4,6 @@ interface Yellowstone { method RegisterEndpoint(RegisterEndpointRequest) -> (); method GetEndpoint(GetEndpointRequest) -> (Endpoint); method GetAhciInfo() -> (AhciInfo); - method GetXhciInfo() -> (XhciInfo); method GetFramebufferInfo() -> (FramebufferInfo); method GetDenali() -> (DenaliInfo); } @@ -27,11 +26,6 @@ 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 05f451c..d7baf54 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.cpp @@ -87,8 +87,7 @@ glcr::Status YellowstoneClient::GetEndpoint(const GetEndpointRequest& request, E RET_ERR(buffer_.At(8)); - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); return glcr::OK; @@ -127,8 +126,7 @@ glcr::Status YellowstoneClient::GetAhciInfo(AhciInfo& response) { RET_ERR(buffer_.At(8)); - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); return glcr::OK; @@ -137,7 +135,7 @@ glcr::Status YellowstoneClient::GetAhciInfo(AhciInfo& response) { -glcr::Status YellowstoneClient::GetXhciInfo(XhciInfo& response) { +glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -167,8 +165,7 @@ glcr::Status YellowstoneClient::GetXhciInfo(XhciInfo& response) { RET_ERR(buffer_.At(8)); - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); return glcr::OK; @@ -177,7 +174,7 @@ glcr::Status YellowstoneClient::GetXhciInfo(XhciInfo& response) { -glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { +glcr::Status YellowstoneClient::GetDenali(DenaliInfo& response) { uint64_t buffer_size = kBufferSize; uint64_t cap_size = kCapBufferSize; @@ -207,48 +204,7 @@ glcr::Status YellowstoneClient::GetFramebufferInfo(FramebufferInfo& response) { RET_ERR(buffer_.At(8)); - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); - - - return glcr::OK; -} - - - - -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_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); return glcr::OK; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h index afe8619..1793f69 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.client.h @@ -34,10 +34,6 @@ 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 1134546..6b78856 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.cpp @@ -1,7 +1,6 @@ // Generated file -- DO NOT MODIFY. #include "yellowstone.yunq.h" -#include #include @@ -17,336 +16,423 @@ struct ExtPointer { }; } // namespace -glcr::Status RegisterEndpointRequest::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse endpoint_capability. - ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1)); + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_endpoint_capability(0); return glcr::Status::Ok(); } -glcr::Status RegisterEndpointRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status RegisterEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse endpoint_capability. - ASSIGN_OR_RETURN(endpoint_capability_, message.ReadCapability(1, caps)); + uint64_t endpoint_capability_ptr = bytes.At(offset + header_size + (8 * 1)); + + set_endpoint_capability(caps.At(endpoint_capability_ptr)); return glcr::Status::Ok(); } -glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status RegisterEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse endpoint_name. - ASSIGN_OR_RETURN(endpoint_name_, message.ReadField(0)); + 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)); // Parse endpoint_capability. + // Skip Cap. return glcr::Status::Ok(); } uint64_t RegisterEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 2); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 2; + const uint32_t core_size = next_extension; + // 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); + // Write endpoint_capability. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 1), 0); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 2; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write endpoint_name. - serializer.WriteField(0, 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); // Write endpoint_capability. - serializer.WriteCapability(1, endpoint_capability_); + caps.WriteAt(next_cap, endpoint_capability()); + bytes.WriteAt(offset + header_size + (8 * 1), next_cap++); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } -glcr::Status GetEndpointRequest::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); return glcr::Status::Ok(); } -glcr::Status GetEndpointRequest::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status GetEndpointRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); return glcr::Status::Ok(); } -glcr::Status GetEndpointRequest::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status GetEndpointRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse endpoint_name. - ASSIGN_OR_RETURN(endpoint_name_, message.ReadField(0)); + 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)); return glcr::Status::Ok(); } uint64_t GetEndpointRequest::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 1); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // 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); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write endpoint_name. - serializer.WriteField(0, endpoint_name_); + ExtPointer endpoint_name_ptr{ + .offset = next_extension, + // FIXME: Check downcast of str length. + .length = (uint32_t)endpoint_name().length(), + }; - serializer.WriteHeader(); + bytes.WriteStringAt(offset + next_extension, endpoint_name()); + next_extension += endpoint_name_ptr.length; - return serializer.size(); + 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; } -glcr::Status Endpoint::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse endpoint. - ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0)); + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_endpoint(0); return glcr::Status::Ok(); } -glcr::Status Endpoint::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status Endpoint::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse endpoint. - ASSIGN_OR_RETURN(endpoint_, message.ReadCapability(0, caps)); + uint64_t endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); + + set_endpoint(caps.At(endpoint_ptr)); return glcr::Status::Ok(); } -glcr::Status Endpoint::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status Endpoint::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse endpoint. + // Skip Cap. return glcr::Status::Ok(); } uint64_t Endpoint::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 1); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // Write endpoint. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 0), 0); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write endpoint. - serializer.WriteCapability(0, endpoint_); + caps.WriteAt(next_cap, endpoint()); + bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } -glcr::Status AhciInfo::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse ahci_region. - ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0)); + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_ahci_region(0); return glcr::Status::Ok(); } -glcr::Status AhciInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status AhciInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse ahci_region. - ASSIGN_OR_RETURN(ahci_region_, message.ReadCapability(0, caps)); + uint64_t ahci_region_ptr = bytes.At(offset + header_size + (8 * 0)); + + set_ahci_region(caps.At(ahci_region_ptr)); return glcr::Status::Ok(); } -glcr::Status AhciInfo::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status AhciInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse ahci_region. + // Skip Cap. // Parse region_length. - ASSIGN_OR_RETURN(region_length_, message.ReadField(1)); + set_region_length(bytes.At(offset + header_size + (8 * 1))); return glcr::Status::Ok(); } uint64_t AhciInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 2); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 2; + const uint32_t core_size = next_extension; + // Write ahci_region. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 0), 0); + // Write region_length. + bytes.WriteAt(offset + header_size + (8 * 1), region_length()); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 2; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write ahci_region. - serializer.WriteCapability(0, ahci_region_); + caps.WriteAt(next_cap, ahci_region()); + bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); // Write region_length. - serializer.WriteField(1, region_length_); + bytes.WriteAt(offset + header_size + (8 * 1), region_length()); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } -glcr::Status XhciInfo::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); - // Parse xhci_region. - ASSIGN_OR_RETURN(xhci_region_, message.ReadCapability(0)); +glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); 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)); +glcr::Status FramebufferInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); 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(); -} - -glcr::Status FramebufferInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); - return glcr::Status::Ok(); -} - -glcr::Status FramebufferInfo::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status FramebufferInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse address_phys. - ASSIGN_OR_RETURN(address_phys_, message.ReadField(0)); + set_address_phys(bytes.At(offset + header_size + (8 * 0))); // Parse width. - ASSIGN_OR_RETURN(width_, message.ReadField(1)); + set_width(bytes.At(offset + header_size + (8 * 1))); // Parse height. - ASSIGN_OR_RETURN(height_, message.ReadField(2)); + set_height(bytes.At(offset + header_size + (8 * 2))); // Parse pitch. - ASSIGN_OR_RETURN(pitch_, message.ReadField(3)); + set_pitch(bytes.At(offset + header_size + (8 * 3))); // Parse bpp. - ASSIGN_OR_RETURN(bpp_, message.ReadField(4)); + set_bpp(bytes.At(offset + header_size + (8 * 4))); // Parse memory_model. - ASSIGN_OR_RETURN(memory_model_, message.ReadField(5)); + set_memory_model(bytes.At(offset + header_size + (8 * 5))); // Parse red_mask_size. - ASSIGN_OR_RETURN(red_mask_size_, message.ReadField(6)); + set_red_mask_size(bytes.At(offset + header_size + (8 * 6))); // Parse red_mask_shift. - ASSIGN_OR_RETURN(red_mask_shift_, message.ReadField(7)); + set_red_mask_shift(bytes.At(offset + header_size + (8 * 7))); // Parse green_mask_size. - ASSIGN_OR_RETURN(green_mask_size_, message.ReadField(8)); + set_green_mask_size(bytes.At(offset + header_size + (8 * 8))); // Parse green_mask_shift. - ASSIGN_OR_RETURN(green_mask_shift_, message.ReadField(9)); + set_green_mask_shift(bytes.At(offset + header_size + (8 * 9))); // Parse blue_mask_size. - ASSIGN_OR_RETURN(blue_mask_size_, message.ReadField(10)); + set_blue_mask_size(bytes.At(offset + header_size + (8 * 10))); // Parse blue_mask_shift. - ASSIGN_OR_RETURN(blue_mask_shift_, message.ReadField(11)); + set_blue_mask_shift(bytes.At(offset + header_size + (8 * 11))); return glcr::Status::Ok(); } uint64_t FramebufferInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 12); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 12; + const uint32_t core_size = next_extension; + // Write address_phys. + bytes.WriteAt(offset + header_size + (8 * 0), address_phys()); + // Write width. + bytes.WriteAt(offset + header_size + (8 * 1), width()); + // Write height. + bytes.WriteAt(offset + header_size + (8 * 2), height()); + // Write pitch. + bytes.WriteAt(offset + header_size + (8 * 3), pitch()); + // Write bpp. + bytes.WriteAt(offset + header_size + (8 * 4), bpp()); + // Write memory_model. + bytes.WriteAt(offset + header_size + (8 * 5), memory_model()); + // Write red_mask_size. + bytes.WriteAt(offset + header_size + (8 * 6), red_mask_size()); + // Write red_mask_shift. + bytes.WriteAt(offset + header_size + (8 * 7), red_mask_shift()); + // Write green_mask_size. + bytes.WriteAt(offset + header_size + (8 * 8), green_mask_size()); + // Write green_mask_shift. + bytes.WriteAt(offset + header_size + (8 * 9), green_mask_shift()); + // Write blue_mask_size. + bytes.WriteAt(offset + header_size + (8 * 10), blue_mask_size()); + // Write blue_mask_shift. + bytes.WriteAt(offset + header_size + (8 * 11), blue_mask_shift()); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 12; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write address_phys. - serializer.WriteField(0, address_phys_); + bytes.WriteAt(offset + header_size + (8 * 0), address_phys()); // Write width. - serializer.WriteField(1, width_); + bytes.WriteAt(offset + header_size + (8 * 1), width()); // Write height. - serializer.WriteField(2, height_); + bytes.WriteAt(offset + header_size + (8 * 2), height()); // Write pitch. - serializer.WriteField(3, pitch_); + bytes.WriteAt(offset + header_size + (8 * 3), pitch()); // Write bpp. - serializer.WriteField(4, bpp_); + bytes.WriteAt(offset + header_size + (8 * 4), bpp()); // Write memory_model. - serializer.WriteField(5, memory_model_); + bytes.WriteAt(offset + header_size + (8 * 5), memory_model()); // Write red_mask_size. - serializer.WriteField(6, red_mask_size_); + bytes.WriteAt(offset + header_size + (8 * 6), red_mask_size()); // Write red_mask_shift. - serializer.WriteField(7, red_mask_shift_); + bytes.WriteAt(offset + header_size + (8 * 7), red_mask_shift()); // Write green_mask_size. - serializer.WriteField(8, green_mask_size_); + bytes.WriteAt(offset + header_size + (8 * 8), green_mask_size()); // Write green_mask_shift. - serializer.WriteField(9, green_mask_shift_); + bytes.WriteAt(offset + header_size + (8 * 9), green_mask_shift()); // Write blue_mask_size. - serializer.WriteField(10, blue_mask_size_); + bytes.WriteAt(offset + header_size + (8 * 10), blue_mask_size()); // Write blue_mask_shift. - serializer.WriteField(11, blue_mask_shift_); + bytes.WriteAt(offset + header_size + (8 * 11), blue_mask_shift()); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } -glcr::Status DenaliInfo::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse denali_endpoint. - ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0)); + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_denali_endpoint(0); return glcr::Status::Ok(); } -glcr::Status DenaliInfo::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status DenaliInfo::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); // Parse denali_endpoint. - ASSIGN_OR_RETURN(denali_endpoint_, message.ReadCapability(0, caps)); + uint64_t denali_endpoint_ptr = bytes.At(offset + header_size + (8 * 0)); + + set_denali_endpoint(caps.At(denali_endpoint_ptr)); return glcr::Status::Ok(); } -glcr::Status DenaliInfo::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status DenaliInfo::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); // Parse denali_endpoint. + // Skip Cap. // Parse device_id. - ASSIGN_OR_RETURN(device_id_, message.ReadField(1)); + set_device_id(bytes.At(offset + header_size + (8 * 1))); // Parse lba_offset. - ASSIGN_OR_RETURN(lba_offset_, message.ReadField(2)); + set_lba_offset(bytes.At(offset + header_size + (8 * 2))); return glcr::Status::Ok(); } uint64_t DenaliInfo::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, 3); - return SerializeInternal(serializer); + uint32_t next_extension = header_size + 8 * 3; + const uint32_t core_size = next_extension; + // Write denali_endpoint. + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * 0), 0); + // Write device_id. + bytes.WriteAt(offset + header_size + (8 * 1), device_id()); + // Write lba_offset. + bytes.WriteAt(offset + header_size + (8 * 2), lba_offset()); + + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; } 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 { + uint32_t next_extension = header_size + 8 * 3; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; // Write denali_endpoint. - serializer.WriteCapability(0, denali_endpoint_); + caps.WriteAt(next_cap, denali_endpoint()); + bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); // Write device_id. - serializer.WriteField(1, device_id_); + bytes.WriteAt(offset + header_size + (8 * 1), device_id()); // Write lba_offset. - serializer.WriteField(2, lba_offset_); + bytes.WriteAt(offset + header_size + (8 * 2), lba_offset()); - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h index 8130d35..3fb2f88 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.h @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include @@ -18,20 +16,15 @@ class RegisterEndpointRequest { RegisterEndpointRequest() {} // Delete copy and move until implemented. RegisterEndpointRequest(const RegisterEndpointRequest&) = delete; - RegisterEndpointRequest(RegisterEndpointRequest&&) = default; - RegisterEndpointRequest& operator=(RegisterEndpointRequest&&) = default; + RegisterEndpointRequest(RegisterEndpointRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: @@ -39,79 +32,62 @@ class RegisterEndpointRequest { z_cap_t endpoint_capability_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; class GetEndpointRequest { public: GetEndpointRequest() {} // Delete copy and move until implemented. GetEndpointRequest(const GetEndpointRequest&) = delete; - GetEndpointRequest(GetEndpointRequest&&) = default; - GetEndpointRequest& operator=(GetEndpointRequest&&) = default; + GetEndpointRequest(GetEndpointRequest&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: glcr::String endpoint_name_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; class Endpoint { public: Endpoint() {} // Delete copy and move until implemented. Endpoint(const Endpoint&) = delete; - Endpoint(Endpoint&&) = default; - Endpoint& operator=(Endpoint&&) = default; + Endpoint(Endpoint&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: z_cap_t endpoint_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; class AhciInfo { public: AhciInfo() {} // Delete copy and move until implemented. AhciInfo(const AhciInfo&) = delete; - AhciInfo(AhciInfo&&) = default; - AhciInfo& operator=(AhciInfo&&) = default; + AhciInfo(AhciInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: @@ -119,99 +95,42 @@ class AhciInfo { uint64_t region_length_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - 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; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; class FramebufferInfo { public: FramebufferInfo() {} // Delete copy and move until implemented. FramebufferInfo(const FramebufferInfo&) = delete; - FramebufferInfo(FramebufferInfo&&) = default; - FramebufferInfo& operator=(FramebufferInfo&&) = default; + FramebufferInfo(FramebufferInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: @@ -229,33 +148,24 @@ class FramebufferInfo { uint64_t blue_mask_shift_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; class DenaliInfo { public: DenaliInfo() {} // Delete copy and move until implemented. DenaliInfo(const DenaliInfo&) = delete; - DenaliInfo(DenaliInfo&&) = default; - DenaliInfo& operator=(DenaliInfo&&) = default; + DenaliInfo(DenaliInfo&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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: @@ -264,9 +174,7 @@ class DenaliInfo { uint64_t lba_offset_; // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp index 5d8c670..c0205ae 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.cpp @@ -106,8 +106,7 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques RegisterEndpointRequest yunq_request; - yunq::MessageView request_view(request, kHeaderSize); - RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); @@ -125,8 +124,7 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques GetEndpointRequest yunq_request; - yunq::MessageView request_view(request, kHeaderSize); - RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); @@ -164,23 +162,6 @@ 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; @@ -193,7 +174,7 @@ glcr::Status YellowstoneServerBase::HandleRequest(const glcr::ByteBuffer& reques break; } - case 5: { + case 4: { diff --git a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h index bdaa1fb..b725140 100644 --- a/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h +++ b/sys/yellowstone/lib/yellowstone/yellowstone.yunq.server.h @@ -41,10 +41,6 @@ class YellowstoneServerBase { - [[nodiscard]] virtual glcr::Status HandleGetXhciInfo(XhciInfo&) = 0; - - - [[nodiscard]] virtual glcr::Status HandleGetFramebufferInfo(FramebufferInfo&) = 0; diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp new file mode 100644 index 0000000..ced7332 --- /dev/null +++ b/sys/yellowstone/yellowstone.cpp @@ -0,0 +1,67 @@ +#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 (uint64_t i = 0; i < files.size(); i++) { + if (!files[i].empty()) { + mmth::File binary = + mmth::File::Open(glcr::StrFormat("/bin/{}", files[i])); + + 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 new file mode 100644 index 0000000..e4e05d6 --- /dev/null +++ b/sys/yellowstone/yellowstone_server.cpp @@ -0,0 +1,135 @@ +#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::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 { + 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(); +} + +} // namespace yellowstone diff --git a/sys/yellowstone/yellowstone_server.h b/sys/yellowstone/yellowstone_server.h new file mode 100644 index 0000000..6866001 --- /dev/null +++ b/sys/yellowstone/yellowstone_server.h @@ -0,0 +1,43 @@ +#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 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(); + + 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_; + + YellowstoneServer(z_cap_t endpoint_cap); +}; + +} // namespace yellowstone diff --git a/usr/testbed/test.cpp b/usr/testbed/test.cpp index 3f7f324..ef3f2eb 100644 --- a/usr/testbed/test.cpp +++ b/usr/testbed/test.cpp @@ -1,10 +1,7 @@ #include -#include uint64_t main(uint64_t init_port_cap) { dbgln("testbed"); - check(ZThreadSleep(2000)); - dbgln("testbed2"); return glcr::OK; } diff --git a/yunq/CMakeLists.txt b/yunq/CMakeLists.txt index df824b8..271476d 100644 --- a/yunq/CMakeLists.txt +++ b/yunq/CMakeLists.txt @@ -19,7 +19,6 @@ 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/client.cpp.jinja b/yunq/client.cpp.jinja index e4e8102..0643ad6 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, {{method.number}}); + buffer_.WriteAt(8, {{loop.index0}}); cap_buffer_.Reset(); {% if method.request == None %} @@ -56,8 +56,7 @@ glcr::Status {{interface.name}}Client::{{method.name}}(const {{method.request}}& RET_ERR(buffer_.At(8)); {% if method.response != None %} - yunq::MessageView resp_view(buffer_, 16); - RETURN_ERROR(response.ParseFromBytes(resp_view, cap_buffer_)); + RETURN_ERROR(response.ParseFromBytes(buffer_, 16, cap_buffer_)); {% endif %} return glcr::OK; diff --git a/yunq/example/example.yunq b/yunq/example/example.yunq new file mode 100644 index 0000000..f286199 --- /dev/null +++ b/yunq/example/example.yunq @@ -0,0 +1,16 @@ +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 new file mode 100644 index 0000000..1d3dd21 --- /dev/null +++ b/yunq/example/example.yunq.client.cpp @@ -0,0 +1,63 @@ +// 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::ErrorCode 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::INVALID_RESPONSE; + } + + // Check Response Code. + RET_ERR(buffer_.At(8)); + + + response.ParseFromBytes(buffer_, 16, cap_buffer_); + + + return glcr::OK; +} + + + + + +} // namepace srv::file diff --git a/yunq/example/example.yunq.client.h b/yunq/example/example.yunq.client.h new file mode 100644 index 0000000..d9fdb3c --- /dev/null +++ b/yunq/example/example.yunq.client.h @@ -0,0 +1,37 @@ +// 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::ErrorCode 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 new file mode 100644 index 0000000..1211542 --- /dev/null +++ b/yunq/example/example.yunq.cpp @@ -0,0 +1,210 @@ +// Generated file -- DO NOT MODIFY. +#include "example.yunq.h" + + +namespace srv::file { + +namespace { + +const uint64_t header_size = 24; // 4x uint32, 1x uint64 + +struct ExtPointer { + uint32_t offset; + 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); +} + +void OpenFileRequest::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); +} + +void OpenFileRequest::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + // Parse path. + auto path_pointer = bytes.At(offset + header_size + (8 * 0)); + + set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + // 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)); + } + + +} + +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; +} + +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; + // 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; +} +void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + ParseFromBytesInternal(bytes, offset); + // Parse mem_cap. + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_mem_cap(0); +} + +void File::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); + // Parse mem_cap. + uint64_t mem_cap_ptr = bytes.At(offset + header_size + (8 * 2)); + + set_mem_cap(caps.At(mem_cap_ptr)); +} + +void File::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + // Parse path. + auto path_pointer = bytes.At(offset + header_size + (8 * 0)); + + set_path(bytes.StringAt(offset + path_pointer.offset, path_pointer.length)); + // Parse attrs. + set_attrs(bytes.At(offset + header_size + (8 * 1))); + // Parse mem_cap. + // Skip Cap. + +} + +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; +} + +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; + // 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. + caps.WriteAt(next_cap, mem_cap()); + bytes.WriteAt(offset + header_size + (8 * 2), next_cap++); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + + +} // namepace srv::file diff --git a/yunq/example/example.yunq.h b/yunq/example/example.yunq.h new file mode 100644 index 0000000..1b9176e --- /dev/null +++ b/yunq/example/example.yunq.h @@ -0,0 +1,64 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#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; + + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + void ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, 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. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class File { + public: + File() {} + // Delete copy and move until implemented. + 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&); + 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. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; + + +} // namepace srv::file diff --git a/yunq/example/example.yunq.server.cpp b/yunq/example/example.yunq.server.cpp new file mode 100644 index 0000000..555c8d7 --- /dev/null +++ b/yunq/example/example.yunq.server.cpp @@ -0,0 +1,133 @@ +// 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::ErrorCode err = HandleRequest(recv_buffer, recv_cap, resp_buffer, resp_length, resp_cap); + if (err != glcr::OK) { + WriteError(resp_buffer, err); + 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::ErrorCode 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; + } + + uint64_t method_select = request.At(8); + + switch(method_select) { + case 0: { + + + OpenFileRequest yunq_request; + yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + + + + File yunq_response; + + + + RET_ERR(Handleopen(yunq_request, yunq_response)); + + + + resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); + + break; + } + default: { + return glcr::UNIMPLEMENTED; + } + } + return glcr::OK; +} + + + +} // namepace srv::file diff --git a/yunq/example/example.yunq.server.h b/yunq/example/example.yunq.server.h new file mode 100644 index 0000000..e1cb556 --- /dev/null +++ b/yunq/example/example.yunq.server.h @@ -0,0 +1,49 @@ +// Generated File -- DO NOT MODIFY. +#pragma once + +#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::ErrorCode Handleopen(const OpenFileRequest&, File&) = 0; + + + + private: + z_cap_t endpoint_; + + 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); +}; + + + + +} // namepace srv::file diff --git a/yunq/message.cpp.jinja b/yunq/message.cpp.jinja index b5e36b9..30f5556 100644 --- a/yunq/message.cpp.jinja +++ b/yunq/message.cpp.jinja @@ -1,7 +1,6 @@ // Generated file -- DO NOT MODIFY. #include "{{file}}.h" -#include #include {% if package != None %} @@ -19,108 +18,167 @@ struct ExtPointer { } // namespace {%- for message in messages %} -glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} -{%- if not field.repeated %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{field.number}})); - {%- else %} - // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{field.number}})); - {%- endif %} + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_{{field.name}}(0); {%- endif %} {%- endfor %} return glcr::Status::Ok(); } -glcr::Status {{message.name}}::ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer& caps) { - RETURN_ERROR(ParseFromBytesInternal(message)); +glcr::Status {{message.name}}::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + RETURN_ERROR(ParseFromBytesInternal(bytes, offset)); {%- for field in message.fields %} {%- if field.type == Type.CAPABILITY %} -{%- if not field.repeated %} // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadCapability({{field.number}}, caps)); - {%- else %} - // Parse {{field.name}}. - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeatedCapability({{field.number}}, caps)); - {%- endif %} + uint64_t {{field.name}}_ptr = bytes.At(offset + header_size + (8 * {{loop.index0}})); + + set_{{field.name}}(caps.At({{field.name}}_ptr)); {%- endif %} {%- endfor %} return glcr::Status::Ok(); } -glcr::Status {{message.name}}::ParseFromBytesInternal(const yunq::MessageView& message) { - RETURN_ERROR(message.CheckHeader()); +glcr::Status {{message.name}}::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + RETURN_ERROR(yunq::CheckHeader(bytes, offset)); {%- for field in message.fields %} // Parse {{field.name}}. -{%- if field.type == Type.MESSAGE %} - {%- if not field.repeated %} - message.ReadMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); +{%- 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 %} - message.ReadRepeatedMessage<{{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}})); -{%- else %} - ASSIGN_OR_RETURN({{field.name}}_, message.ReadRepeated<{{field.cpp_type()}}>({{field.number}})); -{% endif %} - + // TODO: Unimplemented parsing {{field.type}} {%- 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)); + } +{% endif %} {%- endfor %} return glcr::Status::Ok(); } uint64_t {{message.name}}::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { - yunq::Serializer serializer(bytes, offset, {{ message.fields | length }}); - return SerializeInternal(serializer); -} + uint32_t next_extension = header_size + 8 * {{ message.fields | length }}; + const uint32_t core_size = next_extension; -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 %} +{%- 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(), + }; -{%- if field.type == Type.MESSAGE %} - serializer.WriteMessage<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); + 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 %} - serializer.WriteCapability({{field.number}}, {{field.name}}_); + // FIXME: Implement inbuffer capabilities. + bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), 0); {%- else %} - serializer.WriteField<{{field.cpp_type()}}>({{field.number}}, {{field.name}}_); + // TODO: Unimplemented serialization {{field.type}} {%- endif %} - {%- else %} + ExtPointer {{field.name}}_ptr{ + .offset = next_extension, + .length = (uint32_t)({{field.name}}().size() * sizeof({{field.cpp_type()}})), + }; -{%- 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 %} + next_extension += {{field.name}}_ptr.length; + bytes.WriteAt(offset + header_size + (8 * {{loop.index0}}), {{field.name}}_ptr); + 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 %} - serializer.WriteHeader(); + // The next extension pointer is the length of the message. + yunq::WriteHeader(bytes, offset, core_size, next_extension); - return serializer.size(); + return next_extension; } +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; + +{%- 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++); +{%- else %} + // TODO: Unimplemented serialization {{field.type}} +{%- 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); + + 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); + + return next_extension; +} {%- endfor %} {% if package != None %} diff --git a/yunq/message.h.jinja b/yunq/message.h.jinja index 2cca2c2..cf15b59 100644 --- a/yunq/message.h.jinja +++ b/yunq/message.h.jinja @@ -6,8 +6,6 @@ #include #include #include -#include -#include #include {% if package != None %} @@ -20,35 +18,21 @@ class {{message.name}} { {{message.name}}() {} // Delete copy and move until implemented. {{message.name}}(const {{message.name}}&) = delete; - {{message.name}}({{message.name}}&&) = default; - {{message.name}}& operator=({{message.name}}&&) = default; + {{message.name}}({{message.name}}&&) = delete; - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message); - [[nodiscard]] glcr::Status ParseFromBytes(const yunq::MessageView& message, const glcr::CapBuffer&); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset); + [[nodiscard]] glcr::Status ParseFromBytes(const glcr::ByteBuffer&, uint64_t offset, const glcr::CapBuffer&); uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset) const; uint64_t SerializeToBytes(glcr::ByteBuffer&, uint64_t offset, glcr::CapBuffer&) const; {%- for field in message.fields %} {%- 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 %} - 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 %} private: @@ -61,9 +45,7 @@ class {{message.name}} { {%- endfor %} // Parses everything except for caps. - glcr::Status ParseFromBytesInternal(const yunq::MessageView& message); - - uint64_t SerializeInternal(yunq::Serializer& serializer) const; + glcr::Status ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); }; {%- endfor %} diff --git a/yunq/parser.py b/yunq/parser.py index c3ec971..d9c3eaa 100644 --- a/yunq/parser.py +++ b/yunq/parser.py @@ -17,7 +17,6 @@ class LexemeType(Enum): ARROW = 7 SEMICOLON = 8 DOT = 9 - EQUALS = 10 class Lexeme(): @@ -106,7 +105,6 @@ class Type(Enum): STRING = 3 BYTES = 4 CAPABILITY = 5 - MESSAGE = 6 type_str_dict = { "u64": Type.U64, @@ -125,18 +123,12 @@ type_to_cppstr = { } class Field(): - 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 + def __init__(self, fieldtype: Type, name: str, repeated = False): + self.type = fieldtype 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(): @@ -222,11 +214,8 @@ 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) @@ -277,11 +266,8 @@ 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) @@ -300,10 +286,14 @@ 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_str, name, repeated) + return Field(field_type, name, repeated) def type_check(decls: list[Decl]): if sum(1 for decl in decls if type(decl) is Package) > 1: @@ -323,12 +313,6 @@ 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/rust/Cargo.lock b/yunq/rust/Cargo.lock deleted file mode 100644 index cfaa503..0000000 --- a/yunq/rust/Cargo.lock +++ /dev/null @@ -1,267 +0,0 @@ -# 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 = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[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 = "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" -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.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" -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 = "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" -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 = "yunqc" -version = "0.1.0" -dependencies = [ - "clap", - "convert_case", - "prettyplease", - "proc-macro2", - "quote", - "syn", -] diff --git a/yunq/rust/Cargo.toml b/yunq/rust/Cargo.toml deleted file mode 100644 index a972f93..0000000 --- a/yunq/rust/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "yunqc" -version = "0.1.0" -edition = "2021" - -[dependencies] -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/codegen.rs b/yunq/rust/src/codegen.rs deleted file mode 100644 index 9462f4b..0000000 --- a/yunq/rust/src/codegen.rs +++ /dev/null @@ -1,591 +0,0 @@ -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; -use proc_macro2::TokenStream; -use quote::quote; - -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, 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)?; - } - }, - 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, 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)?; - } - }, - } - } 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, offset + 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, offset + 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 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, yunq::message::MESSAGE_IDENT)?; - buf.write_at(offset + 4, core_size)?; - buf.write_at(offset + 8, next_extension)?; - buf.write_at(offset + 12, 0_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: &[z_cap_t], - ) -> Result - where - Self: Sized, - { - 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); - } - // 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| to_path(&f.field_type)); - - let serialize = generate_serialize(message); - let parse = generate_parse(message); - quote! { - #[derive(PartialEq, Eq, Clone, Debug)] - pub struct #name { - #(pub #field_names: #field_types),* - } - - impl YunqMessage for #name { - #serialize - - #parse - } - } -} - -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(#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) - } - }, - (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) - } - }, - _ => unreachable!(), - } -} - -fn generate_client(interface: &Interface) -> TokenStream { - let client_name = interface.name.clone() + "Client"; - let name = ident(&client_name); - let methods = interface.methods.iter().map(generate_method); - quote! { - pub struct #name { - endpoint_cap: Capability, - byte_buffer: ByteBuffer<0x1000>, - } - - impl #name { - pub fn new(endpoint_cap: Capability) -> Self { - Self { - endpoint_cap, - byte_buffer: ByteBuffer::new(), - } - } - #(#methods)* - } - - } -} - -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.clear(); - 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.clear(); - // 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.clear(); - 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 (&mut self, req: #req) -> Result<#resp, ZError>; - }, - (Some(req), None) => quote! { - fn #name (&mut self, req: #req) -> Result<(), ZError>; - }, - (None, Some(resp)) => quote! { - fn #name (&mut 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(generate_server_method); - let server_match_cases = interface.methods.iter().map(generate_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::YunqServer for #server_name { - fn endpoint_cap(&self) -> &Capability { - &self.endpoint_cap - } - - fn handle_request( - &mut 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_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.clear(); - 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.clear(); - // 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.clear(); - 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 + Send; - }, - (Some(req), None) => quote! { - fn #name (&self, req: #req) -> impl Future> + Sync + Send; - }, - (None, Some(resp)) => quote! { - fn #name (&self) -> impl Future> + Sync + Send; - }, - _ => 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 - } -} - -fn any_strings(ast: &[Decl]) -> 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: &[Decl]) -> bool { - ast.iter().any(|decl| matches!(decl, Decl::Interface(_))) -} - -pub fn generate_code(ast: &[Decl]) -> 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 core::future::Future; - use mammoth::cap::Capability; - use mammoth::syscall; - } - } else { - quote! {} - }; - - let prelude = quote! { - - extern crate alloc; - - use alloc::vec::Vec; - use mammoth::zion::z_cap_t; - use mammoth::zion::ZError; - #[allow(unused_imports)] - use yunq::ByteBuffer; - use yunq::YunqMessage; - - #str_imports - - #interface_imports - - }; - - let message_decls = ast - .iter() - .filter_map(|decl| match decl { - Decl::Message(m) => Some(m), - _ => None, - }) - .map(generate_message); - - let interface_decls = ast - .iter() - .filter_map(|decl| match decl { - Decl::Interface(i) => Some(i), - _ => None, - }) - .map(generate_interface); - - let output = quote! { - #prelude - - #(#message_decls)* - - #(#interface_decls)* - } - .to_string(); - - let tokens = syn::parse_file(&output).unwrap_or_else(|e| { - println!("{}", output); - panic!("{}", e); - }); - - prettyplease::unparse(&tokens) -} diff --git a/yunq/rust/src/lexer.rs b/yunq/rust/src/lexer.rs deleted file mode 100644 index 666c1f5..0000000 --- a/yunq/rust/src/lexer.rs +++ /dev/null @@ -1,226 +0,0 @@ -#[derive(Debug, PartialEq)] -pub enum TokenType { - EndOfFile, - Name, - LeftBrace, - RightBrace, - LeftParen, - RightParen, - Arrow, - Semicolon, - Dot, - Equals, -} - -#[derive(Debug)] -#[allow(dead_code)] -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/lib.rs b/yunq/rust/src/lib.rs deleted file mode 100644 index 07ecdb9..0000000 --- a/yunq/rust/src/lib.rs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index a835985..0000000 --- a/yunq/rust/src/main.rs +++ /dev/null @@ -1,27 +0,0 @@ -use std::error::Error; -use std::fs; - -use clap::Parser; - -#[derive(Parser)] -#[command(about)] -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 = fs::read_to_string(args.input_path)?; - - let code = yunqc::codegen(&input)?; - - fs::write(args.output_path, code)?; - - Ok(()) -} diff --git a/yunq/rust/src/parser.rs b/yunq/rust/src/parser.rs deleted file mode 100644 index 3ea7e2b..0000000 --- a/yunq/rust/src/parser.rs +++ /dev/null @@ -1,424 +0,0 @@ -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, PartialEq)] -pub enum Type { - U64, - I64, - String, - Bytes, - Capability, - Message(String), -} - -impl Type { - pub fn rust_type(&self) -> String { - match self { - 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(), - } - } -} - -#[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.inner_type { - Type::U64 => "u64", - Type::I64 => "i64", - Type::String => "string", - Type::Bytes => "bytes", - Type::Capability => "cap", - 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), - "string" => Ok(Type::String), - "bytes" => Ok(Type::Bytes), - "capability" => Ok(Type::Capability), - _ => Ok(Type::Message(value.clone())), - } - } -} - -#[derive(Clone)] -pub struct Field { - pub field_type: FieldType, - pub name: String, - pub number: u64, -} - -#[derive(Clone)] -pub struct Message { - pub name: String, - pub fields: Vec, -} - -pub struct Method { - pub name: String, - pub number: u64, - pub request: Option, - pub 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 { - pub name: String, - pub 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 { - writeln!( - f, - "\t{}: {} ({})", - field.number, field.name, field.field_type - )?; - } - } - 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, - type_map: HashMap, -} - -impl<'a> Parser<'a> { - pub fn new(tokens: &'a Vec) -> Self { - Self { - tokens, - current_index: 0, - ast: Vec::new(), - type_map: HashMap::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(&mut self) -> &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(&mut self, t: TokenType) -> Result<&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(&mut self) -> Result<&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: FieldType { - inner_type: parsed_type, - repeated, - }, - name: name_identifier, - number, - }) - } - - 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 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.inner_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(()) - } -} diff --git a/yunq/server.cpp.jinja b/yunq/server.cpp.jinja index bee46b5..6f8a712 100644 --- a/yunq/server.cpp.jinja +++ b/yunq/server.cpp.jinja @@ -103,12 +103,11 @@ glcr::Status {{interface.name}}ServerBase::HandleRequest(const glcr::ByteBuffer& switch(method_select) { {%- for method in interface.methods %} - case {{method.number}}: { + case {{loop.index0}}: { {% if method.request != None %} {{method.request}} yunq_request; - yunq::MessageView request_view(request, kHeaderSize); - RETURN_ERROR(yunq_request.ParseFromBytes(request_view, req_caps)); + RETURN_ERROR(yunq_request.ParseFromBytes(request, kHeaderSize, req_caps)); {% endif %} {% if method.response != None %} diff --git a/yunq/yunq.py b/yunq/yunq.py index ad6e944..c217e19 100755 --- a/yunq/yunq.py +++ b/yunq/yunq.py @@ -34,7 +34,6 @@ 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) @@ -45,9 +44,6 @@ 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) diff --git a/zion/CMakeLists.txt b/zion/CMakeLists.txt index 598a3de..2e63927 100644 --- a/zion/CMakeLists.txt +++ b/zion/CMakeLists.txt @@ -102,7 +102,4 @@ target_include_directories(zion_stub set_target_properties(zion_stub PROPERTIES - COMPILE_FLAGS "${BASE_COMPILE_FLAGS} -nostdlib -c" - LINK_FLAGS "${BASE_LINK_FLAGS} -nostartfiles -static -lgcc" - ) - + COMPILE_FLAGS "${_Z_COMPILE_FLAGS}") diff --git a/zion/boot/limine.cfg b/zion/boot/limine.cfg new file mode 100644 index 0000000..0d3a965 --- /dev/null +++ b/zion/boot/limine.cfg @@ -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 diff --git a/zion/boot/limine.conf b/zion/boot/limine.conf deleted file mode 100644 index 718e5c3..0000000 --- a/zion/boot/limine.conf +++ /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/capability/capability.h b/zion/capability/capability.h index 96911c7..6a20183 100644 --- a/zion/capability/capability.h +++ b/zion/capability/capability.h @@ -5,7 +5,6 @@ #include #include -#include "debug/debug.h" #include "include/ztypes.h" #include "object/kernel_object.h" @@ -43,10 +42,7 @@ class Capability : public glcr::RefCounted { template glcr::RefPtr Capability::obj() { if (obj_->TypeTag() != KernelObjectTag::type) { - 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 nullptr; } return StaticCastRefPtr(obj_); } diff --git a/zion/debug/debug.cpp b/zion/debug/debug.cpp index 7d10174..a2929d9 100644 --- a/zion/debug/debug.cpp +++ b/zion/debug/debug.cpp @@ -5,18 +5,14 @@ #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) { @@ -43,52 +39,3 @@ 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 d3a6fd4..63b0d0e 100644 --- a/zion/debug/debug.h +++ b/zion/debug/debug.h @@ -37,9 +37,3 @@ 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/include/zcall.h b/zion/include/zcall.h index 6092037..efe5d16 100644 --- a/zion/include/zcall.h +++ b/zion/include/zcall.h @@ -17,7 +17,6 @@ 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); @@ -48,7 +47,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(MsiIrqRegister, uint64_t*, irq_num, z_cap_t*, port_cap); +SYS2(IrqRegister, 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*, @@ -56,7 +55,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, const z_cap_t*, caps); + data, uint64_t, num_caps, 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); diff --git a/zion/include/ztypes.h b/zion/include/ztypes.h index b60db9c..f25df71 100644 --- a/zion/include/ztypes.h +++ b/zion/include/ztypes.h @@ -19,7 +19,6 @@ 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; @@ -43,7 +42,7 @@ const uint64_t kZionPortSend = 0x51; const uint64_t kZionPortRecv = 0x52; const uint64_t kZionPortPoll = 0x53; -const uint64_t kZionMsiIrqRegister = 0x59; +const uint64_t kZionIrqRegister = 0x58; const uint64_t kZionEndpointCreate = 0x60; const uint64_t kZionEndpointSend = 0x61; diff --git a/zion/interrupt/apic.cpp b/zion/interrupt/apic.cpp index 66d7e0c..927edfd 100644 --- a/zion/interrupt/apic.cpp +++ b/zion/interrupt/apic.cpp @@ -136,6 +136,23 @@ 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/apic_timer.cpp b/zion/interrupt/apic_timer.cpp index 8a78329..9fbbaf6 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 = 100; +const uint32_t kScheduleFrequency = 20; ApicTimer* gApicTimer = nullptr; void ApicTimer::Init() { diff --git a/zion/interrupt/driver_manager.cpp b/zion/interrupt/driver_manager.cpp index 3aa2bc5..67e78fc 100644 --- a/zion/interrupt/driver_manager.cpp +++ b/zion/interrupt/driver_manager.cpp @@ -9,24 +9,18 @@ DriverManager& DriverManager::Get() { return *gDriverManager; } DriverManager::DriverManager() { gDriverManager = this; } void DriverManager::WriteMessage(uint64_t irq_num, IpcMessage&& message) { - 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()) { + if (!driver_map_.Contains(irq_num)) { dbgln("WARN IRQ for {x} with no registered driver", irq_num); return; } - driver_list_[offset]->Send(glcr::Move(message)); + driver_map_.at(irq_num)->Send(glcr::Move(message)); } -glcr::ErrorOr DriverManager::RegisterListener( - glcr::RefPtr port) { - if (driver_list_.size() + IRQ_OFFSET >= 0xFF) { - return glcr::EXHAUSTED; +glcr::ErrorCode DriverManager::RegisterListener(uint64_t irq_num, + glcr::RefPtr port) { + if (driver_map_.Contains(irq_num)) { + return glcr::ALREADY_EXISTS; } - uint8_t offset = (driver_list_.size() + IRQ_OFFSET); - driver_list_.PushBack(port); - return offset; + return driver_map_.Insert(irq_num, port); } diff --git a/zion/interrupt/driver_manager.h b/zion/interrupt/driver_manager.h index 3fb897f..db205c8 100644 --- a/zion/interrupt/driver_manager.h +++ b/zion/interrupt/driver_manager.h @@ -15,10 +15,9 @@ class DriverManager { void WriteMessage(uint64_t irq_num, IpcMessage&& message); - [[nodiscard]] glcr::ErrorOr RegisterListener( - glcr::RefPtr port); + [[nodiscard]] glcr::ErrorCode RegisterListener(uint64_t irq_num, + glcr::RefPtr port); private: - const uint64_t IRQ_OFFSET = 0x60; - glcr::Vector> driver_list_; + glcr::HashMap> driver_map_; }; diff --git a/zion/interrupt/interrupt.cpp b/zion/interrupt/interrupt.cpp index 7858e88..8b6c114 100644 --- a/zion/interrupt/interrupt.cpp +++ b/zion/interrupt/interrupt.cpp @@ -109,11 +109,11 @@ extern "C" void interrupt_protection_fault(InterruptFrame* frame) { } else { dbgln("GDT"); } - dbgln("Index: {} ({x})", err >> 3, err >> 3); + dbgln("Index: {}", err >> 3); 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}, RBP: {x}", frame->rsp, frame->rbp); + dbgln("RSP: {x}", frame->rsp); StackUnwind(frame->rbp); if (IsUserSpace(frame->rip)) { @@ -186,38 +186,51 @@ uint64_t cnt = 0; extern "C" void isr_apic_timer(); extern "C" void interrupt_apic_timer(InterruptFrame*) { cnt++; - if (cnt % 100 == 0) { + if (cnt % 20 == 0) { if (cnt == 20) { KernelHeap::DumpDebugData(); phys_mem::DumpPhysicalMemoryUsage(); } - dbgln("timer: {}s", cnt * 10 / 1000); + dbgln("timer: {}s", cnt * 50 / 1000); } gApic->SignalEOI(); gScheduler->Preempt(); } -extern "C" void isr_60(); -extern "C" void interrupt_60(InterruptFrame*) { - DriverManager::Get().WriteMessage(0x60, {}); +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)); + gApic->SignalEOI(); } -extern "C" void isr_61(); -extern "C" void interrupt_61(InterruptFrame*) { - DriverManager::Get().WriteMessage(0x61, {}); +extern "C" void isr_pci1(); +extern "C" void interrupt_pci1(InterruptFrame*) { + DriverManager::Get().WriteMessage(kZIrqPci1, {}); gApic->SignalEOI(); } -extern "C" void isr_62(); -extern "C" void interrupt_62(InterruptFrame*) { - DriverManager::Get().WriteMessage(0x62, {}); +extern "C" void isr_pci2(); +extern "C" void interrupt_pci2(InterruptFrame*) { + DriverManager::Get().WriteMessage(kZIrqPci2, {}); + dbgln("Interrupt PCI line 2"); gApic->SignalEOI(); } -extern "C" void isr_63(); -extern "C" void interrupt_63(InterruptFrame*) { - DriverManager::Get().WriteMessage(0x63, {}); +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"); gApic->SignalEOI(); } @@ -230,11 +243,12 @@ void InitIdt() { gIdt[0x20] = CreateDescriptor(isr_timer); gIdt[0x21] = CreateDescriptor(isr_apic_timer); + gIdt[0x22] = CreateDescriptor(isr_keyboard); - gIdt[0x60] = CreateDescriptor(isr_60); - gIdt[0x61] = CreateDescriptor(isr_61); - gIdt[0x62] = CreateDescriptor(isr_62); - gIdt[0x63] = CreateDescriptor(isr_63); + gIdt[0x30] = CreateDescriptor(isr_pci1); + gIdt[0x31] = CreateDescriptor(isr_pci2); + gIdt[0x32] = CreateDescriptor(isr_pci3); + gIdt[0x33] = CreateDescriptor(isr_pci4); InterruptDescriptorTablePointer idtp{ .size = sizeof(gIdt), diff --git a/zion/interrupt/interrupt_enter.s b/zion/interrupt/interrupt_enter.s index 167d631..db02a22 100644 --- a/zion/interrupt/interrupt_enter.s +++ b/zion/interrupt/interrupt_enter.s @@ -63,8 +63,10 @@ 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/lib/memory_mapping_tree.cpp b/zion/lib/memory_mapping_tree.cpp index d4b2dac..91259ff 100644 --- a/zion/lib/memory_mapping_tree.cpp +++ b/zion/lib/memory_mapping_tree.cpp @@ -45,15 +45,11 @@ 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; } diff --git a/zion/loader/init_loader.cpp b/zion/loader/init_loader.cpp index b05c70a..7e1f16a 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 1 +#define K_INIT_DEBUG 0 namespace { @@ -67,9 +67,6 @@ 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 " @@ -77,19 +74,12 @@ 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 - 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); - } + 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."); } return header->entry; } @@ -100,8 +90,7 @@ 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},{x}", glcr::String(file.path), (uint64_t)file.address, - file.size); + dbgln(" {},{x},{}", file.path, file.address, file.size); } #endif } @@ -122,8 +111,6 @@ 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)); @@ -134,10 +121,6 @@ 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; diff --git a/zion/memory/kernel_heap.cpp b/zion/memory/kernel_heap.cpp index 68b9b24..6ad518a 100644 --- a/zion/memory/kernel_heap.cpp +++ b/zion/memory/kernel_heap.cpp @@ -91,11 +91,6 @@ 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); } diff --git a/zion/object/memory_object.cpp b/zion/object/memory_object.cpp index 9938db6..552f22a 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& page : phys_page_list_) { - page = 0; + for (uint64_t i = 0; i < phys_page_list_.size(); i++) { + phys_page_list_[i] = 0; } } VariableMemoryObject::~VariableMemoryObject() { - for (uint64_t& page : phys_page_list_) { - if (page != 0) { + for (uint64_t p = 0; p < phys_page_list_.size(); p++) { + if (phys_page_list_[p] != 0) { // TODO: We may be able to do some sort of coalescing here. - phys_mem::FreePage(page); + phys_mem::FreePage(phys_page_list_[p]); } } } diff --git a/zion/object/process.cpp b/zion/object/process.cpp index 6fde4f1..8f45086 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 (const auto& t : threads_) { - if (!t->IsDying()) { - t->SetState(Thread::CLEANUP); + for (uint64_t i = 0; i < threads_.size(); i++) { + if (!threads_[i]->IsDying()) { + threads_[i]->SetState(Thread::CLEANUP); } } @@ -93,9 +93,9 @@ void Process::Cleanup() { } // 1. For each thread, call cleanup. - for (const auto& t : threads_) { - if (t->GetState() == Thread::CLEANUP) { - t->Cleanup(); + for (uint64_t i = 0; i < threads_.size(); i++) { + if (threads_[i]->GetState() == Thread::CLEANUP) { + threads_[i]->Cleanup(); } } diff --git a/zion/object/thread.cpp b/zion/object/thread.cpp index fea38f9..701792c 100644 --- a/zion/object/thread.cpp +++ b/zion/object/thread.cpp @@ -51,9 +51,6 @@ 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(); } @@ -123,10 +120,8 @@ void Thread::Cleanup() { // 2. Unblock waiting threads. while (blocked_threads_.size() != 0) { auto thread = blocked_threads_.PopFront(); - if (!thread->IsDying()) { - thread->SetState(Thread::RUNNABLE); - gScheduler->Enqueue(thread); - } + thread->SetState(Thread::RUNNABLE); + gScheduler->Enqueue(thread); } // 3. Release Kernel Stack diff --git a/zion/object/thread.h b/zion/object/thread.h index 6c32007..53bee2b 100644 --- a/zion/object/thread.h +++ b/zion/object/thread.h @@ -29,7 +29,6 @@ class Thread : public KernelObject, public glcr::IntrusiveListNode { RUNNING, RUNNABLE, BLOCKED, - SLEEPING, CLEANUP, FINISHED, }; @@ -70,9 +69,6 @@ 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); @@ -83,7 +79,6 @@ 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 2a21d30..5d745c8 100644 --- a/zion/scheduler/scheduler.cpp +++ b/zion/scheduler/scheduler.cpp @@ -45,11 +45,14 @@ 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. @@ -99,33 +102,9 @@ 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 37aa0b9..823ded8 100644 --- a/zion/scheduler/scheduler.h +++ b/zion/scheduler/scheduler.h @@ -23,23 +23,18 @@ 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/ipc.cpp b/zion/syscall/ipc.cpp index 55c0799..a49e1ed 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 capid : caps) { + for (uint64_t i = 0; i < caps.size(); i++) { // 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(capid); + auto cap = gScheduler->CurrentProcess().GetCapability(caps[i]); 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(capid)); + gScheduler->CurrentProcess().ReleaseCapability(caps[i])); } return message; @@ -156,14 +156,13 @@ glcr::ErrorCode PortPoll(ZPortPollReq* req) { return TranslateIpcMessageToResponse(msg, req); } -glcr::ErrorCode MsiIrqRegister(ZMsiIrqRegisterReq* req) { +glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req) { auto& proc = gScheduler->CurrentProcess(); + glcr::RefPtr port = glcr::MakeRefCounted(); *req->port_cap = proc.AddNewCapability(port); - ASSIGN_OR_RETURN(*req->irq_num, DriverManager::Get().RegisterListener(port)); - - return glcr::OK; + return DriverManager::Get().RegisterListener(req->irq_num, port); } glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req) { @@ -176,7 +175,7 @@ glcr::ErrorCode EndpointSend(ZEndpointSendReq* req) { auto& proc = gScheduler->CurrentProcess(); auto endpoint_cap = proc.GetCapability(req->endpoint_cap); - RET_ERR(ValidateCapability(endpoint_cap, kZionPerm_Write)); + ValidateCapability(endpoint_cap, kZionPerm_Write); auto endpoint = endpoint_cap->obj(); auto reply_port = ReplyPort::Create(); @@ -192,7 +191,7 @@ glcr::ErrorCode EndpointRecv(ZEndpointRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto endpoint_cap = proc.GetCapability(req->endpoint_cap); - RET_ERR(ValidateCapability(endpoint_cap, kZionPerm_Read)); + ValidateCapability(endpoint_cap, kZionPerm_Read); auto endpoint = endpoint_cap->obj(); ASSIGN_OR_RETURN(IpcMessage msg, @@ -203,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_Write)); + ValidateCapability(reply_port_cap, kZionPerm_Read); auto reply_port = reply_port_cap->obj(); ASSIGN_OR_RETURN(IpcMessage message, TranslateRequestToIpcMessage(*req)); @@ -213,7 +212,7 @@ glcr::ErrorCode ReplyPortRecv(ZReplyPortRecvReq* req) { auto& proc = gScheduler->CurrentProcess(); auto reply_port_cap = proc.GetCapability(req->reply_port_cap); - RET_ERR(ValidateCapability(reply_port_cap, kZionPerm_Read)); + ValidateCapability(reply_port_cap, kZionPerm_Read); auto reply_port = reply_port_cap->obj(); ASSIGN_OR_RETURN(IpcMessage msg, diff --git a/zion/syscall/ipc.h b/zion/syscall/ipc.h index 9b0f072..4a3ae97 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 MsiIrqRegister(ZMsiIrqRegisterReq* req); +glcr::ErrorCode IrqRegister(ZIrqRegisterReq* req); glcr::ErrorCode EndpointCreate(ZEndpointCreateReq* req); glcr::ErrorCode EndpointSend(ZEndpointSendReq* req); diff --git a/zion/syscall/syscall.cpp b/zion/syscall/syscall.cpp index 096c931..ac260a5 100644 --- a/zion/syscall/syscall.cpp +++ b/zion/syscall/syscall.cpp @@ -59,7 +59,6 @@ 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); @@ -77,7 +76,7 @@ extern "C" z_err_t SyscallHandler(uint64_t call_id, void* req) { CASE(PortSend); CASE(PortRecv); CASE(PortPoll); - CASE(MsiIrqRegister); + CASE(IrqRegister); CASE(EndpointCreate); CASE(EndpointSend); CASE(EndpointRecv); diff --git a/zion/syscall/thread.cpp b/zion/syscall/thread.cpp index 19f212e..36ca2fe 100644 --- a/zion/syscall/thread.cpp +++ b/zion/syscall/thread.cpp @@ -53,8 +53,3 @@ 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 4abd323..17cc288 100644 --- a/zion/syscall/thread.h +++ b/zion/syscall/thread.h @@ -8,4 +8,3 @@ glcr::ErrorCode ThreadCreate(ZThreadCreateReq* req); glcr::ErrorCode ThreadStart(ZThreadStartReq* req); glcr::ErrorCode ThreadExit(ZThreadExitReq*); glcr::ErrorCode ThreadWait(ZThreadWaitReq* req); -glcr::ErrorCode ThreadSleep(ZThreadSleepReq* req); diff --git a/zion/zion.cpp b/zion/zion.cpp index b2ee2e7..fe9e497 100644 --- a/zion/zion.cpp +++ b/zion/zion.cpp @@ -20,7 +20,6 @@ #include "syscall/syscall.h" extern "C" void zion() { - serial::initialize(9600); dbgln("[boot] Init GDT & IDT."); InitGdt(); InitIdt();