blob: a4669d04fb9a69bf16252233f824f0c3bbe65787 [file] [log] [blame]
Ian Campbell74c78782011-06-01 11:00:29 +01001// 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
16u32 xen_cpuid_base = 0;
Ian Campbell9166c4a2012-06-27 12:08:49 +010017unsigned long xen_hypercall_page = 0;
Ian Campbell74c78782011-06-01 11:00:29 +010018
19struct xen_seabios_info {
20 char signature[14]; /* XenHVMSeaBIOS\0 */
21 u8 length; /* Length of this struct */
22 u8 checksum; /* Set such that the sum over bytes 0..length == 0 */
23 /*
24 * Physical address of an array of tables_nr elements.
25 *
26 * Each element is a 32 bit value contianing the physical address
27 * of a BIOS table.
28 */
29 u32 tables;
30 u32 tables_nr;
31 /*
32 * Physical address of the e820 table, contains e820_nr entries.
33 */
34 u32 e820;
35 u32 e820_nr;
36} PACKED;
37
38static void validate_info(struct xen_seabios_info *t)
39{
40 if ( memcmp(t->signature, "XenHVMSeaBIOS", 14) )
41 panic("Bad Xen info signature\n");
42
43 if ( t->length < sizeof(struct xen_seabios_info) )
44 panic("Bad Xen info length\n");
45
46 if (checksum(t, t->length) != 0)
47 panic("Bad Xen info checksum\n");
48}
49
50void xen_probe(void)
51{
52 u32 base, eax, ebx, ecx, edx;
53 char signature[13];
54
55 if (!CONFIG_XEN)
56 return;
57
58 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
59 cpuid(base, &eax, &ebx, &ecx, &edx);
60 memcpy(signature + 0, &ebx, 4);
61 memcpy(signature + 4, &ecx, 4);
62 memcpy(signature + 8, &edx, 4);
63 signature[12] = 0;
64
Kevin O'Connor36289332012-07-21 13:41:16 -040065 dprintf(9, "Found hypervisor signature \"%s\" at %x\n",
Ian Campbell74c78782011-06-01 11:00:29 +010066 signature, base);
67 if (strcmp(signature, "XenVMMXenVMM") == 0) {
Ian Campbell54f3b252012-06-28 11:08:32 +010068 /* Set debug_io_port first, so the following messages work. */
69 DebugOutputPort = 0xe9;
70 dprintf(1, "SeaBIOS (version %s)\n\n", VERSION);
71 dprintf(1, "Found Xen hypervisor signature at %x\n", base);
Ian Campbell74c78782011-06-01 11:00:29 +010072 if ((eax - base) < 2)
73 panic("Insufficient Xen cpuid leaves. eax=%x at base %x\n",
74 eax, base);
75 xen_cpuid_base = base;
76 break;
77 }
78 }
Ian Campbell54f3b252012-06-28 11:08:32 +010079 if (!xen_cpuid_base)
80 dprintf(1, "No Xen hypervisor found.\n");
Ian Campbell74c78782011-06-01 11:00:29 +010081}
82
83static int hypercall_xen_version( int cmd, void *arg)
84{
85 return _hypercall2(int, xen_version, cmd, arg);
86}
87
88/* Fill in hypercall transfer pages. */
89void xen_init_hypercalls(void)
90{
91 u32 eax, ebx, ecx, edx;
92 xen_extraversion_t extraversion;
93 unsigned long i;
94
95 if (!usingXen())
96 return;
97
98 cpuid(xen_cpuid_base + 2, &eax, &ebx, &ecx, &edx);
99
100 xen_hypercall_page = (unsigned long)memalign_high(PAGE_SIZE, eax*PAGE_SIZE);
101 if (!xen_hypercall_page)
102 panic("unable to allocate Xen hypercall page\n");
103
104 dprintf(1, "Allocated Xen hypercall page at %lx\n", xen_hypercall_page);
105 for ( i = 0; i < eax; i++ )
106 wrmsr(ebx, xen_hypercall_page + (i << 12) + i);
107
108 /* Print version information. */
109 cpuid(xen_cpuid_base + 1, &eax, &ebx, &ecx, &edx);
110 hypercall_xen_version(XENVER_extraversion, extraversion);
111 dprintf(1, "Detected Xen v%u.%u%s\n", eax >> 16, eax & 0xffff, extraversion);
112}
113
114void xen_copy_biostables(void)
115{
116 struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
Kevin O'Connor4d053eb2012-06-09 13:08:02 -0400117 void **tables = (void*)info->tables;
Ian Campbell74c78782011-06-01 11:00:29 +0100118 int i;
119
120 dprintf(1, "xen: copy BIOS tables...\n");
Kevin O'Connor4d053eb2012-06-09 13:08:02 -0400121 for (i=0; i<info->tables_nr; i++)
122 copy_table(tables[i]);
Ian Campbell74c78782011-06-01 11:00:29 +0100123}
124
125void xen_setup(void)
126{
127 u64 maxram = 0, maxram_over4G = 0;
128 int i;
129 struct xen_seabios_info *info = (void *)INFO_PHYSICAL_ADDRESS;
130 struct e820entry *e820 = (struct e820entry *)info->e820;
131 validate_info(info);
132
133 dprintf(1, "xen: copy e820...\n");
134
135 for (i = 0; i < info->e820_nr; i++) {
136 struct e820entry *e = &e820[i];
137 if (e->type == E820_ACPI || e->type == E820_RAM) {
138 u64 end = e->start + e->size;
139 if (end > 0x100000000ull) {
140 end -= 0x100000000ull;
141 if (end > maxram_over4G)
142 maxram_over4G = end;
143 } else if (end > maxram)
144 maxram = end;
145 }
146 add_e820(e->start, e->size, e->type);
147 }
148
149 RamSize = maxram;
150 RamSizeOver4G = maxram_over4G;
151}