Skip to content

Commit ca9f494

Browse files
Bharata B Raopaulusmack
authored andcommitted
KVM: PPC: Book3S HV: Support for running secure guests
A pseries guest can be run as secure guest on Ultravisor-enabled POWER platforms. On such platforms, this driver will be used to manage the movement of guest pages between the normal memory managed by hypervisor (HV) and secure memory managed by Ultravisor (UV). HV is informed about the guest's transition to secure mode via hcalls: H_SVM_INIT_START: Initiate securing a VM H_SVM_INIT_DONE: Conclude securing a VM As part of H_SVM_INIT_START, register all existing memslots with the UV. H_SVM_INIT_DONE call by UV informs HV that transition of the guest to secure mode is complete. These two states (transition to secure mode STARTED and transition to secure mode COMPLETED) are recorded in kvm->arch.secure_guest. Setting these states will cause the assembly code that enters the guest to call the UV_RETURN ucall instead of trying to enter the guest directly. Migration of pages betwen normal and secure memory of secure guest is implemented in H_SVM_PAGE_IN and H_SVM_PAGE_OUT hcalls. H_SVM_PAGE_IN: Move the content of a normal page to secure page H_SVM_PAGE_OUT: Move the content of a secure page to normal page Private ZONE_DEVICE memory equal to the amount of secure memory available in the platform for running secure guests is created. Whenever a page belonging to the guest becomes secure, a page from this private device memory is used to represent and track that secure page on the HV side. The movement of pages between normal and secure memory is done via migrate_vma_pages() using UV_PAGE_IN and UV_PAGE_OUT ucalls. In order to prevent the device private pages (that correspond to pages of secure guest) from participating in KSM merging, H_SVM_PAGE_IN calls ksm_madvise() under read version of mmap_sem. However ksm_madvise() needs to be under write lock. Hence we call kvmppc_svm_page_in with mmap_sem held for writing, and it then downgrades to a read lock after calling ksm_madvise. [[email protected] - roll in patch "KVM: PPC: Book3S HV: Take write mmap_sem when calling ksm_madvise"] Signed-off-by: Bharata B Rao <[email protected]> Signed-off-by: Paul Mackerras <[email protected]>
1 parent 33cf170 commit ca9f494

File tree

8 files changed

+769
-0
lines changed

8 files changed

+769
-0
lines changed

arch/powerpc/include/asm/hvcall.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,12 @@
342342
#define H_TLB_INVALIDATE 0xF808
343343
#define H_COPY_TOFROM_GUEST 0xF80C
344344

345+
/* Platform-specific hcalls used by the Ultravisor */
346+
#define H_SVM_PAGE_IN 0xEF00
347+
#define H_SVM_PAGE_OUT 0xEF04
348+
#define H_SVM_INIT_START 0xEF08
349+
#define H_SVM_INIT_DONE 0xEF0C
350+
345351
/* Values for 2nd argument to H_SET_MODE */
346352
#define H_SET_MODE_RESOURCE_SET_CIABR 1
347353
#define H_SET_MODE_RESOURCE_SET_DAWR 2
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
#ifndef __ASM_KVM_BOOK3S_UVMEM_H__
3+
#define __ASM_KVM_BOOK3S_UVMEM_H__
4+
5+
#ifdef CONFIG_PPC_UV
6+
int kvmppc_uvmem_init(void);
7+
void kvmppc_uvmem_free(void);
8+
int kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot);
9+
void kvmppc_uvmem_slot_free(struct kvm *kvm,
10+
const struct kvm_memory_slot *slot);
11+
unsigned long kvmppc_h_svm_page_in(struct kvm *kvm,
12+
unsigned long gra,
13+
unsigned long flags,
14+
unsigned long page_shift);
15+
unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
16+
unsigned long gra,
17+
unsigned long flags,
18+
unsigned long page_shift);
19+
unsigned long kvmppc_h_svm_init_start(struct kvm *kvm);
20+
unsigned long kvmppc_h_svm_init_done(struct kvm *kvm);
21+
#else
22+
static inline int kvmppc_uvmem_init(void)
23+
{
24+
return 0;
25+
}
26+
27+
static inline void kvmppc_uvmem_free(void) { }
28+
29+
static inline int
30+
kvmppc_uvmem_slot_init(struct kvm *kvm, const struct kvm_memory_slot *slot)
31+
{
32+
return 0;
33+
}
34+
35+
static inline void
36+
kvmppc_uvmem_slot_free(struct kvm *kvm, const struct kvm_memory_slot *slot) { }
37+
38+
static inline unsigned long
39+
kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gra,
40+
unsigned long flags, unsigned long page_shift)
41+
{
42+
return H_UNSUPPORTED;
43+
}
44+
45+
static inline unsigned long
46+
kvmppc_h_svm_page_out(struct kvm *kvm, unsigned long gra,
47+
unsigned long flags, unsigned long page_shift)
48+
{
49+
return H_UNSUPPORTED;
50+
}
51+
52+
static inline unsigned long kvmppc_h_svm_init_start(struct kvm *kvm)
53+
{
54+
return H_UNSUPPORTED;
55+
}
56+
57+
static inline unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
58+
{
59+
return H_UNSUPPORTED;
60+
}
61+
#endif /* CONFIG_PPC_UV */
62+
#endif /* __ASM_KVM_BOOK3S_UVMEM_H__ */

arch/powerpc/include/asm/kvm_host.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ struct kvm_hpt_info {
275275

276276
struct kvm_resize_hpt;
277277

278+
/* Flag values for kvm_arch.secure_guest */
279+
#define KVMPPC_SECURE_INIT_START 0x1 /* H_SVM_INIT_START has been called */
280+
#define KVMPPC_SECURE_INIT_DONE 0x2 /* H_SVM_INIT_DONE completed */
281+
278282
struct kvm_arch {
279283
unsigned int lpid;
280284
unsigned int smt_mode; /* # vcpus per virtual core */
@@ -330,6 +334,8 @@ struct kvm_arch {
330334
#endif
331335
struct kvmppc_ops *kvm_ops;
332336
#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
337+
struct mutex uvmem_lock;
338+
struct list_head uvmem_pfns;
333339
struct mutex mmu_setup_lock; /* nests inside vcpu mutexes */
334340
u64 l1_ptcr;
335341
int max_nested_lpid;

arch/powerpc/include/asm/ultravisor-api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
#define UV_WRITE_PATE 0xF104
2727
#define UV_RETURN 0xF11C
2828
#define UV_ESM 0xF110
29+
#define UV_REGISTER_MEM_SLOT 0xF120
30+
#define UV_PAGE_IN 0xF128
31+
#define UV_PAGE_OUT 0xF12C
2932
#define UV_SHARE_PAGE 0xF130
3033
#define UV_UNSHARE_PAGE 0xF134
3134
#define UV_UNSHARE_ALL_PAGES 0xF140

arch/powerpc/include/asm/ultravisor.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,25 @@ static inline int uv_unshare_all_pages(void)
4646
return ucall_norets(UV_UNSHARE_ALL_PAGES);
4747
}
4848

49+
static inline int uv_page_in(u64 lpid, u64 src_ra, u64 dst_gpa, u64 flags,
50+
u64 page_shift)
51+
{
52+
return ucall_norets(UV_PAGE_IN, lpid, src_ra, dst_gpa, flags,
53+
page_shift);
54+
}
55+
56+
static inline int uv_page_out(u64 lpid, u64 dst_ra, u64 src_gpa, u64 flags,
57+
u64 page_shift)
58+
{
59+
return ucall_norets(UV_PAGE_OUT, lpid, dst_ra, src_gpa, flags,
60+
page_shift);
61+
}
62+
63+
static inline int uv_register_mem_slot(u64 lpid, u64 start_gpa, u64 size,
64+
u64 flags, u64 slotid)
65+
{
66+
return ucall_norets(UV_REGISTER_MEM_SLOT, lpid, start_gpa,
67+
size, flags, slotid);
68+
}
69+
4970
#endif /* _ASM_POWERPC_ULTRAVISOR_H */

arch/powerpc/kvm/Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ kvm-hv-y += \
7171
book3s_64_mmu_radix.o \
7272
book3s_hv_nested.o
7373

74+
kvm-hv-$(CONFIG_PPC_UV) += \
75+
book3s_hv_uvmem.o
76+
7477
kvm-hv-$(CONFIG_PPC_TRANSACTIONAL_MEM) += \
7578
book3s_hv_tm.o
7679

arch/powerpc/kvm/book3s_hv.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@
7272
#include <asm/xics.h>
7373
#include <asm/xive.h>
7474
#include <asm/hw_breakpoint.h>
75+
#include <asm/kvm_host.h>
76+
#include <asm/kvm_book3s_uvmem.h>
7577

7678
#include "book3s.h"
7779

@@ -1070,6 +1072,25 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
10701072
kvmppc_get_gpr(vcpu, 5),
10711073
kvmppc_get_gpr(vcpu, 6));
10721074
break;
1075+
case H_SVM_PAGE_IN:
1076+
ret = kvmppc_h_svm_page_in(vcpu->kvm,
1077+
kvmppc_get_gpr(vcpu, 4),
1078+
kvmppc_get_gpr(vcpu, 5),
1079+
kvmppc_get_gpr(vcpu, 6));
1080+
break;
1081+
case H_SVM_PAGE_OUT:
1082+
ret = kvmppc_h_svm_page_out(vcpu->kvm,
1083+
kvmppc_get_gpr(vcpu, 4),
1084+
kvmppc_get_gpr(vcpu, 5),
1085+
kvmppc_get_gpr(vcpu, 6));
1086+
break;
1087+
case H_SVM_INIT_START:
1088+
ret = kvmppc_h_svm_init_start(vcpu->kvm);
1089+
break;
1090+
case H_SVM_INIT_DONE:
1091+
ret = kvmppc_h_svm_init_done(vcpu->kvm);
1092+
break;
1093+
10731094
default:
10741095
return RESUME_HOST;
10751096
}
@@ -4767,6 +4788,8 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
47674788
char buf[32];
47684789
int ret;
47694790

4791+
mutex_init(&kvm->arch.uvmem_lock);
4792+
INIT_LIST_HEAD(&kvm->arch.uvmem_pfns);
47704793
mutex_init(&kvm->arch.mmu_setup_lock);
47714794

47724795
/* Allocate the guest's logical partition ID */
@@ -4938,6 +4961,7 @@ static void kvmppc_core_destroy_vm_hv(struct kvm *kvm)
49384961
kvm->arch.process_table = 0;
49394962
kvmhv_set_ptbl_entry(kvm->arch.lpid, 0, 0);
49404963
}
4964+
49414965
kvmppc_free_lpid(kvm->arch.lpid);
49424966

49434967
kvmppc_free_pimap(kvm);
@@ -5528,11 +5552,16 @@ static int kvmppc_book3s_init_hv(void)
55285552
no_mixing_hpt_and_radix = true;
55295553
}
55305554

5555+
r = kvmppc_uvmem_init();
5556+
if (r < 0)
5557+
pr_err("KVM-HV: kvmppc_uvmem_init failed %d\n", r);
5558+
55315559
return r;
55325560
}
55335561

55345562
static void kvmppc_book3s_exit_hv(void)
55355563
{
5564+
kvmppc_uvmem_free();
55365565
kvmppc_free_host_rm_ops();
55375566
if (kvmppc_radix_possible())
55385567
kvmppc_radix_exit();

0 commit comments

Comments
 (0)