Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause
0002 /*
0003  * Copyright(c) 2015, 2016 Intel Corporation.
0004  */
0005 
0006 #include <linux/string.h>
0007 #include <linux/string_helpers.h>
0008 
0009 #include "efivar.h"
0010 
0011 /* GUID for HFI1 variables in EFI */
0012 #define HFI1_EFIVAR_GUID EFI_GUID(0xc50a953e, 0xa8b2, 0x42a6, \
0013         0xbf, 0x89, 0xd3, 0x33, 0xa6, 0xe9, 0xe6, 0xd4)
0014 /* largest EFI data size we expect */
0015 #define EFI_DATA_SIZE 4096
0016 
0017 /*
0018  * Read the named EFI variable.  Return the size of the actual data in *size
0019  * and a kmalloc'ed buffer in *return_data.  The caller must free the
0020  * data.  It is guaranteed that *return_data will be NULL and *size = 0
0021  * if this routine fails.
0022  *
0023  * Return 0 on success, -errno on failure.
0024  */
0025 static int read_efi_var(const char *name, unsigned long *size,
0026             void **return_data)
0027 {
0028     efi_status_t status;
0029     efi_char16_t *uni_name;
0030     efi_guid_t guid;
0031     unsigned long temp_size;
0032     void *temp_buffer;
0033     void *data;
0034     int i;
0035     int ret;
0036 
0037     /* set failure return values */
0038     *size = 0;
0039     *return_data = NULL;
0040 
0041     if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
0042         return -EOPNOTSUPP;
0043 
0044     uni_name = kcalloc(strlen(name) + 1, sizeof(efi_char16_t), GFP_KERNEL);
0045     temp_buffer = kzalloc(EFI_DATA_SIZE, GFP_KERNEL);
0046 
0047     if (!uni_name || !temp_buffer) {
0048         ret = -ENOMEM;
0049         goto fail;
0050     }
0051 
0052     /* input: the size of the buffer */
0053     temp_size = EFI_DATA_SIZE;
0054 
0055     /* convert ASCII to unicode - it is a 1:1 mapping */
0056     for (i = 0; name[i]; i++)
0057         uni_name[i] = name[i];
0058 
0059     /* need a variable for our GUID */
0060     guid = HFI1_EFIVAR_GUID;
0061 
0062     /* call into EFI runtime services */
0063     status = efi.get_variable(
0064             uni_name,
0065             &guid,
0066             NULL,
0067             &temp_size,
0068             temp_buffer);
0069 
0070     /*
0071      * It would be nice to call efi_status_to_err() here, but that
0072      * is in the EFIVAR_FS code and may not be compiled in.
0073      * However, even that is insufficient since it does not cover
0074      * EFI_BUFFER_TOO_SMALL which could be an important return.
0075      * For now, just split out success or not found.
0076      */
0077     ret = status == EFI_SUCCESS   ? 0 :
0078           status == EFI_NOT_FOUND ? -ENOENT :
0079                     -EINVAL;
0080     if (ret)
0081         goto fail;
0082 
0083     /*
0084      * We have successfully read the EFI variable into our
0085      * temporary buffer.  Now allocate a correctly sized
0086      * buffer.
0087      */
0088     data = kmemdup(temp_buffer, temp_size, GFP_KERNEL);
0089     if (!data) {
0090         ret = -ENOMEM;
0091         goto fail;
0092     }
0093 
0094     *size = temp_size;
0095     *return_data = data;
0096 
0097 fail:
0098     kfree(uni_name);
0099     kfree(temp_buffer);
0100 
0101     return ret;
0102 }
0103 
0104 /*
0105  * Read an HFI1 EFI variable of the form:
0106  *  <PCIe address>-<kind>
0107  * Return an kalloc'ed array and size of the data.
0108  *
0109  * Returns 0 on success, -errno on failure.
0110  */
0111 int read_hfi1_efi_var(struct hfi1_devdata *dd, const char *kind,
0112               unsigned long *size, void **return_data)
0113 {
0114     char prefix_name[64];
0115     char name[64];
0116     int result;
0117 
0118     /* create a common prefix */
0119     snprintf(prefix_name, sizeof(prefix_name), "%04x:%02x:%02x.%x",
0120          pci_domain_nr(dd->pcidev->bus),
0121          dd->pcidev->bus->number,
0122          PCI_SLOT(dd->pcidev->devfn),
0123          PCI_FUNC(dd->pcidev->devfn));
0124     snprintf(name, sizeof(name), "%s-%s", prefix_name, kind);
0125     result = read_efi_var(name, size, return_data);
0126 
0127     /*
0128      * If reading the lowercase EFI variable fail, read the uppercase
0129      * variable.
0130      */
0131     if (result) {
0132         string_upper(prefix_name, prefix_name);
0133         snprintf(name, sizeof(name), "%s-%s", prefix_name, kind);
0134         result = read_efi_var(name, size, return_data);
0135     }
0136 
0137     return result;
0138 }