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

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

KVM: s390: Clear storage keys



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. This will be used
for lazy storage key handling. Also provide an empty stub for
!CONFIG_PGSTE

Lets adopt the current code (diag 308) to not clear the keys.

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 65eef335
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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);

+3 −3
Original line number Diff line number Diff line
@@ -169,15 +169,15 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
	switch (subcode) {
	case 0:
	case 1:
		page_table_reset_pgste(current->mm, 0, TASK_SIZE);
		page_table_reset_pgste(current->mm, 0, TASK_SIZE, false);
		return -EOPNOTSUPP;
	case 3:
		vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
		page_table_reset_pgste(current->mm, 0, TASK_SIZE);
		page_table_reset_pgste(current->mm, 0, TASK_SIZE, false);
		break;
	case 4:
		vcpu->run->s390_reset_flags = 0;
		page_table_reset_pgste(current->mm, 0, TASK_SIZE);
		page_table_reset_pgste(current->mm, 0, TASK_SIZE, false);
		break;
	default:
		return -EOPNOTSUPP;
+32 −11
Original line number Diff line number Diff line
@@ -883,8 +883,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;
@@ -895,6 +895,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);
@@ -902,8 +918,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;
@@ -913,14 +929,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;
@@ -930,14 +946,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;
@@ -949,7 +965,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);
}
@@ -1011,6 +1027,11 @@ static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
	return NULL;
}

void page_table_reset_pgste(struct mm_struct *mm, unsigned long start,
			    unsigned long end, bool init_skey)
{
}

static inline void page_table_free_pgste(unsigned long *table)
{
}