mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-22 05:40:01 -06:00
Support for dynamic BAT modification (dynamic-bat).
Fundamentally, all this does is enforce the invariant that we always translate effective addresses based on the current BAT registers and page table before we do anything else with them. This change can be logically divided into three parts. The first part is creating a table to represent the current BAT state, and keeping it up to date (PowerPC::IBATUpdated, PowerPC::DBATUpdated, etc.). This does nothing by itself, but it's necessary for the other parts. The second part (mostly in MMU.cpp) is simply removing all the hardcoded checks for specific untranslated addresses, and consistently translating addresses using the current BAT configuration. Very straightforward, but a lot of code changes because we hardcoded assumptions all over the place. The third part (mostly in Memmap.cpp) is making the fastmem arena reflect the current BAT configuration. We do this by redoing the mapping (calling memmap()) based on the BAT table whenever it changes. One additional minor change is that translation can fail in two ways: either the segment is a direct store segment, or page table lookup failed. The difference doesn't usually matter, but the difference affects cache instructions, like dcbz.
This commit is contained in:
@ -157,118 +157,3 @@ u8* MemArena::FindMemoryBase()
|
||||
return static_cast<u8*>(base);
|
||||
#endif
|
||||
}
|
||||
|
||||
// yeah, this could also be done in like two bitwise ops...
|
||||
#define SKIP(a_flags, b_flags) \
|
||||
if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) \
|
||||
continue; \
|
||||
if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) \
|
||||
continue;
|
||||
|
||||
static bool Memory_TryBase(u8* base, MemoryView* views, int num_views, u32 flags, MemArena* arena)
|
||||
{
|
||||
// OK, we know where to find free space. Now grab it!
|
||||
// We just mimic the popular BAT setup.
|
||||
|
||||
int i;
|
||||
for (i = 0; i < num_views; i++)
|
||||
{
|
||||
MemoryView* view = &views[i];
|
||||
void* view_base;
|
||||
bool use_sw_mirror;
|
||||
|
||||
SKIP(flags, view->flags);
|
||||
|
||||
#if _ARCH_64
|
||||
// On 64-bit, we map the same file position multiple times, so we
|
||||
// don't need the software fallback for the mirrors.
|
||||
view_base = base + view->virtual_address;
|
||||
use_sw_mirror = false;
|
||||
#else
|
||||
// On 32-bit, we don't have the actual address space to store all
|
||||
// the mirrors, so we just map the fallbacks somewhere in our address
|
||||
// space and use the software fallbacks for mirroring.
|
||||
view_base = base + (view->virtual_address & 0x3FFFFFFF);
|
||||
use_sw_mirror = true;
|
||||
#endif
|
||||
|
||||
if (use_sw_mirror && (view->flags & MV_MIRROR_PREVIOUS))
|
||||
{
|
||||
view->view_ptr = views[i - 1].view_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
view->mapped_ptr = arena->CreateView(view->shm_position, view->size, view_base);
|
||||
view->view_ptr = view->mapped_ptr;
|
||||
}
|
||||
|
||||
if (!view->view_ptr)
|
||||
{
|
||||
// Argh! ERROR! Free what we grabbed so far so we can try again.
|
||||
MemoryMap_Shutdown(views, i + 1, flags, arena);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (view->out_ptr)
|
||||
*(view->out_ptr) = (u8*)view->view_ptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 MemoryMap_InitializeViews(MemoryView* views, int num_views, u32 flags)
|
||||
{
|
||||
u32 shm_position = 0;
|
||||
u32 last_position = 0;
|
||||
|
||||
for (int i = 0; i < num_views; i++)
|
||||
{
|
||||
// Zero all the pointers to be sure.
|
||||
views[i].mapped_ptr = nullptr;
|
||||
|
||||
SKIP(flags, views[i].flags);
|
||||
|
||||
if (views[i].flags & MV_MIRROR_PREVIOUS)
|
||||
shm_position = last_position;
|
||||
views[i].shm_position = shm_position;
|
||||
last_position = shm_position;
|
||||
shm_position += views[i].size;
|
||||
}
|
||||
|
||||
return shm_position;
|
||||
}
|
||||
|
||||
u8* MemoryMap_Setup(MemoryView* views, int num_views, u32 flags, MemArena* arena)
|
||||
{
|
||||
u32 total_mem = MemoryMap_InitializeViews(views, num_views, flags);
|
||||
|
||||
arena->GrabSHMSegment(total_mem);
|
||||
|
||||
// Now, create views in high memory where there's plenty of space.
|
||||
u8* base = MemArena::FindMemoryBase();
|
||||
// This really shouldn't fail - in 64-bit, there will always be enough
|
||||
// address space.
|
||||
if (!Memory_TryBase(base, views, num_views, flags, arena))
|
||||
{
|
||||
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
|
||||
exit(0);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
void MemoryMap_Shutdown(MemoryView* views, int num_views, u32 flags, MemArena* arena)
|
||||
{
|
||||
std::set<void*> freeset;
|
||||
for (int i = 0; i < num_views; i++)
|
||||
{
|
||||
MemoryView* view = &views[i];
|
||||
if (view->mapped_ptr && !freeset.count(view->mapped_ptr))
|
||||
{
|
||||
arena->ReleaseView(view->mapped_ptr, view->size);
|
||||
freeset.insert(view->mapped_ptr);
|
||||
view->mapped_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user