mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-06-13 06:03:16 +00:00
''
This commit is contained in:
commit
d9da4a9d2b
158 changed files with 4404 additions and 1662 deletions
|
@ -34,10 +34,7 @@ constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL;
|
|||
|
||||
static constexpr size_t SystemManagedSize = SYSTEM_MANAGED_MAX - SYSTEM_MANAGED_MIN + 1;
|
||||
static constexpr size_t SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_MIN + 1;
|
||||
// User area size is normally larger than this. However games are unlikely to map to high
|
||||
// regions of that area, so by default we allocate a smaller virtual address space (about 1/4th).
|
||||
// to save space on page tables.
|
||||
static constexpr size_t UserSize = 1ULL << 39;
|
||||
static constexpr size_t UserSize = 1ULL << 40;
|
||||
|
||||
/**
|
||||
* Represents the user virtual address space backed by a dmem memory block
|
||||
|
|
|
@ -285,20 +285,24 @@ static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGe
|
|||
const auto slot = GetTcbKey();
|
||||
|
||||
#if defined(_WIN32)
|
||||
// The following logic is based on the wine implementation of TlsGetValue
|
||||
// https://github.com/wine-mirror/wine/blob/a27b9551/dlls/kernelbase/thread.c#L719
|
||||
// The following logic is based on the Kernel32.dll asm of TlsGetValue
|
||||
static constexpr u32 TlsSlotsOffset = 0x1480;
|
||||
static constexpr u32 TlsExpansionSlotsOffset = 0x1780;
|
||||
static constexpr u32 TlsMinimumAvailable = 64;
|
||||
|
||||
const u32 teb_offset = slot < TlsMinimumAvailable ? TlsSlotsOffset : TlsExpansionSlotsOffset;
|
||||
const u32 tls_index = slot < TlsMinimumAvailable ? slot : slot - TlsMinimumAvailable;
|
||||
|
||||
// Load the pointer to the table of TLS slots.
|
||||
c.putSeg(gs);
|
||||
c.mov(dst, ptr[reinterpret_cast<void*>(teb_offset)]);
|
||||
// Load the pointer to our buffer.
|
||||
c.mov(dst, qword[dst + tls_index * sizeof(LPVOID)]);
|
||||
if (slot < TlsMinimumAvailable) {
|
||||
// Load the pointer to TLS slots.
|
||||
c.mov(dst, ptr[reinterpret_cast<void*>(TlsSlotsOffset + slot * sizeof(LPVOID))]);
|
||||
} else {
|
||||
const u32 tls_index = slot - TlsMinimumAvailable;
|
||||
|
||||
// Load the pointer to the table of TLS expansion slots.
|
||||
c.mov(dst, ptr[reinterpret_cast<void*>(TlsExpansionSlotsOffset)]);
|
||||
// Load the pointer to our buffer.
|
||||
c.mov(dst, qword[dst + tls_index * sizeof(LPVOID)]);
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
// The following logic is based on the Darwin implementation of _os_tsd_get_direct, used by
|
||||
// pthread_getspecific https://github.com/apple/darwin-xnu/blob/main/libsyscall/os/tsd.h#L89-L96
|
||||
|
|
16
src/core/file_format/playgo_chunk.cpp
Normal file
16
src/core/file_format/playgo_chunk.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/io_file.h"
|
||||
|
||||
#include "playgo_chunk.h"
|
||||
|
||||
bool PlaygoChunk::Open(const std::filesystem::path& filepath) {
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
file.Read(playgoHeader);
|
||||
|
||||
return true;
|
||||
}
|
31
src/core/file_format/playgo_chunk.h
Normal file
31
src/core/file_format/playgo_chunk.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
#include "common/types.h"
|
||||
|
||||
struct PlaygoHeader {
|
||||
u32 magic;
|
||||
|
||||
u16 version_major;
|
||||
u16 version_minor;
|
||||
u16 image_count;
|
||||
u16 chunk_count;
|
||||
u16 mchunk_count;
|
||||
u16 scenario_count;
|
||||
// TODO fill the rest
|
||||
};
|
||||
class PlaygoChunk {
|
||||
public:
|
||||
PlaygoChunk() = default;
|
||||
~PlaygoChunk() = default;
|
||||
|
||||
bool Open(const std::filesystem::path& filepath);
|
||||
PlaygoHeader GetPlaygoHeader() {
|
||||
return playgoHeader;
|
||||
}
|
||||
|
||||
private:
|
||||
PlaygoHeader playgoHeader;
|
||||
};
|
|
@ -26,23 +26,27 @@ void MntPoints::UnmountAll() {
|
|||
}
|
||||
|
||||
std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory) {
|
||||
const MntPair* mount = GetMount(guest_directory);
|
||||
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
|
||||
auto corrected_path = guest_directory;
|
||||
size_t pos = corrected_path.find("//");
|
||||
while (pos != std::string::npos) {
|
||||
corrected_path.replace(pos, 2, "/");
|
||||
pos = corrected_path.find("//", pos + 1);
|
||||
}
|
||||
|
||||
const MntPair* mount = GetMount(corrected_path);
|
||||
if (!mount) {
|
||||
return guest_directory;
|
||||
return "";
|
||||
}
|
||||
|
||||
// Nothing to do if getting the mount itself.
|
||||
if (guest_directory == mount->mount) {
|
||||
if (corrected_path == mount->mount) {
|
||||
return mount->host_path;
|
||||
}
|
||||
|
||||
// Remove device (e.g /app0) from path to retrieve relative path.
|
||||
u32 pos = mount->mount.size() + 1;
|
||||
// Evil games like Turok2 pass double slashes e.g /app0//game.kpf
|
||||
if (guest_directory[pos] == '/') {
|
||||
pos++;
|
||||
}
|
||||
const auto rel_path = std::string_view(guest_directory).substr(pos);
|
||||
pos = mount->mount.size() + 1;
|
||||
const auto rel_path = std::string_view(corrected_path).substr(pos);
|
||||
const auto host_path = mount->host_path / rel_path;
|
||||
if (!NeedsCaseInsensiveSearch) {
|
||||
return host_path;
|
||||
|
@ -66,7 +70,7 @@ std::filesystem::path MntPoints::GetHostPath(const std::string& guest_directory)
|
|||
// exist in filesystem but in different case.
|
||||
auto guest_path = current_path;
|
||||
while (!path_parts.empty()) {
|
||||
const auto& part = path_parts.back();
|
||||
const auto part = path_parts.back();
|
||||
const auto add_match = [&](const auto& host_part) {
|
||||
current_path /= host_part;
|
||||
guest_path /= part;
|
||||
|
|
|
@ -198,13 +198,9 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataMount() {
|
|||
|
||||
int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOption option,
|
||||
OrbisAppContentMountPoint* mountPoint) {
|
||||
if (std::string_view(mountPoint->data).empty()) // causing issues with save_data.
|
||||
if (mountPoint == nullptr)
|
||||
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
|
||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
std::string id(param_sfo->GetString("CONTENT_ID"), 7, 9);
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::TempDataDir) / id;
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
mnt->Mount(mount_dir, mountPoint->data);
|
||||
strncpy(mountPoint->data, "/temp0", 16);
|
||||
LOG_INFO(Lib_AppContent, "sceAppContentTemporaryDataMount2: option = {}, mountPoint = {}",
|
||||
option, mountPoint->data);
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -233,6 +233,9 @@ constexpr int SCE_KERNEL_ERROR_ESDKVERSION = 0x80020063;
|
|||
constexpr int SCE_KERNEL_ERROR_ESTART = 0x80020064;
|
||||
constexpr int SCE_KERNEL_ERROR_ESTOP = 0x80020065;
|
||||
|
||||
// libSceRandom error codes
|
||||
constexpr int SCE_RANDOM_ERROR_INVALID = 0x817C0016;
|
||||
|
||||
// videoOut
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_VALUE = 0x80290001; // invalid argument
|
||||
constexpr int SCE_VIDEO_OUT_ERROR_INVALID_ADDRESS = 0x80290002; // invalid addresses
|
||||
|
|
|
@ -20,13 +20,12 @@
|
|||
|
||||
extern Frontend::WindowSDL* g_window;
|
||||
std::unique_ptr<Vulkan::RendererVulkan> renderer;
|
||||
std::unique_ptr<AmdGpu::Liverpool> liverpool;
|
||||
|
||||
namespace Libraries::GnmDriver {
|
||||
|
||||
using namespace AmdGpu;
|
||||
|
||||
static std::unique_ptr<AmdGpu::Liverpool> liverpool;
|
||||
|
||||
enum GnmEventIdents : u64 {
|
||||
Compute0RelMem = 0x00,
|
||||
Compute1RelMem = 0x01,
|
||||
|
@ -958,7 +957,7 @@ int PS4_SYSV_ABI sceGnmGetGpuBlockStatus() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmGetGpuCoreClockFrequency() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
LOG_DEBUG(Lib_GnmDriver, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -2131,6 +2130,7 @@ int PS4_SYSV_ABI sceGnmSubmitDone() {
|
|||
if (!liverpool->IsGpuIdle()) {
|
||||
submission_lock = true;
|
||||
}
|
||||
liverpool->SubmitDone();
|
||||
send_init_packet = true;
|
||||
++frames_submitted;
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -78,9 +78,7 @@ bool EqueueInternal::TriggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
for (auto& event : m_events) {
|
||||
ASSERT_MSG(event.event.filter == filter,
|
||||
"Event to trigger doesn't match to queue events");
|
||||
if (event.event.ident == ident) {
|
||||
if ((event.event.ident == ident) && (event.event.filter == filter)) {
|
||||
event.Trigger(trigger_data);
|
||||
has_found = true;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,9 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
|||
if (std::string_view{path} == "/dev/stdout") {
|
||||
return 2002;
|
||||
}
|
||||
if (std::string_view{path} == "/dev/urandom") {
|
||||
return 2003;
|
||||
}
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
if (directory) {
|
||||
|
@ -113,6 +116,9 @@ int PS4_SYSV_ABI sceKernelClose(int d) {
|
|||
if (d < 3) { // d probably hold an error code
|
||||
return ORBIS_KERNEL_ERROR_EPERM;
|
||||
}
|
||||
if (d == 2003) { // dev/urandom case
|
||||
return SCE_OK;
|
||||
}
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
auto* file = h->GetFile(d);
|
||||
if (file == nullptr) {
|
||||
|
@ -223,6 +229,13 @@ s64 PS4_SYSV_ABI posix_lseek(int d, s64 offset, int whence) {
|
|||
}
|
||||
|
||||
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes) {
|
||||
if (d == 2003) // dev urandom case
|
||||
{
|
||||
auto rbuf = static_cast<char*>(buf);
|
||||
for (size_t i = 0; i < nbytes; i++)
|
||||
rbuf[i] = std::rand() & 0xFF;
|
||||
return nbytes;
|
||||
}
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
auto* file = h->GetFile(d);
|
||||
if (file == nullptr) {
|
||||
|
@ -459,7 +472,30 @@ s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset) {
|
|||
return file->f.WriteRaw<u8>(buf, nbytes);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelRename(const char* from, const char* to) {
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto src_path = mnt->GetHostPath(from);
|
||||
if (!std::filesystem::exists(src_path)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOENT;
|
||||
}
|
||||
const auto dst_path = mnt->GetHostPath(to);
|
||||
const bool src_is_dir = std::filesystem::is_directory(src_path);
|
||||
const bool dst_is_dir = std::filesystem::is_directory(dst_path);
|
||||
if (src_is_dir && !dst_is_dir) {
|
||||
return ORBIS_KERNEL_ERROR_ENOTDIR;
|
||||
}
|
||||
if (!src_is_dir && dst_is_dir) {
|
||||
return ORBIS_KERNEL_ERROR_EISDIR;
|
||||
}
|
||||
if (dst_is_dir && !std::filesystem::is_empty(dst_path)) {
|
||||
return ORBIS_KERNEL_ERROR_ENOTEMPTY;
|
||||
}
|
||||
std::filesystem::copy(src_path, dst_path, std::filesystem::copy_options::overwrite_existing);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||
std::srand(std::time(nullptr));
|
||||
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
||||
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
|
||||
LIB_FUNCTION("UK2Tl2DWUns", "libkernel", 1, "libkernel", 1, 1, sceKernelClose);
|
||||
|
@ -479,6 +515,7 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("kBwCPsYX-m4", "libkernel", 1, "libkernel", 1, 1, sceKernelFStat);
|
||||
LIB_FUNCTION("mqQMh1zPPT8", "libScePosix", 1, "libkernel", 1, 1, posix_fstat);
|
||||
LIB_FUNCTION("VW3TVZiM4-E", "libkernel", 1, "libkernel", 1, 1, sceKernelFtruncate);
|
||||
LIB_FUNCTION("52NcYU9+lEo", "libkernel", 1, "libkernel", 1, 1, sceKernelRename);
|
||||
|
||||
LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat);
|
||||
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <boost/asio/io_context.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "common/singleton.h"
|
||||
|
@ -84,6 +85,9 @@ static PS4_SYSV_ABI void stack_chk_fail() {
|
|||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
|
||||
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}", fmt::ptr(addr), len);
|
||||
if (len == 0) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);
|
||||
return SCE_OK;
|
||||
|
@ -407,6 +411,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
|||
|
||||
LIB_FUNCTION("2SKEx6bSq-4", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap);
|
||||
LIB_FUNCTION("kBJzF8x4SyE", "libkernel", 1, "libkernel", 1, 1, sceKernelBatchMap2);
|
||||
LIB_FUNCTION("DGMG3JshrZU", "libkernel", 1, "libkernel", 1, 1, sceKernelSetVirtualRangeName);
|
||||
|
||||
// equeue
|
||||
LIB_FUNCTION("D0OdFMjp46I", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEqueue);
|
||||
|
|
|
@ -246,7 +246,8 @@ int PS4_SYSV_ABI sceKernelGetDirectMemoryType(u64 addr, int* directMemoryTypeOut
|
|||
|
||||
s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut) {
|
||||
return sceKernelBatchMap2(entries, numEntries, numEntriesOut, 0x10); // 0x10 : Fixed / 0x410
|
||||
return sceKernelBatchMap2(entries, numEntries, numEntriesOut,
|
||||
MemoryFlags::SCE_KERNEL_MAP_FIXED); // 0x10, 0x410?
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len);
|
||||
|
@ -261,7 +262,7 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
break; // break and assign a value to numEntriesOut.
|
||||
}
|
||||
|
||||
if (entries[i].operation == 0) { // MAP_DIRECT
|
||||
if (entries[i].operation == MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_DIRECT) {
|
||||
result = sceKernelMapNamedDirectMemory(&entries[i].start, entries[i].length,
|
||||
entries[i].protection, flags,
|
||||
static_cast<s64>(entries[i].offset), 0, "");
|
||||
|
@ -274,13 +275,18 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
|
||||
if (result == 0)
|
||||
processed++;
|
||||
<<<<<<< HEAD
|
||||
} else if (entries[i].operation == 1) { // UNMAP
|
||||
=======
|
||||
} else if (entries[i].operation == MemoryOpTypes::ORBIS_KERNEL_MAP_OP_UNMAP) {
|
||||
>>>>>>> cdff4af38da1d832e35d8c057d698f38c64b2932
|
||||
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++;
|
||||
<<<<<<< HEAD
|
||||
} else if (entries[i].operation == 4) { // MPROTECT
|
||||
result =
|
||||
sceKernelMProtect(entries[i].start, entries[i].length, entries[i].protection);
|
||||
|
@ -296,6 +302,19 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
}
|
||||
}
|
||||
else {
|
||||
=======
|
||||
} else if (entries[i].operation == MemoryOpTypes::ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE) {
|
||||
result = sceKernelMapNamedFlexibleMemory(&entries[i].start, entries[i].length,
|
||||
entries[i].protection, flags, "");
|
||||
LOG_INFO(Kernel_Vmm,
|
||||
"BatchMap: entry = {}, operation = {}, len = {:#x}, type = {}, "
|
||||
"result = {}",
|
||||
i, entries[i].operation, entries[i].length, (u8)entries[i].type, result);
|
||||
|
||||
if (result == 0)
|
||||
processed++;
|
||||
} else {
|
||||
>>>>>>> cdff4af38da1d832e35d8c057d698f38c64b2932
|
||||
UNREACHABLE_MSG("called: Unimplemented Operation = {}", entries[i].operation);
|
||||
}
|
||||
}
|
||||
|
@ -305,4 +324,19 @@ s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEn
|
|||
return result;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name) {
|
||||
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;
|
||||
}
|
||||
auto* memory = Core::Memory::Instance();
|
||||
memory->NameVirtualRange(std::bit_cast<VAddr>(addr), len, name);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -31,6 +31,14 @@ enum MemoryProtection : u32 {
|
|||
SCE_KERNEL_PROT_GPU_RW = 0x30 // Permit reads/writes from the GPU
|
||||
};
|
||||
|
||||
enum MemoryOpTypes : u32 {
|
||||
ORBIS_KERNEL_MAP_OP_MAP_DIRECT = 0,
|
||||
ORBIS_KERNEL_MAP_OP_UNMAP = 1,
|
||||
ORBIS_KERNEL_MAP_OP_PROTECT = 2,
|
||||
ORBIS_KERNEL_MAP_OP_MAP_FLEXIBLE = 3,
|
||||
ORBIS_KERNEL_MAP_OP_TYPE_PROTECT = 4
|
||||
};
|
||||
|
||||
struct OrbisQueryInfo {
|
||||
uintptr_t start;
|
||||
uintptr_t end;
|
||||
|
@ -100,4 +108,6 @@ s32 PS4_SYSV_ABI sceKernelBatchMap(OrbisKernelBatchMapEntry* entries, int numEnt
|
|||
s32 PS4_SYSV_ABI sceKernelBatchMap2(OrbisKernelBatchMapEntry* entries, int numEntries,
|
||||
int* numEntriesOut, int flags);
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelSetVirtualRangeName(const void* addr, size_t len, const char* name);
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -394,6 +394,18 @@ int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpuma
|
|||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadGetaffinity(ScePthread thread, /*SceKernelCpumask*/ u64* mask) {
|
||||
LOG_INFO(Kernel_Pthread, "called");
|
||||
|
||||
if (thread == nullptr) {
|
||||
return SCE_KERNEL_ERROR_ESRCH;
|
||||
}
|
||||
|
||||
auto result = scePthreadAttrGetaffinity(&thread->attr, mask);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
|
||||
if (addr == nullptr || *addr != nullptr) {
|
||||
return addr;
|
||||
|
@ -427,11 +439,7 @@ int PS4_SYSV_ABI scePthreadMutexInit(ScePthreadMutex* mutex, const ScePthreadMut
|
|||
|
||||
int result = pthread_mutex_init(&(*mutex)->pth_mutex, &(*attr)->pth_mutex_attr);
|
||||
|
||||
static auto mutex_loc = MUTEX_LOCATION("mutex");
|
||||
(*mutex)->tracy_lock = std::make_unique<tracy::LockableCtx>(&mutex_loc);
|
||||
|
||||
if (name != nullptr) {
|
||||
(*mutex)->tracy_lock->CustomName(name, std::strlen(name));
|
||||
LOG_INFO(Kernel_Pthread, "name={}, result={}", name, result);
|
||||
}
|
||||
|
||||
|
@ -543,15 +551,11 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
|
|||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
(*mutex)->tracy_lock->BeforeLock();
|
||||
|
||||
int result = pthread_mutex_lock(&(*mutex)->pth_mutex);
|
||||
if (result != 0) {
|
||||
LOG_TRACE(Kernel_Pthread, "Locked name={}, result={}", (*mutex)->name, result);
|
||||
}
|
||||
|
||||
(*mutex)->tracy_lock->AfterLock();
|
||||
|
||||
switch (result) {
|
||||
case 0:
|
||||
return SCE_OK;
|
||||
|
@ -577,8 +581,6 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
|
|||
LOG_TRACE(Kernel_Pthread, "Unlocking name={}, result={}", (*mutex)->name, result);
|
||||
}
|
||||
|
||||
(*mutex)->tracy_lock->AfterUnlock();
|
||||
|
||||
switch (result) {
|
||||
case 0:
|
||||
return SCE_OK;
|
||||
|
@ -1183,8 +1185,6 @@ int PS4_SYSV_ABI scePthreadMutexTrylock(ScePthreadMutex* mutex) {
|
|||
LOG_TRACE(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);
|
||||
}
|
||||
|
||||
(*mutex)->tracy_lock->AfterTryLock(result == 0);
|
||||
|
||||
switch (result) {
|
||||
case 0:
|
||||
return ORBIS_OK;
|
||||
|
@ -1243,6 +1243,40 @@ int PS4_SYSV_ABI posix_pthread_attr_destroy(ScePthreadAttr* attr) {
|
|||
return result;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setschedparam(ScePthreadAttr* attr,
|
||||
const SceKernelSchedParam* param) {
|
||||
int result = scePthreadAttrSetschedparam(attr, param);
|
||||
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;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setinheritsched(ScePthreadAttr* attr, int inheritSched) {
|
||||
int result = scePthreadAttrSetinheritsched(attr, inheritSched);
|
||||
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;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_setprio(ScePthread thread, int prio) {
|
||||
int result = scePthreadSetprio(thread, prio);
|
||||
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;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_setdetachstate(ScePthreadAttr* attr, int detachstate) {
|
||||
// LOG_INFO(Kernel_Pthread, "posix pthread_mutexattr_init redirect to scePthreadMutexattrInit");
|
||||
int result = scePthreadAttrSetdetachstate(attr, detachstate);
|
||||
|
@ -1336,14 +1370,56 @@ int PS4_SYSV_ABI posix_sem_wait(sem_t* sem) {
|
|||
return sem_wait(sem);
|
||||
}
|
||||
|
||||
#ifndef HAVE_SEM_TIMEDWAIT
|
||||
int sem_timedwait(sem_t* sem, const struct timespec* abstime) {
|
||||
int rc;
|
||||
while ((rc = sem_trywait(sem)) == EAGAIN) {
|
||||
struct timespec curr_time;
|
||||
clock_gettime(CLOCK_REALTIME, &curr_time);
|
||||
|
||||
s64 remaining_ns = 0;
|
||||
remaining_ns +=
|
||||
(static_cast<s64>(abstime->tv_sec) - static_cast<s64>(curr_time.tv_sec)) * 1000000000L;
|
||||
remaining_ns += static_cast<s64>(abstime->tv_nsec) - static_cast<s64>(curr_time.tv_nsec);
|
||||
|
||||
if (remaining_ns <= 0) {
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
struct timespec sleep_time;
|
||||
sleep_time.tv_sec = 0;
|
||||
if (remaining_ns < 5000000L) {
|
||||
sleep_time.tv_nsec = remaining_ns;
|
||||
} else {
|
||||
sleep_time.tv_nsec = 5000000;
|
||||
}
|
||||
|
||||
nanosleep(&sleep_time, nullptr);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_timedwait(sem_t* sem, const timespec* t) {
|
||||
return sem_timedwait(sem, t);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_post(sem_t* sem) {
|
||||
return sem_post(sem);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_destroy(sem_t* sem) {
|
||||
return sem_destroy(sem);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_sem_getvalue(sem_t* sem, int* sval) {
|
||||
return sem_getvalue(sem, sval);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getstacksize(const pthread_attr_t* attr, size_t* size) {
|
||||
return pthread_attr_getstacksize(attr, size);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadGetschedparam(ScePthread thread, int* policy,
|
||||
SceKernelSchedParam* param) {
|
||||
return pthread_getschedparam(thread->pth, policy, param);
|
||||
|
@ -1403,6 +1479,26 @@ int PS4_SYSV_ABI posix_pthread_condattr_setclock(ScePthreadCondattr* attr, clock
|
|||
return SCE_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_getschedparam(ScePthread thread, int* policy,
|
||||
SceKernelSchedParam* param) {
|
||||
return scePthreadGetschedparam(thread, policy, param);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_setschedparam(ScePthread thread, int policy,
|
||||
const SceKernelSchedParam* param) {
|
||||
return scePthreadSetschedparam(thread, policy, param);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_pthread_attr_getschedpolicy(const ScePthreadAttr* attr, int* policy) {
|
||||
return scePthreadAttrGetschedpolicy(attr, policy);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI scePthreadRename(ScePthread thread, const char* name) {
|
||||
thread->name = name;
|
||||
LOG_INFO(Kernel_Pthread, "scePthreadRename: name = {}", thread->name);
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("lZzFeSxPl08", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setcancelstate);
|
||||
LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init);
|
||||
|
@ -1427,6 +1523,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("EI-5-jlq2dE", "libkernel", 1, "libkernel", 1, 1, scePthreadGetthreadid);
|
||||
LIB_FUNCTION("1tKyG7RlMJo", "libkernel", 1, "libkernel", 1, 1, scePthreadGetprio);
|
||||
LIB_FUNCTION("W0Hpm2X0uPE", "libkernel", 1, "libkernel", 1, 1, scePthreadSetprio);
|
||||
LIB_FUNCTION("GBUY7ywdULE", "libkernel", 1, "libkernel", 1, 1, scePthreadRename);
|
||||
|
||||
LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, scePthreadSelf);
|
||||
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
|
||||
|
@ -1442,6 +1539,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, scePthreadSetaffinity);
|
||||
LIB_FUNCTION("rcrVFJsQWRY", "libkernel", 1, "libkernel", 1, 1, scePthreadGetaffinity);
|
||||
LIB_FUNCTION("6UgtwV+0zb4", "libkernel", 1, "libkernel", 1, 1, scePthreadCreate);
|
||||
LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, scePthreadYield);
|
||||
LIB_FUNCTION("B5GmVDKwpn0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_yield);
|
||||
|
@ -1498,6 +1596,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("EjllaAqAPZo", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_condattr_setclock);
|
||||
LIB_FUNCTION("Z4QosVuAsA0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_once);
|
||||
LIB_FUNCTION("RtLRV-pBTTY", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_getschedpolicy);
|
||||
|
||||
// openorbis weird functions
|
||||
LIB_FUNCTION("7H0iTOciTLo", "libkernel", 1, "libkernel", 1, 1, posix_pthread_mutex_lock);
|
||||
|
@ -1507,15 +1607,26 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("E+tyo3lp5Lw", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_setdetachstate);
|
||||
LIB_FUNCTION("zHchY8ft5pk", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_attr_destroy);
|
||||
LIB_FUNCTION("euKRgm0Vn2M", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_setschedparam);
|
||||
LIB_FUNCTION("7ZlAakEf0Qg", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_setinheritsched);
|
||||
LIB_FUNCTION("a2P9wYGeZvc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setprio);
|
||||
LIB_FUNCTION("Jmi+9w9u0E4", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create_name_np);
|
||||
LIB_FUNCTION("OxhIB8LB-PQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create);
|
||||
LIB_FUNCTION("+U1R4WtXvoc", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_detach);
|
||||
LIB_FUNCTION("CBNtXOoef-E", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_max);
|
||||
LIB_FUNCTION("m0iS6jNsXds", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_min);
|
||||
LIB_FUNCTION("FIs3-UQT9sg", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_getschedparam);
|
||||
LIB_FUNCTION("Xs9hdiD7sAA", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setschedparam);
|
||||
LIB_FUNCTION("pDuPEf3m4fI", "libScePosix", 1, "libkernel", 1, 1, posix_sem_init);
|
||||
LIB_FUNCTION("YCV5dGGBcCo", "libScePosix", 1, "libkernel", 1, 1, posix_sem_wait);
|
||||
LIB_FUNCTION("w5IHyvahg-o", "libScePosix", 1, "libkernel", 1, 1, posix_sem_timedwait);
|
||||
LIB_FUNCTION("IKP8typ0QUk", "libScePosix", 1, "libkernel", 1, 1, posix_sem_post);
|
||||
LIB_FUNCTION("cDW233RAwWo", "libScePosix", 1, "libkernel", 1, 1, posix_sem_destroy);
|
||||
LIB_FUNCTION("Bq+LRV-N6Hk", "libScePosix", 1, "libkernel", 1, 1, posix_sem_getvalue);
|
||||
LIB_FUNCTION("0qOtCR-ZHck", "libScePosix", 1, "libkernel", 1, 1,
|
||||
posix_pthread_attr_getstacksize);
|
||||
// libs
|
||||
RwlockSymbolsRegister(sym);
|
||||
SemaphoreSymbolsRegister(sym);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <vector>
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
#include "common/debug.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
|
@ -74,7 +73,6 @@ struct PthreadMutexInternal {
|
|||
u8 reserved[256];
|
||||
std::string name;
|
||||
pthread_mutex_t pth_mutex;
|
||||
std::unique_ptr<tracy::LockableCtx> tracy_lock;
|
||||
};
|
||||
|
||||
struct PthreadMutexattrInternal {
|
||||
|
@ -169,9 +167,12 @@ ScePthread PS4_SYSV_ABI scePthreadSelf();
|
|||
int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
|
||||
const /*SceKernelCpumask*/ u64 mask);
|
||||
int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpumask*/ u64 mask);
|
||||
int PS4_SYSV_ABI scePthreadGetaffinity(ScePthread thread, /*SceKernelCpumask*/ u64* mask);
|
||||
int PS4_SYSV_ABI scePthreadCreate(ScePthread* thread, const ScePthreadAttr* attr,
|
||||
PthreadEntryFunc start_routine, void* arg, const char* name);
|
||||
|
||||
int PS4_SYSV_ABI scePthreadSetprio(ScePthread thread, int prio);
|
||||
|
||||
/***
|
||||
* Mutex calls
|
||||
*/
|
||||
|
|
|
@ -41,7 +41,6 @@ public:
|
|||
AddWaiter(waiter);
|
||||
|
||||
// Perform the wait.
|
||||
std::exchange(lk, std::unique_lock{waiter.mutex});
|
||||
return waiter.Wait(lk, timeout);
|
||||
}
|
||||
|
||||
|
@ -59,10 +58,9 @@ public:
|
|||
it++;
|
||||
continue;
|
||||
}
|
||||
std::scoped_lock lk2{waiter.mutex};
|
||||
it = wait_list.erase(it);
|
||||
token_count -= waiter.need_count;
|
||||
waiter.cv.notify_one();
|
||||
it = wait_list.erase(it);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -84,7 +82,6 @@ public:
|
|||
|
||||
public:
|
||||
struct WaitingThread : public ListBaseHook {
|
||||
std::mutex mutex;
|
||||
std::string name;
|
||||
std::condition_variable cv;
|
||||
u32 priority;
|
||||
|
|
|
@ -214,6 +214,22 @@ int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) {
|
|||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelConvertLocaltimeToUtc(time_t param_1, int64_t param_2, time_t* seconds,
|
||||
OrbisKernelTimezone* timezone, int* dst_seconds) {
|
||||
LOG_INFO(Kernel, "called");
|
||||
if (timezone) {
|
||||
sceKernelGettimezone(timezone);
|
||||
param_1 -= (timezone->tz_minuteswest + timezone->tz_dsttime) * 60;
|
||||
if (seconds)
|
||||
*seconds = param_1;
|
||||
if (dst_seconds)
|
||||
*dst_seconds = timezone->tz_dsttime * 60;
|
||||
} else {
|
||||
return SCE_KERNEL_ERROR_EINVAL;
|
||||
}
|
||||
return SCE_OK;
|
||||
}
|
||||
|
||||
void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||
clock = std::make_unique<Common::NativeClock>();
|
||||
initial_ptc = clock->GetUptime();
|
||||
|
@ -239,6 +255,7 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime);
|
||||
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
|
||||
LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "core/libraries/np_trophy/np_trophy.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "core/libraries/playgo/playgo.h"
|
||||
#include "core/libraries/random/random.h"
|
||||
#include "core/libraries/rtc/rtc.h"
|
||||
#include "core/libraries/save_data/savedata.h"
|
||||
#include "core/libraries/screenshot/screenshot.h"
|
||||
|
@ -43,8 +44,8 @@ namespace Libraries {
|
|||
void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
||||
LOG_INFO(Lib_Kernel, "Initializing HLE libraries");
|
||||
Libraries::Kernel::LibKernel_Register(sym);
|
||||
Libraries::VideoOut::RegisterLib(sym);
|
||||
Libraries::GnmDriver::RegisterlibSceGnmDriver(sym);
|
||||
Libraries::VideoOut::RegisterLib(sym);
|
||||
if (!Config::isLleLibc()) {
|
||||
Libraries::LibC::libcSymbolsRegister(sym);
|
||||
}
|
||||
|
@ -71,6 +72,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
|
|||
Libraries::AppContent::RegisterlibSceAppContent(sym);
|
||||
Libraries::PngDec::RegisterlibScePngDec(sym);
|
||||
Libraries::PlayGo::RegisterlibScePlayGo(sym);
|
||||
Libraries::Random::RegisterlibSceRandom(sym);
|
||||
Libraries::Usbd::RegisterlibSceUsbd(sym);
|
||||
Libraries::Pad::RegisterlibScePad(sym);
|
||||
Libraries::Ajm::RegisterlibSceAjm(sym);
|
||||
|
|
|
@ -559,7 +559,7 @@ int PS4_SYSV_ABI sceNetEpollDestroy() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetEpollWait() {
|
||||
LOG_ERROR(Lib_Net, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_Net, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ int PS4_SYSV_ABI sceNetCtlUnregisterCallbackV6() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNetCtlCheckCallback() {
|
||||
LOG_ERROR(Lib_NetCtl, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_NetCtl, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -870,7 +870,7 @@ int PS4_SYSV_ABI sceNpAsmTerminate() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpCheckCallback() {
|
||||
LOG_ERROR(Lib_NpManager, "(STUBBED) called");
|
||||
LOG_TRACE(Lib_NpManager, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -3510,4 +3510,4 @@ void RegisterlibSceNpManager(Core::Loader::SymbolsResolver* sym) {
|
|||
sceNpUnregisterStateCallbackForToolkit);
|
||||
};
|
||||
|
||||
} // namespace Libraries::NpManager
|
||||
} // namespace Libraries::NpManager
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <core/file_format/playgo_chunk.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/singleton.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
@ -50,9 +51,16 @@ s32 PS4_SYSV_ABI scePlayGoGetLocus(OrbisPlayGoHandle handle, const OrbisPlayGoCh
|
|||
uint32_t numberOfEntries, OrbisPlayGoLocus* outLoci) {
|
||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called handle = {}, chunkIds = {}, numberOfEntries = {}",
|
||||
handle, *chunkIds, numberOfEntries);
|
||||
// assign all now so that scePlayGoGetLocus is not called again for every single entry
|
||||
std::fill(outLoci, outLoci + numberOfEntries,
|
||||
OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST);
|
||||
|
||||
auto* playgo = Common::Singleton<PlaygoChunk>::Instance();
|
||||
|
||||
for (uint32_t i = 0; i < numberOfEntries; i++) {
|
||||
if (chunkIds[i] <= playgo->GetPlaygoHeader().mchunk_count) {
|
||||
outLoci[i] = OrbisPlayGoLocusValue::ORBIS_PLAYGO_LOCUS_LOCAL_FAST;
|
||||
} else {
|
||||
return ORBIS_PLAYGO_ERROR_BAD_CHUNK_ID;
|
||||
}
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -68,7 +76,7 @@ s32 PS4_SYSV_ABI scePlayGoGetProgress(OrbisPlayGoHandle handle, const OrbisPlayG
|
|||
s32 PS4_SYSV_ABI scePlayGoGetToDoList(OrbisPlayGoHandle handle, OrbisPlayGoToDo* outTodoList,
|
||||
u32 numberOfEntries, u32* outEntries) {
|
||||
LOG_ERROR(Lib_PlayGo, "(STUBBED)called");
|
||||
if (handle != shadMagic)
|
||||
if (handle != 1)
|
||||
return ORBIS_PLAYGO_ERROR_BAD_HANDLE;
|
||||
if (outTodoList == nullptr)
|
||||
return ORBIS_PLAYGO_ERROR_BAD_POINTER;
|
||||
|
@ -86,7 +94,7 @@ s32 PS4_SYSV_ABI scePlayGoInitialize(OrbisPlayGoInitParams* param) {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI scePlayGoOpen(OrbisPlayGoHandle* outHandle, const void* param) {
|
||||
*outHandle = shadMagic;
|
||||
*outHandle = 1;
|
||||
LOG_INFO(Lib_PlayGo, "(STUBBED)called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
|
27
src/core/libraries/random/random.cpp
Normal file
27
src/core/libraries/random/random.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "random.h"
|
||||
|
||||
namespace Libraries::Random {
|
||||
|
||||
s32 PS4_SYSV_ABI sceRandomGetRandomNumber(u8* buf, size_t size) {
|
||||
LOG_TRACE(Lib_Random, "called");
|
||||
if (size > SCE_RANDOM_MAX_SIZE) {
|
||||
return SCE_RANDOM_ERROR_INVALID;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < size; ++i) {
|
||||
buf[i] = std::rand() & 0xFF;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceRandom(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("PI7jIZj4pcE", "libSceRandom", 1, "libSceRandom", 1, 1, sceRandomGetRandomNumber);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Random
|
17
src/core/libraries/random/random.h
Normal file
17
src/core/libraries/random/random.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "common/types.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
|
||||
namespace Libraries::Random {
|
||||
constexpr int32_t SCE_RANDOM_MAX_SIZE = 64;
|
||||
|
||||
s32 PS4_SYSV_ABI sceRandomGetRandomNumber(u8* buf, size_t size);
|
||||
|
||||
void RegisterlibSceRandom(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Random
|
|
@ -15,7 +15,7 @@
|
|||
#include "error_codes.h"
|
||||
|
||||
namespace Libraries::SaveData {
|
||||
|
||||
bool is_rw_mode = false;
|
||||
static constexpr std::string_view g_mount_point = "/savedata0"; // temp mount point (todo)
|
||||
std::string game_serial;
|
||||
|
||||
|
@ -180,27 +180,31 @@ int PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond*
|
|||
OrbisSaveDataDirNameSearchResult* result) {
|
||||
if (cond == nullptr)
|
||||
return ORBIS_SAVE_DATA_ERROR_PARAMETER;
|
||||
LOG_ERROR(Lib_SaveData, "TODO sceSaveDataDirNameSearch: Add params");
|
||||
LOG_INFO(Lib_SaveData, "called");
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(cond->userId) / game_serial;
|
||||
if (!mount_dir.empty() && std::filesystem::exists(mount_dir)) {
|
||||
if (cond->dirName == nullptr) { // look for all dirs if no dir is provided.
|
||||
if (cond->dirName == nullptr || std::string_view(cond->dirName->data)
|
||||
.empty()) { // look for all dirs if no dir is provided.
|
||||
for (int i = 0; const auto& entry : std::filesystem::directory_iterator(mount_dir)) {
|
||||
if (std::filesystem::is_directory(entry.path())) {
|
||||
i++;
|
||||
result->dirNamesNum = 0; // why is it 1024? is it max?
|
||||
if (std::filesystem::is_directory(entry.path()) &&
|
||||
entry.path().filename().string() != "sdmemory") {
|
||||
// sceSaveDataDirNameSearch does not search for dataMemory1/2 dirs.
|
||||
// copy dir name to be used by sceSaveDataMount in read mode.
|
||||
strncpy(result->dirNames[i].data, entry.path().filename().string().c_str(), 32);
|
||||
result->hitNum = i + 1;
|
||||
result->dirNamesNum = i + 1; // to confirm
|
||||
result->setNum = i + 1; // to confirm
|
||||
i++;
|
||||
result->hitNum = i;
|
||||
result->dirNamesNum = i;
|
||||
result->setNum = i;
|
||||
}
|
||||
}
|
||||
} else { // Need a game to test.
|
||||
LOG_ERROR(Lib_SaveData, "Check Me. sceSaveDataDirNameSearch: dirName = {}",
|
||||
cond->dirName->data);
|
||||
strncpy(result->dirNames[0].data, cond->dirName->data, 32);
|
||||
result->hitNum = 1;
|
||||
result->dirNamesNum = 1; // to confirm
|
||||
result->setNum = 1; // to confirm
|
||||
result->dirNamesNum = 1;
|
||||
result->setNum = 1;
|
||||
}
|
||||
} else {
|
||||
result->hitNum = 0;
|
||||
|
@ -303,8 +307,51 @@ int PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountPoi
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceSaveDataGetParam() {
|
||||
LOG_ERROR(Lib_SaveData, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint,
|
||||
const OrbisSaveDataParamType paramType, void* paramBuf,
|
||||
const size_t paramBufSize, size_t* gotSize) {
|
||||
|
||||
if (mountPoint == nullptr)
|
||||
return ORBIS_SAVE_DATA_ERROR_PARAMETER;
|
||||
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto mount_dir = mnt->GetHostPath(mountPoint->data);
|
||||
Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Read);
|
||||
OrbisSaveDataParam params;
|
||||
file.Read(params);
|
||||
|
||||
LOG_INFO(Lib_SaveData, "called");
|
||||
|
||||
switch (paramType) {
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_ALL: {
|
||||
memcpy(paramBuf, ¶ms, sizeof(OrbisSaveDataParam));
|
||||
*gotSize = sizeof(OrbisSaveDataParam);
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_TITLE: {
|
||||
std::memcpy(paramBuf, ¶ms.title, ORBIS_SAVE_DATA_TITLE_MAXSIZE);
|
||||
*gotSize = ORBIS_SAVE_DATA_TITLE_MAXSIZE;
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_SUB_TITLE: {
|
||||
std::memcpy(paramBuf, ¶ms.subTitle, ORBIS_SAVE_DATA_SUBTITLE_MAXSIZE);
|
||||
*gotSize = ORBIS_SAVE_DATA_SUBTITLE_MAXSIZE;
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_DETAIL: {
|
||||
std::memcpy(paramBuf, ¶ms.detail, ORBIS_SAVE_DATA_DETAIL_MAXSIZE);
|
||||
*gotSize = ORBIS_SAVE_DATA_DETAIL_MAXSIZE;
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_USER_PARAM: {
|
||||
std::memcpy(paramBuf, ¶ms.userParam, sizeof(u32));
|
||||
*gotSize = sizeof(u32);
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_MTIME: {
|
||||
std::memcpy(paramBuf, ¶ms.mtime, sizeof(time_t));
|
||||
*gotSize = sizeof(time_t);
|
||||
} break;
|
||||
default: {
|
||||
UNREACHABLE_MSG("Unknown Param = {}", paramType);
|
||||
} break;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -321,7 +368,7 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataCount() {
|
|||
int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const size_t bufSize,
|
||||
const int64_t offset) {
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(userId) / game_serial / "save_mem1.sav";
|
||||
std::to_string(userId) / game_serial / "sdmemory/save_mem1.sav";
|
||||
|
||||
Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
|
@ -336,7 +383,7 @@ int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const
|
|||
|
||||
int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) {
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(getParam->userId) / game_serial;
|
||||
std::to_string(getParam->userId) / game_serial / "sdmemory";
|
||||
if (getParam == nullptr)
|
||||
return ORBIS_SAVE_DATA_ERROR_PARAMETER;
|
||||
if (getParam->data != nullptr) {
|
||||
|
@ -443,6 +490,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
|
|||
case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR:
|
||||
case ORBIS_SAVE_DATA_MOUNT_MODE_RDWR | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF:
|
||||
case ORBIS_SAVE_DATA_MOUNT_MODE_RDONLY | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF: {
|
||||
is_rw_mode = (mount_mode == ORBIS_SAVE_DATA_MOUNT_MODE_RDWR) ? true : false;
|
||||
if (!std::filesystem::exists(mount_dir)) {
|
||||
return ORBIS_SAVE_DATA_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
@ -460,10 +508,6 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
|
|||
case ORBIS_SAVE_DATA_MOUNT_MODE_CREATE | ORBIS_SAVE_DATA_MOUNT_MODE_DESTRUCT_OFF |
|
||||
ORBIS_SAVE_DATA_MOUNT_MODE_COPY_ICON: {
|
||||
if (std::filesystem::exists(mount_dir)) {
|
||||
g_mount_point.copy(mount_result->mount_point.data, 16);
|
||||
mnt->Mount(mount_dir, mount_result->mount_point.data);
|
||||
mount_result->required_blocks = 0;
|
||||
mount_result->mount_status = 0;
|
||||
return ORBIS_SAVE_DATA_ERROR_EXISTS;
|
||||
}
|
||||
if (std::filesystem::create_directories(mount_dir)) {
|
||||
|
@ -483,7 +527,7 @@ s32 saveDataMount(u32 user_id, char* dir_name, u32 mount_mode,
|
|||
mount_result->mount_status = 1;
|
||||
} break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
UNREACHABLE_MSG("Unknown mount mode = {}", mount_mode);
|
||||
}
|
||||
mount_result->required_blocks = 0;
|
||||
|
||||
|
@ -583,15 +627,46 @@ int PS4_SYSV_ABI sceSaveDataSetEventInfo() {
|
|||
int PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint,
|
||||
OrbisSaveDataParamType paramType, const void* paramBuf,
|
||||
size_t paramBufSize) {
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto mount_dir = mnt->GetHostPath(mountPoint->data);
|
||||
LOG_INFO(Lib_SaveData, "called = {}, mountPoint->data = {}", mount_dir.string(),
|
||||
mountPoint->data);
|
||||
if (paramBuf == nullptr)
|
||||
return ORBIS_SAVE_DATA_ERROR_PARAMETER;
|
||||
|
||||
if (paramBuf != nullptr) {
|
||||
Common::FS::IOFile file(mount_dir / "param.txt", Common::FS::FileAccessMode::Write);
|
||||
file.WriteRaw<u8>(paramBuf, paramBufSize);
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto mount_dir = mnt->GetHostPath(mountPoint->data) / "param.txt";
|
||||
OrbisSaveDataParam params;
|
||||
if (std::filesystem::exists(mount_dir)) {
|
||||
Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Read);
|
||||
file.ReadRaw<u8>(¶ms, sizeof(OrbisSaveDataParam));
|
||||
}
|
||||
|
||||
LOG_INFO(Lib_SaveData, "called");
|
||||
|
||||
switch (paramType) {
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_ALL: {
|
||||
memcpy(¶ms, paramBuf, sizeof(OrbisSaveDataParam));
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_TITLE: {
|
||||
strncpy(params.title, static_cast<const char*>(paramBuf), paramBufSize);
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_SUB_TITLE: {
|
||||
strncpy(params.subTitle, static_cast<const char*>(paramBuf), paramBufSize);
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_DETAIL: {
|
||||
strncpy(params.detail, static_cast<const char*>(paramBuf), paramBufSize);
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_USER_PARAM: {
|
||||
params.userParam = *(static_cast<const u32*>(paramBuf));
|
||||
} break;
|
||||
case ORBIS_SAVE_DATA_PARAM_TYPE_MTIME: {
|
||||
params.mtime = *(static_cast<const time_t*>(paramBuf));
|
||||
} break;
|
||||
default: {
|
||||
UNREACHABLE_MSG("Unknown Param = {}", paramType);
|
||||
}
|
||||
}
|
||||
|
||||
Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Write);
|
||||
file.WriteRaw<u8>(¶ms, sizeof(OrbisSaveDataParam));
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -604,11 +679,11 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf,
|
|||
const size_t bufSize, const int64_t offset) {
|
||||
LOG_INFO(Lib_SaveData, "called");
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(userId) / game_serial / "save_mem1.sav";
|
||||
std::to_string(userId) / game_serial / "sdmemory/save_mem1.sav";
|
||||
|
||||
Common::FS::IOFile file(mount_dir, Common::FS::FileAccessMode::Write);
|
||||
file.Seek(offset);
|
||||
file.WriteRaw<u8>((void*)buf, bufSize);
|
||||
file.WriteRaw<u8>(buf, bufSize);
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -616,13 +691,13 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(const u32 userId, const void* buf,
|
|||
int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) {
|
||||
LOG_INFO(Lib_SaveData, "called: dataNum = {}, slotId= {}", setParam->dataNum, setParam->slotId);
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(setParam->userId) / game_serial;
|
||||
std::to_string(setParam->userId) / game_serial / "sdmemory";
|
||||
if (setParam->data != nullptr) {
|
||||
Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Write);
|
||||
if (!file.IsOpen())
|
||||
return -1;
|
||||
file.Seek(setParam->data->offset);
|
||||
file.WriteRaw<u8>((void*)setParam->data->buf, setParam->data->bufSize);
|
||||
file.WriteRaw<u8>(setParam->data->buf, setParam->data->bufSize);
|
||||
}
|
||||
|
||||
if (setParam->param != nullptr) {
|
||||
|
@ -632,7 +707,7 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* se
|
|||
|
||||
if (setParam->icon != nullptr) {
|
||||
Common::FS::IOFile file(mount_dir / "save_icon.png", Common::FS::FileAccessMode::Write);
|
||||
file.WriteRaw<u8>((void*)setParam->icon->buf, setParam->icon->bufSize);
|
||||
file.WriteRaw<u8>(setParam->icon->buf, setParam->icon->bufSize);
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
|
@ -644,7 +719,7 @@ int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(u32 userId, size_t memorySize,
|
|||
LOG_INFO(Lib_SaveData, "called:userId = {}, memorySize = {}", userId, memorySize);
|
||||
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(userId) / game_serial;
|
||||
std::to_string(userId) / game_serial / "sdmemory";
|
||||
|
||||
if (std::filesystem::exists(mount_dir)) {
|
||||
return ORBIS_SAVE_DATA_ERROR_EXISTS;
|
||||
|
@ -663,7 +738,7 @@ int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2
|
|||
LOG_INFO(Lib_SaveData, "called");
|
||||
// if (setupParam->option == 1) { // check this later.
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(setupParam->userId) / game_serial;
|
||||
std::to_string(setupParam->userId) / game_serial / "sdmemory";
|
||||
if (std::filesystem::exists(mount_dir) &&
|
||||
std::filesystem::exists(mount_dir / "save_mem2.sav")) {
|
||||
Common::FS::IOFile file(mount_dir / "save_mem2.sav", Common::FS::FileAccessMode::Read);
|
||||
|
@ -717,16 +792,17 @@ int PS4_SYSV_ABI sceSaveDataTransferringMount() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceSaveDataUmount(const OrbisSaveDataMountPoint* mountPoint) {
|
||||
LOG_INFO(Lib_SaveData, "mountPoint = {}", std::string(mountPoint->data));
|
||||
if (std::string(mountPoint->data).empty()) {
|
||||
return ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED;
|
||||
}
|
||||
const auto& mount_dir = Common::FS::GetUserPath(Common::FS::PathType::SaveDataDir) /
|
||||
std::to_string(1) / game_serial / mountPoint->data;
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
|
||||
const auto& guest_path = mnt->GetHostPath(mountPoint->data);
|
||||
if (guest_path.empty())
|
||||
return ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED;
|
||||
mnt->Unmount(mount_dir, mountPoint->data);
|
||||
LOG_INFO(Lib_SaveData, "mountPoint = {}", std::string(mountPoint->data));
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -736,23 +812,33 @@ int PS4_SYSV_ABI sceSaveDataUmountSys() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceSaveDataUmountWithBackup(const OrbisSaveDataMountPoint* mountPoint) {
|
||||
LOG_ERROR(Lib_SaveData, "called = {}", std::string(mountPoint->data));
|
||||
LOG_INFO(Lib_SaveData, "called mount = {}, is_rw_mode = {}", std::string(mountPoint->data),
|
||||
is_rw_mode);
|
||||
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||
const auto mount_dir = mnt->GetHostPath(mountPoint->data);
|
||||
if (!std::filesystem::exists(mount_dir)) {
|
||||
return ORBIS_SAVE_DATA_ERROR_NOT_FOUND;
|
||||
}
|
||||
// leave disabled for now. and just unmount.
|
||||
|
||||
std::filesystem::create_directories(mount_dir.parent_path() / "backup");
|
||||
/* if (is_rw_mode) { // backup is done only when mount mode is ReadWrite.
|
||||
auto backup_path = mount_dir;
|
||||
std::string save_data_dir = (mount_dir.string() + "_backup");
|
||||
backup_path.replace_filename(save_data_dir);
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(mount_dir)) {
|
||||
const auto& path = entry.path();
|
||||
const auto target_path = mount_dir.parent_path() / "backup";
|
||||
if (std::filesystem::is_regular_file(path)) {
|
||||
std::filesystem::copy(path, target_path,
|
||||
std::filesystem::copy_options::overwrite_existing);
|
||||
std::filesystem::create_directories(backup_path);
|
||||
|
||||
for (const auto& entry : std::filesystem::recursive_directory_iterator(mount_dir)) {
|
||||
const auto& path = entry.path();
|
||||
if (std::filesystem::is_regular_file(path)) {
|
||||
std::filesystem::copy(path, save_data_dir,
|
||||
std::filesystem::copy_options::overwrite_existing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
const auto& guest_path = mnt->GetHostPath(mountPoint->data);
|
||||
if (guest_path.empty())
|
||||
return ORBIS_SAVE_DATA_ERROR_NOT_MOUNTED;
|
||||
|
||||
mnt->Unmount(mount_dir, mountPoint->data);
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -242,6 +242,13 @@ struct OrbisSaveDataMemorySync {
|
|||
u8 reserved[28];
|
||||
};
|
||||
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_ALL = 0;
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_TITLE = 1;
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_SUB_TITLE = 2;
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_DETAIL = 3;
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_USER_PARAM = 4;
|
||||
constexpr int ORBIS_SAVE_DATA_PARAM_TYPE_MTIME = 5;
|
||||
|
||||
int PS4_SYSV_ABI sceSaveDataAbort();
|
||||
int PS4_SYSV_ABI sceSaveDataBackup();
|
||||
int PS4_SYSV_ABI sceSaveDataBindPsnAccount();
|
||||
|
@ -291,7 +298,9 @@ int PS4_SYSV_ABI sceSaveDataGetFormat();
|
|||
int PS4_SYSV_ABI sceSaveDataGetMountedSaveDataCount();
|
||||
int PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountPoint,
|
||||
OrbisSaveDataMountInfo* info);
|
||||
int PS4_SYSV_ABI sceSaveDataGetParam();
|
||||
int PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint,
|
||||
const OrbisSaveDataParamType paramType, void* paramBuf,
|
||||
const size_t paramBufSize, size_t* gotSize);
|
||||
int PS4_SYSV_ABI sceSaveDataGetProgress();
|
||||
int PS4_SYSV_ABI sceSaveDataGetSaveDataCount();
|
||||
int PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const u32 userId, void* buf, const size_t bufSize,
|
||||
|
|
|
@ -3,14 +3,16 @@
|
|||
|
||||
#include <pthread.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/kernel/time_management.h"
|
||||
#include "core/libraries/videoout/driver.h"
|
||||
#include "core/platform.h"
|
||||
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::RendererVulkan> renderer;
|
||||
extern std::unique_ptr<AmdGpu::Liverpool> liverpool;
|
||||
|
||||
namespace Libraries::VideoOut {
|
||||
|
||||
|
@ -41,20 +43,18 @@ VideoOutDriver::VideoOutDriver(u32 width, u32 height) {
|
|||
main_port.resolution.fullHeight = height;
|
||||
main_port.resolution.paneWidth = width;
|
||||
main_port.resolution.paneHeight = height;
|
||||
present_thread = std::jthread([&](std::stop_token token) { PresentThread(token); });
|
||||
}
|
||||
|
||||
VideoOutDriver::~VideoOutDriver() = default;
|
||||
|
||||
int VideoOutDriver::Open(const ServiceThreadParams* params) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
if (main_port.is_open) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_RESOURCE_BUSY;
|
||||
}
|
||||
|
||||
int handle = 1;
|
||||
main_port.is_open = true;
|
||||
return handle;
|
||||
liverpool->SetVoPort(&main_port);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void VideoOutDriver::Close(s32 handle) {
|
||||
|
@ -158,31 +158,22 @@ int VideoOutDriver::UnregisterBuffers(VideoOutPort* port, s32 attributeIndex) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void VideoOutDriver::Flip(std::chrono::microseconds timeout) {
|
||||
Request req;
|
||||
{
|
||||
std::unique_lock lock{mutex};
|
||||
submit_cond.wait_for(lock, timeout, [&] { return !requests.empty(); });
|
||||
if (requests.empty()) {
|
||||
renderer->ShowSplash();
|
||||
return;
|
||||
}
|
||||
|
||||
// Retrieve the request.
|
||||
req = requests.front();
|
||||
requests.pop();
|
||||
std::chrono::microseconds VideoOutDriver::Flip(const Request& req) {
|
||||
if (!req) {
|
||||
return std::chrono::microseconds{0};
|
||||
}
|
||||
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Whatever the game is rendering show splash if it is active
|
||||
if (!renderer->ShowSplash(req.frame)) {
|
||||
// Present the frame.
|
||||
renderer->Present(req.frame);
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
// Update flip status.
|
||||
auto& flip_status = req.port->flip_status;
|
||||
auto* port = req.port;
|
||||
auto& flip_status = port->flip_status;
|
||||
flip_status.count++;
|
||||
flip_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
flip_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
|
@ -192,7 +183,7 @@ void VideoOutDriver::Flip(std::chrono::microseconds timeout) {
|
|||
flip_status.flipPendingNum = static_cast<int>(requests.size());
|
||||
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : req.port->flip_events) {
|
||||
for (auto& event : port->flip_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(SCE_VIDEO_OUT_EVENT_FLIP, Kernel::SceKernelEvent::Filter::VideoOut,
|
||||
reinterpret_cast<void*>(req.flip_arg));
|
||||
|
@ -201,21 +192,23 @@ void VideoOutDriver::Flip(std::chrono::microseconds timeout) {
|
|||
|
||||
// Reset flip label
|
||||
if (req.index != -1) {
|
||||
req.port->buffer_labels[req.index] = 0;
|
||||
port->buffer_labels[req.index] = 0;
|
||||
port->SignalVoLabel();
|
||||
}
|
||||
|
||||
const auto end = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||
}
|
||||
|
||||
bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
|
||||
bool is_eop /*= false*/) {
|
||||
std::scoped_lock lock{mutex};
|
||||
|
||||
Vulkan::Frame* frame;
|
||||
if (index == -1) {
|
||||
frame = renderer->PrepareBlankFrame();
|
||||
} else {
|
||||
const auto& buffer = port->buffer_slots[index];
|
||||
const auto& group = port->groups[buffer.group_index];
|
||||
frame = renderer->PrepareFrame(group, buffer.address_left);
|
||||
frame = renderer->PrepareFrame(group, buffer.address_left, is_eop);
|
||||
}
|
||||
|
||||
if (index != -1 && requests.size() >= port->NumRegisteredBuffers()) {
|
||||
|
@ -223,6 +216,7 @@ bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
|
|||
return false;
|
||||
}
|
||||
|
||||
std::scoped_lock lock{mutex};
|
||||
requests.push({
|
||||
.frame = frame,
|
||||
.port = port,
|
||||
|
@ -234,24 +228,53 @@ bool VideoOutDriver::SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg,
|
|||
|
||||
port->flip_status.flipPendingNum = static_cast<int>(requests.size());
|
||||
port->flip_status.gcQueueNum = 0;
|
||||
submit_cond.notify_one();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void VideoOutDriver::Vblank() {
|
||||
std::scoped_lock lock{mutex};
|
||||
void VideoOutDriver::PresentThread(std::stop_token token) {
|
||||
static constexpr std::chrono::milliseconds VblankPeriod{16};
|
||||
Common::SetCurrentThreadName("PresentThread");
|
||||
|
||||
auto& vblank_status = main_port.vblank_status;
|
||||
vblank_status.count++;
|
||||
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
const auto receive_request = [this] -> Request {
|
||||
std::scoped_lock lk{mutex};
|
||||
if (!requests.empty()) {
|
||||
const auto request = requests.front();
|
||||
requests.pop();
|
||||
return request;
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : main_port.vblank_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(SCE_VIDEO_OUT_EVENT_VBLANK,
|
||||
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
|
||||
auto vblank_period = VblankPeriod / Config::vblankDiv();
|
||||
auto delay = std::chrono::microseconds{0};
|
||||
while (!token.stop_requested()) {
|
||||
// Sleep for most of the vblank duration.
|
||||
std::this_thread::sleep_for(vblank_period - delay);
|
||||
|
||||
// Check if it's time to take a request.
|
||||
auto& vblank_status = main_port.vblank_status;
|
||||
if (vblank_status.count % (main_port.flip_rate + 1) == 0) {
|
||||
const auto request = receive_request();
|
||||
delay = Flip(request);
|
||||
FRAME_END;
|
||||
}
|
||||
|
||||
{
|
||||
// Needs lock here as can be concurrently read by `sceVideoOutGetVblankStatus`
|
||||
std::unique_lock lock{main_port.vo_mutex};
|
||||
vblank_status.count++;
|
||||
vblank_status.processTime = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
vblank_status.tsc = Libraries::Kernel::sceKernelReadTsc();
|
||||
main_port.vblank_cv.notify_all();
|
||||
}
|
||||
|
||||
// Trigger flip events for the port.
|
||||
for (auto& event : main_port.vblank_events) {
|
||||
if (event != nullptr) {
|
||||
event->TriggerEvent(SCE_VIDEO_OUT_EVENT_VBLANK,
|
||||
Kernel::SceKernelEvent::Filter::VideoOut, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/polyfill_thread.h"
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include "core/libraries/videoout/video_out.h"
|
||||
|
||||
namespace Vulkan {
|
||||
struct Frame;
|
||||
|
@ -25,6 +28,9 @@ struct VideoOutPort {
|
|||
SceVideoOutVblankStatus vblank_status;
|
||||
std::vector<Kernel::SceKernelEqueue> flip_events;
|
||||
std::vector<Kernel::SceKernelEqueue> vblank_events;
|
||||
std::mutex vo_mutex;
|
||||
std::condition_variable vo_cv;
|
||||
std::condition_variable vblank_cv;
|
||||
int flip_rate = 0;
|
||||
|
||||
s32 FindFreeGroup() const {
|
||||
|
@ -35,6 +41,22 @@ struct VideoOutPort {
|
|||
return index;
|
||||
}
|
||||
|
||||
bool IsVoLabel(const u64* address) const {
|
||||
const u64* start = &buffer_labels[0];
|
||||
const u64* end = &buffer_labels[MaxDisplayBuffers - 1];
|
||||
return address >= start && address <= end;
|
||||
}
|
||||
|
||||
void WaitVoLabel(auto&& pred) {
|
||||
std::unique_lock lk{vo_mutex};
|
||||
vo_cv.wait(lk, pred);
|
||||
}
|
||||
|
||||
void SignalVoLabel() {
|
||||
std::scoped_lock lk{vo_mutex};
|
||||
vo_cv.notify_one();
|
||||
}
|
||||
|
||||
[[nodiscard]] int NumRegisteredBuffers() const {
|
||||
return std::count_if(buffer_slots.cbegin(), buffer_slots.cend(),
|
||||
[](auto& buffer) { return buffer.group_index != -1; });
|
||||
|
@ -63,11 +85,8 @@ public:
|
|||
const BufferAttribute* attribute);
|
||||
int UnregisterBuffers(VideoOutPort* port, s32 attributeIndex);
|
||||
|
||||
void Flip(std::chrono::microseconds timeout);
|
||||
bool SubmitFlip(VideoOutPort* port, s32 index, s64 flip_arg, bool is_eop = false);
|
||||
|
||||
void Vblank();
|
||||
|
||||
private:
|
||||
struct Request {
|
||||
Vulkan::Frame* frame;
|
||||
|
@ -76,14 +95,19 @@ private:
|
|||
s64 flip_arg;
|
||||
u64 submit_tsc;
|
||||
bool eop;
|
||||
|
||||
operator bool() const noexcept {
|
||||
return frame != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
std::chrono::microseconds Flip(const Request& req);
|
||||
void PresentThread(std::stop_token token);
|
||||
|
||||
std::mutex mutex;
|
||||
VideoOutPort main_port{};
|
||||
std::condition_variable_any submit_cond;
|
||||
std::condition_variable done_cond;
|
||||
std::jthread present_thread;
|
||||
std::queue<Request> requests;
|
||||
bool is_neo{};
|
||||
};
|
||||
|
||||
} // namespace Libraries::VideoOut
|
||||
|
|
|
@ -183,6 +183,7 @@ s32 PS4_SYSV_ABI sceVideoOutGetVblankStatus(int handle, SceVideoOutVblankStatus*
|
|||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
std::unique_lock lock{port->vo_mutex};
|
||||
*status = port->vblank_status;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -229,14 +230,6 @@ s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
|
|||
return driver->UnregisterBuffers(port, attributeIndex);
|
||||
}
|
||||
|
||||
void Flip(std::chrono::microseconds micros) {
|
||||
return driver->Flip(micros);
|
||||
}
|
||||
|
||||
void Vblank() {
|
||||
return driver->Vblank();
|
||||
}
|
||||
|
||||
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr) {
|
||||
auto* port = driver->GetPort(handle);
|
||||
ASSERT(port);
|
||||
|
@ -266,6 +259,18 @@ s32 PS4_SYSV_ABI sceVideoOutGetDeviceCapabilityInfo(
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceVideoOutWaitVblank(s32 handle) {
|
||||
auto* port = driver->GetPort(handle);
|
||||
if (!port) {
|
||||
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
std::unique_lock lock{port->vo_mutex};
|
||||
const auto prev_counter = port->vblank_status.count;
|
||||
port->vblank_cv.wait(lock, [&]() { return prev_counter != port->vblank_status.count; });
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
||||
driver = std::make_unique<VideoOutDriver>(Config::getScreenWidth(), Config::getScreenHeight());
|
||||
|
||||
|
@ -294,6 +299,7 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
|||
sceVideoOutGetVblankStatus);
|
||||
LIB_FUNCTION("kGVLc3htQE8", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutGetDeviceCapabilityInfo);
|
||||
LIB_FUNCTION("j6RaAUlaLv0", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutWaitVblank);
|
||||
|
||||
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
|
||||
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);
|
||||
|
|
|
@ -92,11 +92,12 @@ void PS4_SYSV_ABI sceVideoOutSetBufferAttribute(BufferAttribute* attribute, Pixe
|
|||
u32 tilingMode, u32 aspectRatio, u32 width,
|
||||
u32 height, u32 pitchInPixel);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddVBlankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
||||
s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
|
||||
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
|
||||
s32 bufferNum, const BufferAttribute* attribute);
|
||||
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
|
||||
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceVideoOutWaitVblank(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceVideoOutSubmitFlip(s32 handle, s32 bufferIndex, s32 flipMode, s64 flipArg);
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetFlipStatus(s32 handle, FlipStatus* status);
|
||||
s32 PS4_SYSV_ABI sceVideoOutGetResolutionStatus(s32 handle, SceVideoOutResolutionStatus* status);
|
||||
|
@ -104,9 +105,6 @@ s32 PS4_SYSV_ABI sceVideoOutOpen(SceUserServiceUserId userId, s32 busType, s32 i
|
|||
const void* param);
|
||||
s32 PS4_SYSV_ABI sceVideoOutClose(s32 handle);
|
||||
|
||||
void Flip(std::chrono::microseconds micros);
|
||||
void Vblank();
|
||||
|
||||
// Internal system functions
|
||||
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr);
|
||||
s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk);
|
||||
|
|
|
@ -193,7 +193,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
|
|||
|
||||
// Find first free area to map the file.
|
||||
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||
mapped_addr = SearchFree(mapped_addr, size_aligned);
|
||||
mapped_addr = SearchFree(mapped_addr, size_aligned, 1);
|
||||
}
|
||||
|
||||
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||
|
@ -240,6 +240,7 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) {
|
|||
vma.prot = MemoryProt::NoAccess;
|
||||
vma.phys_base = 0;
|
||||
vma.disallow_merge = false;
|
||||
vma.name = "";
|
||||
MergeAdjacent(vma_map, new_it);
|
||||
|
||||
// Unmap the memory region.
|
||||
|
@ -334,6 +335,7 @@ int MemoryManager::VirtualQuery(VAddr addr, int flags,
|
|||
info->is_flexible.Assign(vma.type == VMAType::Flexible);
|
||||
info->is_direct.Assign(vma.type == VMAType::Direct);
|
||||
info->is_commited.Assign(vma.type != VMAType::Free);
|
||||
vma.name.copy(info->name.data(), std::min(info->name.size(), vma.name.size()));
|
||||
if (vma.type == VMAType::Direct) {
|
||||
const auto dmem_it = FindDmemArea(vma.phys_base);
|
||||
ASSERT(dmem_it != dmem_map.end());
|
||||
|
@ -392,8 +394,23 @@ std::pair<vk::Buffer, size_t> MemoryManager::GetVulkanBuffer(VAddr addr) {
|
|||
return std::make_pair(*it->second.buffer, addr - it->first);
|
||||
}
|
||||
|
||||
VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment) {
|
||||
void MemoryManager::NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name) {
|
||||
auto it = FindVMA(virtual_addr);
|
||||
|
||||
ASSERT_MSG(it->second.Contains(virtual_addr, size),
|
||||
"Range provided is not fully containted in vma");
|
||||
it->second.name = name;
|
||||
}
|
||||
VAddr MemoryManager::SearchFree(VAddr virtual_addr, size_t size, u32 alignment) {
|
||||
// If the requested address is below the mapped range, start search from the lowest address
|
||||
auto min_search_address = impl.SystemManagedVirtualBase();
|
||||
if (virtual_addr < min_search_address) {
|
||||
virtual_addr = min_search_address;
|
||||
}
|
||||
|
||||
auto it = FindVMA(virtual_addr);
|
||||
ASSERT_MSG(it != vma_map.end(), "Specified mapping address was not found!");
|
||||
|
||||
// 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;
|
||||
|
|
|
@ -179,6 +179,8 @@ public:
|
|||
int GetDirectMemoryType(PAddr addr, int* directMemoryTypeOut, void** directMemoryStartOut,
|
||||
void** directMemoryEndOut);
|
||||
|
||||
void NameVirtualRange(VAddr virtual_addr, size_t size, std::string_view name);
|
||||
|
||||
private:
|
||||
VMAHandle FindVMA(VAddr target) {
|
||||
return std::prev(vma_map.upper_bound(target));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue