ia64/xen-unstable

view extras/mini-os/kernel.c @ 17275:7fc9767f966a

minios: Automatically set IP from XenStore information

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 19 16:20:14 2008 +0000 (2008-03-19)
parents bf63d055d30c
children 491a3b62ae5b
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 <fs.h>
44 #include <xmalloc.h>
45 #include <fcntl.h>
46 #include <xen/features.h>
47 #include <xen/version.h>
50 u8 xen_features[XENFEAT_NR_SUBMAPS * 32];
52 void setup_xen_features(void)
53 {
54 xen_feature_info_t fi;
55 int i, j;
57 for (i = 0; i < XENFEAT_NR_SUBMAPS; i++)
58 {
59 fi.submap_idx = i;
60 if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
61 break;
63 for (j=0; j<32; j++)
64 xen_features[i*32+j] = !!(fi.submap & 1<<j);
65 }
66 }
68 void test_xenbus(void);
70 static void xenbus_tester(void *p)
71 {
72 printk("Xenbus tests disabled, because of a Xend bug.\n");
73 /* test_xenbus(); */
74 }
76 static void periodic_thread(void *p)
77 {
78 struct timeval tv;
79 printk("Periodic thread started.\n");
80 for(;;)
81 {
82 gettimeofday(&tv, NULL);
83 printk("T(s=%ld us=%ld)\n", tv.tv_sec, tv.tv_usec);
84 msleep(1000);
85 }
86 }
88 static void netfront_thread(void *p)
89 {
90 init_netfront(NULL, NULL, NULL, NULL);
91 }
93 static struct blkfront_dev *blk_dev;
94 static uint64_t blk_sectors;
95 static unsigned blk_sector_size;
96 static int blk_mode;
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_sector_size, blk_sector_size);
115 req->aiocb.aio_nbytes = blk_sector_size;
116 req->aiocb.aio_offset = sector * blk_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_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_sector_size;
158 buf = (int*) aiocb->aio_buf;
159 rand_value = req->rand_value;
160 for (i = 0; i < blk_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_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_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;
210 blk_dev = init_blkfront(NULL, &blk_sectors, &blk_sector_size, &blk_mode);
211 if (!blk_dev)
212 return;
214 #ifdef BLKTEST_WRITE
215 if (blk_mode == O_RDWR) {
216 blk_write_sector(0);
217 blk_write_sector(blk_sectors-1);
218 } else
219 #endif
220 {
221 blk_read_sector(0);
222 blk_read_sector(blk_sectors-1);
223 }
225 while (1) {
226 uint64_t sector = rand() % blk_sectors;
227 struct timeval tv;
228 #ifdef BLKTEST_WRITE
229 if (blk_mode == O_RDWR)
230 blk_write_sector(sector);
231 else
232 #endif
233 blk_read_sector(sector);
234 blkfront_aio_poll(blk_dev);
235 gettimeofday(&tv, NULL);
236 if (tv.tv_sec > lasttime + 10) {
237 printk("%llu read, %llu write\n", blk_size_read, blk_size_write);
238 lasttime = tv.tv_sec;
239 }
241 #ifdef BLKTEST_WRITE
242 while (blk_to_read) {
243 struct blk_req *req = blk_to_read;
244 blk_to_read = blk_to_read->next;
245 req->aiocb.aio_cb = blk_write_read_completed;
246 blkfront_aio_read(&req->aiocb);
247 }
248 #endif
249 }
250 }
252 #define WIDTH 800
253 #define HEIGHT 600
254 #define DEPTH 32
256 static uint32_t *fb;
257 static struct fbfront_dev *fb_dev;
258 static struct semaphore fbfront_sem = __SEMAPHORE_INITIALIZER(fbfront_sem, 0);
260 static void fbfront_drawvert(int x, int y1, int y2, uint32_t color)
261 {
262 int y;
263 if (x < 0)
264 return;
265 if (x >= WIDTH)
266 return;
267 if (y1 < 0)
268 y1 = 0;
269 if (y2 >= HEIGHT)
270 y2 = HEIGHT-1;
271 for (y = y1; y <= y2; y++)
272 fb[x + y*WIDTH] ^= color;
273 }
275 static void fbfront_drawhoriz(int x1, int x2, int y, uint32_t color)
276 {
277 int x;
278 if (y < 0)
279 return;
280 if (y >= HEIGHT)
281 return;
282 if (x1 < 0)
283 x1 = 0;
284 if (x2 >= WIDTH)
285 x2 = WIDTH-1;
286 for (x = x1; x <= x2; x++)
287 fb[x + y*WIDTH] ^= color;
288 }
290 static void fbfront_thread(void *p)
291 {
292 size_t line_length = WIDTH * (DEPTH / 8);
293 size_t memsize = HEIGHT * line_length;
295 fb = _xmalloc(memsize, PAGE_SIZE);
296 fb_dev = init_fbfront(NULL, fb, WIDTH, HEIGHT, DEPTH, line_length, memsize);
297 if (!fb_dev) {
298 xfree(fb);
299 return;
300 }
301 up(&fbfront_sem);
302 }
304 static void clip_cursor(int *x, int *y)
305 {
306 if (*x < 0)
307 *x = 0;
308 if (*x >= WIDTH)
309 *x = WIDTH - 1;
310 if (*y < 0)
311 *y = 0;
312 if (*y >= HEIGHT)
313 *y = HEIGHT - 1;
314 }
316 static void refresh_cursor(int new_x, int new_y)
317 {
318 static int old_x = -1, old_y = -1;
319 if (old_x != -1 && old_y != -1) {
320 fbfront_drawvert(old_x, old_y + 1, old_y + 8, 0xffffffff);
321 fbfront_drawhoriz(old_x + 1, old_x + 8, old_y, 0xffffffff);
322 fbfront_update(fb_dev, old_x, old_y, 9, 9);
323 }
324 old_x = new_x;
325 old_y = new_y;
326 fbfront_drawvert(new_x, new_y + 1, new_y + 8, 0xffffffff);
327 fbfront_drawhoriz(new_x + 1, new_x + 8, new_y, 0xffffffff);
328 fbfront_update(fb_dev, new_x, new_y, 9, 9);
329 }
331 static void kbdfront_thread(void *p)
332 {
333 struct kbdfront_dev *kbd_dev;
334 DEFINE_WAIT(w);
335 int x = WIDTH / 2, y = HEIGHT / 2, z;
337 kbd_dev = init_kbdfront(NULL, 1);
338 if (!kbd_dev)
339 return;
341 down(&fbfront_sem);
342 refresh_cursor(x, y);
343 while (1) {
344 union xenkbd_in_event event;
346 add_waiter(w, kbdfront_queue);
348 if (kbdfront_receive(kbd_dev, &event, 1) == 0)
349 schedule();
350 else switch(event.type) {
351 case XENKBD_TYPE_MOTION:
352 printk("motion x:%d y:%d z:%d\n",
353 event.motion.rel_x,
354 event.motion.rel_y,
355 event.motion.rel_z);
356 x += event.motion.rel_x;
357 y += event.motion.rel_y;
358 z += event.motion.rel_z;
359 clip_cursor(&x, &y);
360 refresh_cursor(x, y);
361 break;
362 case XENKBD_TYPE_POS:
363 printk("pos x:%d y:%d dz:%d\n",
364 event.pos.abs_x,
365 event.pos.abs_y,
366 event.pos.rel_z);
367 x = event.pos.abs_x;
368 y = event.pos.abs_y;
369 z = event.pos.rel_z;
370 clip_cursor(&x, &y);
371 refresh_cursor(x, y);
372 break;
373 case XENKBD_TYPE_KEY:
374 printk("key %d %s\n",
375 event.key.keycode,
376 event.key.pressed ? "pressed" : "released");
377 if (event.key.keycode == BTN_LEFT) {
378 printk("mouse %s at (%d,%d,%d)\n",
379 event.key.pressed ? "clic" : "release", x, y, z);
380 if (event.key.pressed) {
381 uint32_t color = rand();
382 fbfront_drawvert(x - 16, y - 16, y + 15, color);
383 fbfront_drawhoriz(x - 16, x + 15, y + 16, color);
384 fbfront_drawvert(x + 16, y - 15, y + 16, color);
385 fbfront_drawhoriz(x - 15, x + 16, y - 16, color);
386 fbfront_update(fb_dev, x - 16, y - 16, 33, 33);
387 }
388 } else if (event.key.keycode == KEY_Q) {
389 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_poweroff };
390 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
391 do_exit();
392 }
393 break;
394 }
395 }
396 }
398 static void fs_thread(void *p)
399 {
400 init_fs_frontend();
401 }
403 /* This should be overridden by the application we are linked against. */
404 __attribute__((weak)) int app_main(start_info_t *si)
405 {
406 printk("Dummy main: start_info=%p\n", si);
407 create_thread("xenbus_tester", xenbus_tester, si);
408 create_thread("periodic_thread", periodic_thread, si);
409 create_thread("netfront", netfront_thread, si);
410 create_thread("blkfront", blkfront_thread, si);
411 create_thread("fbfront", fbfront_thread, si);
412 create_thread("kbdfront", kbdfront_thread, si);
413 create_thread("fs-frontend", fs_thread, si);
414 return 0;
415 }
417 /*
418 * INITIAL C ENTRY POINT.
419 */
420 void start_kernel(start_info_t *si)
421 {
422 static char hello[] = "Bootstrapping...\n";
424 (void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
426 arch_init(si);
428 trap_init();
430 /* print out some useful information */
431 printk("Xen Minimal OS!\n");
432 printk("start_info: %p\n", si);
433 printk(" nr_pages: %lu", si->nr_pages);
434 printk(" shared_inf: %08lx\n", si->shared_info);
435 printk(" pt_base: %p", (void *)si->pt_base);
436 printk(" mod_start: 0x%lx\n", si->mod_start);
437 printk(" mod_len: %lu\n", si->mod_len);
438 printk(" flags: 0x%x\n", (unsigned int)si->flags);
439 printk(" cmd_line: %s\n",
440 si->cmd_line ? (const char *)si->cmd_line : "NULL");
442 /* Set up events. */
443 init_events();
445 /* ENABLE EVENT DELIVERY. This is disabled at start of day. */
446 __sti();
448 arch_print_info();
450 setup_xen_features();
452 /* Init memory management. */
453 init_mm();
455 /* Init time and timers. */
456 init_time();
458 /* Init the console driver. */
459 init_console();
461 /* Init grant tables */
462 init_gnttab();
464 /* Init scheduler. */
465 init_sched();
467 /* Init XenBus */
468 init_xenbus();
470 /* Call (possibly overridden) app_main() */
471 app_main(&start_info);
473 /* Everything initialised, start idle thread */
474 run_idle_thread();
475 }
478 /*
479 * do_exit: This is called whenever an IRET fails in entry.S.
480 * This will generally be because an application has got itself into
481 * a really bad state (probably a bad CS or SS). It must be killed.
482 * Of course, minimal OS doesn't have applications :-)
483 */
485 void do_exit(void)
486 {
487 printk("Do_exit called!\n");
488 for( ;; )
489 {
490 struct sched_shutdown sched_shutdown = { .reason = SHUTDOWN_crash };
491 HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
492 }
493 }