mirror of https://gitee.com/openkylin/qemu.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)
|
||||
{
|
||||
const uint32_t nareg_mask = env->config->nareg - 1;
|
||||
uint32_t wb = env->sregs[WINDOW_BASE];
|
||||
uint32_t ws = (xtensa_replicate_windowstart(env) >> (wb + 1)) &
|
||||
((1 << env->config->nareg / 4) - 1);
|
||||
uint32_t d = ctz32(ws) + 1;
|
||||
uint32_t sp;
|
||||
abi_long ret = 0;
|
||||
uint32_t ws = xtensa_replicate_windowstart(env) >> (wb + 1);
|
||||
unsigned d = ctz32(ws) + 1;
|
||||
unsigned i;
|
||||
int ret = 0;
|
||||
|
||||
wb += d;
|
||||
ws >>= d;
|
||||
for (i = d; i < env->config->nareg / 4; i += d) {
|
||||
uint32_t ssp, osp;
|
||||
unsigned j;
|
||||
|
||||
xtensa_sync_phys_from_window(env);
|
||||
sp = env->phys_regs[(wb * 4 + 1) & nareg_mask];
|
||||
|
||||
while (ws && ret == 0) {
|
||||
int d;
|
||||
int i;
|
||||
int idx;
|
||||
ws >>= d;
|
||||
xtensa_rotate_window(env, d);
|
||||
|
||||
if (ws & 0x1) {
|
||||
ws >>= 1;
|
||||
ssp = env->regs[5];
|
||||
d = 1;
|
||||
} else if (ws & 0x2) {
|
||||
ws >>= 2;
|
||||
ssp = env->regs[9];
|
||||
ret |= get_user_ual(osp, env->regs[1] - 12);
|
||||
osp -= 32;
|
||||
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) {
|
||||
ws >>= 3;
|
||||
ssp = env->regs[13];
|
||||
ret |= get_user_ual(osp, env->regs[1] - 12);
|
||||
osp -= 48;
|
||||
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 {
|
||||
g_assert_not_reached();
|
||||
}
|
||||
sp = env->phys_regs[((wb + d) * 4 + 1) & nareg_mask];
|
||||
for (i = 0; i < 4; ++i) {
|
||||
idx = (wb * 4 + i) & nareg_mask;
|
||||
ret |= put_user_ual(env->phys_regs[idx], sp + (i - 4) * 4);
|
||||
|
||||
for (j = 0; j < 4; ++j) {
|
||||
ret |= put_user_ual(env->regs[j], ssp - 16 + j * 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue