mirror of https://github.com/xqemu/xqemu.git
target/xtensa: fix flush_window_regs
flush_window_regs uses wrong stack frame to save overflow registers in call8 and call12 frames, which results in wrong register values in callers of a function that received a signal. Reimplement flush_window_regs closely following window overflow sequence. Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
This commit is contained in:
parent
dfe732fb68
commit
20ef667060
|
@ -7094,52 +7094,45 @@ static abi_ulong get_sigframe(struct target_sigaction *sa,
|
||||||
|
|
||||||
static int flush_window_regs(CPUXtensaState *env)
|
static int flush_window_regs(CPUXtensaState *env)
|
||||||
{
|
{
|
||||||
const uint32_t nareg_mask = env->config->nareg - 1;
|
|
||||||
uint32_t wb = env->sregs[WINDOW_BASE];
|
uint32_t wb = env->sregs[WINDOW_BASE];
|
||||||
uint32_t ws = (xtensa_replicate_windowstart(env) >> (wb + 1)) &
|
uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
|
||||||
((1 << env->config->nareg / 4) - 1);
|
unsigned d = ctz32(ws) + 1;
|
||||||
uint32_t d = ctz32(ws) + 1;
|
unsigned i;
|
||||||
uint32_t sp;
|
int ret = 0;
|
||||||
abi_long ret = 0;
|
|
||||||
|
|
||||||
wb += d;
|
for (i = d; i < env->config->nareg / 4; i += d) {
|
||||||
ws >>= d;
|
uint32_t ssp, osp;
|
||||||
|
unsigned j;
|
||||||
|
|
||||||
xtensa_sync_phys_from_window(env);
|
ws >>= d;
|
||||||
sp = env->phys_regs[(wb * 4 + 1) & nareg_mask];
|
xtensa_rotate_window(env, d);
|
||||||
|
|
||||||
while (ws && ret == 0) {
|
|
||||||
int d;
|
|
||||||
int i;
|
|
||||||
int idx;
|
|
||||||
|
|
||||||
if (ws & 0x1) {
|
if (ws & 0x1) {
|
||||||
ws >>= 1;
|
ssp = env->regs[5];
|
||||||
d = 1;
|
d = 1;
|
||||||
} else if (ws & 0x2) {
|
} else if (ws & 0x2) {
|
||||||
ws >>= 2;
|
ssp = env->regs[9];
|
||||||
|
ret |= get_user_ual(osp, env->regs[1] - 12);
|
||||||
|
osp -= 32;
|
||||||
d = 2;
|
d = 2;
|
||||||
for (i = 0; i < 4; ++i) {
|
|
||||||
idx = (wb * 4 + 4 + i) & nareg_mask;
|
|
||||||
ret |= put_user_ual(env->phys_regs[idx], sp + (i - 12) * 4);
|
|
||||||
}
|
|
||||||
} else if (ws & 0x4) {
|
} else if (ws & 0x4) {
|
||||||
ws >>= 3;
|
ssp = env->regs[13];
|
||||||
|
ret |= get_user_ual(osp, env->regs[1] - 12);
|
||||||
|
osp -= 48;
|
||||||
d = 3;
|
d = 3;
|
||||||
for (i = 0; i < 8; ++i) {
|
|
||||||
idx = (wb * 4 + 4 + i) & nareg_mask;
|
|
||||||
ret |= put_user_ual(env->phys_regs[idx], sp + (i - 16) * 4);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
sp = env->phys_regs[((wb + d) * 4 + 1) & nareg_mask];
|
|
||||||
for (i = 0; i < 4; ++i) {
|
for (j = 0; j < 4; ++j) {
|
||||||
idx = (wb * 4 + i) & nareg_mask;
|
ret |= put_user_ual(env->regs[j], ssp - 16 + j * 4);
|
||||||
ret |= put_user_ual(env->phys_regs[idx], sp + (i - 4) * 4);
|
}
|
||||||
|
for (j = 4; j < d * 4; ++j) {
|
||||||
|
ret |= put_user_ual(env->regs[j], osp - 16 + j * 4);
|
||||||
}
|
}
|
||||||
wb += d;
|
|
||||||
}
|
}
|
||||||
|
xtensa_rotate_window(env, d);
|
||||||
|
g_assert(env->sregs[WINDOW_BASE] == wb);
|
||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue