]>
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 | ||
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 | |
1235fc06 | 57 | /* One must explicitly check that the TB is valid and the FOE bit is reset */ |
3f47aa8c | 58 | static void update_itb (void) |
b82945bc JM |
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 */ | |
5fafdf24 | 64 | mtpr(ITB_PTE); |
b82945bc JM |
65 | } |
66 | ||
3f47aa8c | 67 | static void update_dtb (void); |
b82945bc JM |
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, | |
6ebbf390 | 813 | int mmu_idx, int rw) |
b82945bc JM |
814 | { |
815 | uint64_t pteaddr, pte, pfn; | |
816 | uint8_t gh; | |
6ebbf390 | 817 | int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user; |
b82945bc | 818 | |
6ebbf390 JM |
819 | /* XXX: TOFIX */ |
820 | is_user = mmu_idx == MMU_USER_IDX; | |
b82945bc JM |
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, | |
6ebbf390 | 875 | uint64_t vaddr, int mmu_idx, int rw) |
b82945bc JM |
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 */ | |
6ebbf390 | 913 | ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw); |
b82945bc JM |
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); | |
3b46e624 | 941 | |
b82945bc JM |
942 | return 0; |
943 | } | |
944 | ||
945 | static int virtual_to_physical (CPUState *env, uint64_t *physp, | |
946 | int *zbitsp, int *protp, | |
6ebbf390 | 947 | uint64_t virtual, int mmu_idx, int rw) |
b82945bc JM |
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, | |
6ebbf390 | 965 | virtual, mmu_idx, rw); |
b82945bc JM |
966 | break; |
967 | case 1: | |
968 | /* seg1: 2 levels of PTE */ | |
969 | ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, | |
6ebbf390 | 970 | virtual, mmu_idx, rw); |
b82945bc JM |
971 | break; |
972 | case 2: | |
973 | /* kernel segment */ | |
6ebbf390 | 974 | if (mmu_idx != 0) { |
b82945bc JM |
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, | |
6ebbf390 | 983 | virtual, mmu_idx, rw); |
b82945bc JM |
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, | |
6ebbf390 | 995 | int mmu_idx, int is_softmmu) |
b82945bc JM |
996 | { |
997 | uint64_t physical, page_size, end; | |
998 | int prot, zbits, ret; | |
999 | ||
f48c144e | 1000 | #if defined(CONFIG_USER_ONLY) |
b82945bc | 1001 | ret = 2; |
f48c144e | 1002 | #else |
b82945bc | 1003 | ret = virtual_to_physical(env, &physical, &zbits, &prot, |
6ebbf390 | 1004 | address, mmu_idx, rw); |
f48c144e | 1005 | #endif |
b82945bc JM |
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, | |
6ebbf390 | 1013 | mmu_idx, is_softmmu); |
b82945bc JM |
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 | { | |
d9e147ad | 1061 | target_long ret; |
b82945bc | 1062 | |
b82945bc | 1063 | switch (palcode) { |
fe57ca82 RH |
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); | |
b82945bc JM |
1074 | case 0x83: |
1075 | /* CALLSYS */ | |
93fcfe39 | 1076 | qemu_log("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); |
b82945bc JM |
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]); | |
d74e3b12 AJ |
1080 | if (ret >= 0) { |
1081 | env->ir[IR_A3] = 0; | |
1082 | env->ir[IR_V0] = ret; | |
b82945bc | 1083 | } else { |
d74e3b12 AJ |
1084 | env->ir[IR_A3] = 1; |
1085 | env->ir[IR_V0] = -ret; | |
b82945bc JM |
1086 | } |
1087 | break; | |
fe57ca82 RH |
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; | |
b82945bc JM |
1096 | case 0x9E: |
1097 | /* RDUNIQUE */ | |
93fcfe39 | 1098 | qemu_log("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); |
ab471ade RH |
1099 | /* Handled in the translator for usermode. */ |
1100 | abort(); | |
b82945bc JM |
1101 | case 0x9F: |
1102 | /* WRUNIQUE */ | |
ab471ade RH |
1103 | qemu_log("WRUNIQUE: " TARGET_FMT_lx "\n", env->ir[IR_A0]); |
1104 | /* Handled in the translator for usermode. */ | |
1105 | abort(); | |
fe57ca82 RH |
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); | |
b82945bc | 1117 | default: |
fe57ca82 | 1118 | qemu_log("%s: unhandled palcode %02x\n", __func__, palcode); |
b82945bc JM |
1119 | exit(1); |
1120 | } | |
1121 | } | |
1122 | #endif |