Browse Source

[LibOS,Pal/{Linux, Linux-SGX}] Add bogomips to /proc/cpuinfo

borysp 4 years ago
parent
commit
b40862a59c

+ 71 - 65
LibOS/shim/src/fs/proc/info.c

@@ -7,6 +7,7 @@
 #include <errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
+#include <stdarg.h>
 
 #include <pal.h>
 #include <pal_error.h>
@@ -88,6 +89,46 @@ retry:
     return 0;
 }
 
+// FIXME: remove once global realloc is enabled
+static void* realloc(void* ptr, size_t old_size, size_t new_size) {
+    void* tmp = malloc(new_size);
+    if (!tmp) {
+        return NULL;
+    }
+
+    memcpy(tmp, ptr, old_size);
+
+    free(ptr);
+
+    return tmp;
+}
+
+static int print_to_str(char** str, size_t off, size_t* size, const char* fmt, ...) {
+    int ret;
+    va_list ap;
+
+retry:
+    va_start(ap, fmt);
+    ret = vsnprintf(*str + off, *size - off, fmt, ap);
+    va_end(ap);
+
+    if (ret < 0) {
+        return -EINVAL;
+    }
+
+    if ((size_t)ret >= *size - off) {
+        char* tmp = realloc(*str, *size, *size + 128);
+        if (!tmp) {
+            return -ENOMEM;
+        }
+        *size += 128;
+        *str = tmp;
+        goto retry;
+    }
+
+    return ret;
+}
+
 static int proc_cpuinfo_open(struct shim_handle* hdl, const char* name, int flags) {
     // This function only serves one file
     __UNUSED(name);
@@ -95,76 +136,41 @@ static int proc_cpuinfo_open(struct shim_handle* hdl, const char* name, int flag
     if (flags & (O_WRONLY | O_RDWR))
         return -EACCES;
 
-    int len, max = 128;
-    char* str = NULL;
-
-    struct {
-        const char* fmt;
-        unsigned long val;
+    size_t len = 0,
+           max = 128;
+    char* str = malloc(max);
+    if (!str) {
+        return -ENOMEM;
     }
-    /* below strings must match exactly the strings retrieved from
-     * /proc/cpuinfo (see Linux's arch/x86/kernel/cpu/proc.c) */
-    cpuinfo[] = {
-        {
-            "processor\t: %lu\n",
-            0,
-        },
-        {
-            "vendor_id\t: %s\n",
-            (unsigned long)pal_control.cpu_info.cpu_vendor,
-        },
-        {
-            "cpu family\t: %lu\n",
-            pal_control.cpu_info.cpu_family,
-        },
-        {
-            "model\t\t: %lu\n",
-            pal_control.cpu_info.cpu_model,
-        },
-        {
-            "model name\t: %s\n",
-            (unsigned long)pal_control.cpu_info.cpu_brand,
-        },
-        {
-            "stepping\t: %lu\n",
-            pal_control.cpu_info.cpu_stepping,
-        },
-        {
-            "core id\t\t: %lu\n",
-            0,
-        },
-        {
-            "cpu cores\t: %lu\n",
-            pal_control.cpu_info.cpu_num,
-        },
-    };
 
-retry:
-    max *= 2;
-    len = 0;
-    free(str);
-    str = malloc(max);
-    if (!str)
-        return -ENOMEM;
+#define ADD_INFO(fmt, ...) do {                                         \
+        int ret = print_to_str(&str, len, &max, fmt, ##__VA_ARGS__);    \
+        if (ret < 0) {                                                  \
+            free(str);                                                  \
+            return ret;                                                 \
+        }                                                               \
+        len += ret;                                                     \
+    } while (0)
 
     for (size_t n = 0; n < pal_control.cpu_info.cpu_num; n++) {
-        cpuinfo[0].val = n;
-        cpuinfo[6].val = n;
-        for (size_t i = 0; i < ARRAY_SIZE(cpuinfo); i++) {
-            int ret = snprintf(str + len, max - len, cpuinfo[i].fmt, cpuinfo[i].val);
-
-            if (len + ret == max)
-                goto retry;
-
-            len += ret;
-        }
-
-        if (len >= max - 1)
-            goto retry;
-
-        str[len++] = '\n';
-        str[len]   = 0;
+        /* Below strings must match exactly the strings retrieved from /proc/cpuinfo
+         * (see Linux's arch/x86/kernel/cpu/proc.c) */
+        ADD_INFO("processor\t: %lu\n", n);
+        ADD_INFO("vendor_id\t: %s\n", pal_control.cpu_info.cpu_vendor);
+        ADD_INFO("cpu family\t: %lu\n", pal_control.cpu_info.cpu_family);
+        ADD_INFO("model\t\t: %lu\n", pal_control.cpu_info.cpu_model);
+        ADD_INFO("model name\t: %s\n", pal_control.cpu_info.cpu_brand);
+        ADD_INFO("stepping\t: %lu\n", pal_control.cpu_info.cpu_stepping);
+        ADD_INFO("core id\t\t: %lu\n", n);
+        ADD_INFO("cpu cores\t: %lu\n", pal_control.cpu_info.cpu_num);
+        double bogomips = pal_control.cpu_info.cpu_bogomips;
+        // Apparently graphene snprintf cannot into floats.
+        ADD_INFO("bogomips\t: %lu.%02lu\n",
+                 (unsigned long)bogomips,
+                 (unsigned long)(bogomips * 100.0 + 0.5) % 100);
+        ADD_INFO("\n");
     }
+#undef ADD_INFO
 
     struct shim_str_data* data = calloc(1, sizeof(struct shim_str_data));
     if (!data) {

+ 8 - 0
Pal/include/host/Linux-common/bogomips.h

@@ -0,0 +1,8 @@
+#ifndef BOGOMIPS_H
+#define BOGOMIPS_H
+
+double get_bogomips_from_cpuinfo_buf(const char* buf, size_t size);
+double sanitize_bogomips_value(double);
+
+#endif // BOGOMIPS_H
+

+ 2 - 1
Pal/include/lib/api.h

@@ -186,7 +186,8 @@ void fprintfmt (int (*_fputch)(void *, int, void *), void * f, void * putdat,
 void vfprintfmt (int (*_fputch)(void *, int, void *), void * f, void * putdat,
                  const char * fmt, va_list ap) __attribute__((format(printf, 4, 0)));
 
-int snprintf (char * buf, size_t n, const char * fmt, ...) __attribute__((format(printf, 3, 4)));
+int vsnprintf(char* buf, size_t n, const char* fmt, va_list ap);
+int snprintf(char* buf, size_t n, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
 
 /* Miscelleneous */
 

+ 1 - 0
Pal/include/pal/pal.h

@@ -270,6 +270,7 @@ typedef struct {
     PAL_NUM cpu_family;
     PAL_NUM cpu_model;
     PAL_NUM cpu_stepping;
+    double  cpu_bogomips;
     PAL_STR cpu_flags;
 } PAL_CPU_INFO;
 

+ 4 - 3
Pal/lib/stdlib/printfmt.c

@@ -266,7 +266,8 @@ void fprintfmt(int (*_fputch)(void*, int, void*), void* f, void* putdat, const c
 }
 
 struct sprintbuf {
-    int cnt, max;
+    size_t cnt;
+    size_t max;
     char* buf;
 };
 
@@ -280,7 +281,7 @@ static int sprintputch(void* f, int ch, struct sprintbuf* b) {
     return 0;
 }
 
-static int vsprintf(char* buf, int n, const char* fmt, va_list ap) {
+int vsnprintf(char* buf, size_t n, const char* fmt, va_list ap) {
     struct sprintbuf b = {0, n, buf};
 
     if (!buf || n < 1)
@@ -301,7 +302,7 @@ int snprintf(char* buf, size_t n, const char* fmt, ...) {
     int rc;
 
     va_start(ap, fmt);
-    rc = vsprintf(buf, n, fmt, ap);
+    rc = vsnprintf(buf, n, fmt, ap);
     va_end(ap);
 
     return rc;

+ 8 - 1
Pal/src/host/Linux-SGX/Makefile

@@ -7,6 +7,7 @@ ias_cert_file = quote/$(notdir $(ias_cert_url))
 
 CFLAGS += -I. -Iinclude -I../.. -I../../../include -I../../../include/pal \
 	-I../../../lib/crypto/mbedtls/include -I../../../include/host/Linux-SGX \
+	-I../../../include/host/Linux-common \
 	-I../../../include/lib -Isgx-driver
 ASFLAGS += -I. -I../.. -I../../../include
 
@@ -16,6 +17,8 @@ defs	= -DIN_PAL -DPAL_DIR=$(PAL_DIR) -DRUNTIME_DIR=$(RUNTIME_DIR)
 CFLAGS += $(defs)
 ASFLAGS += $(defs)
 
+commons_objs = bogomips.o
+
 enclave-objs = \
 	db_devices.o \
 	db_eventfd.o \
@@ -39,7 +42,8 @@ enclave-objs = \
 	enclave_pages.o \
 	enclave_platform.o \
 	enclave_untrusted.o \
-	enclave_xstate.o
+	enclave_xstate.o \
+	$(commons_objs)
 
 enclave-asm-objs = enclave_entry.o
 
@@ -75,6 +79,9 @@ $(patsubst %.o,%.s,$(enclave-asm-objs)): ASFLAGS += -DIN_ENCLAVE
 $(urts-objs): quote/aesm.pb-c.h
 $(enclave-objs): quote/generated-cacert.h
 
+$(commons_objs): %.o: ../Linux-common/%.c
+	$(call cmd,cc_o_c)
+
 %.o: %.c
 	$(call cmd,cc_o_c)
 

+ 31 - 6
Pal/src/host/Linux-SGX/db_main.c

@@ -21,18 +21,19 @@
  * processes environment, arguments and manifest.
  */
 
-#include "pal_defs.h"
-#include "pal_linux_defs.h"
+#include "api.h"
+#include "bogomips.h"
 #include "pal.h"
-#include "pal_internal.h"
-#include "pal_linux.h"
 #include "pal_debug.h"
+#include "pal_defs.h"
 #include "pal_error.h"
+#include "pal_internal.h"
+#include "pal_linux.h"
+#include "pal_linux_defs.h"
 #include "pal_security.h"
-#include "api.h"
 
-#include <asm/mman.h>
 #include <asm/ioctls.h>
+#include <asm/mman.h>
 #include <elf/elf.h>
 #include <sysdeps/generic/ldsodefs.h>
 
@@ -490,6 +491,24 @@ static char * cpu_flags[]
           "pbe",    // "pending break event"
         };
 
+static double get_bogomips(void) {
+    int fd = -1;
+    char buf[0x800] = { 0 };
+
+    fd = ocall_open("/proc/cpuinfo", O_RDONLY, 0);
+    if (fd < 0) {
+        return 0.0;
+    }
+
+    /* Although the whole file might not fit in this size, the first cpu description should. */
+    int x = ocall_read(fd, buf, sizeof(buf) - 1);
+    ocall_close(fd);
+    if (x < 0) {
+        return 0.0;
+    }
+
+    return sanitize_bogomips_value(get_bogomips_from_cpuinfo_buf(buf, sizeof(buf)));
+}
 
 int _DkGetCPUInfo (PAL_CPU_INFO * ci)
 {
@@ -557,5 +576,11 @@ int _DkGetCPUInfo (PAL_CPU_INFO * ci)
 
     flags[flen ? flen - 1 : 0] = 0;
     ci->cpu_flags = flags;
+
+    ci->cpu_bogomips = get_bogomips();
+    if (ci->cpu_bogomips == 0.0) {
+        SGX_DBG(DBG_E, "Warning: bogomips could not be retrieved, passing 0.0 to the application\n");
+    }
+
     return rv;
 }

+ 71 - 0
Pal/src/host/Linux-common/bogomips.c

@@ -0,0 +1,71 @@
+#include "api.h"
+#include "bogomips.h"
+
+/* This version is too dumb to be shared by the whole repository and should be removed once we get
+ * a proper stdlib (like musl). */
+static double proc_cpuinfo_atod(const char* s) {
+    double ret = 0.0;
+    char* end = NULL;
+    double base, fractional;
+
+    base = strtol(s, &end, 10);
+
+    if (*end == '.') {
+        s = end + 1;
+        fractional = strtol(s, &end, 10);
+        while (s != end) {
+            fractional /= 10.0;
+            s++;
+        }
+        ret = base + fractional;
+    }
+
+    return ret;
+}
+
+double get_bogomips_from_cpuinfo_buf(const char* buf, size_t size) {
+    /* We could use strstr if graphene had one. */
+    /* Each prefix of the word "bogomips" occurs only once in the whole word, hence this works. */
+    const char* const word = "bogomips";
+    const size_t word_size = strlen(word);
+    size_t i = 0,
+           j = 0;
+
+    if (word_size > size) {
+        return 0.0;
+    }
+
+    while (i < size - word_size && buf[i]) {
+        j = 0;
+        while (j < word_size && buf[i + j] == word[j]) {
+            j++;
+        }
+
+        if (j) {
+            i += j;
+        } else {
+            i += 1;
+        }
+
+        if (j == word_size) {
+            /* buf is null-terminated, so no need to check size. word does not contain neither
+             * spaces nor tabs, hence we can forward global index `i`, even if we do not return
+             * here. */
+            while (buf[i] == ' ' || buf[i] == '\t') {
+                i++;
+            }
+            if (buf[i] == ':') {
+                return proc_cpuinfo_atod(&buf[i + 1]);
+            }
+        }
+    }
+
+    return 0.0;
+}
+
+double sanitize_bogomips_value(double v) {
+    if (!__builtin_isnormal(v) || v < 0.0) {
+        return 0.0;
+    }
+    return v;
+}

+ 10 - 3
Pal/src/host/Linux/Makefile

@@ -2,8 +2,8 @@ include ../../../../Scripts/Makefile.configs
 include Makefile.am
 
 CFLAGS	+= -I. -Iinclude -I../.. -I../../../include -I../../../include/pal \
-	   -I../../../include/host/Linux -I../../../include/lib \
-	   -I../../../linux-kernel/graphene
+	-I../../../include/host/Linux -I../../../include/lib \
+	-I../../../include/host/Linux-common
 ASFLAGS += -I. -Iinclude -I../.. -I../../../include
 
 host_files = libpal-Linux.a pal.map
@@ -11,6 +11,9 @@ host_files = libpal-Linux.a pal.map
 defs	= -DIN_PAL -DPAL_DIR=$(PAL_DIR) -DRUNTIME_DIR=$(RUNTIME_DIR)
 CFLAGS += $(defs)
 ASFLAGS += $(defs)
+
+commons_objs = bogomips.o
+
 objs = \
 	clone-x86_64.o \
 	db_devices.o \
@@ -28,7 +31,8 @@ objs = \
 	db_rtld.o \
 	db_sockets.o \
 	db_streams.o \
-	db_threading.o
+	db_threading.o \
+	$(commons_objs)
 
 graphene_lib = .lib/graphene-lib.a
 
@@ -38,6 +42,9 @@ all: $(host_files)
 libpal-Linux.a: $(objs) $(graphene_lib)
 	$(call cmd,ar_a_o)
 
+$(commons_objs): %.o: ../Linux-common/%.c
+	$(call cmd,cc_o_c)
+
 %.o: %.c
 	$(call cmd,cc_o_c)
 

+ 33 - 7
Pal/src/host/Linux/db_main.c

@@ -21,19 +21,20 @@
  * processes environment, arguments and manifest.
  */
 
-#include "pal_defs.h"
-#include "pal_linux_defs.h"
+#include "api.h"
+#include "bogomips.h"
 #include "pal.h"
-#include "pal_internal.h"
-#include "pal_linux.h"
 #include "pal_debug.h"
+#include "pal_defs.h"
 #include "pal_error.h"
+#include "pal_internal.h"
+#include "pal_linux.h"
+#include "pal_linux_defs.h"
 #include "pal_security.h"
-#include "api.h"
 
-#include <asm/mman.h>
-#include <asm/ioctls.h>
 #include <asm/errno.h>
+#include <asm/ioctls.h>
+#include <asm/mman.h>
 #include <elf/elf.h>
 #include <sysdeps/generic/ldsodefs.h>
 
@@ -432,6 +433,25 @@ int get_cpu_count(void) {
     return cpu_count;
 }
 
+static double get_bogomips(void) {
+    int fd = -1;
+    char buf[0x800] = { 0 };
+
+    fd = INLINE_SYSCALL(open, 2, "/proc/cpuinfo", O_RDONLY);
+    if (fd < 0) {
+        return 0.0;
+    }
+
+    /* Although the whole file might not fit in this size, the first cpu description should. */
+    long x = INLINE_SYSCALL(read, 3, fd, buf, sizeof(buf) - 1);
+    INLINE_SYSCALL(close, 1, fd);
+    if (x < 0) {
+        return 0.0;
+    }
+
+    return sanitize_bogomips_value(get_bogomips_from_cpuinfo_buf(buf, sizeof(buf)));
+}
+
 int _DkGetCPUInfo (PAL_CPU_INFO * ci)
 {
     unsigned int words[PAL_CPUID_WORD_NUM];
@@ -503,5 +523,11 @@ int _DkGetCPUInfo (PAL_CPU_INFO * ci)
 
     flags[flen ? flen - 1 : 0] = 0;
     ci->cpu_flags = flags;
+
+    ci->cpu_bogomips = get_bogomips();
+    if (ci->cpu_bogomips == 0.0) {
+        printf("Warning: bogomips could not be retrieved, passing 0.0 to the application\n");
+    }
+
     return rv;
 }