kern: SvcMapPhysicalMemoryUnsafe, SvcUnmapPhysicalMemoryUnsafe

This commit is contained in:
Michael Scire 2020-07-24 22:04:04 -07:00 committed by SciresM
parent 583899ede3
commit 840ab0785c
7 changed files with 135 additions and 6 deletions

View file

@ -227,6 +227,7 @@ namespace ams::kern::arch::arm64 {
bool Contains(KProcessAddress addr, size_t size) const { return this->page_table.Contains(addr, size); }
bool IsInAliasRegion(KProcessAddress addr, size_t size) const { return this->page_table.IsInAliasRegion(addr, size); }
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return this->page_table.IsInUnsafeAliasRegion(addr, size); }
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->page_table.CanContain(addr, size, state); }

View file

@ -184,6 +184,11 @@ namespace ams::kern {
return this->Contains(addr, size) && this->alias_region_start <= addr && addr + size - 1 <= this->alias_region_end - 1;
}
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
return this->CanContain(addr, size, KMemoryState_AliasCode);
}
KProcessAddress GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;

View file

@ -153,6 +153,8 @@ namespace ams::kern {
constexpr KProcessAddress GetEntryPoint() const { return this->code_address; }
constexpr KMemoryManager::Pool GetMemoryPool() const { return this->memory_pool; }
constexpr u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; }
constexpr bool IsApplication() const { return this->is_application; }

View file

@ -62,6 +62,7 @@ namespace ams::kern::svc {
/* 131 */ using ::ams::svc::ResultPortClosed;
/* 132 */ using ::ams::svc::ResultLimitReached;
/* 133 */ using ::ams::svc::ResultInvalidMemoryPool;
/* 258 */ using ::ams::svc::ResultReceiveListBroken;
/* 259 */ using ::ams::svc::ResultOutOfAddressSpace;

View file

@ -3567,11 +3567,91 @@ namespace ams::kern {
}
Result KPageTableBase::MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) {
MESOSPHERE_UNIMPLEMENTED();
/* Try to reserve the unsafe memory. */
R_UNLESS(Kernel::GetUnsafeMemory().TryReserve(size), svc::ResultLimitReached());
/* Ensure we release our reservation on failure. */
auto reserve_guard = SCOPE_GUARD { Kernel::GetUnsafeMemory().Release(size); };
/* Create a page group for the new memory. */
KPageGroup pg(this->block_info_manager);
/* Allocate the new memory. */
const size_t num_pages = size / PageSize;
R_TRY(Kernel::GetMemoryManager().Allocate(std::addressof(pg), num_pages, KMemoryManager::EncodeOption(KMemoryManager::Pool_Unsafe, KMemoryManager::Direction_FromFront)));
/* Open the page group, and close it when we're done with it. */
pg.Open();
ON_SCOPE_EXIT { pg.Close(); };
/* Clear the new memory. */
for (const auto &block : pg) {
std::memset(GetVoidPointer(block.GetAddress()), this->heap_fill_value, block.GetSize());
}
/* Map the new memory. */
{
/* Lock the table. */
KScopedLightLock lk(this->general_lock);
/* Check the memory state. */
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
/* Create an update allocator. */
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
R_TRY(allocator.GetResult());
/* We're going to perform an update, so create a helper. */
KScopedPageTableUpdater updater(this);
/* Map the pages. */
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, false };
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, pg, map_properties, OperationType_MapGroup, false));
/* Apply the memory block update. */
this->memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None);
/* Update our mapped unsafe size. */
this->mapped_unsafe_physical_memory += size;
/* We succeeded. */
reserve_guard.Cancel();
return ResultSuccess();
}
}
Result KPageTableBase::UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) {
MESOSPHERE_UNIMPLEMENTED();
/* Lock the table. */
KScopedLightLock lk(this->general_lock);
/* Check whether we can unmap this much unsafe physical memory. */
R_UNLESS(size <= this->mapped_unsafe_physical_memory, svc::ResultInvalidCurrentMemory());
/* Check the memory state. */
R_TRY(this->CheckMemoryState(address, size, KMemoryState_All, KMemoryState_Normal, KMemoryPermission_All, KMemoryPermission_UserReadWrite, KMemoryAttribute_All, KMemoryAttribute_None));
/* Create an update allocator. */
KMemoryBlockManagerUpdateAllocator allocator(this->memory_block_slab_manager);
R_TRY(allocator.GetResult());
/* We're going to perform an update, so create a helper. */
KScopedPageTableUpdater updater(this);
/* Unmap the memory. */
const size_t num_pages = size / PageSize;
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, false };
R_TRY(this->Operate(updater.GetPageList(), address, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
/* Apply the memory block update. */
this->memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None);
/* Release the unsafe memory from the limit. */
Kernel::GetUnsafeMemory().Release(size);
/* Update our mapped unsafe size. */
this->mapped_unsafe_physical_memory -= size;
return ResultSuccess();
}
}

View file

@ -90,6 +90,45 @@ namespace ams::kern::svc {
return ResultSuccess();
}
Result MapPhysicalMemoryUnsafe(uintptr_t address, size_t size) {
/* Validate address / size. */
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
R_UNLESS(size > 0, svc::ResultInvalidSize());
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
/* Verify that the region is in range. */
auto &process = GetCurrentProcess();
auto &page_table = process.GetPageTable();
R_UNLESS(page_table.IsInUnsafeAliasRegion(address, size), svc::ResultInvalidMemoryRegion());
/* Verify that the process isn't already using the unsafe pool. */
R_UNLESS(process.GetMemoryPool() != KMemoryManager::Pool_Unsafe, svc::ResultInvalidMemoryPool());
/* Map the memory. */
R_TRY(page_table.MapPhysicalMemoryUnsafe(address, size));
return ResultSuccess();
}
Result UnmapPhysicalMemoryUnsafe(uintptr_t address, size_t size) {
/* Validate address / size. */
R_UNLESS(util::IsAligned(address, PageSize), svc::ResultInvalidAddress());
R_UNLESS(util::IsAligned(size, PageSize), svc::ResultInvalidSize());
R_UNLESS(size > 0, svc::ResultInvalidSize());
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
/* Verify that the region is in range. */
auto &process = GetCurrentProcess();
auto &page_table = process.GetPageTable();
R_UNLESS(page_table.IsInUnsafeAliasRegion(address, size), svc::ResultInvalidMemoryRegion());
/* Unmap the memory. */
R_TRY(page_table.UnmapPhysicalMemoryUnsafe(address, size));
return ResultSuccess();
}
}
/* ============================= 64 ABI ============================= */
@ -108,11 +147,11 @@ namespace ams::kern::svc {
}
Result MapPhysicalMemoryUnsafe64(ams::svc::Address address, ams::svc::Size size) {
MESOSPHERE_PANIC("Stubbed SvcMapPhysicalMemoryUnsafe64 was called.");
return MapPhysicalMemoryUnsafe(address, size);
}
Result UnmapPhysicalMemoryUnsafe64(ams::svc::Address address, ams::svc::Size size) {
MESOSPHERE_PANIC("Stubbed SvcUnmapPhysicalMemoryUnsafe64 was called.");
return UnmapPhysicalMemoryUnsafe(address, size);
}
Result SetUnsafeLimit64(ams::svc::Size limit) {
@ -135,11 +174,11 @@ namespace ams::kern::svc {
}
Result MapPhysicalMemoryUnsafe64From32(ams::svc::Address address, ams::svc::Size size) {
MESOSPHERE_PANIC("Stubbed SvcMapPhysicalMemoryUnsafe64From32 was called.");
return MapPhysicalMemoryUnsafe(address, size);
}
Result UnmapPhysicalMemoryUnsafe64From32(ams::svc::Address address, ams::svc::Size size) {
MESOSPHERE_PANIC("Stubbed SvcUnmapPhysicalMemoryUnsafe64From32 was called.");
return UnmapPhysicalMemoryUnsafe(address, size);
}
Result SetUnsafeLimit64From32(ams::svc::Size limit) {

View file

@ -65,6 +65,7 @@ namespace ams::svc {
R_DEFINE_ERROR_RESULT(PortClosed, 131);
R_DEFINE_ERROR_RESULT(LimitReached, 132);
R_DEFINE_ERROR_RESULT(InvalidMemoryPool, 133);
R_DEFINE_ERROR_RESULT(ReceiveListBroken, 258);
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 259);