tawasuyu

tawasuyu/brahman

Rust 582TOML 222Markdown 73JSON 198635 Definitions

⎇ 07ab095d4202aa5ff30d9a109e610d517a434e74 renaser/apps/pregon/src/lib.rs Rust · 276 lines · 8.8 KB History Who touched what raw

feat(renaser): Fase 19 — voz del userspace hacia la red (pregon) 07ab095d4 · sergio ·

1// =============================================================================
2//  renaser :: apps/pregon — Fase 19 :: voz del userspace hacia la red
3// -----------------------------------------------------------------------------
4//  La Fase 18 hizo que el kernel pudiera hablar con la red; la Fase 19 le da la
5//  misma capacidad a los apps via `sys_net_*`. `pregon` es el primer app que
6//  la usa: al arrancar pide su MAC al host, anuncia su presencia con un frame
7//  Ethernet broadcast (EtherType experimental 0x88B5) y, en cada `tick`, drena
8//  un paquete de la cola RX y lo muestra en pantalla.
9//
10//  El kernel envia tambien al arrancar un ARP request al gateway de QEMU
11//  (Fase 18); `pregon` recibira su respuesta como uno de los primeros paquetes
12//  RX — visible aqui en la linea «ultimo».
13// =============================================================================
14
15#![no_std]
16
17use font8x8::legacy::BASIC_LEGACY;
18
19#[link(wasm_import_module = "renaser")]
20extern "C" {
21    fn sys_render_frame(ptr: u32, len: u32);
22    fn sys_net_mac(salida: u32) -> i32;
23    fn sys_net_enviar(ptr: u32, len: u32) -> i32;
24    fn sys_net_recibir(salida: u32, capacidad: u32) -> i32;
25}
26
27#[panic_handler]
28fn al_fallar(_: &core::panic::PanicInfo) -> ! {
29    loop {}
30}
31
32// --- Geometria del lienzo ----------------------------------------------------
33
34const ANCHO: usize = 480;
35const ALTO: usize = 160;
36const PASO: usize = 16;
37const MARGEN: usize = 16;
38
39const FONDO: u32 = 0x0A_18_30;
40const TINTA: u32 = 0xE8_EC_F4;
41const TINTA_TENUE: u32 = 0x6A_70_80;
42const ETIQUETA: u32 = 0x8B_5C_F6;
43
44// --- Constantes del paquete que enviamos ------------------------------------
45
46const ETHER_TYPE_RENASER: u16 = 0x88B5;
47const MENSAJE: &[u8; 28] = b"renaser :: hola desde mi red";
48const FRAME_LEN: usize = 14 + 28;
49
50// --- Estado del app ---------------------------------------------------------
51
52static mut MAC: [u8; 6] = [0; 6];
53static mut MAC_OK: bool = false;
54static mut TX: u32 = 0;
55static mut RX: u32 = 0;
56static mut BUFFER_RX: [u8; 1600] = [0; 1600];
57static mut ULTIMA_LEN: usize = 0;
58static mut LIENZO: [u32; ANCHO * ALTO] = [0; ANCHO * ALTO];
59
60// --- ABI del userspace ------------------------------------------------------
61
62#[no_mangle]
63pub extern "C" fn init() {
64    // 1. Pedir la MAC al host. -1 significa «no hay red montada».
65    let mac = unsafe { &mut *core::ptr::addr_of_mut!(MAC) };
66    // SEGURIDAD: `sys_net_mac` escribe seis bytes en (ptr, 6); el host lo valida.
67    let r = unsafe { sys_net_mac(mac.as_mut_ptr() as u32) };
68    if r == 0 {
69        unsafe {
70            MAC_OK = true;
71        }
72        // 2. Anunciar la presencia con un broadcast Ethernet de EtherType
73        //    experimental + un mensaje legible. El payload aparece tal cual en
74        //    cualquier pcap, sin descifrar nada.
75        let mut frame = [0u8; FRAME_LEN];
76        frame[0..6].copy_from_slice(&[0xff; 6]); // destino: broadcast
77        frame[6..12].copy_from_slice(mac);
78        frame[12..14].copy_from_slice(&ETHER_TYPE_RENASER.to_be_bytes());
79        frame[14..].copy_from_slice(MENSAJE);
80        // SEGURIDAD: `sys_net_enviar` lee (ptr, len) de nuestra memoria.
81        let r = unsafe { sys_net_enviar(frame.as_ptr() as u32, frame.len() as u32) };
82        if r == 0 {
83            unsafe {
84                TX += 1;
85            }
86        }
87    }
88    pintar();
89}
90
91#[no_mangle]
92pub extern "C" fn tick() {
93    // Drenar UN paquete por tick — si la cola RX tiene mas, se atendera en
94    // las proximas vueltas. Cero coste cuando no hay nada que leer.
95    let buf = unsafe { &mut *core::ptr::addr_of_mut!(BUFFER_RX) };
96    let n = unsafe { sys_net_recibir(buf.as_mut_ptr() as u32, buf.len() as u32) };
97    if n > 0 {
98        unsafe {
99            RX += 1;
100            ULTIMA_LEN = n as usize;
101        }
102    }
103    pintar();
104}
105
106// --- Renderizado ------------------------------------------------------------
107
108fn pintar() {
109    let lienzo = unsafe { &mut *core::ptr::addr_of_mut!(LIENZO) };
110    for p in lienzo.iter_mut() {
111        *p = FONDO;
112    }
113
114    // Titulo + subrayado.
115    pintar_texto(lienzo, b"pregon :: voz hacia la red", MARGEN, 8, ETIQUETA);
116    let y_linea = 8 + PASO + 4;
117    for x in MARGEN..(ANCHO - MARGEN) {
118        lienzo[y_linea * ANCHO + x] = ETIQUETA;
119        lienzo[(y_linea + 1) * ANCHO + x] = ETIQUETA;
120    }
121
122    let mac_ok = unsafe { MAC_OK };
123    if !mac_ok {
124        pintar_texto(lienzo, b"sin red -- no hay tarjeta montada", MARGEN, 48, TINTA);
125        volcar(lienzo);
126        return;
127    }
128
129    let mac = unsafe { &*core::ptr::addr_of!(MAC) };
130    let tx = unsafe { TX };
131    let rx = unsafe { RX };
132
133    // Linea MAC: "mac: xx:xx:xx:xx:xx:xx"
134    {
135        let mut linea = [b' '; 22];
136        linea[0..5].copy_from_slice(b"mac: ");
137        let mut p = 5;
138        for (i, &b) in mac.iter().enumerate() {
139            let par = hex_byte(b);
140            linea[p..p + 2].copy_from_slice(&par);
141            p += 2;
142            if i < 5 {
143                linea[p] = b':';
144                p += 1;
145            }
146        }
147        pintar_texto(lienzo, &linea, MARGEN, 44, TINTA);
148    }
149
150    // Linea TX/RX: "tx: N    rx: M"
151    {
152        let mut linea = [b' '; 20];
153        linea[0..4].copy_from_slice(b"tx: ");
154        let mut buf = [0u8; 10];
155        let s = dec(tx, &mut buf);
156        linea[4..4 + s.len()].copy_from_slice(s);
157        let p = 4 + s.len() + 4;
158        if p + 4 <= linea.len() {
159            linea[p..p + 4].copy_from_slice(b"rx: ");
160            let mut buf2 = [0u8; 10];
161            let s2 = dec(rx, &mut buf2);
162            let q = p + 4;
163            if q + s2.len() <= linea.len() {
164                linea[q..q + s2.len()].copy_from_slice(s2);
165            }
166        }
167        pintar_texto(lienzo, &linea, MARGEN, 72, TINTA);
168    }
169
170    // Linea «ultimo»: cuantos bytes, tipo y src.
171    let len = unsafe { ULTIMA_LEN };
172    if len >= 14 {
173        let buf = unsafe { &*core::ptr::addr_of!(BUFFER_RX) };
174        let etype = u16::from_be_bytes([buf[12], buf[13]]);
175        // Linea 1: "ultimo: N bytes  type=0x????"
176        let mut linea = [b' '; 30];
177        linea[0..8].copy_from_slice(b"ultimo: ");
178        let mut dbuf = [0u8; 10];
179        let s = dec(len as u32, &mut dbuf);
180        linea[8..8 + s.len()].copy_from_slice(s);
181        let mut p = 8 + s.len();
182        linea[p..p + 8].copy_from_slice(b" bytes  ");
183        p += 8;
184        if p + 7 <= linea.len() {
185            linea[p..p + 7].copy_from_slice(b"type=0x");
186            p += 7;
187            let hi = hex_byte((etype >> 8) as u8);
188            let lo = hex_byte((etype & 0xff) as u8);
189            if p + 4 <= linea.len() {
190                linea[p..p + 2].copy_from_slice(&hi);
191                linea[p + 2..p + 4].copy_from_slice(&lo);
192            }
193        }
194        pintar_texto(lienzo, &linea, MARGEN, 104, TINTA_TENUE);
195
196        // Linea 2: "src: xx:xx:xx:xx:xx:xx"
197        let src = &buf[6..12];
198        let mut linea2 = [b' '; 22];
199        linea2[0..5].copy_from_slice(b"src: ");
200        let mut p = 5;
201        for (i, &b) in src.iter().enumerate() {
202            let par = hex_byte(b);
203            linea2[p..p + 2].copy_from_slice(&par);
204            p += 2;
205            if i < 5 {
206                linea2[p] = b':';
207                p += 1;
208            }
209        }
210        pintar_texto(lienzo, &linea2, MARGEN, 132, TINTA);
211    } else {
212        pintar_texto(lienzo, b"esperando primer paquete...", MARGEN, 104, TINTA_TENUE);
213    }
214
215    volcar(lienzo);
216}
217
218fn volcar(lienzo: &[u32]) {
219    // SEGURIDAD: el host valida (ptr, len) contra nuestra memoria lineal.
220    unsafe {
221        sys_render_frame(lienzo.as_ptr() as u32, (ANCHO * ALTO * 4) as u32);
222    }
223}
224
225fn pintar_texto(lienzo: &mut [u32], texto: &[u8], x: usize, y: usize, color: u32) {
226    let mut cx = x;
227    for &c in texto {
228        if cx + PASO > ANCHO {
229            break;
230        }
231        pintar_glifo(lienzo, c, cx, y, color);
232        cx += PASO;
233    }
234}
235
236fn pintar_glifo(lienzo: &mut [u32], c: u8, x: usize, y: usize, color: u32) {
237    let glifo = if (c as usize) < 128 {
238        BASIC_LEGACY[c as usize]
239    } else {
240        BASIC_LEGACY[b'?' as usize]
241    };
242    for row in 0..8 {
243        for col in 0..8 {
244            if glifo[row] & (1 << col) != 0 {
245                let px = x + col * 2;
246                let py = y + row * 2;
247                if px + 1 >= ANCHO || py + 1 >= ALTO {
248                    continue;
249                }
250                lienzo[py * ANCHO + px] = color;
251                lienzo[py * ANCHO + px + 1] = color;
252                lienzo[(py + 1) * ANCHO + px] = color;
253                lienzo[(py + 1) * ANCHO + px + 1] = color;
254            }
255        }
256    }
257}
258
259fn hex_byte(b: u8) -> [u8; 2] {
260    let n = |x: u8| if x < 10 { b'0' + x } else { b'a' + (x - 10) };
261    [n(b >> 4), n(b & 0xf)]
262}
263
264fn dec(mut n: u32, buf: &mut [u8; 10]) -> &[u8] {
265    if n == 0 {
266        buf[0] = b'0';
267        return &buf[..1];
268    }
269    let mut i = 10;
270    while n > 0 {
271        i -= 1;
272        buf[i] = b'0' + (n % 10) as u8;
273        n /= 10;
274    }
275    &buf[i..]
276}