Commit 1bab1c02 authored by Claudio Imbrenda's avatar Claudio Imbrenda Committed by Christian Borntraeger

KVM: s390: expose no-DAT to guest and migration support

The STFLE bit 147 indicates whether the ESSA no-DAT operation code is
valid, the bit is not normally provided to the host; the host is
instead provided with an SCLP bit that indicates whether guests can
support the feature.

This patch:
* enables the STFLE bit in the guest if the corresponding SCLP bit is
  present in the host.
* adds support for migrating the no-DAT bit in the PGSTEs
* fixes the software interpretation of the ESSA instruction that is
  used when migrating, both for the new operation code and for the old
  "set stable", as per specifications.
Signed-off-by: default avatarClaudio Imbrenda <imbrenda@linux.vnet.ibm.com>
Reviewed-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Acked-by: default avatarCornelia Huck <cohuck@redhat.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
parent 631aebfe
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
#define ESSA_SET_STABLE_IF_RESIDENT 6 #define ESSA_SET_STABLE_IF_RESIDENT 6
#define ESSA_SET_STABLE_NODAT 7 #define ESSA_SET_STABLE_NODAT 7
#define ESSA_MAX ESSA_SET_STABLE_IF_RESIDENT #define ESSA_MAX ESSA_SET_STABLE_NODAT
#endif #endif
...@@ -1574,7 +1574,7 @@ static int kvm_s390_get_cmma_bits(struct kvm *kvm, ...@@ -1574,7 +1574,7 @@ static int kvm_s390_get_cmma_bits(struct kvm *kvm,
if (r < 0) if (r < 0)
pgstev = 0; pgstev = 0;
/* save the value */ /* save the value */
res[i++] = (pgstev >> 24) & 0x3; res[i++] = (pgstev >> 24) & 0x43;
/* /*
* if the next bit is too far away, stop. * if the next bit is too far away, stop.
* if we reached the previous "next", find the next one * if we reached the previous "next", find the next one
...@@ -1652,7 +1652,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm, ...@@ -1652,7 +1652,7 @@ static int kvm_s390_set_cmma_bits(struct kvm *kvm,
pgstev = bits[i]; pgstev = bits[i];
pgstev = pgstev << 24; pgstev = pgstev << 24;
mask &= _PGSTE_GPS_USAGE_MASK; mask &= _PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT;
set_pgste_bits(kvm->mm, hva, mask, pgstev); set_pgste_bits(kvm->mm, hva, mask, pgstev);
} }
srcu_read_unlock(&kvm->srcu, srcu_idx); srcu_read_unlock(&kvm->srcu, srcu_idx);
...@@ -1929,6 +1929,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) ...@@ -1929,6 +1929,10 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
set_kvm_facility(kvm->arch.model.fac_mask, 74); set_kvm_facility(kvm->arch.model.fac_mask, 74);
set_kvm_facility(kvm->arch.model.fac_list, 74); set_kvm_facility(kvm->arch.model.fac_list, 74);
if (MACHINE_HAS_TLB_GUEST) {
set_kvm_facility(kvm->arch.model.fac_mask, 147);
set_kvm_facility(kvm->arch.model.fac_list, 147);
}
kvm->arch.model.cpuid = kvm_s390_get_initial_cpuid(); kvm->arch.model.cpuid = kvm_s390_get_initial_cpuid();
kvm->arch.model.ibc = sclp.ibc & 0x0fff; kvm->arch.model.ibc = sclp.ibc & 0x0fff;
......
...@@ -988,6 +988,8 @@ static inline int do_essa(struct kvm_vcpu *vcpu, const int orc) ...@@ -988,6 +988,8 @@ static inline int do_essa(struct kvm_vcpu *vcpu, const int orc)
if (pgstev & _PGSTE_GPS_ZERO) if (pgstev & _PGSTE_GPS_ZERO)
res |= 1; res |= 1;
} }
if (pgstev & _PGSTE_GPS_NODAT)
res |= 0x20;
vcpu->run->s.regs.gprs[r1] = res; vcpu->run->s.regs.gprs[r1] = res;
/* /*
* It is possible that all the normal 511 slots were full, in which case * It is possible that all the normal 511 slots were full, in which case
...@@ -1027,7 +1029,9 @@ static int handle_essa(struct kvm_vcpu *vcpu) ...@@ -1027,7 +1029,9 @@ static int handle_essa(struct kvm_vcpu *vcpu)
return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
/* Check for invalid operation request code */ /* Check for invalid operation request code */
orc = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28; orc = (vcpu->arch.sie_block->ipb & 0xf0000000) >> 28;
if (orc > ESSA_MAX) /* ORCs 0-6 are always valid */
if (orc > (test_kvm_facility(vcpu->kvm, 147) ? ESSA_SET_STABLE_NODAT
: ESSA_SET_STABLE_IF_RESIDENT))
return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
if (likely(!vcpu->kvm->arch.migration_state)) { if (likely(!vcpu->kvm->arch.migration_state)) {
......
...@@ -919,7 +919,7 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc, ...@@ -919,7 +919,7 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
case ESSA_GET_STATE: case ESSA_GET_STATE:
break; break;
case ESSA_SET_STABLE: case ESSA_SET_STABLE:
pgstev &= ~_PGSTE_GPS_USAGE_MASK; pgstev &= ~(_PGSTE_GPS_USAGE_MASK | _PGSTE_GPS_NODAT);
pgstev |= _PGSTE_GPS_USAGE_STABLE; pgstev |= _PGSTE_GPS_USAGE_STABLE;
break; break;
case ESSA_SET_UNUSED: case ESSA_SET_UNUSED:
...@@ -965,6 +965,10 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc, ...@@ -965,6 +965,10 @@ int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
pgstev |= _PGSTE_GPS_USAGE_STABLE; pgstev |= _PGSTE_GPS_USAGE_STABLE;
} }
break; break;
case ESSA_SET_STABLE_NODAT:
pgstev &= ~_PGSTE_GPS_USAGE_MASK;
pgstev |= _PGSTE_GPS_USAGE_STABLE | _PGSTE_GPS_NODAT;
break;
default: default:
/* we should never get here! */ /* we should never get here! */
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment