mirror of
https://github.com/Atmosphere-NX/Atmosphere-libs.git
synced 2025-07-04 08:32:15 +02:00
Compare commits
32 Commits
c3dc418a28
...
132558c338
Author | SHA1 | Date | |
---|---|---|---|
|
132558c338 | ||
|
5d5699a7e8 | ||
|
338d7ce940 | ||
|
77ae1814ff | ||
|
054eeddc0c | ||
|
ee56715f3f | ||
|
c9a576e990 | ||
|
38cc50294b | ||
|
5c8a8adc9a | ||
|
2c77b3e1e3 | ||
|
a2cdc8626d | ||
|
224be3e9f1 | ||
|
d211eb4de7 | ||
|
a55dbf0819 | ||
|
d213377313 | ||
|
e07b0a924d | ||
|
6dcf506423 | ||
|
7ac90cdb0d | ||
|
dfbd37e448 | ||
|
9d485e7df9 | ||
|
9f51df06d5 | ||
|
41eea11a19 | ||
|
15ca0c1b10 | ||
|
d4319842a9 | ||
|
c8f04e21e5 | ||
|
2c2aa8b57c | ||
|
a6e34647de | ||
|
8d84b5776f | ||
|
d21f281094 | ||
|
3abc567a73 | ||
|
ba1a07db68 | ||
|
540ca1351a |
@ -36,6 +36,7 @@ namespace ams::pkg1 {
|
|||||||
KeyGeneration_14_0_0 = 0x0D,
|
KeyGeneration_14_0_0 = 0x0D,
|
||||||
KeyGeneration_15_0_0 = 0x0E,
|
KeyGeneration_15_0_0 = 0x0E,
|
||||||
KeyGeneration_16_0_0 = 0x0F,
|
KeyGeneration_16_0_0 = 0x0F,
|
||||||
|
KeyGeneration_17_0_0 = 0x10,
|
||||||
|
|
||||||
KeyGeneration_Count,
|
KeyGeneration_Count,
|
||||||
|
|
||||||
|
@ -23,8 +23,8 @@ namespace ams::pkg2 {
|
|||||||
|
|
||||||
constexpr inline int PayloadCount = 3;
|
constexpr inline int PayloadCount = 3;
|
||||||
|
|
||||||
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x17 in Nintendo's code. */
|
constexpr inline int MinimumValidDataVersion = 0; /* We allow older package2 to load; this value is currently 0x18 in Nintendo's code. */
|
||||||
constexpr inline int CurrentBootloaderVersion = 0x13;
|
constexpr inline int CurrentBootloaderVersion = 0x14;
|
||||||
|
|
||||||
struct Package2Meta {
|
struct Package2Meta {
|
||||||
using Magic = util::FourCC<'P','K','2','1'>;
|
using Magic = util::FourCC<'P','K','2','1'>;
|
||||||
|
@ -177,6 +177,7 @@ namespace ams::fuse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
constexpr const TargetFirmware FuseVersionIncrementFirmwares[] = {
|
||||||
|
TargetFirmware_17_0_0,
|
||||||
TargetFirmware_16_0_0,
|
TargetFirmware_16_0_0,
|
||||||
TargetFirmware_15_0_0,
|
TargetFirmware_15_0_0,
|
||||||
TargetFirmware_13_2_1,
|
TargetFirmware_13_2_1,
|
||||||
|
@ -19,13 +19,8 @@
|
|||||||
namespace ams::kern::init {
|
namespace ams::kern::init {
|
||||||
|
|
||||||
struct alignas(util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)) KInitArguments {
|
struct alignas(util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)) KInitArguments {
|
||||||
u64 ttbr0;
|
|
||||||
u64 ttbr1;
|
|
||||||
u64 tcr;
|
|
||||||
u64 mair;
|
|
||||||
u64 cpuactlr;
|
u64 cpuactlr;
|
||||||
u64 cpuectlr;
|
u64 cpuectlr;
|
||||||
u64 sctlr;
|
|
||||||
u64 sp;
|
u64 sp;
|
||||||
u64 entrypoint;
|
u64 entrypoint;
|
||||||
u64 argument;
|
u64 argument;
|
||||||
@ -33,13 +28,8 @@ namespace ams::kern::init {
|
|||||||
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
static_assert(alignof(KInitArguments) == util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE));
|
||||||
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
static_assert(sizeof(KInitArguments) == std::max(INIT_ARGUMENTS_SIZE, util::CeilingPowerOfTwo(INIT_ARGUMENTS_SIZE)));
|
||||||
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, ttbr0) == INIT_ARGUMENTS_TTBR0);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, ttbr1) == INIT_ARGUMENTS_TTBR1);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, tcr) == INIT_ARGUMENTS_TCR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, mair) == INIT_ARGUMENTS_MAIR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
|
static_assert(AMS_OFFSETOF(KInitArguments, cpuactlr) == INIT_ARGUMENTS_CPUACTLR);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
|
static_assert(AMS_OFFSETOF(KInitArguments, cpuectlr) == INIT_ARGUMENTS_CPUECTLR);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, sctlr) == INIT_ARGUMENTS_SCTLR);
|
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
static_assert(AMS_OFFSETOF(KInitArguments, sp) == INIT_ARGUMENTS_SP);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
static_assert(AMS_OFFSETOF(KInitArguments, entrypoint) == INIT_ARGUMENTS_ENTRYPOINT);
|
||||||
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
static_assert(AMS_OFFSETOF(KInitArguments, argument) == INIT_ARGUMENTS_ARGUMENT);
|
||||||
|
@ -87,9 +87,8 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
|
|
||||||
template<IsInitialPageAllocator PageAllocator>
|
template<IsInitialPageAllocator PageAllocator>
|
||||||
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) {
|
static ALWAYS_INLINE KPhysicalAddress AllocateNewPageTable(PageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||||
auto address = allocator.Allocate(PageSize);
|
MESOSPHERE_UNUSED(phys_to_virt_offset);
|
||||||
ClearNewPageTable(address, phys_to_virt_offset);
|
return allocator.Allocate(PageSize);
|
||||||
return address;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) {
|
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address, u64 phys_to_virt_offset) {
|
||||||
@ -883,6 +882,12 @@ namespace ams::kern::arch::arm64::init {
|
|||||||
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
|
const size_t ind_max = ((aligned_end - aligned_start) / align) - 1;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
|
if (const uintptr_t random_address = aligned_start + (KSystemControl::Init::GenerateRandomRange(0, ind_max) * align); this->TryAllocate(random_address, size)) {
|
||||||
|
/* Clear the allocated pages. */
|
||||||
|
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(random_address);
|
||||||
|
for (size_t i = 0; i < size / sizeof(u64); ++i) {
|
||||||
|
ptr[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return random_address;
|
return random_address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,3 +94,8 @@ label_done:
|
|||||||
ENABLE_FPU(xtmp1) \
|
ENABLE_FPU(xtmp1) \
|
||||||
GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \
|
GET_THREAD_CONTEXT_AND_RESTORE_FPCR_FPSR(ctx, xtmp1, xtmp2, wtmp1, wtmp2) \
|
||||||
RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1)
|
RESTORE_FPU32_ALL_REGISTERS(ctx, xtmp1)
|
||||||
|
|
||||||
|
#define ERET_WITH_SPECULATION_BARRIER \
|
||||||
|
eret; \
|
||||||
|
dsb nsh; \
|
||||||
|
isb
|
||||||
|
@ -246,17 +246,12 @@
|
|||||||
#define THREAD_LOCAL_REGION_SIZE 0x200
|
#define THREAD_LOCAL_REGION_SIZE 0x200
|
||||||
|
|
||||||
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
|
/* ams::kern::init::KInitArguments, https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/arch/arm64/init/kern_k_init_arguments.hpp */
|
||||||
#define INIT_ARGUMENTS_SIZE 0x50
|
#define INIT_ARGUMENTS_SIZE 0x28
|
||||||
#define INIT_ARGUMENTS_TTBR0 0x00
|
#define INIT_ARGUMENTS_CPUACTLR 0x00
|
||||||
#define INIT_ARGUMENTS_TTBR1 0x08
|
#define INIT_ARGUMENTS_CPUECTLR 0x08
|
||||||
#define INIT_ARGUMENTS_TCR 0x10
|
#define INIT_ARGUMENTS_SP 0x10
|
||||||
#define INIT_ARGUMENTS_MAIR 0x18
|
#define INIT_ARGUMENTS_ENTRYPOINT 0x18
|
||||||
#define INIT_ARGUMENTS_CPUACTLR 0x20
|
#define INIT_ARGUMENTS_ARGUMENT 0x20
|
||||||
#define INIT_ARGUMENTS_CPUECTLR 0x28
|
|
||||||
#define INIT_ARGUMENTS_SCTLR 0x30
|
|
||||||
#define INIT_ARGUMENTS_SP 0x38
|
|
||||||
#define INIT_ARGUMENTS_ENTRYPOINT 0x40
|
|
||||||
#define INIT_ARGUMENTS_ARGUMENT 0x48
|
|
||||||
|
|
||||||
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
|
/* ams::kern::KScheduler (::SchedulingState), https://github.com/Atmosphere-NX/Atmosphere/blob/master/libraries/libmesosphere/include/mesosphere/kern_k_scheduler.hpp */
|
||||||
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
|
/* NOTE: Due to constraints on ldarb relative offsets, KSCHEDULER_NEEDS_SCHEDULING cannot trivially be changed, and will require assembly edits. */
|
||||||
|
@ -372,6 +372,10 @@ namespace ams::kern::arch::arm64::cpu {
|
|||||||
this->SetBit(19, en);
|
this->SetBit(19, en);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE bool GetWxn() const {
|
||||||
|
return this->GetBits(19, 1) != 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Accessors for timer registers. */
|
/* Accessors for timer registers. */
|
||||||
|
@ -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(u32 id, 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 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 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);
|
||||||
@ -208,8 +208,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll);
|
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||||
Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
Result MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll);
|
||||||
|
|
||||||
bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list);
|
bool MergePages(KProcessAddress virt_addr, PageLinkedList *page_list);
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
m_page_table.Activate(id);
|
m_page_table.Activate(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Initialize(u32 id, 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 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) {
|
||||||
R_RETURN(m_page_table.InitializeForProcess(id, as_type, enable_aslr, enable_das_merge, from_back, pool, code_address, code_size, system_resource, 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() { m_page_table.Finalize(); }
|
void Finalize() { m_page_table.Finalize(); }
|
||||||
@ -150,20 +150,24 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_RETURN(m_page_table.InvalidateProcessDataCache(address, size));
|
R_RETURN(m_page_table.InvalidateProcessDataCache(address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) {
|
||||||
|
R_RETURN(m_page_table.InvalidateCurrentProcessDataCache(address, size));
|
||||||
|
}
|
||||||
|
|
||||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||||
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size));
|
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) {
|
||||||
R_RETURN(m_page_table.ReadDebugIoMemory(buffer, address, size));
|
R_RETURN(m_page_table.ReadDebugIoMemory(buffer, address, size, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
|
||||||
R_RETURN(m_page_table.WriteDebugMemory(address, buffer, size));
|
R_RETURN(m_page_table.WriteDebugMemory(address, buffer, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state) {
|
||||||
R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size));
|
R_RETURN(m_page_table.WriteDebugIoMemory(address, buffer, size, state));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap) {
|
||||||
@ -296,6 +300,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInUnsafeAliasRegion(addr, size); }
|
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return m_page_table.IsInUnsafeAliasRegion(addr, size); }
|
||||||
|
|
||||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
||||||
|
bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const { return m_page_table.CanContain(addr, size, state); }
|
||||||
|
|
||||||
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
|
KProcessAddress GetAddressSpaceStart() const { return m_page_table.GetAddressSpaceStart(); }
|
||||||
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
|
KProcessAddress GetHeapRegionStart() const { return m_page_table.GetHeapRegionStart(); }
|
||||||
|
@ -23,9 +23,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
class KSupervisorPageTable {
|
class KSupervisorPageTable {
|
||||||
private:
|
private:
|
||||||
KPageTable m_page_table;
|
KPageTable m_page_table;
|
||||||
u64 m_ttbr0_identity[cpu::NumCores];
|
|
||||||
public:
|
public:
|
||||||
constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize), m_ttbr0_identity() { /* ... */ }
|
constexpr KSupervisorPageTable() : m_page_table(util::ConstantInitialize) { /* ... */ }
|
||||||
|
|
||||||
NOINLINE void Initialize(s32 core_id);
|
NOINLINE void Initialize(s32 core_id);
|
||||||
|
|
||||||
@ -61,8 +60,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
return m_page_table.GetPhysicalAddress(out, address);
|
return m_page_table.GetPhysicalAddress(out, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return m_ttbr0_identity[core_id]; }
|
|
||||||
|
|
||||||
void DumpMemoryBlocks() const {
|
void DumpMemoryBlocks() const {
|
||||||
return m_page_table.DumpMemoryBlocks();
|
return m_page_table.DumpMemoryBlocks();
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,23 @@ namespace ams::kern::init::Elf::Elf64 {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Relr {
|
||||||
|
private:
|
||||||
|
Xword m_info;
|
||||||
|
public:
|
||||||
|
constexpr ALWAYS_INLINE bool IsLocation() const {
|
||||||
|
return (m_info & 1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetLocation() const {
|
||||||
|
return m_info;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr ALWAYS_INLINE Xword GetBitmap() const {
|
||||||
|
return m_info >> 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
enum DynamicTag {
|
enum DynamicTag {
|
||||||
DT_NULL = 0,
|
DT_NULL = 0,
|
||||||
DT_RELA = 7,
|
DT_RELA = 7,
|
||||||
@ -121,6 +138,10 @@ namespace ams::kern::init::Elf::Elf64 {
|
|||||||
DT_REL = 17,
|
DT_REL = 17,
|
||||||
DT_RELENT = 19,
|
DT_RELENT = 19,
|
||||||
|
|
||||||
|
DT_RELRSZ = 35,
|
||||||
|
DT_RELR = 36,
|
||||||
|
DT_RELRENT = 37,
|
||||||
|
|
||||||
DT_RELACOUNT = 0x6ffffff9,
|
DT_RELACOUNT = 0x6ffffff9,
|
||||||
DT_RELCOUNT = 0x6ffffffa
|
DT_RELCOUNT = 0x6ffffffa
|
||||||
};
|
};
|
||||||
|
@ -31,8 +31,22 @@ namespace ams::kern::init {
|
|||||||
u32 dynamic_offset;
|
u32 dynamic_offset;
|
||||||
u32 init_array_offset;
|
u32 init_array_offset;
|
||||||
u32 init_array_end_offset;
|
u32 init_array_end_offset;
|
||||||
|
u32 sysreg_offset;
|
||||||
};
|
};
|
||||||
static_assert(util::is_pod<KernelLayout>::value);
|
static_assert(util::is_pod<KernelLayout>::value);
|
||||||
static_assert(sizeof(KernelLayout) == 0x30);
|
static_assert(sizeof(KernelLayout) == 0x34);
|
||||||
|
|
||||||
|
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||||
|
struct KernelSystemRegisters {
|
||||||
|
u64 ttbr0_el1;
|
||||||
|
u64 ttbr1_el1;
|
||||||
|
u64 tcr_el1;
|
||||||
|
u64 mair_el1;
|
||||||
|
u64 sctlr_el1;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
struct KernelSystemRegisters {
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
@ -34,8 +34,14 @@ namespace ams::kern {
|
|||||||
uintptr_t _08;
|
uintptr_t _08;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct InitialProcessBinaryLayoutWithSize {
|
||||||
|
InitialProcessBinaryLayout layout;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
|
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress();
|
||||||
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr);
|
size_t GetInitialProcessBinarySize();
|
||||||
|
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size);
|
||||||
|
|
||||||
u64 GetInitialProcessIdMin();
|
u64 GetInitialProcessIdMin();
|
||||||
u64 GetInitialProcessIdMax();
|
u64 GetInitialProcessIdMax();
|
||||||
|
@ -133,7 +133,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const;
|
Result MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const;
|
||||||
Result Load(KProcessAddress address, const ams::svc::CreateProcessParameter ¶ms, KProcessAddress src) const;
|
void Load(const KPageGroup &pg, KVirtualAddress data) const;
|
||||||
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ namespace ams::kern {
|
|||||||
KMemoryState_FlagCanChangeAttribute = (1 << 24),
|
KMemoryState_FlagCanChangeAttribute = (1 << 24),
|
||||||
KMemoryState_FlagCanCodeMemory = (1 << 25),
|
KMemoryState_FlagCanCodeMemory = (1 << 25),
|
||||||
KMemoryState_FlagLinearMapped = (1 << 26),
|
KMemoryState_FlagLinearMapped = (1 << 26),
|
||||||
|
KMemoryState_FlagCanPermissionLock = (1 << 27),
|
||||||
|
|
||||||
KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc |
|
KMemoryState_FlagsData = KMemoryState_FlagCanReprotect | KMemoryState_FlagCanUseIpc |
|
||||||
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
KMemoryState_FlagCanUseNonDeviceIpc | KMemoryState_FlagCanUseNonSecureIpc |
|
||||||
@ -66,18 +67,22 @@ namespace ams::kern {
|
|||||||
|
|
||||||
|
|
||||||
KMemoryState_Free = ams::svc::MemoryState_Free,
|
KMemoryState_Free = ams::svc::MemoryState_Free,
|
||||||
KMemoryState_Io = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
|
||||||
KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagMapped | KMemoryState_FlagCanQueryPhysical,
|
KMemoryState_IoMemory = ams::svc::MemoryState_Io | KMemoryState_FlagMapped | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
||||||
|
KMemoryState_IoRegister = ams::svc::MemoryState_Io | KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap,
|
||||||
|
|
||||||
|
|
||||||
|
KMemoryState_Static = ams::svc::MemoryState_Static | KMemoryState_FlagCanQueryPhysical,
|
||||||
KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess,
|
KMemoryState_Code = ams::svc::MemoryState_Code | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess,
|
||||||
KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_CodeData = ams::svc::MemoryState_CodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeMemory | KMemoryState_FlagCanPermissionLock,
|
||||||
KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_Normal = ams::svc::MemoryState_Normal | KMemoryState_FlagsData | KMemoryState_FlagCanCodeMemory,
|
||||||
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
KMemoryState_Shared = ams::svc::MemoryState_Shared | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||||
|
|
||||||
/* KMemoryState_Alias was removed after 1.0.0. */
|
/* KMemoryState_Alias was removed after 1.0.0. */
|
||||||
|
|
||||||
KMemoryState_AliasCode = ams::svc::MemoryState_AliasCode | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias,
|
KMemoryState_AliasCode = ams::svc::MemoryState_AliasCode | KMemoryState_FlagsCode | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias,
|
||||||
KMemoryState_AliasCodeData = ams::svc::MemoryState_AliasCodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias | KMemoryState_FlagCanCodeMemory,
|
KMemoryState_AliasCodeData = ams::svc::MemoryState_AliasCodeData | KMemoryState_FlagsData | KMemoryState_FlagCanMapProcess | KMemoryState_FlagCanCodeAlias | KMemoryState_FlagCanCodeMemory
|
||||||
|
| KMemoryState_FlagCanPermissionLock,
|
||||||
|
|
||||||
KMemoryState_Ipc = ams::svc::MemoryState_Ipc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
KMemoryState_Ipc = ams::svc::MemoryState_Ipc | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
@ -85,7 +90,7 @@ namespace ams::kern {
|
|||||||
KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
KMemoryState_Stack = ams::svc::MemoryState_Stack | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagMapped | KMemoryState_FlagLinearMapped,
|
KMemoryState_ThreadLocal = ams::svc::MemoryState_ThreadLocal | KMemoryState_FlagLinearMapped,
|
||||||
|
|
||||||
KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute
|
KMemoryState_Transfered = ams::svc::MemoryState_Transfered | KMemoryState_FlagsMisc | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanChangeAttribute
|
||||||
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseIpc | KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
@ -104,7 +109,7 @@ namespace ams::kern {
|
|||||||
KMemoryState_NonDeviceIpc = ams::svc::MemoryState_NonDeviceIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanUseNonDeviceIpc,
|
KMemoryState_NonDeviceIpc = ams::svc::MemoryState_NonDeviceIpc | KMemoryState_FlagsMisc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
|
|
||||||
|
|
||||||
KMemoryState_Kernel = ams::svc::MemoryState_Kernel | KMemoryState_FlagMapped,
|
KMemoryState_Kernel = ams::svc::MemoryState_Kernel,
|
||||||
|
|
||||||
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped,
|
KMemoryState_GeneratedCode = ams::svc::MemoryState_GeneratedCode | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagCanDebug | KMemoryState_FlagLinearMapped,
|
||||||
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
KMemoryState_CodeOut = ams::svc::MemoryState_CodeOut | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped,
|
||||||
@ -112,35 +117,36 @@ namespace ams::kern {
|
|||||||
KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped,
|
KMemoryState_Coverage = ams::svc::MemoryState_Coverage | KMemoryState_FlagMapped,
|
||||||
|
|
||||||
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
KMemoryState_Insecure = ams::svc::MemoryState_Insecure | KMemoryState_FlagMapped | KMemoryState_FlagReferenceCounted | KMemoryState_FlagLinearMapped | KMemoryState_FlagCanChangeAttribute
|
||||||
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap
|
| KMemoryState_FlagCanDeviceMap | KMemoryState_FlagCanAlignedDeviceMap | KMemoryState_FlagCanQueryPhysical
|
||||||
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
| KMemoryState_FlagCanUseNonSecureIpc | KMemoryState_FlagCanUseNonDeviceIpc,
|
||||||
};
|
};
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
static_assert(KMemoryState_Free == 0x00000000);
|
static_assert(KMemoryState_Free == 0x00000000);
|
||||||
static_assert(KMemoryState_Io == 0x00182001);
|
static_assert(KMemoryState_IoMemory == 0x00182001);
|
||||||
static_assert(KMemoryState_Static == 0x00042002);
|
static_assert(KMemoryState_IoRegister == 0x00180001);
|
||||||
|
static_assert(KMemoryState_Static == 0x00040002);
|
||||||
static_assert(KMemoryState_Code == 0x04DC7E03);
|
static_assert(KMemoryState_Code == 0x04DC7E03);
|
||||||
static_assert(KMemoryState_CodeData == 0x07FEBD04);
|
static_assert(KMemoryState_CodeData == 0x0FFEBD04);
|
||||||
static_assert(KMemoryState_Normal == 0x077EBD05);
|
static_assert(KMemoryState_Normal == 0x077EBD05);
|
||||||
static_assert(KMemoryState_Shared == 0x04402006);
|
static_assert(KMemoryState_Shared == 0x04402006);
|
||||||
|
|
||||||
static_assert(KMemoryState_AliasCode == 0x04DD7E08);
|
static_assert(KMemoryState_AliasCode == 0x04DD7E08);
|
||||||
static_assert(KMemoryState_AliasCodeData == 0x07FFBD09);
|
static_assert(KMemoryState_AliasCodeData == 0x0FFFBD09);
|
||||||
static_assert(KMemoryState_Ipc == 0x045C3C0A);
|
static_assert(KMemoryState_Ipc == 0x045C3C0A);
|
||||||
static_assert(KMemoryState_Stack == 0x045C3C0B);
|
static_assert(KMemoryState_Stack == 0x045C3C0B);
|
||||||
static_assert(KMemoryState_ThreadLocal == 0x0400200C);
|
static_assert(KMemoryState_ThreadLocal == 0x0400000C);
|
||||||
static_assert(KMemoryState_Transfered == 0x055C3C0D);
|
static_assert(KMemoryState_Transfered == 0x055C3C0D);
|
||||||
static_assert(KMemoryState_SharedTransfered == 0x045C380E);
|
static_assert(KMemoryState_SharedTransfered == 0x045C380E);
|
||||||
static_assert(KMemoryState_SharedCode == 0x0440380F);
|
static_assert(KMemoryState_SharedCode == 0x0440380F);
|
||||||
static_assert(KMemoryState_Inaccessible == 0x00000010);
|
static_assert(KMemoryState_Inaccessible == 0x00000010);
|
||||||
static_assert(KMemoryState_NonSecureIpc == 0x045C3811);
|
static_assert(KMemoryState_NonSecureIpc == 0x045C3811);
|
||||||
static_assert(KMemoryState_NonDeviceIpc == 0x044C2812);
|
static_assert(KMemoryState_NonDeviceIpc == 0x044C2812);
|
||||||
static_assert(KMemoryState_Kernel == 0x00002013);
|
static_assert(KMemoryState_Kernel == 0x00000013);
|
||||||
static_assert(KMemoryState_GeneratedCode == 0x04402214);
|
static_assert(KMemoryState_GeneratedCode == 0x04402214);
|
||||||
static_assert(KMemoryState_CodeOut == 0x04402015);
|
static_assert(KMemoryState_CodeOut == 0x04402015);
|
||||||
static_assert(KMemoryState_Coverage == 0x00002016);
|
static_assert(KMemoryState_Coverage == 0x00002016); /* TODO: Is this correct? */
|
||||||
static_assert(KMemoryState_Insecure == 0x05583817);
|
static_assert(KMemoryState_Insecure == 0x055C3817);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum KMemoryPermission : u8 {
|
enum KMemoryPermission : u8 {
|
||||||
@ -183,8 +189,9 @@ namespace ams::kern {
|
|||||||
KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked,
|
KMemoryAttribute_IpcLocked = ams::svc::MemoryAttribute_IpcLocked,
|
||||||
KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared,
|
KMemoryAttribute_DeviceShared = ams::svc::MemoryAttribute_DeviceShared,
|
||||||
KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached,
|
KMemoryAttribute_Uncached = ams::svc::MemoryAttribute_Uncached,
|
||||||
|
KMemoryAttribute_PermissionLocked = ams::svc::MemoryAttribute_PermissionLocked,
|
||||||
|
|
||||||
KMemoryAttribute_SetMask = KMemoryAttribute_Uncached,
|
KMemoryAttribute_SetMask = KMemoryAttribute_Uncached | KMemoryAttribute_PermissionLocked,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum KMemoryBlockDisableMergeAttribute : u8 {
|
enum KMemoryBlockDisableMergeAttribute : u8 {
|
||||||
@ -258,6 +265,10 @@ namespace ams::kern {
|
|||||||
return m_state;
|
return m_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr ams::svc::MemoryState GetSvcState() const {
|
||||||
|
return static_cast<ams::svc::MemoryState>(m_state & KMemoryState_Mask);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr KMemoryPermission GetPermission() const {
|
constexpr KMemoryPermission GetPermission() const {
|
||||||
return m_permission;
|
return m_permission;
|
||||||
}
|
}
|
||||||
@ -320,6 +331,10 @@ namespace ams::kern {
|
|||||||
return this->GetEndAddress() - 1;
|
return this->GetEndAddress() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr KMemoryState GetState() const {
|
||||||
|
return m_memory_state;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr u16 GetIpcLockCount() const {
|
constexpr u16 GetIpcLockCount() const {
|
||||||
return m_ipc_lock_count;
|
return m_ipc_lock_count;
|
||||||
}
|
}
|
||||||
@ -439,6 +454,14 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr void UpdateAttribute(u32 mask, u32 attr) {
|
||||||
|
MESOSPHERE_ASSERT_THIS();
|
||||||
|
MESOSPHERE_ASSERT((mask & KMemoryAttribute_IpcLocked) == 0);
|
||||||
|
MESOSPHERE_ASSERT((mask & KMemoryAttribute_DeviceShared) == 0);
|
||||||
|
|
||||||
|
m_attribute = static_cast<KMemoryAttribute>((m_attribute & ~mask) | attr);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr void Split(KMemoryBlock *block, KProcessAddress addr) {
|
constexpr void Split(KMemoryBlock *block, KProcessAddress addr) {
|
||||||
MESOSPHERE_ASSERT_THIS();
|
MESOSPHERE_ASSERT_THIS();
|
||||||
MESOSPHERE_ASSERT(this->GetAddress() < addr);
|
MESOSPHERE_ASSERT(this->GetAddress() < addr);
|
||||||
|
@ -104,7 +104,9 @@ namespace ams::kern {
|
|||||||
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
void Update(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
||||||
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
|
void UpdateLock(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, MemoryBlockLockFunction lock_func, KMemoryPermission perm);
|
||||||
|
|
||||||
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr);
|
void UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr);
|
||||||
|
|
||||||
|
void UpdateAttribute(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, u32 mask, u32 attr);
|
||||||
|
|
||||||
iterator FindIterator(KProcessAddress address) const {
|
iterator FindIterator(KProcessAddress address) const {
|
||||||
return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
|
return m_memory_block_tree.find(KMemoryBlock(util::ConstantInitialize, address, 1, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None));
|
||||||
|
@ -212,7 +212,9 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() == (0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
constexpr inline const auto KMemoryRegionType_DramKernelSecureAppletMemory = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
||||||
|
constexpr inline const auto KMemoryRegionType_DramKernelSecureUnknown = KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 1).SetAttribute(KMemoryRegionAttr_LinearMapped);
|
||||||
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() == (0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
static_assert(KMemoryRegionType_DramKernelSecureUnknown.GetValue() == (0x28E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_LinearMapped));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
constexpr inline const auto KMemoryRegionType_DramReservedEarly = KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||||
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() == (0x16 | KMemoryRegionAttr_NoUserMap));
|
||||||
@ -228,53 +230,55 @@ namespace ams::kern {
|
|||||||
constexpr inline const auto KMemoryRegionType_DramPoolPartition = KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
constexpr inline const auto KMemoryRegionType_DramPoolPartition = KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
|
||||||
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramPoolManagement = KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
constexpr inline const auto KMemoryRegionType_DramPoolManagement = KMemoryRegionType_DramPoolPartition.Derive(4, 0).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
||||||
constexpr inline const auto KMemoryRegionType_DramUserPool = KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
|
/* UNUSED: .Derive(4, 1); */
|
||||||
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == (0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
/* UNUSED: .Derive(4, 2); */
|
||||||
static_assert(KMemoryRegionType_DramUserPool.GetValue() == (0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
constexpr inline const auto KMemoryRegionType_DramUserPool = KMemoryRegionType_DramPoolPartition.Derive(4, 3);
|
||||||
|
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() == (0xE6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
||||||
|
static_assert(KMemoryRegionType_DramUserPool .GetValue() == (0x266 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
|
constexpr inline const auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
|
constexpr inline const auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_DramSystemNonSecurePool = KMemoryRegionType_DramUserPool.Derive(4, 2);
|
constexpr inline const auto KMemoryRegionType_DramSystemNonSecurePool = KMemoryRegionType_DramUserPool.Derive(4, 2);
|
||||||
constexpr inline const auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
constexpr inline const auto KMemoryRegionType_DramSystemPool = KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
|
||||||
static_assert(KMemoryRegionType_DramApplicationPool .GetValue() == (0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramApplicationPool .GetValue() == (0xE66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramAppletPool .GetValue() == (0xBA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramAppletPool .GetValue() == (0x1666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == (0xDA6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
static_assert(KMemoryRegionType_DramSystemNonSecurePool.GetValue() == (0x1A66 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
|
||||||
static_assert(KMemoryRegionType_DramSystemPool .GetValue() == (0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
static_assert(KMemoryRegionType_DramSystemPool .GetValue() == (0x2666 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap | KMemoryRegionAttr_CarveoutProtected));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
|
constexpr inline const auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelPtHeap = KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelPtHeap = KMemoryRegionType_Dram.DeriveSparse(1, 4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelTraceBuffer = KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelTraceBuffer = KMemoryRegionType_Dram.DeriveSparse(1, 4, 2);
|
||||||
static_assert(KMemoryRegionType_VirtualDramHeapBase .GetValue() == 0x1A);
|
static_assert(KMemoryRegionType_VirtualDramHeapBase .GetValue() == 0x1A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A);
|
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap .GetValue() == 0x2A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
|
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
|
||||||
|
|
||||||
/* UNUSED: .DeriveSparse(2, 2, 0); */
|
/* UNUSED: .DeriveSparse(2, 2, 0); */
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramUnknownDebug = KMemoryRegionType_Dram.Advance(2).Derive(4, 0);
|
||||||
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.Advance(2).Derive(4, 1);
|
||||||
|
/* UNUSED: .Derive(4, 2); */
|
||||||
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureUnknown = KMemoryRegionType_Dram.Advance(2).Derive(4, 3);
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramUnknownDebug .GetValue() == (0x32));
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x52));
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramKernelSecureUnknown .GetValue() == (0x92));
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory = KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
|
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
|
constexpr inline const auto KMemoryRegionType_VirtualDramKernelInitPt = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 0);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
|
constexpr inline const auto KMemoryRegionType_VirtualDramPoolManagement = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 1);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
|
constexpr inline const auto KMemoryRegionType_VirtualDramUserPool = KMemoryRegionType_VirtualDramHeapBase.Derive(4, 2);
|
||||||
static_assert(KMemoryRegionType_VirtualDramKernelInitPt .GetValue() == 0x19A);
|
/* UNUSED: .Derive(4, 3); */
|
||||||
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
|
static_assert(KMemoryRegionType_VirtualDramKernelInitPt .GetValue() == 0x31A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramUserPool .GetValue() == 0x31A);
|
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x51A);
|
||||||
|
static_assert(KMemoryRegionType_VirtualDramUserPool .GetValue() == 0x61A);
|
||||||
|
|
||||||
/* NOTE: For unknown reason, the pools are derived out-of-order here. */
|
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 0);
|
||||||
/* It's worth eventually trying to understand why Nintendo made this choice. */
|
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 1);
|
||||||
/* UNUSED: .Derive(6, 0); */
|
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 2);
|
||||||
/* UNUSED: .Derive(6, 1); */
|
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = KMemoryRegionType_VirtualDramUserPool.Derive(4, 3);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramAppletPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
|
static_assert(KMemoryRegionType_VirtualDramApplicationPool .GetValue() == 0x361A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramApplicationPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
|
static_assert(KMemoryRegionType_VirtualDramAppletPool .GetValue() == 0x561A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemNonSecurePool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
|
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x661A);
|
||||||
constexpr inline const auto KMemoryRegionType_VirtualDramSystemPool = KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
|
static_assert(KMemoryRegionType_VirtualDramSystemPool .GetValue() == 0x961A);
|
||||||
static_assert(KMemoryRegionType_VirtualDramAppletPool .GetValue() == 0x1B1A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramApplicationPool .GetValue() == 0x271A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
|
|
||||||
static_assert(KMemoryRegionType_VirtualDramSystemPool .GetValue() == 0x331A);
|
|
||||||
|
|
||||||
constexpr inline const auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
|
constexpr inline const auto KMemoryRegionType_ArchDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
|
||||||
constexpr inline const auto KMemoryRegionType_BoardDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
|
constexpr inline const auto KMemoryRegionType_BoardDeviceBase = KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
|
||||||
@ -328,12 +332,14 @@ namespace ams::kern {
|
|||||||
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
|
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
|
constexpr ALWAYS_INLINE KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
|
||||||
if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
||||||
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
|
||||||
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
|
|
||||||
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
return KMemoryRegionType_VirtualDramKernelPtHeap;
|
||||||
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
|
||||||
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
|
||||||
|
} else if (KMemoryRegionType_DramKernelSecureUnknown.IsAncestorOf(type_id)) {
|
||||||
|
return KMemoryRegionType_VirtualDramKernelSecureUnknown;
|
||||||
|
} else if (KMemoryRegionType_KernelTraceBuffer.IsAncestorOf(type_id)) {
|
||||||
|
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
|
||||||
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
|
||||||
return KMemoryRegionType_VirtualDramUnknownDebug;
|
return KMemoryRegionType_VirtualDramUnknownDebug;
|
||||||
} else {
|
} else {
|
||||||
|
@ -158,8 +158,16 @@ namespace ams::kern {
|
|||||||
private:
|
private:
|
||||||
const KPageGroup *m_pg;
|
const KPageGroup *m_pg;
|
||||||
public:
|
public:
|
||||||
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp) : m_pg(gp) { if (m_pg) { m_pg->Open(); } }
|
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup *gp, bool not_first = true) : m_pg(gp) {
|
||||||
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp) : KScopedPageGroup(std::addressof(gp)) { /* ... */ }
|
if (m_pg) {
|
||||||
|
if (not_first) {
|
||||||
|
m_pg->Open();
|
||||||
|
} else {
|
||||||
|
m_pg->OpenFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
explicit ALWAYS_INLINE KScopedPageGroup(const KPageGroup &gp, bool not_first = true) : KScopedPageGroup(std::addressof(gp), not_first) { /* ... */ }
|
||||||
ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } }
|
ALWAYS_INLINE ~KScopedPageGroup() { if (m_pg) { m_pg->Close(); } }
|
||||||
|
|
||||||
ALWAYS_INLINE void CancelClose() {
|
ALWAYS_INLINE void CancelClose() {
|
||||||
|
@ -88,8 +88,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
enum OperationType {
|
enum OperationType {
|
||||||
OperationType_Map = 0,
|
OperationType_Map = 0,
|
||||||
OperationType_MapFirst = 1,
|
OperationType_MapGroup = 1,
|
||||||
OperationType_MapGroup = 2,
|
OperationType_MapFirstGroup = 2,
|
||||||
OperationType_Unmap = 3,
|
OperationType_Unmap = 3,
|
||||||
OperationType_ChangePermissions = 4,
|
OperationType_ChangePermissions = 4,
|
||||||
OperationType_ChangePermissionsAndRefresh = 5,
|
OperationType_ChangePermissionsAndRefresh = 5,
|
||||||
@ -241,16 +241,20 @@ namespace ams::kern {
|
|||||||
|
|
||||||
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const {
|
||||||
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
|
/* Even though Unsafe physical memory is KMemoryState_Normal, it must be mapped inside the alias code region. */
|
||||||
return this->CanContain(addr, size, KMemoryState_AliasCode);
|
return this->CanContain(addr, size, ams::svc::MemoryState_AliasCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
ALWAYS_INLINE KScopedLightLock AcquireDeviceMapLock() {
|
||||||
return KScopedLightLock(m_device_map_lock);
|
return KScopedLightLock(m_device_map_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcessAddress GetRegionAddress(KMemoryState state) const;
|
KProcessAddress GetRegionAddress(ams::svc::MemoryState state) const;
|
||||||
size_t GetRegionSize(KMemoryState state) const;
|
size_t GetRegionSize(ams::svc::MemoryState state) const;
|
||||||
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const;
|
bool CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const;
|
||||||
|
|
||||||
|
ALWAYS_INLINE KProcessAddress GetRegionAddress(KMemoryState state) const { return this->GetRegionAddress(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
|
ALWAYS_INLINE size_t GetRegionSize(KMemoryState state) const { return this->GetRegionSize(static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
|
ALWAYS_INLINE bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->CanContain(addr, size, static_cast<ams::svc::MemoryState>(state & KMemoryState_Mask)); }
|
||||||
protected:
|
protected:
|
||||||
/* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
|
/* NOTE: These three functions (Operate, Operate, FinalizeUpdate) are virtual functions */
|
||||||
/* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
|
/* in Nintendo's kernel. We devirtualize them, since KPageTable is the only derived */
|
||||||
@ -308,6 +312,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||||
|
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||||
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||||
R_RETURN(this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
R_RETURN(this->CheckMemoryState(nullptr, nullptr, nullptr, out_blocks_needed, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
||||||
@ -321,7 +326,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
Result QueryInfoImpl(KMemoryInfo *out_info, ams::svc::PageInfo *out_page, KProcessAddress address) const;
|
||||||
|
|
||||||
Result QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, KMemoryState 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, KMemoryPermission perm);
|
||||||
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);
|
||||||
@ -335,9 +340,9 @@ namespace ams::kern {
|
|||||||
|
|
||||||
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
NOINLINE Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
||||||
|
|
||||||
Result MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm);
|
Result MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryState state, KMemoryPermission perm);
|
||||||
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size);
|
Result ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size, KMemoryState state);
|
||||||
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size);
|
Result WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size, KMemoryState state);
|
||||||
|
|
||||||
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
Result SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
|
||||||
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
Result SetupForIpcServer(KProcessAddress *out_addr, size_t size, KProcessAddress src_addr, KMemoryPermission test_perm, KMemoryState dst_state, KPageTableBase &src_page_table, bool send);
|
||||||
@ -371,8 +376,8 @@ namespace ams::kern {
|
|||||||
Result SetMaxHeapSize(size_t size);
|
Result SetMaxHeapSize(size_t size);
|
||||||
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
Result QueryInfo(KMemoryInfo *out_info, ams::svc::PageInfo *out_page_info, KProcessAddress addr) const;
|
||||||
Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const;
|
Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const;
|
||||||
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, KMemoryState_Static)); }
|
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Static)); }
|
||||||
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, KMemoryState_Io)); }
|
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const { R_RETURN(this->QueryMappingImpl(out, address, size, ams::svc::MemoryState_Io)); }
|
||||||
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size);
|
||||||
@ -407,12 +412,13 @@ namespace ams::kern {
|
|||||||
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
Result MakeAndOpenPageGroup(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr);
|
||||||
|
|
||||||
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
||||||
|
Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size);
|
||||||
|
|
||||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
|
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
|
||||||
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size);
|
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state);
|
||||||
|
|
||||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||||
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size);
|
Result WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state);
|
||||||
|
|
||||||
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap);
|
Result LockForMapDeviceAddressSpace(bool *out_is_io, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned, bool check_heap);
|
||||||
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
|
Result LockForUnmapDeviceAddressSpace(KProcessAddress address, size_t size, bool check_heap);
|
||||||
|
@ -76,6 +76,7 @@ namespace ams::kern {
|
|||||||
bool m_is_signaled;
|
bool m_is_signaled;
|
||||||
bool m_is_initialized;
|
bool m_is_initialized;
|
||||||
bool m_is_application;
|
bool m_is_application;
|
||||||
|
bool m_is_default_application_system_resource;
|
||||||
char m_name[13];
|
char m_name[13];
|
||||||
util::Atomic<u16> m_num_running_threads;
|
util::Atomic<u16> m_num_running_threads;
|
||||||
u32 m_flags;
|
u32 m_flags;
|
||||||
@ -178,6 +179,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr bool IsApplication() const { return m_is_application; }
|
constexpr bool IsApplication() const { return m_is_application; }
|
||||||
|
|
||||||
|
constexpr bool IsDefaultApplicationSystemResource() const { return m_is_default_application_system_resource; }
|
||||||
|
|
||||||
constexpr bool IsSuspended() const { return m_is_suspended; }
|
constexpr bool IsSuspended() const { return m_is_suspended; }
|
||||||
constexpr void SetSuspended(bool suspended) { m_is_suspended = suspended; }
|
constexpr void SetSuspended(bool suspended) { m_is_suspended = suspended; }
|
||||||
|
|
||||||
@ -280,12 +283,20 @@ namespace ams::kern {
|
|||||||
void IncrementRunningThreadCount();
|
void IncrementRunningThreadCount();
|
||||||
void DecrementRunningThreadCount();
|
void DecrementRunningThreadCount();
|
||||||
|
|
||||||
|
size_t GetRequiredSecureMemorySizeNonDefault() const {
|
||||||
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetRequiredSecureMemorySize() const {
|
||||||
|
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t GetTotalSystemResourceSize() const {
|
size_t GetTotalSystemResourceSize() const {
|
||||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0;
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetUsedSystemResourceSize() const {
|
size_t GetUsedSystemResourceSize() const {
|
||||||
return m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
return (!this->IsDefaultApplicationSystemResource() && m_system_resource->IsSecureResource()) ? static_cast<KSecureSystemResource *>(m_system_resource)->GetUsedSize() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) {
|
void SetRunningThread(s32 core, KThread *thread, u64 idle_count, u64 switch_count) {
|
||||||
|
@ -25,7 +25,8 @@ namespace ams::kern {
|
|||||||
static constexpr s32 ExitWorkerPriority = 11;
|
static constexpr s32 ExitWorkerPriority = 11;
|
||||||
|
|
||||||
enum WorkerType {
|
enum WorkerType {
|
||||||
WorkerType_Exit,
|
WorkerType_ExitThread,
|
||||||
|
WorkerType_ExitProcess,
|
||||||
|
|
||||||
WorkerType_Count,
|
WorkerType_Count,
|
||||||
};
|
};
|
||||||
|
@ -59,7 +59,9 @@ namespace ams::kern::arch::arm64 {
|
|||||||
EsrEc_BrkInstruction = 0b111100,
|
EsrEc_BrkInstruction = 0b111100,
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u32 GetInstructionData(const KExceptionContext *context, u64 esr) {
|
|
||||||
|
|
||||||
|
u32 GetInstructionDataSupervisorMode(const KExceptionContext *context, u64 esr) {
|
||||||
/* Check for THUMB usermode */
|
/* Check for THUMB usermode */
|
||||||
if ((context->psr & 0x3F) == 0x30) {
|
if ((context->psr & 0x3F) == 0x30) {
|
||||||
u32 insn = *reinterpret_cast<u16 *>(context->pc & ~0x1);
|
u32 insn = *reinterpret_cast<u16 *>(context->pc & ~0x1);
|
||||||
@ -74,6 +76,37 @@ namespace ams::kern::arch::arm64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetInstructionDataUserMode(const KExceptionContext *context) {
|
||||||
|
/* Check for THUMB usermode */
|
||||||
|
u32 insn = 0;
|
||||||
|
if ((context->psr & 0x3F) == 0x30) {
|
||||||
|
u16 insn_high = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_high), reinterpret_cast<u16 *>(context->pc & ~0x1), sizeof(insn_high))) {
|
||||||
|
insn = insn_high;
|
||||||
|
|
||||||
|
/* Check if the instruction was a THUMB mode branch prefix. */
|
||||||
|
if (((insn >> 11) & 0b11110) == 0b11110) {
|
||||||
|
u16 insn_low = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_low), reinterpret_cast<u16 *>((context->pc & ~0x1) + sizeof(u16)), sizeof(insn_low))) {
|
||||||
|
insn = (static_cast<u32>(insn_high) << 16) | (static_cast<u32>(insn_low) << 0);
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
u32 insn_value = 0;
|
||||||
|
if (UserspaceAccess::CopyMemoryFromUser(std::addressof(insn_value), reinterpret_cast<u32 *>(context->pc), sizeof(insn_value))) {
|
||||||
|
insn = insn_value;
|
||||||
|
} else {
|
||||||
|
insn = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return insn;
|
||||||
|
}
|
||||||
|
|
||||||
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
|
void HandleUserException(KExceptionContext *context, u64 esr, u64 far, u64 afsr0, u64 afsr1, u32 data) {
|
||||||
KProcess &cur_process = GetCurrentProcess();
|
KProcess &cur_process = GetCurrentProcess();
|
||||||
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
|
bool should_process_user_exception = KTargetSystem::IsUserExceptionHandlersEnabled();
|
||||||
@ -501,6 +534,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled());
|
MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled());
|
||||||
|
|
||||||
/* Retrieve information about the exception. */
|
/* Retrieve information about the exception. */
|
||||||
|
const bool is_user_mode = (context->psr & 0xF) == 0;
|
||||||
const u64 esr = cpu::GetEsrEl1();
|
const u64 esr = cpu::GetEsrEl1();
|
||||||
const u64 afsr0 = cpu::GetAfsr0El1();
|
const u64 afsr0 = cpu::GetAfsr0El1();
|
||||||
const u64 afsr1 = cpu::GetAfsr1El1();
|
const u64 afsr1 = cpu::GetAfsr1El1();
|
||||||
@ -514,7 +548,12 @@ namespace ams::kern::arch::arm64 {
|
|||||||
case EsrEc_BkptInstruction:
|
case EsrEc_BkptInstruction:
|
||||||
case EsrEc_BrkInstruction:
|
case EsrEc_BrkInstruction:
|
||||||
far = context->pc;
|
far = context->pc;
|
||||||
data = GetInstructionData(context, esr);
|
/* NOTE: Nintendo always calls GetInstructionDataUserMode. */
|
||||||
|
if (is_user_mode) {
|
||||||
|
data = GetInstructionDataUserMode(context);
|
||||||
|
} else {
|
||||||
|
data = GetInstructionDataSupervisorMode(context, esr);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case EsrEc_Svc32:
|
case EsrEc_Svc32:
|
||||||
if (context->psr & 0x20) {
|
if (context->psr & 0x20) {
|
||||||
@ -543,7 +582,6 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Verify that spsr's M is allowable (EL0t). */
|
/* Verify that spsr's M is allowable (EL0t). */
|
||||||
{
|
{
|
||||||
const bool is_user_mode = (context->psr & 0xF) == 0;
|
|
||||||
if (is_user_mode) {
|
if (is_user_mode) {
|
||||||
/* If the user disable count is set, we may need to pin the current thread. */
|
/* If the user disable count is set, we may need to pin the current thread. */
|
||||||
if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) {
|
if (GetCurrentThread().GetUserDisableCount() != 0 && GetCurrentProcess().GetPinnedThread(GetCurrentCoreId()) == nullptr) {
|
||||||
|
@ -207,10 +207,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::InitializeForProcess(u32 id, 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 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) {
|
||||||
/* The input ID isn't actually used. */
|
|
||||||
MESOSPHERE_UNUSED(id);
|
|
||||||
|
|
||||||
/* 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); };
|
||||||
@ -239,9 +236,15 @@ namespace ams::kern::arch::arm64 {
|
|||||||
/* Only process tables should be finalized. */
|
/* Only process tables should be finalized. */
|
||||||
MESOSPHERE_ASSERT(!this->IsKernel());
|
MESOSPHERE_ASSERT(!this->IsKernel());
|
||||||
|
|
||||||
|
/* NOTE: Here Nintendo calls an unknown OnFinalize function. */
|
||||||
|
/* this->OnFinalize(); */
|
||||||
|
|
||||||
/* Note that we've updated (to ensure we're synchronized). */
|
/* Note that we've updated (to ensure we're synchronized). */
|
||||||
this->NoteUpdated();
|
this->NoteUpdated();
|
||||||
|
|
||||||
|
/* NOTE: Here Nintendo calls a second unknown OnFinalize function. */
|
||||||
|
/* this->OnFinalize2(); */
|
||||||
|
|
||||||
/* Free all pages in the table. */
|
/* Free all pages in the table. */
|
||||||
{
|
{
|
||||||
/* Get implementation objects. */
|
/* Get implementation objects. */
|
||||||
@ -348,7 +351,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||||
MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages));
|
MESOSPHERE_ASSERT(this->ContainsPages(virt_addr, num_pages));
|
||||||
|
|
||||||
if (operation == OperationType_Map || operation == OperationType_MapFirst) {
|
if (operation == OperationType_Map) {
|
||||||
MESOSPHERE_ABORT_UNLESS(is_pa_valid);
|
MESOSPHERE_ABORT_UNLESS(is_pa_valid);
|
||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||||
} else {
|
} else {
|
||||||
@ -375,8 +378,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType_Map:
|
case OperationType_Map:
|
||||||
case OperationType_MapFirst:
|
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll));
|
||||||
R_RETURN(this->MapContiguous(virt_addr, phys_addr, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirst, page_list, reuse_ll));
|
|
||||||
case OperationType_ChangePermissions:
|
case OperationType_ChangePermissions:
|
||||||
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll));
|
R_RETURN(this->ChangePermissions(virt_addr, num_pages, entry_template, properties.disable_merge_attributes, false, false, page_list, reuse_ll));
|
||||||
case OperationType_ChangePermissionsAndRefresh:
|
case OperationType_ChangePermissionsAndRefresh:
|
||||||
@ -399,7 +401,8 @@ namespace ams::kern::arch::arm64 {
|
|||||||
auto entry_template = this->GetEntryTemplate(properties);
|
auto entry_template = this->GetEntryTemplate(properties);
|
||||||
switch (operation) {
|
switch (operation) {
|
||||||
case OperationType_MapGroup:
|
case OperationType_MapGroup:
|
||||||
R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, page_list, reuse_ll));
|
case OperationType_MapFirstGroup:
|
||||||
|
R_RETURN(this->MapGroup(virt_addr, page_group, num_pages, entry_template, properties.disable_merge_attributes == DisableMergeAttribute_DisableHead, operation != OperationType_MapFirstGroup, page_list, reuse_ll));
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -756,7 +759,7 @@ namespace ams::kern::arch::arm64 {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Cache initial addresses for use on cleanup. */
|
/* Cache initial addresses for use on cleanup. */
|
||||||
@ -827,21 +830,17 @@ namespace ams::kern::arch::arm64 {
|
|||||||
|
|
||||||
/* Open references to the pages, if we should. */
|
/* Open references to the pages, if we should. */
|
||||||
if (IsHeapPhysicalAddress(orig_phys_addr)) {
|
if (IsHeapPhysicalAddress(orig_phys_addr)) {
|
||||||
if (not_first) {
|
|
||||||
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
Kernel::GetMemoryManager().Open(orig_phys_addr, num_pages);
|
||||||
} else {
|
|
||||||
Kernel::GetMemoryManager().OpenFirst(orig_phys_addr, num_pages);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll) {
|
Result KPageTable::MapGroup(KProcessAddress virt_addr, const KPageGroup &pg, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, bool not_first, PageLinkedList *page_list, bool reuse_ll) {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* We want to maintain a new reference to every page in the group. */
|
/* We want to maintain a new reference to every page in the group. */
|
||||||
KScopedPageGroup spg(pg);
|
KScopedPageGroup spg(pg, not_first);
|
||||||
|
|
||||||
/* Cache initial address for use on cleanup. */
|
/* Cache initial address for use on cleanup. */
|
||||||
const KProcessAddress orig_virt_addr = virt_addr;
|
const KProcessAddress orig_virt_addr = virt_addr;
|
||||||
|
@ -18,12 +18,8 @@
|
|||||||
namespace ams::kern::arch::arm64 {
|
namespace ams::kern::arch::arm64 {
|
||||||
|
|
||||||
void KSupervisorPageTable::Initialize(s32 core_id) {
|
void KSupervisorPageTable::Initialize(s32 core_id) {
|
||||||
/* Get the identity mapping ttbr0. */
|
/* Verify that sctlr_el1 has the wxn bit set. */
|
||||||
m_ttbr0_identity[core_id] = cpu::GetTtbr0El1();
|
MESOSPHERE_ABORT_UNLESS(cpu::SystemControlRegisterAccessor().GetWxn());
|
||||||
|
|
||||||
/* Set sctlr_el1 */
|
|
||||||
cpu::SystemControlRegisterAccessor().SetWxn(true).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Invalidate the entire TLB. */
|
/* Invalidate the entire TLB. */
|
||||||
cpu::InvalidateEntireTlb();
|
cpu::InvalidateEntireTlb();
|
||||||
|
@ -130,4 +130,4 @@ _ZN3ams4kern3svc14RestoreContextEm:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
@ -194,7 +194,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
5: /* Return from SVC. */
|
5: /* Return from SVC. */
|
||||||
|
|
||||||
@ -297,7 +297,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler64Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
/* ams::kern::arch::arm64::SvcHandler32() */
|
/* ams::kern::arch::arm64::SvcHandler32() */
|
||||||
.section .text._ZN3ams4kern4arch5arm6412SvcHandler32Ev, "ax", %progbits
|
.section .text._ZN3ams4kern4arch5arm6412SvcHandler32Ev, "ax", %progbits
|
||||||
@ -467,7 +467,7 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
|
||||||
5: /* Return from SVC. */
|
5: /* Return from SVC. */
|
||||||
|
|
||||||
@ -547,4 +547,4 @@ _ZN3ams4kern4arch5arm6412SvcHandler32Ev:
|
|||||||
|
|
||||||
/* Return. */
|
/* Return. */
|
||||||
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
|
||||||
eret
|
ERET_WITH_SPECULATION_BARRIER
|
||||||
|
@ -32,7 +32,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
class SavedSystemRegisters {
|
class SavedSystemRegisters {
|
||||||
private:
|
private:
|
||||||
u64 ttbr0_el1;
|
u64 ttbr0_el1;
|
||||||
u64 tcr_el1;
|
|
||||||
u64 elr_el1;
|
u64 elr_el1;
|
||||||
u64 sp_el0;
|
u64 sp_el0;
|
||||||
u64 spsr_el1;
|
u64 spsr_el1;
|
||||||
@ -92,7 +91,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
void SavedSystemRegisters::Save() {
|
void SavedSystemRegisters::Save() {
|
||||||
/* Save system registers. */
|
/* Save system registers. */
|
||||||
this->ttbr0_el1 = cpu::GetTtbr0El1();
|
this->ttbr0_el1 = cpu::GetTtbr0El1();
|
||||||
this->tcr_el1 = cpu::GetTcrEl1();
|
|
||||||
this->tpidr_el0 = cpu::GetTpidrEl0();
|
this->tpidr_el0 = cpu::GetTpidrEl0();
|
||||||
this->elr_el1 = cpu::GetElrEl1();
|
this->elr_el1 = cpu::GetElrEl1();
|
||||||
this->sp_el0 = cpu::GetSpEl0();
|
this->sp_el0 = cpu::GetSpEl0();
|
||||||
@ -408,7 +406,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* Restore system registers. */
|
/* Restore system registers. */
|
||||||
cpu::SetTtbr0El1 (this->ttbr0_el1);
|
cpu::SetTtbr0El1 (this->ttbr0_el1);
|
||||||
cpu::SetTcrEl1 (this->tcr_el1);
|
|
||||||
cpu::SetTpidrEl0 (this->tpidr_el0);
|
cpu::SetTpidrEl0 (this->tpidr_el0);
|
||||||
cpu::SetElrEl1 (this->elr_el1);
|
cpu::SetElrEl1 (this->elr_el1);
|
||||||
cpu::SetSpEl0 (this->sp_el0);
|
cpu::SetSpEl0 (this->sp_el0);
|
||||||
@ -515,24 +512,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
/* Save the system registers for the current core. */
|
/* Save the system registers for the current core. */
|
||||||
g_sleep_system_registers[core_id].Save();
|
g_sleep_system_registers[core_id].Save();
|
||||||
|
|
||||||
/* Change the translation tables to use the kernel table. */
|
|
||||||
{
|
|
||||||
/* Get the current value of the translation control register. */
|
|
||||||
const u64 tcr = cpu::GetTcrEl1();
|
|
||||||
|
|
||||||
/* Disable translation table walks on tlb miss. */
|
|
||||||
cpu::TranslationControlRegisterAccessor(tcr).SetEpd0(true).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Change the translation table base (ttbr0) to use the kernel table. */
|
|
||||||
cpu::SetTtbr0El1(Kernel::GetKernelPageTable().GetIdentityMapTtbr0(core_id));
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
|
|
||||||
/* Enable translation table walks on tlb miss. */
|
|
||||||
cpu::TranslationControlRegisterAccessor(tcr).SetEpd0(false).Store();
|
|
||||||
cpu::EnsureInstructionConsistency();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Invalidate the entire tlb. */
|
/* Invalidate the entire tlb. */
|
||||||
cpu::InvalidateEntireTlb();
|
cpu::InvalidateEntireTlb();
|
||||||
|
|
||||||
@ -552,13 +531,14 @@ namespace ams::kern::board::nintendo::nx {
|
|||||||
|
|
||||||
/* Setup the initial arguments. */
|
/* Setup the initial arguments. */
|
||||||
{
|
{
|
||||||
init_args->ttbr0 = cpu::GetTtbr0El1();
|
/* Determine whether we're running on a cortex-a53 or a-57. */
|
||||||
init_args->ttbr1 = cpu::GetTtbr1El1();
|
cpu::MainIdRegisterAccessor midr_el1;
|
||||||
init_args->tcr = cpu::GetTcrEl1();
|
const auto implementer = midr_el1.GetImplementer();
|
||||||
init_args->mair = cpu::GetMairEl1();
|
const auto primary_part = midr_el1.GetPrimaryPartNumber();
|
||||||
init_args->cpuactlr = cpu::GetCpuActlrEl1();
|
const bool needs_cpu_ctlr = (implementer == cpu::MainIdRegisterAccessor::Implementer::ArmLimited) && (primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA57 || primary_part == cpu::MainIdRegisterAccessor::PrimaryPartNumber::CortexA53);
|
||||||
init_args->cpuectlr = cpu::GetCpuEctlrEl1();
|
|
||||||
init_args->sctlr = cpu::GetSctlrEl1();
|
init_args->cpuactlr = needs_cpu_ctlr ? cpu::GetCpuActlrEl1() : 0;
|
||||||
|
init_args->cpuectlr = needs_cpu_ctlr ? cpu::GetCpuEctlrEl1() : 0;
|
||||||
init_args->sp = 0;
|
init_args->sp = 0;
|
||||||
init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry);
|
init_args->entrypoint = reinterpret_cast<uintptr_t>(::ams::kern::board::nintendo::nx::KSleepManager::ResumeEntry);
|
||||||
init_args->argument = sleep_buffer;
|
init_args->argument = sleep_buffer;
|
||||||
|
@ -21,10 +21,13 @@ namespace ams::kern::init::Elf {
|
|||||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
||||||
uintptr_t dyn_rel = 0;
|
uintptr_t dyn_rel = 0;
|
||||||
uintptr_t dyn_rela = 0;
|
uintptr_t dyn_rela = 0;
|
||||||
|
uintptr_t dyn_relr = 0;
|
||||||
uintptr_t rel_count = 0;
|
uintptr_t rel_count = 0;
|
||||||
uintptr_t rela_count = 0;
|
uintptr_t rela_count = 0;
|
||||||
|
uintptr_t relr_sz = 0;
|
||||||
uintptr_t rel_ent = 0;
|
uintptr_t rel_ent = 0;
|
||||||
uintptr_t rela_ent = 0;
|
uintptr_t rela_ent = 0;
|
||||||
|
uintptr_t relr_ent = 0;
|
||||||
|
|
||||||
/* Iterate over all tags, identifying important extents. */
|
/* Iterate over all tags, identifying important extents. */
|
||||||
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
||||||
@ -35,24 +38,38 @@ namespace ams::kern::init::Elf {
|
|||||||
case DT_RELA:
|
case DT_RELA:
|
||||||
dyn_rela = base_address + cur_entry->GetPtr();
|
dyn_rela = base_address + cur_entry->GetPtr();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELR:
|
||||||
|
dyn_relr = base_address + cur_entry->GetPtr();
|
||||||
|
break;
|
||||||
case DT_RELENT:
|
case DT_RELENT:
|
||||||
rel_ent = cur_entry->GetValue();
|
rel_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELAENT:
|
case DT_RELAENT:
|
||||||
rela_ent = cur_entry->GetValue();
|
rela_ent = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRENT:
|
||||||
|
relr_ent = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
case DT_RELCOUNT:
|
case DT_RELCOUNT:
|
||||||
rel_count = cur_entry->GetValue();
|
rel_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
case DT_RELACOUNT:
|
case DT_RELACOUNT:
|
||||||
rela_count = cur_entry->GetValue();
|
rela_count = cur_entry->GetValue();
|
||||||
break;
|
break;
|
||||||
|
case DT_RELRSZ:
|
||||||
|
relr_sz = cur_entry->GetValue();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apply all Rel relocations */
|
/* Apply all Rel relocations */
|
||||||
for (size_t i = 0; i < rel_count; i++) {
|
if (rel_count > 0) {
|
||||||
const auto &rel = *reinterpret_cast<const Elf::Rel *>(dyn_rel + rel_ent * i);
|
/* Check that the rel relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rel != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rel_ent == sizeof(Elf::Rel));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rel_count; ++i) {
|
||||||
|
const auto &rel = reinterpret_cast<const Elf::Rel *>(dyn_rel)[i];
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
/* Only allow architecture-specific relocations. */
|
||||||
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
@ -61,10 +78,16 @@ namespace ams::kern::init::Elf {
|
|||||||
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
|
||||||
*target_address += base_address;
|
*target_address += base_address;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply all Rela relocations. */
|
/* Apply all Rela relocations. */
|
||||||
for (size_t i = 0; i < rela_count; i++) {
|
if (rela_count > 0) {
|
||||||
const auto &rela = *reinterpret_cast<const Elf::Rela *>(dyn_rela + rela_ent * i);
|
/* Check that the rela relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_rela != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(rela_ent == sizeof(Elf::Rela));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rela_count; ++i) {
|
||||||
|
const auto &rela = reinterpret_cast<const Elf::Rela *>(dyn_rela)[i];
|
||||||
|
|
||||||
/* Only allow architecture-specific relocations. */
|
/* Only allow architecture-specific relocations. */
|
||||||
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
|
||||||
@ -75,6 +98,42 @@ namespace ams::kern::init::Elf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Apply all Relr relocations. */
|
||||||
|
if (relr_sz >= sizeof(Elf::Relr)) {
|
||||||
|
/* Check that the relr relocations are applyable. */
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(dyn_relr != 0);
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(relr_ent == sizeof(Elf::Relr));
|
||||||
|
|
||||||
|
const size_t relr_count = relr_sz / sizeof(Elf::Relr);
|
||||||
|
|
||||||
|
Elf::Addr *where = nullptr;
|
||||||
|
for (size_t i = 0; i < relr_count; ++i) {
|
||||||
|
const auto &relr = reinterpret_cast<const Elf::Relr *>(dyn_relr)[i];
|
||||||
|
|
||||||
|
if (relr.IsLocation()) {
|
||||||
|
/* Update location. */
|
||||||
|
where = reinterpret_cast<Elf::Addr *>(base_address + relr.GetLocation());
|
||||||
|
|
||||||
|
/* Apply the relocation. */
|
||||||
|
*(where++) += base_address;
|
||||||
|
} else {
|
||||||
|
/* Get the bitmap. */
|
||||||
|
u64 bitmap = relr.GetBitmap();
|
||||||
|
|
||||||
|
/* Apply all relocations. */
|
||||||
|
while (bitmap != 0) {
|
||||||
|
const u64 next = util::CountTrailingZeros(bitmap);
|
||||||
|
bitmap &= ~(static_cast<u64>(1) << next);
|
||||||
|
where[next] += base_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
where += BITSIZEOF(bitmap) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
||||||
for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
|
for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
|
||||||
(*(void (**)())(cur_entry))();
|
(*(void (**)())(cur_entry))();
|
||||||
|
@ -171,6 +171,9 @@ namespace ams::kern::init {
|
|||||||
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
const KMemoryRegion &slab_region = KMemoryLayout::GetSlabRegion();
|
||||||
KVirtualAddress address = slab_region.GetAddress();
|
KVirtualAddress address = slab_region.GetAddress();
|
||||||
|
|
||||||
|
/* Clear the slab region. */
|
||||||
|
std::memset(GetVoidPointer(address), 0, slab_region.GetSize());
|
||||||
|
|
||||||
/* Initialize slab type array to be in sorted order. */
|
/* Initialize slab type array to be in sorted order. */
|
||||||
KSlabType slab_types[KSlabType_Count];
|
KSlabType slab_types[KSlabType_Count];
|
||||||
for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); }
|
for (size_t i = 0; i < util::size(slab_types); i++) { slab_types[i] = static_cast<KSlabType>(i); }
|
||||||
|
@ -27,6 +27,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>;
|
constinit KPhysicalAddress g_initial_process_binary_phys_addr = Null<KPhysicalAddress>;
|
||||||
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
constinit KVirtualAddress g_initial_process_binary_address = Null<KVirtualAddress>;
|
||||||
|
constinit size_t g_initial_process_binary_size = 0;
|
||||||
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
constinit InitialProcessBinaryHeader g_initial_process_binary_header = {};
|
||||||
constinit size_t g_initial_process_secure_memory_size = 0;
|
constinit size_t g_initial_process_secure_memory_size = 0;
|
||||||
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
constinit u64 g_initial_process_id_min = std::numeric_limits<u64>::max();
|
||||||
@ -155,40 +156,14 @@ namespace ams::kern {
|
|||||||
KPageGroup *process_pg = std::addressof(pg);
|
KPageGroup *process_pg = std::addressof(pg);
|
||||||
ON_SCOPE_EXIT { process_pg->Close(); };
|
ON_SCOPE_EXIT { process_pg->Close(); };
|
||||||
|
|
||||||
/* Get the temporary region. */
|
|
||||||
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
|
||||||
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
|
||||||
|
|
||||||
/* Map the process's memory into the temporary region. */
|
|
||||||
KProcessAddress temp_address = Null<KProcessAddress>;
|
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
|
||||||
|
|
||||||
/* Setup the new page group's memory, so that we can load the process. */
|
|
||||||
{
|
|
||||||
/* Copy the unaligned ending of the compressed binary. */
|
|
||||||
if (const size_t unaligned_size = binary_size - util::AlignDown(binary_size, PageSize); unaligned_size != 0) {
|
|
||||||
std::memcpy(GetVoidPointer(temp_address + process_size - unaligned_size), GetVoidPointer(data + binary_size - unaligned_size), unaligned_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the aligned part of the compressed binary. */
|
|
||||||
if (const size_t aligned_size = util::AlignDown(binary_size, PageSize); aligned_size != 0 && src_pool == dst_pool) {
|
|
||||||
std::memmove(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(temp_address), aligned_size);
|
|
||||||
} else {
|
|
||||||
if (src_pool != dst_pool) {
|
|
||||||
std::memcpy(GetVoidPointer(temp_address + process_size - binary_size), GetVoidPointer(data), aligned_size);
|
|
||||||
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(data), aligned_size / PageSize);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the first part of the memory. */
|
|
||||||
std::memset(GetVoidPointer(temp_address), 0, process_size - binary_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load the process. */
|
/* Load the process. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.Load(temp_address, params, temp_address + process_size - binary_size));
|
reader.Load(pg, data);
|
||||||
|
|
||||||
/* Unmap the temporary mapping. */
|
/* If necessary, close/release the aligned part of the data we just loaded. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, pg, KMemoryState_Kernel));
|
if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) {
|
||||||
|
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(data), aligned_bin_size / PageSize);
|
||||||
|
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size);
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a KProcess object. */
|
/* Create a KProcess object. */
|
||||||
new_process = KProcess::Create();
|
new_process = KProcess::Create();
|
||||||
@ -241,11 +216,6 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal()));
|
MESOSPHERE_R_ABORT_UNLESS(new_process->Initialize(params, *process_pg, reader.GetCapabilities(), reader.GetNumCapabilities(), std::addressof(Kernel::GetSystemResourceLimit()), dst_pool, reader.IsImmortal()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Release the memory that was previously reserved. */
|
|
||||||
if (const size_t aligned_bin_size = util::AlignDown(binary_size, PageSize); aligned_bin_size != 0 && src_pool != dst_pool) {
|
|
||||||
Kernel::GetSystemResourceLimit().Release(ams::svc::LimitableResource_PhysicalMemoryMax, aligned_bin_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the process's memory permissions. */
|
/* Set the process's memory permissions. */
|
||||||
MESOSPHERE_R_ABORT_UNLESS(reader.SetMemoryPermissions(new_process->GetPageTable(), params));
|
MESOSPHERE_R_ABORT_UNLESS(reader.SetMemoryPermissions(new_process->GetPageTable(), params));
|
||||||
|
|
||||||
@ -275,10 +245,11 @@ namespace ams::kern {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr) {
|
void SetInitialProcessBinaryPhysicalAddress(KPhysicalAddress phys_addr, size_t size) {
|
||||||
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>);
|
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr == Null<KPhysicalAddress>);
|
||||||
|
|
||||||
g_initial_process_binary_phys_addr = phys_addr;
|
g_initial_process_binary_phys_addr = phys_addr;
|
||||||
|
g_initial_process_binary_size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
|
KPhysicalAddress GetInitialProcessBinaryPhysicalAddress() {
|
||||||
@ -287,6 +258,12 @@ namespace ams::kern {
|
|||||||
return g_initial_process_binary_phys_addr;
|
return g_initial_process_binary_phys_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t GetInitialProcessBinarySize() {
|
||||||
|
MESOSPHERE_INIT_ABORT_UNLESS(g_initial_process_binary_phys_addr != Null<KPhysicalAddress>);
|
||||||
|
|
||||||
|
return g_initial_process_binary_size;
|
||||||
|
}
|
||||||
|
|
||||||
u64 GetInitialProcessIdMin() {
|
u64 GetInitialProcessIdMin() {
|
||||||
return g_initial_process_id_min;
|
return g_initial_process_id_min;
|
||||||
}
|
}
|
||||||
@ -305,14 +282,17 @@ namespace ams::kern {
|
|||||||
LoadInitialProcessBinaryHeader();
|
LoadInitialProcessBinaryHeader();
|
||||||
|
|
||||||
if (g_initial_process_binary_header.num_processes > 0) {
|
if (g_initial_process_binary_header.num_processes > 0) {
|
||||||
/* Reserve pages for the initial process binary from the system resource limit. */
|
/* Ensure that we have a non-zero size. */
|
||||||
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
const size_t expected_size = g_initial_process_binary_size;
|
||||||
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
MESOSPHERE_INIT_ABORT_UNLESS(expected_size != 0);
|
||||||
|
|
||||||
/* The initial process binary is potentially over-allocated, so free any extra pages. */
|
/* Ensure that the size we need to reserve is as we expect it to be. */
|
||||||
if (total_size < InitialProcessBinarySizeMax) {
|
const size_t total_size = util::AlignUp(g_initial_process_binary_header.size, PageSize);
|
||||||
Kernel::GetMemoryManager().Close(KMemoryLayout::GetLinearPhysicalAddress(g_initial_process_binary_address + total_size), (InitialProcessBinarySizeMax - total_size) / PageSize);
|
MESOSPHERE_ABORT_UNLESS(total_size == expected_size);
|
||||||
}
|
MESOSPHERE_ABORT_UNLESS(total_size <= InitialProcessBinarySizeMax);
|
||||||
|
|
||||||
|
/* Reserve pages for the initial process binary from the system resource limit. */
|
||||||
|
MESOSPHERE_ABORT_UNLESS(Kernel::GetSystemResourceLimit().Reserve(ams::svc::LimitableResource_PhysicalMemoryMax, total_size));
|
||||||
|
|
||||||
return total_size;
|
return total_size;
|
||||||
} else {
|
} else {
|
||||||
|
@ -118,12 +118,12 @@ namespace ams::kern {
|
|||||||
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
if (info.GetState() != KMemoryState_Io) {
|
if (info.GetSvcState() != ams::svc::MemoryState_Io) {
|
||||||
/* The memory is normal memory. */
|
/* The memory is normal memory. */
|
||||||
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
||||||
} else {
|
} else {
|
||||||
/* The memory is IO memory. */
|
/* The memory is IO memory. */
|
||||||
R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size, info.GetState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
@ -181,12 +181,12 @@ namespace ams::kern {
|
|||||||
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
const size_t cur_size = std::min(remaining, info.GetEndAddress() - GetInteger(cur_address));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
if (info.GetState() != KMemoryState_Io) {
|
if (info.GetSvcState() != ams::svc::MemoryState_Io) {
|
||||||
/* The memory is normal memory. */
|
/* The memory is normal memory. */
|
||||||
R_TRY(target_pt.WriteDebugMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
R_TRY(target_pt.WriteDebugMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
||||||
} else {
|
} else {
|
||||||
/* The memory is IO memory. */
|
/* The memory is IO memory. */
|
||||||
R_TRY(target_pt.WriteDebugIoMemory(cur_address, GetVoidPointer(buffer), cur_size));
|
R_TRY(target_pt.WriteDebugIoMemory(cur_address, GetVoidPointer(buffer), cur_size, info.GetState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
|
@ -73,6 +73,120 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NOINLINE void LoadInitialProcessSegment(const KPageGroup &pg, size_t seg_offset, size_t seg_size, size_t binary_size, KVirtualAddress data, bool compressed) {
|
||||||
|
/* Save the original binary extents, for later use. */
|
||||||
|
const KPhysicalAddress binary_phys = KMemoryLayout::GetLinearPhysicalAddress(data);
|
||||||
|
|
||||||
|
/* Create a page group representing the segment. */
|
||||||
|
KPageGroup segment_pg(Kernel::GetSystemSystemResource().GetBlockInfoManagerPointer());
|
||||||
|
if (size_t remaining_size = util::AlignUp(seg_size, PageSize); remaining_size != 0) {
|
||||||
|
/* 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. */
|
||||||
|
{
|
||||||
|
KVirtualAddress last_block = Null<KVirtualAddress>;
|
||||||
|
KVirtualAddress last_data = Null<KVirtualAddress>;
|
||||||
|
size_t last_copy_size = 0;
|
||||||
|
size_t last_clear_size = 0;
|
||||||
|
size_t remaining_copy_size = binary_size;
|
||||||
|
for (const auto &block : segment_pg) {
|
||||||
|
/* Get the current block extents. */
|
||||||
|
const auto block_addr = block.GetAddress();
|
||||||
|
const size_t block_size = block.GetSize();
|
||||||
|
if (remaining_copy_size > 0) {
|
||||||
|
/* Determine if we need to copy anything. */
|
||||||
|
const size_t cur_size = std::min<size_t>(block_size, remaining_copy_size);
|
||||||
|
|
||||||
|
/* NOTE: The first block may potentially overlap the binary we want to copy to. */
|
||||||
|
/* Consider e.g. the case where the overall compressed image has size 0x40000, seg_offset is 0x30000, and binary_size is > 0x20000. */
|
||||||
|
/* Suppose too that data points, say, 0x18000 into the compressed image. */
|
||||||
|
/* Suppose finally that we simply naively copy in order. */
|
||||||
|
/* The first iteration of this loop will perform an 0x10000 copy from image+0x18000 to image + 0x30000 (as there is no overlap). */
|
||||||
|
/* The second iteration will perform a copy from image+0x28000 to <allocated pages>. */
|
||||||
|
/* However, the first copy will have trashed the data in the second copy. */
|
||||||
|
/* Thus, we must copy the first block after-the-fact to avoid potentially trashing data in the overlap case. */
|
||||||
|
/* It is guaranteed by pre-condition that only the very first block can overlap with the physical binary, so we can simply memmove it at the end. */
|
||||||
|
if (last_block != Null<KVirtualAddress>) {
|
||||||
|
/* This is guaranteed by pre-condition, but for ease of debugging, check for no overlap. */
|
||||||
|
MESOSPHERE_ASSERT(!util::HasOverlap(GetInteger(binary_phys), binary_size, GetInteger(block_addr), cur_size));
|
||||||
|
MESOSPHERE_UNUSED(binary_phys);
|
||||||
|
|
||||||
|
/* We need to copy. */
|
||||||
|
std::memcpy(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), GetVoidPointer(data), cur_size);
|
||||||
|
|
||||||
|
/* If we need to, clear past where we're copying. */
|
||||||
|
if (cur_size != block_size) {
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr + cur_size)), 0, block_size - cur_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
remaining_copy_size -= cur_size;
|
||||||
|
data += cur_size;
|
||||||
|
} else {
|
||||||
|
/* Save the first block, which may potentially overlap, so that we can copy it later. */
|
||||||
|
last_block = KMemoryLayout::GetLinearVirtualAddress(block_addr);
|
||||||
|
last_data = data;
|
||||||
|
last_copy_size = cur_size;
|
||||||
|
last_clear_size = block_size - cur_size;
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
remaining_copy_size -= cur_size;
|
||||||
|
data += cur_size;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We don't have data to copy, so we should just clear the pages. */
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(block_addr)), 0, block_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle a last block. */
|
||||||
|
if (last_copy_size != 0) {
|
||||||
|
if (last_block != last_data) {
|
||||||
|
std::memmove(GetVoidPointer(last_block), GetVoidPointer(last_data), last_copy_size);
|
||||||
|
}
|
||||||
|
if (last_clear_size != 0) {
|
||||||
|
std::memset(GetVoidPointer(last_block + last_copy_size), 0, last_clear_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If compressed, uncompress the data. */
|
||||||
|
if (compressed) {
|
||||||
|
/* Get the temporary region. */
|
||||||
|
const auto &temp_region = KMemoryLayout::GetTempRegion();
|
||||||
|
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
/* Map the process's memory into the temporary region. */
|
||||||
|
KProcessAddress temp_address = Null<KProcessAddress>;
|
||||||
|
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), segment_pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));
|
||||||
|
ON_SCOPE_EXIT { MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().UnmapPageGroup(temp_address, segment_pg, KMemoryState_Kernel)); };
|
||||||
|
|
||||||
|
/* Uncompress the data. */
|
||||||
|
BlzUncompress(GetVoidPointer(temp_address + binary_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const {
|
Result KInitialProcessReader::MakeCreateProcessParameter(ams::svc::CreateProcessParameter *out, bool enable_aslr) const {
|
||||||
@ -118,6 +232,8 @@ namespace ams::kern {
|
|||||||
out->program_id = m_kip_header.GetProgramId();
|
out->program_id = m_kip_header.GetProgramId();
|
||||||
out->version = m_kip_header.GetVersion();
|
out->version = m_kip_header.GetVersion();
|
||||||
out->flags = 0;
|
out->flags = 0;
|
||||||
|
out->reslimit = ams::svc::InvalidHandle;
|
||||||
|
out->system_resource_num_pages = 0;
|
||||||
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
||||||
|
|
||||||
/* Copy name field. */
|
/* Copy name field. */
|
||||||
@ -146,42 +262,55 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::Load(KProcessAddress address, const ams::svc::CreateProcessParameter ¶ms, KProcessAddress src) const {
|
void KInitialProcessReader::Load(const KPageGroup &pg, KVirtualAddress data) const {
|
||||||
/* Prepare to layout the data. */
|
/* Prepare to layout the data. */
|
||||||
const KProcessAddress rx_address = address + m_kip_header.GetRxAddress();
|
const KVirtualAddress rx_data = data;
|
||||||
const KProcessAddress ro_address = address + m_kip_header.GetRoAddress();
|
const KVirtualAddress ro_data = rx_data + m_kip_header.GetRxCompressedSize();
|
||||||
const KProcessAddress rw_address = address + m_kip_header.GetRwAddress();
|
const KVirtualAddress rw_data = ro_data + m_kip_header.GetRoCompressedSize();
|
||||||
const u8 *rx_binary = GetPointer<const u8>(src);
|
const size_t rx_size = m_kip_header.GetRxSize();
|
||||||
const u8 *ro_binary = rx_binary + m_kip_header.GetRxCompressedSize();
|
const size_t ro_size = m_kip_header.GetRoSize();
|
||||||
const u8 *rw_binary = ro_binary + m_kip_header.GetRoCompressedSize();
|
const size_t rw_size = m_kip_header.GetRwSize();
|
||||||
|
|
||||||
/* Copy text. */
|
/* If necessary, setup bss. */
|
||||||
if (util::AlignUp(m_kip_header.GetRxSize(), PageSize)) {
|
if (const size_t bss_size = m_kip_header.GetBssSize(); bss_size > 0) {
|
||||||
std::memmove(GetVoidPointer(rx_address), rx_binary, m_kip_header.GetRxCompressedSize());
|
/* Determine how many additional pages are needed for bss. */
|
||||||
if (m_kip_header.IsRxCompressed()) {
|
const u64 rw_end = util::AlignUp<u64>(m_kip_header.GetRwAddress() + m_kip_header.GetRwSize(), PageSize);
|
||||||
BlzUncompress(GetVoidPointer(rx_address + m_kip_header.GetRxCompressedSize()));
|
const u64 bss_end = util::AlignUp<u64>(m_kip_header.GetBssAddress() + m_kip_header.GetBssSize(), PageSize);
|
||||||
|
if (rw_end != bss_end) {
|
||||||
|
/* Find the pages corresponding to bss. */
|
||||||
|
size_t cur_offset = 0;
|
||||||
|
size_t remaining_size = bss_end - rw_end;
|
||||||
|
size_t bss_offset = rw_end - m_kip_header.GetRxAddress();
|
||||||
|
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 = bss_offset - cur_offset;
|
||||||
|
const bool is_before = cur_offset <= bss_offset;
|
||||||
|
cur_offset += cur_size;
|
||||||
|
if (is_before && bss_offset < cur_offset) {
|
||||||
|
/* It is, so clear the bss range. */
|
||||||
|
const size_t block_size = std::min<size_t>(cur_size - rel_diff, remaining_size);
|
||||||
|
std::memset(GetVoidPointer(KMemoryLayout::GetLinearVirtualAddress(it->GetAddress() + rel_diff)), 0, block_size);
|
||||||
|
|
||||||
|
/* Advance. */
|
||||||
|
cur_offset = bss_offset + block_size;
|
||||||
|
remaining_size -= block_size;
|
||||||
|
bss_offset += block_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy rodata. */
|
/* Load .rwdata. */
|
||||||
if (util::AlignUp(m_kip_header.GetRoSize(), PageSize)) {
|
LoadInitialProcessSegment(pg, m_kip_header.GetRwAddress() - m_kip_header.GetRxAddress(), rw_size, m_kip_header.GetRwCompressedSize(), rw_data, m_kip_header.IsRwCompressed());
|
||||||
std::memmove(GetVoidPointer(ro_address), ro_binary, m_kip_header.GetRoCompressedSize());
|
|
||||||
if (m_kip_header.IsRoCompressed()) {
|
|
||||||
BlzUncompress(GetVoidPointer(ro_address + m_kip_header.GetRoCompressedSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy rwdata. */
|
/* Load .rodata. */
|
||||||
if (util::AlignUp(m_kip_header.GetRwSize(), PageSize)) {
|
LoadInitialProcessSegment(pg, m_kip_header.GetRoAddress() - m_kip_header.GetRxAddress(), ro_size, m_kip_header.GetRoCompressedSize(), ro_data, m_kip_header.IsRoCompressed());
|
||||||
std::memmove(GetVoidPointer(rw_address), rw_binary, m_kip_header.GetRwCompressedSize());
|
|
||||||
if (m_kip_header.IsRwCompressed()) {
|
|
||||||
BlzUncompress(GetVoidPointer(rw_address + m_kip_header.GetRwCompressedSize()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MESOSPHERE_UNUSED(params);
|
/* Load .text. */
|
||||||
|
LoadInitialProcessSegment(pg, m_kip_header.GetRxAddress() - m_kip_header.GetRxAddress(), rx_size, m_kip_header.GetRxCompressedSize(), rx_data, m_kip_header.IsRxCompressed());
|
||||||
R_SUCCEED();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const {
|
Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter ¶ms) const {
|
||||||
|
@ -21,7 +21,8 @@ namespace ams::kern {
|
|||||||
|
|
||||||
constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = {
|
constexpr const std::pair<KMemoryState, const char *> MemoryStateNames[] = {
|
||||||
{KMemoryState_Free , "----- Free -----"},
|
{KMemoryState_Free , "----- Free -----"},
|
||||||
{KMemoryState_Io , "Io "},
|
{KMemoryState_IoMemory , "IoMemory "},
|
||||||
|
{KMemoryState_IoRegister , "IoRegister "},
|
||||||
{KMemoryState_Static , "Static "},
|
{KMemoryState_Static , "Static "},
|
||||||
{KMemoryState_Code , "Code "},
|
{KMemoryState_Code , "Code "},
|
||||||
{KMemoryState_CodeData , "CodeData "},
|
{KMemoryState_CodeData , "CodeData "},
|
||||||
@ -222,7 +223,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update block state. */
|
/* Update block state. */
|
||||||
it->Update(state, perm, attr, cur_address == address, set_disable_attr, clear_disable_attr);
|
it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr);
|
||||||
cur_address += cur_info.GetSize();
|
cur_address += cur_info.GetSize();
|
||||||
remaining_pages -= cur_info.GetNumPages();
|
remaining_pages -= cur_info.GetNumPages();
|
||||||
}
|
}
|
||||||
@ -232,7 +233,7 @@ namespace ams::kern {
|
|||||||
this->CoalesceForUpdate(allocator, address, num_pages);
|
this->CoalesceForUpdate(allocator, address, num_pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr) {
|
void KMemoryBlockManager::UpdateIfMatch(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, KMemoryState test_state, KMemoryPermission test_perm, KMemoryAttribute test_attr, KMemoryState state, KMemoryPermission perm, KMemoryAttribute attr, KMemoryBlockDisableMergeAttribute set_disable_attr, KMemoryBlockDisableMergeAttribute clear_disable_attr) {
|
||||||
/* Ensure for auditing that we never end up with an invalid tree. */
|
/* Ensure for auditing that we never end up with an invalid tree. */
|
||||||
KScopedMemoryBlockManagerAuditor auditor(this);
|
KScopedMemoryBlockManagerAuditor auditor(this);
|
||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize));
|
||||||
@ -269,7 +270,7 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update block state. */
|
/* Update block state. */
|
||||||
it->Update(state, perm, attr, false, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr);
|
||||||
cur_address += cur_info.GetSize();
|
cur_address += cur_info.GetSize();
|
||||||
remaining_pages -= cur_info.GetNumPages();
|
remaining_pages -= cur_info.GetNumPages();
|
||||||
} else {
|
} else {
|
||||||
@ -335,6 +336,62 @@ namespace ams::kern {
|
|||||||
this->CoalesceForUpdate(allocator, address, num_pages);
|
this->CoalesceForUpdate(allocator, address, num_pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KMemoryBlockManager::UpdateAttribute(KMemoryBlockManagerUpdateAllocator *allocator, KProcessAddress address, size_t num_pages, u32 mask, u32 attr) {
|
||||||
|
/* Ensure for auditing that we never end up with an invalid tree. */
|
||||||
|
KScopedMemoryBlockManagerAuditor auditor(this);
|
||||||
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(address), PageSize));
|
||||||
|
|
||||||
|
KProcessAddress cur_address = address;
|
||||||
|
size_t remaining_pages = num_pages;
|
||||||
|
iterator it = this->FindIterator(address);
|
||||||
|
|
||||||
|
while (remaining_pages > 0) {
|
||||||
|
const size_t remaining_size = remaining_pages * PageSize;
|
||||||
|
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
if ((it->GetAttribute() & mask) != attr) {
|
||||||
|
/* If we need to, create a new block before and insert it. */
|
||||||
|
if (cur_info.GetAddress() != GetInteger(cur_address)) {
|
||||||
|
KMemoryBlock *new_block = allocator->Allocate();
|
||||||
|
|
||||||
|
it->Split(new_block, cur_address);
|
||||||
|
it = m_memory_block_tree.insert(*new_block);
|
||||||
|
it++;
|
||||||
|
|
||||||
|
cur_info = it->GetMemoryInfo();
|
||||||
|
cur_address = cur_info.GetAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we need to, create a new block after and insert it. */
|
||||||
|
if (cur_info.GetSize() > remaining_size) {
|
||||||
|
KMemoryBlock *new_block = allocator->Allocate();
|
||||||
|
|
||||||
|
it->Split(new_block, cur_address + remaining_size);
|
||||||
|
it = m_memory_block_tree.insert(*new_block);
|
||||||
|
|
||||||
|
cur_info = it->GetMemoryInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update block state. */
|
||||||
|
it->UpdateAttribute(mask, attr);
|
||||||
|
cur_address += cur_info.GetSize();
|
||||||
|
remaining_pages -= cur_info.GetNumPages();
|
||||||
|
} else {
|
||||||
|
/* If we already have the right attributes, just advance. */
|
||||||
|
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
|
||||||
|
remaining_pages = 0;
|
||||||
|
cur_address += remaining_size;
|
||||||
|
} else {
|
||||||
|
remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
|
||||||
|
cur_address = cur_info.GetEndAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->CoalesceForUpdate(allocator, address, num_pages);
|
||||||
|
}
|
||||||
|
|
||||||
/* Debug. */
|
/* Debug. */
|
||||||
bool KMemoryBlockManager::CheckState() const {
|
bool KMemoryBlockManager::CheckState() const {
|
||||||
/* If we fail, we should dump blocks. */
|
/* If we fail, we should dump blocks. */
|
||||||
|
@ -108,7 +108,8 @@ namespace ams::kern {
|
|||||||
/* Free each region to its corresponding heap. */
|
/* Free each region to its corresponding heap. */
|
||||||
size_t reserved_sizes[MaxManagerCount] = {};
|
size_t reserved_sizes[MaxManagerCount] = {};
|
||||||
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
|
const KPhysicalAddress ini_start = GetInitialProcessBinaryPhysicalAddress();
|
||||||
const KPhysicalAddress ini_end = ini_start + InitialProcessBinarySizeMax;
|
const size_t ini_size = GetInitialProcessBinarySize();
|
||||||
|
const KPhysicalAddress ini_end = ini_start + ini_size;
|
||||||
const KPhysicalAddress ini_last = ini_end - 1;
|
const KPhysicalAddress ini_last = ini_end - 1;
|
||||||
for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
|
for (const auto &it : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
|
||||||
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
|
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
|
||||||
@ -126,13 +127,13 @@ namespace ams::kern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Open/reserve the ini memory. */
|
/* Open/reserve the ini memory. */
|
||||||
manager.OpenFirst(ini_start, InitialProcessBinarySizeMax / PageSize);
|
manager.OpenFirst(ini_start, ini_size / PageSize);
|
||||||
reserved_sizes[it.GetAttributes()] += InitialProcessBinarySizeMax;
|
reserved_sizes[it.GetAttributes()] += ini_size;
|
||||||
|
|
||||||
/* Free memory after the ini to the heap. */
|
/* Free memory after the ini to the heap. */
|
||||||
if (ini_last != cur_last) {
|
if (ini_last != cur_last) {
|
||||||
MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>);
|
MESOSPHERE_ABORT_UNLESS(cur_end != Null<KPhysicalAddress>);
|
||||||
manager.Free(ini_end, cur_end - ini_end);
|
manager.Free(ini_end, (cur_end - ini_end) / PageSize);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Ensure there's no partial overlap with the ini image. */
|
/* Ensure there's no partial overlap with the ini image. */
|
||||||
|
@ -368,77 +368,77 @@ namespace ams::kern {
|
|||||||
cpu::InvalidateEntireInstructionCache();
|
cpu::InvalidateEntireInstructionCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
KProcessAddress KPageTableBase::GetRegionAddress(KMemoryState state) const {
|
KProcessAddress KPageTableBase::GetRegionAddress(ams::svc::MemoryState state) const {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case KMemoryState_Free:
|
case ams::svc::MemoryState_Free:
|
||||||
case KMemoryState_Kernel:
|
case ams::svc::MemoryState_Kernel:
|
||||||
return m_address_space_start;
|
return m_address_space_start;
|
||||||
case KMemoryState_Normal:
|
case ams::svc::MemoryState_Normal:
|
||||||
return m_heap_region_start;
|
return m_heap_region_start;
|
||||||
case KMemoryState_Ipc:
|
case ams::svc::MemoryState_Ipc:
|
||||||
case KMemoryState_NonSecureIpc:
|
case ams::svc::MemoryState_NonSecureIpc:
|
||||||
case KMemoryState_NonDeviceIpc:
|
case ams::svc::MemoryState_NonDeviceIpc:
|
||||||
return m_alias_region_start;
|
return m_alias_region_start;
|
||||||
case KMemoryState_Stack:
|
case ams::svc::MemoryState_Stack:
|
||||||
return m_stack_region_start;
|
return m_stack_region_start;
|
||||||
case KMemoryState_Static:
|
case ams::svc::MemoryState_Static:
|
||||||
case KMemoryState_ThreadLocal:
|
case ams::svc::MemoryState_ThreadLocal:
|
||||||
return m_kernel_map_region_start;
|
return m_kernel_map_region_start;
|
||||||
case KMemoryState_Io:
|
case ams::svc::MemoryState_Io:
|
||||||
case KMemoryState_Shared:
|
case ams::svc::MemoryState_Shared:
|
||||||
case KMemoryState_AliasCode:
|
case ams::svc::MemoryState_AliasCode:
|
||||||
case KMemoryState_AliasCodeData:
|
case ams::svc::MemoryState_AliasCodeData:
|
||||||
case KMemoryState_Transfered:
|
case ams::svc::MemoryState_Transfered:
|
||||||
case KMemoryState_SharedTransfered:
|
case ams::svc::MemoryState_SharedTransfered:
|
||||||
case KMemoryState_SharedCode:
|
case ams::svc::MemoryState_SharedCode:
|
||||||
case KMemoryState_GeneratedCode:
|
case ams::svc::MemoryState_GeneratedCode:
|
||||||
case KMemoryState_CodeOut:
|
case ams::svc::MemoryState_CodeOut:
|
||||||
case KMemoryState_Coverage:
|
case ams::svc::MemoryState_Coverage:
|
||||||
case KMemoryState_Insecure:
|
case ams::svc::MemoryState_Insecure:
|
||||||
return m_alias_code_region_start;
|
return m_alias_code_region_start;
|
||||||
case KMemoryState_Code:
|
case ams::svc::MemoryState_Code:
|
||||||
case KMemoryState_CodeData:
|
case ams::svc::MemoryState_CodeData:
|
||||||
return m_code_region_start;
|
return m_code_region_start;
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t KPageTableBase::GetRegionSize(KMemoryState state) const {
|
size_t KPageTableBase::GetRegionSize(ams::svc::MemoryState state) const {
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case KMemoryState_Free:
|
case ams::svc::MemoryState_Free:
|
||||||
case KMemoryState_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 KMemoryState_Normal:
|
case ams::svc::MemoryState_Normal:
|
||||||
return m_heap_region_end - m_heap_region_start;
|
return m_heap_region_end - m_heap_region_start;
|
||||||
case KMemoryState_Ipc:
|
case ams::svc::MemoryState_Ipc:
|
||||||
case KMemoryState_NonSecureIpc:
|
case ams::svc::MemoryState_NonSecureIpc:
|
||||||
case KMemoryState_NonDeviceIpc:
|
case ams::svc::MemoryState_NonDeviceIpc:
|
||||||
return m_alias_region_end - m_alias_region_start;
|
return m_alias_region_end - m_alias_region_start;
|
||||||
case KMemoryState_Stack:
|
case ams::svc::MemoryState_Stack:
|
||||||
return m_stack_region_end - m_stack_region_start;
|
return m_stack_region_end - m_stack_region_start;
|
||||||
case KMemoryState_Static:
|
case ams::svc::MemoryState_Static:
|
||||||
case KMemoryState_ThreadLocal:
|
case ams::svc::MemoryState_ThreadLocal:
|
||||||
return m_kernel_map_region_end - m_kernel_map_region_start;
|
return m_kernel_map_region_end - m_kernel_map_region_start;
|
||||||
case KMemoryState_Io:
|
case ams::svc::MemoryState_Io:
|
||||||
case KMemoryState_Shared:
|
case ams::svc::MemoryState_Shared:
|
||||||
case KMemoryState_AliasCode:
|
case ams::svc::MemoryState_AliasCode:
|
||||||
case KMemoryState_AliasCodeData:
|
case ams::svc::MemoryState_AliasCodeData:
|
||||||
case KMemoryState_Transfered:
|
case ams::svc::MemoryState_Transfered:
|
||||||
case KMemoryState_SharedTransfered:
|
case ams::svc::MemoryState_SharedTransfered:
|
||||||
case KMemoryState_SharedCode:
|
case ams::svc::MemoryState_SharedCode:
|
||||||
case KMemoryState_GeneratedCode:
|
case ams::svc::MemoryState_GeneratedCode:
|
||||||
case KMemoryState_CodeOut:
|
case ams::svc::MemoryState_CodeOut:
|
||||||
case KMemoryState_Coverage:
|
case ams::svc::MemoryState_Coverage:
|
||||||
case KMemoryState_Insecure:
|
case ams::svc::MemoryState_Insecure:
|
||||||
return m_alias_code_region_end - m_alias_code_region_start;
|
return m_alias_code_region_end - m_alias_code_region_start;
|
||||||
case KMemoryState_Code:
|
case ams::svc::MemoryState_Code:
|
||||||
case KMemoryState_CodeData:
|
case ams::svc::MemoryState_CodeData:
|
||||||
return m_code_region_end - m_code_region_start;
|
return m_code_region_end - m_code_region_start;
|
||||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, KMemoryState state) const {
|
bool KPageTableBase::CanContain(KProcessAddress addr, size_t size, ams::svc::MemoryState state) const {
|
||||||
const KProcessAddress end = addr + size;
|
const KProcessAddress end = addr + size;
|
||||||
const KProcessAddress last = end - 1;
|
const KProcessAddress last = end - 1;
|
||||||
|
|
||||||
@ -449,32 +449,32 @@ namespace ams::kern {
|
|||||||
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_heap_region_start || m_heap_region_end <= addr || m_heap_region_start == m_heap_region_end);
|
||||||
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_alias_region_start || m_alias_region_end <= addr || m_alias_region_start == m_alias_region_end);
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case KMemoryState_Free:
|
case ams::svc::MemoryState_Free:
|
||||||
case KMemoryState_Kernel:
|
case ams::svc::MemoryState_Kernel:
|
||||||
return is_in_region;
|
return is_in_region;
|
||||||
case KMemoryState_Io:
|
case ams::svc::MemoryState_Io:
|
||||||
case KMemoryState_Static:
|
case ams::svc::MemoryState_Static:
|
||||||
case KMemoryState_Code:
|
case ams::svc::MemoryState_Code:
|
||||||
case KMemoryState_CodeData:
|
case ams::svc::MemoryState_CodeData:
|
||||||
case KMemoryState_Shared:
|
case ams::svc::MemoryState_Shared:
|
||||||
case KMemoryState_AliasCode:
|
case ams::svc::MemoryState_AliasCode:
|
||||||
case KMemoryState_AliasCodeData:
|
case ams::svc::MemoryState_AliasCodeData:
|
||||||
case KMemoryState_Stack:
|
case ams::svc::MemoryState_Stack:
|
||||||
case KMemoryState_ThreadLocal:
|
case ams::svc::MemoryState_ThreadLocal:
|
||||||
case KMemoryState_Transfered:
|
case ams::svc::MemoryState_Transfered:
|
||||||
case KMemoryState_SharedTransfered:
|
case ams::svc::MemoryState_SharedTransfered:
|
||||||
case KMemoryState_SharedCode:
|
case ams::svc::MemoryState_SharedCode:
|
||||||
case KMemoryState_GeneratedCode:
|
case ams::svc::MemoryState_GeneratedCode:
|
||||||
case KMemoryState_CodeOut:
|
case ams::svc::MemoryState_CodeOut:
|
||||||
case KMemoryState_Coverage:
|
case ams::svc::MemoryState_Coverage:
|
||||||
case KMemoryState_Insecure:
|
case ams::svc::MemoryState_Insecure:
|
||||||
return is_in_region && !is_in_heap && !is_in_alias;
|
return is_in_region && !is_in_heap && !is_in_alias;
|
||||||
case KMemoryState_Normal:
|
case ams::svc::MemoryState_Normal:
|
||||||
MESOSPHERE_ASSERT(is_in_heap);
|
MESOSPHERE_ASSERT(is_in_heap);
|
||||||
return is_in_region && !is_in_alias;
|
return is_in_region && !is_in_alias;
|
||||||
case KMemoryState_Ipc:
|
case ams::svc::MemoryState_Ipc:
|
||||||
case KMemoryState_NonSecureIpc:
|
case ams::svc::MemoryState_NonSecureIpc:
|
||||||
case KMemoryState_NonDeviceIpc:
|
case ams::svc::MemoryState_NonDeviceIpc:
|
||||||
MESOSPHERE_ASSERT(is_in_alias);
|
MESOSPHERE_ASSERT(is_in_alias);
|
||||||
return is_in_region && !is_in_heap;
|
return is_in_region && !is_in_heap;
|
||||||
default:
|
default:
|
||||||
@ -527,17 +527,12 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
/* Get information about the first block. */
|
/* Get information about the first block. */
|
||||||
const KProcessAddress last_addr = addr + size - 1;
|
|
||||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
|
|
||||||
KMemoryInfo info = it->GetMemoryInfo();
|
KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
/* If the start address isn't aligned, we need a block. */
|
|
||||||
const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
|
|
||||||
|
|
||||||
/* Validate all blocks in the range have correct state. */
|
/* Validate all blocks in the range have correct state. */
|
||||||
const KMemoryState first_state = info.m_state;
|
const KMemoryState first_state = info.m_state;
|
||||||
const KMemoryPermission first_perm = info.m_permission;
|
const KMemoryPermission first_perm = info.m_permission;
|
||||||
@ -562,9 +557,6 @@ namespace ams::kern {
|
|||||||
info = it->GetMemoryInfo();
|
info = it->GetMemoryInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the end address isn't aligned, we need a block. */
|
|
||||||
const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
|
||||||
|
|
||||||
/* Write output state. */
|
/* Write output state. */
|
||||||
if (out_state != nullptr) {
|
if (out_state != nullptr) {
|
||||||
*out_state = first_state;
|
*out_state = first_state;
|
||||||
@ -575,9 +567,29 @@ namespace ams::kern {
|
|||||||
if (out_attr != nullptr) {
|
if (out_attr != nullptr) {
|
||||||
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
*out_attr = static_cast<KMemoryAttribute>(first_attr & ~ignore_attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If the end address isn't aligned, we need a block. */
|
||||||
if (out_blocks_needed != nullptr) {
|
if (out_blocks_needed != nullptr) {
|
||||||
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress()) ? 1 : 0;
|
||||||
|
*out_blocks_needed = blocks_for_end_align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
||||||
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
/* Check memory state. */
|
||||||
|
const KProcessAddress last_addr = addr + size - 1;
|
||||||
|
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
|
||||||
|
R_TRY(this->CheckMemoryState(out_state, out_perm, out_attr, out_blocks_needed, it, last_addr, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr))
|
||||||
|
|
||||||
|
/* If the start address isn't aligned, we need a block. */
|
||||||
|
if (out_blocks_needed != nullptr && util::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) {
|
||||||
|
++(*out_blocks_needed);
|
||||||
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,7 +717,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, KMemoryState state) const {
|
Result KPageTableBase::QueryMappingImpl(KProcessAddress *out, KPhysicalAddress address, size_t size, ams::svc::MemoryState state) const {
|
||||||
MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(!this->IsLockedByCurrentThread());
|
||||||
MESOSPHERE_ASSERT(out != nullptr);
|
MESOSPHERE_ASSERT(out != nullptr);
|
||||||
|
|
||||||
@ -739,7 +751,7 @@ namespace ams::kern {
|
|||||||
if (cur_valid && cur_entry.phys_addr <= address && address + size <= cur_entry.phys_addr + cur_entry.block_size) {
|
if (cur_valid && cur_entry.phys_addr <= address && address + size <= cur_entry.phys_addr + cur_entry.block_size) {
|
||||||
/* Check if this region is valid. */
|
/* Check if this region is valid. */
|
||||||
const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr);
|
const KProcessAddress mapped_address = (region_start + tot_size) + (address - cur_entry.phys_addr);
|
||||||
if (R_SUCCEEDED(this->CheckMemoryState(mapped_address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
if (R_SUCCEEDED(this->CheckMemoryState(mapped_address, size, KMemoryState_Mask, static_cast<KMemoryState>(util::ToUnderlying(state)), KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||||
/* It is! */
|
/* It is! */
|
||||||
*out = mapped_address;
|
*out = mapped_address;
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@ -975,7 +987,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Verify that the destination memory is aliasable code. */
|
/* Verify that the destination memory is aliasable code. */
|
||||||
size_t num_dst_allocator_blocks;
|
size_t num_dst_allocator_blocks;
|
||||||
R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_FlagCanCodeAlias, KMemoryState_FlagCanCodeAlias, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All, KMemoryAttribute_None));
|
R_TRY(this->CheckMemoryStateContiguous(std::addressof(num_dst_allocator_blocks), dst_address, size, KMemoryState_FlagCanCodeAlias, KMemoryState_FlagCanCodeAlias, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_All & ~KMemoryAttribute_PermissionLocked, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Determine whether any pages being unmapped are code. */
|
/* Determine whether any pages being unmapped are code. */
|
||||||
bool any_code_pages = false;
|
bool any_code_pages = false;
|
||||||
@ -1637,9 +1649,10 @@ namespace ams::kern {
|
|||||||
KMemoryAttribute old_attr;
|
KMemoryAttribute old_attr;
|
||||||
size_t num_allocator_blocks;
|
size_t num_allocator_blocks;
|
||||||
constexpr u32 AttributeTestMask = ~(KMemoryAttribute_SetMask | KMemoryAttribute_DeviceShared);
|
constexpr u32 AttributeTestMask = ~(KMemoryAttribute_SetMask | KMemoryAttribute_DeviceShared);
|
||||||
|
const u32 state_test_mask = ((mask & KMemoryAttribute_Uncached) ? static_cast<u32>(KMemoryState_FlagCanChangeAttribute) : 0) | ((mask & KMemoryAttribute_PermissionLocked) ? static_cast<u32>(KMemoryState_FlagCanPermissionLock) : 0);
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
||||||
addr, size,
|
addr, size,
|
||||||
KMemoryState_FlagCanChangeAttribute, KMemoryState_FlagCanChangeAttribute,
|
state_test_mask, state_test_mask,
|
||||||
KMemoryPermission_None, KMemoryPermission_None,
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
AttributeTestMask, KMemoryAttribute_None, ~AttributeTestMask));
|
AttributeTestMask, KMemoryAttribute_None, ~AttributeTestMask));
|
||||||
|
|
||||||
@ -1651,15 +1664,18 @@ namespace ams::kern {
|
|||||||
/* We're going to perform an update, so create a helper. */
|
/* We're going to perform an update, so create a helper. */
|
||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
/* If we need to, perform a change attribute operation. */
|
||||||
|
if ((mask & KMemoryAttribute_Uncached) != 0) {
|
||||||
/* Determine the new attribute. */
|
/* Determine the new attribute. */
|
||||||
const KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(((old_attr & ~mask) | (attr & mask)));
|
const KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(((old_attr & ~mask) | (attr & mask)));
|
||||||
|
|
||||||
/* Perform operation. */
|
/* Perform operation. */
|
||||||
const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None };
|
const KPageProperties properties = { old_perm, false, (new_attr & KMemoryAttribute_Uncached) != 0, DisableMergeAttribute_None };
|
||||||
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefreshAndFlush, false));
|
R_TRY(this->Operate(updater.GetPageList(), addr, num_pages, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissionsAndRefreshAndFlush, false));
|
||||||
|
}
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, old_state, old_perm, new_attr, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.UpdateAttribute(std::addressof(allocator), addr, num_pages, mask, attr);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@ -1899,7 +1915,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
|
Result KPageTableBase::MapIoImpl(KProcessAddress *out, PageLinkedList *page_list, KPhysicalAddress phys_addr, size_t size, KMemoryState state, KMemoryPermission perm) {
|
||||||
/* Check pre-conditions. */
|
/* Check pre-conditions. */
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
MESOSPHERE_ASSERT(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||||
@ -1915,7 +1931,7 @@ namespace ams::kern {
|
|||||||
const size_t region_size = m_kernel_map_region_end - m_kernel_map_region_start;
|
const size_t region_size = m_kernel_map_region_end - m_kernel_map_region_start;
|
||||||
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, KMemoryState_Io));
|
MESOSPHERE_ASSERT(this->CanContain(region_start, region_size, state));
|
||||||
|
|
||||||
/* Locate the memory region. */
|
/* Locate the memory region. */
|
||||||
const KMemoryRegion *region = KMemoryLayout::Find(phys_addr);
|
const KMemoryRegion *region = KMemoryLayout::Find(phys_addr);
|
||||||
@ -1945,10 +1961,16 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Select an address to map at. */
|
/* Select an address to map at. */
|
||||||
KProcessAddress addr = Null<KProcessAddress>;
|
KProcessAddress addr = Null<KProcessAddress>;
|
||||||
const size_t phys_alignment = std::min(std::min(util::GetAlignment(GetInteger(phys_addr)), util::GetAlignment(size)), MaxPhysicalMapAlignment);
|
|
||||||
for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) {
|
for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) {
|
||||||
const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type));
|
const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type));
|
||||||
if (alignment > phys_alignment) {
|
|
||||||
|
const KPhysicalAddress aligned_phys = util::AlignUp(GetInteger(phys_addr), alignment) + alignment - 1;
|
||||||
|
if (aligned_phys <= phys_addr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KPhysicalAddress last_aligned_paddr = util::AlignDown(GetInteger(last) + 1, alignment) - 1;
|
||||||
|
if (!(last_aligned_paddr <= last && aligned_phys <= last_aligned_paddr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1960,11 +1982,11 @@ namespace ams::kern {
|
|||||||
R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory());
|
R_UNLESS(addr != Null<KProcessAddress>, svc::ResultOutOfMemory());
|
||||||
|
|
||||||
/* Check that we can map IO here. */
|
/* Check that we can map IO here. */
|
||||||
MESOSPHERE_ASSERT(this->CanContain(addr, size, KMemoryState_Io));
|
MESOSPHERE_ASSERT(this->CanContain(addr, size, state));
|
||||||
MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
MESOSPHERE_R_ASSERT(this->CheckMemoryState(addr, size, KMemoryState_All, KMemoryState_Free, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Perform mapping operation. */
|
/* Perform mapping operation. */
|
||||||
const KPageProperties properties = { perm, true, false, DisableMergeAttribute_DisableHead };
|
const KPageProperties properties = { perm, state == KMemoryState_IoRegister, false, DisableMergeAttribute_DisableHead };
|
||||||
R_TRY(this->Operate(page_list, addr, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
R_TRY(this->Operate(page_list, addr, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
||||||
|
|
||||||
/* Set the output address. */
|
/* Set the output address. */
|
||||||
@ -1987,10 +2009,10 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Map the io memory. */
|
/* Map the io memory. */
|
||||||
KProcessAddress addr;
|
KProcessAddress addr;
|
||||||
R_TRY(this->MapIoImpl(std::addressof(addr), updater.GetPageList(), phys_addr, size, perm));
|
R_TRY(this->MapIoImpl(std::addressof(addr), updater.GetPageList(), phys_addr, size, KMemoryState_IoRegister, perm));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), addr, size / PageSize, KMemoryState_Io, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), addr, size / PageSize, KMemoryState_IoRegister, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
|
||||||
/* We successfully mapped the pages. */
|
/* We successfully mapped the pages. */
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@ -2020,7 +2042,8 @@ namespace ams::kern {
|
|||||||
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
R_TRY(this->Operate(updater.GetPageList(), dst_address, num_pages, phys_addr, true, properties, OperationType_Map, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, KMemoryState_Io, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
const auto state = mapping == ams::svc::MemoryMapping_Memory ? KMemoryState_IoMemory : KMemoryState_IoRegister;
|
||||||
|
m_memory_block_manager.Update(std::addressof(allocator), dst_address, num_pages, state, perm, KMemoryAttribute_Locked, KMemoryBlockDisableMergeAttribute_Normal, KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
|
||||||
/* We successfully mapped the pages. */
|
/* We successfully mapped the pages. */
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
@ -2039,7 +2062,7 @@ namespace ams::kern {
|
|||||||
size_t num_allocator_blocks;
|
size_t num_allocator_blocks;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
R_TRY(this->CheckMemoryState(std::addressof(old_state), std::addressof(old_perm), std::addressof(old_attr), std::addressof(num_allocator_blocks),
|
||||||
dst_address, size,
|
dst_address, size,
|
||||||
KMemoryState_All, KMemoryState_Io,
|
KMemoryState_All, mapping == ams::svc::MemoryMapping_Memory ? KMemoryState_IoMemory : KMemoryState_IoRegister,
|
||||||
KMemoryPermission_None, KMemoryPermission_None,
|
KMemoryPermission_None, KMemoryPermission_None,
|
||||||
KMemoryAttribute_All, KMemoryAttribute_Locked));
|
KMemoryAttribute_All, KMemoryAttribute_Locked));
|
||||||
|
|
||||||
@ -2129,10 +2152,16 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Select an address to map at. */
|
/* Select an address to map at. */
|
||||||
KProcessAddress addr = Null<KProcessAddress>;
|
KProcessAddress addr = Null<KProcessAddress>;
|
||||||
const size_t phys_alignment = std::min(std::min(util::GetAlignment(GetInteger(phys_addr)), util::GetAlignment(size)), MaxPhysicalMapAlignment);
|
|
||||||
for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) {
|
for (s32 block_type = KPageTable::GetMaxBlockType(); block_type >= 0; block_type--) {
|
||||||
const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type));
|
const size_t alignment = KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(block_type));
|
||||||
if (alignment > phys_alignment) {
|
|
||||||
|
const KPhysicalAddress aligned_phys = util::AlignUp(GetInteger(phys_addr), alignment) + alignment - 1;
|
||||||
|
if (aligned_phys <= phys_addr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const KPhysicalAddress last_aligned_paddr = util::AlignDown(GetInteger(last) + 1, alignment) - 1;
|
||||||
|
if (!(last_aligned_paddr <= last && aligned_phys <= last_aligned_paddr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2308,7 +2337,7 @@ namespace ams::kern {
|
|||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Perform mapping operation. */
|
/* Perform mapping operation. */
|
||||||
const KPageProperties properties = { perm, state == KMemoryState_Io, false, DisableMergeAttribute_DisableHead };
|
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
|
||||||
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
@ -2343,7 +2372,7 @@ namespace ams::kern {
|
|||||||
KScopedPageTableUpdater updater(this);
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
/* Perform mapping operation. */
|
/* Perform mapping operation. */
|
||||||
const KPageProperties properties = { perm, state == KMemoryState_Io, false, DisableMergeAttribute_DisableHead };
|
const KPageProperties properties = { perm, false, false, DisableMergeAttribute_DisableHead };
|
||||||
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||||
|
|
||||||
/* Update the blocks. */
|
/* Update the blocks. */
|
||||||
@ -2479,6 +2508,23 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result KPageTableBase::InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size) {
|
||||||
|
/* Check pre-condition: this is being called on the current process. */
|
||||||
|
MESOSPHERE_ASSERT(this == std::addressof(GetCurrentProcess().GetPageTable().GetBasePageTable()));
|
||||||
|
|
||||||
|
/* Check that the region is in range. */
|
||||||
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
|
/* Lock the table. */
|
||||||
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
/* Check the memory state. */
|
||||||
|
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagReferenceCounted, KMemoryState_FlagReferenceCounted, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_Uncached, KMemoryAttribute_None));
|
||||||
|
|
||||||
|
/* Invalidate the data cache. */
|
||||||
|
R_RETURN(cpu::InvalidateDataCache(GetVoidPointer(address), size));
|
||||||
|
}
|
||||||
|
|
||||||
Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||||
/* Lightly validate the region is in range. */
|
/* Lightly validate the region is in range. */
|
||||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
@ -2653,7 +2699,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size) {
|
Result KPageTableBase::ReadIoMemoryImpl(void *buffer, KPhysicalAddress phys_addr, size_t size, KMemoryState state) {
|
||||||
/* Check pre-conditions. */
|
/* Check pre-conditions. */
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
@ -2667,7 +2713,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Temporarily map the io memory. */
|
/* Temporarily map the io memory. */
|
||||||
KProcessAddress io_addr;
|
KProcessAddress io_addr;
|
||||||
R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, KMemoryPermission_UserRead));
|
R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, state, KMemoryPermission_UserRead));
|
||||||
|
|
||||||
/* Ensure we unmap the io memory when we're done with it. */
|
/* Ensure we unmap the io memory when we're done with it. */
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
@ -2698,7 +2744,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size) {
|
Result KPageTableBase::WriteIoMemoryImpl(KPhysicalAddress phys_addr, const void *buffer, size_t size, KMemoryState state) {
|
||||||
/* Check pre-conditions. */
|
/* Check pre-conditions. */
|
||||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
@ -2712,7 +2758,7 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Temporarily map the io memory. */
|
/* Temporarily map the io memory. */
|
||||||
KProcessAddress io_addr;
|
KProcessAddress io_addr;
|
||||||
R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, KMemoryPermission_UserReadWrite));
|
R_TRY(this->MapIoImpl(std::addressof(io_addr), updater.GetPageList(), map_start, map_size, state, KMemoryPermission_UserReadWrite));
|
||||||
|
|
||||||
/* Ensure we unmap the io memory when we're done with it. */
|
/* Ensure we unmap the io memory when we're done with it. */
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
@ -2743,7 +2789,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size) {
|
Result KPageTableBase::ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) {
|
||||||
/* Lightly validate the range before doing anything else. */
|
/* Lightly validate the range before doing anything else. */
|
||||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
@ -2755,7 +2801,7 @@ namespace ams::kern {
|
|||||||
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock);
|
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock);
|
||||||
|
|
||||||
/* Check that the desired range is readable io memory. */
|
/* Check that the desired range is readable io memory. */
|
||||||
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, state, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
u8 *dst = static_cast<u8 *>(buffer);
|
u8 *dst = static_cast<u8 *>(buffer);
|
||||||
@ -2769,7 +2815,7 @@ namespace ams::kern {
|
|||||||
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, util::AlignDown(GetInteger(address) + PageSize, PageSize) - GetInteger(address));
|
||||||
|
|
||||||
/* Read. */
|
/* Read. */
|
||||||
R_TRY(dst_page_table.ReadIoMemoryImpl(dst, phys_addr, cur_size));
|
R_TRY(dst_page_table.ReadIoMemoryImpl(dst, phys_addr, cur_size, state));
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
address += cur_size;
|
address += cur_size;
|
||||||
@ -2779,7 +2825,7 @@ namespace ams::kern {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTableBase::WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size) {
|
Result KPageTableBase::WriteDebugIoMemory(KProcessAddress address, const void *buffer, size_t size, KMemoryState state) {
|
||||||
/* Lightly validate the range before doing anything else. */
|
/* Lightly validate the range before doing anything else. */
|
||||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
@ -2791,7 +2837,7 @@ namespace ams::kern {
|
|||||||
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock);
|
KScopedLightLockPair lk(src_page_table.m_general_lock, dst_page_table.m_general_lock);
|
||||||
|
|
||||||
/* Check that the desired range is writable io memory. */
|
/* Check that the desired range is writable io memory. */
|
||||||
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, KMemoryState_Io, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None));
|
R_TRY(this->CheckMemoryStateContiguous(address, size, KMemoryState_All, state, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||||
|
|
||||||
/* Read the memory. */
|
/* Read the memory. */
|
||||||
const u8 *src = static_cast<const u8 *>(buffer);
|
const u8 *src = static_cast<const u8 *>(buffer);
|
||||||
@ -2805,7 +2851,7 @@ namespace ams::kern {
|
|||||||
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, util::AlignDown(GetInteger(address) + PageSize, PageSize) - GetInteger(address));
|
||||||
|
|
||||||
/* Read. */
|
/* Read. */
|
||||||
R_TRY(dst_page_table.WriteIoMemoryImpl(phys_addr, src, cur_size));
|
R_TRY(dst_page_table.WriteIoMemoryImpl(phys_addr, src, cur_size, state));
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
address += cur_size;
|
address += cur_size;
|
||||||
@ -2838,7 +2884,7 @@ namespace ams::kern {
|
|||||||
m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
m_memory_block_manager.UpdateLock(std::addressof(allocator), address, num_pages, &KMemoryBlock::ShareToDevice, KMemoryPermission_None);
|
||||||
|
|
||||||
/* Set whether the locked memory was io. */
|
/* Set whether the locked memory was io. */
|
||||||
*out_is_io = old_state == KMemoryState_Io;
|
*out_is_io = static_cast<ams::svc::MemoryState>(old_state & KMemoryState_Mask) == ams::svc::MemoryState_Io;
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@ -4406,11 +4452,21 @@ namespace ams::kern {
|
|||||||
/* If it's unmapped, we need to map it. */
|
/* If it's unmapped, we need to map it. */
|
||||||
if (info.GetState() == KMemoryState_Free) {
|
if (info.GetState() == KMemoryState_Free) {
|
||||||
/* Determine the range to map. */
|
/* Determine the range to map. */
|
||||||
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, DisableMergeAttribute_None };
|
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, cur_address == this->GetAliasRegionStart() ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
||||||
size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize;
|
size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||||
|
|
||||||
/* While we have pages to map, map them. */
|
/* While we have pages to map, map them. */
|
||||||
while (map_pages > 0) {
|
{
|
||||||
|
/* Create a page group for the current mapping range. */
|
||||||
|
KPageGroup cur_pg(m_block_info_manager);
|
||||||
|
{
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
cur_pg.OpenFirst();
|
||||||
|
cur_pg.Close();
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t remain_pages = map_pages;
|
||||||
|
while (remain_pages > 0) {
|
||||||
/* Check if we're at the end of the physical block. */
|
/* Check if we're at the end of the physical block. */
|
||||||
if (pg_pages == 0) {
|
if (pg_pages == 0) {
|
||||||
/* Ensure there are more pages to map. */
|
/* Ensure there are more pages to map. */
|
||||||
@ -4422,19 +4478,21 @@ namespace ams::kern {
|
|||||||
pg_pages = pg_it->GetNumPages();
|
pg_pages = pg_it->GetNumPages();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Map whatever we can. */
|
/* Add whatever we can to the current block. */
|
||||||
const size_t cur_pages = std::min(pg_pages, map_pages);
|
const size_t cur_pages = std::min(pg_pages, remain_pages);
|
||||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, map_properties, OperationType_MapFirst, false));
|
R_TRY(cur_pg.AddBlock(pg_phys_addr + ((pg_pages - cur_pages) * PageSize), cur_pages));
|
||||||
|
|
||||||
/* Advance. */
|
/* Advance. */
|
||||||
cur_address += cur_pages * PageSize;
|
remain_pages -= cur_pages;
|
||||||
map_pages -= cur_pages;
|
|
||||||
|
|
||||||
pg_phys_addr += cur_pages * PageSize;
|
|
||||||
pg_pages -= cur_pages;
|
pg_pages -= cur_pages;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map the papges. */
|
||||||
|
R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, cur_pg, map_properties, OperationType_MapFirstGroup, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if we're done. */
|
/* Check if we're done. */
|
||||||
if (last_address <= info.GetLastAddress()) {
|
if (last_address <= info.GetLastAddress()) {
|
||||||
break;
|
break;
|
||||||
@ -4454,7 +4512,9 @@ namespace ams::kern {
|
|||||||
/* Update the relevant memory blocks. */
|
/* Update the relevant memory blocks. */
|
||||||
m_memory_block_manager.UpdateIfMatch(std::addressof(allocator), address, size / PageSize,
|
m_memory_block_manager.UpdateIfMatch(std::addressof(allocator), address, size / PageSize,
|
||||||
KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None,
|
KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None,
|
||||||
KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None);
|
KMemoryState_Normal, KMemoryPermission_UserReadWrite, KMemoryAttribute_None,
|
||||||
|
address == this->GetAliasRegionStart() ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None,
|
||||||
|
KMemoryBlockDisableMergeAttribute_None);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
@ -4549,6 +4609,9 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Iterate over the memory, unmapping as we go. */
|
/* Iterate over the memory, unmapping as we go. */
|
||||||
auto it = m_memory_block_manager.FindIterator(cur_address);
|
auto it = m_memory_block_manager.FindIterator(cur_address);
|
||||||
|
|
||||||
|
const auto clear_merge_attr = (it->GetState() == KMemoryState_Normal && it->GetAddress() == this->GetAliasRegionStart() && it->GetAddress() == address) ? KMemoryBlockDisableMergeAttribute_Normal : KMemoryBlockDisableMergeAttribute_None;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/* Check that the iterator is valid. */
|
/* Check that the iterator is valid. */
|
||||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||||
@ -4581,7 +4644,7 @@ namespace ams::kern {
|
|||||||
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, mapped_size);
|
m_resource_limit->Release(ams::svc::LimitableResource_PhysicalMemoryMax, mapped_size);
|
||||||
|
|
||||||
/* Update memory blocks. */
|
/* Update memory blocks. */
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, KMemoryBlockDisableMergeAttribute_None);
|
m_memory_block_manager.Update(std::addressof(allocator), address, size / PageSize, KMemoryState_Free, KMemoryPermission_None, KMemoryAttribute_None, KMemoryBlockDisableMergeAttribute_None, clear_merge_attr);
|
||||||
|
|
||||||
/* We succeeded. */
|
/* We succeeded. */
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
|
@ -263,28 +263,47 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_ASSERT(res_limit != nullptr);
|
MESOSPHERE_ASSERT(res_limit != nullptr);
|
||||||
MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast<size_t>(params.code_num_pages));
|
MESOSPHERE_ABORT_UNLESS((params.code_num_pages * PageSize) / PageSize == static_cast<size_t>(params.code_num_pages));
|
||||||
|
|
||||||
/* Determine is application. */
|
|
||||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication) != 0;
|
|
||||||
|
|
||||||
/* Set members. */
|
/* Set members. */
|
||||||
m_memory_pool = pool;
|
m_memory_pool = pool;
|
||||||
m_resource_limit = res_limit;
|
m_resource_limit = res_limit;
|
||||||
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
m_is_default_application_system_resource = false;
|
||||||
m_is_immortal = immortal;
|
m_is_immortal = immortal;
|
||||||
|
|
||||||
/* Open reference to our system resource. */
|
/* Setup our system resource. */
|
||||||
|
if (const size_t system_resource_num_pages = params.system_resource_num_pages; system_resource_num_pages != 0) {
|
||||||
|
/* Create a secure system resource. */
|
||||||
|
KSecureSystemResource *secure_resource = KSecureSystemResource::Create();
|
||||||
|
R_UNLESS(secure_resource != nullptr, svc::ResultOutOfResource());
|
||||||
|
|
||||||
|
ON_RESULT_FAILURE { secure_resource->Close(); };
|
||||||
|
|
||||||
|
/* Initialize the secure resource. */
|
||||||
|
R_TRY(secure_resource->Initialize(system_resource_num_pages * PageSize, m_resource_limit, m_memory_pool));
|
||||||
|
|
||||||
|
/* Set our system resource. */
|
||||||
|
m_system_resource = secure_resource;
|
||||||
|
} else {
|
||||||
|
/* Use the system-wide system resource. */
|
||||||
|
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
||||||
|
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
||||||
|
|
||||||
|
m_is_default_application_system_resource = is_app;
|
||||||
|
|
||||||
|
/* Open reference to the system resource. */
|
||||||
m_system_resource->Open();
|
m_system_resource->Open();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure we clean up our secure resource, if we fail. */
|
||||||
|
ON_RESULT_FAILURE { m_system_resource->Close(); };
|
||||||
|
|
||||||
/* Setup page table. */
|
/* Setup page table. */
|
||||||
/* NOTE: Nintendo passes process ID despite not having set it yet. */
|
|
||||||
/* This goes completely unused, but even so... */
|
|
||||||
{
|
{
|
||||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
||||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit));
|
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 { m_page_table.Finalize(); };
|
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||||
|
|
||||||
/* Ensure we can insert the code region. */
|
/* Ensure we can insert the code region. */
|
||||||
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, KMemoryState_Code), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, KMemoryState_Code), svc::ResultInvalidMemoryRegion());
|
||||||
@ -317,6 +336,7 @@ namespace ams::kern {
|
|||||||
/* Set pool and resource limit. */
|
/* Set pool and resource limit. */
|
||||||
m_memory_pool = pool;
|
m_memory_pool = pool;
|
||||||
m_resource_limit = res_limit;
|
m_resource_limit = res_limit;
|
||||||
|
m_is_default_application_system_resource = false;
|
||||||
m_is_immortal = false;
|
m_is_immortal = false;
|
||||||
|
|
||||||
/* Get the memory sizes. */
|
/* Get the memory sizes. */
|
||||||
@ -348,6 +368,8 @@ namespace ams::kern {
|
|||||||
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
const bool is_app = (params.flags & ams::svc::CreateProcessFlag_IsApplication);
|
||||||
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
m_system_resource = std::addressof(is_app ? Kernel::GetApplicationSystemResource() : Kernel::GetSystemSystemResource());
|
||||||
|
|
||||||
|
m_is_default_application_system_resource = is_app;
|
||||||
|
|
||||||
/* Open reference to the system resource. */
|
/* Open reference to the system resource. */
|
||||||
m_system_resource->Open();
|
m_system_resource->Open();
|
||||||
}
|
}
|
||||||
@ -356,13 +378,11 @@ namespace ams::kern {
|
|||||||
ON_RESULT_FAILURE { m_system_resource->Close(); };
|
ON_RESULT_FAILURE { m_system_resource->Close(); };
|
||||||
|
|
||||||
/* Setup page table. */
|
/* Setup page table. */
|
||||||
/* NOTE: Nintendo passes process ID despite not having set it yet. */
|
|
||||||
/* This goes completely unused, but even so... */
|
|
||||||
{
|
{
|
||||||
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
const auto as_type = static_cast<ams::svc::CreateProcessFlag>(params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask);
|
||||||
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
const bool enable_aslr = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) != 0;
|
||||||
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
const bool enable_das_merge = (params.flags & ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge) == 0;
|
||||||
R_TRY(m_page_table.Initialize(m_process_id, as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, params.code_address, code_size, m_system_resource, res_limit));
|
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(); };
|
||||||
|
|
||||||
@ -471,7 +491,7 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_LOG("KProcess::Exit() pid=%ld name=%-12s\n", m_process_id, m_name);
|
MESOSPHERE_LOG("KProcess::Exit() pid=%ld name=%-12s\n", m_process_id, m_name);
|
||||||
|
|
||||||
/* Register the process as a work task. */
|
/* Register the process as a work task. */
|
||||||
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_Exit, this);
|
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitProcess, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exit the current thread. */
|
/* Exit the current thread. */
|
||||||
@ -516,7 +536,7 @@ namespace ams::kern {
|
|||||||
MESOSPHERE_LOG("KProcess::Terminate() FAIL pid=%ld name=%-12s\n", m_process_id, m_name);
|
MESOSPHERE_LOG("KProcess::Terminate() FAIL pid=%ld name=%-12s\n", m_process_id, m_name);
|
||||||
|
|
||||||
/* Register the process as a work task. */
|
/* Register the process as a work task. */
|
||||||
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_Exit, this);
|
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitProcess, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,7 +868,7 @@ namespace ams::kern {
|
|||||||
size_t KProcess::GetUsedUserPhysicalMemorySize() const {
|
size_t KProcess::GetUsedUserPhysicalMemorySize() const {
|
||||||
const size_t norm_size = m_page_table.GetNormalMemorySize();
|
const size_t norm_size = m_page_table.GetNormalMemorySize();
|
||||||
const size_t other_size = m_code_size + m_main_thread_stack_size;
|
const size_t other_size = m_code_size + m_main_thread_stack_size;
|
||||||
const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
const size_t sec_size = this->GetRequiredSecureMemorySizeNonDefault();
|
||||||
|
|
||||||
return norm_size + other_size + sec_size;
|
return norm_size + other_size + sec_size;
|
||||||
}
|
}
|
||||||
@ -856,13 +876,20 @@ namespace ams::kern {
|
|||||||
size_t KProcess::GetTotalUserPhysicalMemorySize() const {
|
size_t KProcess::GetTotalUserPhysicalMemorySize() const {
|
||||||
/* Get the amount of free and used size. */
|
/* Get the amount of free and used size. */
|
||||||
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
||||||
const size_t used_size = this->GetUsedUserPhysicalMemorySize();
|
|
||||||
const size_t max_size = m_max_process_memory;
|
const size_t max_size = m_max_process_memory;
|
||||||
|
|
||||||
|
/* Determine used size. */
|
||||||
|
/* NOTE: This does *not* check this->IsDefaultApplicationSystemResource(), unlike GetUsedUserPhysicalMemorySize(). */
|
||||||
|
const size_t norm_size = m_page_table.GetNormalMemorySize();
|
||||||
|
const size_t other_size = m_code_size + m_main_thread_stack_size;
|
||||||
|
const size_t sec_size = this->GetRequiredSecureMemorySize();
|
||||||
|
const size_t used_size = norm_size + other_size + sec_size;
|
||||||
|
|
||||||
|
/* NOTE: These function calls will recalculate, introducing a race...it is unclear why Nintendo does it this way. */
|
||||||
if (used_size + free_size > max_size) {
|
if (used_size + free_size > max_size) {
|
||||||
return max_size;
|
return max_size;
|
||||||
} else {
|
} else {
|
||||||
return free_size + used_size;
|
return free_size + this->GetUsedUserPhysicalMemorySize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -876,14 +903,20 @@ namespace ams::kern {
|
|||||||
size_t KProcess::GetTotalNonSystemUserPhysicalMemorySize() const {
|
size_t KProcess::GetTotalNonSystemUserPhysicalMemorySize() const {
|
||||||
/* Get the amount of free and used size. */
|
/* Get the amount of free and used size. */
|
||||||
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
const size_t free_size = m_resource_limit->GetFreeValue(ams::svc::LimitableResource_PhysicalMemoryMax);
|
||||||
const size_t used_size = this->GetUsedUserPhysicalMemorySize();
|
|
||||||
const size_t sec_size = m_system_resource->IsSecureResource() ? static_cast<KSecureSystemResource *>(m_system_resource)->CalculateRequiredSecureMemorySize() : 0;
|
|
||||||
const size_t max_size = m_max_process_memory;
|
const size_t max_size = m_max_process_memory;
|
||||||
|
|
||||||
|
/* Determine used size. */
|
||||||
|
/* NOTE: This does *not* check this->IsDefaultApplicationSystemResource(), unlike GetUsedUserPhysicalMemorySize(). */
|
||||||
|
const size_t norm_size = m_page_table.GetNormalMemorySize();
|
||||||
|
const size_t other_size = m_code_size + m_main_thread_stack_size;
|
||||||
|
const size_t sec_size = this->GetRequiredSecureMemorySize();
|
||||||
|
const size_t used_size = norm_size + other_size + sec_size;
|
||||||
|
|
||||||
|
/* NOTE: These function calls will recalculate, introducing a race...it is unclear why Nintendo does it this way. */
|
||||||
if (used_size + free_size > max_size) {
|
if (used_size + free_size > max_size) {
|
||||||
return max_size - sec_size;
|
return max_size - this->GetRequiredSecureMemorySizeNonDefault();
|
||||||
} else {
|
} else {
|
||||||
return free_size + used_size - sec_size;
|
return free_size + this->GetUsedNonSystemUserPhysicalMemorySize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -476,10 +476,6 @@ namespace ams::kern {
|
|||||||
m_parent->ClearRunningThread(this);
|
m_parent->ClearRunningThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Signal. */
|
|
||||||
m_signaled = true;
|
|
||||||
KSynchronizationObject::NotifyAvailable();
|
|
||||||
|
|
||||||
/* Call the on thread termination handler. */
|
/* Call the on thread termination handler. */
|
||||||
KThreadContext::OnThreadTerminating(this);
|
KThreadContext::OnThreadTerminating(this);
|
||||||
|
|
||||||
@ -507,6 +503,13 @@ namespace ams::kern {
|
|||||||
cpu::SynchronizeCores(m_parent->GetPhysicalCoreMask());
|
cpu::SynchronizeCores(m_parent->GetPhysicalCoreMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Acquire the scheduler lock. */
|
||||||
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
|
/* Signal. */
|
||||||
|
m_signaled = true;
|
||||||
|
KSynchronizationObject::NotifyAvailable();
|
||||||
|
|
||||||
/* Close the thread. */
|
/* Close the thread. */
|
||||||
this->Close();
|
this->Close();
|
||||||
}
|
}
|
||||||
@ -1328,7 +1331,7 @@ namespace ams::kern {
|
|||||||
this->StartTermination();
|
this->StartTermination();
|
||||||
|
|
||||||
/* Register the thread as a work task. */
|
/* Register the thread as a work task. */
|
||||||
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_Exit, this);
|
KWorkerTaskManager::AddTask(KWorkerTaskManager::WorkerType_ExitThread, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
MESOSPHERE_PANIC("KThread::Exit() would return");
|
MESOSPHERE_PANIC("KThread::Exit() would return");
|
||||||
|
@ -115,8 +115,9 @@ namespace ams::kern {
|
|||||||
|
|
||||||
/* Perform more core-0 specific initialization. */
|
/* Perform more core-0 specific initialization. */
|
||||||
if (core_id == 0) {
|
if (core_id == 0) {
|
||||||
/* Initialize the exit worker manager, so that threads and processes may exit cleanly. */
|
/* Initialize the exit worker managers, so that threads and processes may exit cleanly. */
|
||||||
Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_Exit).Initialize(KWorkerTaskManager::ExitWorkerPriority);
|
Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_ExitThread).Initialize(KWorkerTaskManager::ExitWorkerPriority);
|
||||||
|
Kernel::GetWorkerTaskManager(KWorkerTaskManager::WorkerType_ExitProcess).Initialize(KWorkerTaskManager::ExitWorkerPriority);
|
||||||
|
|
||||||
/* Setup so that we may sleep later, and reserve memory for secure applets. */
|
/* Setup so that we may sleep later, and reserve memory for secure applets. */
|
||||||
KSystemControl::InitializePhase2();
|
KSystemControl::InitializePhase2();
|
||||||
|
@ -102,7 +102,11 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||||
|
|
||||||
/* Invalidate the cache. */
|
/* Invalidate the cache. */
|
||||||
|
if (process.GetPointerUnsafe() == GetCurrentProcessPointer()) {
|
||||||
|
R_TRY(process->GetPageTable().InvalidateCurrentProcessDataCache(address, size));
|
||||||
|
} else {
|
||||||
R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size));
|
R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size));
|
||||||
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
@ -127,7 +127,7 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Verify that the mapping is in range. */
|
/* Verify that the mapping is in range. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Io), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, ams::svc::MemoryState_Io), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Validate the map permission. */
|
/* Validate the map permission. */
|
||||||
R_UNLESS(IsValidIoRegionPermission(map_perm), svc::ResultInvalidNewMemoryPermission());
|
R_UNLESS(IsValidIoRegionPermission(map_perm), svc::ResultInvalidNewMemoryPermission());
|
||||||
@ -156,7 +156,7 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Verify that the mapping is in range. */
|
/* Verify that the mapping is in range. */
|
||||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_Io), svc::ResultInvalidMemoryRegion());
|
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, ams::svc::MemoryState_Io), svc::ResultInvalidMemoryRegion());
|
||||||
|
|
||||||
/* Get the io region. */
|
/* Get the io region. */
|
||||||
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle);
|
KScopedAutoObject io_region = GetCurrentProcess().GetHandleTable().GetObject<KIoRegion>(io_region_handle);
|
||||||
|
@ -58,10 +58,13 @@ namespace ams::kern::svc {
|
|||||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||||
|
|
||||||
/* Validate the attribute and mask. */
|
/* Validate the attribute and mask. */
|
||||||
constexpr u32 SupportedMask = ams::svc::MemoryAttribute_Uncached;
|
constexpr u32 SupportedMask = ams::svc::MemoryAttribute_Uncached | ams::svc::MemoryAttribute_PermissionLocked;
|
||||||
R_UNLESS((mask | attr) == mask, svc::ResultInvalidCombination());
|
R_UNLESS((mask | attr) == mask, svc::ResultInvalidCombination());
|
||||||
R_UNLESS((mask | attr | SupportedMask) == SupportedMask, svc::ResultInvalidCombination());
|
R_UNLESS((mask | attr | SupportedMask) == SupportedMask, svc::ResultInvalidCombination());
|
||||||
|
|
||||||
|
/* Check that permission locked is either being set or not masked. */
|
||||||
|
R_UNLESS((mask & ams::svc::MemoryAttribute_PermissionLocked) == (attr & ams::svc::MemoryAttribute_PermissionLocked), svc::ResultInvalidCombination());
|
||||||
|
|
||||||
/* Validate that the region is in range for the current process. */
|
/* Validate that the region is in range for the current process. */
|
||||||
auto &page_table = GetCurrentProcess().GetPageTable();
|
auto &page_table = GetCurrentProcess().GetPageTable();
|
||||||
R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
R_UNLESS(page_table.Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||||
|
@ -25,6 +25,7 @@ namespace ams::exosphere {
|
|||||||
void ForceRebootToRcm();
|
void ForceRebootToRcm();
|
||||||
void ForceRebootToIramPayload();
|
void ForceRebootToIramPayload();
|
||||||
void ForceRebootToFatalError();
|
void ForceRebootToFatalError();
|
||||||
|
void ForceRebootByPmic();
|
||||||
void ForceShutdown();
|
void ForceShutdown();
|
||||||
|
|
||||||
bool IsRcmBugPatched();
|
bool IsRcmBugPatched();
|
||||||
|
@ -178,6 +178,8 @@
|
|||||||
HANDLER(BuiltInWirelessOUIInfo, 137) \
|
HANDLER(BuiltInWirelessOUIInfo, 137) \
|
||||||
HANDLER(WirelessAPOUIInfo, 138) \
|
HANDLER(WirelessAPOUIInfo, 138) \
|
||||||
HANDLER(EthernetAdapterOUIInfo, 139) \
|
HANDLER(EthernetAdapterOUIInfo, 139) \
|
||||||
|
HANDLER(NANDTypeInfo, 140) \
|
||||||
|
HANDLER(MicroSDTypeInfo, 141) \
|
||||||
|
|
||||||
#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 ) \
|
||||||
@ -850,4 +852,15 @@
|
|||||||
HANDLER(BuiltInWirelessOUI, 667, BuiltInWirelessOUIInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(BuiltInWirelessOUI, 667, BuiltInWirelessOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(WirelessAPOUI, 668, WirelessAPOUIInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(WirelessAPOUI, 668, WirelessAPOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
HANDLER(EthernetAdapterOUI, 669, EthernetAdapterOUIInfo, FieldType_String, FieldFlag_None ) \
|
HANDLER(EthernetAdapterOUI, 669, EthernetAdapterOUIInfo, FieldType_String, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisSystemFatSafeControlResult, 670, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisSystemFatErrorNumber, 671, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisSystemFatSafeErrorNumber, 672, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisUserFatSafeControlResult, 673, FsProxyErrorInfo2, FieldType_NumericU8, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisUserFatErrorNumber, 674, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(FatFsBisUserFatSafeErrorNumber, 675, FsProxyErrorInfo2, FieldType_NumericI32, FieldFlag_None ) \
|
||||||
|
HANDLER(GpuCrashDump2, 676, GpuCrashInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||||
|
HANDLER(NANDType, 677, NANDTypeInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||||
|
HANDLER(MicroSDType, 678, MicroSDTypeInfo, FieldType_U8Array, FieldFlag_None ) \
|
||||||
|
HANDLER(GameCardLastDeactivateReasonResult, 679, GameCardErrorInfo, FieldType_NumericU32, FieldFlag_None ) \
|
||||||
|
HANDLER(GameCardLastDeactivateReason, 680, GameCardErrorInfo, FieldType_NumericU8, FieldFlag_None ) \
|
||||||
|
|
||||||
|
@ -111,6 +111,14 @@ namespace ams::erpt {
|
|||||||
static_assert(util::is_pod<ReportFlagSet>::value);
|
static_assert(util::is_pod<ReportFlagSet>::value);
|
||||||
static_assert(sizeof(ReportFlagSet) == sizeof(u32));
|
static_assert(sizeof(ReportFlagSet) == sizeof(u32));
|
||||||
|
|
||||||
|
struct CreateReportOptionFlag {
|
||||||
|
using SubmitFsInfo = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>::Flag<0>;
|
||||||
|
};
|
||||||
|
|
||||||
|
using CreateReportOptionFlagSet = util::BitFlagSet<BITSIZEOF(u32), CreateReportOptionFlag>;
|
||||||
|
static_assert(util::is_pod<CreateReportOptionFlagSet>::value);
|
||||||
|
static_assert(sizeof(CreateReportOptionFlagSet) == sizeof(u32));
|
||||||
|
|
||||||
struct ReportInfo {
|
struct ReportInfo {
|
||||||
ReportType type;
|
ReportType type;
|
||||||
ReportId id;
|
ReportId id;
|
||||||
|
@ -32,8 +32,10 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 8, Result, ClearApplicationLaunchTime, (), (), hos::Version_6_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 8, Result, ClearApplicationLaunchTime, (), (), hos::Version_6_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out<erpt::AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), (out, attachment_name, attachment_data), hos::Version_8_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 9, Result, SubmitAttachment, (ams::sf::Out<erpt::AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data), (out, attachment_name, attachment_data), hos::Version_8_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer), hos::Version_8_0_0, hos::Version_10_2_0) \
|
AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer), hos::Version_8_0_0, hos::Version_10_2_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachments, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer, result), hos::Version_11_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachmentsDeprecated2, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer, result), hos::Version_11_0_0, hos::Version_16_1_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 11, Result, CreateReport, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result), (report_type, ctx_buffer, str_buffer, meta_buffer, result), hos::Version_11_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 10, Result, CreateReportWithAttachments, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags), (report_type, ctx_buffer, str_buffer, attachment_ids_buffer, result, flags), hos::Version_17_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 11, Result, CreateReportV1, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result), (report_type, ctx_buffer, str_buffer, meta_buffer, result), hos::Version_11_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 12, Result, CreateReport, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags), (report_type, ctx_buffer, str_buffer, meta_buffer, result, flags), hos::Version_17_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 20, Result, RegisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 20, Result, RegisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 21, Result, UnregisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 21, Result, UnregisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 22, Result, UpdateAppletSuspendedDuration, (ncm::ProgramId program_id, TimeSpanType duration), (program_id, duration), hos::Version_12_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 22, Result, UpdateAppletSuspendedDuration, (ncm::ProgramId program_id, TimeSpanType duration), (program_id, duration), hos::Version_12_0_0) \
|
||||||
|
@ -76,10 +76,26 @@ namespace ams::erpt::srv {
|
|||||||
};
|
};
|
||||||
#undef GET_FIELD_FLAG
|
#undef GET_FIELD_FLAG
|
||||||
|
|
||||||
|
inline CategoryId ConvertFieldToCategory(FieldId id) {
|
||||||
|
return FieldToCategoryMap[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FieldType ConvertFieldToType(FieldId id) {
|
||||||
|
return FieldToTypeMap[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline FieldFlag ConvertFieldToFlag(FieldId id) {
|
||||||
|
return FieldToFlagMap[id];
|
||||||
|
}
|
||||||
|
|
||||||
constexpr inline ReportFlagSet MakeNoReportFlags() {
|
constexpr inline ReportFlagSet MakeNoReportFlags() {
|
||||||
return util::MakeBitFlagSet<32, ReportFlag>();
|
return util::MakeBitFlagSet<32, ReportFlag>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr inline CreateReportOptionFlagSet MakeNoCreateReportOptionFlags() {
|
||||||
|
return util::MakeBitFlagSet<32, CreateReportOptionFlag>();
|
||||||
|
}
|
||||||
|
|
||||||
constexpr inline AttachmentFlagSet MakeNoAttachmentFlags() {
|
constexpr inline AttachmentFlagSet MakeNoAttachmentFlags() {
|
||||||
return util::MakeBitFlagSet<32, AttachmentFlag>();
|
return util::MakeBitFlagSet<32, AttachmentFlag>();
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@
|
|||||||
#include <stratosphere/fs/fs_signed_system_partition.hpp>
|
#include <stratosphere/fs/fs_signed_system_partition.hpp>
|
||||||
#include <stratosphere/fs/fs_system_data.hpp>
|
#include <stratosphere/fs/fs_system_data.hpp>
|
||||||
#include <stratosphere/fs/fs_program_index_map_info.hpp>
|
#include <stratosphere/fs/fs_program_index_map_info.hpp>
|
||||||
|
#include <stratosphere/fs/fs_program_id.hpp>
|
||||||
#include <stratosphere/fs/impl/fs_access_log_impl.hpp>
|
#include <stratosphere/fs/impl/fs_access_log_impl.hpp>
|
||||||
#include <stratosphere/fs/impl/fs_hash_generator_factory_selector.hpp>
|
#include <stratosphere/fs/impl/fs_hash_generator_factory_selector.hpp>
|
||||||
#include <stratosphere/fs/impl/fs_storage_service_object_adapter.hpp>
|
#include <stratosphere/fs/impl/fs_storage_service_object_adapter.hpp>
|
||||||
|
26
libstratosphere/include/stratosphere/fs/fs_program_id.hpp
Normal file
26
libstratosphere/include/stratosphere/fs/fs_program_id.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
#include <stratosphere/fs/fs_content_attributes.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||||
|
|
||||||
|
namespace ams::fs {
|
||||||
|
|
||||||
|
/* ACCURATE_TO_VERSION: 17.5.0.0 */
|
||||||
|
Result GetProgramId(ncm::ProgramId *out, const char *path, fs::ContentAttributes attr);
|
||||||
|
|
||||||
|
}
|
@ -104,6 +104,7 @@ namespace ams::fssrv {
|
|||||||
Result GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id);
|
Result GetRightsId(ams::sf::Out<fs::RightsId> out, ncm::ProgramId program_id, ncm::StorageId storage_id);
|
||||||
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key);
|
Result RegisterExternalKey(const fs::RightsId &rights_id, const spl::AccessKey &access_key);
|
||||||
Result UnregisterAllExternalKey();
|
Result UnregisterAllExternalKey();
|
||||||
|
Result GetProgramId(ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr);
|
||||||
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path);
|
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path);
|
||||||
Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
|
Result GetRightsIdAndKeyGenerationByPathObsolete(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path);
|
||||||
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr);
|
Result GetRightsIdAndKeyGenerationByPath(ams::sf::Out<fs::RightsId> out, ams::sf::Out<u8> out_key_generation, const fssrv::sf::FspPath &path, fs::ContentAttributes attr);
|
||||||
@ -146,7 +147,8 @@ namespace ams::fssrv {
|
|||||||
/* fsp-ldr */
|
/* fsp-ldr */
|
||||||
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
Result OpenCodeFileSystemDeprecated(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
||||||
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
Result OpenCodeFileSystemDeprecated2(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id);
|
||||||
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
||||||
|
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id);
|
||||||
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id);
|
Result IsArchivedProgram(ams::sf::Out<bool> out, u64 process_id);
|
||||||
};
|
};
|
||||||
static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>);
|
static_assert(sf::IsIFileSystemProxy<FileSystemProxyImpl>);
|
||||||
@ -165,7 +167,12 @@ namespace ams::fssrv {
|
|||||||
R_THROW(fs::ResultPortAcceptableCountLimited());
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
|
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
||||||
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
||||||
R_THROW(fs::ResultPortAcceptableCountLimited());
|
R_THROW(fs::ResultPortAcceptableCountLimited());
|
||||||
}
|
}
|
||||||
|
@ -115,6 +115,7 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 615, Result, QuerySaveDataInternalStorageTotalSize, (), (), hos::Version_5_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 615, Result, QuerySaveDataInternalStorageTotalSize, (), (), hos::Version_5_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 616, Result, GetSaveDataCommitId, (), (), hos::Version_6_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 616, Result, GetSaveDataCommitId, (), (), hos::Version_6_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 617, Result, UnregisterExternalKey, (const fs::RightsId &rights_id), (rights_id), hos::Version_7_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 617, Result, UnregisterExternalKey, (const fs::RightsId &rights_id), (rights_id), hos::Version_7_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 618, Result, GetProgramId, (ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr), (out, path, attr), hos::Version_17_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 620, Result, SetSdCardEncryptionSeed, (const fs::EncryptionSeed &seed), (seed), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 620, Result, SetSdCardEncryptionSeed, (const fs::EncryptionSeed &seed), (seed), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 630, Result, SetSdCardAccessibility, (bool accessible), (accessible), hos::Version_4_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 630, Result, SetSdCardAccessibility, (bool accessible), (accessible), hos::Version_4_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 631, Result, IsSdCardAccessible, (ams::sf::Out<bool> out), (out), hos::Version_4_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 631, Result, IsSdCardAccessible, (ams::sf::Out<bool> out), (out), hos::Version_4_0_0) \
|
||||||
|
@ -20,11 +20,12 @@
|
|||||||
#include <stratosphere/fs/fs_code_verification_data.hpp>
|
#include <stratosphere/fs/fs_code_verification_data.hpp>
|
||||||
#include <stratosphere/fs/fs_content_attributes.hpp>
|
#include <stratosphere/fs/fs_content_attributes.hpp>
|
||||||
|
|
||||||
/* ACCURATE_TO_VERSION: 13.4.0.0 */
|
/* ACCURATE_TO_VERSION: 17.5.0.0 */
|
||||||
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
|
#define AMS_FSSRV_I_FILE_SYSTEM_PROXY_FOR_LOADER_INTERFACE_INFO(C, H) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, path, program_id), hos::Version_Min, hos::Version_9_2_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated2, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0, hos::Version_15_0_1) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated2, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, ncm::ProgramId program_id), (out_fs, out_verif, path, program_id), hos::Version_10_0_0, hos::Version_15_0_1) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_16_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystemDeprecated3, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_16_0_0, hos::Version_16_1_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 0, Result, OpenCodeFileSystem, (ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id), (out_fs, out_verif, path, attr, program_id), hos::Version_17_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
|
AMS_SF_METHOD_INFO(C, H, 1, Result, IsArchivedProgram, (ams::sf::Out<bool> out, u64 process_id), (out, process_id)) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
|
AMS_SF_METHOD_INFO(C, H, 2, Result, SetCurrentProcess, (const ams::sf::ClientProcessId &client_pid), (client_pid), hos::Version_4_0_0)
|
||||||
|
|
||||||
|
@ -80,6 +80,7 @@ namespace ams::hos {
|
|||||||
Version_16_0_2 = ::ams::TargetFirmware_16_0_2,
|
Version_16_0_2 = ::ams::TargetFirmware_16_0_2,
|
||||||
Version_16_0_3 = ::ams::TargetFirmware_16_0_3,
|
Version_16_0_3 = ::ams::TargetFirmware_16_0_3,
|
||||||
Version_16_1_0 = ::ams::TargetFirmware_16_1_0,
|
Version_16_1_0 = ::ams::TargetFirmware_16_1_0,
|
||||||
|
Version_17_0_0 = ::ams::TargetFirmware_17_0_0,
|
||||||
|
|
||||||
Version_Current = ::ams::TargetFirmware_Current,
|
Version_Current = ::ams::TargetFirmware_Current,
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
|
#include <stratosphere/ncm/ncm_content_meta_id.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
|
#include <stratosphere/ncm/ncm_content_meta_key.hpp>
|
||||||
|
#include <stratosphere/ncm/ncm_content_meta_platform.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_info.hpp>
|
#include <stratosphere/ncm/ncm_content_info.hpp>
|
||||||
#include <stratosphere/ncm/ncm_content_info_data.hpp>
|
#include <stratosphere/ncm/ncm_content_info_data.hpp>
|
||||||
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
|
#include <stratosphere/ncm/ncm_firmware_variation.hpp>
|
||||||
@ -58,7 +59,7 @@ namespace ams::ncm {
|
|||||||
u16 content_count;
|
u16 content_count;
|
||||||
u16 content_meta_count;
|
u16 content_meta_count;
|
||||||
u8 attributes;
|
u8 attributes;
|
||||||
StorageId storage_id;
|
ContentMetaPlatform platform;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(ContentMetaHeader) == 0x8);
|
static_assert(sizeof(ContentMetaHeader) == 0x8);
|
||||||
@ -67,7 +68,7 @@ namespace ams::ncm {
|
|||||||
u64 id;
|
u64 id;
|
||||||
u32 version;
|
u32 version;
|
||||||
ContentMetaType type;
|
ContentMetaType type;
|
||||||
u8 reserved_0D;
|
ContentMetaPlatform platform;
|
||||||
u16 extended_header_size;
|
u16 extended_header_size;
|
||||||
u16 content_count;
|
u16 content_count;
|
||||||
u16 content_meta_count;
|
u16 content_meta_count;
|
||||||
@ -79,7 +80,6 @@ namespace ams::ncm {
|
|||||||
u8 reserved_1C[4];
|
u8 reserved_1C[4];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(PackagedContentMetaHeader) == 0x20);
|
static_assert(sizeof(PackagedContentMetaHeader) == 0x20);
|
||||||
static_assert(AMS_OFFSETOF(PackagedContentMetaHeader, reserved_0D) == 0x0D);
|
|
||||||
static_assert(AMS_OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C);
|
static_assert(AMS_OFFSETOF(PackagedContentMetaHeader, reserved_1C) == 0x1C);
|
||||||
|
|
||||||
using InstallContentMetaHeader = PackagedContentMetaHeader;
|
using InstallContentMetaHeader = PackagedContentMetaHeader;
|
||||||
|
@ -221,6 +221,11 @@ namespace ams::ncm {
|
|||||||
AMS_ASSERT(m_interface != nullptr);
|
AMS_ASSERT(m_interface != nullptr);
|
||||||
R_RETURN(m_interface->GetContentInfoByTypeAndIdOffset(out_content_info, key, type, id_offset));
|
R_RETURN(m_interface->GetContentInfoByTypeAndIdOffset(out_content_info, key, type, id_offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetPlatform(ContentMetaPlatform *out, const ContentMetaKey &key) {
|
||||||
|
AMS_ASSERT(m_interface != nullptr);
|
||||||
|
R_RETURN(m_interface->GetPlatform(out, key));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include <vapours.hpp>
|
||||||
|
|
||||||
|
namespace ams::ncm {
|
||||||
|
|
||||||
|
enum class ContentMetaPlatform : u8 {
|
||||||
|
Nx = 0x0,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -207,6 +207,11 @@ namespace ams::ncm {
|
|||||||
R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdWithCacheDeprecated(out_rights_id, cache_content_id, placeholder_id));
|
R_RETURN(m_interface->GetRightsIdFromPlaceHolderIdWithCacheDeprecated(out_rights_id, cache_content_id, placeholder_id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetProgramId(ncm::ProgramId *out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
AMS_ASSERT(m_interface != nullptr);
|
||||||
|
R_RETURN(m_interface->GetProgramId(out, content_id, attr));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 22, Result, GetOwnerApplicationId, (sf::Out<ncm::ApplicationId> out_id, const ncm::ContentMetaKey &key), (out_id, key), hos::Version_10_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 22, Result, GetOwnerApplicationId, (sf::Out<ncm::ApplicationId> out_id, const ncm::ContentMetaKey &key), (out_id, key), hos::Version_10_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 23, Result, GetContentAccessibilities, (sf::Out<u8> out_accessibilities, const ncm::ContentMetaKey &key), (out_accessibilities, key), hos::Version_15_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 23, Result, GetContentAccessibilities, (sf::Out<u8> out_accessibilities, const ncm::ContentMetaKey &key), (out_accessibilities, key), hos::Version_15_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 24, Result, GetContentInfoByType, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type), (out_content_info, key, type), hos::Version_15_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 24, Result, GetContentInfoByType, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type), (out_content_info, key, type), hos::Version_15_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 25, Result, GetContentInfoByTypeAndIdOffset, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type, u8 id_offset), (out_content_info, key, type, id_offset), hos::Version_15_0_0)
|
AMS_SF_METHOD_INFO(C, H, 25, Result, GetContentInfoByTypeAndIdOffset, (sf::Out<ncm::ContentInfo> out_content_info, const ncm::ContentMetaKey &key, ncm::ContentType type, u8 id_offset), (out_content_info, key, type, id_offset), hos::Version_15_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 26, Result, GetPlatform, (sf::Out<ncm::ContentMetaPlatform> out, const ncm::ContentMetaKey &key), (out, key), hos::Version_17_0_0)
|
||||||
|
|
||||||
|
|
||||||
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentMetaDatabase, AMS_NCM_I_CONTENT_META_DATABASE_INTERFACE_INFO, 0x58021FEC)
|
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentMetaDatabase, AMS_NCM_I_CONTENT_META_DATABASE_INTERFACE_INFO, 0x58021FEC)
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCacheDeprecated, (sf::Out<ncm::RightsId> out_rights_id, ncm::ContentId cache_content_id, ncm::PlaceHolderId placeholder_id), (out_rights_id, cache_content_id, placeholder_id), hos::Version_8_0_0, hos::Version_15_0_1) \
|
AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCacheDeprecated, (sf::Out<ncm::RightsId> out_rights_id, ncm::ContentId cache_content_id, ncm::PlaceHolderId placeholder_id), (out_rights_id, cache_content_id, placeholder_id), hos::Version_8_0_0, hos::Version_15_0_1) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCache, (sf::Out<ncm::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id, ncm::ContentId cache_content_id, fs::ContentAttributes attr), (out_rights_id, placeholder_id, cache_content_id, attr), hos::Version_16_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 27, Result, GetRightsIdFromPlaceHolderIdWithCache, (sf::Out<ncm::RightsId> out_rights_id, ncm::PlaceHolderId placeholder_id, ncm::ContentId cache_content_id, fs::ContentAttributes attr), (out_rights_id, placeholder_id, cache_content_id, attr), hos::Version_16_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 28, Result, RegisterPath, (const ncm::ContentId &content_id, const ncm::Path &path), (content_id, path), hos::Version_13_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 28, Result, RegisterPath, (const ncm::ContentId &content_id, const ncm::Path &path), (content_id, path), hos::Version_13_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 29, Result, ClearRegisteredPath, (), (), hos::Version_13_0_0)
|
AMS_SF_METHOD_INFO(C, H, 29, Result, ClearRegisteredPath, (), (), hos::Version_13_0_0) \
|
||||||
|
AMS_SF_METHOD_INFO(C, H, 30, Result, GetProgramId, (sf::Out<ncm::ProgramId> out, ncm::ContentId content_id, fs::ContentAttributes attr), (out, content_id, attr), hos::Version_17_0_0)
|
||||||
|
|
||||||
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentStorage, AMS_NCM_I_CONTENT_STORAGE_INTERFACE_INFO, 0xFEAE3DD1)
|
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentStorage, AMS_NCM_I_CONTENT_STORAGE_INTERFACE_INFO, 0xFEAE3DD1)
|
||||||
|
@ -71,6 +71,7 @@ namespace ams::ncm {
|
|||||||
Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key);
|
Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key);
|
||||||
Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type);
|
Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type);
|
||||||
Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset);
|
Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset);
|
||||||
|
Result GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key);
|
||||||
};
|
};
|
||||||
static_assert(ncm::IsIContentMetaDatabase<IntegratedContentMetaDatabaseImpl>);
|
static_assert(ncm::IsIContentMetaDatabase<IntegratedContentMetaDatabaseImpl>);
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ namespace ams::ncm {
|
|||||||
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
|
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
|
||||||
Result RegisterPath(const ContentId &content_id, const Path &path);
|
Result RegisterPath(const ContentId &content_id, const Path &path);
|
||||||
Result ClearRegisteredPath();
|
Result ClearRegisteredPath();
|
||||||
|
Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr);
|
||||||
|
|
||||||
/* 16.0.0 Alignment change hacks. */
|
/* 16.0.0 Alignment change hacks. */
|
||||||
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
||||||
|
@ -28,6 +28,7 @@ namespace ams::pm::dmnt {
|
|||||||
Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id);
|
Result GetProcessId(os::ProcessId *out_process_id, const ncm::ProgramId program_id);
|
||||||
Result GetApplicationProcessId(os::ProcessId *out_process_id);
|
Result GetApplicationProcessId(os::ProcessId *out_process_id);
|
||||||
Result HookToCreateApplicationProcess(os::NativeHandle *out_handle);
|
Result HookToCreateApplicationProcess(os::NativeHandle *out_handle);
|
||||||
|
Result HookToCreateProcess(os::NativeHandle *out_handle, const ncm::ProgramId program_id);
|
||||||
Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id);
|
Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id);
|
||||||
|
|
||||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||||
|
@ -98,6 +98,7 @@ namespace ams::spl {
|
|||||||
enum class EsDeviceUniqueKeyType {
|
enum class EsDeviceUniqueKeyType {
|
||||||
TitleKey = 0,
|
TitleKey = 0,
|
||||||
ArchiveKey = 1,
|
ArchiveKey = 1,
|
||||||
|
Unknown2 = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AsyncOperationKey {
|
struct AsyncOperationKey {
|
||||||
|
@ -39,6 +39,10 @@ namespace ams::exosphere {
|
|||||||
R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 3));
|
R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ForceRebootByPmic() {
|
||||||
|
R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsReboot, 4));
|
||||||
|
}
|
||||||
|
|
||||||
void ForceShutdown() {
|
void ForceShutdown() {
|
||||||
R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsShutdown, 1));
|
R_ABORT_UNLESS(spl::impl::SetConfig(spl::ConfigItem::ExosphereNeedsShutdown, 1));
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ namespace ams::erpt::srv {
|
|||||||
ON_SCOPE_EXIT { Deallocate(hdr); };
|
ON_SCOPE_EXIT { Deallocate(hdr); };
|
||||||
|
|
||||||
hdr->magic = HeaderMagic;
|
hdr->magic = HeaderMagic;
|
||||||
hdr->field_type = static_cast<u32>(FieldToTypeMap[field_id]);
|
hdr->field_type = static_cast<u32>(ConvertFieldToType(field_id));
|
||||||
hdr->element_count = arr_size;
|
hdr->element_count = arr_size;
|
||||||
hdr->reserved = 0;
|
hdr->reserved = 0;
|
||||||
|
|
||||||
@ -97,7 +97,7 @@ namespace ams::erpt::srv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Result AddField(Report *report, FieldId field_id, char *str, u32 len) {
|
static Result AddField(Report *report, FieldId field_id, char *str, u32 len) {
|
||||||
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) {
|
||||||
R_RETURN(EncryptArray<char>(report, field_id, str, len));
|
R_RETURN(EncryptArray<char>(report, field_id, str, len));
|
||||||
} else {
|
} else {
|
||||||
R_RETURN(Formatter::AddField(report, field_id, str, len));
|
R_RETURN(Formatter::AddField(report, field_id, str, len));
|
||||||
@ -105,7 +105,7 @@ namespace ams::erpt::srv {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) {
|
static Result AddField(Report *report, FieldId field_id, u8 *bin, u32 len) {
|
||||||
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) {
|
||||||
R_RETURN(EncryptArray<u8>(report, field_id, bin, len));
|
R_RETURN(EncryptArray<u8>(report, field_id, bin, len));
|
||||||
} else {
|
} else {
|
||||||
R_RETURN(Formatter::AddField(report, field_id, bin, len));
|
R_RETURN(Formatter::AddField(report, field_id, bin, len));
|
||||||
@ -114,7 +114,7 @@ namespace ams::erpt::srv {
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static Result AddField(Report *report, FieldId field_id, T *arr, u32 len) {
|
static Result AddField(Report *report, FieldId field_id, T *arr, u32 len) {
|
||||||
if (FieldToFlagMap[field_id] == FieldFlag_Encrypt) {
|
if (ConvertFieldToFlag(field_id) == FieldFlag_Encrypt) {
|
||||||
R_RETURN(EncryptArray<T>(report, field_id, arr, len));
|
R_RETURN(EncryptArray<T>(report, field_id, arr, len));
|
||||||
} else {
|
} else {
|
||||||
R_RETURN(Formatter::AddField<T>(report, field_id, arr, len));
|
R_RETURN(Formatter::AddField<T>(report, field_id, arr, len));
|
||||||
|
@ -38,7 +38,7 @@ namespace ams::erpt::srv {
|
|||||||
R_RETURN(Context::SubmitContext(ctx, data, data_size));
|
R_RETURN(Context::SubmitContext(ctx, data, data_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result) {
|
Result ContextImpl::CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags) {
|
||||||
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
||||||
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
||||||
const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer());
|
const ReportMetaData *meta = reinterpret_cast<const ReportMetaData *>(meta_buffer.GetPointer());
|
||||||
@ -50,15 +50,19 @@ namespace ams::erpt::srv {
|
|||||||
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
||||||
R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument());
|
R_UNLESS(meta_size == 0 || meta_size == sizeof(ReportMetaData), erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0));
|
R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, meta_size != 0 ? meta : nullptr, nullptr, 0, flags));
|
||||||
|
|
||||||
ManagerImpl::NotifyAll();
|
ManagerImpl::NotifyAll();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::CreateReportV1(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result) {
|
||||||
|
R_RETURN(this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, result, erpt::srv::MakeNoCreateReportOptionFlags()));
|
||||||
|
}
|
||||||
|
|
||||||
Result ContextImpl::CreateReportV0(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) {
|
Result ContextImpl::CreateReportV0(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer) {
|
||||||
R_RETURN(this->CreateReport(report_type, ctx_buffer, data_buffer, meta_buffer, ResultSuccess()));
|
R_RETURN(this->CreateReportV1(report_type, ctx_buffer, data_buffer, meta_buffer, ResultSuccess()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ContextImpl::SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) {
|
Result ContextImpl::SetInitialLaunchSettingsCompletionTime(const time::SteadyClockTimePoint &time_point) {
|
||||||
@ -138,7 +142,7 @@ namespace ams::erpt::srv {
|
|||||||
R_RETURN(JournalForAttachments::SubmitAttachment(out.GetPointer(), name_safe, data, data_size));
|
R_RETURN(JournalForAttachments::SubmitAttachment(out.GetPointer(), name_safe, data, data_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result) {
|
Result ContextImpl::CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags) {
|
||||||
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
const ContextEntry *ctx = reinterpret_cast<const ContextEntry *>( ctx_buffer.GetPointer());
|
||||||
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
const u8 *data = reinterpret_cast<const u8 *>(data_buffer.GetPointer());
|
||||||
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
|
const u32 ctx_size = static_cast<u32>(ctx_buffer.GetSize());
|
||||||
@ -150,15 +154,19 @@ namespace ams::erpt::srv {
|
|||||||
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
R_UNLESS(ctx_size == sizeof(ContextEntry), erpt::ResultInvalidArgument());
|
||||||
R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument());
|
R_UNLESS(num_attachments <= AttachmentsPerReportMax, erpt::ResultInvalidArgument());
|
||||||
|
|
||||||
R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, nullptr, attachments, num_attachments));
|
R_TRY(Reporter::CreateReport(report_type, result, ctx, data, data_size, nullptr, attachments, num_attachments, flags));
|
||||||
|
|
||||||
ManagerImpl::NotifyAll();
|
ManagerImpl::NotifyAll();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContextImpl::CreateReportWithAttachmentsDeprecated2(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result) {
|
||||||
|
R_RETURN(this->CreateReportWithAttachments(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, result, erpt::srv::MakeNoCreateReportOptionFlags()));
|
||||||
|
}
|
||||||
|
|
||||||
Result ContextImpl::CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) {
|
Result ContextImpl::CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer) {
|
||||||
R_RETURN(this->CreateReportWithAttachments(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, ResultSuccess()));
|
R_RETURN(this->CreateReportWithAttachmentsDeprecated2(report_type, ctx_buffer, data_buffer, attachment_ids_buffer, ResultSuccess()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ContextImpl::RegisterRunningApplet(ncm::ProgramId program_id) {
|
Result ContextImpl::RegisterRunningApplet(ncm::ProgramId program_id) {
|
||||||
|
@ -31,8 +31,10 @@ namespace ams::erpt::srv {
|
|||||||
Result ClearApplicationLaunchTime();
|
Result ClearApplicationLaunchTime();
|
||||||
Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data);
|
Result SubmitAttachment(ams::sf::Out<AttachmentId> out, const ams::sf::InBuffer &attachment_name, const ams::sf::InBuffer &attachment_data);
|
||||||
Result CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer);
|
Result CreateReportWithAttachmentsDeprecated(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer);
|
||||||
Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result);
|
Result CreateReportWithAttachmentsDeprecated2(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result);
|
||||||
Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result);
|
Result CreateReportWithAttachments(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &attachment_ids_buffer, Result result, erpt::CreateReportOptionFlagSet flags);
|
||||||
|
Result CreateReportV1(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result);
|
||||||
|
Result CreateReport(ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &data_buffer, const ams::sf::InBuffer &meta_buffer, Result result, erpt::CreateReportOptionFlagSet flags);
|
||||||
Result RegisterRunningApplet(ncm::ProgramId program_id);
|
Result RegisterRunningApplet(ncm::ProgramId program_id);
|
||||||
Result UnregisterRunningApplet(ncm::ProgramId program_id);
|
Result UnregisterRunningApplet(ncm::ProgramId program_id);
|
||||||
Result UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration);
|
Result UpdateAppletSuspendedDuration(ncm::ProgramId program_id, TimeSpanType duration);
|
||||||
|
@ -78,8 +78,8 @@ namespace ams::erpt::srv {
|
|||||||
R_UNLESS(0 <= m_ctx.fields[i].id && m_ctx.fields[i].id < FieldId_Count, erpt::ResultInvalidArgument());
|
R_UNLESS(0 <= m_ctx.fields[i].id && m_ctx.fields[i].id < FieldId_Count, 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 == FieldToTypeMap[m_ctx.fields[i].id], erpt::ResultFieldTypeMismatch());
|
R_UNLESS(m_ctx.fields[i].type == ConvertFieldToType(m_ctx.fields[i].id), erpt::ResultFieldTypeMismatch());
|
||||||
R_UNLESS(m_ctx.category == FieldToCategoryMap[m_ctx.fields[i].id], erpt::ResultFieldCategoryMismatch());
|
R_UNLESS(m_ctx.category == ConvertFieldToCategory(m_ctx.fields[i].id), erpt::ResultFieldCategoryMismatch());
|
||||||
|
|
||||||
if (IsArrayFieldType(m_ctx.fields[i].type)) {
|
if (IsArrayFieldType(m_ctx.fields[i].type)) {
|
||||||
const u32 start_idx = m_ctx.fields[i].value_array.start_idx;
|
const u32 start_idx = m_ctx.fields[i].value_array.start_idx;
|
||||||
|
@ -86,7 +86,7 @@ namespace ams::erpt::srv {
|
|||||||
R_TRY(record->Add(FieldId_ErrorCode, error_code_str, std::strlen(error_code_str)));
|
R_TRY(record->Add(FieldId_ErrorCode, error_code_str, std::strlen(error_code_str)));
|
||||||
|
|
||||||
/* Create report. */
|
/* Create report. */
|
||||||
R_TRY(Reporter::CreateReport(ReportType_Invisible, ResultSuccess(), std::move(record), nullptr, nullptr, 0));
|
R_TRY(Reporter::CreateReport(ReportType_Invisible, ResultSuccess(), std::move(record), nullptr, nullptr, 0, erpt::srv::MakeNoCreateReportOptionFlags()));
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
@ -413,7 +413,7 @@ namespace ams::erpt::srv {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Reporter::CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments) {
|
Result Reporter::CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags) {
|
||||||
/* Create a context record for the report. */
|
/* Create a context record for the report. */
|
||||||
auto record = std::make_unique<ContextRecord>();
|
auto record = std::make_unique<ContextRecord>();
|
||||||
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
|
||||||
@ -422,10 +422,10 @@ namespace ams::erpt::srv {
|
|||||||
R_TRY(record->Initialize(ctx, data, data_size));
|
R_TRY(record->Initialize(ctx, data, data_size));
|
||||||
|
|
||||||
/* Create the report. */
|
/* Create the report. */
|
||||||
R_RETURN(CreateReport(type, ctx_result, std::move(record), meta, attachments, num_attachments));
|
R_RETURN(CreateReport(type, ctx_result, std::move(record), meta, attachments, num_attachments, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Reporter::CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments) {
|
Result Reporter::CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags) {
|
||||||
/* Clear the automatic categories, when we're done with our report. */
|
/* Clear the automatic categories, when we're done with our report. */
|
||||||
ON_SCOPE_EXIT {
|
ON_SCOPE_EXIT {
|
||||||
Context::ClearContext(CategoryId_ErrorInfo);
|
Context::ClearContext(CategoryId_ErrorInfo);
|
||||||
@ -457,7 +457,7 @@ namespace ams::erpt::srv {
|
|||||||
SaveSyslogReportIfRequired(ctx, report_id);
|
SaveSyslogReportIfRequired(ctx, report_id);
|
||||||
|
|
||||||
/* Submit report contexts. */
|
/* Submit report contexts. */
|
||||||
R_TRY(SubmitReportContexts(report_id, type, ctx_result, std::move(record), timestamp_user, timestamp_network));
|
R_TRY(SubmitReportContexts(report_id, type, ctx_result, std::move(record), timestamp_user, timestamp_network, flags));
|
||||||
|
|
||||||
/* Link attachments to the report. */
|
/* Link attachments to the report. */
|
||||||
R_TRY(LinkAttachments(report_id, attachments, num_attachments));
|
R_TRY(LinkAttachments(report_id, attachments, num_attachments));
|
||||||
@ -468,7 +468,7 @@ namespace ams::erpt::srv {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result Reporter::SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime ×tamp_user, const time::PosixTime ×tamp_network) {
|
Result Reporter::SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime ×tamp_user, const time::PosixTime ×tamp_network, erpt::CreateReportOptionFlagSet flags) {
|
||||||
/* Create automatic record. */
|
/* Create automatic record. */
|
||||||
auto auto_record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto, 0x300);
|
auto auto_record = std::make_unique<ContextRecord>(CategoryId_ErrorInfoAuto, 0x300);
|
||||||
R_UNLESS(auto_record != nullptr, erpt::ResultOutOfMemory());
|
R_UNLESS(auto_record != nullptr, erpt::ResultOutOfMemory());
|
||||||
@ -530,6 +530,10 @@ namespace ams::erpt::srv {
|
|||||||
SubmitResourceLimitContexts();
|
SubmitResourceLimitContexts();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (flags.Test<CreateReportOptionFlag::SubmitFsInfo>()) {
|
||||||
|
/* TODO: 17.0.0 SubmitFsInfo() */
|
||||||
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,10 +56,10 @@ namespace ams::erpt::srv {
|
|||||||
|
|
||||||
static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; }
|
static void SetRedirectNewReportsToSdCard(bool en) { s_redirect_new_reports = en; }
|
||||||
private:
|
private:
|
||||||
static Result SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &user_timestamp, const time::PosixTime &network_timestamp);
|
static Result SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &user_timestamp, const time::PosixTime &network_timestamp, erpt::CreateReportOptionFlagSet flags);
|
||||||
public:
|
public:
|
||||||
static Result CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments);
|
static Result CreateReport(ReportType type, Result ctx_result, const ContextEntry *ctx, const u8 *data, u32 data_size, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags);
|
||||||
static Result CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments);
|
static Result CreateReport(ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const ReportMetaData *meta, const AttachmentId *attachments, u32 num_attachments, erpt::CreateReportOptionFlagSet flags);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ namespace ams::fs {
|
|||||||
R_TRY(fsp->SetCurrentProcess({}));
|
R_TRY(fsp->SetCurrentProcess({}));
|
||||||
|
|
||||||
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
|
sf::SharedPointer<fssrv::sf::IFileSystem> fs;
|
||||||
R_TRY(fsp->OpenCodeFileSystem(std::addressof(fs), out_verification_data, sf_path, attr, program_id));
|
R_TRY(fsp->OpenCodeFileSystem(std::addressof(fs), ams::sf::OutBuffer(out_verification_data, sizeof(*out_verification_data)), sf_path, attr, program_id));
|
||||||
|
|
||||||
/* Allocate a new filesystem wrapper. */
|
/* Allocate a new filesystem wrapper. */
|
||||||
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
|
auto fsa = std::make_unique<impl::FileSystemServiceObjectAdapter>(std::move(fs));
|
||||||
|
36
libstratosphere/source/fs/fs_program_id.cpp
Normal file
36
libstratosphere/source/fs/fs_program_id.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Atmosphère-NX
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stratosphere.hpp>
|
||||||
|
#include <stratosphere/fs/fs_rights_id.hpp>
|
||||||
|
#include "impl/fs_file_system_proxy_service_object.hpp"
|
||||||
|
|
||||||
|
namespace ams::fs {
|
||||||
|
|
||||||
|
Result GetProgramId(ncm::ProgramId *out, const char *path, fs::ContentAttributes attr) {
|
||||||
|
AMS_FS_R_UNLESS(out != nullptr, fs::ResultNullptrArgument());
|
||||||
|
AMS_FS_R_UNLESS(path != nullptr, fs::ResultNullptrArgument());
|
||||||
|
|
||||||
|
/* Convert the path for fsp. */
|
||||||
|
fssrv::sf::FspPath sf_path;
|
||||||
|
R_TRY(fs::ConvertToFspPath(std::addressof(sf_path), path));
|
||||||
|
|
||||||
|
auto fsp = impl::GetFileSystemProxyServiceObject();
|
||||||
|
AMS_FS_R_TRY(fsp->GetProgramId(out, sf_path, attr));
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -320,6 +320,10 @@ namespace ams::fs {
|
|||||||
AMS_ABORT("TODO");
|
AMS_ABORT("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetProgramId(ams::sf::Out<ncm::ProgramId> out, const fssrv::sf::FspPath &path, fs::ContentAttributes attr) {
|
||||||
|
static_assert(sizeof(ncm::ProgramId) == sizeof(u64));
|
||||||
|
R_RETURN(fsGetProgramId(reinterpret_cast<u64 *>(out.GetPointer()), path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr))));
|
||||||
|
}
|
||||||
|
|
||||||
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path) {
|
Result GetRightsIdByPath(ams::sf::Out<fs::RightsId> out, const fssrv::sf::FspPath &path) {
|
||||||
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
|
static_assert(sizeof(RightsId) == sizeof(::FsRightsId));
|
||||||
|
@ -47,7 +47,15 @@ namespace ams::fs {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
Result OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
|
::FsFileSystem fs;
|
||||||
|
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
|
||||||
|
|
||||||
|
out_fs.SetValue(ObjectFactory::CreateSharedEmplaced<fssrv::sf::IFileSystem, fssrv::impl::RemoteFileSystem>(fs));
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
::FsFileSystem fs;
|
::FsFileSystem fs;
|
||||||
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
|
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verif.GetPointer()), program_id.value, path.str, static_cast<::FsContentAttributes>(static_cast<u8>(attr)), std::addressof(fs)));
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ namespace ams::fs::impl {
|
|||||||
#define ADD_ENUM_CASE(v) case v: return #v
|
#define ADD_ENUM_CASE(v) case v: return #v
|
||||||
|
|
||||||
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
|
template<> const char *IdString::ToString<pkg1::KeyGeneration>(pkg1::KeyGeneration id) {
|
||||||
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_16_0_0);
|
static_assert(pkg1::KeyGeneration_Current == pkg1::KeyGeneration_17_0_0);
|
||||||
switch (id) {
|
switch (id) {
|
||||||
using enum pkg1::KeyGeneration;
|
using enum pkg1::KeyGeneration;
|
||||||
case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
|
case KeyGeneration_1_0_0: return "1.0.0-2.3.0";
|
||||||
@ -39,7 +39,8 @@ namespace ams::fs::impl {
|
|||||||
case KeyGeneration_13_0_0: return "13.0.0-13.2.1";
|
case KeyGeneration_13_0_0: return "13.0.0-13.2.1";
|
||||||
case KeyGeneration_14_0_0: return "14.0.0-14.1.2";
|
case KeyGeneration_14_0_0: return "14.0.0-14.1.2";
|
||||||
case KeyGeneration_15_0_0: return "15.0.0-15.0.1";
|
case KeyGeneration_15_0_0: return "15.0.0-15.0.1";
|
||||||
case KeyGeneration_16_0_0: return "16.0.0-";
|
case KeyGeneration_16_0_0: return "16.0.0-16.0.3";
|
||||||
|
case KeyGeneration_17_0_0: return "17.0.0-";
|
||||||
default: return "Unknown";
|
default: return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -465,7 +465,12 @@ namespace ams::fssrv {
|
|||||||
AMS_UNUSED(out_fs, out_verif, path, program_id);
|
AMS_UNUSED(out_fs, out_verif, path, program_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result FileSystemProxyImpl::OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
Result FileSystemProxyImpl::OpenCodeFileSystemDeprecated3(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, ams::sf::Out<fs::CodeVerificationData> out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
|
AMS_ABORT("TODO");
|
||||||
|
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
Result FileSystemProxyImpl::OpenCodeFileSystem(ams::sf::Out<ams::sf::SharedPointer<fssrv::sf::IFileSystem>> out_fs, const ams::sf::OutBuffer &out_verif, const fssrv::sf::Path &path, fs::ContentAttributes attr, ncm::ProgramId program_id) {
|
||||||
AMS_ABORT("TODO");
|
AMS_ABORT("TODO");
|
||||||
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
AMS_UNUSED(out_fs, out_verif, path, attr, program_id);
|
||||||
}
|
}
|
||||||
|
@ -784,7 +784,8 @@ namespace ams::ncm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result ContentManagerImpl::BuildContentMetaDatabase(StorageId storage_id) {
|
Result ContentManagerImpl::BuildContentMetaDatabase(StorageId storage_id) {
|
||||||
if (hos::GetVersion() < hos::Version_5_0_0) {
|
/* NOTE: we build on 17.0.0+, to work around a change in Nintendo save handling behavior. */
|
||||||
|
if (hos::GetVersion() < hos::Version_5_0_0 || hos::GetVersion() >= hos::Version_17_0_0) {
|
||||||
/* Temporarily activate the database. */
|
/* Temporarily activate the database. */
|
||||||
R_TRY(this->ActivateContentMetaDatabase(storage_id));
|
R_TRY(this->ActivateContentMetaDatabase(storage_id));
|
||||||
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(storage_id); };
|
ON_SCOPE_EXIT { this->InactivateContentMetaDatabase(storage_id); };
|
||||||
@ -946,7 +947,8 @@ namespace ams::ncm {
|
|||||||
R_TRY(this->CreateContentMetaDatabase(StorageId::BuiltInSystem));
|
R_TRY(this->CreateContentMetaDatabase(StorageId::BuiltInSystem));
|
||||||
|
|
||||||
/* Try to build or import a database, depending on our configuration. */
|
/* Try to build or import a database, depending on our configuration. */
|
||||||
if (manager_config.ShouldBuildDatabase()) {
|
/* NOTE: To work around a change in save management behavior in 17.0.0+, we build the database if needed. */
|
||||||
|
if (manager_config.ShouldBuildDatabase() || hos::GetVersion() >= hos::Version_17_0_0) {
|
||||||
/* If we should build the database, do so. */
|
/* If we should build the database, do so. */
|
||||||
R_TRY(this->BuildContentMetaDatabase(StorageId::BuiltInSystem));
|
R_TRY(this->BuildContentMetaDatabase(StorageId::BuiltInSystem));
|
||||||
R_TRY(this->VerifyContentMetaDatabase(StorageId::BuiltInSystem));
|
R_TRY(this->VerifyContentMetaDatabase(StorageId::BuiltInSystem));
|
||||||
|
@ -26,6 +26,7 @@ namespace ams::ncm {
|
|||||||
.content_count = src.content_count,
|
.content_count = src.content_count,
|
||||||
.content_meta_count = src.content_meta_count,
|
.content_meta_count = src.content_meta_count,
|
||||||
.attributes = src.attributes,
|
.attributes = src.attributes,
|
||||||
|
.platform = src.platform,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ namespace ams::ncm {
|
|||||||
.content_count = src.content_count,
|
.content_count = src.content_count,
|
||||||
.content_meta_count = src.content_meta_count,
|
.content_meta_count = src.content_meta_count,
|
||||||
.attributes = src.attributes,
|
.attributes = src.attributes,
|
||||||
|
.platform = src.platform,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,4 +518,20 @@ namespace ams::ncm {
|
|||||||
R_RETURN(this->GetContentInfoImpl(out_content_info.GetPointer(), key, type, util::make_optional(id_offset)));
|
R_RETURN(this->GetContentInfoImpl(out_content_info.GetPointer(), key, type, util::make_optional(id_offset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContentMetaDatabaseImpl::GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Obtain the content meta for the key. */
|
||||||
|
const void *meta;
|
||||||
|
size_t meta_size;
|
||||||
|
R_TRY(this->GetContentMetaPointer(&meta, &meta_size, key));
|
||||||
|
|
||||||
|
/* Create a reader. */
|
||||||
|
ContentMetaReader reader(meta, meta_size);
|
||||||
|
|
||||||
|
/* Set the ouput value. */
|
||||||
|
out.SetValue(reader.GetHeader()->platform);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -64,6 +64,7 @@ namespace ams::ncm {
|
|||||||
virtual Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key) override;
|
virtual Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key) override;
|
||||||
virtual Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type) override;
|
virtual Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type) override;
|
||||||
virtual Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) override;
|
virtual Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) override;
|
||||||
|
virtual Result GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ namespace ams::ncm {
|
|||||||
virtual Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key) = 0;
|
virtual Result GetContentAccessibilities(sf::Out<u8> out_accessibilities, const ContentMetaKey &key) = 0;
|
||||||
virtual Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type) = 0;
|
virtual Result GetContentInfoByType(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type) = 0;
|
||||||
virtual Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) = 0;
|
virtual Result GetContentInfoByTypeAndIdOffset(sf::Out<ContentInfo> out_content_info, const ContentMetaKey &key, ContentType type, u8 id_offset) = 0;
|
||||||
|
virtual Result GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key) = 0;
|
||||||
};
|
};
|
||||||
static_assert(ncm::IsIContentMetaDatabase<ContentMetaDatabaseImplBase>);
|
static_assert(ncm::IsIContentMetaDatabase<ContentMetaDatabaseImplBase>);
|
||||||
|
|
||||||
|
@ -918,4 +918,19 @@ namespace ams::ncm {
|
|||||||
R_THROW(ncm::ResultInvalidOperation());
|
R_THROW(ncm::ResultInvalidOperation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ContentStorageImpl::GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Get the path of the content. */
|
||||||
|
Path path;
|
||||||
|
R_TRY(this->GetPath(std::addressof(path), content_id));
|
||||||
|
|
||||||
|
/* Obtain the program id for the content. */
|
||||||
|
ncm::ProgramId program_id;
|
||||||
|
R_TRY(fs::GetProgramId(std::addressof(program_id), path.str, attr));
|
||||||
|
|
||||||
|
out.SetValue(program_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -105,6 +105,7 @@ namespace ams::ncm {
|
|||||||
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) override;
|
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) override;
|
||||||
virtual Result RegisterPath(const ContentId &content_id, const Path &path) override;
|
virtual Result RegisterPath(const ContentId &content_id, const Path &path) override;
|
||||||
virtual Result ClearRegisteredPath() override;
|
virtual Result ClearRegisteredPath() override;
|
||||||
|
virtual Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,6 +79,7 @@ namespace ams::ncm {
|
|||||||
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) = 0;
|
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) = 0;
|
||||||
virtual Result RegisterPath(const ContentId &content_id, const Path &path) = 0;
|
virtual Result RegisterPath(const ContentId &content_id, const Path &path) = 0;
|
||||||
virtual Result ClearRegisteredPath() = 0;
|
virtual Result ClearRegisteredPath() = 0;
|
||||||
|
virtual Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) = 0;
|
||||||
|
|
||||||
/* 16.0.0 Alignment change hacks. */
|
/* 16.0.0 Alignment change hacks. */
|
||||||
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
||||||
|
@ -224,4 +224,27 @@ namespace ams::ncm {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result HostContentStorageImpl::GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Get the content path. */
|
||||||
|
Path path;
|
||||||
|
R_TRY(m_registered_content->GetPath(std::addressof(path), content_id));
|
||||||
|
|
||||||
|
/* Check for correct extension. */
|
||||||
|
const auto path_len = std::strlen(path.str);
|
||||||
|
const char *extension = path.str + path_len - 1;
|
||||||
|
if (*extension == '/') {
|
||||||
|
--extension;
|
||||||
|
}
|
||||||
|
R_UNLESS(path_len >= 4 && std::memcmp(extension - 4, ".ncd", 4) == 0, ncm::ResultInvalidContentMetaDirectory());
|
||||||
|
|
||||||
|
/* Obtain the program id for the content. */
|
||||||
|
ncm::ProgramId program_id;
|
||||||
|
R_TRY(fs::GetProgramId(std::addressof(program_id), path.str, attr));
|
||||||
|
|
||||||
|
out.SetValue(program_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,7 @@ namespace ams::ncm {
|
|||||||
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
|
Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr);
|
||||||
Result RegisterPath(const ContentId &content_id, const Path &path);
|
Result RegisterPath(const ContentId &content_id, const Path &path);
|
||||||
Result ClearRegisteredPath();
|
Result ClearRegisteredPath();
|
||||||
|
Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr);
|
||||||
|
|
||||||
/* 16.0.0 Alignment change hacks. */
|
/* 16.0.0 Alignment change hacks. */
|
||||||
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
||||||
|
@ -446,4 +446,21 @@ namespace ams::ncm {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IntegratedContentMetaDatabaseImpl::GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key) {
|
||||||
|
/* Lock ourselves. */
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
/* Check that we're enabled. */
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Check that our list has interfaces to check. */
|
||||||
|
R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentMetaNotFound());
|
||||||
|
|
||||||
|
/* Check each interface in turn. */
|
||||||
|
R_RETURN(m_list.TryEach([&](const auto &data) {
|
||||||
|
/* Try the current interface. */
|
||||||
|
R_RETURN(data.interface->GetPlatform(out, key));
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -326,4 +326,31 @@ namespace ams::ncm {
|
|||||||
R_THROW(ncm::ResultInvalidOperation());
|
R_THROW(ncm::ResultInvalidOperation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result IntegratedContentStorageImpl::GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
/* Lock ourselves. */
|
||||||
|
std::scoped_lock lk(m_mutex);
|
||||||
|
|
||||||
|
/* Check that we're enabled. */
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Check that our list has interfaces to check. */
|
||||||
|
R_UNLESS(m_list.GetCount() > 0, ncm::ResultContentNotFound());
|
||||||
|
|
||||||
|
/* Check each interface in turn. */
|
||||||
|
R_TRY(m_list.TryEach([&](const auto &data) {
|
||||||
|
/* Check if the current interface has it. */
|
||||||
|
bool has;
|
||||||
|
R_TRY(data.interface->Has(std::addressof(has), content_id));
|
||||||
|
|
||||||
|
/* If it doesn't, continue on. */
|
||||||
|
R_UNLESS(has, ncm::ResultContentNotFound());
|
||||||
|
|
||||||
|
|
||||||
|
/* If it does, read the file. */
|
||||||
|
R_RETURN(data.interface->GetProgramId(out, content_id, attr));
|
||||||
|
}));
|
||||||
|
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -297,4 +297,19 @@ namespace ams::ncm {
|
|||||||
R_THROW(ncm::ResultInvalidOperation());
|
R_THROW(ncm::ResultInvalidOperation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result ReadOnlyContentStorageImpl::GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
R_TRY(this->EnsureEnabled());
|
||||||
|
|
||||||
|
/* Get the path of the content. */
|
||||||
|
Path path;
|
||||||
|
R_TRY(this->GetPath(std::addressof(path), content_id));
|
||||||
|
|
||||||
|
/* Obtain the program id for the content. */
|
||||||
|
ncm::ProgramId program_id;
|
||||||
|
R_TRY(fs::GetProgramId(std::addressof(program_id), path.str, attr));
|
||||||
|
|
||||||
|
out.SetValue(program_id);
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ namespace ams::ncm {
|
|||||||
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) override;
|
virtual Result GetRightsIdFromPlaceHolderIdWithCache(sf::Out<ncm::RightsId> out_rights_id, PlaceHolderId placeholder_id, ContentId cache_content_id, fs::ContentAttributes attr) override;
|
||||||
virtual Result RegisterPath(const ContentId &content_id, const Path &path) override;
|
virtual Result RegisterPath(const ContentId &content_id, const Path &path) override;
|
||||||
virtual Result ClearRegisteredPath() override;
|
virtual Result ClearRegisteredPath() override;
|
||||||
|
virtual Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -186,6 +186,11 @@ namespace ams::ncm {
|
|||||||
AMS_UNUSED(out_content_info, key, type, id_offset);
|
AMS_UNUSED(out_content_info, key, type, id_offset);
|
||||||
AMS_ABORT();
|
AMS_ABORT();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetPlatform(sf::Out<ncm::ContentMetaPlatform> out, const ContentMetaKey &key) {
|
||||||
|
static_assert(sizeof(ncm::ContentMetaPlatform) == sizeof(u8));
|
||||||
|
R_RETURN(ncmContentMetaDatabaseGetPlatform(std::addressof(m_srv), reinterpret_cast<u8 *>(out.GetPointer()), Convert(key)));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
static_assert(ncm::IsIContentMetaDatabase<RemoteContentMetaDatabaseImpl>);
|
static_assert(ncm::IsIContentMetaDatabase<RemoteContentMetaDatabaseImpl>);
|
||||||
#endif
|
#endif
|
||||||
|
@ -219,6 +219,11 @@ namespace ams::ncm {
|
|||||||
R_RETURN(ncmContentStorageClearRegisteredPath(std::addressof(m_srv)));
|
R_RETURN(ncmContentStorageClearRegisteredPath(std::addressof(m_srv)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result GetProgramId(sf::Out<ncm::ProgramId> out, ContentId content_id, fs::ContentAttributes attr) {
|
||||||
|
static_assert(sizeof(ncm::ProgramId) == sizeof(u64));
|
||||||
|
R_RETURN(ncmContentStorageGetProgramId(std::addressof(m_srv), reinterpret_cast<u64 *>(out.GetPointer()), Convert(content_id), Convert(attr)));
|
||||||
|
}
|
||||||
|
|
||||||
/* 16.0.0 Alignment change hacks. */
|
/* 16.0.0 Alignment change hacks. */
|
||||||
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
Result CreatePlaceHolder_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id, s64 size) { R_RETURN(this->CreatePlaceHolder(placeholder_id, content_id, size)); }
|
||||||
Result Register_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id) { R_RETURN(this->Register(placeholder_id, content_id)); }
|
Result Register_AtmosphereAlignmentFix(ContentId content_id, PlaceHolderId placeholder_id) { R_RETURN(this->Register(placeholder_id, content_id)); }
|
||||||
|
@ -44,6 +44,13 @@ namespace ams::pm::dmnt {
|
|||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result HookToCreateProcess(os::NativeHandle *out_handle, const ncm::ProgramId program_id) {
|
||||||
|
Event evt;
|
||||||
|
R_TRY(pmdmntHookToCreateProcess(std::addressof(evt), static_cast<u64>(program_id)));
|
||||||
|
*out_handle = evt.revent;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id) {
|
Result AtmosphereGetProcessInfo(os::NativeHandle *out_handle, ncm::ProgramLocation *out_loc, cfg::OverrideStatus *out_status, os::ProcessId process_id) {
|
||||||
*out_handle = os::InvalidNativeHandle;
|
*out_handle = os::InvalidNativeHandle;
|
||||||
*out_loc = {};
|
*out_loc = {};
|
||||||
|
@ -50,6 +50,7 @@ namespace ams::spl::smc {
|
|||||||
enum EsCommonKeyType {
|
enum EsCommonKeyType {
|
||||||
EsCommonKeyType_TitleKey = 0,
|
EsCommonKeyType_TitleKey = 0,
|
||||||
EsCommonKeyType_ArchiveKey = 1,
|
EsCommonKeyType_ArchiveKey = 1,
|
||||||
|
EsCommonKeyType_Unknown2 = 2,
|
||||||
|
|
||||||
EsCommonKeyType_Count,
|
EsCommonKeyType_Count,
|
||||||
};
|
};
|
||||||
@ -86,6 +87,7 @@ namespace ams::spl::smc {
|
|||||||
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
|
constexpr const u8 EsCommonKeySources[EsCommonKeyType_Count][AesKeySize] = {
|
||||||
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
|
[EsCommonKeyType_TitleKey] = { 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B },
|
||||||
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
|
[EsCommonKeyType_ArchiveKey] = { 0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D },
|
||||||
|
[EsCommonKeyType_Unknown2] = { 0x42, 0x64, 0x0B, 0xE3, 0x5F, 0xC6, 0xBE, 0x47, 0xC7, 0xB4, 0x84, 0xC5, 0xEB, 0x63, 0xAA, 0x02 },
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr u64 InvalidAsyncKey = 0;
|
constexpr u64 InvalidAsyncKey = 0;
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 5
|
#define ATMOSPHERE_RELEASE_VERSION_MINOR 6
|
||||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 5
|
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
|
||||||
|
|
||||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||||
|
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 16
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 17
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
|
||||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||||
|
@ -78,8 +78,9 @@
|
|||||||
#define ATMOSPHERE_TARGET_FIRMWARE_16_0_2 ATMOSPHERE_TARGET_FIRMWARE(16, 0, 2)
|
#define ATMOSPHERE_TARGET_FIRMWARE_16_0_2 ATMOSPHERE_TARGET_FIRMWARE(16, 0, 2)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_16_0_3 ATMOSPHERE_TARGET_FIRMWARE(16, 0, 3)
|
#define ATMOSPHERE_TARGET_FIRMWARE_16_0_3 ATMOSPHERE_TARGET_FIRMWARE(16, 0, 3)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_16_1_0 ATMOSPHERE_TARGET_FIRMWARE(16, 1, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_16_1_0 ATMOSPHERE_TARGET_FIRMWARE(16, 1, 0)
|
||||||
|
#define ATMOSPHERE_TARGET_FIRMWARE_17_0_0 ATMOSPHERE_TARGET_FIRMWARE(17, 0, 0)
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_16_1_0
|
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_17_0_0
|
||||||
|
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
||||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||||
@ -150,6 +151,7 @@ namespace ams {
|
|||||||
TargetFirmware_16_0_2 = ATMOSPHERE_TARGET_FIRMWARE_16_0_2,
|
TargetFirmware_16_0_2 = ATMOSPHERE_TARGET_FIRMWARE_16_0_2,
|
||||||
TargetFirmware_16_0_3 = ATMOSPHERE_TARGET_FIRMWARE_16_0_3,
|
TargetFirmware_16_0_3 = ATMOSPHERE_TARGET_FIRMWARE_16_0_3,
|
||||||
TargetFirmware_16_1_0 = ATMOSPHERE_TARGET_FIRMWARE_16_1_0,
|
TargetFirmware_16_1_0 = ATMOSPHERE_TARGET_FIRMWARE_16_1_0,
|
||||||
|
TargetFirmware_17_0_0 = ATMOSPHERE_TARGET_FIRMWARE_17_0_0,
|
||||||
|
|
||||||
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
||||||
|
|
||||||
|
@ -54,6 +54,8 @@ namespace ams::ncm {
|
|||||||
R_DEFINE_ERROR_RESULT(InvalidContentMetaFileSize, 390);
|
R_DEFINE_ERROR_RESULT(InvalidContentMetaFileSize, 390);
|
||||||
R_DEFINE_ERROR_RESULT(InvalidAddOnContentMetaExtendedHeader, 400);
|
R_DEFINE_ERROR_RESULT(InvalidAddOnContentMetaExtendedHeader, 400);
|
||||||
|
|
||||||
|
R_DEFINE_ERROR_RESULT(InvalidContentMetaDirectory, 430);
|
||||||
|
|
||||||
R_DEFINE_ERROR_RANGE(ContentStorageNotActive, 250, 258);
|
R_DEFINE_ERROR_RANGE(ContentStorageNotActive, 250, 258);
|
||||||
R_DEFINE_ERROR_RESULT(GameCardContentStorageNotActive, 251);
|
R_DEFINE_ERROR_RESULT(GameCardContentStorageNotActive, 251);
|
||||||
R_DEFINE_ERROR_RESULT(BuiltInSystemContentStorageNotActive, 252);
|
R_DEFINE_ERROR_RESULT(BuiltInSystemContentStorageNotActive, 252);
|
||||||
|
@ -116,6 +116,7 @@ namespace ams::svc {
|
|||||||
MemoryAttribute_IpcLocked = (1 << 1),
|
MemoryAttribute_IpcLocked = (1 << 1),
|
||||||
MemoryAttribute_DeviceShared = (1 << 2),
|
MemoryAttribute_DeviceShared = (1 << 2),
|
||||||
MemoryAttribute_Uncached = (1 << 3),
|
MemoryAttribute_Uncached = (1 << 3),
|
||||||
|
MemoryAttribute_PermissionLocked = (1 << 4),
|
||||||
};
|
};
|
||||||
|
|
||||||
enum MemoryMapping : u32 {
|
enum MemoryMapping : u32 {
|
||||||
|
@ -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(16);
|
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(17);
|
||||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 2);
|
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion( 5);
|
||||||
|
|
||||||
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
constexpr inline u32 SupportedKernelVersion = EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user