Commit 060366c5ad18b3e32886d8f7ce89c6cc23abb7ff

Authored by bellard
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 299  
300 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 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 425 #endif
... ... @@ -636,8 +736,16 @@ int main(int argc, char **argv)
636 736 env->cpsr = regs->uregs[16];
637 737 }
638 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 749 #elif defined(TARGET_PPC)
642 750 {
643 751 int i;
... ...