direct-io.hg

view xen/common/kernel.c @ 459:e5d770b7e056

bitkeeper revision 1.237 (3ec4ebc3kTuWXkGgfS_HH1Or5d3BmQ)

Merge scramble.cl.cam.ac.uk:/auto/groups/xeno/BK/xeno.bk
into scramble.cl.cam.ac.uk:/local/scratch/kaf24/xeno
author kaf24@scramble.cl.cam.ac.uk
date Fri May 16 13:46:43 2003 +0000 (2003-05-16)
parents 5df607d873b3 3c7683c7c118
children 0086e866c0d6
line source
1 #include <stdarg.h>
2 #include <xeno/lib.h>
3 #include <xeno/errno.h>
4 #include <xeno/spinlock.h>
5 #include <xeno/multiboot.h>
6 #include <xeno/sched.h>
7 #include <xeno/mm.h>
8 #include <xeno/delay.h>
9 #include <xeno/skbuff.h>
10 #include <xeno/interrupt.h>
11 #include <xeno/compile.h>
12 #include <xeno/version.h>
13 #include <asm/io.h>
14 #include <asm/msr.h>
15 #include <asm/uaccess.h>
16 #include <xeno/dom0_ops.h>
17 #include <asm/byteorder.h>
18 #include <linux/if_ether.h>
19 #include <asm/domain_page.h>
20 #include <xeno/console.h>
22 static int xpos, ypos;
23 static volatile unsigned char *video;
25 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
27 struct e820entry {
28 unsigned long addr_lo, addr_hi; /* start of memory segment */
29 unsigned long size_lo, size_hi; /* size of memory segment */
30 unsigned long type; /* type of memory segment */
31 };
33 void init_vga(void);
34 void init_serial(void);
35 void start_of_day(void);
37 /* Command line options and variables. */
38 unsigned int opt_console = 1;
39 unsigned int opt_ser_baud = 9600; /* default baud for COM1 */
40 unsigned int opt_dom0_mem = 16000; /* default kbytes for DOM0 */
41 unsigned int opt_ne_base = 0; /* NE2k NICs cannot be probed */
42 unsigned char opt_ifname[10] = "eth0";
43 int opt_noht=0, opt_noacpi=0, opt_nosmp=0;
44 enum { OPT_IP, OPT_STR, OPT_UINT, OPT_BOOL };
45 static struct {
46 unsigned char *name;
47 int type;
48 void *var;
49 } opts[] = {
50 { "console", OPT_UINT, &opt_console },
51 { "ser_baud", OPT_UINT, &opt_ser_baud },
52 { "dom0_mem", OPT_UINT, &opt_dom0_mem },
53 { "ne_base", OPT_UINT, &opt_ne_base },
54 { "ifname", OPT_STR, &opt_ifname },
55 { "noht", OPT_BOOL, &opt_noht },
56 { "noacpi", OPT_BOOL, &opt_noacpi },
57 { "nosmp", OPT_BOOL, &opt_nosmp },
58 { NULL, 0, NULL }
59 };
62 void cmain (unsigned long magic, multiboot_info_t *mbi)
63 {
64 struct task_struct *new_dom;
65 dom0_newdomain_t dom0_params;
66 unsigned long max_page;
67 unsigned char *cmdline;
68 module_t *mod;
69 int i;
71 /*
72 * Note that serial output cannot be done properly until
73 * after command-line arguments have been parsed, and the required baud
74 * rate is known. Any messages before that will be output using the
75 * settings of the bootloader, for example. Maybe okay for error msgs...
76 */
77 #define early_error(args...) opt_console=1; init_vga(); cls(); printk(args)
79 if ( magic != MULTIBOOT_BOOTLOADER_MAGIC )
80 {
81 early_error("Invalid magic number: 0x%x\n", (unsigned)magic);
82 return;
83 }
85 /*
86 * We require some kind of memory and module information.
87 * The rest we can fake!
88 */
89 if ( (mbi->flags & 9) != 9 )
90 {
91 early_error("Bad flags passed by bootloader: 0x%x\n", (unsigned)mbi->flags);
92 return;
93 }
95 if ( mbi->mods_count == 0 )
96 {
97 early_error("Require at least one module!\n");
98 return;
99 }
101 /* Are mmap_* valid? */
102 #if 0
103 if ( (mbi->flags & (1<<6)) )
104 {
105 memory_map_t *mmap = (memory_map_t *)mbi->mmap_addr;
106 struct e820entry *e820 = E820_MAP;
108 while ( (unsigned long)mmap < (mbi->mmap_addr + mbi->mmap_length) )
109 {
110 e820->addr_lo = mmap->base_addr_low;
111 e820->addr_hi = mmap->base_addr_high;
112 e820->size_lo = mmap->length_low;
113 e820->size_hi = mmap->length_high;
114 e820->type = mmap->type;
115 e820++;
116 mmap = (memory_map_t *)
117 ((unsigned long)mmap + mmap->size + sizeof (mmap->size));
118 }
119 }
120 #endif
122 mod = (module_t *)__va(mbi->mods_addr);
124 /* Parse the command line. */
125 cmdline = (unsigned char *)(mbi->cmdline ? __va(mbi->cmdline) : NULL);
126 if ( cmdline != NULL )
127 {
128 unsigned char *opt_end, *opt;
129 while ( *cmdline == ' ' ) cmdline++;
130 cmdline = strchr(cmdline, ' ');
131 while ( cmdline != NULL )
132 {
133 while ( *cmdline == ' ' ) cmdline++;
134 if ( *cmdline == '\0' ) break;
135 opt_end = strchr(cmdline, ' ');
136 if ( opt_end != NULL ) *opt_end++ = '\0';
137 opt = strchr(cmdline, '=');
138 if ( opt != NULL ) *opt++ = '\0';
139 for ( i = 0; opts[i].name != NULL; i++ )
140 {
141 if ( strcmp(opts[i].name, cmdline ) != 0 ) continue;
142 switch ( opts[i].type )
143 {
144 case OPT_IP:
145 if ( opt != NULL )
146 *(unsigned long *)opts[i].var = str_to_quad(opt);
147 break;
148 case OPT_STR:
149 if ( opt != NULL )
150 strcpy(opts[i].var, opt);
151 break;
152 case OPT_UINT:
153 if ( opt != NULL )
154 *(unsigned int *)opts[i].var =
155 simple_strtol(opt, (char **)&opt, 0);
156 break;
157 case OPT_BOOL:
158 *(int *)opts[i].var = 1;
159 break;
160 }
161 }
162 cmdline = opt_end;
163 }
164 }
166 #undef early_error
168 init_vga();
169 cls();
171 /* INITIALISE SERIAL LINE (printk will work okay from here on). */
172 init_serial();
174 printk(XEN_BANNER);
175 printk(" http://www.cl.cam.ac.uk/xeno\n");
176 printk(" University of Cambridge Computer Laboratory\n\n");
177 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n\n",
178 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
179 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
180 XEN_COMPILER, XEN_COMPILE_DATE);
182 memcpy(&idle0_task_union, &first_task_struct, sizeof(first_task_struct));
184 max_page = (mbi->mem_upper+1024) >> (PAGE_SHIFT - 10);
185 init_frametable(max_page);
186 printk("Initialised all memory on a %luMB machine\n",
187 max_page >> (20-PAGE_SHIFT));
189 init_page_allocator(__pa(&_end), MAX_MONITOR_ADDRESS);
191 /* These things will get done by do_newdomain() for all other tasks. */
192 current->shared_info = (void *)get_free_page(GFP_KERNEL);
193 memset(current->shared_info, 0, sizeof(shared_info_t));
194 set_fs(USER_DS);
196 start_of_day();
198 /* Create initial domain 0. */
199 dom0_params.num_vifs = 1;
200 dom0_params.memory_kb = opt_dom0_mem;
202 new_dom = do_newdomain(0, 0);
203 if ( new_dom == NULL ) panic("Error creating domain 0\n");
205 /*
206 * We're going to setup domain0 using the module(s) that we stashed safely
207 * above our MAX_DIRECTMAP_ADDRESS in boot/Boot.S The second module, if
208 * present, is an initrd ramdisk
209 */
210 if ( setup_guestos(new_dom,
211 &dom0_params,
212 (char *)MAX_DIRECTMAP_ADDRESS,
213 mod[mbi->mods_count-1].mod_end - mod[0].mod_start,
214 __va(mod[0].string),
215 (mbi->mods_count == 2) ?
216 (mod[1].mod_end - mod[1].mod_start):0)
217 != 0 ) panic("Could not set up DOM0 guest OS\n");
219 update_dom_time(new_dom->shared_info);
220 wake_up(new_dom);
222 cpu_idle();
223 }
226 #define SERIAL_BASE 0x3f8
227 #define RX_BUF 0
228 #define TX_HOLD 0
229 #define INT_ENABLE 1
230 #define INT_IDENT 2
231 #define DATA_FORMAT 3
232 #define LINE_CTL 4
233 #define LINE_STATUS 5
234 #define LINE_IN 6
235 #define DIVISOR_LO 0
236 #define DIVISOR_HI 1
238 void init_serial(void)
239 {
240 #ifdef CONFIG_OUTPUT_SERIAL
241 /* 'opt_ser_baud' baud, no parity, 1 stop bit, 8 data bits. */
242 outb(0x83, SERIAL_BASE+DATA_FORMAT);
243 outb(115200/opt_ser_baud, SERIAL_BASE+DIVISOR_LO);
244 outb(0, SERIAL_BASE+DIVISOR_HI);
245 outb(0x03, SERIAL_BASE+DATA_FORMAT);
247 /* No interrupts. */
248 outb(0x00, SERIAL_BASE+INT_ENABLE);
249 #endif
250 }
253 void putchar_serial(unsigned char c)
254 {
255 #ifdef CONFIG_OUTPUT_SERIAL
256 if ( c == '\n' ) putchar_serial('\r');
257 while ( !(inb(SERIAL_BASE+LINE_STATUS)&(1<<5)) ) barrier();
258 outb(c, SERIAL_BASE+TX_HOLD);
259 #endif
260 }
263 /* VGA text (mode 3) definitions. */
264 #define COLUMNS 80
265 #define LINES 25
266 #define ATTRIBUTE 7
267 #define VIDEO __va(0xB8000)
269 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
270 void init_vga(void)
271 {
272 #ifdef CONFIG_OUTPUT_CONSOLE
273 /* The following VGA state was saved from a chip in text mode 3. */
274 static unsigned char regs[] = {
275 /* Sequencer registers */
276 0x03, 0x00, 0x03, 0x00, 0x02,
277 /* CRTC registers */
278 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
279 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
280 0xb9, 0xa3, 0xff,
281 /* Graphic registers */
282 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
283 /* Attribute registers */
284 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
285 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
286 };
288 int i, j = 0;
289 volatile unsigned char tmp;
291 if(opt_console) {
292 tmp = inb(0x3da);
293 outb(0x00, 0x3c0);
295 for ( i = 0; i < 5; i++ )
296 outw((regs[j++] << 8) | i, 0x3c4);
298 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
299 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
301 for ( i = 0; i < 25; i++ )
302 outw((regs[j++] << 8) | i, 0x3d4);
304 for ( i = 0; i < 9; i++ )
305 outw((regs[j++] << 8) | i, 0x3ce);
307 for ( i = 0; i < 21; i++ )
308 {
309 tmp = inb(0x3da);
310 outb(i, 0x3c0);
311 outb(regs[j++], 0x3c0);
312 }
314 tmp = inb(0x3da);
315 outb(0x20, 0x3c0);
316 }
317 #endif
318 }
321 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
322 void cls(void)
323 {
324 #ifdef CONFIG_OUTPUT_CONSOLE
325 int i;
327 if(opt_console) {
328 video = (unsigned char *) VIDEO;
330 for (i = 0; i < COLUMNS * LINES * 2; i++)
331 *(video + i) = 0;
333 xpos = 0;
334 ypos = 0;
336 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
337 }
338 #endif
339 }
342 /* Put the character C on the screen. */
343 static void putchar (int c)
344 {
345 if ( (c != '\n') && ((c < 32) || (c > 126)) ) return;
346 putchar_serial(c);
348 #ifdef CONFIG_OUTPUT_CONSOLE
349 if(opt_console) {
350 if (c == '\n')
351 {
352 newline:
353 xpos = 0;
354 ypos++;
355 if (ypos >= LINES)
356 {
357 static char zeroarr[2*COLUMNS] = { 0 };
358 ypos = LINES-1;
359 memcpy((char*)video,
360 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
361 memcpy((char*)video + (LINES-1)*2*COLUMNS,
362 zeroarr, 2*COLUMNS);
363 }
364 return;
365 }
367 *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
368 *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
370 xpos++;
371 if (xpos >= COLUMNS)
372 goto newline;
373 }
374 #endif
375 }
377 static inline void __putstr(const char *str)
378 {
379 while ( *str ) putchar(*str++);
380 }
382 void printf (const char *fmt, ...)
383 {
384 va_list args;
385 char buf[128];
386 const char *p = fmt;
387 unsigned long flags;
389 /*
390 * If the format string contains '%' descriptors then we have to parse it
391 * before printing it. We parse it into a fixed-length buffer. Long
392 * strings should therefore _not_ contain '%' characters!
393 */
394 if ( strchr(fmt, '%') != NULL )
395 {
396 va_start(args, fmt);
397 (void)vsnprintf(buf, sizeof(buf), fmt, args);
398 va_end(args);
399 p = buf;
400 }
402 spin_lock_irqsave(&console_lock, flags);
403 while ( *p ) putchar(*p++);
404 spin_unlock_irqrestore(&console_lock, flags);
405 }
407 void panic(const char *fmt, ...)
408 {
409 va_list args;
410 char buf[128];
411 unsigned long flags;
412 extern void machine_restart(char *);
414 va_start(args, fmt);
415 (void)vsnprintf(buf, sizeof(buf), fmt, args);
416 va_end(args);
418 /* Spit out multiline message in one go. */
419 spin_lock_irqsave(&console_lock, flags);
420 __putstr("\n****************************************\n");
421 __putstr(buf);
422 __putstr("Aieee! CPU");
423 sprintf(buf, "%d", smp_processor_id());
424 __putstr(buf);
425 __putstr(" is toast...\n");
426 __putstr("****************************************\n\n");
427 __putstr("Reboot in five seconds...\n");
428 spin_unlock_irqrestore(&console_lock, flags);
430 mdelay(5000);
431 machine_restart(0);
432 }
434 /* No-op syscall. */
435 asmlinkage long sys_ni_syscall(void)
436 {
437 return -ENOSYS;
438 }
441 unsigned short compute_cksum(unsigned short *buf, int count)
442 {
443 /* Function written by ek247
444 * Computes IP and UDP checksum.
445 * To be used for the fake console packets
446 * created in console_export
447 */
449 unsigned long sum=0;
451 while (count--)
452 {
453 sum+=*buf++;
454 if (sum & 0xFFFF0000)
455 {
456 //carry occured, so wrap around
457 sum &=0xFFFF;
458 sum++;
459 }
460 }
461 return ~(sum & 0xFFFF);
462 }
466 /* XXX SMH: below is rather vile; pulled in to allow network console */
468 extern int netif_rx(struct sk_buff *);
470 typedef struct my_udphdr {
471 __u16 source;
472 __u16 dest;
473 __u16 len;
474 __u16 check;
475 } my_udphdr_t;
478 typedef struct my_iphdr {
479 #if defined(__LITTLE_ENDIAN_BITFIELD)
480 __u8 ihl:4,
481 version:4;
482 #elif defined (__BIG_ENDIAN_BITFIELD)
483 __u8 version:4,
484 ihl:4;
485 #else
486 #error "Please fix <asm/byteorder.h>"
487 #endif
488 __u8 tos;
489 __u16 tot_len;
490 __u16 id;
491 __u16 frag_off;
492 __u8 ttl;
493 __u8 protocol;
494 __u16 check;
495 __u32 saddr;
496 __u32 daddr;
497 } my_iphdr_t;
500 typedef struct my_ethhdr {
501 unsigned char h_dest[6];
502 unsigned char h_source[6];
503 unsigned short h_proto;
504 } my_ethhdr_t;
506 /*
507 * Function written by ek247. Exports console output from all domains upwards
508 * to domain0, by stuffing it into a fake network packet.
509 */
510 int console_export(char *str, int len)
511 {
512 struct sk_buff *skb;
513 struct my_iphdr *iph = NULL;
514 struct my_udphdr *udph = NULL;
515 struct my_ethhdr *ethh = NULL;
516 int hdr_size = sizeof(struct my_iphdr) + sizeof(struct my_udphdr);
517 u8 *skb_data;
519 skb = dev_alloc_skb(sizeof(struct my_ethhdr) +
520 hdr_size + len + 20);
521 if ( skb == NULL ) return 0;
523 skb->dev = the_dev;
524 skb_data = (u8 *)map_domain_mem((skb->pf - frame_table) << PAGE_SHIFT);
525 skb_reserve(skb, 2);
527 /* Get a pointer to each header. */
528 ethh = (struct my_ethhdr *)
529 (skb_data + (skb->data - skb->head));
530 iph = (struct my_iphdr *)(ethh + 1);
531 udph = (struct my_udphdr *)(iph + 1);
533 skb_reserve(skb, sizeof(struct my_ethhdr));
534 skb_put(skb, hdr_size + len);
536 /* Build IP header. */
537 iph->version = 4;
538 iph->ihl = 5;
539 iph->frag_off= 0;
540 iph->id = 0xdead;
541 iph->ttl = 255;
542 iph->protocol= 17;
543 iph->daddr = htonl(0xa9fe0100); /* 169.254.1.0 */
544 iph->saddr = htonl(0xa9fefeff); /* 169.254.254.255 */
545 iph->tot_len = htons(hdr_size + len);
546 iph->check = 0;
547 iph->check = compute_cksum((__u16 *)iph, sizeof(struct my_iphdr)/2);
549 /* Build UDP header. */
550 udph->source = htons(current->domain);
551 udph->dest = htons(666);
552 udph->len = htons(sizeof(struct my_udphdr) + len);
553 udph->check = 0;
555 /* Build the UDP payload. */
556 memcpy((char *)(udph + 1), str, len);
558 /* Fix Ethernet header. */
559 memset(ethh->h_source, 0, ETH_ALEN);
560 memset(ethh->h_dest, 0, ETH_ALEN);
561 ethh->h_proto = htons(ETH_P_IP);
562 skb->mac.ethernet= (struct ethhdr *)ethh;
564 unmap_domain_mem(skb_data);
566 skb->dst_vif = find_vif_by_id(0);
567 (void)netif_rx(skb);
569 return 1;
570 }
573 long do_console_write(char *str, unsigned int count)
574 {
575 #define SIZEOF_BUF 256
576 unsigned char safe_str[SIZEOF_BUF];
577 unsigned char exported_str[SIZEOF_BUF];
578 unsigned char dom_id[5];
579 unsigned long flags;
580 int i=0;
581 int j=0;
582 unsigned char prev = '\n';
584 if ( count > SIZEOF_BUF ) count = SIZEOF_BUF;
586 if ( copy_from_user(safe_str, str, count) )
587 return -EFAULT;
589 spin_lock_irqsave(&console_lock, flags);
591 __putstr("DOM");
592 sprintf(dom_id, "%d", current->domain);
593 __putstr(dom_id);
594 __putstr(": ");
596 for ( i = 0; i < count; i++ )
597 {
598 exported_str[j++]=safe_str[i];
600 if ( !safe_str[i] ) break;
601 putchar(prev = safe_str[i]);
602 }
604 if ( prev != '\n' ) putchar('\n');
606 spin_unlock_irqrestore(&console_lock, flags);
608 exported_str[j]='\0';
609 console_export(exported_str, j-1);
611 return(0);
612 }
614 void __out_of_line_bug(int line)
615 {
616 printk("kernel BUG in header file at line %d\n", line);
617 BUG();
618 for ( ; ; ) continue;
619 }