github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_arm.go (about)

     1  //go:build scheduler.tasks && arm && !cortexm && !avr && !xtensa && !tinygo.riscv
     2  
     3  package task
     4  
     5  import "unsafe"
     6  
     7  var systemStack uintptr
     8  
     9  // calleeSavedRegs is the list of registers that must be saved and restored when
    10  // switching between tasks. Also see task_stack_arm.S that relies on the exact
    11  // layout of this struct.
    12  type calleeSavedRegs struct {
    13  	r4  uintptr
    14  	r5  uintptr
    15  	r6  uintptr
    16  	r7  uintptr
    17  	r8  uintptr
    18  	r9  uintptr
    19  	r10 uintptr
    20  	r11 uintptr
    21  
    22  	pc uintptr
    23  }
    24  
    25  // archInit runs architecture-specific setup for the goroutine startup.
    26  func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
    27  	// Store the initial sp for the startTask function (implemented in assembly).
    28  	s.sp = uintptr(unsafe.Pointer(r))
    29  
    30  	// Initialize the registers.
    31  	// These will be popped off of the stack on the first resume of the goroutine.
    32  
    33  	// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_arm.S).
    34  	// This assembly code calls a function (passed in r4) with a single argument
    35  	// (passed in r5). After the function returns, it calls Pause().
    36  	r.pc = uintptr(unsafe.Pointer(&startTask))
    37  
    38  	// Pass the function to call in r4.
    39  	// This function is a compiler-generated wrapper which loads arguments out of a struct pointer.
    40  	// See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information.
    41  	r.r4 = fn
    42  
    43  	// Pass the pointer to the arguments struct in r5.
    44  	r.r5 = uintptr(args)
    45  }
    46  
    47  func (s *state) resume() {
    48  	swapTask(s.sp, &systemStack)
    49  }
    50  
    51  func (s *state) pause() {
    52  	newStack := systemStack
    53  	systemStack = 0
    54  	swapTask(newStack, &s.sp)
    55  }
    56  
    57  // SystemStack returns the system stack pointer when called from a task stack.
    58  // When called from the system stack, it returns 0.
    59  func SystemStack() uintptr {
    60  	return systemStack
    61  }