1#![warn(missing_docs)]
20
21use chipset_device::ChipsetDevice;
22use chipset_device::io::IoError;
23use chipset_device::io::IoResult;
24use chipset_device::pio::PortIoIntercept;
25use inspect::Inspect;
26use inspect::InspectMut;
27use open_enum::open_enum;
28use std::ops::RangeInclusive;
29use vmcore::device_state::ChangeDeviceState;
30use vmcore::isa_dma_channel::IsaDmaBuffer;
31use vmcore::isa_dma_channel::IsaDmaDirection;
32
33const DMA_PAGE_REGISTER_PORT_RANGE: u16 = 0x80;
36const PAGE_PORTS: RangeInclusive<u16> =
37 (DMA_PAGE_REGISTER_PORT_RANGE + 0x1)..=(DMA_PAGE_REGISTER_PORT_RANGE + 0xf);
38const CONTROLLER0_PORTS: RangeInclusive<u16> = 0x00..=0x0f;
39const CONTROLLER1_PORTS: RangeInclusive<u16> = 0xc0..=0xdf;
42
43const CHANNELS_PER_CONTROLLER: usize = 4;
44
45const PAGE_PORTS_FOR_CHANNEL: [usize; 8] = [0x7, 0x3, 0x1, 0x2, 0xF, 0xB, 0x9, 0xA];
46
47open_enum! {
48 enum ControlRegister: u16 {
50 STATUS = 0, COMMAND = 0, REQUEST = 1, MASK = 2, MODE = 3, CLEAR_FLIP_FLOP = 4, INTERMEDIATE = 5, RESET = 5, CLEAR_MASK = 6, WRITE_MASK = 7, }
61}
62
63#[derive(Debug, InspectMut)]
65pub struct DmaController {
66 state: DmaControllerState,
68}
69
70#[derive(Debug, Default, Clone, Inspect)]
71struct DmaControllerState {
72 #[inspect(iter_by_index)]
73 page_registers: [u8; 16],
74 controller0: Controller,
75 controller1: Controller,
76}
77
78impl DmaController {
79 pub fn new() -> Self {
81 Self {
82 state: DmaControllerState::default(),
83 }
84 }
85
86 fn get_controller(&mut self, channel_number: usize) -> Option<&mut Controller> {
87 if channel_number < CHANNELS_PER_CONTROLLER {
88 Some(&mut self.state.controller0)
89 } else if channel_number < CHANNELS_PER_CONTROLLER * 2 {
90 Some(&mut self.state.controller1)
91 } else {
92 None
93 }
94 }
95
96 pub fn check_transfer_size(&mut self, channel_number: usize) -> u16 {
101 let Some(controller) = self.get_controller(channel_number) else {
102 tracelimit::error_ratelimited!(?channel_number, "invalid channel number");
103 return 0;
104 };
105
106 controller.channels[channel_number % CHANNELS_PER_CONTROLLER].count
107 }
108
109 pub fn request(
113 &mut self,
114 channel_number: usize,
115 direction: IsaDmaDirection,
116 ) -> Option<IsaDmaBuffer> {
117 if channel_number >= CHANNELS_PER_CONTROLLER * 2 {
118 tracelimit::error_ratelimited!(?channel_number, "invalid channel number");
119 return None;
120 }
121
122 let page = self.state.page_registers[PAGE_PORTS_FOR_CHANNEL[channel_number]];
123
124 let controller = self.get_controller(channel_number).unwrap();
125 if controller.disabled {
126 tracelimit::warn_ratelimited!(?channel_number, "channel is disabled");
127 return None;
128 }
129
130 let channel_index = channel_number % CHANNELS_PER_CONTROLLER;
131
132 let channel = &controller.channels[channel_index];
133 if !channel.enabled {
134 tracing::warn!(
135 ?channel_number,
136 ?channel_index,
137 "channel currently disabled"
138 );
139 return None;
140 }
141
142 let transfer_type = match (channel.mode >> 2) & 0x3 {
143 0 => {
144 tracing::error!(?channel_number, "invalid request: mode is self-test");
145 return None;
146 }
147 1 => IsaDmaDirection::Write,
148 2 => IsaDmaDirection::Read,
149 _ => {
150 tracing::error!(?channel_number, "invalid request: mode is invalid");
151 return None;
152 }
153 };
154
155 if transfer_type != direction {
156 tracing::warn!(
157 ?channel_number,
158 ?channel_index,
159 "mismatch between programmed and requested transfer directions"
160 );
161 return None;
162 }
163
164 let address = channel.address as u64 | (page as u64) << 16;
165
166 controller.status &= !(1 << channel_index);
168
169 let buffer = IsaDmaBuffer {
170 address,
171 size: channel.count as usize,
172 };
173
174 Some(buffer)
175 }
176
177 pub fn complete(&mut self, channel_number: usize) {
181 let Some(controller) = self.get_controller(channel_number) else {
182 tracing::error!(?channel_number, "invalid channel number");
183 return;
184 };
185
186 let channel_index = channel_number % CHANNELS_PER_CONTROLLER;
187
188 if (controller.status & (1 << channel_index)) != 0 {
189 tracing::warn!(?channel_number, "channel was not active");
190 }
191
192 controller.status |= 1 << channel_index;
194 }
195}
196
197impl ChangeDeviceState for DmaController {
198 fn start(&mut self) {}
199
200 async fn stop(&mut self) {}
201
202 async fn reset(&mut self) {
203 self.state = Default::default();
204 }
205}
206
207impl ChipsetDevice for DmaController {
208 fn supports_pio(&mut self) -> Option<&mut dyn PortIoIntercept> {
209 Some(self)
210 }
211}
212
213impl PortIoIntercept for DmaController {
214 fn io_read(&mut self, io_port: u16, data: &mut [u8]) -> IoResult {
215 data.fill(0);
216 data[0] = if PAGE_PORTS.contains(&io_port) {
217 self.state.page_registers[io_port as usize & 0xf]
218 } else if CONTROLLER0_PORTS.contains(&io_port) {
219 match self.state.controller0.read(io_port) {
220 Ok(val) => val,
221 Err(e) => return IoResult::Err(e),
222 }
223 } else if CONTROLLER1_PORTS.contains(&io_port) {
224 match self.state.controller1.read((io_port / 2) & 0xf) {
226 Ok(val) => val,
227 Err(e) => return IoResult::Err(e),
228 }
229 } else {
230 return IoResult::Err(IoError::InvalidRegister);
231 };
232
233 IoResult::Ok
234 }
235
236 fn io_write(&mut self, io_port: u16, data: &[u8]) -> IoResult {
237 if PAGE_PORTS.contains(&io_port) {
238 self.state.page_registers[io_port as usize & 0xf] = data[0];
239 IoResult::Ok
240 } else if CONTROLLER0_PORTS.contains(&io_port) {
241 self.state.controller0.write(io_port, data[0])
242 } else if CONTROLLER1_PORTS.contains(&io_port) {
243 self.state.controller1.write((io_port / 2) & 0xf, data[0])
245 } else {
246 IoResult::Err(IoError::InvalidRegister)
247 }
248 }
249
250 fn get_static_regions(&mut self) -> &[(&str, RangeInclusive<u16>)] {
251 &[
252 ("page", PAGE_PORTS),
253 ("controller0", CONTROLLER0_PORTS),
254 ("controller1", CONTROLLER1_PORTS),
255 ]
256 }
257}
258
259#[derive(Debug, Default, Clone, Inspect)]
261struct Controller {
262 #[inspect(iter_by_index)]
263 channels: [Channel; CHANNELS_PER_CONTROLLER],
264 flip_flop_high: bool,
265 latched_address: u16,
266 latched_count: u16,
267 disabled: bool,
268 status: u8,
269}
270
271#[derive(Debug, Default, Clone, Inspect)]
272struct Channel {
273 #[inspect(hex)]
274 address: u16,
275 #[inspect(hex)]
276 count: u16,
277 #[inspect(hex)]
278 mode: u8,
279 enabled: bool,
280}
281
282impl Controller {
283 fn read(&mut self, reg: u16) -> Result<u8, IoError> {
284 let res = if reg < 8 {
285 let channel = reg as usize / 2;
286 let data = if reg % 2 == 0 {
287 if !self.flip_flop_high {
289 self.latched_address = self.channels[channel].address;
290 }
291 self.latched_address
292 } else {
293 if !self.flip_flop_high {
295 self.latched_count = self.channels[channel].count;
296 }
297 self.latched_count
298 };
299
300 self.flip_flop_high = !self.flip_flop_high;
302 if !self.flip_flop_high {
303 (data >> 8) as u8
304 } else {
305 data as u8
306 }
307 } else {
308 match ControlRegister(reg - 8) {
309 ControlRegister::STATUS => std::mem::take(&mut self.status),
310 ControlRegister::INTERMEDIATE => 0,
311 ControlRegister::WRITE_MASK => {
312 let mut data = 0xf0;
313 for (n, channel) in self.channels.iter().enumerate() {
314 if channel.enabled {
315 data |= 1 << n;
317 }
318 }
319 data
320 }
321 _ => return Err(IoError::InvalidRegister),
322 }
323 };
324
325 Ok(res)
326 }
327
328 fn write(&mut self, reg: u16, data: u8) -> IoResult {
329 if reg < 8 {
330 let channel = reg as usize / 2;
331 let mem = if reg % 2 == 0 {
332 &mut self.channels[channel].address
334 } else {
335 &mut self.channels[channel].count
336 };
337 if self.flip_flop_high {
338 *mem = (*mem & 0xff) | (data as u16) << 8
339 } else {
340 *mem = (*mem & 0xff00) | data as u16
341 }
342 self.flip_flop_high = !self.flip_flop_high;
343 } else {
344 match ControlRegister(reg - 8) {
345 ControlRegister::COMMAND => {
346 self.disabled = data != 0;
347 }
348 ControlRegister::REQUEST => {
349 self.status |= 1 << (data & 3);
353 }
354 ControlRegister::MASK => {
355 self.channels[data as usize & 3].enabled = data & 4 == 0;
356 }
357 ControlRegister::MODE => self.channels[data as usize & 3].mode = data,
358 ControlRegister::RESET => {
359 *self = Default::default();
360 }
361 ControlRegister::CLEAR_MASK => {
362 for channel in &mut self.channels {
363 channel.enabled = true;
364 }
365 }
366 ControlRegister::WRITE_MASK => {
367 for (n, channel) in self.channels.iter_mut().enumerate() {
368 channel.enabled = data & (1 << n) == 0;
369 }
370 }
371 ControlRegister::CLEAR_FLIP_FLOP => self.flip_flop_high = false,
372 _ => return IoResult::Err(IoError::InvalidRegister),
373 }
374 }
375
376 IoResult::Ok
377 }
378}
379
380mod save_restore {
381 use super::*;
382 use vmcore::save_restore::RestoreError;
383 use vmcore::save_restore::SaveError;
384 use vmcore::save_restore::SaveRestore;
385
386 mod state {
387 use mesh::payload::Protobuf;
388 use vmcore::save_restore::SavedStateRoot;
389
390 #[derive(Protobuf, SavedStateRoot)]
391 #[mesh(package = "chipset.dma")]
392 pub struct SavedState {
393 #[mesh(1)]
394 pub page_registers: [u8; 16],
395 #[mesh(2)]
396 pub controller0: SavedController,
397 #[mesh(3)]
398 pub controller1: SavedController,
399 }
400
401 #[derive(Protobuf)]
402 #[mesh(package = "chipset.dma")]
403 pub struct SavedController {
404 #[mesh(1)]
405 pub channels: [SavedChannel; 4],
406 #[mesh(2)]
407 pub flip_flop_high: bool,
408 #[mesh(3)]
409 pub latched_address: u16,
410 #[mesh(4)]
411 pub latched_count: u16,
412 #[mesh(5)]
413 pub status: u8,
414 #[mesh(6)]
415 pub disabled: bool,
416 }
417
418 #[derive(Protobuf)]
419 #[mesh(package = "chipset.dma")]
420 pub struct SavedChannel {
421 #[mesh(1)]
422 pub address: u16,
423 #[mesh(2)]
424 pub count: u16,
425 #[mesh(3)]
426 pub mode: u8,
427 #[mesh(4)]
428 pub enabled: bool,
429 }
430 }
431
432 impl SaveRestore for DmaController {
433 type SavedState = state::SavedState;
434
435 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
436 let DmaControllerState {
437 page_registers,
438 controller0,
439 controller1,
440 } = self.state.clone();
441
442 let [controller0, controller1] = [controller0, controller1].map(|con| {
443 let Controller {
444 channels,
445 flip_flop_high,
446 latched_address,
447 latched_count,
448 status,
449 disabled,
450 } = con;
451
452 state::SavedController {
453 channels: channels.map(|chan| {
454 let Channel {
455 address,
456 count,
457 mode,
458 enabled,
459 } = chan;
460
461 state::SavedChannel {
462 address,
463 count,
464 mode,
465 enabled,
466 }
467 }),
468 flip_flop_high,
469 latched_address,
470 latched_count,
471 status,
472 disabled,
473 }
474 });
475
476 let saved_state = state::SavedState {
477 page_registers,
478 controller0,
479 controller1,
480 };
481
482 Ok(saved_state)
483 }
484
485 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
486 let state::SavedState {
487 page_registers,
488 controller0,
489 controller1,
490 } = state;
491
492 let [controller0, controller1] = [controller0, controller1].map(|con| {
493 let state::SavedController {
494 channels,
495 flip_flop_high,
496 latched_address,
497 latched_count,
498 status,
499 disabled,
500 } = con;
501
502 Controller {
503 channels: channels.map(|chan| {
504 let state::SavedChannel {
505 address,
506 count,
507 mode,
508 enabled,
509 } = chan;
510
511 Channel {
512 address,
513 count,
514 mode,
515 enabled,
516 }
517 }),
518 flip_flop_high,
519 latched_address,
520 latched_count,
521 status,
522 disabled,
523 }
524 });
525
526 self.state = DmaControllerState {
527 page_registers,
528 controller0,
529 controller1,
530 };
531
532 Ok(())
533 }
534 }
535}