summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Carstens <hca@linux.ibm.com>2023-10-17 21:07:03 +0200
committerVasily Gorbik <gor@linux.ibm.com>2023-10-23 18:21:23 +0200
commit16ba44826a04834d3eeeda4b731c2ea3481062b7 (patch)
treeb1575b41a3baf6722a31b9b6741d1ac294d23cbb
parentc8b5d574fcea49e9974b7658d5337f93d1921f8c (diff)
s390/cmma: fix initial kernel address space page table walk
If the cmma no-dat feature is available the kernel page tables are walked to identify and mark all pages which are used for address translation (all region, segment, and page tables). In a subsequent loop all other pages are marked as "no-dat" pages with the ESSA instruction. This information is visible to the hypervisor, so that the hypervisor can optimize purging of guest TLB entries. The initial loop however does not cover the complete kernel address space. This can result in pages being marked as not being used for dynamic address translation, even though they are. In turn guest TLB entries incorrectly may not be purged. Fix this by adjusting the end address of the kernel address range being walked. Cc: <stable@vger.kernel.org> Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com> Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
-rw-r--r--arch/s390/mm/page-states.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
index 1e2ea706aa22..c3db3c0e75c0 100644
--- a/arch/s390/mm/page-states.c
+++ b/arch/s390/mm/page-states.c
@@ -151,15 +151,22 @@ 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)) {
@@ -168,7 +175,7 @@ static void mark_kernel_pgd(void)
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)