grml...
[seabios.git] / src / xen.c
1 // Xen HVM support
2 //
3 // Copyright (C) 2011 Citrix Systems.
4 //
5 // This file may be distributed under the terms of the GNU LGPLv3 license.
6
7 #include "config.h"
8 #include "xen.h"
9
10 #include "memmap.h" // add_e820
11 #include "types.h" // ASM32FLAT
12 #include "util.h" // copy_acpi_rsdp
13
14 #define INFO_PHYSICAL_ADDRESS 0x00001000
15
16 u32 xen_cpuid_base = 0;
17
18 struct xen_seabios_info {
19     char signature[14]; /* XenHVMSeaBIOS\0 */
20     u8 length;     /* Length of this struct */
21     u8 checksum;   /* Set such that the sum over bytes 0..length == 0 */
22     /*
23      * Physical address of an array of tables_nr elements.
24      *
25      * Each element is a 32 bit value contianing the physical address
26      * of a BIOS table.
27      */
28     u32 tables;
29     u32 tables_nr;
30     /*
31      * Physical address of the e820 table, contains e820_nr entries.
32      */
33     u32 e820;
34     u32 e820_nr;
35 } PACKED;
36
37 static void validate_info(struct xen_seabios_info *t)
38 {
39     if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
40         panic("Bad Xen info signature\n");
41
42     if ( t->length < sizeof(struct xen_seabios_info) )
43         panic("Bad Xen info length\n");
44
45     if (checksum(t, t->length) != 0)
46         panic("Bad Xen info checksum\n");
47 }
48
49 void xen_probe(void)
50 {
51     u32 base, eax, ebx, ecx, edx;
52     char signature[13];
53
54     if (!CONFIG_XEN)
55         return;
56
57     for (base = 0x40000000; base < 0x40010000; base += 0x100) {
58         cpuid(base, &eax, &ebx, &ecx, &edx);
59         memcpy(signature + 0, &ebx, 4);
60         memcpy(signature + 4, &ecx, 4);
61         memcpy(signature + 8, &edx, 4);
62         signature[12] = 0;
63
64         dprintf(1, "Found hypervisor signature \"%s\" at %x\n",
65                 signature, base);
66         if (strcmp(signature, "XenVMMXenVMM") == 0) {
67             if ((eax - base) < 2)
68                 panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
69                       eax, base);
70             xen_cpuid_base = base;
71             break;
72         }
73     }
74 }
75
76 static int hypercall_xen_version( int cmd, void *arg)
77 {
78     return _hypercall2(int, xen_version, cmd, arg);
79 }
80
81 /* Fill in hypercall transfer pages. */
82 void xen_init_hypercalls(void)
83 {
84     u32 eax, ebx, ecx, edx;
85     xen_extraversion_t extraversion;
86     unsigned long i;
87
88     if (!usingXen())
89         return;
90
91     cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
92
93     xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
94     if (!xen_hypercall_page)
95         panic("unable to allocate Xen hypercall page\n");
96
97     dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
98     for ( i = 0; i < eax; i++ )
99         wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
100
101     /* Print version information. */
102     cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
103     hypercall_xen_version(XENVER_extraversion, extraversion);
104     dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
105 }
106
107 void xen_copy_biostables(void)
108 {
109     struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
110     u32 *tables = (u32 *)info->tables;
111     int i;
112
113     dprintf(1, "xen: copy BIOS tables...\n");
114     for (i=0; i<info->tables_nr; i++) {
115         void *table = (void *)tables[i];
116         copy_acpi_rsdp(table);
117         copy_mptable(table);
118         copy_pir(table);
119         copy_smbios(table);
120     }
121 }
122
123 void xen_setup(void)
124 {
125     u64 maxram = 0, maxram_over4G = 0;
126     int i;
127     struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
128     struct e820entry *e820 = (struct e820entry *)info->e820;
129     validate_info(info);
130
131     dprintf(1, "xen: copy e820...\n");
132
133     for (i = 0; i < info->e820_nr; i++) {
134         struct e820entry *e = &e820[i];
135         if (e->type == E820_ACPI || e->type == E820_RAM) {
136             u64 end = e->start + e->size;
137             if (end > 0x100000000ull) {
138                 end -= 0x100000000ull;
139                 if (end > maxram_over4G)
140                     maxram_over4G = end;
141             } else if (end > maxram)
142                 maxram = end;
143         }
144         add_e820(e->start, e->size, e->type);
145     }
146
147     RamSize = maxram;
148     RamSizeOver4G = maxram_over4G;
149 }