6a29152feb
Las ventanas eran anónimas: el escritorio no sabía nombrar lo que mostraba. Esta fase le pone un nombre a cada cuarto y una barra al pie con la lista de quienes lo habitan. - Cada `Ventana` lleva un `nombre: String` —del manifiesto, o del orquestador al engendrarla en vivo—. `Plantilla` lo guarda para las copias que `Alt+N` instancia. - Franja `FRANJA_TASKBAR=40px` reservada al pie. `area_apps` la descuenta — las ventanas teselan y flotan sin tapar la barra. - `consola`: tipos `Taskbar` / `CeldaTaskbar` + métodos `pintar_taskbar` y `pintar_etiqueta` (rasteriza una cadena en (x, base_y) sobre un fondo conocido, sin tocar la pluma). La pestaña enfocada se pinta con el índigo del foco, las desalojadas con su color de baliza, el resto con el slate del panel. - `compositor::recomponer` arma las celdas y las pasa junto a las capas a la consola; un único repintado, una única presentación. - `atender_raton`: si el clic cae en la franja de la barra, `celda_taskbar_en` localiza la pestaña pulsada y la enfoca (sin iniciar arrastre). Verificado en QEMU: al arrancar, la barra al pie muestra las 7 pestañas con sus nombres; `tonada` enfocada en índigo, `discola` y `glotona` en sus colores de baliza. Un clic sobre `pulso` traslada el foco al instante — el borde del compositor envuelve `pulso` y su pestaña se ilumina. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
267 lines
15 KiB
Markdown
267 lines
15 KiB
Markdown
# 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 disco** — `montar` 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.
|
||
|
||
## Fase 11 — el reloj del sistema como capacidad de host (completada)
|
||
|
||
Hasta la Fase 10 una aplicación sólo sabía cuántas veces la habían llamado, no
|
||
cuánto tiempo había pasado. La Fase 11 le da al userspace un sentido del
|
||
tiempo. Verificada en QEMU (`sendkey`).
|
||
|
||
- Capacidad `sys_tiempo_mono`: los milisegundos monótonos desde el arranque —la
|
||
décima función del host—. El temporizador (PIT) ya late a 100 Hz; `reloj`
|
||
expone esa cuenta y `env` la inyecta. Lectura pura, jamás retrocede.
|
||
- App nueva `pulso`: un compás visual cuya escena es una función PURA del reloj
|
||
del host. Dos instancias, nazcan cuando nazcan, laten al unísono — la prueba
|
||
de que el tiempo es absoluto, no una cuenta de fotogramas.
|
||
- El userspace de génesis crece de 5 a 6 apps.
|
||
|
||
## Fase 12 — la bocina del PC como capacidad de host (completada)
|
||
|
||
La Fase 11 le dio al userspace un reloj; la Fase 12, una voz. La bocina del PC
|
||
se suma a la matriz de capacidades. Verificada en QEMU.
|
||
|
||
- Driver `drivers/altavoz`: el canal 2 del PIT como generador de onda cuadrada
|
||
+ la compuerta del puerto 0x61. El canal 0 (latido del kernel) no se toca.
|
||
- Capacidad `sys_tono(frecuencia_hz)` —la undécima—. La bocina es un recurso
|
||
único: pertenece a la ventana ENFOCADA, como el teclado desde la Fase 8c. Al
|
||
cambiar el foco, el compositor la calla.
|
||
- App nueva `tonada`: toca una escala de Do mayor y la dibuja como una
|
||
escalera de barras. Junta el reloj (`sys_tiempo_mono`) y la bocina
|
||
(`sys_tono`). El userspace de génesis crece de 6 a 7 apps.
|
||
- Verificado por captura: la onda cuadrada de la bocina, enrutada a un WAV,
|
||
late a la frecuencia media de la escala.
|
||
|
||
## Fase 13 — ratón, puntero y arrastre de flotantes (completada)
|
||
|
||
Hasta la Fase 12 renaser dialogaba sólo con el teclado; las ventanas flotantes
|
||
nacían en cascada y allí se quedaban. La Fase 13 trae el ratón: un puntero,
|
||
clic-para-enfocar y arrastre del marco de las flotantes. Verificada en QEMU
|
||
(`mouse_move` / `mouse_button` del monitor).
|
||
|
||
- Driver `drivers/raton`: el ratón PS/2 cuelga del dispositivo auxiliar del
|
||
8042 + la IRQ12. El driver despierta el aux, programa su IRQ, le ordena
|
||
reportar, ensambla paquetes de 3 bytes con guarda del bit-3.
|
||
- El puntero como capa de presentación: `Pantalla::estampar_puntero` pinta un
|
||
sprite de flecha de 12×18 sobre el framebuffer, DESPUÉS de copiar el
|
||
lienzo. El lienzo nunca lo contiene — hace de save-under natural—.
|
||
- El compositor gana `atender_raton`: botón bajando → clic-para-enfocar (sobre
|
||
cualquier ventana viva); si la enfocada flota, arranca un ARRASTRE con el
|
||
desfase de agarre; el botón sostenido la sigue al puntero; al soltar, fin.
|
||
|
||
## Fase 14 — la identidad del escritorio: nombres y barra de tareas (completada)
|
||
|
||
Las ventanas eran anónimas; el escritorio no sabía nombrar lo que mostraba. La
|
||
Fase 14 le pone un nombre a cada cuarto y una barra al pie con la lista de
|
||
quienes lo habitan. Verificada en QEMU.
|
||
|
||
- Cada `Ventana` lleva un `nombre: String` —el del manifiesto, o el del
|
||
orquestador al engendrarla en vivo—. `Plantilla` lo guarda para las copias.
|
||
- Una franja de 40 px al pie reservada como `area_taskbar`. `area_apps` la
|
||
descuenta — las ventanas teselan y flotan sin tapar la barra ni la consola.
|
||
- `consola` gana los tipos `Taskbar` / `CeldaTaskbar` y los métodos
|
||
`pintar_taskbar` y `pintar_etiqueta`. La pestaña enfocada lleva el índigo del
|
||
foco; la desalojada, su color de baliza; el resto, el slate.
|
||
- Un clic dentro de la barra enfoca la ventana de la pestaña pulsada, sin
|
||
iniciar arrastre. El compositor encuentra la celda con `celda_taskbar_en`.
|
||
|
||
## Mejora estructural — mapeador MMIO en el kernel (entre fases 13 y 14)
|
||
|
||
Los BAR prefetchables 64-bit que OVMF aloja en la ventana PCI de 64 bits NO
|
||
los mapea `bootloader_api`. El kernel gana `memory::mmio`, que envuelve la
|
||
tabla L4 activa y abre páginas hacia las regiones MMIO que virtio-drivers le
|
||
pide. `KernelHal::mmio_phys_to_virt` llama al mapeador antes de devolver el
|
||
puntero. Trata `PageAlreadyMapped` y `ParentEntryHugePage` como éxito
|
||
silencioso. Los marcos para tablas intermedias salen del banco DMA. Esta
|
||
mejora resolvió el #PF inexplicable en máquinas con un OVMF que coloca el BAR
|
||
del virtio-blk fuera de los primeros 4 GiB.
|
||
|
||
Líneas abiertas posteriores: reciclado de las ranuras de ventana cerradas;
|
||
audio con varias voces (PCM) más allá del tono único de la bocina.
|
||
|
||
## 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.
|