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