2 * Kernel-based Virtual Machine test driver
4 * This test driver provides a simple way of testing kvm, without a full
7 * Copyright (C) 2006 Qumranet
11 * Avi Kivity <avi@qumranet.com>
12 * Yaniv Kamay <yaniv@qumranet.com>
14 * This work is licensed under the GNU LGPL license, version 2.
20 #include "test/lib/x86/fake-apic.h"
21 #include "test/x86/ioram.h"
28 #include <semaphore.h>
29 #include <sys/types.h>
34 #include <sys/syscall.h>
35 #include <linux/unistd.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
);
57 #define IPI_SIGNAL (SIGRTMIN + 4)
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
;
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
)
88 if (vcpu
< 0 || vcpu
>= ncpus
)
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
)
100 switch (addr
- APIC_BASE
) {
109 case APIC_REG_SIPI_ADDR
:
111 *value
= apic_sipi_addr
;
113 apic_sipi_addr
= *value
;
115 case APIC_REG_SEND_SIPI
:
117 apic_send_sipi(*value
);
119 case APIC_REG_IPI_VECTOR
:
121 *value
= apic_ipi_vector
;
123 apic_ipi_vector
= *value
;
125 case APIC_REG_SEND_IPI
:
127 apic_send_ipi(*value
);
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;
149 case 0xff: // irq injector
151 printf("injecting interrupt 0x%x\n", (uint8_t)*value
);
152 kvm_inject_irq(kvm
, 0, *value
);
158 fputs("GUEST: ", stdout
);
160 newline
= *value
== '\n';
165 *value
= memory_size
;
176 static int misc_init(void)
180 err
= io_table_register(&pio_table
, 0xff, 1, misc_io
, NULL
);
184 err
= io_table_register(&pio_table
, 0xf1, 1, misc_io
, NULL
);
188 err
= io_table_register(&pio_table
, 0xf4, 1, misc_io
, NULL
);
192 return io_table_register(&pio_table
, 0xd1, 1, misc_io
, NULL
);
195 #define IRQCHIP_IO_BASE 0x2000
197 static int irqchip_io(void *opaque
, int size
, int is_write
,
198 uint64_t addr
, uint64_t *value
)
200 addr
-= IRQCHIP_IO_BASE
;
203 kvm_set_irq_level(kvm
, addr
, *value
, NULL
);
208 static int test_inb(void *opaque
, uint16_t addr
, uint8_t *value
)
210 struct io_table_entry
*entry
;
212 entry
= io_table_lookup(&pio_table
, addr
);
215 entry
->handler(entry
->opaque
, 1, 0, addr
, &val
);
219 printf("inb 0x%x\n", addr
);
225 static int test_inw(void *opaque
, uint16_t addr
, uint16_t *value
)
227 struct io_table_entry
*entry
;
229 entry
= io_table_lookup(&pio_table
, addr
);
232 entry
->handler(entry
->opaque
, 2, 0, addr
, &val
);
236 printf("inw 0x%x\n", addr
);
242 static int test_inl(void *opaque
, uint16_t addr
, uint32_t *value
)
244 struct io_table_entry
*entry
;
246 entry
= io_table_lookup(&pio_table
, addr
);
249 entry
->handler(entry
->opaque
, 4, 0, addr
, &val
);
253 printf("inl 0x%x\n", addr
);
259 static int test_outb(void *opaque
, uint16_t addr
, uint8_t value
)
261 struct io_table_entry
*entry
;
263 entry
= io_table_lookup(&pio_table
, addr
);
265 uint64_t val
= value
;
266 entry
->handler(entry
->opaque
, 1, 1, addr
, &val
);
268 printf("outb $0x%x, 0x%x\n", value
, addr
);
273 static int test_outw(void *opaque
, uint16_t addr
, uint16_t value
)
275 struct io_table_entry
*entry
;
277 entry
= io_table_lookup(&pio_table
, addr
);
279 uint64_t val
= value
;
280 entry
->handler(entry
->opaque
, 2, 1, addr
, &val
);
282 printf("outw $0x%x, 0x%x\n", value
, addr
);
287 static int test_outl(void *opaque
, uint16_t addr
, uint32_t value
)
289 struct io_table_entry
*entry
;
291 entry
= io_table_lookup(&pio_table
, addr
);
293 uint64_t val
= value
;
294 entry
->handler(entry
->opaque
, 4, 1, addr
, &val
);
296 printf("outl $0x%x, 0x%x\n", value
, addr
);
301 #ifdef KVM_CAP_SET_GUEST_DEBUG
302 static int test_debug(void *opaque
, void *vcpu
,
303 struct kvm_debug_exit_arch
*arch_info
)
305 printf("test_debug\n");
310 static int test_halt(void *opaque
, int vcpu
)
314 sigwait(&ipi_sigmask
, &n
);
315 kvm_inject_irq(kvm
, vcpus
[vcpu
].id
, apic_ipi_vector
);
319 static int test_io_window(void *opaque
)
324 static int test_try_push_interrupts(void *opaque
)
329 #ifdef KVM_CAP_USER_NMI
330 static void test_push_nmi(void *opaque
)
335 static void test_post_kvm_run(void *opaque
, void *vcpu
)
339 static int test_pre_kvm_run(void *opaque
, void *vcpu
)
344 static int test_mem_read(void *opaque
, uint64_t addr
, uint8_t *data
, int len
)
346 if (addr
< IORAM_BASE_PHYS
|| addr
+ len
> IORAM_BASE_PHYS
+ IORAM_LEN
)
348 memcpy(data
, ioram
+ addr
- IORAM_BASE_PHYS
, len
);
352 static int test_mem_write(void *opaque
, uint64_t addr
, uint8_t *data
, int len
)
354 if (addr
< IORAM_BASE_PHYS
|| addr
+ len
> IORAM_BASE_PHYS
+ IORAM_LEN
)
356 memcpy(ioram
+ addr
- IORAM_BASE_PHYS
, data
, len
);
360 static int test_shutdown(void *opaque
, void *env
)
362 printf("shutdown\n");
363 kvm_show_regs(kvm
, 0);
368 static struct kvm_callbacks test_callbacks
= {
375 .mmio_read
= test_mem_read
,
376 .mmio_write
= test_mem_write
,
377 #ifdef KVM_CAP_SET_GUEST_DEBUG
381 .io_window
= test_io_window
,
382 .try_push_interrupts
= test_try_push_interrupts
,
383 #ifdef KVM_CAP_USER_NMI
384 .push_nmi
= test_push_nmi
,
386 .post_kvm_run
= test_post_kvm_run
,
387 .pre_kvm_run
= test_pre_kvm_run
,
388 .shutdown
= test_shutdown
,
391 static void load_file(void *mem
, const char *fname
)
396 fd
= open(fname
, O_RDONLY
);
401 while ((r
= read(fd
, mem
, 4096)) != -1 && r
!= 0)
409 static void enter_32(kvm_context_t kvm
)
411 struct kvm_regs regs
= {
412 .rsp
= 0x80000, /* 512KB */
413 .rip
= 0x100000, /* 1MB */
416 struct kvm_sregs sregs
= {
417 .cs
= { 0, -1u, 8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
418 .ds
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
419 .es
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
420 .fs
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
421 .gs
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
422 .ss
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
424 .tr
= { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
425 .ldt
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
433 .interrupt_bitmap
= { 0 },
436 kvm_set_regs(kvm
, 0, ®s
);
437 kvm_set_sregs(kvm
, 0, &sregs
);
440 static void init_vcpu(int n
)
442 sigemptyset(&ipi_sigmask
);
443 sigaddset(&ipi_sigmask
, IPI_SIGNAL
);
444 sigprocmask(SIG_UNBLOCK
, &ipi_sigmask
, NULL
);
445 sigprocmask(SIG_BLOCK
, &ipi_sigmask
, &kernel_sigmask
);
447 vcpus
[n
].tid
= gettid();
449 kvm_set_signal_mask(kvm
, n
, &kernel_sigmask
);
453 static void *do_create_vcpu(void *_n
)
456 struct kvm_regs regs
;
458 kvm_create_vcpu(kvm
, n
);
460 sem_wait(&vcpus
[n
].sipi_sem
);
461 kvm_get_regs(kvm
, n
, ®s
);
462 regs
.rip
= apic_sipi_addr
;
463 kvm_set_regs(kvm
, n
, ®s
);
464 kvm_run(kvm
, n
, &vcpus
[n
]);
468 static void start_vcpu(int n
)
472 sem_init(&vcpus
[n
].sipi_sem
, 0, 0);
473 pthread_create(&thread
, NULL
, do_create_vcpu
, (void *)(long)n
);
476 static void usage(const char *progname
)
479 "Usage: %s [OPTIONS] [bootstrap] flatfile\n"
480 "KVM test harness.\n"
482 " -s, --smp=NUM create a VM with NUM virtual CPUs\n"
483 " -p, --protected-mode start VM in protected mode\n"
484 " -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n"
485 " can be used to change the unit (default: `M')\n"
486 " -h, --help display this help screen and exit\n"
488 "Report bugs to <kvm@vger.kernel.org>.\n"
492 static void sig_ignore(int sig
)
494 write(1, "boo\n", 4);
497 int main(int argc
, char **argv
)
501 const char *sopts
= "s:phm:";
502 struct option lopts
[] = {
503 { "smp", 1, 0, 's' },
504 { "protected-mode", 0, 0, 'p' },
505 { "memory", 1, 0, 'm' },
506 { "help", 0, 0, 'h' },
510 bool enter_protected_mode
= false;
514 while ((ch
= getopt_long(argc
, argv
, sopts
, lopts
, &opt_ind
)) != -1) {
517 ncpus
= atoi(optarg
);
520 enter_protected_mode
= true;
523 memory_size
= strtoull(optarg
, &endptr
, 0);
537 "Unrecongized memory suffix: %c\n",
541 if (memory_size
== 0) {
543 "Invalid memory size: 0\n");
553 "Try `%s --help' for more information.\n",
559 nb_args
= argc
- optind
;
560 if (nb_args
< 1 || nb_args
> 2) {
562 "Incorrect number of arguments.\n"
563 "Try `%s --help' for more information.\n",
568 signal(IPI_SIGNAL
, sig_ignore
);
570 vcpus
= calloc(ncpus
, sizeof *vcpus
);
572 fprintf(stderr
, "calloc failed\n");
576 kvm
= kvm_init(&test_callbacks
, 0);
578 fprintf(stderr
, "kvm_init failed\n");
581 if (kvm_create(kvm
, memory_size
, &vm_mem
) < 0) {
583 fprintf(stderr
, "kvm_create failed\n");
587 vm_mem
= kvm_create_phys_mem(kvm
, 0, memory_size
, 0, 1);
589 if (enter_protected_mode
)
592 load_file(vm_mem
+ 0xf0000, argv
[optind
]);
595 load_file(vm_mem
+ 0x100000, argv
[optind
+ 1]);
600 io_table_register(&pio_table
, IRQCHIP_IO_BASE
, 0x20, irqchip_io
, NULL
);
602 sem_init(&init_sem
, 0, 0);
603 for (i
= 0; i
< ncpus
; ++i
)
605 for (i
= 0; i
< ncpus
; ++i
)
608 kvm_run(kvm
, 0, &vcpus
[0]);