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 |