Skip to content

Commit 651a631

Browse files
Ram Paipaulusmack
authored andcommitted
KVM: PPC: Book3S HV: Track the state GFNs associated with secure VMs
During the life of SVM, its GFNs transition through normal, secure and shared states. Since the kernel does not track GFNs that are shared, it is not possible to disambiguate a shared GFN from a GFN whose PFN has not yet been migrated to a secure-PFN. Also it is not possible to disambiguate a secure-GFN from a GFN whose GFN has been pagedout from the ultravisor. The ability to identify the state of a GFN is needed to skip migration of its PFN to secure-PFN during ESM transition. The code is re-organized to track the states of a GFN as explained below. ************************************************************************ 1. States of a GFN --------------- The GFN can be in one of the following states. (a) Secure - The GFN is secure. The GFN is associated with a Secure VM, the contents of the GFN is not accessible to the Hypervisor. This GFN can be backed by a secure-PFN, or can be backed by a normal-PFN with contents encrypted. The former is true when the GFN is paged-in into the ultravisor. The latter is true when the GFN is paged-out of the ultravisor. (b) Shared - The GFN is shared. The GFN is associated with a a secure VM. The contents of the GFN is accessible to Hypervisor. This GFN is backed by a normal-PFN and its content is un-encrypted. (c) Normal - The GFN is a normal. The GFN is associated with a normal VM. The contents of the GFN is accesible to the Hypervisor. Its content is never encrypted. 2. States of a VM. --------------- (a) Normal VM: A VM whose contents are always accessible to the hypervisor. All its GFNs are normal-GFNs. (b) Secure VM: A VM whose contents are not accessible to the hypervisor without the VM's consent. Its GFNs are either Shared-GFN or Secure-GFNs. (c) Transient VM: A Normal VM that is transitioning to secure VM. The transition starts on successful return of H_SVM_INIT_START, and ends on successful return of H_SVM_INIT_DONE. This transient VM, can have GFNs in any of the three states; i.e Secure-GFN, Shared-GFN, and Normal-GFN. The VM never executes in this state in supervisor-mode. 3. Memory slot State. ------------------ The state of a memory slot mirrors the state of the VM the memory slot is associated with. 4. VM State transition. -------------------- A VM always starts in Normal Mode. H_SVM_INIT_START moves the VM into transient state. During this time the Ultravisor may request some of its GFNs to be shared or secured. So its GFNs can be in one of the three GFN states. H_SVM_INIT_DONE moves the VM entirely from transient state to secure-state. At this point any left-over normal-GFNs are transitioned to Secure-GFN. H_SVM_INIT_ABORT moves the transient VM back to normal VM. All its GFNs are moved to Normal-GFNs. UV_TERMINATE transitions the secure-VM back to normal-VM. All the secure-GFN and shared-GFNs are tranistioned to normal-GFN Note: The contents of the normal-GFN is undefined at this point. 5. GFN state implementation: ------------------------- Secure GFN is associated with a secure-PFN; also called uvmem_pfn, when the GFN is paged-in. Its pfn[] has KVMPPC_GFN_UVMEM_PFN flag set, and contains the value of the secure-PFN. It is associated with a normal-PFN; also called mem_pfn, when the GFN is pagedout. Its pfn[] has KVMPPC_GFN_MEM_PFN flag set. The value of the normal-PFN is not tracked. Shared GFN is associated with a normal-PFN. Its pfn[] has KVMPPC_UVMEM_SHARED_PFN flag set. The value of the normal-PFN is not tracked. Normal GFN is associated with normal-PFN. Its pfn[] has no flag set. The value of the normal-PFN is not tracked. 6. Life cycle of a GFN -------------------- -------------------------------------------------------------- | | Share | Unshare | SVM |H_SVM_INIT_DONE| | |operation |operation | abort/ | | | | | | terminate | | ------------------------------------------------------------- | | | | | | | Secure | Shared | Secure |Normal |Secure | | | | | | | | Shared | Shared | Secure |Normal |Shared | | | | | | | | Normal | Shared | Secure |Normal |Secure | -------------------------------------------------------------- 7. Life cycle of a VM -------------------- -------------------------------------------------------------------- | | start | H_SVM_ |H_SVM_ |H_SVM_ |UV_SVM_ | | | VM |INIT_START|INIT_DONE|INIT_ABORT |TERMINATE | | | | | | | | --------- ---------------------------------------------------------- | | | | | | | | Normal | Normal | Transient|Error |Error |Normal | | | | | | | | | Secure | Error | Error |Error |Error |Normal | | | | | | | | |Transient| N/A | Error |Secure |Normal |Normal | -------------------------------------------------------------------- ************************************************************************ Reviewed-by: Bharata B Rao <[email protected]> Reviewed-by: Thiago Jung Bauermann <[email protected]> Signed-off-by: Ram Pai <[email protected]> Signed-off-by: Paul Mackerras <[email protected]>
1 parent 2027a24 commit 651a631

File tree

1 file changed

+172
-19
lines changed

1 file changed

+172
-19
lines changed

arch/powerpc/kvm/book3s_hv_uvmem.c

Lines changed: 172 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -98,19 +98,139 @@ static struct dev_pagemap kvmppc_uvmem_pgmap;
9898
static unsigned long *kvmppc_uvmem_bitmap;
9999
static DEFINE_SPINLOCK(kvmppc_uvmem_bitmap_lock);
100100

101-
#define KVMPPC_UVMEM_PFN (1UL << 63)
101+
/*
102+
* States of a GFN
103+
* ---------------
104+
* The GFN can be in one of the following states.
105+
*
106+
* (a) Secure - The GFN is secure. The GFN is associated with
107+
* a Secure VM, the contents of the GFN is not accessible
108+
* to the Hypervisor. This GFN can be backed by a secure-PFN,
109+
* or can be backed by a normal-PFN with contents encrypted.
110+
* The former is true when the GFN is paged-in into the
111+
* ultravisor. The latter is true when the GFN is paged-out
112+
* of the ultravisor.
113+
*
114+
* (b) Shared - The GFN is shared. The GFN is associated with a
115+
* a secure VM. The contents of the GFN is accessible to
116+
* Hypervisor. This GFN is backed by a normal-PFN and its
117+
* content is un-encrypted.
118+
*
119+
* (c) Normal - The GFN is a normal. The GFN is associated with
120+
* a normal VM. The contents of the GFN is accesible to
121+
* the Hypervisor. Its content is never encrypted.
122+
*
123+
* States of a VM.
124+
* ---------------
125+
*
126+
* Normal VM: A VM whose contents are always accessible to
127+
* the hypervisor. All its GFNs are normal-GFNs.
128+
*
129+
* Secure VM: A VM whose contents are not accessible to the
130+
* hypervisor without the VM's consent. Its GFNs are
131+
* either Shared-GFN or Secure-GFNs.
132+
*
133+
* Transient VM: A Normal VM that is transitioning to secure VM.
134+
* The transition starts on successful return of
135+
* H_SVM_INIT_START, and ends on successful return
136+
* of H_SVM_INIT_DONE. This transient VM, can have GFNs
137+
* in any of the three states; i.e Secure-GFN, Shared-GFN,
138+
* and Normal-GFN. The VM never executes in this state
139+
* in supervisor-mode.
140+
*
141+
* Memory slot State.
142+
* -----------------------------
143+
* The state of a memory slot mirrors the state of the
144+
* VM the memory slot is associated with.
145+
*
146+
* VM State transition.
147+
* --------------------
148+
*
149+
* A VM always starts in Normal Mode.
150+
*
151+
* H_SVM_INIT_START moves the VM into transient state. During this
152+
* time the Ultravisor may request some of its GFNs to be shared or
153+
* secured. So its GFNs can be in one of the three GFN states.
154+
*
155+
* H_SVM_INIT_DONE moves the VM entirely from transient state to
156+
* secure-state. At this point any left-over normal-GFNs are
157+
* transitioned to Secure-GFN.
158+
*
159+
* H_SVM_INIT_ABORT moves the transient VM back to normal VM.
160+
* All its GFNs are moved to Normal-GFNs.
161+
*
162+
* UV_TERMINATE transitions the secure-VM back to normal-VM. All
163+
* the secure-GFN and shared-GFNs are tranistioned to normal-GFN
164+
* Note: The contents of the normal-GFN is undefined at this point.
165+
*
166+
* GFN state implementation:
167+
* -------------------------
168+
*
169+
* Secure GFN is associated with a secure-PFN; also called uvmem_pfn,
170+
* when the GFN is paged-in. Its pfn[] has KVMPPC_GFN_UVMEM_PFN flag
171+
* set, and contains the value of the secure-PFN.
172+
* It is associated with a normal-PFN; also called mem_pfn, when
173+
* the GFN is pagedout. Its pfn[] has KVMPPC_GFN_MEM_PFN flag set.
174+
* The value of the normal-PFN is not tracked.
175+
*
176+
* Shared GFN is associated with a normal-PFN. Its pfn[] has
177+
* KVMPPC_UVMEM_SHARED_PFN flag set. The value of the normal-PFN
178+
* is not tracked.
179+
*
180+
* Normal GFN is associated with normal-PFN. Its pfn[] has
181+
* no flag set. The value of the normal-PFN is not tracked.
182+
*
183+
* Life cycle of a GFN
184+
* --------------------
185+
*
186+
* --------------------------------------------------------------
187+
* | | Share | Unshare | SVM |H_SVM_INIT_DONE|
188+
* | |operation |operation | abort/ | |
189+
* | | | | terminate | |
190+
* -------------------------------------------------------------
191+
* | | | | | |
192+
* | Secure | Shared | Secure |Normal |Secure |
193+
* | | | | | |
194+
* | Shared | Shared | Secure |Normal |Shared |
195+
* | | | | | |
196+
* | Normal | Shared | Secure |Normal |Secure |
197+
* --------------------------------------------------------------
198+
*
199+
* Life cycle of a VM
200+
* --------------------
201+
*
202+
* --------------------------------------------------------------------
203+
* | | start | H_SVM_ |H_SVM_ |H_SVM_ |UV_SVM_ |
204+
* | | VM |INIT_START|INIT_DONE|INIT_ABORT |TERMINATE |
205+
* | | | | | | |
206+
* --------- ----------------------------------------------------------
207+
* | | | | | | |
208+
* | Normal | Normal | Transient|Error |Error |Normal |
209+
* | | | | | | |
210+
* | Secure | Error | Error |Error |Error |Normal |
211+
* | | | | | | |
212+
* |Transient| N/A | Error |Secure |Normal |Normal |
213+
* --------------------------------------------------------------------
214+
*/
215+
216+
#define KVMPPC_GFN_UVMEM_PFN (1UL << 63)
217+
#define KVMPPC_GFN_MEM_PFN (1UL << 62)
218+
#define KVMPPC_GFN_SHARED (1UL << 61)
219+
#define KVMPPC_GFN_SECURE (KVMPPC_GFN_UVMEM_PFN | KVMPPC_GFN_MEM_PFN)
220+
#define KVMPPC_GFN_FLAG_MASK (KVMPPC_GFN_SECURE | KVMPPC_GFN_SHARED)
221+
#define KVMPPC_GFN_PFN_MASK (~KVMPPC_GFN_FLAG_MASK)
102222

103223
struct kvmppc_uvmem_slot {
104224
struct list_head list;
105225
unsigned long nr_pfns;
106226
unsigned long base_pfn;
107227
unsigned long *pfns;
108228
};
109-
110229
struct kvmppc_uvmem_page_pvt {
111230
struct kvm *kvm;
112231
unsigned long gpa;
113232
bool skip_page_out;
233+
bool remove_gfn;
114234
};
115235

116236
bool kvmppc_uvmem_available(void)
@@ -163,33 +283,50 @@ void kvmppc_uvmem_slot_free(struct kvm *kvm, const struct kvm_memory_slot *slot)
163283
mutex_unlock(&kvm->arch.uvmem_lock);
164284
}
165285

166-
static void kvmppc_uvmem_pfn_insert(unsigned long gfn, unsigned long uvmem_pfn,
167-
struct kvm *kvm)
286+
static void kvmppc_mark_gfn(unsigned long gfn, struct kvm *kvm,
287+
unsigned long flag, unsigned long uvmem_pfn)
168288
{
169289
struct kvmppc_uvmem_slot *p;
170290

171291
list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) {
172292
if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
173293
unsigned long index = gfn - p->base_pfn;
174294

175-
p->pfns[index] = uvmem_pfn | KVMPPC_UVMEM_PFN;
295+
if (flag == KVMPPC_GFN_UVMEM_PFN)
296+
p->pfns[index] = uvmem_pfn | flag;
297+
else
298+
p->pfns[index] = flag;
176299
return;
177300
}
178301
}
179302
}
180303

181-
static void kvmppc_uvmem_pfn_remove(unsigned long gfn, struct kvm *kvm)
304+
/* mark the GFN as secure-GFN associated with @uvmem pfn device-PFN. */
305+
static void kvmppc_gfn_secure_uvmem_pfn(unsigned long gfn,
306+
unsigned long uvmem_pfn, struct kvm *kvm)
182307
{
183-
struct kvmppc_uvmem_slot *p;
308+
kvmppc_mark_gfn(gfn, kvm, KVMPPC_GFN_UVMEM_PFN, uvmem_pfn);
309+
}
184310

185-
list_for_each_entry(p, &kvm->arch.uvmem_pfns, list) {
186-
if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
187-
p->pfns[gfn - p->base_pfn] = 0;
188-
return;
189-
}
190-
}
311+
/* mark the GFN as secure-GFN associated with a memory-PFN. */
312+
static void kvmppc_gfn_secure_mem_pfn(unsigned long gfn, struct kvm *kvm)
313+
{
314+
kvmppc_mark_gfn(gfn, kvm, KVMPPC_GFN_MEM_PFN, 0);
191315
}
192316

317+
/* mark the GFN as a shared GFN. */
318+
static void kvmppc_gfn_shared(unsigned long gfn, struct kvm *kvm)
319+
{
320+
kvmppc_mark_gfn(gfn, kvm, KVMPPC_GFN_SHARED, 0);
321+
}
322+
323+
/* mark the GFN as a non-existent GFN. */
324+
static void kvmppc_gfn_remove(unsigned long gfn, struct kvm *kvm)
325+
{
326+
kvmppc_mark_gfn(gfn, kvm, 0, 0);
327+
}
328+
329+
/* return true, if the GFN is a secure-GFN backed by a secure-PFN */
193330
static bool kvmppc_gfn_is_uvmem_pfn(unsigned long gfn, struct kvm *kvm,
194331
unsigned long *uvmem_pfn)
195332
{
@@ -199,10 +336,10 @@ static bool kvmppc_gfn_is_uvmem_pfn(unsigned long gfn, struct kvm *kvm,
199336
if (gfn >= p->base_pfn && gfn < p->base_pfn + p->nr_pfns) {
200337
unsigned long index = gfn - p->base_pfn;
201338

202-
if (p->pfns[index] & KVMPPC_UVMEM_PFN) {
339+
if (p->pfns[index] & KVMPPC_GFN_UVMEM_PFN) {
203340
if (uvmem_pfn)
204341
*uvmem_pfn = p->pfns[index] &
205-
~KVMPPC_UVMEM_PFN;
342+
KVMPPC_GFN_PFN_MASK;
206343
return true;
207344
} else
208345
return false;
@@ -354,13 +491,15 @@ void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
354491

355492
mutex_lock(&kvm->arch.uvmem_lock);
356493
if (!kvmppc_gfn_is_uvmem_pfn(gfn, kvm, &uvmem_pfn)) {
494+
kvmppc_gfn_remove(gfn, kvm);
357495
mutex_unlock(&kvm->arch.uvmem_lock);
358496
continue;
359497
}
360498

361499
uvmem_page = pfn_to_page(uvmem_pfn);
362500
pvt = uvmem_page->zone_device_data;
363501
pvt->skip_page_out = skip_page_out;
502+
pvt->remove_gfn = true;
364503
mutex_unlock(&kvm->arch.uvmem_lock);
365504

366505
pfn = gfn_to_pfn(kvm, gfn);
@@ -430,7 +569,7 @@ static struct page *kvmppc_uvmem_get_page(unsigned long gpa, struct kvm *kvm)
430569
goto out_clear;
431570

432571
uvmem_pfn = bit + pfn_first;
433-
kvmppc_uvmem_pfn_insert(gpa >> PAGE_SHIFT, uvmem_pfn, kvm);
572+
kvmppc_gfn_secure_uvmem_pfn(gpa >> PAGE_SHIFT, uvmem_pfn, kvm);
434573

435574
pvt->gpa = gpa;
436575
pvt->kvm = kvm;
@@ -525,6 +664,11 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa,
525664
uvmem_page = pfn_to_page(uvmem_pfn);
526665
pvt = uvmem_page->zone_device_data;
527666
pvt->skip_page_out = true;
667+
/*
668+
* do not drop the GFN. It is a valid GFN
669+
* that is transitioned to a shared GFN.
670+
*/
671+
pvt->remove_gfn = false;
528672
}
529673

530674
retry:
@@ -538,12 +682,16 @@ static unsigned long kvmppc_share_page(struct kvm *kvm, unsigned long gpa,
538682
uvmem_page = pfn_to_page(uvmem_pfn);
539683
pvt = uvmem_page->zone_device_data;
540684
pvt->skip_page_out = true;
685+
pvt->remove_gfn = false; /* it continues to be a valid GFN */
541686
kvm_release_pfn_clean(pfn);
542687
goto retry;
543688
}
544689

545-
if (!uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0, page_shift))
690+
if (!uv_page_in(kvm->arch.lpid, pfn << page_shift, gpa, 0,
691+
page_shift)) {
692+
kvmppc_gfn_shared(gfn, kvm);
546693
ret = H_SUCCESS;
694+
}
547695
kvm_release_pfn_clean(pfn);
548696
mutex_unlock(&kvm->arch.uvmem_lock);
549697
out:
@@ -599,6 +747,7 @@ unsigned long kvmppc_h_svm_page_in(struct kvm *kvm, unsigned long gpa,
599747

600748
if (!kvmppc_svm_page_in(vma, start, end, gpa, kvm, page_shift))
601749
ret = H_SUCCESS;
750+
602751
out_unlock:
603752
mutex_unlock(&kvm->arch.uvmem_lock);
604753
out:
@@ -707,7 +856,8 @@ static vm_fault_t kvmppc_uvmem_migrate_to_ram(struct vm_fault *vmf)
707856
/*
708857
* Release the device PFN back to the pool
709858
*
710-
* Gets called when secure page becomes a normal page during H_SVM_PAGE_OUT.
859+
* Gets called when secure GFN tranistions from a secure-PFN
860+
* to a normal PFN during H_SVM_PAGE_OUT.
711861
* Gets called with kvm->arch.uvmem_lock held.
712862
*/
713863
static void kvmppc_uvmem_page_free(struct page *page)
@@ -722,7 +872,10 @@ static void kvmppc_uvmem_page_free(struct page *page)
722872

723873
pvt = page->zone_device_data;
724874
page->zone_device_data = NULL;
725-
kvmppc_uvmem_pfn_remove(pvt->gpa >> PAGE_SHIFT, pvt->kvm);
875+
if (pvt->remove_gfn)
876+
kvmppc_gfn_remove(pvt->gpa >> PAGE_SHIFT, pvt->kvm);
877+
else
878+
kvmppc_gfn_secure_mem_pfn(pvt->gpa >> PAGE_SHIFT, pvt->kvm);
726879
kfree(pvt);
727880
}
728881

0 commit comments

Comments
 (0)