@@ -379,6 +379,7 @@ static struct TCGCPUOps loongarch_tcg_ops = {
.initialize = loongarch_tcg_init,
.synchronize_from_tb = loongarch_cpu_synchronize_from_tb,
.cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
+ .tlb_fill = loongarch_cpu_tlb_fill,
};
#endif /* CONFIG_TCG */
@@ -95,4 +95,13 @@ static inline void compute_hflags(CPULoongArchState *env)
const char *loongarch_exception_name(int32_t exception);
+/* tlb_helper.c */
+bool loongarch_cpu_tlb_fill(CPUState *cs,
+ vaddr address,
+ int size,
+ MMUAccessType access_type,
+ int mmu_idx,
+ bool probe,
+ uintptr_t retaddr);
+
#endif
new file mode 100644
@@ -0,0 +1,109 @@
+/*
+ * LoongArch tlb emulation helpers for qemu.
+ *
+ * Copyright (c) 2021 Loongson Technology Corporation Limited
+ *
+ * SPDX-License-Identifier: LGPL-2.1+
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "internal.h"
+#include "cpu-csr.h"
+#include "exec/helper-proto.h"
+#include "exec/exec-all.h"
+#include "exec/cpu_ldst.h"
+#include "exec/log.h"
+
+enum {
+ TLBRET_PE = -7,
+ TLBRET_XI = -6,
+ TLBRET_RI = -5,
+ TLBRET_DIRTY = -4,
+ TLBRET_INVALID = -3,
+ TLBRET_NOMATCH = -2,
+ TLBRET_BADADDR = -1,
+ TLBRET_MATCH = 0
+};
+
+static void raise_mmu_exception(CPULoongArchState *env, target_ulong address,
+ MMUAccessType access_type, int tlb_error)
+{
+ CPUState *cs = env_cpu(env);
+ int exception = 0, error_code = 0;
+
+ if (access_type == MMU_INST_FETCH) {
+ error_code |= INST_INAVAIL;
+ }
+
+ switch (tlb_error) {
+ default:
+ case TLBRET_BADADDR:
+ exception = EXCP_ADE;
+ break;
+ case TLBRET_NOMATCH:
+ /* No TLB match for a mapped address */
+ if (access_type == MMU_DATA_STORE) {
+ exception = EXCP_TLBS;
+ } else {
+ exception = EXCP_TLBL;
+ }
+ error_code |= TLB_NOMATCH;
+ break;
+ case TLBRET_INVALID:
+ /* TLB match with no valid bit */
+ if (access_type == MMU_DATA_STORE) {
+ exception = EXCP_TLBS;
+ } else {
+ exception = EXCP_TLBL;
+ }
+ break;
+ case TLBRET_DIRTY:
+ exception = EXCP_TLBM;
+ break;
+ case TLBRET_XI:
+ /* Execute-Inhibit Exception */
+ exception = EXCP_TLBXI;
+ break;
+ case TLBRET_RI:
+ /* Read-Inhibit Exception */
+ exception = EXCP_TLBRI;
+ break;
+ case TLBRET_PE:
+ /* Privileged Exception */
+ exception = EXCP_TLBPE;
+ break;
+ }
+
+ if (env->insn_flags & INSN_LOONGARCH) {
+ if (tlb_error == TLBRET_NOMATCH) {
+ env->CSR_TLBRBADV = address;
+ env->CSR_TLBREHI = address & (TARGET_PAGE_MASK << 1);
+ cs->exception_index = exception;
+ env->error_code = error_code;
+ return;
+ }
+ }
+
+ /* Raise exception */
+ env->CSR_BADV = address;
+ cs->exception_index = exception;
+ env->error_code = error_code;
+
+ if (env->insn_flags & INSN_LOONGARCH) {
+ env->CSR_TLBEHI = address & (TARGET_PAGE_MASK << 1);
+ }
+}
+
+bool loongarch_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ LoongArchCPU *cpu = LOONGARCH_CPU(cs);
+ CPULoongArchState *env = &cpu->env;
+ int ret = TLBRET_BADADDR;
+
+ /* data access */
+ raise_mmu_exception(env, address, access_type, ret);
+ do_raise_exception_err(env, cs->exception_index, env->error_code, retaddr);
+}
This patch introduces one memory-management-related functions - loongarch_cpu_tlb_fill() Signed-off-by: Song Gao <gaosong@loongson.cn> --- target/loongarch/cpu.c | 1 + target/loongarch/internal.h | 9 ++++ target/loongarch/tlb_helper.c | 109 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) create mode 100644 target/loongarch/tlb_helper.c