All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Dr. David Alan Gilbert" <dave@treblig.org>
To: Don Porter <porter@cs.unc.edu>
Cc: qemu-devel@nongnu.org, peter.maydell@linaro.org,
	nadav.amit@gmail.com, richard.henderson@linaro.org,
	philmd@linaro.org, berrange@redhat.com
Subject: Re: [PATCH v4 4/7] Convert 'info tlb' to use generic iterator.
Date: Sat, 27 Jul 2024 20:47:56 +0000	[thread overview]
Message-ID: <ZqVc_Jzs319S55sR@gallifrey> (raw)
In-Reply-To: <20240723010545.3648706-5-porter@cs.unc.edu>

* Don Porter (porter@cs.unc.edu) wrote:
> 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:

This surprises me from the title; the title made me think
this was a change purely to the implementation.

> (qemu) info tlb
> Info guest TLB (guest virtual to guest physical):

It's a shame that the code that prints this has no way to know the column widths,
since it would be nice to have:

   guest virt           guest phys    ???????????
> 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):

Do you actually want this to happen in the same operation, or do you
want info tlb -h (e.g.) to get the host info?

> 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++) {

It's nice to see all this hairy code disappearing.

> -        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);

Do we need that?  It's a pretty arbitrary limit these days.

> -    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.

(What happens if the guest is using huge pages inside the guest?)

> +     */
> +    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");

I wouldn't bother saying ' Internal error'.

>          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
> 
-- 
 -----Open up your eyes, open up your mind, open up your code -------   
/ Dr. David Alan Gilbert    |       Running GNU/Linux       | Happy  \ 
\        dave @ treblig.org |                               | In Hex /
 \ _________________________|_____ http://www.treblig.org   |_______/


  reply	other threads:[~2024-07-27 20:48 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-23  1:05 [PATCH v4 0/7] Rework x86 page table walks Don Porter
2024-07-23  1:05 ` [PATCH v4 1/7] Code motion: expose some TCG definitions for page table walk consolidation Don Porter
2024-07-24  3:14   ` Richard Henderson
2024-07-23  1:05 ` [PATCH v4 2/7] Import vmcs12 definition from Linux/KVM Don Porter
2024-07-24  1:34   ` Dr. David Alan Gilbert
2024-07-24  3:18   ` Richard Henderson
2024-07-23  1:05 ` [PATCH v4 3/7] Add an "info pg" command that prints the current page tables Don Porter
2024-07-24  3:33   ` Richard Henderson
2024-07-26 20:07     ` Don Porter
2024-07-23  1:05 ` [PATCH v4 4/7] Convert 'info tlb' to use generic iterator Don Porter
2024-07-27 20:47   ` Dr. David Alan Gilbert [this message]
2024-07-23  1:05 ` [PATCH v4 5/7] Convert 'info mem' " Don Porter
2024-07-23  1:05 ` [PATCH v4 6/7] Convert x86_cpu_get_memory_mapping() to use generic iterators Don Porter
2024-07-23  1:05 ` [PATCH v4 7/7] Convert x86_mmu_translate() to use common code Don Porter
2024-07-24  3:39 ` [PATCH v4 0/7] Rework x86 page table walks Richard Henderson
2024-08-02 16:53   ` Don Porter

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZqVc_Jzs319S55sR@gallifrey \
    --to=dave@treblig.org \
    --cc=berrange@redhat.com \
    --cc=nadav.amit@gmail.com \
    --cc=peter.maydell@linaro.org \
    --cc=philmd@linaro.org \
    --cc=porter@cs.unc.edu \
    --cc=qemu-devel@nongnu.org \
    --cc=richard.henderson@linaro.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.