On Mon, Aug 26, 2019 at 3:27 AM Laurent Vivier <laur...@vivier.eu> wrote: > > Le 26/08/2019 à 00:17, Max Filippov a écrit : > > Xtensa binaries built for call0 ABI don't rotate register window on > > function calls and returns. Invocation of signal handlers from the > > kernel is therefore different in windowed and call0 ABIs. > > There's currently no way to determine xtensa ELF binary ABI from the > > binary itself. Provide an environment variable QEMU_XTENSA_ABI_CALL0 and > > use it to initialize PS.WOE in xtensa_cpu_reset. Check this flag in > > setup_rt_frame to determine how a signal should be delivered. > > > > Signed-off-by: Max Filippov <jcmvb...@gmail.com> > > --- > > linux-user/xtensa/signal.c | 25 +++++++++++++++++-------- > > target/xtensa/cpu.c | 22 ++++++++++++++++++---- > > 2 files changed, 35 insertions(+), 12 deletions(-) > > > > diff --git a/linux-user/xtensa/signal.c b/linux-user/xtensa/signal.c > > index 8d54ef3ae34b..590f0313ffe9 100644 > > --- a/linux-user/xtensa/signal.c > > +++ b/linux-user/xtensa/signal.c > > @@ -134,6 +134,8 @@ void setup_rt_frame(int sig, struct target_sigaction > > *ka, > > abi_ulong frame_addr; > > struct target_rt_sigframe *frame; > > uint32_t ra; > > + bool abi_call0; > > + unsigned base; > > int i; > > > > frame_addr = get_sigframe(ka, env, sizeof(*frame)); > > @@ -182,20 +184,27 @@ void setup_rt_frame(int sig, struct target_sigaction > > *ka, > > __put_user(0x00, &frame->retcode[5]); > > #endif > > } > > - env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); > > - if (xtensa_option_enabled(env->config, > > XTENSA_OPTION_WINDOWED_REGISTER)) { > > - env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); > > - } > > memset(env->regs, 0, sizeof(env->regs)); > > env->pc = ka->_sa_handler; > > env->regs[1] = frame_addr; > > env->sregs[WINDOW_BASE] = 0; > > env->sregs[WINDOW_START] = 1; > > > > - env->regs[4] = (ra & 0x3fffffff) | 0x40000000; > > - env->regs[6] = sig; > > - env->regs[7] = frame_addr + offsetof(struct target_rt_sigframe, info); > > - env->regs[8] = frame_addr + offsetof(struct target_rt_sigframe, uc); > > + abi_call0 = (env->sregs[PS] & PS_WOE) == 0; > > Is this safe to rely on content of sregs[PS]?
It should be: PS is a privileged register, PS.WOE can only be changed explicitly and windowed registers are not supposed to work when PS.WOE is cleared. > Why don't you use xtensa_abi_call0()? I actually used it in early version of this change, but then decided that PS.WOE might be a better indicator for the call0 ABI. > > + env->sregs[PS] = PS_UM | (3 << PS_RING_SHIFT); > > + > > + if (abi_call0) { > > + base = 0; > > + env->regs[base] = ra; > > + } else { > > + env->sregs[PS] |= PS_WOE | (1 << PS_CALLINC_SHIFT); > > + base = 4; > > + env->regs[base] = (ra & 0x3fffffff) | 0x40000000; > > + } > > + env->regs[base + 2] = sig; > > + env->regs[base + 3] = frame_addr + offsetof(struct target_rt_sigframe, > > + info); > > + env->regs[base + 4] = frame_addr + offsetof(struct target_rt_sigframe, > > uc); > > unlock_user_struct(frame, frame_addr, 1); > > return; > > > > diff --git a/target/xtensa/cpu.c b/target/xtensa/cpu.c > > index 76db1741a796..791c061880e7 100644 > > --- a/target/xtensa/cpu.c > > +++ b/target/xtensa/cpu.c > > @@ -53,6 +53,18 @@ static bool xtensa_cpu_has_work(CPUState *cs) > > #endif > > } > > > > +#ifdef CONFIG_USER_ONLY > > +static int xtensa_abi_call0(void) > > +{ > > + static int abi_call0 = -1; > > + > > + if (abi_call0 == -1) { > > + abi_call0 = getenv("QEMU_XTENSA_ABI_CALL0") != NULL; > > Wouldn't it be cleaner to add this in the arg_table[] in > linux-user/main.c and then use directly the variable? Probably. Will do so in v2. -- Thanks. -- Max