gioser

tawasuyu/brahman

Rust 326TOML 123JSON 14Markdown 114554 Sutichaykuna

⎇ 43e6b32e15dea99bd57a9a11fdafa7bd9a2a236f renaser/kernel/src/manifiesto.rs Rust · 218 siq'ikuna · 9.0 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat(renaser): Fase 7a — el userspace nace del Grafo de Objetos bce4abd8c · 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//  destierra: las aplicaciones pasan a ser OBJETOS DEL GRAFO, y lo que arranca
7//  —con que cuota, en que region— lo dicta este Manifiesto de Genesis, que
8//  tambien habita el grafo. El superbloque guarda su hash en un ancla propia.
9//
10//  El kernel, al despertar: lee el ancla del superbloque, recupera el objeto
11//  del manifiesto, lo deserializa, y por cada `EntradaApp` recupera el objeto
12//  de bytecode —verificado por su hash— y lo inyecta en `wasmi`.
13//
14//  ESTADO: Fase 7a. Tipos, (de)serializacion, carga desde el grafo y siembra
15//  de la genesis, implementados. La siembra es TRANSITORIA — el bytecode aun
16//  viaja empotrado (`include_bytes!`, abajo); la Fase 7b lo movera al
17//  constructor de imagen `boot` y el kernel dejara de empotrar una sola app.
18//  Ver `FASE7.md` para el plan completo.
19// =============================================================================
20
21use alloc::string::String;
22use alloc::vec::Vec;
23
24use serde::{Deserialize, Serialize};
25
26use crate::almacen::Hash;
27use crate::grafico::RegionPantalla;
28
29/// Version del formato del manifiesto serializado. Independiente de la
30/// version del superbloque (`almacen::VERSION`): el manifiesto es un objeto
31/// del grafo, no una estructura de disco.
32pub const VERSION_MANIFIESTO: u32 = 1;
33
34/// El Manifiesto de Genesis: la lista de aplicaciones que el kernel instancia
35/// al arrancar. Vive como un objeto del grafo de objetos; el superbloque
36/// guarda su hash en el campo `manifiesto`.
37#[derive(Serialize, Deserialize, Clone)]
38pub struct Manifiesto {
39    /// Version del formato — debe ser [`VERSION_MANIFIESTO`].
40    pub version: u32,
41    /// Las aplicaciones del userspace, en orden de arranque.
42    pub apps: Vec<EntradaApp>,
43}
44
45/// Una entrada del manifiesto: una aplicacion del userspace y todo lo que el
46/// kernel necesita para darle vida — su bytecode, su ventana, su cuota de
47/// memoria y, si lo tuviera, su ultimo estado persistido.
48#[derive(Serialize, Deserialize, Clone)]
49pub struct EntradaApp {
50    /// Nombre legible — para los rotulos de la consola y la baliza.
51    pub nombre: String,
52    /// Hash del objeto del grafo que contiene el bytecode WASM de la app.
53    pub bytecode: Hash,
54    /// Sub-region del framebuffer asignada a la app. Campos de ancho fijo
55    /// `u32` A PROPOSITO: esto es un formato EN DISCO. `RegionPantalla` usa
56    /// `usize` (ancho dependiente de plataforma) y no sirve para serializar.
57    pub region_x: u32,
58    pub region_y: u32,
59    pub region_ancho: u32,
60    pub region_alto: u32,
61    /// Techo de memoria lineal de la app, en bytes. Sustituye a la constante
62    /// global `wasm::TECHO_MEMORIA` — cada app lleva su cuota.
63    pub techo_memoria: u32,
64    /// Hash del ultimo estado persistido de la app (Fase 7c). `None` hasta
65    /// que la app guarde estado por primera vez.
66    pub estado: Option<Hash>,
67}
68
69impl EntradaApp {
70    /// Construye la `RegionPantalla` que el kernel entiende a partir de los
71    /// campos de ancho fijo del manifiesto.
72    pub fn region(&self) -> RegionPantalla {
73        RegionPantalla {
74            x: self.region_x as usize,
75            y: self.region_y as usize,
76            ancho: self.region_ancho as usize,
77            alto: self.region_alto as usize,
78        }
79    }
80}
81
82impl Manifiesto {
83    /// Serializa el manifiesto a su forma binaria `postcard` — la carga util
84    /// del objeto del grafo que lo aloja.
85    pub fn serializar(&self) -> Result<Vec<u8>, &'static str> {
86        postcard::to_allocvec(self).map_err(|_| "manifiesto :: serializacion fallida")
87    }
88
89    /// Reconstruye un manifiesto desde la carga util de su objeto. Rechaza
90    /// un formato de version desconocida en lugar de malinterpretarlo.
91    pub fn deserializar(bytes: &[u8]) -> Result<Manifiesto, &'static str> {
92        let (manifiesto, _) = postcard::take_from_bytes::<Manifiesto>(bytes)
93            .map_err(|_| "manifiesto :: deserializacion fallida")?;
94        if manifiesto.version != VERSION_MANIFIESTO {
95            return Err("manifiesto :: version de formato desconocida");
96        }
97        Ok(manifiesto)
98    }
99}
100
101/// Lee el manifiesto del grafo: toma su hash del ancla del superbloque,
102/// recupera el objeto y lo deserializa. `Ok(None)` si el disco aun no tiene
103/// manifiesto anclado — el caller debe entonces sembrar la genesis.
104pub fn cargar() -> Result<Option<Manifiesto>, &'static str> {
105    let hash = match crate::almacen::manifiesto() {
106        Some(hash) => hash,
107        None => return Ok(None),
108    };
109    // `recuperar` recomputa el hash del objeto y verifica su integridad: un
110    // manifiesto corrupto se delata aqui.
111    let objeto = crate::almacen::recuperar(&hash)?
112        .ok_or("manifiesto :: el objeto anclado no existe en el grafo")?;
113    let manifiesto = Manifiesto::deserializar(&objeto.datos)?;
114    Ok(Some(manifiesto))
115}
116
117// =============================================================================
118//  La genesis — la semilla transitoria de la Fase 7a
119// -----------------------------------------------------------------------------
120//  El bytecode de las apps de genesis viaja, POR AHORA, empotrado en el kernel.
121//  Es el unico `include_bytes!` que sobrevive a la Fase 7a — y solo como
122//  semilla: en un disco virgen, `sembrar_genesis` lo graba en el grafo una vez.
123//  La Fase 7b lo movera al constructor de imagen `boot` y este bloque morira.
124// =============================================================================
125
126static APP_WASM: &[u8] = include_bytes!("../assets/app.wasm");
127static DISCOLA_WASM: &[u8] = include_bytes!("../assets/discola.wasm");
128static GLOTONA_WASM: &[u8] = include_bytes!("../assets/glotona.wasm");
129static CRONISTA_WASM: &[u8] = include_bytes!("../assets/cronista.wasm");
130
131/// Descriptor de una app de genesis: lo que el kernel sabe de ella ANTES de
132/// que exista en el grafo. `region` es `(x, y, ancho, alto)` en pixeles.
133struct AppGenesis {
134    nombre: &'static str,
135    bytecode: &'static [u8],
136    region: (u32, u32, u32, u32),
137    techo_memoria: u32,
138}
139
140/// El userspace de genesis: las cinco aplicaciones que pueblan un disco
141/// virgen, con las regiones de la Fase 6.2. `app.wasm` aparece dos veces
142/// —dos instancias del mismo bytecode—; el grafo, direccionado por contenido,
143/// lo guarda una sola vez.
144fn genesis() -> [AppGenesis; 5] {
145    let techo = crate::wasm::TECHO_MEMORIA as u32;
146    [
147        AppGenesis {
148            nombre: "hola-izq",
149            bytecode: APP_WASM,
150            region: (100, 120, 480, 560),
151            techo_memoria: techo,
152        },
153        AppGenesis {
154            nombre: "hola-der",
155            bytecode: APP_WASM,
156            region: (700, 120, 480, 560),
157            techo_memoria: techo,
158        },
159        AppGenesis {
160            nombre: "discola",
161            bytecode: DISCOLA_WASM,
162            region: (60, 700, 360, 80),
163            techo_memoria: techo,
164        },
165        AppGenesis {
166            nombre: "glotona",
167            bytecode: GLOTONA_WASM,
168            region: (460, 700, 360, 80),
169            techo_memoria: techo,
170        },
171        AppGenesis {
172            nombre: "cronista",
173            bytecode: CRONISTA_WASM,
174            region: (860, 700, 360, 80),
175            techo_memoria: techo,
176        },
177    ]
178}
179
180/// Siembra el grafo en un disco sin manifiesto: graba el bytecode de cada app
181/// de genesis como un objeto, compone un `Manifiesto` con sus regiones y
182/// cuotas, lo graba —con las aristas hacia los objetos de bytecode— y lo
183/// ancla en el superbloque. Devuelve el hash del manifiesto recien anclado.
184pub fn sembrar_genesis() -> Result<Hash, &'static str> {
185    let mut apps: Vec<EntradaApp> = Vec::new();
186    let mut hijos: Vec<Hash> = Vec::new();
187
188    for app in genesis() {
189        // Grabar el bytecode como objeto del grafo. Idempotente: dos
190        // instancias de la misma app comparten un unico objeto.
191        let bytecode = crate::almacen::almacenar(app.bytecode.to_vec(), Vec::new())?;
192        if !hijos.contains(&bytecode) {
193            hijos.push(bytecode);
194        }
195        let (x, y, ancho, alto) = app.region;
196        apps.push(EntradaApp {
197            nombre: String::from(app.nombre),
198            bytecode,
199            region_x: x,
200            region_y: y,
201            region_ancho: ancho,
202            region_alto: alto,
203            techo_memoria: app.techo_memoria,
204            estado: None,
205        });
206    }
207
208    // El objeto del manifiesto: sus `hijos` son los objetos de bytecode, de
209    // modo que el grafo lo lea como el nodo padre del userspace.
210    let manifiesto = Manifiesto {
211        version: VERSION_MANIFIESTO,
212        apps,
213    };
214    let bytes = manifiesto.serializar()?;
215    let hash = crate::almacen::almacenar(bytes, hijos)?;
216    crate::almacen::fijar_manifiesto(hash)?;
217    Ok(hash)
218}