2013-01-13 07:25:41 +00:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* 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. *
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <xenia/core/memory.h>
|
|
|
|
|
2013-01-30 09:45:55 +00:00
|
|
|
#if !XE_PLATFORM(WIN32)
|
2013-01-13 07:25:41 +00:00
|
|
|
#include <sys/mman.h>
|
2013-01-30 09:45:55 +00:00
|
|
|
#endif // WIN32
|
2013-01-13 07:25:41 +00:00
|
|
|
|
2013-01-29 05:36:03 +00:00
|
|
|
#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>
|
|
|
|
|
2013-01-13 07:25:41 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Memory map:
|
|
|
|
* 0x00000000 - 0x40000000 (1024mb) - virtual 4k pages
|
|
|
|
* 0x40000000 - 0x80000000 (1024mb) - virtual 64k pages
|
|
|
|
* 0x80000000 - 0x8C000000 ( 192mb) - xex 64k pages
|
|
|
|
* 0x8C000000 - 0x90000000 ( 64mb) - xex 64k pages (encrypted)
|
|
|
|
* 0x90000000 - 0xA0000000 ( 256mb) - xex 4k pages
|
|
|
|
* 0xA0000000 - 0xC0000000 ( 512mb) - physical 64k pages
|
|
|
|
*
|
|
|
|
* We use the host OS to create an entire addressable range for this. That way
|
|
|
|
* we don't have to emulate a TLB. It'd be really cool to pass through page
|
|
|
|
* sizes or use madvice to let the OS know what to expect.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
struct xe_memory {
|
|
|
|
xe_ref_t ref;
|
|
|
|
|
|
|
|
size_t length;
|
|
|
|
void *ptr;
|
2013-01-29 05:36:03 +00:00
|
|
|
|
|
|
|
mspace heap;
|
2013-01-13 07:25:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
xe_memory_ref xe_memory_create(xe_pal_ref pal, xe_memory_options_t options) {
|
2013-01-29 05:36:03 +00:00
|
|
|
uint32_t offset;
|
|
|
|
uint32_t mspace_size;
|
|
|
|
|
2013-01-13 07:25:41 +00:00
|
|
|
xe_memory_ref memory = (xe_memory_ref)xe_calloc(sizeof(xe_memory));
|
|
|
|
xe_ref_init((xe_ref)memory);
|
|
|
|
|
|
|
|
memory->length = 0xC0000000;
|
2013-01-30 09:45:55 +00:00
|
|
|
|
|
|
|
#if XE_PLATFORM(WIN32)
|
|
|
|
memory->ptr = VirtualAlloc(0, memory->length,
|
|
|
|
MEM_COMMIT | MEM_RESERVE,
|
|
|
|
PAGE_READWRITE);
|
|
|
|
#else
|
2013-01-13 07:25:41 +00:00
|
|
|
memory->ptr = mmap(0, memory->length, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
|
|
|
XEEXPECT(memory->ptr != MAP_FAILED);
|
2013-01-30 09:45:55 +00:00
|
|
|
#endif // WIN32
|
|
|
|
XEEXPECTNOTNULL(memory->ptr);
|
2013-01-13 07:25:41 +00:00
|
|
|
|
2013-01-29 05:36:03 +00:00
|
|
|
// 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);
|
|
|
|
|
2013-01-13 07:25:41 +00:00
|
|
|
return memory;
|
|
|
|
|
|
|
|
XECLEANUP:
|
|
|
|
xe_memory_release(memory);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void xe_memory_dealloc(xe_memory_ref memory) {
|
2013-01-30 09:45:55 +00:00
|
|
|
if (memory->heap) {
|
|
|
|
destroy_mspace(memory->heap);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if XE_PLATFORM(WIN32)
|
|
|
|
XEIGNORE(VirtualFree(memory->ptr, memory->length, MEM_RELEASE));
|
|
|
|
#else
|
2013-01-13 07:25:41 +00:00
|
|
|
munmap(memory->ptr, memory->length);
|
2013-01-30 09:45:55 +00:00
|
|
|
#endif // WIN32
|
2013-01-13 07:25:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
xe_memory_ref xe_memory_retain(xe_memory_ref memory) {
|
|
|
|
xe_ref_retain((xe_ref)memory);
|
|
|
|
return memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
void xe_memory_release(xe_memory_ref memory) {
|
|
|
|
xe_ref_release((xe_ref)memory, (xe_ref_dealloc_t)xe_memory_dealloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t xe_memory_get_length(xe_memory_ref memory) {
|
|
|
|
return memory->length;
|
|
|
|
}
|
|
|
|
|
2013-01-14 05:25:28 +00:00
|
|
|
uint8_t *xe_memory_addr(xe_memory_ref memory, uint32_t guest_addr) {
|
2013-01-13 07:25:41 +00:00
|
|
|
return (uint8_t*)memory->ptr + guest_addr;
|
|
|
|
}
|
2013-01-18 07:17:49 +00:00
|
|
|
|
|
|
|
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) {
|
|
|
|
XEASSERT(start <= end);
|
|
|
|
const uint32_t *p = (const uint32_t*)xe_memory_addr(memory, start);
|
|
|
|
const uint32_t *pe = (const uint32_t*)xe_memory_addr(memory, end);
|
|
|
|
while (p != pe) {
|
|
|
|
if (*p == values[0]) {
|
|
|
|
const uint32_t *pc = p + 1;
|
|
|
|
size_t matched = 1;
|
|
|
|
for (size_t n = 1; n < value_count; n++, pc++) {
|
|
|
|
if (*pc != values[n]) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
matched++;
|
|
|
|
}
|
|
|
|
if (matched == value_count) {
|
|
|
|
return (uint32_t)((uint8_t*)p - (uint8_t*)memory->ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2013-01-29 05:36:03 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|