diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 7af67d6d3..7d223c682 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -209,6 +209,46 @@ int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int fl "anon"); } +s32 PS4_SYSV_ABI sceKernelMapDirectMemory2(void** addr, u64 len, s32 type, s32 prot, s32 flags, + s64 phys_addr, u64 alignment) { + LOG_INFO(Kernel_Vmm, + "in_addr = {}, len = {:#x}, type = {:#x}, prot = {:#x}, flags = {:#x}, " + "phys_addr = {:#x}, alignment = {:#x}", + fmt::ptr(*addr), len, type, prot, flags, phys_addr, alignment); + + if (len == 0 || !Common::Is16KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + if (!Common::Is16KBAligned(phys_addr)) { + LOG_ERROR(Kernel_Vmm, "Start address is not 16KB aligned!"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + if (alignment != 0) { + if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) { + LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + } + + const VAddr in_addr = reinterpret_cast(*addr); + const auto mem_prot = static_cast(prot); + const auto map_flags = static_cast(flags); + + auto* memory = Core::Memory::Instance(); + const auto ret = memory->MapMemory(addr, in_addr, len, mem_prot, map_flags, + Core::VMAType::Direct, "anon", false, phys_addr, alignment); + + if (ret == 0) { + memory->SetDirectMemoryType(phys_addr, type); + } + + LOG_INFO(Kernel_Vmm, "out_addr = {}", fmt::ptr(*addr)); + return ret; +} + s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t len, int prot, int flags, const char* name) { @@ -646,6 +686,7 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("yDBwVAolDgg", "libkernel", 1, "libkernel", 1, 1, sceKernelIsStack); LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory); LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory); + LIB_FUNCTION("BQQniolj9tQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory2); LIB_FUNCTION("WFcfL2lzido", "libkernel", 1, "libkernel", 1, 1, sceKernelQueryMemoryProtection); LIB_FUNCTION("BHouLQzh0X0", "libkernel", 1, "libkernel", 1, 1, sceKernelDirectMemoryQuery); LIB_FUNCTION("MBuItvba6z8", "libkernel", 1, "libkernel", 1, 1, sceKernelReleaseDirectMemory); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index ec03d6c5e..13290336c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -783,6 +783,19 @@ int MemoryManager::DirectQueryAvailable(PAddr search_start, PAddr search_end, si return ORBIS_OK; } +s32 MemoryManager::SetDirectMemoryType(s64 phys_addr, s32 memory_type) { + std::scoped_lock lk{mutex}; + + auto& dmem_area = FindDmemArea(phys_addr)->second; + + ASSERT_MSG(phys_addr <= dmem_area.GetEnd() && !dmem_area.is_free, + "Direct memory area is not mapped"); + + dmem_area.memory_type = memory_type; + + return ORBIS_OK; +} + void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) { auto it = FindVMA(virtual_addr); diff --git a/src/core/memory.h b/src/core/memory.h index 4c143ff6f..883b48854 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -219,6 +219,8 @@ public: int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut, void** directMemoryEndOut); + s32 SetDirectMemoryType(s64 phys_addr, s32 memory_type); + void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name); void InvalidateMemory(VAddr addr, u64 size) const;