aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/book3s_pr_papr.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kvm/book3s_pr_papr.c')
-rw-r--r--arch/powerpc/kvm/book3s_pr_papr.c92
1 files changed, 80 insertions, 12 deletions
diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c
index 52a63bfe3f07..ce3c893d509b 100644
--- a/arch/powerpc/kvm/book3s_pr_papr.c
+++ b/arch/powerpc/kvm/book3s_pr_papr.c
@@ -40,8 +40,9 @@ static int kvmppc_h_pr_enter(struct kvm_vcpu *vcpu)
{
long flags = kvmppc_get_gpr(vcpu, 4);
long pte_index = kvmppc_get_gpr(vcpu, 5);
- unsigned long pteg[2 * 8];
- unsigned long pteg_addr, i, *hpte;
+ __be64 pteg[2 * 8];
+ __be64 *hpte;
+ unsigned long pteg_addr, i;
long int ret;
i = pte_index & 7;
@@ -93,8 +94,8 @@ static int kvmppc_h_pr_remove(struct kvm_vcpu *vcpu)
pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
- pte[0] = be64_to_cpu(pte[0]);
- pte[1] = be64_to_cpu(pte[1]);
+ pte[0] = be64_to_cpu((__force __be64)pte[0]);
+ pte[1] = be64_to_cpu((__force __be64)pte[1]);
ret = H_NOT_FOUND;
if ((pte[0] & HPTE_V_VALID) == 0 ||
@@ -171,8 +172,8 @@ static int kvmppc_h_pr_bulk_remove(struct kvm_vcpu *vcpu)
pteg = get_pteg_addr(vcpu, tsh & H_BULK_REMOVE_PTEX);
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
- pte[0] = be64_to_cpu(pte[0]);
- pte[1] = be64_to_cpu(pte[1]);
+ pte[0] = be64_to_cpu((__force __be64)pte[0]);
+ pte[1] = be64_to_cpu((__force __be64)pte[1]);
/* tsl = AVPN */
flags = (tsh & H_BULK_REMOVE_FLAGS) >> 26;
@@ -211,8 +212,8 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
pteg = get_pteg_addr(vcpu, pte_index);
mutex_lock(&vcpu->kvm->arch.hpt_mutex);
copy_from_user(pte, (void __user *)pteg, sizeof(pte));
- pte[0] = be64_to_cpu(pte[0]);
- pte[1] = be64_to_cpu(pte[1]);
+ pte[0] = be64_to_cpu((__force __be64)pte[0]);
+ pte[1] = be64_to_cpu((__force __be64)pte[1]);
ret = H_NOT_FOUND;
if ((pte[0] & HPTE_V_VALID) == 0 ||
@@ -231,8 +232,8 @@ static int kvmppc_h_pr_protect(struct kvm_vcpu *vcpu)
rb = compute_tlbie_rb(v, r, pte_index);
vcpu->arch.mmu.tlbie(vcpu, rb, rb & 1 ? true : false);
- pte[0] = cpu_to_be64(pte[0]);
- pte[1] = cpu_to_be64(pte[1]);
+ pte[0] = (__force u64)cpu_to_be64(pte[0]);
+ pte[1] = (__force u64)cpu_to_be64(pte[1]);
copy_to_user((void __user *)pteg, pte, sizeof(pte));
ret = H_SUCCESS;
@@ -266,6 +267,12 @@ static int kvmppc_h_pr_xics_hcall(struct kvm_vcpu *vcpu, u32 cmd)
int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
{
+ int rc, idx;
+
+ if (cmd <= MAX_HCALL_OPCODE &&
+ !test_bit(cmd/4, vcpu->kvm->arch.enabled_hcalls))
+ return EMULATE_FAIL;
+
switch (cmd) {
case H_ENTER:
return kvmppc_h_pr_enter(vcpu);
@@ -294,8 +301,11 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
break;
case H_RTAS:
if (list_empty(&vcpu->kvm->arch.rtas_tokens))
- return RESUME_HOST;
- if (kvmppc_rtas_hcall(vcpu))
+ break;
+ idx = srcu_read_lock(&vcpu->kvm->srcu);
+ rc = kvmppc_rtas_hcall(vcpu);
+ srcu_read_unlock(&vcpu->kvm->srcu, idx);
+ if (rc)
break;
kvmppc_set_gpr(vcpu, 3, 0);
return EMULATE_DONE;
@@ -303,3 +313,61 @@ int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd)
return EMULATE_FAIL;
}
+
+int kvmppc_hcall_impl_pr(unsigned long cmd)
+{
+ switch (cmd) {
+ case H_ENTER:
+ case H_REMOVE:
+ case H_PROTECT:
+ case H_BULK_REMOVE:
+ case H_PUT_TCE:
+ case H_CEDE:
+#ifdef CONFIG_KVM_XICS
+ case H_XIRR:
+ case H_CPPR:
+ case H_EOI:
+ case H_IPI:
+ case H_IPOLL:
+ case H_XIRR_X:
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * List of hcall numbers to enable by default.
+ * For compatibility with old userspace, we enable by default
+ * all hcalls that were implemented before the hcall-enabling
+ * facility was added. Note this list should not include H_RTAS.
+ */
+static unsigned int default_hcall_list[] = {
+ H_ENTER,
+ H_REMOVE,
+ H_PROTECT,
+ H_BULK_REMOVE,
+ H_PUT_TCE,
+ H_CEDE,
+#ifdef CONFIG_KVM_XICS
+ H_XIRR,
+ H_CPPR,
+ H_EOI,
+ H_IPI,
+ H_IPOLL,
+ H_XIRR_X,
+#endif
+ 0
+};
+
+void kvmppc_pr_init_default_hcalls(struct kvm *kvm)
+{
+ int i;
+ unsigned int hcall;
+
+ for (i = 0; default_hcall_list[i]; ++i) {
+ hcall = default_hcall_list[i];
+ WARN_ON(!kvmppc_hcall_impl_pr(hcall));
+ __set_bit(hcall / 4, kvm->arch.enabled_hcalls);
+ }
+}