Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * mmio_warning_test
0003  *
0004  * Copyright (C) 2019, Google LLC.
0005  *
0006  * This work is licensed under the terms of the GNU GPL, version 2.
0007  *
0008  * Test that we don't get a kernel warning when we call KVM_RUN after a
0009  * triple fault occurs.  To get the triple fault to occur we call KVM_RUN
0010  * on a VCPU that hasn't been properly setup.
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 }