Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 65eef335 authored by Dominik Dingel's avatar Dominik Dingel Committed by Christian Borntraeger
Browse files

KVM: s390: Adding skey bit to mmu context



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: default avatarDominik Dingel <dingel@linux.vnet.ibm.com>
Acked-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
parent 0f689a33
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -16,6 +16,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)						      \
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,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;
+27 −14
Original line number Diff line number Diff line
@@ -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;
@@ -870,7 +883,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 {
@@ -1028,7 +1041,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);
@@ -1048,7 +1061,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);
@@ -1182,7 +1195,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;
@@ -1205,7 +1218,7 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
	ptep_flush_lazy(mm, address, ptep);

	if (mm_has_pgste(mm)) {
		pgste = pgste_update_all(&pte, pgste);
		pgste = pgste_update_all(&pte, pgste, mm);
		pgste_set(ptep, pgste);
	}
	return pte;
@@ -1219,7 +1232,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
@@ -1246,7 +1259,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;
@@ -1278,7 +1291,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;