0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #define _GNU_SOURCE
0015 #include <fcntl.h>
0016 #include <kvm_util.h>
0017 #include <linux/kvm.h>
0018 #include <processor.h>
0019 #include <pthread.h>
0020 #include <stdio.h>
0021 #include <stdlib.h>
0022 #include <string.h>
0023 #include <sys/ioctl.h>
0024 #include <sys/mman.h>
0025 #include <sys/stat.h>
0026 #include <sys/types.h>
0027 #include <sys/wait.h>
0028 #include <test_util.h>
0029 #include <unistd.h>
0030
0031 #define NTHREAD 4
0032 #define NPROCESS 5
0033
0034 struct thread_context {
0035 int kvmcpu;
0036 struct kvm_run *run;
0037 };
0038
0039 void *thr(void *arg)
0040 {
0041 struct thread_context *tc = (struct thread_context *)arg;
0042 int res;
0043 int kvmcpu = tc->kvmcpu;
0044 struct kvm_run *run = tc->run;
0045
0046 res = ioctl(kvmcpu, KVM_RUN, 0);
0047 pr_info("ret1=%d exit_reason=%d suberror=%d\n",
0048 res, run->exit_reason, run->internal.suberror);
0049
0050 return 0;
0051 }
0052
0053 void test(void)
0054 {
0055 int i, kvm, kvmvm, kvmcpu;
0056 pthread_t th[NTHREAD];
0057 struct kvm_run *run;
0058 struct thread_context tc;
0059
0060 kvm = open("/dev/kvm", O_RDWR);
0061 TEST_ASSERT(kvm != -1, "failed to open /dev/kvm");
0062 kvmvm = __kvm_ioctl(kvm, KVM_CREATE_VM, NULL);
0063 TEST_ASSERT(kvmvm > 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, kvmvm));
0064 kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0);
0065 TEST_ASSERT(kvmcpu != -1, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, kvmcpu));
0066 run = (struct kvm_run *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED,
0067 kvmcpu, 0);
0068 tc.kvmcpu = kvmcpu;
0069 tc.run = run;
0070 srand(getpid());
0071 for (i = 0; i < NTHREAD; i++) {
0072 pthread_create(&th[i], NULL, thr, (void *)(uintptr_t)&tc);
0073 usleep(rand() % 10000);
0074 }
0075 for (i = 0; i < NTHREAD; i++)
0076 pthread_join(th[i], NULL);
0077 }
0078
0079 int get_warnings_count(void)
0080 {
0081 int warnings;
0082 FILE *f;
0083
0084 f = popen("dmesg | grep \"WARNING:\" | wc -l", "r");
0085 if (fscanf(f, "%d", &warnings) < 1)
0086 warnings = 0;
0087 pclose(f);
0088
0089 return warnings;
0090 }
0091
0092 int main(void)
0093 {
0094 int warnings_before, warnings_after;
0095
0096 TEST_REQUIRE(is_intel_cpu());
0097
0098 TEST_REQUIRE(!vm_is_unrestricted_guest(NULL));
0099
0100 warnings_before = get_warnings_count();
0101
0102 for (int i = 0; i < NPROCESS; ++i) {
0103 int status;
0104 int pid = fork();
0105
0106 if (pid < 0)
0107 exit(1);
0108 if (pid == 0) {
0109 test();
0110 exit(0);
0111 }
0112 while (waitpid(pid, &status, __WALL) != pid)
0113 ;
0114 }
0115
0116 warnings_after = get_warnings_count();
0117 TEST_ASSERT(warnings_before == warnings_after,
0118 "Warnings found in kernel. Run 'dmesg' to inspect them.");
0119
0120 return 0;
0121 }