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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "util.h"
21 #include "config.h"
22 #include "hypercall.h"
23 #include "ctype.h"
24 #include "vnuma.h"
25 #include <acpi2_0.h>
26 #include <libacpi.h>
27 #include <stdint.h>
28 #include <xen/xen.h>
29 #include <xen/memory.h>
30 #include <xen/sched.h>
31 #include <xen/hvm/hvm_xs_strings.h>
32 #include <xen/hvm/params.h>
33
34 /*
35 * Check whether there exists overlap in the specified memory range.
36 * Returns true if exists, else returns false.
37 */
check_overlap(uint64_t start,uint64_t size,uint64_t reserved_start,uint64_t reserved_size)38 bool check_overlap(uint64_t start, uint64_t size,
39 uint64_t reserved_start, uint64_t reserved_size)
40 {
41 return (start + size > reserved_start) &&
42 (start < reserved_start + reserved_size);
43 }
44
cmos_inb(uint8_t idx)45 uint8_t cmos_inb(uint8_t idx)
46 {
47 outb(0x70, idx);
48 return inb(0x71);
49 }
50
cmos_outb(uint8_t idx,uint8_t val)51 void cmos_outb(uint8_t idx, uint8_t val)
52 {
53 outb(0x70, idx);
54 outb(0x71, val);
55 }
56
itoa(char * a,unsigned int i)57 char *itoa(char *a, unsigned int i)
58 {
59 unsigned int _i = i, x = 0;
60
61 do {
62 x++;
63 _i /= 10;
64 } while ( _i != 0 );
65
66 a += x;
67 *a-- = '\0';
68
69 do {
70 *a-- = (i % 10) + '0';
71 i /= 10;
72 } while ( i != 0 );
73
74 return a + 1;
75 }
76
strcmp(const char * cs,const char * ct)77 int strcmp(const char *cs, const char *ct)
78 {
79 signed char res;
80
81 while ( ((res = *cs - *ct++) == 0) && (*cs++ != '\0') )
82 continue;
83
84 return res;
85 }
86
strncmp(const char * s1,const char * s2,uint32_t n)87 int strncmp(const char *s1, const char *s2, uint32_t n)
88 {
89 uint32_t ctr;
90 for (ctr = 0; ctr < n; ctr++)
91 if (s1[ctr] != s2[ctr])
92 return (int)(s1[ctr] - s2[ctr]);
93 return 0;
94 }
95
memcpy(void * dest,const void * src,unsigned n)96 void *memcpy(void *dest, const void *src, unsigned n)
97 {
98 int t0, t1, t2;
99
100 asm volatile (
101 "cld\n"
102 "rep; movsl\n"
103 "testb $2,%b4\n"
104 "je 1f\n"
105 "movsw\n"
106 "1: testb $1,%b4\n"
107 "je 2f\n"
108 "movsb\n"
109 "2:"
110 : "=&c" (t0), "=&D" (t1), "=&S" (t2)
111 : "0" (n/4), "q" (n), "1" ((long) dest), "2" ((long) src)
112 : "memory" );
113 return dest;
114 }
115
memmove(void * dest,const void * src,unsigned n)116 void *memmove(void *dest, const void *src, unsigned n)
117 {
118 if ( (unsigned long)dest > (unsigned long)src )
119 while ( n-- != 0 )
120 ((char *)dest)[n] = ((char *)src)[n];
121 else
122 memcpy(dest, src, n);
123 return dest;
124 }
125
126 char *
strcpy(char * dest,const char * src)127 strcpy(char *dest, const char *src)
128 {
129 char *p = dest;
130 while ( *src )
131 *p++ = *src++;
132 *p = 0;
133 return dest;
134 }
135
136 char *
strncpy(char * dest,const char * src,unsigned n)137 strncpy(char *dest, const char *src, unsigned n)
138 {
139 int i = 0;
140 char *p = dest;
141
142 /* write non-NUL characters from src into dest until we run
143 out of room in dest or encounter a NUL in src */
144 while ( (i < n) && *src )
145 {
146 *p++ = *src++;
147 i++;
148 }
149
150 /* pad remaining bytes of dest with NUL bytes */
151 while ( i < n )
152 {
153 *p++ = 0;
154 i++;
155 }
156
157 return dest;
158 }
159
160 unsigned
strlen(const char * s)161 strlen(const char *s)
162 {
163 int i = 0;
164 while ( *s++ )
165 i++;
166 return i;
167 }
168
__digit(char c,int base)169 static inline int __digit(char c, int base)
170 {
171 int d = -1;
172
173 if ( (c >= '0') && (c <= '9') )
174 d = c - '0';
175
176 if ( (c >= 'A') && (c <= 'Z') )
177 d = c - 'A' + 10;
178
179 if ( (c >= 'a') && (c <= 'z') )
180 d = c - 'a' + 10;
181
182 if (d >= base)
183 d = -1;
184
185 return d;
186 }
187
188 long long
strtoll(const char * s,char ** end,int base)189 strtoll(const char *s, char **end, int base)
190 {
191 long long v = 0;
192 int sign = 1;
193
194 while ( (*s != '\0') && isspace(*s) )
195 s++;
196
197 if ( *s == '\0' ) goto out;
198
199 if ( *s == '-' ) {
200 sign = -1;
201 s++;
202 } else {
203 if ( *s == '+' )
204 s++;
205 }
206
207 if ( *s == '\0' ) goto out;
208
209 if ( *s == '0' ) {
210 s++;
211 if ( *s == '\0' ) goto out;
212
213 if ( *s == 'x' ) {
214 if ( base != 0 && base != 16) goto out;
215 base = 16;
216 s++;
217 } else {
218 if ( base != 0 && base != 8) goto out;
219 base = 8;
220 }
221 } else {
222 if (base != 0 && base != 10) goto out;
223 base = 10;
224 }
225
226 while ( *s != '\0' ) {
227 int d = __digit(*s, base);
228
229 if ( d < 0 ) goto out;
230
231 v = (v * base) + d;
232 s++;
233 }
234
235 out:
236 if (end) *end = (char *)s;
237
238 return sign * v;
239 }
240
241 void *
memset(void * s,int c,unsigned n)242 memset(void *s, int c, unsigned n)
243 {
244 uint8_t b = (uint8_t) c;
245 uint8_t *p = (uint8_t *)s;
246 int i;
247 for ( i = 0; i < n; i++ )
248 *p++ = b;
249 return s;
250 }
251
252 int
memcmp(const void * s1,const void * s2,unsigned n)253 memcmp(const void *s1, const void *s2, unsigned n)
254 {
255 unsigned i;
256 uint8_t *p1 = (uint8_t *) s1;
257 uint8_t *p2 = (uint8_t *) s2;
258
259 for ( i = 0; i < n; i++ )
260 {
261 if ( p1[i] < p2[i] )
262 return -1;
263 else if ( p1[i] > p2[i] )
264 return 1;
265 }
266
267 return 0;
268 }
269
270 void
cpuid(uint32_t idx,uint32_t * eax,uint32_t * ebx,uint32_t * ecx,uint32_t * edx)271 cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
272 {
273 asm volatile (
274 "cpuid"
275 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
276 : "0" (idx) );
277 }
278
279 static const char hex_digits[] = "0123456789abcdef";
280
281 /* Write a two-character hex representation of 'byte' to digits[].
282 Pre-condition: sizeof(digits) >= 2 */
283 void
byte_to_hex(char * digits,uint8_t byte)284 byte_to_hex(char *digits, uint8_t byte)
285 {
286 digits[0] = hex_digits[byte >> 4];
287 digits[1] = hex_digits[byte & 0x0f];
288 }
289
290 /* Convert an array of 16 unsigned bytes to a DCE/OSF formatted UUID
291 string.
292
293 Pre-condition: sizeof(dest) >= 37 */
294 void
uuid_to_string(char * dest,uint8_t * uuid)295 uuid_to_string(char *dest, uint8_t *uuid)
296 {
297 int i = 0;
298 char *p = dest;
299
300 for ( i = 0; i < 4; i++ )
301 {
302 byte_to_hex(p, uuid[i]);
303 p += 2;
304 }
305 *p++ = '-';
306 for ( i = 4; i < 6; i++ )
307 {
308 byte_to_hex(p, uuid[i]);
309 p += 2;
310 }
311 *p++ = '-';
312 for ( i = 6; i < 8; i++ )
313 {
314 byte_to_hex(p, uuid[i]);
315 p += 2;
316 }
317 *p++ = '-';
318 for ( i = 8; i < 10; i++ )
319 {
320 byte_to_hex(p, uuid[i]);
321 p += 2;
322 }
323 *p++ = '-';
324 for ( i = 10; i < 16; i++ )
325 {
326 byte_to_hex(p, uuid[i]);
327 p += 2;
328 }
329 *p = '\0';
330 }
331
get_mem_mapping_layout(struct e820entry entries[],uint32_t * max_entries)332 int get_mem_mapping_layout(struct e820entry entries[], uint32_t *max_entries)
333 {
334 int rc;
335 struct xen_memory_map memmap = {
336 .nr_entries = *max_entries
337 };
338
339 set_xen_guest_handle(memmap.buffer, entries);
340
341 rc = hypercall_memory_op(XENMEM_memory_map, &memmap);
342 *max_entries = memmap.nr_entries;
343
344 return rc;
345 }
346
mem_hole_populate_ram(xen_pfn_t mfn,uint32_t nr_mfns)347 void mem_hole_populate_ram(xen_pfn_t mfn, uint32_t nr_mfns)
348 {
349 static int over_allocated;
350 struct xen_add_to_physmap xatp;
351 struct xen_memory_reservation xmr;
352
353 for ( ; nr_mfns-- != 0; mfn++ )
354 {
355 /* Try to allocate a brand new page in the reserved area. */
356 if ( !over_allocated )
357 {
358 xmr.domid = DOMID_SELF;
359 xmr.mem_flags = 0;
360 xmr.extent_order = 0;
361 xmr.nr_extents = 1;
362 set_xen_guest_handle(xmr.extent_start, &mfn);
363 if ( hypercall_memory_op(XENMEM_populate_physmap, &xmr) == 1 )
364 continue;
365 over_allocated = 1;
366 }
367
368 /* Otherwise, relocate a page from the ordinary RAM map. */
369 if ( hvm_info->high_mem_pgend )
370 {
371 xatp.idx = --hvm_info->high_mem_pgend;
372 if ( xatp.idx == (1ull << (32 - PAGE_SHIFT)) )
373 hvm_info->high_mem_pgend = 0;
374 }
375 else
376 {
377 xatp.idx = --hvm_info->low_mem_pgend;
378 }
379 xatp.domid = DOMID_SELF;
380 xatp.space = XENMAPSPACE_gmfn;
381 xatp.gpfn = mfn;
382 if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
383 BUG();
384 }
385
386 /* Sync memory map[]. */
387 adjust_memory_map();
388 }
389
390 static uint32_t alloc_up = RESERVED_MEMORY_DYNAMIC_START - 1;
391 static uint32_t alloc_down = RESERVED_MEMORY_DYNAMIC_END;
392
mem_hole_alloc(uint32_t nr_mfns)393 xen_pfn_t mem_hole_alloc(uint32_t nr_mfns)
394 {
395 alloc_down -= nr_mfns << PAGE_SHIFT;
396 BUG_ON(alloc_up >= alloc_down);
397 return alloc_down >> PAGE_SHIFT;
398 }
399
mem_alloc(uint32_t size,uint32_t align)400 void *mem_alloc(uint32_t size, uint32_t align)
401 {
402 uint32_t s, e;
403
404 /* Align to at least 16 bytes. */
405 if ( align < 16 )
406 align = 16;
407
408 s = (alloc_up + align) & ~(align - 1);
409 e = s + size - 1;
410
411 BUG_ON((e < s) || (e >= alloc_down));
412
413 while ( (alloc_up >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
414 {
415 alloc_up += PAGE_SIZE;
416 mem_hole_populate_ram(alloc_up >> PAGE_SHIFT, 1);
417 }
418
419 alloc_up = e;
420
421 return (void *)(unsigned long)s;
422 }
423
scratch_alloc(uint32_t size,uint32_t align)424 void *scratch_alloc(uint32_t size, uint32_t align)
425 {
426 uint32_t s, e;
427
428 /* Align to at least 16 bytes. */
429 if ( align < 16 )
430 align = 16;
431
432 s = (scratch_start + align) & ~(align - 1);
433 e = s + size - 1;
434
435 BUG_ON(e < s);
436
437 scratch_start = e;
438
439 return (void *)(unsigned long)s;
440 }
441
442 #define PCI_CONF1_ADDRESS(bus, devfn, reg) \
443 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
444
pci_read(uint32_t devfn,uint32_t reg,uint32_t len)445 uint32_t pci_read(uint32_t devfn, uint32_t reg, uint32_t len)
446 {
447 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
448
449 switch ( len )
450 {
451 case 1: return inb(0xcfc + (reg & 3));
452 case 2: return inw(0xcfc + (reg & 2));
453 }
454
455 return inl(0xcfc);
456 }
457
pci_write(uint32_t devfn,uint32_t reg,uint32_t len,uint32_t val)458 void pci_write(uint32_t devfn, uint32_t reg, uint32_t len, uint32_t val)
459 {
460 outl(0xcf8, PCI_CONF1_ADDRESS(0, devfn, reg));
461
462 switch ( len )
463 {
464 case 1: outb(0xcfc + (reg & 3), val); break;
465 case 2: outw(0xcfc + (reg & 2), val); break;
466 case 4: outl(0xcfc, val); break;
467 }
468 }
469
printnum(char * p,unsigned long num,unsigned base)470 static char *printnum(char *p, unsigned long num, unsigned base)
471 {
472 unsigned long n;
473
474 if ( (n = num/base) > 0 )
475 p = printnum(p, n, base);
476 *p++ = hex_digits[num % base];
477 *p = '\0';
478 return p;
479 }
480
_doprint(void (* emit)(void *,char),void * arg,const char * fmt,va_list ap)481 static void _doprint(void (*emit)(void *, char), void *arg, const char *fmt, va_list ap)
482 {
483 char *str, c;
484 int lflag, zflag, nflag;
485 char buffer[17];
486 unsigned long value;
487 int i, slen, pad;
488
489 for ( ; *fmt != '\0'; fmt++ )
490 {
491 if ( *fmt != '%' )
492 {
493 emit(arg, *fmt);
494 continue;
495 }
496
497 pad = zflag = nflag = lflag = 0;
498 c = *++fmt;
499 if ( (c == '-') || isdigit(c) )
500 {
501 if ( c == '-' )
502 {
503 nflag = 1;
504 c = *++fmt;
505 }
506 zflag = c == '0';
507 for ( pad = 0; isdigit(c); c = *++fmt )
508 pad = (pad * 10) + c - '0';
509 }
510 if ( c == 'l' ) /* long extension */
511 {
512 lflag = 1;
513 c = *++fmt;
514 }
515 if ( (c == 'd') || (c == 'u') || (c == 'o') ||
516 (c == 'x') || (c == 'X') )
517 {
518 if ( lflag )
519 {
520 value = va_arg(ap, unsigned long);
521 if ( (c == 'd') && ((long)value < 0) )
522 {
523 value = -value;
524 emit(arg, '-');
525 }
526 }
527 else
528 {
529 value = va_arg(ap, unsigned int);
530 if ( (c == 'd') && ((int)value < 0) )
531 {
532 value = -(int)value;
533 emit(arg, '-');
534 }
535 }
536 str = buffer;
537 printnum(str, value,
538 c == 'o' ? 8 : ((c == 'x') || (c == 'X') ? 16 : 10));
539 slen = strlen(str);
540 for ( i = pad - slen; i > 0; i-- )
541 emit(arg, zflag ? '0' : ' ');
542 while ( *str )
543 {
544 char ch = *str++;
545 if ( (ch >= 'a') && (c == 'X') )
546 ch += 'A'-'a';
547 emit(arg, ch);
548 }
549 }
550 else if ( c == 's' )
551 {
552 str = va_arg(ap, char *);
553 slen = strlen(str);
554 if ( nflag == 0 )
555 for ( i = pad - slen; i > 0; i-- )
556 emit(arg, ' ');
557 while ( *str )
558 emit(arg, *str++);
559 if ( nflag )
560 for ( i = pad - slen; i > 0; i-- )
561 emit(arg, ' ');
562 }
563 else if ( c == 'c' )
564 {
565 emit(arg, va_arg(ap, int));
566 }
567 else
568 {
569 emit(arg, *fmt);
570 }
571 }
572 }
573
putchar(char c)574 static void putchar(char c)
575 {
576 outb(0xe9, c);
577 }
578
__put(void * arg,char c)579 static void __put(void *arg, char c)
580 {
581 putchar(c);
582 }
583
printf(const char * fmt,...)584 int printf(const char *fmt, ...)
585 {
586 va_list ap;
587
588 va_start(ap, fmt);
589 _doprint(__put, NULL, fmt, ap);
590 va_end(ap);
591
592 return 0;
593 }
594
vprintf(const char * fmt,va_list ap)595 int vprintf(const char *fmt, va_list ap)
596 {
597 _doprint(__put, NULL, fmt, ap);
598 return 0;
599 }
600
601 struct __copy_context {
602 char *ptr;
603 size_t emitted;
604 size_t remaining;
605 };
606
__copy(void * arg,char c)607 static void __copy(void *arg, char c)
608 {
609 struct __copy_context *ctxt = arg;
610
611 ctxt->emitted++;
612
613 if (ctxt->remaining == 0)
614 return;
615
616 *(ctxt->ptr++) = c;
617 --ctxt->remaining;
618 }
619
snprintf(char * buf,size_t size,const char * fmt,...)620 int snprintf(char *buf, size_t size, const char *fmt, ...)
621 {
622 va_list ap;
623 struct __copy_context ctxt;
624
625 ctxt.ptr = buf;
626 ctxt.emitted = 0;
627 ctxt.remaining = size;
628
629 va_start(ap, fmt);
630 _doprint(__copy, &ctxt, fmt, ap);
631 va_end(ap);
632
633 if (ctxt.remaining != 0)
634 *ctxt.ptr = '\0';
635
636 return ctxt.emitted;
637 }
638
crash(void)639 static void __attribute__((noreturn)) crash(void)
640 {
641 struct sched_shutdown shutdown = { .reason = SHUTDOWN_crash };
642 printf("*** HVMLoader crashed.\n");
643 hypercall_sched_op(SCHEDOP_shutdown, &shutdown);
644 printf("*** Failed to crash. Halting.\n");
645 for ( ; ; )
646 asm volatile ( "hlt" );
647 }
648
__assert_failed(const char * assertion,const char * file,int line)649 void __assert_failed(const char *assertion, const char *file, int line)
650 {
651 printf("*** HVMLoader assertion '%s' failed at %s:%d\n",
652 assertion, file, line);
653 crash();
654 }
655
__bug(const char * file,int line)656 void __bug(const char *file, int line)
657 {
658 printf("*** HVMLoader bug at %s:%d\n", file, line);
659 crash();
660 }
661
validate_hvm_info(struct hvm_info_table * t)662 static void validate_hvm_info(struct hvm_info_table *t)
663 {
664 uint8_t *ptr = (uint8_t *)t;
665 uint8_t sum = 0;
666 int i;
667
668 if ( strncmp(t->signature, "HVM INFO", 8) )
669 {
670 printf("Bad hvm info signature\n");
671 BUG();
672 }
673
674 if ( t->length < sizeof(struct hvm_info_table) )
675 {
676 printf("Bad hvm info length\n");
677 BUG();
678 }
679
680 for ( i = 0; i < t->length; i++ )
681 sum += ptr[i];
682
683 if ( sum != 0 )
684 {
685 printf("Bad hvm info checksum\n");
686 BUG();
687 }
688 }
689
get_hvm_info_table(void)690 struct hvm_info_table *get_hvm_info_table(void)
691 {
692 static struct hvm_info_table *table;
693 struct hvm_info_table *t;
694
695 if ( table != NULL )
696 return table;
697
698 t = (struct hvm_info_table *)HVM_INFO_PADDR;
699
700 validate_hvm_info(t);
701
702 table = t;
703
704 return table;
705 }
706
get_shared_info(void)707 struct shared_info *get_shared_info(void)
708 {
709 static struct shared_info *shared_info = NULL;
710 struct xen_add_to_physmap xatp;
711
712 if ( shared_info != NULL )
713 return shared_info;
714
715 xatp.domid = DOMID_SELF;
716 xatp.space = XENMAPSPACE_shared_info;
717 xatp.idx = 0;
718 xatp.gpfn = mem_hole_alloc(1);
719 shared_info = (struct shared_info *)(xatp.gpfn << PAGE_SHIFT);
720 if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
721 BUG();
722
723 return shared_info;
724 }
725
get_cpu_mhz(void)726 uint16_t get_cpu_mhz(void)
727 {
728 struct shared_info *shared_info = get_shared_info();
729 struct vcpu_time_info *info = &shared_info->vcpu_info[0].time;
730 uint64_t cpu_khz;
731 uint32_t tsc_to_nsec_mul, version;
732 int8_t tsc_shift;
733
734 static uint16_t cpu_mhz;
735 if ( cpu_mhz != 0 )
736 return cpu_mhz;
737
738 /* Get a consistent snapshot of scale factor (multiplier and shift). */
739 do {
740 version = info->version;
741 rmb();
742 tsc_to_nsec_mul = info->tsc_to_system_mul;
743 tsc_shift = info->tsc_shift;
744 rmb();
745 } while ((version & 1) | (version ^ info->version));
746
747 /* Compute CPU speed in kHz. */
748 cpu_khz = 1000000ull << 32;
749 do_div(cpu_khz, tsc_to_nsec_mul);
750 if ( tsc_shift < 0 )
751 cpu_khz = cpu_khz << -tsc_shift;
752 else
753 cpu_khz = cpu_khz >> tsc_shift;
754
755 cpu_mhz = (uint16_t)(((uint32_t)cpu_khz + 500) / 1000);
756 return cpu_mhz;
757 }
758
uart_exists(uint16_t uart_base)759 int uart_exists(uint16_t uart_base)
760 {
761 uint16_t ier = uart_base + 1;
762 uint8_t a, b, c;
763
764 a = inb(ier);
765 outb(ier, 0);
766 b = inb(ier);
767 outb(ier, 0xf);
768 c = inb(ier);
769 outb(ier, a);
770
771 return ((b == 0) && (c == 0xf));
772 }
773
lpt_exists(uint16_t lpt_base)774 int lpt_exists(uint16_t lpt_base)
775 {
776 /* Idea taken from linux-2.6.31.5:parport_pc.c */
777 uint16_t control = lpt_base + 2;
778 outb(control, 0xc);
779 return ((inb(control) & 0xf) == 0xc);
780 }
781
hpet_exists(unsigned long hpet_base)782 int hpet_exists(unsigned long hpet_base)
783 {
784 uint32_t hpet_id = *(uint32_t *)hpet_base;
785 return ((hpet_id >> 16) == 0x8086);
786 }
787
battery_port_exists(void)788 static uint8_t battery_port_exists(void)
789 {
790 return (inb(0x88) == 0x1F);
791 }
792
acpi_v2p(struct acpi_ctxt * ctxt,void * v)793 static unsigned long acpi_v2p(struct acpi_ctxt *ctxt, void *v)
794 {
795 return virt_to_phys(v);
796 }
797
798 static unsigned long acpi_alloc_up = ACPI_MEMORY_DYNAMIC_START - 1;
799
acpi_pages_allocated(void)800 unsigned long acpi_pages_allocated(void)
801 {
802 return (acpi_alloc_up >> PAGE_SHIFT) -
803 ((ACPI_MEMORY_DYNAMIC_START - 1) >> PAGE_SHIFT);
804 }
805
acpi_mem_alloc(struct acpi_ctxt * ctxt,uint32_t size,uint32_t align)806 static void *acpi_mem_alloc(struct acpi_ctxt *ctxt,
807 uint32_t size, uint32_t align)
808 {
809 unsigned long s, e;
810
811 /* Align to at least 16 bytes. */
812 if ( align < 16 )
813 align = 16;
814
815 s = (acpi_alloc_up + align) & ~(align - 1);
816 e = s + size - 1;
817
818 BUG_ON((e < s) || (e >= RESERVED_MEMORY_DYNAMIC_START));
819
820 while ( (acpi_alloc_up >> PAGE_SHIFT) != (e >> PAGE_SHIFT) )
821 {
822 acpi_alloc_up += PAGE_SIZE;
823 mem_hole_populate_ram(acpi_alloc_up >> PAGE_SHIFT, 1);
824 }
825
826 acpi_alloc_up = e;
827
828 return (void *)s;
829 }
830
acpi_mem_free(struct acpi_ctxt * ctxt,void * v,uint32_t size)831 static void acpi_mem_free(struct acpi_ctxt *ctxt,
832 void *v, uint32_t size)
833 {
834 /* ACPI builder currently doesn't free memory so this is just a stub */
835 }
836
acpi_lapic_id(unsigned cpu)837 static uint32_t acpi_lapic_id(unsigned cpu)
838 {
839 return LAPIC_ID(cpu);
840 }
841
hvmloader_acpi_build_tables(struct acpi_config * config,unsigned int physical)842 void hvmloader_acpi_build_tables(struct acpi_config *config,
843 unsigned int physical)
844 {
845 const char *s;
846 struct acpi_ctxt ctxt;
847 long long tpm_version;
848 char *end;
849
850 /* Allocate and initialise the acpi info area. */
851 mem_hole_populate_ram(ACPI_INFO_PHYSICAL_ADDRESS >> PAGE_SHIFT, 1);
852
853 /* If the device model is specified switch to the corresponding tables */
854 s = xenstore_read("platform/device-model", "");
855 if ( !strncmp(s, "qemu_xen_traditional", 21) )
856 {
857 config->dsdt_anycpu = dsdt_anycpu;
858 config->dsdt_anycpu_len = dsdt_anycpu_len;
859 config->dsdt_15cpu = dsdt_15cpu;
860 config->dsdt_15cpu_len = dsdt_15cpu_len;
861 }
862 else if ( !strncmp(s, "qemu_xen", 9) )
863 {
864 config->dsdt_anycpu = dsdt_anycpu_qemu_xen;
865 config->dsdt_anycpu_len = dsdt_anycpu_qemu_xen_len;
866 config->dsdt_15cpu = NULL;
867 config->dsdt_15cpu_len = 0;
868 }
869
870 config->lapic_base_address = LAPIC_BASE_ADDRESS;
871 config->lapic_id = acpi_lapic_id;
872 config->ioapic_base_address = IOAPIC_BASE_ADDRESS;
873 config->ioapic_id = IOAPIC_ID;
874 config->pci_isa_irq_mask = PCI_ISA_IRQ_MASK;
875
876 if ( uart_exists(0x3f8) )
877 config->table_flags |= ACPI_HAS_COM1;
878 if ( uart_exists(0x2f8) )
879 config->table_flags |= ACPI_HAS_COM2;
880 if ( lpt_exists(0x378) )
881 config->table_flags |= ACPI_HAS_LPT1;
882 if ( hpet_exists(ACPI_HPET_ADDRESS) )
883 config->table_flags |= ACPI_HAS_HPET;
884
885 config->pci_start = pci_mem_start;
886 config->pci_len = pci_mem_end - pci_mem_start;
887 if ( pci_hi_mem_end > pci_hi_mem_start )
888 {
889 config->pci_hi_start = pci_hi_mem_start;
890 config->pci_hi_len = pci_hi_mem_end - pci_hi_mem_start;
891 }
892
893 s = xenstore_read("platform/generation-id", "0:0");
894 if ( s )
895 {
896 config->vm_gid[0] = strtoll(s, &end, 0);
897 config->vm_gid[1] = 0;
898 if ( end && end[0] == ':' )
899 config->vm_gid[1] = strtoll(end+1, NULL, 0);
900 }
901
902 s = xenstore_read(HVM_XS_ACPI_PT_ADDRESS, NULL);
903 if ( s )
904 {
905 config->pt.addr = strtoll(s, NULL, 0);
906
907 s = xenstore_read(HVM_XS_ACPI_PT_LENGTH, NULL);
908 if ( s )
909 config->pt.length = strtoll(s, NULL, 0);
910 }
911
912 if ( battery_port_exists() )
913 config->table_flags |= ACPI_HAS_SSDT_PM;
914 if ( !strncmp(xenstore_read("platform/acpi_s3", "1"), "1", 1) )
915 config->table_flags |= ACPI_HAS_SSDT_S3;
916 if ( !strncmp(xenstore_read("platform/acpi_s4", "1"), "1", 1) )
917 config->table_flags |= ACPI_HAS_SSDT_S4;
918 if ( !strncmp(xenstore_read("platform/acpi_laptop_slate", "0"), "1", 1) )
919 config->table_flags |= ACPI_HAS_SSDT_LAPTOP_SLATE;
920
921 config->table_flags |= (ACPI_HAS_IOAPIC | ACPI_HAS_WAET |
922 ACPI_HAS_PMTIMER | ACPI_HAS_BUTTONS |
923 ACPI_HAS_VGA | ACPI_HAS_8042 |
924 ACPI_HAS_CMOS_RTC);
925 config->acpi_revision = 4;
926
927 config->tpm_version = 0;
928 s = xenstore_read("platform/tpm_version", "1");
929 tpm_version = strtoll(s, &end, 0);
930
931 if ( end[0] == '\0' )
932 {
933 switch ( tpm_version )
934 {
935 case 1:
936 config->table_flags |= ACPI_HAS_TPM;
937 config->tis_hdr = (uint16_t *)ACPI_TIS_HDR_ADDRESS;
938 config->tpm_version = 1;
939 break;
940
941 case 2:
942 config->table_flags |= ACPI_HAS_TPM;
943 config->crb_id = (uint16_t *)TPM_CRB_INTF_ID;
944
945 mem_hole_populate_ram(TPM_LOG_AREA_ADDRESS >> PAGE_SHIFT,
946 TPM_LOG_SIZE >> PAGE_SHIFT);
947 memset((void *)TPM_LOG_AREA_ADDRESS, 0, TPM_LOG_SIZE);
948 config->tpm_version = 2;
949 break;
950 }
951 }
952
953 config->numa.nr_vmemranges = nr_vmemranges;
954 config->numa.nr_vnodes = nr_vnodes;
955 config->numa.vcpu_to_vnode = vcpu_to_vnode;
956 config->numa.vdistance = vdistance;
957 config->numa.vmemrange = vmemrange;
958
959 config->hvminfo = hvm_info;
960
961 config->rsdp = physical;
962 config->infop = ACPI_INFO_PHYSICAL_ADDRESS;
963
964 ctxt.mem_ops.alloc = acpi_mem_alloc;
965 ctxt.mem_ops.free = acpi_mem_free;
966 ctxt.mem_ops.v2p = acpi_v2p;
967
968 acpi_build_tables(&ctxt, config);
969
970 hvm_param_set(HVM_PARAM_VM_GENERATION_ID_ADDR, config->vm_gid_addr);
971 }
972
973 /*
974 * Local variables:
975 * mode: C
976 * c-file-style: "BSD"
977 * c-basic-offset: 4
978 * tab-width: 4
979 * indent-tabs-mode: nil
980 * End:
981 */
982