From 48fef40fd9af9eaace01bcf5309f1fb7c652675a Mon Sep 17 00:00:00 2001 From: Penny Zheng Date: Tue, 22 Jan 2019 11:03:02 +0800 Subject: [PATCH] kata-check: add kvm extension check on aarch64 Auger Eric's latest patches about "ARM virt: Initial RAM expansion and extended memory map"(https://patchwork.kernel.org/cover/10835377/) paves the way to device memory, which is the foundation for NVDIMM and memory hotplug. This new feature on qemu kinds of depends on host kernel's new feature on dynamic IPA range(https://lwn.net/Articles/750176/). The availability of this feature is advertised by a new kvm cap KVM_CAP_ARM_VM_IPA_SIZE. When supported, this capability returns the maximum IPA shift supported by the host. The supported IPA size on a host could be different from the system's PARange indicated by the CPUs (e.g, kernel limit on the PA size). Fixes: #1796 Signed-off-by: Penny Zheng --- cli/kata-check.go | 49 +++++++++++++++++++++++++++++++++++++++++ cli/kata-check_arm64.go | 33 ++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/cli/kata-check.go b/cli/kata-check.go index 75f427f36f..28c23b6dd7 100644 --- a/cli/kata-check.go +++ b/cli/kata-check.go @@ -11,6 +11,7 @@ package main #include const int ioctl_KVM_CREATE_VM = KVM_CREATE_VM; +const int ioctl_KVM_CHECK_EXTENSION = KVM_CHECK_EXTENSION; */ import "C" @@ -40,6 +41,15 @@ type kernelModule struct { required bool } +// nolint: structcheck, unused, deadcode +type kvmExtension struct { + // description + desc string + + // extension identifier + id int +} + type vmContainerCapableDetails struct { cpuInfoFile string requiredCPUFlags map[string]string @@ -388,3 +398,42 @@ func genericKvmIsUsable() error { return nil } + +// genericCheckKVMExtension allows to query about the specific kvm extensions +// nolint: unused, deadcode +func genericCheckKVMExtensions(extensions map[string]kvmExtension) (map[string]int, error) { + results := make(map[string]int) + + flags := syscall.O_RDWR | syscall.O_CLOEXEC + kvm, err := syscall.Open(kvmDevice, flags, 0) + if err != nil { + return results, err + } + defer syscall.Close(kvm) + + for name, extension := range extensions { + fields := logrus.Fields{ + "type": "kvm extension", + "name": name, + "description": extension.desc, + "id": extension.id, + } + + ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, + uintptr(kvm), + uintptr(C.ioctl_KVM_CHECK_EXTENSION), + uintptr(extension.id)) + + // Generally return value(ret) 0 means no and 1 means yes, + // but some extensions may report additional information in the integer return value. + if errno != 0 || ret <= 0 { + kataLog.WithFields(fields).Error("is not supported") + return results, errno + } + + results[name] = int(ret) + kataLog.WithFields(fields).Info("kvm extension is supported") + } + + return results, nil +} diff --git a/cli/kata-check_arm64.go b/cli/kata-check_arm64.go index 0128287c9e..5f835fcaba 100644 --- a/cli/kata-check_arm64.go +++ b/cli/kata-check_arm64.go @@ -47,6 +47,15 @@ var archRequiredKernelModules = map[string]kernelModule{ }, } +// archRequiredKVMExtensions maps a required kvm extension to a human-readable +// description of what this extension intends to do and its unique identifier. +var archRequiredKVMExtensions = map[string]kvmExtension{ + "KVM_CAP_ARM_VM_IPA_SIZE": { + desc: "Maximum IPA shift supported by the host", + id: 165, + }, +} + func setCPUtype() error { return nil } @@ -57,8 +66,30 @@ func kvmIsUsable() error { return genericKvmIsUsable() } +func checkKVMExtensions() error { + results, err := genericCheckKVMExtensions(archRequiredKVMExtensions) + if err != nil { + return err + } + + // different host supports different maximum IPA limit + ipa := results["KVM_CAP_ARM_VM_IPA_SIZE"] + fields := logrus.Fields{ + "type": "kvm extension", + "name": "KVM_CAP_ARM_VM_IPA_SIZE", + } + + kataLog.WithFields(fields).Infof("IPA limit size: %d bits.", ipa) + + return nil +} + func archHostCanCreateVMContainer() error { - return kvmIsUsable() + if err := kvmIsUsable(); err != nil { + return err + } + + return checkKVMExtensions() } // hostIsVMContainerCapable checks to see if the host is theoretically capable