/* * 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 #include "bpcmitm_reboot_manager.hpp" #include "../utils.hpp" /* TODO: Find a way to pre-populate this with the contents of fusee-primary. */ static u8 g_reboot_payload[IRAM_PAYLOAD_MAX_SIZE] __attribute__ ((aligned (0x1000))); static u8 g_work_page[0x1000] __attribute__ ((aligned (0x1000))); static bool g_payload_loaded = false; static BpcRebootType g_reboot_type = BpcRebootType::ToPayload; void BpcRebootManager::Initialize() { /* Open payload file. */ FsFile payload_file; if (R_FAILED(Utils::OpenSdFile("/atmosphere/reboot_payload.bin", FS_OPEN_READ, &payload_file))) { return; } ON_SCOPE_EXIT { fsFileClose(&payload_file); }; /* Clear payload buffer */ std::memset(g_reboot_payload, 0xFF, sizeof(g_reboot_payload)); /* Read payload file. */ size_t actual_size; fsFileRead(&payload_file, 0, g_reboot_payload, IRAM_PAYLOAD_MAX_SIZE, &actual_size); g_payload_loaded = true; /* TODO: Figure out what kind of reboot we're gonna be doing. */ } static void ClearIram() { /* Make page FFs. */ memset(g_work_page, 0xFF, sizeof(g_work_page)); /* Overwrite all of IRAM with FFs. */ for (size_t ofs = 0; ofs < IRAM_PAYLOAD_MAX_SIZE; ofs += sizeof(g_work_page)) { CopyToIram(IRAM_PAYLOAD_BASE + ofs, g_work_page, sizeof(g_work_page)); } } static void DoRebootToPayload() { /* If we don't actually have a payload loaded, just go to RCM. */ if (!g_payload_loaded) { RebootToRcm(); } /* Ensure clean IRAM state. */ ClearIram(); /* Copy in payload. */ for (size_t ofs = 0; ofs < sizeof(g_reboot_payload); ofs += 0x1000) { CopyToIram(IRAM_PAYLOAD_BASE + ofs, &g_reboot_payload[ofs], 0x1000); } RebootToIramPayload(); } Result BpcRebootManager::PerformReboot() { switch (g_reboot_type) { case BpcRebootType::Standard: return RESULT_FORWARD_TO_SESSION; case BpcRebootType::ToRcm: RebootToRcm(); return 0; case BpcRebootType::ToPayload: default: DoRebootToPayload(); return 0; } }