1117756Sdeischen/* 2117756Sdeischen * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>. 3117756Sdeischen * All rights reserved. 4117756Sdeischen * 5117756Sdeischen * Redistribution and use in source and binary forms, with or without 6117756Sdeischen * modification, are permitted provided that the following conditions 7117756Sdeischen * are met: 8117756Sdeischen * 1. Redistributions of source code must retain the above copyright 9117756Sdeischen * notice, this list of conditions and the following disclaimer. 10117756Sdeischen * 2. Neither the name of the author nor the names of its contributors 11117756Sdeischen * may be used to endorse or promote products derived from this software 12117756Sdeischen * without specific prior written permission. 13117756Sdeischen * 14117756Sdeischen * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND 15117756Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16117756Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17117756Sdeischen * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18117756Sdeischen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19117756Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20117756Sdeischen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21117756Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22117756Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23117756Sdeischen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24117756Sdeischen * SUCH DAMAGE. 25117756Sdeischen */ 26117756Sdeischen 27117756Sdeischen#include <machine/asm.h> 28117756Sdeischen__FBSDID("$FreeBSD: releng/10.2/lib/libkse/arch/amd64/amd64/context.S 155990 2006-02-24 22:03:10Z deischen $"); 29117756Sdeischen 30117756Sdeischen/* 31117756Sdeischen * The following notes ("cheat sheet") was provided by Peter Wemm. 32117756Sdeischen * 33117756Sdeischen * scratch: 34117756Sdeischen * rax (1st return) 35117756Sdeischen * rcx (4th arg) 36117756Sdeischen * rdx (3rd arg, 2nd return) 37117756Sdeischen * rsi (2nd arg) 38117756Sdeischen * rdi (1st arg) 39117756Sdeischen * r8 (5th arg) 40117756Sdeischen * r9 (6th arg) 41117756Sdeischen * r10 (temp, static chain?) 42117756Sdeischen * r11 (temp) 43117756Sdeischen * 44117756Sdeischen * preserved: 45117756Sdeischen * rbx (base pointer) 46117756Sdeischen * rsp (stack) 47117756Sdeischen * rbp (frame) 48117756Sdeischen * r12-r15 (general) 49117756Sdeischen * 50117756Sdeischen * calls: 51117756Sdeischen * rdi 1 52117756Sdeischen * rsi 2 53117756Sdeischen * rdx 3 54117756Sdeischen * rcx 4 55117756Sdeischen * r8 5 56117756Sdeischen * r9 6 57117756Sdeischen * 58117756Sdeischen * return: 59117756Sdeischen * rax 1 60117756Sdeischen * rdx 2 61117756Sdeischen * 62117756Sdeischen * This means: 63117756Sdeischen * arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and 64117756Sdeischen * secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are 65117756Sdeischen * trashed by making a call to something. %rbx,%rbp,%r12-15 are the 66117756Sdeischen * only registers preserved across a call. Note that unlike i386, 67117756Sdeischen * %rsi and %rdi are scratch rather than preserved. FPU is 68117756Sdeischen * different, args are in SSE registers rather than the x87 stack. 69117756Sdeischen * 70117756Sdeischen * Aside from the register calling conventions, amd64 can be treated 71117756Sdeischen * very much like i386. Things like setjmp/longjmp etc were literal 72117756Sdeischen * translations from i386 but with the register names updated, etc. 73117756Sdeischen * The main gotcha is that FPU save/restore is in SSE format, which 74117756Sdeischen * means a sparse 512 byte FPU context. 75117756Sdeischen */ 76117756Sdeischen 77117756Sdeischen 78117756Sdeischen/* 79117756Sdeischen * Where do we define these? 80117756Sdeischen */ 81120108Sdeischen#define MC_SIZE 800 /* sizeof mcontext_t */ 82121163Speter#define MC_LEN_OFFSET (25*8) /* offset to mc_len from mcontext */ 83121163Speter#define MC_FPFMT_OFFSET (26*8) /* offset to mc_fpformat from mcontext */ 84121163Speter#define MC_FPFMT_NODEV 0x10000 85121163Speter#define MC_OWNEDFP_OFFSET (27*8) /* offset to mc_ownedfp from mcontext */ 86117756Sdeischen#define MC_OWNEDFP_NONE 0x20000 87117756Sdeischen#define MC_OWNEDFP_FPU 0x20001 88117756Sdeischen#define MC_OWNEDFP_PCB 0x20002 89117756Sdeischen#define MC_FPREGS_OFFSET (28*8) /* offset to FP registers */ 90117756Sdeischen#define MC_FP_CW_OFFSET (28*8) /* offset to FP control word */ 91117756Sdeischen 92117756Sdeischen#define MC_RDI (1 * 8) 93117756Sdeischen#define MC_RSI (2 * 8) 94117756Sdeischen#define MC_RDX (3 * 8) 95117756Sdeischen#define MC_RCX (4 * 8) 96117756Sdeischen#define MC_R8 (5 * 8) 97117756Sdeischen#define MC_R9 (6 * 8) 98117756Sdeischen#define MC_RAX (7 * 8) 99117756Sdeischen#define MC_RBX (8 * 8) 100117756Sdeischen#define MC_RBP (9 * 8) 101117756Sdeischen#define MC_R10 (10 * 8) 102117756Sdeischen#define MC_R11 (11 * 8) 103117756Sdeischen#define MC_R12 (12 * 8) 104117756Sdeischen#define MC_R13 (13 * 8) 105117756Sdeischen#define MC_R14 (14 * 8) 106117756Sdeischen#define MC_R15 (15 * 8) 107121163Speter#define MC_FLAGS (18 * 8) 108121163Speter#define MC_RIP (20 * 8) 109132928Sdavidxu#define MC_CS (21 * 8) 110121163Speter#define MC_RFLAGS (22 * 8) 111121163Speter#define MC_RSP (23 * 8) 112132928Sdavidxu#define MC_SS (24 * 8) 113117756Sdeischen 114130206Stjr#define REDZONE 128 /* size of the red zone */ 115130206Stjr 116117756Sdeischen/* 117117756Sdeischen * _amd64_ctx_save(mcontext_t *mcp) 118117756Sdeischen * 119132928Sdavidxu * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs. 120117756Sdeischen * For the FPU state, only the floating point control word is stored. 121117756Sdeischen */ 122118037SdavidxuENTRY(_amd64_save_context) 123117756Sdeischen cmpq $0, %rdi /* check for null pointer */ 124117756Sdeischen jne 1f 125117756Sdeischen movq $-1, %rax 126117756Sdeischen jmp 2f 127117756Sdeischen1: movq %rdi, MC_RDI(%rdi) 128117756Sdeischen movq %rsi, MC_RSI(%rdi) 129117756Sdeischen movq %rdx, MC_RDX(%rdi) 130117756Sdeischen movq %rcx, MC_RCX(%rdi) 131117756Sdeischen movq %r8, MC_R8(%rdi) 132117756Sdeischen movq %r9, MC_R9(%rdi) 133117756Sdeischen movq $1, MC_RAX(%rdi) /* return 1 when restored */ 134117756Sdeischen movq %rbx, MC_RBX(%rdi) 135117756Sdeischen movq %rbp, MC_RBP(%rdi) 136117756Sdeischen movq %r10, MC_R10(%rdi) 137117756Sdeischen movq %r11, MC_R11(%rdi) 138117756Sdeischen movq %r12, MC_R12(%rdi) 139117756Sdeischen movq %r13, MC_R13(%rdi) 140117756Sdeischen movq %r14, MC_R14(%rdi) 141117756Sdeischen movq %r15, MC_R15(%rdi) 142117756Sdeischen movq (%rsp), %rax /* get return address */ 143117756Sdeischen movq %rax, MC_RIP(%rdi) /* save return address (%rip) */ 144117756Sdeischen pushfq /* get flags */ 145117756Sdeischen popq %rax 146117756Sdeischen movq %rax, MC_RFLAGS(%rdi) /* save flags */ 147117756Sdeischen movq %rsp, %rax /* setcontext pushes the return */ 148118037Sdavidxu addq $8, %rax /* address onto the stack; */ 149117756Sdeischen movq %rax, MC_RSP(%rdi) /* account for this -- ???. */ 150132928Sdavidxu movw %ss, MC_SS(%rdi) 151117756Sdeischen fnstcw MC_FP_CW_OFFSET(%rdi) /* save FPU control word */ 152117756Sdeischen movq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */ 153132928Sdavidxu movq $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi) 154117756Sdeischen movq $MC_SIZE, MC_LEN_OFFSET(%rdi) 155117756Sdeischen xorq %rax, %rax /* return 0 */ 156117756Sdeischen2: ret 157117756Sdeischen 158117756Sdeischen/* 159117756Sdeischen * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc); 160117756Sdeischen */ 161118037SdavidxuENTRY(_amd64_restore_context) 162117756Sdeischen cmpq $0, %rdi /* check for null pointer */ 163117756Sdeischen jne 1f 164117756Sdeischen movq $-1, %rax 165155990Sdeischen jmp 2f 166117756Sdeischen1: cmpq $MC_SIZE, MC_LEN_OFFSET(%rdi) /* is context valid? */ 167117756Sdeischen je 2f 168117756Sdeischen movq $-1, %rax /* bzzzt, invalid context */ 169155990Sdeischen ret 170117756Sdeischen2: movq MC_RCX(%rdi), %rcx 171117756Sdeischen movq MC_R8(%rdi), %r8 172117756Sdeischen movq MC_R9(%rdi), %r9 173117756Sdeischen movq MC_RBX(%rdi), %rbx 174117756Sdeischen movq MC_RBP(%rdi), %rbp 175117756Sdeischen movq MC_R10(%rdi), %r10 176117756Sdeischen movq MC_R11(%rdi), %r11 177117756Sdeischen movq MC_R12(%rdi), %r12 178117756Sdeischen movq MC_R13(%rdi), %r13 179117756Sdeischen movq MC_R14(%rdi), %r14 180117756Sdeischen movq MC_R15(%rdi), %r15 181117756Sdeischen /* 182117756Sdeischen * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB) 183117756Sdeischen * restore XMM/SSE FP register format 184117756Sdeischen */ 185117756Sdeischen cmpq $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) 186117756Sdeischen je 4f 187117756Sdeischen cmpq $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi) 188117756Sdeischen je 3f 189117756Sdeischen cmpq $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi) 190117756Sdeischen jne 4f 191117756Sdeischen3: fxrstor MC_FPREGS_OFFSET(%rdi) /* restore XMM FP regs */ 192117756Sdeischen jmp 5f 193117756Sdeischen4: fninit 194117756Sdeischen fldcw MC_FP_CW_OFFSET(%rdi) 195117756Sdeischen5: movq MC_RSP(%rdi), %rsp /* switch to context stack */ 196130206Stjr subq $REDZONE, %rsp 197117756Sdeischen movq MC_RIP(%rdi), %rax /* return address on stack */ 198117756Sdeischen pushq %rax 199118037Sdavidxu movq MC_RDI(%rdi), %rax /* rdi on stack */ 200117756Sdeischen pushq %rax 201117756Sdeischen movq MC_RDX(%rdi), %rax /* rdx on stack */ 202117756Sdeischen pushq %rax 203117756Sdeischen movq MC_RSI(%rdi), %rax /* rsi on stack */ 204117756Sdeischen pushq %rax 205117756Sdeischen movq MC_RFLAGS(%rdi), %rax /* flags on stack*/ 206117756Sdeischen pushq %rax 207117756Sdeischen movq MC_RAX(%rdi), %rax /* restore rax */ 208117756Sdeischen /* At this point we're done with the context. */ 209117756Sdeischen cmpq $0, %rdx /* set *loc to val */ 210118037Sdavidxu je 6f 211117756Sdeischen movq %rsi, (%rdx) 212117756Sdeischen6: popfq /* restore flags */ 213117756Sdeischen popq %rsi /* restore rsi, rdx, and rdi */ 214117756Sdeischen popq %rdx 215117756Sdeischen popq %rdi 216155990Sdeischen ret $REDZONE 217155990Sdeischen 218