feat(renaser): Fase 19 — voz del userspace hacia la red (pregon)

Tres capacidades nuevas en wasm/env (12-14):

- sys_net_mac(salida) -> i32: escribe los seis bytes del MAC del
  dispositivo. 0 OK, -1 si no hay red.
- sys_net_enviar(ptr, len) -> i32: envia un frame Ethernet crudo.
  Valida rango contra la memoria lineal del modulo.
- sys_net_recibir(salida, capacidad) -> i32: drena UN paquete por
  llamada hacia el buffer del modulo. Devuelve los bytes copiados, 0
  si nada pendiente, codigos negativos diagnosticos.

Añadida red::recibir_en(buf) -> usize como su contraparte del driver:
gemelo cooperativo de drenar_rx que aterriza en un buffer del usuario.

App nueva pregon (apps/pregon/, 4.2 KiB WASM): lienzo 480x160, tipografia
8x8 (font8x8) escalada x2. Al init pide su MAC y anuncia su presencia
con un broadcast Ethernet — destino FF:FF:FF:FF:FF:FF, EtherType
experimental 0x88B5, payload ASCII 'renaser :: hola desde mi red'. En
cada tick drena un paquete con sys_net_recibir y muestra el titulo, el
MAC propio, las cuentas TX/RX, y los datos del ultimo frame entrante.

GENESIS 8 -> 9 apps (pregon en posicion 2 detras de bitacora);
CELDA_TASKBAR_ANCHO 130 -> 116 px para que las nueve pestañas + lanzador
+ reloj caben holgadas en 1280 px.

tarea_red del kernel ya no drena RX (la cola pertenece al userspace),
conserva solo el envio del ARP de prueba al arrancar.

Verificada en QEMU con -object filter-dump. El pcap captura tres frames
en orden: (1) broadcast 88B5 de pregon con su payload, (2) ARP request
del kernel, (3) ARP reply del gateway 52:55:0a:00:02:02. La consola
anuncia 'manifiesto :: 9 apps nacidas del grafo'.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-23 04:26:22 +00:00
parent b1be94e7c4
commit 07ab095d42
13 changed files with 586 additions and 39 deletions
+30 -1
View File
@@ -37,7 +37,10 @@ const PAQUETE_MAX: usize = 1600;
const PROFUNDIDAD_COLA: usize = 16;
/// EtherType experimental (rango 0x88B5-0x88B6, reservado por IEEE para uso
/// local). renaser lo usaria si quisiera definir su propio protocolo.
/// local). renaser lo usaria si quisiera definir su propio protocolo. Desde
/// la Fase 19 lo usa `pregon` desde el userspace; el kernel lo conserva como
/// referencia para diagnosticos y futuros protocolos nativos.
#[allow(dead_code)]
pub const ETHER_TYPE_RENASER: u16 = 0x88B5;
/// EtherType de ARP.
pub const ETHER_TYPE_ARP: u16 = 0x0806;
@@ -190,6 +193,7 @@ pub fn enviar(frame: &[u8]) -> Result<(), &'static str> {
/// Drena los paquetes RX pendientes y aplica `callback` a cada uno. Cada
/// bufer se recicla a la cola RX al terminar — el dispositivo tiene siempre
/// receptores listos para la proxima IRQ.
#[allow(dead_code)]
pub fn drenar_rx<F: FnMut(&[u8])>(mut callback: F) {
let Some(tarjeta) = TARJETA.get() else {
return;
@@ -211,6 +215,31 @@ pub fn drenar_rx<F: FnMut(&[u8])>(mut callback: F) {
});
}
/// Recibe UN paquete: copia su contenido en `buf` y devuelve los bytes
/// copiados, o `0` si no hay paquete pendiente. La interfaz que el host
/// expone a los apps via `sys_net_recibir` — un paquete por llamada (Fase 19).
pub fn recibir_en(buf: &mut [u8]) -> usize {
let Some(tarjeta) = TARJETA.get() else {
return 0;
};
interrupts::without_interrupts(|| {
let mut tarjeta = tarjeta.lock();
if !tarjeta.0.can_recv() {
return 0;
}
let rx = match tarjeta.0.receive() {
Ok(r) => r,
Err(_) => return 0,
};
let pkt = rx.packet();
let n = pkt.len().min(buf.len());
buf[..n].copy_from_slice(&pkt[..n]);
let _ = tarjeta.0.recycle_rx_buffer(rx);
PAQUETES_RX.fetch_add(1, Ordering::Relaxed);
n
})
}
// =============================================================================
// Composicion de un ARP request — el primer paquete que renaser saluda
// =============================================================================