[Kernel] Added KeSaveFloatingPointState and KeRestoreFloatingPointState from nukernel

This commit is contained in:
Gliniak
2026-02-15 22:23:30 +01:00
committed by Radosław Gliński
parent ec18a89da4
commit 80f2b535e9
3 changed files with 46 additions and 89 deletions

View File

@@ -28,94 +28,28 @@ void KeEnableFpuExceptions_entry(
kthread->fpu_exceptions_on = static_cast<uint32_t>(ctx->r[3]) != 0;
}
DECLARE_XBOXKRNL_EXPORT1(KeEnableFpuExceptions, kNone, kStub);
#if 0
struct __declspec(align(8)) fpucontext_ptr_t {
char unknown_data[158];
__int16 field_9E;
char field_A0[2272];
unsigned __int64 saved_FPSCR;
double saved_fpu_regs[32];
};
#pragma pack(push, 1)
struct __declspec(align(1)) r13_struct_t {
char field_0[6];
__int16 field_6;
char field_8[2];
char field_A;
char field_B[5];
int field_10;
char field_14[315];
char field_14F;
unsigned int field_150;
char field_154[427];
char field_2FF;
char field_300;
};
#pragma pack(pop)
void KeSaveFloatingPointState_entry(const ppc_context_t& ctx) {
// Probably we should use: thread_fpu_related to store/restore state
X_KTHREAD* kthread = ctx->TranslateVirtual(
ctx->TranslateVirtualGPR<X_KPCR*>(ctx->r[13])->prcb_data.current_thread);
static uint64_t Do_mfmsr(ppc_context_t& ctx) {
auto frontend = ctx->thread_state->processor()->frontend();
cpu::ppc::CheckGlobalLock(
ctx, reinterpret_cast<void*>(&xe::global_critical_region::mutex()),
reinterpret_cast<void*>(&frontend->builtins()->global_lock_count));
return ctx->scratch;
}
void KeSaveFloatingPointState_entry(ppc_context_t& ctx) {
xe::Memory* memory = ctx->thread_state->memory();
unsigned int r13 = static_cast<unsigned int>(ctx->r[13]);
r13_struct_t* st = memory->TranslateVirtual<r13_struct_t*>(r13);
/*
lwz r10, 0x150(r13)
lbz r11, 0xA(r13)
tweqi r10, 0
twnei r11, 0
*/
unsigned int r10 = st->field_150;
unsigned char r11 = st->field_A;
if (r10 == 0 || r11 != 0) {
//trap!
for (size_t i = 0; i < xe::countof(ctx->f); ++i) {
kthread->fpu_context[i] = ctx->f[i];
}
//should do mfmsr here
unsigned int r3 = xe::load_and_swap<unsigned int>(&st->field_10);
//too much work to do the mfmsr/mtmsr stuff right now
int to_store = -2049;
xe::store_and_swap(&st->field_10, (unsigned int)to_store);
xe::store_and_swap(&st->field_6, (short)to_store);
if (r3 != ~0u) {
fpucontext_ptr_t* fpucontext =
memory->TranslateVirtual<fpucontext_ptr_t*>(r3);
xe::store_and_swap<uint64_t>(&fpucontext->saved_FPSCR, ctx->fpscr.value);
for (unsigned int i = 0; i < 32; ++i) {
xe::store_and_swap(&fpucontext->saved_fpu_regs[i], ctx->f[i]);
}
xe::store_and_swap<unsigned short>(&fpucontext->field_9E, 0xD7FF);
}
ctx->processor->backend()->SetGuestRoundingMode(ctx.value(), 0);
ctx->fpscr.value = 0;
st->field_A = 1;
xe::store_and_swap(&st->field_10, r13 + 0x300);
ctx->r[3] = r3;
}
DECLARE_XBOXKRNL_EXPORT1(KeSaveFloatingPointState, kNone, kSketchy);
void KeRestoreFloatingPointState_entry(const ppc_context_t& ctx) {
const X_KTHREAD* kthread = ctx->TranslateVirtual(
ctx->TranslateVirtualGPR<X_KPCR*>(ctx->r[13])->prcb_data.current_thread);
for (size_t i = 0; i < xe::countof(ctx->f); ++i) {
ctx->f[i] = kthread->fpu_context[i];
}
}
DECLARE_XBOXKRNL_EXPORT1(KeRestoreFloatingPointState, kNone, kSketchy);
DECLARE_XBOXKRNL_EXPORT1(KeSaveFloatingPointState, kNone, kImplemented);
#endif
static qword_result_t KeQueryInterruptTime_entry(const ppc_context_t& ctx) {
auto kstate = ctx->kernel_state;
uint32_t ts_bundle = kstate->GetKeTimestampBundle();