Part 2 of kernel cleanup: merging functions into shims.

This commit is contained in:
Ben Vanik 2014-08-16 00:11:24 -07:00
parent 916dc397ab
commit bf48e9fbbd
13 changed files with 594 additions and 1159 deletions

View File

@ -30,8 +30,11 @@ using namespace xe::kernel;
// This is a global object initialized with the XboxkrnlModule.
// It references the current kernel state object that all kernel methods should
// be using to stash their variables.
KernelState* xe::kernel::shared_kernel_state_ = NULL;
namespace xe {
namespace kernel {
KernelState* shared_kernel_state_ = nullptr;
} // namespace kernel
} // namespace xe
KernelState::KernelState(Emulator* emulator) :
emulator_(emulator), memory_(emulator->memory()),

View File

@ -95,13 +95,6 @@ private:
};
// This is a global object initialized with the KernelState ctor.
// It references the current kernel state object that all kernel methods should
// be using to stash their variables.
// This sucks, but meh.
extern KernelState* shared_kernel_state_;
} // namespace kernel
} // namespace xe

View File

@ -59,16 +59,6 @@ using PPCContext = alloy::frontend::ppc::PPCContext;
#define SHIM_SET_RETURN_64(v) SHIM_SET_GPR_64(3, v)
#define IMPL_MEM_ADDR(a) (a ? state->memory()->Translate(a) : nullptr)
#define IMPL_MEM_8(a) poly::load_and_swap<uint8_t>(IMPL_MEM_ADDR(a))
#define IMPL_MEM_16(a) poly::load_and_swap<uint16_t>(IMPL_MEM_ADDR(a))
#define IMPL_MEM_32(a) poly::load_and_swap<uint32_t>(IMPL_MEM_ADDR(a))
#define IMPL_SET_MEM_8(a, v) poly::store_and_swap<uint8_t>(IMPL_MEM_ADDR(a), v)
#define IMPL_SET_MEM_16(a, v) poly::store_and_swap<uint16_t>(IMPL_MEM_ADDR(a), v)
#define IMPL_SET_MEM_32(a, v) poly::store_and_swap<uint32_t>(IMPL_MEM_ADDR(a), v)
} // namespace kernel
} // namespace xe

View File

@ -23,13 +23,13 @@ using namespace xe::kernel::xam;
namespace xe {
namespace kernel {
// TODO(benvanik): actually check to see if these are the same.
void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap);
SHIM_CALL XGetVideoMode_shim(
PPCContext* ppc_state, KernelState* state) {
void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode);
SHIM_CALL XGetVideoMode_shim(PPCContext* ppc_state, KernelState* state) {
uint32_t video_mode_ptr = SHIM_GET_ARG_32(0);
X_VIDEO_MODE* video_mode = (X_VIDEO_MODE*)SHIM_MEM_ADDR(video_mode_ptr);
xeVdQueryVideoMode(video_mode, true);
xeVdQueryVideoMode(video_mode);
}

View File

@ -244,14 +244,10 @@ SHIM_CALL DbgPrint_shim(
}
void xeDbgBreakPoint() {
DebugBreak();
}
SHIM_CALL DbgBreakPoint_shim(
PPCContext* ppc_state, KernelState* state) {
XELOGD("DbgBreakPoint()");
DebugBreak();
}

View File

@ -24,9 +24,13 @@ namespace xe {
namespace kernel {
void xeHalReturnToFirmware(uint32_t routine) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL HalReturnToFirmware_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t routine = SHIM_GET_ARG_32(0);
XELOGD(
"HalReturnToFirmware(%d)",
routine);
// void
// IN FIRMWARE_REENTRY Routine
@ -41,18 +45,6 @@ void xeHalReturnToFirmware(uint32_t routine) {
}
SHIM_CALL HalReturnToFirmware_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t routine = SHIM_GET_ARG_32(0);
XELOGD(
"HalReturnToFirmware(%d)",
routine);
xeHalReturnToFirmware(routine);
}
} // namespace kernel
} // namespace xe

View File

@ -25,12 +25,21 @@ namespace xe {
namespace kernel {
X_STATUS xeNtAllocateVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t allocation_type, uint32_t protect_bits,
uint32_t unknown) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL NtAllocateVirtualMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_addr_ptr = SHIM_GET_ARG_32(0);
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr);
uint32_t region_size_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
uint32_t allocation_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
uint32_t unknown = SHIM_GET_ARG_32(4);
XELOGD(
"NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)",
base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value,
allocation_type, protect_bits, unknown);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
@ -48,117 +57,59 @@ X_STATUS xeNtAllocateVirtualMemory(
// it's simple today we could extend it to do better things in the future.
// Must request a size.
if (!*region_size_ptr) {
return X_STATUS_INVALID_PARAMETER;
if (!region_size_value) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
// Check allocation type.
if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) {
return X_STATUS_INVALID_PARAMETER;
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
// If MEM_RESET is set only MEM_RESET can be set.
if (allocation_type & X_MEM_RESET && (allocation_type & ~X_MEM_RESET)) {
return X_STATUS_INVALID_PARAMETER;
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
// Don't allow games to set execute bits.
if (protect_bits & (X_PAGE_EXECUTE | X_PAGE_EXECUTE_READ |
X_PAGE_EXECUTE_READWRITE | X_PAGE_EXECUTE_WRITECOPY)) {
return X_STATUS_ACCESS_DENIED;
SHIM_SET_RETURN_32(X_STATUS_ACCESS_DENIED);
return;
}
// Adjust size.
uint32_t adjusted_size = *region_size_ptr;
uint32_t adjusted_size = region_size_value;
// TODO(benvanik): adjust based on page size flags/etc?
// TODO(benvanik): support different allocation types.
// Right now we treat everything as a commit and ignore allocations that have
// already happened.
if (*base_addr_ptr) {
if (base_addr_value) {
// Having a pointer already means that this is likely a follow-on COMMIT.
assert_true(!(allocation_type & X_MEM_RESERVE) &&
(allocation_type & X_MEM_COMMIT));
return X_STATUS_SUCCESS;
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, adjusted_size);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
return;
}
// Allocate.
uint32_t flags = (allocation_type & X_MEM_NOZERO);
uint32_t addr = (uint32_t)state->memory()->HeapAlloc(
*base_addr_ptr, adjusted_size, flags);
base_addr_value, adjusted_size, flags);
if (!addr) {
// Failed - assume no memory available.
return X_STATUS_NO_MEMORY;
SHIM_SET_RETURN_32(X_STATUS_NO_MEMORY);
return;
}
// Stash back.
// Maybe set X_STATUS_ALREADY_COMMITTED if MEM_COMMIT?
*base_addr_ptr = addr;
*region_size_ptr = adjusted_size;
return X_STATUS_SUCCESS;
}
SHIM_CALL NtAllocateVirtualMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_addr_ptr = SHIM_GET_ARG_32(0);
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr);
uint32_t region_size_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
uint32_t allocation_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
uint32_t unknown = SHIM_GET_ARG_32(4);
XELOGD(
"NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)",
base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value,
allocation_type, protect_bits, unknown);
X_STATUS result = xeNtAllocateVirtualMemory(
&base_addr_value, &region_size_value,
allocation_type, protect_bits, unknown);
if (XSUCCEEDED(result)) {
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, region_size_value);
}
SHIM_SET_RETURN_32(result);
}
X_STATUS xeNtFreeVirtualMemory(
uint32_t* base_addr_ptr, uint32_t* region_size_ptr,
uint32_t free_type, uint32_t unknown) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
// _Inout_ PSIZE_T RegionSize,
// _In_ ULONG FreeType
// ? handle?
// I've only seen zero.
assert_true(unknown == 0);
if (!*base_addr_ptr) {
return X_STATUS_MEMORY_NOT_ALLOCATED;
}
// TODO(benvanik): ignore decommits for now.
if (free_type == X_MEM_DECOMMIT) {
return X_STATUS_SUCCESS;
}
// Free.
uint32_t flags = 0;
uint32_t freed_size = state->memory()->HeapFree(
*base_addr_ptr, flags);
if (!freed_size) {
return X_STATUS_UNSUCCESSFUL;
}
// Stash back.
*region_size_ptr = freed_size;
return X_STATUS_SUCCESS;
SHIM_SET_MEM_32(base_addr_ptr, addr);
SHIM_SET_MEM_32(region_size_ptr, adjusted_size);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@ -178,28 +129,55 @@ SHIM_CALL NtFreeVirtualMemory_shim(
region_size_ptr, region_size_value,
free_type, unknown);
X_STATUS result = xeNtFreeVirtualMemory(
&base_addr_value, &region_size_value,
free_type, unknown);
// NTSTATUS
// _Inout_ PVOID *BaseAddress,
// _Inout_ PSIZE_T RegionSize,
// _In_ ULONG FreeType
// ? handle?
if (XSUCCEEDED(result)) {
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, region_size_value);
// I've only seen zero.
assert_true(unknown == 0);
if (!base_addr_value) {
SHIM_SET_RETURN_32(X_STATUS_MEMORY_NOT_ALLOCATED);
return;
}
SHIM_SET_RETURN_32(result);
// TODO(benvanik): ignore decommits for now.
if (free_type == X_MEM_DECOMMIT) {
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
return;
}
// Free.
uint32_t flags = 0;
uint32_t freed_size = state->memory()->HeapFree(
base_addr_value, flags);
if (!freed_size) {
SHIM_SET_RETURN_32(X_STATUS_UNSUCCESSFUL);
return;
}
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, freed_size);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
SHIM_CALL NtQueryVirtualMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
uint32_t memory_basic_information_ptr = SHIM_GET_ARG_32(1);
X_MEMORY_BASIC_INFORMATION *memory_basic_information = (X_MEMORY_BASIC_INFORMATION*)SHIM_MEM_ADDR(memory_basic_information_ptr);
X_STATUS xeNtQueryVirtualMemory(
uint32_t base_address, X_MEMORY_BASIC_INFORMATION *memory_basic_information, bool swap) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XELOGD(
"NtQueryVirtualMemory(%.8X, %.8X)",
base_address, memory_basic_information_ptr);
MEMORY_BASIC_INFORMATION mem_info;
size_t result = state->memory()->QueryInformation(base_address, &mem_info);
if (!result) {
return STATUS_INVALID_PARAMETER;
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER);
return;
}
auto membase = state->memory()->membase();
@ -214,7 +192,7 @@ X_STATUS xeNtQueryVirtualMemory(
memory_basic_information->protect = mem_info.Protect;
memory_basic_information->type = mem_info.Type;
if (swap) {
// TODO(benvanik): auto swap structure.
memory_basic_information->base_address =
poly::byte_swap(memory_basic_information->base_address);
memory_basic_information->allocation_base =
@ -229,34 +207,26 @@ X_STATUS xeNtQueryVirtualMemory(
poly::byte_swap(memory_basic_information->protect);
memory_basic_information->type =
poly::byte_swap(memory_basic_information->type);
}
XELOGE("NtQueryVirtualMemory NOT IMPLEMENTED");
return X_STATUS_SUCCESS;
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
SHIM_CALL NtQueryVirtualMemory_shim(
SHIM_CALL MmAllocatePhysicalMemoryEx_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
uint32_t memory_basic_information_ptr = SHIM_GET_ARG_32(1);
X_MEMORY_BASIC_INFORMATION *memory_basic_information = (X_MEMORY_BASIC_INFORMATION*)SHIM_MEM_ADDR(memory_basic_information_ptr);
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t region_size = SHIM_GET_ARG_32(1);
uint32_t protect_bits = SHIM_GET_ARG_32(2);
uint32_t min_addr_range = SHIM_GET_ARG_32(3);
uint32_t max_addr_range = SHIM_GET_ARG_32(4);
uint32_t alignment = SHIM_GET_ARG_32(5);
XELOGD(
"NtQueryVirtualMemory(%.8X, %.8X)",
base_address, memory_basic_information_ptr);
X_STATUS result = xeNtQueryVirtualMemory(base_address, memory_basic_information, true);
SHIM_SET_RETURN_32(result);
}
uint32_t xeMmAllocatePhysicalMemoryEx(
uint32_t type, uint32_t region_size, uint32_t protect_bits,
uint32_t min_addr_range, uint32_t max_addr_range, uint32_t alignment) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
"MmAllocatePhysicalMemoryEx(%d, %.8X, %.8X, %.8X, %.8X, %.8X)",
type, region_size, protect_bits,
min_addr_range, max_addr_range, alignment);
// Type will usually be 0 (user request?), where 1 and 2 are sometimes made
// by D3D/etc.
@ -264,7 +234,8 @@ uint32_t xeMmAllocatePhysicalMemoryEx(
// Check protection bits.
if (!(protect_bits & (X_PAGE_READONLY | X_PAGE_READWRITE))) {
XELOGE("MmAllocatePhysicalMemoryEx: bad protection bits");
return 0;
SHIM_SET_RETURN_32(0);
return;
}
// Either may be OR'ed into protect_bits:
@ -302,7 +273,8 @@ uint32_t xeMmAllocatePhysicalMemoryEx(
0, adjusted_size, flags, adjusted_alignment);
if (!base_address) {
// Failed - assume no memory available.
return 0;
SHIM_SET_RETURN_32(0);
return;
}
// Move the address into the right range.
@ -315,35 +287,18 @@ uint32_t xeMmAllocatePhysicalMemoryEx(
//}
base_address += 0xA0000000;
return base_address;
}
SHIM_CALL MmAllocatePhysicalMemoryEx_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t region_size = SHIM_GET_ARG_32(1);
uint32_t protect_bits = SHIM_GET_ARG_32(2);
uint32_t min_addr_range = SHIM_GET_ARG_32(3);
uint32_t max_addr_range = SHIM_GET_ARG_32(4);
uint32_t alignment = SHIM_GET_ARG_32(5);
XELOGD(
"MmAllocatePhysicalMemoryEx(%d, %.8X, %.8X, %.8X, %.8X, %.8X)",
type, region_size, protect_bits,
min_addr_range, max_addr_range, alignment);
uint32_t base_address = xeMmAllocatePhysicalMemoryEx(
type, region_size, protect_bits,
min_addr_range, max_addr_range, alignment);
SHIM_SET_RETURN_32(base_address);
}
void xeMmFreePhysicalMemory(uint32_t type, uint32_t base_address) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL MmFreePhysicalMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t base_address = SHIM_GET_ARG_32(1);
XELOGD(
"MmFreePhysicalAddress(%d, %.8X)",
type, base_address);
// base_address = result of MmAllocatePhysicalMemory.
@ -358,29 +313,6 @@ void xeMmFreePhysicalMemory(uint32_t type, uint32_t base_address) {
}
SHIM_CALL MmFreePhysicalMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t type = SHIM_GET_ARG_32(0);
uint32_t base_address = SHIM_GET_ARG_32(1);
XELOGD(
"MmFreePhysicalAddress(%d, %.8X)",
type, base_address);
xeMmFreePhysicalMemory(type, base_address);
}
uint32_t xeMmQueryAddressProtect(uint32_t base_address) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
uint32_t access = state->memory()->QueryProtect(base_address);
return access;
}
SHIM_CALL MmQueryAddressProtect_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
@ -389,19 +321,9 @@ SHIM_CALL MmQueryAddressProtect_shim(
"MmQueryAddressProtect(%.8X)",
base_address);
uint32_t result = xeMmQueryAddressProtect(base_address);
uint32_t access = state->memory()->QueryProtect(base_address);
SHIM_SET_RETURN_32(result);
}
uint32_t xeMmQueryAllocationSize(uint32_t base_address) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
size_t size = state->memory()->QuerySize(base_address);
return (uint32_t)size;
SHIM_SET_RETURN_32(access);
}
@ -413,9 +335,9 @@ SHIM_CALL MmQueryAllocationSize_shim(
"MmQueryAllocationSize(%.8X)",
base_address);
uint32_t result = xeMmQueryAllocationSize(base_address);
size_t size = state->memory()->QuerySize(base_address);
SHIM_SET_RETURN_32(result);
SHIM_SET_RETURN_32(static_cast<uint32_t>(size));
}
@ -427,7 +349,7 @@ SHIM_CALL MmQueryStatistics_shim(
"MmQueryStatistics(%.8X)",
stats_ptr);
uint32_t size = SHIM_MEM_32(stats_ptr + 0);
uint32_t size = SHIM_MEM_32(stats_ptr + 0);
if (size != 104) {
SHIM_SET_RETURN_32(X_STATUS_BUFFER_TOO_SMALL);
return;
@ -475,7 +397,14 @@ uint32_t size = SHIM_MEM_32(stats_ptr + 0);
// http://msdn.microsoft.com/en-us/library/windows/hardware/ff554547(v=vs.85).aspx
uint32_t xeMmGetPhysicalAddress(uint32_t base_address) {
SHIM_CALL MmGetPhysicalAddress_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
XELOGD(
"MmGetPhysicalAddress(%.8X)",
base_address);
// PHYSICAL_ADDRESS MmGetPhysicalAddress(
// _In_ PVOID BaseAddress
// );
@ -493,21 +422,7 @@ uint32_t xeMmGetPhysicalAddress(uint32_t base_address) {
base_address |= 0xE0000000;
}*/
return base_address;
}
SHIM_CALL MmGetPhysicalAddress_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);
XELOGD(
"MmGetPhysicalAddress(%.8X)",
base_address);
uint32_t result = xeMmGetPhysicalAddress(base_address);
SHIM_SET_RETURN_32(result);
SHIM_SET_RETURN_32(base_address);
}
@ -536,7 +451,6 @@ SHIM_CALL ExAllocatePoolTypeWithTag_shim(
}
SHIM_CALL ExFreePool_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t base_address = SHIM_GET_ARG_32(0);

View File

@ -133,9 +133,13 @@ SHIM_CALL ExGetXConfigSetting_shim(
}
int xeXexCheckExecutablePriviledge(uint32_t privilege) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL XexCheckExecutablePrivilege_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t privilege = SHIM_GET_ARG_32(0);
XELOGD(
"XexCheckExecutablePrivilege(%.8X)",
privilege);
// BOOL
// DWORD Privilege
@ -146,7 +150,8 @@ int xeXexCheckExecutablePriviledge(uint32_t privilege) {
XUserModule* module = state->GetExecutableModule();
if (!module) {
return 0;
SHIM_SET_RETURN_32(0);
return;
}
xe_xex2_ref xex = module->xex();
@ -156,47 +161,10 @@ int xeXexCheckExecutablePriviledge(uint32_t privilege) {
xe_xex2_release(xex);
module->Release();
return result;
}
SHIM_CALL XexCheckExecutablePrivilege_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t privilege = SHIM_GET_ARG_32(0);
XELOGD(
"XexCheckExecutablePrivilege(%.8X)",
privilege);
int result = xeXexCheckExecutablePriviledge(privilege);
SHIM_SET_RETURN_32(result);
}
int xeXexGetModuleHandle(const char* module_name,
X_HANDLE* module_handle_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// BOOL
// LPCSZ ModuleName
// LPHMODULE ModuleHandle
XModule* module = state->GetModule(module_name);
if (!module) {
return 0;
}
// NOTE: we don't retain the handle for return.
*module_handle_ptr = module->handle();
module->Release();
return 1;
}
SHIM_CALL XexGetModuleHandle_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t module_name_ptr = SHIM_GET_ARG_32(0);
@ -207,11 +175,18 @@ SHIM_CALL XexGetModuleHandle_shim(
"XexGetModuleHandle(%s, %.8X)",
module_name, module_handle_ptr);
X_HANDLE module_handle = 0;
int result = xeXexGetModuleHandle(module_name, &module_handle);
SHIM_SET_MEM_32(module_handle_ptr, module_handle);
XModule* module = state->GetModule(module_name);
if (!module) {
SHIM_SET_RETURN_32(X_ERROR_NOT_FOUND);
return;
}
SHIM_SET_RETURN_32(result);
// NOTE: we don't retain the handle for return.
SHIM_SET_MEM_32(module_handle_ptr, module->handle());
module->Release();
SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

View File

@ -27,45 +27,24 @@ namespace xe {
namespace kernel {
//RtlCompareMemory
struct x {
};
struct RtlCompareMemoryExport {
KernelState* state;
static void Call(PPCContext* ppc_state) {
uint32_t source1 = SHIM_GET_ARG_32(0);
uint32_t source2 = SHIM_GET_ARG_32(1);
// http://msdn.microsoft.com/en-us/library/ff561778
SHIM_CALL RtlCompareMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t source1_ptr = SHIM_GET_ARG_32(0);
uint32_t source2_ptr = SHIM_GET_ARG_32(1);
uint32_t length = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemory(%.8X, %.8X, %d)",
source1, source2, length);
uint32_t result = 0;
SHIM_SET_RETURN_64(result);
}
virtual void Log() {
//
}
X_STATUS RtlCompareMemory(uint32_t source1_ptr, uint32_t source2_ptr, uint32_t length) {
}
};
// http://msdn.microsoft.com/en-us/library/ff561778
uint32_t xeRtlCompareMemory(uint32_t source1_ptr, uint32_t source2_ptr,
uint32_t length) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
source1_ptr, source2_ptr, length);
// SIZE_T
// _In_ const VOID *Source1,
// _In_ const VOID *Source2,
// _In_ SIZE_T Length
uint8_t* p1 = IMPL_MEM_ADDR(source1_ptr);
uint8_t* p2 = IMPL_MEM_ADDR(source2_ptr);
uint8_t* p1 = SHIM_MEM_ADDR(source1_ptr);
uint8_t* p2 = SHIM_MEM_ADDR(source2_ptr);
// Note that the return value is the number of bytes that match, so it's best
// we just do this ourselves vs. using memcmp.
@ -78,30 +57,20 @@ uint32_t xeRtlCompareMemory(uint32_t source1_ptr, uint32_t source2_ptr,
}
}
return c;
}
SHIM_CALL RtlCompareMemory_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t source1 = SHIM_GET_ARG_32(0);
uint32_t source2 = SHIM_GET_ARG_32(1);
uint32_t length = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemory(%.8X, %.8X, %d)",
source1, source2, length);
uint32_t result = xeRtlCompareMemory(source1, source2, length);
SHIM_SET_RETURN_64(result);
SHIM_SET_RETURN_64(c);
}
// http://msdn.microsoft.com/en-us/library/ff552123
uint32_t xeRtlCompareMemoryUlong(uint32_t source_ptr, uint32_t length,
uint32_t pattern) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL RtlCompareMemoryUlong_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t source_ptr = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemoryUlong(%.8X, %d, %.8X)",
source_ptr, length, pattern);
// SIZE_T
// _In_ PVOID Source,
@ -109,10 +78,11 @@ uint32_t xeRtlCompareMemoryUlong(uint32_t source_ptr, uint32_t length,
// _In_ ULONG Pattern
if ((source_ptr % 4) || (length % 4)) {
return 0;
SHIM_SET_RETURN_64(0);
return;
}
uint8_t* p = IMPL_MEM_ADDR(source_ptr);
uint8_t* p = SHIM_MEM_ADDR(source_ptr);
// Swap pattern.
// TODO(benvanik): ensure byte order of pattern is correct.
@ -128,30 +98,20 @@ uint32_t xeRtlCompareMemoryUlong(uint32_t source_ptr, uint32_t length,
}
}
return c;
}
SHIM_CALL RtlCompareMemoryUlong_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t source = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlCompareMemoryUlong(%.8X, %d, %.8X)",
source, length, pattern);
uint32_t result = xeRtlCompareMemoryUlong(source, length, pattern);
SHIM_SET_RETURN_64(result);
SHIM_SET_RETURN_64(c);
}
// http://msdn.microsoft.com/en-us/library/ff552263
void xeRtlFillMemoryUlong(uint32_t destination_ptr, uint32_t length,
uint32_t pattern) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL RtlFillMemoryUlong_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlFillMemoryUlong(%.8X, %d, %.8X)",
destination_ptr, length, pattern);
// VOID
// _Out_ PVOID Destination,
@ -159,7 +119,7 @@ void xeRtlFillMemoryUlong(uint32_t destination_ptr, uint32_t length,
// _In_ ULONG Pattern
// NOTE: length must be % 4, so we can work on uint32s.
uint32_t* p = (uint32_t*)IMPL_MEM_ADDR(destination_ptr);
uint32_t* p = (uint32_t*)SHIM_MEM_ADDR(destination_ptr);
// TODO(benvanik): ensure byte order is correct - we're writing back the
// swapped arg value.
@ -175,20 +135,6 @@ void xeRtlFillMemoryUlong(uint32_t destination_ptr, uint32_t length,
}
SHIM_CALL RtlFillMemoryUlong_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t destination = SHIM_GET_ARG_32(0);
uint32_t length = SHIM_GET_ARG_32(1);
uint32_t pattern = SHIM_GET_ARG_32(2);
XELOGD(
"RtlFillMemoryUlong(%.8X, %d, %.8X)",
destination, length, pattern);
xeRtlFillMemoryUlong(destination, length, pattern);
}
// typedef struct _STRING {
// USHORT Length;
// USHORT MaximumLength;
@ -197,27 +143,6 @@ SHIM_CALL RtlFillMemoryUlong_shim(
// http://msdn.microsoft.com/en-us/library/ff561918
void xeRtlInitAnsiString(uint32_t destination_ptr, uint32_t source_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// VOID
// _Out_ PANSI_STRING DestinationString,
// _In_opt_ PCSZ SourceString
if (source_ptr != 0) {
const char* source = (char*)IMPL_MEM_ADDR(source_ptr);
uint16_t length = (uint16_t)xestrlena(source);
IMPL_SET_MEM_16(destination_ptr + 0, length);
IMPL_SET_MEM_16(destination_ptr + 2, length + 1);
} else {
IMPL_SET_MEM_16(destination_ptr + 0, 0);
IMPL_SET_MEM_16(destination_ptr + 2, 0);
}
IMPL_SET_MEM_32(destination_ptr + 4, source_ptr);
}
SHIM_CALL RtlInitAnsiString_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
@ -227,38 +152,43 @@ SHIM_CALL RtlInitAnsiString_shim(
XELOGD("RtlInitAnsiString(%.8X, %.8X = %s)",
destination_ptr, source_ptr, source ? source : "<null>");
xeRtlInitAnsiString(destination_ptr, source_ptr);
// VOID
// _Out_ PANSI_STRING DestinationString,
// _In_opt_ PCSZ SourceString
if (source_ptr != 0) {
const char* source = (char*)SHIM_MEM_ADDR(source_ptr);
uint16_t length = (uint16_t)xestrlena(source);
SHIM_SET_MEM_16(destination_ptr + 0, length);
SHIM_SET_MEM_16(destination_ptr + 2, length + 1);
} else {
SHIM_SET_MEM_16(destination_ptr + 0, 0);
SHIM_SET_MEM_16(destination_ptr + 2, 0);
}
SHIM_SET_MEM_32(destination_ptr + 4, source_ptr);
}
// http://msdn.microsoft.com/en-us/library/ff561899
void xeRtlFreeAnsiString(uint32_t string_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// VOID
// _Inout_ PANSI_STRING AnsiString
uint32_t buffer = IMPL_MEM_32(string_ptr + 4);
if (!buffer) {
return;
}
uint32_t length = IMPL_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
IMPL_SET_MEM_16(string_ptr + 0, 0);
IMPL_SET_MEM_16(string_ptr + 2, 0);
IMPL_SET_MEM_32(string_ptr + 4, 0);
}
SHIM_CALL RtlFreeAnsiString_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t string_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlFreeAnsiString(%.8X)", string_ptr);
xeRtlFreeAnsiString(string_ptr);
// VOID
// _Inout_ PANSI_STRING AnsiString
uint32_t buffer = SHIM_MEM_32(string_ptr + 4);
if (!buffer) {
return;
}
uint32_t length = SHIM_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
SHIM_SET_MEM_16(string_ptr + 0, 0);
SHIM_SET_MEM_16(string_ptr + 2, 0);
SHIM_SET_MEM_32(string_ptr + 4, 0);
}
@ -270,30 +200,6 @@ SHIM_CALL RtlFreeAnsiString_shim(
// http://msdn.microsoft.com/en-us/library/ff561934
void xeRtlInitUnicodeString(uint32_t destination_ptr, uint32_t source_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// VOID
// _Out_ PUNICODE_STRING DestinationString,
// _In_opt_ PCWSTR SourceString
const wchar_t* source =
source_ptr ? (const wchar_t*)IMPL_MEM_ADDR(source_ptr) : NULL;
if (source) {
uint16_t length = (uint16_t)xestrlenw(source);
IMPL_SET_MEM_16(destination_ptr + 0, length * 2);
IMPL_SET_MEM_16(destination_ptr + 2, (length + 1) * 2);
IMPL_SET_MEM_32(destination_ptr + 4, source_ptr);
} else {
IMPL_SET_MEM_16(destination_ptr + 0, 0);
IMPL_SET_MEM_16(destination_ptr + 2, 0);
IMPL_SET_MEM_32(destination_ptr + 4, 0);
}
}
SHIM_CALL RtlInitUnicodeString_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
@ -304,85 +210,47 @@ SHIM_CALL RtlInitUnicodeString_shim(
XELOGD("RtlInitUnicodeString(%.8X, %.8X = %ls)",
destination_ptr, source_ptr, source ? source : L"<null>");
xeRtlInitUnicodeString(destination_ptr, source_ptr);
// VOID
// _Out_ PUNICODE_STRING DestinationString,
// _In_opt_ PCWSTR SourceString
if (source) {
uint16_t length = (uint16_t)xestrlenw(source);
SHIM_SET_MEM_16(destination_ptr + 0, length * 2);
SHIM_SET_MEM_16(destination_ptr + 2, (length + 1) * 2);
SHIM_SET_MEM_32(destination_ptr + 4, source_ptr);
} else {
SHIM_SET_MEM_16(destination_ptr + 0, 0);
SHIM_SET_MEM_16(destination_ptr + 2, 0);
SHIM_SET_MEM_32(destination_ptr + 4, 0);
}
}
// http://msdn.microsoft.com/en-us/library/ff561903
void xeRtlFreeUnicodeString(uint32_t string_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// VOID
// _Inout_ PUNICODE_STRING UnicodeString
uint32_t buffer = IMPL_MEM_32(string_ptr + 4);
if (!buffer) {
return;
}
uint32_t length = IMPL_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
IMPL_SET_MEM_16(string_ptr + 0, 0);
IMPL_SET_MEM_16(string_ptr + 2, 0);
IMPL_SET_MEM_32(string_ptr + 4, 0);
}
SHIM_CALL RtlFreeUnicodeString_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t string_ptr = SHIM_GET_ARG_32(0);
XELOGD("RtlFreeUnicodeString(%.8X)", string_ptr);
xeRtlFreeUnicodeString(string_ptr);
// VOID
// _Inout_ PUNICODE_STRING UnicodeString
uint32_t buffer = SHIM_MEM_32(string_ptr + 4);
if (!buffer) {
return;
}
uint32_t length = SHIM_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
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
X_STATUS xeRtlUnicodeStringToAnsiString(uint32_t destination_ptr,
uint32_t source_ptr,
uint32_t alloc_dest) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// NTSTATUS
// _Inout_ PANSI_STRING DestinationString,
// _In_ PCUNICODE_STRING SourceString,
// _In_ BOOLEAN AllocateDestinationString
std::wstring unicode_str = poly::load_and_swap<std::wstring>(
IMPL_MEM_ADDR(IMPL_MEM_32(source_ptr + 4)));
std::string ansi_str = poly::to_string(unicode_str);
if (ansi_str.size() > 0xFFFF - 1) {
return X_STATUS_INVALID_PARAMETER_2;
}
X_STATUS result = X_STATUS_SUCCESS;
if (alloc_dest) {
auto buffer_ptr = state->memory()->HeapAlloc(0, ansi_str.size() + 1, 0);
memcpy(IMPL_MEM_ADDR(buffer_ptr), ansi_str.data(), ansi_str.size() + 1);
IMPL_SET_MEM_16(destination_ptr + 0,
static_cast<uint16_t>(ansi_str.size()));
IMPL_SET_MEM_16(destination_ptr + 2,
static_cast<uint16_t>(ansi_str.size() + 1));
IMPL_SET_MEM_32(destination_ptr + 4, static_cast<uint32_t>(buffer_ptr));
} else {
uint32_t buffer_capacity = IMPL_MEM_16(destination_ptr + 2);
uint32_t buffer_ptr = IMPL_MEM_32(destination_ptr + 4);
if (buffer_capacity < ansi_str.size() + 1) {
// Too large - we just write what we can.
result = X_STATUS_BUFFER_OVERFLOW;
memcpy(IMPL_MEM_ADDR(buffer_ptr), ansi_str.data(), buffer_capacity - 1);
} else {
memcpy(IMPL_MEM_ADDR(buffer_ptr), ansi_str.data(), ansi_str.size() + 1);
}
IMPL_SET_MEM_8(buffer_ptr + buffer_capacity - 1, 0); // \0
}
return result;
}
SHIM_CALL RtlUnicodeStringToAnsiString_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t destination_ptr = SHIM_GET_ARG_32(0);
@ -392,8 +260,40 @@ SHIM_CALL RtlUnicodeStringToAnsiString_shim(
XELOGD("RtlUnicodeStringToAnsiString(%.8X, %.8X, %d)",
destination_ptr, source_ptr, alloc_dest);
X_STATUS result = xeRtlUnicodeStringToAnsiString(
destination_ptr, source_ptr, alloc_dest);
// NTSTATUS
// _Inout_ PANSI_STRING DestinationString,
// _In_ PCUNICODE_STRING SourceString,
// _In_ BOOLEAN AllocateDestinationString
std::wstring unicode_str = poly::load_and_swap<std::wstring>(
SHIM_MEM_ADDR(SHIM_MEM_32(source_ptr + 4)));
std::string ansi_str = poly::to_string(unicode_str);
if (ansi_str.size() > 0xFFFF - 1) {
SHIM_SET_RETURN_32(X_STATUS_INVALID_PARAMETER_2);
return;
}
X_STATUS result = X_STATUS_SUCCESS;
if (alloc_dest) {
auto buffer_ptr = state->memory()->HeapAlloc(0, ansi_str.size() + 1, 0);
memcpy(SHIM_MEM_ADDR(buffer_ptr), ansi_str.data(), ansi_str.size() + 1);
SHIM_SET_MEM_16(destination_ptr + 0,
static_cast<uint16_t>(ansi_str.size()));
SHIM_SET_MEM_16(destination_ptr + 2,
static_cast<uint16_t>(ansi_str.size() + 1));
SHIM_SET_MEM_32(destination_ptr + 4, static_cast<uint32_t>(buffer_ptr));
} else {
uint32_t buffer_capacity = SHIM_MEM_16(destination_ptr + 2);
uint32_t buffer_ptr = SHIM_MEM_32(destination_ptr + 4);
if (buffer_capacity < ansi_str.size() + 1) {
// Too large - we just write what we can.
result = X_STATUS_BUFFER_OVERFLOW;
memcpy(SHIM_MEM_ADDR(buffer_ptr), ansi_str.data(), buffer_capacity - 1);
} else {
memcpy(SHIM_MEM_ADDR(buffer_ptr), ansi_str.data(), ansi_str.size() + 1);
}
SHIM_SET_MEM_8(buffer_ptr + buffer_capacity - 1, 0); // \0
}
SHIM_SET_RETURN_32(result);
}
@ -457,22 +357,6 @@ SHIM_CALL RtlUnicodeToMultiByteN_shim(
}
uint32_t xeRtlNtStatusToDosError(X_STATUS status) {
if (!status || (status & 0x20000000)) {
// Success.
return status;
} else if ((status & 0xF0000000) == 0xD0000000) {
// High bit doesn't matter.
status &= ~0x10000000;
}
// TODO(benvanik): implement lookup table.
XELOGE("RtlNtStatusToDosError lookup NOT IMPLEMENTED");
return 317; // ERROR_MR_MID_NOT_FOUND
}
SHIM_CALL RtlNtStatusToDosError_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t status = SHIM_GET_ARG_32(0);
@ -481,15 +365,39 @@ SHIM_CALL RtlNtStatusToDosError_shim(
"RtlNtStatusToDosError(%.4X)",
status);
uint32_t result = xeRtlNtStatusToDosError(status);
if (!status || (status & 0x20000000)) {
// Success.
SHIM_SET_RETURN_32(0);
return;
} else if ((status & 0xF0000000) == 0xD0000000) {
// High bit doesn't matter.
status &= ~0x10000000;
}
// TODO(benvanik): implement lookup table.
XELOGE("RtlNtStatusToDosError lookup NOT SHIMEMENTED");
uint32_t result = 317; // ERROR_MR_MID_NOT_FOUND
SHIM_SET_RETURN_32(result);
}
uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr,
uint32_t image_field) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL RtlImageXexHeaderField_shim(
PPCContext* ppc_state, KernelState* state) {
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(
"RtlImageXexHeaderField(%.8X, %.8X)",
xex_header_base, image_field);
// PVOID
// PVOID XexHeaderBase
@ -512,34 +420,15 @@ uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr,
const xe_xex2_header_t* xex_header = module->xex_header();
for (size_t n = 0; n < xex_header->header_count; n++) {
if (xex_header->headers[n].key == image_field) {
uint32_t value = xex_header->headers[n].value;
module->Release();
return xex_header->headers[n].value;
SHIM_SET_RETURN_64(value);
return;
}
}
module->Release();
return 0;
}
SHIM_CALL RtlImageXexHeaderField_shim(
PPCContext* ppc_state, KernelState* state) {
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(
"RtlImageXexHeaderField(%.8X, %.8X)",
xex_header_base, image_field);
uint32_t result = xeRtlImageXexHeaderField(xex_header_base, image_field);
SHIM_SET_RETURN_64(result);
SHIM_SET_RETURN_64(0);
}
@ -560,9 +449,8 @@ SHIM_CALL RtlImageXexHeaderField_shim(
// This structure tries to match the one on the 360 as best I can figure out.
// Unfortunately some games have the critical sections pre-initialized in
// their embedded data and InitializeCriticalSection will never be called.
namespace {
#pragma pack(push, 1)
typedef struct {
struct X_RTL_CRITICAL_SECTION {
uint8_t unknown00;
uint8_t spin_count_div_256; // * 256
uint8_t __padding[6];
@ -572,20 +460,14 @@ typedef struct {
int32_t lock_count; // -1 -> 0 on first lock 0x10
uint32_t recursion_count; // 0 -> 1 on first lock 0x14
uint32_t owning_thread_id; // 0 unless locked 0x18
} X_RTL_CRITICAL_SECTION;
};
#pragma pack(pop)
}
static_assert_size(X_RTL_CRITICAL_SECTION, 28);
void xeRtlInitializeCriticalSection(uint32_t cs_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
void xeRtlInitializeCriticalSection(X_RTL_CRITICAL_SECTION* cs) {
// VOID
// _Out_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
cs->unknown00 = 1;
cs->spin_count_div_256 = 0;
cs->lock_count = -1;
@ -600,15 +482,13 @@ SHIM_CALL RtlInitializeCriticalSection_shim(
XELOGD("RtlInitializeCriticalSection(%.8X)", cs_ptr);
xeRtlInitializeCriticalSection(cs_ptr);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
xeRtlInitializeCriticalSection(cs);
}
X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(
uint32_t cs_ptr, uint32_t spin_count) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
X_RTL_CRITICAL_SECTION* cs, uint32_t spin_count) {
// NTSTATUS
// _Out_ LPCRITICAL_SECTION lpCriticalSection,
// _In_ DWORD dwSpinCount
@ -620,7 +500,6 @@ X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(
spin_count_div_256 = 255;
}
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
cs->unknown00 = 1;
cs->spin_count_div_256 = spin_count_div_256;
cs->lock_count = -1;
@ -639,22 +518,18 @@ SHIM_CALL RtlInitializeCriticalSectionAndSpinCount_shim(
XELOGD("RtlInitializeCriticalSectionAndSpinCount(%.8X, %d)",
cs_ptr, spin_count);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
X_STATUS result = xeRtlInitializeCriticalSectionAndSpinCount(
cs_ptr, spin_count);
cs, spin_count);
SHIM_SET_RETURN_32(result);
}
// TODO(benvanik): remove the need for passing in thread_id.
void xeRtlEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
void xeRtlEnterCriticalSection(X_RTL_CRITICAL_SECTION* cs, uint32_t thread_id) {
// VOID
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
uint32_t spin_wait_remaining = cs->spin_count_div_256 * 256;
spin:
if (poly::atomic_inc(&cs->lock_count) != 0) {
@ -693,20 +568,16 @@ SHIM_CALL RtlEnterCriticalSection_shim(
const uint8_t* thread_state_block = ppc_state->membase + ppc_state->r[13];
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
xeRtlEnterCriticalSection(cs_ptr, thread_id);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
xeRtlEnterCriticalSection(cs, thread_id);
}
// TODO(benvanik): remove the need for passing in thread_id.
uint32_t xeRtlTryEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
uint32_t xeRtlTryEnterCriticalSection(X_RTL_CRITICAL_SECTION* cs, uint32_t thread_id) {
// DWORD
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
if (poly::atomic_cas(-1, 0, &cs->lock_count)) {
// Able to steal the lock right away.
cs->owning_thread_id = thread_id;
@ -731,20 +602,16 @@ SHIM_CALL RtlTryEnterCriticalSection_shim(
const uint8_t* thread_state_block = ppc_state->membase + ppc_state->r[13];
uint32_t thread_id = XThread::GetCurrentThreadId(thread_state_block);
uint32_t result = xeRtlTryEnterCriticalSection(cs_ptr, thread_id);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
uint32_t result = xeRtlTryEnterCriticalSection(cs, thread_id);
SHIM_SET_RETURN_64(result);
}
void xeRtlLeaveCriticalSection(uint32_t cs_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
void xeRtlLeaveCriticalSection(X_RTL_CRITICAL_SECTION* cs) {
// VOID
// _Inout_ LPCRITICAL_SECTION lpCriticalSection
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
// Drop recursion count - if we are still not zero'ed return.
uint32_t recursion_count = --cs->recursion_count;
if (recursion_count) {
@ -768,7 +635,8 @@ SHIM_CALL RtlLeaveCriticalSection_shim(
// XELOGD("RtlLeaveCriticalSection(%.8X)", cs_ptr);
xeRtlLeaveCriticalSection(cs_ptr);
auto cs = (X_RTL_CRITICAL_SECTION*)SHIM_MEM_ADDR(cs_ptr);
xeRtlLeaveCriticalSection(cs);
}

View File

@ -14,21 +14,20 @@
#include <xenia/core.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
struct X_RTL_CRITICAL_SECTION;
void xeRtlInitializeCriticalSection(uint32_t cs_ptr);
X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(
uint32_t cs_ptr, uint32_t spin_count);
void xeRtlEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id);
uint32_t xeRtlTryEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id);
void xeRtlLeaveCriticalSection(uint32_t cs_ptr);
void xeRtlInitializeCriticalSection(X_RTL_CRITICAL_SECTION* cs);
X_STATUS xeRtlInitializeCriticalSectionAndSpinCount(X_RTL_CRITICAL_SECTION* cs,
uint32_t spin_count);
void xeRtlEnterCriticalSection(X_RTL_CRITICAL_SECTION* cs, uint32_t thread_id);
uint32_t xeRtlTryEnterCriticalSection(X_RTL_CRITICAL_SECTION* cs,
uint32_t thread_id);
void xeRtlLeaveCriticalSection(X_RTL_CRITICAL_SECTION* cs);
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_RTL_H_

View File

@ -66,44 +66,6 @@ namespace kernel {
// }
X_STATUS xeExCreateThread(
uint32_t* handle_ptr, uint32_t stack_size, uint32_t* thread_id_ptr,
uint32_t xapi_thread_startup,
uint32_t start_address, uint32_t start_context, uint32_t creation_flags) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// DWORD
// LPHANDLE Handle,
// DWORD StackSize,
// LPDWORD ThreadId,
// LPVOID XapiThreadStartup, ?? often 0
// LPVOID StartAddress,
// LPVOID StartContext,
// DWORD CreationFlags // 0x80?
XThread* thread = new XThread(
state, stack_size, xapi_thread_startup, start_address, start_context,
creation_flags);
X_STATUS result_code = thread->Create();
if (XFAILED(result_code)) {
// Failed!
thread->Release();
XELOGE("Thread creation failed: %.8X", result_code);
return result_code;
}
if (handle_ptr) {
*handle_ptr = thread->handle();
}
if (thread_id_ptr) {
*thread_id_ptr = thread->thread_id();
}
return result_code;
}
SHIM_CALL ExCreateThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
@ -124,18 +86,34 @@ SHIM_CALL ExCreateThread_shim(
start_context,
creation_flags);
uint32_t handle;
uint32_t thread_id;
X_STATUS result = xeExCreateThread(
&handle, stack_size, &thread_id, xapi_thread_startup,
start_address, start_context, creation_flags);
// DWORD
// LPHANDLE Handle,
// DWORD StackSize,
// LPDWORD ThreadId,
// LPVOID XapiThreadStartup, ?? often 0
// LPVOID StartAddress,
// LPVOID StartContext,
// DWORD CreationFlags // 0x80?
XThread* thread = new XThread(
state, stack_size, xapi_thread_startup, start_address, start_context,
creation_flags);
X_STATUS result = thread->Create();
if (XFAILED(result)) {
// Failed!
thread->Release();
XELOGE("Thread creation failed: %.8X", result);
SHIM_SET_RETURN_32(result);
return;
}
if (XSUCCEEDED(result)) {
if (handle_ptr) {
SHIM_SET_MEM_32(handle_ptr, handle);
SHIM_SET_MEM_32(handle_ptr, thread->handle());
}
if (thread_id_ptr) {
SHIM_SET_MEM_32(thread_id_ptr, thread_id);
SHIM_SET_MEM_32(thread_id_ptr, thread->thread_id());
}
}
SHIM_SET_RETURN_32(result);
@ -158,24 +136,6 @@ SHIM_CALL ExTerminateThread_shim(
}
X_STATUS xeNtResumeThread(uint32_t handle, uint32_t* out_suspend_count) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
X_STATUS result = X_STATUS_SUCCESS;
XThread* thread = NULL;
result = state->object_table()->GetObject(
handle, (XObject**)&thread);
if (XSUCCEEDED(result)) {
result = thread->Resume(out_suspend_count);
thread->Release();
}
return result;
}
SHIM_CALL NtResumeThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t handle = SHIM_GET_ARG_32(0);
@ -186,8 +146,14 @@ SHIM_CALL NtResumeThread_shim(
handle,
suspend_count_ptr);
XThread* thread = NULL;
X_STATUS result = state->object_table()->GetObject(
handle, (XObject**)&thread);
uint32_t suspend_count;
X_STATUS result = xeNtResumeThread(handle, &suspend_count);
if (XSUCCEEDED(result)) {
result = thread->Resume(&suspend_count);
thread->Release();
}
if (XSUCCEEDED(result)) {
if (suspend_count_ptr) {
SHIM_SET_MEM_32(suspend_count_ptr, suspend_count);
@ -198,34 +164,22 @@ SHIM_CALL NtResumeThread_shim(
}
X_STATUS xeKeResumeThread(void* thread_ptr, uint32_t* out_suspend_count) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
X_STATUS result = X_STATUS_SUCCESS;
XThread* thread = (XThread*)XObject::GetObject(state, thread_ptr);
if (thread) {
result = thread->Resume(out_suspend_count);
}
return result;
}
SHIM_CALL KeResumeThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t thread = SHIM_GET_ARG_32(0);
uint32_t thread_ptr = SHIM_GET_ARG_32(0);
uint32_t suspend_count_ptr = SHIM_GET_ARG_32(1);
XELOGD(
"KeResumeThread(%.8X, %.8X)",
thread,
thread_ptr,
suspend_count_ptr);
void* thread_ptr = SHIM_MEM_ADDR(thread);
X_STATUS result;
XThread* thread = (XThread*)XObject::GetObject(state, SHIM_MEM_ADDR(thread_ptr));
uint32_t suspend_count;
X_STATUS result = xeKeResumeThread(thread_ptr, &suspend_count);
if (thread) {
result = thread->Resume(&suspend_count);
}
if (XSUCCEEDED(result)) {
if (suspend_count_ptr) {
SHIM_SET_MEM_32(suspend_count_ptr, suspend_count);
@ -236,24 +190,6 @@ SHIM_CALL KeResumeThread_shim(
}
X_STATUS xeNtSuspendThread(uint32_t handle, uint32_t* out_suspend_count) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
X_STATUS result = X_STATUS_SUCCESS;
XThread* thread = NULL;
result = state->object_table()->GetObject(
handle, (XObject**)&thread);
if (XSUCCEEDED(result)) {
result = thread->Suspend(out_suspend_count);
thread->Release();
}
return result;
}
SHIM_CALL NtSuspendThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t handle = SHIM_GET_ARG_32(0);
@ -264,8 +200,15 @@ SHIM_CALL NtSuspendThread_shim(
handle,
suspend_count_ptr);
XThread* thread = NULL;
X_STATUS result = state->object_table()->GetObject(
handle, (XObject**)&thread);
uint32_t suspend_count;
X_STATUS result = xeNtSuspendThread(handle, &suspend_count);
if (XSUCCEEDED(result)) {
result = thread->Suspend(&suspend_count);
thread->Release();
}
if (XSUCCEEDED(result)) {
if (suspend_count_ptr) {
SHIM_SET_MEM_32(suspend_count_ptr, suspend_count);
@ -276,32 +219,22 @@ SHIM_CALL NtSuspendThread_shim(
}
uint32_t xeKeSetAffinityThread(void* thread_ptr, uint32_t affinity) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XThread* thread = (XThread*)XObject::GetObject(state, thread_ptr);
if (thread) {
thread->SetAffinity(affinity);
}
return affinity;
}
SHIM_CALL KeSetAffinityThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t thread = SHIM_GET_ARG_32(0);
uint32_t thread_ptr = SHIM_GET_ARG_32(0);
uint32_t affinity = SHIM_GET_ARG_32(1);
XELOGD(
"KeSetAffinityThread(%.8X, %.8X)",
thread,
thread_ptr,
affinity);
void* thread_ptr = SHIM_MEM_ADDR(thread);
uint32_t result = xeKeSetAffinityThread(thread_ptr, affinity);
SHIM_SET_RETURN_32(result);
XThread* thread = (XThread*)XObject::GetObject(state, SHIM_MEM_ADDR(thread_ptr));
if (thread) {
thread->SetAffinity(affinity);
}
SHIM_SET_RETURN_32(affinity);
}
@ -325,45 +258,26 @@ SHIM_CALL KeQueryBasePriorityThread_shim(
}
uint32_t xeKeSetBasePriorityThread(void* thread_ptr, int32_t increment) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL KeSetBasePriorityThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t thread_ptr = SHIM_GET_ARG_32(0);
uint32_t increment = SHIM_GET_ARG_32(1);
XELOGD(
"KeSetBasePriorityThread(%.8X, %.8X)",
thread_ptr,
increment);
int32_t prev_priority = 0;
XThread* thread = (XThread*)XObject::GetObject(state, thread_ptr);
XThread* thread =
(XThread*)XObject::GetObject(state, SHIM_MEM_ADDR(thread_ptr));
if (thread) {
prev_priority = thread->QueryPriority();
thread->SetPriority(increment);
}
return prev_priority;
}
SHIM_CALL KeSetBasePriorityThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t thread = SHIM_GET_ARG_32(0);
uint32_t increment = SHIM_GET_ARG_32(1);
XELOGD(
"KeSetBasePriorityThread(%.8X, %.8X)",
thread,
increment);
void* thread_ptr = SHIM_MEM_ADDR(thread);
uint32_t result = xeKeSetBasePriorityThread(thread_ptr, increment);
SHIM_SET_RETURN_32(result);
}
uint32_t xeKeGetCurrentProcessType() {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
// DWORD
return X_PROCTYPE_USER;
SHIM_SET_RETURN_32(prev_priority);
}
@ -372,38 +286,27 @@ SHIM_CALL KeGetCurrentProcessType_shim(
// XELOGD(
// "KeGetCurrentProcessType()");
int result = xeKeGetCurrentProcessType();
// DWORD
int result = X_PROCTYPE_USER;
SHIM_SET_RETURN_64(result);
}
uint64_t xeKeQueryPerformanceFrequency() {
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
return frequency.QuadPart;
} else {
return 0;
}
}
SHIM_CALL KeQueryPerformanceFrequency_shim(
PPCContext* ppc_state, KernelState* state) {
// XELOGD(
// "KeQueryPerformanceFrequency()");
uint64_t result = xeKeQueryPerformanceFrequency();
uint64_t result = 0;
LARGE_INTEGER frequency;
if (QueryPerformanceFrequency(&frequency)) {
result = frequency.QuadPart;
}
SHIM_SET_RETURN_64(result);
}
X_STATUS xeKeDelayExecutionThread(
uint32_t processor_mode, uint32_t alertable, uint64_t interval) {
XThread* thread = XThread::GetCurrentThread();
return thread->Delay(processor_mode, alertable, interval);
}
SHIM_CALL KeDelayExecutionThread_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t processor_mode = SHIM_GET_ARG_32(0);
@ -415,8 +318,8 @@ SHIM_CALL KeDelayExecutionThread_shim(
// "KeDelayExecutionThread(%.8X, %d, %.8X(%.16llX)",
// processor_mode, alertable, interval_ptr, interval);
X_STATUS result = xeKeDelayExecutionThread(
processor_mode, alertable, interval);
XThread* thread = XThread::GetCurrentThread();
X_STATUS result = thread->Delay(processor_mode, alertable, interval);
SHIM_SET_RETURN_32(result);
}
@ -425,18 +328,12 @@ SHIM_CALL KeDelayExecutionThread_shim(
SHIM_CALL NtYieldExecution_shim(
PPCContext* ppc_state, KernelState* state) {
XELOGD("NtYieldExecution()");
xeKeDelayExecutionThread(0, 0, 0);
XThread* thread = XThread::GetCurrentThread();
X_STATUS result = thread->Delay(0, 0, 0);
SHIM_SET_RETURN_64(0);
}
void xeKeQuerySystemTime(uint64_t* time_ptr) {
FILETIME t;
GetSystemTimeAsFileTime(&t);
*time_ptr = ((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime;
}
SHIM_CALL KeQuerySystemTime_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t time_ptr = SHIM_GET_ARG_32(0);
@ -445,8 +342,9 @@ SHIM_CALL KeQuerySystemTime_shim(
"KeQuerySystemTime(%.8X)",
time_ptr);
uint64_t time;
xeKeQuerySystemTime(&time);
FILETIME t;
GetSystemTimeAsFileTime(&t);
uint64_t time = ((uint64_t)t.dwHighDateTime << 32) | t.dwLowDateTime;
if (time_ptr) {
SHIM_SET_MEM_64(time_ptr, time);
@ -461,8 +359,10 @@ SHIM_CALL KeQuerySystemTime_shim(
// http://msdn.microsoft.com/en-us/library/ms686801
uint32_t xeKeTlsAlloc() {
// DWORD
SHIM_CALL KeTlsAlloc_shim(
PPCContext* ppc_state, KernelState* state) {
XELOGD(
"KeTlsAlloc()");
uint32_t tls_index;
@ -477,41 +377,11 @@ uint32_t xeKeTlsAlloc() {
}
#endif // WIN32
return tls_index;
}
SHIM_CALL KeTlsAlloc_shim(
PPCContext* ppc_state, KernelState* state) {
XELOGD(
"KeTlsAlloc()");
uint32_t result = xeKeTlsAlloc();
SHIM_SET_RETURN_64(result);
SHIM_SET_RETURN_64(tls_index);
}
// http://msdn.microsoft.com/en-us/library/ms686804
int KeTlsFree(uint32_t tls_index) {
// BOOL
// _In_ DWORD dwTlsIndex
if (tls_index == X_TLS_OUT_OF_INDEXES) {
return 0;
}
int result_code = 0;
#if XE_PLATFORM_WIN32
result_code = TlsFree(tls_index);
#else
result_code = pthread_key_delete(tls_index) == 0;
#endif // WIN32
return result_code;
}
SHIM_CALL KeTlsFree_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
@ -520,15 +390,32 @@ SHIM_CALL KeTlsFree_shim(
"KeTlsFree(%.8X)",
tls_index);
int result = xeKeTlsAlloc();
if (tls_index == X_TLS_OUT_OF_INDEXES) {
SHIM_SET_RETURN_64(0);
return;
}
int result = 0;
#if XE_PLATFORM_WIN32
result = TlsFree(tls_index);
#else
result = pthread_key_delete(tls_index) == 0;
#endif // WIN32
SHIM_SET_RETURN_64(result);
}
// http://msdn.microsoft.com/en-us/library/ms686812
uint64_t xeKeTlsGetValue(uint32_t tls_index) {
// LPVOID
// _In_ DWORD dwTlsIndex
SHIM_CALL KeTlsGetValue_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
// Logging disabled, as some games spam this.
//XELOGD(
// "KeTlsGetValue(%.8X)",
// tls_index);
uint64_t value = 0;
@ -539,46 +426,15 @@ uint64_t xeKeTlsGetValue(uint32_t tls_index) {
#endif // WIN32
if (!value) {
XELOGW("KeTlsGetValue should SetLastError if result is NULL");
// XELOGW("KeTlsGetValue should SetLastError if result is NULL");
// TODO(benvanik): SetLastError
}
return value;
}
SHIM_CALL KeTlsGetValue_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
// Logging disabled, as some games spam this.
//XELOGD(
// "KeTlsGetValue(%.8X)",
// tls_index);
uint64_t result = xeKeTlsGetValue(tls_index);
SHIM_SET_RETURN_64(result);
SHIM_SET_RETURN_64(value);
}
// http://msdn.microsoft.com/en-us/library/ms686818
int xeKeTlsSetValue(uint32_t tls_index, uint64_t tls_value) {
// BOOL
// _In_ DWORD dwTlsIndex,
// _In_opt_ LPVOID lpTlsValue
int result_code = 0;
#if XE_PLATFORM_WIN32
result_code = TlsSetValue(tls_index, (LPVOID)tls_value);
#else
result_code = pthread_setspecific(tls_index, (void*)tls_value) == 0;
#endif // WIN32
return result_code;
}
SHIM_CALL KeTlsSetValue_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t tls_index = SHIM_GET_ARG_32(0);
@ -588,30 +444,18 @@ SHIM_CALL KeTlsSetValue_shim(
"KeTlsSetValue(%.8X, %.8X)",
tls_index, tls_value);
int result = xeKeTlsSetValue(tls_index, tls_value);
int result = 0;
#if XE_PLATFORM_WIN32
result = TlsSetValue(tls_index, (LPVOID)tls_value);
#else
result = pthread_setspecific(tls_index, (void*)tls_value) == 0;
#endif // WIN32
SHIM_SET_RETURN_64(result);
}
X_STATUS xeNtCreateEvent(uint32_t* handle_ptr, void* obj_attributes,
uint32_t event_type, uint32_t initial_state) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XEvent* ev = new XEvent(state);
ev->Initialize(!event_type, !!initial_state);
// obj_attributes may have a name inside of it, if != NULL.
if (obj_attributes) {
//ev->SetName(...);
}
*handle_ptr = ev->handle();
return X_STATUS_SUCCESS;
}
SHIM_CALL NtCreateEvent_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
@ -623,31 +467,19 @@ SHIM_CALL NtCreateEvent_shim(
"NtCreateEvent(%.8X, %.8X, %d, %d)",
handle_ptr, obj_attributes_ptr, event_type, initial_state);
uint32_t handle;
X_STATUS result = xeNtCreateEvent(
&handle, SHIM_MEM_ADDR(obj_attributes_ptr),
event_type, initial_state);
XEvent* ev = new XEvent(state);
ev->Initialize(!event_type, !!initial_state);
// obj_attributes may have a name inside of it, if != NULL.
auto obj_attributes = SHIM_MEM_ADDR(obj_attributes_ptr);
if (obj_attributes) {
//ev->SetName(...);
}
if (XSUCCEEDED(result)) {
if (handle_ptr) {
SHIM_SET_MEM_32(handle_ptr, handle);
SHIM_SET_MEM_32(handle_ptr, ev->handle());
}
}
SHIM_SET_RETURN_32(result);
}
int32_t xeKeSetEvent(void* event_ptr, uint32_t increment, uint32_t wait) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XEvent* ev = (XEvent*)XObject::GetObject(state, event_ptr);
assert_not_null(ev);
if (!ev) {
return 0;
}
return ev->Set(increment, !!wait);
SHIM_SET_RETURN_32(X_STATUS_SUCCESS);
}
@ -662,8 +494,15 @@ SHIM_CALL KeSetEvent_shim(
event_ref, increment, wait);
void* event_ptr = SHIM_MEM_ADDR(event_ref);
int32_t result = xeKeSetEvent(event_ptr, increment, wait);
XEvent* ev = (XEvent*)XObject::GetObject(state, event_ptr);
assert_not_null(ev);
if (!ev) {
SHIM_SET_RETURN_64(0);
return;
}
auto result = ev->Set(increment, !!wait);
SHIM_SET_RETURN_64(result);
}
@ -745,20 +584,6 @@ SHIM_CALL NtPulseEvent_shim(
}
int32_t xeKeResetEvent(void* event_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XEvent* ev = (XEvent*)XEvent::GetObject(state, event_ptr);
assert_not_null(ev);
if (!ev) {
return 0;
}
return ev->Reset();
}
SHIM_CALL KeResetEvent_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t event_ref = SHIM_GET_ARG_32(0);
@ -768,8 +593,14 @@ SHIM_CALL KeResetEvent_shim(
event_ref);
void* event_ptr = SHIM_MEM_ADDR(event_ref);
int32_t result = xeKeResetEvent(event_ptr);
XEvent* ev = (XEvent*)XEvent::GetObject(state, event_ptr);
assert_not_null(ev);
if (!ev) {
SHIM_SET_RETURN_64(0);
return;
}
auto result = ev->Reset();
SHIM_SET_RETURN_64(result);
}
@ -823,22 +654,6 @@ SHIM_CALL NtCreateSemaphore_shim(
}
void xeKeInitializeSemaphore(
void* semaphore_ptr, int32_t count, int32_t limit) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(
state, semaphore_ptr, 5 /* SemaphoreObject */);
assert_not_null(sem);
if (!sem) {
return;
}
sem->Initialize(count, limit);
}
SHIM_CALL KeInitializeSemaphore_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t semaphore_ref = SHIM_GET_ARG_32(0);
@ -850,25 +665,14 @@ SHIM_CALL KeInitializeSemaphore_shim(
semaphore_ref, count, limit);
void* semaphore_ptr = SHIM_MEM_ADDR(semaphore_ref);
xeKeInitializeSemaphore(semaphore_ptr, count, limit);
}
int32_t xeKeReleaseSemaphore(
void* semaphore_ptr, int32_t increment, int32_t adjustment, bool wait) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(state, semaphore_ptr);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(
state, semaphore_ptr, 5 /* SemaphoreObject */);
assert_not_null(sem);
if (!sem) {
return 0;
return;
}
// TODO(benvanik): increment thread priority?
// TODO(benvanik): wait?
return sem->ReleaseSemaphore(adjustment);
sem->Initialize(count, limit);
}
@ -884,9 +688,17 @@ SHIM_CALL KeReleaseSemaphore_shim(
semaphore_ref, increment, adjustment, wait);
void* semaphore_ptr = SHIM_MEM_ADDR(semaphore_ref);
int32_t result = xeKeReleaseSemaphore(
semaphore_ptr, increment, adjustment, wait == 1);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(state, semaphore_ptr);
assert_not_null(sem);
if (!sem) {
SHIM_SET_RETURN_64(0);
return;
}
// TODO(benvanik): increment thread priority?
// TODO(benvanik): wait?
int32_t result = sem->ReleaseSemaphore(adjustment);
SHIM_SET_RETURN_64(result);
}
@ -1072,25 +884,9 @@ SHIM_CALL NtCancelTimer_shim(
}
X_STATUS xeKeWaitForSingleObject(
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
XObject* object = XObject::GetObject(state, object_ptr);
if (!object) {
// The only kind-of failure code.
return X_STATUS_ABANDONED_WAIT_0;
}
return object->Wait(wait_reason, processor_mode, alertable, opt_timeout);
}
SHIM_CALL KeWaitForSingleObject_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t object = SHIM_GET_ARG_32(0);
uint32_t object_ptr = SHIM_GET_ARG_32(0);
uint32_t wait_reason = SHIM_GET_ARG_32(1);
uint32_t processor_mode = SHIM_GET_ARG_32(2);
uint32_t alertable = SHIM_GET_ARG_32(3);
@ -1098,13 +894,18 @@ SHIM_CALL KeWaitForSingleObject_shim(
XELOGD(
"KeWaitForSingleObject(%.8X, %.8X, %.8X, %.1X, %.8X)",
object, wait_reason, processor_mode, alertable, timeout_ptr);
object_ptr, wait_reason, processor_mode, alertable, timeout_ptr);
XObject* object = XObject::GetObject(state, SHIM_MEM_ADDR(object_ptr));
if (!object) {
// The only kind-of failure code.
SHIM_SET_RETURN_32(X_STATUS_ABANDONED_WAIT_0);
return;
}
void* object_ptr = SHIM_MEM_ADDR(object);
uint64_t timeout = timeout_ptr ? SHIM_MEM_64(timeout_ptr) : 0;
X_STATUS result = xeKeWaitForSingleObject(
object_ptr, wait_reason, processor_mode, alertable,
timeout_ptr ? &timeout : NULL);
X_STATUS result = object->Wait(wait_reason, processor_mode, alertable,
timeout_ptr ? &timeout : nullptr);
SHIM_SET_RETURN_32(result);
}
@ -1259,19 +1060,6 @@ SHIM_CALL NtSignalAndWaitForSingleObjectEx_shim(
}
uint32_t xeKfAcquireSpinLock(uint32_t* lock_ptr) {
// Lock.
while (!poly::atomic_cas(0, 1, lock_ptr)) {
// Spin!
// TODO(benvanik): error on deadlock?
}
// Raise IRQL to DISPATCH.
XThread* thread = XThread::GetCurrentThread();
return thread->RaiseIrql(2);
}
SHIM_CALL KfAcquireSpinLock_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t lock_ptr = SHIM_GET_ARG_32(0);
@ -1280,23 +1068,21 @@ SHIM_CALL KfAcquireSpinLock_shim(
// "KfAcquireSpinLock(%.8X)",
// lock_ptr);
// Lock.
auto lock = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr));
uint32_t old_irql = xeKfAcquireSpinLock(lock);
while (!poly::atomic_cas(0, 1, lock)) {
// Spin!
// TODO(benvanik): error on deadlock?
}
// Raise IRQL to DISPATCH.
XThread* thread = XThread::GetCurrentThread();
auto old_irql = thread->RaiseIrql(2);
SHIM_SET_RETURN_64(old_irql);
}
void xeKfReleaseSpinLock(uint32_t* lock_ptr, uint32_t old_irql) {
// Restore IRQL.
XThread* thread = XThread::GetCurrentThread();
thread->LowerIrql(old_irql);
// Unlock.
poly::atomic_dec(lock_ptr);
}
SHIM_CALL KfReleaseSpinLock_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t lock_ptr = SHIM_GET_ARG_32(0);
@ -1307,8 +1093,13 @@ SHIM_CALL KfReleaseSpinLock_shim(
// lock_ptr,
// old_irql);
xeKfReleaseSpinLock(reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr)),
old_irql);
// Restore IRQL.
XThread* thread = XThread::GetCurrentThread();
thread->LowerIrql(old_irql);
// Unlock.
auto lock = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr));
poly::atomic_dec(lock);
}
@ -1343,21 +1134,11 @@ SHIM_CALL KeReleaseSpinLockFromRaisedIrql_shim(
}
void xeKeEnterCriticalRegion() {
XThread::EnterCriticalRegion();
}
SHIM_CALL KeEnterCriticalRegion_shim(
PPCContext* ppc_state, KernelState* state) {
// XELOGD(
// "KeEnterCriticalRegion()");
xeKeEnterCriticalRegion();
}
void xeKeLeaveCriticalRegion() {
XThread::LeaveCriticalRegion();
XThread::EnterCriticalRegion();
}
@ -1365,7 +1146,7 @@ SHIM_CALL KeLeaveCriticalRegion_shim(
PPCContext* ppc_state, KernelState* state) {
// XELOGD(
// "KeLeaveCriticalRegion()");
xeKeLeaveCriticalRegion();
XThread::LeaveCriticalRegion();
}

View File

@ -43,12 +43,6 @@ namespace kernel {
// http://www.microsoft.com/en-za/download/details.aspx?id=5313 -- "Stripped Down Direct3D: Xbox 360 Command Buffer and Resource Management"
void xeVdGetCurrentDisplayGamma(uint32_t* arg0, float* arg1) {
*arg0 = 2;
*arg1 = 2.22222233f;
}
SHIM_CALL VdGetCurrentDisplayGamma_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t arg0_ptr = SHIM_GET_ARG_32(0);
@ -58,14 +52,8 @@ SHIM_CALL VdGetCurrentDisplayGamma_shim(
"VdGetCurrentDisplayGamma(%.8X, %.8X)",
arg0_ptr, arg1_ptr);
uint32_t arg0 = 0;
union {
float float_value;
uint32_t uint_value;
} arg1;
xeVdGetCurrentDisplayGamma(&arg0, &arg1.float_value);
SHIM_SET_MEM_32(arg0_ptr, arg0);
SHIM_SET_MEM_32(arg1_ptr, arg1.uint_value);
SHIM_SET_MEM_32(arg0_ptr, 2);
SHIM_SET_MEM_F32(arg1_ptr, 2.22222233f);
}
@ -103,22 +91,16 @@ SHIM_CALL VdGetCurrentDisplayInformation_shim(
}
uint32_t xeVdQueryVideoFlags() {
// ?
return 0x00000006;
}
SHIM_CALL VdQueryVideoFlags_shim(
PPCContext* ppc_state, KernelState* state) {
XELOGD(
"VdQueryVideoFlags()");
SHIM_SET_RETURN_64(xeVdQueryVideoFlags());
SHIM_SET_RETURN_64(0x00000006);
}
void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap) {
void xeVdQueryVideoMode(X_VIDEO_MODE* video_mode) {
if (video_mode == NULL) {
return;
}
@ -134,7 +116,7 @@ void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap) {
video_mode->unknown_0x8a = 0x8A;
video_mode->unknown_0x01 = 0x01;
if (swap) {
// TODO(benvanik): auto swap structure.
video_mode->display_width = poly::byte_swap(video_mode->display_width);
video_mode->display_height = poly::byte_swap(video_mode->display_height);
video_mode->is_interlaced = poly::byte_swap(video_mode->is_interlaced);
@ -144,7 +126,6 @@ void xeVdQueryVideoMode(X_VIDEO_MODE *video_mode, bool swap) {
video_mode->video_standard = poly::byte_swap(video_mode->video_standard);
video_mode->unknown_0x8a = poly::byte_swap(video_mode->unknown_0x8a);
video_mode->unknown_0x01 = poly::byte_swap(video_mode->unknown_0x01);
}
}
@ -157,23 +138,7 @@ SHIM_CALL VdQueryVideoMode_shim(
"VdQueryVideoMode(%.8X)",
video_mode_ptr);
xeVdQueryVideoMode(video_mode, true);
}
void xeVdInitializeEngines(uint32_t unk0, uint32_t callback, uint32_t unk1,
uint32_t unk2_ptr, uint32_t unk3_ptr) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r3 = 0x4F810000
// r4 = function ptr (cleanup callback?)
// r5 = 0
// r6/r7 = some binary data in .data
xeVdQueryVideoMode(video_mode);
}
@ -189,7 +154,10 @@ SHIM_CALL VdInitializeEngines_shim(
"VdInitializeEngines(%.8X, %.8X, %.8X, %.8X, %.8X)",
unk0, callback, unk1, unk2_ptr, unk3_ptr);
xeVdInitializeEngines(unk0, callback, unk1, unk2_ptr, unk3_ptr);
// r3 = 0x4F810000
// r4 = function ptr (cleanup callback?)
// r5 = 0
// r6/r7 = some binary data in .data
}
@ -204,9 +172,15 @@ SHIM_CALL VdShutdownEngines_shim(
}
void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
SHIM_CALL VdSetGraphicsInterruptCallback_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t callback = SHIM_GET_ARG_32(0);
uint32_t user_data = SHIM_GET_ARG_32(1);
XELOGD(
"VdSetGraphicsInterruptCallback(%.8X, %.8X)",
callback, user_data);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
@ -220,22 +194,15 @@ void xeVdSetGraphicsInterruptCallback(uint32_t callback, uint32_t user_data) {
}
SHIM_CALL VdSetGraphicsInterruptCallback_shim(
SHIM_CALL VdInitializeRingBuffer_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t callback = SHIM_GET_ARG_32(0);
uint32_t user_data = SHIM_GET_ARG_32(1);
uint32_t ptr = SHIM_GET_ARG_32(0);
uint32_t page_count = SHIM_GET_ARG_32(1);
XELOGD(
"VdSetGraphicsInterruptCallback(%.8X, %.8X)",
callback, user_data);
"VdInitializeRingBuffer(%.8X, %.8X)",
ptr, page_count);
xeVdSetGraphicsInterruptCallback(callback, user_data);
}
void xeVdInitializeRingBuffer(uint32_t ptr, uint32_t page_count) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
@ -252,22 +219,15 @@ void xeVdInitializeRingBuffer(uint32_t ptr, uint32_t page_count) {
}
SHIM_CALL VdInitializeRingBuffer_shim(
SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t ptr = SHIM_GET_ARG_32(0);
uint32_t page_count = SHIM_GET_ARG_32(1);
uint32_t block_size = SHIM_GET_ARG_32(1);
XELOGD(
"VdInitializeRingBuffer(%.8X, %.8X)",
ptr, page_count);
"VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)",
ptr, block_size);
xeVdInitializeRingBuffer(ptr, page_count);
}
void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
@ -284,37 +244,18 @@ void xeVdEnableRingBufferRPtrWriteBack(uint32_t ptr, uint32_t block_size) {
//((p + 0x3C) & 0x1FFFFFFF) + ((((p + 0x3C) >> 20) + 0x200) & 0x1000)
//also 0x3C offset into WriteBacks is PrimaryRingBufferReadIndex
//(1:17:38 AM) Rick: .text:8201B348 lwz r11, 0x2B10(r31)
//(1:17:38 AM) Rick: .text:8201B34C addi r11, r11, 0x3C
//(1:17:38 AM) Rick: .text:8201B350 srwi r10, r11, 20 # r10 = r11 >> 20
//(1:17:38 AM) Rick: .text:8201B354 clrlwi r11, r11, 3 # r11 = r11 & 0x1FFFFFFF
//(1:17:38 AM) Rick: .text:8201B358 addi r10, r10, 0x200
//(1:17:39 AM) Rick: .text:8201B35C rlwinm r10, r10, 0,19,19 # r10 = r10 & 0x1000
//(1:17:39 AM) Rick: .text:8201B360 add r3, r10, r11
//(1:17:39 AM) Rick: .text:8201B364 bl VdEnableRingBufferRPtrWriteBack
//(1:17:38 AM) Rick: .text:8201B348 lwz r11, 0x2B10(r31)
//(1:17:38 AM) Rick: .text:8201B34C addi r11, r11, 0x3C
//(1:17:38 AM) Rick: .text:8201B350 srwi r10, r11, 20 # r10 = r11 >> 20
//(1:17:38 AM) Rick: .text:8201B354 clrlwi r11, r11, 3 # r11 = r11 & 0x1FFFFFFF
//(1:17:38 AM) Rick: .text:8201B358 addi r10, r10, 0x200
//(1:17:39 AM) Rick: .text:8201B35C rlwinm r10, r10, 0,19,19 # r10 = r10 & 0x1000
//(1:17:39 AM) Rick: .text:8201B360 add r3, r10, r11
//(1:17:39 AM) Rick: .text:8201B364 bl VdEnableRingBufferRPtrWriteBack
// TODO(benvanik): something?
}
SHIM_CALL VdEnableRingBufferRPtrWriteBack_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t ptr = SHIM_GET_ARG_32(0);
uint32_t block_size = SHIM_GET_ARG_32(1);
XELOGD(
"VdEnableRingBufferRPtrWriteBack(%.8X, %.8X)",
ptr, block_size);
xeVdEnableRingBufferRPtrWriteBack(ptr, block_size);
}
void xeVdGetSystemCommandBuffer(uint32_t* p0, uint32_t* p1) {
*p0 = 0xBEEF0000;
*p1 = 0xBEEF0001;
}
SHIM_CALL VdGetSystemCommandBuffer_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t p0_ptr = SHIM_GET_ARG_32(0);
@ -325,23 +266,8 @@ SHIM_CALL VdGetSystemCommandBuffer_shim(
p0_ptr,
p1_ptr);
uint32_t p0 = 0;
uint32_t p1 = 0;
xeVdGetSystemCommandBuffer(&p0, &p1);
SHIM_SET_MEM_32(p0_ptr, p0);
SHIM_SET_MEM_32(p1_ptr, p1);
}
void xeVdSetSystemCommandBufferGpuIdentifierAddress(uint32_t unk) {
KernelState* state = shared_kernel_state_;
assert_not_null(state);
GraphicsSystem* gs = state->emulator()->graphics_system();
if (!gs) {
return;
}
// r3 = 0x2B10(d3d?) + 8
SHIM_SET_MEM_32(p0_ptr, 0xBEEF0000);
SHIM_SET_MEM_32(p1_ptr, 0xBEEF0001);
}
@ -353,7 +279,7 @@ SHIM_CALL VdSetSystemCommandBufferGpuIdentifierAddress_shim(
"VdSetSystemCommandBufferGpuIdentifierAddress(%.8X)",
unk);
xeVdSetSystemCommandBufferGpuIdentifierAddress(unk);
// r3 = 0x2B10(d3d?) + 8
}
@ -487,8 +413,7 @@ void xe::kernel::xboxkrnl::RegisterVideoExports(
// Pointer to a global D3D device. Games only seem to set this, so we don't
// have to do anything. We may want to read it back later, though.
uint32_t pVdGlobalDevice = (uint32_t)memory->HeapAlloc(0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGlobalDevice,
export_resolver->SetVariableMapping("xboxkrnl.exe", ordinals::VdGlobalDevice,
pVdGlobalDevice);
poly::store_and_swap<uint32_t>(mem + pVdGlobalDevice, 0);
@ -496,15 +421,13 @@ void xe::kernel::xboxkrnl::RegisterVideoExports(
// Pointer to the XAM D3D device, which we don't have.
uint32_t pVdGlobalXamDevice = (uint32_t)memory->HeapAlloc(0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGlobalXamDevice,
pVdGlobalXamDevice);
"xboxkrnl.exe", ordinals::VdGlobalXamDevice, pVdGlobalXamDevice);
poly::store_and_swap<uint32_t>(mem + pVdGlobalXamDevice, 0);
// VdGpuClockInMHz (4b)
// GPU clock. Xenos is 500MHz. Hope nothing is relying on this timing...
uint32_t pVdGpuClockInMHz = (uint32_t)memory->HeapAlloc(0, 4, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdGpuClockInMHz,
export_resolver->SetVariableMapping("xboxkrnl.exe", ordinals::VdGpuClockInMHz,
pVdGpuClockInMHz);
poly::store_and_swap<uint32_t>(mem + pVdGpuClockInMHz, 500);
@ -512,7 +435,8 @@ void xe::kernel::xboxkrnl::RegisterVideoExports(
// CriticalSection.
uint32_t pVdHSIOCalibrationLock = (uint32_t)memory->HeapAlloc(0, 28, 0);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdHSIOCalibrationLock,
pVdHSIOCalibrationLock);
xeRtlInitializeCriticalSectionAndSpinCount(pVdHSIOCalibrationLock, 10000);
"xboxkrnl.exe", ordinals::VdHSIOCalibrationLock, pVdHSIOCalibrationLock);
auto hsio_lock =
reinterpret_cast<X_RTL_CRITICAL_SECTION*>(mem + pVdHSIOCalibrationLock);
xeRtlInitializeCriticalSectionAndSpinCount(hsio_lock, 10000);
}

View File

@ -68,7 +68,7 @@ void XObject::Release() {
}
X_STATUS XObject::Delete() {
return shared_kernel_state_->object_table()->RemoveHandle(handle_);
return kernel_state_->object_table()->RemoveHandle(handle_);
}
uint32_t XObject::TimeoutTicksToMs(int64_t timeout_ticks) {
@ -149,11 +149,11 @@ X_STATUS XObject::WaitMultiple(
}
void XObject::LockType() {
xe_mutex_lock(shared_kernel_state_->object_mutex_);
xe_mutex_lock(KernelState::shared()->object_mutex_);
}
void XObject::UnlockType() {
xe_mutex_unlock(shared_kernel_state_->object_mutex_);
xe_mutex_unlock(KernelState::shared()->object_mutex_);
}
void XObject::SetNativePointer(uint32_t native_ptr) {