1 /* 2 * runtime-wrappers.c - Runtime Services function call wrappers 3 * 4 * Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org> 5 * 6 * Split off from arch/x86/platform/efi/efi.c 7 * 8 * Copyright (C) 1999 VA Linux Systems 9 * Copyright (C) 1999 Walt Drummond <drummond@valinux.com> 10 * Copyright (C) 1999-2002 Hewlett-Packard Co. 11 * Copyright (C) 2005-2008 Intel Co. 12 * Copyright (C) 2013 SuSE Labs 13 * 14 * This file is released under the GPLv2. 15 */ 16 17 #include <linux/bug.h> 18 #include <linux/efi.h> 19 #include <linux/mutex.h> 20 #include <linux/spinlock.h> 21 #include <asm/efi.h> 22 23 /* 24 * According to section 7.1 of the UEFI spec, Runtime Services are not fully 25 * reentrant, and there are particular combinations of calls that need to be 26 * serialized. (source: UEFI Specification v2.4A) 27 * 28 * Table 31. Rules for Reentry Into Runtime Services 29 * +------------------------------------+-------------------------------+ 30 * | If previous call is busy in | Forbidden to call | 31 * +------------------------------------+-------------------------------+ 32 * | Any | SetVirtualAddressMap() | 33 * +------------------------------------+-------------------------------+ 34 * | ConvertPointer() | ConvertPointer() | 35 * +------------------------------------+-------------------------------+ 36 * | SetVariable() | ResetSystem() | 37 * | UpdateCapsule() | | 38 * | SetTime() | | 39 * | SetWakeupTime() | | 40 * | GetNextHighMonotonicCount() | | 41 * +------------------------------------+-------------------------------+ 42 * | GetVariable() | GetVariable() | 43 * | GetNextVariableName() | GetNextVariableName() | 44 * | SetVariable() | SetVariable() | 45 * | QueryVariableInfo() | QueryVariableInfo() | 46 * | UpdateCapsule() | UpdateCapsule() | 47 * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | 48 * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | 49 * +------------------------------------+-------------------------------+ 50 * | GetTime() | GetTime() | 51 * | SetTime() | SetTime() | 52 * | GetWakeupTime() | GetWakeupTime() | 53 * | SetWakeupTime() | SetWakeupTime() | 54 * +------------------------------------+-------------------------------+ 55 * 56 * Due to the fact that the EFI pstore may write to the variable store in 57 * interrupt context, we need to use a spinlock for at least the groups that 58 * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 59 * none of the remaining functions are actually ever called at runtime. 60 * So let's just use a single spinlock to serialize all Runtime Services calls. 61 */ 62 static DEFINE_SPINLOCK(efi_runtime_lock); 63 64 static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 65 { 66 efi_status_t status; 67 68 spin_lock(&efi_runtime_lock); 69 status = efi_call_virt(get_time, tm, tc); 70 spin_unlock(&efi_runtime_lock); 71 return status; 72 } 73 74 static efi_status_t virt_efi_set_time(efi_time_t *tm) 75 { 76 efi_status_t status; 77 78 spin_lock(&efi_runtime_lock); 79 status = efi_call_virt(set_time, tm); 80 spin_unlock(&efi_runtime_lock); 81 return status; 82 } 83 84 static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled, 85 efi_bool_t *pending, 86 efi_time_t *tm) 87 { 88 efi_status_t status; 89 90 spin_lock(&efi_runtime_lock); 91 status = efi_call_virt(get_wakeup_time, enabled, pending, tm); 92 spin_unlock(&efi_runtime_lock); 93 return status; 94 } 95 96 static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm) 97 { 98 efi_status_t status; 99 100 spin_lock(&efi_runtime_lock); 101 status = efi_call_virt(set_wakeup_time, enabled, tm); 102 spin_unlock(&efi_runtime_lock); 103 return status; 104 } 105 106 static efi_status_t virt_efi_get_variable(efi_char16_t *name, 107 efi_guid_t *vendor, 108 u32 *attr, 109 unsigned long *data_size, 110 void *data) 111 { 112 efi_status_t status; 113 114 spin_lock(&efi_runtime_lock); 115 status = efi_call_virt(get_variable, name, vendor, attr, data_size, 116 data); 117 spin_unlock(&efi_runtime_lock); 118 return status; 119 } 120 121 static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, 122 efi_char16_t *name, 123 efi_guid_t *vendor) 124 { 125 efi_status_t status; 126 127 spin_lock(&efi_runtime_lock); 128 status = efi_call_virt(get_next_variable, name_size, name, vendor); 129 spin_unlock(&efi_runtime_lock); 130 return status; 131 } 132 133 static efi_status_t virt_efi_set_variable(efi_char16_t *name, 134 efi_guid_t *vendor, 135 u32 attr, 136 unsigned long data_size, 137 void *data) 138 { 139 efi_status_t status; 140 141 spin_lock(&efi_runtime_lock); 142 status = efi_call_virt(set_variable, name, vendor, attr, data_size, 143 data); 144 spin_unlock(&efi_runtime_lock); 145 return status; 146 } 147 148 static efi_status_t 149 virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor, 150 u32 attr, unsigned long data_size, 151 void *data) 152 { 153 efi_status_t status; 154 155 if (!spin_trylock(&efi_runtime_lock)) 156 return EFI_NOT_READY; 157 158 status = efi_call_virt(set_variable, name, vendor, attr, data_size, 159 data); 160 spin_unlock(&efi_runtime_lock); 161 return status; 162 } 163 164 165 static efi_status_t virt_efi_query_variable_info(u32 attr, 166 u64 *storage_space, 167 u64 *remaining_space, 168 u64 *max_variable_size) 169 { 170 efi_status_t status; 171 172 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 173 return EFI_UNSUPPORTED; 174 175 spin_lock(&efi_runtime_lock); 176 status = efi_call_virt(query_variable_info, attr, storage_space, 177 remaining_space, max_variable_size); 178 spin_unlock(&efi_runtime_lock); 179 return status; 180 } 181 182 static efi_status_t 183 virt_efi_query_variable_info_nonblocking(u32 attr, 184 u64 *storage_space, 185 u64 *remaining_space, 186 u64 *max_variable_size) 187 { 188 efi_status_t status; 189 190 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 191 return EFI_UNSUPPORTED; 192 193 if (!spin_trylock(&efi_runtime_lock)) 194 return EFI_NOT_READY; 195 196 status = efi_call_virt(query_variable_info, attr, storage_space, 197 remaining_space, max_variable_size); 198 spin_unlock(&efi_runtime_lock); 199 return status; 200 } 201 202 static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) 203 { 204 efi_status_t status; 205 206 spin_lock(&efi_runtime_lock); 207 status = efi_call_virt(get_next_high_mono_count, count); 208 spin_unlock(&efi_runtime_lock); 209 return status; 210 } 211 212 static void virt_efi_reset_system(int reset_type, 213 efi_status_t status, 214 unsigned long data_size, 215 efi_char16_t *data) 216 { 217 spin_lock(&efi_runtime_lock); 218 __efi_call_virt(reset_system, reset_type, status, data_size, data); 219 spin_unlock(&efi_runtime_lock); 220 } 221 222 static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 223 unsigned long count, 224 unsigned long sg_list) 225 { 226 efi_status_t status; 227 228 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 229 return EFI_UNSUPPORTED; 230 231 spin_lock(&efi_runtime_lock); 232 status = efi_call_virt(update_capsule, capsules, count, sg_list); 233 spin_unlock(&efi_runtime_lock); 234 return status; 235 } 236 237 static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, 238 unsigned long count, 239 u64 *max_size, 240 int *reset_type) 241 { 242 efi_status_t status; 243 244 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 245 return EFI_UNSUPPORTED; 246 247 spin_lock(&efi_runtime_lock); 248 status = efi_call_virt(query_capsule_caps, capsules, count, max_size, 249 reset_type); 250 spin_unlock(&efi_runtime_lock); 251 return status; 252 } 253 254 void efi_native_runtime_setup(void) 255 { 256 efi.get_time = virt_efi_get_time; 257 efi.set_time = virt_efi_set_time; 258 efi.get_wakeup_time = virt_efi_get_wakeup_time; 259 efi.set_wakeup_time = virt_efi_set_wakeup_time; 260 efi.get_variable = virt_efi_get_variable; 261 efi.get_next_variable = virt_efi_get_next_variable; 262 efi.set_variable = virt_efi_set_variable; 263 efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking; 264 efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count; 265 efi.reset_system = virt_efi_reset_system; 266 efi.query_variable_info = virt_efi_query_variable_info; 267 efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking; 268 efi.update_capsule = virt_efi_update_capsule; 269 efi.query_capsule_caps = virt_efi_query_capsule_caps; 270 } 271