Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa0df994ba | ||
|
|
909a1767a6 | ||
|
|
dbe59fd041 | ||
|
|
9b65daf439 | ||
|
|
4acdc899f5 | ||
|
|
76957e502d | ||
|
|
909397233c | ||
|
|
211a828730 | ||
|
|
28ceedb533 | ||
|
|
f551ca4461 | ||
|
|
2cf5c65bc5 | ||
|
|
47d0d5c6ab | ||
|
|
fd0e3e2160 | ||
|
|
074364753f | ||
|
|
b7d99b732a | ||
|
|
1cccb6efc4 |
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,27 @@
|
||||
# Changelog
|
||||
## 0.14.4
|
||||
+ Several bugs were fixed involving the official jit sysmodule added in 10.0.0.
|
||||
+ A Process handle leak was fixed when JitPlugin NRRs were registered with the `ro` sysmodule.
|
||||
+ This prevented processes using jit from being able to exit, causing a full system freeze.
|
||||
+ The `sm` atmosphere extension to not unregister services when the server's connection is closed was special-case disabled for `jit:u`.
|
||||
+ This extension is normally desirable in order to allow more concurrent processes to exist (as only 0x40 sm connections may ever be concurrently open), but official jit sysmodule relies on the behavior.
|
||||
+ This would cause crashes on attempts to launch a program using jit services more than once per reboot.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.14.3
|
||||
+ Support was added for 10.2.0.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.14.2
|
||||
+ A bug was fixed that could cause a deadlock when installing mitm services.
|
||||
+ Fixing this required a breaking change to the client behavior when installing a mitm service, and so custom sysmodules which use mitm will need to be re-compiled to function properly.
|
||||
+ A bug was fixed that caused atmosphere sysmodules to respond incorrectly when receiving invalid messages.
|
||||
+ A bug was fixed that caused fatal auto-reboot timing to work improperly.
|
||||
+ Support was added to fusee for loading binaries for `mesosphere`, atmosphère's reimplementation of the Nintendo Switch kernel.
|
||||
+ 0.14.2 does not include mesosphere, but those who are especially interested can build and test mesosphere themselves.
|
||||
+ In the future, to enable a sufficient testing period Atmosphère releases will distribute two zips for some time.
|
||||
+ One zip will use mesosphere, and the other will not.
|
||||
+ This will allow users who are interested to opt-in to mesosphere usage before it has been tested to be stable.
|
||||
+ When mesosphere is stable and well-tested, it will be enabled by default and Atmosphère's version will transition to 1.0.0.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.14.1
|
||||
+ An issue was fixed in 0.14.0 that would cause a black screen on boot when the INI1's size was not aligned to 8 bytes.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/m4xw/emuMMC
|
||||
branch = exo2
|
||||
commit = 06ab9b895c4264ecc14d3bf9be1260e2096f6037
|
||||
parent = dccd41f6d25498c191a157123a27724203d3bc37
|
||||
commit = 6a814ebbe72cf5245b863b9edea9cd3801437a12
|
||||
parent = f551ca4461a79908c37307db10cd8cacf8b98f17
|
||||
method = rebase
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "offsets/910_exfat.h"
|
||||
#include "offsets/1000.h"
|
||||
#include "offsets/1000_exfat.h"
|
||||
#include "offsets/1020.h"
|
||||
#include "offsets/1020_exfat.h"
|
||||
#include "../utils/fatal.h"
|
||||
|
||||
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
|
||||
@@ -104,6 +106,8 @@ DEFINE_OFFSET_STRUCT(_910);
|
||||
DEFINE_OFFSET_STRUCT(_910_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1000);
|
||||
DEFINE_OFFSET_STRUCT(_1000_EXFAT);
|
||||
DEFINE_OFFSET_STRUCT(_1020);
|
||||
DEFINE_OFFSET_STRUCT(_1020_EXFAT);
|
||||
|
||||
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
switch (version) {
|
||||
@@ -169,6 +173,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1000));
|
||||
case FS_VER_10_0_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1000_EXFAT));
|
||||
case FS_VER_10_2_0:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1020));
|
||||
case FS_VER_10_2_0_EXFAT:
|
||||
return &(GET_OFFSET_STRUCT_NAME(_1020_EXFAT));
|
||||
default:
|
||||
fatal_abort(Fatal_UnknownVersion);
|
||||
}
|
||||
|
||||
@@ -68,6 +68,9 @@ enum FS_VER
|
||||
FS_VER_10_0_0,
|
||||
FS_VER_10_0_0_EXFAT,
|
||||
|
||||
FS_VER_10_2_0,
|
||||
FS_VER_10_2_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
};
|
||||
|
||||
|
||||
58
emummc/source/FS/offsets/1020.h
Normal file
58
emummc/source/FS/offsets/1020.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1020_H__
|
||||
#define __FS_1020_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1020_SDMMC_ACCESSOR_GC 0x14E0F0
|
||||
#define FS_OFFSET_1020_SDMMC_ACCESSOR_SD 0x14C200
|
||||
#define FS_OFFSET_1020_SDMMC_ACCESSOR_NAND 0x147080
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1020_SDMMC_WRAPPER_READ 0x1427E0
|
||||
#define FS_OFFSET_1020_SDMMC_WRAPPER_WRITE 0x1428C0
|
||||
#define FS_OFFSET_1020_RTLD 0x634
|
||||
#define FS_OFFSET_1020_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_1020_CLKRST_SET_MIN_V_CLK_RATE 0x141A00
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1020_LOCK_MUTEX 0x28910
|
||||
#define FS_OFFSET_1020_UNLOCK_MUTEX 0x28960
|
||||
|
||||
#define FS_OFFSET_1020_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x142740
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1020_SD_MUTEX 0xE273E8
|
||||
#define FS_OFFSET_1020_NAND_MUTEX 0xE22DA0
|
||||
#define FS_OFFSET_1020_ACTIVE_PARTITION 0xE22DE0
|
||||
#define FS_OFFSET_1020_SDMMC_DAS_HANDLE 0xE0AB90
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1020_SD_DAS_INIT 0x15214C
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1020_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1020_H__
|
||||
58
emummc/source/FS/offsets/1020_exfat.h
Normal file
58
emummc/source/FS/offsets/1020_exfat.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2019 m4xw <m4x@m4xw.net>
|
||||
* Copyright (c) 2019 Atmosphere-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef __FS_1020_EXFAT_H__
|
||||
#define __FS_1020_EXFAT_H__
|
||||
|
||||
// Accessor vtable getters
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_GC 0x14E0F0
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_SD 0x14C200
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_ACCESSOR_NAND 0x147080
|
||||
|
||||
// Hooks
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_READ 0x1427E0
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_WRITE 0x1428C0
|
||||
#define FS_OFFSET_1020_EXFAT_RTLD 0x634
|
||||
#define FS_OFFSET_1020_EXFAT_RTLD_DESTINATION 0x9C
|
||||
|
||||
#define FS_OFFSET_1020_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x141A00
|
||||
|
||||
// Misc funcs
|
||||
#define FS_OFFSET_1020_EXFAT_LOCK_MUTEX 0x28910
|
||||
#define FS_OFFSET_1020_EXFAT_UNLOCK_MUTEX 0x28960
|
||||
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_WRAPPER_CONTROLLER_CLOSE 0x142740
|
||||
|
||||
// Misc Data
|
||||
#define FS_OFFSET_1020_EXFAT_SD_MUTEX 0xE353E8
|
||||
#define FS_OFFSET_1020_EXFAT_NAND_MUTEX 0xE30DA0
|
||||
#define FS_OFFSET_1020_EXFAT_ACTIVE_PARTITION 0xE30DE0
|
||||
#define FS_OFFSET_1020_EXFAT_SDMMC_DAS_HANDLE 0xE18B90
|
||||
|
||||
// NOPs
|
||||
#define FS_OFFSET_1020_EXFAT_SD_DAS_INIT 0x15214C
|
||||
|
||||
// Nintendo Paths
|
||||
#define FS_OFFSET_1020_EXFAT_NINTENDO_PATHS \
|
||||
{ \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0006BBA4, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x00078520, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 3, .adrp_offset = 0x0007ED0C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 4, .adrp_offset = 0x0009115C, .add_rel_offset = 0x00000004}, \
|
||||
{.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0}, \
|
||||
}
|
||||
|
||||
#endif // __FS_1020_EXFAT_H__
|
||||
@@ -42,6 +42,8 @@ static const char *get_error_desc_str(uint32_t error_desc) {
|
||||
return "SError";
|
||||
case 0x301:
|
||||
return "Bad SVC";
|
||||
case 0xF00:
|
||||
return "Kernel Panic";
|
||||
case 0xFFD:
|
||||
return "Stack overflow";
|
||||
case 0xFFE:
|
||||
|
||||
@@ -85,6 +85,9 @@ typedef enum {
|
||||
FS_VER_10_0_0,
|
||||
FS_VER_10_0_0_EXFAT,
|
||||
|
||||
FS_VER_10_2_0,
|
||||
FS_VER_10_2_0_EXFAT,
|
||||
|
||||
FS_VER_MAX,
|
||||
} emummc_fs_ver_t;
|
||||
|
||||
|
||||
@@ -420,6 +420,9 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
|
||||
|
||||
"\x3E\xEB\xD9\xB7\xBC\xD1\xB5\xE0", /* FS_VER_10_0_0 */
|
||||
"\x81\x7E\xA2\xB0\xB7\x02\xC1\xF3", /* FS_VER_10_0_0_EXFAT */
|
||||
|
||||
"\xA9\x52\xB6\x57\xAD\xF9\xC2\xBA", /* FS_VER_10_2_0 */
|
||||
"\x16\x0D\x3E\x10\x4E\xAD\x61\x76", /* FS_VER_10_2_0_EXFAT */
|
||||
};
|
||||
|
||||
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
|
||||
|
||||
@@ -236,6 +236,7 @@ static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
|
||||
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
|
||||
|
||||
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
|
||||
CHECK_NCA("26325de4db3909e0ef2379787c7e671d", 10_2_0);
|
||||
CHECK_NCA("5077973537f6735b564dd7475b779f87", 10_1_1); /* Exclusive to China. */
|
||||
CHECK_NCA("fd1faed0ca750700d254c0915b93d506", 10_1_0);
|
||||
CHECK_NCA("34728c771299443420820d8ae490ea41", 10_0_4);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
[subrepo]
|
||||
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
commit = 2d522dc6a12b2eb5eb3f103a8c5b5126ca301b1a
|
||||
parent = 35fffade4ea4fdbba9cf2443c321e724c9e70c3d
|
||||
commit = f6dac1e67793233cc916f317cf517244dd348a5e
|
||||
parent = 909a1767a6080bab7ea6032c00e1ff4cec993af0
|
||||
method = merge
|
||||
cmdver = 0.4.1
|
||||
|
||||
@@ -63,7 +63,7 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
/* Power management. */
|
||||
static void SleepSystem();
|
||||
static NORETURN void StopSystem();
|
||||
static NORETURN void StopSystem(void *arg = nullptr);
|
||||
|
||||
/* User access. */
|
||||
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
|
||||
#if defined(AMS_BUILD_FOR_AUDITING)
|
||||
#define MESOSPHERE_BUILD_FOR_AUDITING
|
||||
#endif
|
||||
|
||||
@@ -28,4 +28,5 @@
|
||||
#define MESOSPHERE_ENABLE_DEBUG_PRINT
|
||||
#endif
|
||||
|
||||
#define MESOSPHERE_BUILD_FOR_TRACING
|
||||
//#define MESOSPHERE_BUILD_FOR_TRACING
|
||||
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace ams::kern {
|
||||
#ifndef MESOSPHERE_DEBUG_LOG_SELECTED
|
||||
|
||||
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
|
||||
#define MESOSPHERE_DEBUG_LOG_USE_UART_C
|
||||
#define MESOSPHERE_DEBUG_LOG_USE_UART_A
|
||||
#else
|
||||
#error "Unknown board for Default Debug Log Source"
|
||||
#endif
|
||||
|
||||
88
libraries/libmesosphere/source/arch/arm64/kern_panic_asm.s
Normal file
88
libraries/libmesosphere/source/arch/arm64/kern_panic_asm.s
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 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 <mesosphere/kern_build_config.hpp>
|
||||
|
||||
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
|
||||
|
||||
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT \
|
||||
/* Save x0/x1 to stack. */ \
|
||||
stp x0, x1, [sp, #-16]!; \
|
||||
\
|
||||
/* Get the exception context for the core. */ \
|
||||
adr x0, _ZN3ams4kern26g_panic_exception_contextsE; \
|
||||
mrs x1, mpidr_el1; \
|
||||
and x1, x1, #0xFF; \
|
||||
lsl x1, x1, #0x8; \
|
||||
add x0, x0, x1; \
|
||||
lsr x1, x1, #0x3; \
|
||||
add x0, x0, x1; \
|
||||
\
|
||||
/* Save x0/x1/sp to the context. */ \
|
||||
ldr x1, [sp, #(8 * 0)]; \
|
||||
str x1, [x0, #(8 * 0)]; \
|
||||
ldr x1, [sp, #(8 * 1)]; \
|
||||
str x1, [x0, #(8 * 1)]; \
|
||||
\
|
||||
/* Save all other registers to the context. */ \
|
||||
stp x2, x3, [x0, #(8 * 2)]; \
|
||||
stp x4, x5, [x0, #(8 * 4)]; \
|
||||
stp x6, x7, [x0, #(8 * 6)]; \
|
||||
stp x8, x9, [x0, #(8 * 8)]; \
|
||||
stp x10, x11, [x0, #(8 * 10)]; \
|
||||
stp x12, x13, [x0, #(8 * 12)]; \
|
||||
stp x14, x15, [x0, #(8 * 14)]; \
|
||||
stp x16, x17, [x0, #(8 * 16)]; \
|
||||
stp x18, x19, [x0, #(8 * 18)]; \
|
||||
stp x20, x21, [x0, #(8 * 20)]; \
|
||||
stp x22, x23, [x0, #(8 * 22)]; \
|
||||
stp x24, x25, [x0, #(8 * 24)]; \
|
||||
stp x26, x27, [x0, #(8 * 26)]; \
|
||||
stp x28, x29, [x0, #(8 * 28)]; \
|
||||
\
|
||||
add x1, sp, #16; \
|
||||
stp x30, x1, [x0, #(8 * 30)]; \
|
||||
\
|
||||
/* Restore x0/x1. */ \
|
||||
ldp x0, x1, [sp], #16;
|
||||
|
||||
#else
|
||||
|
||||
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
|
||||
|
||||
#endif
|
||||
|
||||
/* ams::kern::Panic(const char *file, int line, const char *format, ...) */
|
||||
.section .text._ZN3ams4kern5PanicEPKciS2_z, "ax", %progbits
|
||||
.global _ZN3ams4kern5PanicEPKciS2_z
|
||||
.type _ZN3ams4kern5PanicEPKciS2_z, %function
|
||||
_ZN3ams4kern5PanicEPKciS2_z:
|
||||
/* Generate the exception context. */
|
||||
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
|
||||
|
||||
/* Jump to the architecturally-common implementation function. */
|
||||
b _ZN3ams4kern9PanicImplEPKciS2_z
|
||||
|
||||
|
||||
/* ams::kern::Panic() */
|
||||
.section .text._ZN3ams4kern5PanicEv, "ax", %progbits
|
||||
.global _ZN3ams4kern5PanicEv
|
||||
.type _ZN3ams4kern5PanicEv, %function
|
||||
_ZN3ams4kern5PanicEv:
|
||||
/* Generate the exception context. */
|
||||
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
|
||||
|
||||
/* Jump to the architecturally-common implementation function. */
|
||||
b _ZN3ams4kern9PanicImplEv
|
||||
@@ -532,13 +532,63 @@ namespace ams::kern::board::nintendo::nx {
|
||||
KSleepManager::SleepSystem();
|
||||
}
|
||||
|
||||
void KSystemControl::StopSystem() {
|
||||
void KSystemControl::StopSystem(void *arg) {
|
||||
if (arg != nullptr) {
|
||||
/* NOTE: Atmosphere extension; if we received an exception context from Panic(), */
|
||||
/* generate a fatal error report using it. */
|
||||
const KExceptionContext *e_ctx = static_cast<const KExceptionContext *>(arg);
|
||||
auto *f_ctx = GetPointer<::ams::impl::FatalErrorContext>(KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x3E000);
|
||||
|
||||
/* Clear the fatal context. */
|
||||
std::memset(f_ctx, 0xCC, sizeof(*f_ctx));
|
||||
|
||||
/* Set metadata. */
|
||||
f_ctx->magic = ::ams::impl::FatalErrorContext::Magic;
|
||||
f_ctx->error_desc = ::ams::impl::FatalErrorContext::KernelPanicDesc;
|
||||
f_ctx->program_id = (static_cast<u64>(util::FourCC<'M', 'E', 'S', 'O'>::Code) << 0) | (static_cast<u64>(util::FourCC<'S', 'P', 'H', 'R'>::Code) << 32);
|
||||
|
||||
/* Set identifier. */
|
||||
f_ctx->report_identifier = KHardwareTimer::GetTick();
|
||||
|
||||
/* Set module base. */
|
||||
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
|
||||
|
||||
/* Copy registers. */
|
||||
for (size_t i = 0; i < util::size(e_ctx->x); ++i) {
|
||||
f_ctx->gprs[i] = e_ctx->x[i];
|
||||
}
|
||||
f_ctx->sp = e_ctx->sp;
|
||||
|
||||
/* Dump stack trace. */
|
||||
{
|
||||
uintptr_t fp = e_ctx->x[29];
|
||||
for (f_ctx->stack_trace_size = 0; f_ctx->stack_trace_size < ::ams::impl::FatalErrorContext::MaxStackTrace && fp != 0 && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); ++(f_ctx->stack_trace_size)) {
|
||||
struct {
|
||||
uintptr_t fp;
|
||||
uintptr_t lr;
|
||||
} *stack_frame = reinterpret_cast<decltype(stack_frame)>(fp);
|
||||
|
||||
f_ctx->stack_trace[f_ctx->stack_trace_size] = stack_frame->lr;
|
||||
fp = stack_frame->fp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump stack. */
|
||||
{
|
||||
uintptr_t sp = e_ctx->sp;
|
||||
for (f_ctx->stack_dump_size = 0; f_ctx->stack_dump_size < ::ams::impl::FatalErrorContext::MaxStackDumpSize && cpu::GetPhysicalAddressWritable(nullptr, sp + f_ctx->stack_dump_size, true); f_ctx->stack_dump_size += sizeof(u64)) {
|
||||
*reinterpret_cast<u64 *>(f_ctx->stack_dump + f_ctx->stack_dump_size) = *reinterpret_cast<u64 *>(sp + f_ctx->stack_dump_size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Trigger a reboot to rcm. */
|
||||
smc::init::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToRcm);
|
||||
}
|
||||
|
||||
if (g_call_smc_on_panic) {
|
||||
/* Display a panic screen via secure monitor. */
|
||||
/* If we should, instruct the secure monitor to display a panic screen. */
|
||||
smc::Panic(0xF00);
|
||||
}
|
||||
u32 dummy;
|
||||
smc::init::ReadWriteRegister(std::addressof(dummy), 0x7000E400, 0x10, 0x10);
|
||||
AMS_INFINITE_LOOP();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
u64 x[8];
|
||||
};
|
||||
|
||||
enum UserFunctionId : u32 {
|
||||
UserFunctionId_SetConfig = 0xC3000401,
|
||||
};
|
||||
|
||||
enum FunctionId : u32 {
|
||||
FunctionId_CpuSuspend = 0xC4000001,
|
||||
FunctionId_CpuOff = 0x84000002,
|
||||
@@ -136,6 +140,35 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
void CallUserSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
register u64 x1 asm("x1") = args.x[1];
|
||||
register u64 x2 asm("x2") = args.x[2];
|
||||
register u64 x3 asm("x3") = args.x[3];
|
||||
register u64 x4 asm("x4") = args.x[4];
|
||||
register u64 x5 asm("x5") = args.x[5];
|
||||
register u64 x6 asm("x6") = args.x[6];
|
||||
register u64 x7 asm("x7") = args.x[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
__asm__ __volatile__("smc #0"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Store arguments to output. */
|
||||
args.x[0] = x0;
|
||||
args.x[1] = x1;
|
||||
args.x[2] = x2;
|
||||
args.x[3] = x3;
|
||||
args.x[4] = x4;
|
||||
args.x[5] = x5;
|
||||
args.x[6] = x6;
|
||||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
/* Global lock for generate random bytes. */
|
||||
KSpinLock g_generate_random_lock;
|
||||
|
||||
@@ -177,6 +210,12 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
bool SetConfig(ConfigItem config_item, u64 value) {
|
||||
SecureMonitorArguments args = { UserFunctionId_SetConfig, static_cast<u32>(config_item), 0, value };
|
||||
CallUserSecureMonitorFunctionForInit(args);
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||
|
||||
@@ -83,6 +83,12 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, smc::MemorySize>;
|
||||
};
|
||||
|
||||
enum UserRebootType {
|
||||
UserRebootType_None = 0,
|
||||
UserRebootType_ToRcm = 1,
|
||||
UserRebootType_ToPayload = 2,
|
||||
};
|
||||
|
||||
/* TODO: Rest of Secure Monitor API. */
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||
@@ -102,6 +108,8 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||
|
||||
bool SetConfig(ConfigItem config_item, u64 value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,8 @@
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
#if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
|
||||
|
||||
namespace {
|
||||
|
||||
enum UartRegister {
|
||||
@@ -138,4 +140,52 @@ namespace ams::kern {
|
||||
ReadUartRegister(UartRegister_FCR);
|
||||
}
|
||||
|
||||
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
|
||||
|
||||
namespace {
|
||||
|
||||
constinit KVirtualAddress g_debug_iram_address = 0;
|
||||
|
||||
constexpr size_t RingBufferSize = 0x5000;
|
||||
constinit uintptr_t g_offset = 0;
|
||||
|
||||
constinit u8 g_saved_buffer[RingBufferSize];
|
||||
|
||||
}
|
||||
|
||||
bool KDebugLogImpl::Initialize() {
|
||||
/* Set the base address. */
|
||||
g_debug_iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x38000;
|
||||
|
||||
std::memset(GetVoidPointer(g_debug_iram_address), 0xFF, RingBufferSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void KDebugLogImpl::PutChar(char c) {
|
||||
GetPointer<char>(g_debug_iram_address)[g_offset++] = c;
|
||||
|
||||
if (g_offset == RingBufferSize) {
|
||||
g_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void KDebugLogImpl::Flush() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
void KDebugLogImpl::Save() {
|
||||
std::memcpy(g_saved_buffer, GetVoidPointer(g_debug_iram_address), RingBufferSize);
|
||||
}
|
||||
|
||||
void KDebugLogImpl::Restore() {
|
||||
std::memcpy(GetVoidPointer(g_debug_iram_address), g_saved_buffer, RingBufferSize);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown Debug UART device!"
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace ams::kern {
|
||||
}
|
||||
|
||||
/* Map the memory. */
|
||||
R_TRY(GetCurrentProcess().GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm));
|
||||
R_TRY(this->owner->GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm));
|
||||
|
||||
/* Mark ourselves as mapped. */
|
||||
this->is_owner_mapped = true;
|
||||
@@ -151,7 +151,7 @@ namespace ams::kern {
|
||||
KScopedLightLock lk(this->lock);
|
||||
|
||||
/* Unmap the memory. */
|
||||
R_TRY(GetCurrentProcess().GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode));
|
||||
R_TRY(this->owner->GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode));
|
||||
|
||||
/* Mark ourselves as unmapped. */
|
||||
MESOSPHERE_ASSERT(this->is_owner_mapped);
|
||||
|
||||
@@ -34,6 +34,8 @@ namespace ams::kern {
|
||||
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
|
||||
#elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
|
||||
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
|
||||
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
|
||||
return true;
|
||||
#else
|
||||
#error "Unknown Debug UART device!"
|
||||
#endif
|
||||
|
||||
@@ -27,6 +27,11 @@ namespace ams::result::impl {
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
/* NOTE: This is not exposed via a header, but is referenced via assembly. */
|
||||
/* NOTE: Nintendo does not save register contents on panic; we use this */
|
||||
/* to generate an atmosphere fatal report on panic. */
|
||||
constinit KExceptionContext g_panic_exception_contexts[cpu::NumCores];
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr std::array<s32, cpu::NumCores> NegativeArray = [] {
|
||||
@@ -73,18 +78,38 @@ namespace ams::kern {
|
||||
} while (!g_current_ticket.compare_exchange_weak(compare, desired));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE KExceptionContext *GetPanicExceptionContext(int core_id) {
|
||||
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
|
||||
return std::addressof(g_panic_exception_contexts[core_id]);
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
[[gnu::unused]] void PrintCurrentState() {
|
||||
/* Wait for it to be our turn to print. */
|
||||
WaitCoreTicket();
|
||||
|
||||
const s32 core_id = GetCurrentCoreId();
|
||||
/* Get the current exception context. */
|
||||
const s32 core_id = GetCurrentCoreId();
|
||||
const auto *core_ctx = GetPanicExceptionContext(core_id);
|
||||
|
||||
/* Print the state. */
|
||||
MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id);
|
||||
|
||||
/* TODO: Dump register state. */
|
||||
|
||||
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||
/* Print registers. */
|
||||
if (core_ctx != nullptr) {
|
||||
MESOSPHERE_RELEASE_LOG(" Registers:\n");
|
||||
for (size_t i = 0; i < util::size(core_ctx->x); ++i) {
|
||||
MESOSPHERE_RELEASE_LOG(" X[%02zx]: %p\n", i, reinterpret_cast<void *>(core_ctx->x[i]));
|
||||
}
|
||||
MESOSPHERE_RELEASE_LOG(" SP: %p\n", reinterpret_cast<void *>(core_ctx->x[30]));
|
||||
}
|
||||
|
||||
/* Print backtrace. */
|
||||
MESOSPHERE_RELEASE_LOG(" Backtrace:\n");
|
||||
uintptr_t fp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
|
||||
uintptr_t fp = core_ctx != nullptr ? core_ctx->x[29] : reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
|
||||
for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) {
|
||||
struct {
|
||||
uintptr_t fp;
|
||||
@@ -107,12 +132,12 @@ namespace ams::kern {
|
||||
PrintCurrentState();
|
||||
#endif
|
||||
|
||||
KSystemControl::StopSystem();
|
||||
KSystemControl::StopSystem(GetPanicExceptionContext(GetCurrentCoreId()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
NORETURN WEAK_SYMBOL void Panic(const char *file, int line, const char *format, ...) {
|
||||
NORETURN void PanicImpl(const char *file, int line, const char *format, ...) {
|
||||
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
|
||||
/* Wait for it to be our turn to print. */
|
||||
WaitCoreTicket();
|
||||
@@ -133,7 +158,7 @@ namespace ams::kern {
|
||||
StopSystem();
|
||||
}
|
||||
|
||||
NORETURN WEAK_SYMBOL void Panic() {
|
||||
NORETURN void PanicImpl() {
|
||||
StopSystem();
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace ams::kern::svc {
|
||||
case ams::svc::CodeMemoryOperation_MapToOwner:
|
||||
{
|
||||
/* Check that the region is in range. */
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
|
||||
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Check the memory permission. */
|
||||
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());
|
||||
@@ -122,7 +122,7 @@ namespace ams::kern::svc {
|
||||
case ams::svc::CodeMemoryOperation_UnmapFromOwner:
|
||||
{
|
||||
/* Check that the region is in range. */
|
||||
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
|
||||
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
|
||||
|
||||
/* Check the memory permission. */
|
||||
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());
|
||||
|
||||
@@ -65,47 +65,9 @@ namespace ams::exosphere {
|
||||
|
||||
namespace ams {
|
||||
|
||||
struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
|
||||
static constexpr size_t MaxStackTrace = 0x20;
|
||||
static constexpr size_t MaxStackDumpSize = 0x100;
|
||||
static constexpr size_t ThreadLocalSize = 0x100;
|
||||
static constexpr size_t NumGprs = 29;
|
||||
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
|
||||
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
|
||||
static constexpr u32 StdAbortErrorDesc = 0xFFE;
|
||||
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
|
||||
static constexpr u32 DataAbortErrorDesc = 0x101;
|
||||
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
|
||||
struct FatalErrorContext : ::ams::impl::FatalErrorContext, sf::LargeData, sf::PrefersMapAliasTransferMode {};
|
||||
|
||||
u32 magic;
|
||||
u32 error_desc;
|
||||
u64 program_id;
|
||||
union {
|
||||
u64 gprs[32];
|
||||
struct {
|
||||
u64 _gprs[29];
|
||||
u64 fp;
|
||||
u64 lr;
|
||||
u64 sp;
|
||||
};
|
||||
};
|
||||
u64 pc;
|
||||
u64 module_base;
|
||||
u32 pstate;
|
||||
u32 afsr0;
|
||||
u32 afsr1;
|
||||
u32 esr;
|
||||
u64 far;
|
||||
u64 report_identifier; /* Normally just system tick. */
|
||||
u64 stack_trace_size;
|
||||
u64 stack_dump_size;
|
||||
u64 stack_trace[MaxStackTrace];
|
||||
u8 stack_dump[MaxStackDumpSize];
|
||||
u8 tls[ThreadLocalSize];
|
||||
};
|
||||
|
||||
static_assert(sizeof(FatalErrorContext) == 0x450, "sizeof(FatalErrorContext)");
|
||||
static_assert(util::is_pod<FatalErrorContext>::value, "FatalErrorContext");
|
||||
static_assert(sizeof(FatalErrorContext) == sizeof(::ams::impl::FatalErrorContext));
|
||||
|
||||
#ifdef ATMOSPHERE_GIT_BRANCH
|
||||
NX_CONSTEXPR const char *GetGitBranch() {
|
||||
|
||||
@@ -19,17 +19,17 @@
|
||||
|
||||
namespace ams::fs {
|
||||
|
||||
struct CodeInfo {
|
||||
struct CodeVerificationData {
|
||||
u8 signature[crypto::Rsa2048PssSha256Verifier::SignatureSize];
|
||||
u8 hash[crypto::Rsa2048PssSha256Verifier::HashSize];
|
||||
bool is_signed;
|
||||
u8 target_hash[crypto::Rsa2048PssSha256Verifier::HashSize];
|
||||
bool has_data;
|
||||
u8 reserved[3];
|
||||
};
|
||||
static_assert(sizeof(CodeInfo) == crypto::Rsa2048PssSha256Verifier::SignatureSize + crypto::Rsa2048PssSha256Verifier::HashSize + 4);
|
||||
static_assert(sizeof(CodeVerificationData) == crypto::Rsa2048PssSha256Verifier::SignatureSize + crypto::Rsa2048PssSha256Verifier::HashSize + 4);
|
||||
|
||||
Result MountCode(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id);
|
||||
Result MountCode(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
|
||||
|
||||
Result MountCodeForAtmosphereWithRedirection(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
|
||||
Result MountCodeForAtmosphere(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id);
|
||||
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific);
|
||||
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id);
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace ams::ro::impl {
|
||||
AMS_SF_METHOD_INFO(C, H, 2, Result, RegisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 3, Result, UnregisterModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 4, Result, RegisterProcessHandle, (const sf::ClientProcessId &client_pid, sf::CopyHandle process_h)) \
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterModuleInfoEx, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h), hos::Version_7_0_0)
|
||||
AMS_SF_METHOD_INFO(C, H, 10, Result, RegisterProcessModuleInfo, (const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h), hos::Version_7_0_0)
|
||||
|
||||
AMS_SF_DEFINE_INTERFACE(IRoInterface, AMS_RO_I_RO_INTERFACE_INTERFACE_INFO)
|
||||
|
||||
|
||||
@@ -20,10 +20,11 @@
|
||||
|
||||
namespace ams::ro {
|
||||
|
||||
enum class ModuleType : u8 {
|
||||
ForSelf = 0,
|
||||
ForOthers = 1,
|
||||
Count
|
||||
enum NrrKind : u8 {
|
||||
NrrKind_User = 0,
|
||||
NrrKind_JitPlugin = 1,
|
||||
|
||||
NrrKind_Count,
|
||||
};
|
||||
|
||||
struct ModuleId {
|
||||
@@ -54,7 +55,7 @@ namespace ams::ro {
|
||||
u8 signature[0x100];
|
||||
ncm::ProgramId program_id;
|
||||
u32 size;
|
||||
u8 type; /* 7.0.0+ */
|
||||
u8 nrr_kind; /* 7.0.0+ */
|
||||
u8 reserved_33D[3];
|
||||
u32 hashes_offset;
|
||||
u32 num_hashes;
|
||||
@@ -68,10 +69,10 @@ namespace ams::ro {
|
||||
return (static_cast<u64>(this->program_id) & this->certification.program_id_mask) == this->certification.program_id_pattern;
|
||||
}
|
||||
|
||||
ModuleType GetType() const {
|
||||
const ModuleType type = static_cast<ModuleType>(this->type);
|
||||
AMS_ABORT_UNLESS(type < ModuleType::Count);
|
||||
return type;
|
||||
NrrKind GetNrrKind() const {
|
||||
const NrrKind kind = static_cast<NrrKind>(this->nrr_kind);
|
||||
AMS_ABORT_UNLESS(kind < NrrKind_Count);
|
||||
return kind;
|
||||
}
|
||||
|
||||
ncm::ProgramId GetProgramId() const {
|
||||
|
||||
@@ -20,15 +20,15 @@ namespace ams::fs {
|
||||
|
||||
namespace {
|
||||
|
||||
Result OpenCodeFileSystemImpl(CodeInfo *out_code_info, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||
Result OpenCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||
/* Print a path suitable for the remote service. */
|
||||
fssrv::sf::Path sf_path;
|
||||
R_TRY(FspPathPrintf(std::addressof(sf_path), "%s", path));
|
||||
|
||||
/* Open the filesystem using libnx bindings. */
|
||||
static_assert(sizeof(CodeInfo) == sizeof(::FsCodeInfo));
|
||||
static_assert(sizeof(CodeVerificationData) == sizeof(::FsCodeInfo));
|
||||
::FsFileSystem fs;
|
||||
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_code_info), program_id.value, sf_path.str, std::addressof(fs)));
|
||||
R_TRY(fsldrOpenCodeFileSystem(reinterpret_cast<::FsCodeInfo *>(out_verification_data), program_id.value, sf_path.str, std::addressof(fs)));
|
||||
|
||||
/* Allocate a new filesystem wrapper. */
|
||||
auto fsa = std::make_unique<RemoteFileSystem>(fs);
|
||||
@@ -62,12 +62,12 @@ namespace ams::fs {
|
||||
return OpenPackageFileSystemImpl(out, sf_path.str);
|
||||
}
|
||||
|
||||
Result OpenSdCardCodeOrCodeFileSystemImpl(CodeInfo *out_code_info, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||
Result OpenSdCardCodeOrCodeFileSystemImpl(CodeVerificationData *out_verification_data, std::unique_ptr<fsa::IFileSystem> *out, const char *path, ncm::ProgramId program_id) {
|
||||
/* If we can open an sd card code fs, use it. */
|
||||
R_SUCCEED_IF(R_SUCCEEDED(OpenSdCardCodeFileSystemImpl(out, program_id)));
|
||||
|
||||
/* Otherwise, fall back to a normal code fs. */
|
||||
return OpenCodeFileSystemImpl(out_code_info, out, path, program_id);
|
||||
return OpenCodeFileSystemImpl(out_verification_data, out, path, program_id);
|
||||
}
|
||||
|
||||
Result OpenHblCodeFileSystemImpl(std::unique_ptr<fsa::IFileSystem> *out) {
|
||||
@@ -227,7 +227,7 @@ namespace ams::fs {
|
||||
public:
|
||||
AtmosphereCodeFileSystem() : initialized(false) { /* ... */ }
|
||||
|
||||
Result Initialize(CodeInfo *out_code_info, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||
Result Initialize(CodeVerificationData *out_verification_data, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||
AMS_ABORT_UNLESS(!this->initialized);
|
||||
|
||||
/* If we're hbl, we need to open a hbl fs. */
|
||||
@@ -239,7 +239,7 @@ namespace ams::fs {
|
||||
|
||||
/* Open the code filesystem. */
|
||||
std::unique_ptr<fsa::IFileSystem> fsa;
|
||||
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(out_code_info, std::addressof(fsa), path, program_id));
|
||||
R_TRY(OpenSdCardCodeOrCodeFileSystemImpl(out_verification_data, std::addressof(fsa), path, program_id));
|
||||
this->code_fs.emplace(std::move(fsa), program_id, is_specific);
|
||||
|
||||
this->program_id = program_id;
|
||||
@@ -275,7 +275,7 @@ namespace ams::fs {
|
||||
|
||||
}
|
||||
|
||||
Result MountCode(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||
Result MountCode(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||
/* Clear the output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace ams::fs {
|
||||
return fsa::Register(name, std::move(fsa));
|
||||
}
|
||||
|
||||
Result MountCodeForAtmosphereWithRedirection(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||
Result MountCodeForAtmosphereWithRedirection(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id, bool is_hbl, bool is_specific) {
|
||||
/* Clear the output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
@@ -314,7 +314,7 @@ namespace ams::fs {
|
||||
return fsa::Register(name, std::move(ams_code_fs));
|
||||
}
|
||||
|
||||
Result MountCodeForAtmosphere(CodeInfo *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||
Result MountCodeForAtmosphere(CodeVerificationData *out, const char *name, const char *path, ncm::ProgramId program_id) {
|
||||
/* Clear the output. */
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
|
||||
|
||||
@@ -27,3 +27,5 @@
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/crypto.hpp>
|
||||
#include <vapours/svc.hpp>
|
||||
|
||||
#include <vapours/ams/ams_fatal_error_context.hpp>
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 14
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 4
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO
|
||||
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 10
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 2
|
||||
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 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/includes.hpp>
|
||||
#include <vapours/defines.hpp>
|
||||
|
||||
namespace ams::impl {
|
||||
|
||||
struct FatalErrorContext {
|
||||
static constexpr size_t MaxStackTrace = 0x20;
|
||||
static constexpr size_t MaxStackDumpSize = 0x100;
|
||||
static constexpr size_t ThreadLocalSize = 0x100;
|
||||
static constexpr size_t NumGprs = 29;
|
||||
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
|
||||
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
|
||||
static constexpr u32 StdAbortErrorDesc = 0xFFE;
|
||||
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
|
||||
static constexpr u32 KernelPanicDesc = 0xF00;
|
||||
static constexpr u32 DataAbortErrorDesc = 0x101;
|
||||
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
|
||||
|
||||
u32 magic;
|
||||
u32 error_desc;
|
||||
u64 program_id;
|
||||
union {
|
||||
u64 gprs[32];
|
||||
struct {
|
||||
u64 _gprs[29];
|
||||
u64 fp;
|
||||
u64 lr;
|
||||
u64 sp;
|
||||
};
|
||||
};
|
||||
u64 pc;
|
||||
u64 module_base;
|
||||
u32 pstate;
|
||||
u32 afsr0;
|
||||
u32 afsr1;
|
||||
u32 esr;
|
||||
u64 far;
|
||||
u64 report_identifier; /* Normally just system tick. */
|
||||
u64 stack_trace_size;
|
||||
u64 stack_dump_size;
|
||||
u64 stack_trace[MaxStackTrace];
|
||||
u8 stack_dump[MaxStackDumpSize];
|
||||
u8 tls[ThreadLocalSize];
|
||||
};
|
||||
|
||||
static_assert(sizeof(FatalErrorContext) == 0x450);
|
||||
static_assert(std::is_standard_layout<FatalErrorContext>::value);
|
||||
static_assert(std::is_trivial<FatalErrorContext>::value);
|
||||
|
||||
}
|
||||
@@ -55,8 +55,9 @@
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_10_0_4 ATMOSPHERE_TARGET_FIRMWARE(10, 0, 4)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_10_1_0 ATMOSPHERE_TARGET_FIRMWARE(10, 1, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_10_1_1 ATMOSPHERE_TARGET_FIRMWARE(10, 1, 1)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_10_2_0 ATMOSPHERE_TARGET_FIRMWARE(10, 2, 0)
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_10_1_1
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_10_2_0
|
||||
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE(0, 0, 0)
|
||||
#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_CURRENT
|
||||
@@ -104,6 +105,7 @@ namespace ams {
|
||||
TargetFirmware_10_0_4 = ATMOSPHERE_TARGET_FIRMWARE_10_0_4,
|
||||
TargetFirmware_10_1_0 = ATMOSPHERE_TARGET_FIRMWARE_10_1_0,
|
||||
TargetFirmware_10_1_1 = ATMOSPHERE_TARGET_FIRMWARE_10_1_1,
|
||||
TargetFirmware_10_2_0 = ATMOSPHERE_TARGET_FIRMWARE_10_2_0,
|
||||
|
||||
TargetFirmware_Current = ATMOSPHERE_TARGET_FIRMWARE_CURRENT,
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace ams::ro {
|
||||
R_DEFINE_ERROR_RESULT(TooManyNro, 7);
|
||||
R_DEFINE_ERROR_RESULT(TooManyNrr, 8);
|
||||
R_DEFINE_ERROR_RESULT(NotAuthorized, 9);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNrrType, 10);
|
||||
R_DEFINE_ERROR_RESULT(InvalidNrrKind, 10);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(InternalError, 1023);
|
||||
|
||||
|
||||
@@ -58,15 +58,15 @@ namespace ams::ldr {
|
||||
}
|
||||
|
||||
/* Mount the atmosphere code file system. */
|
||||
R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(this->ams_code_info), AtmosphereCodeMountName, content_path, loc.program_id, this->override_status.IsHbl(), this->override_status.IsProgramSpecific()));
|
||||
R_TRY(fs::MountCodeForAtmosphereWithRedirection(std::addressof(this->ams_code_verification_data), AtmosphereCodeMountName, content_path, loc.program_id, this->override_status.IsHbl(), this->override_status.IsProgramSpecific()));
|
||||
this->mounted_ams = true;
|
||||
|
||||
/* Mount the sd or base code file system. */
|
||||
R_TRY(fs::MountCodeForAtmosphere(std::addressof(this->sd_or_base_code_info), SdOrCodeMountName, content_path, loc.program_id));
|
||||
R_TRY(fs::MountCodeForAtmosphere(std::addressof(this->sd_or_base_code_verification_data), SdOrCodeMountName, content_path, loc.program_id));
|
||||
this->mounted_sd_or_code = true;
|
||||
|
||||
/* Mount the base code file system. */
|
||||
if (R_SUCCEEDED(fs::MountCode(std::addressof(this->base_code_info), CodeMountName, content_path, loc.program_id))) {
|
||||
if (R_SUCCEEDED(fs::MountCode(std::addressof(this->base_code_verification_data), CodeMountName, content_path, loc.program_id))) {
|
||||
this->mounted_code = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ namespace ams::ldr {
|
||||
private:
|
||||
std::scoped_lock<os::Mutex> lk;
|
||||
cfg::OverrideStatus override_status;
|
||||
fs::CodeInfo ams_code_info;
|
||||
fs::CodeInfo sd_or_base_code_info;
|
||||
fs::CodeInfo base_code_info;
|
||||
fs::CodeVerificationData ams_code_verification_data;
|
||||
fs::CodeVerificationData sd_or_base_code_verification_data;
|
||||
fs::CodeVerificationData base_code_verification_data;
|
||||
Result result;
|
||||
bool has_status;
|
||||
bool mounted_ams;
|
||||
@@ -47,16 +47,16 @@ namespace ams::ldr {
|
||||
return this->override_status;
|
||||
}
|
||||
|
||||
const fs::CodeInfo &GetAtmosphereCodeInfo() const {
|
||||
return this->ams_code_info;
|
||||
const fs::CodeVerificationData &GetAtmosphereCodeVerificationData() const {
|
||||
return this->ams_code_verification_data;
|
||||
}
|
||||
|
||||
const fs::CodeInfo &GetSdOrBaseCodeInfo() const {
|
||||
return this->sd_or_base_code_info;
|
||||
const fs::CodeVerificationData &GetSdOrBaseCodeVerificationData() const {
|
||||
return this->sd_or_base_code_verification_data;
|
||||
}
|
||||
|
||||
const fs::CodeInfo &GetCodeInfo() const {
|
||||
return this->base_code_info;
|
||||
const fs::CodeVerificationData &GetCodeVerificationData() const {
|
||||
return this->base_code_verification_data;
|
||||
}
|
||||
private:
|
||||
Result Initialize(const ncm::ProgramLocation &loc);
|
||||
|
||||
@@ -107,7 +107,7 @@ namespace ams::ldr {
|
||||
Result ValidateAcidSignature(Meta *meta) {
|
||||
/* Loader did not check signatures prior to 10.0.0. */
|
||||
if (hos::GetVersion() < hos::Version_10_0_0) {
|
||||
meta->is_signed = false;
|
||||
meta->check_verification_data = false;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ namespace ams::ldr {
|
||||
const bool is_signature_valid = crypto::VerifyRsa2048PssSha256(sig, sig_size, mod, mod_size, exp, exp_size, msg, msg_size);
|
||||
R_UNLESS(is_signature_valid || !IsEnabledProgramVerification(), ResultInvalidAcidSignature());
|
||||
|
||||
meta->is_signed = is_signature_valid;
|
||||
meta->check_verification_data = is_signature_valid;
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -220,8 +220,8 @@ namespace ams::ldr {
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
R_TRY(LoadMetaFromFile(file, &g_original_meta_cache));
|
||||
R_TRY(ValidateAcidSignature(&g_original_meta_cache.meta));
|
||||
meta->modulus = g_original_meta_cache.meta.modulus;
|
||||
meta->is_signed = g_original_meta_cache.meta.is_signed;
|
||||
meta->modulus = g_original_meta_cache.meta.modulus;
|
||||
meta->check_verification_data = g_original_meta_cache.meta.check_verification_data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace ams::ldr {
|
||||
void *aci_kac;
|
||||
|
||||
void *modulus;
|
||||
bool is_signed;
|
||||
bool check_verification_data;
|
||||
};
|
||||
|
||||
/* Meta API. */
|
||||
|
||||
@@ -210,7 +210,7 @@ namespace ams::ldr {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateMeta(const Meta *meta, const ncm::ProgramLocation &loc, const fs::CodeInfo &code_info) {
|
||||
Result ValidateMeta(const Meta *meta, const ncm::ProgramLocation &loc, const fs::CodeVerificationData &code_verification_data) {
|
||||
/* Validate version. */
|
||||
R_TRY(ValidateProgramVersion(loc.program_id, meta->npdm->version));
|
||||
|
||||
@@ -222,15 +222,15 @@ namespace ams::ldr {
|
||||
R_TRY(caps::ValidateCapabilities(meta->acid_kac, meta->acid->kac_size, meta->aci_kac, meta->aci->kac_size));
|
||||
|
||||
/* If we have data to validate, validate it. */
|
||||
if (code_info.is_signed && meta->is_signed) {
|
||||
const u8 *sig = code_info.signature;
|
||||
const size_t sig_size = sizeof(code_info.signature);
|
||||
if (code_verification_data.has_data && meta->check_verification_data) {
|
||||
const u8 *sig = code_verification_data.signature;
|
||||
const size_t sig_size = sizeof(code_verification_data.signature);
|
||||
const u8 *mod = static_cast<u8 *>(meta->modulus);
|
||||
const size_t mod_size = crypto::Rsa2048PssSha256Verifier::ModulusSize;
|
||||
const u8 *exp = fssystem::GetAcidSignatureKeyPublicExponent();
|
||||
const size_t exp_size = fssystem::AcidSignatureKeyPublicExponentSize;
|
||||
const u8 *hsh = code_info.hash;
|
||||
const size_t hsh_size = sizeof(code_info.hash);
|
||||
const u8 *hsh = code_verification_data.target_hash;
|
||||
const size_t hsh_size = sizeof(code_verification_data.target_hash);
|
||||
const bool is_signature_valid = crypto::VerifyRsa2048PssSha256WithHash(sig, sig_size, mod, mod_size, exp, exp_size, hsh, hsh_size);
|
||||
|
||||
R_UNLESS(is_signature_valid, ResultInvalidNcaSignature());
|
||||
@@ -596,7 +596,7 @@ namespace ams::ldr {
|
||||
R_TRY(LoadMetaFromCache(&meta, loc, override_status));
|
||||
|
||||
/* Validate meta. */
|
||||
R_TRY(ValidateMeta(&meta, loc, mount.GetCodeInfo()));
|
||||
R_TRY(ValidateMeta(&meta, loc, mount.GetCodeVerificationData()));
|
||||
|
||||
/* Load, validate NSOs. */
|
||||
R_TRY(LoadNsoHeaders(nso_headers, has_nso));
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace ams::ro::impl {
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
Result ValidateNrr(const NrrHeader *header, u64 size, ncm::ProgramId program_id, ModuleType expected_type, bool enforce_type) {
|
||||
Result ValidateNrr(const NrrHeader *header, u64 size, ncm::ProgramId program_id, NrrKind nrr_kind, bool enforce_nrr_kind) {
|
||||
/* Check magic. */
|
||||
R_UNLESS(header->IsMagicValid(), ResultInvalidNrr());
|
||||
|
||||
@@ -182,9 +182,9 @@ namespace ams::ro::impl {
|
||||
/* Check program id. */
|
||||
R_UNLESS(header->GetProgramId() == program_id, ResultInvalidNrr());
|
||||
|
||||
/* Check type. */
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0 && enforce_type) {
|
||||
R_UNLESS(header->GetType() == expected_type, ResultInvalidNrrType());
|
||||
/* Check nrr kind. */
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0 && enforce_nrr_kind) {
|
||||
R_UNLESS(header->GetNrrKind() == nrr_kind, ResultInvalidNrrKind());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ namespace ams::ro::impl {
|
||||
}
|
||||
|
||||
/* Utilities for working with NRRs. */
|
||||
Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, Handle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, ModuleType expected_type, bool enforce_type) {
|
||||
Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, Handle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, NrrKind nrr_kind, bool enforce_nrr_kind) {
|
||||
map::MappedCodeMemory nrr_mcm(ResultInternalError{});
|
||||
|
||||
/* First, map the NRR. */
|
||||
@@ -209,7 +209,7 @@ namespace ams::ro::impl {
|
||||
R_TRY(nrr_map.GetResult());
|
||||
|
||||
NrrHeader *nrr_header = reinterpret_cast<NrrHeader *>(map_address);
|
||||
R_TRY(ValidateNrr(nrr_header, nrr_heap_size, program_id, expected_type, enforce_type));
|
||||
R_TRY(ValidateNrr(nrr_header, nrr_heap_size, program_id, nrr_kind, enforce_nrr_kind));
|
||||
|
||||
/* Invalidation here actually prevents them from unmapping at scope exit. */
|
||||
nrr_map.Invalidate();
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
namespace ams::ro::impl {
|
||||
|
||||
/* Utilities for working with NRRs. */
|
||||
Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, Handle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, ModuleType expected_type, bool enforce_type);
|
||||
Result MapAndValidateNrr(NrrHeader **out_header, u64 *out_mapped_code_address, void *out_hash, size_t out_hash_size, Handle process_handle, ncm::ProgramId program_id, u64 nrr_heap_address, u64 nrr_heap_size, NrrKind nrr_kind, bool enforce_nrr_kind);
|
||||
Result UnmapNrr(Handle process_handle, const NrrHeader *header, u64 nrr_heap_address, u64 nrr_heap_size, u64 mapped_code_address);
|
||||
|
||||
bool ValidateNrrHashTableEntry(const void *signed_area, size_t signed_area_size, size_t hashes_offset, size_t num_hashes, const void *nrr_hash, const u8 *hash_table, const void *desired_hash);
|
||||
|
||||
@@ -382,13 +382,13 @@ namespace ams::ro::impl {
|
||||
}
|
||||
|
||||
/* Context utilities. */
|
||||
Result RegisterProcess(size_t *out_context_id, Handle process_handle, os::ProcessId process_id) {
|
||||
Result RegisterProcess(size_t *out_context_id, os::ManagedHandle process_handle, os::ProcessId process_id) {
|
||||
/* Validate process handle. */
|
||||
{
|
||||
os::ProcessId handle_pid = os::InvalidProcessId;
|
||||
|
||||
/* Validate handle is a valid process handle. */
|
||||
R_UNLESS(R_SUCCEEDED(os::TryGetProcessId(&handle_pid, process_handle)), ResultInvalidProcess());
|
||||
R_UNLESS(R_SUCCEEDED(os::TryGetProcessId(&handle_pid, process_handle.Get())), ResultInvalidProcess());
|
||||
|
||||
/* Validate process id. */
|
||||
R_UNLESS(handle_pid == process_id, ResultInvalidProcess());
|
||||
@@ -397,7 +397,7 @@ namespace ams::ro::impl {
|
||||
/* Check if a process context already exists. */
|
||||
R_UNLESS(GetContextByProcessId(process_id) == nullptr, ResultInvalidSession());
|
||||
|
||||
*out_context_id = AllocateContext(process_handle, process_id);
|
||||
*out_context_id = AllocateContext(process_handle.Move(), process_id);
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
@@ -413,13 +413,13 @@ namespace ams::ro::impl {
|
||||
}
|
||||
|
||||
/* Service implementations. */
|
||||
Result RegisterModuleInfo(size_t context_id, Handle process_h, u64 nrr_address, u64 nrr_size, ModuleType expected_type, bool enforce_type) {
|
||||
Result RegisterModuleInfo(size_t context_id, os::ManagedHandle process_handle, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind) {
|
||||
/* Get context. */
|
||||
ProcessContext *context = GetContextById(context_id);
|
||||
AMS_ABORT_UNLESS(context != nullptr);
|
||||
|
||||
/* Get program id. */
|
||||
const ncm::ProgramId program_id = context->GetProgramId(process_h);
|
||||
const ncm::ProgramId program_id = context->GetProgramId(process_handle.Get());
|
||||
|
||||
/* Validate address/size. */
|
||||
R_TRY(ValidateAddressAndNonZeroSize(nrr_address, nrr_size));
|
||||
@@ -435,7 +435,7 @@ namespace ams::ro::impl {
|
||||
/* Map. */
|
||||
NrrHeader *header = nullptr;
|
||||
u64 mapped_code_address = 0;
|
||||
R_TRY(MapAndValidateNrr(&header, &mapped_code_address, std::addressof(signed_area_hash), sizeof(signed_area_hash), context->process_handle, program_id, nrr_address, nrr_size, expected_type, enforce_type));
|
||||
R_TRY(MapAndValidateNrr(&header, &mapped_code_address, std::addressof(signed_area_hash), sizeof(signed_area_hash), context->process_handle, program_id, nrr_address, nrr_size, nrr_kind, enforce_nrr_kind));
|
||||
|
||||
/* Set NRR info. */
|
||||
context->SetNrrInfoInUse(nrr_info, true);
|
||||
|
||||
@@ -30,12 +30,12 @@ namespace ams::ro::impl {
|
||||
bool ShouldEaseNroRestriction();
|
||||
|
||||
/* Context utilities. */
|
||||
Result RegisterProcess(size_t *out_context_id, Handle process_handle, os::ProcessId process_id);
|
||||
Result RegisterProcess(size_t *out_context_id, os::ManagedHandle process_handle, os::ProcessId process_id);
|
||||
Result ValidateProcess(size_t context_id, os::ProcessId process_id);
|
||||
void UnregisterProcess(size_t context_id);
|
||||
|
||||
/* Service implementations. */
|
||||
Result RegisterModuleInfo(size_t context_id, Handle process_h, u64 nrr_address, u64 nrr_size, ModuleType expected_type, bool enforce_type);
|
||||
Result RegisterModuleInfo(size_t context_id, os::ManagedHandle process_h, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind);
|
||||
Result UnregisterModuleInfo(size_t context_id, u64 nrr_address);
|
||||
Result MapManualLoadModuleMemory(u64 *out_address, size_t context_id, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
|
||||
Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address);
|
||||
|
||||
@@ -95,11 +95,11 @@ namespace {
|
||||
constexpr size_t DebugMonitorMaxSessions = 2;
|
||||
|
||||
/* NOTE: Official code passes 32 for ldr:ro max sessions. We will pass 2, because that's the actual limit. */
|
||||
constexpr sm::ServiceName ForSelfServiceName = sm::ServiceName::Encode("ldr:ro");
|
||||
constexpr size_t ForSelfMaxSessions = 2;
|
||||
constexpr sm::ServiceName UserServiceName = sm::ServiceName::Encode("ldr:ro");
|
||||
constexpr size_t UserMaxSessions = 2;
|
||||
|
||||
constexpr sm::ServiceName ForOthersServiceName = sm::ServiceName::Encode("ro:1");
|
||||
constexpr size_t ForOthersMaxSessions = 2;
|
||||
constexpr sm::ServiceName JitPluginServiceName = sm::ServiceName::Encode("ro:1");
|
||||
constexpr size_t JitPluginMaxSessions = 2;
|
||||
|
||||
}
|
||||
|
||||
@@ -120,9 +120,9 @@ int main(int argc, char **argv)
|
||||
/* Create services. */
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<ro::impl::IDebugMonitorInterface, ro::DebugMonitorService>(DebugMonitorServiceName, DebugMonitorMaxSessions)));
|
||||
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<ro::impl::IRoInterface, ro::RoServiceForSelf>(ForSelfServiceName, ForSelfMaxSessions)));
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<ro::impl::IRoInterface, ro::RoUserService>(UserServiceName, UserMaxSessions)));
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0) {
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<ro::impl::IRoInterface, ro::RoServiceForOthers>(ForOthersServiceName, ForOthersMaxSessions)));
|
||||
R_ABORT_UNLESS((g_server_manager.RegisterServer<ro::impl::IRoInterface, ro::RoJitPluginService>(JitPluginServiceName, JitPluginMaxSessions)));
|
||||
}
|
||||
|
||||
/* Loop forever, servicing our services. */
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace ams::ro {
|
||||
impl::SetDevelopmentFunctionEnabled(is_development_function_enabled);
|
||||
}
|
||||
|
||||
RoService::RoService(ModuleType t) : context_id(impl::InvalidContextId), type(t) {
|
||||
RoService::RoService(NrrKind k) : context_id(impl::InvalidContextId), nrr_kind(k) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace ams::ro {
|
||||
|
||||
Result RoService::RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size) {
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::RegisterModuleInfo(this->context_id, svc::InvalidHandle, nrr_address, nrr_size, ModuleType::ForSelf, true);
|
||||
return impl::RegisterModuleInfo(this->context_id, svc::InvalidHandle, nrr_address, nrr_size, NrrKind_User, true);
|
||||
}
|
||||
|
||||
Result RoService::UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address) {
|
||||
@@ -56,12 +56,20 @@ namespace ams::ro {
|
||||
}
|
||||
|
||||
Result RoService::RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle process_h) {
|
||||
return impl::RegisterProcess(std::addressof(this->context_id), process_h.GetValue(), client_pid.GetValue());
|
||||
/* Ensure we manage references to the process handle correctly. */
|
||||
os::ManagedHandle process_handle(process_h.GetValue());
|
||||
|
||||
/* Register the process. */
|
||||
return impl::RegisterProcess(std::addressof(this->context_id), std::move(process_handle), client_pid.GetValue());
|
||||
}
|
||||
|
||||
Result RoService::RegisterModuleInfoEx(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h) {
|
||||
Result RoService::RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h) {
|
||||
/* Ensure we manage references to the process handle correctly. */
|
||||
os::ManagedHandle process_handle(process_h.GetValue());
|
||||
|
||||
/* Register the module. */
|
||||
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
|
||||
return impl::RegisterModuleInfo(this->context_id, process_h.GetValue(), nrr_address, nrr_size, this->type, this->type == ModuleType::ForOthers);
|
||||
return impl::RegisterModuleInfo(this->context_id, std::move(process_handle), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace ams::ro {
|
||||
class RoService {
|
||||
private:
|
||||
size_t context_id;
|
||||
ModuleType type;
|
||||
NrrKind nrr_kind;
|
||||
protected:
|
||||
explicit RoService(ModuleType t);
|
||||
explicit RoService(NrrKind k);
|
||||
public:
|
||||
virtual ~RoService();
|
||||
public:
|
||||
@@ -38,19 +38,18 @@ namespace ams::ro {
|
||||
Result RegisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size);
|
||||
Result UnregisterModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address);
|
||||
Result RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle process_h);
|
||||
Result RegisterModuleInfoEx(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h);
|
||||
Result RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h);
|
||||
};
|
||||
static_assert(ro::impl::IsIRoInterface<RoService>);
|
||||
|
||||
class RoServiceForSelf final : public RoService {
|
||||
class RoUserService final : public RoService {
|
||||
public:
|
||||
RoServiceForSelf() : RoService(ro::ModuleType::ForSelf) { /* ... */ }
|
||||
RoUserService() : RoService(NrrKind_User) { /* ... */ }
|
||||
};
|
||||
|
||||
/* TODO: This is really JitPlugin... */
|
||||
class RoServiceForOthers final : public RoService {
|
||||
class RoJitPluginService final : public RoService {
|
||||
public:
|
||||
RoServiceForOthers() : RoService(ro::ModuleType::ForOthers) { /* ... */ }
|
||||
RoJitPluginService() : RoService(NrrKind_JitPlugin) { /* ... */ }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -350,6 +350,12 @@ namespace ams::sm::impl {
|
||||
return service == ServiceName::Encode("fsp-srv");
|
||||
}
|
||||
|
||||
bool ShouldCloseOnClientDisconnect(ServiceName service) {
|
||||
/* jit sysmodule is closed and relaunched by am for each application which uses it. */
|
||||
constexpr auto JitU = ServiceName::Encode("jit:u");
|
||||
return service == JitU;
|
||||
}
|
||||
|
||||
Result GetMitmServiceHandleImpl(Handle *out, ServiceInfo *service_info, const MitmProcessInfo &client_info) {
|
||||
/* Send command to query if we should mitm. */
|
||||
bool should_mitm;
|
||||
@@ -419,6 +425,28 @@ namespace ams::sm::impl {
|
||||
|
||||
return ResultSuccess();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Client disconnection callback. */
|
||||
void OnClientDisconnected(os::ProcessId process_id) {
|
||||
/* Ensure that the process id is valid. */
|
||||
if (process_id == os::InvalidProcessId) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* NOTE: Nintendo unregisters all services a process hosted on client close. */
|
||||
/* We do not do this as an atmosphere extension, in order to reduce the number */
|
||||
/* of sessions open at any given time. */
|
||||
/* However, certain system behavior (jit) relies on this occurring. */
|
||||
/* As such, we will special case the system components which rely on the behavior. */
|
||||
for (size_t i = 0; i < ServiceCountMax; i++) {
|
||||
if (g_service_list[i].name != InvalidServiceName && g_service_list[i].owner_process_id == process_id) {
|
||||
if (ShouldCloseOnClientDisconnect(g_service_list[i].name)) {
|
||||
g_service_list[i].Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Process management. */
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
|
||||
namespace ams::sm::impl {
|
||||
|
||||
/* Client disconnection callback. */
|
||||
void OnClientDisconnected(os::ProcessId process_id);
|
||||
|
||||
/* Process management. */
|
||||
Result RegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus, const void *acid_sac, size_t acid_sac_size, const void *aci_sac, size_t aci_sac_size);
|
||||
Result UnregisterProcess(os::ProcessId process_id);
|
||||
|
||||
@@ -19,6 +19,12 @@
|
||||
|
||||
namespace ams::sm {
|
||||
|
||||
UserService::~UserService() {
|
||||
if (this->has_initialized) {
|
||||
impl::OnClientDisconnected(this->process_id);
|
||||
}
|
||||
}
|
||||
|
||||
Result UserService::RegisterClient(const sf::ClientProcessId &client_process_id) {
|
||||
this->process_id = client_process_id.GetValue();
|
||||
this->has_initialized = true;
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace ams::sm {
|
||||
bool has_initialized = false;
|
||||
private:
|
||||
Result EnsureInitialized();
|
||||
public:
|
||||
virtual ~UserService();
|
||||
public:
|
||||
/* Official commands. */
|
||||
Result RegisterClient(const sf::ClientProcessId &client_process_id);
|
||||
|
||||
Reference in New Issue
Block a user