/* Copyright (C) 1996, 1997, 1998, 2004 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   02111-1307 USA.  */

#include <sysdep-cancel.h>
#include <socketcall.h>

#define P(a, b) P2(a, b)
#define P2(a, b) a##b

	.text
/* The socket-oriented system calls are handled unusally in Linux.
   They are all gated through the single `socketcall' system call number.
   `socketcall' takes two arguments: the first is the subcode, specifying
   which socket function is being called; and the second is a pointer to
   the arguments to the specific function.

   The .S files for the other calls just #define socket and #include this.  */

#ifndef __socket
#ifndef NO_WEAK_ALIAS
#define __socket P(__,socket)
#else
#define __socket socket
#endif
#endif

#ifndef NARGS
#define NARGS 3			/* If we were called with no wrapper, this is really socket() */
#endif

#define _CONCAT(X,Y) X##Y
#define CONCAT(X,Y) _CONCAT(X,Y)

.globl __socket
ENTRY (__socket)
.Lbegin:
	addi	sp, #-STACK_SPACE(NARGS), sp
	CONCAT(SAVE_ARGS_,NARGS)
	
#if defined NEED_CANCELLATION && defined CENABLE
	SINGLE_THREAD_P
	bne icc0,0,.Lthreaded
#endif

	setlos.p #SYS_ify (socketcall), gr7 /* System call number in gr7.  */

	/* Use ## so `socket' is a separate token that might be #define'd.  */
	setlos #P (SOCKOP_,socket), gr8	/* Subcode is first arg to syscall.  */
	addi.p	sp, 8, gr9		/* Address of args is 2nd arg.  */
	setlos	-4096, gr4

	/* Do the system call trap.  */
	tra	gr0, gr0

	subcc.p	gr8, gr4, gr0, icc0
	addi	sp, #STACK_SPACE(NARGS), sp
	blslr	icc0,0x2
	SYSCALL_ERROR_HANDLER

#if defined NEED_CANCELLATION && defined CENABLE
.Lthreaded:
	/* Enable asynchronous cancellation.  */
	CENABLE
	mov	gr8, gr4

	setlos.p #SYS_ify (socketcall), gr7 /* System call number in gr7.  */

	/* Use ## so `socket' is a separate token that might be #define'd.  */
	setlos #P (SOCKOP_,socket), gr8	/* Subcode is first arg to syscall.  */

	ldi.p	@(sp, 4), gr15
	addi	sp, 8, gr9		/* Address of args is 2nd arg.  */

	/* Do the system call trap.  */
	tra	gr0, gr0

	sti	gr8, @(sp,8)
	mov	gr4, gr8
	CDISABLE

	ldd.p	@(sp, gr0), gr14
	setlos	#-4096, gr4
	ldi	@(sp, 8), gr8
	movgs	gr14, lr
	
	subcc.p	gr8, gr4, gr0, icc0
	addi	sp, #STACK_SPACE(NARGS), sp
	blslr	icc0,0x2
	SYSCALL_ERROR_HANDLER
.Lend:

	/* Create unwinding information for the syscall wrapper.  */
	.section .eh_frame,"a",@progbits
.Lstartframe:
	/* Length of the CIE.  */
	.long	.Lendcie-.Lstartcie

.Lstartcie:
	/* CIE ID.  */
	.long	 0

	/* Version number.  */
	.byte	 1

	/* NUL-terminated augmentation string.  */
	.string	 ""

	/* Code alignment factor.  */
	.uleb128 1

	/* Data alignment factor.  */
	.sleb128 -4

	/* Return address register column.  */
	.byte	 169

	/* DW_CFA_def_cfa (register 1, offset 0).  */
	.byte	 0xc
	.uleb128 1
	.uleb128 0

	.p2align 2,0
.Lendcie:
	/* Length of the FDE.  */
	.long	 .Lendfde-.Lstartfde

.Lstartfde:
	/* CIE pointer.  */
	.long	 .Lstartfde-.Lstartframe

	/* Start address of the code.  */
	.long	 .Lbegin

	/* Length of the code.  */
	.long	 .Lend - .Lbegin

	/* DW_CFA_def_cfa_offset (STACKSPACE (NARGS)).  */
	.byte	 14
	.uleb128 STACK_SPACE (NARGS)
	
	/* DW_CFA_offset_extended (r169 at -STACKSPACE (NARGS)).  */
	.byte	 5
	.uleb128 169
	.uleb128 STACK_SPACE (NARGS) / 4

	.p2align 2,0
.Lendfde:
	.previous
#endif
	
PSEUDO_END (__socket)

#ifndef NO_WEAK_ALIAS
weak_alias (__socket, socket)
#endif
