qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Richard Henderson <richard.henderson@linaro.org>
To: Xiaojuan Yang <yangxiaojuan@loongson.cn>, qemu-devel@nongnu.org
Cc: Song Gao <gaosong@loongson.cn>
Subject: Re: [RFC PATCH v2 07/30] target/loongarch: Add MMU support for LoongArch CPU.
Date: Thu, 11 Nov 2021 16:53:16 +0100	[thread overview]
Message-ID: <d7ad6fa5-8a9d-15e2-8dcb-7499309c7681@linaro.org> (raw)
In-Reply-To: <1636594528-8175-8-git-send-email-yangxiaojuan@loongson.cn>

On 11/11/21 2:35 AM, Xiaojuan Yang wrote:
> This patch introduces basic TLB interfaces.
> 
> Signed-off-by: Xiaojuan Yang <yangxiaojuan@loongson.cn>
> Signed-off-by: Song Gao <gaosong@loongson.cn>
> ---
>   target/loongarch/cpu-param.h  |   3 +
>   target/loongarch/cpu.c        |  36 ++++
>   target/loongarch/cpu.h        |  57 ++++++
>   target/loongarch/internals.h  |   7 +
>   target/loongarch/machine.c    |  56 ++++++
>   target/loongarch/meson.build  |   1 +
>   target/loongarch/tlb_helper.c | 339 ++++++++++++++++++++++++++++++++++
>   7 files changed, 499 insertions(+)
>   create mode 100644 target/loongarch/tlb_helper.c
> 
> diff --git a/target/loongarch/cpu-param.h b/target/loongarch/cpu-param.h
> index 9a769b67e0..5a2147fb90 100644
> --- a/target/loongarch/cpu-param.h
> +++ b/target/loongarch/cpu-param.h
> @@ -12,6 +12,9 @@
>   #define TARGET_PHYS_ADDR_SPACE_BITS 48
>   #define TARGET_VIRT_ADDR_SPACE_BITS 48
>   
> +#define TARGET_PHYS_MASK ((1UL << TARGET_PHYS_ADDR_SPACE_BITS) - 1)
> +#define TARGET_VIRT_MASK ((1UL << TARGET_VIRT_ADDR_SPACE_BITS) - 1)

As before, unsigned long is wrong; use MAKE_64BIT_MASK.

These do not belong in cpu-param.h anyway; probably only tlb_helper.c needs them.

> +#ifndef CONFIG_USER_ONLY
> +    qemu_fprintf(f, "EUEN            0x%lx\n", env->CSR_EUEN);
> +    qemu_fprintf(f, "ESTAT           0x%lx\n", env->CSR_ESTAT);
> +    qemu_fprintf(f, "ERA             0x%lx\n", env->CSR_ERA);
> +    qemu_fprintf(f, "CRMD            0x%lx\n", env->CSR_CRMD);
> +    qemu_fprintf(f, "PRMD            0x%lx\n", env->CSR_PRMD);
> +    qemu_fprintf(f, "BadVAddr        0x%lx\n", env->CSR_BADV);
> +    qemu_fprintf(f, "TLB refill ERA  0x%lx\n", env->CSR_TLBRERA);
> +    qemu_fprintf(f, "TLB refill BadV 0x%lx\n", env->CSR_TLBRBADV);
> +    qemu_fprintf(f, "EENTRY          0x%lx\n", env->CSR_EENTRY);
> +    qemu_fprintf(f, "BadInstr        0x%lx\n", env->CSR_BADI);
> +    qemu_fprintf(f, "PRCFG1    0x%lx\nPRCFG2     0x%lx\nPRCFG3     0x%lx\n",
> +                 env->CSR_PRCFG1, env->CSR_PRCFG3, env->CSR_PRCFG3);

%lx is wrong; use PRIx64.

> +#define LOONGARCH_TLB_MAX      2112 /* 2048 STLB + 64 MTLB */

Better to write (2048 + 64).

> +FIELD(TLB_MISC, E, 0, 1)
> +FIELD(TLB_MISC, ASID, 1, 10)
> +FIELD(TLB_MISC, G, 11, 1)
> +FIELD(TLB_MISC, PS, 12, 6)
> +FIELD(TLB_MISC, VPPN, 18, 35)
> +
> +/* Corresponding to CSR_TLBELO0/1 */
> +FIELD(ENTRY0, V, 0, 1)
> +FIELD(ENTRY0, D, 1, 1)
> +FIELD(ENTRY0, NR, 2, 1)
> +FIELD(ENTRY0, NX, 3, 1)
> +FIELD(ENTRY0, MAT, 4, 2)
> +FIELD(ENTRY0, PLV, 6, 2)
> +FIELD(ENTRY0, RPLV, 8, 1)
> +FIELD(ENTRY0, PPN, 9, 36)
> +
> +FIELD(ENTRY1, V, 0, 1)
> +FIELD(ENTRY1, D, 1, 1)
> +FIELD(ENTRY1, NR, 2, 1)
> +FIELD(ENTRY1, NX, 3, 1)
> +FIELD(ENTRY1, MAT, 4, 2)
> +FIELD(ENTRY1, PLV, 6, 2)
> +FIELD(ENTRY1, RPLV, 8, 1)
> +FIELD(ENTRY1, PPN, 9, 36)

Why are you duplicating the CSR_TLBELO* fields?

> +const VMStateInfo vmstate_info_tlb = {
> +    .name = "tlb_entry",
> +    .get  = get_tlb,
> +    .put  = put_tlb,
> +};

Better to use .fields.

> +#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v)                     \
> +    VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, loongarch_tlb)
> +
> +#define VMSTATE_TLB_ARRAY(_f, _s, _n)                           \
> +    VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0)

Don't need these.

> +
> +const VMStateDescription vmstate_tlb = {
> +    .name = "cpu/tlb",
> +    .version_id = 0,
> +    .minimum_version_id = 0,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_TLB_ARRAY(env.tlb, LoongArchCPU, LOONGARCH_TLB_MAX),

VMSTATE_STRUCT_ARRAY.

> +        VMSTATE_END_OF_LIST()
> +    }
> +};
>   
>   /* LoongArch CPU state */
>   
> @@ -22,6 +70,10 @@ const VMStateDescription vmstate_loongarch_cpu = {
>           VMSTATE_UINT64_ARRAY(env.fpr, LoongArchCPU, 32),
>           VMSTATE_UINT32(env.fcsr0, LoongArchCPU),
>   
> +        /* TLB */
> +        VMSTATE_UINT32(env.stlb_size, LoongArchCPU),
> +        VMSTATE_UINT32(env.mtlb_size, LoongArchCPU),

Might as well keep these in vmstate_tlb.

> +/* TLB address map */
> +static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
> +                                   int *prot, target_ulong address,
> +                                   int access_type, loongarch_tlb *tlb)
> +{
> +    uint64_t plv = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PLV);

Incorrect.  PLV associated with mmu_idx, so you need to use that.

> +    uint8_t tlb_ps, n, tlb_v0, tlb_v1, tlb_d0, tlb_d1;
> +    uint8_t tlb_nx0, tlb_nx1, tlb_nr0, tlb_nr1;
> +    uint64_t tlb_ppn0, tlb_ppn1;
> +    uint8_t tlb_rplv0, tlb_rplv1, tlb_plv0, tlb_plv1;
> +
> +    tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
> +    n = (address >> tlb_ps) & 0x1;/* Odd or even */

Surely you need to pass in tlb_ps, since it's not present in the STLB entries.

> +
> +    tlb_v0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, V);
> +    tlb_d0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, D);
> +    tlb_plv0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, PLV);
> +    tlb_ppn0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, PPN);
> +    tlb_nx0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, NX);
> +    tlb_nr0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, NR);
> +    tlb_rplv0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, RPLV);
> +
> +    tlb_v1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, V);
> +    tlb_d1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, D);
> +    tlb_plv1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, PLV);
> +    tlb_ppn1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, PPN);
> +    tlb_nx1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, NX);
> +    tlb_nr1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, NR);
> +    tlb_rplv1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, RPLV);

Better to check N first.

     entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
     v = FIELD_EX64(entry, TLBENTRY, V);

etc.

> +        *physical = (tlb_ppn1 << 12) | (address & ((1 << tlb_ps) - 1));

TARGET_PAGE_SIZE.

> +/* LoongArch 3A5000 -style MMU emulation */

There's no mention of 3A5000 in "LoongArch Reference Manual", which defines this.  I think 
you've copied this from MIPS, which talks about r4k here.

> +static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
> +                                 int *prot,
> +                                 target_ulong address,
> +                                 MMUAccessType access_type)
> +{
> +    loongarch_tlb *tlb;
> +    uint16_t csr_asid, tlb_asid, stlb_idx;
> +    uint8_t tlb_e, stlb_ps, tlb_ps, tlb_g;
> +    int i, stlb_size, mtlb_size;
> +    uint64_t vpn, tlb_vppn;   /* Address to map */
> +
> +    stlb_size = env->stlb_size;
> +    mtlb_size = env->mtlb_size;
> +    csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
> +
> +    /* Search MTLB */
> +    for (i = stlb_size; i < stlb_size + mtlb_size; ++i) {

Bit of a shame to have a linear search.  I guess it's ok for a start, but you'll find that 
this function is critical to the emulation speed of qemu, so you should think about other 
ways to organize the data.

> +        tlb = &env->tlb[i];
> +        tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
> +        tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
> +
> +        vpn = (address & TARGET_VIRT_MASK) >> (tlb_ps + 1);

Why +1?

> +        tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
> +        tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
> +        tlb_g = FIELD_EX64(tlb->tlb_misc, TLB_MISC, G);
> +
> +        if ((tlb_g == 1 || tlb_asid == csr_asid) &&
> +            (vpn == (tlb_vppn >> (tlb_ps + 1 - 13))) && tlb_e) {

Surely extract and test the enable bit E before anything else, just to speed up the lookup.

The -13 is a bit of a magic number.  Surely TARGET_PAGE_BITS + 1.

> +static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
> +                                int *prot, target_ulong real_address,
> +                                MMUAccessType access_type, int mmu_idx)
> +{
> +    int user_mode = mmu_idx == LOONGARCH_HFLAG_UM;
> +    int kernel_mode = !user_mode;

Incorrect.  PLV == mmu_idx, as defined by cpu_mmu_index.

> +    unsigned plv, base_c, base_v, tmp;
> +    uint64_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
> +
> +    /* Effective address */
> +    target_ulong address = real_address;
> +
> +    /* Check PG */
> +    if (!pg) {
> +        /* DA mode */
> +        *physical = address & TARGET_PHYS_MASK;
> +        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> +        return TLBRET_MATCH;
> +    }

You need to define a fifth mmu_index for paging disabled, because the software tlb handler 
runs in this mode.  If you don't define that, you'll have to flush the softmmu tlb every 
time you have a tlb miss.

> +    plv = kernel_mode | (user_mode << 3);

plv_mask = 1 << plv;

> +    base_v = address >> CSR_DMW_BASE_SH;
> +    /* Check direct map window 0 */
> +    base_c = env->CSR_DMWIN0 >> CSR_DMW_BASE_SH;
> +    if ((plv & env->CSR_DMWIN0) && (base_c == base_v)) {
> +        *physical = dmwin_va2pa(address);
> +        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> +        return TLBRET_MATCH;
> +    }
> +    /* Check direct map window 1 */
> +    base_c = env->CSR_DMWIN1 >> CSR_DMW_BASE_SH;
> +    if ((plv & env->CSR_DMWIN1) && (base_c == base_v)) {
> +        *physical = dmwin_va2pa(address);
> +        *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
> +        return TLBRET_MATCH;
> +    }

There are more than 2 of these, which is why I suggested putting them in an array, so that 
you can loop.  Maybe pull this out to a separate function, like the tlb lookup?

> +    /* Check valid extension */
> +    tmp = address >> (TARGET_VIRT_ADDR_SPACE_BITS - 1);
> +    if (!(tmp == 0 || tmp == 0x1ffff)) {

Better to cast to int64_t first, so that this becomes 0 or -1, without knowing that 64 - 
TARGET_VIRT_ADDR_SPACE_BITS - 1 -> 0x1ffff.

> +void loongarch_mmu_init(CPULoongArchState *env)
> +{
> +    /* Number of MTLB */
> +    env->mtlb_size = 64;
> +
> +    /* Number of STLB */
> +    env->stlb_size = 2048;
> +
> +    /* For 16KB, ps = 14, compare the bit [47:15] */
> +    for (int i = 0; i < LOONGARCH_TLB_MAX; i++) {
> +        env->tlb[i].tlb_misc = FIELD_DP64(env->tlb[i].tlb_misc, TLB_MISC, E, 0);
> +    }

Just memset the whole thing?

> +bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
> +                            MMUAccessType access_type, int mmu_idx,
> +                            bool probe, uintptr_t retaddr)
> +{
> +    LoongArchCPU *cpu = LOONGARCH_CPU(cs);
> +    CPULoongArchState *env = &cpu->env;
> +    hwaddr physical;
> +    int prot;
> +    int ret = TLBRET_BADADDR;
> +
> +    /* Data access */
> +    /* XXX: put correct access by using cpu_restore_state() correctly */
> +    ret = get_physical_address(env, &physical, &prot, address,
> +                               access_type, mmu_idx);
> +    switch (ret) {
> +    case TLBRET_MATCH:
> +        qemu_log_mask(CPU_LOG_MMU,
> +                      "%s address=%" VADDR_PRIx " physical " TARGET_FMT_plx
> +                      " prot %d\n", __func__, address, physical, prot);
> +        break;
> +    default:
> +        qemu_log_mask(CPU_LOG_MMU,
> +                      "%s address=%" VADDR_PRIx " ret %d\n", __func__, address,
> +                      ret);
> +        break;
> +    }
> +    if (ret == TLBRET_MATCH) {
> +        tlb_set_page(cs, address & TARGET_PAGE_MASK,
> +                     physical & TARGET_PAGE_MASK, prot,
> +                     mmu_idx, TARGET_PAGE_SIZE);
> +        return true;

Merge the above switch into this?

> +    }
> +    if (probe) {
> +        return false;
> +    } else {
> +        raise_mmu_exception(env, address, access_type, ret);
> +        do_raise_exception(env, cs->exception_index, retaddr);
> +    }
> +}
> 


r~


  reply	other threads:[~2021-11-11 15:59 UTC|newest]

Thread overview: 62+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-11-11  1:34 [RFC PATCH v2 00/30] Add Loongarch softmmu support Xiaojuan Yang
2021-11-11  1:34 ` [RFC PATCH v2 01/30] target/loongarch: Update README Xiaojuan Yang
2021-11-11 11:50   ` chen huacai
2021-11-15  3:34     ` yangxiaojuan
2021-11-11  1:35 ` [RFC PATCH v2 02/30] target/loongarch: Add CSR registers definition Xiaojuan Yang
2021-11-11 13:29   ` Richard Henderson
2021-11-12  2:14     ` yangxiaojuan
2021-11-12  7:14       ` Richard Henderson
2021-11-11 13:33   ` Richard Henderson
2021-11-11  1:35 ` [RFC PATCH v2 03/30] target/loongarch: Add basic vmstate description of CPU Xiaojuan Yang
2021-11-11 13:30   ` Richard Henderson
2021-11-11  1:35 ` [RFC PATCH v2 04/30] target/loongarch: Define exceptions for LoongArch Xiaojuan Yang
2021-11-11 13:36   ` Richard Henderson
2021-11-12  2:24     ` yangxiaojuan
2021-11-11  1:35 ` [RFC PATCH v2 05/30] target/loongarch: Implement qmp_query_cpu_definitions() Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 06/30] target/loongarch: Add stabletimer support Xiaojuan Yang
2021-11-11 14:34   ` Richard Henderson
2021-11-11  1:35 ` [RFC PATCH v2 07/30] target/loongarch: Add MMU support for LoongArch CPU Xiaojuan Yang
2021-11-11 15:53   ` Richard Henderson [this message]
2021-11-17  6:37     ` yangxiaojuan
2021-11-17  6:59       ` Richard Henderson
2021-11-11  1:35 ` [RFC PATCH v2 08/30] target/loongarch: Add LoongArch CSR/IOCSR instruction Xiaojuan Yang
2021-11-11 17:43   ` Richard Henderson
2021-11-17  8:48     ` yangxiaojuan
2021-11-11  1:35 ` [RFC PATCH v2 09/30] target/loongarch: Add TLB instruction support Xiaojuan Yang
2021-11-11 18:14   ` Richard Henderson
2021-11-17  7:29     ` yangxiaojuan
2021-11-17  8:22       ` Richard Henderson
2021-11-17  8:53         ` yangxiaojuan
2021-11-11  1:35 ` [RFC PATCH v2 10/30] target/loongarch: Add other core instructions support Xiaojuan Yang
2021-11-14 10:19   ` Richard Henderson
2021-11-11  1:35 ` [RFC PATCH v2 11/30] target/loongarch: Add LoongArch interrupt and exception handle Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 12/30] target/loongarch: Add timer related instructions support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 13/30] target/loongarch: Add gdb support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 14/30] target/loongarch: Implement privilege instructions disassembly Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 15/30] hw/pci-host: Add ls7a1000 PCIe Host bridge support for Loongson Platform Xiaojuan Yang
2021-11-11 13:17   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 16/30] hw/loongarch: Add a virt LoongArch 3A5000 board support Xiaojuan Yang
2021-11-11 14:17   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 17/30] hw/loongarch: Add LoongArch cpu interrupt support(CPUINTC) Xiaojuan Yang
2021-11-11 14:22   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 18/30] hw/loongarch: Add LoongArch ipi interrupt support(IPI) Xiaojuan Yang
2021-11-11 14:28   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 19/30] hw/intc: Add LoongArch ls7a interrupt controller support(PCH-PIC) Xiaojuan Yang
2021-11-11 14:37   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 20/30] hw/intc: Add LoongArch ls7a msi interrupt controller support(PCH-MSI) Xiaojuan Yang
2021-11-11 14:40   ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 21/30] hw/intc: Add LoongArch extioi interrupt controller(EIOINTC) Xiaojuan Yang
2021-11-11 14:49   ` Mark Cave-Ayland
2021-11-25  8:20     ` yangxiaojuan
2021-11-26  8:19       ` Mark Cave-Ayland
2021-11-11  1:35 ` [RFC PATCH v2 22/30] hw/loongarch: Add irq hierarchy for the system Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 23/30] hw/loongarch: Add some devices support for 3A5000 Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 24/30] hw/loongarch: Add LoongArch ls7a rtc device support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 25/30] hw/loongarch: Add default bios startup support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 26/30] hw/loongarch: Add -kernel and -initrd options support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 27/30] hw/loongarch: Add LoongArch smbios support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 28/30] hw/loongarch: Add LoongArch acpi support Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 29/30] hw/loongarch: Add machine->possible_cpus Xiaojuan Yang
2021-11-11  1:35 ` [RFC PATCH v2 30/30] hw/loongarch: Add Numa support Xiaojuan Yang
2021-11-11 14:58 ` [RFC PATCH v2 00/30] Add Loongarch softmmu support Mark Cave-Ayland
2021-11-12  1:26   ` yangxiaojuan

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=d7ad6fa5-8a9d-15e2-8dcb-7499309c7681@linaro.org \
    --to=richard.henderson@linaro.org \
    --cc=gaosong@loongson.cn \
    --cc=qemu-devel@nongnu.org \
    --cc=yangxiaojuan@loongson.cn \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).