Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: PPC: Book3S HV: Handle hypercalls correctly when nested

When we are running as a nested hypervisor, we use a hypercall to
enter the guest rather than code in book3s_hv_rmhandlers.S. This means
that the hypercall handlers listed in hcall_real_table never get called.
There are some hypercalls that are handled there and not in
kvmppc_pseries_do_hcall(), which therefore won't get processed for
a nested guest.

To fix this, we add cases to kvmppc_pseries_do_hcall() to handle those
hypercalls, with the following exceptions:

- The HPT hypercalls (H_ENTER, H_REMOVE, etc.) are not handled because
we only support radix mode for nested guests.

- H_CEDE has to be handled specially because the cede logic in
kvmhv_run_single_vcpu assumes that it has been processed by the time
that kvmhv_p9_guest_entry() returns. Therefore we put a special
case for H_CEDE in kvmhv_p9_guest_entry().

For the XICS hypercalls, if real-mode processing is enabled, then the
virtual-mode handlers assume that they are being called only to finish
up the operation. Therefore we turn off the real-mode flag in the XICS
code when running as a nested hypervisor.

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

authored by

Paul Mackerras and committed by
Michael Ellerman
4bad7779 f3c18e93

+51 -1
+4
arch/powerpc/include/asm/asm-prototypes.h
··· 167 167 168 168 int __kvmhv_vcpu_entry_p9(struct kvm_vcpu *vcpu); 169 169 170 + long kvmppc_h_set_dabr(struct kvm_vcpu *vcpu, unsigned long dabr); 171 + long kvmppc_h_set_xdabr(struct kvm_vcpu *vcpu, unsigned long dabr, 172 + unsigned long dabrx); 173 + 170 174 #endif /* _ASM_POWERPC_ASM_PROTOTYPES_H */
+43
arch/powerpc/kvm/book3s_hv.c
··· 50 50 #include <asm/reg.h> 51 51 #include <asm/ppc-opcode.h> 52 52 #include <asm/asm-prototypes.h> 53 + #include <asm/archrandom.h> 53 54 #include <asm/debug.h> 54 55 #include <asm/disassemble.h> 55 56 #include <asm/cputable.h> ··· 916 915 break; 917 916 } 918 917 return RESUME_HOST; 918 + case H_SET_DABR: 919 + ret = kvmppc_h_set_dabr(vcpu, kvmppc_get_gpr(vcpu, 4)); 920 + break; 921 + case H_SET_XDABR: 922 + ret = kvmppc_h_set_xdabr(vcpu, kvmppc_get_gpr(vcpu, 4), 923 + kvmppc_get_gpr(vcpu, 5)); 924 + break; 925 + case H_GET_TCE: 926 + ret = kvmppc_h_get_tce(vcpu, kvmppc_get_gpr(vcpu, 4), 927 + kvmppc_get_gpr(vcpu, 5)); 928 + if (ret == H_TOO_HARD) 929 + return RESUME_HOST; 930 + break; 919 931 case H_PUT_TCE: 920 932 ret = kvmppc_h_put_tce(vcpu, kvmppc_get_gpr(vcpu, 4), 921 933 kvmppc_get_gpr(vcpu, 5), ··· 951 937 kvmppc_get_gpr(vcpu, 7)); 952 938 if (ret == H_TOO_HARD) 953 939 return RESUME_HOST; 940 + break; 941 + case H_RANDOM: 942 + if (!powernv_get_random_long(&vcpu->arch.regs.gpr[4])) 943 + ret = H_HARDWARE; 954 944 break; 955 945 956 946 case H_SET_PARTITION_TABLE: ··· 982 964 kvmppc_set_gpr(vcpu, 3, ret); 983 965 vcpu->arch.hcall_needed = 0; 984 966 return RESUME_GUEST; 967 + } 968 + 969 + /* 970 + * Handle H_CEDE in the nested virtualization case where we haven't 971 + * called the real-mode hcall handlers in book3s_hv_rmhandlers.S. 972 + * This has to be done early, not in kvmppc_pseries_do_hcall(), so 973 + * that the cede logic in kvmppc_run_single_vcpu() works properly. 974 + */ 975 + static void kvmppc_nested_cede(struct kvm_vcpu *vcpu) 976 + { 977 + vcpu->arch.shregs.msr |= MSR_EE; 978 + vcpu->arch.ceded = 1; 979 + smp_mb(); 980 + if (vcpu->arch.prodded) { 981 + vcpu->arch.prodded = 0; 982 + smp_mb(); 983 + vcpu->arch.ceded = 0; 984 + } 985 985 } 986 986 987 987 static int kvmppc_hcall_impl_hv(unsigned long cmd) ··· 3460 3424 vcpu->arch.shregs.msr = vcpu->arch.regs.msr; 3461 3425 vcpu->arch.shregs.dar = mfspr(SPRN_DAR); 3462 3426 vcpu->arch.shregs.dsisr = mfspr(SPRN_DSISR); 3427 + 3428 + /* H_CEDE has to be handled now, not later */ 3429 + if (trap == BOOK3S_INTERRUPT_SYSCALL && !vcpu->arch.nested && 3430 + kvmppc_get_gpr(vcpu, 3) == H_CEDE) { 3431 + kvmppc_nested_cede(vcpu); 3432 + trap = 0; 3433 + } 3463 3434 } else { 3464 3435 trap = kvmhv_load_hv_regs_and_go(vcpu, time_limit, lpcr); 3465 3436 }
+2
arch/powerpc/kvm/book3s_hv_rmhandlers.S
··· 2466 2466 hcall_real_table_end: 2467 2467 2468 2468 _GLOBAL(kvmppc_h_set_xdabr) 2469 + EXPORT_SYMBOL_GPL(kvmppc_h_set_xdabr) 2469 2470 andi. r0, r5, DABRX_USER | DABRX_KERNEL 2470 2471 beq 6f 2471 2472 li r0, DABRX_USER | DABRX_KERNEL | DABRX_BTI ··· 2476 2475 blr 2477 2476 2478 2477 _GLOBAL(kvmppc_h_set_dabr) 2478 + EXPORT_SYMBOL_GPL(kvmppc_h_set_dabr) 2479 2479 li r5, DABRX_USER | DABRX_KERNEL 2480 2480 3: 2481 2481 BEGIN_FTR_SECTION
+2 -1
arch/powerpc/kvm/book3s_xics.c
··· 1390 1390 } 1391 1391 1392 1392 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 1393 - if (cpu_has_feature(CPU_FTR_ARCH_206)) { 1393 + if (cpu_has_feature(CPU_FTR_ARCH_206) && 1394 + cpu_has_feature(CPU_FTR_HVMODE)) { 1394 1395 /* Enable real mode support */ 1395 1396 xics->real_mode = ENABLE_REALMODE; 1396 1397 xics->real_mode_dbg = DEBUG_REALMODE;