]> Git Repo - linux.git/commitdiff
Merge tag 'kvm-s390-next-5.6-1' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorPaolo Bonzini <[email protected]>
Wed, 5 Feb 2020 15:15:05 +0000 (16:15 +0100)
committerPaolo Bonzini <[email protected]>
Wed, 5 Feb 2020 15:15:05 +0000 (16:15 +0100)
KVM: s390: Fixes and cleanups for 5.6
- fix register corruption
- ENOTSUPP/EOPNOTSUPP mixed
- reset cleanups/fixes
- selftests

1  2 
Documentation/virt/kvm/api.txt
arch/s390/include/asm/kvm_host.h
arch/s390/kvm/kvm-s390.c
tools/testing/selftests/kvm/Makefile

index 3a0c819c357327ee0d7da4677e33c5a74ec379e9,73448764f544920394033aa8cb4529c90889fc81..c6e1ce5d40de992df7acd2c3782d619fd0838721
@@@ -2196,15 -2196,6 +2196,15 @@@ arm64 CCSIDR registers are demultiplexe
  arm64 system registers have the following id bit patterns:
    0x6030 0000 0013 <op0:2> <op1:3> <crn:4> <crm:4> <op2:3>
  
 +WARNING:
 +     Two system register IDs do not follow the specified pattern.  These
 +     are KVM_REG_ARM_TIMER_CVAL and KVM_REG_ARM_TIMER_CNT, which map to
 +     system registers CNTV_CVAL_EL0 and CNTVCT_EL0 respectively.  These
 +     two had their values accidentally swapped, which means TIMER_CVAL is
 +     derived from the register encoding for CNTVCT_EL0 and TIMER_CNT is
 +     derived from the register encoding for CNTV_CVAL_EL0.  As this is
 +     API, it must remain this way.
 +
  arm64 firmware pseudo-registers have the following bit pattern:
    0x6030 0000 0014 <regno:16>
  
@@@ -4177,6 -4168,42 +4177,42 @@@ This ioctl issues an ultravisor call t
  unpins the VPA pages and releases all the device pages that are used to
  track the secure pages by hypervisor.
  
+ 4.122 KVM_S390_NORMAL_RESET
+ Capability: KVM_CAP_S390_VCPU_RESETS
+ Architectures: s390
+ Type: vcpu ioctl
+ Parameters: none
+ Returns: 0
+ This ioctl resets VCPU registers and control structures according to
+ the cpu reset definition in the POP (Principles Of Operation).
+ 4.123 KVM_S390_INITIAL_RESET
+ Capability: none
+ Architectures: s390
+ Type: vcpu ioctl
+ Parameters: none
+ Returns: 0
+ This ioctl resets VCPU registers and control structures according to
+ the initial cpu reset definition in the POP. However, the cpu is not
+ put into ESA mode. This reset is a superset of the normal reset.
+ 4.124 KVM_S390_CLEAR_RESET
+ Capability: KVM_CAP_S390_VCPU_RESETS
+ Architectures: s390
+ Type: vcpu ioctl
+ Parameters: none
+ Returns: 0
+ This ioctl resets VCPU registers and control structures according to
+ the clear cpu reset definition in the POP. However, the cpu is not put
+ into ESA mode. This reset is a superset of the initial reset.
  5. The kvm_run structure
  ------------------------
  
@@@ -5405,3 -5432,10 +5441,10 @@@ handling by KVM (as some KVM hypercall 
  flush hypercalls by Hyper-V) so userspace should disable KVM identification
  in CPUID and only exposes Hyper-V identification. In this case, guest
  thinks it's running on Hyper-V and only use Hyper-V hypercalls.
+ 8.22 KVM_CAP_S390_VCPU_RESETS
+ Architectures: s390
+ This capability indicates that the KVM_S390_NORMAL_RESET and
+ KVM_S390_CLEAR_RESET ioctls are available.
index 11ecc4071a29f800d2b1246d91542db5dcc6bb0e,73044545ecacc7f1b7a4db59ea359865695dc512..1726224e77727f273350b86bb678f8da9b9a84c7
@@@ -122,6 -122,11 +122,11 @@@ struct mcck_volatile_info 
        __u32 reserved;
  };
  
+ #define CR0_INITIAL_MASK (CR0_UNUSED_56 | CR0_INTERRUPT_KEY_SUBMASK | \
+                         CR0_MEASUREMENT_ALERT_SUBMASK)
+ #define CR14_INITIAL_MASK (CR14_UNUSED_32 | CR14_UNUSED_33 | \
+                          CR14_EXTERNAL_DAMAGE_SUBMASK)
  #define CPUSTAT_STOPPED    0x80000000
  #define CPUSTAT_WAIT       0x10000000
  #define CPUSTAT_ECALL_PEND 0x08000000
@@@ -914,6 -919,7 +919,6 @@@ extern int kvm_s390_gisc_unregister(str
  
  static inline void kvm_arch_hardware_disable(void) {}
  static inline void kvm_arch_sync_events(struct kvm *kvm) {}
 -static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {}
  static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {}
  static inline void kvm_arch_free_memslot(struct kvm *kvm,
                struct kvm_memory_slot *free, struct kvm_memory_slot *dont) {}
diff --combined arch/s390/kvm/kvm-s390.c
index 8646c99217f285443a5973c1a62832767a4ddc48,e39f6ef97b09fc6b39f633773a48416f45f90856..d7ff30e45589935890ad1c1f67c0f36eaa4d480e
@@@ -529,6 -529,7 +529,7 @@@ int kvm_vm_ioctl_check_extension(struc
        case KVM_CAP_S390_CMMA_MIGRATION:
        case KVM_CAP_S390_AIS:
        case KVM_CAP_S390_AIS_MIGRATION:
+       case KVM_CAP_S390_VCPU_RESETS:
                r = 1;
                break;
        case KVM_CAP_S390_HPAGE_1M:
@@@ -2530,6 -2531,9 +2531,6 @@@ void kvm_arch_vcpu_destroy(struct kvm_v
        if (vcpu->kvm->arch.use_cmma)
                kvm_s390_vcpu_unsetup_cmma(vcpu);
        free_page((unsigned long)(vcpu->arch.sie_block));
 -
 -      kvm_vcpu_uninit(vcpu);
 -      kmem_cache_free(kvm_vcpu_cache, vcpu);
  }
  
  static void kvm_free_vcpus(struct kvm *kvm)
        struct kvm_vcpu *vcpu;
  
        kvm_for_each_vcpu(i, vcpu, kvm)
 -              kvm_arch_vcpu_destroy(vcpu);
 +              kvm_vcpu_destroy(vcpu);
  
        mutex_lock(&kvm->lock);
        for (i = 0; i < atomic_read(&kvm->online_vcpus); i++)
@@@ -2700,6 -2704,39 +2701,6 @@@ static int sca_can_add_vcpu(struct kvm 
        return rc == 0 && id < KVM_S390_ESCA_CPU_SLOTS;
  }
  
 -int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
 -{
 -      vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
 -      kvm_clear_async_pf_completion_queue(vcpu);
 -      vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
 -                                  KVM_SYNC_GPRS |
 -                                  KVM_SYNC_ACRS |
 -                                  KVM_SYNC_CRS |
 -                                  KVM_SYNC_ARCH0 |
 -                                  KVM_SYNC_PFAULT;
 -      kvm_s390_set_prefix(vcpu, 0);
 -      if (test_kvm_facility(vcpu->kvm, 64))
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
 -      if (test_kvm_facility(vcpu->kvm, 82))
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC;
 -      if (test_kvm_facility(vcpu->kvm, 133))
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB;
 -      if (test_kvm_facility(vcpu->kvm, 156))
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_ETOKEN;
 -      /* fprs can be synchronized via vrs, even if the guest has no vx. With
 -       * MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format.
 -       */
 -      if (MACHINE_HAS_VX)
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
 -      else
 -              vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
 -
 -      if (kvm_is_ucontrol(vcpu->kvm))
 -              return __kvm_ucontrol_vcpu_init(vcpu);
 -
 -      return 0;
 -}
 -
  /* needs disabled preemption to protect from TOD sync and vcpu_load/put */
  static void __start_cpu_timer_accounting(struct kvm_vcpu *vcpu)
  {
@@@ -2808,35 -2845,6 +2809,6 @@@ void kvm_arch_vcpu_put(struct kvm_vcpu 
  
  }
  
- static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)
- {
-       /* this equals initial cpu reset in pop, but we don't switch to ESA */
-       vcpu->arch.sie_block->gpsw.mask = 0UL;
-       vcpu->arch.sie_block->gpsw.addr = 0UL;
-       kvm_s390_set_prefix(vcpu, 0);
-       kvm_s390_set_cpu_timer(vcpu, 0);
-       vcpu->arch.sie_block->ckc       = 0UL;
-       vcpu->arch.sie_block->todpr     = 0;
-       memset(vcpu->arch.sie_block->gcr, 0, 16 * sizeof(__u64));
-       vcpu->arch.sie_block->gcr[0]  = CR0_UNUSED_56 |
-                                       CR0_INTERRUPT_KEY_SUBMASK |
-                                       CR0_MEASUREMENT_ALERT_SUBMASK;
-       vcpu->arch.sie_block->gcr[14] = CR14_UNUSED_32 |
-                                       CR14_UNUSED_33 |
-                                       CR14_EXTERNAL_DAMAGE_SUBMASK;
-       /* make sure the new fpc will be lazily loaded */
-       save_fpu_regs();
-       current->thread.fpu.fpc = 0;
-       vcpu->arch.sie_block->gbea = 1;
-       vcpu->arch.sie_block->pp = 0;
-       vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
-       vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
-       kvm_clear_async_pf_completion_queue(vcpu);
-       if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
-               kvm_s390_vcpu_stop(vcpu);
-       kvm_s390_clear_local_irqs(vcpu);
- }
  void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
  {
        mutex_lock(&vcpu->kvm->lock);
@@@ -2926,7 -2934,7 +2898,7 @@@ static void kvm_s390_vcpu_setup_model(s
                vcpu->arch.sie_block->fac = (u32)(u64) model->fac_list;
  }
  
 -int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
 +static int kvm_s390_vcpu_setup(struct kvm_vcpu *vcpu)
  {
        int rc = 0;
  
        return rc;
  }
  
 -struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
 -                                    unsigned int id)
 +int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id)
  {
 -      struct kvm_vcpu *vcpu;
 -      struct sie_page *sie_page;
 -      int rc = -EINVAL;
 -
        if (!kvm_is_ucontrol(kvm) && !sca_can_add_vcpu(kvm, id))
 -              goto out;
 -
 -      rc = -ENOMEM;
 +              return -EINVAL;
 +      return 0;
 +}
  
 -      vcpu = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL);
 -      if (!vcpu)
 -              goto out;
 +int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 +{
 +      struct sie_page *sie_page;
 +      int rc;
  
        BUILD_BUG_ON(sizeof(struct sie_page) != 4096);
        sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
        if (!sie_page)
 -              goto out_free_cpu;
 +              return -ENOMEM;
  
        vcpu->arch.sie_block = &sie_page->sie_block;
        vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
        vcpu->arch.sie_block->mso = 0;
        vcpu->arch.sie_block->msl = sclp.hamax;
  
 -      vcpu->arch.sie_block->icpua = id;
 +      vcpu->arch.sie_block->icpua = vcpu->vcpu_id;
        spin_lock_init(&vcpu->arch.local_int.lock);
 -      vcpu->arch.sie_block->gd = (u32)(u64)kvm->arch.gisa_int.origin;
 +      vcpu->arch.sie_block->gd = (u32)(u64)vcpu->kvm->arch.gisa_int.origin;
        if (vcpu->arch.sie_block->gd && sclp.has_gisaf)
                vcpu->arch.sie_block->gd |= GISA_FORMAT1;
        seqcount_init(&vcpu->arch.cputm_seqcount);
  
 -      rc = kvm_vcpu_init(vcpu, kvm, id);
 +      vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
 +      kvm_clear_async_pf_completion_queue(vcpu);
 +      vcpu->run->kvm_valid_regs = KVM_SYNC_PREFIX |
 +                                  KVM_SYNC_GPRS |
 +                                  KVM_SYNC_ACRS |
 +                                  KVM_SYNC_CRS |
 +                                  KVM_SYNC_ARCH0 |
 +                                  KVM_SYNC_PFAULT;
 +      kvm_s390_set_prefix(vcpu, 0);
 +      if (test_kvm_facility(vcpu->kvm, 64))
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_RICCB;
 +      if (test_kvm_facility(vcpu->kvm, 82))
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_BPBC;
 +      if (test_kvm_facility(vcpu->kvm, 133))
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_GSCB;
 +      if (test_kvm_facility(vcpu->kvm, 156))
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_ETOKEN;
 +      /* fprs can be synchronized via vrs, even if the guest has no vx. With
 +       * MACHINE_HAS_VX, (load|store)_fpu_regs() will work with vrs format.
 +       */
 +      if (MACHINE_HAS_VX)
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_VRS;
 +      else
 +              vcpu->run->kvm_valid_regs |= KVM_SYNC_FPRS;
 +
 +      if (kvm_is_ucontrol(vcpu->kvm)) {
 +              rc = __kvm_ucontrol_vcpu_init(vcpu);
 +              if (rc)
 +                      goto out_free_sie_block;
 +      }
 +
 +      VM_EVENT(vcpu->kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK",
 +               vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
 +      trace_kvm_s390_create_vcpu(vcpu->vcpu_id, vcpu, vcpu->arch.sie_block);
 +
 +      rc = kvm_s390_vcpu_setup(vcpu);
        if (rc)
 -              goto out_free_sie_block;
 -      VM_EVENT(kvm, 3, "create cpu %d at 0x%pK, sie block at 0x%pK", id, vcpu,
 -               vcpu->arch.sie_block);
 -      trace_kvm_s390_create_vcpu(id, vcpu, vcpu->arch.sie_block);
 +              goto out_ucontrol_uninit;
 +      return 0;
  
 -      return vcpu;
 +out_ucontrol_uninit:
 +      if (kvm_is_ucontrol(vcpu->kvm))
 +              gmap_remove(vcpu->arch.gmap);
  out_free_sie_block:
        free_page((unsigned long)(vcpu->arch.sie_block));
 -out_free_cpu:
 -      kmem_cache_free(kvm_vcpu_cache, vcpu);
 -out:
 -      return ERR_PTR(rc);
 +      return rc;
  }
  
  int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu)
@@@ -3279,10 -3259,53 +3251,53 @@@ static int kvm_arch_vcpu_ioctl_set_one_
        return r;
  }
  
- static int kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+ static void kvm_arch_vcpu_ioctl_normal_reset(struct kvm_vcpu *vcpu)
  {
-       kvm_s390_vcpu_initial_reset(vcpu);
-       return 0;
+       vcpu->arch.sie_block->gpsw.mask &= ~PSW_MASK_RI;
+       vcpu->arch.pfault_token = KVM_S390_PFAULT_TOKEN_INVALID;
+       memset(vcpu->run->s.regs.riccb, 0, sizeof(vcpu->run->s.regs.riccb));
+       kvm_clear_async_pf_completion_queue(vcpu);
+       if (!kvm_s390_user_cpu_state_ctrl(vcpu->kvm))
+               kvm_s390_vcpu_stop(vcpu);
+       kvm_s390_clear_local_irqs(vcpu);
+ }
+ static void kvm_arch_vcpu_ioctl_initial_reset(struct kvm_vcpu *vcpu)
+ {
+       /* Initial reset is a superset of the normal reset */
+       kvm_arch_vcpu_ioctl_normal_reset(vcpu);
+       /* this equals initial cpu reset in pop, but we don't switch to ESA */
+       vcpu->arch.sie_block->gpsw.mask = 0;
+       vcpu->arch.sie_block->gpsw.addr = 0;
+       kvm_s390_set_prefix(vcpu, 0);
+       kvm_s390_set_cpu_timer(vcpu, 0);
+       vcpu->arch.sie_block->ckc = 0;
+       vcpu->arch.sie_block->todpr = 0;
+       memset(vcpu->arch.sie_block->gcr, 0, sizeof(vcpu->arch.sie_block->gcr));
+       vcpu->arch.sie_block->gcr[0] = CR0_INITIAL_MASK;
+       vcpu->arch.sie_block->gcr[14] = CR14_INITIAL_MASK;
+       vcpu->run->s.regs.fpc = 0;
+       vcpu->arch.sie_block->gbea = 1;
+       vcpu->arch.sie_block->pp = 0;
+       vcpu->arch.sie_block->fpf &= ~FPF_BPBC;
+ }
+ static void kvm_arch_vcpu_ioctl_clear_reset(struct kvm_vcpu *vcpu)
+ {
+       struct kvm_sync_regs *regs = &vcpu->run->s.regs;
+       /* Clear reset is a superset of the initial reset */
+       kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+       memset(&regs->gprs, 0, sizeof(regs->gprs));
+       memset(&regs->vrs, 0, sizeof(regs->vrs));
+       memset(&regs->acrs, 0, sizeof(regs->acrs));
+       memset(&regs->gscb, 0, sizeof(regs->gscb));
+       regs->etoken = 0;
+       regs->etoken_extension = 0;
  }
  
  int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs)
@@@ -4343,7 -4366,7 +4358,7 @@@ long kvm_arch_vcpu_ioctl(struct file *f
        switch (ioctl) {
        case KVM_S390_STORE_STATUS:
                idx = srcu_read_lock(&vcpu->kvm->srcu);
-               r = kvm_s390_vcpu_store_status(vcpu, arg);
+               r = kvm_s390_store_status_unloaded(vcpu, arg);
                srcu_read_unlock(&vcpu->kvm->srcu, idx);
                break;
        case KVM_S390_SET_INITIAL_PSW: {
                r = kvm_arch_vcpu_ioctl_set_initial_psw(vcpu, psw);
                break;
        }
+       case KVM_S390_CLEAR_RESET:
+               r = 0;
+               kvm_arch_vcpu_ioctl_clear_reset(vcpu);
+               break;
        case KVM_S390_INITIAL_RESET:
-               r = kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+               r = 0;
+               kvm_arch_vcpu_ioctl_initial_reset(vcpu);
+               break;
+       case KVM_S390_NORMAL_RESET:
+               r = 0;
+               kvm_arch_vcpu_ioctl_normal_reset(vcpu);
                break;
        case KVM_SET_ONE_REG:
        case KVM_GET_ONE_REG: {
index 608fa835c764dacebd0e1020e8b991dbdd068755,fe1ea294730c079034642879d85c18335e032424..67abc1dd50ee6aeaf082445a9fe78ad103dacf90
@@@ -36,6 -36,7 +36,7 @@@ TEST_GEN_PROGS_aarch64 += kvm_create_ma
  
  TEST_GEN_PROGS_s390x = s390x/memop
  TEST_GEN_PROGS_s390x += s390x/sync_regs_test
+ TEST_GEN_PROGS_s390x += s390x/resets
  TEST_GEN_PROGS_s390x += dirty_log_test
  TEST_GEN_PROGS_s390x += kvm_create_max_vcpus
  
@@@ -45,11 -46,9 +46,11 @@@ LIBKVM += $(LIBKVM_$(UNAME_M)
  INSTALL_HDR_PATH = $(top_srcdir)/usr
  LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/
  LINUX_TOOL_INCLUDE = $(top_srcdir)/tools/include
 +LINUX_TOOL_ARCH_INCLUDE = $(top_srcdir)/tools/arch/x86/include
  CFLAGS += -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 \
        -fno-stack-protector -fno-PIE -I$(LINUX_TOOL_INCLUDE) \
 -      -I$(LINUX_HDR_PATH) -Iinclude -I$(<D) -Iinclude/$(UNAME_M) -I..
 +      -I$(LINUX_TOOL_ARCH_INCLUDE) -I$(LINUX_HDR_PATH) -Iinclude \
 +      -I$(<D) -Iinclude/$(UNAME_M) -I..
  
  no-pie-option := $(call try-run, echo 'int main() { return 0; }' | \
          $(CC) -Werror -no-pie -x c - -o "$$TMP", -no-pie)
This page took 0.129963 seconds and 4 git commands to generate.