Handle SEJ notifications
[qemu-kvm/fedora.git] / kvm / user / main.c
blob9085899eadf769eac3457faa6f3fa13b22285091
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/x86/lib/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 pid_t tid;
71 sem_t sipi_sem;
74 struct vcpu_info *vcpus;
76 static uint32_t apic_sipi_addr;
78 static void apic_send_sipi(int vcpu)
80 sem_post(&vcpus[vcpu].sipi_sem);
83 static void apic_send_ipi(int vcpu)
85 struct vcpu_info *v;
87 if (vcpu < 0 || vcpu >= ncpus)
88 return;
89 v = &vcpus[vcpu];
90 tkill(v->tid, IPI_SIGNAL);
93 static int apic_io(void *opaque, int size, int is_write,
94 uint64_t addr, uint64_t *value)
96 if (!is_write)
97 *value = -1u;
99 switch (addr - APIC_BASE) {
100 case APIC_REG_NCPU:
101 if (!is_write)
102 *value = ncpus;
103 break;
104 case APIC_REG_ID:
105 if (!is_write)
106 *value = vcpu;
107 break;
108 case APIC_REG_SIPI_ADDR:
109 if (!is_write)
110 *value = apic_sipi_addr;
111 else
112 apic_sipi_addr = *value;
113 break;
114 case APIC_REG_SEND_SIPI:
115 if (is_write)
116 apic_send_sipi(*value);
117 break;
118 case APIC_REG_IPI_VECTOR:
119 if (!is_write)
120 *value = apic_ipi_vector;
121 else
122 apic_ipi_vector = *value;
123 break;
124 case APIC_REG_SEND_IPI:
125 if (is_write)
126 apic_send_ipi(*value);
127 break;
130 return 0;
133 static int apic_init(void)
135 return io_table_register(&pio_table, APIC_BASE,
136 APIC_SIZE, apic_io, NULL);
139 static int misc_io(void *opaque, int size, int is_write,
140 uint64_t addr, uint64_t *value)
142 static int newline = 1;
144 if (!is_write)
145 *value = -1;
147 switch (addr) {
148 case 0xff: // irq injector
149 if (is_write) {
150 printf("injecting interrupt 0x%x\n", (uint8_t)*value);
151 kvm_inject_irq(kvm, 0, *value);
153 break;
154 case 0xf1: // serial
155 if (is_write) {
156 if (newline)
157 fputs("GUEST: ", stdout);
158 putchar(*value);
159 newline = *value == '\n';
161 break;
162 case 0xd1:
163 if (!is_write)
164 *value = memory_size;
165 break;
166 case 0xf4: // exit
167 if (is_write)
168 exit(*value);
169 break;
172 return 0;
175 static int misc_init(void)
177 int err;
179 err = io_table_register(&pio_table, 0xff, 1, misc_io, NULL);
180 if (err < 0)
181 return err;
183 err = io_table_register(&pio_table, 0xf1, 1, misc_io, NULL);
184 if (err < 0)
185 return err;
187 err = io_table_register(&pio_table, 0xf4, 1, misc_io, NULL);
188 if (err < 0)
189 return err;
191 return io_table_register(&pio_table, 0xd1, 1, misc_io, NULL);
194 static int test_inb(void *opaque, uint16_t addr, uint8_t *value)
196 struct io_table_entry *entry;
198 entry = io_table_lookup(&pio_table, addr);
199 if (entry) {
200 uint64_t val;
201 entry->handler(entry->opaque, 1, 0, addr, &val);
202 *value = val;
203 } else {
204 *value = -1;
205 printf("inb 0x%x\n", addr);
208 return 0;
211 static int test_inw(void *opaque, uint16_t addr, uint16_t *value)
213 struct io_table_entry *entry;
215 entry = io_table_lookup(&pio_table, addr);
216 if (entry) {
217 uint64_t val;
218 entry->handler(entry->opaque, 2, 0, addr, &val);
219 *value = val;
220 } else {
221 *value = -1;
222 printf("inw 0x%x\n", addr);
225 return 0;
228 static int test_inl(void *opaque, uint16_t addr, uint32_t *value)
230 struct io_table_entry *entry;
232 entry = io_table_lookup(&pio_table, addr);
233 if (entry) {
234 uint64_t val;
235 entry->handler(entry->opaque, 4, 0, addr, &val);
236 *value = val;
237 } else {
238 *value = -1;
239 printf("inl 0x%x\n", addr);
242 return 0;
245 static int test_outb(void *opaque, uint16_t addr, uint8_t value)
247 struct io_table_entry *entry;
249 entry = io_table_lookup(&pio_table, addr);
250 if (entry) {
251 uint64_t val = value;
252 entry->handler(entry->opaque, 1, 1, addr, &val);
253 } else
254 printf("outb $0x%x, 0x%x\n", value, addr);
256 return 0;
259 static int test_outw(void *opaque, uint16_t addr, uint16_t value)
261 struct io_table_entry *entry;
263 entry = io_table_lookup(&pio_table, addr);
264 if (entry) {
265 uint64_t val = value;
266 entry->handler(entry->opaque, 2, 1, addr, &val);
267 } else
268 printf("outw $0x%x, 0x%x\n", value, addr);
270 return 0;
273 static int test_outl(void *opaque, uint16_t addr, uint32_t value)
275 struct io_table_entry *entry;
277 entry = io_table_lookup(&pio_table, addr);
278 if (entry) {
279 uint64_t val = value;
280 entry->handler(entry->opaque, 4, 1, addr, &val);
281 } else
282 printf("outl $0x%x, 0x%x\n", value, addr);
284 return 0;
287 static int test_debug(void *opaque, int vcpu)
289 printf("test_debug\n");
290 return 0;
293 static int test_halt(void *opaque, int vcpu)
295 int n;
297 sigwait(&ipi_sigmask, &n);
298 kvm_inject_irq(kvm, vcpu, apic_ipi_vector);
299 return 0;
302 static int test_io_window(void *opaque)
304 return 0;
307 static int test_try_push_interrupts(void *opaque)
309 return 0;
312 static void test_post_kvm_run(void *opaque, int vcpu)
316 static int test_pre_kvm_run(void *opaque, int vcpu)
318 return 0;
321 static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
323 if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
324 return 1;
325 memcpy(data, ioram + addr - IORAM_BASE_PHYS, len);
326 return 0;
329 static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
331 if (addr < IORAM_BASE_PHYS || addr + len > IORAM_BASE_PHYS + IORAM_LEN)
332 return 1;
333 memcpy(ioram + addr - IORAM_BASE_PHYS, data, len);
334 return 0;
337 static struct kvm_callbacks test_callbacks = {
338 .inb = test_inb,
339 .inw = test_inw,
340 .inl = test_inl,
341 .outb = test_outb,
342 .outw = test_outw,
343 .outl = test_outl,
344 .mmio_read = test_mem_read,
345 .mmio_write = test_mem_write,
346 .debug = test_debug,
347 .halt = test_halt,
348 .io_window = test_io_window,
349 .try_push_interrupts = test_try_push_interrupts,
350 .post_kvm_run = test_post_kvm_run,
351 .pre_kvm_run = test_pre_kvm_run,
354 static void load_file(void *mem, const char *fname)
356 int r;
357 int fd;
359 fd = open(fname, O_RDONLY);
360 if (fd == -1) {
361 perror("open");
362 exit(1);
364 while ((r = read(fd, mem, 4096)) != -1 && r != 0)
365 mem += r;
366 if (r == -1) {
367 perror("read");
368 exit(1);
372 static void enter_32(kvm_context_t kvm)
374 struct kvm_regs regs = {
375 .rsp = 0x80000, /* 512KB */
376 .rip = 0x100000, /* 1MB */
377 .rflags = 2,
379 struct kvm_sregs sregs = {
380 .cs = { 0, -1u, 8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
381 .ds = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
382 .es = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
383 .fs = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
384 .gs = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
385 .ss = { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
387 .tr = { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
388 .ldt = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
389 .gdt = { 0, 0 },
390 .idt = { 0, 0 },
391 .cr0 = 0x37,
392 .cr3 = 0,
393 .cr4 = 0,
394 .efer = 0,
395 .apic_base = 0,
396 .interrupt_bitmap = { 0 },
399 kvm_set_regs(kvm, 0, &regs);
400 kvm_set_sregs(kvm, 0, &sregs);
403 static void init_vcpu(int n)
405 sigemptyset(&ipi_sigmask);
406 sigaddset(&ipi_sigmask, IPI_SIGNAL);
407 sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
408 sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
409 vcpus[n].tid = gettid();
410 vcpu = n;
411 kvm_set_signal_mask(kvm, n, &kernel_sigmask);
412 sem_post(&init_sem);
415 static void *do_create_vcpu(void *_n)
417 int n = (long)_n;
418 struct kvm_regs regs;
420 kvm_create_vcpu(kvm, n);
421 init_vcpu(n);
422 sem_wait(&vcpus[n].sipi_sem);
423 kvm_get_regs(kvm, n, &regs);
424 regs.rip = apic_sipi_addr;
425 kvm_set_regs(kvm, n, &regs);
426 kvm_run(kvm, n);
427 return NULL;
430 static void start_vcpu(int n)
432 pthread_t thread;
434 sem_init(&vcpus[n].sipi_sem, 0, 0);
435 pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
438 static void usage(const char *progname)
440 fprintf(stderr,
441 "Usage: %s [OPTIONS] [bootstrap] flatfile\n"
442 "KVM test harness.\n"
443 "\n"
444 " -s, --smp=NUM create a VM with NUM virtual CPUs\n"
445 " -p, --protected-mode start VM in protected mode\n"
446 " -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n"
447 " can be used to change the unit (default: `M')\n"
448 " -h, --help display this help screen and exit\n"
449 "\n"
450 "Report bugs to <kvm-devel@lists.sourceforge.net>.\n"
451 , progname);
454 static void sig_ignore(int sig)
456 write(1, "boo\n", 4);
459 int main(int argc, char **argv)
461 void *vm_mem;
462 int i;
463 const char *sopts = "s:phm:";
464 struct option lopts[] = {
465 { "smp", 1, 0, 's' },
466 { "protected-mode", 0, 0, 'p' },
467 { "memory", 1, 0, 'm' },
468 { "help", 0, 0, 'h' },
469 { 0 },
471 int opt_ind, ch;
472 bool enter_protected_mode = false;
473 int nb_args;
474 char *endptr;
476 while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
477 switch (ch) {
478 case 's':
479 ncpus = atoi(optarg);
480 break;
481 case 'p':
482 enter_protected_mode = true;
483 break;
484 case 'm':
485 memory_size = strtoull(optarg, &endptr, 0);
486 switch (*endptr) {
487 case 'G': case 'g':
488 memory_size <<= 30;
489 break;
490 case '\0':
491 case 'M': case 'm':
492 memory_size <<= 20;
493 break;
494 case 'K': case 'k':
495 memory_size <<= 10;
496 break;
497 default:
498 fprintf(stderr,
499 "Unrecongized memory suffix: %c\n",
500 *endptr);
501 exit(1);
503 if (memory_size == 0) {
504 fprintf(stderr,
505 "Invalid memory size: 0\n");
506 exit(1);
508 break;
509 case 'h':
510 usage(argv[0]);
511 exit(0);
512 case '?':
513 default:
514 fprintf(stderr,
515 "Try `%s --help' for more information.\n",
516 argv[0]);
517 exit(1);
521 nb_args = argc - optind;
522 if (nb_args < 1 || nb_args > 2) {
523 fprintf(stderr,
524 "Incorrect number of arguments.\n"
525 "Try `%s --help' for more information.\n",
526 argv[0]);
527 exit(1);
530 signal(IPI_SIGNAL, sig_ignore);
532 vcpus = calloc(ncpus, sizeof *vcpus);
533 if (!vcpus) {
534 fprintf(stderr, "calloc failed\n");
535 return 1;
538 kvm = kvm_init(&test_callbacks, 0);
539 if (!kvm) {
540 fprintf(stderr, "kvm_init failed\n");
541 return 1;
543 if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
544 kvm_finalize(kvm);
545 fprintf(stderr, "kvm_create failed\n");
546 return 1;
549 vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 1);
551 if (enter_protected_mode)
552 enter_32(kvm);
553 else
554 load_file(vm_mem + 0xf0000, argv[optind]);
556 if (nb_args > 1)
557 load_file(vm_mem + 0x100000, argv[optind + 1]);
559 apic_init();
560 misc_init();
562 sem_init(&init_sem, 0, 0);
563 init_vcpu(0);
564 for (i = 1; i < ncpus; ++i)
565 start_vcpu(i);
566 for (i = 0; i < ncpus; ++i)
567 sem_wait(&init_sem);
569 kvm_run(kvm, 0);
571 return 0;