mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-29 16:35:29 +03:00
Implement SVC GetThreadContext3
A partial implementation of the `GetThreadContext3` SVC, we cannot return the whole thread context as the kernel only stores the registers we need according to the ARMv8 ABI convention and so far usages of this SVC do not require the unavailable registers but all future usage must be monitored and potentially require extending the amount of saved registers.
This commit is contained in:
parent
b706aa3463
commit
de81d28b1d
@ -1140,6 +1140,63 @@ namespace skyline::kernel::svc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetThreadContext3(const DeviceState &state) {
|
||||||
|
KHandle threadHandle{state.ctx->gpr.w1};
|
||||||
|
try {
|
||||||
|
auto thread{state.process->GetHandle<type::KThread>(threadHandle)};
|
||||||
|
if (thread == state.thread) {
|
||||||
|
Logger::Warn("Thread attempting to retrieve own context: 0x{:X}", threadHandle);
|
||||||
|
state.ctx->gpr.w0 = result::Busy;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::scoped_lock guard{thread->coreMigrationMutex};
|
||||||
|
if (!thread->isPaused) {
|
||||||
|
Logger::Warn("Attemping to get context of running thread: 0x{:X}", threadHandle);
|
||||||
|
state.ctx->gpr.w0 = result::InvalidState;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ThreadContext {
|
||||||
|
std::array<u64, 29> gpr;
|
||||||
|
u64 fp;
|
||||||
|
u64 lr;
|
||||||
|
u64 sp;
|
||||||
|
u64 pc;
|
||||||
|
u32 pstate;
|
||||||
|
u32 _pad_;
|
||||||
|
std::array<u128, 32> vreg;
|
||||||
|
u32 fpcr;
|
||||||
|
u32 fpsr;
|
||||||
|
u64 tpidr;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ThreadContext) == 0x320);
|
||||||
|
|
||||||
|
auto &context{*reinterpret_cast<ThreadContext *>(state.ctx->gpr.x0)};
|
||||||
|
context = {}; // Zero-initialize the contents of the context as not all fields are set
|
||||||
|
|
||||||
|
auto& targetContext{thread->ctx};
|
||||||
|
for (size_t i{}; i < targetContext.gpr.regs.size(); i++)
|
||||||
|
context.gpr[i] = targetContext.gpr.regs[i];
|
||||||
|
|
||||||
|
for (size_t i{}; i < targetContext.fpr.regs.size(); i++)
|
||||||
|
context.vreg[i] = targetContext.fpr.regs[i];
|
||||||
|
|
||||||
|
context.fpcr = targetContext.fpr.fpcr;
|
||||||
|
context.fpsr = targetContext.fpr.fpsr;
|
||||||
|
|
||||||
|
context.tpidr = reinterpret_cast<u64>(targetContext.tpidrEl0);
|
||||||
|
|
||||||
|
// Note: We don't write the whole context as we only store the parts required according to the ARMv8 ABI for syscall handling
|
||||||
|
Logger::Debug("Written partial context for thread 0x{:X}", threadHandle);
|
||||||
|
|
||||||
|
state.ctx->gpr.w0 = Result{};
|
||||||
|
} catch (const std::out_of_range &) {
|
||||||
|
Logger::Warn("'handle' invalid: 0x{:X}", threadHandle);
|
||||||
|
state.ctx->gpr.w0 = result::InvalidHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void WaitForAddress(const DeviceState &state) {
|
void WaitForAddress(const DeviceState &state) {
|
||||||
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
|
||||||
if (!util::IsWordAligned(address)) [[unlikely]] {
|
if (!util::IsWordAligned(address)) [[unlikely]] {
|
||||||
|
@ -228,6 +228,12 @@ namespace skyline::kernel::svc {
|
|||||||
*/
|
*/
|
||||||
void SetThreadActivity(const DeviceState &state);
|
void SetThreadActivity(const DeviceState &state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the context structure of a paused thread
|
||||||
|
* @url https://switchbrew.org/wiki/SVC#GetThreadContext3
|
||||||
|
*/
|
||||||
|
void GetThreadContext3(const DeviceState &state);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Waits on an address based on the value of the address
|
* @brief Waits on an address based on the value of the address
|
||||||
* @url https://switchbrew.org/wiki/SVC#WaitForAddress
|
* @url https://switchbrew.org/wiki/SVC#WaitForAddress
|
||||||
@ -312,7 +318,7 @@ namespace skyline::kernel::svc {
|
|||||||
SVC_NONE, // 0x30
|
SVC_NONE, // 0x30
|
||||||
SVC_NONE, // 0x31
|
SVC_NONE, // 0x31
|
||||||
SVC_ENTRY(SetThreadActivity), // 0x32
|
SVC_ENTRY(SetThreadActivity), // 0x32
|
||||||
SVC_NONE, // 0x33
|
SVC_ENTRY(GetThreadContext3), // 0x33
|
||||||
SVC_ENTRY(WaitForAddress), // 0x34
|
SVC_ENTRY(WaitForAddress), // 0x34
|
||||||
SVC_ENTRY(SignalToAddress), // 0x35
|
SVC_ENTRY(SignalToAddress), // 0x35
|
||||||
SVC_NONE, // 0x36
|
SVC_NONE, // 0x36
|
||||||
|
@ -103,8 +103,8 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace guest {
|
namespace guest {
|
||||||
constexpr size_t SaveCtxSize{39}; //!< The size of the SaveCtx function in 32-bit ARMv8 instructions
|
constexpr size_t SaveCtxSize{34}; //!< The size of the SaveCtx function in 32-bit ARMv8 instructions
|
||||||
constexpr size_t LoadCtxSize{39}; //!< The size of the LoadCtx function in 32-bit ARMv8 instructions
|
constexpr size_t LoadCtxSize{34}; //!< The size of the LoadCtx function in 32-bit ARMv8 instructions
|
||||||
constexpr size_t RescaleClockSize{16}; //!< The size of the RescaleClock function in 32-bit ARMv8 instructions
|
constexpr size_t RescaleClockSize{16}; //!< The size of the RescaleClock function in 32-bit ARMv8 instructions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user