Commit 85eae57b authored by Paolo Bonzini's avatar Paolo Bonzini

Merge tag 'kvm-s390-next-4.19-1' of...

Merge tag 'kvm-s390-next-4.19-1' of git://git.kernel.org/pub/scm/linux/kernel/git/kvms390/linux into HEAD

KVM: s390: Features for 4.19

- initial version for host large page support. Must be enabled with
  module parameter hpage=1 and will conflict with the nested=1
  parameter.
- enable etoken facility for guests
- Fixes
parents 3a1174cd 23758461
...@@ -4391,6 +4391,22 @@ all such vmexits. ...@@ -4391,6 +4391,22 @@ all such vmexits.
Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits. Do not enable KVM_FEATURE_PV_UNHALT if you disable HLT exits.
7.14 KVM_CAP_S390_HPAGE_1M
Architectures: s390
Parameters: none
Returns: 0 on success, -EINVAL if hpage module parameter was not set
or cmma is enabled
With this capability the KVM support for memory backing with 1m pages
through hugetlbfs can be enabled for a VM. After the capability is
enabled, cmma can't be enabled anymore and pfmfi and the storage key
interpretation are disabled. If cmma has already been enabled or the
hpage module parameter is not set to 1, -EINVAL is returned.
While it is generally possible to create a huge page backed VM without
this capability, the VM will not be able to run.
8. Other capabilities. 8. Other capabilities.
---------------------- ----------------------
......
...@@ -9,6 +9,14 @@ ...@@ -9,6 +9,14 @@
#ifndef _ASM_S390_GMAP_H #ifndef _ASM_S390_GMAP_H
#define _ASM_S390_GMAP_H #define _ASM_S390_GMAP_H
/* Generic bits for GMAP notification on DAT table entry changes. */
#define GMAP_NOTIFY_SHADOW 0x2
#define GMAP_NOTIFY_MPROT 0x1
/* Status bits only for huge segment entries */
#define _SEGMENT_ENTRY_GMAP_IN 0x8000 /* invalidation notify bit */
#define _SEGMENT_ENTRY_GMAP_UC 0x4000 /* dirty (migration) */
/** /**
* struct gmap_struct - guest address space * struct gmap_struct - guest address space
* @list: list head for the mm->context gmap list * @list: list head for the mm->context gmap list
...@@ -132,4 +140,6 @@ void gmap_pte_notify(struct mm_struct *, unsigned long addr, pte_t *, ...@@ -132,4 +140,6 @@ void gmap_pte_notify(struct mm_struct *, unsigned long addr, pte_t *,
int gmap_mprotect_notify(struct gmap *, unsigned long start, int gmap_mprotect_notify(struct gmap *, unsigned long start,
unsigned long len, int prot); unsigned long len, int prot);
void gmap_sync_dirty_log_pmd(struct gmap *gmap, unsigned long dirty_bitmap[4],
unsigned long gaddr, unsigned long vmaddr);
#endif /* _ASM_S390_GMAP_H */ #endif /* _ASM_S390_GMAP_H */
...@@ -37,7 +37,10 @@ static inline int prepare_hugepage_range(struct file *file, ...@@ -37,7 +37,10 @@ static inline int prepare_hugepage_range(struct file *file,
return 0; return 0;
} }
#define arch_clear_hugepage_flags(page) do { } while (0) static inline void arch_clear_hugepage_flags(struct page *page)
{
clear_bit(PG_arch_1, &page->flags);
}
static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr, static inline void huge_pte_clear(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, unsigned long sz) pte_t *ptep, unsigned long sz)
......
...@@ -269,6 +269,7 @@ struct kvm_s390_sie_block { ...@@ -269,6 +269,7 @@ struct kvm_s390_sie_block {
__u8 reserved1c0[8]; /* 0x01c0 */ __u8 reserved1c0[8]; /* 0x01c0 */
#define ECD_HOSTREGMGMT 0x20000000 #define ECD_HOSTREGMGMT 0x20000000
#define ECD_MEF 0x08000000 #define ECD_MEF 0x08000000
#define ECD_ETOKENF 0x02000000
__u32 ecd; /* 0x01c8 */ __u32 ecd; /* 0x01c8 */
__u8 reserved1cc[18]; /* 0x01cc */ __u8 reserved1cc[18]; /* 0x01cc */
__u64 pp; /* 0x01de */ __u64 pp; /* 0x01de */
...@@ -655,6 +656,7 @@ struct kvm_vcpu_arch { ...@@ -655,6 +656,7 @@ struct kvm_vcpu_arch {
seqcount_t cputm_seqcount; seqcount_t cputm_seqcount;
__u64 cputm_start; __u64 cputm_start;
bool gs_enabled; bool gs_enabled;
bool skey_enabled;
}; };
struct kvm_vm_stat { struct kvm_vm_stat {
...@@ -793,12 +795,6 @@ struct kvm_s390_vsie { ...@@ -793,12 +795,6 @@ struct kvm_s390_vsie {
struct page *pages[KVM_MAX_VCPUS]; struct page *pages[KVM_MAX_VCPUS];
}; };
struct kvm_s390_migration_state {
unsigned long bitmap_size; /* in bits (number of guest pages) */
atomic64_t dirty_pages; /* number of dirty pages */
unsigned long *pgste_bitmap;
};
struct kvm_arch{ struct kvm_arch{
void *sca; void *sca;
int use_esca; int use_esca;
...@@ -828,7 +824,8 @@ struct kvm_arch{ ...@@ -828,7 +824,8 @@ struct kvm_arch{
struct kvm_s390_vsie vsie; struct kvm_s390_vsie vsie;
u8 epdx; u8 epdx;
u64 epoch; u64 epoch;
struct kvm_s390_migration_state *migration_state; int migration_mode;
atomic64_t cmma_dirty_pages;
/* subset of available cpu features enabled by user space */ /* subset of available cpu features enabled by user space */
DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS); DECLARE_BITMAP(cpu_feat, KVM_S390_VM_CPU_FEAT_NR_BITS);
struct kvm_s390_gisa *gisa; struct kvm_s390_gisa *gisa;
......
...@@ -24,6 +24,8 @@ typedef struct { ...@@ -24,6 +24,8 @@ typedef struct {
unsigned int uses_skeys:1; unsigned int uses_skeys:1;
/* The mmu context uses CMM. */ /* The mmu context uses CMM. */
unsigned int uses_cmm:1; unsigned int uses_cmm:1;
/* The gmaps associated with this context are allowed to use huge pages. */
unsigned int allow_gmap_hpage_1m:1;
} mm_context_t; } mm_context_t;
#define INIT_MM_CONTEXT(name) \ #define INIT_MM_CONTEXT(name) \
......
...@@ -32,6 +32,7 @@ static inline int init_new_context(struct task_struct *tsk, ...@@ -32,6 +32,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.has_pgste = 0; mm->context.has_pgste = 0;
mm->context.uses_skeys = 0; mm->context.uses_skeys = 0;
mm->context.uses_cmm = 0; mm->context.uses_cmm = 0;
mm->context.allow_gmap_hpage_1m = 0;
#endif #endif
switch (mm->context.asce_limit) { switch (mm->context.asce_limit) {
case _REGION2_SIZE: case _REGION2_SIZE:
......
...@@ -268,8 +268,10 @@ static inline int is_module_addr(void *addr) ...@@ -268,8 +268,10 @@ static inline int is_module_addr(void *addr)
#define _REGION_ENTRY_BITS_LARGE 0xffffffff8000fe2fUL #define _REGION_ENTRY_BITS_LARGE 0xffffffff8000fe2fUL
/* Bits in the segment table entry */ /* Bits in the segment table entry */
#define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL #define _SEGMENT_ENTRY_BITS 0xfffffffffffffe33UL
#define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff0ff33UL #define _SEGMENT_ENTRY_BITS_LARGE 0xfffffffffff0ff33UL
#define _SEGMENT_ENTRY_HARDWARE_BITS 0xfffffffffffffe30UL
#define _SEGMENT_ENTRY_HARDWARE_BITS_LARGE 0xfffffffffff00730UL
#define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */ #define _SEGMENT_ENTRY_ORIGIN_LARGE ~0xfffffUL /* large page address */
#define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* page table origin */ #define _SEGMENT_ENTRY_ORIGIN ~0x7ffUL/* page table origin */
#define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */ #define _SEGMENT_ENTRY_PROTECT 0x200 /* segment protection bit */
...@@ -1101,7 +1103,8 @@ int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr, ...@@ -1101,7 +1103,8 @@ int ptep_shadow_pte(struct mm_struct *mm, unsigned long saddr,
pte_t *sptep, pte_t *tptep, pte_t pte); pte_t *sptep, pte_t *tptep, pte_t pte);
void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep); void ptep_unshadow_pte(struct mm_struct *mm, unsigned long saddr, pte_t *ptep);
bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long address); bool ptep_test_and_clear_uc(struct mm_struct *mm, unsigned long address,
pte_t *ptep);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char key, bool nq); unsigned char key, bool nq);
int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int cond_set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
...@@ -1116,6 +1119,10 @@ int set_pgste_bits(struct mm_struct *mm, unsigned long addr, ...@@ -1116,6 +1119,10 @@ int set_pgste_bits(struct mm_struct *mm, unsigned long addr,
int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep); int get_pgste(struct mm_struct *mm, unsigned long hva, unsigned long *pgstep);
int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc, int pgste_perform_essa(struct mm_struct *mm, unsigned long hva, int orc,
unsigned long *oldpte, unsigned long *oldpgste); unsigned long *oldpte, unsigned long *oldpgste);
void gmap_pmdp_csp(struct mm_struct *mm, unsigned long vmaddr);
void gmap_pmdp_invalidate(struct mm_struct *mm, unsigned long vmaddr);
void gmap_pmdp_idte_local(struct mm_struct *mm, unsigned long vmaddr);
void gmap_pmdp_idte_global(struct mm_struct *mm, unsigned long vmaddr);
/* /*
* Certain architectures need to do special things when PTEs * Certain architectures need to do special things when PTEs
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* /*
* KVM s390 specific structures and definitions * KVM s390 specific structures and definitions
* *
* Copyright IBM Corp. 2008 * Copyright IBM Corp. 2008, 2018
* *
* Author(s): Carsten Otte <cotte@de.ibm.com> * Author(s): Carsten Otte <cotte@de.ibm.com>
* Christian Borntraeger <borntraeger@de.ibm.com> * Christian Borntraeger <borntraeger@de.ibm.com>
...@@ -225,6 +225,7 @@ struct kvm_guest_debug_arch { ...@@ -225,6 +225,7 @@ struct kvm_guest_debug_arch {
#define KVM_SYNC_FPRS (1UL << 8) #define KVM_SYNC_FPRS (1UL << 8)
#define KVM_SYNC_GSCB (1UL << 9) #define KVM_SYNC_GSCB (1UL << 9)
#define KVM_SYNC_BPBC (1UL << 10) #define KVM_SYNC_BPBC (1UL << 10)
#define KVM_SYNC_ETOKEN (1UL << 11)
/* length and alignment of the sdnx as a power of two */ /* length and alignment of the sdnx as a power of two */
#define SDNXC 8 #define SDNXC 8
#define SDNXL (1UL << SDNXC) #define SDNXL (1UL << SDNXC)
...@@ -258,6 +259,8 @@ struct kvm_sync_regs { ...@@ -258,6 +259,8 @@ struct kvm_sync_regs {
struct { struct {
__u64 reserved1[2]; __u64 reserved1[2];
__u64 gscb[4]; __u64 gscb[4];
__u64 etoken;
__u64 etoken_extension;
}; };
}; };
}; };
......
This diff is collapsed.
...@@ -205,13 +205,10 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu) ...@@ -205,13 +205,10 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu) int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)
{ {
int rc; int rc;
struct kvm_s390_sie_block *sie_block = vcpu->arch.sie_block;
trace_kvm_s390_skey_related_inst(vcpu); trace_kvm_s390_skey_related_inst(vcpu);
/* Already enabled? */ /* Already enabled? */
if (vcpu->kvm->arch.use_skf && if (vcpu->arch.skey_enabled)
!(sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)) &&
!kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS))
return 0; return 0;
rc = s390_enable_skey(); rc = s390_enable_skey();
...@@ -222,9 +219,10 @@ int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu) ...@@ -222,9 +219,10 @@ int kvm_s390_skey_check_enable(struct kvm_vcpu *vcpu)
if (kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS)) if (kvm_s390_test_cpuflags(vcpu, CPUSTAT_KSS))
kvm_s390_clear_cpuflags(vcpu, CPUSTAT_KSS); kvm_s390_clear_cpuflags(vcpu, CPUSTAT_KSS);
if (!vcpu->kvm->arch.use_skf) if (!vcpu->kvm->arch.use_skf)
sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE; vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
else else
sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE); vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
vcpu->arch.skey_enabled = true;
return 0; return 0;
} }
...@@ -246,9 +244,10 @@ static int try_handle_skey(struct kvm_vcpu *vcpu) ...@@ -246,9 +244,10 @@ static int try_handle_skey(struct kvm_vcpu *vcpu)
static int handle_iske(struct kvm_vcpu *vcpu) static int handle_iske(struct kvm_vcpu *vcpu)
{ {
unsigned long addr; unsigned long gaddr, vmaddr;
unsigned char key; unsigned char key;
int reg1, reg2; int reg1, reg2;
bool unlocked;
int rc; int rc;
vcpu->stat.instruction_iske++; vcpu->stat.instruction_iske++;
...@@ -262,18 +261,28 @@ static int handle_iske(struct kvm_vcpu *vcpu) ...@@ -262,18 +261,28 @@ static int handle_iske(struct kvm_vcpu *vcpu)
kvm_s390_get_regs_rre(vcpu, &reg1, &reg2); kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
addr = kvm_s390_logical_to_effective(vcpu, addr); gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
addr = kvm_s390_real_to_abs(vcpu, addr); gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr)); vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr));
if (kvm_is_error_hva(addr)) if (kvm_is_error_hva(vmaddr))
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
retry:
unlocked = false;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
rc = get_guest_storage_key(current->mm, addr, &key); rc = get_guest_storage_key(current->mm, vmaddr, &key);
up_read(&current->mm->mmap_sem);
if (rc) {
rc = fixup_user_fault(current, current->mm, vmaddr,
FAULT_FLAG_WRITE, &unlocked);
if (!rc) {
up_read(&current->mm->mmap_sem);
goto retry;
}
}
if (rc) if (rc)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
up_read(&current->mm->mmap_sem);
vcpu->run->s.regs.gprs[reg1] &= ~0xff; vcpu->run->s.regs.gprs[reg1] &= ~0xff;
vcpu->run->s.regs.gprs[reg1] |= key; vcpu->run->s.regs.gprs[reg1] |= key;
return 0; return 0;
...@@ -281,8 +290,9 @@ static int handle_iske(struct kvm_vcpu *vcpu) ...@@ -281,8 +290,9 @@ static int handle_iske(struct kvm_vcpu *vcpu)
static int handle_rrbe(struct kvm_vcpu *vcpu) static int handle_rrbe(struct kvm_vcpu *vcpu)
{ {
unsigned long addr; unsigned long vmaddr, gaddr;
int reg1, reg2; int reg1, reg2;
bool unlocked;
int rc; int rc;
vcpu->stat.instruction_rrbe++; vcpu->stat.instruction_rrbe++;
...@@ -296,19 +306,27 @@ static int handle_rrbe(struct kvm_vcpu *vcpu) ...@@ -296,19 +306,27 @@ static int handle_rrbe(struct kvm_vcpu *vcpu)
kvm_s390_get_regs_rre(vcpu, &reg1, &reg2); kvm_s390_get_regs_rre(vcpu, &reg1, &reg2);
addr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK; gaddr = vcpu->run->s.regs.gprs[reg2] & PAGE_MASK;
addr = kvm_s390_logical_to_effective(vcpu, addr); gaddr = kvm_s390_logical_to_effective(vcpu, gaddr);
addr = kvm_s390_real_to_abs(vcpu, addr); gaddr = kvm_s390_real_to_abs(vcpu, gaddr);
addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(addr)); vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(gaddr));
if (kvm_is_error_hva(addr)) if (kvm_is_error_hva(vmaddr))
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
retry:
unlocked = false;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
rc = reset_guest_reference_bit(current->mm, addr); rc = reset_guest_reference_bit(current->mm, vmaddr);
up_read(&current->mm->mmap_sem); if (rc < 0) {
rc = fixup_user_fault(current, current->mm, vmaddr,
FAULT_FLAG_WRITE, &unlocked);
if (!rc) {
up_read(&current->mm->mmap_sem);
goto retry;
}
}
if (rc < 0) if (rc < 0)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
up_read(&current->mm->mmap_sem);
kvm_s390_set_psw_cc(vcpu, rc); kvm_s390_set_psw_cc(vcpu, rc);
return 0; return 0;
} }
...@@ -323,6 +341,7 @@ static int handle_sske(struct kvm_vcpu *vcpu) ...@@ -323,6 +341,7 @@ static int handle_sske(struct kvm_vcpu *vcpu)
unsigned long start, end; unsigned long start, end;
unsigned char key, oldkey; unsigned char key, oldkey;
int reg1, reg2; int reg1, reg2;
bool unlocked;
int rc; int rc;
vcpu->stat.instruction_sske++; vcpu->stat.instruction_sske++;
...@@ -355,19 +374,28 @@ static int handle_sske(struct kvm_vcpu *vcpu) ...@@ -355,19 +374,28 @@ static int handle_sske(struct kvm_vcpu *vcpu)
} }
while (start != end) { while (start != end) {
unsigned long addr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start)); unsigned long vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
unlocked = false;
if (kvm_is_error_hva(addr)) if (kvm_is_error_hva(vmaddr))
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
rc = cond_set_guest_storage_key(current->mm, addr, key, &oldkey, rc = cond_set_guest_storage_key(current->mm, vmaddr, key, &oldkey,
m3 & SSKE_NQ, m3 & SSKE_MR, m3 & SSKE_NQ, m3 & SSKE_MR,
m3 & SSKE_MC); m3 & SSKE_MC);
up_read(&current->mm->mmap_sem);
if (rc < 0) if (rc < 0) {
rc = fixup_user_fault(current, current->mm, vmaddr,
FAULT_FLAG_WRITE, &unlocked);
rc = !rc ? -EAGAIN : rc;
}
if (rc == -EFAULT)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
start += PAGE_SIZE;
up_read(&current->mm->mmap_sem);
if (rc >= 0)
start += PAGE_SIZE;
} }
if (m3 & (SSKE_MC | SSKE_MR)) { if (m3 & (SSKE_MC | SSKE_MR)) {
...@@ -948,15 +976,16 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) ...@@ -948,15 +976,16 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
} }
while (start != end) { while (start != end) {
unsigned long useraddr; unsigned long vmaddr;
bool unlocked = false;
/* Translate guest address to host address */ /* Translate guest address to host address */
useraddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start)); vmaddr = gfn_to_hva(vcpu->kvm, gpa_to_gfn(start));
if (kvm_is_error_hva(useraddr)) if (kvm_is_error_hva(vmaddr))
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) { if (vcpu->run->s.regs.gprs[reg1] & PFMF_CF) {
if (clear_user((void __user *)useraddr, PAGE_SIZE)) if (kvm_clear_guest(vcpu->kvm, start, PAGE_SIZE))
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
} }
...@@ -966,14 +995,20 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) ...@@ -966,14 +995,20 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
if (rc) if (rc)
return rc; return rc;
down_read(&current->mm->mmap_sem); down_read(&current->mm->mmap_sem);
rc = cond_set_guest_storage_key(current->mm, useraddr, rc = cond_set_guest_storage_key(current->mm, vmaddr,
key, NULL, nq, mr, mc); key, NULL, nq, mr, mc);
up_read(&current->mm->mmap_sem); if (rc < 0) {
if (rc < 0) rc = fixup_user_fault(current, current->mm, vmaddr,
FAULT_FLAG_WRITE, &unlocked);
rc = !rc ? -EAGAIN : rc;
}
if (rc == -EFAULT)
return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING);
}
start += PAGE_SIZE; up_read(&current->mm->mmap_sem);
if (rc >= 0)
start += PAGE_SIZE;
}
} }
if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) { if (vcpu->run->s.regs.gprs[reg1] & PFMF_FSC) {
if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT) { if (psw_bits(vcpu->arch.sie_block->gpsw).eaba == PSW_BITS_AMODE_64BIT) {
...@@ -987,9 +1022,11 @@ static int handle_pfmf(struct kvm_vcpu *vcpu) ...@@ -987,9 +1022,11 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
static inline int do_essa(struct kvm_vcpu *vcpu, const int orc) /*
* Must be called with relevant read locks held (kvm->mm->mmap_sem, kvm->srcu)
*/
static inline int __do_essa(struct kvm_vcpu *vcpu, const int orc)
{ {
struct kvm_s390_migration_state *ms = vcpu->kvm->arch.migration_state;
int r1, r2, nappended, entries; int r1, r2, nappended, entries;
unsigned long gfn, hva, res, pgstev, ptev; unsigned long gfn, hva, res, pgstev, ptev;
unsigned long *cbrlo; unsigned long *cbrlo;
...@@ -1039,10 +1076,12 @@ static inline int do_essa(struct kvm_vcpu *vcpu, const int orc) ...@@ -1039,10 +1076,12 @@ static inline int do_essa(struct kvm_vcpu *vcpu, const int orc)
cbrlo[entries] = gfn << PAGE_SHIFT; cbrlo[entries] = gfn << PAGE_SHIFT;
} }
if (orc && gfn < ms->bitmap_size) { if (orc) {
/* increment only if we are really flipping the bit to 1 */ struct kvm_memory_slot *ms = gfn_to_memslot(vcpu->kvm, gfn);
if (!test_and_set_bit(gfn, ms->pgste_bitmap))
atomic64_inc(&ms->dirty_pages); /* Increment only if we are really flipping the bit */
if (ms && !test_and_set_bit(gfn - ms->base_gfn, kvm_second_dirty_bitmap(ms)))
atomic64_inc(&vcpu->kvm->arch.cmma_dirty_pages);
} }
return nappended; return nappended;
...@@ -1071,7 +1110,7 @@ static int handle_essa(struct kvm_vcpu *vcpu) ...@@ -1071,7 +1110,7 @@ static int handle_essa(struct kvm_vcpu *vcpu)
: ESSA_SET_STABLE_IF_RESIDENT)) : 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 (!vcpu->kvm->arch.migration_mode) {
/* /*
* CMMA is enabled in the KVM settings, but is disabled in * CMMA is enabled in the KVM settings, but is disabled in
* the SIE block and in the mm_context, and we are not doing * the SIE block and in the mm_context, and we are not doing
...@@ -1099,10 +1138,16 @@ static int handle_essa(struct kvm_vcpu *vcpu) ...@@ -1099,10 +1138,16 @@ static int handle_essa(struct kvm_vcpu *vcpu)
/* Retry the ESSA instruction */ /* Retry the ESSA instruction */
kvm_s390_retry_instr(vcpu); kvm_s390_retry_instr(vcpu);
} else { } else {
/* Account for the possible extra cbrl entry */ int srcu_idx;
i = do_essa(vcpu, orc);
down_read(&vcpu->kvm->mm->mmap_sem);
srcu_idx = srcu_read_lock(&vcpu->kvm->srcu);
i = __do_essa(vcpu, orc);
srcu_read_unlock(&vcpu->kvm->srcu, srcu_idx);
up_read(&vcpu->kvm->mm->mmap_sem);
if (i < 0) if (i < 0)
return i; return i;
/* Account for the possible extra cbrl entry */
entries += i; entries += i;
} }
vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */ vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* /*
* kvm nested virtualization support for s390x * kvm nested virtualization support for s390x
* *
* Copyright IBM Corp. 2016 * Copyright IBM Corp. 2016, 2018
* *
* Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com> * Author(s): David Hildenbrand <dahi@linux.vnet.ibm.com>
*/ */
...@@ -378,6 +378,10 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -378,6 +378,10 @@ static int shadow_scb(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
if (test_kvm_facility(vcpu->kvm, 139)) if (test_kvm_facility(vcpu->kvm, 139))
scb_s->ecd |= scb_o->ecd & ECD_MEF; scb_s->ecd |= scb_o->ecd & ECD_MEF;
/* etoken */
if (test_kvm_facility(vcpu->kvm, 156))
scb_s->ecd |= scb_o->ecd & ECD_ETOKENF;
prepare_ibc(vcpu, vsie_page); prepare_ibc(vcpu, vsie_page);
rc = shadow_crycb(vcpu, vsie_page); rc = shadow_crycb(vcpu, vsie_page);
out: out:
...@@ -627,7 +631,8 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -627,7 +631,8 @@ static int pin_blocks(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
vsie_page->riccbd_gpa = gpa; vsie_page->riccbd_gpa = gpa;
scb_s->riccbd = hpa; scb_s->riccbd = hpa;
} }
if ((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) { if (((scb_s->ecb & ECB_GS) && !(scb_s->ecd & ECD_HOSTREGMGMT)) ||
(scb_s->ecd & ECD_ETOKENF)) {
unsigned long sdnxc; unsigned long sdnxc;
gpa = READ_ONCE(scb_o->sdnxo) & ~0xfUL; gpa = READ_ONCE(scb_o->sdnxo) & ~0xfUL;
...@@ -818,6 +823,8 @@ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) ...@@ -818,6 +823,8 @@ static int handle_stfle(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
* - < 0 if an error occurred * - < 0 if an error occurred
*/ */
static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page) static int do_vsie_run(struct kvm_vcpu *vcpu, struct vsie_page *vsie_page)
__releases(vcpu->kvm->srcu)
__acquires(vcpu->kvm->srcu)
{ {
struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s; struct kvm_s390_sie_block *scb_s = &vsie_page->scb_s;
struct kvm_s390_sie_block *scb_o = vsie_page->scb_o; struct kvm_s390_sie_block *scb_o = vsie_page->scb_o;
......
This diff is collapsed.
...@@ -123,6 +123,29 @@ static inline pte_t __rste_to_pte(unsigned long rste) ...@@ -123,6 +123,29 @@ static inline pte_t __rste_to_pte(unsigned long rste)
return pte; return pte;
} }
static void clear_huge_pte_skeys(struct mm_struct *mm, unsigned long rste)
{
struct page *page;
unsigned long size, paddr;
if (!mm_uses_skeys(mm) ||
rste & _SEGMENT_ENTRY_INVALID)
return;
if ((rste & _REGION_ENTRY_TYPE_MASK) == _REGION_ENTRY_TYPE_R3) {
page = pud_page(__pud(rste));
size = PUD_SIZE;
paddr = rste & PUD_MASK;
} else {
page = pmd_page(__pmd(rste));
size = PMD_SIZE;
paddr = rste & PMD_MASK;
}
if (!test_and_set_bit(PG_arch_1, &page->flags))
__storage_key_init_range(paddr, paddr + size - 1);
}
void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
pte_t *ptep, pte_t pte) pte_t *ptep, pte_t pte)
{ {
...@@ -137,6 +160,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, ...@@ -137,6 +160,7 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE; rste |= _REGION_ENTRY_TYPE_R3 | _REGION3_ENTRY_LARGE;
else else
rste |= _SEGMENT_ENTRY_LARGE; rste |= _SEGMENT_ENTRY_LARGE;
clear_huge_pte_skeys(mm, rste);
pte_val(*ptep) = rste; pte_val(*ptep) = rste;
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
static inline unsigned long sske_frame(unsigned long addr, unsigned char skey) static inline unsigned long sske_frame(unsigned long addr, unsigned char skey)
{ {
asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],9,0" asm volatile(".insn rrf,0xb22b0000,%[skey],%[addr],1,0"
: [addr] "+a" (addr) : [skey] "d" (skey)); : [addr] "+a" (addr) : [skey] "d" (skey));
return addr; return addr;
} }
...@@ -23,8 +23,6 @@ void __storage_key_init_range(unsigned long start, unsigned long end) ...@@ -23,8 +23,6 @@ void __storage_key_init_range(unsigned long start, unsigned long end)
{ {
unsigned long boundary, size; unsigned long boundary, size;
if (!PAGE_DEFAULT_KEY)
return;
while (start < end) { while (start < end) {
if (MACHINE_HAS_EDAT1) { if (MACHINE_HAS_EDAT1) {
/* set storage keys for a 1MB frame */ /* set storage keys for a 1MB frame */
...@@ -37,7 +35,7 @@ void __storage_key_init_range(unsigned long start, unsigned long end) ...@@ -37,7 +35,7 @@ void __storage_key_init_range(unsigned long start, unsigned long end)
continue; continue;
} }
} }
page_set_storage_key(start, PAGE_DEFAULT_KEY, 0); page_set_storage_key(start, PAGE_DEFAULT_KEY, 1);
start += PAGE_SIZE; start += PAGE_SIZE;
} }
} }
......
...@@ -347,18 +347,27 @@ static inline void pmdp_idte_local(struct mm_struct *mm, ...@@ -347,18 +347,27 @@ static inline void pmdp_idte_local(struct mm_struct *mm,
mm->context.asce, IDTE_LOCAL); mm->context.asce, IDTE_LOCAL);
else else
__pmdp_idte(addr, pmdp, 0, 0, IDTE_LOCAL); __pmdp_idte(addr, pmdp, 0, 0, IDTE_LOCAL);
if (mm_has_pgste(mm) && mm->context.allow_gmap_hpage_1m)
gmap_pmdp_idte_local(mm, addr);
} }
static inline void pmdp_idte_global(struct mm_struct *mm, static inline void pmdp_idte_global(struct mm_struct *mm,
unsigned long addr, pmd_t *pmdp) unsigned long addr, pmd_t *pmdp)
{ {
if (MACHINE_HAS_TLB_GUEST) if (MACHINE_HAS_TLB_GUEST) {
__pmdp_idte(addr, pmdp, IDTE_NODAT | IDTE_GUEST_ASCE, __pmdp_idte(addr, pmdp, IDTE_NODAT | IDTE_GUEST_ASCE,
mm->context.asce, IDTE_GLOBAL); mm->context.asce, IDTE_GLOBAL);
else if (MACHINE_HAS_IDTE) if (mm_has_pgste(mm) && mm->context.allow_gmap_hpage_1m)
gmap_pmdp_idte_global(mm, addr);
} else if (MACHINE_HAS_IDTE) {
__pmdp_idte(addr, pmdp, 0, 0, IDTE_GLOBAL); __pmdp_idte(addr, pmdp, 0, 0, IDTE_GLOBAL);
else if (mm_has_pgste(mm) && mm->context.allow_gmap_hpage_1m)
gmap_pmdp_idte_global(mm, addr);
} else {
__pmdp_csp(pmdp); __pmdp_csp(pmdp);
if (mm_has_pgste(mm) && mm->context.allow_gmap_hpage_1m)
gmap_pmdp_csp(mm, addr);
}
} }
static inline pmd_t pmdp_flush_direct(struct mm_struct *mm, static inline pmd_t pmdp_flush_direct(struct mm_struct *mm,
...@@ -392,6 +401,8 @@ static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm, ...@@ -392,6 +401,8 @@ static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm,
cpumask_of(smp_processor_id()))) { cpumask_of(smp_processor_id()))) {
pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID; pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
mm->context.flush_mm = 1; mm->context.flush_mm = 1;
if (mm_has_pgste(mm))
gmap_pmdp_invalidate(mm, addr);
} else { } else {
pmdp_idte_global(mm, addr, pmdp); pmdp_idte_global(mm, addr, pmdp);
} }
...@@ -399,6 +410,24 @@ static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm, ...@@ -399,6 +410,24 @@ static inline pmd_t pmdp_flush_lazy(struct mm_struct *mm,
return old; return old;
} }
static pmd_t *pmd_alloc_map(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pgd = pgd_offset(mm, addr);
p4d = p4d_alloc(mm, pgd, addr);
if (!p4d)
return NULL;
pud = pud_alloc(mm, p4d, addr);
if (!pud)
return NULL;
pmd = pmd_alloc(mm, pud, addr);
return pmd;
}
pmd_t pmdp_xchg_direct(struct mm_struct *mm, unsigned long addr, pmd_t pmdp_xchg_direct(struct mm_struct *mm, unsigned long addr,
pmd_t *pmdp, pmd_t new) pmd_t *pmdp, pmd_t new)
{ {
...@@ -693,40 +722,14 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep) ...@@ -693,40 +722,14 @@ void ptep_zap_key(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
/* /*
* Test and reset if a guest page is dirty * Test and reset if a guest page is dirty
*/ */
bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr) bool ptep_test_and_clear_uc(struct mm_struct *mm, unsigned long addr,
pte_t *ptep)
{ {
spinlock_t *ptl;
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pgste_t pgste; pgste_t pgste;
pte_t *ptep;
pte_t pte; pte_t pte;
bool dirty; bool dirty;
int nodat; int nodat;
pgd = pgd_offset(mm, addr);
p4d = p4d_alloc(mm, pgd, addr);
if (!p4d)
return false;
pud = pud_alloc(mm, p4d, addr);
if (!pud)
return false;
pmd = pmd_alloc(mm, pud, addr);
if (!pmd)
return false;
/* We can't run guests backed by huge pages, but userspace can
* still set them up and then try to migrate them without any
* migration support.
*/
if (pmd_large(*pmd))
return true;
ptep = pte_alloc_map_lock(mm, pmd, addr, &ptl);
if (unlikely(!ptep))
return false;
pgste = pgste_get_lock(ptep); pgste = pgste_get_lock(ptep);
dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT); dirty = !!(pgste_val(pgste) & PGSTE_UC_BIT);
pgste_val(pgste) &= ~PGSTE_UC_BIT; pgste_val(pgste) &= ~PGSTE_UC_BIT;
...@@ -742,21 +745,43 @@ bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr) ...@@ -742,21 +745,43 @@ bool test_and_clear_guest_dirty(struct mm_struct *mm, unsigned long addr)
*ptep = pte; *ptep = pte;
} }
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
spin_unlock(ptl);
return dirty; return dirty;
} }
EXPORT_SYMBOL_GPL(test_and_clear_guest_dirty); EXPORT_SYMBOL_GPL(ptep_test_and_clear_uc);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char key, bool nq) unsigned char key, bool nq)
{ {
unsigned long keyul; unsigned long keyul, paddr;
spinlock_t *ptl; spinlock_t *ptl;
pgste_t old, new; pgste_t old, new;
pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
ptep = get_locked_pte(mm, addr, &ptl); pmdp = pmd_alloc_map(mm, addr);
if (unlikely(!pmdp))
return -EFAULT;
ptl = pmd_lock(mm, pmdp);
if (!pmd_present(*pmdp)) {
spin_unlock(ptl);
return -EFAULT;
}
if (pmd_large(*pmdp)) {
paddr = pmd_val(*pmdp) & HPAGE_MASK;
paddr |= addr & ~HPAGE_MASK;
/*
* Huge pmds need quiescing operations, they are
* always mapped.
*/
page_set_storage_key(paddr, key, 1);
spin_unlock(ptl);
return 0;
}
spin_unlock(ptl);
ptep = pte_alloc_map_lock(mm, pmdp, addr, &ptl);
if (unlikely(!ptep)) if (unlikely(!ptep))
return -EFAULT; return -EFAULT;
...@@ -767,14 +792,14 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr, ...@@ -767,14 +792,14 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
pgste_val(new) |= (keyul & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48; pgste_val(new) |= (keyul & (_PAGE_CHANGED | _PAGE_REFERENCED)) << 48;
pgste_val(new) |= (keyul & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56; pgste_val(new) |= (keyul & (_PAGE_ACC_BITS | _PAGE_FP_BIT)) << 56;
if (!(pte_val(*ptep) & _PAGE_INVALID)) { if (!(pte_val(*ptep) & _PAGE_INVALID)) {
unsigned long address, bits, skey; unsigned long bits, skey;
address = pte_val(*ptep) & PAGE_MASK; paddr = pte_val(*ptep) & PAGE_MASK;
skey = (unsigned long) page_get_storage_key(address); skey = (unsigned long) page_get_storage_key(paddr);
bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED); bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
skey = key & (_PAGE_ACC_BITS | _PAGE_FP_BIT); skey = key & (_PAGE_ACC_BITS | _PAGE_FP_BIT);
/* Set storage key ACC and FP */ /* Set storage key ACC and FP */
page_set_storage_key(address, skey, !nq); page_set_storage_key(paddr, skey, !nq);
/* Merge host changed & referenced into pgste */ /* Merge host changed & referenced into pgste */
pgste_val(new) |= bits << 52; pgste_val(new) |= bits << 52;
} }
...@@ -830,11 +855,32 @@ EXPORT_SYMBOL(cond_set_guest_storage_key); ...@@ -830,11 +855,32 @@ EXPORT_SYMBOL(cond_set_guest_storage_key);
int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr) int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr)
{ {
spinlock_t *ptl; spinlock_t *ptl;
unsigned long paddr;
pgste_t old, new; pgste_t old, new;
pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
int cc = 0; int cc = 0;
ptep = get_locked_pte(mm, addr, &ptl); pmdp = pmd_alloc_map(mm, addr);
if (unlikely(!pmdp))
return -EFAULT;
ptl = pmd_lock(mm, pmdp);
if (!pmd_present(*pmdp)) {
spin_unlock(ptl);
return -EFAULT;
}
if (pmd_large(*pmdp)) {
paddr = pmd_val(*pmdp) & HPAGE_MASK;
paddr |= addr & ~HPAGE_MASK;
cc = page_reset_referenced(paddr);
spin_unlock(ptl);
return cc;
}
spin_unlock(ptl);
ptep = pte_alloc_map_lock(mm, pmdp, addr, &ptl);
if (unlikely(!ptep)) if (unlikely(!ptep))
return -EFAULT; return -EFAULT;
...@@ -843,7 +889,8 @@ int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr) ...@@ -843,7 +889,8 @@ int reset_guest_reference_bit(struct mm_struct *mm, unsigned long addr)
pgste_val(new) &= ~PGSTE_GR_BIT; pgste_val(new) &= ~PGSTE_GR_BIT;
if (!(pte_val(*ptep) & _PAGE_INVALID)) { if (!(pte_val(*ptep) & _PAGE_INVALID)) {
cc = page_reset_referenced(pte_val(*ptep) & PAGE_MASK); paddr = pte_val(*ptep) & PAGE_MASK;
cc = page_reset_referenced(paddr);
/* Merge real referenced bit into host-set */ /* Merge real referenced bit into host-set */
pgste_val(new) |= ((unsigned long) cc << 53) & PGSTE_HR_BIT; pgste_val(new) |= ((unsigned long) cc << 53) & PGSTE_HR_BIT;
} }
...@@ -862,18 +909,42 @@ EXPORT_SYMBOL(reset_guest_reference_bit); ...@@ -862,18 +909,42 @@ EXPORT_SYMBOL(reset_guest_reference_bit);
int get_guest_storage_key(struct mm_struct *mm, unsigned long addr, int get_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned char *key) unsigned char *key)
{ {
unsigned long paddr;
spinlock_t *ptl; spinlock_t *ptl;
pgste_t pgste; pgste_t pgste;
pmd_t *pmdp;
pte_t *ptep; pte_t *ptep;
ptep = get_locked_pte(mm, addr, &ptl); pmdp = pmd_alloc_map(mm, addr);
if (unlikely(!pmdp))
return -EFAULT;
ptl = pmd_lock(mm, pmdp);
if (!pmd_present(*pmdp)) {
/* Not yet mapped memory has a zero key */
spin_unlock(ptl);
*key = 0;
return 0;
}
if (pmd_large(*pmdp)) {
paddr = pmd_val(*pmdp) & HPAGE_MASK;
paddr |= addr & ~HPAGE_MASK;
*key = page_get_storage_key(paddr);
spin_unlock(ptl);
return 0;
}
spin_unlock(ptl);
ptep = pte_alloc_map_lock(mm, pmdp, addr, &ptl);
if (unlikely(!ptep)) if (unlikely(!ptep))
return -EFAULT; return -EFAULT;
pgste = pgste_get_lock(ptep); pgste = pgste_get_lock(ptep);
*key = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56; *key = (pgste_val(pgste) & (PGSTE_ACC_BITS | PGSTE_FP_BIT)) >> 56;
paddr = pte_val(*ptep) & PAGE_MASK;
if (!(pte_val(*ptep) & _PAGE_INVALID)) if (!(pte_val(*ptep) & _PAGE_INVALID))
*key = page_get_storage_key(pte_val(*ptep) & PAGE_MASK); *key = page_get_storage_key(paddr);
/* Reflect guest's logical view, not physical */ /* Reflect guest's logical view, not physical */
*key |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48; *key |= (pgste_val(pgste) & (PGSTE_GR_BIT | PGSTE_GC_BIT)) >> 48;
pgste_set_unlock(ptep, pgste); pgste_set_unlock(ptep, pgste);
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* numbering scheme from the Princples of Operations: most significant bit * numbering scheme from the Princples of Operations: most significant bit
* has bit number 0. * has bit number 0.
* *
* Copyright IBM Corp. 2015 * Copyright IBM Corp. 2015, 2018
* *
*/ */
...@@ -106,6 +106,7 @@ static struct facility_def facility_defs[] = { ...@@ -106,6 +106,7 @@ static struct facility_def facility_defs[] = {
.name = "FACILITIES_KVM_CPUMODEL", .name = "FACILITIES_KVM_CPUMODEL",
.bits = (int[]){ .bits = (int[]){
156, /* etoken facility */
-1 /* END */ -1 /* END */
} }
}, },
......
...@@ -309,6 +309,13 @@ static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memsl ...@@ -309,6 +309,13 @@ static inline unsigned long kvm_dirty_bitmap_bytes(struct kvm_memory_slot *memsl
return ALIGN(memslot->npages, BITS_PER_LONG) / 8; return ALIGN(memslot->npages, BITS_PER_LONG) / 8;
} }
static inline unsigned long *kvm_second_dirty_bitmap(struct kvm_memory_slot *memslot)
{
unsigned long len = kvm_dirty_bitmap_bytes(memslot);
return memslot->dirty_bitmap + len / sizeof(*memslot->dirty_bitmap);
}
struct kvm_s390_adapter_int { struct kvm_s390_adapter_int {
u64 ind_addr; u64 ind_addr;
u64 summary_addr; u64 summary_addr;
......
...@@ -949,6 +949,7 @@ struct kvm_ppc_resize_hpt { ...@@ -949,6 +949,7 @@ struct kvm_ppc_resize_hpt {
#define KVM_CAP_GET_MSR_FEATURES 153 #define KVM_CAP_GET_MSR_FEATURES 153
#define KVM_CAP_HYPERV_EVENTFD 154 #define KVM_CAP_HYPERV_EVENTFD 154
#define KVM_CAP_HYPERV_TLBFLUSH 155 #define KVM_CAP_HYPERV_TLBFLUSH 155
#define KVM_CAP_S390_HPAGE_1M 156
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
......
...@@ -1169,7 +1169,7 @@ int kvm_get_dirty_log_protect(struct kvm *kvm, ...@@ -1169,7 +1169,7 @@ int kvm_get_dirty_log_protect(struct kvm *kvm,
n = kvm_dirty_bitmap_bytes(memslot); n = kvm_dirty_bitmap_bytes(memslot);
dirty_bitmap_buffer = dirty_bitmap + n / sizeof(long); dirty_bitmap_buffer = kvm_second_dirty_bitmap(memslot);
memset(dirty_bitmap_buffer, 0, n); memset(dirty_bitmap_buffer, 0, n);
spin_lock(&kvm->mmu_lock); spin_lock(&kvm->mmu_lock);
......
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