feat(renaser): Fase 7a — el userspace nace del Grafo de Objetos

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>
This commit is contained in:
sergio
2026-05-22 15:11:47 +00:00
parent 4f31146533
commit bce4abd8cc
6 changed files with 302 additions and 100 deletions
+115 -21
View File
@@ -11,16 +11,13 @@
// del manifiesto, lo deserializa, y por cada `EntradaApp` recupera el objeto
// de bytecode —verificado por su hash— y lo inyecta en `wasmi`.
//
// ESTADO: andamiaje de la Fase 7a. Los tipos y la (de)serializacion estan
// completos; `cargar` y `sembrar_genesis` son esbozos — se implementan al
// abordar la 7a, cuando el superbloque gane su campo `manifiesto`. Ver
// `FASE7.md` para el plan completo.
// ESTADO: Fase 7a. Tipos, (de)serializacion, carga desde el grafo y siembra
// de la genesis, implementados. La siembra es TRANSITORIA — el bytecode aun
// viaja empotrado (`include_bytes!`, abajo); la Fase 7b lo movera al
// constructor de imagen `boot` y el kernel dejara de empotrar una sola app.
// Ver `FASE7.md` para el plan completo.
// =============================================================================
// Fase 7a en construccion: el modulo aun no se cablea a `kernel_main`. El
// `allow` cae en cuanto `cargar`/`sembrar_genesis` tengan llamador real.
#![allow(dead_code)]
use alloc::string::String;
use alloc::vec::Vec;
@@ -104,21 +101,118 @@ impl Manifiesto {
/// Lee el manifiesto del grafo: toma su hash del ancla del superbloque,
/// recupera el objeto y lo deserializa. `Ok(None)` si el disco aun no tiene
/// manifiesto anclado — el caller debe entonces sembrar la genesis.
///
/// ANDAMIAJE (Fase 7a-4): depende de `almacen::manifiesto()` —el nuevo ancla
/// del superbloque— todavia por implementar (tarea 7a-2).
pub fn cargar() -> Result<Option<Manifiesto>, &'static str> {
todo!("Fase 7a-4: leer almacen::manifiesto(), recuperar el objeto y deserializar")
let hash = match crate::almacen::manifiesto() {
Some(hash) => hash,
None => return Ok(None),
};
// `recuperar` recomputa el hash del objeto y verifica su integridad: un
// manifiesto corrupto se delata aqui.
let objeto = crate::almacen::recuperar(&hash)?
.ok_or("manifiesto :: el objeto anclado no existe en el grafo")?;
let manifiesto = Manifiesto::deserializar(&objeto.datos)?;
Ok(Some(manifiesto))
}
/// Siembra el grafo en un disco sin manifiesto: graba el bytecode de las
/// aplicaciones de genesis, compone un `Manifiesto` por defecto con sus
/// regiones y cuotas, lo graba y lo ancla en el superbloque. Devuelve el
/// hash del manifiesto recien anclado.
///
/// ANDAMIAJE (Fase 7a-3): la semilla TRANSITORIA — en la 7a el bytecode aun
/// llega vacia `include_bytes!`; la 7b mueve la siembra al constructor de
/// imagen `boot` y elimina el empotrado del kernel.
// =============================================================================
// La genesis — la semilla transitoria de la Fase 7a
// -----------------------------------------------------------------------------
// El bytecode de las apps de genesis viaja, POR AHORA, empotrado en el kernel.
// Es el unico `include_bytes!` que sobrevive a la Fase 7a — y solo como
// semilla: en un disco virgen, `sembrar_genesis` lo graba en el grafo una vez.
// La Fase 7b lo movera al constructor de imagen `boot` y este bloque morira.
// =============================================================================
static APP_WASM: &[u8] = include_bytes!("../assets/app.wasm");
static DISCOLA_WASM: &[u8] = include_bytes!("../assets/discola.wasm");
static GLOTONA_WASM: &[u8] = include_bytes!("../assets/glotona.wasm");
static CRONISTA_WASM: &[u8] = include_bytes!("../assets/cronista.wasm");
/// Descriptor de una app de genesis: lo que el kernel sabe de ella ANTES de
/// que exista en el grafo. `region` es `(x, y, ancho, alto)` en pixeles.
struct AppGenesis {
nombre: &'static str,
bytecode: &'static [u8],
region: (u32, u32, u32, u32),
techo_memoria: u32,
}
/// El userspace de genesis: las cinco aplicaciones que pueblan un disco
/// virgen, con las regiones de la Fase 6.2. `app.wasm` aparece dos veces
/// —dos instancias del mismo bytecode—; el grafo, direccionado por contenido,
/// lo guarda una sola vez.
fn genesis() -> [AppGenesis; 5] {
let techo = crate::wasm::TECHO_MEMORIA as u32;
[
AppGenesis {
nombre: "hola-izq",
bytecode: APP_WASM,
region: (100, 120, 480, 560),
techo_memoria: techo,
},
AppGenesis {
nombre: "hola-der",
bytecode: APP_WASM,
region: (700, 120, 480, 560),
techo_memoria: techo,
},
AppGenesis {
nombre: "discola",
bytecode: DISCOLA_WASM,
region: (60, 700, 360, 80),
techo_memoria: techo,
},
AppGenesis {
nombre: "glotona",
bytecode: GLOTONA_WASM,
region: (460, 700, 360, 80),
techo_memoria: techo,
},
AppGenesis {
nombre: "cronista",
bytecode: CRONISTA_WASM,
region: (860, 700, 360, 80),
techo_memoria: techo,
},
]
}
/// Siembra el grafo en un disco sin manifiesto: graba el bytecode de cada app
/// de genesis como un objeto, compone un `Manifiesto` con sus regiones y
/// cuotas, lo graba —con las aristas hacia los objetos de bytecode— y lo
/// ancla en el superbloque. Devuelve el hash del manifiesto recien anclado.
pub fn sembrar_genesis() -> Result<Hash, &'static str> {
todo!("Fase 7a-3: grabar los bytecodes de genesis + el manifiesto por defecto, y anclarlo")
let mut apps: Vec<EntradaApp> = Vec::new();
let mut hijos: Vec<Hash> = Vec::new();
for app in genesis() {
// Grabar el bytecode como objeto del grafo. Idempotente: dos
// instancias de la misma app comparten un unico objeto.
let bytecode = crate::almacen::almacenar(app.bytecode.to_vec(), Vec::new())?;
if !hijos.contains(&bytecode) {
hijos.push(bytecode);
}
let (x, y, ancho, alto) = app.region;
apps.push(EntradaApp {
nombre: String::from(app.nombre),
bytecode,
region_x: x,
region_y: y,
region_ancho: ancho,
region_alto: alto,
techo_memoria: app.techo_memoria,
estado: None,
});
}
// El objeto del manifiesto: sus `hijos` son los objetos de bytecode, de
// modo que el grafo lo lea como el nodo padre del userspace.
let manifiesto = Manifiesto {
version: VERSION_MANIFIESTO,
apps,
};
let bytes = manifiesto.serializar()?;
let hash = crate::almacen::almacenar(bytes, hijos)?;
crate::almacen::fijar_manifiesto(hash)?;
Ok(hash)
}