Primer entregable de release engineering (SDD 13 nuevo): scripts/install-image.sh produce una imagen GPT que se BOOTEA SOLA en QEMU (`-drive file=img`, sin -kernel ni firmware extra) — SeaBIOS → MBR → GRUB → kernel del propio disco → arje-zero PID 1. Capaz de arrancar en hardware real. Layout: vda1=BIOS boot (ef02), vda2=/ (con /boot/bzImage + /boot/grub), vda3=/store, vda4=/var/lib/hammer. Reusa el particionado sin-root de B3 (sfdisk + mke2fs -d bajo unshare -r + dd conv=sparse) y el wrapper /sbin/init. GRUB instalado SIN root ni loop: grub-bios-setup sondea el disco físico del host (/dev/nvme…, 660 root:disk) para adivinar el root device del dir -d y falla sin privilegios. Lo reemplaza un patch binario determinista sobre la ABI estable de GRUB i386-pc: grub-mkimage arma core.img; un script Python escribe core.img en la BIOS boot partition y parchea los punteros (boot.img off 0x5c kernel_sector → LBA de core.img; core.img off 0x1F4 blocklist.start → resto de core.img), con asserts de los valores por defecto (1 y 2) para fallar ruidoso si la ABI cambia. boot.img va al MBR sin pisar la GPT protective (sólo 440 B). Verificado in-VM (KVM, sin -kernel): SeaBIOS → GRUB 2.14 → Linux 6.16.12 → vda1..4 detectadas, vda2 root + vda3/vda4 montadas por el wrapper (0 errores) → arje-zero PID 1 + hammerd (store=/store journal=/var/lib/hammer/journal). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
61 lines
4.0 KiB
Markdown
61 lines
4.0 KiB
Markdown
# SDD 13 — Release engineering (Etapa E): imagen auto-booteable, instalador, mirror, upgrades
|
||
|
||
> Estado: **EN CURSO**. Etapa E del roadmap (`docs/10-roadmap.md`, memoria distro-completion-roadmap).
|
||
> Es trabajo nuevo: las Etapas A–D dejaron un sistema que (A) se orquesta, (B) bootea de disco
|
||
> particionado real, (C) tiene userland Rust-nativo y (D) atesta confianza. Falta convertir eso en algo
|
||
> que un tercero **instale y arranque sin el host de dev**: una imagen que bootea sola (sin
|
||
> `qemu -kernel`), un instalador a disco físico, un mirror del store y un camino de upgrade.
|
||
|
||
## 1. El gap concreto que abre la Etapa E
|
||
|
||
Hasta B3 la imagen de disco (`scripts/disk-image.sh`, GPT con `/`, `/store`, `/var/lib/hammer`
|
||
dedicados) **no se auto-bootea**: el `drive-rebuild.py` la arranca con `qemu -kernel <bzImage>
|
||
-append root=/dev/vdaN` — el kernel lo carga QEMU, no la imagen. Eso sirve para verificar el
|
||
auto-alojamiento, pero un disco así no arranca en hardware real ni en una VM "normal": le falta un
|
||
**bootloader** en el propio disco.
|
||
|
||
## 2. Decisión de bootloader: GRUB BIOS (i386-pc) ahora, UEFI después
|
||
|
||
- **GRUB BIOS (i386-pc) — ELEGIDO para el primer corte.** QEMU trae SeaBIOS built-in ⇒ un disco con
|
||
GRUB en el MBR + una *BIOS boot partition* (GPT type `ef02`) bootea con `qemu-system-x86_64 -drive
|
||
file=img` **sin firmware extra ni `-kernel`**. Se instala **en userspace, sin root ni loop**:
|
||
`grub-mkimage` arma `core.img` y `grub-bios-setup` escribe `boot.img`→MBR + `core.img`→partición
|
||
BIOS sobre el *fichero* imagen (es I/O de bloques, no necesita montar). Los módulos de GRUB y el
|
||
kernel van en `/boot` de la partición root, que `mke2fs -d` puebla desde un directorio.
|
||
- **UEFI (EFI-stub + ESP FAT) — diferido.** El kernel ya trae `CONFIG_EFI_STUB=y`, pero (a) el host de
|
||
dev no tiene firmware OVMF usable para verificar el arranque, y (b) poblar un ESP FAT sin root exige
|
||
`mtools` (ausente). Camino futuro cuando haya OVMF + mtools (o se construyan): ESP con
|
||
`EFI/BOOT/BOOTX64.EFI` = el bzImage (EFI-stub), cmdline por `loader.conf`/UKI.
|
||
|
||
## 3. Layout de la imagen instalable (GPT, BIOS)
|
||
|
||
```
|
||
/dev/vda1 BIOS boot (ef02, ~2 MiB, sin fs) core.img de GRUB
|
||
/dev/vda2 / ext4 [hammer-root] + /boot/bzImage + /boot/grub
|
||
/dev/vda3 /store ext4 [hammer-store] artefactos CAS (inmutable)
|
||
/dev/vda4 /var/lib/hammer ext4 [hammer-state] estado mutable (journal, overlays)
|
||
```
|
||
|
||
Cadena de arranque: SeaBIOS → MBR (boot.img) → core.img (BIOS boot part) → lee `(hd0,gpt2)/boot/grub/
|
||
grub.cfg` → `linux /boot/bzImage root=/dev/vda2 rdinit=/sbin/init` → wrapper `/sbin/init` monta
|
||
vda3/vda4 → `exec /usr/bin/arje-zero` (PID 1). El wrapper es el mismo puente de B3 (arje todavía no lee
|
||
fstab/cards de montaje por sí mismo).
|
||
|
||
`scripts/install-image.sh` produce esta imagen. Reusa la técnica de particionado sin-root de B3
|
||
(sfdisk + `mke2fs -d` bajo `unshare -r` + `dd conv=sparse,notrunc`) y añade la BIOS boot partition, el
|
||
kernel en `/boot`, los módulos GRUB en `/boot/grub/i386-pc` y los pasos `grub-mkimage`/`grub-bios-setup`.
|
||
|
||
## 4. Piezas pendientes de la Etapa E (orden tentativo)
|
||
|
||
- **E1 — imagen auto-booteable (GRUB BIOS): ✅ primer corte** (`scripts/install-image.sh`). Bootea en
|
||
QEMU sin `-kernel` hasta la shell de arje-zero. Hoy empaqueta el *builder rootfs* (con toolchain);
|
||
un *product rootfs* lean es refinamiento.
|
||
- **E2 — instalador a disco físico:** un `hammer install <device>` que particiona un disco real y
|
||
vuelca las tres particiones + GRUB (la misma lógica, apuntando a `/dev/sdX` en vez de un fichero).
|
||
- **E3 — mirror del store:** servir/replicar `/store` content-addressed (BLAKE3) entre máquinas; el
|
||
hash ES la dirección, así que un mirror es un CAS replicado + resolución por hash.
|
||
- **E4 — upgrades:** aplicar un nuevo árbol Stage 1 sin reinstalar — atómico vía el modelo overlay +
|
||
el journal (D), con rollback al árbol anterior.
|
||
- **E5 — ISO/medio de arranque:** medio live para correr el instalador (xorriso/grub-mkrescue;
|
||
herramental a construir).
|