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