github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/dmz/nolibc/arch-powerpc.h (about)

     1  /* SPDX-License-Identifier: LGPL-2.1 OR MIT */
     2  /*
     3   * PowerPC specific definitions for NOLIBC
     4   * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org>
     5   */
     6  
     7  #ifndef _NOLIBC_ARCH_POWERPC_H
     8  #define _NOLIBC_ARCH_POWERPC_H
     9  
    10  #include "compiler.h"
    11  #include "crt.h"
    12  
    13  /* Syscalls for PowerPC :
    14   *   - stack is 16-byte aligned
    15   *   - syscall number is passed in r0
    16   *   - arguments are in r3, r4, r5, r6, r7, r8, r9
    17   *   - the system call is performed by calling "sc"
    18   *   - syscall return comes in r3, and the summary overflow bit is checked
    19   *     to know if an error occurred, in which case errno is in r3.
    20   *   - the arguments are cast to long and assigned into the target
    21   *     registers which are then simply passed as registers to the asm code,
    22   *     so that we don't have to experience issues with register constraints.
    23   */
    24  
    25  #define _NOLIBC_SYSCALL_CLOBBERLIST \
    26  	"memory", "cr0", "r12", "r11", "r10", "r9"
    27  
    28  #define my_syscall0(num)                                                     \
    29  ({                                                                           \
    30  	register long _ret  __asm__ ("r3");                                  \
    31  	register long _num  __asm__ ("r0") = (num);                          \
    32  									     \
    33  	__asm__ volatile (                                                   \
    34  		"	sc\n"                                                \
    35  		"	bns+ 1f\n"                                           \
    36  		"	neg  %0, %0\n"                                       \
    37  		"1:\n"                                                       \
    38  		: "=r"(_ret), "+r"(_num)                                     \
    39  		:                                                            \
    40  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4"  \
    41  	);                                                                   \
    42  	_ret;                                                                \
    43  })
    44  
    45  #define my_syscall1(num, arg1)                                               \
    46  ({                                                                           \
    47  	register long _ret  __asm__ ("r3");                                  \
    48  	register long _num  __asm__ ("r0") = (num);                          \
    49  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
    50  									     \
    51  	__asm__ volatile (                                                   \
    52  		"	sc\n"                                                \
    53  		"	bns+ 1f\n"                                           \
    54  		"	neg  %0, %0\n"                                       \
    55  		"1:\n"                                                       \
    56  		: "=r"(_ret), "+r"(_num)                                     \
    57  		: "0"(_arg1)                                                 \
    58  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5", "r4"  \
    59  	);                                                                   \
    60  	_ret;                                                                \
    61  })
    62  
    63  
    64  #define my_syscall2(num, arg1, arg2)                                         \
    65  ({                                                                           \
    66  	register long _ret  __asm__ ("r3");                                  \
    67  	register long _num  __asm__ ("r0") = (num);                          \
    68  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
    69  	register long _arg2 __asm__ ("r4") = (long)(arg2);                   \
    70  									     \
    71  	__asm__ volatile (                                                   \
    72  		"	sc\n"                                                \
    73  		"	bns+ 1f\n"                                           \
    74  		"	neg  %0, %0\n"                                       \
    75  		"1:\n"                                                       \
    76  		: "=r"(_ret), "+r"(_num), "+r"(_arg2)                        \
    77  		: "0"(_arg1)                                                 \
    78  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6", "r5"        \
    79  	);                                                                   \
    80  	_ret;                                                                \
    81  })
    82  
    83  
    84  #define my_syscall3(num, arg1, arg2, arg3)                                   \
    85  ({                                                                           \
    86  	register long _ret  __asm__ ("r3");                                  \
    87  	register long _num  __asm__ ("r0") = (num);                          \
    88  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
    89  	register long _arg2 __asm__ ("r4") = (long)(arg2);                   \
    90  	register long _arg3 __asm__ ("r5") = (long)(arg3);                   \
    91  									     \
    92  	__asm__ volatile (                                                   \
    93  		"	sc\n"                                                \
    94  		"	bns+ 1f\n"                                           \
    95  		"	neg  %0, %0\n"                                       \
    96  		"1:\n"                                                       \
    97  		: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3)           \
    98  		: "0"(_arg1)                                                 \
    99  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7", "r6"              \
   100  	);                                                                   \
   101  	_ret;                                                                \
   102  })
   103  
   104  
   105  #define my_syscall4(num, arg1, arg2, arg3, arg4)                             \
   106  ({                                                                           \
   107  	register long _ret  __asm__ ("r3");                                  \
   108  	register long _num  __asm__ ("r0") = (num);                          \
   109  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
   110  	register long _arg2 __asm__ ("r4") = (long)(arg2);                   \
   111  	register long _arg3 __asm__ ("r5") = (long)(arg3);                   \
   112  	register long _arg4 __asm__ ("r6") = (long)(arg4);                   \
   113  									     \
   114  	__asm__ volatile (                                                   \
   115  		"	sc\n"                                                \
   116  		"	bns+ 1f\n"                                           \
   117  		"	neg  %0, %0\n"                                       \
   118  		"1:\n"                                                       \
   119  		: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3),          \
   120  		  "+r"(_arg4)                                                \
   121  		: "0"(_arg1)                                                 \
   122  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8", "r7"                    \
   123  	);                                                                   \
   124  	_ret;                                                                \
   125  })
   126  
   127  
   128  #define my_syscall5(num, arg1, arg2, arg3, arg4, arg5)                       \
   129  ({                                                                           \
   130  	register long _ret  __asm__ ("r3");                                  \
   131  	register long _num  __asm__ ("r0") = (num);                          \
   132  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
   133  	register long _arg2 __asm__ ("r4") = (long)(arg2);                   \
   134  	register long _arg3 __asm__ ("r5") = (long)(arg3);                   \
   135  	register long _arg4 __asm__ ("r6") = (long)(arg4);                   \
   136  	register long _arg5 __asm__ ("r7") = (long)(arg5);                   \
   137  									     \
   138  	__asm__ volatile (                                                   \
   139  		"	sc\n"                                                \
   140  		"	bns+ 1f\n"                                           \
   141  		"	neg  %0, %0\n"                                       \
   142  		"1:\n"                                                       \
   143  		: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3),          \
   144  		  "+r"(_arg4), "+r"(_arg5)                                   \
   145  		: "0"(_arg1)                                                 \
   146  		: _NOLIBC_SYSCALL_CLOBBERLIST, "r8"                          \
   147  	);                                                                   \
   148  	_ret;                                                                \
   149  })
   150  
   151  #define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6)                 \
   152  ({                                                                           \
   153  	register long _ret  __asm__ ("r3");                                  \
   154  	register long _num  __asm__ ("r0") = (num);                          \
   155  	register long _arg1 __asm__ ("r3") = (long)(arg1);                   \
   156  	register long _arg2 __asm__ ("r4") = (long)(arg2);                   \
   157  	register long _arg3 __asm__ ("r5") = (long)(arg3);                   \
   158  	register long _arg4 __asm__ ("r6") = (long)(arg4);                   \
   159  	register long _arg5 __asm__ ("r7") = (long)(arg5);                   \
   160  	register long _arg6 __asm__ ("r8") = (long)(arg6);                   \
   161  									     \
   162  	__asm__ volatile (                                                   \
   163  		"	sc\n"                                                \
   164  		"	bns+ 1f\n"                                           \
   165  		"	neg  %0, %0\n"                                       \
   166  		"1:\n"                                                       \
   167  		: "=r"(_ret), "+r"(_num), "+r"(_arg2), "+r"(_arg3),          \
   168  		  "+r"(_arg4), "+r"(_arg5), "+r"(_arg6)                      \
   169  		: "0"(_arg1)                                                 \
   170  		: _NOLIBC_SYSCALL_CLOBBERLIST                                \
   171  	);                                                                   \
   172  	_ret;                                                                \
   173  })
   174  
   175  #ifndef __powerpc64__
   176  /* FIXME: For 32-bit PowerPC, with newer gcc compilers (e.g. gcc 13.1.0),
   177   * "omit-frame-pointer" fails with __attribute__((no_stack_protector)) but
   178   * works with __attribute__((__optimize__("-fno-stack-protector")))
   179   */
   180  #ifdef __no_stack_protector
   181  #undef __no_stack_protector
   182  #define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))
   183  #endif
   184  #endif /* !__powerpc64__ */
   185  
   186  /* startup code */
   187  void __attribute__((weak, noreturn, optimize("Os", "omit-frame-pointer"))) __no_stack_protector _start(void)
   188  {
   189  #ifdef __powerpc64__
   190  #if _CALL_ELF == 2
   191  	/* with -mabi=elfv2, save TOC/GOT pointer to r2
   192  	 * r12 is global entry pointer, we use it to compute TOC from r12
   193  	 * https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf
   194  	 * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf
   195  	 */
   196  	__asm__ volatile (
   197  		"addis  2, 12, .TOC. - _start@ha\n"
   198  		"addi   2,  2, .TOC. - _start@l\n"
   199  	);
   200  #endif /* _CALL_ELF == 2 */
   201  
   202  	__asm__ volatile (
   203  		"mr     3, 1\n"         /* save stack pointer to r3, as arg1 of _start_c */
   204  		"clrrdi 1, 1, 4\n"      /* align the stack to 16 bytes                   */
   205  		"li     0, 0\n"         /* zero the frame pointer                        */
   206  		"stdu   1, -32(1)\n"    /* the initial stack frame                       */
   207  		"bl     _start_c\n"     /* transfer to c runtime                         */
   208  	);
   209  #else
   210  	__asm__ volatile (
   211  		"mr     3, 1\n"         /* save stack pointer to r3, as arg1 of _start_c */
   212  		"clrrwi 1, 1, 4\n"      /* align the stack to 16 bytes                   */
   213  		"li     0, 0\n"         /* zero the frame pointer                        */
   214  		"stwu   1, -16(1)\n"    /* the initial stack frame                       */
   215  		"bl     _start_c\n"     /* transfer to c runtime                         */
   216  	);
   217  #endif
   218  	__builtin_unreachable();
   219  }
   220  
   221  #endif /* _NOLIBC_ARCH_POWERPC_H */