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