diff --git a/src/xenia/gpu/register_table.inc b/src/xenia/gpu/register_table.inc index bfe7549d3..2ea5bf93f 100644 --- a/src/xenia/gpu/register_table.inc +++ b/src/xenia/gpu/register_table.inc @@ -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) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index 54b357e13..6835ef6fe 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -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(); diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index c917cdfb7..9c8e23766 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -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 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 diff --git a/src/xenia/kernel/util/kernel_fwd.h b/src/xenia/kernel/util/kernel_fwd.h new file mode 100644 index 000000000..4cae57a82 --- /dev/null +++ b/src/xenia/kernel/util/kernel_fwd.h @@ -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 \ No newline at end of file diff --git a/src/xenia/kernel/util/shim_utils.cc b/src/xenia/kernel/util/shim_utils.cc index 4da37acc0..68c0773ae 100644 --- a/src/xenia/kernel/util/shim_utils.cc +++ b/src/xenia/kernel/util/shim_utils.cc @@ -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 diff --git a/src/xenia/kernel/util/shim_utils.h b/src/xenia/kernel/util/shim_utils.h index 20c677f91..adb8bf450 100644 --- a/src/xenia/kernel/util/shim_utils.h +++ b/src/xenia/kernel/util/shim_utils.h @@ -203,8 +203,21 @@ class ContextParam : public Param { PPCContext* operator->() const { return ctx_; } + template + inline T TranslateVirtual(uint32_t guest_addr) const { + return ctx_->TranslateVirtual(guest_addr); + } + + template + inline T TranslateGPR(uint32_t which_gpr) const { + return ctx_->TranslateVirtualGPR(ctx_->r[which_gpr]); + } + + X_KPCR* GetPCR() const { return TranslateGPR(13); } + + XThread* CurrentXThread() const; protected: - PPCContext* ctx_; + PPCContext* XE_RESTRICT ctx_; }; class PointerParam : public ParamBase { diff --git a/src/xenia/kernel/xam/xam_content.cc b/src/xenia/kernel/xam/xam_content.cc index c6fe73d4b..1b0b9c844 100644 --- a/src/xenia/kernel/xam/xam_content.cc +++ b/src/xenia/kernel/xam/xam_content.cc @@ -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 diff --git a/src/xenia/kernel/xam/xam_ui.cc b/src/xenia/kernel/xam/xam_ui.cc index 11cd8faa7..30fb57bc6 100644 --- a/src/xenia/kernel/xam/xam_ui.cc +++ b/src/xenia/kernel/xam/xam_ui.cc @@ -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 diff --git a/src/xenia/kernel/xam/xam_user.cc b/src/xenia/kernel/xam/xam_user.cc index 32abc65fc..4ba177c38 100644 --- a/src/xenia/kernel/xam/xam_user.cc +++ b/src/xenia/kernel/xam/xam_user.cc @@ -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 diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc index 53f48b2b5..692f56e89 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_memory.cc @@ -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); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc index f7f0308e8..01700c3ad 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_ob.cc @@ -83,12 +83,25 @@ dword_result_t ObLookupThreadByThreadId_entry(dword_t thread_id, return X_STATUS_SUCCESS; } DECLARE_XBOXKRNL_EXPORT1(ObLookupThreadByThreadId, kNone, kImplemented); + +template +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 object_types = { - {XObject::Type::Event, 0xD00EBEEF}, - {XObject::Type::Semaphore, 0xD017BEEF}, - {XObject::Type::Thread, 0xD01BBEEF}}; + {XObject::Type::Event, + object_type_id_for_ordinal_v}, + {XObject::Type::Semaphore, + object_type_id_for_ordinal_v}, + {XObject::Type::Thread, + object_type_id_for_ordinal_v}, + {XObject::Type::File, + object_type_id_for_ordinal_v}, + {XObject::Type::Mutant, + object_type_id_for_ordinal_v}, + {XObject::Type::Device, + object_type_id_for_ordinal_v}}; 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 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(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( kernel_state(), kernel_memory()->TranslateVirtual(native_ptr)); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc index 6fbf2b0be..104b6bbf5 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc @@ -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* 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(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(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((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) { diff --git a/src/xenia/kernel/xobject.h b/src/xenia/kernel/xobject.h index ad693fa79..b42c0ffbd 100644 --- a/src/xenia/kernel/xobject.h +++ b/src/xenia/kernel/xobject.h @@ -134,6 +134,7 @@ class XObject { SymbolicLink, Thread, Timer, + Device }; XObject(Type type); diff --git a/src/xenia/kernel/xthread.h b/src/xenia/kernel/xthread.h index 15c5d8a0e..7f72a7e14 100644 --- a/src/xenia/kernel/xthread.h +++ b/src/xenia/kernel/xthread.h @@ -71,7 +71,10 @@ struct XAPC { struct X_KPCR { xe::be tls_ptr; // 0x0 xe::be msr_mask; // 0x4 - uint8_t unk_08[0x28]; // 0x8 + xe::be interrupt_related; // 0x8 + uint8_t unk_08[0xE]; // 0xA + uint8_t current_irql; // 0x18 + uint8_t unk_19[0x17]; // 0x19 xe::be pcr_ptr; // 0x30 uint8_t unk_34[0x38]; // 0x34 xe::be use_alternative_stack; //0x6C