tawasuyu

tawasuyu/brahman

Rust 582TOML 222Markdown 83JSON 198635 Sutichaykuna

⎇ 5c462e6d307addd58614a8c4495f4becda04e4b2 renaser/kernel/src/baliza.rs Rust · 128 siq'ikuna · 4.9 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat: integra renaser (kernel SASOS bare-metal) al monorepo e2272c0ed · sergio ·

1// =============================================================================
2//  renaser :: kernel/src/baliza.rs — la red de seguridad visual del sistema
3// -----------------------------------------------------------------------------
4//  Sin consola de texto que valga cuando el sistema cae: si renaser colapsa, lo
5//  DIBUJA. La baliza publica —de forma atomica y sin cerrojos— los datos
6//  minimos del framebuffer, de modo que los manejadores de fallo puedan pintar
7//  una franja de advertencia incluso cuando el resto del kernel ya no es fiable.
8// =============================================================================
9
10use core::panic::PanicInfo;
11use core::ptr;
12use core::sync::atomic::{AtomicPtr, AtomicU32, AtomicUsize, Ordering};
13
14use crate::grafico::{escribir_pixel_volatil, Pantalla};
15
16/// Datos del framebuffer expuestos a los manejadores de fallo. Todo son
17/// atomicos: la baliza es intrinsecamente `Sync`, sin cerrojos.
18pub(crate) struct BalizaPanico {
19    base: AtomicPtr<u8>,
20    paso_bytes: AtomicUsize,
21    ancho: AtomicUsize,
22    alto: AtomicUsize,
23    bytes_por_pixel: AtomicUsize,
24    /// Rojo de alerta de colapso, ya codificado al formato de la pantalla.
25    pixel_alerta: AtomicU32,
26    /// Naranja de agotamiento de memoria, ya codificado.
27    pixel_oom: AtomicU32,
28}
29
30impl BalizaPanico {
31    /// Baliza apagada: sin pantalla publicada todavia.
32    const fn apagada() -> BalizaPanico {
33        BalizaPanico {
34            base: AtomicPtr::new(ptr::null_mut()),
35            paso_bytes: AtomicUsize::new(0),
36            ancho: AtomicUsize::new(0),
37            alto: AtomicUsize::new(0),
38            bytes_por_pixel: AtomicUsize::new(0),
39            pixel_alerta: AtomicU32::new(0),
40            pixel_oom: AtomicU32::new(0),
41        }
42    }
43
44    /// Enciende la baliza con los datos de una pantalla viva.
45    pub(crate) fn encender(&self, pantalla: &Pantalla, pixel_alerta: u32, pixel_oom: u32) {
46        self.paso_bytes.store(pantalla.paso_bytes, Ordering::Relaxed);
47        self.ancho.store(pantalla.ancho, Ordering::Relaxed);
48        self.alto.store(pantalla.alto, Ordering::Relaxed);
49        self.bytes_por_pixel
50            .store(pantalla.bytes_por_pixel, Ordering::Relaxed);
51        self.pixel_alerta.store(pixel_alerta, Ordering::Relaxed);
52        self.pixel_oom.store(pixel_oom, Ordering::Relaxed);
53        // La base se publica de ultima, con semantica `Release`.
54        self.base.store(pantalla.base, Ordering::Release);
55    }
56
57    /// Pinta, directa y volatilmente, una banda horizontal sobre el framebuffer
58    /// fisico. Es la herramienta de los manejadores de fallo: no confia ni en
59    /// el lienzo, ni en el heap, ni en estructura dinamica alguna.
60    fn pintar_banda(&self, y0: usize, altura: usize, pixel: u32) {
61        let base = self.base.load(Ordering::Acquire);
62        if base.is_null() {
63            return;
64        }
65        let ancho = self.ancho.load(Ordering::Relaxed);
66        let alto = self.alto.load(Ordering::Relaxed);
67        let paso = self.paso_bytes.load(Ordering::Relaxed);
68        let bpp = self.bytes_por_pixel.load(Ordering::Relaxed);
69
70        let y_fin = (y0 + altura).min(alto);
71        let mut y = y0.min(alto);
72        while y < y_fin {
73            let fila = y * paso;
74            let mut x = 0;
75            while x < ancho {
76                // SEGURIDAD: (x, y) esta acotado por las dimensiones que la
77                // baliza publico desde una pantalla real.
78                unsafe {
79                    escribir_pixel_volatil(base.add(fila + x * bpp), pixel, bpp);
80                }
81                x += 1;
82            }
83            y += 1;
84        }
85    }
86
87    /// Altura de la franja de advertencia: ~8 % de la pantalla.
88    fn franja(&self) -> usize {
89        let alto = self.alto.load(Ordering::Relaxed);
90        if alto == 0 {
91            0
92        } else {
93            (alto / 12).max(1)
94        }
95    }
96}
97
98/// Instancia global de la baliza. Comienza apagada y se enciende en el arranque.
99pub(crate) static BALIZA_PANICO: BalizaPanico = BalizaPanico::apagada();
100
101// =============================================================================
102//  MANEJADORES DE FALLO — cuando el sistema colapsa, lo DIBUJA
103// =============================================================================
104
105/// Si renaser colapsa, tatuamos una franja ROJA en lo alto del framebuffer.
106#[panic_handler]
107fn al_colapsar(_info: &PanicInfo) -> ! {
108    x86_64::instructions::interrupts::disable();
109    BALIZA_PANICO.pintar_banda(
110        0,
111        BALIZA_PANICO.franja(),
112        BALIZA_PANICO.pixel_alerta.load(Ordering::Relaxed),
113    );
114    crate::detener()
115}
116
117/// Si el heap se agota, tatuamos una franja NARANJA: un fallo distinto al
118/// colapso, y distinguible de un vistazo.
119#[alloc_error_handler]
120fn al_agotar_memoria(_disposicion: core::alloc::Layout) -> ! {
121    x86_64::instructions::interrupts::disable();
122    BALIZA_PANICO.pintar_banda(
123        0,
124        BALIZA_PANICO.franja(),
125        BALIZA_PANICO.pixel_oom.load(Ordering::Relaxed),
126    );
127    crate::detener()
128}