aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Kiper <daniel.kiper@oracle.com>2014-06-30 13:53:02 -0400
committerMatt Fleming <matt.fleming@intel.com>2014-07-18 16:23:58 -0400
commitbe81c8a1da24288b0231be50130a64f5cdffdcd4 (patch)
treeb0e011366af28808fffc44e8de8ca690dd645ad0
parentbf1e3ae468aca7ce34110a59ed5d1b877890014b (diff)
xen: Put EFI machinery in place
This patch enables EFI usage under Xen dom0. Standard EFI Linux Kernel infrastructure cannot be used because it requires direct access to EFI data and code. However, in dom0 case it is not possible because above mentioned EFI stuff is fully owned and controlled by Xen hypervisor. In this case all calls from dom0 to EFI must be requested via special hypercall which in turn executes relevant EFI code in behalf of dom0. When dom0 kernel boots it checks for EFI availability on a machine. If it is detected then artificial EFI system table is filled. Native EFI callas are replaced by functions which mimics them by calling relevant hypercall. Later pointer to EFI system table is passed to standard EFI machinery and it continues EFI subsystem initialization taking into account that there is no direct access to EFI boot services, runtime, tables, structures, etc. After that system runs as usual. This patch is based on Jan Beulich and Tang Liang work. Signed-off-by: Jan Beulich <jbeulich@suse.com> Signed-off-by: Tang Liang <liang.tang@oracle.com> Signed-off-by: Daniel Kiper <daniel.kiper@oracle.com> Reviewed-by: David Vrabel <david.vrabel@citrix.com> Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--arch/x86/xen/enlighten.c15
-rw-r--r--drivers/xen/Kconfig4
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/efi.c368
-rw-r--r--include/xen/xen-ops.h11
5 files changed, 401 insertions, 0 deletions
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index f17b29210ac4..bc89647f0325 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -32,6 +32,7 @@
32#include <linux/gfp.h> 32#include <linux/gfp.h>
33#include <linux/memblock.h> 33#include <linux/memblock.h>
34#include <linux/edd.h> 34#include <linux/edd.h>
35#include <linux/efi.h>
35 36
36#include <xen/xen.h> 37#include <xen/xen.h>
37#include <xen/events.h> 38#include <xen/events.h>
@@ -1520,6 +1521,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
1520{ 1521{
1521 struct physdev_set_iopl set_iopl; 1522 struct physdev_set_iopl set_iopl;
1522 int rc; 1523 int rc;
1524 efi_system_table_t *efi_systab_xen;
1523 1525
1524 if (!xen_start_info) 1526 if (!xen_start_info)
1525 return; 1527 return;
@@ -1715,6 +1717,19 @@ asmlinkage __visible void __init xen_start_kernel(void)
1715 1717
1716 xen_setup_runstate_info(0); 1718 xen_setup_runstate_info(0);
1717 1719
1720 efi_systab_xen = xen_efi_probe();
1721
1722 if (efi_systab_xen) {
1723 strncpy((char *)&boot_params.efi_info.efi_loader_signature, "Xen",
1724 sizeof(boot_params.efi_info.efi_loader_signature));
1725 boot_params.efi_info.efi_systab = (__u32)__pa(efi_systab_xen);
1726 boot_params.efi_info.efi_systab_hi = (__u32)(__pa(efi_systab_xen) >> 32);
1727
1728 set_bit(EFI_BOOT, &efi.flags);
1729 set_bit(EFI_PARAVIRT, &efi.flags);
1730 set_bit(EFI_64BIT, &efi.flags);
1731 }
1732
1718 /* Start the world */ 1733 /* Start the world */
1719#ifdef CONFIG_X86_32 1734#ifdef CONFIG_X86_32
1720 i386_start_kernel(); 1735 i386_start_kernel();
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 38fb36e1c592..8bc01838daf9 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -240,4 +240,8 @@ config XEN_MCE_LOG
240config XEN_HAVE_PVMMU 240config XEN_HAVE_PVMMU
241 bool 241 bool
242 242
243config XEN_EFI
244 def_bool y
245 depends on X86_64 && EFI
246
243endmenu 247endmenu
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 45e00afa7f2d..84044b554e33 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -9,6 +9,8 @@ obj-y += xenbus/
9nostackp := $(call cc-option, -fno-stack-protector) 9nostackp := $(call cc-option, -fno-stack-protector)
10CFLAGS_features.o := $(nostackp) 10CFLAGS_features.o := $(nostackp)
11 11
12CFLAGS_efi.o += -fshort-wchar
13
12dom0-$(CONFIG_PCI) += pci.o 14dom0-$(CONFIG_PCI) += pci.o
13dom0-$(CONFIG_USB_SUPPORT) += dbgp.o 15dom0-$(CONFIG_USB_SUPPORT) += dbgp.o
14dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y) 16dom0-$(CONFIG_ACPI) += acpi.o $(xen-pad-y)
@@ -33,6 +35,7 @@ obj-$(CONFIG_XEN_STUB) += xen-stub.o
33obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o 35obj-$(CONFIG_XEN_ACPI_HOTPLUG_MEMORY) += xen-acpi-memhotplug.o
34obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o 36obj-$(CONFIG_XEN_ACPI_HOTPLUG_CPU) += xen-acpi-cpuhotplug.o
35obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o 37obj-$(CONFIG_XEN_ACPI_PROCESSOR) += xen-acpi-processor.o
38obj-$(CONFIG_XEN_EFI) += efi.o
36xen-evtchn-y := evtchn.o 39xen-evtchn-y := evtchn.o
37xen-gntdev-y := gntdev.o 40xen-gntdev-y := gntdev.o
38xen-gntalloc-y := gntalloc.o 41xen-gntalloc-y := gntalloc.o
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
new file mode 100644
index 000000000000..31f618a49661
--- /dev/null
+++ b/drivers/xen/efi.c
@@ -0,0 +1,368 @@
1/*
2 * EFI support for Xen.
3 *
4 * Copyright (C) 1999 VA Linux Systems
5 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
6 * Copyright (C) 1999-2002 Hewlett-Packard Co.
7 * David Mosberger-Tang <davidm@hpl.hp.com>
8 * Stephane Eranian <eranian@hpl.hp.com>
9 * Copyright (C) 2005-2008 Intel Co.
10 * Fenghua Yu <fenghua.yu@intel.com>
11 * Bibo Mao <bibo.mao@intel.com>
12 * Chandramouli Narayanan <mouli@linux.intel.com>
13 * Huang Ying <ying.huang@intel.com>
14 * Copyright (C) 2011 Novell Co.
15 * Jan Beulich <JBeulich@suse.com>
16 * Copyright (C) 2011-2012 Oracle Co.
17 * Liang Tang <liang.tang@oracle.com>
18 * Copyright (c) 2014 Oracle Co., Daniel Kiper
19 */
20
21#include <linux/bug.h>
22#include <linux/efi.h>
23#include <linux/init.h>
24#include <linux/string.h>
25
26#include <xen/interface/xen.h>
27#include <xen/interface/platform.h>
28#include <xen/xen.h>
29
30#include <asm/xen/hypercall.h>
31
32#define INIT_EFI_OP(name) \
33 {.cmd = XENPF_efi_runtime_call, \
34 .u.efi_runtime_call.function = XEN_EFI_##name, \
35 .u.efi_runtime_call.misc = 0}
36
37#define efi_data(op) (op.u.efi_runtime_call)
38
39static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
40{
41 struct xen_platform_op op = INIT_EFI_OP(get_time);
42
43 if (HYPERVISOR_dom0_op(&op) < 0)
44 return EFI_UNSUPPORTED;
45
46 if (tm) {
47 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_time.time));
48 memcpy(tm, &efi_data(op).u.get_time.time, sizeof(*tm));
49 }
50
51 if (tc) {
52 tc->resolution = efi_data(op).u.get_time.resolution;
53 tc->accuracy = efi_data(op).u.get_time.accuracy;
54 tc->sets_to_zero = !!(efi_data(op).misc &
55 XEN_EFI_GET_TIME_SET_CLEARS_NS);
56 }
57
58 return efi_data(op).status;
59}
60
61static efi_status_t xen_efi_set_time(efi_time_t *tm)
62{
63 struct xen_platform_op op = INIT_EFI_OP(set_time);
64
65 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time));
66 memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm));
67
68 if (HYPERVISOR_dom0_op(&op) < 0)
69 return EFI_UNSUPPORTED;
70
71 return efi_data(op).status;
72}
73
74static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
75 efi_bool_t *pending,
76 efi_time_t *tm)
77{
78 struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time);
79
80 if (HYPERVISOR_dom0_op(&op) < 0)
81 return EFI_UNSUPPORTED;
82
83 if (tm) {
84 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.get_wakeup_time));
85 memcpy(tm, &efi_data(op).u.get_wakeup_time, sizeof(*tm));
86 }
87
88 if (enabled)
89 *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
90
91 if (pending)
92 *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
93
94 return efi_data(op).status;
95}
96
97static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
98{
99 struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time);
100
101 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time));
102 if (enabled)
103 efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
104 if (tm)
105 memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm));
106 else
107 efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
108
109 if (HYPERVISOR_dom0_op(&op) < 0)
110 return EFI_UNSUPPORTED;
111
112 return efi_data(op).status;
113}
114
115static efi_status_t xen_efi_get_variable(efi_char16_t *name,
116 efi_guid_t *vendor,
117 u32 *attr,
118 unsigned long *data_size,
119 void *data)
120{
121 struct xen_platform_op op = INIT_EFI_OP(get_variable);
122
123 set_xen_guest_handle(efi_data(op).u.get_variable.name, name);
124 BUILD_BUG_ON(sizeof(*vendor) !=
125 sizeof(efi_data(op).u.get_variable.vendor_guid));
126 memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor));
127 efi_data(op).u.get_variable.size = *data_size;
128 set_xen_guest_handle(efi_data(op).u.get_variable.data, data);
129
130 if (HYPERVISOR_dom0_op(&op) < 0)
131 return EFI_UNSUPPORTED;
132
133 *data_size = efi_data(op).u.get_variable.size;
134 if (attr)
135 *attr = efi_data(op).misc;
136
137 return efi_data(op).status;
138}
139
140static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
141 efi_char16_t *name,
142 efi_guid_t *vendor)
143{
144 struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name);
145
146 efi_data(op).u.get_next_variable_name.size = *name_size;
147 set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name);
148 BUILD_BUG_ON(sizeof(*vendor) !=
149 sizeof(efi_data(op).u.get_next_variable_name.vendor_guid));
150 memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor,
151 sizeof(*vendor));
152
153 if (HYPERVISOR_dom0_op(&op) < 0)
154 return EFI_UNSUPPORTED;
155
156 *name_size = efi_data(op).u.get_next_variable_name.size;
157 memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid,
158 sizeof(*vendor));
159
160 return efi_data(op).status;
161}
162
163static efi_status_t xen_efi_set_variable(efi_char16_t *name,
164 efi_guid_t *vendor,
165 u32 attr,
166 unsigned long data_size,
167 void *data)
168{
169 struct xen_platform_op op = INIT_EFI_OP(set_variable);
170
171 set_xen_guest_handle(efi_data(op).u.set_variable.name, name);
172 efi_data(op).misc = attr;
173 BUILD_BUG_ON(sizeof(*vendor) !=
174 sizeof(efi_data(op).u.set_variable.vendor_guid));
175 memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor));
176 efi_data(op).u.set_variable.size = data_size;
177 set_xen_guest_handle(efi_data(op).u.set_variable.data, data);
178
179 if (HYPERVISOR_dom0_op(&op) < 0)
180 return EFI_UNSUPPORTED;
181
182 return efi_data(op).status;
183}
184
185static efi_status_t xen_efi_query_variable_info(u32 attr,
186 u64 *storage_space,
187 u64 *remaining_space,
188 u64 *max_variable_size)
189{
190 struct xen_platform_op op = INIT_EFI_OP(query_variable_info);
191
192 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
193 return EFI_UNSUPPORTED;
194
195 efi_data(op).u.query_variable_info.attr = attr;
196
197 if (HYPERVISOR_dom0_op(&op) < 0)
198 return EFI_UNSUPPORTED;
199
200 *storage_space = efi_data(op).u.query_variable_info.max_store_size;
201 *remaining_space = efi_data(op).u.query_variable_info.remain_store_size;
202 *max_variable_size = efi_data(op).u.query_variable_info.max_size;
203
204 return efi_data(op).status;
205}
206
207static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
208{
209 struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count);
210
211 if (HYPERVISOR_dom0_op(&op) < 0)
212 return EFI_UNSUPPORTED;
213
214 *count = efi_data(op).misc;
215
216 return efi_data(op).status;
217}
218
219static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules,
220 unsigned long count,
221 unsigned long sg_list)
222{
223 struct xen_platform_op op = INIT_EFI_OP(update_capsule);
224
225 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
226 return EFI_UNSUPPORTED;
227
228 set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array,
229 capsules);
230 efi_data(op).u.update_capsule.capsule_count = count;
231 efi_data(op).u.update_capsule.sg_list = sg_list;
232
233 if (HYPERVISOR_dom0_op(&op) < 0)
234 return EFI_UNSUPPORTED;
235
236 return efi_data(op).status;
237}
238
239static efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules,
240 unsigned long count,
241 u64 *max_size,
242 int *reset_type)
243{
244 struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities);
245
246 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
247 return EFI_UNSUPPORTED;
248
249 set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array,
250 capsules);
251 efi_data(op).u.query_capsule_capabilities.capsule_count = count;
252
253 if (HYPERVISOR_dom0_op(&op) < 0)
254 return EFI_UNSUPPORTED;
255
256 *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size;
257 *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type;
258
259 return efi_data(op).status;
260}
261
262static efi_char16_t vendor[100] __initdata;
263
264static efi_system_table_t efi_systab_xen __initdata = {
265 .hdr = {
266 .signature = EFI_SYSTEM_TABLE_SIGNATURE,
267 .revision = 0, /* Initialized later. */
268 .headersize = 0, /* Ignored by Linux Kernel. */
269 .crc32 = 0, /* Ignored by Linux Kernel. */
270 .reserved = 0
271 },
272 .fw_vendor = EFI_INVALID_TABLE_ADDR, /* Initialized later. */
273 .fw_revision = 0, /* Initialized later. */
274 .con_in_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
275 .con_in = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
276 .con_out_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
277 .con_out = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
278 .stderr_handle = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
279 .stderr = EFI_INVALID_TABLE_ADDR, /* Not used under Xen. */
280 .runtime = (efi_runtime_services_t *)EFI_INVALID_TABLE_ADDR,
281 /* Not used under Xen. */
282 .boottime = (efi_boot_services_t *)EFI_INVALID_TABLE_ADDR,
283 /* Not used under Xen. */
284 .nr_tables = 0, /* Initialized later. */
285 .tables = EFI_INVALID_TABLE_ADDR /* Initialized later. */
286};
287
288static const struct efi efi_xen __initconst = {
289 .systab = NULL, /* Initialized later. */
290 .runtime_version = 0, /* Initialized later. */
291 .mps = EFI_INVALID_TABLE_ADDR,
292 .acpi = EFI_INVALID_TABLE_ADDR,
293 .acpi20 = EFI_INVALID_TABLE_ADDR,
294 .smbios = EFI_INVALID_TABLE_ADDR,
295 .sal_systab = EFI_INVALID_TABLE_ADDR,
296 .boot_info = EFI_INVALID_TABLE_ADDR,
297 .hcdp = EFI_INVALID_TABLE_ADDR,
298 .uga = EFI_INVALID_TABLE_ADDR,
299 .uv_systab = EFI_INVALID_TABLE_ADDR,
300 .fw_vendor = EFI_INVALID_TABLE_ADDR,
301 .runtime = EFI_INVALID_TABLE_ADDR,
302 .config_table = EFI_INVALID_TABLE_ADDR,
303 .get_time = xen_efi_get_time,
304 .set_time = xen_efi_set_time,
305 .get_wakeup_time = xen_efi_get_wakeup_time,
306 .set_wakeup_time = xen_efi_set_wakeup_time,
307 .get_variable = xen_efi_get_variable,
308 .get_next_variable = xen_efi_get_next_variable,
309 .set_variable = xen_efi_set_variable,
310 .query_variable_info = xen_efi_query_variable_info,
311 .update_capsule = xen_efi_update_capsule,
312 .query_capsule_caps = xen_efi_query_capsule_caps,
313 .get_next_high_mono_count = xen_efi_get_next_high_mono_count,
314 .reset_system = NULL, /* Functionality provided by Xen. */
315 .set_virtual_address_map = NULL, /* Not used under Xen. */
316 .memmap = NULL, /* Not used under Xen. */
317 .flags = 0 /* Initialized later. */
318};
319
320efi_system_table_t __init *xen_efi_probe(void)
321{
322 struct xen_platform_op op = {
323 .cmd = XENPF_firmware_info,
324 .u.firmware_info = {
325 .type = XEN_FW_EFI_INFO,
326 .index = XEN_FW_EFI_CONFIG_TABLE
327 }
328 };
329 union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
330
331 if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op) < 0)
332 return NULL;
333
334 /* Here we know that Xen runs on EFI platform. */
335
336 efi = efi_xen;
337
338 efi_systab_xen.tables = info->cfg.addr;
339 efi_systab_xen.nr_tables = info->cfg.nent;
340
341 op.cmd = XENPF_firmware_info;
342 op.u.firmware_info.type = XEN_FW_EFI_INFO;
343 op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
344 info->vendor.bufsz = sizeof(vendor);
345 set_xen_guest_handle(info->vendor.name, vendor);
346
347 if (HYPERVISOR_dom0_op(&op) == 0) {
348 efi_systab_xen.fw_vendor = __pa_symbol(vendor);
349 efi_systab_xen.fw_revision = info->vendor.revision;
350 } else
351 efi_systab_xen.fw_vendor = __pa_symbol(L"UNKNOWN");
352
353 op.cmd = XENPF_firmware_info;
354 op.u.firmware_info.type = XEN_FW_EFI_INFO;
355 op.u.firmware_info.index = XEN_FW_EFI_VERSION;
356
357 if (HYPERVISOR_dom0_op(&op) == 0)
358 efi_systab_xen.hdr.revision = info->version;
359
360 op.cmd = XENPF_firmware_info;
361 op.u.firmware_info.type = XEN_FW_EFI_INFO;
362 op.u.firmware_info.index = XEN_FW_EFI_RT_VERSION;
363
364 if (HYPERVISOR_dom0_op(&op) == 0)
365 efi.runtime_version = info->version;
366
367 return &efi_systab_xen;
368}
diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h
index 0b3149ed7eaa..771bbba27ccb 100644
--- a/include/xen/xen-ops.h
+++ b/include/xen/xen-ops.h
@@ -3,6 +3,7 @@
3 3
4#include <linux/percpu.h> 4#include <linux/percpu.h>
5#include <linux/notifier.h> 5#include <linux/notifier.h>
6#include <linux/efi.h>
6#include <asm/xen/interface.h> 7#include <asm/xen/interface.h>
7 8
8DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu); 9DECLARE_PER_CPU(struct vcpu_info *, xen_vcpu);
@@ -35,4 +36,14 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
35 int numpgs, struct page **pages); 36 int numpgs, struct page **pages);
36 37
37bool xen_running_on_version_or_later(unsigned int major, unsigned int minor); 38bool xen_running_on_version_or_later(unsigned int major, unsigned int minor);
39
40#ifdef CONFIG_XEN_EFI
41extern efi_system_table_t *xen_efi_probe(void);
42#else
43static efi_system_table_t __init *xen_efi_probe(void)
44{
45 return NULL;
46}
47#endif
48
38#endif /* INCLUDE_XEN_OPS_H */ 49#endif /* INCLUDE_XEN_OPS_H */