From e0a41e9d3386d2197baf3b8758b0dc44621676ee Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Wed, 1 Sep 2021 14:05:39 -0700 Subject: [PATCH] fusee_cpp: implement exosphere load/configuration --- fusee_cpp/program/source/fusee_display.cpp | 4 + fusee_cpp/program/source/fusee_display.hpp | 2 + fusee_cpp/program/source/fusee_ini.cpp | 28 ++- .../program/source/fusee_secmon_sync.cpp | 4 + .../program/source/fusee_secmon_sync.hpp | 2 + .../source/fusee_secondary_archive.hpp | 4 +- .../program/source/fusee_setup_horizon.cpp | 201 +++++++++++++++++- fusee_cpp/program/split_bin.py | 4 +- 8 files changed, 236 insertions(+), 13 deletions(-) diff --git a/fusee_cpp/program/source/fusee_display.cpp b/fusee_cpp/program/source/fusee_display.cpp index 4a28eadd5..ad01aacb9 100644 --- a/fusee_cpp/program/source/fusee_display.cpp +++ b/fusee_cpp/program/source/fusee_display.cpp @@ -582,6 +582,10 @@ namespace ams::nxboot { } } + u16 GetDisplayLcdVendor() { + return g_lcd_vendor; + } + void ShowFatalError(const ams::impl::FatalErrorContext *f_ctx, const Result save_result) { /* If needed, initialize the display. */ if (!IsDisplayInitialized()) { diff --git a/fusee_cpp/program/source/fusee_display.hpp b/fusee_cpp/program/source/fusee_display.hpp index b3a9b68d4..f485af2b5 100644 --- a/fusee_cpp/program/source/fusee_display.hpp +++ b/fusee_cpp/program/source/fusee_display.hpp @@ -26,6 +26,8 @@ namespace ams::nxboot { void InitializeDisplay(); void FinalizeDisplay(); + u16 GetDisplayLcdVendor(); + void ShowDisplay(); } diff --git a/fusee_cpp/program/source/fusee_ini.cpp b/fusee_cpp/program/source/fusee_ini.cpp index 8bcc340b0..8cf6088ae 100644 --- a/fusee_cpp/program/source/fusee_ini.cpp +++ b/fusee_cpp/program/source/fusee_ini.cpp @@ -49,7 +49,7 @@ namespace ams::nxboot { file_size = std::min(IniFileSizeMax, file_size); /* Allocate memory for file. */ - char *buffer = static_cast(AllocateMemory(util::AlignUp(file_size + 1, 0x10))); + char *buffer = static_cast(AllocateAligned(util::AlignUp(file_size + 1, 0x10), 0x10)); buffer[file_size] = '\x00'; /* Read file. */ @@ -64,6 +64,7 @@ namespace ams::nxboot { SectionName, Key, KvSpace, + KvSpace2, Value, TrailingSpace, }; @@ -120,20 +121,33 @@ namespace ams::nxboot { } else if (c == '=') { buffer[i] = '\x00'; - val_start = buffer + i + 1; - - state = State::Value; + state = State::KvSpace2; } break; case State::KvSpace: if (c == '=') { - val_start = buffer + i + 1; - - state = State::Value; + state = State::KvSpace2; } else if (!IsWhiteSpace(c)) { return ParseIniResult_InvalidFormat; } break; + case State::KvSpace2: + if (c == '\n') { + buffer[i] = '\x00'; + + auto *entry = AllocateObject(); + entry->key = key_start; + entry->value = buffer + i; + + cur_sec->kv_list.push_back(*entry); + + state = State::Newline; + } else if (!IsWhiteSpace(c)) { + val_start = buffer + i; + + state = State::Value; + } + break; case State::Value: if (IsWhiteSpace(c) || c == '\n') { buffer[i] = '\x00'; diff --git a/fusee_cpp/program/source/fusee_secmon_sync.cpp b/fusee_cpp/program/source/fusee_secmon_sync.cpp index d0a8d0219..034abb10e 100644 --- a/fusee_cpp/program/source/fusee_secmon_sync.cpp +++ b/fusee_cpp/program/source/fusee_secmon_sync.cpp @@ -26,6 +26,10 @@ namespace ams::nxboot { } + void InitializeSecureMonitorMailbox() { + std::memset(std::addressof(GetSecureMonitorParameters()), 0, sizeof(GetSecureMonitorParameters())); + } + void WaitSecureMonitorState(pkg1::SecureMonitorState state) { auto &secmon_params = GetSecureMonitorParameters(); diff --git a/fusee_cpp/program/source/fusee_secmon_sync.hpp b/fusee_cpp/program/source/fusee_secmon_sync.hpp index 570e0ee39..82635e781 100644 --- a/fusee_cpp/program/source/fusee_secmon_sync.hpp +++ b/fusee_cpp/program/source/fusee_secmon_sync.hpp @@ -18,6 +18,8 @@ namespace ams::nxboot { + void InitializeSecureMonitorMailbox(); + void WaitSecureMonitorState(pkg1::SecureMonitorState state); void SetBootloaderState(pkg1::BootloaderState state); diff --git a/fusee_cpp/program/source/fusee_secondary_archive.hpp b/fusee_cpp/program/source/fusee_secondary_archive.hpp index 22efbe341..2dcb9cd7c 100644 --- a/fusee_cpp/program/source/fusee_secondary_archive.hpp +++ b/fusee_cpp/program/source/fusee_secondary_archive.hpp @@ -70,8 +70,8 @@ namespace ams::nxboot { u8 mariko_fatal[0x1C000]; /* 0x004000-0x020000 */ u8 ovl_mtc_erista[0x14000]; /* 0x020000-0x034000 */ u8 ovl_mtc_mariko[0x14000]; /* 0x034000-0x048000 */ - u8 exosphere[0x10000]; /* 0x048000-0x058000 */ - u8 mesosphere[0xA8000]; /* 0x058000-0x100000 */ + u8 exosphere[0xE000]; /* 0x048000-0x056000 */ + u8 mesosphere[0xAA000]; /* 0x056000-0x100000 */ u8 kips[3_MB]; /* 0x100000-0x400000 */ u8 splash_screen_fb[FrameBufferSize]; /* 0x400000-0x7C0000 */ }; diff --git a/fusee_cpp/program/source/fusee_setup_horizon.cpp b/fusee_cpp/program/source/fusee_setup_horizon.cpp index a1b216e8e..621cec3fb 100644 --- a/fusee_cpp/program/source/fusee_setup_horizon.cpp +++ b/fusee_cpp/program/source/fusee_setup_horizon.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include +#include #include "fusee_key_derivation.hpp" #include "fusee_secondary_archive.hpp" #include "fusee_setup_horizon.hpp" @@ -91,6 +92,23 @@ namespace ams::nxboot { } } + u32 ParseDecimalInteger(const char *s) { + u32 x = 0; + while (true) { + const char c = *(s++); + + if (c == '\x00') { + return x; + } else { + x *= 10; + + if ('0' <= c && c <= '9') { + x += c - '0'; + } + } + } + } + bool IsDirectoryExist(const char *path) { fs::DirectoryEntryType entry_type; bool archive; @@ -505,7 +523,7 @@ namespace ams::nxboot { /* Allocate memory. */ warmboot_src_size = static_cast(size); - void *tmp = AllocateMemory(warmboot_src_size); + void *tmp = AllocateAligned(warmboot_src_size, 0x10); /* Read the file. */ if (R_FAILED(fs::ReadFile(file, 0, tmp, warmboot_src_size))) { @@ -542,6 +560,184 @@ namespace ams::nxboot { } } + void ConfigureExosphere(fuse::SocType soc_type, ams::TargetFirmware target_firmware, bool emummc_enabled) { + /* Get monitor configuration. */ + auto &storage_ctx = *secmon::MemoryRegionPhysicalDramMonitorConfiguration.GetPointer(); + std::memset(std::addressof(storage_ctx), 0, sizeof(storage_ctx)); + + /* Set magic. */ + storage_ctx.magic = secmon::SecureMonitorStorageConfiguration::Magic; + + /* Set some defaults. */ + storage_ctx.target_firmware = target_firmware; + storage_ctx.lcd_vendor = GetDisplayLcdVendor(); + storage_ctx.emummc_cfg = g_emummc_cfg; + storage_ctx.flags[0] = secmon::SecureMonitorConfigurationFlag_Default; + storage_ctx.flags[1] = secmon::SecureMonitorConfigurationFlag_None; + storage_ctx.log_port = uart::Port_ReservedDebug; + storage_ctx.log_baud_rate = 115200; + + /* Parse fields from exosphere.ini */ + { + IniSectionList sections; + if (ParseIniSafe(sections, "sdmc:/exosphere.ini")) { + for (const auto §ion : sections) { + /* We only care about the [exosphere] section. */ + if (std::strcmp(section.name, "exosphere")) { + continue; + } + + /* Handle individual fields. */ + for (const auto &entry : section.kv_list) { + if (std::strcmp(entry.key, "debugmode") == 0) { + if (entry.value[0] == '1') { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForKernel; + } + } else if (std::strcmp(entry.key, "debugmode_user") == 0) { + if (entry.value[0] == '1') { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_IsDevelopmentFunctionEnabledForUser; + } + } else if (std::strcmp(entry.key, "disable_user_exception_handlers") == 0) { + if (entry.value[0] == '1') { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_DisableUserModeExceptionHandlers; + } + } else if (std::strcmp(entry.key, "enable_user_pmu_access") == 0) { + if (entry.value[0] == '1') { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_EnableUserModePerformanceCounterAccess; + } + } else if (std::strcmp(entry.key, "blank_prodinfo_sysmmc") == 0) { + if (entry.value[0] == '1' && !emummc_enabled) { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; + } + } else if (std::strcmp(entry.key, "blank_prodinfo_emummc") == 0) { + if (entry.value[0] == '1' && emummc_enabled) { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_ShouldUseBlankCalibrationBinary; + } + } else if (std::strcmp(entry.key, "allow_writing_to_cal_sysmmc") == 0) { + if (entry.value[0] == '1') { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc; + } else { + storage_ctx.flags[0] &= ~secmon::SecureMonitorConfigurationFlag_AllowWritingToCalibrationBinarySysmmc; + } + } else if (std::strcmp(entry.key, "log_port") == 0) { + const u32 log_port = ParseDecimalInteger(entry.value); + if (0 <= log_port && log_port < 4) { + storage_ctx.log_port = log_port; + } + } else if (std::strcmp(entry.key, "log_baud_rate") == 0) { + storage_ctx.log_baud_rate = ParseDecimalInteger(entry.value); + } else if (std::strcmp(entry.key, "log_inverted") == 0) { + if (entry.value[0] == 1) { + storage_ctx.log_flags |= uart::Flag_Inverted; + } + } + } + } + } + } + + /* Parse usb setting from system_settings.ini */ + { + IniSectionList sections; + if (ParseIniSafe(sections, "sdmc:/atmosphere/config/system_settings.ini")) { + for (const auto §ion : sections) { + /* We only care about the [usb] section. */ + if (std::strcmp(section.name, "usb")) { + continue; + } + + /* Handle individual fields. */ + for (const auto &entry : section.kv_list) { + if (std::strcmp(entry.key, "usb30_force_enabled") == 0) { + if (std::strcmp(entry.value, "u8!0x1") == 0) { + storage_ctx.flags[0] |= secmon::SecureMonitorConfigurationFlag_ForceEnableUsb30; + } + } + } + } + } + } + + /* Copy exosphere. */ + void *exosphere_dst = reinterpret_cast(0x40030000); + bool use_sd_exo = false; + { + /* Try to use an sd card file, if present. */ + fs::FileHandle exo_file; + if (R_SUCCEEDED(fs::OpenFile(std::addressof(exo_file), "sdmc:/atmosphere/exosphere.bin", fs::OpenMode_Read))) { + ON_SCOPE_EXIT { fs::CloseFile(exo_file); }; + + /* Note that we're using sd_exo. */ + use_sd_exo = true; + + Result result; + + /* Get the size. */ + s64 size; + if (R_FAILED((result = fs::GetFileSize(std::addressof(size), exo_file))) || size > sizeof(GetSecondaryArchive().exosphere)) { + ShowFatalError("Invalid SD exosphere size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast(size)); + } + + /* Read the file. */ + if (R_FAILED((result = fs::ReadFile(exo_file, 0, exosphere_dst, size)))) { + ShowFatalError("Failed to read SD exosphere: 0x%08" PRIx32 "!\n", result.GetValue()); + } + } + } + + if (!use_sd_exo) { + std::memcpy(exosphere_dst, GetSecondaryArchive().exosphere, sizeof(GetSecondaryArchive().exosphere)); + } + + /* Copy mariko fatal. */ + if (soc_type == fuse::SocType_Mariko) { + u8 *mariko_fatal_dst = secmon::MemoryRegionPhysicalMarikoProgramImage.GetPointer(); + bool use_sd_mariko_fatal = false; + { + /* Try to use an sd card file, if present. */ + fs::FileHandle mariko_program_file; + if (R_SUCCEEDED(fs::OpenFile(std::addressof(mariko_program_file), "sdmc:/atmosphere/mariko_fatal.bin", fs::OpenMode_Read))) { + ON_SCOPE_EXIT { fs::CloseFile(mariko_program_file); }; + + /* Note that we're using sd_exo. */ + use_sd_exo = true; + + Result result; + + /* Get the size. */ + s64 size; + if (R_FAILED((result = fs::GetFileSize(std::addressof(size), mariko_program_file))) || size > sizeof(GetSecondaryArchive().mariko_fatal)) { + ShowFatalError("Invalid SD exosphere size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast(size)); + } + + /* Read the file. */ + if (R_FAILED((result = fs::ReadFile(mariko_program_file, 0, mariko_fatal_dst, size)))) { + ShowFatalError("Failed to read SD exosphere: 0x%08" PRIx32 "!\n", result.GetValue()); + } + + /* Clear the remainder. */ + std::memset(mariko_fatal_dst + size, 0, sizeof(GetSecondaryArchive().mariko_fatal) - size); + } + } + + if (!use_sd_mariko_fatal) { + std::memcpy(mariko_fatal_dst, GetSecondaryArchive().mariko_fatal, sizeof(GetSecondaryArchive().mariko_fatal)); + } + } + } + } void SetupAndStartHorizon() { @@ -571,7 +767,8 @@ namespace ams::nxboot { /* Setup warmboot firmware. */ LoadWarmbootFirmware(soc_type, target_firmware, package1); - /* TODO: Setup exosphere. */ + /* Setup exosphere. */ + ConfigureExosphere(soc_type, target_firmware, emummc_enabled); /* TODO: Start CPU. */ /* NOTE: Security Engine unusable past this point. */ diff --git a/fusee_cpp/program/split_bin.py b/fusee_cpp/program/split_bin.py index e328cd548..b50247c27 100644 --- a/fusee_cpp/program/split_bin.py +++ b/fusee_cpp/program/split_bin.py @@ -47,9 +47,9 @@ def main(argc, argv): # Write Mariko MTC f.write(get_overlay(data, 2)) # TODO: Write exosphere - f.write('\xCC'*0x10000) + f.write('\xCC'*0xE000) # TODO: Write mesosphere - f.write('\xCC'*0xA8000) + f.write('\xCC'*0xAA000) # TODO: Write kips f.write('\xCC'*0x300000) # Write Splash Screen