mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 01:05:31 +03:00
Handle host accesses for NCE Memory Trapping API
We cannot ignore accesses from the host to a region protected by the NCE Memory Trapping API, there's often access to regions which have overlap with a protected region unintentionally and those accesses need to be handled correctly rather than leading to a crash. This is done by implementing an additional signal handler `NCE::HostSignalHandler` to lookup any potential traps on a `SIGSEGV` and handle them correctly or when there isn't a corresponding trap raise a `SIGTRAP` when debugger is connected or delegate to `signal::ExceptionalSignalHandler` when it isn't.
This commit is contained in:
parent
b04a0c386a
commit
cb2614f80e
@ -107,37 +107,46 @@ namespace skyline::nce {
|
|||||||
|
|
||||||
*tls = nullptr;
|
*tls = nullptr;
|
||||||
} else { // If TLS wasn't restored then this occurred in host code
|
} else { // If TLS wasn't restored then this occurred in host code
|
||||||
if (signal == SIGSEGV) {
|
HostSignalHandler(signal, info, ctx);
|
||||||
bool runningUnderDebugger{[]() {
|
|
||||||
static std::ifstream status("/proc/self/status");
|
|
||||||
status.seekg(0);
|
|
||||||
|
|
||||||
constexpr std::string_view TracerPidTag{"TracerPid:"};
|
|
||||||
for (std::string line; std::getline(status, line);) {
|
|
||||||
if (line.starts_with(TracerPidTag)) {
|
|
||||||
line = line.substr(TracerPidTag.size());
|
|
||||||
|
|
||||||
for (char character : line)
|
|
||||||
if (std::isspace(character))
|
|
||||||
continue;
|
|
||||||
else
|
|
||||||
return character != '0';
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}()};
|
|
||||||
|
|
||||||
if (runningUnderDebugger)
|
|
||||||
raise(SIGTRAP); // Notify the debugger if we've got a SIGSEGV as the debugger doesn't catch them by default as they might be hooked
|
|
||||||
}
|
|
||||||
|
|
||||||
signal::ExceptionalSignalHandler(signal, info, ctx); //!< Delegate throwing a host exception to the exceptional signal handler
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static NCE* staticNce{nullptr}; //!< A static instance of NCE for use in the signal handler
|
||||||
|
|
||||||
|
void NCE::HostSignalHandler(int signal, siginfo *info, ucontext *ctx) {
|
||||||
|
if (signal == SIGSEGV) {
|
||||||
|
if (staticNce && staticNce->TrapHandler(reinterpret_cast<u8 *>(info->si_addr), true))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool runningUnderDebugger{[]() {
|
||||||
|
static std::ifstream status("/proc/self/status");
|
||||||
|
status.seekg(0);
|
||||||
|
|
||||||
|
constexpr std::string_view TracerPidTag{"TracerPid:"};
|
||||||
|
for (std::string line; std::getline(status, line);) {
|
||||||
|
if (line.starts_with(TracerPidTag)) {
|
||||||
|
line = line.substr(TracerPidTag.size());
|
||||||
|
|
||||||
|
for (char character : line)
|
||||||
|
if (std::isspace(character))
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
return character != '0';
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}()};
|
||||||
|
|
||||||
|
if (runningUnderDebugger)
|
||||||
|
raise(SIGTRAP); // Notify the debugger if we've got a SIGSEGV as the debugger doesn't catch them by default as they might be hooked
|
||||||
|
}
|
||||||
|
|
||||||
|
signal::ExceptionalSignalHandler(signal, info, ctx); // Delegate throwing a host exception to the exceptional signal handler
|
||||||
|
}
|
||||||
|
|
||||||
void *NceTlsRestorer() {
|
void *NceTlsRestorer() {
|
||||||
ThreadContext *threadCtx;
|
ThreadContext *threadCtx;
|
||||||
asm volatile("MRS %x0, TPIDR_EL0":"=r"(threadCtx));
|
asm volatile("MRS %x0, TPIDR_EL0":"=r"(threadCtx));
|
||||||
@ -149,6 +158,7 @@ namespace skyline::nce {
|
|||||||
|
|
||||||
NCE::NCE(const DeviceState &state) : state(state) {
|
NCE::NCE(const DeviceState &state) : state(state) {
|
||||||
signal::SetTlsRestorer(&NceTlsRestorer);
|
signal::SetTlsRestorer(&NceTlsRestorer);
|
||||||
|
staticNce = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u8 MainSvcTrampolineSize{17}; // Size of the main SVC trampoline function in u32 units
|
constexpr u8 MainSvcTrampolineSize{17}; // Size of the main SVC trampoline function in u32 units
|
||||||
|
@ -64,6 +64,15 @@ namespace skyline::nce {
|
|||||||
*/
|
*/
|
||||||
static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls);
|
static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles signals for any host threads which may access NCE trapped memory
|
||||||
|
* @note Any untrapped SIGSEGVs will emit SIGTRAP when a debugger is attached rather than throwing an exception
|
||||||
|
*/
|
||||||
|
static void HostSignalHandler(int signal, siginfo *info, ucontext *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @note There should only be one instance of NCE concurrently
|
||||||
|
*/
|
||||||
NCE(const DeviceState &state);
|
NCE(const DeviceState &state);
|
||||||
|
|
||||||
struct PatchData {
|
struct PatchData {
|
||||||
|
@ -330,7 +330,8 @@ namespace skyline::soc::gm20b {
|
|||||||
void ChannelGpfifo::Run() {
|
void ChannelGpfifo::Run() {
|
||||||
pthread_setname_np(pthread_self(), "GPFIFO");
|
pthread_setname_np(pthread_self(), "GPFIFO");
|
||||||
try {
|
try {
|
||||||
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler);
|
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE}, signal::ExceptionalSignalHandler);
|
||||||
|
signal::SetSignalHandler({SIGSEGV}, nce::NCE::HostSignalHandler); // We may access NCE trapped memory
|
||||||
|
|
||||||
gpEntries.Process([this](GpEntry gpEntry) {
|
gpEntries.Process([this](GpEntry gpEntry) {
|
||||||
Logger::Debug("Processing pushbuffer: 0x{:X}, Size: 0x{:X}", gpEntry.Address(), +gpEntry.size);
|
Logger::Debug("Processing pushbuffer: 0x{:X}, Size: 0x{:X}", gpEntry.Address(), +gpEntry.size);
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <common/signal.h>
|
#include <common/signal.h>
|
||||||
|
#include <nce.h>
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
#include <kernel/types/KProcess.h>
|
#include <kernel/types/KProcess.h>
|
||||||
#include <soc.h>
|
#include <soc.h>
|
||||||
@ -115,7 +116,8 @@ namespace skyline::soc::host1x {
|
|||||||
void ChannelCommandFifo::Run() {
|
void ChannelCommandFifo::Run() {
|
||||||
pthread_setname_np(pthread_self(), "ChannelCommandFifo");
|
pthread_setname_np(pthread_self(), "ChannelCommandFifo");
|
||||||
try {
|
try {
|
||||||
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler);
|
signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE}, signal::ExceptionalSignalHandler);
|
||||||
|
signal::SetSignalHandler({SIGSEGV}, nce::NCE::HostSignalHandler); // We may access NCE trapped memory
|
||||||
|
|
||||||
gatherQueue.Process([this](span<u32> gather) {
|
gatherQueue.Process([this](span<u32> gather) {
|
||||||
Logger::Debug("Processing pushbuffer: 0x{:X}, size: 0x{:X}", gather.data(), gather.size());
|
Logger::Debug("Processing pushbuffer: 0x{:X}, size: 0x{:X}", gather.data(), gather.size());
|
||||||
@ -144,4 +146,4 @@ namespace skyline::soc::host1x {
|
|||||||
thread.join();
|
thread.join();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user