libc - Fix bugs in getcontext(), setcontext(), and swapcontext()
[dragonfly.git] / lib / libc / x86_64 / gen / mcontext.S
1 /*
2  * Copyright (c) 2007 Matthew T. Emmerton <matt@gsicomp.on.ca>
3  * All rights reserved.
4  * Copyright (c) 2007 Matthew Dillon <dillon@backplane.com>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Neither the name of the author nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <machine/asm.h>
30 #include <cpu/specialreg.h>
31 #include <asmcontext.h>
32
33         /*
34          * int get_mcontext(mcontext_t *mcp : rdi)
35          *
36          * Copy the caller's context into the mcontext, %rax excepted.
37          */
38         .weak   get_mcontext
39         .set    get_mcontext,_get_mcontext
40 ENTRY(_get_mcontext)
41         movq    $0,MC_ONSTACK(%rdi) /*  MC_ONSTACK(%rdi)        */
42         movq    %rdi,MC_RDI(%rdi)
43         movq    %rsi,MC_RSI(%rdi)
44         movq    %rdx,MC_RDX(%rdi)
45         movq    %r8,MC_R8(%rdi)
46         movq    %r9,MC_R9(%rdi)
47         /* movq %rax,MC_RAX(%rdi) - not needed, replaced below */
48         movq    %rbx,MC_RBX(%rdi)
49         /* movq %rcx,MC_RCX(%rdi) - not needed, scratch */
50         movq    %rbp,MC_RBP(%rdi)
51         movq    %r10,MC_R10(%rdi)
52         movq    %r11,MC_R11(%rdi)
53         movq    %r12,MC_R12(%rdi)
54         movq    %r13,MC_R13(%rdi)
55         movq    %r14,MC_R14(%rdi)
56         movq    %r15,MC_R15(%rdi)
57         /*      MC_TRAPNO(%rdi) */
58         /*      MC_ADDR(%rdi)   */
59         /*      MC_FLAGS(%rdi)  */
60         /*      MC_ERR(%rdi)    */
61         /*      MC_RIP(%rdi)    - see below */
62         /*      MC_CS(%rdi)     */
63         movq    $KUCSEL,MC_CS(%rdi)
64
65         pushfq
66         popq    MC_RFLAGS(%rdi)
67         /*      MC_RSP(%rdi)    - see below */
68         /*      MC_SS(%rdi)     */
69
70         /*
71          * FP registers are scratch, do not save or restore, but make
72          * sure the context can be restored by a signal handler (where
73          * they might not be) by properly initializing the FP control
74          * fields.
75          */
76         movl    $_MC_FPOWNED_NONE,MC_OWNEDFP(%rdi)
77         movl    $_MC_FPFMT_NODEV,MC_FPFORMAT(%rdi)
78         /*
79         movl    $_MC_FPFMT_YMM,MC_FPFORMAT(%rdi)
80         */
81         movq    %rdi,%rsi
82         movq    $CPU_XFEATURE_X87 | CPU_XFEATURE_SSE | CPU_XFEATURE_YMM,%rax
83         movq    $0,%rdx
84         xsave   MC_FPREGS(%rsi)
85         movq    %rsi,%rdi
86
87         /*
88          * Saved stack pointer as if we had returned from this
89          * procedure.
90          */
91         movq    %rsp,MC_RSP(%rdi)
92         addq    $8,MC_RSP(%rdi)
93
94         /*
95          * Save rflags
96          * XXX
97          */
98
99         /*
100          * Saved instruction pointer as if we had returned from
101          * this procedure.
102          */
103         movq    (%rsp),%rdx
104         movq    %rdx,MC_RIP(%rdi)
105
106         /*
107          * On restore as if procedure returned the value 1
108          */
109         movq    $1,MC_RAX(%rdi) 
110
111         /*
112          * Set MC_LEN
113          */
114         movl    $SIZEOF_MCONTEXT_T,MC_LEN(%rdi)
115
116         /*
117          * Return 0
118          */
119         subq    %rax,%rax
120         ret
121 END(_get_mcontext)
122
123
124         /*
125          * int set_mcontext(mcontext_t *mcp)
126          *
127          * Load the register context, effectively switching to the
128          * new context.
129          */
130         .weak   set_mcontext
131         .set    set_mcontext,_set_mcontext
132 ENTRY(_set_mcontext)
133         /*
134          * Restore FP regs (might be needed if the context was
135          * taken out of a signal context).
136          */
137         cmpl    $_MC_FPFMT_NODEV,MC_FPFORMAT(%rdi)
138         je      1f
139         movq    %rdi,%rsi
140         movq    $CPU_XFEATURE_X87 | CPU_XFEATURE_SSE | CPU_XFEATURE_YMM,%rax
141         movq    $0,%rdx
142         xrstor  MC_FPREGS(%rsi) /* hack assumes cpu supports this */
143         movq    %rsi,%rdi
144 1:
145
146         /*      MC_ONSTACK(%rdi)        */
147         /*      MC_RDI(%rdi)    - see below */
148         movq    MC_RSI(%rdi),%rsi
149         movq    MC_RDX(%rdi),%rdx
150         movq    MC_R8(%rdi),%r8
151         movq    MC_R9(%rdi),%r9
152         /*      MC_RAX(%rdi)    - see below */
153         movq    MC_RBX(%rdi),%rbx
154         movq    MC_RCX(%rdi),%rcx
155         movq    MC_RBP(%rdi),%rbp
156         movq    MC_R10(%rdi),%r10
157         movq    MC_R11(%rdi),%r11
158         movq    MC_R12(%rdi),%r12
159         movq    MC_R13(%rdi),%r13
160         movq    MC_R14(%rdi),%r14
161         movq    MC_R15(%rdi),%r15
162         /*      MC_TRAPNO(%rdi) */
163         /*      MC_ADDR(%rdi)   */
164         /*      MC_FLAGS(%rdi)  */
165         /*      MC_ERR(%rdi)    */
166         /*      MC_RIP(%rdi)    - see below */
167         /*      MC_CS(%rdi)     */
168         /*      MC_RFLAGS(%rdi) - see below */
169         /*      MC_RSP(%rdi)    - see below */
170         /*      MC_SS(%rdi)     */
171
172         /*
173          * Load the new stack pointer
174          */
175         movq    MC_RSP(%rdi),%rsp
176
177         /*
178          * Push the return pc so we can 'ret' to it.
179          *
180          * Push the flags so we can restore them just prior to the retq
181          * (in case setcontext is called
182          *
183          *
184          * XXX this can cream stuff under the stack pointer, which should
185          * normally be ok but its a side effect I'd rather not have.
186          */
187         pushq   MC_RIP(%rdi)
188         pushq   MC_RFLAGS(%rdi)
189
190         /*
191          * Finally rax and rdi
192          */
193         movq    MC_RAX(%rdi),%rax
194         movq    MC_RDI(%rdi),%rdi
195         popfq
196         retq
197 END(_set_mcontext)
198
199         .section .note.GNU-stack,"",%progbits