Statistics
| Branch: | Revision:

root / hw / alpha_palcode.c @ 6049f4f8

History | View | Annotate | Download (25.4 kB)

1
/*
2
 *  Alpha emulation - PALcode emulation for qemu.
3
 *
4
 *  Copyright (c) 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

    
20
#include <stdint.h>
21
#include <stdlib.h>
22
#include <stdio.h>
23

    
24
#include "cpu.h"
25
#include "exec-all.h"
26

    
27
/* Shared handlers */
28
static void pal_reset (CPUState *env);
29
/* Console handlers */
30
static void pal_console_call (CPUState *env, uint32_t palcode);
31
/* OpenVMS handlers */
32
static void pal_openvms_call (CPUState *env, uint32_t palcode);
33
/* UNIX / Linux handlers */
34
static void pal_unix_call (CPUState *env, uint32_t palcode);
35

    
36
pal_handler_t pal_handlers[] = {
37
    /* Console handler */
38
    {
39
        .reset = &pal_reset,
40
        .call_pal = &pal_console_call,
41
    },
42
    /* OpenVMS handler */
43
    {
44
        .reset = &pal_reset,
45
        .call_pal = &pal_openvms_call,
46
    },
47
    /* UNIX / Linux handler */
48
    {
49
        .reset = &pal_reset,
50
        .call_pal = &pal_unix_call,
51
    },
52
};
53

    
54
#if 0
55
/* One must explicitly check that the TB is valid and the FOE bit is reset */
56
static void update_itb (void)
57
{
58
    /* This writes into a temp register, not the actual one */
59
    mtpr(TB_TAG);
60
    mtpr(TB_CTL);
61
    /* This commits the TB update */
62
    mtpr(ITB_PTE);
63
}
64

65
static void update_dtb (void);
66
{
67
    mtpr(TB_CTL);
68
    /* This write into a temp register, not the actual one */
69
    mtpr(TB_TAG);
70
    /* This commits the TB update */
71
    mtpr(DTB_PTE);
72
}
73
#endif
74

    
75
static void pal_reset (CPUState *env)
76
{
77
}
78

    
79
static void do_swappal (CPUState *env, uint64_t palid)
80
{
81
    pal_handler_t *pal_handler;
82
    int status;
83

    
84
    status = 0;
85
    switch (palid) {
86
    case 0 ... 2:
87
        pal_handler = &pal_handlers[palid];
88
        env->pal_handler = pal_handler;
89
        env->ipr[IPR_PAL_BASE] = -1ULL;
90
        (*pal_handler->reset)(env);
91
        break;
92
    case 3 ... 255:
93
        /* Unknown identifier */
94
        env->ir[0] = 1;
95
        return;
96
    default:
97
        /* We were given the entry point address */
98
        env->pal_handler = NULL;
99
        env->ipr[IPR_PAL_BASE] = palid;
100
        env->pc = env->ipr[IPR_PAL_BASE];
101
        cpu_loop_exit();
102
    }
103
}
104

    
105
static void pal_console_call (CPUState *env, uint32_t palcode)
106
{
107
    uint64_t palid;
108

    
109
    if (palcode < 0x00000080) {
110
        /* Privileged palcodes */
111
        if (!(env->ps >> 3)) {
112
            /* TODO: generate privilege exception */
113
        }
114
    }
115
    switch (palcode) {
116
    case 0x00000000:
117
        /* HALT */
118
        /* REQUIRED */
119
        break;
120
    case 0x00000001:
121
        /* CFLUSH */
122
        break;
123
    case 0x00000002:
124
        /* DRAINA */
125
        /* REQUIRED */
126
        /* Implemented as no-op */
127
        break;
128
    case 0x00000009:
129
        /* CSERVE */
130
        /* REQUIRED */
131
        break;
132
    case 0x0000000A:
133
        /* SWPPAL */
134
        /* REQUIRED */
135
        palid = env->ir[16];
136
        do_swappal(env, palid);
137
        break;
138
    case 0x00000080:
139
        /* BPT */
140
        /* REQUIRED */
141
        break;
142
    case 0x00000081:
143
        /* BUGCHK */
144
        /* REQUIRED */
145
        break;
146
    case 0x00000086:
147
        /* IMB */
148
        /* REQUIRED */
149
        /* Implemented as no-op */
150
        break;
151
    case 0x0000009E:
152
        /* RDUNIQUE */
153
        /* REQUIRED */
154
        break;
155
    case 0x0000009F:
156
        /* WRUNIQUE */
157
        /* REQUIRED */
158
        break;
159
    case 0x000000AA:
160
        /* GENTRAP */
161
        /* REQUIRED */
162
        break;
163
    default:
164
        break;
165
    }
166
}
167

    
168
static void pal_openvms_call (CPUState *env, uint32_t palcode)
169
{
170
    uint64_t palid, val, oldval;
171

    
172
    if (palcode < 0x00000080) {
173
        /* Privileged palcodes */
174
        if (!(env->ps >> 3)) {
175
            /* TODO: generate privilege exception */
176
        }
177
    }
178
    switch (palcode) {
179
    case 0x00000000:
180
        /* HALT */
181
        /* REQUIRED */
182
        break;
183
    case 0x00000001:
184
        /* CFLUSH */
185
        break;
186
    case 0x00000002:
187
        /* DRAINA */
188
        /* REQUIRED */
189
        /* Implemented as no-op */
190
        break;
191
    case 0x00000003:
192
        /* LDQP */
193
        break;
194
    case 0x00000004:
195
        /* STQP */
196
        break;
197
    case 0x00000005:
198
        /* SWPCTX */
199
        break;
200
    case 0x00000006:
201
        /* MFPR_ASN */
202
        if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
203
            env->ir[0] = val;
204
        break;
205
    case 0x00000007:
206
        /* MTPR_ASTEN */
207
        val = env->ir[16];
208
        if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
209
            env->ir[0] = val;
210
        break;
211
    case 0x00000008:
212
        /* MTPR_ASTSR */
213
        val = env->ir[16];
214
        if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
215
            env->ir[0] = val;
216
        break;
217
    case 0x00000009:
218
        /* CSERVE */
219
        /* REQUIRED */
220
        break;
221
    case 0x0000000A:
222
        /* SWPPAL */
223
        /* REQUIRED */
224
        palid = env->ir[16];
225
        do_swappal(env, palid);
226
        break;
227
    case 0x0000000B:
228
        /* MFPR_FEN */
229
        if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
230
            env->ir[0] = val;
231
        break;
232
    case 0x0000000C:
233
        /* MTPR_FEN */
234
        val = env->ir[16];
235
        if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
236
            env->ir[0] = val;
237
        break;
238
    case 0x0000000D:
239
        /* MTPR_IPIR */
240
        val = env->ir[16];
241
        if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
242
            env->ir[0] = val;
243
        break;
244
    case 0x0000000E:
245
        /* MFPR_IPL */
246
        if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
247
            env->ir[0] = val;
248
        break;
249
    case 0x0000000F:
250
        /* MTPR_IPL */
251
        val = env->ir[16];
252
        if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
253
            env->ir[0] = val;
254
        break;
255
    case 0x00000010:
256
        /* MFPR_MCES */
257
        if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
258
            env->ir[0] = val;
259
        break;
260
    case 0x00000011:
261
        /* MTPR_MCES */
262
        val = env->ir[16];
263
        if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
264
            env->ir[0] = val;
265
        break;
266
    case 0x00000012:
267
        /* MFPR_PCBB */
268
        if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
269
            env->ir[0] = val;
270
        break;
271
    case 0x00000013:
272
        /* MFPR_PRBR */
273
        if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
274
            env->ir[0] = val;
275
        break;
276
    case 0x00000014:
277
        /* MTPR_PRBR */
278
        val = env->ir[16];
279
        if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
280
            env->ir[0] = val;
281
        break;
282
    case 0x00000015:
283
        /* MFPR_PTBR */
284
        if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
285
            env->ir[0] = val;
286
        break;
287
    case 0x00000016:
288
        /* MFPR_SCBB */
289
        if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
290
            env->ir[0] = val;
291
        break;
292
    case 0x00000017:
293
        /* MTPR_SCBB */
294
        val = env->ir[16];
295
        if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
296
            env->ir[0] = val;
297
        break;
298
    case 0x00000018:
299
        /* MTPR_SIRR */
300
        val = env->ir[16];
301
        if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
302
            env->ir[0] = val;
303
        break;
304
    case 0x00000019:
305
        /* MFPR_SISR */
306
        if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
307
            env->ir[0] = val;
308
        break;
309
    case 0x0000001A:
310
        /* MFPR_TBCHK */
311
        if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
312
            env->ir[0] = val;
313
        break;
314
    case 0x0000001B:
315
        /* MTPR_TBIA */
316
        val = env->ir[16];
317
        if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
318
            env->ir[0] = val;
319
        break;
320
    case 0x0000001C:
321
        /* MTPR_TBIAP */
322
        val = env->ir[16];
323
        if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
324
            env->ir[0] = val;
325
        break;
326
    case 0x0000001D:
327
        /* MTPR_TBIS */
328
        val = env->ir[16];
329
        if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
330
            env->ir[0] = val;
331
        break;
332
    case 0x0000001E:
333
        /* MFPR_ESP */
334
        if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
335
            env->ir[0] = val;
336
        break;
337
    case 0x0000001F:
338
        /* MTPR_ESP */
339
        val = env->ir[16];
340
        if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
341
            env->ir[0] = val;
342
        break;
343
    case 0x00000020:
344
        /* MFPR_SSP */
345
        if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
346
            env->ir[0] = val;
347
        break;
348
    case 0x00000021:
349
        /* MTPR_SSP */
350
        val = env->ir[16];
351
        if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
352
            env->ir[0] = val;
353
        break;
354
    case 0x00000022:
355
        /* MFPR_USP */
356
        if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
357
            env->ir[0] = val;
358
        break;
359
    case 0x00000023:
360
        /* MTPR_USP */
361
        val = env->ir[16];
362
        if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
363
            env->ir[0] = val;
364
        break;
365
    case 0x00000024:
366
        /* MTPR_TBISD */
367
        val = env->ir[16];
368
        if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
369
            env->ir[0] = val;
370
        break;
371
    case 0x00000025:
372
        /* MTPR_TBISI */
373
        val = env->ir[16];
374
        if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
375
            env->ir[0] = val;
376
        break;
377
    case 0x00000026:
378
        /* MFPR_ASTEN */
379
        if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
380
            env->ir[0] = val;
381
        break;
382
    case 0x00000027:
383
        /* MFPR_ASTSR */
384
        if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
385
            env->ir[0] = val;
386
        break;
387
    case 0x00000029:
388
        /* MFPR_VPTB */
389
        if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
390
            env->ir[0] = val;
391
        break;
392
    case 0x0000002A:
393
        /* MTPR_VPTB */
394
        val = env->ir[16];
395
        if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
396
            env->ir[0] = val;
397
        break;
398
    case 0x0000002B:
399
        /* MTPR_PERFMON */
400
        val = env->ir[16];
401
        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
402
            env->ir[0] = val;
403
        break;
404
    case 0x0000002E:
405
        /* MTPR_DATFX */
406
        val = env->ir[16];
407
        if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
408
            env->ir[0] = val;
409
        break;
410
    case 0x0000003E:
411
        /* WTINT */
412
        break;
413
    case 0x0000003F:
414
        /* MFPR_WHAMI */
415
        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
416
            env->ir[0] = val;
417
        break;
418
    case 0x00000080:
419
        /* BPT */
420
        /* REQUIRED */
421
        break;
422
    case 0x00000081:
423
        /* BUGCHK */
424
        /* REQUIRED */
425
        break;
426
    case 0x00000082:
427
        /* CHME */
428
        break;
429
    case 0x00000083:
430
        /* CHMK */
431
        break;
432
    case 0x00000084:
433
        /* CHMS */
434
        break;
435
    case 0x00000085:
436
        /* CHMU */
437
        break;
438
    case 0x00000086:
439
        /* IMB */
440
        /* REQUIRED */
441
        /* Implemented as no-op */
442
        break;
443
    case 0x00000087:
444
        /* INSQHIL */
445
        break;
446
    case 0x00000088:
447
        /* INSQTIL */
448
        break;
449
    case 0x00000089:
450
        /* INSQHIQ */
451
        break;
452
    case 0x0000008A:
453
        /* INSQTIQ */
454
        break;
455
    case 0x0000008B:
456
        /* INSQUEL */
457
        break;
458
    case 0x0000008C:
459
        /* INSQUEQ */
460
        break;
461
    case 0x0000008D:
462
        /* INSQUEL/D */
463
        break;
464
    case 0x0000008E:
465
        /* INSQUEQ/D */
466
        break;
467
    case 0x0000008F:
468
        /* PROBER */
469
        break;
470
    case 0x00000090:
471
        /* PROBEW */
472
        break;
473
    case 0x00000091:
474
        /* RD_PS */
475
        break;
476
    case 0x00000092:
477
        /* REI */
478
        break;
479
    case 0x00000093:
480
        /* REMQHIL */
481
        break;
482
    case 0x00000094:
483
        /* REMQTIL */
484
        break;
485
    case 0x00000095:
486
        /* REMQHIQ */
487
        break;
488
    case 0x00000096:
489
        /* REMQTIQ */
490
        break;
491
    case 0x00000097:
492
        /* REMQUEL */
493
        break;
494
    case 0x00000098:
495
        /* REMQUEQ */
496
        break;
497
    case 0x00000099:
498
        /* REMQUEL/D */
499
        break;
500
    case 0x0000009A:
501
        /* REMQUEQ/D */
502
        break;
503
    case 0x0000009B:
504
        /* SWASTEN */
505
        break;
506
    case 0x0000009C:
507
        /* WR_PS_SW */
508
        break;
509
    case 0x0000009D:
510
        /* RSCC */
511
        break;
512
    case 0x0000009E:
513
        /* READ_UNQ */
514
        /* REQUIRED */
515
        break;
516
    case 0x0000009F:
517
        /* WRITE_UNQ */
518
        /* REQUIRED */
519
        break;
520
    case 0x000000A0:
521
        /* AMOVRR */
522
        break;
523
    case 0x000000A1:
524
        /* AMOVRM */
525
        break;
526
    case 0x000000A2:
527
        /* INSQHILR */
528
        break;
529
    case 0x000000A3:
530
        /* INSQTILR */
531
        break;
532
    case 0x000000A4:
533
        /* INSQHIQR */
534
        break;
535
    case 0x000000A5:
536
        /* INSQTIQR */
537
        break;
538
    case 0x000000A6:
539
        /* REMQHILR */
540
        break;
541
    case 0x000000A7:
542
        /* REMQTILR */
543
        break;
544
    case 0x000000A8:
545
        /* REMQHIQR */
546
        break;
547
    case 0x000000A9:
548
        /* REMQTIQR */
549
        break;
550
    case 0x000000AA:
551
        /* GENTRAP */
552
        /* REQUIRED */
553
        break;
554
    case 0x000000AE:
555
        /* CLRFEN */
556
        break;
557
    default:
558
        break;
559
    }
560
}
561

    
562
static void pal_unix_call (CPUState *env, uint32_t palcode)
563
{
564
    uint64_t palid, val, oldval;
565

    
566
    if (palcode < 0x00000080) {
567
        /* Privileged palcodes */
568
        if (!(env->ps >> 3)) {
569
            /* TODO: generate privilege exception */
570
        }
571
    }
572
    switch (palcode) {
573
    case 0x00000000:
574
        /* HALT */
575
        /* REQUIRED */
576
        break;
577
    case 0x00000001:
578
        /* CFLUSH */
579
        break;
580
    case 0x00000002:
581
        /* DRAINA */
582
        /* REQUIRED */
583
        /* Implemented as no-op */
584
        break;
585
    case 0x00000009:
586
        /* CSERVE */
587
        /* REQUIRED */
588
        break;
589
    case 0x0000000A:
590
        /* SWPPAL */
591
        /* REQUIRED */
592
        palid = env->ir[16];
593
        do_swappal(env, palid);
594
        break;
595
    case 0x0000000D:
596
        /* WRIPIR */
597
        val = env->ir[16];
598
        if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
599
            env->ir[0] = val;
600
        break;
601
    case 0x00000010:
602
        /* RDMCES */
603
        if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
604
            env->ir[0] = val;
605
        break;
606
    case 0x00000011:
607
        /* WRMCES */
608
        val = env->ir[16];
609
        if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
610
            env->ir[0] = val;
611
        break;
612
    case 0x0000002B:
613
        /* WRFEN */
614
        val = env->ir[16];
615
        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
616
            env->ir[0] = val;
617
        break;
618
    case 0x0000002D:
619
        /* WRVPTPTR */
620
        break;
621
    case 0x00000030:
622
        /* SWPCTX */
623
        break;
624
    case 0x00000031:
625
        /* WRVAL */
626
        break;
627
    case 0x00000032:
628
        /* RDVAL */
629
        break;
630
    case 0x00000033:
631
        /* TBI */
632
        val = env->ir[16];
633
        if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
634
            env->ir[0] = val;
635
        break;
636
    case 0x00000034:
637
        /* WRENT */
638
        break;
639
    case 0x00000035:
640
        /* SWPIPL */
641
        break;
642
    case 0x00000036:
643
        /* RDPS */
644
        break;
645
    case 0x00000037:
646
        /* WRKGP */
647
        break;
648
    case 0x00000038:
649
        /* WRUSP */
650
        val = env->ir[16];
651
        if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
652
            env->ir[0] = val;
653
        break;
654
    case 0x00000039:
655
        /* WRPERFMON */
656
        val = env->ir[16];
657
        if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
658
            env->ir[0] = val;
659
        break;
660
    case 0x0000003A:
661
        /* RDUSP */
662
        if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
663
            env->ir[0] = val;
664
        break;
665
    case 0x0000003C:
666
        /* WHAMI */
667
        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
668
            env->ir[0] = val;
669
        break;
670
    case 0x0000003D:
671
        /* RETSYS */
672
        break;
673
    case 0x0000003E:
674
        /* WTINT */
675
        break;
676
    case 0x0000003F:
677
        /* RTI */
678
        if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
679
            env->ir[0] = val;
680
        break;
681
    case 0x00000080:
682
        /* BPT */
683
        /* REQUIRED */
684
        break;
685
    case 0x00000081:
686
        /* BUGCHK */
687
        /* REQUIRED */
688
        break;
689
    case 0x00000083:
690
        /* CALLSYS */
691
        break;
692
    case 0x00000086:
693
        /* IMB */
694
        /* REQUIRED */
695
        /* Implemented as no-op */
696
        break;
697
    case 0x00000092:
698
        /* URTI */
699
        break;
700
    case 0x0000009E:
701
        /* RDUNIQUE */
702
        /* REQUIRED */
703
        break;
704
    case 0x0000009F:
705
        /* WRUNIQUE */
706
        /* REQUIRED */
707
        break;
708
    case 0x000000AA:
709
        /* GENTRAP */
710
        /* REQUIRED */
711
        break;
712
    case 0x000000AE:
713
        /* CLRFEN */
714
        break;
715
    default:
716
        break;
717
    }
718
}
719

    
720
void call_pal (CPUState *env)
721
{
722
    pal_handler_t *pal_handler = env->pal_handler;
723

    
724
    switch (env->exception_index) {
725
    case EXCP_RESET:
726
        (*pal_handler->reset)(env);
727
        break;
728
    case EXCP_MCHK:
729
        (*pal_handler->machine_check)(env);
730
        break;
731
    case EXCP_ARITH:
732
        (*pal_handler->arithmetic)(env);
733
        break;
734
    case EXCP_INTERRUPT:
735
        (*pal_handler->interrupt)(env);
736
        break;
737
    case EXCP_DFAULT:
738
        (*pal_handler->dfault)(env);
739
        break;
740
    case EXCP_DTB_MISS_PAL:
741
        (*pal_handler->dtb_miss_pal)(env);
742
        break;
743
    case EXCP_DTB_MISS_NATIVE:
744
        (*pal_handler->dtb_miss_native)(env);
745
        break;
746
    case EXCP_UNALIGN:
747
        (*pal_handler->unalign)(env);
748
        break;
749
    case EXCP_ITB_MISS:
750
        (*pal_handler->itb_miss)(env);
751
        break;
752
    case EXCP_ITB_ACV:
753
        (*pal_handler->itb_acv)(env);
754
        break;
755
    case EXCP_OPCDEC:
756
        (*pal_handler->opcdec)(env);
757
        break;
758
    case EXCP_FEN:
759
        (*pal_handler->fen)(env);
760
        break;
761
    default:
762
        if (env->exception_index >= EXCP_CALL_PAL &&
763
            env->exception_index < EXCP_CALL_PALP) {
764
            /* Unprivileged PAL call */
765
            (*pal_handler->call_pal)
766
                (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
767
        } else if (env->exception_index >= EXCP_CALL_PALP &&
768
                   env->exception_index < EXCP_CALL_PALE) {
769
            /* Privileged PAL call */
770
            (*pal_handler->call_pal)
771
                (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
772
        } else {
773
            /* Should never happen */
774
        }
775
        break;
776
    }
777
    env->ipr[IPR_EXC_ADDR] &= ~1;
778
}
779

    
780
void pal_init (CPUState *env)
781
{
782
    do_swappal(env, 0);
783
}
784

    
785
#if 0
786
static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
787
{
788
    uint64_t virbnd, ptbr;
789

790
    if ((env->features & FEATURE_VIRBND)) {
791
        cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
792
        if (vaddr >= virbnd)
793
            cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
794
        else
795
            cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
796
    } else {
797
        cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
798
    }
799

800
    return ptbr;
801
}
802

803
static int get_page_bits (CPUState *env)
804
{
805
    /* XXX */
806
    return 13;
807
}
808

809
static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
810
                    uint64_t ptebase, int page_bits, uint64_t level,
811
                    int mmu_idx, int rw)
812
{
813
    uint64_t pteaddr, pte, pfn;
814
    uint8_t gh;
815
    int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user;
816

817
    /* XXX: TOFIX */
818
    is_user = mmu_idx == MMU_USER_IDX;
819
    pteaddr = (ptebase << page_bits) + (8 * level);
820
    pte = ldq_raw(pteaddr);
821
    /* Decode all interresting PTE fields */
822
    pfn = pte >> 32;
823
    uwe = (pte >> 13) & 1;
824
    kwe = (pte >> 12) & 1;
825
    ure = (pte >> 9) & 1;
826
    kre = (pte >> 8) & 1;
827
    gh = (pte >> 5) & 3;
828
    foE = (pte >> 3) & 1;
829
    foW = (pte >> 2) & 1;
830
    foR = (pte >> 1) & 1;
831
    v = pte & 1;
832
    ret = 0;
833
    if (!v)
834
        ret = 0x1;
835
    /* Check access rights */
836
    ar = 0;
837
    if (is_user) {
838
        if (ure)
839
            ar |= PAGE_READ;
840
        if (uwe)
841
            ar |= PAGE_WRITE;
842
        if (rw == 1 && !uwe)
843
            ret |= 0x2;
844
        if (rw != 1 && !ure)
845
            ret |= 0x2;
846
    } else {
847
        if (kre)
848
            ar |= PAGE_READ;
849
        if (kwe)
850
            ar |= PAGE_WRITE;
851
        if (rw == 1 && !kwe)
852
            ret |= 0x2;
853
        if (rw != 1 && !kre)
854
            ret |= 0x2;
855
    }
856
    if (rw == 0 && foR)
857
        ret |= 0x4;
858
    if (rw == 2 && foE)
859
        ret |= 0x8;
860
    if (rw == 1 && foW)
861
        ret |= 0xC;
862
    *pfnp = pfn;
863
    if (zbitsp != NULL)
864
        *zbitsp = page_bits + (3 * gh);
865
    if (protp != NULL)
866
        *protp = ar;
867

868
    return ret;
869
}
870

871
static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
872
                           uint64_t ptebase, int page_bits,
873
                           uint64_t vaddr, int mmu_idx, int rw)
874
{
875
    uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
876
    int lvl_bits, ret;
877

878
    page_mask = (1ULL << page_bits) - 1ULL;
879
    lvl_bits = page_bits - 3;
880
    lvl_mask = (1ULL << lvl_bits) - 1ULL;
881
    level3 = (vaddr >> page_bits) & lvl_mask;
882
    level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
883
    level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
884
    /* Level 1 PTE */
885
    ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
886
    switch (ret) {
887
    case 3:
888
        /* Access violation */
889
        return 2;
890
    case 2:
891
        /* translation not valid */
892
        return 1;
893
    default:
894
        /* OK */
895
        break;
896
    }
897
    /* Level 2 PTE */
898
    ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
899
    switch (ret) {
900
    case 3:
901
        /* Access violation */
902
        return 2;
903
    case 2:
904
        /* translation not valid */
905
        return 1;
906
    default:
907
        /* OK */
908
        break;
909
    }
910
    /* Level 3 PTE */
911
    ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw);
912
    if (ret & 0x1) {
913
        /* Translation not valid */
914
        ret = 1;
915
    } else if (ret & 2) {
916
        /* Access violation */
917
        ret = 2;
918
    } else {
919
        switch (ret & 0xC) {
920
        case 0:
921
            /* OK */
922
            ret = 0;
923
            break;
924
        case 0x4:
925
            /* Fault on read */
926
            ret = 3;
927
            break;
928
        case 0x8:
929
            /* Fault on execute */
930
            ret = 4;
931
            break;
932
        case 0xC:
933
            /* Fault on write */
934
            ret = 5;
935
            break;
936
        }
937
    }
938
    *paddr = (pfn << page_bits) | (vaddr & page_mask);
939

940
    return 0;
941
}
942

943
static int virtual_to_physical (CPUState *env, uint64_t *physp,
944
                                int *zbitsp, int *protp,
945
                                uint64_t virtual, int mmu_idx, int rw)
946
{
947
    uint64_t sva, ptebase;
948
    int seg, page_bits, ret;
949

950
    sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
951
    if (sva != virtual)
952
        seg = -1;
953
    else
954
        seg = sva >> (VA_BITS - 2);
955
    virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
956
    ptebase = get_ptebase(env, virtual);
957
    page_bits = get_page_bits(env);
958
    ret = 0;
959
    switch (seg) {
960
    case 0:
961
        /* seg1: 3 levels of PTE */
962
        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
963
                             virtual, mmu_idx, rw);
964
        break;
965
    case 1:
966
        /* seg1: 2 levels of PTE */
967
        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
968
                             virtual, mmu_idx, rw);
969
        break;
970
    case 2:
971
        /* kernel segment */
972
        if (mmu_idx != 0) {
973
            ret = 2;
974
        } else {
975
            *physp = virtual;
976
        }
977
        break;
978
    case 3:
979
        /* seg1: TB mapped */
980
        ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
981
                             virtual, mmu_idx, rw);
982
        break;
983
    default:
984
        ret = 1;
985
        break;
986
    }
987

988
    return ret;
989
}
990

991
/* XXX: code provision */
992
int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
993
                              int mmu_idx, int is_softmmu)
994
{
995
    uint64_t physical, page_size, end;
996
    int prot, zbits, ret;
997

998
    ret = virtual_to_physical(env, &physical, &zbits, &prot,
999
                              address, mmu_idx, rw);
1000

1001
    switch (ret) {
1002
    case 0:
1003
        /* No fault */
1004
        page_size = 1ULL << zbits;
1005
        address &= ~(page_size - 1);
1006
        for (end = physical + page_size; physical < end; physical += 0x1000) {
1007
            ret = tlb_set_page(env, address, physical, prot,
1008
                               mmu_idx, is_softmmu);
1009
            address += 0x1000;
1010
        }
1011
        break;
1012
#if 0
1013
    case 1:
1014
        env->exception_index = EXCP_DFAULT;
1015
        env->ipr[IPR_EXC_ADDR] = address;
1016
        ret = 1;
1017
        break;
1018
    case 2:
1019
        env->exception_index = EXCP_ACCESS_VIOLATION;
1020
        env->ipr[IPR_EXC_ADDR] = address;
1021
        ret = 1;
1022
        break;
1023
    case 3:
1024
        env->exception_index = EXCP_FAULT_ON_READ;
1025
        env->ipr[IPR_EXC_ADDR] = address;
1026
        ret = 1;
1027
        break;
1028
    case 4:
1029
        env->exception_index = EXCP_FAULT_ON_EXECUTE;
1030
        env->ipr[IPR_EXC_ADDR] = address;
1031
        ret = 1;
1032
    case 5:
1033
        env->exception_index = EXCP_FAULT_ON_WRITE;
1034
        env->ipr[IPR_EXC_ADDR] = address;
1035
        ret = 1;
1036
#endif
1037
    default:
1038
        /* Should never happen */
1039
        env->exception_index = EXCP_MCHK;
1040
        env->ipr[IPR_EXC_ADDR] = address;
1041
        ret = 1;
1042
        break;
1043
    }
1044

    
1045
    return ret;
1046
}
1047
#endif