Directly check PEB for IsDebuggerAttached

Add constexpr getters to magicdiv class so it can be used from jitted x64/dxbc
Track the guest return address as well for guest/host sync, if multiple entries have the same guest stack find the first one with a matching guest retaddr. this fixes epic mickey 2 (which the previous guest-stack change had allowed to go ingame for a bit) and potentially also a crash in fable3.
Break if under debugger when stackpoints are overflowed

Add much more useful output for host exceptions, print out xenia_canary.exe relative offsets if exception is in module, formatmessage for ntstatus/win32err, strerror

Minor d3d12 microoptimization, instead of doing SetEventOnCompletion + WaitForSingleObject do SetEventOnCompletion w/ nullptr so that the wait happens in kernel mode, avoiding two extra context switches

add unimplemented kernel functions:
ExAllocatePoolWithTag
ObReferenceObject

ObDereferenceObject has no return value.
Log a message when ObDereferenceObject/Reference receive unregistered guest kernel objects
gave ObLookupThreadByThreadId its correct error status
hoist object_types initialization out of ObReferenceObjectByHandle
Fix out parameter values on error for a few kernel funcs
add note about msr to KeSetCurrentStackPointers
add X_STATUS_OBJECT_TYPE_MISMATCH check for xeNtSetEvent
add msr_mask field to X_KPCR
This commit is contained in:
chss95cs@gmail.com
2022-12-04 12:38:19 -08:00
parent 1eb61aa9ab
commit a63f424c0a
18 changed files with 412 additions and 105 deletions

View File

@@ -37,14 +37,30 @@ struct XTASK_MESSAGE {
be<uint32_t> unknown_14;
be<uint32_t> task_handle;
};
struct XAM_TASK_ARGS {
be<uint32_t> value1;
be<uint32_t> value2;
// i think there might be another value here, it might be padding
};
static_assert_size(XTASK_MESSAGE, 0x1C);
dword_result_t XamTaskSchedule_entry(lpvoid_t callback,
pointer_t<XTASK_MESSAGE> message,
lpdword_t unknown, lpdword_t handle_ptr) {
dword_t optional_ptr, lpdword_t handle_ptr,
const ppc_context_t& ctx) {
// TODO(gibbed): figure out what this is for
*handle_ptr = 12345;
if (optional_ptr) {
auto option = ctx->TranslateVirtual<XAM_TASK_ARGS*>(optional_ptr);
auto v1 = option->value1;
auto v2 = option->value2; //typically 0?
XELOGI("Got xam task args: v1 = {:08X}, v2 = {:08X}", v1, v2);
}
uint32_t stack_size = kernel_state()->GetExecutableModule()->stack_size();
// Stack must be aligned to 16kb pages

View File

@@ -609,6 +609,10 @@ dword_result_t ExAllocatePoolTypeWithTag_entry(dword_t size, dword_t tag,
return addr;
}
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePoolTypeWithTag, kMemory, kImplemented);
dword_result_t ExAllocatePoolWithTag_entry(dword_t numbytes, dword_t tag) {
return ExAllocatePoolTypeWithTag_entry(numbytes, tag, 0);
}
DECLARE_XBOXKRNL_EXPORT1(ExAllocatePoolWithTag, kMemory, kImplemented);
dword_result_t ExAllocatePool_entry(dword_t size) {
const uint32_t none = 0x656E6F4E; // 'None'

View File

@@ -52,9 +52,11 @@ dword_result_t ObOpenObjectByName_entry(lpunknown_t obj_attributes_ptr,
return result;
}
DECLARE_XBOXKRNL_EXPORT1(ObOpenObjectByName, kNone, kImplemented);
// chrispy: investigate this, pretty certain it does not properly emulate the
// original
dword_result_t ObOpenObjectByPointer_entry(lpvoid_t object_ptr,
lpdword_t out_handle_ptr) {
*out_handle_ptr = 0;
auto object = XObject::GetNativeObject<XObject>(kernel_state(), object_ptr);
if (!object) {
return X_STATUS_UNSUCCESSFUL;
@@ -71,7 +73,8 @@ dword_result_t ObLookupThreadByThreadId_entry(dword_t thread_id,
lpdword_t out_object_ptr) {
auto thread = kernel_state()->GetThreadByID(thread_id);
if (!thread) {
return X_STATUS_NOT_FOUND;
*out_object_ptr = 0;
return X_STATUS_INVALID_PARAMETER;
}
// Retain the object. Will be released in ObDereferenceObject.
@@ -80,16 +83,18 @@ dword_result_t ObLookupThreadByThreadId_entry(dword_t thread_id,
return X_STATUS_SUCCESS;
}
DECLARE_XBOXKRNL_EXPORT1(ObLookupThreadByThreadId, kNone, kImplemented);
// 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}};
dword_result_t ObReferenceObjectByHandle_entry(dword_t handle,
dword_t object_type_ptr,
lpdword_t out_object_ptr) {
// 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}};
// chrispy: gotta preinit this to 0, kernel is expected to do that
*out_object_ptr = 0;
auto object = kernel_state()->object_table()->LookupObject<XObject>(handle);
if (!object) {
return X_STATUS_INVALID_HANDLE;
@@ -132,22 +137,43 @@ dword_result_t ObReferenceObjectByName_entry(lpstring_t name,
}
DECLARE_XBOXKRNL_EXPORT1(ObReferenceObjectByName, kNone, kImplemented);
dword_result_t ObDereferenceObject_entry(dword_t native_ptr) {
void ObDereferenceObject_entry(dword_t native_ptr, const ppc_context_t& ctx) {
// Check if a dummy value from ObReferenceObjectByHandle.
if (native_ptr == 0xDEADF00D) {
return 0;
return;
}
auto object = XObject::GetNativeObject<XObject>(
kernel_state(), kernel_memory()->TranslateVirtual(native_ptr));
if (object) {
object->ReleaseHandle();
}
return 0;
} else {
if (native_ptr) {
XELOGW("Unregistered guest object provided to ObDereferenceObject {:08X}",
native_ptr.value());
}
}
return;
}
DECLARE_XBOXKRNL_EXPORT1(ObDereferenceObject, kNone, kImplemented);
void ObReferenceObject_entry(dword_t native_ptr) {
// Check if a dummy value from ObReferenceObjectByHandle.
auto object = XObject::GetNativeObject<XObject>(
kernel_state(), kernel_memory()->TranslateVirtual(native_ptr));
if (object) {
object->RetainHandle();
} else {
if (native_ptr) {
XELOGW("Unregistered guest object provided to ObReferenceObject {:08X}",
native_ptr.value());
}
}
return;
}
DECLARE_XBOXKRNL_EXPORT1(ObReferenceObject, kNone, kImplemented);
dword_result_t ObCreateSymbolicLink_entry(pointer_t<X_ANSI_STRING> path_ptr,
pointer_t<X_ANSI_STRING> target_ptr) {
auto path = xe::utf8::canonicalize_guest_path(

View File

@@ -237,7 +237,7 @@ void KeSetCurrentStackPointers_entry(lpvoid_t stack_ptr,
auto current_thread = XThread::GetCurrentThread();
auto pcr = context->TranslateVirtualGPR<X_KPCR*>(context->r[13]);
//also supposed to load msr mask, and the current msr with that, and store
thread->stack_alloc_base = stack_alloc_base.value();
thread->stack_base = stack_base.value();
thread->stack_limit = stack_limit.value();
@@ -500,6 +500,10 @@ uint32_t xeNtSetEvent(uint32_t handle, xe::be<uint32_t>* previous_state_ptr) {
auto ev = kernel_state()->object_table()->LookupObject<XEvent>(handle);
if (ev) {
//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);

View File

@@ -70,7 +70,8 @@ struct XAPC {
// Processor Control Region
struct X_KPCR {
xe::be<uint32_t> tls_ptr; // 0x0
uint8_t unk_04[0x2C]; // 0x4
xe::be<uint32_t> msr_mask; // 0x4
uint8_t unk_08[0x28]; // 0x8
xe::be<uint32_t> pcr_ptr; // 0x30
uint8_t unk_34[0x3C]; // 0x34
xe::be<uint32_t> stack_base_ptr; // 0x70 Stack base address (high addr)