brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · ee2fdb8 Raw
222 lines · c
1/* SPDX-License-Identifier: LGPL-2.1 OR MIT */2/*3 * PowerPC specific definitions for NOLIBC4 * Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org>5 */6 7#ifndef _NOLIBC_ARCH_POWERPC_H8#define _NOLIBC_ARCH_POWERPC_H9 10#include "compiler.h"11#include "crt.h"12 13/* Syscalls for PowerPC :14 *   - stack is 16-byte aligned15 *   - syscall number is passed in r016 *   - arguments are in r3, r4, r5, r6, r7, r8, r917 *   - the system call is performed by calling "sc"18 *   - syscall return comes in r3, and the summary overflow bit is checked19 *     to know if an error occurred, in which case errno is in r3.20 *   - the arguments are cast to long and assigned into the target21 *     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#if !defined(__powerpc64__) && !defined(__clang__)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)) but178 * works with __attribute__((__optimize__("-fno-stack-protector")))179 */180#ifdef __no_stack_protector181#undef __no_stack_protector182#define __no_stack_protector __attribute__((__optimize__("-fno-stack-protector")))183#endif184#endif /* !__powerpc64__ */185 186/* startup code */187void __attribute__((weak, noreturn)) __nolibc_entrypoint __no_stack_protector _start(void)188{189#ifdef __powerpc64__190#if _CALL_ELF == 2191	/* with -mabi=elfv2, save TOC/GOT pointer to r2192	 * r12 is global entry pointer, we use it to compute TOC from r12193	 * https://www.llvm.org/devmtg/2014-04/PDFs/Talks/Euro-LLVM-2014-Weigand.pdf194	 * https://refspecs.linuxfoundation.org/ELF/ppc64/PPC-elf64abi.pdf195	 */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#else210	__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#endif218	__nolibc_entrypoint_epilogue();219}220 221#endif /* _NOLIBC_ARCH_POWERPC_H */222