diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2012-04-02 15:20:02 +0200 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2012-04-06 13:48:09 +0200 |
commit | d4674ed3b7cd98fab499d0d94d364bdb060df3ff (patch) | |
tree | 9c698c566e071091e08acdb5911be66c327f726c | |
parent | f33330c0ff90adad8855250877a4a3d0a407bba4 (diff) | |
download | rockbox-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>
-rw-r--r-- | lib/unwarminder/SOURCES | 1 | ||||
-rw-r--r-- | lib/unwarminder/backtrace.c | 10 | ||||
-rw-r--r-- | lib/unwarminder/safe_read.S | 143 | ||||
-rw-r--r-- | lib/unwarminder/safe_read.h | 33 |
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 | |||
5 | unwarminder.c | 5 | unwarminder.c |
6 | unwarmmem.c | 6 | unwarmmem.c |
7 | unwarm_thumb.c | 7 | unwarm_thumb.c |
8 | 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 @@ | |||
23 | ***************************************************************************/ | 23 | ***************************************************************************/ |
24 | 24 | ||
25 | #include "backtrace.h" | 25 | #include "backtrace.h" |
26 | #include "safe_read.h" | ||
26 | 27 | ||
27 | /*************************************************************************** | 28 | /*************************************************************************** |
28 | * Prototypes | 29 | * Prototypes |
@@ -86,20 +87,17 @@ static Boolean CliReport(void *data, Int32 address) | |||
86 | 87 | ||
87 | static Boolean CliReadW(const Int32 a, Int32 *v) | 88 | static Boolean CliReadW(const Int32 a, Int32 *v) |
88 | { | 89 | { |
89 | *v = *(Int32 *)a; | 90 | return safe_read32((uint32_t *)a, (uint32_t *)v); |
90 | return TRUE; | ||
91 | } | 91 | } |
92 | 92 | ||
93 | static Boolean CliReadH(const Int32 a, Int16 *v) | 93 | static Boolean CliReadH(const Int32 a, Int16 *v) |
94 | { | 94 | { |
95 | *v = *(Int16 *)a; | 95 | return safe_read16((void *)a, (uint16_t *)v); |
96 | return TRUE; | ||
97 | } | 96 | } |
98 | 97 | ||
99 | static Boolean CliReadB(const Int32 a, Int8 *v) | 98 | static Boolean CliReadB(const Int32 a, Int8 *v) |
100 | { | 99 | { |
101 | *v = *(Int8 *)a; | 100 | return safe_read8((void *)a, (uint8_t *)v); |
102 | return TRUE; | ||
103 | } | 101 | } |
104 | 102 | ||
105 | Boolean CliInvalidateW(const Int32 a) | 103 | 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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2012 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "config.h" | ||
22 | |||
23 | .data | ||
24 | was_aborted: | ||
25 | .word 0 | ||
26 | |||
27 | .section .text.safe_read8 | ||
28 | .type safe_read8, %function | ||
29 | .global safe_read8 | ||
30 | @ bool safe_read8(uint8_t *addr, uint8_t *value) | ||
31 | safe_read8: | ||
32 | @ was_aborted = 0 | ||
33 | ldr r2, =was_aborted | ||
34 | mov r3, #0 | ||
35 | str r3, [r2] | ||
36 | @ r0=*addr | ||
37 | safe_read8_faulty_addr: | ||
38 | ldrb r0, [r0] | ||
39 | @ if(was_aborted) | ||
40 | ldr r2, [r2] | ||
41 | cmp r2, #1 | ||
42 | @ return false; | ||
43 | moveq r0, #0 | ||
44 | bxeq lr | ||
45 | @ if(value != NULL) | ||
46 | cmp r1, #0 | ||
47 | @ *value = r0 | ||
48 | strneb r0, [r1] | ||
49 | @ return true; | ||
50 | mov r0, #1 | ||
51 | bx lr | ||
52 | .size safe_read8, . - safe_read8 | ||
53 | |||
54 | .section .text.safe_read16 | ||
55 | .type safe_read16, %function | ||
56 | .global safe_read16 | ||
57 | @ bool safe_read16(uint16_t *addr, uint16_t *value) | ||
58 | safe_read16: | ||
59 | @ was_aborted = 0 | ||
60 | ldr r2, =was_aborted | ||
61 | mov r3, #0 | ||
62 | str r3, [r2] | ||
63 | @ r0=*addr | ||
64 | safe_read16_faulty_addr: | ||
65 | ldrh r0, [r0] | ||
66 | @ if(was_aborted) | ||
67 | ldr r2, [r2] | ||
68 | cmp r2, #1 | ||
69 | @ return false; | ||
70 | moveq r0, #0 | ||
71 | bxeq lr | ||
72 | @ if(value != NULL) | ||
73 | cmp r1, #0 | ||
74 | @ *value = r0 | ||
75 | strneh r0, [r1] | ||
76 | @ return true; | ||
77 | mov r0, #1 | ||
78 | bx lr | ||
79 | .size safe_read16, . - safe_read16 | ||
80 | |||
81 | .section .text.safe_read32 | ||
82 | .type safe_read32, %function | ||
83 | .global safe_read32 | ||
84 | @ bool safe_read32(uint32_t *addr, uint32_t *value) | ||
85 | safe_read32: | ||
86 | @ was_aborted = 0 | ||
87 | ldr r2, =was_aborted | ||
88 | mov r3, #0 | ||
89 | str r3, [r2] | ||
90 | @ r0=*addr | ||
91 | safe_read32_faulty_addr: | ||
92 | ldr r0, [r0] | ||
93 | @ if(was_aborted) | ||
94 | ldr r2, [r2] | ||
95 | cmp r2, #1 | ||
96 | @ return false; | ||
97 | moveq r0, #0 | ||
98 | bxeq lr | ||
99 | @ if(value != NULL) | ||
100 | cmp r1, #0 | ||
101 | @ *value = r0 | ||
102 | strne r0, [r1] | ||
103 | @ return true; | ||
104 | mov r0, #1 | ||
105 | bx lr | ||
106 | .size safe_read32, . - safe_read32 | ||
107 | |||
108 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) | ||
109 | .section .text.data_abort_handler | ||
110 | .type data_abort_handler, %function | ||
111 | .global data_abort_handler | ||
112 | data_abort_handler: | ||
113 | @ store minimal amount of registers | ||
114 | stmfd sp!, {r0-r1} | ||
115 | @ compute faulty address | ||
116 | sub r0, lr, #8 | ||
117 | @ compare to safe_read8 | ||
118 | ldr r1, =safe_read8_faulty_addr | ||
119 | cmp r0, r1 | ||
120 | beq 1f | ||
121 | @ compare to safe_read16 | ||
122 | ldr r1, =safe_read16_faulty_addr | ||
123 | cmp r0, r1 | ||
124 | beq 1f | ||
125 | @ compare to safe_read32 | ||
126 | ldr r1, =safe_read32_faulty_addr | ||
127 | cmp r0, r1 | ||
128 | beq 1f | ||
129 | @ otherwise just normally to UIE | ||
130 | mov r0, r1 | ||
131 | mov r1, #2 | ||
132 | b UIE | ||
133 | 1: | ||
134 | @ set was_aborted | ||
135 | ldr r1, =was_aborted | ||
136 | mov r0, #1 | ||
137 | str r0, [r1] | ||
138 | @ restore registers | ||
139 | ldmfd sp!, {r0-r1} | ||
140 | @ restore mode and jump back to the *next* instruction | ||
141 | subs pc, lr, #-4 | ||
142 | .size data_abort_handler, . - data_abort_handler | ||
143 | #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 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2012 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef __SAFE_READ__ | ||
22 | #define __SAFE_READ__ | ||
23 | |||
24 | #include "system.h" | ||
25 | |||
26 | /* Try to read an X-bit unsigned integer. If the address is not readable, | ||
27 | * returns false. Otherwise returns true and store the result in *value | ||
28 | * if value is not NULL */ | ||
29 | bool safe_read8(uint8_t *addr, uint8_t *value); | ||
30 | bool safe_read16(uint16_t *addr, uint16_t *value); | ||
31 | bool safe_read32(uint32_t *addr, uint32_t *value); | ||
32 | |||
33 | #endif /* __SAFE_READ__ */ \ No newline at end of file | ||