qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v4 4/7] Convert 'info tlb' to use generic iterator.


From: Don Porter
Subject: [PATCH v4 4/7] Convert 'info tlb' to use generic iterator.
Date: Mon, 22 Jul 2024 21:05:42 -0400

If the the guest is using nested page tables, change the output format
slightly, to first show guest virtual to guest physical, then guest
physical to host physical, as below:

(qemu) info tlb
Info guest TLB (guest virtual to guest physical):
0000008000800000: 000000000076a000  -------U-P
0000008000801000: 000000000076b000  -------U-P
0000008000802000: 000000000076c000  -------U-P
0000008000803000: 000000000076d000  -------U-P
[...]
0000008004ffd000: 0000000000ffd000  --------WP
0000008004ffe000: 0000000000ffe000  --------WP
0000008004fff000: 0000000000fff000  --------WP
Info host TLB, (guest physical to host physical):
0000000000001000: 0000000001b20000  ----XWR
0000000000002000: 0000000001b21000  ----XWR
0000000000003000: 0000000001b22000  ----XWR
0000000000004000: 0000000001b23000  ----XWR
0000000000005000: 0000000001b24000  ----XWR
[...]

Signed-off-by: Don Porter <porter@cs.unc.edu>
---
 include/hw/core/sysemu-cpu-ops.h |   7 +
 target/i386/cpu.c                |   1 +
 target/i386/cpu.h                |   2 +
 target/i386/monitor.c            | 233 +++++++++----------------------
 4 files changed, 75 insertions(+), 168 deletions(-)

diff --git a/include/hw/core/sysemu-cpu-ops.h b/include/hw/core/sysemu-cpu-ops.h
index d0e939def8..083df4717c 100644
--- a/include/hw/core/sysemu-cpu-ops.h
+++ b/include/hw/core/sysemu-cpu-ops.h
@@ -225,6 +225,13 @@ typedef struct SysemuCPUOps {
     bool (*mon_flush_page_print_state)(CPUState *cs,
                                        struct mem_print_state *state);
 
+    /**
+     * @mon_print_pte: Hook called by the monitor to print a page
+     * table entry at address addr, with contents pte.
+     */
+    void (*mon_print_pte) (CPUState *cs, GString *buf, hwaddr addr,
+                           hwaddr pte, uint64_t prot, int mmu_idx);
+
 } SysemuCPUOps;
 
 int compressing_iterator(CPUState *cs, void *data, DecodedPTE *pte,
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ec419e0ef0..030198497a 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -8388,6 +8388,7 @@ static const struct SysemuCPUOps i386_sysemu_ops = {
     .mon_init_page_table_iterator = &x86_mon_init_page_table_iterator,
     .mon_info_pg_print_header = &x86_mon_info_pg_print_header,
     .mon_flush_page_print_state = &x86_mon_flush_print_pg_state,
+    .mon_print_pte = &x86_mon_print_pte,
 };
 #endif
 
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
index 4e5877f41d..413c743c1a 100644
--- a/target/i386/cpu.h
+++ b/target/i386/cpu.h
@@ -2264,6 +2264,8 @@ bool x86_mon_init_page_table_iterator(CPUState *cpu, 
GString *buf, int mmu_idx,
                                       struct mem_print_state *state);
 void x86_mon_info_pg_print_header(struct mem_print_state *state);
 bool x86_mon_flush_print_pg_state(CPUState *cs, struct mem_print_state *state);
+void x86_mon_print_pte(CPUState *cs, GString *out_buf, hwaddr addr,
+                       hwaddr child, uint64_t prot, int mmu_idx);
 bool x86_ptw_translate(CPUState *cs, vaddr vaddress, hwaddr *hpa,
                        bool debug, int mmu_idx, bool user_access,
                        const MMUAccessType access_type, uint64_t *page_size,
diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index 8ef92e7c42..d88347684b 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -224,201 +224,98 @@ static hwaddr addr_canonical(CPUArchState *env, hwaddr 
addr)
     return addr;
 }
 
-static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
-                      hwaddr pte, hwaddr mask)
+void x86_mon_print_pte(CPUState *cs, GString *out_buf, hwaddr addr,
+                       hwaddr child, uint64_t prot, int mmu_idx)
 {
+    CPUX86State *env = cpu_env(cs);
+    g_autoptr(GString) buf = g_string_new("");
+
     addr = addr_canonical(env, addr);
 
-    monitor_printf(mon, HWADDR_FMT_plx ": " HWADDR_FMT_plx
-                   " %c%c%c%c%c%c%c%c%c\n",
-                   addr,
-                   pte & mask,
-                   pte & PG_NX_MASK ? 'X' : '-',
-                   pte & PG_GLOBAL_MASK ? 'G' : '-',
-                   pte & PG_PSE_MASK ? 'P' : '-',
-                   pte & PG_DIRTY_MASK ? 'D' : '-',
-                   pte & PG_ACCESSED_MASK ? 'A' : '-',
-                   pte & PG_PCD_MASK ? 'C' : '-',
-                   pte & PG_PWT_MASK ? 'T' : '-',
-                   pte & PG_USER_MASK ? 'U' : '-',
-                   pte & PG_RW_MASK ? 'W' : '-');
-}
+    g_string_append_printf(buf, HWADDR_FMT_plx ": " HWADDR_FMT_plx " ",
+                           addr, child);
 
-static void tlb_info_32(Monitor *mon, CPUArchState *env)
-{
-    unsigned int l1, l2;
-    uint32_t pgd, pde, pte;
+    g_string_append_printf(buf, " %s", pg_bits(cs, prot, mmu_idx));
 
-    pgd = env->cr[3] & ~0xfff;
-    for(l1 = 0; l1 < 1024; l1++) {
-        cpu_physical_memory_read(pgd + l1 * 4, &pde, 4);
-        pde = le32_to_cpu(pde);
-        if (pde & PG_PRESENT_MASK) {
-            if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
-                /* 4M pages */
-                print_pte(mon, env, (l1 << 22), pde, ~((1 << 21) - 1));
-            } else {
-                for(l2 = 0; l2 < 1024; l2++) {
-                    cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4);
-                    pte = le32_to_cpu(pte);
-                    if (pte & PG_PRESENT_MASK) {
-                        print_pte(mon, env, (l1 << 22) + (l2 << 12),
-                                  pte & ~PG_PSE_MASK,
-                                  ~0xfff);
-                    }
-                }
-            }
-        }
-    }
-}
-
-static void tlb_info_pae32(Monitor *mon, CPUArchState *env)
-{
-    unsigned int l1, l2, l3;
-    uint64_t pdpe, pde, pte;
-    uint64_t pdp_addr, pd_addr, pt_addr;
+    /* Trim line to fit screen */
+    g_string_truncate(buf, 79);
 
-    pdp_addr = env->cr[3] & ~0x1f;
-    for (l1 = 0; l1 < 4; l1++) {
-        cpu_physical_memory_read(pdp_addr + l1 * 8, &pdpe, 8);
-        pdpe = le64_to_cpu(pdpe);
-        if (pdpe & PG_PRESENT_MASK) {
-            pd_addr = pdpe & 0x3fffffffff000ULL;
-            for (l2 = 0; l2 < 512; l2++) {
-                cpu_physical_memory_read(pd_addr + l2 * 8, &pde, 8);
-                pde = le64_to_cpu(pde);
-                if (pde & PG_PRESENT_MASK) {
-                    if (pde & PG_PSE_MASK) {
-                        /* 2M pages with PAE, CR4.PSE is ignored */
-                        print_pte(mon, env, (l1 << 30) + (l2 << 21), pde,
-                                  ~((hwaddr)(1 << 20) - 1));
-                    } else {
-                        pt_addr = pde & 0x3fffffffff000ULL;
-                        for (l3 = 0; l3 < 512; l3++) {
-                            cpu_physical_memory_read(pt_addr + l3 * 8, &pte, 
8);
-                            pte = le64_to_cpu(pte);
-                            if (pte & PG_PRESENT_MASK) {
-                                print_pte(mon, env, (l1 << 30) + (l2 << 21)
-                                          + (l3 << 12),
-                                          pte & ~PG_PSE_MASK,
-                                          ~(hwaddr)0xfff);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
+    g_string_append_printf(out_buf, "%s\n", buf->str);
 }
 
-#ifdef TARGET_X86_64
-static void tlb_info_la48(Monitor *mon, CPUArchState *env,
-        uint64_t l0, uint64_t pml4_addr)
+static
+int mem_print_tlb(CPUState *cs, void *data, DecodedPTE *pte, int height,
+                  int offset, int mmu_idx, const PageTableLayout *layout)
 {
-    uint64_t l1, l2, l3, l4;
-    uint64_t pml4e, pdpe, pde, pte;
-    uint64_t pdp_addr, pd_addr, pt_addr;
-
-    for (l1 = 0; l1 < 512; l1++) {
-        cpu_physical_memory_read(pml4_addr + l1 * 8, &pml4e, 8);
-        pml4e = le64_to_cpu(pml4e);
-        if (!(pml4e & PG_PRESENT_MASK)) {
-            continue;
-        }
-
-        pdp_addr = pml4e & 0x3fffffffff000ULL;
-        for (l2 = 0; l2 < 512; l2++) {
-            cpu_physical_memory_read(pdp_addr + l2 * 8, &pdpe, 8);
-            pdpe = le64_to_cpu(pdpe);
-            if (!(pdpe & PG_PRESENT_MASK)) {
-                continue;
-            }
+    struct mem_print_state *state = (struct mem_print_state *) data;
+    CPUClass *cc = CPU_GET_CLASS(cs);
 
-            if (pdpe & PG_PSE_MASK) {
-                /* 1G pages, CR4.PSE is ignored */
-                print_pte(mon, env, (l0 << 48) + (l1 << 39) + (l2 << 30),
-                        pdpe, 0x3ffffc0000000ULL);
-                continue;
-            }
-
-            pd_addr = pdpe & 0x3fffffffff000ULL;
-            for (l3 = 0; l3 < 512; l3++) {
-                cpu_physical_memory_read(pd_addr + l3 * 8, &pde, 8);
-                pde = le64_to_cpu(pde);
-                if (!(pde & PG_PRESENT_MASK)) {
-                    continue;
-                }
+    cc->sysemu_ops->mon_print_pte(cs, state->buf, pte->bits_translated,
+                                  pte->child, pte->prot, mmu_idx);
 
-                if (pde & PG_PSE_MASK) {
-                    /* 2M pages, CR4.PSE is ignored */
-                    print_pte(mon, env, (l0 << 48) + (l1 << 39) + (l2 << 30) +
-                            (l3 << 21), pde, 0x3ffffffe00000ULL);
-                    continue;
-                }
-
-                pt_addr = pde & 0x3fffffffff000ULL;
-                for (l4 = 0; l4 < 512; l4++) {
-                    cpu_physical_memory_read(pt_addr
-                            + l4 * 8,
-                            &pte, 8);
-                    pte = le64_to_cpu(pte);
-                    if (pte & PG_PRESENT_MASK) {
-                        print_pte(mon, env, (l0 << 48) + (l1 << 39) +
-                                (l2 << 30) + (l3 << 21) + (l4 << 12),
-                                pte & ~PG_PSE_MASK, 0x3fffffffff000ULL);
-                    }
-                }
-            }
-        }
-    }
+    return 0;
 }
 
-static void tlb_info_la57(Monitor *mon, CPUArchState *env)
+static
+void helper_hmp_info_tlb(CPUState *cs, Monitor *mon, int mmu_idx)
 {
-    uint64_t l0;
-    uint64_t pml5e;
-    uint64_t pml5_addr;
+    struct mem_print_state state;
+    g_autoptr(GString) buf = g_string_new("");
+    CPUClass *cc = CPU_GET_CLASS(cs);
 
-    pml5_addr = env->cr[3] & 0x3fffffffff000ULL;
-    for (l0 = 0; l0 < 512; l0++) {
-        cpu_physical_memory_read(pml5_addr + l0 * 8, &pml5e, 8);
-        pml5e = le64_to_cpu(pml5e);
-        if (pml5e & PG_PRESENT_MASK) {
-            tlb_info_la48(mon, env, l0, pml5e & 0x3fffffffff000ULL);
-        }
+    if (!cc->sysemu_ops->mon_init_page_table_iterator(cs, buf, mmu_idx,
+                                                      &state)) {
+        monitor_printf(mon, "Unable to initialize page table iterator\n");
+        return;
     }
+
+    /**
+     * 'info tlb' visits only leaf PTEs marked present.
+     * It does not check other protection bits.
+     */
+    for_each_pte(cs, &mem_print_tlb, &state, false, false, false,  mmu_idx);
+
+    monitor_printf(mon, "%s", buf->str);
 }
-#endif /* TARGET_X86_64 */
 
 void hmp_info_tlb(Monitor *mon, const QDict *qdict)
 {
-    CPUArchState *env;
+    CPUState *cs = mon_get_cpu(mon);
+    bool nested;
 
-    env = mon_get_cpu_env(mon);
-    if (!env) {
-        monitor_printf(mon, "No CPU available\n");
+    if (!cs) {
+        monitor_printf(mon, "Unable to get CPUState.  Internal error\n");
         return;
     }
 
-    if (!(env->cr[0] & CR0_PG_MASK)) {
+    if (!cpu_paging_enabled(cs, 0)) {
         monitor_printf(mon, "PG disabled\n");
         return;
     }
-    if (env->cr[4] & CR4_PAE_MASK) {
-#ifdef TARGET_X86_64
-        if (env->hflags & HF_LMA_MASK) {
-            if (env->cr[4] & CR4_LA57_MASK) {
-                tlb_info_la57(mon, env);
-            } else {
-                tlb_info_la48(mon, env, 0, env->cr[3] & 0x3fffffffff000ULL);
-            }
-        } else
-#endif
-        {
-            tlb_info_pae32(mon, env);
-        }
-    } else {
-        tlb_info_32(mon, env);
+
+    CPUClass *cc = CPU_GET_CLASS(cs);
+
+    if (!cc->sysemu_ops->mon_print_pte
+        || !cc->sysemu_ops->mon_init_page_table_iterator) {
+        monitor_printf(mon, "Info tlb unsupported on this ISA\n");
+        return;
+    }
+
+    nested = cpu_paging_enabled(cs, 1);
+
+    if (nested) {
+        monitor_printf(mon,
+                       "Info guest TLB (guest virtual to guest physical):\n");
+    }
+
+    helper_hmp_info_tlb(cs, mon, 0);
+
+    if (nested) {
+        monitor_printf(mon,
+                       "Info host TLB, (guest physical to host physical):\n");
+
+        helper_hmp_info_tlb(cs, mon, 1);
+
     }
 }
 
-- 
2.34.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]