diff --git a/CMakeLists.txt b/CMakeLists.txt index 96cce0b10..1c5cefc7c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -701,6 +701,8 @@ set(CORE src/core/aerolib/stubs.cpp src/core/address_space.h src/core/devices/base_device.cpp src/core/devices/base_device.h + src/core/devices/gc_device.cpp + src/core/devices/gc_device.h src/core/devices/ioccom.h src/core/devices/logger.cpp src/core/devices/logger.h diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 1a6ff9ec8..5616d9503 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -138,6 +138,7 @@ static auto UserPaths = [] { create_path(PathType::PatchesDir, user_dir / PATCHES_DIR); create_path(PathType::MetaDataDir, user_dir / METADATA_DIR); create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY); + create_path(PathType::DevicesDir, user_dir / DEVICES_DIR); std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt"); if (notice_file.is_open()) { diff --git a/src/common/path_util.h b/src/common/path_util.h index 2fd9b1588..848bf27f7 100644 --- a/src/common/path_util.h +++ b/src/common/path_util.h @@ -28,6 +28,7 @@ enum class PathType { PatchesDir, // Where patches are stored. MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored. CustomTrophy, // Where custom files for trophies are stored. + DevicesDir, // Where temporary device files are located. }; constexpr auto PORTABLE_DIR = "user"; @@ -46,6 +47,7 @@ constexpr auto CHEATS_DIR = "cheats"; constexpr auto PATCHES_DIR = "patches"; constexpr auto METADATA_DIR = "game_data"; constexpr auto CUSTOM_TROPHY = "custom_trophy"; +constexpr auto DEVICES_DIR = "device"; // Filenames constexpr auto LOG_FILE = "shad_log.txt"; diff --git a/src/core/devices/gc_device.cpp b/src/core/devices/gc_device.cpp new file mode 100644 index 000000000..ccaad9b16 --- /dev/null +++ b/src/core/devices/gc_device.cpp @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/devices/gc_device.h" +#include "core/libraries/gnmdriver/gnmdriver.h" +#include "core/libraries/kernel/posix_error.h" +#include "core/memory.h" + +namespace Core::Devices { + +std::shared_ptr GcDevice::Create(u32 handle, const char*, int, u16) { + return std::shared_ptr( + reinterpret_cast(new GcDevice(handle))); +} + +s32* submits_addr = 0; + +s32 GcDevice::ioctl(u64 cmd, Common::VaCtx* args) { + auto command = GcCommands(cmd); + switch (command) { + case GcCommands::FlushGarlic: { + LOG_ERROR(Lib_GnmDriver, "ioctl FlushGarlic"); + break; + } + case GcCommands::SubmitDone: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl SubmitDone"); + break; + } + case GcCommands::WaitIdle: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl WaitIdle"); + break; + } + case GcCommands::WaitFree: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl WaitFree"); + break; + } + case GcCommands::GetNumTcaUnits: { + auto data = vaArgPtr(&args->va_list); + *data = 0; + break; + } + case GcCommands::SwitchBuffer: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl SwitchBuffer"); + break; + } + case GcCommands::DebugHardwareStatus: { + break; + } + case GcCommands::InitializeSubmits: { + LOG_INFO(Lib_GnmDriver, "ioctl InitializeSubmits"); + if (submits_addr == nullptr) { + auto* memory = Core::Memory::Instance(); + s32* out_addr; + VAddr in_addr{0xfe0100000}; + auto prot = Core::MemoryProt::CpuRead; + auto flags = Core::MemoryMapFlags::Shared | Core::MemoryMapFlags::Anon | + Core::MemoryMapFlags::System; + auto type = Core::VMAType::Direct; + s32 result = memory->MapMemory(reinterpret_cast(&out_addr), in_addr, 0x4000, + prot, flags, type); + if (result != 0) { + return POSIX_ENOMEM; + } + submits_addr = out_addr; + } + auto data = vaArgPtr(&args->va_list); + *data = submits_addr; + + *submits_addr = 0; + break; + } + case GcCommands::UnmapComputeQueue: { + LOG_ERROR(Lib_GnmDriver, "ioctl UnmapComputeQueue"); + break; + } + case GcCommands::SetGsRingSizes: { + auto data = vaArgPtr(&args->va_list); + LOG_ERROR(Lib_GnmDriver, + "unhandled ioctl SetGsRingSizes, esgs size = {:#x}, gsvs size = {:#x}", + data->esgs_ring_size, data->gsvs_ring_size); + break; + } + case GcCommands::Submit: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl Submit"); + auto data = vaArgPtr(&args->va_list); + // Submit ioctl receives an indirect buffer packet + break; + } + case GcCommands::GetCuMask: { + auto data = vaArgPtr(&args->va_list); + data[0] = 0x10; + data[1] = 0x10; + data[2] = 0; + data[3] = 0; + break; + } + case GcCommands::DingDong: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl DingDong"); + break; + } + case GcCommands::RequiresNeoCompat: { + return POSIX_ENODEV; + } + case GcCommands::SubmitEop: { + ASSERT(true); + LOG_ERROR(Lib_GnmDriver, "ioctl SubmitEop"); + auto data = vaArgPtr(&args->va_list); + // Submit ioctl receives an indirect buffer packet + break; + } + case GcCommands::MapComputeQueue: { + ASSERT(true); + auto data = vaArgPtr(&args->va_list); + auto pipe_id = data->pipe_lo - 1; + auto ring_size = pow(2, data->ring_size_dw); + data->pipe_priority = 0; + LOG_ERROR(Lib_GnmDriver, "ioctl MapComputeQueue, pipe_id = {}", pipe_id); + Libraries::GnmDriver::sceGnmMapComputeQueue(pipe_id, data->queue_id, data->ring_base_addr, + ring_size, data->read_ptr_addr); + break; + } + case GcCommands::MapComputeQueueWithPriority: { + ASSERT(true); + auto data = vaArgPtr(&args->va_list); + auto pipe_id = data->pipe_lo - 1; + auto ring_size = pow(2, data->ring_size_dw); + LOG_ERROR(Lib_GnmDriver, "ioctl MapComputeQueueWithPriority, pipe_id = {}", pipe_id); + Libraries::GnmDriver::sceGnmMapComputeQueueWithPriority( + pipe_id, data->queue_id, data->ring_base_addr, ring_size, data->read_ptr_addr, + data->pipe_priority); + break; + } + case GcCommands::SetWaveLimitMultipliers: { + LOG_ERROR(Lib_GnmDriver, "ioctl SetWaveLimitMultipliers"); + auto data = vaArgPtr(&args->va_list); + break; + } + case GcCommands::MipStatsReport: { + auto data = vaArgPtr(&args->va_list); + switch (data->type) { + case 0x10001: + case 0x18001: { + break; + } + default: { + return POSIX_EINVAL; + } + } + break; + } + default: { + LOG_ERROR(Lib_GnmDriver, "unhandled ioctl cmd = {:#x} called", cmd); + break; + } + } + return 0; +} + +s64 GcDevice::write(const void* buf, size_t nbytes) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +size_t GcDevice::writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +size_t GcDevice::readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +s64 GcDevice::preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +s64 GcDevice::lseek(s64 offset, int whence) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +s64 GcDevice::read(void* buf, size_t nbytes) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +int GcDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +s32 GcDevice::fsync() { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +int GcDevice::ftruncate(s64 length) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +int GcDevice::getdents(void* buf, u32 nbytes, s64* basep) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +s64 GcDevice::pwrite(const void* buf, size_t nbytes, u64 offset) { + LOG_ERROR(Kernel_Pthread, "(STUBBED) called"); + return 0; +} + +} // namespace Core::Devices \ No newline at end of file diff --git a/src/core/devices/gc_device.h b/src/core/devices/gc_device.h new file mode 100644 index 000000000..c95001eb1 --- /dev/null +++ b/src/core/devices/gc_device.h @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include +#include "base_device.h" + +namespace Core::Devices { + +class GcDevice final : BaseDevice { + u32 handle; + +public: + static std::shared_ptr Create(u32 handle, const char*, int, u16); + explicit GcDevice(u32 handle) : handle(handle) {} + + ~GcDevice() override = default; + + int ioctl(u64 cmd, Common::VaCtx* args) override; + s64 write(const void* buf, size_t nbytes) override; + size_t readv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; + size_t writev(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt) override; + s64 preadv(const Libraries::Kernel::SceKernelIovec* iov, int iovcnt, u64 offset) override; + s64 lseek(s64 offset, int whence) override; + s64 read(void* buf, size_t nbytes) override; + int fstat(Libraries::Kernel::OrbisKernelStat* sb) override; + s32 fsync() override; + int ftruncate(s64 length) override; + int getdents(void* buf, u32 nbytes, s64* basep) override; + s64 pwrite(const void* buf, size_t nbytes, u64 offset) override; + +private: + enum class GcCommands : u64 { + FlushGarlic = 0xc0048114, + SubmitDone = 0xc0048116, + WaitIdle = 0xc0048117, + WaitFree = 0xc004811d, + GetNumTcaUnits = 0xc004811f, + SwitchBuffer = 0xc0088101, + DebugHardwareStatus = 0xc0088111, + InitializeSubmits = 0xc008811b, + UnmapComputeQueue = 0xc00c810e, + SetGsRingSizes = 0xc00c8110, + Submit = 0xc0108102, + GetCuMask = 0xc010810b, + DingDong = 0xc010811c, + RequiresNeoCompat = 0xc0108120, + SubmitEop = 0xc020810c, + MapComputeQueue = 0xc030810d, + MapComputeQueueWithPriority = 0xc030811a, + SetWaveLimitMultipliers = 0xc030811e, + MipStatsReport = 0xc0848119, + }; + + struct SetGsRingSizesArgs { + u32 esgs_ring_size; + u32 gsvs_ring_size; + u32 unk; + }; + + struct SubmitArgs { + u32 pid; + u32 count; + u64* cmds; + }; + + struct SubmitEopArgs { + u32 pid; + u32 count; + u64* cmds; + u64 eop_v; + s32 wait; + }; + + struct MapComputeQueueArgs { + u32 pipe_hi; + u32 pipe_lo; + u32 queue_id; + u32 g_queue_id; + VAddr ring_base_addr; + u32* read_ptr_addr; + VAddr ding_dong_ptr; + u32 ring_size_dw; + u32 pipe_priority; + }; + + struct SetWaveLimitMultipliersArgs { + s32 bitset; + s32 values[8]; + s32 unk0; + s32 unk1; + s32 unk2; + }; + + struct SetMipStatsReportArgs { + u32 type; + u32 unk0; + u32 unk1; + u32 unk2; + }; +}; + +} // namespace Core::Devices \ No newline at end of file diff --git a/src/core/libraries/gnmdriver/gnmdriver.cpp b/src/core/libraries/gnmdriver/gnmdriver.cpp index 25ac4921c..f0363ba39 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.cpp +++ b/src/core/libraries/gnmdriver/gnmdriver.cpp @@ -2799,7 +2799,7 @@ int PS4_SYSV_ABI Func_F916890425496553() { return ORBIS_OK; } -void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { +void InitializePresenter() { LOG_INFO(Lib_GnmDriver, "Initializing presenter"); liverpool = std::make_unique(); presenter = std::make_unique(*g_window, liverpool.get()); @@ -2815,10 +2815,42 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { Platform::IrqC::Instance()->Register(Platform::InterruptId::GpuIdle, ResetSubmissionLock, nullptr); +} - LIB_FUNCTION("b0xyllnVY-I", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmAddEqEvent); +void RegisterRequiredGnmDriver(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("29oKvKXzEZo", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmMapComputeQueue); + LIB_FUNCTION("A+uGq+3KFtQ", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmMapComputeQueueWithPriority); + LIB_FUNCTION("gObODli-OH8", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmRequestFlipAndSubmitDone); + LIB_FUNCTION("6YRHhh5mHCs", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmRequestFlipAndSubmitDoneForWorkload); + LIB_FUNCTION("xbxNatawohc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmSubmitAndFlipCommandBuffers); + LIB_FUNCTION("Ga6r7H6Y0RI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmSubmitAndFlipCommandBuffersForWorkload); + LIB_FUNCTION("zwY0YV91TTI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmSubmitCommandBuffers); + LIB_FUNCTION("jRcI8VcgTz4", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmSubmitCommandBuffersForWorkload); + LIB_FUNCTION("yvZ73uQUqrk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmSubmitDone); + LIB_FUNCTION("ArSg-TGinhk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmUnmapComputeQueue); + LIB_FUNCTION("bX5IbRvECXk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDingDong); + LIB_FUNCTION("byXlqupd8cE", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmDingDongForWorkload); LIB_FUNCTION("b08AgtPlHPg", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmAreSubmitsAllowed); + LIB_FUNCTION("b0xyllnVY-I", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmAddEqEvent); + LIB_FUNCTION("UoYY0DWMC0U", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmGetEqEventType); + LIB_FUNCTION("H7-fgvEutM0", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, + sceGnmGetEqTimeStamp); + LIB_FUNCTION("PVT+fuoS9gU", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDeleteEqEvent); +} + +void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("ihxrbsoSKWc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmBeginWorkload); LIB_FUNCTION("ffrNQOshows", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmComputeWaitOnAddress); @@ -2846,12 +2878,8 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { sceGnmDebuggerWriteSqIndirectRegister); LIB_FUNCTION("qpGITzPE+Zc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDebugHardwareStatus); - LIB_FUNCTION("PVT+fuoS9gU", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDeleteEqEvent); LIB_FUNCTION("UtObDRQiGbs", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDestroyWorkloadStream); - LIB_FUNCTION("bX5IbRvECXk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDingDong); - LIB_FUNCTION("byXlqupd8cE", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmDingDongForWorkload); LIB_FUNCTION("HHo1BAljZO8", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmDisableMipStatsReport); LIB_FUNCTION("0BzLGljcwBo", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, @@ -2929,10 +2957,6 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { sceGnmGetDbgGcHandle); LIB_FUNCTION("pd4C7da6sEg", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmGetDebugTimestamp); - LIB_FUNCTION("UoYY0DWMC0U", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmGetEqEventType); - LIB_FUNCTION("H7-fgvEutM0", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmGetEqTimeStamp); LIB_FUNCTION("oL4hGI1PMpw", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmGetGpuBlockStatus); LIB_FUNCTION("Fwvh++m9IQI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, @@ -2996,10 +3020,6 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { sceGnmLogicalCuMaskToPhysicalCuMask); LIB_FUNCTION("Kl0Z3LH07QI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmLogicalTcaUnitToPhysical); - LIB_FUNCTION("29oKvKXzEZo", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmMapComputeQueue); - LIB_FUNCTION("A+uGq+3KFtQ", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmMapComputeQueueWithPriority); LIB_FUNCTION("+N+wrSYBLIw", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmPaDisableFlipCallbacks); LIB_FUNCTION("8WDA9RiXLaw", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, @@ -3016,10 +3036,6 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("ZFqKFl23aMc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmRegisterOwner); LIB_FUNCTION("nvEwfYAImTs", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmRegisterResource); - LIB_FUNCTION("gObODli-OH8", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmRequestFlipAndSubmitDone); - LIB_FUNCTION("6YRHhh5mHCs", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmRequestFlipAndSubmitDoneForWorkload); LIB_FUNCTION("f85orjx7qts", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmRequestMipStatsReportAndReset); LIB_FUNCTION("MYRtYhojKdA", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, @@ -3129,17 +3145,6 @@ void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym) { sceGnmSqttSwitchTraceBuffer2); LIB_FUNCTION("QLzOwOF0t+A", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmSqttWaitForEvent); - LIB_FUNCTION("xbxNatawohc", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmSubmitAndFlipCommandBuffers); - LIB_FUNCTION("Ga6r7H6Y0RI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmSubmitAndFlipCommandBuffersForWorkload); - LIB_FUNCTION("zwY0YV91TTI", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmSubmitCommandBuffers); - LIB_FUNCTION("jRcI8VcgTz4", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmSubmitCommandBuffersForWorkload); - LIB_FUNCTION("yvZ73uQUqrk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmSubmitDone); - LIB_FUNCTION("ArSg-TGinhk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, - sceGnmUnmapComputeQueue); LIB_FUNCTION("yhFCnaz5daw", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, sceGnmUnregisterAllResourcesForOwner); LIB_FUNCTION("fhKwCVVj9nk", "libSceGnmDriver", 1, "libSceGnmDriver", 1, 1, diff --git a/src/core/libraries/gnmdriver/gnmdriver.h b/src/core/libraries/gnmdriver/gnmdriver.h index 94d06c85f..94167cef1 100644 --- a/src/core/libraries/gnmdriver/gnmdriver.h +++ b/src/core/libraries/gnmdriver/gnmdriver.h @@ -14,6 +14,8 @@ namespace Libraries::GnmDriver { using namespace Kernel; +void InitializePresenter(); + s32 PS4_SYSV_ABI sceGnmAddEqEvent(SceKernelEqueue eq, u64 id, void* udata); int PS4_SYSV_ABI sceGnmAreSubmitsAllowed(); int PS4_SYSV_ABI sceGnmBeginWorkload(u32 workload_stream, u64* workload); @@ -295,5 +297,6 @@ int PS4_SYSV_ABI Func_BFB41C057478F0BF(); int PS4_SYSV_ABI Func_E51D44DB8151238C(); int PS4_SYSV_ABI Func_F916890425496553(); +void RegisterRequiredGnmDriver(Core::Loader::SymbolsResolver* sym); void RegisterlibSceGnmDriver(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::GnmDriver diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index bc34dff98..845aa294a 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -10,6 +10,7 @@ #include "common/singleton.h" #include "core/devices/console_device.h" #include "core/devices/deci_tty6_device.h" +#include "core/devices/gc_device.h" #include "core/devices/logger.h" #include "core/devices/nop_device.h" #include "core/devices/random_device.h" @@ -52,7 +53,8 @@ static std::map available_device = { {"/dev/random", &D::RandomDevice::Create }, {"/dev/srandom", &D::SRandomDevice::Create }, {"/dev/console", &D::ConsoleDevice::Create }, - {"/dev/deci_tty6",&D::DeciTty6Device::Create } + {"/dev/deci_tty6",&D::DeciTty6Device::Create }, + {"/dev/gc", &D::GcDevice::Create } // clang-format on }; @@ -89,6 +91,15 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) { file->type = Core::FileSys::FileType::Device; file->m_guest_name = path; file->device = factory(handle, path.data(), flags, mode); + + // Some libraries map memory to their file. We need a host file to support this. + file->m_host_name = mnt->GetHostPath(file->m_guest_name); + bool exists = std::filesystem::exists(file->m_host_name); + if (!exists) { + Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write); + } + auto e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite); + ASSERT(e == 0); return handle; } } diff --git a/src/core/libraries/kernel/memory.cpp b/src/core/libraries/kernel/memory.cpp index 8a0c91479..dfcadaf8e 100644 --- a/src/core/libraries/kernel/memory.cpp +++ b/src/core/libraries/kernel/memory.cpp @@ -234,6 +234,37 @@ s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addr_in_out, std::size_t Core::VMAType::Flexible, name); } +s32 PS4_SYSV_ABI sceKernelMapNamedSystemFlexibleMemory(void** addr_in_out, std::size_t len, + int prot, int flags, const char* name) { + if (len == 0 || !Common::Is16KBAligned(len)) { + LOG_ERROR(Kernel_Vmm, "len is 0 or not 16kb multiple"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + + static constexpr size_t MaxNameSize = 32; + if (std::strlen(name) > MaxNameSize) { + LOG_ERROR(Kernel_Vmm, "name exceeds 32 bytes!"); + return ORBIS_KERNEL_ERROR_ENAMETOOLONG; + } + + if (name == nullptr) { + LOG_ERROR(Kernel_Vmm, "name is invalid!"); + return ORBIS_KERNEL_ERROR_EFAULT; + } + + const VAddr in_addr = reinterpret_cast(*addr_in_out); + const auto mem_prot = static_cast(prot); + const auto map_flags = static_cast(flags); + SCOPE_EXIT { + LOG_INFO(Kernel_Vmm, + "in_addr = {:#x}, out_addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}", + in_addr, fmt::ptr(*addr_in_out), len, prot, flags); + }; + auto* memory = Core::Memory::Instance(); + return memory->MapSystemMemory(addr_in_out, in_addr, len, mem_prot, map_flags, + Core::VMAType::Flexible, name); +} + s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot, int flags) { return sceKernelMapNamedFlexibleMemory(addr_in_out, len, prot, flags, ""); @@ -578,6 +609,8 @@ void RegisterMemory(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("PGhQHd-dzv8", "libkernel", 1, "libkernel", 1, 1, sceKernelMmap); LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap); LIB_FUNCTION("mL8NDH86iQI", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedFlexibleMemory); + LIB_FUNCTION("kc+LEEIYakc", "libkernel", 1, "libkernel", 1, 1, + sceKernelMapNamedSystemFlexibleMemory); LIB_FUNCTION("aNz11fnnzi4", "libkernel", 1, "libkernel", 1, 1, sceKernelAvailableFlexibleMemorySize); LIB_FUNCTION("aNz11fnnzi4", "libkernel_avlfmem", 1, "libkernel", 1, 1, diff --git a/src/core/libraries/kernel/memory.h b/src/core/libraries/kernel/memory.h index 400b6c3fc..517c1c1c8 100644 --- a/src/core/libraries/kernel/memory.h +++ b/src/core/libraries/kernel/memory.h @@ -129,6 +129,9 @@ s32 PS4_SYSV_ABI sceKernelMemoryPoolReserve(void* addrIn, size_t len, size_t ali s32 PS4_SYSV_ABI sceKernelMemoryPoolCommit(void* addr, size_t len, int type, int prot, int flags); s32 PS4_SYSV_ABI sceKernelMemoryPoolDecommit(void* addr, size_t len, int flags); +int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset, + void** res); + int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len); void RegisterMemory(Core::Loader::SymbolsResolver* sym); diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index 3f5baf640..8d8d755cf 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -66,7 +66,8 @@ namespace Libraries { void InitHLELibs(Core::Loader::SymbolsResolver* sym) { LOG_INFO(Lib_Kernel, "Initializing HLE libraries"); Libraries::Kernel::RegisterKernel(sym); - Libraries::GnmDriver::RegisterlibSceGnmDriver(sym); + Libraries::GnmDriver::InitializePresenter(); + Libraries::GnmDriver::RegisterRequiredGnmDriver(sym); Libraries::VideoOut::RegisterLib(sym); Libraries::UserService::RegisterlibSceUserService(sym); Libraries::SystemService::RegisterlibSceSystemService(sym); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 494ffa70c..071364c6d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -358,6 +358,19 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M return ORBIS_OK; } +int MemoryManager::MapSystemMemory(void** out_addr, VAddr virtual_addr, size_t size, + MemoryProt prot, MemoryMapFlags flags, VMAType type, + std::string_view name) { + // If address is 0, this maps to System Reserved memory. + // System Reserved memory starts at address 0x880000000. + VAddr in_addr = virtual_addr; + if (in_addr == 0) { + static constexpr VAddr KernelAllocBase = 0x880000000ULL; + in_addr = SearchFree(KernelAllocBase, size, 1); + } + return MapMemory(out_addr, in_addr, size, prot, flags, type, name); +} + int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, uintptr_t fd, size_t offset) { VAddr mapped_addr = (virtual_addr == 0) ? impl.SystemManagedVirtualBase() : virtual_addr; diff --git a/src/core/memory.h b/src/core/memory.h index a6a55e288..13dfb8d3d 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -41,8 +41,10 @@ enum class MemoryMapFlags : u32 { Shared = 1, Private = 2, Fixed = 0x10, - NoOverwrite = 0x0080, + NoOverwrite = 0x80, NoSync = 0x800, + Anon = 0x1000, + System = 0x2000, NoCore = 0x20000, NoCoalesce = 0x400000, }; @@ -189,6 +191,9 @@ public: MemoryMapFlags flags, VMAType type, std::string_view name = "", bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); + int MapSystemMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, + MemoryMapFlags flags, VMAType type, std::string_view name = ""); + int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, MemoryMapFlags flags, uintptr_t fd, size_t offset); diff --git a/src/emulator.cpp b/src/emulator.cpp index 1a71b99cb..efc3480dc 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -26,6 +26,7 @@ #include "core/file_format/trp.h" #include "core/file_sys/fs.h" #include "core/libraries/disc_map/disc_map.h" +#include "core/libraries/gnmdriver/gnmdriver.h" #include "core/libraries/libc_internal/libc_internal.h" #include "core/libraries/libs.h" #include "core/libraries/ngs2/ngs2.h" @@ -244,6 +245,12 @@ void Emulator::Run(const std::filesystem::path& file, const std::vectorMount(devices_dir, "/dev"); + // Initialize kernel and library facilities. Libraries::InitHLELibs(&linker->GetHLESymbols()); @@ -288,7 +295,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector ModulesToLoad{ + constexpr std::array ModulesToLoad{ {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2}, {"libSceUlt.sprx", nullptr}, {"libSceJson.sprx", nullptr}, @@ -298,7 +305,8 @@ void Emulator::LoadSystemModules(const std::string& game_serial) { {"libSceCesCs.sprx", nullptr}, {"libSceFont.sprx", nullptr}, {"libSceFontFt.sprx", nullptr}, - {"libSceFreeTypeOt.sprx", nullptr}}}; + {"libSceFreeTypeOt.sprx", nullptr}, + {"libSceGnmDriver.sprx", &Libraries::GnmDriver::RegisterlibSceGnmDriver}}}; std::vector found_modules; const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);