mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-17 17:36:44 +00:00
fusee_cpp: implement nogc patches
This commit is contained in:
parent
cefdda77e5
commit
07779b787a
4 changed files with 334 additions and 20 deletions
|
@ -32,6 +32,10 @@ namespace ams::nxboot {
|
||||||
|
|
||||||
NORETURN void ExceptionHandlerImpl(s32 which, u32 lr, u32 svc_lr) {
|
NORETURN void ExceptionHandlerImpl(s32 which, u32 lr, u32 svc_lr) {
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
*reinterpret_cast<volatile u32 *>(0x40038004) = 0xCAFEBABE;
|
||||||
|
*reinterpret_cast<volatile u32 *>(0x40038008) = which;
|
||||||
|
*reinterpret_cast<volatile u32 *>(0x4003800C) = lr;
|
||||||
|
*reinterpret_cast<volatile u32 *>(0x40038010) = svc_lr;
|
||||||
ErrorStop();
|
ErrorStop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
namespace ams::nxboot {
|
namespace ams::nxboot {
|
||||||
|
|
||||||
constexpr inline const size_t SecondaryArchiveSize = 4_MB + FrameBufferSize;
|
constexpr inline const size_t SecondaryArchiveSize = 8_MB;
|
||||||
|
|
||||||
constexpr inline const size_t InitialProcessStorageSizeMax = 3_MB / 8;
|
constexpr inline const size_t InitialProcessStorageSizeMax = 3_MB / 8;
|
||||||
|
|
||||||
|
@ -46,12 +46,12 @@ namespace ams::nxboot {
|
||||||
|
|
||||||
u32 reserved0; /* Previously entrypoint. */
|
u32 reserved0; /* Previously entrypoint. */
|
||||||
u32 metadata_offset;
|
u32 metadata_offset;
|
||||||
u32 reserved1;
|
u32 flags;
|
||||||
u32 num_kips;
|
u32 num_kips;
|
||||||
u32 reserved2[4];
|
u32 reserved1[4];
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 total_size;
|
u32 total_size;
|
||||||
u32 reserved3; /* Previously crt0 offset. */
|
u32 reserved2; /* Previously crt0 offset. */
|
||||||
u32 content_header_offset;
|
u32 content_header_offset;
|
||||||
u32 num_content_headers;
|
u32 num_content_headers;
|
||||||
u32 supported_hos_version;
|
u32 supported_hos_version;
|
||||||
|
@ -60,7 +60,7 @@ namespace ams::nxboot {
|
||||||
SecondaryArchiveContentMeta content_metas[(0x400 - 0x40) / sizeof(SecondaryArchiveContentMeta)];
|
SecondaryArchiveContentMeta content_metas[(0x400 - 0x40) / sizeof(SecondaryArchiveContentMeta)];
|
||||||
SecondaryArchiveKipMeta emummc_meta;
|
SecondaryArchiveKipMeta emummc_meta;
|
||||||
SecondaryArchiveKipMeta kip_metas[8];
|
SecondaryArchiveKipMeta kip_metas[8];
|
||||||
u8 reserved4[0x800 - (0x400 + 9 * sizeof(SecondaryArchiveKipMeta))];
|
u8 reserved3[0x800 - (0x400 + 9 * sizeof(SecondaryArchiveKipMeta))];
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SecondaryArchiveHeader) == 0x800);
|
static_assert(sizeof(SecondaryArchiveHeader) == 0x800);
|
||||||
|
|
||||||
|
@ -75,6 +75,9 @@ namespace ams::nxboot {
|
||||||
u8 mesosphere[0xAA000]; /* 0x056000-0x100000 */
|
u8 mesosphere[0xAA000]; /* 0x056000-0x100000 */
|
||||||
u8 kips[3_MB]; /* 0x100000-0x400000 */
|
u8 kips[3_MB]; /* 0x100000-0x400000 */
|
||||||
u8 splash_screen_fb[FrameBufferSize]; /* 0x400000-0x7C0000 */
|
u8 splash_screen_fb[FrameBufferSize]; /* 0x400000-0x7C0000 */
|
||||||
|
u8 fusee[0x20000]; /* 0x7C0000-0x7E0000 */
|
||||||
|
u8 reboot_stub[0x1000]; /* 0x7E0000-0x7E1000 */
|
||||||
|
u8 reserved[0x1F000]; /* 0x7E1000-0x800000 */
|
||||||
};
|
};
|
||||||
static_assert(sizeof(SecondaryArchive) == SecondaryArchiveSize);
|
static_assert(sizeof(SecondaryArchive) == SecondaryArchiveSize);
|
||||||
|
|
||||||
|
|
|
@ -64,8 +64,10 @@ namespace ams::nxboot {
|
||||||
static_assert(sizeof(InitialProcessHeader) == 0x100);
|
static_assert(sizeof(InitialProcessHeader) == 0x100);
|
||||||
|
|
||||||
struct PatchMeta {
|
struct PatchMeta {
|
||||||
u32 offset;
|
PatchMeta *next;
|
||||||
void *data;
|
u32 start_segment;
|
||||||
|
u32 rel_offset;
|
||||||
|
const void *data;
|
||||||
u32 size;
|
u32 size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,7 +75,8 @@ namespace ams::nxboot {
|
||||||
InitialProcessMeta *next = nullptr;
|
InitialProcessMeta *next = nullptr;
|
||||||
const InitialProcessHeader *kip;
|
const InitialProcessHeader *kip;
|
||||||
u32 kip_size;
|
u32 kip_size;
|
||||||
PatchMeta *patches;
|
PatchMeta *patches_head;
|
||||||
|
PatchMeta *patches_tail;
|
||||||
u32 patch_segments;
|
u32 patch_segments;
|
||||||
u64 program_id;
|
u64 program_id;
|
||||||
se::Sha256Hash kip_hash;
|
se::Sha256Hash kip_hash;
|
||||||
|
@ -271,7 +274,8 @@ namespace ams::nxboot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear patches. */
|
/* Clear patches. */
|
||||||
meta->patches = nullptr;
|
meta->patches_head = nullptr;
|
||||||
|
meta->patches_tail = nullptr;
|
||||||
meta->patch_segments = 0;
|
meta->patch_segments = 0;
|
||||||
|
|
||||||
/* Increase the initial process binary's size. */
|
/* Increase the initial process binary's size. */
|
||||||
|
@ -308,8 +312,8 @@ namespace ams::nxboot {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InitialProcessMeta *FindInitialProcess(u64 program_id) {
|
InitialProcessMeta *FindInitialProcess(u64 program_id) {
|
||||||
for (const InitialProcessMeta *cur = std::addressof(g_initial_process_meta); cur != nullptr; cur = cur->next) {
|
for (InitialProcessMeta *cur = std::addressof(g_initial_process_meta); cur != nullptr; cur = cur->next) {
|
||||||
if (cur->program_id == program_id) {
|
if (cur->program_id == program_id) {
|
||||||
return cur;
|
return cur;
|
||||||
}
|
}
|
||||||
|
@ -317,6 +321,193 @@ namespace ams::nxboot {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 GetPatchSegments(const InitialProcessHeader *kip, u32 offset, size_t size) {
|
||||||
|
/* Create segment mask. */
|
||||||
|
u32 segments = 0;
|
||||||
|
|
||||||
|
/* Get the segment extents. */
|
||||||
|
const u32 rx_start = kip->rx_address;
|
||||||
|
const u32 ro_start = kip->ro_address;
|
||||||
|
const u32 rw_start = kip->rw_address;
|
||||||
|
const u32 rx_end = ro_start;
|
||||||
|
const u32 ro_end = rw_start;
|
||||||
|
const u32 rw_end = rw_start + kip->rw_size;
|
||||||
|
|
||||||
|
/* If the offset is below the kip header, ignore it. */
|
||||||
|
if (offset < sizeof(*kip)) {
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust the offset in bounds. */
|
||||||
|
offset -= sizeof(*kip);
|
||||||
|
|
||||||
|
/* Check if the offset strays out of bounds. */
|
||||||
|
if (offset + size > rw_end) {
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set bits for the affected segments. */
|
||||||
|
if (util::HasOverlap(offset, size, rx_start, rx_end - rx_start)) {
|
||||||
|
segments |= (1 << 0);
|
||||||
|
}
|
||||||
|
if (util::HasOverlap(offset, size, ro_start, ro_end - ro_start)) {
|
||||||
|
segments |= (1 << 1);
|
||||||
|
}
|
||||||
|
if (util::HasOverlap(offset, size, rw_start, rw_end - rw_start)) {
|
||||||
|
segments |= (1 << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddPatch(InitialProcessMeta *meta, u32 offset, const void *data, size_t data_size) {
|
||||||
|
/* Determine the segment. */
|
||||||
|
const u32 segments = GetPatchSegments(meta->kip, offset, data_size);
|
||||||
|
|
||||||
|
/* If the patch hits no segments, we don't need it. */
|
||||||
|
if (segments == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update patch segments. */
|
||||||
|
meta->patch_segments |= segments;
|
||||||
|
|
||||||
|
/* Adjust offset. */
|
||||||
|
const u32 start_segment = util::CountTrailingZeros(segments);
|
||||||
|
offset -= sizeof(*meta->kip);
|
||||||
|
switch (start_segment) {
|
||||||
|
case 0: offset -= meta->kip->rx_address; break;
|
||||||
|
case 1: offset -= meta->kip->ro_address; break;
|
||||||
|
case 2: offset -= meta->kip->rw_address; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create patch. */
|
||||||
|
auto *new_patch = static_cast<PatchMeta *>(AllocateAligned(sizeof(PatchMeta), alignof(PatchMeta)));
|
||||||
|
|
||||||
|
new_patch->next = nullptr;
|
||||||
|
new_patch->start_segment = start_segment;
|
||||||
|
new_patch->rel_offset = offset;
|
||||||
|
new_patch->data = data;
|
||||||
|
new_patch->size = data_size;
|
||||||
|
|
||||||
|
/* Add the patch. */
|
||||||
|
if (meta->patches_head == nullptr) {
|
||||||
|
meta->patches_head = new_patch;
|
||||||
|
} else {
|
||||||
|
meta->patches_tail->next = new_patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
meta->patches_tail = new_patch;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const u8 NogcPatch0[] = {
|
||||||
|
0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr const u8 NogcPatch1[] = {
|
||||||
|
0xE0, 0x03, 0x1F, 0x2A, 0xC0, 0x03, 0x5F, 0xD6,
|
||||||
|
};
|
||||||
|
|
||||||
|
void AddNogcPatches(InitialProcessMeta *fs_meta, FsVersion fs_version) {
|
||||||
|
switch (fs_version) {
|
||||||
|
case FsVersion_1_0_0:
|
||||||
|
case FsVersion_2_0_0:
|
||||||
|
case FsVersion_2_0_0_Exfat:
|
||||||
|
case FsVersion_2_1_0:
|
||||||
|
case FsVersion_2_1_0_Exfat:
|
||||||
|
case FsVersion_3_0_0:
|
||||||
|
case FsVersion_3_0_0_Exfat:
|
||||||
|
case FsVersion_3_0_1:
|
||||||
|
case FsVersion_3_0_1_Exfat:
|
||||||
|
/* There were no lotus firmware updates prior to 4.0.0. */
|
||||||
|
/* TODO: Implement patches, regardless? */
|
||||||
|
break;
|
||||||
|
case FsVersion_4_0_0:
|
||||||
|
case FsVersion_4_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x0A3539, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x0AAC44, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_4_1_0:
|
||||||
|
case FsVersion_4_1_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x0A35BD, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x0AACA8, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_5_0_0:
|
||||||
|
case FsVersion_5_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x0CF4C5, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x0D74A0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_5_1_0:
|
||||||
|
case FsVersion_5_1_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x0CF895, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x0D7870, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_6_0_0:
|
||||||
|
AddPatch(fs_meta, 0x1539F5, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x12CD20, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_6_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x15F0F5, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x138420, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_7_0_0:
|
||||||
|
AddPatch(fs_meta, 0x15C005, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x134260, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_7_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x1675B5, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x13F810, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_8_0_0:
|
||||||
|
case FsVersion_8_1_0:
|
||||||
|
AddPatch(fs_meta, 0x15EC95, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x136900, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_8_0_0_Exfat:
|
||||||
|
case FsVersion_8_1_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x16A245, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x141EB0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_9_0_0:
|
||||||
|
case FsVersion_9_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x143369, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x129520, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_9_1_0:
|
||||||
|
case FsVersion_9_1_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x143379, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x129530, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_10_0_0:
|
||||||
|
case FsVersion_10_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x14DF09, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x13BF90, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_10_2_0:
|
||||||
|
case FsVersion_10_2_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x14E369, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x13C3F0, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_11_0_0:
|
||||||
|
case FsVersion_11_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x156FB9, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x1399B4, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_12_0_0:
|
||||||
|
case FsVersion_12_0_0_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x155469, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x13EB24, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
case FsVersion_12_0_3:
|
||||||
|
case FsVersion_12_0_3_Exfat:
|
||||||
|
AddPatch(fs_meta, 0x155579, NogcPatch0, sizeof(NogcPatch0));
|
||||||
|
AddPatch(fs_meta, 0x13EC34, NogcPatch1, sizeof(NogcPatch1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled) {
|
u32 ConfigureStratosphere(const u8 *nn_package2, ams::TargetFirmware target_firmware, bool emummc_enabled, bool nogc_enabled) {
|
||||||
|
@ -393,7 +584,7 @@ namespace ams::nxboot {
|
||||||
|
|
||||||
/* Get meta for FS process. */
|
/* Get meta for FS process. */
|
||||||
constexpr u64 FsProgramId = 0x0100000000000000;
|
constexpr u64 FsProgramId = 0x0100000000000000;
|
||||||
const auto *fs_meta = FindInitialProcess(FsProgramId);
|
auto *fs_meta = FindInitialProcess(FsProgramId);
|
||||||
if (fs_meta == nullptr) {
|
if (fs_meta == nullptr) {
|
||||||
/* Get nintendo header/data. */
|
/* Get nintendo header/data. */
|
||||||
const pkg2::Package2Header *nn_header = reinterpret_cast<const pkg2::Package2Header *>(nn_package2);
|
const pkg2::Package2Header *nn_header = reinterpret_cast<const pkg2::Package2Header *>(nn_package2);
|
||||||
|
@ -431,7 +622,15 @@ namespace ams::nxboot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: Parse/prepare relevant nogc/kip patches. */
|
/* Parse/prepare relevant nogc/kip patches. */
|
||||||
|
{
|
||||||
|
/* Add nogc patches. */
|
||||||
|
if (nogc_enabled) {
|
||||||
|
AddNogcPatches(fs_meta, fs_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add generic patches. */
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the fs version we're using. */
|
/* Return the fs version we're using. */
|
||||||
return static_cast<u32>(fs_version);
|
return static_cast<u32>(fs_version);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
import sys, lz4
|
import sys, lz4, hashlib
|
||||||
from struct import unpack as up
|
from struct import unpack as up, pack as pk
|
||||||
|
|
||||||
def lz4_compress(data):
|
def lz4_compress(data):
|
||||||
try:
|
try:
|
||||||
|
@ -20,6 +20,105 @@ def pad(data, size):
|
||||||
def get_overlay(program, i):
|
def get_overlay(program, i):
|
||||||
return program[0x2B000 + 0x14000 * i:0x2B000 + 0x14000 * (i+1)]
|
return program[0x2B000 + 0x14000 * i:0x2B000 + 0x14000 * (i+1)]
|
||||||
|
|
||||||
|
KIP_NAMES = ['Loader', 'NCM', 'ProcessManager', 'sm', 'boot', 'spl', 'ams_mitm']
|
||||||
|
|
||||||
|
def get_kips():
|
||||||
|
emummc = read_file('../../../../emummc/emummc.kip')
|
||||||
|
loader = read_file('../../../../stratosphere/loader/loader.kip')
|
||||||
|
ncm = read_file('../../../../stratosphere/ncm/ncm.kip')
|
||||||
|
pm = read_file('../../../../stratosphere/pm/pm.kip')
|
||||||
|
sm = read_file('../../../../stratosphere/sm/sm.kip')
|
||||||
|
boot = read_file('../../../../stratosphere/boot/boot.kip')
|
||||||
|
spl = read_file('../../../../stratosphere/spl/spl.kip')
|
||||||
|
ams_mitm = read_file('../../../../stratosphere/ams_mitm/ams_mitm.kip')
|
||||||
|
return (emummc, {
|
||||||
|
'Loader' : loader,
|
||||||
|
'NCM' : ncm,
|
||||||
|
'ProcessManager' : pm,
|
||||||
|
'sm' : sm,
|
||||||
|
'boot' : boot,
|
||||||
|
'spl' : spl,
|
||||||
|
'ams_mitm' : ams_mitm,
|
||||||
|
})
|
||||||
|
|
||||||
|
def write_kip_meta(f, kip, ofs):
|
||||||
|
# Write program id
|
||||||
|
f.write(kip[0x10:0x18])
|
||||||
|
# Write offset, size
|
||||||
|
f.write(pk('<II', ofs, len(kip)))
|
||||||
|
# Write hash
|
||||||
|
f.write(hashlib.sha256(kip).digest())
|
||||||
|
|
||||||
|
def write_header(f, all_kips):
|
||||||
|
# Unpack kips
|
||||||
|
emummc, kips = all_kips
|
||||||
|
# Write reserved0 (previously entrypoint) as infinite loop instruction.
|
||||||
|
f.write(pk('<I', 0xEAFFFFFE))
|
||||||
|
# Write metadata offset = 0x10
|
||||||
|
f.write(pk('<I', 0x20))
|
||||||
|
# Write flags
|
||||||
|
f.write(pk('<I', 0x00000000))
|
||||||
|
# Write num_kips
|
||||||
|
f.write(pk('<I', len(KIP_NAMES)))
|
||||||
|
# Write reserved2
|
||||||
|
f.write(b'\xCC' * 0x10)
|
||||||
|
# Write magic
|
||||||
|
f.write('FSS0')
|
||||||
|
# Write total size
|
||||||
|
f.write(pk('<I', 0x800000))
|
||||||
|
# Write reserved3
|
||||||
|
f.write(pk('<I', 0xCCCCCCCC))
|
||||||
|
# Write content_header_offset
|
||||||
|
f.write(pk('<I', 0x40))
|
||||||
|
# Write num_content_headers;
|
||||||
|
f.write(pk('<I', 8 + len(KIP_NAMES)))
|
||||||
|
# Write supported_hos_version;
|
||||||
|
f.write(pk('<I', 0xCCCCCCCC)) # TODO
|
||||||
|
# Write release_version;
|
||||||
|
f.write(pk('<I', 0xCCCCCCCC)) # TODO
|
||||||
|
# Write git_revision;
|
||||||
|
f.write(pk('<I', 0xCCCCCCCC)) # TODO
|
||||||
|
# Write content metas
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x000800, 0x001800, 2, 0, 0, 0, 0xCCCCCCCC, 'warmboot'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x002000, 0x002000, 12, 0, 0, 0, 0xCCCCCCCC, 'tsec_keygen'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x004000, 0x01C000, 11, 0, 0, 0, 0xCCCCCCCC, 'exosphere_fatal'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x048000, 0x00E000, 1, 0, 0, 0, 0xCCCCCCCC, 'exosphere'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x056000, 0x0AA000, 10, 0, 0, 0, 0xCCCCCCCC, 'mesosphere'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x7C0000, 0x020000, 0, 0, 0, 0, 0xCCCCCCCC, 'fusee'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x7E0000, 0x001000, 3, 0, 0, 0, 0xCCCCCCCC, 'rebootstub'))
|
||||||
|
f.write(pk('<IIBBBBI16s', 0x100000, len(emummc), 8, 0, 0, 0, 0xCCCCCCCC, 'emummc'))
|
||||||
|
ofs = 0x100000 + len(emummc)
|
||||||
|
for kip_name in KIP_NAMES:
|
||||||
|
kip_data = kips[kip_name]
|
||||||
|
f.write(pk('<IIBBBBI16s', ofs, len(kip_data), 6, 0, 0, 0, 0xCCCCCCCC, kip_name))
|
||||||
|
ofs += len(kip_data)
|
||||||
|
# Pad to kip metas.
|
||||||
|
f.write(b'\xCC' * (0x400 - 0x40 - (0x20 * (8 + len(KIP_NAMES)))))
|
||||||
|
# Write emummc_meta. */
|
||||||
|
write_kip_meta(f, emummc, 0x100000)
|
||||||
|
# Write kip metas
|
||||||
|
ofs = 0x100000 + len(emummc)
|
||||||
|
for kip_name in KIP_NAMES:
|
||||||
|
kip_data = kips[kip_name]
|
||||||
|
write_kip_meta(f, kip_data, ofs)
|
||||||
|
ofs += len(kip_data)
|
||||||
|
# Pad to end of header
|
||||||
|
f.write(b'\xCC' * (0x800 - (0x400 + (1 + len(KIP_NAMES)) * 0x30)))
|
||||||
|
|
||||||
|
def write_kips(f, all_kips):
|
||||||
|
# Unpack kips
|
||||||
|
emummc, kips = all_kips
|
||||||
|
# Write emummc
|
||||||
|
f.write(emummc)
|
||||||
|
# Write kips
|
||||||
|
tot = len(emummc)
|
||||||
|
for kip_name in KIP_NAMES:
|
||||||
|
kip_data = kips[kip_name]
|
||||||
|
f.write(kip_data)
|
||||||
|
tot += len(kip_data)
|
||||||
|
# Pad to 3 MB
|
||||||
|
f.write(b'\xCC' * (0x300000 - tot))
|
||||||
|
|
||||||
def main(argc, argv):
|
def main(argc, argv):
|
||||||
if argc == 2:
|
if argc == 2:
|
||||||
target = argv[1]
|
target = argv[1]
|
||||||
|
@ -30,13 +129,15 @@ def main(argc, argv):
|
||||||
else:
|
else:
|
||||||
print('Usage: %s target' % argv[0])
|
print('Usage: %s target' % argv[0])
|
||||||
return 1
|
return 1
|
||||||
|
all_kips = get_kips()
|
||||||
with open('../../program%s.bin' % target, 'rb') as f:
|
with open('../../program%s.bin' % target, 'rb') as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
|
fusee_program = lz4_compress(data[:0x2B000] + get_overlay(data, 0)[:0x11000])
|
||||||
with open('../../program%s.lz4' % target, 'wb') as f:
|
with open('../../program%s.lz4' % target, 'wb') as f:
|
||||||
f.write(lz4_compress(data[:0x2B000] + get_overlay(data, 0)[:0x11000]))
|
f.write(fusee_program)
|
||||||
with open('../../fusee-boogaloo%s.bin' % target, 'wb') as f:
|
with open('../../fusee-boogaloo%s.bin' % target, 'wb') as f:
|
||||||
# TODO: Write header
|
# Write header
|
||||||
f.write('\xCC'*0x800)
|
write_header(f, all_kips)
|
||||||
# Write warmboot
|
# Write warmboot
|
||||||
f.write(pad(read_file('../../../../exosphere/warmboot%s.bin' % target), 0x1800))
|
f.write(pad(read_file('../../../../exosphere/warmboot%s.bin' % target), 0x1800))
|
||||||
# Write TSEC Keygen
|
# Write TSEC Keygen
|
||||||
|
@ -51,10 +152,17 @@ def main(argc, argv):
|
||||||
f.write(pad(read_file('../../../../exosphere/exosphere%s.bin' % target), 0xE000))
|
f.write(pad(read_file('../../../../exosphere/exosphere%s.bin' % target), 0xE000))
|
||||||
# Write mesosphere
|
# Write mesosphere
|
||||||
f.write(pad(read_file('../../../../mesosphere/mesosphere%s.bin' % target), 0xAA000))
|
f.write(pad(read_file('../../../../mesosphere/mesosphere%s.bin' % target), 0xAA000))
|
||||||
# TODO: Write kips
|
# Write kips
|
||||||
f.write('\xCC'*0x300000)
|
write_kips(f, all_kips)
|
||||||
# Write Splash Screen
|
# Write Splash Screen
|
||||||
f.write(pad(read_file('../../splash_screen/splash_screen.bin'), 0x3C0000))
|
f.write(pad(read_file('../../splash_screen/splash_screen.bin'), 0x3C0000))
|
||||||
|
# Write fusee
|
||||||
|
f.write(pad(fusee_program, 0x20000))
|
||||||
|
# Write rebootstub
|
||||||
|
f.write(pad(read_file('../../../../exosphere/program/rebootstub/rebootstub%s.bin' % target), 0x1000))
|
||||||
|
# Pad to 8 MB
|
||||||
|
f.write(b'\xCC' * (0x800000 - 0x7E1000))
|
||||||
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue