mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-01-10 14:54:48 +00:00
Compare commits
16 commits
4301e948cc
...
e6cf70a18a
Author | SHA1 | Date | |
---|---|---|---|
|
e6cf70a18a | ||
|
b4d453882d | ||
|
05df389d30 | ||
|
23d6014f91 | ||
|
496f8bf45e | ||
|
4974a98ec6 | ||
|
1f44a9c4bf | ||
|
6113ffa191 | ||
|
48e86f0406 | ||
|
bf3203da0f | ||
|
af7a200865 | ||
|
cfb12deb51 | ||
|
4aac5f0082 | ||
|
f5a9d1d6e8 | ||
|
5e63792a67 | ||
|
8cacb07d5f |
41 changed files with 1767 additions and 1230 deletions
|
@ -84,7 +84,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c
|
#mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420
|
||||||
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240
|
mkdir -p $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240
|
||||||
|
@ -98,7 +98,7 @@ dist-no-debug: package3 $(CURRENT_DIRECTORY)/$(ATMOSPHERE_OUT_DIR)
|
||||||
cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
|
cp stratosphere/fatal/$(ATMOSPHERE_OUT_DIR)/fatal.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000034/exefs.nsp
|
||||||
cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
|
cp stratosphere/creport/$(ATMOSPHERE_OUT_DIR)/creport.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000036/exefs.nsp
|
||||||
cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
|
cp stratosphere/ro/$(ATMOSPHERE_OUT_DIR)/ro.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000037/exefs.nsp
|
||||||
cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c/exefs.nsp
|
#cp stratosphere/jpegdec/$(ATMOSPHERE_OUT_DIR)/jpegdec.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000003c/exefs.nsp
|
||||||
cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
cp stratosphere/pgl/$(ATMOSPHERE_OUT_DIR)/pgl.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000042/exefs.nsp
|
||||||
cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
cp stratosphere/LogManager/$(ATMOSPHERE_OUT_DIR)/LogManager.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/0100000000000420/exefs.nsp
|
||||||
cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp
|
cp stratosphere/htc/$(ATMOSPHERE_OUT_DIR)/htc.nsp $(DIST_DIR)/stratosphere_romfs/atmosphere/contents/010000000000b240/exefs.nsp
|
||||||
|
|
2
emummc/README.md
vendored
2
emummc/README.md
vendored
|
@ -2,7 +2,7 @@
|
||||||
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
*A SDMMC driver replacement for Nintendo's Filesystem Services, by **m4xw***
|
||||||
|
|
||||||
### Supported Horizon Versions
|
### Supported Horizon Versions
|
||||||
**1.0.0 - 17.0.0**
|
**1.0.0 - 18.0.0**
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
* Arbitrary SDMMC backend selection
|
* Arbitrary SDMMC backend selection
|
||||||
|
|
8
emummc/source/FS/FS_offsets.c
vendored
8
emummc/source/FS/FS_offsets.c
vendored
|
@ -69,6 +69,8 @@
|
||||||
#include "offsets/1603_exfat.h"
|
#include "offsets/1603_exfat.h"
|
||||||
#include "offsets/1700.h"
|
#include "offsets/1700.h"
|
||||||
#include "offsets/1700_exfat.h"
|
#include "offsets/1700_exfat.h"
|
||||||
|
#include "offsets/1800.h"
|
||||||
|
#include "offsets/1800_exfat.h"
|
||||||
#include "../utils/fatal.h"
|
#include "../utils/fatal.h"
|
||||||
|
|
||||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||||
|
@ -149,6 +151,8 @@ DEFINE_OFFSET_STRUCT(_1603);
|
||||||
DEFINE_OFFSET_STRUCT(_1603_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1603_EXFAT);
|
||||||
DEFINE_OFFSET_STRUCT(_1700);
|
DEFINE_OFFSET_STRUCT(_1700);
|
||||||
DEFINE_OFFSET_STRUCT(_1700_EXFAT);
|
DEFINE_OFFSET_STRUCT(_1700_EXFAT);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1800);
|
||||||
|
DEFINE_OFFSET_STRUCT(_1800_EXFAT);
|
||||||
|
|
||||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
|
@ -258,6 +262,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_1700));
|
return &(GET_OFFSET_STRUCT_NAME(_1700));
|
||||||
case FS_VER_17_0_0_EXFAT:
|
case FS_VER_17_0_0_EXFAT:
|
||||||
return &(GET_OFFSET_STRUCT_NAME(_1700_EXFAT));
|
return &(GET_OFFSET_STRUCT_NAME(_1700_EXFAT));
|
||||||
|
case FS_VER_18_0_0:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1800));
|
||||||
|
case FS_VER_18_0_0_EXFAT:
|
||||||
|
return &(GET_OFFSET_STRUCT_NAME(_1800_EXFAT));
|
||||||
default:
|
default:
|
||||||
fatal_abort(Fatal_UnknownVersion);
|
fatal_abort(Fatal_UnknownVersion);
|
||||||
}
|
}
|
||||||
|
|
3
emummc/source/FS/FS_versions.h
vendored
3
emummc/source/FS/FS_versions.h
vendored
|
@ -101,6 +101,9 @@ enum FS_VER
|
||||||
FS_VER_17_0_0,
|
FS_VER_17_0_0,
|
||||||
FS_VER_17_0_0_EXFAT,
|
FS_VER_17_0_0_EXFAT,
|
||||||
|
|
||||||
|
FS_VER_18_0_0,
|
||||||
|
FS_VER_18_0_0_EXFAT,
|
||||||
|
|
||||||
FS_VER_MAX,
|
FS_VER_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
59
emummc/source/FS/offsets/1800.h
vendored
Normal file
59
emummc/source/FS/offsets/1800.h
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-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/>.
|
||||||
|
*/
|
||||||
|
#ifndef __FS_1800_H__
|
||||||
|
#define __FS_1800_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_GC 0x18AB00
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_SD 0x18C800
|
||||||
|
#define FS_OFFSET_1800_SDMMC_ACCESSOR_NAND 0x18AFE0
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_READ 0x186A50
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_WRITE 0x186AB0
|
||||||
|
#define FS_OFFSET_1800_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1800_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_CLKRST_SET_MIN_V_CLK_RATE 0x1A77D0
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1800_LOCK_MUTEX 0x17FCC0
|
||||||
|
#define FS_OFFSET_1800_UNLOCK_MUTEX 0x17FD10
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_OPEN 0x186A10
|
||||||
|
#define FS_OFFSET_1800_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x186A30
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1800_SD_MUTEX 0xFD13F0
|
||||||
|
#define FS_OFFSET_1800_NAND_MUTEX 0xFCCB28
|
||||||
|
#define FS_OFFSET_1800_ACTIVE_PARTITION 0xFCCB68
|
||||||
|
#define FS_OFFSET_1800_SDMMC_DAS_HANDLE 0xFB1950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1800_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1800_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1800_H__
|
59
emummc/source/FS/offsets/1800_exfat.h
vendored
Normal file
59
emummc/source/FS/offsets/1800_exfat.h
vendored
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||||
|
* Copyright (c) 2019 Atmosphere-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/>.
|
||||||
|
*/
|
||||||
|
#ifndef __FS_1800_EXFAT_H__
|
||||||
|
#define __FS_1800_EXFAT_H__
|
||||||
|
|
||||||
|
// Accessor vtable getters
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_GC 0x195B90
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_SD 0x197890
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_ACCESSOR_NAND 0x196070
|
||||||
|
|
||||||
|
// Hooks
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_READ 0x191AE0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_WRITE 0x191B40
|
||||||
|
#define FS_OFFSET_1800_EXFAT_RTLD 0x2A3A4
|
||||||
|
#define FS_OFFSET_1800_EXFAT_RTLD_DESTINATION ((uintptr_t)(INT64_C(-0x44)))
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x1B2860
|
||||||
|
|
||||||
|
// Misc funcs
|
||||||
|
#define FS_OFFSET_1800_EXFAT_LOCK_MUTEX 0x18AD50
|
||||||
|
#define FS_OFFSET_1800_EXFAT_UNLOCK_MUTEX 0x18ADA0
|
||||||
|
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_OPEN 0x191AA0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x191AC0
|
||||||
|
|
||||||
|
// Misc Data
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SD_MUTEX 0xFE33F0
|
||||||
|
#define FS_OFFSET_1800_EXFAT_NAND_MUTEX 0xFDEB28
|
||||||
|
#define FS_OFFSET_1800_EXFAT_ACTIVE_PARTITION 0xFDEB68
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SDMMC_DAS_HANDLE 0xFBE950
|
||||||
|
|
||||||
|
// NOPs
|
||||||
|
#define FS_OFFSET_1800_EXFAT_SD_DAS_INIT 0x28F24
|
||||||
|
|
||||||
|
// Nintendo Paths
|
||||||
|
#define FS_OFFSET_1800_EXFAT_NINTENDO_PATHS \
|
||||||
|
{ \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x00068B08, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 3, .adrp_offset = 0x000758DC, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x0007C77C, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 4, .adrp_offset = 0x000905C4, .add_rel_offset = 0x00000004}, \
|
||||||
|
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // __FS_1800_EXFAT_H__
|
|
@ -177,7 +177,6 @@ namespace ams::fuse {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||||
TargetFirmware_18_0_0,
|
|
||||||
TargetFirmware_17_0_0,
|
TargetFirmware_17_0_0,
|
||||||
TargetFirmware_16_0_0,
|
TargetFirmware_16_0_0,
|
||||||
TargetFirmware_15_0_0,
|
TargetFirmware_15_0_0,
|
||||||
|
|
|
@ -178,7 +178,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
||||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||||
Result Finalize();
|
Result Finalize();
|
||||||
private:
|
private:
|
||||||
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
|
@ -30,6 +30,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
KPhysicalAddress phys_addr;
|
KPhysicalAddress phys_addr;
|
||||||
size_t block_size;
|
size_t block_size;
|
||||||
u8 sw_reserved_bits;
|
u8 sw_reserved_bits;
|
||||||
|
u8 attr;
|
||||||
|
|
||||||
constexpr bool IsHeadMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHead) != 0; }
|
constexpr bool IsHeadMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHead) != 0; }
|
||||||
constexpr bool IsHeadAndBodyMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
constexpr bool IsHeadAndBodyMergeDisabled() const { return (this->sw_reserved_bits & PageTableEntry::SoftwareReservedBit_DisableMergeHeadAndBody) != 0; }
|
||||||
|
|
|
@ -28,8 +28,8 @@ namespace ams::kern::arch::arm64 {
|
||||||
m_page_table.Activate(id);
|
m_page_table.Activate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Initialize(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||||
R_RETURN(m_page_table.InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() { m_page_table.Finalize(); }
|
void Finalize() { m_page_table.Finalize(); }
|
||||||
|
@ -316,6 +316,8 @@ namespace ams::kern::arch::arm64 {
|
||||||
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
|
size_t GetKernelMapRegionSize() const { return m_page_table.GetKernelMapRegionSize(); }
|
||||||
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
|
size_t GetAliasCodeRegionSize() const { return m_page_table.GetAliasCodeRegionSize(); }
|
||||||
|
|
||||||
|
size_t GetAliasRegionExtraSize() const { return m_page_table.GetAliasRegionExtraSize(); }
|
||||||
|
|
||||||
size_t GetNormalMemorySize() const { return m_page_table.GetNormalMemorySize(); }
|
size_t GetNormalMemorySize() const { return m_page_table.GetNormalMemorySize(); }
|
||||||
|
|
||||||
size_t GetCodeSize() const { return m_page_table.GetCodeSize(); }
|
size_t GetCodeSize() const { return m_page_table.GetCodeSize(); }
|
||||||
|
|
|
@ -16,11 +16,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <mesosphere/kern_common.hpp>
|
#include <mesosphere/kern_common.hpp>
|
||||||
#include <mesosphere/kern_select_cpu.hpp>
|
#include <mesosphere/kern_select_cpu.hpp>
|
||||||
#include <mesosphere/kern_select_interrupt_manager.hpp>
|
|
||||||
|
|
||||||
namespace ams::kern::arch::arm64::smc {
|
namespace ams::kern::arch::arm64::smc {
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
void SecureMonitorCall(u64 *buf) {
|
void SecureMonitorCall(u64 *buf) {
|
||||||
/* Load arguments into registers. */
|
/* Load arguments into registers. */
|
||||||
register u64 x0 asm("x0") = buf[0];
|
register u64 x0 asm("x0") = buf[0];
|
||||||
|
@ -32,13 +31,10 @@ namespace ams::kern::arch::arm64::smc {
|
||||||
register u64 x6 asm("x6") = buf[6];
|
register u64 x6 asm("x6") = buf[6];
|
||||||
register u64 x7 asm("x7") = buf[7];
|
register u64 x7 asm("x7") = buf[7];
|
||||||
|
|
||||||
|
/* Backup the current thread pointer. */
|
||||||
|
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
||||||
|
|
||||||
/* Perform the call. */
|
/* Perform the call. */
|
||||||
if constexpr (DisableInterrupt) {
|
|
||||||
KScopedInterruptDisable di;
|
|
||||||
|
|
||||||
/* Backup the current thread pointer. */
|
|
||||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
|
||||||
|
|
||||||
__asm__ __volatile__("smc %c[smc_id]"
|
__asm__ __volatile__("smc %c[smc_id]"
|
||||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||||
: [smc_id]"i"(SmcId)
|
: [smc_id]"i"(SmcId)
|
||||||
|
@ -47,19 +43,6 @@ namespace ams::kern::arch::arm64::smc {
|
||||||
|
|
||||||
/* Restore the current thread pointer into X18. */
|
/* Restore the current thread pointer into X18. */
|
||||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
||||||
} else {
|
|
||||||
/* Backup the current thread pointer. */
|
|
||||||
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
|
|
||||||
|
|
||||||
__asm__ __volatile__("smc %c[smc_id]"
|
|
||||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
|
||||||
: [smc_id]"i"(SmcId)
|
|
||||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
|
||||||
);
|
|
||||||
|
|
||||||
/* Restore the current thread pointer into X18. */
|
|
||||||
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store arguments to output. */
|
/* Store arguments to output. */
|
||||||
buf[0] = x0;
|
buf[0] = x0;
|
||||||
|
@ -78,18 +61,18 @@ namespace ams::kern::arch::arm64::smc {
|
||||||
PsciFunction_CpuOn = 0xC4000003,
|
PsciFunction_CpuOn = 0xC4000003,
|
||||||
};
|
};
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) {
|
u64 PsciCall(PsciFunction function, u64 x1 = 0, u64 x2 = 0, u64 x3 = 0, u64 x4 = 0, u64 x5 = 0, u64 x6 = 0, u64 x7 = 0) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } };
|
ams::svc::lp64::SecureMonitorArguments args = { { function, x1, x2, x3, x4, x5, x6, x7 } };
|
||||||
|
|
||||||
SecureMonitorCall<SmcId, DisableInterrupt>(args.r);
|
SecureMonitorCall<SmcId>(args.r);
|
||||||
|
|
||||||
return args.r[0];
|
return args.r[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int SmcId, bool DisableInterrupt>
|
template<int SmcId>
|
||||||
u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
u64 CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
return PsciCall<SmcId, DisableInterrupt>(PsciFunction_CpuOn, core_id, entrypoint, arg);
|
return PsciCall<SmcId>(PsciFunction_CpuOn, core_id, entrypoint, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -185,7 +185,7 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random);
|
Result AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index);
|
||||||
public:
|
public:
|
||||||
KMemoryManager()
|
KMemoryManager()
|
||||||
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process()
|
: m_pool_locks(), m_pool_managers_head(), m_pool_managers_tail(), m_managers(), m_num_managers(), m_optimized_process_ids(), m_has_optimized_process()
|
||||||
|
@ -199,7 +199,7 @@ namespace ams::kern {
|
||||||
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
NOINLINE void FinalizeOptimizedMemory(u64 process_id, Pool pool);
|
||||||
|
|
||||||
NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
NOINLINE KPhysicalAddress AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
|
||||||
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option);
|
NOINLINE Result AllocateAndOpen(KPageGroup *out, size_t num_pages, size_t align_pages, u32 option);
|
||||||
NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
NOINLINE Result AllocateForProcess(KPageGroup *out, size_t num_pages, u32 option, u64 process_id, u8 fill_pattern);
|
||||||
|
|
||||||
Pool GetPool(KPhysicalAddress address) const {
|
Pool GetPool(KPhysicalAddress address) const {
|
||||||
|
|
|
@ -145,6 +145,8 @@ namespace ams::kern {
|
||||||
|
|
||||||
bool IsEquivalentTo(const KPageGroup &rhs) const;
|
bool IsEquivalentTo(const KPageGroup &rhs) const;
|
||||||
|
|
||||||
|
Result CopyRangeTo(KPageGroup &out, size_t offset, size_t size) const;
|
||||||
|
|
||||||
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
ALWAYS_INLINE bool operator==(const KPageGroup &rhs) const {
|
||||||
return this->IsEquivalentTo(rhs);
|
return this->IsEquivalentTo(rhs);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,18 +62,21 @@ namespace ams::kern {
|
||||||
KPhysicalAddress m_address;
|
KPhysicalAddress m_address;
|
||||||
size_t m_size;
|
size_t m_size;
|
||||||
bool m_heap;
|
bool m_heap;
|
||||||
|
u8 m_attr;
|
||||||
public:
|
public:
|
||||||
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false) { /* ... */ }
|
constexpr MemoryRange() : m_address(Null<KPhysicalAddress>), m_size(0), m_heap(false), m_attr(0) { /* ... */ }
|
||||||
|
|
||||||
void Set(KPhysicalAddress address, size_t size, bool heap) {
|
void Set(KPhysicalAddress address, size_t size, bool heap, u8 attr) {
|
||||||
m_address = address;
|
m_address = address;
|
||||||
m_size = size;
|
m_size = size;
|
||||||
m_heap = heap;
|
m_heap = heap;
|
||||||
|
m_attr = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr KPhysicalAddress GetAddress() const { return m_address; }
|
constexpr KPhysicalAddress GetAddress() const { return m_address; }
|
||||||
constexpr size_t GetSize() const { return m_size; }
|
constexpr size_t GetSize() const { return m_size; }
|
||||||
constexpr bool IsHeap() const { return m_heap; }
|
constexpr bool IsHeap() const { return m_heap; }
|
||||||
|
constexpr u8 GetAttribute() const { return m_attr; }
|
||||||
|
|
||||||
void Open();
|
void Open();
|
||||||
void Close();
|
void Close();
|
||||||
|
@ -86,6 +89,15 @@ namespace ams::kern {
|
||||||
MemoryFillValue_Heap = 'Z',
|
MemoryFillValue_Heap = 'Z',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RegionType {
|
||||||
|
RegionType_KernelMap = 0,
|
||||||
|
RegionType_Stack = 1,
|
||||||
|
RegionType_Alias = 2,
|
||||||
|
RegionType_Heap = 3,
|
||||||
|
|
||||||
|
RegionType_Count,
|
||||||
|
};
|
||||||
|
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
OperationType_Map = 0,
|
OperationType_Map = 0,
|
||||||
OperationType_MapGroup = 1,
|
OperationType_MapGroup = 1,
|
||||||
|
@ -165,15 +177,9 @@ namespace ams::kern {
|
||||||
private:
|
private:
|
||||||
KProcessAddress m_address_space_start;
|
KProcessAddress m_address_space_start;
|
||||||
KProcessAddress m_address_space_end;
|
KProcessAddress m_address_space_end;
|
||||||
KProcessAddress m_heap_region_start;
|
KProcessAddress m_region_starts[RegionType_Count];
|
||||||
KProcessAddress m_heap_region_end;
|
KProcessAddress m_region_ends[RegionType_Count];
|
||||||
KProcessAddress m_current_heap_end;
|
KProcessAddress m_current_heap_end;
|
||||||
KProcessAddress m_alias_region_start;
|
|
||||||
KProcessAddress m_alias_region_end;
|
|
||||||
KProcessAddress m_stack_region_start;
|
|
||||||
KProcessAddress m_stack_region_end;
|
|
||||||
KProcessAddress m_kernel_map_region_start;
|
|
||||||
KProcessAddress m_kernel_map_region_end;
|
|
||||||
KProcessAddress m_alias_code_region_start;
|
KProcessAddress m_alias_code_region_start;
|
||||||
KProcessAddress m_alias_code_region_end;
|
KProcessAddress m_alias_code_region_end;
|
||||||
KProcessAddress m_code_region_start;
|
KProcessAddress m_code_region_start;
|
||||||
|
@ -183,6 +189,7 @@ namespace ams::kern {
|
||||||
size_t m_mapped_unsafe_physical_memory;
|
size_t m_mapped_unsafe_physical_memory;
|
||||||
size_t m_mapped_insecure_memory;
|
size_t m_mapped_insecure_memory;
|
||||||
size_t m_mapped_ipc_server_memory;
|
size_t m_mapped_ipc_server_memory;
|
||||||
|
size_t m_alias_region_extra_size;
|
||||||
mutable KLightLock m_general_lock;
|
mutable KLightLock m_general_lock;
|
||||||
mutable KLightLock m_map_physical_memory_lock;
|
mutable KLightLock m_map_physical_memory_lock;
|
||||||
KLightLock m_device_map_lock;
|
KLightLock m_device_map_lock;
|
||||||
|
@ -203,12 +210,12 @@ namespace ams::kern {
|
||||||
MemoryFillValue m_stack_fill_value;
|
MemoryFillValue m_stack_fill_value;
|
||||||
public:
|
public:
|
||||||
constexpr explicit KPageTableBase(util::ConstantInitializeTag)
|
constexpr explicit KPageTableBase(util::ConstantInitializeTag)
|
||||||
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>), m_heap_region_start(Null<KProcessAddress>),
|
: m_address_space_start(Null<KProcessAddress>), m_address_space_end(Null<KProcessAddress>),
|
||||||
m_heap_region_end(Null<KProcessAddress>), m_current_heap_end(Null<KProcessAddress>), m_alias_region_start(Null<KProcessAddress>),
|
m_region_starts{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
|
||||||
m_alias_region_end(Null<KProcessAddress>), m_stack_region_start(Null<KProcessAddress>), m_stack_region_end(Null<KProcessAddress>),
|
m_region_ends{Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>, Null<KProcessAddress>},
|
||||||
m_kernel_map_region_start(Null<KProcessAddress>), m_kernel_map_region_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
|
m_current_heap_end(Null<KProcessAddress>), m_alias_code_region_start(Null<KProcessAddress>),
|
||||||
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
m_alias_code_region_end(Null<KProcessAddress>), m_code_region_start(Null<KProcessAddress>), m_code_region_end(Null<KProcessAddress>),
|
||||||
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(),
|
m_max_heap_size(), m_mapped_physical_memory_size(), m_mapped_unsafe_physical_memory(), m_mapped_insecure_memory(), m_mapped_ipc_server_memory(), m_alias_region_extra_size(),
|
||||||
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
m_general_lock(), m_map_physical_memory_lock(), m_device_map_lock(), m_impl(util::ConstantInitialize), m_memory_block_manager(util::ConstantInitialize),
|
||||||
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
m_allocate_option(), m_address_space_width(), m_is_kernel(), m_enable_aslr(), m_enable_device_address_space_merge(),
|
||||||
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
m_memory_block_slab_manager(), m_block_info_manager(), m_resource_limit(), m_cached_physical_linear_region(), m_cached_physical_heap_region(),
|
||||||
|
@ -220,7 +227,7 @@ namespace ams::kern {
|
||||||
explicit KPageTableBase() { /* ... */ }
|
explicit KPageTableBase() { /* ... */ }
|
||||||
|
|
||||||
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
NOINLINE Result InitializeForKernel(bool is_64_bit, void *table, KVirtualAddress start, KVirtualAddress end);
|
||||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_device_address_space_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||||
|
|
||||||
void Finalize();
|
void Finalize();
|
||||||
|
|
||||||
|
@ -236,7 +243,7 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
|
constexpr bool IsInAliasRegion(KProcessAddress addr, size_t size) const {
|
||||||
return this->Contains(addr, size) && m_alias_region_start <= addr && addr + size - 1 <= m_alias_region_end - 1;
|
return this->Contains(addr, size) && m_region_starts[RegionType_Alias] <= addr && addr + size - 1 <= m_region_ends[RegionType_Alias] - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
||||||
|
@ -328,7 +335,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const;
|
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const;
|
||||||
|
|
||||||
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, KMemoryPermission perm);
|
Result AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties &properties);
|
||||||
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
Result MapPageGroupImpl(PageLinkedList *page_list, KProcessAddress address, const KPageGroup &pg, const KPageProperties properties, bool reuse_ll);
|
||||||
|
|
||||||
void RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg);
|
void RemapPageGroup(PageLinkedList *page_list, KProcessAddress address, size_t size, const KPageGroup &pg);
|
||||||
|
@ -479,24 +486,30 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
|
KProcessAddress GetAddressSpaceStart() const { return m_address_space_start; }
|
||||||
KProcessAddress GetHeapRegionStart() const { return m_heap_region_start; }
|
|
||||||
KProcessAddress GetAliasRegionStart() const { return m_alias_region_start; }
|
KProcessAddress GetHeapRegionStart() const { return m_region_starts[RegionType_Heap]; }
|
||||||
KProcessAddress GetStackRegionStart() const { return m_stack_region_start; }
|
KProcessAddress GetAliasRegionStart() const { return m_region_starts[RegionType_Alias]; }
|
||||||
KProcessAddress GetKernelMapRegionStart() const { return m_kernel_map_region_start; }
|
KProcessAddress GetStackRegionStart() const { return m_region_starts[RegionType_Stack]; }
|
||||||
|
KProcessAddress GetKernelMapRegionStart() const { return m_region_starts[RegionType_KernelMap]; }
|
||||||
|
|
||||||
KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; }
|
KProcessAddress GetAliasCodeRegionStart() const { return m_alias_code_region_start; }
|
||||||
|
|
||||||
size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; }
|
size_t GetAddressSpaceSize() const { return m_address_space_end - m_address_space_start; }
|
||||||
size_t GetHeapRegionSize() const { return m_heap_region_end - m_heap_region_start; }
|
|
||||||
size_t GetAliasRegionSize() const { return m_alias_region_end - m_alias_region_start; }
|
size_t GetHeapRegionSize() const { return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]; }
|
||||||
size_t GetStackRegionSize() const { return m_stack_region_end - m_stack_region_start; }
|
size_t GetAliasRegionSize() const { return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias]; }
|
||||||
size_t GetKernelMapRegionSize() const { return m_kernel_map_region_end - m_kernel_map_region_start; }
|
size_t GetStackRegionSize() const { return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack]; }
|
||||||
|
size_t GetKernelMapRegionSize() const { return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap]; }
|
||||||
|
|
||||||
size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; }
|
size_t GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; }
|
||||||
|
|
||||||
|
size_t GetAliasRegionExtraSize() const { return m_alias_region_extra_size; }
|
||||||
|
|
||||||
size_t GetNormalMemorySize() const {
|
size_t GetNormalMemorySize() const {
|
||||||
/* Lock the table. */
|
/* Lock the table. */
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
return (m_current_heap_end - m_heap_region_start) + m_mapped_physical_memory_size;
|
return (m_current_heap_end - m_region_starts[RegionType_Heap]) + m_mapped_physical_memory_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetCodeSize() const;
|
size_t GetCodeSize() const;
|
||||||
|
|
|
@ -223,6 +223,13 @@ namespace ams::kern::arch::arm64 {
|
||||||
type = ams::svc::ExceptionType_InstructionAbort;
|
type = ams::svc::ExceptionType_InstructionAbort;
|
||||||
break;
|
break;
|
||||||
case EsrEc_DataAbortEl0:
|
case EsrEc_DataAbortEl0:
|
||||||
|
/* If esr.IFSC is "Alignment Fault", return UnalignedData instead of DataAbort. */
|
||||||
|
if ((esr & 0x3F) == 0b100001) {
|
||||||
|
type = ams::svc::ExceptionType_UnalignedData;
|
||||||
|
} else {
|
||||||
|
type = ams::svc::ExceptionType_DataAbort;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
type = ams::svc::ExceptionType_DataAbort;
|
type = ams::svc::ExceptionType_DataAbort;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -207,7 +207,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||||
/* Get an ASID */
|
/* Get an ASID */
|
||||||
m_asid = g_asid_manager.Reserve();
|
m_asid = g_asid_manager.Reserve();
|
||||||
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
||||||
|
@ -222,10 +222,10 @@ namespace ams::kern::arch::arm64 {
|
||||||
ON_RESULT_FAILURE_2 { m_manager->Free(new_table); };
|
ON_RESULT_FAILURE_2 { m_manager->Free(new_table); };
|
||||||
|
|
||||||
/* Initialize our base table. */
|
/* Initialize our base table. */
|
||||||
const size_t as_width = GetAddressSpaceWidth(as_type);
|
const size_t as_width = GetAddressSpaceWidth(flags);
|
||||||
const KProcessAddress as_start = 0;
|
const KProcessAddress as_start = 0;
|
||||||
const KProcessAddress as_end = (1ul << as_width);
|
const KProcessAddress as_end = (1ul << as_width);
|
||||||
R_TRY(KPageTableBase::InitializeForProcess(as_type, enable_aslr, enable_das_merge, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
||||||
|
|
||||||
/* Note that we've updated the table (since we created it). */
|
/* Note that we've updated the table (since we created it). */
|
||||||
this->NoteUpdated();
|
this->NoteUpdated();
|
||||||
|
@ -258,7 +258,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
|
|
||||||
/* Begin the traversal. */
|
/* Begin the traversal. */
|
||||||
TraversalContext context;
|
TraversalContext context;
|
||||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 };
|
||||||
bool cur_valid = false;
|
bool cur_valid = false;
|
||||||
TraversalEntry next_entry;
|
TraversalEntry next_entry;
|
||||||
bool next_valid;
|
bool next_valid;
|
||||||
|
@ -268,7 +268,9 @@ namespace ams::kern::arch::arm64 {
|
||||||
|
|
||||||
/* Iterate over entries. */
|
/* Iterate over entries. */
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) {
|
/* NOTE: Nintendo really does check next_entry.attr == (cur_entry.attr != 0)...but attr is always zero as of 18.0.0, and this is "probably" for the new console or debug-only anyway, */
|
||||||
|
/* so we'll implement the weird logic verbatim even though it doesn't match the GetContiguousRange logic. */
|
||||||
|
if ((!next_valid && !cur_valid) || (next_valid && cur_valid && next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size && next_entry.attr == (cur_entry.attr ? 1 : 0))) {
|
||||||
cur_entry.block_size += next_entry.block_size;
|
cur_entry.block_size += next_entry.block_size;
|
||||||
} else {
|
} else {
|
||||||
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
|
if (cur_valid && IsHeapPhysicalAddressForFinalize(cur_entry.phys_addr)) {
|
||||||
|
|
|
@ -46,12 +46,14 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->block_size = L3BlockSize;
|
out_entry->block_size = L3BlockSize;
|
||||||
}
|
}
|
||||||
out_entry->sw_reserved_bits = l3_entry->GetSoftwareReservedBits();
|
out_entry->sw_reserved_bits = l3_entry->GetSoftwareReservedBits();
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L3BlockSize;
|
out_entry->block_size = L3BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->block_size = L2BlockSize;
|
out_entry->block_size = L2BlockSize;
|
||||||
}
|
}
|
||||||
out_entry->sw_reserved_bits = l2_entry->GetSoftwareReservedBits();
|
out_entry->sw_reserved_bits = l2_entry->GetSoftwareReservedBits();
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
/* Set the output context. */
|
/* Set the output context. */
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
|
@ -79,6 +82,8 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L2BlockSize;
|
out_entry->block_size = L2BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +113,8 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
|
|
||||||
out_context->l2_entry = nullptr;
|
out_context->l2_entry = nullptr;
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
return false;
|
return false;
|
||||||
|
@ -119,6 +126,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
out_context->l1_entry = m_table + m_num_entries;
|
out_context->l1_entry = m_table + m_num_entries;
|
||||||
out_context->l2_entry = nullptr;
|
out_context->l2_entry = nullptr;
|
||||||
out_context->l3_entry = nullptr;
|
out_context->l3_entry = nullptr;
|
||||||
|
@ -220,6 +228,7 @@ namespace ams::kern::arch::arm64 {
|
||||||
out_entry->phys_addr = Null<KPhysicalAddress>;
|
out_entry->phys_addr = Null<KPhysicalAddress>;
|
||||||
out_entry->block_size = L1BlockSize;
|
out_entry->block_size = L1BlockSize;
|
||||||
out_entry->sw_reserved_bits = 0;
|
out_entry->sw_reserved_bits = 0;
|
||||||
|
out_entry->attr = 0;
|
||||||
context->l1_entry = m_table + m_num_entries;
|
context->l1_entry = m_table + m_num_entries;
|
||||||
context->l2_entry = nullptr;
|
context->l2_entry = nullptr;
|
||||||
context->l3_entry = nullptr;
|
context->l3_entry = nullptr;
|
||||||
|
|
|
@ -296,7 +296,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||||
/* TODO: Move this into a header for the MC in general. */
|
/* TODO: Move this into a header for the MC in general. */
|
||||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||||
u32 config_value;
|
u32 config_value;
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(smc::init::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
smc::init::ReadWriteRegister(std::addressof(config_value), MemoryControllerConfigurationRegister, 0, 0);
|
||||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +387,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||||
}
|
}
|
||||||
|
|
||||||
void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
void KSystemControl::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor, false>(core_id, entrypoint, arg)) == 0);
|
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<smc::SmcId_Supervisor>(core_id, entrypoint, arg)) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Randomness for Initialization. */
|
/* Randomness for Initialization. */
|
||||||
|
@ -601,8 +601,9 @@ namespace ams::kern::board::nintendo::nx {
|
||||||
|
|
||||||
if (g_call_smc_on_panic) {
|
if (g_call_smc_on_panic) {
|
||||||
/* If we should, instruct the secure monitor to display a panic screen. */
|
/* If we should, instruct the secure monitor to display a panic screen. */
|
||||||
smc::Panic(0xF00);
|
smc::ShowError(0xF00);
|
||||||
}
|
}
|
||||||
|
|
||||||
AMS_INFINITE_LOOP();
|
AMS_INFINITE_LOOP();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||||
enum FunctionId : u32 {
|
enum FunctionId : u32 {
|
||||||
FunctionId_GetConfig = 0xC3000004,
|
FunctionId_GetConfig = 0xC3000004,
|
||||||
FunctionId_GenerateRandomBytes = 0xC3000005,
|
FunctionId_GenerateRandomBytes = 0xC3000005,
|
||||||
FunctionId_Panic = 0xC3000006,
|
FunctionId_ShowError = 0xC3000006,
|
||||||
FunctionId_ConfigureCarveout = 0xC3000007,
|
FunctionId_ConfigureCarveout = 0xC3000007,
|
||||||
FunctionId_ReadWriteRegister = 0xC3000008,
|
FunctionId_ReadWriteRegister = 0xC3000008,
|
||||||
|
|
||||||
|
@ -51,122 +51,187 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||||
FunctionId_SetConfig = 0xC3000409,
|
FunctionId_SetConfig = 0xC3000409,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr size_t GenerateRandomBytesSizeMax = sizeof(::ams::svc::lp64::SecureMonitorArguments) - sizeof(::ams::svc::lp64::SecureMonitorArguments{}.r[0]);
|
||||||
|
|
||||||
/* Global lock for generate random bytes. */
|
/* Global lock for generate random bytes. */
|
||||||
constinit KSpinLock g_generate_random_lock;
|
constinit KSpinLock g_generate_random_lock;
|
||||||
|
|
||||||
|
bool TryGetConfigImpl(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||||
|
/* Create the arguments .*/
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* If successful, copy the output. */
|
||||||
|
const bool success = static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
if (AMS_LIKELY(success)) {
|
||||||
|
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
||||||
|
out[i] = args.r[1 + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetConfigImpl(ConfigItem config_item, u64 value) {
|
||||||
|
/* Create the arguments .*/
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* Return whether the call was successful. */
|
||||||
|
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ReadWriteRegisterImpl(u32 *out, u64 address, u32 mask, u32 value) {
|
||||||
|
/* Create the arguments .*/
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* Unconditionally write the output. */
|
||||||
|
*out = static_cast<u32>(args.r[1]);
|
||||||
|
|
||||||
|
/* Return whether the call was successful. */
|
||||||
|
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GenerateRandomBytesImpl(void *dst, size_t size) {
|
||||||
|
/* Create the arguments. */
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* If successful, copy the output. */
|
||||||
|
const bool success = static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
if (AMS_LIKELY(success)) {
|
||||||
|
std::memcpy(dst, std::addressof(args.r[1]), size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigureCarveoutImpl(size_t which, uintptr_t address, size_t size) {
|
||||||
|
/* Create the arguments .*/
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast<u64>(which), static_cast<u64>(address), static_cast<u64>(size) } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* Return whether the call was successful. */
|
||||||
|
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShowErrorImpl(u32 color) {
|
||||||
|
/* Create the arguments .*/
|
||||||
|
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ShowError, color } };
|
||||||
|
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor>(args.r);
|
||||||
|
|
||||||
|
/* Return whether the call was successful. */
|
||||||
|
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CallSecureMonitorFromUserImpl(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||||
|
/* Call into the secure monitor. */
|
||||||
|
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_User>(args->r);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SMC functionality needed for init. */
|
/* SMC functionality needed for init. */
|
||||||
namespace init {
|
namespace init {
|
||||||
|
|
||||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } };
|
/* Ensure we successfully get the config. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(TryGetConfigImpl(out, num_qwords, config_item));
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
|
||||||
out[i] = args.r[1 + i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateRandomBytes(void *dst, size_t size) {
|
void GenerateRandomBytes(void *dst, size_t size) {
|
||||||
/* Call SmcGenerateRandomBytes() */
|
/* Check that the size is valid. */
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } };
|
MESOSPHERE_INIT_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax);
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0]));
|
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
/* Ensure we successfully generate the random bytes. */
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
MESOSPHERE_INIT_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size));
|
||||||
|
|
||||||
/* Copy output. */
|
|
||||||
std::memcpy(dst, std::addressof(args.r[1]), size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } };
|
/* Ensure we successfully access the register. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(ReadWriteRegisterImpl(out, address, mask, value));
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, false>(args.r);
|
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
|
||||||
|
|
||||||
*out = args.r[1];
|
|
||||||
|
|
||||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GetConfig, static_cast<u32>(config_item) } };
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Get the config. */
|
||||||
if (AMS_UNLIKELY(static_cast<SmcResult>(args.r[0]) != SmcResult::Success)) {
|
return TryGetConfigImpl(out, num_qwords, config_item);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
|
||||||
out[i] = args.r[1 + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||||
|
/* Ensure we successfully get the config. */
|
||||||
MESOSPHERE_ABORT_UNLESS(TryGetConfig(out, num_qwords, config_item));
|
MESOSPHERE_ABORT_UNLESS(TryGetConfig(out, num_qwords, config_item));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SetConfig(ConfigItem config_item, u64 value) {
|
bool SetConfig(ConfigItem config_item, u64 value) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value } };
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Set the config. */
|
||||||
|
return SetConfigImpl(config_item, value);
|
||||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) {
|
bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ReadWriteRegister, address, mask, value } };
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Access the register. */
|
||||||
|
return ReadWriteRegisterImpl(out, address, mask, value);
|
||||||
*out = static_cast<u32>(args.r[1]);
|
|
||||||
return static_cast<SmcResult>(args.r[0]) == SmcResult::Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureCarveout(size_t which, uintptr_t address, size_t size) {
|
void ConfigureCarveout(size_t which, uintptr_t address, size_t size) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_ConfigureCarveout, static_cast<u64>(which), static_cast<u64>(address), static_cast<u64>(size) } };
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Ensure that we successfully configure the carveout. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(ConfigureCarveoutImpl(which, address, size));
|
||||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateRandomBytes(void *dst, size_t size) {
|
void GenerateRandomBytes(void *dst, size_t size) {
|
||||||
/* Setup for call. */
|
/* Check that the size is valid. */
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_GenerateRandomBytes, size } };
|
MESOSPHERE_ABORT_UNLESS(0 < size && size <= GenerateRandomBytesSizeMax);
|
||||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.r[0]));
|
|
||||||
|
|
||||||
/* Make call. */
|
/* Disable interrupts. */
|
||||||
{
|
KScopedInterruptDisable di;
|
||||||
KScopedInterruptDisable intr_disable;
|
|
||||||
|
/* Acquire the exclusive right to generate random bytes. */
|
||||||
KScopedSpinLock lk(g_generate_random_lock);
|
KScopedSpinLock lk(g_generate_random_lock);
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Ensure we successfully generate the random bytes. */
|
||||||
}
|
MESOSPHERE_ABORT_UNLESS(GenerateRandomBytesImpl(dst, size));
|
||||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.r[0]) == SmcResult::Success));
|
|
||||||
|
|
||||||
/* Copy output. */
|
|
||||||
std::memcpy(dst, std::addressof(args.r[1]), size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NORETURN Panic(u32 color) {
|
void ShowError(u32 color) {
|
||||||
ams::svc::lp64::SecureMonitorArguments args = { { FunctionId_Panic, color } };
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_Supervisor, true>(args.r);
|
/* Ensure we successfully show the error. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(ShowErrorImpl(color));
|
||||||
AMS_INFINITE_LOOP();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args) {
|
||||||
::ams::kern::arch::arm64::smc::SecureMonitorCall<SmcId_User, true>(args->r);
|
/* Disable interrupts. */
|
||||||
|
KScopedInterruptDisable di;
|
||||||
|
|
||||||
|
/* Perform the call. */
|
||||||
|
CallSecureMonitorFromUserImpl(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -111,7 +111,7 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||||
|
|
||||||
bool SetConfig(ConfigItem config_item, u64 value);
|
bool SetConfig(ConfigItem config_item, u64 value);
|
||||||
|
|
||||||
void NORETURN Panic(u32 color);
|
void ShowError(u32 color);
|
||||||
|
|
||||||
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||||
|
|
||||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||||
void GenerateRandomBytes(void *dst, size_t size);
|
void GenerateRandomBytes(void *dst, size_t size);
|
||||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
void ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,7 +136,7 @@ namespace ams::kern {
|
||||||
{
|
{
|
||||||
/* Allocate the previously unreserved pages. */
|
/* Allocate the previously unreserved pages. */
|
||||||
KPageGroup unreserve_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
KPageGroup unreserve_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(unreserve_pg), unreserved_size / PageSize, 1, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
/* Add the previously reserved pages. */
|
/* Add the previously reserved pages. */
|
||||||
if (src_pool == dst_pool && binary_pages != 0) {
|
if (src_pool == dst_pool && binary_pages != 0) {
|
||||||
|
@ -173,7 +173,7 @@ namespace ams::kern {
|
||||||
/* If the pool is the same, we need to use the workaround page group. */
|
/* If the pool is the same, we need to use the workaround page group. */
|
||||||
if (src_pool == dst_pool) {
|
if (src_pool == dst_pool) {
|
||||||
/* Allocate a new, usable group for the process. */
|
/* Allocate a new, usable group for the process. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(workaround_pg), static_cast<size_t>(params.code_num_pages), KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(workaround_pg), static_cast<size_t>(params.code_num_pages), 1, KMemoryManager::EncodeOption(dst_pool, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
/* Copy data from the working page group to the usable one. */
|
/* Copy data from the working page group to the usable one. */
|
||||||
auto work_it = pg.begin();
|
auto work_it = pg.begin();
|
||||||
|
|
|
@ -79,29 +79,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Create a page group representing the segment. */
|
/* Create a page group representing the segment. */
|
||||||
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||||
if (size_t remaining_size = util::AlignUp(seg_size, PageSize); remaining_size != 0) {
|
MESOSPHERE_R_ABORT_UNLESS(pg.CopyRangeTo(segment_pg, seg_offset, util::AlignUp(seg_size, PageSize)));
|
||||||
/* Find the pages whose data corresponds to the segment. */
|
|
||||||
size_t cur_offset = 0;
|
|
||||||
for (auto it = pg.begin(); it != pg.end() && remaining_size > 0; ++it) {
|
|
||||||
/* Get the current size. */
|
|
||||||
const size_t cur_size = it->GetSize();
|
|
||||||
|
|
||||||
/* Determine if the offset is in range. */
|
|
||||||
const size_t rel_diff = seg_offset - cur_offset;
|
|
||||||
const bool is_before = cur_offset <= seg_offset;
|
|
||||||
cur_offset += cur_size;
|
|
||||||
if (is_before && seg_offset < cur_offset) {
|
|
||||||
/* It is, so add the block. */
|
|
||||||
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(segment_pg.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize));
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
cur_offset = seg_offset + block_size;
|
|
||||||
remaining_size -= block_size;
|
|
||||||
seg_offset += block_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup the new page group's memory so that we can load the segment. */
|
/* Setup the new page group's memory so that we can load the segment. */
|
||||||
{
|
{
|
||||||
|
@ -226,6 +204,9 @@ namespace ams::kern {
|
||||||
const uintptr_t map_end = map_start + map_size;
|
const uintptr_t map_end = map_start + map_size;
|
||||||
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
||||||
|
|
||||||
|
/* Default fields in parameter to zero. */
|
||||||
|
*out = {};
|
||||||
|
|
||||||
/* Set fields in parameter. */
|
/* Set fields in parameter. */
|
||||||
out->code_address = map_start + start_address;
|
out->code_address = map_start + start_address;
|
||||||
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
||||||
|
|
|
@ -225,7 +225,7 @@ namespace ams::kern {
|
||||||
return allocated_block;
|
return allocated_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random) {
|
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup *out, size_t num_pages, Pool pool, Direction dir, bool unoptimized, bool random, s32 min_heap_index) {
|
||||||
/* Choose a heap based on our page size request. */
|
/* Choose a heap based on our page size request. */
|
||||||
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
|
||||||
R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory());
|
R_UNLESS(0 <= heap_index, svc::ResultOutOfMemory());
|
||||||
|
@ -241,7 +241,7 @@ namespace ams::kern {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Keep allocating until we've allocated all our pages. */
|
/* Keep allocating until we've allocated all our pages. */
|
||||||
for (s32 index = heap_index; index >= 0 && num_pages > 0; index--) {
|
for (s32 index = heap_index; index >= min_heap_index && num_pages > 0; index--) {
|
||||||
const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index);
|
const size_t pages_per_alloc = KPageHeap::GetBlockNumPages(index);
|
||||||
for (Impl *cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; cur_manager = this->GetNextManager(cur_manager, dir)) {
|
for (Impl *cur_manager = this->GetFirstManager(pool, dir); cur_manager != nullptr; cur_manager = this->GetNextManager(cur_manager, dir)) {
|
||||||
while (num_pages >= pages_per_alloc) {
|
while (num_pages >= pages_per_alloc) {
|
||||||
|
@ -274,7 +274,7 @@ namespace ams::kern {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KMemoryManager::AllocateAndOpen(KPageGroup *out, size_t num_pages, u32 option) {
|
Result KMemoryManager::AllocateAndOpen(KPageGroup *out, size_t num_pages, size_t align_pages, u32 option) {
|
||||||
MESOSPHERE_ASSERT(out != nullptr);
|
MESOSPHERE_ASSERT(out != nullptr);
|
||||||
MESOSPHERE_ASSERT(out->GetNumPages() == 0);
|
MESOSPHERE_ASSERT(out->GetNumPages() == 0);
|
||||||
|
|
||||||
|
@ -285,8 +285,11 @@ namespace ams::kern {
|
||||||
const auto [pool, dir] = DecodeOption(option);
|
const auto [pool, dir] = DecodeOption(option);
|
||||||
KScopedLightLock lk(m_pool_locks[pool]);
|
KScopedLightLock lk(m_pool_locks[pool]);
|
||||||
|
|
||||||
|
/* Choose a heap based on our alignment size request. */
|
||||||
|
const s32 heap_index = KPageHeap::GetAlignedBlockIndex(align_pages, align_pages);
|
||||||
|
|
||||||
/* Allocate the page group. */
|
/* Allocate the page group. */
|
||||||
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, m_has_optimized_process[pool], true));
|
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, m_has_optimized_process[pool], true, heap_index));
|
||||||
|
|
||||||
/* Open the first reference to the pages. */
|
/* Open the first reference to the pages. */
|
||||||
for (const auto &block : *out) {
|
for (const auto &block : *out) {
|
||||||
|
@ -326,8 +329,11 @@ namespace ams::kern {
|
||||||
const bool has_optimized = m_has_optimized_process[pool];
|
const bool has_optimized = m_has_optimized_process[pool];
|
||||||
const bool is_optimized = m_optimized_process_ids[pool] == process_id;
|
const bool is_optimized = m_optimized_process_ids[pool] == process_id;
|
||||||
|
|
||||||
|
/* Always use the minimum alignment size. */
|
||||||
|
const s32 heap_index = 0;
|
||||||
|
|
||||||
/* Allocate the page group. */
|
/* Allocate the page group. */
|
||||||
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, has_optimized && !is_optimized, false));
|
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, has_optimized && !is_optimized, false, heap_index));
|
||||||
|
|
||||||
/* Set whether we should optimize. */
|
/* Set whether we should optimize. */
|
||||||
optimized = has_optimized && is_optimized;
|
optimized = has_optimized && is_optimized;
|
||||||
|
|
|
@ -84,6 +84,58 @@ namespace ams::kern {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KPageGroup::CopyRangeTo(KPageGroup &out, size_t range_offset, size_t range_size) const {
|
||||||
|
/* Get the previous last block for the group. */
|
||||||
|
KBlockInfo * const out_last = out.m_last_block;
|
||||||
|
const auto out_last_addr = out_last != nullptr ? out_last->GetAddress() : Null<KPhysicalAddress>;
|
||||||
|
const auto out_last_np = out_last != nullptr ? out_last->GetNumPages() : 0;
|
||||||
|
|
||||||
|
/* Ensure we cleanup the group on failure. */
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
KBlockInfo *cur = out_last != nullptr ? out_last->GetNext() : out.m_first_block;
|
||||||
|
while (cur != nullptr) {
|
||||||
|
KBlockInfo *next = cur->GetNext();
|
||||||
|
out.m_manager->Free(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_last != nullptr) {
|
||||||
|
out_last->Initialize(out_last_addr, out_last_np);
|
||||||
|
out_last->SetNext(nullptr);
|
||||||
|
} else {
|
||||||
|
out.m_first_block = nullptr;
|
||||||
|
}
|
||||||
|
out.m_last_block = out_last;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Find the pages within the requested range. */
|
||||||
|
size_t cur_offset = 0, remaining_size = range_size;
|
||||||
|
for (auto it = this->begin(); it != this->end() && remaining_size > 0; ++it) {
|
||||||
|
/* Get the current size. */
|
||||||
|
const size_t cur_size = it->GetSize();
|
||||||
|
|
||||||
|
/* Determine if the offset is in range. */
|
||||||
|
const size_t rel_diff = range_offset - cur_offset;
|
||||||
|
const bool is_before = cur_offset <= range_offset;
|
||||||
|
cur_offset += cur_size;
|
||||||
|
if (is_before && range_offset < cur_offset) {
|
||||||
|
/* It is, so add the block. */
|
||||||
|
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||||
|
R_TRY(out.AddBlock(it->GetAddress() + rel_diff, block_size / PageSize));
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_offset = range_offset + block_size;
|
||||||
|
remaining_size -= block_size;
|
||||||
|
range_offset += block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that we successfully copied the range. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(remaining_size == 0);
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
void KPageGroup::Open() const {
|
void KPageGroup::Open() const {
|
||||||
auto &mm = Kernel::GetMemoryManager();
|
auto &mm = Kernel::GetMemoryManager();
|
||||||
|
|
||||||
|
|
|
@ -97,15 +97,12 @@ namespace ams::kern {
|
||||||
m_enable_aslr = true;
|
m_enable_aslr = true;
|
||||||
m_enable_device_address_space_merge = false;
|
m_enable_device_address_space_merge = false;
|
||||||
|
|
||||||
m_heap_region_start = 0;
|
for (auto i = 0; i < RegionType_Count; ++i) {
|
||||||
m_heap_region_end = 0;
|
m_region_starts[i] = 0;
|
||||||
|
m_region_ends[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
m_current_heap_end = 0;
|
m_current_heap_end = 0;
|
||||||
m_alias_region_start = 0;
|
|
||||||
m_alias_region_end = 0;
|
|
||||||
m_stack_region_start = 0;
|
|
||||||
m_stack_region_end = 0;
|
|
||||||
m_kernel_map_region_start = 0;
|
|
||||||
m_kernel_map_region_end = 0;
|
|
||||||
m_alias_code_region_start = 0;
|
m_alias_code_region_start = 0;
|
||||||
m_alias_code_region_end = 0;
|
m_alias_code_region_end = 0;
|
||||||
m_code_region_start = 0;
|
m_code_region_start = 0;
|
||||||
|
@ -115,6 +112,7 @@ namespace ams::kern {
|
||||||
m_mapped_unsafe_physical_memory = 0;
|
m_mapped_unsafe_physical_memory = 0;
|
||||||
m_mapped_insecure_memory = 0;
|
m_mapped_insecure_memory = 0;
|
||||||
m_mapped_ipc_server_memory = 0;
|
m_mapped_ipc_server_memory = 0;
|
||||||
|
m_alias_region_extra_size = 0;
|
||||||
|
|
||||||
m_memory_block_slab_manager = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManagerPointer();
|
m_memory_block_slab_manager = Kernel::GetSystemSystemResource().GetMemoryBlockSlabManagerPointer();
|
||||||
m_block_info_manager = Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer();
|
m_block_info_manager = Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer();
|
||||||
|
@ -135,7 +133,7 @@ namespace ams::kern {
|
||||||
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
|
R_RETURN(m_memory_block_manager.Initialize(m_address_space_start, m_address_space_end, m_memory_block_slab_manager));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool enable_das_merge, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
Result KPageTableBase::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, void *table, KProcessAddress start, KProcessAddress end, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||||
/* Validate the region. */
|
/* Validate the region. */
|
||||||
MESOSPHERE_ABORT_UNLESS(start <= code_address);
|
MESOSPHERE_ABORT_UNLESS(start <= code_address);
|
||||||
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
|
MESOSPHERE_ABORT_UNLESS(code_address < code_address + code_size);
|
||||||
|
@ -149,13 +147,16 @@ namespace ams::kern {
|
||||||
return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type);
|
return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Default to zero alias region extra size. */
|
||||||
|
m_alias_region_extra_size = 0;
|
||||||
|
|
||||||
/* Set our width and heap/alias sizes. */
|
/* Set our width and heap/alias sizes. */
|
||||||
m_address_space_width = GetAddressSpaceWidth(as_type);
|
m_address_space_width = GetAddressSpaceWidth(flags);
|
||||||
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
|
size_t alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
|
||||||
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
|
size_t heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
|
||||||
|
|
||||||
/* Adjust heap/alias size if we don't have an alias region. */
|
/* Adjust heap/alias size if we don't have an alias region. */
|
||||||
if ((as_type & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) {
|
if ((flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) {
|
||||||
heap_region_size += alias_region_size;
|
heap_region_size += alias_region_size;
|
||||||
alias_region_size = 0;
|
alias_region_size = 0;
|
||||||
}
|
}
|
||||||
|
@ -165,35 +166,57 @@ namespace ams::kern {
|
||||||
KProcessAddress process_code_end;
|
KProcessAddress process_code_end;
|
||||||
size_t stack_region_size;
|
size_t stack_region_size;
|
||||||
size_t kernel_map_region_size;
|
size_t kernel_map_region_size;
|
||||||
|
KProcessAddress before_process_code_start, after_process_code_start;
|
||||||
|
size_t before_process_code_size, after_process_code_size;
|
||||||
if (m_address_space_width == 39) {
|
if (m_address_space_width == 39) {
|
||||||
alias_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Alias);
|
|
||||||
heap_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Heap);
|
|
||||||
stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack);
|
stack_region_size = GetSpaceSize(KAddressSpaceInfo::Type_Stack);
|
||||||
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
|
kernel_map_region_size = GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
|
||||||
|
|
||||||
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit);
|
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_Map39Bit);
|
||||||
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit);
|
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_Map39Bit);
|
||||||
m_alias_code_region_start = m_code_region_start;
|
m_alias_code_region_start = m_code_region_start;
|
||||||
m_alias_code_region_end = m_code_region_end;
|
m_alias_code_region_end = m_code_region_end;
|
||||||
|
|
||||||
process_code_start = util::AlignDown(GetInteger(code_address), RegionAlignment);
|
process_code_start = util::AlignDown(GetInteger(code_address), RegionAlignment);
|
||||||
process_code_end = util::AlignUp(GetInteger(code_address) + code_size, RegionAlignment);
|
process_code_end = util::AlignUp(GetInteger(code_address) + code_size, RegionAlignment);
|
||||||
|
|
||||||
|
before_process_code_start = m_code_region_start;
|
||||||
|
before_process_code_size = process_code_start - before_process_code_start;
|
||||||
|
after_process_code_start = process_code_end;
|
||||||
|
after_process_code_size = m_code_region_end - process_code_end;
|
||||||
|
|
||||||
|
/* If we have a 39-bit address space and should, enable extra size to the alias region. */
|
||||||
|
if (flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) {
|
||||||
|
/* Extra size is 1/8th of the address space. */
|
||||||
|
m_alias_region_extra_size = (static_cast<size_t>(1) << m_address_space_width) / 8;
|
||||||
|
|
||||||
|
alias_region_size += m_alias_region_extra_size;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
stack_region_size = 0;
|
stack_region_size = 0;
|
||||||
kernel_map_region_size = 0;
|
kernel_map_region_size = 0;
|
||||||
|
|
||||||
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapSmall);
|
m_code_region_start = GetSpaceStart(KAddressSpaceInfo::Type_MapSmall);
|
||||||
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
|
m_code_region_end = m_code_region_start + GetSpaceSize(KAddressSpaceInfo::Type_MapSmall);
|
||||||
m_stack_region_start = m_code_region_start;
|
|
||||||
m_alias_code_region_start = m_code_region_start;
|
m_alias_code_region_start = m_code_region_start;
|
||||||
m_alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge) + GetSpaceSize(KAddressSpaceInfo::Type_MapLarge);
|
m_alias_code_region_end = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge) + GetSpaceSize(KAddressSpaceInfo::Type_MapLarge);
|
||||||
m_stack_region_end = m_code_region_end;
|
m_region_starts[RegionType_Stack] = m_code_region_start;
|
||||||
m_kernel_map_region_start = m_code_region_start;
|
m_region_ends[RegionType_Stack] = m_code_region_end;
|
||||||
m_kernel_map_region_end = m_code_region_end;
|
m_region_starts[RegionType_KernelMap] = m_code_region_start;
|
||||||
|
m_region_ends[RegionType_KernelMap] = m_code_region_end;
|
||||||
|
|
||||||
process_code_start = m_code_region_start;
|
process_code_start = m_code_region_start;
|
||||||
process_code_end = m_code_region_end;
|
process_code_end = m_code_region_end;
|
||||||
|
|
||||||
|
before_process_code_start = m_code_region_start;
|
||||||
|
before_process_code_size = 0;
|
||||||
|
after_process_code_start = GetSpaceStart(KAddressSpaceInfo::Type_MapLarge);
|
||||||
|
after_process_code_size = GetSpaceSize(KAddressSpaceInfo::Type_MapLarge);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set other basic fields. */
|
/* Set other basic fields. */
|
||||||
m_enable_aslr = enable_aslr;
|
m_enable_aslr = (flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||||
m_enable_device_address_space_merge = enable_das_merge;
|
m_enable_device_address_space_merge = (flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||||
m_address_space_start = start;
|
m_address_space_start = start;
|
||||||
m_address_space_end = end;
|
m_address_space_end = end;
|
||||||
m_is_kernel = false;
|
m_is_kernel = false;
|
||||||
|
@ -201,100 +224,285 @@ namespace ams::kern {
|
||||||
m_block_info_manager = system_resource->GetBlockInfoManagerPointer();
|
m_block_info_manager = system_resource->GetBlockInfoManagerPointer();
|
||||||
m_resource_limit = resource_limit;
|
m_resource_limit = resource_limit;
|
||||||
|
|
||||||
/* Determine the region we can place our undetermineds in. */
|
/* Set up our undetermined regions. */
|
||||||
KProcessAddress alloc_start;
|
{
|
||||||
size_t alloc_size;
|
/* Declare helper structure for layout process. */
|
||||||
if ((GetInteger(process_code_start) - GetInteger(m_code_region_start)) >= (GetInteger(end) - GetInteger(process_code_end))) {
|
struct RegionLayoutInfo {
|
||||||
alloc_start = m_code_region_start;
|
size_t size;
|
||||||
alloc_size = GetInteger(process_code_start) - GetInteger(m_code_region_start);
|
RegionType type;
|
||||||
|
s32 alloc_index; /* 0 for before process code, 1 for after process code */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create region layout info array, and add regions to it. */
|
||||||
|
RegionLayoutInfo region_layouts[RegionType_Count] = {};
|
||||||
|
size_t num_regions = 0;
|
||||||
|
|
||||||
|
if (kernel_map_region_size > 0) { region_layouts[num_regions++] = { .size = kernel_map_region_size, .type = RegionType_KernelMap, .alloc_index = 0, }; }
|
||||||
|
if (stack_region_size > 0) { region_layouts[num_regions++] = { .size = stack_region_size, .type = RegionType_Stack, .alloc_index = 0, }; }
|
||||||
|
|
||||||
|
region_layouts[num_regions++] = { .size = alias_region_size, .type = RegionType_Alias, .alloc_index = 0, };
|
||||||
|
region_layouts[num_regions++] = { .size = heap_region_size, .type = RegionType_Heap, .alloc_index = 0, };
|
||||||
|
|
||||||
|
/* Selection-sort the regions by size largest-to-smallest. */
|
||||||
|
for (size_t i = 0; i < num_regions - 1; ++i) {
|
||||||
|
for (size_t j = i + 1; j < num_regions; ++j) {
|
||||||
|
if (region_layouts[i].size < region_layouts[j].size) {
|
||||||
|
std::swap(region_layouts[i], region_layouts[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout the regions. */
|
||||||
|
constexpr auto AllocIndexCount = 2;
|
||||||
|
KProcessAddress alloc_starts[AllocIndexCount] = { before_process_code_start, after_process_code_start };
|
||||||
|
size_t alloc_sizes[AllocIndexCount] = { before_process_code_size, after_process_code_size };
|
||||||
|
size_t alloc_counts[AllocIndexCount] = {};
|
||||||
|
for (size_t i = 0; i < num_regions; ++i) {
|
||||||
|
/* Get reference to the current region. */
|
||||||
|
auto &cur_region = region_layouts[i];
|
||||||
|
|
||||||
|
/* Determine where the current region should go. */
|
||||||
|
cur_region.alloc_index = alloc_sizes[1] >= alloc_sizes[0] ? 1 : 0;
|
||||||
|
++alloc_counts[cur_region.alloc_index];
|
||||||
|
|
||||||
|
/* Check that the current region can fit. */
|
||||||
|
R_UNLESS(alloc_sizes[cur_region.alloc_index] >= cur_region.size, svc::ResultOutOfMemory());
|
||||||
|
|
||||||
|
/* Update our remaining size tracking. */
|
||||||
|
alloc_sizes[cur_region.alloc_index] -= cur_region.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Selection sort the regions to coalesce them by alloc index. */
|
||||||
|
for (size_t i = 0; i < num_regions - 1; ++i) {
|
||||||
|
for (size_t j = i + 1; j < num_regions; ++j) {
|
||||||
|
if (region_layouts[i].alloc_index > region_layouts[j].alloc_index) {
|
||||||
|
std::swap(region_layouts[i], region_layouts[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout the regions for each alloc index. */
|
||||||
|
for (auto cur_alloc_index = 0; cur_alloc_index < AllocIndexCount; ++cur_alloc_index) {
|
||||||
|
/* If there are no regions to place, continue. */
|
||||||
|
const size_t cur_alloc_count = alloc_counts[cur_alloc_index];
|
||||||
|
if (cur_alloc_count == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine the starting region index for the current alloc index. */
|
||||||
|
size_t cur_region_index = 0;
|
||||||
|
for (size_t i = 0; i < num_regions; ++i) {
|
||||||
|
if (region_layouts[i].alloc_index == cur_alloc_index) {
|
||||||
|
cur_region_index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If aslr is enabled, randomize the current region order. Otherwise, sort by type. */
|
||||||
|
if (m_enable_aslr) {
|
||||||
|
for (size_t i = 0; i < cur_alloc_count - 1; ++i) {
|
||||||
|
std::swap(region_layouts[cur_region_index + i], region_layouts[cur_region_index + KSystemControl::GenerateRandomRange(i, cur_alloc_count - 1)]);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
alloc_start = process_code_end;
|
for (size_t i = 0; i < cur_alloc_count - 1; ++i) {
|
||||||
alloc_size = GetInteger(end) - GetInteger(process_code_end);
|
for (size_t j = i + 1; j < cur_alloc_count; ++j) {
|
||||||
|
if (region_layouts[cur_region_index + i].type > region_layouts[cur_region_index + j].type) {
|
||||||
|
std::swap(region_layouts[cur_region_index + i], region_layouts[cur_region_index + j]);
|
||||||
}
|
}
|
||||||
const size_t needed_size = (alias_region_size + heap_region_size + stack_region_size + kernel_map_region_size);
|
|
||||||
R_UNLESS(alloc_size >= needed_size, svc::ResultOutOfMemory());
|
|
||||||
|
|
||||||
const size_t remaining_size = alloc_size - needed_size;
|
|
||||||
|
|
||||||
/* Determine random placements for each region. */
|
|
||||||
size_t alias_rnd = 0, heap_rnd = 0, stack_rnd = 0, kmap_rnd = 0;
|
|
||||||
if (enable_aslr) {
|
|
||||||
alias_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
|
||||||
heap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
|
||||||
stack_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
|
||||||
kmap_rnd = KSystemControl::GenerateRandomRange(0, remaining_size / RegionAlignment) * RegionAlignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup heap and alias regions. */
|
|
||||||
m_alias_region_start = alloc_start + alias_rnd;
|
|
||||||
m_alias_region_end = m_alias_region_start + alias_region_size;
|
|
||||||
m_heap_region_start = alloc_start + heap_rnd;
|
|
||||||
m_heap_region_end = m_heap_region_start + heap_region_size;
|
|
||||||
|
|
||||||
if (alias_rnd <= heap_rnd) {
|
|
||||||
m_heap_region_start += alias_region_size;
|
|
||||||
m_heap_region_end += alias_region_size;
|
|
||||||
} else {
|
|
||||||
m_alias_region_start += heap_region_size;
|
|
||||||
m_alias_region_end += heap_region_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup stack region. */
|
|
||||||
if (stack_region_size) {
|
|
||||||
m_stack_region_start = alloc_start + stack_rnd;
|
|
||||||
m_stack_region_end = m_stack_region_start + stack_region_size;
|
|
||||||
|
|
||||||
if (alias_rnd < stack_rnd) {
|
|
||||||
m_stack_region_start += alias_region_size;
|
|
||||||
m_stack_region_end += alias_region_size;
|
|
||||||
} else {
|
|
||||||
m_alias_region_start += stack_region_size;
|
|
||||||
m_alias_region_end += stack_region_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (heap_rnd < stack_rnd) {
|
|
||||||
m_stack_region_start += heap_region_size;
|
|
||||||
m_stack_region_end += heap_region_size;
|
|
||||||
} else {
|
|
||||||
m_heap_region_start += stack_region_size;
|
|
||||||
m_heap_region_end += stack_region_size;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup kernel map region. */
|
/* Determine aslr offsets for the current space. */
|
||||||
if (kernel_map_region_size) {
|
size_t aslr_offsets[RegionType_Count] = {};
|
||||||
m_kernel_map_region_start = alloc_start + kmap_rnd;
|
if (m_enable_aslr) {
|
||||||
m_kernel_map_region_end = m_kernel_map_region_start + kernel_map_region_size;
|
/* Generate the aslr offsets. */
|
||||||
|
for (size_t i = 0; i < cur_alloc_count; ++i) {
|
||||||
if (alias_rnd < kmap_rnd) {
|
aslr_offsets[i] = KSystemControl::GenerateRandomRange(0, alloc_sizes[cur_alloc_index] / RegionAlignment) * RegionAlignment;
|
||||||
m_kernel_map_region_start += alias_region_size;
|
|
||||||
m_kernel_map_region_end += alias_region_size;
|
|
||||||
} else {
|
|
||||||
m_alias_region_start += kernel_map_region_size;
|
|
||||||
m_alias_region_end += kernel_map_region_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heap_rnd < kmap_rnd) {
|
/* Sort the aslr offsets. */
|
||||||
m_kernel_map_region_start += heap_region_size;
|
for (size_t i = 0; i < cur_alloc_count - 1; ++i) {
|
||||||
m_kernel_map_region_end += heap_region_size;
|
for (size_t j = i + 1; j < cur_alloc_count; ++j) {
|
||||||
} else {
|
if (aslr_offsets[i] > aslr_offsets[j]) {
|
||||||
m_heap_region_start += kernel_map_region_size;
|
std::swap(aslr_offsets[i], aslr_offsets[j]);
|
||||||
m_heap_region_end += kernel_map_region_size;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stack_region_size) {
|
/* Calculate final region positions. */
|
||||||
if (stack_rnd < kmap_rnd) {
|
KProcessAddress prev_region_end = alloc_starts[cur_alloc_index];
|
||||||
m_kernel_map_region_start += stack_region_size;
|
size_t prev_aslr_offset = 0;
|
||||||
m_kernel_map_region_end += stack_region_size;
|
for (size_t i = 0; i < cur_alloc_count; ++i) {
|
||||||
} else {
|
/* Get the current region. */
|
||||||
m_stack_region_start += kernel_map_region_size;
|
auto &cur_region = region_layouts[cur_region_index + i];
|
||||||
m_stack_region_end += kernel_map_region_size;
|
|
||||||
|
/* Set the current region start/end. */
|
||||||
|
m_region_starts[cur_region.type] = (aslr_offsets[i] - prev_aslr_offset) + GetInteger(prev_region_end);
|
||||||
|
m_region_ends[cur_region.type] = m_region_starts[cur_region.type] + cur_region.size;
|
||||||
|
|
||||||
|
/* Update tracking variables. */
|
||||||
|
prev_region_end = m_region_ends[cur_region.type];
|
||||||
|
prev_aslr_offset = aslr_offsets[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Declare helpers to check that regions are inside our address space. */
|
||||||
|
const KProcessAddress process_code_last = process_code_end - 1;
|
||||||
|
auto IsInAddressSpace = [&](KProcessAddress addr) ALWAYS_INLINE_LAMBDA { return m_address_space_start <= addr && addr <= m_address_space_end; };
|
||||||
|
|
||||||
|
/* Ensure that the KernelMap region is valid. */
|
||||||
|
for (size_t k = 0; k < num_regions; ++k) {
|
||||||
|
if (const auto &kmap_region = region_layouts[k]; kmap_region.type == RegionType_KernelMap) {
|
||||||
|
/* If there's no kmap region, we have nothing to check. */
|
||||||
|
if (kmap_region.size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the kmap region is within our address space. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_KernelMap]));
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_KernelMap]));
|
||||||
|
|
||||||
|
/* Check for overlap with process code. */
|
||||||
|
const KProcessAddress kmap_start = m_region_starts[RegionType_KernelMap];
|
||||||
|
const KProcessAddress kmap_last = m_region_ends[RegionType_KernelMap] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(kernel_map_region_size == 0 || kmap_last < process_code_start || process_code_last < kmap_start);
|
||||||
|
|
||||||
|
/* Check for overlap with stack. */
|
||||||
|
for (size_t s = 0; s < num_regions; ++s) {
|
||||||
|
if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) {
|
||||||
|
if (stack_region.size != 0) {
|
||||||
|
const KProcessAddress stack_start = m_region_starts[RegionType_Stack];
|
||||||
|
const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS((kernel_map_region_size == 0 && stack_region_size == 0) || kmap_last < stack_start || stack_last < kmap_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for overlap with alias. */
|
||||||
|
for (size_t a = 0; a < num_regions; ++a) {
|
||||||
|
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
|
||||||
|
if (alias_region.size != 0) {
|
||||||
|
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
|
||||||
|
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(kmap_last < alias_start || alias_last < kmap_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for overlap with heap. */
|
||||||
|
for (size_t h = 0; h < num_regions; ++h) {
|
||||||
|
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
|
||||||
|
if (heap_region.size != 0) {
|
||||||
|
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
|
||||||
|
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(kmap_last < heap_start || heap_last < kmap_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the Stack region is valid. */
|
||||||
|
for (size_t s = 0; s < num_regions; ++s) {
|
||||||
|
if (const auto &stack_region = region_layouts[s]; stack_region.type == RegionType_Stack) {
|
||||||
|
/* If there's no stack region, we have nothing to check. */
|
||||||
|
if (stack_region.size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the stack region is within our address space. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Stack]));
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Stack]));
|
||||||
|
|
||||||
|
/* Check for overlap with process code. */
|
||||||
|
const KProcessAddress stack_start = m_region_starts[RegionType_Stack];
|
||||||
|
const KProcessAddress stack_last = m_region_ends[RegionType_Stack] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(stack_region_size == 0 || stack_last < process_code_start || process_code_last < stack_start);
|
||||||
|
|
||||||
|
/* Check for overlap with alias. */
|
||||||
|
for (size_t a = 0; a < num_regions; ++a) {
|
||||||
|
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
|
||||||
|
if (alias_region.size != 0) {
|
||||||
|
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
|
||||||
|
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(stack_last < alias_start || alias_last < stack_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for overlap with heap. */
|
||||||
|
for (size_t h = 0; h < num_regions; ++h) {
|
||||||
|
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
|
||||||
|
if (heap_region.size != 0) {
|
||||||
|
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
|
||||||
|
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(stack_last < heap_start || heap_last < stack_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the Alias region is valid. */
|
||||||
|
for (size_t a = 0; a < num_regions; ++a) {
|
||||||
|
if (const auto &alias_region = region_layouts[a]; alias_region.type == RegionType_Alias) {
|
||||||
|
/* If there's no alias region, we have nothing to check. */
|
||||||
|
if (alias_region.size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the alias region is within our address space. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Alias]));
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Alias]));
|
||||||
|
|
||||||
|
/* Check for overlap with process code. */
|
||||||
|
const KProcessAddress alias_start = m_region_starts[RegionType_Alias];
|
||||||
|
const KProcessAddress alias_last = m_region_ends[RegionType_Alias] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(alias_last < process_code_start || process_code_last < alias_start);
|
||||||
|
|
||||||
|
/* Check for overlap with heap. */
|
||||||
|
for (size_t h = 0; h < num_regions; ++h) {
|
||||||
|
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
|
||||||
|
if (heap_region.size != 0) {
|
||||||
|
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
|
||||||
|
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(alias_last < heap_start || heap_last < alias_start);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the Heap region is valid. */
|
||||||
|
for (size_t h = 0; h < num_regions; ++h) {
|
||||||
|
if (const auto &heap_region = region_layouts[h]; heap_region.type == RegionType_Heap) {
|
||||||
|
/* If there's no heap region, we have nothing to check. */
|
||||||
|
if (heap_region.size == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that the heap region is within our address space. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_starts[RegionType_Heap]));
|
||||||
|
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_region_ends[RegionType_Heap]));
|
||||||
|
|
||||||
|
/* Check for overlap with process code. */
|
||||||
|
const KProcessAddress heap_start = m_region_starts[RegionType_Heap];
|
||||||
|
const KProcessAddress heap_last = m_region_ends[RegionType_Heap] - 1;
|
||||||
|
MESOSPHERE_ABORT_UNLESS(heap_last < process_code_start || process_code_last < heap_start);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set heap and fill members. */
|
/* Set heap and fill members. */
|
||||||
m_current_heap_end = m_heap_region_start;
|
m_current_heap_end = m_region_starts[RegionType_Heap];
|
||||||
m_max_heap_size = 0;
|
m_max_heap_size = 0;
|
||||||
m_mapped_physical_memory_size = 0;
|
m_mapped_physical_memory_size = 0;
|
||||||
m_mapped_unsafe_physical_memory = 0;
|
m_mapped_unsafe_physical_memory = 0;
|
||||||
|
@ -309,32 +517,6 @@ namespace ams::kern {
|
||||||
/* Set allocation option. */
|
/* Set allocation option. */
|
||||||
m_allocate_option = KMemoryManager::EncodeOption(pool, from_back ? KMemoryManager::Direction_FromBack : KMemoryManager::Direction_FromFront);
|
m_allocate_option = KMemoryManager::EncodeOption(pool, from_back ? KMemoryManager::Direction_FromBack : KMemoryManager::Direction_FromFront);
|
||||||
|
|
||||||
/* Ensure that we regions inside our address space. */
|
|
||||||
auto IsInAddressSpace = [&](KProcessAddress addr) ALWAYS_INLINE_LAMBDA { return m_address_space_start <= addr && addr <= m_address_space_end; };
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_alias_region_start));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_alias_region_end));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_heap_region_start));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_heap_region_end));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_stack_region_start));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_stack_region_end));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_kernel_map_region_start));
|
|
||||||
MESOSPHERE_ABORT_UNLESS(IsInAddressSpace(m_kernel_map_region_end));
|
|
||||||
|
|
||||||
/* Ensure that we selected regions that don't overlap. */
|
|
||||||
const KProcessAddress alias_start = m_alias_region_start;
|
|
||||||
const KProcessAddress alias_last = m_alias_region_end - 1;
|
|
||||||
const KProcessAddress heap_start = m_heap_region_start;
|
|
||||||
const KProcessAddress heap_last = m_heap_region_end - 1;
|
|
||||||
const KProcessAddress stack_start = m_stack_region_start;
|
|
||||||
const KProcessAddress stack_last = m_stack_region_end - 1;
|
|
||||||
const KProcessAddress kmap_start = m_kernel_map_region_start;
|
|
||||||
const KProcessAddress kmap_last = m_kernel_map_region_end - 1;
|
|
||||||
MESOSPHERE_ABORT_UNLESS(alias_last < heap_start || heap_last < alias_start);
|
|
||||||
MESOSPHERE_ABORT_UNLESS(alias_last < stack_start || stack_last < alias_start);
|
|
||||||
MESOSPHERE_ABORT_UNLESS(alias_last < kmap_start || kmap_last < alias_start);
|
|
||||||
MESOSPHERE_ABORT_UNLESS(heap_last < stack_start || stack_last < heap_start);
|
|
||||||
MESOSPHERE_ABORT_UNLESS(heap_last < kmap_start || kmap_last < heap_start);
|
|
||||||
|
|
||||||
/* Initialize our implementation. */
|
/* Initialize our implementation. */
|
||||||
m_impl.InitializeForProcess(table, GetInteger(start), GetInteger(end));
|
m_impl.InitializeForProcess(table, GetInteger(start), GetInteger(end));
|
||||||
|
|
||||||
|
@ -374,16 +556,16 @@ namespace ams::kern {
|
||||||
case ams::svc::MemoryState_Kernel:
|
case ams::svc::MemoryState_Kernel:
|
||||||
return m_address_space_start;
|
return m_address_space_start;
|
||||||
case ams::svc::MemoryState_Normal:
|
case ams::svc::MemoryState_Normal:
|
||||||
return m_heap_region_start;
|
return m_region_starts[RegionType_Heap];
|
||||||
case ams::svc::MemoryState_Ipc:
|
case ams::svc::MemoryState_Ipc:
|
||||||
case ams::svc::MemoryState_NonSecureIpc:
|
case ams::svc::MemoryState_NonSecureIpc:
|
||||||
case ams::svc::MemoryState_NonDeviceIpc:
|
case ams::svc::MemoryState_NonDeviceIpc:
|
||||||
return m_alias_region_start;
|
return m_region_starts[RegionType_Alias];
|
||||||
case ams::svc::MemoryState_Stack:
|
case ams::svc::MemoryState_Stack:
|
||||||
return m_stack_region_start;
|
return m_region_starts[RegionType_Stack];
|
||||||
case ams::svc::MemoryState_Static:
|
case ams::svc::MemoryState_Static:
|
||||||
case ams::svc::MemoryState_ThreadLocal:
|
case ams::svc::MemoryState_ThreadLocal:
|
||||||
return m_kernel_map_region_start;
|
return m_region_starts[RegionType_KernelMap];
|
||||||
case ams::svc::MemoryState_Io:
|
case ams::svc::MemoryState_Io:
|
||||||
case ams::svc::MemoryState_Shared:
|
case ams::svc::MemoryState_Shared:
|
||||||
case ams::svc::MemoryState_AliasCode:
|
case ams::svc::MemoryState_AliasCode:
|
||||||
|
@ -409,16 +591,16 @@ namespace ams::kern {
|
||||||
case ams::svc::MemoryState_Kernel:
|
case ams::svc::MemoryState_Kernel:
|
||||||
return m_address_space_end - m_address_space_start;
|
return m_address_space_end - m_address_space_start;
|
||||||
case ams::svc::MemoryState_Normal:
|
case ams::svc::MemoryState_Normal:
|
||||||
return m_heap_region_end - m_heap_region_start;
|
return m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap];
|
||||||
case ams::svc::MemoryState_Ipc:
|
case ams::svc::MemoryState_Ipc:
|
||||||
case ams::svc::MemoryState_NonSecureIpc:
|
case ams::svc::MemoryState_NonSecureIpc:
|
||||||
case ams::svc::MemoryState_NonDeviceIpc:
|
case ams::svc::MemoryState_NonDeviceIpc:
|
||||||
return m_alias_region_end - m_alias_region_start;
|
return m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias];
|
||||||
case ams::svc::MemoryState_Stack:
|
case ams::svc::MemoryState_Stack:
|
||||||
return m_stack_region_end - m_stack_region_start;
|
return m_region_ends[RegionType_Stack] - m_region_starts[RegionType_Stack];
|
||||||
case ams::svc::MemoryState_Static:
|
case ams::svc::MemoryState_Static:
|
||||||
case ams::svc::MemoryState_ThreadLocal:
|
case ams::svc::MemoryState_ThreadLocal:
|
||||||
return m_kernel_map_region_end - m_kernel_map_region_start;
|
return m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap];
|
||||||
case ams::svc::MemoryState_Io:
|
case ams::svc::MemoryState_Io:
|
||||||
case ams::svc::MemoryState_Shared:
|
case ams::svc::MemoryState_Shared:
|
||||||
case ams::svc::MemoryState_AliasCode:
|
case ams::svc::MemoryState_AliasCode:
|
||||||
|
@ -446,8 +628,8 @@ namespace ams::kern {
|
||||||
const size_t region_size = this->GetRegionSize(state);
|
const size_t region_size = this->GetRegionSize(state);
|
||||||
|
|
||||||
const bool is_in_region = region_start <= addr && addr < end && last <= region_start + region_size - 1;
|
const bool is_in_region = region_start <= addr && addr < end && last <= region_start + region_size - 1;
|
||||||
const bool is_in_heap = !(end <= m_heap_region_start || m_heap_region_end <= addr || m_heap_region_start == m_heap_region_end);
|
const bool is_in_heap = !(end <= m_region_starts[RegionType_Heap] || m_region_ends[RegionType_Heap] <= addr || m_region_starts[RegionType_Heap] == m_region_ends[RegionType_Heap]);
|
||||||
const bool is_in_alias = !(end <= m_alias_region_start || m_alias_region_end <= addr || m_alias_region_start == m_alias_region_end);
|
const bool is_in_alias = !(end <= m_region_starts[RegionType_Alias] || m_region_ends[RegionType_Alias] <= addr || m_region_starts[RegionType_Alias] == m_region_ends[RegionType_Alias]);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case ams::svc::MemoryState_Free:
|
case ams::svc::MemoryState_Free:
|
||||||
case ams::svc::MemoryState_Kernel:
|
case ams::svc::MemoryState_Kernel:
|
||||||
|
@ -734,7 +916,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Begin traversal. */
|
/* Begin traversal. */
|
||||||
TraversalContext context;
|
TraversalContext context;
|
||||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 };
|
||||||
bool cur_valid = false;
|
bool cur_valid = false;
|
||||||
TraversalEntry next_entry;
|
TraversalEntry next_entry;
|
||||||
bool next_valid;
|
bool next_valid;
|
||||||
|
@ -1084,7 +1266,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Allocate pages for the insecure memory. */
|
/* Allocate pages for the insecure memory. */
|
||||||
KPageGroup pg(m_block_info_manager);
|
KPageGroup pg(m_block_info_manager);
|
||||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), size / PageSize, KMemoryManager::EncodeOption(insecure_pool, KMemoryManager::Direction_FromFront)));
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), size / PageSize, 1, KMemoryManager::EncodeOption(insecure_pool, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
/* Close the opened pages when we're done with them. */
|
/* Close the opened pages when we're done with them. */
|
||||||
/* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */
|
/* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */
|
||||||
|
@ -1237,14 +1419,14 @@ namespace ams::kern {
|
||||||
return this->GetSize(KMemoryState_AliasCodeData);
|
return this->GetSize(KMemoryState_AliasCodeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, KMemoryPermission perm) {
|
Result KPageTableBase::AllocateAndMapPagesImpl(PageLinkedList *page_list, KProcessAddress address, size_t num_pages, const KPageProperties &properties) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Create a page group to hold the pages we allocate. */
|
/* Create a page group to hold the pages we allocate. */
|
||||||
KPageGroup pg(m_block_info_manager);
|
KPageGroup pg(m_block_info_manager);
|
||||||
|
|
||||||
/* Allocate the pages. */
|
/* Allocate the pages. */
|
||||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, 1, m_allocate_option));
|
||||||
|
|
||||||
/* Ensure that the page group is closed when we're done working with it. */
|
/* Ensure that the page group is closed when we're done working with it. */
|
||||||
ON_SCOPE_EXIT { pg.Close(); };
|
ON_SCOPE_EXIT { pg.Close(); };
|
||||||
|
@ -1255,7 +1437,6 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map the pages. */
|
/* Map the pages. */
|
||||||
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_None };
|
|
||||||
R_RETURN(this->Operate(page_list, address, num_pages, pg, properties, OperationType_MapGroup, false));
|
R_RETURN(this->Operate(page_list, address, num_pages, pg, properties, OperationType_MapGroup, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1506,11 +1687,12 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Begin a traversal. */
|
/* Begin a traversal. */
|
||||||
TraversalContext context;
|
TraversalContext context;
|
||||||
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0 };
|
TraversalEntry cur_entry = { .phys_addr = Null<KPhysicalAddress>, .block_size = 0, .sw_reserved_bits = 0, .attr = 0 };
|
||||||
R_UNLESS(impl.BeginTraversal(std::addressof(cur_entry), std::addressof(context), address), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(impl.BeginTraversal(std::addressof(cur_entry), std::addressof(context), address), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Traverse until we have enough size or we aren't contiguous any more. */
|
/* Traverse until we have enough size or we aren't contiguous any more. */
|
||||||
const KPhysicalAddress phys_address = cur_entry.phys_addr;
|
const KPhysicalAddress phys_address = cur_entry.phys_addr;
|
||||||
|
const u8 entry_attr = cur_entry.attr;
|
||||||
size_t contig_size;
|
size_t contig_size;
|
||||||
for (contig_size = cur_entry.block_size - (GetInteger(phys_address) & (cur_entry.block_size - 1)); contig_size < size; contig_size += cur_entry.block_size) {
|
for (contig_size = cur_entry.block_size - (GetInteger(phys_address) & (cur_entry.block_size - 1)); contig_size < size; contig_size += cur_entry.block_size) {
|
||||||
if (!impl.ContinueTraversal(std::addressof(cur_entry), std::addressof(context))) {
|
if (!impl.ContinueTraversal(std::addressof(cur_entry), std::addressof(context))) {
|
||||||
|
@ -1519,6 +1701,9 @@ namespace ams::kern {
|
||||||
if (cur_entry.phys_addr != phys_address + contig_size) {
|
if (cur_entry.phys_addr != phys_address + contig_size) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (cur_entry.attr != entry_attr) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Take the minimum size for our region. */
|
/* Take the minimum size for our region. */
|
||||||
|
@ -1532,7 +1717,7 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The memory is contiguous, so set the output range. */
|
/* The memory is contiguous, so set the output range. */
|
||||||
out->Set(phys_address, size, is_heap);
|
out->Set(phys_address, size, is_heap, attr);
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1693,16 +1878,16 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Validate that setting heap size is possible at all. */
|
/* Validate that setting heap size is possible at all. */
|
||||||
R_UNLESS(!m_is_kernel, svc::ResultOutOfMemory());
|
R_UNLESS(!m_is_kernel, svc::ResultOutOfMemory());
|
||||||
R_UNLESS(size <= static_cast<size_t>(m_heap_region_end - m_heap_region_start), svc::ResultOutOfMemory());
|
R_UNLESS(size <= static_cast<size_t>(m_region_ends[RegionType_Heap] - m_region_starts[RegionType_Heap]), svc::ResultOutOfMemory());
|
||||||
R_UNLESS(size <= m_max_heap_size, svc::ResultOutOfMemory());
|
R_UNLESS(size <= m_max_heap_size, svc::ResultOutOfMemory());
|
||||||
|
|
||||||
if (size < static_cast<size_t>(m_current_heap_end - m_heap_region_start)) {
|
if (size < static_cast<size_t>(m_current_heap_end - m_region_starts[RegionType_Heap])) {
|
||||||
/* The size being requested is less than the current size, so we need to free the end of the heap. */
|
/* The size being requested is less than the current size, so we need to free the end of the heap. */
|
||||||
|
|
||||||
/* Validate memory state. */
|
/* Validate memory state. */
|
||||||
size_t num_allocator_blocks;
|
size_t num_allocator_blocks;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks),
|
||||||
m_heap_region_start + size, (m_current_heap_end - m_heap_region_start) - size,
|
m_region_starts[RegionType_Heap] + size, (m_current_heap_end - m_region_starts[RegionType_Heap]) - size,
|
||||||
KMemoryState_All, KMemoryState_Normal,
|
KMemoryState_All, KMemoryState_Normal,
|
||||||
KMemoryPermission_All, KMemoryPermission_UserReadWrite,
|
KMemoryPermission_All, KMemoryPermission_UserReadWrite,
|
||||||
KMemoryAttribute_All, KMemoryAttribute_None));
|
KMemoryAttribute_All, KMemoryAttribute_None));
|
||||||
|
@ -1716,30 +1901,30 @@ namespace ams::kern {
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Unmap the end of the heap. */
|
/* Unmap the end of the heap. */
|
||||||
const size_t num_pages = ((m_current_heap_end - m_heap_region_start) - size) / PageSize;
|
const size_t num_pages = ((m_current_heap_end - m_region_starts[RegionType_Heap]) - size) / PageSize;
|
||||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||||
R_TRY(this->Operate(updater.GetPageList(), m_heap_region_start + size, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
R_TRY(this->Operate(updater.GetPageList(), m_region_starts[RegionType_Heap] + size, num_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||||
|
|
||||||
/* Release the memory from the resource limit. */
|
/* Release the memory from the resource limit. */
|
||||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, num_pages * PageSize);
|
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, num_pages * PageSize);
|
||||||
|
|
||||||
/* Apply the memory block update. */
|
/* Apply the memory block update. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), m_heap_region_start + size, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, size == 0 ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), m_region_starts[RegionType_Heap] + size, num_pages, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, size == 0 ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
|
||||||
/* Update the current heap end. */
|
/* Update the current heap end. */
|
||||||
m_current_heap_end = m_heap_region_start + size;
|
m_current_heap_end = m_region_starts[RegionType_Heap] + size;
|
||||||
|
|
||||||
/* Set the output. */
|
/* Set the output. */
|
||||||
*out = m_heap_region_start;
|
*out = m_region_starts[RegionType_Heap];
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
} else if (size == static_cast<size_t>(m_current_heap_end - m_heap_region_start)) {
|
} else if (size == static_cast<size_t>(m_current_heap_end - m_region_starts[RegionType_Heap])) {
|
||||||
/* The size requested is exactly the current size. */
|
/* The size requested is exactly the current size. */
|
||||||
*out = m_heap_region_start;
|
*out = m_region_starts[RegionType_Heap];
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
} else {
|
} else {
|
||||||
/* We have to allocate memory. Determine how much to allocate and where while the table is locked. */
|
/* We have to allocate memory. Determine how much to allocate and where while the table is locked. */
|
||||||
cur_address = m_current_heap_end;
|
cur_address = m_current_heap_end;
|
||||||
allocation_size = size - (m_current_heap_end - m_heap_region_start);
|
allocation_size = size - (m_current_heap_end - m_region_starts[RegionType_Heap]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1749,7 +1934,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Allocate pages for the heap extension. */
|
/* Allocate pages for the heap extension. */
|
||||||
KPageGroup pg(m_block_info_manager);
|
KPageGroup pg(m_block_info_manager);
|
||||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), allocation_size / PageSize, m_allocate_option));
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), allocation_size / PageSize, 1, m_allocate_option));
|
||||||
|
|
||||||
/* Close the opened pages when we're done with them. */
|
/* Close the opened pages when we're done with them. */
|
||||||
/* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */
|
/* If the mapping succeeds, each page will gain an extra reference, otherwise they will be freed automatically. */
|
||||||
|
@ -1782,20 +1967,20 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Map the pages. */
|
/* Map the pages. */
|
||||||
const size_t num_pages = allocation_size / PageSize;
|
const size_t num_pages = allocation_size / PageSize;
|
||||||
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, (m_current_heap_end == m_heap_region_start) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, (m_current_heap_end == m_region_starts[RegionType_Heap]) ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
||||||
R_TRY(this->Operate(updater.GetPageList(), m_current_heap_end, num_pages, pg, map_properties, OperationType_MapGroup, false));
|
R_TRY(this->Operate(updater.GetPageList(), m_current_heap_end, num_pages, pg, map_properties, OperationType_MapGroup, false));
|
||||||
|
|
||||||
/* We succeeded, so commit our memory reservation. */
|
/* We succeeded, so commit our memory reservation. */
|
||||||
memory_reservation.Commit();
|
memory_reservation.Commit();
|
||||||
|
|
||||||
/* Apply the memory block update. */
|
/* Apply the memory block update. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), m_current_heap_end, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, m_heap_region_start == m_current_heap_end ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), m_current_heap_end, num_pages, KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, m_region_starts[RegionType_Heap] == m_current_heap_end ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
|
||||||
/* Update the current heap end. */
|
/* Update the current heap end. */
|
||||||
m_current_heap_end = m_heap_region_start + size;
|
m_current_heap_end = m_region_starts[RegionType_Heap] + size;
|
||||||
|
|
||||||
/* Set the output. */
|
/* Set the output. */
|
||||||
*out = m_heap_region_start;
|
*out = m_region_starts[RegionType_Heap];
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1927,8 +2112,8 @@ namespace ams::kern {
|
||||||
const KPhysicalAddress last = phys_addr + size - 1;
|
const KPhysicalAddress last = phys_addr + size - 1;
|
||||||
|
|
||||||
/* Get region extents. */
|
/* Get region extents. */
|
||||||
const KProcessAddress region_start = m_kernel_map_region_start;
|
const KProcessAddress region_start = m_region_starts[RegionType_KernelMap];
|
||||||
const size_t region_size = m_kernel_map_region_end - m_kernel_map_region_start;
|
const size_t region_size = m_region_ends[RegionType_KernelMap] - m_region_starts[RegionType_KernelMap];
|
||||||
const size_t region_num_pages = region_size / PageSize;
|
const size_t region_num_pages = region_size / PageSize;
|
||||||
|
|
||||||
MESOSPHERE_ASSERT(this->CanContain(region_start, region_size, state));
|
MESOSPHERE_ASSERT(this->CanContain(region_start, region_size, state));
|
||||||
|
@ -2237,11 +2422,11 @@ namespace ams::kern {
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Perform mapping operation. */
|
/* Perform mapping operation. */
|
||||||
if (is_pa_valid) {
|
|
||||||
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
|
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
|
||||||
|
if (is_pa_valid) {
|
||||||
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
||||||
} else {
|
} else {
|
||||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
|
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, properties));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
|
@ -2273,7 +2458,8 @@ namespace ams::kern {
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Map the pages. */
|
/* Map the pages. */
|
||||||
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
|
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
|
||||||
|
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, properties));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
@ -2812,7 +2998,7 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address));
|
MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address));
|
||||||
|
|
||||||
/* Determine the current read size. */
|
/* Determine the current read size. */
|
||||||
const size_t cur_size = std::min<size_t>(last_address - address + 1, util::AlignDown(GetInteger(address) + PageSize, PageSize) - GetInteger(address));
|
const size_t cur_size = std::min<size_t>(last_address - address + 1, PageSize - (GetInteger(address) & (PageSize - 1)));
|
||||||
|
|
||||||
/* Read. */
|
/* Read. */
|
||||||
R_TRY(dst_page_table.ReadIoMemoryImpl(dst, phys_addr, cur_size, state));
|
R_TRY(dst_page_table.ReadIoMemoryImpl(dst, phys_addr, cur_size, state));
|
||||||
|
@ -2848,7 +3034,7 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address));
|
MESOSPHERE_ABORT_UNLESS(src_page_table.GetPhysicalAddressLocked(std::addressof(phys_addr), address));
|
||||||
|
|
||||||
/* Determine the current read size. */
|
/* Determine the current read size. */
|
||||||
const size_t cur_size = std::min<size_t>(last_address - address + 1, util::AlignDown(GetInteger(address) + PageSize, PageSize) - GetInteger(address));
|
const size_t cur_size = std::min<size_t>(last_address - address + 1, PageSize - (GetInteger(address) & (PageSize - 1)));
|
||||||
|
|
||||||
/* Read. */
|
/* Read. */
|
||||||
R_TRY(dst_page_table.WriteIoMemoryImpl(phys_addr, src, cur_size, state));
|
R_TRY(dst_page_table.WriteIoMemoryImpl(phys_addr, src, cur_size, state));
|
||||||
|
@ -3720,8 +3906,8 @@ namespace ams::kern {
|
||||||
MESOSPHERE_ASSERT(src_page_table.IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(src_page_table.IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Check that we can theoretically map. */
|
/* Check that we can theoretically map. */
|
||||||
const KProcessAddress region_start = m_alias_region_start;
|
const KProcessAddress region_start = m_region_starts[RegionType_Alias];
|
||||||
const size_t region_size = m_alias_region_end - m_alias_region_start;
|
const size_t region_size = m_region_ends[RegionType_Alias] - m_region_starts[RegionType_Alias];
|
||||||
R_UNLESS(size < region_size, svc::ResultOutOfAddressSpace());
|
R_UNLESS(size < region_size, svc::ResultOutOfAddressSpace());
|
||||||
|
|
||||||
/* Get aligned source extents. */
|
/* Get aligned source extents. */
|
||||||
|
@ -4662,7 +4848,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Allocate the new memory. */
|
/* Allocate the new memory. */
|
||||||
const size_t num_pages = size / PageSize;
|
const size_t num_pages = size / PageSize;
|
||||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, KMemoryManager::EncodeOption(KMemoryManager::Pool_Unsafe, KMemoryManager::Direction_FromFront)));
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, 1, KMemoryManager::EncodeOption(KMemoryManager::Pool_Unsafe, KMemoryManager::Direction_FromFront)));
|
||||||
|
|
||||||
/* Close the page group when we're done with it. */
|
/* Close the page group when we're done with it. */
|
||||||
ON_SCOPE_EXIT { pg.Close(); };
|
ON_SCOPE_EXIT { pg.Close(); };
|
||||||
|
|
|
@ -298,10 +298,8 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Setup page table. */
|
/* Setup page table. */
|
||||||
{
|
{
|
||||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0;
|
||||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit));
|
||||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit));
|
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||||
|
|
||||||
|
@ -379,10 +377,8 @@ namespace ams::kern {
|
||||||
|
|
||||||
/* Setup page table. */
|
/* Setup page table. */
|
||||||
{
|
{
|
||||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0;
|
||||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit));
|
||||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
|
||||||
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, m_system_resource, res_limit));
|
|
||||||
}
|
}
|
||||||
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace ams::kern {
|
||||||
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
R_UNLESS(memory_reservation.Succeeded(), svc::ResultLimitReached());
|
||||||
|
|
||||||
/* Allocate the memory. */
|
/* Allocate the memory. */
|
||||||
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(m_page_group), num_pages, owner->GetAllocateOption()));
|
R_TRY(Kernel::GetMemoryManager().AllocateAndOpen(std::addressof(m_page_group), num_pages, 1, owner->GetAllocateOption()));
|
||||||
|
|
||||||
/* Commit our reservation. */
|
/* Commit our reservation. */
|
||||||
memory_reservation.Commit();
|
memory_reservation.Commit();
|
||||||
|
|
|
@ -78,7 +78,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
void KSystemControlBase::Init::CpuOnImpl(u64 core_id, uintptr_t entrypoint, uintptr_t arg) {
|
||||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0, false>(core_id, entrypoint, arg)) == 0);
|
MESOSPHERE_INIT_ABORT_UNLESS((::ams::kern::arch::arm64::smc::CpuOn<0>(core_id, entrypoint, arg)) == 0);
|
||||||
#else
|
#else
|
||||||
AMS_INFINITE_LOOP();
|
AMS_INFINITE_LOOP();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -106,6 +106,9 @@ namespace ams::kern::svc {
|
||||||
*out = 0;
|
*out = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ams::svc::InfoType_AliasRegionExtraSize:
|
||||||
|
*out = process->GetPageTable().GetAliasRegionExtraSize();
|
||||||
|
break;
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +137,7 @@ namespace ams::kern::svc {
|
||||||
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
case ams::svc::InfoType_UsedNonSystemMemorySize:
|
||||||
case ams::svc::InfoType_IsApplication:
|
case ams::svc::InfoType_IsApplication:
|
||||||
case ams::svc::InfoType_FreeThreadCount:
|
case ams::svc::InfoType_FreeThreadCount:
|
||||||
|
case ams::svc::InfoType_AliasRegionExtraSize:
|
||||||
{
|
{
|
||||||
/* These info types don't support non-zero subtypes. */
|
/* These info types don't support non-zero subtypes. */
|
||||||
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||||
|
|
|
@ -162,6 +162,18 @@ namespace ams::kern::svc {
|
||||||
/* Check that the number of extra resource pages is >= 0. */
|
/* Check that the number of extra resource pages is >= 0. */
|
||||||
R_UNLESS(params.system_resource_num_pages >= 0, svc::ResultInvalidSize());
|
R_UNLESS(params.system_resource_num_pages >= 0, svc::ResultInvalidSize());
|
||||||
|
|
||||||
|
/* Validate that the alias region extra size is allowed, if enabled. */
|
||||||
|
if (params.flags & ams::svc::CreateProcessFlag_EnableAliasRegionExtraSize) {
|
||||||
|
/* Check that we have a 64-bit address space. */
|
||||||
|
R_UNLESS((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask) == ams::svc::CreateProcessFlag_AddressSpace64Bit, svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Check that the system resource page count is non-zero. */
|
||||||
|
R_UNLESS(params.system_resource_num_pages > 0, svc::ResultInvalidState());
|
||||||
|
|
||||||
|
/* Check that debug mode is enabled. */
|
||||||
|
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultInvalidState());
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert to sizes. */
|
/* Convert to sizes. */
|
||||||
const size_t code_num_pages = params.code_num_pages;
|
const size_t code_num_pages = params.code_num_pages;
|
||||||
const size_t system_resource_num_pages = params.system_resource_num_pages;
|
const size_t system_resource_num_pages = params.system_resource_num_pages;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
HANDLER(FieldType_NumericU8, 12) \
|
HANDLER(FieldType_NumericU8, 12) \
|
||||||
HANDLER(FieldType_NumericI16, 13) \
|
HANDLER(FieldType_NumericI16, 13) \
|
||||||
HANDLER(FieldType_NumericI8, 14) \
|
HANDLER(FieldType_NumericI8, 14) \
|
||||||
HANDLER(FieldType_I8Array, 15) \
|
HANDLER(FieldType_I8Array, 15)
|
||||||
|
|
||||||
#define AMS_ERPT_FOREACH_CATEGORY(HANDLER) \
|
#define AMS_ERPT_FOREACH_CATEGORY(HANDLER) \
|
||||||
HANDLER(Test, 0 ) \
|
HANDLER(Test, 0 ) \
|
||||||
|
@ -180,6 +180,7 @@
|
||||||
HANDLER(EthernetAdapterOUIInfo, 139 ) \
|
HANDLER(EthernetAdapterOUIInfo, 139 ) \
|
||||||
HANDLER(NANDTypeInfo, 140 ) \
|
HANDLER(NANDTypeInfo, 140 ) \
|
||||||
HANDLER(MicroSDTypeInfo, 141 ) \
|
HANDLER(MicroSDTypeInfo, 141 ) \
|
||||||
|
HANDLER(TestNx, 1000)
|
||||||
|
|
||||||
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
|
#define AMS_ERPT_FOREACH_FIELD(HANDLER) \
|
||||||
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
|
HANDLER(TestU64, 0, Test, FieldType_NumericU64, FieldFlag_None ) \
|
||||||
|
@ -354,13 +355,13 @@
|
||||||
HANDLER(CompositorDisplayState, 169, CompositorDisplayInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(CompositorDisplayState, 169, CompositorDisplayInfo, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(CompositorHWCState, 170, CompositorHWCInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(CompositorHWCState, 170, CompositorHWCInfo, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(InputCurrentLimit, 171, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(InputCurrentLimit, 171, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(BoostModeCurrentLimit, 172, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(BoostModeCurrentLimitDeprecated, 172, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(FastChargeCurrentLimit, 173, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(FastChargeCurrentLimit, 173, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(ChargeVoltageLimit, 174, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(ChargeVoltageLimit, 174, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(ChargeConfiguration, 175, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(ChargeConfigurationDeprecated, 175, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(HizMode, 176, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(HizModeDeprecated, 176, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(ChargeEnabled, 177, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(ChargeEnabled, 177, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(PowerSupplyPath, 178, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(PowerSupplyPathDeprecated, 178, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(BatteryTemperature, 179, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(BatteryTemperature, 179, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(BatteryChargePercent, 180, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(BatteryChargePercent, 180, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(BatteryChargeVoltage, 181, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(BatteryChargeVoltage, 181, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
@ -370,8 +371,8 @@
|
||||||
HANDLER(PowerSupplyVoltage, 185, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(PowerSupplyVoltage, 185, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(PowerSupplyCurrent, 186, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
HANDLER(PowerSupplyCurrent, 186, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(FastBatteryChargingEnabled, 187, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(ControllerPowerSupplyAcquired, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(ControllerPowerSupplyAcquiredDeprecated, 188, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(OtgRequested, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
HANDLER(OtgRequestedDeprecated, 189, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
HANDLER(NANDPreEolInfo, 190, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(NANDPreEolInfo, 190, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(NANDDeviceLifeTimeEstTypA, 191, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(NANDDeviceLifeTimeEstTypA, 191, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(NANDDeviceLifeTimeEstTypB, 192, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(NANDDeviceLifeTimeEstTypB, 192, NANDExtendedCsd, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
@ -435,15 +436,15 @@
|
||||||
HANDLER(GpuErrorPbdmaGpShadow1, 250, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(GpuErrorPbdmaGpShadow1, 250, GpuErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AccessPointChannel, 251, AccessPointInfo, FieldType_NumericU16, FieldFlag_None ) \
|
HANDLER(AccessPointChannel, 251, AccessPointInfo, FieldType_NumericU16, FieldFlag_None ) \
|
||||||
HANDLER(ThreadName, 252, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(ThreadName, 252, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionRegisters, 253, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
HANDLER(AdspExceptionRegistersDeprecated, 253, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionSpsr, 254, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionSpsrDeprecated, 254, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionProgramCounter, 255, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionProgramCounter, 255, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionLinkRegister, 256, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionLinkRegister, 256, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionStackPointer, 257, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionStackPointer, 257, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionArmModeRegisters, 258, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
HANDLER(AdspExceptionArmModeRegistersDeprecated, 258, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionStackAddress, 259, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionStackAddressDeprecated, 259, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionStackDump, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
HANDLER(AdspExceptionStackDumpDeprecated, 260, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
HANDLER(AdspExceptionReason, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(AdspExceptionReasonDeprecated, 261, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(OscillatorClock, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(OscillatorClock, 262, PowerClockInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(CpuDvfsTableClocks, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
HANDLER(CpuDvfsTableClocks, 263, PowerClockInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
HANDLER(CpuDvfsTableVoltages, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
HANDLER(CpuDvfsTableVoltages, 264, PowerClockInfo, FieldType_I32Array, FieldFlag_None ) \
|
||||||
|
@ -863,4 +864,18 @@
|
||||||
HANDLER(MicroSDType, 678, MicroSDTypeInfo, FieldType_U8Array, FieldFlag_None ) \
|
HANDLER(MicroSDType, 678, MicroSDTypeInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||||
HANDLER(GameCardLastDeactivateReasonResult, 679, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
HANDLER(GameCardLastDeactivateReasonResult, 679, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
HANDLER(GameCardLastDeactivateReason, 680, GameCardErrorInfo, FieldType_NumericU8, FieldFlag_None ) \
|
HANDLER(GameCardLastDeactivateReason, 680, GameCardErrorInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||||
|
HANDLER(InvalidErrorCode, 681, ErrorInfo, FieldType_String, FieldFlag_None ) \
|
||||||
|
HANDLER(TestStringNx, 1000, TestNx, FieldType_String, FieldFlag_None ) \
|
||||||
|
HANDLER(BoostModeCurrentLimit, 1001, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(ChargeConfiguration, 1002, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(HizMode, 1003, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
|
HANDLER(PowerSupplyPath, 1004, BatteryChargeInfo, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(ControllerPowerSupplyAcquired, 1005, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
|
HANDLER(OtgRequested, 1006, BatteryChargeInfo, FieldType_Bool, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionRegisters, 1007, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionSpsr, 1008, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionArmModeRegisters, 1009, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionStackAddress, 1010, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionStackDump, 1011, AdspErrorInfo, FieldType_U32Array, FieldFlag_None ) \
|
||||||
|
HANDLER(AdspExceptionReason, 1012, AdspErrorInfo, FieldType_NumericU32, FieldFlag_None )
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,6 @@ namespace ams::erpt {
|
||||||
|
|
||||||
enum CategoryId {
|
enum CategoryId {
|
||||||
AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM)
|
AMS_ERPT_FOREACH_CATEGORY(GENERATE_ENUM)
|
||||||
CategoryId_Count,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef GENERATE_ENUM
|
#undef GENERATE_ENUM
|
||||||
|
@ -43,7 +42,6 @@ namespace ams::erpt {
|
||||||
|
|
||||||
enum FieldId {
|
enum FieldId {
|
||||||
AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM)
|
AMS_ERPT_FOREACH_FIELD(GENERATE_ENUM)
|
||||||
FieldId_Count,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef GENERATE_ENUM
|
#undef GENERATE_ENUM
|
||||||
|
|
|
@ -58,34 +58,88 @@ namespace ams::erpt::srv {
|
||||||
};
|
};
|
||||||
#undef STRINGIZE_HANDLER
|
#undef STRINGIZE_HANDLER
|
||||||
|
|
||||||
#define GET_FIELD_CATEGORY(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = CategoryId_##CATEGORY,
|
#define GET_FIELD_CATEGORY(FIELD, ID, CATEGORY, TYPE, FLAG) CategoryId_##CATEGORY,
|
||||||
constexpr inline const CategoryId FieldToCategoryMap[] = {
|
constexpr inline const CategoryId FieldIndexToCategoryMap[] = {
|
||||||
AMS_ERPT_FOREACH_FIELD(GET_FIELD_CATEGORY)
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_CATEGORY)
|
||||||
};
|
};
|
||||||
#undef GET_FIELD_CATEGORY
|
#undef GET_FIELD_CATEGORY
|
||||||
|
|
||||||
#define GET_FIELD_TYPE(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = TYPE,
|
#define GET_FIELD_TYPE(FIELD, ID, CATEGORY, TYPE, FLAG) TYPE,
|
||||||
constexpr inline const FieldType FieldToTypeMap[] = {
|
constexpr inline const FieldType FieldIndexToTypeMap[] = {
|
||||||
AMS_ERPT_FOREACH_FIELD(GET_FIELD_TYPE)
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_TYPE)
|
||||||
};
|
};
|
||||||
#undef GET_FIELD_TYPE
|
#undef GET_FIELD_TYPE
|
||||||
|
|
||||||
#define GET_FIELD_FLAG(FIELD, ID, CATEGORY, TYPE, FLAG) [FieldId_##FIELD] = FLAG,
|
#define GET_FIELD_FLAG(FIELD, ID, CATEGORY, TYPE, FLAG) FLAG,
|
||||||
constexpr inline const FieldFlag FieldToFlagMap[] = {
|
constexpr inline const FieldFlag FieldIndexToFlagMap[] = {
|
||||||
AMS_ERPT_FOREACH_FIELD(GET_FIELD_FLAG)
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_FLAG)
|
||||||
};
|
};
|
||||||
#undef GET_FIELD_FLAG
|
#undef GET_FIELD_FLAG
|
||||||
|
|
||||||
inline CategoryId ConvertFieldToCategory(FieldId id) {
|
#define GET_FIELD_ID(FIELD, ...) FieldId_##FIELD,
|
||||||
return FieldToCategoryMap[id];
|
constexpr inline const FieldId FieldIndexToFieldIdMap[] = {
|
||||||
|
AMS_ERPT_FOREACH_FIELD(GET_FIELD_ID)
|
||||||
|
};
|
||||||
|
#undef GET_FIELD_ID
|
||||||
|
|
||||||
|
#define GET_CATEGORY_ID(CATEGORY, ...) CategoryId_##CATEGORY,
|
||||||
|
constexpr inline const CategoryId CategoryIndexToCategoryIdMap[] = {
|
||||||
|
AMS_ERPT_FOREACH_CATEGORY(GET_CATEGORY_ID)
|
||||||
|
};
|
||||||
|
#undef GET_CATEGORY_ID
|
||||||
|
|
||||||
|
constexpr util::optional<size_t> FindFieldIndex(FieldId id) {
|
||||||
|
if (std::is_constant_evaluated()) {
|
||||||
|
for (size_t i = 0; i < util::size(FieldIndexToFieldIdMap); ++i) {
|
||||||
|
if (FieldIndexToFieldIdMap[i] == id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FieldType ConvertFieldToType(FieldId id) {
|
return util::nullopt;
|
||||||
return FieldToTypeMap[id];
|
} else {
|
||||||
|
if (const auto it = std::lower_bound(std::begin(FieldIndexToFieldIdMap), std::end(FieldIndexToFieldIdMap), id); it != std::end(FieldIndexToFieldIdMap) && *it == id) {
|
||||||
|
return std::distance(FieldIndexToFieldIdMap, it);
|
||||||
|
} else {
|
||||||
|
return util::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline FieldFlag ConvertFieldToFlag(FieldId id) {
|
constexpr util::optional<size_t> FindCategoryIndex(CategoryId id) {
|
||||||
return FieldToFlagMap[id];
|
if (std::is_constant_evaluated()) {
|
||||||
|
for (size_t i = 0; i < util::size(CategoryIndexToCategoryIdMap); ++i) {
|
||||||
|
if (CategoryIndexToCategoryIdMap[i] == id) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util::nullopt;
|
||||||
|
} else {
|
||||||
|
if (const auto it = std::lower_bound(std::begin(CategoryIndexToCategoryIdMap), std::end(CategoryIndexToCategoryIdMap), id); it != std::end(CategoryIndexToCategoryIdMap) && *it == id) {
|
||||||
|
return std::distance(CategoryIndexToCategoryIdMap, it);
|
||||||
|
} else {
|
||||||
|
return util::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline CategoryId ConvertFieldToCategory(FieldId id) {
|
||||||
|
const auto index = FindFieldIndex(id);
|
||||||
|
AMS_ASSERT(index.has_value());
|
||||||
|
return FieldIndexToCategoryMap[index.value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline FieldType ConvertFieldToType(FieldId id) {
|
||||||
|
const auto index = FindFieldIndex(id);
|
||||||
|
AMS_ASSERT(index.has_value());
|
||||||
|
return FieldIndexToTypeMap[index.value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr inline FieldFlag ConvertFieldToFlag(FieldId id) {
|
||||||
|
const auto index = FindFieldIndex(id);
|
||||||
|
AMS_ASSERT(index.has_value());
|
||||||
|
return FieldIndexToFlagMap[index.value()];
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr inline ReportFlagSet MakeNoReportFlags() {
|
constexpr inline ReportFlagSet MakeNoReportFlags() {
|
||||||
|
|
|
@ -70,12 +70,12 @@ namespace ams::erpt::srv {
|
||||||
auto guard = SCOPE_GUARD { m_ctx.field_count = 0; };
|
auto guard = SCOPE_GUARD { m_ctx.field_count = 0; };
|
||||||
|
|
||||||
R_UNLESS(m_ctx.field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
|
R_UNLESS(m_ctx.field_count <= FieldsPerContext, erpt::ResultInvalidArgument());
|
||||||
R_UNLESS(0 <= m_ctx.category && m_ctx.category < CategoryId_Count, erpt::ResultInvalidArgument());
|
R_UNLESS(FindCategoryIndex(m_ctx.category).has_value(), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
for (u32 i = 0; i < m_ctx.field_count; i++) {
|
for (u32 i = 0; i < m_ctx.field_count; i++) {
|
||||||
m_ctx.fields[i] = ctx_ptr->fields[i];
|
m_ctx.fields[i] = ctx_ptr->fields[i];
|
||||||
|
|
||||||
R_UNLESS(0 <= m_ctx.fields[i].id && m_ctx.fields[i].id < FieldId_Count, erpt::ResultInvalidArgument());
|
R_UNLESS(FindFieldIndex(m_ctx.fields[i].id).has_value(), erpt::ResultInvalidArgument());
|
||||||
R_UNLESS(0 <= m_ctx.fields[i].type && m_ctx.fields[i].type < FieldType_Count, erpt::ResultInvalidArgument());
|
R_UNLESS(0 <= m_ctx.fields[i].type && m_ctx.fields[i].type < FieldType_Count, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
R_UNLESS(m_ctx.fields[i].type == ConvertFieldToType(m_ctx.fields[i].id), erpt::ResultFieldTypeMismatch());
|
R_UNLESS(m_ctx.fields[i].type == ConvertFieldToType(m_ctx.fields[i].id), erpt::ResultFieldTypeMismatch());
|
||||||
|
|
|
@ -62,7 +62,10 @@ namespace ams::erpt::srv {
|
||||||
static Result AddId(Report *report, FieldId field_id) {
|
static Result AddId(Report *report, FieldId field_id) {
|
||||||
static_assert(MaxFieldStringSize < ElementSize_256);
|
static_assert(MaxFieldStringSize < ElementSize_256);
|
||||||
|
|
||||||
R_TRY(AddStringValue(report, FieldString[field_id], strnlen(FieldString[field_id], MaxFieldStringSize)));
|
const auto index = FindFieldIndex(field_id);
|
||||||
|
AMS_ASSERT(index.has_value());
|
||||||
|
|
||||||
|
R_TRY(AddStringValue(report, FieldString[index.value()], strnlen(FieldString[index.value()], MaxFieldStringSize)));
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,8 +105,8 @@ namespace ams::erpt::srv {
|
||||||
|
|
||||||
g_sf_allocator.Attach(g_heap_handle);
|
g_sf_allocator.Attach(g_heap_handle);
|
||||||
|
|
||||||
for (auto i = 0; i < CategoryId_Count; i++) {
|
for (const auto category_id : CategoryIndexToCategoryIdMap) {
|
||||||
Context *ctx = new Context(static_cast<CategoryId>(i));
|
Context *ctx = new Context(category_id);
|
||||||
AMS_ABORT_UNLESS(ctx != nullptr);
|
AMS_ABORT_UNLESS(ctx != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -277,7 +277,7 @@ namespace ams::erpt::srv {
|
||||||
void SaveSyslogReportIfRequired(const ContextEntry *ctx, const ReportId &report_id) {
|
void SaveSyslogReportIfRequired(const ContextEntry *ctx, const ReportId &report_id) {
|
||||||
bool needs_save_syslog = true;
|
bool needs_save_syslog = true;
|
||||||
for (u32 i = 0; i < ctx->field_count; i++) {
|
for (u32 i = 0; i < ctx->field_count; i++) {
|
||||||
static_assert(FieldToTypeMap[FieldId_HasSyslogFlag] == FieldType_Bool);
|
static_assert(FieldIndexToTypeMap[*FindFieldIndex(FieldId_HasSyslogFlag)] == FieldType_Bool);
|
||||||
if (ctx->fields[i].id == FieldId_HasSyslogFlag && !ctx->fields[i].value_bool) {
|
if (ctx->fields[i].id == FieldId_HasSyslogFlag && !ctx->fields[i].value_bool) {
|
||||||
needs_save_syslog = false;
|
needs_save_syslog = false;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -21,11 +21,12 @@ namespace ams::os::impl {
|
||||||
class VammManagerHorizonImpl {
|
class VammManagerHorizonImpl {
|
||||||
public:
|
public:
|
||||||
static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) {
|
static void GetReservedRegionImpl(uintptr_t *out_start, uintptr_t *out_size) {
|
||||||
u64 start, size;
|
u64 start, size, extra_size;
|
||||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(start), svc::InfoType_AliasRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
|
R_ABORT_UNLESS(svc::GetInfo(std::addressof(start), svc::InfoType_AliasRegionAddress, svc::PseudoHandle::CurrentProcess, 0));
|
||||||
R_ABORT_UNLESS(svc::GetInfo(std::addressof(size), svc::InfoType_AliasRegionSize, svc::PseudoHandle::CurrentProcess, 0));
|
R_ABORT_UNLESS(svc::GetInfo(std::addressof(size), svc::InfoType_AliasRegionSize, svc::PseudoHandle::CurrentProcess, 0));
|
||||||
|
R_ABORT_UNLESS(svc::GetInfo(std::addressof(extra_size), svc::InfoType_AliasRegionExtraSize, svc::PseudoHandle::CurrentProcess, 0));
|
||||||
*out_start = start;
|
*out_start = start;
|
||||||
*out_size = size;
|
*out_size = size - extra_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
static Result AllocatePhysicalMemoryImpl(uintptr_t address, size_t size) {
|
||||||
|
|
|
@ -190,6 +190,7 @@ namespace ams::svc {
|
||||||
InfoType_ThreadTickCount = 25,
|
InfoType_ThreadTickCount = 25,
|
||||||
InfoType_IsSvcPermitted = 26,
|
InfoType_IsSvcPermitted = 26,
|
||||||
InfoType_IoRegionHint = 27,
|
InfoType_IoRegionHint = 27,
|
||||||
|
InfoType_AliasRegionExtraSize = 28,
|
||||||
|
|
||||||
InfoType_MesosphereMeta = 65000,
|
InfoType_MesosphereMeta = 65000,
|
||||||
InfoType_MesosphereCurrentProcess = 65001,
|
InfoType_MesosphereCurrentProcess = 65001,
|
||||||
|
@ -436,6 +437,9 @@ namespace ams::svc {
|
||||||
/* 11.x+ DisableDeviceAddressSpaceMerge. */
|
/* 11.x+ DisableDeviceAddressSpaceMerge. */
|
||||||
CreateProcessFlag_DisableDeviceAddressSpaceMerge = (1 << 12),
|
CreateProcessFlag_DisableDeviceAddressSpaceMerge = (1 << 12),
|
||||||
|
|
||||||
|
/* 18.x EnableAliasRegionExtraSize. */
|
||||||
|
CreateProcessFlag_EnableAliasRegionExtraSize = (1 << 13),
|
||||||
|
|
||||||
/* Mask of all flags. */
|
/* Mask of all flags. */
|
||||||
CreateProcessFlag_All = CreateProcessFlag_Is64Bit |
|
CreateProcessFlag_All = CreateProcessFlag_Is64Bit |
|
||||||
CreateProcessFlag_AddressSpaceMask |
|
CreateProcessFlag_AddressSpaceMask |
|
||||||
|
@ -444,7 +448,8 @@ namespace ams::svc {
|
||||||
CreateProcessFlag_IsApplication |
|
CreateProcessFlag_IsApplication |
|
||||||
CreateProcessFlag_PoolPartitionMask |
|
CreateProcessFlag_PoolPartitionMask |
|
||||||
CreateProcessFlag_OptimizeMemoryAllocation |
|
CreateProcessFlag_OptimizeMemoryAllocation |
|
||||||
CreateProcessFlag_DisableDeviceAddressSpaceMerge,
|
CreateProcessFlag_DisableDeviceAddressSpaceMerge |
|
||||||
|
CreateProcessFlag_EnableAliasRegionExtraSize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Debug types. */
|
/* Debug types. */
|
||||||
|
|
|
@ -57,8 +57,8 @@ namespace ams::svc {
|
||||||
|
|
||||||
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
|
/* This is the highest SVC version supported by Atmosphere, to be updated on new kernel releases. */
|
||||||
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
|
/* NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor. */
|
||||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(17);
|
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(18);
|
||||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 5);
|
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 3);
|
||||||
|
|
||||||
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||||
|
|
||||||
|
|
|
@ -238,6 +238,7 @@ CATEGORIES = {
|
||||||
139 : 'EthernetAdapterOUIInfo',
|
139 : 'EthernetAdapterOUIInfo',
|
||||||
140 : 'NANDTypeInfo',
|
140 : 'NANDTypeInfo',
|
||||||
141 : 'MicroSDTypeInfo',
|
141 : 'MicroSDTypeInfo',
|
||||||
|
1000 : 'TestNx',
|
||||||
}
|
}
|
||||||
|
|
||||||
FIELD_TYPES = {
|
FIELD_TYPES = {
|
||||||
|
@ -408,6 +409,14 @@ def find_flags(full, num_fields, magic_idx):
|
||||||
ind = full.index(KNOWN) - magic_idx
|
ind = full.index(KNOWN) - magic_idx
|
||||||
return list(up('<'+'B'*num_fields, full[ind:ind+num_fields]))
|
return list(up('<'+'B'*num_fields, full[ind:ind+num_fields]))
|
||||||
|
|
||||||
|
def find_id_array(full, num_fields, magic_idx, table_format):
|
||||||
|
if table_format == 0:
|
||||||
|
return list(range(num_fields))
|
||||||
|
else:
|
||||||
|
KNOWN = pk('<IIIIII', *range(444, 450))
|
||||||
|
ind = full.index(KNOWN) - 4 * magic_idx
|
||||||
|
return list(up('<' + 'I'*num_fields, full[ind:ind+4*num_fields]))
|
||||||
|
|
||||||
def cat_to_string(c):
|
def cat_to_string(c):
|
||||||
return CATEGORIES[c] if c in CATEGORIES else 'Category_Unknown%d' % c
|
return CATEGORIES[c] if c in CATEGORIES else 'Category_Unknown%d' % c
|
||||||
|
|
||||||
|
@ -430,6 +439,8 @@ def main(argc, argv):
|
||||||
cats = find_categories(full, NUM_FIELDS)
|
cats = find_categories(full, NUM_FIELDS)
|
||||||
types = find_types(full, NUM_FIELDS)
|
types = find_types(full, NUM_FIELDS)
|
||||||
flags = find_flags(full, NUM_FIELDS, fields.index('TestStringEncrypt') - 1)
|
flags = find_flags(full, NUM_FIELDS, fields.index('TestStringEncrypt') - 1)
|
||||||
|
ids = find_id_array(full, NUM_FIELDS, fields.index('TestStringEncrypt'), table_format)
|
||||||
|
assert ids[:4] == [0, 1, 2, 3]
|
||||||
print 'Identified %d fields.' % NUM_FIELDS
|
print 'Identified %d fields.' % NUM_FIELDS
|
||||||
mf = max(len(s) for s in fields)
|
mf = max(len(s) for s in fields)
|
||||||
mc = max(len(cat_to_string(c)) for c in cats)
|
mc = max(len(cat_to_string(c)) for c in cats)
|
||||||
|
@ -453,8 +464,8 @@ def main(argc, argv):
|
||||||
out.write('\n')
|
out.write('\n')
|
||||||
out.write('#define AMS_ERPT_FOREACH_FIELD(HANDLER) \\\n')
|
out.write('#define AMS_ERPT_FOREACH_FIELD(HANDLER) \\\n')
|
||||||
for i in xrange(NUM_FIELDS):
|
for i in xrange(NUM_FIELDS):
|
||||||
f, c, t, l = fields[i], cats[i], types[i], flags[i]
|
f, c, t, l, d = fields[i], cats[i], types[i], flags[i], ids[i]
|
||||||
out.write((' HANDLER(%%-%ds %%-4s %%-%ds %%-%ds %%-%ds) \\\n' % (mf+1, mc+1, mt+1, ml)) % (f+',', '%d,'%i, cat_to_string(c)+',', typ_to_string(t)+',', flg_to_string(l)))
|
out.write((' HANDLER(%%-%ds %%-4s %%-%ds %%-%ds %%-%ds) \\\n' % (mf+1, mc+1, mt+1, ml)) % (f+',', '%d,'%d, cat_to_string(c)+',', typ_to_string(t)+',', flg_to_string(l)))
|
||||||
out.write('\n')
|
out.write('\n')
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue