feat: integra renaser (kernel SASOS bare-metal) al monorepo
renaser —kernel asíncrono de espacio de direcciones único, no-POSIX, `no_std` x86_64— entra al monorepo como su PROPIO workspace de Cargo, no fusionado: usa toolchain nightly, target `x86_64-unknown-none` y `panic = "abort"`, incompatibles con los perfiles globales de brahman. - `renaser/` — copia del proyecto (sin su `.git`; el repo original conserva su historia standalone). Workspace propio con su `rust-toolchain.toml` y `.cargo/`. - `exclude = ["renaser"]` en el workspace de brahman: Cargo lo trata como ajeno. - El kernel de renaser path-depende `mirada-layout` cruzando la frontera de workspace — primer núcleo compartido. Semilla de la Fase 8 (compositor): geometría de teselado compartida, framebuffer nativo de renaser; smithay se queda en el lado Linux. Verificado: `cargo build -p boot` compila kernel + imagen UEFI con mirada-layout enlazado para bare-metal. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,457 @@
|
||||
# Registro de cambios — renaser
|
||||
|
||||
Registro técnico detallado, fase a fase, en orden cronológico. Formato
|
||||
inspirado en *Keep a Changelog*. Para la crónica en lenguaje llano, ver
|
||||
`DIARIO.md`; para el estado y los planes, `ROADMAP.md`.
|
||||
|
||||
---
|
||||
|
||||
## Fase 1 — El primer microsegundo — 2026-05-21
|
||||
|
||||
### Infraestructura
|
||||
- Espacio de trabajo Cargo, `kernel/Cargo.toml`, `.cargo/config.toml`,
|
||||
`rust-toolchain.toml`.
|
||||
- Target inicial: especificación JSON propia `x86_64-renaser.json` — PIC,
|
||||
soft-float, sin SSE, enlazador `lld`.
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/main.rs`: punto de entrada con el macro `entry_point!` de
|
||||
`bootloader_api` 0.11.
|
||||
- Adopción y verificación con seguridad de tipos del framebuffer GOP (ancho,
|
||||
alto, formato de píxel, *stride*).
|
||||
- Lienzo intermedio estático de 8 MiB en `.bss`, alineado a página: la técnica
|
||||
de doble búfer para evitar parpadeos.
|
||||
- `#[panic_handler]` que dibuja una franja roja directamente sobre el
|
||||
framebuffer mediante escrituras volátiles.
|
||||
- Dependencias: `bootloader_api` 0.11, `x86_64` 0.15, `embedded-graphics` 0.8.
|
||||
|
||||
### Notas
|
||||
- Corrección clave: `bootloader` (constructor de imagen, lado anfitrión) no es
|
||||
`bootloader_api` (la API `no_std` que consume el kernel).
|
||||
|
||||
---
|
||||
|
||||
## Fase 1.5 — Empaquetado y arranque — 2026-05-21
|
||||
|
||||
### Cambiado
|
||||
- Migración del target del kernel: de la JSON propia `x86_64-renaser.json` al
|
||||
target nativo precompilado `x86_64-unknown-none`. Elimina `build-std` y la
|
||||
burocracia de compilador asociada.
|
||||
|
||||
### Añadido
|
||||
- Miembro `boot/`: orquestador de anfitrión. Dependencia de artefacto
|
||||
(RFC 3028) sobre el kernel; construcción de la imagen de disco UEFI con
|
||||
`bootloader::UefiBoot`; lanzador de QEMU.
|
||||
|
||||
### Toolchain
|
||||
- Instalación de la toolchain nightly (la máquina solo tenía la estable).
|
||||
|
||||
### Corregido
|
||||
- Los nightly recientes exigen `-Zjson-target-spec` para usar specs JSON
|
||||
(resuelto al migrar al target nativo).
|
||||
- Sintaxis del acelerador de QEMU: `-machine q35,accel=kvm:tcg`.
|
||||
|
||||
### Verificado
|
||||
- Arranque en QEMU: superficie índigo limpia a 1280×800.
|
||||
- Baliza de pánico (franja roja) confirmada inyectando un pánico de prueba.
|
||||
|
||||
---
|
||||
|
||||
## Fase 2.0 — Cimientos del manejo de fallos — 2026-05-21
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/gdt.rs`: GDT propia, TSS y un stack de emergencia (IST)
|
||||
reservado para el manejador de doble fallo.
|
||||
- `kernel/src/interrupts.rs`: IDT con manejadores de excepción de CPU. El
|
||||
breakpoint (#BP) es recuperable; #UD, #DE, #GP, #PF y #DF son fatales y
|
||||
encienden la baliza.
|
||||
- `#![feature(abi_x86_interrupt)]`.
|
||||
|
||||
### Corregido
|
||||
- La GDT debe recargar los registros SS/DS/ES con un segmento de datos del
|
||||
kernel: el cargador deja `SS = 0x10`, valor que en la GDT nueva pasa a ser el
|
||||
descriptor del TSS; el primer `iretq` de una rutina de excepción provocaba un
|
||||
#GP. Diagnosticado con la traza `-d int` de QEMU.
|
||||
|
||||
### Verificado
|
||||
- Excepción `int3` atrapada y superada; línea-latido teal dibujada como prueba.
|
||||
|
||||
---
|
||||
|
||||
## Fase 2.1 — Interrupciones de hardware — 2026-05-21
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/pic.rs`: remapeo del par 8259 (PIC) fuera del rango de las
|
||||
excepciones (vectores 0x20+); programación del temporizador PIT a 100 Hz;
|
||||
IRQ1 de teclado.
|
||||
- Bucle de render en `kernel_main`, despertado por el temporizador, en
|
||||
sustitución del `hlt` estático.
|
||||
|
||||
### Verificado
|
||||
- La línea-latido se anima (temporizador en marcha); las pulsaciones de teclado
|
||||
inyectadas cambian el cuadro-eco (teclado en marcha).
|
||||
|
||||
---
|
||||
|
||||
## Fase 3 — Memoria dinámica y reactor asíncrono — 2026-05-21
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/memory/`: `linked_list_allocator` como `#[global_allocator]`
|
||||
sobre una región estática en `.bss`.
|
||||
- `#[alloc_error_handler]`: franja naranja de agotamiento de memoria.
|
||||
`#![feature(alloc_error_handler)]`.
|
||||
- `kernel/src/async_system/`: reactor cooperativo — `Executor`, `Task`/`TaskId`,
|
||||
`Waker` (vía `alloc::task::Wake`) y `ScancodeStream`.
|
||||
- `kernel/src/texto.rs`: rasterización de tipografía vectorial con `fontdue`;
|
||||
TTF Adwaita Mono empotrada con `include_bytes!`.
|
||||
- Dependencias: `linked_list_allocator` 0.10, `spin` 0.9, `crossbeam-queue`
|
||||
0.3, `futures-util` 0.3, `fontdue` 0.9.
|
||||
|
||||
### Cambiado
|
||||
- Heap ampliado de 16 MiB a 64 MiB: `fontdue`, al analizar una tipografía real,
|
||||
agotaba los 16 MiB iniciales. El `#[alloc_error_handler]` lo delató pintando
|
||||
la franja naranja — el guardarraíl funcionó en silicio real.
|
||||
|
||||
### Corregido
|
||||
- El modo `no_std` de `fontdue` está condicionado a su feature `hashbrown`; sin
|
||||
ella recae en `std`. Se fija `default-features = false, features = ["hashbrown"]`.
|
||||
|
||||
### Verificado
|
||||
- Rótulo de bienvenida rasterizado al arranque; el texto tecleado aparece en vivo.
|
||||
|
||||
---
|
||||
|
||||
## Fase 4 — El escudo de aislamiento WASM — 2026-05-21
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/wasm/`: intérprete `wasmi` 1.0.9 en modo `no_std`. `env.rs`
|
||||
define la matriz de capacidades — exactamente dos funciones de host:
|
||||
`sys_render_frame(ptr, len)`, con validación infranqueable de los límites de
|
||||
la memoria lineal, y `sys_get_scancode()`.
|
||||
- `apps/hello_wasm/`: primera aplicación del userspace — módulo
|
||||
`wasm32-unknown-unknown` (cdylib), un cuadrado móvil dirigido por teclado. Se
|
||||
empotra en el kernel con `include_bytes!`.
|
||||
- Dependencia: `wasmi` 1.0.
|
||||
|
||||
### Cambiado
|
||||
- El kernel se EXCLUYE del espacio de trabajo (`exclude = ["kernel", "apps"]`):
|
||||
al añadir `wasmi`, `cargo build` intentaba compilar el kernel para el
|
||||
anfitrión y fallaba por un símbolo `_start` duplicado. El kernel pasa a
|
||||
construirse únicamente como dependencia de artefacto de `boot`.
|
||||
|
||||
### Corregido
|
||||
- `wasmi` `no_std` necesita `default-features = false, features = ["hash-collections"]`.
|
||||
- `wasmi` 1.0.9 usa `Linker::instantiate_and_start` (no existe `instantiate`).
|
||||
|
||||
### Verificado
|
||||
- La aplicación WASM pinta su propia superficie y responde a las pulsaciones de
|
||||
teclado inyectadas, sin más vía hacia el kernel que las dos capacidades.
|
||||
|
||||
---
|
||||
|
||||
## Mantenimiento — Estructura, documentación e integración — 2026-05-21
|
||||
|
||||
### Cambiado
|
||||
- Refactorización: `main.rs` dividido de 692 a ~155 líneas. Se extraen los
|
||||
módulos `sync.rs`, `grafico.rs`, `consola.rs` y `baliza.rs`. Sin cambios de
|
||||
comportamiento (verificado en QEMU).
|
||||
|
||||
### Añadido
|
||||
- Documentación: `CLAUDE.md`, `README.md`, `ARCHITECTURE.md`, `ROADMAP.md`,
|
||||
`CHANGELOG.md` y `DIARIO.md`.
|
||||
- Integración con git: repositorio inicializado, remoto `origin` en Gitea,
|
||||
`.gitignore`.
|
||||
|
||||
### Seguridad
|
||||
- `renaser.txt` —un borrador de trabajo que contenía una credencial— se subió
|
||||
por error en el commit inicial. Se purgó de todo el historial con
|
||||
`git filter-branch` y se reescribió el remoto con `push --force`. La
|
||||
credencial expuesta debe rotarse.
|
||||
|
||||
---
|
||||
|
||||
## Fase 5 — Multitarea cooperativa, guardarrail de fuel y reloj — 2026-05-22
|
||||
|
||||
Unificación de la Fase 3 (reactor) y la Fase 4 (WASM): el userspace deja de ser
|
||||
una sola app que monopoliza la CPU y pasa a ser un conjunto de aplicaciones
|
||||
cooperativas, aisladas también en el TIEMPO.
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/async_system/reloj.rs`: convierte la IRQ0 (PIT, 100 Hz) en una
|
||||
primitiva asíncrona. `CONTADOR_PULSOS` (`AtomicU64`) y `EsperaFrame`, un
|
||||
`Future` que se resuelve en el siguiente pulso — la unidad de cesión
|
||||
cooperativa del userspace. Censo de wakers tras `Mutex`, drenado por la IRQ0.
|
||||
- `kernel/src/wasm`: ABI de fotograma. `AplicacionWasm` —instancia PERSISTENTE
|
||||
entre fotogramas (`Store` + `TypedFunc<(), ()>` + región)— sustituye al
|
||||
`wasm::ejecutar` de fuego-y-olvido. El módulo del userspace exporta ahora
|
||||
`init()` (una vez) y `tick()` (un fotograma, y retorna).
|
||||
- Escudo de combustible: `Engine` con `Config::consume_fuel(true)` y
|
||||
`CompilationMode::Eager` (el `fuel` mide solo ejecución). Presupuesto recargado
|
||||
antes de cada `tick` — `FUEL_ARRANQUE` (20 M) y `FUEL_FOTOGRAMA` (2 M).
|
||||
- `kernel/src/wasm/env.rs`: capacidad `sys_render_frame` con **regiones de
|
||||
dibujo** — cada fotograma se compone desplazado por el `(offset_x, offset_y)`
|
||||
de la app; un tamaño ajeno a la región se rechaza. Canal de teclado **por
|
||||
aplicación**: la IRQ1 difunde cada scancode a TODOS los canales, de modo que
|
||||
varias apps reciben la entrada en paralelo sin robársela.
|
||||
- `kernel/src/grafico.rs`: `RegionPantalla` y `Color::DESALOJO` (púrpura).
|
||||
- `apps/discola/`: aplicación WASM construida para portarse mal — su `tick` es
|
||||
un bucle cerrado. Demuestra el guardarrail de fuel en vivo.
|
||||
|
||||
### Cambiado
|
||||
- `apps/hello_wasm`: migrada al ABI `init`/`tick`; su lienzo se dimensiona a la
|
||||
región (480×560). El estado del cuadrado persiste en su memoria lineal.
|
||||
- `interrupts.rs`: la IRQ0 avanza el `reloj`; la IRQ1 difunde a los canales.
|
||||
- `consola.rs`: `volcar_marco` compone en una sub-región; `pintar_desalojo`
|
||||
tatúa la baliza púrpura.
|
||||
- Contención de fallos: el subsistema WASM ya no usa `.expect()`. Toda falla
|
||||
—carga, instanciación, desbordamiento, agotamiento de fuel— se devuelve como
|
||||
`Result`; la tarea desaloja la app (baliza púrpura) y el kernel sigue vivo.
|
||||
|
||||
### Verificado
|
||||
- QEMU: tres apps concurrentes. Dos instancias de `hello_wasm` (mismo bytecode,
|
||||
regiones izquierda y derecha) renderizan y responden a W/A/S/D **en paralelo**,
|
||||
con movimiento idéntico. La app díscola es desalojada en su primer fotograma
|
||||
por agotamiento de combustible: su región queda púrpura y el sistema —kernel y
|
||||
apps vecinas— no sufre un solo sobresalto.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6.0 — Cuotas de memoria y ciclo de vida del userspace — 2026-05-22
|
||||
|
||||
El aislamiento de las aplicaciones, que la Fase 5 hizo temporal (combustible),
|
||||
se completa ahora en la dimensión espacial (memoria) y se cierra la fuga de
|
||||
recursos del ciclo de vida.
|
||||
|
||||
### Añadido
|
||||
- Techo de memoria lineal por aplicación: `4 MiB`. `wasm/mod.rs` construye un
|
||||
`StoreLimits` (`StoreLimitsBuilder::memory_size` + `trap_on_grow_failure`) y lo
|
||||
liga al `Store` con `Store::limiter`. Un `memory.grow` que rebase la cuota se
|
||||
convierte en trampa; el kernel la captura y desaloja la app.
|
||||
- `FallaApp::SinMemoria` y `Color::DESALOJO_MEMORIA` (amarillo pálido). El
|
||||
desalojo distingue la causa por color: púrpura (tiempo/aborto), amarillo
|
||||
(memoria). La clasificación es robusta — `Error::as_trap_code()` da un código
|
||||
público y unívoco: `TrapCode::GrowthOperationLimited`.
|
||||
- `Drop` para `AplicacionWasm`: al morir una app desalojada, su canal de teclado
|
||||
se da de baja del censo de difusión de la IRQ1 — cierra la fuga señalada en la
|
||||
Fase 5. `async_system::teclado` se reorganiza en `crear_canal` /
|
||||
`registrar_canal` / `cerrar_canal`; el canal se inscribe al FINAL de la carga,
|
||||
de modo que una carga fallida no deja canales huérfanos.
|
||||
- `apps/glotona/`: aplicación WASM construida para devorar memoria — su `tick`
|
||||
invoca `memory.grow` sin freno. Demuestra el guardarrail espacial en vivo.
|
||||
|
||||
### Verificado
|
||||
- QEMU: cuatro apps concurrentes. Las dos `hello_wasm` renderizan y responden al
|
||||
teclado en paralelo; la app díscola es desalojada por combustible (franja
|
||||
púrpura) y la app glotona por cuota de memoria (franja amarilla), ambas en su
|
||||
primer fotograma, sin que el kernel ni las apps honradas se inmuten.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6.1a — Sonda PCI y disco de pruebas — 2026-05-22
|
||||
|
||||
Primer paso de la estrategia incremental hacia el almacenamiento: derribar el
|
||||
muro del descubrimiento de hardware antes de diseñar nada encima.
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/drivers/`: nuevo subsistema de drivers. `pci.rs` enumera el bus
|
||||
PCI por fuerza bruta mediante el mecanismo de configuración #1 —puertos de E/S
|
||||
`0xCF8` (dirección) y `0xCFC` (datos)—; recorre buses y dispositivos leyendo
|
||||
el Vendor/Device ID, y localiza el disco virtio-blk (vendor `0x1AF4`, device
|
||||
`0x1001`/`0x1042`), devolviendo su ubicación y sus seis BARs.
|
||||
- `kernel_main`: tras fundar la consola, sondea el bus PCI y deja constancia
|
||||
visual del hallazgo.
|
||||
|
||||
### Cambiado
|
||||
- `boot/src/main.rs`: forja un disco de pruebas `target/disk.img` (fichero
|
||||
disperso de 32 MiB; se respeta si ya existe) y lo adjunta a QEMU como
|
||||
`virtio-blk-pci`. **Corrección de plataforma:** la máquina `q35` es x86_64 y
|
||||
exige la transmisión PCI; `virtio-blk-device` (su gemelo MMIO) es de ARM.
|
||||
|
||||
### Verificado
|
||||
- QEMU: el kernel enumera el bus y reporta en pantalla
|
||||
`virtio-blk en bus 0 dev 3 :: BAR0 E/S 0x6000` — un dispositivo virtio-blk
|
||||
transicional (device `0x1001`), con su BAR0 en espacio de E/S. El muro del
|
||||
descubrimiento PCI queda derribado; las cuatro apps del userspace siguen
|
||||
operando sin alteración.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6.1b — HAL, DMA y lectura del sector 0 — 2026-05-22
|
||||
|
||||
Segundo paso del sustrato de almacenamiento: el diálogo real con el disco. El
|
||||
kernel monta el dispositivo virtio-blk y lee su primer sector por DMA.
|
||||
|
||||
### Añadido
|
||||
- Dependencia `virtio-drivers` 1.13 (`no_std`, `default-features = false`,
|
||||
feature `alloc`).
|
||||
- `kernel/src/drivers/disco.rs`:
|
||||
- **Asignador de marcos** «bump» — reparte páginas físicas de 4 KiB para el
|
||||
DMA, tomadas de la mayor región de RAM libre que el cargador reporta. No
|
||||
libera: suficiente para una sonda (la gestión fina llegará con el grafo).
|
||||
- **`KernelHal`** — implementa el `trait Hal` de `virtio-drivers`. `dma_alloc`
|
||||
entrega marcos físicos a cero; `mmio_phys_to_virt` traduce los BARs (el
|
||||
cargador mapea ≥ 4 GiB de memoria física, que cubre todo MMIO de PCI);
|
||||
`share`/`unshare` usan un buffer rebote para que cualquier región del kernel
|
||||
pueda viajar al dispositivo.
|
||||
- **`montar_y_leer_sector0`** — enumera el bus, habilita E/S + memoria +
|
||||
bus-master, monta el `PciTransport` y el `VirtIOBlk`, y lee el sector 0 por
|
||||
**sondeo** del *used ring* (sin depender aún de interrupciones).
|
||||
- `kernel/src/drivers/pci.rs`: reescrito como `CamPuertos`, la implementación de
|
||||
`ConfigurationAccess` de `virtio-drivers` sobre los puertos `0xCF8`/`0xCFC`.
|
||||
- `kernel_main` captura `physical_memory_offset` y la región de RAM de
|
||||
`BootInfo`, funda el subsistema de disco y reporta el resultado de la sonda.
|
||||
|
||||
### Cambiado
|
||||
- `boot/src/main.rs`: al forjar el disco de pruebas graba una firma
|
||||
(`renaser-6.1b`) en su sector 0 — el testigo del viaje de ida y vuelta.
|
||||
|
||||
### Verificado
|
||||
- QEMU: el kernel reporta `virtio-blk :: bus 0 dev 3 :: 65536 sectores ::
|
||||
s0=renaser-6.1b`. La firma grabada por el anfitrión se lee de vuelta intacta:
|
||||
descubrimiento PCI, transporte, DMA y transferencia funcionan de punta a
|
||||
punta. Las cuatro apps del userspace siguen operando sin alteración.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6.1c — El grafo de objetos direccionado por contenido — 2026-05-22
|
||||
|
||||
Tercer y último paso del sustrato de almacenamiento. El disco deja de ser un
|
||||
dispositivo que se sondea y pasa a ser una MEMORIA QUE PERDURA: un grafo
|
||||
dirigido acíclico de objetos direccionados por contenido — no un sistema de
|
||||
archivos plano POSIX.
|
||||
|
||||
### Añadido
|
||||
- `kernel/src/almacen.rs` — el grafo de objetos:
|
||||
- **Objeto** — una carga útil de bytes (`datos`) y una lista de aristas
|
||||
(`hijos`: hashes de otros objetos). Las aristas hacen del almacén un DAG.
|
||||
- **Direccionamiento por contenido** — la identidad de un objeto es el hash
|
||||
BLAKE3 de su forma serializada. De ello se siguen dos propiedades que un
|
||||
sistema de archivos jamás regala: INTEGRIDAD (el contenido leído se
|
||||
rehashea y se verifica contra el hash pedido) y DEDUPLICACIÓN (contenido
|
||||
idéntico produce el mismo hash; se almacena una sola vez).
|
||||
- **Disco como log** — el sector 0 es el superbloque (magia `RENASGRF`,
|
||||
versión, cursor del log y hash de la raíz); tras él se anexan los registros
|
||||
de objetos, `[longitud u32 LE][payload postcard][relleno a cero]`. Un
|
||||
índice en memoria (hash -> sector) se reconstruye al arrancar recorriendo
|
||||
el log de cabo a rabo.
|
||||
- API: `init` —monta el disco, lee o forja el superbloque, reconstruye el
|
||||
índice—, `almacenar`, `recuperar`, `raiz` y `fijar_raiz`.
|
||||
- Cinco capacidades nuevas del host en `wasm/env.rs` — `sys_object_put`,
|
||||
`sys_object_datos`, `sys_object_hijo`, `sys_object_raiz` y
|
||||
`sys_object_fijar_raiz` —, con la misma validación infranqueable de límites
|
||||
de la memoria lineal que `sys_render_frame`. Distinguen dos clases de fallo:
|
||||
un puntero inválido ABORTA la app —es su culpa, se traduce en trampa—; un
|
||||
fallo del almacenamiento le devuelve un código de error negativo —no lo es—.
|
||||
- `apps/cronista/` — la primera aplicación del userspace que escribe en el
|
||||
almacenamiento PERSISTENTE. En cada arranque consulta la raíz del grafo,
|
||||
graba un objeto nuevo —`datos`: el número de arranque; `hijos`: la raíz
|
||||
anterior, el eslabón del DAG— y lo corona como raíz. Pinta una celda por
|
||||
arranque registrado y un testigo de integridad que recorre la cadena entera.
|
||||
- Dependencias: `serde` 1 y `postcard` 1 (serialización binaria compacta, el
|
||||
formato que viaja al disco) y `blake3` 1 (la función hash). Las tres `no_std`.
|
||||
|
||||
### Cambiado
|
||||
- `kernel/src/drivers/disco.rs` reescrito para un sustrato PERMANENTE:
|
||||
- El asignador de marcos «bump» de la Fase 6.1b cede el paso a uno de MAPA DE
|
||||
BITS con liberación real. `dma_dealloc` y `unshare` devuelven los marcos a
|
||||
la arena: un almacén vivo, con su trasiego incesante de DMA, ya no la agota.
|
||||
- El `VirtIOBlk` deja de montarse y destruirse en cada llamada: se monta UNA
|
||||
vez y queda tras un `Mutex` global. `leer_sectores` / `escribir_sectores`
|
||||
exponen la E/S de bloques — el disco deja de ser de solo lectura. Se retira
|
||||
`montar_y_leer_sector0`, la sonda de un solo uso de la Fase 6.1b.
|
||||
- `boot/src/main.rs`: el disco de pruebas pasa a ser el disco de objetos. Ya
|
||||
no se le graba una firma — se forja virgen, a cero, y el kernel lo formatea
|
||||
la primera vez que no halle el superbloque.
|
||||
- `main.rs`: `informar_disco` (la sonda de la Fase 6.1b) se sustituye por
|
||||
`informar_almacen`, que funda el grafo. El userspace pasa de cuatro a cinco
|
||||
apps; las regiones de discola y glotona se reajustan para alojar a cronista.
|
||||
|
||||
### Notas
|
||||
- **blake3 forzado a escalar.** El target del kernel corre sin SSE; un camino
|
||||
SIMD de blake3 activado por detección en tiempo de ejecución ejecutaría
|
||||
instrucciones que la CPU, sin `CR4.OSFXSR`, rechazaría con un #UD. Se fija
|
||||
blake3 con `pure` + los cuatro `no_*` (`sse2`, `sse41`, `avx2`, `avx512`):
|
||||
implementación puramente escalar, sin SIMD ni ensamblador.
|
||||
|
||||
### Verificado
|
||||
- QEMU, TRES arranques consecutivos sobre el mismo disco persistente: la app
|
||||
cronista pinta 1, luego 2, luego 3 celdas — la cuenta de arranques sobrevive
|
||||
a los reinicios porque vive en el grafo, en el disco, no en la RAM. El
|
||||
testigo de integridad queda VERDE en los tres: el DAG entero se recorre, de
|
||||
la raíz al primer eslabón, y su profundidad cuadra con la cuenta. El
|
||||
superbloque en disco confirma la magia `RENASGRF`, versión 1, cursor 4 y la
|
||||
raíz del tercer arranque; el registro del primer arranque guarda `datos = 1`
|
||||
y cero hijos. Las otras cuatro apps siguen su curso sin alteración — las dos
|
||||
`hello_wasm` renderizando, discola desalojada en púrpura, glotona en amarillo.
|
||||
|
||||
---
|
||||
|
||||
## Fase 6.2 — E/S de disco asíncrona por interrupción — 2026-05-22
|
||||
|
||||
La Fase 6.1 hizo hablar al disco, pero por SONDEO: el procesador se quedaba en
|
||||
espera activa vigilando el *used ring* de virtio, incapaz de atender nada más.
|
||||
La 6.2 libera el planificador cooperativo — la E/S de bloques pasa a ser
|
||||
REACTIVA, guiada por la interrupción física del dispositivo.
|
||||
|
||||
### Añadido
|
||||
- `EsperaDisco` (`drivers/disco.rs`): una transferencia de bloques expresada
|
||||
como `Future` nativo. Posee sus buferes DMA —`BlkReq`, `BlkResp` y los datos,
|
||||
en el heap para una dirección estable—; su `poll` envía la petición por la
|
||||
API NO BLOQUEANTE de `virtio-drivers` (`read_blocks_nb`/`write_blocks_nb`),
|
||||
consulta el *used ring* (`peek_used`) y, si la transferencia sigue en vuelo,
|
||||
inscribe el waker y cede. `leer_bloques`/`escribir_bloques` lo construyen.
|
||||
- La IRQ del disco: `montar` descubre la línea de IRQ legada del dispositivo
|
||||
(registro «Interrupt Line», offset 0x3C del espacio de configuración PCI),
|
||||
registra un manejador en la IDT y abre la línea en el PIC.
|
||||
`interrupts::irq_disco` → `disco::atender_irq` reconoce la interrupción en el
|
||||
dispositivo —leer su registro ISR baja la línea INTx— y despierta, vía un
|
||||
waker de ranura única, a la tarea que aguardaba el bloque.
|
||||
- `bloquear_en` — el puente para los contextos SÍNCRONOS (el arranque, las
|
||||
capacidades WASM, que no pueden `.await`): lleva un `Future` de disco hasta
|
||||
su final durmiendo la CPU con `hlt` —la despiertan la IRQ del disco o el
|
||||
temporizador, como red de seguridad—; jamás en espera activa con el sistema
|
||||
ya en marcha.
|
||||
- `pic::desenmascarar` / `pic::vector_irq`: abrir una línea concreta del par
|
||||
8259 (con su cascada, si vive en el esclavo) y mapear línea → vector de IDT.
|
||||
- `pci::linea_irq`: leer el registro «Interrupt Line» de un dispositivo.
|
||||
- `tarea_sonda_disco` (`main.rs`): una tarea del reactor que lee el sector 0 de
|
||||
forma asíncrona — la prueba viva de que la IRQ conduce la E/S sin detener a
|
||||
las aplicaciones.
|
||||
|
||||
### Cambiado
|
||||
- `leer_sectores`/`escribir_sectores` se reescriben sobre la maquinaria
|
||||
asíncrona (`bloquear_en` + `EsperaDisco`). El `almacen` y las capacidades
|
||||
`sys_object_*` NO cambian una línea: heredan la E/S por interrupción de
|
||||
forma transparente — la espera de disco deja de quemar ciclos en sondeo.
|
||||
- El `VirtIOBlk` pide al dispositivo que emita interrupciones al completar cada
|
||||
petición (`enable_interrupts`).
|
||||
|
||||
### Decisiones de ingeniería
|
||||
- **PIC, no IOAPIC.** El kernel corre íntegramente sobre el par 8259 (`pic.rs`)
|
||||
y la crate `x86_64` no ofrece abstracción de APIC. Las IRQ legadas de PCI de
|
||||
la máquina `q35` se enrutan por el 8259: basta leer la línea que el firmware
|
||||
UEFI ya asignó y abrirla. Migrar al IOAPIC habría exigido levantar LAPIC +
|
||||
IOAPIC + parseo de tablas ACPI — un subsistema entero, desproporcionado para
|
||||
el objetivo. El resultado funcional es idéntico: E/S conducida por la
|
||||
interrupción física.
|
||||
- **Las capacidades WASM no `.await`-ean.** El intérprete `wasmi` ejecuta las
|
||||
funciones de host de forma SÍNCRONA: no hay manera de suspender un módulo a
|
||||
mitad de una llamada de host. Por eso `sys_object_*` no se vuelven
|
||||
asíncronas; usan `bloquear_en`, que duerme la CPU con `hlt` en lugar de
|
||||
sondear. El verdadero solapamiento E/S ↔ render lo aprovechan las TAREAS del
|
||||
reactor (`tarea_sonda_disco` hoy; la carga dinámica de módulos, mañana).
|
||||
- Una IRQ legada de PCI es de NIVEL: el manejador reconoce primero al
|
||||
dispositivo —lo que baja su línea— y sólo después cierra el EOI del PIC; el
|
||||
orden inverso reavivaría la interrupción en bucle.
|
||||
- Todo acceso al disco toma su `Mutex` con las interrupciones desactivadas
|
||||
(`without_interrupts`): la IRQ del disco jamás encuentra el cerrojo ocupado,
|
||||
lo que hace imposible el interbloqueo por interrupción.
|
||||
|
||||
### Verificado
|
||||
- QEMU: el disco virtio-blk se enruta a la IRQ 11. La `tarea_sonda_disco`
|
||||
reporta «sonda asíncrona OK -- 2 IRQ de disco atendidas»: la interrupción del
|
||||
disco dispara de verdad. La app cronista, sobre el disco persistente heredado
|
||||
de la Fase 6.1c, continúa la cuenta de arranques (3 → 4 → 5 celdas) con el
|
||||
testigo de integridad del DAG en verde — la nueva E/S asíncrona lee y escribe
|
||||
el grafo sin un solo fallo. Las cuatro apps WASM siguen su curso, sin un
|
||||
sobresalto ni un micro-congelamiento.
|
||||
Reference in New Issue
Block a user