1628e3cbeSEdward Pilatowicz/* 2628e3cbeSEdward Pilatowicz * CDDL HEADER START 3628e3cbeSEdward Pilatowicz * 4628e3cbeSEdward Pilatowicz * The contents of this file are subject to the terms of the 5628e3cbeSEdward Pilatowicz * Common Development and Distribution License (the "License"). 6628e3cbeSEdward Pilatowicz * You may not use this file except in compliance with the License. 7628e3cbeSEdward Pilatowicz * 8628e3cbeSEdward Pilatowicz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9628e3cbeSEdward Pilatowicz * or http://www.opensolaris.org/os/licensing. 10628e3cbeSEdward Pilatowicz * See the License for the specific language governing permissions 11628e3cbeSEdward Pilatowicz * and limitations under the License. 12628e3cbeSEdward Pilatowicz * 13628e3cbeSEdward Pilatowicz * When distributing Covered Code, include this CDDL HEADER in each 14628e3cbeSEdward Pilatowicz * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15628e3cbeSEdward Pilatowicz * If applicable, add the following below this CDDL HEADER, with the 16628e3cbeSEdward Pilatowicz * fields enclosed by brackets "[]" replaced with your own identifying 17628e3cbeSEdward Pilatowicz * information: Portions Copyright [yyyy] [name of copyright owner] 18628e3cbeSEdward Pilatowicz * 19628e3cbeSEdward Pilatowicz * CDDL HEADER END 20628e3cbeSEdward Pilatowicz */ 211b30f017Sgvasick 22628e3cbeSEdward Pilatowicz/* 2380e2ca85S * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 24628e3cbeSEdward Pilatowicz */ 25628e3cbeSEdward Pilatowicz 2680e2ca85S#include <brand_misc.h> 27628e3cbeSEdward Pilatowicz 28b72c368aS/* 29b72c368aS * Each JMP must occupy 16 bytes 30b72c368aS */ 31b72c368aS#define JMP \ 3280e2ca85S pushl $_CONST(. - brand_handler_table); \ 3380e2ca85S jmp brand_handler; \ 34*55fea89dSDan Cross .align 16; 35b72c368aS 36b72c368aS#define JMP4 JMP; JMP; JMP; JMP 37b72c368aS#define JMP16 JMP4; JMP4; JMP4; JMP4 38b72c368aS#define JMP64 JMP16; JMP16; JMP16; JMP16 39b72c368aS#define JMP256 JMP64; JMP64; JMP64; JMP64 40b72c368aS 41628e3cbeSEdward Pilatowicz#if defined(lint) 42628e3cbeSEdward Pilatowicz 43b72c368aSvoid 4480e2ca85Sbrand_handler_table(void) 45b72c368aS{} 46b72c368aS 47628e3cbeSEdward Pilatowiczvoid 4880e2ca85Sbrand_handler(void) 49628e3cbeSEdward Pilatowicz{ 50628e3cbeSEdward Pilatowicz} 51628e3cbeSEdward Pilatowicz 52628e3cbeSEdward Pilatowicz#else /* lint */ 53628e3cbeSEdward Pilatowicz 54b72c368aS /* 55b72c368aS * On entry to this table, %eax will hold the return address. The 56b72c368aS * location where we enter the table is a function of the system 57b72c368aS * call number. The table needs the same alignment as the individual 58b72c368aS * entries. 59b72c368aS */ 60b72c368aS .align 16 6180e2ca85S ENTRY_NP(brand_handler_table) 62b72c368aS JMP256 6380e2ca85S SET_SIZE(brand_handler_table) 64b72c368aS 65628e3cbeSEdward Pilatowicz#define PIC_SETUP(r) \ 66628e3cbeSEdward Pilatowicz call 9f; \ 67628e3cbeSEdward Pilatowicz9: \ 68628e3cbeSEdward Pilatowicz popl r; \ 69628e3cbeSEdward Pilatowicz addl $_GLOBAL_OFFSET_TABLE_ + [. - 9b], r 70628e3cbeSEdward Pilatowicz 71628e3cbeSEdward Pilatowicz /* 72b72c368aS * %eax - userland return address 73628e3cbeSEdward Pilatowicz * stack contains: 74b72c368aS * | -------------------------------------- 75b72c368aS * v 4 | syscall arguments | 76b72c368aS * %esp+0 | syscall number | 77628e3cbeSEdward Pilatowicz * -------------------------------------- 78628e3cbeSEdward Pilatowicz */ 7980e2ca85S ENTRY_NP(brand_handler) 80628e3cbeSEdward Pilatowicz pushl %ebp /* allocate a stack frame */ 81628e3cbeSEdward Pilatowicz movl %esp, %ebp 82628e3cbeSEdward Pilatowicz 83628e3cbeSEdward Pilatowicz /* Save registers at the time of the syscall. */ 84628e3cbeSEdward Pilatowicz movl $0, EH_LOCALS_GREG(TRAPNO)(%ebp) 85628e3cbeSEdward Pilatowicz movl $0, EH_LOCALS_GREG(ERR)(%ebp) 86628e3cbeSEdward Pilatowicz movl %ebx, EH_LOCALS_GREG(EBX)(%ebp) 87628e3cbeSEdward Pilatowicz movl %ecx, EH_LOCALS_GREG(ECX)(%ebp) 88628e3cbeSEdward Pilatowicz movl %edx, EH_LOCALS_GREG(EDX)(%ebp) 89628e3cbeSEdward Pilatowicz movl %edi, EH_LOCALS_GREG(EDI)(%ebp) 90628e3cbeSEdward Pilatowicz movl %esi, EH_LOCALS_GREG(ESI)(%ebp) 911b30f017Sgvasick mov %cs, EH_LOCALS_GREG(CS)(%ebp) 921b30f017Sgvasick mov %ds, EH_LOCALS_GREG(DS)(%ebp) 931b30f017Sgvasick mov %es, EH_LOCALS_GREG(ES)(%ebp) 941b30f017Sgvasick mov %fs, EH_LOCALS_GREG(FS)(%ebp) 951b30f017Sgvasick mov %gs, EH_LOCALS_GREG(GS)(%ebp) 96628e3cbeSEdward Pilatowicz pushfl /* save syscall flags */ 97628e3cbeSEdward Pilatowicz popl %ecx 98628e3cbeSEdward Pilatowicz movl %ecx, EH_LOCALS_GREG(EFL)(%ebp) 99628e3cbeSEdward Pilatowicz movl EH_ARGS_OFFSET(0)(%ebp), %ecx /* save syscall ebp */ 100628e3cbeSEdward Pilatowicz movl %ecx, EH_LOCALS_GREG(EBP)(%ebp) 101628e3cbeSEdward Pilatowicz movl %ebp, %ecx /* save syscall esp */ 102628e3cbeSEdward Pilatowicz addl $CPTRSIZE, %ecx 103628e3cbeSEdward Pilatowicz movl %ecx, EH_LOCALS_GREG(ESP)(%ebp) 104b72c368aS 105b72c368aS /* 10680e2ca85S * The kernel drops us into the middle of the brand_handle_table 107b72c368aS * above that then pushes that table offset onto the stack, and calls 10880e2ca85S * into brand_handler. That offset indicates the system call number 10980e2ca85S * while %eax holds the return address for the system call. We replace 11080e2ca85S * the value on the stack with the return address, and use the value to 111b72c368aS * compute the system call number by dividing by the table entry size. 112b72c368aS */ 113b72c368aS xchgl CPTRSIZE(%ebp), %eax /* swap JMP table offset and ret addr */ 114b72c368aS shrl $4, %eax /* table_offset/size = syscall num */ 115b72c368aS movl %eax, EH_LOCALS_GREG(EAX)(%ebp) /* save syscall num */ 116628e3cbeSEdward Pilatowicz 117628e3cbeSEdward Pilatowicz /* 118628e3cbeSEdward Pilatowicz * Finish setting up our stack frame. We would normally do this 119628e3cbeSEdward Pilatowicz * upon entry to this function, but in this case we delayed it 120628e3cbeSEdward Pilatowicz * because a "sub" operation can modify flags and we wanted to 121628e3cbeSEdward Pilatowicz * save the flags into the gregset_t above before they get modified. 122628e3cbeSEdward Pilatowicz * 12380e2ca85S * Our stack frame format is documented in brand_misc.h. 124628e3cbeSEdward Pilatowicz */ 125628e3cbeSEdward Pilatowicz subl $EH_LOCALS_SIZE, %esp 126628e3cbeSEdward Pilatowicz 127628e3cbeSEdward Pilatowicz /* Look up the system call's entry in the sysent table */ 128628e3cbeSEdward Pilatowicz PIC_SETUP(%ecx) 12980e2ca85S movl brand_sysent_table@GOT(%ecx), %edx /* %edx = sysent_table */ 130628e3cbeSEdward Pilatowicz shll $3, %eax /* each entry is 8 bytes */ 131628e3cbeSEdward Pilatowicz add %eax, %edx /* %edx = sysent entry address */ 132628e3cbeSEdward Pilatowicz 133628e3cbeSEdward Pilatowicz /* 134628e3cbeSEdward Pilatowicz * Get the return value flag and the number of arguments from the 135628e3cbeSEdward Pilatowicz * sysent table. 136628e3cbeSEdward Pilatowicz */ 137628e3cbeSEdward Pilatowicz movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ 138628e3cbeSEdward Pilatowicz andl $RV_MASK, %ecx /* strip out number of args */ 139628e3cbeSEdward Pilatowicz movl %ecx, EH_LOCALS_RVFLAG(%ebp) /* save rv flag */ 140628e3cbeSEdward Pilatowicz movl CPTRSIZE(%edx), %ecx /* number of args + rv flag */ 141628e3cbeSEdward Pilatowicz andl $NARGS_MASK, %ecx /* strip out rv flag */ 142628e3cbeSEdward Pilatowicz 143628e3cbeSEdward Pilatowicz /* 144628e3cbeSEdward Pilatowicz * Setup arguments for our emulation call. Our input arguments, 145628e3cbeSEdward Pilatowicz * 0 to N, will become emulation call arguments 1 to N+1. 146628e3cbeSEdward Pilatowicz * %ecx == number of arguments. 147628e3cbeSEdward Pilatowicz */ 148628e3cbeSEdward Pilatowicz movl %ebp, %esi /* args are at 12(%ebp) */ 149*55fea89dSDan Cross addl $EH_ARGS_OFFSET(3), %esi 150628e3cbeSEdward Pilatowicz movl %esp, %edi /* copy args to 4(%esp) */ 151*55fea89dSDan Cross addl $EH_ARGS_OFFSET(1), %edi 152628e3cbeSEdward Pilatowicz rep; smovl /* copy: (%esi) -> (%edi) */ 153628e3cbeSEdward Pilatowicz /* copy: %ecx 32-bit words */ 154628e3cbeSEdward Pilatowicz movl EH_LOCALS_GREG(ESI)(%ebp), %esi /* restore %esi */ 155628e3cbeSEdward Pilatowicz movl EH_LOCALS_GREG(EDI)(%ebp), %edi /* restore %edi */ 156628e3cbeSEdward Pilatowicz 157628e3cbeSEdward Pilatowicz /* 158628e3cbeSEdward Pilatowicz * The first parameter to the emulation callback function is a 159628e3cbeSEdward Pilatowicz * pointer to a sysret_t structure. 160628e3cbeSEdward Pilatowicz */ 161628e3cbeSEdward Pilatowicz movl %ebp, %ecx 162628e3cbeSEdward Pilatowicz addl $EH_LOCALS_SYSRET, %ecx 163628e3cbeSEdward Pilatowicz movl %ecx, EH_ARGS_OFFSET(0)(%esp) /* arg0 == sysret_t ptr */ 164628e3cbeSEdward Pilatowicz 165628e3cbeSEdward Pilatowicz /* invoke the emulation routine */ 16680e2ca85S ALTENTRY(brand_handler_savepc) 167628e3cbeSEdward Pilatowicz call *(%edx) /* call emulation routine */ 168628e3cbeSEdward Pilatowicz 169628e3cbeSEdward Pilatowicz /* restore scratch registers */ 170628e3cbeSEdward Pilatowicz movl EH_LOCALS_GREG(ECX)(%ebp), %ecx /* restore %ecx */ 171628e3cbeSEdward Pilatowicz movl EH_LOCALS_GREG(EDX)(%ebp), %edx /* restore %edx */ 172628e3cbeSEdward Pilatowicz 173628e3cbeSEdward Pilatowicz /* Check for syscall emulation success or failure */ 174628e3cbeSEdward Pilatowicz cmpl $0, %eax /* check for an error */ 175628e3cbeSEdward Pilatowicz je success 176628e3cbeSEdward Pilatowicz stc /* failure, set carry flag */ 177628e3cbeSEdward Pilatowicz jmp return /* return, %rax == errno */ 178628e3cbeSEdward Pilatowicz 179628e3cbeSEdward Pilatowiczsuccess: 180628e3cbeSEdward Pilatowicz /* There is always at least one return value. */ 181628e3cbeSEdward Pilatowicz movl EH_LOCALS_SYSRET1(%ebp), %eax /* %eax == sys_rval1 */ 182628e3cbeSEdward Pilatowicz cmpl $RV_DEFAULT, EH_LOCALS_RVFLAG(%ebp) /* check rv flag */ 183628e3cbeSEdward Pilatowicz je clear_carry 184628e3cbeSEdward Pilatowicz mov EH_LOCALS_SYSRET2(%ebp), %edx /* %edx == sys_rval2 */ 185628e3cbeSEdward Pilatowiczclear_carry: 186628e3cbeSEdward Pilatowicz clc /* success, clear carry flag */ 187628e3cbeSEdward Pilatowicz 188628e3cbeSEdward Pilatowiczreturn: 189628e3cbeSEdward Pilatowicz movl %ebp, %esp /* restore stack */ 190628e3cbeSEdward Pilatowicz popl %ebp 191628e3cbeSEdward Pilatowicz ret /* ret to instr after syscall */ 19280e2ca85S SET_SIZE(brand_handler) 193628e3cbeSEdward Pilatowicz 194628e3cbeSEdward Pilatowicz 195628e3cbeSEdward Pilatowicz#endif /* lint */ 196