tawasuyu

tawasuyu/brahman

Rust 321TOML 122JSON 14Markdown 114332 Definiciones

⎇ main renaser/kernel/src/manifiesto.rs Rust · 111 líneas · 5.1 KB Historia Quién tocó qué crudo

feat(renaser): Fase 7c — persistencia inter-sesión por-app 900cd19e4 · sergio ·

1// =============================================================================
2//  renaser :: kernel/src/manifiesto.rs — Fase 7 :: el Manifiesto de Génesis
3// -----------------------------------------------------------------------------
4//  Hasta la Fase 6, el userspace venia EMPOTRADO en el binario del kernel:
5//  `include_bytes!` de cada `.wasm` y regiones escritas a mano. La Fase 7 lo
6//  desterro: las aplicaciones son OBJETOS DEL GRAFO, y lo que arranca —con que
7//  cuota, en que region— lo dicta este Manifiesto de Genesis, que tambien
8//  habita el grafo. El superbloque guarda su hash en un ancla propia.
9//
10//  ESTADO: Fase 7c. El manifiesto deja de ser de solo lectura. El kernel
11//  conserva una copia VIVA —`VIVO`, un `Mutex<Manifiesto>`—; cuando una app
12//  persiste su estado (`sys_estado_guardar`), el kernel actualiza la ranura
13//  `estado` de su `EntradaApp`, re-graba el manifiesto en el grafo y lo
14//  re-ancla. Asi el estado de cada app sobrevive, por separado, a un reinicio.
15//
16//  Los tipos `Manifiesto` / `EntradaApp` y su (de)serializacion viven en la
17//  crate `formato`, el nucleo `no_std` compartido con `boot`. Aqui solo queda
18//  lo que es del kernel: cargar el manifiesto, traducir regiones, custodiar la
19//  copia viva y mutarla cuando una app graba su estado.
20// =============================================================================
21
22use alloc::vec::Vec;
23
24use spin::{Mutex, Once};
25
26use formato::Hash;
27
28use crate::almacen;
29use crate::grafico::RegionPantalla;
30
31// Los tipos del manifiesto los define `formato`; se reexportan para que el
32// resto del kernel los nombre `manifiesto::EntradaApp` / `manifiesto::Manifiesto`.
33pub use formato::{EntradaApp, Manifiesto};
34
35/// El manifiesto VIVO del kernel: la copia en memoria, mutable, del Manifiesto
36/// de Genesis. Las apps la actualizan al persistir su estado (Fase 7c); el
37/// kernel la re-graba en el grafo y la re-ancla en el superbloque. Se instala
38/// una sola vez, en el arranque, con [`instalar`].
39static VIVO: Once<Mutex<Manifiesto>> = Once::new();
40
41/// Traduce la sub-region de una `EntradaApp` —campos `u32` de ancho fijo, el
42/// formato en disco— a la `RegionPantalla` que el kernel entiende (`usize`,
43/// ancho de plataforma). El puente entre lo que el disco guarda y lo que el
44/// compositor dibuja.
45pub fn region(entrada: &EntradaApp) -> RegionPantalla {
46    RegionPantalla {
47        x: entrada.region_x as usize,
48        y: entrada.region_y as usize,
49        ancho: entrada.region_ancho as usize,
50        alto: entrada.region_alto as usize,
51    }
52}
53
54/// Lee el manifiesto del grafo: toma su hash del ancla del superbloque,
55/// recupera el objeto y lo deserializa. `Ok(None)` si el disco no tiene
56/// manifiesto anclado —un disco que `boot` no sembro—; el kernel se levanta
57/// entonces sin userspace, pero se levanta.
58pub fn cargar() -> Result<Option<Manifiesto>, &'static str> {
59    let hash = match almacen::manifiesto() {
60        Some(hash) => hash,
61        None => return Ok(None),
62    };
63    // `recuperar` recomputa el hash del objeto y verifica su integridad: un
64    // manifiesto corrupto se delata aqui.
65    let objeto = almacen::recuperar(&hash)?
66        .ok_or("manifiesto :: el objeto anclado no existe en el grafo")?;
67    let manifiesto = Manifiesto::deserializar(&objeto.datos)?;
68    Ok(Some(manifiesto))
69}
70
71/// Instala el manifiesto recien cargado como el manifiesto VIVO del kernel. Se
72/// invoca una sola vez, en el arranque, ANTES de instanciar las apps — el
73/// `init` de cada app ya consulta su estado persistido, y eso lee de aqui.
74pub fn instalar(manifiesto: Manifiesto) {
75    VIVO.call_once(|| Mutex::new(manifiesto));
76}
77
78/// El hash del estado persistido de la app `indice`, si tiene uno anclado. Lo
79/// consulta la capacidad `sys_estado_cargar` cuando una app despierta.
80pub fn estado_de(indice: usize) -> Option<Hash> {
81    VIVO.get()
82        .and_then(|vivo| vivo.lock().apps.get(indice).and_then(|app| app.estado))
83}
84
85/// Registra `hash` como el nuevo estado persistido de la app `indice`: muta el
86/// manifiesto vivo, lo re-serializa, lo graba como un objeto NUEVO del grafo y
87/// lo re-ancla en el superbloque. Desde esta llamada, el estado de esa app
88/// sobrevive a un reinicio. La invoca la capacidad `sys_estado_guardar`.
89pub fn fijar_estado(indice: usize, hash: Hash) -> Result<(), &'static str> {
90    let vivo = VIVO.get().ok_or("manifiesto :: no hay manifiesto vivo")?;
91    let mut manifiesto = vivo.lock();
92    let entrada = manifiesto
93        .apps
94        .get_mut(indice)
95        .ok_or("manifiesto :: indice de app fuera de rango")?;
96    entrada.estado = Some(hash);
97
98    // Re-grabar el manifiesto mutado. Sus `hijos` son, como en la siembra de
99    // `boot`, los objetos de bytecode deduplicados: el grafo lo sigue leyendo
100    // como el nodo padre del userspace. El objeto nuevo se ancla en el
101    // superbloque; el viejo queda en el log, inerte e inofensivo.
102    let bytes = manifiesto.serializar()?;
103    let mut hijos: Vec<Hash> = Vec::new();
104    for app in &manifiesto.apps {
105        if !hijos.contains(&app.bytecode) {
106            hijos.push(app.bytecode);
107        }
108    }
109    let nuevo = almacen::almacenar(bytes, hijos)?;
110    almacen::fijar_manifiesto(nuevo)
111}