4 * Copyright (c) 2011-2012 Jia Liu <proljc@gmail.com>
5 * Zhizhou Zhang <etouzh@gmail.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "exec/exec-all.h"
24 #include "qemu-common.h"
25 #include "exec/gdbstub.h"
26 #include "qemu/host-utils.h"
27 #ifndef CONFIG_USER_ONLY
28 #include "hw/loader.h"
31 #ifndef CONFIG_USER_ONLY
32 static inline int get_phys_nommu(hwaddr *physical, int *prot,
36 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
40 static int get_phys_code(OpenRISCCPU *cpu, hwaddr *physical, int *prot,
41 target_ulong address, int rw, bool supervisor)
43 int vpn = address >> TARGET_PAGE_BITS;
44 int idx = vpn & TLB_MASK;
46 uint32_t mr = cpu->env.tlb.itlb[idx].mr;
47 uint32_t tr = cpu->env.tlb.itlb[idx].tr;
49 if ((mr >> TARGET_PAGE_BITS) != vpn) {
50 return TLBRET_NOMATCH;
53 return TLBRET_INVALID;
64 if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
65 return TLBRET_BADADDR;
68 *physical = (tr & TARGET_PAGE_MASK) | (address & ~TARGET_PAGE_MASK);
73 static int get_phys_data(OpenRISCCPU *cpu, hwaddr *physical, int *prot,
74 target_ulong address, int rw, bool supervisor)
76 int vpn = address >> TARGET_PAGE_BITS;
77 int idx = vpn & TLB_MASK;
79 uint32_t mr = cpu->env.tlb.dtlb[idx].mr;
80 uint32_t tr = cpu->env.tlb.dtlb[idx].tr;
82 if ((mr >> TARGET_PAGE_BITS) != vpn) {
83 return TLBRET_NOMATCH;
86 return TLBRET_INVALID;
104 if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
105 return TLBRET_BADADDR;
107 if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
108 return TLBRET_BADADDR;
111 *physical = (tr & TARGET_PAGE_MASK) | (address & ~TARGET_PAGE_MASK);
116 static int get_phys_addr(OpenRISCCPU *cpu, hwaddr *physical,
117 int *prot, target_ulong address, int rw)
119 bool supervisor = (cpu->env.sr & SR_SM) != 0;
122 /* Assume nommu results for a moment. */
123 ret = get_phys_nommu(physical, prot, address);
125 /* Overwrite with TLB lookup if enabled. */
126 if (rw == MMU_INST_FETCH) {
127 if (cpu->env.sr & SR_IME) {
128 ret = get_phys_code(cpu, physical, prot, address, rw, supervisor);
131 if (cpu->env.sr & SR_DME) {
132 ret = get_phys_data(cpu, physical, prot, address, rw, supervisor);
140 static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
141 target_ulong address,
142 int rw, int tlb_error)
144 CPUState *cs = CPU(cpu);
150 exception = EXCP_IPF;
152 exception = EXCP_DPF;
155 #ifndef CONFIG_USER_ONLY
158 exception = EXCP_IPF;
160 exception = EXCP_DPF;
165 /* No TLB match for a mapped address */
167 exception = EXCP_ITLBMISS;
169 exception = EXCP_DTLBMISS;
175 cs->exception_index = exception;
176 cpu->env.eear = address;
177 cpu->env.lock_addr = -1;
180 #ifndef CONFIG_USER_ONLY
181 int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
184 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
189 ret = get_phys_addr(cpu, &physical, &prot, address, rw);
191 if (ret == TLBRET_MATCH) {
192 tlb_set_page(cs, address & TARGET_PAGE_MASK,
193 physical & TARGET_PAGE_MASK, prot,
194 mmu_idx, TARGET_PAGE_SIZE);
196 } else if (ret < 0) {
197 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
204 int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
207 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
210 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
217 #ifndef CONFIG_USER_ONLY
218 hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
220 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
225 /* Check memory for any kind of address, since during debug the
226 gdb can ask for anything, check data tlb for address */
227 miss = get_phys_addr(cpu, &phys_addr, &prot, addr, 0);
229 /* Check instruction tlb */
231 miss = get_phys_addr(cpu, &phys_addr, &prot, addr, MMU_INST_FETCH);
234 /* Last, fall back to a plain address */
236 miss = get_phys_nommu(&phys_addr, &prot, addr);
246 void tlb_fill(CPUState *cs, target_ulong addr, int size,
247 MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
249 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
253 if (mmu_idx == MMU_NOMMU_IDX) {
254 ret = get_phys_nommu(&physical, &prot, addr);
256 bool super = mmu_idx == MMU_SUPERVISOR_IDX;
257 if (access_type == MMU_INST_FETCH) {
258 ret = get_phys_code(cpu, &physical, &prot, addr, 2, super);
260 ret = get_phys_data(cpu, &physical, &prot, addr,
261 access_type == MMU_DATA_STORE, super);
265 if (ret == TLBRET_MATCH) {
266 tlb_set_page(cs, addr & TARGET_PAGE_MASK,
267 physical & TARGET_PAGE_MASK, prot,
268 mmu_idx, TARGET_PAGE_SIZE);
269 } else if (ret < 0) {
271 if (access_type == MMU_INST_FETCH) {
273 } else if (access_type == MMU_DATA_STORE) {
278 cpu_openrisc_raise_mmu_exception(cpu, addr, rw, ret);
279 /* Raise Exception. */
280 cpu_loop_exit_restore(cs, retaddr);