当前位置: 首页 > 工具软件 > cpuid > 使用案例 >

CPUID、SGX中使用CPUID

海景曜
2023-12-01

CPUID官网手册

返回值汇总表位于《Intel® 64 and IA-32 Architectures Software Developer's Manual Combined Volumes 2A Vol》的Table 3-8. Information Returned by CPUID Instruction。

这个表占了足足19页,吓人。不过很丰富,很有用。

官网下载地址如下,注意是在2A卷中。

https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-software-developers-manual-volume-2a-instruction-set-reference-a-l.html

下完以后搜索Table 3-8. Information Returned by CPUID Instruction就能快速找到。

SGX中使用CPUID

正常来说,Enclave内部是不可以使用CPUID指令的(SGX手册上有说)。但实际中Enclave内部却有cpuid硬件的直接使用,挺奇怪?难道是SGX更新了?

至于为什么Enclave内部为什么不能用CPUID硬件指令,相关资料挺少,我的猜测是CPUID硬件指令需要系统权限(但似乎并不是)或者存在某些安全影响(什么安全影响尚不清楚)。

总之,Enclave内部不能使用cpuid指令,不可信世界是可以任意使用cpuid指令。

1. 不可信世界端(可任意调用cpuid硬件指令)

如下几个是壳函数,最终会调用实际执行CPUID的函数

//位于/psw/urts/cpu_features.h
inline void sgx_cpuid(unsigned int in_eax, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
{
    int cpu_info[4] = {0};
    __cpuid(cpu_info, in_eax);
    *eax = cpu_info[0];
    *ebx = cpu_info[1];
    *ecx = cpu_info[2];
    *edx = cpu_info[3];
}
//位于/psw/urts/cpu_features.h
inline void sgx_cpuidex(unsigned int in_eax, unsigned int leaf, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx)
{
    int cpu_info[4] = {0};
    __cpuidex(cpu_info, in_eax, leaf);
    *eax = cpu_info[0];
    *ebx = cpu_info[1];
    *ecx = cpu_info[2];
    *edx = cpu_info[3];
}

下面这个函数是一个OCALL函数,专门承载Enclave内部对CPUID指令调用的需求,因为Enclave内部是不能使用CPUID硬件指令。这个OCALL已经被写到了psw/urts/linux/urts{_internal}.lds符号文件、common/inc/sgx_tstdc.edl这个Enclave接口描述文件中,方便Enclave内部调用。

//psw/urts/se_ocalls.cpp
extern "C" void sgx_oc_cpuidex(int cpuinfo[4], int leaf, int subleaf)
{
    __cpuidex(cpuinfo, leaf, subleaf);
}

上述几个壳函数都是最终调用__cpuid{ex}这个壳函数

//位于common/inc/internal/linux/cpuid_gnu.h
static inline void __cpuidex(int a[4], int b, int c)
{
    a[0] = b;
    a[2] = c;
    cpuid(&a[0], &a[1], &a[2], &a[3]);
}
//位于common/inc/internal/linux/cpuid_gnu.h
static inline void __cpuid(int a[4], int b)
{
    a[0] = b;
    a[2] = 0;
    cpuid(&a[0], &a[1], &a[2], &a[3]);
}

__cpuid{ex}壳函数最终会调用下面这个cpuid函数,并执行CPUID硬件指令。这些函数定义下common文件夹下面,这个common指代的是什么意思。

//位于common/inc/internal/linux/cpuid_gnu.h

/* This is a PIC-compliant version of CPUID */
static inline void cpuid(int *eax, int *ebx, int *ecx, int *edx)
{
#if defined(__x86_64__)
    asm("cpuid"
            : "=a" (*eax),
            "=b" (*ebx),
            "=c" (*ecx),
            "=d" (*edx)
            : "0" (*eax), "2" (*ecx));

#else
    /*on 32bit, ebx can NOT be used as PIC code*/
    asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
            : "=a" (*eax), "=r" (*ebx), "=c" (*ecx), "=d" (*edx)
            : "0" (*eax), "2" (*ecx));
#endif
}

2. Enclave内部(不能直接使用cpuid硬件指令)

//位于sdk/tlibc/gen/se_cpuid.c
sgx_status_t sgx_cpuid(int cpuinfo[4], int leaf)
{
    return sgx_cpuidex(cpuinfo, leaf, 0);
}
//位于sdk/tlibc/gen/se_cpuid.c
sgx_status_t sgx_cpuidex(int cpuinfo[4], int leaf, int subleaf)
{
    if (cpuinfo == NULL)
        return SGX_ERROR_INVALID_PARAMETER;

    return sgx_oc_cpuidex(cpuinfo, leaf, subleaf);
}

Enclave内部的壳函数会通过sgx_oc_cpuidex这个OCALL函数切换到不可新世界调用CPUID硬件指令

下面这两个函数位于sdk内(sdk是Enclave内部程序所依赖的静态库),这就很奇怪了,为什么Enclave内部会需要定义这两个函数,难道能直接用?

//位于sdk/gperftools/gperftools-2.7/src/base/atomicops-internals-x86.cc

// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
// of the global offset table.  To avoid breaking such executables, this code
// must preserve that register's value across cpuid instructions.
#if defined(__i386__)
#define cpuid(a, b, c, d, inp) \
  asm ("mov %%ebx, %%edi\n"    \
       "cpuid\n"               \
       "xchg %%edi, %%ebx\n"   \
       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
#elif defined (__x86_64__)
#define cpuid(a, b, c, d, inp) \
  asm ("mov %%rbx, %%rdi\n"    \
       "cpuid\n"               \
       "xchg %%rdi, %%rbx\n"   \
       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))
#endif
//位于sdk/libcapable/linux/sgx_capable.cpp

/* __cpuid(unsinged int info[4], unsigned int leaf, unsigned int subleaf); */
/* Because gcc's __get_cpuid() intrinsic is difficult to work with */
#define __cpuid(x,y,z) asm volatile("cpuid":"=a"(x[0]),"=b"(x[1]),"=c"(x[2]),"=d"(x[3]):"a"(y),"c"(z))

 

 类似资料: