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