sys_unix_s390x.s 3.4 KB

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