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