1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2023 Oxide Computer Company 29 */ 30 31 .file "getcontext.s" 32 33 #include <sys/asm_linkage.h> 34 35 ANSI_PRAGMA_WEAK(getcontext,function) 36 ANSI_PRAGMA_WEAK(swapcontext,function) 37 38 #include "SYS.h" 39 #include <../assym.h> 40 41 /* 42 * getcontext() is written in assembler since it has to capture the correct 43 * machine state of the calle. 44 * 45 * As swapcontext() is actually equivalent to getcontext() + setcontext(), 46 * swapcontext() shares the most code with getcontext(). 47 */ 48 49 #define GETCONTEXT_IMPL(offset, func) \ 50 pushq %rdi; /* preserve the ucontext_t pointer */ \ 51 call func; \ 52 /* call getcontext: syscall */ \ 53 popq %rdx; \ 54 andl %eax, %eax; /* if (error_return_from_syscall) */ \ 55 je 1f; \ 56 addq $offset, %rsp; \ 57 ret; /* then just return */ \ 58 1: \ 59 /* \ 60 * fix up %rsp and %rip \ 61 */ \ 62 addq $UC_MCONTEXT_GREGS, %rdx; \ 63 /* &ucp->uc_mcontext.gregs */ \ 64 movq offset+0(%rsp), %rax; \ 65 /* read return PC from stack */ \ 66 movq %rax, RIP_OFF (%rdx); \ 67 /* store ret PC in EIP of env var */ \ 68 leaq offset+8(%rsp), %rax; \ 69 /* get caller's sp at time of call */ \ 70 movq %rax, RSP_OFF (%rdx); \ 71 /* store the sp into UESP of env var */ \ 72 xorq %rax, %rax; /* return 0 */ \ 73 movq %rax, RAX_OFF (%rdx); \ 74 /* getcontext returns 0 after setcontext */ 75 76 /* 77 * int getcontext(ucontext_t *ucp) 78 */ 79 80 ENTRY(getcontext) 81 GETCONTEXT_IMPL(0, __getcontext) 82 ret 83 SET_SIZE(getcontext) 84 85 /* 86 * int swapcontext(ucontext_t *oucp, const ucontext_t *ucp) 87 */ 88 89 ENTRY(swapcontext) 90 pushq %rsi /* preserve the 2nd argument */ 91 92 GETCONTEXT_IMPL(8, __getcontext) 93 94 /* call setcontext */ 95 popq %rdi 96 call setcontext 97 ret 98 SET_SIZE(swapcontext) 99 100 /* 101 * int getcontext_extd(ucontext_t * ctx, uint32_t flags) 102 */ 103 ENTRY(getcontext_extd) 104 cmpl $0, %esi 105 jne 2f 106 GETCONTEXT_IMPL(0, __getcontext_extd) 107 ret 108 2: 109 movl $EINVAL, %eax /* errno = EINVAL */ 110 jmp __cerror /* return (-1) */ 111 SET_SIZE(getcontext_extd) 112 113 /* 114 * int swapcontext_extd(ucontext_t *oucp, uint32_t flags, const ucontext_t *ucp) 115 */ 116 117 ENTRY(swapcontext_extd) 118 cmpl $0, %esi 119 jne 2f 120 pushq %rdx /* preserve the 3rd argument */ 121 122 GETCONTEXT_IMPL(8, __getcontext_extd) 123 124 /* call setcontext */ 125 popq %rdi 126 call setcontext 127 ret 128 2: 129 movl $EINVAL, %eax /* errno = EINVAL */ 130 jmp __cerror /* return (-1) */ 131 SET_SIZE(swapcontext_extd)