]> git.proxmox.com Git - mirror_qemu.git/blame - target/hppa/mem_helper.c
target/hppa: fix overwriting source reg in addb
[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;
46559e81
RH
99 /* ??? Unconditionally report data tlb miss,
100 even if this is an instruction fetch. */
101 ret = EXCP_DTLB_MISS;
650cdb2a
RH
102 goto egress;
103 }
104
105 /* We now know the physical address. */
106 phys = ent->pa + (addr & ~TARGET_PAGE_MASK);
107
108 /* Map TLB access_rights field to QEMU protection. */
109 r_prot = (mmu_idx <= ent->ar_pl1) * PAGE_READ;
110 w_prot = (mmu_idx <= ent->ar_pl2) * PAGE_WRITE;
111 x_prot = (ent->ar_pl2 <= mmu_idx && mmu_idx <= ent->ar_pl1) * PAGE_EXEC;
112 switch (ent->ar_type) {
113 case 0: /* read-only: data page */
114 prot = r_prot;
115 break;
116 case 1: /* read/write: dynamic data page */
117 prot = r_prot | w_prot;
118 break;
119 case 2: /* read/execute: normal code page */
120 prot = r_prot | x_prot;
121 break;
122 case 3: /* read/write/execute: dynamic code page */
123 prot = r_prot | w_prot | x_prot;
124 break;
125 default: /* execute: promote to privilege level type & 3 */
126 prot = x_prot;
43e05652 127 break;
650cdb2a
RH
128 }
129
130 /* ??? Check PSW_P and ent->access_prot. This can remove PAGE_WRITE. */
131
132 /* No guest access type indicates a non-architectural access from
133 within QEMU. Bypass checks for access, D, B and T bits. */
134 if (type == 0) {
135 goto egress;
136 }
137
138 if (unlikely(!(prot & type))) {
139 /* The access isn't allowed -- Inst/Data Memory Protection Fault. */
5f538f75
HD
140 ret = (type & PAGE_EXEC ? EXCP_IMP :
141 prot & PAGE_READ ? EXCP_DMP : EXCP_DMAR);
650cdb2a
RH
142 goto egress;
143 }
144
145 /* In reverse priority order, check for conditions which raise faults.
146 As we go, remove PROT bits that cover the condition we want to check.
147 In this way, the resulting PROT will force a re-check of the
148 architectural TLB entry for the next access. */
149 if (unlikely(!ent->d)) {
150 if (type & PAGE_WRITE) {
151 /* The D bit is not set -- TLB Dirty Bit Fault. */
152 ret = EXCP_TLB_DIRTY;
153 }
154 prot &= PAGE_READ | PAGE_EXEC;
155 }
156 if (unlikely(ent->b)) {
157 if (type & PAGE_WRITE) {
158 /* The B bit is set -- Data Memory Break Fault. */
159 ret = EXCP_DMB;
160 }
161 prot &= PAGE_READ | PAGE_EXEC;
162 }
163 if (unlikely(ent->t)) {
164 if (!(type & PAGE_EXEC)) {
165 /* The T bit is set -- Page Reference Fault. */
166 ret = EXCP_PAGE_REF;
167 }
168 prot &= PAGE_EXEC;
169 }
170
171 egress:
172 *pphys = phys;
173 *pprot = prot;
174 return ret;
175}
176
813dff13
HD
177hwaddr hppa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
178{
650cdb2a
RH
179 HPPACPU *cpu = HPPA_CPU(cs);
180 hwaddr phys;
181 int prot, excp;
182
183 /* If the (data) mmu is disabled, bypass translation. */
184 /* ??? We really ought to know if the code mmu is disabled too,
185 in order to get the correct debugging dumps. */
186 if (!(cpu->env.psw & PSW_D)) {
187 return addr;
188 }
189
190 excp = hppa_get_physical_address(&cpu->env, addr, MMU_KERNEL_IDX, 0,
191 &phys, &prot);
192
193 /* Since we're translating for debugging, the only error that is a
194 hard error is no translation at all. Otherwise, while a real cpu
195 access might not have permission, the debugger does. */
196 return excp == EXCP_DTLB_MISS ? -1 : phys;
813dff13
HD
197}
198
650cdb2a
RH
199void tlb_fill(CPUState *cs, target_ulong addr, int size,
200 MMUAccessType type, int mmu_idx, uintptr_t retaddr)
813dff13 201{
650cdb2a
RH
202 HPPACPU *cpu = HPPA_CPU(cs);
203 int prot, excp, a_prot;
204 hwaddr phys;
205
206 switch (type) {
207 case MMU_INST_FETCH:
208 a_prot = PAGE_EXEC;
209 break;
210 case MMU_DATA_STORE:
211 a_prot = PAGE_WRITE;
212 break;
213 default:
214 a_prot = PAGE_READ;
215 break;
216 }
217
218 excp = hppa_get_physical_address(&cpu->env, addr, mmu_idx,
219 a_prot, &phys, &prot);
220 if (unlikely(excp >= 0)) {
221 /* Failure. Raise the indicated exception. */
222 cs->exception_index = excp;
223 if (cpu->env.psw & PSW_Q) {
224 /* ??? Needs tweaking for hppa64. */
225 cpu->env.cr[CR_IOR] = addr;
226 cpu->env.cr[CR_ISR] = addr >> 32;
227 }
228 cpu_loop_exit_restore(cs, retaddr);
229 }
813dff13
HD
230
231 /* Success! Store the translation into the QEMU TLB. */
232 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
233 prot, mmu_idx, TARGET_PAGE_SIZE);
234}
8d6ae7fb
RH
235
236/* Insert (Insn/Data) TLB Address. Note this is PA 1.1 only. */
237void HELPER(itlba)(CPUHPPAState *env, target_ulong addr, target_ureg reg)
238{
239 hppa_tlb_entry *empty = NULL;
240 int i;
241
242 /* Zap any old entries covering ADDR; notice empty entries on the way. */
243 for (i = 0; i < ARRAY_SIZE(env->tlb); ++i) {
244 hppa_tlb_entry *ent = &env->tlb[i];
245 if (!ent->entry_valid) {
246 empty = ent;
247 } else if (ent->va_b <= addr && addr <= ent->va_e) {
248 hppa_flush_tlb_ent(env, ent);
249 empty = ent;
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 */