diff --git a/Pal/src/db_main.c b/Pal/src/db_main.c index 8fce1711..249be8aa 100644 --- a/Pal/src/db_main.c +++ b/Pal/src/db_main.c @@ -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"); } diff --git a/Pal/src/host/FreeBSD/db_main.c b/Pal/src/host/FreeBSD/db_main.c index 71554cec..95f52015 100644 --- a/Pal/src/host/FreeBSD/db_main.c +++ b/Pal/src/host/FreeBSD/db_main.c @@ -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); diff --git a/Pal/src/host/Linux-SGX/db_main.c b/Pal/src/host/Linux-SGX/db_main.c index d8ccf43a..18afd004 100644 --- a/Pal/src/host/Linux-SGX/db_main.c +++ b/Pal/src/host/Linux-SGX/db_main.c @@ -75,6 +75,7 @@ PAL_NUM _DkGetHostId (void) #include "elf-x86_64.h" #include "dynamic_link.h" +#include 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; } diff --git a/Pal/src/host/Linux-SGX/pal_security.h b/Pal/src/host/Linux-SGX/pal_security.h index d468f217..4a0010e6 100644 --- a/Pal/src/host/Linux-SGX/pal_security.h +++ b/Pal/src/host/Linux-SGX/pal_security.h @@ -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 diff --git a/Pal/src/host/Linux-SGX/sgx_main.c b/Pal/src/host/Linux-SGX/sgx_main.c index f9e11869..d84b9913 100644 --- a/Pal/src/host/Linux-SGX/sgx_main.c +++ b/Pal/src/host/Linux-SGX/sgx_main.c @@ -1,4 +1,5 @@ #include +#include #include #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; diff --git a/Pal/src/host/Linux/db_devices.c b/Pal/src/host/Linux/db_devices.c index f7903791..abefe01e 100644 --- a/Pal/src/host/Linux/db_devices.c +++ b/Pal/src/host/Linux/db_devices.c @@ -35,8 +35,6 @@ typedef __kernel_pid_t pid_t; #include #include -#include -#include #define DEVICE_OPS(handle) \ ({ \ diff --git a/Pal/src/host/Linux/db_files.c b/Pal/src/host/Linux/db_files.c index 9b1fc096..5750a069 100644 --- a/Pal/src/host/Linux/db_files.c +++ b/Pal/src/host/Linux/db_files.c @@ -35,8 +35,6 @@ typedef __kernel_pid_t pid_t; #undef __GLIBC__ #include -#include -#include #include /* 'open' operation for file streams */ diff --git a/Pal/src/host/Linux/db_main.c b/Pal/src/host/Linux/db_main.c index 471a481b..9949b901 100644 --- a/Pal/src/host/Linux/db_main.c +++ b/Pal/src/host/Linux/db_main.c @@ -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; } diff --git a/Pal/src/host/Linux/db_streams.c b/Pal/src/host/Linux/db_streams.c index a4ce137c..d588df0e 100644 --- a/Pal/src/host/Linux/db_streams.c +++ b/Pal/src/host/Linux/db_streams.c @@ -32,12 +32,10 @@ #include typedef __kernel_pid_t pid_t; -#include #include #include #include #include -#include #include #include #include diff --git a/Pal/src/host/Linux/pal_linux.h b/Pal/src/host/Linux/pal_linux.h index 55aaaaac..90ed5409 100644 --- a/Pal/src/host/Linux/pal_linux.h +++ b/Pal/src/host/Linux/pal_linux.h @@ -30,6 +30,11 @@ #include #include +#include +#include +#include +#include + #ifdef __x86_64__ # include "sysdep-x86_64.h" #endif @@ -74,7 +79,7 @@ extern struct pal_linux_state { #endif } linux_state; -#include + #include #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, diff --git a/Pal/src/pal_internal.h b/Pal/src/pal_internal.h index 73af96d8..57117575 100644 --- a/Pal/src/pal_internal.h +++ b/Pal/src/pal_internal.h @@ -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 */