1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 1999 VA Linux Systems
6 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
7 * Copyright (C) 1999-2002 Hewlett-Packard Co.
8 * David Mosberger-Tang <davidm@hpl.hp.com>
9 * Stephane Eranian <eranian@hpl.hp.com>
10 * Copyright (C) 2005-2008 Intel Co.
11 * Fenghua Yu <fenghua.yu@intel.com>
12 * Bibo Mao <bibo.mao@intel.com>
13 * Chandramouli Narayanan <mouli@linux.intel.com>
14 * Huang Ying <ying.huang@intel.com>
15 * Copyright (C) 2011 Novell Co.
16 * Jan Beulich <JBeulich@suse.com>
17 * Copyright (C) 2011-2012 Oracle Co.
18 * Liang Tang <liang.tang@oracle.com>
19 * Copyright (c) 2014 Oracle Co., Daniel Kiper
22 #include <linux/bug.h>
23 #include <linux/efi.h>
24 #include <linux/init.h>
25 #include <linux/string.h>
27 #include <xen/interface/xen.h>
28 #include <xen/interface/platform.h>
31 #include <xen/xen-ops.h>
35 #include <asm/xen/hypercall.h>
37 #define INIT_EFI_OP(name) \
38 {.cmd = XENPF_efi_runtime_call, \
39 .u.efi_runtime_call.function = XEN_EFI_##name, \
40 .u.efi_runtime_call.misc = 0}
42 #define efi_data(op) (op.u.efi_runtime_call)
44 static efi_status_t
xen_efi_get_time(efi_time_t
*tm
, efi_time_cap_t
*tc
)
46 struct xen_platform_op op
= INIT_EFI_OP(get_time
);
48 if (HYPERVISOR_platform_op(&op
) < 0)
49 return EFI_UNSUPPORTED
;
52 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_time
.time
));
53 memcpy(tm
, &efi_data(op
).u
.get_time
.time
, sizeof(*tm
));
57 tc
->resolution
= efi_data(op
).u
.get_time
.resolution
;
58 tc
->accuracy
= efi_data(op
).u
.get_time
.accuracy
;
59 tc
->sets_to_zero
= !!(efi_data(op
).misc
&
60 XEN_EFI_GET_TIME_SET_CLEARS_NS
);
63 return efi_data(op
).status
;
66 static efi_status_t
xen_efi_set_time(efi_time_t
*tm
)
68 struct xen_platform_op op
= INIT_EFI_OP(set_time
);
70 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_time
));
71 memcpy(&efi_data(op
).u
.set_time
, tm
, sizeof(*tm
));
73 if (HYPERVISOR_platform_op(&op
) < 0)
74 return EFI_UNSUPPORTED
;
76 return efi_data(op
).status
;
79 static efi_status_t
xen_efi_get_wakeup_time(efi_bool_t
*enabled
,
83 struct xen_platform_op op
= INIT_EFI_OP(get_wakeup_time
);
85 if (HYPERVISOR_platform_op(&op
) < 0)
86 return EFI_UNSUPPORTED
;
89 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_wakeup_time
));
90 memcpy(tm
, &efi_data(op
).u
.get_wakeup_time
, sizeof(*tm
));
94 *enabled
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_ENABLED
);
97 *pending
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_PENDING
);
99 return efi_data(op
).status
;
102 static efi_status_t
xen_efi_set_wakeup_time(efi_bool_t enabled
, efi_time_t
*tm
)
104 struct xen_platform_op op
= INIT_EFI_OP(set_wakeup_time
);
106 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_wakeup_time
));
108 efi_data(op
).misc
= XEN_EFI_SET_WAKEUP_TIME_ENABLE
;
110 memcpy(&efi_data(op
).u
.set_wakeup_time
, tm
, sizeof(*tm
));
112 efi_data(op
).misc
|= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY
;
114 if (HYPERVISOR_platform_op(&op
) < 0)
115 return EFI_UNSUPPORTED
;
117 return efi_data(op
).status
;
120 static efi_status_t
xen_efi_get_variable(efi_char16_t
*name
, efi_guid_t
*vendor
,
121 u32
*attr
, unsigned long *data_size
,
124 struct xen_platform_op op
= INIT_EFI_OP(get_variable
);
126 set_xen_guest_handle(efi_data(op
).u
.get_variable
.name
, name
);
127 BUILD_BUG_ON(sizeof(*vendor
) !=
128 sizeof(efi_data(op
).u
.get_variable
.vendor_guid
));
129 memcpy(&efi_data(op
).u
.get_variable
.vendor_guid
, vendor
, sizeof(*vendor
));
130 efi_data(op
).u
.get_variable
.size
= *data_size
;
131 set_xen_guest_handle(efi_data(op
).u
.get_variable
.data
, data
);
133 if (HYPERVISOR_platform_op(&op
) < 0)
134 return EFI_UNSUPPORTED
;
136 *data_size
= efi_data(op
).u
.get_variable
.size
;
138 *attr
= efi_data(op
).misc
;
140 return efi_data(op
).status
;
143 static efi_status_t
xen_efi_get_next_variable(unsigned long *name_size
,
147 struct xen_platform_op op
= INIT_EFI_OP(get_next_variable_name
);
149 efi_data(op
).u
.get_next_variable_name
.size
= *name_size
;
150 set_xen_guest_handle(efi_data(op
).u
.get_next_variable_name
.name
, name
);
151 BUILD_BUG_ON(sizeof(*vendor
) !=
152 sizeof(efi_data(op
).u
.get_next_variable_name
.vendor_guid
));
153 memcpy(&efi_data(op
).u
.get_next_variable_name
.vendor_guid
, vendor
,
156 if (HYPERVISOR_platform_op(&op
) < 0)
157 return EFI_UNSUPPORTED
;
159 *name_size
= efi_data(op
).u
.get_next_variable_name
.size
;
160 memcpy(vendor
, &efi_data(op
).u
.get_next_variable_name
.vendor_guid
,
163 return efi_data(op
).status
;
166 static efi_status_t
xen_efi_set_variable(efi_char16_t
*name
, efi_guid_t
*vendor
,
167 u32 attr
, unsigned long data_size
,
170 struct xen_platform_op op
= INIT_EFI_OP(set_variable
);
172 set_xen_guest_handle(efi_data(op
).u
.set_variable
.name
, name
);
173 efi_data(op
).misc
= attr
;
174 BUILD_BUG_ON(sizeof(*vendor
) !=
175 sizeof(efi_data(op
).u
.set_variable
.vendor_guid
));
176 memcpy(&efi_data(op
).u
.set_variable
.vendor_guid
, vendor
, sizeof(*vendor
));
177 efi_data(op
).u
.set_variable
.size
= data_size
;
178 set_xen_guest_handle(efi_data(op
).u
.set_variable
.data
, data
);
180 if (HYPERVISOR_platform_op(&op
) < 0)
181 return EFI_UNSUPPORTED
;
183 return efi_data(op
).status
;
186 static efi_status_t
xen_efi_query_variable_info(u32 attr
, u64
*storage_space
,
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_platform_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_platform_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
,
220 unsigned long count
, unsigned long sg_list
)
222 struct xen_platform_op op
= INIT_EFI_OP(update_capsule
);
224 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
225 return EFI_UNSUPPORTED
;
227 set_xen_guest_handle(efi_data(op
).u
.update_capsule
.capsule_header_array
,
229 efi_data(op
).u
.update_capsule
.capsule_count
= count
;
230 efi_data(op
).u
.update_capsule
.sg_list
= sg_list
;
232 if (HYPERVISOR_platform_op(&op
) < 0)
233 return EFI_UNSUPPORTED
;
235 return efi_data(op
).status
;
238 static efi_status_t
xen_efi_query_capsule_caps(efi_capsule_header_t
**capsules
,
239 unsigned long count
, u64
*max_size
, int *reset_type
)
241 struct xen_platform_op op
= INIT_EFI_OP(query_capsule_capabilities
);
243 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
244 return EFI_UNSUPPORTED
;
246 set_xen_guest_handle(efi_data(op
).u
.query_capsule_capabilities
.capsule_header_array
,
248 efi_data(op
).u
.query_capsule_capabilities
.capsule_count
= count
;
250 if (HYPERVISOR_platform_op(&op
) < 0)
251 return EFI_UNSUPPORTED
;
253 *max_size
= efi_data(op
).u
.query_capsule_capabilities
.max_capsule_size
;
254 *reset_type
= efi_data(op
).u
.query_capsule_capabilities
.reset_type
;
256 return efi_data(op
).status
;
259 static void xen_efi_reset_system(int reset_type
, efi_status_t status
,
260 unsigned long data_size
, efi_char16_t
*data
)
262 switch (reset_type
) {
265 xen_reboot(SHUTDOWN_reboot
);
267 case EFI_RESET_SHUTDOWN
:
268 xen_reboot(SHUTDOWN_poweroff
);
276 * Set XEN EFI runtime services function pointers. Other fields of struct efi,
277 * e.g. efi.systab, will be set like normal EFI.
279 void __init
xen_efi_runtime_setup(void)
281 efi
.get_time
= xen_efi_get_time
;
282 efi
.set_time
= xen_efi_set_time
;
283 efi
.get_wakeup_time
= xen_efi_get_wakeup_time
;
284 efi
.set_wakeup_time
= xen_efi_set_wakeup_time
;
285 efi
.get_variable
= xen_efi_get_variable
;
286 efi
.get_next_variable
= xen_efi_get_next_variable
;
287 efi
.set_variable
= xen_efi_set_variable
;
288 efi
.set_variable_nonblocking
= xen_efi_set_variable
;
289 efi
.query_variable_info
= xen_efi_query_variable_info
;
290 efi
.query_variable_info_nonblocking
= xen_efi_query_variable_info
;
291 efi
.update_capsule
= xen_efi_update_capsule
;
292 efi
.query_capsule_caps
= xen_efi_query_capsule_caps
;
293 efi
.get_next_high_mono_count
= xen_efi_get_next_high_mono_count
;
294 efi
.reset_system
= xen_efi_reset_system
;
297 int efi_mem_desc_lookup(u64 phys_addr
, efi_memory_desc_t
*out_md
)
299 static_assert(XEN_PAGE_SHIFT
== EFI_PAGE_SHIFT
,
300 "Mismatch between EFI_PAGE_SHIFT and XEN_PAGE_SHIFT");
301 struct xen_platform_op op
;
302 union xenpf_efi_info
*info
= &op
.u
.firmware_info
.u
.efi_info
;
305 if (!efi_enabled(EFI_PARAVIRT
) || efi_enabled(EFI_MEMMAP
))
306 return __efi_mem_desc_lookup(phys_addr
, out_md
);
307 phys_addr
&= ~(u64
)(EFI_PAGE_SIZE
- 1);
308 op
= (struct xen_platform_op
) {
309 .cmd
= XENPF_firmware_info
,
311 .type
= XEN_FW_EFI_INFO
,
312 .index
= XEN_FW_EFI_MEM_INFO
,
313 .u
.efi_info
.mem
.addr
= phys_addr
,
314 .u
.efi_info
.mem
.size
= U64_MAX
- phys_addr
,
318 rc
= HYPERVISOR_platform_op(&op
);
320 pr_warn("Failed to lookup header 0x%llx in Xen memory map: error %d\n",
324 out_md
->phys_addr
= info
->mem
.addr
;
325 out_md
->num_pages
= info
->mem
.size
>> EFI_PAGE_SHIFT
;
326 out_md
->type
= info
->mem
.type
;
327 out_md
->attribute
= info
->mem
.attr
;
332 bool __init
xen_efi_config_table_is_usable(const efi_guid_t
*guid
,
335 efi_memory_desc_t md
;
338 if (!efi_enabled(EFI_PARAVIRT
))
341 rc
= efi_mem_desc_lookup(table
, &md
);
346 case EFI_RUNTIME_SERVICES_CODE
:
347 case EFI_RUNTIME_SERVICES_DATA
:
348 case EFI_ACPI_RECLAIM_MEMORY
:
349 case EFI_ACPI_MEMORY_NVS
:
350 case EFI_RESERVED_TYPE
: