diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2018-03-17 14:15:03 +0000 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2018-03-17 14:15:03 +0000 |
commit | e1e44a9916b4318e943aecd669e096222cb3eaeb (patch) | |
tree | 050e13d8d06a2603be5a4cb9e4a599a6d4b28ba2 /linux-user/main.c | |
parent | 979454028cf93e5ef340569c616f477fa7c8630a (diff) | |
parent | b8105d2194f06ab8e3566467e8e3c582457424bb (diff) |
Merge remote-tracking branch 'remotes/xtensa/tags/20180316-xtensa' into staging
target/xtensa linux-user support.
- small cleanup for xtensa registers dumping (-d cpu);
- add support for debugging linux-user process with xtensa-linux-gdb
(as opposed to xtensa-elf-gdb), which can only access unprivileged
registers;
- enable MTTCG for target/xtensa;
- cleanup in linux-user/mmap area making sure that it works correctly
with limited 30-bit-wide user address space;
- import xtensa-specific definitions from the linux kernel,
conditionalize user-only/softmmu-only code and add handlers for
signals, exceptions, process/thread creation and core registers dumping.
# gpg: Signature made Fri 16 Mar 2018 16:46:19 GMT
# gpg: using RSA key 51F9CC91F83FA044
# gpg: Good signature from "Max Filippov <filippov@cadence.com>"
# gpg: aka "Max Filippov <max.filippov@cogentembedded.com>"
# gpg: aka "Max Filippov <jcmvbkbc@gmail.com>"
# Primary key fingerprint: 2B67 854B 98E5 327D CDEB 17D8 51F9 CC91 F83F A044
* remotes/xtensa/tags/20180316-xtensa:
MAINTAINERS: fix W: address for xtensa
qemu-binfmt-conf.sh: add qemu-xtensa
target/xtensa: add linux-user support
linux-user: drop unused target_msync function
linux-user: fix target_mprotect/target_munmap error return values
linux-user: fix assertion in shmdt
linux-user: fix mmap/munmap/mprotect/mremap/shmat
target/xtensa: support MTTCG
target/xtensa: use correct number of registers in gdbstub
target/xtensa: mark register windows in the dump
target/xtensa: dump correct physical registers
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
# Conflicts:
# linux-user/syscall.c
Diffstat (limited to 'linux-user/main.c')
-rw-r--r-- | linux-user/main.c | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/linux-user/main.c b/linux-user/main.c index 73aafcf1e0..108e1f202c 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -3841,6 +3841,242 @@ void cpu_loop(CPUHPPAState *env) #endif /* TARGET_HPPA */ +#ifdef TARGET_XTENSA + +static void xtensa_rfw(CPUXtensaState *env) +{ + xtensa_restore_owb(env); + env->pc = env->sregs[EPC1]; +} + +static void xtensa_rfwu(CPUXtensaState *env) +{ + env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]); + xtensa_rfw(env); +} + +static void xtensa_rfwo(CPUXtensaState *env) +{ + env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]); + xtensa_rfw(env); +} + +static void xtensa_overflow4(CPUXtensaState *env) +{ + put_user_ual(env->regs[0], env->regs[5] - 16); + put_user_ual(env->regs[1], env->regs[5] - 12); + put_user_ual(env->regs[2], env->regs[5] - 8); + put_user_ual(env->regs[3], env->regs[5] - 4); + xtensa_rfwo(env); +} + +static void xtensa_underflow4(CPUXtensaState *env) +{ + get_user_ual(env->regs[0], env->regs[5] - 16); + get_user_ual(env->regs[1], env->regs[5] - 12); + get_user_ual(env->regs[2], env->regs[5] - 8); + get_user_ual(env->regs[3], env->regs[5] - 4); + xtensa_rfwu(env); +} + +static void xtensa_overflow8(CPUXtensaState *env) +{ + put_user_ual(env->regs[0], env->regs[9] - 16); + get_user_ual(env->regs[0], env->regs[1] - 12); + put_user_ual(env->regs[1], env->regs[9] - 12); + put_user_ual(env->regs[2], env->regs[9] - 8); + put_user_ual(env->regs[3], env->regs[9] - 4); + put_user_ual(env->regs[4], env->regs[0] - 32); + put_user_ual(env->regs[5], env->regs[0] - 28); + put_user_ual(env->regs[6], env->regs[0] - 24); + put_user_ual(env->regs[7], env->regs[0] - 20); + xtensa_rfwo(env); +} + +static void xtensa_underflow8(CPUXtensaState *env) +{ + get_user_ual(env->regs[0], env->regs[9] - 16); + get_user_ual(env->regs[1], env->regs[9] - 12); + get_user_ual(env->regs[2], env->regs[9] - 8); + get_user_ual(env->regs[7], env->regs[1] - 12); + get_user_ual(env->regs[3], env->regs[9] - 4); + get_user_ual(env->regs[4], env->regs[7] - 32); + get_user_ual(env->regs[5], env->regs[7] - 28); + get_user_ual(env->regs[6], env->regs[7] - 24); + get_user_ual(env->regs[7], env->regs[7] - 20); + xtensa_rfwu(env); +} + +static void xtensa_overflow12(CPUXtensaState *env) +{ + put_user_ual(env->regs[0], env->regs[13] - 16); + get_user_ual(env->regs[0], env->regs[1] - 12); + put_user_ual(env->regs[1], env->regs[13] - 12); + put_user_ual(env->regs[2], env->regs[13] - 8); + put_user_ual(env->regs[3], env->regs[13] - 4); + put_user_ual(env->regs[4], env->regs[0] - 48); + put_user_ual(env->regs[5], env->regs[0] - 44); + put_user_ual(env->regs[6], env->regs[0] - 40); + put_user_ual(env->regs[7], env->regs[0] - 36); + put_user_ual(env->regs[8], env->regs[0] - 32); + put_user_ual(env->regs[9], env->regs[0] - 28); + put_user_ual(env->regs[10], env->regs[0] - 24); + put_user_ual(env->regs[11], env->regs[0] - 20); + xtensa_rfwo(env); +} + +static void xtensa_underflow12(CPUXtensaState *env) +{ + get_user_ual(env->regs[0], env->regs[13] - 16); + get_user_ual(env->regs[1], env->regs[13] - 12); + get_user_ual(env->regs[2], env->regs[13] - 8); + get_user_ual(env->regs[11], env->regs[1] - 12); + get_user_ual(env->regs[3], env->regs[13] - 4); + get_user_ual(env->regs[4], env->regs[11] - 48); + get_user_ual(env->regs[5], env->regs[11] - 44); + get_user_ual(env->regs[6], env->regs[11] - 40); + get_user_ual(env->regs[7], env->regs[11] - 36); + get_user_ual(env->regs[8], env->regs[11] - 32); + get_user_ual(env->regs[9], env->regs[11] - 28); + get_user_ual(env->regs[10], env->regs[11] - 24); + get_user_ual(env->regs[11], env->regs[11] - 20); + xtensa_rfwu(env); +} + +void cpu_loop(CPUXtensaState *env) +{ + CPUState *cs = CPU(xtensa_env_get_cpu(env)); + target_siginfo_t info; + abi_ulong ret; + int trapnr; + + while (1) { + cpu_exec_start(cs); + trapnr = cpu_exec(cs); + cpu_exec_end(cs); + process_queued_cpu_work(cs); + + env->sregs[PS] &= ~PS_EXCM; + switch (trapnr) { + case EXCP_INTERRUPT: + break; + + case EXC_WINDOW_OVERFLOW4: + xtensa_overflow4(env); + break; + case EXC_WINDOW_UNDERFLOW4: + xtensa_underflow4(env); + break; + case EXC_WINDOW_OVERFLOW8: + xtensa_overflow8(env); + break; + case EXC_WINDOW_UNDERFLOW8: + xtensa_underflow8(env); + break; + case EXC_WINDOW_OVERFLOW12: + xtensa_overflow12(env); + break; + case EXC_WINDOW_UNDERFLOW12: + xtensa_underflow12(env); + break; + + case EXC_USER: + switch (env->sregs[EXCCAUSE]) { + case ILLEGAL_INSTRUCTION_CAUSE: + case PRIVILEGED_CAUSE: + info.si_signo = TARGET_SIGILL; + info.si_errno = 0; + info.si_code = + env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ? + TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC; + info._sifields._sigfault._addr = env->sregs[EPC1]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + + case SYSCALL_CAUSE: + env->pc += 3; + ret = do_syscall(env, env->regs[2], + env->regs[6], env->regs[3], + env->regs[4], env->regs[5], + env->regs[8], env->regs[9], 0, 0); + switch (ret) { + default: + env->regs[2] = ret; + break; + + case -TARGET_ERESTARTSYS: + case -TARGET_QEMU_ESIGRETURN: + break; + } + break; + + case ALLOCA_CAUSE: + env->sregs[PS] = deposit32(env->sregs[PS], + PS_OWB_SHIFT, + PS_OWB_LEN, + env->sregs[WINDOW_BASE]); + + switch (env->regs[0] & 0xc0000000) { + case 0x00000000: + case 0x40000000: + xtensa_rotate_window(env, -1); + xtensa_underflow4(env); + break; + + case 0x80000000: + xtensa_rotate_window(env, -2); + xtensa_underflow8(env); + break; + + case 0xc0000000: + xtensa_rotate_window(env, -3); + xtensa_underflow12(env); + break; + } + break; + + case INTEGER_DIVIDE_BY_ZERO_CAUSE: + info.si_signo = TARGET_SIGFPE; + info.si_errno = 0; + info.si_code = TARGET_FPE_INTDIV; + info._sifields._sigfault._addr = env->sregs[EPC1]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + + case LOAD_PROHIBITED_CAUSE: + case STORE_PROHIBITED_CAUSE: + info.si_signo = TARGET_SIGSEGV; + info.si_errno = 0; + info.si_code = TARGET_SEGV_ACCERR; + info._sifields._sigfault._addr = env->sregs[EXCVADDR]; + queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info); + break; + + default: + fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]); + g_assert_not_reached(); + } + break; + case EXCP_DEBUG: + trapnr = gdb_handlesig(cs, TARGET_SIGTRAP); + if (trapnr) { + info.si_signo = trapnr; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, trapnr, QEMU_SI_FAULT, &info); + } + break; + case EXC_DEBUG: + default: + fprintf(stderr, "trapnr = %d\n", trapnr); + g_assert_not_reached(); + } + process_pending_signals(env); + } +} + +#endif /* TARGET_XTENSA */ + __thread CPUState *thread_cpu; bool qemu_cpu_is_self(CPUState *cpu) @@ -4873,6 +5109,15 @@ int main(int argc, char **argv, char **envp) env->iaoq_f = regs->iaoq[0]; env->iaoq_b = regs->iaoq[1]; } +#elif defined(TARGET_XTENSA) + { + int i; + for (i = 0; i < 16; ++i) { + env->regs[i] = regs->areg[i]; + } + env->sregs[WINDOW_START] = regs->windowstart; + env->pc = regs->pc; + } #else #error unsupported target CPU #endif |