summaryrefslogtreecommitdiff
path: root/src/pal/src/arch/arm/context2.S
blob: 88aee3b32190062bec3110fc5a6c1efbcb6421be (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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
//
// Implementation of _CONTEXT_CaptureContext for the ARM platform.
// This function is processor dependent.  It is used by exception handling,
// and is always apply to the current thread.
//

#include "unixasmmacros.inc"

.syntax unified
.thumb

#define CONTEXT_ARM     0x00200000

#define CONTEXT_CONTROL 1 // Sp, Lr, Pc, Cpsr
#define CONTEXT_INTEGER 2 // R0-R12
#define CONTEXT_SEGMENTS 4 // 
#define CONTEXT_FLOATING_POINT 8
#define CONTEXT_DEBUG_REGISTERS 16 //

#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)

#define CONTEXT_ContextFlags 0
#define CONTEXT_R0           CONTEXT_ContextFlags+4
#define CONTEXT_R1           CONTEXT_R0+4
#define CONTEXT_R2           CONTEXT_R1+4
#define CONTEXT_R3           CONTEXT_R2+4
#define CONTEXT_R4           CONTEXT_R3+4
#define CONTEXT_R5           CONTEXT_R4+4
#define CONTEXT_R6           CONTEXT_R5+4
#define CONTEXT_R7           CONTEXT_R6+4
#define CONTEXT_R8           CONTEXT_R7+4
#define CONTEXT_R9           CONTEXT_R8+4
#define CONTEXT_R10          CONTEXT_R9+4
#define CONTEXT_R11          CONTEXT_R10+4
#define CONTEXT_R12          CONTEXT_R11+4
#define CONTEXT_Sp           CONTEXT_R12+4
#define CONTEXT_Lr           CONTEXT_Sp+4
#define CONTEXT_Pc           CONTEXT_Lr+4
#define CONTEXT_Cpsr         CONTEXT_Pc+4
#define CONTEXT_Fpscr        CONTEXT_Cpsr+4
#define CONTEXT_Padding      CONTEXT_Fpscr+4
#define CONTEXT_D0           CONTEXT_Padding+4
#define CONTEXT_D1           CONTEXT_D0+8
#define CONTEXT_D2           CONTEXT_D1+8
#define CONTEXT_D3           CONTEXT_D2+8
#define CONTEXT_D4           CONTEXT_D3+8
#define CONTEXT_D5           CONTEXT_D4+8
#define CONTEXT_D6           CONTEXT_D5+8
#define CONTEXT_D7           CONTEXT_D6+8
#define CONTEXT_D8           CONTEXT_D7+8
#define CONTEXT_D9           CONTEXT_D8+8
#define CONTEXT_D10          CONTEXT_D9+8
#define CONTEXT_D11          CONTEXT_D10+8
#define CONTEXT_D12          CONTEXT_D11+8
#define CONTEXT_D13          CONTEXT_D12+8
#define CONTEXT_D14          CONTEXT_D13+8
#define CONTEXT_D15          CONTEXT_D14+8
#define CONTEXT_D16          CONTEXT_D15+8
#define CONTEXT_D17          CONTEXT_D16+8
#define CONTEXT_D18          CONTEXT_D17+8
#define CONTEXT_D19          CONTEXT_D18+8
#define CONTEXT_D20          CONTEXT_D19+8
#define CONTEXT_D21          CONTEXT_D20+8
#define CONTEXT_D22          CONTEXT_D21+8
#define CONTEXT_D23          CONTEXT_D22+8
#define CONTEXT_D24          CONTEXT_D23+8
#define CONTEXT_D25          CONTEXT_D24+8
#define CONTEXT_D26          CONTEXT_D25+8
#define CONTEXT_D27          CONTEXT_D26+8
#define CONTEXT_D28          CONTEXT_D27+8
#define CONTEXT_D29          CONTEXT_D28+8
#define CONTEXT_D30          CONTEXT_D29+8
#define CONTEXT_D31          CONTEXT_D30+8

// Incoming:
//  r0: Context*
//
LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
    // Ensure we save these registers
    push {r4-r11}
    // Save processor flags before calling any of the following 'test' instructions
    // because they will modify state of some flags
    push {r1}
    mrs r1, apsr // Get APSR - equivalent to eflags
    push {r1} // Save APSR
    END_PROLOGUE
    
    push {r2}
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_INTEGER)
    pop {r2}
    
    // Add 4 to stack so we point at R1, pop, then sub 8 to point at APSR
    add sp, sp, #4
    pop {r1}
    sub sp, sp, #8
    
    itttt ne
    strne r0, [r0, #(CONTEXT_R0)]
    addne r0, CONTEXT_R1
    stmiane r0, {r1-r12}
    subne r0, CONTEXT_R1
    
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_CONTROL)
    
    ittt ne
    addne sp, sp, #(10*4) // This needs to put the stack in the same state as it started
    strne sp, [r0, #(CONTEXT_Sp)]
    subne sp, sp, #(10*4)
    
    itt ne
    strne lr, [r0, #(CONTEXT_Lr)]
    strne lr, [r0, #(CONTEXT_Pc)]
    
    // Get the APSR pushed onto the stack at the start
    pop {r1}
    it ne
    strne r1, [r0, #(CONTEXT_Cpsr)]
    
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_FLOATING_POINT)
    
    itt ne
    vmrsne r3, fpscr
    strne r3, [r0, #(CONTEXT_Fpscr)]
    
    itttt ne
    addne r0, CONTEXT_D0
    vstmiane r0!, {d0-d15}
    vstmiane r0!, {d16-d31}
    subne r0, CONTEXT_D31
    
    // Make sure sp is restored
    add sp, sp, #4

    // Restore callee saved registers
    pop {r4-r11}
    bx lr
LEAF_END CONTEXT_CaptureContext, _TEXT

// Incoming:
//  R0: Context*
//
LEAF_ENTRY RtlCaptureContext, _TEXT
    push {r1}
    mov r1, #0
    orr r1, r1, #CONTEXT_ARM
    orr r1, r1, #CONTEXT_INTEGER
    orr r1, r1, #CONTEXT_CONTROL
    orr r1, r1, #CONTEXT_FLOATING_POINT
    str r1, [r0, #(CONTEXT_ContextFlags)]
    pop {r1}
    b C_FUNC(CONTEXT_CaptureContext)
LEAF_END RtlCaptureContext, _TEXT

// Incoming:
//  r0: Context*
//  r1: Exception*
//
LEAF_ENTRY RtlRestoreContext, _TEXT
    END_PROLOGUE
    
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_FLOATING_POINT)
    
    itttt ne
    addne r0, CONTEXT_D0
    vldmiane r0!, {d0-d15}
    vldmiane r0, {d16-d31}
    subne r0, CONTEXT_D16
    
    itt ne
    ldrne r3, [r0, #(CONTEXT_Fpscr)]
    vmrsne r3, FPSCR
    
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_CONTROL)
    
    it eq
    beq LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
    
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_INTEGER)
    
    it eq
    beq LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
    
    ldr R2, [r0, #(CONTEXT_Cpsr)]
    msr APSR, r2    
    
    add r0, CONTEXT_R0
    ldmia r0, {r0-r12, sp, lr, pc}
    
LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
    
    ldr r2, [r0, #(CONTEXT_Cpsr)]
    msr APSR, r2    
    
    add r0, CONTEXT_Sp
    ldmia r0, {sp, lr, pc}
    
LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
    ldr r2, [r0, #(CONTEXT_ContextFlags)]
    tst r2, #(CONTEXT_INTEGER)
    
    itt ne
    addne r0, CONTEXT_R0
    ldmiane r0, {r0-r12}

    sub sp, sp, #4
    bx lr
LEAF_END RtlRestoreContext, _TEXT