Progress on ghetto memory allocator.

This commit is contained in:
Ben Vanik 2013-01-28 21:36:03 -08:00
parent 0fde6135a0
commit 7b62fa96bd
11 changed files with 6471 additions and 44 deletions

View File

@ -35,5 +35,12 @@ uint32_t xe_memory_search_aligned(xe_memory_ref memory, uint32_t start,
uint32_t end, const uint32_t *values, uint32_t end, const uint32_t *values,
const size_t value_count); const size_t value_count);
// These methods slice off memory from the virtual address space.
// They should only be used by kernel modules that know what they are doing.
uint32_t xe_memory_heap_alloc(xe_memory_ref memory, uint32_t base_addr,
uint32_t size, uint32_t flags);
uint32_t xe_memory_heap_free(xe_memory_ref memory, uint32_t addr,
uint32_t flags);
#endif // XENIA_CORE_MEMORY_H_ #endif // XENIA_CORE_MEMORY_H_

View File

@ -11,6 +11,17 @@
#include <sys/mman.h> #include <sys/mman.h>
#define MSPACES 1
#define USE_LOCKS 1
#define USE_DL_PREFIX 1
#define HAVE_MORECORE 0
#define HAVE_MMAP 0
#define HAVE_MREMAP 0
#define malloc_getpagesize 4096
#define DEFAULT_GRANULARITY 64 * 1024
#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
#include <third_party/dlmalloc/malloc.c.h>
/** /**
* Memory map: * Memory map:
@ -32,10 +43,15 @@ struct xe_memory {
size_t length; size_t length;
void *ptr; void *ptr;
mspace heap;
}; };
xe_memory_ref xe_memory_create(xe_pal_ref pal, xe_memory_options_t options) { xe_memory_ref xe_memory_create(xe_pal_ref pal, xe_memory_options_t options) {
uint32_t offset;
uint32_t mspace_size;
xe_memory_ref memory = (xe_memory_ref)xe_calloc(sizeof(xe_memory)); xe_memory_ref memory = (xe_memory_ref)xe_calloc(sizeof(xe_memory));
xe_ref_init((xe_ref)memory); xe_ref_init((xe_ref)memory);
@ -45,14 +61,25 @@ xe_memory_ref xe_memory_create(xe_pal_ref pal, xe_memory_options_t options) {
XEEXPECTNOTNULL(memory->ptr); XEEXPECTNOTNULL(memory->ptr);
XEEXPECT(memory->ptr != MAP_FAILED); XEEXPECT(memory->ptr != MAP_FAILED);
// Allocate the mspace for our heap.
// We skip the first page to make writes to 0 easier to find.
offset = 64 * 1024;
mspace_size = 512 * 1024 * 1024 - offset;
memory->heap = create_mspace_with_base(
(uint8_t*)memory->ptr + offset, mspace_size, 0);
return memory; return memory;
XECLEANUP: XECLEANUP:
if (memory->heap) {
destroy_mspace(memory->heap);
}
xe_memory_release(memory); xe_memory_release(memory);
return NULL; return NULL;
} }
void xe_memory_dealloc(xe_memory_ref memory) { void xe_memory_dealloc(xe_memory_ref memory) {
destroy_mspace(memory->heap);
munmap(memory->ptr, memory->length); munmap(memory->ptr, memory->length);
} }
@ -97,3 +124,36 @@ uint32_t xe_memory_search_aligned(xe_memory_ref memory, uint32_t start,
} }
return 0; return 0;
} }
// TODO(benvanik): reserve/commit states/large pages/etc
uint32_t xe_memory_heap_alloc(xe_memory_ref memory, uint32_t base_addr,
uint32_t size, uint32_t flags) {
if (base_addr) {
return base_addr;
}
XEASSERT(base_addr == 0);
XEASSERT(flags == 0);
uint8_t* p = (uint8_t*)mspace_malloc(memory->heap, size);
if (!p) {
return 0;
}
return (uint32_t)((uintptr_t)p - (uintptr_t)memory->ptr);
}
uint32_t xe_memory_heap_free(xe_memory_ref memory, uint32_t addr,
uint32_t flags) {
XEASSERT(flags == 0);
uint8_t* p = (uint8_t*)memory->ptr + addr;
size_t real_size = mspace_usable_size(p);
if (!real_size) {
return 0;
}
mspace_free(memory->heap, p);
return (uint32_t)real_size;
}

View File

@ -194,14 +194,15 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) {
GenericValue lr_arg; GenericValue lr_arg;
lr_arg.IntVal = APInt(64, lr); lr_arg.IntVal = APInt(64, lr);
args.push_back(lr_arg); args.push_back(lr_arg);
GenericValue ret = engine_->runFunction(f, args); GenericValue ret = engine_->runFunction(f, args);
// return (uint32_t)ret.IntVal.getSExtValue();
// Faster, somewhat.
// Messes with the stack in such a way as to cause Xcode to behave oddly.
// typedef void (*fnptr)(xe_ppc_state_t*, uint64_t); // typedef void (*fnptr)(xe_ppc_state_t*, uint64_t);
// fnptr ptr = (fnptr)engine_->getPointerToFunction(f); // fnptr ptr = (fnptr)engine_->getPointerToFunction(f);
// ptr(ppc_state, lr); // ptr(ppc_state, lr);
//return (uint32_t)ret.IntVal.getSExtValue();
return 0; return 0;
} }

View File

@ -19,10 +19,14 @@ namespace kernel {
namespace xboxkrnl { namespace xboxkrnl {
typedef uint32_t X_HANDLE;
#define X_INVALID_HANDLE_VALUE ((X_HANDLE)-1)
// NT_STATUS (STATUS_*) // NT_STATUS (STATUS_*)
// http://msdn.microsoft.com/en-us/library/cc704588.aspx // http://msdn.microsoft.com/en-us/library/cc704588.aspx
// Adding as needed. // Adding as needed.
#define X_STAUTS_SUCCESS ((uint32_t)0x00000000L) #define X_STATUS_SUCCESS ((uint32_t)0x00000000L)
#define X_STATUS_UNSUCCESSFUL ((uint32_t)0xC0000001L) #define X_STATUS_UNSUCCESSFUL ((uint32_t)0xC0000001L)
#define X_STATUS_NOT_IMPLEMENTED ((uint32_t)0xC0000002L) #define X_STATUS_NOT_IMPLEMENTED ((uint32_t)0xC0000002L)
#define X_STATUS_ACCESS_VIOLATION ((uint32_t)0xC0000005L) #define X_STATUS_ACCESS_VIOLATION ((uint32_t)0xC0000005L)
@ -56,7 +60,10 @@ namespace xboxkrnl {
#define X_PAGE_READONLY 0x00000002 #define X_PAGE_READONLY 0x00000002
#define X_PAGE_READWRITE 0x00000004 #define X_PAGE_READWRITE 0x00000004
#define X_PAGE_WRITECOPY 0x00000008 #define X_PAGE_WRITECOPY 0x00000008
// *_EXECUTE_* bits omitted, as user code can't mark pages as executable. #define X_PAGE_EXECUTE 0x00000010
#define X_PAGE_EXECUTE_READ 0x00000020
#define X_PAGE_EXECUTE_READWRITE 0x00000040
#define X_PAGE_EXECUTE_WRITECOPY 0x00000080
#define X_PAGE_GUARD 0x00000100 #define X_PAGE_GUARD 0x00000100
#define X_PAGE_NOCACHE 0x00000200 #define X_PAGE_NOCACHE 0x00000200
#define X_PAGE_WRITECOMBINE 0x00000400 #define X_PAGE_WRITECOMBINE 0x00000400

View File

@ -35,29 +35,65 @@ void NtAllocateVirtualMemory_shim(
uint32_t base_addr_value = SHIM_MEM_32(base_addr_ptr); 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_ptr = SHIM_GET_ARG_32(1);
uint32_t region_size_value = SHIM_MEM_32(region_size_ptr); uint32_t region_size_value = SHIM_MEM_32(region_size_ptr);
// X_MEM_* uint32_t allocation_type = SHIM_GET_ARG_32(2); // X_MEM_* bitmask
uint32_t allocation_type = SHIM_GET_ARG_32(2); uint32_t protect_bits = SHIM_GET_ARG_32(3); // X_PAGE_* bitmask
// X_PAGE_*
uint32_t protect_bits = SHIM_GET_ARG_32(3);
uint32_t unknown = SHIM_GET_ARG_32(4); uint32_t unknown = SHIM_GET_ARG_32(4);
// I've only seen zero.
XEASSERT(unknown == 0);
XELOGD( XELOGD(
XT("NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)"), XT("NtAllocateVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X, %.8X)"),
base_addr_ptr, base_addr_value, base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value, region_size_ptr, region_size_value,
allocation_type, protect_bits, unknown); allocation_type, protect_bits, unknown);
// TODO(benvanik): alloc memory // 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.
// Possible return codes: // Must request a size.
// X_STATUS_UNSUCCESSFUL if (!region_size_value) {
// X_STATUS_INVALID_PAGE_PROTECTION SHIM_SET_RETURN(X_STATUS_INVALID_PARAMETER);
// X_STATUS_ACCESS_DENIED return;
// X_STATUS_ALREADY_COMMITTED }
// X_STATUS_INVALID_HANDLE // Check allocation type.
// X_STATUS_INVALID_PAGE_PROTECTION if (!(allocation_type & (X_MEM_COMMIT | X_MEM_RESET | X_MEM_RESERVE))) {
// X_STATUS_NO_MEMORY SHIM_SET_RETURN(X_STATUS_INVALID_PARAMETER);
SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL); 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);
} }
void NtFreeVirtualMemory_shim( void NtFreeVirtualMemory_shim(
@ -76,19 +112,28 @@ void NtFreeVirtualMemory_shim(
uint32_t free_type = SHIM_GET_ARG_32(2); uint32_t free_type = SHIM_GET_ARG_32(2);
uint32_t unknown = SHIM_GET_ARG_32(3); uint32_t unknown = SHIM_GET_ARG_32(3);
// I've only seen zero.
XEASSERT(unknown == 0);
XELOGD( XELOGD(
XT("NtFreeVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X)"), XT("NtFreeVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X)"),
base_addr_ptr, base_addr_value, base_addr_ptr, base_addr_value,
region_size_ptr, region_size_value, region_size_ptr, region_size_value,
free_type, unknown); free_type, unknown);
// TODO(benvanik): free memory // Free.
uint32_t flags = 0;
// Possible return codes: uint32_t freed_size = xe_memory_heap_free(state->memory, base_addr_value,
// X_STATUS_UNSUCCESSFUL flags);
// X_STATUS_ACCESS_DENIED if (!freed_size) {
// X_STATUS_INVALID_HANDLE
SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL); SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL);
return;
}
// Stash back.
SHIM_SET_MEM_32(base_addr_ptr, base_addr_value);
SHIM_SET_MEM_32(region_size_ptr, freed_size);
SHIM_SET_RETURN(X_STATUS_SUCCESS);
} }

View File

@ -50,9 +50,12 @@ XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
uint8_t* mem = xe_memory_addr(memory, 0); uint8_t* mem = xe_memory_addr(memory, 0);
// KeDebugMonitorData (?*) // KeDebugMonitorData (?*)
// I'm not sure what this is for, but games make sure it's not null and
// exit if it is.
resolver->SetVariableMapping( resolver->SetVariableMapping(
"xboxkrnl.exe", 0x00000059, "xboxkrnl.exe", 0x00000059,
0x40001000); 0x80102100);
XESETUINT32BE(mem + 0x80102100, 0x1);
// XboxHardwareInfo (XboxHardwareInfo_t, 16b) // XboxHardwareInfo (XboxHardwareInfo_t, 16b)
// flags cpu# ? ? ? ? ? ? // flags cpu# ? ? ? ? ? ?

View File

@ -54,6 +54,8 @@ void RtlImageXexHeaderField_shim(
case XEX_HEADER_DEFAULT_HEAP_SIZE: case XEX_HEADER_DEFAULT_HEAP_SIZE:
// TODO(benvanik): pull from running module // TODO(benvanik): pull from running module
// This is header->exe_heap_size. // This is header->exe_heap_size.
//SHIM_SET_MEM_32(0x80101104, [some value]);
//return_value = 0x80101104;
return_value = 0; return_value = 0;
break; break;
default: default:
@ -67,6 +69,10 @@ void RtlImageXexHeaderField_shim(
} }
//RtlInitializeCriticalSection
//RtlEnterCriticalSection
//RtlLeaveCriticalSection
} }

BIN
test/codegen/subfe.bin Executable file

Binary file not shown.

9
test/codegen/subfe.dis Normal file
View File

@ -0,0 +1,9 @@
subfe.o: file format elf64-powerpc
Disassembly of section .text:
0000000082010000 <.text>:
82010000: 7c 6a 59 10 subfe r3,r10,r11
82010004: 4e 80 00 20 blr

9
test/codegen/subfe.s Normal file
View File

@ -0,0 +1,9 @@
# REGISTER_IN r10 0x00000000000103BF
# REGISTER_IN r11 0x00000000000103C0
subfe r3, r10, r11
blr
# REGISTER_OUT r10 0x00000000000103BF
# REGISTER_OUT r11 0x00000000000103C0
# REGISTER_OUT r3 0x1

6280
third_party/dlmalloc/malloc.c.h vendored Normal file

File diff suppressed because it is too large Load Diff