Merge pull request #4413 from wwylele/memory-global
Fix shared font addres; Remove global PhysicalToVirtualAddress
This commit is contained in:
commit
fe47243690
4 changed files with 72 additions and 78 deletions
|
@ -142,7 +142,10 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||||
|
|
||||||
if (base_address == 0 && target_address == 0) {
|
if (base_address == 0 && target_address == 0) {
|
||||||
// Calculate the address at which to map the memory block.
|
// Calculate the address at which to map the memory block.
|
||||||
target_address = linear_heap_phys_offset + target_process->GetLinearHeapAreaAddress();
|
// Note: even on new firmware versions, the target address is still in the old linear heap
|
||||||
|
// region. This exception is made to keep the shared font compatibility. See
|
||||||
|
// APT:GetSharedFont for detail.
|
||||||
|
target_address = linear_heap_phys_offset + Memory::LINEAR_HEAP_VADDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vma = target_process->vm_manager.FindVMA(target_address);
|
auto vma = target_process->vm_manager.FindVMA(target_address);
|
||||||
|
|
|
@ -207,10 +207,17 @@ void Module::Interface::GetSharedFont(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
// The shared font has to be relocated to the new address before being passed to the
|
// The shared font has to be relocated to the new address before being passed to the
|
||||||
// application.
|
// application.
|
||||||
auto maybe_vaddr = Memory::PhysicalToVirtualAddress(
|
|
||||||
apt->shared_font_mem->linear_heap_phys_offset + Memory::FCRAM_PADDR);
|
// Note: the target address is still in the old linear heap region even on new firmware
|
||||||
ASSERT(maybe_vaddr);
|
// versions. This exception is made for shared font to resolve the following compatibility
|
||||||
VAddr target_address = *maybe_vaddr;
|
// issue:
|
||||||
|
// The linear heap region changes depending on the kernel version marked in application's
|
||||||
|
// exheader (not the actual version the application is running on). If an application with old
|
||||||
|
// kernel version and an applet with new kernel version run at the same time, and they both use
|
||||||
|
// shared font, different linear heap region would have required shared font to relocate
|
||||||
|
// according to two different addresses at the same time, which is impossible.
|
||||||
|
VAddr target_address =
|
||||||
|
apt->shared_font_mem->linear_heap_phys_offset + Memory::LINEAR_HEAP_VADDR;
|
||||||
if (!apt->shared_font_relocated) {
|
if (!apt->shared_font_relocated) {
|
||||||
BCFNT::RelocateSharedFont(apt->shared_font_mem, target_address);
|
BCFNT::RelocateSharedFont(apt->shared_font_mem, target_address);
|
||||||
apt->shared_font_relocated = true;
|
apt->shared_font_relocated = true;
|
||||||
|
|
|
@ -318,6 +318,25 @@ u8* GetPhysicalPointer(PAddr address) {
|
||||||
return target_pointer;
|
return target_pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// For a rasterizer-accessible PAddr, gets a list of all possible VAddr
|
||||||
|
static std::vector<VAddr> PhysicalToVirtualAddressForRasterizer(PAddr addr) {
|
||||||
|
if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
|
||||||
|
return {addr - VRAM_PADDR + VRAM_VADDR};
|
||||||
|
}
|
||||||
|
if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
|
||||||
|
return {addr - FCRAM_PADDR + LINEAR_HEAP_VADDR, addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR};
|
||||||
|
}
|
||||||
|
if (addr >= FCRAM_PADDR_END && addr < FCRAM_N3DS_PADDR_END) {
|
||||||
|
return {addr - FCRAM_PADDR + NEW_LINEAR_HEAP_VADDR};
|
||||||
|
}
|
||||||
|
// While the physical <-> virtual mapping is 1:1 for the regions supported by the cache,
|
||||||
|
// some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond
|
||||||
|
// the end address of VRAM, causing the Virtual->Physical translation to fail when flushing
|
||||||
|
// parts of the texture.
|
||||||
|
LOG_ERROR(HW_Memory, "Trying to use invalid physical address for rasterizer: {:08X}", addr);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -327,57 +346,46 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
PAddr paddr = start;
|
PAddr paddr = start;
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
|
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
|
||||||
std::optional<VAddr> maybe_vaddr = PhysicalToVirtualAddress(paddr);
|
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
|
||||||
// While the physical <-> virtual mapping is 1:1 for the regions supported by the cache,
|
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||||
// some games (like Pokemon Super Mystery Dungeon) will try to use textures that go beyond
|
|
||||||
// the end address of VRAM, causing the Virtual->Physical translation to fail when flushing
|
|
||||||
// parts of the texture.
|
|
||||||
if (!maybe_vaddr) {
|
|
||||||
LOG_ERROR(HW_Memory,
|
|
||||||
"Trying to flush a cached region to an invalid physical address {:08X}",
|
|
||||||
paddr);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
VAddr vaddr = *maybe_vaddr;
|
|
||||||
|
|
||||||
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
if (cached) {
|
||||||
|
// Switch page type to cached if now cached
|
||||||
if (cached) {
|
switch (page_type) {
|
||||||
// Switch page type to cached if now cached
|
case PageType::Unmapped:
|
||||||
switch (page_type) {
|
// It is not necessary for a process to have this region mapped into its address
|
||||||
case PageType::Unmapped:
|
// space, for example, a system module need not have a VRAM mapping.
|
||||||
// It is not necessary for a process to have this region mapped into its address
|
break;
|
||||||
// space, for example, a system module need not have a VRAM mapping.
|
case PageType::Memory:
|
||||||
break;
|
page_type = PageType::RasterizerCachedMemory;
|
||||||
case PageType::Memory:
|
current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
||||||
page_type = PageType::RasterizerCachedMemory;
|
break;
|
||||||
current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
default:
|
||||||
break;
|
UNREACHABLE();
|
||||||
default:
|
}
|
||||||
UNREACHABLE();
|
} else {
|
||||||
}
|
// Switch page type to uncached if now uncached
|
||||||
} else {
|
switch (page_type) {
|
||||||
// Switch page type to uncached if now uncached
|
case PageType::Unmapped:
|
||||||
switch (page_type) {
|
// It is not necessary for a process to have this region mapped into its address
|
||||||
case PageType::Unmapped:
|
// space, for example, a system module need not have a VRAM mapping.
|
||||||
// It is not necessary for a process to have this region mapped into its address
|
break;
|
||||||
// space, for example, a system module need not have a VRAM mapping.
|
case PageType::RasterizerCachedMemory: {
|
||||||
break;
|
u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
|
||||||
case PageType::RasterizerCachedMemory: {
|
if (pointer == nullptr) {
|
||||||
u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
|
// It's possible that this function has been called while updating the
|
||||||
if (pointer == nullptr) {
|
// pagetable after unmapping a VMA. In that case the underlying VMA will no
|
||||||
// It's possible that this function has been called while updating the pagetable
|
// longer exist, and we should just leave the pagetable entry blank.
|
||||||
// after unmapping a VMA. In that case the underlying VMA will no longer exist,
|
page_type = PageType::Unmapped;
|
||||||
// and we should just leave the pagetable entry blank.
|
} else {
|
||||||
page_type = PageType::Unmapped;
|
page_type = PageType::Memory;
|
||||||
} else {
|
current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
|
||||||
page_type = PageType::Memory;
|
}
|
||||||
current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -820,25 +828,6 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) {
|
||||||
return *paddr;
|
return *paddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) {
|
|
||||||
if (addr == 0) {
|
|
||||||
return 0;
|
|
||||||
} else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
|
|
||||||
return addr - VRAM_PADDR + VRAM_VADDR;
|
|
||||||
} else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
|
|
||||||
return addr - FCRAM_PADDR +
|
|
||||||
Core::System::GetInstance().Kernel().GetCurrentProcess()->GetLinearHeapAreaAddress();
|
|
||||||
} else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
|
|
||||||
return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
|
|
||||||
} else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
|
|
||||||
return addr - IO_AREA_PADDR + IO_AREA_VADDR;
|
|
||||||
} else if (addr >= N3DS_EXTRA_RAM_PADDR && addr < N3DS_EXTRA_RAM_PADDR_END) {
|
|
||||||
return addr - N3DS_EXTRA_RAM_PADDR + N3DS_EXTRA_RAM_VADDR;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 GetFCRAMOffset(u8* pointer) {
|
u32 GetFCRAMOffset(u8* pointer) {
|
||||||
ASSERT(pointer >= fcram.data() && pointer < fcram.data() + fcram.size());
|
ASSERT(pointer >= fcram.data() && pointer < fcram.data() + fcram.size());
|
||||||
return pointer - fcram.data();
|
return pointer - fcram.data();
|
||||||
|
|
|
@ -228,11 +228,6 @@ std::optional<PAddr> TryVirtualToPhysicalAddress(VAddr addr);
|
||||||
*/
|
*/
|
||||||
PAddr VirtualToPhysicalAddress(VAddr addr);
|
PAddr VirtualToPhysicalAddress(VAddr addr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Undoes a mapping performed by VirtualToPhysicalAddress().
|
|
||||||
*/
|
|
||||||
std::optional<VAddr> PhysicalToVirtualAddress(PAddr paddr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a pointer to the memory region beginning at the specified physical address.
|
* Gets a pointer to the memory region beginning at the specified physical address.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue