/* * 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 #include #include "boot_power_utils.hpp" #include "fusee-primary_bin.h" namespace sts::boot { namespace { /* Convenience definitions. */ constexpr uintptr_t IramBase = 0x40000000ull; constexpr uintptr_t IramPayloadBase = 0x40010000ull; constexpr size_t IramSize = 0x40000; constexpr size_t IramPayloadMaxSize = 0x2E000; /* Globals. */ u8 __attribute__ ((aligned (0x1000))) g_work_page[0x1000]; /* Helpers. */ void ClearIram() { /* Make page FFs. */ std::memset(g_work_page, 0xFF, sizeof(g_work_page)); /* Overwrite all of IRAM with FFs. */ for (size_t ofs = 0; ofs < IramSize; ofs += sizeof(g_work_page)) { ams::CopyToIram(IramBase + ofs, g_work_page, sizeof(g_work_page)); } } void DoRebootToPayload(ams::FatalErrorContext *ctx) { /* Ensure clean IRAM state. */ ClearIram(); /* Copy in payload. */ for (size_t ofs = 0; ofs < fusee_primary_bin_size; ofs += 0x1000) { std::memcpy(g_work_page, &fusee_primary_bin[ofs], std::min(static_cast(fusee_primary_bin_size - ofs), size_t(0x1000))); ams::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)); ams::CopyToIram(IramPayloadBase + IramPayloadMaxSize, g_work_page, sizeof(g_work_page)); } ams::ForceRebootToIramPayload(); } } void RebootSystem() { DoRebootToPayload(nullptr); } void RebootForFatalError(ams::FatalErrorContext *ctx) { DoRebootToPayload(ctx); } }