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 static 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 65 static efi_status_t xen_efi_set_time(efi_time_t *tm) 66 { 67 struct xen_platform_op op = INIT_EFI_OP(set_time); 68 69 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_time)); 70 memcpy(&efi_data(op).u.set_time, tm, sizeof(*tm)); 71 72 if (HYPERVISOR_platform_op(&op) < 0) 73 return EFI_UNSUPPORTED; 74 75 return efi_data(op).status; 76 } 77 78 static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled, 79 efi_bool_t *pending, 80 efi_time_t *tm) 81 { 82 struct xen_platform_op op = INIT_EFI_OP(get_wakeup_time); 83 84 if (HYPERVISOR_platform_op(&op) < 0) 85 return EFI_UNSUPPORTED; 86 87 if (tm) { 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)); 90 } 91 92 if (enabled) 93 *enabled = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED); 94 95 if (pending) 96 *pending = !!(efi_data(op).misc & XEN_EFI_GET_WAKEUP_TIME_PENDING); 97 98 return efi_data(op).status; 99 } 100 101 static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 102 { 103 struct xen_platform_op op = INIT_EFI_OP(set_wakeup_time); 104 105 BUILD_BUG_ON(sizeof(*tm) != sizeof(efi_data(op).u.set_wakeup_time)); 106 if (enabled) 107 efi_data(op).misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE; 108 if (tm) 109 memcpy(&efi_data(op).u.set_wakeup_time, tm, sizeof(*tm)); 110 else 111 efi_data(op).misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY; 112 113 if (HYPERVISOR_platform_op(&op) < 0) 114 return EFI_UNSUPPORTED; 115 116 return efi_data(op).status; 117 } 118 119 static efi_status_t xen_efi_get_variable(efi_char16_t *name, efi_guid_t *vendor, 120 u32 *attr, unsigned long *data_size, 121 void *data) 122 { 123 struct xen_platform_op op = INIT_EFI_OP(get_variable); 124 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); 131 132 if (HYPERVISOR_platform_op(&op) < 0) 133 return EFI_UNSUPPORTED; 134 135 *data_size = efi_data(op).u.get_variable.size; 136 if (attr) 137 *attr = efi_data(op).misc; 138 139 return efi_data(op).status; 140 } 141 142 static efi_status_t xen_efi_get_next_variable(unsigned long *name_size, 143 efi_char16_t *name, 144 efi_guid_t *vendor) 145 { 146 struct xen_platform_op op = INIT_EFI_OP(get_next_variable_name); 147 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, 153 sizeof(*vendor)); 154 155 if (HYPERVISOR_platform_op(&op) < 0) 156 return EFI_UNSUPPORTED; 157 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, 160 sizeof(*vendor)); 161 162 return efi_data(op).status; 163 } 164 165 static efi_status_t xen_efi_set_variable(efi_char16_t *name, efi_guid_t *vendor, 166 u32 attr, unsigned long data_size, 167 void *data) 168 { 169 struct xen_platform_op op = INIT_EFI_OP(set_variable); 170 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); 178 179 if (HYPERVISOR_platform_op(&op) < 0) 180 return EFI_UNSUPPORTED; 181 182 return efi_data(op).status; 183 } 184 185 static efi_status_t xen_efi_query_variable_info(u32 attr, u64 *storage_space, 186 u64 *remaining_space, 187 u64 *max_variable_size) 188 { 189 struct xen_platform_op op = INIT_EFI_OP(query_variable_info); 190 191 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 192 return EFI_UNSUPPORTED; 193 194 efi_data(op).u.query_variable_info.attr = attr; 195 196 if (HYPERVISOR_platform_op(&op) < 0) 197 return EFI_UNSUPPORTED; 198 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; 202 203 return efi_data(op).status; 204 } 205 206 static efi_status_t xen_efi_get_next_high_mono_count(u32 *count) 207 { 208 struct xen_platform_op op = INIT_EFI_OP(get_next_high_monotonic_count); 209 210 if (HYPERVISOR_platform_op(&op) < 0) 211 return EFI_UNSUPPORTED; 212 213 *count = efi_data(op).misc; 214 215 return efi_data(op).status; 216 } 217 218 static efi_status_t xen_efi_update_capsule(efi_capsule_header_t **capsules, 219 unsigned long count, unsigned long sg_list) 220 { 221 struct xen_platform_op op = INIT_EFI_OP(update_capsule); 222 223 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 224 return EFI_UNSUPPORTED; 225 226 set_xen_guest_handle(efi_data(op).u.update_capsule.capsule_header_array, 227 capsules); 228 efi_data(op).u.update_capsule.capsule_count = count; 229 efi_data(op).u.update_capsule.sg_list = sg_list; 230 231 if (HYPERVISOR_platform_op(&op) < 0) 232 return EFI_UNSUPPORTED; 233 234 return efi_data(op).status; 235 } 236 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) 239 { 240 struct xen_platform_op op = INIT_EFI_OP(query_capsule_capabilities); 241 242 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 243 return EFI_UNSUPPORTED; 244 245 set_xen_guest_handle(efi_data(op).u.query_capsule_capabilities.capsule_header_array, 246 capsules); 247 efi_data(op).u.query_capsule_capabilities.capsule_count = count; 248 249 if (HYPERVISOR_platform_op(&op) < 0) 250 return EFI_UNSUPPORTED; 251 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; 254 255 return efi_data(op).status; 256 } 257 258 static void xen_efi_reset_system(int reset_type, efi_status_t status, 259 unsigned long data_size, efi_char16_t *data) 260 { 261 switch (reset_type) { 262 case EFI_RESET_COLD: 263 case EFI_RESET_WARM: 264 xen_reboot(SHUTDOWN_reboot); 265 break; 266 case EFI_RESET_SHUTDOWN: 267 xen_reboot(SHUTDOWN_poweroff); 268 break; 269 default: 270 BUG(); 271 } 272 } 273 274 /* 275 * Set XEN EFI runtime services function pointers. Other fields of struct efi, 276 * e.g. efi.systab, will be set like normal EFI. 277 */ 278 void __init xen_efi_runtime_setup(void) 279 { 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; 294 } 295