]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/mem_helper.c
target/hppa: report ITLB_EXCP_MISS for ITLB misses
[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"
24#include "qom/cpu.h"
25
26#ifdef CONFIG_USER_ONLY
27int hppa_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
28 int size, int rw, int mmu_idx)
29{
30 HPPACPU *cpu = HPPA_CPU(cs);
31
2986721d
RH
32 /* ??? Test between data page fault and data memory protection trap,
33 which would affect si_code. */
34 cs->exception_index = EXCP_DMP;
35136a77 35 cpu->env.cr[CR_IOR] = address;
813dff13
HD
36 return 1;
37}
38#else
650cdb2a
RH
39static hppa_tlb_entry *hppa_find_tlb(CPUHPPAState *env, vaddr addr)
40{
41 int i;
42
43 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
44 hppa_tlb_entry *ent = &env->tlb[i];
8d6ae7fb 45 if (ent->va_b <= addr && addr <= ent->va_e) {
650cdb2a
RH
46 return ent;
47 }
48 }
49 return NULL;
50}
51
8d6ae7fb
RH
52static void hppa_flush_tlb_ent(CPUHPPAState *env, hppa_tlb_entry *ent)
53{
54 CPUState *cs = CPU(hppa_env_get_cpu(env));
55 unsigned i, n = 1 << (2 * ent->page_size);
56 uint64_t addr = ent->va_b;
57
58 for (i = 0; i < n; ++i, addr += TARGET_PAGE_SIZE) {
59 /* Do not flush MMU_PHYS_IDX. */
60 tlb_flush_page_by_mmuidx(cs, addr, 0xf);
61 }
62
63 memset(ent, 0, sizeof(*ent));
64 ent->va_b = -1;
65}
66
67static hppa_tlb_entry *hppa_alloc_tlb_ent(CPUHPPAState *env)
68{
69 hppa_tlb_entry *ent;
70 uint32_t i = env->tlb_last;
71
72 env->tlb_last = (i == ARRAY_SIZE(env->tlb) - 1 ? 0 : i + 1);
73 ent = &env->tlb[i];
74
75 hppa_flush_tlb_ent(env, ent);
76 return ent;
77}
78
650cdb2a
RH
79int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
80 int type, hwaddr *pphys, int *pprot)
81{
82 hwaddr phys;
83 int prot, r_prot, w_prot, x_prot;
84 hppa_tlb_entry *ent;
85 int ret = -1;
86
87 /* Virtual translation disabled. Direct map virtual to physical. */
88 if (mmu_idx == MMU_PHYS_IDX) {
89 phys = addr;
90 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
91 goto egress;
92 }
93
94 /* Find a valid tlb entry that matches the virtual address. */
95 ent = hppa_find_tlb(env, addr);
8d6ae7fb 96 if (ent == NULL || !ent->entry_valid) {
650cdb2a
RH
97 phys = 0;
98 prot = 0;
acd6ba74 99 ret = (type == PAGE_EXEC) ? EXCP_ITLB_MISS : EXCP_DTLB_MISS;
650cdb2a
RH
100 goto egress;
101 }
102
103 /* We now know the physical address. */
104 phys = ent->pa + (addr & ~TARGET_PAGE_MASK);
105
106 /* Map TLB access_rights field to QEMU protection. */
107 r_prot = (mmu_idx <= ent->ar_pl1) * PAGE_READ;
108 w_prot = (mmu_idx <= ent->ar_pl2) * PAGE_WRITE;
109 x_prot = (ent->ar_pl2 <= mmu_idx && mmu_idx <= ent->ar_pl1) * PAGE_EXEC;
110 switch (ent->ar_type) {
111 case 0: /* read-only: data page */
112 prot = r_prot;
113 break;
114 case 1: /* read/write: dynamic data page */
115 prot = r_prot | w_prot;
116 break;
117 case 2: /* read/execute: normal code page */
118 prot = r_prot | x_prot;
119 break;
120 case 3: /* read/write/execute: dynamic code page */
121 prot = r_prot | w_prot | x_prot;
122 break;
123 default: /* execute: promote to privilege level type & 3 */
124 prot = x_prot;
43e05652 125 break;
650cdb2a
RH
126 }
127
128 /* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */
129
130 /* No guest access type indicates a non-architectural access from
131 within QEMU. Bypass checks for access, D, B and T bits. */
132 if (type == 0) {
133 goto egress;
134 }
135
136 if (unlikely(!(prot & type))) {
137 /* The access isn't allowed -- Inst/Data Memory Protection Fault. */
5f538f75
HD
138 ret = (type & PAGE_EXEC ? EXCP_IMP :
139 prot & PAGE_READ ? EXCP_DMP : EXCP_DMAR);
650cdb2a
RH
140 goto egress;
141 }
142
143 /* In reverse priority order, check for conditions which raise faults.
144 As we go, remove PROT bits that cover the condition we want to check.
145 In this way, the resulting PROT will force a re-check of the
146 architectural TLB entry for the next access. */
147 if (unlikely(!ent->d)) {
148 if (type & PAGE_WRITE) {
149 /* The D bit is not set -- TLB Dirty Bit Fault. */
150 ret = EXCP_TLB_DIRTY;
151 }
152 prot &= PAGE_READ | PAGE_EXEC;
153 }
154 if (unlikely(ent->b)) {
155 if (type & PAGE_WRITE) {
156 /* The B bit is set -- Data Memory Break Fault. */
157 ret = EXCP_DMB;
158 }
159 prot &= PAGE_READ | PAGE_EXEC;
160 }
161 if (unlikely(ent->t)) {
162 if (!(type & PAGE_EXEC)) {
163 /* The T bit is set -- Page Reference Fault. */
164 ret = EXCP_PAGE_REF;
165 }
166 prot &= PAGE_EXEC;
167 }
168
169 egress:
170 *pphys = phys;
171 *pprot = prot;
172 return ret;
173}
174
813dff13
HD
175hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
176{
650cdb2a
RH
177 HPPACPU *cpu = HPPA_CPU(cs);
178 hwaddr phys;
179 int prot, excp;
180
181 /* If the (data) mmu is disabled, bypass translation. */
182 /* ??? We really ought to know if the code mmu is disabled too,
183 in order to get the correct debugging dumps. */
184 if (!(cpu->env.psw & PSW_D)) {
185 return addr;
186 }
187
188 excp = hppa_get_physical_address(&cpu->env, addr, MMU_KERNEL_IDX, 0,
189 &phys, &prot);
190
191 /* Since we're translating for debugging, the only error that is a
192 hard error is no translation at all. Otherwise, while a real cpu
193 access might not have permission, the debugger does. */
194 return excp == EXCP_DTLB_MISS ? -1 : phys;
813dff13
HD
195}
196
650cdb2a
RH
197void tlb_fill(CPUState *cs, target_ulong addr, int size,
198 MMUAccessType type, int mmu_idx, uintptr_t retaddr)
813dff13 199{
650cdb2a
RH
200 HPPACPU *cpu = HPPA_CPU(cs);
201 int prot, excp, a_prot;
202 hwaddr phys;
203
204 switch (type) {
205 case MMU_INST_FETCH:
206 a_prot = PAGE_EXEC;
207 break;
208 case MMU_DATA_STORE:
209 a_prot = PAGE_WRITE;
210 break;
211 default:
212 a_prot = PAGE_READ;
213 break;
214 }
215
216 excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx,
217 a_prot, &phys, &prot);
218 if (unlikely(excp >= 0)) {
219 /* Failure. Raise the indicated exception. */
220 cs->exception_index = excp;
221 if (cpu->env.psw & PSW_Q) {
222 /* ??? Needs tweaking for hppa64. */
223 cpu->env.cr[CR_IOR] = addr;
224 cpu->env.cr[CR_ISR] = addr >> 32;
225 }
226 cpu_loop_exit_restore(cs, retaddr);
227 }
813dff13
HD
228
229 /* Success! Store the translation into the QEMU TLB. */
230 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
231 prot, mmu_idx, TARGET_PAGE_SIZE);
232}
8d6ae7fb
RH
233
234/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
235void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
236{
237 hppa_tlb_entry *empty = NULL;
238 int i;
239
240 /* Zap any old entries covering ADDR; notice empty entries on the way. */
241 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
242 hppa_tlb_entry *ent = &env->tlb[i];
0b49c339
SS
243 if (ent->va_b <= addr && addr <= ent->va_e) {
244 if (ent->entry_valid) {
245 hppa_flush_tlb_ent(env, ent);
246 }
247 if (!empty) {
248 empty = ent;
249 }
8d6ae7fb
RH
250 }
251 }
252
253 /* If we didn't see an empty entry, evict one. */
254 if (empty == NULL) {
255 empty = hppa_alloc_tlb_ent(env);
256 }
257
258 /* Note that empty->entry_valid == 0 already. */
259 empty->va_b = addr & TARGET_PAGE_MASK;
260 empty->va_e = empty->va_b + TARGET_PAGE_SIZE - 1;
261 empty->pa = extract32(reg, 5, 20) << TARGET_PAGE_BITS;
262}
263
264/* Insert (Insn/Data) TLB Protection. Note this is PA 1.1 only. */
265void HELPER(itlbp)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
266{
267 hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
268
269 if (unlikely(ent == NULL || ent->entry_valid)) {
270 qemu_log_mask(LOG_GUEST_ERROR, "ITLBP not following ITLBA\n");
271 return;
272 }
273
274 ent->access_id = extract32(reg, 1, 18);
275 ent->u = extract32(reg, 19, 1);
276 ent->ar_pl2 = extract32(reg, 20, 2);
277 ent->ar_pl1 = extract32(reg, 22, 2);
278 ent->ar_type = extract32(reg, 24, 3);
279 ent->b = extract32(reg, 27, 1);
280 ent->d = extract32(reg, 28, 1);
281 ent->t = extract32(reg, 29, 1);
282 ent->entry_valid = 1;
283}
63300a00
RH
284
285/* Purge (Insn/Data) TLB. This is explicitly page-based, and is
286 synchronous across all processors. */
287static void ptlb_work(CPUState *cpu, run_on_cpu_data data)
288{
289 CPUHPPAState *env = cpu->env_ptr;
290 target_ulong addr = (target_ulong) data.target_ptr;
291 hppa_tlb_entry *ent = hppa_find_tlb(env, addr);
292
293 if (ent && ent->entry_valid) {
294 hppa_flush_tlb_ent(env, ent);
295 }
296}
297
298void HELPER(ptlb)(CPUHPPAState *env, target_ulong addr)
299{
300 CPUState *src = CPU(hppa_env_get_cpu(env));
301 CPUState *cpu;
302 run_on_cpu_data data = RUN_ON_CPU_TARGET_PTR(addr);
303
304 CPU_FOREACH(cpu) {
305 if (cpu != src) {
306 async_run_on_cpu(cpu, ptlb_work, data);
307 }
308 }
309 async_safe_run_on_cpu(src, ptlb_work, data);
310}
311
312/* Purge (Insn/Data) TLB entry. This affects an implementation-defined
313 number of pages/entries (we choose all), and is local to the cpu. */
314void HELPER(ptlbe)(CPUHPPAState *env)
315{
316 CPUState *src = CPU(hppa_env_get_cpu(env));
317
318 memset(env->tlb, 0, sizeof(env->tlb));
319 tlb_flush_by_mmuidx(src, 0xf);
320}
2dfcca9f
RH
321
322target_ureg HELPER(lpa)(CPUHPPAState *env, target_ulong addr)
323{
324 hwaddr phys;
325 int prot, excp;
326
327 excp = hppa_get_physical_address(env, addr, MMU_KERNEL_IDX, 0,
328 &phys, &prot);
329 if (excp >= 0) {
330 if (env->psw & PSW_Q) {
331 /* ??? Needs tweaking for hppa64. */
332 env->cr[CR_IOR] = addr;
333 env->cr[CR_ISR] = addr >> 32;
334 }
335 if (excp == EXCP_DTLB_MISS) {
336 excp = EXCP_NA_DTLB_MISS;
337 }
338 hppa_dynamic_excp(env, excp, GETPC());
339 }
340 return phys;
341}
43e05652
RH
342
343/* Return the ar_type of the TLB at VADDR, or -1. */
344int hppa_artype_for_page(CPUHPPAState *env, target_ulong vaddr)
345{
346 hppa_tlb_entry *ent = hppa_find_tlb(env, vaddr);
347 return ent ? ent->ar_type : -1;
348}
813dff13 349#endif /* CONFIG_USER_ONLY */