target/mips: Only update MVPControl.EVP bit if executed by master VPE

According to the 'MIPS MT Application-Specific Extension' manual:

  If the VPE executing the instruction is not a Master VPE,
  with the MVP bit of the VPEConf0 register set, the EVP bit
  is unchanged by the instruction.

Modify the DVPE/EVPE opcodes to only update the MVPControl.EVP bit
if executed on a master VPE.

Cc: qemu-stable@nongnu.org
Reported-by: Hansni Bu
Buglink: https://bugs.launchpad.net/qemu/+bug/1926277
Fixes: f249412c74 ("mips: Add MT halting and waking of VPEs")
Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Message-ID: <20210427133343.159718-1-f4bug@amsat.org>
Signed-off-by: Philippe Mathieu-Daudé <philmd@linaro.org>
This commit is contained in:
Philippe Mathieu-Daudé 2021-04-27 15:33:37 +02:00 committed by Philippe Mathieu-Daudé
parent c017386f28
commit e895095c78

View file

@ -1562,12 +1562,14 @@ target_ulong helper_dvpe(CPUMIPSState *env)
CPUState *other_cs = first_cpu;
target_ulong prev = env->mvp->CP0_MVPControl;
CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
/* Turn off all VPEs except the one executing the dvpe. */
if (&other_cpu->env != env) {
other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
mips_vpe_sleep(other_cpu);
if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
/* Turn off all VPEs except the one executing the dvpe. */
if (&other_cpu->env != env) {
other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
mips_vpe_sleep(other_cpu);
}
}
}
return prev;
@ -1578,15 +1580,17 @@ target_ulong helper_evpe(CPUMIPSState *env)
CPUState *other_cs = first_cpu;
target_ulong prev = env->mvp->CP0_MVPControl;
CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
if (env->CP0_VPEConf0 & (1 << CP0VPEC0_MVP)) {
CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
if (&other_cpu->env != env
/* If the VPE is WFI, don't disturb its sleep. */
&& !mips_vpe_is_wfi(other_cpu)) {
/* Enable the VPE. */
other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
mips_vpe_wake(other_cpu); /* And wake it up. */
if (&other_cpu->env != env
/* If the VPE is WFI, don't disturb its sleep. */
&& !mips_vpe_is_wfi(other_cpu)) {
/* Enable the VPE. */
other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
mips_vpe_wake(other_cpu); /* And wake it up. */
}
}
}
return prev;