@@ -4646,12 +4646,11 @@ static bool kvm_arch_setup_async_pf(struct kvm_vcpu *vcpu)
46464646 if (!vcpu -> arch .gmap -> pfault_enabled )
46474647 return false;
46484648
4649- hva = gfn_to_hva (vcpu -> kvm , gpa_to_gfn (current -> thread .gmap_addr ));
4650- hva += current -> thread .gmap_addr & ~PAGE_MASK ;
4649+ hva = gfn_to_hva (vcpu -> kvm , current -> thread .gmap_teid .addr );
46514650 if (read_guest_real (vcpu , vcpu -> arch .pfault_token , & arch .pfault_token , 8 ))
46524651 return false;
46534652
4654- return kvm_setup_async_pf (vcpu , current -> thread .gmap_addr , hva , & arch );
4653+ return kvm_setup_async_pf (vcpu , current -> thread .gmap_teid . addr * PAGE_SIZE , hva , & arch );
46554654}
46564655
46574656static int vcpu_pre_run (struct kvm_vcpu * vcpu )
@@ -4689,14 +4688,15 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
46894688 clear_bit (vcpu -> vcpu_idx , vcpu -> kvm -> arch .gisa_int .kicked_mask );
46904689
46914690 vcpu -> arch .sie_block -> icptcode = 0 ;
4691+ current -> thread .gmap_int_code = 0 ;
46924692 cpuflags = atomic_read (& vcpu -> arch .sie_block -> cpuflags );
46934693 VCPU_EVENT (vcpu , 6 , "entering sie flags %x" , cpuflags );
46944694 trace_kvm_s390_sie_enter (vcpu , cpuflags );
46954695
46964696 return 0 ;
46974697}
46984698
4699- static int vcpu_post_run_fault_in_sie (struct kvm_vcpu * vcpu )
4699+ static int vcpu_post_run_addressing_exception (struct kvm_vcpu * vcpu )
47004700{
47014701 struct kvm_s390_pgm_info pgm_info = {
47024702 .code = PGM_ADDRESSING ,
@@ -4732,10 +4732,106 @@ static int vcpu_post_run_fault_in_sie(struct kvm_vcpu *vcpu)
47324732 return kvm_s390_inject_prog_irq (vcpu , & pgm_info );
47334733}
47344734
4735+ static int vcpu_post_run_handle_fault (struct kvm_vcpu * vcpu )
4736+ {
4737+ unsigned long gaddr ;
4738+ unsigned int flags ;
4739+ int rc = 0 ;
4740+
4741+ gaddr = current -> thread .gmap_teid .addr * PAGE_SIZE ;
4742+ if (kvm_s390_cur_gmap_fault_is_write ())
4743+ flags = FAULT_FLAG_WRITE ;
4744+
4745+ switch (current -> thread .gmap_int_code ) {
4746+ case 0 :
4747+ vcpu -> stat .exit_null ++ ;
4748+ break ;
4749+ case PGM_NON_SECURE_STORAGE_ACCESS :
4750+ KVM_BUG (current -> thread .gmap_teid .as != PSW_BITS_AS_PRIMARY , vcpu -> kvm ,
4751+ "Unexpected program interrupt 0x%x, TEID 0x%016lx" ,
4752+ current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4753+ /*
4754+ * This is normal operation; a page belonging to a protected
4755+ * guest has not been imported yet. Try to import the page into
4756+ * the protected guest.
4757+ */
4758+ if (gmap_convert_to_secure (vcpu -> arch .gmap , gaddr ) == - EINVAL )
4759+ send_sig (SIGSEGV , current , 0 );
4760+ break ;
4761+ case PGM_SECURE_STORAGE_ACCESS :
4762+ case PGM_SECURE_STORAGE_VIOLATION :
4763+ KVM_BUG (current -> thread .gmap_teid .as != PSW_BITS_AS_PRIMARY , vcpu -> kvm ,
4764+ "Unexpected program interrupt 0x%x, TEID 0x%016lx" ,
4765+ current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4766+ /*
4767+ * This can happen after a reboot with asynchronous teardown;
4768+ * the new guest (normal or protected) will run on top of the
4769+ * previous protected guest. The old pages need to be destroyed
4770+ * so the new guest can use them.
4771+ */
4772+ if (gmap_destroy_page (vcpu -> arch .gmap , gaddr )) {
4773+ /*
4774+ * Either KVM messed up the secure guest mapping or the
4775+ * same page is mapped into multiple secure guests.
4776+ *
4777+ * This exception is only triggered when a guest 2 is
4778+ * running and can therefore never occur in kernel
4779+ * context.
4780+ */
4781+ pr_warn_ratelimited ("Secure storage violation (%x) in task: %s, pid %d\n" ,
4782+ current -> thread .gmap_int_code , current -> comm ,
4783+ current -> pid );
4784+ send_sig (SIGSEGV , current , 0 );
4785+ }
4786+ break ;
4787+ case PGM_PROTECTION :
4788+ case PGM_SEGMENT_TRANSLATION :
4789+ case PGM_PAGE_TRANSLATION :
4790+ case PGM_ASCE_TYPE :
4791+ case PGM_REGION_FIRST_TRANS :
4792+ case PGM_REGION_SECOND_TRANS :
4793+ case PGM_REGION_THIRD_TRANS :
4794+ KVM_BUG (current -> thread .gmap_teid .as != PSW_BITS_AS_PRIMARY , vcpu -> kvm ,
4795+ "Unexpected program interrupt 0x%x, TEID 0x%016lx" ,
4796+ current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4797+ if (vcpu -> arch .gmap -> pfault_enabled ) {
4798+ rc = gmap_fault (vcpu -> arch .gmap , gaddr , flags | FAULT_FLAG_RETRY_NOWAIT );
4799+ if (rc == - EFAULT )
4800+ return vcpu_post_run_addressing_exception (vcpu );
4801+ if (rc == - EAGAIN ) {
4802+ trace_kvm_s390_major_guest_pfault (vcpu );
4803+ if (kvm_arch_setup_async_pf (vcpu ))
4804+ return 0 ;
4805+ vcpu -> stat .pfault_sync ++ ;
4806+ } else {
4807+ return rc ;
4808+ }
4809+ }
4810+ rc = gmap_fault (vcpu -> arch .gmap , gaddr , flags );
4811+ if (rc == - EFAULT ) {
4812+ if (kvm_is_ucontrol (vcpu -> kvm )) {
4813+ vcpu -> run -> exit_reason = KVM_EXIT_S390_UCONTROL ;
4814+ vcpu -> run -> s390_ucontrol .trans_exc_code = gaddr ;
4815+ vcpu -> run -> s390_ucontrol .pgm_code = 0x10 ;
4816+ return - EREMOTE ;
4817+ }
4818+ return vcpu_post_run_addressing_exception (vcpu );
4819+ }
4820+ break ;
4821+ default :
4822+ KVM_BUG (1 , vcpu -> kvm , "Unexpected program interrupt 0x%x, TEID 0x%016lx" ,
4823+ current -> thread .gmap_int_code , current -> thread .gmap_teid .val );
4824+ send_sig (SIGSEGV , current , 0 );
4825+ break ;
4826+ }
4827+ return rc ;
4828+ }
4829+
47354830static int vcpu_post_run (struct kvm_vcpu * vcpu , int exit_reason )
47364831{
47374832 struct mcck_volatile_info * mcck_info ;
47384833 struct sie_page * sie_page ;
4834+ int rc ;
47394835
47404836 VCPU_EVENT (vcpu , 6 , "exit sie icptcode %d" ,
47414837 vcpu -> arch .sie_block -> icptcode );
@@ -4757,7 +4853,7 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
47574853 }
47584854
47594855 if (vcpu -> arch .sie_block -> icptcode > 0 ) {
4760- int rc = kvm_handle_sie_intercept (vcpu );
4856+ rc = kvm_handle_sie_intercept (vcpu );
47614857
47624858 if (rc != - EOPNOTSUPP )
47634859 return rc ;
@@ -4766,24 +4862,9 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
47664862 vcpu -> run -> s390_sieic .ipa = vcpu -> arch .sie_block -> ipa ;
47674863 vcpu -> run -> s390_sieic .ipb = vcpu -> arch .sie_block -> ipb ;
47684864 return - EREMOTE ;
4769- } else if (exit_reason != - EFAULT ) {
4770- vcpu -> stat .exit_null ++ ;
4771- return 0 ;
4772- } else if (kvm_is_ucontrol (vcpu -> kvm )) {
4773- vcpu -> run -> exit_reason = KVM_EXIT_S390_UCONTROL ;
4774- vcpu -> run -> s390_ucontrol .trans_exc_code =
4775- current -> thread .gmap_addr ;
4776- vcpu -> run -> s390_ucontrol .pgm_code = 0x10 ;
4777- return - EREMOTE ;
4778- } else if (current -> thread .gmap_pfault ) {
4779- trace_kvm_s390_major_guest_pfault (vcpu );
4780- current -> thread .gmap_pfault = 0 ;
4781- if (kvm_arch_setup_async_pf (vcpu ))
4782- return 0 ;
4783- vcpu -> stat .pfault_sync ++ ;
4784- return gmap_fault (vcpu -> arch .gmap , current -> thread .gmap_addr , FAULT_FLAG_WRITE );
47854865 }
4786- return vcpu_post_run_fault_in_sie (vcpu );
4866+
4867+ return vcpu_post_run_handle_fault (vcpu );
47874868}
47884869
47894870#define PSW_INT_MASK (PSW_MASK_EXT | PSW_MASK_IO | PSW_MASK_MCHECK)
0 commit comments