1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#include "qemu/osdep.h"
22#include "cpu.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"
29#endif
30
31#ifndef CONFIG_USER_ONLY
32static inline void get_phys_nommu(hwaddr *phys_addr, int *prot,
33 target_ulong address)
34{
35 *phys_addr = address;
36 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
37}
38
39static int get_phys_mmu(OpenRISCCPU *cpu, hwaddr *phys_addr, int *prot,
40 target_ulong addr, int need, bool super)
41{
42 int idx = (addr >> TARGET_PAGE_BITS) & TLB_MASK;
43 uint32_t imr = cpu->env.tlb.itlb[idx].mr;
44 uint32_t itr = cpu->env.tlb.itlb[idx].tr;
45 uint32_t dmr = cpu->env.tlb.dtlb[idx].mr;
46 uint32_t dtr = cpu->env.tlb.dtlb[idx].tr;
47 int right, match, valid;
48
49
50
51
52 if (unlikely((itr ^ dtr) & TARGET_PAGE_MASK)) {
53 if (need & PAGE_EXEC) {
54 dmr = dtr = 0;
55 } else {
56 imr = itr = 0;
57 }
58 }
59
60
61 match = (imr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_EXEC;
62 match |= (dmr ^ addr) & TARGET_PAGE_MASK ? 0 : PAGE_READ | PAGE_WRITE;
63
64
65 valid = imr & 1 ? PAGE_EXEC : 0;
66 valid |= dmr & 1 ? PAGE_READ | PAGE_WRITE : 0;
67 valid &= match;
68
69
70 right = itr & (super ? SXE : UXE) ? PAGE_EXEC : 0;
71 right |= dtr & (super ? SRE : URE) ? PAGE_READ : 0;
72 right |= dtr & (super ? SWE : UWE) ? PAGE_WRITE : 0;
73 right &= valid;
74
75
76
77
78
79 *phys_addr = ((itr | dtr) & TARGET_PAGE_MASK) | (addr & ~TARGET_PAGE_MASK);
80 *prot = right;
81
82 qemu_log_mask(CPU_LOG_MMU,
83 "MMU lookup: need %d match %d valid %d right %d -> %s\n",
84 need, match, valid, right, (need & right) ? "OK" : "FAIL");
85
86
87 if (likely(need & right)) {
88 return 0;
89 }
90
91
92 if (need & valid) {
93 return need & PAGE_EXEC ? EXCP_IPF : EXCP_DPF;
94 } else {
95 return need & PAGE_EXEC ? EXCP_ITLBMISS : EXCP_DTLBMISS;
96 }
97}
98#endif
99
100static void raise_mmu_exception(OpenRISCCPU *cpu, target_ulong address,
101 int exception)
102{
103 CPUState *cs = CPU(cpu);
104
105 cs->exception_index = exception;
106 cpu->env.eear = address;
107 cpu->env.lock_addr = -1;
108}
109
110int openrisc_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int size,
111 int rw, int mmu_idx)
112{
113#ifdef CONFIG_USER_ONLY
114 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
115 raise_mmu_exception(cpu, address, EXCP_DPF);
116 return 1;
117#else
118 g_assert_not_reached();
119#endif
120}
121
122#ifndef CONFIG_USER_ONLY
123hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
124{
125 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
126 int prot, excp, sr = cpu->env.sr;
127 hwaddr phys_addr;
128
129 switch (sr & (SR_DME | SR_IME)) {
130 case SR_DME | SR_IME:
131
132 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
133 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
134 (sr & SR_SM) != 0);
135 return excp ? -1 : phys_addr;
136
137 default:
138
139
140
141 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr,
142 PAGE_EXEC | PAGE_READ | PAGE_WRITE,
143 (sr & SR_SM) != 0);
144 if (!excp) {
145 return phys_addr;
146 }
147
148
149 case 0:
150
151 get_phys_nommu(&phys_addr, &prot, addr);
152 return phys_addr;
153 }
154}
155
156void tlb_fill(CPUState *cs, target_ulong addr, int size,
157 MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
158{
159 OpenRISCCPU *cpu = OPENRISC_CPU(cs);
160 int prot, excp;
161 hwaddr phys_addr;
162
163 if (mmu_idx == MMU_NOMMU_IDX) {
164
165 get_phys_nommu(&phys_addr, &prot, addr);
166 excp = 0;
167 } else {
168 bool super = mmu_idx == MMU_SUPERVISOR_IDX;
169 int need = (access_type == MMU_INST_FETCH ? PAGE_EXEC
170 : access_type == MMU_DATA_STORE ? PAGE_WRITE
171 : PAGE_READ);
172 excp = get_phys_mmu(cpu, &phys_addr, &prot, addr, need, super);
173 }
174
175 if (unlikely(excp)) {
176 raise_mmu_exception(cpu, addr, excp);
177 cpu_loop_exit_restore(cs, retaddr);
178 }
179
180 tlb_set_page(cs, addr & TARGET_PAGE_MASK,
181 phys_addr & TARGET_PAGE_MASK, prot,
182 mmu_idx, TARGET_PAGE_SIZE);
183}
184#endif
185