Skip to content

Commit 00a9a8a

Browse files
authoredNov 4, 2016
Fix: AArch64 context switch (#3498)
Fiber context switch fails on AArch64 with a SIGBUS error. It's caused by the stack being incorrectly aligned. Pushing any other register to th stack fixes the issue. It's also impossible to read a pointer value directly into the SP register, so this patch avoids the pointer for the second argument altogether. The same could be applied for all platforms.
1 parent b36f72a commit 00a9a8a

File tree

1 file changed

+19
-17
lines changed

1 file changed

+19
-17
lines changed
 

Diff for: ‎src/fiber.cr

+19-17
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,11 @@ class Fiber
4949
stack_ptr[-1] = Pointer(Void).null # Empty space to keep the stack alignment (16 bytes)
5050
stack_ptr[-2] = fiber_main.pointer # Initial `resume` will `ret` to this address
5151
{% elsif flag?(:aarch64) %}
52-
# In ARMv6 / ARVMv7, the context switch push/pops 19 registers.
53-
# Add one more to store the argument of `fiber_main`
54-
@stack_top = (stack_ptr - 21).as(Void*)
55-
56-
stack_ptr[-1] = self.as(Void*) # This will be `pop` into r0 (first argument)
57-
stack_ptr[-13] = fiber_main.pointer # Initial `resume` will `ret` to this address
52+
# In ARMv8, the context switch push/pops 12 registers + 8 FPU registers.
53+
# Add one more to store the argument of `fiber_main` (+ alignment)
54+
@stack_top = (stack_ptr - 22).as(Void*)
55+
stack_ptr[-2] = self.as(Void*) # This will be `pop` into r0 (first argument)
56+
stack_ptr[-14] = fiber_main.pointer # Initial `resume` will `ret` to this address
5857
{% elsif flag?(:arm) %}
5958
# In ARMv6 / ARVMv7, the context switch push/pops 8 registers.
6059
# Add one more to store the argument of `fiber_main`
@@ -185,36 +184,35 @@ class Fiber
185184
# Adapted from https://github.com/ldc-developers/druntime/blob/ldc/src/core/threadasm.S
186185
#
187186
# preserve/restore AAPCS64 registers
188-
# r19-r28 5.1.1 64-bit callee saved
189-
# r29 fp, or possibly callee saved reg - depends on platform choice 5.2.3)
190-
# r30 lr
187+
# x19-x28 5.1.1 64-bit callee saved
188+
# x29 fp, or possibly callee saved reg - depends on platform choice 5.2.3)
189+
# x30 lr
190+
# x0 self argument (initial call)
191191
# d8-d15 5.1.2 says callee only must save bottom 64-bits (the "d" regs)
192-
#
193192
asm("
194193
stp d15, d14, [sp, #-22*8]!
195194
stp d13, d12, [sp, #2*8]
196195
stp d11, d10, [sp, #4*8]
197196
stp d9, d8, [sp, #6*8]
198-
stp x30, x29, [sp, #8*8] // lr, fp
197+
stp x30, x29, [sp, #8*8] // lr, fp
199198
stp x28, x27, [sp, #10*8]
200199
stp x26, x25, [sp, #12*8]
201200
stp x24, x23, [sp, #14*8]
202201
stp x22, x21, [sp, #16*8]
203202
stp x20, x19, [sp, #18*8]
204-
str x0, [sp, #20*8]
203+
stp x0, x1, [sp, #20*8] // self, alignment
205204
206205
mov x19, sp
207206
str x19, [$0]
208-
ldr x19, [$1]
209-
mov sp, x19
207+
mov sp, $1
210208
211-
ldr x0, [sp, #20*8]
209+
ldp x0, x1, [sp, #20*8] // self, alignment
212210
ldp x20, x19, [sp, #18*8]
213211
ldp x22, x21, [sp, #16*8]
214212
ldp x24, x23, [sp, #14*8]
215213
ldp x26, x25, [sp, #12*8]
216214
ldp x28, x27, [sp, #10*8]
217-
ldp x30, x29, [sp, #8*8] // lr, fp
215+
ldp x30, x29, [sp, #8*8] // lr, fp
218216
ldp d9, d8, [sp, #6*8]
219217
ldp d11, d10, [sp, #4*8]
220218
ldp d13, d12, [sp, #2*8]
@@ -261,7 +259,11 @@ class Fiber
261259
def resume : Nil
262260
current, Thread.current.current_fiber = Thread.current.current_fiber, self
263261
LibGC.stackbottom = @stack_bottom
264-
Fiber.switch_stacks(pointerof(current.@stack_top), pointerof(@stack_top))
262+
{% if flag?(:aarch64) %}
263+
Fiber.switch_stacks(pointerof(current.@stack_top), @stack_top)
264+
{% else %}
265+
Fiber.switch_stacks(pointerof(current.@stack_top), pointerof(@stack_top))
266+
{% end %}
265267
end
266268

267269
def sleep(time)

0 commit comments

Comments
 (0)
Please sign in to comment.