sys_unix_s390x.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  // S390X ELF ABI callbackasm1 implementation
  11  // On entry, R0 contains the callback index (set by callbackasm)
  12  // NOTE: We use R0 instead of R11 because R11 is callee-saved on S390X.
  13  //
  14  // S390X stack frame layout:
  15  //   0(R15)   - back chain
  16  //  48(R15)   - register save area (R6-R15)
  17  // 160(R15)  - parameter area
  18  //
  19  // S390X uses R2-R6 for integer arguments (5 registers) and F0,F2,F4,F6 for floats (4 registers).
  20  //
  21  // Our frame layout (total 264 bytes, 8-byte aligned):
  22  //  0(R15)    - back chain
  23  // 48(R15)   - saved R6-R15 (done by STMG)
  24  // 160(R15)  - callbackArgs struct (32 bytes: index, args, result, stackArgs)
  25  // 192(R15)  - args array start
  26  //
  27  // Args array layout:
  28  // - floats F0,F2,F4,F6 (32 bytes)
  29  // - ints R2-R6 (40 bytes)
  30  // Total args array: 72 bytes, ends at 264
  31  //
  32  // Stack args in caller's frame start at old_R15+160
  33  
  34  #define FRAME_SIZE     264
  35  #define CB_ARGS        160
  36  #define ARGS_ARRAY     192
  37  #define FLOAT_OFF      0
  38  #define INT_OFF        32
  39  
  40  TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
  41  	NO_LOCAL_POINTERS
  42  
  43  	// On entry, the trampoline in zcallback_s390x.s left
  44  	// the callback index in R0 (NOT R11, since R11 is callee-saved).
  45  	// R6 contains the 5th integer argument.
  46  
  47  	// Save R6-R15 in caller's frame (per S390X ABI) BEFORE allocating our frame
  48  	// STMG stores R6's current value (the 5th arg) at 48(R15)
  49  	STMG R6, R15, 48(R15)
  50  
  51  	// Save current stack pointer (will be back chain)
  52  	MOVD R15, R1
  53  
  54  	// Allocate our stack frame
  55  	SUB  $FRAME_SIZE, R15
  56  	MOVD R1, 0(R15)       // back chain
  57  
  58  	// Save R0 (callback index) immediately - it's volatile
  59  	MOVD R0, (CB_ARGS+0)(R15)
  60  
  61  	// Save callback arguments to args array.
  62  	// Layout: floats first (F0,F2,F4,F6), then ints (R2-R6)
  63  	FMOVD F0, (ARGS_ARRAY+FLOAT_OFF+0*8)(R15)
  64  	FMOVD F2, (ARGS_ARRAY+FLOAT_OFF+1*8)(R15)
  65  	FMOVD F4, (ARGS_ARRAY+FLOAT_OFF+2*8)(R15)
  66  	FMOVD F6, (ARGS_ARRAY+FLOAT_OFF+3*8)(R15)
  67  
  68  	MOVD R2, (ARGS_ARRAY+INT_OFF+0*8)(R15)
  69  	MOVD R3, (ARGS_ARRAY+INT_OFF+1*8)(R15)
  70  	MOVD R4, (ARGS_ARRAY+INT_OFF+2*8)(R15)
  71  	MOVD R5, (ARGS_ARRAY+INT_OFF+3*8)(R15)
  72  
  73  	// R6 (5th int arg) was saved at 48(old_R15) by STMG
  74  	// old_R15 = current R15 + FRAME_SIZE, so R6 is at 48+FRAME_SIZE(R15) = 312(R15)
  75  	MOVD (48+FRAME_SIZE)(R15), R1
  76  	MOVD R1, (ARGS_ARRAY+INT_OFF+4*8)(R15)
  77  
  78  	// Finish setting up callbackArgs struct at CB_ARGS(R15)
  79  	// struct { index uintptr; args unsafe.Pointer; result uintptr; stackArgs unsafe.Pointer }
  80  	// Note: index was already saved earlier
  81  	ADD  $ARGS_ARRAY, R15, R1
  82  	MOVD R1, (CB_ARGS+8)(R15)  // args = address of register args
  83  	MOVD $0, (CB_ARGS+16)(R15) // result = 0
  84  
  85  	// stackArgs points to caller's stack arguments at old_R15+160 = R15+FRAME_SIZE+160
  86  	ADD  $(FRAME_SIZE+160), R15, R1
  87  	MOVD R1, (CB_ARGS+24)(R15)      // stackArgs = &caller_stack_args
  88  
  89  	// Call crosscall2 with arguments in registers:
  90  	// R2 = fn (from callbackWrap_call closure)
  91  	// R3 = frame (address of callbackArgs)
  92  	// R5 = ctxt (0)
  93  	MOVD ·callbackWrap_call(SB), R2
  94  	MOVD (R2), R2                   // dereference closure to get fn
  95  	ADD  $CB_ARGS, R15, R3          // frame = &callbackArgs
  96  	MOVD $0, R5                     // ctxt = 0
  97  
  98  	BL crosscall2(SB)
  99  
 100  	// Get callback result into R2
 101  	MOVD (CB_ARGS+16)(R15), R2
 102  
 103  	// Deallocate frame
 104  	ADD $FRAME_SIZE, R15
 105  
 106  	// Restore R6-R15 from caller's frame
 107  	LMG 48(R15), R6, R15
 108  
 109  	RET
 110