2018-11-10 20:38:24 +00:00
|
|
|
/*
|
2021-10-04 20:59:10 +01:00
|
|
|
* Copyright (c) Atmosphère-NX
|
2018-11-10 20:38:24 +00:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
2020-05-11 23:02:10 +01:00
|
|
|
#include <stratosphere.hpp>
|
2018-11-10 20:38:24 +00:00
|
|
|
#include "fatal_config.hpp"
|
|
|
|
|
2019-10-24 10:30:10 +01:00
|
|
|
namespace ams::fatal::srv {
|
2018-11-10 20:38:24 +00:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
namespace {
|
2018-11-10 20:38:24 +00:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
/* Global config. */
|
2021-10-08 01:44:54 +01:00
|
|
|
constinit os::SdkMutex g_config_mutex;
|
|
|
|
constinit bool g_initialized_config;
|
|
|
|
constinit util::TypedStorage<FatalConfig> g_config;
|
|
|
|
|
|
|
|
FatalConfig &GetFatalConfigImpl() {
|
|
|
|
if (AMS_UNLIKELY(!g_initialized_config)) {
|
|
|
|
std::scoped_lock lk(g_config_mutex);
|
|
|
|
|
|
|
|
if (AMS_LIKELY(!g_initialized_config)) {
|
|
|
|
util::ConstructAt(g_config);
|
|
|
|
|
|
|
|
g_initialized_config = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return util::GetReference(g_config);
|
|
|
|
}
|
|
|
|
|
2018-11-10 20:38:24 +00:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
/* Event creator. */
|
2021-10-05 01:12:32 +01:00
|
|
|
os::NativeHandle GetFatalDirtyEventReadableHandle() {
|
2019-07-19 03:09:35 +01:00
|
|
|
Event evt;
|
2020-03-18 07:14:26 +00:00
|
|
|
R_ABORT_UNLESS(setsysAcquireFatalDirtyFlagEventHandle(&evt));
|
2019-09-28 02:04:58 +01:00
|
|
|
return evt.revent;
|
2018-11-10 20:38:24 +00:00
|
|
|
}
|
2019-06-18 00:41:03 +01:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
/* Global event. */
|
2021-10-08 01:44:54 +01:00
|
|
|
constinit os::SystemEventType g_fatal_dirty_event;
|
|
|
|
constinit os::MultiWaitHolderType g_fatal_dirty_multi_wait_holder;
|
|
|
|
constinit bool g_initialized_fatal_dirty_event;
|
2019-09-28 02:04:58 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-10-01 03:00:47 +01:00
|
|
|
os::MultiWaitHolderType *GetFatalDirtyMultiWaitHolder() {
|
2021-10-08 01:44:54 +01:00
|
|
|
if (AMS_UNLIKELY(!g_initialized_fatal_dirty_event)) {
|
2020-04-08 10:21:35 +01:00
|
|
|
os::AttachReadableHandleToSystemEvent(std::addressof(g_fatal_dirty_event), GetFatalDirtyEventReadableHandle(), true, os::EventClearMode_ManualClear);
|
2021-10-01 03:00:47 +01:00
|
|
|
os::InitializeMultiWaitHolder(std::addressof(g_fatal_dirty_multi_wait_holder), std::addressof(g_fatal_dirty_event));
|
|
|
|
os::SetMultiWaitHolderUserData(std::addressof(g_fatal_dirty_multi_wait_holder), reinterpret_cast<uintptr_t>(std::addressof(g_fatal_dirty_multi_wait_holder)));
|
2021-10-08 01:44:54 +01:00
|
|
|
g_initialized_fatal_dirty_event = true;
|
2020-04-08 10:21:35 +01:00
|
|
|
}
|
2021-10-01 03:00:47 +01:00
|
|
|
return std::addressof(g_fatal_dirty_multi_wait_holder);
|
2019-09-28 02:04:58 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void OnFatalDirtyEvent() {
|
2020-04-08 10:21:35 +01:00
|
|
|
os::ClearSystemEvent(std::addressof(g_fatal_dirty_event));
|
2019-09-28 02:04:58 +01:00
|
|
|
|
|
|
|
u64 flags_0, flags_1;
|
|
|
|
if (R_SUCCEEDED(setsysGetFatalDirtyFlags(&flags_0, &flags_1)) && (flags_0 & 1)) {
|
2021-10-08 01:44:54 +01:00
|
|
|
GetFatalConfigImpl().UpdateLanguageCode();
|
2019-09-28 02:04:58 +01:00
|
|
|
}
|
2018-11-14 01:53:26 +00:00
|
|
|
}
|
2019-06-18 00:41:03 +01:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
FatalConfig::FatalConfig() {
|
|
|
|
/* Get information from set. */
|
2020-04-14 01:07:37 +01:00
|
|
|
settings::system::GetSerialNumber(std::addressof(this->serial_number));
|
|
|
|
settings::system::GetFirmwareVersion(std::addressof(this->firmware_version));
|
2019-10-18 18:37:03 +01:00
|
|
|
setsysGetQuestFlag(&this->quest_flag);
|
2019-07-19 03:09:35 +01:00
|
|
|
this->UpdateLanguageCode();
|
2019-06-18 00:41:03 +01:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
/* Read information from settings. */
|
2019-11-27 04:58:39 +00:00
|
|
|
settings::fwdbg::GetSettingsItemValue(&this->transition_to_fatal, sizeof(this->transition_to_fatal), "fatal", "transition_to_fatal");
|
|
|
|
settings::fwdbg::GetSettingsItemValue(&this->show_extra_info, sizeof(this->show_extra_info), "fatal", "show_extra_info");
|
2020-08-04 03:52:53 +01:00
|
|
|
|
|
|
|
u64 quest_interval_second;
|
|
|
|
settings::fwdbg::GetSettingsItemValue(&quest_interval_second, sizeof(quest_interval_second), "fatal", "quest_reboot_interval_second");
|
|
|
|
this->quest_reboot_interval = TimeSpan::FromSeconds(quest_interval_second);
|
2019-06-18 00:41:03 +01:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
/* Atmosphere extension for automatic reboot. */
|
2020-08-04 03:52:53 +01:00
|
|
|
u64 auto_reboot_ms;
|
|
|
|
if (settings::fwdbg::GetSettingsItemValue(&auto_reboot_ms, sizeof(auto_reboot_ms), "atmosphere", "fatal_auto_reboot_interval") == sizeof(auto_reboot_ms)) {
|
|
|
|
this->fatal_auto_reboot_interval = TimeSpan::FromMilliSeconds(auto_reboot_ms);
|
|
|
|
this->fatal_auto_reboot_enabled = auto_reboot_ms != 0;
|
2019-07-19 03:09:35 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup messages. */
|
|
|
|
{
|
2020-05-11 23:02:10 +01:00
|
|
|
this->error_msg = "Error Code: 2%03d-%04d (0x%x)\n";
|
2019-07-19 03:09:35 +01:00
|
|
|
|
2020-11-25 14:29:09 +00:00
|
|
|
this->error_desc = "An error has occurred.\n\n"
|
2020-05-11 23:02:10 +01:00
|
|
|
"Please press the POWER Button to restart the console normally, or a VOL button\n"
|
|
|
|
"to reboot to a payload (or RCM, if none is present). If you are unable to\n"
|
|
|
|
"restart the console, hold the POWER Button for 12 seconds to turn the console off.\n\n"
|
|
|
|
"If the problem persists, refer to the Nintendo Support Website.\n"
|
|
|
|
"support.nintendo.com/switch/error\n";
|
2019-07-19 03:09:35 +01:00
|
|
|
|
|
|
|
/* If you're running Atmosphere on a quest unit for some reason, talk to me on discord. */
|
2020-05-11 23:02:10 +01:00
|
|
|
this->quest_desc = "Please call 1-800-875-1852 for service.\n\n"
|
|
|
|
"Also, please be aware that running Atmosphere on a Quest device is not fully\n"
|
|
|
|
"supported. Perhaps try booting your device without Atmosphere before calling\n"
|
|
|
|
"an official Nintendo service hotline. If you encounter further issues, please\n"
|
|
|
|
"contact SciresM#0524 on Discord, or via some other means.\n";
|
2019-07-19 03:09:35 +01:00
|
|
|
|
|
|
|
/* TODO: Try to load dynamically? */
|
|
|
|
/* FsStorage message_storage; */
|
|
|
|
/* TODO: if (R_SUCCEEDED(fsOpenDataStorageByDataId(0x010000000000081D, "fatal_msg"))) { ... } */
|
|
|
|
}
|
|
|
|
}
|
2019-06-18 00:41:03 +01:00
|
|
|
|
2019-07-19 03:09:35 +01:00
|
|
|
const FatalConfig &GetFatalConfig() {
|
2021-10-08 01:44:54 +01:00
|
|
|
return GetFatalConfigImpl();
|
2019-07-19 03:09:35 +01:00
|
|
|
}
|
2019-04-22 08:18:01 +01:00
|
|
|
|
2018-11-10 20:38:24 +00:00
|
|
|
}
|