Compare commits

...

8 Commits

Author SHA1 Message Date
Michael Scire
fa0df994ba git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "f6dac1e6"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "f6dac1e6"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-09-17 08:34:48 -07:00
Michael Scire
909a1767a6 ams: bump version to 0.14.4 2020-09-17 08:34:02 -07:00
Michael Scire
dbe59fd041 kern: fix KCodeMemory SVCs when Owner process != Generator process 2020-09-17 08:26:08 -07:00
Michael Scire
9b65daf439 kern: default to release config 2020-09-17 08:26:08 -07:00
Michael Scire
4acdc899f5 kern: generate fatal error on panic 2020-09-17 08:26:08 -07:00
Michael Scire
76957e502d kern: add build-define for logging to iram ringbuffer 2020-09-17 08:26:08 -07:00
Michael Scire
909397233c sm: Fix atmosphere-extension interaction with official JIT sysmodule usage 2020-09-17 08:24:47 -07:00
Michael Scire
211a828730 ro: fix process handle leak when using JitPlugin NROs 2020-09-17 08:17:11 -07:00
26 changed files with 421 additions and 71 deletions

View File

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

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

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 48dbf4808f4f2042de8c45e9ec471a8f60d5d621
parent = 47d0d5c6abc1c9957cd05c63b02ee5e712179b80
commit = f6dac1e67793233cc916f317cf517244dd348a5e
parent = 909a1767a6080bab7ea6032c00e1ff4cec993af0
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

@@ -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,7 +17,7 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 14
#define ATMOSPHERE_RELEASE_VERSION_MICRO 3
#define ATMOSPHERE_RELEASE_VERSION_MICRO 4
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

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

@@ -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, NrrKind nrr_kind, bool enforce_nrr_kind) {
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));

View File

@@ -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, NrrKind nrr_kind, bool enforce_nrr_kind);
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);

View File

@@ -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::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->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
return impl::RegisterModuleInfo(this->context_id, std::move(process_handle), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
}
}

View File

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

View File

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

View File

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

View File

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