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>
30 #include <asm/xen/hypercall.h>
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}
37 #define efi_data(op) (op.u.efi_runtime_call)
39 static efi_status_t
xen_efi_get_time(efi_time_t
*tm
, efi_time_cap_t
*tc
)
41 struct xen_platform_op op
= INIT_EFI_OP(get_time
);
43 if (HYPERVISOR_dom0_op(&op
) < 0)
44 return EFI_UNSUPPORTED
;
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
));
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
);
58 return efi_data(op
).status
;
61 static efi_status_t
xen_efi_set_time(efi_time_t
*tm
)
63 struct xen_platform_op op
= INIT_EFI_OP(set_time
);
65 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_time
));
66 memcpy(&efi_data(op
).u
.set_time
, tm
, sizeof(*tm
));
68 if (HYPERVISOR_dom0_op(&op
) < 0)
69 return EFI_UNSUPPORTED
;
71 return efi_data(op
).status
;
74 static efi_status_t
xen_efi_get_wakeup_time(efi_bool_t
*enabled
,
78 struct xen_platform_op op
= INIT_EFI_OP(get_wakeup_time
);
80 if (HYPERVISOR_dom0_op(&op
) < 0)
81 return EFI_UNSUPPORTED
;
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
));
89 *enabled
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_ENABLED
);
92 *pending
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_PENDING
);
94 return efi_data(op
).status
;
97 static efi_status_t
xen_efi_set_wakeup_time(efi_bool_t enabled
, efi_time_t
*tm
)
99 struct xen_platform_op op
= INIT_EFI_OP(set_wakeup_time
);
101 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_wakeup_time
));
103 efi_data(op
).misc
= XEN_EFI_SET_WAKEUP_TIME_ENABLE
;
105 memcpy(&efi_data(op
).u
.set_wakeup_time
, tm
, sizeof(*tm
));
107 efi_data(op
).misc
|= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY
;
109 if (HYPERVISOR_dom0_op(&op
) < 0)
110 return EFI_UNSUPPORTED
;
112 return efi_data(op
).status
;
115 static efi_status_t
xen_efi_get_variable(efi_char16_t
*name
,
118 unsigned long *data_size
,
121 struct xen_platform_op op
= INIT_EFI_OP(get_variable
);
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
);
130 if (HYPERVISOR_dom0_op(&op
) < 0)
131 return EFI_UNSUPPORTED
;
133 *data_size
= efi_data(op
).u
.get_variable
.size
;
135 *attr
= efi_data(op
).misc
;
137 return efi_data(op
).status
;
140 static efi_status_t
xen_efi_get_next_variable(unsigned long *name_size
,
144 struct xen_platform_op op
= INIT_EFI_OP(get_next_variable_name
);
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
,
153 if (HYPERVISOR_dom0_op(&op
) < 0)
154 return EFI_UNSUPPORTED
;
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
,
160 return efi_data(op
).status
;
163 static efi_status_t
xen_efi_set_variable(efi_char16_t
*name
,
166 unsigned long data_size
,
169 struct xen_platform_op op
= INIT_EFI_OP(set_variable
);
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
);
179 if (HYPERVISOR_dom0_op(&op
) < 0)
180 return EFI_UNSUPPORTED
;
182 return efi_data(op
).status
;
185 static efi_status_t
xen_efi_query_variable_info(u32 attr
,
187 u64
*remaining_space
,
188 u64
*max_variable_size
)
190 struct xen_platform_op op
= INIT_EFI_OP(query_variable_info
);
192 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
193 return EFI_UNSUPPORTED
;
195 efi_data(op
).u
.query_variable_info
.attr
= attr
;
197 if (HYPERVISOR_dom0_op(&op
) < 0)
198 return EFI_UNSUPPORTED
;
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
;
204 return efi_data(op
).status
;
207 static efi_status_t
xen_efi_get_next_high_mono_count(u32
*count
)
209 struct xen_platform_op op
= INIT_EFI_OP(get_next_high_monotonic_count
);
211 if (HYPERVISOR_dom0_op(&op
) < 0)
212 return EFI_UNSUPPORTED
;
214 *count
= efi_data(op
).misc
;
216 return efi_data(op
).status
;
219 static efi_status_t
xen_efi_update_capsule(efi_capsule_header_t
**capsules
,
221 unsigned long sg_list
)
223 struct xen_platform_op op
= INIT_EFI_OP(update_capsule
);
225 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
226 return EFI_UNSUPPORTED
;
228 set_xen_guest_handle(efi_data(op
).u
.update_capsule
.capsule_header_array
,
230 efi_data(op
).u
.update_capsule
.capsule_count
= count
;
231 efi_data(op
).u
.update_capsule
.sg_list
= sg_list
;
233 if (HYPERVISOR_dom0_op(&op
) < 0)
234 return EFI_UNSUPPORTED
;
236 return efi_data(op
).status
;
239 static efi_status_t
xen_efi_query_capsule_caps(efi_capsule_header_t
**capsules
,
244 struct xen_platform_op op
= INIT_EFI_OP(query_capsule_capabilities
);
246 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
247 return EFI_UNSUPPORTED
;
249 set_xen_guest_handle(efi_data(op
).u
.query_capsule_capabilities
.capsule_header_array
,
251 efi_data(op
).u
.query_capsule_capabilities
.capsule_count
= count
;
253 if (HYPERVISOR_dom0_op(&op
) < 0)
254 return EFI_UNSUPPORTED
;
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
;
259 return efi_data(op
).status
;
262 static efi_char16_t vendor
[100] __initdata
;
264 static efi_system_table_t efi_systab_xen __initdata
= {
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. */
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. */
288 static 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. */
320 efi_system_table_t __init
*xen_efi_probe(void)
322 struct xen_platform_op op
= {
323 .cmd
= XENPF_firmware_info
,
325 .type
= XEN_FW_EFI_INFO
,
326 .index
= XEN_FW_EFI_CONFIG_TABLE
329 union xenpf_efi_info
*info
= &op
.u
.firmware_info
.u
.efi_info
;
331 if (!xen_initial_domain() || HYPERVISOR_dom0_op(&op
) < 0)
334 /* Here we know that Xen runs on EFI platform. */
338 efi_systab_xen
.tables
= info
->cfg
.addr
;
339 efi_systab_xen
.nr_tables
= info
->cfg
.nent
;
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
);
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
;
351 efi_systab_xen
.fw_vendor
= __pa_symbol(L
"UNKNOWN");
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
;
357 if (HYPERVISOR_dom0_op(&op
) == 0)
358 efi_systab_xen
.hdr
.revision
= info
->version
;
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
;
364 if (HYPERVISOR_dom0_op(&op
) == 0)
365 efi
.runtime_version
= info
->version
;
367 return &efi_systab_xen
;