Skip to content

Commit 89ea60c

Browse files
sean-jcbonzini
authored andcommitted
KVM: x86: Add support for "protected VMs" that can utilize private memory
Add a new x86 VM type, KVM_X86_SW_PROTECTED_VM, to serve as a development and testing vehicle for Confidential (CoCo) VMs, and potentially to even become a "real" product in the distant future, e.g. a la pKVM. The private memory support in KVM x86 is aimed at AMD's SEV-SNP and Intel's TDX, but those technologies are extremely complex (understatement), difficult to debug, don't support running as nested guests, and require hardware that's isn't universally accessible. I.e. relying SEV-SNP or TDX for maintaining guest private memory isn't a realistic option. At the very least, KVM_X86_SW_PROTECTED_VM will enable a variety of selftests for guest_memfd and private memory support without requiring unique hardware. Signed-off-by: Sean Christopherson <seanjc@google.com> Reviewed-by: Paolo Bonzini <pbonzini@redhat.com> Message-Id: <20231027182217.3615211-24-seanjc@google.com> Reviewed-by: Fuad Tabba <tabba@google.com> Tested-by: Fuad Tabba <tabba@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent eed52e4 commit 89ea60c

8 files changed

Lines changed: 78 additions & 7 deletions

File tree

Documentation/virt/kvm/api.rst

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,29 @@ described as 'basic' will be available.
147147
The new VM has no virtual cpus and no memory.
148148
You probably want to use 0 as machine type.
149149

150+
X86:
151+
^^^^
152+
153+
Supported X86 VM types can be queried via KVM_CAP_VM_TYPES.
154+
155+
S390:
156+
^^^^^
157+
150158
In order to create user controlled virtual machines on S390, check
151159
KVM_CAP_S390_UCONTROL and use the flag KVM_VM_S390_UCONTROL as
152160
privileged user (CAP_SYS_ADMIN).
153161

162+
MIPS:
163+
^^^^^
164+
165+
To use hardware assisted virtualization on MIPS (VZ ASE) rather than
166+
the default trap & emulate implementation (which changes the virtual
167+
memory layout to fit in user mode), check KVM_CAP_MIPS_VZ and use the
168+
flag KVM_VM_MIPS_VZ.
169+
170+
ARM64:
171+
^^^^^^
172+
154173
On arm64, the physical address size for a VM (IPA Size limit) is limited
155174
to 40bits by default. The limit can be configured if the host supports the
156175
extension KVM_CAP_ARM_VM_IPA_SIZE. When supported, use
@@ -8765,6 +8784,19 @@ block sizes is exposed in KVM_CAP_ARM_SUPPORTED_BLOCK_SIZES as a
87658784
64-bit bitmap (each bit describing a block size). The default value is
87668785
0, to disable the eager page splitting.
87678786

8787+
8.41 KVM_CAP_VM_TYPES
8788+
---------------------
8789+
8790+
:Capability: KVM_CAP_MEMORY_ATTRIBUTES
8791+
:Architectures: x86
8792+
:Type: system ioctl
8793+
8794+
This capability returns a bitmap of support VM types. The 1-setting of bit @n
8795+
means the VM type with value @n is supported. Possible values of @n are::
8796+
8797+
#define KVM_X86_DEFAULT_VM 0
8798+
#define KVM_X86_SW_PROTECTED_VM 1
8799+
87688800
9. Known KVM API problems
87698801
=========================
87708802

arch/x86/include/asm/kvm_host.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,6 +1255,7 @@ enum kvm_apicv_inhibit {
12551255
};
12561256

12571257
struct kvm_arch {
1258+
unsigned long vm_type;
12581259
unsigned long n_used_mmu_pages;
12591260
unsigned long n_requested_mmu_pages;
12601261
unsigned long n_max_mmu_pages;
@@ -2089,6 +2090,12 @@ void kvm_mmu_new_pgd(struct kvm_vcpu *vcpu, gpa_t new_pgd);
20892090
void kvm_configure_mmu(bool enable_tdp, int tdp_forced_root_level,
20902091
int tdp_max_root_level, int tdp_huge_page_level);
20912092

2093+
#ifdef CONFIG_KVM_PRIVATE_MEM
2094+
#define kvm_arch_has_private_mem(kvm) ((kvm)->arch.vm_type != KVM_X86_DEFAULT_VM)
2095+
#else
2096+
#define kvm_arch_has_private_mem(kvm) false
2097+
#endif
2098+
20922099
static inline u16 kvm_read_ldt(void)
20932100
{
20942101
u16 ldt;
@@ -2137,14 +2144,10 @@ enum {
21372144
#define HF_SMM_INSIDE_NMI_MASK (1 << 2)
21382145

21392146
# define KVM_MAX_NR_ADDRESS_SPACES 2
2147+
/* SMM is currently unsupported for guests with private memory. */
2148+
# define kvm_arch_nr_memslot_as_ids(kvm) (kvm_arch_has_private_mem(kvm) ? 1 : 2)
21402149
# define kvm_arch_vcpu_memslots_id(vcpu) ((vcpu)->arch.hflags & HF_SMM_MASK ? 1 : 0)
21412150
# define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, (role).smm)
2142-
2143-
static inline int kvm_arch_nr_memslot_as_ids(struct kvm *kvm)
2144-
{
2145-
return KVM_MAX_NR_ADDRESS_SPACES;
2146-
}
2147-
21482151
#else
21492152
# define kvm_memslots_for_spte_role(kvm, role) __kvm_memslots(kvm, 0)
21502153
#endif

arch/x86/include/uapi/asm/kvm.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,4 +562,7 @@ struct kvm_pmu_event_filter {
562562
/* x86-specific KVM_EXIT_HYPERCALL flags. */
563563
#define KVM_EXIT_HYPERCALL_LONG_MODE BIT(0)
564564

565+
#define KVM_X86_DEFAULT_VM 0
566+
#define KVM_X86_SW_PROTECTED_VM 1
567+
565568
#endif /* _ASM_X86_KVM_H */

arch/x86/kvm/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ config KVM_WERROR
7777

7878
If in doubt, say "N".
7979

80+
config KVM_SW_PROTECTED_VM
81+
bool "Enable support for KVM software-protected VMs"
82+
depends on EXPERT
83+
depends on X86_64
84+
select KVM_GENERIC_PRIVATE_MEM
85+
help
86+
Enable support for KVM software-protected VMs. Currently "protected"
87+
means the VM can be backed with memory provided by
88+
KVM_CREATE_GUEST_MEMFD.
89+
90+
If unsure, say "N".
91+
8092
config KVM_INTEL
8193
tristate "KVM for Intel (and compatible) processors support"
8294
depends on KVM && IA32_FEAT_CTL

arch/x86/kvm/mmu/mmu_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
297297
.max_level = KVM_MAX_HUGEPAGE_LEVEL,
298298
.req_level = PG_LEVEL_4K,
299299
.goal_level = PG_LEVEL_4K,
300+
.is_private = kvm_mem_is_private(vcpu->kvm, cr2_or_gpa >> PAGE_SHIFT),
300301
};
301302
int r;
302303

arch/x86/kvm/x86.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4548,6 +4548,13 @@ static int kvm_ioctl_get_supported_hv_cpuid(struct kvm_vcpu *vcpu,
45484548
return 0;
45494549
}
45504550

4551+
static bool kvm_is_vm_type_supported(unsigned long type)
4552+
{
4553+
return type == KVM_X86_DEFAULT_VM ||
4554+
(type == KVM_X86_SW_PROTECTED_VM &&
4555+
IS_ENABLED(CONFIG_KVM_SW_PROTECTED_VM) && tdp_enabled);
4556+
}
4557+
45514558
int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
45524559
{
45534560
int r = 0;
@@ -4739,6 +4746,11 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext)
47394746
case KVM_CAP_X86_NOTIFY_VMEXIT:
47404747
r = kvm_caps.has_notify_vmexit;
47414748
break;
4749+
case KVM_CAP_VM_TYPES:
4750+
r = BIT(KVM_X86_DEFAULT_VM);
4751+
if (kvm_is_vm_type_supported(KVM_X86_SW_PROTECTED_VM))
4752+
r |= BIT(KVM_X86_SW_PROTECTED_VM);
4753+
break;
47424754
default:
47434755
break;
47444756
}
@@ -12436,9 +12448,11 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
1243612448
int ret;
1243712449
unsigned long flags;
1243812450

12439-
if (type)
12451+
if (!kvm_is_vm_type_supported(type))
1244012452
return -EINVAL;
1244112453

12454+
kvm->arch.vm_type = type;
12455+
1244212456
ret = kvm_page_track_init(kvm);
1244312457
if (ret)
1244412458
goto out;

include/uapi/linux/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1227,6 +1227,7 @@ struct kvm_ppc_resize_hpt {
12271227
#define KVM_CAP_MEMORY_FAULT_INFO 232
12281228
#define KVM_CAP_MEMORY_ATTRIBUTES 233
12291229
#define KVM_CAP_GUEST_MEMFD 234
1230+
#define KVM_CAP_VM_TYPES 235
12301231

12311232
#ifdef KVM_CAP_IRQ_ROUTING
12321233

virt/kvm/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,8 @@ config KVM_GENERIC_MEMORY_ATTRIBUTES
104104
config KVM_PRIVATE_MEM
105105
select XARRAY_MULTI
106106
bool
107+
108+
config KVM_GENERIC_PRIVATE_MEM
109+
select KVM_GENERIC_MEMORY_ATTRIBUTES
110+
select KVM_PRIVATE_MEM
111+
bool

0 commit comments

Comments
 (0)