From d222b01e516bba73ef9fefee4146734a5f260fa1 Mon Sep 17 00:00:00 2001
From: Lianbo Jiang <lijiang@redhat.com>
Date: Wed, 30 Jan 2019 10:48:53 +0800
Subject: x86_64: Add support for AMD Secure Memory Encryption
References: bsc#1141895
Upstream: merged
Git-commit: d222b01e516bba73ef9fefee4146734a5f260fa1

On AMD machine with Secure Memory Encryption (SME) feature, if SME is
enabled, page tables contain a specific attribute bit (C-bit) in their
entries to indicate whether a page is encrypted or unencrypted.

So get NUMBER(sme_mask) from vmcoreinfo, which stores the value of
the C-bit position, and drop it to obtain the true physical address.

Signed-off-by: Lianbo Jiang <lijiang@redhat.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 arch/x86_64.c  |   27 ++++++++++++++++++---------
 makedumpfile.c |    4 ++++
 makedumpfile.h |    1 +
 3 files changed, 23 insertions(+), 9 deletions(-)

--- a/arch/x86_64.c
+++ b/arch/x86_64.c
@@ -268,6 +268,7 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 {
 	unsigned long page_dir, pgd, pud_paddr, pud_pte, pmd_paddr, pmd_pte;
 	unsigned long pte_paddr, pte;
+	unsigned long entry_mask = ENTRY_MASK;
 
 	/*
 	 * Get PGD.
@@ -278,6 +279,10 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 		if (page_dir == NOT_PADDR)
 			return NOT_PADDR;
 	}
+
+	if (NUMBER(sme_mask) != NOT_FOUND_NUMBER)
+		entry_mask &= ~(NUMBER(sme_mask));
+
 	page_dir += pgd_index(vaddr) * sizeof(unsigned long);
 	if (!readmem(PADDR, page_dir, &pgd, sizeof pgd)) {
 		ERRMSG("Can't get pgd (page_dir:%lx).\n", page_dir);
@@ -294,7 +299,7 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 	/*
 	 * Get PUD.
 	 */
-	pud_paddr  = pgd & ENTRY_MASK;
+	pud_paddr = pgd & entry_mask;
 	pud_paddr += pud_index(vaddr) * sizeof(unsigned long);
 	if (!readmem(PADDR, pud_paddr, &pud_pte, sizeof pud_pte)) {
 		ERRMSG("Can't get pud_pte (pud_paddr:%lx).\n", pud_paddr);
@@ -308,13 +313,13 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 		return NOT_PADDR;
 	}
 	if (pud_pte & _PAGE_PSE)	/* 1GB pages */
-		return (pud_pte & ENTRY_MASK & PUD_MASK) +
+		return (pud_pte & entry_mask & PUD_MASK) +
 			(vaddr & ~PUD_MASK);
 
 	/*
 	 * Get PMD.
 	 */
-	pmd_paddr  = pud_pte & ENTRY_MASK;
+	pmd_paddr = pud_pte & entry_mask;
 	pmd_paddr += pmd_index(vaddr) * sizeof(unsigned long);
 	if (!readmem(PADDR, pmd_paddr, &pmd_pte, sizeof pmd_pte)) {
 		ERRMSG("Can't get pmd_pte (pmd_paddr:%lx).\n", pmd_paddr);
@@ -328,13 +333,13 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 		return NOT_PADDR;
 	}
 	if (pmd_pte & _PAGE_PSE)	/* 2MB pages */
-		return (pmd_pte & ENTRY_MASK & PMD_MASK) +
+		return (pmd_pte & entry_mask & PMD_MASK) +
 			(vaddr & ~PMD_MASK);
 
 	/*
 	 * Get PTE.
 	 */
-	pte_paddr  = pmd_pte & ENTRY_MASK;
+	pte_paddr = pmd_pte & entry_mask;
 	pte_paddr += pte_index(vaddr) * sizeof(unsigned long);
 	if (!readmem(PADDR, pte_paddr, &pte, sizeof pte)) {
 		ERRMSG("Can't get pte (pte_paddr:%lx).\n", pte_paddr);
@@ -347,7 +352,7 @@ __vtop4_x86_64(unsigned long vaddr, unsi
 		ERRMSG("Can't get a valid pte.\n");
 		return NOT_PADDR;
 	}
-	return (pte & ENTRY_MASK) + PAGEOFFSET(vaddr);
+	return (pte & entry_mask) + PAGEOFFSET(vaddr);
 }
 
 unsigned long long
@@ -585,6 +590,7 @@ find_vmemmap_x86_64()
 	unsigned long pmd, tpfn;
 	unsigned long pvaddr = 0;
 	unsigned long data_addr = 0, last_data_addr = 0, start_data_addr = 0;
+	unsigned long pmask = PMASK;
 	/*
 	 * data_addr is the paddr of the page holding the page structs.
 	 * We keep lists of contiguous pages and the pfn's that their
@@ -609,6 +615,9 @@ find_vmemmap_x86_64()
 		ERRMSG("kernel is configured for 5-level page tables\n");
 		return FAILED;
 	}
+	if (NUMBER(sme_mask) != NOT_FOUND_NUMBER)
+		pmask &= ~(NUMBER(sme_mask));
+
 	pagestructsize = size_table.page;
 	hugepagesize = PTRS_PER_PMD * info->page_size;
 	vaddr_base = info->vmemmap_start;
@@ -637,7 +646,7 @@ find_vmemmap_x86_64()
 			return FAILED;
 		}
 		/* mask the pgd entry for the address of the pud page */
-		pud_addr &= PMASK;
+		pud_addr &= pmask;
 		if (pud_addr == 0)
 			  continue;
 		/* read the entire pud page */
@@ -650,7 +659,7 @@ find_vmemmap_x86_64()
 		/* pudp points to an entry in the pud page */
 		for (pudp = (unsigned long *)pud_page, pudindex = 0;
 					pudindex < PTRS_PER_PUD; pudindex++, pudp++) {
-			pmd_addr = *pudp & PMASK;
+			pmd_addr = *pudp & pmask;
 			/* read the entire pmd page */
 			if (pmd_addr == 0)
 				continue;
@@ -692,7 +701,7 @@ find_vmemmap_x86_64()
 				 * - we discontiguous page is a string of valids
 				 */
 				if (pmd) {
-					data_addr = (pmd & PMASK);
+					data_addr = (pmd & pmask);
 					if (start_range) {
 						/* first-time kludge */
 						start_data_addr = data_addr;
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -993,6 +993,8 @@ next_page:
 	read_size = MIN(info->page_size - PAGEOFFSET(paddr), size);
 
 	pgaddr = PAGEBASE(paddr);
+	if (NUMBER(sme_mask) != NOT_FOUND_NUMBER)
+		pgaddr = pgaddr & ~(NUMBER(sme_mask));
 	pgbuf = cache_search(pgaddr, read_size);
 	if (!pgbuf) {
 		++cache_miss;
@@ -2290,6 +2292,7 @@ write_vmcoreinfo_data(void)
 
 	WRITE_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES);
 	WRITE_NUMBER("N_ONLINE", N_ONLINE);
+	WRITE_NUMBER("sme_mask", sme_mask);
 
 	WRITE_NUMBER("PG_lru", PG_lru);
 	WRITE_NUMBER("PG_private", PG_private);
@@ -2690,6 +2693,7 @@ read_vmcoreinfo(void)
 
 	READ_NUMBER("NR_FREE_PAGES", NR_FREE_PAGES);
 	READ_NUMBER("N_ONLINE", N_ONLINE);
+	READ_NUMBER("sme_mask", sme_mask);
 
 	READ_NUMBER("PG_lru", PG_lru);
 	READ_NUMBER("PG_private", PG_private);
--- a/makedumpfile.h
+++ b/makedumpfile.h
@@ -1861,6 +1861,7 @@ struct array_table {
 struct number_table {
 	long	NR_FREE_PAGES;
 	long	N_ONLINE;
+	long	sme_mask;
 
 	/*
  	* Page flags
