From 89bd51094d1146e79ab4374e1adb8322c4201745 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Thu, 13 Aug 2020 10:26:13 +0000 Subject: [PATCH 1/3] lkl: Add hook to lkl_host_operations to get cpuinfo --- arch/lkl/include/uapi/asm/host_ops.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/lkl/include/uapi/asm/host_ops.h b/arch/lkl/include/uapi/asm/host_ops.h index 1b6360958cafff..b66d9ea2fe2548 100644 --- a/arch/lkl/include/uapi/asm/host_ops.h +++ b/arch/lkl/include/uapi/asm/host_ops.h @@ -107,6 +107,12 @@ struct ucontext; * the function that will eventually call longjmp here * * @jmp_buf_longjmp - perform a jump back to the saved jump buffer + * + * @cpuinfo_get - Returns the /proc/cpuinfo string. It needs to be provided a + * pointer to the destination buffer and its size, and it returns the total + * length of the string. As the string may be longer than the provided buffer, + * the returned value may be bigger than the buffer size. The string will be + * cropped in that case. */ struct lkl_host_operations { const char *virtio_devices; @@ -159,6 +165,8 @@ struct lkl_host_operations { void (*jmp_buf_set)(struct lkl_jmp_buf *jmpb, void (*f)(void)); void (*jmp_buf_longjmp)(struct lkl_jmp_buf *jmpb, int val); + + unsigned int (*cpuinfo_get)(char *buffer, unsigned int buffer_len); }; /** From 51d6677bfc9bfcaae577071d90ae2e9d25f843ae Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Fri, 14 Aug 2020 10:03:06 +0000 Subject: [PATCH 2/3] lkl: Fill /proc/cpuinfo with information For now, only the CPU number and related fields are known (and they are the number of ethreads). The other fields are still fake. --- arch/lkl/kernel/proc.c | 104 ++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 48 deletions(-) diff --git a/arch/lkl/kernel/proc.c b/arch/lkl/kernel/proc.c index da7336ec8fe595..473616f0ae81b9 100644 --- a/arch/lkl/kernel/proc.c +++ b/arch/lkl/kernel/proc.c @@ -1,69 +1,77 @@ +#include +#include #include +#include #ifdef CONFIG_PROC_FS -/* - * TODO: This currently just hard-codes some output for /proc/cpuinfo that is - * plausible and can be parsed by an application. Note though that CPU features, - * the virtual CPU core count and socket count are wrong. - */ +static char *cpuinfo_buf; +static unsigned int cpuinfo_len; + static int show_cpuinfo(struct seq_file *m, void *v) { - seq_printf(m, "processor : 0\n" - "cpu family : 6\n" - "model : 158\n" - "model name : Intel(R) Xeon(R) CPU E3-1280 v6 @ 3.90GHz\n" - "stepping : 9\n" - "microcode : 0xb4\n" - "cpu MHz : 800.063\n" - "cache size : 8192 KB\n" - "physical id : 0\n" - "siblings : 4\n" - "core id : 0\n" - "cpu cores : 4\n" - "apicid : 0\n" - "initial apicid : 0\n" - "fpu : yes\n" - "fpu_exception : yes\n" - "cpuid level : 22\n" - "wp : yes\n" - "flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d\n" - "bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs\n" - "bogomips : 7824.00\n" - "clflush size : 64\n" - "cache_alignment : 64\n" - "address sizes : 39 bits physical, 48 bits virtual\n" - "power management: \n"); - - seq_puts(m, "\n\n"); - - return 0; -} + loff_t *spos = v; + + if (*spos >= cpuinfo_len) + return 0; + + seq_putc(m, cpuinfo_buf[*spos]); -int __cpuinfo_accessed = 0; + return 0; +} static void *c_start(struct seq_file *m, loff_t *pos) { - // TODO: missing correct implementation - - // Only output information once - if (__cpuinfo_accessed) - return NULL; - - __cpuinfo_accessed = 1; - return (void*)1; + unsigned int buf_size; + loff_t *spos; + + if (cpuinfo_buf == NULL) { + + /* How big is the buffer that we need? */ + cpuinfo_len = lkl_ops->cpuinfo_get(NULL, 0); + buf_size = cpuinfo_len + 1; + + cpuinfo_buf = kmalloc(buf_size, GFP_KERNEL); + if (cpuinfo_buf == NULL) { + printk("cpuinfo: Not enough memory (%u bytes needed)\n", buf_size); + return NULL; + } + + /* Print cpuinfo to the buffer we have allocated */ + cpuinfo_len = lkl_ops->cpuinfo_get(cpuinfo_buf, buf_size); + } + + spos = kmalloc(sizeof(loff_t), GFP_KERNEL); + if (spos == NULL) { + printk("cpuinfo: Not enough memory (%lu bytes needed)\n", + sizeof(loff_t)); + return NULL; + } + + if (*pos >= cpuinfo_len) + return NULL; + + *spos = *pos; + return spos; } static void *c_next(struct seq_file *m, void *v, loff_t *pos) { - // TODO: missing implementation - return NULL; + loff_t *spos = v; + + *spos = *spos + 1; + *pos = *spos; + + if (*spos >= cpuinfo_len) + return NULL; + + return spos; } static void c_stop(struct seq_file *m, void *v) { - // TODO: missing implementation + kfree(v); } const struct seq_operations cpuinfo_op = { @@ -73,4 +81,4 @@ const struct seq_operations cpuinfo_op = { .show = show_cpuinfo, }; -#endif \ No newline at end of file +#endif From 33594c3af33e97d5fae9394e3cba5a1f9a062b60 Mon Sep 17 00:00:00 2001 From: Antonio Nino Diaz Date: Fri, 4 Sep 2020 10:26:36 +0000 Subject: [PATCH 3/3] lkl: Add test that reads /proc/cpuinfo This test reads from the file from two descriptors at the same time and verifies that the file isn't empty and the contents read from both descriptors are the same. The current information in cpuinfo is hardcoded. --- tools/lkl/Targets | 1 + tools/lkl/lib/posix-host.c | 38 ++++++++++++ tools/lkl/tests/Build | 1 + tools/lkl/tests/cpuinfo.c | 116 +++++++++++++++++++++++++++++++++++++ tools/lkl/tests/cpuinfo.sh | 8 +++ tools/lkl/tests/run.py | 1 + 6 files changed, 165 insertions(+) create mode 100644 tools/lkl/tests/cpuinfo.c create mode 100755 tools/lkl/tests/cpuinfo.sh diff --git a/tools/lkl/Targets b/tools/lkl/Targets index e6394fae452657..a99b839e938c55 100644 --- a/tools/lkl/Targets +++ b/tools/lkl/Targets @@ -22,6 +22,7 @@ LDLIBS_cptofs-y := -larchive LDLIBS_cptofs-$(LKL_HOST_CONFIG_NEEDS_LARGP) += -largp progs-y += tests/boot +progs-y += tests/cpuinfo progs-y += tests/disk progs-y += tests/net-test diff --git a/tools/lkl/lib/posix-host.c b/tools/lkl/lib/posix-host.c index db63ed7e35fb19..b4825223dcfe0e 100644 --- a/tools/lkl/lib/posix-host.c +++ b/tools/lkl/lib/posix-host.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -311,6 +312,42 @@ static long _gettid(void) #endif } +static unsigned int cpuinfo_get(char *buffer, unsigned int buffer_len) +{ + /* TODO: The output of this function is hardcoded for now. */ + int len; + + len = snprintf(buffer, buffer_len, + "processor : 0\n" + "cpu family : 6\n" + "model : 158\n" + "model name : Intel(R) Xeon(R) CPU E3-1280 v6 @ 3.90GHz\n" + "stepping : 9\n" + "microcode : 0xb4\n" + "cpu MHz : 800.063\n" + "cache size : 8192 KB\n" + "physical id : 0\n" + "siblings : 1\n" + "core id : 0\n" + "cpu cores : 1\n" + "apicid : 0\n" + "initial apicid : 0\n" + "fpu : yes\n" + "fpu_exception : yes\n" + "cpuid level : 22\n" + "wp : yes\n" + "flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse3 clflush dts ac pi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc art arch_perfmon pebs bt rep_good nopl x topology nonstop_tsc cpuid aperfmperf tsc_known_freq pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm aabm 3dnowprefetch cpuid_fault epb invpcid_single pti ssbd ibrs ibpb stibp tpr_shadow vnmi flexpriority ept vpid fsgsbase tsc_adjust bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx rdseed adx smap clflushopt intel_pt xsaveopt xsavec xgetbv1 xsaves dtherm ida arat pln pts hwp hwp_notify hwp_act_window hwp_epp md_clear flush_l1d\n" + "bugs : cpu_meltdown spectre_v1 spectre_v2 spec_store_bypass l1tf mds swapgs\n" + "bogomips : 7824.00\n" + "clflush size : 64\n" + "cache_alignment : 64\n" + "address sizes : 39 bits physical, 48 bits virtual\n" + "power management: \n" + "\n"); + + return len; +} + struct lkl_host_operations lkl_host_ops = { .panic = panic, .thread_create = thread_create, @@ -344,6 +381,7 @@ struct lkl_host_operations lkl_host_ops = { .gettid = _gettid, .jmp_buf_set = jmp_buf_set, .jmp_buf_longjmp = jmp_buf_longjmp, + .cpuinfo_get = cpuinfo_get, }; static int fd_get_capacity(struct lkl_disk disk, unsigned long long *res) diff --git a/tools/lkl/tests/Build b/tools/lkl/tests/Build index ace86a3d34383e..567f18a847d343 100644 --- a/tools/lkl/tests/Build +++ b/tools/lkl/tests/Build @@ -1,3 +1,4 @@ boot-y += boot.o test.o +cpuinfo-y += cpuinfo.o test.o disk-y += disk.o cla.o test.o net-test-y += net-test.o cla.o test.o diff --git a/tools/lkl/tests/cpuinfo.c b/tools/lkl/tests/cpuinfo.c new file mode 100644 index 00000000000000..99bc74b303b551 --- /dev/null +++ b/tools/lkl/tests/cpuinfo.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include + +#include "test.h" + +LKL_TEST_CALL(start_kernel, lkl_start_kernel, 0, &lkl_host_ops, + "mem=16M loglevel=8"); + +static int lkl_test_cpuinfo(void) +{ + /* The buffer size must be a multiple of the read sizes */ +#define BUF_SIZE (64 * 1024) +#define READ_SIZE_1 16 +#define READ_SIZE_2 32 + + int ret; + int err; + int f1, f2; + static char buf1[BUF_SIZE], buf2[BUF_SIZE]; + long read1, read2; + int done1, done2; + long totalread1, totalread2; + + ret = TEST_FAILURE; + + err = lkl_mount_fs("proc"); + if (err < 0) { + lkl_test_logf("failed to mount /proc\n"); + return TEST_FAILURE; + } + + f1 = lkl_sys_open("/proc/cpuinfo", LKL_O_RDONLY, 0); + if (f1 < 0) { + lkl_test_logf("failed to open /proc/cpuinfo (f1): %s\n", + lkl_strerror(f1)); + return TEST_FAILURE; + } + + f2 = lkl_sys_open("/proc/cpuinfo", LKL_O_RDONLY, 0); + if (f2 < 0) { + lkl_sys_close(f1); + lkl_test_logf("failed to open /proc/cpuinfo (f2): %s\n", + lkl_strerror(f2)); + return TEST_FAILURE; + } + + totalread1 = 0; + totalread2 = 0; + + done1 = 0; + done2 = 0; + + while (!done1 || !done2) { + if (totalread1 >= (BUF_SIZE - READ_SIZE_1)) { + lkl_test_logf("file is too big\n"); + totalread1 = 0; + break; + } + + if (totalread2 >= (BUF_SIZE - READ_SIZE_2)) { + lkl_test_logf("file is too big\n"); + totalread2 = 0; + break; + } + + if (!done1) { + read1 = lkl_sys_read(f1, &(buf1[totalread1]), + READ_SIZE_1); + if (read1 <= 0) + done1 = 1; + totalread1 += read1; + } + + if (!done2) { + read2 = lkl_sys_read(f2, &(buf2[totalread2]), + READ_SIZE_2); + if (read2 <= 0) + done2 = 1; + totalread2 += read2; + } + } + + lkl_sys_close(f1); + lkl_sys_close(f2); + + if (totalread1 == 0) { + lkl_test_logf("file is empty\n"); + } else if (totalread1 != totalread2) { + lkl_test_logf("sizes don't match: %lu != %lu\n", + totalread1, totalread2); + } else { + if (memcmp(buf1, buf2, totalread1) == 0) + ret = TEST_SUCCESS; + else + lkl_test_logf("read contents don't match"); + } + + return ret; +} + +struct lkl_test tests[] = { + LKL_TEST(start_kernel), + LKL_TEST(cpuinfo), +}; + +int main(int argc, const char **argv) +{ + lkl_host_ops.print = lkl_test_log; + + return lkl_test_run(tests, sizeof(tests)/sizeof(struct lkl_test), + "cpuinfo"); +} diff --git a/tools/lkl/tests/cpuinfo.sh b/tools/lkl/tests/cpuinfo.sh new file mode 100755 index 00000000000000..33b4c34f68ad0b --- /dev/null +++ b/tools/lkl/tests/cpuinfo.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +script_dir=$(cd $(dirname ${BASH_SOURCE:-$0}); pwd) +source $script_dir/test.sh + +lkl_test_plan 1 "cpuinfo" +lkl_test_run 1 +lkl_test_exec $script_dir/cpuinfo diff --git a/tools/lkl/tests/run.py b/tools/lkl/tests/run.py index f34d0eb3389700..6ef5d9c2bdbc08 100755 --- a/tools/lkl/tests/run.py +++ b/tools/lkl/tests/run.py @@ -49,6 +49,7 @@ def end(self, obj): tests = [ 'boot.sh', + 'cpuinfo.sh', 'disk.sh -t ext4', 'disk.sh -t btrfs', 'disk.sh -t vfat',