summaryrefslogtreecommitdiffstats
path: root/lib/unwarminder/safe_read.S
blob: 557f3dca31f27b08027d44d1020a393d2eab89be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/***************************************************************************
 *             __________               __   ___.
 *   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"

.syntax unified

.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
    strbne  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
    strhne  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     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