bobuhiro11/gokvm - GitHub

2021/2/24 WSL2 Support 4f6b785

When running gokvm on Ubuntu 20.04 on WSL2 (Windows Subsystem for Linux 2), output to IO port 0x64 was repeated infinitely and didn’t reach the Init process startup. It seems the behavior around the PS/2 keyboard was the cause.

In kvmtool, it returns 0x20 for in (0x61) 1, so I followed that approach. IO port 0x61 appears to be used as NMI (Non-Maskable Interrupt) status and control register 2. Looking at the content of this status register, bit 5 means mirrors timer 2 output condition, but I couldn’t interpret it further. There are parts I don’t understand, but as a result, I was able to boot the guest VM on WSL2.

0061 r KB controller port B control register (ISA, EISA)
       system control port for compatibility with 8255
       bit 7  parity check occurred
       bit 6  channel check occurred
       bit 5  mirrors timer 2 output condition
       bit 4  toggles with each refresh request
       bit 3  channel check status
       bit 2  parity check status
       bit 1  speaker data status
       bit 0  timer 2 gate to speaker status

Source: XT, AT and PS/2 I/O port addresses

2021/2/27 Boot Guest with Fedora’s Standard Kernel a86d86b

I want to support not only kernels built within gokvm but also widely used kernels. When I simply tried to boot it, it resulted in a kernel panic as follows. Since I’m passing 1GB memory to KVM API’s KVM_SET_MEMORY_REGION, looking at the output below, it clearly seems that size is too small.

[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] BIOS-88: [mem 0x0000000000000000-0x000000000009efff] usable
[ 0.000000] BIOS-88: [mem 0x0000000000100000-0x00000000002fa7ff] usable
[ 0.020431] Kernel panic - not syncing: initrd too large to handle,
            disabling initrd (33769847 needed, 22421504 available)

It seems that e820 entry specification is incorrect and memory is exhausted. By the way, e820 is a table that manages the memory map, and has entries consisting of memory start position, memory end position, and flags.

struct e820_entry {
	u64 addr;
	u64 size;
	enum e820_type type;
} __attribute__((packed));

struct e820_table {
	__u32 nr_entries;
	struct e820_entry entries[E820_MAX_ENTRIES];
};

Source: linux/arch/x86/include/asm/e820/types.h#L55-L97

2021/2/28 e820 Setup 6712e09

How should I configure e820? Since it’s boot-time behavior, I reviewed the documentation around x86 Boot, and found e820_entries and e820_table in a region called Zero Page 3. The offset written in Zero Page can be interpreted the same way as the Boot Protocol Real-Mode Kernel Header 4 mentioned in the previous article. So, I refactored it to have a structure that can freely manipulate e820 entries. For the actual entries to register, I referred to kvmtool 5. Finally, I was able to boot the guest using Fedora’s standard kernel.

Future Work

I’m exploring whether to tackle disk or NIC device emulation. For NIC, which would be simpler, e1000 (Intel 8254x) or virtio-net? I want to bring it to a working state with a naive implementation. In either case, emulation around PCI device Configuration Space initialization will be necessary.