]>
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 | |
17 | * License along with this library; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include <stdint.h> | |
22 | #include <stdlib.h> | |
23 | #include <stdio.h> | |
24 | ||
25 | #include "qemu.h" | |
26 | #include "cpu.h" | |
27 | #include "exec-all.h" | |
28 | ||
29 | #if !defined (CONFIG_USER_ONLY) | |
30 | /* Shared handlers */ | |
31 | static void pal_reset (CPUState *env); | |
32 | /* Console handlers */ | |
33 | static void pal_console_call (CPUState *env, uint32_t palcode); | |
34 | /* OpenVMS handlers */ | |
35 | static void pal_openvms_call (CPUState *env, uint32_t palcode); | |
36 | /* UNIX / Linux handlers */ | |
37 | static void pal_unix_call (CPUState *env, uint32_t palcode); | |
38 | ||
39 | pal_handler_t pal_handlers[] = { | |
40 | /* Console handler */ | |
41 | { | |
42 | .reset = &pal_reset, | |
43 | .call_pal = &pal_console_call, | |
44 | }, | |
45 | /* OpenVMS handler */ | |
46 | { | |
47 | .reset = &pal_reset, | |
48 | .call_pal = &pal_openvms_call, | |
49 | }, | |
50 | /* UNIX / Linux handler */ | |
51 | { | |
52 | .reset = &pal_reset, | |
53 | .call_pal = &pal_unix_call, | |
54 | }, | |
55 | }; | |
56 | ||
57 | #if 0 | |
1235fc06 | 58 | /* One must explicitly check that the TB is valid and the FOE bit is reset */ |
3f47aa8c | 59 | static void update_itb (void) |
b82945bc JM |
60 | { |
61 | /* This writes into a temp register, not the actual one */ | |
62 | mtpr(TB_TAG); | |
63 | mtpr(TB_CTL); | |
64 | /* This commits the TB update */ | |
5fafdf24 | 65 | mtpr(ITB_PTE); |
b82945bc JM |
66 | } |
67 | ||
3f47aa8c | 68 | static void update_dtb (void); |
b82945bc JM |
69 | { |
70 | mtpr(TB_CTL); | |
71 | /* This write into a temp register, not the actual one */ | |
72 | mtpr(TB_TAG); | |
73 | /* This commits the TB update */ | |
74 | mtpr(DTB_PTE); | |
75 | } | |
76 | #endif | |
77 | ||
78 | static void pal_reset (CPUState *env) | |
79 | { | |
80 | } | |
81 | ||
82 | static void do_swappal (CPUState *env, uint64_t palid) | |
83 | { | |
84 | pal_handler_t *pal_handler; | |
85 | int status; | |
86 | ||
87 | status = 0; | |
88 | switch (palid) { | |
89 | case 0 ... 2: | |
90 | pal_handler = &pal_handlers[palid]; | |
91 | env->pal_handler = pal_handler; | |
92 | env->ipr[IPR_PAL_BASE] = -1ULL; | |
93 | (*pal_handler->reset)(env); | |
94 | break; | |
95 | case 3 ... 255: | |
96 | /* Unknown identifier */ | |
97 | env->ir[0] = 1; | |
98 | return; | |
99 | default: | |
100 | /* We were given the entry point address */ | |
101 | env->pal_handler = NULL; | |
102 | env->ipr[IPR_PAL_BASE] = palid; | |
103 | env->pc = env->ipr[IPR_PAL_BASE]; | |
104 | cpu_loop_exit(); | |
105 | } | |
106 | } | |
107 | ||
108 | static void pal_console_call (CPUState *env, uint32_t palcode) | |
109 | { | |
110 | uint64_t palid; | |
111 | ||
112 | if (palcode < 0x00000080) { | |
113 | /* Privileged palcodes */ | |
114 | if (!(env->ps >> 3)) { | |
115 | /* TODO: generate privilege exception */ | |
116 | } | |
117 | } | |
118 | switch (palcode) { | |
119 | case 0x00000000: | |
120 | /* HALT */ | |
121 | /* REQUIRED */ | |
122 | break; | |
123 | case 0x00000001: | |
124 | /* CFLUSH */ | |
125 | break; | |
126 | case 0x00000002: | |
127 | /* DRAINA */ | |
128 | /* REQUIRED */ | |
129 | /* Implemented as no-op */ | |
130 | break; | |
131 | case 0x00000009: | |
132 | /* CSERVE */ | |
133 | /* REQUIRED */ | |
134 | break; | |
135 | case 0x0000000A: | |
136 | /* SWPPAL */ | |
137 | /* REQUIRED */ | |
138 | palid = env->ir[16]; | |
139 | do_swappal(env, palid); | |
140 | break; | |
141 | case 0x00000080: | |
142 | /* BPT */ | |
143 | /* REQUIRED */ | |
144 | break; | |
145 | case 0x00000081: | |
146 | /* BUGCHK */ | |
147 | /* REQUIRED */ | |
148 | break; | |
149 | case 0x00000086: | |
150 | /* IMB */ | |
151 | /* REQUIRED */ | |
152 | /* Implemented as no-op */ | |
153 | break; | |
154 | case 0x0000009E: | |
155 | /* RDUNIQUE */ | |
156 | /* REQUIRED */ | |
157 | break; | |
158 | case 0x0000009F: | |
159 | /* WRUNIQUE */ | |
160 | /* REQUIRED */ | |
161 | break; | |
162 | case 0x000000AA: | |
163 | /* GENTRAP */ | |
164 | /* REQUIRED */ | |
165 | break; | |
166 | default: | |
167 | break; | |
168 | } | |
169 | } | |
170 | ||
171 | static void pal_openvms_call (CPUState *env, uint32_t palcode) | |
172 | { | |
173 | uint64_t palid, val, oldval; | |
174 | ||
175 | if (palcode < 0x00000080) { | |
176 | /* Privileged palcodes */ | |
177 | if (!(env->ps >> 3)) { | |
178 | /* TODO: generate privilege exception */ | |
179 | } | |
180 | } | |
181 | switch (palcode) { | |
182 | case 0x00000000: | |
183 | /* HALT */ | |
184 | /* REQUIRED */ | |
185 | break; | |
186 | case 0x00000001: | |
187 | /* CFLUSH */ | |
188 | break; | |
189 | case 0x00000002: | |
190 | /* DRAINA */ | |
191 | /* REQUIRED */ | |
192 | /* Implemented as no-op */ | |
193 | break; | |
194 | case 0x00000003: | |
195 | /* LDQP */ | |
196 | break; | |
197 | case 0x00000004: | |
198 | /* STQP */ | |
199 | break; | |
200 | case 0x00000005: | |
201 | /* SWPCTX */ | |
202 | break; | |
203 | case 0x00000006: | |
204 | /* MFPR_ASN */ | |
205 | if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0) | |
206 | env->ir[0] = val; | |
207 | break; | |
208 | case 0x00000007: | |
209 | /* MTPR_ASTEN */ | |
210 | val = env->ir[16]; | |
211 | if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1) | |
212 | env->ir[0] = val; | |
213 | break; | |
214 | case 0x00000008: | |
215 | /* MTPR_ASTSR */ | |
216 | val = env->ir[16]; | |
217 | if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1) | |
218 | env->ir[0] = val; | |
219 | break; | |
220 | case 0x00000009: | |
221 | /* CSERVE */ | |
222 | /* REQUIRED */ | |
223 | break; | |
224 | case 0x0000000A: | |
225 | /* SWPPAL */ | |
226 | /* REQUIRED */ | |
227 | palid = env->ir[16]; | |
228 | do_swappal(env, palid); | |
229 | break; | |
230 | case 0x0000000B: | |
231 | /* MFPR_FEN */ | |
232 | if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0) | |
233 | env->ir[0] = val; | |
234 | break; | |
235 | case 0x0000000C: | |
236 | /* MTPR_FEN */ | |
237 | val = env->ir[16]; | |
238 | if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1) | |
239 | env->ir[0] = val; | |
240 | break; | |
241 | case 0x0000000D: | |
242 | /* MTPR_IPIR */ | |
243 | val = env->ir[16]; | |
244 | if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) | |
245 | env->ir[0] = val; | |
246 | break; | |
247 | case 0x0000000E: | |
248 | /* MFPR_IPL */ | |
249 | if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0) | |
250 | env->ir[0] = val; | |
251 | break; | |
252 | case 0x0000000F: | |
253 | /* MTPR_IPL */ | |
254 | val = env->ir[16]; | |
255 | if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1) | |
256 | env->ir[0] = val; | |
257 | break; | |
258 | case 0x00000010: | |
259 | /* MFPR_MCES */ | |
260 | if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) | |
261 | env->ir[0] = val; | |
262 | break; | |
263 | case 0x00000011: | |
264 | /* MTPR_MCES */ | |
265 | val = env->ir[16]; | |
266 | if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) | |
267 | env->ir[0] = val; | |
268 | break; | |
269 | case 0x00000012: | |
270 | /* MFPR_PCBB */ | |
271 | if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0) | |
272 | env->ir[0] = val; | |
273 | break; | |
274 | case 0x00000013: | |
275 | /* MFPR_PRBR */ | |
276 | if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0) | |
277 | env->ir[0] = val; | |
278 | break; | |
279 | case 0x00000014: | |
280 | /* MTPR_PRBR */ | |
281 | val = env->ir[16]; | |
282 | if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1) | |
283 | env->ir[0] = val; | |
284 | break; | |
285 | case 0x00000015: | |
286 | /* MFPR_PTBR */ | |
287 | if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0) | |
288 | env->ir[0] = val; | |
289 | break; | |
290 | case 0x00000016: | |
291 | /* MFPR_SCBB */ | |
292 | if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0) | |
293 | env->ir[0] = val; | |
294 | break; | |
295 | case 0x00000017: | |
296 | /* MTPR_SCBB */ | |
297 | val = env->ir[16]; | |
298 | if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1) | |
299 | env->ir[0] = val; | |
300 | break; | |
301 | case 0x00000018: | |
302 | /* MTPR_SIRR */ | |
303 | val = env->ir[16]; | |
304 | if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1) | |
305 | env->ir[0] = val; | |
306 | break; | |
307 | case 0x00000019: | |
308 | /* MFPR_SISR */ | |
309 | if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0) | |
310 | env->ir[0] = val; | |
311 | break; | |
312 | case 0x0000001A: | |
313 | /* MFPR_TBCHK */ | |
314 | if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0) | |
315 | env->ir[0] = val; | |
316 | break; | |
317 | case 0x0000001B: | |
318 | /* MTPR_TBIA */ | |
319 | val = env->ir[16]; | |
320 | if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1) | |
321 | env->ir[0] = val; | |
322 | break; | |
323 | case 0x0000001C: | |
324 | /* MTPR_TBIAP */ | |
325 | val = env->ir[16]; | |
326 | if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1) | |
327 | env->ir[0] = val; | |
328 | break; | |
329 | case 0x0000001D: | |
330 | /* MTPR_TBIS */ | |
331 | val = env->ir[16]; | |
332 | if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) | |
333 | env->ir[0] = val; | |
334 | break; | |
335 | case 0x0000001E: | |
336 | /* MFPR_ESP */ | |
337 | if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0) | |
338 | env->ir[0] = val; | |
339 | break; | |
340 | case 0x0000001F: | |
341 | /* MTPR_ESP */ | |
342 | val = env->ir[16]; | |
343 | if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1) | |
344 | env->ir[0] = val; | |
345 | break; | |
346 | case 0x00000020: | |
347 | /* MFPR_SSP */ | |
348 | if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0) | |
349 | env->ir[0] = val; | |
350 | break; | |
351 | case 0x00000021: | |
352 | /* MTPR_SSP */ | |
353 | val = env->ir[16]; | |
354 | if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1) | |
355 | env->ir[0] = val; | |
356 | break; | |
357 | case 0x00000022: | |
358 | /* MFPR_USP */ | |
359 | if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) | |
360 | env->ir[0] = val; | |
361 | break; | |
362 | case 0x00000023: | |
363 | /* MTPR_USP */ | |
364 | val = env->ir[16]; | |
365 | if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) | |
366 | env->ir[0] = val; | |
367 | break; | |
368 | case 0x00000024: | |
369 | /* MTPR_TBISD */ | |
370 | val = env->ir[16]; | |
371 | if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1) | |
372 | env->ir[0] = val; | |
373 | break; | |
374 | case 0x00000025: | |
375 | /* MTPR_TBISI */ | |
376 | val = env->ir[16]; | |
377 | if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1) | |
378 | env->ir[0] = val; | |
379 | break; | |
380 | case 0x00000026: | |
381 | /* MFPR_ASTEN */ | |
382 | if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0) | |
383 | env->ir[0] = val; | |
384 | break; | |
385 | case 0x00000027: | |
386 | /* MFPR_ASTSR */ | |
387 | if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0) | |
388 | env->ir[0] = val; | |
389 | break; | |
390 | case 0x00000029: | |
391 | /* MFPR_VPTB */ | |
392 | if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0) | |
393 | env->ir[0] = val; | |
394 | break; | |
395 | case 0x0000002A: | |
396 | /* MTPR_VPTB */ | |
397 | val = env->ir[16]; | |
398 | if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1) | |
399 | env->ir[0] = val; | |
400 | break; | |
401 | case 0x0000002B: | |
402 | /* MTPR_PERFMON */ | |
403 | val = env->ir[16]; | |
404 | if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) | |
405 | env->ir[0] = val; | |
406 | break; | |
407 | case 0x0000002E: | |
408 | /* MTPR_DATFX */ | |
409 | val = env->ir[16]; | |
410 | if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1) | |
411 | env->ir[0] = val; | |
412 | break; | |
413 | case 0x0000003E: | |
414 | /* WTINT */ | |
415 | break; | |
416 | case 0x0000003F: | |
417 | /* MFPR_WHAMI */ | |
418 | if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) | |
419 | env->ir[0] = val; | |
420 | break; | |
421 | case 0x00000080: | |
422 | /* BPT */ | |
423 | /* REQUIRED */ | |
424 | break; | |
425 | case 0x00000081: | |
426 | /* BUGCHK */ | |
427 | /* REQUIRED */ | |
428 | break; | |
429 | case 0x00000082: | |
430 | /* CHME */ | |
431 | break; | |
432 | case 0x00000083: | |
433 | /* CHMK */ | |
434 | break; | |
435 | case 0x00000084: | |
436 | /* CHMS */ | |
437 | break; | |
438 | case 0x00000085: | |
439 | /* CHMU */ | |
440 | break; | |
441 | case 0x00000086: | |
442 | /* IMB */ | |
443 | /* REQUIRED */ | |
444 | /* Implemented as no-op */ | |
445 | break; | |
446 | case 0x00000087: | |
447 | /* INSQHIL */ | |
448 | break; | |
449 | case 0x00000088: | |
450 | /* INSQTIL */ | |
451 | break; | |
452 | case 0x00000089: | |
453 | /* INSQHIQ */ | |
454 | break; | |
455 | case 0x0000008A: | |
456 | /* INSQTIQ */ | |
457 | break; | |
458 | case 0x0000008B: | |
459 | /* INSQUEL */ | |
460 | break; | |
461 | case 0x0000008C: | |
462 | /* INSQUEQ */ | |
463 | break; | |
464 | case 0x0000008D: | |
465 | /* INSQUEL/D */ | |
466 | break; | |
467 | case 0x0000008E: | |
468 | /* INSQUEQ/D */ | |
469 | break; | |
470 | case 0x0000008F: | |
471 | /* PROBER */ | |
472 | break; | |
473 | case 0x00000090: | |
474 | /* PROBEW */ | |
475 | break; | |
476 | case 0x00000091: | |
477 | /* RD_PS */ | |
478 | break; | |
479 | case 0x00000092: | |
480 | /* REI */ | |
481 | break; | |
482 | case 0x00000093: | |
483 | /* REMQHIL */ | |
484 | break; | |
485 | case 0x00000094: | |
486 | /* REMQTIL */ | |
487 | break; | |
488 | case 0x00000095: | |
489 | /* REMQHIQ */ | |
490 | break; | |
491 | case 0x00000096: | |
492 | /* REMQTIQ */ | |
493 | break; | |
494 | case 0x00000097: | |
495 | /* REMQUEL */ | |
496 | break; | |
497 | case 0x00000098: | |
498 | /* REMQUEQ */ | |
499 | break; | |
500 | case 0x00000099: | |
501 | /* REMQUEL/D */ | |
502 | break; | |
503 | case 0x0000009A: | |
504 | /* REMQUEQ/D */ | |
505 | break; | |
506 | case 0x0000009B: | |
507 | /* SWASTEN */ | |
508 | break; | |
509 | case 0x0000009C: | |
510 | /* WR_PS_SW */ | |
511 | break; | |
512 | case 0x0000009D: | |
513 | /* RSCC */ | |
514 | break; | |
515 | case 0x0000009E: | |
516 | /* READ_UNQ */ | |
517 | /* REQUIRED */ | |
518 | break; | |
519 | case 0x0000009F: | |
520 | /* WRITE_UNQ */ | |
521 | /* REQUIRED */ | |
522 | break; | |
523 | case 0x000000A0: | |
524 | /* AMOVRR */ | |
525 | break; | |
526 | case 0x000000A1: | |
527 | /* AMOVRM */ | |
528 | break; | |
529 | case 0x000000A2: | |
530 | /* INSQHILR */ | |
531 | break; | |
532 | case 0x000000A3: | |
533 | /* INSQTILR */ | |
534 | break; | |
535 | case 0x000000A4: | |
536 | /* INSQHIQR */ | |
537 | break; | |
538 | case 0x000000A5: | |
539 | /* INSQTIQR */ | |
540 | break; | |
541 | case 0x000000A6: | |
542 | /* REMQHILR */ | |
543 | break; | |
544 | case 0x000000A7: | |
545 | /* REMQTILR */ | |
546 | break; | |
547 | case 0x000000A8: | |
548 | /* REMQHIQR */ | |
549 | break; | |
550 | case 0x000000A9: | |
551 | /* REMQTIQR */ | |
552 | break; | |
553 | case 0x000000AA: | |
554 | /* GENTRAP */ | |
555 | /* REQUIRED */ | |
556 | break; | |
557 | case 0x000000AE: | |
558 | /* CLRFEN */ | |
559 | break; | |
560 | default: | |
561 | break; | |
562 | } | |
563 | } | |
564 | ||
565 | static void pal_unix_call (CPUState *env, uint32_t palcode) | |
566 | { | |
567 | uint64_t palid, val, oldval; | |
568 | ||
569 | if (palcode < 0x00000080) { | |
570 | /* Privileged palcodes */ | |
571 | if (!(env->ps >> 3)) { | |
572 | /* TODO: generate privilege exception */ | |
573 | } | |
574 | } | |
575 | switch (palcode) { | |
576 | case 0x00000000: | |
577 | /* HALT */ | |
578 | /* REQUIRED */ | |
579 | break; | |
580 | case 0x00000001: | |
581 | /* CFLUSH */ | |
582 | break; | |
583 | case 0x00000002: | |
584 | /* DRAINA */ | |
585 | /* REQUIRED */ | |
586 | /* Implemented as no-op */ | |
587 | break; | |
588 | case 0x00000009: | |
589 | /* CSERVE */ | |
590 | /* REQUIRED */ | |
591 | break; | |
592 | case 0x0000000A: | |
593 | /* SWPPAL */ | |
594 | /* REQUIRED */ | |
595 | palid = env->ir[16]; | |
596 | do_swappal(env, palid); | |
597 | break; | |
598 | case 0x0000000D: | |
599 | /* WRIPIR */ | |
600 | val = env->ir[16]; | |
601 | if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1) | |
602 | env->ir[0] = val; | |
603 | break; | |
604 | case 0x00000010: | |
605 | /* RDMCES */ | |
606 | if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0) | |
607 | env->ir[0] = val; | |
608 | break; | |
609 | case 0x00000011: | |
610 | /* WRMCES */ | |
611 | val = env->ir[16]; | |
612 | if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1) | |
613 | env->ir[0] = val; | |
614 | break; | |
615 | case 0x0000002B: | |
616 | /* WRFEN */ | |
617 | val = env->ir[16]; | |
618 | if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) | |
619 | env->ir[0] = val; | |
620 | break; | |
621 | case 0x0000002D: | |
622 | /* WRVPTPTR */ | |
623 | break; | |
624 | case 0x00000030: | |
625 | /* SWPCTX */ | |
626 | break; | |
627 | case 0x00000031: | |
628 | /* WRVAL */ | |
629 | break; | |
630 | case 0x00000032: | |
631 | /* RDVAL */ | |
632 | break; | |
633 | case 0x00000033: | |
634 | /* TBI */ | |
635 | val = env->ir[16]; | |
636 | if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1) | |
637 | env->ir[0] = val; | |
638 | break; | |
639 | case 0x00000034: | |
640 | /* WRENT */ | |
641 | break; | |
642 | case 0x00000035: | |
643 | /* SWPIPL */ | |
644 | break; | |
645 | case 0x00000036: | |
646 | /* RDPS */ | |
647 | break; | |
648 | case 0x00000037: | |
649 | /* WRKGP */ | |
650 | break; | |
651 | case 0x00000038: | |
652 | /* WRUSP */ | |
653 | val = env->ir[16]; | |
654 | if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1) | |
655 | env->ir[0] = val; | |
656 | break; | |
657 | case 0x00000039: | |
658 | /* WRPERFMON */ | |
659 | val = env->ir[16]; | |
660 | if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1) | |
661 | env->ir[0] = val; | |
662 | break; | |
663 | case 0x0000003A: | |
664 | /* RDUSP */ | |
665 | if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0) | |
666 | env->ir[0] = val; | |
667 | break; | |
668 | case 0x0000003C: | |
669 | /* WHAMI */ | |
670 | if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) | |
671 | env->ir[0] = val; | |
672 | break; | |
673 | case 0x0000003D: | |
674 | /* RETSYS */ | |
675 | break; | |
676 | case 0x0000003E: | |
677 | /* WTINT */ | |
678 | break; | |
679 | case 0x0000003F: | |
680 | /* RTI */ | |
681 | if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0) | |
682 | env->ir[0] = val; | |
683 | break; | |
684 | case 0x00000080: | |
685 | /* BPT */ | |
686 | /* REQUIRED */ | |
687 | break; | |
688 | case 0x00000081: | |
689 | /* BUGCHK */ | |
690 | /* REQUIRED */ | |
691 | break; | |
692 | case 0x00000083: | |
693 | /* CALLSYS */ | |
694 | break; | |
695 | case 0x00000086: | |
696 | /* IMB */ | |
697 | /* REQUIRED */ | |
698 | /* Implemented as no-op */ | |
699 | break; | |
700 | case 0x00000092: | |
701 | /* URTI */ | |
702 | break; | |
703 | case 0x0000009E: | |
704 | /* RDUNIQUE */ | |
705 | /* REQUIRED */ | |
706 | break; | |
707 | case 0x0000009F: | |
708 | /* WRUNIQUE */ | |
709 | /* REQUIRED */ | |
710 | break; | |
711 | case 0x000000AA: | |
712 | /* GENTRAP */ | |
713 | /* REQUIRED */ | |
714 | break; | |
715 | case 0x000000AE: | |
716 | /* CLRFEN */ | |
717 | break; | |
718 | default: | |
719 | break; | |
720 | } | |
721 | } | |
722 | ||
723 | void call_pal (CPUState *env) | |
724 | { | |
725 | pal_handler_t *pal_handler = env->pal_handler; | |
726 | ||
727 | switch (env->exception_index) { | |
728 | case EXCP_RESET: | |
729 | (*pal_handler->reset)(env); | |
730 | break; | |
731 | case EXCP_MCHK: | |
732 | (*pal_handler->machine_check)(env); | |
733 | break; | |
734 | case EXCP_ARITH: | |
735 | (*pal_handler->arithmetic)(env); | |
736 | break; | |
737 | case EXCP_INTERRUPT: | |
738 | (*pal_handler->interrupt)(env); | |
739 | break; | |
740 | case EXCP_DFAULT: | |
741 | (*pal_handler->dfault)(env); | |
742 | break; | |
743 | case EXCP_DTB_MISS_PAL: | |
744 | (*pal_handler->dtb_miss_pal)(env); | |
745 | break; | |
746 | case EXCP_DTB_MISS_NATIVE: | |
747 | (*pal_handler->dtb_miss_native)(env); | |
748 | break; | |
749 | case EXCP_UNALIGN: | |
750 | (*pal_handler->unalign)(env); | |
751 | break; | |
752 | case EXCP_ITB_MISS: | |
753 | (*pal_handler->itb_miss)(env); | |
754 | break; | |
755 | case EXCP_ITB_ACV: | |
756 | (*pal_handler->itb_acv)(env); | |
757 | break; | |
758 | case EXCP_OPCDEC: | |
759 | (*pal_handler->opcdec)(env); | |
760 | break; | |
761 | case EXCP_FEN: | |
762 | (*pal_handler->fen)(env); | |
763 | break; | |
764 | default: | |
765 | if (env->exception_index >= EXCP_CALL_PAL && | |
766 | env->exception_index < EXCP_CALL_PALP) { | |
767 | /* Unprivileged PAL call */ | |
768 | (*pal_handler->call_pal) | |
769 | (env, (env->exception_index - EXCP_CALL_PAL) >> 6); | |
770 | } else if (env->exception_index >= EXCP_CALL_PALP && | |
771 | env->exception_index < EXCP_CALL_PALE) { | |
772 | /* Privileged PAL call */ | |
773 | (*pal_handler->call_pal) | |
774 | (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80); | |
775 | } else { | |
776 | /* Should never happen */ | |
777 | } | |
778 | break; | |
779 | } | |
780 | env->ipr[IPR_EXC_ADDR] &= ~1; | |
781 | } | |
782 | ||
783 | void pal_init (CPUState *env) | |
784 | { | |
785 | do_swappal(env, 0); | |
786 | } | |
787 | ||
788 | #if 0 | |
789 | static uint64_t get_ptebase (CPUState *env, uint64_t vaddr) | |
790 | { | |
791 | uint64_t virbnd, ptbr; | |
792 | ||
793 | if ((env->features & FEATURE_VIRBND)) { | |
794 | cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd); | |
795 | if (vaddr >= virbnd) | |
796 | cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr); | |
797 | else | |
798 | cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); | |
799 | } else { | |
800 | cpu_alpha_mfpr(env, IPR_PTBR, &ptbr); | |
801 | } | |
802 | ||
803 | return ptbr; | |
804 | } | |
805 | ||
806 | static int get_page_bits (CPUState *env) | |
807 | { | |
808 | /* XXX */ | |
809 | return 13; | |
810 | } | |
811 | ||
812 | static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp, | |
813 | uint64_t ptebase, int page_bits, uint64_t level, | |
6ebbf390 | 814 | int mmu_idx, int rw) |
b82945bc JM |
815 | { |
816 | uint64_t pteaddr, pte, pfn; | |
817 | uint8_t gh; | |
6ebbf390 | 818 | int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar, is_user; |
b82945bc | 819 | |
6ebbf390 JM |
820 | /* XXX: TOFIX */ |
821 | is_user = mmu_idx == MMU_USER_IDX; | |
b82945bc JM |
822 | pteaddr = (ptebase << page_bits) + (8 * level); |
823 | pte = ldq_raw(pteaddr); | |
824 | /* Decode all interresting PTE fields */ | |
825 | pfn = pte >> 32; | |
826 | uwe = (pte >> 13) & 1; | |
827 | kwe = (pte >> 12) & 1; | |
828 | ure = (pte >> 9) & 1; | |
829 | kre = (pte >> 8) & 1; | |
830 | gh = (pte >> 5) & 3; | |
831 | foE = (pte >> 3) & 1; | |
832 | foW = (pte >> 2) & 1; | |
833 | foR = (pte >> 1) & 1; | |
834 | v = pte & 1; | |
835 | ret = 0; | |
836 | if (!v) | |
837 | ret = 0x1; | |
838 | /* Check access rights */ | |
839 | ar = 0; | |
840 | if (is_user) { | |
841 | if (ure) | |
842 | ar |= PAGE_READ; | |
843 | if (uwe) | |
844 | ar |= PAGE_WRITE; | |
845 | if (rw == 1 && !uwe) | |
846 | ret |= 0x2; | |
847 | if (rw != 1 && !ure) | |
848 | ret |= 0x2; | |
849 | } else { | |
850 | if (kre) | |
851 | ar |= PAGE_READ; | |
852 | if (kwe) | |
853 | ar |= PAGE_WRITE; | |
854 | if (rw == 1 && !kwe) | |
855 | ret |= 0x2; | |
856 | if (rw != 1 && !kre) | |
857 | ret |= 0x2; | |
858 | } | |
859 | if (rw == 0 && foR) | |
860 | ret |= 0x4; | |
861 | if (rw == 2 && foE) | |
862 | ret |= 0x8; | |
863 | if (rw == 1 && foW) | |
864 | ret |= 0xC; | |
865 | *pfnp = pfn; | |
866 | if (zbitsp != NULL) | |
867 | *zbitsp = page_bits + (3 * gh); | |
868 | if (protp != NULL) | |
869 | *protp = ar; | |
870 | ||
871 | return ret; | |
872 | } | |
873 | ||
874 | static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot, | |
875 | uint64_t ptebase, int page_bits, | |
6ebbf390 | 876 | uint64_t vaddr, int mmu_idx, int rw) |
b82945bc JM |
877 | { |
878 | uint64_t pfn, page_mask, lvl_mask, level1, level2, level3; | |
879 | int lvl_bits, ret; | |
880 | ||
881 | page_mask = (1ULL << page_bits) - 1ULL; | |
882 | lvl_bits = page_bits - 3; | |
883 | lvl_mask = (1ULL << lvl_bits) - 1ULL; | |
884 | level3 = (vaddr >> page_bits) & lvl_mask; | |
885 | level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask; | |
886 | level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask; | |
887 | /* Level 1 PTE */ | |
888 | ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0); | |
889 | switch (ret) { | |
890 | case 3: | |
891 | /* Access violation */ | |
892 | return 2; | |
893 | case 2: | |
894 | /* translation not valid */ | |
895 | return 1; | |
896 | default: | |
897 | /* OK */ | |
898 | break; | |
899 | } | |
900 | /* Level 2 PTE */ | |
901 | ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0); | |
902 | switch (ret) { | |
903 | case 3: | |
904 | /* Access violation */ | |
905 | return 2; | |
906 | case 2: | |
907 | /* translation not valid */ | |
908 | return 1; | |
909 | default: | |
910 | /* OK */ | |
911 | break; | |
912 | } | |
913 | /* Level 3 PTE */ | |
6ebbf390 | 914 | ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, mmu_idx, rw); |
b82945bc JM |
915 | if (ret & 0x1) { |
916 | /* Translation not valid */ | |
917 | ret = 1; | |
918 | } else if (ret & 2) { | |
919 | /* Access violation */ | |
920 | ret = 2; | |
921 | } else { | |
922 | switch (ret & 0xC) { | |
923 | case 0: | |
924 | /* OK */ | |
925 | ret = 0; | |
926 | break; | |
927 | case 0x4: | |
928 | /* Fault on read */ | |
929 | ret = 3; | |
930 | break; | |
931 | case 0x8: | |
932 | /* Fault on execute */ | |
933 | ret = 4; | |
934 | break; | |
935 | case 0xC: | |
936 | /* Fault on write */ | |
937 | ret = 5; | |
938 | break; | |
939 | } | |
940 | } | |
941 | *paddr = (pfn << page_bits) | (vaddr & page_mask); | |
3b46e624 | 942 | |
b82945bc JM |
943 | return 0; |
944 | } | |
945 | ||
946 | static int virtual_to_physical (CPUState *env, uint64_t *physp, | |
947 | int *zbitsp, int *protp, | |
6ebbf390 | 948 | uint64_t virtual, int mmu_idx, int rw) |
b82945bc JM |
949 | { |
950 | uint64_t sva, ptebase; | |
951 | int seg, page_bits, ret; | |
952 | ||
953 | sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS); | |
954 | if (sva != virtual) | |
955 | seg = -1; | |
956 | else | |
957 | seg = sva >> (VA_BITS - 2); | |
958 | virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43)); | |
959 | ptebase = get_ptebase(env, virtual); | |
960 | page_bits = get_page_bits(env); | |
961 | ret = 0; | |
962 | switch (seg) { | |
963 | case 0: | |
964 | /* seg1: 3 levels of PTE */ | |
965 | ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, | |
6ebbf390 | 966 | virtual, mmu_idx, rw); |
b82945bc JM |
967 | break; |
968 | case 1: | |
969 | /* seg1: 2 levels of PTE */ | |
970 | ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, | |
6ebbf390 | 971 | virtual, mmu_idx, rw); |
b82945bc JM |
972 | break; |
973 | case 2: | |
974 | /* kernel segment */ | |
6ebbf390 | 975 | if (mmu_idx != 0) { |
b82945bc JM |
976 | ret = 2; |
977 | } else { | |
978 | *physp = virtual; | |
979 | } | |
980 | break; | |
981 | case 3: | |
982 | /* seg1: TB mapped */ | |
983 | ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits, | |
6ebbf390 | 984 | virtual, mmu_idx, rw); |
b82945bc JM |
985 | break; |
986 | default: | |
987 | ret = 1; | |
988 | break; | |
989 | } | |
990 | ||
991 | return ret; | |
992 | } | |
993 | ||
994 | /* XXX: code provision */ | |
995 | int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw, | |
6ebbf390 | 996 | int mmu_idx, int is_softmmu) |
b82945bc JM |
997 | { |
998 | uint64_t physical, page_size, end; | |
999 | int prot, zbits, ret; | |
1000 | ||
1001 | if (env->user_mode_only) { | |
1002 | ret = 2; | |
5fafdf24 | 1003 | } else { |
b82945bc | 1004 | ret = virtual_to_physical(env, &physical, &zbits, &prot, |
6ebbf390 | 1005 | address, mmu_idx, rw); |
b82945bc JM |
1006 | } |
1007 | switch (ret) { | |
1008 | case 0: | |
1009 | /* No fault */ | |
1010 | page_size = 1ULL << zbits; | |
1011 | address &= ~(page_size - 1); | |
1012 | for (end = physical + page_size; physical < end; physical += 0x1000) { | |
1013 | ret = tlb_set_page(env, address, physical, prot, | |
6ebbf390 | 1014 | mmu_idx, is_softmmu); |
b82945bc JM |
1015 | address += 0x1000; |
1016 | } | |
1017 | break; | |
1018 | #if 0 | |
1019 | case 1: | |
1020 | env->exception_index = EXCP_DFAULT; | |
1021 | env->ipr[IPR_EXC_ADDR] = address; | |
1022 | ret = 1; | |
1023 | break; | |
1024 | case 2: | |
1025 | env->exception_index = EXCP_ACCESS_VIOLATION; | |
1026 | env->ipr[IPR_EXC_ADDR] = address; | |
1027 | ret = 1; | |
1028 | break; | |
1029 | case 3: | |
1030 | env->exception_index = EXCP_FAULT_ON_READ; | |
1031 | env->ipr[IPR_EXC_ADDR] = address; | |
1032 | ret = 1; | |
1033 | break; | |
1034 | case 4: | |
1035 | env->exception_index = EXCP_FAULT_ON_EXECUTE; | |
1036 | env->ipr[IPR_EXC_ADDR] = address; | |
1037 | ret = 1; | |
1038 | case 5: | |
1039 | env->exception_index = EXCP_FAULT_ON_WRITE; | |
1040 | env->ipr[IPR_EXC_ADDR] = address; | |
1041 | ret = 1; | |
1042 | #endif | |
1043 | default: | |
1044 | /* Should never happen */ | |
1045 | env->exception_index = EXCP_MCHK; | |
1046 | env->ipr[IPR_EXC_ADDR] = address; | |
1047 | ret = 1; | |
1048 | break; | |
1049 | } | |
1050 | ||
1051 | return ret; | |
1052 | } | |
1053 | #endif | |
1054 | ||
1055 | #else /* !defined (CONFIG_USER_ONLY) */ | |
1056 | void pal_init (CPUState *env) | |
1057 | { | |
1058 | } | |
1059 | ||
1060 | void call_pal (CPUState *env, int palcode) | |
1061 | { | |
d9e147ad | 1062 | target_long ret; |
b82945bc | 1063 | |
b82945bc JM |
1064 | if (logfile != NULL) |
1065 | fprintf(logfile, "%s: palcode %02x\n", __func__, palcode); | |
1066 | switch (palcode) { | |
1067 | case 0x83: | |
1068 | /* CALLSYS */ | |
b82945bc JM |
1069 | if (logfile != NULL) |
1070 | fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]); | |
1071 | ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1], | |
1072 | env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4], | |
1073 | env->ir[IR_A5]); | |
d74e3b12 AJ |
1074 | if (ret >= 0) { |
1075 | env->ir[IR_A3] = 0; | |
1076 | env->ir[IR_V0] = ret; | |
b82945bc | 1077 | } else { |
d74e3b12 AJ |
1078 | env->ir[IR_A3] = 1; |
1079 | env->ir[IR_V0] = -ret; | |
b82945bc JM |
1080 | } |
1081 | break; | |
1082 | case 0x9E: | |
1083 | /* RDUNIQUE */ | |
1084 | env->ir[IR_V0] = env->unique; | |
c690524e AJ |
1085 | if (logfile != NULL) |
1086 | fprintf(logfile, "RDUNIQUE: " TARGET_FMT_lx "\n", env->unique); | |
b82945bc JM |
1087 | break; |
1088 | case 0x9F: | |
1089 | /* WRUNIQUE */ | |
1090 | env->unique = env->ir[IR_A0]; | |
c690524e AJ |
1091 | if (logfile != NULL) |
1092 | fprintf(logfile, "WRUNIQUE: " TARGET_FMT_lx "\n", env->unique); | |
b82945bc JM |
1093 | break; |
1094 | default: | |
b82945bc JM |
1095 | if (logfile != NULL) |
1096 | fprintf(logfile, "%s: unhandled palcode %02x\n", | |
1097 | __func__, palcode); | |
1098 | exit(1); | |
1099 | } | |
1100 | } | |
1101 | #endif |