Compare commits

...

32 Commits

Author SHA1 Message Date
Michael Scire
132558c338 erpt: amend min-version for latest CreateReportWithAttachments 2023-10-12 09:22:33 -07:00
Michael Scire
5d5699a7e8 ncm: work around change in Nintendo save handling behavior
Static save files do not require an entry in the save data indexer to mount.
Prior to 17.0.0, save data files were considered static if userid was 0.
In 17.0.0+, only 8000000000000000 is static.

However, some users using cfw do not have an entry for 8000000000000120 in the indexer,
for various reasons (but mostly manual nand-restore, I think). Thus, on boot of 17.0.0+,
FS will say 8000000000000120 is not present (not in indexer), and NCM will create it anew.

The 8000000000000120 save will then be empty, and then the firmware can't boot.

To workaround this, logic has been re-enabled on 17.0.0+ for building the content meta database.
Thus, if the user encounters this error, the 8000000000000120 save will be emptied, but then
it will be automatically reconstructed, fixing the problem.
2023-10-12 09:22:32 -07:00
Michael Scire
338d7ce940 bpc.mitm/exo: support pmic reboot/shutdown on mariko (thanks @CTCaer) 2023-10-12 09:22:32 -07:00
Michael Scire
77ae1814ff erpt: remove deprecated fields, they didn't actually change IDs, just the mapping between id and name table index 2023-10-12 09:22:32 -07:00
Michael Scire
054eeddc0c erpt: Add basic (TODO-impl post-prerelease) support for 17.0.0 changes 2023-10-12 09:22:30 -07:00
Michael Scire
ee56715f3f fs: update OpenCodeFileSystem abi for 17.0.0 2023-10-12 09:22:30 -07:00
Michael Scire
c9a576e990 ncm: update for new 17.0.0 apis 2023-10-12 09:22:29 -07:00
Michael Scire
38cc50294b exo/spl: Add new EsCommonKeyType 2023-10-12 09:22:29 -07:00
Michael Scire
5c8a8adc9a fusee/exo: implement the usual changes for new firmware support 2023-10-12 09:22:28 -07:00
Michael Scire
2c77b3e1e3 kern: fix assert usage in process load 2023-10-12 09:22:28 -07:00
Michael Scire
a2cdc8626d kern: bump supported version to 17.x 2023-10-12 09:22:27 -07:00
Michael Scire
224be3e9f1 kern: fix operation type enum-value whoops 2023-10-12 09:22:27 -07:00
Michael Scire
d211eb4de7 kern: implement support for applying relr relocations 2023-10-12 09:22:27 -07:00
Michael Scire
a55dbf0819 kern: split Process/Thread exit to separate WorkerTaskManagers 2023-10-12 09:22:27 -07:00
Michael Scire
d213377313 kern: split out GetInstructionDataUserMode in exception handler 2023-10-12 09:22:26 -07:00
Michael Scire
e07b0a924d kern: Add special-case for InvalidateProcessDataCache on current process 2023-10-12 09:22:26 -07:00
Michael Scire
6dcf506423 kern: KPageTable: remove MapFirst operation, replace with MapFirstGroup 2023-10-12 09:22:25 -07:00
Michael Scire
7ac90cdb0d kern: note OnFinalize calls in KPageTable::Finalize 2023-10-12 09:22:25 -07:00
Michael Scire
dfbd37e448 kern: implement new default application system resource field in KProcess 2023-10-12 09:22:25 -07:00
Michael Scire
9d485e7df9 kern: update KMemoryRegionType values for new ids + SecureUnknown region 2023-10-12 09:22:25 -07:00
Michael Scire
9f51df06d5 kern: KSupervisorPageTable now checks wxn instead of setting it 2023-10-12 09:22:24 -07:00
Michael Scire
41eea11a19 kern: KPageTable::Initialize no longer takes unused process id 2023-10-12 09:22:24 -07:00
Michael Scire
15ca0c1b10 kern: implement PermissionLock, update KPageTableBase attribute/alignment checks 2023-10-12 09:22:24 -07:00
Michael Scire
d4319842a9 kern: KPageTableBase::CheckMemoryState now invokes a helper 2023-10-12 09:22:23 -07:00
Michael Scire
c8f04e21e5 kern: update KMemoryState, remove bijection (separate IoRegister/IoMemory) 2023-10-12 09:22:23 -07:00
Michael Scire
2c2aa8b57c kern: update initial process load logic to do per-segment mapping/decompression 2023-10-12 09:22:23 -07:00
Michael Scire
a6e34647de kern: clear new pages in init page allocator, not init page table 2023-10-12 09:22:22 -07:00
Michael Scire
8d84b5776f kern: add speculation barriers after eret 2023-10-12 09:22:22 -07:00
Michael Scire
d21f281094 kern: remove unnecessary fields from InitArgs (0x80 -> 0x40) 2023-10-12 09:22:22 -07:00
Michael Scire
3abc567a73 kern/ldr: move crt0 into .rodata 2023-10-12 09:22:21 -07:00
Michael Scire
ba1a07db68 kern: pass ini1 size from loader to kernel, remove slab memset from init0 2023-10-12 09:22:21 -07:00
Liam
540ca1351a dmnt.gen2: enable attach to arbitrary program id 2023-10-12 09:22:20 -07:00
100 changed files with 1321 additions and 534 deletions

View File

@ -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,

View File

@ -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'>;

View File

@ -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,

View File

@ -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);

View File

@ -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;
} }
} }

View File

@ -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

View File

@ -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. */

View File

@ -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. */

View File

@ -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);

View File

@ -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(); }

View File

@ -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();
} }

View File

@ -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
}; };

View File

@ -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
} }

View File

@ -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();

View File

@ -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 &params, KProcessAddress src) const; void Load(const KPageGroup &pg, KVirtualAddress data) const;
Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter &params) const; Result SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter &params) const;
}; };

View File

@ -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,43 +109,44 @@ 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,
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 {
@ -175,16 +181,17 @@ namespace ams::kern {
} }
enum KMemoryAttribute : u8 { enum KMemoryAttribute : u8 {
KMemoryAttribute_None = 0x00, KMemoryAttribute_None = 0x00,
KMemoryAttribute_All = 0xFF, KMemoryAttribute_All = 0xFF,
KMemoryAttribute_UserMask = KMemoryAttribute_All, KMemoryAttribute_UserMask = KMemoryAttribute_All,
KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked, KMemoryAttribute_Locked = ams::svc::MemoryAttribute_Locked,
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);

View File

@ -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));

View File

@ -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 {

View File

@ -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() {

View File

@ -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);

View File

@ -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) {

View File

@ -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,
}; };

View File

@ -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,9 +534,10 @@ namespace ams::kern::arch::arm64 {
MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled()); MESOSPHERE_ASSERT(!KInterruptManager::AreInterruptsEnabled());
/* Retrieve information about the exception. */ /* Retrieve information about the exception. */
const u64 esr = cpu::GetEsrEl1(); const bool is_user_mode = (context->psr & 0xF) == 0;
const u64 afsr0 = cpu::GetAfsr0El1(); const u64 esr = cpu::GetEsrEl1();
const u64 afsr1 = cpu::GetAfsr1El1(); const u64 afsr0 = cpu::GetAfsr0El1();
const u64 afsr1 = cpu::GetAfsr1El1();
u64 far = 0; u64 far = 0;
u32 data = 0; u32 data = 0;
@ -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) {

View File

@ -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;

View File

@ -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();

View File

@ -130,4 +130,4 @@ _ZN3ams4kern3svc14RestoreContextEm:
/* Return. */ /* Return. */
add sp, sp, #(EXCEPTION_CONTEXT_SIZE) add sp, sp, #(EXCEPTION_CONTEXT_SIZE)
eret ERET_WITH_SPECULATION_BARRIER

View File

@ -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

View File

@ -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;

View File

@ -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,43 +38,99 @@ 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));
/* Only allow architecture-specific relocations. */ for (size_t i = 0; i < rel_count; ++i) {
while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ } const auto &rel = reinterpret_cast<const Elf::Rel *>(dyn_rel)[i];
/* Apply the relocation. */ /* Only allow architecture-specific relocations. */
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset()); while (rel.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
*target_address += base_address;
/* Apply the relocation. */
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rel.GetOffset());
*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));
/* Only allow architecture-specific relocations. */ for (size_t i = 0; i < rela_count; ++i) {
while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ } const auto &rela = reinterpret_cast<const Elf::Rela *>(dyn_rela)[i];
/* Apply the relocation. */ /* Only allow architecture-specific relocations. */
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rela.GetOffset()); while (rela.GetType() != R_ARCHITECTURE_RELATIVE) { /* ... */ }
*target_address = base_address + rela.GetAddend();
/* Apply the relocation. */
Elf::Addr *target_address = reinterpret_cast<Elf::Addr *>(base_address + rela.GetOffset());
*target_address = base_address + rela.GetAddend();
}
}
/* 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;
}
}
} }
} }

View File

@ -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); }

View File

@ -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 {

View File

@ -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. */

View File

@ -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 {
@ -113,11 +227,13 @@ namespace ams::kern {
MESOSPHERE_ABORT_UNLESS(start_address == 0); MESOSPHERE_ABORT_UNLESS(start_address == 0);
/* Set fields in parameter. */ /* Set fields in parameter. */
out->code_address = map_start + start_address; out->code_address = map_start + start_address;
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize; out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
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 &params, 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 &params) const { Result KInitialProcessReader::SetMemoryPermissions(KProcessPageTable &page_table, const ams::svc::CreateProcessParameter &params) const {

View File

@ -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. */

View File

@ -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. */

View File

@ -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);
/* Determine the new attribute. */ /* If we need to, perform a change attribute operation. */
const KMemoryAttribute new_attr = static_cast<KMemoryAttribute>(((old_attr & ~mask) | (attr & mask))); if ((mask & KMemoryAttribute_Uncached) != 0) {
/* Determine the new attribute. */
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,32 +4452,44 @@ 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) { {
/* Check if we're at the end of the physical block. */ /* Create a page group for the current mapping range. */
if (pg_pages == 0) { KPageGroup cur_pg(m_block_info_manager);
/* Ensure there are more pages to map. */ {
MESOSPHERE_ASSERT(pg_it != pg.end()); ON_RESULT_FAILURE {
cur_pg.OpenFirst();
cur_pg.Close();
};
/* Advance our physical block. */ size_t remain_pages = map_pages;
++pg_it; while (remain_pages > 0) {
pg_phys_addr = pg_it->GetAddress(); /* Check if we're at the end of the physical block. */
pg_pages = pg_it->GetNumPages(); if (pg_pages == 0) {
/* Ensure there are more pages to map. */
MESOSPHERE_ASSERT(pg_it != pg.end());
/* Advance our physical block. */
++pg_it;
pg_phys_addr = pg_it->GetAddress();
pg_pages = pg_it->GetNumPages();
}
/* Add whatever we can to the current block. */
const size_t cur_pages = std::min(pg_pages, remain_pages);
R_TRY(cur_pg.AddBlock(pg_phys_addr + ((pg_pages - cur_pages) * PageSize), cur_pages));
/* Advance. */
remain_pages -= cur_pages;
pg_pages -= cur_pages;
}
} }
/* Map whatever we can. */ /* Map the papges. */
const size_t cur_pages = std::min(pg_pages, map_pages); R_TRY(this->Operate(updater.GetPageList(), cur_address, map_pages, cur_pg, map_properties, OperationType_MapFirstGroup, false));
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_pages, pg_phys_addr, true, map_properties, OperationType_MapFirst, false));
/* Advance. */
cur_address += cur_pages * PageSize;
map_pages -= cur_pages;
pg_phys_addr += cur_pages * PageSize;
pg_pages -= cur_pages;
} }
} }
@ -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();

View File

@ -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. */
m_system_resource->Open(); 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();
}
/* 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());
@ -315,9 +334,10 @@ namespace ams::kern {
MESOSPHERE_ASSERT(res_limit != nullptr); MESOSPHERE_ASSERT(res_limit != nullptr);
/* 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_immortal = false; m_is_default_application_system_resource = false;
m_is_immortal = false;
/* Get the memory sizes. */ /* Get the memory sizes. */
const size_t code_num_pages = params.code_num_pages; const size_t code_num_pages = params.code_num_pages;
@ -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();
} }
} }

View File

@ -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");

View File

@ -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();

View File

@ -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. */
R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size)); if (process.GetPointerUnsafe() == GetCurrentProcessPointer()) {
R_TRY(process->GetPageTable().InvalidateCurrentProcessDataCache(address, size));
} else {
R_TRY(process->GetPageTable().InvalidateProcessDataCache(address, size));
}
R_SUCCEED(); R_SUCCEED();
} }

View File

@ -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);

View File

@ -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());

View File

@ -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();

View File

@ -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 ) \

View File

@ -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;

View File

@ -20,24 +20,26 @@
#include <stratosphere/erpt/erpt_multiple_category_context.hpp> #include <stratosphere/erpt/erpt_multiple_category_context.hpp>
#include <stratosphere/time/time_steady_clock_time_point.hpp> #include <stratosphere/time/time_steady_clock_time_point.hpp>
#define AMS_ERPT_I_CONTEXT_INTERFACE_INFO(C, H) \ #define AMS_ERPT_I_CONTEXT_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 0, Result, SubmitContext, (const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer), (ctx_buffer, str_buffer)) \ AMS_SF_METHOD_INFO(C, H, 0, Result, SubmitContext, (const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer), (ctx_buffer, str_buffer)) \
AMS_SF_METHOD_INFO(C, H, 1, Result, CreateReportV0, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer), (report_type, ctx_buffer, str_buffer, meta_buffer)) \ AMS_SF_METHOD_INFO(C, H, 1, Result, CreateReportV0, (erpt::ReportType report_type, const ams::sf::InBuffer &ctx_buffer, const ams::sf::InBuffer &str_buffer, const ams::sf::InBuffer &meta_buffer), (report_type, ctx_buffer, str_buffer, meta_buffer)) \
AMS_SF_METHOD_INFO(C, H, 2, Result, SetInitialLaunchSettingsCompletionTime, (const time::SteadyClockTimePoint &time_point), (time_point), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 2, Result, SetInitialLaunchSettingsCompletionTime, (const time::SteadyClockTimePoint &time_point), (time_point), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 3, Result, ClearInitialLaunchSettingsCompletionTime, (), (), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 3, Result, ClearInitialLaunchSettingsCompletionTime, (), (), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 4, Result, UpdatePowerOnTime, (), (), hos::Version_3_0_0) \ AMS_SF_METHOD_INFO(C, H, 4, Result, UpdatePowerOnTime, (), (), hos::Version_3_0_0) \
AMS_SF_METHOD_INFO(C, H, 5, Result, UpdateAwakeTime, (), (), hos::Version_3_0_0, hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 5, Result, UpdateAwakeTime, (), (), hos::Version_3_0_0, hos::Version_12_0_0) \
AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleCategoryContext, (const erpt::MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer), (ctx_entry, str_buffer), hos::Version_5_0_0, hos::Version_12_0_0) \ AMS_SF_METHOD_INFO(C, H, 6, Result, SubmitMultipleCategoryContext, (const erpt::MultipleCategoryContextEntry &ctx_entry, const ams::sf::InBuffer &str_buffer), (ctx_entry, str_buffer), hos::Version_5_0_0, hos::Version_12_0_0) \
AMS_SF_METHOD_INFO(C, H, 7, Result, UpdateApplicationLaunchTime, (), (), hos::Version_6_0_0) \ AMS_SF_METHOD_INFO(C, H, 7, Result, UpdateApplicationLaunchTime, (), (), 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, 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, 20, Result, RegisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_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, 21, Result, UnregisterRunningApplet, (ncm::ProgramId program_id), (program_id), hos::Version_12_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, 22, Result, UpdateAppletSuspendedDuration, (ncm::ProgramId program_id, TimeSpanType duration), (program_id, duration), 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, 30, Result, InvalidateForcedShutdownDetection, (), (), 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, 30, Result, InvalidateForcedShutdownDetection, (), (), hos::Version_12_0_0)
AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO, 0xDD41DD03) AMS_SF_DEFINE_INTERFACE(ams::erpt::sf, IContext, AMS_ERPT_I_CONTEXT_INTERFACE_INFO, 0xDD41DD03)

View File

@ -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>();
} }

View File

@ -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>

View 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);
}

View File

@ -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());
} }

View File

@ -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) \

View File

@ -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)

View File

@ -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,

View File

@ -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;

View File

@ -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));
}
}; };
} }

View File

@ -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,
};
}

View File

@ -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));
}
}; };
} }

View File

@ -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)

View File

@ -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)

View File

@ -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>);

View File

@ -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)); }

View File

@ -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)

View File

@ -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 {

View File

@ -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));
} }

View File

@ -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));

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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();
} }

View File

@ -164,7 +164,7 @@ namespace ams::erpt::srv {
if (R_FAILED(svc::GetResourceLimitLimitValue(std::addressof(limit_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ if (R_FAILED(svc::GetResourceLimitLimitValue(std::addressof(limit_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \
return; \ return; \
} \ } \
if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Limit, limit_value))) { \ if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Limit, limit_value))) { \
return; \ return; \
} \ } \
} while (0) } while (0)
@ -203,7 +203,7 @@ namespace ams::erpt::srv {
if (R_FAILED(svc::GetResourceLimitPeakValue(std::addressof(peak_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \ if (R_FAILED(svc::GetResourceLimitPeakValue(std::addressof(peak_value), handle, svc::LimitableResource_##__RESOURCE__##Max))) { \
return; \ return; \
} \ } \
if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Peak, peak_value))) { \ if (R_FAILED(record->Add(FieldId_System##__RESOURCE__##Peak, peak_value))) { \
return; \ return; \
} \ } \
} while (0) } while (0)
@ -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 &timestamp_user, const time::PosixTime &timestamp_network) { Result Reporter::SubmitReportContexts(const ReportId &report_id, ReportType type, Result ctx_result, std::unique_ptr<ContextRecord> record, const time::PosixTime &timestamp_user, const time::PosixTime &timestamp_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();
} }

View File

@ -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);
}; };
} }

View File

@ -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));

View 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();
}
}

View File

@ -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));

View File

@ -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)));

View File

@ -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";
} }
} }

View File

@ -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);
} }

View File

@ -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));

View File

@ -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,
}; };
} }

View File

@ -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();
}
} }

View File

@ -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;
}; };
} }

View File

@ -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>);

View File

@ -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();
}
} }

View File

@ -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;
}; };
} }

View File

@ -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)); }

View File

@ -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();
}
} }

View File

@ -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)); }

View File

@ -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));
}));
}
} }

View File

@ -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();
}
} }

View File

@ -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();
}
} }

View File

@ -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;
}; };
} }

View File

@ -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

View File

@ -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)); }

View File

@ -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 = {};

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -112,10 +112,11 @@ namespace ams::svc {
}; };
enum MemoryAttribute : u32 { enum MemoryAttribute : u32 {
MemoryAttribute_Locked = (1 << 0), MemoryAttribute_Locked = (1 << 0),
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 {

View File

@ -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);