mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
kern: implement SvcMapMemory
This commit is contained in:
parent
78da7422ae
commit
9503aae522
5 changed files with 105 additions and 5 deletions
|
@ -56,7 +56,11 @@ namespace ams::kern::arch::arm64 {
|
||||||
return this->page_table.QueryInfo(out_info, out_page_info, addr);
|
return this->page_table.QueryInfo(out_info, out_page_info, addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) {
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
|
return this->page_table.MapMemory(dst_address, src_address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
return this->page_table.UnmapMemory(dst_address, src_address, size);
|
return this->page_table.UnmapMemory(dst_address, src_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,7 +252,8 @@ namespace ams::kern {
|
||||||
Result SetHeapSize(KProcessAddress *out, size_t size);
|
Result SetHeapSize(KProcessAddress *out, size_t size);
|
||||||
Result SetMaxHeapSize(size_t size);
|
Result SetMaxHeapSize(size_t size);
|
||||||
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
||||||
Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size);
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
|
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapStatic(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
||||||
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
Result MapRegion(KMemoryRegionType region_type, KMemoryPermission perm);
|
||||||
|
|
|
@ -498,7 +498,67 @@ namespace ams::kern {
|
||||||
return ResultSuccess();
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) {
|
Result KPageTableBase::MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
/* Validate that the source address's state is valid. */
|
||||||
|
KMemoryState src_state;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(src_state), nullptr, nullptr, src_address, size, KMemoryState_FlagCanAlias, KMemoryState_FlagCanAlias, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
|
||||||
|
/* Validate that the dst address's state is valid. */
|
||||||
|
R_TRY(this->CheckMemoryState(dst_address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
|
/* Create an update allocator for the source. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator src_allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(src_allocator.GetResult());
|
||||||
|
|
||||||
|
/* Create an update allocator for the destination. */
|
||||||
|
KMemoryBlockManagerUpdateAllocator dst_allocator(this->memory_block_slab_manager);
|
||||||
|
R_TRY(dst_allocator.GetResult());
|
||||||
|
|
||||||
|
/* Map the memory. */
|
||||||
|
{
|
||||||
|
/* Determine the number of pages being operated on. */
|
||||||
|
const size_t num_pages = size / PageSize;
|
||||||
|
|
||||||
|
/* Create page groups for the memory being unmapped. */
|
||||||
|
KPageGroup pg(this->block_info_manager);
|
||||||
|
|
||||||
|
/* Create the page group representing the source. */
|
||||||
|
R_TRY(this->MakePageGroup(pg, src_address, num_pages));
|
||||||
|
|
||||||
|
/* We're going to perform an update, so create a helper. */
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
/* Reprotect the source as kernel-read/not mapped. */
|
||||||
|
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(KMemoryPermission_KernelRead | KMemoryPermission_NotMapped);
|
||||||
|
const KMemoryAttribute new_src_attr = static_cast<KMemoryAttribute>(KMemoryAttribute_AnyLocked | KMemoryAttribute_Locked);
|
||||||
|
const KPageProperties src_properties = { new_src_perm, false, false, false };
|
||||||
|
R_TRY(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, src_properties, OperationType_ChangePermissions, false));
|
||||||
|
|
||||||
|
/* Ensure that we unprotect the source pages on failure. */
|
||||||
|
auto unprot_guard = SCOPE_GUARD {
|
||||||
|
const KPageProperties unprotect_properties = { KMemoryPermission_UserReadWrite, false, false, false };
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), src_address, num_pages, Null<KPhysicalAddress>, false, unprotect_properties, OperationType_ChangePermissions, true));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Map the alias pages. */
|
||||||
|
const KPageProperties dst_map_properties = { KMemoryPermission_UserReadWrite, false, false, false };
|
||||||
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties, false));
|
||||||
|
|
||||||
|
/* We successfully mapped the alias pages, so we don't need to unprotect the src pages on failure. */
|
||||||
|
unprot_guard.Cancel();
|
||||||
|
|
||||||
|
/* Apply the memory block updates. */
|
||||||
|
this->memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state, new_src_perm, new_src_attr);
|
||||||
|
this->memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryAttribute_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(this->general_lock);
|
KScopedLightLock lk(this->general_lock);
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,8 @@ namespace ams::kern::svc {
|
||||||
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetInfo returned %016lx\n", *out); };
|
ON_SCOPE_EXIT{ MESOSPHERE_LOG("GetInfo returned %016lx\n", *out); };
|
||||||
|
|
||||||
switch (info_type) {
|
switch (info_type) {
|
||||||
|
case ams::svc::InfoType_CoreMask:
|
||||||
|
case ams::svc::InfoType_PriorityMask:
|
||||||
case ams::svc::InfoType_AliasRegionAddress:
|
case ams::svc::InfoType_AliasRegionAddress:
|
||||||
case ams::svc::InfoType_AliasRegionSize:
|
case ams::svc::InfoType_AliasRegionSize:
|
||||||
case ams::svc::InfoType_HeapRegionAddress:
|
case ams::svc::InfoType_HeapRegionAddress:
|
||||||
|
@ -47,6 +49,12 @@ namespace ams::kern::svc {
|
||||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
switch (info_type) {
|
switch (info_type) {
|
||||||
|
case ams::svc::InfoType_CoreMask:
|
||||||
|
*out = process->GetCoreMask();
|
||||||
|
break;
|
||||||
|
case ams::svc::InfoType_PriorityMask:
|
||||||
|
*out = process->GetPriorityMask();
|
||||||
|
break;
|
||||||
case ams::svc::InfoType_AliasRegionAddress:
|
case ams::svc::InfoType_AliasRegionAddress:
|
||||||
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
*out = GetInteger(process->GetPageTable().GetAliasRegionStart());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,6 +21,33 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
Result MapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) {
|
||||||
|
/* Log the call parameters for debugging. */
|
||||||
|
MESOSPHERE_LOG("MapMemory(%zx, %zx, %zx)\n", dst_address, src_address, size);
|
||||||
|
|
||||||
|
/* Validate that addresses are page aligned. */
|
||||||
|
R_UNLESS(util::IsAligned(dst_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
R_UNLESS(util::IsAligned(src_address, PageSize), svc::ResultInvalidAddress());
|
||||||
|
|
||||||
|
/* Validate that size is positive and page aligned. */
|
||||||
|
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||||
|
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
|
||||||
|
|
||||||
|
/* Ensure that neither mapping overflows. */
|
||||||
|
R_UNLESS(src_address < src_address + size, svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS(dst_address < dst_address + size, svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Get the page table we're operating on. */
|
||||||
|
auto &page_table = GetCurrentProcess().GetPageTable();
|
||||||
|
|
||||||
|
/* Ensure that the memory we're mapping is in range. */
|
||||||
|
R_UNLESS(page_table.Contains(src_address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
R_UNLESS(page_table.CanContain(dst_address, size, KMemoryState_Stack), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
|
/* Map the memory. */
|
||||||
|
return page_table.MapMemory(dst_address, src_address, size);
|
||||||
|
}
|
||||||
|
|
||||||
Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) {
|
Result UnmapMemory(uintptr_t dst_address, uintptr_t src_address, size_t size) {
|
||||||
/* Log the call parameters for debugging. */
|
/* Log the call parameters for debugging. */
|
||||||
MESOSPHERE_LOG("UnmapMemory(%zx, %zx, %zx)\n", dst_address, src_address, size);
|
MESOSPHERE_LOG("UnmapMemory(%zx, %zx, %zx)\n", dst_address, src_address, size);
|
||||||
|
@ -61,7 +88,7 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
Result MapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapMemory64 was called.");
|
return MapMemory(dst_address, src_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
Result UnmapMemory64(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
||||||
|
@ -79,7 +106,7 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
Result MapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
||||||
MESOSPHERE_PANIC("Stubbed SvcMapMemory64From32 was called.");
|
return MapMemory(dst_address, src_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result UnmapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
Result UnmapMemory64From32(ams::svc::Address dst_address, ams::svc::Address src_address, ams::svc::Size size) {
|
||||||
|
|
Loading…
Reference in a new issue