Nothing to see here, move along meow
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 5.8 kB View raw
1#![no_std] 2#![no_main] 3 4mod net; 5mod virtio; 6mod virtqueue; 7 8use lancer_core::packet_ring::{PacketRingReader, PacketRingWriter}; 9use lancer_user::show; 10use lancer_user::syscall; 11use net::VirtioNetHdr; 12use virtio::RX_BUF_SIZE; 13 14const IRQ_CAP_SLOT: u64 = 3; 15const NOTIF_CAP_SLOT: u64 = 4; 16#[allow(dead_code)] 17const ENDPOINT_SLOT: u64 = 1; 18const PACKET_RING_BASE_SLOT: u64 = 64; 19const PACKET_RING_FRAME_COUNT: u64 = 16; 20const NETSTACK_NOTIF_SLOT: u64 = 7; 21const RING_BASE_VADDR: u64 = 0x4020_0000; 22const RING_HALF_SIZE: usize = 32768; 23 24fn print_mac(mac: &[u8; 6]) { 25 show!( 26 virtio, 27 "mac {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}", 28 mac[0], 29 mac[1], 30 mac[2], 31 mac[3], 32 mac[4], 33 mac[5] 34 ); 35} 36 37#[unsafe(no_mangle)] 38pub extern "C" fn lancer_main() -> ! { 39 show!(virtio, "driver starting"); 40 41 let mut dev = virtio::init(); 42 43 print_mac(&dev.mac); 44 45 let ring_ok = (0..PACKET_RING_FRAME_COUNT) 46 .all(|i| syscall::frame_map(PACKET_RING_BASE_SLOT + i, RING_BASE_VADDR + i * 4096, 1) >= 0); 47 if !ring_ok { 48 show!(virtio, error, "packet ring frame_map failed"); 49 syscall::exit(); 50 } 51 52 let rx_ring_base = RING_BASE_VADDR as *mut u8; 53 let tx_ring_base = (RING_BASE_VADDR + RING_HALF_SIZE as u64) as *mut u8; 54 55 let rx_writer = unsafe { PacketRingWriter::init(rx_ring_base, RING_HALF_SIZE, 2048) }; 56 let tx_reader = unsafe { PacketRingReader::attach(tx_ring_base, RING_HALF_SIZE) }; 57 58 show!(virtio, "ready"); 59 syscall::irq_ack(IRQ_CAP_SLOT); 60 61 loop { 62 let (status, _bits) = syscall::notify_wait(NOTIF_CAP_SLOT); 63 if status < 0 { 64 continue; 65 } 66 67 let mut rx_completed = [(0u16, 0u32); crate::virtqueue::QUEUE_SIZE as usize]; 68 let rx_count = core::iter::from_fn(|| dev.rx_queue.poll_used()) 69 .take(crate::virtqueue::QUEUE_SIZE as usize) 70 .enumerate() 71 .fold(0usize, |_, (i, entry)| { 72 rx_completed[i] = entry; 73 i + 1 74 }); 75 76 let mut pushed_any = false; 77 let mut recycle_bufs = [0u16; crate::virtqueue::QUEUE_SIZE as usize]; 78 let recycle_count = rx_completed[..rx_count].iter().enumerate().fold( 79 0usize, 80 |count, (i, &(desc_idx, total_len))| { 81 let buf_idx = match (desc_idx as usize) < dev.rx_desc_to_buf.len() { 82 true => dev.rx_desc_to_buf[desc_idx as usize] as usize, 83 false => return count, 84 }; 85 let buf_virt = dev.rx_buf_virt_base + buf_idx * RX_BUF_SIZE; 86 87 let hdr_size = VirtioNetHdr::SIZE; 88 let clamped_len = (total_len as usize).min(RX_BUF_SIZE); 89 if clamped_len > hdr_size { 90 let payload_len = clamped_len - hdr_size; 91 let payload = unsafe { 92 core::slice::from_raw_parts((buf_virt + hdr_size) as *const u8, payload_len) 93 }; 94 if rx_writer.try_push(payload) { 95 pushed_any = true; 96 } 97 } 98 99 recycle_bufs[i] = buf_idx as u16; 100 count + 1 101 }, 102 ); 103 104 recycle_bufs[..recycle_count].iter().for_each(|&buf_idx| { 105 let buf_phys = dev.rx_buf_phys(buf_idx as usize); 106 if let Some(new_desc) = dev 107 .rx_queue 108 .add_buf_single(buf_phys, RX_BUF_SIZE as u32, true) 109 { 110 dev.rx_desc_to_buf[new_desc as usize] = buf_idx; 111 } 112 }); 113 114 if rx_count > 0 { 115 dev.notify_queue(0); 116 } 117 118 if pushed_any { 119 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 1); 120 } 121 122 let mut sent_any; 123 { 124 let hdr_size = VirtioNetHdr::SIZE; 125 let zeroed_hdr = VirtioNetHdr::zeroed(); 126 let hdr_bytes: &[u8] = unsafe { 127 core::slice::from_raw_parts( 128 &zeroed_hdr as *const VirtioNetHdr as *const u8, 129 hdr_size, 130 ) 131 }; 132 133 sent_any = false; 134 135 core::iter::from_fn(|| dev.tx_queue.poll_used()) 136 .take(crate::virtqueue::QUEUE_SIZE as usize) 137 .count(); 138 139 let mut payload_buf = [0u8; 1514]; 140 core::iter::from_fn(|| match tx_reader.try_pop(&mut payload_buf) { 141 Some(payload_len) => match dev.acquire_tx_buf() { 142 Some((_buf_idx, buf_phys, buf_virt)) => { 143 let total = hdr_size + payload_len; 144 let dst = buf_virt as *mut u8; 145 unsafe { 146 core::ptr::copy_nonoverlapping(hdr_bytes.as_ptr(), dst, hdr_size); 147 core::ptr::copy_nonoverlapping( 148 payload_buf.as_ptr(), 149 dst.add(hdr_size), 150 payload_len, 151 ); 152 } 153 dev.tx_queue.add_buf_single(buf_phys, total as u32, false); 154 sent_any = true; 155 Some(()) 156 } 157 None => None, 158 }, 159 None => None, 160 }) 161 .take(virtio::TX_BUF_COUNT) 162 .count(); 163 164 if sent_any { 165 dev.notify_queue(1); 166 syscall::notify_signal(NETSTACK_NOTIF_SLOT, 2); 167 } 168 } 169 170 core::iter::from_fn(|| dev.tx_queue.poll_used()) 171 .take(crate::virtqueue::QUEUE_SIZE as usize) 172 .count(); 173 174 syscall::irq_ack(IRQ_CAP_SLOT); 175 } 176}