summaryrefslogtreecommitdiffstats
path: root/lib/unwarminder
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-04-02 15:20:02 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2012-04-06 13:48:09 +0200
commitd4674ed3b7cd98fab499d0d94d364bdb060df3ff (patch)
tree9c698c566e071091e08acdb5911be66c327f726c /lib/unwarminder
parentf33330c0ff90adad8855250877a4a3d0a407bba4 (diff)
downloadrockbox-d4674ed3b7cd98fab499d0d94d364bdb060df3ff.tar.gz
rockbox-d4674ed3b7cd98fab499d0d94d364bdb060df3ff.zip
arm: implement safe reads by intercepting the data abort handler.
Implement functions to read from a memory location and indicate failure in case this is not possible. Since we do not have a MMU, intercept the data abort handler and simply return when the abort comes from the safe read routines. Change-Id: I08f2e59898dcac893319a8150d4cf626f3adabbd Reviewed-on: http://gerrit.rockbox.org/207 Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
Diffstat (limited to 'lib/unwarminder')
-rw-r--r--lib/unwarminder/SOURCES1
-rw-r--r--lib/unwarminder/backtrace.c10
-rw-r--r--lib/unwarminder/safe_read.S143
-rw-r--r--lib/unwarminder/safe_read.h33
4 files changed, 181 insertions, 6 deletions
diff --git a/lib/unwarminder/SOURCES b/lib/unwarminder/SOURCES
index 055e6d0ab3..b060e2908d 100644
--- a/lib/unwarminder/SOURCES
+++ b/lib/unwarminder/SOURCES
@@ -5,3 +5,4 @@ unwarm.c
unwarminder.c
unwarmmem.c
unwarm_thumb.c
+safe_read.S \ No newline at end of file
diff --git a/lib/unwarminder/backtrace.c b/lib/unwarminder/backtrace.c
index 4e1609137c..294b7f66f4 100644
--- a/lib/unwarminder/backtrace.c
+++ b/lib/unwarminder/backtrace.c
@@ -23,6 +23,7 @@
***************************************************************************/
#include "backtrace.h"
+#include "safe_read.h"
/***************************************************************************
* Prototypes
@@ -86,20 +87,17 @@ static Boolean CliReport(void *data, Int32 address)
static Boolean CliReadW(const Int32 a, Int32 *v)
{
- *v = *(Int32 *)a;
- return TRUE;
+ return safe_read32((uint32_t *)a, (uint32_t *)v);
}
static Boolean CliReadH(const Int32 a, Int16 *v)
{
- *v = *(Int16 *)a;
- return TRUE;
+ return safe_read16((void *)a, (uint16_t *)v);
}
static Boolean CliReadB(const Int32 a, Int8 *v)
{
- *v = *(Int8 *)a;
- return TRUE;
+ return safe_read8((void *)a, (uint8_t *)v);
}
Boolean CliInvalidateW(const Int32 a)
diff --git a/lib/unwarminder/safe_read.S b/lib/unwarminder/safe_read.S
new file mode 100644
index 0000000000..2e3fc78955
--- /dev/null
+++ b/lib/unwarminder/safe_read.S
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+.data
+was_aborted:
+ .word 0
+
+.section .text.safe_read8
+.type safe_read8, %function
+.global safe_read8
+@ bool safe_read8(uint8_t *addr, uint8_t *value)
+safe_read8:
+ @ was_aborted = 0
+ ldr r2, =was_aborted
+ mov r3, #0
+ str r3, [r2]
+ @ r0=*addr
+safe_read8_faulty_addr:
+ ldrb r0, [r0]
+ @ if(was_aborted)
+ ldr r2, [r2]
+ cmp r2, #1
+ @ return false;
+ moveq r0, #0
+ bxeq lr
+ @ if(value != NULL)
+ cmp r1, #0
+ @ *value = r0
+ strneb r0, [r1]
+ @ return true;
+ mov r0, #1
+ bx lr
+.size safe_read8, . - safe_read8
+
+.section .text.safe_read16
+.type safe_read16, %function
+.global safe_read16
+@ bool safe_read16(uint16_t *addr, uint16_t *value)
+safe_read16:
+ @ was_aborted = 0
+ ldr r2, =was_aborted
+ mov r3, #0
+ str r3, [r2]
+ @ r0=*addr
+safe_read16_faulty_addr:
+ ldrh r0, [r0]
+ @ if(was_aborted)
+ ldr r2, [r2]
+ cmp r2, #1
+ @ return false;
+ moveq r0, #0
+ bxeq lr
+ @ if(value != NULL)
+ cmp r1, #0
+ @ *value = r0
+ strneh r0, [r1]
+ @ return true;
+ mov r0, #1
+ bx lr
+.size safe_read16, . - safe_read16
+
+.section .text.safe_read32
+.type safe_read32, %function
+.global safe_read32
+@ bool safe_read32(uint32_t *addr, uint32_t *value)
+safe_read32:
+ @ was_aborted = 0
+ ldr r2, =was_aborted
+ mov r3, #0
+ str r3, [r2]
+ @ r0=*addr
+safe_read32_faulty_addr:
+ ldr r0, [r0]
+ @ if(was_aborted)
+ ldr r2, [r2]
+ cmp r2, #1
+ @ return false;
+ moveq r0, #0
+ bxeq lr
+ @ if(value != NULL)
+ cmp r1, #0
+ @ *value = r0
+ strne r0, [r1]
+ @ return true;
+ mov r0, #1
+ bx lr
+.size safe_read32, . - safe_read32
+
+#if (CONFIG_PLATFORM & PLATFORM_NATIVE)
+.section .text.data_abort_handler
+.type data_abort_handler, %function
+.global data_abort_handler
+data_abort_handler:
+ @ store minimal amount of registers
+ stmfd sp!, {r0-r1}
+ @ compute faulty address
+ sub r0, lr, #8
+ @ compare to safe_read8
+ ldr r1, =safe_read8_faulty_addr
+ cmp r0, r1
+ beq 1f
+ @ compare to safe_read16
+ ldr r1, =safe_read16_faulty_addr
+ cmp r0, r1
+ beq 1f
+ @ compare to safe_read32
+ ldr r1, =safe_read32_faulty_addr
+ cmp r0, r1
+ beq 1f
+ @ otherwise just normally to UIE
+ mov r0, r1
+ mov r1, #2
+ b UIE
+1:
+ @ set was_aborted
+ ldr r1, =was_aborted
+ mov r0, #1
+ str r0, [r1]
+ @ restore registers
+ ldmfd sp!, {r0-r1}
+ @ restore mode and jump back to the *next* instruction
+ subs pc, lr, #-4
+.size data_abort_handler, . - data_abort_handler
+#endif
diff --git a/lib/unwarminder/safe_read.h b/lib/unwarminder/safe_read.h
new file mode 100644
index 0000000000..0ad23e648d
--- /dev/null
+++ b/lib/unwarminder/safe_read.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __SAFE_READ__
+#define __SAFE_READ__
+
+#include "system.h"
+
+/* Try to read an X-bit unsigned integer. If the address is not readable,
+ * returns false. Otherwise returns true and store the result in *value
+ * if value is not NULL */
+bool safe_read8(uint8_t *addr, uint8_t *value);
+bool safe_read16(uint16_t *addr, uint16_t *value);
+bool safe_read32(uint32_t *addr, uint32_t *value);
+
+#endif /* __SAFE_READ__ */ \ No newline at end of file