⎇ 07ab095d4202aa5ff30d9a109e610d517a434e74
renaser/apps/pregon/src/lib.rs
History
Who touched what
raw
feat(renaser): Fase 19 — voz del userspace hacia la red (pregon)
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(ÐER_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}