[Qemu-devel] [PATCH] pl190: fix read of VECTADDR

2012-08-18 Thread Brendan Fennell
Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..d69d5be 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -133,7 +133,7 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t 
offset,
 s->priority = i;
 pl190_update(s);
   }
-return s->vect_addr[s->priority];
+return s->vect_addr[s->priority - 1];
 case 13: /* DEFVECTADDR */
 return s->vect_addr[16];
 default:
-- 
1.7.2.5




Re: [Qemu-devel] [PATCH] pl190: fix read of VECTADDR

2012-08-18 Thread Brendan Fennell



On Sat, 18 Aug 2012, Peter Maydell wrote:


On 18 August 2012 03:55, Brendan Fennell  wrote:

Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..d69d5be 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -133,7 +133,7 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t 
offset,
 s->priority = i;
 pl190_update(s);
   }
-return s->vect_addr[s->priority];
+return s->vect_addr[s->priority - 1];
 case 13: /* DEFVECTADDR */
 return s->vect_addr[16];
 default:


This doesn't look right -- if s->priority is zero then we'll read off
the beginning of the array.
What's the actual bug you're trying to fix here?


The bug is that when, for example, interrupt 4 triggers the VECTADDR of 
interrupt 5 is returned by pl190_read().


Each s->prio_mask entry contains the interrupt mask for all *higher* 
priority interrupts, see pl190_update_vectors(). This means that 
s->prio_mask[0] is always zero (as zero is the highest priority), 
s->priority can never be  zero as ((s->level | s->soft_level) & 
s->prio_mask[0]) is always zero.


Therefore after the for loop in pl190_read() i is the index of the
current highest priority interrupt + 1.

Brendan.



-- PMM








Re: [Qemu-devel] [PATCH] pl190: fix read of VECTADDR

2012-08-18 Thread Brendan Fennell



On Sat, 18 Aug 2012, Peter Maydell wrote:


On 18 August 2012 11:41, Brendan Fennell  wrote:



On Sat, 18 Aug 2012, Peter Maydell wrote:


On 18 August 2012 03:55, Brendan Fennell  wrote:


Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..d69d5be 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -133,7 +133,7 @@ static uint64_t pl190_read(void *opaque,
target_phys_addr_t offset,
 s->priority = i;
 pl190_update(s);
   }
-return s->vect_addr[s->priority];
+return s->vect_addr[s->priority - 1];
 case 13: /* DEFVECTADDR */
 return s->vect_addr[16];
 default:



This doesn't look right -- if s->priority is zero then we'll read off
the beginning of the array.
What's the actual bug you're trying to fix here?



The bug is that when, for example, interrupt 4 triggers the VECTADDR of
interrupt 5 is returned by pl190_read().

Each s->prio_mask entry contains the interrupt mask for all *higher*
priority interrupts, see pl190_update_vectors(). This means that
s->prio_mask[0] is always zero (as zero is the highest priority),
s->priority can never be  zero as ((s->level | s->soft_level) &
s->prio_mask[0]) is always zero.

Therefore after the for loop in pl190_read() i is the index of the
current highest priority interrupt + 1.


Yes, looking more closely, you're right (though that's not obvious
at all...)

But we set s->priority to i, which seems wrong -- s->priority should
be the priority of the current active interrupt, and that's how we
treat it in pl190_update() [we assert s->irq if there's a pending
interrupt that's higher priority than the one we're currently servicing.]

So I think the fix ought to be to change the s->prio_mask[i] in the
loop to be s->prio_mask[i+1] instead. Then we'll exit the loop with
i as the current highest priority interrupt, which is what the following
code expects.

Some sort of explanatory comment in the loop might also assist
future readers :-)


I agree, that's a better solution - I'll follow up with a new patch.

Brendan.



-- PMM






[Qemu-devel] [PATCH v2] pl190: fix read of VECTADDR

2012-08-19 Thread Brendan Fennell

Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..eddb531 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -120,7 +120,8 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t 
offset,
current priority level to that of the current interrupt.  */
 for (i = 0; i < s->priority; i++)
   {
-if ((s->level | s->soft_level) & s->prio_mask[i])
+/* Ensure that 'i' is current highest priority interrupt on exit */
+if ((s->level | s->soft_level) & s->prio_mask[i+1])
   break;
   }
 /* Reading this value with no pending interrupts is undefined.
-- 
1.7.2.5




Re: [Qemu-devel] [PATCH v2] pl190: fix read of VECTADDR

2012-08-20 Thread Brendan Fennell



On Mon, 20 Aug 2012, Peter Maydell wrote:


On 19 August 2012 11:59, Brendan Fennell  wrote:


Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..eddb531 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -120,7 +120,8 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t 
offset,
current priority level to that of the current interrupt.  */
 for (i = 0; i < s->priority; i++)
   {
-if ((s->level | s->soft_level) & s->prio_mask[i])
+/* Ensure that 'i' is current highest priority interrupt on exit */
+if ((s->level | s->soft_level) & s->prio_mask[i+1])
   break;
   }
 /* Reading this value with no pending interrupts is undefined.
--
1.7.2.5


The technical content of this patch looks correct to me, and I've tested
it on a versatilepb Linux image. (Presumably Linux doesn't make use
of different vector addresses/priorities, which is why we haven't noticed
this bug before now.)

As Blue says, you need to fix the coding style issues (you can run
your patch through scripts/checkpatch.pl to help with this). checkpatch
is probably going to end up getting you to fix the indent on the
whole for() loop, which is fine -- we usually fix up the coding style
locally when we make a change. (the key bits of coding style here are
4 space indent, open-brace on same line as 'for' and 'if', braces
mandatory even for single line 'if' bodies.)


Thanks for the helpful feedback - checkpatch.pl does indeed point out the 
coding style problems in the patch.




I also think we could improve on the comment text. Here's my
suggestion (replaces the current just-above-the-loop comment):

   /* Read vector address at the start of an ISR.  Increases the
* current priority level to that of the current interrupt.
*
* Since an enabled interrupt X at priority P causes prio_mask[Y]
* to have bit X set for all Y > P, this loop will stop with
* i == the priority of the highest priority set interrupt.
*/


That explains the situation more clearly, thanks. V3 to follow.



thanks
-- PMM






[Qemu-devel] [PATCH v3] pl190: fix read of VECTADDR

2012-08-20 Thread Brendan Fennell
Signed-off-by: Brendan Fennell 
---
 hw/pl190.c |   18 --
 1 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/hw/pl190.c b/hw/pl190.c
index cb50afb..b372da8 100644
--- a/hw/pl190.c
+++ b/hw/pl190.c
@@ -117,12 +117,18 @@ static uint64_t pl190_read(void *opaque, 
target_phys_addr_t offset,
 return s->protected;
 case 12: /* VECTADDR */
 /* Read vector address at the start of an ISR.  Increases the
-   current priority level to that of the current interrupt.  */
-for (i = 0; i < s->priority; i++)
-  {
-if ((s->level | s->soft_level) & s->prio_mask[i])
-  break;
-  }
+ * current priority level to that of the current interrupt.
+ *
+ * Since an enabled interrupt X at priority P causes prio_mask[Y]
+ * to have bit X set for all Y > P, this loop will stop with
+ * i == the priority of the highest priority set interrupt.
+ */
+for (i = 0; i < s->priority; i++) {
+if ((s->level | s->soft_level) & s->prio_mask[(i + 1)]) {
+break;
+}
+}
+
 /* Reading this value with no pending interrupts is undefined.
We return the default address.  */
 if (i == PL190_NUM_PRIO)
-- 
1.7.2.5




Re: [Qemu-devel] [PATCH v3] pl190: fix read of VECTADDR

2012-08-20 Thread Brendan Fennell



On Mon, 20 Aug 2012, Peter Maydell wrote:


On 20 August 2012 18:59, Brendan Fennell  wrote:

Signed-off-by: Brendan Fennell 


Reviewed-by: Peter Maydell 

The () inside the [] aren't actually necessary, but I'm just
going to fix those as I take this patch into the arm-devs
queue, I think. I've also expanded the commit message a little:

=
Reading VECTADDR was causing us to set the current priority to
the wrong value, the most obvious effect of which was that we
would return the vector for the wrong interrupt as the result
of the read.
=

What guest did you see this problem with? Since the QEMU 1.2
release is now less than 2 weeks away, and this bug has been
present since the versatilepb platform was added 6 years ago,
I'm reluctant to squeeze it into this release unless it's
going to be hit by a lot of people. (1.3 is only 3 months
later so it's not a huge deal for a minor fix to miss 1.2.)


I'm working on a custom application, not a standard guest OS. I think it's 
safe to say this can wait for 1.3.


Brendan.



thanks
-- PMM