aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBibo Mao <maobibo@loongson.cn>2025-07-29 12:03:43 +0800
committerBibo Mao <maobibo@loongson.cn>2025-08-29 10:05:02 +0800
commit7392cb1c7b24e34987b6f2bbff00c39fe0829cc9 (patch)
tree7c7d45ca5d6cc65de5498307664a5e47beeca3d6
parente6c855f44ad63b5e94bc3d27adca12c24ce7953d (diff)
downloadqemu-7392cb1c7b24e34987b6f2bbff00c39fe0829cc9.zip
qemu-7392cb1c7b24e34987b6f2bbff00c39fe0829cc9.tar.gz
qemu-7392cb1c7b24e34987b6f2bbff00c39fe0829cc9.tar.bz2
target/loongarch: Add common function loongarch_check_pte()
Common function loongarch_check_pte() is to check tlb entry, return the physical address and access priviledge if found. Also it can be used with page table entry, which is used in page table walker. Signed-off-by: Bibo Mao <maobibo@loongson.cn> Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--target/loongarch/cpu-mmu.h10
-rw-r--r--target/loongarch/cpu_helper.c61
-rw-r--r--target/loongarch/tcg/tlb_helper.c66
3 files changed, 83 insertions, 54 deletions
diff --git a/target/loongarch/cpu-mmu.h b/target/loongarch/cpu-mmu.h
index dffc128..be3d11d 100644
--- a/target/loongarch/cpu-mmu.h
+++ b/target/loongarch/cpu-mmu.h
@@ -19,7 +19,17 @@ typedef enum TLBRet {
TLBRET_PE,
} TLBRet;
+typedef struct MMUContext {
+ vaddr addr;
+ uint64_t pte;
+ hwaddr physical;
+ int ps; /* page size shift */
+ int prot;
+} MMUContext;
+
bool check_ps(CPULoongArchState *ent, uint8_t ps);
+TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType access_type, int mmu_idx);
TLBRet get_physical_address(CPULoongArchState *env, hwaddr *physical,
int *prot, vaddr address,
MMUAccessType access_type, int mmu_idx,
diff --git a/target/loongarch/cpu_helper.c b/target/loongarch/cpu_helper.c
index 0c037ef..739cdab 100644
--- a/target/loongarch/cpu_helper.c
+++ b/target/loongarch/cpu_helper.c
@@ -44,6 +44,67 @@ void get_dir_base_width(CPULoongArchState *env, uint64_t *dir_base,
}
}
+TLBRet loongarch_check_pte(CPULoongArchState *env, MMUContext *context,
+ MMUAccessType 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;
+ }
+
+ /* 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->physical = (tlb_ppn << R_TLBENTRY_64_PPN_SHIFT) |
+ (context->addr & 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 TLBRet loongarch_page_table_walker(CPULoongArchState *env,
hwaddr *physical,
int *prot, vaddr address)
diff --git a/target/loongarch/tcg/tlb_helper.c b/target/loongarch/tcg/tlb_helper.c
index 915b1aa..10322da 100644
--- a/target/loongarch/tcg/tlb_helper.c
+++ b/target/loongarch/tcg/tlb_helper.c
@@ -654,64 +654,22 @@ static TLBRet loongarch_map_tlb_entry(CPULoongArchState *env, hwaddr *physical,
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;
+ uint8_t tlb_ps, n;
+ MMUContext context;
+ TLBRet ret;
tlb_ps = FIELD_EX64(tlb->tlb_misc, TLB_MISC, PS);
n = (address >> tlb_ps) & 0x1;/* Odd or even */
+ context.pte = n ? tlb->tlb_entry1 : tlb->tlb_entry0;
+ context.addr = address;
+ context.ps = tlb_ps;
+ ret = loongarch_check_pte(env, &context, access_type, mmu_idx);
+ if (ret == TLBRET_MATCH) {
+ *physical = context.physical;
+ *prot = context.prot;
+ }
- 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;
- }
-
- *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;
}
TLBRet loongarch_get_addr_from_tlb(CPULoongArchState *env, hwaddr *physical,