[Kernel] Experimental debug monitor/PIX code.

This commit is contained in:
gibbed 2018-05-23 04:54:26 -05:00
parent 09585eb103
commit 2ef3ea996f
6 changed files with 306 additions and 6 deletions

View File

@ -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 <gflags/gflags.h>
#include <vector>
#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<XboxkrnlModule>("xboxkrnl.exe");
}
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe

View File

@ -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 <memory>
#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<uint32_t> 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_

View File

@ -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 <gflags/gflags.h>
#include <vector>
#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<DebugMonitorCommand>(ppc_context->r[3] & 0xFFFFFFFFu);
auto arg = static_cast<uint32_t>(ppc_context->r[4] & 0xFFFFFFFFu);
XELOGI("KeDebugMonitorCallback(%u, %08x)", static_cast<uint32_t>(id), arg);
if (!FLAGS_kernel_pix) {
SHIM_SET_RETURN_32(-1);
return;
}
auto xboxkrnl = kernel_state->GetKernelModule<XboxkrnlModule>("xboxkrnl.exe");
switch (id) {
case DebugMonitorCommand::PIXCommandResult: {
auto s = kernel_state->memory()->TranslateVirtual<const char*>(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<uint32_t> callback_fn;
xe::be<uint32_t> callback_arg; // D3D device object?
};
auto cbi = kernel_state->memory()->TranslateVirtual<callback_info*>(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

View File

@ -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 <memory>
#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<uint32_t> unk_00; // 0x00
xe::be<uint32_t> unk_04; // 0x04
xe::be<uint32_t> unk_08; // 0x08
xe::be<uint32_t> unk_0C; // 0x0C
xe::be<uint32_t> unk_10; // 0x10
xe::be<uint32_t> unk_14; // 0x14
xe::be<uint32_t> callback_fn; // 0x18 function
xe::be<uint32_t> unk_1C; // 0x1C
xe::be<uint32_t> 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_

View File

@ -14,17 +14,64 @@
#include <vector> #include <vector>
#include "xenia/base/clock.h" #include "xenia/base/clock.h"
#include "xenia/base/debugging.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/base/math.h" #include "xenia/base/math.h"
#include "xenia/cpu/ppc/ppc_context.h"
#include "xenia/cpu/processor.h"
#include "xenia/emulator.h" #include "xenia/emulator.h"
#include "xenia/kernel/kernel_state.h" #include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/user_module.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/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 xe {
namespace kernel { namespace kernel {
namespace xboxkrnl { 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<const char*>(scratch + 0);
auto command = memory_->TranslateVirtual<char*>(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) XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
: KernelModule(kernel_state, "xe:\\xboxkrnl.exe"), : KernelModule(kernel_state, "xe:\\xboxkrnl.exe"),
timestamp_timer_(nullptr) { 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. // 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 // 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. // arguments. If we wanted to see what would happen we could fake that.
uint32_t pKeDebugMonitorData = memory_->SystemHeapAlloc(256); uint32_t pKeDebugMonitorData;
if (!FLAGS_kernel_debug_monitor) {
pKeDebugMonitorData = memory_->SystemHeapAlloc(4);
auto lpKeDebugMonitorData = memory_->TranslateVirtual(pKeDebugMonitorData); auto lpKeDebugMonitorData = memory_->TranslateVirtual(pKeDebugMonitorData);
xe::store_and_swap<uint32_t>(lpKeDebugMonitorData, 0);
} else {
pKeDebugMonitorData =
memory_->SystemHeapAlloc(4 + sizeof(X_KEDEBUGMONITORDATA));
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(pKeDebugMonitorData),
pKeDebugMonitorData + 4);
auto lpKeDebugMonitorData =
memory_->TranslateVirtual<X_KEDEBUGMONITORDATA*>(pKeDebugMonitorData +
4);
std::memset(lpKeDebugMonitorData, 0, sizeof(X_KEDEBUGMONITORDATA));
lpKeDebugMonitorData->callback_fn =
GenerateTrampoline("KeDebugMonitorCallback", KeDebugMonitorCallback);
}
export_resolver_->SetVariableMapping( export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeDebugMonitorData, pKeDebugMonitorData); "xboxkrnl.exe", ordinals::KeDebugMonitorData, pKeDebugMonitorData);
xe::store_and_swap<uint32_t>(lpKeDebugMonitorData, 0);
// KeCertMonitorData (?*) // KeCertMonitorData (?*)
// Always set to zero, ignored. // Always set to zero, ignored.
uint32_t pKeCertMonitorData = memory_->SystemHeapAlloc(4); uint32_t pKeCertMonitorData;
if (!FLAGS_kernel_cert_monitor) {
pKeCertMonitorData = memory_->SystemHeapAlloc(4);
auto lpKeCertMonitorData = memory_->TranslateVirtual(pKeCertMonitorData); auto lpKeCertMonitorData = memory_->TranslateVirtual(pKeCertMonitorData);
xe::store_and_swap<uint32_t>(lpKeCertMonitorData, 0);
} else {
pKeCertMonitorData =
memory_->SystemHeapAlloc(4 + sizeof(X_KECERTMONITORDATA));
xe::store_and_swap<uint32_t>(memory_->TranslateVirtual(pKeCertMonitorData),
pKeCertMonitorData + 4);
auto lpKeCertMonitorData =
memory_->TranslateVirtual<X_KECERTMONITORDATA*>(pKeCertMonitorData + 4);
std::memset(lpKeCertMonitorData, 0, sizeof(X_KECERTMONITORDATA));
lpKeCertMonitorData->callback_fn =
GenerateTrampoline("KeCertMonitorCallback", KeCertMonitorCallback);
}
export_resolver_->SetVariableMapping( export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeCertMonitorData, pKeCertMonitorData); "xboxkrnl.exe", ordinals::KeCertMonitorData, pKeCertMonitorData);
xe::store_and_swap<uint32_t>(lpKeCertMonitorData, 0);
// XboxHardwareInfo (XboxHardwareInfo_t, 16b) // XboxHardwareInfo (XboxHardwareInfo_t, 16b)
// flags cpu# ? ? ? ? ? ? // flags cpu# ? ? ? ? ? ?

View File

@ -32,6 +32,13 @@ class XboxkrnlModule : public KernelModule {
static void RegisterExportTable(xe::cpu::ExportResolver* export_resolver); 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: private:
std::unique_ptr<xe::threading::HighResolutionTimer> timestamp_timer_; std::unique_ptr<xe::threading::HighResolutionTimer> timestamp_timer_;
}; };