Files
brahman/renaser/ROADMAP.md
T
sergio 089afccbbc feat(renaser): Fase 10 — alta y baja de aplicaciones en vivo
El censo de aplicaciones deja de fijarse en el arranque: una app puede
nacer o cerrarse con el reactor ya en marcha.

- El reactor admite NACIMIENTOS en vivo: cola `NACIMIENTOS` +
  `engendrar()`, drenada al inicio de cada vuelta de `run()`;
  `Task::adoptar` acoge un futuro ya empaquetado.
- `Alt+Q` (`Mando::Cerrar`): baja limpia. El compositor saca la
  ventana enfocada del teselado y del orden-Z; la app advierte la
  baja (`ventana_cerrada`) y concluye su tarea — su memoria, su
  combustible y su canal de teclado se liberan. Sin baliza.
- `Alt+N` (`Mando::Lanzar`): alta en vivo. `nacer_ventana` añade la
  ventana y entrega su índice; el orquestador instancia el WASM y
  engendra su tarea. Las apps de génesis dejan su bytecode cacheado
  como `Plantilla`; cada `Alt+N` instancia una en rotación.

Verificado en QEMU (sendkey): tres Alt+N hacen crecer el escritorio
de 5 a 8 ventanas; tres Alt+Q lo reducen de 8 a 5. Kernel estable.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 20:26:25 +00:00

11 KiB

renaser — Hoja de ruta

Estado de las fases del proyecto. Para la arquitectura, ver ARCHITECTURE.md.

Fases completadas

Todas verificadas en QEMU (captura de pantalla incluida en su momento).

Fase 1 — el primer microsegundo

Arranque UEFI, adopción del framebuffer GOP, lienzo de doble búfer y la baliza de pánico (franja roja al colapsar). Punto de entrada con bootloader_api.

Fase 1.5 — empaquetado y arranque

Miembro boot/: constructor de la imagen de disco UEFI (crate bootloader 0.11, vía dependencia de artefacto) y lanzador de QEMU. cargo run pasa a compilar, forjar la imagen y arrancar, todo de un gesto.

Fase 2.0 — cimientos del manejo de fallos

GDT propia + TSS con stack de emergencia (IST) para el doble fallo. IDT con manejadores de excepción de CPU. El breakpoint es recuperable; el resto de excepciones encienden la baliza.

Fase 2.1 — interrupciones de hardware

Remapeo del PIC 8259 fuera del rango de las excepciones. Temporizador (PIT) a 100 Hz e IRQ1 de teclado. El kernel pasa de "pintar una vez" a un bucle de render despertado por el hardware.

Fase 3 — memoria dinámica y reactor asíncrono

Heap de 64 MiB con linked_list_allocator como asignador global; manejador propio de OOM (franja naranja). Reactor cooperativo: Executor, Task, Waker. Texto vectorial con fontdue: el texto deja de ser mapa de bits.

Fase 4 — el escudo de aislamiento WASM

Runtime wasmi no_std. Matriz de capacidades con dos funciones de host (sys_render_frame, sys_get_scancode) y validación infranqueable de límites de la memoria lineal. Primera app del userspace: apps/hello_wasm, un módulo wasm32 aislado que pinta y responde al teclado.

Fase 5 — multitarea cooperativa, fuel y reloj

Unificación del reactor (Fase 3) y el runtime WASM (Fase 4). El ABI del userspace pasa a init/tick: cada tick es un punto de cesión cooperativa. async_system::reloj convierte la IRQ0 en el Future EsperaFrame, que marca el compás de los fotogramas. Cada app es una AplicacionWasm persistente y una tarea del reactor. Escudo de combustible (fuel): cada tick corre con un presupuesto estricto; agotarlo desaloja la app sin tocar al kernel. Capacidades ampliadas — regiones de dibujo por app y canal de teclado por app. Verificado en QEMU con tres apps concurrentes, una de ellas díscola y desalojada en vivo.

Fase 6.0 — cuotas de memoria y ciclo de vida

Completa el aislamiento espacial del userspace. Cada AplicacionWasm instancia su Store con un StoreLimits (techo de memoria lineal de 4 MiB, vía Store::limiter); rebasarlo es una trampa que desaloja la app con baliza amarilla — gemela de la púrpura del desalojo por combustible. Drop para AplicacionWasm reconcilia el ciclo de vida: da de baja el canal de teclado de la difusión de la IRQ1. Verificado en QEMU con cuatro apps — una díscola (desalojo temporal) y una glotona (desalojo espacial), ambas en vivo.

Fase 6.1 — sustrato de almacenamiento (completada)

Estrategia incremental para el almacenamiento, frente al riesgo del hardware:

  • 6.1a — Sonda PCI (hecha)drivers/pci.rs enumera el bus PCI por 0xCF8/0xCFC y localiza el disco virtio-blk; boot forja el disco de pruebas y lo adjunta como virtio-blk-pci. El muro del descubrimiento de hardware queda derribado.
  • 6.1b — HAL y lectura de sector (hecha)drivers/disco.rs: asignador de marcos «bump», KernelHal (el trait Hal de virtio-drivers: DMA y traducción de direcciones) y montar_y_leer_sector0, que lee el sector 0 por sondeo. Verificado por una firma que viaja del anfitrión al disco y vuelve.
  • 6.1c — Grafo de objetos (hecha)almacen.rs: el almacenamiento como DAG direccionado por contenido —la identidad de un objeto es el hash BLAKE3 de su forma serializada (postcard); el disco se organiza como un log con superbloque e índice—, y las cinco capacidades sys_object_* que lo exponen al userspace. drivers/disco.rs gana un asignador de marcos con liberación real (mapa de bits), escritura de sectores y un VirtIOBlk persistente. La app cronista lleva la cuenta de los arranques en el grafo: la cuenta perdura entre reinicios.

Fase 6.2 — E/S de disco asíncrona por interrupción (completada)

La Fase 6.1 hizo hablar al disco, pero por sondeo: el procesador se quedaba en espera activa vigilando el used ring de virtio. La 6.2 libera el planificador cooperativo — la E/S de bloques pasa a ser reactiva:

  • EsperaDisco — una transferencia de bloques como Future nativo, sobre la API no bloqueante de virtio-drivers (read_blocks_nb / peek_used / complete_*). Cede la CPU mientras el disco trabaja.
  • La IRQ del discomontar descubre la línea de IRQ legada del dispositivo (registro «Interrupt Line» del espacio de configuración PCI), la enruta por el 8259 y registra su manejador; atender_irq reconoce la interrupción y despierta a la tarea que aguardaba el bloque.
  • bloquear_en — el puente para los contextos síncronos (el arranque, las capacidades WASM): duerme la CPU con hlt en vez de sondear.

Decisión de ingeniería: las IRQ se enrutan por el PIC 8259 que el kernel ya gobierna, no por el IOAPIC — basta leer la línea que el firmware ya asignó. Verificado en QEMU: el disco se enruta a la IRQ 11; una tarea-sonda del reactor lee un bloque de forma asíncrona mientras las apps siguen pintando.

Fase 7 — el userspace nace del Grafo de Objetos (completada)

Hasta la Fase 6, el userspace venía empotrado en el binario del kernel: cuatro include_bytes! de .wasm y regiones escritas a mano. La Fase 7 lo destierra — las aplicaciones pasan a ser objetos del grafo, gobernadas por un Manifiesto de Génesis que también vive en el grafo. Plan completo en FASE7.md.

  • 7a — el Manifiesto (completada). manifiesto.rs: tipos Manifiesto / EntradaApp y carga desde el grafo. El superbloque gana el ancla manifiesto (VERSION 1→2). kernel_main lee el manifiesto e instancia cada app recuperando su bytecode del grafo, verificado por su hash.
  • 7b — la imagen sembrada por boot (completada). Nace la crate formato, un núcleo no_std con el formato del grafo en disco, COMPARTIDO por el kernel y el constructor de imagen boot. boot siembra el disco virgen con el grafo ya poblado —bytecode y manifiesto—; el kernel pierde todo include_bytes! del userspace. Su binario ya no carga ni un .wasm.
  • 7c — persistencia inter-sesión (completada). La app memoriosa graba su estado como un objeto del grafo; el kernel lo ancla en la ranura EntradaApp.estado y re-graba el manifiesto. Al despertar, init lo relee y la app retoma donde quedó. Capacidades sys_estado_cargar / sys_estado_guardar; el kernel custodia un manifiesto VIVO y mutable.

Fase 8 — el compositor teselante e interactivo (completada)

El kernel deja de colocar las ventanas a mano: las tesela. El motor es mirada-layout —el mismo núcleo no_std que ordena el compositor Wayland de brahman—, enlazado por path cruzando la frontera de workspace. Plan completo en FASE8.md.

  • 8a — el compositor tesela (completada). compositor.rs calcula un marco por app con el algoritmo MasterStack. El kernel centra el fotograma natural de cada app dentro de su marco; las apps no cambian una instrucción. region_x/y del manifiesto quedan vestigiales — la posición la decide el compositor.
  • 8b — teselado interactivo (completada). Alt+Espacio cicla los modos de teselado en caliente. El kernel cachea el último fotograma de cada app y recompone desde la caché: las apps estáticas sobreviven al re-teselado sin enterarse del cambio.
  • 8c — foco y enrutamiento selectivo (completada). Una ventana enfocada, con borde índigo; Alt+J / Alt+K mueven el foco entre las ventanas vivas. El teclado deja de difundir: entrega cada tecla sólo a la app enfocada.
  • 8d — manipulación de ventanas (completada). El orden de teselado se separa de la identidad de las ventanas. Alt+Enter promueve la ventana enfocada a la celda maestra; Alt+H / Alt+L la reordenan. El foco viaja con la ventana.

Fase 9 — orden-Z y ventanas flotantes (completada)

El teselado de la Fase 8 repartía la pantalla sin solapamiento. La Fase 9 suma un segundo modelo de composición —el SOLAPAMIENTO—: una ventana puede abandonar el teselado y FLOTAR sobre las demás. Verificada en QEMU (sendkey).

  • El Escritorio separa dos capas: las ventanas TESELADAS, al fondo; y las FLOTANTES, encima, apiladas en un orden-Z (flotantes, de atrás hacia adelante). Juntas son una partición de las ventanas.
  • Alt+F alterna la ventana enfocada entre teselada y flotante. Una flotante nace con un marco propio, en cascada, y al frente del orden-Z; al volver al teselado se reincorpora a la rejilla, que se recalcula.
  • Con flotantes vivas, el kernel deja de pintar ventana a ventana: RECOMPONE el escritorio entero, capa a capa de atrás hacia adelante —el solapamiento se resuelve por el orden del pintado—. Sin flotantes conserva el camino rápido de la Fase 8.
  • El foco recorre todas las ventanas; al posarse en una flotante, la alza al frente: la flotante enfocada está siempre delante.

Fase 10 — alta y baja de aplicaciones en vivo (completada)

Hasta la Fase 9 el censo de aplicaciones se fijaba en el arranque. La Fase 10 lo vuelve DINÁMICO: una app puede nacer o cerrarse con el reactor ya en marcha. Verificada en QEMU (sendkey).

  • El reactor admite NACIMIENTOS en vivo: una cola que engendrar alimenta y que el ejecutor drena al inicio de cada vuelta, adoptando cada futuro como tarea. El censo de tareas deja de ser inmutable tras el arranque.
  • Alt+Q cierra la app enfocada: una baja LIMPIA. El compositor saca la ventana del teselado y del orden-Z; la app, al advertir la baja, concluye su tarea y AplicacionWasm::drop libera su memoria, su combustible y su canal.
  • Alt+N lanza una app nueva: nacer_ventana la añade y entrega su índice; el orquestador instancia el WASM y engendra su tarea. Las apps de génesis dejan su bytecode cacheado como plantilla; cada Alt+N instancia una en rotación.
  • El censo de ventanas sólo crece —los índices son la identidad, jamás se reciclan—; una ventana cerrada queda como ranura inerte, fuera del teselado.

Líneas abiertas posteriores: más capacidades del host (temporización, audio); reciclado de las ranuras de ventana cerradas.

Principios que persisten entre fases

  • Reutilizar infraestructura madura de la comunidad antes que reinventar.
  • unsafe mínimo, confinado y justificado.
  • Verificar cada fase en QEMU antes de cerrarla.
  • git commit + git push tras cada iteración.