Patchwork [ARM] Fix sp804 dual-timer

login
register
mail settings
Submitter Peter Chubb
Date Sept. 29, 2011, 2:34 a.m.
Message ID <w4y5x8yt37.wl%peter@chubb.wattle.id.au>
Download mbox | patch
Permalink /patch/116882/
State New
Headers show

Comments

Peter Chubb - Sept. 29, 2011, 2:34 a.m.
This patch was written by David Mirabito.

Properly implement the dual-timer read/write for the sp804 dual timer module.
Based on ARM specs at
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html

Signed-off-by: Peter Chubb <peter.chubb@nicta.com.au>
Signed-off-by: David Mirabito <davidm@ok-labs.com>
Signed-off-by: Hans Jang <hsjang@ok-labs.com>
---
 hw/arm_timer.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 47 insertions(+), 5 deletions(-)
Peter Maydell - Sept. 29, 2011, 9:58 a.m.
On 29 September 2011 03:34, Peter Chubb <peter.chubb@nicta.com.au> wrote:
> -    /* ??? Don't know the PrimeCell ID for this device.  */
>     if (offset < 0x20) {
>         return arm_timer_read(s->timer[0], offset);
> -    } else {
> +    }
> +    if (offset < 0x40) {
>         return arm_timer_read(s->timer[1], offset - 0x20);
>   }

if (offset < 0x20) {..} else if (offset < 0x40) {..}
would be consistent with what you did in the write function.

> +    /* Timer Peripheral ID Registers, one byte per word:
> +     * [11:0]  - Part number    = 0x804
> +     * [19:12] - Designer Id    = 0x41   ('A')
> +     * [23:20] - Revision       = 1
> +     * [31:24] - Configurations = 0
> +     */
> +    case 0xfe0: /* TimerPeriphID0 */
> +        return 0x04;
> +    case 0xfe4: /* TimerPeriphID1 */
> +        return 0x18;
> +    case 0xfe8: /* TimerPeriphID2 */
> +        return 0x14;
> +    case 0xfec: /* TimerPeriphID3 */
> +        return 0x00;

[etc]

It's neater to do the 8 ID registers with an array, as the other
pl* devices do -- look at hw/pl061.c:pl061_read() for an example.

> +    cpu_abort (cpu_single_env, "sp804_read: Bad offset %x\n",
> +               (int)offset);

Don't cpu_abort() for something a malicious guest can trigger.
(Yes, we do this in some other devices at the moment, but we
shouldn't be introducing new instances of the problem.)

Maybe we should update the comment that says "docs for
this device don't seem to be available"...

-- PMM

Patch

diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 09a4b24..35f4bb5 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -196,12 +196,49 @@  static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
 {
     sp804_state *s = (sp804_state *)opaque;
 
-    /* ??? Don't know the PrimeCell ID for this device.  */
     if (offset < 0x20) {
         return arm_timer_read(s->timer[0], offset);
-    } else {
+    } 
+    if (offset < 0x40) {
         return arm_timer_read(s->timer[1], offset - 0x20);
     }
+
+    /* Is it one of the test or id registers */
+    switch(offset){
+    /* Integration Test control registers, which we won't support */
+    case 0xf00: /* TimerITCR */
+    case 0xf04: /* TimerITOP (strictly write only but..) */
+        return 0;
+
+    /* Timer Peripheral ID Registers, one byte per word:
+     * [11:0]  - Part number    = 0x804
+     * [19:12] - Designer Id    = 0x41   ('A')
+     * [23:20] - Revision       = 1
+     * [31:24] - Configurations = 0
+     */
+    case 0xfe0: /* TimerPeriphID0 */
+        return 0x04;
+    case 0xfe4: /* TimerPeriphID1 */
+        return 0x18;
+    case 0xfe8: /* TimerPeriphID2 */
+        return 0x14;
+    case 0xfec: /* TimerPeriphID3 */
+        return 0x00;
+
+    /* PrimeCell ID Registers = 0xB105F00D */
+    case 0xff0: /* TimerPCellID0 */
+        return 0x0d;
+    case 0xff4: /* TimerPCellID1 */
+        return 0xf0;
+    case 0xff8: /* TimerPCellID2 */
+        return 0x05;
+    case 0xffc: /* TimerPCellID3 */
+        return 0xb1;
+    }
+    cpu_abort (cpu_single_env, "sp804_read: Bad offset %x\n",
+               (int)offset);
+
+    return 0;
 }
 
 static void sp804_write(void *opaque, target_phys_addr_t offset,
@@ -211,8 +248,12 @@  static void sp804_write(void *opaque, target_phys_addr_t offset,
 
     if (offset < 0x20) {
         arm_timer_write(s->timer[0], offset, value);
-    } else {
+    } else if (offset < 0x40) {
         arm_timer_write(s->timer[1], offset - 0x20, value);
+    } else {
+        /* Technically we could be writing to the Test Registers, but not likely */
+        cpu_abort (cpu_single_env, "sp804_write: Bad offset %x\n",
+                   (int)offset);
     }
 }
 
@@ -269,8 +310,9 @@  static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
 
     /* ??? Don't know the PrimeCell ID for this device.  */
     n = offset >> 8;
+
     if (n > 3) {
-        hw_error("sp804_read: Bad timer %d\n", n);
+        hw_error("icp_pit_read: Bad timer %d\n", n);
     }
 
     return arm_timer_read(s->timer[n], offset & 0xff);
@@ -284,7 +326,7 @@  static void icp_pit_write(void *opaque, target_phys_addr_t offset,
 
     n = offset >> 8;
     if (n > 3) {
-        hw_error("sp804_write: Bad timer %d\n", n);
+        hw_error("icp_pit_write: Bad timer %d\n", n);
     }
 
     arm_timer_write(s->timer[n], offset & 0xff, value);