Re: [RFC PATCH v2 09/30] target/loongarch: Add TLB instruction support

2021-11-17 Thread yangxiaojuan



On 11/17/2021 04:22 PM, Richard Henderson wrote:
> On 11/17/21 8:29 AM, yangxiaojuan wrote:
>> On 11/12/2021 02:14 AM, Richard Henderson wrote:
>>> On 11/11/21 2:35 AM, Xiaojuan Yang wrote:
 +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
 +{
 +gen_helper_check_plv(cpu_env);
 +gen_helper_tlbwr(cpu_env);
 +tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
 +ctx->base.is_jmp = DISAS_EXIT;
 +return true;
 +}
>>>
>>> I think you can skip the EXIT if paging is disabled, which it usually will 
>>> be in the software tlb handler.  You'd be able to tell with the mmu_idx 
>>> being the one you use for paging disabled.
>>
>> The paging disabled only enabled at the bios startup, we can get the phys 
>> address directly, tlbwr instruction will not be used when paging enabled.
> 
> Paging is also disabled during TLBRENTRY exception (see section 6.2.4 
> Hardware Exception Handling of TLB Refil Exception).  It is this routine that 
> will usually use tlbwr most often (although the kernel at PRV 0 is not 
> prevented from doing so).

Sorry, I forgot this situation.

> 
 +default:
 +do_raise_exception(env, EXCP_INE, GETPC());
>>>
>>> You can detect this during translation, and dispatch to the appropriate 
>>> invtlb sub-function.
>>>
>> oh, sorry, I don't quiet understand this. detect during the translation sees 
>> more complicated.
> 
> It is not more complex at all.  Less complex, I would say.
> 
> static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
> {
> TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
> TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);
> 
> if (check_plv(ctx)) {
> return false;
> }
> 
> switch (a->invop) {
> case 0:
> case 1:
> gen_helper_invtlb_all(cpu_env);
> break;
> case 2:
> gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1));
> break;
> case 3:
> gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0));
> break;
> case 4:
> gen_helper_invtlb_all_asid(cpu_env, rj);
> break;
> case 5:
> gen_helper_invtlb_page_asid(cpu_env, rj, rk);
> break;
> case 6:
> gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk);
> break;
> default:
> return false;
> }
> ctx->base.is_jmp = DISAS_STOP;
> return true;
> }
> 
Thank you. I get it.
> 
> r~




Re: [RFC PATCH v2 09/30] target/loongarch: Add TLB instruction support

2021-11-17 Thread Richard Henderson

On 11/17/21 8:29 AM, yangxiaojuan wrote:

On 11/12/2021 02:14 AM, Richard Henderson wrote:

On 11/11/21 2:35 AM, Xiaojuan Yang wrote:

+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
+{
+gen_helper_check_plv(cpu_env);
+gen_helper_tlbwr(cpu_env);
+tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ctx->base.is_jmp = DISAS_EXIT;
+return true;
+}


I think you can skip the EXIT if paging is disabled, which it usually will be 
in the software tlb handler.  You'd be able to tell with the mmu_idx being the 
one you use for paging disabled.


The paging disabled only enabled at the bios startup, we can get the phys 
address directly, tlbwr instruction will not be used when paging enabled.


Paging is also disabled during TLBRENTRY exception (see section 6.2.4 Hardware Exception 
Handling of TLB Refil Exception).  It is this routine that will usually use tlbwr most 
often (although the kernel at PRV 0 is not prevented from doing so).



+default:
+do_raise_exception(env, EXCP_INE, GETPC());


You can detect this during translation, and dispatch to the appropriate invtlb 
sub-function.


oh, sorry, I don't quiet understand this. detect during the translation sees 
more complicated.


It is not more complex at all.  Less complex, I would say.

static bool trans_invtlb(DisasContext *ctx, arg_invtlb *a)
{
TCGv rj = gpr_src(ctx, a->rj, EXT_NONE);
TCGv rk = gpr_src(ctx, a->rk, EXT_NONE);

if (check_plv(ctx)) {
return false;
}

switch (a->invop) {
case 0:
case 1:
gen_helper_invtlb_all(cpu_env);
break;
case 2:
gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(1));
break;
case 3:
gen_helper_invtlb_all_g(cpu_env, tcg_constant_i32(0));
break;
case 4:
gen_helper_invtlb_all_asid(cpu_env, rj);
break;
case 5:
gen_helper_invtlb_page_asid(cpu_env, rj, rk);
break;
case 6:
gen_helper_invtlb_page_asid_or_g(cpu_env, rj, rk);
break;
default:
return false;
}
ctx->base.is_jmp = DISAS_STOP;
return true;
}


r~



Re: [RFC PATCH v2 09/30] target/loongarch: Add TLB instruction support

2021-11-16 Thread yangxiaojuan
Hi, Richard:

On 11/12/2021 02:14 AM, Richard Henderson wrote:
> On 11/11/21 2:35 AM, Xiaojuan Yang wrote:
>> +static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
>> +{
>> +gen_helper_check_plv(cpu_env);
>> +gen_helper_tlbwr(cpu_env);
>> +tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
>> +ctx->base.is_jmp = DISAS_EXIT;
>> +return true;
>> +}
> 
> I think you can skip the EXIT if paging is disabled, which it usually will be 
> in the software tlb handler.  You'd be able to tell with the mmu_idx being 
> the one you use for paging disabled.

The paging disabled only enabled at the bios startup, we can get the phys 
address directly, tlbwr instruction will not be used when paging enabled.

> 
>> +static void loongarch_invalidate_tlb_entry(CPULoongArchState *env,
>> +   loongarch_tlb *tlb)
>> +{
>> +CPUState *cs = env_cpu(env);
>> +target_ulong addr, end, mask;
>> +int tlb_v0, tlb_v1;
>> +uint64_t tlb_vppn;
>> +uint8_t tlb_ps;
>> +
>> +tlb_v0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, V);
>> +tlb_v1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, V);
>> +tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
>> +tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
>> +mask = (1 << (1 + tlb_ps)) - 1;
> 
> MAKE_64BIT_MASK.
> 
>> +
>> +if (tlb_v0) {
>> +addr = tlb_vppn & ~mask;/* xxx...xxx[0]000.. */
>> +end = addr | (mask >> 1);   /* xxx...xxx[0]111.. */
>> +while (addr < end) {
>> +tlb_flush_page(cs, addr);
>> +addr += TARGET_PAGE_SIZE;
> 
> tlb_flush_range_by_mmuidx.
> 
>> +tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn);
>> +tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1);
>> +csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
>> +tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid);
>> +
>> +csr_g = FIELD_EX64(env->CSR_TLBELO0, CSR_TLBELO0, G) &
>> + FIELD_EX64(env->CSR_TLBELO1, CSR_TLBELO1, G);
>> +tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, G, csr_g);
>> +
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, V,
>> + FIELD_EX64(lo0, CSR_TLBELO0, V));/* [0] */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, D,
>> + FIELD_EX64(lo0, CSR_TLBELO0, D));/* [1] */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, PLV,
>> + FIELD_EX64(lo0, CSR_TLBELO0, PLV));/* 
>> [3:2] */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, MAT,
>> + FIELD_EX64(lo0, CSR_TLBELO0, MAT));/* 
>> [5:4] */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, PPN,
>> + FIELD_EX64(lo0, CSR_TLBELO0, PPN));/* 
>> [47:12] */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, NR,
>> + FIELD_EX64(lo0, CSR_TLBELO0, NR));/* [61] 
>> */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, NX,
>> + FIELD_EX64(lo0, CSR_TLBELO0, NX));/* [62] 
>> */
>> +tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, RPLV,
>> + FIELD_EX64(lo0, CSR_TLBELO0, RPLV));/* 
>> [63] */
>> +
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, V,
>> + FIELD_EX64(lo1, CSR_TLBELO1, V));/* [0] */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, D,
>> + FIELD_EX64(lo1, CSR_TLBELO1, D));/* [1] */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, PLV,
>> + FIELD_EX64(lo1, CSR_TLBELO1, PLV));/* 
>> [3:2] */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, MAT,
>> + FIELD_EX64(lo1, CSR_TLBELO1, MAT));/* 
>> [5:4] */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, PPN,
>> + FIELD_EX64(lo1, CSR_TLBELO1, PPN));/* 
>> [47:12] */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, NR,
>> + FIELD_EX64(lo1, CSR_TLBELO1, NR));/* [61] 
>> */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, NX,
>> + FIELD_EX64(lo1, CSR_TLBELO1, NX));/* [62] 
>> */
>> +tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, RPLV,
>> + FIELD_EX64(lo1, CSR_TLBELO1, RPLV));/* 
>> [63] */
> 
> The point of making the two values have the same field layout is so that you 
> can just assign the whole value across, not extract and re-deposit each field.

Yes, it is much simpler when use the same field layout.

> 
>> +void helper_tlbsrch(CPULoongArchState *env)
>> +{
>> +loongarch_tlb *tlb;
>> +uint64_t vpn, tlb_vppn;
>> +uint16_t csr_asid, tlb_asid, tlb_ps, tlb_e, tlb_g;
>> +
>> +int stlb_size = 

Re: [RFC PATCH v2 09/30] target/loongarch: Add TLB instruction support

2021-11-11 Thread Richard Henderson

On 11/11/21 2:35 AM, Xiaojuan Yang wrote:

+static bool trans_tlbwr(DisasContext *ctx, arg_tlbwr *a)
+{
+gen_helper_check_plv(cpu_env);
+gen_helper_tlbwr(cpu_env);
+tcg_gen_movi_tl(cpu_pc, ctx->base.pc_next + 4);
+ctx->base.is_jmp = DISAS_EXIT;
+return true;
+}


I think you can skip the EXIT if paging is disabled, which it usually will be in the 
software tlb handler.  You'd be able to tell with the mmu_idx being the one you use for 
paging disabled.



+static void loongarch_invalidate_tlb_entry(CPULoongArchState *env,
+   loongarch_tlb *tlb)
+{
+CPUState *cs = env_cpu(env);
+target_ulong addr, end, mask;
+int tlb_v0, tlb_v1;
+uint64_t tlb_vppn;
+uint8_t tlb_ps;
+
+tlb_v0 = FIELD_EX64(tlb->tlb_entry0, ENTRY0, V);
+tlb_v1 = FIELD_EX64(tlb->tlb_entry1, ENTRY1, V);
+tlb_vppn = FIELD_EX64(tlb->tlb_misc, TLB_MISC, VPPN);
+tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+mask = (1 << (1 + tlb_ps)) - 1;


MAKE_64BIT_MASK.


+
+if (tlb_v0) {
+addr = tlb_vppn & ~mask;/* xxx...xxx[0]000.. */
+end = addr | (mask >> 1);   /* xxx...xxx[0]111.. */
+while (addr < end) {
+tlb_flush_page(cs, addr);
+addr += TARGET_PAGE_SIZE;


tlb_flush_range_by_mmuidx.


+tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, VPPN, csr_vppn);
+tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, E, 1);
+csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, ASID, csr_asid);
+
+csr_g = FIELD_EX64(env->CSR_TLBELO0, CSR_TLBELO0, G) &
+ FIELD_EX64(env->CSR_TLBELO1, CSR_TLBELO1, G);
+tlb->tlb_misc = FIELD_DP64(tlb->tlb_misc, TLB_MISC, G, csr_g);
+
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, V,
+ FIELD_EX64(lo0, CSR_TLBELO0, V));/* [0] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, D,
+ FIELD_EX64(lo0, CSR_TLBELO0, D));/* [1] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, PLV,
+ FIELD_EX64(lo0, CSR_TLBELO0, PLV));/* [3:2] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, MAT,
+ FIELD_EX64(lo0, CSR_TLBELO0, MAT));/* [5:4] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, PPN,
+ FIELD_EX64(lo0, CSR_TLBELO0, PPN));/* [47:12] 
*/
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, NR,
+ FIELD_EX64(lo0, CSR_TLBELO0, NR));/* [61] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, NX,
+ FIELD_EX64(lo0, CSR_TLBELO0, NX));/* [62] */
+tlb->tlb_entry0 = FIELD_DP64(tlb->tlb_entry0, ENTRY0, RPLV,
+ FIELD_EX64(lo0, CSR_TLBELO0, RPLV));/* [63] */
+
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, V,
+ FIELD_EX64(lo1, CSR_TLBELO1, V));/* [0] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, D,
+ FIELD_EX64(lo1, CSR_TLBELO1, D));/* [1] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, PLV,
+ FIELD_EX64(lo1, CSR_TLBELO1, PLV));/* [3:2] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, MAT,
+ FIELD_EX64(lo1, CSR_TLBELO1, MAT));/* [5:4] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, PPN,
+ FIELD_EX64(lo1, CSR_TLBELO1, PPN));/* [47:12] 
*/
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, NR,
+ FIELD_EX64(lo1, CSR_TLBELO1, NR));/* [61] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, NX,
+ FIELD_EX64(lo1, CSR_TLBELO1, NX));/* [62] */
+tlb->tlb_entry1 = FIELD_DP64(tlb->tlb_entry1, ENTRY1, RPLV,
+ FIELD_EX64(lo1, CSR_TLBELO1, RPLV));/* [63] */


The point of making the two values have the same field layout is so that you can just 
assign the whole value across, not extract and re-deposit each field.



+void helper_tlbsrch(CPULoongArchState *env)
+{
+loongarch_tlb *tlb;
+uint64_t vpn, tlb_vppn;
+uint16_t csr_asid, tlb_asid, tlb_ps, tlb_e, tlb_g;
+
+int stlb_size = env->stlb_size;
+int mtlb_size = env->mtlb_size;
+int i;
+csr_asid = FIELD_EX64(env->CSR_ASID, CSR_ASID, ASID);
+
+/* Search MTLB + STLB */
+for (i = 0; i < stlb_size + mtlb_size; ++i) {
+tlb = >tlb[i];
+vpn = FIELD_EX64(env->CSR_TLBEHI, CSR_TLBEHI, VPPN);
+tlb_asid = FIELD_EX64(tlb->tlb_misc, TLB_MISC, ASID);
+tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
+tlb_e = FIELD_EX64(tlb->tlb_misc, TLB_MISC, E);
+tlb_g = FIELD_EX64(tlb->tlb_misc, TLB_MISC, G);
+tlb_vppn =