Nyx: emuMMC tab realign on reload, sd_out script, bootloader/sys doc

- gui_emummc_tools: re-apply container position after reload so content
  does not jump to top when returning from sub-windows (Change emuMMC, etc.)
- Add sd_out.py: pack build output to output/hekate_X.Y.Z_Nyx_A.B.C.zip
  (payload.bin, bootloader/update.bin, bootloader/sys/*, no ini/patches)
- Add nyx/BOOTLOADER_SYS_ORIGINS.md: where res.pak, thk.bin, emummc.kipm, l4t/ come from

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-20 22:54:16 +01:00
parent fed7f05831
commit 6b956c6fe2
3 changed files with 161 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
# bootloader/sys/ Missing files and where they come from
The repo only builds and packages **nyx.bin**, **libsys_lp0.bso**, and **libsys_minerva.bso**. The rest of `bootloader/sys/` is not built here. Below is where each missing piece comes from.
---
## res.pak
- **What:** Nyx GUI resource pack (fonts, glyphs, assets). Loaded at `NYX_RES_ADDR`; without it Nyx will show “res.pak not found or corrupted”.
- **Where:** Built with **nyx-res-tool** (extract/build res.pak from a directory of resources).
- **Repo:** https://github.com/friedkeenan/nyx-res-tool
- **Usage:** `extract.py` to unpack an existing res.pak; `build.py` to pack a directory into res.pak.
- **Alternative:** Use a res.pak from an official hekate release (e.g. CTCaer) and place it in `bootloader/sys/`.
---
## thk.bin
- **What:** Atmosphère **Tsec Hovi Keygen** firmware. Used for TSEC/crypto when booting HOS (e.g. package1 decryption). If missing, boot can fail with TSEC/keygen errors.
- **Where:** From **Atmosphère** (Atmosphere-NX/Atmosphere). It is built as part of their sept/tsec keygen and shipped in their release package; the binary that hekate expects as `bootloader/sys/thk.bin` is that keygen blob.
- **Repo:** https://github.com/Atmosphere-NX/Atmosphere
- **In practice:** Copy `thk.bin` from an official Atmosphère release (e.g. `atmosphere/` or their “hekate” bundle) into `bootloader/sys/`.
---
## emummc.kipm
- **What:** emuMMC **KIP1 module** (patch data). Injected into the **FS** KIP1 at boot when emuMMC is used (`_kipm_inject("bootloader/sys/emummc.kipm", "FS", ki)` in `pkg2.c`). Contains caps + .text that get merged into the FS kip.
- **Where:** Built from the **m4xw/emuMMC** project (not this repo).
- **Repo:** https://github.com/m4xw/emuMMC
- **Build (hekate):** Run `./build.sh` in the emuMMC repo; it produces a `.kipm` file. Copy that file to `bootloader/sys/` as `emummc.kipm`.
- **Requirements:** devkitARM / devkitA64 and the toolchain expected by the emuMMC Makefile (see their README).
- **Alternative:** Copy **emummc.kipm** from an official hekate release (e.g. CTCaer/hekate) into `bootloader/sys/`. Use a kipm that matches your hekate/HOS version.
---
## bootloader/sys/l4t/
- **What:** Firmware blobs for **L4T** (Linux/Android on Switch): BL31, BL33, SC7 entry/exit, BPMP, etc. Used when booting L4T or when warmboot needs `sc7exit_b01.bin`.
- **Files expected (from `l4t.c` and `pkg1.c`):**
- `bl31.bin`
- `bl33.bin`
- `sc7entry.bin`
- `sc7exit.bin`
- `bpmpfw.bin`
- `bpmpfw_b01.bin`
- `mtc_tbl_b01.bin`
- `sc7exit_b01.bin` (referenced in `pkg1.c` for warmboot)
- **Where:** From **L4T / Switchroot** (or similar) L4T/SD release packages that provide “bootloader/sys/l4t/” (or equivalent) with these binaries. Not built in hekate-pro.
- **In practice:** Copy the **l4t/** folder (with the files above) from an official hekate L4T-capable release or from a Switchroot/L4T image that matches the expected layout.
---
## Summary
| File or folder | Origin |
|----------------------|--------|
| **res.pak** | Build with [nyx-res-tool](https://github.com/friedkeenan/nyx-res-tool), or copy from official hekate release. |
| **thk.bin** | Atmosphère (sept/tsec keygen); copy from official Atmosphère release. |
| **emummc.kipm** | Build from [m4xw/emuMMC](https://github.com/m4xw/emuMMC) (`./build.sh`), or copy from official hekate release. |
| **bootloader/sys/l4t/** | L4T/Switchroot firmware; copy from hekate L4T bundle or L4T image. |
After copying these into `bootloader/sys/` (and `bootloader/sys/l4t/`), your SD layout matches what the reference `hekate_pro_6.5.1_Nyx_1.9.1`-style folder expects.

View File

@@ -23,6 +23,7 @@
#include <libs/lvgl/lv_objx/lv_list.h>
#include <libs/lvgl/lv_objx/lv_mbox.h>
#include <libs/lvgl/lv_objx/lv_slider.h>
#include <libs/lvgl/lv_objx/lv_win.h>
#include <memory_map.h>
#include <module.h>
#include <stdlib.h>
@@ -2120,6 +2121,13 @@ lv_res_t create_tab_emummc_tools(lv_obj_t *parent)
lv_obj_align(h1, parent, LV_ALIGN_IN_TOP_LEFT, 0, 0);
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);
/* Re-apply container position after reload so it does not jump when returning from sub-windows */
lv_obj_t *win = lv_obj_get_parent(parent);
if (win) {
lv_obj_t *content = lv_win_get_content(win);
if (content)
lv_obj_align(parent, content, LV_ALIGN_IN_TOP_MID, -20, 50);
}
return LV_RES_OK;
}

90
sd_out.py Normal file
View File

@@ -0,0 +1,90 @@
#!/usr/bin/env python3
"""
Pack hekate build output into a ZIP with SD card layout:
ZIP
├── payload.bin (hekate payload for injection / root of SD)
└── bootloader/
├── update.bin (hekate payload; for modchips / auto-update)
├── ini/ (empty; for More configs)
├── res/ (empty; for user icons/background)
├── payloads/ (empty; for Payloads menu)
└── sys/
├── nyx.bin
├── libsys_lp0.bso
└── libsys_minerva.bso
Run from repo root after `make`. No hekate_ipl.ini or patches.ini.
Optional: res.pak, thk.bin, emummc.kipm must be added separately.
"""
import os
import re
import sys
import zipfile
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parent
OUTPUT = REPO_ROOT / "output"
def parse_versions():
"""Read Versions.inc and return (bl_ver, nyx_ver) e.g. ('6.5.1', '1.9.1')."""
inc = REPO_ROOT / "Versions.inc"
if not inc.exists():
return ("0.0.0", "0.0.0")
vals = {}
for line in inc.read_text().splitlines():
m = re.match(r"(\w+)\s*:?=\s*(\d+)", line.strip())
if m:
vals[m.group(1)] = m.group(2)
bl_ver = f"{vals.get('BLVERSION_MAJOR', 0)}.{vals.get('BLVERSION_MINOR', 0)}.{vals.get('BLVERSION_HOTFX', 0)}"
nyx_ver = f"{vals.get('NYXVERSION_MAJOR', 0)}.{vals.get('NYXVERSION_MINOR', 0)}.{vals.get('NYXVERSION_HOTFX', 0)}"
return (bl_ver, nyx_ver)
def main():
bl_ver, nyx_ver = parse_versions()
zip_name = f"hekate_{bl_ver}_Nyx_{nyx_ver}.zip"
zip_path = OUTPUT / zip_name
# Required build artifacts
payload_src = OUTPUT / "hekate.bin"
sys_files = [
("bootloader/sys/nyx.bin", OUTPUT / "nyx.bin"),
("bootloader/sys/libsys_lp0.bso", OUTPUT / "libsys_lp0.bso"),
("bootloader/sys/libsys_minerva.bso", OUTPUT / "libsys_minerva.bso"),
]
missing = []
if not payload_src.exists():
missing.append(str(payload_src))
for _, src in sys_files:
if not src.exists():
missing.append(str(src))
if missing:
print("Missing build outputs (run 'make' first):", file=sys.stderr)
for m in missing:
print(" ", m, file=sys.stderr)
sys.exit(1)
zip_path.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
# Payload at root (for injection / some setups)
zf.write(payload_src, "payload.bin")
# bootloader/update.bin (same payload; for modchips / auto-update)
zf.write(payload_src, "bootloader/update.bin")
# bootloader/sys/*
for arc, src in sys_files:
zf.write(src, arc)
# Empty dirs (ZIP has no true directories; .keep so extractors create them)
for d in ("bootloader/ini/", "bootloader/res/", "bootloader/payloads/", "bootloader/screenshots/"):
zf.writestr(d + ".keep", "")
print(f"Wrote {zip_path}")
print("Note: res.pak, thk.bin, emummc.kipm are not in this repo; add to bootloader/sys/ if needed.")
if __name__ == "__main__":
main()