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>
23 KiB
Registro de cambios — renaser
Registro técnico detallado, fase a fase, en orden cronológico. Formato
inspirado en Keep a Changelog. Para la crónica en lenguaje llano, ver
DIARIO.md; para el estado y los planes, ROADMAP.md.
Fase 1 — El primer microsegundo — 2026-05-21
Infraestructura
- Espacio de trabajo Cargo,
kernel/Cargo.toml,.cargo/config.toml,rust-toolchain.toml. - Target inicial: especificación JSON propia
x86_64-renaser.json— PIC, soft-float, sin SSE, enlazadorlld.
Añadido
kernel/src/main.rs: punto de entrada con el macroentry_point!debootloader_api0.11.- Adopción y verificación con seguridad de tipos del framebuffer GOP (ancho, alto, formato de píxel, stride).
- Lienzo intermedio estático de 8 MiB en
.bss, alineado a página: la técnica de doble búfer para evitar parpadeos. #[panic_handler]que dibuja una franja roja directamente sobre el framebuffer mediante escrituras volátiles.- Dependencias:
bootloader_api0.11,x86_640.15,embedded-graphics0.8.
Notas
- Corrección clave:
bootloader(constructor de imagen, lado anfitrión) no esbootloader_api(la APIno_stdque consume el kernel).
Fase 1.5 — Empaquetado y arranque — 2026-05-21
Cambiado
- Migración del target del kernel: de la JSON propia
x86_64-renaser.jsonal target nativo precompiladox86_64-unknown-none. Eliminabuild-stdy la burocracia de compilador asociada.
Añadido
- Miembro
boot/: orquestador de anfitrión. Dependencia de artefacto (RFC 3028) sobre el kernel; construcción de la imagen de disco UEFI conbootloader::UefiBoot; lanzador de QEMU.
Toolchain
- Instalación de la toolchain nightly (la máquina solo tenía la estable).
Corregido
- Los nightly recientes exigen
-Zjson-target-specpara usar specs JSON (resuelto al migrar al target nativo). - Sintaxis del acelerador de QEMU:
-machine q35,accel=kvm:tcg.
Verificado
- Arranque en QEMU: superficie índigo limpia a 1280×800.
- Baliza de pánico (franja roja) confirmada inyectando un pánico de prueba.
Fase 2.0 — Cimientos del manejo de fallos — 2026-05-21
Añadido
kernel/src/gdt.rs: GDT propia, TSS y un stack de emergencia (IST) reservado para el manejador de doble fallo.kernel/src/interrupts.rs: IDT con manejadores de excepción de CPU. El breakpoint (#BP) es recuperable; #UD, #DE, #GP, #PF y #DF son fatales y encienden la baliza.#![feature(abi_x86_interrupt)].
Corregido
- La GDT debe recargar los registros SS/DS/ES con un segmento de datos del
kernel: el cargador deja
SS = 0x10, valor que en la GDT nueva pasa a ser el descriptor del TSS; el primeriretqde una rutina de excepción provocaba un #GP. Diagnosticado con la traza-d intde QEMU.
Verificado
- Excepción
int3atrapada y superada; línea-latido teal dibujada como prueba.
Fase 2.1 — Interrupciones de hardware — 2026-05-21
Añadido
kernel/src/pic.rs: remapeo del par 8259 (PIC) fuera del rango de las excepciones (vectores 0x20+); programación del temporizador PIT a 100 Hz; IRQ1 de teclado.- Bucle de render en
kernel_main, despertado por el temporizador, en sustitución delhltestático.
Verificado
- La línea-latido se anima (temporizador en marcha); las pulsaciones de teclado inyectadas cambian el cuadro-eco (teclado en marcha).
Fase 3 — Memoria dinámica y reactor asíncrono — 2026-05-21
Añadido
kernel/src/memory/:linked_list_allocatorcomo#[global_allocator]sobre una región estática en.bss.#[alloc_error_handler]: franja naranja de agotamiento de memoria.#![feature(alloc_error_handler)].kernel/src/async_system/: reactor cooperativo —Executor,Task/TaskId,Waker(víaalloc::task::Wake) yScancodeStream.kernel/src/texto.rs: rasterización de tipografía vectorial confontdue; TTF Adwaita Mono empotrada coninclude_bytes!.- Dependencias:
linked_list_allocator0.10,spin0.9,crossbeam-queue0.3,futures-util0.3,fontdue0.9.
Cambiado
- Heap ampliado de 16 MiB a 64 MiB:
fontdue, al analizar una tipografía real, agotaba los 16 MiB iniciales. El#[alloc_error_handler]lo delató pintando la franja naranja — el guardarraíl funcionó en silicio real.
Corregido
- El modo
no_stddefontdueestá condicionado a su featurehashbrown; sin ella recae enstd. Se fijadefault-features = false, features = ["hashbrown"].
Verificado
- Rótulo de bienvenida rasterizado al arranque; el texto tecleado aparece en vivo.
Fase 4 — El escudo de aislamiento WASM — 2026-05-21
Añadido
kernel/src/wasm/: intérpretewasmi1.0.9 en modono_std.env.rsdefine la matriz de capacidades — exactamente dos funciones de host:sys_render_frame(ptr, len), con validación infranqueable de los límites de la memoria lineal, ysys_get_scancode().apps/hello_wasm/: primera aplicación del userspace — módulowasm32-unknown-unknown(cdylib), un cuadrado móvil dirigido por teclado. Se empotra en el kernel coninclude_bytes!.- Dependencia:
wasmi1.0.
Cambiado
- El kernel se EXCLUYE del espacio de trabajo (
exclude = ["kernel", "apps"]): al añadirwasmi,cargo buildintentaba compilar el kernel para el anfitrión y fallaba por un símbolo_startduplicado. El kernel pasa a construirse únicamente como dependencia de artefacto deboot.
Corregido
wasmino_stdnecesitadefault-features = false, features = ["hash-collections"].wasmi1.0.9 usaLinker::instantiate_and_start(no existeinstantiate).
Verificado
- La aplicación WASM pinta su propia superficie y responde a las pulsaciones de teclado inyectadas, sin más vía hacia el kernel que las dos capacidades.
Mantenimiento — Estructura, documentación e integración — 2026-05-21
Cambiado
- Refactorización:
main.rsdividido de 692 a ~155 líneas. Se extraen los módulossync.rs,grafico.rs,consola.rsybaliza.rs. Sin cambios de comportamiento (verificado en QEMU).
Añadido
- Documentación:
CLAUDE.md,README.md,ARCHITECTURE.md,ROADMAP.md,CHANGELOG.mdyDIARIO.md. - Integración con git: repositorio inicializado, remoto
originen Gitea,.gitignore.
Seguridad
renaser.txt—un borrador de trabajo que contenía una credencial— se subió por error en el commit inicial. Se purgó de todo el historial congit filter-branchy se reescribió el remoto conpush --force. La credencial expuesta debe rotarse.
Fase 5 — Multitarea cooperativa, guardarrail de fuel y reloj — 2026-05-22
Unificación de la Fase 3 (reactor) y la Fase 4 (WASM): el userspace deja de ser una sola app que monopoliza la CPU y pasa a ser un conjunto de aplicaciones cooperativas, aisladas también en el TIEMPO.
Añadido
kernel/src/async_system/reloj.rs: convierte la IRQ0 (PIT, 100 Hz) en una primitiva asíncrona.CONTADOR_PULSOS(AtomicU64) yEsperaFrame, unFutureque se resuelve en el siguiente pulso — la unidad de cesión cooperativa del userspace. Censo de wakers trasMutex, drenado por la IRQ0.kernel/src/wasm: ABI de fotograma.AplicacionWasm—instancia PERSISTENTE entre fotogramas (Store+TypedFunc<(), ()>+ región)— sustituye alwasm::ejecutarde fuego-y-olvido. El módulo del userspace exporta ahorainit()(una vez) ytick()(un fotograma, y retorna).- Escudo de combustible:
EngineconConfig::consume_fuel(true)yCompilationMode::Eager(elfuelmide solo ejecución). Presupuesto recargado antes de cadatick—FUEL_ARRANQUE(20 M) yFUEL_FOTOGRAMA(2 M). kernel/src/wasm/env.rs: capacidadsys_render_framecon regiones de dibujo — cada fotograma se compone desplazado por el(offset_x, offset_y)de la app; un tamaño ajeno a la región se rechaza. Canal de teclado por aplicación: la IRQ1 difunde cada scancode a TODOS los canales, de modo que varias apps reciben la entrada en paralelo sin robársela.kernel/src/grafico.rs:RegionPantallayColor::DESALOJO(púrpura).apps/discola/: aplicación WASM construida para portarse mal — sutickes un bucle cerrado. Demuestra el guardarrail de fuel en vivo.
Cambiado
apps/hello_wasm: migrada al ABIinit/tick; su lienzo se dimensiona a la región (480×560). El estado del cuadrado persiste en su memoria lineal.interrupts.rs: la IRQ0 avanza elreloj; la IRQ1 difunde a los canales.consola.rs:volcar_marcocompone en una sub-región;pintar_desalojotatúa la baliza púrpura.- Contención de fallos: el subsistema WASM ya no usa
.expect(). Toda falla —carga, instanciación, desbordamiento, agotamiento de fuel— se devuelve comoResult; la tarea desaloja la app (baliza púrpura) y el kernel sigue vivo.
Verificado
- QEMU: tres apps concurrentes. Dos instancias de
hello_wasm(mismo bytecode, regiones izquierda y derecha) renderizan y responden a W/A/S/D en paralelo, con movimiento idéntico. La app díscola es desalojada en su primer fotograma por agotamiento de combustible: su región queda púrpura y el sistema —kernel y apps vecinas— no sufre un solo sobresalto.
Fase 6.0 — Cuotas de memoria y ciclo de vida del userspace — 2026-05-22
El aislamiento de las aplicaciones, que la Fase 5 hizo temporal (combustible), se completa ahora en la dimensión espacial (memoria) y se cierra la fuga de recursos del ciclo de vida.
Añadido
- Techo de memoria lineal por aplicación:
4 MiB.wasm/mod.rsconstruye unStoreLimits(StoreLimitsBuilder::memory_size+trap_on_grow_failure) y lo liga alStoreconStore::limiter. Unmemory.growque rebase la cuota se convierte en trampa; el kernel la captura y desaloja la app. FallaApp::SinMemoriayColor::DESALOJO_MEMORIA(amarillo pálido). El desalojo distingue la causa por color: púrpura (tiempo/aborto), amarillo (memoria). La clasificación es robusta —Error::as_trap_code()da un código público y unívoco:TrapCode::GrowthOperationLimited.DropparaAplicacionWasm: al morir una app desalojada, su canal de teclado se da de baja del censo de difusión de la IRQ1 — cierra la fuga señalada en la Fase 5.async_system::tecladose reorganiza encrear_canal/registrar_canal/cerrar_canal; el canal se inscribe al FINAL de la carga, de modo que una carga fallida no deja canales huérfanos.apps/glotona/: aplicación WASM construida para devorar memoria — sutickinvocamemory.growsin freno. Demuestra el guardarrail espacial en vivo.
Verificado
- QEMU: cuatro apps concurrentes. Las dos
hello_wasmrenderizan y responden al teclado en paralelo; la app díscola es desalojada por combustible (franja púrpura) y la app glotona por cuota de memoria (franja amarilla), ambas en su primer fotograma, sin que el kernel ni las apps honradas se inmuten.
Fase 6.1a — Sonda PCI y disco de pruebas — 2026-05-22
Primer paso de la estrategia incremental hacia el almacenamiento: derribar el muro del descubrimiento de hardware antes de diseñar nada encima.
Añadido
kernel/src/drivers/: nuevo subsistema de drivers.pci.rsenumera el bus PCI por fuerza bruta mediante el mecanismo de configuración #1 —puertos de E/S0xCF8(dirección) y0xCFC(datos)—; recorre buses y dispositivos leyendo el Vendor/Device ID, y localiza el disco virtio-blk (vendor0x1AF4, device0x1001/0x1042), devolviendo su ubicación y sus seis BARs.kernel_main: tras fundar la consola, sondea el bus PCI y deja constancia visual del hallazgo.
Cambiado
boot/src/main.rs: forja un disco de pruebastarget/disk.img(fichero disperso de 32 MiB; se respeta si ya existe) y lo adjunta a QEMU comovirtio-blk-pci. Corrección de plataforma: la máquinaq35es x86_64 y exige la transmisión PCI;virtio-blk-device(su gemelo MMIO) es de ARM.
Verificado
- QEMU: el kernel enumera el bus y reporta en pantalla
virtio-blk en bus 0 dev 3 :: BAR0 E/S 0x6000— un dispositivo virtio-blk transicional (device0x1001), con su BAR0 en espacio de E/S. El muro del descubrimiento PCI queda derribado; las cuatro apps del userspace siguen operando sin alteración.
Fase 6.1b — HAL, DMA y lectura del sector 0 — 2026-05-22
Segundo paso del sustrato de almacenamiento: el diálogo real con el disco. El kernel monta el dispositivo virtio-blk y lee su primer sector por DMA.
Añadido
- Dependencia
virtio-drivers1.13 (no_std,default-features = false, featurealloc). kernel/src/drivers/disco.rs:- Asignador de marcos «bump» — reparte páginas físicas de 4 KiB para el DMA, tomadas de la mayor región de RAM libre que el cargador reporta. No libera: suficiente para una sonda (la gestión fina llegará con el grafo).
KernelHal— implementa eltrait Haldevirtio-drivers.dma_allocentrega marcos físicos a cero;mmio_phys_to_virttraduce los BARs (el cargador mapea ≥ 4 GiB de memoria física, que cubre todo MMIO de PCI);share/unshareusan un buffer rebote para que cualquier región del kernel pueda viajar al dispositivo.montar_y_leer_sector0— enumera el bus, habilita E/S + memoria + bus-master, monta elPciTransporty elVirtIOBlk, y lee el sector 0 por sondeo del used ring (sin depender aún de interrupciones).
kernel/src/drivers/pci.rs: reescrito comoCamPuertos, la implementación deConfigurationAccessdevirtio-driverssobre los puertos0xCF8/0xCFC.kernel_maincapturaphysical_memory_offsety la región de RAM deBootInfo, funda el subsistema de disco y reporta el resultado de la sonda.
Cambiado
boot/src/main.rs: al forjar el disco de pruebas graba una firma (renaser-6.1b) en su sector 0 — el testigo del viaje de ida y vuelta.
Verificado
- QEMU: el kernel reporta
virtio-blk :: bus 0 dev 3 :: 65536 sectores :: s0=renaser-6.1b. La firma grabada por el anfitrión se lee de vuelta intacta: descubrimiento PCI, transporte, DMA y transferencia funcionan de punta a punta. Las cuatro apps del userspace siguen operando sin alteración.
Fase 6.1c — El grafo de objetos direccionado por contenido — 2026-05-22
Tercer y último paso del sustrato de almacenamiento. El disco deja de ser un dispositivo que se sondea y pasa a ser una MEMORIA QUE PERDURA: un grafo dirigido acíclico de objetos direccionados por contenido — no un sistema de archivos plano POSIX.
Añadido
kernel/src/almacen.rs— el grafo de objetos:- Objeto — una carga útil de bytes (
datos) y una lista de aristas (hijos: hashes de otros objetos). Las aristas hacen del almacén un DAG. - Direccionamiento por contenido — la identidad de un objeto es el hash BLAKE3 de su forma serializada. De ello se siguen dos propiedades que un sistema de archivos jamás regala: INTEGRIDAD (el contenido leído se rehashea y se verifica contra el hash pedido) y DEDUPLICACIÓN (contenido idéntico produce el mismo hash; se almacena una sola vez).
- Disco como log — el sector 0 es el superbloque (magia
RENASGRF, versión, cursor del log y hash de la raíz); tras él se anexan los registros de objetos,[longitud u32 LE][payload postcard][relleno a cero]. Un índice en memoria (hash -> sector) se reconstruye al arrancar recorriendo el log de cabo a rabo. - API:
init—monta el disco, lee o forja el superbloque, reconstruye el índice—,almacenar,recuperar,raizyfijar_raiz.
- Objeto — una carga útil de bytes (
- Cinco capacidades nuevas del host en
wasm/env.rs—sys_object_put,sys_object_datos,sys_object_hijo,sys_object_raizysys_object_fijar_raiz—, con la misma validación infranqueable de límites de la memoria lineal quesys_render_frame. Distinguen dos clases de fallo: un puntero inválido ABORTA la app —es su culpa, se traduce en trampa—; un fallo del almacenamiento le devuelve un código de error negativo —no lo es—. apps/cronista/— la primera aplicación del userspace que escribe en el almacenamiento PERSISTENTE. En cada arranque consulta la raíz del grafo, graba un objeto nuevo —datos: el número de arranque;hijos: la raíz anterior, el eslabón del DAG— y lo corona como raíz. Pinta una celda por arranque registrado y un testigo de integridad que recorre la cadena entera.- Dependencias:
serde1 ypostcard1 (serialización binaria compacta, el formato que viaja al disco) yblake31 (la función hash). Las tresno_std.
Cambiado
kernel/src/drivers/disco.rsreescrito para un sustrato PERMANENTE:- El asignador de marcos «bump» de la Fase 6.1b cede el paso a uno de MAPA DE
BITS con liberación real.
dma_deallocyunsharedevuelven los marcos a la arena: un almacén vivo, con su trasiego incesante de DMA, ya no la agota. - El
VirtIOBlkdeja de montarse y destruirse en cada llamada: se monta UNA vez y queda tras unMutexglobal.leer_sectores/escribir_sectoresexponen la E/S de bloques — el disco deja de ser de solo lectura. Se retiramontar_y_leer_sector0, la sonda de un solo uso de la Fase 6.1b.
- El asignador de marcos «bump» de la Fase 6.1b cede el paso a uno de MAPA DE
BITS con liberación real.
boot/src/main.rs: el disco de pruebas pasa a ser el disco de objetos. Ya no se le graba una firma — se forja virgen, a cero, y el kernel lo formatea la primera vez que no halle el superbloque.main.rs:informar_disco(la sonda de la Fase 6.1b) se sustituye porinformar_almacen, que funda el grafo. El userspace pasa de cuatro a cinco apps; las regiones de discola y glotona se reajustan para alojar a cronista.
Notas
- blake3 forzado a escalar. El target del kernel corre sin SSE; un camino
SIMD de blake3 activado por detección en tiempo de ejecución ejecutaría
instrucciones que la CPU, sin
CR4.OSFXSR, rechazaría con un #UD. Se fija blake3 conpure+ los cuatrono_*(sse2,sse41,avx2,avx512): implementación puramente escalar, sin SIMD ni ensamblador.
Verificado
- QEMU, TRES arranques consecutivos sobre el mismo disco persistente: la app
cronista pinta 1, luego 2, luego 3 celdas — la cuenta de arranques sobrevive
a los reinicios porque vive en el grafo, en el disco, no en la RAM. El
testigo de integridad queda VERDE en los tres: el DAG entero se recorre, de
la raíz al primer eslabón, y su profundidad cuadra con la cuenta. El
superbloque en disco confirma la magia
RENASGRF, versión 1, cursor 4 y la raíz del tercer arranque; el registro del primer arranque guardadatos = 1y cero hijos. Las otras cuatro apps siguen su curso sin alteración — las doshello_wasmrenderizando, discola desalojada en púrpura, glotona en amarillo.
Fase 6.2 — E/S de disco asíncrona por interrupción — 2026-05-22
La Fase 6.1 hizo hablar al disco, pero por SONDEO: el procesador se quedaba en espera activa vigilando el used ring de virtio, incapaz de atender nada más. La 6.2 libera el planificador cooperativo — la E/S de bloques pasa a ser REACTIVA, guiada por la interrupción física del dispositivo.
Añadido
EsperaDisco(drivers/disco.rs): una transferencia de bloques expresada comoFuturenativo. Posee sus buferes DMA —BlkReq,BlkRespy los datos, en el heap para una dirección estable—; supollenvía la petición por la API NO BLOQUEANTE devirtio-drivers(read_blocks_nb/write_blocks_nb), consulta el used ring (peek_used) y, si la transferencia sigue en vuelo, inscribe el waker y cede.leer_bloques/escribir_bloqueslo construyen.- La IRQ del disco:
montardescubre la línea de IRQ legada del dispositivo (registro «Interrupt Line», offset 0x3C del espacio de configuración PCI), registra un manejador en la IDT y abre la línea en el PIC.interrupts::irq_disco→disco::atender_irqreconoce la interrupción en el dispositivo —leer su registro ISR baja la línea INTx— y despierta, vía un waker de ranura única, a la tarea que aguardaba el bloque. bloquear_en— el puente para los contextos SÍNCRONOS (el arranque, las capacidades WASM, que no pueden.await): lleva unFuturede disco hasta su final durmiendo la CPU conhlt—la despiertan la IRQ del disco o el temporizador, como red de seguridad—; jamás en espera activa con el sistema ya en marcha.pic::desenmascarar/pic::vector_irq: abrir una línea concreta del par 8259 (con su cascada, si vive en el esclavo) y mapear línea → vector de IDT.pci::linea_irq: leer el registro «Interrupt Line» de un dispositivo.tarea_sonda_disco(main.rs): una tarea del reactor que lee el sector 0 de forma asíncrona — la prueba viva de que la IRQ conduce la E/S sin detener a las aplicaciones.
Cambiado
leer_sectores/escribir_sectoresse reescriben sobre la maquinaria asíncrona (bloquear_en+EsperaDisco). Elalmaceny las capacidadessys_object_*NO cambian una línea: heredan la E/S por interrupción de forma transparente — la espera de disco deja de quemar ciclos en sondeo.- El
VirtIOBlkpide al dispositivo que emita interrupciones al completar cada petición (enable_interrupts).
Decisiones de ingeniería
- PIC, no IOAPIC. El kernel corre íntegramente sobre el par 8259 (
pic.rs) y la cratex86_64no ofrece abstracción de APIC. Las IRQ legadas de PCI de la máquinaq35se enrutan por el 8259: basta leer la línea que el firmware UEFI ya asignó y abrirla. Migrar al IOAPIC habría exigido levantar LAPIC + IOAPIC + parseo de tablas ACPI — un subsistema entero, desproporcionado para el objetivo. El resultado funcional es idéntico: E/S conducida por la interrupción física. - Las capacidades WASM no
.await-ean. El intérpretewasmiejecuta las funciones de host de forma SÍNCRONA: no hay manera de suspender un módulo a mitad de una llamada de host. Por esosys_object_*no se vuelven asíncronas; usanbloquear_en, que duerme la CPU conhlten lugar de sondear. El verdadero solapamiento E/S ↔ render lo aprovechan las TAREAS del reactor (tarea_sonda_discohoy; la carga dinámica de módulos, mañana). - Una IRQ legada de PCI es de NIVEL: el manejador reconoce primero al dispositivo —lo que baja su línea— y sólo después cierra el EOI del PIC; el orden inverso reavivaría la interrupción en bucle.
- Todo acceso al disco toma su
Mutexcon las interrupciones desactivadas (without_interrupts): la IRQ del disco jamás encuentra el cerrojo ocupado, lo que hace imposible el interbloqueo por interrupción.
Verificado
- QEMU: el disco virtio-blk se enruta a la IRQ 11. La
tarea_sonda_discoreporta «sonda asíncrona OK -- 2 IRQ de disco atendidas»: la interrupción del disco dispara de verdad. La app cronista, sobre el disco persistente heredado de la Fase 6.1c, continúa la cuenta de arranques (3 → 4 → 5 celdas) con el testigo de integridad del DAG en verde — la nueva E/S asíncrona lee y escribe el grafo sin un solo fallo. Las cuatro apps WASM siguen su curso, sin un sobresalto ni un micro-congelamiento.