ia64/xen-unstable

view tools/firmware/hvmloader/util.c @ 17747:4c75850a0caa

hvmloader: No need to map shared_info page into the legacy VGA MMIO
hole. We can access address 0xfffff000 from 32-bit protected mode.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed May 28 10:02:00 2008 +0100 (2008-05-28)
parents a1112c23b202
children dade7f0bdc8d
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>
28 #include <xen/hvm/hvm_info_table.h>
30 void wrmsr(uint32_t idx, uint64_t v)
31 {
32 asm volatile (
33 "wrmsr"
34 : : "c" (idx), "a" ((uint32_t)v), "d" ((uint32_t)(v>>32)) );
35 }
37 uint64_t rdmsr(uint32_t idx)
38 {
39 uint32_t lo, hi;
41 asm volatile (
42 "rdmsr"
43 : "=a" (lo), "=d" (hi) : "c" (idx) );
45 return (lo | ((uint64_t)hi << 32));
46 }
48 void outb(uint16_t addr, uint8_t val)
49 {
50 asm volatile ( "outb %%al, %%dx" : : "d" (addr), "a" (val) );
51 }
53 void outw(uint16_t addr, uint16_t val)
54 {
55 asm volatile ( "outw %%ax, %%dx" : : "d" (addr), "a" (val) );
56 }
58 void outl(uint16_t addr, uint32_t val)
59 {
60 asm volatile ( "outl %%eax, %%dx" : : "d" (addr), "a" (val) );
61 }
63 uint8_t inb(uint16_t addr)
64 {
65 uint8_t val;
66 asm volatile ( "inb %%dx,%%al" : "=a" (val) : "d" (addr) );
67 return val;
68 }
70 uint16_t inw(uint16_t addr)
71 {
72 uint16_t val;
73 asm volatile ( "inw %%dx,%%ax" : "=a" (val) : "d" (addr) );
74 return val;
75 }
77 uint32_t inl(uint16_t addr)
78 {
79 uint32_t val;
80 asm volatile ( "inl %%dx,%%eax" : "=a" (val) : "d" (addr) );
81 return val;
82 }
84 uint8_t cmos_inb(uint8_t idx)
85 {
86 outb(0x70, idx);
87 return inb(0x71);
88 }
90 void cmos_outb(uint8_t idx, uint8_t val)
91 {
92 outb(0x70, idx);
93 outb(0x71, val);
94 }
96 char *itoa(char *a, unsigned int i)
97 {
98 unsigned int _i = i, x = 0;
100 do {
101 x++;
102 _i /= 10;
103 } while ( _i != 0 );
105 a += x;
106 *a-- = '\0';
108 do {
109 *a-- = (i % 10) + '0';
110 i /= 10;
111 } while ( i != 0 );
113 return a + 1;
114 }
116 int strcmp(const char *cs, const char *ct)
117 {
118 signed char res;
120 while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
121 continue;
123 return res;
124 }
126 int strncmp(const char *s1, const char *s2, uint32_t n)
127 {
128 uint32_t ctr;
129 for (ctr = 0; ctr < n; ctr++)
130 if (s1[ctr] != s2[ctr])
131 return (int)(s1[ctr] - s2[ctr]);
132 return 0;
133 }
135 void *memcpy(void *dest, const void *src, unsigned n)
136 {
137 int t0, t1, t2;
139 asm volatile (
140 "cld\n"
141 "rep; movsl\n"
142 "testb $2,%b4\n"
143 "je 1f\n"
144 "movsw\n"
145 "1: testb $1,%b4\n"
146 "je 2f\n"
147 "movsb\n"
148 "2:"
149 : "=&c" (t0), "=&D" (t1), "=&S" (t2)
150 : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
151 : "memory" );
152 return dest;
153 }
155 void *memmove(void *dest, const void *src, unsigned n)
156 {
157 if ( (unsigned long)dest > (unsigned long)src )
158 while ( n-- != 0 )
159 ((char *)dest)[n] = ((char *)src)[n];
160 else
161 memcpy(dest, src, n);
162 return dest;
163 }
165 char *
166 strcpy(char *dest, const char *src)
167 {
168 char *p = dest;
169 while ( *src )
170 *p++ = *src++;
171 *p = 0;
172 return dest;
173 }
175 char *
176 strncpy(char *dest, const char *src, unsigned n)
177 {
178 int i = 0;
179 char *p = dest;
181 /* write non-NUL characters from src into dest until we run
182 out of room in dest or encounter a NUL in src */
183 while ( (i < n) && *src )
184 {
185 *p++ = *src++;
186 i++;
187 }
189 /* pad remaining bytes of dest with NUL bytes */
190 while ( i < n )
191 {
192 *p++ = 0;
193 i++;
194 }
196 return dest;
197 }
199 unsigned
200 strlen(const char *s)
201 {
202 int i = 0;
203 while ( *s++ )
204 i++;
205 return i;
206 }
208 void *
209 memset(void *s, int c, unsigned n)
210 {
211 uint8_t b = (uint8_t) c;
212 uint8_t *p = (uint8_t *)s;
213 int i;
214 for ( i = 0; i < n; i++ )
215 *p++ = b;
216 return s;
217 }
219 int
220 memcmp(const void *s1, const void *s2, unsigned n)
221 {
222 unsigned i;
223 uint8_t *p1 = (uint8_t *) s1;
224 uint8_t *p2 = (uint8_t *) s2;
226 for ( i = 0; i < n; i++ )
227 {
228 if ( p1[i] < p2[i] )
229 return -1;
230 else if ( p1[i] > p2[i] )
231 return 1;
232 }
234 return 0;
235 }
237 void
238 cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
239 {
240 asm volatile (
241 "cpuid"
242 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
243 : "0" (idx) );
244 }
246 /* Write a two-character hex representation of 'byte' to digits[].
247 Pre-condition: sizeof(digits) >= 2 */
248 void
249 byte_to_hex(char *digits, uint8_t byte)
250 {
251 uint8_t nybbel = byte >> 4;
253 if ( nybbel > 9 )
254 digits[0] = 'a' + nybbel-10;
255 else
256 digits[0] = '0' + nybbel;
258 nybbel = byte & 0x0f;
259 if ( nybbel > 9 )
260 digits[1] = 'a' + nybbel-10;
261 else
262 digits[1] = '0' + nybbel;
263 }
265 /* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
266 string.
268 Pre-condition: sizeof(dest) >= 37 */
269 void
270 uuid_to_string(char *dest, uint8_t *uuid)
271 {
272 int i = 0;
273 char *p = dest;
275 for ( i = 0; i < 4; i++ )
276 {
277 byte_to_hex(p, uuid[i]);
278 p += 2;
279 }
280 *p++ = '-';
281 for ( i = 4; i < 6; i++ )
282 {
283 byte_to_hex(p, uuid[i]);
284 p += 2;
285 }
286 *p++ = '-';
287 for ( i = 6; i < 8; i++ )
288 {
289 byte_to_hex(p, uuid[i]);
290 p += 2;
291 }
292 *p++ = '-';
293 for ( i = 8; i < 10; i++ )
294 {
295 byte_to_hex(p, uuid[i]);
296 p += 2;
297 }
298 *p++ = '-';
299 for ( i = 10; i < 16; i++ )
300 {
301 byte_to_hex(p, uuid[i]);
302 p += 2;
303 }
304 *p = '\0';
305 }
307 static void e820_collapse(void)
308 {
309 int i = 0;
310 struct e820entry *ent = (struct e820entry *)HVM_E820;
312 while ( i < (*HVM_E820_NR-1) )
313 {
314 if ( (ent[i].type == ent[i+1].type) &&
315 ((ent[i].addr + ent[i].size) == ent[i+1].addr) )
316 {
317 ent[i].size += ent[i+1].size;
318 memcpy(&ent[i+1], &ent[i+2], (*HVM_E820_NR-i-2) * sizeof(*ent));
319 (*HVM_E820_NR)--;
320 }
321 else
322 {
323 i++;
324 }
325 }
326 }
328 uint32_t e820_malloc(uint32_t size)
329 {
330 uint32_t addr;
331 int i;
332 struct e820entry *ent = (struct e820entry *)HVM_E820;
334 /* Align allocation request to a reasonable boundary (1kB). */
335 size = (size + 1023) & ~1023;
337 for ( i = *HVM_E820_NR - 1; i >= 0; i-- )
338 {
339 addr = ent[i].addr;
340 if ( (ent[i].type != E820_RAM) || /* not ram? */
341 (ent[i].size < size) || /* too small? */
342 (addr != ent[i].addr) || /* starts above 4gb? */
343 ((addr + size) < addr) ) /* ends above 4gb? */
344 continue;
346 if ( ent[i].size != size )
347 {
348 memmove(&ent[i+1], &ent[i], (*HVM_E820_NR-i) * sizeof(*ent));
349 (*HVM_E820_NR)++;
350 ent[i].size -= size;
351 addr += ent[i].size;
352 i++;
353 }
355 ent[i].addr = addr;
356 ent[i].size = size;
357 ent[i].type = E820_RESERVED;
359 e820_collapse();
361 return addr;
362 }
364 return 0;
365 }
367 uint32_t ioapic_read(uint32_t reg)
368 {
369 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
370 return *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10);
371 }
373 void ioapic_write(uint32_t reg, uint32_t val)
374 {
375 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x00) = reg;
376 *(volatile uint32_t *)(IOAPIC_BASE_ADDRESS + 0x10) = val;
377 }
379 uint32_t lapic_read(uint32_t reg)
380 {
381 return *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg);
382 }
384 void lapic_write(uint32_t reg, uint32_t val)
385 {
386 *(volatile uint32_t *)(LAPIC_BASE_ADDRESS + reg) = val;
387 }
389 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
390 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
392 uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
393 {
394 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
396 switch ( len )
397 {
398 case 1: return inb(0xcfc + (reg & 3));
399 case 2: return inw(0xcfc + (reg & 2));
400 }
402 return inl(0xcfc);
403 }
405 void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
406 {
407 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
409 switch ( len )
410 {
411 case 1: outb(0xcfc + (reg & 3), val); break;
412 case 2: outw(0xcfc + (reg & 2), val); break;
413 case 4: outl(0xcfc, val); break;
414 }
415 }
417 static char *printnum(char *p, unsigned long num, int base)
418 {
419 unsigned long n;
421 if ( (n = num/base) > 0 )
422 p = printnum(p, n, base);
423 *p++ = "0123456789abcdef"[(int)(num % base)];
424 *p = '\0';
425 return p;
426 }
428 static void _doprint(void (*put)(char), const char *fmt, va_list ap)
429 {
430 register char *str, c;
431 int lflag, zflag, nflag;
432 char buffer[17];
433 unsigned value;
434 int i, slen, pad;
436 for ( ; *fmt != '\0'; fmt++ )
437 {
438 if ( *fmt != '%' )
439 {
440 put(*fmt);
441 continue;
442 }
444 pad = zflag = nflag = lflag = 0;
445 c = *++fmt;
446 if ( (c == '-') || isdigit(c) )
447 {
448 if ( c == '-' )
449 {
450 nflag = 1;
451 c = *++fmt;
452 }
453 zflag = c == '0';
454 for ( pad = 0; isdigit(c); c = *++fmt )
455 pad = (pad * 10) + c - '0';
456 }
457 if ( c == 'l' ) /* long extension */
458 {
459 lflag = 1;
460 c = *++fmt;
461 }
462 if ( (c == 'd') || (c == 'u') || (c == 'o') || (c == 'x') )
463 {
464 if ( lflag )
465 value = va_arg(ap, unsigned);
466 else
467 value = (unsigned) va_arg(ap, unsigned int);
468 str = buffer;
469 printnum(str, value,
470 c == 'o' ? 8 : (c == 'x' ? 16 : 10));
471 goto printn;
472 }
473 else if ( (c == 'O') || (c == 'D') || (c == 'X') )
474 {
475 value = va_arg(ap, unsigned);
476 str = buffer;
477 printnum(str, value,
478 c == 'O' ? 8 : (c == 'X' ? 16 : 10));
479 printn:
480 slen = strlen(str);
481 for ( i = pad - slen; i > 0; i-- )
482 put(zflag ? '0' : ' ');
483 while ( *str )
484 put(*str++);
485 }
486 else if ( c == 's' )
487 {
488 str = va_arg(ap, char *);
489 slen = strlen(str);
490 if ( nflag == 0 )
491 for ( i = pad - slen; i > 0; i-- )
492 put(' ');
493 while ( *str )
494 put(*str++);
495 if ( nflag )
496 for ( i = pad - slen; i > 0; i-- )
497 put(' ');
498 }
499 else if ( c == 'c' )
500 {
501 put(va_arg(ap, int));
502 }
503 else
504 {
505 put(*fmt);
506 }
507 }
508 }
510 static void putchar(char c)
511 {
512 outb(0xe9, c);
513 }
515 int printf(const char *fmt, ...)
516 {
517 va_list ap;
519 va_start(ap, fmt);
520 _doprint(putchar, fmt, ap);
521 va_end(ap);
523 return 0;
524 }
526 int vprintf(const char *fmt, va_list ap)
527 {
528 _doprint(putchar, fmt, ap);
529 return 0;
530 }
532 void __assert_failed(char *assertion, char *file, int line)
533 {
534 printf("HVMLoader assertion '%s' failed at %s:%d\n",
535 assertion, file, line);
536 for ( ; ; )
537 asm volatile ( "ud2" );
538 }
540 void __bug(char *file, int line)
541 {
542 printf("HVMLoader bug at %s:%d\n", file, line);
543 for ( ; ; )
544 asm volatile ( "ud2" );
545 }
547 static int validate_hvm_info(struct hvm_info_table *t)
548 {
549 char signature[] = "HVM INFO";
550 uint8_t *ptr = (uint8_t *)t;
551 uint8_t sum = 0;
552 int i;
554 /* strncmp(t->signature, "HVM INFO", 8) */
555 for ( i = 0; i < 8; i++ )
556 {
557 if ( signature[i] != t->signature[i] )
558 {
559 printf("Bad hvm info signature\n");
560 return 0;
561 }
562 }
564 for ( i = 0; i < t->length; i++ )
565 sum += ptr[i];
567 return (sum == 0);
568 }
570 static struct hvm_info_table *get_hvm_info_table(void)
571 {
572 static struct hvm_info_table *table;
573 struct hvm_info_table *t;
575 if ( table != NULL )
576 return table;
578 t = (struct hvm_info_table *)HVM_INFO_PADDR;
580 if ( !validate_hvm_info(t) )
581 {
582 printf("Bad hvm info table\n");
583 return NULL;
584 }
586 table = t;
588 return table;
589 }
591 int get_vcpu_nr(void)
592 {
593 struct hvm_info_table *t = get_hvm_info_table();
594 return (t ? t->nr_vcpus : 1);
595 }
597 int get_acpi_enabled(void)
598 {
599 struct hvm_info_table *t = get_hvm_info_table();
600 return (t ? t->acpi_enabled : 1);
601 }
603 int get_apic_mode(void)
604 {
605 struct hvm_info_table *t = get_hvm_info_table();
606 return (t ? t->apic_mode : 1);
607 }
609 uint16_t get_cpu_mhz(void)
610 {
611 struct xen_add_to_physmap xatp;
612 struct shared_info *shared_info = (struct shared_info *)0xfffff000;
613 struct vcpu_time_info *info = &shared_info->vcpu_info[0].time;
614 uint64_t cpu_khz;
615 uint32_t tsc_to_nsec_mul, version;
616 int8_t tsc_shift;
618 static uint16_t cpu_mhz;
619 if ( cpu_mhz != 0 )
620 return cpu_mhz;
622 /* Map shared-info page. */
623 xatp.domid = DOMID_SELF;
624 xatp.space = XENMAPSPACE_shared_info;
625 xatp.idx = 0;
626 xatp.gpfn = (unsigned long)shared_info >> 12;
627 if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
628 BUG();
630 /* Get a consistent snapshot of scale factor (multiplier and shift). */
631 do {
632 version = info->version;
633 rmb();
634 tsc_to_nsec_mul = info->tsc_to_system_mul;
635 tsc_shift = info->tsc_shift;
636 rmb();
637 } while ((version & 1) | (version ^ info->version));
639 /* Compute CPU speed in kHz. */
640 cpu_khz = 1000000ull << 32;
641 do_div(cpu_khz, tsc_to_nsec_mul);
642 if ( tsc_shift < 0 )
643 cpu_khz = cpu_khz << -tsc_shift;
644 else
645 cpu_khz = cpu_khz >> tsc_shift;
647 cpu_mhz = (uint16_t)(((uint32_t)cpu_khz + 500) / 1000);
648 return cpu_mhz;
649 }
651 /*
652 * Local variables:
653 * mode: C
654 * c-set-style: "BSD"
655 * c-basic-offset: 4
656 * tab-width: 4
657 * indent-tabs-mode: nil
658 * End:
659 */