ia64/xen-unstable

view extras/mini-os/kernel.c @ 19557:226ef307cd2e

AMD IOMMU: Fix ioapic interrupt remapping

A few ioapic redirection entries are initialized by hypervisor before
enabling iommu hardware. This patch copies those entries from ioapic
redirection table into interrupt remapping table after interrupt
remapping table has been allocated.

Signed-off-by: Wei Wang <wei.wang2@amd.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Apr 17 13:16:39 2009 +0100 (2009-04-17)
parents c9e9602cc080
children 11d8ca329b54
line source
1 /******************************************************************************
2 * kernel.c
3 *
4 * Assorted crap goes here, including the initial C entry point, jumped at
5 * from head.S.
6 *
7 * Copyright (c) 2002-2003, K A Fraser & R Neugebauer
8 * Copyright (c) 2005, Grzegorz Milos, Intel Research Cambridge
9 * Copyright (c) 2006, Robert Kaiser, FH Wiesbaden
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to
13 * deal in the Software without restriction, including without limitation the
14 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15 * sell copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 */
30 #include <os.h>
31 #include <hypervisor.h>
32 #include <mm.h>
33 #include <events.h>
34 #include <time.h>
35 #include <types.h>
36 #include <lib.h>
37 #include <sched.h>
38 #include <xenbus.h>
39 #include <gnttab.h>
40 #include <netfront.h>
41 #include <blkfront.h>
42 #include <fbfront.h>
43 #include <pcifront.h>
44 #include <fs.h>
45 #include <xmalloc.h>
46 #include <fcntl.h>
47 #include <xen/features.h>
48 #include <xen/version.h>
50 static struct netfront_dev *net_dev;
52 u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
54 void setup_xen_features(void)
55 {
56 xen_feature_info_t fi;
57 int i, j;
59 for (i = 0; i < XENFEAT_NR_SUBMAPS; i++)
60 {
61 fi.submap_idx = i;
62 if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
63 break;
65 for (j=0; j<32; j++)
66 xen_features[i*32+j] = !!(fi.submap & 1<<j);
67 }
68 }
70 void test_xenbus(void);
72 static void xenbus_tester(void *p)
73 {
74 printk("Xenbus tests disabled, because of a Xend bug.\n");
75 /* test_xenbus(); */
76 }
78 static void periodic_thread(void *p)
79 {
80 struct timeval tv;
81 printk("Periodic thread started.\n");
82 for(;;)
83 {
84 gettimeofday(&tv, NULL);
85 printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
86 msleep(1000);
87 }
88 }
90 static void netfront_thread(void *p)
91 {
92 net_dev = init_netfront(NULL, NULL, NULL, NULL);
93 }
95 static struct blkfront_dev *blk_dev;
96 static struct blkfront_info blk_info;
97 static uint64_t blk_size_read;
98 static uint64_t blk_size_write;
100 struct blk_req {
101 struct blkfront_aiocb aiocb;
102 int rand_value;
103 struct blk_req *next;
104 };
106 #ifdef BLKTEST_WRITE
107 static struct blk_req *blk_to_read;
108 #endif
110 static struct blk_req *blk_alloc_req(uint64_t sector)
111 {
112 struct blk_req *req = xmalloc(struct blk_req);
113 req->aiocb.aio_dev = blk_dev;
114 req->aiocb.aio_buf = _xmalloc(blk_info.sector_size, blk_info.sector_size);
115 req->aiocb.aio_nbytes = blk_info.sector_size;
116 req->aiocb.aio_offset = sector * blk_info.sector_size;
117 req->aiocb.data = req;
118 req->next = NULL;
119 return req;
120 }
122 static void blk_read_completed(struct blkfront_aiocb *aiocb, int ret)
123 {
124 struct blk_req *req = aiocb->data;
125 if (ret)
126 printk("got error code %d when reading at offset %ld\n", ret, aiocb->aio_offset);
127 else
128 blk_size_read += blk_info.sector_size;
129 free(aiocb->aio_buf);
130 free(req);
131 }
133 static void blk_read_sector(uint64_t sector)
134 {
135 struct blk_req *req;
137 req = blk_alloc_req(sector);
138 req->aiocb.aio_cb = blk_read_completed;
140 blkfront_aio_read(&req->aiocb);
141 }
143 #ifdef BLKTEST_WRITE
144 static void blk_write_read_completed(struct blkfront_aiocb *aiocb, int ret)
145 {
146 struct blk_req *req = aiocb->data;
147 int rand_value;
148 int i;
149 int *buf;
151 if (ret) {
152 printk("got error code %d when reading back at offset %ld\n", ret, aiocb->aio_offset);
153 free(aiocb->aio_buf);
154 free(req);
155 return;
156 }
157 blk_size_read += blk_info.sector_size;
158 buf = (int*) aiocb->aio_buf;
159 rand_value = req->rand_value;
160 for (i = 0; i < blk_info.sector_size / sizeof(int); i++) {
161 if (buf[i] != rand_value) {
162 printk("bogus data at offset %ld\n", aiocb->aio_offset + i);
163 break;
164 }
165 rand_value *= RAND_MIX;
166 }
167 free(aiocb->aio_buf);
168 free(req);
169 }
171 static void blk_write_completed(struct blkfront_aiocb *aiocb, int ret)
172 {
173 struct blk_req *req = aiocb->data;
174 if (ret) {
175 printk("got error code %d when writing at offset %ld\n", ret, aiocb->aio_offset);
176 free(aiocb->aio_buf);
177 free(req);
178 return;
179 }
180 blk_size_write += blk_info.sector_size;
181 /* Push write check */
182 req->next = blk_to_read;
183 blk_to_read = req;
184 }
186 static void blk_write_sector(uint64_t sector)
187 {
188 struct blk_req *req;
189 int rand_value;
190 int i;
191 int *buf;
193 req = blk_alloc_req(sector);
194 req->aiocb.aio_cb = blk_write_completed;
195 req->rand_value = rand_value = rand();
197 buf = (int*) req->aiocb.aio_buf;
198 for (i = 0; i < blk_info.sector_size / sizeof(int); i++) {
199 buf[i] = rand_value;
200 rand_value *= RAND_MIX;
201 }
203 blkfront_aio_write(&req->aiocb);
204 }
205 #endif
207 static void blkfront_thread(void *p)
208 {
209 time_t lasttime = 0;
211 blk_dev = init_blkfront(NULL, &blk_info);
212 if (!blk_dev)
213 return;
215 if (blk_info.info & VDISK_CDROM)
216 printk("Block device is a CDROM\n");
217 if (blk_info.info & VDISK_REMOVABLE)
218 printk("Block device is removable\n");
219 if (blk_info.info & VDISK_READONLY)
220 printk("Block device is read-only\n");
222 #ifdef BLKTEST_WRITE
223 if (blk_info.mode == O_RDWR) {
224 blk_write_sector(0);
225 blk_write_sector(blk_info.sectors-1);
226 } else
227 #endif
228 {
229 blk_read_sector(0);
230 blk_read_sector(blk_info.sectors-1);
231 }
233 while (1) {
234 uint64_t sector = rand() % blk_info.sectors;
235 struct timeval tv;
236 #ifdef BLKTEST_WRITE
237 if (blk_info.mode == O_RDWR)
238 blk_write_sector(sector);
239 else
240 #endif
241 blk_read_sector(sector);
242 blkfront_aio_poll(blk_dev);
243 gettimeofday(&tv, NULL);
244 if (tv.tv_sec > lasttime + 10) {
245 printk("%llu read, %llu write\n", blk_size_read, blk_size_write);
246 lasttime = tv.tv_sec;
247 }
249 #ifdef BLKTEST_WRITE
250 while (blk_to_read) {
251 struct blk_req *req = blk_to_read;
252 blk_to_read = blk_to_read->next;
253 req->aiocb.aio_cb = blk_write_read_completed;
254 blkfront_aio_read(&req->aiocb);
255 }
256 #endif
257 }
258 }
260 #define WIDTH 800
261 #define HEIGHT 600
262 #define DEPTH 32
264 static uint32_t *fb;
265 static int refresh_period = 50;
266 static struct fbfront_dev *fb_dev;
267 static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
269 static void fbfront_drawvert(int x, int y1, int y2, uint32_t color)
270 {
271 int y;
272 if (x < 0)
273 return;
274 if (x >= WIDTH)
275 return;
276 if (y1 < 0)
277 y1 = 0;
278 if (y2 >= HEIGHT)
279 y2 = HEIGHT-1;
280 for (y = y1; y <= y2; y++)
281 fb[x + y*WIDTH] ^= color;
282 }
284 static void fbfront_drawhoriz(int x1, int x2, int y, uint32_t color)
285 {
286 int x;
287 if (y < 0)
288 return;
289 if (y >= HEIGHT)
290 return;
291 if (x1 < 0)
292 x1 = 0;
293 if (x2 >= WIDTH)
294 x2 = WIDTH-1;
295 for (x = x1; x <= x2; x++)
296 fb[x + y*WIDTH] ^= color;
297 }
299 static void fbfront_thread(void *p)
300 {
301 size_t line_length = WIDTH * (DEPTH / 8);
302 size_t memsize = HEIGHT * line_length;
303 unsigned long *mfns;
304 int i, n = (memsize + PAGE_SIZE-1) / PAGE_SIZE;
306 memsize = n * PAGE_SIZE;
307 fb = _xmalloc(memsize, PAGE_SIZE);
308 memset(fb, 0, memsize);
309 mfns = xmalloc_array(unsigned long, n);
310 for (i = 0; i < n; i++)
311 mfns[i] = virtual_to_mfn((char *) fb + i * PAGE_SIZE);
312 fb_dev = init_fbfront(NULL, mfns, WIDTH, HEIGHT, DEPTH, line_length, n);
313 xfree(mfns);
314 if (!fb_dev) {
315 xfree(fb);
316 return;
317 }
318 up(&fbfront_sem);
319 }
321 static void clip_cursor(int *x, int *y)
322 {
323 if (*x < 0)
324 *x = 0;
325 if (*x >= WIDTH)
326 *x = WIDTH - 1;
327 if (*y < 0)
328 *y = 0;
329 if (*y >= HEIGHT)
330 *y = HEIGHT - 1;
331 }
333 static void refresh_cursor(int new_x, int new_y)
334 {
335 static int old_x = -1, old_y = -1;
337 if (!refresh_period)
338 return;
340 if (old_x != -1 && old_y != -1) {
341 fbfront_drawvert(old_x, old_y + 1, old_y + 8, 0xffffffff);
342 fbfront_drawhoriz(old_x + 1, old_x + 8, old_y, 0xffffffff);
343 fbfront_update(fb_dev, old_x, old_y, 9, 9);
344 }
345 old_x = new_x;
346 old_y = new_y;
347 fbfront_drawvert(new_x, new_y + 1, new_y + 8, 0xffffffff);
348 fbfront_drawhoriz(new_x + 1, new_x + 8, new_y, 0xffffffff);
349 fbfront_update(fb_dev, new_x, new_y, 9, 9);
350 }
352 static struct kbdfront_dev *kbd_dev;
353 static void kbdfront_thread(void *p)
354 {
355 DEFINE_WAIT(w);
356 int x = WIDTH / 2, y = HEIGHT / 2, z = 0;
358 kbd_dev = init_kbdfront(NULL, 1);
359 if (!kbd_dev)
360 return;
362 down(&fbfront_sem);
363 refresh_cursor(x, y);
364 while (1) {
365 union xenkbd_in_event kbdevent;
366 union xenfb_in_event fbevent;
367 int sleep = 1;
369 add_waiter(w, kbdfront_queue);
370 add_waiter(w, fbfront_queue);
372 while (kbdfront_receive(kbd_dev, &kbdevent, 1) != 0) {
373 sleep = 0;
374 switch(kbdevent.type) {
375 case XENKBD_TYPE_MOTION:
376 printk("motion x:%d y:%d z:%d\n",
377 kbdevent.motion.rel_x,
378 kbdevent.motion.rel_y,
379 kbdevent.motion.rel_z);
380 x += kbdevent.motion.rel_x;
381 y += kbdevent.motion.rel_y;
382 z += kbdevent.motion.rel_z;
383 clip_cursor(&x, &y);
384 refresh_cursor(x, y);
385 break;
386 case XENKBD_TYPE_POS:
387 printk("pos x:%d y:%d dz:%d\n",
388 kbdevent.pos.abs_x,
389 kbdevent.pos.abs_y,
390 kbdevent.pos.rel_z);
391 x = kbdevent.pos.abs_x;
392 y = kbdevent.pos.abs_y;
393 z = kbdevent.pos.rel_z;
394 clip_cursor(&x, &y);
395 refresh_cursor(x, y);
396 break;
397 case XENKBD_TYPE_KEY:
398 printk("key %d %s\n",
399 kbdevent.key.keycode,
400 kbdevent.key.pressed ? "pressed" : "released");
401 if (kbdevent.key.keycode == BTN_LEFT) {
402 printk("mouse %s at (%d,%d,%d)\n",
403 kbdevent.key.pressed ? "clic" : "release", x, y, z);
404 if (kbdevent.key.pressed) {
405 uint32_t color = rand();
406 fbfront_drawvert(x - 16, y - 16, y + 15, color);
407 fbfront_drawhoriz(x - 16, x + 15, y + 16, color);
408 fbfront_drawvert(x + 16, y - 15, y + 16, color);
409 fbfront_drawhoriz(x - 15, x + 16, y - 16, color);
410 fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
411 }
412 } else if (kbdevent.key.keycode == KEY_Q) {
413 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
414 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
415 do_exit();
416 }
417 break;
418 }
419 }
420 while (fbfront_receive(fb_dev, &fbevent, 1) != 0) {
421 sleep = 0;
422 switch(fbevent.type) {
423 case XENFB_TYPE_REFRESH_PERIOD:
424 refresh_period = fbevent.refresh_period.period;
425 printk("refresh period %d\n", refresh_period);
426 refresh_cursor(x, y);
427 break;
428 }
429 }
430 if (sleep)
431 schedule();
432 }
433 }
435 static struct pcifront_dev *pci_dev;
437 static void print_pcidev(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun)
438 {
439 unsigned int vendor, device, rev, class;
441 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor);
442 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device);
443 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev);
444 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class);
446 printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev);
447 }
449 static void pcifront_thread(void *p)
450 {
451 pci_dev = init_pcifront(NULL);
452 if (!pci_dev)
453 return;
454 printk("PCI devices:\n");
455 pcifront_scan(pci_dev, print_pcidev);
456 }
458 static void fs_thread(void *p)
459 {
460 init_fs_frontend();
461 }
463 /* This should be overridden by the application we are linked against. */
464 __attribute__((weak)) int app_main(start_info_t *si)
465 {
466 printk("Dummy main: start_info=%p\n", si);
467 create_thread("xenbus_tester", xenbus_tester, si);
468 create_thread("periodic_thread", periodic_thread, si);
469 create_thread("netfront", netfront_thread, si);
470 create_thread("blkfront", blkfront_thread, si);
471 create_thread("fbfront", fbfront_thread, si);
472 create_thread("kbdfront", kbdfront_thread, si);
473 create_thread("pcifront", pcifront_thread, si);
474 create_thread("fs-frontend", fs_thread, si);
475 return 0;
476 }
478 /*
479 * INITIAL C ENTRY POINT.
480 */
481 void start_kernel(start_info_t *si)
482 {
483 static char hello[] = "Bootstrapping...\n";
485 (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
487 arch_init(si);
489 trap_init();
491 /* print out some useful information */
492 printk("Xen Minimal OS!\n");
493 printk(" start_info: %p(VA)\n", si);
494 printk(" nr_pages: 0x%lx\n", si->nr_pages);
495 printk(" shared_inf: 0x%08lx(MA)\n", si->shared_info);
496 printk(" pt_base: %p(VA)\n", (void *)si->pt_base);
497 printk("nr_pt_frames: 0x%lx\n", si->nr_pt_frames);
498 printk(" mfn_list: %p(VA)\n", (void *)si->mfn_list);
499 printk(" mod_start: 0x%lx(VA)\n", si->mod_start);
500 printk(" mod_len: %lu\n", si->mod_len);
501 printk(" flags: 0x%x\n", (unsigned int)si->flags);
502 printk(" cmd_line: %s\n",
503 si->cmd_line ? (const char *)si->cmd_line : "NULL");
505 /* Set up events. */
506 init_events();
508 /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
509 __sti();
511 arch_print_info();
513 setup_xen_features();
515 /* Init memory management. */
516 init_mm();
518 /* Init time and timers. */
519 init_time();
521 /* Init the console driver. */
522 init_console();
524 /* Init grant tables */
525 init_gnttab();
527 /* Init scheduler. */
528 init_sched();
530 /* Init XenBus */
531 init_xenbus();
533 /* Call (possibly overridden) app_main() */
534 app_main(&start_info);
536 /* Everything initialised, start idle thread */
537 run_idle_thread();
538 }
540 void stop_kernel(void)
541 {
542 if (net_dev)
543 shutdown_netfront(net_dev);
545 if (blk_dev)
546 shutdown_blkfront(blk_dev);
548 if (fb_dev)
549 shutdown_fbfront(fb_dev);
551 if (kbd_dev)
552 shutdown_kbdfront(kbd_dev);
554 if (pci_dev)
555 shutdown_pcifront(pci_dev);
557 /* TODO: fs import */
559 local_irq_disable();
561 /* Reset grant tables */
562 fini_gnttab();
564 /* Reset the console driver. */
565 fini_console();
566 /* TODO: record new ring mfn & event in start_info */
568 /* Reset XenBus */
569 fini_xenbus();
571 /* Reset timers */
572 fini_time();
574 /* Reset memory management. */
575 fini_mm();
577 /* Reset events. */
578 fini_events();
580 /* Reset traps */
581 trap_fini();
583 /* Reset arch details */
584 arch_fini();
585 }
587 /*
588 * do_exit: This is called whenever an IRET fails in entry.S.
589 * This will generally be because an application has got itself into
590 * a really bad state (probably a bad CS or SS). It must be killed.
591 * Of course, minimal OS doesn't have applications :-)
592 */
594 void do_exit(void)
595 {
596 printk("Do_exit called!\n");
597 stack_walk();
598 for( ;; )
599 {
600 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
601 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
602 }
603 }