aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/firmware
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 21:03:54 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-11 21:03:54 -0500
commit6b00f7efb5303418c231994c91fb8239f5ada260 (patch)
tree1daba87ccda34e632ea39dedc5055391c7e94bdc /drivers/firmware
parentb3d6524ff7956c5a898d51a18eaecb62a60a2b84 (diff)
parentd476d94f180af3f0fca77394651d4a98f4df1c54 (diff)
Merge tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux
Pull arm64 updates from Catalin Marinas: "arm64 updates for 3.20: - reimplementation of the virtual remapping of UEFI Runtime Services in a way that is stable across kexec - emulation of the "setend" instruction for 32-bit tasks (user endianness switching trapped in the kernel, SCTLR_EL1.E0E bit set accordingly) - compat_sys_call_table implemented in C (from asm) and made it a constant array together with sys_call_table - export CPU cache information via /sys (like other architectures) - DMA API implementation clean-up in preparation for IOMMU support - macros clean-up for KVM - dropped some unnecessary cache+tlb maintenance - CONFIG_ARM64_CPU_SUSPEND clean-up - defconfig update (CPU_IDLE) The EFI changes going via the arm64 tree have been acked by Matt Fleming. There is also a patch adding sys_*stat64 prototypes to include/linux/syscalls.h, acked by Andrew Morton" * tag 'arm64-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux: (47 commits) arm64: compat: Remove incorrect comment in compat_siginfo arm64: Fix section mismatch on alloc_init_p[mu]d() arm64: Avoid breakage caused by .altmacro in fpsimd save/restore macros arm64: mm: use *_sect to check for section maps arm64: drop unnecessary cache+tlb maintenance arm64:mm: free the useless initial page table arm64: Enable CPU_IDLE in defconfig arm64: kernel: remove ARM64_CPU_SUSPEND config option arm64: make sys_call_table const arm64: Remove asm/syscalls.h arm64: Implement the compat_sys_call_table in C syscalls: Declare sys_*stat64 prototypes if __ARCH_WANT_(COMPAT_)STAT64 compat: Declare compat_sys_sigpending and compat_sys_sigprocmask prototypes arm64: uapi: expose our struct ucontext to the uapi headers smp, ARM64: Kill SMP single function call interrupt arm64: Emulate SETEND for AArch32 tasks arm64: Consolidate hotplug notifier for instruction emulation arm64: Track system support for mixed endian EL0 arm64: implement generic IOMMU configuration arm64: Combine coherent and non-coherent swiotlb dma_ops ...
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/efi/efi.c56
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c59
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c25
-rw-r--r--drivers/firmware/efi/libstub/efistub.h4
-rw-r--r--drivers/firmware/efi/libstub/fdt.c62
5 files changed, 171 insertions, 35 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index fccb464928c3..3061bb8629dc 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -297,29 +297,15 @@ static __init int match_config_table(efi_guid_t *guid,
297 return 0; 297 return 0;
298} 298}
299 299
300int __init efi_config_init(efi_config_table_type_t *arch_tables) 300int __init efi_config_parse_tables(void *config_tables, int count, int sz,
301 efi_config_table_type_t *arch_tables)
301{ 302{
302 void *config_tables, *tablep; 303 void *tablep;
303 int i, sz; 304 int i;
304
305 if (efi_enabled(EFI_64BIT))
306 sz = sizeof(efi_config_table_64_t);
307 else
308 sz = sizeof(efi_config_table_32_t);
309
310 /*
311 * Let's see what config tables the firmware passed to us.
312 */
313 config_tables = early_memremap(efi.systab->tables,
314 efi.systab->nr_tables * sz);
315 if (config_tables == NULL) {
316 pr_err("Could not map Configuration table!\n");
317 return -ENOMEM;
318 }
319 305
320 tablep = config_tables; 306 tablep = config_tables;
321 pr_info(""); 307 pr_info("");
322 for (i = 0; i < efi.systab->nr_tables; i++) { 308 for (i = 0; i < count; i++) {
323 efi_guid_t guid; 309 efi_guid_t guid;
324 unsigned long table; 310 unsigned long table;
325 311
@@ -332,8 +318,6 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
332 if (table64 >> 32) { 318 if (table64 >> 32) {
333 pr_cont("\n"); 319 pr_cont("\n");
334 pr_err("Table located above 4GB, disabling EFI.\n"); 320 pr_err("Table located above 4GB, disabling EFI.\n");
335 early_memunmap(config_tables,
336 efi.systab->nr_tables * sz);
337 return -EINVAL; 321 return -EINVAL;
338 } 322 }
339#endif 323#endif
@@ -348,13 +332,37 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
348 tablep += sz; 332 tablep += sz;
349 } 333 }
350 pr_cont("\n"); 334 pr_cont("\n");
351 early_memunmap(config_tables, efi.systab->nr_tables * sz);
352
353 set_bit(EFI_CONFIG_TABLES, &efi.flags); 335 set_bit(EFI_CONFIG_TABLES, &efi.flags);
354
355 return 0; 336 return 0;
356} 337}
357 338
339int __init efi_config_init(efi_config_table_type_t *arch_tables)
340{
341 void *config_tables;
342 int sz, ret;
343
344 if (efi_enabled(EFI_64BIT))
345 sz = sizeof(efi_config_table_64_t);
346 else
347 sz = sizeof(efi_config_table_32_t);
348
349 /*
350 * Let's see what config tables the firmware passed to us.
351 */
352 config_tables = early_memremap(efi.systab->tables,
353 efi.systab->nr_tables * sz);
354 if (config_tables == NULL) {
355 pr_err("Could not map Configuration table!\n");
356 return -ENOMEM;
357 }
358
359 ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
360 arch_tables);
361
362 early_memunmap(config_tables, efi.systab->nr_tables * sz);
363 return ret;
364}
365
358#ifdef CONFIG_EFI_VARS_MODULE 366#ifdef CONFIG_EFI_VARS_MODULE
359static int __init efi_load_efivars(void) 367static int __init efi_load_efivars(void)
360{ 368{
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 2b3814702dcf..dcae482a9a17 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -295,3 +295,62 @@ fail_free_image:
295fail: 295fail:
296 return EFI_ERROR; 296 return EFI_ERROR;
297} 297}
298
299/*
300 * This is the base address at which to start allocating virtual memory ranges
301 * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use
302 * any allocation we choose, and eliminate the risk of a conflict after kexec.
303 * The value chosen is the largest non-zero power of 2 suitable for this purpose
304 * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
305 * be mapped efficiently.
306 */
307#define EFI_RT_VIRTUAL_BASE 0x40000000
308
309/*
310 * efi_get_virtmap() - create a virtual mapping for the EFI memory map
311 *
312 * This function populates the virt_addr fields of all memory region descriptors
313 * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
314 * are also copied to @runtime_map, and their total count is returned in @count.
315 */
316void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
317 unsigned long desc_size, efi_memory_desc_t *runtime_map,
318 int *count)
319{
320 u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
321 efi_memory_desc_t *out = runtime_map;
322 int l;
323
324 for (l = 0; l < map_size; l += desc_size) {
325 efi_memory_desc_t *in = (void *)memory_map + l;
326 u64 paddr, size;
327
328 if (!(in->attribute & EFI_MEMORY_RUNTIME))
329 continue;
330
331 /*
332 * Make the mapping compatible with 64k pages: this allows
333 * a 4k page size kernel to kexec a 64k page size kernel and
334 * vice versa.
335 */
336 paddr = round_down(in->phys_addr, SZ_64K);
337 size = round_up(in->num_pages * EFI_PAGE_SIZE +
338 in->phys_addr - paddr, SZ_64K);
339
340 /*
341 * Avoid wasting memory on PTEs by choosing a virtual base that
342 * is compatible with section mappings if this region has the
343 * appropriate size and physical alignment. (Sections are 2 MB
344 * on 4k granule kernels)
345 */
346 if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
347 efi_virt_base = round_up(efi_virt_base, SZ_2M);
348
349 in->virt_addr = efi_virt_base + in->phys_addr - paddr;
350 efi_virt_base += size;
351
352 memcpy(out, in, desc_size);
353 out = (void *)out + desc_size;
354 ++*count;
355 }
356}
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index d073e3946383..af5d63c7cc53 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -32,6 +32,15 @@
32 32
33static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; 33static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
34 34
35/*
36 * Allow the platform to override the allocation granularity: this allows
37 * systems that have the capability to run with a larger page size to deal
38 * with the allocations for initrd and fdt more efficiently.
39 */
40#ifndef EFI_ALLOC_ALIGN
41#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
42#endif
43
35struct file_info { 44struct file_info {
36 efi_file_handle_t *handle; 45 efi_file_handle_t *handle;
37 u64 size; 46 u64 size;
@@ -154,10 +163,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
154 * a specific address. We are doing page-based allocations, 163 * a specific address. We are doing page-based allocations,
155 * so we must be aligned to a page. 164 * so we must be aligned to a page.
156 */ 165 */
157 if (align < EFI_PAGE_SIZE) 166 if (align < EFI_ALLOC_ALIGN)
158 align = EFI_PAGE_SIZE; 167 align = EFI_ALLOC_ALIGN;
159 168
160 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 169 nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
161again: 170again:
162 for (i = 0; i < map_size / desc_size; i++) { 171 for (i = 0; i < map_size / desc_size; i++) {
163 efi_memory_desc_t *desc; 172 efi_memory_desc_t *desc;
@@ -239,10 +248,10 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
239 * a specific address. We are doing page-based allocations, 248 * a specific address. We are doing page-based allocations,
240 * so we must be aligned to a page. 249 * so we must be aligned to a page.
241 */ 250 */
242 if (align < EFI_PAGE_SIZE) 251 if (align < EFI_ALLOC_ALIGN)
243 align = EFI_PAGE_SIZE; 252 align = EFI_ALLOC_ALIGN;
244 253
245 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 254 nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
246 for (i = 0; i < map_size / desc_size; i++) { 255 for (i = 0; i < map_size / desc_size; i++) {
247 efi_memory_desc_t *desc; 256 efi_memory_desc_t *desc;
248 unsigned long m = (unsigned long)map; 257 unsigned long m = (unsigned long)map;
@@ -296,7 +305,7 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
296 if (!size) 305 if (!size)
297 return; 306 return;
298 307
299 nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 308 nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
300 efi_call_early(free_pages, addr, nr_pages); 309 efi_call_early(free_pages, addr, nr_pages);
301} 310}
302 311
@@ -565,7 +574,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
565 * to the preferred address. If that fails, allocate as low 574 * to the preferred address. If that fails, allocate as low
566 * as possible while respecting the required alignment. 575 * as possible while respecting the required alignment.
567 */ 576 */
568 nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; 577 nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
569 status = efi_call_early(allocate_pages, 578 status = efi_call_early(allocate_pages,
570 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA, 579 EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
571 nr_pages, &efi_addr); 580 nr_pages, &efi_addr);
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 304ab295ca1a..2be10984a67a 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -39,4 +39,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
39 39
40void *get_fdt(efi_system_table_t *sys_table); 40void *get_fdt(efi_system_table_t *sys_table);
41 41
42void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
43 unsigned long desc_size, efi_memory_desc_t *runtime_map,
44 int *count);
45
42#endif 46#endif
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index c846a9608cbd..91da56c4fd54 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -14,6 +14,8 @@
14#include <linux/libfdt.h> 14#include <linux/libfdt.h>
15#include <asm/efi.h> 15#include <asm/efi.h>
16 16
17#include "efistub.h"
18
17efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, 19efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
18 unsigned long orig_fdt_size, 20 unsigned long orig_fdt_size,
19 void *fdt, int new_fdt_size, char *cmdline_ptr, 21 void *fdt, int new_fdt_size, char *cmdline_ptr,
@@ -193,9 +195,26 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
193 unsigned long map_size, desc_size; 195 unsigned long map_size, desc_size;
194 u32 desc_ver; 196 u32 desc_ver;
195 unsigned long mmap_key; 197 unsigned long mmap_key;
196 efi_memory_desc_t *memory_map; 198 efi_memory_desc_t *memory_map, *runtime_map;
197 unsigned long new_fdt_size; 199 unsigned long new_fdt_size;
198 efi_status_t status; 200 efi_status_t status;
201 int runtime_entry_count = 0;
202
203 /*
204 * Get a copy of the current memory map that we will use to prepare
205 * the input for SetVirtualAddressMap(). We don't have to worry about
206 * subsequent allocations adding entries, since they could not affect
207 * the number of EFI_MEMORY_RUNTIME regions.
208 */
209 status = efi_get_memory_map(sys_table, &runtime_map, &map_size,
210 &desc_size, &desc_ver, &mmap_key);
211 if (status != EFI_SUCCESS) {
212 pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
213 return status;
214 }
215
216 pr_efi(sys_table,
217 "Exiting boot services and installing virtual address map...\n");
199 218
200 /* 219 /*
201 * Estimate size of new FDT, and allocate memory for it. We 220 * Estimate size of new FDT, and allocate memory for it. We
@@ -248,12 +267,48 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
248 } 267 }
249 } 268 }
250 269
270 /*
271 * Update the memory map with virtual addresses. The function will also
272 * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
273 * entries so that we can pass it straight into SetVirtualAddressMap()
274 */
275 efi_get_virtmap(memory_map, map_size, desc_size, runtime_map,
276 &runtime_entry_count);
277
251 /* Now we are ready to exit_boot_services.*/ 278 /* Now we are ready to exit_boot_services.*/
252 status = sys_table->boottime->exit_boot_services(handle, mmap_key); 279 status = sys_table->boottime->exit_boot_services(handle, mmap_key);
253 280
281 if (status == EFI_SUCCESS) {
282 efi_set_virtual_address_map_t *svam;
254 283
255 if (status == EFI_SUCCESS) 284 /* Install the new virtual address map */
256 return status; 285 svam = sys_table->runtime->set_virtual_address_map;
286 status = svam(runtime_entry_count * desc_size, desc_size,
287 desc_ver, runtime_map);
288
289 /*
290 * We are beyond the point of no return here, so if the call to
291 * SetVirtualAddressMap() failed, we need to signal that to the
292 * incoming kernel but proceed normally otherwise.
293 */
294 if (status != EFI_SUCCESS) {
295 int l;
296
297 /*
298 * Set the virtual address field of all
299 * EFI_MEMORY_RUNTIME entries to 0. This will signal
300 * the incoming kernel that no virtual translation has
301 * been installed.
302 */
303 for (l = 0; l < map_size; l += desc_size) {
304 efi_memory_desc_t *p = (void *)memory_map + l;
305
306 if (p->attribute & EFI_MEMORY_RUNTIME)
307 p->virt_addr = 0;
308 }
309 }
310 return EFI_SUCCESS;
311 }
257 312
258 pr_efi_err(sys_table, "Exit boot services failed.\n"); 313 pr_efi_err(sys_table, "Exit boot services failed.\n");
259 314
@@ -264,6 +319,7 @@ fail_free_new_fdt:
264 efi_free(sys_table, new_fdt_size, *new_fdt_addr); 319 efi_free(sys_table, new_fdt_size, *new_fdt_addr);
265 320
266fail: 321fail:
322 sys_table->boottime->free_pool(runtime_map);
267 return EFI_LOAD_ERROR; 323 return EFI_LOAD_ERROR;
268} 324}
269 325