Progress on ghetto memory allocator.
This commit is contained in:
parent
0fde6135a0
commit
7b62fa96bd
|
@ -35,5 +35,12 @@ uint32_t xe_memory_search_aligned(xe_memory_ref memory, uint32_t start,
|
|||
uint32_t end, const uint32_t *values,
|
||||
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_
|
||||
|
|
|
@ -11,6 +11,17 @@
|
|||
|
||||
#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:
|
||||
|
@ -32,10 +43,15 @@ struct xe_memory {
|
|||
|
||||
size_t length;
|
||||
void *ptr;
|
||||
|
||||
mspace heap;
|
||||
};
|
||||
|
||||
|
||||
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_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);
|
||||
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;
|
||||
|
||||
XECLEANUP:
|
||||
if (memory->heap) {
|
||||
destroy_mspace(memory->heap);
|
||||
}
|
||||
xe_memory_release(memory);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void xe_memory_dealloc(xe_memory_ref memory) {
|
||||
destroy_mspace(memory->heap);
|
||||
munmap(memory->ptr, memory->length);
|
||||
}
|
||||
|
||||
|
@ -97,3 +124,36 @@ uint32_t xe_memory_search_aligned(xe_memory_ref memory, uint32_t start,
|
|||
}
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -194,14 +194,15 @@ int Processor::Execute(ThreadState* thread_state, uint32_t address) {
|
|||
GenericValue lr_arg;
|
||||
lr_arg.IntVal = APInt(64, lr);
|
||||
args.push_back(lr_arg);
|
||||
|
||||
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);
|
||||
// fnptr ptr = (fnptr)engine_->getPointerToFunction(f);
|
||||
// ptr(ppc_state, lr);
|
||||
|
||||
//return (uint32_t)ret.IntVal.getSExtValue();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,10 +19,14 @@ namespace kernel {
|
|||
namespace xboxkrnl {
|
||||
|
||||
|
||||
typedef uint32_t X_HANDLE;
|
||||
#define X_INVALID_HANDLE_VALUE ((X_HANDLE)-1)
|
||||
|
||||
|
||||
// NT_STATUS (STATUS_*)
|
||||
// http://msdn.microsoft.com/en-us/library/cc704588.aspx
|
||||
// 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_NOT_IMPLEMENTED ((uint32_t)0xC0000002L)
|
||||
#define X_STATUS_ACCESS_VIOLATION ((uint32_t)0xC0000005L)
|
||||
|
@ -56,7 +60,10 @@ namespace xboxkrnl {
|
|||
#define X_PAGE_READONLY 0x00000002
|
||||
#define X_PAGE_READWRITE 0x00000004
|
||||
#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_NOCACHE 0x00000200
|
||||
#define X_PAGE_WRITECOMBINE 0x00000400
|
||||
|
|
|
@ -35,29 +35,65 @@ void NtAllocateVirtualMemory_shim(
|
|||
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);
|
||||
// X_MEM_*
|
||||
uint32_t allocation_type = SHIM_GET_ARG_32(2);
|
||||
// X_PAGE_*
|
||||
uint32_t protect_bits = SHIM_GET_ARG_32(3);
|
||||
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);
|
||||
|
||||
// I've only seen zero.
|
||||
XEASSERT(unknown == 0);
|
||||
|
||||
XELOGD(
|
||||
XT("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);
|
||||
|
||||
// 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:
|
||||
// X_STATUS_UNSUCCESSFUL
|
||||
// X_STATUS_INVALID_PAGE_PROTECTION
|
||||
// X_STATUS_ACCESS_DENIED
|
||||
// X_STATUS_ALREADY_COMMITTED
|
||||
// X_STATUS_INVALID_HANDLE
|
||||
// X_STATUS_INVALID_PAGE_PROTECTION
|
||||
// X_STATUS_NO_MEMORY
|
||||
SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL);
|
||||
// Must request a size.
|
||||
if (!region_size_value) {
|
||||
SHIM_SET_RETURN(X_STATUS_INVALID_PARAMETER);
|
||||
return;
|
||||
}
|
||||
// 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);
|
||||
}
|
||||
|
||||
void NtFreeVirtualMemory_shim(
|
||||
|
@ -76,19 +112,28 @@ void NtFreeVirtualMemory_shim(
|
|||
uint32_t free_type = SHIM_GET_ARG_32(2);
|
||||
uint32_t unknown = SHIM_GET_ARG_32(3);
|
||||
|
||||
// I've only seen zero.
|
||||
XEASSERT(unknown == 0);
|
||||
|
||||
XELOGD(
|
||||
XT("NtFreeVirtualMemory(%.8X(%.8X), %.8X(%.8X), %.8X, %.8X)"),
|
||||
base_addr_ptr, base_addr_value,
|
||||
region_size_ptr, region_size_value,
|
||||
free_type, unknown);
|
||||
|
||||
// TODO(benvanik): free memory
|
||||
|
||||
// Possible return codes:
|
||||
// X_STATUS_UNSUCCESSFUL
|
||||
// X_STATUS_ACCESS_DENIED
|
||||
// X_STATUS_INVALID_HANDLE
|
||||
// Free.
|
||||
uint32_t flags = 0;
|
||||
uint32_t freed_size = xe_memory_heap_free(state->memory, base_addr_value,
|
||||
flags);
|
||||
if (!freed_size) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,9 +50,12 @@ XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
|||
uint8_t* mem = xe_memory_addr(memory, 0);
|
||||
|
||||
// KeDebugMonitorData (?*)
|
||||
// I'm not sure what this is for, but games make sure it's not null and
|
||||
// exit if it is.
|
||||
resolver->SetVariableMapping(
|
||||
"xboxkrnl.exe", 0x00000059,
|
||||
0x40001000);
|
||||
0x80102100);
|
||||
XESETUINT32BE(mem + 0x80102100, 0x1);
|
||||
|
||||
// XboxHardwareInfo (XboxHardwareInfo_t, 16b)
|
||||
// flags cpu# ? ? ? ? ? ?
|
||||
|
|
|
@ -54,6 +54,8 @@ void RtlImageXexHeaderField_shim(
|
|||
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:
|
||||
|
@ -67,6 +69,10 @@ void RtlImageXexHeaderField_shim(
|
|||
}
|
||||
|
||||
|
||||
//RtlInitializeCriticalSection
|
||||
//RtlEnterCriticalSection
|
||||
//RtlLeaveCriticalSection
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue