mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-25 03:36:02 +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 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 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); }
|
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;
|
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;
|
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
||||||
size_t GetRegionSize(KMemoryState state) const;
|
size_t GetRegionSize(KMemoryState state) const;
|
||||||
bool CanContain(KProcessAddress addr, size_t size, 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 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 u64 GetRandomEntropy(size_t i) const { return this->entropy[i]; }
|
||||||
|
|
||||||
constexpr bool IsApplication() const { return this->is_application; }
|
constexpr bool IsApplication() const { return this->is_application; }
|
||||||
|
|
|
@ -62,6 +62,7 @@ namespace ams::kern::svc {
|
||||||
|
|
||||||
/* 131 */ using ::ams::svc::ResultPortClosed;
|
/* 131 */ using ::ams::svc::ResultPortClosed;
|
||||||
/* 132 */ using ::ams::svc::ResultLimitReached;
|
/* 132 */ using ::ams::svc::ResultLimitReached;
|
||||||
|
/* 133 */ using ::ams::svc::ResultInvalidMemoryPool;
|
||||||
|
|
||||||
/* 258 */ using ::ams::svc::ResultReceiveListBroken;
|
/* 258 */ using ::ams::svc::ResultReceiveListBroken;
|
||||||
/* 259 */ using ::ams::svc::ResultOutOfAddressSpace;
|
/* 259 */ using ::ams::svc::ResultOutOfAddressSpace;
|
||||||
|
|
|
@ -3567,11 +3567,91 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) {
|
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) {
|
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();
|
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 ============================= */
|
/* ============================= 64 ABI ============================= */
|
||||||
|
@ -108,11 +147,11 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapPhysicalMemoryUnsafe64(ams::svc::Address address, ams::svc::Size size) {
|
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) {
|
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) {
|
Result SetUnsafeLimit64(ams::svc::Size limit) {
|
||||||
|
@ -135,11 +174,11 @@ namespace ams::kern::svc {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapPhysicalMemoryUnsafe64From32(ams::svc::Address address, ams::svc::Size size) {
|
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) {
|
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) {
|
Result SetUnsafeLimit64From32(ams::svc::Size limit) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ namespace ams::svc {
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(PortClosed, 131);
|
R_DEFINE_ERROR_RESULT(PortClosed, 131);
|
||||||
R_DEFINE_ERROR_RESULT(LimitReached, 132);
|
R_DEFINE_ERROR_RESULT(LimitReached, 132);
|
||||||
|
R_DEFINE_ERROR_RESULT(InvalidMemoryPool, 133);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RESULT(ReceiveListBroken, 258);
|
R_DEFINE_ERROR_RESULT(ReceiveListBroken, 258);
|
||||||
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 259);
|
R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 259);
|
||||||
|
|
Loading…
Reference in a new issue