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:
@@ -33,7 +33,9 @@ use crate::drivers::disco::{self, TAM_SECTOR};
|
||||
const MAGIA: [u8; 8] = *b"RENASGRF";
|
||||
|
||||
/// Version del formato en disco. Un disco con otra version se reformatea.
|
||||
const VERSION: u32 = 1;
|
||||
/// v2 (Fase 7) — el superbloque gana el ancla `manifiesto`; un disco v1 se
|
||||
/// reformatea al arrancar, como cualquier disco ajeno.
|
||||
const VERSION: u32 = 2;
|
||||
|
||||
/// Techo del tamaño de un objeto serializado: 1 MiB. Acota los buferes de E/S
|
||||
/// y permite descartar un registro corrupto sin intentar leer un disparate.
|
||||
@@ -56,7 +58,7 @@ pub struct Objeto {
|
||||
}
|
||||
|
||||
/// El superbloque: el sector 0 del disco. Ancla el grafo entero — dice por
|
||||
/// donde continua el log y cual es el objeto raiz.
|
||||
/// donde continua el log, cual es el objeto raiz y cual el manifiesto.
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct SuperBloque {
|
||||
/// Firma magica: debe ser [`MAGIA`].
|
||||
@@ -67,15 +69,20 @@ struct SuperBloque {
|
||||
cursor: u64,
|
||||
/// El objeto raiz del DAG: el punto de entrada que el userspace fija y lee.
|
||||
raiz: Option<Hash>,
|
||||
/// El Manifiesto de Genesis (Fase 7): el objeto que dicta que apps nacen
|
||||
/// del grafo al arrancar. Ancla del kernel, gemela de `raiz` (del userspace).
|
||||
manifiesto: Option<Hash>,
|
||||
}
|
||||
|
||||
/// El estado vivo del almacen: el cursor del log, la raiz y el indice en
|
||||
/// memoria que traduce cada hash al sector donde habita su registro.
|
||||
/// El estado vivo del almacen: el cursor del log, la raiz, el manifiesto y el
|
||||
/// indice en memoria que traduce cada hash al sector donde habita su registro.
|
||||
struct Almacen {
|
||||
/// Proximo sector libre del log.
|
||||
cursor: u64,
|
||||
/// El objeto raiz del DAG.
|
||||
raiz: Option<Hash>,
|
||||
/// El objeto del Manifiesto de Genesis (Fase 7).
|
||||
manifiesto: Option<Hash>,
|
||||
/// Indice hash -> sector del registro. Se reconstruye al arrancar.
|
||||
indice: BTreeMap<Hash, u64>,
|
||||
/// Capacidad del disco, en sectores.
|
||||
@@ -116,16 +123,16 @@ pub fn init() -> Result<Resumen, &'static str> {
|
||||
let mut sector0 = [0u8; TAM_SECTOR];
|
||||
disco::leer_sectores(0, &mut sector0)?;
|
||||
|
||||
let (cursor, raiz, indice, formateado) =
|
||||
let (cursor, raiz, manifiesto, indice, formateado) =
|
||||
match postcard::take_from_bytes::<SuperBloque>(§or0) {
|
||||
// Disco de renaser, con la version corriente: adoptar su grafo.
|
||||
Ok((sb, _)) if sb.magia == MAGIA && sb.version == VERSION => {
|
||||
let indice = reconstruir_indice(sb.cursor)?;
|
||||
(sb.cursor, sb.raiz, indice, false)
|
||||
(sb.cursor, sb.raiz, sb.manifiesto, indice, false)
|
||||
}
|
||||
// Disco virgen, ajeno o de otra version: empezar de cero. El log
|
||||
// arranca en el sector 1, justo despues del superbloque.
|
||||
_ => (1, None, BTreeMap::new(), true),
|
||||
_ => (1, None, None, BTreeMap::new(), true),
|
||||
};
|
||||
|
||||
let objetos = indice.len();
|
||||
@@ -133,6 +140,7 @@ pub fn init() -> Result<Resumen, &'static str> {
|
||||
let almacen = Almacen {
|
||||
cursor,
|
||||
raiz,
|
||||
manifiesto,
|
||||
indice,
|
||||
capacidad,
|
||||
};
|
||||
@@ -204,6 +212,7 @@ fn persistir(almacen: &Almacen) -> Result<(), &'static str> {
|
||||
version: VERSION,
|
||||
cursor: almacen.cursor,
|
||||
raiz: almacen.raiz,
|
||||
manifiesto: almacen.manifiesto,
|
||||
};
|
||||
let bytes = postcard::to_allocvec(&sb).map_err(|_| "no se pudo serializar el superbloque")?;
|
||||
if bytes.len() > TAM_SECTOR {
|
||||
@@ -290,3 +299,19 @@ pub fn fijar_raiz(hash: Hash) -> Result<(), &'static str> {
|
||||
almacen.raiz = Some(hash);
|
||||
persistir(&almacen)
|
||||
}
|
||||
|
||||
/// El hash del objeto del Manifiesto de Genesis, si el disco tiene uno
|
||||
/// anclado. Gemelo de [`raiz`], pero del lado del kernel: lo lee la Fase 7
|
||||
/// para descubrir que apps poblar al arrancar.
|
||||
pub fn manifiesto() -> Option<Hash> {
|
||||
ALMACEN.get().and_then(|mutex| mutex.lock().manifiesto)
|
||||
}
|
||||
|
||||
/// Ancla un objeto como el Manifiesto de Genesis y graba el cambio en el
|
||||
/// superbloque. Gemelo de [`fijar_raiz`].
|
||||
pub fn fijar_manifiesto(hash: Hash) -> Result<(), &'static str> {
|
||||
let mutex = ALMACEN.get().ok_or("almacen no inicializado")?;
|
||||
let mut almacen = mutex.lock();
|
||||
almacen.manifiesto = Some(hash);
|
||||
persistir(&almacen)
|
||||
}
|
||||
|
||||
+78
-69
@@ -66,33 +66,9 @@ use async_system::executor::Executor;
|
||||
use baliza::BALIZA_PANICO;
|
||||
use consola::{Consola, CONSOLA};
|
||||
use grafico::{
|
||||
codificar, reclamar_memoria_lienzo, Color, Lienzo, Pantalla, RegionPantalla, ALTO_MAX,
|
||||
ANCHO_MAX,
|
||||
codificar, reclamar_memoria_lienzo, Color, Lienzo, Pantalla, ALTO_MAX, ANCHO_MAX,
|
||||
};
|
||||
|
||||
/// El modulo WASM del userspace, empotrado en el binario del kernel para esta
|
||||
/// fase de pruebas. Es un `.wasm` puro, compilado aparte para `wasm32`. La
|
||||
/// Fase 5 lo instancia DOS veces —el mismo bytecode, dos regiones distintas—
|
||||
/// para demostrar la multitarea cooperativa sobre el espacio unico.
|
||||
static APP_WASM: &[u8] = include_bytes!("../assets/app.wasm");
|
||||
|
||||
/// La aplicacion DISCOLA: un modulo WASM cuyo `tick` cae en un bucle cerrado y
|
||||
/// jamas retorna. Existe para una sola cosa — demostrar que el guardarrail de
|
||||
/// combustible la fulmina sin despeinar al kernel ni a sus vecinas.
|
||||
static DISCOLA_WASM: &[u8] = include_bytes!("../assets/discola.wasm");
|
||||
|
||||
/// La aplicacion GLOTONA: un modulo WASM que reclama memoria lineal sin freno.
|
||||
/// Demuestra el guardarrail ESPACIAL — el techo de memoria la desaloja con la
|
||||
/// baliza amarilla, gemela de la purpura del desalojo por combustible.
|
||||
static GLOTONA_WASM: &[u8] = include_bytes!("../assets/glotona.wasm");
|
||||
|
||||
/// La aplicacion CRONISTA: la primera ciudadana del userspace que escribe en el
|
||||
/// almacenamiento PERSISTENTE. En cada arranque graba un objeto en el grafo
|
||||
/// —enlazado al del arranque anterior—, lo corona como raiz y pinta una celda
|
||||
/// por cada arranque registrado. El disco recuerda; la cuenta sobrevive a los
|
||||
/// reinicios. Demuestra las capacidades `sys_object_*` de la Fase 6.1c.
|
||||
static CRONISTA_WASM: &[u8] = include_bytes!("../assets/cronista.wasm");
|
||||
|
||||
/// Configuracion que el cargador `bootloader` aplicara antes de cedernos la CPU.
|
||||
static CONFIG_ARRANQUE: BootloaderConfig = {
|
||||
let mut config = BootloaderConfig::new_default();
|
||||
@@ -152,16 +128,80 @@ async fn tarea_sonda_disco() {
|
||||
consola.presentar();
|
||||
}
|
||||
|
||||
/// Da vida a una aplicacion del userspace: la carga en su region y, si lo
|
||||
/// logra, la despacha como tarea cooperativa del reactor. Una carga fallida se
|
||||
/// salda pintando su region con la baliza de desalojo — el kernel no se inmuta.
|
||||
fn encender_app(ejecutor: &mut Executor, bytecode: &'static [u8], region: RegionPantalla) {
|
||||
match wasm::AplicacionWasm::cargar(bytecode, region) {
|
||||
/// Da vida a una aplicacion del userspace a partir de su `EntradaApp` del
|
||||
/// manifiesto: recupera su bytecode del grafo, la carga en su region y la
|
||||
/// despacha como tarea cooperativa del reactor. Si el bytecode falta, esta
|
||||
/// corrupto, o la carga fracasa, se salda pintando la region de la app con
|
||||
/// la baliza de desalojo — el kernel no se inmuta y sigue con las demas.
|
||||
fn encender_app(ejecutor: &mut Executor, entrada: &manifiesto::EntradaApp) {
|
||||
let region = entrada.region();
|
||||
// Recuperar el bytecode del grafo. `recuperar` recomputa el hash del
|
||||
// objeto y verifica su integridad: un bytecode corrupto se delata aqui
|
||||
// —y la app se niega, no se instancia un modulo en el que no se confia.
|
||||
let bytecode = match almacen::recuperar(&entrada.bytecode) {
|
||||
Ok(Some(objeto)) => objeto.datos,
|
||||
_ => {
|
||||
consola::pintar_desalojo(region, Color::DESALOJO);
|
||||
return;
|
||||
}
|
||||
};
|
||||
match wasm::AplicacionWasm::cargar(&bytecode, region, entrada.techo_memoria as usize) {
|
||||
Ok(app) => ejecutor.spawn(tarea_aplicacion(app)),
|
||||
Err(_) => consola::pintar_desalojo(region, Color::DESALOJO),
|
||||
}
|
||||
}
|
||||
|
||||
/// Escribe una linea en la consola global y la presenta. Atajo para los
|
||||
/// informes de arranque; no hace nada si la consola aun no existe.
|
||||
fn reportar(linea: &str) {
|
||||
if let Some(consola) = CONSOLA.get() {
|
||||
let mut consola = consola.lock();
|
||||
consola.escribir(linea);
|
||||
consola.escribir("\n");
|
||||
consola.presentar();
|
||||
}
|
||||
}
|
||||
|
||||
/// FASE 7 :: puebla el userspace DESDE EL GRAFO. Carga el Manifiesto de
|
||||
/// Genesis; si el disco no tiene uno —disco virgen—, lo siembra y lo vuelve a
|
||||
/// cargar. Por cada `EntradaApp`, enciende su aplicacion. Toda falla se
|
||||
/// reporta a la consola y NO detiene el arranque: el kernel se levanta con
|
||||
/// las apps que pueda — o con ninguna, si el grafo no tiene userspace.
|
||||
fn cargar_userspace(ejecutor: &mut Executor) {
|
||||
let manifiesto = match manifiesto::cargar() {
|
||||
Ok(Some(m)) => Some(m),
|
||||
// Disco sin manifiesto: sembrar la genesis y volver a cargarlo.
|
||||
Ok(None) => match manifiesto::sembrar_genesis() {
|
||||
Ok(_) => {
|
||||
reportar("manifiesto :: genesis sembrada en disco virgen");
|
||||
manifiesto::cargar().ok().flatten()
|
||||
}
|
||||
Err(motivo) => {
|
||||
reportar(&format!("manifiesto :: siembra fallida -- {motivo}"));
|
||||
None
|
||||
}
|
||||
},
|
||||
Err(motivo) => {
|
||||
reportar(&format!("manifiesto :: carga fallida -- {motivo}"));
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
match &manifiesto {
|
||||
Some(m) => reportar(&format!(
|
||||
"manifiesto :: {} apps nacidas del grafo",
|
||||
m.apps.len(),
|
||||
)),
|
||||
None => reportar("manifiesto :: sin userspace -- el kernel se levanta solo"),
|
||||
}
|
||||
|
||||
if let Some(m) = manifiesto {
|
||||
for entrada in &m.apps {
|
||||
encender_app(ejecutor, entrada);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Localiza la mayor region de RAM libre que el cargador reporto — la cantera
|
||||
/// de la que el DMA del disco tomara sus marcos fisicos.
|
||||
fn mayor_region_usable(regiones: &MemoryRegions) -> Option<(u64, u64)> {
|
||||
@@ -291,50 +331,19 @@ fn kernel_main(boot_info: &'static mut BootInfo) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
// --- 7. FASE 5/6 :: levantar el reactor y poblar el userspace con CINCO
|
||||
// aplicaciones WASM concurrentes, cada una en su propia region:
|
||||
//
|
||||
// * App 1 — instancia de hello_wasm, a la izquierda, gobernada
|
||||
// por el teclado.
|
||||
// * App 2 — segunda instancia del MISMO bytecode, a la derecha:
|
||||
// un unico modulo en la RAM unificada, dos vidas aisladas.
|
||||
// * App discola — su `tick` es un bucle cerrado: el escudo de
|
||||
// COMBUSTIBLE la desaloja (baliza purpura) en su 1er fotograma.
|
||||
// * App glotona — reclama memoria sin freno: el escudo ESPACIAL
|
||||
// la desaloja (baliza amarilla) en su 1er fotograma.
|
||||
// * App cronista — escribe en el GRAFO DE OBJETOS persistente:
|
||||
// cada arranque deja un objeto enlazado al anterior y pinta una
|
||||
// celda por arranque. El disco recuerda entre reinicios.
|
||||
// --- 7. FASE 7 :: levantar el reactor y poblar el userspace DESDE EL
|
||||
// GRAFO. El kernel ya no empotra los modulos WASM: lee el
|
||||
// Manifiesto de Genesis —si el disco esta virgen, lo siembra— e
|
||||
// instancia cada `EntradaApp` recuperando su bytecode del grafo de
|
||||
// objetos. Las cinco apps de genesis (dos instancias de hello, la
|
||||
// discola, la glotona y la cronista) nacen ahora del disco, no del
|
||||
// binario del kernel.
|
||||
//
|
||||
// Las interrupciones se habilitan AHORA: el temporizador marcara el
|
||||
// compas de los fotogramas y la IRQ del teclado difundira cada
|
||||
// scancode a los canales que las apps consultan. ---
|
||||
let mut ejecutor = Executor::nuevo();
|
||||
encender_app(
|
||||
&mut ejecutor,
|
||||
APP_WASM,
|
||||
RegionPantalla { x: 100, y: 120, ancho: 480, alto: 560 },
|
||||
);
|
||||
encender_app(
|
||||
&mut ejecutor,
|
||||
APP_WASM,
|
||||
RegionPantalla { x: 700, y: 120, ancho: 480, alto: 560 },
|
||||
);
|
||||
encender_app(
|
||||
&mut ejecutor,
|
||||
DISCOLA_WASM,
|
||||
RegionPantalla { x: 60, y: 700, ancho: 360, alto: 80 },
|
||||
);
|
||||
encender_app(
|
||||
&mut ejecutor,
|
||||
GLOTONA_WASM,
|
||||
RegionPantalla { x: 460, y: 700, ancho: 360, alto: 80 },
|
||||
);
|
||||
encender_app(
|
||||
&mut ejecutor,
|
||||
CRONISTA_WASM,
|
||||
RegionPantalla { x: 860, y: 700, ancho: 360, alto: 80 },
|
||||
);
|
||||
cargar_userspace(&mut ejecutor);
|
||||
// FASE 6.2 :: una tarea mas del reactor — no una app WASM— que sondea el
|
||||
// disco de forma ASINCRONA: la demostracion de que la IRQ del disco
|
||||
// conduce la E/S sin detener a las aplicaciones visuales.
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -35,7 +35,11 @@ const FUEL_FOTOGRAMA: u64 = 2_000_000;
|
||||
/// Techo de memoria lineal por aplicacion: 4 MiB. Un modulo que intente crecer
|
||||
/// su memoria mas alla es desalojado — el aislamiento ESPACIAL del userspace,
|
||||
/// gemelo del techo TEMPORAL que impone el combustible.
|
||||
const TECHO_MEMORIA: usize = 4 * 1024 * 1024;
|
||||
///
|
||||
/// Desde la Fase 7 el techo es POR-APP: cada `EntradaApp` del manifiesto
|
||||
/// lleva el suyo. Esta constante es el valor por DEFECTO — el que usan las
|
||||
/// apps de genesis (ver `manifiesto::genesis`).
|
||||
pub(crate) const TECHO_MEMORIA: usize = 4 * 1024 * 1024;
|
||||
|
||||
/// Por que el kernel da por terminada —desaloja— una aplicacion WASM.
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -88,7 +92,14 @@ impl AplicacionWasm {
|
||||
/// El nuevo ABI del userspace exige dos exportaciones: `init` —invocada una
|
||||
/// sola vez, aqui— y `tick` —un fotograma de trabajo, invocada despues por
|
||||
/// el reactor en cada pulso del reloj.
|
||||
pub fn cargar(bytecode: &[u8], region: RegionPantalla) -> Result<AplicacionWasm, FallaApp> {
|
||||
///
|
||||
/// `techo_memoria` es la cuota de memoria lineal de ESTA app, en bytes —
|
||||
/// desde la Fase 7 la dicta su `EntradaApp` del manifiesto.
|
||||
pub fn cargar(
|
||||
bytecode: &[u8],
|
||||
region: RegionPantalla,
|
||||
techo_memoria: usize,
|
||||
) -> Result<AplicacionWasm, FallaApp> {
|
||||
// 1. El motor, con metricas de combustible y compilacion ANTICIPADA: la
|
||||
// traduccion del modulo ocurre ahora, de modo que el `fuel` mida
|
||||
// despues solo EJECUCION, jamas compilacion diferida.
|
||||
@@ -106,7 +117,7 @@ impl AplicacionWasm {
|
||||
// ya con la app cargada: una carga fallida no deja canales huerfanos.
|
||||
let canal = crate::async_system::teclado::crear_canal();
|
||||
let limites = StoreLimitsBuilder::new()
|
||||
.memory_size(TECHO_MEMORIA)
|
||||
.memory_size(techo_memoria)
|
||||
// Una expansion denegada se convierte en TRAMPA, no en un -1 que la
|
||||
// app pudiera ignorar: asi el kernel la captura y la desaloja.
|
||||
.trap_on_grow_failure(true)
|
||||
|
||||
Reference in New Issue
Block a user