devices/
pit.rs

1// Copyright 2019 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Based heavily on GCE VMM's pit.cc.
6
7use 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// Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant
50// names are kept the same as Intel PIT data sheet.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
52enum CommandBit {
53    CommandBCD = 0x01,  // Binary/BCD input. x86 only uses binary mode.
54    CommandMode = 0x0e, // Operating Mode (mode 0-5).
55    CommandRW = 0x30,   // Access mode: Choose high/low byte(s) to Read/Write.
56    CommandSC = 0xc0,   // Select Counter/Read-back command.
57}
58
59// Selects which counter is to be used by the associated command in the lower
60// six bits of the byte. However, if 0xc0 is specified, it indicates that the
61// command is a "Read-Back", which can latch count and/or status of the
62// counters selected in the lower bits. See Intel 8254 data sheet for details.
63#[allow(dead_code)]
64#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
65enum CommandCounter {
66    CommandCounter0 = 0x00, // Select counter 0.
67    CommandCounter1 = 0x40, // Select counter 1.
68    CommandCounter2 = 0x80, // Select counter 2.
69    CommandReadBack = 0xc0, // Execute Read-Back.
70}
71
72// Used for both CommandRW and ReadBackAccess.
73#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
74enum CommandAccess {
75    CommandLatch = 0x00,   // Latch specified counter.
76    CommandRWLeast = 0x10, // Read/Write least significant byte.
77    CommandRWMost = 0x20,  // Read/Write most significant byte.
78    CommandRWBoth = 0x30,  // Read/Write both bytes.
79}
80
81// Used for both CommandMode and ReadBackMode.
82// For mode 2 & 3, bit 3 is don't care bit (does not matter to be 0 or 1) but
83// per 8254 spec, should be 0 to insure compatibility with future Intel
84// products.
85#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
86enum CommandMode {
87    // NOTE:  No h/w modes are currently implemented.
88    CommandInterrupt = 0x00,     // Mode 0, interrupt on terminal count.
89    CommandHWOneShot = 0x02,     // Mode 1, h/w re-triggerable one-shot.
90    CommandRateGen = 0x04,       // Mode 2, rate generator.
91    CommandSquareWaveGen = 0x06, // Mode 3, square wave generator.
92    CommandSWStrobe = 0x08,      // Mode 4, s/w triggered strobe.
93    CommandHWStrobe = 0x0a,      // Mode 5, h/w triggered strobe.
94}
95
96// Bitmask for the latch portion of the ReadBack command.
97#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
98#[rustfmt::skip]  // rustfmt mangles comment indentation for trailing line comments.
99enum CommandReadBackLatch {
100    CommandRBLatchBits = 0x30,   // Mask bits that determine latching.
101    CommandRBLatchBoth = 0x00,   // Latch both count and status. This should
102                                 // never happen in device, since bit 4 and 5 in
103                                 // read back command are inverted.
104    CommandRBLatchCount = 0x10,  // Latch count.
105    CommandRBLatchStatus = 0x20, // Latch status.
106}
107
108// Bitmask for the counter portion of the ReadBack command.
109#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
110enum CommandReadBackCounters {
111    //CommandRBCounters = 0x0e, // Counters for which to provide ReadBack info.
112    CommandRBCounter2 = 0x08,
113    CommandRBCounter1 = 0x04,
114    CommandRBCounter0 = 0x02,
115}
116
117// Bitmask for the ReadBack status command.
118#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
119#[rustfmt::skip]  // rustfmt mangles comment indentation for last line of this enum.
120enum ReadBackData {
121    // Output format for ReadBack command.
122    ReadBackOutput = 0x80, // Output pin status.
123    ReadBackNullCount = 0x40, // Whether counter has value.
124    // ReadBackAccess, ReadBackMode, and ReadBackBCD intentionally omitted.
125}
126
127// I/O Port mappings in I/O bus.
128#[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
129enum PortIOSpace {
130    PortCounter0Data = 0x40, // Read/write.
131    PortCounter1Data = 0x41, // Read/write.
132    PortCounter2Data = 0x42, // Read/write.
133    PortCommand = 0x43,      // Write only.
134    PortSpeaker = 0x61,      // Read/write.
135}
136
137#[bitfield]
138#[derive(Clone, Copy, PartialEq, Eq)]
139pub struct SpeakerPortFields {
140    // This field is documented in the chipset spec as NMI status and control
141    // register.  Bits 2, 3, 6, 7 and low level hardware bits that need no
142    // emulation for virtualized environments.  We call it speaker port because
143    // kvm, qemu, linux, and plan9 still call it speaker port, even though it
144    // has these other uses and is called something differently in the spec.
145    gate: BitField1,
146    speaker_on: BitField1,
147    pic_serr: BitField1,
148    iochk_enable: BitField1,
149    // This value changes as part of the refresh frequency of the board for
150    // piix4, this is about 1/15us.
151    refresh_clock: BitField1,
152    output: BitField1,
153    iochk_nmi: BitField1,
154    serr_nmi: BitField1,
155}
156
157// PIT frequency (in Hertz). See http://wiki.osdev.org/pit.
158const 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    // The timer expired.
169    TimerExpire,
170    // The parent thread requested an exit.
171    Kill,
172}
173
174#[sorted]
175#[derive(Error, Debug)]
176pub enum PitError {
177    /// Error while cloning event for worker thread.
178    #[error("failed to clone event: {0}")]
179    CloneEvent(SysError),
180    /// Error while creating event.
181    #[error("failed to create event: {0}")]
182    CreateEvent(SysError),
183    /// Creating WaitContext failed.
184    #[error("failed to create poll context: {0}")]
185    CreateWaitContext(SysError),
186    /// Error while trying to create worker thread.
187    #[error("failed to spawn thread: {0}")]
188    SpawnThread(IoError),
189    /// Error while trying to create timer.
190    #[error("failed to create pit counter due to timer fd: {0}")]
191    TimerCreateError(SysError),
192    /// Error while waiting for events.
193    #[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    // Structs that store each counter's state.
201    counters: Vec<Arc<Mutex<PitCounter>>>,
202    // Worker thread to update counter 0's state asynchronously. Counter 0 needs to send interrupts
203    // when timers expire, so it needs asynchronous updates. All other counters need only update
204    // when queried directly by the guest.
205    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            // This should function as a no-op, since the specification doesn't allow the
247            // command register to be read. However, software is free to ask for it to
248            // to be read.
249            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            // pass interrupt IrqFd ONLY to counter 0; the rest do not deliver interrupts.
270            interrupt = None;
271        }
272        // We asssert here because:
273        // (a) this code only gets invoked at VM startup
274        // (b) the assert is very loud and would be easy to notice in tests
275        // (c) if we have the wrong number of counters, something is very wrong with the PIT and it
276        // may not make sense to continue operation.
277        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            // ReadBack commands can apply to multiple counters.
311            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    /// The PIT is only used in very early boot on x86_64, and snapshots are not
373    /// generally taken during that time, so we can safely skip the PIT for now.
374    fn snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
375        AnySnapshot::to_any(())
376    }
377
378    /// The PIT is only used in very early boot on x86_64, and snapshots are not
379    /// generally taken during that time, so we can safely skip the PIT for now.
380    fn restore(&mut self, _data: AnySnapshot) -> anyhow::Result<()> {
381        Ok(())
382    }
383}
384
385// Each instance of this represents one of the PIT counters. They are used to
386// implement one-shot and repeating timer alarms. An 8254 has three counters.
387struct PitCounter {
388    // Event to write when asserting an interrupt.
389    interrupt_evt: Option<IrqEdgeEvent>,
390    // Stores the value with which the counter was initialized. Counters are 16-
391    // bit values with an effective range of 1-65536 (65536 represented by 0).
392    reload_value: u16,
393    // Stores value when latch was called.
394    latched_value: u16,
395    // Stores last command from command register.
396    command: u8,
397    // Stores status from readback command
398    status: u8,
399    // Stores time of starting timer. Used for calculating remaining count, if an alarm is
400    // scheduled.
401    start: Option<Instant>,
402    // Current time.
403    clock: Arc<Mutex<Clock>>,
404    // Time when object was created. Used for a 15us counter.
405    creation_time: Instant,
406    // The number of the counter. The behavior for each counter is slightly different.
407    // Note that once a PitCounter is created, this value should never change.
408    counter_id: usize,
409    // Indicates if the low byte has been written in RWBoth.
410    wrote_low_byte: bool,
411    // Indicates if the low byte has been read in RWBoth.
412    read_low_byte: bool,
413    // Indicates whether counter has been latched.
414    latched: bool,
415    // Indicates whether ReadBack status has been latched.
416    status_latched: bool,
417    // Only should be used for counter 2. See http://wiki.osdev.org/PIT.
418    gate: bool,
419    speaker_on: bool,
420    // The starting value for the counter.
421    count: u32,
422    // Indicates whether the current timer is valid.
423    timer_valid: bool,
424    // Timer to set and receive periodic notifications.
425    timer: Box<dyn TimerTrait>,
426}
427
428impl Drop for PitCounter {
429    fn drop(&mut self) {
430        if self.timer_valid {
431            // This should not fail - timer.clear() only fails if timerfd_settime fails, which
432            // only happens due to invalid arguments or bad file descriptors. The arguments to
433            // timerfd_settime are constant, so its arguments won't be invalid, and it manages
434            // the file descriptor safely (we don't use the unsafe FromRawDescriptor) so its file
435            // descriptor will be valid.
436            self.timer.clear().unwrap();
437        }
438    }
439}
440
441fn adjust_count(count: u32) -> u32 {
442    // As per spec 0 means max.
443    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` is undefined in real hardware and can't ever be programmed to 0, so we
477            // initialize it to max to prevent a misbehaving guest from triggering a divide by 0.
478            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                // If access mode is least, RWStates are always LSB
509                state.rw_mode = PitRWMode::Least;
510                state.read_state = PitRWState::LSB;
511                state.write_state = PitRWState::LSB;
512            }
513            Some(CommandAccess::CommandRWMost) => {
514                // If access mode is most, RWStates are always MSB
515                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                // read_state depends on whether or not we've read the low byte already
522                state.read_state = if self.read_low_byte {
523                    PitRWState::Word1
524                } else {
525                    PitRWState::Word0
526                };
527                // write_state depends on whether or not we've written the low byte already
528                state.write_state = if self.wrote_low_byte {
529                    PitRWState::Word1
530                } else {
531                    PitRWState::Word0
532                };
533            }
534            _ => {}
535        };
536
537        // Count_latched should be PitRWSTate::None unless we're latched
538        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        // the command consists of:
553        //  - 1 bcd bit, which we don't care about because we don't support non-binary mode
554        //  - 3 mode bits
555        //  - 2 access mode bits
556        //  - 2 counter select bits, which aren't used by the counter/channel itself
557        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        // Latch may be true without being indicated by the access mode if
589        // a ReadBack was issued.
590        match (access_mode, self.read_low_byte) {
591            (Some(CommandAccess::CommandRWLeast), _) => {
592                self.latched = false; // Unlatch if only reading the low byte.
593                (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; // Allow for future reads for RWBoth.
602                self.latched = false;
603                (data_value >> 8) as u8
604            }
605            (_, _) => 0, // Default for erroneous call
606        }
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                // In kCommandRWBoth mode, the first guest write is the low byte and the
618                // the second guest write is the high byte.  The timer isn't started
619                // until after the second byte is written.
620                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; // Don't start until high byte written.
626                    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        // Refresh clock is a value independent of the actual
660        // counter that goes up and down approx every 15 us (~66000/s).
661        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(/* offset= */ 0, /* width= */ 8) as u8
677    }
678
679    fn write_speaker(&mut self, datum: u8) {
680        let mut speaker = SpeakerPortFields::new();
681        speaker.set(/* offset= */ 0, /* width= */ 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        // Counter 0 is the only counter that generates interrupts, so we
708        // don't need to set a timer for the other two counters.
709        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            // Don't arm timer if invalid mode.
735            None => {
736                // This will still result in start being set to the current time.
737                // Per spec:
738                //   A new initial count may be written to a Counter at any time without affecting
739                //   the Counter’s programmed Mode in any way. Counting will be affected as
740                //   described in the Mode definitions. The new count must follow the programmed
741                //   count format
742                // It's unclear whether setting `self.start` in this case is entirely compliant,
743                // but the spec is fairly quiet on expected behavior in error cases, so OSs
744                // shouldn't enter invalid modes in the first place.  If they do, and then try to
745                // get out of it by first setting the counter then the command, this behavior will
746                // (perhaps) be minimally surprising, but arguments can be made for other behavior.
747                // It's uncertain if this behavior matches real PIT hardware.
748                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        // Including BCD here, even though it currently never gets used.
785        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 a new RW command is written, cancel the current timer.
803        if self.timer_valid {
804            self.start = None;
805            self.timer_valid = false;
806            // See the comment in the impl of Drop for PitCounter for justification of the unwrap()
807            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            // Under the current Timer implementation (as of Jan 2019), this failure shouldn't
817            // happen but implementation details may change in the future, and the failure
818            // cases are complex to reason about. Because of this, avoid unwrap().
819            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            // Reset the start time for timer modes that repeat.
827            self.start = Some(self.clock.lock().now());
828        }
829
830        // For square wave mode, this isn't quite accurate to the spec, but the
831        // difference isn't meaningfully visible to the guest in any important way,
832        // and the code is simpler without the special case.
833        if let Some(interrupt) = &mut self.interrupt_evt {
834            // This is safe because the file descriptor is nonblocking and we're writing 1.
835            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                            // Some risk of raciness here in that the count may return a value
863                            // indicating that the count has expired when the interrupt hasn't
864                            // yet been injected.
865                            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        // The PIT is added to the io_bus in two locations, so the offset depends on which
920        // address range the address is in. The PIT implementation currently does not use the
921        // offset, but we're setting it accurately here in case it does in the future.
922        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    /// Utility method for writing a command word to a command register.
940    fn write_command(pit: &mut Pit, command: u8) {
941        pit.write(pit_bus_address(PortIOSpace::PortCommand), &[command])
942    }
943
944    /// Utility method for writing a command word to the speaker register.
945    fn write_speaker(pit: &mut Pit, command: u8) {
946        pit.write(pit_bus_address(PortIOSpace::PortSpeaker), &[command])
947    }
948
949    /// Utility method for writing to a counter.
950    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        // Write the least, then the most, significant byte.
958        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    /// Utility method for reading a counter. Check if the read value matches expected_value.
971    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    /// Tests the ability to write a command and data and read the data back using latch.
1021    #[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        // Issue a command to write both digits of counter 0 in interrupt mode.
1027        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 time by one tick -- value read back should decrease.
1033        advance_by_tick(&mut data);
1034
1035        // Latch and read back the value written.
1036        write_command(
1037            &mut data.pit,
1038            CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1039        );
1040        // Advance again after latching to verify that value read back doesn't change.
1041        advance_by_tick(&mut data);
1042        read_counter(&mut data.pit, 0, 23, CommandAccess::CommandRWBoth);
1043
1044        // Repeat with counter 1.
1045        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        // Repeat with counter 2.
1059        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    /// Tests the ability to read only the least significant byte.
1074    #[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    /// Tests the ability to read only the most significant byte.
1094    #[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    /// Tests that reading the command register does nothing.
1114    #[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    /// Tests that latching prevents the read time from actually advancing.
1124    #[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        // The counter should ignore this second latch.
1140        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        // It should, however, store the count for this latch.
1146        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    /// Tests Mode 0 (Interrupt on terminal count); checks whether IRQ has been asserted.
1159    #[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 clock enough to trigger interrupt.
1170        advance_by_ticks(&mut data, 0xffff);
1171        data.irqfd.wait().unwrap();
1172    }
1173
1174    /// Tests that Rate Generator mode (mode 2) handls the interrupt properly when the timer
1175    /// expires and that it resets the timer properly.
1176    #[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        // Repatedly advance clock and expect interrupt.
1187        advance_by_ticks(&mut data, 0xffff);
1188        data.irqfd.wait().unwrap();
1189
1190        // Repatedly advance clock and expect interrupt.
1191        advance_by_ticks(&mut data, 0xffff);
1192        data.irqfd.wait().unwrap();
1193
1194        // Repatedly advance clock and expect interrupt.
1195        advance_by_ticks(&mut data, 0xffff);
1196        data.irqfd.wait().unwrap();
1197    }
1198
1199    /// Tests that square wave mode advances the counter correctly.
1200    #[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    /// Tests that rategen mode updates the counter correctly.
1221    #[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    /// Tests that interrupt counter mode updates the counter correctly.
1242    #[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    /// Tests that ReadBack count works properly for `low` access mode.
1266    #[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 100 ticks and verify that low byte of counter is appropriately updated.
1284        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    /// Tests that ReadBack count works properly for `high` access mode.
1307    #[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 100 ticks and verify that low byte of counter is appropriately updated.
1325        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    /// Tests that ReadBack status returns the expected values.
1348    #[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        // In Rate Gen mode, the counter should start over when the gate is
1405        // set to high using SpeakerWrite.
1406        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        // In Interrupt mode, the counter should NOT start over when the gate is
1427        // set to high using SpeakerWrite.
1428        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    /// Verify that invalid reads and writes do not cause crashes.
1437    #[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}