[PATCH v3 05/17] target/loongarch: Add common function loongarch_check_pte()

Bibo Mao posted 17 patches 3 months, 3 weeks ago
Maintainers: Song Gao <gaosong@loongson.cn>, Bibo Mao <maobibo@loongson.cn>, Jiaxun Yang <jiaxun.yang@flygoat.com>
There is a newer version of this series
[PATCH v3 05/17] target/loongarch: Add common function loongarch_check_pte()
Posted by Bibo Mao 3 months, 3 weeks ago
Common function loongarch_check_pte() is to check tlb entry, return
the physical address and access priviledge. Also it can be used with
page table entry, which is used in page table walker.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
 target/loongarch/cpu-mmu.h        | 10 +++++
 target/loongarch/cpu_helper.c     | 62 ++++++++++++++++++++++++++++++
 target/loongarch/tcg/tlb_helper.c | 63 ++++++-------------------------
 3 files changed, 84 insertions(+), 51 deletions(-)

diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index 4c5cbd7425..62b3acfbc7 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -19,7 +19,17 @@ enum {
     TLBRET_PE = 7,
 };
 
+typedef struct mmu_context {
+    target_ulong  vaddr;
+    uint64_t      pte;
+    hwaddr        physical;
+    int           ps;  /* page size shift */
+    int           prot;
+} mmu_context;
+
 bool check_ps(CPULoongArchState *ent, uint8_t ps);
+int loongarch_check_pte(CPULoongArchState *env, mmu_context *context,
+                        int access_type, int mmu_idx);
 int get_physical_address(CPULoongArchState *env, hwaddr *physical,
                          int *prot, target_ulong address,
                          MMUAccessType access_type, int mmu_idx, int is_debug);
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 2e8d3d7cfb..1b3dfaf15d 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -44,6 +44,68 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
     }
 }
 
+int loongarch_check_pte(CPULoongArchState *env, mmu_context *context,
+                        int access_type, int mmu_idx)
+{
+    uint64_t plv = mmu_idx;
+    uint64_t tlb_entry, tlb_ppn;
+    uint8_t tlb_ps, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
+
+    tlb_entry = context->pte;
+    tlb_ps = context->ps;
+    tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V);
+    tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D);
+    tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
+    if (is_la64(env)) {
+        tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN);
+        tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX);
+        tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR);
+        tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV);
+    } else {
+        tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN);
+        tlb_nx = 0;
+        tlb_nr = 0;
+        tlb_rplv = 0;
+    }
+
+    /* Check access rights */
+    if (!tlb_v) {
+        return TLBRET_INVALID;
+    }
+
+    if (access_type == MMU_INST_FETCH && tlb_nx) {
+        return TLBRET_XI;
+    }
+
+    if (access_type == MMU_DATA_LOAD && tlb_nr) {
+        return TLBRET_RI;
+    }
+
+    if (((tlb_rplv == 0) && (plv > tlb_plv)) ||
+        ((tlb_rplv == 1) && (plv != tlb_plv))) {
+        return TLBRET_PE;
+    }
+
+    if ((access_type == MMU_DATA_STORE) && !tlb_d) {
+        return TLBRET_DIRTY;
+    }
+
+    /* Remove sw bit between bit12 -- bit PS*/
+    tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) - 1));
+    context->physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) |
+                        (context->vaddr & MAKE_64BIT_MASK(0, tlb_ps));
+    context->prot = PAGE_READ;
+    if (tlb_d) {
+        context->prot |= PAGE_WRITE;
+    }
+
+    if (!tlb_nx) {
+        context->prot |= PAGE_EXEC;
+    }
+
+    return TLBRET_MATCH;
+}
+
 static int loongarch_page_table_walker(CPULoongArchState *env, hwaddr *physical,
                                  int *prot, target_ulong address)
 {
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 1f49619e7f..dd99a063cc 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -653,64 +653,25 @@ static int loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
                                    int access_type, int index, int mmu_idx)
 {
     LoongArchTLB *tlb = &env->tlb[index];
-    uint64_t plv = mmu_idx;
-    uint64_t tlb_entry, tlb_ppn;
-    uint8_t tlb_ps, n, tlb_v, tlb_d, tlb_plv, tlb_nx, tlb_nr, tlb_rplv;
+    uint64_t tlb_entry;
+    uint8_t tlb_ps, n;
+    mmu_context context;
+    int ret;
 
     tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
     n = (address >> tlb_ps) & 0x1;/* Odd or even */
 
     tlb_entry = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
-    tlb_v = FIELD_EX64(tlb_entry, TLBENTRY, V);
-    tlb_d = FIELD_EX64(tlb_entry, TLBENTRY, D);
-    tlb_plv = FIELD_EX64(tlb_entry, TLBENTRY, PLV);
-    if (is_la64(env)) {
-        tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_64, PPN);
-        tlb_nx = FIELD_EX64(tlb_entry, TLBENTRY_64, NX);
-        tlb_nr = FIELD_EX64(tlb_entry, TLBENTRY_64, NR);
-        tlb_rplv = FIELD_EX64(tlb_entry, TLBENTRY_64, RPLV);
-    } else {
-        tlb_ppn = FIELD_EX64(tlb_entry, TLBENTRY_32, PPN);
-        tlb_nx = 0;
-        tlb_nr = 0;
-        tlb_rplv = 0;
-    }
-
-    /* Remove sw bit between bit12 -- bit PS*/
-    tlb_ppn = tlb_ppn & ~(((0x1UL << (tlb_ps - 12)) - 1));
-
-    /* Check access rights */
-    if (!tlb_v) {
-        return TLBRET_INVALID;
-    }
-
-    if (access_type == MMU_INST_FETCH && tlb_nx) {
-        return TLBRET_XI;
-    }
-
-    if (access_type == MMU_DATA_LOAD && tlb_nr) {
-        return TLBRET_RI;
-    }
-
-    if (((tlb_rplv == 0) && (plv > tlb_plv)) ||
-        ((tlb_rplv == 1) && (plv != tlb_plv))) {
-        return TLBRET_PE;
-    }
-
-    if ((access_type == MMU_DATA_STORE) && !tlb_d) {
-        return TLBRET_DIRTY;
+    context.vaddr = address;
+    context.ps = tlb_ps;
+    context.pte  = tlb_entry;
+    ret = loongarch_check_pte(env, &context, access_type, mmu_idx);
+    if (ret == TLBRET_MATCH) {
+        *physical = context.physical;
+        *prot = context.prot;
     }
 
-    *physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) |
-                (address & MAKE_64BIT_MASK(0, tlb_ps));
-    *prot = PAGE_READ;
-    if (tlb_d) {
-        *prot |= PAGE_WRITE;
-    }
-    if (!tlb_nx) {
-        *prot |= PAGE_EXEC;
-    }
-    return TLBRET_MATCH;
+    return ret;
 }
 
 int loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical,
-- 
2.39.3
Re: [PATCH v3 05/17] target/loongarch: Add common function loongarch_check_pte()
Posted by Richard Henderson 3 months, 3 weeks ago
On 7/24/25 15:37, Bibo Mao wrote:
> Common function loongarch_check_pte() is to check tlb entry, return
> the physical address and access priviledge. Also it can be used with
> page table entry, which is used in page table walker.
> 
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> ---
>   target/loongarch/cpu-mmu.h        | 10 +++++
>   target/loongarch/cpu_helper.c     | 62 ++++++++++++++++++++++++++++++
>   target/loongarch/tcg/tlb_helper.c | 63 ++++++-------------------------
>   3 files changed, 84 insertions(+), 51 deletions(-)
> 
> diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
> index 4c5cbd7425..62b3acfbc7 100644
> --- a/target/loongarch/cpu-mmu.h
> +++ b/target/loongarch/cpu-mmu.h
> @@ -19,7 +19,17 @@ enum {
>       TLBRET_PE = 7,
>   };
>   
> +typedef struct mmu_context {
> +    target_ulong  vaddr;

Use the 'vaddr' type.

> +    uint64_t      pte;
> +    hwaddr        physical;
> +    int           ps;  /* page size shift */
> +    int           prot;
> +} mmu_context;

QEMU coding style prefers CamelCase.

> +int loongarch_check_pte(CPULoongArchState *env, mmu_context *context,
> +                        int access_type, int mmu_idx)

Use MMUAccessType access_type.
And fix loongarch_map_tlb_entry in a separate patch.
That's the type from loongarch_get_addr_from_tlb and above.


r~
Re: [PATCH v3 05/17] target/loongarch: Add common function loongarch_check_pte()
Posted by Bibo Mao 3 months, 2 weeks ago

On 2025/7/26 上午9:19, Richard Henderson wrote:
> On 7/24/25 15:37, Bibo Mao wrote:
>> Common function loongarch_check_pte() is to check tlb entry, return
>> the physical address and access priviledge. Also it can be used with
>> page table entry, which is used in page table walker.
>>
>> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
>> ---
>>   target/loongarch/cpu-mmu.h        | 10 +++++
>>   target/loongarch/cpu_helper.c     | 62 ++++++++++++++++++++++++++++++
>>   target/loongarch/tcg/tlb_helper.c | 63 ++++++-------------------------
>>   3 files changed, 84 insertions(+), 51 deletions(-)
>>
>> diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
>> index 4c5cbd7425..62b3acfbc7 100644
>> --- a/target/loongarch/cpu-mmu.h
>> +++ b/target/loongarch/cpu-mmu.h
>> @@ -19,7 +19,17 @@ enum {
>>       TLBRET_PE = 7,
>>   };
>> +typedef struct mmu_context {
>> +    target_ulong  vaddr;
> 
> Use the 'vaddr' type.
will do in this way. It is simple and work on 32-bit guest vm on 64-bit 
host also.
> 
>> +    uint64_t      pte;
>> +    hwaddr        physical;
>> +    int           ps;  /* page size shift */
>> +    int           prot;
>> +} mmu_context;
> 
> QEMU coding style prefers CamelCase.
Will do, how about the name MMUContext?
> 
>> +int loongarch_check_pte(CPULoongArchState *env, mmu_context *context,
>> +                        int access_type, int mmu_idx)
> 
> Use MMUAccessType access_type.
> And fix loongarch_map_tlb_entry in a separate patch.
Will do this in a new patch.
> That's the type from loongarch_get_addr_from_tlb and above.

Regards
Bibo Mao
> 
> 
> r~


Re: [PATCH v3 05/17] target/loongarch: Add common function loongarch_check_pte()
Posted by Richard Henderson 3 months, 2 weeks ago
On 7/27/25 17:15, Bibo Mao wrote:
>>> +    uint64_t      pte;
>>> +    hwaddr        physical;
>>> +    int           ps;  /* page size shift */
>>> +    int           prot;
>>> +} mmu_context;
>>
>> QEMU coding style prefers CamelCase.
> Will do, how about the name MMUContext?

That sounds good.


r~