kvm: testsuite: handle shutdown exits
[qemu-kvm/fedora.git] / kvm / user / main.c
blob8f38a49caea3d619096034c2f62bb2201a317266
1 /*
2 * Kernel-based Virtual Machine test driver
4 * This test driver provides a simple way of testing kvm, without a full
5 * device model.
7 * Copyright (C) 2006 Qumranet
9 * Authors:
11 * Avi Kivity <avi@qumranet.com>
12 * Yaniv Kamay <yaniv@qumranet.com>
14 * This work is licensed under the GNU LGPL license, version 2.
17 #define _GNU_SOURCE
19 #include <libkvm.h>
20 #include "test/lib/x86/fake-apic.h"
21 #include "test/x86/ioram.h"
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <semaphore.h>
29 #include <sys/types.h>
30 #include <errno.h>
31 #include <pthread.h>
32 #include <signal.h>
33 #include <pthread.h>
34 #include <sys/syscall.h>
35 #include <linux/unistd.h>
36 #include <getopt.h>
37 #include <stdbool.h>
39 #include "iotable.h"
41 static uint8_t ioram[IORAM_LEN];
43 static int gettid(void)
45 return syscall(__NR_gettid);
48 static int tkill(int pid, int sig)
50 return syscall(__NR_tkill, pid, sig);
53 kvm_context_t kvm;
55 #define MAX_VCPUS 4
57 #define IPI_SIGNAL (SIGRTMIN + 4)
59 static int ncpus = 1;
60 static sem_t init_sem;
61 static __thread int vcpu;
62 static int apic_ipi_vector = 0xff;
63 static sigset_t kernel_sigmask;
64 static sigset_t ipi_sigmask;
65 static uint64_t memory_size = 128 * 1024 * 1024;
67 static struct io_table pio_table;
69 struct vcpu_info {
70 int id;
71 pid_t tid;
72 sem_t sipi_sem;
75 struct vcpu_info *vcpus;
77 static uint32_t apic_sipi_addr;
79 static void apic_send_sipi(int vcpu)
81 sem_post(&vcpus[vcpu].sipi_sem);
84 static void apic_send_ipi(int vcpu)
86 struct vcpu_info *v;
88 if (vcpu < 0 || vcpu >= ncpus)
89 return;
90 v = &vcpus[vcpu];
91 tkill(v->tid, IPI_SIGNAL);
94 static int apic_io(void *opaque, int size, int is_write,
95 uint64_t addr, uint64_t *value)
97 if (!is_write)
98 *value = -1u;
100 switch (addr - APIC_BASE) {
101 case APIC_REG_NCPU:
102 if (!is_write)
103 *value = ncpus;
104 break;
105 case APIC_REG_ID:
106 if (!is_write)
107 *value = vcpu;
108 break;
109 case APIC_REG_SIPI_ADDR:
110 if (!is_write)
111 *value = apic_sipi_addr;
112 else
113 apic_sipi_addr = *value;
114 break;
115 case APIC_REG_SEND_SIPI:
116 if (is_write)
117 apic_send_sipi(*value);
118 break;
119 case APIC_REG_IPI_VECTOR:
120 if (!is_write)
121 *value = apic_ipi_vector;
122 else
123 apic_ipi_vector = *value;
124 break;
125 case APIC_REG_SEND_IPI:
126 if (is_write)
127 apic_send_ipi(*value);
128 break;
131 return 0;
134 static int apic_init(void)
136 return io_table_register(&pio_table, APIC_BASE,
137 APIC_SIZE, apic_io, NULL);
140 static int misc_io(void *opaque, int size, int is_write,
141 uint64_t addr, uint64_t *value)
143 static int newline = 1;
145 if (!is_write)
146 *value = -1;
148 switch (addr) {
149 case 0xff: // irq injector
150 if (is_write) {
151 printf("injecting interrupt 0x%x\n", (uint8_t)*value);
152 kvm_inject_irq(kvm, 0, *value);
154 break;
155 case 0xf1: // serial
156 if (is_write) {
157 if (newline)
158 fputs("GUEST: ", stdout);
159 putchar(*value);
160 newline = *value == '\n';
162 break;
163 case 0xd1:
164 if (!is_write)
165 *value = memory_size;
166 break;
167 case 0xf4: // exit
168 if (is_write)
169 exit(*value);
170 break;
173 return 0;
176 static int misc_init(void)
178 int err;
180 err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL);
181 if (err < 0)
182 return err;
184 err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL);
185 if (err < 0)
186 return err;
188 err = io_table_register(&pio_table, 0xf4, 1, misc_io, NULL);
189 if (err < 0)
190 return err;
192 return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL);
195 static int test_inb(void *opaque, uint16_t addr, uint8_t *value)
197 struct io_table_entry *entry;
199 entry = io_table_lookup(&pio_table, addr);
200 if (entry) {
201 uint64_t val;
202 entry->handler(entry->opaque, 1, 0, addr, &val);
203 *value = val;
204 } else {
205 *value = -1;
206 printf("inb 0x%x\n", addr);
209 return 0;
212 static int test_inw(void *opaque, uint16_t addr, uint16_t *value)
214 struct io_table_entry *entry;
216 entry = io_table_lookup(&pio_table, addr);
217 if (entry) {
218 uint64_t val;
219 entry->handler(entry->opaque, 2, 0, addr, &val);
220 *value = val;
221 } else {
222 *value = -1;
223 printf("inw 0x%x\n", addr);
226 return 0;
229 static int test_inl(void *opaque, uint16_t addr, uint32_t *value)
231 struct io_table_entry *entry;
233 entry = io_table_lookup(&pio_table, addr);
234 if (entry) {
235 uint64_t val;
236 entry->handler(entry->opaque, 4, 0, addr, &val);
237 *value = val;
238 } else {
239 *value = -1;
240 printf("inl 0x%x\n", addr);
243 return 0;
246 static int test_outb(void *opaque, uint16_t addr, uint8_t value)
248 struct io_table_entry *entry;
250 entry = io_table_lookup(&pio_table, addr);
251 if (entry) {
252 uint64_t val = value;
253 entry->handler(entry->opaque, 1, 1, addr, &val);
254 } else
255 printf("outb $0x%x, 0x%x\n", value, addr);
257 return 0;
260 static int test_outw(void *opaque, uint16_t addr, uint16_t value)
262 struct io_table_entry *entry;
264 entry = io_table_lookup(&pio_table, addr);
265 if (entry) {
266 uint64_t val = value;
267 entry->handler(entry->opaque, 2, 1, addr, &val);
268 } else
269 printf("outw $0x%x, 0x%x\n", value, addr);
271 return 0;
274 static int test_outl(void *opaque, uint16_t addr, uint32_t value)
276 struct io_table_entry *entry;
278 entry = io_table_lookup(&pio_table, addr);
279 if (entry) {
280 uint64_t val = value;
281 entry->handler(entry->opaque, 4, 1, addr, &val);
282 } else
283 printf("outl $0x%x, 0x%x\n", value, addr);
285 return 0;
288 static int test_debug(void *opaque, void *vcpu)
290 printf("test_debug\n");
291 return 0;
294 static int test_halt(void *opaque, void *_vcpu)
296 struct vcpu_info *vcpu = _vcpu;
297 int n;
299 sigwait(&ipi_sigmask, &n);
300 kvm_inject_irq(kvm, vcpu->id, apic_ipi_vector);
301 return 0;
304 static int test_io_window(void *opaque)
306 return 0;
309 static int test_try_push_interrupts(void *opaque)
311 return 0;
314 static int test_try_push_nmi(void *opaque)
316 return 0;
319 static void test_post_kvm_run(void *opaque, void *vcpu)
323 static int test_pre_kvm_run(void *opaque, void *vcpu)
325 return 0;
328 static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
330 if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
331 return 1;
332 memcpy(data, ioram + addr - IORAM_BASE_PHYS, len);
333 return 0;
336 static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
338 if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
339 return 1;
340 memcpy(ioram + addr - IORAM_BASE_PHYS, data, len);
341 return 0;
344 static int test_shutdown(void *opaque, void *env)
346 printf("shutdown\n");
347 kvm_show_regs(kvm, 0);
348 exit(1);
349 return 1;
352 static struct kvm_callbacks test_callbacks = {
353 .inb = test_inb,
354 .inw = test_inw,
355 .inl = test_inl,
356 .outb = test_outb,
357 .outw = test_outw,
358 .outl = test_outl,
359 .mmio_read = test_mem_read,
360 .mmio_write = test_mem_write,
361 .debug = test_debug,
362 .halt = test_halt,
363 .io_window = test_io_window,
364 .try_push_interrupts = test_try_push_interrupts,
365 .try_push_nmi = test_try_push_nmi,
366 .post_kvm_run = test_post_kvm_run,
367 .pre_kvm_run = test_pre_kvm_run,
368 .shutdown = test_shutdown,
371 static void load_file(void *mem, const char *fname)
373 int r;
374 int fd;
376 fd = open(fname, O_RDONLY);
377 if (fd == -1) {
378 perror("open");
379 exit(1);
381 while ((r = read(fd, mem, 4096)) != -1 && r != 0)
382 mem += r;
383 if (r == -1) {
384 perror("read");
385 exit(1);
389 static void enter_32(kvm_context_t kvm)
391 struct kvm_regs regs = {
392 .rsp = 0x80000, /* 512KB */
393 .rip = 0x100000, /* 1MB */
394 .rflags = 2,
396 struct kvm_sregs sregs = {
397 .cs = { 0, -1u, 8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
398 .ds = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
399 .es = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
400 .fs = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
401 .gs = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
402 .ss = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
404 .tr = { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
405 .ldt = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
406 .gdt = { 0, 0 },
407 .idt = { 0, 0 },
408 .cr0 = 0x37,
409 .cr3 = 0,
410 .cr4 = 0,
411 .efer = 0,
412 .apic_base = 0,
413 .interrupt_bitmap = { 0 },
416 kvm_set_regs(kvm, 0, &regs);
417 kvm_set_sregs(kvm, 0, &sregs);
420 static void init_vcpu(int n)
422 sigemptyset(&ipi_sigmask);
423 sigaddset(&ipi_sigmask, IPI_SIGNAL);
424 sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
425 sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
426 vcpus[n].id = n;
427 vcpus[n].tid = gettid();
428 vcpu = n;
429 kvm_set_signal_mask(kvm, n, &kernel_sigmask);
430 sem_post(&init_sem);
433 static void *do_create_vcpu(void *_n)
435 int n = (long)_n;
436 struct kvm_regs regs;
438 kvm_create_vcpu(kvm, n);
439 init_vcpu(n);
440 sem_wait(&vcpus[n].sipi_sem);
441 kvm_get_regs(kvm, n, &regs);
442 regs.rip = apic_sipi_addr;
443 kvm_set_regs(kvm, n, &regs);
444 kvm_run(kvm, n, &vcpus[n]);
445 return NULL;
448 static void start_vcpu(int n)
450 pthread_t thread;
452 sem_init(&vcpus[n].sipi_sem, 0, 0);
453 pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
456 static void usage(const char *progname)
458 fprintf(stderr,
459 "Usage: %s [OPTIONS] [bootstrap] flatfile\n"
460 "KVM test harness.\n"
461 "\n"
462 " -s, --smp=NUM create a VM with NUM virtual CPUs\n"
463 " -p, --protected-mode start VM in protected mode\n"
464 " -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n"
465 " can be used to change the unit (default: `M')\n"
466 " -h, --help display this help screen and exit\n"
467 "\n"
468 "Report bugs to <kvm-devel@lists.sourceforge.net>.\n"
469 , progname);
472 static void sig_ignore(int sig)
474 write(1, "boo\n", 4);
477 int main(int argc, char **argv)
479 void *vm_mem;
480 int i;
481 const char *sopts = "s:phm:";
482 struct option lopts[] = {
483 { "smp", 1, 0, 's' },
484 { "protected-mode", 0, 0, 'p' },
485 { "memory", 1, 0, 'm' },
486 { "help", 0, 0, 'h' },
487 { 0 },
489 int opt_ind, ch;
490 bool enter_protected_mode = false;
491 int nb_args;
492 char *endptr;
494 while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
495 switch (ch) {
496 case 's':
497 ncpus = atoi(optarg);
498 break;
499 case 'p':
500 enter_protected_mode = true;
501 break;
502 case 'm':
503 memory_size = strtoull(optarg, &endptr, 0);
504 switch (*endptr) {
505 case 'G': case 'g':
506 memory_size <<= 30;
507 break;
508 case '\0':
509 case 'M': case 'm':
510 memory_size <<= 20;
511 break;
512 case 'K': case 'k':
513 memory_size <<= 10;
514 break;
515 default:
516 fprintf(stderr,
517 "Unrecongized memory suffix: %c\n",
518 *endptr);
519 exit(1);
521 if (memory_size == 0) {
522 fprintf(stderr,
523 "Invalid memory size: 0\n");
524 exit(1);
526 break;
527 case 'h':
528 usage(argv[0]);
529 exit(0);
530 case '?':
531 default:
532 fprintf(stderr,
533 "Try `%s --help' for more information.\n",
534 argv[0]);
535 exit(1);
539 nb_args = argc - optind;
540 if (nb_args < 1 || nb_args > 2) {
541 fprintf(stderr,
542 "Incorrect number of arguments.\n"
543 "Try `%s --help' for more information.\n",
544 argv[0]);
545 exit(1);
548 signal(IPI_SIGNAL, sig_ignore);
550 vcpus = calloc(ncpus, sizeof *vcpus);
551 if (!vcpus) {
552 fprintf(stderr, "calloc failed\n");
553 return 1;
556 kvm = kvm_init(&test_callbacks, 0);
557 if (!kvm) {
558 fprintf(stderr, "kvm_init failed\n");
559 return 1;
561 if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
562 kvm_finalize(kvm);
563 fprintf(stderr, "kvm_create failed\n");
564 return 1;
567 vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 1);
569 if (enter_protected_mode)
570 enter_32(kvm);
571 else
572 load_file(vm_mem + 0xf0000, argv[optind]);
574 if (nb_args > 1)
575 load_file(vm_mem + 0x100000, argv[optind + 1]);
577 apic_init();
578 misc_init();
580 sem_init(&init_sem, 0, 0);
581 for (i = 0; i < ncpus; ++i)
582 start_vcpu(i);
583 for (i = 0; i < ncpus; ++i)
584 sem_wait(&init_sem);
586 kvm_run(kvm, 0, &vcpus[0]);
588 return 0;