diff --git a/src/xenia/kernel/modules/xboxkrnl/module.cc b/src/xenia/kernel/modules/xboxkrnl/module.cc index aa2dfd7da..56d66954b 100644 --- a/src/xenia/kernel/modules/xboxkrnl/module.cc +++ b/src/xenia/kernel/modules/xboxkrnl/module.cc @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -31,6 +32,9 @@ DEFINE_bool(abort_before_entry, false, "Abort execution right before launching the module."); +KernelState* xe::kernel::xboxkrnl::shared_kernel_state_ = NULL; + + XboxkrnlModule::XboxkrnlModule(Runtime* runtime) : KernelModule(runtime) { ExportResolver* resolver = export_resolver_.get(); @@ -48,6 +52,10 @@ XboxkrnlModule::XboxkrnlModule(Runtime* runtime) : // This is where all kernel objects are kept while running. kernel_state_ = auto_ptr(new KernelState(runtime)); + // Setup the shared global state object. + XEASSERTNULL(shared_kernel_state_); + shared_kernel_state_ = kernel_state_.get(); + // Register all exported functions. RegisterHalExports(resolver, kernel_state_.get()); RegisterMemoryExports(resolver, kernel_state_.get()); @@ -109,6 +117,8 @@ XboxkrnlModule::XboxkrnlModule(Runtime* runtime) : } XboxkrnlModule::~XboxkrnlModule() { + // Clear the shared kernel state. + shared_kernel_state_ = NULL; } int XboxkrnlModule::LaunchModule(const char* path) { diff --git a/src/xenia/kernel/modules/xboxkrnl/module.h b/src/xenia/kernel/modules/xboxkrnl/module.h index f3732b421..91f46caba 100644 --- a/src/xenia/kernel/modules/xboxkrnl/module.h +++ b/src/xenia/kernel/modules/xboxkrnl/module.h @@ -41,4 +41,5 @@ private: } // namespace kernel } // namespace xe + #endif // XENIA_KERNEL_MODULES_XBOXKRNL_MODULE_H_ diff --git a/src/xenia/kernel/modules/xboxkrnl/sources.gypi b/src/xenia/kernel/modules/xboxkrnl/sources.gypi index d9df59293..2a62109fc 100644 --- a/src/xenia/kernel/modules/xboxkrnl/sources.gypi +++ b/src/xenia/kernel/modules/xboxkrnl/sources.gypi @@ -12,6 +12,7 @@ 'xboxkrnl_module.cc', 'xboxkrnl_module.h', 'xboxkrnl_ordinals.h', + 'xboxkrnl_private.h', 'xboxkrnl_rtl.cc', 'xboxkrnl_rtl.h', 'xboxkrnl_table.inc', diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.cc index 9f81b15d6..bc0e9b2d1 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.cc @@ -11,6 +11,7 @@ #include #include +#include using namespace xe; @@ -23,8 +24,13 @@ namespace kernel { namespace xboxkrnl { -SHIM_CALL NtAllocateVirtualMemory_shim( - xe_ppc_state_t* ppc_state, KernelState* state) { +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_; + XEASSERTNOTNULL(state); + // NTSTATUS // _Inout_ PVOID *BaseAddress, // _In_ ULONG_PTR ZeroBits, @@ -33,6 +39,55 @@ SHIM_CALL NtAllocateVirtualMemory_shim( // _In_ ULONG Protect // ? handle? + // I've only seen zero. + XEASSERT(unknown == 0); + + // This allocates memory from the kernel heap, which is initialized on startup + // and shared by both the kernel implementation and user code. + // The xe_memory_ref object is used to actually get the memory, and although + // 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; + } + // Check allocation type. + if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) { + return X_STATUS_INVALID_PARAMETER; + } + // 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; + } + // 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; + } + + // Adjust size. + uint32_t adjusted_size = *region_size_ptr; + // TODO(benvanik): adjust based on page size flags/etc? + + // Allocate. + uint32_t flags = 0; + uint32_t addr = xe_memory_heap_alloc( + state->memory(), *base_addr_ptr, adjusted_size, flags); + if (!addr) { + // Failed - assume no memory available. + return X_STATUS_NO_MEMORY; + } + + // Stash back. + // Maybe set X_STATUS_ALREADY_COMMITTED if MEM_COMMIT? + *base_addr_ptr = addr; + *region_size_ptr = adjusted_size; + return X_STATUS_SUCCESS; +} + +// TODO(benvanik): remove state parameter. +SHIM_CALL NtAllocateVirtualMemory_shim( + xe_ppc_state_t* 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); @@ -41,61 +96,21 @@ SHIM_CALL NtAllocateVirtualMemory_shim( uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask uint32_t unknown = SHIM_GET_ARG_32(4); - // I've only seen zero. - XEASSERT(unknown == 0); - 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); - // This allocates memory from the kernel heap, which is initialized on startup - // and shared by both the kernel implementation and user code. - // The xe_memory_ref object is used to actually get the memory, and although - // it's simple today we could extend it to do better things in the future. + X_STATUS result = xeNtAllocateVirtualMemory( + &base_addr_value, ®ion_size_value, + allocation_type, protect_bits, unknown); - // Must request a size. - if (!region_size_value) { - SHIM_SET_RETURN(X_STATUS_INVALID_PARAMETER); - return; + if (XSUCCEEDED(result)) { + SHIM_SET_MEM_32(base_addr_ptr, base_addr_value); + SHIM_SET_MEM_32(region_size_ptr, region_size_value); } - // Check allocation type. - if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) { - SHIM_SET_RETURN(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)) { - SHIM_SET_RETURN(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)) { - SHIM_SET_RETURN(X_STATUS_ACCESS_DENIED); - return; - } - - // Adjust size. - uint32_t adjusted_size = region_size_value; - // TODO(benvanik): adjust based on page size flags/etc? - - // Allocate. - uint32_t flags = 0; - uint32_t addr = xe_memory_heap_alloc( - state->memory(), base_addr_value, adjusted_size, flags); - if (!addr) { - // Failed - assume no memory available. - SHIM_SET_RETURN(X_STATUS_NO_MEMORY); - return; - } - - // Stash back. - // Maybe set X_STATUS_ALREADY_COMMITTED if MEM_COMMIT? - SHIM_SET_MEM_32(base_addr_ptr, addr); - SHIM_SET_MEM_32(region_size_ptr, adjusted_size); - SHIM_SET_RETURN(X_STATUS_SUCCESS); + SHIM_SET_RETURN(result); } SHIM_CALL NtFreeVirtualMemory_shim( diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.h index 8126f0b6c..4363e4878 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.h +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_memory.h @@ -19,6 +19,12 @@ namespace kernel { namespace xboxkrnl { +X_STATUS xeNtAllocateVirtualMemory( + uint32_t* base_addr_ptr, uint32_t* region_size_ptr, + uint32_t allocation_type, uint32_t protect_bits, + uint32_t unknown); + + void RegisterMemoryExports(ExportResolver* export_resolver, KernelState* state); diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h new file mode 100644 index 000000000..9dac45f7e --- /dev/null +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h @@ -0,0 +1,32 @@ +/** + ****************************************************************************** + * 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_MODULES_XBOXKRNL_PRIVATE_H_ +#define XENIA_KERNEL_MODULES_XBOXKRNL_PRIVATE_H_ + +#include +#include + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + +class KernelState; + + +extern KernelState* shared_kernel_state_; + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_MODULES_XBOXKRNL_PRIVATE_H_