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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  24  * Copyright (c) 2018, Joyent, Inc.
  25  */
  26 
  27 /*
  28  * Floating point configuration.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/regset.h>
  33 #include <sys/privregs.h>
  34 #include <sys/x86_archext.h>
  35 #include <sys/archsystm.h>
  36 #include <sys/fp.h>
  37 #include <sys/cmn_err.h>
  38 #include <sys/exec.h>
  39 
  40 #define XMM_ALIGN       16
  41 
  42 /*
  43  * See section 10.5.1 in the Intel 64 and IA-32 Architectures Software
  44  * Developer’s Manual, Volume 1.
  45  */
  46 #define FXSAVE_ALIGN    16
  47 
  48 /*
  49  * See section 13.4 in the Intel 64 and IA-32 Architectures Software
  50  * Developer’s Manual, Volume 1.
  51  */
  52 #define XSAVE_ALIGN     64
  53 
  54 /*
  55  * If fpu_exists is non-zero, fpu_probe will attempt to use any
  56  * hardware FPU (subject to other constraints, see below).  If
  57  * fpu_exists is zero, fpu_probe will report that there is no
  58  * FPU even if there is one.
  59  */
  60 int fpu_exists = 1;
  61 
  62 int fp_kind = FP_387;
  63 
  64 /*
  65  * The kind of FPU we advertise to rtld so it knows what to do on context
  66  * switch.
  67  */
  68 int fp_elf = AT_386_FPINFO_FXSAVE;
  69 
  70 /*
  71  * Mechanism to save FPU state.
  72  */
  73 int fp_save_mech = FP_FXSAVE;
  74 
  75 /*
  76  * The variable fpu_ignored is provided to allow other code to
  77  * determine whether emulation is being done because there is
  78  * no FPU or because of an override requested via /etc/system.
  79  */
  80 int fpu_ignored = 0;
  81 
  82 /*
  83  * Used by ppcopy and ppzero to determine whether or not to use the
  84  * SSE-based pagecopy and pagezero routines
  85  */
  86 int use_sse_pagecopy = 0;
  87 int use_sse_pagezero = 0;
  88 int use_sse_copy = 0;
  89 
  90 #if defined(__xpv)
  91 
  92 /*
  93  * Use of SSE or otherwise is forcibly configured for us by the hypervisor.
  94  */
  95 
  96 #define ENABLE_SSE()
  97 #define DISABLE_SSE()
  98 
  99 #else   /* __xpv */
 100 
 101 #define ENABLE_SSE()    setcr4(CR4_ENABLE_SSE_FLAGS(getcr4()))
 102 #define DISABLE_SSE()   setcr4(CR4_DISABLE_SSE_FLAGS(getcr4()))
 103 
 104 #endif  /* __xpv */
 105 
 106 /*
 107  * Try and figure out what kind of FP capabilities we have, and
 108  * set up the control registers accordingly.
 109  */
 110 void
 111 fpu_probe(void)
 112 {
 113         if (fpu_initial_probe() != 0)
 114                 goto nofpu;
 115 
 116         if (fpu_exists == 0) {
 117                 fpu_ignored = 1;
 118                 goto nofpu;
 119         }
 120 
 121 #ifndef __xpv
 122         /*
 123          * Check and see if the fpu is present by looking
 124          * at the "extension type" bit.  (While this used to
 125          * indicate a 387DX coprocessor in days gone by,
 126          * it's forced on by modern implementations for
 127          * compatibility.)
 128          */
 129         if ((getcr0() & CR0_ET) == 0)
 130                 goto nofpu;
 131 #endif
 132 
 133         /* Use the more complex exception clearing code if necessary */
 134         if (cpuid_need_fp_excp_handling())
 135                 fpsave_ctxt = fpxsave_excp_clr_ctxt;
 136 
 137         /*
 138          * SSE and SSE2 are required for the 64-bit ABI.
 139          *
 140          * If they're not present, we can in principal run
 141          * 32-bit userland, though 64-bit processes will be hosed.
 142          *
 143          * (Perhaps we should complain more about this case!)
 144          */
 145         if (is_x86_feature(x86_featureset, X86FSET_SSE) &&
 146             is_x86_feature(x86_featureset, X86FSET_SSE2)) {
 147                 fp_kind |= __FP_SSE;
 148                 ENABLE_SSE();
 149 
 150                 if (is_x86_feature(x86_featureset, X86FSET_AVX)) {
 151                         ASSERT(is_x86_feature(x86_featureset, X86FSET_XSAVE));
 152                         fp_kind |= __FP_AVX;
 153                 }
 154 
 155                 if (is_x86_feature(x86_featureset, X86FSET_XSAVE)) {
 156                         fp_save_mech = FP_XSAVE;
 157                         fp_elf = AT_386_FPINFO_XSAVE;
 158                         if (is_x86_feature(x86_featureset, X86FSET_XSAVEOPT)) {
 159                                 /*
 160                                  * Use the more complex exception
 161                                  * clearing code if necessary.
 162                                  */
 163                                 if (cpuid_need_fp_excp_handling()) {
 164                                         fpsave_ctxt = xsaveopt_excp_clr_ctxt;
 165                                         fp_elf = AT_386_FPINFO_XSAVE_AMD;
 166                                 } else {
 167                                         fpsave_ctxt = xsaveopt_ctxt;
 168                                 }
 169                                 xsavep = xsaveopt;
 170                         } else {
 171                                 /*
 172                                  * Use the more complex exception
 173                                  * clearing code if necessary.
 174                                  */
 175                                 if (cpuid_need_fp_excp_handling()) {
 176                                         fpsave_ctxt = xsave_excp_clr_ctxt;
 177                                         fp_elf = AT_386_FPINFO_XSAVE_AMD;
 178                                 } else {
 179                                         fpsave_ctxt = xsave_ctxt;
 180                                 }
 181                         }
 182                         fprestore_ctxt = xrestore_ctxt;
 183                         fpsave_cachep = kmem_cache_create("xsave_cache",
 184                             cpuid_get_xsave_size(), XSAVE_ALIGN,
 185                             NULL, NULL, NULL, NULL, NULL, 0);
 186                 } else {
 187                         /* fp_save_mech defaults to FP_FXSAVE */
 188                         fpsave_cachep = kmem_cache_create("fxsave_cache",
 189                             sizeof (struct fxsave_state), FXSAVE_ALIGN,
 190                             NULL, NULL, NULL, NULL, NULL, 0);
 191                         fp_elf = AT_386_FPINFO_FXSAVE;
 192                 }
 193         }
 194 
 195         if (is_x86_feature(x86_featureset, X86FSET_SSE2)) {
 196                 use_sse_pagecopy = use_sse_pagezero = use_sse_copy = 1;
 197         }
 198 
 199         if (fp_kind & __FP_SSE) {
 200                 struct fxsave_state *fx;
 201                 uint8_t fxsave_state[sizeof (struct fxsave_state) + XMM_ALIGN];
 202 
 203                 /*
 204                  * Extract the mxcsr mask from our first fxsave
 205                  */
 206                 fx = (void *)(((uintptr_t)(&fxsave_state[0]) +
 207                     XMM_ALIGN) & ~(XMM_ALIGN - 1ul));
 208 
 209                 fx->fx_mxcsr_mask = 0;
 210                 fxsave_insn(fx);
 211                 if (fx->fx_mxcsr_mask != 0) {
 212                         /*
 213                          * Override default mask initialized in fpu.c
 214                          */
 215                         sse_mxcsr_mask = fx->fx_mxcsr_mask;
 216                 }
 217         }
 218 
 219         setcr0(CR0_ENABLE_FPU_FLAGS(getcr0()));
 220         return;
 221 
 222         /*
 223          * No FPU hardware present
 224          */
 225 nofpu:
 226         setcr0(CR0_DISABLE_FPU_FLAGS(getcr0()));
 227         DISABLE_SSE();
 228         fp_kind = FP_NO;
 229         fpu_exists = 0;
 230 }
 231 
 232 /*
 233  * Fill in FPU information that is required by exec.
 234  */
 235 void
 236 fpu_auxv_info(int *typep, size_t *lenp)
 237 {
 238         *typep = fp_elf;
 239         switch (fp_save_mech) {
 240         case FP_FXSAVE:
 241                 *lenp = sizeof (struct fxsave_state);
 242                 break;
 243         case FP_XSAVE:
 244                 *lenp = cpuid_get_xsave_size();
 245                 break;
 246         default:
 247                 *lenp = 0;
 248                 break;
 249         }
 250 }