diff --git a/fusee/program/source/fatfs/diskio.c b/fusee/program/source/fatfs/diskio.c index e4c636d88..2f9411677 100644 --- a/fusee/program/source/fatfs/diskio.c +++ b/fusee/program/source/fatfs/diskio.c @@ -63,7 +63,8 @@ DRESULT disk_read ( return diskio_read_boot1(buff, count * 512, sector, count) ? RES_OK : RES_ERROR; case DRIVE_BOOT1_OFF: return diskio_read_boot1(buff, count * 512, sector + BOOT1_OFFSET_SCT_1MB, count) ? RES_OK : RES_ERROR; - + case DRIVE_EMUSD: + return diskio_read_emusd(buff, count * 512, sector, count) ? RES_OK : RES_ERROR; default: return RES_PARERR; } @@ -93,6 +94,8 @@ DRESULT disk_write ( return diskio_write_boot1(sector, count, buff, count * 512) ? RES_OK : RES_ERROR; case DRIVE_BOOT1_OFF: return diskio_write_boot1(sector + DRIVE_BOOT1_OFF, count, buff, count * 512) ? RES_OK : RES_ERROR; + case DRIVE_EMUSD: + return diskio_write_emusd(sector, count, buff, count * 512) ? RES_OK : RES_ERROR; default: return RES_PARERR; } diff --git a/fusee/program/source/fatfs/diskio.h b/fusee/program/source/fatfs/diskio.h index b127bc6ff..1f544c962 100644 --- a/fusee/program/source/fatfs/diskio.h +++ b/fusee/program/source/fatfs/diskio.h @@ -27,6 +27,7 @@ typedef enum { DRIVE_SYS, DRIVE_BOOT1, DRIVE_BOOT1_OFF, + DRIVE_EMUSD, } DDRIVE; diff --git a/fusee/program/source/fatfs/diskio_cpp.h b/fusee/program/source/fatfs/diskio_cpp.h index f29bd0a6a..8cda1236b 100644 --- a/fusee/program/source/fatfs/diskio_cpp.h +++ b/fusee/program/source/fatfs/diskio_cpp.h @@ -22,6 +22,9 @@ extern "C" { bool diskio_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count); bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void *src, size_t size); +bool diskio_read_emusd(void *dst, size_t size, size_t sector_index, size_t sector_count); +bool diskio_write_emusd(size_t sector_index, size_t sector_count, const void *src, size_t size); + bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count); bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size); diff --git a/fusee/program/source/fatfs/ffconf.h b/fusee/program/source/fatfs/ffconf.h index 81e3369ec..6db77f033 100644 --- a/fusee/program/source/fatfs/ffconf.h +++ b/fusee/program/source/fatfs/ffconf.h @@ -163,12 +163,12 @@ / Drive/Volume Configurations /---------------------------------------------------------------------------*/ -#define FF_VOLUMES 4 +#define FF_VOLUMES 5 /* Number of volumes (logical drives) to be used. (1-10) */ #define FF_STR_VOLUME_ID 1 -#define FF_VOLUME_STRS "sdmc","sys","boot1","boot1_off" +#define FF_VOLUME_STRS "sdmc","sys","boot1","boot1_off","emusd" /* FF_STR_VOLUME_ID switches support for volume ID in arbitrary strings. / When FF_STR_VOLUME_ID is set to 1 or 2, arbitrary strings can be used as drive / number in the path name. FF_VOLUME_STRS defines the volume ID strings for each diff --git a/fusee/program/source/fatfs/fusee_diskio.cpp b/fusee/program/source/fatfs/fusee_diskio.cpp index eb211e532..fa7643338 100644 --- a/fusee/program/source/fatfs/fusee_diskio.cpp +++ b/fusee/program/source/fatfs/fusee_diskio.cpp @@ -17,6 +17,7 @@ #include "diskio_cpp.h" #include "../fusee_sd_card.hpp" #include "../fusee_mmc.hpp" +#include "../fusee_emusd.hpp" bool diskio_read_sd_card(void *dst, size_t size, size_t sector_index, size_t sector_count) { return R_SUCCEEDED(::ams::nxboot::ReadSdCard(dst, size, sector_index, sector_count)); @@ -42,4 +43,12 @@ bool diskio_read_boot1(void *dst, size_t size, size_t sector_index, size_t secto bool diskio_write_boot1(size_t sector_index, size_t sector_count, const void *src, size_t size) { /* Don't allow writes to eMMC BOOT1 */ return false; -} \ No newline at end of file +} + +bool diskio_read_emusd(void *dst, size_t size, size_t sector_index, size_t sector_count) { + return R_SUCCEEDED(::ams::nxboot::ReadEmuSd(dst, size, sector_index, sector_count)); +} + +bool diskio_write_emusd(size_t sector_index, size_t sector_count, const void *src, size_t size) { + return R_SUCCEEDED(::ams::nxboot::WriteEmuSd(sector_index, sector_count, src, size)); +} diff --git a/fusee/program/source/fs/fusee_fs_api.cpp b/fusee/program/source/fs/fusee_fs_api.cpp index b602c1cea..cfab452a4 100644 --- a/fusee/program/source/fs/fusee_fs_api.cpp +++ b/fusee/program/source/fs/fusee_fs_api.cpp @@ -30,10 +30,12 @@ namespace ams::fs { constinit bool g_is_sys_mounted = false; constinit bool g_is_boot1_mounted = false; constinit bool g_is_boot1_off_mounted = false; + constinit bool g_is_emusd_mounted = false; alignas(0x10) constinit FATFS g_sd_fs = {}; alignas(0x10) constinit FATFS g_sys_fs = {}; alignas(0x10) constinit FATFS g_boot1_fs = {}; + alignas(0x10) constinit FATFS g_emusd_fs = {}; alignas(0x10) constinit FIL g_files[MaxFiles] = {}; alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {}; @@ -122,53 +124,75 @@ namespace ams::fs { } + bool MountEmuSD() { + if(!g_is_emusd_mounted) { + g_is_emusd_mounted = f_mount(std::addressof(g_emusd_fs), "emusd:", 1) == FR_OK; + } + return g_is_emusd_mounted; + } + + void UnmountEmuSD () { + if(g_is_emusd_mounted) { + f_unmount("emusd:"); + } + g_is_emusd_mounted = false; + } + bool MountBoot1() { /* Can't mount both */ - AMS_ASSERT(!g_is_boot1_mounted && !g_is_boot1_off_mounted); - g_is_boot1_mounted = f_mount(std::addressof(g_boot1_fs), "boot1:", 1) == FR_OK; + if (!g_is_boot1_mounted && !g_is_boot1_off_mounted) { + g_is_boot1_mounted = f_mount(std::addressof(g_boot1_fs), "boot1:", 1) == FR_OK; + } return g_is_boot1_mounted; } void UnmountBoot1 () { - AMS_ASSERT(g_is_boot1_mounted); - f_unmount("boot1:"); + if (g_is_boot1_mounted) { + f_unmount("boot1:"); + } g_is_boot1_mounted = false; } bool MountBoot1Off() { /* Can't mount both */ - AMS_ASSERT(!g_is_boot1_mounted && !g_is_boot1_off_mounted); - g_is_boot1_off_mounted = f_mount(std::addressof(g_boot1_fs), "boot1_off:", 1) == FR_OK; + if (!g_is_boot1_mounted && !g_is_boot1_off_mounted) { + g_is_boot1_off_mounted = f_mount(std::addressof(g_boot1_fs), "boot1_off:", 1) == FR_OK; + } return g_is_boot1_off_mounted; } void UnmountBoot1Off () { - AMS_ASSERT(g_is_boot1_off_mounted); - f_unmount("boot1_off:"); + if (g_is_boot1_off_mounted) { + f_unmount("boot1_off:"); + } g_is_boot1_off_mounted = false; } bool MountSys() { - AMS_ASSERT(!g_is_sys_mounted); - g_is_sys_mounted = f_mount(std::addressof(g_sys_fs), "sys:", 1) == FR_OK; + if (!g_is_sys_mounted) { + g_is_sys_mounted = f_mount(std::addressof(g_sys_fs), "sys:", 1) == FR_OK; + } return g_is_sys_mounted; } void UnmountSys() { - AMS_ASSERT(g_is_sys_mounted); - f_unmount("sys:"); + if (g_is_sys_mounted) { + f_unmount("sys:"); + } g_is_sys_mounted = false; } bool MountSdCard() { - AMS_ASSERT(!g_is_sd_mounted); - g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc:", 1) == FR_OK; + if (!g_is_sd_mounted) { + g_is_sd_mounted = f_mount(std::addressof(g_sd_fs), "sdmc:", 1) == FR_OK; + } return g_is_sd_mounted; } void UnmountSdCard() { - AMS_ASSERT(g_is_sd_mounted); - f_unmount("sdmc:"); + if (g_is_sd_mounted) { + f_unmount("sdmc:"); + } g_is_sd_mounted = false; } diff --git a/fusee/program/source/fs/fusee_fs_api.hpp b/fusee/program/source/fs/fusee_fs_api.hpp index 1bc9bdd7e..89e1d0386 100644 --- a/fusee/program/source/fs/fusee_fs_api.hpp +++ b/fusee/program/source/fs/fusee_fs_api.hpp @@ -108,6 +108,9 @@ namespace ams::fs { bool MountBoot1Off(); void UnmountBoot1Off(); + bool MountEmuSD(); + void UnmountEmuSD(); + Result ChangeDrive(const char *path); Result ChangeDirectory(const char *path); diff --git a/fusee/program/source/fs/fusee_fs_storage.hpp b/fusee/program/source/fs/fusee_fs_storage.hpp index 286a6bbdd..89e9077ca 100644 --- a/fusee/program/source/fs/fusee_fs_storage.hpp +++ b/fusee/program/source/fs/fusee_fs_storage.hpp @@ -16,6 +16,9 @@ #pragma once #include #include "fusee_fs_api.hpp" +#include "../fusee_mmc.hpp" +#include "../fusee_fatal.hpp" +#include "../fusee_sd_card.hpp" namespace ams::fs { @@ -155,4 +158,95 @@ namespace ams::fs { virtual Result SetSize(s64 size) override; }; + class SdCardStorage : public fs::IStorage { + public: + virtual Result Read(s64 offset, void *buffer, size_t size) override { + if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { + nxboot::ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); + } + + R_RETURN(nxboot::ReadSdCard(buffer, size, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); + } + + virtual Result Flush() override { + R_SUCCEED(); + } + + virtual Result GetSize(s64 *out) override { + u32 num_sectors; + R_TRY(nxboot::GetSdCardMemoryCapacity(std::addressof(num_sectors))); + + *out = static_cast(num_sectors) * static_cast(sdmmc::SectorSize); + R_SUCCEED(); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { + nxboot::ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); + } + + R_RETURN(nxboot::WriteSdCard(offset / sdmmc::SectorSize, size / sdmmc::SectorSize, buffer, size)); + } + + virtual Result SetSize(s64 size) override { + R_THROW(fs::ResultUnsupportedOperation()); + } + }; + + template + class MmcPartitionStorage : public fs::IStorage { + public: + constexpr MmcPartitionStorage() { /* ... */ } + + virtual Result Read(s64 offset, void *buffer, size_t size) override { + if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { + nxboot::ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); + } + + R_RETURN(nxboot::ReadMmc(buffer, size, Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); + } + + virtual Result Flush() override { + R_SUCCEED(); + } + + virtual Result GetSize(s64 *out) override { + u32 num_sectors; + R_TRY(nxboot::GetMmcMemoryCapacity(std::addressof(num_sectors), Partition)); + + *out = static_cast(num_sectors) * static_cast(sdmmc::SectorSize); + R_SUCCEED(); + } + + virtual Result Write(s64 offset, const void *buffer, size_t size) override { + if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { + nxboot::ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); + } + + R_RETURN(nxboot::WriteMmc(Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize, buffer, size)); + } + + virtual Result SetSize(s64 size) override { + R_THROW(fs::ResultUnsupportedOperation()); + } + }; + + class MultiFileStorage : public fs::IStorage { + private: + s64 m_file_size; + fs::FileHandle m_handles[64]; + bool m_open[64]; + int m_file_path_ofs; + char m_base_path[0x300]; + private: + void EnsureFile(int id); + public: + MultiFileStorage(const char *base_path); + virtual Result Read(s64 offset, void *buffer, size_t size) override; + virtual Result Flush() override; + virtual Result GetSize(s64 *out) override; + virtual Result Write(s64 offset, const void *buffer, size_t size) override; + virtual Result SetSize(s64 size) override; + }; + } diff --git a/fusee/program/source/fs/fusee_multi_file_storage.cpp b/fusee/program/source/fs/fusee_multi_file_storage.cpp new file mode 100644 index 000000000..82b801d02 --- /dev/null +++ b/fusee/program/source/fs/fusee_multi_file_storage.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 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 "fusee_fs_storage.hpp" + +namespace ams::fs { + + void MultiFileStorage::EnsureFile(int id) { + if (!m_open[id]) { + /* Update path. */ + m_base_path[m_file_path_ofs + 1] = '0' + (id % 10); + m_base_path[m_file_path_ofs + 0] = '0' + (id / 10); + + /* Open new file. */ + const Result result = fs::OpenFile(m_handles + id, m_base_path, fs::OpenMode_Read); + if (R_FAILED(result)) { + nxboot::ShowFatalError("Failed to open part %02d (%s): 0x%08" PRIx32 "!\n", id, m_base_path, result.GetValue()); + } + + m_open[id] = true; + } + } + + MultiFileStorage::MultiFileStorage(const char *base_path) { + util::Strlcpy(m_base_path, base_path, sizeof(m_base_path) - 2); + m_file_path_ofs = strlen(m_base_path); + + for (size_t i = 0; i < util::size(m_handles); i++) { + m_open[i] = false; + } + + std::memcpy(m_base_path + m_file_path_ofs, "00", 3); + Result r; + if (R_FAILED(r = fs::OpenFile(std::addressof(m_handles[0]), m_base_path, fs::OpenMode_Read))) { + nxboot::ShowFatalError("Failed to open part %02d (%s): 0x%08" PRIx32 "!\n", 0, m_base_path, r.GetValue()); + } + + m_open[0] = true; + } + + Result MultiFileStorage::Read(s64 offset, void *buffer, size_t size) { + int file = offset / m_file_size; + s64 subofs = offset % m_file_size; + + u8 *cur_dst = static_cast(buffer); + + for (/* ... */; size > 0; ++file) { + /* Ensure the current file is open. */ + EnsureFile(file); + + /* Perform the current read. */ + const size_t cur_size = std::min(m_file_size - subofs, size); + R_TRY(fs::ReadFile(m_handles[file], subofs, cur_dst, cur_size)); + + /* Advance. */ + cur_dst += cur_size; + size -= cur_size; + subofs = 0; + } + + R_SUCCEED(); + } + + Result MultiFileStorage::Flush() { + R_THROW(fs::ResultUnsupportedOperation()); + } + + Result MultiFileStorage::GetSize(s64 *out) { + R_THROW(fs::ResultUnsupportedOperation()); + } + + Result MultiFileStorage::Write(s64 offset, const void *buffer, size_t size) { + int file = offset / m_file_size; + s64 subofs = offset % m_file_size; + + const u8 *cur_src = static_cast(buffer); + + for (/* ... */; size > 0; ++file) { + /* Ensure the current file is open. */ + EnsureFile(file); + + /* Perform the current read. */ + const size_t cur_size = std::min(m_file_size - subofs, size); + R_TRY(fs::WriteFile(m_handles[file], subofs, cur_src, cur_size, fs::WriteOption::Flush)); + + /* Advance. */ + cur_src += cur_size; + size -= cur_size; + subofs = 0; + } + + R_SUCCEED(); + } + + Result MultiFileStorage::SetSize(s64 size) { + R_THROW(fs::ResultUnsupportedOperation()); + } + +} diff --git a/fusee/program/source/fusee_boot_storage.cpp b/fusee/program/source/fusee_boot_storage.cpp index 557f22b10..ccd98d2f3 100644 --- a/fusee/program/source/fusee_boot_storage.cpp +++ b/fusee/program/source/fusee_boot_storage.cpp @@ -1,10 +1,8 @@ #include "fusee_boot_storage.hpp" #include "fs/fusee_fs_api.hpp" -#include "fusee_display.hpp" #include "fusee_mmc.hpp" #include "fusee_sd_card.hpp" #include -#include namespace ams::nxboot { namespace { @@ -75,7 +73,6 @@ namespace ams::nxboot { R_THROW(fs::ResultInvalidMountName()); } - } Result MountBootStorage() { diff --git a/fusee/program/source/fusee_emummc.cpp b/fusee/program/source/fusee_emummc.cpp index 509ddab3c..cc1e9d7d6 100644 --- a/fusee/program/source/fusee_emummc.cpp +++ b/fusee/program/source/fusee_emummc.cpp @@ -14,167 +14,27 @@ * along with this program. If not, see . */ #include +#include #include "fusee_emummc.hpp" +#include "fusee_ini.hpp" #include "fusee_mmc.hpp" -#include "fusee_sd_card.hpp" #include "fusee_fatal.hpp" #include "fusee_malloc.hpp" #include "fs/fusee_fs_api.hpp" #include "fs/fusee_fs_storage.hpp" +#include "fusee_sd_card.hpp" +#include "fusee_util.hpp" namespace ams::nxboot { namespace { - class SdCardStorage : public fs::IStorage { - public: - virtual Result Read(s64 offset, void *buffer, size_t size) override { - if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { - ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); - } - - R_RETURN(ReadSdCard(buffer, size, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); - } - - virtual Result Flush() override { - R_SUCCEED(); - } - - virtual Result GetSize(s64 *out) override { - u32 num_sectors; - R_TRY(GetSdCardMemoryCapacity(std::addressof(num_sectors))); - - *out = static_cast(num_sectors) * static_cast(sdmmc::SectorSize); - R_SUCCEED(); - } - - virtual Result Write(s64 offset, const void *buffer, size_t size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - - virtual Result SetSize(s64 size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - }; - - template - class MmcPartitionStorage : public fs::IStorage { - public: - constexpr MmcPartitionStorage() { /* ... */ } - - virtual Result Read(s64 offset, void *buffer, size_t size) override { - if (!util::IsAligned(offset, sdmmc::SectorSize) || !util::IsAligned(size, sdmmc::SectorSize)) { - ShowFatalError("SdCard: unaligned access to %" PRIx64 ", size=%" PRIx64"\n", static_cast(offset), static_cast(size)); - } - - R_RETURN(ReadMmc(buffer, size, Partition, offset / sdmmc::SectorSize, size / sdmmc::SectorSize)); - } - - virtual Result Flush() override { - R_SUCCEED(); - } - - virtual Result GetSize(s64 *out) override { - u32 num_sectors; - R_TRY(GetMmcMemoryCapacity(std::addressof(num_sectors), Partition)); - - *out = static_cast(num_sectors) * static_cast(sdmmc::SectorSize); - R_SUCCEED(); - } - - virtual Result Write(s64 offset, const void *buffer, size_t size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - - virtual Result SetSize(s64 size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - }; - - using MmcBoot0Storage = MmcPartitionStorage; - using MmcUserStorage = MmcPartitionStorage; - - constinit char g_emummc_path[0x300]; - - class EmummcFileStorage : public fs::IStorage { - private: - s64 m_file_size; - fs::FileHandle m_handles[64]; - bool m_open[64]; - int m_file_path_ofs; - private: - void EnsureFile(int id) { - if (!m_open[id]) { - /* Update path. */ - g_emummc_path[m_file_path_ofs + 1] = '0' + (id % 10); - g_emummc_path[m_file_path_ofs + 0] = '0' + (id / 10); - - /* Open new file. */ - const Result result = fs::OpenFile(m_handles + id, g_emummc_path, fs::OpenMode_Read); - if (R_FAILED(result)) { - ShowFatalError("Failed to open emummc user %02d file: 0x%08" PRIx32 "!\n", id, result.GetValue()); - } - - m_open[id] = true; - } - } - public: - EmummcFileStorage(fs::FileHandle user00, int ofs) : m_file_path_ofs(ofs) { - const Result result = fs::GetFileSize(std::addressof(m_file_size), user00); - if (R_FAILED(result)) { - ShowFatalError("Failed to get emummc file size: 0x%08" PRIx32 "!\n", result.GetValue()); - } - - for (size_t i = 0; i < util::size(m_handles); ++i) { - m_open[i] = false; - } - - m_handles[0] = user00; - m_open[0] = true; - } - - virtual Result Read(s64 offset, void *buffer, size_t size) override { - int file = offset / m_file_size; - s64 subofs = offset % m_file_size; - - u8 *cur_dst = static_cast(buffer); - - for (/* ... */; size > 0; ++file) { - /* Ensure the current file is open. */ - EnsureFile(file); - - /* Perform the current read. */ - const size_t cur_size = std::min(m_file_size - subofs, size); - R_TRY(fs::ReadFile(m_handles[file], subofs, cur_dst, cur_size)); - - /* Advance. */ - cur_dst += cur_size; - size -= cur_size; - subofs = 0; - } - - R_SUCCEED(); - } - - virtual Result Flush() override { - R_THROW(fs::ResultUnsupportedOperation()); - } - - virtual Result GetSize(s64 *out) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - - virtual Result Write(s64 offset, const void *buffer, size_t size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - - virtual Result SetSize(s64 size) override { - R_THROW(fs::ResultUnsupportedOperation()); - } - }; - - constinit SdCardStorage g_sd_card_storage; + using MmcBoot0Storage = fs::MmcPartitionStorage; + using MmcUserStorage = fs::MmcPartitionStorage; + using EmummcFileStorage = fs::MultiFileStorage; + constinit secmon::EmummcConfiguration g_emummc_cfg = {}; + constinit fs::SdCardStorage g_sd_card_storage; constinit MmcBoot0Storage g_mmc_boot0_storage; constinit MmcUserStorage g_mmc_user_storage; @@ -231,24 +91,28 @@ namespace ams::nxboot { 'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0 }; + bool IsDirectoryExist(const char *path) { + fs::DirectoryEntryType entry_type; + bool archive; + return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory; + } + } void InitializeEmummc(bool emummc_enabled, const secmon::EmummcEmmcConfiguration &emummc_cfg) { Result result; if (emummc_enabled) { - /* Get sd card size. */ - s64 sd_card_size; - if (R_FAILED((result = g_sd_card_storage.GetSize(std::addressof(sd_card_size))))) { - ShowFatalError("Failed to get sd card size: 0x%08" PRIx32 "!\n", result.GetValue()); - } - if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Emmc || emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Sd) { /* Partition based emummc */ if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_Partition_Emmc) { /* When emmc based, init eMMC */ if (R_FAILED((result = InitializeMmc()))) { ShowFatalError("Failed to initialize mmc: 0x%08" PRIx32 "\n", result.GetValue()); - } + } + } else { + if (R_FAILED((result = InitializeSdCard ()))) { + ShowFatalError("Failed to initialize sd: 0x%08" PRIx32 "\n", result.GetValue()); + } } /* Get SD or eMMC storage */ @@ -265,6 +129,8 @@ namespace ams::nxboot { g_user_storage = AllocateObject(storage, partition_start + 8_MB, storage_size - (partition_start + 8_MB)); } else if (emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Emmc || emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Sd) { /* File based emummc */ + char path[0x300]; + if(emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Emmc) { /* When emmc based, init eMMC */ if (R_FAILED((result = InitializeMmc()))) { @@ -274,33 +140,43 @@ namespace ams::nxboot { if (!fs::MountSys()) { ShowFatalError("Failed to mount mmc!\n"); } + } else { + /* When sd based, init sd */ + if (R_FAILED((result = InitializeSdCard ()))) { + ShowFatalError("Failed to initialize sd: 0x%08" PRIx32 "\n", result.GetValue()); + } + + if (!fs::MountSdCard()) { + ShowFatalError("Failed to mount sd!\n"); + } } /* Set drive to read from */ if (emummc_cfg.base_cfg.type == secmon::EmummcEmmcType_File_Sd) { - std::strcpy(g_emummc_path, "sdmc:"); + std::strcpy(path, "sdmc:"); } else { - std::strcpy(g_emummc_path, "sys:"); + std::strcpy(path, "sys:"); } - std::memcpy(g_emummc_path + std::strlen(g_emummc_path), emummc_cfg.file_cfg.path.str, sizeof(emummc_cfg.file_cfg.path.str)); - std::strcat(g_emummc_path, "/eMMC"); - auto len = std::strlen(g_emummc_path); + std::memcpy(path + std::strlen(path), emummc_cfg.file_cfg.path.str, sizeof(emummc_cfg.file_cfg.path.str)); + std::strcat(path, "/eMMC"); + + auto len = std::strlen(path); /* Open boot0 file */ fs::FileHandle boot0_file; - std::strcat(g_emummc_path, "/boot0"); - if(R_FAILED((result = fs::OpenFile(std::addressof(boot0_file), g_emummc_path, fs::OpenMode_Read)))) { - ShowFatalError("Failed to open emummc boot0 file: 0x%08" PRIx32 " %s!\n", result.GetValue(), g_emummc_path); + std::strcat(path, "/boot0"); + if(R_FAILED((result = fs::OpenFile(std::addressof(boot0_file), path, fs::OpenMode_Read)))) { + ShowFatalError("Failed to open emummc boot0 file: 0x%08" PRIx32 " %s!\n", result.GetValue(), path); } /* Check if boot1 file exists */ - std::strcpy(g_emummc_path + len, "/boot1"); + std::strcpy(path + len, "/boot1"); { fs::DirectoryEntryType entry_type; bool is_archive; - if (R_FAILED((result = fs::GetEntryType(std::addressof(entry_type), std::addressof(is_archive), g_emummc_path)))){ + if (R_FAILED((result = fs::GetEntryType(std::addressof(entry_type), std::addressof(is_archive), path)))){ ShowFatalError("Failed to find emummc boot1 file: 0x%08" PRIx32 "!\n", result.GetValue()); } @@ -310,15 +186,12 @@ namespace ams::nxboot { } /* Open userdata */ - std::strcpy(g_emummc_path + len, "/00"); - fs::FileHandle user00_file; - if(R_FAILED((result = fs::OpenFile(std::addressof(user00_file), g_emummc_path, fs::OpenMode_Read)))) { - ShowFatalError("Failed to open emummc user %02d file: 0x%08" PRIx32 "!\n", 0, result.GetValue()); - } + std::strcpy(path + len, "/"); /* Create partition */ + /* TODO: construct boot0 storage from path instead */ g_boot0_storage = AllocateObject(boot0_file); - g_user_storage = AllocateObject(user00_file, len + 1); + g_user_storage = AllocateObject(path); } else { ShowFatalError("Unknown emummc type %d\n", static_cast(emummc_cfg.base_cfg.type)); } @@ -388,4 +261,130 @@ namespace ams::nxboot { R_RETURN(g_package2_storage->Read(offset, dst, size)); } + Result ReadEmummcConfig() { + /* Set magic. */ + auto &sd_cfg = g_emummc_cfg.sd_cfg; + auto &emmc_cfg = g_emummc_cfg.emmc_cfg; + + emmc_cfg.base_cfg.magic = secmon::EmummcEmmcBaseConfiguration::Magic; + sd_cfg.base_cfg.magic = secmon::EmummcSdBaseConfiguration::Magic; + + /* Parse emummc ini. */ + u32 enabled = 0; + u32 id = 0; + u32 sector = 0; + const char *path = ""; + const char *n_path = ""; + + { + IniSectionList sections; + if (ParseIniSafe(sections, "emummc/emummc.ini")) { + for (const auto §ion : sections){ + /* Skip non-emummc sections */ + if (std::strcmp(section.name, "emummc")) { + continue; + } + + for (const auto &entry : section.kv_list) { + if(std::strcmp(entry.key, "enabled") == 0) { + enabled = ParseDecimalInteger(entry.value); + } else if (std::strcmp(entry.key, "id") == 0) { + id = ParseHexInteger(entry.value); + } else if (std::strcmp(entry.key, "sector") == 0) { + sector = ParseHexInteger(entry.value); + } else if (std::strcmp(entry.key, "path") == 0) { + path = entry.value; + } else if (std::strcmp(entry.key, "nintendo_path") == 0) { + n_path = entry.value; + } + } + } + } + } + + /* Set parsed values to config */ + constexpr const char *emummc_err_str = "Invalid emummc setting!\n"; + + emmc_cfg.base_cfg.id = id; + std::strncpy(emmc_cfg.emu_dir_path.str, n_path, sizeof(emmc_cfg.emu_dir_path.str)); + emmc_cfg.emu_dir_path.str[sizeof(emmc_cfg.emu_dir_path.str) - 1] = '\x00'; + + if (enabled == 1) { + /* SD based */ + if (sector > 0) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Sd; + emmc_cfg.partition_cfg.start_sector = sector; + } else if (path[0] != '\x00' && IsDirectoryExist(path)) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Sd; + std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); + emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; + } else { + ShowFatalError(emummc_err_str); + } + } else if (enabled == 4){ + /* eMMC based */ + if (sector > 0) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Emmc; + emmc_cfg.partition_cfg.start_sector = sector; + } else if (path[0] != '\x00' /* && IsDirectoryExist(path) */) { + /* TODO: Should check if directory exist on *eMMC* fat partition instead of SD */ + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Emmc; + std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); + emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; + } else { + ShowFatalError(emummc_err_str); + } + } else if (enabled == 0) { + emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_None; + } else { + ShowFatalError(emummc_err_str); + } + + /* Parse emusd ini. */ + constexpr const char *emusd_err_str = "Invalid emusd setting!\n"; + + u32 sd_enabled = 0; + u32 sd_sector = 0; + + { + IniSectionList sections; + if (ParseIniSafe(sections, "emusd/emusd.ini")) { + for (const auto §ion : sections){ + /* Skip non-emummc sections */ + if (std::strcmp(section.name, "emusd")) { + continue; + } + + for (const auto &entry : section.kv_list) { + if(std::strcmp(entry.key, "enabled") == 0) { + sd_enabled = ParseDecimalInteger(entry.value); + } else if (std::strcmp(entry.key, "sector") == 0) { + sd_sector = ParseHexInteger(entry.value); + } + } + } + } + } + + /* Set parsed values to config */ + if (sd_enabled == 4) { + if (sd_sector > 0) { + sd_cfg.partition_cfg.start_sector = sd_sector; + sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_Partition_Emmc; + } else { + ShowFatalError(emusd_err_str); + } + } else if (sd_enabled == 0) { + sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_None; + } else { + ShowFatalError(emusd_err_str); + } + + R_SUCCEED(); + } + + const secmon::EmummcConfiguration &GetEmummcConfig() { + return g_emummc_cfg; + } + } diff --git a/fusee/program/source/fusee_emummc.hpp b/fusee/program/source/fusee_emummc.hpp index a0e99f6aa..69627922a 100644 --- a/fusee/program/source/fusee_emummc.hpp +++ b/fusee/program/source/fusee_emummc.hpp @@ -15,13 +15,16 @@ */ #pragma once -#include +#include #include namespace ams::nxboot { void InitializeEmummc(bool emummc_enabled, const secmon::EmummcEmmcConfiguration &emummc_cfg); + Result ReadEmummcConfig(); + const secmon::EmummcConfiguration &GetEmummcConfig(); + Result ReadBoot0(s64 offset, void *dst, size_t size); Result ReadPackage2(s64 offset, void *dst, size_t size); Result ReadSystem(s64 offset, void *dst, size_t size); diff --git a/fusee/program/source/fusee_emusd.cpp b/fusee/program/source/fusee_emusd.cpp new file mode 100644 index 000000000..b5304b55e --- /dev/null +++ b/fusee/program/source/fusee_emusd.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (c) 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 "fusee_emusd.hpp" +#include "fs/fusee_fs_storage.hpp" +#include "fusee_fatal.hpp" +#include "fusee_malloc.hpp" +#include "fusee_mmc.hpp" +#include + +namespace ams::nxboot { + + namespace { + constinit fs::IStorage *g_emusd_base_storage = nullptr; + constinit fs::IStorage *g_emusd_storage = nullptr; + + struct MbrPartitionEntry { + u8 boot_flag; + u8 chs_start[3]; + u8 type; + u8 chs_end[3]; + u32 sct_start; + u32 sct_size; + }; + + struct __attribute__((packed)) Mbr { + u8 bootloader[440]; + u32 signature; + u8 padding[2]; + MbrPartitionEntry entries[4]; + u16 magic; + }; + } + + void InitializeEmuSd(const secmon::EmummcSdConfiguration &emusd_cfg) { + if (emusd_cfg.IsActive()) { + if (emusd_cfg.base_cfg.type == secmon::EmummcSdType_Partition_Emmc) { + Result r; + if (R_FAILED(r = InitializeMmc())) { + ShowFatalError("Failed to initializeMmc: %" PRIx32 "!\n", r.GetValue()); + } + + g_emusd_base_storage = AllocateObject>(); + + /* Get base storage size */ + s64 size; + if(R_FAILED(g_emusd_base_storage->GetSize(std::addressof(size)))) { + ShowFatalError("Failed to get eMMC size!"); + } + + /* Read emuSD size from mbr */ + Mbr *mbr = static_cast(AllocateAligned(sizeof(mbr), 0x200)); + const s64 offset = INT64_C(0x200) * emusd_cfg.partition_cfg.start_sector; + r = g_emusd_base_storage->Read(offset, mbr, sizeof(*mbr)); + if (R_FAILED(r)) { + ShowFatalError("Failed to read MBR: 0x%08" PRIx32 "\n", r.GetValue()); + } + + + /* Fatal if emuSD too big */ + const s64 emusd_size = INT64_C(0x200) * (mbr->entries[0].sct_size + mbr->entries[0].sct_start); + if (offset + emusd_size > static_cast(size)) { + ShowFatalError("Invalid emusd!"); + } + + g_emusd_storage = AllocateObject(*g_emusd_base_storage, offset, emusd_size); + } + /* TODO: support other emusd types */ + } else { + const Result r = InitializeSdCard(); + if (R_FAILED(r)) { + ShowFatalError("Failed to initialize SD card: 0x%08" PRIx32 "!\n", r.GetValue()); + } + g_emusd_storage = AllocateObject(); + } + } + + Result ReadEmuSd(void *dst, size_t size, size_t sector_index, size_t sector_count) { + R_UNLESS(g_emusd_storage, fs::ResultNotInitialized()); + R_RETURN(g_emusd_storage->Read(INT64_C(0x200) * sector_index, dst, INT64_C(0x200) * sector_count)); + } + + Result WriteEmuSd(size_t sector_index, size_t sector_count, const void *src, size_t size) { + R_UNLESS(g_emusd_storage, fs::ResultNotInitialized()); + R_RETURN(g_emusd_storage->Write(INT64_C(0x200) * sector_index, src, INT64_C(0x200) * sector_count)); + } + +} diff --git a/fusee/program/source/fusee_emusd.hpp b/fusee/program/source/fusee_emusd.hpp new file mode 100644 index 000000000..f3811a7df --- /dev/null +++ b/fusee/program/source/fusee_emusd.hpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 "fusee_sd_card.hpp" +#include +#include + +namespace ams::nxboot { + void InitializeEmuSd(const secmon::EmummcSdConfiguration &emusd_cfg); + Result ReadEmuSd(void *dst, size_t size, size_t sector_index, size_t sector_count); + Result WriteEmuSd(size_t sector_index, size_t sector_count, const void *src, size_t size); + +} \ No newline at end of file diff --git a/fusee/program/source/fusee_ini.cpp b/fusee/program/source/fusee_ini.cpp index 5e9b6eb66..081049c36 100644 --- a/fusee/program/source/fusee_ini.cpp +++ b/fusee/program/source/fusee_ini.cpp @@ -15,6 +15,7 @@ */ #include #include "fusee_ini.hpp" +#include "fusee_fatal.hpp" #include "fusee_malloc.hpp" #include "fs/fusee_fs_api.hpp" @@ -190,7 +191,17 @@ namespace ams::nxboot { return ParseIniResult_InvalidFormat; } + } + bool ParseIniSafe(IniSectionList &out_sections, const char *ini_path) { + const auto result = ParseIniFile(out_sections, ini_path); + if (result == ParseIniResult_Success) { + return true; + } else if (result == ParseIniResult_NoFile) { + return false; + } else { + ShowFatalError("Failed to parse %s!\n", ini_path); + } } } diff --git a/fusee/program/source/fusee_ini.hpp b/fusee/program/source/fusee_ini.hpp index 706e0b7c9..bc7a195c1 100644 --- a/fusee/program/source/fusee_ini.hpp +++ b/fusee/program/source/fusee_ini.hpp @@ -41,5 +41,6 @@ namespace ams::nxboot { }; ParseIniResult ParseIniFile(IniSectionList &out_sections, const char *ini_path); - + bool ParseIniSafe(IniSectionList &out_sections, const char *ini_path); + } \ No newline at end of file diff --git a/fusee/program/source/fusee_main.cpp b/fusee/program/source/fusee_main.cpp index f7119a234..df119a976 100644 --- a/fusee/program/source/fusee_main.cpp +++ b/fusee/program/source/fusee_main.cpp @@ -16,6 +16,8 @@ #include #include "fusee_boot_storage.hpp" #include "fusee_display.hpp" +#include "fusee_emummc.hpp" +#include "fusee_emusd.hpp" #include "sein/fusee_secure_initialize.hpp" #include "sdram/fusee_sdram.hpp" #include "mtc/fusee_mtc.hpp" @@ -67,6 +69,19 @@ namespace ams::nxboot { fs::CloseFile(g_package_file); } + void SwapToEmuSd() { + /* Switch to emuSD, if active */ + if (GetEmummcConfig().sd_cfg.IsActive()) { + /* UnmountBootStorage(); */ + FinalizeBootStorage(); + InitializeEmuSd(GetEmummcConfig().sd_cfg); + fs::ChangeDrive("emusd:"); + if (!fs::MountEmuSD()) { + ShowFatalError("Failed to mount emuSD"); + } + } + } + } void Main() { @@ -87,6 +102,12 @@ namespace ams::nxboot { ShowFatalError("Failed to mount boot storage."); } + /* Read emuMMC/emuSD config now, need to switch to emuSD, if active, to read AMS files from there */ + ReadEmummcConfig(); + + /* Switch to emuSD, if active */ + SwapToEmuSd(); + /* If we have a fatal error, save and display it. */ SaveAndShowFatalError(); @@ -117,6 +138,7 @@ namespace ams::nxboot { /* Restore the memory training overlay. */ RestoreMemoryTrainingOverlay(); + /* Restore memory clock rate. */ RestoreMemoryClockRate(); @@ -127,8 +149,10 @@ namespace ams::nxboot { /* Finalize display. */ FinalizeDisplay(); + // TODO: proper finalize /* Finalize sd card. */ UnmountBootStorage(); + fs::UnmountEmuSD(); FinalizeSdCard(); /* Finalize the data cache. */ diff --git a/fusee/program/source/fusee_mmc.cpp b/fusee/program/source/fusee_mmc.cpp index 19de3550e..5644741b6 100644 --- a/fusee/program/source/fusee_mmc.cpp +++ b/fusee/program/source/fusee_mmc.cpp @@ -20,6 +20,8 @@ namespace ams::nxboot { namespace { + constinit bool g_is_initialized = false; + constexpr inline auto MmcPort = sdmmc::Port_Mmc0; alignas(0x10) constinit u8 g_mmc_work_buffer[sdmmc::MmcWorkBufferSize]; @@ -40,22 +42,29 @@ namespace ams::nxboot { } void FinalizeMmc() { - /* Deactivate MMC. */ - sdmmc::Deactivate(MmcPort); + if (g_is_initialized) { + g_is_initialized = false; + /* Deactivate MMC. */ + sdmmc::Deactivate(MmcPort); - /* Finalize MMC. */ - sdmmc::Finalize(MmcPort); + /* Finalize MMC. */ + sdmmc::Finalize(MmcPort); + } } Result InitializeMmc() { - /* Initialize the mmc. */ - sdmmc::Initialize(MmcPort); + if (!g_is_initialized) { + /* Initialize the mmc. */ + sdmmc::Initialize(MmcPort); + g_is_initialized = true; - /* Set the mmc work buffer. */ - sdmmc::SetMmcWorkBuffer(MmcPort, g_mmc_work_buffer, sizeof(g_mmc_work_buffer)); + /* Set the mmc work buffer. */ + sdmmc::SetMmcWorkBuffer(MmcPort, g_mmc_work_buffer, sizeof(g_mmc_work_buffer)); - /* Activate the mmc. */ - R_RETURN(sdmmc::Activate(MmcPort)); + /* Activate the mmc. */ + R_RETURN(sdmmc::Activate(MmcPort)); + } + R_SUCCEED(); } Result CheckMmcConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) { diff --git a/fusee/program/source/fusee_sd_card.cpp b/fusee/program/source/fusee_sd_card.cpp index 0b9ec98ed..9ccdc9b56 100644 --- a/fusee/program/source/fusee_sd_card.cpp +++ b/fusee/program/source/fusee_sd_card.cpp @@ -20,6 +20,8 @@ namespace ams::nxboot { namespace { + constinit bool g_is_initialized = false; + constexpr inline auto SdCardPort = sdmmc::Port_SdCard0; constexpr inline const uintptr_t APB = secmon::MemoryRegionPhysicalDeviceApbMisc.GetAddress(); @@ -69,24 +71,32 @@ namespace ams::nxboot { Result InitializeSdCard() { /* Perform initial pinmux config to enable sd card access. */ - ConfigureInitialSdCardPinmux(); + if (!g_is_initialized) { + ConfigureInitialSdCardPinmux(); - /* Initialize the SD card. */ - sdmmc::Initialize(SdCardPort); + /* Initialize the SD card. */ + sdmmc::Initialize(SdCardPort); - /* Set the SD card work buffer. */ - sdmmc::SetSdCardWorkBuffer(SdCardPort, g_sd_work_buffer, sizeof(g_sd_work_buffer)); + g_is_initialized = true; - /* Activate the SD card. */ - R_RETURN(sdmmc::Activate(SdCardPort)); + /* Set the SD card work buffer. */ + sdmmc::SetSdCardWorkBuffer(SdCardPort, g_sd_work_buffer, sizeof(g_sd_work_buffer)); + + /* Activate the SD card. */ + R_RETURN(sdmmc::Activate(SdCardPort)); + } + R_SUCCEED(); } void FinalizeSdCard() { /* Deactivate the SD card. */ - sdmmc::Deactivate(SdCardPort); + if (g_is_initialized) { + g_is_initialized = false; + sdmmc::Deactivate(SdCardPort); + /* Finalize the SD card. */ + sdmmc::Finalize(SdCardPort); + } - /* Finalize the SD card. */ - sdmmc::Finalize(SdCardPort); } Result CheckSdCardConnection(sdmmc::SpeedMode *out_sm, sdmmc::BusWidth *out_bw) { diff --git a/fusee/program/source/fusee_sd_card.hpp b/fusee/program/source/fusee_sd_card.hpp index 2caa3a868..6025a3f81 100644 --- a/fusee/program/source/fusee_sd_card.hpp +++ b/fusee/program/source/fusee_sd_card.hpp @@ -13,8 +13,8 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include #pragma once +#include namespace ams::nxboot { diff --git a/fusee/program/source/fusee_setup_horizon.cpp b/fusee/program/source/fusee_setup_horizon.cpp index c34c211b6..ed330f462 100644 --- a/fusee/program/source/fusee_setup_horizon.cpp +++ b/fusee/program/source/fusee_setup_horizon.cpp @@ -14,6 +14,7 @@ * along with this program. If not, see . */ #include +#include #include #include "fusee_key_derivation.hpp" #include "fusee_external_package.hpp" @@ -28,6 +29,7 @@ #include "fusee_secmon_sync.hpp" #include "fusee_stratosphere.hpp" #include "fs/fusee_fs_api.hpp" +#include "fusee_util.hpp" namespace ams::nxboot { @@ -37,8 +39,6 @@ namespace ams::nxboot { constexpr inline const uintptr_t PMC = secmon::MemoryRegionPhysicalDevicePmc.GetAddress(); constexpr inline const uintptr_t MC = secmon::MemoryRegionPhysicalDeviceMemoryController.GetAddress(); - constinit secmon::EmummcConfiguration g_emummc_cfg = {}; - void DeriveAllKeys(const fuse::SocType soc_type) { /* If on erista, run the TSEC keygen firmware. */ if (soc_type == fuse::SocType_Erista) { @@ -59,65 +59,6 @@ namespace ams::nxboot { } } - bool ParseIniSafe(IniSectionList &out_sections, const char *ini_path) { - const auto result = ParseIniFile(out_sections, ini_path); - if (result == ParseIniResult_Success) { - return true; - } else if (result == ParseIniResult_NoFile) { - return false; - } else { - ShowFatalError("Failed to parse %s!\n", ini_path); - } - } - - u32 ParseHexInteger(const char *s) { - u32 x = 0; - if (s[0] == '0' && s[1] == 'x') { - s += 2; - } - - while (true) { - const char c = *(s++); - - if (c == '\x00') { - return x; - } else { - x <<= 4; - - if ('0' <= c && c <= '9') { - x |= (c - '0'); - } else if ('a' <= c && c <= 'f') { - x |= (c - 'a') + 10; - } else if ('A' <= c && c <= 'F') { - x |= (c - 'A') + 10; - } - } - } - } - - 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; - return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory; - } - bool IsFileExist(const char *path) { fs::DirectoryEntryType entry_type; bool archive; @@ -126,128 +67,8 @@ namespace ams::nxboot { bool ConfigureEmummc() { /* Set magic. */ - auto &sd_cfg = g_emummc_cfg.sd_cfg; - auto &emmc_cfg = g_emummc_cfg.emmc_cfg; - - emmc_cfg.base_cfg.magic = secmon::EmummcEmmcBaseConfiguration::Magic; - sd_cfg.base_cfg.magic = secmon::EmummcSdBaseConfiguration::Magic; - - bool emummc_driver_enabled = false; - - /* Parse emummc ini. */ - u32 enabled = 0; - u32 id = 0; - u32 sector = 0; - const char *path = ""; - const char *n_path = ""; - - { - IniSectionList sections; - if (ParseIniSafe(sections, "emummc/emummc.ini")) { - for (const auto §ion : sections){ - /* Skip non-emummc sections */ - if (std::strcmp(section.name, "emummc")) { - continue; - } - - for (const auto &entry : section.kv_list) { - if(std::strcmp(entry.key, "enabled") == 0) { - enabled = ParseDecimalInteger(entry.value); - } else if (std::strcmp(entry.key, "id") == 0) { - id = ParseHexInteger(entry.value); - } else if (std::strcmp(entry.key, "sector") == 0) { - sector = ParseHexInteger(entry.value); - } else if (std::strcmp(entry.key, "path") == 0) { - path = entry.value; - } else if (std::strcmp(entry.key, "nintendo_path") == 0) { - n_path = entry.value; - } - } - } - } - } - - /* Set parsed values to config */ - constexpr const char *emummc_err_str = "Invalid emummc setting!\n"; - - emmc_cfg.base_cfg.id = id; - std::strncpy(emmc_cfg.emu_dir_path.str, n_path, sizeof(emmc_cfg.emu_dir_path.str)); - emmc_cfg.emu_dir_path.str[sizeof(emmc_cfg.emu_dir_path.str) - 1] = '\x00'; - - if (enabled == 1) { - /* SD based */ - emummc_driver_enabled = true; - if (sector > 0) { - emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Sd; - emmc_cfg.partition_cfg.start_sector = sector; - } else if (path[0] != '\x00' && IsDirectoryExist(path)) { - emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Sd; - std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); - emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; - } else { - ShowFatalError(emummc_err_str); - } - } else if (enabled == 4){ - /* eMMC based */ - emummc_driver_enabled = true; - if (sector > 0) { - emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_Partition_Emmc; - emmc_cfg.partition_cfg.start_sector = sector; - } else if (path[0] != '\x00' /* && IsDirectoryExist(path) */) { - /* TODO: Should check if directory exist on *eMMC* fat partition instead of SD */ - emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_File_Emmc; - std::strncpy(emmc_cfg.file_cfg.path.str, path, sizeof(emmc_cfg.file_cfg.path.str)); - emmc_cfg.file_cfg.path.str[sizeof(emmc_cfg.file_cfg.path.str) - 1] = '\x00'; - } else { - ShowFatalError(emummc_err_str); - } - } else if (enabled == 0) { - emmc_cfg.base_cfg.type = secmon::EmummcEmmcType::EmummcEmmcType_None; - } else { - ShowFatalError(emummc_err_str); - } - - /* Parse emusd ini. */ - constexpr const char *emusd_err_str = "Invalid emusd setting!\n"; - - u32 sd_enabled = 0; - u32 sd_sector = 0; - - { - IniSectionList sections; - if (ParseIniSafe(sections, "emusd/emusd.ini")) { - for (const auto §ion : sections){ - /* Skip non-emummc sections */ - if (std::strcmp(section.name, "emusd")) { - continue; - } - - for (const auto &entry : section.kv_list) { - if(std::strcmp(entry.key, "enabled") == 0) { - sd_enabled = ParseDecimalInteger(entry.value); - } else if (std::strcmp(entry.key, "sector") == 0) { - sd_sector = ParseHexInteger(entry.value); - } - } - } - } - } - - /* Set parsed values to config */ - if (sd_enabled == 4) { - emummc_driver_enabled = true; - if (sd_sector > 0) { - sd_cfg.partition_cfg.start_sector = sd_sector; - sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_Partition_Emmc; - } else { - ShowFatalError(emusd_err_str); - } - } else if (sd_enabled == 0) { - sd_cfg.base_cfg.type = secmon::EmummcSdType::EmummcSdType_None; - } else { - ShowFatalError(emusd_err_str); - } - + const secmon::EmummcConfiguration &emummc_cfg = GetEmummcConfig(); + bool emummc_driver_enabled = emummc_cfg.emmc_cfg.IsActive() || emummc_cfg.sd_cfg.IsActive(); return emummc_driver_enabled; } @@ -563,7 +384,7 @@ namespace ams::nxboot { /* Set some defaults. */ storage_ctx.target_firmware = target_firmware; storage_ctx.lcd_vendor = GetDisplayLcdVendor(); - storage_ctx.emummc_cfg = g_emummc_cfg; + storage_ctx.emummc_cfg = GetEmummcConfig(); storage_ctx.flags[0] = secmon::SecureMonitorConfigurationFlag_Default; storage_ctx.flags[1] = secmon::SecureMonitorConfigurationFlag_None; storage_ctx.log_port = uart::Port_ReservedDebug; @@ -793,6 +614,7 @@ namespace ams::nxboot { void SetupAndStartHorizon() { /* Get soc type. */ + const auto soc_type = fuse::GetSocType(); /* Derive all keys. */ @@ -800,11 +622,11 @@ namespace ams::nxboot { /* Determine whether we're using emummc. */ const bool emummc_driver_enabled = ConfigureEmummc(); - const bool emummc_enabled = g_emummc_cfg.emmc_cfg.base_cfg.type != secmon::EmummcEmmcType_None; + const bool emummc_enabled = GetEmummcConfig().emmc_cfg.IsActive(); /* Initialize emummc. */ /* NOTE: SYSTEM:/ accessible past this point. */ - InitializeEmummc(emummc_enabled, g_emummc_cfg.emmc_cfg); + InitializeEmummc(emummc_enabled, GetEmummcConfig().emmc_cfg); /* Read bootloader. */ const u8 * const package1 = LoadPackage1(soc_type); diff --git a/fusee/program/source/fusee_util.cpp b/fusee/program/source/fusee_util.cpp new file mode 100644 index 000000000..2b5d8fec2 --- /dev/null +++ b/fusee/program/source/fusee_util.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 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 "fusee_util.hpp" + +namespace ams::nxboot { + + u32 ParseHexInteger(const char *s) { + u32 x = 0; + if (s[0] == '0' && s[1] == 'x') { + s += 2; + } + + while (true) { + const char c = *(s++); + + if (c == '\x00') { + return x; + } else { + x <<= 4; + + if ('0' <= c && c <= '9') { + x |= (c - '0'); + } else if ('a' <= c && c <= 'f') { + x |= (c - 'a') + 10; + } else if ('A' <= c && c <= 'F') { + x |= (c - 'A') + 10; + } + } + } + } + + 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'; + } + } + } + } + +} diff --git a/fusee/program/source/fusee_util.hpp b/fusee/program/source/fusee_util.hpp new file mode 100644 index 000000000..f04175696 --- /dev/null +++ b/fusee/program/source/fusee_util.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) 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 +#pragma once + +namespace ams::nxboot { + + u32 ParseHexInteger(const char *s); + u32 ParseDecimalInteger(const char *s); + +} \ No newline at end of file diff --git a/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp b/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp index 2e2b84292..62cce555b 100644 --- a/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp +++ b/libraries/libvapours/source/sdmmc/impl/sdmmc_mmc_device_accessor.cpp @@ -499,7 +499,12 @@ namespace ams::sdmmc::impl { /* Get the sector index alignment. */ u32 sector_index_alignment = 0; if (!is_read) { + #ifdef ATMOSPHERE_IS_EXOSPHERE + /* Allow unaligned writes */ + constexpr u32 MmcWriteSectorAlignment = 0; + #else constexpr u32 MmcWriteSectorAlignment = 16_KB / SectorSize; + #endif sector_index_alignment = MmcWriteSectorAlignment; AMS_ABORT_UNLESS(util::IsAligned(sector_index, MmcWriteSectorAlignment)); }