Commit ad0a048b096ac819f28667602285453468a8d8f9

Authored by Alexander Graf
Committed by Avi Kivity
1 parent 71fbfd5f38

KVM: PPC: Add OSI hypercall interface

MOL uses its own hypercall interface to call back into userspace when
the guest wants to do something.

So let's implement that as an exit reason, specify it with a CAP and
only really use it when userspace wants us to.

The only user of it so far is MOL.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>

Showing 6 changed files with 59 additions and 9 deletions Side-by-side Diff

Documentation/kvm/api.txt
... ... @@ -958,9 +958,9 @@
958 958 by kvm. The 'data' member contains the written data if 'is_write' is
959 959 true, and should be filled by application code otherwise.
960 960  
961   -NOTE: For KVM_EXIT_IO and KVM_EXIT_MMIO, the corresponding operations
962   -are complete (and guest state is consistent) only after userspace has
963   -re-entered the kernel with KVM_RUN. The kernel side will first finish
  961 +NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding
  962 +operations are complete (and guest state is consistent) only after userspace
  963 +has re-entered the kernel with KVM_RUN. The kernel side will first finish
964 964 incomplete operations and then check for pending signals. Userspace
965 965 can re-enter the guest with an unmasked signal pending to complete
966 966 pending operations.
... ... @@ -1014,6 +1014,19 @@
1014 1014 } dcr;
1015 1015  
1016 1016 powerpc specific.
  1017 +
  1018 + /* KVM_EXIT_OSI */
  1019 + struct {
  1020 + __u64 gprs[32];
  1021 + } osi;
  1022 +
  1023 +MOL uses a special hypercall interface it calls 'OSI'. To enable it, we catch
  1024 +hypercalls and exit with this exit struct that contains all the guest gprs.
  1025 +
  1026 +If exit_reason is KVM_EXIT_OSI, then the vcpu has triggered such a hypercall.
  1027 +Userspace can now handle the hypercall and when it's done modify the gprs as
  1028 +necessary. Upon guest entry all guest GPRs will then be replaced by the values
  1029 +in this struct.
1017 1030  
1018 1031 /* Fix the size of the union. */
1019 1032 char padding[256];
arch/powerpc/include/asm/kvm_book3s.h
... ... @@ -148,6 +148,11 @@
148 148  
149 149 extern void kvm_return_point(void);
150 150  
  151 +/* Magic register values loaded into r3 and r4 before the 'sc' assembly
  152 + * instruction for the OSI hypercalls */
  153 +#define OSI_SC_MAGIC_R3 0x113724FA
  154 +#define OSI_SC_MAGIC_R4 0x77810F9B
  155 +
151 156 #define INS_DCBZ 0x7c0007ec
152 157  
153 158 #endif /* __ASM_KVM_BOOK3S_H__ */
arch/powerpc/include/asm/kvm_host.h
... ... @@ -273,6 +273,8 @@
273 273 u8 mmio_sign_extend;
274 274 u8 dcr_needed;
275 275 u8 dcr_is_write;
  276 + u8 osi_needed;
  277 + u8 osi_enabled;
276 278  
277 279 u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */
278 280  
arch/powerpc/kvm/book3s.c
... ... @@ -872,12 +872,24 @@
872 872 break;
873 873 }
874 874 case BOOK3S_INTERRUPT_SYSCALL:
875   -#ifdef EXIT_DEBUG
876   - printk(KERN_INFO "Syscall Nr %d\n", (int)kvmppc_get_gpr(vcpu, 0));
877   -#endif
878   - vcpu->stat.syscall_exits++;
879   - kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
880   - r = RESUME_GUEST;
  875 + // XXX make user settable
  876 + if (vcpu->arch.osi_enabled &&
  877 + (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) &&
  878 + (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) {
  879 + u64 *gprs = run->osi.gprs;
  880 + int i;
  881 +
  882 + run->exit_reason = KVM_EXIT_OSI;
  883 + for (i = 0; i < 32; i++)
  884 + gprs[i] = kvmppc_get_gpr(vcpu, i);
  885 + vcpu->arch.osi_needed = 1;
  886 + r = RESUME_HOST_NV;
  887 +
  888 + } else {
  889 + vcpu->stat.syscall_exits++;
  890 + kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
  891 + r = RESUME_GUEST;
  892 + }
881 893 break;
882 894 case BOOK3S_INTERRUPT_FP_UNAVAIL:
883 895 case BOOK3S_INTERRUPT_ALTIVEC:
arch/powerpc/kvm/powerpc.c
... ... @@ -151,6 +151,7 @@
151 151 case KVM_CAP_PPC_PAIRED_SINGLES:
152 152 case KVM_CAP_PPC_UNSET_IRQ:
153 153 case KVM_CAP_ENABLE_CAP:
  154 + case KVM_CAP_PPC_OSI:
154 155 r = 1;
155 156 break;
156 157 case KVM_CAP_COALESCED_MMIO:
... ... @@ -433,6 +434,13 @@
433 434 if (!vcpu->arch.dcr_is_write)
434 435 kvmppc_complete_dcr_load(vcpu, run);
435 436 vcpu->arch.dcr_needed = 0;
  437 + } else if (vcpu->arch.osi_needed) {
  438 + u64 *gprs = run->osi.gprs;
  439 + int i;
  440 +
  441 + for (i = 0; i < 32; i++)
  442 + kvmppc_set_gpr(vcpu, i, gprs[i]);
  443 + vcpu->arch.osi_needed = 0;
436 444 }
437 445  
438 446 kvmppc_core_deliver_interrupts(vcpu);
... ... @@ -475,6 +483,10 @@
475 483 return -EINVAL;
476 484  
477 485 switch (cap->cap) {
  486 + case KVM_CAP_PPC_OSI:
  487 + r = 0;
  488 + vcpu->arch.osi_enabled = true;
  489 + break;
478 490 default:
479 491 r = -EINVAL;
480 492 break;
... ... @@ -160,6 +160,7 @@
160 160 #define KVM_EXIT_DCR 15
161 161 #define KVM_EXIT_NMI 16
162 162 #define KVM_EXIT_INTERNAL_ERROR 17
  163 +#define KVM_EXIT_OSI 18
163 164  
164 165 /* For KVM_EXIT_INTERNAL_ERROR */
165 166 #define KVM_INTERNAL_ERROR_EMULATION 1
... ... @@ -259,6 +260,10 @@
259 260 __u32 ndata;
260 261 __u64 data[16];
261 262 } internal;
  263 + /* KVM_EXIT_OSI */
  264 + struct {
  265 + __u64 gprs[32];
  266 + } osi;
262 267 /* Fix the size of the union. */
263 268 char padding[256];
264 269 };
... ... @@ -516,6 +521,7 @@
516 521 #define KVM_CAP_DEBUGREGS 50
517 522 #endif
518 523 #define KVM_CAP_X86_ROBUST_SINGLESTEP 51
  524 +#define KVM_CAP_PPC_OSI 52
519 525 #define KVM_CAP_PPC_UNSET_IRQ 53
520 526 #define KVM_CAP_ENABLE_CAP 54
521 527