1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * EFI support for Xen. 4 * 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 20 */ 21 22 #include <linux/bug.h> 23 #include <linux/efi.h> 24 #include <linux/init.h> 25 #include <linux/string.h> 26 27 #include <xen/interface/xen.h> 28 #include <xen/interface/platform.h> 29 #include <xen/xen.h> 30 #include <xen/xen-ops.h> 31 32 #include <asm/page.h> 33 34 #include <asm/xen/hypercall.h> 35 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} 40 41 #define efi_data(op) (op.u.efi_runtime_call) 42 43 efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 44 { 45 struct xen_platform_op op = INIT_EFI_OP(get_time); 46 47 if (HYPERVISOR_platform_op(&op) < 0) 48 return EFI_UNSUPPORTED; 49 50 if (tm) { 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)); 53 } 54 55 if (tc) { 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); 60 } 61 62 return efi_data(op).status; 63 } 64 EXPORT_SYMBOL_GPL(xen_efi_get_time); 65 66 efi_status_t xen_efi_set_time(efi_time_t *tm) 67 { 68 struct xen_platform_op op = INIT_EFI_OP(set_time); 69 70 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time)); 71 memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm)); 72 73 if (HYPERVISOR_platform_op(&op) < 0) 74 return EFI_UNSUPPORTED; 75 76 return efi_data(op).status; 77 } 78 EXPORT_SYMBOL_GPL(xen_efi_set_time); 79 80 efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled, efi_bool_t *pending, 81 efi_time_t *tm) 82 { 83 struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time); 84 85 if (HYPERVISOR_platform_op(&op) < 0) 86 return EFI_UNSUPPORTED; 87 88 if (tm) { 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)); 91 } 92 93 if (enabled) 94 *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED); 95 96 if (pending) 97 *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING); 98 99 return efi_data(op).status; 100 } 101 EXPORT_SYMBOL_GPL(xen_efi_get_wakeup_time); 102 103 efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 104 { 105 struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time); 106 107 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time)); 108 if (enabled) 109 efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE; 110 if (tm) 111 memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm)); 112 else 113 efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY; 114 115 if (HYPERVISOR_platform_op(&op) < 0) 116 return EFI_UNSUPPORTED; 117 118 return efi_data(op).status; 119 } 120 EXPORT_SYMBOL_GPL(xen_efi_set_wakeup_time); 121 122 efi_status_t xen_efi_get_variable(efi_char16_t *name, efi_guid_t *vendor, 123 u32 *attr, unsigned long *data_size, 124 void *data) 125 { 126 struct xen_platform_op op = INIT_EFI_OP(get_variable); 127 128 set_xen_guest_handle(efi_data(op).u.get_variable.name, name); 129 BUILD_BUG_ON(sizeof(*vendor) != 130 sizeof(efi_data(op).u.get_variable.vendor_guid)); 131 memcpy(&efi_data(op).u.get_variable.vendor_guid, vendor, sizeof(*vendor)); 132 efi_data(op).u.get_variable.size = *data_size; 133 set_xen_guest_handle(efi_data(op).u.get_variable.data, data); 134 135 if (HYPERVISOR_platform_op(&op) < 0) 136 return EFI_UNSUPPORTED; 137 138 *data_size = efi_data(op).u.get_variable.size; 139 if (attr) 140 *attr = efi_data(op).misc; 141 142 return efi_data(op).status; 143 } 144 EXPORT_SYMBOL_GPL(xen_efi_get_variable); 145 146 efi_status_t xen_efi_get_next_variable(unsigned long *name_size, 147 efi_char16_t *name, 148 efi_guid_t *vendor) 149 { 150 struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name); 151 152 efi_data(op).u.get_next_variable_name.size = *name_size; 153 set_xen_guest_handle(efi_data(op).u.get_next_variable_name.name, name); 154 BUILD_BUG_ON(sizeof(*vendor) != 155 sizeof(efi_data(op).u.get_next_variable_name.vendor_guid)); 156 memcpy(&efi_data(op).u.get_next_variable_name.vendor_guid, vendor, 157 sizeof(*vendor)); 158 159 if (HYPERVISOR_platform_op(&op) < 0) 160 return EFI_UNSUPPORTED; 161 162 *name_size = efi_data(op).u.get_next_variable_name.size; 163 memcpy(vendor, &efi_data(op).u.get_next_variable_name.vendor_guid, 164 sizeof(*vendor)); 165 166 return efi_data(op).status; 167 } 168 EXPORT_SYMBOL_GPL(xen_efi_get_next_variable); 169 170 efi_status_t xen_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor, 171 u32 attr, unsigned long data_size, 172 void *data) 173 { 174 struct xen_platform_op op = INIT_EFI_OP(set_variable); 175 176 set_xen_guest_handle(efi_data(op).u.set_variable.name, name); 177 efi_data(op).misc = attr; 178 BUILD_BUG_ON(sizeof(*vendor) != 179 sizeof(efi_data(op).u.set_variable.vendor_guid)); 180 memcpy(&efi_data(op).u.set_variable.vendor_guid, vendor, sizeof(*vendor)); 181 efi_data(op).u.set_variable.size = data_size; 182 set_xen_guest_handle(efi_data(op).u.set_variable.data, data); 183 184 if (HYPERVISOR_platform_op(&op) < 0) 185 return EFI_UNSUPPORTED; 186 187 return efi_data(op).status; 188 } 189 EXPORT_SYMBOL_GPL(xen_efi_set_variable); 190 191 efi_status_t xen_efi_query_variable_info(u32 attr, u64 *storage_space, 192 u64 *remaining_space, 193 u64 *max_variable_size) 194 { 195 struct xen_platform_op op = INIT_EFI_OP(query_variable_info); 196 197 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 198 return EFI_UNSUPPORTED; 199 200 efi_data(op).u.query_variable_info.attr = attr; 201 202 if (HYPERVISOR_platform_op(&op) < 0) 203 return EFI_UNSUPPORTED; 204 205 *storage_space = efi_data(op).u.query_variable_info.max_store_size; 206 *remaining_space = efi_data(op).u.query_variable_info.remain_store_size; 207 *max_variable_size = efi_data(op).u.query_variable_info.max_size; 208 209 return efi_data(op).status; 210 } 211 EXPORT_SYMBOL_GPL(xen_efi_query_variable_info); 212 213 efi_status_t xen_efi_get_next_high_mono_count(u32 *count) 214 { 215 struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count); 216 217 if (HYPERVISOR_platform_op(&op) < 0) 218 return EFI_UNSUPPORTED; 219 220 *count = efi_data(op).misc; 221 222 return efi_data(op).status; 223 } 224 EXPORT_SYMBOL_GPL(xen_efi_get_next_high_mono_count); 225 226 efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules, 227 unsigned long count, unsigned long sg_list) 228 { 229 struct xen_platform_op op = INIT_EFI_OP(update_capsule); 230 231 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 232 return EFI_UNSUPPORTED; 233 234 set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array, 235 capsules); 236 efi_data(op).u.update_capsule.capsule_count = count; 237 efi_data(op).u.update_capsule.sg_list = sg_list; 238 239 if (HYPERVISOR_platform_op(&op) < 0) 240 return EFI_UNSUPPORTED; 241 242 return efi_data(op).status; 243 } 244 EXPORT_SYMBOL_GPL(xen_efi_update_capsule); 245 246 efi_status_t xen_efi_query_capsule_caps(efi_capsule_header_t **capsules, 247 unsigned long count, u64 *max_size, 248 int *reset_type) 249 { 250 struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities); 251 252 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 253 return EFI_UNSUPPORTED; 254 255 set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array, 256 capsules); 257 efi_data(op).u.query_capsule_capabilities.capsule_count = count; 258 259 if (HYPERVISOR_platform_op(&op) < 0) 260 return EFI_UNSUPPORTED; 261 262 *max_size = efi_data(op).u.query_capsule_capabilities.max_capsule_size; 263 *reset_type = efi_data(op).u.query_capsule_capabilities.reset_type; 264 265 return efi_data(op).status; 266 } 267 EXPORT_SYMBOL_GPL(xen_efi_query_capsule_caps); 268 269 void xen_efi_reset_system(int reset_type, efi_status_t status, 270 unsigned long data_size, efi_char16_t *data) 271 { 272 switch (reset_type) { 273 case EFI_RESET_COLD: 274 case EFI_RESET_WARM: 275 xen_reboot(SHUTDOWN_reboot); 276 break; 277 case EFI_RESET_SHUTDOWN: 278 xen_reboot(SHUTDOWN_poweroff); 279 break; 280 default: 281 BUG(); 282 } 283 } 284 EXPORT_SYMBOL_GPL(xen_efi_reset_system); 285