diff --git a/lib/mammoth/ipc/port_client.cpp b/lib/mammoth/ipc/port_client.cpp index 9bb5525..3c9f909 100644 --- a/lib/mammoth/ipc/port_client.cpp +++ b/lib/mammoth/ipc/port_client.cpp @@ -15,4 +15,8 @@ glcr::ErrorCode PortClient::WriteString(glcr::String str, z_cap_t cap) { ZPortSend(port_cap_, str.length() + 1, str.cstr(), 1, &cap)); } +glcr::ErrorCode PortClient::WriteByte(uint8_t byte) { + return static_cast( + ZPortSend(port_cap_, 1, &byte, 0, nullptr)); +} } // namespace mmth diff --git a/lib/mammoth/ipc/port_client.h b/lib/mammoth/ipc/port_client.h index 3a38ee6..80571a3 100644 --- a/lib/mammoth/ipc/port_client.h +++ b/lib/mammoth/ipc/port_client.h @@ -17,6 +17,8 @@ class PortClient { glcr::ErrorCode WriteString(glcr::String str, z_cap_t cap); + glcr::ErrorCode WriteByte(uint8_t byte); + z_cap_t cap() { return port_cap_; } bool empty() { return port_cap_ == 0; } diff --git a/lib/mammoth/ipc/port_server.h b/lib/mammoth/ipc/port_server.h index e49642a..997c134 100644 --- a/lib/mammoth/ipc/port_server.h +++ b/lib/mammoth/ipc/port_server.h @@ -9,6 +9,7 @@ namespace mmth { class PortServer { public: + PortServer() {} static glcr::ErrorOr Create(); static PortServer AdoptCap(z_cap_t cap); diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 3c22374..e2eb139 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -3,6 +3,7 @@ set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") add_subdirectory(denali) add_subdirectory(teton) add_subdirectory(victoriafalls) +add_subdirectory(voyageurs) add_subdirectory(yellowstone) set(SYS_BUNDLE diff --git a/sys/voyageurs/CMakeLists.txt b/sys/voyageurs/CMakeLists.txt new file mode 100644 index 0000000..10a3754 --- /dev/null +++ b/sys/voyageurs/CMakeLists.txt @@ -0,0 +1,23 @@ +add_executable(voyageurs + keyboard/keyboard_driver.cpp + voyageurs_server.cpp + voyageurs.cpp) + +target_include_directories(voyageurs + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(voyageurs + glacier + mammoth + voyageurs_yunq + yellowstone_yunq + ) + +set_target_properties(voyageurs PROPERTIES + COMPILE_FLAGS "${CMAKE_CXX_FLAGS} ${BASE_COMPILE_FLAGS}" + LINK_FLAGS "${CMAKE_EXE_LINK_FLAGS} ${BASE_LINK_FLAGS}" + ) + +install(TARGETS voyageurs) + +yunq_gen(lib/voyageurs lib voyageurs) diff --git a/sys/voyageurs/keyboard/keyboard_driver.cpp b/sys/voyageurs/keyboard/keyboard_driver.cpp new file mode 100644 index 0000000..924d96a --- /dev/null +++ b/sys/voyageurs/keyboard/keyboard_driver.cpp @@ -0,0 +1,34 @@ +#include "keyboard/keyboard_driver.h" + +#include + +void InterruptEnter(void* void_keyboard) { + KeyboardDriver* keyboard = static_cast(void_keyboard); + + keyboard->InterruptLoop(); +} + +KeyboardDriver::KeyboardDriver() { check(ZIrqRegister(kZIrqKbd, &irq_cap_)); } + +void KeyboardDriver::RegisterListener(uint64_t port_cap) { + listeners_.PushFront(mmth::PortClient::AdoptPort(port_cap)); +} + +Thread KeyboardDriver::StartInterruptLoop() { + return Thread(InterruptEnter, this); +} + +void KeyboardDriver::InterruptLoop() { + dbgln("Interrupt"); + while (true) { + uint8_t scancode; + uint64_t num_bytes = 1; + uint64_t num_caps = 0; + check(ZPortRecv(irq_cap_, &num_bytes, &scancode, &num_caps, nullptr)); + dbgln("Scan {x}", scancode); + + for (mmth::PortClient& client : listeners_) { + client.WriteByte(scancode); + } + } +} diff --git a/sys/voyageurs/keyboard/keyboard_driver.h b/sys/voyageurs/keyboard/keyboard_driver.h new file mode 100644 index 0000000..b38af0e --- /dev/null +++ b/sys/voyageurs/keyboard/keyboard_driver.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include + +class KeyboardDriver { + public: + KeyboardDriver(); + KeyboardDriver(const KeyboardDriver&) = delete; + KeyboardDriver(KeyboardDriver&&) = delete; + + void RegisterListener(uint64_t port_cap); + + Thread StartInterruptLoop(); + void InterruptLoop(); + + private: + z_cap_t irq_cap_; + glcr::LinkedList listeners_; +}; diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq b/sys/voyageurs/lib/voyageurs/voyageurs.yunq new file mode 100644 index 0000000..4d59744 --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq @@ -0,0 +1,12 @@ +interface Voyageurs { + method RegisterKeyboardListener(KeyboardListener) -> (None); +} + +message KeyboardListener { + capability port_capability; +} + +message None { + +} + diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.cpp new file mode 100644 index 0000000..80703fd --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.cpp @@ -0,0 +1,41 @@ +// Generated file - DO NOT MODIFY +#include "voyageurs.yunq.client.h" + +#include +#include +#include + + + + +glcr::ErrorCode VoyageursClient::RegisterKeyboardListener(const KeyboardListener& request, None& 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; +} + + diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.h new file mode 100644 index 0000000..2fea9ba --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.client.h @@ -0,0 +1,28 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#include +#include +#include +#include + +#include "voyageurs.yunq.h" + +class VoyageursClient { + public: + VoyageursClient(z_cap_t Voyageurs_cap) : endpoint_(Voyageurs_cap) {} + VoyageursClient(const VoyageursClient&) = delete; + VoyageursClient(VoyageursClient&& other) : endpoint_(other.endpoint_) {other.endpoint_ = 0;}; + + z_cap_t Capability() { return endpoint_; } + + + [[nodiscard]] glcr::ErrorCode RegisterKeyboardListener(const KeyboardListener& request, None& 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/voyageurs/lib/voyageurs/voyageurs.yunq.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp new file mode 100644 index 0000000..22394d7 --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.cpp @@ -0,0 +1,110 @@ +// Generated file -- DO NOT MODIFY. +#include "voyageurs.yunq.h" + +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 KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + ParseFromBytesInternal(bytes, offset); + // Parse port_capability. + // FIXME: Implement in-buffer capabilities for inprocess serialization. + set_port_capability(0); +} + +void KeyboardListener::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); + // Parse port_capability. + uint64_t port_capability_ptr = bytes.At(offset + header_size + (8 * 0)); + + set_port_capability(caps.At(port_capability_ptr)); +} + +void KeyboardListener::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + // Parse port_capability. + // Skip Cap. + +} + +uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + // 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. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +uint64_t KeyboardListener::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + uint32_t next_extension = header_size + 8 * 1; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; + // Write port_capability. + caps.WriteAt(next_cap, port_capability()); + bytes.WriteAt(offset + header_size + (8 * 0), next_cap++); + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} +void None::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset) { + ParseFromBytesInternal(bytes, offset); +} + +void None::ParseFromBytes(const glcr::ByteBuffer& bytes, uint64_t offset, const glcr::CapBuffer& caps) { + ParseFromBytesInternal(bytes, offset); +} + +void None::ParseFromBytesInternal(const glcr::ByteBuffer& bytes, uint64_t offset) { + CheckHeader(bytes); + +} + +uint64_t None::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset) const { + uint32_t next_extension = header_size + 8 * 0; + const uint32_t core_size = next_extension; + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} + +uint64_t None::SerializeToBytes(glcr::ByteBuffer& bytes, uint64_t offset, glcr::CapBuffer& caps) const { + uint32_t next_extension = header_size + 8 * 0; + const uint32_t core_size = next_extension; + uint64_t next_cap = 0; + + // The next extension pointer is the length of the message. + WriteHeader(bytes, offset, core_size, next_extension); + + return next_extension; +} \ No newline at end of file diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h new file mode 100644 index 0000000..4961d5e --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.h @@ -0,0 +1,45 @@ +// Generated file - DO NOT MODIFY +#pragma once + +#include +#include +#include +#include +#include +class KeyboardListener { + public: + KeyboardListener() {} + // Delete copy and move until implemented. + KeyboardListener(const KeyboardListener&) = delete; + KeyboardListener(KeyboardListener&&) = 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 z_cap_t& port_capability() const { 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. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; +class None { + public: + None() {} + // Delete copy and move until implemented. + None(const None&) = delete; + None(None&&) = 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; + + private: + + // Parses everything except for caps. + void ParseFromBytesInternal(const glcr::ByteBuffer&, uint64_t offset); +}; \ No newline at end of file diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp new file mode 100644 index 0000000..f21e594 --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.cpp @@ -0,0 +1,105 @@ +// Generated file -- DO NOT MODIFY. +#include "voyageurs.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 VoyageursServerBaseThreadBootstrap(void* server_base) { + ((VoyageursServerBase*)server_base)->ServerThread(); +} + +glcr::ErrorOr VoyageursServerBase::CreateClient() { + uint64_t client_cap; + RET_ERR(ZCapDuplicate(endpoint_, ~(kZionPerm_Read), &client_cap)); + return VoyageursClient(client_cap); +} + +Thread VoyageursServerBase::RunServer() { + return Thread(VoyageursServerBaseThreadBootstrap, this); +} + +void VoyageursServerBase::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 VoyageursServerBase::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: { + KeyboardListener yunq_request; + None yunq_response; + + yunq_request.ParseFromBytes(request, kHeaderSize, req_caps); + + RET_ERR(HandleRegisterKeyboardListener(yunq_request, yunq_response)); + + resp_length = yunq_response.SerializeToBytes(response, kHeaderSize, resp_caps); + break; + } + default: { + return glcr::UNIMPLEMENTED; + } + } + return glcr::OK; +} diff --git a/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.h b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.h new file mode 100644 index 0000000..7781c61 --- /dev/null +++ b/sys/voyageurs/lib/voyageurs/voyageurs.yunq.server.h @@ -0,0 +1,37 @@ +// Generated File -- DO NOT MODIFY. +#pragma once + +#include +#include +#include + +#include "voyageurs.yunq.h" +#include "voyageurs.yunq.client.h" + + + +class VoyageursServerBase { + public: + VoyageursServerBase(z_cap_t Voyageurs_cap) : endpoint_(Voyageurs_cap) {} + VoyageursServerBase(const VoyageursServerBase&) = delete; + VoyageursServerBase(VoyageursServerBase&&) = delete; + + glcr::ErrorOr CreateClient(); + + [[nodiscard]] Thread RunServer(); + + + [[nodiscard]] virtual glcr::ErrorCode HandleRegisterKeyboardListener(const KeyboardListener&, None&) = 0; + + + private: + z_cap_t endpoint_; + + friend void VoyageursServerBaseThreadBootstrap(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); +}; + diff --git a/sys/voyageurs/voyageurs.cpp b/sys/voyageurs/voyageurs.cpp new file mode 100644 index 0000000..ece9afd --- /dev/null +++ b/sys/voyageurs/voyageurs.cpp @@ -0,0 +1,27 @@ + +#include +#include + +#include "keyboard/keyboard_driver.h" +#include "voyageurs_server.h" + +uint64_t main(uint64_t init_port) { + ParseInitPort(init_port); + + dbgln("Initializing PS/2 Driver."); + KeyboardDriver driver; + + dbgln("Starting PS/2 Thread."); + Thread keyboard_thread = driver.StartInterruptLoop(); + + dbgln("Starting voyaguers server."); + ASSIGN_OR_RETURN(glcr::UniquePtr server, + VoyageursServer::Create(driver)); + + Thread server_thread = server->RunServer(); + + check(server_thread.Join()); + check(keyboard_thread.Join()); + + return glcr::OK; +} diff --git a/sys/voyageurs/voyageurs_server.cpp b/sys/voyageurs/voyageurs_server.cpp new file mode 100644 index 0000000..93f31d7 --- /dev/null +++ b/sys/voyageurs/voyageurs_server.cpp @@ -0,0 +1,19 @@ +#include "voyageurs_server.h" + +glcr::ErrorOr> VoyageursServer::Create( + KeyboardDriver& keyboard_driver) { + z_cap_t cap; + RET_ERR(ZEndpointCreate(&cap)); + return glcr::UniquePtr( + new VoyageursServer(cap, keyboard_driver)); +} + +glcr::ErrorCode VoyageursServer::HandleRegisterKeyboardListener( + const KeyboardListener& listener, None&) { + keyboard_driver_.RegisterListener(listener.port_capability()); + return glcr::OK; +} + +VoyageursServer::VoyageursServer(z_cap_t voyageurs_cap, + KeyboardDriver& keyboard_driver) + : VoyageursServerBase(voyageurs_cap), keyboard_driver_(keyboard_driver) {} diff --git a/sys/voyageurs/voyageurs_server.h b/sys/voyageurs/voyageurs_server.h new file mode 100644 index 0000000..d95a272 --- /dev/null +++ b/sys/voyageurs/voyageurs_server.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "keyboard/keyboard_driver.h" +#include "voyageurs/voyageurs.yunq.server.h" + +class VoyageursServer : public VoyageursServerBase { + public: + static glcr::ErrorOr> Create( + KeyboardDriver& keyboard_driver); + + virtual glcr::ErrorCode HandleRegisterKeyboardListener( + const KeyboardListener& listener, None&) override; + + private: + KeyboardDriver& keyboard_driver_; + VoyageursServer(z_cap_t voyageurs_cap, KeyboardDriver& keyboard_driver); +}; diff --git a/sysroot/init.txt b/sysroot/init.txt index 00a31bd..74ca826 100644 --- a/sysroot/init.txt +++ b/sysroot/init.txt @@ -1,2 +1,3 @@ +voyageurs teton