Commit 060366c5ad18b3e32886d8f7ce89c6cc23abb7ff
1 parent
6da41eaf
SPARC fixes : syscall fixes - added user register window exception support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@494 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
129 additions
and
21 deletions
linux-user/main.c
| @@ -299,27 +299,127 @@ void cpu_loop(CPUARMState *env) | @@ -299,27 +299,127 @@ void cpu_loop(CPUARMState *env) | ||
| 299 | 299 | ||
| 300 | #ifdef TARGET_SPARC | 300 | #ifdef TARGET_SPARC |
| 301 | 301 | ||
| 302 | +//#define DEBUG_WIN | ||
| 303 | + | ||
| 304 | +/* WARNING: dealing with register windows _is_ complicated */ | ||
| 305 | +static inline int get_reg_index(CPUSPARCState *env, int cwp, int index) | ||
| 306 | +{ | ||
| 307 | + index = (index + cwp * 16) & (16 * NWINDOWS - 1); | ||
| 308 | + /* wrap handling : if cwp is on the last window, then we use the | ||
| 309 | + registers 'after' the end */ | ||
| 310 | + if (index < 8 && env->cwp == (NWINDOWS - 1)) | ||
| 311 | + index += (16 * NWINDOWS); | ||
| 312 | + return index; | ||
| 313 | +} | ||
| 314 | + | ||
| 315 | +static inline void save_window_offset(CPUSPARCState *env, int offset) | ||
| 316 | +{ | ||
| 317 | + unsigned int new_wim, i, cwp1; | ||
| 318 | + uint32_t *sp_ptr; | ||
| 319 | + | ||
| 320 | + new_wim = ((env->wim >> 1) | (env->wim << (NWINDOWS - 1))) & | ||
| 321 | + ((1LL << NWINDOWS) - 1); | ||
| 322 | + /* save the window */ | ||
| 323 | + cwp1 = (env->cwp + offset) & (NWINDOWS - 1); | ||
| 324 | + sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); | ||
| 325 | +#if defined(DEBUG_WIN) | ||
| 326 | + printf("win_overflow: sp_ptr=0x%x save_cwp=%d\n", | ||
| 327 | + (int)sp_ptr, cwp1); | ||
| 328 | +#endif | ||
| 329 | + for(i = 0; i < 16; i++) | ||
| 330 | + stl_raw(sp_ptr + i, env->regbase[get_reg_index(env, cwp1, 8 + i)]); | ||
| 331 | + env->wim = new_wim; | ||
| 332 | +} | ||
| 333 | + | ||
| 334 | +static void save_window(CPUSPARCState *env) | ||
| 335 | +{ | ||
| 336 | + save_window_offset(env, 2); | ||
| 337 | +} | ||
| 338 | + | ||
| 339 | +static void restore_window(CPUSPARCState *env) | ||
| 340 | +{ | ||
| 341 | + unsigned int new_wim, i, cwp1; | ||
| 342 | + uint32_t *sp_ptr; | ||
| 343 | + | ||
| 344 | + new_wim = ((env->wim << 1) | (env->wim >> (NWINDOWS - 1))) & | ||
| 345 | + ((1LL << NWINDOWS) - 1); | ||
| 346 | + | ||
| 347 | + /* restore the invalid window */ | ||
| 348 | + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); | ||
| 349 | + sp_ptr = (uint32_t *)(env->regbase[get_reg_index(env, cwp1, 6)]); | ||
| 350 | +#if defined(DEBUG_WIN) | ||
| 351 | + printf("win_underflow: sp_ptr=0x%x load_cwp=%d\n", | ||
| 352 | + (int)sp_ptr, cwp1); | ||
| 353 | +#endif | ||
| 354 | + for(i = 0; i < 16; i++) | ||
| 355 | + env->regbase[get_reg_index(env, cwp1, 8 + i)] = ldl_raw(sp_ptr + i); | ||
| 356 | + env->wim = new_wim; | ||
| 357 | +} | ||
| 358 | + | ||
| 359 | +static void flush_windows(CPUSPARCState *env) | ||
| 360 | +{ | ||
| 361 | + int offset, cwp1; | ||
| 362 | +#if defined(DEBUG_WIN) | ||
| 363 | + printf("flush_windows:\n"); | ||
| 364 | +#endif | ||
| 365 | + offset = 2; | ||
| 366 | + for(;;) { | ||
| 367 | + /* if restore would invoke restore_window(), then we can stop */ | ||
| 368 | + cwp1 = (env->cwp + 1) & (NWINDOWS - 1); | ||
| 369 | + if (env->wim & (1 << cwp1)) | ||
| 370 | + break; | ||
| 371 | +#if defined(DEBUG_WIN) | ||
| 372 | + printf("offset=%d: ", offset); | ||
| 373 | +#endif | ||
| 374 | + save_window_offset(env, offset); | ||
| 375 | + offset++; | ||
| 376 | + } | ||
| 377 | +} | ||
| 378 | + | ||
| 302 | void cpu_loop (CPUSPARCState *env) | 379 | void cpu_loop (CPUSPARCState *env) |
| 303 | { | 380 | { |
| 304 | - int trapnr; | ||
| 305 | - | ||
| 306 | - while (1) { | ||
| 307 | - trapnr = cpu_sparc_exec (env); | ||
| 308 | - | ||
| 309 | - switch (trapnr) { | ||
| 310 | - case 0x8: case 0x10: | ||
| 311 | - env->regwptr[0] = do_syscall (env, env->gregs[1], | ||
| 312 | - env->regwptr[0], env->regwptr[1], env->regwptr[2], | ||
| 313 | - env->regwptr[3], env->regwptr[4], env->regwptr[13]); | ||
| 314 | - if (env->regwptr[0] >= 0xffffffe0) | ||
| 315 | - env->psr |= PSR_CARRY; | ||
| 316 | - break; | ||
| 317 | - default: | ||
| 318 | - printf ("Invalid trap: %d\n", trapnr); | ||
| 319 | - exit (1); | ||
| 320 | - } | ||
| 321 | - process_pending_signals (env); | ||
| 322 | - } | 381 | + int trapnr, ret; |
| 382 | + | ||
| 383 | + while (1) { | ||
| 384 | + trapnr = cpu_sparc_exec (env); | ||
| 385 | + | ||
| 386 | + switch (trapnr) { | ||
| 387 | + case 0x88: | ||
| 388 | + case 0x90: | ||
| 389 | + ret = do_syscall (env, env->gregs[1], | ||
| 390 | + env->regwptr[0], env->regwptr[1], | ||
| 391 | + env->regwptr[2], env->regwptr[3], | ||
| 392 | + env->regwptr[4], env->regwptr[5]); | ||
| 393 | + if ((unsigned int)ret >= (unsigned int)(-515)) { | ||
| 394 | + env->psr |= PSR_CARRY; | ||
| 395 | + ret = -ret; | ||
| 396 | + } else { | ||
| 397 | + env->psr &= ~PSR_CARRY; | ||
| 398 | + } | ||
| 399 | + env->regwptr[0] = ret; | ||
| 400 | + /* next instruction */ | ||
| 401 | + env->pc = env->npc; | ||
| 402 | + env->npc = env->npc + 4; | ||
| 403 | + break; | ||
| 404 | + case 0x83: /* flush windows */ | ||
| 405 | + // flush_windows(env); | ||
| 406 | + /* next instruction */ | ||
| 407 | + env->pc = env->npc; | ||
| 408 | + env->npc = env->npc + 4; | ||
| 409 | + break; | ||
| 410 | + case TT_WIN_OVF: /* window overflow */ | ||
| 411 | + save_window(env); | ||
| 412 | + break; | ||
| 413 | + case TT_WIN_UNF: /* window underflow */ | ||
| 414 | + restore_window(env); | ||
| 415 | + break; | ||
| 416 | + default: | ||
| 417 | + printf ("Unhandled trap: 0x%x\n", trapnr); | ||
| 418 | + cpu_sparc_dump_state(env, stderr, 0); | ||
| 419 | + exit (1); | ||
| 420 | + } | ||
| 421 | + process_pending_signals (env); | ||
| 422 | + } | ||
| 323 | } | 423 | } |
| 324 | 424 | ||
| 325 | #endif | 425 | #endif |
| @@ -636,8 +736,16 @@ int main(int argc, char **argv) | @@ -636,8 +736,16 @@ int main(int argc, char **argv) | ||
| 636 | env->cpsr = regs->uregs[16]; | 736 | env->cpsr = regs->uregs[16]; |
| 637 | } | 737 | } |
| 638 | #elif defined(TARGET_SPARC) | 738 | #elif defined(TARGET_SPARC) |
| 639 | - env->pc = regs->u_regs[0]; | ||
| 640 | - env->regwptr[6] = regs->u_regs[1]-0x40; | 739 | + { |
| 740 | + int i; | ||
| 741 | + env->pc = regs->pc; | ||
| 742 | + env->npc = regs->npc; | ||
| 743 | + env->y = regs->y; | ||
| 744 | + for(i = 0; i < 8; i++) | ||
| 745 | + env->gregs[i] = regs->u_regs[i]; | ||
| 746 | + for(i = 0; i < 8; i++) | ||
| 747 | + env->regwptr[i] = regs->u_regs[i + 8]; | ||
| 748 | + } | ||
| 641 | #elif defined(TARGET_PPC) | 749 | #elif defined(TARGET_PPC) |
| 642 | { | 750 | { |
| 643 | int i; | 751 | int i; |