[Crash-utility] [PATCH 05/16] MIPS64: Add 'pte' command support

Youling Tang tangyouling at loongson.cn
Tue Jan 26 11:11:32 UTC 2021


The pte command converts the pte table entry into a physical address and
displays the page flags. Also fixed the pte part in the vtop command.

E.g. With this patch:
crash> vtop ffffffffc0004000
VIRTUAL           PHYSICAL
ffffffffc0004000  2504ac000

SEGMENT: sseg
PAGE DIRECTORY: ffffffff81330000
  PGD: ffffffff81333ff8 => 9800000255828000
  PMD: 000000025582bf00 => 98000002504bc000
  PTE: 00000002504bc008 => 0000001282563e0f
 PAGE: 00000002504ac000

   PTE      PHYSICAL   FLAGS
1282563e0f  2504ac000  (PRESENT|WRITE|ACCESSED|MODIFIED|GLOBAL|VALID|DIRTY)

      PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
9800000257f04ac0 2504ac000                0        0  1 2501fff000000
crash> pte 1282563e0f
   PTE      PHYSICAL   FLAGS
1282563e0f  2504ac000  (PRESENT|WRITE|ACCESSED|MODIFIED|GLOBAL|VALID|DIRTY)

Signed-off-by: Huacai Chen <chenhuacai at loongson.cn>
Signed-off-by: Youling Tang <tangyouling at loongson.cn>
---
 mips64.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 118 insertions(+)

diff --git a/mips64.c b/mips64.c
index 21a8206..74f0492 100644
--- a/mips64.c
+++ b/mips64.c
@@ -23,6 +23,9 @@ static int mips64_uvtop(struct task_context *tc, ulong vaddr,
 			physaddr_t *paddr, int verbose);
 static int mips64_kvtop(struct task_context *tc, ulong kvaddr,
 			physaddr_t *paddr, int verbose);
+static void mips64_init_page_flags(void);
+static int mips64_translate_pte(ulong pte, void *physaddr,
+			ulonglong pte64);
 
 /*
  * 3 Levels paging       PAGE_SIZE=16KB
@@ -75,6 +78,104 @@ static struct machine_specific mips64_machine_specific = { 0 };
 static struct mips64_register *panic_task_regs;
 
 /*
+ * 31                15 14    12 11 10  9  8  7  6  5  4  3  2  1  0
+ * +-------------------+--------+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |       VPN         |    C   | D| V| G|RI|XI|SP|PN| H| M| A| W| P|
+ * +-------------------+--------+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+static void
+mips64_init_page_flags(void)
+{
+	ulong shift = 0;
+
+	_PAGE_PRESENT = 1UL << shift++;
+	_PAGE_WRITE = 1UL << shift++;
+	_PAGE_ACCESSED = 1UL << shift++;
+	_PAGE_MODIFIED = 1UL << shift++;
+	_PAGE_HUGE = 1UL << shift++;
+	_PAGE_PROTNONE = 1UL << shift++;
+
+	if (THIS_KERNEL_VERSION >= LINUX(4,5,0))
+		_PAGE_SPECIAL = 1UL << shift++;
+
+	_PAGE_NO_EXEC = 1UL << shift++;
+	_PAGE_NO_READ = _PAGE_READ = 1UL << shift++;
+	_PAGE_GLOBAL = 1UL << shift++;
+	_PAGE_VALID = 1UL << shift++;
+	_PAGE_DIRTY = 1UL << shift++;
+
+	_PFN_SHIFT =  PAGESHIFT() - 12 + shift + 3;
+}
+
+/*
+ * Translate a PTE, returning TRUE if the page is present.
+ * If a physaddr pointer is passed in, don't print anything.
+ */
+static int
+mips64_translate_pte(ulong pte, void *physaddr, ulonglong pte64)
+{
+	char ptebuf[BUFSIZE];
+	char physbuf[BUFSIZE];
+	char buf[BUFSIZE];
+	int page_present;
+	int len1, len2, others;
+	ulong paddr;
+
+	paddr = PTOB(pte >> _PFN_SHIFT);
+	page_present = !!(pte & _PAGE_PRESENT);
+
+	if (physaddr) {
+		*(ulong *)physaddr = paddr;
+		return page_present;
+	}
+
+	sprintf(ptebuf, "%lx", pte);
+	len1 = MAX(strlen(ptebuf), strlen("PTE"));
+	fprintf(fp, "%s  ", mkstring(buf, len1, CENTER | LJUST, "PTE"));
+
+	if (!page_present)
+		return page_present;
+
+	sprintf(physbuf, "%lx", paddr);
+	len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
+	fprintf(fp, "%s  ", mkstring(buf, len2, CENTER | LJUST, "PHYSICAL"));
+
+	fprintf(fp, "FLAGS\n");
+	fprintf(fp, "%s  %s  ",
+		mkstring(ptebuf, len1, CENTER | RJUST, NULL),
+		mkstring(physbuf, len2, CENTER | RJUST, NULL));
+
+	fprintf(fp, "(");
+	others = 0;
+
+#define CHECK_PAGE_FLAG(flag)				\
+	if ((_PAGE_##flag) && (pte & _PAGE_##flag))	\
+		fprintf(fp, "%s" #flag, others++ ? "|" : "")
+
+	if (pte) {
+		CHECK_PAGE_FLAG(PRESENT);
+		CHECK_PAGE_FLAG(WRITE);
+		CHECK_PAGE_FLAG(ACCESSED);
+		CHECK_PAGE_FLAG(MODIFIED);
+		CHECK_PAGE_FLAG(HUGE);
+		CHECK_PAGE_FLAG(PROTNONE);
+		CHECK_PAGE_FLAG(SPECIAL);
+		CHECK_PAGE_FLAG(NO_EXEC);
+		CHECK_PAGE_FLAG(NO_READ);
+		CHECK_PAGE_FLAG(READ);
+		CHECK_PAGE_FLAG(GLOBAL);
+		CHECK_PAGE_FLAG(VALID);
+		CHECK_PAGE_FLAG(DIRTY);
+	} else {
+		fprintf(fp, "no mapping");
+	}
+
+	fprintf(fp, ")\n");
+
+	return page_present;
+}
+
+/*
  * Virtual to physical memory translation. This function will be called
  * by both mips64_kvtop and mips64_uvtop.
  */
@@ -140,6 +241,21 @@ mips64_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
 	if (!pte_val)
 		goto no_page;
 
+	if (!(pte_val & _PAGE_PRESENT)) {
+		if (verbose) {
+			fprintf(fp, "\n");
+			mips64_translate_pte((ulong)pte_val, 0, pte_val);
+		}
+		return FALSE;
+	}
+
+	*paddr = PTOB(pte_val >> _PFN_SHIFT) + PAGEOFFSET(vaddr);
+
+	if (verbose) {
+		fprintf(fp, " PAGE: %016lx\n\n", PAGEBASE(*paddr));
+		mips64_translate_pte(pte_val, 0, 0);
+	}
+
 	return TRUE;
 no_page:
 	fprintf(fp, "invalid\n");
@@ -327,6 +443,7 @@ mips64_init(int when)
 		machdep->processor_speed = mips64_processor_speed;
 		machdep->get_stackbase = generic_get_stackbase;
 		machdep->get_stacktop = generic_get_stacktop;
+		machdep->translate_pte = mips64_translate_pte;
 		machdep->memory_size = generic_memory_size;
 		machdep->is_task_addr = mips64_is_task_addr;
 		machdep->get_smp_cpus = mips64_get_smp_cpus;
@@ -335,6 +452,7 @@ mips64_init(int when)
 		break;
 
 	case POST_GDB:
+		mips64_init_page_flags();
 		machdep->section_size_bits = _SECTION_SIZE_BITS;
 		machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
 		break;
-- 
2.1.0




More information about the Crash-utility mailing list