int *prot, target_ulong address,
MMUAccessType access_type, int mmu_idx)
{
- int user_mode = mmu_idx == MMU_USER_IDX;
- int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
+ int user_mode = mmu_idx == MMU_IDX_USER;
+ int kernel_mode = mmu_idx == MMU_IDX_KERNEL;
uint32_t plv, base_c, base_v;
int64_t addr_high;
uint8_t da = FIELD_EX64(env->CSR_CRMD, CSR_CRMD, DA);
switch (tlb_error) {
default:
case TLBRET_BADADDR:
- cs->exception_index = EXCCODE_ADEM;
+ cs->exception_index = access_type == MMU_INST_FETCH
+ ? EXCCODE_ADEF : EXCCODE_ADEM;
break;
case TLBRET_NOMATCH:
/* No TLB match for a mapped address */
} else {
tlb_ps = FIELD_EX64(env->CSR_STLBPS, CSR_STLBPS, PS);
}
- pagesize = 1 << tlb_ps;
+ pagesize = MAKE_64BIT_MASK(tlb_ps, 1);
mask = MAKE_64BIT_MASK(0, tlb_ps + 1);
if (tlb_v0) {
CPULoongArchState *env = &cpu->env;
hwaddr physical;
int prot;
- int ret = TLBRET_BADADDR;
+ int ret;
/* Data access */
ret = get_physical_address(env, &physical, &prot, address,
raise_mmu_exception(env, address, access_type, ret);
cpu_loop_exit_restore(cs, retaddr);
}
+
+target_ulong helper_lddir(CPULoongArchState *env, target_ulong base,
+ target_ulong level, uint32_t mem_idx)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong badvaddr, index, phys, ret;
+ int shift;
+ uint64_t dir_base, dir_width;
+ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+
+ badvaddr = env->CSR_TLBRBADV;
+ base = base & TARGET_PHYS_MASK;
+
+ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
+ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+ shift = (shift + 1) * 3;
+
+ if (huge) {
+ return base;
+ }
+ switch (level) {
+ case 1:
+ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR1_WIDTH);
+ break;
+ case 2:
+ dir_base = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, DIR2_WIDTH);
+ break;
+ case 3:
+ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR3_WIDTH);
+ break;
+ case 4:
+ dir_base = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_BASE);
+ dir_width = FIELD_EX64(env->CSR_PWCH, CSR_PWCH, DIR4_WIDTH);
+ break;
+ default:
+ do_raise_exception(env, EXCCODE_INE, GETPC());
+ return 0;
+ }
+ index = (badvaddr >> dir_base) & ((1 << dir_width) - 1);
+ phys = base | index << shift;
+ ret = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+ return ret;
+}
+
+void helper_ldpte(CPULoongArchState *env, target_ulong base, target_ulong odd,
+ uint32_t mem_idx)
+{
+ CPUState *cs = env_cpu(env);
+ target_ulong phys, tmp0, ptindex, ptoffset0, ptoffset1, ps, badv;
+ int shift;
+ bool huge = (base >> LOONGARCH_PAGE_HUGE_SHIFT) & 0x1;
+ uint64_t ptbase = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTBASE);
+ uint64_t ptwidth = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTWIDTH);
+
+ base = base & TARGET_PHYS_MASK;
+
+ if (huge) {
+ /* Huge Page. base is paddr */
+ tmp0 = base ^ (1 << LOONGARCH_PAGE_HUGE_SHIFT);
+ /* Move Global bit */
+ tmp0 = ((tmp0 & (1 << LOONGARCH_HGLOBAL_SHIFT)) >>
+ LOONGARCH_HGLOBAL_SHIFT) << R_TLBENTRY_G_SHIFT |
+ (tmp0 & (~(1 << R_TLBENTRY_G_SHIFT)));
+ ps = ptbase + ptwidth - 1;
+ if (odd) {
+ tmp0 += MAKE_64BIT_MASK(ps, 1);
+ }
+ } else {
+ /* 0:64bit, 1:128bit, 2:192bit, 3:256bit */
+ shift = FIELD_EX64(env->CSR_PWCL, CSR_PWCL, PTEWIDTH);
+ shift = (shift + 1) * 3;
+ badv = env->CSR_TLBRBADV;
+
+ ptindex = (badv >> ptbase) & ((1 << ptwidth) - 1);
+ ptindex = ptindex & ~0x1; /* clear bit 0 */
+ ptoffset0 = ptindex << shift;
+ ptoffset1 = (ptindex + 1) << shift;
+
+ phys = base | (odd ? ptoffset1 : ptoffset0);
+ tmp0 = ldq_phys(cs->as, phys) & TARGET_PHYS_MASK;
+ ps = ptbase;
+ }
+
+ if (odd) {
+ env->CSR_TLBRELO1 = tmp0;
+ } else {
+ env->CSR_TLBRELO0 = tmp0;
+ }
+ env->CSR_TLBREHI = FIELD_DP64(env->CSR_TLBREHI, CSR_TLBREHI, PS, ps);
+}