Skip to content

Commit

Permalink
Make sure to squash all these when you merge
Browse files Browse the repository at this point in the history
  • Loading branch information
OFFTKP committed Sep 18, 2024
1 parent dbc7b11 commit 1c4873d
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 50 deletions.
51 changes: 15 additions & 36 deletions src/core/cpu_patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -800,9 +800,9 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {

if (needs_trampoline && instruction.length < 5) {
// Trampoline is needed but instruction is too short to patch.
// Should be handled at illegal instruction handler.
// This if is for Linux which does some AOT patching,
// should be removed if that gets removed.
// Return false and length to fall back to the illegal instruction handler,
// or to signal to AOT compilation that this instruction should be skipped and
// handled at runtime.
return std::make_pair(false, instruction.length);
}

Expand Down Expand Up @@ -847,27 +847,8 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
}

#if defined(ARCH_X86_64)
// We need to check, before patching, if there's enough space for a relative jump to the trampoline.
// If there isn't, the instruction must be handled specially in the illegal instruction handler
// itself.
static bool ShouldNotBePatched(void* code_address) {
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status =
Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address);
if (!ZYAN_SUCCESS(status)) {
LOG_ERROR(Core, "Failed to decode instruction at: {}", fmt::ptr(code_address));
}

if (instruction.length < 5) {
// not enough bytes for a relative jump for the trampoline
return true;
}

return false;
}

static bool HandleIllegalInstruction(void* ctx, void* code_address) {
static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT];
const auto status =
Expand Down Expand Up @@ -924,15 +905,13 @@ static bool HandleIllegalInstruction(void* ctx, void* code_address) {
return false;
}
}

UNREACHABLE();
}
#elif defined(ARCH_ARM64)
// These functions shouldn't be needed for ARM as it will use a JIT so there's no need to patch
// instructions. Returning false lets it go through with whatever handler is set up.
static bool ShouldNotBePatched(void*) {
return false;
}

static bool HandleIllegalInstruction(void*, void*) {
// instructions.
static bool TryExecuteIllegalInstruction(void*, void*) {
return false;
}
#else
Expand Down Expand Up @@ -971,16 +950,16 @@ static void TryPatchAot(void* code_address, u64 code_size) {
}
}

static bool PatchesAccessViolationHandler(void* code_address, void* fault_address, bool is_write) {
return TryPatchJit(code_address);
static bool PatchesAccessViolationHandler(void* context, void* /* fault_address */) {
return TryPatchJit(context);
}

static bool PatchesIllegalInstructionHandler(void* context, void* code_address) {
if (ShouldNotBePatched(code_address)) {
return HandleIllegalInstruction(context, code_address);
} else {
return TryPatchJit(code_address);
static bool PatchesIllegalInstructionHandler(void* context) {
void* code_address = Common::GetRip(context);
if (!TryPatchJit(code_address)) {
return TryExecuteIllegalInstruction(context, code_address);
}
return true;
}

static void PatchesInit() {
Expand Down
18 changes: 9 additions & 9 deletions src/core/signals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,17 @@ static void SignalHandler(int sig, siginfo_t* info, void* raw_context) {

switch (sig) {
case SIGSEGV:
case SIGBUS:
if (const bool is_write = Common::IsWriteError(raw_context);
!signals->DispatchAccessViolation(code_address, info->si_addr, is_write)) {
case SIGBUS: {
const bool is_write = Common::IsWriteError(raw_context);
if (!signals->DispatchAccessViolation(code_address, info->si_addr)) {
UNREACHABLE_MSG("Unhandled access violation at code address {}: {} address {}",
fmt::ptr(code_address), is_write ? "Write to" : "Read from",
fmt::ptr(info->si_addr));
}
break;
}
case SIGILL:
if (!signals->DispatchIllegalInstruction(raw_context, code_address)) {
if (!signals->DispatchIllegalInstruction(raw_context)) {
UNREACHABLE_MSG("Unhandled illegal instruction at code address {}: {}",
fmt::ptr(code_address), DisassembleInstruction(code_address));
}
Expand Down Expand Up @@ -127,19 +128,18 @@ SignalDispatch::~SignalDispatch() {
#endif
}

bool SignalDispatch::DispatchAccessViolation(void* code_address, void* fault_address,
bool is_write) const {
bool SignalDispatch::DispatchAccessViolation(void* context, void* fault_address) const {
for (const auto& [handler, _] : access_violation_handlers) {
if (handler(code_address, fault_address, is_write)) {
if (handler(context, fault_address)) {
return true;
}
}
return false;
}

bool SignalDispatch::DispatchIllegalInstruction(void* context, void* code_address) const {
bool SignalDispatch::DispatchIllegalInstruction(void* context) const {
for (const auto& [handler, _] : illegal_instruction_handlers) {
if (handler(context, code_address)) {
if (handler(context)) {
return true;
}
}
Expand Down
8 changes: 4 additions & 4 deletions src/core/signals.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

namespace Core {

using AccessViolationHandler = bool (*)(void* code_address, void* fault_address, bool is_write);
using IllegalInstructionHandler = bool (*)(void* context, void* code_address);
using AccessViolationHandler = bool (*)(void* context, void* fault_address);
using IllegalInstructionHandler = bool (*)(void* context);

/// Receives OS signals and dispatches to the appropriate handlers.
class SignalDispatch {
Expand All @@ -28,10 +28,10 @@ class SignalDispatch {
}

/// Dispatches an access violation signal, returning whether it was successfully handled.
bool DispatchAccessViolation(void* code_address, void* fault_address, bool is_write) const;
bool DispatchAccessViolation(void* context, void* fault_address) const;

/// Dispatches an illegal instruction signal, returning whether it was successfully handled.
bool DispatchIllegalInstruction(void* context, void* code_address) const;
bool DispatchIllegalInstruction(void* context) const;

private:
template <typename T>
Expand Down
4 changes: 3 additions & 1 deletion src/video_core/page_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/error.h"
#include "common/signal_context.h"
#include "core/signals.h"
#include "video_core/page_manager.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
Expand Down Expand Up @@ -152,8 +153,9 @@ struct PageManager::Impl {
#endif
}

static bool GuestFaultSignalHandler(void* code_address, void* fault_address, bool is_write) {
static bool GuestFaultSignalHandler(void* code_address, void* fault_address) {
const auto addr = reinterpret_cast<VAddr>(fault_address);
const bool is_write = Common::IsWriteError(code_address);
if (is_write && owned_ranges.find(addr) != owned_ranges.end()) {
const VAddr addr_aligned = Common::AlignDown(addr, PAGESIZE);
rasterizer->InvalidateMemory(addr_aligned, PAGESIZE);
Expand Down

0 comments on commit 1c4873d

Please sign in to comment.