mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
kernel: memory mapping, event flags and condvar fixes
- Event flags gain a zero-timeout polling path, which this title uses heavily, and map their results to the right errno. - Memory mapping, address-space and file-system corrections its startup path depends on. - pthread condvar waits dispatch pending signals while waiting.
This commit is contained in:
@@ -23,6 +23,7 @@ public:
|
|||||||
|
|
||||||
KernelEventFlagPrivate(const std::string& name, bool single, bool /*fifo*/, uint64_t bits)
|
KernelEventFlagPrivate(const std::string& name, bool single, bool /*fifo*/, uint64_t bits)
|
||||||
: m_name(name), m_single_thread(single), m_bits(bits) {}
|
: m_name(name), m_single_thread(single), m_bits(bits) {}
|
||||||
|
|
||||||
virtual ~KernelEventFlagPrivate();
|
virtual ~KernelEventFlagPrivate();
|
||||||
|
|
||||||
KYTY_CLASS_NO_COPY(KernelEventFlagPrivate);
|
KYTY_CLASS_NO_COPY(KernelEventFlagPrivate);
|
||||||
@@ -110,6 +111,24 @@ KernelEventFlagPrivate::Result KernelEventFlagPrivate::Wait(uint64_t bits, WaitM
|
|||||||
infinitely = false;
|
infinitely = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!infinitely && micros == 0) {
|
||||||
|
const bool satisfied = (wait_mode == WaitMode::And && (m_bits & bits) == bits) ||
|
||||||
|
(wait_mode == WaitMode::Or && (m_bits & bits) != 0);
|
||||||
|
if (result != nullptr) {
|
||||||
|
*result = m_bits;
|
||||||
|
}
|
||||||
|
*ptr_micros = 0;
|
||||||
|
if (!satisfied) {
|
||||||
|
return Result::TimedOut;
|
||||||
|
}
|
||||||
|
switch (clear_mode) {
|
||||||
|
case ClearMode::All: m_bits = 0; break;
|
||||||
|
case ClearMode::Bits: m_bits &= ~bits; break;
|
||||||
|
case ClearMode::None: break;
|
||||||
|
}
|
||||||
|
return Result::Ok;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t elapsed = 0;
|
uint32_t elapsed = 0;
|
||||||
Common::Timer t;
|
Common::Timer t;
|
||||||
t.Start();
|
t.Start();
|
||||||
@@ -284,6 +303,17 @@ int KYTY_SYSV_ABI KernelDeleteEventFlag(KernelEventFlag ef) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int EventFlagResultToErrno(KernelEventFlagPrivate::Result result) {
|
||||||
|
switch (result) {
|
||||||
|
case KernelEventFlagPrivate::Result::Ok: return OK;
|
||||||
|
case KernelEventFlagPrivate::Result::AlreadyWaiting: return KERNEL_ERROR_EPERM;
|
||||||
|
case KernelEventFlagPrivate::Result::TimedOut: return KERNEL_ERROR_ETIMEDOUT;
|
||||||
|
case KernelEventFlagPrivate::Result::Canceled: return KERNEL_ERROR_ECANCELED;
|
||||||
|
case KernelEventFlagPrivate::Result::Deleted: return KERNEL_ERROR_EACCES;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
|
int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern, uint32_t wait_mode,
|
||||||
uint64_t* result_pat, KernelUseconds* timeout) {
|
uint64_t* result_pat, KernelUseconds* timeout) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
@@ -296,8 +326,14 @@ int KYTY_SYSV_ABI KernelWaitEventFlag(KernelEventFlag ef, uint64_t bit_pattern,
|
|||||||
return KERNEL_ERROR_EINVAL;
|
return KERNEL_ERROR_EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto mode = DecodeEventFlagWaitMode(wait_mode);
|
const auto mode = DecodeEventFlagWaitMode(wait_mode);
|
||||||
auto result = ef->Wait(bit_pattern, mode.wait, mode.clear, result_pat, timeout);
|
|
||||||
|
const bool polling = timeout != nullptr && *timeout == 0;
|
||||||
|
if (polling) {
|
||||||
|
return EventFlagResultToErrno(ef->Wait(bit_pattern, mode.wait, mode.clear, result_pat, timeout));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = ef->Wait(bit_pattern, mode.wait, mode.clear, result_pat, timeout);
|
||||||
|
|
||||||
int ret = OK;
|
int ret = OK;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#include "kernel/fileSystem.h"
|
#include "kernel/fileSystem.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include <utility>
|
||||||
|
#include <cstdlib>
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
#include "common/dateTime.h"
|
#include "common/dateTime.h"
|
||||||
#include "common/emulatorConfig.h"
|
#include "common/emulatorConfig.h"
|
||||||
@@ -545,7 +547,18 @@ int KYTY_SYSV_ABI KernelClose(int d) {
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FileReadWatchCheck(const char* who, uint64_t dst, uint64_t size) {
|
||||||
|
static const auto watch = [] {
|
||||||
|
std::pair<uint64_t, uint64_t> range {0, 0};
|
||||||
|
return range;
|
||||||
|
}();
|
||||||
|
if (watch.second == 0 || dst >= watch.first + watch.second || watch.first >= dst + size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes) {
|
int64_t KYTY_SYSV_ABI KernelRead(int d, void* buf, size_t nbytes) {
|
||||||
|
FileReadWatchCheck("read", reinterpret_cast<uint64_t>(buf), nbytes);
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
if (d < DESCRIPTOR_MIN) {
|
if (d < DESCRIPTOR_MIN) {
|
||||||
@@ -671,6 +684,7 @@ int64_t KYTY_SYSV_ABI KernelWrite(int d, const void* buf, size_t nbytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset) {
|
int64_t KYTY_SYSV_ABI KernelPread(int d, void* buf, size_t nbytes, int64_t offset) {
|
||||||
|
FileReadWatchCheck("pread", reinterpret_cast<uint64_t>(buf), nbytes);
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
if (d < DESCRIPTOR_MIN) {
|
if (d < DESCRIPTOR_MIN) {
|
||||||
|
|||||||
+222
-4
@@ -1,7 +1,9 @@
|
|||||||
|
#include <thread>
|
||||||
#include "kernel/memory.h"
|
#include "kernel/memory.h"
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include <utility>
|
||||||
#include "common/magicEnum.h"
|
#include "common/magicEnum.h"
|
||||||
#include "common/stringUtils.h"
|
#include "common/stringUtils.h"
|
||||||
#include "common/threads.h"
|
#include "common/threads.h"
|
||||||
@@ -896,6 +898,10 @@ uint64_t ClampRangeSize(uint64_t vaddr, uint64_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept {
|
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept {
|
||||||
|
{
|
||||||
|
constexpr uint64_t AppMapAreaStart = 0x1000000000ull;
|
||||||
|
constexpr uint64_t AppMapAreaEnd = 0x1030000000ull;
|
||||||
|
}
|
||||||
if (!TryWriteBacking(vaddr, data, size)) {
|
if (!TryWriteBacking(vaddr, data, size)) {
|
||||||
EXIT("Memory: required direct-backing write failed, addr=0x%016" PRIx64
|
EXIT("Memory: required direct-backing write failed, addr=0x%016" PRIx64
|
||||||
" size=0x%016" PRIx64 "\n",
|
" size=0x%016" PRIx64 "\n",
|
||||||
@@ -915,8 +921,20 @@ void InstallGpuResources(Graphics::GpuResourceManager* resources) noexcept {
|
|||||||
g_gpu_resources = resources;
|
g_gpu_resources = resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static thread_local bool g_in_gpu_fault = false;
|
||||||
|
|
||||||
|
bool IsHandlingGpuFault() noexcept {
|
||||||
|
return g_in_gpu_fault;
|
||||||
|
}
|
||||||
|
|
||||||
bool HandleGpuFault(Graphics::PageFaultAccess access, uint64_t fault_vaddr) noexcept {
|
bool HandleGpuFault(Graphics::PageFaultAccess access, uint64_t fault_vaddr) noexcept {
|
||||||
return g_gpu_resources != nullptr && g_gpu_resources->HandleFault(access, fault_vaddr);
|
if (g_gpu_resources == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto previous = std::exchange(g_in_gpu_fault, true);
|
||||||
|
const bool handled = g_gpu_resources->HandleFault(access, fault_vaddr);
|
||||||
|
g_in_gpu_fault = previous;
|
||||||
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PrtAperture {
|
struct PrtAperture {
|
||||||
@@ -965,6 +983,53 @@ bool TryReadPrtBacking(uint64_t vaddr, void* data, uint64_t size) {
|
|||||||
return g_guest_address_space->TryReadSparseBacking(vaddr, data, size);
|
return g_guest_address_space->TryReadSparseBacking(vaddr, data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool SelfTestDirectMemoryAliasAndPersistence() {
|
||||||
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
|
constexpr uint64_t PageSize = 0x4000;
|
||||||
|
constexpr uint64_t Pattern = 0x4b595459414c4941ull; // "KYTYALIA"
|
||||||
|
const auto granularity = g_guest_address_space->GetGranularity();
|
||||||
|
|
||||||
|
const auto first = FindGuestFreeRange(0, granularity * 2u, granularity);
|
||||||
|
if (first == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const auto second = FindGuestFreeRange(first + granularity * 2u, granularity, granularity);
|
||||||
|
if (second == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t backing_offset = granularity;
|
||||||
|
|
||||||
|
bool alias_ok = false;
|
||||||
|
bool persist_ok = false;
|
||||||
|
auto reason = GuestBackingStore::FailureReason::None;
|
||||||
|
|
||||||
|
if (g_guest_address_space->MapBacking(first, PageSize, backing_offset,
|
||||||
|
VirtualMemory::Mode::ReadWrite, &reason)) {
|
||||||
|
*reinterpret_cast<volatile uint64_t*>(first) = Pattern;
|
||||||
|
|
||||||
|
if (g_guest_address_space->MapBacking(second, PageSize, backing_offset,
|
||||||
|
VirtualMemory::Mode::ReadWrite, &reason)) {
|
||||||
|
alias_ok = (*reinterpret_cast<volatile uint64_t*>(second) == Pattern);
|
||||||
|
EXIT_IF(!g_guest_address_space->UnmapBacking(second, PageSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_guest_address_space->UnmapBacking(first, PageSize) &&
|
||||||
|
g_guest_address_space->MapBacking(first, PageSize, backing_offset,
|
||||||
|
VirtualMemory::Mode::ReadWrite, &reason)) {
|
||||||
|
persist_ok = (*reinterpret_cast<volatile uint64_t*>(first) == Pattern);
|
||||||
|
std::memset(reinterpret_cast<void*>(first), 0, PageSize);
|
||||||
|
EXIT_IF(!g_guest_address_space->UnmapBacking(first, PageSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool ok = alias_ok && persist_ok;
|
||||||
|
return ok;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static bool SelfTestSub64SharedPlaceholderAlias() {
|
static bool SelfTestSub64SharedPlaceholderAlias() {
|
||||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
constexpr uint64_t PageSize = 0x4000;
|
constexpr uint64_t PageSize = 0x4000;
|
||||||
@@ -1018,6 +1083,7 @@ void Initialize() {
|
|||||||
g_virtual_ranges = std::make_unique<VirtualRanges>();
|
g_virtual_ranges = std::make_unique<VirtualRanges>();
|
||||||
EXIT_IF(!g_guest_address_space->SelfTest());
|
EXIT_IF(!g_guest_address_space->SelfTest());
|
||||||
EXIT_IF(!SelfTestSub64SharedPlaceholderAlias());
|
EXIT_IF(!SelfTestSub64SharedPlaceholderAlias());
|
||||||
|
EXIT_IF(!SelfTestDirectMemoryAliasAndPersistence());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown() {
|
void Shutdown() {
|
||||||
@@ -3044,6 +3110,20 @@ int KYTY_SYSV_ABI KernelMapDirectMemory(void** addr, size_t len, int prot, int f
|
|||||||
return KERNEL_ERROR_EBUSY;
|
return KERNEL_ERROR_EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
static std::atomic<uint32_t> after_log_count {0};
|
||||||
|
if (after_log_count.fetch_add(1, std::memory_order_relaxed) < 64) {
|
||||||
|
uint64_t after[4] = {0, 0, 0, 0};
|
||||||
|
std::memcpy(after, reinterpret_cast<const void*>(out_addr), sizeof(after));
|
||||||
|
uint64_t zero_bytes = 0;
|
||||||
|
uint64_t total_bytes = std::min<uint64_t>(len, 1u << 20u);
|
||||||
|
const auto* probe = reinterpret_cast<const uint8_t*>(out_addr);
|
||||||
|
for (uint64_t i = 0; i < total_bytes; i++) {
|
||||||
|
zero_bytes += (probe[i] == 0 ? 1u : 0u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PhysicalMemory::AllocatedBlock mapped_block {};
|
PhysicalMemory::AllocatedBlock mapped_block {};
|
||||||
g_physical_memory->Find(direct_memory_start, false, &mapped_block);
|
g_physical_memory->Find(direct_memory_start, false, &mapped_block);
|
||||||
if (!g_virtual_ranges->Add(out_addr, len, direct_memory_start, prot, mapped_block.memory_type,
|
if (!g_virtual_ranges->Add(out_addr, len, direct_memory_start, prot, mapped_block.memory_type,
|
||||||
@@ -3075,8 +3155,6 @@ int KYTY_SYSV_ABI KernelMapDirectMemory2(void** addr, size_t len, int type, int
|
|||||||
|
|
||||||
std::lock_guard<std::recursive_mutex> memory_operation_lock(g_memory_operation_mutex);
|
std::lock_guard<std::recursive_mutex> memory_operation_lock(g_memory_operation_mutex);
|
||||||
|
|
||||||
LOGF("\t type = %d\n", type);
|
|
||||||
|
|
||||||
auto ret = KernelMapDirectMemory(addr, len, prot, flags, direct_memory_start, alignment);
|
auto ret = KernelMapDirectMemory(addr, len, prot, flags, direct_memory_start, alignment);
|
||||||
if (ret == OK && addr != nullptr && *addr != nullptr) {
|
if (ret == OK && addr != nullptr && *addr != nullptr) {
|
||||||
const auto out_addr = reinterpret_cast<uint64_t>(*addr);
|
const auto out_addr = reinterpret_cast<uint64_t>(*addr);
|
||||||
@@ -3175,6 +3253,24 @@ static bool ReplaceFixedRangeWithReserved(uint64_t start, uint64_t size) {
|
|||||||
const auto range_end = range.start + range.size;
|
const auto range_end = range.start + range.size;
|
||||||
const auto chunk = std::min<uint64_t>(end, range_end) - current;
|
const auto chunk = std::min<uint64_t>(end, range_end) - current;
|
||||||
|
|
||||||
|
if (range.type != VirtualRangeType::Reserved) {
|
||||||
|
static std::atomic<uint32_t> replace_log_count {0};
|
||||||
|
if (replace_log_count.fetch_add(1, std::memory_order_relaxed) < 64) {
|
||||||
|
uint64_t before[4] = {0, 0, 0, 0};
|
||||||
|
std::memcpy(before, reinterpret_cast<const void*>(current), sizeof(before));
|
||||||
|
uint32_t zero_bytes = 0;
|
||||||
|
{
|
||||||
|
const auto* probe = reinterpret_cast<const uint8_t*>(current);
|
||||||
|
for (uint32_t i = 0; i < 4096u; i++) {
|
||||||
|
zero_bytes += (probe[i] == 0 ? 1u : 0u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
ReplacedChunk replaced {};
|
ReplacedChunk replaced {};
|
||||||
replaced.range = range;
|
replaced.range = range;
|
||||||
replaced.range.start = current;
|
replaced.range.start = current;
|
||||||
@@ -3447,6 +3543,115 @@ bool TestGuestFreeRangeBounds() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
bool KernelHandleReservedRangeAccessViolation(uint64_t vaddr) {
|
||||||
|
std::unique_lock<std::recursive_mutex> memory_operation_lock(g_memory_operation_mutex,
|
||||||
|
std::try_to_lock);
|
||||||
|
if (!memory_operation_lock.owns_lock()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualRanges::Range range {};
|
||||||
|
if (!g_virtual_ranges->Query(vaddr, 0, &range) ||
|
||||||
|
std::strncmp(range.name, "AMM", KERNEL_MAXIMUM_NAME_LENGTH) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
EXIT("AMM virtual-memory unmap is unsupported: addr=0x%016" PRIx64 "\n", vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KernelHandleTransientMappingFault(Graphics::PageFaultAccess access, uint64_t vaddr) {
|
||||||
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
|
if (g_virtual_ranges == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(g_memory_operation_mutex, std::try_to_lock);
|
||||||
|
if (lock.owns_lock()) {
|
||||||
|
VirtualRanges::Range range {};
|
||||||
|
if (!g_virtual_ranges->Query(vaddr, 0, &range)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MEMORY_BASIC_INFORMATION mbi {};
|
||||||
|
if (VirtualQuery(reinterpret_cast<const void*>(vaddr), &mbi, sizeof(mbi)) == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mbi.State != MEM_COMMIT || (mbi.Protect & PAGE_GUARD) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr DWORD READABLE = PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ |
|
||||||
|
PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||||
|
constexpr DWORD WRITABLE =
|
||||||
|
PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||||
|
constexpr DWORD EXECUTABLE =
|
||||||
|
PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY;
|
||||||
|
|
||||||
|
bool allowed = false;
|
||||||
|
switch (access) {
|
||||||
|
case Graphics::PageFaultAccess::Read: allowed = (mbi.Protect & READABLE) != 0; break;
|
||||||
|
case Graphics::PageFaultAccess::Write: allowed = (mbi.Protect & WRITABLE) != 0; break;
|
||||||
|
case Graphics::PageFaultAccess::Execute: allowed = (mbi.Protect & EXECUTABLE) != 0; break;
|
||||||
|
case Graphics::PageFaultAccess::Unknown: allowed = false; break;
|
||||||
|
}
|
||||||
|
if (!allowed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::atomic<uint32_t> log_count {0};
|
||||||
|
const auto seen = log_count.fetch_add(1, std::memory_order_relaxed);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
(void)access;
|
||||||
|
(void)vaddr;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t MappedExtentFrom(uint64_t vaddr, bool* known) {
|
||||||
|
if (known != nullptr) {
|
||||||
|
*known = false;
|
||||||
|
}
|
||||||
|
if (g_virtual_ranges == nullptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(g_memory_operation_mutex, std::defer_lock);
|
||||||
|
for (uint32_t attempt = 0; attempt < 64 && !lock.owns_lock(); attempt++) {
|
||||||
|
if (!lock.try_lock()) {
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!lock.owns_lock()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (known != nullptr) {
|
||||||
|
*known = true;
|
||||||
|
}
|
||||||
|
VirtualRanges::Range range {};
|
||||||
|
if (!g_virtual_ranges->Query(vaddr, 0, &range)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
const auto end = range.start + range.size;
|
||||||
|
return vaddr < end ? end - vaddr : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DumpVirtualRangeForAddress(uint64_t vaddr) {
|
||||||
|
if (g_virtual_ranges == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::unique_lock<std::recursive_mutex> lock(g_memory_operation_mutex, std::try_to_lock);
|
||||||
|
if (!lock.owns_lock()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualRanges::Range candidate {};
|
||||||
|
if (!g_virtual_ranges->Query(vaddr, 0, &candidate)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info,
|
int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info,
|
||||||
uint64_t info_size) {
|
uint64_t info_size) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
@@ -3465,7 +3670,20 @@ int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
VirtualRanges::Range candidate {};
|
VirtualRanges::Range candidate {};
|
||||||
if (!g_virtual_ranges->Query(vaddr, flags, &candidate)) {
|
const bool found = g_virtual_ranges->Query(vaddr, flags, &candidate);
|
||||||
|
|
||||||
|
{
|
||||||
|
static const auto watch = [] {
|
||||||
|
std::pair<uint64_t, uint64_t> range {0, 0};
|
||||||
|
return range;
|
||||||
|
}();
|
||||||
|
if (watch.second != 0 && vaddr >= watch.first - 0x100000 &&
|
||||||
|
vaddr < watch.first + watch.second + 0x100000) {
|
||||||
|
static std::atomic<uint32_t> log_count {0};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
return KERNEL_ERROR_EACCES;
|
return KERNEL_ERROR_EACCES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,6 +117,8 @@ void InvalidateMemory(uint64_t vaddr, uint64_t size);
|
|||||||
void InstallGpuResources(Graphics::GpuResourceManager* resources) noexcept;
|
void InstallGpuResources(Graphics::GpuResourceManager* resources) noexcept;
|
||||||
[[nodiscard]] bool HandleGpuFault(Graphics::PageFaultAccess access, uint64_t fault_vaddr) noexcept;
|
[[nodiscard]] bool HandleGpuFault(Graphics::PageFaultAccess access, uint64_t fault_vaddr) noexcept;
|
||||||
|
|
||||||
|
[[nodiscard]] bool IsHandlingGpuFault() noexcept;
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags,
|
int KYTY_SYSV_ABI KernelMapNamedFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags,
|
||||||
const char* name);
|
const char* name);
|
||||||
int KYTY_SYSV_ABI KernelMapFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags);
|
int KYTY_SYSV_ABI KernelMapFlexibleMemory(void** addr_in_out, size_t len, int prot, int flags);
|
||||||
@@ -147,6 +149,13 @@ int KYTY_SYSV_ABI KernelGetPrtAperture(int index, void** addr, size_t* len);
|
|||||||
int KYTY_SYSV_ABI KernelIsAddressSanitizerEnabled();
|
int KYTY_SYSV_ABI KernelIsAddressSanitizerEnabled();
|
||||||
int KYTY_SYSV_ABI KernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot);
|
int KYTY_SYSV_ABI KernelQueryMemoryProtection(void* addr, void** start, void** end, int* prot);
|
||||||
int KYTY_SYSV_ABI KernelDirectMemoryQuery(int64_t offset, int flags, void* info, size_t info_size);
|
int KYTY_SYSV_ABI KernelDirectMemoryQuery(int64_t offset, int flags, void* info, size_t info_size);
|
||||||
|
bool KernelHandleReservedRangeAccessViolation(uint64_t vaddr);
|
||||||
|
bool KernelHandleTransientMappingFault(Graphics::PageFaultAccess access, uint64_t vaddr);
|
||||||
|
|
||||||
|
|
||||||
|
void DumpVirtualRangeForAddress(uint64_t vaddr);
|
||||||
|
uint64_t MappedExtentFrom(uint64_t vaddr, bool* known = nullptr);
|
||||||
|
|
||||||
int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info,
|
int KYTY_SYSV_ABI KernelVirtualQuery(const void* addr, int flags, VirtualQueryInfo* info,
|
||||||
uint64_t info_size);
|
uint64_t info_size);
|
||||||
int KYTY_SYSV_ABI KernelIsStack(void* addr, void** start, void** end);
|
int KYTY_SYSV_ABI KernelIsStack(void* addr, void** start, void** end);
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ static constexpr uint64_t HOST_USER_MIN = 0x1000000000ull;
|
|||||||
#endif
|
#endif
|
||||||
static constexpr uint64_t HOST_USER_MAX = 0xfbffffffffull;
|
static constexpr uint64_t HOST_USER_MAX = 0xfbffffffffull;
|
||||||
|
|
||||||
|
static constexpr uint64_t HOST_GUEST_RESERVE_MAX = 0x6000000000ull;
|
||||||
|
static_assert(HOST_GUEST_RESERVE_MAX > HOST_USER_MIN);
|
||||||
|
static_assert(HOST_GUEST_RESERVE_MAX <= HOST_USER_MAX + 1u);
|
||||||
|
|
||||||
static bool GuestFreeRangeContains(uint64_t base, uint64_t range_size, uint64_t candidate,
|
static bool GuestFreeRangeContains(uint64_t base, uint64_t range_size, uint64_t candidate,
|
||||||
uint64_t size) {
|
uint64_t size) {
|
||||||
if (UINT64_MAX - base < range_size || candidate < base) {
|
if (UINT64_MAX - base < range_size || candidate < base) {
|
||||||
@@ -758,14 +762,26 @@ public:
|
|||||||
if (size == 0 || UINT64_MAX - vaddr < size) {
|
if (size == 0 || UINT64_MAX - vaddr < size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
LogBackingChange("Protect", vaddr, size, static_cast<uint64_t>(mode));
|
||||||
|
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
return ProtectMappedUnlocked(vaddr, size, mode);
|
return ProtectMappedUnlocked(vaddr, size, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void LogBackingChange(const char* what, uint64_t vaddr, uint64_t size, uint64_t offset) {
|
||||||
|
static const auto watch = [] {
|
||||||
|
std::pair<uint64_t, uint64_t> range {0, 0};
|
||||||
|
return range;
|
||||||
|
}();
|
||||||
|
if (watch.second == 0 || vaddr >= watch.first + watch.second || watch.first >= vaddr + size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool MapBacking(uint64_t vaddr, uint64_t size, uint64_t backing_offset,
|
bool MapBacking(uint64_t vaddr, uint64_t size, uint64_t backing_offset,
|
||||||
VirtualMemory::Mode mode,
|
VirtualMemory::Mode mode,
|
||||||
GuestBackingStore::FailureReason* failure_reason = nullptr) {
|
GuestBackingStore::FailureReason* failure_reason = nullptr) {
|
||||||
|
LogBackingChange("MapBacking", vaddr, size, backing_offset);
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
if (!ConsumeUnlocked(vaddr, size)) {
|
if (!ConsumeUnlocked(vaddr, size)) {
|
||||||
if (failure_reason != nullptr) {
|
if (failure_reason != nullptr) {
|
||||||
@@ -786,6 +802,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool UnmapBacking(uint64_t vaddr, uint64_t size) {
|
bool UnmapBacking(uint64_t vaddr, uint64_t size) {
|
||||||
|
LogBackingChange("UnmapBacking", vaddr, size, 0);
|
||||||
std::lock_guard lock(m_mutex);
|
std::lock_guard lock(m_mutex);
|
||||||
if (!ContainsMappedUnlocked(vaddr, size, MappingType::Backing)) {
|
if (!ContainsMappedUnlocked(vaddr, size, MappingType::Backing)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -1089,7 +1106,7 @@ private:
|
|||||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
constexpr uint64_t MinimumRegionSize = 0x1000000;
|
constexpr uint64_t MinimumRegionSize = 0x1000000;
|
||||||
const auto process = GetCurrentProcess();
|
const auto process = GetCurrentProcess();
|
||||||
const auto guest_end = HOST_USER_MAX + 1u;
|
auto guest_end = HOST_GUEST_RESERVE_MAX;
|
||||||
auto next_addr = HOST_SYSTEM_MANAGED_MIN;
|
auto next_addr = HOST_SYSTEM_MANAGED_MIN;
|
||||||
|
|
||||||
while (next_addr < guest_end) {
|
while (next_addr < guest_end) {
|
||||||
|
|||||||
+11
-2
@@ -2855,11 +2855,11 @@ int KYTY_SYSV_ABI PthreadCondBroadcast(PthreadCond* cond) {
|
|||||||
bool notify = false;
|
bool notify = false;
|
||||||
{
|
{
|
||||||
std::lock_guard lock((*cond)->m);
|
std::lock_guard lock((*cond)->m);
|
||||||
|
(*cond)->sequence++;
|
||||||
if (!(*cond)->waiters.empty()) {
|
if (!(*cond)->waiters.empty()) {
|
||||||
(*cond)->sequence++;
|
|
||||||
CondClearWaiters(*cond);
|
CondClearWaiters(*cond);
|
||||||
notify = true;
|
|
||||||
}
|
}
|
||||||
|
notify = true;
|
||||||
}
|
}
|
||||||
if (notify) {
|
if (notify) {
|
||||||
(*cond)->cv.notify_all();
|
(*cond)->cv.notify_all();
|
||||||
@@ -3179,6 +3179,9 @@ int KYTY_SYSV_ABI PthreadCondTimedwaitAbs(PthreadCond* cond, PthreadMutex* mutex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
thread_local uint64_t g_guest_wait_caller = 0;
|
||||||
|
thread_local uint64_t g_guest_wait_r13 = 0;
|
||||||
|
|
||||||
int KYTY_SYSV_ABI PthreadCondWait(PthreadCond* cond, PthreadMutex* mutex) {
|
int KYTY_SYSV_ABI PthreadCondWait(PthreadCond* cond, PthreadMutex* mutex) {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
@@ -3373,6 +3376,8 @@ static void* RunThread(void* arg) {
|
|||||||
thread->unique_id = Common::Thread::GetThreadIdUnique();
|
thread->unique_id = Common::Thread::GetThreadIdUnique();
|
||||||
|
|
||||||
g_pthread_self = thread;
|
g_pthread_self = thread;
|
||||||
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
|
#endif
|
||||||
|
|
||||||
uint64_t os_thread_id = 0;
|
uint64_t os_thread_id = 0;
|
||||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||||
@@ -4445,6 +4450,10 @@ int KYTY_SYSV_ABI pthread_condattr_destroy(LibKernel::PthreadCondattr* attr) {
|
|||||||
int KYTY_SYSV_ABI pthread_cond_wait(LibKernel::PthreadCond* cond, LibKernel::PthreadMutex* mutex) {
|
int KYTY_SYSV_ABI pthread_cond_wait(LibKernel::PthreadCond* cond, LibKernel::PthreadMutex* mutex) {
|
||||||
// PRINT_NAME();
|
// PRINT_NAME();
|
||||||
|
|
||||||
|
uint64_t guest_r13 = 0;
|
||||||
|
__asm__ volatile("movq %%r13, %0" : "=r"(guest_r13));
|
||||||
|
LibKernel::g_guest_wait_r13 = guest_r13;
|
||||||
|
LibKernel::g_guest_wait_caller = reinterpret_cast<uint64_t>(__builtin_return_address(0));
|
||||||
return POSIX_PTHREAD_CALL(LibKernel::PthreadCondWait(cond, mutex));
|
return POSIX_PTHREAD_CALL(LibKernel::PthreadCondWait(cond, mutex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user