Files
brahman/renaser/kernel/src/baliza.rs
T
sergio e2272c0ed3 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>
2026-05-22 14:37:14 +00:00

129 lines
4.9 KiB
Rust

// =============================================================================
// renaser :: kernel/src/baliza.rs — la red de seguridad visual del sistema
// -----------------------------------------------------------------------------
// Sin consola de texto que valga cuando el sistema cae: si renaser colapsa, lo
// DIBUJA. La baliza publica —de forma atomica y sin cerrojos— los datos
// minimos del framebuffer, de modo que los manejadores de fallo puedan pintar
// una franja de advertencia incluso cuando el resto del kernel ya no es fiable.
// =============================================================================
use core::panic::PanicInfo;
use core::ptr;
use core::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering};
use crate::grafico::{escribir_pixel_volatil, Pantalla};
/// Datos del framebuffer expuestos a los manejadores de fallo. Todo son
/// atomicos: la baliza es intrinsecamente `Sync`, sin cerrojos.
pub(crate) struct BalizaPanico {
base: AtomicPtr<u8>,
paso_bytes: AtomicUsize,
ancho: AtomicUsize,
alto: AtomicUsize,
bytes_por_pixel: AtomicUsize,
/// Rojo de alerta de colapso, ya codificado al formato de la pantalla.
pixel_alerta: AtomicU32,
/// Naranja de agotamiento de memoria, ya codificado.
pixel_oom: AtomicU32,
}
impl BalizaPanico {
/// Baliza apagada: sin pantalla publicada todavia.
const fn apagada() -> BalizaPanico {
BalizaPanico {
base: AtomicPtr::new(ptr::null_mut()),
paso_bytes: AtomicUsize::new(0),
ancho: AtomicUsize::new(0),
alto: AtomicUsize::new(0),
bytes_por_pixel: AtomicUsize::new(0),
pixel_alerta: AtomicU32::new(0),
pixel_oom: AtomicU32::new(0),
}
}
/// Enciende la baliza con los datos de una pantalla viva.
pub(crate) fn encender(&self, pantalla: &Pantalla, pixel_alerta: u32, pixel_oom: u32) {
self.paso_bytes.store(pantalla.paso_bytes, Ordering::Relaxed);
self.ancho.store(pantalla.ancho, Ordering::Relaxed);
self.alto.store(pantalla.alto, Ordering::Relaxed);
self.bytes_por_pixel
.store(pantalla.bytes_por_pixel, Ordering::Relaxed);
self.pixel_alerta.store(pixel_alerta, Ordering::Relaxed);
self.pixel_oom.store(pixel_oom, Ordering::Relaxed);
// La base se publica de ultima, con semantica `Release`.
self.base.store(pantalla.base, Ordering::Release);
}
/// Pinta, directa y volatilmente, una banda horizontal sobre el framebuffer
/// fisico. Es la herramienta de los manejadores de fallo: no confia ni en
/// el lienzo, ni en el heap, ni en estructura dinamica alguna.
fn pintar_banda(&self, y0: usize, altura: usize, pixel: u32) {
let base = self.base.load(Ordering::Acquire);
if base.is_null() {
return;
}
let ancho = self.ancho.load(Ordering::Relaxed);
let alto = self.alto.load(Ordering::Relaxed);
let paso = self.paso_bytes.load(Ordering::Relaxed);
let bpp = self.bytes_por_pixel.load(Ordering::Relaxed);
let y_fin = (y0 + altura).min(alto);
let mut y = y0.min(alto);
while y < y_fin {
let fila = y * paso;
let mut x = 0;
while x < ancho {
// SEGURIDAD: (x, y) esta acotado por las dimensiones que la
// baliza publico desde una pantalla real.
unsafe {
escribir_pixel_volatil(base.add(fila + x * bpp), pixel, bpp);
}
x += 1;
}
y += 1;
}
}
/// Altura de la franja de advertencia: ~8 % de la pantalla.
fn franja(&self) -> usize {
let alto = self.alto.load(Ordering::Relaxed);
if alto == 0 {
0
} else {
(alto / 12).max(1)
}
}
}
/// Instancia global de la baliza. Comienza apagada y se enciende en el arranque.
pub(crate) static BALIZA_PANICO: BalizaPanico = BalizaPanico::apagada();
// =============================================================================
// MANEJADORES DE FALLO — cuando el sistema colapsa, lo DIBUJA
// =============================================================================
/// Si renaser colapsa, tatuamos una franja ROJA en lo alto del framebuffer.
#[panic_handler]
fn al_colapsar(_info: &PanicInfo) -> ! {
x86_64::instructions::interrupts::disable();
BALIZA_PANICO.pintar_banda(
0,
BALIZA_PANICO.franja(),
BALIZA_PANICO.pixel_alerta.load(Ordering::Relaxed),
);
crate::detener()
}
/// Si el heap se agota, tatuamos una franja NARANJA: un fallo distinto al
/// colapso, y distinguible de un vistazo.
#[alloc_error_handler]
fn al_agotar_memoria(_disposicion: core::alloc::Layout) -> ! {
x86_64::instructions::interrupts::disable();
BALIZA_PANICO.pintar_banda(
0,
BALIZA_PANICO.franja(),
BALIZA_PANICO.pixel_oom.load(Ordering::Relaxed),
);
crate::detener()
}