diff --git a/TODO.md b/TODO.md index ad2aa05ce..9109c938d 100644 --- a/TODO.md +++ b/TODO.md @@ -9,28 +9,24 @@ Ordered: ``` RtlInitializeCriticalSection/RtlInitializeCriticalSectionAndSpinCount RtlEnterCriticalSection/RtlLeaveCriticalSection -ExGetXConfigSetting -KeTlsAlloc -KeTlsSetValue +NtCreateEvent +NtClose +NtWaitForSingleObjectEx +RtlFreeAnsiString/RtlFreeUnicodeString +RtlUnicodeStringToAnsiString ``` Others: ``` -NtQueryVirtualMemory - -KeTlsAlloc/KeTlsFree/KeTlsGetValue/KeTlsSetValue - +NtCreateEvent NtWaitForSingleObjectEx -RtlInitUnicodeString/RtlFreeUnicodeString -RtlInitAnsiString/RtlFreeAnsiString -RtlUnicodeStringToAnsiString - RtlCompareMemoryUlong RtlNtStatusToDosError RtlRaiseException NtCreateFile/NtOpenFile +NtClose NtReadFile/NtReadFileScatter NtQueryFullAttributesFile NtQueryInformationFile/NtSetInformationFile diff --git a/include/xenia/kernel/xbox.h b/include/xenia/kernel/xbox.h index ecbb233eb..d0c3131f9 100644 --- a/include/xenia/kernel/xbox.h +++ b/include/xenia/kernel/xbox.h @@ -85,6 +85,11 @@ typedef uint32_t X_STATUS; #define X_TLS_OUT_OF_INDEXES UINT32_MAX // (-1) +// Languages. +#define X_LANGUAGE_ENGLISH 1 +#define X_LANGUAGE_JAPANESE 2 + + } // namespace kernel } // namespace xe diff --git a/src/kernel/modules/xam/xam_info.cc b/src/kernel/modules/xam/xam_info.cc index bd5f2f175..160fd59eb 100644 --- a/src/kernel/modules/xam/xam_info.cc +++ b/src/kernel/modules/xam/xam_info.cc @@ -9,6 +9,8 @@ #include "kernel/modules/xam/xam_info.h" +#include + #include "kernel/shim_utils.h" #include "kernel/modules/xam/xam_module.h" @@ -32,6 +34,33 @@ void XGetAVPack_shim( } +void XGetGameRegion_shim( + xe_ppc_state_t* ppc_state, XamState* state) { + XELOGD(XT("XGetGameRegion()")); + + SHIM_SET_RETURN(XEX_REGION_ALL); +} + + +void XGetLanguage_shim( + xe_ppc_state_t* ppc_state, XamState* state) { + XELOGD(XT("XGetLanguage()")); + + uint32_t desired_language = X_LANGUAGE_ENGLISH; + + // Switch the language based on game region. + // TODO(benvanik): pull from xex header. + uint32_t game_region = XEX_REGION_NTSCU; + if (game_region & XEX_REGION_NTSCU) { + desired_language = X_LANGUAGE_ENGLISH; + } else if (game_region & XEX_REGION_NTSCJ) { + desired_language = X_LANGUAGE_JAPANESE; + } + // Add more overrides? + + SHIM_SET_RETURN(desired_language); +} + } @@ -42,6 +71,8 @@ void xe::kernel::xam::RegisterInfoExports( state, (xe_kernel_export_shim_fn)shim, (xe_kernel_export_impl_fn)impl) SHIM_SET_MAPPING(0x000003CB, XGetAVPack_shim, NULL); + SHIM_SET_MAPPING(0x000003CC, XGetGameRegion_shim, NULL); + SHIM_SET_MAPPING(0x000003CD, XGetLanguage_shim, NULL); #undef SET_MAPPING } diff --git a/src/kernel/modules/xboxkrnl/objects/xthread.cc b/src/kernel/modules/xboxkrnl/objects/xthread.cc index 825665079..da955d4db 100644 --- a/src/kernel/modules/xboxkrnl/objects/xthread.cc +++ b/src/kernel/modules/xboxkrnl/objects/xthread.cc @@ -43,7 +43,7 @@ XThread::XThread(KernelState* kernel_state, } XThread::~XThread() { - // TODO(benvanik): if executing, kill it? + PlatformDestroy(); if (processor_state_) { kernel_state()->processor()->DeallocThread(processor_state_); @@ -156,6 +156,11 @@ X_STATUS XThread::PlatformCreate() { return X_STATUS_SUCCESS; } +void XThread::PlatformDestroy() { + CloseHandle(reinterpret_cast(thread_handle_)); + thread_handle_ = NULL; +} + X_STATUS XThread::PlatformExit(int exit_code) { // NOTE: does not return. ExitThread(exit_code); @@ -207,6 +212,10 @@ X_STATUS XThread::PlatformCreate() { } } +void XThread::PlatformDestroy() { + // No-op? +} + X_STATUS XThread::PlatformExit(int exit_code) { // NOTE: does not return. pthread_exit((void*)exit_code); diff --git a/src/kernel/modules/xboxkrnl/objects/xthread.h b/src/kernel/modules/xboxkrnl/objects/xthread.h index 69dacb05e..7a43ec45d 100644 --- a/src/kernel/modules/xboxkrnl/objects/xthread.h +++ b/src/kernel/modules/xboxkrnl/objects/xthread.h @@ -40,6 +40,7 @@ public: private: X_STATUS PlatformCreate(); + void PlatformDestroy(); X_STATUS PlatformExit(int exit_code); struct { diff --git a/src/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc b/src/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc index 8e2eb23bb..a6a5a78df 100644 --- a/src/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc +++ b/src/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc @@ -23,60 +23,6 @@ using namespace xe::kernel::xboxkrnl; namespace { -void RtlImageXexHeaderField_shim( - xe_ppc_state_t* ppc_state, KernelState* state) { - // PVOID - // PVOID XexHeaderBase - // DWORD ImageField - - uint32_t xex_header_base = SHIM_GET_ARG_32(0); - uint32_t image_field = SHIM_GET_ARG_32(1); - - // NOTE: this is totally faked! - // We set the XexExecutableModuleHandle pointer to a block that has at offset - // 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match - // then die. - // The only ImageField I've seen in the wild is - // 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support. - - XELOGD( - XT("RtlImageXexHeaderField(%.8X, %.8X)"), - xex_header_base, image_field); - - if (xex_header_base != 0x80101100) { - XELOGE(XT("RtlImageXexHeaderField with non-magic base NOT IMPLEMENTED")); - SHIM_SET_RETURN(0); - return; - } - - // TODO(benvanik): pull from xex header - // module = GetExecutableModule() || (user defined one) - // header = module->xex_header() - // for (n = 0; n < header->header_count; n++) { - // if (header->headers[n].key == ImageField) { - // return value? or offset? - // } - // } - - uint32_t return_value = 0; - switch (image_field) { - case XEX_HEADER_DEFAULT_HEAP_SIZE: - // TODO(benvanik): pull from running module - // This is header->exe_heap_size. - //SHIM_SET_MEM_32(0x80101104, [some value]); - //return_value = 0x80101104; - return_value = 0; - break; - default: - XELOGE(XT("RtlImageXexHeaderField header field %.8X NOT IMPLEMENTED"), - image_field); - SHIM_SET_RETURN(0); - return; - } - - SHIM_SET_RETURN(return_value); -} - // http://msdn.microsoft.com/en-us/library/ff561778 void RtlCompareMemory_shim( xe_ppc_state_t* ppc_state, KernelState* state) { @@ -178,6 +124,186 @@ void RtlFillMemoryUlong_shim( } +// typedef struct _STRING { +// USHORT Length; +// USHORT MaximumLength; +// PCHAR Buffer; +// } ANSI_STRING, *PANSI_STRING; + + +// http://msdn.microsoft.com/en-us/library/ff561918 +void RtlInitAnsiString_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // VOID + // _Out_ PANSI_STRING DestinationString, + // _In_opt_ PCSZ SourceString + + uint32_t destination_ptr = SHIM_GET_ARG_32(0); + uint32_t source_ptr = SHIM_GET_ARG_32(1); + + const char* source = source_ptr ? (char*)SHIM_MEM_ADDR(source_ptr) : NULL; + XELOGD(XT("RtlInitAnsiString(%.8X, %.8X = %s)"), + destination_ptr, source_ptr, source ? source : ""); + + uint16_t length = source ? (uint16_t)xestrlena(source) : 0; + SHIM_SET_MEM_16(destination_ptr + 0, length * 2); + SHIM_SET_MEM_16(destination_ptr + 2, length * 2); + SHIM_SET_MEM_32(destination_ptr + 4, source_ptr); +} + + +// http://msdn.microsoft.com/en-us/library/ff561899 +void RtlFreeAnsiString_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // VOID + // _Inout_ PANSI_STRING AnsiString + + uint32_t string_ptr = SHIM_GET_ARG_32(0); + + XELOGD(XT("RtlFreeAnsiString(%.8X)"), string_ptr); + + //uint32_t buffer = SHIM_MEM_32(string_ptr + 4); + // TODO(benvanik): free the buffer + XELOGE(XT("RtlFreeAnsiString leaking buffer")); + + SHIM_SET_MEM_16(string_ptr + 0, 0); + SHIM_SET_MEM_16(string_ptr + 2, 0); + SHIM_SET_MEM_32(string_ptr + 4, 0); +} + + +// typedef struct _UNICODE_STRING { +// USHORT Length; +// USHORT MaximumLength; +// PWSTR Buffer; +// } UNICODE_STRING, *PUNICODE_STRING; + + +// http://msdn.microsoft.com/en-us/library/ff561934 +void RtlInitUnicodeString_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // VOID + // _Out_ PUNICODE_STRING DestinationString, + // _In_opt_ PCWSTR SourceString + + uint32_t destination_ptr = SHIM_GET_ARG_32(0); + uint32_t source_ptr = SHIM_GET_ARG_32(1); + + const wchar_t* source = + source_ptr ? (const wchar_t*)SHIM_MEM_ADDR(source_ptr) : NULL; + XELOGD(XT("RtlInitUnicodeString(%.8X, %.8X = %ls)"), + destination_ptr, source_ptr, source ? source : L""); + + uint16_t length = source ? (uint16_t)xestrlenw(source) : 0; + SHIM_SET_MEM_16(destination_ptr + 0, length * 2); + SHIM_SET_MEM_16(destination_ptr + 2, length * 2); + SHIM_SET_MEM_32(destination_ptr + 4, source_ptr); +} + + +// http://msdn.microsoft.com/en-us/library/ff561903 +void RtlFreeUnicodeString_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // VOID + // _Inout_ PUNICODE_STRING UnicodeString + + uint32_t string_ptr = SHIM_GET_ARG_32(0); + + XELOGD(XT("RtlFreeUnicodeString(%.8X)"), string_ptr); + + //uint32_t buffer = SHIM_MEM_32(string_ptr + 4); + // TODO(benvanik): free the buffer + XELOGE(XT("RtlFreeUnicodeString leaking buffer")); + + SHIM_SET_MEM_16(string_ptr + 0, 0); + SHIM_SET_MEM_16(string_ptr + 2, 0); + SHIM_SET_MEM_32(string_ptr + 4, 0); +} + + +// http://msdn.microsoft.com/en-us/library/ff562969 +void RtlUnicodeStringToAnsiString_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // NTSTATUS + // _Inout_ PANSI_STRING DestinationString, + // _In_ PCUNICODE_STRING SourceString, + // _In_ BOOLEAN AllocateDestinationString + + uint32_t destination_ptr = SHIM_GET_ARG_32(0); + uint32_t source_ptr = SHIM_GET_ARG_32(1); + uint32_t alloc_dest = SHIM_GET_ARG_32(2); + + XELOGD(XT("RtlUnicodeStringToAnsiString(%.8X, %.8X, %d)"), + destination_ptr, source_ptr, alloc_dest); + + XELOGE(XT("RtlUnicodeStringToAnsiString not yet implemented")); + + if (alloc_dest) { + // Allocate a new buffer to place the string into. + //SHIM_SET_MEM_32(destination_ptr + 4, buffer_ptr); + } else { + // Reuse the buffer in the target. + //uint32_t buffer_size = SHIM_MEM_16(destination_ptr + 2); + } + + SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL); +} + + +void RtlImageXexHeaderField_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + // PVOID + // PVOID XexHeaderBase + // DWORD ImageField + + uint32_t xex_header_base = SHIM_GET_ARG_32(0); + uint32_t image_field = SHIM_GET_ARG_32(1); + + // NOTE: this is totally faked! + // We set the XexExecutableModuleHandle pointer to a block that has at offset + // 0x58 a pointer to our XexHeaderBase. If the value passed doesn't match + // then die. + // The only ImageField I've seen in the wild is + // 0x20401 (XEX_HEADER_DEFAULT_HEAP_SIZE), so that's all we'll support. + + XELOGD( + XT("RtlImageXexHeaderField(%.8X, %.8X)"), + xex_header_base, image_field); + + if (xex_header_base != 0x80101100) { + XELOGE(XT("RtlImageXexHeaderField with non-magic base NOT IMPLEMENTED")); + SHIM_SET_RETURN(0); + return; + } + + // TODO(benvanik): pull from xex header + // module = GetExecutableModule() || (user defined one) + // header = module->xex_header() + // for (n = 0; n < header->header_count; n++) { + // if (header->headers[n].key == ImageField) { + // return value? or offset? + // } + // } + + uint32_t return_value = 0; + switch (image_field) { + case XEX_HEADER_DEFAULT_HEAP_SIZE: + // TODO(benvanik): pull from running module + // This is header->exe_heap_size. + //SHIM_SET_MEM_32(0x80101104, [some value]); + //return_value = 0x80101104; + return_value = 0; + break; + default: + XELOGE(XT("RtlImageXexHeaderField header field %.8X NOT IMPLEMENTED"), + image_field); + SHIM_SET_RETURN(0); + return; + } + + SHIM_SET_RETURN(return_value); +} + //RtlInitializeCriticalSection //RtlEnterCriticalSection @@ -196,6 +322,12 @@ void xe::kernel::xboxkrnl::RegisterRtlExports( SHIM_SET_MAPPING(0x0000011B, RtlCompareMemoryUlong_shim, NULL); SHIM_SET_MAPPING(0x00000126, RtlFillMemoryUlong_shim, NULL); + SHIM_SET_MAPPING(0x0000012C, RtlInitAnsiString_shim, NULL); + SHIM_SET_MAPPING(0x00000127, RtlFreeAnsiString_shim, NULL); + SHIM_SET_MAPPING(0x0000012D, RtlInitUnicodeString_shim, NULL); + SHIM_SET_MAPPING(0x00000128, RtlFreeUnicodeString_shim, NULL); + SHIM_SET_MAPPING(0x00000142, RtlUnicodeStringToAnsiString_shim, NULL); + SHIM_SET_MAPPING(0x0000012B, RtlImageXexHeaderField_shim, NULL); #undef SET_MAPPING diff --git a/src/kernel/shim_utils.h b/src/kernel/shim_utils.h index e9333cb35..22ed3b089 100644 --- a/src/kernel/shim_utils.h +++ b/src/kernel/shim_utils.h @@ -24,7 +24,9 @@ namespace kernel { #define SHIM_MEM_ADDR(a) (ppc_state->membase + a) +#define SHIM_MEM_16(a) (uint16_t)XEGETUINT16BE(SHIM_MEM_ADDR(a)); #define SHIM_MEM_32(a) (uint32_t)XEGETUINT32BE(SHIM_MEM_ADDR(a)); +#define SHIM_SET_MEM_16(a, v) (*(uint16_t*)SHIM_MEM_ADDR(a)) = XESWAP16(v) #define SHIM_SET_MEM_32(a, v) (*(uint32_t*)SHIM_MEM_ADDR(a)) = XESWAP32(v) #define SHIM_GPR_32(n) (uint32_t)(ppc_state->r[n])