diff --git a/include/kernel/kernel.hpp b/include/kernel/kernel.hpp index 2384c769..31a6b209 100644 --- a/include/kernel/kernel.hpp +++ b/include/kernel/kernel.hpp @@ -45,6 +45,7 @@ class Kernel { Handle makePort(const char* name); Handle makeSession(Handle port); Handle makeThread(u32 entrypoint, u32 initialSP, u32 priority, s32 id, u32 arg,ThreadStatus status = ThreadStatus::Dormant); + Handle makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission); public: Handle makeEvent(ResetType resetType); // Needs to be public to be accessible to the APT/HID services diff --git a/include/kernel/kernel_types.hpp b/include/kernel/kernel_types.hpp index 282d554a..3e4f510d 100644 --- a/include/kernel/kernel_types.hpp +++ b/include/kernel/kernel_types.hpp @@ -17,13 +17,17 @@ namespace SVCResult { BadHandle = 0xD8E007F7, BadHandleAlt = 0xD9001BF7, + InvalidCombination = 0xE0E01BEE, // Used for invalid memory permission combinations + UnalignedAddr = 0xE0E01BF1, + UnalignedSize = 0xE0E01BF2, + BadThreadPriority = 0xE0E01BFD, PortNameTooLong = 0xE0E0181E, }; } enum class KernelObjectType : u8 { - AddressArbiter, Archive, File, Process, ResourceLimit, Session, Dummy, + AddressArbiter, Archive, File, MemoryBlock, Process, ResourceLimit, Session, Dummy, // Bundle waitable objects together in the enum to let the compiler optimize certain checks better Event, Mutex, Port, Semaphore, Timer, Thread }; @@ -142,6 +146,7 @@ static const char* kernelObjectTypeToString(KernelObjectType t) { case KernelObjectType::Archive: return "archive"; case KernelObjectType::Event: return "event"; case KernelObjectType::File: return "file"; + case KernelObjectType::MemoryBlock: return "memory block"; case KernelObjectType::Port: return "port"; case KernelObjectType::Process: return "process"; case KernelObjectType::ResourceLimit: return "resource limit"; @@ -168,6 +173,17 @@ struct Semaphore { Semaphore(u32 initialCount, u32 maximumCount) : initialCount(initialCount), maximumCount(maximumCount) {} }; +struct MemoryBlock { + u32 addr = 0; + u32 size = 0; + u32 myPermission = 0; + u32 otherPermission = 0; + bool mapped = false; + + MemoryBlock(u32 addr, u32 size, u32 myPerm, u32 otherPerm) : addr(addr), size(size), myPermission(myPerm), otherPermission(otherPerm), + mapped(false) {} +}; + // Generic kernel object class struct KernelObject { Handle handle = 0; // A u32 the OS will use to identify objects diff --git a/include/services/mic.hpp b/include/services/mic.hpp index a83eb5dc..a7af986d 100644 --- a/include/services/mic.hpp +++ b/include/services/mic.hpp @@ -10,6 +10,7 @@ class MICService { MAKE_LOG_FUNCTION(log, micLogger) // Service commands + void mapSharedMem(u32 messagePointer); public: MICService(Memory& mem) : mem(mem) {} diff --git a/src/core/kernel/memory_management.cpp b/src/core/kernel/memory_management.cpp index a6e22c54..3c171231 100644 --- a/src/core/kernel/memory_management.cpp +++ b/src/core/kernel/memory_management.cpp @@ -16,6 +16,21 @@ namespace Operation { }; } +namespace MemoryPermissions { + enum : u32 { + None = 0, // --- + Read = 1, // R-- + Write = 2, // -W- + ReadWrite = 3, // RW- + Execute = 4, // --X + ReadExecute = 5, // R-X + WriteExecute = 6, // -WX + ReadWriteExecute = 7, // RWX + + DontCare = 0x10000000 + }; +} + // Returns whether "value" is aligned to a page boundary (Ie a boundary of 4096 bytes) static constexpr bool isAligned(u32 value) { return (value & 0xFFF) == 0; @@ -32,8 +47,8 @@ void Kernel::controlMemory() { u32 size = regs[3]; u32 perms = regs[4]; - if (perms == 0x10000000) { - perms = 3; // We make "don't care" equivalent to read-write + if (perms == MemoryPermissions::DontCare) { + perms = MemoryPermissions::ReadWrite; // We make "don't care" equivalent to read-write Helpers::panic("Unimplemented allocation permission: DONTCARE"); } @@ -126,13 +141,56 @@ void Kernel::mapMemoryBlock() { regs[0] = SVCResult::Success; } +Handle Kernel::makeMemoryBlock(u32 addr, u32 size, u32 myPermission, u32 otherPermission) { + Handle ret = makeObject(KernelObjectType::MemoryBlock); + objects[ret].data = new MemoryBlock(addr, size, myPermission, otherPermission); + + return ret; +} + void Kernel::createMemoryBlock() { const u32 addr = regs[1]; const u32 size = regs[2]; - const u32 myPermission = regs[3]; - const u32 otherPermission = regs[4]; + u32 myPermission = regs[3]; + u32 otherPermission = mem.read32(regs[13] + 4); // This is placed on the stack rather than r4 logSVC("CreateMemoryBlock (addr = %08X, size = %08X, myPermission = %d, otherPermission = %d)\n", addr, size, myPermission, otherPermission); - regs[0] = SVCResult::Success; regs[1] = 0x66666666; - //Helpers::panic("Kernel::CreateMemoryBlock"); + // Returns whether a permission is valid + auto isPermValid = [](u32 permission) { + switch (permission) { + case MemoryPermissions::None: + case MemoryPermissions::Read: + case MemoryPermissions::Write: + case MemoryPermissions::ReadWrite: + case MemoryPermissions::DontCare: + return true; + + default: // Permissions with the executable flag enabled or invalid permissions are not allowed + return false; + } + }; + + // Throw error if the size of the shared memory block is not aligned to page boundary + if (!isAligned(size)) { + regs[0] = SVCResult::UnalignedSize; + return; + } + + // Throw error if one of the permissions is not valid + if (!isPermValid(myPermission) || !isPermValid(otherPermission)) { + regs[0] = SVCResult::InvalidCombination; + return; + } + + // TODO: The address needs to be in a specific range otherwise it throws an invalid address error + + if (addr == 0) + Helpers::panic("CreateMemoryBlock: Tried to use addr = 0"); + + // Implement "Don't care" permission as RW + if (myPermission == MemoryPermissions::DontCare) myPermission = MemoryPermissions::ReadWrite; + if (otherPermission == MemoryPermissions::DontCare) otherPermission = MemoryPermissions::ReadWrite; + + regs[0] = SVCResult::Success; + regs[1] = makeMemoryBlock(addr, size, myPermission, otherPermission); } \ No newline at end of file diff --git a/src/core/services/mic.cpp b/src/core/services/mic.cpp index 4c4ef2c9..248b5ff5 100644 --- a/src/core/services/mic.cpp +++ b/src/core/services/mic.cpp @@ -2,6 +2,7 @@ namespace MICCommands { enum : u32 { + MapSharedMem = 0x00010042 }; } @@ -16,6 +17,15 @@ void MICService::reset() {} void MICService::handleSyncRequest(u32 messagePointer) { const u32 command = mem.read32(messagePointer); switch (command) { + case MICCommands::MapSharedMem: mapSharedMem(messagePointer); break; default: Helpers::panic("MIC service requested. Command: %08X\n", command); } +} + +void MICService::mapSharedMem(u32 messagePointer) { + u32 size = mem.read32(messagePointer + 4); + u32 handle = mem.read32(messagePointer + 12); + + log("MIC::MapSharedMem (size = %08X, handle = %X) (stubbed)\n", size, handle); + mem.write32(messagePointer + 4, Result::Success); } \ No newline at end of file