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 "qemu-common.h"
24 #include "exec/gdbstub.h"
25 #include "qemu/host-utils.h"
26 #ifndef CONFIG_USER_ONLY
27 #include "hw/loader.h"
30 #ifndef CONFIG_USER_ONLY
31 int cpu_openrisc_get_phys_nommu(OpenRISCCPU *cpu,
33 int *prot, target_ulong address, int rw)
36 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
40 int cpu_openrisc_get_phys_code(OpenRISCCPU *cpu,
42 int *prot, target_ulong address, int rw)
44 int vpn = address >> TARGET_PAGE_BITS;
45 int idx = vpn & ITLB_MASK;
48 if ((cpu->env.tlb->itlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
49 return TLBRET_NOMATCH;
51 if (!(cpu->env.tlb->itlb[0][idx].mr & 1)) {
52 return TLBRET_INVALID;
55 if (cpu->env.sr & SR_SM) { /* supervisor mode */
56 if (cpu->env.tlb->itlb[0][idx].tr & SXE) {
60 if (cpu->env.tlb->itlb[0][idx].tr & UXE) {
65 if ((rw & 2) && ((right & PAGE_EXEC) == 0)) {
66 return TLBRET_BADADDR;
69 *physical = (cpu->env.tlb->itlb[0][idx].tr & TARGET_PAGE_MASK) |
70 (address & (TARGET_PAGE_SIZE-1));
75 int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
77 int *prot, target_ulong address, int rw)
79 int vpn = address >> TARGET_PAGE_BITS;
80 int idx = vpn & DTLB_MASK;
83 if ((cpu->env.tlb->dtlb[0][idx].mr >> TARGET_PAGE_BITS) != vpn) {
84 return TLBRET_NOMATCH;
86 if (!(cpu->env.tlb->dtlb[0][idx].mr & 1)) {
87 return TLBRET_INVALID;
90 if (cpu->env.sr & SR_SM) { /* supervisor mode */
91 if (cpu->env.tlb->dtlb[0][idx].tr & SRE) {
94 if (cpu->env.tlb->dtlb[0][idx].tr & SWE) {
98 if (cpu->env.tlb->dtlb[0][idx].tr & URE) {
101 if (cpu->env.tlb->dtlb[0][idx].tr & UWE) {
106 if (!(rw & 1) && ((right & PAGE_READ) == 0)) {
107 return TLBRET_BADADDR;
109 if ((rw & 1) && ((right & PAGE_WRITE) == 0)) {
110 return TLBRET_BADADDR;
113 *physical = (cpu->env.tlb->dtlb[0][idx].tr & TARGET_PAGE_MASK) |
114 (address & (TARGET_PAGE_SIZE-1));
119 static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
121 int *prot, target_ulong address,
124 int ret = TLBRET_MATCH;
126 if (rw == 2) { /* ITLB */
128 ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
131 ret = cpu->env.tlb->cpu_openrisc_map_address_data(cpu, physical,
139 static void cpu_openrisc_raise_mmu_exception(OpenRISCCPU *cpu,
140 target_ulong address,
141 int rw, int tlb_error)
143 CPUState *cs = CPU(cpu);
149 exception = EXCP_IPF;
151 exception = EXCP_DPF;
154 #ifndef CONFIG_USER_ONLY
157 exception = EXCP_IPF;
159 exception = EXCP_DPF;
164 /* No TLB match for a mapped address */
166 exception = EXCP_ITLBMISS;
168 exception = EXCP_DTLBMISS;
174 cs->exception_index = exception;
175 cpu->env.eear = address;
178 #ifndef CONFIG_USER_ONLY
179 int openrisc_cpu_handle_mmu_fault(CPUState *cs,
180 vaddr address, int rw, int mmu_idx)
182 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
187 ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
190 if (ret == TLBRET_MATCH) {
191 tlb_set_page(cs, address & TARGET_PAGE_MASK,
192 physical & TARGET_PAGE_MASK, prot,
193 mmu_idx, TARGET_PAGE_SIZE);
195 } else if (ret < 0) {
196 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
203 int openrisc_cpu_handle_mmu_fault(CPUState *cs,
204 vaddr address, int rw, int mmu_idx)
206 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
209 cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
216 #ifndef CONFIG_USER_ONLY
217 hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
219 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
223 if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
230 void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
232 cpu->env.tlb = g_malloc0(sizeof(CPUOpenRISCTLBContext));
234 cpu->env.tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
235 cpu->env.tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;