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
21 #include <linux/bug.h>
22 #include <linux/efi.h>
23 #include <linux/init.h>
24 #include <linux/string.h>
26 #include <xen/interface/xen.h>
27 #include <xen/interface/platform.h>
32 #include <asm/xen/hypercall.h>
34 #define INIT_EFI_OP(name) \
35 {.cmd = XENPF_efi_runtime_call, \
36 .u.efi_runtime_call.function = XEN_EFI_##name, \
37 .u.efi_runtime_call.misc = 0}
39 #define efi_data(op) (op.u.efi_runtime_call)
41 static efi_status_t
xen_efi_get_time(efi_time_t
*tm
, efi_time_cap_t
*tc
)
43 struct xen_platform_op op
= INIT_EFI_OP(get_time
);
45 if (HYPERVISOR_dom0_op(&op
) < 0)
46 return EFI_UNSUPPORTED
;
49 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_time
.time
));
50 memcpy(tm
, &efi_data(op
).u
.get_time
.time
, sizeof(*tm
));
54 tc
->resolution
= efi_data(op
).u
.get_time
.resolution
;
55 tc
->accuracy
= efi_data(op
).u
.get_time
.accuracy
;
56 tc
->sets_to_zero
= !!(efi_data(op
).misc
&
57 XEN_EFI_GET_TIME_SET_CLEARS_NS
);
60 return efi_data(op
).status
;
63 static efi_status_t
xen_efi_set_time(efi_time_t
*tm
)
65 struct xen_platform_op op
= INIT_EFI_OP(set_time
);
67 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_time
));
68 memcpy(&efi_data(op
).u
.set_time
, tm
, sizeof(*tm
));
70 if (HYPERVISOR_dom0_op(&op
) < 0)
71 return EFI_UNSUPPORTED
;
73 return efi_data(op
).status
;
76 static efi_status_t
xen_efi_get_wakeup_time(efi_bool_t
*enabled
,
80 struct xen_platform_op op
= INIT_EFI_OP(get_wakeup_time
);
82 if (HYPERVISOR_dom0_op(&op
) < 0)
83 return EFI_UNSUPPORTED
;
86 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_wakeup_time
));
87 memcpy(tm
, &efi_data(op
).u
.get_wakeup_time
, sizeof(*tm
));
91 *enabled
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_ENABLED
);
94 *pending
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_PENDING
);
96 return efi_data(op
).status
;
99 static efi_status_t
xen_efi_set_wakeup_time(efi_bool_t enabled
, efi_time_t
*tm
)
101 struct xen_platform_op op
= INIT_EFI_OP(set_wakeup_time
);
103 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_wakeup_time
));
105 efi_data(op
).misc
= XEN_EFI_SET_WAKEUP_TIME_ENABLE
;
107 memcpy(&efi_data(op
).u
.set_wakeup_time
, tm
, sizeof(*tm
));
109 efi_data(op
).misc
|= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY
;
111 if (HYPERVISOR_dom0_op(&op
) < 0)
112 return EFI_UNSUPPORTED
;
114 return efi_data(op
).status
;
117 static efi_status_t
xen_efi_get_variable(efi_char16_t
*name
,
120 unsigned long *data_size
,
123 struct xen_platform_op op
= INIT_EFI_OP(get_variable
);
125 set_xen_guest_handle(efi_data(op
).u
.get_variable
.name
, name
);
126 BUILD_BUG_ON(sizeof(*vendor
) !=
127 sizeof(efi_data(op
).u
.get_variable
.vendor_guid
));
128 memcpy(&efi_data(op
).u
.get_variable
.vendor_guid
, vendor
, sizeof(*vendor
));
129 efi_data(op
).u
.get_variable
.size
= *data_size
;
130 set_xen_guest_handle(efi_data(op
).u
.get_variable
.data
, data
);
132 if (HYPERVISOR_dom0_op(&op
) < 0)
133 return EFI_UNSUPPORTED
;
135 *data_size
= efi_data(op
).u
.get_variable
.size
;
137 *attr
= efi_data(op
).misc
;
139 return efi_data(op
).status
;
142 static efi_status_t
xen_efi_get_next_variable(unsigned long *name_size
,
146 struct xen_platform_op op
= INIT_EFI_OP(get_next_variable_name
);
148 efi_data(op
).u
.get_next_variable_name
.size
= *name_size
;
149 set_xen_guest_handle(efi_data(op
).u
.get_next_variable_name
.name
, name
);
150 BUILD_BUG_ON(sizeof(*vendor
) !=
151 sizeof(efi_data(op
).u
.get_next_variable_name
.vendor_guid
));
152 memcpy(&efi_data(op
).u
.get_next_variable_name
.vendor_guid
, vendor
,
155 if (HYPERVISOR_dom0_op(&op
) < 0)
156 return EFI_UNSUPPORTED
;
158 *name_size
= efi_data(op
).u
.get_next_variable_name
.size
;
159 memcpy(vendor
, &efi_data(op
).u
.get_next_variable_name
.vendor_guid
,
162 return efi_data(op
).status
;
165 static efi_status_t
xen_efi_set_variable(efi_char16_t
*name
,
168 unsigned long data_size
,
171 struct xen_platform_op op
= INIT_EFI_OP(set_variable
);
173 set_xen_guest_handle(efi_data(op
).u
.set_variable
.name
, name
);
174 efi_data(op
).misc
= attr
;
175 BUILD_BUG_ON(sizeof(*vendor
) !=
176 sizeof(efi_data(op
).u
.set_variable
.vendor_guid
));
177 memcpy(&efi_data(op
).u
.set_variable
.vendor_guid
, vendor
, sizeof(*vendor
));
178 efi_data(op
).u
.set_variable
.size
= data_size
;
179 set_xen_guest_handle(efi_data(op
).u
.set_variable
.data
, data
);
181 if (HYPERVISOR_dom0_op(&op
) < 0)
182 return EFI_UNSUPPORTED
;
184 return efi_data(op
).status
;
187 static efi_status_t
xen_efi_query_variable_info(u32 attr
,
189 u64
*remaining_space
,
190 u64
*max_variable_size
)
192 struct xen_platform_op op
= INIT_EFI_OP(query_variable_info
);
194 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
195 return EFI_UNSUPPORTED
;
197 efi_data(op
).u
.query_variable_info
.attr
= attr
;
199 if (HYPERVISOR_dom0_op(&op
) < 0)
200 return EFI_UNSUPPORTED
;
202 *storage_space
= efi_data(op
).u
.query_variable_info
.max_store_size
;
203 *remaining_space
= efi_data(op
).u
.query_variable_info
.remain_store_size
;
204 *max_variable_size
= efi_data(op
).u
.query_variable_info
.max_size
;
206 return efi_data(op
).status
;
209 static efi_status_t
xen_efi_get_next_high_mono_count(u32
*count
)
211 struct xen_platform_op op
= INIT_EFI_OP(get_next_high_monotonic_count
);
213 if (HYPERVISOR_dom0_op(&op
) < 0)
214 return EFI_UNSUPPORTED
;
216 *count
= efi_data(op
).misc
;
218 return efi_data(op
).status
;
221 static efi_status_t
xen_efi_update_capsule(efi_capsule_header_t
**capsules
,
223 unsigned long sg_list
)
225 struct xen_platform_op op
= INIT_EFI_OP(update_capsule
);
227 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
228 return EFI_UNSUPPORTED
;
230 set_xen_guest_handle(efi_data(op
).u
.update_capsule
.capsule_header_array
,
232 efi_data(op
).u
.update_capsule
.capsule_count
= count
;
233 efi_data(op
).u
.update_capsule
.sg_list
= sg_list
;
235 if (HYPERVISOR_dom0_op(&op
) < 0)
236 return EFI_UNSUPPORTED
;
238 return efi_data(op
).status
;
241 static efi_status_t
xen_efi_query_capsule_caps(efi_capsule_header_t
**capsules
,
246 struct xen_platform_op op
= INIT_EFI_OP(query_capsule_capabilities
);
248 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
249 return EFI_UNSUPPORTED
;
251 set_xen_guest_handle(efi_data(op
).u
.query_capsule_capabilities
.capsule_header_array
,
253 efi_data(op
).u
.query_capsule_capabilities
.capsule_count
= count
;
255 if (HYPERVISOR_dom0_op(&op
) < 0)
256 return EFI_UNSUPPORTED
;
258 *max_size
= efi_data(op
).u
.query_capsule_capabilities
.max_capsule_size
;
259 *reset_type
= efi_data(op
).u
.query_capsule_capabilities
.reset_type
;
261 return efi_data(op
).status
;
264 static efi_char16_t vendor
[100] __initdata
;
266 static efi_system_table_t efi_systab_xen __initdata
= {
268 .signature
= EFI_SYSTEM_TABLE_SIGNATURE
,
269 .revision
= 0, /* Initialized later. */
270 .headersize
= 0, /* Ignored by Linux Kernel. */
271 .crc32
= 0, /* Ignored by Linux Kernel. */
274 .fw_vendor
= EFI_INVALID_TABLE_ADDR
, /* Initialized later. */
275 .fw_revision
= 0, /* Initialized later. */
276 .con_in_handle
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
277 .con_in
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
278 .con_out_handle
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
279 .con_out
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
280 .stderr_handle
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
281 .stderr
= EFI_INVALID_TABLE_ADDR
, /* Not used under Xen. */
282 .runtime
= (efi_runtime_services_t
*)EFI_INVALID_TABLE_ADDR
,
283 /* Not used under Xen. */
284 .boottime
= (efi_boot_services_t
*)EFI_INVALID_TABLE_ADDR
,
285 /* Not used under Xen. */
286 .nr_tables
= 0, /* Initialized later. */
287 .tables
= EFI_INVALID_TABLE_ADDR
/* Initialized later. */
290 static const struct efi efi_xen __initconst
= {
291 .systab
= NULL
, /* Initialized later. */
292 .runtime_version
= 0, /* Initialized later. */
293 .mps
= EFI_INVALID_TABLE_ADDR
,
294 .acpi
= EFI_INVALID_TABLE_ADDR
,
295 .acpi20
= EFI_INVALID_TABLE_ADDR
,
296 .smbios
= EFI_INVALID_TABLE_ADDR
,
297 .smbios3
= EFI_INVALID_TABLE_ADDR
,
298 .sal_systab
= EFI_INVALID_TABLE_ADDR
,
299 .boot_info
= EFI_INVALID_TABLE_ADDR
,
300 .hcdp
= EFI_INVALID_TABLE_ADDR
,
301 .uga
= EFI_INVALID_TABLE_ADDR
,
302 .uv_systab
= EFI_INVALID_TABLE_ADDR
,
303 .fw_vendor
= EFI_INVALID_TABLE_ADDR
,
304 .runtime
= EFI_INVALID_TABLE_ADDR
,
305 .config_table
= EFI_INVALID_TABLE_ADDR
,
306 .get_time
= xen_efi_get_time
,
307 .set_time
= xen_efi_set_time
,
308 .get_wakeup_time
= xen_efi_get_wakeup_time
,
309 .set_wakeup_time
= xen_efi_set_wakeup_time
,
310 .get_variable
= xen_efi_get_variable
,
311 .get_next_variable
= xen_efi_get_next_variable
,
312 .set_variable
= xen_efi_set_variable
,
313 .query_variable_info
= xen_efi_query_variable_info
,
314 .update_capsule
= xen_efi_update_capsule
,
315 .query_capsule_caps
= xen_efi_query_capsule_caps
,
316 .get_next_high_mono_count
= xen_efi_get_next_high_mono_count
,
317 .reset_system
= NULL
, /* Functionality provided by Xen. */
318 .set_virtual_address_map
= NULL
, /* Not used under Xen. */
319 .memmap
= NULL
, /* Not used under Xen. */
320 .flags
= 0 /* Initialized later. */
323 efi_system_table_t __init
*xen_efi_probe(void)
325 struct xen_platform_op op
= {
326 .cmd
= XENPF_firmware_info
,
328 .type
= XEN_FW_EFI_INFO
,
329 .index
= XEN_FW_EFI_CONFIG_TABLE
332 union xenpf_efi_info
*info
= &op
.u
.firmware_info
.u
.efi_info
;
334 if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op
) < 0)
337 /* Here we know that Xen runs on EFI platform. */
341 efi_systab_xen
.tables
= info
->cfg
.addr
;
342 efi_systab_xen
.nr_tables
= info
->cfg
.nent
;
344 op
.cmd
= XENPF_firmware_info
;
345 op
.u
.firmware_info
.type
= XEN_FW_EFI_INFO
;
346 op
.u
.firmware_info
.index
= XEN_FW_EFI_VENDOR
;
347 info
->vendor
.bufsz
= sizeof(vendor
);
348 set_xen_guest_handle(info
->vendor
.name
, vendor
);
350 if (HYPERVISOR_dom0_op(&op
) == 0) {
351 efi_systab_xen
.fw_vendor
= __pa_symbol(vendor
);
352 efi_systab_xen
.fw_revision
= info
->vendor
.revision
;
354 efi_systab_xen
.fw_vendor
= __pa_symbol(L
"UNKNOWN");
356 op
.cmd
= XENPF_firmware_info
;
357 op
.u
.firmware_info
.type
= XEN_FW_EFI_INFO
;
358 op
.u
.firmware_info
.index
= XEN_FW_EFI_VERSION
;
360 if (HYPERVISOR_dom0_op(&op
) == 0)
361 efi_systab_xen
.hdr
.revision
= info
->version
;
363 op
.cmd
= XENPF_firmware_info
;
364 op
.u
.firmware_info
.type
= XEN_FW_EFI_INFO
;
365 op
.u
.firmware_info
.index
= XEN_FW_EFI_RT_VERSION
;
367 if (HYPERVISOR_dom0_op(&op
) == 0)
368 efi
.runtime_version
= info
->version
;
370 return &efi_systab_xen
;