ia64/xen-unstable

view xen/common/kernel.c @ 720:017595b44310

bitkeeper revision 1.426 (3f67735ai0MOd0z8ockI7RQVT4dA_Q)

fix broken checksum calculation code for UDP console.
author iap10@labyrinth.cl.cam.ac.uk
date Tue Sep 16 20:32:26 2003 +0000 (2003-09-16)
parents 4862078df9ac
children e2fd844b9778 a3017cd62e5d
line source
1 /******************************************************************************
2 * kernel.c
3 *
4 * This file should contain architecture-independent bootstrap and low-level
5 * help routines. It's a bit x86/PC specific right now!
6 *
7 * Copyright (c) 2002-2003 K A Fraser
8 */
10 #include <stdarg.h>
11 #include <xeno/lib.h>
12 #include <xeno/errno.h>
13 #include <xeno/spinlock.h>
14 #include <xeno/multiboot.h>
15 #include <xeno/sched.h>
16 #include <xeno/mm.h>
17 #include <xeno/delay.h>
18 #include <xeno/skbuff.h>
19 #include <xeno/interrupt.h>
20 #include <xeno/compile.h>
21 #include <xeno/version.h>
22 #include <xeno/netdevice.h>
23 #include <asm/io.h>
24 #include <asm/msr.h>
25 #include <asm/uaccess.h>
26 #include <hypervisor-ifs/dom0_ops.h>
27 #include <asm/byteorder.h>
28 #include <linux/if_ether.h>
29 #include <asm/domain_page.h>
30 #include <xeno/console.h>
31 #include <xeno/net_headers.h>
33 static int xpos, ypos;
34 static volatile unsigned char *video;
36 spinlock_t console_lock = SPIN_LOCK_UNLOCKED;
38 struct e820entry {
39 unsigned long addr_lo, addr_hi; /* start of memory segment */
40 unsigned long size_lo, size_hi; /* size of memory segment */
41 unsigned long type; /* type of memory segment */
42 };
44 void init_vga(void);
45 void init_serial(void);
46 void start_of_day(void);
48 /* opt_console: If true, Xen sends logging to the VGA console. */
49 int opt_console = 1;
50 /* opt_ser_baud: Baud rate at which logging is sent to COM1. */
51 unsigned int opt_ser_baud = 9600;
52 /* opt_dom0_mem: Kilobytes of memory allocated to domain 0. */
53 unsigned int opt_dom0_mem = 16000;
54 /* opt_ifname: Name of physical network interface to use. */
55 unsigned char opt_ifname[10] = "eth0";
56 /* opt_noht: If true, Hyperthreading is ignored. */
57 int opt_noht=0;
58 /* opt_noacpi: If true, ACPI tables are not parsed. */
59 int opt_noacpi=0;
60 /* opt_nosmp: If true, secondary processors are ignored. */
61 int opt_nosmp=0;
62 /* opt_watchdog: If true, run a watchdog NMI on each processor. */
63 int opt_watchdog=0;
65 static struct {
66 unsigned char *name;
67 enum { OPT_IP, OPT_STR, OPT_UINT, OPT_BOOL } type;
68 void *var;
69 } opts[] = {
70 { "console", OPT_UINT, &opt_console },
71 { "ser_baud", OPT_UINT, &opt_ser_baud },
72 { "dom0_mem", OPT_UINT, &opt_dom0_mem },
73 { "ifname", OPT_STR, &opt_ifname },
74 { "noht", OPT_BOOL, &opt_noht },
75 { "noacpi", OPT_BOOL, &opt_noacpi },
76 { "nosmp", OPT_BOOL, &opt_nosmp },
77 { "watchdog", OPT_BOOL, &opt_watchdog },
78 { NULL, 0, NULL }
79 };
82 void cmain (unsigned long magic, multiboot_info_t *mbi)
83 {
84 struct task_struct *new_dom;
85 dom0_newdomain_t dom0_params;
86 unsigned long max_page;
87 unsigned char *cmdline;
88 module_t *mod;
89 int i;
91 /*
92 * Note that serial output cannot be done properly until after
93 * command-line arguments have been parsed, and the required baud rate is
94 * known. Any messages before that will be output using the settings of
95 * the bootloader, for example.
96 */
98 if ( magic != MULTIBOOT_BOOTLOADER_MAGIC )
99 {
100 init_vga();
101 cls();
102 printk("Invalid magic number: 0x%x\n", (unsigned)magic);
103 for ( ; ; ) ;
104 }
106 /* Parse the command line. */
107 cmdline = (unsigned char *)(mbi->cmdline ? __va(mbi->cmdline) : NULL);
108 if ( cmdline != NULL )
109 {
110 unsigned char *opt_end, *opt;
111 while ( *cmdline == ' ' ) cmdline++;
112 cmdline = strchr(cmdline, ' ');
113 while ( cmdline != NULL )
114 {
115 while ( *cmdline == ' ' ) cmdline++;
116 if ( *cmdline == '\0' ) break;
117 opt_end = strchr(cmdline, ' ');
118 if ( opt_end != NULL ) *opt_end++ = '\0';
119 opt = strchr(cmdline, '=');
120 if ( opt != NULL ) *opt++ = '\0';
121 for ( i = 0; opts[i].name != NULL; i++ )
122 {
123 if ( strcmp(opts[i].name, cmdline ) != 0 ) continue;
124 switch ( opts[i].type )
125 {
126 case OPT_IP:
127 if ( opt != NULL )
128 *(unsigned long *)opts[i].var = str_to_quad(opt);
129 break;
130 case OPT_STR:
131 if ( opt != NULL )
132 strcpy(opts[i].var, opt);
133 break;
134 case OPT_UINT:
135 if ( opt != NULL )
136 *(unsigned int *)opts[i].var =
137 simple_strtol(opt, (char **)&opt, 0);
138 break;
139 case OPT_BOOL:
140 *(int *)opts[i].var = 1;
141 break;
142 }
143 }
144 cmdline = opt_end;
145 }
146 }
148 init_serial();
149 init_vga();
150 cls();
152 printk(XEN_BANNER);
153 printk(" http://www.cl.cam.ac.uk/netos/xen\n");
154 printk(" University of Cambridge Computer Laboratory\n\n");
155 printk(" Xen version %d.%d%s (%s@%s) (%s) %s\n\n",
156 XEN_VERSION, XEN_SUBVERSION, XEN_EXTRAVERSION,
157 XEN_COMPILE_BY, XEN_COMPILE_DOMAIN,
158 XEN_COMPILER, XEN_COMPILE_DATE);
160 /* We require memory and module information. */
161 if ( (mbi->flags & 9) != 9 )
162 {
163 printk("FATAL ERROR: Bad flags passed by bootloader: 0x%x\n",
164 (unsigned)mbi->flags);
165 for ( ; ; ) ;
166 }
168 if ( mbi->mods_count == 0 )
169 {
170 printk("Require at least one Multiboot module!\n");
171 for ( ; ; ) ;
172 }
174 memcpy(&idle0_task_union, &first_task_struct, sizeof(first_task_struct));
176 max_page = (mbi->mem_upper+1024) >> (PAGE_SHIFT - 10);
177 init_frametable(max_page);
178 printk("Initialised all memory on a %luMB machine\n",
179 max_page >> (20-PAGE_SHIFT));
181 init_page_allocator(__pa(&_end), MAX_MONITOR_ADDRESS);
183 /* These things will get done by do_newdomain() for all other tasks. */
184 current->shared_info = (void *)get_free_page(GFP_KERNEL);
185 memset(current->shared_info, 0, sizeof(shared_info_t));
186 set_fs(USER_DS);
188 start_of_day();
190 /* Create initial domain 0. */
191 dom0_params.memory_kb = opt_dom0_mem;
192 new_dom = do_newdomain(0, 0);
193 if ( new_dom == NULL ) panic("Error creating domain 0\n");
195 /*
196 * We're going to setup domain0 using the module(s) that we stashed safely
197 * above our MAX_DIRECTMAP_ADDRESS in boot/Boot.S The second module, if
198 * present, is an initrd ramdisk
199 */
200 mod = (module_t *)__va(mbi->mods_addr);
201 if ( setup_guestos(new_dom,
202 &dom0_params, 1,
203 (char *)MAX_DIRECTMAP_ADDRESS,
204 mod[mbi->mods_count-1].mod_end - mod[0].mod_start,
205 __va(mod[0].string),
206 (mbi->mods_count == 2) ?
207 (mod[1].mod_end - mod[1].mod_start):0)
208 != 0 ) panic("Could not set up DOM0 guest OS\n");
210 update_dom_time(new_dom->shared_info);
211 wake_up(new_dom);
213 cpu_idle();
214 }
217 #ifdef CONFIG_OUTPUT_SERIAL
219 #define SERIAL_BASE 0x3f8
220 #define RX_BUF 0
221 #define TX_HOLD 0
222 #define INT_ENABLE 1
223 #define INT_IDENT 2
224 #define DATA_FORMAT 3
225 #define LINE_CTL 4
226 #define LINE_STATUS 5
227 #define LINE_IN 6
228 #define DIVISOR_LO 0
229 #define DIVISOR_HI 1
231 void init_serial(void)
232 {
233 /* 'opt_ser_baud' baud, no parity, 1 stop bit, 8 data bits. */
234 outb(0x83, SERIAL_BASE+DATA_FORMAT);
235 outb(115200/opt_ser_baud, SERIAL_BASE+DIVISOR_LO);
236 outb(0, SERIAL_BASE+DIVISOR_HI);
237 outb(0x03, SERIAL_BASE+DATA_FORMAT);
239 /* No interrupts. */
240 outb(0x00, SERIAL_BASE+INT_ENABLE);
241 }
244 void putchar_serial(unsigned char c)
245 {
246 if ( c == '\n' ) putchar_serial('\r');
247 while ( !(inb(SERIAL_BASE+LINE_STATUS)&(1<<5)) ) barrier();
248 outb(c, SERIAL_BASE+TX_HOLD);
249 }
251 #else
253 void init_serial(void) {}
254 void putchar_serial(unsigned char c) {}
256 #endif
259 #ifdef CONFIG_OUTPUT_CONSOLE
261 /* VGA text (mode 3) definitions. */
262 #define COLUMNS 80
263 #define LINES 25
264 #define ATTRIBUTE 7
265 #define VIDEO __va(0xB8000)
267 /* This is actually code from vgaHWRestore in an old version of XFree86 :-) */
268 void init_vga(void)
269 {
270 /* The following VGA state was saved from a chip in text mode 3. */
271 static unsigned char regs[] = {
272 /* Sequencer registers */
273 0x03, 0x00, 0x03, 0x00, 0x02,
274 /* CRTC registers */
275 0x5f, 0x4f, 0x50, 0x82, 0x55, 0x81, 0xbf, 0x1f, 0x00, 0x4f, 0x20,
276 0x0e, 0x00, 0x00, 0x01, 0xe0, 0x9c, 0x8e, 0x8f, 0x28, 0x1f, 0x96,
277 0xb9, 0xa3, 0xff,
278 /* Graphic registers */
279 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0e, 0x00, 0xff,
280 /* Attribute registers */
281 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3a,
282 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x0c, 0x00, 0x0f, 0x08, 0x00
283 };
285 int i, j = 0;
286 volatile unsigned char tmp;
288 if ( !opt_console )
289 return;
291 tmp = inb(0x3da);
292 outb(0x00, 0x3c0);
294 for ( i = 0; i < 5; i++ )
295 outw((regs[j++] << 8) | i, 0x3c4);
297 /* Ensure CRTC registers 0-7 are unlocked by clearing bit 7 of CRTC[17]. */
298 outw(((regs[5+17] & 0x7F) << 8) | 17, 0x3d4);
300 for ( i = 0; i < 25; i++ )
301 outw((regs[j++] << 8) | i, 0x3d4);
303 for ( i = 0; i < 9; i++ )
304 outw((regs[j++] << 8) | i, 0x3ce);
306 for ( i = 0; i < 21; i++ )
307 {
308 tmp = inb(0x3da);
309 outb(i, 0x3c0);
310 outb(regs[j++], 0x3c0);
311 }
313 tmp = inb(0x3da);
314 outb(0x20, 0x3c0);
315 }
318 /* Clear the screen and initialize VIDEO, XPOS and YPOS. */
319 void cls(void)
320 {
321 int i;
323 if ( !opt_console )
324 return;
326 video = (unsigned char *) VIDEO;
328 for (i = 0; i < COLUMNS * LINES * 2; i++)
329 *(video + i) = 0;
331 xpos = 0;
332 ypos = 0;
334 outw(10+(1<<(5+8)), 0x3d4); /* cursor off */
335 }
338 static void put_newline(void)
339 {
340 xpos = 0;
341 ypos++;
343 if (ypos >= LINES)
344 {
345 static char zeroarr[2*COLUMNS] = { 0 };
346 ypos = LINES-1;
347 memcpy((char*)video,
348 (char*)video + 2*COLUMNS, (LINES-1)*2*COLUMNS);
349 memcpy((char*)video + (LINES-1)*2*COLUMNS,
350 zeroarr, 2*COLUMNS);
351 }
352 }
355 void putchar_console(int c)
356 {
357 if ( !opt_console )
358 return;
360 if ( c == '\n' )
361 {
362 put_newline();
363 }
364 else
365 {
366 *(video + (xpos + ypos * COLUMNS) * 2) = c & 0xFF;
367 *(video + (xpos + ypos * COLUMNS) * 2 + 1) = ATTRIBUTE;
369 xpos++;
370 if (xpos >= COLUMNS)
371 put_newline();
372 }
373 }
375 #else
377 void init_vga(void) {}
378 void cls(void) {}
379 void putchar_console(int c) {}
381 #endif
384 static void putchar(int c)
385 {
386 if ( (c != '\n') && ((c < 32) || (c > 126)) ) return;
387 putchar_serial(c);
388 putchar_console(c);
389 }
392 static inline void __putstr(const char *str)
393 {
394 while ( *str ) putchar(*str++);
395 }
398 void printf (const char *fmt, ...)
399 {
400 va_list args;
401 char buf[128];
402 const char *p = fmt;
403 unsigned long flags;
405 /*
406 * If the format string contains '%' descriptors then we have to parse it
407 * before printing it. We parse it into a fixed-length buffer. Long
408 * strings should therefore _not_ contain '%' characters!
409 */
410 if ( strchr(fmt, '%') != NULL )
411 {
412 va_start(args, fmt);
413 (void)vsnprintf(buf, sizeof(buf), fmt, args);
414 va_end(args);
415 p = buf;
416 }
418 spin_lock_irqsave(&console_lock, flags);
419 while ( *p ) putchar(*p++);
420 spin_unlock_irqrestore(&console_lock, flags);
421 }
424 void panic(const char *fmt, ...)
425 {
426 va_list args;
427 char buf[128];
428 unsigned long flags;
429 extern void machine_restart(char *);
431 va_start(args, fmt);
432 (void)vsnprintf(buf, sizeof(buf), fmt, args);
433 va_end(args);
435 /* Spit out multiline message in one go. */
436 spin_lock_irqsave(&console_lock, flags);
437 __putstr("\n****************************************\n");
438 __putstr(buf);
439 __putstr("Aieee! CPU");
440 sprintf(buf, "%d", smp_processor_id());
441 __putstr(buf);
442 __putstr(" is toast...\n");
443 __putstr("****************************************\n\n");
444 __putstr("Reboot in five seconds...\n");
445 spin_unlock_irqrestore(&console_lock, flags);
447 mdelay(5000);
448 machine_restart(0);
449 }
452 /* No-op syscall. */
453 asmlinkage long sys_ni_syscall(void)
454 {
455 return -ENOSYS;
456 }
459 unsigned short compute_cksum(unsigned short *buf, int count)
460 {
461 unsigned long sum = 0;
462 while ( count-- )
463 sum += *buf++;
464 while ( sum >> 16 )
465 sum = (sum & 0xffff) + (sum >> 16);
466 return (unsigned short) ~sum;
467 }
470 /*
471 * Function written by ek247. Exports console output from all domains upwards
472 * to domain0, by stuffing it into a fake network packet.
473 */
474 int console_export(char *str, int len)
475 {
476 struct sk_buff *skb;
477 struct iphdr *iph = NULL;
478 struct udphdr *udph = NULL;
479 struct ethhdr *ethh = NULL;
480 int hdr_size = sizeof(struct iphdr) + sizeof(struct udphdr);
481 u8 *skb_data;
483 skb = dev_alloc_skb(sizeof(struct ethhdr) +
484 hdr_size + len + 20);
485 if ( skb == NULL ) return 0;
487 skb->dev = the_dev;
488 skb_data = (u8 *)map_domain_mem((skb->pf - frame_table) << PAGE_SHIFT);
489 skb_reserve(skb, 2);
491 /* Get a pointer to each header. */
492 ethh = (struct ethhdr *)
493 (skb_data + (skb->data - skb->head));
494 iph = (struct iphdr *)(ethh + 1);
495 udph = (struct udphdr *)(iph + 1);
497 skb_reserve(skb, sizeof(struct ethhdr));
498 skb_put(skb, hdr_size + len);
500 /* Build IP header. */
501 iph->version = 4;
502 iph->ihl = 5;
503 iph->tos = 0;
504 iph->tot_len = htons(hdr_size + len);
505 iph->id = 0xdead;
506 iph->frag_off= 0;
507 iph->ttl = 255;
508 iph->protocol= 17;
509 iph->daddr = htonl(0xa9fe0100); /* 169.254.1.0 */
510 iph->saddr = htonl(0xa9fefeff); /* 169.254.254.255 */
511 iph->check = 0;
512 iph->check = compute_cksum((__u16 *)iph, sizeof(struct iphdr)/2);
514 /* Build UDP header. */
515 udph->source = htons(current->domain);
516 udph->dest = htons(666);
517 udph->len = htons(sizeof(struct udphdr) + len);
518 udph->check = 0;
520 /* Build the UDP payload. */
521 memcpy((char *)(udph + 1), str, len);
523 /* Fix Ethernet header. */
524 memset(ethh->h_source, 0, ETH_ALEN);
525 memset(ethh->h_dest, 0, ETH_ALEN);
526 ethh->h_proto = htons(ETH_P_IP);
527 skb->mac.ethernet= (struct ethhdr *)ethh;
529 unmap_domain_mem(skb_data);
531 skb->dst_vif = find_vif_by_id(0);
532 (void)netif_rx(skb);
534 return 1;
535 }
538 long do_console_write(char *str, unsigned int count)
539 {
540 #define SIZEOF_BUF 256
541 unsigned char safe_str[SIZEOF_BUF];
542 unsigned char exported_str[SIZEOF_BUF+1];
543 unsigned char dom_id[5];
544 unsigned long flags;
545 int i=0;
546 int j=0;
547 unsigned char prev = '\n';
549 if ( count > SIZEOF_BUF ) count = SIZEOF_BUF;
551 if ( copy_from_user(safe_str, str, count) )
552 return -EFAULT;
554 spin_lock_irqsave(&console_lock, flags);
556 __putstr("DOM");
557 sprintf(dom_id, "%d", current->domain);
558 __putstr(dom_id);
559 __putstr(": ");
561 for ( i = 0; i < count; i++ )
562 {
563 exported_str[j++]=safe_str[i];
565 if ( !safe_str[i] ) break;
566 putchar(prev = safe_str[i]);
567 }
569 if ( prev != '\n' ) putchar('\n');
571 spin_unlock_irqrestore(&console_lock, flags);
573 exported_str[j++]='\0';
575 if ( current->domain != 0 )
576 console_export(exported_str, j);
578 return(0);
579 }
582 void __out_of_line_bug(int line)
583 {
584 printk("kernel BUG in header file at line %d\n", line);
585 BUG();
586 for ( ; ; ) continue;
587 }
590 /*
591 * GRAVEYARD
592 */
593 #if 0
594 if ( (mbi->flags & (1<<6)) )
595 {
596 memory_map_t *mmap = (memory_map_t *)mbi->mmap_addr;
597 struct e820entry *e820 = E820_MAP;
599 while ( (unsigned long)mmap < (mbi->mmap_addr + mbi->mmap_length) )
600 {
601 e820->addr_lo = mmap->base_addr_low;
602 e820->addr_hi = mmap->base_addr_high;
603 e820->size_lo = mmap->length_low;
604 e820->size_hi = mmap->length_high;
605 e820->type = mmap->type;
606 e820++;
607 mmap = (memory_map_t *)
608 ((unsigned long)mmap + mmap->size + sizeof (mmap->size));
609 }
610 }
611 #endif