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>
30 #include <xen/xen-ops.h>
34 #include <asm/xen/hypercall.h>
36 #define INIT_EFI_OP(name) \
37 {.cmd = XENPF_efi_runtime_call, \
38 .u.efi_runtime_call.function = XEN_EFI_##name, \
39 .u.efi_runtime_call.misc = 0}
41 #define efi_data(op) (op.u.efi_runtime_call)
43 static efi_status_t
xen_efi_get_time(efi_time_t
*tm
, efi_time_cap_t
*tc
)
45 struct xen_platform_op op
= INIT_EFI_OP(get_time
);
47 if (HYPERVISOR_platform_op(&op
) < 0)
48 return EFI_UNSUPPORTED
;
51 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_time
.time
));
52 memcpy(tm
, &efi_data(op
).u
.get_time
.time
, sizeof(*tm
));
56 tc
->resolution
= efi_data(op
).u
.get_time
.resolution
;
57 tc
->accuracy
= efi_data(op
).u
.get_time
.accuracy
;
58 tc
->sets_to_zero
= !!(efi_data(op
).misc
&
59 XEN_EFI_GET_TIME_SET_CLEARS_NS
);
62 return efi_data(op
).status
;
65 static efi_status_t
xen_efi_set_time(efi_time_t
*tm
)
67 struct xen_platform_op op
= INIT_EFI_OP(set_time
);
69 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_time
));
70 memcpy(&efi_data(op
).u
.set_time
, tm
, sizeof(*tm
));
72 if (HYPERVISOR_platform_op(&op
) < 0)
73 return EFI_UNSUPPORTED
;
75 return efi_data(op
).status
;
78 static efi_status_t
xen_efi_get_wakeup_time(efi_bool_t
*enabled
,
82 struct xen_platform_op op
= INIT_EFI_OP(get_wakeup_time
);
84 if (HYPERVISOR_platform_op(&op
) < 0)
85 return EFI_UNSUPPORTED
;
88 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.get_wakeup_time
));
89 memcpy(tm
, &efi_data(op
).u
.get_wakeup_time
, sizeof(*tm
));
93 *enabled
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_ENABLED
);
96 *pending
= !!(efi_data(op
).misc
& XEN_EFI_GET_WAKEUP_TIME_PENDING
);
98 return efi_data(op
).status
;
101 static efi_status_t
xen_efi_set_wakeup_time(efi_bool_t enabled
, efi_time_t
*tm
)
103 struct xen_platform_op op
= INIT_EFI_OP(set_wakeup_time
);
105 BUILD_BUG_ON(sizeof(*tm
) != sizeof(efi_data(op
).u
.set_wakeup_time
));
107 efi_data(op
).misc
= XEN_EFI_SET_WAKEUP_TIME_ENABLE
;
109 memcpy(&efi_data(op
).u
.set_wakeup_time
, tm
, sizeof(*tm
));
111 efi_data(op
).misc
|= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY
;
113 if (HYPERVISOR_platform_op(&op
) < 0)
114 return EFI_UNSUPPORTED
;
116 return efi_data(op
).status
;
119 static efi_status_t
xen_efi_get_variable(efi_char16_t
*name
, efi_guid_t
*vendor
,
120 u32
*attr
, 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_platform_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_platform_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
, efi_guid_t
*vendor
,
166 u32 attr
, 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_platform_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
, u64
*storage_space
,
186 u64
*remaining_space
,
187 u64
*max_variable_size
)
189 struct xen_platform_op op
= INIT_EFI_OP(query_variable_info
);
191 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
192 return EFI_UNSUPPORTED
;
194 efi_data(op
).u
.query_variable_info
.attr
= attr
;
196 if (HYPERVISOR_platform_op(&op
) < 0)
197 return EFI_UNSUPPORTED
;
199 *storage_space
= efi_data(op
).u
.query_variable_info
.max_store_size
;
200 *remaining_space
= efi_data(op
).u
.query_variable_info
.remain_store_size
;
201 *max_variable_size
= efi_data(op
).u
.query_variable_info
.max_size
;
203 return efi_data(op
).status
;
206 static efi_status_t
xen_efi_get_next_high_mono_count(u32
*count
)
208 struct xen_platform_op op
= INIT_EFI_OP(get_next_high_monotonic_count
);
210 if (HYPERVISOR_platform_op(&op
) < 0)
211 return EFI_UNSUPPORTED
;
213 *count
= efi_data(op
).misc
;
215 return efi_data(op
).status
;
218 static efi_status_t
xen_efi_update_capsule(efi_capsule_header_t
**capsules
,
219 unsigned long count
, unsigned long sg_list
)
221 struct xen_platform_op op
= INIT_EFI_OP(update_capsule
);
223 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
224 return EFI_UNSUPPORTED
;
226 set_xen_guest_handle(efi_data(op
).u
.update_capsule
.capsule_header_array
,
228 efi_data(op
).u
.update_capsule
.capsule_count
= count
;
229 efi_data(op
).u
.update_capsule
.sg_list
= sg_list
;
231 if (HYPERVISOR_platform_op(&op
) < 0)
232 return EFI_UNSUPPORTED
;
234 return efi_data(op
).status
;
237 static efi_status_t
xen_efi_query_capsule_caps(efi_capsule_header_t
**capsules
,
238 unsigned long count
, u64
*max_size
, int *reset_type
)
240 struct xen_platform_op op
= INIT_EFI_OP(query_capsule_capabilities
);
242 if (efi
.runtime_version
< EFI_2_00_SYSTEM_TABLE_REVISION
)
243 return EFI_UNSUPPORTED
;
245 set_xen_guest_handle(efi_data(op
).u
.query_capsule_capabilities
.capsule_header_array
,
247 efi_data(op
).u
.query_capsule_capabilities
.capsule_count
= count
;
249 if (HYPERVISOR_platform_op(&op
) < 0)
250 return EFI_UNSUPPORTED
;
252 *max_size
= efi_data(op
).u
.query_capsule_capabilities
.max_capsule_size
;
253 *reset_type
= efi_data(op
).u
.query_capsule_capabilities
.reset_type
;
255 return efi_data(op
).status
;
258 static void xen_efi_reset_system(int reset_type
, efi_status_t status
,
259 unsigned long data_size
, efi_char16_t
*data
)
261 switch (reset_type
) {
264 xen_reboot(SHUTDOWN_reboot
);
266 case EFI_RESET_SHUTDOWN
:
267 xen_reboot(SHUTDOWN_poweroff
);
275 * Set XEN EFI runtime services function pointers. Other fields of struct efi,
276 * e.g. efi.systab, will be set like normal EFI.
278 void __init
xen_efi_runtime_setup(void)
280 efi
.get_time
= xen_efi_get_time
;
281 efi
.set_time
= xen_efi_set_time
;
282 efi
.get_wakeup_time
= xen_efi_get_wakeup_time
;
283 efi
.set_wakeup_time
= xen_efi_set_wakeup_time
;
284 efi
.get_variable
= xen_efi_get_variable
;
285 efi
.get_next_variable
= xen_efi_get_next_variable
;
286 efi
.set_variable
= xen_efi_set_variable
;
287 efi
.set_variable_nonblocking
= xen_efi_set_variable
;
288 efi
.query_variable_info
= xen_efi_query_variable_info
;
289 efi
.query_variable_info_nonblocking
= xen_efi_query_variable_info
;
290 efi
.update_capsule
= xen_efi_update_capsule
;
291 efi
.query_capsule_caps
= xen_efi_query_capsule_caps
;
292 efi
.get_next_high_mono_count
= xen_efi_get_next_high_mono_count
;
293 efi
.reset_system
= xen_efi_reset_system
;