]> err.no Git - linux-2.6/blob - arch/s390/kvm/kvm-s390.c
KVM: s390: sie intercept handling
[linux-2.6] / arch / s390 / kvm / kvm-s390.c
1 /*
2  * s390host.c --  hosting zSeries kernel virtual machines
3  *
4  * Copyright IBM Corp. 2008
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License (version 2 only)
8  * as published by the Free Software Foundation.
9  *
10  *    Author(s): Carsten Otte <cotte@de.ibm.com>
11  *               Christian Borntraeger <borntraeger@de.ibm.com>
12  *               Heiko Carstens <heiko.carstens@de.ibm.com>
13  */
14
15 #include <linux/compiler.h>
16 #include <linux/err.h>
17 #include <linux/fs.h>
18 #include <linux/init.h>
19 #include <linux/kvm.h>
20 #include <linux/kvm_host.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
23 #include <asm/lowcore.h>
24 #include <asm/pgtable.h>
25
26 #include "kvm-s390.h"
27 #include "gaccess.h"
28
29 #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU
30
31 struct kvm_stats_debugfs_item debugfs_entries[] = {
32         { "userspace_handled", VCPU_STAT(exit_userspace) },
33         { "exit_validity", VCPU_STAT(exit_validity) },
34         { "exit_stop_request", VCPU_STAT(exit_stop_request) },
35         { "exit_external_request", VCPU_STAT(exit_external_request) },
36         { "exit_external_interrupt", VCPU_STAT(exit_external_interrupt) },
37         { NULL }
38 };
39
40
41 /* Section: not file related */
42 void kvm_arch_hardware_enable(void *garbage)
43 {
44         /* every s390 is virtualization enabled ;-) */
45 }
46
47 void kvm_arch_hardware_disable(void *garbage)
48 {
49 }
50
51 void decache_vcpus_on_cpu(int cpu)
52 {
53 }
54
55 int kvm_arch_hardware_setup(void)
56 {
57         return 0;
58 }
59
60 void kvm_arch_hardware_unsetup(void)
61 {
62 }
63
64 void kvm_arch_check_processor_compat(void *rtn)
65 {
66 }
67
68 int kvm_arch_init(void *opaque)
69 {
70         return 0;
71 }
72
73 void kvm_arch_exit(void)
74 {
75 }
76
77 /* Section: device related */
78 long kvm_arch_dev_ioctl(struct file *filp,
79                         unsigned int ioctl, unsigned long arg)
80 {
81         if (ioctl == KVM_S390_ENABLE_SIE)
82                 return s390_enable_sie();
83         return -EINVAL;
84 }
85
86 int kvm_dev_ioctl_check_extension(long ext)
87 {
88         return 0;
89 }
90
91 /* Section: vm related */
92 /*
93  * Get (and clear) the dirty memory log for a memory slot.
94  */
95 int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm,
96                                struct kvm_dirty_log *log)
97 {
98         return 0;
99 }
100
101 long kvm_arch_vm_ioctl(struct file *filp,
102                        unsigned int ioctl, unsigned long arg)
103 {
104         struct kvm *kvm = filp->private_data;
105         void __user *argp = (void __user *)arg;
106         int r;
107
108         switch (ioctl) {
109         default:
110                 r = -EINVAL;
111         }
112
113         return r;
114 }
115
116 struct kvm *kvm_arch_create_vm(void)
117 {
118         struct kvm *kvm;
119         int rc;
120         char debug_name[16];
121
122         rc = s390_enable_sie();
123         if (rc)
124                 goto out_nokvm;
125
126         rc = -ENOMEM;
127         kvm = kzalloc(sizeof(struct kvm), GFP_KERNEL);
128         if (!kvm)
129                 goto out_nokvm;
130
131         kvm->arch.sca = (struct sca_block *) get_zeroed_page(GFP_KERNEL);
132         if (!kvm->arch.sca)
133                 goto out_nosca;
134
135         sprintf(debug_name, "kvm-%u", current->pid);
136
137         kvm->arch.dbf = debug_register(debug_name, 8, 2, 8 * sizeof(long));
138         if (!kvm->arch.dbf)
139                 goto out_nodbf;
140
141         debug_register_view(kvm->arch.dbf, &debug_sprintf_view);
142         VM_EVENT(kvm, 3, "%s", "vm created");
143
144         try_module_get(THIS_MODULE);
145
146         return kvm;
147 out_nodbf:
148         free_page((unsigned long)(kvm->arch.sca));
149 out_nosca:
150         kfree(kvm);
151 out_nokvm:
152         return ERR_PTR(rc);
153 }
154
155 void kvm_arch_destroy_vm(struct kvm *kvm)
156 {
157         debug_unregister(kvm->arch.dbf);
158         free_page((unsigned long)(kvm->arch.sca));
159         kfree(kvm);
160         module_put(THIS_MODULE);
161 }
162
163 /* Section: vcpu related */
164 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
165 {
166         return 0;
167 }
168
169 void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu)
170 {
171         /* kvm common code refers to this, but does'nt call it */
172         BUG();
173 }
174
175 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
176 {
177         save_fp_regs(&vcpu->arch.host_fpregs);
178         save_access_regs(vcpu->arch.host_acrs);
179         vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
180         restore_fp_regs(&vcpu->arch.guest_fpregs);
181         restore_access_regs(vcpu->arch.guest_acrs);
182
183         if (signal_pending(current))
184                 atomic_set_mask(CPUSTAT_STOP_INT,
185                         &vcpu->arch.sie_block->cpuflags);
186 }
187
188 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
189 {
190         save_fp_regs(&vcpu->arch.guest_fpregs);
191         save_access_regs(vcpu->arch.guest_acrs);
192         restore_fp_regs(&vcpu->arch.host_fpregs);
193         restore_access_regs(vcpu->arch.host_acrs);
194 }
195
196 static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
197 {
198         /* this equals initial cpu reset in pop, but we don't switch to ESA */
199         vcpu->arch.sie_block->gpsw.mask = 0UL;
200         vcpu->arch.sie_block->gpsw.addr = 0UL;
201         vcpu->arch.sie_block->prefix    = 0UL;
202         vcpu->arch.sie_block->ihcpu     = 0xffff;
203         vcpu->arch.sie_block->cputm     = 0UL;
204         vcpu->arch.sie_block->ckc       = 0UL;
205         vcpu->arch.sie_block->todpr     = 0;
206         memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
207         vcpu->arch.sie_block->gcr[0]  = 0xE0UL;
208         vcpu->arch.sie_block->gcr[14] = 0xC2000000UL;
209         vcpu->arch.guest_fpregs.fpc = 0;
210         asm volatile("lfpc %0" : : "Q" (vcpu->arch.guest_fpregs.fpc));
211         vcpu->arch.sie_block->gbea = 1;
212 }
213
214 int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
215 {
216         atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH);
217         vcpu->arch.sie_block->gmslm = 0xffffffffffUL;
218         vcpu->arch.sie_block->gmsor = 0x000000000000;
219         vcpu->arch.sie_block->ecb   = 2;
220         vcpu->arch.sie_block->eca   = 0xC1002001U;
221
222         return 0;
223 }
224
225 struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
226                                       unsigned int id)
227 {
228         struct kvm_vcpu *vcpu = kzalloc(sizeof(struct kvm_vcpu), GFP_KERNEL);
229         int rc = -ENOMEM;
230
231         if (!vcpu)
232                 goto out_nomem;
233
234         vcpu->arch.sie_block = (struct sie_block *) get_zeroed_page(GFP_KERNEL);
235
236         if (!vcpu->arch.sie_block)
237                 goto out_free_cpu;
238
239         vcpu->arch.sie_block->icpua = id;
240         BUG_ON(!kvm->arch.sca);
241         BUG_ON(kvm->arch.sca->cpu[id].sda);
242         kvm->arch.sca->cpu[id].sda = (__u64) vcpu->arch.sie_block;
243         vcpu->arch.sie_block->scaoh = (__u32)(((__u64)kvm->arch.sca) >> 32);
244         vcpu->arch.sie_block->scaol = (__u32)(__u64)kvm->arch.sca;
245
246         rc = kvm_vcpu_init(vcpu, kvm, id);
247         if (rc)
248                 goto out_free_cpu;
249         VM_EVENT(kvm, 3, "create cpu %d at %p, sie block at %p", id, vcpu,
250                  vcpu->arch.sie_block);
251
252         try_module_get(THIS_MODULE);
253
254         return vcpu;
255 out_free_cpu:
256         kfree(vcpu);
257 out_nomem:
258         return ERR_PTR(rc);
259 }
260
261 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
262 {
263         VCPU_EVENT(vcpu, 3, "%s", "destroy cpu");
264         free_page((unsigned long)(vcpu->arch.sie_block));
265         kfree(vcpu);
266         module_put(THIS_MODULE);
267 }
268
269 int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
270 {
271         /* kvm common code refers to this, but never calls it */
272         BUG();
273         return 0;
274 }
275
276 static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
277 {
278         vcpu_load(vcpu);
279         kvm_s390_vcpu_initial_reset(vcpu);
280         vcpu_put(vcpu);
281         return 0;
282 }
283
284 int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
285 {
286         vcpu_load(vcpu);
287         memcpy(&vcpu->arch.guest_gprs, &regs->gprs, sizeof(regs->gprs));
288         vcpu_put(vcpu);
289         return 0;
290 }
291
292 int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
293 {
294         vcpu_load(vcpu);
295         memcpy(&regs->gprs, &vcpu->arch.guest_gprs, sizeof(regs->gprs));
296         vcpu_put(vcpu);
297         return 0;
298 }
299
300 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
301                                   struct kvm_sregs *sregs)
302 {
303         vcpu_load(vcpu);
304         memcpy(&vcpu->arch.guest_acrs, &sregs->acrs, sizeof(sregs->acrs));
305         memcpy(&vcpu->arch.sie_block->gcr, &sregs->crs, sizeof(sregs->crs));
306         vcpu_put(vcpu);
307         return 0;
308 }
309
310 int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,
311                                   struct kvm_sregs *sregs)
312 {
313         vcpu_load(vcpu);
314         memcpy(&sregs->acrs, &vcpu->arch.guest_acrs, sizeof(sregs->acrs));
315         memcpy(&sregs->crs, &vcpu->arch.sie_block->gcr, sizeof(sregs->crs));
316         vcpu_put(vcpu);
317         return 0;
318 }
319
320 int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
321 {
322         vcpu_load(vcpu);
323         memcpy(&vcpu->arch.guest_fpregs.fprs, &fpu->fprs, sizeof(fpu->fprs));
324         vcpu->arch.guest_fpregs.fpc = fpu->fpc;
325         vcpu_put(vcpu);
326         return 0;
327 }
328
329 int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu)
330 {
331         vcpu_load(vcpu);
332         memcpy(&fpu->fprs, &vcpu->arch.guest_fpregs.fprs, sizeof(fpu->fprs));
333         fpu->fpc = vcpu->arch.guest_fpregs.fpc;
334         vcpu_put(vcpu);
335         return 0;
336 }
337
338 static int kvm_arch_vcpu_ioctl_set_initial_psw(struct kvm_vcpu *vcpu, psw_t psw)
339 {
340         int rc = 0;
341
342         vcpu_load(vcpu);
343         if (atomic_read(&vcpu->arch.sie_block->cpuflags) & CPUSTAT_RUNNING)
344                 rc = -EBUSY;
345         else
346                 vcpu->arch.sie_block->gpsw = psw;
347         vcpu_put(vcpu);
348         return rc;
349 }
350
351 int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu,
352                                   struct kvm_translation *tr)
353 {
354         return -EINVAL; /* not implemented yet */
355 }
356
357 int kvm_arch_vcpu_ioctl_debug_guest(struct kvm_vcpu *vcpu,
358                                     struct kvm_debug_guest *dbg)
359 {
360         return -EINVAL; /* not implemented yet */
361 }
362
363 static void __vcpu_run(struct kvm_vcpu *vcpu)
364 {
365         memcpy(&vcpu->arch.sie_block->gg14, &vcpu->arch.guest_gprs[14], 16);
366
367         if (need_resched())
368                 schedule();
369
370         vcpu->arch.sie_block->icptcode = 0;
371         local_irq_disable();
372         kvm_guest_enter();
373         local_irq_enable();
374         VCPU_EVENT(vcpu, 6, "entering sie flags %x",
375                    atomic_read(&vcpu->arch.sie_block->cpuflags));
376         sie64a(vcpu->arch.sie_block, vcpu->arch.guest_gprs);
377         VCPU_EVENT(vcpu, 6, "exit sie icptcode %d",
378                    vcpu->arch.sie_block->icptcode);
379         local_irq_disable();
380         kvm_guest_exit();
381         local_irq_enable();
382
383         memcpy(&vcpu->arch.guest_gprs[14], &vcpu->arch.sie_block->gg14, 16);
384 }
385
386 int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run)
387 {
388         int rc;
389         sigset_t sigsaved;
390
391         vcpu_load(vcpu);
392
393         if (vcpu->sigset_active)
394                 sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved);
395
396         atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags);
397
398         switch (kvm_run->exit_reason) {
399         case KVM_EXIT_S390_SIEIC:
400                 vcpu->arch.sie_block->gpsw.mask = kvm_run->s390_sieic.mask;
401                 vcpu->arch.sie_block->gpsw.addr = kvm_run->s390_sieic.addr;
402                 break;
403         case KVM_EXIT_UNKNOWN:
404         case KVM_EXIT_S390_RESET:
405                 break;
406         default:
407                 BUG();
408         }
409
410         might_sleep();
411
412         do {
413                 __vcpu_run(vcpu);
414
415                 rc = kvm_handle_sie_intercept(vcpu);
416         } while (!signal_pending(current) && !rc);
417
418         if (signal_pending(current) && !rc)
419                 rc = -EINTR;
420
421         if (rc == -ENOTSUPP) {
422                 /* intercept cannot be handled in-kernel, prepare kvm-run */
423                 kvm_run->exit_reason         = KVM_EXIT_S390_SIEIC;
424                 kvm_run->s390_sieic.icptcode = vcpu->arch.sie_block->icptcode;
425                 kvm_run->s390_sieic.mask     = vcpu->arch.sie_block->gpsw.mask;
426                 kvm_run->s390_sieic.addr     = vcpu->arch.sie_block->gpsw.addr;
427                 kvm_run->s390_sieic.ipa      = vcpu->arch.sie_block->ipa;
428                 kvm_run->s390_sieic.ipb      = vcpu->arch.sie_block->ipb;
429                 rc = 0;
430         }
431
432         if (rc == -EREMOTE) {
433                 /* intercept was handled, but userspace support is needed
434                  * kvm_run has been prepared by the handler */
435                 rc = 0;
436         }
437
438         if (vcpu->sigset_active)
439                 sigprocmask(SIG_SETMASK, &sigsaved, NULL);
440
441         vcpu_put(vcpu);
442
443         vcpu->stat.exit_userspace++;
444         return 0;
445 }
446
447 static int __guestcopy(struct kvm_vcpu *vcpu, u64 guestdest, const void *from,
448                        unsigned long n, int prefix)
449 {
450         if (prefix)
451                 return copy_to_guest(vcpu, guestdest, from, n);
452         else
453                 return copy_to_guest_absolute(vcpu, guestdest, from, n);
454 }
455
456 /*
457  * store status at address
458  * we use have two special cases:
459  * KVM_S390_STORE_STATUS_NOADDR: -> 0x1200 on 64 bit
460  * KVM_S390_STORE_STATUS_PREFIXED: -> prefix
461  */
462 int __kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
463 {
464         const unsigned char archmode = 1;
465         int prefix;
466
467         if (addr == KVM_S390_STORE_STATUS_NOADDR) {
468                 if (copy_to_guest_absolute(vcpu, 163ul, &archmode, 1))
469                         return -EFAULT;
470                 addr = SAVE_AREA_BASE;
471                 prefix = 0;
472         } else if (addr == KVM_S390_STORE_STATUS_PREFIXED) {
473                 if (copy_to_guest(vcpu, 163ul, &archmode, 1))
474                         return -EFAULT;
475                 addr = SAVE_AREA_BASE;
476                 prefix = 1;
477         } else
478                 prefix = 0;
479
480         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, fp_regs),
481                         vcpu->arch.guest_fpregs.fprs, 128, prefix))
482                 return -EFAULT;
483
484         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, gp_regs),
485                         vcpu->arch.guest_gprs, 128, prefix))
486                 return -EFAULT;
487
488         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, psw),
489                         &vcpu->arch.sie_block->gpsw, 16, prefix))
490                 return -EFAULT;
491
492         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, pref_reg),
493                         &vcpu->arch.sie_block->prefix, 4, prefix))
494                 return -EFAULT;
495
496         if (__guestcopy(vcpu,
497                         addr + offsetof(struct save_area_s390x, fp_ctrl_reg),
498                         &vcpu->arch.guest_fpregs.fpc, 4, prefix))
499                 return -EFAULT;
500
501         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, tod_reg),
502                         &vcpu->arch.sie_block->todpr, 4, prefix))
503                 return -EFAULT;
504
505         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, timer),
506                         &vcpu->arch.sie_block->cputm, 8, prefix))
507                 return -EFAULT;
508
509         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, clk_cmp),
510                         &vcpu->arch.sie_block->ckc, 8, prefix))
511                 return -EFAULT;
512
513         if (__guestcopy(vcpu, addr + offsetof(struct save_area_s390x, acc_regs),
514                         &vcpu->arch.guest_acrs, 64, prefix))
515                 return -EFAULT;
516
517         if (__guestcopy(vcpu,
518                         addr + offsetof(struct save_area_s390x, ctrl_regs),
519                         &vcpu->arch.sie_block->gcr, 128, prefix))
520                 return -EFAULT;
521         return 0;
522 }
523
524 static int kvm_s390_vcpu_store_status(struct kvm_vcpu *vcpu, unsigned long addr)
525 {
526         int rc;
527
528         vcpu_load(vcpu);
529         rc = __kvm_s390_vcpu_store_status(vcpu, addr);
530         vcpu_put(vcpu);
531         return rc;
532 }
533
534 long kvm_arch_vcpu_ioctl(struct file *filp,
535                          unsigned int ioctl, unsigned long arg)
536 {
537         struct kvm_vcpu *vcpu = filp->private_data;
538         void __user *argp = (void __user *)arg;
539
540         switch (ioctl) {
541         case KVM_S390_STORE_STATUS:
542                 return kvm_s390_vcpu_store_status(vcpu, arg);
543         case KVM_S390_SET_INITIAL_PSW: {
544                 psw_t psw;
545
546                 if (copy_from_user(&psw, argp, sizeof(psw)))
547                         return -EFAULT;
548                 return kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
549         }
550         case KVM_S390_INITIAL_RESET:
551                 return kvm_arch_vcpu_ioctl_initial_reset(vcpu);
552         default:
553                 ;
554         }
555         return -EINVAL;
556 }
557
558 /* Section: memory related */
559 int kvm_arch_set_memory_region(struct kvm *kvm,
560                                 struct kvm_userspace_memory_region *mem,
561                                 struct kvm_memory_slot old,
562                                 int user_alloc)
563 {
564         /* A few sanity checks. We can have exactly one memory slot which has
565            to start at guest virtual zero and which has to be located at a
566            page boundary in userland and which has to end at a page boundary.
567            The memory in userland is ok to be fragmented into various different
568            vmas. It is okay to mmap() and munmap() stuff in this slot after
569            doing this call at any time */
570
571         if (mem->slot)
572                 return -EINVAL;
573
574         if (mem->guest_phys_addr)
575                 return -EINVAL;
576
577         if (mem->userspace_addr & (PAGE_SIZE - 1))
578                 return -EINVAL;
579
580         if (mem->memory_size & (PAGE_SIZE - 1))
581                 return -EINVAL;
582
583         kvm->arch.guest_origin = mem->userspace_addr;
584         kvm->arch.guest_memsize = mem->memory_size;
585
586         /* FIXME: we do want to interrupt running CPUs and update their memory
587            configuration now to avoid race conditions. But hey, changing the
588            memory layout while virtual CPUs are running is usually bad
589            programming practice. */
590
591         return 0;
592 }
593
594 gfn_t unalias_gfn(struct kvm *kvm, gfn_t gfn)
595 {
596         return gfn;
597 }
598
599 static int __init kvm_s390_init(void)
600 {
601         return kvm_init(NULL, sizeof(struct kvm_vcpu), THIS_MODULE);
602 }
603
604 static void __exit kvm_s390_exit(void)
605 {
606         kvm_exit();
607 }
608
609 module_init(kvm_s390_init);
610 module_exit(kvm_s390_exit);