diff mbox series

[v4,2/2] arm/monitor: Add support for 'info tlb' command

Message ID 162928727089.357603.8471789223247950118.stgit@pc-System-Product-Name (mailing list archive)
State New, archived
Headers show
Series arm: Add support for 'info tlb' command | expand

Commit Message

NDNF Aug. 18, 2021, 11:47 a.m. UTC
This adds hmp 'info tlb' command support for the arm platform.
The limitation is that this only implements a page walker for
ARMv8-A AArch64 Long Descriptor format, 32bit addressing is
not supported yet.

Signed-off-by: Changbin Du <changbin.du@gmail.com>
Signed-off-by: Ivanov Arkady <arkaisp2021@gmail.com>
---
 hmp-commands-info.hx |    3 +
 target/arm/monitor.c |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 172 insertions(+), 1 deletion(-)

Comments

Bin Meng Aug. 18, 2021, noon UTC | #1
On Wed, Aug 18, 2021 at 7:48 PM NDNF <arkaisp2021@gmail.com> wrote:
>
> This adds hmp 'info tlb' command support for the arm platform.
> The limitation is that this only implements a page walker for
> ARMv8-A AArch64 Long Descriptor format, 32bit addressing is
> not supported yet.
>
> Signed-off-by: Changbin Du <changbin.du@gmail.com>
> Signed-off-by: Ivanov Arkady <arkaisp2021@gmail.com>
> ---
>  hmp-commands-info.hx |    3 +
>  target/arm/monitor.c |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 172 insertions(+), 1 deletion(-)
>

I believe this is not TLB on ARM, but PTE?

RISC-V implemented a "info mem" for page table walk.

Regards,
Bin
Peter Maydell Aug. 18, 2021, 12:53 p.m. UTC | #2
On Wed, 18 Aug 2021 at 13:00, Bin Meng <bmeng.cn@gmail.com> wrote:
>
> On Wed, Aug 18, 2021 at 7:48 PM NDNF <arkaisp2021@gmail.com> wrote:
> >
> > This adds hmp 'info tlb' command support for the arm platform.
> > The limitation is that this only implements a page walker for
> > ARMv8-A AArch64 Long Descriptor format, 32bit addressing is
> > not supported yet.
> >
> > Signed-off-by: Changbin Du <changbin.du@gmail.com>
> > Signed-off-by: Ivanov Arkady <arkaisp2021@gmail.com>
> > ---
> >  hmp-commands-info.hx |    3 +
> >  target/arm/monitor.c |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  2 files changed, 172 insertions(+), 1 deletion(-)
> >
>
> I believe this is not TLB on ARM, but PTE?
>
> RISC-V implemented a "info mem" for page table walk.

We call our "give page table walk" monitor command "info tlb"
for some reason (probably historical). From the docs:
https://qemu-project.gitlab.io/qemu/system/monitor.html
  info tlb
      Show virtual to physical memory mappings
  info mem
      Show the active virtual memory mappings.

Looking at x86's output, "info tlb" gives lines like this:

ffffffffc04f6000: 00000000b2576000 -G-DA----
ffffffffc04f7000: 00000000b2579000 -G-DA----
ffffffffc04f8000: 00000000bac74000 XG-DA----
ffffffffc04f9000: 00000000b258b000 XG-DA----
ffffffffc04fa000: 00000000b248b000 XG-DA---W
ffffffffc04fb000: 00000000b2431000 XG-DA---W
ffffffffc0502000: 00000000bb69c000 -G-DA----
ffffffffc0503000: 00000000b27d3000 XG-DA----

which is a dump of the page table, with one line per page,
giving the vaddr, the physaddr and associated flag information.

"info mem" gives lines like this:

ffffffffc04f6000-ffffffffc04fa000 0000000000004000 -r-
ffffffffc04fa000-ffffffffc04fc000 0000000000002000 -rw
ffffffffc0502000-ffffffffc0504000 0000000000002000 -r-

which just give "this range of virtual addresses of this
length have these permissions". You can see that it
coalesces multiple adjacent pages with the same permissions
into a single line.

The only architectures which implement "info mem"
are i386 and riscv. If riscv has given the command
different semantics to i386 that would be unfortunate.

"info tlb" is implemented by i386, m68k, nios2, ppc, sh4,
sparc, xtensa.

It's not clear to me that "info mem" is all that useful -- you
can figure out the same info from "info tlb".

-- PMM
Bin Meng Aug. 18, 2021, 1:35 p.m. UTC | #3
On Wed, Aug 18, 2021 at 8:54 PM Peter Maydell <peter.maydell@linaro.org> wrote:
>
> On Wed, 18 Aug 2021 at 13:00, Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > On Wed, Aug 18, 2021 at 7:48 PM NDNF <arkaisp2021@gmail.com> wrote:
> > >
> > > This adds hmp 'info tlb' command support for the arm platform.
> > > The limitation is that this only implements a page walker for
> > > ARMv8-A AArch64 Long Descriptor format, 32bit addressing is
> > > not supported yet.
> > >
> > > Signed-off-by: Changbin Du <changbin.du@gmail.com>
> > > Signed-off-by: Ivanov Arkady <arkaisp2021@gmail.com>
> > > ---
> > >  hmp-commands-info.hx |    3 +
> > >  target/arm/monitor.c |  170 ++++++++++++++++++++++++++++++++++++++++++++++++++
> > >  2 files changed, 172 insertions(+), 1 deletion(-)
> > >
> >
> > I believe this is not TLB on ARM, but PTE?
> >
> > RISC-V implemented a "info mem" for page table walk.
>
> We call our "give page table walk" monitor command "info tlb"
> for some reason (probably historical). From the docs:
> https://qemu-project.gitlab.io/qemu/system/monitor.html
>   info tlb
>       Show virtual to physical memory mappings
>   info mem
>       Show the active virtual memory mappings.
>
> Looking at x86's output, "info tlb" gives lines like this:

I don't know why x86 provides 2 almost the same things.

>
> ffffffffc04f6000: 00000000b2576000 -G-DA----
> ffffffffc04f7000: 00000000b2579000 -G-DA----
> ffffffffc04f8000: 00000000bac74000 XG-DA----
> ffffffffc04f9000: 00000000b258b000 XG-DA----
> ffffffffc04fa000: 00000000b248b000 XG-DA---W
> ffffffffc04fb000: 00000000b2431000 XG-DA---W
> ffffffffc0502000: 00000000bb69c000 -G-DA----
> ffffffffc0503000: 00000000b27d3000 XG-DA----
>

Naming it to "tlb" really confuses people. On ppce500, "info tlb"
gives the real processor TLBs, not the PTEs.

(qemu) info tlb

TLB0:
Effective          Physical           Size TID   TS SRWX URWX WIMGE U0123

TLB1:
Effective          Physical           Size TID   TS SRWX URWX WIMGE U0123
0x00000000e0000000 0x0000000fe0000000   1M 0     0  SRW-U--- -I-G- U----
0x0000000000000000 0x0000000000000000  64M 0     0  SRWXU--- --M-- U----
0x0000000004000000 0x0000000004000000  64M 0     0  SRWXU--- --M-- U----
0x00000000f0000000 0x0000000f00000000  64M 0     0  SRW-U--- -I-G- U----
0x0000000080000000 0x0000000c00000000 256M 0     0  SRW-U--- -I-G- U----
0x0000000090000000 0x0000000c10000000 256M 0     0  SRW-U--- -I-G- U----
0x00000000a0000000 0x0000000fe1000000  64K 0     0  SRW-U--- -I-G- U----
0x00000000f4000000 0x0000000f04000000  64M 0     0  SRW-U--- -I-G- U----

So we are unfortunately inconsistent among these arches that support "info tlb".

> which is a dump of the page table, with one line per page,
> giving the vaddr, the physaddr and associated flag information.
>
> "info mem" gives lines like this:
>
> ffffffffc04f6000-ffffffffc04fa000 0000000000004000 -r-
> ffffffffc04fa000-ffffffffc04fc000 0000000000002000 -rw
> ffffffffc0502000-ffffffffc0504000 0000000000002000 -r-
>
> which just give "this range of virtual addresses of this
> length have these permissions". You can see that it
> coalesces multiple adjacent pages with the same permissions
> into a single line.
>
> The only architectures which implement "info mem"
> are i386 and riscv. If riscv has given the command
> different semantics to i386 that would be unfortunate.
>
> "info tlb" is implemented by i386, m68k, nios2, ppc, sh4,
> sparc, xtensa.
>
> It's not clear to me that "info mem" is all that useful -- you
> can figure out the same info from "info tlb".

Yes. But I feel "info mem" is more a suitable name than "info tlb"
unless we are really printing the TLB.

Regards,
Bin
diff mbox series

Patch

diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
index 117ba25f91..1b5b3f2616 100644
--- a/hmp-commands-info.hx
+++ b/hmp-commands-info.hx
@@ -222,7 +222,8 @@  SRST
 ERST
 
 #if defined(TARGET_I386) || defined(TARGET_SH4) || defined(TARGET_SPARC) || \
-    defined(TARGET_PPC) || defined(TARGET_XTENSA) || defined(TARGET_M68K)
+    defined(TARGET_PPC) || defined(TARGET_XTENSA) || defined(TARGET_M68K) || \
+    defined(TARGET_ARM)
     {
         .name       = "tlb",
         .args_type  = "",
diff --git a/target/arm/monitor.c b/target/arm/monitor.c
index 80c64fa355..4f14834148 100644
--- a/target/arm/monitor.c
+++ b/target/arm/monitor.c
@@ -31,6 +31,10 @@ 
 #include "qapi/qmp/qerror.h"
 #include "qapi/qmp/qdict.h"
 #include "qom/qom-qobject.h"
+#include "monitor/monitor.h"
+#include "monitor/hmp-target.h"
+#include "internals.h"
+#include "qemu/qemu-print.h"
 
 static GICCapability *gic_cap_new(int version)
 {
@@ -228,3 +232,169 @@  CpuModelExpansionInfo *qmp_query_cpu_model_expansion(CpuModelExpansionType type,
 
     return expansion_info;
 }
+
+#define PTE_HEADER_FIELDS       "vaddr              paddr              "\
+                                "size               attr\n"
+#define PTE_HEADER_DELIMITER    "------------------ ------------------ "\
+                                "------------------ ------------------------------\n"
+
+static void print_pte_header(void)
+{
+    qemu_printf(PTE_HEADER_FIELDS);
+    qemu_printf(PTE_HEADER_DELIMITER);
+}
+
+static void
+print_pte_lpae(uint32_t tableattrs, uint64_t vaddr, hwaddr paddr,
+               target_ulong size, target_ulong pte)
+{
+    uint32_t ns = extract64(pte, 5, 1) | extract32(tableattrs, 4, 1);
+    uint32_t ap = extract64(pte, 6, 2) & ~extract32(tableattrs, 2, 2);
+    uint32_t af = extract64(pte, 10, 1);
+    uint32_t ng = extract64(pte, 11, 1);
+    uint32_t gp = extract64(pte, 50, 1);
+    uint32_t con = extract64(pte, 52, 1);
+    uint32_t pxn = extract64(pte, 53, 1) | extract32(tableattrs, 0, 1);
+    uint32_t uxn = extract64(pte, 54, 1) | extract32(tableattrs, 1, 1);
+
+    qemu_printf("0x%016lx 0x" TARGET_FMT_plx " 0x" TARGET_FMT_lx
+                   " %s %s %s %s %s %s %s %s %s\n",
+                   vaddr, paddr, size,
+                   ap & 0x2 ? "ro" : "RW",
+                   ap & 0x1 ? "USR" : "   ",
+                   ns ? "NS" : "  ",
+                   af ? "AF" : "  ",
+                   ng ? "nG" : "  ",
+                   gp ? "GP" : "  ",
+                   con ? "Con" : "   ",
+                   pxn ? "PXN" : "   ",
+                   uxn ? "UXN" : "   ");
+}
+
+static void
+walk_pte_lpae(uint64_t descaddrmask, uint32_t tableattrs, hwaddr base,
+              uint64_t vaddr, int level, int stride, int inputsize,
+              ARMMMUIdx mmu_idx, CPUState *cs, ARMMMUFaultInfo *fi)
+{
+    int indx;
+    for (indx = 0; indx < (1ul << stride); indx++) {
+        uint64_t descriptor, cur_IA, cur_vaddr = vaddr;
+        uint32_t cur_tableattrs = tableattrs;
+        hwaddr descaddr;
+        target_ulong pgsize;
+        bool nstable;
+
+        cur_IA = ((uint64_t)indx << ((stride * (4 - level)) + 3));
+        cur_vaddr += cur_IA;
+        descaddr = base + (indx << 3);
+        descaddr &= ~7ULL;
+        nstable = extract32(cur_tableattrs, 4, 1);
+        descriptor = arm_ldq_ptw(cs, descaddr, !nstable, mmu_idx, fi);
+        if (fi->type != ARMFault_None) {
+            continue;
+        }
+
+        if (!(descriptor & 1) ||
+            (!(descriptor & 2) && (level == 3))) {
+            /* Invalid, or the Reserved level 3 encoding */
+            continue;
+        }
+        descaddr = descriptor & descaddrmask;
+        if ((descriptor & 2) && (level < 3)) {
+            /* Table entry */
+            cur_tableattrs |= extract64(descriptor, 59, 5);
+            walk_pte_lpae(descaddrmask, cur_tableattrs, descaddr, cur_vaddr,
+                          level + 1, stride, inputsize, mmu_idx, cs, fi);
+            continue;
+        }
+        pgsize = (1ULL << ((stride * (4 - level)) + 3));
+
+        print_pte_lpae(cur_tableattrs, cur_vaddr, descaddr, pgsize, descaddr);
+    }
+}
+
+/* ARMv8-A AArch64 Long Descriptor format */
+static void tlb_info_vmsav8_64(Monitor *mon, CPUArchState *env)
+{
+    ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
+    ARMCPU *cpu = env_archcpu(env);
+    CPUState *cs = CPU(cpu);
+    uint64_t ttbr[2];
+    uint64_t tcr, descaddrmask;
+    int tsz[2];
+    bool using16k, using64k;
+    int stride;
+    uint32_t tableattrs;
+    ARMMMUFaultInfo fi = {};
+
+    ttbr[0] = regime_ttbr(env, mmu_idx, 0);
+    ttbr[1] = regime_ttbr(env, mmu_idx, 1);
+
+    tcr = regime_tcr(env, mmu_idx)->raw_tcr;
+    using64k = extract32(tcr, 14, 1);
+    using16k = extract32(tcr, 15, 1);
+    tsz[0] = extract32(tcr, 0, 6);
+    tsz[1] = extract32(tcr, 16, 6);
+
+    if (using64k) {
+        stride = 13;
+    } else if (using16k) {
+        stride = 11;
+    } else {
+        stride = 9;
+    }
+
+    hwaddr indexmask_grainsize = (1ULL << (stride + 3)) - 1;
+    descaddrmask = ((1ull << 48) - 1) &  ~indexmask_grainsize;
+
+    tableattrs = regime_is_secure(env, mmu_idx) ? 0 : (1 << 4);
+
+    /* print header */
+    print_pte_header();
+
+    for (unsigned int i = 0; i < 2; i++) {
+        if (ttbr[i]) {
+            hwaddr base, indexmask;
+            int inputsize, level;
+            uint64_t vaddr;
+            base = extract64(ttbr[i], 0, 48);
+            inputsize = 64 - tsz[i];
+            level = pt_start_level_stage1(inputsize, stride);
+            indexmask = (1ULL << (inputsize - (stride * (4 - level)))) - 1;
+            base &= ~indexmask;
+            vaddr = i == 0 ? 0 : ~((1ull << inputsize) - 1);
+
+            walk_pte_lpae(descaddrmask, tableattrs, base, vaddr, level, stride,
+                          inputsize, mmu_idx, cs, &fi);
+        }
+    }
+}
+
+void hmp_info_tlb(Monitor *mon, const QDict *qdict)
+{
+    CPUArchState *env;
+    env = mon_get_cpu_env(mon);
+    if (!env) {
+        monitor_printf(mon, "No CPU available\n");
+        return;
+    }
+
+    if (arm_feature(env, ARM_FEATURE_PMSA)) {
+        monitor_printf(mon, "No MMU\n");
+        return;
+    }
+
+    ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env);
+
+    if (regime_translation_disabled(env, mmu_idx)) {
+        monitor_printf(mon, "MMU disabled\n");
+        return;
+    }
+
+    if (!arm_s1_regime_using_lpae_format(env, mmu_idx)) {
+        monitor_printf(mon, "Only AArch64 Long Descriptor is supported\n");
+        return;
+    }
+
+    tlb_info_vmsav8_64(mon, env);
+}