ia64/xen-unstable

view tools/firmware/hvmloader/util.c @ 19709:011948e1b5a7

hvmloader: Scan for gpxe-capable NICs until one is found.

Signed-off-by: Akio Takebe <takebe_akio@jp.fujitsu.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Jun 03 16:12:34 2009 +0100 (2009-06-03)
parents f3240cd3cd2b
children
line source
1 /*
2 * util.c: Helper library functions for HVMLoader.
3 *
4 * Leendert van Doorn, leendert@watson.ibm.com
5 * Copyright (c) 2005, International Business Machines Corporation.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place - Suite 330, Boston, MA 02111-1307 USA.
19 */
21 #include "util.h"
22 #include "config.h"
23 #include "e820.h"
24 #include "hypercall.h"
25 #include <stdint.h>
26 #include <xen/xen.h>
27 #include <xen/memory.h>
29 void wrmsr(uint32_t idx, uint64_t v)
30 {
31 asm volatile (
32 "wrmsr"
33 : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
34 }
36 uint64_t rdmsr(uint32_t idx)
37 {
38 uint32_t lo, hi;
40 asm volatile (
41 "rdmsr"
42 : "=a" (lo), "=d" (hi) : "c" (idx) );
44 return (lo | ((uint64_t)hi << 32));
45 }
47 void outb(uint16_t addr, uint8_t val)
48 {
49 asm volatile ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
50 }
52 void outw(uint16_t addr, uint16_t val)
53 {
54 asm volatile ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
55 }
57 void outl(uint16_t addr, uint32_t val)
58 {
59 asm volatile ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
60 }
62 uint8_t inb(uint16_t addr)
63 {
64 uint8_t val;
65 asm volatile ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) );
66 return val;
67 }
69 uint16_t inw(uint16_t addr)
70 {
71 uint16_t val;
72 asm volatile ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) );
73 return val;
74 }
76 uint32_t inl(uint16_t addr)
77 {
78 uint32_t val;
79 asm volatile ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) );
80 return val;
81 }
83 uint8_t cmos_inb(uint8_t idx)
84 {
85 outb(0x70, idx);
86 return inb(0x71);
87 }
89 void cmos_outb(uint8_t idx, uint8_t val)
90 {
91 outb(0x70, idx);
92 outb(0x71, val);
93 }
95 char *itoa(char *a, unsigned int i)
96 {
97 unsigned int _i = i, x = 0;
99 do {
100 x++;
101 _i /= 10;
102 } while ( _i != 0 );
104 a += x;
105 *a-- = '\0';
107 do {
108 *a-- = (i % 10) + '0';
109 i /= 10;
110 } while ( i != 0 );
112 return a + 1;
113 }
115 int strcmp(const char *cs, const char *ct)
116 {
117 signed char res;
119 while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
120 continue;
122 return res;
123 }
125 int strncmp(const char *s1, const char *s2, uint32_t n)
126 {
127 uint32_t ctr;
128 for (ctr = 0; ctr < n; ctr++)
129 if (s1[ctr] != s2[ctr])
130 return (int)(s1[ctr] - s2[ctr]);
131 return 0;
132 }
134 void *memcpy(void *dest, const void *src, unsigned n)
135 {
136 int t0, t1, t2;
138 asm volatile (
139 "cld\n"
140 "rep; movsl\n"
141 "testb $2,%b4\n"
142 "je 1f\n"
143 "movsw\n"
144 "1: testb $1,%b4\n"
145 "je 2f\n"
146 "movsb\n"
147 "2:"
148 : "=&c" (t0), "=&D" (t1), "=&S" (t2)
149 : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
150 : "memory" );
151 return dest;
152 }
154 void *memmove(void *dest, const void *src, unsigned n)
155 {
156 if ( (unsigned long)dest > (unsigned long)src )
157 while ( n-- != 0 )
158 ((char *)dest)[n] = ((char *)src)[n];
159 else
160 memcpy(dest, src, n);
161 return dest;
162 }
164 char *
165 strcpy(char *dest, const char *src)
166 {
167 char *p = dest;
168 while ( *src )
169 *p++ = *src++;
170 *p = 0;
171 return dest;
172 }
174 char *
175 strncpy(char *dest, const char *src, unsigned n)
176 {
177 int i = 0;
178 char *p = dest;
180 /* write non-NUL characters from src into dest until we run
181 out of room in dest or encounter a NUL in src */
182 while ( (i < n) && *src )
183 {
184 *p++ = *src++;
185 i++;
186 }
188 /* pad remaining bytes of dest with NUL bytes */
189 while ( i < n )
190 {
191 *p++ = 0;
192 i++;
193 }
195 return dest;
196 }
198 unsigned
199 strlen(const char *s)
200 {
201 int i = 0;
202 while ( *s++ )
203 i++;
204 return i;
205 }
207 void *
208 memset(void *s, int c, unsigned n)
209 {
210 uint8_t b = (uint8_t) c;
211 uint8_t *p = (uint8_t *)s;
212 int i;
213 for ( i = 0; i < n; i++ )
214 *p++ = b;
215 return s;
216 }
218 int
219 memcmp(const void *s1, const void *s2, unsigned n)
220 {
221 unsigned i;
222 uint8_t *p1 = (uint8_t *) s1;
223 uint8_t *p2 = (uint8_t *) s2;
225 for ( i = 0; i < n; i++ )
226 {
227 if ( p1[i] < p2[i] )
228 return -1;
229 else if ( p1[i] > p2[i] )
230 return 1;
231 }
233 return 0;
234 }
236 void
237 cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
238 {
239 asm volatile (
240 "cpuid"
241 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
242 : "0" (idx) );
243 }
245 /* Write a two-character hex representation of 'byte' to digits[].
246 Pre-condition: sizeof(digits) >= 2 */
247 void
248 byte_to_hex(char *digits, uint8_t byte)
249 {
250 uint8_t nybbel = byte >> 4;
252 if ( nybbel > 9 )
253 digits[0] = 'a' + nybbel-10;
254 else
255 digits[0] = '0' + nybbel;
257 nybbel = byte & 0x0f;
258 if ( nybbel > 9 )
259 digits[1] = 'a' + nybbel-10;
260 else
261 digits[1] = '0' + nybbel;
262 }
264 /* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
265 string.
267 Pre-condition: sizeof(dest) >= 37 */
268 void
269 uuid_to_string(char *dest, uint8_t *uuid)
270 {
271 int i = 0;
272 char *p = dest;
274 for ( i = 0; i < 4; i++ )
275 {
276 byte_to_hex(p, uuid[i]);
277 p += 2;
278 }
279 *p++ = '-';
280 for ( i = 4; i < 6; i++ )
281 {
282 byte_to_hex(p, uuid[i]);
283 p += 2;
284 }
285 *p++ = '-';
286 for ( i = 6; i < 8; i++ )
287 {
288 byte_to_hex(p, uuid[i]);
289 p += 2;
290 }
291 *p++ = '-';
292 for ( i = 8; i < 10; i++ )
293 {
294 byte_to_hex(p, uuid[i]);
295 p += 2;
296 }
297 *p++ = '-';
298 for ( i = 10; i < 16; i++ )
299 {
300 byte_to_hex(p, uuid[i]);
301 p += 2;
302 }
303 *p = '\0';
304 }
306 void *mem_alloc(uint32_t size, uint32_t align)
307 {
308 static uint32_t reserve = RESERVED_MEMBASE - 1;
309 static int over_allocated;
310 struct xen_add_to_physmap xatp;
311 struct xen_memory_reservation xmr;
312 xen_pfn_t mfn;
313 uint32_t s, e;
315 /* Align to at least one kilobyte. */
316 if ( align < 1024 )
317 align = 1024;
319 s = (reserve + align) & ~(align - 1);
320 e = s + size - 1;
322 BUG_ON((e < s) || (e >> PAGE_SHIFT) >= hvm_info->reserved_mem_pgstart);
324 while ( (reserve >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
325 {
326 reserve += PAGE_SIZE;
327 mfn = reserve >> PAGE_SHIFT;
329 /* Try to allocate a brand new page in the reserved area. */
330 if ( !over_allocated )
331 {
332 xmr.domid = DOMID_SELF;
333 xmr.mem_flags = 0;
334 xmr.extent_order = 0;
335 xmr.nr_extents = 1;
336 set_xen_guest_handle(xmr.extent_start, &mfn);
337 if ( hypercall_memory_op(XENMEM_populate_physmap, &xmr) == 1 )
338 continue;
339 over_allocated = 1;
340 }
342 /* Otherwise, relocate a page from the ordinary RAM map. */
343 if ( hvm_info->high_mem_pgend )
344 {
345 xatp.idx = --hvm_info->high_mem_pgend;
346 if ( xatp.idx == (1ull << (32 - PAGE_SHIFT)) )
347 hvm_info->high_mem_pgend = 0;
348 }
349 else
350 {
351 xatp.idx = --hvm_info->low_mem_pgend;
352 }
353 xatp.domid = DOMID_SELF;
354 xatp.space = XENMAPSPACE_gmfn;
355 xatp.gpfn = mfn;
356 if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
357 BUG();
358 }
360 reserve = e;
362 return (void *)(unsigned long)s;
363 }
365 uint32_t ioapic_read(uint32_t reg)
366 {
367 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
368 return *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
369 }
371 void ioapic_write(uint32_t reg, uint32_t val)
372 {
373 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
374 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = val;
375 }
377 uint32_t lapic_read(uint32_t reg)
378 {
379 return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
380 }
382 void lapic_write(uint32_t reg, uint32_t val)
383 {
384 *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
385 }
387 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
388 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
390 uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
391 {
392 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
394 switch ( len )
395 {
396 case 1: return inb(0xcfc + (reg & 3));
397 case 2: return inw(0xcfc + (reg & 2));
398 }
400 return inl(0xcfc);
401 }
403 void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
404 {
405 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
407 switch ( len )
408 {
409 case 1: outb(0xcfc + (reg & 3), val); break;
410 case 2: outw(0xcfc + (reg & 2), val); break;
411 case 4: outl(0xcfc, val); break;
412 }
413 }
415 static char *printnum(char *p, unsigned long num, int base)
416 {
417 unsigned long n;
419 if ( (n = num/base) > 0 )
420 p = printnum(p, n, base);
421 *p++ = "0123456789abcdef"[(int)(num % base)];
422 *p = '\0';
423 return p;
424 }
426 static void _doprint(void (*put)(char), const char *fmt, va_list ap)
427 {
428 register char *str, c;
429 int lflag, zflag, nflag;
430 char buffer[17];
431 unsigned value;
432 int i, slen, pad;
434 for ( ; *fmt != '\0'; fmt++ )
435 {
436 if ( *fmt != '%' )
437 {
438 put(*fmt);
439 continue;
440 }
442 pad = zflag = nflag = lflag = 0;
443 c = *++fmt;
444 if ( (c == '-') || isdigit(c) )
445 {
446 if ( c == '-' )
447 {
448 nflag = 1;
449 c = *++fmt;
450 }
451 zflag = c == '0';
452 for ( pad = 0; isdigit(c); c = *++fmt )
453 pad = (pad * 10) + c - '0';
454 }
455 if ( c == 'l' ) /* long extension */
456 {
457 lflag = 1;
458 c = *++fmt;
459 }
460 if ( (c == 'd') || (c == 'u') || (c == 'o') || (c == 'x') )
461 {
462 if ( lflag )
463 value = va_arg(ap, unsigned);
464 else
465 value = (unsigned) va_arg(ap, unsigned int);
466 str = buffer;
467 printnum(str, value,
468 c == 'o' ? 8 : (c == 'x' ? 16 : 10));
469 goto printn;
470 }
471 else if ( (c == 'O') || (c == 'D') || (c == 'X') )
472 {
473 value = va_arg(ap, unsigned);
474 str = buffer;
475 printnum(str, value,
476 c == 'O' ? 8 : (c == 'X' ? 16 : 10));
477 printn:
478 slen = strlen(str);
479 for ( i = pad - slen; i > 0; i-- )
480 put(zflag ? '0' : ' ');
481 while ( *str )
482 put(*str++);
483 }
484 else if ( c == 's' )
485 {
486 str = va_arg(ap, char *);
487 slen = strlen(str);
488 if ( nflag == 0 )
489 for ( i = pad - slen; i > 0; i-- )
490 put(' ');
491 while ( *str )
492 put(*str++);
493 if ( nflag )
494 for ( i = pad - slen; i > 0; i-- )
495 put(' ');
496 }
497 else if ( c == 'c' )
498 {
499 put(va_arg(ap, int));
500 }
501 else
502 {
503 put(*fmt);
504 }
505 }
506 }
508 static void putchar(char c)
509 {
510 outb(0xe9, c);
511 }
513 int printf(const char *fmt, ...)
514 {
515 va_list ap;
517 va_start(ap, fmt);
518 _doprint(putchar, fmt, ap);
519 va_end(ap);
521 return 0;
522 }
524 int vprintf(const char *fmt, va_list ap)
525 {
526 _doprint(putchar, fmt, ap);
527 return 0;
528 }
530 void __assert_failed(char *assertion, char *file, int line)
531 {
532 printf("HVMLoader assertion '%s' failed at %s:%d\n",
533 assertion, file, line);
534 for ( ; ; )
535 asm volatile ( "ud2" );
536 }
538 void __bug(char *file, int line)
539 {
540 printf("HVMLoader bug at %s:%d\n", file, line);
541 for ( ; ; )
542 asm volatile ( "ud2" );
543 }
545 static void validate_hvm_info(struct hvm_info_table *t)
546 {
547 uint8_t *ptr = (uint8_t *)t;
548 uint8_t sum = 0;
549 int i;
551 if ( strncmp(t->signature, "HVM INFO", 8) )
552 {
553 printf("Bad hvm info signature\n");
554 BUG();
555 }
557 if ( t->length < sizeof(struct hvm_info_table) )
558 {
559 printf("Bad hvm info length\n");
560 BUG();
561 }
563 for ( i = 0; i < t->length; i++ )
564 sum += ptr[i];
566 if ( sum != 0 )
567 {
568 printf("Bad hvm info checksum\n");
569 BUG();
570 }
571 }
573 struct hvm_info_table *get_hvm_info_table(void)
574 {
575 static struct hvm_info_table *table;
576 struct hvm_info_table *t;
578 if ( table != NULL )
579 return table;
581 t = (struct hvm_info_table *)HVM_INFO_PADDR;
583 validate_hvm_info(t);
585 table = t;
587 return table;
588 }
590 uint16_t get_cpu_mhz(void)
591 {
592 struct xen_add_to_physmap xatp;
593 struct shared_info *shared_info = (struct shared_info *)0xfffff000;
594 struct vcpu_time_info *info = &shared_info->vcpu_info[0].time;
595 uint64_t cpu_khz;
596 uint32_t tsc_to_nsec_mul, version;
597 int8_t tsc_shift;
599 static uint16_t cpu_mhz;
600 if ( cpu_mhz != 0 )
601 return cpu_mhz;
603 /* Map shared-info page. */
604 xatp.domid = DOMID_SELF;
605 xatp.space = XENMAPSPACE_shared_info;
606 xatp.idx = 0;
607 xatp.gpfn = (unsigned long)shared_info >> 12;
608 if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
609 BUG();
611 /* Get a consistent snapshot of scale factor (multiplier and shift). */
612 do {
613 version = info->version;
614 rmb();
615 tsc_to_nsec_mul = info->tsc_to_system_mul;
616 tsc_shift = info->tsc_shift;
617 rmb();
618 } while ((version & 1) | (version ^ info->version));
620 /* Compute CPU speed in kHz. */
621 cpu_khz = 1000000ull << 32;
622 do_div(cpu_khz, tsc_to_nsec_mul);
623 if ( tsc_shift < 0 )
624 cpu_khz = cpu_khz << -tsc_shift;
625 else
626 cpu_khz = cpu_khz >> tsc_shift;
628 cpu_mhz = (uint16_t)(((uint32_t)cpu_khz + 500) / 1000);
629 return cpu_mhz;
630 }
632 int uart_exists(uint16_t uart_base)
633 {
634 uint16_t ier = uart_base + 1;
635 uint8_t a, b, c;
637 a = inb(ier);
638 outb(ier, 0);
639 b = inb(ier);
640 outb(ier, 0xf);
641 c = inb(ier);
642 outb(ier, a);
644 return ((b == 0) && (c == 0xf));
645 }
647 int hpet_exists(unsigned long hpet_base)
648 {
649 uint32_t hpet_id = *(uint32_t *)hpet_base;
650 return ((hpet_id >> 16) == 0x8086);
651 }
653 /*
654 * Local variables:
655 * mode: C
656 * c-set-style: "BSD"
657 * c-basic-offset: 4
658 * tab-width: 4
659 * indent-tabs-mode: nil
660 * End:
661 */