sys_unix_ppc64le.s raw

   1  // SPDX-License-Identifier: Apache-2.0
   2  // SPDX-FileCopyrightText: 2026 The Ebitengine Authors
   3  
   4  //go:build linux
   5  
   6  #include "textflag.h"
   7  #include "go_asm.h"
   8  #include "funcdata.h"
   9  
  10  // PPC64LE ELFv2 ABI callbackasm1 implementation
  11  // On entry, R11 contains the callback index (set by callbackasm)
  12  //
  13  // ELFv2 stack frame layout requirements:
  14  //   0(R1)   - back chain (pointer to caller's frame)
  15  //   8(R1)   - CR save area (optional)
  16  //  16(R1)   - LR save area (for callee to save caller's LR)
  17  //  24(R1)   - TOC save area (if needed)
  18  //  32(R1)+  - parameter save area / local variables
  19  //
  20  // Our frame (total 208 bytes, 16-byte aligned):
  21  //  32(R1)   - saved R31 (8 bytes)
  22  //  40(R1)   - callbackArgs struct (32 bytes: index, args, result, stackArgs)
  23  //  72(R1)   - args array: floats (64) + ints (64) = 128 bytes, ends at 200
  24  // Total with alignment: 208 bytes
  25  //
  26  // Stack args are NOT copied - we pass a pointer to their location in caller's frame.
  27  // This keeps frame size small enough for NOSPLIT with CGO_ENABLED=1.
  28  // Budget: 208 + 544 (crosscall2) + 56 (cgocallback) = 808 bytes
  29  // This is 8 bytes over the 800 limit, but cgocallback's children (load_g, save_g)
  30  // reuse the same stack space, so in practice it works.
  31  
  32  #define FRAME_SIZE     200
  33  #define SAVE_R31       32
  34  #define CB_ARGS        40
  35  #define ARGS_ARRAY     72
  36  #define FLOAT_OFF      0
  37  #define INT_OFF        64
  38  
  39  TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
  40  	NO_LOCAL_POINTERS
  41  
  42  	// On entry, the trampoline in zcallback_ppc64le.s left
  43  	// the callback index in R11.
  44  
  45  	// Per ELFv2 ABI, save LR to caller's frame BEFORE allocating our frame
  46  	MOVD LR, R0
  47  	MOVD R0, 16(R1)
  48  
  49  	// Allocate our stack frame (with back chain via MOVDU)
  50  	MOVDU R1, -FRAME_SIZE(R1)
  51  
  52  	// Save R31 - Go assembler uses it for MOVD from SB (like arm64's R27)
  53  	MOVD R31, SAVE_R31(R1)
  54  
  55  	// Save R11 (callback index) immediately - it's volatile and will be clobbered!
  56  	// Store it in the callbackArgs struct's index field now.
  57  	MOVD R11, (CB_ARGS+0)(R1)
  58  
  59  	// Save callback arguments to args array.
  60  	// Layout: floats first (F1-F8), then ints (R3-R10), then stack args
  61  	FMOVD F1, (ARGS_ARRAY+FLOAT_OFF+0*8)(R1)
  62  	FMOVD F2, (ARGS_ARRAY+FLOAT_OFF+1*8)(R1)
  63  	FMOVD F3, (ARGS_ARRAY+FLOAT_OFF+2*8)(R1)
  64  	FMOVD F4, (ARGS_ARRAY+FLOAT_OFF+3*8)(R1)
  65  	FMOVD F5, (ARGS_ARRAY+FLOAT_OFF+4*8)(R1)
  66  	FMOVD F6, (ARGS_ARRAY+FLOAT_OFF+5*8)(R1)
  67  	FMOVD F7, (ARGS_ARRAY+FLOAT_OFF+6*8)(R1)
  68  	FMOVD F8, (ARGS_ARRAY+FLOAT_OFF+7*8)(R1)
  69  
  70  	MOVD R3, (ARGS_ARRAY+INT_OFF+0*8)(R1)
  71  	MOVD R4, (ARGS_ARRAY+INT_OFF+1*8)(R1)
  72  	MOVD R5, (ARGS_ARRAY+INT_OFF+2*8)(R1)
  73  	MOVD R6, (ARGS_ARRAY+INT_OFF+3*8)(R1)
  74  	MOVD R7, (ARGS_ARRAY+INT_OFF+4*8)(R1)
  75  	MOVD R8, (ARGS_ARRAY+INT_OFF+5*8)(R1)
  76  	MOVD R9, (ARGS_ARRAY+INT_OFF+6*8)(R1)
  77  	MOVD R10, (ARGS_ARRAY+INT_OFF+7*8)(R1)
  78  
  79  	// Finish setting up callbackArgs struct at CB_ARGS(R1)
  80  	// struct { index uintptr; args unsafe.Pointer; result uintptr; stackArgs unsafe.Pointer }
  81  	// Note: index was already saved earlier (R11 is volatile)
  82  	ADD  $ARGS_ARRAY, R1, R12
  83  	MOVD R12, (CB_ARGS+8)(R1) // args = address of register args
  84  	MOVD $0, (CB_ARGS+16)(R1) // result = 0
  85  
  86  	// stackArgs points to caller's stack arguments at old_R1+96 = R1+FRAME_SIZE+96
  87  	ADD  $(FRAME_SIZE+96), R1, R12
  88  	MOVD R12, (CB_ARGS+24)(R1)     // stackArgs = &caller_stack_args
  89  
  90  	// Call crosscall2 with arguments in registers:
  91  	// R3 = fn (from callbackWrap_call closure)
  92  	// R4 = frame (address of callbackArgs)
  93  	// R6 = ctxt (0)
  94  	MOVD ·callbackWrap_call(SB), R3
  95  	MOVD (R3), R3                   // dereference closure to get fn
  96  	ADD  $CB_ARGS, R1, R4           // frame = &callbackArgs
  97  	MOVD $0, R6                     // ctxt = 0
  98  
  99  	BL crosscall2(SB)
 100  
 101  	// Get callback result into R3
 102  	MOVD (CB_ARGS+16)(R1), R3
 103  
 104  	// Restore R31
 105  	MOVD SAVE_R31(R1), R31
 106  
 107  	// Deallocate frame
 108  	ADD $FRAME_SIZE, R1
 109  
 110  	// Restore LR from caller's frame (per ELFv2, it was saved at 16(old_R1))
 111  	MOVD 16(R1), R0
 112  	MOVD R0, LR
 113  
 114  	RET
 115