veridian_kernel/virt/
devices.rs1#[cfg(feature = "alloc")]
4extern crate alloc;
5
6#[cfg(feature = "alloc")]
7use alloc::{boxed::Box, collections::BTreeMap, vec::Vec};
8
9use super::VmError;
10
11pub trait VirtualDevice: Send {
12 fn handle_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> Result<(), VmError>;
13 fn name(&self) -> &str;
14 fn base_port(&self) -> u16;
15 fn port_count(&self) -> u16;
16}
17
18const UART_BUFFER_SIZE: usize = 256;
19
20pub struct VirtualUart {
21 base: u16,
22 #[cfg(feature = "alloc")]
23 output_buffer: Vec<u8>,
24 line_status: u8,
25}
26
27impl VirtualUart {
28 pub fn new(base: u16) -> Self {
29 Self {
30 base,
31 #[cfg(feature = "alloc")]
32 output_buffer: Vec::with_capacity(UART_BUFFER_SIZE),
33 line_status: 0x60,
34 }
35 }
36
37 fn write_byte(&mut self, byte: u8) {
38 #[cfg(feature = "alloc")]
39 {
40 self.output_buffer.push(byte);
41 if byte == b'\n' || self.output_buffer.len() >= UART_BUFFER_SIZE {
42 self.flush();
43 }
44 }
45 #[cfg(not(feature = "alloc"))]
46 {
47 let _ = byte;
48 }
49 }
50
51 fn read_status(&self) -> u8 {
52 self.line_status
53 }
54
55 #[cfg(feature = "alloc")]
56 fn flush(&mut self) {
57 if !self.output_buffer.is_empty() {
58 for &b in &self.output_buffer {
59 if b.is_ascii() {
60 crate::print!("{}", b as char);
61 }
62 }
63 self.output_buffer.clear();
64 }
65 }
66}
67
68impl VirtualDevice for VirtualUart {
69 fn handle_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> Result<(), VmError> {
70 let offset = port - self.base;
71 match offset {
72 0 => {
73 if is_write {
74 if let Some(&b) = data.first() {
75 self.write_byte(b);
76 }
77 } else if let Some(d) = data.first_mut() {
78 *d = 0xFF;
79 }
80 }
81 5 => {
82 if !is_write {
83 if let Some(d) = data.first_mut() {
84 *d = self.read_status();
85 }
86 }
87 }
88 1..=4 | 6 | 7 => {
89 if !is_write {
90 if let Some(d) = data.first_mut() {
91 *d = 0x00;
92 }
93 }
94 }
95 _ => {}
96 }
97 Ok(())
98 }
99 fn name(&self) -> &str {
100 "8250 UART"
101 }
102 fn base_port(&self) -> u16 {
103 self.base
104 }
105 fn port_count(&self) -> u16 {
106 8
107 }
108}
109
110pub struct VirtualPic {
111 base: u16,
112 mask: u8,
113 isr: u8,
114 is_master: bool,
115}
116
117impl VirtualPic {
118 pub fn new(base: u16) -> Self {
119 Self {
120 base,
121 mask: 0xFF,
122 isr: 0,
123 is_master: base == 0x20,
124 }
125 }
126}
127
128impl VirtualDevice for VirtualPic {
129 fn handle_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> Result<(), VmError> {
130 let offset = port - self.base;
131 match offset {
132 0 => {
133 if is_write {
134 if let Some(&b) = data.first() {
135 if b & 0x10 != 0 {
136 self.mask = 0xFF;
137 self.isr = 0;
138 } else if b == 0x20 {
139 self.isr = 0;
140 }
141 }
142 } else if let Some(d) = data.first_mut() {
143 *d = self.isr;
144 }
145 }
146 1 => {
147 if is_write {
148 if let Some(&b) = data.first() {
149 self.mask = b;
150 }
151 } else if let Some(d) = data.first_mut() {
152 *d = self.mask;
153 }
154 }
155 _ => {}
156 }
157 Ok(())
158 }
159 fn name(&self) -> &str {
160 if self.is_master {
161 "8259A PIC (master)"
162 } else {
163 "8259A PIC (slave)"
164 }
165 }
166 fn base_port(&self) -> u16 {
167 self.base
168 }
169 fn port_count(&self) -> u16 {
170 2
171 }
172}
173
174#[cfg(feature = "alloc")]
175struct DeviceRegistration {
176 base: u16,
177 size: u16,
178 device: Box<dyn VirtualDevice>,
179}
180
181#[cfg(feature = "alloc")]
182pub struct DeviceManager {
183 devices: BTreeMap<u16, DeviceRegistration>,
184}
185
186#[cfg(feature = "alloc")]
187impl DeviceManager {
188 pub fn new() -> Self {
189 Self {
190 devices: BTreeMap::new(),
191 }
192 }
193
194 pub fn register_device(&mut self, base: u16, size: u16, device: Box<dyn VirtualDevice>) {
195 self.devices
196 .insert(base, DeviceRegistration { base, size, device });
197 }
198
199 pub fn handle_io(&mut self, port: u16, is_write: bool, data: &mut [u8]) -> Result<(), VmError> {
200 for reg in self.devices.values_mut() {
201 if port >= reg.base && port < reg.base + reg.size {
202 return reg.device.handle_io(port, is_write, data);
203 }
204 }
205 if !is_write {
206 for b in data.iter_mut() {
207 *b = 0xFF;
208 }
209 }
210 Ok(())
211 }
212
213 pub fn device_count(&self) -> usize {
214 self.devices.len()
215 }
216
217 pub fn list_devices(&self) {
218 for reg in self.devices.values() {
219 crate::println!(
220 " [vdev] {} at ports 0x{:04x}-0x{:04x}",
221 reg.device.name(),
222 reg.base,
223 reg.base + reg.size - 1
224 );
225 }
226 }
227
228 pub fn with_standard_devices() -> Self {
229 let mut mgr = Self::new();
230 mgr.register_device(0x3F8, 8, Box::new(VirtualUart::new(0x3F8)));
231 mgr.register_device(0x2F8, 8, Box::new(VirtualUart::new(0x2F8)));
232 mgr.register_device(0x20, 2, Box::new(VirtualPic::new(0x20)));
233 mgr.register_device(0xA0, 2, Box::new(VirtualPic::new(0xA0)));
234 mgr
235 }
236}
237
238#[cfg(feature = "alloc")]
239impl Default for DeviceManager {
240 fn default() -> Self {
241 Self::new()
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use super::*;
248
249 #[test]
250 fn test_uart_write() {
251 let mut uart = VirtualUart::new(0x3F8);
252 let mut data = [b'A'];
253 assert!(uart.handle_io(0x3F8, true, &mut data).is_ok());
254 }
255
256 #[test]
257 fn test_uart_status() {
258 let mut uart = VirtualUart::new(0x3F8);
259 let mut data = [0u8];
260 assert!(uart.handle_io(0x3FD, false, &mut data).is_ok());
261 assert_eq!(data[0], 0x60);
262 }
263
264 #[test]
265 fn test_pic_eoi() {
266 let mut pic = VirtualPic::new(0x20);
267 pic.isr = 1;
268 let mut data = [0x20];
269 assert!(pic.handle_io(0x20, true, &mut data).is_ok());
270 assert_eq!(pic.isr, 0);
271 }
272
273 #[test]
274 fn test_device_manager() {
275 let mut mgr = DeviceManager::new();
276 mgr.register_device(0x3F8, 8, Box::new(VirtualUart::new(0x3F8)));
277 assert_eq!(mgr.device_count(), 1);
278 let mut data = [b'X'];
279 assert!(mgr.handle_io(0x3F8, true, &mut data).is_ok());
280 }
281
282 #[test]
283 fn test_standard_devices() {
284 let mgr = DeviceManager::with_standard_devices();
285 assert_eq!(mgr.device_count(), 4);
286 }
287}