diff --git a/stratosphere/pm/source/pm_main.cpp b/stratosphere/pm/source/pm_main.cpp
index 2c33145fb..034567ecf 100644
--- a/stratosphere/pm/source/pm_main.cpp
+++ b/stratosphere/pm/source/pm_main.cpp
@@ -28,6 +28,7 @@
#include "pm_process_track.hpp"
#include "pm_registration.hpp"
#include "pm_debug_monitor.hpp"
+#include "smm_ams.h"
extern "C" {
extern u32 __start__;
@@ -56,6 +57,20 @@ void __libnx_initheap(void) {
fake_heap_end = (char*)addr + size;
}
+void RegisterPrivilegedProcessesWithFs() {
+ /* Ensures that all privileged processes are registered with full FS permissions. */
+ constexpr u64 PRIVILEGED_PROCESS_MIN = 0;
+ constexpr u64 PRIVILEGED_PROCESS_MAX = 0x4F;
+
+ const u32 PRIVILEGED_FAH[0x1C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x0000001C, 0x00000000, 0x0000001C, 0x00000000};
+ const u32 PRIVILEGED_FAC[0x2C/sizeof(u32)] = {0x00000001, 0x00000000, 0x80000000, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF};
+
+ for (u64 pid = PRIVILEGED_PROCESS_MIN; pid <= PRIVILEGED_PROCESS_MAX; pid++) {
+ fsprUnregisterProgram(pid);
+ fsprRegisterProgram(pid, pid, FsStorageId_NandSystem, PRIVILEGED_FAH, sizeof(PRIVILEGED_FAH), PRIVILEGED_FAC, sizeof(PRIVILEGED_FAC));
+ }
+}
+
void __appInit(void) {
Result rc;
@@ -64,27 +79,33 @@ void __appInit(void) {
fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_SM));
}
- rc = fsInitialize();
- if (R_FAILED(rc)) {
- fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
- }
-
- rc = lrInitialize();
+ rc = fsprInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 1);
}
- rc = fsprInitialize();
- if (R_FAILED(rc)) {
+ /* This works around a bug with process permissions on < 4.0.0. */
+ RegisterPrivilegedProcessesWithFs();
+
+ rc = smManagerAmsInitialize();
+ if (R_SUCCEEDED(rc)) {
+ smManagerAmsEndInitialDefers();
+ smManagerAmsExit();
+ } else {
fatalSimple(0xCAFE << 4 | 2);
}
- rc = ldrPmInitialize();
+ rc = smManagerInitialize();
+ if (R_FAILED(rc)) {
+ fatalSimple(0xCAFE << 4 | 3);
+ }
+
+ rc = lrInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 4);
}
- rc = smManagerInitialize();
+ rc = ldrPmInitialize();
if (R_FAILED(rc)) {
fatalSimple(0xCAFE << 4 | 5);
}
@@ -94,6 +115,11 @@ void __appInit(void) {
fatalSimple(0xCAFE << 4 | 6);
}
+ rc = fsInitialize();
+ if (R_FAILED(rc)) {
+ fatalSimple(MAKERESULT(Module_Libnx, LibnxError_InitFail_FS));
+ }
+
CheckAtmosphereVersion();
}
diff --git a/stratosphere/pm/source/pm_resource_limits.cpp b/stratosphere/pm/source/pm_resource_limits.cpp
index e0d729075..3d311d713 100644
--- a/stratosphere/pm/source/pm_resource_limits.cpp
+++ b/stratosphere/pm/source/pm_resource_limits.cpp
@@ -182,7 +182,8 @@ void ResourceLimitUtils::InitializeLimits() {
/* Atmosphere: Allocate extra memory (24 MiB) to SYSTEM away from Applet. */
for (unsigned int i = 0; i < 6; i++) {
g_memory_resource_limits[i][0] += ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
- g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
+ //g_memory_resource_limits[i][2] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
+ g_memory_resource_limits[i][1] -= ATMOSPHERE_EXTRA_SYSTEM_MEMORY_FOR_SYSMODULES;
}
/* Set resource limits. */
diff --git a/stratosphere/pm/source/smm_ams.c b/stratosphere/pm/source/smm_ams.c
new file mode 100644
index 000000000..4437ba949
--- /dev/null
+++ b/stratosphere/pm/source/smm_ams.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 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 .
+ */
+
+#include
+#include
+#include "smm_ams.h"
+
+static Service g_smManagerAmsSrv;
+static u64 g_smManagerAmsRefcnt;
+
+Result smManagerAmsInitialize(void) {
+ atomicIncrement64(&g_smManagerAmsRefcnt);
+
+ if (serviceIsActive(&g_smManagerAmsSrv))
+ return 0;
+
+ return smGetService(&g_smManagerAmsSrv, "sm:m");
+}
+
+void smManagerAmsExit(void) {
+ if (atomicDecrement64(&g_smManagerAmsRefcnt) == 0)
+ serviceClose(&g_smManagerAmsSrv);
+}
+
+Result smManagerAmsEndInitialDefers(void) {
+ IpcCommand c;
+ ipcInitialize(&c);
+
+ struct {
+ u64 magic;
+ u64 cmd_id;
+ } *raw;
+
+ raw = serviceIpcPrepareHeader(&g_smManagerAmsSrv, &c, sizeof(*raw));
+ raw->magic = SFCI_MAGIC;
+ raw->cmd_id = 65000;
+
+
+ Result rc = serviceIpcDispatch(&g_smManagerAmsSrv);
+
+ if (R_SUCCEEDED(rc)) {
+ IpcParsedCommand r;
+ struct {
+ u64 magic;
+ u64 result;
+ } *resp;
+
+ serviceIpcParse(&g_smManagerAmsSrv, &r, sizeof(*resp));
+ resp = r.Raw;
+
+ rc = resp->result;
+ }
+
+ return rc;
+
+}
\ No newline at end of file
diff --git a/stratosphere/pm/source/smm_ams.h b/stratosphere/pm/source/smm_ams.h
new file mode 100644
index 000000000..6d6dd5ed0
--- /dev/null
+++ b/stratosphere/pm/source/smm_ams.h
@@ -0,0 +1,21 @@
+/**
+ * @file smm_ams.h
+ * @brief Service manager (sm:m) IPC wrapper for Atmosphere extensions.
+ * @author SciresM
+ * @copyright libnx Authors
+ */
+#pragma once
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+Result smManagerAmsInitialize(void);
+void smManagerAmsExit(void);
+
+Result smManagerAmsEndInitialDefers(void);
+
+#ifdef __cplusplus
+}
+#endif
\ No newline at end of file
diff --git a/stratosphere/sm/Makefile b/stratosphere/sm/Makefile
index 3f6b0589d..dae1cae4a 100644
--- a/stratosphere/sm/Makefile
+++ b/stratosphere/sm/Makefile
@@ -34,7 +34,7 @@ ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
-CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_MINIMUM_SESSION_LIMIT=8
+CFLAGS += $(INCLUDE) -D__SWITCH__ -DSM_ENABLE_SMHAX -DSM_ENABLE_MITM -DSM_ENABLE_INIT_DEFERS -DSM_MINIMUM_SESSION_LIMIT=8
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
diff --git a/stratosphere/sm/source/sm_manager_service.cpp b/stratosphere/sm/source/sm_manager_service.cpp
index 04190f7ed..03e0e5d95 100644
--- a/stratosphere/sm/source/sm_manager_service.cpp
+++ b/stratosphere/sm/source/sm_manager_service.cpp
@@ -28,6 +28,9 @@ Result ManagerService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_
case Manager_Cmd_UnregisterProcess:
rc = WrapIpcCommandImpl<&ManagerService::unregister_process>(this, r, out_c, pointer_buffer, pointer_buffer_size);
break;
+ case Manager_Cmd_AtmosphereEndInitDefers:
+ rc = WrapIpcCommandImpl<&ManagerService::end_init_defers>(this, r, out_c, pointer_buffer, pointer_buffer_size);
+ break;
default:
break;
}
@@ -47,3 +50,9 @@ std::tuple ManagerService::register_process(u64 pid, InBuffer acid_s
std::tuple ManagerService::unregister_process(u64 pid) {
return {Registration::UnregisterProcess(pid)};
}
+
+std::tuple ManagerService::end_init_defers() {
+ Registration::EndInitDefers();
+ return {0};
+}
+
diff --git a/stratosphere/sm/source/sm_manager_service.hpp b/stratosphere/sm/source/sm_manager_service.hpp
index f64b26a03..fd7a98647 100644
--- a/stratosphere/sm/source/sm_manager_service.hpp
+++ b/stratosphere/sm/source/sm_manager_service.hpp
@@ -20,7 +20,10 @@
enum ManagerServiceCmd {
Manager_Cmd_RegisterProcess = 0,
- Manager_Cmd_UnregisterProcess = 1
+ Manager_Cmd_UnregisterProcess = 1,
+
+
+ Manager_Cmd_AtmosphereEndInitDefers = 65000,
};
class ManagerService final : public IServiceObject {
@@ -36,4 +39,5 @@ class ManagerService final : public IServiceObject {
/* Actual commands. */
std::tuple register_process(u64 pid, InBuffer acid_sac, InBuffer aci0_sac);
std::tuple unregister_process(u64 pid);
+ std::tuple end_init_defers();
};
diff --git a/stratosphere/sm/source/sm_registration.cpp b/stratosphere/sm/source/sm_registration.cpp
index 63def66d9..46c6d62fc 100644
--- a/stratosphere/sm/source/sm_registration.cpp
+++ b/stratosphere/sm/source/sm_registration.cpp
@@ -26,6 +26,7 @@ static std::array g_servic
static u64 g_initial_process_id_low = 0;
static u64 g_initial_process_id_high = 0;
static bool g_determined_initial_process_ids = false;
+static bool g_end_init_defers = false;
u64 GetServiceNameLength(u64 service) {
u64 service_name_len = 0;
@@ -36,6 +37,38 @@ u64 GetServiceNameLength(u64 service) {
return service_name_len;
}
+/* Atmosphere extension utilities. */
+void Registration::EndInitDefers() {
+ g_end_init_defers = true;
+}
+
+constexpr u64 EncodeNameConstant(const char *name) {
+ u64 service = 0;
+ for (unsigned int i = 0; i < sizeof(service); i++) {
+ if (name[i] == '\x00') {
+ break;
+ }
+ service |= ((u64)name[i]) << (8 * i);
+ }
+ return service;
+}
+
+bool Registration::ShouldInitDefer(u64 service) {
+ /* Only enable if compile-time generated. */
+#ifndef SM_ENABLE_INIT_DEFERS
+ return false;
+#endif
+
+ if (g_end_init_defers) {
+ return false;
+ }
+
+ /* This is a mechanism by which certain services will always be deferred until sm:m receives a special command. */
+ /* This can be extended with more services as needed at a later date. */
+ constexpr u64 FSP_SRV = EncodeNameConstant("fsp-srv");
+ return service == FSP_SRV;
+}
+
/* Utilities. */
Registration::Process *Registration::GetProcessForPid(u64 pid) {
auto process_it = std::find_if(g_process_list.begin(), g_process_list.end(), member_equals_fn(&Process::pid, pid));
@@ -188,11 +221,13 @@ bool Registration::HasService(u64 service) {
Result Registration::GetServiceHandle(u64 pid, u64 service, Handle *out) {
Registration::Service *target_service = GetService(service);
- if (target_service == NULL) {
+ if (target_service == NULL || ShouldInitDefer(service)) {
/* Note: This defers the result until later. */
return RESULT_DEFER_SESSION;
}
+ /* */
+
*out = 0;
Result rc;
if (target_service->mitm_pid == 0 || target_service->mitm_pid == pid) {
diff --git a/stratosphere/sm/source/sm_registration.hpp b/stratosphere/sm/source/sm_registration.hpp
index 630a72181..9a30652bc 100644
--- a/stratosphere/sm/source/sm_registration.hpp
+++ b/stratosphere/sm/source/sm_registration.hpp
@@ -46,6 +46,9 @@ class Registration {
};
/* Utilities. */
+ static void EndInitDefers();
+ static bool ShouldInitDefer(u64 service);
+
static Registration::Process *GetProcessForPid(u64 pid);
static Registration::Process *GetFreeProcess();
static Registration::Service *GetService(u64 service);
diff --git a/stratosphere/sm/source/sm_user_service.cpp b/stratosphere/sm/source/sm_user_service.cpp
index 0f8927ed8..00cf6f971 100644
--- a/stratosphere/sm/source/sm_user_service.cpp
+++ b/stratosphere/sm/source/sm_user_service.cpp
@@ -53,7 +53,7 @@ Result UserService::dispatch(IpcParsedCommand &r, IpcCommand &out_c, u64 cmd_id,
Result UserService::handle_deferred() {
/* If we're deferred, GetService failed. */
- return WrapDeferredIpcCommandImpl<&UserService::deferred_get_service>(this, this->deferred_service);;
+ return WrapDeferredIpcCommandImpl<&UserService::deferred_get_service>(this, this->deferred_service);
}