1use std::io::Error as IoError;
8use std::sync::Arc;
9use std::time::Duration;
10use std::time::Instant;
11
12use base::error;
13use base::warn;
14use base::Descriptor;
15use base::Error as SysError;
16use base::Event;
17use base::EventToken;
18use base::WaitContext;
19use bit_field::BitField1;
20use bit_field::*;
21use hypervisor::PitChannelState;
22use hypervisor::PitRWMode;
23use hypervisor::PitRWState;
24use hypervisor::PitState;
25use remain::sorted;
26use sync::Mutex;
27use thiserror::Error;
28
29cfg_if::cfg_if! {
30 if #[cfg(test)] {
31 use base::FakeClock as Clock;
32 use base::FakeTimer as Timer;
33 } else {
34 use base::Clock;
35 use base::Timer;
36 }
37}
38use base::TimerTrait;
39use base::WorkerThread;
40use snapshot::AnySnapshot;
41
42use crate::bus::BusAccessInfo;
43use crate::pci::CrosvmDeviceId;
44use crate::BusDevice;
45use crate::DeviceId;
46use crate::IrqEdgeEvent;
47use crate::Suspendable;
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
52enum CommandBit {
53 CommandBCD = 0x01, CommandMode = 0x0e, CommandRW = 0x30, CommandSC = 0xc0, }
58
59#[allow(dead_code)]
64#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
65enum CommandCounter {
66 CommandCounter0 = 0x00, CommandCounter1 = 0x40, CommandCounter2 = 0x80, CommandReadBack = 0xc0, }
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
74enum CommandAccess {
75 CommandLatch = 0x00, CommandRWLeast = 0x10, CommandRWMost = 0x20, CommandRWBoth = 0x30, }
80
81#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
86enum CommandMode {
87 CommandInterrupt = 0x00, CommandHWOneShot = 0x02, CommandRateGen = 0x04, CommandSquareWaveGen = 0x06, CommandSWStrobe = 0x08, CommandHWStrobe = 0x0a, }
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
98#[rustfmt::skip] enum CommandReadBackLatch {
100 CommandRBLatchBits = 0x30, CommandRBLatchBoth = 0x00, CommandRBLatchCount = 0x10, CommandRBLatchStatus = 0x20, }
107
108#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
110enum CommandReadBackCounters {
111 CommandRBCounter2 = 0x08,
113 CommandRBCounter1 = 0x04,
114 CommandRBCounter0 = 0x02,
115}
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
119#[rustfmt::skip] enum ReadBackData {
121 ReadBackOutput = 0x80, ReadBackNullCount = 0x40, }
126
127#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
129enum PortIOSpace {
130 PortCounter0Data = 0x40, PortCounter1Data = 0x41, PortCounter2Data = 0x42, PortCommand = 0x43, PortSpeaker = 0x61, }
136
137#[bitfield]
138#[derive(Clone, Copy, PartialEq, Eq)]
139pub struct SpeakerPortFields {
140 gate: BitField1,
146 speaker_on: BitField1,
147 pic_serr: BitField1,
148 iochk_enable: BitField1,
149 refresh_clock: BitField1,
152 output: BitField1,
153 iochk_nmi: BitField1,
154 serr_nmi: BitField1,
155}
156
157const FREQUENCY_HZ: u64 = 1193182;
159
160const NUM_OF_COUNTERS: usize = 3;
161
162const NANOS_PER_SEC: u64 = 1_000_000_000;
163
164const MAX_TIMER_FREQ: u32 = 65536;
165
166#[derive(EventToken)]
167enum Token {
168 TimerExpire,
170 Kill,
172}
173
174#[sorted]
175#[derive(Error, Debug)]
176pub enum PitError {
177 #[error("failed to clone event: {0}")]
179 CloneEvent(SysError),
180 #[error("failed to create event: {0}")]
182 CreateEvent(SysError),
183 #[error("failed to create poll context: {0}")]
185 CreateWaitContext(SysError),
186 #[error("failed to spawn thread: {0}")]
188 SpawnThread(IoError),
189 #[error("failed to create pit counter due to timer fd: {0}")]
191 TimerCreateError(SysError),
192 #[error("failed to wait for events: {0}")]
194 WaitError(SysError),
195}
196
197type PitResult<T> = std::result::Result<T, PitError>;
198
199pub struct Pit {
200 counters: Vec<Arc<Mutex<PitCounter>>>,
202 worker_thread: Option<WorkerThread<()>>,
206 activated: bool,
207}
208
209impl BusDevice for Pit {
210 fn debug_label(&self) -> String {
211 "userspace PIT".to_string()
212 }
213
214 fn device_id(&self) -> DeviceId {
215 CrosvmDeviceId::Pit.into()
216 }
217
218 fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
219 self.ensure_started();
220
221 if data.len() != 1 {
222 warn!("Bad write size for Pit: {}", data.len());
223 return;
224 }
225 match PortIOSpace::n(info.address as i64) {
226 Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().write_counter(data[0]),
227 Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().write_counter(data[0]),
228 Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().write_counter(data[0]),
229 Some(PortIOSpace::PortCommand) => self.command_write(data[0]),
230 Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().write_speaker(data[0]),
231 None => warn!("PIT: bad write to {}", info),
232 }
233 }
234
235 fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
236 self.ensure_started();
237
238 if data.len() != 1 {
239 warn!("Bad read size for Pit: {}", data.len());
240 return;
241 }
242 data[0] = match PortIOSpace::n(info.address as i64) {
243 Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().read_counter(),
244 Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().read_counter(),
245 Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().read_counter(),
246 Some(PortIOSpace::PortCommand) => {
250 warn!("Ignoring read to command reg");
251 0
252 }
253 Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().read_speaker(),
254 None => {
255 warn!("PIT: bad read from {}", info);
256 return;
257 }
258 };
259 }
260}
261
262impl Pit {
263 pub fn new(interrupt_evt: IrqEdgeEvent, clock: Arc<Mutex<Clock>>) -> PitResult<Pit> {
264 let mut counters = Vec::new();
265 let mut interrupt = Some(interrupt_evt);
266 for i in 0..NUM_OF_COUNTERS {
267 let pit_counter = PitCounter::new(i, interrupt, clock.clone())?;
268 counters.push(Arc::new(Mutex::new(pit_counter)));
269 interrupt = None;
271 }
272 assert_eq!(counters.len(), NUM_OF_COUNTERS);
278
279 Ok(Pit {
280 counters,
281 worker_thread: None,
282 activated: false,
283 })
284 }
285
286 fn ensure_started(&mut self) {
287 if self.worker_thread.is_some() {
288 return;
289 }
290 if let Err(e) = self.start() {
291 error!("failed to start PIT: {}", e);
292 }
293 }
294
295 fn start(&mut self) -> PitResult<()> {
296 let pit_counter = self.counters[0].clone();
297 self.worker_thread = Some(WorkerThread::start("pit counter worker", move |kill_evt| {
298 if let Err(e) = worker_run(kill_evt, pit_counter) {
299 error!("pit worker failed: {e:#}");
300 }
301 }));
302 self.activated = true;
303 Ok(())
304 }
305
306 fn command_write(&mut self, control_word: u8) {
307 let command: u16 = (control_word & CommandBit::CommandSC as u8).into();
308 let counter_index: usize = (command >> 6).into();
309 if command == (CommandCounter::CommandReadBack as u16) {
310 if (control_word & (CommandReadBackCounters::CommandRBCounter0 as u8)) != 0 {
312 self.counters[0].lock().read_back_command(control_word);
313 }
314 if (control_word & (CommandReadBackCounters::CommandRBCounter1 as u8)) != 0 {
315 self.counters[1].lock().read_back_command(control_word);
316 }
317 if (control_word & (CommandReadBackCounters::CommandRBCounter2 as u8)) != 0 {
318 self.counters[2].lock().read_back_command(control_word);
319 }
320 } else if (control_word & (CommandBit::CommandRW as u8))
321 == (CommandAccess::CommandLatch as u8)
322 {
323 self.counters[counter_index].lock().latch_counter();
324 } else {
325 self.counters[counter_index]
326 .lock()
327 .store_command(control_word);
328 }
329 }
330
331 pub fn get_pit_state(&self) -> PitState {
332 PitState {
333 channels: [
334 self.counters[0].lock().get_channel_state(),
335 self.counters[1].lock().get_channel_state(),
336 self.counters[2].lock().get_channel_state(),
337 ],
338 flags: 0,
339 }
340 }
341
342 pub fn set_pit_state(&mut self, state: &PitState) {
343 self.counters[0]
344 .lock()
345 .set_channel_state(&state.channels[0]);
346 self.counters[1]
347 .lock()
348 .set_channel_state(&state.channels[1]);
349 self.counters[2]
350 .lock()
351 .set_channel_state(&state.channels[2]);
352 }
353}
354
355impl Suspendable for Pit {
356 fn sleep(&mut self) -> anyhow::Result<()> {
357 if let Some(thread) = self.worker_thread.take() {
358 thread.stop();
359 }
360 Ok(())
361 }
362
363 fn wake(&mut self) -> anyhow::Result<()> {
364 if self.activated {
365 if let Err(e) = self.start() {
366 error!("failed to start PIT: {}", e);
367 }
368 }
369 Ok(())
370 }
371
372 fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
375 AnySnapshot::to_any(())
376 }
377
378 fn restore(&mut self, _data: AnySnapshot) -> anyhow::Result<()> {
381 Ok(())
382 }
383}
384
385struct PitCounter {
388 interrupt_evt: Option<IrqEdgeEvent>,
390 reload_value: u16,
393 latched_value: u16,
395 command: u8,
397 status: u8,
399 start: Option<Instant>,
402 clock: Arc<Mutex<Clock>>,
404 creation_time: Instant,
406 counter_id: usize,
409 wrote_low_byte: bool,
411 read_low_byte: bool,
413 latched: bool,
415 status_latched: bool,
417 gate: bool,
419 speaker_on: bool,
420 count: u32,
422 timer_valid: bool,
424 timer: Box<dyn TimerTrait>,
426}
427
428impl Drop for PitCounter {
429 fn drop(&mut self) {
430 if self.timer_valid {
431 self.timer.clear().unwrap();
437 }
438 }
439}
440
441fn adjust_count(count: u32) -> u32 {
442 if count == 0 {
444 MAX_TIMER_FREQ
445 } else {
446 count
447 }
448}
449
450impl PitCounter {
451 fn new(
452 counter_id: usize,
453 interrupt_evt: Option<IrqEdgeEvent>,
454 clock: Arc<Mutex<Clock>>,
455 ) -> PitResult<PitCounter> {
456 #[cfg(not(test))]
457 let timer = Timer::new().map_err(PitError::TimerCreateError)?;
458 #[cfg(test)]
459 let timer = Timer::new(clock.clone());
460 Ok(PitCounter {
461 interrupt_evt,
462 reload_value: 0,
463 latched_value: 0,
464 command: 0,
465 status: 0,
466 start: None,
467 clock: clock.clone(),
468 creation_time: clock.lock().now(),
469 counter_id,
470 wrote_low_byte: false,
471 read_low_byte: false,
472 latched: false,
473 status_latched: false,
474 gate: false,
475 speaker_on: false,
476 count: MAX_TIMER_FREQ,
479 timer_valid: false,
480 timer: Box::new(timer),
481 })
482 }
483
484 fn get_channel_state(&self) -> PitChannelState {
485 let load_time = match &self.start {
486 Some(t) => t.saturating_duration_since(self.creation_time).as_nanos() as u64,
487 None => 0,
488 };
489
490 let mut state = PitChannelState {
491 count: self.count,
492 latched_count: self.latched_value,
493 status_latched: self.status_latched,
494 status: self.status,
495 reload_value: self.reload_value,
496 mode: (self.command & CommandBit::CommandMode as u8) >> 1,
497 bcd: false,
498 gate: self.gate,
499 count_load_time: load_time,
500 rw_mode: PitRWMode::None,
501 read_state: PitRWState::None,
502 write_state: PitRWState::None,
503 count_latched: PitRWState::None,
504 };
505
506 match self.get_access_mode() {
507 Some(CommandAccess::CommandRWLeast) => {
508 state.rw_mode = PitRWMode::Least;
510 state.read_state = PitRWState::LSB;
511 state.write_state = PitRWState::LSB;
512 }
513 Some(CommandAccess::CommandRWMost) => {
514 state.rw_mode = PitRWMode::Most;
516 state.read_state = PitRWState::MSB;
517 state.write_state = PitRWState::MSB;
518 }
519 Some(CommandAccess::CommandRWBoth) => {
520 state.rw_mode = PitRWMode::Both;
521 state.read_state = if self.read_low_byte {
523 PitRWState::Word1
524 } else {
525 PitRWState::Word0
526 };
527 state.write_state = if self.wrote_low_byte {
529 PitRWState::Word1
530 } else {
531 PitRWState::Word0
532 };
533 }
534 _ => {}
535 };
536
537 if self.latched {
539 state.count_latched = state.read_state;
540 }
541
542 state
543 }
544
545 fn set_channel_state(&mut self, state: &PitChannelState) {
546 self.count = state.count;
547 self.latched_value = state.latched_count;
548 self.status_latched = state.status_latched;
549 self.status = state.status;
550 self.reload_value = state.reload_value;
551
552 self.command = (state.mode << 1) | ((state.rw_mode as u8) << 4);
558 self.gate = state.gate;
559 self.latched = state.count_latched != PitRWState::None;
560 self.read_low_byte = state.read_state == PitRWState::Word1;
561 self.wrote_low_byte = state.write_state == PitRWState::Word1;
562
563 self.start = self
564 .creation_time
565 .checked_add(Duration::from_nanos(state.count_load_time));
566 }
567
568 fn get_access_mode(&self) -> Option<CommandAccess> {
569 CommandAccess::n(self.command & (CommandBit::CommandRW as u8))
570 }
571
572 fn get_command_mode(&self) -> Option<CommandMode> {
573 CommandMode::n(self.command & CommandBit::CommandMode as u8)
574 }
575
576 fn read_counter(&mut self) -> u8 {
577 if self.status_latched {
578 self.status_latched = false;
579 return self.status;
580 };
581 let data_value: u16 = if self.latched {
582 self.latched_value
583 } else {
584 self.get_read_value()
585 };
586
587 let access_mode = self.get_access_mode();
588 match (access_mode, self.read_low_byte) {
591 (Some(CommandAccess::CommandRWLeast), _) => {
592 self.latched = false; (data_value & 0xff) as u8
594 }
595 (Some(CommandAccess::CommandRWBoth), false) => {
596 self.read_low_byte = true;
597 (data_value & 0xff) as u8
598 }
599 (Some(CommandAccess::CommandRWBoth), true)
600 | (Some(CommandAccess::CommandRWMost), _) => {
601 self.read_low_byte = false; self.latched = false;
603 (data_value >> 8) as u8
604 }
605 (_, _) => 0, }
607 }
608
609 fn write_counter(&mut self, written_datum: u8) {
610 let access_mode = self.get_access_mode();
611 let datum: u16 = written_datum.into();
612 let mut should_start_timer = true;
613 self.reload_value = match access_mode {
614 Some(CommandAccess::CommandRWLeast) => datum,
615 Some(CommandAccess::CommandRWMost) => datum << 8,
616 Some(CommandAccess::CommandRWBoth) => {
617 if self.wrote_low_byte {
621 self.wrote_low_byte = false;
622 self.reload_value | (datum << 8)
623 } else {
624 self.wrote_low_byte = true;
625 should_start_timer = false; datum
627 }
628 }
629 _ => {
630 should_start_timer = false;
631 self.reload_value
632 }
633 };
634 if should_start_timer {
635 let reload: u32 = self.reload_value.into();
636 self.load_and_start_timer(reload);
637 }
638 }
639
640 fn get_output(&self) -> bool {
641 let ticks_passed = self.get_ticks_passed();
642 let count: u64 = self.count.into();
643 match self.get_command_mode() {
644 Some(CommandMode::CommandInterrupt) => ticks_passed >= count,
645 Some(CommandMode::CommandHWOneShot) => ticks_passed < count,
646 Some(CommandMode::CommandRateGen) => ticks_passed != 0 && ticks_passed % count == 0,
647 Some(CommandMode::CommandSquareWaveGen) => ticks_passed < count.div_ceil(2),
648 Some(CommandMode::CommandSWStrobe) | Some(CommandMode::CommandHWStrobe) => {
649 ticks_passed == count
650 }
651 None => {
652 warn!("Invalid command mode based on command: {:#x}", self.command);
653 false
654 }
655 }
656 }
657
658 fn read_speaker(&self) -> u8 {
659 let us = self
662 .clock
663 .lock()
664 .now()
665 .duration_since(self.creation_time)
666 .subsec_micros();
667 let refresh_clock = us % 15 == 0;
668 let mut speaker = SpeakerPortFields::new();
669 speaker.set_gate(self.gate.into());
670 speaker.set_speaker_on(self.speaker_on.into());
671 speaker.set_iochk_enable(0);
672 speaker.set_refresh_clock(refresh_clock.into());
673 speaker.set_output(self.get_output().into());
674 speaker.set_iochk_nmi(0);
675 speaker.set_serr_nmi(0);
676 speaker.get(0, 8) as u8
677 }
678
679 fn write_speaker(&mut self, datum: u8) {
680 let mut speaker = SpeakerPortFields::new();
681 speaker.set(0, 8, datum.into());
682 let new_gate = speaker.get_gate() != 0;
683 match self.get_command_mode() {
684 Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (),
685 Some(_) => {
686 if new_gate && !self.gate {
687 self.start = Some(self.clock.lock().now());
688 }
689 }
690 None => {
691 warn!("Invalid command mode based on command {:#x}", self.command);
692 return;
693 }
694 }
695 self.speaker_on = speaker.get_speaker_on() != 0;
696 self.gate = new_gate;
697 }
698
699 fn load_and_start_timer(&mut self, initial_count: u32) {
700 self.count = adjust_count(initial_count);
701 self.start_timer();
702 }
703
704 fn start_timer(&mut self) {
705 self.start = Some(self.clock.lock().now());
706
707 if self.counter_id != 0 {
710 return;
711 }
712
713 let timer_len = Duration::from_nanos(u64::from(self.count) * NANOS_PER_SEC / FREQUENCY_HZ);
714 let safe_timer_len = if timer_len == Duration::new(0, 0) {
715 Duration::from_nanos(1)
716 } else {
717 timer_len
718 };
719
720 match self.get_command_mode() {
721 Some(CommandMode::CommandInterrupt)
722 | Some(CommandMode::CommandHWOneShot)
723 | Some(CommandMode::CommandSWStrobe)
724 | Some(CommandMode::CommandHWStrobe) => {
725 if let Err(e) = self.timer.reset_oneshot(safe_timer_len) {
726 error!("failed to reset oneshot timer: {}", e);
727 }
728 }
729 Some(CommandMode::CommandRateGen) | Some(CommandMode::CommandSquareWaveGen) => {
730 if let Err(e) = self.timer.reset_repeating(safe_timer_len) {
731 error!("failed to reset repeating timer: {}", e);
732 }
733 }
734 None => {
736 warn!("Invalid command mode based on command {:#x}", self.command);
749 return;
750 }
751 }
752
753 self.timer_valid = true;
754 }
755
756 fn read_back_command(&mut self, control_word: u8) {
757 let latch_cmd =
758 CommandReadBackLatch::n(control_word & CommandReadBackLatch::CommandRBLatchBits as u8);
759 match latch_cmd {
760 Some(CommandReadBackLatch::CommandRBLatchCount) => {
761 self.latch_counter();
762 }
763 Some(CommandReadBackLatch::CommandRBLatchStatus) => {
764 self.latch_status();
765 }
766 _ => warn!(
767 "Unexpected ReadBackLatch. control_word: {:#x}",
768 control_word
769 ),
770 };
771 }
772
773 fn latch_counter(&mut self) {
774 if self.latched {
775 return;
776 }
777
778 self.latched_value = self.get_read_value();
779 self.latched = true;
780 self.read_low_byte = false;
781 }
782
783 fn latch_status(&mut self) {
784 self.status = self.command
786 & (CommandBit::CommandRW as u8
787 | CommandBit::CommandMode as u8
788 | CommandBit::CommandBCD as u8);
789 if self.start.is_none() {
790 self.status |= ReadBackData::ReadBackNullCount as u8;
791 }
792 if self.get_output() {
793 self.status |= ReadBackData::ReadBackOutput as u8;
794 }
795 self.status_latched = true;
796 }
797
798 fn store_command(&mut self, datum: u8) {
799 self.command = datum;
800 self.latched = false;
801
802 if self.timer_valid {
804 self.start = None;
805 self.timer_valid = false;
806 self.timer.clear().unwrap();
808 }
809
810 self.wrote_low_byte = false;
811 self.read_low_byte = false;
812 }
813
814 fn timer_handler(&mut self) {
815 if let Err(e) = self.timer.mark_waited() {
816 error!("pit: timer wait unexpectedly failed: {}", e);
820 return;
821 }
822 let mode = self.get_command_mode();
823 if mode == Some(CommandMode::CommandRateGen)
824 || mode == Some(CommandMode::CommandSquareWaveGen)
825 {
826 self.start = Some(self.clock.lock().now());
828 }
829
830 if let Some(interrupt) = &mut self.interrupt_evt {
834 interrupt.trigger().unwrap();
836 }
837 }
838
839 fn get_ticks_passed(&self) -> u64 {
840 match self.start {
841 None => 0,
842 Some(t) => {
843 let dur = self.clock.lock().now().duration_since(t);
844 let dur_ns: u64 = dur.as_secs() * NANOS_PER_SEC + u64::from(dur.subsec_nanos());
845 dur_ns * FREQUENCY_HZ / NANOS_PER_SEC
846 }
847 }
848 }
849
850 fn get_read_value(&self) -> u16 {
851 match self.start {
852 None => 0,
853 Some(_) => {
854 let count: u64 = adjust_count(self.reload_value.into()).into();
855 let ticks_passed = self.get_ticks_passed();
856 match self.get_command_mode() {
857 Some(CommandMode::CommandInterrupt)
858 | Some(CommandMode::CommandHWOneShot)
859 | Some(CommandMode::CommandSWStrobe)
860 | Some(CommandMode::CommandHWStrobe) => {
861 if ticks_passed > count {
862 0
866 } else {
867 ((count - ticks_passed) & 0xFFFF) as u16
868 }
869 }
870 Some(CommandMode::CommandRateGen) => (count - (ticks_passed % count)) as u16,
871 Some(CommandMode::CommandSquareWaveGen) => {
872 (count - ((ticks_passed * 2) % count)) as u16
873 }
874 None => {
875 warn!("Invalid command mode: command = {:#x}", self.command);
876 0
877 }
878 }
879 }
880 }
881 }
882}
883
884fn worker_run(kill_evt: Event, pit_counter: Arc<Mutex<PitCounter>>) -> PitResult<()> {
885 let timer_descriptor = Descriptor(pit_counter.lock().timer.as_raw_descriptor());
886 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
887 (&timer_descriptor, Token::TimerExpire),
888 (&kill_evt, Token::Kill),
889 ])
890 .map_err(PitError::CreateWaitContext)?;
891
892 loop {
893 let events = wait_ctx.wait().map_err(PitError::WaitError)?;
894 for event in events.iter().filter(|e| e.is_readable) {
895 match event.token {
896 Token::TimerExpire => {
897 let mut pit = pit_counter.lock();
898 pit.timer_handler();
899 }
900 Token::Kill => return Ok(()),
901 }
902 }
903 }
904}
905
906#[cfg(test)]
907mod tests {
908 use base::Event;
909
910 use super::*;
911
912 struct TestData {
913 pit: Pit,
914 irqfd: Event,
915 clock: Arc<Mutex<Clock>>,
916 }
917
918 fn pit_bus_address(address: PortIOSpace) -> BusAccessInfo {
919 let offset = match address as u64 {
923 x if x >= PortIOSpace::PortCounter0Data as u64
924 && x < PortIOSpace::PortCounter0Data as u64 + 0x8 =>
925 {
926 address as u64 - PortIOSpace::PortCounter0Data as u64
927 }
928 x if x == PortIOSpace::PortSpeaker as u64 => 0,
929 _ => panic!("invalid PIT address: {:#x}", address as u64),
930 };
931
932 BusAccessInfo {
933 offset,
934 address: address as u64,
935 id: 0,
936 }
937 }
938
939 fn write_command(pit: &mut Pit, command: u8) {
941 pit.write(pit_bus_address(PortIOSpace::PortCommand), &[command])
942 }
943
944 fn write_speaker(pit: &mut Pit, command: u8) {
946 pit.write(pit_bus_address(PortIOSpace::PortSpeaker), &[command])
947 }
948
949 fn write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess) {
951 let port = match counter_idx {
952 0 => PortIOSpace::PortCounter0Data,
953 1 => PortIOSpace::PortCounter1Data,
954 2 => PortIOSpace::PortCounter2Data,
955 _ => panic!("Invalid counter_idx: {counter_idx}"),
956 };
957 if access_mode == CommandAccess::CommandRWLeast
959 || access_mode == CommandAccess::CommandRWBoth
960 {
961 pit.write(pit_bus_address(port), &[(data & 0xff) as u8]);
962 }
963 if access_mode == CommandAccess::CommandRWMost
964 || access_mode == CommandAccess::CommandRWBoth
965 {
966 pit.write(pit_bus_address(port), &[(data >> 8) as u8]);
967 }
968 }
969
970 fn read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess) {
972 let port = match counter_idx {
973 0 => PortIOSpace::PortCounter0Data,
974 1 => PortIOSpace::PortCounter1Data,
975 2 => PortIOSpace::PortCounter2Data,
976 _ => panic!("Invalid counter_idx: {counter_idx}"),
977 };
978 let mut result: u16 = 0;
979 if access_mode == CommandAccess::CommandRWLeast
980 || access_mode == CommandAccess::CommandRWBoth
981 {
982 let mut buffer = [0];
983 pit.read(pit_bus_address(port), &mut buffer);
984 result = buffer[0].into();
985 }
986 if access_mode == CommandAccess::CommandRWMost
987 || access_mode == CommandAccess::CommandRWBoth
988 {
989 let mut buffer = [0];
990 pit.read(pit_bus_address(port), &mut buffer);
991 result |= u16::from(buffer[0]) << 8;
992 }
993 assert_eq!(result, expected);
994 }
995
996 fn set_up() -> TestData {
997 let evt = IrqEdgeEvent::new().unwrap();
998 let clock = Arc::new(Mutex::new(Clock::new()));
999 TestData {
1000 irqfd: evt.get_trigger().try_clone().unwrap(),
1001 pit: Pit::new(evt, clock.clone()).unwrap(),
1002 clock,
1003 }
1004 }
1005
1006 fn advance_by_tick(data: &mut TestData) {
1007 advance_by_ticks(data, 1);
1008 }
1009
1010 fn advance_by_ticks(data: &mut TestData, ticks: u64) {
1011 println!(
1012 "Advancing by {:#x} ticks ({} ns)",
1013 ticks,
1014 (NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1
1015 );
1016 let mut lock = data.clock.lock();
1017 lock.add_ns((NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1);
1018 }
1019
1020 #[test]
1022 fn write_and_latch() {
1023 let mut data = set_up();
1024 let both_interrupt =
1025 CommandAccess::CommandRWBoth as u8 | CommandMode::CommandInterrupt as u8;
1026 write_command(
1028 &mut data.pit,
1029 CommandCounter::CommandCounter0 as u8 | both_interrupt,
1030 );
1031 write_counter(&mut data.pit, 0, 24, CommandAccess::CommandRWBoth);
1032 advance_by_tick(&mut data);
1034
1035 write_command(
1037 &mut data.pit,
1038 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1039 );
1040 advance_by_tick(&mut data);
1042 read_counter(&mut data.pit, 0, 23, CommandAccess::CommandRWBoth);
1043
1044 write_command(
1046 &mut data.pit,
1047 CommandCounter::CommandCounter1 as u8 | both_interrupt,
1048 );
1049 write_counter(&mut data.pit, 1, 314, CommandAccess::CommandRWBoth);
1050 advance_by_tick(&mut data);
1051 write_command(
1052 &mut data.pit,
1053 CommandCounter::CommandCounter1 as u8 | CommandAccess::CommandLatch as u8,
1054 );
1055 advance_by_tick(&mut data);
1056 read_counter(&mut data.pit, 1, 313, CommandAccess::CommandRWBoth);
1057
1058 write_command(
1060 &mut data.pit,
1061 CommandCounter::CommandCounter2 as u8 | both_interrupt,
1062 );
1063 write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1064 advance_by_tick(&mut data);
1065 write_command(
1066 &mut data.pit,
1067 CommandCounter::CommandCounter2 as u8 | CommandAccess::CommandLatch as u8,
1068 );
1069 advance_by_tick(&mut data);
1070 read_counter(&mut data.pit, 2, 0xfffe, CommandAccess::CommandRWBoth);
1071 }
1072
1073 #[test]
1075 fn write_and_read_least() {
1076 let mut data = set_up();
1077 write_command(
1078 &mut data.pit,
1079 CommandCounter::CommandCounter0 as u8
1080 | CommandAccess::CommandRWLeast as u8
1081 | CommandMode::CommandInterrupt as u8,
1082 );
1083 write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWLeast);
1084 read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1085 write_command(
1086 &mut data.pit,
1087 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1088 );
1089 advance_by_tick(&mut data);
1090 read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1091 }
1092
1093 #[test]
1095 fn write_and_read_most() {
1096 let mut data = set_up();
1097 write_command(
1098 &mut data.pit,
1099 CommandCounter::CommandCounter0 as u8
1100 | CommandAccess::CommandRWMost as u8
1101 | CommandMode::CommandInterrupt as u8,
1102 );
1103 write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWMost);
1104 read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1105 write_command(
1106 &mut data.pit,
1107 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1108 );
1109 advance_by_tick(&mut data);
1110 read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1111 }
1112
1113 #[test]
1115 fn read_command() {
1116 let mut data = set_up();
1117 let mut buf = [0];
1118 data.pit
1119 .read(pit_bus_address(PortIOSpace::PortCommand), &mut buf);
1120 assert_eq!(buf, [0]);
1121 }
1122
1123 #[test]
1125 fn test_timed_latch() {
1126 let mut data = set_up();
1127 write_command(
1128 &mut data.pit,
1129 CommandCounter::CommandCounter0 as u8
1130 | CommandAccess::CommandRWBoth as u8
1131 | CommandMode::CommandInterrupt as u8,
1132 );
1133 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1134 write_command(
1135 &mut data.pit,
1136 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1137 );
1138 data.clock.lock().add_ns(25_000_000);
1139 write_command(
1141 &mut data.pit,
1142 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1143 );
1144 read_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1145 write_command(
1147 &mut data.pit,
1148 CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1149 );
1150 read_counter(
1151 &mut data.pit,
1152 0,
1153 0xffff - ((25_000_000 * FREQUENCY_HZ) / NANOS_PER_SEC) as u16,
1154 CommandAccess::CommandRWBoth,
1155 );
1156 }
1157
1158 #[test]
1160 fn interrupt_mode() {
1161 let mut data = set_up();
1162 write_command(
1163 &mut data.pit,
1164 CommandCounter::CommandCounter0 as u8
1165 | CommandAccess::CommandRWBoth as u8
1166 | CommandMode::CommandInterrupt as u8,
1167 );
1168 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1169 advance_by_ticks(&mut data, 0xffff);
1171 data.irqfd.wait().unwrap();
1172 }
1173
1174 #[test]
1177 fn rate_gen_mode() {
1178 let mut data = set_up();
1179 write_command(
1180 &mut data.pit,
1181 CommandCounter::CommandCounter0 as u8
1182 | CommandAccess::CommandRWBoth as u8
1183 | CommandMode::CommandRateGen as u8,
1184 );
1185 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1186 advance_by_ticks(&mut data, 0xffff);
1188 data.irqfd.wait().unwrap();
1189
1190 advance_by_ticks(&mut data, 0xffff);
1192 data.irqfd.wait().unwrap();
1193
1194 advance_by_ticks(&mut data, 0xffff);
1196 data.irqfd.wait().unwrap();
1197 }
1198
1199 #[test]
1201 fn square_wave_counter_read() {
1202 let mut data = set_up();
1203 write_command(
1204 &mut data.pit,
1205 CommandCounter::CommandCounter0 as u8
1206 | CommandAccess::CommandRWBoth as u8
1207 | CommandMode::CommandSquareWaveGen as u8,
1208 );
1209 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1210
1211 advance_by_ticks(&mut data, 10_000);
1212 read_counter(
1213 &mut data.pit,
1214 0,
1215 0xffff - 10_000 * 2,
1216 CommandAccess::CommandRWBoth,
1217 );
1218 }
1219
1220 #[test]
1222 fn rate_gen_counter_read() {
1223 let mut data = set_up();
1224 write_command(
1225 &mut data.pit,
1226 CommandCounter::CommandCounter0 as u8
1227 | CommandAccess::CommandRWBoth as u8
1228 | CommandMode::CommandRateGen as u8,
1229 );
1230 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1231
1232 advance_by_ticks(&mut data, 10_000);
1233 read_counter(
1234 &mut data.pit,
1235 0,
1236 0xffff - 10_000,
1237 CommandAccess::CommandRWBoth,
1238 );
1239 }
1240
1241 #[test]
1243 fn interrupt_counter_read() {
1244 let mut data = set_up();
1245 write_command(
1246 &mut data.pit,
1247 CommandCounter::CommandCounter0 as u8
1248 | CommandAccess::CommandRWBoth as u8
1249 | CommandMode::CommandInterrupt as u8,
1250 );
1251 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1252
1253 advance_by_ticks(&mut data, 10_000);
1254 read_counter(
1255 &mut data.pit,
1256 0,
1257 0xffff - 10_000,
1258 CommandAccess::CommandRWBoth,
1259 );
1260
1261 advance_by_ticks(&mut data, 3 * FREQUENCY_HZ);
1262 read_counter(&mut data.pit, 0, 0, CommandAccess::CommandRWBoth);
1263 }
1264
1265 #[test]
1267 fn read_back_count_access_low() {
1268 let mut data = set_up();
1269 write_command(
1270 &mut data.pit,
1271 CommandCounter::CommandCounter0 as u8
1272 | CommandAccess::CommandRWLeast as u8
1273 | CommandMode::CommandInterrupt as u8,
1274 );
1275 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1276 write_command(
1277 &mut data.pit,
1278 CommandCounter::CommandReadBack as u8
1279 | CommandReadBackLatch::CommandRBLatchCount as u8
1280 | CommandReadBackCounters::CommandRBCounter0 as u8,
1281 );
1282
1283 advance_by_ticks(&mut data, 100);
1285 write_command(
1286 &mut data.pit,
1287 CommandCounter::CommandReadBack as u8
1288 | CommandReadBackLatch::CommandRBLatchCount as u8
1289 | CommandReadBackCounters::CommandRBCounter0 as u8,
1290 );
1291 read_counter(&mut data.pit, 0, 0x00ff, CommandAccess::CommandRWLeast);
1292 write_command(
1293 &mut data.pit,
1294 CommandCounter::CommandReadBack as u8
1295 | CommandReadBackLatch::CommandRBLatchCount as u8
1296 | CommandReadBackCounters::CommandRBCounter0 as u8,
1297 );
1298 read_counter(
1299 &mut data.pit,
1300 0,
1301 (0xffff - 100) & 0x00ff,
1302 CommandAccess::CommandRWLeast,
1303 );
1304 }
1305
1306 #[test]
1308 fn read_back_count_access_high() {
1309 let mut data = set_up();
1310 write_command(
1311 &mut data.pit,
1312 CommandCounter::CommandCounter0 as u8
1313 | CommandAccess::CommandRWMost as u8
1314 | CommandMode::CommandInterrupt as u8,
1315 );
1316 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1317 write_command(
1318 &mut data.pit,
1319 CommandCounter::CommandReadBack as u8
1320 | CommandReadBackLatch::CommandRBLatchCount as u8
1321 | CommandReadBackCounters::CommandRBCounter0 as u8,
1322 );
1323
1324 advance_by_ticks(&mut data, 512);
1326 write_command(
1327 &mut data.pit,
1328 CommandCounter::CommandReadBack as u8
1329 | CommandReadBackLatch::CommandRBLatchCount as u8
1330 | CommandReadBackCounters::CommandRBCounter0 as u8,
1331 );
1332 read_counter(&mut data.pit, 0, 0xff00, CommandAccess::CommandRWMost);
1333 write_command(
1334 &mut data.pit,
1335 CommandCounter::CommandReadBack as u8
1336 | CommandReadBackLatch::CommandRBLatchCount as u8
1337 | CommandReadBackCounters::CommandRBCounter0 as u8,
1338 );
1339 read_counter(
1340 &mut data.pit,
1341 0,
1342 (0xffff - 512) & 0xff00,
1343 CommandAccess::CommandRWMost,
1344 );
1345 }
1346
1347 #[test]
1349 fn read_back_status() {
1350 let mut data = set_up();
1351 write_command(
1352 &mut data.pit,
1353 CommandCounter::CommandCounter0 as u8
1354 | CommandAccess::CommandRWBoth as u8
1355 | CommandMode::CommandSWStrobe as u8,
1356 );
1357 write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1358 write_command(
1359 &mut data.pit,
1360 CommandCounter::CommandReadBack as u8
1361 | CommandReadBackLatch::CommandRBLatchStatus as u8
1362 | CommandReadBackCounters::CommandRBCounter0 as u8,
1363 );
1364
1365 read_counter(
1366 &mut data.pit,
1367 0,
1368 CommandAccess::CommandRWBoth as u16 | CommandMode::CommandSWStrobe as u16,
1369 CommandAccess::CommandRWLeast,
1370 );
1371 }
1372
1373 #[test]
1374 fn speaker_square_wave() {
1375 let mut data = set_up();
1376 write_command(
1377 &mut data.pit,
1378 CommandCounter::CommandCounter2 as u8
1379 | CommandAccess::CommandRWBoth as u8
1380 | CommandMode::CommandSquareWaveGen as u8,
1381 );
1382 write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1383
1384 advance_by_ticks(&mut data, 128);
1385 read_counter(
1386 &mut data.pit,
1387 2,
1388 0xffff - 128 * 2,
1389 CommandAccess::CommandRWBoth,
1390 );
1391 }
1392
1393 #[test]
1394 fn speaker_rate_gen() {
1395 let mut data = set_up();
1396 write_command(
1397 &mut data.pit,
1398 CommandCounter::CommandCounter2 as u8
1399 | CommandAccess::CommandRWBoth as u8
1400 | CommandMode::CommandRateGen as u8,
1401 );
1402 write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1403
1404 advance_by_ticks(&mut data, 128);
1407 read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1408
1409 write_speaker(&mut data.pit, 0x1);
1410 advance_by_ticks(&mut data, 128);
1411 read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1412 }
1413
1414 #[test]
1415 fn speaker_interrupt() {
1416 let mut data = set_up();
1417
1418 write_command(
1419 &mut data.pit,
1420 CommandCounter::CommandCounter2 as u8
1421 | CommandAccess::CommandRWBoth as u8
1422 | CommandMode::CommandInterrupt as u8,
1423 );
1424 write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1425
1426 advance_by_ticks(&mut data, 128);
1429 read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1430
1431 write_speaker(&mut data.pit, 0x1);
1432 advance_by_ticks(&mut data, 128);
1433 read_counter(&mut data.pit, 2, 0xffff - 256, CommandAccess::CommandRWBoth);
1434 }
1435
1436 #[test]
1438 fn invalid_write_and_read() {
1439 let mut data = set_up();
1440 data.pit.write(
1441 BusAccessInfo {
1442 address: 0x44,
1443 offset: 0x4,
1444 id: 0,
1445 },
1446 &[0],
1447 );
1448 data.pit.read(
1449 BusAccessInfo {
1450 address: 0x55,
1451 offset: 0x15,
1452 id: 0,
1453 },
1454 &mut [0],
1455 );
1456 }
1457}