Special memory functions for system allocs.

This commit is contained in:
Ben Vanik 2015-03-28 15:54:44 -07:00
parent 71eabf7f2b
commit 3a197705bb
12 changed files with 87 additions and 70 deletions

View File

@ -78,9 +78,8 @@ X_STATUS AudioSystem::Setup() {
reinterpret_cast<MMIOWriteCallback>(MMIOWriteRegisterThunk));
// Setup XMA contexts ptr.
registers_.xma_context_array_ptr = uint32_t(
memory()->HeapAlloc(0, kXmaContextSize * kXmaContextCount,
MEMORY_FLAG_PHYSICAL | MEMORY_FLAG_ZERO, 256));
registers_.xma_context_array_ptr = memory()->SystemHeapAlloc(
kXmaContextSize * kXmaContextCount, 256, kSystemHeapPhysical);
// Add all contexts to the free list.
for (int i = kXmaContextCount - 1; i >= 0; --i) {
xma_context_free_list_.push_back(registers_.xma_context_array_ptr +
@ -92,7 +91,7 @@ X_STATUS AudioSystem::Setup() {
thread_state_ =
new ThreadState(emulator_->processor()->runtime(), 0, 0, 16 * 1024, 0);
thread_state_->set_name("Audio Worker");
thread_block_ = (uint32_t)memory()->HeapAlloc(0, 2048, MEMORY_FLAG_ZERO);
thread_block_ = memory()->SystemHeapAlloc(2048);
thread_state_->context()->r[13] = thread_block_;
// Create worker thread.
@ -169,9 +168,9 @@ void AudioSystem::Shutdown() {
thread_.join();
delete thread_state_;
memory()->HeapFree(thread_block_, 0);
memory()->SystemHeapFree(thread_block_);
memory()->HeapFree(registers_.xma_context_array_ptr, 0);
memory()->SystemHeapFree(registers_.xma_context_array_ptr);
}
uint32_t AudioSystem::AllocateXmaContext() {
@ -217,7 +216,7 @@ X_STATUS AudioSystem::RegisterClient(uint32_t callback, uint32_t callback_arg,
unused_clients_.pop();
uint32_t ptr = (uint32_t)memory()->HeapAlloc(0, 0x4, 0);
uint32_t ptr = memory()->SystemHeapAlloc(0x4);
auto mem = memory()->membase();
poly::store_and_swap<uint32_t>(mem + ptr, callback_arg);

View File

@ -55,7 +55,7 @@ Processor::Processor(xe::Memory* memory, ExportResolver* export_resolver)
Processor::~Processor() {
if (interrupt_thread_block_) {
memory_->HeapFree(interrupt_thread_block_, 2048);
memory_->SystemHeapFree(interrupt_thread_block_);
delete interrupt_thread_state_;
}
@ -98,7 +98,7 @@ int Processor::Setup() {
interrupt_thread_state_ = new ThreadState(runtime_, 0, 0, 16 * 1024, 0);
interrupt_thread_state_->set_name("Interrupt");
interrupt_thread_block_ = memory_->HeapAlloc(0, 2048, MEMORY_FLAG_ZERO);
interrupt_thread_block_ = memory_->SystemHeapAlloc(2048);
interrupt_thread_state_->context()->r[13] = interrupt_thread_block_;
return 0;

View File

@ -41,7 +41,7 @@ ThreadState::ThreadState(Runtime* runtime, uint32_t thread_id,
backend_data_ = runtime->backend()->AllocThreadData();
if (!stack_address) {
stack_address_ = memory()->HeapAlloc(0, stack_size, MEMORY_FLAG_ZERO);
stack_address_ = memory()->SystemHeapAlloc(stack_size);
stack_allocated_ = true;
} else {
stack_address_ = stack_address;
@ -86,7 +86,7 @@ ThreadState::~ThreadState() {
free(context_);
if (stack_allocated_) {
memory()->HeapFree(stack_address_, stack_size_);
memory()->SystemHeapFree(stack_address_);
}
}

View File

@ -78,15 +78,9 @@ XThread::~XThread() {
if (thread_state_) {
delete thread_state_;
}
if (scratch_address_) {
kernel_state()->memory()->HeapFree(scratch_address_, 0);
}
if (tls_address_) {
kernel_state()->memory()->HeapFree(tls_address_, 0);
}
if (thread_state_address_) {
kernel_state()->memory()->HeapFree(thread_state_address_, 0);
}
kernel_state()->memory()->SystemHeapFree(scratch_address_);
kernel_state()->memory()->SystemHeapFree(tls_address_);
kernel_state()->memory()->SystemHeapFree(thread_state_address_);
if (thread_handle_) {
// TODO(benvanik): platform kill
@ -151,8 +145,7 @@ X_STATUS XThread::Create() {
// 0x160: last error
// So, at offset 0x100 we have a 4b pointer to offset 200, then have the
// structure.
thread_state_address_ =
(uint32_t)memory()->HeapAlloc(0, 2048, MEMORY_FLAG_ZERO);
thread_state_address_ = memory()->SystemHeapAlloc(2048);
if (!thread_state_address_) {
XELOGW("Unable to allocate thread state block");
return X_STATUS_NO_MEMORY;
@ -166,13 +159,12 @@ X_STATUS XThread::Create() {
// Allocate thread scratch.
// This is used by interrupts/APCs/etc so we can round-trip pointers through.
scratch_size_ = 4 * 16;
scratch_address_ =
(uint32_t)memory()->HeapAlloc(0, scratch_size_, MEMORY_FLAG_ZERO);
scratch_address_ = memory()->SystemHeapAlloc(scratch_size_);
// Allocate TLS block.
const xe_xex2_header_t* header = module->xex_header();
uint32_t tls_size = header->tls_info.slot_count * header->tls_info.data_size;
tls_address_ = (uint32_t)memory()->HeapAlloc(0, tls_size, MEMORY_FLAG_ZERO);
tls_address_ = memory()->SystemHeapAlloc(tls_size);
if (!tls_address_) {
XELOGW("Unable to allocate thread local storage block");
module->Release();
@ -421,9 +413,8 @@ void XThread::DeliverAPCs(void* data) {
// kernel_routine(apc_address, &normal_routine, &normal_context,
// &system_arg1, &system_arg2)
uint64_t kernel_args[] = {
apc_address, thread->scratch_address_ + 0,
thread->scratch_address_ + 4, thread->scratch_address_ + 8,
thread->scratch_address_ + 12,
apc_address, thread->scratch_address_ + 0, thread->scratch_address_ + 4,
thread->scratch_address_ + 8, thread->scratch_address_ + 12,
};
processor->ExecuteInterrupt(0, kernel_routine, kernel_args,
poly::countof(kernel_args));

View File

@ -23,9 +23,7 @@ XUserModule::XUserModule(KernelState* kernel_state, const char* path)
: XModule(kernel_state, path), xex_(nullptr), execution_info_ptr_(0) {}
XUserModule::~XUserModule() {
if (execution_info_ptr_) {
kernel_state()->memory()->HeapFree(execution_info_ptr_, 0);
}
kernel_state()->memory()->SystemHeapFree(execution_info_ptr_);
xe_xex2_dealloc(xex_);
}
@ -116,8 +114,7 @@ X_STATUS XUserModule::LoadFromMemory(const void* addr, const size_t length) {
// Store execution info for later use.
// TODO(benvanik): just put entire xex header in memory somewhere?
execution_info_ptr_ =
uint32_t(kernel_state()->memory()->HeapAlloc(0, 24, MEMORY_FLAG_ZERO, 0));
execution_info_ptr_ = kernel_state()->memory()->SystemHeapAlloc(24);
auto eip = kernel_state()->memory()->membase() + execution_info_ptr_;
const auto& ex = xe_xex2_get_header(xex_)->execution_info;
poly::store_and_swap<uint32_t>(eip + 0x00, ex.media_id);

View File

@ -127,8 +127,8 @@ SHIM_CALL XamAlloc_shim(PPCContext* ppc_state, KernelState* state) {
// Allocate from the heap. Not sure why XAM does this specially, perhaps
// it keeps stuff in a separate heap?
uint64_t ptr = state->memory()->HeapAlloc(0, size, MEMORY_FLAG_ZERO);
SHIM_SET_MEM_32(out_ptr, uint32_t(ptr));
uint32_t ptr = state->memory()->SystemHeapAlloc(size);
SHIM_SET_MEM_32(out_ptr, ptr);
SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}
@ -138,7 +138,7 @@ SHIM_CALL XamFree_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("XamFree(%.8X)", ptr);
state->memory()->HeapFree(ptr, 0);
state->memory()->SystemHeapFree(ptr);
SHIM_SET_RETURN_32(X_ERROR_SUCCESS);
}

View File

@ -418,8 +418,7 @@ SHIM_CALL ExAllocatePoolTypeWithTag_shim(PPCContext* ppc_state,
alignment = 4 * 1024;
}
uint32_t addr = (uint32_t)state->memory()->HeapAlloc(
0, adjusted_size, MEMORY_FLAG_ZERO, alignment);
uint32_t addr = state->memory()->SystemHeapAlloc(adjusted_size, alignment);
SHIM_SET_RETURN_32(addr);
}
@ -429,7 +428,7 @@ SHIM_CALL ExFreePool_shim(PPCContext* ppc_state, KernelState* state) {
XELOGD("ExFreePool(%.8X)", base_address);
state->memory()->HeapFree(base_address, 0);
state->memory()->SystemHeapFree(base_address);
}
SHIM_CALL KeLockL2_shim(PPCContext* ppc_state, KernelState* state) {

View File

@ -50,14 +50,14 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
// Set to a valid value when a remote debugger is attached.
// Offset 0x18 is a 4b pointer to a handler function that seems to take two
// arguments. If we wanted to see what would happen we could fake that.
uint32_t pKeDebugMonitorData = (uint32_t)memory_->HeapAlloc(0, 256, 0);
uint32_t pKeDebugMonitorData = memory_->SystemHeapAlloc(256);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeDebugMonitorData, pKeDebugMonitorData);
poly::store_and_swap<uint32_t>(mem + pKeDebugMonitorData, 0);
// KeCertMonitorData (?*)
// Always set to zero, ignored.
uint32_t pKeCertMonitorData = (uint32_t)memory_->HeapAlloc(0, 4, 0);
uint32_t pKeCertMonitorData = memory_->SystemHeapAlloc(4);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeCertMonitorData, pKeCertMonitorData);
poly::store_and_swap<uint32_t>(mem + pKeCertMonitorData, 0);
@ -70,7 +70,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
//
// aomega08 says the value is 0x02000817, bit 27: debug mode on.
// When that is set, though, allocs crash in weird ways.
uint32_t pXboxHardwareInfo = (uint32_t)memory_->HeapAlloc(0, 16, 0);
uint32_t pXboxHardwareInfo = memory_->SystemHeapAlloc(16);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::XboxHardwareInfo, pXboxHardwareInfo);
poly::store_and_swap<uint32_t>(mem + pXboxHardwareInfo + 0, 0); // flags
@ -87,11 +87,11 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
// 0x80101000 <- our module structure
// 0x80101058 <- pointer to xex header
// 0x80101100 <- xex header base
uint32_t ppXexExecutableModuleHandle = (uint32_t)memory_->HeapAlloc(0, 4, 0);
uint32_t ppXexExecutableModuleHandle = memory_->SystemHeapAlloc(4);
export_resolver_->SetVariableMapping("xboxkrnl.exe",
ordinals::XexExecutableModuleHandle,
ppXexExecutableModuleHandle);
uint32_t pXexExecutableModuleHandle = (uint32_t)memory_->HeapAlloc(0, 256, 0);
uint32_t pXexExecutableModuleHandle = memory_->SystemHeapAlloc(256);
poly::store_and_swap<uint32_t>(mem + ppXexExecutableModuleHandle,
pXexExecutableModuleHandle);
poly::store_and_swap<uint32_t>(mem + pXexExecutableModuleHandle + 0x58,
@ -101,7 +101,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
// The name of the xex. Not sure this is ever really used on real devices.
// Perhaps it's how swap disc/etc data is sent?
// Always set to "default.xex" (with quotes) for now.
uint32_t pExLoadedCommandLine = (uint32_t)memory_->HeapAlloc(0, 1024, 0);
uint32_t pExLoadedCommandLine = memory_->SystemHeapAlloc(1024);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::ExLoadedCommandLine, pExLoadedCommandLine);
char command_line[] = "\"default.xex\"";
@ -111,7 +111,7 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
// XboxKrnlVersion (8b)
// Kernel version, looks like 2b.2b.2b.2b.
// I've only seen games check >=, so we just fake something here.
uint32_t pXboxKrnlVersion = (uint32_t)memory_->HeapAlloc(0, 8, 0);
uint32_t pXboxKrnlVersion = memory_->SystemHeapAlloc(8);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::XboxKrnlVersion, pXboxKrnlVersion);
poly::store_and_swap<uint16_t>(mem + pXboxKrnlVersion + 0, 2);
@ -123,23 +123,22 @@ XboxkrnlModule::XboxkrnlModule(Emulator* emulator, KernelState* kernel_state)
// KeTimeStampBundle (ad)
// This must be updated during execution, at 1ms intevals.
// We setup a system timer here to do that.
uint32_t pKeTimeStampBundle = (uint32_t)memory_->HeapAlloc(0, 24, 0);
uint32_t pKeTimeStampBundle = memory_->SystemHeapAlloc(24);
export_resolver_->SetVariableMapping(
"xboxkrnl.exe", ordinals::KeTimeStampBundle, pKeTimeStampBundle);
poly::store_and_swap<uint64_t>(mem + pKeTimeStampBundle + 0, 0);
poly::store_and_swap<uint64_t>(mem + pKeTimeStampBundle + 8, 0);
poly::store_and_swap<uint32_t>(mem + pKeTimeStampBundle + 16, GetTickCount());
poly::store_and_swap<uint32_t>(mem + pKeTimeStampBundle + 20, 0);
CreateTimerQueueTimer(&timestamp_timer_, nullptr,
[](PVOID param, BOOLEAN timer_or_wait_fired) {
auto timestamp_bundle =
reinterpret_cast<uint8_t*>(param);
poly::store_and_swap<uint32_t>(timestamp_bundle + 16,
GetTickCount());
},
mem + pKeTimeStampBundle, 0,
1, // 1ms
WT_EXECUTEINTIMERTHREAD);
CreateTimerQueueTimer(
&timestamp_timer_, nullptr,
[](PVOID param, BOOLEAN timer_or_wait_fired) {
auto timestamp_bundle = reinterpret_cast<uint8_t*>(param);
poly::store_and_swap<uint32_t>(timestamp_bundle + 16, GetTickCount());
},
mem + pKeTimeStampBundle, 0,
1, // 1ms
WT_EXECUTEINTIMERTHREAD);
}
void XboxkrnlModule::RegisterExportTable(ExportResolver* export_resolver) {
@ -149,14 +148,14 @@ void XboxkrnlModule::RegisterExportTable(ExportResolver* export_resolver) {
return;
}
// Build the export table used for resolution.
// Build the export table used for resolution.
#include "xenia/kernel/util/export_table_pre.inc"
static KernelExport xboxkrnl_export_table[] = {
#include "xenia/kernel/xboxkrnl_table.inc"
};
#include "xenia/kernel/util/export_table_post.inc"
export_resolver->RegisterTable("xboxkrnl.exe", xboxkrnl_export_table,
poly::countof(xboxkrnl_export_table));
poly::countof(xboxkrnl_export_table));
}
XboxkrnlModule::~XboxkrnlModule() {

View File

@ -205,7 +205,7 @@ SHIM_CALL RtlFreeAnsiString_shim(PPCContext* ppc_state, KernelState* state) {
return;
}
uint32_t length = SHIM_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
state->memory()->SystemHeapFree(buffer);
SHIM_SET_MEM_16(string_ptr + 0, 0);
SHIM_SET_MEM_16(string_ptr + 2, 0);
@ -260,7 +260,7 @@ SHIM_CALL RtlFreeUnicodeString_shim(PPCContext* ppc_state, KernelState* state) {
return;
}
uint32_t length = SHIM_MEM_16(string_ptr + 2);
state->memory()->HeapFree(buffer, length);
state->memory()->SystemHeapFree(buffer);
SHIM_SET_MEM_16(string_ptr + 0, 0);
SHIM_SET_MEM_16(string_ptr + 2, 0);
@ -292,8 +292,8 @@ SHIM_CALL RtlUnicodeStringToAnsiString_shim(PPCContext* ppc_state,
X_STATUS result = X_STATUS_SUCCESS;
if (alloc_dest) {
auto buffer_ptr =
state->memory()->HeapAlloc(0, uint32_t(ansi_str.size() + 1), 0);
uint32_t buffer_ptr =
state->memory()->SystemHeapAlloc(uint32_t(ansi_str.size() + 1));
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()));

View File

@ -452,28 +452,32 @@ void xe::kernel::xboxkrnl::RegisterVideoExports(ExportResolver* export_resolver,
// VdGlobalDevice (4b)
// 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);
uint32_t pVdGlobalDevice =
memory->SystemHeapAlloc(4, 32, kSystemHeapPhysical);
export_resolver->SetVariableMapping("xboxkrnl.exe", ordinals::VdGlobalDevice,
pVdGlobalDevice);
poly::store_and_swap<uint32_t>(mem + pVdGlobalDevice, 0);
// VdGlobalXamDevice (4b)
// Pointer to the XAM D3D device, which we don't have.
uint32_t pVdGlobalXamDevice = (uint32_t)memory->HeapAlloc(0, 4, 0);
uint32_t pVdGlobalXamDevice =
memory->SystemHeapAlloc(4, 32, kSystemHeapPhysical);
export_resolver->SetVariableMapping(
"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);
uint32_t pVdGpuClockInMHz =
memory->SystemHeapAlloc(4, 32, kSystemHeapPhysical);
export_resolver->SetVariableMapping("xboxkrnl.exe", ordinals::VdGpuClockInMHz,
pVdGpuClockInMHz);
poly::store_and_swap<uint32_t>(mem + pVdGpuClockInMHz, 500);
// VdHSIOCalibrationLock (28b)
// CriticalSection.
uint32_t pVdHSIOCalibrationLock = (uint32_t)memory->HeapAlloc(0, 28, 0);
uint32_t pVdHSIOCalibrationLock =
memory->SystemHeapAlloc(28, 32, kSystemHeapPhysical);
export_resolver->SetVariableMapping(
"xboxkrnl.exe", ordinals::VdHSIOCalibrationLock, pVdHSIOCalibrationLock);
auto hsio_lock =

View File

@ -267,18 +267,18 @@ void Memory::UnmapViews() {
void Memory::Zero(uint32_t address, uint32_t size) {
uint8_t* p = membase_ + address;
memset(p, 0, size);
std::memset(p, 0, size);
}
void Memory::Fill(uint32_t address, uint32_t size, uint8_t value) {
uint8_t* p = membase_ + address;
memset(p, value, size);
std::memset(p, value, size);
}
void Memory::Copy(uint32_t dest, uint32_t src, uint32_t size) {
uint8_t* pdest = membase_ + dest;
const uint8_t* psrc = membase_ + src;
memcpy(pdest, psrc, size);
std::memcpy(pdest, psrc, size);
}
uint32_t Memory::SearchAligned(uint32_t start, uint32_t end,
@ -328,6 +328,25 @@ void Memory::CancelWriteWatch(uintptr_t watch_handle) {
mmio_handler_->CancelWriteWatch(watch_handle);
}
uint32_t Memory::SystemHeapAlloc(uint32_t size, uint32_t alignment,
uint32_t system_heap_flags) {
// TODO(benvanik): lightweight pool.
bool is_physical = !!(system_heap_flags & kSystemHeapPhysical);
uint32_t flags = MEMORY_FLAG_ZERO;
if (is_physical) {
flags |= MEMORY_FLAG_PHYSICAL;
}
return HeapAlloc(0, size, flags, alignment);
}
void Memory::SystemHeapFree(uint32_t address) {
if (!address) {
return;
}
// TODO(benvanik): lightweight pool.
HeapFree(address, 0);
}
uint32_t Memory::HeapAlloc(uint32_t base_address, uint32_t size, uint32_t flags,
uint32_t alignment) {
// If we were given a base address we are outside of the normal heap and

View File

@ -21,6 +21,12 @@
namespace xe {
enum SystemHeapFlag : uint32_t {
kSystemHeapVirtual = 1 << 0,
kSystemHeapPhysical = 1 << 1,
kSystemHeapDefault = kSystemHeapVirtual,
};
class MemoryHeap;
// TODO(benvanik): move to heap.
@ -75,6 +81,9 @@ class Memory {
void* callback_context, void* callback_data);
void CancelWriteWatch(uintptr_t watch_handle);
uint32_t SystemHeapAlloc(uint32_t size, uint32_t alignment = 0x20,
uint32_t system_heap_flags = kSystemHeapDefault);
void SystemHeapFree(uint32_t address);
uint32_t HeapAlloc(uint32_t base_address, uint32_t size, uint32_t flags,
uint32_t alignment = 0x20);
int HeapFree(uint32_t address, uint32_t size);