+ base = ldq_phys(cs->as, phys);
+ }
+
+ /* TODO: check plv and other bits? */
+
+ /* base is pte, in normal pte format */
+ if (!FIELD_EX64(base, TLBENTRY, V)) {
+ return TLBRET_NOMATCH;
+ }
+
+ if (!FIELD_EX64(base, TLBENTRY, D)) {
+ *prot = PAGE_READ;
+ } else {
+ *prot = PAGE_READ | PAGE_WRITE;
+ }
+
+ /* get TARGET_PAGE_SIZE aligned physical address */
+ base += (address & TARGET_PHYS_MASK) & ((1 << dir_base) - 1);
+ /* mask RPLV, NX, NR bits */
+ base = FIELD_DP64(base, TLBENTRY_64, RPLV, 0);
+ base = FIELD_DP64(base, TLBENTRY_64, NX, 0);
+ base = FIELD_DP64(base, TLBENTRY_64, NR, 0);
+ /* mask other attribute bits */
+ *physical = base & TARGET_PAGE_MASK;
+
+ return 0;
+}
+
static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
- MMUAccessType access_type, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx,
+ int is_debug)
{
int index, match;
@@ -151,6 +237,13 @@ static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
if (match) {
return loongarch_map_tlb_entry(env, physical, prot,
address, access_type, index, mmu_idx);
+ } else if (is_debug) {
+ /*
+ * For debugger memory access, we want to do the map when there is a
+ * legal mapping, even if the mapping is not yet in TLB. return 0 if
+ * there is a valid map, else none zero.
+ */
+ return loongarch_page_table_walker(env, physical, prot, address);
}
return TLBRET_NOMATCH;
@@ -158,7 +251,8 @@ static int loongarch_map_address(CPULoongArchState *env,
hwaddr *physical,
#else
static int loongarch_map_address(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
- MMUAccessType access_type, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx,
+ int is_debug)
{
return TLBRET_NOMATCH;
}
@@ -178,7 +272,7 @@ static hwaddr dmw_va2pa(CPULoongArchState *env,
target_ulong va,
int get_physical_address(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
- MMUAccessType access_type, int mmu_idx)
+ MMUAccessType access_type, int mmu_idx, int is_debug)
{
int user_mode = mmu_idx == MMU_USER_IDX;
int kernel_mode = mmu_idx == MMU_KERNEL_IDX;
@@ -222,7 +316,7 @@ int get_physical_address(CPULoongArchState *env, hwaddr
*physical,
/* Mapped address */
return loongarch_map_address(env, physical, prot, address,
- access_type, mmu_idx);
+ access_type, mmu_idx, is_debug);
}
hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
@@ -232,7 +326,7 @@ hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cs,
vaddr addr)
int prot;
if (get_physical_address(env, &phys_addr, &prot, addr, MMU_DATA_LOAD,
- cpu_mmu_index(cs, false)) != 0) {
+ cpu_mmu_index(cs, false), 1) != 0) {
return -1;
}
return phys_addr;
diff --git a/target/loongarch/internals.h b/target/loongarch/internals.h
index 1a02427627..bc2ca30746 100644
--- a/target/loongarch/internals.h
+++ b/target/loongarch/internals.h
@@ -56,7 +56,9 @@ bool loongarch_tlb_search(CPULoongArchState *env,
target_ulong vaddr,
int *index);
int get_physical_address(CPULoongArchState *env, hwaddr *physical,
int *prot, target_ulong address,
- MMUAccessType access_type, int mmu_idx);
+ MMUAccessType access_type, int mmu_idx, int is_debug);
+void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
+ uint64_t *dir_width, target_ulong level);
hwaddr loongarch_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
#ifdef CONFIG_TCG
diff --git a/target/loongarch/tcg/tlb_helper.c
b/target/loongarch/tcg/tlb_helper.c
index 97f38fc391..564f336df9 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -18,7 +18,7 @@
#include "exec/log.h"
#include "cpu-csr.h"
-static void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
+void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
uint64_t *dir_width, target_ulong level)
{
switch (level) {
@@ -485,7 +485,7 @@ bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address,
int size,
/* Data access */
ret = get_physical_address(env, &physical, &prot, address,
- access_type, mmu_idx);
+ access_type, mmu_idx, 0);
if (ret == TLBRET_MATCH) {
tlb_set_page(cs, address & TARGET_PAGE_MASK,