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/page.h> 30 #include <xen/xen.h> 31 #include <xen/xen-ops.h> 32 33 #include <asm/page.h> 34 35 #include <asm/xen/hypercall.h> 36 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} 41 42 #define efi_data(op) (op.u.efi_runtime_call) 43 44 static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 45 { 46 struct xen_platform_op op = INIT_EFI_OP(get_time); 47 48 if (HYPERVISOR_platform_op(&op) < 0) 49 return EFI_UNSUPPORTED; 50 51 if (tm) { 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)); 54 } 55 56 if (tc) { 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); 61 } 62 63 return efi_data(op).status; 64 } 65 66 static 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 79 static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled, 80 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 102 static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 103 { 104 struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time); 105 106 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time)); 107 if (enabled) 108 efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE; 109 if (tm) 110 memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm)); 111 else 112 efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY; 113 114 if (HYPERVISOR_platform_op(&op) < 0) 115 return EFI_UNSUPPORTED; 116 117 return efi_data(op).status; 118 } 119 120 static efi_status_t xen_efi_get_variable(efi_char16_t *name, efi_guid_t *vendor, 121 u32 *attr, unsigned long *data_size, 122 void *data) 123 { 124 struct xen_platform_op op = INIT_EFI_OP(get_variable); 125 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); 132 133 if (HYPERVISOR_platform_op(&op) < 0) 134 return EFI_UNSUPPORTED; 135 136 *data_size = efi_data(op).u.get_variable.size; 137 if (attr) 138 *attr = efi_data(op).misc; 139 140 return efi_data(op).status; 141 } 142 143 static efi_status_t xen_efi_get_next_variable(unsigned long *name_size, 144 efi_char16_t *name, 145 efi_guid_t *vendor) 146 { 147 struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name); 148 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, 154 sizeof(*vendor)); 155 156 if (HYPERVISOR_platform_op(&op) < 0) 157 return EFI_UNSUPPORTED; 158 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, 161 sizeof(*vendor)); 162 163 return efi_data(op).status; 164 } 165 166 static efi_status_t xen_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor, 167 u32 attr, unsigned long data_size, 168 void *data) 169 { 170 struct xen_platform_op op = INIT_EFI_OP(set_variable); 171 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); 179 180 if (HYPERVISOR_platform_op(&op) < 0) 181 return EFI_UNSUPPORTED; 182 183 return efi_data(op).status; 184 } 185 186 static efi_status_t xen_efi_query_variable_info(u32 attr, u64 *storage_space, 187 u64 *remaining_space, 188 u64 *max_variable_size) 189 { 190 struct xen_platform_op op = INIT_EFI_OP(query_variable_info); 191 192 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 193 return EFI_UNSUPPORTED; 194 195 efi_data(op).u.query_variable_info.attr = attr; 196 197 if (HYPERVISOR_platform_op(&op) < 0) 198 return EFI_UNSUPPORTED; 199 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; 203 204 return efi_data(op).status; 205 } 206 207 static efi_status_t xen_efi_get_next_high_mono_count(u32 *count) 208 { 209 struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count); 210 211 if (HYPERVISOR_platform_op(&op) < 0) 212 return EFI_UNSUPPORTED; 213 214 *count = efi_data(op).misc; 215 216 return efi_data(op).status; 217 } 218 219 static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules, 220 unsigned long count, unsigned long sg_list) 221 { 222 struct xen_platform_op op = INIT_EFI_OP(update_capsule); 223 224 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 225 return EFI_UNSUPPORTED; 226 227 set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array, 228 capsules); 229 efi_data(op).u.update_capsule.capsule_count = count; 230 efi_data(op).u.update_capsule.sg_list = sg_list; 231 232 if (HYPERVISOR_platform_op(&op) < 0) 233 return EFI_UNSUPPORTED; 234 235 return efi_data(op).status; 236 } 237 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) 240 { 241 struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities); 242 243 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 244 return EFI_UNSUPPORTED; 245 246 set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array, 247 capsules); 248 efi_data(op).u.query_capsule_capabilities.capsule_count = count; 249 250 if (HYPERVISOR_platform_op(&op) < 0) 251 return EFI_UNSUPPORTED; 252 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; 255 256 return efi_data(op).status; 257 } 258 259 static void xen_efi_reset_system(int reset_type, efi_status_t status, 260 unsigned long data_size, efi_char16_t *data) 261 { 262 switch (reset_type) { 263 case EFI_RESET_COLD: 264 case EFI_RESET_WARM: 265 xen_reboot(SHUTDOWN_reboot); 266 break; 267 case EFI_RESET_SHUTDOWN: 268 xen_reboot(SHUTDOWN_poweroff); 269 break; 270 default: 271 BUG(); 272 } 273 } 274 275 /* 276 * Set XEN EFI runtime services function pointers. Other fields of struct efi, 277 * e.g. efi.systab, will be set like normal EFI. 278 */ 279 void __init xen_efi_runtime_setup(void) 280 { 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; 295 } 296 297 int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) 298 { 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; 303 int rc; 304 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, 310 .u.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, 315 }, 316 }; 317 318 rc = HYPERVISOR_platform_op(&op); 319 if (rc) { 320 pr_warn("Failed to lookup header 0x%llx in Xen memory map: error %d\n", 321 phys_addr, rc); 322 } 323 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; 328 329 return 0; 330 } 331 332 bool __init xen_efi_config_table_is_usable(const efi_guid_t *guid, 333 unsigned long table) 334 { 335 efi_memory_desc_t md; 336 int rc; 337 338 if (!efi_enabled(EFI_PARAVIRT)) 339 return true; 340 341 rc = efi_mem_desc_lookup(table, &md); 342 if (rc) 343 return false; 344 345 switch (md.type) { 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: 351 return true; 352 default: 353 return false; 354 } 355 } 356