e2k: Fix C++ exceptions for v5+.

v5+ has different procedure stack layout. Reading
the stack through the acees_hw_stacks syscall
requires to shuffle registers for a backward
compatibility with previous versions.

Signed-off-by: Denis Drakhnya <numas13@gmail.com>
This commit is contained in:
Denis Drakhnia 2021-03-12 00:21:06 +02:00 committed by Denis Drakhnia
parent 8f4de9d485
commit 401ccafc8c

View File

@ -7132,13 +7132,12 @@ exit:
return ret;
}
static abi_long copy_procedure_stack(abi_ulong dst, abi_ulong dst_tag, abi_ulong src,
abi_ulong size)
static abi_long copy_procedure_stack(CPUE2KState *env, abi_ulong dst,
abi_ulong dst_tag, abi_ulong src, abi_ulong size)
{
abi_ullong *from, *to;
uint8_t *to_tag = NULL;
abi_long ret = 0;
int i;
from = lock_user(VERIFY_READ, src, size, 1);
to = lock_user(VERIFY_WRITE, dst, size, 0);
@ -7158,8 +7157,26 @@ static abi_long copy_procedure_stack(abi_ulong dst, abi_ulong dst_tag, abi_ulong
memset(to_tag, 0, size / 8);
}
for (i = 0; i < size; i += sizeof(abi_ullong), to++, from++) {
*to = *from;
/* v5+ has different stack layout and we need to shuffle registers
* for backward compatibility. */
if (env->version >= 5) {
int i, j;
bool to_ps = dst >= env->psp.base
&& dst < (env->psp.base + env->psp.size);
i = ((to_ps ? dst : src) - env->psp.base) / sizeof(abi_ullong);
if (to_ps) {
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
to[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))] = from[j];
}
} else {
for (j = 0; j < size / sizeof(abi_ullong); j++, i++) {
to[j] = from[j + ((i & 3) == 1 ? 1 : ((i & 3) == 2 ? -1 : 0))];
}
}
} else {
memcpy(to, from, size);
}
exit:
@ -7286,7 +7303,7 @@ static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2,
dst_tag = env->psp.base_tag;
src = buf_addr;
}
ret = copy_procedure_stack(dst, dst_tag, src, used_size);
ret = copy_procedure_stack(env, dst, dst_tag, src, used_size);
break;
}
case READ_PROCEDURE_STACK_EX:
@ -7311,7 +7328,7 @@ static abi_long do_e2k_access_hw_stacks(CPUState *cpu, abi_ulong arg2,
dst_tag = env->psp.base_tag + offset / 8;
src = buf_addr;
}
ret = copy_procedure_stack(dst, dst_tag, src, buf_size);
ret = copy_procedure_stack(env, dst, dst_tag, src, buf_size);
break;
}
default: