[Memory] Refactor GetPhysicalAddress and use it for XMA, resolve #1448
This commit is contained in:
parent
3e6c2bb47c
commit
7e6bf8022f
|
@ -113,9 +113,7 @@ X_STATUS XmaDecoder::Setup(kernel::KernelState* kernel_state) {
|
||||||
context_data_last_ptr_ =
|
context_data_last_ptr_ =
|
||||||
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
|
context_data_first_ptr_ + (sizeof(XMA_CONTEXT_DATA) * kContextCount - 1);
|
||||||
register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 =
|
register_file_[XE_XMA_REG_CONTEXT_ARRAY_ADDRESS].u32 =
|
||||||
memory()
|
memory()->GetPhysicalAddress(context_data_first_ptr_);
|
||||||
->LookupHeap(context_data_first_ptr_)
|
|
||||||
->GetPhysicalAddress(context_data_first_ptr_);
|
|
||||||
|
|
||||||
// Setup XMA contexts.
|
// Setup XMA contexts.
|
||||||
for (int i = 0; i < kContextCount; ++i) {
|
for (int i = 0; i < kContextCount; ++i) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include "xenia/apu/audio_system.h"
|
#include "xenia/apu/audio_system.h"
|
||||||
#include "xenia/apu/xma_decoder.h"
|
#include "xenia/apu/xma_decoder.h"
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/emulator.h"
|
#include "xenia/emulator.h"
|
||||||
#include "xenia/kernel/kernel_state.h"
|
#include "xenia/kernel/kernel_state.h"
|
||||||
|
@ -184,9 +185,19 @@ DECLARE_XBOXKRNL_EXPORT2(XMASetInputBufferReadOffset, kAudio, kImplemented,
|
||||||
|
|
||||||
dword_result_t XMASetInputBuffer0(lpvoid_t context_ptr, lpvoid_t buffer,
|
dword_result_t XMASetInputBuffer0(lpvoid_t context_ptr, lpvoid_t buffer,
|
||||||
dword_t packet_count) {
|
dword_t packet_count) {
|
||||||
|
uint32_t buffer_physical_address =
|
||||||
|
kernel_memory()->GetPhysicalAddress(buffer.guest_address());
|
||||||
|
assert_true(buffer_physical_address != UINT32_MAX);
|
||||||
|
if (buffer_physical_address == UINT32_MAX) {
|
||||||
|
// Xenia-specific safety check.
|
||||||
|
XELOGE("XMASetInputBuffer0: Invalid buffer virtual address %.8X",
|
||||||
|
buffer.guest_address());
|
||||||
|
return X_E_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
XMA_CONTEXT_DATA context(context_ptr);
|
XMA_CONTEXT_DATA context(context_ptr);
|
||||||
|
|
||||||
context.input_buffer_0_ptr = buffer.guest_address();
|
context.input_buffer_0_ptr = buffer_physical_address;
|
||||||
context.input_buffer_0_packet_count = packet_count;
|
context.input_buffer_0_packet_count = packet_count;
|
||||||
|
|
||||||
context.Store(context_ptr);
|
context.Store(context_ptr);
|
||||||
|
@ -215,9 +226,19 @@ DECLARE_XBOXKRNL_EXPORT2(XMASetInputBuffer0Valid, kAudio, kImplemented,
|
||||||
|
|
||||||
dword_result_t XMASetInputBuffer1(lpvoid_t context_ptr, lpvoid_t buffer,
|
dword_result_t XMASetInputBuffer1(lpvoid_t context_ptr, lpvoid_t buffer,
|
||||||
dword_t packet_count) {
|
dword_t packet_count) {
|
||||||
|
uint32_t buffer_physical_address =
|
||||||
|
kernel_memory()->GetPhysicalAddress(buffer.guest_address());
|
||||||
|
assert_true(buffer_physical_address != UINT32_MAX);
|
||||||
|
if (buffer_physical_address == UINT32_MAX) {
|
||||||
|
// Xenia-specific safety check.
|
||||||
|
XELOGE("XMASetInputBuffer1: Invalid buffer virtual address %.8X",
|
||||||
|
buffer.guest_address());
|
||||||
|
return X_E_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
XMA_CONTEXT_DATA context(context_ptr);
|
XMA_CONTEXT_DATA context(context_ptr);
|
||||||
|
|
||||||
context.input_buffer_1_ptr = buffer.guest_address();
|
context.input_buffer_1_ptr = buffer_physical_address;
|
||||||
context.input_buffer_1_packet_count = packet_count;
|
context.input_buffer_1_packet_count = packet_count;
|
||||||
|
|
||||||
context.Store(context_ptr);
|
context.Store(context_ptr);
|
||||||
|
|
|
@ -502,13 +502,11 @@ dword_result_t MmGetPhysicalAddress(dword_t base_address) {
|
||||||
// _In_ PVOID BaseAddress
|
// _In_ PVOID BaseAddress
|
||||||
// );
|
// );
|
||||||
// base_address = result of MmAllocatePhysicalMemory.
|
// base_address = result of MmAllocatePhysicalMemory.
|
||||||
assert_true(base_address >= 0xA0000000);
|
uint32_t physical_address = kernel_memory()->GetPhysicalAddress(base_address);
|
||||||
|
assert_true(physical_address != UINT32_MAX);
|
||||||
uint32_t physical_address = base_address & 0x1FFFFFFF;
|
if (physical_address == UINT32_MAX) {
|
||||||
if (base_address >= 0xE0000000) {
|
physical_address = 0;
|
||||||
physical_address += 0x1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return physical_address;
|
return physical_address;
|
||||||
}
|
}
|
||||||
DECLARE_XBOXKRNL_EXPORT1(MmGetPhysicalAddress, kMemory, kImplemented);
|
DECLARE_XBOXKRNL_EXPORT1(MmGetPhysicalAddress, kMemory, kImplemented);
|
||||||
|
|
|
@ -362,13 +362,26 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
|
||||||
xe::copy_and_swap_32_unaligned(
|
xe::copy_and_swap_32_unaligned(
|
||||||
&fetch, reinterpret_cast<uint32_t*>(fetch_ptr.host_address()), 6);
|
&fetch, reinterpret_cast<uint32_t*>(fetch_ptr.host_address()), 6);
|
||||||
|
|
||||||
|
// Kernel virtual -> GPU physical.
|
||||||
|
uint32_t frontbuffer_address = fetch.base_address << 12;
|
||||||
|
assert_true(*frontbuffer_ptr == frontbuffer_address);
|
||||||
|
frontbuffer_address =
|
||||||
|
kernel_memory()->GetPhysicalAddress(frontbuffer_address);
|
||||||
|
assert_true(frontbuffer_address != UINT32_MAX);
|
||||||
|
if (frontbuffer_address == UINT32_MAX) {
|
||||||
|
// Xenia-specific safety check.
|
||||||
|
XELOGE("VdSwap: Invalid front buffer virtual address 0x%.8X",
|
||||||
|
fetch.base_address << 12);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fetch.base_address = frontbuffer_address >> 12;
|
||||||
|
|
||||||
auto texture_format = gpu::TextureFormat(texture_format_ptr.value());
|
auto texture_format = gpu::TextureFormat(texture_format_ptr.value());
|
||||||
auto color_space = *color_space_ptr;
|
auto color_space = *color_space_ptr;
|
||||||
assert_true(texture_format == gpu::TextureFormat::k_8_8_8_8 ||
|
assert_true(texture_format == gpu::TextureFormat::k_8_8_8_8 ||
|
||||||
texture_format ==
|
texture_format ==
|
||||||
gpu::TextureFormat::k_2_10_10_10_AS_16_16_16_16);
|
gpu::TextureFormat::k_2_10_10_10_AS_16_16_16_16);
|
||||||
assert_true(color_space == 0); // RGB(0)
|
assert_true(color_space == 0); // RGB(0)
|
||||||
assert_true(*frontbuffer_ptr == fetch.base_address << 12);
|
|
||||||
assert_true(*width == 1 + fetch.size_2d.width);
|
assert_true(*width == 1 + fetch.size_2d.width);
|
||||||
assert_true(*height == 1 + fetch.size_2d.height);
|
assert_true(*height == 1 + fetch.size_2d.height);
|
||||||
|
|
||||||
|
@ -379,14 +392,6 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
|
||||||
// use this method.
|
// use this method.
|
||||||
buffer_ptr.Zero(64 * 4);
|
buffer_ptr.Zero(64 * 4);
|
||||||
|
|
||||||
// virtual -> physical
|
|
||||||
// Doom 3: BFG Edition uses front buffers from the 0xE0000000 range with 4 KB
|
|
||||||
// offset, so & 0x1FFFF is not enough for this.
|
|
||||||
fetch.base_address = kernel_memory()
|
|
||||||
->LookupHeap(fetch.base_address << 12)
|
|
||||||
->GetPhysicalAddress(fetch.base_address << 12) >>
|
|
||||||
12;
|
|
||||||
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
auto dwords = buffer_ptr.as_array<uint32_t>();
|
auto dwords = buffer_ptr.as_array<uint32_t>();
|
||||||
|
|
||||||
|
@ -402,9 +407,7 @@ void VdSwap(lpvoid_t buffer_ptr, // ptr into primary ringbuffer
|
||||||
|
|
||||||
dwords[offset++] = xenos::MakePacketType3(xenos::PM4_XE_SWAP, 4);
|
dwords[offset++] = xenos::MakePacketType3(xenos::PM4_XE_SWAP, 4);
|
||||||
dwords[offset++] = 'SWAP';
|
dwords[offset++] = 'SWAP';
|
||||||
dwords[offset++] = kernel_memory()
|
dwords[offset++] = frontbuffer_address;
|
||||||
->LookupHeap(*frontbuffer_ptr)
|
|
||||||
->GetPhysicalAddress(*frontbuffer_ptr);
|
|
||||||
|
|
||||||
dwords[offset++] = *width;
|
dwords[offset++] = *width;
|
||||||
dwords[offset++] = *height;
|
dwords[offset++] = *height;
|
||||||
|
|
|
@ -369,6 +369,14 @@ uint32_t Memory::HostToGuestVirtualThunk(const void* context,
|
||||||
host_address);
|
host_address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Memory::GetPhysicalAddress(uint32_t address) const {
|
||||||
|
const BaseHeap* heap = LookupHeap(address);
|
||||||
|
if (!heap || !heap->IsGuestPhysicalHeap()) {
|
||||||
|
return UINT32_MAX;
|
||||||
|
}
|
||||||
|
return static_cast<const PhysicalHeap*>(heap)->GetPhysicalAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
void Memory::Zero(uint32_t address, uint32_t size) {
|
void Memory::Zero(uint32_t address, uint32_t size) {
|
||||||
std::memset(TranslateVirtual(address), 0, size);
|
std::memset(TranslateVirtual(address), 0, size);
|
||||||
}
|
}
|
||||||
|
@ -440,8 +448,7 @@ bool Memory::AccessViolationCallback(void* host_address, bool is_write) {
|
||||||
}
|
}
|
||||||
uint32_t virtual_address = HostToGuestVirtual(host_address);
|
uint32_t virtual_address = HostToGuestVirtual(host_address);
|
||||||
BaseHeap* heap = LookupHeap(virtual_address);
|
BaseHeap* heap = LookupHeap(virtual_address);
|
||||||
if (heap == &heaps_.vA0000000 || heap == &heaps_.vC0000000 ||
|
if (heap->IsGuestPhysicalHeap()) {
|
||||||
heap == &heaps_.vE0000000) {
|
|
||||||
// Will be rounded to physical page boundaries internally, so just pass 1 as
|
// Will be rounded to physical page boundaries internally, so just pass 1 as
|
||||||
// the length - guranteed not to cross page boundaries also.
|
// the length - guranteed not to cross page boundaries also.
|
||||||
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(virtual_address, 1,
|
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(virtual_address, 1,
|
||||||
|
@ -461,8 +468,7 @@ bool Memory::TriggerWatches(uint32_t virtual_address, uint32_t length,
|
||||||
bool is_write, bool unwatch_exact_range,
|
bool is_write, bool unwatch_exact_range,
|
||||||
bool unprotect) {
|
bool unprotect) {
|
||||||
BaseHeap* heap = LookupHeap(virtual_address);
|
BaseHeap* heap = LookupHeap(virtual_address);
|
||||||
if (heap == &heaps_.vA0000000 || heap == &heaps_.vC0000000 ||
|
if (heap->IsGuestPhysicalHeap()) {
|
||||||
heap == &heaps_.vE0000000) {
|
|
||||||
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(
|
return static_cast<PhysicalHeap*>(heap)->TriggerWatches(
|
||||||
virtual_address, length, is_write, unwatch_exact_range, unprotect);
|
virtual_address, length, is_write, unwatch_exact_range, unprotect);
|
||||||
}
|
}
|
||||||
|
@ -1274,16 +1280,6 @@ bool BaseHeap::QueryProtect(uint32_t address, uint32_t* out_protect) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t BaseHeap::GetPhysicalAddress(uint32_t address) {
|
|
||||||
// Only valid for memory in this range - will be bogus if the origin was
|
|
||||||
// outside of it.
|
|
||||||
uint32_t physical_address = address & 0x1FFFFFFF;
|
|
||||||
if (address >= 0xE0000000) {
|
|
||||||
physical_address += 0x1000;
|
|
||||||
}
|
|
||||||
return physical_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualHeap::VirtualHeap() = default;
|
VirtualHeap::VirtualHeap() = default;
|
||||||
|
|
||||||
VirtualHeap::~VirtualHeap() = default;
|
VirtualHeap::~VirtualHeap() = default;
|
||||||
|
@ -1724,4 +1720,14 @@ bool PhysicalHeap::TriggerWatches(uint32_t virtual_address, uint32_t length,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t PhysicalHeap::GetPhysicalAddress(uint32_t address) const {
|
||||||
|
assert_true(address >= heap_base_);
|
||||||
|
address -= heap_base_;
|
||||||
|
assert_true(address <= heap_size_);
|
||||||
|
if (heap_base_ >= 0xE0000000) {
|
||||||
|
address += 0x1000;
|
||||||
|
}
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -171,9 +171,8 @@ class BaseHeap {
|
||||||
// address.
|
// address.
|
||||||
bool QueryProtect(uint32_t address, uint32_t* out_protect);
|
bool QueryProtect(uint32_t address, uint32_t* out_protect);
|
||||||
|
|
||||||
// Gets the physical address of a virtual address.
|
// Whether the heap is a guest virtual memory mapping of the physical memory.
|
||||||
// This is only valid if the page is backed by a physical allocation.
|
virtual bool IsGuestPhysicalHeap() const { return false; }
|
||||||
uint32_t GetPhysicalAddress(uint32_t address);
|
|
||||||
|
|
||||||
bool Save(ByteStream* stream);
|
bool Save(ByteStream* stream);
|
||||||
bool Restore(ByteStream* stream);
|
bool Restore(ByteStream* stream);
|
||||||
|
@ -244,6 +243,9 @@ class PhysicalHeap : public BaseHeap {
|
||||||
bool TriggerWatches(uint32_t virtual_address, uint32_t length, bool is_write,
|
bool TriggerWatches(uint32_t virtual_address, uint32_t length, bool is_write,
|
||||||
bool unwatch_exact_range, bool unprotect = true);
|
bool unwatch_exact_range, bool unprotect = true);
|
||||||
|
|
||||||
|
bool IsGuestPhysicalHeap() const override { return true; }
|
||||||
|
uint32_t GetPhysicalAddress(uint32_t address) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VirtualHeap* parent_heap_;
|
VirtualHeap* parent_heap_;
|
||||||
|
|
||||||
|
@ -317,6 +319,10 @@ class Memory {
|
||||||
// Note that the contents at the returned host address are big-endian.
|
// Note that the contents at the returned host address are big-endian.
|
||||||
uint32_t HostToGuestVirtual(const void* host_address) const;
|
uint32_t HostToGuestVirtual(const void* host_address) const;
|
||||||
|
|
||||||
|
// Returns the guest physical address for the guest virtual address, or
|
||||||
|
// UINT32_MAX if it can't be obtained.
|
||||||
|
uint32_t GetPhysicalAddress(uint32_t address) const;
|
||||||
|
|
||||||
// Zeros out a range of memory at the given guest address.
|
// Zeros out a range of memory at the given guest address.
|
||||||
void Zero(uint32_t address, uint32_t size);
|
void Zero(uint32_t address, uint32_t size);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue