From b4385901daf51e0898789022cbf313402f4f07ee Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Tue, 21 Aug 2018 08:22:57 +0000 Subject: [PATCH] qemu/arm64: Detect host GIC version to configure guest GIC QEMU supports GICv2, GICv3 and host parameters for guest gic-version. The "host" parameter will let QEMU detect GIC version by itself. This parameter will work properly when host GIC version is GICv2 or GICv3. But the detection will failed when host GIC is GICv4 or higher: "Unable to determine GIC version supported by host" In this case, we have to detect the host GIC version manually and force QEMU to use GICv3 when host GIC is GICv4 or higher. Fixes: #614 Signed-off-by: Wei Chen Signed-off-by: Penny Zheng --- virtcontainers/qemu_arm64.go | 64 +++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/virtcontainers/qemu_arm64.go b/virtcontainers/qemu_arm64.go index 8c6090fea7..112631b09b 100644 --- a/virtcontainers/qemu_arm64.go +++ b/virtcontainers/qemu_arm64.go @@ -6,9 +6,12 @@ package virtcontainers import ( + "io/ioutil" "runtime" + "strings" govmmQemu "github.com/intel/govmm/qemu" + "github.com/sirupsen/logrus" ) type qemuArm64 struct { @@ -20,7 +23,7 @@ const defaultQemuPath = "/usr/bin/qemu-system-aarch64" const defaultQemuMachineType = QemuVirt -const defaultQemuMachineOptions = "gic-version=host,usb=off,accel=kvm" +var defaultQemuMachineOptions = "usb=off,accel=kvm,gic-version=" + getGuestGICVersion() // Not used const defaultPCBridgeBus = "" @@ -45,6 +48,65 @@ var supportedQemuMachines = []govmmQemu.Machine{ }, } +// Logger returns a logrus logger appropriate for logging qemu-aarch64 messages +func qemuArmLogger() *logrus.Entry { + return virtLog.WithField("subsystem", "qemu-aarch64") +} + +// On ARM platform, we have different GIC interrupt controllers. Different +// GIC supports different QEMU parameters for virtual GIC and max VCPUs +var hostGICVersion = getHostGICVersion() + +// We will access this file on host to detect host GIC version +var gicProfile = "/proc/interrupts" + +// Detect the host GIC version. +// Success: return the number of GIC version +// Failed: return 0 +func getHostGICVersion() (version uint32) { + bytes, err := ioutil.ReadFile(gicProfile) + if err != nil { + qemuArmLogger().WithField("GIC profile", gicProfile).WithError(err).Error("Failed to parse GIC profile") + return 0 + } + + s := string(bytes) + if strings.Contains(s, "GICv2") { + return 2 + } + + if strings.Contains(s, "GICv3") { + return 3 + } + + if strings.Contains(s, "GICv4") { + return 4 + } + + return 0 +} + +// QEMU supports GICv2, GICv3 and host parameters for gic-version. The host +// parameter will let QEMU detect GIC version by itself. This parameter +// will work properly when host GIC version is GICv2 or GICv3. But the +// detection will failed when host GIC is gicv4 or higher. In this case, +// we have to detect the host GIC version manually and force QEMU to use +// GICv3 when host GIC is GICv4 or higher. +func getGuestGICVersion() (version string) { + if hostGICVersion == 2 { + return "2" + } + + if hostGICVersion >= 3 { + return "3" + } + + // We can't parse valid host GIC version from GIC profile. + // But we can use "host" to ask QEMU to detect valid GIC + // through KVM API for a try. + return "host" +} + // MaxQemuVCPUs returns the maximum number of vCPUs supported func MaxQemuVCPUs() uint32 { return uint32(runtime.NumCPU())