# 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<Box<dyn Future>>`) 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`.
