[Kernel] Experimental debug monitor/PIX code.
This commit is contained in:
parent
09585eb103
commit
2ef3ea996f
|
@ -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
|
|
@ -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_
|
|
@ -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
|
|
@ -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_
|
|
@ -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# ? ? ? ? ? ?
|
||||||
|
|
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue