root/usr/src/lib/libc/amd64/sys/door.S
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

        .file   "door.s"

#include "SYS.h"
#include <sys/door.h>

        /*
         * weak aliases for public interfaces
         */
        ANSI_PRAGMA_WEAK2(door_bind,__door_bind,function)
        ANSI_PRAGMA_WEAK2(door_getparam,__door_getparam,function)
        ANSI_PRAGMA_WEAK2(door_info,__door_info,function)
        ANSI_PRAGMA_WEAK2(door_revoke,__door_revoke,function)
        ANSI_PRAGMA_WEAK2(door_setparam,__door_setparam,function)

/*
 * Offsets within struct door_results
 */
#define DOOR_COOKIE     _MUL(0, CLONGSIZE)
#define DOOR_DATA_PTR   _MUL(1, CLONGSIZE)
#define DOOR_DATA_SIZE  _MUL(2, CLONGSIZE)
#define DOOR_DESC_PTR   _MUL(3, CLONGSIZE)
#define DOOR_DESC_SIZE  _MUL(4, CLONGSIZE)
#define DOOR_PC         _MUL(5, CLONGSIZE)
#define DOOR_SERVERS    _MUL(6, CLONGSIZE)
#define DOOR_INFO_PTR   _MUL(7, CLONGSIZE)

/*
 * All of the syscalls except door_return() follow the same pattern.  The
 * subcode goes in %r9, after all of the other arguments.
 */
#define DOOR_SYSCALL(name, code)                                        \
        ENTRY(name);                                                    \
        movq    $code, %r9;             /* subcode */                   \
        SYSTRAP_RVAL1(door);                                            \
        SYSCERROR;                                                      \
        RET;                                                            \
        SET_SIZE(name)

        DOOR_SYSCALL(__door_bind,       DOOR_BIND)
        DOOR_SYSCALL(__door_call,       DOOR_CALL)
        DOOR_SYSCALL(__door_create,     DOOR_CREATE)
        DOOR_SYSCALL(__door_getparam,   DOOR_GETPARAM)
        DOOR_SYSCALL(__door_info,       DOOR_INFO)
        DOOR_SYSCALL(__door_revoke,     DOOR_REVOKE)
        DOOR_SYSCALL(__door_setparam,   DOOR_SETPARAM)
        DOOR_SYSCALL(__door_ucred,      DOOR_UCRED)
        DOOR_SYSCALL(__door_unbind,     DOOR_UNBIND)
        DOOR_SYSCALL(__door_unref,      DOOR_UNREFSYS)

/*
 * int
 * __door_return(
 *      void                    *data_ptr,
 *      size_t                  data_size,      (in bytes)
 *      door_return_desc_t      *door_ptr,      (holds returned desc info)
 *      caddr_t                 stack_base,
 *      size_t                  stack_size)
 */
        ENTRY(__door_return)
        pushq   %rbp
        movq    %rsp, %rbp
        subq    $0x8, %rsp
        /*
         * Save stack_base (arg4), since %rcx will be trashed if the syscall
         * returns via sysret
         */
        movq    %rcx, -0x8(%rbp)

door_restart:
        movq    $DOOR_RETURN, %r9       /* subcode */
        SYSTRAP_RVAL1(door)
        jb      2f                      /* errno is set */
        /*
         * On return, we're serving a door_call.  Our stack looks like this:
         *
         *              descriptors (if any)
         *              data (if any)
         *       sp->   struct door_results
         */
        movl    DOOR_SERVERS(%rsp), %eax
        andl    %eax, %eax      /* test nservers */
        jg      1f
        /*
         * this is the last server thread - call creation func for more
         */
        movq    DOOR_INFO_PTR(%rsp), %rdi
        call    door_depletion_cb@PLT
1:
        /* Call the door server function now */
        movq    DOOR_COOKIE(%rsp), %rdi
        movq    DOOR_DATA_PTR(%rsp), %rsi
        movq    DOOR_DATA_SIZE(%rsp), %rdx
        movq    DOOR_DESC_PTR(%rsp), %rcx
        movq    DOOR_DESC_SIZE(%rsp), %r8
        movq    DOOR_PC(%rsp), %rax
        call    *%rax
        /* Exit the thread if we return here */
        movq    $0, %rdi
        call    _thrp_terminate
        /* NOTREACHED */
2:
        /*
         * Error during door_return call.  Repark the thread in the kernel if
         * the error code is EINTR (or ERESTART) and this lwp is still part
         * of the same process.
         */
        cmpl    $ERESTART, %eax         /* ERESTART is same as EINTR */
        jne     3f
        movl    $EINTR, %eax
3:
        cmpl    $EINTR, %eax            /* interrupted while waiting? */
        jne     4f                      /* if not, return the error */

        call    getpid                  /* get current process id */
        movq    _daref_(door_create_pid), %rdx
        movl    0(%rdx), %edx
        cmpl    %eax, %edx              /* same process? */
        movl    $EINTR, %eax    /* if no, return EINTR (child of forkall) */
        jne     4f

        movq    $0, %rdi                /* clear arguments and restart */
        movq    $0, %rsi
        movq    $0, %rdx
        movq    -0x8(%rbp), %rcx        /* Restore arg4 (stack_base) */
        jmp     door_restart

4:
        leave
        jmp     __cerror
        SET_SIZE(__door_return)