]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/mem_helper.c
Merge remote-tracking branch 'remotes/kraxel/tags/usb-20190822-pull-request' into...
[mirror_qemu.git] / target / hppa / mem_helper.c
CommitLineData
813dff13
HD
1/*
2 * HPPA memory access helper routines
3 *
4 * Copyright (c) 2017 Helge Deller
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "qemu/osdep.h"
21#include "cpu.h"
22#include "exec/exec-all.h"
23#include "exec/helper-proto.h"
2e5b09fd 24#include "hw/core/cpu.h"
23c3d569 25#include "trace.h"
813dff13
HD
26
27#ifdef CONFIG_USER_ONLY
3c7bef03
RH
28bool hppa_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
29 MMUAccessType access_type, int mmu_idx,
30 bool probe, uintptr_t retaddr)
813dff13
HD
31{
32 HPPACPU *cpu = HPPA_CPU(cs);
33
2986721d
RH
34 /* ??? Test between data page fault and data memory protection trap,
35 which would affect si_code. */
36 cs->exception_index = EXCP_DMP;
35136a77 37 cpu->env.cr[CR_IOR] = address;
3c7bef03 38 cpu_loop_exit_restore(cs, retaddr);
813dff13
HD
39}
40#else
650cdb2a
RH
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];
8d6ae7fb 47 if (ent->va_b <= addr && addr <= ent->va_e) {
23c3d569
SS
48 trace_hppa_tlb_find_entry(env, ent + i, ent->entry_valid,
49 ent->va_b, ent->va_e, ent->pa);
650cdb2a
RH
50 return ent;
51 }
52 }
23c3d569 53 trace_hppa_tlb_find_entry_not_found(env, addr);
650cdb2a
RH
54 return NULL;
55}
56
8d6ae7fb
RH
57static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent)
58{
25f32708 59 CPUState *cs = env_cpu(env);
8d6ae7fb
RH
60 unsigned i, n = 1 << (2 * ent->page_size);
61 uint64_t addr = ent->va_b;
62
23c3d569
SS
63 trace_hppa_tlb_flush_ent(env, ent, ent->va_b, ent->va_e, ent->pa);
64
8d6ae7fb
RH
65 for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
66 /* Do not flush MMU_PHYS_IDX. */
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
650cdb2a
RH
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 /* Virtual translation disabled. Direct map virtual to physical. */
95 if (mmu_idx == MMU_PHYS_IDX) {
96 phys = addr;
97 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
98 goto egress;
99 }
100
101 /* Find a valid tlb entry that matches the virtual address. */
102 ent = hppa_find_tlb(env, addr);
8d6ae7fb 103 if (ent == NULL || !ent->entry_valid) {
650cdb2a
RH
104 phys = 0;
105 prot = 0;
acd6ba74 106 ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
650cdb2a
RH
107 goto egress;
108 }
109
110 /* We now know the physical address. */
111 phys = ent->pa + (addr & ~TARGET_PAGE_MASK);
112
113 /* Map TLB access_rights field to QEMU protection. */
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: /* read-only: data page */
119 prot = r_prot;
120 break;
121 case 1: /* read/write: dynamic data page */
122 prot = r_prot | w_prot;
123 break;
124 case 2: /* read/execute: normal code page */
125 prot = r_prot | x_prot;
126 break;
127 case 3: /* read/write/execute: dynamic code page */
128 prot = r_prot | w_prot | x_prot;
129 break;
130 default: /* execute: promote to privilege level type & 3 */
131 prot = x_prot;
43e05652 132 break;
650cdb2a
RH
133 }
134
d5de20bd
SS
135 /* access_id == 0 means public page and no check is performed */
136 if ((env->psw & PSW_P) && ent->access_id) {
137 /* If bits [31:1] match, and bit 0 is set, suppress write. */
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 }
650cdb2a
RH
149
150 /* No guest access type indicates a non-architectural access from
151 within QEMU. Bypass checks for access, D, B and T bits. */
152 if (type == 0) {
153 goto egress;
154 }
155
156 if (unlikely(!(prot & type))) {
157 /* The access isn't allowed -- Inst/Data Memory Protection Fault. */
affdb7e6 158 ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
650cdb2a
RH
159 goto egress;
160 }
161
162 /* In reverse priority order, check for conditions which raise faults.
163 As we go, remove PROT bits that cover the condition we want to check.
164 In this way, the resulting PROT will force a re-check of the
165 architectural TLB entry for the next access. */
166 if (unlikely(!ent->d)) {
167 if (type & PAGE_WRITE) {
168 /* The D bit is not set -- TLB Dirty Bit Fault. */
169 ret = EXCP_TLB_DIRTY;
170 }
171 prot &= PAGE_READ | PAGE_EXEC;
172 }
173 if (unlikely(ent->b)) {
174 if (type & PAGE_WRITE) {
175 /* The B bit is set -- Data Memory Break Fault. */
176 ret = EXCP_DMB;
177 }
178 prot &= PAGE_READ | PAGE_EXEC;
179 }
180 if (unlikely(ent->t)) {
181 if (!(type & PAGE_EXEC)) {
182 /* The T bit is set -- Page Reference Fault. */
183 ret = EXCP_PAGE_REF;
184 }
185 prot &= PAGE_EXEC;
186 }
187
188 egress:
189 *pphys = phys;
190 *pprot = prot;
23c3d569 191 trace_hppa_tlb_get_physical_address(env, ret, prot, addr, phys);
650cdb2a
RH
192 return ret;
193}
194
813dff13
HD
195hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
196{
650cdb2a
RH
197 HPPACPU *cpu = HPPA_CPU(cs);
198 hwaddr phys;
199 int prot, excp;
200
201 /* If the (data) mmu is disabled, bypass translation. */
202 /* ??? We really ought to know if the code mmu is disabled too,
203 in order to get the correct debugging dumps. */
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 /* Since we're translating for debugging, the only error that is a
212 hard error is no translation at all. Otherwise, while a real cpu
213 access might not have permission, the debugger does. */
214 return excp == EXCP_DTLB_MISS ? -1 : phys;
813dff13
HD
215}
216
3c7bef03
RH
217bool hppa_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
218 MMUAccessType type, int mmu_idx,
219 bool probe, uintptr_t retaddr)
813dff13 220{
650cdb2a 221 HPPACPU *cpu = HPPA_CPU(cs);
23c3d569 222 CPUHPPAState *env = &cpu->env;
650cdb2a
RH
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
23c3d569 238 excp = hppa_get_physical_address(env, addr, mmu_idx,
650cdb2a
RH
239 a_prot, &phys, &prot);
240 if (unlikely(excp >= 0)) {
3c7bef03
RH
241 if (probe) {
242 return false;
243 }
23c3d569 244 trace_hppa_tlb_fill_excp(env, addr, size, type, mmu_idx);
650cdb2a
RH
245 /* Failure. Raise the indicated exception. */
246 cs->exception_index = excp;
247 if (cpu->env.psw & PSW_Q) {
248 /* ??? Needs tweaking for hppa64. */
249 cpu->env.cr[CR_IOR] = addr;
250 cpu->env.cr[CR_ISR] = addr >> 32;
251 }
252 cpu_loop_exit_restore(cs, retaddr);
253 }
813dff13 254
23c3d569
SS
255 trace_hppa_tlb_fill_success(env, addr & TARGET_PAGE_MASK,
256 phys & TARGET_PAGE_MASK, size, type, mmu_idx);
813dff13
HD
257 /* Success! Store the translation into the QEMU TLB. */
258 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
259 prot, mmu_idx, TARGET_PAGE_SIZE);
3c7bef03
RH
260 return true;
261}
262
8d6ae7fb
RH
263/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
264void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
265{
266 hppa_tlb_entry *empty = NULL;
267 int i;
268
269 /* Zap any old entries covering ADDR; notice empty entries on the way. */
270 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
271 hppa_tlb_entry *ent = &env->tlb[i];
0b49c339
SS
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 }
8d6ae7fb
RH
279 }
280 }
281
282 /* If we didn't see an empty entry, evict one. */
283 if (empty == NULL) {
284 empty = hppa_alloc_tlb_ent(env);
285 }
286
287 /* Note that empty->entry_valid == 0 already. */
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;
23c3d569 291 trace_hppa_tlb_itlba(env, empty, empty->va_b, empty->va_e, empty->pa);
8d6ae7fb
RH
292}
293
294/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
295void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
296{
297 hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
298
38188fd2 299 if (unlikely(ent == NULL)) {
8d6ae7fb
RH
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;
23c3d569
SS
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);
8d6ae7fb 315}
63300a00
RH
316
317/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
318 synchronous across all processors. */
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{
25f32708 332 CPUState *src = env_cpu(env);
63300a00 333 CPUState *cpu;
23c3d569 334 trace_hppa_tlb_ptlb(env);
63300a00
RH
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/* Purge (Insn/Data) TLB entry. This affects an implementation-defined
346 number of pages/entries (we choose all), and is local to the cpu. */
347void HELPER(ptlbe)(CPUHPPAState *env)
348{
23c3d569 349 trace_hppa_tlb_ptlbe(env);
63300a00 350 memset(env->tlb, 0, sizeof(env->tlb));
25f32708 351 tlb_flush_by_mmuidx(env_cpu(env), 0xf);
63300a00 352}
2dfcca9f 353
d5de20bd
SS
354void cpu_hppa_change_prot_id(CPUHPPAState *env)
355{
356 if (env->psw & PSW_P) {
25f32708 357 tlb_flush_by_mmuidx(env_cpu(env), 0xf);
d5de20bd
SS
358 }
359}
360
361void HELPER(change_prot_id)(CPUHPPAState *env)
362{
363 cpu_hppa_change_prot_id(env);
364}
365
2dfcca9f
RH
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 /* ??? Needs tweaking for hppa64. */
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 }
23c3d569 382 trace_hppa_tlb_lpa_failed(env, addr);
2dfcca9f
RH
383 hppa_dynamic_excp(env, excp, GETPC());
384 }
23c3d569 385 trace_hppa_tlb_lpa_success(env, addr, phys);
2dfcca9f
RH
386 return phys;
387}
43e05652
RH
388
389/* Return the ar_type of the TLB at VADDR, or -1. */
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}
813dff13 395#endif /* CONFIG_USER_ONLY */