42fee6fcbc
Tres mensajes y un EtherType propio bastan para extender el grafo de
objetos —direccionado por contenido, ya BLAKE3— a otras maquinas
renaser que escuchen en la misma red de capa-2. Sin TCP, sin IP,
sin DNS.
Crate nueva 'akasha/' (no_std compartido, gemela de 'formato',
excluida del workspace):
- MensajeAkasha enum con SolicitarObjeto(id), ProveedorObjeto(id,
payload), AnunciarRaiz(id).
- Codec: postcard (mismo que ya usa el grafo en disco).
- EtherType: 0x88B5. MAX_PAYLOAD_AKASHA = 1486 (MTU sin fragmentar).
- Helpers componer_frame(src, dst, msg) y analizar_frame(bytes) que
distinguen EtherType ajeno, frame truncado y payload basura.
- 6 pruebas unitarias en verde.
Modulo nuevo 'kernel/src/akasha.rs' con tres oficios:
1. Demuxer (drenar_y_demultiplexar): drena la cola RX del dispositivo
virtio-net y demultiplexa: frames AoE con payload valido los
procesa el respondedor; el resto va a una cola del userspace que
'sys_net_recibir' ahora lee. Frames 0x88B5 con payload
no-postcard (saludo de pregon) se cuentan y tambien viajan al
userspace.
2. Atencion de mensajes (procesar):
- SolicitarObjeto(id): consulta almacen::recuperar; si tenemos el
objeto, respondemos ProveedorObjeto unicast con objeto.serializar()
y re-hashing de defensa en profundidad.
- ProveedorObjeto(id, payload): verifica blake3(payload)==id antes
de absorber con almacen::almacenar.
- AnunciarRaiz(id): si ignoramos el nodo, le solicitamos al emisor.
3. Faro periodico (difundir_raiz cada 5 s): broadcast del hash del
manifiesto actual. Cadencia medida contra reloj::milisegundos(),
no contra los awaits — el interprete wasmi de los apps degrada
la cadencia de EsperaFrame::await a varios cientos de ms, asi
que se mide contra el reloj monotono y los oficios per-fotograma
se enganchan al tic del compositor (cuyo latido es fiable).
Contadores ResumenAkasha (rx/tx por variante, descartados, cola del
usuario) listos para un futuro indicador AoE en la barra de tareas.
Cambios complementarios:
- sys_net_recibir lee de akasha::pop_usuario, no de
drivers::red::recibir_en (que queda #[allow(dead_code)] como
primitiva del driver para diagnostico).
- tarea_red queda corta: envia un ARP al gateway y termina. El
demuxer y el faro viven en el tic del compositor.
Verificacion:
- 'cargo test -p akasha' → 6 pruebas en verde.
- QEMU headless 60 s con -object filter-dump → 14 frames: 11
AnunciarRaiz (Δ promedio 5.86 s sobre 5.00 s de target), 2 ARP
y el pregon hello. Cada AnunciarRaiz lleva el hash del manifiesto
'2f3deadfcc7dae25..' en 33 bytes postcard sobre 47 bytes de frame.
- COM1 vuelca 'akasha :: ANUNCIO emitido :: raiz=2f3deadfcc7dae25..'
en cada disparo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
409 lines
23 KiB
Markdown
409 lines
23 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.
|
||
|
||
## Fase 15 — la voz del sistema (completada)
|
||
|
||
La bocina pertenecía al app enfocado (Fase 12), pero el kernel necesita hablar
|
||
también: un acorde al arrancar, un repique al lanzar una app, un bajo al
|
||
desalojarla. Verificada en QEMU con captura PCM a WAV.
|
||
|
||
- `altavoz` gana una cola de notas (`SECUENCIA: Mutex<VecDeque<(u32,u32)>>`) y
|
||
un reloj de fin (`FIN_NOTA: AtomicU64`). `agendar(&[(frec, ms)])` encola;
|
||
`atender()` —invocada por la tarea del compositor cada fotograma— pasa a la
|
||
nota siguiente cuando la actual termina. `kernel_sonando()` gatea a los apps:
|
||
mientras el kernel habla, `sys_tono` ignora a las apps.
|
||
- Catálogo: `VOZ_BIENVENIDA` (Do-Mi-Sol), `VOZ_LANZAR` (repique ascendente),
|
||
`VOZ_CERRAR` (descendente), `VOZ_DESALOJO` (bajo grave).
|
||
- Hitos: `kernel_main` agenda el acorde antes de `ejecutor.run`. `nacer_ventana`,
|
||
`cerrar` y `desalojar` lo agendan al hacer su trabajo.
|
||
- Pestañas de la barra de tareas: tinta calculada por brillo del fondo, así la
|
||
pestaña crema del desalojo por memoria ya no lleva texto invisible.
|
||
|
||
## Fase 16 — la barra viva: lanzador y reloj (completada)
|
||
|
||
La barra de tareas era pasiva. Esta fase la activa con un botón lanzador a la
|
||
izquierda («+», equivalente táctil de `Alt+N`) y un reloj `mm:ss` a la derecha
|
||
que late cada segundo. Verificada en QEMU con dos capturas separadas en el
|
||
tiempo: el reloj avanza de `0:17` a `0:29`.
|
||
|
||
- `compositor`: layout reorganizado — lanzador a la izquierda (36 px), celdas
|
||
en el medio, reloj a la derecha (80 px). `clic_en_launcher` enruta el clic
|
||
al contador `PARTOS`; la tarea del compositor lo recoge y lanza.
|
||
- `compositor::tick_reloj()` — invocada cada fotograma; recompone sólo cuando
|
||
el segundo del reloj monótono cambia respecto al último mostrado.
|
||
- `consola::Taskbar` crece con `launcher`, `reloj` y `reloj_region`.
|
||
`pintar_taskbar` dibuja la cruz del lanzador como dos rectángulos
|
||
cruzados (sin depender de la tipografía) y rotula el reloj.
|
||
|
||
## Fase 17 — `bitacora`, el editor que recuerda (completada)
|
||
|
||
`memoriosa` (Fase 7c) demostró que un app podía persistir su huella. La Fase 17
|
||
lo lleva al gesto natural: un editor de texto. Tecleas, reinicias renaser, el
|
||
texto sigue ahí. Verificada en QEMU.
|
||
|
||
- Nuevo crate `apps/bitacora/`: lienzo 480×280, tipografía 8×8 (crate `font8x8`)
|
||
escalada x2 a 16×16, render pixel a pixel desde la memoria del propio app.
|
||
Buffer 512 bytes, wrap a 28 columnas, Enter / Backspace, persiste cada
|
||
cambio con `sys_estado_guardar`. Mapeo de scancodes US a ASCII (minúsculas).
|
||
- `GENESIS` crece de 7 a 8 apps; `bitacora` es la maestra al arrancar.
|
||
- `CELDA_TASKBAR_ANCHO` baja de 150 a 130 px para que las ocho pestañas
|
||
quepan holgadas con el lanzador y el reloj.
|
||
|
||
## Fase 18 — red: virtio-net y el primer hola al exterior (completada)
|
||
|
||
renaser hablaba solo. Esta fase abre una boca y una oreja al exterior con
|
||
virtio-net, reutilizando el `KernelHal` del disco y el mapeador MMIO. Al
|
||
arrancar, el kernel envía un ARP request al gateway de QEMU; lee la
|
||
respuesta y la registra. Verificada con captura pcap.
|
||
|
||
- Driver `drivers/red`: monta `VirtIONet<KernelHal, PciTransport, 16>`,
|
||
expone `enviar(frame)` y `drenar_rx(callback)`. Sin pila TCP/IP — solo
|
||
ethernet crudo —; la composición de paquetes se hace en el llamante.
|
||
- `componer_arp_request`: helper para construir el ARP request inicial.
|
||
- `interrupts::registrar_irq_red` + handler de IDT, gemelo del de disco.
|
||
- Tarea `tarea_red` en el reactor: envía el ARP al arrancar, drena RX en
|
||
cada fotograma y vuelca cada paquete a COM1.
|
||
- QEMU args ganan `-netdev user,id=net0 -device virtio-net-pci`.
|
||
|
||
Líneas abiertas posteriores: capacidades `sys_net_*` para que los apps
|
||
también hablen; una pila mínima ARP/IP/UDP; reciclado de las ranuras de
|
||
ventana cerradas; audio con varias voces (PCM).
|
||
|
||
## Fase 19 — voz del userspace hacia la red (completada)
|
||
|
||
La Fase 18 hizo que el kernel hablara con la red. La Fase 19 le da la
|
||
misma capacidad a los apps con tres capacidades nuevas, y estrena la
|
||
primera app que las usa.
|
||
|
||
- `drivers::red::recibir_en(buf) -> usize`: drena UN paquete por
|
||
llamada, recicla el descriptor a la cola RX. El gemelo cooperativo de
|
||
`drenar_rx`, dimensionado para el patrón que los apps usan.
|
||
- Tres capacidades `wasm/env` nuevas: `sys_net_mac` (escribe la MAC en
|
||
un buffer del módulo), `sys_net_enviar(ptr, len)` (envía un frame
|
||
Ethernet crudo) y `sys_net_recibir(salida, capacidad)` (drena un
|
||
paquete, devuelve los bytes copiados). Todas validan rango contra la
|
||
memoria lineal del módulo y devuelven códigos negativos diagnósticos.
|
||
- App `pregon` (4.2 KiB WASM): al arrancar pide su MAC, anuncia su
|
||
presencia con un broadcast Ethernet (EtherType `0x88B5`, payload
|
||
`"renaser :: hola desde mi red"`) y en cada `tick` drena un paquete y
|
||
lo muestra en su lienzo 480×160 — título, MAC, cuentas TX/RX y datos
|
||
del último frame entrante (tamaño, EtherType, src MAC).
|
||
- `tarea_red` ya no drena RX: la posesión de la cola pasa al userspace.
|
||
El kernel conserva sólo el envío del ARP de prueba al arrancar.
|
||
- `GENESIS` crece de 8 a 9 apps; `pregon` queda en posición 2 (detrás
|
||
de `bitacora`). `CELDA_TASKBAR_ANCHO` baja de 130 a 116 px para que
|
||
las nueve pestañas + lanzador + reloj caben en 1280 px.
|
||
|
||
Verificada con `-object filter-dump,...,file=/tmp/renaser.pcap`. El
|
||
pcap captura tres frames: el broadcast `0x88B5` de `pregon`, el ARP
|
||
request del kernel y el ARP reply del gateway. El primero es el del
|
||
huésped — la voz del userspace ya pasó al cable.
|
||
|
||
Líneas abiertas posteriores: una pila mínima ARP/IP/UDP para los apps;
|
||
un servidor de eco / un cliente DNS de juguete; reciclado de las
|
||
ranuras de ventana cerradas; audio con varias voces (PCM).
|
||
|
||
## Fase 20 — Akasha Over Ether: el grafo distribuido (completada)
|
||
|
||
El grafo de objetos persistentes —direccionado por contenido, ya BLAKE3—
|
||
deja de ser una propiedad LOCAL del disco y se vuelve una propiedad
|
||
DISTRIBUIDA del cable. Sin TCP, sin IP, sin DNS: tres mensajes y un
|
||
EtherType propio bastan.
|
||
|
||
- Crate `akasha/` (no_std compartido, gemela de `formato`): el
|
||
protocolo. `MensajeAkasha` con `SolicitarObjeto(id)`,
|
||
`ProveedorObjeto(id, payload)`, `AnunciarRaiz(id)`. Serializado con
|
||
`postcard`. Helpers `componer_frame` y `analizar_frame`. EtherType
|
||
experimental `0x88B5`. Seis pruebas unitarias.
|
||
- Módulo `kernel/src/akasha.rs`: el respondedor. Drena la cola RX del
|
||
dispositivo de red y **demultiplexa**: los frames AoE legítimos los
|
||
procesa en el núcleo; el resto va a una cola del userspace que
|
||
`sys_net_recibir` lee. Atiende `SolicitarObjeto` consultando
|
||
`almacen`, absorbe `ProveedorObjeto` verificando integridad, registra
|
||
`AnunciarRaiz` y, si ignoramos el nodo anunciado, le pedimos al emisor.
|
||
- Faro periódico: cada 5 s, `AnunciarRaiz` con el hash del manifiesto se
|
||
difunde por broadcast. La cadencia se mide contra el reloj monótono —
|
||
no contra los awaits—, por lo que el ritmo del faro es independiente
|
||
de cuánto trabajo del reactor consume cada vuelta.
|
||
- `tic_compositor`: el pulso fiable. Los oficios AoE se enganchan al tic
|
||
del compositor (cuyo latido cooperativo es el único garantizado bajo
|
||
carga del reactor); una tarea propia con `EsperaFrame::await` en bucle
|
||
no escalaba porque el intérprete `wasmi` de los apps degrada la
|
||
cadencia de los awaits a varios cientos de ms.
|
||
- `sys_net_recibir` lee de la cola del userspace que mantiene `akasha`,
|
||
no del driver. `drivers::red::recibir_en` queda como primitiva del
|
||
driver para futuras herramientas de diagnóstico.
|
||
|
||
Verificada con `cargo test -p akasha` (6 pruebas verdes) y con QEMU
|
||
headless + `-object filter-dump`. En 60 s de captura: 11 `AnunciarRaiz`
|
||
con Δ promedio 5.86 s, un ARP request + reply y el saludo en texto
|
||
plano de `pregon`. La casa ya tiene su propio idioma de red — y un faro
|
||
que late.
|
||
|
||
Líneas abiertas posteriores: una pila ARP/IP/UDP mínima para los apps;
|
||
un peer real en una segunda VM para ver la replicación end-to-end
|
||
`AnunciarRaiz → SolicitarObjeto → ProveedorObjeto`; un indicador AoE en
|
||
la barra de tareas que pinte los contadores de `ResumenAkasha`;
|
||
reciclado de las ranuras de ventana cerradas; audio con varias voces.
|
||
|
||
## 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.
|