debuggers.hg

view tools/firmware/hvmloader/util.c @ 16961:4a92c68db1d2

firmware: Use new path to xen public headers.
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jan 28 12:03:02 2008 +0000 (2008-01-28)
parents feeca16435bf
children 69c951243105
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 <stdint.h>
25 #include <xen/hvm/hvm_info_table.h>
27 void outb(uint16_t addr, uint8_t val)
28 {
29 __asm__ __volatile__ ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
30 }
32 void outw(uint16_t addr, uint16_t val)
33 {
34 __asm__ __volatile__ ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
35 }
37 void outl(uint16_t addr, uint32_t val)
38 {
39 __asm__ __volatile__ ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
40 }
42 uint8_t inb(uint16_t addr)
43 {
44 uint8_t val;
45 __asm__ __volatile__ ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) );
46 return val;
47 }
49 uint16_t inw(uint16_t addr)
50 {
51 uint16_t val;
52 __asm__ __volatile__ ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) );
53 return val;
54 }
56 uint32_t inl(uint16_t addr)
57 {
58 uint32_t val;
59 __asm__ __volatile__ ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) );
60 return val;
61 }
63 uint8_t cmos_inb(uint8_t idx)
64 {
65 outb(0x70, idx);
66 return inb(0x71);
67 }
69 void cmos_outb(uint8_t idx, uint8_t val)
70 {
71 outb(0x70, idx);
72 outb(0x71, val);
73 }
75 char *itoa(char *a, unsigned int i)
76 {
77 unsigned int _i = i, x = 0;
79 do {
80 x++;
81 _i /= 10;
82 } while ( _i != 0 );
84 a += x;
85 *a-- = '\0';
87 do {
88 *a-- = (i % 10) + '0';
89 i /= 10;
90 } while ( i != 0 );
92 return a + 1;
93 }
95 int strcmp(const char *cs, const char *ct)
96 {
97 signed char res;
99 while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
100 continue;
102 return res;
103 }
105 int strncmp(const char *s1, const char *s2, uint32_t n)
106 {
107 uint32_t ctr;
108 for (ctr = 0; ctr < n; ctr++)
109 if (s1[ctr] != s2[ctr])
110 return (int)(s1[ctr] - s2[ctr]);
111 return 0;
112 }
114 void *memcpy(void *dest, const void *src, unsigned n)
115 {
116 int t0, t1, t2;
118 __asm__ __volatile__ (
119 "cld\n"
120 "rep; movsl\n"
121 "testb $2,%b4\n"
122 "je 1f\n"
123 "movsw\n"
124 "1: testb $1,%b4\n"
125 "je 2f\n"
126 "movsb\n"
127 "2:"
128 : "=&c" (t0), "=&D" (t1), "=&S" (t2)
129 : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
130 : "memory" );
131 return dest;
132 }
134 void *memmove(void *dest, const void *src, unsigned n)
135 {
136 if ( (unsigned long)dest > (unsigned long)src )
137 while ( n-- != 0 )
138 ((char *)dest)[n] = ((char *)src)[n];
139 else
140 memcpy(dest, src, n);
141 return dest;
142 }
144 char *
145 strcpy(char *dest, const char *src)
146 {
147 char *p = dest;
148 while ( *src )
149 *p++ = *src++;
150 *p = 0;
151 return dest;
152 }
154 char *
155 strncpy(char *dest, const char *src, unsigned n)
156 {
157 int i = 0;
158 char *p = dest;
160 /* write non-NUL characters from src into dest until we run
161 out of room in dest or encounter a NUL in src */
162 while ( (i < n) && *src )
163 {
164 *p++ = *src++;
165 i++;
166 }
168 /* pad remaining bytes of dest with NUL bytes */
169 while ( i < n )
170 {
171 *p++ = 0;
172 i++;
173 }
175 return dest;
176 }
178 unsigned
179 strlen(const char *s)
180 {
181 int i = 0;
182 while ( *s++ )
183 i++;
184 return i;
185 }
187 void *
188 memset(void *s, int c, unsigned n)
189 {
190 uint8_t b = (uint8_t) c;
191 uint8_t *p = (uint8_t *)s;
192 int i;
193 for ( i = 0; i < n; i++ )
194 *p++ = b;
195 return s;
196 }
198 int
199 memcmp(const void *s1, const void *s2, unsigned n)
200 {
201 unsigned i;
202 uint8_t *p1 = (uint8_t *) s1;
203 uint8_t *p2 = (uint8_t *) s2;
205 for ( i = 0; i < n; i++ )
206 {
207 if ( p1[i] < p2[i] )
208 return -1;
209 else if ( p1[i] > p2[i] )
210 return 1;
211 }
213 return 0;
214 }
216 void
217 cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
218 {
219 __asm__ __volatile__ (
220 "cpuid"
221 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
222 : "0" (idx) );
223 }
225 /* Write a two-character hex representation of 'byte' to digits[].
226 Pre-condition: sizeof(digits) >= 2 */
227 void
228 byte_to_hex(char *digits, uint8_t byte)
229 {
230 uint8_t nybbel = byte >> 4;
232 if ( nybbel > 9 )
233 digits[0] = 'a' + nybbel-10;
234 else
235 digits[0] = '0' + nybbel;
237 nybbel = byte & 0x0f;
238 if ( nybbel > 9 )
239 digits[1] = 'a' + nybbel-10;
240 else
241 digits[1] = '0' + nybbel;
242 }
244 /* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
245 string.
247 Pre-condition: sizeof(dest) >= 37 */
248 void
249 uuid_to_string(char *dest, uint8_t *uuid)
250 {
251 int i = 0;
252 char *p = dest;
254 for ( i = 0; i < 4; i++ )
255 {
256 byte_to_hex(p, uuid[i]);
257 p += 2;
258 }
259 *p++ = '-';
260 for ( i = 4; i < 6; i++ )
261 {
262 byte_to_hex(p, uuid[i]);
263 p += 2;
264 }
265 *p++ = '-';
266 for ( i = 6; i < 8; i++ )
267 {
268 byte_to_hex(p, uuid[i]);
269 p += 2;
270 }
271 *p++ = '-';
272 for ( i = 8; i < 10; i++ )
273 {
274 byte_to_hex(p, uuid[i]);
275 p += 2;
276 }
277 *p++ = '-';
278 for ( i = 10; i < 16; i++ )
279 {
280 byte_to_hex(p, uuid[i]);
281 p += 2;
282 }
283 *p = '\0';
284 }
286 static void e820_collapse(void)
287 {
288 int i = 0;
289 struct e820entry *ent = (struct e820entry *)HVM_E820;
291 while ( i < (*HVM_E820_NR-1) )
292 {
293 if ( (ent[i].type == ent[i+1].type) &&
294 ((ent[i].addr + ent[i].size) == ent[i+1].addr) )
295 {
296 ent[i].size += ent[i+1].size;
297 memcpy(&ent[i+1], &ent[i+2], (*HVM_E820_NR-i-2) * sizeof(*ent));
298 (*HVM_E820_NR)--;
299 }
300 else
301 {
302 i++;
303 }
304 }
305 }
307 uint32_t e820_malloc(uint32_t size)
308 {
309 uint32_t addr;
310 int i;
311 struct e820entry *ent = (struct e820entry *)HVM_E820;
313 /* Align allocation request to a reasonable boundary (1kB). */
314 size = (size + 1023) & ~1023;
316 for ( i = *HVM_E820_NR - 1; i >= 0; i-- )
317 {
318 addr = ent[i].addr;
319 if ( (ent[i].type != E820_RAM) || /* not ram? */
320 (ent[i].size < size) || /* too small? */
321 (addr != ent[i].addr) || /* starts above 4gb? */
322 ((addr + size) < addr) ) /* ends above 4gb? */
323 continue;
325 if ( ent[i].size != size )
326 {
327 memmove(&ent[i+1], &ent[i], (*HVM_E820_NR-i) * sizeof(*ent));
328 (*HVM_E820_NR)++;
329 ent[i].size -= size;
330 addr += ent[i].size;
331 i++;
332 }
334 ent[i].addr = addr;
335 ent[i].size = size;
336 ent[i].type = E820_RESERVED;
338 e820_collapse();
340 return addr;
341 }
343 return 0;
344 }
346 uint32_t ioapic_read(uint32_t reg)
347 {
348 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
349 return *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
350 }
352 void ioapic_write(uint32_t reg, uint32_t val)
353 {
354 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
355 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = val;
356 }
358 uint32_t lapic_read(uint32_t reg)
359 {
360 return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
361 }
363 void lapic_write(uint32_t reg, uint32_t val)
364 {
365 *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
366 }
368 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
369 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
371 uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
372 {
373 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
375 switch ( len )
376 {
377 case 1: return inb(0xcfc + (reg & 3));
378 case 2: return inw(0xcfc + (reg & 2));
379 }
381 return inl(0xcfc);
382 }
384 void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
385 {
386 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
388 switch ( len )
389 {
390 case 1: outb(0xcfc + (reg & 3), val); break;
391 case 2: outw(0xcfc + (reg & 2), val); break;
392 case 4: outl(0xcfc, val); break;
393 }
394 }
396 static char *printnum(char *p, unsigned long num, int base)
397 {
398 unsigned long n;
400 if ( (n = num/base) > 0 )
401 p = printnum(p, n, base);
402 *p++ = "0123456789abcdef"[(int)(num % base)];
403 *p = '\0';
404 return p;
405 }
407 static void _doprint(void (*put)(char), const char *fmt, va_list ap)
408 {
409 register char *str, c;
410 int lflag, zflag, nflag;
411 char buffer[17];
412 unsigned value;
413 int i, slen, pad;
415 for ( ; *fmt != '\0'; fmt++ )
416 {
417 if ( *fmt != '%' )
418 {
419 put(*fmt);
420 continue;
421 }
423 pad = zflag = nflag = lflag = 0;
424 c = *++fmt;
425 if ( (c == '-') || isdigit(c) )
426 {
427 if ( c == '-' )
428 {
429 nflag = 1;
430 c = *++fmt;
431 }
432 zflag = c == '0';
433 for ( pad = 0; isdigit(c); c = *++fmt )
434 pad = (pad * 10) + c - '0';
435 }
436 if ( c == 'l' ) /* long extension */
437 {
438 lflag = 1;
439 c = *++fmt;
440 }
441 if ( (c == 'd') || (c == 'u') || (c == 'o') || (c == 'x') )
442 {
443 if ( lflag )
444 value = va_arg(ap, unsigned);
445 else
446 value = (unsigned) va_arg(ap, unsigned int);
447 str = buffer;
448 printnum(str, value,
449 c == 'o' ? 8 : (c == 'x' ? 16 : 10));
450 goto printn;
451 }
452 else if ( (c == 'O') || (c == 'D') || (c == 'X') )
453 {
454 value = va_arg(ap, unsigned);
455 str = buffer;
456 printnum(str, value,
457 c == 'O' ? 8 : (c == 'X' ? 16 : 10));
458 printn:
459 slen = strlen(str);
460 for ( i = pad - slen; i > 0; i-- )
461 put(zflag ? '0' : ' ');
462 while ( *str )
463 put(*str++);
464 }
465 else if ( c == 's' )
466 {
467 str = va_arg(ap, char *);
468 slen = strlen(str);
469 if ( nflag == 0 )
470 for ( i = pad - slen; i > 0; i-- )
471 put(' ');
472 while ( *str )
473 put(*str++);
474 if ( nflag )
475 for ( i = pad - slen; i > 0; i-- )
476 put(' ');
477 }
478 else if ( c == 'c' )
479 {
480 put(va_arg(ap, int));
481 }
482 else
483 {
484 put(*fmt);
485 }
486 }
487 }
489 static void putchar(char c)
490 {
491 outb(0xe9, c);
492 }
494 int printf(const char *fmt, ...)
495 {
496 va_list ap;
498 va_start(ap, fmt);
499 _doprint(putchar, fmt, ap);
500 va_end(ap);
502 return 0;
503 }
505 int vprintf(const char *fmt, va_list ap)
506 {
507 _doprint(putchar, fmt, ap);
508 return 0;
509 }
511 void __assert_failed(char *assertion, char *file, int line)
512 {
513 printf("HVMLoader assertion '%s' failed at %s:%d\n",
514 assertion, file, line);
515 for ( ; ; )
516 __asm__ __volatile__ ( "ud2" );
517 }
519 void __bug(char *file, int line)
520 {
521 printf("HVMLoader bug at %s:%d\n", file, line);
522 for ( ; ; )
523 __asm__ __volatile__ ( "ud2" );
524 }
526 static int validate_hvm_info(struct hvm_info_table *t)
527 {
528 char signature[] = "HVM INFO";
529 uint8_t *ptr = (uint8_t *)t;
530 uint8_t sum = 0;
531 int i;
533 /* strncmp(t->signature, "HVM INFO", 8) */
534 for ( i = 0; i < 8; i++ )
535 {
536 if ( signature[i] != t->signature[i] )
537 {
538 printf("Bad hvm info signature\n");
539 return 0;
540 }
541 }
543 for ( i = 0; i < t->length; i++ )
544 sum += ptr[i];
546 return (sum == 0);
547 }
549 static struct hvm_info_table *get_hvm_info_table(void)
550 {
551 static struct hvm_info_table *table;
552 struct hvm_info_table *t;
554 if ( table != NULL )
555 return table;
557 t = (struct hvm_info_table *)HVM_INFO_PADDR;
559 if ( !validate_hvm_info(t) )
560 {
561 printf("Bad hvm info table\n");
562 return NULL;
563 }
565 table = t;
567 return table;
568 }
570 int get_vcpu_nr(void)
571 {
572 struct hvm_info_table *t = get_hvm_info_table();
573 return (t ? t->nr_vcpus : 1);
574 }
576 int get_acpi_enabled(void)
577 {
578 struct hvm_info_table *t = get_hvm_info_table();
579 return (t ? t->acpi_enabled : 1);
580 }
582 int get_apic_mode(void)
583 {
584 struct hvm_info_table *t = get_hvm_info_table();
585 return (t ? t->apic_mode : 1);
586 }
588 /*
589 * Local variables:
590 * mode: C
591 * c-set-style: "BSD"
592 * c-basic-offset: 4
593 * tab-width: 4
594 * indent-tabs-mode: nil
595 * End:
596 */