gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/arch/fpu/fpu_amd64.s (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include "textflag.h"
    16  
    17  // MXCSR_DEFAULT is the reset value of MXCSR (Intel SDM Vol. 2, Ch. 3.2
    18  // "LDMXCSR")
    19  #define MXCSR_DEFAULT	0x1f80
    20  
    21  // MXCSR_OFFSET is the offset in bytes of the MXCSR field from the start of the
    22  // FXSAVE/XSAVE area. (Intel SDM Vol. 1, Table 10-2 "Format of an FXSAVE Area")
    23  #define MXCSR_OFFSET	24
    24  
    25  // The value for XCR0 is defined to xsave/xrstor everything except for PKRU and
    26  // AMX regions.
    27  // TODO(gvisor.dev/issues/9896): Implement AMX support.
    28  // TODO(gvisor.dev/issues/10087): Implement PKRU support.
    29  #define XCR0_DISABLED_MASK ((1 << 9) | (1 << 17) | (1 << 18))
    30  #define XCR0_EAX (0xffffffff ^ XCR0_DISABLED_MASK)
    31  #define XCR0_EDX 0xffffffff
    32  
    33  // initX86FPState initializes floating point state.
    34  //
    35  // func initX86FPState(data *FloatingPointData, useXsave bool)
    36  //
    37  // We need to clear out and initialize an empty fp state area since the sentry,
    38  // or any previous loader, may have left sensitive information in the floating
    39  // point registers.
    40  //
    41  // Preconditions: data is zeroed.
    42  TEXT ·initX86FPState(SB), $24-9
    43  	// Save MXCSR (callee-save)
    44  	STMXCSR	mxcsr-8(SP)
    45  
    46  	// Save x87 CW (callee-save)
    47  	FSTCW	cw-16(SP)
    48  
    49  	MOVQ	data+0(FP), DI
    50  
    51  	// Do we use xsave?
    52  	MOVBQZX	useXsave+8(FP), AX
    53  	TESTQ	AX, AX
    54  	JZ	no_xsave
    55  
    56  	// Use XRSTOR to clear all FP state to an initial state.
    57  	//
    58  	// The fpState XSAVE area is zeroed on function entry, meaning
    59  	// XSTATE_BV is zero.
    60  	//
    61  	// "If RFBM[i] = 1 and bit i is clear in the XSTATE_BV field in the
    62  	// XSAVE header, XRSTOR initializes state component i."
    63  	//
    64  	// Initialization is defined in SDM Vol 1, Chapter 13.3. It puts all
    65  	// the registers in a reasonable initial state, except MXCSR:
    66  	//
    67  	// "The MXCSR register is part of state component 1, SSE state (see
    68  	// Section 13.5.2). However, the standard form of XRSTOR loads the
    69  	// MXCSR register from memory whenever the RFBM[1] (SSE) or RFBM[2]
    70  	// (AVX) is set, regardless of the values of XSTATE_BV[1] and
    71  	// XSTATE_BV[2]."
    72  
    73  	// Set MXCSR to the default value.
    74  	MOVL	$MXCSR_DEFAULT, MXCSR_OFFSET(DI)
    75  
    76  	// Initialize registers with XRSTOR.
    77  	MOVL	$XCR0_EAX, AX
    78  	MOVL	$XCR0_EDX, DX
    79  	BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0x2f // XRSTOR64 0(DI)
    80  
    81  	// Now that all the state has been reset, write it back out to the
    82  	// XSAVE area.
    83  	BYTE $0x48; BYTE $0x0f; BYTE $0xae; BYTE $0x27 // XSAVE64 0(DI)
    84  
    85  	JMP	out
    86  
    87  no_xsave:
    88  	// Clear out existing X values.
    89  	PXOR	X0, X0
    90  	MOVO	X0, X1
    91  	MOVO	X0, X2
    92  	MOVO	X0, X3
    93  	MOVO	X0, X4
    94  	MOVO	X0, X5
    95  	MOVO	X0, X6
    96  	MOVO	X0, X7
    97  	MOVO	X0, X8
    98  	MOVO	X0, X9
    99  	MOVO	X0, X10
   100  	MOVO	X0, X11
   101  	MOVO	X0, X12
   102  	MOVO	X0, X13
   103  	MOVO	X0, X14
   104  	MOVO	X0, X15
   105  
   106  	// Zero out %rax and store into MMX registers. MMX registers are
   107  	// an alias of 8x64 bits of the 8x80 bits used for the original
   108  	// x87 registers. Storing zero into them will reset the FPU registers
   109  	// to bits [63:0] = 0, [79:64] = 1. But the contents aren't too
   110  	// important, just the fact that we have reset them to a known value.
   111  	XORQ	AX, AX
   112  	MOVQ	AX, M0
   113  	MOVQ	AX, M1
   114  	MOVQ	AX, M2
   115  	MOVQ	AX, M3
   116  	MOVQ	AX, M4
   117  	MOVQ	AX, M5
   118  	MOVQ	AX, M6
   119  	MOVQ	AX, M7
   120  
   121  	// The Go assembler doesn't support FNINIT, so we use BYTE.
   122  	// This will:
   123  	//  - Reset FPU control word to 0x037f
   124  	//  - Clear FPU status word
   125  	//  - Reset FPU tag word to 0xffff
   126  	//  - Clear FPU data pointer
   127  	//  - Clear FPU instruction pointer
   128  	BYTE $0xDB; BYTE $0xE3; // FNINIT
   129  
   130  	// Reset MXCSR.
   131  	MOVL	$MXCSR_DEFAULT, tmpmxcsr-24(SP)
   132  	LDMXCSR	tmpmxcsr-24(SP)
   133  
   134  	// Save the floating point state with fxsave.
   135  	FXSAVE64	0(DI)
   136  
   137  out:
   138  	// Restore MXCSR.
   139  	LDMXCSR	mxcsr-8(SP)
   140  
   141  	// Restore x87 CW.
   142  	FLDCW	cw-16(SP)
   143  
   144  	RET