Nothing to see here, move along
at main 103 lines 3.0 kB view raw
1use core::sync::atomic::{AtomicU32, Ordering}; 2 3use x86_64::PhysAddr; 4 5use crate::mem::addr; 6use crate::mem::phys::BitmapFrameAllocator; 7 8const MAX_RING_FRAMES: usize = 16; 9const PAGE_SIZE: usize = 4096; 10const HEADER_SIZE: usize = 16; 11 12#[repr(C)] 13struct RingHeader { 14 write_head: AtomicU32, 15 read_tail: AtomicU32, 16 capacity: u32, 17 _reserved: u32, 18} 19 20#[allow(dead_code)] 21struct ConsoleRingState { 22 header: *mut RingHeader, 23 data: *mut u8, 24 capacity: u32, 25 phys_addrs: [u64; MAX_RING_FRAMES], 26 frame_count: u16, 27} 28 29unsafe impl Send for ConsoleRingState {} 30unsafe impl Sync for ConsoleRingState {} 31 32static mut RING_STATE: Option<ConsoleRingState> = None; 33 34pub fn init(frame_count: u16) { 35 assert!( 36 (frame_count as usize) <= MAX_RING_FRAMES && frame_count > 0, 37 "console ring: frame_count out of range" 38 ); 39 40 let allocator = BitmapFrameAllocator; 41 let phys_base = allocator 42 .allocate_contiguous(frame_count as usize) 43 .expect("console ring: failed to allocate contiguous frames"); 44 45 let mut phys_addrs = [0u64; MAX_RING_FRAMES]; 46 (0..frame_count as usize).fold((), |(), i| { 47 let frame_phys = PhysAddr::new(phys_base.as_u64() + (i as u64) * PAGE_SIZE as u64); 48 addr::zero_frame(frame_phys); 49 crate::mem::refcount::increment(frame_phys).expect("console ring: refcount init failed"); 50 phys_addrs[i] = frame_phys.as_u64(); 51 }); 52 53 let virt_base = addr::phys_to_virt(phys_base); 54 let header = virt_base.as_mut_ptr::<RingHeader>(); 55 let data = unsafe { (header as *mut u8).add(HEADER_SIZE) }; 56 let capacity = (frame_count as u32) * (PAGE_SIZE as u32) - (HEADER_SIZE as u32); 57 58 unsafe { 59 (*header).write_head = AtomicU32::new(0); 60 (*header).read_tail = AtomicU32::new(0); 61 (*header).capacity = capacity; 62 (*header)._reserved = 0; 63 64 RING_STATE = Some(ConsoleRingState { 65 header, 66 data, 67 capacity, 68 phys_addrs, 69 frame_count, 70 }); 71 } 72} 73 74#[allow(clippy::deref_addrof)] 75pub fn ring_frame_info() -> Option<([u64; MAX_RING_FRAMES], u16)> { 76 let state = unsafe { &*(&raw const RING_STATE) }; 77 state.as_ref().map(|s| (s.phys_addrs, s.frame_count)) 78} 79 80#[allow(clippy::deref_addrof)] 81pub fn write_bytes(bytes: &[u8]) { 82 let state = unsafe { &*(&raw const RING_STATE) }; 83 let state = match state.as_ref() { 84 Some(s) => s, 85 None => return, 86 }; 87 88 let header = unsafe { &*state.header }; 89 let head = header.write_head.load(Ordering::Relaxed); 90 let cap = state.capacity; 91 92 bytes 93 .iter() 94 .enumerate() 95 .fold(head, |current_head, (_i, &b)| { 96 let idx = current_head % cap; 97 unsafe { state.data.add(idx as usize).write_volatile(b) }; 98 current_head.wrapping_add(1) 99 }); 100 101 let new_head = head.wrapping_add(bytes.len() as u32); 102 header.write_head.store(new_head, Ordering::Release); 103}