~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/boot/compressed/efi.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Helpers for early access to EFI configuration table.
  4  *
  5  * Originally derived from arch/x86/boot/compressed/acpi.c
  6  */
  7 
  8 #include "misc.h"
  9 
 10 #include <asm/bootparam.h>
 11 
 12 /**
 13  * efi_get_type - Given a pointer to boot_params, determine the type of EFI environment.
 14  *
 15  * @bp:         pointer to boot_params
 16  *
 17  * Return: EFI_TYPE_{32,64} for valid EFI environments, EFI_TYPE_NONE otherwise.
 18  */
 19 enum efi_type efi_get_type(struct boot_params *bp)
 20 {
 21         struct efi_info *ei;
 22         enum efi_type et;
 23         const char *sig;
 24 
 25         ei = &bp->efi_info;
 26         sig = (char *)&ei->efi_loader_signature;
 27 
 28         if (!strncmp(sig, EFI64_LOADER_SIGNATURE, 4)) {
 29                 et = EFI_TYPE_64;
 30         } else if (!strncmp(sig, EFI32_LOADER_SIGNATURE, 4)) {
 31                 et = EFI_TYPE_32;
 32         } else {
 33                 debug_putstr("No EFI environment detected.\n");
 34                 et = EFI_TYPE_NONE;
 35         }
 36 
 37 #ifndef CONFIG_X86_64
 38         /*
 39          * Existing callers like acpi.c treat this case as an indicator to
 40          * fall-through to non-EFI, rather than an error, so maintain that
 41          * functionality here as well.
 42          */
 43         if (ei->efi_systab_hi || ei->efi_memmap_hi) {
 44                 debug_putstr("EFI system table is located above 4GB and cannot be accessed.\n");
 45                 et = EFI_TYPE_NONE;
 46         }
 47 #endif
 48 
 49         return et;
 50 }
 51 
 52 /**
 53  * efi_get_system_table - Given a pointer to boot_params, retrieve the physical address
 54  *                        of the EFI system table.
 55  *
 56  * @bp:         pointer to boot_params
 57  *
 58  * Return: EFI system table address on success. On error, return 0.
 59  */
 60 unsigned long efi_get_system_table(struct boot_params *bp)
 61 {
 62         unsigned long sys_tbl_pa;
 63         struct efi_info *ei;
 64         enum efi_type et;
 65 
 66         /* Get systab from boot params. */
 67         ei = &bp->efi_info;
 68 #ifdef CONFIG_X86_64
 69         sys_tbl_pa = ei->efi_systab | ((__u64)ei->efi_systab_hi << 32);
 70 #else
 71         sys_tbl_pa = ei->efi_systab;
 72 #endif
 73         if (!sys_tbl_pa) {
 74                 debug_putstr("EFI system table not found.");
 75                 return 0;
 76         }
 77 
 78         return sys_tbl_pa;
 79 }
 80 
 81 /*
 82  * EFI config table address changes to virtual address after boot, which may
 83  * not be accessible for the kexec'd kernel. To address this, kexec provides
 84  * the initial physical address via a struct setup_data entry, which is
 85  * checked for here, along with some sanity checks.
 86  */
 87 static struct efi_setup_data *get_kexec_setup_data(struct boot_params *bp,
 88                                                    enum efi_type et)
 89 {
 90 #ifdef CONFIG_X86_64
 91         struct efi_setup_data *esd = NULL;
 92         struct setup_data *data;
 93         u64 pa_data;
 94 
 95         pa_data = bp->hdr.setup_data;
 96         while (pa_data) {
 97                 data = (struct setup_data *)pa_data;
 98                 if (data->type == SETUP_EFI) {
 99                         esd = (struct efi_setup_data *)(pa_data + sizeof(struct setup_data));
100                         break;
101                 }
102 
103                 pa_data = data->next;
104         }
105 
106         /*
107          * Original ACPI code falls back to attempting normal EFI boot in these
108          * cases, so maintain existing behavior by indicating non-kexec
109          * environment to the caller, but print them for debugging.
110          */
111         if (esd && !esd->tables) {
112                 debug_putstr("kexec EFI environment missing valid configuration table.\n");
113                 return NULL;
114         }
115 
116         return esd;
117 #endif
118         return NULL;
119 }
120 
121 /**
122  * efi_get_conf_table - Given a pointer to boot_params, locate and return the physical
123  *                      address of EFI configuration table.
124  *
125  * @bp:                 pointer to boot_params
126  * @cfg_tbl_pa:         location to store physical address of config table
127  * @cfg_tbl_len:        location to store number of config table entries
128  *
129  * Return: 0 on success. On error, return params are left unchanged.
130  */
131 int efi_get_conf_table(struct boot_params *bp, unsigned long *cfg_tbl_pa,
132                        unsigned int *cfg_tbl_len)
133 {
134         unsigned long sys_tbl_pa;
135         enum efi_type et;
136         int ret;
137 
138         if (!cfg_tbl_pa || !cfg_tbl_len)
139                 return -EINVAL;
140 
141         sys_tbl_pa = efi_get_system_table(bp);
142         if (!sys_tbl_pa)
143                 return -EINVAL;
144 
145         /* Handle EFI bitness properly */
146         et = efi_get_type(bp);
147         if (et == EFI_TYPE_64) {
148                 efi_system_table_64_t *stbl = (efi_system_table_64_t *)sys_tbl_pa;
149                 struct efi_setup_data *esd;
150 
151                 /* kexec provides an alternative EFI conf table, check for it. */
152                 esd = get_kexec_setup_data(bp, et);
153 
154                 *cfg_tbl_pa = esd ? esd->tables : stbl->tables;
155                 *cfg_tbl_len = stbl->nr_tables;
156         } else if (et == EFI_TYPE_32) {
157                 efi_system_table_32_t *stbl = (efi_system_table_32_t *)sys_tbl_pa;
158 
159                 *cfg_tbl_pa = stbl->tables;
160                 *cfg_tbl_len = stbl->nr_tables;
161         } else {
162                 return -EINVAL;
163         }
164 
165         return 0;
166 }
167 
168 /* Get vendor table address/guid from EFI config table at the given index */
169 static int get_vendor_table(void *cfg_tbl, unsigned int idx,
170                             unsigned long *vendor_tbl_pa,
171                             efi_guid_t *vendor_tbl_guid,
172                             enum efi_type et)
173 {
174         if (et == EFI_TYPE_64) {
175                 efi_config_table_64_t *tbl_entry = (efi_config_table_64_t *)cfg_tbl + idx;
176 
177                 if (!IS_ENABLED(CONFIG_X86_64) && tbl_entry->table >> 32) {
178                         debug_putstr("Error: EFI config table entry located above 4GB.\n");
179                         return -EINVAL;
180                 }
181 
182                 *vendor_tbl_pa = tbl_entry->table;
183                 *vendor_tbl_guid = tbl_entry->guid;
184 
185         } else if (et == EFI_TYPE_32) {
186                 efi_config_table_32_t *tbl_entry = (efi_config_table_32_t *)cfg_tbl + idx;
187 
188                 *vendor_tbl_pa = tbl_entry->table;
189                 *vendor_tbl_guid = tbl_entry->guid;
190         } else {
191                 return -EINVAL;
192         }
193 
194         return 0;
195 }
196 
197 /**
198  * efi_find_vendor_table - Given EFI config table, search it for the physical
199  *                         address of the vendor table associated with GUID.
200  *
201  * @bp:                pointer to boot_params
202  * @cfg_tbl_pa:        pointer to EFI configuration table
203  * @cfg_tbl_len:       number of entries in EFI configuration table
204  * @guid:              GUID of vendor table
205  *
206  * Return: vendor table address on success. On error, return 0.
207  */
208 unsigned long efi_find_vendor_table(struct boot_params *bp,
209                                     unsigned long cfg_tbl_pa,
210                                     unsigned int cfg_tbl_len,
211                                     efi_guid_t guid)
212 {
213         enum efi_type et;
214         unsigned int i;
215 
216         et = efi_get_type(bp);
217         if (et == EFI_TYPE_NONE)
218                 return 0;
219 
220         for (i = 0; i < cfg_tbl_len; i++) {
221                 unsigned long vendor_tbl_pa;
222                 efi_guid_t vendor_tbl_guid;
223                 int ret;
224 
225                 ret = get_vendor_table((void *)cfg_tbl_pa, i,
226                                        &vendor_tbl_pa,
227                                        &vendor_tbl_guid, et);
228                 if (ret)
229                         return 0;
230 
231                 if (!efi_guidcmp(guid, vendor_tbl_guid))
232                         return vendor_tbl_pa;
233         }
234 
235         return 0;
236 }
237 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php