[PAL] Fix cpuid parsing on a system with hyperthreads

This commit is contained in:
Don Porter
2019-08-19 16:13:42 -04:00
parent 30e0b8bfba
commit 60bed726e3
11 changed files with 167 additions and 44 deletions
+4 -1
View File
@@ -452,7 +452,9 @@ noreturn void pal_main (
__pal_control.alloc_align = pal_state.alloc_align;
__pal_control.broadcast_stream = _DkBroadcastStreamOpen();
_DkGetCPUInfo(&__pal_control.cpu_info);
if (_DkGetCPUInfo(&__pal_control.cpu_info) < 0) {
goto out_fail;
}
__pal_control.mem_info.mem_total = _DkMemoryQuota();
#if PROFILING == 1
@@ -470,6 +472,7 @@ noreturn void pal_main (
/* Now we will start the execution */
start_execution(first_argument, arguments, environments);
out_fail:
/* We wish we will never reached here */
INIT_FAIL(PAL_ERROR_DENIED, "unexpected termination");
}
+26 -9
View File
@@ -331,7 +331,23 @@ static char * cpu_flags[]
"pbe", // "pending break event"
};
void _DkGetCPUInfo (PAL_CPU_INFO * ci)
/*
* Returns the number of online CPUs read from sysctl hw.ncpus, -errno on failure.
*/
int get_cpu_count(void) {
int mib[2], cores;
size_t len = sizeof(cores);
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
int rv = sysctl(mib, 2, &cores, &len, NULL, 0);
if (rv < 0)
return unix_to_pal_error(ERRNO(rv));
return cores;
}
int _DkGetCPUInfo (PAL_CPU_INFO * ci)
{
unsigned int words[PAL_CPUID_WORD_NUM];
@@ -361,14 +377,15 @@ void _DkGetCPUInfo (PAL_CPU_INFO * ci)
ci->cpu_model = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EAX], 4, 8);
ci->cpu_stepping = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EAX], 0, 4);
/* According to SDM: EBX[15:0] is to enumerate processor topology
* of the system. However this value is intended for display/diagnostic
* purposes. The actual number of logical processors available to
* BIOS/OS/App may be different. We use this leaf for now as it's the
* best option we have so far to get the cpu number */
cpuid(0xb, 1, words, 0);
ci->cpu_num = BIT_EXTRACT_LE(words[WORD_EBX], 0, 16);
/* we cannot use CPUID(0xb) because it counts even disabled-by-BIOS cores (e.g. HT cores);
* instead we extract info on number of online CPUs by parsing sysfs pseudo-files */
int cores = get_cpu_count();
if (cores < 0) {
free(brand);
free(vendor_id);
return cores;
}
ci->cpu_num = cores;
int flen = 0, fmax = 80;
char * flags = malloc(fmax);
+14 -9
View File
@@ -75,6 +75,7 @@ PAL_NUM _DkGetHostId (void)
#include "elf-x86_64.h"
#include "dynamic_link.h"
#include <asm/errno.h>
void setup_pal_map (struct link_map * map);
static struct link_map pal_map;
@@ -293,6 +294,12 @@ void pal_linux_main(char * uptr_args, uint64_t args_size,
pal_sec.uid = sec_info.uid;
pal_sec.gid = sec_info.gid;
int num_cpus = sec_info.num_cpus;
if (num_cpus >= 1 && num_cpus <= (1 << 16)) {
pal_sec.num_cpus = num_cpus;
} else {
return;
}
/* set up page allocator and slab manager */
init_slab_mgr(pagesz);
@@ -459,9 +466,11 @@ static char * cpu_flags[]
"pbe", // "pending break event"
};
void _DkGetCPUInfo (PAL_CPU_INFO * ci)
int _DkGetCPUInfo (PAL_CPU_INFO * ci)
{
unsigned int words[PAL_CPUID_WORD_NUM];
int rv = 0;
const size_t VENDOR_ID_SIZE = 13;
char* vendor_id = malloc(VENDOR_ID_SIZE);
@@ -486,14 +495,9 @@ void _DkGetCPUInfo (PAL_CPU_INFO * ci)
brand[BRAND_SIZE - 1] = '\0';
ci->cpu_brand = brand;
/* According to SDM: EBX[15:0] is to enumerate processor topology
* of the system. However this value is intended for display/diagnostic
* purposes. The actual number of logical processors available to
* BIOS/OS/App may be different. We use this leaf for now as it's the
* best option we have so far to get the cpu number */
cpuid(0xb, 1, words);
ci->cpu_num = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EBX], 0, 16);
/* we cannot use CPUID(0xb) because it counts even disabled-by-BIOS cores (e.g. HT cores);
* instead, this is passed in via pal_sec at start-up time. */
ci->cpu_num = pal_sec.num_cpus;
cpuid(1, 0, words);
ci->cpu_family = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EAX], 8, 12) +
@@ -526,4 +530,5 @@ void _DkGetCPUInfo (PAL_CPU_INFO * ci)
flags[flen ? flen - 1 : 0] = 0;
ci->cpu_flags = flags;
return rv;
}
+3
View File
@@ -49,6 +49,9 @@ struct pal_sec {
PAL_SEC_STR pipe_prefix;
PAL_IDX mcast_port, mcast_srv, mcast_cli;
/* Need to pass in the number of cores */
PAL_NUM num_cpus;
#ifdef DEBUG
PAL_BOL in_gdb;
#endif
+54
View File
@@ -1,4 +1,5 @@
#include <pal_linux.h>
#include <pal_linux_error.h>
#include <pal_rtld.h>
#include "sgx_internal.h"
#include "sgx_tls.h"
@@ -707,6 +708,54 @@ out:
return ret;
}
/*
* Returns the number of online CPUs read from /sys/devices/system/cpu/online, -errno on failure.
* Understands complex formats like "1,3-5,6".
*/
int get_cpu_count(void) {
int fd = INLINE_SYSCALL(open, 3, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC, 0);
if (fd < 0)
return unix_to_pal_error(ERRNO(fd));
char buf[64];
int ret = INLINE_SYSCALL(read, 3, fd, buf, sizeof(buf) - 1);
if (ret < 0) {
INLINE_SYSCALL(close, 1, fd);
return unix_to_pal_error(ERRNO(ret));
}
buf[ret] = '\0'; /* ensure null-terminated buf even in partial read */
char* end;
char* ptr = buf;
int cpu_count = 0;
while (*ptr) {
while (*ptr == ' ' || *ptr == '\t' || *ptr == ',')
ptr++;
int firstint = (int)strtol(ptr, &end, 10);
if (ptr == end)
break;
if (*end == '\0' || *end == ',') {
/* single CPU index, count as one more CPU */
cpu_count++;
} else if (*end == '-') {
/* CPU range, count how many CPUs in range */
ptr = end + 1;
int secondint = (int)strtol(ptr, &end, 10);
if (secondint > firstint)
cpu_count += secondint - firstint + 1; // inclusive (e.g., 0-7, or 8-16)
}
ptr = end;
}
INLINE_SYSCALL(close, 1, fd);
if (cpu_count == 0)
return -PAL_ERROR_STREAMNOTEXIST;
return cpu_count;
}
static int load_enclave (struct pal_enclave * enclave,
char * manifest_uri,
char * exec_uri,
@@ -737,6 +786,11 @@ static int load_enclave (struct pal_enclave * enclave,
pal_sec->pid = INLINE_SYSCALL(getpid, 0);
pal_sec->uid = INLINE_SYSCALL(getuid, 0);
pal_sec->gid = INLINE_SYSCALL(getgid, 0);
int num_cpus = get_cpu_count();
if (num_cpus < 0) {
return num_cpus;
}
pal_sec->num_cpus = num_cpus;
#ifdef DEBUG
size_t env_i = 0;
-2
View File
@@ -35,8 +35,6 @@
typedef __kernel_pid_t pid_t;
#include <asm/errno.h>
#include <asm/fcntl.h>
#include <asm/stat.h>
#include <linux/stat.h>
#define DEVICE_OPS(handle) \
({ \
-2
View File
@@ -35,8 +35,6 @@
typedef __kernel_pid_t pid_t;
#undef __GLIBC__
#include <linux/stat.h>
#include <asm/stat.h>
#include <asm/fcntl.h>
#include <asm/errno.h>
/* 'open' operation for file streams */
+58 -16
View File
@@ -383,9 +383,57 @@ static char * cpu_flags[]
"pbe", // "pending break event"
};
void _DkGetCPUInfo (PAL_CPU_INFO * ci)
/*
* Returns the number of online CPUs read from /sys/devices/system/cpu/online, -errno on failure.
* Understands complex formats like "1,3-5,6".
*/
int get_cpu_count(void) {
int fd = INLINE_SYSCALL(open, 3, "/sys/devices/system/cpu/online", O_RDONLY|O_CLOEXEC, 0);
if (fd < 0)
return unix_to_pal_error(ERRNO(fd));
char buf[64];
int ret = INLINE_SYSCALL(read, 3, fd, buf, sizeof(buf) - 1);
INLINE_SYSCALL(close, 1, fd);
if (ret < 0) {
return unix_to_pal_error(ERRNO(ret));
}
buf[ret] = '\0'; /* ensure null-terminated buf even in partial read */
char* end;
char* ptr = buf;
int cpu_count = 0;
while (*ptr) {
while (*ptr == ' ' || *ptr == '\t' || *ptr == ',')
ptr++;
int firstint = (int)strtol(ptr, &end, 10);
if (ptr == end)
break;
if (*end == '\0' || *end == ',') {
/* single CPU index, count as one more CPU */
cpu_count++;
} else if (*end == '-') {
/* CPU range, count how many CPUs in range */
ptr = end + 1;
int secondint = (int)strtol(ptr, &end, 10);
if (secondint > firstint)
cpu_count += secondint - firstint + 1; // inclusive (e.g., 0-7, or 8-16)
}
ptr = end;
}
if (cpu_count == 0)
return -PAL_ERROR_STREAMNOTEXIST;
return cpu_count;
}
int _DkGetCPUInfo (PAL_CPU_INFO * ci)
{
unsigned int words[PAL_CPUID_WORD_NUM];
int rv = 0;
const size_t VENDOR_ID_SIZE = 13;
char* vendor_id = malloc(VENDOR_ID_SIZE);
@@ -408,22 +456,15 @@ void _DkGetCPUInfo (PAL_CPU_INFO * ci)
brand[BRAND_SIZE - 1] = '\0';
ci->cpu_brand = brand;
if (!memcmp(vendor_id, "GenuineIntel", 12)) {
/* According to SDM: EBX[15:0] is to enumerate processor topology
* of the system. However this value is intended for display/diagnostic
* purposes. The actual number of logical processors available to
* BIOS/OS/App may be different. We use this leaf for now as it's the
* best option we have so far to get the cpu number */
cpuid(0xb, 1, words);
ci->cpu_num = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EBX], 0, 16);
} else if (!memcmp(vendor_id, "AuthenticAMD", 12)) {
cpuid(0x8000008, 0, words);
ci->cpu_num = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EAX], 0, 8) + 1;
} else {
ci->cpu_num = 1;
/* we cannot use CPUID(0xb) because it counts even disabled-by-BIOS cores (e.g. HT cores);
* instead we extract info on number of online CPUs by parsing sysfs pseudo-files */
int cores = get_cpu_count();
if (cores < 0) {
free(vendor_id);
free(brand);
return cores;
}
ci->cpu_num = cores;
cpuid(1, 0, words);
ci->cpu_family = BIT_EXTRACT_LE(words[PAL_CPUID_WORD_EAX], 8, 12);
@@ -460,4 +501,5 @@ void _DkGetCPUInfo (PAL_CPU_INFO * ci)
flags[flen ? flen - 1 : 0] = 0;
ci->cpu_flags = flags;
return rv;
}
-2
View File
@@ -32,12 +32,10 @@
#include <linux/types.h>
typedef __kernel_pid_t pid_t;
#include <linux/stat.h>
#include <linux/msg.h>
#include <linux/socket.h>
#include <linux/wait.h>
#include <asm/fcntl.h>
#include <asm/stat.h>
#include <asm/socket.h>
#include <asm/poll.h>
#include <sys/signal.h>
+6 -2
View File
@@ -30,6 +30,11 @@
#include <sys/syscall.h>
#include <sigset.h>
#include <asm/fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef __x86_64__
# include "sysdep-x86_64.h"
#endif
@@ -74,7 +79,7 @@ extern struct pal_linux_state {
#endif
} linux_state;
#include <asm/fcntl.h>
#include <asm/mman.h>
#ifdef INLINE_SYSCALL
@@ -153,7 +158,6 @@ int handle_deserialize (PAL_HANDLE * handle, const void * data, int size);
#define ACCESS_W 2
#define ACCESS_X 1
struct stat;
bool stataccess (struct stat * stats, int acc);
void init_child_process (PAL_HANDLE * parent, PAL_HANDLE * exec,
+2 -1
View File
@@ -269,7 +269,8 @@ PAL_NUM _DkGetProcessId (void);
PAL_NUM _DkGetHostId (void);
unsigned long _DkMemoryQuota (void);
unsigned long _DkMemoryAvailableQuota (void);
void _DkGetCPUInfo (PAL_CPU_INFO * info);
// Returns 0 on success, negative PAL code on failure
int _DkGetCPUInfo (PAL_CPU_INFO * info);
/* Internal DK calls, in case any of the internal routines needs to use them */
/* DkStream calls */