# Worked example: EMV9.3 DVB-T2 release v2026.10.15 First release built with this procedure (project prjID `emv93-dvbt2`; its bmem entry records the location and the git tag `release-v2026.10.15`). Use it as a model. Board values below belong to EMV9.3 only and must not be reused for another board. ## Platform - Zynq xc7z100 (PL + PS) plus an i.MX6ULL board controller that has its own app and web UI. - Toolchain: PetaLinux 2018.1, Vivado 2018.1. - Two PetaLinux projects on the cross-build VM: - `emv93_t2`: production; FIT on eMMC, PL bin loaded by U-Boot `plload`. - `emv93_qspi`: rescue initramfs in QSPI. - The VM host and credentials come from `~\skills_env.md` (`CROSS_VM_*`). ## Requirement doc `Notes/PR02.md` listed nine items: 1. BSP 2. QSPI flash files 3. eMMC flash files 4. rootfs 5. PL bit on the rootfs 6. PS runtime 7. PS app source 8. i.MX6 app source 9. a README The Vivado (PL) sources were explicitly excluded. The i.MX6 runtime and the PC test tools were added as directories 09 and 10, because item 8 cannot be deployed without them. ## Layouts recorded from evidence QSPI layout (from the proven U-Boot scripts `g4_stage1.txt` and `g4g5_write.txt`): | Region | Offset | Content length | Erase length | CRC32 | |---|---|---|---|---| | BOOT.BIN | 0x0 | 0x89df0 | 0x500000 | 03cd9c7b | | U-Boot env | 0x500000 | — | 0x20000, left blank | — | | image.ub.qspi | 0x520000 | 0x9bbca0 | 0x1800000 | 0653b9e8 | | Full image | 0x0 | 0xEDBCA0 | — | 183d24ec | The full image was built with: ``` qspi_image.py qspi_full_0x0.bin 0x0:BOOT.BIN 0x520000:image.ub.qspi --erase 0x500000:0x20000 ``` eMMC layout: - Device `/dev/mmcblk1`, 7.3 GiB, the factory DOS partition table. - The partition boundaries came from `/proc/partitions` (179,1 = 125016 KiB) and a `fdisk -l` line ("16 250047 250032 122.1M b W95 FAT32"). - p1: FAT32, sectors 16–250047. It holds only 120 MB: P-0059 recorded that with seven bit files on it, `cp` failed silently. - p2: ext4, sector 250048 to the end. ## Pieces and where they came from | Release dir | Source | |---|---| | 01 BSP | `petalinux-package --bsp -p --output .bsp` on the VM, for both projects. Before packaging, the t2ps recipe's `files/src` was replaced with the released 1.8 sources; the old recipe was tarred as a backup first. | | 02 / 03 / 05 | The verified delivery directory (`Notes/auto/delivery_t2_dpd_20261014`). The VM `images/linux` hashes were checked against it, and they matched. | | 04 rootfs | Merged from the base `rootfs.tar.gz`, the T2 runtime overlay, the released binaries and configs, and the C23 symlinks. Each key member hash was checked against the board-verified files, and GNU tar on the VM listed all 1229 members. | | 06 | Copied from the delivery dirs; the stream files were extracted from the overlay tarball. | | 07 / 08 | `git archive ps` and `git archive imx6`, giving 325 files with no build output. | ## What the scan / review caught (and how it was handled) - **i.MX6 MACs.** - `network.conf` carried the test board's MAC. It was blanked in the release copy, with a comment. - The source copy and an old deploy script held two other boards' MACs; these were listed in the README. - Deriving the MAC from OTP does not work on that image, so the README says each board's MAC must be filled in. - **TP receiver address.** `t2ps.conf` holds the receiving PC's MAC/IP for the TP IQ stream; this is documented as a site setting. - **DPD curve.** It depends on the board and its loopback, so it was left out; a new board runs a full DPD instead. - **Development-machine paths.** The PC tools contain dev-machine paths; this is documented under the known limits. - **Credentials.** The product's own web account (`usr.conf`) is part of the firmware and stays. No infrastructure password appeared. - **Hardware not used.** The board went silent during packaging. That was harmless, because nothing in the release was taken from the live board. ## Script mistakes made the first time (now handled by the skill's scripts) - **Two archives unpacked into one directory.** The recipe tarball and the source tarball both unpacked into `t2ps/`, mixing their contents. Unpack each archive into its own empty directory. - **Shell `set -e` ignores a negated command.** `! grep` does not stop the script; write the test as an explicit `if`. - **Over-eager path normalisation.** `n.lstrip("./")` also strips the leading dot of names such as `./.ssh`. `merge_rootfs.py` removes only the `./` prefixes. - **CRLF from Windows editors.** Shell scripts written on Windows can get CRLF line endings. Strip them, then run `sh -n` and `busybox sh -n` on the VM. - **Archive bytes are not reproducible.** The gzip header mtime and the mtime of added files changed the archive hash on every run. `merge_rootfs.py` is now deterministic, so compare member hashes rather than archive bytes across tool versions.