Files
sergio e2272c0ed3 feat: integra renaser (kernel SASOS bare-metal) al monorepo
renaser —kernel asíncrono de espacio de direcciones único, no-POSIX,
`no_std` x86_64— entra al monorepo como su PROPIO workspace de Cargo,
no fusionado: usa toolchain nightly, target `x86_64-unknown-none` y
`panic = "abort"`, incompatibles con los perfiles globales de brahman.

- `renaser/` — copia del proyecto (sin su `.git`; el repo original
  conserva su historia standalone). Workspace propio con su
  `rust-toolchain.toml` y `.cargo/`.
- `exclude = ["renaser"]` en el workspace de brahman: Cargo lo trata
  como ajeno.
- El kernel de renaser path-depende `mirada-layout` cruzando la
  frontera de workspace — primer núcleo compartido. Semilla de la
  Fase 8 (compositor): geometría de teselado compartida, framebuffer
  nativo de renaser; smithay se queda en el lado Linux.

Verificado: `cargo build -p boot` compila kernel + imagen UEFI con
mirada-layout enlazado para bare-metal.

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

9.4 KiB

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 SASOSSingle 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.

  • pciCamPuertos: 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

  • taskTask: 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.