diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index f44d928b..a7f619f1 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -405,6 +405,9 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("VOx8NGmHXTs", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCpumode); LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate); + LIB_FUNCTION("2SKEx6bSq-4", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap); + LIB_FUNCTION("kBJzF8x4SyE", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap2); + // equeue LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue); LIB_FUNCTION("jpFjmgAC5AE", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEqueue); diff --git a/src/core/libraries/kernel/memory_management.cpp b/src/core/libraries/kernel/memory_management.cpp index cdee3f46..e0509fb4 100644 --- a/src/core/libraries/kernel/memory_management.cpp +++ b/src/core/libraries/kernel/memory_management.cpp @@ -3,6 +3,7 @@ #include #include "common/alignment.h" +#include "common/assert.h" #include "common/logging/log.h" #include "common/singleton.h" #include "core/libraries/error_codes.h" @@ -225,4 +226,51 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut directMemoryEndOut); } +s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries, + int* numEntriesOut) { + return sceKernelBatchMap2(entries, numEntries, numEntriesOut, 0x10); // 0x10 : Fixed / 0x410 +} + +int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len); + +s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEntries, + int* numEntriesOut, int flags) { + int processed = 0; + int result = 0; + for (int i = 0; i < numEntries; i++) { + if (entries == nullptr || entries[i].length == 0 || entries[i].operation > 4) { + result = ORBIS_KERNEL_ERROR_EINVAL; + break; // break and assign a value to numEntriesOut. + } + + if (entries[i].operation == 0) { // MAP_DIRECT + result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length, + entries[i].protection, flags, + static_cast(entries[i].offset), 0, ""); + LOG_INFO( + Kernel_Vmm, + "BatchMap: entry = {}, operation = {}, len = {:#x}, offset = {:#x}, type = {}, " + "result = {}", + i, entries[i].operation, entries[i].length, entries[i].offset, (u8)entries[i].type, + result); + + if (result == 0) + processed++; + } else if (entries[i].operation == 1) { + result = sceKernelMunmap(entries[i].start, entries[i].length); + LOG_INFO(Kernel_Vmm, "BatchMap: entry = {}, operation = {}, len = {:#x}, result = {}", + i, entries[i].operation, entries[i].length, result); + + if (result == 0) + processed++; + } else { + UNREACHABLE_MSG("called: Unimplemented Operation = {}", entries[i].operation); + } + } + if (numEntriesOut != NULL) { // can be zero. do not return an error code. + *numEntriesOut = processed; + } + return result; +} + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/memory_management.h b/src/core/libraries/kernel/memory_management.h index 2a17f6ed..25434ecb 100644 --- a/src/core/libraries/kernel/memory_management.h +++ b/src/core/libraries/kernel/memory_management.h @@ -6,7 +6,7 @@ #include "common/bit_field.h" #include "common/types.h" -constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 5376_MB; // ~ 6GB +constexpr u64 SCE_KERNEL_MAIN_DMEM_SIZE = 6_GB; // ~ 6GB namespace Libraries::Kernel { @@ -53,6 +53,16 @@ struct OrbisVirtualQueryInfo { std::array name; }; +struct OrbisKernelBatchMapEntry { + void* start; + off_t offset; + size_t length; + char protection; + char type; + short reserved; + int operation; +}; + u64 PS4_SYSV_ABI sceKernelGetDirectMemorySize(); int PS4_SYSV_ABI sceKernelAllocateDirectMemory(s64 searchStart, s64 searchEnd, u64 len, u64 alignment, int memoryType, s64* physAddrOut); @@ -85,4 +95,9 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut void** directMemoryStartOut, void** directMemoryEndOut); +s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries, + int* numEntriesOut); +s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEntries, + int* numEntriesOut, int flags); + } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index e536412f..7c075e87 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -785,7 +785,22 @@ int PS4_SYSV_ABI posix_pthread_mutex_destroy(ScePthreadMutex* mutex) { int PS4_SYSV_ABI posix_pthread_cond_wait(ScePthreadCond* cond, ScePthreadMutex* mutex) { int result = scePthreadCondWait(cond, mutex); if (result < 0) { - UNREACHABLE(); + int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP + ? result + -SCE_KERNEL_ERROR_UNKNOWN + : POSIX_EOTHER; + return rt; + } + return result; +} + +int PS4_SYSV_ABI posix_pthread_cond_timedwait(ScePthreadCond* cond, ScePthreadMutex* mutex, + u64 usec) { + int result = scePthreadCondTimedwait(cond, mutex, usec); + if (result < 0) { + int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP + ? result + -SCE_KERNEL_ERROR_UNKNOWN + : POSIX_EOTHER; + return rt; } return result; } @@ -1350,6 +1365,11 @@ int PS4_SYSV_ABI scePthreadOnce(int* once_control, void (*init_routine)(void)) { UNREACHABLE(); } +[[noreturn]] void PS4_SYSV_ABI posix_pthread_exit(void* value_ptr) { + pthread_exit(value_ptr); + UNREACHABLE(); +} + int PS4_SYSV_ABI scePthreadGetthreadid() { return (int)(size_t)g_pthread_self; } @@ -1401,6 +1421,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("4qGrR6eoP9Y", "libkernel", 1, "libkernel", 1, 1, scePthreadDetach); LIB_FUNCTION("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, scePthreadEqual); LIB_FUNCTION("3kg7rT0NQIs", "libkernel", 1, "libkernel", 1, 1, scePthreadExit); + LIB_FUNCTION("FJrT5LuUBAU", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_exit); LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_equal); LIB_FUNCTION("h9CcP3J0oVM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join); LIB_FUNCTION("EI-5-jlq2dE", "libkernel", 1, "libkernel", 1, 1, scePthreadGetthreadid); @@ -1462,6 +1483,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("ltCfaGr2JGE", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutex_destroy); LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", 1, 1, posix_pthread_cond_wait); LIB_FUNCTION("Op8TBGY5KHg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_wait); + LIB_FUNCTION("27bAgiJmOh0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_timedwait); LIB_FUNCTION("mkx2fVhNMsg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_broadcast); LIB_FUNCTION("dQHWEsJtoE4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_mutexattr_init); LIB_FUNCTION("mDmgMOGVUqg", "libScePosix", 1, "libkernel", 1, 1, diff --git a/src/core/libraries/playgo/playgo.cpp b/src/core/libraries/playgo/playgo.cpp index 1a335a2a..e029413e 100644 --- a/src/core/libraries/playgo/playgo.cpp +++ b/src/core/libraries/playgo/playgo.cpp @@ -8,8 +8,6 @@ #include "playgo.h" namespace Libraries::PlayGo { -// this lib is used to play as the game is being installed. -// can be skipped by just returning and assigning the correct values. s32 PS4_SYSV_ABI sceDbgPlayGoRequestNextChunk() { LOG_ERROR(Lib_PlayGo, "(STUBBED)called"); @@ -141,4 +139,4 @@ void RegisterlibScePlayGo(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("MPe0EeBGM-E", "libScePlayGo", 1, "libScePlayGo", 1, 0, scePlayGoTerminate); }; -} // namespace Libraries::PlayGo \ No newline at end of file +} // namespace Libraries::PlayGo diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 2e47d17d..e4cbe573 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -320,11 +320,15 @@ void Linker::InitTlsForThread(bool is_primary) { static constexpr size_t TlsAllocAlign = 0x20; const size_t total_tls_size = Common::AlignUp(static_tls_size, TlsAllocAlign) + TcbSize; + // If sceKernelMapNamedFlexibleMemory is being called from libkernel and addr = 0 + // it automatically places mappings in system reserved area instead of managed. + static constexpr VAddr KernelAllocBase = 0x880000000ULL; + // The kernel module has a few different paths for TLS allocation. // For SDK < 1.7 it allocates both main and secondary thread blocks using libc mspace/malloc. // In games compiled with newer SDK, the main thread gets mapped from flexible memory, // with addr = 0, so system managed area. Here we will only implement the latter. - void* addr_out{}; + void* addr_out{reinterpret_cast(KernelAllocBase)}; if (is_primary) { const size_t tls_aligned = Common::AlignUp(total_tls_size, 16_KB); const int ret = Libraries::Kernel::sceKernelMapNamedFlexibleMemory( diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 9326ccaa..f2607bff 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -4,7 +4,6 @@ #include "common/alignment.h" #include "common/assert.h" #include "common/debug.h" -#include "common/scope_exit.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/memory_management.h" #include "core/memory.h" @@ -55,7 +54,7 @@ PAddr MemoryManager::Allocate(PAddr search_start, PAddr search_end, size_t size, free_addr = alignment > 0 ? Common::AlignUp(free_addr, alignment) : free_addr; // Add the allocated region to the list and commit its pages. - auto& area = AddDmemAllocation(free_addr, size); + auto& area = CarveDmemArea(free_addr, size); area.memory_type = memory_type; area.is_free = false; return free_addr; @@ -100,29 +99,32 @@ int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, Mem alignment = alignment > 0 ? alignment : 16_KB; VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr; + // Fixed mapping means the virtual address must exactly match the provided one. + if (True(flags & MemoryMapFlags::Fixed)) { + const auto& vma = FindVMA(mapped_addr)->second; + // If the VMA is mapped, unmap the region first. + if (vma.IsMapped()) { + ASSERT_MSG(vma.base == mapped_addr && vma.size == size, + "Region must match when reserving a mapped region"); + UnmapMemory(mapped_addr, size); + } + const size_t remaining_size = vma.base + vma.size - mapped_addr; + ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size); + } + // Find the first free area starting with provided virtual address. if (False(flags & MemoryMapFlags::Fixed)) { - auto it = FindVMA(mapped_addr); - // If the VMA is free and contains the requested mapping we are done. - if (it->second.type == VMAType::Free && it->second.Contains(virtual_addr, size)) { - mapped_addr = virtual_addr; - } else { - // Search for the first free VMA that fits our mapping. - while (it->second.type != VMAType::Free || it->second.size < size) { - it++; - } - ASSERT(it != vma_map.end()); - const auto& vma = it->second; - mapped_addr = alignment > 0 ? Common::AlignUp(vma.base, alignment) : vma.base; - } + mapped_addr = SearchFree(mapped_addr, size, alignment); } // Add virtual memory area - auto& new_vma = AddMapping(mapped_addr, size); + const auto new_vma_handle = CarveVMA(mapped_addr, size); + auto& new_vma = new_vma_handle->second; new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); new_vma.prot = MemoryProt::NoAccess; new_vma.name = ""; new_vma.type = VMAType::Reserved; + MergeAdjacent(vma_map, new_vma_handle); *out_addr = std::bit_cast(mapped_addr); return ORBIS_OK; @@ -132,6 +134,9 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M MemoryMapFlags flags, VMAType type, std::string_view name, bool is_exec, PAddr phys_addr, u64 alignment) { std::scoped_lock lk{mutex}; + + // Certain games perform flexible mappings on loop to determine + // the available flexible memory size. Questionable but we need to handle this. if (type == VMAType::Flexible && flexible_usage + size > total_flexible_size) { return SCE_KERNEL_ERROR_ENOMEM; } @@ -140,91 +145,63 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M // flag so we will take the branch that searches for free (or reserved) mappings. virtual_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; alignment = alignment > 0 ? alignment : 16_KB; - VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr; - SCOPE_EXIT { - auto& new_vma = AddMapping(mapped_addr, size); - new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); - new_vma.prot = prot; - new_vma.name = name; - new_vma.type = type; - - if (type == VMAType::Direct) { - new_vma.phys_base = phys_addr; - MapVulkanMemory(mapped_addr, size); - } - if (type == VMAType::Flexible) { - flexible_usage += size; - } - }; // Fixed mapping means the virtual address must exactly match the provided one. - if (True(flags & MemoryMapFlags::Fixed) && True(flags & MemoryMapFlags::NoOverwrite)) { + if (True(flags & MemoryMapFlags::Fixed)) { // This should return SCE_KERNEL_ERROR_ENOMEM but shouldn't normally happen. const auto& vma = FindVMA(mapped_addr)->second; const size_t remaining_size = vma.base + vma.size - mapped_addr; - ASSERT_MSG(vma.type == VMAType::Free && remaining_size >= size); + ASSERT_MSG(!vma.IsMapped() && remaining_size >= size); } // Find the first free area starting with provided virtual address. if (False(flags & MemoryMapFlags::Fixed)) { - auto it = FindVMA(mapped_addr); - // If the VMA is free and contains the requested mapping we are done. - if (it->second.type == VMAType::Free && it->second.Contains(virtual_addr, size)) { - mapped_addr = virtual_addr; - } else { - // Search for the first free VMA that fits our mapping. - while (it->second.type != VMAType::Free || it->second.size < size) { - it++; - } - ASSERT(it != vma_map.end()); - const auto& vma = it->second; - mapped_addr = alignment > 0 ? Common::AlignUp(vma.base, alignment) : vma.base; - } + mapped_addr = SearchFree(mapped_addr, size, alignment); } // Perform the mapping. *out_addr = impl.Map(mapped_addr, size, alignment, phys_addr, is_exec); TRACK_ALLOC(*out_addr, size, "VMEM"); + + auto& new_vma = CarveVMA(mapped_addr, size)->second; + new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); + new_vma.prot = prot; + new_vma.name = name; + new_vma.type = type; + + if (type == VMAType::Direct) { + new_vma.phys_base = phys_addr; + MapVulkanMemory(mapped_addr, size); + } + if (type == VMAType::Flexible) { + flexible_usage += size; + } + return ORBIS_OK; } int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, uintptr_t fd, size_t offset) { - if (virtual_addr == 0) { - virtual_addr = impl.SystemManagedVirtualBase(); - } else { - LOG_INFO(Kernel_Vmm, "Virtual addr {:#x} with size {:#x}", virtual_addr, size); - } - - VAddr mapped_addr = 0; + VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; const size_t size_aligned = Common::AlignUp(size, 16_KB); // Find first free area to map the file. if (False(flags & MemoryMapFlags::Fixed)) { - auto it = FindVMA(virtual_addr); - while (it->second.type != VMAType::Free || it->second.size < size_aligned) { - it++; - } - ASSERT(it != vma_map.end()); - - mapped_addr = it->second.base; + mapped_addr = SearchFree(mapped_addr, size_aligned); } if (True(flags & MemoryMapFlags::Fixed)) { const auto& vma = FindVMA(virtual_addr)->second; const size_t remaining_size = vma.base + vma.size - virtual_addr; - ASSERT_MSG((vma.type == VMAType::Free || vma.type == VMAType::Reserved) && - remaining_size >= size); - - mapped_addr = virtual_addr; + ASSERT_MSG(!vma.IsMapped() && remaining_size >= size); } // Map the file. impl.MapFile(mapped_addr, size, offset, std::bit_cast(prot), fd); // Add virtual memory area - auto& new_vma = AddMapping(mapped_addr, size_aligned); + auto& new_vma = CarveVMA(mapped_addr, size_aligned)->second; new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); new_vma.prot = prot; new_vma.name = "File"; @@ -238,10 +215,9 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { std::scoped_lock lk{mutex}; - // TODO: Partial unmaps are technically supported by the guest. - const auto it = vma_map.find(virtual_addr); - ASSERT_MSG(it != vma_map.end() && it->first == virtual_addr, - "Attempting to unmap partially mapped range"); + const auto it = FindVMA(virtual_addr); + ASSERT_MSG(it->second.Contains(virtual_addr, size), + "Existing mapping does not contain requested unmap range"); const auto type = it->second.type; const bool has_backing = type == VMAType::Direct || type == VMAType::File; @@ -253,11 +229,13 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { } // Mark region as free and attempt to coalesce it with neighbours. - auto& vma = it->second; + const auto new_it = CarveVMA(virtual_addr, size); + auto& vma = new_it->second; vma.type = VMAType::Free; vma.prot = MemoryProt::NoAccess; vma.phys_base = 0; - MergeAdjacent(vma_map, it); + vma.disallow_merge = false; + MergeAdjacent(vma_map, new_it); // Unmap the memory region. impl.Unmap(virtual_addr, size, has_backing); @@ -288,10 +266,10 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags, std::scoped_lock lk{mutex}; auto it = FindVMA(addr); - if (it->second.type == VMAType::Free && flags == 1) { + if (!it->second.IsMapped() && flags == 1) { it++; } - if (it->second.type == VMAType::Free) { + if (!it->second.IsMapped()) { LOG_WARNING(Kernel_Vmm, "VirtualQuery on free memory region"); return ORBIS_KERNEL_ERROR_EACCES; } @@ -360,14 +338,38 @@ std::pair MemoryManager::GetVulkanBuffer(VAddr addr) { return std::make_pair(*it->second.buffer, addr - it->first); } -VirtualMemoryArea& MemoryManager::AddMapping(VAddr virtual_addr, size_t size) { +VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment) { + auto it = FindVMA(virtual_addr); + // If the VMA is free and contains the requested mapping we are done. + if (it->second.IsFree() && it->second.Contains(virtual_addr, size)) { + return virtual_addr; + } + // Search for the first free VMA that fits our mapping. + const auto is_suitable = [&] { + if (!it->second.IsFree()) { + return false; + } + const auto& vma = it->second; + virtual_addr = Common::AlignUp(vma.base, alignment); + // Sometimes the alignment itself might be larger than the VMA. + if (virtual_addr > vma.base + vma.size) { + return false; + } + const size_t remaining_size = vma.base + vma.size - virtual_addr; + return remaining_size >= size; + }; + while (!is_suitable()) { + it++; + } + return virtual_addr; +} + +MemoryManager::VMAHandle MemoryManager::CarveVMA(VAddr virtual_addr, size_t size) { auto vma_handle = FindVMA(virtual_addr); ASSERT_MSG(vma_handle != vma_map.end(), "Virtual address not in vm_map"); const VirtualMemoryArea& vma = vma_handle->second; - ASSERT_MSG((vma.type == VMAType::Free || vma.type == VMAType::Reserved) && - vma.base <= virtual_addr, - "Adding a mapping to already mapped region"); + ASSERT_MSG(vma.base <= virtual_addr, "Adding a mapping to already mapped region"); const VAddr start_in_vma = virtual_addr - vma.base; const VAddr end_in_vma = start_in_vma + size; @@ -382,10 +384,10 @@ VirtualMemoryArea& MemoryManager::AddMapping(VAddr virtual_addr, size_t size) { vma_handle = Split(vma_handle, start_in_vma); } - return vma_handle->second; + return vma_handle; } -DirectMemoryArea& MemoryManager::AddDmemAllocation(PAddr addr, size_t size) { +DirectMemoryArea& MemoryManager::CarveDmemArea(PAddr addr, size_t size) { auto dmem_handle = FindDmemArea(addr); ASSERT_MSG(dmem_handle != dmem_map.end(), "Physical address not in dmem_map"); diff --git a/src/core/memory.h b/src/core/memory.h index 93aef2d8..ff4af5cd 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -89,7 +89,15 @@ struct VirtualMemoryArea { uintptr_t fd = 0; bool Contains(VAddr addr, size_t size) const { - return addr >= base && (addr + size) < (base + this->size); + return addr >= base && (addr + size) <= (base + this->size); + } + + bool IsFree() const noexcept { + return type == VMAType::Free; + } + + bool IsMapped() const noexcept { + return type != VMAType::Free && type != VMAType::Reserved; } bool CanMergeWith(const VirtualMemoryArea& next) const { @@ -198,9 +206,11 @@ private: return iter; } - VirtualMemoryArea& AddMapping(VAddr virtual_addr, size_t size); + VAddr SearchFree(VAddr virtual_addr, size_t size, u32 alignment = 0); - DirectMemoryArea& AddDmemAllocation(PAddr addr, size_t size); + VMAHandle CarveVMA(VAddr virtual_addr, size_t size); + + DirectMemoryArea& CarveDmemArea(PAddr addr, size_t size); VMAHandle Split(VMAHandle vma_handle, size_t offset_in_vma); diff --git a/src/emulator.cpp b/src/emulator.cpp index 5e584eee..47ac57ac 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -150,10 +150,12 @@ void Emulator::Run(const std::filesystem::path& file) { } void Emulator::LoadSystemModules(const std::filesystem::path& file) { - constexpr std::array ModulesToLoad{ + constexpr std::array ModulesToLoad{ {{"libSceNgs2.sprx", nullptr}, {"libSceFiber.sprx", nullptr}, {"libSceUlt.sprx", nullptr}, + {"libSceJson.sprx", nullptr}, + {"libSceJson2.sprx", nullptr}, {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, {"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap}, {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 16c10f53..9ce87add 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -388,6 +388,10 @@ spv::ImageFormat GetFormat(const AmdGpu::Image& image) { image.GetNumberFmt() == AmdGpu::NumberFormat::Unorm) { return spv::ImageFormat::Rgba8; } + if (image.GetDataFmt() == AmdGpu::DataFormat::Format8_8_8_8 && + image.GetNumberFmt() == AmdGpu::NumberFormat::Uint) { + return spv::ImageFormat::Rgba8ui; + } UNREACHABLE(); }