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
);
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 static int test_debug(void *opaque
, void *vcpu
)
303 printf("test_debug\n");
307 static int test_halt(void *opaque
, int vcpu
)
311 sigwait(&ipi_sigmask
, &n
);
312 kvm_inject_irq(kvm
, vcpus
[vcpu
].id
, apic_ipi_vector
);
316 static int test_io_window(void *opaque
)
321 static int test_try_push_interrupts(void *opaque
)
326 static void test_push_nmi(void *opaque
)
330 static void test_post_kvm_run(void *opaque
, void *vcpu
)
334 static int test_pre_kvm_run(void *opaque
, void *vcpu
)
339 static int test_mem_read(void *opaque
, uint64_t addr
, uint8_t *data
, int len
)
341 if (addr
< IORAM_BASE_PHYS
|| addr
+ len
> IORAM_BASE_PHYS
+ IORAM_LEN
)
343 memcpy(data
, ioram
+ addr
- IORAM_BASE_PHYS
, len
);
347 static int test_mem_write(void *opaque
, uint64_t addr
, uint8_t *data
, int len
)
349 if (addr
< IORAM_BASE_PHYS
|| addr
+ len
> IORAM_BASE_PHYS
+ IORAM_LEN
)
351 memcpy(ioram
+ addr
- IORAM_BASE_PHYS
, data
, len
);
355 static int test_shutdown(void *opaque
, void *env
)
357 printf("shutdown\n");
358 kvm_show_regs(kvm
, 0);
363 static struct kvm_callbacks test_callbacks
= {
370 .mmio_read
= test_mem_read
,
371 .mmio_write
= test_mem_write
,
374 .io_window
= test_io_window
,
375 .try_push_interrupts
= test_try_push_interrupts
,
376 .push_nmi
= test_push_nmi
,
377 .post_kvm_run
= test_post_kvm_run
,
378 .pre_kvm_run
= test_pre_kvm_run
,
379 .shutdown
= test_shutdown
,
382 static void load_file(void *mem
, const char *fname
)
387 fd
= open(fname
, O_RDONLY
);
392 while ((r
= read(fd
, mem
, 4096)) != -1 && r
!= 0)
400 static void enter_32(kvm_context_t kvm
)
402 struct kvm_regs regs
= {
403 .rsp
= 0x80000, /* 512KB */
404 .rip
= 0x100000, /* 1MB */
407 struct kvm_sregs sregs
= {
408 .cs
= { 0, -1u, 8, 11, 1, 0, 1, 1, 0, 1, 0, 0 },
409 .ds
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
410 .es
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
411 .fs
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
412 .gs
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
413 .ss
= { 0, -1u, 16, 3, 1, 0, 1, 1, 0, 1, 0, 0 },
415 .tr
= { 0, 10000, 24, 11, 1, 0, 0, 0, 0, 0, 0, 0 },
416 .ldt
= { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
424 .interrupt_bitmap
= { 0 },
427 kvm_set_regs(kvm
, 0, ®s
);
428 kvm_set_sregs(kvm
, 0, &sregs
);
431 static void init_vcpu(int n
)
433 sigemptyset(&ipi_sigmask
);
434 sigaddset(&ipi_sigmask
, IPI_SIGNAL
);
435 sigprocmask(SIG_UNBLOCK
, &ipi_sigmask
, NULL
);
436 sigprocmask(SIG_BLOCK
, &ipi_sigmask
, &kernel_sigmask
);
438 vcpus
[n
].tid
= gettid();
440 kvm_set_signal_mask(kvm
, n
, &kernel_sigmask
);
444 static void *do_create_vcpu(void *_n
)
447 struct kvm_regs regs
;
449 kvm_create_vcpu(kvm
, n
);
451 sem_wait(&vcpus
[n
].sipi_sem
);
452 kvm_get_regs(kvm
, n
, ®s
);
453 regs
.rip
= apic_sipi_addr
;
454 kvm_set_regs(kvm
, n
, ®s
);
455 kvm_run(kvm
, n
, &vcpus
[n
]);
459 static void start_vcpu(int n
)
463 sem_init(&vcpus
[n
].sipi_sem
, 0, 0);
464 pthread_create(&thread
, NULL
, do_create_vcpu
, (void *)(long)n
);
467 static void usage(const char *progname
)
470 "Usage: %s [OPTIONS] [bootstrap] flatfile\n"
471 "KVM test harness.\n"
473 " -s, --smp=NUM create a VM with NUM virtual CPUs\n"
474 " -p, --protected-mode start VM in protected mode\n"
475 " -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n"
476 " can be used to change the unit (default: `M')\n"
477 " -h, --help display this help screen and exit\n"
479 "Report bugs to <kvm-devel@lists.sourceforge.net>.\n"
483 static void sig_ignore(int sig
)
485 write(1, "boo\n", 4);
488 int main(int argc
, char **argv
)
492 const char *sopts
= "s:phm:";
493 struct option lopts
[] = {
494 { "smp", 1, 0, 's' },
495 { "protected-mode", 0, 0, 'p' },
496 { "memory", 1, 0, 'm' },
497 { "help", 0, 0, 'h' },
501 bool enter_protected_mode
= false;
505 while ((ch
= getopt_long(argc
, argv
, sopts
, lopts
, &opt_ind
)) != -1) {
508 ncpus
= atoi(optarg
);
511 enter_protected_mode
= true;
514 memory_size
= strtoull(optarg
, &endptr
, 0);
528 "Unrecongized memory suffix: %c\n",
532 if (memory_size
== 0) {
534 "Invalid memory size: 0\n");
544 "Try `%s --help' for more information.\n",
550 nb_args
= argc
- optind
;
551 if (nb_args
< 1 || nb_args
> 2) {
553 "Incorrect number of arguments.\n"
554 "Try `%s --help' for more information.\n",
559 signal(IPI_SIGNAL
, sig_ignore
);
561 vcpus
= calloc(ncpus
, sizeof *vcpus
);
563 fprintf(stderr
, "calloc failed\n");
567 kvm
= kvm_init(&test_callbacks
, 0);
569 fprintf(stderr
, "kvm_init failed\n");
572 if (kvm_create(kvm
, memory_size
, &vm_mem
) < 0) {
574 fprintf(stderr
, "kvm_create failed\n");
578 vm_mem
= kvm_create_phys_mem(kvm
, 0, memory_size
, 0, 1);
580 if (enter_protected_mode
)
583 load_file(vm_mem
+ 0xf0000, argv
[optind
]);
586 load_file(vm_mem
+ 0x100000, argv
[optind
+ 1]);
591 io_table_register(&pio_table
, IRQCHIP_IO_BASE
, 0x20, irqchip_io
, NULL
);
593 sem_init(&init_sem
, 0, 0);
594 for (i
= 0; i
< ncpus
; ++i
)
596 for (i
= 0; i
< ncpus
; ++i
)
599 kvm_run(kvm
, 0, &vcpus
[0]);