]>
Commit | Line | Data |
---|---|---|
b82945bc JM |
1 | /* |
2 | * Alpha emulation - PALcode emulation for qemu. | |
5fafdf24 | 3 | * |
b82945bc JM |
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 | |
8167ee88 | 17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
b82945bc JM |
18 | */ |
19 | ||
20 | #include <stdint.h> | |
21 | #include <stdlib.h> | |
22 | #include <stdio.h> | |
23 | ||
b82945bc JM |
24 | #include "cpu.h" |
25 | #include "exec-all.h" | |
26 | ||
b82945bc JM |
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 | |
1235fc06 | 55 | /* One must explicitly check that the TB is valid and the FOE bit is reset */ |
3f47aa8c | 56 | static void update_itb (void) |
b82945bc JM |
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 */ | |
5fafdf24 | 62 | mtpr(ITB_PTE); |
b82945bc JM |
63 | } |
64 | ||
3f47aa8c | 65 | static void update_dtb (void); |
b82945bc JM |
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, | |
6ebbf390 | 811 | int mmu_idx, int rw) |
b82945bc JM |
812 | { |
813 | uint64_t pteaddr, pte, pfn; | |
814 | uint8_t gh; | |
6ebbf390 | 815 | int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user; |
b82945bc | 816 | |
6ebbf390 JM |
817 | /* XXX: TOFIX */ |
818 | is_user = mmu_idx == MMU_USER_IDX; | |
b82945bc JM |
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, | |
6ebbf390 | 873 | uint64_t vaddr, int mmu_idx, int rw) |
b82945bc JM |
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 */ | |
6ebbf390 | 911 | ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw); |
b82945bc JM |
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); | |
3b46e624 | 939 | |
b82945bc JM |
940 | return 0; |
941 | } | |
942 | ||
943 | static int virtual_to_physical (CPUState *env, uint64_t *physp, | |
944 | int *zbitsp, int *protp, | |
6ebbf390 | 945 | uint64_t virtual, int mmu_idx, int rw) |
b82945bc JM |
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, | |
6ebbf390 | 963 | virtual, mmu_idx, rw); |
b82945bc JM |
964 | break; |
965 | case 1: | |
966 | /* seg1: 2 levels of PTE */ | |
967 | ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, | |
6ebbf390 | 968 | virtual, mmu_idx, rw); |
b82945bc JM |
969 | break; |
970 | case 2: | |
971 | /* kernel segment */ | |
6ebbf390 | 972 | if (mmu_idx != 0) { |
b82945bc JM |
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, | |
6ebbf390 | 981 | virtual, mmu_idx, rw); |
b82945bc JM |
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, | |
6ebbf390 | 993 | int mmu_idx, int is_softmmu) |
b82945bc JM |
994 | { |
995 | uint64_t physical, page_size, end; | |
996 | int prot, zbits, ret; | |
997 | ||
6049f4f8 RH |
998 | ret = virtual_to_physical(env, &physical, &zbits, &prot, |
999 | address, mmu_idx, rw); | |
1000 | ||
b82945bc JM |
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, | |
6ebbf390 | 1008 | mmu_idx, is_softmmu); |
b82945bc JM |
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 |