diff options
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r-- | arch/s390/kvm/interrupt.c | 30 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 20 | ||||
-rw-r--r-- | arch/s390/kvm/sigp.c | 45 |
3 files changed, 90 insertions, 5 deletions
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c9aeb4b4d0b8..87c16705b381 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c | |||
@@ -38,6 +38,11 @@ static int __interrupt_is_deliverable(struct kvm_vcpu *vcpu, | |||
38 | struct kvm_s390_interrupt_info *inti) | 38 | struct kvm_s390_interrupt_info *inti) |
39 | { | 39 | { |
40 | switch (inti->type) { | 40 | switch (inti->type) { |
41 | case KVM_S390_INT_EXTERNAL_CALL: | ||
42 | if (psw_extint_disabled(vcpu)) | ||
43 | return 0; | ||
44 | if (vcpu->arch.sie_block->gcr[0] & 0x2000ul) | ||
45 | return 1; | ||
41 | case KVM_S390_INT_EMERGENCY: | 46 | case KVM_S390_INT_EMERGENCY: |
42 | if (psw_extint_disabled(vcpu)) | 47 | if (psw_extint_disabled(vcpu)) |
43 | return 0; | 48 | return 0; |
@@ -98,6 +103,7 @@ static void __set_intercept_indicator(struct kvm_vcpu *vcpu, | |||
98 | struct kvm_s390_interrupt_info *inti) | 103 | struct kvm_s390_interrupt_info *inti) |
99 | { | 104 | { |
100 | switch (inti->type) { | 105 | switch (inti->type) { |
106 | case KVM_S390_INT_EXTERNAL_CALL: | ||
101 | case KVM_S390_INT_EMERGENCY: | 107 | case KVM_S390_INT_EMERGENCY: |
102 | case KVM_S390_INT_SERVICE: | 108 | case KVM_S390_INT_SERVICE: |
103 | case KVM_S390_INT_VIRTIO: | 109 | case KVM_S390_INT_VIRTIO: |
@@ -143,6 +149,28 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu, | |||
143 | exception = 1; | 149 | exception = 1; |
144 | break; | 150 | break; |
145 | 151 | ||
152 | case KVM_S390_INT_EXTERNAL_CALL: | ||
153 | VCPU_EVENT(vcpu, 4, "%s", "interrupt: sigp ext call"); | ||
154 | vcpu->stat.deliver_external_call++; | ||
155 | rc = put_guest_u16(vcpu, __LC_EXT_INT_CODE, 0x1202); | ||
156 | if (rc == -EFAULT) | ||
157 | exception = 1; | ||
158 | |||
159 | rc = put_guest_u16(vcpu, __LC_CPU_ADDRESS, inti->extcall.code); | ||
160 | if (rc == -EFAULT) | ||
161 | exception = 1; | ||
162 | |||
163 | rc = copy_to_guest(vcpu, __LC_EXT_OLD_PSW, | ||
164 | &vcpu->arch.sie_block->gpsw, sizeof(psw_t)); | ||
165 | if (rc == -EFAULT) | ||
166 | exception = 1; | ||
167 | |||
168 | rc = copy_from_guest(vcpu, &vcpu->arch.sie_block->gpsw, | ||
169 | __LC_EXT_NEW_PSW, sizeof(psw_t)); | ||
170 | if (rc == -EFAULT) | ||
171 | exception = 1; | ||
172 | break; | ||
173 | |||
146 | case KVM_S390_INT_SERVICE: | 174 | case KVM_S390_INT_SERVICE: |
147 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", | 175 | VCPU_EVENT(vcpu, 4, "interrupt: sclp parm:%x", |
148 | inti->ext.ext_params); | 176 | inti->ext.ext_params); |
@@ -522,6 +550,7 @@ int kvm_s390_inject_vm(struct kvm *kvm, | |||
522 | break; | 550 | break; |
523 | case KVM_S390_PROGRAM_INT: | 551 | case KVM_S390_PROGRAM_INT: |
524 | case KVM_S390_SIGP_STOP: | 552 | case KVM_S390_SIGP_STOP: |
553 | case KVM_S390_INT_EXTERNAL_CALL: | ||
525 | case KVM_S390_INT_EMERGENCY: | 554 | case KVM_S390_INT_EMERGENCY: |
526 | default: | 555 | default: |
527 | kfree(inti); | 556 | kfree(inti); |
@@ -581,6 +610,7 @@ int kvm_s390_inject_vcpu(struct kvm_vcpu *vcpu, | |||
581 | break; | 610 | break; |
582 | case KVM_S390_SIGP_STOP: | 611 | case KVM_S390_SIGP_STOP: |
583 | case KVM_S390_RESTART: | 612 | case KVM_S390_RESTART: |
613 | case KVM_S390_INT_EXTERNAL_CALL: | ||
584 | case KVM_S390_INT_EMERGENCY: | 614 | case KVM_S390_INT_EMERGENCY: |
585 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); | 615 | VCPU_EVENT(vcpu, 3, "inject: type %x", s390int->type); |
586 | inti->type = s390int->type; | 616 | inti->type = s390int->type; |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 189d6bdcac08..0bd3bea1e4cd 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -46,6 +46,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
46 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, | 46 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, |
47 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | 47 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, |
48 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | 48 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, |
49 | { "deliver_external_call", VCPU_STAT(deliver_external_call) }, | ||
49 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | 50 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, |
50 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, | 51 | { "deliver_virtio_interrupt", VCPU_STAT(deliver_virtio_interrupt) }, |
51 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, | 52 | { "deliver_stop_signal", VCPU_STAT(deliver_stop_signal) }, |
@@ -64,6 +65,7 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
64 | { "instruction_stfl", VCPU_STAT(instruction_stfl) }, | 65 | { "instruction_stfl", VCPU_STAT(instruction_stfl) }, |
65 | { "instruction_tprot", VCPU_STAT(instruction_tprot) }, | 66 | { "instruction_tprot", VCPU_STAT(instruction_tprot) }, |
66 | { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, | 67 | { "instruction_sigp_sense", VCPU_STAT(instruction_sigp_sense) }, |
68 | { "instruction_sigp_external_call", VCPU_STAT(instruction_sigp_external_call) }, | ||
67 | { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, | 69 | { "instruction_sigp_emergency", VCPU_STAT(instruction_sigp_emergency) }, |
68 | { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, | 70 | { "instruction_sigp_stop", VCPU_STAT(instruction_sigp_stop) }, |
69 | { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, | 71 | { "instruction_sigp_set_arch", VCPU_STAT(instruction_sigp_arch) }, |
@@ -176,6 +178,8 @@ int kvm_arch_init_vm(struct kvm *kvm) | |||
176 | if (rc) | 178 | if (rc) |
177 | goto out_err; | 179 | goto out_err; |
178 | 180 | ||
181 | rc = -ENOMEM; | ||
182 | |||
179 | kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL); | 183 | kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL); |
180 | if (!kvm->arch.sca) | 184 | if (!kvm->arch.sca) |
181 | goto out_err; | 185 | goto out_err; |
@@ -313,11 +317,17 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | |||
313 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, | 317 | struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, |
314 | unsigned int id) | 318 | unsigned int id) |
315 | { | 319 | { |
316 | struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); | 320 | struct kvm_vcpu *vcpu; |
317 | int rc = -ENOMEM; | 321 | int rc = -EINVAL; |
322 | |||
323 | if (id >= KVM_MAX_VCPUS) | ||
324 | goto out; | ||
318 | 325 | ||
326 | rc = -ENOMEM; | ||
327 | |||
328 | vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL); | ||
319 | if (!vcpu) | 329 | if (!vcpu) |
320 | goto out_nomem; | 330 | goto out; |
321 | 331 | ||
322 | vcpu->arch.sie_block = (struct kvm_s390_sie_block *) | 332 | vcpu->arch.sie_block = (struct kvm_s390_sie_block *) |
323 | get_zeroed_page(GFP_KERNEL); | 333 | get_zeroed_page(GFP_KERNEL); |
@@ -353,7 +363,7 @@ out_free_sie_block: | |||
353 | free_page((unsigned long)(vcpu->arch.sie_block)); | 363 | free_page((unsigned long)(vcpu->arch.sie_block)); |
354 | out_free_cpu: | 364 | out_free_cpu: |
355 | kfree(vcpu); | 365 | kfree(vcpu); |
356 | out_nomem: | 366 | out: |
357 | return ERR_PTR(rc); | 367 | return ERR_PTR(rc); |
358 | } | 368 | } |
359 | 369 | ||
@@ -387,6 +397,7 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | |||
387 | { | 397 | { |
388 | memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs)); | 398 | memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs)); |
389 | memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs)); | 399 | memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs)); |
400 | restore_access_regs(vcpu->arch.guest_acrs); | ||
390 | return 0; | 401 | return 0; |
391 | } | 402 | } |
392 | 403 | ||
@@ -402,6 +413,7 @@ int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | |||
402 | { | 413 | { |
403 | memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); | 414 | memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs)); |
404 | vcpu->arch.guest_fpregs.fpc = fpu->fpc; | 415 | vcpu->arch.guest_fpregs.fpc = fpu->fpc; |
416 | restore_fp_regs(&vcpu->arch.guest_fpregs); | ||
405 | return 0; | 417 | return 0; |
406 | } | 418 | } |
407 | 419 | ||
diff --git a/arch/s390/kvm/sigp.c b/arch/s390/kvm/sigp.c index d6a50c1fb2e6..f815118835f3 100644 --- a/arch/s390/kvm/sigp.c +++ b/arch/s390/kvm/sigp.c | |||
@@ -87,6 +87,7 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
87 | return -ENOMEM; | 87 | return -ENOMEM; |
88 | 88 | ||
89 | inti->type = KVM_S390_INT_EMERGENCY; | 89 | inti->type = KVM_S390_INT_EMERGENCY; |
90 | inti->emerg.code = vcpu->vcpu_id; | ||
90 | 91 | ||
91 | spin_lock(&fi->lock); | 92 | spin_lock(&fi->lock); |
92 | li = fi->local_int[cpu_addr]; | 93 | li = fi->local_int[cpu_addr]; |
@@ -103,9 +104,47 @@ static int __sigp_emergency(struct kvm_vcpu *vcpu, u16 cpu_addr) | |||
103 | wake_up_interruptible(&li->wq); | 104 | wake_up_interruptible(&li->wq); |
104 | spin_unlock_bh(&li->lock); | 105 | spin_unlock_bh(&li->lock); |
105 | rc = 0; /* order accepted */ | 106 | rc = 0; /* order accepted */ |
107 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
108 | unlock: | ||
109 | spin_unlock(&fi->lock); | ||
110 | return rc; | ||
111 | } | ||
112 | |||
113 | static int __sigp_external_call(struct kvm_vcpu *vcpu, u16 cpu_addr) | ||
114 | { | ||
115 | struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int; | ||
116 | struct kvm_s390_local_interrupt *li; | ||
117 | struct kvm_s390_interrupt_info *inti; | ||
118 | int rc; | ||
119 | |||
120 | if (cpu_addr >= KVM_MAX_VCPUS) | ||
121 | return 3; /* not operational */ | ||
122 | |||
123 | inti = kzalloc(sizeof(*inti), GFP_KERNEL); | ||
124 | if (!inti) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | inti->type = KVM_S390_INT_EXTERNAL_CALL; | ||
128 | inti->extcall.code = vcpu->vcpu_id; | ||
129 | |||
130 | spin_lock(&fi->lock); | ||
131 | li = fi->local_int[cpu_addr]; | ||
132 | if (li == NULL) { | ||
133 | rc = 3; /* not operational */ | ||
134 | kfree(inti); | ||
135 | goto unlock; | ||
136 | } | ||
137 | spin_lock_bh(&li->lock); | ||
138 | list_add_tail(&inti->list, &li->list); | ||
139 | atomic_set(&li->active, 1); | ||
140 | atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); | ||
141 | if (waitqueue_active(&li->wq)) | ||
142 | wake_up_interruptible(&li->wq); | ||
143 | spin_unlock_bh(&li->lock); | ||
144 | rc = 0; /* order accepted */ | ||
145 | VCPU_EVENT(vcpu, 4, "sent sigp ext call to cpu %x", cpu_addr); | ||
106 | unlock: | 146 | unlock: |
107 | spin_unlock(&fi->lock); | 147 | spin_unlock(&fi->lock); |
108 | VCPU_EVENT(vcpu, 4, "sent sigp emerg to cpu %x", cpu_addr); | ||
109 | return rc; | 148 | return rc; |
110 | } | 149 | } |
111 | 150 | ||
@@ -267,6 +306,10 @@ int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu) | |||
267 | rc = __sigp_sense(vcpu, cpu_addr, | 306 | rc = __sigp_sense(vcpu, cpu_addr, |
268 | &vcpu->arch.guest_gprs[r1]); | 307 | &vcpu->arch.guest_gprs[r1]); |
269 | break; | 308 | break; |
309 | case SIGP_EXTERNAL_CALL: | ||
310 | vcpu->stat.instruction_sigp_external_call++; | ||
311 | rc = __sigp_external_call(vcpu, cpu_addr); | ||
312 | break; | ||
270 | case SIGP_EMERGENCY: | 313 | case SIGP_EMERGENCY: |
271 | vcpu->stat.instruction_sigp_emergency++; | 314 | vcpu->stat.instruction_sigp_emergency++; |
272 | rc = __sigp_emergency(vcpu, cpu_addr); | 315 | rc = __sigp_emergency(vcpu, cpu_addr); |