diff options
author | Alexander Graf <agraf@suse.de> | 2010-03-24 16:48:30 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:17:10 -0400 |
commit | ad0a048b096ac819f28667602285453468a8d8f9 (patch) | |
tree | 491128ccab48eb277a5cf5919a798b0507da9859 | |
parent | 71fbfd5f38f73515f1516a68fbe04dba198b70f0 (diff) |
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>
-rw-r--r-- | Documentation/kvm/api.txt | 19 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_book3s.h | 5 | ||||
-rw-r--r-- | arch/powerpc/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/powerpc/kvm/book3s.c | 24 | ||||
-rw-r--r-- | arch/powerpc/kvm/powerpc.c | 12 | ||||
-rw-r--r-- | include/linux/kvm.h | 6 |
6 files changed, 59 insertions, 9 deletions
diff --git a/Documentation/kvm/api.txt b/Documentation/kvm/api.txt index f9724dc8d079..6f362356e738 100644 --- a/Documentation/kvm/api.txt +++ b/Documentation/kvm/api.txt | |||
@@ -958,9 +958,9 @@ executed a memory-mapped I/O instruction which could not be satisfied | |||
958 | by kvm. The 'data' member contains the written data if 'is_write' is | 958 | by kvm. The 'data' member contains the written data if 'is_write' is |
959 | true, and should be filled by application code otherwise. | 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 | 961 | NOTE: For KVM_EXIT_IO, KVM_EXIT_MMIO and KVM_EXIT_OSI, the corresponding |
962 | are complete (and guest state is consistent) only after userspace has | 962 | operations are complete (and guest state is consistent) only after userspace |
963 | re-entered the kernel with KVM_RUN. The kernel side will first finish | 963 | has re-entered the kernel with KVM_RUN. The kernel side will first finish |
964 | incomplete operations and then check for pending signals. Userspace | 964 | incomplete operations and then check for pending signals. Userspace |
965 | can re-enter the guest with an unmasked signal pending to complete | 965 | can re-enter the guest with an unmasked signal pending to complete |
966 | pending operations. | 966 | pending operations. |
@@ -1015,6 +1015,19 @@ s390 specific. | |||
1015 | 1015 | ||
1016 | powerpc specific. | 1016 | powerpc specific. |
1017 | 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. | ||
1030 | |||
1018 | /* Fix the size of the union. */ | 1031 | /* Fix the size of the union. */ |
1019 | char padding[256]; | 1032 | char padding[256]; |
1020 | }; | 1033 | }; |
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h index bea76371dbe1..7e243b2cac72 100644 --- a/arch/powerpc/include/asm/kvm_book3s.h +++ b/arch/powerpc/include/asm/kvm_book3s.h | |||
@@ -148,6 +148,11 @@ static inline ulong dsisr(void) | |||
148 | 148 | ||
149 | extern void kvm_return_point(void); | 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 | #define INS_DCBZ 0x7c0007ec | 156 | #define INS_DCBZ 0x7c0007ec |
152 | 157 | ||
153 | #endif /* __ASM_KVM_BOOK3S_H__ */ | 158 | #endif /* __ASM_KVM_BOOK3S_H__ */ |
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index 0ebda67ad6a8..486f1cafd5f7 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -273,6 +273,8 @@ struct kvm_vcpu_arch { | |||
273 | u8 mmio_sign_extend; | 273 | u8 mmio_sign_extend; |
274 | u8 dcr_needed; | 274 | u8 dcr_needed; |
275 | u8 dcr_is_write; | 275 | u8 dcr_is_write; |
276 | u8 osi_needed; | ||
277 | u8 osi_enabled; | ||
276 | 278 | ||
277 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ | 279 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ |
278 | 280 | ||
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index de12202fe1c6..7696d0f547e3 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c | |||
@@ -872,12 +872,24 @@ program_interrupt: | |||
872 | break; | 872 | break; |
873 | } | 873 | } |
874 | case BOOK3S_INTERRUPT_SYSCALL: | 874 | case BOOK3S_INTERRUPT_SYSCALL: |
875 | #ifdef EXIT_DEBUG | 875 | // XXX make user settable |
876 | printk(KERN_INFO "Syscall Nr %d\n", (int)kvmppc_get_gpr(vcpu, 0)); | 876 | if (vcpu->arch.osi_enabled && |
877 | #endif | 877 | (((u32)kvmppc_get_gpr(vcpu, 3)) == OSI_SC_MAGIC_R3) && |
878 | vcpu->stat.syscall_exits++; | 878 | (((u32)kvmppc_get_gpr(vcpu, 4)) == OSI_SC_MAGIC_R4)) { |
879 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | 879 | u64 *gprs = run->osi.gprs; |
880 | r = RESUME_GUEST; | 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 | break; | 893 | break; |
882 | case BOOK3S_INTERRUPT_FP_UNAVAIL: | 894 | case BOOK3S_INTERRUPT_FP_UNAVAIL: |
883 | case BOOK3S_INTERRUPT_ALTIVEC: | 895 | case BOOK3S_INTERRUPT_ALTIVEC: |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 646bfd256e5d..9a4dd8146d39 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -151,6 +151,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
151 | case KVM_CAP_PPC_PAIRED_SINGLES: | 151 | case KVM_CAP_PPC_PAIRED_SINGLES: |
152 | case KVM_CAP_PPC_UNSET_IRQ: | 152 | case KVM_CAP_PPC_UNSET_IRQ: |
153 | case KVM_CAP_ENABLE_CAP: | 153 | case KVM_CAP_ENABLE_CAP: |
154 | case KVM_CAP_PPC_OSI: | ||
154 | r = 1; | 155 | r = 1; |
155 | break; | 156 | break; |
156 | case KVM_CAP_COALESCED_MMIO: | 157 | case KVM_CAP_COALESCED_MMIO: |
@@ -433,6 +434,13 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) | |||
433 | if (!vcpu->arch.dcr_is_write) | 434 | if (!vcpu->arch.dcr_is_write) |
434 | kvmppc_complete_dcr_load(vcpu, run); | 435 | kvmppc_complete_dcr_load(vcpu, run); |
435 | vcpu->arch.dcr_needed = 0; | 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 | kvmppc_core_deliver_interrupts(vcpu); | 446 | kvmppc_core_deliver_interrupts(vcpu); |
@@ -475,6 +483,10 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu, | |||
475 | return -EINVAL; | 483 | return -EINVAL; |
476 | 484 | ||
477 | switch (cap->cap) { | 485 | switch (cap->cap) { |
486 | case KVM_CAP_PPC_OSI: | ||
487 | r = 0; | ||
488 | vcpu->arch.osi_enabled = true; | ||
489 | break; | ||
478 | default: | 490 | default: |
479 | r = -EINVAL; | 491 | r = -EINVAL; |
480 | break; | 492 | break; |
diff --git a/include/linux/kvm.h b/include/linux/kvm.h index ecb68e433558..23ea02253900 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h | |||
@@ -160,6 +160,7 @@ struct kvm_pit_config { | |||
160 | #define KVM_EXIT_DCR 15 | 160 | #define KVM_EXIT_DCR 15 |
161 | #define KVM_EXIT_NMI 16 | 161 | #define KVM_EXIT_NMI 16 |
162 | #define KVM_EXIT_INTERNAL_ERROR 17 | 162 | #define KVM_EXIT_INTERNAL_ERROR 17 |
163 | #define KVM_EXIT_OSI 18 | ||
163 | 164 | ||
164 | /* For KVM_EXIT_INTERNAL_ERROR */ | 165 | /* For KVM_EXIT_INTERNAL_ERROR */ |
165 | #define KVM_INTERNAL_ERROR_EMULATION 1 | 166 | #define KVM_INTERNAL_ERROR_EMULATION 1 |
@@ -259,6 +260,10 @@ struct kvm_run { | |||
259 | __u32 ndata; | 260 | __u32 ndata; |
260 | __u64 data[16]; | 261 | __u64 data[16]; |
261 | } internal; | 262 | } internal; |
263 | /* KVM_EXIT_OSI */ | ||
264 | struct { | ||
265 | __u64 gprs[32]; | ||
266 | } osi; | ||
262 | /* Fix the size of the union. */ | 267 | /* Fix the size of the union. */ |
263 | char padding[256]; | 268 | char padding[256]; |
264 | }; | 269 | }; |
@@ -516,6 +521,7 @@ struct kvm_enable_cap { | |||
516 | #define KVM_CAP_DEBUGREGS 50 | 521 | #define KVM_CAP_DEBUGREGS 50 |
517 | #endif | 522 | #endif |
518 | #define KVM_CAP_X86_ROBUST_SINGLESTEP 51 | 523 | #define KVM_CAP_X86_ROBUST_SINGLESTEP 51 |
524 | #define KVM_CAP_PPC_OSI 52 | ||
519 | #define KVM_CAP_PPC_UNSET_IRQ 53 | 525 | #define KVM_CAP_PPC_UNSET_IRQ 53 |
520 | #define KVM_CAP_ENABLE_CAP 54 | 526 | #define KVM_CAP_ENABLE_CAP 54 |
521 | 527 | ||