ia64/xen-unstable

view extras/mini-os/kernel.c @ 18811:390ef36eb596

Remove Xen-private definitions from kexec public header.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Nov 19 13:13:39 2008 +0000 (2008-11-19)
parents f4135a620f59
children b33b745cd5ec
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 pcifront_thread(void *p)
438 {
439 void print(unsigned int domain, unsigned int bus, unsigned int slot, unsigned int fun)
440 {
441 unsigned int vendor, device, rev, class;
443 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x00, 2, &vendor);
444 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x02, 2, &device);
445 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x08, 1, &rev);
446 pcifront_conf_read(pci_dev, domain, bus, slot, fun, 0x0a, 2, &class);
448 printk("%04x:%02x:%02x.%02x %04x: %04x:%04x (rev %02x)\n", domain, bus, slot, fun, class, vendor, device, rev);
449 }
451 pci_dev = init_pcifront(NULL);
452 if (!pci_dev)
453 return;
454 printk("PCI devices:\n");
455 pcifront_scan(pci_dev, print);
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\n", si);
494 printk(" nr_pages: %lu", si->nr_pages);
495 printk(" shared_inf: %08lx\n", si->shared_info);
496 printk(" pt_base: %p", (void *)si->pt_base);
497 printk(" mod_start: 0x%lx\n", si->mod_start);
498 printk(" mod_len: %lu\n", si->mod_len);
499 printk(" flags: 0x%x\n", (unsigned int)si->flags);
500 printk(" cmd_line: %s\n",
501 si->cmd_line ? (const char *)si->cmd_line : "NULL");
503 /* Set up events. */
504 init_events();
506 /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
507 __sti();
509 arch_print_info();
511 setup_xen_features();
513 /* Init memory management. */
514 init_mm();
516 /* Init time and timers. */
517 init_time();
519 /* Init the console driver. */
520 init_console();
522 /* Init grant tables */
523 init_gnttab();
525 /* Init scheduler. */
526 init_sched();
528 /* Init XenBus */
529 init_xenbus();
531 /* Call (possibly overridden) app_main() */
532 app_main(&start_info);
534 /* Everything initialised, start idle thread */
535 run_idle_thread();
536 }
538 void stop_kernel(void)
539 {
540 if (net_dev)
541 shutdown_netfront(net_dev);
543 if (blk_dev)
544 shutdown_blkfront(blk_dev);
546 if (fb_dev)
547 shutdown_fbfront(fb_dev);
549 if (kbd_dev)
550 shutdown_kbdfront(kbd_dev);
552 if (pci_dev)
553 shutdown_pcifront(pci_dev);
555 /* TODO: fs import */
557 local_irq_disable();
559 /* Reset grant tables */
560 fini_gnttab();
562 /* Reset the console driver. */
563 fini_console();
564 /* TODO: record new ring mfn & event in start_info */
566 /* Reset XenBus */
567 fini_xenbus();
569 /* Reset timers */
570 fini_time();
572 /* Reset memory management. */
573 fini_mm();
575 /* Reset events. */
576 fini_events();
578 /* Reset traps */
579 trap_fini();
581 /* Reset arch details */
582 arch_fini();
583 }
585 /*
586 * do_exit: This is called whenever an IRET fails in entry.S.
587 * This will generally be because an application has got itself into
588 * a really bad state (probably a bad CS or SS). It must be killed.
589 * Of course, minimal OS doesn't have applications :-)
590 */
592 void do_exit(void)
593 {
594 printk("Do_exit called!\n");
595 stack_walk();
596 for( ;; )
597 {
598 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
599 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
600 }
601 }