# renaser — Arquitectura Este documento describe la arquitectura del kernel `renaser` subsistema a subsistema. Para el estado por fases, ver `ROADMAP.md`. ## 1. Filosofía renaser es un **SASOS** — *Single Address Space Operating System*. No hay un espacio de direcciones por proceso ni cambios de contexto de hardware: todo el sistema —kernel y aplicaciones— comparte una única RAM plana. El aislamiento NO lo da la MMU ni los anillos de privilegio de la CPU. Lo da el **software**: las aplicaciones se distribuyen como bytecode WebAssembly y se ejecutan dentro de un intérprete que acota matemáticamente cada acceso a memoria. Una aplicación solo puede hacer aquello para lo que el kernel le haya inyectado una *capacidad* (una función de host). Lo que no está importado no tiene camino físico que recorrer. La interfaz es **visual desde el primer microsegundo**. No hay TTY; el texto se rasteriza como gráfico vectorial. "El texto es un caso particular del dibujo." ## 2. La cadena de arranque ``` Firmware UEFI → crate `bootloader` 0.11 → kernel::_start → kernel_main ``` El miembro `boot/` (que corre en el **anfitrión**) toma el ELF del kernel, lo fusiona con el cargador `bootloader` 0.11 en una imagen de disco UEFI GPT y la lanza en QEMU con el firmware OVMF. El cargador deja la CPU en modo largo de 64 bits, mapea el kernel y le entrega una `BootInfo` con el framebuffer GOP. ## 3. Estructura del espacio de trabajo El workspace tiene **un solo miembro**, `boot`. El `kernel` y las `apps` están **excluidos** a propósito: - El kernel es `#![no_std] #![no_main]` y define su propio `_start`. Si fuese miembro del workspace, `cargo build` intentaría compilarlo para el anfitrión y fallaría por un símbolo `_start` duplicado con el `crt0` del sistema. - Por eso el kernel se construye **solo** como *dependencia de artefacto* (RFC 3028) de `boot`, que le fija el target `x86_64-unknown-none`. - Las apps WASM tienen su propio target (`wasm32-unknown-unknown`) y se compilan aparte. El kernel usa el target **nativo precompilado** `x86_64-unknown-none`: sin target JSON propio, sin `build-std`. Soft-float y sin SSE, para que las interrupciones no corrompan registros de punto flotante. ## 4. Subsistemas del kernel ### `grafico` — el sustrato visual `Color` (RGB de 24 bits, independiente del hardware), `Pantalla` (el framebuffer GOP físico, envuelto en seguridad) y `Lienzo` (el búfer intermedio en RAM). Toda composición ocurre en el `Lienzo`; `Pantalla::presentar` lo vuelca de un solo gesto con escrituras volátiles — **doble búfer**, sin desgarros. `codificar` traduce un `Color` al formato nativo del framebuffer. ### `consola` — la superficie de texto e imagen Une `Lienzo` + `Pantalla` + una pluma de escritura. Rasteriza glifos con `fontdue` y los funde sobre el lienzo mezclando por cobertura (anti-aliasing). También vuelca fotogramas crudos del userspace WASM. Es global, tras un `Mutex`. ### `baliza` — la red de seguridad visual Publica de forma atómica y sin cerrojos los datos mínimos del framebuffer. Los manejadores `#[panic_handler]` y `#[alloc_error_handler]` los usan para pintar una franja de advertencia —**roja** si el sistema colapsa, **naranja** si el heap se agota— escribiendo directo sobre el silicio, sin confiar en el heap ni en estructura dinámica alguna. ### `gdt` — cimientos del manejo de fallos GDT propia con segmentos de código y datos del kernel, y un TSS cuyo único cometido es alojar un **stack de emergencia** (IST) para el doble fallo: ni un desbordamiento de la pila del kernel impide su diagnóstico. ### `interrupts` — la tabla de reflejos IDT con manejadores de excepción de CPU (breakpoint recuperable; el resto, fatales → `panic!`) e interrupciones de hardware. El doble fallo se atiende sobre el stack de emergencia del TSS. ### `pic` — el latido del hardware Remapea el par 8259 (PIC) fuera del rango de las excepciones de CPU y programa el temporizador de intervalos (PIT). El teclado (IRQ1) deposita scancodes en una cola lock-free. `desenmascarar` abre una línea de IRQ concreta —la del disco, descubierta en tiempo de ejecución (Fase 6.2)—. ### `drivers` — el hardware que el kernel conquista (Fases 6.1, 6.2) A diferencia del framebuffer o el temporizador —que el firmware sirve en bandeja—, el disco hay que DESCUBRIRLO y reclamarlo. - `pci` — `CamPuertos`: acceso al espacio de configuración del bus PCI por el mecanismo #1 (puertos `0xCF8`/`0xCFC`); `linea_irq` lee la IRQ del dispositivo. - `disco` — el disco virtio-blk. Un asignador de marcos por **mapa de bits** —con liberación real— reparte páginas físicas para el DMA; `KernelHal` implementa el `trait Hal` de `virtio-drivers` (traducción de direcciones, memoria rebote para el DMA); el `VirtIOBlk` se monta una vez y persiste tras un `Mutex`. La E/S de bloques es **asíncrona** (Fase 6.2): `EsperaDisco` es un `Future` que envía la petición por la API no bloqueante de `virtio-drivers`, cede la CPU y se reanuda con la IRQ del disco (`atender_irq`). `bloquear_en` conduce ese `Future` desde los contextos síncronos durmiendo la CPU con `hlt`; sobre él, `leer_sectores`/`escribir_sectores` sirven al grafo de objetos. La IRQ del disco se enruta por el PIC 8259, no por el IOAPIC. ### `almacen` — el grafo de objetos direccionado por contenido (Fase 6.1c) renaser no tiene un sistema de archivos plano POSIX: tiene un DAG de objetos. Un `Objeto` es una carga útil de bytes y una lista de aristas (hashes de hijos). La identidad de un objeto es el hash BLAKE3 de su forma serializada (`postcard`) — de ahí integridad (un objeto se verifica al leerlo) y deduplicación (contenido idéntico, un solo registro). El disco es un **log**: el sector 0 es el superbloque (magia, versión, cursor, raíz); tras él se anexan los registros de objetos. Un índice hash→sector se reconstruye al arrancar recorriendo el log. Las capacidades `sys_object_*` exponen el grafo al userspace. ### `memory` — el heap dinámico `linked_list_allocator` como `#[global_allocator]` sobre una región estática de 64 MiB en `.bss`. Desbloquea `alloc::*` — `Box`, `Vec`, `BTreeMap`, `Arc`. ### `async_system` — el reactor cooperativo - `task` — `Task`: un `Future` anclado (`Pin>`) con `TaskId`. - `executor` — el `Executor`: censo de tareas, cola de listas, y un `hlt` controlado cuando no hay trabajo. - `waker` — un `Waker` que reinyecta el `TaskId` en la cola al despertar. - `teclado` — los canales de scancodes. Cada app abre el suyo; la IRQ1 **difunde** cada scancode a todos, de modo que varias apps reciben la entrada en paralelo. - `reloj` — convierte la IRQ0 (PIT, 100 Hz) en el `Future` `EsperaFrame`, que se resuelve en el siguiente pulso. Es el **compás de los fotogramas**: una tarea WASM hace su trabajo de un fotograma y `.await`-ea el siguiente. Las interrupciones de hardware no conmutan el contexto de la CPU: **despiertan tareas**. El kernel avanza cooperativamente. ### `texto` — tipografía vectorial Empotra un `.ttf` en el binario (`include_bytes!`) y lo rasteriza con `fontdue` glifo a glifo, bajo demanda. ### `wasm` — el escudo de aislamiento - `mod` — el runtime y la `AplicacionWasm`: una instancia **persistente** entre fotogramas (`Store` + `TypedFunc<(), ()>` + región). El ABI del userspace es `init()` (una vez) y `tick()` (un fotograma, y retorna). Dos guardarraíles acotan a cada app: el **temporal** —un presupuesto de **combustible** (`fuel`) por `tick`; agotarlo la desaloja (baliza púrpura)— y el **espacial** —un techo de memoria lineal vía `Store::limiter`; rebasarlo la desaloja (baliza amarilla)—. En ambos casos `wasmi` lanza una trampa, el kernel recupera el mando y el sistema no sufre. El `Drop` de `AplicacionWasm` reconcilia el ciclo de vida: da de baja su canal de teclado. - `env` — la **matriz de capacidades**: las funciones de host que el módulo WASM puede invocar. Hoy son siete: - `sys_render_frame(ptr, len)` — compone un fotograma dentro de la **región** de pantalla asignada a la app. El kernel valida **matemáticamente** que `[ptr, ptr+len)` cae dentro de la memoria lineal del módulo, y que el tamaño es el de la región, antes de leer un byte; si no, aborta la app. - `sys_get_scancode()` — entrega, sin bloquear, el siguiente scancode del canal de teclado **propio** de la app. - `sys_object_put` / `sys_object_datos` / `sys_object_hijo` / `sys_object_raiz` / `sys_object_fijar_raiz` — el acceso al grafo de objetos persistente (ver `almacen`): grabar un objeto, leer su carga útil, recorrer sus aristas, y leer o fijar la raíz del DAG. Cada puntero que la app entrega se valida contra su memoria lineal, igual que en `sys_render_frame`. Todo puntero inválido aborta la app —es su culpa: el `Error` se traduce en una trampa de WASM, la app se desaloja y el resto del sistema sigue—. Un fallo del almacenamiento, en cambio, no es culpa de la app: se le devuelve un código de error que ella decide cómo afrontar. ## 5. Restricciones de ingeniería - **Escrituras volátiles** obligatorias para framebuffer y MMIO. - **`unsafe`** confinado en células mínimas, cada una con un contrato `SEGURIDAD:` y envuelta en una abstracción segura. `unsafe_op_in_unsafe_fn` está en `deny`. - **Alineación**: 16 bytes para estructuras genéricas; 4096 (página) para buffers de asignador y el lienzo de respaldo. - **`no_std` estricto**: `core` + `alloc`; nada de `std`.