1use base::debug;
16use base::warn;
17use base::Event;
18use hypervisor::PicInitState;
19use hypervisor::PicSelect;
20use hypervisor::PicState;
21use snapshot::AnySnapshot;
22
23use crate::bus::BusAccessInfo;
24use crate::pci::CrosvmDeviceId;
25use crate::BusDevice;
26use crate::DeviceId;
27use crate::Suspendable;
28
29pub struct Pic {
30 interrupt_request: bool,
32 resample_events: Vec<Vec<Event>>,
35 pics: [PicState; 2],
37}
38
39const PIC_PRIMARY: u64 = 0x20;
41const PIC_PRIMARY_COMMAND: u64 = PIC_PRIMARY;
42const PIC_PRIMARY_DATA: u64 = PIC_PRIMARY + 1;
43const PIC_PRIMARY_ELCR: u64 = 0x4d0;
44
45const PIC_SECONDARY: u64 = 0xa0;
46const PIC_SECONDARY_COMMAND: u64 = PIC_SECONDARY;
47const PIC_SECONDARY_DATA: u64 = PIC_SECONDARY + 1;
48const PIC_SECONDARY_ELCR: u64 = 0x4d1;
49
50const LEVEL_HIGH: bool = true;
51const LEVEL_LOW: bool = false;
52const INVALID_PRIORITY: u8 = 8;
53const SPURIOUS_IRQ: u8 = 0x07;
54const PRIMARY_PIC_CASCADE_PIN: u8 = 2;
55const PRIMARY_PIC_CASCADE_PIN_MASK: u8 = 0x04;
56const PRIMARY_PIC_MAX_IRQ: u8 = 7;
57
58const ICW1_MASK: u8 = 0x10;
60const OCW3_MASK: u8 = 0x08;
61
62const ICW1_NEED_ICW4: u8 = 0x01; const ICW1_SINGLE_PIC_MODE: u8 = 0x02;
65const ICW1_LEVEL_TRIGGER_MODE: u8 = 0x08;
66
67const ICW2_IRQ_BASE_MASK: u8 = 0xf8;
68
69const ICW4_SPECIAL_FULLY_NESTED_MODE: u8 = 0x10;
70const ICW4_AUTO_EOI: u8 = 0x02;
71
72const OCW2_IRQ_MASK: u8 = 0x07;
74const OCW2_COMMAND_MASK: u8 = 0xe0;
75#[derive(Debug, Clone, Copy, PartialEq, enumn::N)]
76enum Ocw2 {
77 RotateAutoEoiClear = 0x00,
78 NonSpecificEoi = 0x20,
79 NoOp = 0x40,
80 SpecificEoi = 0x60,
81 RotateAutoEoiSet = 0x80,
82 RotateNonSpecificEoi = 0xa0,
83 SetPriority = 0xc0,
84 RotateSpecificEoi = 0xe0,
85}
86
87const OCW3_POLL_COMMAND: u8 = 0x04;
89const OCW3_READ_REGISTER: u8 = 0x02;
90const OCW3_READ_ISR: u8 = 0x01;
92const OCW3_SPECIAL_MASK: u8 = 0x40;
93const OCW3_SPECIAL_MASK_VALUE: u8 = 0x20;
94
95impl BusDevice for Pic {
96 fn device_id(&self) -> DeviceId {
97 CrosvmDeviceId::Pic.into()
98 }
99
100 fn debug_label(&self) -> String {
101 "userspace PIC".to_string()
102 }
103
104 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
105 if data.len() != 1 {
106 warn!("PIC: Bad write size: {}", data.len());
107 return;
108 }
109 match info.address {
110 PIC_PRIMARY_COMMAND => self.pic_write_command(PicSelect::Primary, data[0]),
111 PIC_PRIMARY_DATA => self.pic_write_data(PicSelect::Primary, data[0]),
112 PIC_PRIMARY_ELCR => self.pic_write_elcr(PicSelect::Primary, data[0]),
113 PIC_SECONDARY_COMMAND => self.pic_write_command(PicSelect::Secondary, data[0]),
114 PIC_SECONDARY_DATA => self.pic_write_data(PicSelect::Secondary, data[0]),
115 PIC_SECONDARY_ELCR => self.pic_write_elcr(PicSelect::Secondary, data[0]),
116 _ => warn!("PIC: Invalid write to {}", info),
117 }
118 }
119
120 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
121 if data.len() != 1 {
122 warn!("PIC: Bad read size: {}", data.len());
123 return;
124 }
125 data[0] = match info.address {
126 PIC_PRIMARY_COMMAND => self.pic_read_command(PicSelect::Primary),
127 PIC_PRIMARY_DATA => self.pic_read_data(PicSelect::Primary),
128 PIC_PRIMARY_ELCR => self.pic_read_elcr(PicSelect::Primary),
129 PIC_SECONDARY_COMMAND => self.pic_read_command(PicSelect::Secondary),
130 PIC_SECONDARY_DATA => self.pic_read_data(PicSelect::Secondary),
131 PIC_SECONDARY_ELCR => self.pic_read_elcr(PicSelect::Secondary),
132 _ => {
133 warn!("PIC: Invalid read from {}", info);
134 return;
135 }
136 };
137 }
138}
139
140impl Pic {
141 pub fn new() -> Pic {
142 let mut primary_pic: PicState = Default::default();
143 let mut secondary_pic: PicState = Default::default();
144 primary_pic.elcr_mask = !((1 << 0) | (1 << 1) | (1 << 2));
151 secondary_pic.elcr_mask = !((1 << 0) | (1 << 5));
154
155 Pic {
156 interrupt_request: false,
157 pics: [primary_pic, secondary_pic],
158 resample_events: Vec::new(),
159 }
160 }
161
162 pub fn get_pic_state(&self, select: PicSelect) -> PicState {
164 self.pics[select as usize]
165 }
166
167 pub fn set_pic_state(&mut self, select: PicSelect, state: &PicState) {
169 self.pics[select as usize] = *state;
170 }
171
172 pub fn register_resample_events(&mut self, resample_events: Vec<Vec<Event>>) {
173 self.resample_events = resample_events;
174 }
175
176 pub fn service_irq(&mut self, irq: u8, level: bool) -> bool {
177 assert!(irq <= 15, "Unexpectedly high value irq: {irq} vs 15");
178
179 let pic = if irq <= PRIMARY_PIC_MAX_IRQ {
180 PicSelect::Primary
181 } else {
182 PicSelect::Secondary
183 };
184 Pic::set_irq_internal(&mut self.pics[pic as usize], irq & 7, level);
185
186 self.update_irq()
187 }
188
189 pub fn masked(&self) -> bool {
191 self.pics[PicSelect::Primary as usize].imr == 0xFF
192 }
193
194 pub fn has_interrupt(&self) -> bool {
196 self.get_irq(PicSelect::Primary).is_some()
197 }
198
199 pub fn interrupt_requested(&self) -> bool {
201 self.interrupt_request
202 }
203
204 pub fn get_external_interrupt(&mut self) -> Option<u8> {
206 self.interrupt_request = false;
207 let irq_primary = self.get_irq(PicSelect::Primary)?;
215
216 self.interrupt_ack(PicSelect::Primary, irq_primary);
217 let int_num = if irq_primary == PRIMARY_PIC_CASCADE_PIN {
218 let irq_secondary = if let Some(irq) = self.get_irq(PicSelect::Secondary) {
220 self.interrupt_ack(PicSelect::Secondary, irq);
221 irq
222 } else {
223 SPURIOUS_IRQ
224 };
225 self.pics[PicSelect::Secondary as usize].irq_base + irq_secondary
226 } else {
227 self.pics[PicSelect::Primary as usize].irq_base + irq_primary
228 };
229
230 self.update_irq();
231 Some(int_num)
232 }
233
234 fn pic_read_command(&mut self, pic_type: PicSelect) -> u8 {
235 if self.pics[pic_type as usize].poll {
236 let (ret, update_irq_needed) = self.poll_read(pic_type);
237 self.pics[pic_type as usize].poll = false;
238
239 if update_irq_needed {
240 self.update_irq();
241 }
242
243 ret
244 } else if self.pics[pic_type as usize].read_reg_select {
245 self.pics[pic_type as usize].isr
246 } else {
247 self.pics[pic_type as usize].irr
248 }
249 }
250
251 fn pic_read_data(&mut self, pic_type: PicSelect) -> u8 {
252 if self.pics[pic_type as usize].poll {
253 let (ret, update_needed) = self.poll_read(pic_type);
254 self.pics[pic_type as usize].poll = false;
255 if update_needed {
256 self.update_irq();
257 }
258 ret
259 } else {
260 self.pics[pic_type as usize].imr
261 }
262 }
263
264 fn pic_read_elcr(&mut self, pic_type: PicSelect) -> u8 {
265 self.pics[pic_type as usize].elcr
266 }
267
268 fn pic_write_command(&mut self, pic_type: PicSelect, value: u8) {
269 if value & ICW1_MASK != 0 {
270 self.init_command_word_1(pic_type, value);
271 } else if value & OCW3_MASK != 0 {
272 Pic::operation_command_word_3(&mut self.pics[pic_type as usize], value);
273 } else {
274 self.operation_command_word_2(pic_type, value);
275 }
276 }
277
278 fn pic_write_data(&mut self, pic_type: PicSelect, value: u8) {
279 match self.pics[pic_type as usize].init_state {
280 PicInitState::Icw1 => {
281 self.pics[pic_type as usize].imr = value;
282 self.update_irq();
283 }
284 PicInitState::Icw2 => {
285 self.pics[pic_type as usize].irq_base = value & ICW2_IRQ_BASE_MASK;
286 self.pics[pic_type as usize].init_state = PicInitState::Icw3;
287 }
288 PicInitState::Icw3 => {
289 if self.pics[pic_type as usize].use_4_byte_icw {
290 self.pics[pic_type as usize].init_state = PicInitState::Icw4;
291 } else {
292 self.pics[pic_type as usize].init_state = PicInitState::Icw1;
293 }
294 }
295 PicInitState::Icw4 => {
296 self.pics[pic_type as usize].special_fully_nested_mode =
297 (value & ICW4_SPECIAL_FULLY_NESTED_MODE) != 0;
298 self.pics[pic_type as usize].auto_eoi = (value & ICW4_AUTO_EOI) != 0;
299 self.pics[pic_type as usize].init_state = PicInitState::Icw1;
300 }
301 }
302 }
303
304 fn pic_write_elcr(&mut self, pic_type: PicSelect, value: u8) {
305 self.pics[pic_type as usize].elcr = value & !self.pics[pic_type as usize].elcr;
306 }
307
308 fn reset_pic(&mut self, pic_type: PicSelect) {
309 let pic = &mut self.pics[pic_type as usize];
310
311 let edge_irr = pic.irr & !pic.elcr;
312
313 pic.last_irr = 0;
314 pic.irr &= pic.elcr;
315 pic.imr = 0;
316 pic.priority_add = 0;
317 pic.special_mask = false;
318 pic.read_reg_select = false;
319 if !pic.use_4_byte_icw {
320 pic.special_fully_nested_mode = false;
321 pic.auto_eoi = false;
322 }
323 pic.init_state = PicInitState::Icw2;
324
325 for irq in 0..8 {
326 if edge_irr & (1 << irq) != 0 {
327 self.clear_isr(pic_type, irq);
328 }
329 }
330 }
331
332 fn poll_read(&mut self, pic_type: PicSelect) -> (u8, bool) {
334 if let Some(irq) = self.get_irq(pic_type) {
335 if pic_type == PicSelect::Secondary {
336 self.pics[PicSelect::Primary as usize].isr &= !PRIMARY_PIC_CASCADE_PIN_MASK;
337 self.pics[PicSelect::Primary as usize].irr &= !PRIMARY_PIC_CASCADE_PIN_MASK;
338 }
339 self.pics[pic_type as usize].irr &= !(1 << irq);
340 self.clear_isr(pic_type, irq);
341 let update_irq_needed =
342 pic_type == PicSelect::Secondary && irq != PRIMARY_PIC_CASCADE_PIN;
343 (irq, update_irq_needed)
344 } else {
345 (SPURIOUS_IRQ, true)
347 }
348 }
349
350 fn get_irq(&self, pic_type: PicSelect) -> Option<u8> {
351 let pic = &self.pics[pic_type as usize];
352 let mut irq_bitmap = pic.irr & !pic.imr;
353 let priority = Pic::get_priority(pic, irq_bitmap)?;
354
355 irq_bitmap = pic.isr;
358 if pic_type == PicSelect::Primary && pic.special_fully_nested_mode {
359 irq_bitmap &= !PRIMARY_PIC_CASCADE_PIN_MASK;
360 }
361 let new_priority = Pic::get_priority(pic, irq_bitmap).unwrap_or(INVALID_PRIORITY);
362 if priority < new_priority {
363 Some((priority + pic.priority_add) & 7)
365 } else {
366 None
367 }
368 }
369
370 fn clear_isr(&mut self, pic_type: PicSelect, irq: u8) {
371 let pic = &mut self.pics[pic_type as usize];
372
373 assert!(irq <= 7, "Unexpectedly high value for irq: {irq} vs 7");
374 pic.isr &= !(1 << irq);
375 Pic::set_irq_internal(pic, irq, false);
376 let irq = if pic_type == PicSelect::Primary {
377 irq
378 } else {
379 irq + 8
380 };
381 if let Some(resample_events) = self.resample_events.get(irq as usize) {
382 for resample_evt in resample_events {
383 resample_evt.signal().unwrap();
384 }
385 }
386 }
387
388 fn update_irq(&mut self) -> bool {
389 if self.get_irq(PicSelect::Secondary).is_some() {
390 Pic::set_irq_internal(
392 &mut self.pics[PicSelect::Primary as usize],
393 PRIMARY_PIC_CASCADE_PIN,
394 LEVEL_HIGH,
395 );
396 Pic::set_irq_internal(
397 &mut self.pics[PicSelect::Primary as usize],
398 PRIMARY_PIC_CASCADE_PIN,
399 LEVEL_LOW,
400 );
401 }
402
403 if self.get_irq(PicSelect::Primary).is_some() {
404 self.interrupt_request = true;
405 true
408 } else {
409 false
410 }
411 }
412
413 fn set_irq_internal(pic: &mut PicState, irq: u8, level: bool) {
415 assert!(irq <= 7, "Unexpectedly high value for irq: {irq} vs 7");
416 let irq_bitmap = 1 << irq;
417 if (pic.elcr & irq_bitmap) != 0 {
418 if level {
420 pic.irr |= irq_bitmap;
422 pic.last_irr |= irq_bitmap;
423 } else {
424 pic.irr &= !irq_bitmap;
425 pic.last_irr &= !irq_bitmap;
426 }
427 } else {
428 if level {
430 if (pic.last_irr & irq_bitmap) == 0 {
431 pic.irr |= irq_bitmap;
433 }
434 pic.last_irr |= irq_bitmap;
435 } else {
436 pic.last_irr &= !irq_bitmap;
437 }
438 }
439 }
440
441 fn get_priority(pic: &PicState, irq_bitmap: u8) -> Option<u8> {
442 if irq_bitmap == 0 {
443 None
444 } else {
445 let mut priority = 0;
448 let mut priority_mask = 1 << ((priority + pic.priority_add) & 7);
449 while (irq_bitmap & priority_mask) == 0 {
450 priority += 1;
451 priority_mask = 1 << ((priority + pic.priority_add) & 7);
452 }
453 Some(priority)
454 }
455 }
456
457 fn interrupt_ack(&mut self, pic_type: PicSelect, irq: u8) {
461 let pic = &mut self.pics[pic_type as usize];
462
463 assert!(irq <= 7, "Unexpectedly high value for irq: {irq} vs 7");
464
465 let irq_bitmap = 1 << irq;
466 pic.isr |= irq_bitmap;
467
468 if (pic.elcr & irq_bitmap) == 0 {
469 pic.irr &= !irq_bitmap;
470 }
471
472 if pic.auto_eoi {
473 if pic.rotate_on_auto_eoi {
474 pic.priority_add = (irq + 1) & 7;
475 }
476 self.clear_isr(pic_type, irq);
477 }
478 }
479
480 fn init_command_word_1(&mut self, pic_type: PicSelect, value: u8) {
481 let pic = &mut self.pics[pic_type as usize];
482 pic.use_4_byte_icw = (value & ICW1_NEED_ICW4) != 0;
483 if (value & ICW1_SINGLE_PIC_MODE) != 0 {
484 debug!("PIC: Single PIC mode not supported.");
485 }
486 if (value & ICW1_LEVEL_TRIGGER_MODE) != 0 {
487 debug!("PIC: Level triggered IRQ not supported.");
488 }
489 self.reset_pic(pic_type);
490 }
491
492 fn operation_command_word_2(&mut self, pic_type: PicSelect, value: u8) {
493 let mut irq = value & OCW2_IRQ_MASK;
494 if let Some(cmd) = Ocw2::n(value & OCW2_COMMAND_MASK) {
495 match cmd {
496 Ocw2::RotateAutoEoiSet => self.pics[pic_type as usize].rotate_on_auto_eoi = true,
497 Ocw2::RotateAutoEoiClear => self.pics[pic_type as usize].rotate_on_auto_eoi = false,
498 Ocw2::NonSpecificEoi | Ocw2::RotateNonSpecificEoi => {
499 if let Some(priority) = Pic::get_priority(
500 &self.pics[pic_type as usize],
501 self.pics[pic_type as usize].isr,
502 ) {
503 irq = (priority + self.pics[pic_type as usize].priority_add) & 7;
504 if cmd == Ocw2::RotateNonSpecificEoi {
505 self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
506 }
507 self.clear_isr(pic_type, irq);
508 self.update_irq();
509 }
510 }
511 Ocw2::SpecificEoi => {
512 self.clear_isr(pic_type, irq);
513 self.update_irq();
514 }
515 Ocw2::SetPriority => {
516 self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
517 self.update_irq();
518 }
519 Ocw2::RotateSpecificEoi => {
520 self.pics[pic_type as usize].priority_add = (irq + 1) & 7;
521 self.clear_isr(pic_type, irq);
522 self.update_irq();
523 }
524 Ocw2::NoOp => {} }
526 }
527 }
528
529 fn operation_command_word_3(pic: &mut PicState, value: u8) {
530 if value & OCW3_POLL_COMMAND != 0 {
531 pic.poll = true;
532 }
533 if value & OCW3_READ_REGISTER != 0 {
534 pic.read_reg_select = value & OCW3_READ_ISR != 0;
536 }
537 if value & OCW3_SPECIAL_MASK != 0 {
538 pic.special_mask = value & OCW3_SPECIAL_MASK_VALUE != 0;
539 }
540 }
541}
542
543impl Default for Pic {
544 fn default() -> Self {
545 Self::new()
546 }
547}
548
549impl Suspendable for Pic {
552 fn sleep(&mut self) -> anyhow::Result<()> {
553 Ok(())
554 }
555
556 fn wake(&mut self) -> anyhow::Result<()> {
557 Ok(())
558 }
559
560 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
561 AnySnapshot::to_any(())
562 }
563
564 fn restore(&mut self, _data: AnySnapshot) -> anyhow::Result<()> {
565 Ok(())
566 }
567}
568
569#[cfg(test)]
570mod tests {
571 const FULLY_NESTED_NO_AUTO_EOI: u8 = 0x11;
573 use super::*;
574
575 struct TestData {
576 pic: Pic,
577 }
578
579 fn pic_bus_address(address: u64) -> BusAccessInfo {
580 let base_address = if (PIC_PRIMARY..PIC_PRIMARY + 0x2).contains(&address) {
584 PIC_PRIMARY
585 } else if (PIC_SECONDARY..PIC_SECONDARY + 0x2).contains(&address) {
586 PIC_SECONDARY
587 } else if (PIC_PRIMARY_ELCR..PIC_PRIMARY_ELCR + 0x2).contains(&address) {
588 PIC_PRIMARY_ELCR
589 } else {
590 panic!("invalid PIC address: {address:#x}");
591 };
592 BusAccessInfo {
593 offset: address - base_address,
594 address,
595 id: 0,
596 }
597 }
598
599 fn set_up() -> TestData {
600 let mut pic = Pic::new();
601 pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0]);
603 pic.write(pic_bus_address(PIC_SECONDARY_ELCR), &[0]);
604 TestData { pic }
605 }
606
607 fn icw_init(pic: &mut Pic, pic_type: PicSelect, icw1: u8, icw2: u8, icw3: u8, icw4: u8) {
609 let command_offset = match pic_type {
610 PicSelect::Primary => PIC_PRIMARY_COMMAND,
611 PicSelect::Secondary => PIC_SECONDARY_COMMAND,
612 };
613 let data_offset = match pic_type {
614 PicSelect::Primary => PIC_PRIMARY_DATA,
615 PicSelect::Secondary => PIC_SECONDARY_DATA,
616 };
617
618 pic.write(pic_bus_address(command_offset), &[icw1]);
619 pic.write(pic_bus_address(data_offset), &[icw2]);
620 pic.write(pic_bus_address(data_offset), &[icw3]);
621 pic.write(pic_bus_address(data_offset), &[icw4]);
622 }
623
624 fn icw_init_primary(pic: &mut Pic) {
626 icw_init(pic, PicSelect::Primary, 0x11, 0x08, 0xff, 0x13);
631 }
632
633 fn icw_init_secondary(pic: &mut Pic) {
635 icw_init(pic, PicSelect::Secondary, 0x11, 0x70, 0xff, 0x13);
640 }
641
642 fn icw_init_both_with_icw4(pic: &mut Pic, icw4: u8) {
644 icw_init(pic, PicSelect::Primary, 0x11, 0x08, 0xff, icw4);
648 icw_init(pic, PicSelect::Secondary, 0x11, 0x70, 0xff, icw4);
652 }
653
654 fn icw_init_both(pic: &mut Pic) {
655 icw_init_primary(pic);
656 icw_init_secondary(pic);
657 }
658
659 #[test]
661 fn write_read_elcr() {
662 let mut data = set_up();
663 let data_write = [0x5f];
664 let mut data_read = [0];
665
666 data.pic
667 .write(pic_bus_address(PIC_PRIMARY_ELCR), &data_write);
668 data.pic
669 .read(pic_bus_address(PIC_PRIMARY_ELCR), &mut data_read);
670 assert_eq!(data_read, data_write);
671
672 data.pic
673 .write(pic_bus_address(PIC_SECONDARY_ELCR), &data_write);
674 data.pic
675 .read(pic_bus_address(PIC_SECONDARY_ELCR), &mut data_read);
676 assert_eq!(data_read, data_write);
677 }
678
679 #[test]
681 fn icw_2_step() {
682 let mut data = set_up();
683
684 let mut data_write = [0x10];
686 data.pic
687 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &data_write);
688
689 data_write[0] = 0x08;
690 data.pic
691 .write(pic_bus_address(PIC_PRIMARY_DATA), &data_write);
692
693 data_write[0] = 0xff;
694 data.pic
695 .write(pic_bus_address(PIC_PRIMARY_DATA), &data_write);
696
697 assert_eq!(
698 data.pic.pics[PicSelect::Primary as usize].init_state,
699 PicInitState::Icw1
700 );
701 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irq_base, 0x08);
702 assert_eq!(
703 data.pic.pics[PicSelect::Primary as usize].use_4_byte_icw,
704 false
705 );
706 }
707
708 #[test]
710 fn initial_values() {
711 let mut data = set_up();
712 icw_init_primary(&mut data.pic);
713
714 let primary_pic = &data.pic.pics[PicSelect::Primary as usize];
715 assert_eq!(primary_pic.last_irr, 0x00);
716 assert_eq!(primary_pic.irr, 0x00);
717 assert_eq!(primary_pic.imr, 0x00);
718 assert_eq!(primary_pic.isr, 0x00);
719 assert_eq!(primary_pic.priority_add, 0);
720 assert_eq!(primary_pic.irq_base, 0x08);
721 assert_eq!(primary_pic.read_reg_select, false);
722 assert_eq!(primary_pic.poll, false);
723 assert_eq!(primary_pic.special_mask, false);
724 assert_eq!(primary_pic.init_state, PicInitState::Icw1);
725 assert_eq!(primary_pic.auto_eoi, true);
726 assert_eq!(primary_pic.rotate_on_auto_eoi, false);
727 assert_eq!(primary_pic.special_fully_nested_mode, true);
728 assert_eq!(primary_pic.use_4_byte_icw, true);
729 assert_eq!(primary_pic.elcr, 0x00);
730 assert_eq!(primary_pic.elcr_mask, 0xf8);
731 }
732
733 #[test]
735 fn ocw() {
736 let mut data = set_up();
737
738 icw_init_secondary(&mut data.pic);
739
740 data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x5f]);
742
743 data.pic
745 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x80]);
746
747 data.pic
749 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0xc0]);
750
751 data.pic
753 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x6b]);
754
755 let mut data_read = [0];
756 data.pic
757 .read(pic_bus_address(PIC_SECONDARY_DATA), &mut data_read);
758 assert_eq!(data_read, [0x5f]);
759
760 let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
761
762 assert_eq!(secondary_pic.imr, 0x5f);
764
765 assert!(secondary_pic.rotate_on_auto_eoi);
767 assert_eq!(secondary_pic.priority_add, 1);
768
769 assert!(secondary_pic.special_mask);
771 assert_eq!(secondary_pic.poll, false);
772 assert!(secondary_pic.read_reg_select);
773 }
774
775 #[test]
777 fn ocw_auto_rotate_set_and_clear() {
778 let mut data = set_up();
779
780 icw_init_secondary(&mut data.pic);
781
782 data.pic
784 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x80]);
785
786 let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
787 assert!(secondary_pic.rotate_on_auto_eoi);
788
789 data.pic
791 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x00]);
792
793 let secondary_pic = &data.pic.pics[PicSelect::Secondary as usize];
794 assert!(!secondary_pic.rotate_on_auto_eoi);
795 }
796
797 #[test]
799 fn auto_eoi() {
800 let mut data = set_up();
801
802 icw_init_both(&mut data.pic);
803
804 data.pic.service_irq(12, true);
806
807 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, (1 << 4));
809 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
810 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, (1 << 2));
811 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
812
813 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
815
816 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
818 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
819 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
820 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
821 }
822
823 #[test]
828 fn fully_nested_mode_on() {
829 let mut data = set_up();
830
831 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
832
833 data.pic.service_irq(12, true);
835 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
836
837 data.pic.service_irq(8, true);
840 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0));
841
842 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
844 assert_eq!(
845 data.pic.pics[PicSelect::Secondary as usize].isr,
846 (1 << 4) + (1 << 0)
847 );
848 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
849 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
850 }
851
852 #[test]
856 fn fully_nested_mode_off() {
857 let mut data = set_up();
858
859 icw_init_both_with_icw4(&mut data.pic, 0x01);
861
862 data.pic.service_irq(12, true);
864 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
865
866 data.pic.service_irq(8, true);
867 assert_eq!(data.pic.get_external_interrupt(), None);
869
870 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 0);
871 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 4);
872 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2);
873 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
874
875 data.pic
880 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
881 data.pic
882 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0x20]);
883
884 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 0));
886
887 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
888 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 0);
889 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
890 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
891 }
892
893 #[test]
895 fn mask_irq() {
896 let mut data = set_up();
897
898 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
899
900 data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x40]);
902
903 data.pic.service_irq(14, true);
904 assert_eq!(data.pic.get_external_interrupt(), None);
905
906 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 6);
907 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
908 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
909 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
910
911 data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x00]);
914
915 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 6));
917
918 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
919 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 6);
920 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 0);
921 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 2);
922 }
923
924 #[test]
928 fn mask_multiple_irq() {
929 let mut data = set_up();
930 icw_init_both(&mut data.pic);
931
932 data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xff]);
934 data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0xff]);
935
936 data.pic.service_irq(14, true);
937 data.pic.service_irq(4, true);
938 data.pic.service_irq(12, true);
939
940 assert_eq!(data.pic.get_external_interrupt(), None);
942
943 data.pic.write(pic_bus_address(PIC_SECONDARY_DATA), &[0x00]);
945
946 assert_eq!(data.pic.get_external_interrupt(), None);
948
949 data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0xfb]);
952
953 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
956 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 6));
957
958 data.pic.write(pic_bus_address(PIC_PRIMARY_DATA), &[0x00]);
961 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
962 }
963
964 #[test]
966 fn ocw3() {
967 let mut data = set_up();
968 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
969
970 data.pic.service_irq(5, true);
973 data.pic.service_irq(4, true);
974 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
975
976 data.pic
978 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0a]);
979 let mut data_read = [0];
980 data.pic
981 .read(pic_bus_address(PIC_PRIMARY_COMMAND), &mut data_read);
982 assert_eq!(data_read[0], 1 << 5);
983
984 data.pic
986 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0b]);
987 data_read = [0];
988 data.pic
989 .read(pic_bus_address(PIC_PRIMARY_COMMAND), &mut data_read);
990 assert_eq!(data_read[0], 1 << 4);
991
992 data.pic
995 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
996
997 data.pic
999 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x0c]);
1000 data_read = [0];
1001 data.pic
1002 .read(pic_bus_address(PIC_PRIMARY_COMMAND), &mut data_read);
1003 assert_eq!(data_read[0], 5);
1004 }
1005
1006 #[test]
1009 fn fake_irq_on_primary_irq2() {
1010 let mut data = set_up();
1011 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1012
1013 data.pic.service_irq(2, true);
1015 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 7));
1017 }
1018
1019 #[test]
1021 fn edge_trigger_mode() {
1022 let mut data = set_up();
1023 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1024
1025 data.pic.service_irq(4, true);
1027 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
1029
1030 data.pic.service_irq(4, true);
1031
1032 data.pic
1035 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
1036 }
1037
1038 #[test]
1040 fn level_trigger_mode() {
1041 let mut data = set_up();
1042 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1043
1044 data.pic.write(pic_bus_address(PIC_PRIMARY_ELCR), &[0x10]);
1046
1047 data.pic.service_irq(4, true);
1049 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
1051
1052 data.pic.service_irq(4, true);
1053
1054 data.pic
1057 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
1058 }
1059
1060 #[test]
1062 fn specific_eoi() {
1063 let mut data = set_up();
1064 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1065
1066 data.pic.service_irq(4, true);
1068 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 4));
1069
1070 data.pic
1073 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x63]);
1074 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 4);
1075
1076 data.pic
1078 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x64]);
1079 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1080 }
1081
1082 #[test]
1084 fn rotate_on_auto_eoi() {
1085 let mut data = set_up();
1086 icw_init_both(&mut data.pic);
1087
1088 data.pic
1090 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x00]);
1091
1092 data.pic.service_irq(5, true);
1094 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
1095 data.pic.service_irq(5, false);
1096
1097 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1099 assert_eq!(data.pic.pics[PicSelect::Primary as usize].imr, 0);
1100 assert_eq!(data.pic.pics[PicSelect::Primary as usize].last_irr, 0);
1101 assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 0);
1102
1103 data.pic
1105 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x80]);
1106
1107 data.pic.service_irq(5, true);
1109 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
1110 data.pic.service_irq(5, false);
1111
1112 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1114 assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
1115 }
1116
1117 #[test]
1119 fn rotate_on_specific_eoi() {
1120 let mut data = set_up();
1121 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1122
1123 data.pic.service_irq(5, true);
1125 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
1126 data.pic.service_irq(5, false);
1127
1128 data.pic
1131 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0xe4]);
1132
1133 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 1 << 5);
1134
1135 data.pic
1137 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0xe5]);
1138
1139 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1140 assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
1141 }
1142
1143 #[test]
1145 fn rotate_non_specific_eoi() {
1146 let mut data = set_up();
1147 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1148
1149 data.pic.service_irq(5, true);
1151 assert_eq!(data.pic.get_external_interrupt(), Some(0x08 + 5));
1152 data.pic.service_irq(5, false);
1153
1154 data.pic
1156 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0xa0]);
1157
1158 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1160 assert_eq!(data.pic.pics[PicSelect::Primary as usize].priority_add, 6);
1161 }
1162
1163 #[test]
1165 fn cascade_irq() {
1166 let mut data = set_up();
1167 icw_init_both_with_icw4(&mut data.pic, FULLY_NESTED_NO_AUTO_EOI);
1168
1169 data.pic.service_irq(12, true);
1171
1172 assert_eq!(data.pic.pics[PicSelect::Primary as usize].irr, 1 << 2);
1173 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 1 << 4);
1174
1175 assert_eq!(data.pic.get_external_interrupt(), Some(0x70 + 4));
1176
1177 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].irr, 0);
1179 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 1 << 4);
1180
1181 data.pic
1187 .write(pic_bus_address(PIC_PRIMARY_COMMAND), &[0x20]);
1188 data.pic
1190 .write(pic_bus_address(PIC_SECONDARY_COMMAND), &[0xa0]);
1191
1192 assert_eq!(data.pic.pics[PicSelect::Primary as usize].isr, 0);
1193 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].isr, 0);
1194 assert_eq!(data.pic.pics[PicSelect::Secondary as usize].priority_add, 5);
1195 }
1196}