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:
sergio
2026-05-22 14:37:14 +00:00
parent 1c6aafbc24
commit e2272c0ed3
55 changed files with 6668 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "hello_wasm"
version = "0.1.0"
+28
View File
@@ -0,0 +1,28 @@
# =============================================================================
# renaser :: apps/hello_wasm — primera aplicacion del userspace aislado
# -----------------------------------------------------------------------------
# No es un ELF: es un modulo WebAssembly puro. Se compila para wasm32 y el
# kernel lo ejecuta dentro de wasmi, encerrado en su propia memoria lineal.
# Tiene su propio `[workspace]`: queda fuera del espacio de trabajo del kernel.
# =============================================================================
[package]
name = "hello_wasm"
version = "0.1.0"
edition = "2021"
description = "renaser :: app WASM de prueba — un cuadrado movil dirigido por teclado"
[workspace]
# `cdylib` produce un modulo `.wasm` que exporta funciones — el formato que
# wasmi instancia. La aplicacion solo habla con el kernel por funciones del host.
[lib]
crate-type = ["cdylib"]
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
opt-level = "s"
lto = true
+140
View File
@@ -0,0 +1,140 @@
// =============================================================================
// renaser :: apps/hello_wasm — Fase 4/5 :: el primer ciudadano del userspace
// -----------------------------------------------------------------------------
// Esta aplicacion vive DENTRO de su propia memoria lineal de WebAssembly. No
// conoce la MMU, no conoce los anillos de privilegio de la CPU: su unica via
// hacia el mundo son las dos capacidades que el kernel le inyecta. Lo que no
// este importado, sencillamente, no tiene camino fisico que recorrer.
//
// FASE 5 :: el ABI deja de ser un `run()` que se queda dentro para siempre.
// Ahora la app exporta `init()` —preparacion, una sola vez— y `tick()` —un
// fotograma de trabajo, y RETORNA—. Ese retorno es el punto de cesion
// cooperativa: el kernel recupera el control y atiende a las demas apps.
// =============================================================================
#![no_std]
// --- Las dos UNICAS capacidades que el kernel `renaser` expone al modulo. ---
#[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);
/// Devuelve el ultimo scancode crudo del teclado, o 0 si no hay ninguno.
fn sys_get_scancode() -> u32;
}
/// 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: el host rechaza cualquier fotograma de
// un tamaño que no sea, exactamente, el de su ventana. ---
const ANCHO: usize = 480;
const ALTO: usize = 560;
const LADO: usize = 96;
const PASO: i32 = 24;
/// Azul nocturno: el fondo del lienzo de la aplicacion.
const FONDO: u32 = 0x0A_18_30;
/// Ambar: el cuadrado que el usuario gobierna.
const CUADRO: u32 = 0xFF_B0_00;
/// El lienzo de la aplicacion, en SU propia memoria lineal. El kernel jamas lo
/// ve directamente: solo recibe el (ptr, len) que cada fotograma le entrega.
static mut LIENZO: [u32; ANCHO * ALTO] = [0; ANCHO * ALTO];
/// Posicion del cuadrado. Vive entre fotogramas en la memoria lineal del modulo
/// — el estado persiste porque la instancia, en la Fase 5, ya no es efimera.
static mut POS_X: i32 = 0;
static mut POS_Y: i32 = 0;
/// Preparacion: el kernel la invoca UNA sola vez, al cargar el modulo. Pinta el
/// fondo, centra el cuadrado y vuelca el primer fotograma.
#[no_mangle]
pub extern "C" fn init() {
// SEGURIDAD: durante `init` y `tick` esta es la unica via de acceso a
// LIENZO, y el kernel jamas reentra el modulo mientras una de ellas corre.
let lienzo: &mut [u32] = unsafe { &mut *core::ptr::addr_of_mut!(LIENZO) };
for pixel in lienzo.iter_mut() {
*pixel = FONDO;
}
let x = (ANCHO / 2 - LADO / 2) as i32;
let y = (ALTO / 2 - LADO / 2) as i32;
rellenar(lienzo, x, y, CUADRO);
// SEGURIDAD: escritura de escalares `Copy`; no se crea referencia alguna.
unsafe {
POS_X = x;
POS_Y = y;
}
volcar(lienzo);
}
/// Un fotograma de trabajo: escucha el teclado, mueve el cuadrado, vuelca la
/// imagen y RETORNA. El retorno cede la CPU al kernel y a las apps vecinas.
#[no_mangle]
pub extern "C" fn tick() {
let lienzo: &mut [u32] = unsafe { &mut *core::ptr::addr_of_mut!(LIENZO) };
let (mut x, mut y) = unsafe { (POS_X, POS_Y) };
// 1. Escuchar al teclado a traves de la capacidad del host.
let (dx, dy) = match unsafe { sys_get_scancode() } {
0x11 => (0, -PASO), // tecla W -> arriba
0x1F => (0, PASO), // tecla S -> abajo
0x1E => (-PASO, 0), // tecla A -> izquierda
0x20 => (PASO, 0), // tecla D -> derecha
_ => (0, 0),
};
// 2. Borrar el cuadrado anterior repintando su hueco con el fondo.
rellenar(lienzo, x, y, FONDO);
// 3. Moverlo, manteniendolo siempre dentro del lienzo.
x = (x + dx).clamp(0, (ANCHO - LADO) as i32);
y = (y + dy).clamp(0, (ALTO - LADO) as i32);
// 4. Dibujar el cuadrado en su nueva posicion y guardar el estado.
rellenar(lienzo, x, y, CUADRO);
unsafe {
POS_X = x;
POS_Y = y;
}
// 5. Volcar el fotograma: el host lo compondra dentro de nuestra region.
volcar(lienzo);
}
/// Entrega el lienzo completo al kernel. El (ptr, len) apunta SIEMPRE dentro de
/// nuestra memoria lineal, y su tamaño es, exactamente, el de la region.
fn volcar(lienzo: &[u32]) {
// 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 cuadrado de lado `LADO`, con su esquina en (x, y), recortado con
/// firmeza a los limites del lienzo.
fn rellenar(lienzo: &mut [u32], x: i32, y: i32, color: u32) {
let x0 = x.max(0) as usize;
let y0 = y.max(0) as usize;
let x1 = (x0 + LADO).min(ANCHO);
let y1 = (y0 + LADO).min(ALTO);
let mut fila = y0;
while fila < y1 {
let base = fila * ANCHO;
let mut col = x0;
while col < x1 {
lienzo[base + col] = color;
col += 1;
}
fila += 1;
}
}