2024-01-17 21:12:43 +00:00
|
|
|
# `cloud-hypervisor` debug IO ports
|
2019-08-15 06:21:51 +00:00
|
|
|
|
2024-01-17 21:12:43 +00:00
|
|
|
When running x86 guests, `cloud-hypervisor` provides different kinds of debug ports:
|
|
|
|
- [`0x80` debug port](https://www.intel.com/content/www/us/en/support/articles/000005500/boards-and-kits.html)
|
|
|
|
- Debug console (by default at `0xe9`).
|
|
|
|
- Firmware debug port at `0x402`.
|
|
|
|
|
|
|
|
All of them can be used to trace user-defined guest events and all of them can
|
|
|
|
be used simultaneously.
|
|
|
|
|
|
|
|
## Debug Ports Overview
|
|
|
|
|
|
|
|
### `0x80` I/O port
|
2019-08-15 06:21:51 +00:00
|
|
|
|
|
|
|
Whenever the guest write one byte between `0x0` and `0xF` on this particular
|
|
|
|
I/O port, `cloud-hypervisor` will log and timestamp that event at the `debug`
|
|
|
|
log level.
|
|
|
|
|
|
|
|
It is up to the guest stack to decide when and what to write to the 0x80 port
|
|
|
|
in order to signal the host about specific events and have `cloud-hypervisor`
|
|
|
|
log it.
|
|
|
|
|
|
|
|
`cloud-hypervisor` defines several debug port code ranges that should be used
|
|
|
|
for debugging specific components of the guest software stack. When logging a
|
|
|
|
write of one of those codes to the debug port, `cloud-hypervisor` adds a
|
|
|
|
pre-defined string to the logs.
|
|
|
|
|
|
|
|
| Code Range | Component | Log string |
|
|
|
|
| ---------------- | ----------- | ------------ |
|
|
|
|
| `0x00` to `0x1f` | Firmware | `Firmware` |
|
|
|
|
| `0x20` to `0x3f` | Bootloader | `Bootloader` |
|
|
|
|
| `0x40` to `0x5f` | Kernel | `Kernel` |
|
|
|
|
| `0x60` to `0x7f` | Userspace | `Userspace` |
|
|
|
|
| `0x80` to `0xff` | Custom | `Custom` |
|
|
|
|
|
|
|
|
One typical use case is guest boot time measurement and tracing. By writing
|
|
|
|
different values to the debug I/O port at different boot process steps, the
|
|
|
|
guest will have `cloud-hypervisor` generate timestamped logs of all those steps.
|
|
|
|
That provides a basic but convenient way of measuring not only the overall guest
|
|
|
|
boot time but all intermediate steps as well.
|
|
|
|
|
2024-01-17 21:12:43 +00:00
|
|
|
#### Logging
|
2019-08-15 06:21:51 +00:00
|
|
|
|
|
|
|
Assuming parts of the guest software stack have been instrumented to use the
|
|
|
|
`cloud-hypervisor` debug I/O port, we may want to gather the related logs.
|
|
|
|
|
|
|
|
To do so we need to start `cloud-hypervisor` with the right debug level
|
2023-09-11 15:32:41 +00:00
|
|
|
(`-vvv`). It is also recommended to have it log into a dedicated file in order
|
2019-08-15 06:21:51 +00:00
|
|
|
to easily grep for the tracing logs (e.g.
|
|
|
|
`--log-file /tmp/cloud-hypervisor.log`):
|
|
|
|
|
|
|
|
```
|
|
|
|
./target/debug/cloud-hypervisor \
|
|
|
|
--kernel ~/rust-hypervisor-firmware/target/target/release/hypervisor-fw \
|
2020-07-02 16:30:16 +00:00
|
|
|
--disk path=~/hypervisor/images/focal-server-cloudimg-amd64.raw \
|
2019-08-15 06:21:51 +00:00
|
|
|
--cpus 4 \
|
|
|
|
--memory size=1024M \
|
|
|
|
--rng \
|
|
|
|
--log-file /tmp/ch-fw.log \
|
2023-09-11 15:32:41 +00:00
|
|
|
-vvv
|
2019-08-15 06:21:51 +00:00
|
|
|
```
|
|
|
|
|
|
|
|
After booting the guest, we then have to grep for the debug I/O port traces in
|
|
|
|
the log file:
|
|
|
|
|
|
|
|
```Shell
|
|
|
|
$ grep "Debug I/O port" /tmp/ch-fw.log
|
|
|
|
cloud-hypervisor: 19.762449ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x0] 0.019004 seconds
|
|
|
|
cloud-hypervisor: 403.499628ms: DEBUG:vmm/src/vm.rs:510 -- [Debug I/O port: Firmware code 0x1] 0.402744 seconds
|
|
|
|
```
|
2024-01-17 21:12:43 +00:00
|
|
|
|
|
|
|
### Debug console port
|
|
|
|
|
|
|
|
The debug console is inspired by QEMU and Bochs, which have a similar feature.
|
|
|
|
By default, the I/O port `0xe9` is used. This port can be configured like a
|
|
|
|
console. Thus, it can print to a tty, a file, or a pty, for example.
|
|
|
|
|
|
|
|
### Firmware debug port
|
|
|
|
|
|
|
|
The firmware debug port is also a simple port that prints all bytes written to
|
|
|
|
it. The firmware debug port only prints to stdout.
|
|
|
|
|
|
|
|
## When do I need these ports?
|
|
|
|
|
|
|
|
The ports are on the one hand interesting for firmware or kernel developers, as
|
|
|
|
they provide an easy way to print debug information from within a guest.
|
|
|
|
Furthermore, you can patch "normal" software to measure certain events, such as
|
|
|
|
the boot time of a guest.
|
|
|
|
|
|
|
|
## Which port should I choose?
|
|
|
|
|
|
|
|
The `0x80` debug port and the port of the firmware debug device are always
|
|
|
|
available. The debug console must be activated via the command line, but
|
|
|
|
provides more configuration options.
|
|
|
|
|
|
|
|
You can use different ports for different aspect of your logging messages.
|