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