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

Commit 09b53883 authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

[S390] fix pgste update logic



The pgste_update_all / pgste_update_young and pgste_set_pte need to
check if the pte entry contains a valid page address before the storage
key can be accessed. In addition pgste_set_pte needs to set the access
key and fetch protection bit of the new pte entry, not the old entry.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 80025297
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -593,6 +593,8 @@ static inline pgste_t pgste_update_all(pte_t *ptep, pgste_t pgste)
	unsigned long address, bits;
	unsigned char skey;

	if (!pte_present(*ptep))
		return pgste;
	address = pte_val(*ptep) & PAGE_MASK;
	skey = page_get_storage_key(address);
	bits = skey & (_PAGE_CHANGED | _PAGE_REFERENCED);
@@ -625,6 +627,8 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)
#ifdef CONFIG_PGSTE
	int young;

	if (!pte_present(*ptep))
		return pgste;
	young = page_reset_referenced(pte_val(*ptep) & PAGE_MASK);
	/* Transfer page referenced bit to pte software bit (host view) */
	if (young || (pgste_val(pgste) & RCP_HR_BIT))
@@ -638,13 +642,15 @@ static inline pgste_t pgste_update_young(pte_t *ptep, pgste_t pgste)

}

static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste)
static inline void pgste_set_pte(pte_t *ptep, pgste_t pgste, pte_t entry)
{
#ifdef CONFIG_PGSTE
	unsigned long address;
	unsigned long okey, nkey;

	address = pte_val(*ptep) & PAGE_MASK;
	if (!pte_present(entry))
		return;
	address = pte_val(entry) & PAGE_MASK;
	okey = nkey = page_get_storage_key(address);
	nkey &= ~(_PAGE_ACC_BITS | _PAGE_FP_BIT);
	/* Set page access key and fetch protection bit from pgste */
@@ -712,7 +718,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_set_pte(ptep, pgste);
		pgste_set_pte(ptep, pgste, entry);
		*ptep = entry;
		pgste_set_unlock(ptep, pgste);
	} else