mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 20:31:14 +00:00
kern: SvcMapPhysicalMemoryUnsafe, SvcUnmapPhysicalMemoryUnsafe
This commit is contained in:
parent
583899ede3
commit
840ab0785c
7 changed files with 135 additions and 6 deletions
|
@ -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); }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue