From: Jia Liu <proljc@gmail.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] [PATCH v2 04/17] Openrisc: add MMU support
Date: Sun, 27 May 2012 13:32:46 +0800 [thread overview]
Message-ID: <1338096779-30821-5-git-send-email-proljc@gmail.com> (raw)
In-Reply-To: <1338096779-30821-1-git-send-email-proljc@gmail.com>
add openrisc MMU support.
Signed-off-by: Jia Liu <proljc@gmail.com>
---
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
next prev parent reply other threads:[~2012-05-27 5:34 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-27 5:32 [Qemu-devel] [PATCH v2 00/17] Qemu Openrisc support Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 01/17] Openrisc: add target stubs Jia Liu
2012-05-27 12:44 ` Andreas Färber
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 02/17] Openrisc: add cpu QOM implement Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 03/17] Openrisc: add basic machine Jia Liu
2012-05-27 5:32 ` Jia Liu [this message]
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 05/17] Openrisc: add interrupt support Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 06/17] Openrisc: add exception support Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 07/17] Openrisc: add int instruction helpers Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 08/17] Openrisc: add float " Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 09/17] Openrisc: add instruction translation routines Jia Liu
2012-05-28 11:38 ` Max Filippov
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 10/17] Openrisc: add Programmable Interrupt Controller Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 11/17] Openrisc: add a timer Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 12/17] Openrisc: add a simulator board Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 13/17] Openrisc: add system instruction helpers Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 14/17] Openrisc: add gdb stub support Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 15/17] Openrisc: add linux syscall, signal and termbits Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 16/17] Openrisc: add linux user support Jia Liu
2012-05-27 5:32 ` [Qemu-devel] [PATCH v2 17/17] Openrisc: add testcases Jia Liu
2012-05-27 6:01 ` [Qemu-devel] [PATCH v2 00/17] Qemu Openrisc support Stefan Weil
2012-05-27 6:10 ` Jia Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1338096779-30821-5-git-send-email-proljc@gmail.com \
--to=proljc@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).