linux/drivers/firmware/efi/runtime-wrappers.c
<<
>>
Prefs
   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#define pr_fmt(fmt)     "efi: " fmt
  18
  19#include <linux/bug.h>
  20#include <linux/efi.h>
  21#include <linux/irqflags.h>
  22#include <linux/mutex.h>
  23#include <linux/semaphore.h>
  24#include <linux/stringify.h>
  25#include <asm/efi.h>
  26
  27/*
  28 * Wrap around the new efi_call_virt_generic() macros so that the
  29 * code doesn't get too cluttered:
  30 */
  31#define efi_call_virt(f, args...)   \
  32        efi_call_virt_pointer(efi.systab->runtime, f, args)
  33#define __efi_call_virt(f, args...) \
  34        __efi_call_virt_pointer(efi.systab->runtime, f, args)
  35
  36void efi_call_virt_check_flags(unsigned long flags, const char *call)
  37{
  38        unsigned long cur_flags, mismatch;
  39
  40        local_save_flags(cur_flags);
  41
  42        mismatch = flags ^ cur_flags;
  43        if (!WARN_ON_ONCE(mismatch & ARCH_EFI_IRQ_FLAGS_MASK))
  44                return;
  45
  46        add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_NOW_UNRELIABLE);
  47        pr_err_ratelimited(FW_BUG "IRQ flags corrupted (0x%08lx=>0x%08lx) by EFI %s\n",
  48                           flags, cur_flags, call);
  49        local_irq_restore(flags);
  50}
  51
  52/*
  53 * According to section 7.1 of the UEFI spec, Runtime Services are not fully
  54 * reentrant, and there are particular combinations of calls that need to be
  55 * serialized. (source: UEFI Specification v2.4A)
  56 *
  57 * Table 31. Rules for Reentry Into Runtime Services
  58 * +------------------------------------+-------------------------------+
  59 * | If previous call is busy in        | Forbidden to call             |
  60 * +------------------------------------+-------------------------------+
  61 * | Any                                | SetVirtualAddressMap()        |
  62 * +------------------------------------+-------------------------------+
  63 * | ConvertPointer()                   | ConvertPointer()              |
  64 * +------------------------------------+-------------------------------+
  65 * | SetVariable()                      | ResetSystem()                 |
  66 * | UpdateCapsule()                    |                               |
  67 * | SetTime()                          |                               |
  68 * | SetWakeupTime()                    |                               |
  69 * | GetNextHighMonotonicCount()        |                               |
  70 * +------------------------------------+-------------------------------+
  71 * | GetVariable()                      | GetVariable()                 |
  72 * | GetNextVariableName()              | GetNextVariableName()         |
  73 * | SetVariable()                      | SetVariable()                 |
  74 * | QueryVariableInfo()                | QueryVariableInfo()           |
  75 * | UpdateCapsule()                    | UpdateCapsule()               |
  76 * | QueryCapsuleCapabilities()         | QueryCapsuleCapabilities()    |
  77 * | GetNextHighMonotonicCount()        | GetNextHighMonotonicCount()   |
  78 * +------------------------------------+-------------------------------+
  79 * | GetTime()                          | GetTime()                     |
  80 * | SetTime()                          | SetTime()                     |
  81 * | GetWakeupTime()                    | GetWakeupTime()               |
  82 * | SetWakeupTime()                    | SetWakeupTime()               |
  83 * +------------------------------------+-------------------------------+
  84 *
  85 * Due to the fact that the EFI pstore may write to the variable store in
  86 * interrupt context, we need to use a lock for at least the groups that
  87 * contain SetVariable() and QueryVariableInfo(). That leaves little else, as
  88 * none of the remaining functions are actually ever called at runtime.
  89 * So let's just use a single lock to serialize all Runtime Services calls.
  90 */
  91static DEFINE_SEMAPHORE(efi_runtime_lock);
  92
  93static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
  94{
  95        efi_status_t status;
  96
  97        if (down_interruptible(&efi_runtime_lock))
  98                return EFI_ABORTED;
  99        status = efi_call_virt(get_time, tm, tc);
 100        up(&efi_runtime_lock);
 101        return status;
 102}
 103
 104static efi_status_t virt_efi_set_time(efi_time_t *tm)
 105{
 106        efi_status_t status;
 107
 108        if (down_interruptible(&efi_runtime_lock))
 109                return EFI_ABORTED;
 110        status = efi_call_virt(set_time, tm);
 111        up(&efi_runtime_lock);
 112        return status;
 113}
 114
 115static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
 116                                             efi_bool_t *pending,
 117                                             efi_time_t *tm)
 118{
 119        efi_status_t status;
 120
 121        if (down_interruptible(&efi_runtime_lock))
 122                return EFI_ABORTED;
 123        status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
 124        up(&efi_runtime_lock);
 125        return status;
 126}
 127
 128static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
 129{
 130        efi_status_t status;
 131
 132        if (down_interruptible(&efi_runtime_lock))
 133                return EFI_ABORTED;
 134        status = efi_call_virt(set_wakeup_time, enabled, tm);
 135        up(&efi_runtime_lock);
 136        return status;
 137}
 138
 139static efi_status_t virt_efi_get_variable(efi_char16_t *name,
 140                                          efi_guid_t *vendor,
 141                                          u32 *attr,
 142                                          unsigned long *data_size,
 143                                          void *data)
 144{
 145        efi_status_t status;
 146
 147        if (down_interruptible(&efi_runtime_lock))
 148                return EFI_ABORTED;
 149        status = efi_call_virt(get_variable, name, vendor, attr, data_size,
 150                               data);
 151        up(&efi_runtime_lock);
 152        return status;
 153}
 154
 155static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
 156                                               efi_char16_t *name,
 157                                               efi_guid_t *vendor)
 158{
 159        efi_status_t status;
 160
 161        if (down_interruptible(&efi_runtime_lock))
 162                return EFI_ABORTED;
 163        status = efi_call_virt(get_next_variable, name_size, name, vendor);
 164        up(&efi_runtime_lock);
 165        return status;
 166}
 167
 168static efi_status_t virt_efi_set_variable(efi_char16_t *name,
 169                                          efi_guid_t *vendor,
 170                                          u32 attr,
 171                                          unsigned long data_size,
 172                                          void *data)
 173{
 174        efi_status_t status;
 175
 176        if (down_interruptible(&efi_runtime_lock))
 177                return EFI_ABORTED;
 178        status = efi_call_virt(set_variable, name, vendor, attr, data_size,
 179                               data);
 180        up(&efi_runtime_lock);
 181        return status;
 182}
 183
 184static efi_status_t
 185virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
 186                                  u32 attr, unsigned long data_size,
 187                                  void *data)
 188{
 189        efi_status_t status;
 190
 191        if (down_trylock(&efi_runtime_lock))
 192                return EFI_NOT_READY;
 193
 194        status = efi_call_virt(set_variable, name, vendor, attr, data_size,
 195                               data);
 196        up(&efi_runtime_lock);
 197        return status;
 198}
 199
 200
 201static efi_status_t virt_efi_query_variable_info(u32 attr,
 202                                                 u64 *storage_space,
 203                                                 u64 *remaining_space,
 204                                                 u64 *max_variable_size)
 205{
 206        efi_status_t status;
 207
 208        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
 209                return EFI_UNSUPPORTED;
 210
 211        if (down_interruptible(&efi_runtime_lock))
 212                return EFI_ABORTED;
 213        status = efi_call_virt(query_variable_info, attr, storage_space,
 214                               remaining_space, max_variable_size);
 215        up(&efi_runtime_lock);
 216        return status;
 217}
 218
 219static efi_status_t
 220virt_efi_query_variable_info_nonblocking(u32 attr,
 221                                         u64 *storage_space,
 222                                         u64 *remaining_space,
 223                                         u64 *max_variable_size)
 224{
 225        efi_status_t status;
 226
 227        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
 228                return EFI_UNSUPPORTED;
 229
 230        if (down_trylock(&efi_runtime_lock))
 231                return EFI_NOT_READY;
 232
 233        status = efi_call_virt(query_variable_info, attr, storage_space,
 234                               remaining_space, max_variable_size);
 235        up(&efi_runtime_lock);
 236        return status;
 237}
 238
 239static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
 240{
 241        efi_status_t status;
 242
 243        if (down_interruptible(&efi_runtime_lock))
 244                return EFI_ABORTED;
 245        status = efi_call_virt(get_next_high_mono_count, count);
 246        up(&efi_runtime_lock);
 247        return status;
 248}
 249
 250static void virt_efi_reset_system(int reset_type,
 251                                  efi_status_t status,
 252                                  unsigned long data_size,
 253                                  efi_char16_t *data)
 254{
 255        if (down_interruptible(&efi_runtime_lock)) {
 256                pr_warn("failed to invoke the reset_system() runtime service:\n"
 257                        "could not get exclusive access to the firmware\n");
 258                return;
 259        }
 260        __efi_call_virt(reset_system, reset_type, status, data_size, data);
 261        up(&efi_runtime_lock);
 262}
 263
 264static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
 265                                            unsigned long count,
 266                                            unsigned long sg_list)
 267{
 268        efi_status_t status;
 269
 270        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
 271                return EFI_UNSUPPORTED;
 272
 273        if (down_interruptible(&efi_runtime_lock))
 274                return EFI_ABORTED;
 275        status = efi_call_virt(update_capsule, capsules, count, sg_list);
 276        up(&efi_runtime_lock);
 277        return status;
 278}
 279
 280static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
 281                                                unsigned long count,
 282                                                u64 *max_size,
 283                                                int *reset_type)
 284{
 285        efi_status_t status;
 286
 287        if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
 288                return EFI_UNSUPPORTED;
 289
 290        if (down_interruptible(&efi_runtime_lock))
 291                return EFI_ABORTED;
 292        status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
 293                               reset_type);
 294        up(&efi_runtime_lock);
 295        return status;
 296}
 297
 298void efi_native_runtime_setup(void)
 299{
 300        efi.get_time = virt_efi_get_time;
 301        efi.set_time = virt_efi_set_time;
 302        efi.get_wakeup_time = virt_efi_get_wakeup_time;
 303        efi.set_wakeup_time = virt_efi_set_wakeup_time;
 304        efi.get_variable = virt_efi_get_variable;
 305        efi.get_next_variable = virt_efi_get_next_variable;
 306        efi.set_variable = virt_efi_set_variable;
 307        efi.set_variable_nonblocking = virt_efi_set_variable_nonblocking;
 308        efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
 309        efi.reset_system = virt_efi_reset_system;
 310        efi.query_variable_info = virt_efi_query_variable_info;
 311        efi.query_variable_info_nonblocking = virt_efi_query_variable_info_nonblocking;
 312        efi.update_capsule = virt_efi_update_capsule;
 313        efi.query_capsule_caps = virt_efi_query_capsule_caps;
 314}
 315