1#![warn(missing_docs)]
7
8mod ps2keyboard;
9mod ps2mouse;
10pub mod resolver;
11mod spec;
12
13use self::ps2keyboard::Ps2Keyboard;
14use self::ps2mouse::Ps2Mouse;
15use chipset_device::ChipsetDevice;
16use chipset_device::io::IoError;
17use chipset_device::io::IoResult;
18use chipset_device::pio::PortIoIntercept;
19use chipset_device::poll_device::PollDevice;
20use input_core::InputSource;
21use input_core::KeyboardData;
22use inspect::Inspect;
23use inspect::InspectMut;
24use open_enum::open_enum;
25use spec::CommandFlag;
26use spec::ControllerCommand;
27use spec::KeyboardStatus;
28use spec::OutputPort;
29use std::task::Context;
30use std::task::Waker;
31use vmcore::device_state::ChangeDeviceState;
32use vmcore::line_interrupt::LineInterrupt;
33
34#[derive(InspectMut)]
36pub struct I8042Device {
37 #[inspect(skip)]
39 trigger_reset: Box<dyn Fn() + Send + Sync>,
40 keyboard_interrupt: LineInterrupt,
41 mouse_interrupt: LineInterrupt,
42
43 keyboard: Ps2Keyboard,
45 mouse: Ps2Mouse,
46
47 #[inspect(skip)]
49 waker: Option<Waker>,
50
51 state: I8042State,
53}
54
55#[derive(Inspect, Clone)]
56struct I8042State {
57 command_flag: CommandFlag,
58 #[inspect(flatten)]
59 data_port_target: DataPortTarget,
60 output_buffer: u8,
61 output_buffer_state: OutputBufferState,
62 a20_gate: bool,
63 memory: [u8; 32],
64}
65
66#[derive(Inspect, Copy, Clone, PartialEq, Eq)]
67enum OutputBufferState {
68 Empty,
69 Controller,
70 Keyboard,
71 Mouse,
72}
73
74#[derive(Copy, Clone, Inspect)]
75#[inspect(tag = "data_port_target")]
76enum DataPortTarget {
77 Keyboard,
78 Mouse,
79 Controller(#[inspect(rename = "target_command")] ControllerCommand),
80}
81
82impl I8042State {
83 fn new() -> Self {
84 Self {
85 command_flag: CommandFlag::new()
86 .with_allow_keyboard_interrupts(true)
87 .with_allow_mouse_interrupts(true)
88 .with_keyboard_self_test(true)
89 .with_enable_scan_code(true),
90 memory: [0; 32],
91 data_port_target: DataPortTarget::Keyboard,
92 output_buffer: 0,
93 output_buffer_state: OutputBufferState::Empty,
94 a20_gate: true,
95 }
96 }
97}
98
99open_enum! {
100 enum ControllerPort: u16 {
101 DATA = 0x60,
102 COMMAND = 0x64,
103 }
104}
105
106impl I8042Device {
107 pub async fn new(
111 reset: Box<dyn Fn() + Send + Sync>,
112 keyboard_interrupt: LineInterrupt,
113 mouse_interrupt: LineInterrupt,
114 mut keyboard_input: Box<dyn InputSource<KeyboardData>>,
115 ) -> Self {
116 keyboard_input.set_active(true).await;
118 I8042Device {
119 trigger_reset: reset,
120 keyboard_interrupt,
121 mouse_interrupt,
122 state: I8042State::new(),
123 keyboard: Ps2Keyboard::new(keyboard_input),
124 mouse: Ps2Mouse::new(),
125 waker: None,
126 }
127 }
128}
129
130impl ChangeDeviceState for I8042Device {
131 fn start(&mut self) {}
132
133 async fn stop(&mut self) {}
134
135 async fn reset(&mut self) {
136 let Self {
137 trigger_reset: _,
138 keyboard_interrupt: _,
139 mouse_interrupt: _,
140 keyboard,
141 mouse,
142 waker: _,
143 state,
144 } = self;
145
146 *state = I8042State::new();
147 keyboard.reset();
148 mouse.reset();
149
150 self.sync_interrupts();
151 }
152}
153
154impl ChipsetDevice for I8042Device {
155 fn supports_pio(&mut self) -> Option<&mut dyn PortIoIntercept> {
156 Some(self)
157 }
158
159 fn supports_poll_device(&mut self) -> Option<&mut dyn PollDevice> {
160 Some(self)
161 }
162}
163
164impl PollDevice for I8042Device {
165 fn poll_device(&mut self, cx: &mut Context<'_>) {
166 self.keyboard.poll(cx);
167 self.load_device_output();
168 self.waker = Some(cx.waker().clone());
169 }
170}
171
172impl PortIoIntercept for I8042Device {
173 fn io_read(&mut self, io_port: u16, data: &mut [u8]) -> IoResult {
174 if data.len() != 1 {
175 return IoResult::Err(IoError::InvalidAccessSize);
176 }
177 data[0] = match ControllerPort(io_port) {
178 ControllerPort::DATA => {
179 self.read_output_byte()
181 }
182 ControllerPort::COMMAND => {
183 let data = KeyboardStatus::new()
185 .with_output_buffer_full(
186 self.state.output_buffer_state != OutputBufferState::Empty,
187 )
188 .with_input_buffer_full(false)
189 .with_keyboard_self_test(true)
190 .with_input_buffer_for_controller(matches!(
191 self.state.data_port_target,
192 DataPortTarget::Controller(_)
193 ))
194 .with_keyboard_unlocked(true)
195 .with_output_buffer_for_mouse(
196 self.state.output_buffer_state == OutputBufferState::Mouse,
197 );
198
199 data.into()
200 }
201 _ => return IoResult::Err(IoError::InvalidRegister),
202 };
203 self.check_devices_for_output();
205 IoResult::Ok
206 }
207
208 fn io_write(&mut self, io_port: u16, data: &[u8]) -> IoResult {
209 let &[data] = data else {
210 return IoResult::Err(IoError::InvalidAccessSize);
211 };
212 match ControllerPort(io_port) {
213 ControllerPort::DATA => {
214 match std::mem::replace(&mut self.state.data_port_target, DataPortTarget::Keyboard)
215 {
216 DataPortTarget::Keyboard => {
217 self.state.command_flag.set_disable_keyboard(false);
218 self.keyboard.input(data);
219 }
220 DataPortTarget::Mouse => {
221 self.state.command_flag.set_disable_mouse(false);
222 self.mouse.input(data);
223 }
224 DataPortTarget::Controller(command) => {
225 self.handle_command(command, Some(data));
226 }
227 }
228
229 self.check_devices_for_output();
232 }
233 ControllerPort::COMMAND => {
234 self.state.data_port_target = DataPortTarget::Keyboard;
236 let command = ControllerCommand(data);
237 if self.handle_command(command, None).is_none() {
238 self.state.data_port_target = DataPortTarget::Controller(command);
239 }
240
241 self.check_devices_for_output();
244 }
245 _ => return IoResult::Err(IoError::InvalidRegister),
246 }
247 IoResult::Ok
248 }
249
250 fn get_static_regions(&mut self) -> &[(&str, std::ops::RangeInclusive<u16>)] {
251 &[
252 ("data", ControllerPort::DATA.0..=ControllerPort::DATA.0),
253 (
254 "command",
255 ControllerPort::COMMAND.0..=ControllerPort::COMMAND.0,
256 ),
257 ]
258 }
259}
260
261impl I8042Device {
262 fn sync_interrupts(&mut self) {
263 self.keyboard_interrupt.set_level(
264 self.state.command_flag.allow_keyboard_interrupts()
265 && self.state.output_buffer_state == OutputBufferState::Keyboard,
266 );
267 self.mouse_interrupt.set_level(
268 self.state.command_flag.allow_mouse_interrupts()
269 && self.state.output_buffer_state == OutputBufferState::Mouse,
270 );
271 }
272
273 fn write_output_byte(&mut self, state: OutputBufferState, data: u8) {
274 self.state.output_buffer = data;
275 self.state.output_buffer_state = state;
276 self.sync_interrupts();
277 }
278
279 fn read_output_byte(&mut self) -> u8 {
280 self.state.output_buffer_state = OutputBufferState::Empty;
281 self.sync_interrupts();
282 self.state.output_buffer
283 }
284
285 fn handle_command(
287 &mut self,
288 command: ControllerCommand,
289 command_data: Option<u8>,
290 ) -> Option<()> {
291 tracing::debug!(?command, command_data, "8042 command");
292 match command {
293 ControllerCommand::READ_COMMAND_BYTE => {
294 self.write_output_byte(
295 OutputBufferState::Controller,
296 self.state.command_flag.into(),
297 );
298 }
299 ControllerCommand::WRITE_COMMAND_BYTE => {
300 self.state.command_flag = command_data?.into();
301 }
302 ControllerCommand::DISABLE_AUX_INTERFACE => {
303 self.state.command_flag.set_disable_mouse(true);
304 }
305 ControllerCommand::ENABLE_AUX_INTERFACE => {
306 self.state.command_flag.set_disable_mouse(false);
307 }
308 ControllerCommand::CHECK_AUX_INTERFACE => {
309 self.write_output_byte(OutputBufferState::Controller, 0);
310 }
311 ControllerCommand::SELF_TEST => {
312 self.write_output_byte(OutputBufferState::Controller, 0x55);
313 }
314 ControllerCommand::CHECK_INTERFACE => {
315 self.write_output_byte(OutputBufferState::Controller, 0);
316 }
317 ControllerCommand::DISABLE_KEYBOARD => {
318 self.state.command_flag.set_disable_keyboard(true);
319 }
320 ControllerCommand::ENABLE_KEYBOARD => {
321 self.state.command_flag.set_disable_keyboard(false);
322 }
323 ControllerCommand::READ_INPUT_PORT => {
324 self.write_output_byte(OutputBufferState::Controller, 0x80);
326 }
327 ControllerCommand::READ_OUT_INPUT_PORT_LO
328 | ControllerCommand::READ_OUT_INPUT_PORT_HI => {
329 }
335 ControllerCommand::READ_OUTPUT_PORT => {
336 let output_port = OutputPort::new()
337 .with_reset(true)
338 .with_a20_gate(self.state.a20_gate)
339 .with_aux_clock(true)
340 .with_aux_data(false)
341 .with_keyboard_output_buffered(
342 self.state.output_buffer_state == OutputBufferState::Keyboard,
343 )
344 .with_mouse_output_buffered(
345 self.state.output_buffer_state == OutputBufferState::Mouse,
346 )
347 .with_clock(true)
348 .with_data(false);
349
350 self.write_output_byte(OutputBufferState::Controller, output_port.into());
351 }
352 ControllerCommand::WRITE_OUTPUT_PORT => {
353 let output_port = OutputPort::from(command_data?);
354 if output_port.a20_gate() != self.state.a20_gate {
355 tracelimit::warn_ratelimited!(
356 a20_gate = output_port.a20_gate(),
357 "a20 gate changed, not supported"
358 );
359 self.state.a20_gate = output_port.a20_gate();
360 }
361 if !output_port.reset() {
362 tracing::info!("initiated reset via WRITE_OUTPUT_PORT command");
363 (self.trigger_reset)();
364 }
365 }
366 ControllerCommand::WRITE_OUTPUT_BUFFER => {
367 self.write_output_byte(OutputBufferState::Keyboard, command_data?);
371 }
372 ControllerCommand::WRITE_AUX_OUTPUT_BUFFER => {
373 self.write_output_byte(OutputBufferState::Mouse, command_data?);
376 }
377 ControllerCommand::WRITE_AUX_DEVICE => {
378 self.state.data_port_target = DataPortTarget::Mouse;
380 }
381 cmd if (ControllerCommand::PULSE_OUTPUT_F0..=ControllerCommand::PULSE_OUTPUT_FF)
382 .contains(&cmd) =>
383 {
384 if (cmd.0 & 1) == 0 {
385 tracing::info!("initiated reset via PULSE_OUTPUT_FX command");
388 (self.trigger_reset)();
389 } else {
390 }
396 }
397 cmd if (0x20..=0x3f).contains(&cmd.0) => {
398 self.write_output_byte(
405 OutputBufferState::Keyboard,
406 self.state.memory[cmd.0 as usize & 0x1f],
407 );
408 }
409 command if (0x60..=0x7f).contains(&command.0) => {
410 self.state.memory[command.0 as usize & 0x1f] = command_data?;
411 }
412
413 ControllerCommand::UNKNOWN_A1 => {
414 self.write_output_byte(OutputBufferState::Controller, 0);
415 }
416 ControllerCommand::PWD_CHECK => {
417 self.write_output_byte(OutputBufferState::Controller, 0xf1);
418 }
419 cmd => {
420 tracelimit::warn_ratelimited!(?cmd, "unsupported keyboard command");
421 }
422 }
423 Some(())
424 }
425
426 fn load_device_output(&mut self) -> bool {
428 if self.state.output_buffer_state != OutputBufferState::Empty {
429 return true;
430 }
431
432 if !self.state.command_flag.disable_mouse() {
433 if let Some(byte) = self.mouse.output() {
434 self.write_output_byte(OutputBufferState::Mouse, byte);
435 return true;
436 }
437 }
438
439 if let Some(byte) = self.keyboard.output() {
440 self.write_output_byte(OutputBufferState::Keyboard, byte);
441 return true;
442 }
443
444 false
445 }
446
447 fn check_devices_for_output(&mut self) {
450 if !self.load_device_output() {
451 if let Some(waker) = self.waker.take() {
453 waker.wake();
454 }
455 }
456 }
457}
458
459mod save_restore {
460 use super::*;
461 use vmcore::save_restore::RestoreError;
462 use vmcore::save_restore::SaveError;
463 use vmcore::save_restore::SaveRestore;
464
465 mod state {
466 use mesh::payload::Protobuf;
467 use vmcore::save_restore::SaveRestore;
468 use vmcore::save_restore::SavedStateRoot;
469
470 #[derive(Protobuf, SavedStateRoot)]
472 #[mesh(package = "chipset.i8042")]
473 pub struct SavedState {
474 #[mesh(1)]
475 pub controller: SavedControllerState,
476 #[mesh(2)]
477 pub keyboard: <super::ps2keyboard::Ps2Keyboard as SaveRestore>::SavedState,
478 #[mesh(3)]
479 pub mouse: <super::ps2mouse::Ps2Mouse as SaveRestore>::SavedState,
480 }
481
482 #[derive(Protobuf)]
483 #[mesh(package = "chipset.i8042")]
484 pub struct SavedControllerState {
485 #[mesh(1)]
486 pub command_flag: u8,
487 #[mesh(2)]
488 pub data_port_target: SavedDataPortTarget,
489 #[mesh(3)]
490 pub output_buffer: u8,
491 #[mesh(4)]
492 pub output_buffer_state: SavedOutputBufferState,
493 #[mesh(5)]
494 pub a20_gate: bool,
495 #[mesh(6)]
496 pub memory: [u8; 32],
497 }
498
499 #[derive(Protobuf)]
500 #[mesh(package = "chipset.i8042")]
501 pub enum SavedOutputBufferState {
502 #[mesh(1)]
503 Empty,
504 #[mesh(2)]
505 Controller,
506 #[mesh(3)]
507 Keyboard,
508 #[mesh(4)]
509 Mouse,
510 }
511
512 #[derive(Protobuf)]
513 #[mesh(package = "chipset.i8042")]
514 pub enum SavedDataPortTarget {
515 #[mesh(1)]
516 Keyboard,
517 #[mesh(2)]
518 Mouse,
519 #[mesh(3)]
520 Controller(u8),
521 }
522 }
523
524 impl SaveRestore for I8042Device {
525 type SavedState = state::SavedState;
526
527 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
528 let I8042State {
529 command_flag,
530 data_port_target,
531 output_buffer,
532 output_buffer_state,
533 a20_gate,
534 memory,
535 } = self.state;
536
537 let saved_state = state::SavedState {
538 controller: state::SavedControllerState {
539 command_flag: command_flag.into(),
540 data_port_target: match data_port_target {
541 DataPortTarget::Keyboard => state::SavedDataPortTarget::Keyboard,
542 DataPortTarget::Mouse => state::SavedDataPortTarget::Mouse,
543 DataPortTarget::Controller(ControllerCommand(b)) => {
544 state::SavedDataPortTarget::Controller(b)
545 }
546 },
547 output_buffer,
548 output_buffer_state: match output_buffer_state {
549 OutputBufferState::Empty => state::SavedOutputBufferState::Empty,
550 OutputBufferState::Controller => state::SavedOutputBufferState::Controller,
551 OutputBufferState::Keyboard => state::SavedOutputBufferState::Keyboard,
552 OutputBufferState::Mouse => state::SavedOutputBufferState::Mouse,
553 },
554 a20_gate,
555 memory,
556 },
557 keyboard: self.keyboard.save()?,
558 mouse: self.mouse.save()?,
559 };
560
561 Ok(saved_state)
562 }
563
564 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
565 let state::SavedState {
566 controller,
567 keyboard,
568 mouse,
569 } = state;
570
571 {
572 let state::SavedControllerState {
573 command_flag,
574 data_port_target,
575 output_buffer,
576 output_buffer_state,
577 a20_gate,
578 memory,
579 } = controller;
580
581 self.state = I8042State {
582 command_flag: CommandFlag::from(command_flag), data_port_target: match data_port_target {
584 state::SavedDataPortTarget::Keyboard => DataPortTarget::Keyboard,
585 state::SavedDataPortTarget::Mouse => DataPortTarget::Mouse,
586 state::SavedDataPortTarget::Controller(b) => {
587 DataPortTarget::Controller(ControllerCommand(b))
588 }
589 },
590 output_buffer,
591 output_buffer_state: match output_buffer_state {
592 state::SavedOutputBufferState::Empty => OutputBufferState::Empty,
593 state::SavedOutputBufferState::Controller => OutputBufferState::Controller,
594 state::SavedOutputBufferState::Keyboard => OutputBufferState::Keyboard,
595 state::SavedOutputBufferState::Mouse => OutputBufferState::Mouse,
596 },
597 a20_gate,
598 memory,
599 };
600 }
601
602 self.keyboard.restore(keyboard)?;
603 self.mouse.restore(mouse)?;
604
605 self.sync_interrupts();
606
607 Ok(())
608 }
609 }
610}