diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp
new file mode 100644
index 000000000..70e924897
--- /dev/null
+++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018-2019 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 "amsmitm_initialization.hpp"
+#include "amsmitm_fs_utils.hpp"
+
+namespace ams::mitm::fs {
+
+ namespace {
+
+ /* Globals. */
+ FsFileSystem g_sd_filesystem;
+
+ /* Helpers. */
+ Result EnsureSdInitialized() {
+ R_UNLESS(mitm::IsInitialized(), ams::fs::ResultSdCardNotPresent());
+ return ResultSuccess();
+ }
+
+ void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, const char *src_path) {
+ if (src_path[0] == '/') {
+ std::snprintf(dst_path, dst_path_size, "/atmosphere%s", src_path);
+ } else {
+ std::snprintf(dst_path, dst_path_size, "/atmosphere/%s", src_path);
+ }
+ }
+
+ void FormatAtmosphereSdPath(char *dst_path, size_t dst_path_size, ncm::ProgramId program_id, const char *src_path) {
+ if (src_path[0] == '/') {
+ std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx%s", static_cast(program_id), src_path);
+ } else {
+ std::snprintf(dst_path, dst_path_size, "/atmosphere/contents/%016lx/%s", static_cast(program_id), src_path);
+ }
+ }
+
+ }
+
+ void OpenGlobalSdCardFileSystem() {
+ R_ASSERT(fsOpenSdCardFileSystem(&g_sd_filesystem));
+ }
+
+ Result OpenSdFile(FsFile *out, const char *path, u32 mode) {
+ R_TRY(EnsureSdInitialized());
+ return fsFsOpenFile(&g_sd_filesystem, path, mode, out);
+ }
+
+ Result OpenAtmosphereSdFile(FsFile *out, const char *path, u32 mode) {
+ char fixed_path[FS_MAX_PATH];
+ FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), path);
+ return OpenSdFile(out, fixed_path, mode);
+ }
+
+ Result OpenAtmosphereSdFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode) {
+ char fixed_path[FS_MAX_PATH];
+ FormatAtmosphereSdPath(fixed_path, sizeof(fixed_path), program_id, path);
+ return OpenSdFile(out, fixed_path, mode);
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp
new file mode 100644
index 000000000..17e972daf
--- /dev/null
+++ b/stratosphere/ams_mitm/source/amsmitm_fs_utils.hpp
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018-2019 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 .
+ */
+#pragma once
+#include
+
+namespace ams::mitm::fs {
+
+ /* Initialization. */
+ void OpenGlobalSdCardFileSystem();
+
+ /* Utilities. */
+ Result OpenSdFile(FsFile *out, const char *path, u32 mode);
+ Result OpenAtmosphereSdFile(FsFile *out, const char *path, u32 mode);
+ Result OpenAtmosphereSdFile(FsFile *out, ncm::ProgramId program_id, const char *path, u32 mode);
+
+}
diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.cpp b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp
new file mode 100644
index 000000000..1537e81bb
--- /dev/null
+++ b/stratosphere/ams_mitm/source/amsmitm_initialization.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018-2019 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 "amsmitm_initialization.hpp"
+#include "amsmitm_fs_utils.hpp"
+
+namespace ams::mitm {
+
+ namespace {
+
+ void InitializeThreadFunc(void *arg);
+
+ constexpr size_t InitializeThreadStackSize = 0x4000;
+ constexpr int InitializeThreadPriority = 0x15;
+ os::StaticThread g_initialize_thread(&InitializeThreadFunc, nullptr, InitializeThreadPriority);
+
+ /* Globals. */
+ os::Event g_init_event(false);
+
+ /* Initialization implementation */
+ void InitializeThreadFunc(void *arg) {
+ /* Wait for the SD card to be ready. */
+ cfg::WaitSdCardInitialized();
+
+ /* TODO: Other initialization tasks. */
+
+ /* Open global SD card file system, so that other threads can begin using the SD. */
+ mitm::fs::OpenGlobalSdCardFileSystem();
+
+ /* Signal to waiters that we are ready. */
+ g_init_event.Signal();
+ }
+
+ }
+
+ void StartInitialize() {
+ R_ASSERT(g_initialize_thread.Start());
+ }
+
+ bool IsInitialized() {
+ return g_init_event.TryWait();
+ }
+
+ void WaitInitialized() {
+ g_init_event.Wait();
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/amsmitm_initialization.hpp b/stratosphere/ams_mitm/source/amsmitm_initialization.hpp
new file mode 100644
index 000000000..9af84b3c9
--- /dev/null
+++ b/stratosphere/ams_mitm/source/amsmitm_initialization.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019 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 .
+ */
+#pragma once
+#include
+
+namespace ams::mitm {
+
+ void StartInitialize();
+ bool IsInitialized();
+ void WaitInitialized();
+
+}
diff --git a/stratosphere/ams_mitm/source/amsmitm_main.cpp b/stratosphere/ams_mitm/source/amsmitm_main.cpp
index ff8635b3b..505e5346c 100644
--- a/stratosphere/ams_mitm/source/amsmitm_main.cpp
+++ b/stratosphere/ams_mitm/source/amsmitm_main.cpp
@@ -13,6 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+#include "amsmitm_initialization.hpp"
#include "amsmitm_module_management.hpp"
extern "C" {
@@ -95,6 +96,9 @@ void __appExit(void) {
}
int main(int argc, char **argv) {
+ /* Start initialization (sd card init, automatic backups, etc) */
+ mitm::StartInitialize();
+
/* Launch all mitm modules in sequence. */
mitm::LaunchAllModules();
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.cpp
new file mode 100644
index 000000000..46ce4ff99
--- /dev/null
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018-2019 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 "bpc_ams_power_utils.hpp"
+#include "../amsmitm_fs_utils.hpp"
+
+namespace ams::mitm::bpc {
+
+ namespace {
+
+ /* Convenience definitions. */
+ constexpr uintptr_t IramBase = 0x40000000ull;
+ constexpr uintptr_t IramPayloadBase = 0x40010000ull;
+ constexpr size_t IramSize = 0x40000;
+ constexpr size_t IramPayloadMaxSize = 0x2E000;
+
+ /* Helper enum. */
+ enum class RebootType : u32 {
+ Standard,
+ ToRcm,
+ ToPayload,
+ };
+
+ /* Globals. */
+ alignas(0x1000) u8 g_work_page[0x1000];
+ alignas(0x1000) u8 g_reboot_payload[IramPayloadMaxSize];
+ RebootType g_reboot_type = RebootType::ToRcm;
+
+ /* Helpers. */
+ void ClearIram() {
+ /* Make page CCs. */
+ std::memset(g_work_page, 0xCC, sizeof(g_work_page));
+
+ /* Overwrite all of IRAM with CCs. */
+ for (size_t ofs = 0; ofs < IramSize; ofs += sizeof(g_work_page)) {
+ exosphere::CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page));
+ }
+ }
+
+ void DoRebootToPayload(const ams::FatalErrorContext *ctx) {
+ /* Ensure clean IRAM state. */
+ ClearIram();
+
+ /* Copy in payload. */
+ for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) {
+ std::memcpy(g_work_page, &g_reboot_payload[ofs], std::min(sizeof(g_reboot_payload) - ofs, size_t(0x1000)));
+ exosphere::CopyToIram(IramPayloadBase + ofs, g_work_page, 0x1000);
+ }
+
+ /* Copy in fatal error context, if relevant. */
+ if (ctx != nullptr) {
+ std::memset(g_work_page, 0xCC, sizeof(g_work_page));
+ std::memcpy(g_work_page, ctx, sizeof(*ctx));
+ exosphere::CopyToIram(IramPayloadBase + IramPayloadMaxSize, g_work_page, sizeof(g_work_page));
+ }
+
+ exosphere::ForceRebootToIramPayload();
+ }
+
+ }
+
+ /* Power utilities. */
+ bool IsRebootManaged() {
+ return g_reboot_type != RebootType::Standard;
+ }
+
+ void RebootSystem() {
+ switch (g_reboot_type) {
+ case RebootType::ToRcm:
+ exosphere::ForceRebootToRcm();
+ break;
+ case RebootType::ToPayload:
+ default: /* This should never be called with ::Standard */
+ DoRebootToPayload(nullptr);
+ break;
+ }
+ }
+
+ void ShutdownSystem() {
+ exosphere::ForceShutdown();
+ }
+
+ /* Atmosphere power utilities. */
+ void RebootForFatalError(const ams::FatalErrorContext *ctx) {
+ DoRebootToPayload(ctx);
+ }
+
+ Result LoadRebootPayload() {
+ /* Clear payload buffer */
+ std::memset(g_reboot_payload, 0xCC, sizeof(g_reboot_payload));
+
+ /* Open payload file. */
+ FsFile payload_file;
+ R_TRY(fs::OpenAtmosphereSdFile(&payload_file, "/reboot_payload.bin", FsOpenMode_Read));
+ ON_SCOPE_EXIT { fsFileClose(&payload_file); };
+
+ /* Read payload file. Discard result. */
+ {
+ size_t actual_size;
+ fsFileRead(&payload_file, 0, g_reboot_payload, sizeof(g_reboot_payload), FsReadOption_None, &actual_size);
+ }
+
+ /* TODO: Parse reboot type from settings. */
+ g_reboot_type = RebootType::ToPayload;
+
+ return ResultSuccess();
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.hpp
new file mode 100644
index 000000000..841678ab6
--- /dev/null
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_power_utils.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2018-2019 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 .
+ */
+#pragma once
+#include
+
+namespace ams::mitm::bpc {
+
+ /* Power utilities. */
+ bool IsRebootManaged();
+ void RebootSystem();
+ void ShutdownSystem();
+
+ /* Atmosphere power utilities. */
+ Result LoadRebootPayload();
+ void RebootForFatalError(const ams::FatalErrorContext *ctx);
+
+}
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp
new file mode 100644
index 000000000..071186d29
--- /dev/null
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.cpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2018-2019 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 "bpc_ams_service.hpp"
+#include "bpc_ams_power_utils.hpp"
+
+namespace ams::mitm::bpc {
+
+ void AtmosphereService::RebootToFatalError(const ams::FatalErrorContext &ctx) {
+ bpc::RebootForFatalError(&ctx);
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp
new file mode 100644
index 000000000..256d9d0de
--- /dev/null
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_ams_service.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018-2019 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 .
+ */
+
+#pragma once
+#include
+
+namespace ams::mitm::bpc {
+
+ class AtmosphereService final : public sf::IServiceObject {
+ private:
+ enum class CommandId {
+ RebootToFatalError = 65000,
+ };
+ private:
+ void RebootToFatalError(const ams::FatalErrorContext &ctx);
+ public:
+ DEFINE_SERVICE_DISPATCH_TABLE {
+ MAKE_SERVICE_COMMAND_META(RebootToFatalError),
+ };
+ };
+
+}
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.cpp
new file mode 100644
index 000000000..1eb48ba6e
--- /dev/null
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018-2019 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 "bpc_mitm_service.hpp"
+#include "bpc_ams_power_utils.hpp"
+
+namespace ams::mitm::bpc {
+
+ Result BpcMitmService::RebootSystem() {
+ R_UNLESS(bpc::IsRebootManaged(), sm::mitm::ResultShouldForwardToSession());
+ bpc::RebootSystem();
+ return ResultSuccess();
+ }
+
+ Result BpcMitmService::ShutdownSystem() {
+ bpc::ShutdownSystem();
+ return ResultSuccess();
+ }
+
+}
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp
index 758e90f2d..1c4a596bc 100644
--- a/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpc_mitm_service.hpp
@@ -21,20 +21,31 @@ namespace ams::mitm::bpc {
class BpcMitmService : public sf::IMitmServiceObject {
private:
enum class CommandId {
- /* TODO */
+ ShutdownSystem = 0,
+ RebootSystem = 1,
};
public:
static bool ShouldMitm(os::ProcessId process_id, ncm::ProgramId program_id) {
- /* TODO */
- return false;
+ /* We will mitm:
+ * - am, to intercept the Reboot/Power buttons in the overlay menu.
+ * - fatal, to simplify payload reboot logic significantly
+ * - applications and hbl, to allow homebrew to take advantage of the feature.
+ */
+ return program_id == ncm::ProgramId::Am ||
+ program_id == ncm::ProgramId::Fatal ||
+ ncm::IsApplicationProgramId(program_id);
+ /* TODO: Hbl */
}
public:
SF_MITM_SERVICE_OBJECT_CTOR(BpcMitmService) { /* ... */ }
protected:
- /* TODO */
+ /* Overridden commands. */
+ Result ShutdownSystem();
+ Result RebootSystem();
public:
DEFINE_SERVICE_DISPATCH_TABLE {
- /* TODO */
+ MAKE_SERVICE_COMMAND_META(ShutdownSystem),
+ MAKE_SERVICE_COMMAND_META(RebootSystem),
};
};
diff --git a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp
index a0b6aa967..b55c0f6c9 100644
--- a/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp
+++ b/stratosphere/ams_mitm/source/bpc_mitm/bpcmitm_module.cpp
@@ -13,8 +13,11 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+#include "../amsmitm_initialization.hpp"
#include "bpcmitm_module.hpp"
#include "bpc_mitm_service.hpp"
+#include "bpc_ams_service.hpp"
+#include "bpc_ams_power_utils.hpp"
namespace ams::mitm::bpc {
@@ -24,14 +27,31 @@ namespace ams::mitm::bpc {
constexpr sm::ServiceName DeprecatedMitmServiceName = sm::ServiceName::Encode("bpc:c");
constexpr size_t MitmServiceMaxSessions = 13;
- constexpr size_t MaxServers = 1;
- constexpr size_t MaxSessions = MitmServiceMaxSessions;
+ constexpr sm::ServiceName AtmosphereServiceName = sm::ServiceName::Encode("bpc:ams");
+ constexpr size_t AtmosphereMaxSessions = 3;
+
+ constexpr size_t MaxServers = 2;
+ constexpr size_t MaxSessions = MitmServiceMaxSessions + AtmosphereMaxSessions;
using ServerOptions = sf::hipc::DefaultServerManagerOptions;
sf::hipc::ServerManager g_server_manager;
}
void MitmModule::ThreadFunction(void *arg) {
+ /* Wait until initialization is complete. */
+ mitm::WaitInitialized();
+
+ /* Initialize the reboot manager (load a payload off the SD). */
+ /* Discard result, since it doesn't need to succeed. */
+ LoadRebootPayload();
+
+ /* Create bpc:ams. */
+ {
+ Handle bpcams_h;
+ R_ASSERT(svcManageNamedPort(&bpcams_h, AtmosphereServiceName.name, AtmosphereMaxSessions));
+ g_server_manager.RegisterServer(bpcams_h);
+ }
+
/* Create bpc mitm. */
const sm::ServiceName service_name = (hos::GetVersion() >= hos::Version_200) ? MitmServiceName : DeprecatedMitmServiceName;
R_ASSERT(g_server_manager.RegisterMitmServer(service_name));