sgxutils.c 2.1 KB
Newer Older
1 2 3 4 5 6 7 8 9
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include "sgx.h"

static inline void cpuid(int *eax, int *ebx, int *ecx, int *edx)
{
#if defined(__x86_64__)
	asm volatile ("cpuid"
10 11 12
		      : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
		      : "0" (*eax), "2" (*ecx)
		      : "memory");
13
#else
14
	/* on 32bit, ebx can NOT be used as PIC code */
15
	asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
16 17 18
		      : "=a" (*eax), "=r" (*ebx), "=c" (*ecx), "=d" (*edx)
		      : "0" (*eax), "2" (*ecx)
		      : "memory");
19 20 21 22 23
#endif
}

static inline void __cpuid(int a[4], int b)
{
24 25 26
	a[0] = b;
	a[2] = 0;
	cpuid(&a[0], &a[1], &a[2], &a[3]);
27 28 29 30
}

static inline void __cpuidex(int a[4], int b, int c)
{
31 32 33
	a[0] = b;
	a[2] = c;
	cpuid(&a[0], &a[1], &a[2], &a[3]);
34 35 36 37
}

static inline uint64_t xgetbv(uint32_t index)
{
38
	uint32_t eax, edx;
39

40 41 42
	asm volatile(".byte 0x0f,0x01,0xd0" /* xgetbv */
		     : "=a" (eax), "=d" (edx)
		     : "c" (index));
43

44
	return eax + ((uint64_t)edx << 32);
45 46 47 48
}

static inline uint64_t get_xcr0()
{
49
	return xgetbv(0);
50 51 52 53
}

static bool try_get_xcr0(uint64_t *value)
{
54
	int cpu_info[4] = {0, 0, 0, 0};
55

56
	*value = SGX_XFRM_LEGACY;
57

58 59 60 61 62
	// check if xgetbv instruction is supported
	__cpuid(cpu_info, 1);
	// ecx[27:26] indicate whether support xsave/xrstor, and whether enable xgetbv, xsetbv
	if (!(cpu_info[2] & (1<<XSAVE_SHIFT)) || !(cpu_info[2] & (1<<OSXSAVE_SHIFT)))
		return false;
63

64
	*value = get_xcr0();
65

66 67 68 69 70 71
	// check if xsavec is supported
	// Assume that XSAVEC is always supported if XSAVE is supported
	cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
	__cpuidex(cpu_info, 0xD, 1);
	if (!(cpu_info[0] & (1<<XSAVEC_SHIFT)))
		return false;
72

73
	return true;
74 75 76 77
}

void get_sgx_xfrm_by_cpuid(uint64_t *xfrm)
{
78
	int cpu_info[4] = {0, 0, 0, 0};
79

80
	__cpuidex(cpu_info, SGX_LEAF, 1);
81

82
	if (try_get_xcr0(xfrm) == false) {
83 84
	// if XSAVE is supported, while XSAVEC is not supported,
	// set xfrm to legacy, because XSAVEC cannot be executed within enclave.
85 86
		*xfrm = SGX_XFRM_LEGACY;
	} else {
87
	// If x-feature is supported and enabled by OS, we need make sure it is also supported in enclave.
88 89
		*xfrm &= (((uint64_t)cpu_info[3] << 32) | cpu_info[2]);
	}
90
}