forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
kernel/arch/s390/kvm/intercept.c
....@@ -2,7 +2,7 @@
22 /*
33 * in-kernel handling for sie intercepts
44 *
5
- * Copyright IBM Corp. 2008, 2014
5
+ * Copyright IBM Corp. 2008, 2020
66 *
77 * Author(s): Carsten Otte <cotte@de.ibm.com>
88 * Christian Borntraeger <borntraeger@de.ibm.com>
....@@ -12,10 +12,10 @@
1212 #include <linux/errno.h>
1313 #include <linux/pagemap.h>
1414
15
-#include <asm/kvm_host.h>
1615 #include <asm/asm-offsets.h>
1716 #include <asm/irq.h>
1817 #include <asm/sysinfo.h>
18
+#include <asm/uv.h>
1919
2020 #include "kvm-s390.h"
2121 #include "gaccess.h"
....@@ -79,6 +79,10 @@
7979 return rc;
8080 }
8181
82
+ /*
83
+ * no need to check the return value of vcpu_stop as it can only have
84
+ * an error for protvirt, but protvirt means user cpu state
85
+ */
8286 if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
8387 kvm_s390_vcpu_stop(vcpu);
8488 return -EOPNOTSUPP;
....@@ -230,6 +234,13 @@
230234 int rc;
231235
232236 vcpu->stat.exit_program_interruption++;
237
+
238
+ /*
239
+ * Intercept 8 indicates a loop of specification exceptions
240
+ * for protected guests.
241
+ */
242
+ if (kvm_s390_pv_cpu_is_protected(vcpu))
243
+ return -EOPNOTSUPP;
233244
234245 if (guestdbg_enabled(vcpu) && per_event(vcpu)) {
235246 rc = kvm_s390_handle_per_event(vcpu);
....@@ -384,7 +395,7 @@
384395 goto out;
385396 }
386397
387
- if (addr & ~PAGE_MASK)
398
+ if (!kvm_s390_pv_cpu_is_protected(vcpu) && (addr & ~PAGE_MASK))
388399 return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
389400
390401 sctns = (void *)get_zeroed_page(GFP_KERNEL);
....@@ -395,10 +406,15 @@
395406
396407 out:
397408 if (!cc) {
398
- r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
399
- if (r) {
400
- free_page((unsigned long)sctns);
401
- return kvm_s390_inject_prog_cond(vcpu, r);
409
+ if (kvm_s390_pv_cpu_is_protected(vcpu)) {
410
+ memcpy((void *)(sida_origin(vcpu->arch.sie_block)),
411
+ sctns, PAGE_SIZE);
412
+ } else {
413
+ r = write_guest(vcpu, addr, reg2, sctns, PAGE_SIZE);
414
+ if (r) {
415
+ free_page((unsigned long)sctns);
416
+ return kvm_s390_inject_prog_cond(vcpu, r);
417
+ }
402418 }
403419 }
404420
....@@ -444,6 +460,92 @@
444460 return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
445461 }
446462
463
+static int handle_pv_spx(struct kvm_vcpu *vcpu)
464
+{
465
+ u32 pref = *(u32 *)vcpu->arch.sie_block->sidad;
466
+
467
+ kvm_s390_set_prefix(vcpu, pref);
468
+ trace_kvm_s390_handle_prefix(vcpu, 1, pref);
469
+ return 0;
470
+}
471
+
472
+static int handle_pv_sclp(struct kvm_vcpu *vcpu)
473
+{
474
+ struct kvm_s390_float_interrupt *fi = &vcpu->kvm->arch.float_int;
475
+
476
+ spin_lock(&fi->lock);
477
+ /*
478
+ * 2 cases:
479
+ * a: an sccb answering interrupt was already pending or in flight.
480
+ * As the sccb value is not known we can simply set some value to
481
+ * trigger delivery of a saved SCCB. UV will then use its saved
482
+ * copy of the SCCB value.
483
+ * b: an error SCCB interrupt needs to be injected so we also inject
484
+ * a fake SCCB address. Firmware will use the proper one.
485
+ * This makes sure, that both errors and real sccb returns will only
486
+ * be delivered after a notification intercept (instruction has
487
+ * finished) but not after others.
488
+ */
489
+ fi->srv_signal.ext_params |= 0x43000;
490
+ set_bit(IRQ_PEND_EXT_SERVICE, &fi->pending_irqs);
491
+ clear_bit(IRQ_PEND_EXT_SERVICE, &fi->masked_irqs);
492
+ spin_unlock(&fi->lock);
493
+ return 0;
494
+}
495
+
496
+static int handle_pv_uvc(struct kvm_vcpu *vcpu)
497
+{
498
+ struct uv_cb_share *guest_uvcb = (void *)vcpu->arch.sie_block->sidad;
499
+ struct uv_cb_cts uvcb = {
500
+ .header.cmd = UVC_CMD_UNPIN_PAGE_SHARED,
501
+ .header.len = sizeof(uvcb),
502
+ .guest_handle = kvm_s390_pv_get_handle(vcpu->kvm),
503
+ .gaddr = guest_uvcb->paddr,
504
+ };
505
+ int rc;
506
+
507
+ if (guest_uvcb->header.cmd != UVC_CMD_REMOVE_SHARED_ACCESS) {
508
+ WARN_ONCE(1, "Unexpected notification intercept for UVC 0x%x\n",
509
+ guest_uvcb->header.cmd);
510
+ return 0;
511
+ }
512
+ rc = gmap_make_secure(vcpu->arch.gmap, uvcb.gaddr, &uvcb);
513
+ /*
514
+ * If the unpin did not succeed, the guest will exit again for the UVC
515
+ * and we will retry the unpin.
516
+ */
517
+ if (rc == -EINVAL)
518
+ return 0;
519
+ return rc;
520
+}
521
+
522
+static int handle_pv_notification(struct kvm_vcpu *vcpu)
523
+{
524
+ int ret;
525
+
526
+ if (vcpu->arch.sie_block->ipa == 0xb210)
527
+ return handle_pv_spx(vcpu);
528
+ if (vcpu->arch.sie_block->ipa == 0xb220)
529
+ return handle_pv_sclp(vcpu);
530
+ if (vcpu->arch.sie_block->ipa == 0xb9a4)
531
+ return handle_pv_uvc(vcpu);
532
+ if (vcpu->arch.sie_block->ipa >> 8 == 0xae) {
533
+ /*
534
+ * Besides external call, other SIGP orders also cause a
535
+ * 108 (pv notify) intercept. In contrast to external call,
536
+ * these orders need to be emulated and hence the appropriate
537
+ * place to handle them is in handle_instruction().
538
+ * So first try kvm_s390_handle_sigp_pei() and if that isn't
539
+ * successful, go on with handle_instruction().
540
+ */
541
+ ret = kvm_s390_handle_sigp_pei(vcpu);
542
+ if (!ret)
543
+ return ret;
544
+ }
545
+
546
+ return handle_instruction(vcpu);
547
+}
548
+
447549 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu)
448550 {
449551 int rc, per_rc = 0;
....@@ -480,6 +582,28 @@
480582 case ICPT_KSS:
481583 rc = kvm_s390_skey_check_enable(vcpu);
482584 break;
585
+ case ICPT_MCHKREQ:
586
+ case ICPT_INT_ENABLE:
587
+ /*
588
+ * PSW bit 13 or a CR (0, 6, 14) changed and we might
589
+ * now be able to deliver interrupts. The pre-run code
590
+ * will take care of this.
591
+ */
592
+ rc = 0;
593
+ break;
594
+ case ICPT_PV_INSTR:
595
+ rc = handle_instruction(vcpu);
596
+ break;
597
+ case ICPT_PV_NOTIFY:
598
+ rc = handle_pv_notification(vcpu);
599
+ break;
600
+ case ICPT_PV_PREF:
601
+ rc = 0;
602
+ gmap_convert_to_secure(vcpu->arch.gmap,
603
+ kvm_s390_get_prefix(vcpu));
604
+ gmap_convert_to_secure(vcpu->arch.gmap,
605
+ kvm_s390_get_prefix(vcpu) + PAGE_SIZE);
606
+ break;
483607 default:
484608 return -EOPNOTSUPP;
485609 }