diff --git a/lib/mammoth/include/mammoth/process.h b/lib/mammoth/include/mammoth/process.h index 33113c6..477f0fb 100644 --- a/lib/mammoth/include/mammoth/process.h +++ b/lib/mammoth/include/mammoth/process.h @@ -2,4 +2,6 @@ #include -uint64_t SpawnProcessFromElfRegion(uint64_t program); +#include "mammoth/channel.h" + +uint64_t SpawnProcessFromElfRegion(uint64_t program, Channel& local); diff --git a/lib/mammoth/src/channel.cpp b/lib/mammoth/src/channel.cpp index 191c1ff..07dcbfd 100644 --- a/lib/mammoth/src/channel.cpp +++ b/lib/mammoth/src/channel.cpp @@ -33,7 +33,7 @@ z_err_t Channel::WriteStr(const char* msg) { if (!chan_cap_) { return Z_ERR_NULL; } - uint64_t type = 11; + uint64_t type = 0; return ZChannelSend(chan_cap_, type, strlen(msg), reinterpret_cast(msg), 0, 0); } diff --git a/lib/mammoth/src/process.cpp b/lib/mammoth/src/process.cpp index cd273d3..883e290 100644 --- a/lib/mammoth/src/process.cpp +++ b/lib/mammoth/src/process.cpp @@ -93,8 +93,8 @@ uint64_t LoadElfProgram(uint64_t base, uint64_t as_cap) { } // namespace -uint64_t SpawnProcessFromElfRegion(uint64_t program) { - Channel local, foreign; +uint64_t SpawnProcessFromElfRegion(uint64_t program, Channel& local) { + Channel foreign; check(CreateChannels(local, foreign)); #if MAM_PROC_DEBUG @@ -118,7 +118,5 @@ uint64_t SpawnProcessFromElfRegion(uint64_t program) { #endif check(ZThreadStart(thread_cap, entry_point, foreign_chan_id, 0)); - local.WriteStr("Hello!"); - return Z_OK; } diff --git a/sys/denali/CMakeLists.txt b/sys/denali/CMakeLists.txt index 8c03131..49d0355 100644 --- a/sys/denali/CMakeLists.txt +++ b/sys/denali/CMakeLists.txt @@ -1,11 +1,14 @@ add_executable(denali ahci/ahci_device.cpp ahci/ahci_driver.cpp - denali.cpp) + denali.cpp + denali_server.cpp + ) target_include_directories(denali - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include") target_link_libraries(denali cxx diff --git a/sys/denali/ahci/ahci_device.cpp b/sys/denali/ahci/ahci_device.cpp index c8e5d1d..a7d43f4 100644 --- a/sys/denali/ahci/ahci_device.cpp +++ b/sys/denali/ahci/ahci_device.cpp @@ -74,7 +74,7 @@ z_err_t AhciDevice::SendIdentify() { memcpy(command_table_->command_fis, &fis, sizeof(fis)); commands_[0].region = MappedMemoryRegion::ContiguousPhysical(512); - commands_[0].callback = HandleIdent; + // commands_[0].callback = HandleIdent; command_table_->prds[0].region_address = commands_[0].region.paddr(); command_table_->prds[0].byte_count = 512; @@ -119,7 +119,7 @@ void AhciDevice::HandleIrq() { for (uint64_t i = 0; i < 32; i++) { if (commands_finished & (1 << i)) { - commands_[i].callback(this); + // commands_[i].callback(this); commands_issued_ &= ~(1 << i); } } diff --git a/sys/denali/ahci/ahci_device.h b/sys/denali/ahci/ahci_device.h index f815427..b0ebe2b 100644 --- a/sys/denali/ahci/ahci_device.h +++ b/sys/denali/ahci/ahci_device.h @@ -29,9 +29,8 @@ class AhciDevice { CommandTable* command_table_ = nullptr; struct Command { - typedef void (*Callback)(AhciDevice*); MappedMemoryRegion region; - Callback callback; + // std::function callback; }; Command commands_[32]; uint32_t commands_issued_ = 0; diff --git a/sys/denali/ahci/ahci_driver.cpp b/sys/denali/ahci/ahci_driver.cpp index 2b88a3c..753caf0 100644 --- a/sys/denali/ahci/ahci_driver.cpp +++ b/sys/denali/ahci/ahci_driver.cpp @@ -33,6 +33,19 @@ z_err_t AhciDriver::Init() { return Z_OK; } +z_err_t AhciDriver::GetDevice(uint64_t id, AhciDevice& device) { + if (id >= 32) { + return Z_ERR_INVALID; + } + + if (!devices_[id].IsInit()) { + return Z_ERR_NOT_FOUND; + } + + device = devices_[id]; + return Z_OK; +} + void AhciDriver::DumpCapabilities() { dbgln("AHCI Capabilities:"); uint32_t caps = ahci_hba_->capabilities; diff --git a/sys/denali/ahci/ahci_driver.h b/sys/denali/ahci/ahci_driver.h index 173790e..5af934a 100644 --- a/sys/denali/ahci/ahci_driver.h +++ b/sys/denali/ahci/ahci_driver.h @@ -12,6 +12,8 @@ class AhciDriver { void InterruptLoop(); + z_err_t GetDevice(uint64_t id, AhciDevice& device); + void DumpCapabilities(); void DumpPorts(); diff --git a/sys/denali/denali.cpp b/sys/denali/denali.cpp index 3a43fc2..cc5066c 100644 --- a/sys/denali/denali.cpp +++ b/sys/denali/denali.cpp @@ -1,13 +1,16 @@ +#include #include #include #include "ahci/ahci_driver.h" +#include "denali_server.h" int main(uint64_t bootstrap_cap) { AhciDriver driver; RET_ERR(driver.Init()); - while (1) { - }; + DenaliServer server(bootstrap_cap, driver); + RET_ERR(server.RunServer()); + // FIXME: Add thread join. return 0; } diff --git a/sys/denali/denali_server.cpp b/sys/denali/denali_server.cpp new file mode 100644 index 0000000..b21049f --- /dev/null +++ b/sys/denali/denali_server.cpp @@ -0,0 +1,44 @@ +#include "denali_server.h" + +#include +#include + +DenaliServer::DenaliServer(uint64_t channel_cap, AhciDriver& driver) + : channel_cap_(channel_cap), driver_(driver) {} + +z_err_t DenaliServer::RunServer() { + while (true) { + uint64_t buff_size = kBuffSize; + uint64_t cap_size = 0; + uint64_t type = DENALI_INVALID; + RET_ERR(ZChannelRecv(channel_cap_, buff_size, read_buffer_, 0, nullptr, + &type, &buff_size, &cap_size)); + switch (type) { + case Z_INVALID: + dbgln(reinterpret_cast(read_buffer_)); + break; + case DENALI_READ: { + DenaliRead* read_req = reinterpret_cast(read_buffer_); + uint64_t memcap = 0; + DenaliReadResponse resp; + RET_ERR(HandleRead(*read_req, resp, memcap)); + uint64_t caps_len = memcap ? 1 : 0; + RET_ERR(ZChannelSend(channel_cap_, 0, sizeof(DenaliReadResponse), + reinterpret_cast(&resp), caps_len, + &memcap)); + break; + } + default: + dbgln("Invalid message type."); + return Z_ERR_UNIMPLEMENTED; + } + } +} + +z_err_t DenaliServer::HandleRead(const DenaliRead& read, + DenaliReadResponse& resp, uint64_t& memcap) { + AhciDevice device; + RET_ERR(driver_.GetDevice(read.device_id, device)); + + return Z_OK; +} diff --git a/sys/denali/denali_server.h b/sys/denali/denali_server.h new file mode 100644 index 0000000..dc2fedd --- /dev/null +++ b/sys/denali/denali_server.h @@ -0,0 +1,21 @@ +#pragma once + +#include "ahci/ahci_driver.h" +#include "denali/denali.h" + +class DenaliServer { + public: + DenaliServer(uint64_t channel_cap, AhciDriver& driver); + + z_err_t RunServer(); + + private: + static const uint64_t kBuffSize = 1024; + uint64_t channel_cap_; + uint8_t read_buffer_[kBuffSize]; + + AhciDriver& driver_; + + z_err_t HandleRead(const DenaliRead& read, DenaliReadResponse& resp, + uint64_t& mem_cap); +}; diff --git a/sys/denali/include/denali/denali.h b/sys/denali/include/denali/denali.h new file mode 100644 index 0000000..ba51636 --- /dev/null +++ b/sys/denali/include/denali/denali.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#define DENALI_INVALID 0 +#define DENALI_READ 100 + +struct DenaliRead { + uint64_t device_id; + + uint64_t lba; + uint64_t size; +}; + +// Will also include a memory capability. +struct DenaliReadResponse { + uint64_t device_id; + uint64_t lba; + uint64_t size; +}; diff --git a/sys/yellowstone/CMakeLists.txt b/sys/yellowstone/CMakeLists.txt index d84f031..9e0b3ae 100644 --- a/sys/yellowstone/CMakeLists.txt +++ b/sys/yellowstone/CMakeLists.txt @@ -3,7 +3,8 @@ add_executable(yellowstone yellowstone.cpp ) target_include_directories(yellowstone - PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + "${CMAKE_CURRENT_SOURCE_DIR}/../denali/include/") target_link_libraries(yellowstone cxx diff --git a/sys/yellowstone/yellowstone.cpp b/sys/yellowstone/yellowstone.cpp index 1598394..5a0e145 100644 --- a/sys/yellowstone/yellowstone.cpp +++ b/sys/yellowstone/yellowstone.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -8,7 +10,10 @@ uint64_t main() { dbgln("Yellowstone Initializing."); uint64_t vaddr; check(ZAddressSpaceMap(Z_INIT_VMAS_SELF, 0, Z_INIT_BOOT_VMMO, &vaddr)); - check(SpawnProcessFromElfRegion(vaddr)); + + Channel local; + check(SpawnProcessFromElfRegion(vaddr, local)); + local.WriteStr("Hello!"); DumpPciEDevices(); diff --git a/zion/lib/shared_ptr.h b/zion/lib/shared_ptr.h new file mode 100644 index 0000000..8c26a31 --- /dev/null +++ b/zion/lib/shared_ptr.h @@ -0,0 +1,89 @@ +#pragma once + +#include + +#include "debug/debug.h" + +template +class SharedPtr { + public: + SharedPtr() : init_(false), ptr_(0), ref_cnt_(0) {} + // Takes ownership. + SharedPtr(T* ptr) { + ptr_ = ptr; + ref_cnt_ = new uint64_t(1); + } + + SharedPtr(const SharedPtr& other) + : init_(other.init_), ptr_(other.ptr_), ref_cnt_(other.ref_cnt_) { + (*ref_cnt_)++; + } + + SharedPtr& operator=(const SharedPtr& other) { + Cleanup(); + init_ = other.init_; + ptr_ = other.ptr_; + ref_cnt_ = other.ref_cnt_; + (*ref_cnt_)++; + return *this; + } + + ~SharedPtr() { Cleanup(); } + + T& operator*() { + CheckValid(); + return *ptr_; + } + const T& operator*() const { + CheckValid(); + return *ptr_; + } + T* operator->() { + CheckValid(); + return ptr_; + } + const T* operator->() const { + CheckValid(); + return ptr_; + } + + T* ptr() { + CheckValid(); + return ptr_; + } + + bool operator==(const SharedPtr& other) { + CheckValid(); + other.CheckValid(); + return ptr_ == other.ptr_; + } + + bool empty() { return !init_; } + + private: + bool init_ = true; + T* ptr_; + uint64_t* ref_cnt_; + + void Cleanup() { + if (!init_) { + return; + } + if (--(*ref_cnt_) == 0) { + dbgln("Deleting shared ptr: %m", ptr_); + delete ptr_; + delete ref_cnt_; + } + } + + void CheckValid() const { + if (!init_) { + panic("Accessing invalid shared ptr"); + } + } +}; + +template +SharedPtr MakeShared(A... args) { + return {new T(args...)}; +} diff --git a/zion/object/channel.cpp b/zion/object/channel.cpp index 890ae7a..e7513d5 100644 --- a/zion/object/channel.cpp +++ b/zion/object/channel.cpp @@ -1,6 +1,7 @@ #include "object/channel.h" #include "include/zerrors.h" +#include "scheduler/scheduler.h" Pair, RefPtr> Channel::CreateChannelPair() { auto c1 = MakeRefCounted(); @@ -15,21 +16,35 @@ z_err_t Channel::Write(const ZMessage& msg) { } z_err_t Channel::Read(ZMessage& msg) { - if (pending_messages_.size() == 0) { - dbgln("Unimplemented add blocking."); - return Z_ERR_UNIMPLEMENTED; + mutex_.Lock(); + while (pending_messages_.size() == 0) { + blocked_threads_.PushBack(gScheduler->CurrentThread()); + mutex_.Unlock(); + gScheduler->Yield(); + mutex_.Lock(); } - Message next_msg = pending_messages_.PeekFront(); - if (next_msg.num_bytes > msg.num_bytes) { + mutex_.Unlock(); + + MutexHolder lock(mutex_); + auto next_msg = pending_messages_.PeekFront(); + if (next_msg->num_bytes > msg.num_bytes) { + return Z_ERR_BUFF_SIZE; + } + if (next_msg->caps.size() > msg.num_caps) { return Z_ERR_BUFF_SIZE; } - msg.type = next_msg.type; - msg.num_bytes = next_msg.num_bytes; - msg.num_caps = 0; + msg.type = next_msg->type; + msg.num_bytes = next_msg->num_bytes; for (uint64_t i = 0; i < msg.num_bytes; i++) { - msg.bytes[i] = next_msg.bytes[i]; + msg.bytes[i] = next_msg->bytes[i]; + } + + msg.num_caps = next_msg->caps.size(); + auto& proc = gScheduler->CurrentProcess(); + for (uint64_t i = 0; i < msg.num_caps; i++) { + msg.caps[i] = proc.AddCapability(next_msg->caps.PopFront()); } pending_messages_.PopFront(); @@ -38,24 +53,36 @@ z_err_t Channel::Read(ZMessage& msg) { } z_err_t Channel::EnqueueMessage(const ZMessage& msg) { - if (msg.num_caps > 0) { - dbgln("Unimplemented passing caps on channel"); - return Z_ERR_UNIMPLEMENTED; - } - if (msg.num_bytes > 0x1000) { dbgln("Large message size unimplemented: %x", msg.num_bytes); return Z_ERR_INVALID; } - Message message{ - .type = msg.type, - .num_bytes = msg.num_bytes, - .bytes = new uint8_t[msg.num_bytes], - }; + auto message = MakeShared(); + message->type = msg.type; + + // Copy Message body. + message->num_bytes = msg.num_bytes; + message->bytes = new uint8_t[msg.num_bytes]; for (uint64_t i = 0; i < msg.num_bytes; i++) { - message.bytes[i] = msg.bytes[i]; + message->bytes[i] = msg.bytes[i]; } + + // Release and store capabilities. + for (uint64_t i = 0; i < msg.num_caps; i++) { + auto cap = gScheduler->CurrentProcess().ReleaseCapability(msg.caps[i]); + if (!cap) { + return Z_ERR_CAP_NOT_FOUND; + } + message->caps.PushBack(cap); + } + + // Enqueue. + MutexHolder lock(mutex_); pending_messages_.PushBack(message); + + if (blocked_threads_.size() > 0) { + gScheduler->Enqueue(blocked_threads_.PopFront()); + } return Z_OK; } diff --git a/zion/object/channel.h b/zion/object/channel.h index 3f9a12c..b9ba8d3 100644 --- a/zion/object/channel.h +++ b/zion/object/channel.h @@ -3,8 +3,10 @@ #include "capability/capability.h" #include "include/zerrors.h" #include "lib/linked_list.h" +#include "lib/mutex.h" #include "lib/pair.h" #include "lib/ref_ptr.h" +#include "lib/shared_ptr.h" #include "object/kernel_object.h" #include "usr/zcall_internal.h" @@ -22,16 +24,21 @@ class Channel : public KernelObject { // circular dependency. RefPtr peer_{nullptr}; + Mutex mutex_{"channel"}; + struct Message { uint64_t type; uint64_t num_bytes; uint8_t* bytes; + + LinkedList> caps; }; // FIXME: This is probably dangerous because of an // implicit shallow copy. - LinkedList pending_messages_; + LinkedList> pending_messages_; + LinkedList> blocked_threads_; friend class MakeRefCountedFriend; Channel() {} diff --git a/zion/object/process.cpp b/zion/object/process.cpp index 6218856..e049df8 100644 --- a/zion/object/process.cpp +++ b/zion/object/process.cpp @@ -76,7 +76,7 @@ RefPtr Process::ReleaseCapability(uint64_t cid) { } ++iter; } - dbgln("Bad cap access"); + dbgln("Bad cap release: %u", cid); dbgln("Num caps: %u", caps_.size()); return {}; } @@ -90,7 +90,7 @@ RefPtr Process::GetCapability(uint64_t cid) { } ++iter; } - dbgln("Bad cap access"); + dbgln("Bad cap access %u", cid); dbgln("Num caps: %u", caps_.size()); return {}; }