El `-global pci-hole64-size=0` del commit anterior NO movía los BAR:
verifiqué con `info pci` que OVMF seguía alojando el BAR4 prefetchable
64-bit del virtio-blk en `0xc000000000` (mi Proxmox) o `0x800000000`
(la laptop del usuario). El cargador `bootloader_api` 0.11 mapea la
memoria física pero no extiende su mapeo hasta la ventana PCI de 64
bits, y `KernelHal::mmio_phys_to_virt` devolvía `phys + offset` a
ciegas — un puntero a memoria sin tabla de páginas, al primer registro
MMIO leído → #PF.
La solución: un mapeador MMIO propio del kernel.
- `memory::mmio`: envuelve la tabla L4 activa (vía CR3 + el mapeo de
memoria física del cargador) en un `OffsetPageTable`. Su función
`mapear(fisica, tam)` abre, para cada página de la región, una
entrada en la L4 con `PRESENT | WRITABLE | NO_CACHE | WRITE_THROUGH`
— las banderas habituales del MMIO.
- Los marcos para tablas intermedias salen del banco DMA del disco
(`drivers::disco::asignar_marco_para_tabla`, sin pánico). Se ponen
a cero antes de cederlos: las tablas empiezan vacías.
- Tratamos `PageAlreadyMapped` y `ParentEntryHugePage` como éxito: la
región ya estaba cubierta por el cargador (con páginas 4 KiB o
hugepages 2 MiB / 1 GiB) y el acceso ya funciona. Solo abortamos el
mapeo si se nos agota la arena DMA.
- `KernelHal::mmio_phys_to_virt` llama a `memory::mmio::mapear` antes
de devolver el puntero virtual. virtio-drivers lo invoca con la
base y el tamaño exactos de cada BAR; el kernel asegura que cada
uno sea accesible antes de devolverlo.
- `kernel_main` funda el mapeador justo después del heap (paso 4.5),
antes del disco. Necesita `physical_memory_offset` para alcanzar
la L4 activa.
Quito el `-global q35-pcihost.pci-hole64-size=0` que añadí antes: no
movía los BAR (verificado con `info pci`) y solo confundía la
descripción del fix. Esta solución es la robusta: el kernel sabe
mapear sus propios MMIOs y deja de depender del firmware.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Era la causa raíz del «pantalla negra + franja roja» en máquinas con
nightlies recientes (laptops, KVM, etc.) que mi Proxmox no exhibía:
- En modo debug, la stdlib inyecta `<usize>::unchecked_mul::precondition_check`
en cada `unchecked_mul` (RawVec::current_memory, in_place_collect…).
- El camino de pánico de ese check, en bare-metal, escribe en regiones
que el cargador no mapeó → #PF → al panic handler del kernel, que pinta
la franja roja: un colapso DENTRO de la red de seguridad del colapso.
- 1202 callsites en el binario debug — uno fallaba en la laptop del usuario.
El fix: `rustflags = ["-Cdebug-assertions=off", "-Coverflow-checks=off"]`
en `[target.x86_64-unknown-none]` de `.cargo/config.toml`. Los `[profile]`
del manifiesto no propagaban a las deps precompiladas (wasmi, virtio-
drivers, etc., que se quedan como artifact-deps fuera del workspace);
`rustflags` por target sí. Tras un `cargo clean` + rebuild, cero llamadas
a precondition_check, y el boot trace por COM1 corre completo.
También: `[profile.dev]`/`[profile.release]` del kernel y workspace
declaran los flags explícitamente, por si alguna ruta de cargo cambia.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Para localizar dónde colapsa el kernel en máquinas que no son la del
autor, cada hito de `kernel_main` deja una traza por COM1 (con el
panic-handler-a-serie de antes, ya tenemos boot trace + autopsia).
- `baliza::Serie` se hace `pub(crate)` para que cualquier módulo deje
trazas con `writeln!(baliza::Serie, ...)`.
- `kernel_main`: traza tras adoptar el framebuffer, encender la baliza,
fundar GDT/IDT/PIC, fundar el heap, fundar teclado/reloj/texto,
publicar la consola, iniciar disco y almacén, arrancar el ratón,
crear el ejecutor, cargar el userspace y arrancar el reactor. Y un
volcado de `physical_memory_offset` + `region_dma` al inicio.
- `drivers::disco::init`: registra offset, región, base de la arena y
número de marcos disponibles.
- Endurecimiento: `disco::init` ahora salta SIEMPRE la primera página
física al elegir la base de la arena DMA. Algunos cargadores la dejan
sin mapear como protección NULL; un marco DMA ahí se traduce a una
dirección que peta al desreferenciar.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
En pantalla solo cabe la franja roja: un grito breve, sin matiz. Para
diagnosticar colapsos en máquinas distintas a la del autor —donde no
es posible reproducirlos a mano—, los manejadores de fallo escriben
ahora una pista por COM1, además de pintar la franja.
- `baliza`: sumidero `Serie` que formatea sin tocar el heap, escribe a
0x3F8 con espera acotada (antes mudo que colgar el sistema).
- El panic-handler vuelca el mensaje y la ubicación del `panic!`.
- El alloc-error-handler vuelca el `Layout` que reventó el techo.
QEMU con `-serial stdio` enruta COM1 a la terminal de `cargo run` — la
pista llega a quien lanzó el kernel, aunque la pantalla esté en negro.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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.
- Driver `drivers/raton`: el ratón PS/2 cuelga del dispositivo
auxiliar del 8042 + IRQ12. El driver despierta el aux, programa
su IRQ, le ordena reportar, ensambla paquetes de 3 bytes con
guarda del bit-3. Posición como atómicos, eventos como cola
lock-free — el mismo guardarraíl que el teclado.
- El puntero, capa de PRESENTACIÓN: `Pantalla::estampar_puntero`
pinta un sprite de flecha 12×18 sobre el framebuffer después de
copiar el lienzo. El lienzo nunca lo contiene — hace de
save-under natural—.
- Compositor: `atender_raton` drena eventos. Botón bajando es un
clic-para-enfocar consistente con `mover_foco` (silencia bocina,
alza si flota). Si la enfocada flota, arranca un arrastre con el
desfase de agarre; el botón sostenido la sigue al puntero; al
soltar, termina.
- `refrescar_puntero` reestampa el framebuffer si el puntero se
movió en una vuelta tranquila en que ninguna app pintó.
Verificado en QEMU (mouse_move / mouse_button del monitor): el
puntero aparece al arrancar, se mueve por la pantalla, un clic
sobre pulso le da el foco, y un arrastre con el botón sostenido
mueve la flotante de la cascada al centro-abajo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
La Fase 11 dio al userspace un reloj; la Fase 12, una voz. Hasta hoy
renaser solo sabía dibujar para llamar la atención.
- 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. `tono(hz)` es su única vía; un 0 la silencia.
- Capacidad `sys_tono(frecuencia_hz)` — la undécima función del host.
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; la nueva dueña la reclama en su próximo fotograma.
- App nueva `tonada` (`apps/tonada/`, wasm32): 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`).
- `GENESIS` crece de 6 a 7 apps; `tonada` es la maestra del escritorio.
Verificado en QEMU. Visual: la escalera de `tonada` recorre la escala
con el tiempo. Sonido: con la bocina enrutada a un WAV, el PCM
capturado es una onda cuadrada oscilante de ~375 Hz — la frecuencia
media de la escala de Do mayor.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El userspace gana un sentido del tiempo: hasta ahora una app solo sabía
cuántas veces la habían llamado, no cuánto tiempo había pasado.
- Capacidad `sys_tiempo_mono() -> u64` — la décima función del host:
los milisegundos monótonos desde el arranque. `reloj` expone la
cuenta del PIT (100 Hz) como `milisegundos()`; `env` la inyecta.
Lectura pura, no toca la memoria del módulo, jamás retrocede.
- App nueva `pulso` (`apps/pulso/`, wasm32): un compás visual cuya
escena es una función PURA de `sys_tiempo_mono` — sin estado entre
fotogramas—. Dos instancias laten al unísono nazcan cuando nazcan.
- `GENESIS` crece de 5 a 6 apps; `pulso` es la maestra del escritorio.
Verificado en QEMU (sendkey): la barra de `pulso` avanza con el tiempo
de pared; un segundo `pulso` lanzado con Alt+N ~15 s después aparece
sincronizado con el primero — el compás se rige por el reloj absoluto,
no por una cuenta de fotogramas.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El censo de aplicaciones deja de fijarse en el arranque: una app puede
nacer o cerrarse con el reactor ya en marcha.
- El reactor admite NACIMIENTOS en vivo: cola `NACIMIENTOS` +
`engendrar()`, drenada al inicio de cada vuelta de `run()`;
`Task::adoptar` acoge un futuro ya empaquetado.
- `Alt+Q` (`Mando::Cerrar`): baja limpia. El compositor saca la
ventana enfocada del teselado y del orden-Z; la app advierte la
baja (`ventana_cerrada`) y concluye su tarea — su memoria, su
combustible y su canal de teclado se liberan. Sin baliza.
- `Alt+N` (`Mando::Lanzar`): alta en vivo. `nacer_ventana` añade la
ventana 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.
Verificado en QEMU (sendkey): tres Alt+N hacen crecer el escritorio
de 5 a 8 ventanas; tres Alt+Q lo reducen de 8 a 5. Kernel estable.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Segundo modelo de composición sobre el teselado de la Fase 8: el
SOLAPAMIENTO. Una ventana puede abandonar el teselado y FLOTAR sobre
las demás.
- `Escritorio` gana `flotantes: Vec<usize>` — la pila orden-Z, de
atrás hacia adelante; con `orden` forma una partición de las
ventanas.
- Mando `Flotar` (`Alt+F`): alterna la ventana enfocada entre
teselada y flotante; una flotante nace con marco propio en cascada,
al frente del orden-Z.
- `compositor::recomponer` + `consola::recomponer` (tipos `Capa` /
`Contenido`): con flotantes vivas el escritorio se repinta entero,
capa a capa de atrás hacia adelante — el solapamiento se resuelve
por el orden del pintado. Sin flotantes, camino rápido de la Fase 8.
- El foco recorre todas las ventanas y alza al frente la flotante
enfocada.
Verificado en QEMU (sendkey): flotar, cascada, alzado-Z y regreso al
teselado.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El escritorio se podía recorrer con el foco, pero no reordenar. La 8d lo
hace manipulable: el orden de teselado se separa de la identidad.
- Escritorio gana `orden: Vec<usize>` — una permutacion que dice que
ventana ocupa cada celda. Mover una ventana cambia su celda, no su
indice_app: conserva su canal de teclado y su ranura de estado.
- aplicar_teselado reparte los marcos segun el orden.
- Alt+Enter promueve la ventana enfocada a la celda maestra; Alt+H/Alt+L
la reordenan. mover_foco recorre ahora el orden, no los indices crudos.
Verificado en QEMU (sendkey): con memoriosa enfocada, Alt+Enter la
promueve a maestra y hola baja a la pila; Alt+L la devuelve a la pila. El
foco —el borde indigo— viaja siempre con la ventana, no con la celda.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El compositor de la 8a teselaba, pero era inmovil. Las 8b/8c lo hacen
vivo: el teclado reordena el escritorio y mueve el foco en caliente.
- Cache de fotogramas: cada ventana guarda en RAM del kernel su ultimo
fotograma —reservada una vez, acotada al lienzo natural—. Al re-teselar
o mover el foco, el kernel recompone desde la cache: las apps que solo
pintan en init (cronista) conservan su imagen sin enterarse del cambio.
- compositor: el registro ESCRITORIO (ventanas, marcos, caches, modo);
presentar_fotograma, desalojar, atender_mandos, ciclar_layout,
mover_foco. Foco en un AtomicUsize, mandos en una cola lock-free.
- teclado: la IRQ1 deja de difundir. Alt es el modificador del sistema —
Alt+Espacio cicla el teselado, Alt+J/K mueven el foco—; una tecla
ordinaria va SOLO a la app enfocada (CANALES reindexado por indice_app).
- consola: borde de foco (indigo / gris) en cada marco.
Guardarrail anti-interbloqueo: la IRQ1 jamas bloquea ESCRITORIO; se
comunica por dos atomicos y una cola lock-free. Las caches se reservan
una sola vez, al tamaño natural — sin asignacion en el bucle del reactor.
Verificado en QEMU (screendump + sendkey): arranque teselado con hola
enfocada; Alt+Espacio cicla a CenteredMaster y las apps estaticas
conservan su contenido; Alt+J mueve el foco; las teclas llegan solo a la
app enfocada. Cierra la Fase 8 — el compositor teselante e interactivo.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El kernel deja de colocar las ventanas a mano: las tesela. El motor es
mirada-layout — el mismo nucleo no_std que ordena el compositor Wayland
de brahman, enlazado por path cruzando la frontera de workspace. Es el
primer consumo REAL del nucleo compartido brahman <-> renaser.
- kernel/compositor.rs: enlaza mirada-layout y calcula un marco por app
con el algoritmo MasterStack, dentro del area de pantalla.
- consola::volcar_marco centra el fotograma natural de la app dentro de
su marco teselado (antes lo depositaba en region.x/y fijos).
- ContextoCapacidades lleva marco + natural_ancho/alto; sys_render_frame
valida el fotograma contra el tamaño natural.
- cargar_userspace tesela con el compositor y pinta el escenario antes
de encender las apps. Las apps NO cambian: el compositor reordena la
pantalla sin que ninguna toque una instruccion.
Verificado en QEMU (screendump): las cinco apps de genesis teseladas en
MasterStack — hola como ventana maestra, el resto apiladas a la derecha,
cada lienzo centrado en su panel.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Cada app tiene ahora su propia ranura de estado en el Manifiesto de
Génesis (EntradaApp.estado): guarda y recobra lo suyo, sobrevive al
reinicio, y no pisa a ninguna otra app.
- apps/memoriosa: app WASM interactiva nueva. Cuenta las teclas pulsadas
y persiste el recuento; al reiniciar despierta con su cuenta intacta.
Reemplaza la 2a instancia de hola en la genesis.
- kernel: capacidades sys_estado_cargar / sys_estado_guardar. El kernel
custodia un manifiesto VIVO (Mutex<Manifiesto>); fijar_estado lo muta,
lo re-graba en el grafo y lo re-ancla. ContextoCapacidades.indice_app
da a cada app su identidad — su ranura, jamas la de otra.
- cargar_userspace instala el manifiesto vivo antes de instanciar las
apps: el init de una app ya consulta su estado al despertar.
Verificado en QEMU (screendump + sendkey): disco virgen -> memoriosa con
0 celdas, testigo verde; 5 pulsaciones -> 5 celdas; reinicio -> 5 celdas
intactas, testigo ambar (init releyo el estado del grafo).
Cierra la Fase 7 — el userspace nace del grafo, completa.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El kernel deja de empotrar el userspace por completo. Ya no carga ni un
solo .wasm: es boot quien siembra el disco con el grafo poblado.
- kernel/almacen.rs y manifiesto.rs migran al nucleo compartido `formato`
(tipos, postcard, BLAKE3, trazado de registros). El kernel pierde los
include_bytes!, genesis() y sembrar_genesis().
- boot::sembrar_grafo siembra un disco virgen con el bytecode de las apps
(deduplicado) y el Manifiesto de Genesis anclado en el superbloque.
- cargar_userspace sin rama de siembra; wasm/mod.rs sin TECHO_MEMORIA.
- alias `cargo kernel` -> --manifest-path (esquiva un ICE de cargo con
formato compartido entre el kernel y boot via artifact-dep).
Verificado en QEMU (screendump): disco virgen -> boot siembra 5 objetos,
el kernel monta su grafo; segundo arranque -> boot respeta el disco, la
cronista persiste. formato: 5/5 pruebas.
Nota: el crate `formato` y los 3 Cargo.toml entraron antes en 43e6b32 por
un `git add -A` de un trabajo concurrente; este commit cierra el resto.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El corpus ya rebana la carta en tajadas vivenciales: una sola
configuración mirada plano a plano, sin promediar la contradicción.
- Colocacion / AspectoEnCarta: la posición real de un planeta en una
carta — el puente entre el motor astronómico y las claves del JOIN.
- combinaciones_de_carta: deriva todas las CombinacionId de una carta.
- rebanar_por_dominio: la tomografía — cada planeta@cN cae en el
dominio de su casa, cada planeta·signo hereda el de su casa, y un
aspecto puentea apareciendo en las dos tajadas que conecta.
- Corpus::interpretar_por_dominio: el JOIN agrupado por dominio,
entrada directa del gráfico «por tajadas».
- CombinacionId acepta el alias ASCII '/' del punto medio '·'.
- ejemplo.ron: plantilla cargable y comentada del corpus.
- GUIA.md: los pasos exactos para generar el corpus a mano.
12 tests verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
El kernel deja de empotrar las apps. Las cinco aplicaciones ya no
llegan por include_bytes! en main.rs: nacen del grafo, gobernadas por
un Manifiesto de Génesis que también vive en el grafo.
- almacen: el SuperBloque gana el ancla `manifiesto: Option<Hash>`
(gemela de `raiz`, del lado del kernel) + accesores. VERSION 1→2 —
un disco v1 se reformatea.
- manifiesto.rs: implementados `cargar` (lee el manifiesto del grafo)
y `sembrar_genesis` (puebla un disco virgen con las 5 apps de
génesis). El bytecode viaja empotrado AÚN, sólo como semilla
transitoria (la Fase 7b lo mueve al constructor de imagen `boot`).
- kernel_main: `cargar_userspace` reemplaza las 5 `encender_app`
escritas a mano; `encender_app` recupera el bytecode del grafo —
`recuperar` verifica el hash, un módulo corrupto se niega y el
arranque sigue.
- wasm: el techo de memoria pasa a ser por-app (del manifiesto).
Compila limpio. Verificación en QEMU pendiente (la corre el operador):
la pantalla debe verse idéntica a la Fase 6.2 + la línea «manifiesto».
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Abre la Fase 7 («apps que nacen del grafo»): destierra el include_bytes!
del userspace — las apps pasan a ser objetos del grafo, gobernadas por
un Manifiesto de Génesis que también vive en el grafo.
Este commit es sólo plan + andamiaje; el kernel se comporta idéntico a
la Fase 6.2.
- FASE7.md — el plan de ataque: el problema de la génesis, las
sub-fases 7a/7b/7c y los guardarraíles.
- kernel/src/manifiesto.rs — andamiaje: tipos Manifiesto/EntradaApp +
(de)serialización postcard completos; cargar/sembrar_genesis son
esbozos hasta la 7a. Declarado en main.rs, aún sin cablear a
kernel_main (#![allow(dead_code)] temporal).
CHANGELOG y DIARIO al día.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>