Welcome to mirror list, hosted at ThFree Co, Russian Federation.

PInvoke.asm « arm « Runtime « Native « src - github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5151d5a3910c010d1f8dd2dd7a9844f860c5b9ce (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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
;; Licensed to the .NET Foundation under one or more agreements.
;; The .NET Foundation licenses this file to you under the MIT license.
;; See the LICENSE file in the project root for more information.

#include "AsmMacros.h"

        TEXTAREA

        IMPORT RhpReversePInvokeBadTransition

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForSuspend -- rare path for RhpPInvoke and RhpReversePInvokeReturn
;;
;;
;; INPUT: none
;;
;; TRASHES: none
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        NESTED_ENTRY RhpWaitForSuspend

        PROLOG_PUSH {r0-r4,lr}     ; Need to save argument registers r0-r3 and lr, r4 is just for alignment
        PROLOG_VPUSH {d0-d7}       ; Save float argument registers as well since they're volatile

        bl          RhpWaitForSuspend2
        
        EPILOG_VPOP {d0-d7}
        EPILOG_POP  {r0-r4,pc}

        NESTED_END RhpWaitForSuspend


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForGCNoAbort
;;
;;
;; INPUT: r2: transition frame
;;
;; OUTPUT: 
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        NESTED_ENTRY RhpWaitForGCNoAbort

        PROLOG_PUSH {r0-r6,lr}  ; Even number of registers to maintain 8-byte stack alignment
        PROLOG_VPUSH {d0-d3}    ; Save float return value registers as well

        ldr         r5, [r2, #OFFSETOF__PInvokeTransitionFrame__m_pThread]

        ldr         r0, [r5, #OFFSETOF__Thread__m_ThreadStateFlags]
        tst         r0, #TSF_DoNotTriggerGc
        bne         Done

        mov         r0, r2      ; passing transition frame in r0
        bl          RhpWaitForGC2

Done
        EPILOG_VPOP {d0-d3}
        EPILOG_POP  {r0-r6,pc}

        NESTED_END RhpWaitForGCNoAbort

        EXTERN RhpThrowHwEx

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpWaitForGCNoAbort
;;
;;
;; INPUT: r2: transition frame
;;
;; OUTPUT: 
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        NESTED_ENTRY RhpWaitForGC
        PROLOG_PUSH  {r0,lr}

        ldr         r0, =RhpTrapThreads
        ldr         r0, [r0]
        tst         r0, #TrapThreadsFlags_TrapThreads
        beq         NoWait
        bl          RhpWaitForGCNoAbort
NoWait
        tst         r0, #TrapThreadsFlags_AbortInProgress
        beq         NoAbort
        ldr         r0, [r2, #OFFSETOF__PInvokeTransitionFrame__m_dwFlags]
        tst         r0, #PTFF_THREAD_ABORT
        beq         NoAbort
        EPILOG_POP  {r0,r1}         ; hijack target address as exception PC
        EPILOG_NOP  mov r0, #STATUS_REDHAWK_THREAD_ABORT
        EPILOG_BRANCH RhpThrowHwEx        
NoAbort
        EPILOG_POP  {r0,pc}
        NESTED_END RhpWaitForGC

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpReversePInvoke
;;
;; IN:  r4: address of reverse pinvoke frame
;;                  0: save slot for previous M->U transition frame
;;                  4: save slot for thread pointer to avoid re-calc in epilog sequence
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        NESTED_ENTRY RhpReversePInvoke

        PROLOG_PUSH {r5-r7,lr}  ; Even number of registers to maintain 8-byte stack alignment

        INLINE_GETTHREAD r5, r6     ; r5 = Thread, r6 trashed
        str         r5, [r4, #4]    ; save Thread pointer for RhpReversePInvokeReturn

        ; r4 = prev save slot
        ; r5 = thread
        ; r6 = scratch

        ldr         r6, [r5, #OFFSETOF__Thread__m_ThreadStateFlags]
        tst         r6, #TSF_Attached
        beq         AttachThread

ThreadAttached
        ;;
        ;; Check for the correct mode.  This is accessible via various odd things that we cannot completely 
        ;; prevent such as :
        ;;     1) Registering a reverse pinvoke entrypoint as a vectored exception handler
        ;;     2) Performing a managed delegate invoke on a reverse pinvoke delegate.
        ;;
        ldr         r6, [r5, #OFFSETOF__Thread__m_pTransitionFrame]
        cbz         r6, CheckBadTransition

        ;; Save previous TransitionFrame prior to making the mode transition so that it is always valid 
        ;; whenever we might attempt to hijack this thread.
        str         r6, [r4]

        mov         r6, #0
        str         r6, [r5, #OFFSETOF__Thread__m_pTransitionFrame]
        dmb

        ldr         r6, =RhpTrapThreads
        ldr         r6, [r6]
        tst         r6, #TrapThreadsFlags_TrapThreads
        bne         TrapThread

AllDone
        EPILOG_POP  {r5-r7,lr}
        EPILOG_RETURN


CheckBadTransition
        ;; Allow 'bad transitions' in when the TSF_DoNotTriggerGc mode is set.  This allows us to have 
        ;; [NativeCallable] methods that are called via the "restricted GC callouts" as well as from native,
        ;; which is necessary because the methods are CCW vtable methods on interfaces passed to native.
        ldr         r7, [r5, #OFFSETOF__Thread__m_ThreadStateFlags]
        tst         r7, #TSF_DoNotTriggerGc
        beq         BadTransition

        ;; zero-out our 'previous transition frame' save slot
        mov         r7, #0
        str         r7, [r4]

        ;; nothing more to do
        b           AllDone

TrapThread
        ;; put the previous frame back (sets us back to preemptive mode)
        ldr         r6, [r4]
        str         r6, [r5, #OFFSETOF__Thread__m_pTransitionFrame]
        dmb

AttachThread
        ; passing address of reverse pinvoke frame in r4
        EPILOG_POP  {r5-r7,lr}
        EPILOG_BRANCH RhpReversePInvokeAttachOrTrapThread

BadTransition
        EPILOG_POP  {r5-r7,lr}
        EPILOG_NOP  mov r0, lr  ; arg <- return address
        EPILOG_BRANCH RhpReversePInvokeBadTransition

        NESTED_END RhpReversePInvoke

        INLINE_GETTHREAD_CONSTANT_POOL


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpReversePInvokeAttachOrTrapThread -- rare path for RhpPInvoke
;;
;;
;; INPUT: r4: address of reverse pinvoke frame
;;
;; TRASHES: none
;; 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        NESTED_ENTRY RhpReversePInvokeAttachOrTrapThread

        PROLOG_PUSH {r0-r4,lr}     ; Need to save argument registers r0-r3 and lr, r4 is just for alignment
        PROLOG_VPUSH {d0-d7}       ; Save float argument registers as well since they're volatile

        mov         r0, r4         ; passing reverse pinvoke frame pointer in r0
        bl          RhpReversePInvokeAttachOrTrapThread2

        EPILOG_VPOP {d0-d7}
        EPILOG_POP  {r0-r4,pc}

        NESTED_END RhpReversePInvokeTrapThread


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; RhpReversePInvokeReturn
;;
;; IN:  r3: address of reverse pinvoke frame
;;                  0: save slot for previous M->U transition frame
;;                  4: save slot for thread pointer to avoid re-calc in epilog sequence
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        LEAF_ENTRY RhpReversePInvokeReturn

        ldr         r2, [r3, #4]    ; get Thread pointer
        ldr         r3, [r3, #0]    ; get previous M->U transition frame

        str         r3, [r2, #OFFSETOF__Thread__m_pTransitionFrame]
        dmb

        ldr         r3, =RhpTrapThreads
        ldr         r3, [r3]
        tst         r3, #TrapThreadsFlags_TrapThreads
        bne         RareTrapThread

        bx          lr

RareTrapThread
        b           RhpWaitForSuspend

        LEAF_END RhpReversePInvokeReturn


        end