KVM: PPC: Book3S HV: Implement H_SVM_INIT_ABORT hcall
Implement the H_SVM_INIT_ABORT hcall which the Ultravisor can use to abort an SVM after it has issued the H_SVM_INIT_START and before the H_SVM_INIT_DONE hcalls. This hcall could be used when Ultravisor encounters security violations or other errors when starting an SVM. Note that this hcall is different from UV_SVM_TERMINATE ucall which is used by HV to terminate/cleanup an VM that has becore secure. The H_SVM_INIT_ABORT basically undoes operations that were done since the H_SVM_INIT_START hcall - i.e page-out all the VM pages back to normal memory, and terminate the SVM. (If we do not bring the pages back to normal memory, the text/data of the VM would be stuck in secure memory and since the SVM did not go secure, its MSR_S bit will be clear and the VM wont be able to access its pages even to do a clean exit). Based on patches and discussion with Paul Mackerras, Ram Pai and Bharata Rao. Signed-off-by: Ram Pai <linuxram@linux.ibm.com> Signed-off-by: Sukadev Bhattiprolu <sukadev@linux.ibm.com> Signed-off-by: Bharata B Rao <bharata@linux.ibm.com> Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
ce477a7a1c
commit
3a43970d55
|
@ -948,6 +948,66 @@ Use cases
|
|||
up its internal state for this virtual machine.
|
||||
|
||||
|
||||
H_SVM_INIT_ABORT
|
||||
----------------
|
||||
|
||||
Abort the process of securing an SVM.
|
||||
|
||||
Syntax
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
uint64_t hypercall(const uint64_t H_SVM_INIT_ABORT)
|
||||
|
||||
Return values
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
One of the following values:
|
||||
|
||||
* H_PARAMETER on successfully cleaning up the state,
|
||||
Hypervisor will return this value to the
|
||||
**guest**, to indicate that the underlying
|
||||
UV_ESM ultracall failed.
|
||||
|
||||
* H_STATE if called after a VM has gone secure (i.e
|
||||
H_SVM_INIT_DONE hypercall was successful).
|
||||
|
||||
* H_UNSUPPORTED if called from a wrong context (e.g. from a
|
||||
normal VM).
|
||||
|
||||
Description
|
||||
~~~~~~~~~~~
|
||||
|
||||
Abort the process of securing a virtual machine. This call must
|
||||
be made after a prior call to ``H_SVM_INIT_START`` hypercall and
|
||||
before a call to ``H_SVM_INIT_DONE``.
|
||||
|
||||
On entry into this hypercall the non-volatile GPRs and FPRs are
|
||||
expected to contain the values they had at the time the VM issued
|
||||
the UV_ESM ultracall. Further ``SRR0`` is expected to contain the
|
||||
address of the instruction after the ``UV_ESM`` ultracall and ``SRR1``
|
||||
the MSR value with which to return to the VM.
|
||||
|
||||
This hypercall will cleanup any partial state that was established for
|
||||
the VM since the prior ``H_SVM_INIT_START`` hypercall, including paging
|
||||
out pages that were paged-into secure memory, and issue the
|
||||
``UV_SVM_TERMINATE`` ultracall to terminate the VM.
|
||||
|
||||
After the partial state is cleaned up, control returns to the VM
|
||||
(**not Ultravisor**), at the address specified in ``SRR0`` with the
|
||||
MSR values set to the value in ``SRR1``.
|
||||
|
||||
Use cases
|
||||
~~~~~~~~~
|
||||
|
||||
If after a successful call to ``H_SVM_INIT_START``, the Ultravisor
|
||||
encounters an error while securing a virtual machine, either due
|
||||
to lack of resources or because the VM's security information could
|
||||
not be validated, Ultravisor informs the Hypervisor about it.
|
||||
Hypervisor should use this call to clean up any internal state for
|
||||
this virtual machine and return to the VM.
|
||||
|
||||
H_SVM_PAGE_IN
|
||||
-------------
|
||||
|
||||
|
|
|
@ -350,6 +350,7 @@
|
|||
#define H_SVM_PAGE_OUT 0xEF04
|
||||
#define H_SVM_INIT_START 0xEF08
|
||||
#define H_SVM_INIT_DONE 0xEF0C
|
||||
#define H_SVM_INIT_ABORT 0xEF14
|
||||
|
||||
/* Values for 2nd argument to H_SET_MODE */
|
||||
#define H_SET_MODE_RESOURCE_SET_CIABR 1
|
||||
|
|
|
@ -19,6 +19,7 @@ unsigned long kvmppc_h_svm_page_out(struct kvm *kvm,
|
|||
unsigned long kvmppc_h_svm_init_start(struct kvm *kvm);
|
||||
unsigned long kvmppc_h_svm_init_done(struct kvm *kvm);
|
||||
int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn);
|
||||
unsigned long kvmppc_h_svm_init_abort(struct kvm *kvm);
|
||||
void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
|
||||
struct kvm *kvm, bool skip_page_out);
|
||||
#else
|
||||
|
@ -62,6 +63,11 @@ static inline unsigned long kvmppc_h_svm_init_done(struct kvm *kvm)
|
|||
return H_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static inline unsigned long kvmppc_h_svm_init_abort(struct kvm *kvm)
|
||||
{
|
||||
return H_UNSUPPORTED;
|
||||
}
|
||||
|
||||
static inline int kvmppc_send_page_to_uv(struct kvm *kvm, unsigned long gfn)
|
||||
{
|
||||
return -EFAULT;
|
||||
|
|
|
@ -278,6 +278,7 @@ struct kvm_resize_hpt;
|
|||
/* Flag values for kvm_arch.secure_guest */
|
||||
#define KVMPPC_SECURE_INIT_START 0x1 /* H_SVM_INIT_START has been called */
|
||||
#define KVMPPC_SECURE_INIT_DONE 0x2 /* H_SVM_INIT_DONE completed */
|
||||
#define KVMPPC_SECURE_INIT_ABORT 0x4 /* H_SVM_INIT_ABORT issued */
|
||||
|
||||
struct kvm_arch {
|
||||
unsigned int lpid;
|
||||
|
|
|
@ -1091,6 +1091,9 @@ int kvmppc_pseries_do_hcall(struct kvm_vcpu *vcpu)
|
|||
case H_SVM_INIT_DONE:
|
||||
ret = kvmppc_h_svm_init_done(vcpu->kvm);
|
||||
break;
|
||||
case H_SVM_INIT_ABORT:
|
||||
ret = kvmppc_h_svm_init_abort(vcpu->kvm);
|
||||
break;
|
||||
|
||||
default:
|
||||
return RESUME_HOST;
|
||||
|
|
|
@ -286,6 +286,34 @@ void kvmppc_uvmem_drop_pages(const struct kvm_memory_slot *free,
|
|||
}
|
||||
}
|
||||
|
||||
unsigned long kvmppc_h_svm_init_abort(struct kvm *kvm)
|
||||
{
|
||||
int srcu_idx;
|
||||
struct kvm_memory_slot *memslot;
|
||||
|
||||
/*
|
||||
* Expect to be called only after INIT_START and before INIT_DONE.
|
||||
* If INIT_DONE was completed, use normal VM termination sequence.
|
||||
*/
|
||||
if (!(kvm->arch.secure_guest & KVMPPC_SECURE_INIT_START))
|
||||
return H_UNSUPPORTED;
|
||||
|
||||
if (kvm->arch.secure_guest & KVMPPC_SECURE_INIT_DONE)
|
||||
return H_STATE;
|
||||
|
||||
srcu_idx = srcu_read_lock(&kvm->srcu);
|
||||
|
||||
kvm_for_each_memslot(memslot, kvm_memslots(kvm))
|
||||
kvmppc_uvmem_drop_pages(memslot, kvm, false);
|
||||
|
||||
srcu_read_unlock(&kvm->srcu, srcu_idx);
|
||||
|
||||
kvm->arch.secure_guest = 0;
|
||||
uv_svm_terminate(kvm->arch.lpid);
|
||||
|
||||
return H_PARAMETER;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free device PFN from the pool
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue