core: hle: kernel: Pin threads on CPU exceptions.
This commit is contained in:
@@ -167,6 +167,9 @@ add_library(core STATIC
|
||||
hle/api_version.h
|
||||
hle/ipc.h
|
||||
hle/ipc_helpers.h
|
||||
hle/kernel/arch/arm64/exception_handlers.cpp
|
||||
hle/kernel/arch/arm64/exception_handlers.h
|
||||
hle/kernel/arch/arm64/k_exception_context.h
|
||||
hle/kernel/board/nintendo/nx/k_memory_layout.h
|
||||
hle/kernel/board/nintendo/nx/k_system_control.cpp
|
||||
hle/kernel/board/nintendo/nx/k_system_control.h
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/debugger/debugger.h"
|
||||
#include "core/hle/kernel/arch/arm64/exception_handlers.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
@@ -104,11 +105,11 @@ public:
|
||||
case Dynarmic::A32::Exception::NoExecuteFault:
|
||||
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#08x}", pc);
|
||||
ReturnException(pc, ARM_Interface::no_execute);
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (debugger_enabled) {
|
||||
ReturnException(pc, ARM_Interface::breakpoint);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
parent.LogBacktrace();
|
||||
@@ -116,6 +117,21 @@ public:
|
||||
"ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X}, thumb = {})",
|
||||
exception, pc, memory.Read32(pc), parent.IsInThumbMode());
|
||||
}
|
||||
|
||||
// Load KExceptionContext
|
||||
Kernel::Arch::Arm64::KExceptionContext exception_context{};
|
||||
Core::ARM_Interface::ThreadContext32 thread_context{};
|
||||
parent.LoadContext(thread_context);
|
||||
for (size_t index = 0; index < thread_context.cpu_registers.size(); ++index) {
|
||||
exception_context.x[index] = thread_context.cpu_registers[index];
|
||||
}
|
||||
exception_context.sp = thread_context.cpu_registers[13];
|
||||
exception_context.pc = thread_context.cpu_registers[15];
|
||||
exception_context.psr = thread_context.cpsr;
|
||||
exception_context.tpidr = thread_context.tpidr;
|
||||
|
||||
// Kernel to handle exception
|
||||
Kernel::Arch::Arm64::HandleException(parent.system.Kernel(), exception_context);
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/debugger/debugger.h"
|
||||
#include "core/hardware_properties.h"
|
||||
#include "core/hle/kernel/arch/arm64/exception_handlers.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/memory.h"
|
||||
@@ -142,21 +143,36 @@ public:
|
||||
case Dynarmic::A64::Exception::SendEvent:
|
||||
case Dynarmic::A64::Exception::SendEventLocal:
|
||||
case Dynarmic::A64::Exception::Yield:
|
||||
return;
|
||||
break;
|
||||
case Dynarmic::A64::Exception::NoExecuteFault:
|
||||
LOG_CRITICAL(Core_ARM, "Cannot execute instruction at unmapped address {:#016x}", pc);
|
||||
ReturnException(pc, ARM_Interface::no_execute);
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
if (debugger_enabled) {
|
||||
ReturnException(pc, ARM_Interface::breakpoint);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
|
||||
parent.LogBacktrace();
|
||||
LOG_CRITICAL(Core_ARM, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
|
||||
static_cast<std::size_t>(exception), pc, memory.Read32(pc));
|
||||
}
|
||||
|
||||
// Load KExceptionContext
|
||||
Kernel::Arch::Arm64::KExceptionContext exception_context{};
|
||||
Core::ARM_Interface::ThreadContext64 thread_context{};
|
||||
parent.LoadContext(thread_context);
|
||||
for (size_t index = 0; index < thread_context.cpu_registers.size(); ++index) {
|
||||
exception_context.x[index] = thread_context.cpu_registers[index];
|
||||
}
|
||||
exception_context.sp = thread_context.sp;
|
||||
exception_context.pc = thread_context.pc;
|
||||
exception_context.psr = thread_context.pstate;
|
||||
exception_context.tpidr = thread_context.tpidr;
|
||||
|
||||
// Kernel to handle exception
|
||||
Kernel::Arch::Arm64::HandleException(parent.system.Kernel(), exception_context);
|
||||
}
|
||||
|
||||
void CallSVC(u32 swi) override {
|
||||
|
||||
33
src/core/hle/kernel/arch/arm64/exception_handlers.cpp
Normal file
33
src/core/hle/kernel/arch/arm64/exception_handlers.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/arch/arm64/exception_handlers.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
namespace Kernel::Arch::Arm64 {
|
||||
|
||||
void HandleException(KernelCore& kernel, const KExceptionContext& context) {
|
||||
auto* process = kernel.CurrentProcess();
|
||||
if (!process) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool is_user_mode = (context.psr & 0xF) == 0;
|
||||
if (is_user_mode) {
|
||||
// If the user disable count is set, we may need to pin the current thread.
|
||||
if (GetCurrentThread(kernel).GetUserDisableCount() != 0 &&
|
||||
process->GetPinnedThread(GetCurrentCoreId(kernel)) == nullptr) {
|
||||
KScopedSchedulerLock sl{kernel};
|
||||
|
||||
// Pin the current thread.
|
||||
process->PinCurrentThread(GetCurrentCoreId(kernel));
|
||||
|
||||
// Set the interrupt flag for the thread.
|
||||
GetCurrentThread(kernel).SetInterruptFlag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Kernel::Arch::Arm64
|
||||
15
src/core/hle/kernel/arch/arm64/exception_handlers.h
Normal file
15
src/core/hle/kernel/arch/arm64/exception_handlers.h
Normal file
@@ -0,0 +1,15 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/arch/arm64/k_exception_context.h"
|
||||
|
||||
namespace Kernel {
|
||||
class KernelCore;
|
||||
}
|
||||
|
||||
namespace Kernel::Arch::Arm64 {
|
||||
void HandleException(KernelCore& kernel, const KExceptionContext& context);
|
||||
}
|
||||
21
src/core/hle/kernel/arch/arm64/k_exception_context.h
Normal file
21
src/core/hle/kernel/arch/arm64/k_exception_context.h
Normal file
@@ -0,0 +1,21 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Kernel::Arch::Arm64 {
|
||||
|
||||
struct KExceptionContext {
|
||||
u64 x[(30 - 0) + 1];
|
||||
u64 sp;
|
||||
u64 pc;
|
||||
u32 psr;
|
||||
u32 write;
|
||||
u64 tpidr;
|
||||
u64 reserved;
|
||||
};
|
||||
static_assert(sizeof(KExceptionContext) == 0x120);
|
||||
|
||||
} // namespace Kernel::Arch::Arm64
|
||||
Reference in New Issue
Block a user