Skip to content

Commit

Permalink
Fix: AArch64 context switch (#3498)
Browse files Browse the repository at this point in the history
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.
ysbaddaden authored Nov 4, 2016
1 parent b36f72a commit 00a9a8a
Showing 1 changed file with 19 additions and 17 deletions.
36 changes: 19 additions & 17 deletions src/fiber.cr
Original file line number Diff line number Diff line change
@@ -49,12 +49,11 @@ class Fiber
stack_ptr[-1] = Pointer(Void).null # Empty space to keep the stack alignment (16 bytes)
stack_ptr[-2] = fiber_main.pointer # Initial `resume` will `ret` to this address
{% elsif flag?(:aarch64) %}
# In ARMv6 / ARVMv7, the context switch push/pops 19 registers.
# Add one more to store the argument of `fiber_main`
@stack_top = (stack_ptr - 21).as(Void*)

stack_ptr[-1] = self.as(Void*) # This will be `pop` into r0 (first argument)
stack_ptr[-13] = fiber_main.pointer # Initial `resume` will `ret` to this address
# In ARMv8, the context switch push/pops 12 registers + 8 FPU registers.
# Add one more to store the argument of `fiber_main` (+ alignment)
@stack_top = (stack_ptr - 22).as(Void*)
stack_ptr[-2] = self.as(Void*) # This will be `pop` into r0 (first argument)
stack_ptr[-14] = fiber_main.pointer # Initial `resume` will `ret` to this address
{% elsif flag?(:arm) %}
# In ARMv6 / ARVMv7, the context switch push/pops 8 registers.
# Add one more to store the argument of `fiber_main`
@@ -185,36 +184,35 @@ class Fiber
# Adapted from https://github.com/ldc-developers/druntime/blob/ldc/src/core/threadasm.S
#
# preserve/restore AAPCS64 registers
# r19-r28 5.1.1 64-bit callee saved
# r29 fp, or possibly callee saved reg - depends on platform choice 5.2.3)
# r30 lr
# x19-x28 5.1.1 64-bit callee saved
# x29 fp, or possibly callee saved reg - depends on platform choice 5.2.3)
# x30 lr
# x0 self argument (initial call)
# d8-d15 5.1.2 says callee only must save bottom 64-bits (the "d" regs)
#
asm("
stp d15, d14, [sp, #-22*8]!
stp d13, d12, [sp, #2*8]
stp d11, d10, [sp, #4*8]
stp d9, d8, [sp, #6*8]
stp x30, x29, [sp, #8*8] // lr, fp
stp x30, x29, [sp, #8*8] // lr, fp
stp x28, x27, [sp, #10*8]
stp x26, x25, [sp, #12*8]
stp x24, x23, [sp, #14*8]
stp x22, x21, [sp, #16*8]
stp x20, x19, [sp, #18*8]
str x0, [sp, #20*8]
stp x0, x1, [sp, #20*8] // self, alignment
mov x19, sp
str x19, [$0]
ldr x19, [$1]
mov sp, x19
mov sp, $1
ldr x0, [sp, #20*8]
ldp x0, x1, [sp, #20*8] // self, alignment
ldp x20, x19, [sp, #18*8]
ldp x22, x21, [sp, #16*8]
ldp x24, x23, [sp, #14*8]
ldp x26, x25, [sp, #12*8]
ldp x28, x27, [sp, #10*8]
ldp x30, x29, [sp, #8*8] // lr, fp
ldp x30, x29, [sp, #8*8] // lr, fp
ldp d9, d8, [sp, #6*8]
ldp d11, d10, [sp, #4*8]
ldp d13, d12, [sp, #2*8]
@@ -261,7 +259,11 @@ class Fiber
def resume : Nil
current, Thread.current.current_fiber = Thread.current.current_fiber, self
LibGC.stackbottom = @stack_bottom
Fiber.switch_stacks(pointerof(current.@stack_top), pointerof(@stack_top))
{% if flag?(:aarch64) %}
Fiber.switch_stacks(pointerof(current.@stack_top), @stack_top)
{% else %}
Fiber.switch_stacks(pointerof(current.@stack_top), pointerof(@stack_top))
{% end %}
end

def sleep(time)

0 comments on commit 00a9a8a

Please sign in to comment.