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 <penny.zheng@arm.com>
This commit is contained in:
Penny Zheng 2019-01-22 11:03:02 +08:00
parent 1858c4da2c
commit 48fef40fd9
2 changed files with 81 additions and 1 deletions

View File

@ -11,6 +11,7 @@ package main
#include <linux/kvm.h> #include <linux/kvm.h>
const int ioctl_KVM_CREATE_VM = KVM_CREATE_VM; const int ioctl_KVM_CREATE_VM = KVM_CREATE_VM;
const int ioctl_KVM_CHECK_EXTENSION = KVM_CHECK_EXTENSION;
*/ */
import "C" import "C"
@ -40,6 +41,15 @@ type kernelModule struct {
required bool required bool
} }
// nolint: structcheck, unused, deadcode
type kvmExtension struct {
// description
desc string
// extension identifier
id int
}
type vmContainerCapableDetails struct { type vmContainerCapableDetails struct {
cpuInfoFile string cpuInfoFile string
requiredCPUFlags map[string]string requiredCPUFlags map[string]string
@ -388,3 +398,42 @@ func genericKvmIsUsable() error {
return nil 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
}

View File

@ -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 { func setCPUtype() error {
return nil return nil
} }
@ -57,8 +66,30 @@ func kvmIsUsable() error {
return genericKvmIsUsable() 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 { func archHostCanCreateVMContainer() error {
return kvmIsUsable() if err := kvmIsUsable(); err != nil {
return err
}
return checkKVMExtensions()
} }
// hostIsVMContainerCapable checks to see if the host is theoretically capable // hostIsVMContainerCapable checks to see if the host is theoretically capable