[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v7 03/16] target-or32: Add MMU support
From: |
Jia Liu |
Subject: |
[Qemu-devel] [PATCH v7 03/16] target-or32: Add MMU support |
Date: |
Wed, 27 Jun 2012 17:54:01 +0800 |
Add OpenRISC MMU support.
Signed-off-by: Jia Liu <address@hidden>
---
target-openrisc/cpu.h | 75 +++++++++++++++-
target-openrisc/mmu.c | 199 +++++++++++++++++++++++++++++++++++++++++-
target-openrisc/mmu_helper.c | 20 +++++
3 files changed, 292 insertions(+), 2 deletions(-)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 58c8081..dbb3f17 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -43,6 +43,12 @@ struct CPUOpenRISCState;
#define NB_MMU_MODES 3
+enum {
+ MMU_NOMMU_IDX = 0,
+ MMU_SUPERVISOR_IDX = 1,
+ MMU_USER_IDX = 2,
+};
+
#define TARGET_PAGE_BITS 13
#define TARGET_PHYS_ADDR_SPACE_BITS 32
@@ -206,6 +212,54 @@ enum {
TTMR_M = (3 << 30),
};
+/* TLB size */
+enum {
+ DTLB_WAYS = 1,
+ DTLB_SIZE = 64,
+ DTLB_MASK = (DTLB_SIZE-1),
+ ITLB_WAYS = 1,
+ ITLB_SIZE = 64,
+ ITLB_MASK = (ITLB_SIZE-1),
+};
+
+/* TLB prot */
+enum {
+ URE = (1 << 6),
+ UWE = (1 << 7),
+ SRE = (1 << 8),
+ SWE = (1 << 9),
+
+ SXE = (1 << 6),
+ UXE = (1 << 7),
+};
+
+/* check if tlb available */
+enum {
+ TLBRET_INVALID = -3,
+ TLBRET_NOMATCH = -2,
+ TLBRET_BADADDR = -1,
+ TLBRET_MATCH = 0
+};
+
+typedef struct OpenRISCTLBEntry {
+ uint32_t mr;
+ uint32_t tr;
+} OpenRISCTLBEntry;
+
+#ifndef CONFIG_USER_ONLY
+typedef struct CPUOpenRISCTLBContext {
+ OpenRISCTLBEntry itlb[ITLB_WAYS][ITLB_SIZE];
+ OpenRISCTLBEntry dtlb[DTLB_WAYS][DTLB_SIZE];
+
+ int (*map_address_code)(struct CPUOpenRISCState *env,
+ target_phys_addr_t *physical, int *prot,
+ target_ulong address, int rw);
+ int (*map_address_data)(struct CPUOpenRISCState *env,
+ target_phys_addr_t *physical, int *prot,
+ target_ulong address, int rw);
+} CPUOpenRISCTLBContext;
+#endif
+
typedef struct CPUOpenRISCState CPUOpenRISCState;
struct CPUOpenRISCState {
target_ulong gpr[32]; /* General registers */
@@ -240,6 +294,8 @@ struct CPUOpenRISCState {
CPU_COMMON
#ifndef CONFIG_USER_ONLY
+ CPUOpenRISCTLBContext * tlb;
+
struct QEMUTimer *timer;
uint32_t ttmr; /* Timer tick mode register */
uint32_t ttcr; /* Timer tick count register */
@@ -301,19 +357,33 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model);
int cpu_openrisc_exec(CPUOpenRISCState *s);
void do_interrupt(CPUOpenRISCState *env);
void openrisc_translate_init(void);
+int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env, target_ulong address,
+ int rw, int mmu_idx);
#define cpu_list cpu_openrisc_list
#define cpu_exec cpu_openrisc_exec
#define cpu_gen_code cpu_openrisc_gen_code
+#define cpu_handle_mmu_fault cpu_openrisc_handle_mmu_fault
#define CPU_SAVE_VERSION 1
#ifndef CONFIG_USER_ONLY
void cpu_openrisc_pic_reset(CPUOpenRISCState *env);
+void cpu_openrisc_store_picsr(CPUOpenRISCState *env, uint32_t value);
+void cpu_openrisc_store_picmr(CPUOpenRISCState *env, uint32_t value);
void cpu_openrisc_timer_reset(CPUOpenRISCState *env);
+void cpu_openrisc_store_count(CPUOpenRISCState *env, target_ulong count);
+void cpu_openrisc_store_compare(CPUOpenRISCState *env, target_ulong value);
+uint32_t cpu_openrisc_get_count(CPUOpenRISCState *env);
void openrisc_mmu_init(CPUOpenRISCState *env);
+int get_phys_nommu(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw);
+int get_phys_code(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw);
+int get_phys_data(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw);
#endif
static inline CPUOpenRISCState *cpu_init(const char *cpu_model)
@@ -339,7 +409,10 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState
*env,
static inline int cpu_mmu_index(CPUOpenRISCState *env)
{
- return 0;
+ if (!(env->sr & SR_IME)) {
+ return MMU_NOMMU_IDX;
+ }
+ return (env->sr & SR_SM) == 0 ? MMU_USER_IDX : MMU_SUPERVISOR_IDX;
}
static inline bool cpu_has_work(CPUOpenRISCState *env)
diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c
index cd82b7a..ecef2e1 100644
--- a/target-openrisc/mmu.c
+++ b/target-openrisc/mmu.c
@@ -27,13 +27,210 @@
#endif
#ifndef CONFIG_USER_ONLY
+int get_phys_nommu(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw)
+{
+ *physical = address;
+ *prot = PAGE_READ | PAGE_WRITE;
+ return TLBRET_MATCH;
+}
+
+int get_phys_code(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw)
+{
+ int vpn = address >> TARGET_PAGE_BITS;
+ int idx = vpn & ITLB_MASK;
+ int right = 0;
+
+ if ((env->tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(env->tlb->itlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (env->sr & SR_SM) { /* supervisor mode */
+ if (env->tlb->itlb[0][idx].tr & SXE) {
+ right |= PAGE_EXEC;
+ }
+ } else {
+ if (env->tlb->itlb[0][idx].tr & UXE) {
+ right |= PAGE_EXEC;
+ }
+ }
+
+ if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
+ return TLBRET_BADADDR;
+ }
+
+ *physical = (env->tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
+ (address & (TARGET_PAGE_SIZE-1));
+ *prot = right;
+ return TLBRET_MATCH;
+}
+
+int get_phys_data(CPUOpenRISCState *env, target_phys_addr_t *physical,
+ int *prot, target_ulong address, int rw)
+{
+ int vpn = address >> TARGET_PAGE_BITS;
+ int idx = vpn & DTLB_MASK;
+ int right = 0;
+
+ if ((env->tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(env->tlb->dtlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (env->sr & SR_SM) { /* supervisor mode */
+ if (env->tlb->dtlb[0][idx].tr & SRE) {
+ right |= PAGE_READ;
+ }
+ if (env->tlb->dtlb[0][idx].tr & SWE) {
+ right |= PAGE_WRITE;
+ }
+ } else {
+ if (env->tlb->dtlb[0][idx].tr & URE) {
+ right |= PAGE_READ;
+ }
+ if (env->tlb->dtlb[0][idx].tr & UWE) {
+ right |= PAGE_WRITE;
+ }
+ }
+
+ if ((rw & 0) && ((right & PAGE_READ) == 0)) {
+ return TLBRET_BADADDR;
+ }
+ if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
+ return TLBRET_BADADDR;
+ }
+
+ *physical = (env->tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
+ (address & (TARGET_PAGE_SIZE-1));
+ *prot = right;
+ return TLBRET_MATCH;
+}
+
+static int get_physical_address(CPUOpenRISCState *env,
+ target_phys_addr_t *physical,
+ int *prot, target_ulong address,
+ int rw)
+{
+ int ret = TLBRET_MATCH;
+
+ /* [0x0000--0x2000]: unmapped */
+ if (address < 0x2000 && (env->sr & SR_SM)) {
+ *physical = address;
+ *prot = PAGE_READ | PAGE_WRITE;
+ return ret;
+ }
+
+ if (rw == 2) { /* ITLB */
+ *physical = 0;
+ ret = env->tlb->map_address_code(env, physical,
+ prot, address, rw);
+ } else { /* DTLB */
+ ret = env->tlb->map_address_data(env, physical,
+ prot, address, rw);
+ }
+
+ return ret;
+}
+#endif
+
+static void raise_mmu_exception(CPUOpenRISCState *env, target_ulong address,
+ int rw, int tlb_error)
+{
+ int exception = 0;
+
+ switch (tlb_error) {
+ default:
+ if (rw == 2) {
+ exception = EXCP_IPF;
+ } else {
+ exception = EXCP_DPF;
+ }
+ break;
+#ifndef CONFIG_USER_ONLY
+ case TLBRET_BADADDR:
+ if (rw == 2) {
+ exception = EXCP_IPF;
+ } else {
+ exception = EXCP_DPF;
+ }
+ break;
+ case TLBRET_INVALID:
+ case TLBRET_NOMATCH:
+ /* No TLB match for a mapped address */
+ if (rw == 2) {
+ exception = EXCP_ITLBMISS;
+ } else {
+ exception = EXCP_DTLBMISS;
+ }
+ break;
+#endif
+ }
+
+ env->exception_index = exception;
+ env->eear = address;
+}
+
+#ifndef CONFIG_USER_ONLY
+int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
+ target_ulong address, int rw, int mmu_idx)
+{
+ int ret = 0;
+ target_phys_addr_t physical = 0;
+ int prot = 0;
+
+ ret = get_physical_address(env, &physical, &prot,
+ address, rw);
+
+ if (ret == TLBRET_MATCH) {
+ tlb_set_page(env, address & TARGET_PAGE_MASK,
+ physical & TARGET_PAGE_MASK, prot | PAGE_EXEC,
+ mmu_idx, TARGET_PAGE_SIZE);
+ ret = 0;
+ } else if (ret < 0) {
+ raise_mmu_exception(env, address, rw, ret);
+ ret = 1;
+ }
+
+ return ret;
+}
+#else
+int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
+ target_ulong address, int rw, int mmu_idx)
+{
+ int ret = 0;
+
+ raise_mmu_exception(env, address, rw, ret);
+ ret = 1;
+
+ return ret;
+}
+#endif
+
+#ifndef CONFIG_USER_ONLY
target_phys_addr_t cpu_get_phys_page_debug(CPUOpenRISCState *env,
target_ulong addr)
{
- return addr;
+ target_phys_addr_t phys_addr;
+ int prot;
+
+ if (get_physical_address(env, &phys_addr, &prot, addr, 0)) {
+ return -1;
+ }
+
+ return phys_addr;
}
void openrisc_mmu_init(CPUOpenRISCState *env)
{
+ env->tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
+
+ env->tlb->map_address_code = &get_phys_nommu;
+ env->tlb->map_address_data = &get_phys_nommu;
}
#endif
diff --git a/target-openrisc/mmu_helper.c b/target-openrisc/mmu_helper.c
index f526ba8..29387e3 100644
--- a/target-openrisc/mmu_helper.c
+++ b/target-openrisc/mmu_helper.c
@@ -39,5 +39,25 @@
void tlb_fill(CPUOpenRISCState *env, target_ulong addr, int is_write,
int mmu_idx, uintptr_t retaddr)
{
+ TranslationBlock *tb;
+ unsigned long pc;
+ int ret;
+
+ ret = cpu_openrisc_handle_mmu_fault(env, addr, is_write, mmu_idx);
+
+ if (ret) {
+ if (retaddr) {
+ /* now we have a real cpu fault. */
+ pc = (unsigned long)retaddr;
+ tb = tb_find_pc(pc);
+ if (tb) {
+ /* the PC is inside the translated code. It means that we
+ have a virtual CPU fault. */
+ cpu_restore_state(tb, env, pc);
+ }
+ }
+ /* Raise Exception. */
+ cpu_loop_exit(env);
+ }
}
#endif
--
1.7.9.5
- [Qemu-devel] [PATCH v7 00/16] QEMU OpenRISC support, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 01/16] target-or32: Add target stubs and cpu support, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 02/16] target-or32: Add target machine, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 03/16] target-or32: Add MMU support,
Jia Liu <=
- [Qemu-devel] [PATCH v7 04/16] target-or32: Add interrupt support, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 05/16] target-or32: Add exception support, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 06/16] target-or32: Add int instruction helpers, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 07/16] target-or32: Add float instruction helpers, Jia Liu, 2012/06/27
- [Qemu-devel] [PATCH v7 08/16] target-or32: Add instruction translation, Jia Liu, 2012/06/27
[Qemu-devel] [PATCH v7 11/16] target-or32: Add a IIS dummy board, Jia Liu, 2012/06/27