summaryrefslogtreecommitdiffstats
path: root/arch/s390/mm/page-states.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/mm/page-states.c')
-rw-r--r--arch/s390/mm/page-states.c25
1 files changed, 19 insertions, 6 deletions
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
index 1e2ea706aa22..a31acb2c4ef2 100644
--- a/arch/s390/mm/page-states.c
+++ b/arch/s390/mm/page-states.c
@@ -121,7 +121,7 @@ static void mark_kernel_pud(p4d_t *p4d, unsigned long addr, unsigned long end)
continue;
if (!pud_folded(*pud)) {
page = phys_to_page(pud_val(*pud));
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
set_bit(PG_arch_1, &page[i].flags);
}
mark_kernel_pmd(pud, addr, next);
@@ -142,7 +142,7 @@ static void mark_kernel_p4d(pgd_t *pgd, unsigned long addr, unsigned long end)
continue;
if (!p4d_folded(*p4d)) {
page = phys_to_page(p4d_val(*p4d));
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
set_bit(PG_arch_1, &page[i].flags);
}
mark_kernel_pud(p4d, addr, next);
@@ -151,24 +151,31 @@ static void mark_kernel_p4d(pgd_t *pgd, unsigned long addr, unsigned long end)
static void mark_kernel_pgd(void)
{
- unsigned long addr, next;
+ unsigned long addr, next, max_addr;
struct page *page;
pgd_t *pgd;
int i;
addr = 0;
+ /*
+ * Figure out maximum virtual address accessible with the
+ * kernel ASCE. This is required to keep the page table walker
+ * from accessing non-existent entries.
+ */
+ max_addr = (S390_lowcore.kernel_asce.val & _ASCE_TYPE_MASK) >> 2;
+ max_addr = 1UL << (max_addr * 11 + 31);
pgd = pgd_offset_k(addr);
do {
- next = pgd_addr_end(addr, MODULES_END);
+ next = pgd_addr_end(addr, max_addr);
if (pgd_none(*pgd))
continue;
if (!pgd_folded(*pgd)) {
page = phys_to_page(pgd_val(*pgd));
- for (i = 0; i < 3; i++)
+ for (i = 0; i < 4; i++)
set_bit(PG_arch_1, &page[i].flags);
}
mark_kernel_p4d(pgd, addr, next);
- } while (pgd++, addr = next, addr != MODULES_END);
+ } while (pgd++, addr = next, addr != max_addr);
}
void __init cmma_init_nodat(void)
@@ -181,6 +188,12 @@ void __init cmma_init_nodat(void)
return;
/* Mark pages used in kernel page tables */
mark_kernel_pgd();
+ page = virt_to_page(&swapper_pg_dir);
+ for (i = 0; i < 4; i++)
+ set_bit(PG_arch_1, &page[i].flags);
+ page = virt_to_page(&invalid_pg_dir);
+ for (i = 0; i < 4; i++)
+ set_bit(PG_arch_1, &page[i].flags);
/* Set all kernel pages not used for page tables to stable/no-dat */
for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, NULL) {