* [PATCH 1/5] KVM: s390: make cmma usage conditionally
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
@ 2014-04-02 9:24 ` Christian Borntraeger
2014-04-02 9:24 ` [PATCH 2/5] KVM: s390: Adding skey bit to mmu context Christian Borntraeger
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Christian Borntraeger @ 2014-04-02 9:24 UTC (permalink / raw)
To: Paolo Bonzini, Martin Schwidefsky
Cc: KVM, linux-s390, Cornelia Huck, Dominik Dingel,
Christian Borntraeger
From: Dominik Dingel <dingel@linux.vnet.ibm.com>
Old userspace versions could reset the guest, without notifying kvm,
which could result in a cmma state unknow to the guest, resulting
in data corruption. Lets only enable CMMA if userspace understands
when it needs to reset the usage state.
CMMA should be enabled on vCPU creation, if it is already enabled
for the complete vm, if this fails, the creation should fail, to
be sure we have a consistent state.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
[Remove now unnecessary calls to page_table_reset_pgste]
---
arch/s390/include/asm/kvm_host.h | 1 +
arch/s390/kvm/diag.c | 6 ---
arch/s390/kvm/kvm-s390.c | 60 +++++++++++++++++++-----------
arch/s390/kvm/kvm-s390.h | 6 ++-
arch/s390/kvm/priv.c | 80 ++++++++++++++++++++--------------------
5 files changed, 84 insertions(+), 69 deletions(-)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index da93b6e..9f2f45d 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -290,6 +290,7 @@ struct kvm_arch{
struct gmap *gmap;
int css_support;
int use_irqchip;
+ int use_cmma;
struct s390_io_adapter *adapters[MAX_S390_IO_ADAPTERS];
struct kvm_s390_config *cfg;
};
diff --git a/arch/s390/kvm/diag.c b/arch/s390/kvm/diag.c
index 08dfc83..ff768f1 100644
--- a/arch/s390/kvm/diag.c
+++ b/arch/s390/kvm/diag.c
@@ -167,17 +167,11 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
switch (subcode) {
- case 0:
- case 1:
- page_table_reset_pgste(current->mm, 0, TASK_SIZE);
- return -EOPNOTSUPP;
case 3:
vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
- page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
case 4:
vcpu->run->s390_reset_flags = 0;
- page_table_reset_pgste(current->mm, 0, TASK_SIZE);
break;
default:
return -EOPNOTSUPP;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 4504015..fcb1c32 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -340,9 +340,8 @@ void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
if (kvm_is_ucontrol(vcpu->kvm))
gmap_free(vcpu->arch.gmap);
- if (vcpu->arch.sie_block->cbrlo)
- __free_page(__pfn_to_page(
- vcpu->arch.sie_block->cbrlo >> PAGE_SHIFT));
+ if (kvm_s390_cmma_enabled(vcpu->kvm))
+ kvm_s390_vcpu_unsetup_cmma(vcpu);
free_page((unsigned long)(vcpu->arch.sie_block));
kvm_vcpu_uninit(vcpu);
@@ -457,10 +456,31 @@ int kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
return 0;
}
-int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu)
+{
+ if (vcpu->arch.sie_block->cbrlo) {
+ __free_page(__pfn_to_page(vcpu->arch.sie_block->cbrlo >>
+ PAGE_SHIFT));
+ vcpu->arch.sie_block->cbrlo = 0;
+ }
+}
+
+bool kvm_s390_vcpu_activate_cmma(struct kvm_vcpu *vcpu)
{
struct page *cbrl;
+ vcpu->arch.sie_block->ecb2 |= 0x80;
+ vcpu->arch.sie_block->ecb2 &= ~0x08;
+ cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!cbrl)
+ return false;
+
+ vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl);
+ return true;
+}
+
+int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
+{
atomic_set(&vcpu->arch.sie_block->cpuflags, CPUSTAT_ZARCH |
CPUSTAT_SM |
CPUSTAT_STOPPED |
@@ -472,13 +492,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) vfacilities;
- if (kvm_enabled_cmma()) {
- cbrl = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (cbrl) {
- vcpu->arch.sie_block->ecb2 |= 0x80;
- vcpu->arch.sie_block->ecb2 &= ~0x08;
- vcpu->arch.sie_block->cbrlo = page_to_phys(cbrl);
- }
+ if (kvm_s390_cmma_enabled(vcpu->kvm)) {
+ if (!kvm_s390_vcpu_activate_cmma(vcpu))
+ return -ENOMEM;
}
hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
@@ -793,6 +809,18 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
return -EINVAL; /* not implemented yet */
}
+bool kvm_s390_cmma_enabled(struct kvm *kvm)
+{
+ if (!MACHINE_IS_LPAR)
+ return false;
+ /* only enable for z10 and later */
+ if (!MACHINE_HAS_EDAT1)
+ return false;
+ if (!kvm->arch.use_cmma)
+ return false;
+ return true;
+}
+
static int kvm_s390_handle_requests(struct kvm_vcpu *vcpu)
{
/*
@@ -975,16 +1003,6 @@ static int vcpu_post_run(struct kvm_vcpu *vcpu, int exit_reason)
return rc;
}
-bool kvm_enabled_cmma(void)
-{
- if (!MACHINE_IS_LPAR)
- return false;
- /* only enable for z10 and later */
- if (!MACHINE_HAS_EDAT1)
- return false;
- return true;
-}
-
static int __vcpu_run(struct kvm_vcpu *vcpu)
{
int rc, exit_reason;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 50185a3..bc66c45 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -158,8 +158,10 @@ void s390_vcpu_block(struct kvm_vcpu *vcpu);
void s390_vcpu_unblock(struct kvm_vcpu *vcpu);
void exit_sie(struct kvm_vcpu *vcpu);
void exit_sie_sync(struct kvm_vcpu *vcpu);
-/* are we going to support cmma? */
-bool kvm_enabled_cmma(void);
+bool kvm_s390_vcpu_activate_cmma(struct kvm_vcpu *vcpu);
+void kvm_s390_vcpu_unsetup_cmma(struct kvm_vcpu *vcpu);
+/* is cmma enabled */
+bool kvm_s390_cmma_enabled(struct kvm *kvm);
/* implemented in diag.c */
int kvm_s390_handle_diag(struct kvm_vcpu *vcpu);
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 4e5fba5..8f5e111 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -558,6 +558,46 @@ static int handle_epsw(struct kvm_vcpu *vcpu)
return 0;
}
+static int handle_essa(struct kvm_vcpu *vcpu)
+{
+ /* entries expected to be 1FF */
+ int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
+ unsigned long *cbrlo, cbrle;
+ struct gmap *gmap;
+ int i;
+
+ VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries);
+ gmap = vcpu->arch.gmap;
+ vcpu->stat.instruction_essa++;
+ if (!kvm_s390_cmma_enabled(vcpu->kvm))
+ return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
+
+ if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
+ return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
+
+ if (((vcpu->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+
+ /* Rewind PSW to repeat the ESSA instruction */
+ vcpu->arch.sie_block->gpsw.addr =
+ __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
+ vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
+ cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
+ down_read(&gmap->mm->mmap_sem);
+ for (i = 0; i < entries; ++i) {
+ cbrle = cbrlo[i];
+ if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE))
+ /* invalid entry */
+ break;
+ /* try to free backing */
+ __gmap_zap(cbrle, gmap);
+ }
+ up_read(&gmap->mm->mmap_sem);
+ if (i < entries)
+ return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
+ return 0;
+}
+
#define PFMF_RESERVED 0xfffc0101UL
#define PFMF_SK 0x00020000UL
#define PFMF_CF 0x00010000UL
@@ -635,46 +675,6 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
return 0;
}
-static int handle_essa(struct kvm_vcpu *vcpu)
-{
- /* entries expected to be 1FF */
- int entries = (vcpu->arch.sie_block->cbrlo & ~PAGE_MASK) >> 3;
- unsigned long *cbrlo, cbrle;
- struct gmap *gmap;
- int i;
-
- VCPU_EVENT(vcpu, 5, "cmma release %d pages", entries);
- gmap = vcpu->arch.gmap;
- vcpu->stat.instruction_essa++;
- if (!kvm_enabled_cmma() || !vcpu->arch.sie_block->cbrlo)
- return kvm_s390_inject_program_int(vcpu, PGM_OPERATION);
-
- if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
- return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP);
-
- if (((vcpu->arch.sie_block->ipb & 0xf0000000) >> 28) > 6)
- return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
-
- /* Rewind PSW to repeat the ESSA instruction */
- vcpu->arch.sie_block->gpsw.addr =
- __rewind_psw(vcpu->arch.sie_block->gpsw, 4);
- vcpu->arch.sie_block->cbrlo &= PAGE_MASK; /* reset nceo */
- cbrlo = phys_to_virt(vcpu->arch.sie_block->cbrlo);
- down_read(&gmap->mm->mmap_sem);
- for (i = 0; i < entries; ++i) {
- cbrle = cbrlo[i];
- if (unlikely(cbrle & ~PAGE_MASK || cbrle < 2 * PAGE_SIZE))
- /* invalid entry */
- break;
- /* try to free backing */
- __gmap_zap(cbrle, gmap);
- }
- up_read(&gmap->mm->mmap_sem);
- if (i < entries)
- return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION);
- return 0;
-}
-
static const intercept_handler_t b9_handlers[256] = {
[0x8d] = handle_epsw,
[0xab] = handle_essa,
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/5] KVM: s390: Adding skey bit to mmu context
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
2014-04-02 9:24 ` [PATCH 1/5] KVM: s390: make cmma usage conditionally Christian Borntraeger
@ 2014-04-02 9:24 ` Christian Borntraeger
2014-04-02 9:24 ` [PATCH 3/5] KVM: s390: Clear storage keys Christian Borntraeger
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Christian Borntraeger @ 2014-04-02 9:24 UTC (permalink / raw)
To: Paolo Bonzini, Martin Schwidefsky
Cc: KVM, linux-s390, Cornelia Huck, Dominik Dingel,
Christian Borntraeger
From: Dominik Dingel <dingel@linux.vnet.ibm.com>
For lazy storage key handling, we need a mechanism to track if the
process ever issued a storage key operation.
This patch adds the basic infrastructure for making the storage
key handling optional, but still leaves it enabled for now by default.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/mmu.h | 2 ++
arch/s390/include/asm/mmu_context.h | 1 +
arch/s390/include/asm/pgtable.h | 41 ++++++++++++++++++++++++-------------
3 files changed, 30 insertions(+), 14 deletions(-)
diff --git a/arch/s390/include/asm/mmu.h b/arch/s390/include/asm/mmu.h
index ff132ac..665cfb3 100644
--- a/arch/s390/include/asm/mmu.h
+++ b/arch/s390/include/asm/mmu.h
@@ -14,6 +14,8 @@ typedef struct {
unsigned long vdso_base;
/* The mmu context has extended page tables. */
unsigned int has_pgste:1;
+ /* The mmu context uses storage keys. */
+ unsigned int use_skey:1;
} mm_context_t;
#define INIT_MM_CONTEXT(name) \
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 5d1f950..c913486 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -22,6 +22,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.asce_bits |= _ASCE_TYPE_REGION3;
#endif
mm->context.has_pgste = 0;
+ mm->context.use_skey = 1;
mm->context.asce_limit = STACK_TOP_MAX;
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
return 0;
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 8d23a15..a82678e 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -466,6 +466,16 @@ static inline int mm_has_pgste(struct mm_struct *mm)
#endif
return 0;
}
+
+static inline int mm_use_skey(struct mm_struct *mm)
+{
+#ifdef CONFIG_PGSTE
+ if (mm->context.use_skey)
+ return 1;
+#endif
+ return 0;
+}
+
/*
* pgd/pmd/pte query functions
*/
@@ -699,12 +709,13 @@ static inline void pgste_set(pte_t *ptep, pgste_t pgste)
#endif
}
-static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
+static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste,
+ struct mm_struct *mm)
{
#ifdef CONFIG_PGSTE
unsigned long address, bits, skey;
- if (pte_val(*ptep) & _PAGE_INVALID)
+ if (!mm_use_skey(mm) || pte_val(*ptep) & _PAGE_INVALID)
return pgste;
address = pte_val(*ptep) & PAGE_MASK;
skey = (unsigned long) page_get_storage_key(address);
@@ -729,10 +740,11 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
}
-static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
+static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste,
+ struct mm_struct *mm)
{
#ifdef CONFIG_PGSTE
- if (pte_val(*ptep) & _PAGE_INVALID)
+ if (!mm_use_skey(mm) || pte_val(*ptep) & _PAGE_INVALID)
return pgste;
/* Get referenced bit from storage key */
if (page_reset_referenced(pte_val(*ptep) & PAGE_MASK))
@@ -741,13 +753,14 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
return pgste;
}
-static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry)
+static inline void pgste_set_key(pte_t *ptep, pgste_t pgste, pte_t entry,
+ struct mm_struct *mm)
{
#ifdef CONFIG_PGSTE
unsigned long address;
unsigned long nkey;
- if (pte_val(entry) & _PAGE_INVALID)
+ if (!mm_use_skey(mm) || pte_val(entry) & _PAGE_INVALID)
return;
VM_BUG_ON(!(pte_val(*ptep) & _PAGE_INVALID));
address = pte_val(entry) & PAGE_MASK;
@@ -871,7 +884,7 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
pgste_val(pgste) &= ~_PGSTE_GPS_ZERO;
- pgste_set_key(ptep, pgste, entry);
+ pgste_set_key(ptep, pgste, entry, mm);
pgste_set_pte(ptep, entry);
pgste_set_unlock(ptep, pgste);
} else {
@@ -1029,7 +1042,7 @@ static inline int ptep_test_and_clear_user_dirty(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_update_all(ptep, pgste);
+ pgste = pgste_update_all(ptep, pgste, mm);
dirty = !!(pgste_val(pgste) & PGSTE_HC_BIT);
pgste_val(pgste) &= ~PGSTE_HC_BIT;
pgste_set_unlock(ptep, pgste);
@@ -1049,7 +1062,7 @@ static inline int ptep_test_and_clear_user_young(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get_lock(ptep);
- pgste = pgste_update_young(ptep, pgste);
+ pgste = pgste_update_young(ptep, pgste, mm);
young = !!(pgste_val(pgste) & PGSTE_HR_BIT);
pgste_val(pgste) &= ~PGSTE_HR_BIT;
pgste_set_unlock(ptep, pgste);
@@ -1149,7 +1162,7 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
pte_val(*ptep) = _PAGE_INVALID;
if (mm_has_pgste(mm)) {
- pgste = pgste_update_all(&pte, pgste);
+ pgste = pgste_update_all(&pte, pgste, mm);
pgste_set_unlock(ptep, pgste);
}
return pte;
@@ -1173,7 +1186,7 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
pte_val(*ptep) |= _PAGE_INVALID;
if (mm_has_pgste(mm)) {
- pgste = pgste_update_all(&pte, pgste);
+ pgste = pgste_update_all(&pte, pgste, mm);
pgste_set(ptep, pgste);
}
return pte;
@@ -1187,7 +1200,7 @@ static inline void ptep_modify_prot_commit(struct mm_struct *mm,
if (mm_has_pgste(mm)) {
pgste = pgste_get(ptep);
- pgste_set_key(ptep, pgste, pte);
+ pgste_set_key(ptep, pgste, pte, mm);
pgste_set_pte(ptep, pte);
pgste_set_unlock(ptep, pgste);
} else
@@ -1214,7 +1227,7 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
if ((pgste_val(pgste) & _PGSTE_GPS_USAGE_MASK) ==
_PGSTE_GPS_USAGE_UNUSED)
pte_val(pte) |= _PAGE_UNUSED;
- pgste = pgste_update_all(&pte, pgste);
+ pgste = pgste_update_all(&pte, pgste, vma->vm_mm);
pgste_set_unlock(ptep, pgste);
}
return pte;
@@ -1246,7 +1259,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
pte_val(*ptep) = _PAGE_INVALID;
if (!full && mm_has_pgste(mm)) {
- pgste = pgste_update_all(&pte, pgste);
+ pgste = pgste_update_all(&pte, pgste, mm);
pgste_set_unlock(ptep, pgste);
}
return pte;
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/5] KVM: s390: Clear storage keys
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
2014-04-02 9:24 ` [PATCH 1/5] KVM: s390: make cmma usage conditionally Christian Borntraeger
2014-04-02 9:24 ` [PATCH 2/5] KVM: s390: Adding skey bit to mmu context Christian Borntraeger
@ 2014-04-02 9:24 ` Christian Borntraeger
2014-04-02 9:24 ` [PATCH 4/5] KVM: s390: Allow skeys to be enabled for the current process Christian Borntraeger
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Christian Borntraeger @ 2014-04-02 9:24 UTC (permalink / raw)
To: Paolo Bonzini, Martin Schwidefsky
Cc: KVM, linux-s390, Cornelia Huck, Dominik Dingel,
Christian Borntraeger
From: Dominik Dingel <dingel@linux.vnet.ibm.com>
page_table_reset_pgste() already does a complete page table walk to
reset the pgste. Enhance it to initialize the storage keys to
PAGE_DEFAULT_KEY if requested by the caller.
The current caller, the config device will not make use of this right
now, but this will be used by lazy sske handling.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/pgalloc.h | 3 ++-
arch/s390/mm/pgtable.c | 38 +++++++++++++++++++++++++++-----------
2 files changed, 29 insertions(+), 12 deletions(-)
diff --git a/arch/s390/include/asm/pgalloc.h b/arch/s390/include/asm/pgalloc.h
index 14d43c7..82f7d12 100644
--- a/arch/s390/include/asm/pgalloc.h
+++ b/arch/s390/include/asm/pgalloc.h
@@ -22,7 +22,8 @@ unsigned long *page_table_alloc(struct mm_struct *, unsigned long);
void page_table_free(struct mm_struct *, unsigned long *);
void page_table_free_rcu(struct mmu_gather *, unsigned long *);
-void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long);
+void page_table_reset_pgste(struct mm_struct *, unsigned long, unsigned long,
+ bool init_skey);
int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
unsigned long key, bool nq);
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 9c26b7a..02a3575 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -879,8 +879,8 @@ static inline void page_table_free_pgste(unsigned long *table)
__free_page(page);
}
-static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
- pmd_t *pmd, unsigned long addr, unsigned long end)
+static inline unsigned long page_table_reset_pte(struct mm_struct *mm, pmd_t *pmd,
+ unsigned long addr, unsigned long end, bool init_skey)
{
pte_t *start_pte, *pte;
spinlock_t *ptl;
@@ -891,6 +891,22 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
do {
pgste = pgste_get_lock(pte);
pgste_val(pgste) &= ~_PGSTE_GPS_USAGE_MASK;
+ if (init_skey) {
+ unsigned long address;
+
+ pgste_val(pgste) &= ~(PGSTE_ACC_BITS | PGSTE_FP_BIT |
+ PGSTE_GR_BIT | PGSTE_GC_BIT);
+
+ /* skip invalid and not writable pages */
+ if (pte_val(*pte) & _PAGE_INVALID ||
+ !(pte_val(*pte) & _PAGE_WRITE)) {
+ pgste_set_unlock(pte, pgste);
+ continue;
+ }
+
+ address = pte_val(*pte) & PAGE_MASK;
+ page_set_storage_key(address, PAGE_DEFAULT_KEY, 1);
+ }
pgste_set_unlock(pte, pgste);
} while (pte++, addr += PAGE_SIZE, addr != end);
pte_unmap_unlock(start_pte, ptl);
@@ -898,8 +914,8 @@ static inline unsigned long page_table_reset_pte(struct mm_struct *mm,
return addr;
}
-static inline unsigned long page_table_reset_pmd(struct mm_struct *mm,
- pud_t *pud, unsigned long addr, unsigned long end)
+static inline unsigned long page_table_reset_pmd(struct mm_struct *mm, pud_t *pud,
+ unsigned long addr, unsigned long end, bool init_skey)
{
unsigned long next;
pmd_t *pmd;
@@ -909,14 +925,14 @@ static inline unsigned long page_table_reset_pmd(struct mm_struct *mm,
next = pmd_addr_end(addr, end);
if (pmd_none_or_clear_bad(pmd))
continue;
- next = page_table_reset_pte(mm, pmd, addr, next);
+ next = page_table_reset_pte(mm, pmd, addr, next, init_skey);
} while (pmd++, addr = next, addr != end);
return addr;
}
-static inline unsigned long page_table_reset_pud(struct mm_struct *mm,
- pgd_t *pgd, unsigned long addr, unsigned long end)
+static inline unsigned long page_table_reset_pud(struct mm_struct *mm, pgd_t *pgd,
+ unsigned long addr, unsigned long end, bool init_skey)
{
unsigned long next;
pud_t *pud;
@@ -926,14 +942,14 @@ static inline unsigned long page_table_reset_pud(struct mm_struct *mm,
next = pud_addr_end(addr, end);
if (pud_none_or_clear_bad(pud))
continue;
- next = page_table_reset_pmd(mm, pud, addr, next);
+ next = page_table_reset_pmd(mm, pud, addr, next, init_skey);
} while (pud++, addr = next, addr != end);
return addr;
}
-void page_table_reset_pgste(struct mm_struct *mm,
- unsigned long start, unsigned long end)
+void page_table_reset_pgste(struct mm_struct *mm, unsigned long start,
+ unsigned long end, bool init_skey)
{
unsigned long addr, next;
pgd_t *pgd;
@@ -945,7 +961,7 @@ void page_table_reset_pgste(struct mm_struct *mm,
next = pgd_addr_end(addr, end);
if (pgd_none_or_clear_bad(pgd))
continue;
- next = page_table_reset_pud(mm, pgd, addr, next);
+ next = page_table_reset_pud(mm, pgd, addr, next, init_skey);
} while (pgd++, addr = next, addr != end);
up_read(&mm->mmap_sem);
}
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 4/5] KVM: s390: Allow skeys to be enabled for the current process
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
` (2 preceding siblings ...)
2014-04-02 9:24 ` [PATCH 3/5] KVM: s390: Clear storage keys Christian Borntraeger
@ 2014-04-02 9:24 ` Christian Borntraeger
2014-04-02 9:24 ` [PATCH 5/5] KVM: s390: Don't enable skeys by default Christian Borntraeger
2014-04-02 14:31 ` [PATCH 0/5] cmma and lazy sske Martin Schwidefsky
5 siblings, 0 replies; 7+ messages in thread
From: Christian Borntraeger @ 2014-04-02 9:24 UTC (permalink / raw)
To: Paolo Bonzini, Martin Schwidefsky
Cc: KVM, linux-s390, Cornelia Huck, Dominik Dingel,
Christian Borntraeger
From: Dominik Dingel <dingel@linux.vnet.ibm.com>
Introduce a new function s390_enable_skey(), which enables storage key
handling via setting the use_skey flag in the mmu context.
This function is only useful within the context of kvm.
Note that enabling storage keys will cause a one-time hickup when
walking the page table; however, it saves us special effort for cases
like clear reset while making it possible for us to be architecture
conform.
s390_enable_skey() takes the page table lock to prevent reseting
storage keys triggered from multiple vcpus.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/pgtable.h | 1 +
arch/s390/mm/pgtable.c | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index a82678e..1852389 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -1678,6 +1678,7 @@ static inline pte_t mk_swap_pte(unsigned long type, unsigned long offset)
extern int vmem_add_mapping(unsigned long start, unsigned long size);
extern int vmem_remove_mapping(unsigned long start, unsigned long size);
extern int s390_enable_sie(void);
+extern void s390_enable_skey(void);
/*
* No page table caches to initialise
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index 02a3575..2ed28bc 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -1369,6 +1369,29 @@ int s390_enable_sie(void)
}
EXPORT_SYMBOL_GPL(s390_enable_sie);
+/*
+ * Enable storage key handling from now on and initialize the storage
+ * keys with the default key.
+ */
+void s390_enable_skey(void)
+{
+ /*
+ * To avoid races between multiple vcpus, ending in calling
+ * page_table_reset twice or more,
+ * the page_table_lock is taken for serialization.
+ */
+ spin_lock(¤t->mm->page_table_lock);
+ if (mm_use_skey(current->mm)) {
+ spin_unlock(¤t->mm->page_table_lock);
+ return;
+ }
+
+ current->mm->context.use_skey = 1;
+ spin_unlock(¤t->mm->page_table_lock);
+ page_table_reset_pgste(current->mm, 0, TASK_SIZE, true);
+}
+EXPORT_SYMBOL_GPL(s390_enable_skey);
+
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
int pmdp_clear_flush_young(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 5/5] KVM: s390: Don't enable skeys by default
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
` (3 preceding siblings ...)
2014-04-02 9:24 ` [PATCH 4/5] KVM: s390: Allow skeys to be enabled for the current process Christian Borntraeger
@ 2014-04-02 9:24 ` Christian Borntraeger
2014-04-02 14:31 ` [PATCH 0/5] cmma and lazy sske Martin Schwidefsky
5 siblings, 0 replies; 7+ messages in thread
From: Christian Borntraeger @ 2014-04-02 9:24 UTC (permalink / raw)
To: Paolo Bonzini, Martin Schwidefsky
Cc: KVM, linux-s390, Cornelia Huck, Dominik Dingel,
Christian Borntraeger
From: Dominik Dingel <dingel@linux.vnet.ibm.com>
The first invocation of storage key operations on a given cpu will be intercepted.
On these intercepts we will enable storage keys for the guest and remove the
previously added intercepts.
Signed-off-by: Dominik Dingel <dingel@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
---
arch/s390/include/asm/kvm_host.h | 3 +++
arch/s390/include/asm/mmu_context.h | 2 +-
arch/s390/kvm/kvm-s390.c | 1 +
arch/s390/kvm/priv.c | 14 ++++++++++++++
arch/s390/kvm/trace.h | 14 ++++++++++++++
5 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 9f2f45d..33c425e 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -89,6 +89,9 @@ struct kvm_s390_sie_block {
__u16 lctl; /* 0x0044 */
__s16 icpua; /* 0x0046 */
#define ICTL_LPSW 0x00400000
+#define ICTL_ISKE 0x00004000
+#define ICTL_SSKE 0x00002000
+#define ICTL_RRBE 0x00001000
__u32 ictl; /* 0x0048 */
__u32 eca; /* 0x004c */
__u8 icptcode; /* 0x0050 */
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index c913486..f230e6c 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -22,7 +22,7 @@ static inline int init_new_context(struct task_struct *tsk,
mm->context.asce_bits |= _ASCE_TYPE_REGION3;
#endif
mm->context.has_pgste = 0;
- mm->context.use_skey = 1;
+ mm->context.use_skey = 0;
mm->context.asce_limit = STACK_TOP_MAX;
crst_table_init((unsigned long *) mm->pgd, pgd_entry_type(mm));
return 0;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index fcb1c32..2d981b4 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -492,6 +492,7 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
vcpu->arch.sie_block->ecb2 = 8;
vcpu->arch.sie_block->eca = 0xC1002001U;
vcpu->arch.sie_block->fac = (int) (long) vfacilities;
+ vcpu->arch.sie_block->ictl |= ICTL_ISKE | ICTL_SSKE | ICTL_RRBE;
if (kvm_s390_cmma_enabled(vcpu->kvm)) {
if (!kvm_s390_vcpu_activate_cmma(vcpu))
return -ENOMEM;
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 8f5e111..6cba3e0 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -148,8 +148,21 @@ static int handle_store_cpu_address(struct kvm_vcpu *vcpu)
return 0;
}
+static void __skey_check_enable(struct kvm_vcpu *vcpu)
+{
+ if (!(vcpu->arch.sie_block->ictl & (ICTL_ISKE | ICTL_SSKE | ICTL_RRBE)))
+ return;
+
+ s390_enable_skey();
+ trace_kvm_s390_skey_related_inst(vcpu);
+ vcpu->arch.sie_block->ictl &= ~(ICTL_ISKE | ICTL_SSKE | ICTL_RRBE);
+}
+
+
static int handle_skey(struct kvm_vcpu *vcpu)
{
+ __skey_check_enable(vcpu);
+
vcpu->stat.instruction_storage_key++;
if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE)
@@ -662,6 +675,7 @@ static int handle_pfmf(struct kvm_vcpu *vcpu)
}
if (vcpu->run->s.regs.gprs[reg1] & PFMF_SK) {
+ __skey_check_enable(vcpu);
if (set_guest_storage_key(current->mm, useraddr,
vcpu->run->s.regs.gprs[reg1] & PFMF_KEY,
vcpu->run->s.regs.gprs[reg1] & PFMF_NQ))
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h
index e8e7213..a4bf7d7 100644
--- a/arch/s390/kvm/trace.h
+++ b/arch/s390/kvm/trace.h
@@ -30,6 +30,20 @@
TP_printk("%02d[%016lx-%016lx]: " p_str, __entry->id, \
__entry->pswmask, __entry->pswaddr, p_args)
+TRACE_EVENT(kvm_s390_skey_related_inst,
+ TP_PROTO(VCPU_PROTO_COMMON),
+ TP_ARGS(VCPU_ARGS_COMMON),
+
+ TP_STRUCT__entry(
+ VCPU_FIELD_COMMON
+ ),
+
+ TP_fast_assign(
+ VCPU_ASSIGN_COMMON
+ ),
+ VCPU_TP_PRINTK("%s", "first instruction related to skeys on vcpu")
+ );
+
TRACE_EVENT(kvm_s390_major_guest_pfault,
TP_PROTO(VCPU_PROTO_COMMON),
TP_ARGS(VCPU_ARGS_COMMON),
--
1.8.4.2
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH 0/5] cmma and lazy sske
2014-04-02 9:24 [PATCH 0/5] cmma and lazy sske Christian Borntraeger
` (4 preceding siblings ...)
2014-04-02 9:24 ` [PATCH 5/5] KVM: s390: Don't enable skeys by default Christian Borntraeger
@ 2014-04-02 14:31 ` Martin Schwidefsky
5 siblings, 0 replies; 7+ messages in thread
From: Martin Schwidefsky @ 2014-04-02 14:31 UTC (permalink / raw)
To: Christian Borntraeger; +Cc: Paolo Bonzini, KVM, linux-s390, Cornelia Huck
On Wed, 2 Apr 2014 11:24:43 +0200
Christian Borntraeger <borntraeger@de.ibm.com> wrote:
> shall we send out patch 1 via your tree or kvm? Should be still in for 3.15
>
> Can you ACK patches 2-5?
>
>
> Dominik Dingel (5):
> KVM: s390: make cmma usage conditionally
> KVM: s390: Adding skey bit to mmu context
> KVM: s390: Clear storage keys
> KVM: s390: Allow skeys to be enabled for the current process
> KVM: s390: Don't enable skeys by default
>
> arch/s390/include/asm/kvm_host.h | 4 ++
> arch/s390/include/asm/mmu.h | 2 +
> arch/s390/include/asm/mmu_context.h | 1 +
> arch/s390/include/asm/pgalloc.h | 3 +-
> arch/s390/include/asm/pgtable.h | 42 +++++++++++------
> arch/s390/kvm/diag.c | 6 ---
> arch/s390/kvm/kvm-s390.c | 61 +++++++++++++++---------
> arch/s390/kvm/kvm-s390.h | 6 ++-
> arch/s390/kvm/priv.c | 94 +++++++++++++++++++++----------------
> arch/s390/kvm/trace.h | 14 ++++++
> arch/s390/mm/pgtable.c | 61 +++++++++++++++++++-----
> 11 files changed, 199 insertions(+), 95 deletions(-)
This is all related to kvm and the majority of changes are for files
in the kvm directory. The changes in the mm headers only affect the
code for CONFIG_PGSTE=y. I think this should go over the kvm tree.
And "Acked-by: Martin Schwidefsky <schwidefsky@de.ibm.com>" for the
patches 2-5.
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
^ permalink raw reply [flat|nested] 7+ messages in thread