|
|
|
@ -127,22 +127,22 @@ constexpr Common::MemoryPermission ConvertToMemoryPermission(KMemoryPermission p |
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
void KPageTableBase::MemoryRange::Open() { |
|
|
|
void KPageTableBase::MemoryRange::Open(KernelCore& kernel) { |
|
|
|
// If the range contains heap pages, open them.
|
|
|
|
if (this->IsHeap()) { |
|
|
|
m_kernel.MemoryManager().Open(this->GetAddress(), this->GetSize() / PageSize); |
|
|
|
kernel.MemoryManager().Open(this->GetAddress(), this->GetSize() / PageSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void KPageTableBase::MemoryRange::Close() { |
|
|
|
void KPageTableBase::MemoryRange::Close(KernelCore& kernel) { |
|
|
|
// If the range contains heap pages, close them.
|
|
|
|
if (this->IsHeap()) { |
|
|
|
m_kernel.MemoryManager().Close(this->GetAddress(), this->GetSize() / PageSize); |
|
|
|
kernel.MemoryManager().Close(this->GetAddress(), this->GetSize() / PageSize); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
KPageTableBase::KPageTableBase(KernelCore& kernel) |
|
|
|
: m_kernel(kernel), m_system(kernel.System()), m_general_lock(kernel), |
|
|
|
: m_system(kernel.System()), m_general_lock(kernel), |
|
|
|
m_map_physical_memory_lock(kernel), m_device_map_lock(kernel) {} |
|
|
|
KPageTableBase::~KPageTableBase() = default; |
|
|
|
|
|
|
|
@ -177,9 +177,9 @@ Result KPageTableBase::InitializeForKernel(bool is_64_bit, KVirtualAddress start |
|
|
|
m_mapped_ipc_server_memory = 0; |
|
|
|
|
|
|
|
m_memory_block_slab_manager = |
|
|
|
m_kernel.GetSystemSystemResource().GetMemoryBlockSlabManagerPointer(); |
|
|
|
m_block_info_manager = m_kernel.GetSystemSystemResource().GetBlockInfoManagerPointer(); |
|
|
|
m_resource_limit = m_kernel.GetSystemResourceLimit(); |
|
|
|
m_system.Kernel().GetSystemSystemResource().GetMemoryBlockSlabManagerPointer(); |
|
|
|
m_block_info_manager = m_system.Kernel().GetSystemSystemResource().GetBlockInfoManagerPointer(); |
|
|
|
m_resource_limit = m_system.Kernel().GetSystemResourceLimit(); |
|
|
|
|
|
|
|
m_allocate_option = KMemoryManager::EncodeOption(KMemoryManager::Pool::System, |
|
|
|
KMemoryManager::Direction::FromFront); |
|
|
|
@ -469,11 +469,11 @@ void KPageTableBase::Finalize() { |
|
|
|
} |
|
|
|
|
|
|
|
// Get physical pages.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
this->MakePageGroup(pg, addr, size / PageSize); |
|
|
|
|
|
|
|
// Free the pages.
|
|
|
|
pg.CloseAndReset(); |
|
|
|
pg.CloseAndReset(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Finalize memory blocks.
|
|
|
|
@ -490,7 +490,7 @@ void KPageTableBase::Finalize() { |
|
|
|
// Release any insecure mapped memory.
|
|
|
|
if (m_mapped_insecure_memory) { |
|
|
|
if (auto* const insecure_resource_limit = |
|
|
|
KSystemControl::GetInsecureMemoryResourceLimit(m_kernel); |
|
|
|
KSystemControl::GetInsecureMemoryResourceLimit(m_system.Kernel()); |
|
|
|
insecure_resource_limit != nullptr) { |
|
|
|
insecure_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax, |
|
|
|
m_mapped_insecure_memory); |
|
|
|
@ -833,7 +833,7 @@ Result KPageTableBase::LockMemoryAndOpen(KPageGroup* out_pg, KPhysicalAddress* o |
|
|
|
|
|
|
|
// If we have an output group, open.
|
|
|
|
if (out_pg) { |
|
|
|
out_pg->Open(); |
|
|
|
out_pg->Open(m_system.Kernel()); |
|
|
|
} |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
@ -1041,7 +1041,7 @@ Result KPageTableBase::MapMemory(KProcessAddress dst_address, KProcessAddress sr |
|
|
|
const size_t num_pages = size / PageSize; |
|
|
|
|
|
|
|
// Create page groups for the memory being unmapped.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Create the page group representing the source.
|
|
|
|
R_TRY(this->MakePageGroup(pg, src_address, num_pages)); |
|
|
|
@ -1129,7 +1129,7 @@ Result KPageTableBase::UnmapMemory(KProcessAddress dst_address, KProcessAddress |
|
|
|
const size_t num_pages = size / PageSize; |
|
|
|
|
|
|
|
// Create page groups for the memory being unmapped.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Create the page group representing the destination.
|
|
|
|
R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); |
|
|
|
@ -1217,7 +1217,7 @@ Result KPageTableBase::MapCodeMemory(KProcessAddress dst_address, KProcessAddres |
|
|
|
const size_t num_pages = size / PageSize; |
|
|
|
|
|
|
|
// Create page groups for the memory being unmapped.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Create the page group representing the source.
|
|
|
|
R_TRY(this->MakePageGroup(pg, src_address, num_pages)); |
|
|
|
@ -1312,7 +1312,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr |
|
|
|
bool reprotected_pages = false; |
|
|
|
SCOPE_EXIT { |
|
|
|
if (reprotected_pages && any_code_pages) { |
|
|
|
InvalidateInstructionCache(m_kernel, this, dst_address, size); |
|
|
|
InvalidateInstructionCache(m_system.Kernel(), this, dst_address, size); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@ -1322,7 +1322,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr |
|
|
|
const size_t num_pages = size / PageSize; |
|
|
|
|
|
|
|
// Create page groups for the memory being unmapped.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Create the page group representing the destination.
|
|
|
|
R_TRY(this->MakePageGroup(pg, dst_address, num_pages)); |
|
|
|
@ -1383,7 +1383,7 @@ Result KPageTableBase::UnmapCodeMemory(KProcessAddress dst_address, KProcessAddr |
|
|
|
|
|
|
|
Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) { |
|
|
|
// Get the insecure memory resource limit and pool.
|
|
|
|
auto* const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(m_kernel); |
|
|
|
auto* const insecure_resource_limit = KSystemControl::GetInsecureMemoryResourceLimit(m_system.Kernel()); |
|
|
|
const auto insecure_pool = |
|
|
|
static_cast<KMemoryManager::Pool>(KSystemControl::GetInsecureMemoryPool()); |
|
|
|
|
|
|
|
@ -1394,8 +1394,8 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) { |
|
|
|
R_UNLESS(memory_reservation.Succeeded(), ResultOutOfMemory); |
|
|
|
|
|
|
|
// Allocate pages for the insecure memory.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
R_TRY(m_kernel.MemoryManager().AllocateAndOpen( |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen( |
|
|
|
std::addressof(pg), size / PageSize, |
|
|
|
KMemoryManager::EncodeOption(insecure_pool, KMemoryManager::Direction::FromFront))); |
|
|
|
|
|
|
|
@ -1403,7 +1403,7 @@ Result KPageTableBase::MapInsecureMemory(KProcessAddress address, size_t size) { |
|
|
|
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
|
|
|
// automatically.
|
|
|
|
SCOPE_EXIT { |
|
|
|
pg.Close(); |
|
|
|
pg.Close(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Clear all the newly allocated pages.
|
|
|
|
@ -1491,7 +1491,7 @@ Result KPageTableBase::UnmapInsecureMemory(KProcessAddress address, size_t size) |
|
|
|
|
|
|
|
// Release the insecure memory from the insecure limit.
|
|
|
|
if (auto* const insecure_resource_limit = |
|
|
|
KSystemControl::GetInsecureMemoryResourceLimit(m_kernel); |
|
|
|
KSystemControl::GetInsecureMemoryResourceLimit(m_system.Kernel()); |
|
|
|
insecure_resource_limit != nullptr) { |
|
|
|
insecure_resource_limit->Release(Svc::LimitableResource::PhysicalMemoryMax, size); |
|
|
|
} |
|
|
|
@ -1603,15 +1603,15 @@ Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProce |
|
|
|
ASSERT(this->IsLockedByCurrentThread()); |
|
|
|
|
|
|
|
// Create a page group to hold the pages we allocate.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Allocate the pages.
|
|
|
|
R_TRY( |
|
|
|
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); |
|
|
|
m_system.Kernel().MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option)); |
|
|
|
|
|
|
|
// Ensure that the page group is closed when we're done working with it.
|
|
|
|
SCOPE_EXIT { |
|
|
|
pg.Close(); |
|
|
|
pg.Close(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Clear all pages.
|
|
|
|
@ -1992,7 +1992,7 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s |
|
|
|
KMemoryAttribute::All, KMemoryAttribute::None)); |
|
|
|
|
|
|
|
// Make a new page group for the region.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
|
|
|
|
// Determine new perm/state.
|
|
|
|
const KMemoryPermission new_perm = ConvertToKMemoryPermission(svc_perm); |
|
|
|
@ -2048,9 +2048,9 @@ Result KPageTableBase::SetProcessMemoryPermission(KProcessAddress addr, size_t s |
|
|
|
// Ensure cache coherency, if we're setting pages as executable.
|
|
|
|
if (is_x) { |
|
|
|
for (const auto& block : pg) { |
|
|
|
StoreDataCache(GetHeapVirtualPointer(m_kernel, block.GetAddress()), block.GetSize()); |
|
|
|
StoreDataCache(GetHeapVirtualPointer(m_system.Kernel(), block.GetAddress()), block.GetSize()); |
|
|
|
} |
|
|
|
InvalidateInstructionCache(m_kernel, this, addr, size); |
|
|
|
InvalidateInstructionCache(m_system.Kernel(), this, addr, size); |
|
|
|
} |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
@ -2193,15 +2193,15 @@ Result KPageTableBase::SetHeapSize(KProcessAddress* out, size_t size) { |
|
|
|
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); |
|
|
|
|
|
|
|
// Allocate pages for the heap extension.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
R_TRY(m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), allocation_size / PageSize, |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(std::addressof(pg), allocation_size / PageSize, |
|
|
|
m_allocate_option)); |
|
|
|
|
|
|
|
// Close the opened pages when we're done with them.
|
|
|
|
// If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed
|
|
|
|
// automatically.
|
|
|
|
SCOPE_EXIT { |
|
|
|
pg.Close(); |
|
|
|
pg.Close(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Clear all the newly allocated pages.
|
|
|
|
@ -2406,7 +2406,7 @@ Result KPageTableBase::MapIoImpl(KProcessAddress* out, PageLinkedList* page_list |
|
|
|
ASSERT(this->CanContain(region_start, region_size, state)); |
|
|
|
|
|
|
|
// Locate the memory region.
|
|
|
|
const KMemoryRegion* region = KMemoryLayout::Find(m_kernel.MemoryLayout(), phys_addr); |
|
|
|
const KMemoryRegion* region = KMemoryLayout::Find(m_system.Kernel().MemoryLayout(), phys_addr); |
|
|
|
R_UNLESS(region != nullptr, ResultInvalidAddress); |
|
|
|
|
|
|
|
ASSERT(region->Contains(GetInteger(phys_addr))); |
|
|
|
@ -2640,7 +2640,7 @@ Result KPageTableBase::MapStatic(KPhysicalAddress phys_addr, size_t size, KMemor |
|
|
|
const size_t region_num_pages = region_size / PageSize; |
|
|
|
|
|
|
|
// Locate the memory region.
|
|
|
|
const KMemoryRegion* region = KMemoryLayout::Find(m_kernel.MemoryLayout(), phys_addr); |
|
|
|
const KMemoryRegion* region = KMemoryLayout::Find(m_system.Kernel().MemoryLayout(), phys_addr); |
|
|
|
R_UNLESS(region != nullptr, ResultInvalidAddress); |
|
|
|
|
|
|
|
ASSERT(region->Contains(GetInteger(phys_addr))); |
|
|
|
@ -2707,7 +2707,7 @@ Result KPageTableBase::MapStatic(KPhysicalAddress phys_addr, size_t size, KMemor |
|
|
|
Result KPageTableBase::MapRegion(KMemoryRegionType region_type, KMemoryPermission perm) { |
|
|
|
// Get the memory region.
|
|
|
|
const KMemoryRegion* region = |
|
|
|
m_kernel.MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(region_type); |
|
|
|
m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree().FindFirstDerived(region_type); |
|
|
|
R_UNLESS(region != nullptr, ResultOutOfRange); |
|
|
|
|
|
|
|
// Check that the region is valid.
|
|
|
|
@ -3004,7 +3004,7 @@ Result KPageTableBase::MakeAndOpenPageGroup(KPageGroup* out, KProcessAddress add |
|
|
|
R_TRY(this->MakePageGroup(*out, address, num_pages)); |
|
|
|
|
|
|
|
// Open a new reference to the pages in the group.
|
|
|
|
out->Open(); |
|
|
|
out->Open(m_system.Kernel()); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
@ -3051,7 +3051,7 @@ Result KPageTableBase::InvalidateProcessDataCache(KProcessAddress address, size_ |
|
|
|
// Invalidate the block.
|
|
|
|
if (cur_size > 0) { |
|
|
|
// NOTE: Nintendo does not check the result of invalidation.
|
|
|
|
InvalidateDataCache(GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size); |
|
|
|
InvalidateDataCache(GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size); |
|
|
|
} |
|
|
|
|
|
|
|
// Advance.
|
|
|
|
@ -3075,7 +3075,7 @@ Result KPageTableBase::InvalidateProcessDataCache(KProcessAddress address, size_ |
|
|
|
// Invalidate the last block.
|
|
|
|
if (cur_size > 0) { |
|
|
|
// NOTE: Nintendo does not check the result of invalidation.
|
|
|
|
InvalidateDataCache(GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size); |
|
|
|
InvalidateDataCache(GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size); |
|
|
|
} |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
@ -3083,7 +3083,7 @@ Result KPageTableBase::InvalidateProcessDataCache(KProcessAddress address, size_ |
|
|
|
|
|
|
|
Result KPageTableBase::InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) { |
|
|
|
// Check pre-condition: this is being called on the current process.
|
|
|
|
ASSERT(this == std::addressof(GetCurrentProcess(m_kernel).GetPageTable().GetBasePageTable())); |
|
|
|
ASSERT(this == std::addressof(GetCurrentProcess(m_system.Kernel()).GetPageTable().GetBasePageTable())); |
|
|
|
|
|
|
|
// Check that the region is in range.
|
|
|
|
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory); |
|
|
|
@ -3144,7 +3144,7 @@ Result KPageTableBase::ReadDebugMemory(KProcessAddress dst_address, KProcessAddr |
|
|
|
// Copy as much aligned data as we can.
|
|
|
|
if (cur_size >= sizeof(u32)) { |
|
|
|
const size_t copy_size = Common::AlignDown(cur_size, sizeof(u32)); |
|
|
|
const void* copy_src = GetLinearMappedVirtualPointer(m_kernel, cur_addr); |
|
|
|
const void* copy_src = GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr); |
|
|
|
FlushDataCache(copy_src, copy_size); |
|
|
|
R_UNLESS(dst_memory.WriteBlock(dst_address, copy_src, copy_size), ResultInvalidPointer); |
|
|
|
|
|
|
|
@ -3155,7 +3155,7 @@ Result KPageTableBase::ReadDebugMemory(KProcessAddress dst_address, KProcessAddr |
|
|
|
|
|
|
|
// Copy remaining data.
|
|
|
|
if (cur_size > 0) { |
|
|
|
const void* copy_src = GetLinearMappedVirtualPointer(m_kernel, cur_addr); |
|
|
|
const void* copy_src = GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr); |
|
|
|
FlushDataCache(copy_src, cur_size); |
|
|
|
R_UNLESS(dst_memory.WriteBlock(dst_address, copy_src, cur_size), ResultInvalidPointer); |
|
|
|
} |
|
|
|
@ -3240,11 +3240,11 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd |
|
|
|
// Copy as much aligned data as we can.
|
|
|
|
if (cur_size >= sizeof(u32)) { |
|
|
|
const size_t copy_size = Common::AlignDown(cur_size, sizeof(u32)); |
|
|
|
void* copy_dst = GetLinearMappedVirtualPointer(m_kernel, cur_addr); |
|
|
|
void* copy_dst = GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr); |
|
|
|
R_UNLESS(src_memory.ReadBlock(src_address, copy_dst, copy_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
StoreDataCache(GetLinearMappedVirtualPointer(m_kernel, cur_addr), copy_size); |
|
|
|
StoreDataCache(GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), copy_size); |
|
|
|
|
|
|
|
src_address += copy_size; |
|
|
|
cur_addr += copy_size; |
|
|
|
@ -3253,11 +3253,11 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd |
|
|
|
|
|
|
|
// Copy remaining data.
|
|
|
|
if (cur_size > 0) { |
|
|
|
void* copy_dst = GetLinearMappedVirtualPointer(m_kernel, cur_addr); |
|
|
|
void* copy_dst = GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr); |
|
|
|
R_UNLESS(src_memory.ReadBlock(src_address, copy_dst, cur_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
StoreDataCache(GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size); |
|
|
|
StoreDataCache(GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size); |
|
|
|
} |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
@ -3295,7 +3295,7 @@ Result KPageTableBase::WriteDebugMemory(KProcessAddress dst_address, KProcessAdd |
|
|
|
R_TRY(PerformCopy()); |
|
|
|
|
|
|
|
// Invalidate the instruction cache, as this svc allows modifying executable pages.
|
|
|
|
InvalidateInstructionCache(m_kernel, this, dst_address, size); |
|
|
|
InvalidateInstructionCache(m_system.Kernel(), this, dst_address, size); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
@ -3311,7 +3311,7 @@ Result KPageTableBase::ReadIoMemoryImpl(KProcessAddress dst_addr, KPhysicalAddre |
|
|
|
const size_t map_size = map_end - map_start; |
|
|
|
|
|
|
|
// Get the memory reference to write into.
|
|
|
|
auto& dst_memory = GetCurrentMemory(m_kernel); |
|
|
|
auto& dst_memory = GetCurrentMemory(m_system.Kernel()); |
|
|
|
|
|
|
|
// We're going to perform an update, so create a helper.
|
|
|
|
KScopedPageTableUpdater updater(this); |
|
|
|
@ -3347,7 +3347,7 @@ Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, KProcessAdd |
|
|
|
const size_t map_size = map_end - map_start; |
|
|
|
|
|
|
|
// Get the memory reference to read from.
|
|
|
|
auto& src_memory = GetCurrentMemory(m_kernel); |
|
|
|
auto& src_memory = GetCurrentMemory(m_system.Kernel()); |
|
|
|
|
|
|
|
// We're going to perform an update, so create a helper.
|
|
|
|
KScopedPageTableUpdater updater(this); |
|
|
|
@ -3379,7 +3379,7 @@ Result KPageTableBase::ReadDebugIoMemory(KProcessAddress dst_address, KProcessAd |
|
|
|
|
|
|
|
// We need to lock both this table, and the current process's table, so set up some aliases.
|
|
|
|
KPageTableBase& src_page_table = *this; |
|
|
|
KPageTableBase& dst_page_table = GetCurrentProcess(m_kernel).GetPageTable().GetBasePageTable(); |
|
|
|
KPageTableBase& dst_page_table = GetCurrentProcess(m_system.Kernel()).GetPageTable().GetBasePageTable(); |
|
|
|
|
|
|
|
// Acquire the table locks.
|
|
|
|
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); |
|
|
|
@ -3421,7 +3421,7 @@ Result KPageTableBase::WriteDebugIoMemory(KProcessAddress dst_address, KProcessA |
|
|
|
|
|
|
|
// We need to lock both this table, and the current process's table, so set up some aliases.
|
|
|
|
KPageTableBase& src_page_table = *this; |
|
|
|
KPageTableBase& dst_page_table = GetCurrentProcess(m_kernel).GetPageTable().GetBasePageTable(); |
|
|
|
KPageTableBase& dst_page_table = GetCurrentProcess(m_system.Kernel()).GetPageTable().GetBasePageTable(); |
|
|
|
|
|
|
|
// Acquire the table locks.
|
|
|
|
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock); |
|
|
|
@ -3606,7 +3606,7 @@ Result KPageTableBase::OpenMemoryRangeForMapDeviceAddressSpace(KPageTableBase::M |
|
|
|
KMemoryAttribute::IpcLocked | KMemoryAttribute::Locked, KMemoryAttribute::None)); |
|
|
|
|
|
|
|
// We got the range, so open it.
|
|
|
|
out->Open(); |
|
|
|
out->Open(m_system.Kernel()); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
@ -3624,7 +3624,7 @@ Result KPageTableBase::OpenMemoryRangeForUnmapDeviceAddressSpace(MemoryRange* ou |
|
|
|
KMemoryAttribute::DeviceShared | KMemoryAttribute::Locked, KMemoryAttribute::DeviceShared)); |
|
|
|
|
|
|
|
// We got the range, so open it.
|
|
|
|
out->Open(); |
|
|
|
out->Open(m_system.Kernel()); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
@ -3697,7 +3697,7 @@ Result KPageTableBase::OpenMemoryRangeForProcessCacheOperation(MemoryRange* out, |
|
|
|
KMemoryAttribute::None)); |
|
|
|
|
|
|
|
// We got the range, so open it.
|
|
|
|
out->Open(); |
|
|
|
out->Open(m_system.Kernel()); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
} |
|
|
|
@ -3710,7 +3710,7 @@ Result KPageTableBase::CopyMemoryFromLinearToUser( |
|
|
|
R_UNLESS(this->Contains(src_addr, size), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Get the destination memory reference.
|
|
|
|
auto& dst_memory = GetCurrentMemory(m_kernel); |
|
|
|
auto& dst_memory = GetCurrentMemory(m_system.Kernel()); |
|
|
|
|
|
|
|
// Copy the memory.
|
|
|
|
{ |
|
|
|
@ -3745,7 +3745,7 @@ Result KPageTableBase::CopyMemoryFromLinearToUser( |
|
|
|
if (cur_size >= sizeof(u32)) { |
|
|
|
const size_t copy_size = Common::AlignDown(cur_size, sizeof(u32)); |
|
|
|
R_UNLESS(dst_memory.WriteBlock(dst_addr, |
|
|
|
GetLinearMappedVirtualPointer(m_kernel, cur_addr), |
|
|
|
GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), |
|
|
|
copy_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
@ -3757,7 +3757,7 @@ Result KPageTableBase::CopyMemoryFromLinearToUser( |
|
|
|
// Copy remaining data.
|
|
|
|
if (cur_size > 0) { |
|
|
|
R_UNLESS(dst_memory.WriteBlock( |
|
|
|
dst_addr, GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size), |
|
|
|
dst_addr, GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
} |
|
|
|
|
|
|
|
@ -3836,7 +3836,7 @@ Result KPageTableBase::CopyMemoryFromLinearToKernel( |
|
|
|
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Copy the data.
|
|
|
|
std::memcpy(buffer, GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size); |
|
|
|
std::memcpy(buffer, GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
@ -3884,7 +3884,7 @@ Result KPageTableBase::CopyMemoryFromUserToLinear( |
|
|
|
R_UNLESS(this->Contains(dst_addr, size), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Get the source memory reference.
|
|
|
|
auto& src_memory = GetCurrentMemory(m_kernel); |
|
|
|
auto& src_memory = GetCurrentMemory(m_system.Kernel()); |
|
|
|
|
|
|
|
// Copy the memory.
|
|
|
|
{ |
|
|
|
@ -3919,7 +3919,7 @@ Result KPageTableBase::CopyMemoryFromUserToLinear( |
|
|
|
if (cur_size >= sizeof(u32)) { |
|
|
|
const size_t copy_size = Common::AlignDown(cur_size, sizeof(u32)); |
|
|
|
R_UNLESS(src_memory.ReadBlock(src_addr, |
|
|
|
GetLinearMappedVirtualPointer(m_kernel, cur_addr), |
|
|
|
GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), |
|
|
|
copy_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
src_addr += copy_size; |
|
|
|
@ -3930,7 +3930,7 @@ Result KPageTableBase::CopyMemoryFromUserToLinear( |
|
|
|
// Copy remaining data.
|
|
|
|
if (cur_size > 0) { |
|
|
|
R_UNLESS(src_memory.ReadBlock( |
|
|
|
src_addr, GetLinearMappedVirtualPointer(m_kernel, cur_addr), cur_size), |
|
|
|
src_addr, GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), cur_size), |
|
|
|
ResultInvalidCurrentMemory); |
|
|
|
} |
|
|
|
|
|
|
|
@ -4011,7 +4011,7 @@ Result KPageTableBase::CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, si |
|
|
|
R_UNLESS(IsLinearMappedPhysicalAddress(cur_addr), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Copy the data.
|
|
|
|
std::memcpy(GetLinearMappedVirtualPointer(m_kernel, cur_addr), buffer, cur_size); |
|
|
|
std::memcpy(GetLinearMappedVirtualPointer(m_system.Kernel(), cur_addr), buffer, cur_size); |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
}; |
|
|
|
@ -4162,8 +4162,8 @@ Result KPageTableBase::CopyMemoryFromHeapToHeap( |
|
|
|
R_UNLESS(IsHeapPhysicalAddress(cur_dst_addr), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Copy the data.
|
|
|
|
std::memcpy(GetHeapVirtualPointer(m_kernel, cur_dst_addr), |
|
|
|
GetHeapVirtualPointer(m_kernel, cur_src_addr), cur_copy_size); |
|
|
|
std::memcpy(GetHeapVirtualPointer(m_system.Kernel(), cur_dst_addr), |
|
|
|
GetHeapVirtualPointer(m_system.Kernel(), cur_src_addr), cur_copy_size); |
|
|
|
|
|
|
|
// Update.
|
|
|
|
cur_src_block_addr = src_next_entry.phys_addr; |
|
|
|
@ -4296,8 +4296,8 @@ Result KPageTableBase::CopyMemoryFromHeapToHeapWithoutCheckDestination( |
|
|
|
R_UNLESS(IsHeapPhysicalAddress(cur_dst_addr), ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
// Copy the data.
|
|
|
|
std::memcpy(GetHeapVirtualPointer(m_kernel, cur_dst_addr), |
|
|
|
GetHeapVirtualPointer(m_kernel, cur_src_addr), cur_copy_size); |
|
|
|
std::memcpy(GetHeapVirtualPointer(m_system.Kernel(), cur_dst_addr), |
|
|
|
GetHeapVirtualPointer(m_system.Kernel(), cur_src_addr), cur_copy_size); |
|
|
|
|
|
|
|
// Update.
|
|
|
|
cur_src_block_addr = src_next_entry.phys_addr; |
|
|
|
@ -4506,10 +4506,10 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
// free on scope exit.
|
|
|
|
SCOPE_EXIT { |
|
|
|
if (start_partial_page != 0) { |
|
|
|
m_kernel.MemoryManager().Close(start_partial_page, 1); |
|
|
|
m_system.Kernel().MemoryManager().Close(start_partial_page, 1); |
|
|
|
} |
|
|
|
if (end_partial_page != 0) { |
|
|
|
m_kernel.MemoryManager().Close(end_partial_page, 1); |
|
|
|
m_system.Kernel().MemoryManager().Close(end_partial_page, 1); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@ -4526,7 +4526,7 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
// Allocate the start page as needed.
|
|
|
|
if (aligned_src_start < mapping_src_start) { |
|
|
|
start_partial_page = |
|
|
|
m_kernel.MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); |
|
|
|
m_system.Kernel().MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); |
|
|
|
R_UNLESS(start_partial_page != 0, ResultOutOfMemory); |
|
|
|
} |
|
|
|
|
|
|
|
@ -4534,7 +4534,7 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
if (mapping_src_end < aligned_src_end && |
|
|
|
(aligned_src_start < mapping_src_end || aligned_src_start == mapping_src_start)) { |
|
|
|
end_partial_page = |
|
|
|
m_kernel.MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); |
|
|
|
m_system.Kernel().MemoryManager().AllocateAndOpenContinuous(1, 1, m_allocate_option); |
|
|
|
R_UNLESS(end_partial_page != 0, ResultOutOfMemory); |
|
|
|
} |
|
|
|
|
|
|
|
@ -4560,7 +4560,7 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
// Map the start page, if we have one.
|
|
|
|
if (start_partial_page != 0) { |
|
|
|
// Ensure the page holds correct data.
|
|
|
|
u8* const start_partial_virt = GetHeapVirtualPointer(m_kernel, start_partial_page); |
|
|
|
u8* const start_partial_virt = GetHeapVirtualPointer(m_system.Kernel(), start_partial_page); |
|
|
|
if (send) { |
|
|
|
const size_t partial_offset = src_start - aligned_src_start; |
|
|
|
size_t copy_size, clear_size; |
|
|
|
@ -4574,7 +4574,7 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
|
|
|
|
std::memset(start_partial_virt, fill_val, partial_offset); |
|
|
|
std::memcpy(start_partial_virt + partial_offset, |
|
|
|
GetHeapVirtualPointer(m_kernel, cur_block_addr) + partial_offset, |
|
|
|
GetHeapVirtualPointer(m_system.Kernel(), cur_block_addr) + partial_offset, |
|
|
|
copy_size); |
|
|
|
if (clear_size > 0) { |
|
|
|
std::memset(start_partial_virt + partial_offset + copy_size, fill_val, clear_size); |
|
|
|
@ -4663,10 +4663,10 @@ Result KPageTableBase::SetupForIpcServer(KProcessAddress* out_addr, size_t size, |
|
|
|
// Map the end page, if we have one.
|
|
|
|
if (end_partial_page != 0) { |
|
|
|
// Ensure the page holds correct data.
|
|
|
|
u8* const end_partial_virt = GetHeapVirtualPointer(m_kernel, end_partial_page); |
|
|
|
u8* const end_partial_virt = GetHeapVirtualPointer(m_system.Kernel(), end_partial_page); |
|
|
|
if (send) { |
|
|
|
const size_t copy_size = src_end - mapping_src_end; |
|
|
|
std::memcpy(end_partial_virt, GetHeapVirtualPointer(m_kernel, cur_block_addr), |
|
|
|
std::memcpy(end_partial_virt, GetHeapVirtualPointer(m_system.Kernel(), cur_block_addr), |
|
|
|
copy_size); |
|
|
|
std::memset(end_partial_virt + copy_size, fill_val, PageSize - copy_size); |
|
|
|
} else { |
|
|
|
@ -5173,15 +5173,15 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { |
|
|
|
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); |
|
|
|
|
|
|
|
// Allocate pages for the new memory.
|
|
|
|
KPageGroup pg(m_kernel, m_block_info_manager); |
|
|
|
R_TRY(m_kernel.MemoryManager().AllocateForProcess( |
|
|
|
KPageGroup pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
R_TRY(m_system.Kernel().MemoryManager().AllocateForProcess( |
|
|
|
std::addressof(pg), (size - mapped_size) / PageSize, m_allocate_option, |
|
|
|
GetCurrentProcess(m_kernel).GetId(), m_heap_fill_value)); |
|
|
|
GetCurrentProcess(m_system.Kernel()).GetId(), m_heap_fill_value)); |
|
|
|
|
|
|
|
// If we fail in the next bit (or retry), we need to cleanup the pages.
|
|
|
|
auto pg_guard = SCOPE_GUARD { |
|
|
|
pg.OpenFirst(); |
|
|
|
pg.Close(); |
|
|
|
pg.OpenFirst(m_system.Kernel()); |
|
|
|
pg.Close(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Map the memory.
|
|
|
|
@ -5304,12 +5304,12 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { |
|
|
|
} |
|
|
|
|
|
|
|
// Release any remaining unmapped memory.
|
|
|
|
m_kernel.MemoryManager().OpenFirst(pg_phys_addr, pg_pages); |
|
|
|
m_kernel.MemoryManager().Close(pg_phys_addr, pg_pages); |
|
|
|
m_system.Kernel().MemoryManager().OpenFirst(pg_phys_addr, pg_pages); |
|
|
|
m_system.Kernel().MemoryManager().Close(pg_phys_addr, pg_pages); |
|
|
|
for (++pg_it; pg_it != pg.end(); ++pg_it) { |
|
|
|
m_kernel.MemoryManager().OpenFirst(pg_it->GetAddress(), |
|
|
|
m_system.Kernel().MemoryManager().OpenFirst(pg_it->GetAddress(), |
|
|
|
pg_it->GetNumPages()); |
|
|
|
m_kernel.MemoryManager().Close(pg_it->GetAddress(), pg_it->GetNumPages()); |
|
|
|
m_system.Kernel().MemoryManager().Close(pg_it->GetAddress(), pg_it->GetNumPages()); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
@ -5337,11 +5337,11 @@ Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { |
|
|
|
// While we have pages to map, map them.
|
|
|
|
{ |
|
|
|
// Create a page group for the current mapping range.
|
|
|
|
KPageGroup cur_pg(m_kernel, m_block_info_manager); |
|
|
|
KPageGroup cur_pg(m_system.Kernel(), m_block_info_manager); |
|
|
|
{ |
|
|
|
ON_RESULT_FAILURE_2 { |
|
|
|
cur_pg.OpenFirst(); |
|
|
|
cur_pg.Close(); |
|
|
|
cur_pg.OpenFirst(m_system.Kernel()); |
|
|
|
cur_pg.Close(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
size_t remain_pages = map_pages; |
|
|
|
@ -5706,9 +5706,9 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a |
|
|
|
const bool separate_heap = operation == OperationType::UnmapPhysical; |
|
|
|
|
|
|
|
// Ensure that any pages we track are closed on exit.
|
|
|
|
KPageGroup pages_to_close(m_kernel, this->GetBlockInfoManager()); |
|
|
|
KPageGroup pages_to_close(m_system.Kernel(), this->GetBlockInfoManager()); |
|
|
|
SCOPE_EXIT { |
|
|
|
pages_to_close.CloseAndReset(); |
|
|
|
pages_to_close.CloseAndReset(m_system.Kernel()); |
|
|
|
}; |
|
|
|
|
|
|
|
// Make a page group representing the region to unmap.
|
|
|
|
@ -5727,7 +5727,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a |
|
|
|
|
|
|
|
// Open references to pages, if we should.
|
|
|
|
if (this->IsHeapPhysicalAddress(phys_addr)) { |
|
|
|
m_kernel.MemoryManager().Open(phys_addr, num_pages); |
|
|
|
m_system.Kernel().MemoryManager().Open(phys_addr, num_pages); |
|
|
|
} |
|
|
|
|
|
|
|
R_SUCCEED(); |
|
|
|
@ -5767,7 +5767,7 @@ Result KPageTableBase::Operate(PageLinkedList* page_list, KProcessAddress virt_a |
|
|
|
const bool separate_heap = operation == OperationType::MapFirstGroupPhysical; |
|
|
|
|
|
|
|
// We want to maintain a new reference to every page in the group.
|
|
|
|
KScopedPageGroup spg(page_group, operation == OperationType::MapGroup); |
|
|
|
KScopedPageGroup spg(m_system.Kernel(), page_group, operation == OperationType::MapGroup); |
|
|
|
|
|
|
|
for (const auto& node : page_group) { |
|
|
|
const size_t size{node.GetNumPages() * PageSize}; |
|
|
|
|