mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
ams: allow bootloader to merely approximate correct target firmware
This commit is contained in:
parent
d41de21753
commit
5708bb1557
24 changed files with 281 additions and 396 deletions
|
@ -164,6 +164,7 @@ namespace ams::secmon::smc {
|
||||||
}
|
}
|
||||||
|
|
||||||
constinit u64 g_payload_address = 0;
|
constinit u64 g_payload_address = 0;
|
||||||
|
constinit bool g_set_true_target_firmware = false;
|
||||||
|
|
||||||
SmcResult GetConfig(SmcArguments &args, bool kern) {
|
SmcResult GetConfig(SmcArguments &args, bool kern) {
|
||||||
switch (static_cast<ConfigItem>(args.r[1])) {
|
switch (static_cast<ConfigItem>(args.r[1])) {
|
||||||
|
@ -240,11 +241,15 @@ namespace ams::secmon::smc {
|
||||||
break;
|
break;
|
||||||
case ConfigItem::ExosphereApiVersion:
|
case ConfigItem::ExosphereApiVersion:
|
||||||
/* Get information about the current exosphere version. */
|
/* Get information about the current exosphere version. */
|
||||||
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
|
if (kern || g_set_true_target_firmware) {
|
||||||
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
|
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
|
||||||
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
|
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
|
||||||
(static_cast<u64>(GetKeyGeneration()) << 32) |
|
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
|
||||||
(static_cast<u64>(GetTargetFirmware()) << 0);
|
(static_cast<u64>(GetKeyGeneration()) << 32) |
|
||||||
|
(static_cast<u64>(GetTargetFirmware()) << 0);
|
||||||
|
} else {
|
||||||
|
return SmcResult::NotInitialized;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ConfigItem::ExosphereNeedsReboot:
|
case ConfigItem::ExosphereNeedsReboot:
|
||||||
/* We are executing, so we aren't in the process of rebooting. */
|
/* We are executing, so we aren't in the process of rebooting. */
|
||||||
|
@ -297,6 +302,18 @@ namespace ams::secmon::smc {
|
||||||
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR & 0xFF) << 16) |
|
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR & 0xFF) << 16) |
|
||||||
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO & 0xFF) << 8);
|
(static_cast<u64>(ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO & 0xFF) << 8);
|
||||||
break;
|
break;
|
||||||
|
case ConfigItem::ExosphereApproximateApiVersion:
|
||||||
|
/* Get information about the current exosphere version. */
|
||||||
|
if (!g_set_true_target_firmware) {
|
||||||
|
args.r[1] = (static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR & 0xFF) << 56) |
|
||||||
|
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR & 0xFF) << 48) |
|
||||||
|
(static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO & 0xFF) << 40) |
|
||||||
|
(static_cast<u64>(GetKeyGeneration()) << 32) |
|
||||||
|
(static_cast<u64>(GetTargetFirmware()) << 0);
|
||||||
|
} else {
|
||||||
|
return SmcResult::Busy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return SmcResult::InvalidArgument;
|
return SmcResult::InvalidArgument;
|
||||||
}
|
}
|
||||||
|
@ -312,6 +329,14 @@ namespace ams::secmon::smc {
|
||||||
/* Configure the HiZ mode. */
|
/* Configure the HiZ mode. */
|
||||||
SetChargerHiZModeEnabled(static_cast<bool>(args.r[3]));
|
SetChargerHiZModeEnabled(static_cast<bool>(args.r[3]));
|
||||||
break;
|
break;
|
||||||
|
case ConfigItem::ExosphereApiVersion:
|
||||||
|
if (!g_set_true_target_firmware) {
|
||||||
|
::ams::secmon::impl::SetTargetFirmware(static_cast<ams::TargetFirmware>(args.r[3] & 0xFFFFFFFF));
|
||||||
|
g_set_true_target_firmware = true;
|
||||||
|
} else {
|
||||||
|
return SmcResult::Busy;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ConfigItem::ExosphereNeedsReboot:
|
case ConfigItem::ExosphereNeedsReboot:
|
||||||
if (soc_type == fuse::SocType_Erista) {
|
if (soc_type == fuse::SocType_Erista) {
|
||||||
switch (static_cast<UserRebootType>(args.r[3])) {
|
switch (static_cast<UserRebootType>(args.r[3])) {
|
||||||
|
|
|
@ -40,18 +40,19 @@ namespace ams::secmon::smc {
|
||||||
Package2Hash = 17,
|
Package2Hash = 17,
|
||||||
|
|
||||||
/* Extension config items for exosphere. */
|
/* Extension config items for exosphere. */
|
||||||
ExosphereApiVersion = 65000,
|
ExosphereApiVersion = 65000,
|
||||||
ExosphereNeedsReboot = 65001,
|
ExosphereNeedsReboot = 65001,
|
||||||
ExosphereNeedsShutdown = 65002,
|
ExosphereNeedsShutdown = 65002,
|
||||||
ExosphereGitCommitHash = 65003,
|
ExosphereGitCommitHash = 65003,
|
||||||
ExosphereHasRcmBugPatch = 65004,
|
ExosphereHasRcmBugPatch = 65004,
|
||||||
ExosphereBlankProdInfo = 65005,
|
ExosphereBlankProdInfo = 65005,
|
||||||
ExosphereAllowCalWrites = 65006,
|
ExosphereAllowCalWrites = 65006,
|
||||||
ExosphereEmummcType = 65007,
|
ExosphereEmummcType = 65007,
|
||||||
ExospherePayloadAddress = 65008,
|
ExospherePayloadAddress = 65008,
|
||||||
ExosphereLogConfiguration = 65009,
|
ExosphereLogConfiguration = 65009,
|
||||||
ExosphereForceEnableUsb30 = 65010,
|
ExosphereForceEnableUsb30 = 65010,
|
||||||
ExosphereSupportedHosVersion = 65011,
|
ExosphereSupportedHosVersion = 65011,
|
||||||
|
ExosphereApproximateApiVersion = 65012,
|
||||||
};
|
};
|
||||||
|
|
||||||
SmcResult SmcGetConfigUser(SmcArguments &args);
|
SmcResult SmcGetConfigUser(SmcArguments &args);
|
||||||
|
|
2
fusee/program/source/fatfs/fusee_diskio.cpp
vendored
2
fusee/program/source/fatfs/fusee_diskio.cpp
vendored
|
@ -27,7 +27,7 @@ bool diskio_write_sd_card(size_t sector_index, size_t sector_count, const void *
|
||||||
}
|
}
|
||||||
|
|
||||||
bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
bool diskio_read_system(void *dst, size_t size, size_t sector_index, size_t sector_count) {
|
||||||
return R_SUCCEEDED(::ams::nxboot::ReadSystem(sector_index * 0x200, dst, size));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
bool diskio_write_system(size_t sector_index, size_t sector_count, const void *src, size_t size) {
|
||||||
|
|
|
@ -27,10 +27,8 @@ namespace ams::fs {
|
||||||
constexpr size_t MaxDirectories = 2;
|
constexpr size_t MaxDirectories = 2;
|
||||||
|
|
||||||
constinit bool g_is_sd_mounted = false;
|
constinit bool g_is_sd_mounted = false;
|
||||||
constinit bool g_is_sys_mounted = false;
|
|
||||||
|
|
||||||
alignas(0x10) constinit FATFS g_sd_fs = {};
|
alignas(0x10) constinit FATFS g_sd_fs = {};
|
||||||
alignas(0x10) constinit FATFS g_sys_fs = {};
|
|
||||||
|
|
||||||
alignas(0x10) constinit FIL g_files[MaxFiles] = {};
|
alignas(0x10) constinit FIL g_files[MaxFiles] = {};
|
||||||
alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {};
|
alignas(0x10) constinit DIR g_dirs[MaxDirectories] = {};
|
||||||
|
@ -131,18 +129,6 @@ namespace ams::fs {
|
||||||
g_is_sd_mounted = false;
|
g_is_sd_mounted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MountSystem() {
|
|
||||||
AMS_ASSERT(!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 UnmountSystem() {
|
|
||||||
AMS_ASSERT(g_is_sys_mounted);
|
|
||||||
f_unmount("sys:");
|
|
||||||
g_is_sys_mounted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path) {
|
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path) {
|
||||||
/* Get the file info. */
|
/* Get the file info. */
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
|
|
|
@ -98,9 +98,6 @@ namespace ams::fs {
|
||||||
bool MountSdCard();
|
bool MountSdCard();
|
||||||
void UnmountSdCard();
|
void UnmountSdCard();
|
||||||
|
|
||||||
bool MountSystem();
|
|
||||||
void UnmountSystem();
|
|
||||||
|
|
||||||
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path);
|
Result GetEntryType(DirectoryEntryType *out_entry_type, bool *out_archive, const char *path);
|
||||||
|
|
||||||
Result CreateFile(const char *path, s64 size);
|
Result CreateFile(const char *path, s64 size);
|
||||||
|
|
|
@ -181,112 +181,6 @@ namespace ams::nxboot {
|
||||||
constinit fs::IStorage *g_boot0_storage = nullptr;
|
constinit fs::IStorage *g_boot0_storage = nullptr;
|
||||||
constinit fs::IStorage *g_user_storage = nullptr;
|
constinit fs::IStorage *g_user_storage = nullptr;
|
||||||
|
|
||||||
class SystemPartitionStorage : public fs::IStorage {
|
|
||||||
private:
|
|
||||||
static constexpr size_t CacheEntries = BITSIZEOF(u32);
|
|
||||||
static constexpr size_t SectorSize = 0x4000;
|
|
||||||
private:
|
|
||||||
fs::SubStorage m_storage;
|
|
||||||
u8 *m_sector_cache;
|
|
||||||
u32 *m_sector_ids;
|
|
||||||
u32 m_sector_flags;
|
|
||||||
u32 m_next_idx;
|
|
||||||
private:
|
|
||||||
Result LoadSector(u8 *sector, u32 sector_id) {
|
|
||||||
/* Read the sector data. */
|
|
||||||
R_TRY(m_storage.Read(static_cast<s64>(sector_id) * SectorSize, sector, SectorSize));
|
|
||||||
|
|
||||||
/* Decrypt the sector. */
|
|
||||||
se::DecryptAes128Xts(sector, SectorSize, pkg1::AesKeySlot_BootloaderSystem0, pkg1::AesKeySlot_BootloaderSystem1, sector, SectorSize, sector_id);
|
|
||||||
|
|
||||||
/* Mark the sector as freshly loaded. */
|
|
||||||
m_sector_flags &= ~(1u << (sector_id % CacheEntries));
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result GetSector(u8 **out_sector, u32 sector_id) {
|
|
||||||
/* Try to find in the cache. */
|
|
||||||
for (size_t i = 0; i < CacheEntries; ++i) {
|
|
||||||
if (m_sector_ids[i] == sector_id) {
|
|
||||||
m_sector_flags &= ~(1u << i);
|
|
||||||
*out_sector = m_sector_cache + SectorSize * i;
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find a sector to evict. */
|
|
||||||
while ((m_sector_flags & (1u << m_next_idx)) == 0) {
|
|
||||||
m_sector_flags |= (1u << m_next_idx);
|
|
||||||
m_next_idx = (m_next_idx + 1) % CacheEntries;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the chosen sector. */
|
|
||||||
*out_sector = m_sector_cache + SectorSize * m_next_idx;
|
|
||||||
m_next_idx = (m_next_idx + 1) % CacheEntries;
|
|
||||||
|
|
||||||
/* Load the sector. */
|
|
||||||
return this->LoadSector(*out_sector, sector_id);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
SystemPartitionStorage(s64 ofs, s64 size) : m_storage(*g_user_storage, ofs, size) {
|
|
||||||
/* Allocate sector cache. */
|
|
||||||
m_sector_cache = static_cast<u8 *>(AllocateAligned(CacheEntries * SectorSize, SectorSize));
|
|
||||||
|
|
||||||
/* Allocate sector ids. */
|
|
||||||
m_sector_ids = static_cast<u32 *>(AllocateAligned(CacheEntries * sizeof(u32), alignof(u32)));
|
|
||||||
for (size_t i = 0; i < CacheEntries; ++i) {
|
|
||||||
m_sector_ids[i] = std::numeric_limits<u32>::max();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* All sectors are dirty. */
|
|
||||||
m_sector_flags = ~0u;
|
|
||||||
|
|
||||||
/* Next sector is 0. */
|
|
||||||
m_next_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result Read(s64 offset, void *buffer, size_t size) override {
|
|
||||||
u32 sector_id = offset / SectorSize;
|
|
||||||
s64 subofs = offset % SectorSize;
|
|
||||||
|
|
||||||
u8 *cur_dst = static_cast<u8 *>(buffer);
|
|
||||||
while (size > 0) {
|
|
||||||
/* Get the current sector. */
|
|
||||||
u8 *sector;
|
|
||||||
R_TRY(this->GetSector(std::addressof(sector), sector_id++));
|
|
||||||
|
|
||||||
/* Copy the data. */
|
|
||||||
const size_t cur_size = std::min<size_t>(SectorSize - subofs, size);
|
|
||||||
std::memcpy(cur_dst, sector + subofs, cur_size);
|
|
||||||
|
|
||||||
/* Advance. */
|
|
||||||
cur_dst += cur_size;
|
|
||||||
size -= cur_size;
|
|
||||||
subofs = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultSuccess();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result Flush() override {
|
|
||||||
return m_storage.Flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result GetSize(s64 *out) override {
|
|
||||||
return m_storage.GetSize(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result Write(s64 offset, const void *buffer, size_t size) override {
|
|
||||||
return fs::ResultUnsupportedOperation();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Result SetSize(s64 size) override {
|
|
||||||
return fs::ResultUnsupportedOperation();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
constinit SystemPartitionStorage *g_system_storage = nullptr;
|
|
||||||
constinit fs::SubStorage *g_package2_storage = nullptr;
|
constinit fs::SubStorage *g_package2_storage = nullptr;
|
||||||
|
|
||||||
struct Guid {
|
struct Guid {
|
||||||
|
@ -333,10 +227,6 @@ namespace ams::nxboot {
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Gpt) == 16_KB + 0x200);
|
static_assert(sizeof(Gpt) == 16_KB + 0x200);
|
||||||
|
|
||||||
constexpr const u16 SystemPartitionName[] = {
|
|
||||||
'S', 'Y', 'S', 'T', 'E', 'M', 0
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr const u16 Package2PartitionName[] = {
|
constexpr const u16 Package2PartitionName[] = {
|
||||||
'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0
|
'B', 'C', 'P', 'K', 'G', '2', '-', '1', '-', 'N', 'o', 'r', 'm', 'a', 'l', '-', 'M', 'a', 'i', 'n', 0
|
||||||
};
|
};
|
||||||
|
@ -447,27 +337,15 @@ namespace ams::nxboot {
|
||||||
const s64 offset = INT64_C(0x200) * gpt->entries[i].starting_lba;
|
const s64 offset = INT64_C(0x200) * gpt->entries[i].starting_lba;
|
||||||
const u64 size = UINT64_C(0x200) * (gpt->entries[i].ending_lba + 1 - gpt->entries[i].starting_lba);
|
const u64 size = UINT64_C(0x200) * (gpt->entries[i].ending_lba + 1 - gpt->entries[i].starting_lba);
|
||||||
|
|
||||||
if (std::memcmp(gpt->entries[i].partition_name, SystemPartitionName, sizeof(SystemPartitionName)) == 0) {
|
if (std::memcmp(gpt->entries[i].partition_name, Package2PartitionName, sizeof(Package2PartitionName)) == 0) {
|
||||||
g_system_storage = AllocateObject<SystemPartitionStorage>(offset, size);
|
|
||||||
} else if (std::memcmp(gpt->entries[i].partition_name, Package2PartitionName, sizeof(Package2PartitionName)) == 0) {
|
|
||||||
g_package2_storage = AllocateObject<fs::SubStorage>(*g_user_storage, offset, size);
|
g_package2_storage = AllocateObject<fs::SubStorage>(*g_user_storage, offset, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that we created system storage. */
|
|
||||||
if (g_system_storage == nullptr) {
|
|
||||||
ShowFatalError("Failed to initialize SYSTEM\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check that we created package2 storage. */
|
/* Check that we created package2 storage. */
|
||||||
if (g_package2_storage == nullptr) {
|
if (g_package2_storage == nullptr) {
|
||||||
ShowFatalError("Failed to initialize Package2\n");
|
ShowFatalError("Failed to initialize Package2\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mount system. */
|
|
||||||
if (!fs::MountSystem()) {
|
|
||||||
ShowFatalError("Failed to mount SYSTEM\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ReadBoot0(s64 offset, void *dst, size_t size) {
|
Result ReadBoot0(s64 offset, void *dst, size_t size) {
|
||||||
|
@ -478,8 +356,4 @@ namespace ams::nxboot {
|
||||||
return g_package2_storage->Read(offset, dst, size);
|
return g_package2_storage->Read(offset, dst, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result ReadSystem(s64 offset, void *dst, size_t size) {
|
}
|
||||||
return g_system_storage->Read(offset, dst, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -118,26 +118,12 @@ namespace ams::nxboot {
|
||||||
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory;
|
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_Directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[maybe_unused]] bool IsFileExist(const char *path) {
|
bool IsFileExist(const char *path) {
|
||||||
fs::DirectoryEntryType entry_type;
|
fs::DirectoryEntryType entry_type;
|
||||||
bool archive;
|
bool archive;
|
||||||
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_File;
|
return R_SUCCEEDED(fs::GetEntryType(std::addressof(entry_type), std::addressof(archive), path)) && entry_type == fs::DirectoryEntryType_File;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsConcatenationFileExist(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_File) || (entry_type == fs::DirectoryEntryType_Directory && archive));
|
|
||||||
}
|
|
||||||
|
|
||||||
constinit char g_nca_path[0x40] = "sys:/contents/registered/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.nca";
|
|
||||||
|
|
||||||
bool IsNcaExist(const char *nca_name) {
|
|
||||||
std::memcpy(g_nca_path + 0x19, nca_name, 0x20);
|
|
||||||
|
|
||||||
return IsConcatenationFileExist(g_nca_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ConfigureEmummc() {
|
bool ConfigureEmummc() {
|
||||||
/* Set magic. */
|
/* Set magic. */
|
||||||
g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic;
|
g_emummc_cfg.base_cfg.magic = secmon::EmummcBaseConfiguration::Magic;
|
||||||
|
@ -220,143 +206,56 @@ namespace ams::nxboot {
|
||||||
return package1;
|
return package1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ams::TargetFirmware GetTargetFirmware(const u8 *package1) {
|
ams::TargetFirmware GetApproximateTargetFirmware(const u8 *package1) {
|
||||||
/* Get first an approximation of the target firmware. */
|
/* Get an approximation of the target firmware. */
|
||||||
ams::TargetFirmware target_firmware = ams::TargetFirmware_Current;
|
|
||||||
switch (package1[0x1F]) {
|
switch (package1[0x1F]) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
target_firmware = ams::TargetFirmware_1_0_0;
|
return ams::TargetFirmware_1_0_0;
|
||||||
break;
|
|
||||||
case 0x02:
|
case 0x02:
|
||||||
target_firmware = ams::TargetFirmware_2_0_0;
|
return ams::TargetFirmware_2_0_0;
|
||||||
break;
|
|
||||||
case 0x04:
|
case 0x04:
|
||||||
target_firmware = ams::TargetFirmware_3_0_0;
|
return ams::TargetFirmware_3_0_0;
|
||||||
break;
|
|
||||||
case 0x07:
|
case 0x07:
|
||||||
target_firmware = ams::TargetFirmware_4_0_0;
|
return ams::TargetFirmware_4_0_0;
|
||||||
break;
|
|
||||||
case 0x0B:
|
case 0x0B:
|
||||||
target_firmware = ams::TargetFirmware_5_0_0;
|
return ams::TargetFirmware_5_0_0;
|
||||||
break;
|
|
||||||
case 0x0E:
|
case 0x0E:
|
||||||
if (std::memcmp(package1 + 0x10, "20180802", 8) == 0) {
|
if (std::memcmp(package1 + 0x10, "20180802", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_6_0_0;
|
return ams::TargetFirmware_6_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20181107", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20181107", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_6_2_0;
|
return ams::TargetFirmware_6_2_0;
|
||||||
} else {
|
|
||||||
ShowFatalError("Unable to identify package1!\n");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x0F:
|
case 0x0F:
|
||||||
target_firmware = ams::TargetFirmware_7_0_0;
|
return ams::TargetFirmware_7_0_0;
|
||||||
break;
|
|
||||||
case 0x10:
|
case 0x10:
|
||||||
if (std::memcmp(package1 + 0x10, "20190314", 8) == 0) {
|
if (std::memcmp(package1 + 0x10, "20190314", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_8_0_0;
|
return ams::TargetFirmware_8_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20190531", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20190531", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_8_1_0;
|
return ams::TargetFirmware_8_1_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20190809", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20190809", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_9_0_0;
|
return ams::TargetFirmware_9_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20191021", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20191021", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_9_1_0;
|
return ams::TargetFirmware_9_1_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20200303", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20200303", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_10_0_0;
|
return ams::TargetFirmware_10_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20201030", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20201030", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_11_0_0;
|
return ams::TargetFirmware_11_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20210129", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20210129", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_12_0_0;
|
return ams::TargetFirmware_12_0_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20210422", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20210422", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_12_0_2;
|
return ams::TargetFirmware_12_0_2;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20210607", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20210607", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_12_1_0;
|
return ams::TargetFirmware_12_1_0;
|
||||||
} else if (std::memcmp(package1 + 0x10, "20210805", 8) == 0) {
|
} else if (std::memcmp(package1 + 0x10, "20210805", 8) == 0) {
|
||||||
target_firmware = ams::TargetFirmware_13_0_0;
|
return ams::TargetFirmware_13_0_0;
|
||||||
} else {
|
|
||||||
ShowFatalError("Unable to identify package1!\n");
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ShowFatalError("Unable to identify package1!\n");
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_NCA(NCA_ID, VERSION) do { if (IsNcaExist(NCA_ID)) { return ams::TargetFirmware_##VERSION; } } while(0)
|
ShowFatalError("Unable to identify package1!\n");
|
||||||
|
|
||||||
if (target_firmware >= ams::TargetFirmware_13_0_0) {
|
|
||||||
CHECK_NCA("bf2337ee88bd9f963a33b3ecbbc3732a", 13_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_12_1_0) {
|
|
||||||
CHECK_NCA("9d9d83d68d9517f245f3e8cd7f93c416", 12_1_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_12_0_2) {
|
|
||||||
CHECK_NCA("a1863a5c0e1cedd442f5e60b0422dc15", 12_0_3);
|
|
||||||
CHECK_NCA("63d928b5a3016fe8cc0e76d2f06f4e98", 12_0_2);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_12_0_0) {
|
|
||||||
CHECK_NCA("e65114b456f9d0b566a80e53bade2d89", 12_0_1);
|
|
||||||
CHECK_NCA("bd4185843550fbba125b20787005d1d2", 12_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_11_0_0) {
|
|
||||||
CHECK_NCA("56211c7a5ed20a5332f5cdda67121e37", 11_0_1);
|
|
||||||
CHECK_NCA("594c90bcdbcccad6b062eadba0cd0e7e", 11_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_10_0_0) {
|
|
||||||
CHECK_NCA("26325de4db3909e0ef2379787c7e671d", 10_2_0);
|
|
||||||
CHECK_NCA("5077973537f6735b564dd7475b779f87", 10_1_1); /* Exclusive to China. */
|
|
||||||
CHECK_NCA("fd1faed0ca750700d254c0915b93d506", 10_1_0);
|
|
||||||
CHECK_NCA("34728c771299443420820d8ae490ea41", 10_0_4);
|
|
||||||
CHECK_NCA("5b1df84f88c3334335bbb45d8522cbb4", 10_0_3);
|
|
||||||
CHECK_NCA("e951bc9dedcd54f65ffd83d4d050f9e0", 10_0_2);
|
|
||||||
CHECK_NCA("36ab1acf0c10a2beb9f7d472685f9a89", 10_0_1);
|
|
||||||
CHECK_NCA("5625cdc21d5f1ca52f6c36ba261505b9", 10_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_9_1_0) {
|
|
||||||
CHECK_NCA("09ef4d92bb47b33861e695ba524a2c17", 9_2_0);
|
|
||||||
CHECK_NCA("c5fbb49f2e3648c8cfca758020c53ecb", 9_1_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_9_0_0) {
|
|
||||||
CHECK_NCA("fd1ffb82dc1da76346343de22edbc97c", 9_0_1);
|
|
||||||
CHECK_NCA("a6af05b33f8f903aab90c8b0fcbcc6a4", 9_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_8_1_0) {
|
|
||||||
CHECK_NCA("724d9b432929ea43e787ad81bf09ae65", 8_1_1); /* 8.1.1-100 from Lite */
|
|
||||||
CHECK_NCA("e9bb0602e939270a9348bddd9b78827b", 8_1_1); /* 8.1.1-12 from chinese gamecard */
|
|
||||||
CHECK_NCA("7eedb7006ad855ec567114be601b2a9d", 8_1_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_8_0_0) {
|
|
||||||
CHECK_NCA("6c5426d27c40288302ad616307867eba", 8_0_1);
|
|
||||||
CHECK_NCA("4fe7b4abcea4a0bcc50975c1a926efcb", 8_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_7_0_0) {
|
|
||||||
CHECK_NCA("e6b22c40bb4fa66a151f1dc8db5a7b5c", 7_0_1);
|
|
||||||
CHECK_NCA("c613bd9660478de69bc8d0e2e7ea9949", 7_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_6_2_0) {
|
|
||||||
CHECK_NCA("6dfaaf1a3cebda6307aa770d9303d9b6", 6_2_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_6_0_0) {
|
|
||||||
CHECK_NCA("1d21680af5a034d626693674faf81b02", 6_1_0);
|
|
||||||
CHECK_NCA("663e74e45ffc86fbbaeb98045feea315", 6_0_1);
|
|
||||||
CHECK_NCA("258c1786b0f6844250f34d9c6f66095b", 6_0_0); /* Release 6.0.0-5.0 */
|
|
||||||
CHECK_NCA("286e30bafd7e4197df6551ad802dd815", 6_0_0); /* Pre-Release 6.0.0-4.0 */
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_5_0_0) {
|
|
||||||
CHECK_NCA("fce3b0ea366f9c95fe6498b69274b0e7", 5_1_0);
|
|
||||||
CHECK_NCA("c5758b0cb8c6512e8967e38842d35016", 5_0_2);
|
|
||||||
CHECK_NCA("53eb605d4620e8fd50064b24fd57783a", 5_0_1);
|
|
||||||
CHECK_NCA("09a2f9c16ce1c121ae6d231b35d17515", 5_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_4_0_0) {
|
|
||||||
CHECK_NCA("77e1ae7661ad8a718b9b13b70304aeea", 4_1_0);
|
|
||||||
CHECK_NCA("d0e5d20e3260f3083bcc067483b71274", 4_0_1);
|
|
||||||
CHECK_NCA("483a24ee3fd7149f9112d1931166a678", 4_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_3_0_0) {
|
|
||||||
CHECK_NCA("704129fc89e1fcb85c37b3112e51b0fc", 3_0_2);
|
|
||||||
CHECK_NCA("1fb00543307337d523ccefa9923e0c50", 3_0_1);
|
|
||||||
CHECK_NCA("6ebd3447473bade18badbeb5032af87d", 3_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_2_0_0) {
|
|
||||||
CHECK_NCA("d1c991c53a8a9038f8c3157a553d876d", 2_3_0);
|
|
||||||
CHECK_NCA("7f90353dff2d7ce69e19e07ebc0d5489", 2_2_0);
|
|
||||||
CHECK_NCA("e9b3e75fce00e52fe646156634d229b4", 2_1_0);
|
|
||||||
CHECK_NCA("7a1f79f8184d4b9bae1755090278f52c", 2_0_0);
|
|
||||||
} else if (target_firmware >= ams::TargetFirmware_1_0_0) {
|
|
||||||
CHECK_NCA("a1b287e07f8455e8192f13d0e45a2aaf", 1_0_0); /* 1.0.0 from Factory */
|
|
||||||
CHECK_NCA("117f7b9c7da3e8cef02340596af206b3", 1_0_0); /* 1.0.0 from Gamecard */
|
|
||||||
} else {
|
|
||||||
ShowFatalError("Unable to determine target firmware!\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CHECK_NCA
|
|
||||||
|
|
||||||
/* If we didn't find a more specific firmware, return our package1 approximation. */
|
|
||||||
return target_firmware;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 *LoadBootConfigAndPackage2() {
|
u8 *LoadBootConfigAndPackage2() {
|
||||||
|
@ -825,7 +724,7 @@ namespace ams::nxboot {
|
||||||
const u8 * const package1 = LoadPackage1(soc_type);
|
const u8 * const package1 = LoadPackage1(soc_type);
|
||||||
|
|
||||||
/* Get target firmware. */
|
/* Get target firmware. */
|
||||||
const auto target_firmware = GetTargetFirmware(package1);
|
const auto target_firmware = GetApproximateTargetFirmware(package1);
|
||||||
|
|
||||||
/* Read/decrypt package2. */
|
/* Read/decrypt package2. */
|
||||||
u8 * const package2 = LoadBootConfigAndPackage2();
|
u8 * const package2 = LoadBootConfigAndPackage2();
|
||||||
|
|
|
@ -70,6 +70,10 @@ namespace ams::secmon {
|
||||||
GetConfigurationContext().secmon_cfg.key_generation = generation;
|
GetConfigurationContext().secmon_cfg.key_generation = generation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ALWAYS_INLINE void SetTargetFirmware(ams::TargetFirmware target_firmware) {
|
||||||
|
GetConfigurationContext().secmon_cfg.target_firmware = target_firmware;
|
||||||
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
|
ALWAYS_INLINE pkg1::BootConfig *GetBootConfigStorage() {
|
||||||
return std::addressof(GetConfigurationContext().boot_config);
|
return std::addressof(GetConfigurationContext().boot_config);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,6 @@
|
||||||
AMS_SF_METHOD_INFO(C, H, 11, Result, ActivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 11, Result, ActivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 12, Result, InactivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 12, Result, InactivateContentMetaDatabase, (ncm::StorageId storage_id), (storage_id), hos::Version_2_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateRightsIdCache, (), (), hos::Version_9_0_0) \
|
AMS_SF_METHOD_INFO(C, H, 13, Result, InvalidateRightsIdCache, (), (), hos::Version_9_0_0) \
|
||||||
AMS_SF_METHOD_INFO(C, H, 14, Result, GetMemoryReport, (sf::Out<ncm::MemoryReport> out), (out), hos::Version_10_0_0)
|
AMS_SF_METHOD_INFO(C, H, 14, Result, GetMemoryReport, (sf::Out<ncm::MemoryReport> out), (out), hos::Version_10_0_0)
|
||||||
|
|
||||||
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentManager, AMS_NCM_I_CONTENT_MANAGER_INTERFACE_INFO);
|
AMS_SF_DEFINE_INTERFACE(ams::ncm, IContentManager, AMS_NCM_I_CONTENT_MANAGER_INTERFACE_INFO);
|
||||||
|
|
|
@ -39,6 +39,7 @@ namespace ams::spl {
|
||||||
Result DecryptAesKey(void *dst, size_t dst_size, const void *src, size_t src_size, s32 generation, u32 option);
|
Result DecryptAesKey(void *dst, size_t dst_size, const void *src, size_t src_size, s32 generation, u32 option);
|
||||||
|
|
||||||
Result GetConfig(u64 *out, ConfigItem item);
|
Result GetConfig(u64 *out, ConfigItem item);
|
||||||
|
Result SetConfig(ConfigItem item, u64 v);
|
||||||
bool IsDevelopment();
|
bool IsDevelopment();
|
||||||
MemoryArrangement GetMemoryArrangement();
|
MemoryArrangement GetMemoryArrangement();
|
||||||
|
|
||||||
|
|
|
@ -231,18 +231,19 @@ namespace ams::spl {
|
||||||
Package2Hash = 17,
|
Package2Hash = 17,
|
||||||
|
|
||||||
/* Extension config items for exosphere. */
|
/* Extension config items for exosphere. */
|
||||||
ExosphereApiVersion = 65000,
|
ExosphereApiVersion = 65000,
|
||||||
ExosphereNeedsReboot = 65001,
|
ExosphereNeedsReboot = 65001,
|
||||||
ExosphereNeedsShutdown = 65002,
|
ExosphereNeedsShutdown = 65002,
|
||||||
ExosphereGitCommitHash = 65003,
|
ExosphereGitCommitHash = 65003,
|
||||||
ExosphereHasRcmBugPatch = 65004,
|
ExosphereHasRcmBugPatch = 65004,
|
||||||
ExosphereBlankProdInfo = 65005,
|
ExosphereBlankProdInfo = 65005,
|
||||||
ExosphereAllowCalWrites = 65006,
|
ExosphereAllowCalWrites = 65006,
|
||||||
ExosphereEmummcType = 65007,
|
ExosphereEmummcType = 65007,
|
||||||
ExospherePayloadAddress = 65008,
|
ExospherePayloadAddress = 65008,
|
||||||
ExosphereLogConfiguration = 65009,
|
ExosphereLogConfiguration = 65009,
|
||||||
ExosphereForceEnableUsb30 = 65010,
|
ExosphereForceEnableUsb30 = 65010,
|
||||||
ExosphereSupportedHosVersion = 65011,
|
ExosphereSupportedHosVersion = 65011,
|
||||||
|
ExosphereApproximateApiVersion = 65012, /* NOTE: Internal use only. */
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "hos_version_api_private.hpp"
|
|
||||||
#include "../os/impl/os_rng_manager.hpp"
|
#include "../os/impl/os_rng_manager.hpp"
|
||||||
|
|
||||||
namespace ams::os {
|
namespace ams::os {
|
||||||
|
@ -34,23 +33,29 @@ extern "C" {
|
||||||
|
|
||||||
namespace ams::hos {
|
namespace ams::hos {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool CanAllowTemporaryApproximateVersion() {
|
||||||
|
/* Check if we're a program that can use a temporary approximate version. */
|
||||||
|
const auto program_id = os::GetCurrentProgramId();
|
||||||
|
|
||||||
|
return program_id == ncm::SystemProgramId::Pm || /* Needed so that boot has permissions to use fsp-srv. */
|
||||||
|
program_id == ncm::SystemProgramId::Sm || /* Needed so that boot can acquire fsp-srv. */
|
||||||
|
program_id == ncm::SystemProgramId::Boot || /* Needed so that boot can set the true target firmware. */
|
||||||
|
program_id == ncm::SystemProgramId::Spl || /* Needed so that FS can complete initialization. */
|
||||||
|
program_id == ncm::SystemProgramId::Ncm; /* Needed so that FS can determine where SystemVersion is located. */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeVersionInternal(bool allow_approximate);
|
||||||
|
|
||||||
void InitializeForStratosphere() {
|
void InitializeForStratosphere() {
|
||||||
/* Initialize the global os resource managers. This *must* be done before anything else in stratosphere. */
|
/* Initialize the global os resource managers. This *must* be done before anything else in stratosphere. */
|
||||||
os::InitializeForStratosphereInternal();
|
os::InitializeForStratosphereInternal();
|
||||||
|
|
||||||
/* Initialize hos::Version API. */
|
/* Initialize hos::Version API. */
|
||||||
hos::SetVersionForLibnxInternal();
|
hos::InitializeVersionInternal(CanAllowTemporaryApproximateVersion());
|
||||||
|
|
||||||
/* Check that we're running under mesosphere. */
|
|
||||||
AMS_ABORT_UNLESS(svc::IsKernelMesosphere());
|
|
||||||
}
|
|
||||||
|
|
||||||
void InitializeForStratosphereDebug(hos::Version debug_version) {
|
|
||||||
/* Initialize the global os resource managers. This *must* be done before anything else in stratosphere. */
|
|
||||||
os::InitializeForStratosphereInternal();
|
|
||||||
|
|
||||||
/* Initialize hos::Version API. */
|
|
||||||
hos::SetVersionForLibnxInternalDebug(debug_version);
|
|
||||||
|
|
||||||
/* Check that we're running under mesosphere. */
|
/* Check that we're running under mesosphere. */
|
||||||
AMS_ABORT_UNLESS(svc::IsKernelMesosphere());
|
AMS_ABORT_UNLESS(svc::IsKernelMesosphere());
|
||||||
|
|
|
@ -14,69 +14,139 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <stratosphere.hpp>
|
#include <stratosphere.hpp>
|
||||||
#include "hos_version_api_private.hpp"
|
|
||||||
|
|
||||||
namespace ams::hos {
|
namespace ams::hos {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
hos::Version g_hos_version;
|
constinit os::SdkMutex g_hos_init_lock;
|
||||||
bool g_has_cached;
|
constinit hos::Version g_hos_version;
|
||||||
os::SdkMutex g_mutex;
|
constinit bool g_set_hos_version;
|
||||||
|
|
||||||
void CacheValues() {
|
Result GetExosphereApiInfo(exosphere::ApiInfo *out) {
|
||||||
if (__atomic_load_n(&g_has_cached, __ATOMIC_SEQ_CST)) {
|
u64 exosphere_cfg;
|
||||||
return;
|
R_TRY_CATCH(spl::impl::GetConfig(std::addressof(exosphere_cfg), spl::ConfigItem::ExosphereApiVersion)) {
|
||||||
|
R_CATCH_RETHROW(spl::ResultSecureMonitorNotInitialized)
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
|
||||||
|
*out = { exosphere_cfg };
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result GetApproximateExosphereApiInfo(exosphere::ApiInfo *out) {
|
||||||
|
u64 exosphere_cfg;
|
||||||
|
|
||||||
|
R_TRY_CATCH(spl::impl::GetConfig(std::addressof(exosphere_cfg), spl::ConfigItem::ExosphereApproximateApiVersion)) {
|
||||||
|
R_CATCH_RETHROW(spl::ResultSecureMonitorBusy)
|
||||||
|
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
|
||||||
|
|
||||||
|
*out = { exosphere_cfg };
|
||||||
|
return ResultSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
exosphere::ApiInfo GetExosphereApiInfo(bool allow_approximate) {
|
||||||
|
exosphere::ApiInfo info;
|
||||||
|
while (true) {
|
||||||
|
if (R_SUCCEEDED(GetExosphereApiInfo(std::addressof(info)))) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allow_approximate && R_SUCCEEDED(GetApproximateExosphereApiInfo(std::addressof(info)))) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
svc::SleepThread(TimeSpan::FromMilliSeconds(25).GetNanoSeconds());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::scoped_lock lk(g_mutex);
|
settings::FirmwareVersion GetSettingsFirmwareVersion() {
|
||||||
|
/* Mount the system version title. */
|
||||||
|
R_ABORT_UNLESS(ams::fs::MountSystemData("sysver", ncm::SystemDataId::SystemVersion));
|
||||||
|
ON_SCOPE_EXIT { ams::fs::Unmount("sysver"); };
|
||||||
|
|
||||||
if (g_has_cached) {
|
/* Read the firmware version file. */
|
||||||
return;
|
ams::fs::FileHandle file;
|
||||||
}
|
R_ABORT_UNLESS(ams::fs::OpenFile(std::addressof(file), "sysver:/file", fs::OpenMode_Read));
|
||||||
|
ON_SCOPE_EXIT { ams::fs::CloseFile(file); };
|
||||||
|
|
||||||
/* Hos version is a direct copy of target firmware, just renamed. */
|
/* Must be possible to read firmware version from file. */
|
||||||
g_hos_version = static_cast<hos::Version>(exosphere::GetApiInfo().GetTargetFirmware());
|
settings::FirmwareVersion firmware_version;
|
||||||
|
R_ABORT_UNLESS(ams::fs::ReadFile(file, 0, std::addressof(firmware_version), sizeof(firmware_version)));
|
||||||
|
|
||||||
/* Ensure that this is a hos version we can sanely *try* to run. */
|
return firmware_version;
|
||||||
/* To be friendly, we will only require that we recognize the major and minor versions. */
|
|
||||||
/* We can consider only recognizing major in the future, but micro seems safe to ignore as */
|
|
||||||
/* there are no breaking IPC changes in minor updates. */
|
|
||||||
{
|
|
||||||
constexpr u32 MaxMajor = (static_cast<u32>(hos::Version_Max) >> 24) & 0xFF;
|
|
||||||
constexpr u32 MaxMinor = (static_cast<u32>(hos::Version_Max) >> 16) & 0xFF;
|
|
||||||
|
|
||||||
const u32 major = (static_cast<u32>(g_hos_version) >> 24) & 0xFF;
|
|
||||||
const u32 minor = (static_cast<u32>(g_hos_version) >> 16) & 0xFF;
|
|
||||||
|
|
||||||
const bool is_safely_tryable_version = (g_hos_version <= hos::Version_Max) || (major == MaxMajor && minor <= MaxMinor);
|
|
||||||
AMS_ABORT_UNLESS(is_safely_tryable_version);
|
|
||||||
}
|
|
||||||
|
|
||||||
__atomic_store_n(&g_has_cached, true, __ATOMIC_SEQ_CST);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitializeVersionInternal(bool allow_approximate) {
|
||||||
|
/* Get the current (and previous approximation of) target firmware. */
|
||||||
|
hos::Version prev, current;
|
||||||
|
bool has_prev = false;
|
||||||
|
{
|
||||||
|
/* Acquire exclusive access to set hos version. */
|
||||||
|
std::scoped_lock lk(g_hos_init_lock);
|
||||||
|
|
||||||
|
/* Save the previous value of g_hos_version. */
|
||||||
|
prev = g_hos_version;
|
||||||
|
has_prev = g_set_hos_version;
|
||||||
|
|
||||||
|
/* Set hos version = exosphere api version target firmware. */
|
||||||
|
g_hos_version = static_cast<hos::Version>(GetExosphereApiInfo(allow_approximate).GetTargetFirmware());
|
||||||
|
|
||||||
|
/* Save the current value of g_hos_version. */
|
||||||
|
current = g_hos_version;
|
||||||
|
|
||||||
|
/* Note that we've set a previous hos version. */
|
||||||
|
g_set_hos_version = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that this is a hos version we can sanely *try* to run. */
|
||||||
|
/* To be friendly, we will only require that we recognize the major and minor versions. */
|
||||||
|
/* We can consider only recognizing major in the future, but micro seems safe to ignore as */
|
||||||
|
/* there are no breaking IPC changes in minor updates. */
|
||||||
|
{
|
||||||
|
constexpr u32 MaxMajor = (static_cast<u32>(hos::Version_Max) >> 24) & 0xFF;
|
||||||
|
constexpr u32 MaxMinor = (static_cast<u32>(hos::Version_Max) >> 16) & 0xFF;
|
||||||
|
|
||||||
|
const u32 major = (static_cast<u32>(current) >> 24) & 0xFF;
|
||||||
|
const u32 minor = (static_cast<u32>(current) >> 16) & 0xFF;
|
||||||
|
|
||||||
|
const bool is_safely_tryable_version = (current <= hos::Version_Max) || (major == MaxMajor && minor <= MaxMinor);
|
||||||
|
AMS_ABORT_UNLESS(is_safely_tryable_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure that this is a hos version compatible with previous approximations. */
|
||||||
|
if (has_prev) {
|
||||||
|
AMS_ABORT_UNLESS(current >= prev);
|
||||||
|
|
||||||
|
const u32 current_major = (static_cast<u32>(current) >> 24) & 0xFF;
|
||||||
|
const u32 prev_major = (static_cast<u32>(prev) >> 24) & 0xFF;
|
||||||
|
|
||||||
|
AMS_ABORT_UNLESS(current_major == prev_major);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the version for libnx. */
|
||||||
|
{
|
||||||
|
const u32 major = (static_cast<u32>(current) >> 24) & 0xFF;
|
||||||
|
const u32 minor = (static_cast<u32>(current) >> 16) & 0xFF;
|
||||||
|
const u32 micro = (static_cast<u32>(current) >> 8) & 0xFF;
|
||||||
|
hosversionSet((BIT(31)) | (MAKEHOSVERSION(major, minor, micro)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNonApproximateVersionInternal() {
|
||||||
|
/* Get the settings . */
|
||||||
|
const auto firmware_version = GetSettingsFirmwareVersion();
|
||||||
|
|
||||||
|
/* Set the exosphere api version. */
|
||||||
|
R_ABORT_UNLESS(spl::SetConfig(spl::ConfigItem::ExosphereApiVersion, (static_cast<u32>(firmware_version.major) << 24) | (static_cast<u32>(firmware_version.minor) << 16) | (static_cast<u32>(firmware_version.micro) << 8)));
|
||||||
|
|
||||||
|
/* Update our own version value. */
|
||||||
|
InitializeVersionInternal(false);
|
||||||
|
}
|
||||||
|
|
||||||
::ams::hos::Version GetVersion() {
|
::ams::hos::Version GetVersion() {
|
||||||
CacheValues();
|
|
||||||
return g_hos_version;
|
return g_hos_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void SetVersionForLibnxInternalDebug(hos::Version debug_version) {
|
|
||||||
std::scoped_lock lk(g_mutex);
|
|
||||||
g_hos_version = debug_version;
|
|
||||||
__atomic_store_n(&g_has_cached, true, __ATOMIC_SEQ_CST);
|
|
||||||
SetVersionForLibnxInternal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVersionForLibnxInternal() {
|
|
||||||
const u32 hos_version_val = static_cast<u32>(hos::GetVersion());
|
|
||||||
const u32 major = (hos_version_val >> 24) & 0xFF;
|
|
||||||
const u32 minor = (hos_version_val >> 16) & 0xFF;
|
|
||||||
const u32 micro = (hos_version_val >> 8) & 0xFF;
|
|
||||||
hosversionSet((BIT(31)) | (MAKEHOSVERSION(major, minor, micro)));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
#include <stratosphere.hpp>
|
|
||||||
|
|
||||||
namespace ams::hos {
|
|
||||||
|
|
||||||
void SetVersionForLibnxInternal();
|
|
||||||
void SetVersionForLibnxInternalDebug(hos::Version debug_version);
|
|
||||||
|
|
||||||
}
|
|
|
@ -35,6 +35,7 @@ namespace ams::powctl::impl::board::nintendo::nx {
|
||||||
|
|
||||||
if (AMS_LIKELY(!g_constructed_max17050_driver)) {
|
if (AMS_LIKELY(!g_constructed_max17050_driver)) {
|
||||||
util::ConstructAt(g_max17050_driver);
|
util::ConstructAt(g_max17050_driver);
|
||||||
|
g_constructed_max17050_driver = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace ams::powctl::impl::board::nintendo::nx {
|
||||||
|
|
||||||
if (AMS_LIKELY(!g_constructed_bq24193_driver)) {
|
if (AMS_LIKELY(!g_constructed_bq24193_driver)) {
|
||||||
util::ConstructAt(g_bq24193_driver);
|
util::ConstructAt(g_bq24193_driver);
|
||||||
|
g_constructed_bq24193_driver = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,12 @@
|
||||||
#include "spl_device_address_mapper.hpp"
|
#include "spl_device_address_mapper.hpp"
|
||||||
#include "spl_key_slot_cache.hpp"
|
#include "spl_key_slot_cache.hpp"
|
||||||
|
|
||||||
|
namespace ams::hos {
|
||||||
|
|
||||||
|
void InitializeVersionInternal(bool allow_approximate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace ams::spl::impl {
|
namespace ams::spl::impl {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -536,7 +542,13 @@ namespace ams::spl::impl {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result SetConfig(ConfigItem key, u64 value) {
|
Result SetConfig(ConfigItem key, u64 value) {
|
||||||
return smc::ConvertResult(smc::SetConfig(key, value));
|
R_TRY(smc::ConvertResult(smc::SetConfig(key, value)));
|
||||||
|
|
||||||
|
/* Work around for temporary version. */
|
||||||
|
if (key == ConfigItem::ExosphereApiVersion) {
|
||||||
|
hos::InitializeVersionInternal(false);
|
||||||
|
}
|
||||||
|
return ResultSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result GenerateRandomBytes(void *out, size_t size) {
|
Result GenerateRandomBytes(void *out, size_t size) {
|
||||||
|
|
|
@ -216,6 +216,10 @@ namespace ams::spl {
|
||||||
return splGetConfig(static_cast<::SplConfigItem>(item), out);
|
return splGetConfig(static_cast<::SplConfigItem>(item), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result SetConfig(ConfigItem item, u64 v) {
|
||||||
|
return splSetConfig(static_cast<::SplConfigItem>(item), v);
|
||||||
|
}
|
||||||
|
|
||||||
bool IsDevelopment() {
|
bool IsDevelopment() {
|
||||||
bool is_dev;
|
bool is_dev;
|
||||||
R_ABORT_UNLESS(splIsDevelopment(std::addressof(is_dev)));
|
R_ABORT_UNLESS(splIsDevelopment(std::addressof(is_dev)));
|
||||||
|
|
|
@ -123,7 +123,8 @@ namespace ams::mitm::bpc {
|
||||||
std::memcpy(g_reboot_payload, payload, payload_size);
|
std::memcpy(g_reboot_payload, payload, payload_size);
|
||||||
|
|
||||||
/* Note to the secure monitor that we have a payload. */
|
/* Note to the secure monitor that we have a payload. */
|
||||||
spl::smc::SetConfig(spl::ConfigItem::ExospherePayloadAddress, g_reboot_payload, nullptr, 0);
|
spl::smc::AsyncOperationKey dummy;
|
||||||
|
spl::smc::SetConfig(std::addressof(dummy), spl::ConfigItem::ExospherePayloadAddress, nullptr, 0, g_reboot_payload);
|
||||||
|
|
||||||
/* NOTE: Preferred reboot type may be overrwritten when parsed from settings during boot. */
|
/* NOTE: Preferred reboot type may be overrwritten when parsed from settings during boot. */
|
||||||
g_reboot_type = RebootType::ToPayload;
|
g_reboot_type = RebootType::ToPayload;
|
||||||
|
|
|
@ -68,21 +68,31 @@ namespace ams {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
|
||||||
|
void SetNonApproximateVersionInternal();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace init {
|
namespace init {
|
||||||
|
|
||||||
void InitializeSystemModule() {
|
void InitializeSystemModule() {
|
||||||
/* Initialize heaps. */
|
/* Initialize heaps. */
|
||||||
boot::InitializeHeaps();
|
boot::InitializeHeaps();
|
||||||
|
|
||||||
/* Set fs allocator. */
|
/* Connect to sm. */
|
||||||
fs::SetAllocator(boot::Allocate, boot::Deallocate);
|
|
||||||
|
|
||||||
/* Initialize services we need. */
|
|
||||||
R_ABORT_UNLESS(sm::Initialize());
|
R_ABORT_UNLESS(sm::Initialize());
|
||||||
|
|
||||||
|
/* Initialize fs. */
|
||||||
fs::InitializeForSystem();
|
fs::InitializeForSystem();
|
||||||
|
fs::SetAllocator(boot::Allocate, boot::Deallocate);
|
||||||
|
fs::SetEnabledAutoAbort(false);
|
||||||
|
|
||||||
|
/* Initialize spl. */
|
||||||
spl::Initialize();
|
spl::Initialize();
|
||||||
R_ABORT_UNLESS(pmshellInitialize());
|
|
||||||
|
/* Set the true hos version. */
|
||||||
|
hos::SetNonApproximateVersionInternal();
|
||||||
|
|
||||||
/* Verify that we can sanely execute. */
|
/* Verify that we can sanely execute. */
|
||||||
ams::CheckApiVersion();
|
ams::CheckApiVersion();
|
||||||
|
@ -174,6 +184,7 @@ namespace ams {
|
||||||
boot::FinalizeGpioDriverLibrary();
|
boot::FinalizeGpioDriverLibrary();
|
||||||
|
|
||||||
/* Tell PM to start boot2. */
|
/* Tell PM to start boot2. */
|
||||||
|
R_ABORT_UNLESS(pmshellInitialize());
|
||||||
R_ABORT_UNLESS(pmshellNotifyBootFinished());
|
R_ABORT_UNLESS(pmshellNotifyBootFinished());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -195,9 +195,6 @@ namespace ams {
|
||||||
|
|
||||||
/* Initialize our connection to sm. */
|
/* Initialize our connection to sm. */
|
||||||
R_ABORT_UNLESS(sm::Initialize());
|
R_ABORT_UNLESS(sm::Initialize());
|
||||||
|
|
||||||
/* Verify that we can sanely execute. */
|
|
||||||
ams::CheckApiVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeSystemModule() { /* ... */ }
|
void FinalizeSystemModule() { /* ... */ }
|
||||||
|
|
|
@ -165,6 +165,12 @@ namespace ams {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace hos {
|
||||||
|
|
||||||
|
void InitializeVersionInternal(bool allow_approximate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace init {
|
namespace init {
|
||||||
|
|
||||||
void InitializeSystemModule() {
|
void InitializeSystemModule() {
|
||||||
|
@ -182,6 +188,12 @@ namespace ams {
|
||||||
/* Use our manager extension to tell SM that the FS bug has been worked around. */
|
/* Use our manager extension to tell SM that the FS bug has been worked around. */
|
||||||
R_ABORT_UNLESS(sm::manager::EndInitialDefers());
|
R_ABORT_UNLESS(sm::manager::EndInitialDefers());
|
||||||
|
|
||||||
|
/* Wait for the true hos version to be available. */
|
||||||
|
hos::InitializeVersionInternal(false);
|
||||||
|
|
||||||
|
/* Now that the true hos version is available, we should once more end defers (alerting sm to the available hos version). */
|
||||||
|
R_ABORT_UNLESS(sm::manager::EndInitialDefers());
|
||||||
|
|
||||||
/* Initialize remaining services we need. */
|
/* Initialize remaining services we need. */
|
||||||
R_ABORT_UNLESS(ldrPmInitialize());
|
R_ABORT_UNLESS(ldrPmInitialize());
|
||||||
spl::Initialize();
|
spl::Initialize();
|
||||||
|
|
|
@ -17,6 +17,12 @@
|
||||||
#include "sm_service_manager.hpp"
|
#include "sm_service_manager.hpp"
|
||||||
#include "../sm_wait_list.hpp"
|
#include "../sm_wait_list.hpp"
|
||||||
|
|
||||||
|
namespace ams::hos {
|
||||||
|
|
||||||
|
void InitializeVersionInternal(bool allow_approximate);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
namespace ams::sm::impl {
|
namespace ams::sm::impl {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -862,8 +868,12 @@ namespace ams::sm::impl {
|
||||||
std::scoped_lock lk(g_mutex);
|
std::scoped_lock lk(g_mutex);
|
||||||
|
|
||||||
/* Note that we have ended the initial deferral period. */
|
/* Note that we have ended the initial deferral period. */
|
||||||
|
const bool had_ended_defers = g_ended_initial_defers;
|
||||||
g_ended_initial_defers = true;
|
g_ended_initial_defers = true;
|
||||||
|
|
||||||
|
/* Something about deferral state has changed, so we should refresh our hos version. */
|
||||||
|
hos::InitializeVersionInternal(!had_ended_defers);
|
||||||
|
|
||||||
/* This might undefer some requests. */
|
/* This might undefer some requests. */
|
||||||
for (const auto &service_name : InitiallyDeferredServices) {
|
for (const auto &service_name : InitiallyDeferredServices) {
|
||||||
TriggerResume(service_name);
|
TriggerResume(service_name);
|
||||||
|
|
|
@ -162,9 +162,6 @@ namespace ams {
|
||||||
void InitializeSystemModule() {
|
void InitializeSystemModule() {
|
||||||
/* Initialize our connection to sm. */
|
/* Initialize our connection to sm. */
|
||||||
R_ABORT_UNLESS(sm::Initialize());
|
R_ABORT_UNLESS(sm::Initialize());
|
||||||
|
|
||||||
/* Verify that we can sanely execute. */
|
|
||||||
ams::CheckApiVersion();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FinalizeSystemModule() { /* ... */ }
|
void FinalizeSystemModule() { /* ... */ }
|
||||||
|
|
Loading…
Reference in a new issue