fusee: fix buildsystem, rename secondary -> package3

This commit is contained in:
Michael Scire
2021-09-05 15:45:40 -07:00
committed by SciresM
parent b7521465ee
commit 045f9b2f15
16 changed files with 246 additions and 139 deletions

View File

@@ -111,7 +111,7 @@ DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
$(OUTPUT).lz4 : $(OUTPUT).bin
@python $(TOPDIR)/split_bin.py "$(ATMOSPHERE_BUILD_TARGET)"
@python $(TOPDIR)/lz4_compress.py $(OUTPUT).bin $(OUTPUT).lz4
@echo built ... $(notdir $@)
$(OUTPUT).bin : $(OUTPUT).elf

View File

@@ -0,0 +1,35 @@
#!/usr/bin/env python
import sys, lz4, hashlib
from struct import unpack as up, pack as pk
def lz4_compress(data):
try:
import lz4.block as block
except ImportError:
block = lz4.LZ4_compress
return block.compress(data, 'high_compression', store_size=False)
def read_file(fn):
with open(fn, 'rb') as f:
return f.read()
def get_overlay(program, i):
return program[0x2B000 + 0x14000 * i:0x2B000 + 0x14000 * (i+1)]
def main(argc, argv):
if argc != 3:
print('Usage: %s in out' % argv[0])
return 1
data = read_file(argv[1])
erista_mtc = get_overlay(data, 1)
mariko_mtc = get_overlay(data, 2)
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])
with open(argv[2], 'wb') as f:
f.write(fusee_program)
return 0
if __name__ == '__main__':
sys.exit(main(len(sys.argv), sys.argv))

View File

@@ -19,11 +19,11 @@
namespace ams::nxboot {
constexpr inline const size_t SecondaryArchiveSize = 8_MB;
constexpr inline const size_t ExternalPackageSize = 8_MB;
constexpr inline const size_t InitialProcessStorageSizeMax = 3_MB / 8;
struct SecondaryArchiveContentMeta {
struct ExternalPackageContentMeta {
u32 offset;
u32 size;
u8 type;
@@ -31,17 +31,17 @@ namespace ams::nxboot {
u32 pad;
char name[0x10];
};
static_assert(sizeof(SecondaryArchiveContentMeta) == 0x20);
static_assert(sizeof(ExternalPackageContentMeta) == 0x20);
struct SecondaryArchiveKipMeta {
struct ExternalPackageKipMeta {
u64 program_id;
u32 offset;
u32 size;
se::Sha256Hash hash;
};
static_assert(sizeof(SecondaryArchiveKipMeta) == 0x30);
static_assert(sizeof(ExternalPackageKipMeta) == 0x30);
struct SecondaryArchiveHeader {
struct ExternalPackageHeader {
static constexpr u32 Magic = util::FourCC<'F','S','S','0'>::Code;
u32 reserved0; /* Previously entrypoint. */
@@ -58,15 +58,15 @@ namespace ams::nxboot {
u32 supported_hos_version;
u32 release_version;
u32 git_revision;
SecondaryArchiveContentMeta content_metas[(0x400 - 0x40) / sizeof(SecondaryArchiveContentMeta)];
SecondaryArchiveKipMeta emummc_meta;
SecondaryArchiveKipMeta kip_metas[8];
u8 reserved3[0x800 - (0x400 + 9 * sizeof(SecondaryArchiveKipMeta))];
ExternalPackageContentMeta content_metas[(0x400 - 0x40) / sizeof(ExternalPackageContentMeta)];
ExternalPackageKipMeta emummc_meta;
ExternalPackageKipMeta kip_metas[8];
u8 reserved3[0x800 - (0x400 + 9 * sizeof(ExternalPackageKipMeta))];
};
static_assert(sizeof(SecondaryArchiveHeader) == 0x800);
static_assert(sizeof(ExternalPackageHeader) == 0x800);
struct SecondaryArchive {
SecondaryArchiveHeader header; /* 0x000000-0x000800 */
struct ExternalPackage {
ExternalPackageHeader header; /* 0x000000-0x000800 */
u8 warmboot[0x1800]; /* 0x000800-0x002000 */
u8 tsec_keygen[0x2000]; /* 0x002000-0x004000 */
u8 mariko_fatal[0x1C000]; /* 0x004000-0x020000 */
@@ -80,8 +80,8 @@ namespace ams::nxboot {
u8 reboot_stub[0x1000]; /* 0x7E0000-0x7E1000 */
u8 reserved[0x1F000]; /* 0x7E1000-0x800000 */
};
static_assert(sizeof(SecondaryArchive) == SecondaryArchiveSize);
static_assert(sizeof(ExternalPackage) == ExternalPackageSize);
ALWAYS_INLINE const SecondaryArchive &GetSecondaryArchive() { return *reinterpret_cast<const SecondaryArchive *>(0xC0000000); }
ALWAYS_INLINE const ExternalPackage &GetExternalPackage() { return *reinterpret_cast<const ExternalPackage *>(0xC0000000); }
}

View File

@@ -22,7 +22,7 @@
#include "fusee_overlay_manager.hpp"
#include "fusee_sd_card.hpp"
#include "fusee_fatal.hpp"
#include "fusee_secondary_archive.hpp"
#include "fusee_external_package.hpp"
#include "fusee_setup_horizon.hpp"
#include "fusee_secmon_sync.hpp"
@@ -30,41 +30,40 @@ namespace ams::nxboot {
namespace {
/* TODO: Change to fusee-secondary.bin when development is done. */
constexpr const char SecondaryArchiveFilePath[] = "sdmc:/atmosphere/fusee-boogaloo.bin";
constexpr const char ExternalPackageFilePath[] = "sdmc:/atmosphere/package3";
constinit fs::FileHandle g_archive_file;
constinit fs::FileHandle g_package_file;
void OpenSecondaryArchive() {
void OpenExternalPackage() {
Result result;
/* Open fusee-secondary. */
if (R_FAILED((result = fs::OpenFile(std::addressof(g_archive_file), SecondaryArchiveFilePath, fs::OpenMode_Read)))) {
ShowFatalError("Failed to open %s!\n", SecondaryArchiveFilePath);
/* Open external package. */
if (R_FAILED((result = fs::OpenFile(std::addressof(g_package_file), ExternalPackageFilePath, fs::OpenMode_Read)))) {
ShowFatalError("Failed to open %s!\n", ExternalPackageFilePath);
}
/* Get file size. */
s64 file_size;
if (R_FAILED((result = fs::GetFileSize(std::addressof(file_size), g_archive_file)))) {
ShowFatalError("Failed to get fusee-secondary size: 0x%08" PRIx32 "\n", result.GetValue());
if (R_FAILED((result = fs::GetFileSize(std::addressof(file_size), g_package_file)))) {
ShowFatalError("Failed to get package3 size: 0x%08" PRIx32 "\n", result.GetValue());
}
/* Check file size. */
if (static_cast<size_t>(file_size) != SecondaryArchiveSize) {
ShowFatalError("fusee-secondary seems corrupted (size 0x%zx != 0x%zx)", static_cast<size_t>(file_size), SecondaryArchiveSize);
if (static_cast<size_t>(file_size) != ExternalPackageSize) {
ShowFatalError("package3 seems corrupted (size 0x%zx != 0x%zx)", static_cast<size_t>(file_size), ExternalPackageSize);
}
}
void ReadFullSecondaryArchive() {
void ReadFullExternalPackage() {
Result result;
if (R_FAILED((result = fs::ReadFile(g_archive_file, 0, const_cast<void *>(static_cast<const void *>(std::addressof(GetSecondaryArchive()))), SecondaryArchiveSize)))) {
ShowFatalError("Failed to read %s!\n", SecondaryArchiveFilePath);
if (R_FAILED((result = fs::ReadFile(g_package_file, 0, const_cast<void *>(static_cast<const void *>(std::addressof(GetExternalPackage()))), ExternalPackageSize)))) {
ShowFatalError("Failed to read %s!\n", ExternalPackageFilePath);
}
}
void CloseSecondaryArchive() {
fs::CloseFile(g_archive_file);
void CloseExternalPackage() {
fs::CloseFile(g_package_file);
}
}
@@ -98,17 +97,17 @@ namespace ams::nxboot {
/* If we have a fatal error, save and display it. */
SaveAndShowFatalError();
/* Open the secondary archive. */
OpenSecondaryArchive();
/* Open the external package. */
OpenExternalPackage();
/* Load the memory training overlay. */
LoadOverlay(g_archive_file, OverlayId_MemoryTraining);
LoadOverlay(g_package_file, OverlayId_MemoryTraining);
/* Do memory training. */
DoMemoryTraining();
/* Read the rest of the archive file. */
ReadFullSecondaryArchive();
ReadFullExternalPackage();
/* Save the memory training overlay. */
SaveMemoryTrainingOverlay();
@@ -117,8 +116,8 @@ namespace ams::nxboot {
InitializeDisplay();
ShowDisplay();
/* Close the secondary archive. */
CloseSecondaryArchive();
/* Close the external package. */
CloseExternalPackage();
/* Perform rest of the boot process. */
SetupAndStartHorizon();

View File

@@ -15,7 +15,6 @@
*/
#include <exosphere.hpp>
#include "fusee_malloc.hpp"
#include "fusee_secondary_archive.hpp"
#include "fusee_fatal.hpp"
namespace ams::nxboot {

View File

@@ -15,7 +15,7 @@
*/
#include <exosphere.hpp>
#include "fusee_overlay_manager.hpp"
#include "fusee_secondary_archive.hpp"
#include "fusee_external_package.hpp"
#include "fusee_fatal.hpp"
namespace ams::nxboot {
@@ -33,13 +33,13 @@ namespace ams::nxboot {
u32 verif_hash;
u32 store_hash;
if (fuse::GetSocType() == fuse::SocType_Erista) {
result = fs::ReadFile(archive_file, __builtin_offsetof(SecondaryArchive, ovl_mtc_erista), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_erista));
result = fs::ReadFile(archive_file, __builtin_offsetof(ExternalPackage, ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_erista));
verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-2];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(SecondaryArchive{}.ovl_mtc_erista) / sizeof(u32)) - 1];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_erista) / sizeof(u32)) - 1];
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
result = fs::ReadFile(archive_file, __builtin_offsetof(SecondaryArchive, ovl_mtc_mariko), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_mariko));
result = fs::ReadFile(archive_file, __builtin_offsetof(ExternalPackage, ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko));
verif_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[-1];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(SecondaryArchive{}.ovl_mtc_mariko) / sizeof(u32)) - 1];
store_hash = reinterpret_cast<const u32 *>(GetOverlayDestination())[(sizeof(ExternalPackage{}.ovl_mtc_mariko) / sizeof(u32)) - 1];
}
if (R_FAILED(result)) {
@@ -64,19 +64,19 @@ 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)); */
/* std::memcpy(const_cast<u8 *>(GetExternalPackage().ovl_mtc_erista), GetOverlayDestination(), sizeof(ExternalPackage{}.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) - 0x2000);
std::memcpy(const_cast<u8 *>(GetExternalPackage().ovl_mtc_mariko), GetOverlayDestination(), sizeof(ExternalPackage{}.ovl_mtc_mariko) - 0x2000);
}
}
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)); */
/* std::memcpy(GetOverlayDestination(), GetExternalPackage().ovl_mtc_erista, sizeof(ExternalPackage{}.ovl_mtc_erista)); */
} else /* if (fuse::GetSocType() == fuse::SocType_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);
std::memcpy(GetOverlayDestination(), GetExternalPackage().ovl_mtc_mariko, sizeof(ExternalPackage{}.ovl_mtc_mariko) - 0x2000);
}
}

View File

@@ -16,7 +16,7 @@
#include <exosphere.hpp>
#include <exosphere/secmon/secmon_monitor_context.hpp>
#include "fusee_key_derivation.hpp"
#include "fusee_secondary_archive.hpp"
#include "fusee_external_package.hpp"
#include "fusee_setup_horizon.hpp"
#include "fusee_ini.hpp"
#include "fusee_emummc.hpp"
@@ -44,7 +44,7 @@ namespace ams::nxboot {
if (soc_type == fuse::SocType_Erista) {
clkrst::SetBpmpClockRate(clkrst::BpmpClockRate_408MHz);
if (!tsec::RunTsecFirmware(GetSecondaryArchive().tsec_keygen, sizeof(GetSecondaryArchive().tsec_keygen))) {
if (!tsec::RunTsecFirmware(GetExternalPackage().tsec_keygen, sizeof(GetExternalPackage().tsec_keygen))) {
ShowFatalError("Failed to run tsec_keygen firmware!\n");
}
@@ -428,10 +428,10 @@ namespace ams::nxboot {
void LoadWarmbootFirmware(fuse::SocType soc_type, ams::TargetFirmware target_firmware, const u8 *package1) {
u8 *warmboot_dst = secmon::MemoryRegionPhysicalIramWarmbootBin.GetPointer<u8>();
size_t warmboot_size = std::min(sizeof(GetSecondaryArchive().warmboot), secmon::MemoryRegionPhysicalIramWarmbootBin.GetSize());
size_t warmboot_size = std::min(sizeof(GetExternalPackage().warmboot), secmon::MemoryRegionPhysicalIramWarmbootBin.GetSize());
if (soc_type == fuse::SocType_Erista) {
/* Copy the ams warmboot binary. */
std::memcpy(warmboot_dst, GetSecondaryArchive().warmboot, warmboot_size);
std::memcpy(warmboot_dst, GetExternalPackage().warmboot, warmboot_size);
/* Set the rsa modulus. */
if (fuse::GetHardwareState() == fuse::HardwareState_Production) {
@@ -694,7 +694,7 @@ namespace ams::nxboot {
/* Get the size. */
s64 size;
if (R_FAILED((result = fs::GetFileSize(std::addressof(size), exo_file))) || size > sizeof(GetSecondaryArchive().exosphere)) {
if (R_FAILED((result = fs::GetFileSize(std::addressof(size), exo_file))) || size > sizeof(GetExternalPackage().exosphere)) {
ShowFatalError("Invalid SD exosphere size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast<u64>(size));
}
@@ -706,7 +706,7 @@ namespace ams::nxboot {
}
if (!use_sd_exo) {
std::memcpy(exosphere_dst, GetSecondaryArchive().exosphere, sizeof(GetSecondaryArchive().exosphere));
std::memcpy(exosphere_dst, GetExternalPackage().exosphere, sizeof(GetExternalPackage().exosphere));
}
/* Copy mariko fatal. */
@@ -726,7 +726,7 @@ namespace ams::nxboot {
/* Get the size. */
s64 size;
if (R_FAILED((result = fs::GetFileSize(std::addressof(size), mariko_program_file))) || size > sizeof(GetSecondaryArchive().mariko_fatal)) {
if (R_FAILED((result = fs::GetFileSize(std::addressof(size), mariko_program_file))) || size > sizeof(GetExternalPackage().mariko_fatal)) {
ShowFatalError("Invalid SD mariko_fatal size: 0x%08" PRIx32 ", %" PRIx64 "!\n", result.GetValue(), static_cast<u64>(size));
}
@@ -736,12 +736,12 @@ namespace ams::nxboot {
}
/* Clear the remainder. */
std::memset(mariko_fatal_dst + size, 0, sizeof(GetSecondaryArchive().mariko_fatal) - size);
std::memset(mariko_fatal_dst + size, 0, sizeof(GetExternalPackage().mariko_fatal) - size);
}
}
if (!use_sd_mariko_fatal) {
std::memcpy(mariko_fatal_dst, GetSecondaryArchive().mariko_fatal, sizeof(GetSecondaryArchive().mariko_fatal));
std::memcpy(mariko_fatal_dst, GetExternalPackage().mariko_fatal, sizeof(GetExternalPackage().mariko_fatal));
}
}

View File

@@ -17,7 +17,7 @@
#include "fusee_stratosphere.hpp"
#include "fusee_fatal.hpp"
#include "fusee_malloc.hpp"
#include "fusee_secondary_archive.hpp"
#include "fusee_external_package.hpp"
#include "fs/fusee_fs_api.hpp"
namespace ams::nxboot {
@@ -726,11 +726,11 @@ namespace ams::nxboot {
/* Add the stratosphere kips. */
{
const auto &secondary_archive = GetSecondaryArchive();
for (u32 i = 0; i < secondary_archive.header.num_kips; ++i) {
const auto &meta = secondary_archive.header.kip_metas[i];
const auto &external_package = GetExternalPackage();
for (u32 i = 0; i < external_package.header.num_kips; ++i) {
const auto &meta = external_package.header.kip_metas[i];
AddInitialProcess(reinterpret_cast<const InitialProcessHeader *>(secondary_archive.kips + meta.offset), std::addressof(meta.hash));
AddInitialProcess(reinterpret_cast<const InitialProcessHeader *>(external_package.kips + meta.offset), std::addressof(meta.hash));
}
}
@@ -893,8 +893,8 @@ namespace ams::nxboot {
}
void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled) {
/* Get the secondary archive. */
const auto &secondary_archive = GetSecondaryArchive();
/* Get the external package. */
const auto &external_package = GetExternalPackage();
/* Clear package2 header. */
auto *package2 = secmon::MemoryRegionDramPackage2.GetPointer<pkg2::Package2Header>();
@@ -918,8 +918,8 @@ namespace ams::nxboot {
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);
meso_size = external_package.header.meso_size;
std::memcpy(payload_data, external_package.mesosphere, meso_size);
}
/* Read emummc, if needed. */
@@ -928,8 +928,8 @@ namespace ams::nxboot {
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;
emummc = reinterpret_cast<const InitialProcessHeader *>(external_package.kips + external_package.header.emummc_meta.offset);
emummc_size = external_package.header.emummc_meta.size;
}
}

View File

@@ -1,189 +0,0 @@
#!/usr/bin/env python
import sys, lz4, hashlib
from struct import unpack as up, pack as pk
def lz4_compress(data):
try:
import lz4.block as block
except ImportError:
block = lz4.LZ4_compress
return block.compress(data, 'high_compression', store_size=False)
def read_file(fn):
with open(fn, 'rb') as f:
return f.read()
def pad(data, size):
assert len(data) <= size
return (data + '\x00' * size)[:size]
def get_overlay(program, i):
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_unpacked.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 - 0x100000, len(kip)))
# Write hash
f.write(hashlib.sha256(kip).digest())
def write_header(f, all_kips, meso_size):
# 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 meso_size
f.write(pk('<I', meso_size))
# Write num_kips
f.write(pk('<I', len(KIP_NAMES)))
# Write reserved1
f.write(b'\xCC' * 0xC)
# Write magic
f.write('FSS0')
# Write total size
f.write(pk('<I', 0x800000))
# Write reserved2
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) + 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) + 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)))
def write_kips(f, all_kips):
# Unpack kips
emummc, kips = all_kips
# Write emummc
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))
def main(argc, argv):
if argc == 2:
target = argv[1]
if len(target) == 0:
target = ''
elif argc == 1:
target = ''
else:
print('Usage: %s target' % argv[0])
return 1
all_kips = get_kips()
with open('../../program%s.bin' % target, 'rb') as f:
data = f.read()
erista_mtc = get_overlay(data, 1)
mariko_mtc = get_overlay(data, 2)
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, len(mesosphere))
# Write warmboot
f.write(pad(read_file('../../../../exosphere/warmboot%s.bin' % target), 0x1800))
# Write TSEC Keygen
f.write(pad(read_file('../../tsec_keygen/tsec_keygen.bin'), 0x2000))
# Write Mariko Fatal
f.write(pad(read_file('../../../../exosphere/mariko_fatal%s.bin' % target), 0x1C000))
# Write Erista MTC
f.write(erista_mtc[:-4] + erista_hsh)
# Write Mariko MTC
f.write(mariko_mtc[:-4] + mariko_hsh)
# Write exosphere
f.write(pad(read_file('../../../../exosphere/exosphere%s.bin' % target), 0xE000))
# Write mesosphere
f.write(pad(read_file('../../../../mesosphere/mesosphere%s.bin' % target), 0xAA000))
# Write kips
write_kips(f, all_kips)
# Write Splash Screen
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
if __name__ == '__main__':
sys.exit(main(len(sys.argv), sys.argv))