diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 21:03:54 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 21:03:54 -0500 |
commit | 6b00f7efb5303418c231994c91fb8239f5ada260 (patch) | |
tree | 1daba87ccda34e632ea39dedc5055391c7e94bdc /drivers/firmware | |
parent | b3d6524ff7956c5a898d51a18eaecb62a60a2b84 (diff) | |
parent | d476d94f180af3f0fca77394651d4a98f4df1c54 (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.c | 56 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/arm-stub.c | 59 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efi-stub-helper.c | 25 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/efistub.h | 4 | ||||
-rw-r--r-- | drivers/firmware/efi/libstub/fdt.c | 62 |
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 | ||
300 | int __init efi_config_init(efi_config_table_type_t *arch_tables) | 300 | int __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 | ||
339 | int __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 |
359 | static int __init efi_load_efivars(void) | 367 | static 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: | |||
295 | fail: | 295 | fail: |
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 | */ | ||
316 | void 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 | ||
33 | static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE; | 33 | static 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 | |||
35 | struct file_info { | 44 | struct 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; |
161 | again: | 170 | again: |
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 | ||
40 | void *get_fdt(efi_system_table_t *sys_table); | 40 | void *get_fdt(efi_system_table_t *sys_table); |
41 | 41 | ||
42 | void 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 | |||
17 | efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt, | 19 | efi_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 | ||
266 | fail: | 321 | fail: |
322 | sys_table->boottime->free_pool(runtime_map); | ||
267 | return EFI_LOAD_ERROR; | 323 | return EFI_LOAD_ERROR; |
268 | } | 324 | } |
269 | 325 | ||