Add CONFIG_PKVM_INTEL configuration to enable or disable pKVM feature on x86 platform (starting from Intel platform), and do pkvm_init as an extension of KVM. Now pkvm_init only reserves memory for pkvm data structure and does a quick setup for num_cpus. New pKVM on Intel platform files are placed under arch/x86/kvm/vmx/pkvm. Signed-off-by: Jason Chen CJ <jason.cj.chen@xxxxxxxxx> --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/Kconfig | 13 +++++++++++ arch/x86/kvm/Makefile | 1 + arch/x86/kvm/vmx/pkvm/Makefile | 7 ++++++ arch/x86/kvm/vmx/pkvm/include/pkvm.h | 15 ++++++++++++ arch/x86/kvm/vmx/pkvm/pkvm_host.c | 34 ++++++++++++++++++++++++++++ arch/x86/kvm/vmx/vmx.c | 3 +++ arch/x86/kvm/vmx/vmx.h | 4 ++++ arch/x86/kvm/x86.c | 5 ++++ 9 files changed, 83 insertions(+) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 6aaae18f1854..c3cf849a1370 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1731,6 +1731,7 @@ struct kvm_x86_nested_ops { }; struct kvm_x86_init_ops { + int (*pkvm_init)(void); int (*cpu_has_kvm_support)(void); int (*disabled_by_bios)(void); int (*check_processor_compatibility)(void); diff --git a/arch/x86/kvm/Kconfig b/arch/x86/kvm/Kconfig index fbeaa9ddef59..5a8ae5f80849 100644 --- a/arch/x86/kvm/Kconfig +++ b/arch/x86/kvm/Kconfig @@ -87,6 +87,19 @@ config KVM_INTEL To compile this as a module, choose M here: the module will be called kvm-intel. +config PKVM_INTEL + bool "pKVM for Intel processors support" + depends on KVM_INTEL=y + depends on X86_64 + help + Provides support for pKVM on Intel processors. + + This will deprivilege the host as a VM running in non-root VMX + operation mode, and pKVM hypervisor will run in root VMX + operation mode. + + If unsure, say N. + config X86_SGX_KVM bool "Software Guard eXtensions (SGX) Virtualization" depends on X86_SGX && KVM_INTEL diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index 80e3fe184d17..7fbca5cc7c1d 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile @@ -35,6 +35,7 @@ endif obj-$(CONFIG_KVM) += kvm.o obj-$(CONFIG_KVM_INTEL) += kvm-intel.o +obj-$(CONFIG_PKVM_INTEL) += vmx/pkvm/ obj-$(CONFIG_KVM_AMD) += kvm-amd.o AFLAGS_svm/vmenter.o := -iquote $(obj) diff --git a/arch/x86/kvm/vmx/pkvm/Makefile b/arch/x86/kvm/vmx/pkvm/Makefile new file mode 100644 index 000000000000..493bec8501c9 --- /dev/null +++ b/arch/x86/kvm/vmx/pkvm/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +ccflags-y += -I $(srctree)/arch/x86/kvm/vmx/pkvm/include + +pkvm-obj := pkvm_host.o + +obj-$(CONFIG_PKVM_INTEL) += $(pkvm-obj) diff --git a/arch/x86/kvm/vmx/pkvm/include/pkvm.h b/arch/x86/kvm/vmx/pkvm/include/pkvm.h new file mode 100644 index 000000000000..3fb76665e785 --- /dev/null +++ b/arch/x86/kvm/vmx/pkvm/include/pkvm.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Intel Corporation + */ + +#ifndef _PKVM_H_ +#define _PKVM_H_ + +struct pkvm_hyp { + int num_cpus; +}; + +#define PKVM_PAGES (ALIGN(sizeof(struct pkvm_hyp), PAGE_SIZE) >> PAGE_SHIFT) + +#endif diff --git a/arch/x86/kvm/vmx/pkvm/pkvm_host.c b/arch/x86/kvm/vmx/pkvm/pkvm_host.c new file mode 100644 index 000000000000..7677df6a2b34 --- /dev/null +++ b/arch/x86/kvm/vmx/pkvm/pkvm_host.c @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Intel Corporation + */ + +#include <linux/kernel.h> +#include <linux/module.h> + +#include <pkvm.h> + +MODULE_LICENSE("GPL"); + +static struct pkvm_hyp *pkvm; + +static void *pkvm_early_alloc_contig(int pages) +{ + return alloc_pages_exact(pages << PAGE_SHIFT, GFP_KERNEL | __GFP_ZERO); +} + +__init int pkvm_init(void) +{ + int ret = 0; + + pkvm = pkvm_early_alloc_contig(PKVM_PAGES); + if (!pkvm) { + ret = -ENOMEM; + goto out; + } + + pkvm->num_cpus = num_possible_cpus(); + +out: + return ret; +} diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 7eec0226d56a..1e55bde497f8 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8467,6 +8467,9 @@ static __init int hardware_setup(void) } static struct kvm_x86_init_ops vmx_init_ops __initdata = { +#ifdef CONFIG_PKVM_INTEL + .pkvm_init = pkvm_init, +#endif .cpu_has_kvm_support = cpu_has_kvm_support, .disabled_by_bios = vmx_disabled_by_bios, .check_processor_compatibility = vmx_check_processor_compat, diff --git a/arch/x86/kvm/vmx/vmx.h b/arch/x86/kvm/vmx/vmx.h index a3da84f4ea45..8b2c4f1f4c8e 100644 --- a/arch/x86/kvm/vmx/vmx.h +++ b/arch/x86/kvm/vmx/vmx.h @@ -752,4 +752,8 @@ static inline bool guest_cpuid_has_evmcs(struct kvm_vcpu *vcpu) to_vmx(vcpu)->nested.enlightened_vmcs_enabled; } +#ifdef CONFIG_PKVM_INTEL +int __init pkvm_init(void); +#endif + #endif /* __KVM_X86_VMX_H */ diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index a2c299d47e69..84ddeabbf94b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9312,6 +9312,11 @@ int kvm_arch_init(void *opaque) return -EOPNOTSUPP; } + if (ops->pkvm_init && ops->pkvm_init()) { + pr_err_ratelimited("kvm: pkvm init fail\n"); + return -EOPNOTSUPP; + } + /* * KVM explicitly assumes that the guest has an FPU and * FXSAVE/FXRSTOR. For example, the KVM_GET_FPU explicitly casts the -- 2.25.1