diff --git a/src/xenia/kernel/xboxkrnl/cert_monitor.cc b/src/xenia/kernel/xboxkrnl/cert_monitor.cc new file mode 100644 index 000000000..9f552b9c3 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/cert_monitor.cc @@ -0,0 +1,42 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h" + +#include + +#include + +#include "xenia/base/clock.h" +#include "xenia/base/debugging.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/cpu/ppc/ppc_context.h" +#include "xenia/cpu/processor.h" +#include "xenia/emulator.h" +#include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/user_module.h" +#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/kernel/xthread.h" + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +void KeCertMonitorCallback(cpu::ppc::PPCContext* ppc_context, + kernel::KernelState* kernel_state) { + auto id = ppc_context->r[3]; + auto arg = ppc_context->r[4]; + XELOGI("KeCertMonitorCallback(%u, %08x)", id, arg); + auto xboxkrnl = kernel_state->GetKernelModule("xboxkrnl.exe"); +} + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/cert_monitor.h b/src/xenia/kernel/xboxkrnl/cert_monitor.h new file mode 100644 index 000000000..16a80d982 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/cert_monitor.h @@ -0,0 +1,35 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_KERNEL_XBOXKRNL_CERT_MONITOR_H_ +#define XENIA_KERNEL_KERNEL_XBOXKRNL_CERT_MONITOR_H_ + +#include + +#include "xenia/base/threading.h" +#include "xenia/cpu/export_resolver.h" +#include "xenia/kernel/kernel_module.h" +#include "xenia/kernel/kernel_state.h" + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +struct X_KECERTMONITORDATA { + xe::be callback_fn; +}; + +void KeCertMonitorCallback(cpu::ppc::PPCContext* ppc_context, + kernel::KernelState* kernel_state); + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_KERNEL_XBOXKRNL_CERT_MONITOR_H_ diff --git a/src/xenia/kernel/xboxkrnl/debug_monitor.cc b/src/xenia/kernel/xboxkrnl/debug_monitor.cc new file mode 100644 index 000000000..cfd4ef967 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/debug_monitor.cc @@ -0,0 +1,99 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include "xenia/kernel/xboxkrnl/xboxkrnl_module.h" + +#include + +#include + +#include "xenia/base/clock.h" +#include "xenia/base/debugging.h" +#include "xenia/base/logging.h" +#include "xenia/base/math.h" +#include "xenia/cpu/ppc/ppc_context.h" +#include "xenia/cpu/processor.h" +#include "xenia/emulator.h" +#include "xenia/kernel/kernel_state.h" +#include "xenia/kernel/user_module.h" +#include "xenia/kernel/util/shim_utils.h" +#include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/kernel/xthread.h" + +DECLARE_bool(kernel_pix); + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +enum class DebugMonitorCommand { + PIXCommandResult = 27, + SetPIXCallback = 28, + Unknown66 = 66, + Unknown89 = 89, + Unknown94 = 94, +}; + +void KeDebugMonitorCallback(cpu::ppc::PPCContext* ppc_context, + kernel::KernelState* kernel_state) { + auto id = static_cast(ppc_context->r[3] & 0xFFFFFFFFu); + auto arg = static_cast(ppc_context->r[4] & 0xFFFFFFFFu); + + XELOGI("KeDebugMonitorCallback(%u, %08x)", static_cast(id), arg); + + if (!FLAGS_kernel_pix) { + SHIM_SET_RETURN_32(-1); + return; + } + + auto xboxkrnl = kernel_state->GetKernelModule("xboxkrnl.exe"); + + switch (id) { + case DebugMonitorCommand::PIXCommandResult: { + auto s = kernel_state->memory()->TranslateVirtual(arg); + debugging::DebugPrint("%s\n", s); + XELOGD("PIX command result: %s\n", s); + if (strcmp(s, "PIX!{CaptureFileCreationEnded} 0x00000000") == 0) { + xboxkrnl->SendPIXCommand("{BeginCapture}"); + } + SHIM_SET_RETURN_32(0); + break; + } + case DebugMonitorCommand::SetPIXCallback: + xboxkrnl->set_pix_function(arg); + xboxkrnl->SendPIXCommand("{LimitCaptureSize} 100"); // in MB + xboxkrnl->SendPIXCommand("{BeginCaptureFileCreation} scratch:\\test.cap"); + SHIM_SET_RETURN_32(0); + break; + case DebugMonitorCommand::Unknown66: { + struct callback_info { + xe::be callback_fn; + xe::be callback_arg; // D3D device object? + }; + auto cbi = kernel_state->memory()->TranslateVirtual(arg); + SHIM_SET_RETURN_32(0); + break; + } + case DebugMonitorCommand::Unknown89: + // arg = function pointer? + SHIM_SET_RETURN_32(0); + break; + case DebugMonitorCommand::Unknown94: + // xboxkrnl->SendPIXCommand("{EndCapture}"); + SHIM_SET_RETURN_32(0); + break; + default: + SHIM_SET_RETURN_32(-1); + break; + } +} + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe diff --git a/src/xenia/kernel/xboxkrnl/debug_monitor.h b/src/xenia/kernel/xboxkrnl/debug_monitor.h new file mode 100644 index 000000000..38a7581b8 --- /dev/null +++ b/src/xenia/kernel/xboxkrnl/debug_monitor.h @@ -0,0 +1,43 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_KERNEL_XBOXKRNL_DEBUG_MONITOR_H_ +#define XENIA_KERNEL_KERNEL_XBOXKRNL_DEBUG_MONITOR_H_ + +#include + +#include "xenia/base/threading.h" +#include "xenia/cpu/export_resolver.h" +#include "xenia/kernel/kernel_module.h" +#include "xenia/kernel/kernel_state.h" + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +struct X_KEDEBUGMONITORDATA { + xe::be unk_00; // 0x00 + xe::be unk_04; // 0x04 + xe::be unk_08; // 0x08 + xe::be unk_0C; // 0x0C + xe::be unk_10; // 0x10 + xe::be unk_14; // 0x14 + xe::be callback_fn; // 0x18 function + xe::be unk_1C; // 0x1C + xe::be unk_20; // 0x20 Vd graphics data? +}; + +void KeDebugMonitorCallback(cpu::ppc::PPCContext* ppc_context, + kernel::KernelState* kernel_state); + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_KERNEL_DEBUG_MONITOR_H_ diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc index fa1a01bd0..9fca76715 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc @@ -14,17 +14,64 @@ #include #include "xenia/base/clock.h" +#include "xenia/base/debugging.h" #include "xenia/base/logging.h" #include "xenia/base/math.h" +#include "xenia/cpu/ppc/ppc_context.h" +#include "xenia/cpu/processor.h" #include "xenia/emulator.h" #include "xenia/kernel/kernel_state.h" #include "xenia/kernel/user_module.h" +#include "xenia/kernel/xboxkrnl/cert_monitor.h" +#include "xenia/kernel/xboxkrnl/debug_monitor.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" +#include "xenia/kernel/xthread.h" + +DEFINE_bool(kernel_debug_monitor, false, "Enable debug monitor."); +DEFINE_bool(kernel_cert_monitor, false, "Enable cert monitor."); +DEFINE_bool(kernel_pix, false, "Enable PIX."); namespace xe { namespace kernel { namespace xboxkrnl { +bool XboxkrnlModule::SendPIXCommand(const char* cmd) { + if (!FLAGS_kernel_pix) { + return false; + } + + auto global_lock = global_critical_region_.Acquire(); + if (!XThread::IsInThread()) { + assert_always(); + return false; + } + + auto scratch = memory_->SystemHeapAlloc(260 + 260); + + auto response = memory_->TranslateVirtual(scratch + 0); + auto command = memory_->TranslateVirtual(scratch + 260); + + std::snprintf(command, 260, "PIX!m!%s", cmd); + + global_lock.unlock(); + uint64_t args[] = {scratch + 260, scratch, 260}; + auto result = kernel_state_->processor()->Execute( + XThread::GetCurrentThread()->thread_state(), pix_function_, args, + xe::countof(args)); + global_lock.lock(); + + XELOGD("PIX(command): %s", cmd); + XELOGD("PIX(response): %s", response); + + memory_->SystemHeapFree(scratch); + + if (XSUCCEEDED(result)) { + return true; + } + + return false; +} + XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) : KernelModule(kernel_state, "xe:\\xboxkrnl.exe"), timestamp_timer_(nullptr) { @@ -52,19 +99,46 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state) // Set to a valid value when a remote debugger is attached. // Offset 0x18 is a 4b pointer to a handler function that seems to take two // arguments. If we wanted to see what would happen we could fake that. - uint32_t pKeDebugMonitorData = memory_->SystemHeapAlloc(256); - auto lpKeDebugMonitorData = memory_->TranslateVirtual(pKeDebugMonitorData); + uint32_t pKeDebugMonitorData; + if (!FLAGS_kernel_debug_monitor) { + pKeDebugMonitorData = memory_->SystemHeapAlloc(4); + auto lpKeDebugMonitorData = memory_->TranslateVirtual(pKeDebugMonitorData); + xe::store_and_swap(lpKeDebugMonitorData, 0); + } else { + pKeDebugMonitorData = + memory_->SystemHeapAlloc(4 + sizeof(X_KEDEBUGMONITORDATA)); + xe::store_and_swap(memory_->TranslateVirtual(pKeDebugMonitorData), + pKeDebugMonitorData + 4); + auto lpKeDebugMonitorData = + memory_->TranslateVirtual(pKeDebugMonitorData + + 4); + std::memset(lpKeDebugMonitorData, 0, sizeof(X_KEDEBUGMONITORDATA)); + lpKeDebugMonitorData->callback_fn = + GenerateTrampoline("KeDebugMonitorCallback", KeDebugMonitorCallback); + } export_resolver_->SetVariableMapping( "xboxkrnl.exe", ordinals::KeDebugMonitorData, pKeDebugMonitorData); - xe::store_and_swap(lpKeDebugMonitorData, 0); // KeCertMonitorData (?*) // Always set to zero, ignored. - uint32_t pKeCertMonitorData = memory_->SystemHeapAlloc(4); - auto lpKeCertMonitorData = memory_->TranslateVirtual(pKeCertMonitorData); + uint32_t pKeCertMonitorData; + if (!FLAGS_kernel_cert_monitor) { + pKeCertMonitorData = memory_->SystemHeapAlloc(4); + auto lpKeCertMonitorData = memory_->TranslateVirtual(pKeCertMonitorData); + xe::store_and_swap(lpKeCertMonitorData, 0); + } else { + pKeCertMonitorData = + memory_->SystemHeapAlloc(4 + sizeof(X_KECERTMONITORDATA)); + xe::store_and_swap(memory_->TranslateVirtual(pKeCertMonitorData), + pKeCertMonitorData + 4); + auto lpKeCertMonitorData = + memory_->TranslateVirtual(pKeCertMonitorData + 4); + std::memset(lpKeCertMonitorData, 0, sizeof(X_KECERTMONITORDATA)); + lpKeCertMonitorData->callback_fn = + GenerateTrampoline("KeCertMonitorCallback", KeCertMonitorCallback); + } export_resolver_->SetVariableMapping( "xboxkrnl.exe", ordinals::KeCertMonitorData, pKeCertMonitorData); - xe::store_and_swap(lpKeCertMonitorData, 0); // XboxHardwareInfo (XboxHardwareInfo_t, 16b) // flags cpu# ? ? ? ? ? ? diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.h b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.h index 338adb51c..5a817453c 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_module.h +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_module.h @@ -32,6 +32,13 @@ class XboxkrnlModule : public KernelModule { static void RegisterExportTable(xe::cpu::ExportResolver* export_resolver); + bool SendPIXCommand(const char* cmd); + + void set_pix_function(uint32_t addr) { pix_function_ = addr; } + + protected: + uint32_t pix_function_ = 0; + private: std::unique_ptr timestamp_timer_; };