strat: remove map namespace, svc: add address space defs

This commit is contained in:
Michael Scire 2021-10-05 12:22:34 -07:00
parent 69777cf792
commit 719ead824e
17 changed files with 643 additions and 494 deletions

View file

@ -22,19 +22,19 @@ namespace ams::kern {
constexpr uintptr_t Invalid = std::numeric_limits<uintptr_t>::max();
constexpr KAddressSpaceInfo AddressSpaceInfos[] = {
{ 32, 2_MB, 1_GB - 2_MB, KAddressSpaceInfo::Type_MapSmall, },
{ 32, 1_GB, 4_GB - 1_GB, KAddressSpaceInfo::Type_MapLarge, },
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Heap, },
{ 32, Invalid, 1_GB, KAddressSpaceInfo::Type_Alias, },
{ 36, 128_MB, 2_GB - 128_MB, KAddressSpaceInfo::Type_MapSmall, },
{ 36, 2_GB, 64_GB - 2_GB, KAddressSpaceInfo::Type_MapLarge, },
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
{ 36, Invalid, 6_GB, KAddressSpaceInfo::Type_Alias, },
{ 39, 128_MB, 512_GB - 128_MB, KAddressSpaceInfo::Type_Map39Bit, },
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_MapSmall, },
{ 39, Invalid, 6_GB, KAddressSpaceInfo::Type_Heap, },
{ 39, Invalid, 64_GB, KAddressSpaceInfo::Type_Alias, },
{ 39, Invalid, 2_GB, KAddressSpaceInfo::Type_Stack, },
{ 32, ams::svc::AddressSmallMap32Start, ams::svc::AddressSmallMap32Size, KAddressSpaceInfo::Type_MapSmall, },
{ 32, ams::svc::AddressLargeMap32Start, ams::svc::AddressLargeMap32Size, KAddressSpaceInfo::Type_MapLarge, },
{ 32, Invalid, ams::svc::AddressMemoryRegionHeap32Size, KAddressSpaceInfo::Type_Heap, },
{ 32, Invalid, ams::svc::AddressMemoryRegionAlias32Size, KAddressSpaceInfo::Type_Alias, },
{ 36, ams::svc::AddressSmallMap36Start, ams::svc::AddressSmallMap36Size, KAddressSpaceInfo::Type_MapSmall, },
{ 36, ams::svc::AddressLargeMap36Start, ams::svc::AddressLargeMap36Size, KAddressSpaceInfo::Type_MapLarge, },
{ 36, Invalid, ams::svc::AddressMemoryRegionHeap36Size, KAddressSpaceInfo::Type_Heap, },
{ 36, Invalid, ams::svc::AddressMemoryRegionAlias36Size, KAddressSpaceInfo::Type_Alias, },
{ 39, ams::svc::AddressMap39Start, ams::svc::AddressMap39Size, KAddressSpaceInfo::Type_Map39Bit, },
{ 39, Invalid, ams::svc::AddressMemoryRegionSmall39Size, KAddressSpaceInfo::Type_MapSmall, },
{ 39, Invalid, ams::svc::AddressMemoryRegionHeap39Size, KAddressSpaceInfo::Type_Heap, },
{ 39, Invalid, ams::svc::AddressMemoryRegionAlias39Size, KAddressSpaceInfo::Type_Alias, },
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
};
constexpr bool IsAllowedIndexForAddress(size_t index) {

View file

@ -66,7 +66,6 @@
#include <stratosphere/ldr.hpp>
#include <stratosphere/lr.hpp>
#include <stratosphere/lm.hpp>
#include <stratosphere/map.hpp>
#include <stratosphere/ncm.hpp>
#include <stratosphere/nim.hpp>
#include <stratosphere/ns.hpp>

View file

@ -1,20 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/map/map_types.hpp>
#include <stratosphere/map/map_api.hpp>

View file

@ -1,28 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stratosphere/map/map_types.hpp>
namespace ams::map {
/* Public API. */
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, os::NativeHandle process_h);
Result LocateMappableSpace(uintptr_t *out_address, size_t size);
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size);
bool CanAddGuardRegionsInProcess(os::NativeHandle process_handle, uintptr_t address, size_t size);
}

View file

@ -1,123 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <stratosphere/os/os_native_handle.hpp>
namespace ams::map {
/* Types. */
struct AddressSpaceInfo {
uintptr_t heap_base;
size_t heap_size;
uintptr_t heap_end;
uintptr_t alias_base;
size_t alias_size;
uintptr_t alias_end;
uintptr_t aslr_base;
size_t aslr_size;
uintptr_t aslr_end;
};
static constexpr uintptr_t AslrBase32Bit = 0x0000200000ul;
static constexpr size_t AslrSize32Bit = 0x003FE00000ul;
static constexpr uintptr_t AslrBase64BitDeprecated = 0x0008000000ul;
static constexpr size_t AslrSize64BitDeprecated = 0x0078000000ul;
static constexpr uintptr_t AslrBase64Bit = 0x0008000000ul;
static constexpr size_t AslrSize64Bit = 0x7FF8000000ul;
class AutoCloseMap {
private:
os::NativeHandle process_handle;
Result result;
uintptr_t mapped_address;
uintptr_t base_address;
size_t size;
public:
AutoCloseMap(uintptr_t mp, os::NativeHandle p_h, uintptr_t ba, size_t sz) : process_handle(p_h), mapped_address(mp), base_address(ba), size(sz) {
this->result = svc::MapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size);
}
~AutoCloseMap() {
if (this->process_handle != os::InvalidNativeHandle && R_SUCCEEDED(this->result)) {
R_ABORT_UNLESS(svc::UnmapProcessMemory(this->mapped_address, this->process_handle, this->base_address, this->size));
}
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = os::InvalidNativeHandle;
}
};
class MappedCodeMemory {
private:
os::NativeHandle process_handle;
Result result;
uintptr_t dst_address;
uintptr_t src_address;
size_t size;
public:
MappedCodeMemory(Result init_res) : process_handle(os::InvalidNativeHandle), result(init_res), dst_address(0), src_address(0), size(0) {
/* ... */
}
MappedCodeMemory(os::NativeHandle p_h, uintptr_t dst, uintptr_t src, size_t sz) : process_handle(p_h), dst_address(dst), src_address(src), size(sz) {
this->result = svc::MapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size);
}
~MappedCodeMemory() {
if (this->process_handle != os::InvalidNativeHandle && R_SUCCEEDED(this->result) && this->size > 0) {
R_ABORT_UNLESS(svc::UnmapProcessCodeMemory(this->process_handle, this->dst_address, this->src_address, this->size));
}
}
uintptr_t GetDstAddress() const {
return this->dst_address;
}
Result GetResult() const {
return this->result;
}
bool IsSuccess() const {
return R_SUCCEEDED(this->result);
}
void Invalidate() {
this->process_handle = os::InvalidNativeHandle;
}
MappedCodeMemory &operator=(MappedCodeMemory &&o) {
this->process_handle = o.process_handle;
this->result = o.result;
this->dst_address = o.dst_address;
this->src_address = o.src_address;
this->size = o.size;
o.Invalidate();
return *this;
}
};
}

View file

@ -1,205 +0,0 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stratosphere.hpp>
namespace ams::map {
namespace {
/* Convenience defines. */
constexpr size_t GuardRegionSize = 0x4000;
constexpr size_t LocateRetryCount = 0x200;
/* Deprecated/Modern implementations. */
Result LocateMappableSpaceDeprecated(uintptr_t *out_address, size_t size) {
svc::MemoryInfo mem_info;
svc::PageInfo page_info;
uintptr_t cur_base = 0;
AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base;
do {
R_TRY(svc::QueryMemory(&mem_info, &page_info, cur_base));
if (mem_info.state == svc::MemoryState_Free && mem_info.addr - cur_base + mem_info.size >= size) {
*out_address = cur_base;
return ResultSuccess();
}
const uintptr_t mem_end = mem_info.addr + mem_info.size;
R_UNLESS(mem_info.state != svc::MemoryState_Inaccessible, svc::ResultOutOfMemory());
R_UNLESS(cur_base <= mem_end, svc::ResultOutOfMemory());
R_UNLESS(mem_end <= static_cast<uintptr_t>(std::numeric_limits<s32>::max()), svc::ResultOutOfMemory());
cur_base = mem_end;
} while (true);
}
Result LocateMappableSpaceModern(uintptr_t *out_address, size_t size) {
svc::MemoryInfo mem_info;
svc::PageInfo page_info;
uintptr_t cur_base = 0, cur_end = 0;
AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, dd::GetCurrentProcessHandle()));
cur_base = address_space.aslr_base;
cur_end = cur_base + size;
R_UNLESS(cur_base < cur_end, svc::ResultOutOfMemory());
while (true) {
if (address_space.heap_size && (address_space.heap_base <= cur_end - 1 && cur_base <= address_space.heap_end - 1)) {
/* If we overlap the heap region, go to the end of the heap region. */
R_UNLESS(cur_base != address_space.heap_end, svc::ResultOutOfMemory());
cur_base = address_space.heap_end;
} else if (address_space.alias_size && (address_space.alias_base <= cur_end - 1 && cur_base <= address_space.alias_end - 1)) {
/* If we overlap the alias region, go to the end of the alias region. */
R_UNLESS(cur_base != address_space.alias_end, svc::ResultOutOfMemory());
cur_base = address_space.alias_end;
} else {
R_ABORT_UNLESS(svc::QueryMemory(&mem_info, &page_info, cur_base));
if (mem_info.state == svc::MemoryState_Free && mem_info.addr - cur_base + mem_info.size >= size) {
*out_address = cur_base;
return ResultSuccess();
}
R_UNLESS(cur_base < mem_info.addr + mem_info.size, svc::ResultOutOfMemory());
cur_base = mem_info.addr + mem_info.size;
R_UNLESS(cur_base < address_space.aslr_end, svc::ResultOutOfMemory());
}
cur_end = cur_base + size;
R_UNLESS(cur_base < cur_base + size, svc::ResultOutOfMemory());
}
}
Result MapCodeMemoryInProcessDeprecated(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, process_handle));
R_UNLESS(size <= address_space.aslr_size, ro::ResultOutOfAddressSpace());
uintptr_t try_address;
for (unsigned int i = 0; i < LocateRetryCount; i++) {
try_address = address_space.aslr_base + (os::GenerateRandomU64(static_cast<u64>(address_space.aslr_size - size) / os::MemoryPageSize) * os::MemoryPageSize);
MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size);
R_TRY_CATCH(tmp_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
} R_END_TRY_CATCH;
if (!CanAddGuardRegionsInProcess(process_handle, try_address, size)) {
continue;
}
/* We're done searching. */
out_mcm = std::move(tmp_mcm);
return ResultSuccess();
}
return ro::ResultOutOfAddressSpace();
}
Result MapCodeMemoryInProcessModern(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
AddressSpaceInfo address_space;
R_TRY(GetProcessAddressSpaceInfo(&address_space, process_handle));
R_UNLESS(size <= address_space.aslr_size, ro::ResultOutOfAddressSpace());
uintptr_t try_address;
for (unsigned int i = 0; i < LocateRetryCount; i++) {
while (true) {
try_address = address_space.aslr_base + (os::GenerateRandomU64(static_cast<u64>(address_space.aslr_size - size) / os::MemoryPageSize) * os::MemoryPageSize);
if (address_space.heap_size && (address_space.heap_base <= try_address + size - 1 && try_address <= address_space.heap_end - 1)) {
continue;
}
if (address_space.alias_size && (address_space.alias_base <= try_address + size - 1 && try_address <= address_space.alias_end - 1)) {
continue;
}
break;
}
MappedCodeMemory tmp_mcm(process_handle, try_address, base_address, size);
R_TRY_CATCH(tmp_mcm.GetResult()) {
R_CATCH(svc::ResultInvalidCurrentMemory) { continue; }
} R_END_TRY_CATCH;
if (!CanAddGuardRegionsInProcess(process_handle, try_address, size)) {
continue;
}
/* We're done searching. */
out_mcm = std::move(tmp_mcm);
return ResultSuccess();
}
return ro::ResultOutOfAddressSpace();
}
}
/* Public API. */
Result GetProcessAddressSpaceInfo(AddressSpaceInfo *out, os::NativeHandle process_h) {
/* Clear output. */
std::memset(out, 0, sizeof(*out));
/* Retrieve info from kernel. */
R_TRY(svc::GetInfo(&out->heap_base, svc::InfoType_HeapRegionAddress, process_h, 0));
R_TRY(svc::GetInfo(&out->heap_size, svc::InfoType_HeapRegionSize, process_h, 0));
R_TRY(svc::GetInfo(&out->alias_base, svc::InfoType_AliasRegionAddress, process_h, 0));
R_TRY(svc::GetInfo(&out->alias_size, svc::InfoType_AliasRegionSize, process_h, 0));
R_TRY(svc::GetInfo(&out->aslr_base, svc::InfoType_AslrRegionAddress, process_h, 0));
R_TRY(svc::GetInfo(&out->aslr_size, svc::InfoType_AslrRegionSize, process_h, 0));
out->heap_end = out->heap_base + out->heap_size;
out->alias_end = out->alias_base + out->alias_size;
out->aslr_end = out->aslr_base + out->aslr_size;
return ResultSuccess();
}
Result LocateMappableSpace(uintptr_t *out_address, size_t size) {
if (hos::GetVersion() >= hos::Version_2_0_0) {
return LocateMappableSpaceModern(out_address, size);
} else {
return LocateMappableSpaceDeprecated(out_address, size);
}
}
Result MapCodeMemoryInProcess(MappedCodeMemory &out_mcm, os::NativeHandle process_handle, uintptr_t base_address, size_t size) {
if (hos::GetVersion() >= hos::Version_2_0_0) {
return MapCodeMemoryInProcessModern(out_mcm, process_handle, base_address, size);
} else {
return MapCodeMemoryInProcessDeprecated(out_mcm, process_handle, base_address, size);
}
}
bool CanAddGuardRegionsInProcess(os::NativeHandle process_handle, uintptr_t address, size_t size) {
svc::MemoryInfo mem_info;
svc::PageInfo page_info;
/* Nintendo doesn't validate SVC return values at all. */
/* TODO: Should we allow these to fail? */
R_ABORT_UNLESS(svc::QueryProcessMemory(&mem_info, &page_info, process_handle, address - 1));
if (mem_info.state == svc::MemoryState_Free && address - GuardRegionSize >= mem_info.addr) {
R_ABORT_UNLESS(svc::QueryProcessMemory(&mem_info, &page_info, process_handle, address + size));
return mem_info.state == svc::MemoryState_Free && address + size + GuardRegionSize <= mem_info.addr + mem_info.size;
}
return false;
}
}

View file

@ -21,5 +21,6 @@
#include <vapours/svc/svc_types.hpp>
#include <vapours/svc/svc_definitions.hpp>
#include <vapours/svc/svc_memory_map.hpp>
#include <vapours/svc/svc_version.hpp>
#include <vapours/svc/ipc/svc_message_buffer.hpp>

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours/common.hpp>
namespace ams::svc {
#if defined(ATMOSPHERE_ARCH_ARM64)
constexpr inline size_t AddressMemoryRegionSmall32Size = 1_GB;
constexpr inline size_t AddressMemoryRegionLarge32Size = 4_GB - AddressMemoryRegionSmall32Size;
constexpr inline size_t AddressMemoryRegionHeap32Size = 1_GB;
constexpr inline size_t AddressMemoryRegionAlias32Size = 1_GB;
constexpr inline size_t AddressMemoryRegionSmall36Size = 2_GB;
constexpr inline size_t AddressMemoryRegionLarge36Size = 64_GB - AddressMemoryRegionSmall36Size;
constexpr inline size_t AddressMemoryRegionHeap36Size = 6_GB;
constexpr inline size_t AddressMemoryRegionAlias36Size = 6_GB;
constexpr inline size_t AddressMemoryRegionSmall39Size = 64_GB;
constexpr inline size_t AddressMemoryRegionHeap39Size = 6_GB;
constexpr inline size_t AddressMemoryRegionAlias39Size = 64_GB;
constexpr inline size_t AddressMemoryRegionStack39Size = 2_GB;
constexpr inline size_t AddressMemoryRegion39Size = 512_GB;
#elif defined(ATMOSPHERE_ARCH_ARM)
constexpr inline size_t AddressMemoryRegionSmall32Size = 512_MB;
constexpr inline size_t AddressMemoryRegionLarge32Size = 2_GB - AddressMemoryRegionSmall32Size;
constexpr inline size_t AddressMemoryRegionHeap32Size = 1_GB;
constexpr inline size_t AddressMemoryRegionAlias32Size = 512_MB;
constexpr inline size_t AddressMemoryRegionSmall36Size = 0;
constexpr inline size_t AddressMemoryRegionLarge36Size = 0;
constexpr inline size_t AddressMemoryRegionHeap36Size = 0;
constexpr inline size_t AddressMemoryRegionAlias36Size = 0;
constexpr inline size_t AddressMemoryRegionSmall39Size = 0;
constexpr inline size_t AddressMemoryRegionHeap39Size = 0;
constexpr inline size_t AddressMemoryRegionAlias39Size = 0;
constexpr inline size_t AddressMemoryRegionStack39Size = 0;
constexpr inline size_t AddressMemoryRegion39Size = 0;
#else
#error "Unknown architecture for svc::AddressMemoryRegion*Size"
#endif
constexpr inline size_t AddressNullGuard32Size = 2_MB;
constexpr inline size_t AddressNullGuard64Size = 128_MB;
constexpr inline uintptr_t AddressMemoryRegionSmall32Start = 0;
constexpr inline uintptr_t AddressMemoryRegionSmall32End = AddressMemoryRegionSmall32Start + AddressMemoryRegionSmall32Size;
constexpr inline uintptr_t AddressMemoryRegionLarge32Start = AddressMemoryRegionSmall32End;
constexpr inline uintptr_t AddressMemoryRegionLarge32End = AddressMemoryRegionLarge32Start + AddressMemoryRegionLarge32Size;
constexpr inline uintptr_t AddressSmallMap32Start = AddressMemoryRegionSmall32Start + AddressNullGuard32Size;
constexpr inline uintptr_t AddressSmallMap32End = AddressMemoryRegionSmall32End;
constexpr inline size_t AddressSmallMap32Size = AddressSmallMap32End - AddressSmallMap32Start;
constexpr inline uintptr_t AddressLargeMap32Start = AddressMemoryRegionLarge32Start;
constexpr inline uintptr_t AddressLargeMap32End = AddressMemoryRegionLarge32End;
constexpr inline size_t AddressLargeMap32Size = AddressLargeMap32End - AddressLargeMap32Start;
constexpr inline uintptr_t AddressMemoryRegionSmall36Start = 0;
constexpr inline uintptr_t AddressMemoryRegionSmall36End = AddressMemoryRegionSmall36Start + AddressMemoryRegionSmall36Size;
constexpr inline uintptr_t AddressMemoryRegionLarge36Start = AddressMemoryRegionSmall36End;
constexpr inline uintptr_t AddressMemoryRegionLarge36End = AddressMemoryRegionLarge36Start + AddressMemoryRegionLarge36Size;
constexpr inline uintptr_t AddressSmallMap36Start = AddressMemoryRegionSmall36Start + AddressNullGuard64Size;
constexpr inline uintptr_t AddressSmallMap36End = AddressMemoryRegionSmall36End;
constexpr inline size_t AddressSmallMap36Size = AddressSmallMap36End - AddressSmallMap36Start;
constexpr inline uintptr_t AddressLargeMap36Start = AddressMemoryRegionLarge36Start;
constexpr inline uintptr_t AddressLargeMap36End = AddressMemoryRegionLarge36End;
constexpr inline size_t AddressLargeMap36Size = AddressLargeMap36End - AddressLargeMap36Start;
constexpr inline uintptr_t AddressMap39Start = 0 + AddressNullGuard64Size;
constexpr inline uintptr_t AddressMap39End = AddressMemoryRegion39Size;
constexpr inline size_t AddressMap39Size = AddressMap39End - AddressMap39Start;
}