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