# KVM Host Development Record
## Note of [kvm-host](https://hackmd.io/@sysprog/linux-kvm)
The note is available in [HackMD](https://hackmd.io/@otischung/kvm-host-init).
## Resolved Issues
### Misconfiguration of Setting Base Address Register (BAR)
This is the original method in [kvm-host (`src/pci.c`, commit: 93f1fee)](https://github.com/sysprog21/kvm-host/blob/93f1fee173645a01258084f9c65800f324f5805a/src/pci.c#L145-L157):
```cpp
void pci_set_bar(struct pci_dev *dev,
uint8_t bar,
uint32_t bar_size,
bool is_io_space,
dev_io_fn do_io)
{
/* TODO: mem type, prefetch */
/* FIXME: bar_size must be power of 2 */
PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), is_io_space, 32);
dev->bar_size[bar] = bar_size;
dev->bar_is_io_space[bar] = is_io_space;
dev_init(&dev->space_dev[bar], 0, bar_size, dev, do_io);
}
```
**Usage**:
In [`src/virtio-pci.c`](https://github.com/sysprog21/kvm-host/blob/93f1fee173645a01258084f9c65800f324f5805a/src/virtio-pci.c#L271):
```cpp
void virtio_pci_init(struct virtio_pci_dev *dev,
struct pci *pci,
struct bus *io_bus,
struct bus *mmio_bus)
{
// ...
pci_set_bar(&dev->pci_dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY,
virtio_pci_space_io);
// ...
}
```
**Definitions**:
In `/usr/include/linux/pci_regs.h`:
```c
/*
* Base addresses specify locations in memory or I/O space.
* Decoded size can be determined by writing a value of
* 0xffffffff to the register, and reading it back. Only
* 1 bits are decoded.
*/
#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */
#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */
#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */
#define PCI_BASE_ADDRESS_SPACE_IO 0x01
#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00
#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06
#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */
#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */
#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */
#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */
#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL)
#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL)
/* bit 1 is reserved if address_space = 1 */
```
In [`src/pci.h`](https://github.com/sysprog21/kvm-host/blob/93f1fee173645a01258084f9c65800f324f5805a/src/pci.h#L26):
```c
#define PCI_BAR_OFFSET(bar) (PCI_BASE_ADDRESS_0 + ((bar) << 2))
```
---
Therefore, the `pci_set_bar()` in `virtio_pci_init()` does the followings:
```cpp
PCI_HDR_WRITE(dev->pci_dev->dev->hdr, PCI_BAR_OFFSET(0), PCI_BASE_ADDRESS_SPACE_MEMORY, 32);
dev->pci_dev->dev->bar_size[bar] = 0x100; // 256
dev->pci_dev->dev->bar_is_io_space[bar] = PCI_BASE_ADDRESS_SPACE_MEMORY;
dev_init(dev->pci_dev->dev->space_dev[0], 0, 0x100, dev->pci_dev->dev, virtio_pci_space_io);
```
---
According to the [BAR settings](https://hackmd.io/@otischung/kvm-init#Base-Address-Register-(BAR)), we have to configure:
1. if this is memory space layout or I/O space layout.
2. Avoid to implicitly cast the `PCI_BASE_ADDRESS_SPACE_MEMORY = 0x00` to `bool bar_is_io_space[6];`
---
The fix applied in commit [c4b325e](https://github.com/otischung/kvm-host/blob/c4b325e659e7cceebaed6b39b2eb3d6796b2f5e0/src/pci.h#L49-L82) replaces individual BAR flags with one `layout` parameter.
Users are required to indicate the correct flags via `layout`, as demonstrated below:
```diff
diff --git a/src/virtio-pci.c b/src/virtio-pci.c
index 289abb8..f712e8c 100644
--- a/src/virtio-pci.c
+++ b/src/virtio-pci.c
@@ -268,7 +268,9 @@ void virtio_pci_init(struct virtio_pci_dev *dev,
pci_set_status(&dev->pci_dev, PCI_STATUS_CAP_LIST | PCI_STATUS_INTERRUPT);
- pci_set_bar(&dev->pci_dev, 0, 0x100, PCI_BASE_ADDRESS_SPACE_MEMORY,
+ pci_set_bar(&dev->pci_dev, 0, 0x100,
+ PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_32
+ /* | PCI_BASE_ADDRESS_MEM_PREFETCH */,
virtio_pci_set_cap(dev, cap_list);
```
The `pci_set_bar()` function writes the layout directly into the BAR and extracts the boolean `bar_is_io_space` from bit 0 of the layout.
```diff
diff --git a/src/pci.c b/src/pci.c
index 2b59ded..aa4dccf 100644
--- a/src/pci.c
+++ b/src/pci.c
@@ -145,14 +145,13 @@ static void pci_mmio_io(void *owner,
void pci_set_bar(struct pci_dev *dev,
uint8_t bar,
uint32_t bar_size,
- bool is_io_space,
+ uint32_t layout,
dev_io_fn do_io)
{
- /* TODO: mem type, prefetch */
/* FIXME: bar_size must be power of 2 */
- PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), is_io_space, 32);
+ PCI_HDR_WRITE(dev->hdr, PCI_BAR_OFFSET(bar), layout, 32);
dev->bar_size[bar] = bar_size;
- dev->bar_is_io_space[bar] = is_io_space;
+ dev->bar_is_io_space[bar] = layout & 0x1U; // Get the bit[0] of layout
dev_init(&dev->space_dev[bar], 0, bar_size, dev, do_io);
}
```
## TODO List
### Network IRQ Descriptor in arm64
`VIRTIO_NET_IRQ` is defined in [`src/arch/x86/desc.h`](https://github.com/sysprog21/kvm-host/blob/93f1fee173645a01258084f9c65800f324f5805a/src/arch/x86/desc.h#L5-L6):
```c
#define VIRTIO_NET_IRQ 14
#define VIRTIO_BLK_IRQ 15
```
but not in arm64.
Below is the compliation error log in arm64 platform.
```
CC build/virtio-net.o
src/virtio-net.c: In function ‘virtio_net_setup’:
src/virtio-net.c:242:20: error: ‘VIRTIO_NET_IRQ’ undeclared (first use in this function); did you mean ‘VIRTIO_NET_ERR’?
242 | dev->irq_num = VIRTIO_NET_IRQ;
| ^~~~~~~~~~~~~~
| VIRTIO_NET_ERR
src/virtio-net.c:242:20: note: each undeclared identifier is reported only once for each function it appears in
make: *** [Makefile:60: build/virtio-net.o] Error 1
```
### TODO: 閱讀清單與目前進度
- [GICv3 and GICv4 Software Overview](https://developer.arm.com/documentation/dai0492/latest/)
- 進度:Chapter 1 - Chapter 4: Configuring the GIC
- [VirtIO 1.1](https://docs.oasis-open.org/virtio/virtio/v1.1/csprd01/virtio-v1.1-csprd01.html)
- 進度:Chapter 1 - Chapter 2.4
- 進度:Chapter 4.1: Virtio Over PCI Bus
- [OS Dev: PCI](https://wiki.osdev.org/PCI)
- 進度:Chapter 1 - Chapter 2
### Others
[Linux 核心專題: KVM 在 Arm64 的驗證和調整](https://hackmd.io/@sysprog/BkHQfVYWgg)