From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40495) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XgA4P-0007TM-8w for qemu-devel@nongnu.org; Mon, 20 Oct 2014 06:20:14 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1XgA4H-0006Xk-SJ for qemu-devel@nongnu.org; Mon, 20 Oct 2014 06:20:09 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:16988) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1XgA4H-0006SW-K9 for qemu-devel@nongnu.org; Mon, 20 Oct 2014 06:20:01 -0400 Message-ID: <5444E1CB.8000009@imgtec.com> Date: Mon, 20 Oct 2014 11:19:55 +0100 From: Yongbok Kim MIME-Version: 1.0 References: <1405354795-25884-1-git-send-email-leon.alrae@imgtec.com> <1405354795-25884-5-git-send-email-leon.alrae@imgtec.com> In-Reply-To: <1405354795-25884-5-git-send-email-leon.alrae@imgtec.com> Content-Type: multipart/alternative; boundary="------------020202030809020309020405" Subject: Re: [Qemu-devel] [PATCH 4/6] target-mips: add restrictions for possible values in registers List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Leon Alrae , "qemu-devel@nongnu.org" Cc: "aurelien@aurel32.net" --------------020202030809020309020405 Content-Type: text/plain; charset="windows-1252"; format=flowed Content-Transfer-Encoding: 7bit On 14/07/2014 17:19, Leon Alrae wrote: > In Release 6 not all the values are allowed to be written to a register. > If the value is not valid or unsupported then it should stay unchanged. > > For pre-R6 the existing behaviour has been changed only for CP0_Index register > as the current implementation does not seem to be correct - it looks like it > tries to limit the input value but the limit is higher than the actual > number of tlb entries. > > Signed-off-by: Leon Alrae > --- > target-mips/op_helper.c | 63 ++++++++++++++++++++++++++++++++++------------ > 1 files changed, 46 insertions(+), 17 deletions(-) > > diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c > index 431f3a1..4be435c 100644 > --- a/target-mips/op_helper.c > +++ b/target-mips/op_helper.c > @@ -959,14 +959,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) > > void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1) > { > - int num = 1; > - unsigned int tmp = env->tlb->nb_tlb; > - > - do { > - tmp >>= 1; > - num <<= 1; > - } while (tmp); > - env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1)); > + uint32_t index_p = env->CP0_Index & 0x80000000; > + uint32_t tlb_index = arg1 & 0x7fffffff; > + if (tlb_index < env->tlb->nb_tlb) { > + if (env->insn_flags & ISA_MIPS32R6) { > + index_p |= arg1 & 0x80000000; > + } > + env->CP0_Index = index_p | tlb_index; > + } Agree to restrict index for pre R6 as well. It is UNDEFINED and software shouldn't rely on the undefined behaviour. > } > > void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1) > @@ -1294,8 +1294,13 @@ void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) > > void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) > { > - /* 1k pages not implemented */ This comment is still valid but it is appeared several times in the code already. Agreed to remove the comment here. > - env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); > + uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1); > + if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) || > + (mask == 0x0000 || mask == 0x0003 || mask == 0x000F || > + mask == 0x003F || mask == 0x00FF || mask == 0x03FF || > + mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) { > + env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); > + } > } > > void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) > @@ -1309,7 +1314,13 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) > > void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) > { > - env->CP0_Wired = arg1 % env->tlb->nb_tlb; > + if (env->insn_flags & ISA_MIPS32R6) { > + if (arg1 < env->tlb->nb_tlb) { > + env->CP0_Wired = arg1; Wired field should be compared with Limit field (and as a result, number of entries in the TLB). > + } > + } else { > + env->CP0_Wired = arg1 % env->tlb->nb_tlb; > + } > } > > void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) > @@ -1368,11 +1379,14 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) > } > > /* 1k pages not implemented */ > - val = arg1 & mask; > #if defined(TARGET_MIPS64) > - val &= env->SEGMask; > + if ((env->insn_flags & ISA_MIPS32R6) && extract64(arg1, 62, 2) == 0x2) { > + mask &= ~(0x3ull << 62); If Config0_AT = 1, R field is restricted for 1 as well. > + } > + mask &= env->SEGMask; > #endif > old = env->CP0_EntryHi; > + val = (arg1 & mask) | (old & ~mask); > env->CP0_EntryHi = val; > if (env->CP0_Config3 & (1 << CP0C3_MT)) { > sync_c0_entryhi(env, env->current_tc); > @@ -1402,6 +1416,13 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) > uint32_t val, old; > uint32_t mask = env->CP0_Status_rw_bitmask; > > + if (env->insn_flags & ISA_MIPS32R6) { > + if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) { > + mask &= ~(3 << CP0St_KSU); > + } > + mask &= ~(0x00180000 & arg1); > + } > + > val = arg1 & mask; > old = env->CP0_Status; > env->CP0_Status = (env->CP0_Status & ~mask) | val; > @@ -1457,6 +1478,9 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) > if (cpu->insn_flags & ISA_MIPS32R2) { > mask |= 1 << CP0Ca_DC; > } > + if (cpu->insn_flags & ISA_MIPS32R6) { > + mask &= ~((1 << CP0Ca_WP) & arg1); > + } > > cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask); > > @@ -2381,8 +2405,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) > } > break; > case 25: > - if (arg1 & 0xffffff00) > + if (env->insn_flags & ISA_MIPS32R6 || arg1 & 0xffffff00) { > return; > + } > env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) | > ((arg1 & 0x1) << 23); > break; > @@ -2398,9 +2423,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt) > ((arg1 & 0x4) << 22); > break; > case 31: > - if (arg1 & 0x007c0000) > - return; > - env->active_fpu.fcr31 = arg1; > + if (env->insn_flags & ISA_MIPS32R6) { > + uint32_t mask = 0xfefc0000; > + env->active_fpu.fcr31 = (arg1 & ~mask) | > + (env->active_fpu.fcr31 & mask); > + } else if (!(arg1 & 0x007c0000)) { > + env->active_fpu.fcr31 = arg1; > + } > break; > default: > return; Regards, Yongbok --------------020202030809020309020405 Content-Type: text/html; charset="windows-1252" Content-Transfer-Encoding: 7bit
On 14/07/2014 17:19, Leon Alrae wrote:
In Release 6 not all the values are allowed to be written to a register.
If the value is not valid or unsupported then it should stay unchanged.

For pre-R6 the existing behaviour has been changed only for CP0_Index register
as the current implementation does not seem to be correct - it looks like it
tries to limit the input value but the limit is higher than the actual
number of tlb entries.

Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
---
 target-mips/op_helper.c |   63 ++++++++++++++++++++++++++++++++++------------
 1 files changed, 46 insertions(+), 17 deletions(-)

diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 431f3a1..4be435c 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -959,14 +959,14 @@ target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel)
 
 void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1)
 {
-    int num = 1;
-    unsigned int tmp = env->tlb->nb_tlb;
-
-    do {
-        tmp >>= 1;
-        num <<= 1;
-    } while (tmp);
-    env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1));
+    uint32_t index_p = env->CP0_Index & 0x80000000;
+    uint32_t tlb_index = arg1 & 0x7fffffff;
+    if (tlb_index < env->tlb->nb_tlb) {
+        if (env->insn_flags & ISA_MIPS32R6) {
+            index_p |= arg1 & 0x80000000;
+        }
+        env->CP0_Index = index_p | tlb_index;
+    }

Agree to restrict index for pre R6 as well. It is UNDEFINED and software shouldn't rely on the undefined behaviour.

 }
 
 void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1)
@@ -1294,8 +1294,13 @@ void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1)
 
 void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1)
 {
-    /* 1k pages not implemented */

This comment is still valid but it is appeared several times in the code already.
Agreed to remove the comment here.

-    env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
+    uint64_t mask = arg1 >> (TARGET_PAGE_BITS + 1);
+    if (!(env->insn_flags & ISA_MIPS32R6) || (arg1 == ~0) ||
+        (mask == 0x0000 || mask == 0x0003 || mask == 0x000F ||
+         mask == 0x003F || mask == 0x00FF || mask == 0x03FF ||
+         mask == 0x0FFF || mask == 0x3FFF || mask == 0xFFFF)) {
+        env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1));
+    }
 }
 
 void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
@@ -1309,7 +1314,13 @@ void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1)
 
 void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1)
 {
-    env->CP0_Wired = arg1 % env->tlb->nb_tlb;
+    if (env->insn_flags & ISA_MIPS32R6) {
+        if (arg1 < env->tlb->nb_tlb) {
+            env->CP0_Wired = arg1;

Wired field should be compared with Limit field (and as a result, number of entries in the TLB).

+        }
+    } else {
+        env->CP0_Wired = arg1 % env->tlb->nb_tlb;
+    }
 }
 
 void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1)
@@ -1368,11 +1379,14 @@ void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1)
     }
 
     /* 1k pages not implemented */
-    val = arg1 & mask;
 #if defined(TARGET_MIPS64)
-    val &= env->SEGMask;
+    if ((env->insn_flags & ISA_MIPS32R6) && extract64(arg1, 62, 2) == 0x2) {
+        mask &= ~(0x3ull << 62);

If Config0_AT = 1, R field is restricted for 1 as well.

+    }
+    mask &= env->SEGMask;
 #endif
     old = env->CP0_EntryHi;
+    val = (arg1 & mask) | (old & ~mask);
     env->CP0_EntryHi = val;
     if (env->CP0_Config3 & (1 << CP0C3_MT)) {
         sync_c0_entryhi(env, env->current_tc);
@@ -1402,6 +1416,13 @@ void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1)
     uint32_t val, old;
     uint32_t mask = env->CP0_Status_rw_bitmask;
 
+    if (env->insn_flags & ISA_MIPS32R6) {
+        if (extract32(env->CP0_Status, CP0St_KSU, 2) == 0x3) {
+            mask &= ~(3 << CP0St_KSU);
+        }
+        mask &= ~(0x00180000 & arg1); 
+    }
+
     val = arg1 & mask;
     old = env->CP0_Status;
     env->CP0_Status = (env->CP0_Status & ~mask) | val;
@@ -1457,6 +1478,9 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1)
     if (cpu->insn_flags & ISA_MIPS32R2) {
         mask |= 1 << CP0Ca_DC;
     }
+    if (cpu->insn_flags & ISA_MIPS32R6) {
+        mask &= ~((1 << CP0Ca_WP) & arg1);
+    }
 
     cpu->CP0_Cause = (cpu->CP0_Cause & ~mask) | (arg1 & mask);
 
@@ -2381,8 +2405,9 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
         }
         break;
     case 25:
-        if (arg1 & 0xffffff00)
+        if (env->insn_flags & ISA_MIPS32R6 || arg1 & 0xffffff00) {
             return;
+        }
         env->active_fpu.fcr31 = (env->active_fpu.fcr31 & 0x017fffff) | ((arg1 & 0xfe) << 24) |
                      ((arg1 & 0x1) << 23);
         break;
@@ -2398,9 +2423,13 @@ void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t fs, uint32_t rt)
                      ((arg1 & 0x4) << 22);
         break;
     case 31:
-        if (arg1 & 0x007c0000)
-            return;
-        env->active_fpu.fcr31 = arg1;
+        if (env->insn_flags & ISA_MIPS32R6) {
+            uint32_t mask = 0xfefc0000;
+            env->active_fpu.fcr31 = (arg1 & ~mask) |
+                (env->active_fpu.fcr31 & mask);
+        } else if (!(arg1 & 0x007c0000)) {
+            env->active_fpu.fcr31 = arg1;
+        }
         break;
     default:
         return;


Regards,
Yongbok

--------------020202030809020309020405--