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:
PixelyIon 2022-04-09 17:02:40 +05:30
parent b706aa3463
commit de81d28b1d
3 changed files with 66 additions and 3 deletions

View File

@ -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) {
auto address{reinterpret_cast<u32 *>(state.ctx->gpr.x0)};
if (!util::IsWordAligned(address)) [[unlikely]] {

View File

@ -228,6 +228,12 @@ namespace skyline::kernel::svc {
*/
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
* @url https://switchbrew.org/wiki/SVC#WaitForAddress
@ -312,7 +318,7 @@ namespace skyline::kernel::svc {
SVC_NONE, // 0x30
SVC_NONE, // 0x31
SVC_ENTRY(SetThreadActivity), // 0x32
SVC_NONE, // 0x33
SVC_ENTRY(GetThreadContext3), // 0x33
SVC_ENTRY(WaitForAddress), // 0x34
SVC_ENTRY(SignalToAddress), // 0x35
SVC_NONE, // 0x36

View File

@ -103,8 +103,8 @@ namespace skyline {
};
namespace guest {
constexpr size_t SaveCtxSize{39}; //!< 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 SaveCtxSize{34}; //!< The size of the SaveCtx 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
/**