1 /* 2 * mmio_warning_test 3 * 4 * Copyright (C) 2019, Google LLC. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2. 7 * 8 * Test that we don't get a kernel warning when we call KVM_RUN after a 9 * triple fault occurs. To get the triple fault to occur we call KVM_RUN 10 * on a VCPU that hasn't been properly setup. 11 * 12 */ 13 14 #define _GNU_SOURCE 15 #include <fcntl.h> 16 #include <kvm_util.h> 17 #include <linux/kvm.h> 18 #include <processor.h> 19 #include <pthread.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/ioctl.h> 24 #include <sys/mman.h> 25 #include <sys/stat.h> 26 #include <sys/types.h> 27 #include <sys/wait.h> 28 #include <test_util.h> 29 #include <unistd.h> 30 31 #define NTHREAD 4 32 #define NPROCESS 5 33 34 struct thread_context { 35 int kvmcpu; 36 struct kvm_run *run; 37 }; 38 39 void *thr(void *arg) 40 { 41 struct thread_context *tc = (struct thread_context *)arg; 42 int res; 43 int kvmcpu = tc->kvmcpu; 44 struct kvm_run *run = tc->run; 45 46 res = ioctl(kvmcpu, KVM_RUN, 0); 47 printf("ret1=%d exit_reason=%d suberror=%d\n", 48 res, run->exit_reason, run->internal.suberror); 49 50 return 0; 51 } 52 53 void test(void) 54 { 55 int i, kvm, kvmvm, kvmcpu; 56 pthread_t th[NTHREAD]; 57 struct kvm_run *run; 58 struct thread_context tc; 59 60 kvm = open("/dev/kvm", O_RDWR); 61 TEST_ASSERT(kvm != -1, "failed to open /dev/kvm"); 62 kvmvm = ioctl(kvm, KVM_CREATE_VM, 0); 63 TEST_ASSERT(kvmvm != -1, "KVM_CREATE_VM failed"); 64 kvmcpu = ioctl(kvmvm, KVM_CREATE_VCPU, 0); 65 TEST_ASSERT(kvmcpu != -1, "KVM_CREATE_VCPU failed"); 66 run = (struct kvm_run *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, 67 kvmcpu, 0); 68 tc.kvmcpu = kvmcpu; 69 tc.run = run; 70 srand(getpid()); 71 for (i = 0; i < NTHREAD; i++) { 72 pthread_create(&th[i], NULL, thr, (void *)(uintptr_t)&tc); 73 usleep(rand() % 10000); 74 } 75 for (i = 0; i < NTHREAD; i++) 76 pthread_join(th[i], NULL); 77 } 78 79 int get_warnings_count(void) 80 { 81 int warnings; 82 FILE *f; 83 84 f = popen("dmesg | grep \"WARNING:\" | wc -l", "r"); 85 fscanf(f, "%d", &warnings); 86 fclose(f); 87 88 return warnings; 89 } 90 91 int main(void) 92 { 93 int warnings_before, warnings_after; 94 95 if (!is_intel_cpu()) { 96 printf("Must be run on an Intel CPU, skipping test\n"); 97 exit(KSFT_SKIP); 98 } 99 100 if (vm_is_unrestricted_guest(NULL)) { 101 printf("Unrestricted guest must be disabled, skipping test\n"); 102 exit(KSFT_SKIP); 103 } 104 105 warnings_before = get_warnings_count(); 106 107 for (int i = 0; i < NPROCESS; ++i) { 108 int status; 109 int pid = fork(); 110 111 if (pid < 0) 112 exit(1); 113 if (pid == 0) { 114 test(); 115 exit(0); 116 } 117 while (waitpid(pid, &status, __WALL) != pid) 118 ; 119 } 120 121 warnings_after = get_warnings_count(); 122 TEST_ASSERT(warnings_before == warnings_after, 123 "Warnings found in kernel. Run 'dmesg' to inspect them."); 124 125 return 0; 126 } 127