[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 04/17] Openrisc: add MMU support
From: |
Jia Liu |
Subject: |
[Qemu-devel] [PATCH v2 04/17] Openrisc: add MMU support |
Date: |
Sun, 27 May 2012 13:32:46 +0800 |
add openrisc MMU support.
Signed-off-by: Jia Liu <address@hidden>
---
target-openrisc/cpu.h | 82 ++++++++++++++++-
target-openrisc/mmu.c | 199 +++++++++++++++++++++++++++++++++++++++++-
target-openrisc/mmu_helper.c | 20 +++++
3 files changed, 298 insertions(+), 3 deletions(-)
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 24d82f8..779c889 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -55,6 +55,9 @@ struct CPUOpenriscState;
(reg) |= ((v & 0x1f) << 2);\
} while (0)
+/* Internel flags, delay slot flag */
+#define D_FLAG 1
+
/* Verison Register */
#define SPR_VR 0x12000001
#define SPR_CPUCFGR 0x12000001
@@ -92,6 +95,25 @@ enum {
FPCSR_DZF = (1 << 11),
};
+/* Exceptions indices */
+enum {
+ EXCP_RESET = 0x1,
+ EXCP_BUSERR = 0x2,
+ EXCP_DPF = 0x3,
+ EXCP_IPF = 0x4,
+ EXCP_TICK = 0x5,
+ EXCP_ALIGN = 0x6,
+ EXCP_ILLEGAL = 0x7,
+ EXCP_INT = 0x8,
+ EXCP_DTLBMISS = 0x9,
+ EXCP_ITLBMISS = 0xa,
+ EXCP_RANGE = 0xb,
+ EXCP_SYSCALL = 0xc,
+ EXCP_FPE = 0xd,
+ EXCP_TRAP = 0xe,
+ EXCP_NR,
+};
+
/* Supervisor register */
enum {
SR_SM = 1,
@@ -114,6 +136,39 @@ enum {
SR_SCE = (1<<17),
};
+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 tlb_entry {
+ uint32_t mr;
+ uint32_t tr;
+} tlb_entry;
+
typedef struct CPUOpenriscState CPUOpenriscState;
struct CPUOpenriscState {
target_ulong gpr[32]; /* General registers */
@@ -123,9 +178,21 @@ struct CPUOpenriscState {
target_ulong epcr; /* Exception PC register */
target_ulong eear; /* Exception EA register */
uint32_t esr; /* Exception supervisor register */
+#if !defined(CONFIG_USER_ONLY)
+ tlb_entry itlb[ITLB_WAYS][ITLB_SIZE];
+ tlb_entry dtlb[DTLB_WAYS][DTLB_SIZE];
+#endif
CPU_COMMON
+#if !defined(CONFIG_USER_ONLY)
+ 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);
+#endif
uint32_t fpcsr; /* Float register */
target_ulong pc; /* Program counter */
target_ulong npc; /* Next PC */
@@ -187,10 +254,13 @@ 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
@@ -201,6 +271,10 @@ void cpu_openrisc_pic_reset(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)
@@ -220,12 +294,16 @@ static inline void cpu_get_tb_cpu_state(CPUOpenriscState
*env,
{
*pc = env->pc;
*cs_base = 0;
- *flags = 0;
+ /* D_FLAG -- branch insrtuction exception */
+ *flags = (env->flags&D_FLAG);
}
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 4f0312f..2403b77 100644
--- a/target-openrisc/mmu.c
+++ b/target-openrisc/mmu.c
@@ -27,13 +27,210 @@
#endif
#if !defined(CONFIG_USER_ONLY)
+/* no MMU emulation */
+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->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(env->itlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (env->sr & SR_SM) { /* supervisor mode */
+ if (env->itlb[0][idx].tr & SXE) {
+ right |= PAGE_EXEC;
+ }
+ } else {
+ if (env->itlb[0][idx].tr & UXE) {
+ right |= PAGE_EXEC;
+ }
+ }
+
+ if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
+ return TLBRET_BADADDR;
+ }
+
+ *physical = (env->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->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
+ return TLBRET_NOMATCH;
+ }
+ if (!(env->dtlb[0][idx].mr & 1)) {
+ return TLBRET_INVALID;
+ }
+
+ if (env->sr & SR_SM) { /* supervisor mode */
+ if (env->dtlb[0][idx].tr & SRE) {
+ right |= PAGE_READ;
+ }
+ if (env->dtlb[0][idx].tr & SWE) {
+ right |= PAGE_WRITE;
+ }
+ } else {
+ if (env->dtlb[0][idx].tr & URE) {
+ right |= PAGE_READ;
+ }
+ if (env->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->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->map_address_code(env, physical,
+ prot, address, rw);
+ } else { /* DTLB */
+ ret = env->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;
+#if !defined(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;
+}
+
+#if !defined(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
+
+#if !defined(CONFIG_USER_ONLY)
target_phys_addr_t cpu_get_phys_page_debug(CPUOpenriscState *env,
target_ulong addr)
{
- return 0;
+ 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->map_address_code = &get_phys_nommu;
+ env->map_address_data = &get_phys_nommu;
+ memset(env->dtlb, 0, sizeof(tlb_entry)*DTLB_SIZE*DTLB_WAYS);
+ memset(env->itlb, 0, sizeof(tlb_entry)*ITLB_SIZE*ITLB_WAYS);
}
#endif
diff --git a/target-openrisc/mmu_helper.c b/target-openrisc/mmu_helper.c
index 8c658ff..1fbd6a4 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 v2 00/17] Qemu Openrisc support, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 01/17] Openrisc: add target stubs, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 02/17] Openrisc: add cpu QOM implement, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 03/17] Openrisc: add basic machine, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 04/17] Openrisc: add MMU support,
Jia Liu <=
- [Qemu-devel] [PATCH v2 06/17] Openrisc: add exception support, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 07/17] Openrisc: add int instruction helpers, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 08/17] Openrisc: add float instruction helpers, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 09/17] Openrisc: add instruction translation routines, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 10/17] Openrisc: add Programmable Interrupt Controller, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 11/17] Openrisc: add a timer, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 12/17] Openrisc: add a simulator board, Jia Liu, 2012/05/27
- [Qemu-devel] [PATCH v2 13/17] Openrisc: add system instruction helpers, Jia Liu, 2012/05/27