At 2026-07-02 05:05:58, "Dr. David Alan Gilbert" <[email protected]> wrote:
>(Added Phil's new address in)
>
>* [email protected] ([email protected]) wrote:
>> When booting an i386 target, the `info tlb` command
>> may walk the entire page table hierarchy and emit
>> an enormous amount of output.
>> It will take dozens of minutes to print all the info,
>> because each monitor print function will holds 'mon_lock'.
>> This effectively hangs the qemu monitor.
>>
>> It may be better to add warning note in help message,
>> and add a address range by argument to help user control
>> the number of output items.
>>
>> Signed-off-by: Alano Song <[email protected]>
>> ---
>> hmp-commands-info.hx | 12 ++++---
>> target/i386/monitor.c | 82 +++++++++++++++++++++++++++++--------------
>> 2 files changed, 64 insertions(+), 30 deletions(-)
>>
>> diff --git a/hmp-commands-info.hx b/hmp-commands-info.hx
>> index 82134eb6c2..3189e20de3 100644
>> --- a/hmp-commands-info.hx
>> +++ b/hmp-commands-info.hx
>> @@ -188,17 +188,21 @@ ERST
>>
>> {
>> .name = "tlb",
>> - .args_type = "",
>> - .params = "",
>> - .help = "show virtual to physical memory mappings",
>> + .args_type = "start:l?,end:l?",
>> + .params = "[start [end]]",
>> + .help = "show virtual to physical memory mappings. "
>
>> + "output can be extremely large for i386 target. "
>> + "use 'info tlb [start] [end]' to show a range of
>> entries.",
>
>That can be;
>> + "The address range can be limited with the optional
>> parameters."
>
>Now, is that the *virtual* address - because it feels like that needs
>specifying.
>
>> .cmd = hmp_info_tlb,
>> .arch_bitmask = QEMU_ARCH_I386 | QEMU_ARCH_SH4 | QEMU_ARCH_SPARC \
>> | QEMU_ARCH_PPC | QEMU_ARCH_XTENSA | QEMU_ARCH_M68K,
>
>You have added the start/end params to the help, but only implemented it on
>x86.
>That seems odd.
>
>Dave
>
Hi Dr. Gilbert,
On this patch, I’m currently enabling the `start`/`end` parameters only for
x86, since other targets typically maintain a relatively small TLB.
For example, xtensa only has a handful of entries, as shown below, so it’s
reasonable to simply ignore start/end parameters and dump all items:
// target/xtensa/cpu.h
...
#define MAX_TLB_WAY_SIZE 8
...
struct CPUArchState {
...
#ifndef CONFIG_USER_ONLY
xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE];
xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE];
...
The same applies to sparc64, ppc, and sh4.
Thanks for the reminder.
I went through all architectures supporting the
`info tlb` command. I noticed that sparc32 and m68k may also produce a
large number of TLB entries, so I plan to extend start/end filtering
to those as well.
What do you think?
Alano.
>> },
>>
>> SRST
>> - ``info tlb``
>> + ``info tlb`` [*start* [*end*]]
>> Show virtual to physical memory mappings.
>> + The output can be extremely large for i386 target.
>> + Use *start* and *end* to print entries located in address range [start,
>> end].
>> ERST
>>
>> {
>> diff --git a/target/i386/monitor.c b/target/i386/monitor.c
>> index a536712c75..c0e0c3e405 100644
>> --- a/target/i386/monitor.c
>> +++ b/target/i386/monitor.c
>> @@ -48,11 +48,9 @@ static hwaddr addr_canonical(CPUArchState *env, hwaddr
>> addr)
>> return addr;
>> }
>>
>> -static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
>> - hwaddr pte, hwaddr mask)
>> +static void do_print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
>> + hwaddr pte, hwaddr mask)
>> {
>> - 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,
>> @@ -68,7 +66,20 @@ static void print_pte(Monitor *mon, CPUArchState *env,
>> hwaddr addr,
>> pte & PG_RW_MASK ? 'W' : '-');
>> }
>>
>> -static void tlb_info_32(Monitor *mon, CPUArchState *env, AddressSpace *as)
>> +static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
>> + hwaddr pte, hwaddr mask,
>> + hwaddr start, hwaddr end)
>> +{
>> + addr = addr_canonical(env, addr);
>> + if (addr < start || addr > end) {
>> + return;
>> + }
>> +
>> + do_print_pte(mon, env, addr, pte, mask);
>> +}
>> +
>> +static void tlb_info_32(Monitor *mon, CPUArchState *env, AddressSpace *as,
>> + hwaddr start, hwaddr end)
>> {
>> const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
>> unsigned int l1, l2;
>> @@ -80,15 +91,15 @@ static void tlb_info_32(Monitor *mon, CPUArchState *env,
>> AddressSpace *as)
>> 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));
>> + print_pte(mon, env, (l1 << 22), pde, ~((1 << 21) - 1),
>> + start, end);
>> } else {
>> for(l2 = 0; l2 < 1024; l2++) {
>> pte = address_space_ldl_le(as, (pde & ~0xfff) + l2 * 4,
>> attrs, NULL);
>> if (pte & PG_PRESENT_MASK) {
>> print_pte(mon, env, (l1 << 22) + (l2 << 12),
>> - pte & ~PG_PSE_MASK,
>> - ~0xfff);
>> + pte & ~PG_PSE_MASK, ~0xfff, start, end);
>> }
>> }
>> }
>> @@ -96,7 +107,8 @@ static void tlb_info_32(Monitor *mon, CPUArchState *env,
>> AddressSpace *as)
>> }
>> }
>>
>> -static void tlb_info_pae32(Monitor *mon, CPUArchState *env, AddressSpace
>> *as)
>> +static void tlb_info_pae32(Monitor *mon, CPUArchState *env, AddressSpace
>> *as,
>> + hwaddr start, hwaddr end)
>> {
>> const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
>> unsigned int l1, l2, l3;
>> @@ -114,17 +126,19 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState
>> *env, AddressSpace *as)
>> 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));
>> + ~((hwaddr)(1 << 20) - 1),
>> + start, end);
>> } else {
>> pt_addr = pde & 0x3fffffffff000ULL;
>> for (l3 = 0; l3 < 512; l3++) {
>> pte = address_space_ldq_le(as, pt_addr + l3 * 8,
>> attrs, NULL);
>> if (pte & PG_PRESENT_MASK) {
>> - print_pte(mon, env, (l1 << 30) + (l2 << 21)
>> - + (l3 << 12),
>> + print_pte(mon, env,
>> + (l1 << 30) + (l2 << 21) + (l3 <<
>> 12),
>> pte & ~PG_PSE_MASK,
>> - ~(hwaddr)0xfff);
>> + ~(hwaddr)0xfff,
>> + start, end);
>> }
>> }
>> }
>> @@ -136,7 +150,8 @@ static void tlb_info_pae32(Monitor *mon, CPUArchState
>> *env, AddressSpace *as)
>>
>> #ifdef TARGET_X86_64
>> static void tlb_info_la48(Monitor *mon, CPUArchState *env, AddressSpace *as,
>> - uint64_t l0, uint64_t pml4_addr)
>> + uint64_t l0, uint64_t pml4_addr, hwaddr start,
>> + hwaddr end)
>> {
>> const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
>> uint64_t l1, l2, l3, l4;
>> @@ -159,7 +174,7 @@ static void tlb_info_la48(Monitor *mon, CPUArchState
>> *env, AddressSpace *as,
>> if (pdpe & PG_PSE_MASK) {
>> /* 1G pages, CR4.PSE is ignored */
>> print_pte(mon, env, (l0 << 48) + (l1 << 39) + (l2 << 30),
>> - pdpe, 0x3ffffc0000000ULL);
>> + pdpe, 0x3ffffc0000000ULL, start, end);
>> continue;
>> }
>>
>> @@ -172,8 +187,9 @@ static void tlb_info_la48(Monitor *mon, CPUArchState
>> *env, AddressSpace *as,
>>
>> 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);
>> + print_pte(mon, env,
>> + (l0 << 48) + (l1 << 39) + (l2 << 30) + (l3 <<
>> 21),
>> + pde, 0x3ffffffe00000ULL, start, end);
>> continue;
>> }
>>
>> @@ -182,9 +198,11 @@ static void tlb_info_la48(Monitor *mon, CPUArchState
>> *env, AddressSpace *as,
>> pte = address_space_ldq_le(as, pt_addr + l4 * 8,
>> attrs, NULL);
>> if (pte & PG_PRESENT_MASK) {
>> - print_pte(mon, env, (l0 << 48) + (l1 << 39) +
>> - (l2 << 30) + (l3 << 21) + (l4 << 12),
>> - pte & ~PG_PSE_MASK, 0x3fffffffff000ULL);
>> + print_pte(mon, env,
>> + (l0 << 48) + (l1 << 39) + (l2 << 30) +
>> + (l3 << 21) + (l4 << 12),
>> + pte & ~PG_PSE_MASK,
>> + 0x3fffffffff000ULL, start, end);
>> }
>> }
>> }
>> @@ -192,7 +210,8 @@ static void tlb_info_la48(Monitor *mon, CPUArchState
>> *env, AddressSpace *as,
>> }
>> }
>>
>> -static void tlb_info_la57(Monitor *mon, CPUArchState *env, AddressSpace *as)
>> +static void tlb_info_la57(Monitor *mon, CPUArchState *env, AddressSpace *as,
>> + hwaddr start, hwaddr end)
>> {
>> const MemTxAttrs attrs = MEMTXATTRS_UNSPECIFIED;
>> uint64_t l0;
>> @@ -203,7 +222,8 @@ static void tlb_info_la57(Monitor *mon, CPUArchState
>> *env, AddressSpace *as)
>> for (l0 = 0; l0 < 512; l0++) {
>> pml5e = address_space_ldq_le(as, pml5_addr + l0 * 8, attrs, NULL);
>> if (pml5e & PG_PRESENT_MASK) {
>> - tlb_info_la48(mon, env, as, l0, pml5e & 0x3fffffffff000ULL);
>> + tlb_info_la48(mon, env, as, l0, pml5e & 0x3fffffffff000ULL,
>> + start, end);
>> }
>> }
>> }
>> @@ -213,6 +233,14 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
>> {
>> CPUArchState *env;
>> AddressSpace *as;
>> + hwaddr start = 0, end = HWADDR_MAX;
>> +
>> + if (qdict_haskey(qdict, "start")) {
>> + start = (hwaddr)qdict_get_int(qdict, "start");
>> + }
>> + if (qdict_haskey(qdict, "end")) {
>> + end = (hwaddr)qdict_get_int(qdict, "end");
>> + }
>>
>> env = mon_get_cpu_env(mon);
>> if (!env) {
>> @@ -229,17 +257,19 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
>> #ifdef TARGET_X86_64
>> if (env->hflags & HF_LMA_MASK) {
>> if (env->cr[4] & CR4_LA57_MASK) {
>> - tlb_info_la57(mon, env, as);
>> + tlb_info_la57(mon, env, as, start, end);
>> } else {
>> - tlb_info_la48(mon, env, as, 0, env->cr[3] &
>> 0x3fffffffff000ULL);
>> + tlb_info_la48(mon, env, as, 0,
>> + env->cr[3] & 0x3fffffffff000ULL,
>> + start, end);
>> }
>> } else
>> #endif
>> {
>> - tlb_info_pae32(mon, env, as);
>> + tlb_info_pae32(mon, env, as, start, end);
>> }
>> } else {
>> - tlb_info_32(mon, env, as);
>> + tlb_info_32(mon, env, as, start, end);
>> }
>> }
>>
>> --
>> 2.43.0
>>
>--
> -----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 |_______/