CPU boot mode
[qemu] / target-sparc / helper.c
1 /*
2  *  sparc helpers
3  *
4  *  Copyright (c) 2003-2005 Fabrice Bellard
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, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdarg.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <inttypes.h>
25 #include <signal.h>
26 #include <assert.h>
27
28 #include "cpu.h"
29 #include "exec-all.h"
30
31 //#define DEBUG_MMU
32
33 /* Sparc MMU emulation */
34
35 /* thread support */
36
37 spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED;
38
39 void cpu_lock(void)
40 {
41     spin_lock(&global_cpu_lock);
42 }
43
44 void cpu_unlock(void)
45 {
46     spin_unlock(&global_cpu_lock);
47 }
48
49 #if defined(CONFIG_USER_ONLY)
50
51 int cpu_sparc_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
52                                int is_user, int is_softmmu)
53 {
54     if (rw & 2)
55         env->exception_index = TT_TFAULT;
56     else
57         env->exception_index = TT_DFAULT;
58     return 1;
59 }
60
61 #else
62
63 #ifndef TARGET_SPARC64
64 /*
65  * Sparc V8 Reference MMU (SRMMU)
66  */
67 static const int access_table[8][8] = {
68     { 0, 0, 0, 0, 2, 0, 3, 3 },
69     { 0, 0, 0, 0, 2, 0, 0, 0 },
70     { 2, 2, 0, 0, 0, 2, 3, 3 },
71     { 2, 2, 0, 0, 0, 2, 0, 0 },
72     { 2, 0, 2, 0, 2, 2, 3, 3 },
73     { 2, 0, 2, 0, 2, 0, 2, 0 },
74     { 2, 2, 2, 0, 2, 2, 3, 3 },
75     { 2, 2, 2, 0, 2, 2, 2, 0 }
76 };
77
78 static const int perm_table[2][8] = {
79     {
80         PAGE_READ,
81         PAGE_READ | PAGE_WRITE,
82         PAGE_READ | PAGE_EXEC,
83         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
84         PAGE_EXEC,
85         PAGE_READ | PAGE_WRITE,
86         PAGE_READ | PAGE_EXEC,
87         PAGE_READ | PAGE_WRITE | PAGE_EXEC
88     },
89     {
90         PAGE_READ,
91         PAGE_READ | PAGE_WRITE,
92         PAGE_READ | PAGE_EXEC,
93         PAGE_READ | PAGE_WRITE | PAGE_EXEC,
94         PAGE_EXEC,
95         PAGE_READ,
96         0,
97         0,
98     }
99 };
100
101 int get_physical_address (CPUState *env, target_phys_addr_t *physical, int *prot,
102                           int *access_index, target_ulong address, int rw,
103                           int is_user)
104 {
105     int access_perms = 0;
106     target_phys_addr_t pde_ptr;
107     uint32_t pde;
108     target_ulong virt_addr;
109     int error_code = 0, is_dirty;
110     unsigned long page_offset;
111
112     virt_addr = address & TARGET_PAGE_MASK;
113
114     if ((env->mmuregs[0] & MMU_E) == 0) { /* MMU disabled */
115         // Boot mode: instruction fetches are taken from PROM
116         if (rw == 2 && (env->mmuregs[0] & MMU_BM)) {
117             *physical = 0xff0000000ULL | (address & 0x3ffffULL);
118             *prot = PAGE_READ | PAGE_EXEC;
119             return 0;
120         }
121         *physical = address;
122         *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
123         return 0;
124     }
125
126     *access_index = ((rw & 1) << 2) | (rw & 2) | (is_user? 0 : 1);
127     *physical = 0xffffffffffff0000ULL;
128
129     /* SPARC reference MMU table walk: Context table->L1->L2->PTE */
130     /* Context base + context number */
131     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
132     pde = ldl_phys(pde_ptr);
133
134     /* Ctx pde */
135     switch (pde & PTE_ENTRYTYPE_MASK) {
136     default:
137     case 0: /* Invalid */
138         return 1 << 2;
139     case 2: /* L0 PTE, maybe should not happen? */
140     case 3: /* Reserved */
141         return 4 << 2;
142     case 1: /* L0 PDE */
143         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
144         pde = ldl_phys(pde_ptr);
145
146         switch (pde & PTE_ENTRYTYPE_MASK) {
147         default:
148         case 0: /* Invalid */
149             return (1 << 8) | (1 << 2);
150         case 3: /* Reserved */
151             return (1 << 8) | (4 << 2);
152         case 1: /* L1 PDE */
153             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
154             pde = ldl_phys(pde_ptr);
155
156             switch (pde & PTE_ENTRYTYPE_MASK) {
157             default:
158             case 0: /* Invalid */
159                 return (2 << 8) | (1 << 2);
160             case 3: /* Reserved */
161                 return (2 << 8) | (4 << 2);
162             case 1: /* L2 PDE */
163                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
164                 pde = ldl_phys(pde_ptr);
165
166                 switch (pde & PTE_ENTRYTYPE_MASK) {
167                 default:
168                 case 0: /* Invalid */
169                     return (3 << 8) | (1 << 2);
170                 case 1: /* PDE, should not happen */
171                 case 3: /* Reserved */
172                     return (3 << 8) | (4 << 2);
173                 case 2: /* L3 PTE */
174                     virt_addr = address & TARGET_PAGE_MASK;
175                     page_offset = (address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1);
176                 }
177                 break;
178             case 2: /* L2 PTE */
179                 virt_addr = address & ~0x3ffff;
180                 page_offset = address & 0x3ffff;
181             }
182             break;
183         case 2: /* L1 PTE */
184             virt_addr = address & ~0xffffff;
185             page_offset = address & 0xffffff;
186         }
187     }
188
189     /* update page modified and dirty bits */
190     is_dirty = (rw & 1) && !(pde & PG_MODIFIED_MASK);
191     if (!(pde & PG_ACCESSED_MASK) || is_dirty) {
192         pde |= PG_ACCESSED_MASK;
193         if (is_dirty)
194             pde |= PG_MODIFIED_MASK;
195         stl_phys_notdirty(pde_ptr, pde);
196     }
197     /* check access */
198     access_perms = (pde & PTE_ACCESS_MASK) >> PTE_ACCESS_SHIFT;
199     error_code = access_table[*access_index][access_perms];
200     if (error_code && !((env->mmuregs[0] & MMU_NF) && is_user))
201         return error_code;
202
203     /* the page can be put in the TLB */
204     *prot = perm_table[is_user][access_perms];
205     if (!(pde & PG_MODIFIED_MASK)) {
206         /* only set write access if already dirty... otherwise wait
207            for dirty access */
208         *prot &= ~PAGE_WRITE;
209     }
210
211     /* Even if large ptes, we map only one 4KB page in the cache to
212        avoid filling it too fast */
213     *physical = ((target_phys_addr_t)(pde & PTE_ADDR_MASK) << 4) + page_offset;
214     return error_code;
215 }
216
217 /* Perform address translation */
218 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
219                               int is_user, int is_softmmu)
220 {
221     target_phys_addr_t paddr;
222     target_ulong vaddr;
223     int error_code = 0, prot, ret = 0, access_index;
224
225     error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
226     if (error_code == 0) {
227         vaddr = address & TARGET_PAGE_MASK;
228         paddr &= TARGET_PAGE_MASK;
229 #ifdef DEBUG_MMU
230         printf("Translate at " TARGET_FMT_lx " -> " TARGET_FMT_plx ", vaddr "
231                TARGET_FMT_lx "\n", address, paddr, vaddr);
232 #endif
233         ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
234         return ret;
235     }
236
237     if (env->mmuregs[3]) /* Fault status register */
238         env->mmuregs[3] = 1; /* overflow (not read before another fault) */
239     env->mmuregs[3] |= (access_index << 5) | error_code | 2;
240     env->mmuregs[4] = address; /* Fault address register */
241
242     if ((env->mmuregs[0] & MMU_NF) || env->psret == 0)  {
243         // No fault mode: if a mapping is available, just override
244         // permissions. If no mapping is available, redirect accesses to
245         // neverland. Fake/overridden mappings will be flushed when
246         // switching to normal mode.
247         vaddr = address & TARGET_PAGE_MASK;
248         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
249         ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
250         return ret;
251     } else {
252         if (rw & 2)
253             env->exception_index = TT_TFAULT;
254         else
255             env->exception_index = TT_DFAULT;
256         return 1;
257     }
258 }
259
260 target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev)
261 {
262     target_phys_addr_t pde_ptr;
263     uint32_t pde;
264
265     /* Context base + context number */
266     pde_ptr = (target_phys_addr_t)(env->mmuregs[1] << 4) +
267         (env->mmuregs[2] << 2);
268     pde = ldl_phys(pde_ptr);
269
270     switch (pde & PTE_ENTRYTYPE_MASK) {
271     default:
272     case 0: /* Invalid */
273     case 2: /* PTE, maybe should not happen? */
274     case 3: /* Reserved */
275         return 0;
276     case 1: /* L1 PDE */
277         if (mmulev == 3)
278             return pde;
279         pde_ptr = ((address >> 22) & ~3) + ((pde & ~3) << 4);
280         pde = ldl_phys(pde_ptr);
281
282         switch (pde & PTE_ENTRYTYPE_MASK) {
283         default:
284         case 0: /* Invalid */
285         case 3: /* Reserved */
286             return 0;
287         case 2: /* L1 PTE */
288             return pde;
289         case 1: /* L2 PDE */
290             if (mmulev == 2)
291                 return pde;
292             pde_ptr = ((address & 0xfc0000) >> 16) + ((pde & ~3) << 4);
293             pde = ldl_phys(pde_ptr);
294
295             switch (pde & PTE_ENTRYTYPE_MASK) {
296             default:
297             case 0: /* Invalid */
298             case 3: /* Reserved */
299                 return 0;
300             case 2: /* L2 PTE */
301                 return pde;
302             case 1: /* L3 PDE */
303                 if (mmulev == 1)
304                     return pde;
305                 pde_ptr = ((address & 0x3f000) >> 10) + ((pde & ~3) << 4);
306                 pde = ldl_phys(pde_ptr);
307
308                 switch (pde & PTE_ENTRYTYPE_MASK) {
309                 default:
310                 case 0: /* Invalid */
311                 case 1: /* PDE, should not happen */
312                 case 3: /* Reserved */
313                     return 0;
314                 case 2: /* L3 PTE */
315                     return pde;
316                 }
317             }
318         }
319     }
320     return 0;
321 }
322
323 #ifdef DEBUG_MMU
324 void dump_mmu(CPUState *env)
325 {
326     target_ulong va, va1, va2;
327     unsigned int n, m, o;
328     target_phys_addr_t pde_ptr, pa;
329     uint32_t pde;
330
331     printf("MMU dump:\n");
332     pde_ptr = (env->mmuregs[1] << 4) + (env->mmuregs[2] << 2);
333     pde = ldl_phys(pde_ptr);
334     printf("Root ptr: " TARGET_FMT_plx ", ctx: %d\n",
335            (target_phys_addr_t)env->mmuregs[1] << 4, env->mmuregs[2]);
336     for (n = 0, va = 0; n < 256; n++, va += 16 * 1024 * 1024) {
337         pde = mmu_probe(env, va, 2);
338         if (pde) {
339             pa = cpu_get_phys_page_debug(env, va);
340             printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
341                    " PDE: " TARGET_FMT_lx "\n", va, pa, pde);
342             for (m = 0, va1 = va; m < 64; m++, va1 += 256 * 1024) {
343                 pde = mmu_probe(env, va1, 1);
344                 if (pde) {
345                     pa = cpu_get_phys_page_debug(env, va1);
346                     printf(" VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_plx
347                            " PDE: " TARGET_FMT_lx "\n", va1, pa, pde);
348                     for (o = 0, va2 = va1; o < 64; o++, va2 += 4 * 1024) {
349                         pde = mmu_probe(env, va2, 0);
350                         if (pde) {
351                             pa = cpu_get_phys_page_debug(env, va2);
352                             printf("  VA: " TARGET_FMT_lx ", PA: "
353                                    TARGET_FMT_plx " PTE: " TARGET_FMT_lx "\n",
354                                    va2, pa, pde);
355                         }
356                     }
357                 }
358             }
359         }
360     }
361     printf("MMU dump ends\n");
362 }
363 #endif /* DEBUG_MMU */
364
365 #else /* !TARGET_SPARC64 */
366 /*
367  * UltraSparc IIi I/DMMUs
368  */
369 static int get_physical_address_data(CPUState *env, target_phys_addr_t *physical, int *prot,
370                           int *access_index, target_ulong address, int rw,
371                           int is_user)
372 {
373     target_ulong mask;
374     unsigned int i;
375
376     if ((env->lsu & DMMU_E) == 0) { /* DMMU disabled */
377         *physical = address;
378         *prot = PAGE_READ | PAGE_WRITE;
379         return 0;
380     }
381
382     for (i = 0; i < 64; i++) {
383         switch ((env->dtlb_tte[i] >> 61) & 3) {
384         default:
385         case 0x0: // 8k
386             mask = 0xffffffffffffe000ULL;
387             break;
388         case 0x1: // 64k
389             mask = 0xffffffffffff0000ULL;
390             break;
391         case 0x2: // 512k
392             mask = 0xfffffffffff80000ULL;
393             break;
394         case 0x3: // 4M
395             mask = 0xffffffffffc00000ULL;
396             break;
397         }
398         // ctx match, vaddr match?
399         if (env->dmmuregs[1] == (env->dtlb_tag[i] & 0x1fff) &&
400             (address & mask) == (env->dtlb_tag[i] & ~0x1fffULL)) {
401             // valid, access ok?
402             if ((env->dtlb_tte[i] & 0x8000000000000000ULL) == 0 ||
403                 ((env->dtlb_tte[i] & 0x4) && is_user) ||
404                 (!(env->dtlb_tte[i] & 0x2) && (rw == 1))) {
405                 if (env->dmmuregs[3]) /* Fault status register */
406                     env->dmmuregs[3] = 2; /* overflow (not read before another fault) */
407                 env->dmmuregs[3] |= (is_user << 3) | ((rw == 1) << 2) | 1;
408                 env->dmmuregs[4] = address; /* Fault address register */
409                 env->exception_index = TT_DFAULT;
410 #ifdef DEBUG_MMU
411                 printf("DFAULT at 0x%" PRIx64 "\n", address);
412 #endif
413                 return 1;
414             }
415             *physical = (env->dtlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
416             *prot = PAGE_READ;
417             if (env->dtlb_tte[i] & 0x2)
418                 *prot |= PAGE_WRITE;
419             return 0;
420         }
421     }
422 #ifdef DEBUG_MMU
423     printf("DMISS at 0x%" PRIx64 "\n", address);
424 #endif
425     env->exception_index = TT_DMISS;
426     return 1;
427 }
428
429 static int get_physical_address_code(CPUState *env, target_phys_addr_t *physical, int *prot,
430                           int *access_index, target_ulong address, int rw,
431                           int is_user)
432 {
433     target_ulong mask;
434     unsigned int i;
435
436     if ((env->lsu & IMMU_E) == 0) { /* IMMU disabled */
437         *physical = address;
438         *prot = PAGE_EXEC;
439         return 0;
440     }
441
442     for (i = 0; i < 64; i++) {
443         switch ((env->itlb_tte[i] >> 61) & 3) {
444         default:
445         case 0x0: // 8k
446             mask = 0xffffffffffffe000ULL;
447             break;
448         case 0x1: // 64k
449             mask = 0xffffffffffff0000ULL;
450             break;
451         case 0x2: // 512k
452             mask = 0xfffffffffff80000ULL;
453             break;
454         case 0x3: // 4M
455             mask = 0xffffffffffc00000ULL;
456                 break;
457         }
458         // ctx match, vaddr match?
459         if (env->dmmuregs[1] == (env->itlb_tag[i] & 0x1fff) &&
460             (address & mask) == (env->itlb_tag[i] & ~0x1fffULL)) {
461             // valid, access ok?
462             if ((env->itlb_tte[i] & 0x8000000000000000ULL) == 0 ||
463                 ((env->itlb_tte[i] & 0x4) && is_user)) {
464                 if (env->immuregs[3]) /* Fault status register */
465                     env->immuregs[3] = 2; /* overflow (not read before another fault) */
466                 env->immuregs[3] |= (is_user << 3) | 1;
467                 env->exception_index = TT_TFAULT;
468 #ifdef DEBUG_MMU
469                 printf("TFAULT at 0x%" PRIx64 "\n", address);
470 #endif
471                 return 1;
472             }
473             *physical = (env->itlb_tte[i] & mask & 0x1fffffff000ULL) + (address & ~mask & 0x1fffffff000ULL);
474             *prot = PAGE_EXEC;
475             return 0;
476         }
477     }
478 #ifdef DEBUG_MMU
479     printf("TMISS at 0x%" PRIx64 "\n", address);
480 #endif
481     env->exception_index = TT_TMISS;
482     return 1;
483 }
484
485 int get_physical_address(CPUState *env, target_phys_addr_t *physical, int *prot,
486                           int *access_index, target_ulong address, int rw,
487                           int is_user)
488 {
489     if (rw == 2)
490         return get_physical_address_code(env, physical, prot, access_index, address, rw, is_user);
491     else
492         return get_physical_address_data(env, physical, prot, access_index, address, rw, is_user);
493 }
494
495 /* Perform address translation */
496 int cpu_sparc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
497                               int is_user, int is_softmmu)
498 {
499     target_ulong virt_addr, vaddr;
500     target_phys_addr_t paddr;
501     int error_code = 0, prot, ret = 0, access_index;
502
503     error_code = get_physical_address(env, &paddr, &prot, &access_index, address, rw, is_user);
504     if (error_code == 0) {
505         virt_addr = address & TARGET_PAGE_MASK;
506         vaddr = virt_addr + ((address & TARGET_PAGE_MASK) & (TARGET_PAGE_SIZE - 1));
507 #ifdef DEBUG_MMU
508         printf("Translate at 0x%" PRIx64 " -> 0x%" PRIx64 ", vaddr 0x%" PRIx64 "\n", address, paddr, vaddr);
509 #endif
510         ret = tlb_set_page_exec(env, vaddr, paddr, prot, is_user, is_softmmu);
511         return ret;
512     }
513     // XXX
514     return 1;
515 }
516
517 #ifdef DEBUG_MMU
518 void dump_mmu(CPUState *env)
519 {
520     unsigned int i;
521     const char *mask;
522
523     printf("MMU contexts: Primary: %" PRId64 ", Secondary: %" PRId64 "\n", env->dmmuregs[1], env->dmmuregs[2]);
524     if ((env->lsu & DMMU_E) == 0) {
525         printf("DMMU disabled\n");
526     } else {
527         printf("DMMU dump:\n");
528         for (i = 0; i < 64; i++) {
529             switch ((env->dtlb_tte[i] >> 61) & 3) {
530             default:
531             case 0x0:
532                 mask = "  8k";
533                 break;
534             case 0x1:
535                 mask = " 64k";
536                 break;
537             case 0x2:
538                 mask = "512k";
539                 break;
540             case 0x3:
541                 mask = "  4M";
542                 break;
543             }
544             if ((env->dtlb_tte[i] & 0x8000000000000000ULL) != 0) {
545                 printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, %s, ctx %" PRId64 "\n",
546                        env->dtlb_tag[i] & ~0x1fffULL,
547                        env->dtlb_tte[i] & 0x1ffffffe000ULL,
548                        mask,
549                        env->dtlb_tte[i] & 0x4? "priv": "user",
550                        env->dtlb_tte[i] & 0x2? "RW": "RO",
551                        env->dtlb_tte[i] & 0x40? "locked": "unlocked",
552                        env->dtlb_tag[i] & 0x1fffULL);
553             }
554         }
555     }
556     if ((env->lsu & IMMU_E) == 0) {
557         printf("IMMU disabled\n");
558     } else {
559         printf("IMMU dump:\n");
560         for (i = 0; i < 64; i++) {
561             switch ((env->itlb_tte[i] >> 61) & 3) {
562             default:
563             case 0x0:
564                 mask = "  8k";
565                 break;
566             case 0x1:
567                 mask = " 64k";
568                 break;
569             case 0x2:
570                 mask = "512k";
571                 break;
572             case 0x3:
573                 mask = "  4M";
574                 break;
575             }
576             if ((env->itlb_tte[i] & 0x8000000000000000ULL) != 0) {
577                 printf("VA: " TARGET_FMT_lx ", PA: " TARGET_FMT_lx ", %s, %s, %s, ctx %" PRId64 "\n",
578                        env->itlb_tag[i] & ~0x1fffULL,
579                        env->itlb_tte[i] & 0x1ffffffe000ULL,
580                        mask,
581                        env->itlb_tte[i] & 0x4? "priv": "user",
582                        env->itlb_tte[i] & 0x40? "locked": "unlocked",
583                        env->itlb_tag[i] & 0x1fffULL);
584             }
585         }
586     }
587 }
588 #endif /* DEBUG_MMU */
589
590 #endif /* TARGET_SPARC64 */
591 #endif /* !CONFIG_USER_ONLY */
592
593 void memcpy32(target_ulong *dst, const target_ulong *src)
594 {
595     dst[0] = src[0];
596     dst[1] = src[1];
597     dst[2] = src[2];
598     dst[3] = src[3];
599     dst[4] = src[4];
600     dst[5] = src[5];
601     dst[6] = src[6];
602     dst[7] = src[7];
603 }