Etapa metal: kernel-metal (drivers reales =y) + firmware AX201 + ESTADO.md

Pieza 1+2 de 'hammer en el metal' (laptop TigerLake, WiFi AX201):
- recipes/linux-metal.toml: variante del kernel con hardware real built-in
  (efifb/simpledrm, USB+HID, AHCI/NVMe, cfg80211+mac80211+iwlwifi/iwlmvm,
  e1000e/r8169, USB-CDC). Conserva los bits hammer (overlay/userns/fanotify/
  virtio) ⇒ sigue booteando en QEMU. MODULES=off (monolítico, sin modprobe).
  Deja linux.toml INTOCADO (su of_tree es load-bearing del selfhost).
- scripts/metal-firmware.sh: inyecta iwlwifi-QuZ-a0-hr-b0/cc-a0 + regulatory.db
  en /lib/firmware de un rootfs (descomprime .zst → .ucode plano). Blobs fijos
  (TODO pin a linux-firmware).
- ESTADO.md: resumen humano del proyecto.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 20:56:19 -04:00
co-authored by Claude Opus 4.8
parent 367b167991
commit ac2835f4e7
3 changed files with 185 additions and 0 deletions
+62
View File
@@ -0,0 +1,62 @@
# ¿Dónde está hammer hoy? (mapa amigable)
> Una foto en lenguaje humano de qué funciona, qué falta y por dónde seguir.
> Fecha: 2026-06-22. Para el detalle de arquitectura, ver [`docs/`](docs/).
## La idea en una frase
`hammer` es una distro de Linux con dos pisos: un **sótano de laboratorio** que compila
todo desde fuente de forma reproducible y guarda cada binario por su hash, y un **piso de
arriba** clásico y mutable (un Linux normal con `/bin`, `/lib`, `/etc`) donde puedes romper
cosas y revertir. Está pensada para que una **IA** entienda y modifique el sistema entero.
## El semáforo: qué está listo
| Pieza | Estado | En cristiano |
|---|---|---|
| 🟢 Núcleo del laboratorio | **Listo** | Compila aislado (bubblewrap + zig cc + musl), direcciona por hash BLAKE3 |
| 🟢 Auto-hospedaje (self-host) | **Listo y verificado** | El toolchain se reconstruye a sí mismo *bit a bit* dentro de una VM |
| 🟢 Kernel propio | **Listo** | Linux 6.16.12 compilado por nosotros, **arranca** la VM y se reproduce idéntico |
| 🟢 Frente Rust/LLVM | **Cerrado** | Cadena pura mrustc → rustc 1.91.1, sin binarios ajenos de confianza |
| 🟢 Paquetería `.swm` | **Listo (6/6 piezas)** | Empaquetar, repo firmado, instalar/desinstalar, deps, repo por red |
| 🟢 Catálogo de software | **145 recetas** | Subió de 88 a 145 en una sola sesión (sobre todo CLIs de Rust) |
| 🟡 Instalar en disco real | **En curso** | Imágenes EFI/ISO existen; falta pulir "instalar desde el live" |
| 🟡 Userland Rust-nativo | **En curso** | coreutils/findutils de uutils ya construyen y corren |
| ⚪ Distro instalable redonda | **Pendiente** | Las etapas B/D/E del roadmap |
## Lo más importante que se logró
1. **Soberanía del arranque.** No dependemos de binarios precocidos de nadie. Partiendo de
un compilador mínimo, hammer reconstruye su propio Rust, su propio kernel y sus propias
herramientas — y al hacerlo dos veces da **exactamente el mismo resultado** (reproducible
bit a bit). Eso se probó dentro de una máquina virtual, no solo en teoría.
2. **Una "granja" de software que escala.** Hay un pipeline que toma recetas de `nixpkgs` y
Alpine, las adapta al formato de hammer, las compila y promueve las que funcionan al
catálogo. En esta sesión pasó de 88 a 145 paquetes, casi todo CLIs de Rust populares
(ripgrep, bat, fd, zoxide, helix, zellij, uv, ruff, biome…).
3. **El "techo" actual es conocido.** Lo que frena más builds ya no es un misterio: es la
versión mínima de Rust que pide cada programa (MSRV) y los paquetes que arrastran C/C++
(`openssl`, `git2`). Subir el toolchain de 1.91.1 a 1.96 destrabó una tanda entera.
## Por dónde sigue
- **Escalar el catálogo a cientos** de paquetes con la cola ya pre-cargada
(`JOBS=4 scripts/build-farm.sh`).
- **Terminar "instalar desde el live"**: que arrancar el ISO y darle a instalar deje un
sistema usable en disco (Etapa B del roadmap).
- **Seguir reemplazando el userland** por equivalentes Rust-nativos (xargs es el próximo).
- Pulidos opcionales: squashfs+overlay, arranque EFI fino, rollback al boot.
## Para orientarte en el repo
- `crates/` — el código de hammer (CLI, daemon, build lab, journal, overlay…).
- `recipes/` — el catálogo (145 `.toml`); `recipes/incoming/` es la cola por procesar.
- `scripts/` — orquestadores: `selfhost-verify.sh` (la prueba de fuego), `build-farm.sh`
(la granja), `import-batch.sh` (importa tandas), `rust-frontier/` (la cadena Rust pura).
- `docs/` — el diseño completo (SDD); empieza por `00-vision.md` y `10-roadmap.md`.
---
*Este archivo es el resumen humano. El estado técnico denso vive en la memoria del proyecto
y en los mensajes de commit (en español, granulares).*
+77
View File
@@ -0,0 +1,77 @@
# Linux kernel 6.16.12 — VARIANTE "METAL": booteable en hardware real (no sólo QEMU).
#
# Hermana de recipes/linux.toml (el kernel QEMU-tuned del selfhost-verify, INTOCADO: su of_tree es
# load-bearing para la reproducibilidad bit-a-bit). Esta variante NO recorta el hardware; al revés, lo
# habilita built-in (=y) porque el producto hammer es monolítico (arje-zero PID1, sin udev/modprobe en
# el camino de boot ⇒ todo lo que haga falta para arrancar/ver/teclear/conectar debe ser =y, no =m).
#
# Target concreto: laptop TigerLake-LP (Intel Iris Xe + Wi-Fi 6 AX201 [8086:a0f0]), boot EFI.
# - Pantalla: DRM_SIMPLEDRM + SYSFB_SIMPLEFB + FB_EFI (framebuffer del GOP de EFI; NO i915 → sin
# firmware GuC/DMC/HuC, consola fbcon basta). i915/amdgpu/nouveau/radeon quedan OFF.
# - Teclado: USB_HID + HID_GENERIC + i8042/atkbd (teclado integrado del portátil suele ser PS/2).
# - Discos: AHCI/ATA + NVMe + USB_STORAGE + SCSI/sd (NVMe es lo más probable en TigerLake).
# - WiFi: cfg80211 + mac80211 + iwlwifi + iwlmvm (AX201 usa el path mvm). El firmware
# (iwlwifi-QuZ-a0-hr-b0-*.ucode, cc-a0-*) + regulatory.db NO van acá — son blobs no
# compilables; se inyectan en /lib/firmware del rootfs (ver scripts/metal-firmware.sh).
# - Red extra: e1000e/r8169/igb/igc/tg3 (Ethernet común) + USB-CDC/RNDIS (tether del celu) — baratos.
# - Boot: EFI_STUB + EFI_PARTITION + VFAT (ESP) + ISO9660/Joliet (leer el medio live).
#
# Conserva TODO lo que hammer necesita (de linux.toml): E1000/OVERLAY_FS(+subfeatures)/USER_NS/
# NAMESPACES/FANOTIFY/VIRTIO* ⇒ esta misma imagen sigue booteando en QEMU (para poder testear el boot
# antes de quemar el USB). MODULES=off ⇒ monolítico puro (sin .ko que nadie cargaría).
#
# Compilador: CC=gcc/HOSTCC=gcc — MISMA decisión del gueto-GCC que linux.toml (zig cc choca con el
# kbuild x86). Build ~45min (config ancha). Build-deps idénticos (flex/bison/m4/openssl/elfutils +
# bootstrap-libs apk del bootstrap-devfs.sh).
name = "linux-metal"
version = "6.16.12"
[source]
tarball = "https://mirrors.edge.kernel.org/pub/linux/kernel/v6.x/linux-6.16.12.tar.gz"
sha256 = "ffc6af80b014ddebd55e116aa29a9f7a5256c87a29a8a9dd97270b6d49625109"
[build]
compiler = "zig-cc"
target = "x86_64-linux-musl"
link = "dynamic"
[deps]
build = ["flex", "bison", "m4", "openssl", "elfutils"]
[build.phases]
configure = """
make ARCH=x86_64 defconfig && \
scripts/config -d MODULE_SIG -d MODULE_SIG_ALL -d DEBUG_INFO_BTF -d DEBUG_INFO -d MODULES \
-d UNWINDER_ORC -e UNWINDER_FRAME_POINTER \
-e BLK_DEV_INITRD -e DEVTMPFS -e DEVTMPFS_MOUNT -e TMPFS \
-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 \
-e PCI -e PCIEPORTBUS -e ACPI \
-e SATA_AHCI -e ATA -e ATA_PIIX -e SCSI -e BLK_DEV_SD -e BLK_DEV_LOOP \
-e NVME_CORE -e BLK_DEV_NVME \
-e USB_SUPPORT -e USB -e USB_PCI -e USB_XHCI_HCD -e USB_XHCI_PCI \
-e USB_EHCI_HCD -e USB_EHCI_PCI -e USB_OHCI_HCD -e USB_UHCI_HCD -e USB_STORAGE \
-e HID -e HID_GENERIC -e USB_HID -e INPUT_EVDEV \
-e INPUT_KEYBOARD -e KEYBOARD_ATKBD -e INPUT_MOUSE -e MOUSE_PS2 \
-e SERIO -e SERIO_I8042 -e VT -e VT_CONSOLE \
-e DRM -e DRM_SIMPLEDRM -e SYSFB_SIMPLEFB -e FB -e FB_EFI \
-e FRAMEBUFFER_CONSOLE -e FRAMEBUFFER_CONSOLE_DETECT_PRIMARY \
-e EFI -e EFI_STUB -e EFI_PARTITION -e EFIVAR_FS \
-e VFAT_FS -e FAT_FS -e MSDOS_FS -e NLS_CODEPAGE_437 -e NLS_ISO8859_1 -e NLS_UTF8 \
-e ISO9660_FS -e JOLIET \
-e WLAN -e WIRELESS -e CFG80211 -e MAC80211 -e RFKILL \
-e WLAN_VENDOR_INTEL -e IWLWIFI -e IWLMVM \
-e ETHERNET -e NET_VENDOR_INTEL -e E1000 -e E1000E -e IGB -e IGC \
-e NET_VENDOR_REALTEK -e R8169 -e NET_VENDOR_BROADCOM -e TG3 \
-e USB_NET_DRIVERS -e USB_USBNET -e USB_NET_CDCETHER -e USB_NET_CDC_NCM -e USB_NET_RNDIS_HOST \
-d DRM_I915 -d DRM_AMDGPU -d DRM_NOUVEAU -d DRM_RADEON -d AGP \
-d SOUND -d SND -d MEDIA_SUPPORT -d INFINIBAND -d BT -d NFC -d CAN \
-d WATCHDOG -d THUNDERBOLT -d FIREWIRE \
-d XFS_FS -d BTRFS_FS -d F2FS_FS -d JFS_FS -d REISERFS_FS -d GFS2_FS -d NTFS3_FS && \
make ARCH=x86_64 olddefconfig
"""
compile = "make ARCH=x86_64 CC=gcc HOSTCC=gcc -j\"$(nproc)\" bzImage"
install = "mkdir -p /out/boot && cp arch/x86/boot/bzImage /out/boot/bzImage && cp .config /out/boot/config-6.16.12-metal"
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env sh
# metal-firmware.sh — inyecta el firmware del WiFi AX201 (y reg.db) en /lib/firmware de un rootfs.
#
# El firmware de iwlwifi son BLOBS binarios NO compilables desde fuente (Intel no libera el código); la
# soberanía de hammer (build-from-source) no aplica acá — son datos fijos como el microcódigo de la CPU.
# Se fijan por contenido (igual que un tarball pinned): se copian de un linux-firmware ya presente y se
# descomprimen a .ucode plano (el kernel metal NO habilita FW_LOADER_COMPRESS, así evitamos esa dep).
#
# Target: Intel Wi-Fi 6 AX201 [8086:a0f0] en TigerLake ⇒ familias QuZ-a0-hr-b0 + cc-a0 (el driver elige
# la API más alta que soporta) + regulatory.db(+.p7s) que cfg80211 verifica con la clave built-in.
#
# Uso: scripts/metal-firmware.sh <rootfs-dir>
# Vars: FWSRC dir origen del firmware (default /lib/firmware del host)
#
# TODO(soberanía): reemplazar FWSRC=host por un pin a un commit de linux-firmware (recipe fetch+extract).
set -eu
DST="${1:?uso: metal-firmware.sh <rootfs-dir>}"
FWSRC="${FWSRC:-/lib/firmware}"
OUT="$DST/lib/firmware"
mkdir -p "$OUT"
# patrones de firmware que el AX201 puede pedir (ambas familias, todas las API presentes)
PATTERNS="iwlwifi-QuZ-a0-hr-b0-*.ucode iwlwifi-cc-a0-*.ucode"
n=0
for pat in $PATTERNS; do
for src in "$FWSRC"/$pat "$FWSRC"/$pat.zst "$FWSRC"/$pat.xz; do
[ -e "$src" ] || continue
base=$(basename "$src")
case "$base" in
*.zst) dst="$OUT/${base%.zst}"; zstd -q -d -f -o "$dst" "$src" ;;
*.xz) dst="$OUT/${base%.xz}"; xz -dc "$src" > "$dst" ;;
*) dst="$OUT/$base"; cp "$src" "$dst" ;;
esac
n=$((n+1))
done
done
# regulatory db (texto firmado; cfg80211 lo carga vía firmware loader y verifica .p7s con clave built-in)
for f in regulatory.db regulatory.db.p7s; do
if [ -e "$FWSRC/$f" ]; then cp "$FWSRC/$f" "$OUT/$f"; n=$((n+1)); fi
done
[ "$n" -gt 0 ] || { echo "metal-firmware: NO encontré firmware AX201 en $FWSRC" >&2; exit 1; }
echo "metal-firmware: $n blobs → $OUT"
ls "$OUT" | sed 's/^/ /'