diff mbox series

[v3,5/6] target/loongarch: Support LoongArch32 DMW

Message ID 20230807094505.2030603-6-c@jia.je (mailing list archive)
State New, archived
Headers show
Series Add loongarch32 mode for loongarch64-softmmu | expand

Commit Message

Jiajie Chen Aug. 7, 2023, 9:45 a.m. UTC
LA32 uses a different encoding for CSR.DMW and a new direct mapping
mechanism.

Signed-off-by: Jiajie Chen <c@jia.je>
---
 target/loongarch/cpu-csr.h    |  7 +++----
 target/loongarch/tlb_helper.c | 31 ++++++++++++++++++++++++++++---
 2 files changed, 31 insertions(+), 7 deletions(-)

Comments

Richard Henderson Aug. 7, 2023, 3:50 p.m. UTC | #1
On 8/7/23 02:45, Jiajie Chen wrote:
> LA32 uses a different encoding for CSR.DMW and a new direct mapping
> mechanism.
> 
> Signed-off-by: Jiajie Chen <c@jia.je>
> ---
>   target/loongarch/cpu-csr.h    |  7 +++----
>   target/loongarch/tlb_helper.c | 31 ++++++++++++++++++++++++++++---
>   2 files changed, 31 insertions(+), 7 deletions(-)
> 
> diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
> index 48ed2e0632..b93f99a9ef 100644
> --- a/target/loongarch/cpu-csr.h
> +++ b/target/loongarch/cpu-csr.h
> @@ -188,10 +188,9 @@ FIELD(CSR_DMW, PLV1, 1, 1)
>   FIELD(CSR_DMW, PLV2, 2, 1)
>   FIELD(CSR_DMW, PLV3, 3, 1)
>   FIELD(CSR_DMW, MAT, 4, 2)
> -FIELD(CSR_DMW, VSEG, 60, 4)
> -
> -#define dmw_va2pa(va) \
> -    (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS))
> +FIELD(CSR_DMW_32, PSEG, 25, 3)
> +FIELD(CSR_DMW_32, VSEG, 29, 3)
> +FIELD(CSR_DMW_64, VSEG, 60, 4)
>   
>   /* Debug CSRs */
>   #define LOONGARCH_CSR_DBG            0x500 /* debug config */
> diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
> index 690c6ef25f..cf6f5863f9 100644
> --- a/target/loongarch/tlb_helper.c
> +++ b/target/loongarch/tlb_helper.c
> @@ -173,6 +173,18 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
>       return TLBRET_NOMATCH;
>   }
>   
> +static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
> +                        target_ulong dmw)
> +{
> +    if (env->mode == LA64) {
> +        return va & TARGET_PHYS_MASK;
> +    } else {
> +        uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG);
> +        return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \
> +            (pseg << R_CSR_DMW_32_VSEG_SHIFT);
> +    }
> +}
> +
>   static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
>                                   int *prot, target_ulong address,
>                                   MMUAccessType access_type, int mmu_idx)
> @@ -184,6 +196,11 @@ static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
>       uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
>       uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
>   
> +    /* Truncate high 32 bits for LA32 */
> +    if (env->mode == LA32) {
> +        address = (uint32_t)address;
> +    }

You need to do this in the translator, because this also depends on VA32L* and the current 
priv level.

Otherwise the window manipulation looks correct.


r~
Jiajie Chen Aug. 7, 2023, 5:32 p.m. UTC | #2
On 2023/8/7 23:50, Richard Henderson wrote:
> On 8/7/23 02:45, Jiajie Chen wrote:
>> LA32 uses a different encoding for CSR.DMW and a new direct mapping
>> mechanism.
>>
>> Signed-off-by: Jiajie Chen <c@jia.je>
>> ---
>>   target/loongarch/cpu-csr.h    |  7 +++----
>>   target/loongarch/tlb_helper.c | 31 ++++++++++++++++++++++++++++---
>>   2 files changed, 31 insertions(+), 7 deletions(-)
>>
>> diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
>> index 48ed2e0632..b93f99a9ef 100644
>> --- a/target/loongarch/cpu-csr.h
>> +++ b/target/loongarch/cpu-csr.h
>> @@ -188,10 +188,9 @@ FIELD(CSR_DMW, PLV1, 1, 1)
>>   FIELD(CSR_DMW, PLV2, 2, 1)
>>   FIELD(CSR_DMW, PLV3, 3, 1)
>>   FIELD(CSR_DMW, MAT, 4, 2)
>> -FIELD(CSR_DMW, VSEG, 60, 4)
>> -
>> -#define dmw_va2pa(va) \
>> -    (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS))
>> +FIELD(CSR_DMW_32, PSEG, 25, 3)
>> +FIELD(CSR_DMW_32, VSEG, 29, 3)
>> +FIELD(CSR_DMW_64, VSEG, 60, 4)
>>     /* Debug CSRs */
>>   #define LOONGARCH_CSR_DBG            0x500 /* debug config */
>> diff --git a/target/loongarch/tlb_helper.c 
>> b/target/loongarch/tlb_helper.c
>> index 690c6ef25f..cf6f5863f9 100644
>> --- a/target/loongarch/tlb_helper.c
>> +++ b/target/loongarch/tlb_helper.c
>> @@ -173,6 +173,18 @@ static int 
>> loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
>>       return TLBRET_NOMATCH;
>>   }
>>   +static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
>> +                        target_ulong dmw)
>> +{
>> +    if (env->mode == LA64) {
>> +        return va & TARGET_PHYS_MASK;
>> +    } else {
>> +        uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG);
>> +        return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \
>> +            (pseg << R_CSR_DMW_32_VSEG_SHIFT);
>> +    }
>> +}
>> +
>>   static int get_physical_address(CPULoongArchState *env, hwaddr 
>> *physical,
>>                                   int *prot, target_ulong address,
>>                                   MMUAccessType access_type, int 
>> mmu_idx)
>> @@ -184,6 +196,11 @@ static int 
>> get_physical_address(CPULoongArchState *env, hwaddr *physical,
>>       uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
>>       uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
>>   +    /* Truncate high 32 bits for LA32 */
>> +    if (env->mode == LA32) {
>> +        address = (uint32_t)address;
>> +    }
>
> You need to do this in the translator, because this also depends on 
> VA32L* and the current priv level.
Could you please elaborate on this? I am checking LA32 and VA32L* in 
get_physical_address() currently, the current priv level is read from 
mmu_idx(or alternatively, read from env->CSR_CRMD), and I am unsure how 
to do this in the translator.
>
> Otherwise the window manipulation looks correct.
>
>
> r~
Richard Henderson Aug. 7, 2023, 7:34 p.m. UTC | #3
On 8/7/23 10:32, Jiajie Chen wrote:
>>>       uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
>>>       uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
>>>   +    /* Truncate high 32 bits for LA32 */
>>> +    if (env->mode == LA32) {
>>> +        address = (uint32_t)address;
>>> +    }
>>
>> You need to do this in the translator, because this also depends on VA32L* and the 
>> current priv level.
> Could you please elaborate on this? I am checking LA32 and VA32L* in 
> get_physical_address() currently, the current priv level is read from mmu_idx(or 
> alternatively, read from env->CSR_CRMD), and I am unsure how to do this in the translator.

In insn_trans/trans_memory.c.inc, gen_load, we compute the address,


>     TCGv addr = gpr_src(ctx, a->rj, EXT_NONE);
> 
>     if (a->imm) {
>         TCGv temp = tcg_temp_new();
>         tcg_gen_addi_tl(temp, addr, a->imm);
>         addr = temp;
>     }

One would use

     if (ctx->va32) {
         tcg_gen_ext32u_tl(temp, addr);
         addr = temp;
     }

to zero-extend the address.  You would want to create no more than one temporary for the 
entire computation.

You would need to modify all of the places which generate an address for tcg_gen_qemu_*: 
gen_load*, gen_store*, gen_ldptr, gen_stptr.  Also trans_fmemory.c.inc and trans_lsx.c.inc.

I would strongly suggest creating helper functions, so that all of the addition and 
extension is done in one place, and not in lots of places as we do now.

If this sounds like more work than just changing get_physical_address, and it is.  But it 
works better with the softmmu tlb.  If you clear upper bits late, then you get false 
conflicts in the tlb, and extra tlb fills.



r~
diff mbox series

Patch

diff --git a/target/loongarch/cpu-csr.h b/target/loongarch/cpu-csr.h
index 48ed2e0632..b93f99a9ef 100644
--- a/target/loongarch/cpu-csr.h
+++ b/target/loongarch/cpu-csr.h
@@ -188,10 +188,9 @@  FIELD(CSR_DMW, PLV1, 1, 1)
 FIELD(CSR_DMW, PLV2, 2, 1)
 FIELD(CSR_DMW, PLV3, 3, 1)
 FIELD(CSR_DMW, MAT, 4, 2)
-FIELD(CSR_DMW, VSEG, 60, 4)
-
-#define dmw_va2pa(va) \
-    (va & MAKE_64BIT_MASK(0, TARGET_VIRT_ADDR_SPACE_BITS))
+FIELD(CSR_DMW_32, PSEG, 25, 3)
+FIELD(CSR_DMW_32, VSEG, 29, 3)
+FIELD(CSR_DMW_64, VSEG, 60, 4)
 
 /* Debug CSRs */
 #define LOONGARCH_CSR_DBG            0x500 /* debug config */
diff --git a/target/loongarch/tlb_helper.c b/target/loongarch/tlb_helper.c
index 690c6ef25f..cf6f5863f9 100644
--- a/target/loongarch/tlb_helper.c
+++ b/target/loongarch/tlb_helper.c
@@ -173,6 +173,18 @@  static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
     return TLBRET_NOMATCH;
 }
 
+static hwaddr dmw_va2pa(CPULoongArchState *env, target_ulong va,
+                        target_ulong dmw)
+{
+    if (env->mode == LA64) {
+        return va & TARGET_PHYS_MASK;
+    } else {
+        uint32_t pseg = FIELD_EX32(dmw, CSR_DMW_32, PSEG);
+        return (va & MAKE_64BIT_MASK(0, R_CSR_DMW_32_VSEG_SHIFT)) | \
+            (pseg << R_CSR_DMW_32_VSEG_SHIFT);
+    }
+}
+
 static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
                                 int *prot, target_ulong address,
                                 MMUAccessType access_type, int mmu_idx)
@@ -184,6 +196,11 @@  static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
     uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
     uint8_t pg = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, PG);
 
+    /* Truncate high 32 bits for LA32 */
+    if (env->mode == LA32) {
+        address = (uint32_t)address;
+    }
+
     /* Check PG and DA */
     if (da & !pg) {
         *physical = address & TARGET_PHYS_MASK;
@@ -192,12 +209,20 @@  static int get_physical_address(CPULoongArchState *env, hwaddr *physical,
     }
 
     plv = kernel_mode | (user_mode << R_CSR_DMW_PLV3_SHIFT);
-    base_v = address >> R_CSR_DMW_VSEG_SHIFT;
+    if (env->mode == LA64) {
+        base_v = address >> R_CSR_DMW_64_VSEG_SHIFT;
+    } else {
+        base_v = address >> R_CSR_DMW_32_VSEG_SHIFT;
+    }
     /* Check direct map window */
     for (int i = 0; i < 4; i++) {
-        base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW, VSEG);
+        if (env->mode == LA64) {
+            base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_64, VSEG);
+        } else {
+            base_c = FIELD_EX64(env->CSR_DMW[i], CSR_DMW_32, VSEG);
+        }
         if ((plv & env->CSR_DMW[i]) && (base_c == base_v)) {
-            *physical = dmw_va2pa(address);
+            *physical = dmw_va2pa(env, address, env->CSR_DMW[i]);
             *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
             return TLBRET_MATCH;
         }