Statistics
| Branch: | Revision:

root / hw / alpha_palcode.c @ fe57ca82

History | View | Annotate | Download (27.6 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 "qemu.h"
25
#include "cpu.h"
26
#include "exec-all.h"
27

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

802
    return ptbr;
803
}
804

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

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

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

870
    return ret;
871
}
872

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

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

942
    return 0;
943
}
944

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

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

990
    return ret;
991
}
992

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

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

    
1050
    return ret;
1051
}
1052
#endif
1053

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

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

    
1063
    switch (palcode) {
1064
    case 0x80:
1065
        /* BPT */
1066
        qemu_log("BPT\n");
1067
        /* FIXME: Sends SIGTRAP, si_code=TRAP_BRKPT.  */
1068
        exit(1);
1069
    case 0x81:
1070
        /* BUGCHK */
1071
        qemu_log("BUGCHK\n");
1072
        /* FIXME: Sends SIGTRAP, si_code=SI_FAULT.  */
1073
        exit(1);
1074
    case 0x83:
1075
        /* CALLSYS */
1076
        qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
1077
        ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
1078
                         env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
1079
                         env->ir[IR_A5]);
1080
        if (ret >= 0) {
1081
            env->ir[IR_A3] = 0;
1082
            env->ir[IR_V0] = ret;
1083
        } else {
1084
            env->ir[IR_A3] = 1;
1085
            env->ir[IR_V0] = -ret;
1086
        }
1087
        break;
1088
    case 0x86:
1089
        /* IMB */
1090
        qemu_log("IMB\n");
1091
        /* ??? We can probably elide the code using page_unprotect that is
1092
           checking for self-modifying code.  Instead we could simply call
1093
           tb_flush here.  Until we work out the changes required to turn
1094
           off the extra write protection, this can be a no-op.  */
1095
        break;
1096
    case 0x9E:
1097
        /* RDUNIQUE */
1098
        qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
1099
        /* Handled in the translator for usermode.  */
1100
        abort();
1101
    case 0x9F:
1102
        /* WRUNIQUE */
1103
        qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]);
1104
        /* Handled in the translator for usermode.  */
1105
        abort();
1106
    case 0xAA:
1107
        /* GENTRAP */
1108
        qemu_log("GENTRAP: " TARGET_FMT_lx "\n", env->ir[IR_A0]);
1109
        /* FIXME: This is supposed to send a signal:
1110
           SIGFPE:
1111
             GEN_INTOVF, GEN_INTDIV, GEN_FLTOVF, GEN_FLTDIV,
1112
             GEN_FLTUND, GEN_FLTINV, GEN_FLTINE, GEN_ROPRAND
1113
           SIGTRAP:
1114
             others
1115
           with various settings of si_code.  */
1116
        exit(1);
1117
    default:
1118
        qemu_log("%s: unhandled palcode %02x\n", __func__, palcode);
1119
        exit(1);
1120
    }
1121
}
1122
#endif