]> git.proxmox.com Git - qemu.git/blame - target-ppc/mmu_helper.c
ppc: Avoid a warning with the next patch
[qemu.git] / target-ppc / mmu_helper.c
CommitLineData
ec19c4d1
BS
1/*
2 * PowerPC MMU, TLB, SLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
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#include "cpu.h"
ec19c4d1
BS
20#include "helper.h"
21
22//#define DEBUG_SOFTWARE_TLB
23
24#ifdef DEBUG_SOFTWARE_TLB
25# define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
26#else
27# define LOG_SWTLB(...) do { } while (0)
28#endif
29
30/*****************************************************************************/
31/* SPR accesses */
32
33#if !defined(CONFIG_USER_ONLY)
c6c7cf05 34void helper_store_ibatu(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
35{
36 ppc_store_ibatu(env, nr, val);
37}
38
c6c7cf05 39void helper_store_ibatl(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
40{
41 ppc_store_ibatl(env, nr, val);
42}
43
c6c7cf05 44void helper_store_dbatu(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
45{
46 ppc_store_dbatu(env, nr, val);
47}
48
c6c7cf05 49void helper_store_dbatl(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
50{
51 ppc_store_dbatl(env, nr, val);
52}
53
c6c7cf05 54void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
55{
56 ppc_store_ibatl_601(env, nr, val);
57}
58
c6c7cf05 59void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong val)
ec19c4d1
BS
60{
61 ppc_store_ibatu_601(env, nr, val);
62}
63
64/* Segment registers load and store */
c6c7cf05 65target_ulong helper_load_sr(CPUPPCState *env, target_ulong sr_num)
ec19c4d1
BS
66{
67#if defined(TARGET_PPC64)
68 if (env->mmu_model & POWERPC_MMU_64) {
69 return ppc_load_sr(env, sr_num);
70 }
71#endif
72 return env->sr[sr_num];
73}
74
c6c7cf05 75void helper_store_sr(CPUPPCState *env, target_ulong sr_num, target_ulong val)
ec19c4d1
BS
76{
77 ppc_store_sr(env, sr_num, val);
78}
79
80/* SLB management */
81#if defined(TARGET_PPC64)
c6c7cf05 82void helper_store_slb(CPUPPCState *env, target_ulong rb, target_ulong rs)
ec19c4d1
BS
83{
84 if (ppc_store_slb(env, rb, rs) < 0) {
85 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
86 POWERPC_EXCP_INVAL);
87 }
88}
89
c6c7cf05 90target_ulong helper_load_slb_esid(CPUPPCState *env, target_ulong rb)
ec19c4d1 91{
4cc2cc08 92 target_ulong rt = 0;
ec19c4d1
BS
93
94 if (ppc_load_slb_esid(env, rb, &rt) < 0) {
95 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
96 POWERPC_EXCP_INVAL);
97 }
98 return rt;
99}
100
c6c7cf05 101target_ulong helper_load_slb_vsid(CPUPPCState *env, target_ulong rb)
ec19c4d1 102{
4cc2cc08 103 target_ulong rt = 0;
ec19c4d1
BS
104
105 if (ppc_load_slb_vsid(env, rb, &rt) < 0) {
106 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
107 POWERPC_EXCP_INVAL);
108 }
109 return rt;
110}
111
c6c7cf05 112void helper_slbia(CPUPPCState *env)
ec19c4d1
BS
113{
114 ppc_slb_invalidate_all(env);
115}
116
c6c7cf05 117void helper_slbie(CPUPPCState *env, target_ulong addr)
ec19c4d1
BS
118{
119 ppc_slb_invalidate_one(env, addr);
120}
121
122#endif /* defined(TARGET_PPC64) */
123
124/* TLB management */
c6c7cf05 125void helper_tlbia(CPUPPCState *env)
ec19c4d1
BS
126{
127 ppc_tlb_invalidate_all(env);
128}
129
c6c7cf05 130void helper_tlbie(CPUPPCState *env, target_ulong addr)
ec19c4d1
BS
131{
132 ppc_tlb_invalidate_one(env, addr);
133}
134
135/* Software driven TLBs management */
136/* PowerPC 602/603 software TLB load instructions helpers */
c6c7cf05 137static void do_6xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
ec19c4d1
BS
138{
139 target_ulong RPN, CMP, EPN;
140 int way;
141
142 RPN = env->spr[SPR_RPA];
143 if (is_code) {
144 CMP = env->spr[SPR_ICMP];
145 EPN = env->spr[SPR_IMISS];
146 } else {
147 CMP = env->spr[SPR_DCMP];
148 EPN = env->spr[SPR_DMISS];
149 }
150 way = (env->spr[SPR_SRR1] >> 17) & 1;
151 (void)EPN; /* avoid a compiler warning */
152 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
153 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
154 RPN, way);
155 /* Store this TLB */
156 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
157 way, is_code, CMP, RPN);
158}
159
c6c7cf05 160void helper_6xx_tlbd(CPUPPCState *env, target_ulong EPN)
ec19c4d1 161{
c6c7cf05 162 do_6xx_tlb(env, EPN, 0);
ec19c4d1
BS
163}
164
c6c7cf05 165void helper_6xx_tlbi(CPUPPCState *env, target_ulong EPN)
ec19c4d1 166{
c6c7cf05 167 do_6xx_tlb(env, EPN, 1);
ec19c4d1
BS
168}
169
170/* PowerPC 74xx software TLB load instructions helpers */
c6c7cf05 171static void do_74xx_tlb(CPUPPCState *env, target_ulong new_EPN, int is_code)
ec19c4d1
BS
172{
173 target_ulong RPN, CMP, EPN;
174 int way;
175
176 RPN = env->spr[SPR_PTELO];
177 CMP = env->spr[SPR_PTEHI];
178 EPN = env->spr[SPR_TLBMISS] & ~0x3;
179 way = env->spr[SPR_TLBMISS] & 0x3;
180 (void)EPN; /* avoid a compiler warning */
181 LOG_SWTLB("%s: EPN " TARGET_FMT_lx " " TARGET_FMT_lx " PTE0 " TARGET_FMT_lx
182 " PTE1 " TARGET_FMT_lx " way %d\n", __func__, new_EPN, EPN, CMP,
183 RPN, way);
184 /* Store this TLB */
185 ppc6xx_tlb_store(env, (uint32_t)(new_EPN & TARGET_PAGE_MASK),
186 way, is_code, CMP, RPN);
187}
188
c6c7cf05 189void helper_74xx_tlbd(CPUPPCState *env, target_ulong EPN)
ec19c4d1 190{
c6c7cf05 191 do_74xx_tlb(env, EPN, 0);
ec19c4d1
BS
192}
193
c6c7cf05 194void helper_74xx_tlbi(CPUPPCState *env, target_ulong EPN)
ec19c4d1 195{
c6c7cf05 196 do_74xx_tlb(env, EPN, 1);
ec19c4d1
BS
197}
198
199/*****************************************************************************/
200/* PowerPC 601 specific instructions (POWER bridge) */
201
c6c7cf05 202target_ulong helper_rac(CPUPPCState *env, target_ulong addr)
ec19c4d1
BS
203{
204 mmu_ctx_t ctx;
205 int nb_BATs;
206 target_ulong ret = 0;
207
208 /* We don't have to generate many instances of this instruction,
209 * as rac is supervisor only.
210 */
211 /* XXX: FIX THIS: Pretend we have no BAT */
212 nb_BATs = env->nb_BATs;
213 env->nb_BATs = 0;
214 if (get_physical_address(env, &ctx, addr, 0, ACCESS_INT) == 0) {
215 ret = ctx.raddr;
216 }
217 env->nb_BATs = nb_BATs;
218 return ret;
219}
220
221static inline target_ulong booke_tlb_to_page_size(int size)
222{
223 return 1024 << (2 * size);
224}
225
226static inline int booke_page_size_to_tlb(target_ulong page_size)
227{
228 int size;
229
230 switch (page_size) {
231 case 0x00000400UL:
232 size = 0x0;
233 break;
234 case 0x00001000UL:
235 size = 0x1;
236 break;
237 case 0x00004000UL:
238 size = 0x2;
239 break;
240 case 0x00010000UL:
241 size = 0x3;
242 break;
243 case 0x00040000UL:
244 size = 0x4;
245 break;
246 case 0x00100000UL:
247 size = 0x5;
248 break;
249 case 0x00400000UL:
250 size = 0x6;
251 break;
252 case 0x01000000UL:
253 size = 0x7;
254 break;
255 case 0x04000000UL:
256 size = 0x8;
257 break;
258 case 0x10000000UL:
259 size = 0x9;
260 break;
261 case 0x40000000UL:
262 size = 0xA;
263 break;
264#if defined(TARGET_PPC64)
265 case 0x000100000000ULL:
266 size = 0xB;
267 break;
268 case 0x000400000000ULL:
269 size = 0xC;
270 break;
271 case 0x001000000000ULL:
272 size = 0xD;
273 break;
274 case 0x004000000000ULL:
275 size = 0xE;
276 break;
277 case 0x010000000000ULL:
278 size = 0xF;
279 break;
280#endif
281 default:
282 size = -1;
283 break;
284 }
285
286 return size;
287}
288
289/* Helpers for 4xx TLB management */
290#define PPC4XX_TLB_ENTRY_MASK 0x0000003f /* Mask for 64 TLB entries */
291
292#define PPC4XX_TLBHI_V 0x00000040
293#define PPC4XX_TLBHI_E 0x00000020
294#define PPC4XX_TLBHI_SIZE_MIN 0
295#define PPC4XX_TLBHI_SIZE_MAX 7
296#define PPC4XX_TLBHI_SIZE_DEFAULT 1
297#define PPC4XX_TLBHI_SIZE_SHIFT 7
298#define PPC4XX_TLBHI_SIZE_MASK 0x00000007
299
300#define PPC4XX_TLBLO_EX 0x00000200
301#define PPC4XX_TLBLO_WR 0x00000100
302#define PPC4XX_TLBLO_ATTR_MASK 0x000000FF
303#define PPC4XX_TLBLO_RPN_MASK 0xFFFFFC00
304
c6c7cf05 305target_ulong helper_4xx_tlbre_hi(CPUPPCState *env, target_ulong entry)
ec19c4d1
BS
306{
307 ppcemb_tlb_t *tlb;
308 target_ulong ret;
309 int size;
310
311 entry &= PPC4XX_TLB_ENTRY_MASK;
312 tlb = &env->tlb.tlbe[entry];
313 ret = tlb->EPN;
314 if (tlb->prot & PAGE_VALID) {
315 ret |= PPC4XX_TLBHI_V;
316 }
317 size = booke_page_size_to_tlb(tlb->size);
318 if (size < PPC4XX_TLBHI_SIZE_MIN || size > PPC4XX_TLBHI_SIZE_MAX) {
319 size = PPC4XX_TLBHI_SIZE_DEFAULT;
320 }
321 ret |= size << PPC4XX_TLBHI_SIZE_SHIFT;
322 env->spr[SPR_40x_PID] = tlb->PID;
323 return ret;
324}
325
c6c7cf05 326target_ulong helper_4xx_tlbre_lo(CPUPPCState *env, target_ulong entry)
ec19c4d1
BS
327{
328 ppcemb_tlb_t *tlb;
329 target_ulong ret;
330
331 entry &= PPC4XX_TLB_ENTRY_MASK;
332 tlb = &env->tlb.tlbe[entry];
333 ret = tlb->RPN;
334 if (tlb->prot & PAGE_EXEC) {
335 ret |= PPC4XX_TLBLO_EX;
336 }
337 if (tlb->prot & PAGE_WRITE) {
338 ret |= PPC4XX_TLBLO_WR;
339 }
340 return ret;
341}
342
c6c7cf05
BS
343void helper_4xx_tlbwe_hi(CPUPPCState *env, target_ulong entry,
344 target_ulong val)
ec19c4d1
BS
345{
346 ppcemb_tlb_t *tlb;
347 target_ulong page, end;
348
349 LOG_SWTLB("%s entry %d val " TARGET_FMT_lx "\n", __func__, (int)entry,
350 val);
351 entry &= PPC4XX_TLB_ENTRY_MASK;
352 tlb = &env->tlb.tlbe[entry];
353 /* Invalidate previous TLB (if it's valid) */
354 if (tlb->prot & PAGE_VALID) {
355 end = tlb->EPN + tlb->size;
356 LOG_SWTLB("%s: invalidate old TLB %d start " TARGET_FMT_lx " end "
357 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
358 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
359 tlb_flush_page(env, page);
360 }
361 }
362 tlb->size = booke_tlb_to_page_size((val >> PPC4XX_TLBHI_SIZE_SHIFT)
363 & PPC4XX_TLBHI_SIZE_MASK);
364 /* We cannot handle TLB size < TARGET_PAGE_SIZE.
365 * If this ever occurs, one should use the ppcemb target instead
366 * of the ppc or ppc64 one
367 */
368 if ((val & PPC4XX_TLBHI_V) && tlb->size < TARGET_PAGE_SIZE) {
369 cpu_abort(env, "TLB size " TARGET_FMT_lu " < %u "
370 "are not supported (%d)\n",
371 tlb->size, TARGET_PAGE_SIZE, (int)((val >> 7) & 0x7));
372 }
373 tlb->EPN = val & ~(tlb->size - 1);
374 if (val & PPC4XX_TLBHI_V) {
375 tlb->prot |= PAGE_VALID;
376 if (val & PPC4XX_TLBHI_E) {
377 /* XXX: TO BE FIXED */
378 cpu_abort(env,
379 "Little-endian TLB entries are not supported by now\n");
380 }
381 } else {
382 tlb->prot &= ~PAGE_VALID;
383 }
384 tlb->PID = env->spr[SPR_40x_PID]; /* PID */
385 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
386 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
387 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
388 tlb->prot & PAGE_READ ? 'r' : '-',
389 tlb->prot & PAGE_WRITE ? 'w' : '-',
390 tlb->prot & PAGE_EXEC ? 'x' : '-',
391 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
392 /* Invalidate new TLB (if valid) */
393 if (tlb->prot & PAGE_VALID) {
394 end = tlb->EPN + tlb->size;
395 LOG_SWTLB("%s: invalidate TLB %d start " TARGET_FMT_lx " end "
396 TARGET_FMT_lx "\n", __func__, (int)entry, tlb->EPN, end);
397 for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE) {
398 tlb_flush_page(env, page);
399 }
400 }
401}
402
c6c7cf05
BS
403void helper_4xx_tlbwe_lo(CPUPPCState *env, target_ulong entry,
404 target_ulong val)
ec19c4d1
BS
405{
406 ppcemb_tlb_t *tlb;
407
408 LOG_SWTLB("%s entry %i val " TARGET_FMT_lx "\n", __func__, (int)entry,
409 val);
410 entry &= PPC4XX_TLB_ENTRY_MASK;
411 tlb = &env->tlb.tlbe[entry];
412 tlb->attr = val & PPC4XX_TLBLO_ATTR_MASK;
413 tlb->RPN = val & PPC4XX_TLBLO_RPN_MASK;
414 tlb->prot = PAGE_READ;
415 if (val & PPC4XX_TLBLO_EX) {
416 tlb->prot |= PAGE_EXEC;
417 }
418 if (val & PPC4XX_TLBLO_WR) {
419 tlb->prot |= PAGE_WRITE;
420 }
421 LOG_SWTLB("%s: set up TLB %d RPN " TARGET_FMT_plx " EPN " TARGET_FMT_lx
422 " size " TARGET_FMT_lx " prot %c%c%c%c PID %d\n", __func__,
423 (int)entry, tlb->RPN, tlb->EPN, tlb->size,
424 tlb->prot & PAGE_READ ? 'r' : '-',
425 tlb->prot & PAGE_WRITE ? 'w' : '-',
426 tlb->prot & PAGE_EXEC ? 'x' : '-',
427 tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
428}
429
c6c7cf05 430target_ulong helper_4xx_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
431{
432 return ppcemb_tlb_search(env, address, env->spr[SPR_40x_PID]);
433}
434
435/* PowerPC 440 TLB management */
c6c7cf05
BS
436void helper_440_tlbwe(CPUPPCState *env, uint32_t word, target_ulong entry,
437 target_ulong value)
ec19c4d1
BS
438{
439 ppcemb_tlb_t *tlb;
440 target_ulong EPN, RPN, size;
441 int do_flush_tlbs;
442
443 LOG_SWTLB("%s word %d entry %d value " TARGET_FMT_lx "\n",
444 __func__, word, (int)entry, value);
445 do_flush_tlbs = 0;
446 entry &= 0x3F;
447 tlb = &env->tlb.tlbe[entry];
448 switch (word) {
449 default:
450 /* Just here to please gcc */
451 case 0:
452 EPN = value & 0xFFFFFC00;
453 if ((tlb->prot & PAGE_VALID) && EPN != tlb->EPN) {
454 do_flush_tlbs = 1;
455 }
456 tlb->EPN = EPN;
457 size = booke_tlb_to_page_size((value >> 4) & 0xF);
458 if ((tlb->prot & PAGE_VALID) && tlb->size < size) {
459 do_flush_tlbs = 1;
460 }
461 tlb->size = size;
462 tlb->attr &= ~0x1;
463 tlb->attr |= (value >> 8) & 1;
464 if (value & 0x200) {
465 tlb->prot |= PAGE_VALID;
466 } else {
467 if (tlb->prot & PAGE_VALID) {
468 tlb->prot &= ~PAGE_VALID;
469 do_flush_tlbs = 1;
470 }
471 }
472 tlb->PID = env->spr[SPR_440_MMUCR] & 0x000000FF;
473 if (do_flush_tlbs) {
474 tlb_flush(env, 1);
475 }
476 break;
477 case 1:
478 RPN = value & 0xFFFFFC0F;
479 if ((tlb->prot & PAGE_VALID) && tlb->RPN != RPN) {
480 tlb_flush(env, 1);
481 }
482 tlb->RPN = RPN;
483 break;
484 case 2:
485 tlb->attr = (tlb->attr & 0x1) | (value & 0x0000FF00);
486 tlb->prot = tlb->prot & PAGE_VALID;
487 if (value & 0x1) {
488 tlb->prot |= PAGE_READ << 4;
489 }
490 if (value & 0x2) {
491 tlb->prot |= PAGE_WRITE << 4;
492 }
493 if (value & 0x4) {
494 tlb->prot |= PAGE_EXEC << 4;
495 }
496 if (value & 0x8) {
497 tlb->prot |= PAGE_READ;
498 }
499 if (value & 0x10) {
500 tlb->prot |= PAGE_WRITE;
501 }
502 if (value & 0x20) {
503 tlb->prot |= PAGE_EXEC;
504 }
505 break;
506 }
507}
508
c6c7cf05
BS
509target_ulong helper_440_tlbre(CPUPPCState *env, uint32_t word,
510 target_ulong entry)
ec19c4d1
BS
511{
512 ppcemb_tlb_t *tlb;
513 target_ulong ret;
514 int size;
515
516 entry &= 0x3F;
517 tlb = &env->tlb.tlbe[entry];
518 switch (word) {
519 default:
520 /* Just here to please gcc */
521 case 0:
522 ret = tlb->EPN;
523 size = booke_page_size_to_tlb(tlb->size);
524 if (size < 0 || size > 0xF) {
525 size = 1;
526 }
527 ret |= size << 4;
528 if (tlb->attr & 0x1) {
529 ret |= 0x100;
530 }
531 if (tlb->prot & PAGE_VALID) {
532 ret |= 0x200;
533 }
534 env->spr[SPR_440_MMUCR] &= ~0x000000FF;
535 env->spr[SPR_440_MMUCR] |= tlb->PID;
536 break;
537 case 1:
538 ret = tlb->RPN;
539 break;
540 case 2:
541 ret = tlb->attr & ~0x1;
542 if (tlb->prot & (PAGE_READ << 4)) {
543 ret |= 0x1;
544 }
545 if (tlb->prot & (PAGE_WRITE << 4)) {
546 ret |= 0x2;
547 }
548 if (tlb->prot & (PAGE_EXEC << 4)) {
549 ret |= 0x4;
550 }
551 if (tlb->prot & PAGE_READ) {
552 ret |= 0x8;
553 }
554 if (tlb->prot & PAGE_WRITE) {
555 ret |= 0x10;
556 }
557 if (tlb->prot & PAGE_EXEC) {
558 ret |= 0x20;
559 }
560 break;
561 }
562 return ret;
563}
564
c6c7cf05 565target_ulong helper_440_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
566{
567 return ppcemb_tlb_search(env, address, env->spr[SPR_440_MMUCR] & 0xFF);
568}
569
570/* PowerPC BookE 2.06 TLB management */
571
572static ppcmas_tlb_t *booke206_cur_tlb(CPUPPCState *env)
573{
574 uint32_t tlbncfg = 0;
575 int esel = (env->spr[SPR_BOOKE_MAS0] & MAS0_ESEL_MASK) >> MAS0_ESEL_SHIFT;
576 int ea = (env->spr[SPR_BOOKE_MAS2] & MAS2_EPN_MASK);
577 int tlb;
578
579 tlb = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
580 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlb];
581
582 if ((tlbncfg & TLBnCFG_HES) && (env->spr[SPR_BOOKE_MAS0] & MAS0_HES)) {
583 cpu_abort(env, "we don't support HES yet\n");
584 }
585
586 return booke206_get_tlbm(env, tlb, ea, esel);
587}
588
c6c7cf05 589void helper_booke_setpid(CPUPPCState *env, uint32_t pidn, target_ulong pid)
ec19c4d1
BS
590{
591 env->spr[pidn] = pid;
592 /* changing PIDs mean we're in a different address space now */
593 tlb_flush(env, 1);
594}
595
c6c7cf05 596void helper_booke206_tlbwe(CPUPPCState *env)
ec19c4d1
BS
597{
598 uint32_t tlbncfg, tlbn;
599 ppcmas_tlb_t *tlb;
600 uint32_t size_tlb, size_ps;
601
602 switch (env->spr[SPR_BOOKE_MAS0] & MAS0_WQ_MASK) {
603 case MAS0_WQ_ALWAYS:
604 /* good to go, write that entry */
605 break;
606 case MAS0_WQ_COND:
607 /* XXX check if reserved */
608 if (0) {
609 return;
610 }
611 break;
612 case MAS0_WQ_CLR_RSRV:
613 /* XXX clear entry */
614 return;
615 default:
616 /* no idea what to do */
617 return;
618 }
619
620 if (((env->spr[SPR_BOOKE_MAS0] & MAS0_ATSEL) == MAS0_ATSEL_LRAT) &&
621 !msr_gs) {
622 /* XXX we don't support direct LRAT setting yet */
623 fprintf(stderr, "cpu: don't support LRAT setting yet\n");
624 return;
625 }
626
627 tlbn = (env->spr[SPR_BOOKE_MAS0] & MAS0_TLBSEL_MASK) >> MAS0_TLBSEL_SHIFT;
628 tlbncfg = env->spr[SPR_BOOKE_TLB0CFG + tlbn];
629
630 tlb = booke206_cur_tlb(env);
631
632 if (!tlb) {
633 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
634 POWERPC_EXCP_INVAL |
635 POWERPC_EXCP_INVAL_INVAL);
636 }
637
638 /* check that we support the targeted size */
639 size_tlb = (env->spr[SPR_BOOKE_MAS1] & MAS1_TSIZE_MASK) >> MAS1_TSIZE_SHIFT;
640 size_ps = booke206_tlbnps(env, tlbn);
641 if ((env->spr[SPR_BOOKE_MAS1] & MAS1_VALID) && (tlbncfg & TLBnCFG_AVAIL) &&
642 !(size_ps & (1 << size_tlb))) {
643 helper_raise_exception_err(env, POWERPC_EXCP_PROGRAM,
644 POWERPC_EXCP_INVAL |
645 POWERPC_EXCP_INVAL_INVAL);
646 }
647
648 if (msr_gs) {
649 cpu_abort(env, "missing HV implementation\n");
650 }
651 tlb->mas7_3 = ((uint64_t)env->spr[SPR_BOOKE_MAS7] << 32) |
652 env->spr[SPR_BOOKE_MAS3];
653 tlb->mas1 = env->spr[SPR_BOOKE_MAS1];
654
655 /* MAV 1.0 only */
656 if (!(tlbncfg & TLBnCFG_AVAIL)) {
657 /* force !AVAIL TLB entries to correct page size */
658 tlb->mas1 &= ~MAS1_TSIZE_MASK;
659 /* XXX can be configured in MMUCSR0 */
660 tlb->mas1 |= (tlbncfg & TLBnCFG_MINSIZE) >> 12;
661 }
662
663 /* XXX needs to change when supporting 64-bit e500 */
664 tlb->mas2 = env->spr[SPR_BOOKE_MAS2] & 0xffffffff;
665
666 if (!(tlbncfg & TLBnCFG_IPROT)) {
667 /* no IPROT supported by TLB */
668 tlb->mas1 &= ~MAS1_IPROT;
669 }
670
671 if (booke206_tlb_to_page_size(env, tlb) == TARGET_PAGE_SIZE) {
672 tlb_flush_page(env, tlb->mas2 & MAS2_EPN_MASK);
673 } else {
674 tlb_flush(env, 1);
675 }
676}
677
678static inline void booke206_tlb_to_mas(CPUPPCState *env, ppcmas_tlb_t *tlb)
679{
680 int tlbn = booke206_tlbm_to_tlbn(env, tlb);
681 int way = booke206_tlbm_to_way(env, tlb);
682
683 env->spr[SPR_BOOKE_MAS0] = tlbn << MAS0_TLBSEL_SHIFT;
684 env->spr[SPR_BOOKE_MAS0] |= way << MAS0_ESEL_SHIFT;
685 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
686
687 env->spr[SPR_BOOKE_MAS1] = tlb->mas1;
688 env->spr[SPR_BOOKE_MAS2] = tlb->mas2;
689 env->spr[SPR_BOOKE_MAS3] = tlb->mas7_3;
690 env->spr[SPR_BOOKE_MAS7] = tlb->mas7_3 >> 32;
691}
692
c6c7cf05 693void helper_booke206_tlbre(CPUPPCState *env)
ec19c4d1
BS
694{
695 ppcmas_tlb_t *tlb = NULL;
696
697 tlb = booke206_cur_tlb(env);
698 if (!tlb) {
699 env->spr[SPR_BOOKE_MAS1] = 0;
700 } else {
701 booke206_tlb_to_mas(env, tlb);
702 }
703}
704
c6c7cf05 705void helper_booke206_tlbsx(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
706{
707 ppcmas_tlb_t *tlb = NULL;
708 int i, j;
709 target_phys_addr_t raddr;
710 uint32_t spid, sas;
711
712 spid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID_MASK) >> MAS6_SPID_SHIFT;
713 sas = env->spr[SPR_BOOKE_MAS6] & MAS6_SAS;
714
715 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
716 int ways = booke206_tlb_ways(env, i);
717
718 for (j = 0; j < ways; j++) {
719 tlb = booke206_get_tlbm(env, i, address, j);
720
721 if (!tlb) {
722 continue;
723 }
724
725 if (ppcmas_tlb_check(env, tlb, &raddr, address, spid)) {
726 continue;
727 }
728
729 if (sas != ((tlb->mas1 & MAS1_TS) >> MAS1_TS_SHIFT)) {
730 continue;
731 }
732
733 booke206_tlb_to_mas(env, tlb);
734 return;
735 }
736 }
737
738 /* no entry found, fill with defaults */
739 env->spr[SPR_BOOKE_MAS0] = env->spr[SPR_BOOKE_MAS4] & MAS4_TLBSELD_MASK;
740 env->spr[SPR_BOOKE_MAS1] = env->spr[SPR_BOOKE_MAS4] & MAS4_TSIZED_MASK;
741 env->spr[SPR_BOOKE_MAS2] = env->spr[SPR_BOOKE_MAS4] & MAS4_WIMGED_MASK;
742 env->spr[SPR_BOOKE_MAS3] = 0;
743 env->spr[SPR_BOOKE_MAS7] = 0;
744
745 if (env->spr[SPR_BOOKE_MAS6] & MAS6_SAS) {
746 env->spr[SPR_BOOKE_MAS1] |= MAS1_TS;
747 }
748
749 env->spr[SPR_BOOKE_MAS1] |= (env->spr[SPR_BOOKE_MAS6] >> 16)
750 << MAS1_TID_SHIFT;
751
752 /* next victim logic */
753 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_ESEL_SHIFT;
754 env->last_way++;
755 env->last_way &= booke206_tlb_ways(env, 0) - 1;
756 env->spr[SPR_BOOKE_MAS0] |= env->last_way << MAS0_NV_SHIFT;
757}
758
759static inline void booke206_invalidate_ea_tlb(CPUPPCState *env, int tlbn,
760 uint32_t ea)
761{
762 int i;
763 int ways = booke206_tlb_ways(env, tlbn);
764 target_ulong mask;
765
766 for (i = 0; i < ways; i++) {
767 ppcmas_tlb_t *tlb = booke206_get_tlbm(env, tlbn, ea, i);
768 if (!tlb) {
769 continue;
770 }
771 mask = ~(booke206_tlb_to_page_size(env, tlb) - 1);
772 if (((tlb->mas2 & MAS2_EPN_MASK) == (ea & mask)) &&
773 !(tlb->mas1 & MAS1_IPROT)) {
774 tlb->mas1 &= ~MAS1_VALID;
775 }
776 }
777}
778
c6c7cf05 779void helper_booke206_tlbivax(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
780{
781 if (address & 0x4) {
782 /* flush all entries */
783 if (address & 0x8) {
784 /* flush all of TLB1 */
785 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB1, 1);
786 } else {
787 /* flush all of TLB0 */
788 booke206_flush_tlb(env, BOOKE206_FLUSH_TLB0, 0);
789 }
790 return;
791 }
792
793 if (address & 0x8) {
794 /* flush TLB1 entries */
795 booke206_invalidate_ea_tlb(env, 1, address);
796 tlb_flush(env, 1);
797 } else {
798 /* flush TLB0 entries */
799 booke206_invalidate_ea_tlb(env, 0, address);
800 tlb_flush_page(env, address & MAS2_EPN_MASK);
801 }
802}
803
c6c7cf05 804void helper_booke206_tlbilx0(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
805{
806 /* XXX missing LPID handling */
807 booke206_flush_tlb(env, -1, 1);
808}
809
c6c7cf05 810void helper_booke206_tlbilx1(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
811{
812 int i, j;
813 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
814 ppcmas_tlb_t *tlb = env->tlb.tlbm;
815 int tlb_size;
816
817 /* XXX missing LPID handling */
818 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
819 tlb_size = booke206_tlb_size(env, i);
820 for (j = 0; j < tlb_size; j++) {
821 if (!(tlb[j].mas1 & MAS1_IPROT) &&
822 ((tlb[j].mas1 & MAS1_TID_MASK) == tid)) {
823 tlb[j].mas1 &= ~MAS1_VALID;
824 }
825 }
826 tlb += booke206_tlb_size(env, i);
827 }
828 tlb_flush(env, 1);
829}
830
c6c7cf05 831void helper_booke206_tlbilx3(CPUPPCState *env, target_ulong address)
ec19c4d1
BS
832{
833 int i, j;
834 ppcmas_tlb_t *tlb;
835 int tid = (env->spr[SPR_BOOKE_MAS6] & MAS6_SPID);
836 int pid = tid >> MAS6_SPID_SHIFT;
837 int sgs = env->spr[SPR_BOOKE_MAS5] & MAS5_SGS;
838 int ind = (env->spr[SPR_BOOKE_MAS6] & MAS6_SIND) ? MAS1_IND : 0;
839 /* XXX check for unsupported isize and raise an invalid opcode then */
840 int size = env->spr[SPR_BOOKE_MAS6] & MAS6_ISIZE_MASK;
841 /* XXX implement MAV2 handling */
842 bool mav2 = false;
843
844 /* XXX missing LPID handling */
845 /* flush by pid and ea */
846 for (i = 0; i < BOOKE206_MAX_TLBN; i++) {
847 int ways = booke206_tlb_ways(env, i);
848
849 for (j = 0; j < ways; j++) {
850 tlb = booke206_get_tlbm(env, i, address, j);
851 if (!tlb) {
852 continue;
853 }
854 if ((ppcmas_tlb_check(env, tlb, NULL, address, pid) != 0) ||
855 (tlb->mas1 & MAS1_IPROT) ||
856 ((tlb->mas1 & MAS1_IND) != ind) ||
857 ((tlb->mas8 & MAS8_TGS) != sgs)) {
858 continue;
859 }
860 if (mav2 && ((tlb->mas1 & MAS1_TSIZE_MASK) != size)) {
861 /* XXX only check when MMUCFG[TWC] || TLBnCFG[HES] */
862 continue;
863 }
864 /* XXX e500mc doesn't match SAS, but other cores might */
865 tlb->mas1 &= ~MAS1_VALID;
866 }
867 }
868 tlb_flush(env, 1);
869}
870
c6c7cf05 871void helper_booke206_tlbflush(CPUPPCState *env, uint32_t type)
ec19c4d1
BS
872{
873 int flags = 0;
874
875 if (type & 2) {
876 flags |= BOOKE206_FLUSH_TLB1;
877 }
878
879 if (type & 4) {
880 flags |= BOOKE206_FLUSH_TLB0;
881 }
882
883 booke206_flush_tlb(env, flags, 1);
884}
885#endif