gioser

tawasuyu/brahman

Rust 212TOML 64JSON 14HTML 12703 Sutichaykuna

⎇ 7695dbf3ceda3ab6114a460bbae238eae3d91dd8 renaser/CHANGELOG.md Markdown · 589 siq'ikuna · 30.5 KB Ñawpa willay ch'uya

feat(renaser): Fase 7b — boot siembra la imagen, muere el include_bytes! 7695dbf3c · sergio ·

1# Registro de cambios — renaser
2
3Registro técnico detallado, fase a fase, en orden cronológico. Formato
4inspirado en *Keep a Changelog*. Para la crónica en lenguaje llano, ver
5`DIARIO.md`; para el estado y los planes, `ROADMAP.md`.
6
7---
8
9## Fase 1 — El primer microsegundo — 2026-05-21
10
11### Infraestructura
12- Espacio de trabajo Cargo, `kernel/Cargo.toml`, `.cargo/config.toml`,
13  `rust-toolchain.toml`.
14- Target inicial: especificación JSON propia `x86_64-renaser.json` — PIC,
15  soft-float, sin SSE, enlazador `lld`.
16
17### Añadido
18- `kernel/src/main.rs`: punto de entrada con el macro `entry_point!` de
19  `bootloader_api` 0.11.
20- Adopción y verificación con seguridad de tipos del framebuffer GOP (ancho,
21  alto, formato de píxel, *stride*).
22- Lienzo intermedio estático de 8 MiB en `.bss`, alineado a página: la técnica
23  de doble búfer para evitar parpadeos.
24- `#[panic_handler]` que dibuja una franja roja directamente sobre el
25  framebuffer mediante escrituras volátiles.
26- Dependencias: `bootloader_api` 0.11, `x86_64` 0.15, `embedded-graphics` 0.8.
27
28### Notas
29- Corrección clave: `bootloader` (constructor de imagen, lado anfitrión) no es
30  `bootloader_api` (la API `no_std` que consume el kernel).
31
32---
33
34## Fase 1.5 — Empaquetado y arranque — 2026-05-21
35
36### Cambiado
37- Migración del target del kernel: de la JSON propia `x86_64-renaser.json` al
38  target nativo precompilado `x86_64-unknown-none`. Elimina `build-std` y la
39  burocracia de compilador asociada.
40
41### Añadido
42- Miembro `boot/`: orquestador de anfitrión. Dependencia de artefacto
43  (RFC 3028) sobre el kernel; construcción de la imagen de disco UEFI con
44  `bootloader::UefiBoot`; lanzador de QEMU.
45
46### Toolchain
47- Instalación de la toolchain nightly (la máquina solo tenía la estable).
48
49### Corregido
50- Los nightly recientes exigen `-Zjson-target-spec` para usar specs JSON
51  (resuelto al migrar al target nativo).
52- Sintaxis del acelerador de QEMU: `-machine q35,accel=kvm:tcg`.
53
54### Verificado
55- Arranque en QEMU: superficie índigo limpia a 1280×800.
56- Baliza de pánico (franja roja) confirmada inyectando un pánico de prueba.
57
58---
59
60## Fase 2.0 — Cimientos del manejo de fallos — 2026-05-21
61
62### Añadido
63- `kernel/src/gdt.rs`: GDT propia, TSS y un stack de emergencia (IST)
64  reservado para el manejador de doble fallo.
65- `kernel/src/interrupts.rs`: IDT con manejadores de excepción de CPU. El
66  breakpoint (#BP) es recuperable; #UD, #DE, #GP, #PF y #DF son fatales y
67  encienden la baliza.
68- `#![feature(abi_x86_interrupt)]`.
69
70### Corregido
71- La GDT debe recargar los registros SS/DS/ES con un segmento de datos del
72  kernel: el cargador deja `SS = 0x10`, valor que en la GDT nueva pasa a ser el
73  descriptor del TSS; el primer `iretq` de una rutina de excepción provocaba un
74  #GP. Diagnosticado con la traza `-d int` de QEMU.
75
76### Verificado
77- Excepción `int3` atrapada y superada; línea-latido teal dibujada como prueba.
78
79---
80
81## Fase 2.1 — Interrupciones de hardware — 2026-05-21
82
83### Añadido
84- `kernel/src/pic.rs`: remapeo del par 8259 (PIC) fuera del rango de las
85  excepciones (vectores 0x20+); programación del temporizador PIT a 100 Hz;
86  IRQ1 de teclado.
87- Bucle de render en `kernel_main`, despertado por el temporizador, en
88  sustitución del `hlt` estático.
89
90### Verificado
91- La línea-latido se anima (temporizador en marcha); las pulsaciones de teclado
92  inyectadas cambian el cuadro-eco (teclado en marcha).
93
94---
95
96## Fase 3 — Memoria dinámica y reactor asíncrono — 2026-05-21
97
98### Añadido
99- `kernel/src/memory/`: `linked_list_allocator` como `#[global_allocator]`
100  sobre una región estática en `.bss`.
101- `#[alloc_error_handler]`: franja naranja de agotamiento de memoria.
102  `#![feature(alloc_error_handler)]`.
103- `kernel/src/async_system/`: reactor cooperativo — `Executor`, `Task`/`TaskId`,
104  `Waker` (vía `alloc::task::Wake`) y `ScancodeStream`.
105- `kernel/src/texto.rs`: rasterización de tipografía vectorial con `fontdue`;
106  TTF Adwaita Mono empotrada con `include_bytes!`.
107- Dependencias: `linked_list_allocator` 0.10, `spin` 0.9, `crossbeam-queue`
108  0.3, `futures-util` 0.3, `fontdue` 0.9.
109
110### Cambiado
111- Heap ampliado de 16 MiB a 64 MiB: `fontdue`, al analizar una tipografía real,
112  agotaba los 16 MiB iniciales. El `#[alloc_error_handler]` lo delató pintando
113  la franja naranja — el guardarraíl funcionó en silicio real.
114
115### Corregido
116- El modo `no_std` de `fontdue` está condicionado a su feature `hashbrown`; sin
117  ella recae en `std`. Se fija `default-features = false, features = ["hashbrown"]`.
118
119### Verificado
120- Rótulo de bienvenida rasterizado al arranque; el texto tecleado aparece en vivo.
121
122---
123
124## Fase 4 — El escudo de aislamiento WASM — 2026-05-21
125
126### Añadido
127- `kernel/src/wasm/`: intérprete `wasmi` 1.0.9 en modo `no_std`. `env.rs`
128  define la matriz de capacidades — exactamente dos funciones de host:
129  `sys_render_frame(ptr, len)`, con validación infranqueable de los límites de
130  la memoria lineal, y `sys_get_scancode()`.
131- `apps/hello_wasm/`: primera aplicación del userspace — módulo
132  `wasm32-unknown-unknown` (cdylib), un cuadrado móvil dirigido por teclado. Se
133  empotra en el kernel con `include_bytes!`.
134- Dependencia: `wasmi` 1.0.
135
136### Cambiado
137- El kernel se EXCLUYE del espacio de trabajo (`exclude = ["kernel", "apps"]`):
138  al añadir `wasmi`, `cargo build` intentaba compilar el kernel para el
139  anfitrión y fallaba por un símbolo `_start` duplicado. El kernel pasa a
140  construirse únicamente como dependencia de artefacto de `boot`.
141
142### Corregido
143- `wasmi` `no_std` necesita `default-features = false, features = ["hash-collections"]`.
144- `wasmi` 1.0.9 usa `Linker::instantiate_and_start` (no existe `instantiate`).
145
146### Verificado
147- La aplicación WASM pinta su propia superficie y responde a las pulsaciones de
148  teclado inyectadas, sin más vía hacia el kernel que las dos capacidades.
149
150---
151
152## Mantenimiento — Estructura, documentación e integración — 2026-05-21
153
154### Cambiado
155- Refactorización: `main.rs` dividido de 692 a ~155 líneas. Se extraen los
156  módulos `sync.rs`, `grafico.rs`, `consola.rs` y `baliza.rs`. Sin cambios de
157  comportamiento (verificado en QEMU).
158
159### Añadido
160- Documentación: `CLAUDE.md`, `README.md`, `ARCHITECTURE.md`, `ROADMAP.md`,
161  `CHANGELOG.md` y `DIARIO.md`.
162- Integración con git: repositorio inicializado, remoto `origin` en Gitea,
163  `.gitignore`.
164
165### Seguridad
166- `renaser.txt` —un borrador de trabajo que contenía una credencial— se subió
167  por error en el commit inicial. Se purgó de todo el historial con
168  `git filter-branch` y se reescribió el remoto con `push --force`. La
169  credencial expuesta debe rotarse.
170
171---
172
173## Fase 5 — Multitarea cooperativa, guardarrail de fuel y reloj — 2026-05-22
174
175Unificación de la Fase 3 (reactor) y la Fase 4 (WASM): el userspace deja de ser
176una sola app que monopoliza la CPU y pasa a ser un conjunto de aplicaciones
177cooperativas, aisladas también en el TIEMPO.
178
179### Añadido
180- `kernel/src/async_system/reloj.rs`: convierte la IRQ0 (PIT, 100 Hz) en una
181  primitiva asíncrona. `CONTADOR_PULSOS` (`AtomicU64`) y `EsperaFrame`, un
182  `Future` que se resuelve en el siguiente pulso — la unidad de cesión
183  cooperativa del userspace. Censo de wakers tras `Mutex`, drenado por la IRQ0.
184- `kernel/src/wasm`: ABI de fotograma. `AplicacionWasm` —instancia PERSISTENTE
185  entre fotogramas (`Store` + `TypedFunc<(), ()>` + región)— sustituye al
186  `wasm::ejecutar` de fuego-y-olvido. El módulo del userspace exporta ahora
187  `init()` (una vez) y `tick()` (un fotograma, y retorna).
188- Escudo de combustible: `Engine` con `Config::consume_fuel(true)` y
189  `CompilationMode::Eager` (el `fuel` mide solo ejecución). Presupuesto recargado
190  antes de cada `tick` — `FUEL_ARRANQUE` (20 M) y `FUEL_FOTOGRAMA` (2 M).
191- `kernel/src/wasm/env.rs`: capacidad `sys_render_frame` con **regiones de
192  dibujo** — cada fotograma se compone desplazado por el `(offset_x, offset_y)`
193  de la app; un tamaño ajeno a la región se rechaza. Canal de teclado **por
194  aplicación**: la IRQ1 difunde cada scancode a TODOS los canales, de modo que
195  varias apps reciben la entrada en paralelo sin robársela.
196- `kernel/src/grafico.rs`: `RegionPantalla` y `Color::DESALOJO` (púrpura).
197- `apps/discola/`: aplicación WASM construida para portarse mal — su `tick` es
198  un bucle cerrado. Demuestra el guardarrail de fuel en vivo.
199
200### Cambiado
201- `apps/hello_wasm`: migrada al ABI `init`/`tick`; su lienzo se dimensiona a la
202  región (480×560). El estado del cuadrado persiste en su memoria lineal.
203- `interrupts.rs`: la IRQ0 avanza el `reloj`; la IRQ1 difunde a los canales.
204- `consola.rs`: `volcar_marco` compone en una sub-región; `pintar_desalojo`
205  tatúa la baliza púrpura.
206- Contención de fallos: el subsistema WASM ya no usa `.expect()`. Toda falla
207  —carga, instanciación, desbordamiento, agotamiento de fuel— se devuelve como
208  `Result`; la tarea desaloja la app (baliza púrpura) y el kernel sigue vivo.
209
210### Verificado
211- QEMU: tres apps concurrentes. Dos instancias de `hello_wasm` (mismo bytecode,
212  regiones izquierda y derecha) renderizan y responden a W/A/S/D **en paralelo**,
213  con movimiento idéntico. La app díscola es desalojada en su primer fotograma
214  por agotamiento de combustible: su región queda púrpura y el sistema —kernel y
215  apps vecinas— no sufre un solo sobresalto.
216
217---
218
219## Fase 6.0 — Cuotas de memoria y ciclo de vida del userspace — 2026-05-22
220
221El aislamiento de las aplicaciones, que la Fase 5 hizo temporal (combustible),
222se completa ahora en la dimensión espacial (memoria) y se cierra la fuga de
223recursos del ciclo de vida.
224
225### Añadido
226- Techo de memoria lineal por aplicación: `4 MiB`. `wasm/mod.rs` construye un
227  `StoreLimits` (`StoreLimitsBuilder::memory_size` + `trap_on_grow_failure`) y lo
228  liga al `Store` con `Store::limiter`. Un `memory.grow` que rebase la cuota se
229  convierte en trampa; el kernel la captura y desaloja la app.
230- `FallaApp::SinMemoria` y `Color::DESALOJO_MEMORIA` (amarillo pálido). El
231  desalojo distingue la causa por color: púrpura (tiempo/aborto), amarillo
232  (memoria). La clasificación es robusta — `Error::as_trap_code()` da un código
233  público y unívoco: `TrapCode::GrowthOperationLimited`.
234- `Drop` para `AplicacionWasm`: al morir una app desalojada, su canal de teclado
235  se da de baja del censo de difusión de la IRQ1 — cierra la fuga señalada en la
236  Fase 5. `async_system::teclado` se reorganiza en `crear_canal` /
237  `registrar_canal` / `cerrar_canal`; el canal se inscribe al FINAL de la carga,
238  de modo que una carga fallida no deja canales huérfanos.
239- `apps/glotona/`: aplicación WASM construida para devorar memoria — su `tick`
240  invoca `memory.grow` sin freno. Demuestra el guardarrail espacial en vivo.
241
242### Verificado
243- QEMU: cuatro apps concurrentes. Las dos `hello_wasm` renderizan y responden al
244  teclado en paralelo; la app díscola es desalojada por combustible (franja
245  púrpura) y la app glotona por cuota de memoria (franja amarilla), ambas en su
246  primer fotograma, sin que el kernel ni las apps honradas se inmuten.
247
248---
249
250## Fase 6.1a — Sonda PCI y disco de pruebas — 2026-05-22
251
252Primer paso de la estrategia incremental hacia el almacenamiento: derribar el
253muro del descubrimiento de hardware antes de diseñar nada encima.
254
255### Añadido
256- `kernel/src/drivers/`: nuevo subsistema de drivers. `pci.rs` enumera el bus
257  PCI por fuerza bruta mediante el mecanismo de configuración #1 —puertos de E/S
258  `0xCF8` (dirección) y `0xCFC` (datos)—; recorre buses y dispositivos leyendo
259  el Vendor/Device ID, y localiza el disco virtio-blk (vendor `0x1AF4`, device
260  `0x1001`/`0x1042`), devolviendo su ubicación y sus seis BARs.
261- `kernel_main`: tras fundar la consola, sondea el bus PCI y deja constancia
262  visual del hallazgo.
263
264### Cambiado
265- `boot/src/main.rs`: forja un disco de pruebas `target/disk.img` (fichero
266  disperso de 32 MiB; se respeta si ya existe) y lo adjunta a QEMU como
267  `virtio-blk-pci`. **Corrección de plataforma:** la máquina `q35` es x86_64 y
268  exige la transmisión PCI; `virtio-blk-device` (su gemelo MMIO) es de ARM.
269
270### Verificado
271- QEMU: el kernel enumera el bus y reporta en pantalla
272  `virtio-blk en bus 0 dev 3 :: BAR0 E/S 0x6000` — un dispositivo virtio-blk
273  transicional (device `0x1001`), con su BAR0 en espacio de E/S. El muro del
274  descubrimiento PCI queda derribado; las cuatro apps del userspace siguen
275  operando sin alteración.
276
277---
278
279## Fase 6.1b — HAL, DMA y lectura del sector 0 — 2026-05-22
280
281Segundo paso del sustrato de almacenamiento: el diálogo real con el disco. El
282kernel monta el dispositivo virtio-blk y lee su primer sector por DMA.
283
284### Añadido
285- Dependencia `virtio-drivers` 1.13 (`no_std`, `default-features = false`,
286  feature `alloc`).
287- `kernel/src/drivers/disco.rs`:
288  - **Asignador de marcos** «bump» — reparte páginas físicas de 4 KiB para el
289    DMA, tomadas de la mayor región de RAM libre que el cargador reporta. No
290    libera: suficiente para una sonda (la gestión fina llegará con el grafo).
291  - **`KernelHal`** — implementa el `trait Hal` de `virtio-drivers`. `dma_alloc`
292    entrega marcos físicos a cero; `mmio_phys_to_virt` traduce los BARs (el
293    cargador mapea ≥ 4 GiB de memoria física, que cubre todo MMIO de PCI);
294    `share`/`unshare` usan un buffer rebote para que cualquier región del kernel
295    pueda viajar al dispositivo.
296  - **`montar_y_leer_sector0`** — enumera el bus, habilita E/S + memoria +
297    bus-master, monta el `PciTransport` y el `VirtIOBlk`, y lee el sector 0 por
298    **sondeo** del *used ring* (sin depender aún de interrupciones).
299- `kernel/src/drivers/pci.rs`: reescrito como `CamPuertos`, la implementación de
300  `ConfigurationAccess` de `virtio-drivers` sobre los puertos `0xCF8`/`0xCFC`.
301- `kernel_main` captura `physical_memory_offset` y la región de RAM de
302  `BootInfo`, funda el subsistema de disco y reporta el resultado de la sonda.
303
304### Cambiado
305- `boot/src/main.rs`: al forjar el disco de pruebas graba una firma
306  (`renaser-6.1b`) en su sector 0 — el testigo del viaje de ida y vuelta.
307
308### Verificado
309- QEMU: el kernel reporta `virtio-blk :: bus 0 dev 3 :: 65536 sectores ::
310  s0=renaser-6.1b`. La firma grabada por el anfitrión se lee de vuelta intacta:
311  descubrimiento PCI, transporte, DMA y transferencia funcionan de punta a
312  punta. Las cuatro apps del userspace siguen operando sin alteración.
313
314---
315
316## Fase 6.1c — El grafo de objetos direccionado por contenido — 2026-05-22
317
318Tercer y último paso del sustrato de almacenamiento. El disco deja de ser un
319dispositivo que se sondea y pasa a ser una MEMORIA QUE PERDURA: un grafo
320dirigido acíclico de objetos direccionados por contenido — no un sistema de
321archivos plano POSIX.
322
323### Añadido
324- `kernel/src/almacen.rs` — el grafo de objetos:
325  - **Objeto** — una carga útil de bytes (`datos`) y una lista de aristas
326    (`hijos`: hashes de otros objetos). Las aristas hacen del almacén un DAG.
327  - **Direccionamiento por contenido** — la identidad de un objeto es el hash
328    BLAKE3 de su forma serializada. De ello se siguen dos propiedades que un
329    sistema de archivos jamás regala: INTEGRIDAD (el contenido leído se
330    rehashea y se verifica contra el hash pedido) y DEDUPLICACIÓN (contenido
331    idéntico produce el mismo hash; se almacena una sola vez).
332  - **Disco como log** — el sector 0 es el superbloque (magia `RENASGRF`,
333    versión, cursor del log y hash de la raíz); tras él se anexan los registros
334    de objetos, `[longitud u32 LE][payload postcard][relleno a cero]`. Un
335    índice en memoria (hash -> sector) se reconstruye al arrancar recorriendo
336    el log de cabo a rabo.
337  - API: `init` —monta el disco, lee o forja el superbloque, reconstruye el
338    índice—, `almacenar`, `recuperar`, `raiz` y `fijar_raiz`.
339- Cinco capacidades nuevas del host en `wasm/env.rs` — `sys_object_put`,
340  `sys_object_datos`, `sys_object_hijo`, `sys_object_raiz` y
341  `sys_object_fijar_raiz` —, con la misma validación infranqueable de límites
342  de la memoria lineal que `sys_render_frame`. Distinguen dos clases de fallo:
343  un puntero inválido ABORTA la app —es su culpa, se traduce en trampa—; un
344  fallo del almacenamiento le devuelve un código de error negativo —no lo es—.
345- `apps/cronista/` — la primera aplicación del userspace que escribe en el
346  almacenamiento PERSISTENTE. En cada arranque consulta la raíz del grafo,
347  graba un objeto nuevo —`datos`: el número de arranque; `hijos`: la raíz
348  anterior, el eslabón del DAG— y lo corona como raíz. Pinta una celda por
349  arranque registrado y un testigo de integridad que recorre la cadena entera.
350- Dependencias: `serde` 1 y `postcard` 1 (serialización binaria compacta, el
351  formato que viaja al disco) y `blake3` 1 (la función hash). Las tres `no_std`.
352
353### Cambiado
354- `kernel/src/drivers/disco.rs` reescrito para un sustrato PERMANENTE:
355  - El asignador de marcos «bump» de la Fase 6.1b cede el paso a uno de MAPA DE
356    BITS con liberación real. `dma_dealloc` y `unshare` devuelven los marcos a
357    la arena: un almacén vivo, con su trasiego incesante de DMA, ya no la agota.
358  - El `VirtIOBlk` deja de montarse y destruirse en cada llamada: se monta UNA
359    vez y queda tras un `Mutex` global. `leer_sectores` / `escribir_sectores`
360    exponen la E/S de bloques — el disco deja de ser de solo lectura. Se retira
361    `montar_y_leer_sector0`, la sonda de un solo uso de la Fase 6.1b.
362- `boot/src/main.rs`: el disco de pruebas pasa a ser el disco de objetos. Ya
363  no se le graba una firma — se forja virgen, a cero, y el kernel lo formatea
364  la primera vez que no halle el superbloque.
365- `main.rs`: `informar_disco` (la sonda de la Fase 6.1b) se sustituye por
366  `informar_almacen`, que funda el grafo. El userspace pasa de cuatro a cinco
367  apps; las regiones de discola y glotona se reajustan para alojar a cronista.
368
369### Notas
370- **blake3 forzado a escalar.** El target del kernel corre sin SSE; un camino
371  SIMD de blake3 activado por detección en tiempo de ejecución ejecutaría
372  instrucciones que la CPU, sin `CR4.OSFXSR`, rechazaría con un #UD. Se fija
373  blake3 con `pure` + los cuatro `no_*` (`sse2`, `sse41`, `avx2`, `avx512`):
374  implementación puramente escalar, sin SIMD ni ensamblador.
375
376### Verificado
377- QEMU, TRES arranques consecutivos sobre el mismo disco persistente: la app
378  cronista pinta 1, luego 2, luego 3 celdas — la cuenta de arranques sobrevive
379  a los reinicios porque vive en el grafo, en el disco, no en la RAM. El
380  testigo de integridad queda VERDE en los tres: el DAG entero se recorre, de
381  la raíz al primer eslabón, y su profundidad cuadra con la cuenta. El
382  superbloque en disco confirma la magia `RENASGRF`, versión 1, cursor 4 y la
383  raíz del tercer arranque; el registro del primer arranque guarda `datos = 1`
384  y cero hijos. Las otras cuatro apps siguen su curso sin alteración — las dos
385  `hello_wasm` renderizando, discola desalojada en púrpura, glotona en amarillo.
386
387---
388
389## Fase 6.2 — E/S de disco asíncrona por interrupción — 2026-05-22
390
391La Fase 6.1 hizo hablar al disco, pero por SONDEO: el procesador se quedaba en
392espera activa vigilando el *used ring* de virtio, incapaz de atender nada más.
393La 6.2 libera el planificador cooperativo — la E/S de bloques pasa a ser
394REACTIVA, guiada por la interrupción física del dispositivo.
395
396### Añadido
397- `EsperaDisco` (`drivers/disco.rs`): una transferencia de bloques expresada
398  como `Future` nativo. Posee sus buferes DMA —`BlkReq`, `BlkResp` y los datos,
399  en el heap para una dirección estable—; su `poll` envía la petición por la
400  API NO BLOQUEANTE de `virtio-drivers` (`read_blocks_nb`/`write_blocks_nb`),
401  consulta el *used ring* (`peek_used`) y, si la transferencia sigue en vuelo,
402  inscribe el waker y cede. `leer_bloques`/`escribir_bloques` lo construyen.
403- La IRQ del disco: `montar` descubre la línea de IRQ legada del dispositivo
404  (registro «Interrupt Line», offset 0x3C del espacio de configuración PCI),
405  registra un manejador en la IDT y abre la línea en el PIC.
406  `interrupts::irq_disco` → `disco::atender_irq` reconoce la interrupción en el
407  dispositivo —leer su registro ISR baja la línea INTx— y despierta, vía un
408  waker de ranura única, a la tarea que aguardaba el bloque.
409- `bloquear_en` — el puente para los contextos SÍNCRONOS (el arranque, las
410  capacidades WASM, que no pueden `.await`): lleva un `Future` de disco hasta
411  su final durmiendo la CPU con `hlt` —la despiertan la IRQ del disco o el
412  temporizador, como red de seguridad—; jamás en espera activa con el sistema
413  ya en marcha.
414- `pic::desenmascarar` / `pic::vector_irq`: abrir una línea concreta del par
415  8259 (con su cascada, si vive en el esclavo) y mapear línea → vector de IDT.
416- `pci::linea_irq`: leer el registro «Interrupt Line» de un dispositivo.
417- `tarea_sonda_disco` (`main.rs`): una tarea del reactor que lee el sector 0 de
418  forma asíncrona — la prueba viva de que la IRQ conduce la E/S sin detener a
419  las aplicaciones.
420
421### Cambiado
422- `leer_sectores`/`escribir_sectores` se reescriben sobre la maquinaria
423  asíncrona (`bloquear_en` + `EsperaDisco`). El `almacen` y las capacidades
424  `sys_object_*` NO cambian una línea: heredan la E/S por interrupción de
425  forma transparente — la espera de disco deja de quemar ciclos en sondeo.
426- El `VirtIOBlk` pide al dispositivo que emita interrupciones al completar cada
427  petición (`enable_interrupts`).
428
429### Decisiones de ingeniería
430- **PIC, no IOAPIC.** El kernel corre íntegramente sobre el par 8259 (`pic.rs`)
431  y la crate `x86_64` no ofrece abstracción de APIC. Las IRQ legadas de PCI de
432  la máquina `q35` se enrutan por el 8259: basta leer la línea que el firmware
433  UEFI ya asignó y abrirla. Migrar al IOAPIC habría exigido levantar LAPIC +
434  IOAPIC + parseo de tablas ACPI — un subsistema entero, desproporcionado para
435  el objetivo. El resultado funcional es idéntico: E/S conducida por la
436  interrupción física.
437- **Las capacidades WASM no `.await`-ean.** El intérprete `wasmi` ejecuta las
438  funciones de host de forma SÍNCRONA: no hay manera de suspender un módulo a
439  mitad de una llamada de host. Por eso `sys_object_*` no se vuelven
440  asíncronas; usan `bloquear_en`, que duerme la CPU con `hlt` en lugar de
441  sondear. El verdadero solapamiento E/S ↔ render lo aprovechan las TAREAS del
442  reactor (`tarea_sonda_disco` hoy; la carga dinámica de módulos, mañana).
443- Una IRQ legada de PCI es de NIVEL: el manejador reconoce primero al
444  dispositivo —lo que baja su línea— y sólo después cierra el EOI del PIC; el
445  orden inverso reavivaría la interrupción en bucle.
446- Todo acceso al disco toma su `Mutex` con las interrupciones desactivadas
447  (`without_interrupts`): la IRQ del disco jamás encuentra el cerrojo ocupado,
448  lo que hace imposible el interbloqueo por interrupción.
449
450### Verificado
451- QEMU: el disco virtio-blk se enruta a la IRQ 11. La `tarea_sonda_disco`
452  reporta «sonda asíncrona OK -- 2 IRQ de disco atendidas»: la interrupción del
453  disco dispara de verdad. La app cronista, sobre el disco persistente heredado
454  de la Fase 6.1c, continúa la cuenta de arranques (3 → 4 → 5 celdas) con el
455  testigo de integridad del DAG en verde — la nueva E/S asíncrona lee y escribe
456  el grafo sin un solo fallo. Las cuatro apps WASM siguen su curso, sin un
457  sobresalto ni un micro-congelamiento.
458
459## Fase 7 — Apertura: Apps que nacen del Grafo — 2026-05-22
460
461Apertura de la Fase 7. Este commit asienta el plan y el andamiaje; **no
462cambia el comportamiento del kernel**. La Fase 7 destierra el
463`include_bytes!` del userspace: las aplicaciones pasan a ser objetos del
464grafo, y un Manifiesto de Génesis —también en el grafo— dicta qué arranca,
465con qué cuota y en qué región.
466
467### Añadido
468- `FASE7.md` — el plan de ataque: el objetivo, el problema huevo-y-gallina
469  de la génesis, las sub-fases 7a (manifiesto + carga desde el grafo, con
470  semilla por el kernel), 7b (siembra de la imagen por `boot`, muerte del
471  `include_bytes!`) y 7c (persistencia inter-sesión), y los guardarraíles.
472- `kernel/src/manifiesto.rs` — andamiaje del Manifiesto de Génesis. Los
473  tipos `Manifiesto` / `EntradaApp` y la (de)serialización `postcard` están
474  completos; `cargar` y `sembrar_genesis` son esbozos hasta la Fase 7a.
475  La sub-región se guarda en campos `u32` de ancho fijo (formato en disco),
476  no como `RegionPantalla` (`usize`, ancho de plataforma).
477
478### Notas
479- El módulo se declara en `main.rs` pero aún no se cablea a `kernel_main`
480  (`#![allow(dead_code)]` temporal, hasta que la 7a le dé un llamador). El
481  kernel compila y se comporta idéntico a la Fase 6.2 — nada observable que
482  verificar en QEMU en esta apertura.
483
484## Fase 7a — Apps que nacen del Grafo: el Manifiesto — 2026-05-22
485
486El kernel deja de empotrar el userspace. Las cinco aplicaciones ya no llegan
487por `include_bytes!` en `main.rs`: nacen del grafo de objetos, gobernadas por
488un Manifiesto de Génesis que también vive en el grafo.
489
490### Añadido
491- `kernel/src/manifiesto.rs` — el Manifiesto de Génesis implementado: tipos
492  `Manifiesto` / `EntradaApp`, (de)serialización `postcard`, `cargar` (lee el
493  manifiesto del grafo vía el ancla del superbloque) y `sembrar_genesis`
494  (puebla un disco virgen con las cinco apps de génesis).
495- `almacen`: el `SuperBloque` gana el ancla `manifiesto: Option<Hash>` —
496  gemela de `raiz`, pero del lado del kernel. Accesores `manifiesto()` y
497  `fijar_manifiesto()`.
498
499### Cambiado
500- `almacen::VERSION` 1 → 2: el superbloque cambia de forma. Un disco v1 se
501  reformatea al arrancar, como cualquier disco ajeno — la cuenta de la
502  cronista reinicia una vez.
503- `kernel_main`: las cinco llamadas `encender_app` escritas a mano se
504  sustituyen por `cargar_userspace`, que carga el manifiesto —o lo siembra si
505  el disco está virgen— e itera sus `EntradaApp`.
506- `encender_app` recibe una `EntradaApp` y recupera el bytecode del grafo.
507  `recuperar` ya recomputa y verifica el hash: un bytecode corrupto se niega,
508  se pinta la baliza de desalojo en su región y el arranque continúa.
509- `wasm::AplicacionWasm::cargar` recibe el techo de memoria por-app (del
510  manifiesto) en vez de la constante global `TECHO_MEMORIA`.
511
512### Notas
513- La siembra es TRANSITORIA: el bytecode aún viaja empotrado en
514  `manifiesto.rs` (`include_bytes!`) como semilla. La Fase 7b lo moverá al
515  constructor de imagen `boot` y el `include_bytes!` morirá del todo.
516
517### Verificado
518- QEMU (captura headless por el monitor, `screendump`): los dos caminos del
519  Manifiesto confirmados.
520  - **Disco virgen** — el almacén reporta «disco formateado :: 65536 sectores
521    :: 0 objetos», la consola imprime «manifiesto :: genesis sembrada en disco
522    virgen» y «manifiesto :: 5 apps nacidas del grafo». La pantalla es
523    idéntica a la Fase 6.2: dos `hello_wasm` renderizando, discola desalojada
524    en púrpura, glotona en amarillo, cronista pintando su primera celda.
525  - **Disco ya sembrado** — sin línea de siembra: el almacén reporta «grafo
526    montado :: 6 objetos :: raíz presente» (las 5 semillas más el objeto que
527    la cronista persistió), la consola imprime sólo «manifiesto :: 5 apps
528    nacidas del grafo», y la cronista pinta su segunda celda — la cuenta de
529    arranques sobrevivió al apagón. El userspace nace del grafo en ambos
530    casos.
531
532## Fase 7b — La imagen sembrada por `boot`; muere el `include_bytes!` — 2026-05-22
533
534El kernel deja de empotrar el userspace POR COMPLETO. Hasta la 7a, el bytecode
535de las cinco apps de génesis aún viajaba dentro del binario del kernel
536(`include_bytes!`), como semilla transitoria. La 7b lo mata: es el constructor
537de imagen `boot` —en el anfitrión— quien siembra el disco con el grafo ya
538poblado. El binario del kernel ya no carga ni un solo `.wasm`.
539
540### Añadido
541- **`formato`** — nueva crate: un núcleo `#![no_std]` COMPARTIDO que define el
542  formato del grafo de objetos en disco. Tipos (`Objeto`, `SuperBloque`,
543  `Manifiesto`, `EntradaApp`), su (de)serialización `postcard`, la función hash
544  BLAKE3 (escalar pura) y el trazado de un registro del log
545  (`componer_registro` / `longitud_registro`). Lo enlazan el kernel bare-metal
546  Y el anfitrión `boot`: una sola verdad del formato, imposible de divergir
547  entre los dos lados. 5 pruebas de ida y vuelta. Excluida del workspace, como
548  el kernel.
549- `boot`: `sembrar_grafo` — siembra un disco virgen con el grafo ya poblado.
550  Graba el bytecode de cada app de génesis como un objeto (deduplicado:
551  `app.wasm`, usado dos veces, se guarda una sola), compone el Manifiesto de
552  Génesis con sus regiones y cuotas, lo graba con las aristas hacia los objetos
553  de bytecode, y forja el superbloque que lo ancla. El `.wasm` se lee de
554  `kernel/assets/` en tiempo de ejecución.
555
556### Cambiado
557- `kernel/manifiesto.rs`: pierde los cuatro `include_bytes!`, el descriptor
558  `AppGenesis`, `genesis()` y `sembrar_genesis()`. Se reduce a `cargar()` —leer
559  el manifiesto del grafo— y `region()` —traducir la región en disco a la del
560  kernel—. Los tipos `Manifiesto` / `EntradaApp` migran a `formato`.
561- `kernel/almacen.rs`: los tipos `Objeto` / `SuperBloque`, las constantes del
562  formato, el hash y el trazado de registros migran a `formato`. El módulo
563  queda como el almacén VIVO: cursor, índice y E/S contra virtio-blk.
564- `kernel_main` / `cargar_userspace`: sin la rama de siembra. Un disco sin
565  manifiesto anclado ya no se siembra desde el kernel —`boot` lo hace siempre
566  al forjar la imagen—; el kernel se levanta sin userspace y lo reporta.
567- `kernel/Cargo.toml`: deja de declarar `serde` / `postcard` / `blake3` por su
568  cuenta; los hereda —mismas features, BLAKE3 escalar puro— a través de
569  `formato`.
570- `wasm/mod.rs`: se retira la constante `TECHO_MEMORIA`, ya sin uso (el techo
571  por-app lo dicta el manifiesto; el valor de génesis vive ahora en `boot`).
572- `.cargo/config.toml`: el alias `cargo kernel` pasa de `-p kernel` a
573  `--manifest-path kernel/Cargo.toml`. Con `formato` compartido entre el kernel
574  y `boot`, pedir `-p kernel` dentro del workspace —con el kernel a la vez como
575  dependencia de artefacto— hace caer al resolvedor de features de cargo;
576  apuntar al manifiesto del kernel lo compila como raíz y esquiva el grafo.
577
578### Verificado
579- QEMU (captura headless por el monitor, `screendump`), los dos caminos:
580  - **Disco virgen** — `boot` imprime «disco de objetos sembrado :: 5 objetos,
581    manifiesto anclado»; el kernel monta el grafo de `boot` —«grafo montado ::
582    5 objetos :: raíz ausente», SIN «disco formateado» ni «génesis sembrada»—
583    e instancia las cinco apps. Pantalla idéntica a la Fase 6.2.
584  - **Segundo arranque** — `boot` respeta el disco existente («el grafo
585    perdura»); el kernel carga «6 objetos :: raíz presente» y la cronista pinta
586    su segunda celda: la persistencia sobrevive a través de un disco sembrado
587    por `boot`.
588- `cargo build -p boot` y `cargo kernel` compilan limpios; `cargo test` de
589  `formato` — 5/5 en verde.

CHANGELOG.md

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

Añadido

Notas


Fase 1.5 — Empaquetado y arranque — 2026-05-21

Cambiado

Añadido

Toolchain

Corregido

Verificado


Fase 2.0 — Cimientos del manejo de fallos — 2026-05-21

Añadido

Corregido

Verificado


Fase 2.1 — Interrupciones de hardware — 2026-05-21

Añadido

Verificado


Fase 3 — Memoria dinámica y reactor asíncrono — 2026-05-21

Añadido

Cambiado

Corregido

Verificado


Fase 4 — El escudo de aislamiento WASM — 2026-05-21

Añadido

Cambiado

Corregido

Verificado


Mantenimiento — Estructura, documentación e integración — 2026-05-21

Cambiado

Añadido

Seguridad


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

Cambiado

Verificado


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

Verificado


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

Cambiado

Verificado


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

Cambiado

Verificado


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

Cambiado

Notas

Verificado


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

Cambiado

Decisiones de ingeniería

Verificado

Fase 7 — Apertura: Apps que nacen del Grafo — 2026-05-22

Apertura de la Fase 7. Este commit asienta el plan y el andamiaje; no cambia el comportamiento del kernel. La Fase 7 destierra el include_bytes! del userspace: las aplicaciones pasan a ser objetos del grafo, y un Manifiesto de Génesis —también en el grafo— dicta qué arranca, con qué cuota y en qué región.

Añadido

Notas

Fase 7a — Apps que nacen del Grafo: el Manifiesto — 2026-05-22

El kernel deja de empotrar el userspace. Las cinco aplicaciones ya no llegan por include_bytes! en main.rs: nacen del grafo de objetos, gobernadas por un Manifiesto de Génesis que también vive en el grafo.

Añadido

Cambiado

Notas

Verificado

Fase 7b — La imagen sembrada por boot; muere el include_bytes! — 2026-05-22

El kernel deja de empotrar el userspace POR COMPLETO. Hasta la 7a, el bytecode de las cinco apps de génesis aún viajaba dentro del binario del kernel (include_bytes!), como semilla transitoria. La 7b lo mata: es el constructor de imagen boot —en el anfitrión— quien siembra el disco con el grafo ya poblado. El binario del kernel ya no carga ni un solo .wasm.

Añadido

Cambiado

Verificado