Statistics
| Branch: | Revision:

root / hw / alpha_palcode.c @ 6ebbf390

History | View | Annotate | Download (27 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, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
 */
20

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

    
25
#include "qemu.h"
26
#include "cpu.h"
27
#include "exec-all.h"
28

    
29
#if !defined (CONFIG_USER_ONLY)
30
/* Shared handlers */
31
static void pal_reset (CPUState *env);
32
/* Console handlers */
33
static void pal_console_call (CPUState *env, uint32_t palcode);
34
/* OpenVMS handlers */
35
static void pal_openvms_call (CPUState *env, uint32_t palcode);
36
/* UNIX / Linux handlers */
37
static void pal_unix_call (CPUState *env, uint32_t palcode);
38

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

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

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

    
78
static void pal_reset (CPUState *env)
79
{
80
}
81

    
82
static void do_swappal (CPUState *env, uint64_t palid)
83
{
84
    pal_handler_t *pal_handler;
85
    int status;
86

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

    
108
static void pal_console_call (CPUState *env, uint32_t palcode)
109
{
110
    uint64_t palid;
111

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

    
171
static void pal_openvms_call (CPUState *env, uint32_t palcode)
172
{
173
    uint64_t palid, val, oldval;
174

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

    
565
static void pal_unix_call (CPUState *env, uint32_t palcode)
566
{
567
    uint64_t palid, val, oldval;
568

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

    
723
void call_pal (CPUState *env)
724
{
725
    pal_handler_t *pal_handler = env->pal_handler;
726

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

    
783
void pal_init (CPUState *env)
784
{
785
    do_swappal(env, 0);
786
}
787

    
788
#if 0
789
static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
790
{
791
    uint64_t virbnd, ptbr;
792

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

803
    return ptbr;
804
}
805

806
static int get_page_bits (CPUState *env)
807
{
808
    /* XXX */
809
    return 13;
810
}
811

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

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

871
    return ret;
872
}
873

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

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

943
    return 0;
944
}
945

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

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

991
    return ret;
992
}
993

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

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

    
1051
    return ret;
1052
}
1053
#endif
1054

    
1055
#else /* !defined (CONFIG_USER_ONLY) */
1056
void pal_init (CPUState *env)
1057
{
1058
}
1059

    
1060
void call_pal (CPUState *env, int palcode)
1061
{
1062
    target_ulong ret;
1063

    
1064
    printf("%s: palcode %02x\n", __func__, palcode);
1065
    if (logfile != NULL)
1066
        fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
1067
    switch (palcode) {
1068
    case 0x83:
1069
        /* CALLSYS */
1070
        printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1071
        if (logfile != NULL)
1072
            fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1073
        ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1074
                         env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1075
                         env->ir[IR_A5]);
1076
        env->ir[IR_A3] = ret;
1077
        if (ret > (target_ulong)(-515)) {
1078
            env->ir[IR_V0] = 1;
1079
        } else {
1080
            env->ir[IR_V0] = 0;
1081
        }
1082
        break;
1083
    case 0x9E:
1084
        /* RDUNIQUE */
1085
        env->ir[IR_V0] = env->unique;
1086
        printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1087
        break;
1088
    case 0x9F:
1089
        /* WRUNIQUE */
1090
        env->unique = env->ir[IR_A0];
1091
        printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1092
        break;
1093
    default:
1094
        printf("%s: unhandled palcode %02x\n", __func__, palcode);
1095
        if (logfile != NULL)
1096
            fprintf(logfile, "%s: unhandled palcode %02x\n",
1097
                    __func__, palcode);
1098
        exit(1);
1099
    }
1100
}
1101
#endif