Fix hw/acpi.c build w/ DEBUG enabled
[qemu-kvm/fedora.git] / kvm / user / main-ppc.c
blobbc27050e7dc4aba45999961cda95e1808958abe1
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
8 * Copyright IBM Corp. 2008
10 * Authors:
12 * Avi Kivity <avi@qumranet.com>
13 * Yaniv Kamay <yaniv@qumranet.com>
14 * Hollis Blanchard <hollisb@us.ibm.com>
16 * This work is licensed under the GNU LGPL license, version 2.
19 #define _GNU_SOURCE
21 #include <libkvm.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>
38 #include <inttypes.h>
40 #include "iotable.h"
42 static int gettid(void)
44 return syscall(__NR_gettid);
47 kvm_context_t kvm;
49 #define IPI_SIGNAL (SIGRTMIN + 4)
51 struct io_table mmio_table;
53 static int ncpus = 1;
54 static sem_t init_sem;
55 static __thread int vcpu;
56 static sigset_t kernel_sigmask;
57 static sigset_t ipi_sigmask;
58 static uint64_t memory_size = 128 * 1024 * 1024;
60 struct vcpu_info {
61 pid_t tid;
64 struct vcpu_info *vcpus;
66 static int test_debug(void *opaque, int vcpu)
68 printf("test_debug\n");
69 return 0;
72 static int test_halt(void *opaque, int vcpu)
74 int n;
76 sigwait(&ipi_sigmask, &n);
77 return 0;
80 static int test_io_window(void *opaque)
82 return 0;
85 static int test_try_push_interrupts(void *opaque)
87 return 0;
90 static void test_post_kvm_run(void *opaque, int vcpu)
94 static int test_pre_kvm_run(void *opaque, int vcpu)
96 return 0;
99 static int mmio_handler(void *opaque, int len, int is_write, uint64_t offset,
100 uint64_t *data)
102 int r = 0;
104 switch (offset) {
105 case 0: /* putc */
106 putc(*(char *)data, stdout);
107 fflush(stdout);
108 break;
109 case 1: /* exit */
110 r = *(char *)data;
111 break;
112 default:
113 printf("%s: offset %"PRIx64" len %d data %"PRIx64"\n",
114 __func__, offset, len, *(uint64_t *)data);
115 r = -EINVAL;
118 return r;
121 static int test_mem_read(void *opaque, uint64_t addr, uint8_t *data, int len)
123 struct io_table_entry *iodev;
125 #if 0
126 printf("%s: addr %"PRIx64" len %d\n", __func__, addr, len);
127 #endif
129 iodev = io_table_lookup(&mmio_table, addr);
130 if (!iodev) {
131 printf("couldn't find device\n");
132 return -ENODEV;
135 return iodev->handler(iodev->opaque, len, 0, addr - iodev->start,
136 (uint64_t *)data);
139 static int test_mem_write(void *opaque, uint64_t addr, uint8_t *data, int len)
141 struct io_table_entry *iodev;
143 #if 0
144 printf("%s: addr %"PRIx64" len %d data %"PRIx64"\n",
145 __func__, addr, len, *(uint64_t *)data);
146 #endif
148 iodev = io_table_lookup(&mmio_table, addr);
149 if (!iodev) {
150 printf("couldn't find device\n");
151 return -ENODEV;
154 return iodev->handler(iodev->opaque, len, 1, addr - iodev->start,
155 (uint64_t *)data);
158 static int test_dcr_read(uint32_t dcrn, uint32_t *data)
160 printf("%s: dcrn %04X\n", __func__, dcrn);
161 *data = 0;
162 return 0;
165 static int test_dcr_write(uint32_t dcrn, uint32_t data)
167 printf("%s: dcrn %04X data %04X\n", __func__, dcrn, data);
168 return 0;
171 static struct kvm_callbacks test_callbacks = {
172 .mmio_read = test_mem_read,
173 .mmio_write = test_mem_write,
174 .debug = test_debug,
175 .halt = test_halt,
176 .io_window = test_io_window,
177 .try_push_interrupts = test_try_push_interrupts,
178 .post_kvm_run = test_post_kvm_run,
179 .pre_kvm_run = test_pre_kvm_run,
180 .powerpc_dcr_read = test_dcr_read,
181 .powerpc_dcr_write = test_dcr_write,
184 static unsigned long load_file(void *mem, const char *fname, int inval_icache)
186 int r;
187 int fd;
188 unsigned long bytes = 0;
190 fd = open(fname, O_RDONLY);
191 if (fd == -1) {
192 perror("open");
193 exit(1);
196 while ((r = read(fd, mem, 4096)) != -1 && r != 0) {
197 mem += r;
198 bytes += r;
201 if (r == -1) {
202 perror("read");
203 exit(1);
206 return bytes;
209 #define ICACHE_LINE_SIZE 32
211 void sync_caches(void *mem, unsigned long len)
213 unsigned long i;
215 for (i = 0; i < len; i += ICACHE_LINE_SIZE)
216 asm volatile ("dcbst %0, %1" : : "g"(mem), "r"(i));
217 asm volatile ("sync");
218 for (i = 0; i < len; i += ICACHE_LINE_SIZE)
219 asm volatile ("icbi %0, %1" : : "g"(mem), "r"(i));
220 asm volatile ("sync; isync");
223 static void init_vcpu(int n, unsigned long entry)
225 /* XXX must set initial TLB state and stack
226 struct kvm_regs regs = {
227 .pc = entry,
230 kvm_set_regs(kvm, 0, &regs);
233 sigemptyset(&ipi_sigmask);
234 sigaddset(&ipi_sigmask, IPI_SIGNAL);
235 sigprocmask(SIG_UNBLOCK, &ipi_sigmask, NULL);
236 sigprocmask(SIG_BLOCK, &ipi_sigmask, &kernel_sigmask);
237 vcpus[n].tid = gettid();
238 vcpu = n;
239 kvm_set_signal_mask(kvm, n, &kernel_sigmask);
240 sem_post(&init_sem);
243 static void *do_create_vcpu(void *_n)
245 int n = (long)_n;
247 kvm_create_vcpu(kvm, n);
248 init_vcpu(n, 0x0);
249 kvm_run(kvm, n);
250 return NULL;
253 static void start_vcpu(int n)
255 pthread_t thread;
257 pthread_create(&thread, NULL, do_create_vcpu, (void *)(long)n);
260 static void usage(const char *progname)
262 fprintf(stderr,
263 "Usage: %s [OPTIONS] [bootstrap] flatfile\n"
264 "KVM test harness.\n"
265 "\n"
266 " -s, --smp=NUM create a VM with NUM virtual CPUs\n"
267 " -m, --memory=NUM[GMKB] allocate NUM memory for virtual machine. A suffix\n"
268 " can be used to change the unit (default: `M')\n"
269 " -h, --help display this help screen and exit\n"
270 "\n"
271 "Report bugs to <kvm-devel@lists.sourceforge.net>.\n"
272 , progname);
275 static void sig_ignore(int sig)
277 write(1, "boo\n", 4);
280 int main(int argc, char **argv)
282 void *vm_mem;
283 unsigned long len;
284 int i;
285 const char *sopts = "s:phm:";
286 struct option lopts[] = {
287 { "smp", 1, 0, 's' },
288 { "memory", 1, 0, 'm' },
289 { "help", 0, 0, 'h' },
290 { 0 },
292 int opt_ind, ch;
293 int nb_args;
294 char *endptr;
296 while ((ch = getopt_long(argc, argv, sopts, lopts, &opt_ind)) != -1) {
297 switch (ch) {
298 case 's':
299 ncpus = atoi(optarg);
300 break;
301 case 'm':
302 memory_size = strtoull(optarg, &endptr, 0);
303 switch (*endptr) {
304 case 'G': case 'g':
305 memory_size <<= 30;
306 break;
307 case '\0':
308 case 'M': case 'm':
309 memory_size <<= 20;
310 break;
311 case 'K': case 'k':
312 memory_size <<= 10;
313 break;
314 default:
315 fprintf(stderr,
316 "Unrecongized memory suffix: %c\n",
317 *endptr);
318 exit(1);
320 if (memory_size == 0) {
321 fprintf(stderr,
322 "Invalid memory size: 0\n");
323 exit(1);
325 break;
326 case 'h':
327 usage(argv[0]);
328 exit(0);
329 case '?':
330 default:
331 fprintf(stderr,
332 "Try `%s --help' for more information.\n",
333 argv[0]);
334 exit(1);
338 nb_args = argc - optind;
339 if (nb_args < 1 || nb_args > 2) {
340 fprintf(stderr,
341 "Incorrect number of arguments.\n"
342 "Try `%s --help' for more information.\n",
343 argv[0]);
344 exit(1);
347 signal(IPI_SIGNAL, sig_ignore);
349 vcpus = calloc(ncpus, sizeof *vcpus);
350 if (!vcpus) {
351 fprintf(stderr, "calloc failed\n");
352 return 1;
355 kvm = kvm_init(&test_callbacks, 0);
356 if (!kvm) {
357 fprintf(stderr, "kvm_init failed\n");
358 return 1;
360 if (kvm_create(kvm, memory_size, &vm_mem) < 0) {
361 kvm_finalize(kvm);
362 fprintf(stderr, "kvm_create failed\n");
363 return 1;
366 vm_mem = kvm_create_phys_mem(kvm, 0, memory_size, 0, 1);
368 len = load_file(vm_mem, argv[optind], 1);
369 sync_caches(vm_mem, len);
371 sem_init(&init_sem, 0, 0);
372 init_vcpu(0, 0x0);
373 for (i = 1; i < ncpus; ++i)
374 start_vcpu(i);
375 for (i = 0; i < ncpus; ++i)
376 sem_wait(&init_sem);
378 io_table_register(&mmio_table, 0xf0000000, 64, mmio_handler, NULL);
380 return kvm_run(kvm, 0);