#include "pmem.hpp" #include "IoDevice.hpp" #include "KernelAllocator.hpp" #include "KernelObject.hpp" #include "error.hpp" #include "error/ErrorCode.hpp" #include "file.hpp" #include "kernel/KernelObject.hpp" #include "kernel/MemoryResource.hpp" #include "rx/AddressRange.hpp" #include "rx/Rc.hpp" #include "rx/print.hpp" #include "vmem.hpp" #include #include struct PhysicalMemoryAllocation { bool allocated = false; [[nodiscard]] bool isAllocated() const { return allocated; } [[nodiscard]] bool isRelated(const PhysicalMemoryAllocation &left, rx::AddressRange, rx::AddressRange) const { return allocated == left.allocated; } [[nodiscard]] PhysicalMemoryAllocation merge(const PhysicalMemoryAllocation &other, rx::AddressRange, rx::AddressRange) const { assert(other.allocated == allocated); return other; } bool operator==(const PhysicalMemoryAllocation &) const = default; }; using MappableMemoryResource = kernel::MappableResource; using PhysicalMemoryResource = kernel::AllocableResource; static auto g_pmemInstance = orbis::createGlobalObject< kernel::LockableKernelObject>(); struct PhysicalMemory : orbis::IoDevice { orbis::File file; PhysicalMemory() { incRef(); // do not delete global object file.device = this; file.incRef(); // do not delete property } orbis::ErrorCode open(rx::Ref *file, const char *path, std::uint32_t flags, std::uint32_t mode, orbis::Thread *thread) override { rx::die("open PhysicalMemory device"); } orbis::ErrorCode map(rx::AddressRange range, std::int64_t offset, rx::EnumBitSet protection, orbis::File *, orbis::Process *) override { return orbis::pmem::map( range.beginAddress(), rx::AddressRange::fromBeginSize(offset, range.size()), orbis::vmem::toCpuProtection(protection)); } void serialize(rx::Serializer &s) const {} void deserialize(rx::Deserializer &s) {} }; static auto g_phyMemory = orbis::createGlobalObject(); orbis::ErrorCode orbis::pmem::initialize(std::uint64_t size) { std::lock_guard lock(*g_pmemInstance); rx::println("pmem: {:x}", size); return toErrorCode( g_pmemInstance->create(rx::AddressRange::fromBeginSize(0, size))); } void orbis::pmem::destroy() { std::lock_guard lock(*g_pmemInstance); g_pmemInstance->destroy(); } std::pair orbis::pmem::allocate(std::uint64_t addressHint, std::uint64_t size, rx::EnumBitSet flags, std::uint64_t alignment) { std::lock_guard lock(*g_pmemInstance); PhysicalMemoryAllocation allocation{.allocated = true}; auto [it, errc, range] = g_pmemInstance->map(addressHint, size, allocation, flags, alignment); if (errc != std::errc{}) { return {{}, toErrorCode(errc)}; } return {range, {}}; } orbis::ErrorCode orbis::pmem::deallocate(rx::AddressRange range) { std::lock_guard lock(*g_pmemInstance); PhysicalMemoryAllocation allocation{}; auto [it, errc, _] = g_pmemInstance->map(range.beginAddress(), range.size(), allocation, AllocationFlags::Fixed, 1); return toErrorCode(errc); } std::optional orbis::pmem::query(std::uint64_t address) { std::lock_guard lock(*g_pmemInstance); auto result = g_pmemInstance->query(address); if (result == g_pmemInstance->end()) { return {}; } return result.range(); } orbis::ErrorCode orbis::pmem::map(std::uint64_t virtualAddress, rx::AddressRange range, rx::EnumBitSet protection) { auto virtualRange = rx::AddressRange::fromBeginSize(virtualAddress, range.size()); auto errc = g_pmemInstance->mappable.map(virtualRange, range.beginAddress(), protection, vmem::kPageSize); return toErrorCode(errc); } std::size_t orbis::pmem::getSize() { return g_pmemInstance->size; } orbis::IoDevice *orbis::pmem::getDevice() { return g_phyMemory.get(); } orbis::File *orbis::pmem::getFile() { return &g_phyMemory->file; }