mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-19 08:52:25 +00:00
fusee_cpp: implement package2 rebuild/kip patching
This commit is contained in:
parent
968ced677e
commit
e5106ffa2c
10 changed files with 330 additions and 19 deletions
emummc
exosphere/program/source/boot
fusee_cpp/program
source
fusee_main.cppfusee_overlay_manager.cppfusee_overlay_manager.hppfusee_secondary_archive.hppfusee_setup_horizon.cppfusee_stratosphere.cpp
split_bin.pylibraries/libexosphere/include/exosphere/secmon
|
@ -98,7 +98,10 @@ else
|
|||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
all : $(OUTPUT).kip
|
||||
all : $(OUTPUT)_unpacked.kip
|
||||
|
||||
$(OUTPUT)_unpacked.kip : $(OUTPUT).kip
|
||||
@hactool -t kip --uncompressed=$(OUTPUT)_unpacked.kip $(OUTPUT).kip
|
||||
|
||||
$(OUTPUT).kip : $(OUTPUT).elf
|
||||
|
||||
|
|
|
@ -154,8 +154,11 @@ namespace ams::secmon::boot {
|
|||
bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) {
|
||||
/* Verify hashes match for all payloads. */
|
||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||
if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) {
|
||||
return false;
|
||||
/* Allow all-zero bytes to match any payload. */
|
||||
if (!(meta.payload_hashes[i][0] == 0 && std::memcmp(meta.payload_hashes[i] + 0, meta.payload_hashes[i] + 1, sizeof(meta.payload_hashes[i]) - 1) == 0)) {
|
||||
if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
payload_address += meta.payload_sizes[i];
|
||||
|
|
|
@ -129,6 +129,9 @@ namespace ams::nxboot {
|
|||
/* Restore memory clock rate. */
|
||||
RestoreMemoryClockRate();
|
||||
|
||||
/* Restore secure monitor code. */
|
||||
RestoreSecureMonitorOverlay();
|
||||
|
||||
/* Finalize display. */
|
||||
FinalizeDisplay();
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ namespace ams::nxboot {
|
|||
|
||||
namespace {
|
||||
|
||||
constinit u8 g_secmon_debug_storage[secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetSize()];
|
||||
|
||||
ALWAYS_INLINE void *GetOverlayDestination() {
|
||||
return reinterpret_cast<void *>(0x4002C000);
|
||||
}
|
||||
|
@ -64,7 +66,7 @@ namespace ams::nxboot {
|
|||
/* NOTE: Erista does not do memory clock restoration. */
|
||||
/* std::memcpy(const_cast<u8 *>(GetSecondaryArchive().ovl_mtc_erista), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
||||
std::memcpy(const_cast<u8 *>(GetSecondaryArchive().ovl_mtc_mariko), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_mariko));
|
||||
std::memcpy(const_cast<u8 *>(GetSecondaryArchive().ovl_mtc_mariko), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_mariko) - 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,7 +75,16 @@ namespace ams::nxboot {
|
|||
/* NOTE: Erista does not do memory clock restoration. */
|
||||
/* std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_erista, sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
||||
std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_mariko, sizeof(SecondaryArchive{}.ovl_mtc_mariko));
|
||||
std::memcpy(g_secmon_debug_storage, secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetPointer<void>(), sizeof(g_secmon_debug_storage));
|
||||
std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_mariko, sizeof(SecondaryArchive{}.ovl_mtc_mariko) - 0x2000);
|
||||
}
|
||||
}
|
||||
|
||||
void RestoreSecureMonitorOverlay() {
|
||||
if (fuse::GetSocType() == fuse::SocType_Erista) {
|
||||
/* NOTE: Erista does not do memory clock restoration. */
|
||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
||||
std::memcpy(secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetPointer<void>(), g_secmon_debug_storage, sizeof(g_secmon_debug_storage));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,5 +28,6 @@ namespace ams::nxboot {
|
|||
|
||||
void SaveMemoryTrainingOverlay();
|
||||
void RestoreMemoryTrainingOverlay();
|
||||
void RestoreSecureMonitorOverlay();
|
||||
|
||||
}
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace ams::nxboot {
|
|||
u32 reserved0; /* Previously entrypoint. */
|
||||
u32 metadata_offset;
|
||||
u32 flags;
|
||||
u32 meso_size;
|
||||
u32 num_kips;
|
||||
u32 reserved1[4];
|
||||
u32 reserved1[3];
|
||||
u32 magic;
|
||||
u32 total_size;
|
||||
u32 reserved2; /* Previously crt0 offset. */
|
||||
|
|
|
@ -834,7 +834,8 @@ namespace ams::nxboot {
|
|||
/* Build modified package2. */
|
||||
RebuildPackage2(target_firmware, emummc_enabled);
|
||||
|
||||
WaitForReboot();
|
||||
/* Wait for confirmation that exosphere is ready. */
|
||||
WaitSecureMonitorState(pkg1::SecureMonitorState_Initialized);
|
||||
}
|
||||
|
||||
}
|
|
@ -85,6 +85,8 @@ namespace ams::nxboot {
|
|||
static_assert(sizeof(InitialProcessMeta) == 0x40);
|
||||
static_assert(alignof(InitialProcessMeta) == 0x10);
|
||||
|
||||
constexpr inline const u64 FsProgramId = 0x0100000000000000;
|
||||
|
||||
enum FsVersion {
|
||||
FsVersion_1_0_0 = 0,
|
||||
|
||||
|
@ -284,6 +286,11 @@ namespace ams::nxboot {
|
|||
}
|
||||
|
||||
bool AddInitialProcess(const InitialProcessHeader *kip, const se::Sha256Hash *hash = nullptr) {
|
||||
/* Check kip magic. */
|
||||
if (kip->magic != InitialProcessHeader::Magic) {
|
||||
ShowFatalError("KIP seems corrupted!\n");
|
||||
}
|
||||
|
||||
/* Handle the initial case. */
|
||||
if (g_initial_process_binary_size == 0) {
|
||||
AddInitialProcessImpl(std::addressof(g_initial_process_meta), kip, hash);
|
||||
|
@ -591,6 +598,60 @@ namespace ams::nxboot {
|
|||
}
|
||||
}
|
||||
|
||||
struct BlzSegmentFlags {
|
||||
using Offset = util::BitPack16::Field<0, 12, u32>;
|
||||
using Size = util::BitPack16::Field<Offset::Next, 4, u32>;
|
||||
};
|
||||
|
||||
void BlzUncompress(void *_end) {
|
||||
/* Parse the footer, endian agnostic. */
|
||||
static_assert(sizeof(u32) == 4);
|
||||
static_assert(sizeof(u16) == 2);
|
||||
static_assert(sizeof(u8) == 1);
|
||||
|
||||
u8 *end = static_cast<u8 *>(_end);
|
||||
const u32 total_size = (end[-12] << 0) | (end[-11] << 8) | (end[-10] << 16) | (end[- 9] << 24);
|
||||
const u32 footer_size = (end[- 8] << 0) | (end[- 7] << 8) | (end[- 6] << 16) | (end[- 5] << 24);
|
||||
const u32 additional_size = (end[- 4] << 0) | (end[- 3] << 8) | (end[- 2] << 16) | (end[- 1] << 24);
|
||||
|
||||
/* Prepare to decompress. */
|
||||
u8 *cmp_start = end - total_size;
|
||||
u32 cmp_ofs = total_size - footer_size;
|
||||
u32 out_ofs = total_size + additional_size;
|
||||
|
||||
/* Decompress. */
|
||||
while (out_ofs) {
|
||||
u8 control = cmp_start[--cmp_ofs];
|
||||
|
||||
/* Each bit in the control byte is a flag indicating compressed or not compressed. */
|
||||
for (size_t i = 0; i < 8 && out_ofs; ++i, control <<= 1) {
|
||||
if (control & 0x80) {
|
||||
/* NOTE: Nintendo does not check if it's possible to decompress. */
|
||||
/* As such, we will leave the following as a debug assertion, and not a release assertion. */
|
||||
AMS_AUDIT(cmp_ofs >= sizeof(u16));
|
||||
cmp_ofs -= sizeof(u16);
|
||||
|
||||
/* Extract segment bounds. */
|
||||
const util::BitPack16 seg_flags{static_cast<u16>((cmp_start[cmp_ofs] << 0) | (cmp_start[cmp_ofs + 1] << 8))};
|
||||
const u32 seg_ofs = seg_flags.Get<BlzSegmentFlags::Offset>() + 3;
|
||||
const u32 seg_size = std::min(seg_flags.Get<BlzSegmentFlags::Size>() + 3, out_ofs);
|
||||
AMS_AUDIT(out_ofs + seg_ofs <= total_size + additional_size);
|
||||
|
||||
/* Copy the data. */
|
||||
out_ofs -= seg_size;
|
||||
for (size_t j = 0; j < seg_size; j++) {
|
||||
cmp_start[out_ofs + j] = cmp_start[out_ofs + seg_ofs + j];
|
||||
}
|
||||
} else {
|
||||
/* NOTE: Nintendo does not check if it's possible to copy. */
|
||||
/* As such, we will leave the following as a debug assertion, and not a release assertion. */
|
||||
AMS_AUDIT(cmp_ofs >= sizeof(u8));
|
||||
cmp_start[--out_ofs] = cmp_start[--cmp_ofs];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))) {
|
||||
|
@ -674,7 +735,6 @@ namespace ams::nxboot {
|
|||
}
|
||||
|
||||
/* Get meta for FS process. */
|
||||
constexpr u64 FsProgramId = 0x0100000000000000;
|
||||
auto *fs_meta = FindInitialProcess(FsProgramId);
|
||||
if (fs_meta == nullptr) {
|
||||
/* Get nintendo header/data. */
|
||||
|
@ -833,7 +893,220 @@ namespace ams::nxboot {
|
|||
}
|
||||
|
||||
void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled) {
|
||||
/* TODO */
|
||||
/* Get the secondary archive. */
|
||||
const auto &secondary_archive = GetSecondaryArchive();
|
||||
|
||||
/* Clear package2 header. */
|
||||
auto *package2 = secmon::MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>();
|
||||
std::memset(package2, 0, sizeof(*package2));
|
||||
|
||||
/* Get payload data pointer. */
|
||||
u8 * const payload_data = reinterpret_cast<u8 *>(package2 + 1);
|
||||
|
||||
/* Useful values. */
|
||||
constexpr u32 KernelPayloadBase = 0x60000;
|
||||
|
||||
/* Set fields. */
|
||||
package2->meta.key_generation = pkg1::KeyGeneration_Current;
|
||||
std::memcpy(package2->meta.magic, pkg2::Package2Meta::Magic::String, sizeof(package2->meta.magic));
|
||||
package2->meta.entrypoint = KernelPayloadBase;
|
||||
package2->meta.bootloader_version = pkg2::CurrentBootloaderVersion;
|
||||
package2->meta.package2_version = pkg2::MinimumValidDataVersion;
|
||||
|
||||
/* Load mesosphere. */
|
||||
s64 meso_size;
|
||||
if (void *sd_meso = ReadFile(std::addressof(meso_size), "sdmc:/atmosphere/mesosphere.bin"); sd_meso != nullptr) {
|
||||
std::memcpy(payload_data, sd_meso, meso_size);
|
||||
} else {
|
||||
meso_size = secondary_archive.header.meso_size;
|
||||
std::memcpy(payload_data, secondary_archive.mesosphere, meso_size);
|
||||
}
|
||||
|
||||
/* Read emummc, if needed. */
|
||||
const InitialProcessHeader *emummc;
|
||||
s64 emummc_size;
|
||||
if (emummc_enabled) {
|
||||
emummc = static_cast<const InitialProcessHeader *>(ReadFile(std::addressof(emummc_size), "sdmc:/atmosphere/emummc.kip"));
|
||||
if (emummc == nullptr) {
|
||||
emummc = reinterpret_cast<const InitialProcessHeader *>(secondary_archive.kips + secondary_archive.header.emummc_meta.offset);
|
||||
emummc_size = secondary_archive.header.emummc_meta.size;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the embedded ini pointer. */
|
||||
std::memcpy(payload_data + 8, std::addressof(meso_size), sizeof(meso_size));
|
||||
|
||||
/* Get the ini pointer. */
|
||||
InitialProcessBinaryHeader * const ini = reinterpret_cast<InitialProcessBinaryHeader *>(payload_data + meso_size);
|
||||
|
||||
/* Set ini fields. */
|
||||
ini->magic = InitialProcessBinaryHeader::Magic;
|
||||
ini->num_processes = 0;
|
||||
ini->reserved = 0;
|
||||
|
||||
/* Iterate all processes. */
|
||||
u8 * const dst_kip_start = reinterpret_cast<u8 *>(ini + 1);
|
||||
u8 * dst_kip_cur = dst_kip_start;
|
||||
|
||||
for (InitialProcessMeta *meta = std::addressof(g_initial_process_meta); meta != nullptr; meta = meta->next) {
|
||||
/* Get the current kip. */
|
||||
const auto *src_kip = meta->kip;
|
||||
auto *dst_kip = reinterpret_cast<InitialProcessHeader *>(dst_kip_cur);
|
||||
|
||||
/* Copy the kip header */
|
||||
std::memcpy(dst_kip, src_kip, sizeof(*src_kip));
|
||||
|
||||
const u8 *src_kip_data = reinterpret_cast<const u8 *>(src_kip + 1);
|
||||
u8 *dst_kip_data = reinterpret_cast< u8 *>(dst_kip + 1);
|
||||
|
||||
/* If necessary, inject emummc. */
|
||||
u32 addl_text_offset = 0;
|
||||
if (dst_kip->program_id == FsProgramId && emummc_enabled) {
|
||||
/* Get emummc extents. */
|
||||
addl_text_offset = emummc->bss_address + emummc->bss_size;
|
||||
if ((emummc->flags & 7) || !util::IsAligned(addl_text_offset, 0x1000)) {
|
||||
ShowFatalError("Invalid emummc kip!\n");
|
||||
}
|
||||
|
||||
/* Copy emummc capabilities. */
|
||||
{
|
||||
std::memcpy(dst_kip->capabilities, emummc->capabilities, sizeof(emummc->capabilities));
|
||||
|
||||
if (target_firmware <= ams::TargetFirmware_1_0_0) {
|
||||
for (size_t i = 0; i < util::size(dst_kip->capabilities); ++i) {
|
||||
if (dst_kip->capabilities[i] == 0xFFFFFFFF) {
|
||||
dst_kip->capabilities[i] = 0x07000E7F;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update section headers. */
|
||||
dst_kip->ro_address += addl_text_offset;
|
||||
dst_kip->rw_address += addl_text_offset;
|
||||
dst_kip->bss_address += addl_text_offset;
|
||||
|
||||
/* Get emummc sections. */
|
||||
const u8 *emummc_data = reinterpret_cast<const u8 *>(emummc + 1);
|
||||
|
||||
/* Copy emummc sections. */
|
||||
std::memcpy(dst_kip_data + emummc->rx_address, emummc_data, emummc->rx_compressed_size);
|
||||
std::memcpy(dst_kip_data + emummc->ro_address, emummc_data + emummc->rx_compressed_size, emummc->ro_compressed_size);
|
||||
std::memcpy(dst_kip_data + emummc->rw_address, emummc_data + emummc->rx_compressed_size + emummc->ro_compressed_size, emummc->rw_compressed_size);
|
||||
std::memset(dst_kip_data + emummc->bss_address, 0, emummc->bss_size);
|
||||
|
||||
/* Advance. */
|
||||
dst_kip_data += addl_text_offset;
|
||||
}
|
||||
|
||||
/* Prepare to process segments. */
|
||||
u8 *dst_rx_data, *dst_ro_data, *dst_rw_data;
|
||||
|
||||
/* Process .text. */
|
||||
{
|
||||
dst_rx_data = dst_kip_data;
|
||||
|
||||
std::memcpy(dst_kip_data, src_kip_data, src_kip->rx_compressed_size);
|
||||
|
||||
/* Uncompress, if necessary. */
|
||||
if ((meta->patch_segments & src_kip->flags) & (1 << 0)) {
|
||||
BlzUncompress(dst_kip_data + dst_kip->rx_compressed_size);
|
||||
|
||||
dst_kip->rx_compressed_size = dst_kip->rx_size;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_kip_data += dst_kip->rx_compressed_size;
|
||||
src_kip_data += src_kip->rx_compressed_size;
|
||||
|
||||
/* Account for potential emummc. */
|
||||
dst_kip->rx_size += addl_text_offset;
|
||||
dst_kip->rx_compressed_size += addl_text_offset;
|
||||
}
|
||||
|
||||
/* Process .rodata. */
|
||||
{
|
||||
dst_ro_data = dst_kip_data;
|
||||
|
||||
std::memcpy(dst_kip_data, src_kip_data, src_kip->ro_compressed_size);
|
||||
|
||||
/* Uncompress, if necessary. */
|
||||
if ((meta->patch_segments & src_kip->flags) & (1 << 1)) {
|
||||
BlzUncompress(dst_kip_data + dst_kip->ro_compressed_size);
|
||||
|
||||
dst_kip->ro_compressed_size = dst_kip->ro_size;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_kip_data += dst_kip->ro_compressed_size;
|
||||
src_kip_data += src_kip->ro_compressed_size;
|
||||
}
|
||||
|
||||
/* Process .rwdata. */
|
||||
{
|
||||
dst_rw_data = dst_kip_data;
|
||||
|
||||
std::memcpy(dst_kip_data, src_kip_data, src_kip->rw_compressed_size);
|
||||
|
||||
/* Uncompress, if necessary. */
|
||||
if ((meta->patch_segments & src_kip->flags) & (1 << 2)) {
|
||||
BlzUncompress(dst_kip_data + dst_kip->rw_compressed_size);
|
||||
|
||||
dst_kip->rw_compressed_size = dst_kip->rw_size;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_kip_data += dst_kip->rw_compressed_size;
|
||||
src_kip_data += src_kip->rw_compressed_size;
|
||||
}
|
||||
|
||||
/* Adjust flags. */
|
||||
dst_kip->flags &= ~meta->patch_segments;
|
||||
|
||||
/* Apply patches. */
|
||||
for (auto *patch = meta->patches_head; patch != nullptr; patch = patch->next) {
|
||||
/* Get the destination segment. */
|
||||
u8 *patch_dst_segment;
|
||||
switch (patch->start_segment) {
|
||||
case 0: patch_dst_segment = dst_rx_data; break;
|
||||
case 1: patch_dst_segment = dst_ro_data; break;
|
||||
case 2: patch_dst_segment = dst_rw_data; break;
|
||||
default: ShowFatalError("Unknown patch segment %" PRIu32 "\n", patch->start_segment); break;
|
||||
}
|
||||
|
||||
/* Get the destination. */
|
||||
u8 * const patch_dst = patch_dst_segment + patch->rel_offset;
|
||||
|
||||
/* Apply the patch. */
|
||||
if (patch->is_memset) {
|
||||
const u8 val = *static_cast<const u8 *>(patch->data);
|
||||
std::memset(patch_dst, val, patch->size);
|
||||
} else {
|
||||
std::memcpy(patch_dst, patch->data, patch->size);
|
||||
}
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
dst_kip_cur += GetInitialProcessSize(dst_kip);
|
||||
|
||||
/* Increment num kips. */
|
||||
++ini->num_processes;
|
||||
}
|
||||
|
||||
/* Set INI size. */
|
||||
ini->size = sizeof(*ini) + (dst_kip_cur - dst_kip_start);
|
||||
if (ini->size > 12_MB) {
|
||||
ShowFatalError("INI is too big! (0x%08" PRIx32 ")\n", ini->size);
|
||||
}
|
||||
|
||||
/* Set the payload size/offset. */
|
||||
package2->meta.payload_offsets[0] = KernelPayloadBase;
|
||||
package2->meta.payload_sizes[0] = util::AlignUp(meso_size + ini->size, 0x10);
|
||||
|
||||
|
||||
/* Set total size. */
|
||||
package2->meta.package2_size = sizeof(*package2) + package2->meta.payload_sizes[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ def get_overlay(program, i):
|
|||
KIP_NAMES = ['Loader', 'NCM', 'ProcessManager', 'sm', 'boot', 'spl', 'ams_mitm']
|
||||
|
||||
def get_kips():
|
||||
emummc = read_file('../../../../emummc/emummc.kip')
|
||||
emummc = read_file('../../../../emummc/emummc_unpacked.kip')
|
||||
loader = read_file('../../../../stratosphere/loader/loader.kip')
|
||||
ncm = read_file('../../../../stratosphere/ncm/ncm.kip')
|
||||
pm = read_file('../../../../stratosphere/pm/pm.kip')
|
||||
|
@ -45,11 +45,11 @@ 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)))
|
||||
f.write(pk('<II', ofs - 0x100000, len(kip)))
|
||||
# Write hash
|
||||
f.write(hashlib.sha256(kip).digest())
|
||||
|
||||
def write_header(f, all_kips):
|
||||
def write_header(f, all_kips, meso_size):
|
||||
# Unpack kips
|
||||
emummc, kips = all_kips
|
||||
# Write reserved0 (previously entrypoint) as infinite loop instruction.
|
||||
|
@ -58,15 +58,17 @@ def write_header(f, all_kips):
|
|||
f.write(pk('<I', 0x20))
|
||||
# Write flags
|
||||
f.write(pk('<I', 0x00000000))
|
||||
# Write meso_size
|
||||
f.write(pk('<I', meso_size))
|
||||
# Write num_kips
|
||||
f.write(pk('<I', len(KIP_NAMES)))
|
||||
# Write reserved2
|
||||
f.write(b'\xCC' * 0x10)
|
||||
# Write reserved1
|
||||
f.write(b'\xCC' * 0xC)
|
||||
# Write magic
|
||||
f.write('FSS0')
|
||||
# Write total size
|
||||
f.write(pk('<I', 0x800000))
|
||||
# Write reserved3
|
||||
# Write reserved2
|
||||
f.write(pk('<I', 0xCCCCCCCC))
|
||||
# Write content_header_offset
|
||||
f.write(pk('<I', 0x40))
|
||||
|
@ -87,21 +89,25 @@ def write_header(f, all_kips):
|
|||
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)
|
||||
ofs = (0x100000 + len(emummc) + 0xF) & ~0xF
|
||||
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)
|
||||
ofs += 0xF
|
||||
ofs &= ~0xF
|
||||
# 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)
|
||||
ofs = (0x100000 + len(emummc) + 0xF) & ~0xF
|
||||
for kip_name in KIP_NAMES:
|
||||
kip_data = kips[kip_name]
|
||||
write_kip_meta(f, kip_data, ofs)
|
||||
ofs += len(kip_data)
|
||||
ofs += 0xF
|
||||
ofs &= ~0xF
|
||||
# Pad to end of header
|
||||
f.write(b'\xCC' * (0x800 - (0x400 + (1 + len(KIP_NAMES)) * 0x30)))
|
||||
|
||||
|
@ -112,10 +118,18 @@ def write_kips(f, all_kips):
|
|||
f.write(emummc)
|
||||
# Write kips
|
||||
tot = len(emummc)
|
||||
if (tot & 0xF):
|
||||
f.write('\xCC' * (0x10 - (tot & 0xF)))
|
||||
tot += 0xF
|
||||
tot &= ~0xF
|
||||
for kip_name in KIP_NAMES:
|
||||
kip_data = kips[kip_name]
|
||||
f.write(kip_data)
|
||||
tot += len(kip_data)
|
||||
if (tot & 0xF):
|
||||
f.write('\xCC' * (0x10 - (tot & 0xF)))
|
||||
tot += 0xF
|
||||
tot &= ~0xF
|
||||
# Pad to 3 MB
|
||||
f.write(b'\xCC' * (0x300000 - tot))
|
||||
|
||||
|
@ -137,11 +151,12 @@ def main(argc, argv):
|
|||
erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4]
|
||||
mariko_hsh = hashlib.sha256(mariko_mtc[:-4]).digest()[:4]
|
||||
fusee_program = lz4_compress(data[:0x2B000 - 8] + erista_hsh + mariko_hsh + get_overlay(data, 0)[:0x11000])
|
||||
mesosphere = read_file('../../../../mesosphere/mesosphere%s.bin' % target)
|
||||
with open('../../program%s.lz4' % target, 'wb') as f:
|
||||
f.write(fusee_program)
|
||||
with open('../../fusee-boogaloo%s.bin' % target, 'wb') as f:
|
||||
# Write header
|
||||
write_header(f, all_kips)
|
||||
write_header(f, all_kips, len(mesosphere))
|
||||
# Write warmboot
|
||||
f.write(pad(read_file('../../../../exosphere/warmboot%s.bin' % target), 0x1800))
|
||||
# Write TSEC Keygen
|
||||
|
|
|
@ -333,7 +333,7 @@ namespace ams::secmon {
|
|||
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable));
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0x6000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeImage = MemoryRegion(UINT64_C(0x40032000), 0xC000);
|
||||
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeCode = MemoryRegion(UINT64_C(0x40032000), 0x1000);
|
||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeKeys = MemoryRegion(UINT64_C(0x40033000), 0x1000);
|
||||
|
|
Loading…
Reference in a new issue