Volt VMM (Neutron Stardust): source-available under AGPSL v5.0
KVM-based microVMM for the Volt platform: - Sub-second VM boot times - Minimal memory footprint - Landlock LSM + seccomp security - Virtio device support - Custom kernel management Copyright (c) Armored Gates LLC. All rights reserved. Licensed under AGPSL v5.0
This commit is contained in:
116
docs/i8042-implementation.md
Normal file
116
docs/i8042-implementation.md
Normal file
@@ -0,0 +1,116 @@
|
||||
# i8042 PS/2 Controller Implementation
|
||||
|
||||
## Summary
|
||||
|
||||
Completed the i8042 PS/2 keyboard controller emulation to handle the full Linux
|
||||
kernel probe sequence. Previously, the controller only handled self-test (0xAA)
|
||||
and interface test (0xAB), but was missing the command byte (CTR) read/write
|
||||
support, causing the kernel to fail with "Can't read CTR while initializing
|
||||
i8042" and adding ~500ms+ of timeout penalty during boot.
|
||||
|
||||
## Problem
|
||||
|
||||
The Linux kernel's i8042 driver probe sequence requires:
|
||||
|
||||
1. **Self-test** (0xAA → 0x55) ✅ was working
|
||||
2. **Read CTR** (0x20 → command byte on port 0x60) ❌ was missing
|
||||
3. **Write CTR** (0x60, then data byte to port 0x60) ❌ was missing
|
||||
4. **Interface test** (0xAB → 0x00) ✅ was working
|
||||
5. **Enable/disable keyboard** (0xAD/0xAE) ❌ was missing
|
||||
|
||||
Additionally, the code had compilation errors — `I8042State` in `vcpu.rs`
|
||||
referenced `self.cmd_byte` and `self.expecting_data` fields that didn't exist
|
||||
in the struct definition. The data port (0x60) write handler also didn't forward
|
||||
writes to the i8042 state machine.
|
||||
|
||||
## Changes Made
|
||||
|
||||
### `vmm/src/kvm/vcpu.rs` — Active I8042State (used in vCPU run loop)
|
||||
|
||||
Added missing fields to `I8042State`:
|
||||
- `cmd_byte: u8` — Controller Configuration Register, default `0x47`
|
||||
(keyboard IRQ enabled, system flag, keyboard enabled, translation)
|
||||
- `expecting_data: bool` — tracks when next port 0x60 write is a command data byte
|
||||
- `pending_cmd: u8` — which command is waiting for data
|
||||
|
||||
Added `write_data()` method for port 0x60 writes:
|
||||
- Handles 0x60 (write command byte) data phase
|
||||
- Handles 0xD4 (write to aux device) data phase
|
||||
|
||||
Enhanced `write_command()`:
|
||||
- 0x20: Read command byte → queues `cmd_byte` to output buffer
|
||||
- 0x60: Write command byte → sets `expecting_data`, `pending_cmd`
|
||||
- 0xA7/0xA8: Disable/enable aux port (updates CTR bit 5)
|
||||
- 0xA9: Aux interface test → queues 0x00
|
||||
- 0xAA: Self-test → queues 0x55, resets CTR to default
|
||||
- 0xAD/0xAE: Disable/enable keyboard (updates CTR bit 4)
|
||||
- 0xD4: Write to aux → sets `expecting_data`, `pending_cmd`
|
||||
|
||||
Fixed port 0x60 IoOut handler to call `i8042.write_data(data[0])` instead of
|
||||
ignoring all data port writes.
|
||||
|
||||
### `vmm/src/devices/i8042.rs` — Library I8042 (updated for parity)
|
||||
|
||||
Rewrote to match the same logic as the vcpu.rs inline version, with full
|
||||
test coverage including the complete Linux probe sequence test.
|
||||
|
||||
## Boot Timing Results (5 iterations)
|
||||
|
||||
Kernel: vmlinux (4.14.174), Memory: 128M, Command line includes `i8042.noaux`
|
||||
|
||||
| Run | i8042 Init (kernel time) | KBD Port Ready | Reboot Trigger |
|
||||
|-----|--------------------------|----------------|----------------|
|
||||
| 1 | 0.288149s | 0.288716s | 1.118453s |
|
||||
| 2 | 0.287622s | 0.288232s | 1.116971s |
|
||||
| 3 | 0.292594s | 0.293164s | 1.123013s |
|
||||
| 4 | 0.288518s | 0.289095s | 1.118687s |
|
||||
| 5 | 0.288203s | 0.288780s | 1.119400s |
|
||||
|
||||
**Average i8042 init time: 0.289s** (kernel timestamp)
|
||||
**i8042 init duration: <1ms** (from "Keylock active" to "KBD port" message)
|
||||
|
||||
### Before Fix
|
||||
|
||||
The kernel would output:
|
||||
```
|
||||
i8042: Can't read CTR while initializing i8042
|
||||
```
|
||||
and the i8042 probe would either timeout (~500ms-1000ms penalty) or fail entirely,
|
||||
depending on kernel configuration. The `i8042.noaux` kernel parameter mitigates
|
||||
some of the timeout but the CTR read failure still caused delays.
|
||||
|
||||
### After Fix
|
||||
|
||||
The kernel successfully probes the i8042:
|
||||
```
|
||||
[ 0.288149] i8042: Warning: Keylock active
|
||||
[ 0.288716] serio: i8042 KBD port at 0x60,0x64 irq 1
|
||||
```
|
||||
|
||||
The "Warning: Keylock active" message is normal — it's because our default CTR
|
||||
value (0x47) has bit 2 (system flag) set, which the kernel interprets as the
|
||||
keylock being active. This is harmless.
|
||||
|
||||
## Status Register (OBF) Behavior
|
||||
|
||||
The status register (port 0x64 read) correctly reflects the Output Buffer Full
|
||||
(OBF) bit:
|
||||
- **OBF set (bit 0 = 1)**: When the output queue has data pending for the guest
|
||||
to read from port 0x60 (after self-test, read CTR, interface test, etc.)
|
||||
- **OBF clear (bit 0 = 0)**: When the output queue is empty (after the guest
|
||||
reads all pending data from port 0x60)
|
||||
|
||||
This is critical because the Linux kernel polls the status register to know when
|
||||
response data is available. Without correct OBF tracking, the kernel's
|
||||
`i8042_wait_read()` times out.
|
||||
|
||||
## Architecture Note
|
||||
|
||||
There are two i8042 implementations in the codebase:
|
||||
1. **`vmm/src/kvm/vcpu.rs`** — Inline `I8042State` struct used in the actual vCPU
|
||||
run loop. This is the active implementation.
|
||||
2. **`vmm/src/devices/i8042.rs`** — Library `I8042` struct with full test suite.
|
||||
This is exported but currently unused in the hot path.
|
||||
|
||||
Both are kept in sync. A future refactor could consolidate them by having the
|
||||
vCPU run loop use the `devices::I8042` implementation directly.
|
||||
Reference in New Issue
Block a user