summaryrefslogtreecommitdiffstats
path: root/lib/unwarminder/safe_read.S
diff options
context:
space:
mode:
Diffstat (limited to 'lib/unwarminder/safe_read.S')
-rw-r--r--lib/unwarminder/safe_read.S143
1 files changed, 143 insertions, 0 deletions
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