Merge pull request #2842 from Subv/switchable_page_table
Kernel/Memory: Give each process its own page table and allow switching the current page table upon reschedule
This commit is contained in:
commit
813837c5cf
14 changed files with 191 additions and 123 deletions
|
@ -8,7 +8,6 @@
|
|||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "audio_core/audio_core.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -24,7 +23,7 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
static MemoryRegionInfo memory_regions[3];
|
||||
MemoryRegionInfo memory_regions[3];
|
||||
|
||||
/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system
|
||||
/// memory configuration type.
|
||||
|
@ -96,9 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
|
|||
}
|
||||
}
|
||||
|
||||
std::array<u8, Memory::VRAM_SIZE> vram;
|
||||
std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram;
|
||||
|
||||
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {
|
||||
using namespace Memory;
|
||||
|
||||
|
@ -143,30 +139,14 @@ void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mappin
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO(yuriks): Use GetPhysicalPointer when that becomes independent of the virtual
|
||||
// mappings.
|
||||
u8* target_pointer = nullptr;
|
||||
switch (area->paddr_base) {
|
||||
case VRAM_PADDR:
|
||||
target_pointer = vram.data();
|
||||
break;
|
||||
case DSP_RAM_PADDR:
|
||||
target_pointer = AudioCore::GetDspMemory().data();
|
||||
break;
|
||||
case N3DS_EXTRA_RAM_PADDR:
|
||||
target_pointer = n3ds_extra_ram.data();
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
u8* target_pointer = Memory::GetPhysicalPointer(area->paddr_base + offset_into_region);
|
||||
|
||||
// TODO(yuriks): This flag seems to have some other effect, but it's unknown what
|
||||
MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
|
||||
|
||||
auto vma = address_space
|
||||
.MapBackingMemory(mapping.address, target_pointer + offset_into_region,
|
||||
mapping.size, memory_state)
|
||||
.Unwrap();
|
||||
auto vma =
|
||||
address_space.MapBackingMemory(mapping.address, target_pointer, mapping.size, memory_state)
|
||||
.Unwrap();
|
||||
address_space.Reprotect(vma,
|
||||
mapping.read_only ? VMAPermission::Read : VMAPermission::ReadWrite);
|
||||
}
|
||||
|
|
|
@ -26,4 +26,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
|||
|
||||
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
|
||||
void MapSharedPages(VMManager& address_space);
|
||||
|
||||
extern MemoryRegionInfo memory_regions[3];
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -171,6 +171,8 @@ static void SwitchContext(Thread* new_thread) {
|
|||
// Cancel any outstanding wakeup events for this thread
|
||||
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
|
||||
|
||||
auto previous_process = Kernel::g_current_process;
|
||||
|
||||
current_thread = new_thread;
|
||||
|
||||
ready_queue.remove(new_thread->current_priority, new_thread);
|
||||
|
@ -178,8 +180,18 @@ static void SwitchContext(Thread* new_thread) {
|
|||
|
||||
Core::CPU().LoadContext(new_thread->context);
|
||||
Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
|
||||
|
||||
if (previous_process != current_thread->owner_process) {
|
||||
Kernel::g_current_process = current_thread->owner_process;
|
||||
Memory::current_page_table = &Kernel::g_current_process->vm_manager.page_table;
|
||||
// We have switched processes and thus, page tables, clear the instruction cache so we
|
||||
// don't keep stale data from the previous process.
|
||||
Core::CPU().ClearInstructionCache();
|
||||
}
|
||||
} else {
|
||||
current_thread = nullptr;
|
||||
// Note: We do not reset the current process and current page table when idling because
|
||||
// technically we haven't changed processes, our threads are just paused.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,10 @@ void VMManager::Reset() {
|
|||
initial_vma.size = MAX_ADDRESS;
|
||||
vma_map.emplace(initial_vma.base, initial_vma);
|
||||
|
||||
page_table.pointers.fill(nullptr);
|
||||
page_table.attributes.fill(Memory::PageType::Unmapped);
|
||||
page_table.cached_res_count.fill(0);
|
||||
|
||||
UpdatePageTableForVMA(initial_vma);
|
||||
}
|
||||
|
||||
|
@ -328,16 +332,17 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
|
|||
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
|
||||
switch (vma.type) {
|
||||
case VMAType::Free:
|
||||
Memory::UnmapRegion(vma.base, vma.size);
|
||||
Memory::UnmapRegion(page_table, vma.base, vma.size);
|
||||
break;
|
||||
case VMAType::AllocatedMemoryBlock:
|
||||
Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
|
||||
Memory::MapMemoryRegion(page_table, vma.base, vma.size,
|
||||
vma.backing_block->data() + vma.offset);
|
||||
break;
|
||||
case VMAType::BackingMemory:
|
||||
Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
|
||||
Memory::MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
|
||||
break;
|
||||
case VMAType::MMIO:
|
||||
Memory::MapIoRegion(vma.base, vma.size, vma.mmio_handler);
|
||||
Memory::MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/mmio.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -102,7 +103,6 @@ struct VirtualMemoryArea {
|
|||
* - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
|
||||
*/
|
||||
class VMManager final {
|
||||
// TODO(yuriks): Make page tables switchable to support multiple VMManagers
|
||||
public:
|
||||
/**
|
||||
* The maximum amount of address space managed by the kernel. Addresses above this are never
|
||||
|
@ -184,6 +184,10 @@ public:
|
|||
/// Dumps the address space layout to the log, for debugging
|
||||
void LogLayout(Log::Level log_level) const;
|
||||
|
||||
/// Each VMManager has its own page table, which is set as the main one when the owning process
|
||||
/// is scheduled.
|
||||
Memory::PageTable page_table;
|
||||
|
||||
private:
|
||||
using VMAIter = decltype(vma_map)::iterator;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue