xref: /aosp_15_r20/external/crosvm/devices/src/pit.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 
7 use std::io::Error as IoError;
8 use std::sync::Arc;
9 use std::time::Duration;
10 use std::time::Instant;
11 
12 use anyhow::Context;
13 use base::error;
14 use base::warn;
15 use base::Descriptor;
16 use base::Error as SysError;
17 use base::EventToken;
18 use base::WaitContext;
19 use bit_field::BitField1;
20 use bit_field::*;
21 use hypervisor::PitChannelState;
22 use hypervisor::PitRWMode;
23 use hypervisor::PitRWState;
24 use hypervisor::PitState;
25 use remain::sorted;
26 use sync::Mutex;
27 use thiserror::Error;
28 
29 cfg_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 }
38 use base::TimerTrait;
39 use base::WorkerThread;
40 
41 use crate::bus::BusAccessInfo;
42 use crate::pci::CrosvmDeviceId;
43 use crate::BusDevice;
44 use crate::DeviceId;
45 use crate::IrqEdgeEvent;
46 use crate::Suspendable;
47 
48 // Bitmask for areas of standard (non-ReadBack) Control Word Format. Constant
49 // names are kept the same as Intel PIT data sheet.
50 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
51 enum CommandBit {
52     CommandBCD = 0x01,  // Binary/BCD input. x86 only uses binary mode.
53     CommandMode = 0x0e, // Operating Mode (mode 0-5).
54     CommandRW = 0x30,   // Access mode: Choose high/low byte(s) to Read/Write.
55     CommandSC = 0xc0,   // Select Counter/Read-back command.
56 }
57 
58 // Selects which counter is to be used by the associated command in the lower
59 // six bits of the byte. However, if 0xc0 is specified, it indicates that the
60 // command is a "Read-Back", which can latch count and/or status of the
61 // counters selected in the lower bits. See Intel 8254 data sheet for details.
62 #[allow(dead_code)]
63 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
64 enum CommandCounter {
65     CommandCounter0 = 0x00, // Select counter 0.
66     CommandCounter1 = 0x40, // Select counter 1.
67     CommandCounter2 = 0x80, // Select counter 2.
68     CommandReadBack = 0xc0, // Execute Read-Back.
69 }
70 
71 // Used for both CommandRW and ReadBackAccess.
72 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
73 enum CommandAccess {
74     CommandLatch = 0x00,   // Latch specified counter.
75     CommandRWLeast = 0x10, // Read/Write least significant byte.
76     CommandRWMost = 0x20,  // Read/Write most significant byte.
77     CommandRWBoth = 0x30,  // Read/Write both bytes.
78 }
79 
80 // Used for both CommandMode and ReadBackMode.
81 // For mode 2 & 3, bit 3 is don't care bit (does not matter to be 0 or 1) but
82 // per 8254 spec, should be 0 to insure compatibility with future Intel
83 // products.
84 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
85 enum CommandMode {
86     // NOTE:  No h/w modes are currently implemented.
87     CommandInterrupt = 0x00,     // Mode 0, interrupt on terminal count.
88     CommandHWOneShot = 0x02,     // Mode 1, h/w re-triggerable one-shot.
89     CommandRateGen = 0x04,       // Mode 2, rate generator.
90     CommandSquareWaveGen = 0x06, // Mode 3, square wave generator.
91     CommandSWStrobe = 0x08,      // Mode 4, s/w triggered strobe.
92     CommandHWStrobe = 0x0a,      // Mode 5, h/w triggered strobe.
93 }
94 
95 // Bitmask for the latch portion of the ReadBack command.
96 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
97 #[rustfmt::skip]  // rustfmt mangles comment indentation for trailing line comments.
98 enum CommandReadBackLatch {
99     CommandRBLatchBits = 0x30,   // Mask bits that determine latching.
100     CommandRBLatchBoth = 0x00,   // Latch both count and status. This should
101                                  // never happen in device, since bit 4 and 5 in
102                                  // read back command are inverted.
103     CommandRBLatchCount = 0x10,  // Latch count.
104     CommandRBLatchStatus = 0x20, // Latch status.
105 }
106 
107 // Bitmask for the counter portion of the ReadBack command.
108 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
109 enum CommandReadBackCounters {
110     //CommandRBCounters = 0x0e, // Counters for which to provide ReadBack info.
111     CommandRBCounter2 = 0x08,
112     CommandRBCounter1 = 0x04,
113     CommandRBCounter0 = 0x02,
114 }
115 
116 // Bitmask for the ReadBack status command.
117 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
118 #[rustfmt::skip]  // rustfmt mangles comment indentation for last line of this enum.
119 enum ReadBackData {
120     // Output format for ReadBack command.
121     ReadBackOutput = 0x80, // Output pin status.
122     ReadBackNullCount = 0x40, // Whether counter has value.
123     // ReadBackAccess, ReadBackMode, and ReadBackBCD intentionally omitted.
124 }
125 
126 // I/O Port mappings in I/O bus.
127 #[derive(Debug, Clone, Copy, PartialEq, Eq, enumn::N)]
128 enum PortIOSpace {
129     PortCounter0Data = 0x40, // Read/write.
130     PortCounter1Data = 0x41, // Read/write.
131     PortCounter2Data = 0x42, // Read/write.
132     PortCommand = 0x43,      // Write only.
133     PortSpeaker = 0x61,      // Read/write.
134 }
135 
136 #[bitfield]
137 #[derive(Clone, Copy, PartialEq, Eq)]
138 pub struct SpeakerPortFields {
139     // This field is documented in the chipset spec as NMI status and control
140     // register.  Bits 2, 3, 6, 7 and low level hardware bits that need no
141     // emulation for virtualized environments.  We call it speaker port because
142     // kvm, qemu, linux, and plan9 still call it speaker port, even though it
143     // has these other uses and is called something differently in the spec.
144     gate: BitField1,
145     speaker_on: BitField1,
146     pic_serr: BitField1,
147     iochk_enable: BitField1,
148     // This value changes as part of the refresh frequency of the board for
149     // piix4, this is about 1/15us.
150     refresh_clock: BitField1,
151     output: BitField1,
152     iochk_nmi: BitField1,
153     serr_nmi: BitField1,
154 }
155 
156 // PIT frequency (in Hertz). See http://wiki.osdev.org/pit.
157 const FREQUENCY_HZ: u64 = 1193182;
158 
159 const NUM_OF_COUNTERS: usize = 3;
160 
161 const NANOS_PER_SEC: u64 = 1_000_000_000;
162 
163 const MAX_TIMER_FREQ: u32 = 65536;
164 
165 #[derive(EventToken)]
166 enum Token {
167     // The timer expired.
168     TimerExpire,
169     // The parent thread requested an exit.
170     Kill,
171 }
172 
173 #[sorted]
174 #[derive(Error, Debug)]
175 pub enum PitError {
176     /// Error while cloning event for worker thread.
177     #[error("failed to clone event: {0}")]
178     CloneEvent(SysError),
179     /// Error while creating event.
180     #[error("failed to create event: {0}")]
181     CreateEvent(SysError),
182     /// Creating WaitContext failed.
183     #[error("failed to create poll context: {0}")]
184     CreateWaitContext(SysError),
185     /// Error while trying to create worker thread.
186     #[error("failed to spawn thread: {0}")]
187     SpawnThread(IoError),
188     /// Error while trying to create timer.
189     #[error("failed to create pit counter due to timer fd: {0}")]
190     TimerCreateError(SysError),
191     /// Error while waiting for events.
192     #[error("failed to wait for events: {0}")]
193     WaitError(SysError),
194 }
195 
196 type PitResult<T> = std::result::Result<T, PitError>;
197 
198 pub struct Pit {
199     // Structs that store each counter's state.
200     counters: Vec<Arc<Mutex<PitCounter>>>,
201     // Worker thread to update counter 0's state asynchronously. Counter 0 needs to send interrupts
202     // when timers expire, so it needs asynchronous updates. All other counters need only update
203     // when queried directly by the guest.
204     worker_thread: Option<WorkerThread<PitResult<()>>>,
205     activated: bool,
206 }
207 
208 impl BusDevice for Pit {
debug_label(&self) -> String209     fn debug_label(&self) -> String {
210         "userspace PIT".to_string()
211     }
212 
device_id(&self) -> DeviceId213     fn device_id(&self) -> DeviceId {
214         CrosvmDeviceId::Pit.into()
215     }
216 
write(&mut self, info: BusAccessInfo, data: &[u8])217     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
218         self.ensure_started();
219 
220         if data.len() != 1 {
221             warn!("Bad write size for Pit: {}", data.len());
222             return;
223         }
224         match PortIOSpace::n(info.address as i64) {
225             Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().write_counter(data[0]),
226             Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().write_counter(data[0]),
227             Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().write_counter(data[0]),
228             Some(PortIOSpace::PortCommand) => self.command_write(data[0]),
229             Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().write_speaker(data[0]),
230             None => warn!("PIT: bad write to {}", info),
231         }
232     }
233 
read(&mut self, info: BusAccessInfo, data: &mut [u8])234     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
235         self.ensure_started();
236 
237         if data.len() != 1 {
238             warn!("Bad read size for Pit: {}", data.len());
239             return;
240         }
241         data[0] = match PortIOSpace::n(info.address as i64) {
242             Some(PortIOSpace::PortCounter0Data) => self.counters[0].lock().read_counter(),
243             Some(PortIOSpace::PortCounter1Data) => self.counters[1].lock().read_counter(),
244             Some(PortIOSpace::PortCounter2Data) => self.counters[2].lock().read_counter(),
245             // This should function as a no-op, since the specification doesn't allow the
246             // command register to be read. However, software is free to ask for it to
247             // to be read.
248             Some(PortIOSpace::PortCommand) => {
249                 warn!("Ignoring read to command reg");
250                 0
251             }
252             Some(PortIOSpace::PortSpeaker) => self.counters[2].lock().read_speaker(),
253             None => {
254                 warn!("PIT: bad read from {}", info);
255                 return;
256             }
257         };
258     }
259 }
260 
261 impl Pit {
new(interrupt_evt: IrqEdgeEvent, clock: Arc<Mutex<Clock>>) -> PitResult<Pit>262     pub fn new(interrupt_evt: IrqEdgeEvent, clock: Arc<Mutex<Clock>>) -> PitResult<Pit> {
263         let mut counters = Vec::new();
264         let mut interrupt = Some(interrupt_evt);
265         for i in 0..NUM_OF_COUNTERS {
266             let pit_counter = PitCounter::new(i, interrupt, clock.clone())?;
267             counters.push(Arc::new(Mutex::new(pit_counter)));
268             // pass interrupt IrqFd ONLY to counter 0; the rest do not deliver interrupts.
269             interrupt = None;
270         }
271         // We asssert here because:
272         // (a) this code only gets invoked at VM startup
273         // (b) the assert is very loud and would be easy to notice in tests
274         // (c) if we have the wrong number of counters, something is very wrong with the PIT and it
275         // may not make sense to continue operation.
276         assert_eq!(counters.len(), NUM_OF_COUNTERS);
277 
278         Ok(Pit {
279             counters,
280             worker_thread: None,
281             activated: false,
282         })
283     }
284 
ensure_started(&mut self)285     fn ensure_started(&mut self) {
286         if self.worker_thread.is_some() {
287             return;
288         }
289         if let Err(e) = self.start() {
290             error!("failed to start PIT: {}", e);
291         }
292     }
293 
start(&mut self) -> PitResult<()>294     fn start(&mut self) -> PitResult<()> {
295         let pit_counter = self.counters[0].clone();
296         self.worker_thread = Some(WorkerThread::start("pit counter worker", move |kill_evt| {
297             let timer_descriptor = Descriptor(pit_counter.lock().timer.as_raw_descriptor());
298             let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[
299                 (&timer_descriptor, Token::TimerExpire),
300                 (&kill_evt, Token::Kill),
301             ])
302             .map_err(PitError::CreateWaitContext)?;
303 
304             let mut worker = Worker {
305                 pit_counter,
306                 wait_ctx,
307             };
308 
309             worker.run()
310         }));
311         self.activated = true;
312         Ok(())
313     }
314 
command_write(&mut self, control_word: u8)315     fn command_write(&mut self, control_word: u8) {
316         let command: u16 = (control_word & CommandBit::CommandSC as u8).into();
317         let counter_index: usize = (command >> 6).into();
318         if command == (CommandCounter::CommandReadBack as u16) {
319             // ReadBack commands can apply to multiple counters.
320             if (control_word & (CommandReadBackCounters::CommandRBCounter0 as u8)) != 0 {
321                 self.counters[0].lock().read_back_command(control_word);
322             }
323             if (control_word & (CommandReadBackCounters::CommandRBCounter1 as u8)) != 0 {
324                 self.counters[1].lock().read_back_command(control_word);
325             }
326             if (control_word & (CommandReadBackCounters::CommandRBCounter2 as u8)) != 0 {
327                 self.counters[2].lock().read_back_command(control_word);
328             }
329         } else if (control_word & (CommandBit::CommandRW as u8))
330             == (CommandAccess::CommandLatch as u8)
331         {
332             self.counters[counter_index].lock().latch_counter();
333         } else {
334             self.counters[counter_index]
335                 .lock()
336                 .store_command(control_word);
337         }
338     }
339 
get_pit_state(&self) -> PitState340     pub fn get_pit_state(&self) -> PitState {
341         PitState {
342             channels: [
343                 self.counters[0].lock().get_channel_state(),
344                 self.counters[1].lock().get_channel_state(),
345                 self.counters[2].lock().get_channel_state(),
346             ],
347             flags: 0,
348         }
349     }
350 
set_pit_state(&mut self, state: &PitState)351     pub fn set_pit_state(&mut self, state: &PitState) {
352         self.counters[0]
353             .lock()
354             .set_channel_state(&state.channels[0]);
355         self.counters[1]
356             .lock()
357             .set_channel_state(&state.channels[1]);
358         self.counters[2]
359             .lock()
360             .set_channel_state(&state.channels[2]);
361     }
362 }
363 
364 impl Suspendable for Pit {
sleep(&mut self) -> anyhow::Result<()>365     fn sleep(&mut self) -> anyhow::Result<()> {
366         if let Some(thread) = self.worker_thread.take() {
367             thread
368                 .stop()
369                 .context("pit worker thread exited with error")?;
370         }
371         Ok(())
372     }
373 
wake(&mut self) -> anyhow::Result<()>374     fn wake(&mut self) -> anyhow::Result<()> {
375         if self.activated {
376             if let Err(e) = self.start() {
377                 error!("failed to start PIT: {}", e);
378             }
379         }
380         Ok(())
381     }
382 
383     /// The PIT is only used in very early boot on x86_64, and snapshots are not
384     /// generally taken during that time, so we can safely skip the PIT for now.
snapshot(&mut self) -> anyhow::Result<serde_json::Value>385     fn snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
386         Ok(serde_json::Value::Null)
387     }
388 
389     /// The PIT is only used in very early boot on x86_64, and snapshots are not
390     /// generally taken during that time, so we can safely skip the PIT for now.
restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()>391     fn restore(&mut self, _data: serde_json::Value) -> anyhow::Result<()> {
392         Ok(())
393     }
394 }
395 
396 // Each instance of this represents one of the PIT counters. They are used to
397 // implement one-shot and repeating timer alarms. An 8254 has three counters.
398 struct PitCounter {
399     // Event to write when asserting an interrupt.
400     interrupt_evt: Option<IrqEdgeEvent>,
401     // Stores the value with which the counter was initialized. Counters are 16-
402     // bit values with an effective range of 1-65536 (65536 represented by 0).
403     reload_value: u16,
404     // Stores value when latch was called.
405     latched_value: u16,
406     // Stores last command from command register.
407     command: u8,
408     // Stores status from readback command
409     status: u8,
410     // Stores time of starting timer. Used for calculating remaining count, if an alarm is
411     // scheduled.
412     start: Option<Instant>,
413     // Current time.
414     clock: Arc<Mutex<Clock>>,
415     // Time when object was created. Used for a 15us counter.
416     creation_time: Instant,
417     // The number of the counter. The behavior for each counter is slightly different.
418     // Note that once a PitCounter is created, this value should never change.
419     counter_id: usize,
420     // Indicates if the low byte has been written in RWBoth.
421     wrote_low_byte: bool,
422     // Indicates if the low byte has been read in RWBoth.
423     read_low_byte: bool,
424     // Indicates whether counter has been latched.
425     latched: bool,
426     // Indicates whether ReadBack status has been latched.
427     status_latched: bool,
428     // Only should be used for counter 2. See http://wiki.osdev.org/PIT.
429     gate: bool,
430     speaker_on: bool,
431     // The starting value for the counter.
432     count: u32,
433     // Indicates whether the current timer is valid.
434     timer_valid: bool,
435     // Timer to set and receive periodic notifications.
436     timer: Box<dyn TimerTrait>,
437 }
438 
439 impl Drop for PitCounter {
drop(&mut self)440     fn drop(&mut self) {
441         if self.timer_valid {
442             // This should not fail - timer.clear() only fails if timerfd_settime fails, which
443             // only happens due to invalid arguments or bad file descriptors. The arguments to
444             // timerfd_settime are constant, so its arguments won't be invalid, and it manages
445             // the file descriptor safely (we don't use the unsafe FromRawDescriptor) so its file
446             // descriptor will be valid.
447             self.timer.clear().unwrap();
448         }
449     }
450 }
451 
adjust_count(count: u32) -> u32452 fn adjust_count(count: u32) -> u32 {
453     // As per spec 0 means max.
454     if count == 0 {
455         MAX_TIMER_FREQ
456     } else {
457         count
458     }
459 }
460 
461 impl PitCounter {
new( counter_id: usize, interrupt_evt: Option<IrqEdgeEvent>, clock: Arc<Mutex<Clock>>, ) -> PitResult<PitCounter>462     fn new(
463         counter_id: usize,
464         interrupt_evt: Option<IrqEdgeEvent>,
465         clock: Arc<Mutex<Clock>>,
466     ) -> PitResult<PitCounter> {
467         #[cfg(not(test))]
468         let timer = Timer::new().map_err(PitError::TimerCreateError)?;
469         #[cfg(test)]
470         let timer = Timer::new(clock.clone());
471         Ok(PitCounter {
472             interrupt_evt,
473             reload_value: 0,
474             latched_value: 0,
475             command: 0,
476             status: 0,
477             start: None,
478             clock: clock.clone(),
479             creation_time: clock.lock().now(),
480             counter_id,
481             wrote_low_byte: false,
482             read_low_byte: false,
483             latched: false,
484             status_latched: false,
485             gate: false,
486             speaker_on: false,
487             // `count` is undefined in real hardware and can't ever be programmed to 0, so we
488             // initialize it to max to prevent a misbehaving guest from triggering a divide by 0.
489             count: MAX_TIMER_FREQ,
490             timer_valid: false,
491             timer: Box::new(timer),
492         })
493     }
494 
get_channel_state(&self) -> PitChannelState495     fn get_channel_state(&self) -> PitChannelState {
496         let load_time = match &self.start {
497             Some(t) => t.saturating_duration_since(self.creation_time).as_nanos() as u64,
498             None => 0,
499         };
500 
501         let mut state = PitChannelState {
502             count: self.count,
503             latched_count: self.latched_value,
504             status_latched: self.status_latched,
505             status: self.status,
506             reload_value: self.reload_value,
507             mode: (self.command & CommandBit::CommandMode as u8) >> 1,
508             bcd: false,
509             gate: self.gate,
510             count_load_time: load_time,
511             rw_mode: PitRWMode::None,
512             read_state: PitRWState::None,
513             write_state: PitRWState::None,
514             count_latched: PitRWState::None,
515         };
516 
517         match self.get_access_mode() {
518             Some(CommandAccess::CommandRWLeast) => {
519                 // If access mode is least, RWStates are always LSB
520                 state.rw_mode = PitRWMode::Least;
521                 state.read_state = PitRWState::LSB;
522                 state.write_state = PitRWState::LSB;
523             }
524             Some(CommandAccess::CommandRWMost) => {
525                 // If access mode is most, RWStates are always MSB
526                 state.rw_mode = PitRWMode::Most;
527                 state.read_state = PitRWState::MSB;
528                 state.write_state = PitRWState::MSB;
529             }
530             Some(CommandAccess::CommandRWBoth) => {
531                 state.rw_mode = PitRWMode::Both;
532                 // read_state depends on whether or not we've read the low byte already
533                 state.read_state = if self.read_low_byte {
534                     PitRWState::Word1
535                 } else {
536                     PitRWState::Word0
537                 };
538                 // write_state depends on whether or not we've written the low byte already
539                 state.write_state = if self.wrote_low_byte {
540                     PitRWState::Word1
541                 } else {
542                     PitRWState::Word0
543                 };
544             }
545             _ => {}
546         };
547 
548         // Count_latched should be PitRWSTate::None unless we're latched
549         if self.latched {
550             state.count_latched = state.read_state;
551         }
552 
553         state
554     }
555 
set_channel_state(&mut self, state: &PitChannelState)556     fn set_channel_state(&mut self, state: &PitChannelState) {
557         self.count = state.count;
558         self.latched_value = state.latched_count;
559         self.status_latched = state.status_latched;
560         self.status = state.status;
561         self.reload_value = state.reload_value;
562 
563         // the command consists of:
564         //  - 1 bcd bit, which we don't care about because we don't support non-binary mode
565         //  - 3 mode bits
566         //  - 2 access mode bits
567         //  - 2 counter select bits, which aren't used by the counter/channel itself
568         self.command = (state.mode << 1) | ((state.rw_mode as u8) << 4);
569         self.gate = state.gate;
570         self.latched = state.count_latched != PitRWState::None;
571         self.read_low_byte = state.read_state == PitRWState::Word1;
572         self.wrote_low_byte = state.write_state == PitRWState::Word1;
573 
574         self.start = self
575             .creation_time
576             .checked_add(Duration::from_nanos(state.count_load_time));
577     }
578 
get_access_mode(&self) -> Option<CommandAccess>579     fn get_access_mode(&self) -> Option<CommandAccess> {
580         CommandAccess::n(self.command & (CommandBit::CommandRW as u8))
581     }
582 
get_command_mode(&self) -> Option<CommandMode>583     fn get_command_mode(&self) -> Option<CommandMode> {
584         CommandMode::n(self.command & CommandBit::CommandMode as u8)
585     }
586 
read_counter(&mut self) -> u8587     fn read_counter(&mut self) -> u8 {
588         if self.status_latched {
589             self.status_latched = false;
590             return self.status;
591         };
592         let data_value: u16 = if self.latched {
593             self.latched_value
594         } else {
595             self.get_read_value()
596         };
597 
598         let access_mode = self.get_access_mode();
599         // Latch may be true without being indicated by the access mode if
600         // a ReadBack was issued.
601         match (access_mode, self.read_low_byte) {
602             (Some(CommandAccess::CommandRWLeast), _) => {
603                 self.latched = false; // Unlatch if only reading the low byte.
604                 (data_value & 0xff) as u8
605             }
606             (Some(CommandAccess::CommandRWBoth), false) => {
607                 self.read_low_byte = true;
608                 (data_value & 0xff) as u8
609             }
610             (Some(CommandAccess::CommandRWBoth), true)
611             | (Some(CommandAccess::CommandRWMost), _) => {
612                 self.read_low_byte = false; // Allow for future reads for RWBoth.
613                 self.latched = false;
614                 (data_value >> 8) as u8
615             }
616             (_, _) => 0, // Default for erroneous call
617         }
618     }
619 
write_counter(&mut self, written_datum: u8)620     fn write_counter(&mut self, written_datum: u8) {
621         let access_mode = self.get_access_mode();
622         let datum: u16 = written_datum.into();
623         let mut should_start_timer = true;
624         self.reload_value = match access_mode {
625             Some(CommandAccess::CommandRWLeast) => datum,
626             Some(CommandAccess::CommandRWMost) => datum << 8,
627             Some(CommandAccess::CommandRWBoth) => {
628                 // In kCommandRWBoth mode, the first guest write is the low byte and the
629                 // the second guest write is the high byte.  The timer isn't started
630                 // until after the second byte is written.
631                 if self.wrote_low_byte {
632                     self.wrote_low_byte = false;
633                     self.reload_value | (datum << 8)
634                 } else {
635                     self.wrote_low_byte = true;
636                     should_start_timer = false; // Don't start until high byte written.
637                     datum
638                 }
639             }
640             _ => {
641                 should_start_timer = false;
642                 self.reload_value
643             }
644         };
645         if should_start_timer {
646             let reload: u32 = self.reload_value.into();
647             self.load_and_start_timer(reload);
648         }
649     }
650 
get_output(&self) -> bool651     fn get_output(&self) -> bool {
652         let ticks_passed = self.get_ticks_passed();
653         let count: u64 = self.count.into();
654         match self.get_command_mode() {
655             Some(CommandMode::CommandInterrupt) => ticks_passed >= count,
656             Some(CommandMode::CommandHWOneShot) => ticks_passed < count,
657             Some(CommandMode::CommandRateGen) => ticks_passed != 0 && ticks_passed % count == 0,
658             Some(CommandMode::CommandSquareWaveGen) => ticks_passed < (count + 1) / 2,
659             Some(CommandMode::CommandSWStrobe) | Some(CommandMode::CommandHWStrobe) => {
660                 ticks_passed == count
661             }
662             None => {
663                 warn!("Invalid command mode based on command: {:#x}", self.command);
664                 false
665             }
666         }
667     }
668 
read_speaker(&self) -> u8669     fn read_speaker(&self) -> u8 {
670         // Refresh clock is a value independent of the actual
671         // counter that goes up and down approx every 15 us (~66000/s).
672         let us = self
673             .clock
674             .lock()
675             .now()
676             .duration_since(self.creation_time)
677             .subsec_micros();
678         let refresh_clock = us % 15 == 0;
679         let mut speaker = SpeakerPortFields::new();
680         speaker.set_gate(self.gate.into());
681         speaker.set_speaker_on(self.speaker_on.into());
682         speaker.set_iochk_enable(0);
683         speaker.set_refresh_clock(refresh_clock.into());
684         speaker.set_output(self.get_output().into());
685         speaker.set_iochk_nmi(0);
686         speaker.set_serr_nmi(0);
687         speaker.get(/* offset= */ 0, /* width= */ 8) as u8
688     }
689 
write_speaker(&mut self, datum: u8)690     fn write_speaker(&mut self, datum: u8) {
691         let mut speaker = SpeakerPortFields::new();
692         speaker.set(/* offset= */ 0, /* width= */ 8, datum.into());
693         let new_gate = speaker.get_gate() != 0;
694         match self.get_command_mode() {
695             Some(CommandMode::CommandInterrupt) | Some(CommandMode::CommandSWStrobe) => (),
696             Some(_) => {
697                 if new_gate && !self.gate {
698                     self.start = Some(self.clock.lock().now());
699                 }
700             }
701             None => {
702                 warn!("Invalid command mode based on command {:#x}", self.command);
703                 return;
704             }
705         }
706         self.speaker_on = speaker.get_speaker_on() != 0;
707         self.gate = new_gate;
708     }
709 
load_and_start_timer(&mut self, initial_count: u32)710     fn load_and_start_timer(&mut self, initial_count: u32) {
711         self.count = adjust_count(initial_count);
712         self.start_timer();
713     }
714 
start_timer(&mut self)715     fn start_timer(&mut self) {
716         self.start = Some(self.clock.lock().now());
717 
718         // Counter 0 is the only counter that generates interrupts, so we
719         // don't need to set a timer for the other two counters.
720         if self.counter_id != 0 {
721             return;
722         }
723 
724         let timer_len = Duration::from_nanos(u64::from(self.count) * NANOS_PER_SEC / FREQUENCY_HZ);
725         let safe_timer_len = if timer_len == Duration::new(0, 0) {
726             Duration::from_nanos(1)
727         } else {
728             timer_len
729         };
730 
731         match self.get_command_mode() {
732             Some(CommandMode::CommandInterrupt)
733             | Some(CommandMode::CommandHWOneShot)
734             | Some(CommandMode::CommandSWStrobe)
735             | Some(CommandMode::CommandHWStrobe) => {
736                 if let Err(e) = self.timer.reset_oneshot(safe_timer_len) {
737                     error!("failed to reset oneshot timer: {}", e);
738                 }
739             }
740             Some(CommandMode::CommandRateGen) | Some(CommandMode::CommandSquareWaveGen) => {
741                 if let Err(e) = self.timer.reset_repeating(safe_timer_len) {
742                     error!("failed to reset repeating timer: {}", e);
743                 }
744             }
745             // Don't arm timer if invalid mode.
746             None => {
747                 // This will still result in start being set to the current time.
748                 // Per spec:
749                 //   A new initial count may be written to a Counter at any time without affecting
750                 //   the Counter’s programmed Mode in any way. Counting will be affected as
751                 //   described in the Mode definitions. The new count must follow the programmed
752                 //   count format
753                 // It's unclear whether setting `self.start` in this case is entirely compliant,
754                 // but the spec is fairly quiet on expected behavior in error cases, so OSs
755                 // shouldn't enter invalid modes in the first place.  If they do, and then try to
756                 // get out of it by first setting the counter then the command, this behavior will
757                 // (perhaps) be minimally surprising, but arguments can be made for other behavior.
758                 // It's uncertain if this behavior matches real PIT hardware.
759                 warn!("Invalid command mode based on command {:#x}", self.command);
760                 return;
761             }
762         }
763 
764         self.timer_valid = true;
765     }
766 
read_back_command(&mut self, control_word: u8)767     fn read_back_command(&mut self, control_word: u8) {
768         let latch_cmd =
769             CommandReadBackLatch::n(control_word & CommandReadBackLatch::CommandRBLatchBits as u8);
770         match latch_cmd {
771             Some(CommandReadBackLatch::CommandRBLatchCount) => {
772                 self.latch_counter();
773             }
774             Some(CommandReadBackLatch::CommandRBLatchStatus) => {
775                 self.latch_status();
776             }
777             _ => warn!(
778                 "Unexpected ReadBackLatch. control_word: {:#x}",
779                 control_word
780             ),
781         };
782     }
783 
latch_counter(&mut self)784     fn latch_counter(&mut self) {
785         if self.latched {
786             return;
787         }
788 
789         self.latched_value = self.get_read_value();
790         self.latched = true;
791         self.read_low_byte = false;
792     }
793 
latch_status(&mut self)794     fn latch_status(&mut self) {
795         // Including BCD here, even though it currently never gets used.
796         self.status = self.command
797             & (CommandBit::CommandRW as u8
798                 | CommandBit::CommandMode as u8
799                 | CommandBit::CommandBCD as u8);
800         if self.start.is_none() {
801             self.status |= ReadBackData::ReadBackNullCount as u8;
802         }
803         if self.get_output() {
804             self.status |= ReadBackData::ReadBackOutput as u8;
805         }
806         self.status_latched = true;
807     }
808 
store_command(&mut self, datum: u8)809     fn store_command(&mut self, datum: u8) {
810         self.command = datum;
811         self.latched = false;
812 
813         // If a new RW command is written, cancel the current timer.
814         if self.timer_valid {
815             self.start = None;
816             self.timer_valid = false;
817             // See the comment in the impl of Drop for PitCounter for justification of the unwrap()
818             self.timer.clear().unwrap();
819         }
820 
821         self.wrote_low_byte = false;
822         self.read_low_byte = false;
823     }
824 
timer_handler(&mut self)825     fn timer_handler(&mut self) {
826         if let Err(e) = self.timer.mark_waited() {
827             // Under the current Timer implementation (as of Jan 2019), this failure shouldn't
828             // happen but implementation details may change in the future, and the failure
829             // cases are complex to reason about. Because of this, avoid unwrap().
830             error!("pit: timer wait unexpectedly failed: {}", e);
831             return;
832         }
833         let mode = self.get_command_mode();
834         if mode == Some(CommandMode::CommandRateGen)
835             || mode == Some(CommandMode::CommandSquareWaveGen)
836         {
837             // Reset the start time for timer modes that repeat.
838             self.start = Some(self.clock.lock().now());
839         }
840 
841         // For square wave mode, this isn't quite accurate to the spec, but the
842         // difference isn't meaningfully visible to the guest in any important way,
843         // and the code is simpler without the special case.
844         if let Some(interrupt) = &mut self.interrupt_evt {
845             // This is safe because the file descriptor is nonblocking and we're writing 1.
846             interrupt.trigger().unwrap();
847         }
848     }
849 
get_ticks_passed(&self) -> u64850     fn get_ticks_passed(&self) -> u64 {
851         match self.start {
852             None => 0,
853             Some(t) => {
854                 let dur = self.clock.lock().now().duration_since(t);
855                 let dur_ns: u64 = dur.as_secs() * NANOS_PER_SEC + u64::from(dur.subsec_nanos());
856                 dur_ns * FREQUENCY_HZ / NANOS_PER_SEC
857             }
858         }
859     }
860 
get_read_value(&self) -> u16861     fn get_read_value(&self) -> u16 {
862         match self.start {
863             None => 0,
864             Some(_) => {
865                 let count: u64 = adjust_count(self.reload_value.into()).into();
866                 let ticks_passed = self.get_ticks_passed();
867                 match self.get_command_mode() {
868                     Some(CommandMode::CommandInterrupt)
869                     | Some(CommandMode::CommandHWOneShot)
870                     | Some(CommandMode::CommandSWStrobe)
871                     | Some(CommandMode::CommandHWStrobe) => {
872                         if ticks_passed > count {
873                             // Some risk of raciness here in that the count may return a value
874                             // indicating that the count has expired when the interrupt hasn't
875                             // yet been injected.
876                             0
877                         } else {
878                             ((count - ticks_passed) & 0xFFFF) as u16
879                         }
880                     }
881                     Some(CommandMode::CommandRateGen) => (count - (ticks_passed % count)) as u16,
882                     Some(CommandMode::CommandSquareWaveGen) => {
883                         (count - ((ticks_passed * 2) % count)) as u16
884                     }
885                     None => {
886                         warn!("Invalid command mode: command = {:#x}", self.command);
887                         0
888                     }
889                 }
890             }
891         }
892     }
893 }
894 
895 struct Worker {
896     pit_counter: Arc<Mutex<PitCounter>>,
897     wait_ctx: WaitContext<Token>,
898 }
899 
900 impl Worker {
run(&mut self) -> PitResult<()>901     fn run(&mut self) -> PitResult<()> {
902         loop {
903             let events = self.wait_ctx.wait().map_err(PitError::WaitError)?;
904             for event in events.iter().filter(|e| e.is_readable) {
905                 match event.token {
906                     Token::TimerExpire => {
907                         let mut pit = self.pit_counter.lock();
908                         pit.timer_handler();
909                     }
910                     Token::Kill => return Ok(()),
911                 }
912             }
913         }
914     }
915 }
916 
917 #[cfg(test)]
918 mod tests {
919     use base::Event;
920 
921     use super::*;
922 
923     struct TestData {
924         pit: Pit,
925         irqfd: Event,
926         clock: Arc<Mutex<Clock>>,
927     }
928 
pit_bus_address(address: PortIOSpace) -> BusAccessInfo929     fn pit_bus_address(address: PortIOSpace) -> BusAccessInfo {
930         // The PIT is added to the io_bus in two locations, so the offset depends on which
931         // address range the address is in. The PIT implementation currently does not use the
932         // offset, but we're setting it accurately here in case it does in the future.
933         let offset = match address as u64 {
934             x if x >= PortIOSpace::PortCounter0Data as u64
935                 && x < PortIOSpace::PortCounter0Data as u64 + 0x8 =>
936             {
937                 address as u64 - PortIOSpace::PortCounter0Data as u64
938             }
939             x if x == PortIOSpace::PortSpeaker as u64 => 0,
940             _ => panic!("invalid PIT address: {:#x}", address as u64),
941         };
942 
943         BusAccessInfo {
944             offset,
945             address: address as u64,
946             id: 0,
947         }
948     }
949 
950     /// Utility method for writing a command word to a command register.
write_command(pit: &mut Pit, command: u8)951     fn write_command(pit: &mut Pit, command: u8) {
952         pit.write(pit_bus_address(PortIOSpace::PortCommand), &[command])
953     }
954 
955     /// Utility method for writing a command word to the speaker register.
write_speaker(pit: &mut Pit, command: u8)956     fn write_speaker(pit: &mut Pit, command: u8) {
957         pit.write(pit_bus_address(PortIOSpace::PortSpeaker), &[command])
958     }
959 
960     /// Utility method for writing to a counter.
write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess)961     fn write_counter(pit: &mut Pit, counter_idx: usize, data: u16, access_mode: CommandAccess) {
962         let port = match counter_idx {
963             0 => PortIOSpace::PortCounter0Data,
964             1 => PortIOSpace::PortCounter1Data,
965             2 => PortIOSpace::PortCounter2Data,
966             _ => panic!("Invalid counter_idx: {}", counter_idx),
967         };
968         // Write the least, then the most, significant byte.
969         if access_mode == CommandAccess::CommandRWLeast
970             || access_mode == CommandAccess::CommandRWBoth
971         {
972             pit.write(pit_bus_address(port), &[(data & 0xff) as u8]);
973         }
974         if access_mode == CommandAccess::CommandRWMost
975             || access_mode == CommandAccess::CommandRWBoth
976         {
977             pit.write(pit_bus_address(port), &[(data >> 8) as u8]);
978         }
979     }
980 
981     /// Utility method for reading a counter. Check if the read value matches expected_value.
read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess)982     fn read_counter(pit: &mut Pit, counter_idx: usize, expected: u16, access_mode: CommandAccess) {
983         let port = match counter_idx {
984             0 => PortIOSpace::PortCounter0Data,
985             1 => PortIOSpace::PortCounter1Data,
986             2 => PortIOSpace::PortCounter2Data,
987             _ => panic!("Invalid counter_idx: {}", counter_idx),
988         };
989         let mut result: u16 = 0;
990         if access_mode == CommandAccess::CommandRWLeast
991             || access_mode == CommandAccess::CommandRWBoth
992         {
993             let mut buffer = [0];
994             pit.read(pit_bus_address(port), &mut buffer);
995             result = buffer[0].into();
996         }
997         if access_mode == CommandAccess::CommandRWMost
998             || access_mode == CommandAccess::CommandRWBoth
999         {
1000             let mut buffer = [0];
1001             pit.read(pit_bus_address(port), &mut buffer);
1002             result |= u16::from(buffer[0]) << 8;
1003         }
1004         assert_eq!(result, expected);
1005     }
1006 
set_up() -> TestData1007     fn set_up() -> TestData {
1008         let evt = IrqEdgeEvent::new().unwrap();
1009         let clock = Arc::new(Mutex::new(Clock::new()));
1010         TestData {
1011             irqfd: evt.get_trigger().try_clone().unwrap(),
1012             pit: Pit::new(evt, clock.clone()).unwrap(),
1013             clock,
1014         }
1015     }
1016 
advance_by_tick(data: &mut TestData)1017     fn advance_by_tick(data: &mut TestData) {
1018         advance_by_ticks(data, 1);
1019     }
1020 
advance_by_ticks(data: &mut TestData, ticks: u64)1021     fn advance_by_ticks(data: &mut TestData, ticks: u64) {
1022         println!(
1023             "Advancing by {:#x} ticks ({} ns)",
1024             ticks,
1025             (NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1
1026         );
1027         let mut lock = data.clock.lock();
1028         lock.add_ns((NANOS_PER_SEC * ticks) / FREQUENCY_HZ + 1);
1029     }
1030 
1031     /// Tests the ability to write a command and data and read the data back using latch.
1032     #[test]
write_and_latch()1033     fn write_and_latch() {
1034         let mut data = set_up();
1035         let both_interrupt =
1036             CommandAccess::CommandRWBoth as u8 | CommandMode::CommandInterrupt as u8;
1037         // Issue a command to write both digits of counter 0 in interrupt mode.
1038         write_command(
1039             &mut data.pit,
1040             CommandCounter::CommandCounter0 as u8 | both_interrupt,
1041         );
1042         write_counter(&mut data.pit, 0, 24, CommandAccess::CommandRWBoth);
1043         // Advance time by one tick -- value read back should decrease.
1044         advance_by_tick(&mut data);
1045 
1046         // Latch and read back the value written.
1047         write_command(
1048             &mut data.pit,
1049             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1050         );
1051         // Advance again after latching to verify that value read back doesn't change.
1052         advance_by_tick(&mut data);
1053         read_counter(&mut data.pit, 0, 23, CommandAccess::CommandRWBoth);
1054 
1055         // Repeat with counter 1.
1056         write_command(
1057             &mut data.pit,
1058             CommandCounter::CommandCounter1 as u8 | both_interrupt,
1059         );
1060         write_counter(&mut data.pit, 1, 314, CommandAccess::CommandRWBoth);
1061         advance_by_tick(&mut data);
1062         write_command(
1063             &mut data.pit,
1064             CommandCounter::CommandCounter1 as u8 | CommandAccess::CommandLatch as u8,
1065         );
1066         advance_by_tick(&mut data);
1067         read_counter(&mut data.pit, 1, 313, CommandAccess::CommandRWBoth);
1068 
1069         // Repeat with counter 2.
1070         write_command(
1071             &mut data.pit,
1072             CommandCounter::CommandCounter2 as u8 | both_interrupt,
1073         );
1074         write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1075         advance_by_tick(&mut data);
1076         write_command(
1077             &mut data.pit,
1078             CommandCounter::CommandCounter2 as u8 | CommandAccess::CommandLatch as u8,
1079         );
1080         advance_by_tick(&mut data);
1081         read_counter(&mut data.pit, 2, 0xfffe, CommandAccess::CommandRWBoth);
1082     }
1083 
1084     /// Tests the ability to read only the least significant byte.
1085     #[test]
write_and_read_least()1086     fn write_and_read_least() {
1087         let mut data = set_up();
1088         write_command(
1089             &mut data.pit,
1090             CommandCounter::CommandCounter0 as u8
1091                 | CommandAccess::CommandRWLeast as u8
1092                 | CommandMode::CommandInterrupt as u8,
1093         );
1094         write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWLeast);
1095         read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1096         write_command(
1097             &mut data.pit,
1098             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1099         );
1100         advance_by_tick(&mut data);
1101         read_counter(&mut data.pit, 0, 0x0024, CommandAccess::CommandRWLeast);
1102     }
1103 
1104     /// Tests the ability to read only the most significant byte.
1105     #[test]
write_and_read_most()1106     fn write_and_read_most() {
1107         let mut data = set_up();
1108         write_command(
1109             &mut data.pit,
1110             CommandCounter::CommandCounter0 as u8
1111                 | CommandAccess::CommandRWMost as u8
1112                 | CommandMode::CommandInterrupt as u8,
1113         );
1114         write_counter(&mut data.pit, 0, 0x3424, CommandAccess::CommandRWMost);
1115         read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1116         write_command(
1117             &mut data.pit,
1118             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1119         );
1120         advance_by_tick(&mut data);
1121         read_counter(&mut data.pit, 0, 0x3400, CommandAccess::CommandRWMost);
1122     }
1123 
1124     /// Tests that reading the command register does nothing.
1125     #[test]
read_command()1126     fn read_command() {
1127         let mut data = set_up();
1128         let mut buf = [0];
1129         data.pit
1130             .read(pit_bus_address(PortIOSpace::PortCommand), &mut buf);
1131         assert_eq!(buf, [0]);
1132     }
1133 
1134     /// Tests that latching prevents the read time from actually advancing.
1135     #[test]
test_timed_latch()1136     fn test_timed_latch() {
1137         let mut data = set_up();
1138         write_command(
1139             &mut data.pit,
1140             CommandCounter::CommandCounter0 as u8
1141                 | CommandAccess::CommandRWBoth as u8
1142                 | CommandMode::CommandInterrupt as u8,
1143         );
1144         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1145         write_command(
1146             &mut data.pit,
1147             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1148         );
1149         data.clock.lock().add_ns(25_000_000);
1150         // The counter should ignore this second latch.
1151         write_command(
1152             &mut data.pit,
1153             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1154         );
1155         read_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1156         // It should, however, store the count for this latch.
1157         write_command(
1158             &mut data.pit,
1159             CommandCounter::CommandCounter0 as u8 | CommandAccess::CommandLatch as u8,
1160         );
1161         read_counter(
1162             &mut data.pit,
1163             0,
1164             0xffff - ((25_000_000 * FREQUENCY_HZ) / NANOS_PER_SEC) as u16,
1165             CommandAccess::CommandRWBoth,
1166         );
1167     }
1168 
1169     /// Tests Mode 0 (Interrupt on terminal count); checks whether IRQ has been asserted.
1170     #[test]
interrupt_mode()1171     fn interrupt_mode() {
1172         let mut data = set_up();
1173         write_command(
1174             &mut data.pit,
1175             CommandCounter::CommandCounter0 as u8
1176                 | CommandAccess::CommandRWBoth as u8
1177                 | CommandMode::CommandInterrupt as u8,
1178         );
1179         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1180         // Advance clock enough to trigger interrupt.
1181         advance_by_ticks(&mut data, 0xffff);
1182         data.irqfd.wait().unwrap();
1183     }
1184 
1185     /// Tests that Rate Generator mode (mode 2) handls the interrupt properly when the timer
1186     /// expires and that it resets the timer properly.
1187     #[test]
rate_gen_mode()1188     fn rate_gen_mode() {
1189         let mut data = set_up();
1190         write_command(
1191             &mut data.pit,
1192             CommandCounter::CommandCounter0 as u8
1193                 | CommandAccess::CommandRWBoth as u8
1194                 | CommandMode::CommandRateGen as u8,
1195         );
1196         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1197         // Repatedly advance clock and expect interrupt.
1198         advance_by_ticks(&mut data, 0xffff);
1199         data.irqfd.wait().unwrap();
1200 
1201         // Repatedly advance clock and expect interrupt.
1202         advance_by_ticks(&mut data, 0xffff);
1203         data.irqfd.wait().unwrap();
1204 
1205         // Repatedly advance clock and expect interrupt.
1206         advance_by_ticks(&mut data, 0xffff);
1207         data.irqfd.wait().unwrap();
1208     }
1209 
1210     /// Tests that square wave mode advances the counter correctly.
1211     #[test]
square_wave_counter_read()1212     fn square_wave_counter_read() {
1213         let mut data = set_up();
1214         write_command(
1215             &mut data.pit,
1216             CommandCounter::CommandCounter0 as u8
1217                 | CommandAccess::CommandRWBoth as u8
1218                 | CommandMode::CommandSquareWaveGen as u8,
1219         );
1220         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1221 
1222         advance_by_ticks(&mut data, 10_000);
1223         read_counter(
1224             &mut data.pit,
1225             0,
1226             0xffff - 10_000 * 2,
1227             CommandAccess::CommandRWBoth,
1228         );
1229     }
1230 
1231     /// Tests that rategen mode updates the counter correctly.
1232     #[test]
rate_gen_counter_read()1233     fn rate_gen_counter_read() {
1234         let mut data = set_up();
1235         write_command(
1236             &mut data.pit,
1237             CommandCounter::CommandCounter0 as u8
1238                 | CommandAccess::CommandRWBoth as u8
1239                 | CommandMode::CommandRateGen as u8,
1240         );
1241         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1242 
1243         advance_by_ticks(&mut data, 10_000);
1244         read_counter(
1245             &mut data.pit,
1246             0,
1247             0xffff - 10_000,
1248             CommandAccess::CommandRWBoth,
1249         );
1250     }
1251 
1252     /// Tests that interrupt counter mode updates the counter correctly.
1253     #[test]
interrupt_counter_read()1254     fn interrupt_counter_read() {
1255         let mut data = set_up();
1256         write_command(
1257             &mut data.pit,
1258             CommandCounter::CommandCounter0 as u8
1259                 | CommandAccess::CommandRWBoth as u8
1260                 | CommandMode::CommandInterrupt as u8,
1261         );
1262         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1263 
1264         advance_by_ticks(&mut data, 10_000);
1265         read_counter(
1266             &mut data.pit,
1267             0,
1268             0xffff - 10_000,
1269             CommandAccess::CommandRWBoth,
1270         );
1271 
1272         advance_by_ticks(&mut data, 3 * FREQUENCY_HZ);
1273         read_counter(&mut data.pit, 0, 0, CommandAccess::CommandRWBoth);
1274     }
1275 
1276     /// Tests that ReadBack count works properly for `low` access mode.
1277     #[test]
read_back_count_access_low()1278     fn read_back_count_access_low() {
1279         let mut data = set_up();
1280         write_command(
1281             &mut data.pit,
1282             CommandCounter::CommandCounter0 as u8
1283                 | CommandAccess::CommandRWLeast as u8
1284                 | CommandMode::CommandInterrupt as u8,
1285         );
1286         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1287         write_command(
1288             &mut data.pit,
1289             CommandCounter::CommandReadBack as u8
1290                 | CommandReadBackLatch::CommandRBLatchCount as u8
1291                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1292         );
1293 
1294         // Advance 100 ticks and verify that low byte of counter is appropriately updated.
1295         advance_by_ticks(&mut data, 100);
1296         write_command(
1297             &mut data.pit,
1298             CommandCounter::CommandReadBack as u8
1299                 | CommandReadBackLatch::CommandRBLatchCount as u8
1300                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1301         );
1302         read_counter(&mut data.pit, 0, 0x00ff, CommandAccess::CommandRWLeast);
1303         write_command(
1304             &mut data.pit,
1305             CommandCounter::CommandReadBack as u8
1306                 | CommandReadBackLatch::CommandRBLatchCount as u8
1307                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1308         );
1309         read_counter(
1310             &mut data.pit,
1311             0,
1312             (0xffff - 100) & 0x00ff,
1313             CommandAccess::CommandRWLeast,
1314         );
1315     }
1316 
1317     /// Tests that ReadBack count works properly for `high` access mode.
1318     #[test]
read_back_count_access_high()1319     fn read_back_count_access_high() {
1320         let mut data = set_up();
1321         write_command(
1322             &mut data.pit,
1323             CommandCounter::CommandCounter0 as u8
1324                 | CommandAccess::CommandRWMost as u8
1325                 | CommandMode::CommandInterrupt as u8,
1326         );
1327         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWLeast);
1328         write_command(
1329             &mut data.pit,
1330             CommandCounter::CommandReadBack as u8
1331                 | CommandReadBackLatch::CommandRBLatchCount as u8
1332                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1333         );
1334 
1335         // Advance 100 ticks and verify that low byte of counter is appropriately updated.
1336         advance_by_ticks(&mut data, 512);
1337         write_command(
1338             &mut data.pit,
1339             CommandCounter::CommandReadBack as u8
1340                 | CommandReadBackLatch::CommandRBLatchCount as u8
1341                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1342         );
1343         read_counter(&mut data.pit, 0, 0xff00, CommandAccess::CommandRWMost);
1344         write_command(
1345             &mut data.pit,
1346             CommandCounter::CommandReadBack as u8
1347                 | CommandReadBackLatch::CommandRBLatchCount as u8
1348                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1349         );
1350         read_counter(
1351             &mut data.pit,
1352             0,
1353             (0xffff - 512) & 0xff00,
1354             CommandAccess::CommandRWMost,
1355         );
1356     }
1357 
1358     /// Tests that ReadBack status returns the expected values.
1359     #[test]
read_back_status()1360     fn read_back_status() {
1361         let mut data = set_up();
1362         write_command(
1363             &mut data.pit,
1364             CommandCounter::CommandCounter0 as u8
1365                 | CommandAccess::CommandRWBoth as u8
1366                 | CommandMode::CommandSWStrobe as u8,
1367         );
1368         write_counter(&mut data.pit, 0, 0xffff, CommandAccess::CommandRWBoth);
1369         write_command(
1370             &mut data.pit,
1371             CommandCounter::CommandReadBack as u8
1372                 | CommandReadBackLatch::CommandRBLatchStatus as u8
1373                 | CommandReadBackCounters::CommandRBCounter0 as u8,
1374         );
1375 
1376         read_counter(
1377             &mut data.pit,
1378             0,
1379             CommandAccess::CommandRWBoth as u16 | CommandMode::CommandSWStrobe as u16,
1380             CommandAccess::CommandRWLeast,
1381         );
1382     }
1383 
1384     #[test]
speaker_square_wave()1385     fn speaker_square_wave() {
1386         let mut data = set_up();
1387         write_command(
1388             &mut data.pit,
1389             CommandCounter::CommandCounter2 as u8
1390                 | CommandAccess::CommandRWBoth as u8
1391                 | CommandMode::CommandSquareWaveGen as u8,
1392         );
1393         write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1394 
1395         advance_by_ticks(&mut data, 128);
1396         read_counter(
1397             &mut data.pit,
1398             2,
1399             0xffff - 128 * 2,
1400             CommandAccess::CommandRWBoth,
1401         );
1402     }
1403 
1404     #[test]
speaker_rate_gen()1405     fn speaker_rate_gen() {
1406         let mut data = set_up();
1407         write_command(
1408             &mut data.pit,
1409             CommandCounter::CommandCounter2 as u8
1410                 | CommandAccess::CommandRWBoth as u8
1411                 | CommandMode::CommandRateGen as u8,
1412         );
1413         write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1414 
1415         // In Rate Gen mode, the counter should start over when the gate is
1416         // set to high using SpeakerWrite.
1417         advance_by_ticks(&mut data, 128);
1418         read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1419 
1420         write_speaker(&mut data.pit, 0x1);
1421         advance_by_ticks(&mut data, 128);
1422         read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1423     }
1424 
1425     #[test]
speaker_interrupt()1426     fn speaker_interrupt() {
1427         let mut data = set_up();
1428 
1429         write_command(
1430             &mut data.pit,
1431             CommandCounter::CommandCounter2 as u8
1432                 | CommandAccess::CommandRWBoth as u8
1433                 | CommandMode::CommandInterrupt as u8,
1434         );
1435         write_counter(&mut data.pit, 2, 0xffff, CommandAccess::CommandRWBoth);
1436 
1437         // In Interrupt mode, the counter should NOT start over when the gate is
1438         // set to high using SpeakerWrite.
1439         advance_by_ticks(&mut data, 128);
1440         read_counter(&mut data.pit, 2, 0xffff - 128, CommandAccess::CommandRWBoth);
1441 
1442         write_speaker(&mut data.pit, 0x1);
1443         advance_by_ticks(&mut data, 128);
1444         read_counter(&mut data.pit, 2, 0xffff - 256, CommandAccess::CommandRWBoth);
1445     }
1446 
1447     /// Verify that invalid reads and writes do not cause crashes.
1448     #[test]
invalid_write_and_read()1449     fn invalid_write_and_read() {
1450         let mut data = set_up();
1451         data.pit.write(
1452             BusAccessInfo {
1453                 address: 0x44,
1454                 offset: 0x4,
1455                 id: 0,
1456             },
1457             &[0],
1458         );
1459         data.pit.read(
1460             BusAccessInfo {
1461                 address: 0x55,
1462                 offset: 0x15,
1463                 id: 0,
1464             },
1465             &mut [0],
1466         );
1467     }
1468 }
1469