Revision fbb4a2e3 linux-user/main.c
b/linux-user/main.c | ||
---|---|---|
365 | 365 |
} |
366 | 366 |
} |
367 | 367 |
|
368 |
/* Handle a jump to the kernel code page. */ |
|
369 |
static int |
|
370 |
do_kernel_trap(CPUARMState *env) |
|
371 |
{ |
|
372 |
uint32_t addr; |
|
373 |
uint32_t cpsr; |
|
374 |
uint32_t val; |
|
375 |
|
|
376 |
switch (env->regs[15]) { |
|
377 |
case 0xffff0fa0: /* __kernel_memory_barrier */ |
|
378 |
/* ??? No-op. Will need to do better for SMP. */ |
|
379 |
break; |
|
380 |
case 0xffff0fc0: /* __kernel_cmpxchg */ |
|
381 |
/* ??? This is not really atomic. However we don't support |
|
382 |
threads anyway, so it doesn't realy matter. */ |
|
383 |
cpsr = cpsr_read(env); |
|
384 |
addr = env->regs[2]; |
|
385 |
/* FIXME: This should SEGV if the access fails. */ |
|
386 |
if (get_user_u32(val, addr)) |
|
387 |
val = ~env->regs[0]; |
|
388 |
if (val == env->regs[0]) { |
|
389 |
val = env->regs[1]; |
|
390 |
/* FIXME: Check for segfaults. */ |
|
391 |
put_user_u32(val, addr); |
|
392 |
env->regs[0] = 0; |
|
393 |
cpsr |= CPSR_C; |
|
394 |
} else { |
|
395 |
env->regs[0] = -1; |
|
396 |
cpsr &= ~CPSR_C; |
|
397 |
} |
|
398 |
cpsr_write(env, cpsr, CPSR_C); |
|
399 |
break; |
|
400 |
case 0xffff0fe0: /* __kernel_get_tls */ |
|
401 |
env->regs[0] = env->cp15.c13_tls2; |
|
402 |
break; |
|
403 |
default: |
|
404 |
return 1; |
|
405 |
} |
|
406 |
/* Jump back to the caller. */ |
|
407 |
addr = env->regs[14]; |
|
408 |
if (addr & 1) { |
|
409 |
env->thumb = 1; |
|
410 |
addr &= ~1; |
|
411 |
} |
|
412 |
env->regs[15] = addr; |
|
413 |
|
|
414 |
return 0; |
|
415 |
} |
|
416 |
|
|
368 | 417 |
void cpu_loop(CPUARMState *env) |
369 | 418 |
{ |
370 | 419 |
int trapnr; |
... | ... | |
489 | 538 |
n -= ARM_SYSCALL_BASE; |
490 | 539 |
env->eabi = 0; |
491 | 540 |
} |
492 |
env->regs[0] = do_syscall(env, |
|
493 |
n, |
|
494 |
env->regs[0], |
|
495 |
env->regs[1], |
|
496 |
env->regs[2], |
|
497 |
env->regs[3], |
|
498 |
env->regs[4], |
|
499 |
env->regs[5]); |
|
541 |
if ( n > ARM_NR_BASE) { |
|
542 |
switch (n) { |
|
543 |
case ARM_NR_cacheflush: |
|
544 |
arm_cache_flush(env->regs[0], env->regs[1]); |
|
545 |
break; |
|
546 |
case ARM_NR_set_tls: |
|
547 |
cpu_set_tls(env, env->regs[0]); |
|
548 |
env->regs[0] = 0; |
|
549 |
break; |
|
550 |
default: |
|
551 |
gemu_log("qemu: Unsupported ARM syscall: 0x%x\n", |
|
552 |
n); |
|
553 |
env->regs[0] = -TARGET_ENOSYS; |
|
554 |
break; |
|
555 |
} |
|
556 |
} else { |
|
557 |
env->regs[0] = do_syscall(env, |
|
558 |
n, |
|
559 |
env->regs[0], |
|
560 |
env->regs[1], |
|
561 |
env->regs[2], |
|
562 |
env->regs[3], |
|
563 |
env->regs[4], |
|
564 |
env->regs[5]); |
|
565 |
} |
|
500 | 566 |
} else { |
501 | 567 |
goto error; |
502 | 568 |
} |
... | ... | |
535 | 601 |
} |
536 | 602 |
} |
537 | 603 |
break; |
604 |
case EXCP_KERNEL_TRAP: |
|
605 |
if (do_kernel_trap(env)) |
|
606 |
goto error; |
|
607 |
break; |
|
538 | 608 |
default: |
539 | 609 |
error: |
540 | 610 |
fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n", |
Also available in: Unified diff