feat: integra renaser (kernel SASOS bare-metal) al monorepo
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>
This commit is contained in:
Generated
+7
@@ -0,0 +1,7 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "cronista"
|
||||
version = "0.1.0"
|
||||
@@ -0,0 +1,31 @@
|
||||
# =============================================================================
|
||||
# renaser :: apps/cronista — Fase 6.1c :: el primer escriba del userspace
|
||||
# -----------------------------------------------------------------------------
|
||||
# Un modulo WebAssembly que, a diferencia de sus vecinas, deja HUELLA. En cada
|
||||
# arranque graba un objeto en el grafo persistente del kernel —enlazado al del
|
||||
# arranque anterior, formando una cadena— y lo corona como raiz. Asi lleva la
|
||||
# cronica de cuantas veces ha despertado el sistema: una cuenta que sobrevive
|
||||
# a los reinicios porque vive en el disco, no en la RAM.
|
||||
# Tiene su propio `[workspace]`: queda fuera del espacio de trabajo del kernel.
|
||||
# =============================================================================
|
||||
|
||||
[package]
|
||||
name = "cronista"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
description = "renaser :: app WASM cronista — la cronica persistente de los arranques"
|
||||
|
||||
[workspace]
|
||||
|
||||
# `cdylib` produce un modulo `.wasm` que exporta funciones — el formato que
|
||||
# wasmi instancia.
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[profile.dev]
|
||||
panic = "abort"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
opt-level = "s"
|
||||
lto = true
|
||||
@@ -0,0 +1,234 @@
|
||||
// =============================================================================
|
||||
// renaser :: apps/cronista — Fase 6.1c :: el primer escriba del userspace
|
||||
// -----------------------------------------------------------------------------
|
||||
// Las apps de fases anteriores eran efimeras: su mundo se borraba al apagar la
|
||||
// maquina. `cronista` es la primera que deja HUELLA. En cada arranque:
|
||||
//
|
||||
// 1. pregunta al kernel por la RAIZ del grafo de objetos —la cabeza de la
|
||||
// cadena de arranques anteriores—;
|
||||
// 2. lee de ella el numero del ultimo arranque;
|
||||
// 3. graba un objeto nuevo —sus datos: el numero de arranque; su hijo: la
|
||||
// raiz anterior— y lo corona como raiz;
|
||||
// 4. recorre la cadena entera para verificar que el DAG persiste integro;
|
||||
// 5. pinta una celda por cada arranque registrado.
|
||||
//
|
||||
// La cuenta NO vive en la RAM: vive en el disco, en el grafo direccionado por
|
||||
// contenido. Sobrevive a los reinicios. Cada vez que renaser despierta, la
|
||||
// cronista añade un eslabon a la cadena y una celda a su rejilla.
|
||||
//
|
||||
// Sus unicas vias hacia el mundo son las capacidades `sys_object_*` que el
|
||||
// kernel le inyecta. No conoce el disco, ni el bus PCI, ni el formato en
|
||||
// sectores: solo objetos, hashes y aristas.
|
||||
// =============================================================================
|
||||
|
||||
#![no_std]
|
||||
|
||||
// --- Las capacidades que el kernel `renaser` inyecta a esta aplicacion. ---
|
||||
#[link(wasm_import_module = "renaser")]
|
||||
extern "C" {
|
||||
/// Compone un bufer de pixeles (de ESTA memoria lineal) en la region que el
|
||||
/// kernel asigno a esta aplicacion.
|
||||
fn sys_render_frame(ptr: u32, len: u32);
|
||||
|
||||
/// Graba un objeto en el grafo: `datos` es su carga util; `hijos` apunta a
|
||||
/// un arreglo de `hijos_cnt` hashes de 32 bytes —las aristas—. El hash
|
||||
/// resultante se escribe en `salida`. Devuelve 0 si todo fue bien.
|
||||
fn sys_object_put(datos: u32, datos_len: u32, hijos: u32, hijos_cnt: u32, salida: u32) -> i32;
|
||||
|
||||
/// Copia la carga util del objeto `hash` en `salida`. Devuelve el numero de
|
||||
/// bytes copiados, o un valor negativo si fallo.
|
||||
fn sys_object_datos(hash: u32, salida: u32, capacidad: u32) -> i32;
|
||||
|
||||
/// Devuelve el numero de hijos del objeto `hash` y, si `indice` es valido,
|
||||
/// escribe el hash de ese hijo en `salida`. Negativo si el objeto no existe.
|
||||
fn sys_object_hijo(hash: u32, indice: u32, salida: u32) -> i32;
|
||||
|
||||
/// Escribe en `salida` el hash de la raiz del grafo. Devuelve 1 si hay
|
||||
/// raiz, 0 si el grafo aun esta vacio.
|
||||
fn sys_object_raiz(salida: u32) -> i32;
|
||||
|
||||
/// Corona el objeto `hash` como raiz del grafo. Devuelve 0 si lo logro.
|
||||
fn sys_object_fijar_raiz(hash: u32) -> i32;
|
||||
}
|
||||
|
||||
/// Sin sistema operativo bajo nosotros, un panico solo puede detenerse en seco.
|
||||
#[panic_handler]
|
||||
fn al_fallar(_: &core::panic::PanicInfo) -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
||||
// --- Geometria de la escena. El ancho y el alto DEBEN coincidir con la region
|
||||
// que el kernel asigna a esta app. ---
|
||||
const ANCHO: usize = 360;
|
||||
const ALTO: usize = 80;
|
||||
|
||||
/// Lado de paso de la rejilla de celdas, en pixeles.
|
||||
const PASO: usize = 20;
|
||||
/// Lado de una celda, en pixeles.
|
||||
const LADO: usize = 16;
|
||||
/// Celdas que caben en una fila.
|
||||
const POR_FILA: usize = ANCHO / PASO;
|
||||
/// Celdas que caben en la rejilla entera — el techo de lo que se pinta.
|
||||
const MAX_CELDAS: usize = POR_FILA * (ALTO / PASO);
|
||||
|
||||
/// Indigo casi negro: el fondo del lienzo de la cronista.
|
||||
const FONDO: u32 = 0x0E_14_22;
|
||||
/// Ambar calido: una celda por arranque registrado.
|
||||
const CELDA: u32 = 0xF2_B2_33;
|
||||
/// Verde: el DAG se recorrio integro de la raiz al primer eslabon.
|
||||
const VERDE: u32 = 0x35_C4_6A;
|
||||
/// Rojo: la cadena se rompio — un objeto no resolvio.
|
||||
const ROJO: u32 = 0xD4_1E_2C;
|
||||
|
||||
/// El lienzo de la aplicacion, en SU propia memoria lineal.
|
||||
static mut LIENZO: [u32; ANCHO * ALTO] = [0; ANCHO * ALTO];
|
||||
|
||||
// --- Buferes de intercambio con las capacidades `sys_object_*`. El kernel lee
|
||||
// y escribe hashes y datos AQUI, siempre dentro de esta memoria lineal. ---
|
||||
/// El hash de la raiz anterior — la cabeza de la cadena al arrancar.
|
||||
static mut HASH_RAIZ: [u8; 32] = [0; 32];
|
||||
/// El hash del objeto que esta cronista graba en este arranque.
|
||||
static mut HASH_NUEVO: [u8; 32] = [0; 32];
|
||||
/// Hash de trabajo para recorrer la cadena del DAG.
|
||||
static mut HASH_AUX: [u8; 32] = [0; 32];
|
||||
/// Los ocho bytes del numero de arranque, de ida y de vuelta del grafo.
|
||||
static mut DATOS_IO: [u8; 8] = [0; 8];
|
||||
|
||||
/// Preparacion: el kernel la invoca UNA sola vez. Aqui ocurre toda la cronica —
|
||||
/// leer el grafo, grabar el eslabon nuevo, verificar el DAG y pintar.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn init() {
|
||||
// 1. ¿Hay ya una raiz? Es la cabeza de la cadena de arranques anteriores.
|
||||
let tiene_raiz = unsafe { sys_object_raiz(core::ptr::addr_of_mut!(HASH_RAIZ) as u32) } == 1;
|
||||
|
||||
// 2. El numero del ultimo arranque vive en los `datos` de esa raiz.
|
||||
let mut previo: u64 = 0;
|
||||
if tiene_raiz {
|
||||
let leidos = unsafe {
|
||||
sys_object_datos(
|
||||
core::ptr::addr_of!(HASH_RAIZ) as u32,
|
||||
core::ptr::addr_of_mut!(DATOS_IO) as u32,
|
||||
8,
|
||||
)
|
||||
};
|
||||
if leidos == 8 {
|
||||
// SEGURIDAD: lectura de un escalar `Copy` de un estatico propio.
|
||||
previo = u64::from_le_bytes(unsafe { *core::ptr::addr_of!(DATOS_IO) });
|
||||
}
|
||||
}
|
||||
let cuenta = previo + 1;
|
||||
|
||||
// 3. Grabar el objeto de ESTE arranque. Sus `datos` son el numero de
|
||||
// arranque; su unico hijo, la raiz anterior — el eslabon nuevo del DAG.
|
||||
// SEGURIDAD: escritura de un escalar `Copy` a un estatico propio.
|
||||
unsafe {
|
||||
*core::ptr::addr_of_mut!(DATOS_IO) = cuenta.to_le_bytes();
|
||||
}
|
||||
let (hijos_ptr, hijos_cnt) = if tiene_raiz {
|
||||
(core::ptr::addr_of!(HASH_RAIZ) as u32, 1u32)
|
||||
} else {
|
||||
(0u32, 0u32)
|
||||
};
|
||||
let grabado = unsafe {
|
||||
sys_object_put(
|
||||
core::ptr::addr_of!(DATOS_IO) as u32,
|
||||
8,
|
||||
hijos_ptr,
|
||||
hijos_cnt,
|
||||
core::ptr::addr_of_mut!(HASH_NUEVO) as u32,
|
||||
)
|
||||
};
|
||||
|
||||
// 4. Coronar el objeto nuevo como raiz y verificar la integridad del DAG.
|
||||
let mut integro = false;
|
||||
if grabado == 0
|
||||
&& unsafe { sys_object_fijar_raiz(core::ptr::addr_of!(HASH_NUEVO) as u32) } == 0
|
||||
{
|
||||
integro = verificar_cadena(cuenta);
|
||||
}
|
||||
|
||||
// 5. Pintar la cronica: una celda por arranque, un testigo de integridad.
|
||||
pintar(cuenta, integro);
|
||||
}
|
||||
|
||||
/// Un fotograma de trabajo. El numero de arranque no cambia durante una sesion:
|
||||
/// la cronica que `init` pinto persiste en el lienzo del kernel. `tick` solo
|
||||
/// cede el control, fiel al ABI cooperativo — no toda app necesita redibujar.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn tick() {}
|
||||
|
||||
/// Recorre la cadena del DAG desde el objeto recien grabado, descendiendo por
|
||||
/// el hijo 0, y comprueba que su profundidad coincide con el numero de
|
||||
/// arranque. Si coincide, el grafo entero se leyo de vuelta del disco integro.
|
||||
fn verificar_cadena(cuenta: u64) -> bool {
|
||||
// Partir del objeto recien grabado.
|
||||
// SEGURIDAD: copia de un arreglo `Copy` entre dos estaticos propios.
|
||||
unsafe {
|
||||
*core::ptr::addr_of_mut!(HASH_AUX) = *core::ptr::addr_of!(HASH_NUEVO);
|
||||
}
|
||||
let mut profundidad: u64 = 0;
|
||||
loop {
|
||||
profundidad += 1;
|
||||
// `sys_object_hijo` lee el hash de HASH_AUX y, si hay hijo, escribe el
|
||||
// del hijo 0 en el MISMO bufer: la cadena desciende un eslabon.
|
||||
let hijos = unsafe {
|
||||
sys_object_hijo(
|
||||
core::ptr::addr_of!(HASH_AUX) as u32,
|
||||
0,
|
||||
core::ptr::addr_of_mut!(HASH_AUX) as u32,
|
||||
)
|
||||
};
|
||||
// Sin hijos: fin de la cadena — el primer arranque de todos. Un valor
|
||||
// negativo seria un objeto que no resolvio: la cadena estaria rota.
|
||||
if hijos <= 0 || profundidad >= 4096 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
profundidad == cuenta
|
||||
}
|
||||
|
||||
/// Pinta la cronica: el fondo, una celda ambar por arranque y, en la esquina,
|
||||
/// el testigo de integridad del grafo.
|
||||
fn pintar(cuenta: u64, integro: bool) {
|
||||
// SEGURIDAD: durante `init` esta es la unica via de acceso a LIENZO, y el
|
||||
// kernel jamas reentra el modulo mientras `init` corre.
|
||||
let lienzo: &mut [u32] = unsafe { &mut *core::ptr::addr_of_mut!(LIENZO) };
|
||||
for pixel in lienzo.iter_mut() {
|
||||
*pixel = FONDO;
|
||||
}
|
||||
|
||||
// Una celda ambar por cada arranque registrado, dispuestas en rejilla.
|
||||
let celdas = (cuenta as usize).min(MAX_CELDAS);
|
||||
for i in 0..celdas {
|
||||
let x = (i % POR_FILA) * PASO + 2;
|
||||
let y = (i / POR_FILA) * PASO + 2;
|
||||
rellenar(lienzo, x, y, LADO, LADO, CELDA);
|
||||
}
|
||||
|
||||
// El testigo de integridad: verde si la cadena se recorrio entera de la
|
||||
// raiz al primer eslabon, rojo si algo se rompio.
|
||||
let testigo = if integro { VERDE } else { ROJO };
|
||||
rellenar(lienzo, ANCHO - 14, 4, 10, 10, testigo);
|
||||
|
||||
// SEGURIDAD: `sys_render_frame` es una capacidad del host; el (ptr, len)
|
||||
// describe nuestra propia memoria lineal y el host lo verifica sin piedad.
|
||||
unsafe {
|
||||
sys_render_frame(lienzo.as_ptr() as u32, (ANCHO * ALTO * 4) as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Rellena un rectangulo, recortado con firmeza a los limites del lienzo.
|
||||
fn rellenar(lienzo: &mut [u32], x: usize, y: usize, ancho: usize, alto: usize, color: u32) {
|
||||
let x1 = (x + ancho).min(ANCHO);
|
||||
let y1 = (y + alto).min(ALTO);
|
||||
let mut fila = y;
|
||||
while fila < y1 {
|
||||
let base = fila * ANCHO;
|
||||
let mut col = x;
|
||||
while col < x1 {
|
||||
lienzo[base + col] = color;
|
||||
col += 1;
|
||||
}
|
||||
fila += 1;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user