root/usr/src/lib/libc/i386/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.
 *
 * Copyright 2021 Tintri by DDN, Inc. All rights reserved.
 */

        .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 argument 6, which means we have to copy our
 * arguments into a new bit of stack, large enough to include the
 * subcode.  We fill the unused positions with zeros.
 */
#define DOOR_SYSCALL(name, code, copy_args)                             \
        ENTRY(name);                                                    \
        pushl   %ebp;                                                   \
        movl    %esp, %ebp;                                             \
        pushl   $code;          /* syscall subcode, arg 6 */            \
        pushl   $0;             /* dummy arg 5 */                       \
        pushl   $0;             /* dummy arg 4 */                       \
        copy_args;              /* args 1, 2, 3 */                      \
        pushl   $0;             /* dummy return PC */                   \
        SYSTRAP_RVAL1(door);                                            \
        jae     1f;                                                     \
        addl    $28, %esp;                                              \
        leave;                                                          \
        jmp     __cerror;                                               \
1:                                                                      \
        addl    $28, %esp;                                              \
        leave;                                                          \
        ret;                                                            \
        SET_SIZE(name)

#define COPY_0                                                          \
        pushl   $0;             /* dummy */                             \
        pushl   $0;             /* dummy */                             \
        pushl   $0              /* dummy */

#define COPY_1                                                          \
        pushl   $0;             /* dummy */                             \
        pushl   $0;             /* dummy */                             \
        pushl   8(%ebp)         /* 1 */

#define COPY_2                                                          \
        pushl   $0;             /* dummy */                             \
        pushl   12(%ebp);       /* 2 */                                 \
        pushl   8(%ebp)         /* 1 */

#define COPY_3                                                          \
        pushl   16(%ebp);       /* 3 */                                 \
        pushl   12(%ebp);       /* 2 */                                 \
        pushl   8(%ebp)         /* 1 */

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

/*
 * 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)
        movl    %esp, %edx              / Save pointer to args

        pushl   %edi                    / save old %edi and %esi
        pushl   %esi                    / and use them to hold the
        movl    16(%edx), %esi          / stack pointer and
        movl    20(%edx), %edi          / size.

        pushl   $DOOR_RETURN            / syscall subcode
        pushl   %edi                    / size of user stack
        pushl   %esi                    / base of user stack
        pushl   12(%edx)                / desc arguments ptr
        pushl   8(%edx)                 / data size
        pushl   4(%edx)                 / data ptr
        pushl   0(%edx)                 / dummy return PC

door_restart:
        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
         *
         * The stack will be aligned to 16 bytes; we must maintain that
         * alignment prior to any call instruction.
         * struct door_results has the arguments in place for the server proc,
         * so we just call it directly.
         */
        movl    DOOR_SERVERS(%esp), %eax
        andl    %eax, %eax      /* test nservers */
        jg      1f
        /*
         * this is the last server thread - call creation func for more
         */
        movl    DOOR_INFO_PTR(%esp), %eax
        subl    $12, %esp
        pushl   %eax            /* door_info_t * */
        call    door_depletion_cb@PLT
        addl    $16, %esp
1:
        /* Call the door server function now */
        movl    DOOR_PC(%esp), %eax
        call    *%eax
        /* Exit the thread if we return here */
        subl    $12, %esp
        pushl   $0
        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.
         *
         * If the error code is EINTR or ERESTART, our stack may have been
         * corrupted by a partial door call, so we refresh the system call
         * arguments.
         */
        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 */
        _prologue_
        call    getpid
        movl    _daref_(door_create_pid), %edx
        movl    0(%edx), %edx
        _epilogue_
        cmpl    %eax, %edx              /* same process? */
        movl    $EINTR, %eax    /* if no, return EINTR (child of forkall) */
        jne     4f
        movl    $0, 4(%esp)             /* clear arguments and restart */
        movl    $0, 8(%esp)
        movl    $0, 12(%esp)
        movl    %esi, 16(%esp)          /* refresh sp */
        movl    %edi, 20(%esp)          /* refresh ssize */
        movl    $DOOR_RETURN, 24(%esp)  /* refresh syscall subcode */
        jmp     door_restart
4:
        /* Something bad happened during the door_return */
        addl    $28, %esp
        popl    %esi
        popl    %edi
        jmp     __cerror
        SET_SIZE(__door_return)