diff mbox

target-mips: fix corner case in TLBWR causing QEMU to hang

Message ID 1442234628-15658-1-git-send-email-leon.alrae@imgtec.com
State New
Headers show

Commit Message

Leon Alrae Sept. 14, 2015, 12:43 p.m. UTC
cpu_mips_get_random() function is used to generate a random index from
CP0.Wired to TLBSize-1 range. Current implementation avoids generating
the same as before value, hence the while loop. If the guest sets
CP0.Wired to TLBSize-1 (which actually does not sound to be very
practical) QEMU will get stuck in the loop infinitely as we always
generate the same index.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 hw/mips/cputimer.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Comments

Aurelien Jarno Sept. 14, 2015, 7:21 p.m. UTC | #1
On 2015-09-14 13:43, Leon Alrae wrote:
> cpu_mips_get_random() function is used to generate a random index from
> CP0.Wired to TLBSize-1 range. Current implementation avoids generating
> the same as before value, hence the while loop. If the guest sets
> CP0.Wired to TLBSize-1 (which actually does not sound to be very
> practical) QEMU will get stuck in the loop infinitely as we always
> generate the same index.
> 
> Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
> ---
>  hw/mips/cputimer.c | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c
> index 577c9ae..c55d102 100644
> --- a/hw/mips/cputimer.c
> +++ b/hw/mips/cputimer.c
> @@ -33,10 +33,16 @@ uint32_t cpu_mips_get_random (CPUMIPSState *env)
>      static uint32_t lfsr = 1;
>      static uint32_t prev_idx = 0;
>      uint32_t idx;
> +    uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
> +
> +    if (nb_rand_tlb == 1) {
> +        return env->tlb->nb_tlb - 1;
> +    }
> +
>      /* Don't return same value twice, so get another value */
>      do {
>          lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
> -        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
> +        idx = lfsr % nb_rand_tlb + env->CP0_Wired;
>      } while (idx == prev_idx);
>      prev_idx = idx;
>      return idx;

Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>

Note that this patch conflicts with the following one, that we might
want to merge, even if the whole series is not ready:

https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg01171.html
Leon Alrae Sept. 15, 2015, 9:41 a.m. UTC | #2
On 14/09/15 20:21, Aurelien Jarno wrote:
> Note that this patch conflicts with the following one, that we might
> want to merge, even if the whole series is not ready:
> 
> https://lists.gnu.org/archive/html/qemu-devel/2015-07/msg01171.html

Indeed, we should merge that patch as well.

Thanks,
Leon
diff mbox

Patch

diff --git a/hw/mips/cputimer.c b/hw/mips/cputimer.c
index 577c9ae..c55d102 100644
--- a/hw/mips/cputimer.c
+++ b/hw/mips/cputimer.c
@@ -33,10 +33,16 @@  uint32_t cpu_mips_get_random (CPUMIPSState *env)
     static uint32_t lfsr = 1;
     static uint32_t prev_idx = 0;
     uint32_t idx;
+    uint32_t nb_rand_tlb = env->tlb->nb_tlb - env->CP0_Wired;
+
+    if (nb_rand_tlb == 1) {
+        return env->tlb->nb_tlb - 1;
+    }
+
     /* Don't return same value twice, so get another value */
     do {
         lfsr = (lfsr >> 1) ^ (-(lfsr & 1u) & 0xd0000001u);
-        idx = lfsr % (env->tlb->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
+        idx = lfsr % nb_rand_tlb + env->CP0_Wired;
     } while (idx == prev_idx);
     prev_idx = idx;
     return idx;