]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/i386/gen/getcontextx.c
x86 __vdso_gettc(): use machine/cpufunc.h function for CPUID.
[FreeBSD/FreeBSD.git] / lib / libc / i386 / gen / getcontextx.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
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  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/types.h>
33 #include <sys/ucontext.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <machine/npx.h>
38 #include <machine/specialreg.h>
39 #include <machine/sysarch.h>
40
41 static int xstate_sz = -1;
42
43 int
44 __getcontextx_size(void)
45 {
46         u_int p[4];
47         int cpuid_supported;
48
49         if (xstate_sz == -1) {
50                 __asm __volatile(
51                     "   pushfl\n"
52                     "   popl    %%eax\n"
53                     "   movl    %%eax,%%ecx\n"
54                     "   xorl    $0x200000,%%eax\n"
55                     "   pushl   %%eax\n"
56                     "   popfl\n"
57                     "   pushfl\n"
58                     "   popl    %%eax\n"
59                     "   xorl    %%eax,%%ecx\n"
60                     "   je      1f\n"
61                     "   movl    $1,%0\n"
62                     "   jmp     2f\n"
63                     "1: movl    $0,%0\n"
64                     "2:\n"
65                     : "=r" (cpuid_supported) : : "eax", "ecx");
66                 if (cpuid_supported) {
67                         __asm __volatile(
68                             "   pushl   %%ebx\n"
69                             "   cpuid\n"
70                             "   movl    %%ebx,%1\n"
71                             "   popl    %%ebx\n"
72                             : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]), "=d" (p[3])
73                             :  "0" (0x1));
74                         if ((p[2] & CPUID2_OSXSAVE) != 0) {
75                                 __asm __volatile(
76                                     "   pushl   %%ebx\n"
77                                     "   cpuid\n"
78                                     "   movl    %%ebx,%1\n"
79                                     "   popl    %%ebx\n"
80                                     : "=a" (p[0]), "=r" (p[1]), "=c" (p[2]),
81                                         "=d" (p[3])
82                                     :  "0" (0xd), "2" (0x0));
83                                 xstate_sz = p[1] - sizeof(struct savexmm);
84                         } else
85                                 xstate_sz = 0;
86                 } else
87                         xstate_sz = 0;
88         }
89
90         return (sizeof(ucontext_t) + xstate_sz);
91 }
92
93 int
94 __fillcontextx2(char *ctx)
95 {
96         struct i386_get_xfpustate xfpu;
97         ucontext_t *ucp;
98
99         ucp = (ucontext_t *)ctx;
100         if (xstate_sz != 0) {
101                 xfpu.addr = (char *)(ucp + 1);
102                 xfpu.len = xstate_sz;
103                 if (sysarch(I386_GET_XFPUSTATE, &xfpu) == -1)
104                         return (-1);
105                 ucp->uc_mcontext.mc_xfpustate = (__register_t)xfpu.addr;
106                 ucp->uc_mcontext.mc_xfpustate_len = xstate_sz;
107                 ucp->uc_mcontext.mc_flags |= _MC_HASFPXSTATE;
108         } else {
109                 ucp->uc_mcontext.mc_xfpustate = 0;
110                 ucp->uc_mcontext.mc_xfpustate_len = 0;
111         }
112         return (0);
113 }
114
115 int
116 __fillcontextx(char *ctx)
117 {
118         ucontext_t *ucp;
119
120         ucp = (ucontext_t *)ctx;
121         if (getcontext(ucp) == -1)
122                 return (-1);
123         __fillcontextx2(ctx);
124         return (0);
125 }
126
127 __weak_reference(__getcontextx, getcontextx);
128
129 ucontext_t *
130 __getcontextx(void)
131 {
132         char *ctx;
133         int error;
134
135         ctx = malloc(__getcontextx_size());
136         if (ctx == NULL)
137                 return (NULL);
138         if (__fillcontextx(ctx) == -1) {
139                 error = errno;
140                 free(ctx);
141                 errno = error;
142                 return (NULL);
143         }
144         return ((ucontext_t *)ctx);
145 }