mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
fusee_cpp: implement ips patching of kips
This commit is contained in:
parent
07779b787a
commit
c5d021c172
7 changed files with 253 additions and 42 deletions
|
@ -17,18 +17,6 @@ SECTIONS
|
|||
BYTE(00);
|
||||
} >main AT>glob
|
||||
|
||||
.ovl_data :
|
||||
{
|
||||
FILL(0x00000000)
|
||||
fusee_mtc_erista.o(SORT(.data*));
|
||||
fusee_mtc_erista.o(SORT(.bss*));
|
||||
fusee_mtc_mariko.o(SORT(.data*));
|
||||
fusee_mtc_mariko.o(SORT(.bss*));
|
||||
. = ALIGN(16);
|
||||
. = . + 15;
|
||||
BYTE(00);
|
||||
} >main AT>glob
|
||||
|
||||
.text :
|
||||
{
|
||||
FILL(0x00000000)
|
||||
|
|
|
@ -26,6 +26,8 @@ SECTIONS {
|
|||
KEEP(*(.text._ZN3ams6nxboot22DoMemoryTrainingEristaEiPv))
|
||||
fusee_mtc_erista.o(.text*);
|
||||
fusee_mtc_erista.o(SORT(.rodata*));
|
||||
fusee_mtc_erista.o(SORT(.data*));
|
||||
fusee_mtc_erista.o(SORT(.bss*));
|
||||
FILL(0x00000000)
|
||||
. = ORIGIN(ovl) + LENGTH(ovl) - 1;
|
||||
BYTE(0x00);
|
||||
|
@ -34,6 +36,8 @@ SECTIONS {
|
|||
KEEP(*(.text._ZN3ams6nxboot22DoMemoryTrainingMarikoEPbiPv))
|
||||
fusee_mtc_mariko.o(.text*);
|
||||
fusee_mtc_mariko.o(SORT(.rodata*));
|
||||
fusee_mtc_mariko.o(SORT(.data*));
|
||||
fusee_mtc_mariko.o(SORT(.bss*));
|
||||
FILL(0x00000000)
|
||||
. = ORIGIN(ovl) + LENGTH(ovl) - 1;
|
||||
BYTE(0x00);
|
||||
|
|
|
@ -110,6 +110,9 @@ namespace ams::nxboot {
|
|||
/* Read the rest of the archive file. */
|
||||
ReadFullSecondaryArchive();
|
||||
|
||||
/* Save the memory training overlay. */
|
||||
SaveMemoryTrainingOverlay();
|
||||
|
||||
/* Initialize display (splash screen will be visible from this point onwards). */
|
||||
InitializeDisplay();
|
||||
ShowDisplay();
|
||||
|
@ -120,6 +123,12 @@ namespace ams::nxboot {
|
|||
/* Perform rest of the boot process. */
|
||||
SetupAndStartHorizon();
|
||||
|
||||
/* Restore the memory training overlay. */
|
||||
RestoreMemoryTrainingOverlay();
|
||||
|
||||
/* Restore memory clock rate. */
|
||||
RestoreMemoryClockRate();
|
||||
|
||||
/* Finalize display. */
|
||||
FinalizeDisplay();
|
||||
|
||||
|
|
|
@ -49,4 +49,22 @@ namespace ams::nxboot {
|
|||
}
|
||||
}
|
||||
|
||||
void SaveMemoryTrainingOverlay() {
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
/* NOTE: Erista does not do memory clock restoration. */
|
||||
/* std::memcpy(const_cast<u8 *>(GetSecondaryArchive().ovl_mtc_erista), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||
} else {
|
||||
std::memcpy(const_cast<u8 *>(GetSecondaryArchive().ovl_mtc_mariko), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_mariko));
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreMemoryTrainingOverlay() {
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
/* NOTE: Erista does not do memory clock restoration. */
|
||||
/* std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_erista, sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||
} else {
|
||||
std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_mariko, sizeof(SecondaryArchive{}.ovl_mtc_mariko));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -26,4 +26,7 @@ namespace ams::nxboot {
|
|||
|
||||
void LoadOverlay(fs::FileHandle archive_file, OverlayId ovl);
|
||||
|
||||
void SaveMemoryTrainingOverlay();
|
||||
void RestoreMemoryTrainingOverlay();
|
||||
|
||||
}
|
||||
|
|
|
@ -85,11 +85,11 @@ namespace ams::nxboot {
|
|||
x <<= 4;
|
||||
|
||||
if ('0' <= c && c <= '9') {
|
||||
x |= c - '0';
|
||||
x |= (c - '0');
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
x |= c - 'a';
|
||||
x |= (c - 'a') + 10;
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
x |= c - 'A';
|
||||
x |= (c - 'A') + 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ namespace ams::nxboot {
|
|||
|
||||
struct PatchMeta {
|
||||
PatchMeta *next;
|
||||
bool is_memset;
|
||||
u32 start_segment;
|
||||
u32 rel_offset;
|
||||
const void *data;
|
||||
|
@ -321,6 +322,15 @@ namespace ams::nxboot {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
InitialProcessMeta *FindInitialProcess(const se::Sha256Hash &hash) {
|
||||
for (InitialProcessMeta *cur = std::addressof(g_initial_process_meta); cur != nullptr; cur = cur->next) {
|
||||
if (std::memcmp(std::addressof(cur->kip_hash), std::addressof(hash), sizeof(hash)) == 0) {
|
||||
return cur;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 GetPatchSegments(const InitialProcessHeader *kip, u32 offset, size_t size) {
|
||||
/* Create segment mask. */
|
||||
u32 segments = 0;
|
||||
|
@ -360,7 +370,7 @@ namespace ams::nxboot {
|
|||
return segments;
|
||||
}
|
||||
|
||||
void AddPatch(InitialProcessMeta *meta, u32 offset, const void *data, size_t data_size) {
|
||||
void AddPatch(InitialProcessMeta *meta, u32 offset, const void *data, size_t data_size, bool is_memset = false) {
|
||||
/* Determine the segment. */
|
||||
const u32 segments = GetPatchSegments(meta->kip, offset, data_size);
|
||||
|
||||
|
@ -385,6 +395,7 @@ namespace ams::nxboot {
|
|||
auto *new_patch = static_cast<PatchMeta *>(AllocateAligned(sizeof(PatchMeta), alignof(PatchMeta)));
|
||||
|
||||
new_patch->next = nullptr;
|
||||
new_patch->is_memset = is_memset;
|
||||
new_patch->start_segment = start_segment;
|
||||
new_patch->rel_offset = offset;
|
||||
new_patch->data = data;
|
||||
|
@ -400,6 +411,78 @@ namespace ams::nxboot {
|
|||
meta->patches_tail = new_patch;
|
||||
}
|
||||
|
||||
void AddIps24PatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
||||
while (size > 0) {
|
||||
/* Read offset, stopping at EOF */
|
||||
const u32 offset = (static_cast<u32>(ips[0]) << 16) | (static_cast<u32>(ips[1]) << 8) | (static_cast<u32>(ips[2]) << 0);
|
||||
if (offset == 0x454F46) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read size. */
|
||||
const u16 cur_size = (static_cast<u32>(ips[3]) << 8) | (static_cast<u32>(ips[4]) << 0);
|
||||
|
||||
if (cur_size > 0) {
|
||||
/* Add patch. */
|
||||
AddPatch(meta, offset, ips + 5, cur_size, false);
|
||||
|
||||
/* Advance. */
|
||||
ips += (5 + cur_size);
|
||||
size -= (5 + cur_size);
|
||||
} else {
|
||||
/* Read RLE size */
|
||||
const u16 rle_size = (static_cast<u32>(ips[5]) << 8) | (static_cast<u32>(ips[6]) << 0);
|
||||
|
||||
/* Add patch. */
|
||||
AddPatch(meta, offset, ips + 7, rle_size, true);
|
||||
|
||||
/* Advance. */
|
||||
ips += 8;
|
||||
size -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddIps32PatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
||||
while (size > 0) {
|
||||
/* Read offset, stopping at EOF */
|
||||
const u32 offset = (static_cast<u32>(ips[0]) << 24) | (static_cast<u32>(ips[1]) << 16) | (static_cast<u32>(ips[2]) << 8) | (static_cast<u32>(ips[3]) << 0);
|
||||
if (offset == 0x45454F46) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read size. */
|
||||
const u16 cur_size = (static_cast<u32>(ips[4]) << 8) | (static_cast<u32>(ips[5]) << 0);
|
||||
|
||||
if (cur_size > 0) {
|
||||
/* Add patch. */
|
||||
AddPatch(meta, offset, ips + 6, cur_size, false);
|
||||
|
||||
/* Advance. */
|
||||
ips += (6 + cur_size);
|
||||
size -= (6 + cur_size);
|
||||
} else {
|
||||
/* Read RLE size */
|
||||
const u16 rle_size = (static_cast<u32>(ips[6]) << 8) | (static_cast<u32>(ips[7]) << 0);
|
||||
|
||||
/* Add patch. */
|
||||
AddPatch(meta, offset, ips + 8, rle_size, true);
|
||||
|
||||
/* Advance. */
|
||||
ips += 9;
|
||||
size -= 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddIpsPatchToKip(InitialProcessMeta *meta, const u8 *ips, s32 size) {
|
||||
if (std::memcmp(ips, "PATCH", 5) == 0) {
|
||||
AddIps24PatchToKip(meta, ips + 5, size - 5);
|
||||
} else if (std::memcmp(ips, "IPS32", 5) == 0) {
|
||||
AddIps32PatchToKip(meta, ips + 5, size - 5);
|
||||
}
|
||||
}
|
||||
|
||||
constexpr const u8 NogcPatch0[] = {
|
||||
0x80
|
||||
};
|
||||
|
@ -508,6 +591,32 @@ namespace ams::nxboot {
|
|||
}
|
||||
}
|
||||
|
||||
void *ReadFile(s64 *out_size, const char *path, size_t align = 0x10) {
|
||||
fs::FileHandle file;
|
||||
if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) {
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
Result result;
|
||||
|
||||
/* Get the kip size. */
|
||||
if (R_FAILED((result = fs::GetFileSize(out_size, file)))) {
|
||||
ShowFatalError("Failed to get size (0x%08" PRIx32 ") of %s!\n", result.GetValue(), path);
|
||||
}
|
||||
|
||||
/* Allocate file. */
|
||||
void *data = AllocateAligned(*out_size, std::max<size_t>(align, 0x10));
|
||||
|
||||
/* Read the file. */
|
||||
if (R_FAILED((result = fs::ReadFile(file, 0, data, *out_size)))) {
|
||||
ShowFatalError("Failed to read (0x%08" PRIx32 ") %s!\n", result.GetValue(), path);
|
||||
}
|
||||
|
||||
return data;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled) {
|
||||
|
@ -524,6 +633,11 @@ namespace ams::nxboot {
|
|||
s64 count;
|
||||
fs::DirectoryEntry entries[1];
|
||||
while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, kip_dir, util::size(entries))) && count > 0) {
|
||||
/* Check that file is a file. */
|
||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_File) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get filename length. */
|
||||
const int name_len = std::strlen(entries[0].file_name);
|
||||
|
||||
|
@ -537,32 +651,9 @@ namespace ams::nxboot {
|
|||
continue;
|
||||
}
|
||||
|
||||
/* Check that file is a file. */
|
||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_File) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Open the kip. */
|
||||
fs::FileHandle kip_file;
|
||||
if (R_SUCCEEDED(fs::OpenFile(std::addressof(kip_file), kip_path, fs::OpenMode_Read))) {
|
||||
ON_SCOPE_EXIT { fs::CloseFile(kip_file); };
|
||||
|
||||
Result result;
|
||||
|
||||
/* Get the kip size. */
|
||||
s64 file_size;
|
||||
if (R_FAILED((result = fs::GetFileSize(std::addressof(file_size), kip_file)))) {
|
||||
ShowFatalError("Failed to get size (0x%08" PRIx32 ") of %s!\n", result.GetValue(), kip_path);
|
||||
}
|
||||
|
||||
/* Allocate kip. */
|
||||
InitialProcessHeader *kip = static_cast<InitialProcessHeader *>(AllocateAligned(file_size, alignof(InitialProcessHeader)));
|
||||
|
||||
/* Read the kip. */
|
||||
if (R_FAILED((result = fs::ReadFile(kip_file, 0, kip, file_size)))) {
|
||||
ShowFatalError("Failed to read (0x%08" PRIx32 ") %s!\n", result.GetValue(), kip_path);
|
||||
}
|
||||
|
||||
s64 file_size;
|
||||
if (InitialProcessHeader *kip = static_cast<InitialProcessHeader *>(ReadFile(std::addressof(file_size), kip_path, alignof(InitialProcessHeader))); kip != nullptr) {
|
||||
/* If the kip is valid, add it. */
|
||||
if (kip->magic == InitialProcessHeader::Magic && file_size == GetInitialProcessSize(kip)) {
|
||||
AddInitialProcess(kip);
|
||||
|
@ -630,6 +721,104 @@ namespace ams::nxboot {
|
|||
}
|
||||
|
||||
/* Add generic patches. */
|
||||
{
|
||||
/* Create patch path. */
|
||||
char patch_path[0x220];
|
||||
std::memcpy(patch_path, "sdmc:/atmosphere/kip_patches", 0x1D);
|
||||
|
||||
fs::DirectoryHandle patch_root_dir;
|
||||
if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(patch_root_dir), patch_path))) {
|
||||
ON_SCOPE_EXIT { fs::CloseDirectory(patch_root_dir); };
|
||||
|
||||
s64 count;
|
||||
fs::DirectoryEntry entries[1];
|
||||
while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, patch_root_dir, util::size(entries))) && count > 0) {
|
||||
/* Check that dir is a dir. */
|
||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_Directory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* For compatibility, ignore the old "default_nogc" patches. */
|
||||
if (std::strcmp(entries[0].file_name, "default_nogc") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get filename length. */
|
||||
const int dir_len = std::strlen(entries[0].file_name);
|
||||
|
||||
/* Adjust patch path. */
|
||||
patch_path[0x1C] = '/';
|
||||
std::memcpy(patch_path + 0x1D, entries[0].file_name, dir_len + 1);
|
||||
|
||||
/* Try to open the patch subdirectory. */
|
||||
fs::DirectoryHandle patch_dir;
|
||||
if (R_SUCCEEDED(fs::OpenDirectory(std::addressof(patch_dir), patch_path))) {
|
||||
ON_SCOPE_EXIT { fs::CloseDirectory(patch_dir); };
|
||||
|
||||
/* Read patches. */
|
||||
while (R_SUCCEEDED(fs::ReadDirectory(std::addressof(count), entries, patch_dir, util::size(entries))) && count > 0) {
|
||||
/* Check that file is a file. */
|
||||
if (fs::GetEntryType(entries[0]) != fs::DirectoryEntryType_File) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get filename length. */
|
||||
const int name_len = std::strlen(entries[0].file_name);
|
||||
|
||||
/* Adjust patch path. */
|
||||
patch_path[0x1D + dir_len] = '/';
|
||||
std::memcpy(patch_path + 0x1D + dir_len + 1, entries[0].file_name, name_len + 1);
|
||||
|
||||
/* Check that file is "{hex}.ips" file. */
|
||||
const int path_len = 0x1D + dir_len + 1 + name_len;
|
||||
if (name_len != 0x44 || std::memcmp(patch_path + path_len - 4, ".ips", 5) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check that the filename is hex. */
|
||||
bool valid_name = true;
|
||||
se::Sha256Hash patch_name = {};
|
||||
u32 shift = 4;
|
||||
for (int i = 0; i < name_len - 4; ++i) {
|
||||
const char c = entries[0].file_name[i];
|
||||
|
||||
u8 val;
|
||||
if ('0' <= c && c <= '9') {
|
||||
val = (c - '0');
|
||||
} else if ('a' <= c && c <= 'f') {
|
||||
val = (c - 'a') + 10;
|
||||
} else if ('A' <= c && c <= 'F') {
|
||||
val = (c - 'A') + 10;
|
||||
} else {
|
||||
valid_name = false;
|
||||
break;
|
||||
}
|
||||
|
||||
patch_name.bytes[i >> 1] |= val << shift;
|
||||
shift ^= 4;
|
||||
}
|
||||
|
||||
/* Ignore invalid patches. */
|
||||
if (!valid_name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find kip for the patch. */
|
||||
auto *kip_meta = FindInitialProcess(patch_name);
|
||||
if (kip_meta == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read the ips patch. */
|
||||
s64 file_size;
|
||||
if (u8 *ips = static_cast<u8 *>(ReadFile(std::addressof(file_size), patch_path)); ips != nullptr) {
|
||||
AddIpsPatchToKip(kip_meta, ips, static_cast<s32>(file_size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the fs version we're using. */
|
||||
|
|
Loading…
Reference in a new issue