Misc implementations and fixes. (#250)
* Implement `sceKernelFtruncate` and `sceKernelUnlink`. * Remove unused variable. * Implement `sceKernelReserveVirtualRange`, misc fixes * Fix `sceKernelReserveVirtualRange`. * Add TODO on reserve * Replace comment with assert. * Add missing copyright header * Add `UNREACHABLE` for `IOFile::Unlink`. * Move NT API initialization out of the header * Fix bug where files were always mapped as read only. * `clang-format`
This commit is contained in:
parent
989f88837d
commit
914aa10875
|
@ -270,6 +270,8 @@ set(COMMON src/common/logging/backend.cpp
|
||||||
src/common/types.h
|
src/common/types.h
|
||||||
src/common/uint128.h
|
src/common/uint128.h
|
||||||
src/common/version.h
|
src/common/version.h
|
||||||
|
src/common/ntapi.h
|
||||||
|
src/common/ntapi.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CORE src/core/aerolib/stubs.cpp
|
set(CORE src/core/aerolib/stubs.cpp
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#include "common/ntapi.h"
|
||||||
|
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#include <share.h>
|
#include <share.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -221,15 +223,46 @@ void IOFile::Close() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IOFile::Unlink() {
|
||||||
|
if (!IsOpen()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark the file for deletion
|
||||||
|
// TODO: Also remove the file path?
|
||||||
|
#if _WIN64
|
||||||
|
FILE_DISPOSITION_INFORMATION disposition;
|
||||||
|
IO_STATUS_BLOCK iosb;
|
||||||
|
|
||||||
|
const int fd = fileno(file);
|
||||||
|
HANDLE hfile = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||||
|
|
||||||
|
disposition.DeleteFile = TRUE;
|
||||||
|
NtSetInformationFile(hfile, &iosb, &disposition, sizeof(disposition),
|
||||||
|
FileDispositionInformation);
|
||||||
|
#else
|
||||||
|
UNREACHABLE_MSG("Missing Linux implementation");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
uintptr_t IOFile::GetFileMapping() {
|
uintptr_t IOFile::GetFileMapping() {
|
||||||
if (file_mapping) {
|
if (file_mapping) {
|
||||||
return file_mapping;
|
return file_mapping;
|
||||||
}
|
}
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
const int fd = fileno(file);
|
const int fd = fileno(file);
|
||||||
|
|
||||||
HANDLE hfile = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
HANDLE hfile = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
|
||||||
HANDLE mapping =
|
HANDLE mapping = nullptr;
|
||||||
CreateFileMapping2(hfile, NULL, FILE_MAP_READ, PAGE_READONLY, SEC_COMMIT, 0, NULL, NULL, 0);
|
|
||||||
|
if (file_access_mode == FileAccessMode::ReadWrite) {
|
||||||
|
mapping = CreateFileMapping2(hfile, NULL, FILE_MAP_WRITE, PAGE_READWRITE, SEC_COMMIT, 0,
|
||||||
|
NULL, NULL, 0);
|
||||||
|
} else {
|
||||||
|
mapping = CreateFileMapping2(hfile, NULL, FILE_MAP_READ, PAGE_READONLY, SEC_COMMIT, 0, NULL,
|
||||||
|
NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
file_mapping = std::bit_cast<uintptr_t>(mapping);
|
file_mapping = std::bit_cast<uintptr_t>(mapping);
|
||||||
ASSERT_MSG(file_mapping, "{}", Common::GetLastErrorMsg());
|
ASSERT_MSG(file_mapping, "{}", Common::GetLastErrorMsg());
|
||||||
return file_mapping;
|
return file_mapping;
|
||||||
|
|
|
@ -107,6 +107,8 @@ public:
|
||||||
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
FileShareFlag flag = FileShareFlag::ShareReadOnly);
|
||||||
void Close();
|
void Close();
|
||||||
|
|
||||||
|
void Unlink();
|
||||||
|
|
||||||
bool Flush() const;
|
bool Flush() const;
|
||||||
bool Commit() const;
|
bool Commit() const;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include "ntapi.h"
|
||||||
|
|
||||||
|
NtDelayExecution_t NtDelayExecution = nullptr;
|
||||||
|
NtSetInformationFile_t NtSetInformationFile = nullptr;
|
||||||
|
|
||||||
|
namespace Common::NtApi {
|
||||||
|
|
||||||
|
void Initialize() {
|
||||||
|
HMODULE nt_handle = GetModuleHandleA("ntdll.dll");
|
||||||
|
|
||||||
|
// http://stackoverflow.com/a/31411628/4725495
|
||||||
|
NtDelayExecution = (NtDelayExecution_t)GetProcAddress(nt_handle, "NtDelayExecution");
|
||||||
|
NtSetInformationFile =
|
||||||
|
(NtSetInformationFile_t)GetProcAddress(nt_handle, "NtSetInformationFile");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Common::NtApi
|
|
@ -0,0 +1,124 @@
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
#include "common/types.h"
|
||||||
|
|
||||||
|
typedef enum _FILE_INFORMATION_CLASS {
|
||||||
|
FileDirectoryInformation = 1,
|
||||||
|
FileFullDirectoryInformation = 2,
|
||||||
|
FileBothDirectoryInformation = 3,
|
||||||
|
FileBasicInformation = 4,
|
||||||
|
FileStandardInformation = 5,
|
||||||
|
FileInternalInformation = 6,
|
||||||
|
FileEaInformation = 7,
|
||||||
|
FileAccessInformation = 8,
|
||||||
|
FileNameInformation = 9,
|
||||||
|
FileRenameInformation = 10,
|
||||||
|
FileLinkInformation = 11,
|
||||||
|
FileNamesInformation = 12,
|
||||||
|
FileDispositionInformation = 13,
|
||||||
|
FilePositionInformation = 14,
|
||||||
|
FileFullEaInformation = 15,
|
||||||
|
FileModeInformation = 16,
|
||||||
|
FileAlignmentInformation = 17,
|
||||||
|
FileAllInformation = 18,
|
||||||
|
FileAllocationInformation = 19,
|
||||||
|
FileEndOfFileInformation = 20,
|
||||||
|
FileAlternateNameInformation = 21,
|
||||||
|
FileStreamInformation = 22,
|
||||||
|
FilePipeInformation = 23,
|
||||||
|
FilePipeLocalInformation = 24,
|
||||||
|
FilePipeRemoteInformation = 25,
|
||||||
|
FileMailslotQueryInformation = 26,
|
||||||
|
FileMailslotSetInformation = 27,
|
||||||
|
FileCompressionInformation = 28,
|
||||||
|
FileObjectIdInformation = 29,
|
||||||
|
FileCompletionInformation = 30,
|
||||||
|
FileMoveClusterInformation = 31,
|
||||||
|
FileQuotaInformation = 32,
|
||||||
|
FileReparsePointInformation = 33,
|
||||||
|
FileNetworkOpenInformation = 34,
|
||||||
|
FileAttributeTagInformation = 35,
|
||||||
|
FileTrackingInformation = 36,
|
||||||
|
FileIdBothDirectoryInformation = 37,
|
||||||
|
FileIdFullDirectoryInformation = 38,
|
||||||
|
FileValidDataLengthInformation = 39,
|
||||||
|
FileShortNameInformation = 40,
|
||||||
|
FileIoCompletionNotificationInformation = 41,
|
||||||
|
FileIoStatusBlockRangeInformation = 42,
|
||||||
|
FileIoPriorityHintInformation = 43,
|
||||||
|
FileSfioReserveInformation = 44,
|
||||||
|
FileSfioVolumeInformation = 45,
|
||||||
|
FileHardLinkInformation = 46,
|
||||||
|
FileProcessIdsUsingFileInformation = 47,
|
||||||
|
FileNormalizedNameInformation = 48,
|
||||||
|
FileNetworkPhysicalNameInformation = 49,
|
||||||
|
FileIdGlobalTxDirectoryInformation = 50,
|
||||||
|
FileIsRemoteDeviceInformation = 51,
|
||||||
|
FileUnusedInformation = 52,
|
||||||
|
FileNumaNodeInformation = 53,
|
||||||
|
FileStandardLinkInformation = 54,
|
||||||
|
FileRemoteProtocolInformation = 55,
|
||||||
|
FileRenameInformationBypassAccessCheck = 56,
|
||||||
|
FileLinkInformationBypassAccessCheck = 57,
|
||||||
|
FileVolumeNameInformation = 58,
|
||||||
|
FileIdInformation = 59,
|
||||||
|
FileIdExtdDirectoryInformation = 60,
|
||||||
|
FileReplaceCompletionInformation = 61,
|
||||||
|
FileHardLinkFullIdInformation = 62,
|
||||||
|
FileIdExtdBothDirectoryInformation = 63,
|
||||||
|
FileDispositionInformationEx = 64,
|
||||||
|
FileRenameInformationEx = 65,
|
||||||
|
FileRenameInformationExBypassAccessCheck = 66,
|
||||||
|
FileDesiredStorageClassInformation = 67,
|
||||||
|
FileStatInformation = 68,
|
||||||
|
FileMemoryPartitionInformation = 69,
|
||||||
|
FileStatLxInformation = 70,
|
||||||
|
FileCaseSensitiveInformation = 71,
|
||||||
|
FileLinkInformationEx = 72,
|
||||||
|
FileLinkInformationExBypassAccessCheck = 73,
|
||||||
|
FileStorageReserveIdInformation = 74,
|
||||||
|
FileCaseSensitiveInformationForceAccessCheck = 75,
|
||||||
|
FileKnownFolderInformation = 76,
|
||||||
|
FileStatBasicInformation = 77,
|
||||||
|
FileId64ExtdDirectoryInformation = 78,
|
||||||
|
FileId64ExtdBothDirectoryInformation = 79,
|
||||||
|
FileIdAllExtdDirectoryInformation = 80,
|
||||||
|
FileIdAllExtdBothDirectoryInformation = 81,
|
||||||
|
FileStreamReservationInformation,
|
||||||
|
FileMupProviderInfo,
|
||||||
|
FileMaximumInformation
|
||||||
|
} FILE_INFORMATION_CLASS,
|
||||||
|
*PFILE_INFORMATION_CLASS;
|
||||||
|
|
||||||
|
typedef struct _IO_STATUS_BLOCK {
|
||||||
|
union {
|
||||||
|
u32 Status;
|
||||||
|
PVOID Pointer;
|
||||||
|
};
|
||||||
|
ULONG_PTR Information;
|
||||||
|
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||||
|
|
||||||
|
typedef struct _FILE_DISPOSITION_INFORMATION {
|
||||||
|
BOOLEAN DeleteFile;
|
||||||
|
} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
|
||||||
|
|
||||||
|
typedef u32(__stdcall* NtDelayExecution_t)(BOOL Alertable, PLARGE_INTEGER DelayInterval);
|
||||||
|
|
||||||
|
typedef u32(__stdcall* NtSetInformationFile_t)(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock,
|
||||||
|
PVOID FileInformation, ULONG Length,
|
||||||
|
FILE_INFORMATION_CLASS FileInformationClass);
|
||||||
|
|
||||||
|
extern NtDelayExecution_t NtDelayExecution;
|
||||||
|
extern NtSetInformationFile_t NtSetInformationFile;
|
||||||
|
|
||||||
|
namespace Common::NtApi {
|
||||||
|
void Initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -6,6 +6,7 @@
|
||||||
#include "common/error.h"
|
#include "common/error.h"
|
||||||
#include "core/address_space.h"
|
#include "core/address_space.h"
|
||||||
#include "core/libraries/kernel/memory_management.h"
|
#include "core/libraries/kernel/memory_management.h"
|
||||||
|
#include "core/memory.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
@ -18,6 +19,18 @@ namespace Core {
|
||||||
|
|
||||||
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE;
|
static constexpr size_t BackingSize = SCE_KERNEL_MAIN_DMEM_SIZE;
|
||||||
|
|
||||||
|
[[nodiscard]] constexpr u64 ToWindowsProt(Core::MemoryProt prot) {
|
||||||
|
switch (prot) {
|
||||||
|
case Core::MemoryProt::NoAccess:
|
||||||
|
default:
|
||||||
|
return PAGE_NOACCESS;
|
||||||
|
case Core::MemoryProt::CpuRead:
|
||||||
|
return PAGE_READONLY;
|
||||||
|
case Core::MemoryProt::CpuReadWrite:
|
||||||
|
return PAGE_READWRITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
struct AddressSpace::Impl {
|
struct AddressSpace::Impl {
|
||||||
Impl() : process{GetCurrentProcess()} {
|
Impl() : process{GetCurrentProcess()} {
|
||||||
|
@ -325,8 +338,10 @@ void* AddressSpace::Map(VAddr virtual_addr, size_t size, u64 alignment, PAddr ph
|
||||||
is_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
|
is_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd) {
|
void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, u32 prot,
|
||||||
return impl->Map(virtual_addr, offset, size, fd ? PAGE_READONLY : PAGE_READWRITE, fd);
|
uintptr_t fd) {
|
||||||
|
return impl->Map(virtual_addr, offset, size,
|
||||||
|
ToWindowsProt(std::bit_cast<Core::MemoryProt>(prot)), fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddressSpace::Unmap(VAddr virtual_addr, size_t size, bool has_backing) {
|
void AddressSpace::Unmap(VAddr virtual_addr, size_t size, bool has_backing) {
|
||||||
|
|
|
@ -63,7 +63,7 @@ public:
|
||||||
bool exec = false);
|
bool exec = false);
|
||||||
|
|
||||||
/// Memory maps a specified file descriptor.
|
/// Memory maps a specified file descriptor.
|
||||||
void* MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd);
|
void* MapFile(VAddr virtual_addr, size_t size, size_t offset, u32 prot, uintptr_t fd);
|
||||||
|
|
||||||
/// Unmaps specified virtual memory area.
|
/// Unmaps specified virtual memory area.
|
||||||
void Unmap(VAddr virtual_addr, size_t size, bool has_backing);
|
void Unmap(VAddr virtual_addr, size_t size, bool has_backing);
|
||||||
|
|
|
@ -157,6 +157,33 @@ size_t PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes) {
|
||||||
return file->f.WriteRaw<u8>(buf, nbytes);
|
return file->f.WriteRaw<u8>(buf, nbytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelUnlink(const char* path) {
|
||||||
|
if (path == nullptr) {
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
|
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
|
||||||
|
|
||||||
|
std::string host_path = mnt->GetHostFile(path);
|
||||||
|
|
||||||
|
if (host_path.empty()) {
|
||||||
|
return SCE_KERNEL_ERROR_EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::filesystem::is_directory(host_path)) {
|
||||||
|
return SCE_KERNEL_ERROR_EPERM;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* file = h->getFile(host_path);
|
||||||
|
if (file != nullptr) {
|
||||||
|
file->f.Unlink();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_INFO(Kernel_Fs, "Unlinked {}", path);
|
||||||
|
return SCE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
|
size_t PS4_SYSV_ABI _readv(int d, const SceKernelIovec* iov, int iovcnt) {
|
||||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
auto* file = h->GetFile(d);
|
auto* file = h->GetFile(d);
|
||||||
|
@ -356,6 +383,22 @@ s32 PS4_SYSV_ABI sceKernelFsync(int fd) {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int PS4_SYSV_ABI sceKernelFtruncate(int fd, s64 length) {
|
||||||
|
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||||
|
auto* file = h->GetFile(fd);
|
||||||
|
|
||||||
|
if (file == nullptr) {
|
||||||
|
return SCE_KERNEL_ERROR_EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file->m_host_name.empty()) {
|
||||||
|
return SCE_KERNEL_ERROR_EACCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
file->f.SetSize(length);
|
||||||
|
return SCE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
|
static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
|
||||||
// TODO error codes
|
// TODO error codes
|
||||||
ASSERT(buf != nullptr);
|
ASSERT(buf != nullptr);
|
||||||
|
@ -372,7 +415,7 @@ static int GetDents(int fd, char* buf, int nbytes, s64* basep) {
|
||||||
static int fileno = 1000; // random
|
static int fileno = 1000; // random
|
||||||
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf;
|
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf;
|
||||||
sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a
|
sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a
|
||||||
// hash or something?
|
// hash or something?
|
||||||
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
|
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
|
||||||
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
||||||
sce_ent->d_namlen = str_size;
|
sce_ent->d_namlen = str_size;
|
||||||
|
@ -435,6 +478,7 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("eV9wAD2riIA", "libkernel", 1, "libkernel", 1, 1, sceKernelStat);
|
LIB_FUNCTION("eV9wAD2riIA", "libkernel", 1, "libkernel", 1, 1, sceKernelStat);
|
||||||
LIB_FUNCTION("kBwCPsYX-m4", "libkernel", 1, "libkernel", 1, 1, sceKernelFStat);
|
LIB_FUNCTION("kBwCPsYX-m4", "libkernel", 1, "libkernel", 1, 1, sceKernelFStat);
|
||||||
LIB_FUNCTION("mqQMh1zPPT8", "libScePosix", 1, "libkernel", 1, 1, posix_fstat);
|
LIB_FUNCTION("mqQMh1zPPT8", "libScePosix", 1, "libkernel", 1, 1, posix_fstat);
|
||||||
|
LIB_FUNCTION("VW3TVZiM4-E", "libkernel", 1, "libkernel", 1, 1, sceKernelFtruncate);
|
||||||
|
|
||||||
LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat);
|
LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat);
|
||||||
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
|
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
|
||||||
|
@ -443,6 +487,7 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
|
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
|
||||||
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
|
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
|
||||||
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
|
LIB_FUNCTION("nKWi-N2HBV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPwrite);
|
||||||
|
LIB_FUNCTION("AUXVxWeJU-A", "libkernel", 1, "libkernel", 1, 1, sceKernelUnlink);
|
||||||
|
|
||||||
// openOrbis (to check if it is valid out of OpenOrbis
|
// openOrbis (to check if it is valid out of OpenOrbis
|
||||||
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1,
|
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1,
|
||||||
|
|
|
@ -370,6 +370,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||||
LIB_FUNCTION("hwVSPCmp5tM", "libkernel", 1, "libkernel", 1, 1,
|
LIB_FUNCTION("hwVSPCmp5tM", "libkernel", 1, "libkernel", 1, 1,
|
||||||
sceKernelCheckedReleaseDirectMemory);
|
sceKernelCheckedReleaseDirectMemory);
|
||||||
LIB_FUNCTION("rVjRvHJ0X6c", "libkernel", 1, "libkernel", 1, 1, sceKernelVirtualQuery);
|
LIB_FUNCTION("rVjRvHJ0X6c", "libkernel", 1, "libkernel", 1, 1, sceKernelVirtualQuery);
|
||||||
|
LIB_FUNCTION("7oxv3PPCumo", "libkernel", 1, "libkernel", 1, 1, sceKernelReserveVirtualRange);
|
||||||
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
LIB_FUNCTION("pO96TwzOm5E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetDirectMemorySize);
|
||||||
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
LIB_FUNCTION("NcaWUxfMNIQ", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedDirectMemory);
|
||||||
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
LIB_FUNCTION("L-Q3LEjIbgA", "libkernel", 1, "libkernel", 1, 1, sceKernelMapDirectMemory);
|
||||||
|
|
|
@ -87,6 +87,33 @@ s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtual
|
||||||
return memory->VirtualQuery(std::bit_cast<VAddr>(addr), flags, info);
|
return memory->VirtualQuery(std::bit_cast<VAddr>(addr), flags, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment) {
|
||||||
|
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}, flags = {:#x}, alignment = {:#x}",
|
||||||
|
fmt::ptr(*addr), len, flags, alignment);
|
||||||
|
|
||||||
|
if (addr == nullptr) {
|
||||||
|
LOG_ERROR(Kernel_Vmm, "Address is invalid!");
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
if (len == 0 || !Common::Is16KBAligned(len)) {
|
||||||
|
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
if (alignment != 0) {
|
||||||
|
if ((!std::has_single_bit(alignment) && !Common::Is16KBAligned(alignment))) {
|
||||||
|
LOG_ERROR(Kernel_Vmm, "Alignment value is invalid!");
|
||||||
|
return SCE_KERNEL_ERROR_EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto* memory = Core::Memory::Instance();
|
||||||
|
const VAddr in_addr = reinterpret_cast<VAddr>(*addr);
|
||||||
|
const auto map_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||||
|
memory->Reserve(addr, in_addr, len, map_flags, alignment);
|
||||||
|
|
||||||
|
return SCE_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
|
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
|
||||||
s64 directMemoryStart, u64 alignment,
|
s64 directMemoryStart, u64 alignment,
|
||||||
const char* name) {
|
const char* name) {
|
||||||
|
|
|
@ -70,6 +70,7 @@ s32 PS4_SYSV_ABI sceKernelAvailableDirectMemorySize(u64 searchStart, u64 searchE
|
||||||
size_t* sizeOut);
|
size_t* sizeOut);
|
||||||
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
|
s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtualQueryInfo* info,
|
||||||
size_t infoSize);
|
size_t infoSize);
|
||||||
|
s32 PS4_SYSV_ABI sceKernelReserveVirtualRange(void** addr, u64 len, int flags, u64 alignment);
|
||||||
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addrInOut, std::size_t len, int prot,
|
s32 PS4_SYSV_ABI sceKernelMapNamedFlexibleMemory(void** addrInOut, std::size_t len, int prot,
|
||||||
int flags, const char* name);
|
int flags, const char* name);
|
||||||
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
s32 PS4_SYSV_ABI sceKernelMapFlexibleMemory(void** addr_in_out, std::size_t len, int prot,
|
||||||
|
|
|
@ -12,10 +12,8 @@
|
||||||
#include <pthread_time.h>
|
#include <pthread_time.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
// http://stackoverflow.com/a/31411628/4725495
|
#include "common/ntapi.h"
|
||||||
static u32(__stdcall* NtDelayExecution)(BOOL Alertable, PLARGE_INTEGER DelayInterval) =
|
|
||||||
(u32(__stdcall*)(BOOL, PLARGE_INTEGER))GetProcAddress(GetModuleHandleA("ntdll.dll"),
|
|
||||||
"NtDelayExecution");
|
|
||||||
#else
|
#else
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
|
@ -83,6 +83,25 @@ void MemoryManager::Free(PAddr phys_addr, size_t size) {
|
||||||
MergeAdjacent(dmem_map, dmem_area);
|
MergeAdjacent(dmem_map, dmem_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MemoryManager::Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags,
|
||||||
|
u64 alignment) {
|
||||||
|
std::scoped_lock lk{mutex};
|
||||||
|
|
||||||
|
ASSERT_MSG(virtual_addr != 0, "TODO: Reserve address is zero - search for free space");
|
||||||
|
|
||||||
|
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
|
||||||
|
|
||||||
|
// Add virtual memory area
|
||||||
|
auto& new_vma = AddMapping(mapped_addr, size);
|
||||||
|
new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce);
|
||||||
|
new_vma.prot = MemoryProt::NoAccess;
|
||||||
|
new_vma.name = "";
|
||||||
|
new_vma.type = VMAType::Reserved;
|
||||||
|
|
||||||
|
*out_addr = std::bit_cast<void*>(mapped_addr);
|
||||||
|
return ORBIS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||||
MemoryMapFlags flags, VMAType type, std::string_view name,
|
MemoryMapFlags flags, VMAType type, std::string_view name,
|
||||||
bool is_exec, PAddr phys_addr, u64 alignment) {
|
bool is_exec, PAddr phys_addr, u64 alignment) {
|
||||||
|
@ -146,20 +165,37 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
|
||||||
|
|
||||||
int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||||
MemoryMapFlags flags, uintptr_t fd, size_t offset) {
|
MemoryMapFlags flags, uintptr_t fd, size_t offset) {
|
||||||
ASSERT(virtual_addr == 0);
|
if (virtual_addr == 0) {
|
||||||
virtual_addr = impl.VirtualBase();
|
virtual_addr = impl.VirtualBase();
|
||||||
|
} else {
|
||||||
|
LOG_INFO(Kernel_Vmm, "Virtual addr {:#x} with size {:#x}", virtual_addr, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr mapped_addr = 0;
|
||||||
const size_t size_aligned = Common::AlignUp(size, 16_KB);
|
const size_t size_aligned = Common::AlignUp(size, 16_KB);
|
||||||
|
|
||||||
// Find first free area to map the file.
|
// Find first free area to map the file.
|
||||||
auto it = FindVMA(virtual_addr);
|
if (False(flags & MemoryMapFlags::Fixed)) {
|
||||||
while (it->second.type != VMAType::Free || it->second.size < size_aligned) {
|
auto it = FindVMA(virtual_addr);
|
||||||
it++;
|
while (it->second.type != VMAType::Free || it->second.size < size_aligned) {
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
ASSERT(it != vma_map.end());
|
||||||
|
|
||||||
|
mapped_addr = it->second.base;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (True(flags & MemoryMapFlags::Fixed)) {
|
||||||
|
const auto& vma = FindVMA(virtual_addr)->second;
|
||||||
|
const size_t remaining_size = vma.base + vma.size - virtual_addr;
|
||||||
|
ASSERT_MSG((vma.type == VMAType::Free || vma.type == VMAType::Reserved) &&
|
||||||
|
remaining_size >= size);
|
||||||
|
|
||||||
|
mapped_addr = virtual_addr;
|
||||||
}
|
}
|
||||||
ASSERT(it != vma_map.end());
|
|
||||||
|
|
||||||
// Map the file.
|
// Map the file.
|
||||||
const VAddr mapped_addr = it->second.base;
|
impl.MapFile(mapped_addr, size, offset, std::bit_cast<u32>(prot), fd);
|
||||||
impl.MapFile(mapped_addr, size, offset, fd);
|
|
||||||
|
|
||||||
// Add virtual memory area
|
// Add virtual memory area
|
||||||
auto& new_vma = AddMapping(mapped_addr, size_aligned);
|
auto& new_vma = AddMapping(mapped_addr, size_aligned);
|
||||||
|
@ -303,7 +339,8 @@ VirtualMemoryArea& MemoryManager::AddMapping(VAddr virtual_addr, size_t size) {
|
||||||
ASSERT_MSG(vma_handle != vma_map.end(), "Virtual address not in vm_map");
|
ASSERT_MSG(vma_handle != vma_map.end(), "Virtual address not in vm_map");
|
||||||
|
|
||||||
const VirtualMemoryArea& vma = vma_handle->second;
|
const VirtualMemoryArea& vma = vma_handle->second;
|
||||||
ASSERT_MSG(vma.type == VMAType::Free && vma.base <= virtual_addr,
|
ASSERT_MSG((vma.type == VMAType::Free || vma.type == VMAType::Reserved) &&
|
||||||
|
vma.base <= virtual_addr,
|
||||||
"Adding a mapping to already mapped region");
|
"Adding a mapping to already mapped region");
|
||||||
|
|
||||||
const VAddr start_in_vma = virtual_addr - vma.base;
|
const VAddr start_in_vma = virtual_addr - vma.base;
|
||||||
|
|
|
@ -137,6 +137,9 @@ public:
|
||||||
|
|
||||||
void Free(PAddr phys_addr, size_t size);
|
void Free(PAddr phys_addr, size_t size);
|
||||||
|
|
||||||
|
int Reserve(void** out_addr, VAddr virtual_addr, size_t size, MemoryMapFlags flags,
|
||||||
|
u64 alignment = 0);
|
||||||
|
|
||||||
int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
int MapMemory(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
|
||||||
MemoryMapFlags flags, VMAType type, std::string_view name = "",
|
MemoryMapFlags flags, VMAType type, std::string_view name = "",
|
||||||
bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
|
bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "common/config.h"
|
#include "common/config.h"
|
||||||
#include "common/debug.h"
|
#include "common/debug.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
|
#include "common/ntapi.h"
|
||||||
#include "common/path_util.h"
|
#include "common/path_util.h"
|
||||||
#include "common/singleton.h"
|
#include "common/singleton.h"
|
||||||
#include "common/version.h"
|
#include "common/version.h"
|
||||||
|
@ -38,6 +39,9 @@ Emulator::Emulator()
|
||||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir);
|
||||||
Config::load(config_dir / "config.toml");
|
Config::load(config_dir / "config.toml");
|
||||||
|
|
||||||
|
// Initialize NT API functions
|
||||||
|
Common::NtApi::Initialize();
|
||||||
|
|
||||||
// Start logger.
|
// Start logger.
|
||||||
Common::Log::Initialize();
|
Common::Log::Initialize();
|
||||||
Common::Log::Start();
|
Common::Log::Start();
|
||||||
|
|
Loading…
Reference in New Issue