]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - lib/libkse/arch/amd64/amd64/context.S
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / lib / libkse / arch / amd64 / amd64 / context.S
1 /*
2  * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Neither the name of the author nor the names of its contributors
11  *    may be used to endorse or promote products derived from this software
12  *    without specific prior written permission.
13  *
14  * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <machine/asm.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31  * The following notes ("cheat sheet") was provided by Peter Wemm.
32  *
33  *   scratch:
34  *   rax     (1st return)
35  *   rcx     (4th arg)
36  *   rdx     (3rd arg, 2nd return)
37  *   rsi     (2nd arg)
38  *   rdi     (1st arg)
39  *   r8      (5th arg)
40  *   r9      (6th arg)
41  *   r10     (temp, static chain?)
42  *   r11     (temp)
43  * 
44  *   preserved:
45  *   rbx     (base pointer)
46  *   rsp     (stack)
47  *   rbp     (frame)
48  *   r12-r15 (general)
49  * 
50  *   calls:
51  *   rdi     1
52  *   rsi     2
53  *   rdx     3
54  *   rcx     4
55  *   r8      5
56  *   r9      6
57  * 
58  *   return:
59  *   rax     1
60  *   rdx     2
61  * 
62  *   This means:
63  *   arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and
64  *   secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are
65  *   trashed by making a call to something. %rbx,%rbp,%r12-15 are the
66  *   only registers preserved across a call. Note that unlike i386,
67  *   %rsi and %rdi are scratch rather than preserved. FPU is
68  *   different, args are in SSE registers rather than the x87 stack.
69  * 
70  *   Aside from the register calling conventions, amd64 can be treated
71  *   very much like i386.  Things like setjmp/longjmp etc were literal
72  *   translations from i386 but with the register names updated, etc. 
73  *   The main gotcha is that FPU save/restore is in SSE format, which
74  *   means a sparse 512 byte FPU context.
75  */
76
77
78 /*
79  * Where do we define these?
80  */
81 #define MC_SIZE                 800     /* sizeof mcontext_t */
82 #define MC_LEN_OFFSET           (25*8)  /* offset to mc_len from mcontext */
83 #define MC_FPFMT_OFFSET         (26*8)  /* offset to mc_fpformat from mcontext */
84 #define MC_FPFMT_NODEV          0x10000
85 #define MC_OWNEDFP_OFFSET       (27*8)  /* offset to mc_ownedfp from mcontext */
86 #define MC_OWNEDFP_NONE         0x20000
87 #define MC_OWNEDFP_FPU          0x20001
88 #define MC_OWNEDFP_PCB          0x20002
89 #define MC_FPREGS_OFFSET        (28*8)  /* offset to FP registers */
90 #define MC_FP_CW_OFFSET         (28*8)  /* offset to FP control word */
91
92 #define MC_RDI          (1 * 8)
93 #define MC_RSI          (2 * 8)
94 #define MC_RDX          (3 * 8)
95 #define MC_RCX          (4 * 8)
96 #define MC_R8           (5 * 8)
97 #define MC_R9           (6 * 8)
98 #define MC_RAX          (7 * 8)
99 #define MC_RBX          (8 * 8)
100 #define MC_RBP          (9 * 8)
101 #define MC_R10          (10 * 8)
102 #define MC_R11          (11 * 8)
103 #define MC_R12          (12 * 8)
104 #define MC_R13          (13 * 8)
105 #define MC_R14          (14 * 8)
106 #define MC_R15          (15 * 8)
107 #define MC_FLAGS        (18 * 8)
108 #define MC_RIP          (20 * 8)
109 #define MC_CS           (21 * 8)
110 #define MC_RFLAGS       (22 * 8)
111 #define MC_RSP          (23 * 8)
112 #define MC_SS           (24 * 8)
113
114 #define REDZONE         128             /* size of the red zone */
115
116 /*
117  * _amd64_ctx_save(mcontext_t *mcp)
118  *
119  * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs.
120  * For the FPU state, only the floating point control word is stored.
121  */
122 ENTRY(_amd64_save_context)
123         cmpq    $0, %rdi                /* check for null pointer */
124         jne     1f
125         movq    $-1, %rax
126         jmp     2f
127 1:      movq    %rdi, MC_RDI(%rdi)
128         movq    %rsi, MC_RSI(%rdi)
129         movq    %rdx, MC_RDX(%rdi)
130         movq    %rcx, MC_RCX(%rdi)
131         movq    %r8, MC_R8(%rdi)
132         movq    %r9, MC_R9(%rdi)
133         movq    $1, MC_RAX(%rdi)        /* return 1 when restored */
134         movq    %rbx, MC_RBX(%rdi)
135         movq    %rbp, MC_RBP(%rdi)
136         movq    %r10, MC_R10(%rdi)
137         movq    %r11, MC_R11(%rdi)
138         movq    %r12, MC_R12(%rdi)
139         movq    %r13, MC_R13(%rdi)
140         movq    %r14, MC_R14(%rdi)
141         movq    %r15, MC_R15(%rdi)
142         movq    (%rsp), %rax            /* get return address */
143         movq    %rax, MC_RIP(%rdi)      /* save return address (%rip) */
144         pushfq                          /* get flags */
145         popq    %rax
146         movq    %rax, MC_RFLAGS(%rdi)   /* save flags */
147         movq    %rsp, %rax              /* setcontext pushes the return */
148         addq    $8, %rax                /*   address onto the stack; */
149         movq    %rax, MC_RSP(%rdi)      /*   account for this -- ???. */
150         movw    %ss, MC_SS(%rdi)
151         fnstcw  MC_FP_CW_OFFSET(%rdi)   /* save FPU control word */
152         movq    $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */
153         movq    $MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi)
154         movq    $MC_SIZE, MC_LEN_OFFSET(%rdi)
155         xorq    %rax, %rax              /* return 0 */
156 2:      ret
157
158 /*
159  * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc);
160  */
161 ENTRY(_amd64_restore_context)
162         cmpq    $0, %rdi                /* check for null pointer */
163         jne     1f
164         movq    $-1, %rax
165         jmp     2f
166 1:      cmpq    $MC_SIZE, MC_LEN_OFFSET(%rdi)   /* is context valid? */
167         je      2f
168         movq    $-1, %rax               /* bzzzt, invalid context */
169         ret
170 2:      movq    MC_RCX(%rdi), %rcx
171         movq    MC_R8(%rdi), %r8
172         movq    MC_R9(%rdi), %r9
173         movq    MC_RBX(%rdi), %rbx
174         movq    MC_RBP(%rdi), %rbp
175         movq    MC_R10(%rdi), %r10
176         movq    MC_R11(%rdi), %r11
177         movq    MC_R12(%rdi), %r12
178         movq    MC_R13(%rdi), %r13
179         movq    MC_R14(%rdi), %r14
180         movq    MC_R15(%rdi), %r15
181         /*
182          * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB)
183          *    restore XMM/SSE FP register format
184          */
185         cmpq    $MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi)
186         je      4f
187         cmpq    $MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi)
188         je      3f
189         cmpq    $MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi)
190         jne     4f
191 3:      fxrstor MC_FPREGS_OFFSET(%rdi)  /* restore XMM FP regs */
192         jmp     5f
193 4:      fninit
194         fldcw   MC_FP_CW_OFFSET(%rdi)
195 5:      movq    MC_RSP(%rdi), %rsp      /* switch to context stack */
196         subq    $REDZONE, %rsp
197         movq    MC_RIP(%rdi), %rax      /* return address on stack */
198         pushq   %rax
199         movq    MC_RDI(%rdi), %rax      /* rdi on stack */
200         pushq   %rax
201         movq    MC_RDX(%rdi), %rax      /* rdx on stack */
202         pushq   %rax
203         movq    MC_RSI(%rdi), %rax      /* rsi on stack */
204         pushq   %rax
205         movq    MC_RFLAGS(%rdi), %rax   /* flags on stack*/
206         pushq   %rax
207         movq    MC_RAX(%rdi), %rax      /* restore rax */
208         /* At this point we're done with the context. */
209         cmpq    $0, %rdx                /* set *loc to val */
210         je      6f
211         movq    %rsi, (%rdx)
212 6:      popfq                           /* restore flags */
213         popq    %rsi                    /* restore rsi, rdx, and rdi */
214         popq    %rdx
215         popq    %rdi
216         ret     $REDZONE
217