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