Merge pull request #156 from chrisps/misc_krnl4_23_23
[Kernel] Misc fixes, stubs
This commit is contained in:
commit
1b307ae129
|
@ -52,6 +52,10 @@ XE_GPU_REGISTER(0x057F, kDword, SCRATCH_REG7)
|
|||
|
||||
XE_GPU_REGISTER(0x05C8, kDword, WAIT_UNTIL)
|
||||
|
||||
//src is flash_xam.xex, i've seen it used by the kernel and aurora
|
||||
//seems to have a negative value while the gpu is busy
|
||||
//XE_GPU_REGISTER(0x05D0, kDword, RBBM_STATUS)
|
||||
|
||||
|
||||
//update count = 6 bit field, bits 8- 14
|
||||
//there are several other fields here, they have an unknown purpose
|
||||
|
@ -271,6 +275,8 @@ XE_GPU_REGISTER(0x0F0C, kDword, BC_PERFCOUNTER2_LOW)
|
|||
XE_GPU_REGISTER(0x0F0D, kDword, BC_PERFCOUNTER2_HI)
|
||||
XE_GPU_REGISTER(0x0F0E, kDword, BC_PERFCOUNTER3_LOW)
|
||||
XE_GPU_REGISTER(0x0F0F, kDword, BC_PERFCOUNTER3_HI)
|
||||
//src is flash_xam.xex
|
||||
//XE_GPU_REGISTER(0x0F12, RB_SIDEBAND_DATA,
|
||||
|
||||
XE_GPU_REGISTER(0x1004, kDword, HZ_PERFCOUNTER0_SELECT)
|
||||
XE_GPU_REGISTER(0x1005, kDword, HZ_PERFCOUNTER0_HI)
|
||||
|
|
|
@ -67,6 +67,14 @@ KernelState::KernelState(Emulator* emulator)
|
|||
// Hardcoded maximum of 2048 TLS slots.
|
||||
tls_bitmap_.Resize(2048);
|
||||
|
||||
auto hc_loc_heap = memory_->LookupHeap(strange_hardcoded_page_);
|
||||
bool fixed_alloc_worked = hc_loc_heap->AllocFixed(
|
||||
strange_hardcoded_page_, 65536, 0,
|
||||
kMemoryAllocationCommit | kMemoryAllocationReserve,
|
||||
kMemoryProtectRead | kMemoryProtectWrite);
|
||||
|
||||
xenia_assert(fixed_alloc_worked);
|
||||
|
||||
xam::AppManager::RegisterApps(this, app_manager_.get());
|
||||
}
|
||||
|
||||
|
@ -954,9 +962,7 @@ void KernelState::UpdateKeTimestampBundle() {
|
|||
}
|
||||
|
||||
uint32_t KernelState::GetKeTimestampBundle() {
|
||||
XE_LIKELY_IF(ke_timestamp_bundle_ptr_) {
|
||||
return ke_timestamp_bundle_ptr_;
|
||||
}
|
||||
XE_LIKELY_IF(ke_timestamp_bundle_ptr_) { return ke_timestamp_bundle_ptr_; }
|
||||
else {
|
||||
global_critical_region::PrepareToAcquire();
|
||||
return CreateKeTimestampBundle();
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/mutex.h"
|
||||
#include "xenia/cpu/export_resolver.h"
|
||||
#include "xenia/kernel/util/kernel_fwd.h"
|
||||
#include "xenia/kernel/util/native_list.h"
|
||||
#include "xenia/kernel/util/object_table.h"
|
||||
#include "xenia/kernel/util/xdbf_utils.h"
|
||||
|
@ -45,14 +46,6 @@ namespace kernel {
|
|||
|
||||
constexpr fourcc_t kKernelSaveSignature = make_fourcc("KRNL");
|
||||
|
||||
class Dispatcher;
|
||||
class XHostThread;
|
||||
class KernelModule;
|
||||
class XModule;
|
||||
class XNotifyListener;
|
||||
class XThread;
|
||||
class UserModule;
|
||||
|
||||
// (?), used by KeGetCurrentProcessType
|
||||
constexpr uint32_t X_PROCTYPE_IDLE = 0;
|
||||
constexpr uint32_t X_PROCTYPE_USER = 1;
|
||||
|
@ -292,7 +285,13 @@ class KernelState {
|
|||
BitMap tls_bitmap_;
|
||||
uint32_t ke_timestamp_bundle_ptr_ = 0;
|
||||
std::unique_ptr<xe::threading::HighResolutionTimer> timestamp_timer_;
|
||||
//fixed address referenced by dashboards. Data is currently unknown
|
||||
uint32_t strange_hardcoded_page_ = 0x8E038634 & (~0xFFFF);
|
||||
uint32_t strange_hardcoded_location_ = 0x8E038634;
|
||||
|
||||
friend class XObject;
|
||||
public:
|
||||
uint32_t dash_context_ = 0;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef XENIA_KERNEL_UTIL_KERNEL_FWD_H_
|
||||
#define XENIA_KERNEL_UTIL_KERNEL_FWD_H_
|
||||
|
||||
namespace xe::kernel {
|
||||
class Dispatcher;
|
||||
class XHostThread;
|
||||
class KernelModule;
|
||||
class XModule;
|
||||
class XNotifyListener;
|
||||
class XThread;
|
||||
class UserModule;
|
||||
struct ProcessInfoBlock;
|
||||
struct TerminateNotification;
|
||||
struct X_TIME_STAMP_BUNDLE;
|
||||
class KernelState;
|
||||
struct XAPC;
|
||||
|
||||
struct X_KPCR;
|
||||
struct X_KTHREAD;
|
||||
struct X_OBJECT_HEADER;
|
||||
struct X_OBJECT_CREATE_INFORMATION;
|
||||
struct X_OBJECT_TYPE;
|
||||
|
||||
} // namespace xe::kernel
|
||||
|
||||
namespace xe::kernel::util {
|
||||
class NativeList;
|
||||
class ObjectTable;
|
||||
}
|
||||
#endif
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
#include "xenia/kernel/util/shim_utils.h"
|
||||
|
||||
#include "xenia/kernel/xthread.h"
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace shim {
|
||||
|
@ -17,6 +17,10 @@ thread_local StringBuffer string_buffer_;
|
|||
|
||||
StringBuffer* thread_local_string_buffer() { return &string_buffer_; }
|
||||
|
||||
XThread* ContextParam::CurrentXThread() const {
|
||||
return XThread::GetCurrentThread();
|
||||
}
|
||||
|
||||
} // namespace shim
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -203,8 +203,21 @@ class ContextParam : public Param {
|
|||
|
||||
PPCContext* operator->() const { return ctx_; }
|
||||
|
||||
template <typename T>
|
||||
inline T TranslateVirtual(uint32_t guest_addr) const {
|
||||
return ctx_->TranslateVirtual<T>(guest_addr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T TranslateGPR(uint32_t which_gpr) const {
|
||||
return ctx_->TranslateVirtualGPR<T>(ctx_->r[which_gpr]);
|
||||
}
|
||||
|
||||
X_KPCR* GetPCR() const { return TranslateGPR<X_KPCR*>(13); }
|
||||
|
||||
XThread* CurrentXThread() const;
|
||||
protected:
|
||||
PPCContext* ctx_;
|
||||
PPCContext* XE_RESTRICT ctx_;
|
||||
};
|
||||
|
||||
class PointerParam : public ParamBase<uint32_t> {
|
||||
|
|
|
@ -475,7 +475,7 @@ dword_result_t XamSwapDisc_entry(
|
|||
completion_event();
|
||||
return X_ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
auto filesystem = kernel_state()->file_system();
|
||||
auto mount_path = "\\Device\\LauncherData";
|
||||
|
||||
|
@ -498,6 +498,14 @@ dword_result_t XamSwapDisc_entry(
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamSwapDisc, kContent, kSketchy);
|
||||
|
||||
dword_result_t XamLoaderGetMediaInfoEx_entry(dword_t unk1, dword_t unk2,
|
||||
lpdword_t unk3) {
|
||||
*unk3 = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_XAM_EXPORT1(XamLoaderGetMediaInfoEx, kContent, kStub);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -529,6 +529,22 @@ dword_result_t XamShowCommunitySessionsUI_entry(unknown_t r3, unknown_t r4) {
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamShowCommunitySessionsUI, kNone, kStub);
|
||||
|
||||
// this is supposed to do a lot more, calls another function that triggers some
|
||||
// cbs
|
||||
dword_result_t XamSetDashContext_entry(dword_t value,
|
||||
const ppc_context_t& ctx) {
|
||||
ctx->kernel_state->dash_context_ = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_XAM_EXPORT1(XamSetDashContext, kNone, kImplemented);
|
||||
|
||||
dword_result_t XamGetDashContext_entry(const ppc_context_t& ctx) {
|
||||
return ctx->kernel_state->dash_context_;
|
||||
}
|
||||
|
||||
DECLARE_XAM_EXPORT1(XamGetDashContext, kNone, kImplemented);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -808,6 +808,28 @@ dword_result_t XamSessionRefObjByHandle_entry(dword_t handle,
|
|||
}
|
||||
DECLARE_XAM_EXPORT1(XamSessionRefObjByHandle, kUserProfiles, kStub);
|
||||
|
||||
dword_result_t XamUserIsUnsafeProgrammingAllowed_entry(dword_t unk1, dword_t unk2,
|
||||
lpdword_t unk3, dword_t unk4,
|
||||
dword_t unk5, dword_t unk6) {
|
||||
if (!unk3 || unk1 != 255 && unk1 >= 4) {
|
||||
return 87;
|
||||
}
|
||||
*unk3 = 1;
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamUserIsUnsafeProgrammingAllowed, kUserProfiles, kStub);
|
||||
|
||||
dword_result_t XamUserGetSubscriptionType_entry(dword_t user_index, dword_t unk2,
|
||||
dword_t unk3, dword_t unk4,
|
||||
dword_t unk5, dword_t unk6) {
|
||||
if (!unk2 || !unk3 || user_index > 4) {
|
||||
return 0x80070057;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
DECLARE_XAM_EXPORT1(XamUserGetSubscriptionType, kUserProfiles, kStub);
|
||||
|
||||
} // namespace xam
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
|
|
@ -632,9 +632,30 @@ void ExFreePool_entry(lpvoid_t base_address) {
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(ExFreePool, kMemory, kImplemented);
|
||||
|
||||
dword_result_t KeGetImagePageTableEntry_entry(lpvoid_t address) {
|
||||
// Unknown
|
||||
return 1;
|
||||
// hv syscall 15, jumps into (bootloader function table??) alternative table ptr
|
||||
// offset 224
|
||||
// this is not a correct implementation. i just wanted to get it to return a
|
||||
// value thats in the same range as the hv's values that kind of reflects the
|
||||
// pages index and heap
|
||||
dword_result_t KeGetImagePageTableEntry_entry(dword_t address,
|
||||
const ppc_context_t& ctx) {
|
||||
auto kernel_state = ctx->kernel_state;
|
||||
xe::BaseHeap* image_heap = kernel_state->memory()->LookupHeap(address);
|
||||
if (image_heap->heap_type() != HeapType::kGuestXex) {
|
||||
return 0;
|
||||
}
|
||||
uint32_t returned_value = address - image_heap->heap_base();
|
||||
|
||||
// todo: its always a power of two, should shift
|
||||
returned_value /= image_heap->page_size();
|
||||
|
||||
if (image_heap->page_size() < 65536) {
|
||||
returned_value |= 0x40000000;
|
||||
}
|
||||
|
||||
return returned_value & 0x400FFFFF; // this is actually the mask it applies
|
||||
// to the final
|
||||
// result before returning it
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(KeGetImagePageTableEntry, kMemory, kStub);
|
||||
|
||||
|
|
|
@ -83,12 +83,25 @@ dword_result_t ObLookupThreadByThreadId_entry(dword_t thread_id,
|
|||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(ObLookupThreadByThreadId, kNone, kImplemented);
|
||||
|
||||
template <uint32_t ordinal>
|
||||
static constexpr uint32_t object_type_id_for_ordinal_v =
|
||||
0xD000BEEF | (ordinal << 16);
|
||||
// These values come from how Xenia handles uninitialized kernel data exports.
|
||||
// D###BEEF where ### is the ordinal.
|
||||
const static std::unordered_map<XObject::Type, uint32_t> object_types = {
|
||||
{XObject::Type::Event, 0xD00EBEEF},
|
||||
{XObject::Type::Semaphore, 0xD017BEEF},
|
||||
{XObject::Type::Thread, 0xD01BBEEF}};
|
||||
{XObject::Type::Event,
|
||||
object_type_id_for_ordinal_v<ordinals::ExEventObjectType>},
|
||||
{XObject::Type::Semaphore,
|
||||
object_type_id_for_ordinal_v<ordinals::ExSemaphoreObjectType>},
|
||||
{XObject::Type::Thread,
|
||||
object_type_id_for_ordinal_v<ordinals::ExThreadObjectType>},
|
||||
{XObject::Type::File,
|
||||
object_type_id_for_ordinal_v<ordinals::IoFileObjectType>},
|
||||
{XObject::Type::Mutant,
|
||||
object_type_id_for_ordinal_v<ordinals::ExMutantObjectType>},
|
||||
{XObject::Type::Device,
|
||||
object_type_id_for_ordinal_v<ordinals::IoDeviceObjectType>}};
|
||||
dword_result_t ObReferenceObjectByHandle_entry(dword_t handle,
|
||||
dword_t object_type_ptr,
|
||||
lpdword_t out_object_ptr) {
|
||||
|
@ -113,6 +126,8 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle,
|
|||
// Caller takes the reference.
|
||||
// It's released in ObDereferenceObject.
|
||||
object->RetainHandle();
|
||||
|
||||
xenia_assert(native_ptr != 0);
|
||||
if (out_object_ptr.guest_address()) {
|
||||
*out_object_ptr = native_ptr;
|
||||
}
|
||||
|
@ -120,14 +135,17 @@ dword_result_t ObReferenceObjectByHandle_entry(dword_t handle,
|
|||
}
|
||||
DECLARE_XBOXKRNL_EXPORT1(ObReferenceObjectByHandle, kNone, kImplemented);
|
||||
|
||||
dword_result_t ObReferenceObjectByName_entry(lpstring_t name,
|
||||
dword_result_t ObReferenceObjectByName_entry(pointer_t<X_ANSI_STRING> name,
|
||||
dword_t attributes,
|
||||
dword_t object_type_ptr,
|
||||
lpvoid_t parse_context,
|
||||
lpdword_t out_object_ptr) {
|
||||
lpdword_t out_object_ptr,
|
||||
const ppc_context_t& ctx) {
|
||||
X_HANDLE handle = X_INVALID_HANDLE_VALUE;
|
||||
|
||||
char* name_str = ctx.TranslateVirtual<char*>(name->pointer);
|
||||
X_STATUS result =
|
||||
kernel_state()->object_table()->GetObjectByName(name.value(), &handle);
|
||||
kernel_state()->object_table()->GetObjectByName(name_str, &handle);
|
||||
if (XSUCCEEDED(result)) {
|
||||
return ObReferenceObjectByHandle_entry(handle, object_type_ptr,
|
||||
out_object_ptr);
|
||||
|
@ -142,6 +160,10 @@ void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) {
|
|||
if (native_ptr == 0xDEADF00D) {
|
||||
return;
|
||||
}
|
||||
if (!native_ptr) {
|
||||
XELOGE("Null native ptr in ObDereferenceObject!");
|
||||
return;
|
||||
}
|
||||
|
||||
auto object = XObject::GetNativeObject<XObject>(
|
||||
kernel_state(), kernel_memory()->TranslateVirtual(native_ptr));
|
||||
|
|
|
@ -245,7 +245,7 @@ void KeSetCurrentStackPointers_entry(lpvoid_t stack_ptr,
|
|||
pcr->stack_base_ptr = stack_base.guest_address();
|
||||
pcr->stack_end_ptr = stack_limit.guest_address();
|
||||
context->r[1] = stack_ptr.guest_address();
|
||||
|
||||
|
||||
// If a fiber is set, and the thread matches, reenter to avoid issues with
|
||||
// host stack overflowing.
|
||||
if (thread->fiber_ptr &&
|
||||
|
@ -337,8 +337,8 @@ DECLARE_XBOXKRNL_EXPORT2(KeQueryPerformanceFrequency, kThreading, kImplemented,
|
|||
kHighFrequency);
|
||||
|
||||
uint32_t KeDelayExecutionThread(uint32_t processor_mode,
|
||||
uint32_t alertable,
|
||||
uint64_t* interval_ptr) {
|
||||
uint32_t alertable,
|
||||
uint64_t* interval_ptr) {
|
||||
XThread* thread = XThread::GetCurrentThread();
|
||||
X_STATUS result = thread->Delay(processor_mode, alertable, *interval_ptr);
|
||||
|
||||
|
@ -521,7 +521,7 @@ uint32_t xeNtSetEvent(uint32_t handle, xe::be<uint32_t>* previous_state_ptr) {
|
|||
//d3 ros does this
|
||||
if (ev->type() != XObject::Type::Event) {
|
||||
return X_STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
}
|
||||
int32_t was_signalled = ev->Set(0, false);
|
||||
if (previous_state_ptr) {
|
||||
*previous_state_ptr = static_cast<uint32_t>(was_signalled);
|
||||
|
@ -746,7 +746,7 @@ dword_result_t NtReleaseMutant_entry(dword_t mutant_handle, dword_t unknown) {
|
|||
auto mutant =
|
||||
kernel_state()->object_table()->LookupObject<XMutant>(mutant_handle);
|
||||
if (mutant) {
|
||||
result = mutant->ReleaseMutant(priority_increment, abandon, wait);
|
||||
mutant->ReleaseMutant(priority_increment, abandon, wait);
|
||||
} else {
|
||||
result = X_STATUS_INVALID_HANDLE;
|
||||
}
|
||||
|
@ -992,11 +992,7 @@ dword_result_t NtSignalAndWaitForSingleObjectEx_entry(dword_t signal_handle,
|
|||
DECLARE_XBOXKRNL_EXPORT3(NtSignalAndWaitForSingleObjectEx, kThreading,
|
||||
kImplemented, kBlocking, kHighFrequency);
|
||||
|
||||
static void PrefetchForCAS(const void* value) {
|
||||
if (amd64::GetFeatureFlags() & amd64::kX64EmitPrefetchW) {
|
||||
swcache::PrefetchW(value);
|
||||
}
|
||||
}
|
||||
static void PrefetchForCAS(const void* value) { swcache::PrefetchW(value); }
|
||||
|
||||
uint32_t xeKeKfAcquireSpinLock(uint32_t* lock, uint64_t r13 = 1) {
|
||||
// XELOGD(
|
||||
|
@ -1111,21 +1107,58 @@ void KeLeaveCriticalRegion_entry() {
|
|||
DECLARE_XBOXKRNL_EXPORT2(KeLeaveCriticalRegion, kThreading, kImplemented,
|
||||
kHighFrequency);
|
||||
|
||||
dword_result_t KeRaiseIrqlToDpcLevel_entry() {
|
||||
auto old_value = kernel_state()->processor()->RaiseIrql(cpu::Irql::DPC);
|
||||
return (uint32_t)old_value;
|
||||
dword_result_t KeRaiseIrqlToDpcLevel_entry(const ppc_context_t& ctx) {
|
||||
auto pcr = ctx.GetPCR();
|
||||
uint32_t old_irql = pcr->current_irql;
|
||||
|
||||
if (old_irql > 2) {
|
||||
XELOGE("KeRaiseIrqlToDpcLevel - old_irql > 2");
|
||||
}
|
||||
|
||||
pcr->current_irql = 2;
|
||||
|
||||
return old_irql;
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT2(KeRaiseIrqlToDpcLevel, kThreading, kImplemented,
|
||||
kHighFrequency);
|
||||
|
||||
void KfLowerIrql_entry(dword_t old_value) {
|
||||
kernel_state()->processor()->LowerIrql(
|
||||
static_cast<cpu::Irql>((uint32_t)old_value));
|
||||
// irql is supposed to be per thread afaik...
|
||||
void KfLowerIrql_entry(dword_t new_irql, const ppc_context_t& ctx) {
|
||||
X_KPCR* kpcr = ctx.GetPCR();
|
||||
|
||||
XThread::GetCurrentThread()->CheckApcs();
|
||||
if (new_irql > kpcr->current_irql) {
|
||||
XELOGE("KfLowerIrql : new_irql > kpcr->current_irql!");
|
||||
}
|
||||
kpcr->current_irql = new_irql;
|
||||
if (new_irql < 2) {
|
||||
{
|
||||
// this actually calls a function that eventually calls checkapcs.
|
||||
// the called function does a ton of other stuff including changing the
|
||||
// irql and interrupt_related
|
||||
ctx.CurrentXThread()->CheckApcs();
|
||||
}
|
||||
}
|
||||
}
|
||||
DECLARE_XBOXKRNL_EXPORT2(KfLowerIrql, kThreading, kImplemented, kHighFrequency);
|
||||
|
||||
// used by aurora's nova plugin
|
||||
// like the other irql related functions, writes to an unknown mmio range (
|
||||
// 0x7FFF ). The range is indexed by the low 16 bits of the KPCR's pointer (so
|
||||
// r13)
|
||||
dword_result_t KfRaiseIrql_entry(dword_t new_irql, const ppc_context_t& ctx) {
|
||||
X_KPCR* v1 = ctx.GetPCR();
|
||||
|
||||
uint32_t old_irql = v1->current_irql;
|
||||
v1->current_irql = new_irql;
|
||||
|
||||
if (old_irql > (unsigned int)new_irql) {
|
||||
XELOGE("KfRaiseIrql - old_irql > new_irql!");
|
||||
}
|
||||
return old_irql;
|
||||
}
|
||||
|
||||
DECLARE_XBOXKRNL_EXPORT2(KfRaiseIrql, kThreading, kImplemented, kHighFrequency);
|
||||
|
||||
void NtQueueApcThread_entry(dword_t thread_handle, lpvoid_t apc_routine,
|
||||
lpvoid_t apc_routine_context, lpvoid_t arg1,
|
||||
lpvoid_t arg2) {
|
||||
|
|
|
@ -134,6 +134,7 @@ class XObject {
|
|||
SymbolicLink,
|
||||
Thread,
|
||||
Timer,
|
||||
Device
|
||||
};
|
||||
|
||||
XObject(Type type);
|
||||
|
|
|
@ -71,7 +71,10 @@ struct XAPC {
|
|||
struct X_KPCR {
|
||||
xe::be<uint32_t> tls_ptr; // 0x0
|
||||
xe::be<uint32_t> msr_mask; // 0x4
|
||||
uint8_t unk_08[0x28]; // 0x8
|
||||
xe::be<uint16_t> interrupt_related; // 0x8
|
||||
uint8_t unk_08[0xE]; // 0xA
|
||||
uint8_t current_irql; // 0x18
|
||||
uint8_t unk_19[0x17]; // 0x19
|
||||
xe::be<uint32_t> pcr_ptr; // 0x30
|
||||
uint8_t unk_34[0x38]; // 0x34
|
||||
xe::be<uint32_t> use_alternative_stack; //0x6C
|
||||
|
|
Loading…
Reference in New Issue