]> Git Repo - qemu.git/blob - target-ppc/mmu-hash32.c
mmu-hash*: Add header file for definitions
[qemu.git] / target-ppc / mmu-hash32.c
1 /*
2  *  PowerPC MMU, TLB and BAT emulation helpers for QEMU.
3  *
4  *  Copyright (c) 2003-2007 Jocelyn Mayer
5  *  Copyright (c) 2013 David Gibson, IBM Corporation
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "cpu.h"
22 #include "helper.h"
23 #include "sysemu/kvm.h"
24 #include "kvm_ppc.h"
25 #include "mmu-hash32.h"
26
27 //#define DEBUG_MMU
28 //#define DEBUG_BAT
29
30 #ifdef DEBUG_MMU
31 #  define LOG_MMU(...) qemu_log(__VA_ARGS__)
32 #  define LOG_MMU_STATE(env) log_cpu_state((env), 0)
33 #else
34 #  define LOG_MMU(...) do { } while (0)
35 #  define LOG_MMU_STATE(...) do { } while (0)
36 #endif
37
38 #ifdef DEBUG_BATS
39 #  define LOG_BATS(...) qemu_log(__VA_ARGS__)
40 #else
41 #  define LOG_BATS(...) do { } while (0)
42 #endif
43
44 struct mmu_ctx_hash32 {
45     hwaddr raddr;      /* Real address              */
46     hwaddr eaddr;      /* Effective address         */
47     int prot;                      /* Protection bits           */
48     hwaddr hash[2];    /* Pagetable hash values     */
49     target_ulong ptem;             /* Virtual segment ID | API  */
50     int key;                       /* Access key                */
51     int nx;                        /* Non-execute area          */
52 };
53
54 #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
55
56 static int ppc_hash32_pp_check(int key, int pp, int nx)
57 {
58     int access;
59
60     /* Compute access rights */
61     access = 0;
62     if (key == 0) {
63         switch (pp) {
64         case 0x0:
65         case 0x1:
66         case 0x2:
67             access |= PAGE_WRITE;
68             /* No break here */
69         case 0x3:
70             access |= PAGE_READ;
71             break;
72         }
73     } else {
74         switch (pp) {
75         case 0x0:
76             access = 0;
77             break;
78         case 0x1:
79         case 0x3:
80             access = PAGE_READ;
81             break;
82         case 0x2:
83             access = PAGE_READ | PAGE_WRITE;
84             break;
85         }
86     }
87     if (nx == 0) {
88         access |= PAGE_EXEC;
89     }
90
91     return access;
92 }
93
94 static int ppc_hash32_check_prot(int prot, int rw, int access_type)
95 {
96     int ret;
97
98     if (access_type == ACCESS_CODE) {
99         if (prot & PAGE_EXEC) {
100             ret = 0;
101         } else {
102             ret = -2;
103         }
104     } else if (rw) {
105         if (prot & PAGE_WRITE) {
106             ret = 0;
107         } else {
108             ret = -2;
109         }
110     } else {
111         if (prot & PAGE_READ) {
112             ret = 0;
113         } else {
114             ret = -2;
115         }
116     }
117
118     return ret;
119 }
120
121 /* Perform BAT hit & translation */
122 static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
123                                  int *validp, int *protp, target_ulong *BATu,
124                                  target_ulong *BATl)
125 {
126     target_ulong bl;
127     int pp, valid, prot;
128
129     bl = (*BATu & BATU32_BL) << 15;
130     valid = 0;
131     prot = 0;
132     if (((msr_pr == 0) && (*BATu & BATU32_VS)) ||
133         ((msr_pr != 0) && (*BATu & BATU32_VP))) {
134         valid = 1;
135         pp = *BATl & BATL32_PP;
136         if (pp != 0) {
137             prot = PAGE_READ | PAGE_EXEC;
138             if (pp == 0x2) {
139                 prot |= PAGE_WRITE;
140             }
141         }
142     }
143     *blp = bl;
144     *validp = valid;
145     *protp = prot;
146 }
147
148 static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
149                                      int *validp, int *protp,
150                                      target_ulong *BATu, target_ulong *BATl)
151 {
152     target_ulong bl;
153     int key, pp, valid, prot;
154
155     bl = (*BATl & BATL32_601_BL) << 17;
156     LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
157              (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl);
158     prot = 0;
159     valid = !!(*BATl & BATL32_601_V);
160     if (valid) {
161         pp = *BATu & BATU32_601_PP;
162         if (msr_pr == 0) {
163             key = !!(*BATu & BATU32_601_KS);
164         } else {
165             key = !!(*BATu & BATU32_601_KP);
166         }
167         prot = ppc_hash32_pp_check(key, pp, 0);
168     }
169     *blp = bl;
170     *validp = valid;
171     *protp = prot;
172 }
173
174 static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
175                               target_ulong virtual, int rw, int type)
176 {
177     target_ulong *BATlt, *BATut, *BATu, *BATl;
178     target_ulong BEPIl, BEPIu, bl;
179     int i, valid, prot;
180     int ret = -1;
181
182     LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
183              type == ACCESS_CODE ? 'I' : 'D', virtual);
184     switch (type) {
185     case ACCESS_CODE:
186         BATlt = env->IBAT[1];
187         BATut = env->IBAT[0];
188         break;
189     default:
190         BATlt = env->DBAT[1];
191         BATut = env->DBAT[0];
192         break;
193     }
194     for (i = 0; i < env->nb_BATs; i++) {
195         BATu = &BATut[i];
196         BATl = &BATlt[i];
197         BEPIu = *BATu & BATU32_BEPIU;
198         BEPIl = *BATu & BATU32_BEPIL;
199         if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
200             hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
201         } else {
202             hash32_bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
203         }
204         LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
205                  " BATl " TARGET_FMT_lx "\n", __func__,
206                  type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
207         if ((virtual & BATU32_BEPIU) == BEPIu &&
208             ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
209             /* BAT matches */
210             if (valid != 0) {
211                 /* Get physical address */
212                 ctx->raddr = (*BATl & BATL32_BRPNU) |
213                     ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) |
214                     (virtual & 0x0001F000);
215                 /* Compute access rights */
216                 ctx->prot = prot;
217                 ret = ppc_hash32_check_prot(ctx->prot, rw, type);
218                 if (ret == 0) {
219                     LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
220                              i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
221                              ctx->prot & PAGE_WRITE ? 'W' : '-');
222                 }
223                 break;
224             }
225         }
226     }
227     if (ret < 0) {
228 #if defined(DEBUG_BATS)
229         if (qemu_log_enabled()) {
230             LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
231             for (i = 0; i < 4; i++) {
232                 BATu = &BATut[i];
233                 BATl = &BATlt[i];
234                 BEPIu = *BATu & BATU32_BEPIU;
235                 BEPIl = *BATu & BATU32_BEPIL;
236                 bl = (*BATu & 0x00001FFC) << 15;
237                 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
238                          " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
239                          TARGET_FMT_lx " " TARGET_FMT_lx "\n",
240                          __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
241                          *BATu, *BATl, BEPIu, BEPIl, bl);
242             }
243         }
244 #endif
245     }
246     /* No hit */
247     return ret;
248 }
249
250 static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
251                             target_ulong pte1, int h, int rw, int type)
252 {
253     target_ulong mmask;
254     int access, ret, pp;
255
256     ret = -1;
257     /* Check validity and table match */
258     if ((pte0 & HPTE32_V_VALID) && (h == !!(pte0 & HPTE32_V_SECONDARY))) {
259         /* Check vsid & api */
260         mmask = PTE_CHECK_MASK;
261         pp = pte1 & HPTE32_R_PP;
262         if (HPTE32_V_COMPARE(pte0, ctx->ptem)) {
263             if (ctx->raddr != (hwaddr)-1ULL) {
264                 /* all matches should have equal RPN, WIMG & PP */
265                 if ((ctx->raddr & mmask) != (pte1 & mmask)) {
266                     qemu_log("Bad RPN/WIMG/PP\n");
267                     return -3;
268                 }
269             }
270             /* Compute access rights */
271             access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
272             /* Keep the matching PTE informations */
273             ctx->raddr = pte1;
274             ctx->prot = access;
275             ret = ppc_hash32_check_prot(ctx->prot, rw, type);
276             if (ret == 0) {
277                 /* Access granted */
278                 LOG_MMU("PTE access granted !\n");
279             } else {
280                 /* Access right violation */
281                 LOG_MMU("PTE access rejected\n");
282             }
283         }
284     }
285
286     return ret;
287 }
288
289 static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, target_ulong *pte1p,
290                                        int ret, int rw)
291 {
292     int store = 0;
293
294     /* Update page flags */
295     if (!(*pte1p & HPTE32_R_R)) {
296         /* Update accessed flag */
297         *pte1p |= HPTE32_R_R;
298         store = 1;
299     }
300     if (!(*pte1p & HPTE32_R_C)) {
301         if (rw == 1 && ret == 0) {
302             /* Update changed flag */
303             *pte1p |= HPTE32_R_C;
304             store = 1;
305         } else {
306             /* Force page fault for first write access */
307             ctx->prot &= ~PAGE_WRITE;
308         }
309     }
310
311     return store;
312 }
313
314 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
315 {
316     return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
317 }
318
319 /* PTE table lookup */
320 static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx, int h,
321                       int rw, int type, int target_page_bits)
322 {
323     hwaddr pteg_off;
324     target_ulong pte0, pte1;
325     int i, good = -1;
326     int ret, r;
327
328     ret = -1; /* No entry found */
329     pteg_off = get_pteg_offset32(env, ctx->hash[h]);
330     for (i = 0; i < HPTES_PER_GROUP; i++) {
331         if (env->external_htab) {
332             pte0 = ldl_p(env->external_htab + pteg_off + (i * 8));
333             pte1 = ldl_p(env->external_htab + pteg_off + (i * 8) + 4);
334         } else {
335             pte0 = ldl_phys(env->htab_base + pteg_off + (i * 8));
336             pte1 = ldl_phys(env->htab_base + pteg_off + (i * 8) + 4);
337         }
338         r = pte_check_hash32(ctx, pte0, pte1, h, rw, type);
339         LOG_MMU("Load pte from %08" HWADDR_PRIx " => " TARGET_FMT_lx " "
340                 TARGET_FMT_lx " %d %d %d " TARGET_FMT_lx "\n",
341                 pteg_off + (i * 8), pte0, pte1, (int)(pte0 >> 31), h,
342                 (int)((pte0 >> 6) & 1), ctx->ptem);
343         switch (r) {
344         case -3:
345             /* PTE inconsistency */
346             return -1;
347         case -2:
348             /* Access violation */
349             ret = -2;
350             good = i;
351             break;
352         case -1:
353         default:
354             /* No PTE match */
355             break;
356         case 0:
357             /* access granted */
358             /* XXX: we should go on looping to check all PTEs consistency
359              *      but if we can speed-up the whole thing as the
360              *      result would be undefined if PTEs are not consistent.
361              */
362             ret = 0;
363             good = i;
364             goto done;
365         }
366     }
367     if (good != -1) {
368     done:
369         LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
370                 ctx->raddr, ctx->prot, ret);
371         /* Update page flags */
372         pte1 = ctx->raddr;
373         if (ppc_hash32_pte_update_flags(ctx, &pte1, ret, rw) == 1) {
374             if (env->external_htab) {
375                 stl_p(env->external_htab + pteg_off + (good * 8) + 4,
376                       pte1);
377             } else {
378                 stl_phys_notdirty(env->htab_base + pteg_off +
379                                   (good * 8) + 4, pte1);
380             }
381         }
382     }
383
384     /* We have a TLB that saves 4K pages, so let's
385      * split a huge page to 4k chunks */
386     if (target_page_bits != TARGET_PAGE_BITS) {
387         ctx->raddr |= (ctx->eaddr & ((1 << target_page_bits) - 1))
388                       & TARGET_PAGE_MASK;
389     }
390     return ret;
391 }
392
393 static int get_segment32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
394                          target_ulong eaddr, int rw, int type)
395 {
396     hwaddr hash;
397     target_ulong vsid;
398     int ds, pr, target_page_bits;
399     int ret, ret2;
400     target_ulong sr, pgidx;
401
402     pr = msr_pr;
403     ctx->eaddr = eaddr;
404
405     sr = env->sr[eaddr >> 28];
406     ctx->key = (((sr & SR32_KP) && (pr != 0)) ||
407                 ((sr & SR32_KS) && (pr == 0))) ? 1 : 0;
408     ds = !!(sr & SR32_T);
409     ctx->nx = !!(sr & SR32_NX);
410     vsid = sr & SR32_VSID;
411     target_page_bits = TARGET_PAGE_BITS;
412     LOG_MMU("Check segment v=" TARGET_FMT_lx " %d " TARGET_FMT_lx " nip="
413             TARGET_FMT_lx " lr=" TARGET_FMT_lx
414             " ir=%d dr=%d pr=%d %d t=%d\n",
415             eaddr, (int)(eaddr >> 28), sr, env->nip, env->lr, (int)msr_ir,
416             (int)msr_dr, pr != 0 ? 1 : 0, rw, type);
417     pgidx = (eaddr & ~SEGMENT_MASK_256M) >> target_page_bits;
418     hash = vsid ^ pgidx;
419     ctx->ptem = (vsid << 7) | (pgidx >> 10);
420
421     LOG_MMU("pte segment: key=%d ds %d nx %d vsid " TARGET_FMT_lx "\n",
422             ctx->key, ds, ctx->nx, vsid);
423     ret = -1;
424     if (!ds) {
425         /* Check if instruction fetch is allowed, if needed */
426         if (type != ACCESS_CODE || ctx->nx == 0) {
427             /* Page address translation */
428             LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
429                     " hash " TARGET_FMT_plx "\n",
430                     env->htab_base, env->htab_mask, hash);
431             ctx->hash[0] = hash;
432             ctx->hash[1] = ~hash;
433
434             /* Initialize real address with an invalid value */
435             ctx->raddr = (hwaddr)-1ULL;
436             LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
437                     " vsid=" TARGET_FMT_lx " ptem=" TARGET_FMT_lx
438                     " hash=" TARGET_FMT_plx "\n",
439                     env->htab_base, env->htab_mask, vsid, ctx->ptem,
440                     ctx->hash[0]);
441             /* Primary table lookup */
442             ret = find_pte32(env, ctx, 0, rw, type, target_page_bits);
443             if (ret < 0) {
444                 /* Secondary table lookup */
445                 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
446                         " vsid=" TARGET_FMT_lx " api=" TARGET_FMT_lx
447                         " hash=" TARGET_FMT_plx "\n", env->htab_base,
448                         env->htab_mask, vsid, ctx->ptem, ctx->hash[1]);
449                 ret2 = find_pte32(env, ctx, 1, rw, type,
450                                   target_page_bits);
451                 if (ret2 != -1) {
452                     ret = ret2;
453                 }
454             }
455 #if defined(DUMP_PAGE_TABLES)
456             if (qemu_log_enabled()) {
457                 hwaddr curaddr;
458                 uint32_t a0, a1, a2, a3;
459
460                 qemu_log("Page table: " TARGET_FMT_plx " len " TARGET_FMT_plx
461                          "\n", sdr, mask + 0x80);
462                 for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
463                      curaddr += 16) {
464                     a0 = ldl_phys(curaddr);
465                     a1 = ldl_phys(curaddr + 4);
466                     a2 = ldl_phys(curaddr + 8);
467                     a3 = ldl_phys(curaddr + 12);
468                     if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
469                         qemu_log(TARGET_FMT_plx ": %08x %08x %08x %08x\n",
470                                  curaddr, a0, a1, a2, a3);
471                     }
472                 }
473             }
474 #endif
475         } else {
476             LOG_MMU("No access allowed\n");
477             ret = -3;
478         }
479     } else {
480         target_ulong sr;
481
482         LOG_MMU("direct store...\n");
483         /* Direct-store segment : absolutely *BUGGY* for now */
484
485         /* Direct-store implies a 32-bit MMU.
486          * Check the Segment Register's bus unit ID (BUID).
487          */
488         sr = env->sr[eaddr >> 28];
489         if ((sr & 0x1FF00000) >> 20 == 0x07f) {
490             /* Memory-forced I/O controller interface access */
491             /* If T=1 and BUID=x'07F', the 601 performs a memory access
492              * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
493              */
494             ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
495             ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
496             return 0;
497         }
498
499         switch (type) {
500         case ACCESS_INT:
501             /* Integer load/store : only access allowed */
502             break;
503         case ACCESS_CODE:
504             /* No code fetch is allowed in direct-store areas */
505             return -4;
506         case ACCESS_FLOAT:
507             /* Floating point load/store */
508             return -4;
509         case ACCESS_RES:
510             /* lwarx, ldarx or srwcx. */
511             return -4;
512         case ACCESS_CACHE:
513             /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
514             /* Should make the instruction do no-op.
515              * As it already do no-op, it's quite easy :-)
516              */
517             ctx->raddr = eaddr;
518             return 0;
519         case ACCESS_EXT:
520             /* eciwx or ecowx */
521             return -4;
522         default:
523             qemu_log("ERROR: instruction should not need "
524                         "address translation\n");
525             return -4;
526         }
527         if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
528             ctx->raddr = eaddr;
529             ret = 2;
530         } else {
531             ret = -2;
532         }
533     }
534
535     return ret;
536 }
537
538 static int ppc_hash32_get_physical_address(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
539                                            target_ulong eaddr, int rw,
540                                            int access_type)
541 {
542     bool real_mode = (access_type == ACCESS_CODE && msr_ir == 0)
543         || (access_type != ACCESS_CODE && msr_dr == 0);
544
545     if (real_mode) {
546         ctx->raddr = eaddr;
547         ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
548         return 0;
549     } else {
550         int ret = -1;
551
552         /* Try to find a BAT */
553         if (env->nb_BATs != 0) {
554             ret = ppc_hash32_get_bat(env, ctx, eaddr, rw, access_type);
555         }
556         if (ret < 0) {
557             /* We didn't match any BAT entry or don't have BATs */
558             ret = get_segment32(env, ctx, eaddr, rw, access_type);
559         }
560         return ret;
561     }
562 }
563
564 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
565 {
566     struct mmu_ctx_hash32 ctx;
567
568     if (unlikely(ppc_hash32_get_physical_address(env, &ctx, addr, 0, ACCESS_INT)
569                  != 0)) {
570         return -1;
571     }
572
573     return ctx.raddr & TARGET_PAGE_MASK;
574 }
575
576 int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rw,
577                                 int mmu_idx)
578 {
579     struct mmu_ctx_hash32 ctx;
580     int access_type;
581     int ret = 0;
582
583     if (rw == 2) {
584         /* code access */
585         rw = 0;
586         access_type = ACCESS_CODE;
587     } else {
588         /* data access */
589         access_type = env->access_type;
590     }
591     ret = ppc_hash32_get_physical_address(env, &ctx, address, rw, access_type);
592     if (ret == 0) {
593         tlb_set_page(env, address & TARGET_PAGE_MASK,
594                      ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
595                      mmu_idx, TARGET_PAGE_SIZE);
596         ret = 0;
597     } else if (ret < 0) {
598         LOG_MMU_STATE(env);
599         if (access_type == ACCESS_CODE) {
600             switch (ret) {
601             case -1:
602                 /* No matches in page tables or TLB */
603                 env->exception_index = POWERPC_EXCP_ISI;
604                 env->error_code = 0x40000000;
605                 break;
606             case -2:
607                 /* Access rights violation */
608                 env->exception_index = POWERPC_EXCP_ISI;
609                 env->error_code = 0x08000000;
610                 break;
611             case -3:
612                 /* No execute protection violation */
613                 env->exception_index = POWERPC_EXCP_ISI;
614                 env->error_code = 0x10000000;
615                 break;
616             case -4:
617                 /* Direct store exception */
618                 /* No code fetch is allowed in direct-store areas */
619                 env->exception_index = POWERPC_EXCP_ISI;
620                 env->error_code = 0x10000000;
621                 break;
622             }
623         } else {
624             switch (ret) {
625             case -1:
626                 /* No matches in page tables or TLB */
627                 env->exception_index = POWERPC_EXCP_DSI;
628                 env->error_code = 0;
629                 env->spr[SPR_DAR] = address;
630                 if (rw == 1) {
631                     env->spr[SPR_DSISR] = 0x42000000;
632                 } else {
633                     env->spr[SPR_DSISR] = 0x40000000;
634                 }
635                 break;
636             case -2:
637                 /* Access rights violation */
638                 env->exception_index = POWERPC_EXCP_DSI;
639                 env->error_code = 0;
640                 env->spr[SPR_DAR] = address;
641                 if (rw == 1) {
642                     env->spr[SPR_DSISR] = 0x0A000000;
643                 } else {
644                     env->spr[SPR_DSISR] = 0x08000000;
645                 }
646                 break;
647             case -4:
648                 /* Direct store exception */
649                 switch (access_type) {
650                 case ACCESS_FLOAT:
651                     /* Floating point load/store */
652                     env->exception_index = POWERPC_EXCP_ALIGN;
653                     env->error_code = POWERPC_EXCP_ALIGN_FP;
654                     env->spr[SPR_DAR] = address;
655                     break;
656                 case ACCESS_RES:
657                     /* lwarx, ldarx or stwcx. */
658                     env->exception_index = POWERPC_EXCP_DSI;
659                     env->error_code = 0;
660                     env->spr[SPR_DAR] = address;
661                     if (rw == 1) {
662                         env->spr[SPR_DSISR] = 0x06000000;
663                     } else {
664                         env->spr[SPR_DSISR] = 0x04000000;
665                     }
666                     break;
667                 case ACCESS_EXT:
668                     /* eciwx or ecowx */
669                     env->exception_index = POWERPC_EXCP_DSI;
670                     env->error_code = 0;
671                     env->spr[SPR_DAR] = address;
672                     if (rw == 1) {
673                         env->spr[SPR_DSISR] = 0x06100000;
674                     } else {
675                         env->spr[SPR_DSISR] = 0x04100000;
676                     }
677                     break;
678                 default:
679                     printf("DSI: invalid exception (%d)\n", ret);
680                     env->exception_index = POWERPC_EXCP_PROGRAM;
681                     env->error_code =
682                         POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
683                     env->spr[SPR_DAR] = address;
684                     break;
685                 }
686                 break;
687             }
688         }
689 #if 0
690         printf("%s: set exception to %d %02x\n", __func__,
691                env->exception, env->error_code);
692 #endif
693         ret = 1;
694     }
695
696     return ret;
697 }
This page took 0.062876 seconds and 4 git commands to generate.