Compare commits

..

12 Commits

Author SHA1 Message Date
Michael Scire
9b3b08bdeb kern: fix KCodeMemory SVCs when Owner process != Generator process 2020-09-17 08:25:27 -07:00
Michael Scire
84f17f6a3a kern: default to release config 2020-09-16 21:18:02 -07:00
Michael Scire
3b0ed9cdba kern: generate fatal error on panic 2020-09-16 16:47:29 -07:00
Michael Scire
4df583cbb6 kern: add build-define for logging to iram ringbuffer 2020-09-16 16:47:18 -07:00
Michael Scire
28ceedb533 git subrepo push emummc
subrepo:
  subdir:   "emummc"
  merged:   "6a814ebb"
upstream:
  origin:   "https://github.com/m4xw/emuMMC"
  branch:   "exo2"
  commit:   "6a814ebb"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-09-14 18:21:38 -07:00
Michael Scire
f551ca4461 emummc: manually fix .gitrepo 2020-09-14 18:17:32 -07:00
Michael Scire
2cf5c65bc5 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "48dbf480"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "48dbf480"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-09-14 18:14:05 -07:00
Michael Scire
47d0d5c6ab ams: support 10.2.0 (bump vers to 0.14.3) 2020-09-14 18:13:18 -07:00
Michael Scire
fd0e3e2160 docs: update changelog 2020-09-14 18:12:48 -07:00
Michael Scire
074364753f loader: improve verification terminology 2020-09-08 15:34:22 -07:00
Michael Scire
b7d99b732a ro: rename ModuleType to reflect reality 2020-09-08 15:05:15 -07:00
Michael Scire
1cccb6efc4 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "04ef9bf8"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "04ef9bf8"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-09-07 10:52:49 -07:00
47 changed files with 593 additions and 147 deletions

View File

@@ -1,4 +1,19 @@
# Changelog
## 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.

View File

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

View File

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

View File

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

View 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__

View 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__

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 2d522dc6a12b2eb5eb3f103a8c5b5126ca301b1a
parent = 35fffade4ea4fdbba9cf2443c321e724c9e70c3d
commit = 48dbf4808f4f2042de8c45e9ec471a8f60d5d621
parent = 47d0d5c6abc1c9957cd05c63b02ee5e712179b80
method = merge
cmdver = 0.4.1

View File

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

View File

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

View File

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

View 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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -27,3 +27,5 @@
#include <vapours/results.hpp>
#include <vapours/crypto.hpp>
#include <vapours/svc.hpp>
#include <vapours/ams/ams_fatal_error_context.hpp>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -32,7 +32,7 @@ namespace ams::ldr {
void *aci_kac;
void *modulus;
bool is_signed;
bool check_verification_data;
};
/* Meta API. */

View File

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

View File

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

View File

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

View File

@@ -413,7 +413,7 @@ 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, Handle process_h, 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);
@@ -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);

View File

@@ -35,7 +35,7 @@ namespace ams::ro::impl {
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, Handle 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);

View File

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

View File

@@ -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) {
@@ -59,9 +59,9 @@ namespace ams::ro {
return impl::RegisterProcess(std::addressof(this->context_id), process_h.GetValue(), 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) {
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, process_h.GetValue(), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
}
}

View File

@@ -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) { /* ... */ }
};
}