tawasuyu

sergio/takana

> Una distribución Linux construida con un laboratorio funcional y hermético en el > sótano, y una terminal mutable, clásica y anárquica en el piso de arriba — diseñada > desde el suelo para que una IA programadora entienda, modifique y co…

TOML 1572Shell 203Rust 109Markdown 993728 Definiciones

Etapa B (B1+B2): boot desde disco real ext4, sin switch_root

B1 — kernel con disco+FS: linux.toml añade VIRTIO_BLK/VIRTIO_PCI/VIRTIO_NET/EXT4_FS
built-in (=y, sin módulos), aditivo al path initramfs. B2 — infra de disco:
  - scripts/disk-image.sh: empaqueta un rootfs como imagen ext4 booteable con
    `mke2fs -d` bajo `unshare -r` (archivos root-owned sin sudo, como el cpio
    --owner=root:root; evita EACCES en el copy-up de overlay del rebuild).
  - scripts/drive-rebuild.py: modo DISK= ⇒ QEMU monta la imagen como virtio /dev/vda
    y el kernel arranca con `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs.

Verificado en QEMU/KVM: el kernel monta /dev/vda ext4 como root REAL y arje-zero
arranca como PID 1 DIRECTO, sin el hack /init+switch_root (el muro pivot_root del
path initramfs desaparece por construcción: / ya es un mount pivotable).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

462e0275d3cc5ef13a495dfd13ecc34b87e9a883 · por sergio · (hace 4 meses) · padre 761b074d1 · ver el árbol en este commit

Delta semántico

Ninguna definición cambió: el cambio es de texto, documentación o datos.

3 archivos · +78 −5

diff --git a/recipes/linux.toml b/recipes/linux.toml
index 1f158442..48118e10 100644
--- a/recipes/linux.toml
+++ b/recipes/linux.toml
@@ -25,6 +25,10 @@
 # Config: defconfig x86_64 (base PC booteable en QEMU: 8250 serial, initrd, PCI) + ajustes monolíticos
 #   - E1000/OVERLAY_FS/USER_NS =y (built-in): el builder usa e1000 (vendoring) + overlay (sandbox bwrap)
 #     + user namespaces (bwrap). Built-in ⇒ sin inyección de .ko ni version-magic.
+#   - VIRTIO_BLK/VIRTIO_PCI/VIRTIO_NET/EXT4_FS =y (Etapa B, imagen en disco real): permiten montar un
+#     disco virtio (`/dev/vda`, ext4) como root sin initramfs ⇒ `root=/dev/vda rw` directo, sin el hack
+#     /init+switch_root. Built-in (no módulos) porque no hay initramfs que cargue .ko antes del root.
+#     Aditivos: no tocan el camino initramfs del selfhost-verify (que sigue booteando igual).
 #   - MODULE_SIG/DEBUG_INFO_BTF off: evitan firma de módulos y pahole (BTF), ausente del toolchain.
 #   - UNWINDER_FRAME_POINTER en vez de ORC: reduce objtool pero NO lo elimina — en x86_64 las
 #     mitigaciones (RETHUNK/retpoline-validation) seleccionan CONFIG_OBJTOOL igual, y objtool necesita
@@ -71,13 +75,14 @@ scripts/config -d MODULE_SIG -d MODULE_SIG_ALL -d DEBUG_INFO_BTF -d DEBUG_INFO \
   -e E1000 -e OVERLAY_FS -e USER_NS -e NAMESPACES \
   -e FANOTIFY -e FANOTIFY_ACCESS_PERMISSIONS \
   -e OVERLAY_FS_REDIRECT_DIR -e OVERLAY_FS_INDEX -e OVERLAY_FS_XINO_AUTO -e OVERLAY_FS_METACOPY \
+  -e VIRTIO -e VIRTIO_PCI -e VIRTIO_BLK -e VIRTIO_NET -e EXT4_FS \
   -d DRM -d AGP -d FB -d BACKLIGHT_CLASS_DEVICE -d SOUND -d SND \
   -d USB_SUPPORT -d MEDIA_SUPPORT -d INFINIBAND -d BT -d NFC -d CAN \
   -d WLAN -d WIRELESS -d CFG80211 -d MAC80211 -d RFKILL \
   -d HID_SUPPORT -d HID -d INPUT_MOUSE -d INPUT_JOYSTICK -d INPUT_TABLET -d INPUT_TOUCHSCREEN \
   -d WATCHDOG -d THUNDERBOLT -d FIREWIRE -d HWMON -d POWER_SUPPLY -d MEMSTICK -d MMC \
   -d ATA -d SCSI -d NVME_CORE -d MD -d STAGING -d IIO -d PPS -d PTP_1588_CLOCK \
-  -d EXT4_FS -d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS \
+  -d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS \
   -d DRM_I915 -d DRM_AMDGPU -d DRM_NOUVEAU -d DRM_RADEON && \
 make ARCH=x86_64 olddefconfig
 """
diff --git a/scripts/disk-image.sh b/scripts/disk-image.sh
new file mode 100755
index 00000000..57e167b1
--- /dev/null
+++ b/scripts/disk-image.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+# disk-image.sh — Etapa B (imagen en disco real): empaqueta un rootfs como imagen ext4 booteable de
+# disco virtio (/dev/vda) en vez de initramfs. Con un kernel que trae VIRTIO_BLK+EXT4 built-in
+# (recipes/linux.toml), QEMU monta la imagen como root REAL y el kernel arranca con
+# `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs, sin el wrapper /init+switch_root: `/` ya es un
+# mount ext4 pivotable (el muro pivot_root del path initramfs desaparece por construcción).
+#
+# `mke2fs -d <dir>` puebla la imagen DESDE un directorio sin montar nada y sin root (e2fsprogs >= 1.43).
+#
+# Uso:
+#   ./scripts/disk-image.sh                 # crea work/hammer-disk.img desde work/builder-rootfs
+#   BOOT=1 KERNEL=<bzImage> KVM=1 ./scripts/disk-image.sh   # además bootea y corre rebuild-stage1
+#
+# Variables:
+#   ROOTFS  dir rootfs a empaquetar      (default work/builder-rootfs, lo arma selfhost-verify)
+#   IMG     imagen de salida             (default work/hammer-disk.img)
+#   SIZE    tamaño de la imagen          (default 6G; el rootfs ronda ~2G + holgura para el rebuild)
+#   BOOT    1 ⇒ bootea con drive-rebuild.py tras crear la imagen
+#   KERNEL  bzImage con VIRTIO_BLK+EXT4  (requerido si BOOT=1)
+#   KVM/MEM/NET  passthrough a drive-rebuild.py
+set -eu
+ROOT="$(cd "$(dirname "$0")/.." && pwd)"
+cd "$ROOT"
+
+ROOTFS="${ROOTFS:-work/builder-rootfs}"
+IMG="${IMG:-work/hammer-disk.img}"
+SIZE="${SIZE:-6G}"
+
+[ -d "$ROOTFS" ] || { echo "no existe ROOTFS: $ROOTFS (corré selfhost-verify para armar el builder)" >&2; exit 1; }
+[ -x "$ROOTFS/sbin/init" ] || [ -L "$ROOTFS/sbin/init" ] || { echo "ROOTFS sin /sbin/init (arje-zero)" >&2; exit 1; }
+
+echo "==> rootfs : $ROOTFS ($(du -sh "$ROOTFS" | cut -f1))"
+echo "==> imagen : $IMG ($SIZE, ext4, label hammer-root)"
+rm -f "$IMG"
+# Ownership root en la imagen (igual que el `--owner=root:root` del cpio): el rebuild usa bwrap+overlay
+# con un userns que mapea 0→0; si los ficheros van con el uid del host (1000) el copy-up falla EACCES.
+# `unshare -r` mapea nuestro uid→0, así los ficheros uid-1000 se ven como root y mke2fs escribe uid 0
+# en la imagen — sin sudo. mke2fs -d puebla desde el dir sin montar. Fallback a mke2fs directo si no hay
+# unshare (la imagen quedaría uid-host: bootea y da shell, pero el rebuild fallaría en el copy-up).
+if command -v unshare >/dev/null 2>&1 && unshare -r true 2>/dev/null; then
+    unshare -r mke2fs -q -t ext4 -L hammer-root -d "$ROOTFS" "$IMG" "$SIZE"
+else
+    echo "   (sin unshare -r: imagen con uid del host; el rebuild in-VM podría fallar el copy-up)" >&2
+    mke2fs -q -t ext4 -L hammer-root -d "$ROOTFS" "$IMG" "$SIZE"
+fi
+echo "==> imagen creada: $(du -h "$IMG" | cut -f1)"
+
+if [ "${BOOT:-0}" = 1 ]; then
+    [ -n "${KERNEL:-}" ] || { echo "BOOT=1 requiere KERNEL=<bzImage con VIRTIO_BLK+EXT4>" >&2; exit 1; }
+    echo "==> booteando de disco (root=/dev/vda, sin initramfs ni switch_root)"
+    DISK="$IMG" KERNEL="$KERNEL" KVM="${KVM:-0}" MEM="${MEM:-6144}" NET="${NET:-1}" \
+        python3 scripts/drive-rebuild.py
+fi
diff --git a/scripts/drive-rebuild.py b/scripts/drive-rebuild.py
index 5eed8532..228975cf 100755
--- a/scripts/drive-rebuild.py
+++ b/scripts/drive-rebuild.py
@@ -8,6 +8,10 @@
 #
 # Variables de entorno (todas opcionales):
 #   BUILDER_CPIO  initramfs del builder        (default work/builder.cpio.gz)
+#   DISK          imagen ext4 a bootear como ROOT real (Etapa B). Si está seteada, se ignora el
+#                 initramfs: QEMU monta la imagen como disco virtio (/dev/vda) y el kernel arranca con
+#                 `root=/dev/vda rw rdinit=/sbin/init` — sin initramfs ni switch_root (/ ya es un mount
+#                 ext4 real, pivotable). Requiere un kernel con VIRTIO_BLK+EXT4 (recipes/linux.toml).
 #   KERNEL        bzImage/vmlinuz a bootear     (default /boot/vmlinuz-linux)
 #   MEM           RAM de la VM en MiB           (default 6144)
 #   CPU           modelo de CPU TCG             (default Broadwell; AVX2 sin KVM)
@@ -29,6 +33,9 @@ def envpath(name, default):
 
 
 CPIO = envpath("BUILDER_CPIO", "work/builder.cpio.gz")
+DISK = os.environ.get("DISK", "")  # Etapa B: si está, booteamos de disco real en vez de initramfs.
+if DISK and not os.path.isabs(DISK):
+    DISK = os.path.join(ROOT, DISK)
 KERNEL = os.environ.get("KERNEL", "/boot/vmlinuz-linux")
 LOG = envpath("LOG", "work/rebuild-run.log")
 MEM = os.environ.get("MEM", "6144")
@@ -37,7 +44,8 @@ DEADLINE = int(os.environ.get("DEADLINE", "14400"))
 WANT_KVM = os.environ.get("KVM", "0") == "1"
 WANT_NET = os.environ.get("NET", "1") == "1"
 
-for p, what in [(CPIO, "initramfs del builder"), (KERNEL, "kernel")]:
+_needed = [(DISK, "imagen de disco")] if DISK else [(CPIO, "initramfs del builder")]
+for p, what in _needed + [(KERNEL, "kernel")]:
     if not os.path.exists(p):
         sys.exit(f"no existe {what}: {p}")
 
@@ -54,12 +62,19 @@ net = ["-netdev", "user,id=n0", "-device", "e1000,netdev=n0"] if WANT_NET else [
 # (p.ej. el frente kernel-from-source: el bzImage hammer bootea pero bwrap falla en pivot_root porque /
 # es el rootfs absoluto del namespace; `rootfstype=tmpfs` NO lo arregla — la causa es que / no tiene
 # mount padre, no el tipo de fs). Override con APPEND="…".
-APPEND = os.environ.get("APPEND", "console=ttyS0 rdinit=/sbin/init")
+# Boot de disco (Etapa B) vs initramfs. En disco / ya es un mount ext4 real ⇒ rdinit=/sbin/init directo
+# (arje-zero PID1), sin el wrapper switch_root del path initramfs.
+if DISK:
+    APPEND = os.environ.get("APPEND", "console=ttyS0 root=/dev/vda rw rdinit=/sbin/init")
+    media = ["-drive", f"file={DISK},if=virtio,format=raw", "-append", APPEND]
+else:
+    APPEND = os.environ.get("APPEND", "console=ttyS0 rdinit=/sbin/init")
+    media = ["-initrd", CPIO, "-append", APPEND]
 QEMU = (["qemu-system-x86_64", "-m", MEM, "-no-reboot", "-nographic"] + accel + net +
-        ["-kernel", KERNEL, "-initrd", CPIO, "-append", APPEND])
+        ["-kernel", KERNEL] + media)
 
 print(f"==> kernel    : {KERNEL}")
-print(f"==> initramfs : {CPIO}")
+print(f"==> {'disco     ' if DISK else 'initramfs '}: {DISK or CPIO}")
 print(f"==> mem       : {MEM} MiB   deadline: {DEADLINE}s   net: {'sí' if WANT_NET else 'no'}")
 print(f"==> log       : {LOG}")