direct-io.hg

view xen/common/kernel.c @ 418:cbe60e831a04

bitkeeper revision 1.203 (3eb284e8XJjBijrpL1sa9HnT3VaQKA)

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 02 14:47:04 2003 +0000 (2003-05-02)
parents 34407efa21dc a1275253dbd1
children 56e5f664744d d5610c721158
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 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;
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_BOOL, &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 };
61 void cmain (unsigned long magic, multiboot_info_t *mbi)
62 {
63 struct task_struct *new_dom;
64 dom0_newdomain_t dom0_params;
65 unsigned long max_page;
66 unsigned char *cmdline;
67 module_t *mod;
68 int i;
70 /*
71 * Clear the screen. Note that serial output cannot be done properly until
72 * after command-line arguments have been parsed, and the required baud
73 * rate is known. Any messages before that will be output using the
74 * seetings of the bootloader, for example. Maybe okay for error msgs...
75 */
76 init_vga();
77 cls();
79 if ( magic != MULTIBOOT_BOOTLOADER_MAGIC )
80 {
81 printk("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 printk("Bad flags passed by bootloader: 0x%x\n", (unsigned)mbi->flags);
92 return;
93 }
95 if ( mbi->mods_count == 0 )
96 {
97 printk("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 /* INITIALISE SERIAL LINE (printk will work okay from here on). */
167 init_serial();
169 /* Print the intro banner. The ASCII art is ugle since '\\' -> '\'. */
170 printk(" __ __ _ ___ _ _ \n");
171 printk(" \\ \\/ /___ _ __ / | / _ \\ | |__ ___| |_ __ _ \n");
172 printk(" \\ // _ \\ '_ \\ | || | | | | '_ \\ / _ \\ __/ _` |\n");
173 printk(" / \\ __/ | | | | || |_| | | |_) | __/ || (_| |\n");
174 printk(" /_/\\_\\___|_| |_| |_(_)___/ |_.__/ \\___|\\__\\__,_|\n\n");
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 #ifdef CONFIG_OUTPUT_CONSOLE
346 static char zeroarr[2*COLUMNS] = { 0 };
347 if ( (c != '\n') && ((c < 32) || (c > 126)) ) return;
348 #endif
350 putchar_serial(c);
352 #ifdef CONFIG_OUTPUT_CONSOLE
353 if(opt_console) {
354 if (c == '\n')
355 {
356 newline:
357 xpos = 0;
358 ypos++;
359 if (ypos >= LINES)
360 {
361 ypos = LINES-1;
362 memcpy((char*)video,
363 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
364 memcpy((char*)video + (LINES-1)*2*COLUMNS,
365 zeroarr, 2*COLUMNS);
366 }
367 return;
368 }
370 *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
371 *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
373 xpos++;
374 if (xpos >= COLUMNS)
375 goto newline;
376 }
377 #endif
378 }
380 static inline void __putstr(const char *str)
381 {
382 while ( *str ) putchar(*str++);
383 }
385 void printf (const char *fmt, ...)
386 {
387 va_list args;
388 char buf[128], *p;
389 unsigned long flags;
391 va_start(args, fmt);
392 (void)vsnprintf(buf, sizeof(buf), fmt, args);
393 va_end(args);
395 p = buf;
396 spin_lock_irqsave(&console_lock, flags);
397 while ( *p ) putchar(*p++);
398 spin_unlock_irqrestore(&console_lock, flags);
399 }
401 void panic(const char *fmt, ...)
402 {
403 va_list args;
404 char buf[128];
405 unsigned long flags;
406 extern void machine_restart(char *);
408 va_start(args, fmt);
409 (void)vsnprintf(buf, sizeof(buf), fmt, args);
410 va_end(args);
412 /* Spit out multiline message in one go. */
413 spin_lock_irqsave(&console_lock, flags);
414 __putstr("\n****************************************\n");
415 __putstr(buf);
416 __putstr("Aieee! CPU");
417 sprintf(buf, "%d", smp_processor_id());
418 __putstr(buf);
419 __putstr(" is toast...\n");
420 __putstr("****************************************\n\n");
421 __putstr("Reboot in five seconds...\n");
422 spin_unlock_irqrestore(&console_lock, flags);
424 mdelay(5000);
425 machine_restart(0);
426 }
428 /* No-op syscall. */
429 asmlinkage long sys_ni_syscall(void)
430 {
431 return -ENOSYS;
432 }
435 unsigned short compute_cksum(unsigned short *buf, int count)
436 {
437 /* Function written by ek247
438 * Computes IP and UDP checksum.
439 * To be used for the fake console packets
440 * created in console_export
441 */
443 unsigned long sum=0;
445 while (count--)
446 {
447 sum+=*buf++;
448 if (sum & 0xFFFF0000)
449 {
450 //carry occured, so wrap around
451 sum &=0xFFFF;
452 sum++;
453 }
454 }
455 return ~(sum & 0xFFFF);
456 }
460 /* XXX SMH: below is rather vile; pulled in to allow network console */
462 extern int netif_rx(struct sk_buff *);
464 typedef struct my_udphdr {
465 __u16 source;
466 __u16 dest;
467 __u16 len;
468 __u16 check;
469 } my_udphdr_t;
472 typedef struct my_iphdr {
473 #if defined(__LITTLE_ENDIAN_BITFIELD)
474 __u8 ihl:4,
475 version:4;
476 #elif defined (__BIG_ENDIAN_BITFIELD)
477 __u8 version:4,
478 ihl:4;
479 #else
480 #error "Please fix <asm/byteorder.h>"
481 #endif
482 __u8 tos;
483 __u16 tot_len;
484 __u16 id;
485 __u16 frag_off;
486 __u8 ttl;
487 __u8 protocol;
488 __u16 check;
489 __u32 saddr;
490 __u32 daddr;
491 } my_iphdr_t;
494 typedef struct my_ethhdr {
495 unsigned char h_dest[6];
496 unsigned char h_source[6];
497 unsigned short h_proto;
498 } my_ethhdr_t;
500 /*
501 * Function written by ek247. Exports console output from all domains upwards
502 * to domain0, by stuffing it into a fake network packet.
503 */
504 int console_export(char *str, int len)
505 {
506 struct sk_buff *skb;
507 struct my_iphdr *iph = NULL;
508 struct my_udphdr *udph = NULL;
509 struct my_ethhdr *ethh = NULL;
510 int hdr_size = sizeof(struct my_iphdr) + sizeof(struct my_udphdr);
511 u8 *skb_data;
513 skb = dev_alloc_skb(sizeof(struct my_ethhdr) +
514 hdr_size + len + 20);
515 if ( skb == NULL ) return 0;
517 skb->dev = the_dev;
518 skb_data = (u8 *)map_domain_mem((skb->pf - frame_table) << PAGE_SHIFT);
519 skb_reserve(skb, 2);
521 /* Get a pointer to each header. */
522 ethh = (struct my_ethhdr *)
523 (skb_data + (skb->data - skb->head));
524 iph = (struct my_iphdr *)(ethh + 1);
525 udph = (struct my_udphdr *)(iph + 1);
527 skb_reserve(skb, sizeof(struct my_ethhdr));
528 skb_put(skb, hdr_size + len);
530 /* Build IP header. */
531 iph->version = 4;
532 iph->ihl = 5;
533 iph->frag_off= 0;
534 iph->id = 0xdead;
535 iph->ttl = 255;
536 iph->protocol= 17;
537 iph->daddr = htonl(0xa9fe0100); /* 169.254.1.0 */
538 iph->saddr = htonl(0xa9fe0100); /* 169.254.1.0 */
539 iph->tot_len = htons(hdr_size + len);
540 iph->check = 0;
541 iph->check = compute_cksum((__u16 *)iph, sizeof(struct my_iphdr)/2);
543 /* Build UDP header. */
544 udph->source = htons(current->domain);
545 udph->dest = htons(666);
546 udph->len = htons(sizeof(struct my_udphdr) + len);
547 udph->check = 0;
549 /* Build the UDP payload. */
550 memcpy((char *)(udph + 1), str, len);
552 /* Fix Ethernet header. */
553 memset(ethh->h_source, 0, ETH_ALEN);
554 memset(ethh->h_dest, 0, ETH_ALEN);
555 ethh->h_proto = htons(ETH_P_IP);
556 skb->mac.ethernet= (struct ethhdr *)ethh;
558 unmap_domain_mem(skb_data);
560 (void)netif_rx(skb);
562 return 1;
563 }
566 long do_console_write(char *str, unsigned int count)
567 {
568 #define SIZEOF_BUF 256
569 unsigned char safe_str[SIZEOF_BUF];
570 unsigned char exported_str[SIZEOF_BUF];
571 unsigned char dom_id[5];
572 unsigned long flags;
573 int i=0;
574 int j=0;
575 unsigned char prev = '\n';
577 if ( count > SIZEOF_BUF ) count = SIZEOF_BUF;
579 if ( copy_from_user(safe_str, str, count) )
580 return -EFAULT;
582 spin_lock_irqsave(&console_lock, flags);
584 __putstr("DOM");
585 sprintf(dom_id, "%d", current->domain);
586 __putstr(dom_id);
587 __putstr(": ");
589 for ( i = 0; i < count; i++ )
590 {
591 exported_str[j++]=safe_str[i];
593 if ( !safe_str[i] ) break;
594 putchar(prev = safe_str[i]);
595 }
597 if ( prev != '\n' ) putchar('\n');
599 spin_unlock_irqrestore(&console_lock, flags);
601 exported_str[j]='\0';
602 console_export(exported_str, j-1);
604 return(0);
605 }
607 void __out_of_line_bug(int line)
608 {
609 printk("kernel BUG in header file at line %d\n", line);
610 BUG();
611 for ( ; ; ) continue;
612 }