106b6cf06S /* 206b6cf06S * CDDL HEADER START 306b6cf06S * 406b6cf06S * The contents of this file are subject to the terms of the 506b6cf06S * Common Development and Distribution License (the "License"). 606b6cf06S * You may not use this file except in compliance with the License. 706b6cf06S * 806b6cf06S * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 906b6cf06S * or http://www.opensolaris.org/os/licensing. 1006b6cf06S * See the License for the specific language governing permissions 1106b6cf06S * and limitations under the License. 1206b6cf06S * 1306b6cf06S * When distributing Covered Code, include this CDDL HEADER in each 1406b6cf06S * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1506b6cf06S * If applicable, add the following below this CDDL HEADER, with the 1606b6cf06S * fields enclosed by brackets "[]" replaced with your own identifying 1706b6cf06S * information: Portions Copyright [yyyy] [name of copyright owner] 1806b6cf06S * 1906b6cf06S * CDDL HEADER END 2006b6cf06S */ 2106b6cf06S /* 2280e2ca85S * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23*abe1e6b3SAndy Fiddaman * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 2406b6cf06S */ 2506b6cf06S 2606b6cf06S #ifndef _COMMON_BRAND_ASM_H 2706b6cf06S #define _COMMON_BRAND_ASM_H 2806b6cf06S 2906b6cf06S #ifdef __cplusplus 3006b6cf06S extern "C" { 3106b6cf06S #endif 3206b6cf06S 3306b6cf06S #ifndef lint 3406b6cf06S 3506b6cf06S #include <sys/asm_linkage.h> 3606b6cf06S #include <sys/privregs.h> 3706b6cf06S #include <sys/segments.h> 3806b6cf06S #include "assym.h" 3906b6cf06S 4006b6cf06S #endif /* lint */ 4106b6cf06S 4206b6cf06S #ifdef _ASM /* The remainder of this file is only for assembly files */ 4306b6cf06S 4406b6cf06S #if defined(__amd64) 4506b6cf06S /* 4606b6cf06S * Common to all 64-bit callbacks: 4706b6cf06S * 4806b6cf06S * We're running on the kernel's %gs. 4906b6cf06S * 5006b6cf06S * We return directly to userland, bypassing the _update_sregs logic, so 5106b6cf06S * the routine must NOT do anything that could cause a context switch. 5206b6cf06S * 5306b6cf06S * %rax - syscall number 5406b6cf06S * 5506b6cf06S * When called, all general registers, except for %r15, are as they were when 5606b6cf06S * the user process made the system call. %r15 is available to the callback as 5706b6cf06S * a scratch register. If the callback returns to the kernel path, %r15 does 5806b6cf06S * not have to be restored to the user value. If the callback returns to the 5906b6cf06S * userlevel emulation code, the callback should restore %r15 if the emulation 6006b6cf06S * depends on the original userlevel value. 6106b6cf06S * 6206b6cf06S * 64-BIT INTERPOSITION STACK 6306b6cf06S * On entry to the callback the stack looks like this: 6406b6cf06S * -------------------------------------- 6506b6cf06S * 32 | callback pointer | 6606b6cf06S * 24 | saved stack pointer | 6706b6cf06S * | 16 | lwp pointer | 6806b6cf06S * v 8 | user return address | 69*abe1e6b3SAndy Fiddaman * 0 | BRAND_CALLBACK()'s return addr | 7006b6cf06S * -------------------------------------- 7106b6cf06S */ 7206b6cf06S 7306b6cf06S #define V_COUNT 5 7406b6cf06S #define V_END (CLONGSIZE * 5) 7506b6cf06S #define V_SSP (CLONGSIZE * 3) 7606b6cf06S #define V_LWP (CLONGSIZE * 2) 7706b6cf06S #define V_URET_ADDR (CLONGSIZE * 1) 7806b6cf06S #define V_CB_ADDR (CLONGSIZE * 0) 7906b6cf06S 8006b6cf06S #define SP_REG %rsp 8106b6cf06S #define SCR_REG %r15 8206b6cf06S #define SCR_REGB %r15b 8306b6cf06S #define SYSCALL_REG %rax 8406b6cf06S 8506b6cf06S /* 8606b6cf06S * 64-BIT INT STACK 8706b6cf06S * For int callbacks (e.g. int91) the saved stack pointer (V_SSP) points at 8806b6cf06S * the state saved when we took the interrupt: 8906b6cf06S * -------------------------------------- 9006b6cf06S * | 32 | user's %ss | 9106b6cf06S * | 24 | user's %esp | 9206b6cf06S * | 16 | EFLAGS register | 9306b6cf06S * v 8 | user's %cs | 9406b6cf06S * 0 | user's %eip (user return address) | 9506b6cf06S * -------------------------------------- 9606b6cf06S */ 9706b6cf06S #define V_U_EIP (CLONGSIZE * 0) 9806b6cf06S 9906b6cf06S #else /* !__amd64 */ 10006b6cf06S /* 10106b6cf06S * 32-BIT INTERPOSITION STACK 10206b6cf06S * When our syscall interposition callback entry point gets invoked the 10306b6cf06S * stack looks like this: 10406b6cf06S * -------------------------------------- 10506b6cf06S * | 16 | 'scratch space' | 10606b6cf06S * | 12 | user's %ebx | 10706b6cf06S * | 8 | user's %gs selector | 10806b6cf06S * v 4 | lwp pointer | 10906b6cf06S * 0 | callback wrapper return addr | 11006b6cf06S * -------------------------------------- 11106b6cf06S */ 11206b6cf06S 11306b6cf06S #define V_COUNT 5 11406b6cf06S #define V_END (CLONGSIZE * 5) 11506b6cf06S #define V_U_EBX (CLONGSIZE * 3) 11606b6cf06S #define V_LWP (CLONGSIZE * 1) 11706b6cf06S #define V_CB_ADDR (CLONGSIZE * 0) 11806b6cf06S 11906b6cf06S #define SP_REG %esp 12006b6cf06S #define SCR_REG %ebx 12106b6cf06S #define SCR_REGB %bl 12206b6cf06S #define SYSCALL_REG %eax 12306b6cf06S 12406b6cf06S /* 12506b6cf06S * 32-BIT INT STACK 12606b6cf06S * For the lcall handler for 32-bit OS (i.e. xxx_brand_syscall_callback) 12706b6cf06S * above the stack contents common to all callbacks is the int/lcall-specific 12806b6cf06S * state: 12906b6cf06S * -------------------------------------- 13006b6cf06S * | 36 | user's %ss | 13106b6cf06S * | 32 | user's %esp | 13206b6cf06S * | 28 | EFLAGS register | 13306b6cf06S * v 24 | user's %cs | 13406b6cf06S * 20 | user's %eip (user return address) | 13506b6cf06S * -------------------------------------- 13606b6cf06S */ 13706b6cf06S #define V_U_EIP (V_END + (CLONGSIZE * 0)) 13806b6cf06S 13906b6cf06S #endif /* !__amd64 */ 14006b6cf06S 14106b6cf06S /* 14206b6cf06S * The following macros allow us to access to variables/parameters passed 14306b6cf06S * in on the stack. They take the following variables: 14406b6cf06S * sp - a register with the current stack pointer value 14506b6cf06S * pcnt - the number of words currently pushed onto the stack 14606b6cf06S * var - the variable to lookup 14706b6cf06S * reg - a register to read the variable into, or 14806b6cf06S * a register to write to the variable 14906b6cf06S */ 15006b6cf06S #define V_OFFSET(pcnt, var) \ 15106b6cf06S (var + (pcnt * CLONGSIZE)) 15206b6cf06S 15306b6cf06S #define GET_V(sp, pcnt, var, reg) \ 15406b6cf06S mov V_OFFSET(pcnt, var)(sp), reg 15506b6cf06S 15606b6cf06S #define SET_V(sp, pcnt, var, reg) \ 15706b6cf06S mov reg, V_OFFSET(pcnt, var)(sp) 15806b6cf06S 15906b6cf06S #define GET_PROCP(sp, pcnt, reg) \ 16006b6cf06S GET_V(sp, pcnt, V_LWP, reg); /* get lwp pointer */ \ 16106b6cf06S mov LWP_PROCP(reg), reg /* get proc pointer */ 16206b6cf06S 16306b6cf06S #define GET_P_BRAND_DATA(sp, pcnt, reg) \ 16406b6cf06S GET_PROCP(sp, pcnt, reg); \ 16506b6cf06S mov P_BRAND_DATA(reg), reg /* get p_brand_data */ 16606b6cf06S 16706b6cf06S /* 16806b6cf06S * Each of the following macros returns to the standard syscall codepath if 16906b6cf06S * it detects that this process is not able, or intended, to emulate this 17006b6cf06S * system call. They all assume that the routine provides a 'bail-out' 17106b6cf06S * label of '9'. 17206b6cf06S */ 17306b6cf06S 17406b6cf06S /* 17506b6cf06S * See if this process has a user-space handler registered for it. For the 17606b6cf06S * brand, the per-process brand data holds the address of the handler. 17706b6cf06S * As shown in the stack diagrams above, the callback code leaves the lwp 17806b6cf06S * pointer at well-defined offsets, so check if proc_data_t->X_handler is 17906b6cf06S * non-NULL. For each brand, the handler parameter refers to the brand's 18006b6cf06S * user-space handler variable name. 18106b6cf06S */ 18206b6cf06S #define CHECK_FOR_HANDLER(scr, handler) \ 18306b6cf06S GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data */ \ 18406b6cf06S cmp $0, scr; \ 18506b6cf06S je 9f; \ 186*abe1e6b3SAndy Fiddaman cmpq $0, handler(scr); /* check handler */ \ 18706b6cf06S je 9f 18806b6cf06S 18906b6cf06S /* 19006b6cf06S * If the system call number is >= 1024, then it is coming from the 19106b6cf06S * emulation support library. As such we should handle it natively instead 19206b6cf06S * of sending it back to the emulation library. 19306b6cf06S */ 19406b6cf06S #define CHECK_FOR_NATIVE(reg) \ 19506b6cf06S cmp $1024, reg; \ 19606b6cf06S jl 1f; \ 19706b6cf06S sub $1024, reg; \ 19806b6cf06S jmp 9f; \ 19906b6cf06S 1: 20006b6cf06S 20106b6cf06S /* 20206b6cf06S * Check to see if we want to interpose on this system call. If not, we 20306b6cf06S * jump back into the normal syscall path and pretend nothing happened. 20406b6cf06S * This macro is usable for brands which have the same number of syscalls 20506b6cf06S * as the base OS. 20606b6cf06S */ 20706b6cf06S #define CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low) \ 20806b6cf06S cmp $NSYSCALL, call; /* is 0 <= syscall <= MAX? */ \ 20906b6cf06S ja 9f; /* no, take normal ret path */ \ 21006b6cf06S lea emul_table, scr; \ 21106b6cf06S /*CSTYLED*/ \ 21206b6cf06S mov (scr), scr; \ 21306b6cf06S add call, scr; \ 21406b6cf06S /*CSTYLED*/ \ 21506b6cf06S movb (scr), scr_low; \ 21606b6cf06S cmpb $0, scr_low; \ 21706b6cf06S je 9f /* no, take normal ret path */ 21806b6cf06S 21906b6cf06S #define CALLBACK_PROLOGUE(emul_table, handler, call, scr, scr_low) \ 22006b6cf06S CHECK_FOR_HANDLER(scr, handler); \ 22106b6cf06S CHECK_FOR_NATIVE(call); \ 22206b6cf06S CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low) 22306b6cf06S 22406b6cf06S /* 22506b6cf06S * Rather than returning to the instruction after the syscall, we need to 22606b6cf06S * transfer control into the brand library's handler table at 22706b6cf06S * table_addr + (16 * syscall_num), thus encoding the system call number in the 22806b6cf06S * instruction pointer. The CALC_TABLE_ADDR macro performs that calculation. 22906b6cf06S * 23006b6cf06S * This macro assumes the syscall number is in SYSCALL_REG and it clobbers 23106b6cf06S * that register. It leaves the calculated handler table return address in 23206b6cf06S * the scratch reg. 23306b6cf06S */ 23406b6cf06S #define CALC_TABLE_ADDR(scr, handler) \ 23506b6cf06S GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data ptr */ \ 23606b6cf06S mov handler(scr), scr; /* get p_brand_data->XX_handler */ \ 23706b6cf06S shl $4, SYSCALL_REG; /* syscall_num * 16 */ \ 23806b6cf06S add SYSCALL_REG, scr /* leave return addr in scr reg. */ 23906b6cf06S 24006b6cf06S #endif /* _ASM */ 24106b6cf06S 24206b6cf06S #ifdef __cplusplus 24306b6cf06S } 24406b6cf06S #endif 24506b6cf06S 24606b6cf06S #endif /* _COMMON_BRAND_ASM_H */ 247