mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +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
|
@ -98,7 +98,10 @@ else
|
||||||
|
|
||||||
DEPENDS := $(OFILES:.o=.d)
|
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
|
$(OUTPUT).kip : $(OUTPUT).elf
|
||||||
|
|
||||||
|
|
|
@ -154,8 +154,11 @@ namespace ams::secmon::boot {
|
||||||
bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) {
|
bool VerifyPackage2Payloads(const pkg2::Package2Meta &meta, uintptr_t payload_address) {
|
||||||
/* Verify hashes match for all payloads. */
|
/* Verify hashes match for all payloads. */
|
||||||
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
for (int i = 0; i < pkg2::PayloadCount; ++i) {
|
||||||
if (!VerifyHash(meta.payload_hashes[i], payload_address, meta.payload_sizes[i])) {
|
/* Allow all-zero bytes to match any payload. */
|
||||||
return false;
|
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];
|
payload_address += meta.payload_sizes[i];
|
||||||
|
|
|
@ -129,6 +129,9 @@ namespace ams::nxboot {
|
||||||
/* Restore memory clock rate. */
|
/* Restore memory clock rate. */
|
||||||
RestoreMemoryClockRate();
|
RestoreMemoryClockRate();
|
||||||
|
|
||||||
|
/* Restore secure monitor code. */
|
||||||
|
RestoreSecureMonitorOverlay();
|
||||||
|
|
||||||
/* Finalize display. */
|
/* Finalize display. */
|
||||||
FinalizeDisplay();
|
FinalizeDisplay();
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@ namespace ams::nxboot {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constinit u8 g_secmon_debug_storage[secmon::MemoryRegionPhysicalIramSecureMonitorDebug.GetSize()];
|
||||||
|
|
||||||
ALWAYS_INLINE void *GetOverlayDestination() {
|
ALWAYS_INLINE void *GetOverlayDestination() {
|
||||||
return reinterpret_cast<void *>(0x4002C000);
|
return reinterpret_cast<void *>(0x4002C000);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +66,7 @@ namespace ams::nxboot {
|
||||||
/* NOTE: Erista does not do memory clock restoration. */
|
/* 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 *>(GetSecondaryArchive().ovl_mtc_erista), GetOverlayDestination(), sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
} 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. */
|
/* NOTE: Erista does not do memory clock restoration. */
|
||||||
/* std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_erista, sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
/* std::memcpy(GetOverlayDestination(), GetSecondaryArchive().ovl_mtc_erista, sizeof(SecondaryArchive{}.ovl_mtc_erista)); */
|
||||||
} else /* if (fuse::GetSocType() == fuse::SocType_Mariko) */ {
|
} 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 SaveMemoryTrainingOverlay();
|
||||||
void RestoreMemoryTrainingOverlay();
|
void RestoreMemoryTrainingOverlay();
|
||||||
|
void RestoreSecureMonitorOverlay();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,8 +47,9 @@ namespace ams::nxboot {
|
||||||
u32 reserved0; /* Previously entrypoint. */
|
u32 reserved0; /* Previously entrypoint. */
|
||||||
u32 metadata_offset;
|
u32 metadata_offset;
|
||||||
u32 flags;
|
u32 flags;
|
||||||
|
u32 meso_size;
|
||||||
u32 num_kips;
|
u32 num_kips;
|
||||||
u32 reserved1[4];
|
u32 reserved1[3];
|
||||||
u32 magic;
|
u32 magic;
|
||||||
u32 total_size;
|
u32 total_size;
|
||||||
u32 reserved2; /* Previously crt0 offset. */
|
u32 reserved2; /* Previously crt0 offset. */
|
||||||
|
|
|
@ -834,7 +834,8 @@ namespace ams::nxboot {
|
||||||
/* Build modified package2. */
|
/* Build modified package2. */
|
||||||
RebuildPackage2(target_firmware, emummc_enabled);
|
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(sizeof(InitialProcessMeta) == 0x40);
|
||||||
static_assert(alignof(InitialProcessMeta) == 0x10);
|
static_assert(alignof(InitialProcessMeta) == 0x10);
|
||||||
|
|
||||||
|
constexpr inline const u64 FsProgramId = 0x0100000000000000;
|
||||||
|
|
||||||
enum FsVersion {
|
enum FsVersion {
|
||||||
FsVersion_1_0_0 = 0,
|
FsVersion_1_0_0 = 0,
|
||||||
|
|
||||||
|
@ -284,6 +286,11 @@ namespace ams::nxboot {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AddInitialProcess(const InitialProcessHeader *kip, const se::Sha256Hash *hash = nullptr) {
|
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. */
|
/* Handle the initial case. */
|
||||||
if (g_initial_process_binary_size == 0) {
|
if (g_initial_process_binary_size == 0) {
|
||||||
AddInitialProcessImpl(std::addressof(g_initial_process_meta), kip, hash);
|
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) {
|
void *ReadFile(s64 *out_size, const char *path, size_t align = 0x10) {
|
||||||
fs::FileHandle file;
|
fs::FileHandle file;
|
||||||
if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) {
|
if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), path, fs::OpenMode_Read))) {
|
||||||
|
@ -674,7 +735,6 @@ namespace ams::nxboot {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get meta for FS process. */
|
/* Get meta for FS process. */
|
||||||
constexpr u64 FsProgramId = 0x0100000000000000;
|
|
||||||
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. */
|
||||||
|
@ -833,7 +893,220 @@ namespace ams::nxboot {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RebuildPackage2(ams::TargetFirmware target_firmware, bool emummc_enabled) {
|
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']
|
KIP_NAMES = ['Loader', 'NCM', 'ProcessManager', 'sm', 'boot', 'spl', 'ams_mitm']
|
||||||
|
|
||||||
def get_kips():
|
def get_kips():
|
||||||
emummc = read_file('../../../../emummc/emummc.kip')
|
emummc = read_file('../../../../emummc/emummc_unpacked.kip')
|
||||||
loader = read_file('../../../../stratosphere/loader/loader.kip')
|
loader = read_file('../../../../stratosphere/loader/loader.kip')
|
||||||
ncm = read_file('../../../../stratosphere/ncm/ncm.kip')
|
ncm = read_file('../../../../stratosphere/ncm/ncm.kip')
|
||||||
pm = read_file('../../../../stratosphere/pm/pm.kip')
|
pm = read_file('../../../../stratosphere/pm/pm.kip')
|
||||||
|
@ -45,11 +45,11 @@ def write_kip_meta(f, kip, ofs):
|
||||||
# Write program id
|
# Write program id
|
||||||
f.write(kip[0x10:0x18])
|
f.write(kip[0x10:0x18])
|
||||||
# Write offset, size
|
# Write offset, size
|
||||||
f.write(pk('<II', ofs, len(kip)))
|
f.write(pk('<II', ofs - 0x100000, len(kip)))
|
||||||
# Write hash
|
# Write hash
|
||||||
f.write(hashlib.sha256(kip).digest())
|
f.write(hashlib.sha256(kip).digest())
|
||||||
|
|
||||||
def write_header(f, all_kips):
|
def write_header(f, all_kips, meso_size):
|
||||||
# Unpack kips
|
# Unpack kips
|
||||||
emummc, kips = all_kips
|
emummc, kips = all_kips
|
||||||
# Write reserved0 (previously entrypoint) as infinite loop instruction.
|
# Write reserved0 (previously entrypoint) as infinite loop instruction.
|
||||||
|
@ -58,15 +58,17 @@ def write_header(f, all_kips):
|
||||||
f.write(pk('<I', 0x20))
|
f.write(pk('<I', 0x20))
|
||||||
# Write flags
|
# Write flags
|
||||||
f.write(pk('<I', 0x00000000))
|
f.write(pk('<I', 0x00000000))
|
||||||
|
# Write meso_size
|
||||||
|
f.write(pk('<I', meso_size))
|
||||||
# Write num_kips
|
# Write num_kips
|
||||||
f.write(pk('<I', len(KIP_NAMES)))
|
f.write(pk('<I', len(KIP_NAMES)))
|
||||||
# Write reserved2
|
# Write reserved1
|
||||||
f.write(b'\xCC' * 0x10)
|
f.write(b'\xCC' * 0xC)
|
||||||
# Write magic
|
# Write magic
|
||||||
f.write('FSS0')
|
f.write('FSS0')
|
||||||
# Write total size
|
# Write total size
|
||||||
f.write(pk('<I', 0x800000))
|
f.write(pk('<I', 0x800000))
|
||||||
# Write reserved3
|
# Write reserved2
|
||||||
f.write(pk('<I', 0xCCCCCCCC))
|
f.write(pk('<I', 0xCCCCCCCC))
|
||||||
# Write content_header_offset
|
# Write content_header_offset
|
||||||
f.write(pk('<I', 0x40))
|
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', 0x7C0000, 0x020000, 0, 0, 0, 0, 0xCCCCCCCC, 'fusee'))
|
||||||
f.write(pk('<IIBBBBI16s', 0x7E0000, 0x001000, 3, 0, 0, 0, 0xCCCCCCCC, 'rebootstub'))
|
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'))
|
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:
|
for kip_name in KIP_NAMES:
|
||||||
kip_data = kips[kip_name]
|
kip_data = kips[kip_name]
|
||||||
f.write(pk('<IIBBBBI16s', ofs, len(kip_data), 6, 0, 0, 0, 0xCCCCCCCC, kip_name))
|
f.write(pk('<IIBBBBI16s', ofs, len(kip_data), 6, 0, 0, 0, 0xCCCCCCCC, kip_name))
|
||||||
ofs += len(kip_data)
|
ofs += len(kip_data)
|
||||||
|
ofs += 0xF
|
||||||
|
ofs &= ~0xF
|
||||||
# Pad to kip metas.
|
# Pad to kip metas.
|
||||||
f.write(b'\xCC' * (0x400 - 0x40 - (0x20 * (8 + len(KIP_NAMES)))))
|
f.write(b'\xCC' * (0x400 - 0x40 - (0x20 * (8 + len(KIP_NAMES)))))
|
||||||
# Write emummc_meta. */
|
# Write emummc_meta. */
|
||||||
write_kip_meta(f, emummc, 0x100000)
|
write_kip_meta(f, emummc, 0x100000)
|
||||||
# Write kip metas
|
# Write kip metas
|
||||||
ofs = 0x100000 + len(emummc)
|
ofs = (0x100000 + len(emummc) + 0xF) & ~0xF
|
||||||
for kip_name in KIP_NAMES:
|
for kip_name in KIP_NAMES:
|
||||||
kip_data = kips[kip_name]
|
kip_data = kips[kip_name]
|
||||||
write_kip_meta(f, kip_data, ofs)
|
write_kip_meta(f, kip_data, ofs)
|
||||||
ofs += len(kip_data)
|
ofs += len(kip_data)
|
||||||
|
ofs += 0xF
|
||||||
|
ofs &= ~0xF
|
||||||
# Pad to end of header
|
# Pad to end of header
|
||||||
f.write(b'\xCC' * (0x800 - (0x400 + (1 + len(KIP_NAMES)) * 0x30)))
|
f.write(b'\xCC' * (0x800 - (0x400 + (1 + len(KIP_NAMES)) * 0x30)))
|
||||||
|
|
||||||
|
@ -112,10 +118,18 @@ def write_kips(f, all_kips):
|
||||||
f.write(emummc)
|
f.write(emummc)
|
||||||
# Write kips
|
# Write kips
|
||||||
tot = len(emummc)
|
tot = len(emummc)
|
||||||
|
if (tot & 0xF):
|
||||||
|
f.write('\xCC' * (0x10 - (tot & 0xF)))
|
||||||
|
tot += 0xF
|
||||||
|
tot &= ~0xF
|
||||||
for kip_name in KIP_NAMES:
|
for kip_name in KIP_NAMES:
|
||||||
kip_data = kips[kip_name]
|
kip_data = kips[kip_name]
|
||||||
f.write(kip_data)
|
f.write(kip_data)
|
||||||
tot += len(kip_data)
|
tot += len(kip_data)
|
||||||
|
if (tot & 0xF):
|
||||||
|
f.write('\xCC' * (0x10 - (tot & 0xF)))
|
||||||
|
tot += 0xF
|
||||||
|
tot &= ~0xF
|
||||||
# Pad to 3 MB
|
# Pad to 3 MB
|
||||||
f.write(b'\xCC' * (0x300000 - tot))
|
f.write(b'\xCC' * (0x300000 - tot))
|
||||||
|
|
||||||
|
@ -137,11 +151,12 @@ def main(argc, argv):
|
||||||
erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4]
|
erista_hsh = hashlib.sha256(erista_mtc[:-4]).digest()[:4]
|
||||||
mariko_hsh = hashlib.sha256(mariko_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])
|
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:
|
with open('../../program%s.lz4' % target, 'wb') as f:
|
||||||
f.write(fusee_program)
|
f.write(fusee_program)
|
||||||
with open('../../fusee-boogaloo%s.bin' % target, 'wb') as f:
|
with open('../../fusee-boogaloo%s.bin' % target, 'wb') as f:
|
||||||
# Write header
|
# Write header
|
||||||
write_header(f, all_kips)
|
write_header(f, all_kips, len(mesosphere))
|
||||||
# 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
|
||||||
|
|
|
@ -333,7 +333,7 @@ namespace ams::secmon {
|
||||||
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable));
|
static_assert(MemoryRegionPhysicalTzramNonVolatile.Contains(MemoryRegionPhysicalTzramL2L3PageTable));
|
||||||
|
|
||||||
constexpr inline const MemoryRegion MemoryRegionPhysicalTzramFullProgramImage = MemoryRegion(UINT64_C(0x7C010800), 0xD800);
|
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 MemoryRegionPhysicalIramBootCodeCode = MemoryRegion(UINT64_C(0x40032000), 0x1000);
|
||||||
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeKeys = MemoryRegion(UINT64_C(0x40033000), 0x1000);
|
constexpr inline const MemoryRegion MemoryRegionPhysicalIramBootCodeKeys = MemoryRegion(UINT64_C(0x40033000), 0x1000);
|
||||||
|
|
Loading…
Reference in a new issue