1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "exec/exec-all.h"
23#include "exec/helper-proto.h"
24#include "hw/core/cpu.h"
25#include "trace.h"
26
27#ifdef CONFIG_USER_ONLY
28bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
29 MMUAccessType access_type, int mmu_idx,
30 bool probe, uintptr_t retaddr)
31{
32 HPPACPU *cpu = HPPA_CPU(cs);
33
34
35
36 cs->exception_index = EXCP_DMP;
37 cpu->env.cr[CR_IOR] = address;
38 cpu_loop_exit_restore(cs, retaddr);
39}
40#else
41static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
42{
43 int i;
44
45 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
46 hppa_tlb_entry *ent = &env->tlb[i];
47 if (ent->va_b <= addr && addr <= ent->va_e) {
48 trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
49 ent->va_b, ent->va_e, ent->pa);
50 return ent;
51 }
52 }
53 trace_hppa_tlb_find_entry_not_found(env, addr);
54 return NULL;
55}
56
57static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent)
58{
59 CPUState *cs = env_cpu(env);
60 unsigned i, n = 1 << (2 * ent->page_size);
61 uint64_t addr = ent->va_b;
62
63 trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa);
64
65 for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
66
67 tlb_flush_page_by_mmuidx(cs, addr, 0xf);
68 }
69
70 memset(ent, 0, sizeof(*ent));
71 ent->va_b = -1;
72}
73
74static hppa_tlb_entry *hppa_alloc_tlb_ent(CPUHPPAState *env)
75{
76 hppa_tlb_entry *ent;
77 uint32_t i = env->tlb_last;
78
79 env->tlb_last = (i == ARRAY_SIZE(env->tlb) - 1 ? 0 : i + 1);
80 ent = &env->tlb[i];
81
82 hppa_flush_tlb_ent(env, ent);
83 return ent;
84}
85
86int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
87 int type, hwaddr *pphys, int *pprot)
88{
89 hwaddr phys;
90 int prot, r_prot, w_prot, x_prot;
91 hppa_tlb_entry *ent;
92 int ret = -1;
93
94
95 if (mmu_idx == MMU_PHYS_IDX) {
96 phys = addr;
97 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
98 goto egress;
99 }
100
101
102 ent = hppa_find_tlb(env, addr);
103 if (ent == NULL || !ent->entry_valid) {
104 phys = 0;
105 prot = 0;
106 ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
107 goto egress;
108 }
109
110
111 phys = ent->pa + (addr & ~TARGET_PAGE_MASK);
112
113
114 r_prot = (mmu_idx <= ent->ar_pl1) * PAGE_READ;
115 w_prot = (mmu_idx <= ent->ar_pl2) * PAGE_WRITE;
116 x_prot = (ent->ar_pl2 <= mmu_idx && mmu_idx <= ent->ar_pl1) * PAGE_EXEC;
117 switch (ent->ar_type) {
118 case 0:
119 prot = r_prot;
120 break;
121 case 1:
122 prot = r_prot | w_prot;
123 break;
124 case 2:
125 prot = r_prot | x_prot;
126 break;
127 case 3:
128 prot = r_prot | w_prot | x_prot;
129 break;
130 default:
131 prot = x_prot;
132 break;
133 }
134
135
136 if ((env->psw & PSW_P) && ent->access_id) {
137
138 int match = ent->access_id * 2 + 1;
139
140 if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] ||
141 match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) {
142 prot &= PAGE_READ | PAGE_EXEC;
143 if (type == PAGE_WRITE) {
144 ret = EXCP_DMPI;
145 goto egress;
146 }
147 }
148 }
149
150
151
152 if (type == 0) {
153 goto egress;
154 }
155
156 if (unlikely(!(prot & type))) {
157
158 ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
159 goto egress;
160 }
161
162
163
164
165
166 if (unlikely(!ent->d)) {
167 if (type & PAGE_WRITE) {
168
169 ret = EXCP_TLB_DIRTY;
170 }
171 prot &= PAGE_READ | PAGE_EXEC;
172 }
173 if (unlikely(ent->b)) {
174 if (type & PAGE_WRITE) {
175
176 ret = EXCP_DMB;
177 }
178 prot &= PAGE_READ | PAGE_EXEC;
179 }
180 if (unlikely(ent->t)) {
181 if (!(type & PAGE_EXEC)) {
182
183 ret = EXCP_PAGE_REF;
184 }
185 prot &= PAGE_EXEC;
186 }
187
188 egress:
189 *pphys = phys;
190 *pprot = prot;
191 trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
192 return ret;
193}
194
195hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
196{
197 HPPACPU *cpu = HPPA_CPU(cs);
198 hwaddr phys;
199 int prot, excp;
200
201
202
203
204 if (!(cpu->env.psw & PSW_D)) {
205 return addr;
206 }
207
208 excp = hppa_get_physical_address(&cpu->env, addr, MMU_KERNEL_IDX, 0,
209 &phys, &prot);
210
211
212
213
214 return excp == EXCP_DTLB_MISS ? -1 : phys;
215}
216
217bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
218 MMUAccessType type, int mmu_idx,
219 bool probe, uintptr_t retaddr)
220{
221 HPPACPU *cpu = HPPA_CPU(cs);
222 CPUHPPAState *env = &cpu->env;
223 int prot, excp, a_prot;
224 hwaddr phys;
225
226 switch (type) {
227 case MMU_INST_FETCH:
228 a_prot = PAGE_EXEC;
229 break;
230 case MMU_DATA_STORE:
231 a_prot = PAGE_WRITE;
232 break;
233 default:
234 a_prot = PAGE_READ;
235 break;
236 }
237
238 excp = hppa_get_physical_address(env, addr, mmu_idx,
239 a_prot, &phys, &prot);
240 if (unlikely(excp >= 0)) {
241 if (probe) {
242 return false;
243 }
244 trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
245
246 cs->exception_index = excp;
247 if (cpu->env.psw & PSW_Q) {
248
249 cpu->env.cr[CR_IOR] = addr;
250 cpu->env.cr[CR_ISR] = addr >> 32;
251 }
252 cpu_loop_exit_restore(cs, retaddr);
253 }
254
255 trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
256 phys & TARGET_PAGE_MASK, size, type, mmu_idx);
257
258 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
259 prot, mmu_idx, TARGET_PAGE_SIZE);
260 return true;
261}
262
263
264void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
265{
266 hppa_tlb_entry *empty = NULL;
267 int i;
268
269
270 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
271 hppa_tlb_entry *ent = &env->tlb[i];
272 if (ent->va_b <= addr && addr <= ent->va_e) {
273 if (ent->entry_valid) {
274 hppa_flush_tlb_ent(env, ent);
275 }
276 if (!empty) {
277 empty = ent;
278 }
279 }
280 }
281
282
283 if (empty == NULL) {
284 empty = hppa_alloc_tlb_ent(env);
285 }
286
287
288 empty->va_b = addr & TARGET_PAGE_MASK;
289 empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
290 empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
291 trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa);
292}
293
294
295void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
296{
297 hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
298
299 if (unlikely(ent == NULL)) {
300 qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
301 return;
302 }
303
304 ent->access_id = extract32(reg, 1, 18);
305 ent->u = extract32(reg, 19, 1);
306 ent->ar_pl2 = extract32(reg, 20, 2);
307 ent->ar_pl1 = extract32(reg, 22, 2);
308 ent->ar_type = extract32(reg, 24, 3);
309 ent->b = extract32(reg, 27, 1);
310 ent->d = extract32(reg, 28, 1);
311 ent->t = extract32(reg, 29, 1);
312 ent->entry_valid = 1;
313 trace_hppa_tlb_itlbp(env, ent, ent->access_id, ent->u, ent->ar_pl2,
314 ent->ar_pl1, ent->ar_type, ent->b, ent->d, ent->t);
315}
316
317
318
319static void ptlb_work(CPUState *cpu, run_on_cpu_data data)
320{
321 CPUHPPAState *env = cpu->env_ptr;
322 target_ulong addr = (target_ulong) data.target_ptr;
323 hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
324
325 if (ent && ent->entry_valid) {
326 hppa_flush_tlb_ent(env, ent);
327 }
328}
329
330void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
331{
332 CPUState *src = env_cpu(env);
333 CPUState *cpu;
334 trace_hppa_tlb_ptlb(env);
335 run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
336
337 CPU_FOREACH(cpu) {
338 if (cpu != src) {
339 async_run_on_cpu(cpu, ptlb_work, data);
340 }
341 }
342 async_safe_run_on_cpu(src, ptlb_work, data);
343}
344
345
346
347void HELPER(ptlbe)(CPUHPPAState *env)
348{
349 trace_hppa_tlb_ptlbe(env);
350 memset(env->tlb, 0, sizeof(env->tlb));
351 tlb_flush_by_mmuidx(env_cpu(env), 0xf);
352}
353
354void cpu_hppa_change_prot_id(CPUHPPAState *env)
355{
356 if (env->psw & PSW_P) {
357 tlb_flush_by_mmuidx(env_cpu(env), 0xf);
358 }
359}
360
361void HELPER(change_prot_id)(CPUHPPAState *env)
362{
363 cpu_hppa_change_prot_id(env);
364}
365
366target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
367{
368 hwaddr phys;
369 int prot, excp;
370
371 excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
372 &phys, &prot);
373 if (excp >= 0) {
374 if (env->psw & PSW_Q) {
375
376 env->cr[CR_IOR] = addr;
377 env->cr[CR_ISR] = addr >> 32;
378 }
379 if (excp == EXCP_DTLB_MISS) {
380 excp = EXCP_NA_DTLB_MISS;
381 }
382 trace_hppa_tlb_lpa_failed(env, addr);
383 hppa_dynamic_excp(env, excp, GETPC());
384 }
385 trace_hppa_tlb_lpa_success(env, addr, phys);
386 return phys;
387}
388
389
390int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
391{
392 hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr);
393 return ent ? ent->ar_type : -1;
394}
395#endif
396