mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-04-19 19:14:52 +00:00
Compare commits
7 commits
1.8.0-prer
...
master
Author | SHA1 | Date | |
---|---|---|---|
|
6125f40bdb | ||
|
85fd13f724 | ||
|
4e99a5e08d | ||
|
9f8d17b9e6 | ||
|
3a5f70dceb | ||
|
e51e11a71c | ||
|
57e15f3622 |
32 changed files with 500 additions and 112 deletions
|
@ -49,7 +49,7 @@ Code type 0x0 allows writing a static value to a memory address.
|
|||
`0TMR00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
||||
|
||||
+ T: Width of memory write (1, 2, 4, or 8 bytes).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative).
|
||||
+ R: Register to use as an offset from memory region base.
|
||||
+ A: Immediate offset to use from memory region base.
|
||||
+ V: Value to write.
|
||||
|
@ -62,11 +62,13 @@ Code type 0x1 performs a comparison of the contents of memory to a static value.
|
|||
If the condition is not met, all instructions until the appropriate End or Else conditional block terminator are skipped.
|
||||
|
||||
#### Encoding
|
||||
`1TMC00AA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
||||
`1TMCXrAA AAAAAAAA VVVVVVVV (VVVVVVVV)`
|
||||
|
||||
+ T: Width of memory write (1, 2, 4, or 8 bytes).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr).
|
||||
+ T: Width of memory read (1, 2, 4, or 8 bytes).
|
||||
+ M: Memory region to read from (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative).
|
||||
+ C: Condition to use, see below.
|
||||
+ X: Operand Type, see below.
|
||||
+ r: Offset Register (operand types 1).
|
||||
+ A: Immediate offset to use from memory region base.
|
||||
+ V: Value to compare to.
|
||||
|
||||
|
@ -78,6 +80,9 @@ If the condition is not met, all instructions until the appropriate End or Else
|
|||
+ 5: ==
|
||||
+ 6: !=
|
||||
|
||||
#### Operand Type
|
||||
+ 0: Memory Base + Relative Offset
|
||||
+ 1: Memory Base + Offset Register + Relative Offset
|
||||
---
|
||||
|
||||
### Code Type 0x2: End Conditional Block
|
||||
|
@ -126,7 +131,7 @@ Code type 0x5 allows loading a value from memory into a register, either using a
|
|||
`5TMR00AA AAAAAAAA`
|
||||
|
||||
+ T: Width of memory read (1, 2, 4, or 8 bytes).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative).
|
||||
+ R: Register to load value into.
|
||||
+ A: Immediate offset to use from memory region base.
|
||||
|
||||
|
@ -137,6 +142,22 @@ Code type 0x5 allows loading a value from memory into a register, either using a
|
|||
+ R: Register to load value into. (This register is also used as the base memory address).
|
||||
+ A: Immediate offset to use from register R.
|
||||
|
||||
#### Load from Register Address Encoding
|
||||
`5T0R2SAA AAAAAAAA`
|
||||
|
||||
+ T: Width of memory read (1, 2, 4, or 8 bytes).
|
||||
+ R: Register to load value into.
|
||||
+ S: Register to use as the base memory address.
|
||||
+ A: Immediate offset to use from register R.
|
||||
|
||||
#### Load From Fixed Address Encoding with offset register
|
||||
`5TMR3SAA AAAAAAAA`
|
||||
|
||||
+ T: Width of memory read (1, 2, 4, or 8 bytes).
|
||||
+ M: Memory region to write to (0 = Main NSO, 1 = Heap, 2 = Alias, 3 = Aslr, 4 = non-relative).
|
||||
+ R: Register to load value into.
|
||||
+ S: Register to use as offset register.
|
||||
+ A: Immediate offset to use from memory region base.
|
||||
---
|
||||
|
||||
### Code Type 0x6: Store Static Value to Register Memory Address
|
||||
|
@ -250,7 +271,10 @@ Code type 0x9 allows performing arithmetic on registers.
|
|||
+ 7: Logical Not (discards right-hand operand)
|
||||
+ 8: Logical Xor
|
||||
+ 9: None/Move (discards right-hand operand)
|
||||
|
||||
+ 10: Float Addition, T==4 single T==8 double
|
||||
+ 11: Float Subtraction, T==4 single T==8 double
|
||||
+ 12: Float Multiplication, T==4 single T==8 double
|
||||
+ 13: Float Division, T==4 single T==8 double
|
||||
---
|
||||
|
||||
### Code Type 0xA: Store Register to Memory Address
|
||||
|
@ -380,6 +404,61 @@ Code type 0xC3 reads or writes a static register with a given register.
|
|||
|
||||
---
|
||||
|
||||
### Code Type 0xC4: Begin Extended Keypress Conditional Block
|
||||
Code type 0xC4 enters or skips a conditional block based on whether a key combination is pressed.
|
||||
|
||||
#### Encoding
|
||||
`C4r00000 kkkkkkkk kkkkkkkk`
|
||||
|
||||
+ r: Auto-repeat, see below.
|
||||
+ kkkkkkkkkk: Keypad mask to check against output of `hidKeysDown()`.
|
||||
|
||||
Note that for multiple button combinations, the bitmasks should be OR'd together.
|
||||
|
||||
#### Auto-repeat
|
||||
|
||||
+ 0: The conditional block executes only once when the keypad mask matches. The mask must stop matching to reset for the next trigger.
|
||||
+ 1: The conditional block executes as long as the keypad mask matches.
|
||||
|
||||
#### Keypad Values
|
||||
Note: This is the direct output of `hidKeysDown()`.
|
||||
|
||||
+ 000000001: A
|
||||
+ 000000002: B
|
||||
+ 000000004: X
|
||||
+ 000000008: Y
|
||||
+ 000000010: Left Stick Pressed
|
||||
+ 000000020: Right Stick Pressed
|
||||
+ 000000040: L
|
||||
+ 000000080: R
|
||||
+ 000000100: ZL
|
||||
+ 000000200: ZR
|
||||
+ 000000400: Plus
|
||||
+ 000000800: Minus
|
||||
+ 000001000: Left
|
||||
+ 000002000: Up
|
||||
+ 000004000: Right
|
||||
+ 000008000: Down
|
||||
+ 000010000: Left Stick Left
|
||||
+ 000020000: Left Stick Up
|
||||
+ 000040000: Left Stick Right
|
||||
+ 000080000: Left Stick Down
|
||||
+ 000100000: Right Stick Left
|
||||
+ 000200000: Right Stick Up
|
||||
+ 000400000: Right Stick Right
|
||||
+ 000800000: Right Stick Down
|
||||
+ 001000000: SL Left Joy-Con
|
||||
+ 002000000: SR Left Joy-Con
|
||||
+ 004000000: SL Right Joy-Con
|
||||
+ 008000000: SR Right Joy-Con
|
||||
+ 010000000: Top button on Poké Ball Plus (Palma) controller
|
||||
+ 020000000: Verification
|
||||
+ 040000000: B button on Left NES/HVC controller in Handheld mode
|
||||
+ 080000000: Left C button in N64 controller
|
||||
+ 100000000: Up C button in N64 controller
|
||||
+ 200000000: Right C button in N64 controller
|
||||
+ 400000000: Down C button in N64 controller
|
||||
|
||||
### Code Type 0xF0: Double Extended-Width Instruction
|
||||
Code Type 0xF0 signals to the VM to treat the upper three nybbles of the first dword as instruction type, instead of just the upper nybble.
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||
|
||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||
if (l1_entry->IsMappedBlock() || l1_entry->IsEmpty()) {
|
||||
if (l1_entry->IsMappedBlock() || l1_entry->IsMappedEmpty()) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
|
||||
virt_addr += L1BlockSize;
|
||||
|
@ -126,7 +126,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
/* Table, so check if we're mapped in L2. */
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
if (l2_entry->IsMappedBlock() || l2_entry->IsEmpty()) {
|
||||
if (l2_entry->IsMappedBlock() || l2_entry->IsMappedEmpty()) {
|
||||
const size_t advance_size = (l2_entry->IsMappedBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
|
@ -144,7 +144,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* L3 must be block or empty. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsEmpty());
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsMappedEmpty());
|
||||
|
||||
const size_t advance_size = (l3_entry->IsMappedBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
|
@ -164,7 +164,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
L1PageTableEntry *l1_entry = this->GetL1Entry(virt_addr);
|
||||
|
||||
/* If an L1 block is mapped or we're empty, advance by L1BlockSize. */
|
||||
if (l1_entry->IsMappedBlock() || l1_entry->IsEmpty()) {
|
||||
if (l1_entry->IsMappedBlock() || l1_entry->IsMappedEmpty()) {
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= L1BlockSize);
|
||||
if (l1_entry->IsMappedBlock() && block_size == L1BlockSize) {
|
||||
|
@ -182,7 +182,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
/* Table, so check if we're mapped in L2. */
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
if (l2_entry->IsMappedBlock() || l2_entry->IsEmpty()) {
|
||||
if (l2_entry->IsMappedBlock() || l2_entry->IsMappedEmpty()) {
|
||||
const size_t advance_size = (l2_entry->IsMappedBlock() && l2_entry->IsContiguous()) ? L2ContiguousBlockSize : L2BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(static_cast<size_t>(end_virt_addr - virt_addr) >= advance_size);
|
||||
|
@ -202,7 +202,7 @@ namespace ams::kern::arch::arm64::init {
|
|||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* L3 must be block or empty. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsEmpty());
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(l3_entry->IsMappedBlock() || l3_entry->IsMappedEmpty());
|
||||
|
||||
const size_t advance_size = (l3_entry->IsMappedBlock() && l3_entry->IsContiguous()) ? L3ContiguousBlockSize : L3BlockSize;
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), advance_size));
|
||||
|
|
|
@ -122,7 +122,7 @@ namespace ams::kern::arch::arm64 {
|
|||
|
||||
/* Construct a new attribute. */
|
||||
constexpr explicit ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share, MappingFlag m)
|
||||
: m_attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share) | static_cast<u64>(ExtensionFlag_Valid) | static_cast<u64>(m))
|
||||
: m_attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share) | static_cast<u64>(m))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
@ -205,6 +205,7 @@ namespace ams::kern::arch::arm64 {
|
|||
|
||||
constexpr ALWAYS_INLINE bool IsMappedBlock() const { return this->GetBits(0, 2) == 1; }
|
||||
constexpr ALWAYS_INLINE bool IsMappedTable() const { return this->GetBits(0, 2) == 3; }
|
||||
constexpr ALWAYS_INLINE bool IsMappedEmpty() const { return this->GetBits(0, 2) == 0; }
|
||||
constexpr ALWAYS_INLINE bool IsMapped() const { return this->GetBits(0, 1) != 0; }
|
||||
|
||||
constexpr ALWAYS_INLINE decltype(auto) SetUserExecuteNever(bool en) { this->SetBit(54, en); return *this; }
|
||||
|
|
|
@ -21,12 +21,6 @@ namespace ams::kern::arch::arm64 {
|
|||
m_table = static_cast<L1PageTableEntry *>(tb);
|
||||
m_is_kernel = true;
|
||||
m_num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize;
|
||||
}
|
||||
|
||||
void KPageTableImpl::InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end) {
|
||||
m_table = static_cast<L1PageTableEntry *>(tb);
|
||||
m_is_kernel = false;
|
||||
m_num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize;
|
||||
|
||||
/* Page table entries created by KInitialPageTable need to be iterated and modified to ensure KPageTable invariants. */
|
||||
PageTableEntry *level_entries[EntryLevel_Count] = { nullptr, nullptr, m_table };
|
||||
|
@ -68,7 +62,6 @@ namespace ams::kern::arch::arm64 {
|
|||
/* Advance. */
|
||||
while (true) {
|
||||
/* Advance to the next entry at the current level. */
|
||||
++level_entries[level];
|
||||
if (!util::IsAligned(reinterpret_cast<uintptr_t>(++level_entries[level]), PageSize)) {
|
||||
break;
|
||||
}
|
||||
|
@ -83,6 +76,12 @@ namespace ams::kern::arch::arm64 {
|
|||
}
|
||||
}
|
||||
|
||||
void KPageTableImpl::InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end) {
|
||||
m_table = static_cast<L1PageTableEntry *>(tb);
|
||||
m_is_kernel = false;
|
||||
m_num_entries = util::AlignUp(end - start, L1BlockSize) / L1BlockSize;
|
||||
}
|
||||
|
||||
L1PageTableEntry *KPageTableImpl::Finalize() {
|
||||
return m_table;
|
||||
}
|
||||
|
|
|
@ -1214,7 +1214,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
for (size_t i = 0; i < map_count; ++i) {
|
||||
/* Get the physical address. */
|
||||
const KPhysicalAddress phys_addr = l2[l2_index + i].GetPhysicalAddress();
|
||||
MESOSPHERE_ASSERT(IsHeapPhysicalAddress(phys_addr));
|
||||
MESOSPHERE_ASSERT(phys_addr == Null<KPhysicalAddress> || IsHeapPhysicalAddress(phys_addr));
|
||||
|
||||
/* Fully invalidate the entry. */
|
||||
l2[l2_index + i].Invalidate();
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace ams::impl {
|
|||
AMS_DEFINE_SYSTEM_THREAD(16, creport, Main);
|
||||
|
||||
/* ro. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(16, ro, Main);
|
||||
AMS_DEFINE_SYSTEM_THREAD(21, ro, Main);
|
||||
|
||||
/* gpio. */
|
||||
AMS_DEFINE_SYSTEM_THREAD(-12, gpio, InterruptHandler);
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace ams::ddsf {
|
|||
}
|
||||
|
||||
void DetachDevice() {
|
||||
AMS_ASSERT(this->IsOpen());
|
||||
/* AMS_ASSERT(this->IsOpen()); */
|
||||
m_device = nullptr;
|
||||
m_access_mode = AccessMode_None;
|
||||
AMS_ASSERT(!this->IsOpen());
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/fssystem/fssystem_nca_file_system_driver.hpp>
|
||||
#include <stratosphere/ldr/ldr_platform_id.hpp>
|
||||
#include <stratosphere/ncm/ncm_content_meta_platform.hpp>
|
||||
|
||||
namespace ams::fssystem {
|
||||
|
||||
|
@ -26,10 +26,10 @@ namespace ams::fssystem {
|
|||
|
||||
void InvalidateHardwareAesKey();
|
||||
|
||||
bool IsValidSignatureKeyGeneration(ldr::PlatformId platform, size_t key_generation);
|
||||
bool IsValidSignatureKeyGeneration(ncm::ContentMetaPlatform platform, size_t key_generation);
|
||||
|
||||
const u8 *GetAcidSignatureKeyModulus(ldr::PlatformId platform, bool prod, size_t key_generation, bool unk_unused);
|
||||
size_t GetAcidSignatureKeyModulusSize(ldr::PlatformId platform, bool unk_unused);
|
||||
const u8 *GetAcidSignatureKeyModulus(ncm::ContentMetaPlatform platform, bool prod, size_t key_generation, bool unk_unused);
|
||||
size_t GetAcidSignatureKeyModulusSize(ncm::ContentMetaPlatform platform, bool unk_unused);
|
||||
|
||||
const u8 *GetAcidSignatureKeyPublicExponent();
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::ldr {
|
||||
|
||||
/* TODO: Is this really a FS type? What namespace does this actually live inside? */
|
||||
enum PlatformId {
|
||||
PlatformId_Nx = 0,
|
||||
};
|
||||
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
#include <stratosphere/ncm/ncm_ids.hpp>
|
||||
#include <stratosphere/ncm/ncm_program_location.hpp>
|
||||
#include <stratosphere/sf/sf_buffer_tags.hpp>
|
||||
#include <stratosphere/ldr/ldr_platform_id.hpp>
|
||||
#include <stratosphere/ncm/ncm_content_meta_platform.hpp>
|
||||
|
||||
namespace ams::ldr {
|
||||
|
||||
|
|
|
@ -154,12 +154,14 @@ spl_secure_monitor_api.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/l
|
|||
fs_id_string_impl.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include
|
||||
|
||||
ifeq ($(ATMOSPHERE_OS_NAME),windows)
|
||||
# I do not remember why these had fno-lto, but it appears to
|
||||
# work without no-lto (2023/03/09), so I am disabling these. I may regret this later.
|
||||
#os_%.o: CXXFLAGS += -fno-lto
|
||||
#fssystem_%.o: CXXFLAGS += -fno-lto
|
||||
#fssrv_%.o: CXXFLAGS += -fno-lto
|
||||
#fs_%.o: CXXFLAGS += -fno-lto
|
||||
# Audit builds fail when these have lto disabled.
|
||||
# Noting 10/29/24:
|
||||
# In member function '__ct ':
|
||||
# internal compiler error: in binds_to_current_def_p, at symtab.cc:2589
|
||||
os_%.o: CXXFLAGS += -fno-lto
|
||||
fssystem_%.o: CXXFLAGS += -fno-lto
|
||||
fssrv_%.o: CXXFLAGS += -fno-lto
|
||||
fs_%.o: CXXFLAGS += -fno-lto
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace ams::diag {
|
|||
|
||||
namespace impl {
|
||||
|
||||
constexpr inline size_t DebugPrintBufferLength = 0x80;
|
||||
constexpr inline size_t DebugPrintBufferLength = 0x100;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -537,6 +537,8 @@ namespace ams::erpt::srv {
|
|||
/* NOTE: Nintendo ignores the result of this call. */
|
||||
SubmitFsInfo();
|
||||
}
|
||||
#else
|
||||
AMS_UNUSED(flags);
|
||||
#endif
|
||||
|
||||
|
||||
|
|
|
@ -297,20 +297,20 @@ namespace ams::fssystem {
|
|||
}
|
||||
}
|
||||
|
||||
bool IsValidSignatureKeyGeneration(ldr::PlatformId platform, size_t key_generation) {
|
||||
bool IsValidSignatureKeyGeneration(ncm::ContentMetaPlatform platform, size_t key_generation) {
|
||||
switch (platform) {
|
||||
case ldr::PlatformId_Nx:
|
||||
case ncm::ContentMetaPlatform::Nx:
|
||||
return key_generation <= NxAcidSignatureKeyGenerationMax;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
||||
const u8 *GetAcidSignatureKeyModulus(ldr::PlatformId platform, bool prod, size_t key_generation, bool unk_unused) {
|
||||
const u8 *GetAcidSignatureKeyModulus(ncm::ContentMetaPlatform platform, bool prod, size_t key_generation, bool unk_unused) {
|
||||
AMS_ASSERT(IsValidSignatureKeyGeneration(platform, key_generation));
|
||||
AMS_UNUSED(unk_unused);
|
||||
|
||||
switch (platform) {
|
||||
case ldr::PlatformId_Nx:
|
||||
case ncm::ContentMetaPlatform::Nx:
|
||||
{
|
||||
const size_t used_keygen = (key_generation % (NxAcidSignatureKeyGenerationMax + 1));
|
||||
return prod ? NxAcidSignatureKeyModulusProd[used_keygen] : NxAcidSignatureKeyModulusDev[used_keygen];
|
||||
|
@ -319,11 +319,11 @@ namespace ams::fssystem {
|
|||
}
|
||||
}
|
||||
|
||||
size_t GetAcidSignatureKeyModulusSize(ldr::PlatformId platform, bool unk_unused) {
|
||||
size_t GetAcidSignatureKeyModulusSize(ncm::ContentMetaPlatform platform, bool unk_unused) {
|
||||
AMS_UNUSED(unk_unused);
|
||||
|
||||
switch (platform) {
|
||||
case ldr::PlatformId_Nx:
|
||||
case ncm::ContentMetaPlatform::Nx:
|
||||
return NxAcidSignatureKeyModulusSize;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
|
|
@ -1346,7 +1346,7 @@ namespace ams::fssystem {
|
|||
R_UNLESS(::GetLastError() == ERROR_ACCESS_DENIED, last_error_result);
|
||||
|
||||
/* Check if we tried to open a directory. */
|
||||
fs::DirectoryEntryType type;
|
||||
fs::DirectoryEntryType type{};
|
||||
R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get()));
|
||||
|
||||
/* If the type is anything other than directory, perform generic result conversion. */
|
||||
|
@ -1459,7 +1459,7 @@ namespace ams::fssystem {
|
|||
R_TRY(this->ResolveFullPath(std::addressof(native_new_path), new_path, MaxFilePathLength, 0, false));
|
||||
|
||||
/* Check that the old path is a file. */
|
||||
fs::DirectoryEntryType type;
|
||||
fs::DirectoryEntryType type{};
|
||||
R_TRY(GetEntryTypeImpl(std::addressof(type), native_old_path.get()));
|
||||
R_UNLESS(type == fs::DirectoryEntryType_File, fs::ResultPathNotFound());
|
||||
|
||||
|
@ -1509,7 +1509,7 @@ namespace ams::fssystem {
|
|||
R_TRY(this->ResolveFullPath(std::addressof(native_new_path), new_path, MaxDirectoryPathLength, 0, false));
|
||||
|
||||
/* Check that the old path is a file. */
|
||||
fs::DirectoryEntryType type;
|
||||
fs::DirectoryEntryType type{};
|
||||
R_TRY(GetEntryTypeImpl(std::addressof(type), native_old_path.get()));
|
||||
R_UNLESS(type == fs::DirectoryEntryType_Directory, fs::ResultPathNotFound());
|
||||
|
||||
|
@ -1577,7 +1577,7 @@ namespace ams::fssystem {
|
|||
R_UNLESS(::GetLastError() == ERROR_ACCESS_DENIED, last_error_result);
|
||||
|
||||
/* Check if we tried to open a directory. */
|
||||
fs::DirectoryEntryType type;
|
||||
fs::DirectoryEntryType type{};
|
||||
R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get()));
|
||||
|
||||
/* If the type isn't file, return path not found. */
|
||||
|
@ -1623,7 +1623,7 @@ namespace ams::fssystem {
|
|||
ON_RESULT_FAILURE { ::CloseHandle(dir_handle); };
|
||||
|
||||
/* Check that we tried to open a directory. */
|
||||
fs::DirectoryEntryType type;
|
||||
fs::DirectoryEntryType type{};
|
||||
R_TRY(GetEntryTypeImpl(std::addressof(type), native_path.get()));
|
||||
|
||||
/* If the type isn't directory, return path not found. */
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ams::powctl {
|
|||
namespace {
|
||||
|
||||
impl::SessionImpl &GetOpenSessionImpl(Session &session) {
|
||||
AMS_ASSERT(session.has_session);
|
||||
/* AMS_ASSERT(session.has_session); */
|
||||
auto &impl = GetReference(session.impl_storage);
|
||||
AMS_ASSERT(impl.IsOpen());
|
||||
return impl;
|
||||
|
|
|
@ -22,7 +22,7 @@ namespace ams::powctl {
|
|||
namespace {
|
||||
|
||||
impl::SessionImpl &GetOpenSessionImpl(Session &session) {
|
||||
AMS_ASSERT(session.has_session);
|
||||
/* AMS_ASSERT(session.has_session); */
|
||||
auto &impl = GetReference(session.impl_storage);
|
||||
AMS_ASSERT(impl.IsOpen());
|
||||
return impl;
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace ams {
|
||||
|
||||
constexpr inline size_t DefaultAlignment = alignof(max_align_t);
|
||||
constexpr inline size_t DefaultAlignment = /*alignof(max_align_t)*/ 0x8;
|
||||
|
||||
using AllocateFunction = void *(*)(size_t);
|
||||
using AllocateFunctionWithUserData = void *(*)(size_t, void *);
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <vapours/crypto/crypto_aes_ctr_encryptor_decryptor.hpp>
|
||||
#include <vapours/crypto/crypto_aes_xts_encryptor_decryptor.hpp>
|
||||
#include <vapours/crypto/crypto_aes_gcm_encryptor.hpp>
|
||||
#include <vapours/crypto/crypto_aes_128_cmac_generator.hpp>
|
||||
#include <vapours/crypto/crypto_rsa_pkcs1_sha256_verifier.hpp>
|
||||
#include <vapours/crypto/crypto_rsa_pss_sha256_verifier.hpp>
|
||||
#include <vapours/crypto/crypto_rsa_oaep_sha256_decoder.hpp>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/crypto_aes_encryptor.hpp>
|
||||
#include <vapours/crypto/crypto_cmac_generator.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
class Aes128CmacGenerator {
|
||||
NON_COPYABLE(Aes128CmacGenerator);
|
||||
NON_MOVEABLE(Aes128CmacGenerator);
|
||||
public:
|
||||
static constexpr size_t MacSize = AesEncryptor128::BlockSize;
|
||||
private:
|
||||
AesEncryptor128 m_aes;
|
||||
CmacGenerator<AesEncryptor128> m_cmac_generator;
|
||||
public:
|
||||
Aes128CmacGenerator() { /* ... */ }
|
||||
|
||||
void Initialize(const void *key, size_t key_size) {
|
||||
AMS_ASSERT(key_size == AesEncryptor128::KeySize);
|
||||
|
||||
m_aes.Initialize(key, key_size);
|
||||
m_cmac_generator.Initialize(std::addressof(m_aes));
|
||||
}
|
||||
|
||||
void Update(const void *data, size_t size) {
|
||||
m_cmac_generator.Update(data, size);
|
||||
}
|
||||
|
||||
void GetMac(void *dst, size_t size) {
|
||||
m_cmac_generator.GetMac(dst, size);
|
||||
}
|
||||
};
|
||||
|
||||
ALWAYS_INLINE void GenerateAes128Cmac(void *dst, size_t dst_size, const void *data, size_t data_size, const void *key, size_t key_size) {
|
||||
Aes128CmacGenerator cmac_generator;
|
||||
|
||||
cmac_generator.Initialize(key, key_size);
|
||||
cmac_generator.Update(data, data_size);
|
||||
cmac_generator.GetMac(dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_cmac_impl.hpp>
|
||||
|
||||
namespace ams::crypto {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CmacGenerator {
|
||||
NON_COPYABLE(CmacGenerator);
|
||||
NON_MOVEABLE(CmacGenerator);
|
||||
private:
|
||||
using Impl = impl::CmacImpl<BlockCipher>;
|
||||
public:
|
||||
static constexpr size_t MacSize = BlockCipher::BlockSize;
|
||||
private:
|
||||
Impl m_impl;
|
||||
public:
|
||||
CmacGenerator() { /* ... */ }
|
||||
|
||||
void Initialize(const BlockCipher *cipher) {
|
||||
return m_impl.Initialize(cipher);
|
||||
}
|
||||
|
||||
void Update(const void *data, size_t size) {
|
||||
return m_impl.Update(data, size);
|
||||
}
|
||||
|
||||
void GetMac(void *dst, size_t dst_size) {
|
||||
return m_impl.GetMac(dst, dst_size);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
#include <vapours/assert.hpp>
|
||||
#include <vapours/util.hpp>
|
||||
#include <vapours/crypto/impl/crypto_hash_function.hpp>
|
||||
#include <vapours/crypto/impl/crypto_cbc_mac_impl.hpp>
|
||||
#include <vapours/crypto/crypto_memory_clear.hpp>
|
||||
|
||||
namespace ams::crypto::impl {
|
||||
|
||||
template<typename BlockCipher>
|
||||
class CmacImpl {
|
||||
NON_COPYABLE(CmacImpl);
|
||||
NON_MOVEABLE(CmacImpl);
|
||||
public:
|
||||
static constexpr size_t BlockSize = BlockCipher::BlockSize;
|
||||
static constexpr size_t MacSize = BlockSize;
|
||||
static_assert(BlockSize == 0x10); /* TODO: Should this be supported? */
|
||||
private:
|
||||
enum State {
|
||||
State_None = 0,
|
||||
State_Initialized = 1,
|
||||
State_Done = 2,
|
||||
};
|
||||
private:
|
||||
CbcMacImpl m_cbc_mac_impl;
|
||||
u8 m_sub_key[BlockSize];
|
||||
State m_state;
|
||||
public:
|
||||
CmacImpl() : m_state(State_None) { /* ... */ }
|
||||
~CmacImpl() {
|
||||
/* Clear everything. */
|
||||
ClearMemory(this, sizeof(*this));
|
||||
}
|
||||
|
||||
void Initialize(const BlockCipher *cipher);
|
||||
void Update(const void *data, size_t data_size);
|
||||
void GetMac(void *dst, size_t dst_size);
|
||||
private:
|
||||
static void MultiplyOneOverGF128(u8 *data) {
|
||||
/* Determine the carry bit. */
|
||||
const u8 carry = data[0] & 0x80;
|
||||
|
||||
/* Shift all bytes by one bit. */
|
||||
for (size_t i = 0; i < BlockSize - 1; ++i) {
|
||||
data[i] = (data[i] << 1) | (data[i + 1] >> 7);
|
||||
}
|
||||
data[BlockSize - 1] <<= 1;
|
||||
|
||||
/* Adjust based on carry. */
|
||||
if (carry) {
|
||||
data[BlockSize - 1] ^= 0x87;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::Initialize(const BlockCipher *cipher) {
|
||||
/* Clear the key storage. */
|
||||
std::memset(m_sub_key, 0, sizeof(m_sub_key));
|
||||
|
||||
/* Set the key storage. */
|
||||
cipher->EncryptBlock(m_sub_key, BlockSize, m_sub_key, BlockSize);
|
||||
MultiplyOneOverGF128(m_sub_key);
|
||||
|
||||
/* Initialize the cbc-mac impl. */
|
||||
m_cbc_mac_impl.Initialize(cipher);
|
||||
|
||||
/* Mark initialized. */
|
||||
m_state = State_Initialized;
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::Update(const void *data, size_t data_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized);
|
||||
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(data, data_size);
|
||||
}
|
||||
|
||||
template<typename BlockCipher>
|
||||
inline void CmacImpl<BlockCipher>::GetMac(void *dst, size_t dst_size) {
|
||||
AMS_ASSERT(m_state == State_Initialized || m_state == State_Done);
|
||||
AMS_ASSERT(dst_size >= MacSize);
|
||||
AMS_UNUSED(dst_size);
|
||||
|
||||
/* If we're not already finalized, get the final mac. */
|
||||
if (m_state == State_Initialized) {
|
||||
/* Process padding as needed. */
|
||||
if (m_cbc_mac_impl.GetBufferedDataSize() != BlockSize) {
|
||||
/* Determine the remaining size. */
|
||||
const size_t remaining = BlockSize - m_cbc_mac_impl.GetBufferedDataSize();
|
||||
|
||||
/* Update with padding. */
|
||||
static constexpr u8 s_padding[BlockSize] = { 0x80, /* ... */ };
|
||||
m_cbc_mac_impl.template Update<BlockCipher>(s_padding, remaining);
|
||||
|
||||
/* Update our subkey. */
|
||||
MultiplyOneOverGF128(m_sub_key);
|
||||
}
|
||||
|
||||
/* Mask the subkey. */
|
||||
m_cbc_mac_impl.MaskBufferedData(m_sub_key, BlockSize);
|
||||
|
||||
/* Set our state as done. */
|
||||
m_state = State_Done;
|
||||
}
|
||||
|
||||
/* Get the mac. */
|
||||
m_cbc_mac_impl.GetMac(dst, dst_size);
|
||||
}
|
||||
|
||||
}
|
|
@ -49,7 +49,7 @@ namespace ams::kern::init::loader {
|
|||
|
||||
constinit void *g_final_state[2];
|
||||
|
||||
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout) {
|
||||
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout, const uintptr_t &ini_base_address) {
|
||||
/* Adjust layout to be correct. */
|
||||
{
|
||||
const ptrdiff_t layout_offset = reinterpret_cast<uintptr_t>(layout) - base_address;
|
||||
|
@ -74,6 +74,12 @@ namespace ams::kern::init::loader {
|
|||
const uintptr_t diff = GetInteger(correct_base) - base_address;
|
||||
const size_t size = layout->rw_end_offset;
|
||||
|
||||
/* Check that the new kernel doesn't overlap with us. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((GetInteger(correct_base) >= reinterpret_cast<uintptr_t>(__bin_end__)) || (GetInteger(correct_base) + size <= reinterpret_cast<uintptr_t>(__bin_start__)));
|
||||
|
||||
/* Check that the new kernel doesn't overlap with the initial process binary. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((ini_base_address + InitialProcessBinarySizeMax <= GetInteger(correct_base)) || (GetInteger(correct_base) + size <= ini_base_address));
|
||||
|
||||
/* Conversion from KPhysicalAddress to void * is safe here, because MMU is not set up yet. */
|
||||
std::memmove(reinterpret_cast<void *>(GetInteger(correct_base)), reinterpret_cast<void *>(base_address), size);
|
||||
base_address += diff;
|
||||
|
@ -90,11 +96,11 @@ namespace ams::kern::init::loader {
|
|||
constexpr PageTableEntry KernelLdrRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
|
||||
const uintptr_t kernel_ldr_base = util::AlignDown(reinterpret_cast<uintptr_t>(__bin_start__), PageSize);
|
||||
const uintptr_t kernel_ldr_size = util::AlignUp(reinterpret_cast<uintptr_t>(__bin_end__), PageSize) - kernel_ldr_base;
|
||||
init_pt.Map(kernel_ldr_base, kernel_ldr_size, kernel_ldr_base, KernelRWXIdentityAttribute, allocator, 0);
|
||||
init_pt.Map(kernel_ldr_base, kernel_ldr_size, kernel_ldr_base, KernelLdrRWXIdentityAttribute, allocator, 0);
|
||||
|
||||
/* Map in the page table region as RW- for ourselves. */
|
||||
constexpr PageTableEntry PageTableRegionRWAttribute(PageTableEntry::Permission_KernelRW, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable, PageTableEntry::MappingFlag_Mapped);
|
||||
init_pt.Map(page_table_region, page_table_region_size, page_table_region, KernelRWXIdentityAttribute, allocator, 0);
|
||||
init_pt.Map(page_table_region, page_table_region_size, page_table_region, PageTableRegionRWAttribute, allocator, 0);
|
||||
|
||||
/* Place the L1 table addresses in the relevant system registers. */
|
||||
cpu::SetTtbr0El1(init_pt.GetTtbr0L1TableAddress());
|
||||
|
@ -165,7 +171,7 @@ namespace ams::kern::init::loader {
|
|||
uintptr_t Main(uintptr_t base_address, KernelLayout *layout, uintptr_t ini_base_address) {
|
||||
/* Relocate the kernel to the correct physical base address. */
|
||||
/* Base address and layout are passed by reference and modified. */
|
||||
RelocateKernelPhysically(base_address, layout);
|
||||
RelocateKernelPhysically(base_address, layout, ini_base_address);
|
||||
|
||||
/* Validate kernel layout. */
|
||||
const uintptr_t rx_offset = layout->rx_offset;
|
||||
|
@ -229,6 +235,9 @@ namespace ams::kern::init::loader {
|
|||
/* Setup initial identity mapping. TTBR1 table passed by reference. */
|
||||
SetupInitialIdentityMapping(init_pt, base_address, bss_end_offset, resource_end_address, InitialPageTableRegionSizeMax, g_initial_page_allocator, reinterpret_cast<KernelSystemRegisters *>(base_address + sysreg_offset));
|
||||
|
||||
/* NOTE: On 19.0.0+, Nintendo calls an unknown function here on init_pt and g_initial_page_allocator. */
|
||||
/* This is stubbed in prod KernelLdr. */
|
||||
|
||||
/* Generate a random slide for the kernel's base address. */
|
||||
const KVirtualAddress virtual_base_address = GetRandomKernelBaseAddress(init_pt, base_address, bss_end_offset);
|
||||
|
||||
|
|
|
@ -108,6 +108,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->LogToDebugFile("Bit Width: %x\n", opcode->begin_cond.bit_width);
|
||||
this->LogToDebugFile("Mem Type: %x\n", opcode->begin_cond.mem_type);
|
||||
this->LogToDebugFile("Cond Type: %x\n", opcode->begin_cond.cond_type);
|
||||
this->LogToDebugFile("Inc Ofs reg: %d\n", opcode->begin_cond.include_ofs_reg);
|
||||
this->LogToDebugFile("Ofs Reg Idx: %x\n", opcode->begin_cond.ofs_reg_index);
|
||||
this->LogToDebugFile("Rel Addr: %lx\n", opcode->begin_cond.rel_address);
|
||||
this->LogToDebugFile("Value: %lx\n", opcode->begin_cond.value.bit64);
|
||||
break;
|
||||
|
@ -158,6 +160,11 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->LogToDebugFile("Opcode: Begin Keypress Conditional\n");
|
||||
this->LogToDebugFile("Key Mask: %x\n", opcode->begin_keypress_cond.key_mask);
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
this->LogToDebugFile("Opcode: Begin Extended Keypress Conditional\n");
|
||||
this->LogToDebugFile("Key Mask: %x\n", opcode->begin_ext_keypress_cond.key_mask);
|
||||
this->LogToDebugFile("Auto Repeat: %d\n", opcode->begin_ext_keypress_cond.auto_repeat);
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
this->LogToDebugFile("Opcode: Perform Register Arithmetic\n");
|
||||
this->LogToDebugFile("Bit Width: %x\n", opcode->perform_math_reg.bit_width);
|
||||
|
@ -358,6 +365,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
switch (opcode.opcode) {
|
||||
case CheatVmOpcodeType_BeginConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginKeypressConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
case CheatVmOpcodeType_BeginRegisterConditionalBlock:
|
||||
opcode.begin_conditional_block = true;
|
||||
break;
|
||||
|
@ -387,6 +395,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.begin_cond.bit_width = (first_dword >> 24) & 0xF;
|
||||
opcode.begin_cond.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
|
||||
opcode.begin_cond.cond_type = (ConditionalComparisonType)((first_dword >> 16) & 0xF);
|
||||
opcode.begin_cond.include_ofs_reg = ((first_dword >> 12) & 0xF) != 0;
|
||||
opcode.begin_cond.ofs_reg_index = ((first_dword >> 8) & 0xF);
|
||||
opcode.begin_cond.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
|
||||
opcode.begin_cond.value = GetNextVmInt(opcode.begin_cond.bit_width);
|
||||
}
|
||||
|
@ -427,7 +437,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.ldr_memory.bit_width = (first_dword >> 24) & 0xF;
|
||||
opcode.ldr_memory.mem_type = (MemoryAccessType)((first_dword >> 20) & 0xF);
|
||||
opcode.ldr_memory.reg_index = ((first_dword >> 16) & 0xF);
|
||||
opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0;
|
||||
opcode.ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF);
|
||||
opcode.ldr_memory.offset_register = ((first_dword >> 8) & 0xF);
|
||||
opcode.ldr_memory.rel_address = ((u64)(first_dword & 0xFF) << 32ul) | ((u64)second_dword);
|
||||
}
|
||||
break;
|
||||
|
@ -460,6 +471,14 @@ namespace ams::dmnt::cheat::impl {
|
|||
opcode.begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
{
|
||||
/* C4r00000 kkkkkkkk kkkkkkkk */
|
||||
/* Read additional words. */
|
||||
opcode.begin_ext_keypress_cond.key_mask = (u64)GetNextDword() << 32ul | (u64)GetNextDword();
|
||||
opcode.begin_ext_keypress_cond.auto_repeat = ((first_dword >> 20) & 0xF) != 0;
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
{
|
||||
/* 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) */
|
||||
|
@ -734,6 +753,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
return metadata->alias_extents.base + rel_address;
|
||||
case MemoryAccessType_Aslr:
|
||||
return metadata->aslr_extents.base + rel_address;
|
||||
case MemoryAccessType_NonRelative:
|
||||
return rel_address;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -769,6 +790,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
return true;
|
||||
}
|
||||
|
||||
static u64 s_keyold = 0;
|
||||
void CheatVirtualMachine::Execute(const CheatProcessMetadata *metadata) {
|
||||
CheatVmOpcode cur_opcode;
|
||||
u64 kHeld = 0;
|
||||
|
@ -824,7 +846,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
case CheatVmOpcodeType_BeginConditionalBlock:
|
||||
{
|
||||
/* Read value from memory. */
|
||||
u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, cur_opcode.begin_cond.rel_address);
|
||||
u64 src_address = GetCheatProcessAddress(metadata, cur_opcode.begin_cond.mem_type, (cur_opcode.begin_cond.include_ofs_reg) ? m_registers[cur_opcode.begin_cond.ofs_reg_index] + cur_opcode.begin_cond.rel_address : cur_opcode.begin_cond.rel_address);
|
||||
u64 src_value = 0;
|
||||
switch (cur_opcode.store_static.bit_width) {
|
||||
case 1:
|
||||
|
@ -896,8 +918,12 @@ namespace ams::dmnt::cheat::impl {
|
|||
{
|
||||
/* Choose source address. */
|
||||
u64 src_address;
|
||||
if (cur_opcode.ldr_memory.load_from_reg) {
|
||||
if (cur_opcode.ldr_memory.load_from_reg == 1) {
|
||||
src_address = m_registers[cur_opcode.ldr_memory.reg_index] + cur_opcode.ldr_memory.rel_address;
|
||||
} else if (cur_opcode.ldr_memory.load_from_reg == 2) {
|
||||
src_address = m_registers[cur_opcode.ldr_memory.offset_register] + cur_opcode.ldr_memory.rel_address;
|
||||
} else if (cur_opcode.ldr_memory.load_from_reg == 3) {
|
||||
src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, m_registers[cur_opcode.ldr_memory.offset_register] + cur_opcode.ldr_memory.rel_address);
|
||||
} else {
|
||||
src_address = GetCheatProcessAddress(metadata, cur_opcode.ldr_memory.mem_type, cur_opcode.ldr_memory.rel_address);
|
||||
}
|
||||
|
@ -982,6 +1008,18 @@ namespace ams::dmnt::cheat::impl {
|
|||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock:
|
||||
/* Check for keypress. */
|
||||
if (!cur_opcode.begin_ext_keypress_cond.auto_repeat) {
|
||||
if ((cur_opcode.begin_ext_keypress_cond.key_mask & kHeld) != (cur_opcode.begin_ext_keypress_cond.key_mask) || (cur_opcode.begin_ext_keypress_cond.key_mask & s_keyold) == (cur_opcode.begin_ext_keypress_cond.key_mask)) {
|
||||
/* Keys not pressed. Skip conditional block. */
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
} else if ((cur_opcode.begin_ext_keypress_cond.key_mask & kHeld) != cur_opcode.begin_ext_keypress_cond.key_mask) {
|
||||
/* Keys not pressed. Skip conditional block. */
|
||||
this->SkipConditionalBlock(true);
|
||||
}
|
||||
break;
|
||||
case CheatVmOpcodeType_PerformArithmeticRegister:
|
||||
{
|
||||
const u64 operand_1_value = m_registers[cur_opcode.perform_math_reg.src_reg_1_index];
|
||||
|
@ -1022,6 +1060,34 @@ namespace ams::dmnt::cheat::impl {
|
|||
case RegisterArithmeticType_None:
|
||||
res_val = operand_1_value;
|
||||
break;
|
||||
case RegisterArithmeticType_FloatAddition:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) + std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) + std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatSubtraction:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) - std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) - std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatMultiplication:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) * std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) * std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
case RegisterArithmeticType_FloatDivision:
|
||||
if (cur_opcode.perform_math_reg.bit_width == 4) {
|
||||
res_val = std::bit_cast<std::uint32_t>(std::bit_cast<float>(static_cast<uint32_t>(operand_1_value)) / std::bit_cast<float>(static_cast<uint32_t>(operand_2_value)));
|
||||
} else if (cur_opcode.perform_math_reg.bit_width == 8) {
|
||||
res_val = std::bit_cast<std::uint64_t>(std::bit_cast<double>(operand_1_value) / std::bit_cast<double>(operand_2_value));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1304,6 +1370,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
break;
|
||||
}
|
||||
}
|
||||
s_keyold = kHeld;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
CheatVmOpcodeType_SaveRestoreRegister = 0xC1,
|
||||
CheatVmOpcodeType_SaveRestoreRegisterMask = 0xC2,
|
||||
CheatVmOpcodeType_ReadWriteStaticRegister = 0xC3,
|
||||
CheatVmOpcodeType_BeginExtendedKeypressConditionalBlock = 0xC4,
|
||||
|
||||
/* This is a meta entry, and not a real opcode. */
|
||||
/* This is to facilitate multi-nybble instruction decoding. */
|
||||
|
@ -59,6 +60,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
MemoryAccessType_Heap = 1,
|
||||
MemoryAccessType_Alias = 2,
|
||||
MemoryAccessType_Aslr = 3,
|
||||
MemoryAccessType_NonRelative = 4,
|
||||
};
|
||||
|
||||
enum ConditionalComparisonType : u32 {
|
||||
|
@ -84,6 +86,10 @@ namespace ams::dmnt::cheat::impl {
|
|||
RegisterArithmeticType_LogicalXor = 8,
|
||||
|
||||
RegisterArithmeticType_None = 9,
|
||||
RegisterArithmeticType_FloatAddition = 10,
|
||||
RegisterArithmeticType_FloatSubtraction = 11,
|
||||
RegisterArithmeticType_FloatMultiplication = 12,
|
||||
RegisterArithmeticType_FloatDivision = 13,
|
||||
};
|
||||
|
||||
enum StoreRegisterOffsetType : u32 {
|
||||
|
@ -138,6 +144,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 bit_width;
|
||||
MemoryAccessType mem_type;
|
||||
ConditionalComparisonType cond_type;
|
||||
bool include_ofs_reg;
|
||||
u32 ofs_reg_index;
|
||||
u64 rel_address;
|
||||
VmInt value;
|
||||
};
|
||||
|
@ -161,7 +169,8 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 bit_width;
|
||||
MemoryAccessType mem_type;
|
||||
u32 reg_index;
|
||||
bool load_from_reg;
|
||||
u8 load_from_reg;
|
||||
u8 offset_register;
|
||||
u64 rel_address;
|
||||
};
|
||||
|
||||
|
@ -185,6 +194,11 @@ namespace ams::dmnt::cheat::impl {
|
|||
u32 key_mask;
|
||||
};
|
||||
|
||||
struct BeginExtendedKeypressConditionalOpcode {
|
||||
u64 key_mask;
|
||||
bool auto_repeat;
|
||||
};
|
||||
|
||||
struct PerformArithmeticRegisterOpcode {
|
||||
u32 bit_width;
|
||||
RegisterArithmeticType math_type;
|
||||
|
@ -259,6 +273,7 @@ namespace ams::dmnt::cheat::impl {
|
|||
StoreStaticToAddressOpcode str_static;
|
||||
PerformArithmeticStaticOpcode perform_math_static;
|
||||
BeginKeypressConditionalOpcode begin_keypress_cond;
|
||||
BeginExtendedKeypressConditionalOpcode begin_ext_keypress_cond;
|
||||
PerformArithmeticRegisterOpcode perform_math_reg;
|
||||
StoreRegisterToAddressOpcode str_register;
|
||||
BeginRegisterConditionalOpcode begin_reg_cond;
|
||||
|
|
|
@ -25,11 +25,11 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* ScopedCodeMount functionality. */
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, PlatformId platform) : m_lk(g_scoped_code_mount_lock), m_has_status(false), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform) : m_lk(g_scoped_code_mount_lock), m_has_status(false), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
m_result = this->Initialize(loc, platform);
|
||||
}
|
||||
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o, PlatformId platform) : m_lk(g_scoped_code_mount_lock), m_override_status(o), m_has_status(true), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
ScopedCodeMount::ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &o, ncm::ContentMetaPlatform platform) : m_lk(g_scoped_code_mount_lock), m_override_status(o), m_has_status(true), m_mounted_ams(false), m_mounted_sd_or_code(false), m_mounted_code(false) {
|
||||
m_result = this->Initialize(loc, platform);
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace ams::ldr {
|
|||
}
|
||||
}
|
||||
|
||||
Result ScopedCodeMount::Initialize(const ncm::ProgramLocation &loc, PlatformId platform) {
|
||||
Result ScopedCodeMount::Initialize(const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform) {
|
||||
/* Capture override status, if necessary. */
|
||||
this->EnsureOverrideStatus(loc);
|
||||
AMS_ABORT_UNLESS(m_has_status);
|
||||
|
@ -83,7 +83,7 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Redirection API. */
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, PlatformId platform) {
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform) {
|
||||
/* Check for storage id none. */
|
||||
if (static_cast<ncm::StorageId>(loc.storage_id) == ncm::StorageId::None) {
|
||||
std::memset(out_path, 0, out_size);
|
||||
|
@ -166,9 +166,9 @@ namespace ams::ldr {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
fs::ContentAttributes GetPlatformContentAttributes(PlatformId platform) {
|
||||
fs::ContentAttributes GetPlatformContentAttributes(ncm::ContentMetaPlatform platform) {
|
||||
switch (platform) {
|
||||
case PlatformId_Nx:
|
||||
case ncm::ContentMetaPlatform::Nx:
|
||||
return fs::ContentAttributes_None;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ namespace ams::ldr {
|
|||
bool m_mounted_sd_or_code;
|
||||
bool m_mounted_code;
|
||||
public:
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc, PlatformId platform);
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, PlatformId platform);
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform);
|
||||
ScopedCodeMount(const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, ncm::ContentMetaPlatform platform);
|
||||
~ScopedCodeMount();
|
||||
|
||||
Result GetResult() const {
|
||||
|
@ -59,7 +59,7 @@ namespace ams::ldr {
|
|||
return m_base_code_verification_data;
|
||||
}
|
||||
private:
|
||||
Result Initialize(const ncm::ProgramLocation &loc, PlatformId platform);
|
||||
Result Initialize(const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform);
|
||||
void EnsureOverrideStatus(const ncm::ProgramLocation &loc);
|
||||
};
|
||||
|
||||
|
@ -76,10 +76,10 @@ namespace ams::ldr {
|
|||
#define ENCODE_CMPT_PATH(relative) "cmpt:" relative
|
||||
|
||||
/* Redirection API. */
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, PlatformId platform);
|
||||
Result GetProgramPath(char *out_path, size_t out_size, const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform);
|
||||
Result RedirectProgramPath(const char *path, size_t size, const ncm::ProgramLocation &loc);
|
||||
Result RedirectHtmlDocumentPathForHbl(const ncm::ProgramLocation &loc);
|
||||
|
||||
fs::ContentAttributes GetPlatformContentAttributes(PlatformId platform);
|
||||
fs::ContentAttributes GetPlatformContentAttributes(ncm::ContentMetaPlatform platform);
|
||||
|
||||
}
|
||||
|
|
|
@ -27,11 +27,11 @@ namespace ams::ldr {
|
|||
|
||||
constinit ArgumentStore g_argument_store;
|
||||
|
||||
bool IsValidPlatform(PlatformId platform) {
|
||||
return platform == PlatformId_Nx;
|
||||
bool IsValidPlatform(ncm::ContentMetaPlatform platform) {
|
||||
return platform == ncm::ContentMetaPlatform::Nx;
|
||||
}
|
||||
|
||||
Result CreateProcessByPlatform(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit, PlatformId platform) {
|
||||
Result CreateProcessByPlatform(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit, ncm::ContentMetaPlatform platform) {
|
||||
/* Check that the platform is valid. */
|
||||
R_UNLESS(IsValidPlatform(platform), ldr::ResultInvalidPlatformId());
|
||||
|
||||
|
@ -49,7 +49,7 @@ namespace ams::ldr {
|
|||
R_RETURN(ldr::CreateProcess(out, pin_id, loc, override_status, path, g_argument_store.Get(loc.program_id), flags, resource_limit, platform));
|
||||
}
|
||||
|
||||
Result GetProgramInfoByPlatform(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, PlatformId platform) {
|
||||
Result GetProgramInfoByPlatform(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, ncm::ContentMetaPlatform platform) {
|
||||
/* Check that the platform is valid. */
|
||||
R_UNLESS(IsValidPlatform(platform), ldr::ResultInvalidPlatformId());
|
||||
|
||||
|
@ -88,11 +88,11 @@ namespace ams::ldr {
|
|||
|
||||
|
||||
Result LoaderService::CreateProcess(os::NativeHandle *out, PinId pin_id, u32 flags, os::NativeHandle resource_limit) {
|
||||
R_RETURN(CreateProcessByPlatform(out, pin_id, flags, resource_limit, PlatformId_Nx));
|
||||
R_RETURN(CreateProcessByPlatform(out, pin_id, flags, resource_limit, ncm::ContentMetaPlatform::Nx));
|
||||
}
|
||||
|
||||
Result LoaderService::GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc) {
|
||||
R_RETURN(GetProgramInfoByPlatform(out, out_status, loc, PlatformId_Nx));
|
||||
R_RETURN(GetProgramInfoByPlatform(out, out_status, loc, ncm::ContentMetaPlatform::Nx));
|
||||
}
|
||||
|
||||
Result LoaderService::PinProgram(PinId *out, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status) {
|
||||
|
|
|
@ -103,15 +103,15 @@ namespace ams::ldr {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
const u8 *GetAcidSignatureModulus(PlatformId platform, u8 key_generation, bool unk_unused) {
|
||||
const u8 *GetAcidSignatureModulus(ncm::ContentMetaPlatform platform, u8 key_generation, bool unk_unused) {
|
||||
return fssystem::GetAcidSignatureKeyModulus(platform, !IsDevelopmentForAcidSignatureCheck(), key_generation, unk_unused);
|
||||
}
|
||||
|
||||
size_t GetAcidSignatureModulusSize(PlatformId platform, bool unk_unused) {
|
||||
size_t GetAcidSignatureModulusSize(ncm::ContentMetaPlatform platform, bool unk_unused) {
|
||||
return fssystem::GetAcidSignatureKeyModulusSize(platform, unk_unused);
|
||||
}
|
||||
|
||||
Result ValidateAcidSignature(Meta *meta, PlatformId platform, bool unk_unused) {
|
||||
Result ValidateAcidSignature(Meta *meta, ncm::ContentMetaPlatform platform, bool unk_unused) {
|
||||
/* Loader did not check signatures prior to 10.0.0. */
|
||||
if (hos::GetVersion() < hos::Version_10_0_0) {
|
||||
meta->check_verification_data = false;
|
||||
|
@ -190,7 +190,7 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* API. */
|
||||
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform, bool unk_unused) {
|
||||
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused) {
|
||||
/* Set the cached program id back to zero. */
|
||||
g_cached_program_id = {};
|
||||
|
||||
|
@ -282,7 +282,7 @@ namespace ams::ldr {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform) {
|
||||
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform) {
|
||||
if (g_cached_program_id != loc.program_id || g_cached_override_status != status) {
|
||||
R_RETURN(LoadMeta(out_meta, loc, status, platform, false));
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ namespace ams::ldr {
|
|||
};
|
||||
|
||||
/* Meta API. */
|
||||
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform, bool unk_unused);
|
||||
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, PlatformId platform);
|
||||
Result LoadMeta(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform, bool unk_unused);
|
||||
Result LoadMetaFromCache(Meta *out_meta, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &status, ncm::ContentMetaPlatform platform);
|
||||
void InvalidateMetaCache();
|
||||
|
||||
}
|
||||
|
|
|
@ -664,7 +664,7 @@ namespace ams::ldr {
|
|||
}
|
||||
|
||||
/* Process Creation API. */
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit, PlatformId platform) {
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit, ncm::ContentMetaPlatform platform) {
|
||||
/* Mount code. */
|
||||
AMS_UNUSED(path);
|
||||
ScopedCodeMount mount(loc, override_status, platform);
|
||||
|
@ -720,7 +720,7 @@ namespace ams::ldr {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, PlatformId platform) {
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, ncm::ContentMetaPlatform platform) {
|
||||
Meta meta;
|
||||
|
||||
/* Load Meta. */
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
namespace ams::ldr {
|
||||
|
||||
/* Process Creation API. */
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit, PlatformId platform);
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, PlatformId platform);
|
||||
Result CreateProcess(os::NativeHandle *out, PinId pin_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status, const char *path, const ArgumentStore::Entry *argument, u32 flags, os::NativeHandle resource_limit, ncm::ContentMetaPlatform platform);
|
||||
Result GetProgramInfo(ProgramInfo *out, cfg::OverrideStatus *out_status, const ncm::ProgramLocation &loc, const char *path, ncm::ContentMetaPlatform platform);
|
||||
|
||||
Result PinProgram(PinId *out_id, const ncm::ProgramLocation &loc, const cfg::OverrideStatus &override_status);
|
||||
Result UnpinProgram(PinId id);
|
||||
|
|
Loading…
Add table
Reference in a new issue