el reconciliador ARRANCA solo: montar sysfs, y un diagnóstico que no mentía a medias

Cierra el §2 del ADR 0018, verificado con dos arranques de la imagen
completa en OVMF:

  1º (por la fallback) → "ESP detectada en /dev/vda p1",
     "⚠ EL ARRANQUE ESTABA CAMBIADO — takana lo repuso",
     "faltaba la entrada «takana» ⇒ escrita en Boot0004",
     "BootOrder: 0000,0001,0002,0003 → 0004,0000,0001,0002,0003"
  2º → BdsDxe: starting Boot0004 "takana" from HD(1,GPT,923A070F-…)
       /\EFI\takana\takanax64.efi
       "✓ arranque en orden: Boot0004 «takana» ya es la primera"

Un sistema recién instalado se da de alta en el firmware en su PRIMER
arranque y desde el segundo arranca por su propia entrada, sin que nadie
corra un comando. Y el segundo no escribe nada.

Lo caro no fue el reconciliador sino un diagnóstico FALSO: el primer
arranque con el hook dijo "sin firmware EFI — esta máquina no arrancó
por UEFI" en una VM que SÍ arrancó por UEFI. La causa no tenía nada que
ver con UEFI: busybox switch_root no arrastra /sys —igual que no
arrastra /dev, cosa que el script ya contemplaba— así que el directorio
de efivars no existía. El mensaje mandaba a investigar el firmware, que
estaba perfecto.

Dos arreglos:
- el wrapper monta sysfs y después efivarfs. CONFIG_EFIVAR_FS=y ya
  estaba en el .config SELLADO (verificado, no supuesto) ⇒ no se
  re-hashea ningún kernel.
- el mensaje distingue TRES estados que se parecen: no existe (BIOS o
  /sys sin montar), existe y está VACÍO (falta el mount, y lo dice con
  el comando exacto), o tiene variables. Decir "no hay UEFI" cuando
  falta un mount manda a diagnosticar al lugar equivocado.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HHAKWoBqof9XvsYCvDicEj
This commit is contained in:
Sergio
2026-09-11 22:25:12 +00:00
co-authored by Claude Opus 5
parent 236abe48f3
commit 66eaf8738f
4 changed files with 69 additions and 2 deletions
+11 -2
View File
@@ -1574,9 +1574,18 @@ fn main() -> anyhow::Result<()> {
EntryCmd::Reconcile { loader, label, efivars, sys_block, disk, partition, dry_run } => {
// 1) ¿Hay firmware EFI? Sin NVRAM no hay nada que reconciliar, y eso NO es
// un error: puede ser una máquina que arranca por BIOS. Salir limpio.
// Tres estados que se parecen y NO son lo mismo. Decir «no arrancó por UEFI»
// cuando lo que falta es un `mount` manda a diagnosticar al lugar equivocado
// — y eso pasó de verdad en el primer arranque de este hook.
if !efi_boot::hay_firmware_efi(&efivars) {
println!("boot entry reconcile: sin firmware EFI en {} — nada que hacer", efivars.display());
println!(" (esta máquina no arrancó por UEFI; el arranque sigue normal)");
if !efivars.exists() {
println!("boot entry reconcile: no existe {} — nada que hacer", efivars.display());
println!(" (o esta máquina arrancó por BIOS, o /sys no está montado)");
} else {
println!("boot entry reconcile: {} existe pero está VACÍO", efivars.display());
println!(" ⇒ falta montarlo: mount -t efivarfs efivarfs {}", efivars.display());
println!(" (NO es que no haya UEFI: el directorio existe porque el kernel trae CONFIG_EFI)");
}
return Ok(());
}
+39
View File
@@ -69,6 +69,45 @@ Y —esto no es opcional— **el reconciliador reporta que tuvo que actuar**. Si
usuario vive con una rareza intermitente que nunca entiende. Un ausente falla ruidosamente; un
arreglo mudo se parece demasiado a que no pasó nada (regla 3 de `CLAUDE.md`).
> **ENMIENDA 2026-09-11 (3ª) — el §2 está implementado, y lo caro no fue el reconciliador.**
>
> `takana boot entry reconcile` descubre su propia ESP por **tipo de partición** (GUID de ESP en GPT,
> `0xEF` en MBR), que es el único dato fiable sin montar nada. Si hay **varias** ESP no adivina: las
> lista y pide `--disk`. Elegir mal significa escribir una entrada que apunta a un disco que puede no
> estar, y eso es peor que no escribir nada. Corre desde el wrapper de PID1 de las dos imágenes, y
> cuando actúa **grita a `/dev/tty0` además del serial** — un reconciliador que repara en silencio
> deja al usuario conviviendo con una rareza que no entiende.
>
> **Lo que costó el tiempo fue un diagnóstico falso, y vale más que el código:** el primer arranque
> con el hook puesto imprimió
>
> > `boot entry reconcile: sin firmware EFI en /sys/firmware/efi/efivars — nada que hacer`
> > `(esta máquina no arrancó por UEFI)`
>
> **en una VM que había arrancado por UEFI.** La causa no tenía nada que ver con UEFI:
> `busybox switch_root` **no arrastra `/sys`** —igual que no arrastra `/dev`, cosa que el script ya
> contemplaba con su `mount -t devtmpfs`— así que `/sys/firmware/efi/efivars` sencillamente no
> existía. El mensaje mandaba a investigar el firmware, que estaba perfecto.
>
> **Verificado después en la máquina real, dos arranques seguidos de la imagen completa:**
>
> | arranque | qué hizo | salida |
> |---|---|---|
> | 1º (por la ruta fallback) | detectó su ESP **solo** y vio que faltaba la entrada | `ESP detectada en /dev/vda p1` · `⚠ EL ARRANQUE ESTABA CAMBIADO — takana lo repuso` · `faltaba la entrada «takana» ⇒ escrita en Boot0004` · `BootOrder: 0000,0001,0002,0003 → 0004,0000,…` |
> | 2º (sin tocar nada) | **el firmware arrancó por la entrada que se escribió sola** | `BdsDxe: starting Boot0004 "takana" from HD(1,GPT,923A070F-…)/\EFI\takana\takanax64.efi` · `✓ arranque en orden: Boot0004 «takana» ya es la primera` |
>
> O sea: un sistema recién instalado **se da de alta en el firmware en su primer arranque** y a
> partir del segundo arranca por su propia entrada, sin que nadie corra un comando. Y el segundo
> arranque no escribe nada.
>
> Dos arreglos, y el segundo importa tanto como el primero:
> 1. El wrapper monta `sysfs` y después `efivarfs`. El kernel ya traía `CONFIG_EFIVAR_FS=y`
> —verificado en el `.config` **sellado**, no supuesto—, así que no se re-hashea nada.
> 2. El mensaje distingue ahora **tres** estados que se parecen: el directorio no existe (BIOS, o
> `/sys` sin montar), existe y está **vacío** (falta el `mount`, y lo dice con el comando exacto),
> o tiene variables. Decir «no hay UEFI» cuando lo que falta es un `mount` manda a diagnosticar al
> lugar equivocado — y el que se equivocó primero fue este ADR.
### 3. La segunda pata, porque el reconciliador tiene huevo y gallina
Si Windows deja a takana de último, **takana no arranca, y entonces el reconciliador nunca corre**.
+13
View File
@@ -194,6 +194,19 @@ if [ -x /usr/bin/hammer ]; then
/bin/busybox timeout 15 /usr/bin/hammer boot menu > /dev/ttyS0 2>&1 || true
fi
# efivarfs: la NVRAM del firmware NO es visible hasta que se monta, y el kernel `linux-metal` ya trae
# CONFIG_EFIVAR_FS=y (verificado en el .config sellado, no supuesto) — sólo faltaba montarlo. El
# directorio sólo existe si la máquina arrancó por UEFI, así que el `[ -d ]` es la prueba de firmware
# y no una precaución: en BIOS no está y no hay nada que montar.
# ⚠ `busybox switch_root` NO arrastra /sys, igual que no arrastra /dev (por eso existe la línea del
# devtmpfs de arriba). Sin sysfs, `/sys/firmware/efi/efivars` NO EXISTE y el reconciliador concluye
# «esta máquina no arrancó por UEFI» — en una máquina que arrancó por UEFI. Medido: el primer intento
# de este hook dio exactamente ese diagnóstico falso.
/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true
if [ -d /sys/firmware/efi/efivars ]; then
/bin/busybox mount -t efivarfs efivarfs /sys/firmware/efi/efivars 2>/dev/null || true
fi
# Reconciliador del arranque (ADR 0018 §2). La NVRAM del firmware es estado compartido: otro sistema
# operativo instalado al lado la reescribe sin coordinarse —Windows Update poniéndose primero en
# BootOrder es el caso típico—. Contra eso no sirve confiar, sirve CONVERGER en cada arranque.
+6
View File
@@ -452,6 +452,12 @@ echo "HAMMER-EFI-INIT-OK: arje-zero PID1" > /dev/ttyS0 2>/dev/null || true
# Menú de arranque por grafo (ADR 0010): emite /run/hammer/boot-graph.json y, si hay compositor (mirada),
# lo pinta sobre KMS. Graceful (sin compositor sigue) y al serial (no pinta tty0 ⇒ cero-parpadeo).
[ -x /usr/bin/hammer ] && /usr/bin/hammer boot menu > /dev/ttyS0 2>&1 || true
# efivarfs: sin montarlo la NVRAM del firmware no se ve. El directorio sólo existe si arrancamos por
# UEFI, así que el `[ -d ]` distingue UEFI de BIOS sin preguntarle a nadie.
# switch_root no arrastra /sys (ni /dev): sin esto el directorio de efivars no existe y el
# reconciliador diagnostica «no arrancó por UEFI» en una máquina que sí lo hizo.
/bin/busybox mount -t sysfs sys /sys 2>/dev/null || true
[ -d /sys/firmware/efi/efivars ] && /bin/busybox mount -t efivarfs efivarfs /sys/firmware/efi/efivars 2>/dev/null || true
# Reconciliador del arranque (ADR 0018 §2): la NVRAM es estado compartido y el vecino la reescribe
# sin avisar. Converger en cada arranque, y DECIRLO en pantalla cuando hubo que actuar — si repara
# en silencio, el usuario nunca se entera de que algo le está pisando el arranque.