> -----Original Message-----
> From: Brian Cain <[email protected]>
> Sent: Friday, February 28, 2025 11:26 PM
> To: [email protected]
> Cc: [email protected]; [email protected];
> [email protected]; [email protected]; [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; [email protected];
> [email protected]; Brian Cain <[email protected]>; Michael Lambert
> <[email protected]>
> Subject: [PATCH 34/38] target/hexagon: Add initial MMU model
> 
> From: Brian Cain <[email protected]>
> 
> Co-authored-by: Taylor Simpson <[email protected]>
> Co-authored-by: Michael Lambert <[email protected]>
> Co-authored-by: Sid Manning <[email protected]>
> Co-authored-by: Matheus Tavares Bernardino
> <[email protected]>
> Signed-off-by: Brian Cain <[email protected]>


> diff --git a/target/hexagon/hex_mmu.c b/target/hexagon/hex_mmu.c new
> file mode 100644 index 0000000000..54c4ba2dbf
> --- /dev/null
> +++ b/target/hexagon/hex_mmu.c
> @@ -0,0 +1,528 @@
> +/*
> + * Copyright(c) 2019-2025 Qualcomm Innovation Center, Inc. All Rights
> Reserved.
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later  */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/main-loop.h"
> +#include "qemu/qemu-print.h"
> +#include "cpu.h"
> +#include "system/cpus.h"
> +#include "internal.h"
> +#include "exec/exec-all.h"
> +#include "hex_mmu.h"
> +#include "macros.h"
> +#include "sys_macros.h"
> +#include "reg_fields.h"
> +
> +#define GET_TLB_FIELD(ENTRY, FIELD)                               \
> +    ((uint64_t)fEXTRACTU_BITS(ENTRY, reg_field_info[FIELD].width, \
> +                              reg_field_info[FIELD].offset))
> +
> +/* PPD (physical page descriptor) */
> +static inline uint64_t GET_PPD(uint64_t entry) {
> +    return GET_TLB_FIELD(entry, PTE_PPD) |
> +        (GET_TLB_FIELD(entry, PTE_PA35) <<
> +reg_field_info[PTE_PPD].width); }
> +
> +#define NO_ASID      (1 << 8)
> +
> +typedef enum {
> +    PGSIZE_4K,
> +    PGSIZE_16K,
> +    PGSIZE_64K,
> +    PGSIZE_256K,
> +    PGSIZE_1M,
> +    PGSIZE_4M,
> +    PGSIZE_16M,
> +    PGSIZE_64M,
> +    PGSIZE_256M,
> +    PGSIZE_1G,
> +    NUM_PGSIZE_TYPES
> +} tlb_pgsize_t;
> +
> +static const char *pgsize_str[NUM_PGSIZE_TYPES] = {
> +    "4K",
> +    "16K",
> +    "64K",
> +    "256K",
> +    "1M",
> +    "4M",
> +    "16M",
> +    "64M",
> +    "256M",
> +    "1G",
> +};
> +
> +#define INVALID_MASK 0xffffffffLL
> +
> +static const uint64_t encmask_2_mask[] = {
> +    0x0fffLL,                           /* 4k,   0000 */
> +    0x3fffLL,                           /* 16k,  0001 */
> +    0xffffLL,                           /* 64k,  0010 */
> +    0x3ffffLL,                          /* 256k, 0011 */
> +    0xfffffLL,                          /* 1m,   0100 */
> +    0x3fffffLL,                         /* 4m,   0101 */
> +    0xffffffLL,                         /* 16m,  0110 */
> +    0x3ffffffLL,                        /* 64m,  0111 */
> +    0xfffffffLL,                        /* 256m, 1000 */
> +    0x3fffffffLL,                       /* 1g,   1001 */
> +    INVALID_MASK,                      /* RSVD, 0111 */
> +};
> +
> +/*
> + * @return the page size type from @a entry.
> + */
> +static inline tlb_pgsize_t hex_tlb_pgsize_type(uint64_t entry) {
> +    if (entry == 0) {
> +        qemu_log_mask(CPU_LOG_MMU, "%s: Supplied TLB entry was 0!\n",
> __func__);
> +        return 0;
> +    }
> +    tlb_pgsize_t size = ctz64(entry);
> +    g_assert(size < NUM_PGSIZE_TYPES);
> +    return size;
> +}
> +
> +/*
> + * @return the page size of @a entry, in bytes.
> + */
> +static inline uint64_t hex_tlb_page_size_bytes(uint64_t entry) {
> +    return 1ull << (TARGET_PAGE_BITS + 2 * hex_tlb_pgsize_type(entry));
> +}
> +
> +static inline uint64_t hex_tlb_phys_page_num(uint64_t entry) {
> +    uint32_t ppd = GET_PPD(entry);
> +    return ppd >> 1;
> +}
> +
> +static inline uint64_t hex_tlb_phys_addr(uint64_t entry) {
> +    uint64_t pagemask = encmask_2_mask[hex_tlb_pgsize_type(entry)];
> +    uint64_t pagenum = hex_tlb_phys_page_num(entry);
> +    uint64_t PA = (pagenum << TARGET_PAGE_BITS) & (~pagemask);
> +    return PA;
> +}
> +
> +static inline uint64_t hex_tlb_virt_addr(uint64_t entry) {
> +    return (uint64_t)GET_TLB_FIELD(entry, PTE_VPN) <<
> TARGET_PAGE_BITS;
> +}
> +
> +static bool hex_dump_mmu_entry(FILE *f, uint64_t entry) {
> +    if (GET_TLB_FIELD(entry, PTE_V)) {
> +        fprintf(f, "0x%016" PRIx64 ": ", entry);
> +        uint64_t PA = hex_tlb_phys_addr(entry);
> +        uint64_t VA = hex_tlb_virt_addr(entry);
> +        fprintf(f, "V:%" PRId64 " G:%" PRId64 " A1:%" PRId64 " A0:%" PRId64,
> +                GET_TLB_FIELD(entry, PTE_V), GET_TLB_FIELD(entry, PTE_G),
> +                GET_TLB_FIELD(entry, PTE_ATR1), GET_TLB_FIELD(entry,
> PTE_ATR0));
> +        fprintf(f, " ASID:0x%02" PRIx64 " VA:0x%08" PRIx64,
> +                GET_TLB_FIELD(entry, PTE_ASID), VA);
> +        fprintf(f,
> +                " X:%" PRId64 " W:%" PRId64 " R:%" PRId64 " U:%" PRId64
> +                " C:%" PRId64,
> +                GET_TLB_FIELD(entry, PTE_X), GET_TLB_FIELD(entry, PTE_W),
> +                GET_TLB_FIELD(entry, PTE_R), GET_TLB_FIELD(entry, PTE_U),
> +                GET_TLB_FIELD(entry, PTE_C));
> +        fprintf(f, " PA:0x%09" PRIx64 " SZ:%s (0x%" PRIx64 ")", PA,
> +                pgsize_str[hex_tlb_pgsize_type(entry)],
> +                hex_tlb_page_size_bytes(entry));
> +        fprintf(f, "\n");
> +        return true;
> +    }
> +
> +    /* Not valid */
> +    return false;
> +}
> +
> +void dump_mmu(CPUHexagonState *env)
> +{
> +    int i;
> +
> +    HexagonCPU *cpu = env_archcpu(env);
> +    for (i = 0; i < cpu->num_tlbs; i++) {
> +        uint64_t entry = env->hex_tlb->entries[i];
> +        if (GET_TLB_FIELD(entry, PTE_V)) {
> +            qemu_printf("0x%016" PRIx64 ": ", entry);
> +            uint64_t PA = hex_tlb_phys_addr(entry);
> +            uint64_t VA = hex_tlb_virt_addr(entry);
> +            qemu_printf(
> +                "V:%" PRId64 " G:%" PRId64 " A1:%" PRId64 " A0:%" PRId64,
> +                GET_TLB_FIELD(entry, PTE_V), GET_TLB_FIELD(entry, PTE_G),
> +                GET_TLB_FIELD(entry, PTE_ATR1), GET_TLB_FIELD(entry,
> PTE_ATR0));
> +            qemu_printf(" ASID:0x%02" PRIx64 " VA:0x%08" PRIx64,
> +                        GET_TLB_FIELD(entry, PTE_ASID), VA);
> +            qemu_printf(
> +                " X:%" PRId64 " W:%" PRId64 " R:%" PRId64 " U:%" PRId64
> +                " C:%" PRId64,
> +                GET_TLB_FIELD(entry, PTE_X), GET_TLB_FIELD(entry, PTE_W),
> +                GET_TLB_FIELD(entry, PTE_R), GET_TLB_FIELD(entry, PTE_U),
> +                GET_TLB_FIELD(entry, PTE_C));
> +            qemu_printf(" PA:0x%09" PRIx64 " SZ:%s (0x%" PRIx64 ")", PA,
> +                        pgsize_str[hex_tlb_pgsize_type(entry)],
> +                        hex_tlb_page_size_bytes(entry));
> +            qemu_printf("\n");

Use hex_dump_mmu_entry instead.

> +        }
> +    }
> +}
> +
> +static inline void hex_log_tlbw(uint32_t index, uint64_t entry) {
> +    if (qemu_loglevel_mask(CPU_LOG_MMU)) {
> +        if (qemu_log_enabled()) {
> +            FILE *logfile = qemu_log_trylock();
> +            if (logfile) {
> +                fprintf(logfile, "tlbw[%03d]: ", index);
> +                if (!hex_dump_mmu_entry(logfile, entry)) {
> +                    fprintf(logfile, "invalid\n");
> +                }
> +                qemu_log_unlock(logfile);
> +            }
> +        }
> +    }
> +}
> +
> +void hex_tlbw(CPUHexagonState *env, uint32_t index, uint64_t value) {
> +    uint32_t myidx = fTLB_NONPOW2WRAP(fTLB_IDXMASK(index));
> +    bool old_entry_valid = GET_TLB_FIELD(env->hex_tlb->entries[myidx],
> PTE_V);
> +    if (old_entry_valid && hexagon_cpu_mmu_enabled(env)) {
> +        CPUState *cs = env_cpu(env);
> +
> +        tlb_flush(cs);
> +    }
> +    env->hex_tlb->entries[myidx] = (value);
> +    hex_log_tlbw(myidx, value);
> +}
> +
> +void hex_mmu_realize(CPUHexagonState *env) {
> +    CPUState *cs = env_cpu(env);
> +    if (cs->cpu_index == 0) {
> +        env->hex_tlb = g_malloc0(sizeof(CPUHexagonTLBContext));
> +    } else {
> +        CPUState *cpu0_s = NULL;
> +        CPUHexagonState *env0 = NULL;
> +        CPU_FOREACH(cpu0_s) {
> +            assert(cpu0_s->cpu_index == 0);
> +            env0 = &(HEXAGON_CPU(cpu0_s)->env);
> +            break;
> +        }

Seems fragile to assume cpu_index == 0 will be first in CPU_FOREACH.  This 
would be better
    CPU_FOREACH(cpu0_s) {
        if (cpu0_s->cpu_index == 0) {
            env0 = &(HEXAGON_CPU(cpu0_s)->env);
            break;
        }
    }
    g_assert(env0);  /* Make sure we found it */


> +        env->hex_tlb = env0->hex_tlb;
> +    }
> +}


> diff --git a/target/hexagon/meson.build b/target/hexagon/meson.build
> index 3ec53010fa..aa729a3683 100644
> --- a/target/hexagon/meson.build
> +++ b/target/hexagon/meson.build
> @@ -273,7 +273,8 @@ hexagon_ss.add(files(
>  #     idef-generated-enabled-instructions
>  #
>  idef_parser_enabled = get_option('hexagon_idef_parser') -if
> idef_parser_enabled and 'hexagon-linux-user' in target_dirs
> +if idef_parser_enabled and ('hexagon-linux-user' in target_dirs or
> +                            'hexagon-softmmu' in target_dirs)
>      idef_parser_input_generated = custom_target(
>          'idef_parser_input.h.inc',
>          output: 'idef_parser_input.h.inc',

Move this to later patch "add build config for softmmu"




Reply via email to