diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2016-01-12 08:41:03 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2016-01-12 08:41:03 -0500 |
commit | 6660800fb7fd0f66faecb3c550fe59709220ade5 (patch) | |
tree | 19f95c0579bc13ba8c1d326e5058330e2fd14d63 | |
parent | 598bcc6ea6ec4032d2ace8b1b43d11b4708af072 (diff) | |
parent | 06312f44ad638c02e26c5f187c9ee8f94cbaa3a2 (diff) |
Merge branch 'devel-stable' into for-linus
29 files changed, 986 insertions, 368 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 47288163ce18..a4a756bfe889 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -20,6 +20,7 @@ config ARM | |||
20 | select GENERIC_ALLOCATOR | 20 | select GENERIC_ALLOCATOR |
21 | select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI) | 21 | select GENERIC_ATOMIC64 if (CPU_V7M || CPU_V6 || !CPU_32v6K || !AEABI) |
22 | select GENERIC_CLOCKEVENTS_BROADCAST if SMP | 22 | select GENERIC_CLOCKEVENTS_BROADCAST if SMP |
23 | select GENERIC_EARLY_IOREMAP | ||
23 | select GENERIC_IDLE_POLL_SETUP | 24 | select GENERIC_IDLE_POLL_SETUP |
24 | select GENERIC_IRQ_PROBE | 25 | select GENERIC_IRQ_PROBE |
25 | select GENERIC_IRQ_SHOW | 26 | select GENERIC_IRQ_SHOW |
@@ -2060,6 +2061,25 @@ config AUTO_ZRELADDR | |||
2060 | 0xf8000000. This assumes the zImage being placed in the first 128MB | 2061 | 0xf8000000. This assumes the zImage being placed in the first 128MB |
2061 | from start of memory. | 2062 | from start of memory. |
2062 | 2063 | ||
2064 | config EFI_STUB | ||
2065 | bool | ||
2066 | |||
2067 | config EFI | ||
2068 | bool "UEFI runtime support" | ||
2069 | depends on OF && !CPU_BIG_ENDIAN && MMU && AUTO_ZRELADDR && !XIP_KERNEL | ||
2070 | select UCS2_STRING | ||
2071 | select EFI_PARAMS_FROM_FDT | ||
2072 | select EFI_STUB | ||
2073 | select EFI_ARMSTUB | ||
2074 | select EFI_RUNTIME_WRAPPERS | ||
2075 | ---help--- | ||
2076 | This option provides support for runtime services provided | ||
2077 | by UEFI firmware (such as non-volatile variables, realtime | ||
2078 | clock, and platform reset). A UEFI stub is also provided to | ||
2079 | allow the kernel to be booted as an EFI application. This | ||
2080 | is only useful for kernels that may run on systems that have | ||
2081 | UEFI firmware. | ||
2082 | |||
2063 | endmenu | 2083 | endmenu |
2064 | 2084 | ||
2065 | menu "CPU Power Management" | 2085 | menu "CPU Power Management" |
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 3f9a9ebc77c3..4c23a68a0917 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile | |||
@@ -167,9 +167,11 @@ if [ $(words $(ZRELADDR)) -gt 1 -a "$(CONFIG_AUTO_ZRELADDR)" = "" ]; then \ | |||
167 | false; \ | 167 | false; \ |
168 | fi | 168 | fi |
169 | 169 | ||
170 | efi-obj-$(CONFIG_EFI_STUB) := $(objtree)/drivers/firmware/efi/libstub/lib.a | ||
171 | |||
170 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ | 172 | $(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.$(suffix_y).o \ |
171 | $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \ | 173 | $(addprefix $(obj)/, $(OBJS)) $(lib1funcs) $(ashldi3) \ |
172 | $(bswapsdi2) FORCE | 174 | $(bswapsdi2) $(efi-obj-y) FORCE |
173 | @$(check_for_multiple_zreladdr) | 175 | @$(check_for_multiple_zreladdr) |
174 | $(call if_changed,ld) | 176 | $(call if_changed,ld) |
175 | @$(check_for_bad_syms) | 177 | @$(check_for_bad_syms) |
diff --git a/arch/arm/boot/compressed/efi-header.S b/arch/arm/boot/compressed/efi-header.S new file mode 100644 index 000000000000..9d5dc4fda3c1 --- /dev/null +++ b/arch/arm/boot/compressed/efi-header.S | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013-2015 Linaro Ltd | ||
3 | * Authors: Roy Franz <roy.franz@linaro.org> | ||
4 | * Ard Biesheuvel <ard.biesheuvel@linaro.org> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | .macro __nop | ||
12 | #ifdef CONFIG_EFI_STUB | ||
13 | @ This is almost but not quite a NOP, since it does clobber the | ||
14 | @ condition flags. But it is the best we can do for EFI, since | ||
15 | @ PE/COFF expects the magic string "MZ" at offset 0, while the | ||
16 | @ ARM/Linux boot protocol expects an executable instruction | ||
17 | @ there. | ||
18 | .inst 'M' | ('Z' << 8) | (0x1310 << 16) @ tstne r0, #0x4d000 | ||
19 | #else | ||
20 | mov r0, r0 | ||
21 | #endif | ||
22 | .endm | ||
23 | |||
24 | .macro __EFI_HEADER | ||
25 | #ifdef CONFIG_EFI_STUB | ||
26 | b __efi_start | ||
27 | |||
28 | .set start_offset, __efi_start - start | ||
29 | .org start + 0x3c | ||
30 | @ | ||
31 | @ The PE header can be anywhere in the file, but for | ||
32 | @ simplicity we keep it together with the MSDOS header | ||
33 | @ The offset to the PE/COFF header needs to be at offset | ||
34 | @ 0x3C in the MSDOS header. | ||
35 | @ The only 2 fields of the MSDOS header that are used are this | ||
36 | @ PE/COFF offset, and the "MZ" bytes at offset 0x0. | ||
37 | @ | ||
38 | .long pe_header - start @ Offset to the PE header. | ||
39 | |||
40 | pe_header: | ||
41 | .ascii "PE\0\0" | ||
42 | |||
43 | coff_header: | ||
44 | .short 0x01c2 @ ARM or Thumb | ||
45 | .short 2 @ nr_sections | ||
46 | .long 0 @ TimeDateStamp | ||
47 | .long 0 @ PointerToSymbolTable | ||
48 | .long 1 @ NumberOfSymbols | ||
49 | .short section_table - optional_header | ||
50 | @ SizeOfOptionalHeader | ||
51 | .short 0x306 @ Characteristics. | ||
52 | @ IMAGE_FILE_32BIT_MACHINE | | ||
53 | @ IMAGE_FILE_DEBUG_STRIPPED | | ||
54 | @ IMAGE_FILE_EXECUTABLE_IMAGE | | ||
55 | @ IMAGE_FILE_LINE_NUMS_STRIPPED | ||
56 | |||
57 | optional_header: | ||
58 | .short 0x10b @ PE32 format | ||
59 | .byte 0x02 @ MajorLinkerVersion | ||
60 | .byte 0x14 @ MinorLinkerVersion | ||
61 | .long _end - __efi_start @ SizeOfCode | ||
62 | .long 0 @ SizeOfInitializedData | ||
63 | .long 0 @ SizeOfUninitializedData | ||
64 | .long efi_stub_entry - start @ AddressOfEntryPoint | ||
65 | .long start_offset @ BaseOfCode | ||
66 | .long 0 @ data | ||
67 | |||
68 | extra_header_fields: | ||
69 | .long 0 @ ImageBase | ||
70 | .long 0x200 @ SectionAlignment | ||
71 | .long 0x200 @ FileAlignment | ||
72 | .short 0 @ MajorOperatingSystemVersion | ||
73 | .short 0 @ MinorOperatingSystemVersion | ||
74 | .short 0 @ MajorImageVersion | ||
75 | .short 0 @ MinorImageVersion | ||
76 | .short 0 @ MajorSubsystemVersion | ||
77 | .short 0 @ MinorSubsystemVersion | ||
78 | .long 0 @ Win32VersionValue | ||
79 | |||
80 | .long _end - start @ SizeOfImage | ||
81 | .long start_offset @ SizeOfHeaders | ||
82 | .long 0 @ CheckSum | ||
83 | .short 0xa @ Subsystem (EFI application) | ||
84 | .short 0 @ DllCharacteristics | ||
85 | .long 0 @ SizeOfStackReserve | ||
86 | .long 0 @ SizeOfStackCommit | ||
87 | .long 0 @ SizeOfHeapReserve | ||
88 | .long 0 @ SizeOfHeapCommit | ||
89 | .long 0 @ LoaderFlags | ||
90 | .long 0x6 @ NumberOfRvaAndSizes | ||
91 | |||
92 | .quad 0 @ ExportTable | ||
93 | .quad 0 @ ImportTable | ||
94 | .quad 0 @ ResourceTable | ||
95 | .quad 0 @ ExceptionTable | ||
96 | .quad 0 @ CertificationTable | ||
97 | .quad 0 @ BaseRelocationTable | ||
98 | |||
99 | section_table: | ||
100 | @ | ||
101 | @ The EFI application loader requires a relocation section | ||
102 | @ because EFI applications must be relocatable. This is a | ||
103 | @ dummy section as far as we are concerned. | ||
104 | @ | ||
105 | .ascii ".reloc\0\0" | ||
106 | .long 0 @ VirtualSize | ||
107 | .long 0 @ VirtualAddress | ||
108 | .long 0 @ SizeOfRawData | ||
109 | .long 0 @ PointerToRawData | ||
110 | .long 0 @ PointerToRelocations | ||
111 | .long 0 @ PointerToLineNumbers | ||
112 | .short 0 @ NumberOfRelocations | ||
113 | .short 0 @ NumberOfLineNumbers | ||
114 | .long 0x42100040 @ Characteristics | ||
115 | |||
116 | .ascii ".text\0\0\0" | ||
117 | .long _end - __efi_start @ VirtualSize | ||
118 | .long __efi_start @ VirtualAddress | ||
119 | .long _edata - __efi_start @ SizeOfRawData | ||
120 | .long __efi_start @ PointerToRawData | ||
121 | .long 0 @ PointerToRelocations | ||
122 | .long 0 @ PointerToLineNumbers | ||
123 | .short 0 @ NumberOfRelocations | ||
124 | .short 0 @ NumberOfLineNumbers | ||
125 | .long 0xe0500020 @ Characteristics | ||
126 | |||
127 | .align 9 | ||
128 | __efi_start: | ||
129 | #endif | ||
130 | .endm | ||
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 06e983f59980..af11c2f8f3b7 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S | |||
@@ -12,6 +12,8 @@ | |||
12 | #include <asm/assembler.h> | 12 | #include <asm/assembler.h> |
13 | #include <asm/v7m.h> | 13 | #include <asm/v7m.h> |
14 | 14 | ||
15 | #include "efi-header.S" | ||
16 | |||
15 | AR_CLASS( .arch armv7-a ) | 17 | AR_CLASS( .arch armv7-a ) |
16 | M_CLASS( .arch armv7-m ) | 18 | M_CLASS( .arch armv7-m ) |
17 | 19 | ||
@@ -126,7 +128,7 @@ | |||
126 | start: | 128 | start: |
127 | .type start,#function | 129 | .type start,#function |
128 | .rept 7 | 130 | .rept 7 |
129 | mov r0, r0 | 131 | __nop |
130 | .endr | 132 | .endr |
131 | ARM( mov r0, r0 ) | 133 | ARM( mov r0, r0 ) |
132 | ARM( b 1f ) | 134 | ARM( b 1f ) |
@@ -139,7 +141,8 @@ start: | |||
139 | .word 0x04030201 @ endianness flag | 141 | .word 0x04030201 @ endianness flag |
140 | 142 | ||
141 | THUMB( .thumb ) | 143 | THUMB( .thumb ) |
142 | 1: | 144 | 1: __EFI_HEADER |
145 | |||
143 | ARM_BE8( setend be ) @ go BE8 if compiled for BE8 | 146 | ARM_BE8( setend be ) @ go BE8 if compiled for BE8 |
144 | AR_CLASS( mrs r9, cpsr ) | 147 | AR_CLASS( mrs r9, cpsr ) |
145 | #ifdef CONFIG_ARM_VIRT_EXT | 148 | #ifdef CONFIG_ARM_VIRT_EXT |
@@ -1353,6 +1356,53 @@ __enter_kernel: | |||
1353 | 1356 | ||
1354 | reloc_code_end: | 1357 | reloc_code_end: |
1355 | 1358 | ||
1359 | #ifdef CONFIG_EFI_STUB | ||
1360 | .align 2 | ||
1361 | _start: .long start - . | ||
1362 | |||
1363 | ENTRY(efi_stub_entry) | ||
1364 | @ allocate space on stack for passing current zImage address | ||
1365 | @ and for the EFI stub to return of new entry point of | ||
1366 | @ zImage, as EFI stub may copy the kernel. Pointer address | ||
1367 | @ is passed in r2. r0 and r1 are passed through from the | ||
1368 | @ EFI firmware to efi_entry | ||
1369 | adr ip, _start | ||
1370 | ldr r3, [ip] | ||
1371 | add r3, r3, ip | ||
1372 | stmfd sp!, {r3, lr} | ||
1373 | mov r2, sp @ pass zImage address in r2 | ||
1374 | bl efi_entry | ||
1375 | |||
1376 | @ Check for error return from EFI stub. r0 has FDT address | ||
1377 | @ or error code. | ||
1378 | cmn r0, #1 | ||
1379 | beq efi_load_fail | ||
1380 | |||
1381 | @ Preserve return value of efi_entry() in r4 | ||
1382 | mov r4, r0 | ||
1383 | bl cache_clean_flush | ||
1384 | bl cache_off | ||
1385 | |||
1386 | @ Set parameters for booting zImage according to boot protocol | ||
1387 | @ put FDT address in r2, it was returned by efi_entry() | ||
1388 | @ r1 is the machine type, and r0 needs to be 0 | ||
1389 | mov r0, #0 | ||
1390 | mov r1, #0xFFFFFFFF | ||
1391 | mov r2, r4 | ||
1392 | |||
1393 | @ Branch to (possibly) relocated zImage that is in [sp] | ||
1394 | ldr lr, [sp] | ||
1395 | ldr ip, =start_offset | ||
1396 | add lr, lr, ip | ||
1397 | mov pc, lr @ no mode switch | ||
1398 | |||
1399 | efi_load_fail: | ||
1400 | @ Return EFI_LOAD_ERROR to EFI firmware on error. | ||
1401 | ldr r0, =0x80000001 | ||
1402 | ldmfd sp!, {ip, pc} | ||
1403 | ENDPROC(efi_stub_entry) | ||
1404 | #endif | ||
1405 | |||
1356 | .align | 1406 | .align |
1357 | .section ".stack", "aw", %nobits | 1407 | .section ".stack", "aw", %nobits |
1358 | .L_user_stack: .space 4096 | 1408 | .L_user_stack: .space 4096 |
diff --git a/arch/arm/boot/compressed/vmlinux.lds.S b/arch/arm/boot/compressed/vmlinux.lds.S index 2b60b843ac5e..81c493156ce8 100644 --- a/arch/arm/boot/compressed/vmlinux.lds.S +++ b/arch/arm/boot/compressed/vmlinux.lds.S | |||
@@ -48,6 +48,13 @@ SECTIONS | |||
48 | *(.rodata) | 48 | *(.rodata) |
49 | *(.rodata.*) | 49 | *(.rodata.*) |
50 | } | 50 | } |
51 | .data : { | ||
52 | /* | ||
53 | * The EFI stub always executes from RAM, and runs strictly before the | ||
54 | * decompressor, so we can make an exception for its r/w data, and keep it | ||
55 | */ | ||
56 | *(.data.efistub) | ||
57 | } | ||
51 | .piggydata : { | 58 | .piggydata : { |
52 | *(.piggydata) | 59 | *(.piggydata) |
53 | } | 60 | } |
diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index bd425302c97a..16da6380eb85 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild | |||
@@ -3,6 +3,7 @@ | |||
3 | generic-y += bitsperlong.h | 3 | generic-y += bitsperlong.h |
4 | generic-y += cputime.h | 4 | generic-y += cputime.h |
5 | generic-y += current.h | 5 | generic-y += current.h |
6 | generic-y += early_ioremap.h | ||
6 | generic-y += emergency-restart.h | 7 | generic-y += emergency-restart.h |
7 | generic-y += errno.h | 8 | generic-y += errno.h |
8 | generic-y += exec.h | 9 | generic-y += exec.h |
diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h new file mode 100644 index 000000000000..e0eea72deb87 --- /dev/null +++ b/arch/arm/include/asm/efi.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #ifndef __ASM_ARM_EFI_H | ||
10 | #define __ASM_ARM_EFI_H | ||
11 | |||
12 | #include <asm/cacheflush.h> | ||
13 | #include <asm/cachetype.h> | ||
14 | #include <asm/early_ioremap.h> | ||
15 | #include <asm/fixmap.h> | ||
16 | #include <asm/highmem.h> | ||
17 | #include <asm/mach/map.h> | ||
18 | #include <asm/mmu_context.h> | ||
19 | #include <asm/pgtable.h> | ||
20 | |||
21 | #ifdef CONFIG_EFI | ||
22 | void efi_init(void); | ||
23 | |||
24 | int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); | ||
25 | |||
26 | #define efi_call_virt(f, ...) \ | ||
27 | ({ \ | ||
28 | efi_##f##_t *__f; \ | ||
29 | efi_status_t __s; \ | ||
30 | \ | ||
31 | efi_virtmap_load(); \ | ||
32 | __f = efi.systab->runtime->f; \ | ||
33 | __s = __f(__VA_ARGS__); \ | ||
34 | efi_virtmap_unload(); \ | ||
35 | __s; \ | ||
36 | }) | ||
37 | |||
38 | #define __efi_call_virt(f, ...) \ | ||
39 | ({ \ | ||
40 | efi_##f##_t *__f; \ | ||
41 | \ | ||
42 | efi_virtmap_load(); \ | ||
43 | __f = efi.systab->runtime->f; \ | ||
44 | __f(__VA_ARGS__); \ | ||
45 | efi_virtmap_unload(); \ | ||
46 | }) | ||
47 | |||
48 | static inline void efi_set_pgd(struct mm_struct *mm) | ||
49 | { | ||
50 | check_and_switch_context(mm, NULL); | ||
51 | } | ||
52 | |||
53 | void efi_virtmap_load(void); | ||
54 | void efi_virtmap_unload(void); | ||
55 | |||
56 | #else | ||
57 | #define efi_init() | ||
58 | #endif /* CONFIG_EFI */ | ||
59 | |||
60 | /* arch specific definitions used by the stub code */ | ||
61 | |||
62 | #define efi_call_early(f, ...) sys_table_arg->boottime->f(__VA_ARGS__) | ||
63 | |||
64 | /* | ||
65 | * A reasonable upper bound for the uncompressed kernel size is 32 MBytes, | ||
66 | * so we will reserve that amount of memory. We have no easy way to tell what | ||
67 | * the actuall size of code + data the uncompressed kernel will use. | ||
68 | * If this is insufficient, the decompressor will relocate itself out of the | ||
69 | * way before performing the decompression. | ||
70 | */ | ||
71 | #define MAX_UNCOMP_KERNEL_SIZE SZ_32M | ||
72 | |||
73 | /* | ||
74 | * The kernel zImage should preferably be located between 32 MB and 128 MB | ||
75 | * from the base of DRAM. The min address leaves space for a maximal size | ||
76 | * uncompressed image, and the max address is due to how the zImage decompressor | ||
77 | * picks a destination address. | ||
78 | */ | ||
79 | #define ZIMAGE_OFFSET_LIMIT SZ_128M | ||
80 | #define MIN_ZIMAGE_OFFSET MAX_UNCOMP_KERNEL_SIZE | ||
81 | #define MAX_FDT_OFFSET ZIMAGE_OFFSET_LIMIT | ||
82 | |||
83 | #endif /* _ASM_ARM_EFI_H */ | ||
diff --git a/arch/arm/include/asm/fixmap.h b/arch/arm/include/asm/fixmap.h index 58cfe9f1a687..5c17d2dec777 100644 --- a/arch/arm/include/asm/fixmap.h +++ b/arch/arm/include/asm/fixmap.h | |||
@@ -19,20 +19,47 @@ enum fixed_addresses { | |||
19 | FIX_TEXT_POKE0, | 19 | FIX_TEXT_POKE0, |
20 | FIX_TEXT_POKE1, | 20 | FIX_TEXT_POKE1, |
21 | 21 | ||
22 | __end_of_fixed_addresses | 22 | __end_of_fixmap_region, |
23 | |||
24 | /* | ||
25 | * Share the kmap() region with early_ioremap(): this is guaranteed | ||
26 | * not to clash since early_ioremap() is only available before | ||
27 | * paging_init(), and kmap() only after. | ||
28 | */ | ||
29 | #define NR_FIX_BTMAPS 32 | ||
30 | #define FIX_BTMAPS_SLOTS 7 | ||
31 | #define TOTAL_FIX_BTMAPS (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS) | ||
32 | |||
33 | FIX_BTMAP_END = __end_of_permanent_fixed_addresses, | ||
34 | FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1, | ||
35 | __end_of_early_ioremap_region | ||
23 | }; | 36 | }; |
24 | 37 | ||
38 | static const enum fixed_addresses __end_of_fixed_addresses = | ||
39 | __end_of_fixmap_region > __end_of_early_ioremap_region ? | ||
40 | __end_of_fixmap_region : __end_of_early_ioremap_region; | ||
41 | |||
25 | #define FIXMAP_PAGE_COMMON (L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY) | 42 | #define FIXMAP_PAGE_COMMON (L_PTE_YOUNG | L_PTE_PRESENT | L_PTE_XN | L_PTE_DIRTY) |
26 | 43 | ||
27 | #define FIXMAP_PAGE_NORMAL (FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK) | 44 | #define FIXMAP_PAGE_NORMAL (FIXMAP_PAGE_COMMON | L_PTE_MT_WRITEBACK) |
45 | #define FIXMAP_PAGE_RO (FIXMAP_PAGE_NORMAL | L_PTE_RDONLY) | ||
28 | 46 | ||
29 | /* Used by set_fixmap_(io|nocache), both meant for mapping a device */ | 47 | /* Used by set_fixmap_(io|nocache), both meant for mapping a device */ |
30 | #define FIXMAP_PAGE_IO (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED) | 48 | #define FIXMAP_PAGE_IO (FIXMAP_PAGE_COMMON | L_PTE_MT_DEV_SHARED | L_PTE_SHARED) |
31 | #define FIXMAP_PAGE_NOCACHE FIXMAP_PAGE_IO | 49 | #define FIXMAP_PAGE_NOCACHE FIXMAP_PAGE_IO |
32 | 50 | ||
51 | #define __early_set_fixmap __set_fixmap | ||
52 | |||
53 | #ifdef CONFIG_MMU | ||
54 | |||
33 | void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); | 55 | void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot); |
34 | void __init early_fixmap_init(void); | 56 | void __init early_fixmap_init(void); |
35 | 57 | ||
36 | #include <asm-generic/fixmap.h> | 58 | #include <asm-generic/fixmap.h> |
37 | 59 | ||
60 | #else | ||
61 | |||
62 | static inline void early_fixmap_init(void) { } | ||
63 | |||
64 | #endif | ||
38 | #endif | 65 | #endif |
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h index f98c7f32c9c8..9b7c328fb207 100644 --- a/arch/arm/include/asm/mach/map.h +++ b/arch/arm/include/asm/mach/map.h | |||
@@ -42,6 +42,8 @@ enum { | |||
42 | extern void iotable_init(struct map_desc *, int); | 42 | extern void iotable_init(struct map_desc *, int); |
43 | extern void vm_reserve_area_early(unsigned long addr, unsigned long size, | 43 | extern void vm_reserve_area_early(unsigned long addr, unsigned long size, |
44 | void *caller); | 44 | void *caller); |
45 | extern void create_mapping_late(struct mm_struct *mm, struct map_desc *md, | ||
46 | bool ng); | ||
45 | 47 | ||
46 | #ifdef CONFIG_DEBUG_LL | 48 | #ifdef CONFIG_DEBUG_LL |
47 | extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr); | 49 | extern void debug_ll_addr(unsigned long *paddr, unsigned long *vaddr); |
diff --git a/arch/arm/include/asm/mmu_context.h b/arch/arm/include/asm/mmu_context.h index 9b32f76bb0dd..432ce8176498 100644 --- a/arch/arm/include/asm/mmu_context.h +++ b/arch/arm/include/asm/mmu_context.h | |||
@@ -26,7 +26,7 @@ void __check_vmalloc_seq(struct mm_struct *mm); | |||
26 | #ifdef CONFIG_CPU_HAS_ASID | 26 | #ifdef CONFIG_CPU_HAS_ASID |
27 | 27 | ||
28 | void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); | 28 | void check_and_switch_context(struct mm_struct *mm, struct task_struct *tsk); |
29 | #define init_new_context(tsk,mm) ({ atomic64_set(&mm->context.id, 0); 0; }) | 29 | #define init_new_context(tsk,mm) ({ atomic64_set(&(mm)->context.id, 0); 0; }) |
30 | 30 | ||
31 | #ifdef CONFIG_ARM_ERRATA_798181 | 31 | #ifdef CONFIG_ARM_ERRATA_798181 |
32 | void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm, | 32 | void a15_erratum_get_cpumask(int this_cpu, struct mm_struct *mm, |
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 82bdac0f2804..f729085ece28 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -76,6 +76,7 @@ obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_xscale.o perf_event_v6.o \ | |||
76 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt | 76 | AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt |
77 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o | 77 | obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o |
78 | obj-$(CONFIG_VDSO) += vdso.o | 78 | obj-$(CONFIG_VDSO) += vdso.o |
79 | obj-$(CONFIG_EFI) += efi.o | ||
79 | 80 | ||
80 | ifneq ($(CONFIG_ARCH_EBSA110),y) | 81 | ifneq ($(CONFIG_ARCH_EBSA110),y) |
81 | obj-y += io.o | 82 | obj-y += io.o |
diff --git a/arch/arm/kernel/efi.c b/arch/arm/kernel/efi.c new file mode 100644 index 000000000000..ff8a9d8acfac --- /dev/null +++ b/arch/arm/kernel/efi.c | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Linaro Ltd <ard.biesheuvel@linaro.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/efi.h> | ||
10 | #include <asm/efi.h> | ||
11 | #include <asm/mach/map.h> | ||
12 | #include <asm/mmu_context.h> | ||
13 | |||
14 | int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) | ||
15 | { | ||
16 | struct map_desc desc = { | ||
17 | .virtual = md->virt_addr, | ||
18 | .pfn = __phys_to_pfn(md->phys_addr), | ||
19 | .length = md->num_pages * EFI_PAGE_SIZE, | ||
20 | }; | ||
21 | |||
22 | /* | ||
23 | * Order is important here: memory regions may have all of the | ||
24 | * bits below set (and usually do), so we check them in order of | ||
25 | * preference. | ||
26 | */ | ||
27 | if (md->attribute & EFI_MEMORY_WB) | ||
28 | desc.type = MT_MEMORY_RWX; | ||
29 | else if (md->attribute & EFI_MEMORY_WT) | ||
30 | desc.type = MT_MEMORY_RWX_NONCACHED; | ||
31 | else if (md->attribute & EFI_MEMORY_WC) | ||
32 | desc.type = MT_DEVICE_WC; | ||
33 | else | ||
34 | desc.type = MT_DEVICE; | ||
35 | |||
36 | create_mapping_late(mm, &desc, true); | ||
37 | return 0; | ||
38 | } | ||
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index e07f567487cd..7d0cba6f1cc5 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * it under the terms of the GNU General Public License version 2 as | 7 | * it under the terms of the GNU General Public License version 2 as |
8 | * published by the Free Software Foundation. | 8 | * published by the Free Software Foundation. |
9 | */ | 9 | */ |
10 | #include <linux/efi.h> | ||
10 | #include <linux/export.h> | 11 | #include <linux/export.h> |
11 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
12 | #include <linux/stddef.h> | 13 | #include <linux/stddef.h> |
@@ -37,7 +38,9 @@ | |||
37 | #include <asm/cp15.h> | 38 | #include <asm/cp15.h> |
38 | #include <asm/cpu.h> | 39 | #include <asm/cpu.h> |
39 | #include <asm/cputype.h> | 40 | #include <asm/cputype.h> |
41 | #include <asm/efi.h> | ||
40 | #include <asm/elf.h> | 42 | #include <asm/elf.h> |
43 | #include <asm/early_ioremap.h> | ||
41 | #include <asm/fixmap.h> | 44 | #include <asm/fixmap.h> |
42 | #include <asm/procinfo.h> | 45 | #include <asm/procinfo.h> |
43 | #include <asm/psci.h> | 46 | #include <asm/psci.h> |
@@ -1023,8 +1026,8 @@ void __init setup_arch(char **cmdline_p) | |||
1023 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); | 1026 | strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); |
1024 | *cmdline_p = cmd_line; | 1027 | *cmdline_p = cmd_line; |
1025 | 1028 | ||
1026 | if (IS_ENABLED(CONFIG_FIX_EARLYCON_MEM)) | 1029 | early_fixmap_init(); |
1027 | early_fixmap_init(); | 1030 | early_ioremap_init(); |
1028 | 1031 | ||
1029 | parse_early_param(); | 1032 | parse_early_param(); |
1030 | 1033 | ||
@@ -1032,9 +1035,12 @@ void __init setup_arch(char **cmdline_p) | |||
1032 | early_paging_init(mdesc); | 1035 | early_paging_init(mdesc); |
1033 | #endif | 1036 | #endif |
1034 | setup_dma_zone(mdesc); | 1037 | setup_dma_zone(mdesc); |
1038 | efi_init(); | ||
1035 | sanity_check_meminfo(); | 1039 | sanity_check_meminfo(); |
1036 | arm_memblock_init(mdesc); | 1040 | arm_memblock_init(mdesc); |
1037 | 1041 | ||
1042 | early_ioremap_reset(); | ||
1043 | |||
1038 | paging_init(mdesc); | 1044 | paging_init(mdesc); |
1039 | request_standard_resources(mdesc); | 1045 | request_standard_resources(mdesc); |
1040 | 1046 | ||
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c index 7f8cd1b3557f..49bd08178008 100644 --- a/arch/arm/mm/init.c +++ b/arch/arm/mm/init.c | |||
@@ -192,7 +192,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max_low, | |||
192 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID | 192 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID |
193 | int pfn_valid(unsigned long pfn) | 193 | int pfn_valid(unsigned long pfn) |
194 | { | 194 | { |
195 | return memblock_is_memory(__pfn_to_phys(pfn)); | 195 | return memblock_is_map_memory(__pfn_to_phys(pfn)); |
196 | } | 196 | } |
197 | EXPORT_SYMBOL(pfn_valid); | 197 | EXPORT_SYMBOL(pfn_valid); |
198 | #endif | 198 | #endif |
@@ -433,6 +433,9 @@ static void __init free_highpages(void) | |||
433 | if (end <= max_low) | 433 | if (end <= max_low) |
434 | continue; | 434 | continue; |
435 | 435 | ||
436 | if (memblock_is_nomap(mem)) | ||
437 | continue; | ||
438 | |||
436 | /* Truncate partial highmem entries */ | 439 | /* Truncate partial highmem entries */ |
437 | if (start < max_low) | 440 | if (start < max_low) |
438 | start = max_low; | 441 | start = max_low; |
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c index 0c81056c1dd7..66a978d05958 100644 --- a/arch/arm/mm/ioremap.c +++ b/arch/arm/mm/ioremap.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/cp15.h> | 30 | #include <asm/cp15.h> |
31 | #include <asm/cputype.h> | 31 | #include <asm/cputype.h> |
32 | #include <asm/cacheflush.h> | 32 | #include <asm/cacheflush.h> |
33 | #include <asm/early_ioremap.h> | ||
33 | #include <asm/mmu_context.h> | 34 | #include <asm/mmu_context.h> |
34 | #include <asm/pgalloc.h> | 35 | #include <asm/pgalloc.h> |
35 | #include <asm/tlbflush.h> | 36 | #include <asm/tlbflush.h> |
@@ -469,3 +470,11 @@ int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr) | |||
469 | } | 470 | } |
470 | EXPORT_SYMBOL_GPL(pci_ioremap_io); | 471 | EXPORT_SYMBOL_GPL(pci_ioremap_io); |
471 | #endif | 472 | #endif |
473 | |||
474 | /* | ||
475 | * Must be called after early_fixmap_init | ||
476 | */ | ||
477 | void __init early_ioremap_init(void) | ||
478 | { | ||
479 | early_ioremap_setup(); | ||
480 | } | ||
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index de9f8921e407..a87f6cc3fa2b 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -390,7 +390,7 @@ void __init early_fixmap_init(void) | |||
390 | * The early fixmap range spans multiple pmds, for which | 390 | * The early fixmap range spans multiple pmds, for which |
391 | * we are not prepared: | 391 | * we are not prepared: |
392 | */ | 392 | */ |
393 | BUILD_BUG_ON((__fix_to_virt(__end_of_permanent_fixed_addresses) >> PMD_SHIFT) | 393 | BUILD_BUG_ON((__fix_to_virt(__end_of_early_ioremap_region) >> PMD_SHIFT) |
394 | != FIXADDR_TOP >> PMD_SHIFT); | 394 | != FIXADDR_TOP >> PMD_SHIFT); |
395 | 395 | ||
396 | pmd = fixmap_pmd(FIXADDR_TOP); | 396 | pmd = fixmap_pmd(FIXADDR_TOP); |
@@ -724,30 +724,49 @@ static void __init *early_alloc(unsigned long sz) | |||
724 | return early_alloc_aligned(sz, sz); | 724 | return early_alloc_aligned(sz, sz); |
725 | } | 725 | } |
726 | 726 | ||
727 | static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, unsigned long prot) | 727 | static void *__init late_alloc(unsigned long sz) |
728 | { | ||
729 | void *ptr = (void *)__get_free_pages(PGALLOC_GFP, get_order(sz)); | ||
730 | |||
731 | BUG_ON(!ptr); | ||
732 | return ptr; | ||
733 | } | ||
734 | |||
735 | static pte_t * __init pte_alloc(pmd_t *pmd, unsigned long addr, | ||
736 | unsigned long prot, | ||
737 | void *(*alloc)(unsigned long sz)) | ||
728 | { | 738 | { |
729 | if (pmd_none(*pmd)) { | 739 | if (pmd_none(*pmd)) { |
730 | pte_t *pte = early_alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); | 740 | pte_t *pte = alloc(PTE_HWTABLE_OFF + PTE_HWTABLE_SIZE); |
731 | __pmd_populate(pmd, __pa(pte), prot); | 741 | __pmd_populate(pmd, __pa(pte), prot); |
732 | } | 742 | } |
733 | BUG_ON(pmd_bad(*pmd)); | 743 | BUG_ON(pmd_bad(*pmd)); |
734 | return pte_offset_kernel(pmd, addr); | 744 | return pte_offset_kernel(pmd, addr); |
735 | } | 745 | } |
736 | 746 | ||
747 | static pte_t * __init early_pte_alloc(pmd_t *pmd, unsigned long addr, | ||
748 | unsigned long prot) | ||
749 | { | ||
750 | return pte_alloc(pmd, addr, prot, early_alloc); | ||
751 | } | ||
752 | |||
737 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, | 753 | static void __init alloc_init_pte(pmd_t *pmd, unsigned long addr, |
738 | unsigned long end, unsigned long pfn, | 754 | unsigned long end, unsigned long pfn, |
739 | const struct mem_type *type) | 755 | const struct mem_type *type, |
756 | void *(*alloc)(unsigned long sz), | ||
757 | bool ng) | ||
740 | { | 758 | { |
741 | pte_t *pte = early_pte_alloc(pmd, addr, type->prot_l1); | 759 | pte_t *pte = pte_alloc(pmd, addr, type->prot_l1, alloc); |
742 | do { | 760 | do { |
743 | set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), 0); | 761 | set_pte_ext(pte, pfn_pte(pfn, __pgprot(type->prot_pte)), |
762 | ng ? PTE_EXT_NG : 0); | ||
744 | pfn++; | 763 | pfn++; |
745 | } while (pte++, addr += PAGE_SIZE, addr != end); | 764 | } while (pte++, addr += PAGE_SIZE, addr != end); |
746 | } | 765 | } |
747 | 766 | ||
748 | static void __init __map_init_section(pmd_t *pmd, unsigned long addr, | 767 | static void __init __map_init_section(pmd_t *pmd, unsigned long addr, |
749 | unsigned long end, phys_addr_t phys, | 768 | unsigned long end, phys_addr_t phys, |
750 | const struct mem_type *type) | 769 | const struct mem_type *type, bool ng) |
751 | { | 770 | { |
752 | pmd_t *p = pmd; | 771 | pmd_t *p = pmd; |
753 | 772 | ||
@@ -765,7 +784,7 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr, | |||
765 | pmd++; | 784 | pmd++; |
766 | #endif | 785 | #endif |
767 | do { | 786 | do { |
768 | *pmd = __pmd(phys | type->prot_sect); | 787 | *pmd = __pmd(phys | type->prot_sect | (ng ? PMD_SECT_nG : 0)); |
769 | phys += SECTION_SIZE; | 788 | phys += SECTION_SIZE; |
770 | } while (pmd++, addr += SECTION_SIZE, addr != end); | 789 | } while (pmd++, addr += SECTION_SIZE, addr != end); |
771 | 790 | ||
@@ -774,7 +793,8 @@ static void __init __map_init_section(pmd_t *pmd, unsigned long addr, | |||
774 | 793 | ||
775 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | 794 | static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, |
776 | unsigned long end, phys_addr_t phys, | 795 | unsigned long end, phys_addr_t phys, |
777 | const struct mem_type *type) | 796 | const struct mem_type *type, |
797 | void *(*alloc)(unsigned long sz), bool ng) | ||
778 | { | 798 | { |
779 | pmd_t *pmd = pmd_offset(pud, addr); | 799 | pmd_t *pmd = pmd_offset(pud, addr); |
780 | unsigned long next; | 800 | unsigned long next; |
@@ -792,10 +812,10 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | |||
792 | */ | 812 | */ |
793 | if (type->prot_sect && | 813 | if (type->prot_sect && |
794 | ((addr | next | phys) & ~SECTION_MASK) == 0) { | 814 | ((addr | next | phys) & ~SECTION_MASK) == 0) { |
795 | __map_init_section(pmd, addr, next, phys, type); | 815 | __map_init_section(pmd, addr, next, phys, type, ng); |
796 | } else { | 816 | } else { |
797 | alloc_init_pte(pmd, addr, next, | 817 | alloc_init_pte(pmd, addr, next, |
798 | __phys_to_pfn(phys), type); | 818 | __phys_to_pfn(phys), type, alloc, ng); |
799 | } | 819 | } |
800 | 820 | ||
801 | phys += next - addr; | 821 | phys += next - addr; |
@@ -805,21 +825,24 @@ static void __init alloc_init_pmd(pud_t *pud, unsigned long addr, | |||
805 | 825 | ||
806 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, | 826 | static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr, |
807 | unsigned long end, phys_addr_t phys, | 827 | unsigned long end, phys_addr_t phys, |
808 | const struct mem_type *type) | 828 | const struct mem_type *type, |
829 | void *(*alloc)(unsigned long sz), bool ng) | ||
809 | { | 830 | { |
810 | pud_t *pud = pud_offset(pgd, addr); | 831 | pud_t *pud = pud_offset(pgd, addr); |
811 | unsigned long next; | 832 | unsigned long next; |
812 | 833 | ||
813 | do { | 834 | do { |
814 | next = pud_addr_end(addr, end); | 835 | next = pud_addr_end(addr, end); |
815 | alloc_init_pmd(pud, addr, next, phys, type); | 836 | alloc_init_pmd(pud, addr, next, phys, type, alloc, ng); |
816 | phys += next - addr; | 837 | phys += next - addr; |
817 | } while (pud++, addr = next, addr != end); | 838 | } while (pud++, addr = next, addr != end); |
818 | } | 839 | } |
819 | 840 | ||
820 | #ifndef CONFIG_ARM_LPAE | 841 | #ifndef CONFIG_ARM_LPAE |
821 | static void __init create_36bit_mapping(struct map_desc *md, | 842 | static void __init create_36bit_mapping(struct mm_struct *mm, |
822 | const struct mem_type *type) | 843 | struct map_desc *md, |
844 | const struct mem_type *type, | ||
845 | bool ng) | ||
823 | { | 846 | { |
824 | unsigned long addr, length, end; | 847 | unsigned long addr, length, end; |
825 | phys_addr_t phys; | 848 | phys_addr_t phys; |
@@ -859,7 +882,7 @@ static void __init create_36bit_mapping(struct map_desc *md, | |||
859 | */ | 882 | */ |
860 | phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20); | 883 | phys |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20); |
861 | 884 | ||
862 | pgd = pgd_offset_k(addr); | 885 | pgd = pgd_offset(mm, addr); |
863 | end = addr + length; | 886 | end = addr + length; |
864 | do { | 887 | do { |
865 | pud_t *pud = pud_offset(pgd, addr); | 888 | pud_t *pud = pud_offset(pgd, addr); |
@@ -867,7 +890,8 @@ static void __init create_36bit_mapping(struct map_desc *md, | |||
867 | int i; | 890 | int i; |
868 | 891 | ||
869 | for (i = 0; i < 16; i++) | 892 | for (i = 0; i < 16; i++) |
870 | *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER); | 893 | *pmd++ = __pmd(phys | type->prot_sect | PMD_SECT_SUPER | |
894 | (ng ? PMD_SECT_nG : 0)); | ||
871 | 895 | ||
872 | addr += SUPERSECTION_SIZE; | 896 | addr += SUPERSECTION_SIZE; |
873 | phys += SUPERSECTION_SIZE; | 897 | phys += SUPERSECTION_SIZE; |
@@ -876,33 +900,15 @@ static void __init create_36bit_mapping(struct map_desc *md, | |||
876 | } | 900 | } |
877 | #endif /* !CONFIG_ARM_LPAE */ | 901 | #endif /* !CONFIG_ARM_LPAE */ |
878 | 902 | ||
879 | /* | 903 | static void __init __create_mapping(struct mm_struct *mm, struct map_desc *md, |
880 | * Create the page directory entries and any necessary | 904 | void *(*alloc)(unsigned long sz), |
881 | * page tables for the mapping specified by `md'. We | 905 | bool ng) |
882 | * are able to cope here with varying sizes and address | ||
883 | * offsets, and we take full advantage of sections and | ||
884 | * supersections. | ||
885 | */ | ||
886 | static void __init create_mapping(struct map_desc *md) | ||
887 | { | 906 | { |
888 | unsigned long addr, length, end; | 907 | unsigned long addr, length, end; |
889 | phys_addr_t phys; | 908 | phys_addr_t phys; |
890 | const struct mem_type *type; | 909 | const struct mem_type *type; |
891 | pgd_t *pgd; | 910 | pgd_t *pgd; |
892 | 911 | ||
893 | if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { | ||
894 | pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n", | ||
895 | (long long)__pfn_to_phys((u64)md->pfn), md->virtual); | ||
896 | return; | ||
897 | } | ||
898 | |||
899 | if ((md->type == MT_DEVICE || md->type == MT_ROM) && | ||
900 | md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START && | ||
901 | (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) { | ||
902 | pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n", | ||
903 | (long long)__pfn_to_phys((u64)md->pfn), md->virtual); | ||
904 | } | ||
905 | |||
906 | type = &mem_types[md->type]; | 912 | type = &mem_types[md->type]; |
907 | 913 | ||
908 | #ifndef CONFIG_ARM_LPAE | 914 | #ifndef CONFIG_ARM_LPAE |
@@ -910,7 +916,7 @@ static void __init create_mapping(struct map_desc *md) | |||
910 | * Catch 36-bit addresses | 916 | * Catch 36-bit addresses |
911 | */ | 917 | */ |
912 | if (md->pfn >= 0x100000) { | 918 | if (md->pfn >= 0x100000) { |
913 | create_36bit_mapping(md, type); | 919 | create_36bit_mapping(mm, md, type, ng); |
914 | return; | 920 | return; |
915 | } | 921 | } |
916 | #endif | 922 | #endif |
@@ -925,12 +931,12 @@ static void __init create_mapping(struct map_desc *md) | |||
925 | return; | 931 | return; |
926 | } | 932 | } |
927 | 933 | ||
928 | pgd = pgd_offset_k(addr); | 934 | pgd = pgd_offset(mm, addr); |
929 | end = addr + length; | 935 | end = addr + length; |
930 | do { | 936 | do { |
931 | unsigned long next = pgd_addr_end(addr, end); | 937 | unsigned long next = pgd_addr_end(addr, end); |
932 | 938 | ||
933 | alloc_init_pud(pgd, addr, next, phys, type); | 939 | alloc_init_pud(pgd, addr, next, phys, type, alloc, ng); |
934 | 940 | ||
935 | phys += next - addr; | 941 | phys += next - addr; |
936 | addr = next; | 942 | addr = next; |
@@ -938,6 +944,43 @@ static void __init create_mapping(struct map_desc *md) | |||
938 | } | 944 | } |
939 | 945 | ||
940 | /* | 946 | /* |
947 | * Create the page directory entries and any necessary | ||
948 | * page tables for the mapping specified by `md'. We | ||
949 | * are able to cope here with varying sizes and address | ||
950 | * offsets, and we take full advantage of sections and | ||
951 | * supersections. | ||
952 | */ | ||
953 | static void __init create_mapping(struct map_desc *md) | ||
954 | { | ||
955 | if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) { | ||
956 | pr_warn("BUG: not creating mapping for 0x%08llx at 0x%08lx in user region\n", | ||
957 | (long long)__pfn_to_phys((u64)md->pfn), md->virtual); | ||
958 | return; | ||
959 | } | ||
960 | |||
961 | if ((md->type == MT_DEVICE || md->type == MT_ROM) && | ||
962 | md->virtual >= PAGE_OFFSET && md->virtual < FIXADDR_START && | ||
963 | (md->virtual < VMALLOC_START || md->virtual >= VMALLOC_END)) { | ||
964 | pr_warn("BUG: mapping for 0x%08llx at 0x%08lx out of vmalloc space\n", | ||
965 | (long long)__pfn_to_phys((u64)md->pfn), md->virtual); | ||
966 | } | ||
967 | |||
968 | __create_mapping(&init_mm, md, early_alloc, false); | ||
969 | } | ||
970 | |||
971 | void __init create_mapping_late(struct mm_struct *mm, struct map_desc *md, | ||
972 | bool ng) | ||
973 | { | ||
974 | #ifdef CONFIG_ARM_LPAE | ||
975 | pud_t *pud = pud_alloc(mm, pgd_offset(mm, md->virtual), md->virtual); | ||
976 | if (WARN_ON(!pud)) | ||
977 | return; | ||
978 | pmd_alloc(mm, pud, 0); | ||
979 | #endif | ||
980 | __create_mapping(mm, md, late_alloc, ng); | ||
981 | } | ||
982 | |||
983 | /* | ||
941 | * Create the architecture specific mappings | 984 | * Create the architecture specific mappings |
942 | */ | 985 | */ |
943 | void __init iotable_init(struct map_desc *io_desc, int nr) | 986 | void __init iotable_init(struct map_desc *io_desc, int nr) |
@@ -1392,6 +1435,9 @@ static void __init map_lowmem(void) | |||
1392 | phys_addr_t end = start + reg->size; | 1435 | phys_addr_t end = start + reg->size; |
1393 | struct map_desc map; | 1436 | struct map_desc map; |
1394 | 1437 | ||
1438 | if (memblock_is_nomap(reg)) | ||
1439 | continue; | ||
1440 | |||
1395 | if (end > arm_lowmem_limit) | 1441 | if (end > arm_lowmem_limit) |
1396 | end = arm_lowmem_limit; | 1442 | end = arm_lowmem_limit; |
1397 | if (start >= end) | 1443 | if (start >= end) |
diff --git a/arch/arm64/include/asm/efi.h b/arch/arm64/include/asm/efi.h index ef572206f1c3..8e88a696c9cb 100644 --- a/arch/arm64/include/asm/efi.h +++ b/arch/arm64/include/asm/efi.h | |||
@@ -2,7 +2,9 @@ | |||
2 | #define _ASM_EFI_H | 2 | #define _ASM_EFI_H |
3 | 3 | ||
4 | #include <asm/io.h> | 4 | #include <asm/io.h> |
5 | #include <asm/mmu_context.h> | ||
5 | #include <asm/neon.h> | 6 | #include <asm/neon.h> |
7 | #include <asm/tlbflush.h> | ||
6 | 8 | ||
7 | #ifdef CONFIG_EFI | 9 | #ifdef CONFIG_EFI |
8 | extern void efi_init(void); | 10 | extern void efi_init(void); |
@@ -10,6 +12,8 @@ extern void efi_init(void); | |||
10 | #define efi_init() | 12 | #define efi_init() |
11 | #endif | 13 | #endif |
12 | 14 | ||
15 | int efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md); | ||
16 | |||
13 | #define efi_call_virt(f, ...) \ | 17 | #define efi_call_virt(f, ...) \ |
14 | ({ \ | 18 | ({ \ |
15 | efi_##f##_t *__f; \ | 19 | efi_##f##_t *__f; \ |
@@ -63,6 +67,11 @@ extern void efi_init(void); | |||
63 | * Services are enabled and the EFI_RUNTIME_SERVICES bit set. | 67 | * Services are enabled and the EFI_RUNTIME_SERVICES bit set. |
64 | */ | 68 | */ |
65 | 69 | ||
70 | static inline void efi_set_pgd(struct mm_struct *mm) | ||
71 | { | ||
72 | switch_mm(NULL, mm, NULL); | ||
73 | } | ||
74 | |||
66 | void efi_virtmap_load(void); | 75 | void efi_virtmap_load(void); |
67 | void efi_virtmap_unload(void); | 76 | void efi_virtmap_unload(void); |
68 | 77 | ||
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c index 4eeb17198cfa..b6abc852f2a1 100644 --- a/arch/arm64/kernel/efi.c +++ b/arch/arm64/kernel/efi.c | |||
@@ -11,317 +11,34 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/atomic.h> | ||
15 | #include <linux/dmi.h> | 14 | #include <linux/dmi.h> |
16 | #include <linux/efi.h> | 15 | #include <linux/efi.h> |
17 | #include <linux/export.h> | 16 | #include <linux/init.h> |
18 | #include <linux/memblock.h> | ||
19 | #include <linux/mm_types.h> | ||
20 | #include <linux/bootmem.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_fdt.h> | ||
23 | #include <linux/preempt.h> | ||
24 | #include <linux/rbtree.h> | ||
25 | #include <linux/rwsem.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/spinlock.h> | ||
29 | 17 | ||
30 | #include <asm/cacheflush.h> | ||
31 | #include <asm/efi.h> | 18 | #include <asm/efi.h> |
32 | #include <asm/tlbflush.h> | ||
33 | #include <asm/mmu_context.h> | ||
34 | #include <asm/mmu.h> | ||
35 | #include <asm/pgtable.h> | ||
36 | 19 | ||
37 | struct efi_memory_map memmap; | 20 | int __init efi_create_mapping(struct mm_struct *mm, efi_memory_desc_t *md) |
38 | |||
39 | static u64 efi_system_table; | ||
40 | |||
41 | static pgd_t efi_pgd[PTRS_PER_PGD] __page_aligned_bss; | ||
42 | |||
43 | static struct mm_struct efi_mm = { | ||
44 | .mm_rb = RB_ROOT, | ||
45 | .pgd = efi_pgd, | ||
46 | .mm_users = ATOMIC_INIT(2), | ||
47 | .mm_count = ATOMIC_INIT(1), | ||
48 | .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), | ||
49 | .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), | ||
50 | .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), | ||
51 | }; | ||
52 | |||
53 | static int __init is_normal_ram(efi_memory_desc_t *md) | ||
54 | { | ||
55 | if (md->attribute & EFI_MEMORY_WB) | ||
56 | return 1; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Translate a EFI virtual address into a physical address: this is necessary, | ||
62 | * as some data members of the EFI system table are virtually remapped after | ||
63 | * SetVirtualAddressMap() has been called. | ||
64 | */ | ||
65 | static phys_addr_t efi_to_phys(unsigned long addr) | ||
66 | { | 21 | { |
67 | efi_memory_desc_t *md; | 22 | pteval_t prot_val; |
68 | |||
69 | for_each_efi_memory_desc(&memmap, md) { | ||
70 | if (!(md->attribute & EFI_MEMORY_RUNTIME)) | ||
71 | continue; | ||
72 | if (md->virt_addr == 0) | ||
73 | /* no virtual mapping has been installed by the stub */ | ||
74 | break; | ||
75 | if (md->virt_addr <= addr && | ||
76 | (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) | ||
77 | return md->phys_addr + addr - md->virt_addr; | ||
78 | } | ||
79 | return addr; | ||
80 | } | ||
81 | |||
82 | static int __init uefi_init(void) | ||
83 | { | ||
84 | efi_char16_t *c16; | ||
85 | void *config_tables; | ||
86 | u64 table_size; | ||
87 | char vendor[100] = "unknown"; | ||
88 | int i, retval; | ||
89 | |||
90 | efi.systab = early_memremap(efi_system_table, | ||
91 | sizeof(efi_system_table_t)); | ||
92 | if (efi.systab == NULL) { | ||
93 | pr_warn("Unable to map EFI system table.\n"); | ||
94 | return -ENOMEM; | ||
95 | } | ||
96 | |||
97 | set_bit(EFI_BOOT, &efi.flags); | ||
98 | set_bit(EFI_64BIT, &efi.flags); | ||
99 | 23 | ||
100 | /* | 24 | /* |
101 | * Verify the EFI Table | 25 | * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be |
26 | * executable, everything else can be mapped with the XN bits | ||
27 | * set. | ||
102 | */ | 28 | */ |
103 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { | 29 | if ((md->attribute & EFI_MEMORY_WB) == 0) |
104 | pr_err("System table signature incorrect\n"); | 30 | prot_val = PROT_DEVICE_nGnRE; |
105 | retval = -EINVAL; | 31 | else if (md->type == EFI_RUNTIME_SERVICES_CODE || |
106 | goto out; | 32 | !PAGE_ALIGNED(md->phys_addr)) |
107 | } | 33 | prot_val = pgprot_val(PAGE_KERNEL_EXEC); |
108 | if ((efi.systab->hdr.revision >> 16) < 2) | 34 | else |
109 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", | 35 | prot_val = pgprot_val(PAGE_KERNEL); |
110 | efi.systab->hdr.revision >> 16, | 36 | |
111 | efi.systab->hdr.revision & 0xffff); | 37 | create_pgd_mapping(mm, md->phys_addr, md->virt_addr, |
112 | 38 | md->num_pages << EFI_PAGE_SHIFT, | |
113 | /* Show what we know for posterity */ | 39 | __pgprot(prot_val | PTE_NG)); |
114 | c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), | ||
115 | sizeof(vendor) * sizeof(efi_char16_t)); | ||
116 | if (c16) { | ||
117 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) | ||
118 | vendor[i] = c16[i]; | ||
119 | vendor[i] = '\0'; | ||
120 | early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t)); | ||
121 | } | ||
122 | |||
123 | pr_info("EFI v%u.%.02u by %s\n", | ||
124 | efi.systab->hdr.revision >> 16, | ||
125 | efi.systab->hdr.revision & 0xffff, vendor); | ||
126 | |||
127 | table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; | ||
128 | config_tables = early_memremap(efi_to_phys(efi.systab->tables), | ||
129 | table_size); | ||
130 | if (config_tables == NULL) { | ||
131 | pr_warn("Unable to map EFI config table array.\n"); | ||
132 | retval = -ENOMEM; | ||
133 | goto out; | ||
134 | } | ||
135 | retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, | ||
136 | sizeof(efi_config_table_64_t), NULL); | ||
137 | |||
138 | early_memunmap(config_tables, table_size); | ||
139 | out: | ||
140 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); | ||
141 | return retval; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Return true for RAM regions we want to permanently reserve. | ||
146 | */ | ||
147 | static __init int is_reserve_region(efi_memory_desc_t *md) | ||
148 | { | ||
149 | switch (md->type) { | ||
150 | case EFI_LOADER_CODE: | ||
151 | case EFI_LOADER_DATA: | ||
152 | case EFI_BOOT_SERVICES_CODE: | ||
153 | case EFI_BOOT_SERVICES_DATA: | ||
154 | case EFI_CONVENTIONAL_MEMORY: | ||
155 | case EFI_PERSISTENT_MEMORY: | ||
156 | return 0; | ||
157 | default: | ||
158 | break; | ||
159 | } | ||
160 | return is_normal_ram(md); | ||
161 | } | ||
162 | |||
163 | static __init void reserve_regions(void) | ||
164 | { | ||
165 | efi_memory_desc_t *md; | ||
166 | u64 paddr, npages, size; | ||
167 | |||
168 | if (efi_enabled(EFI_DBG)) | ||
169 | pr_info("Processing EFI memory map:\n"); | ||
170 | |||
171 | for_each_efi_memory_desc(&memmap, md) { | ||
172 | paddr = md->phys_addr; | ||
173 | npages = md->num_pages; | ||
174 | |||
175 | if (efi_enabled(EFI_DBG)) { | ||
176 | char buf[64]; | ||
177 | |||
178 | pr_info(" 0x%012llx-0x%012llx %s", | ||
179 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, | ||
180 | efi_md_typeattr_format(buf, sizeof(buf), md)); | ||
181 | } | ||
182 | |||
183 | memrange_efi_to_native(&paddr, &npages); | ||
184 | size = npages << PAGE_SHIFT; | ||
185 | |||
186 | if (is_normal_ram(md)) | ||
187 | early_init_dt_add_memory_arch(paddr, size); | ||
188 | |||
189 | if (is_reserve_region(md)) { | ||
190 | memblock_reserve(paddr, size); | ||
191 | if (efi_enabled(EFI_DBG)) | ||
192 | pr_cont("*"); | ||
193 | } | ||
194 | |||
195 | if (efi_enabled(EFI_DBG)) | ||
196 | pr_cont("\n"); | ||
197 | } | ||
198 | |||
199 | set_bit(EFI_MEMMAP, &efi.flags); | ||
200 | } | ||
201 | |||
202 | void __init efi_init(void) | ||
203 | { | ||
204 | struct efi_fdt_params params; | ||
205 | |||
206 | /* Grab UEFI information placed in FDT by stub */ | ||
207 | if (!efi_get_fdt_params(¶ms)) | ||
208 | return; | ||
209 | |||
210 | efi_system_table = params.system_table; | ||
211 | |||
212 | memblock_reserve(params.mmap & PAGE_MASK, | ||
213 | PAGE_ALIGN(params.mmap_size + (params.mmap & ~PAGE_MASK))); | ||
214 | memmap.phys_map = params.mmap; | ||
215 | memmap.map = early_memremap(params.mmap, params.mmap_size); | ||
216 | if (memmap.map == NULL) { | ||
217 | /* | ||
218 | * If we are booting via UEFI, the UEFI memory map is the only | ||
219 | * description of memory we have, so there is little point in | ||
220 | * proceeding if we cannot access it. | ||
221 | */ | ||
222 | panic("Unable to map EFI memory map.\n"); | ||
223 | } | ||
224 | memmap.map_end = memmap.map + params.mmap_size; | ||
225 | memmap.desc_size = params.desc_size; | ||
226 | memmap.desc_version = params.desc_ver; | ||
227 | |||
228 | if (uefi_init() < 0) | ||
229 | return; | ||
230 | |||
231 | reserve_regions(); | ||
232 | early_memunmap(memmap.map, params.mmap_size); | ||
233 | } | ||
234 | |||
235 | static bool __init efi_virtmap_init(void) | ||
236 | { | ||
237 | efi_memory_desc_t *md; | ||
238 | |||
239 | init_new_context(NULL, &efi_mm); | ||
240 | |||
241 | for_each_efi_memory_desc(&memmap, md) { | ||
242 | pgprot_t prot; | ||
243 | |||
244 | if (!(md->attribute & EFI_MEMORY_RUNTIME)) | ||
245 | continue; | ||
246 | if (md->virt_addr == 0) | ||
247 | return false; | ||
248 | |||
249 | pr_info(" EFI remap 0x%016llx => %p\n", | ||
250 | md->phys_addr, (void *)md->virt_addr); | ||
251 | |||
252 | /* | ||
253 | * Only regions of type EFI_RUNTIME_SERVICES_CODE need to be | ||
254 | * executable, everything else can be mapped with the XN bits | ||
255 | * set. | ||
256 | */ | ||
257 | if (!is_normal_ram(md)) | ||
258 | prot = __pgprot(PROT_DEVICE_nGnRE); | ||
259 | else if (md->type == EFI_RUNTIME_SERVICES_CODE || | ||
260 | !PAGE_ALIGNED(md->phys_addr)) | ||
261 | prot = PAGE_KERNEL_EXEC; | ||
262 | else | ||
263 | prot = PAGE_KERNEL; | ||
264 | |||
265 | create_pgd_mapping(&efi_mm, md->phys_addr, md->virt_addr, | ||
266 | md->num_pages << EFI_PAGE_SHIFT, | ||
267 | __pgprot(pgprot_val(prot) | PTE_NG)); | ||
268 | } | ||
269 | return true; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Enable the UEFI Runtime Services if all prerequisites are in place, i.e., | ||
274 | * non-early mapping of the UEFI system table and virtual mappings for all | ||
275 | * EFI_MEMORY_RUNTIME regions. | ||
276 | */ | ||
277 | static int __init arm64_enable_runtime_services(void) | ||
278 | { | ||
279 | u64 mapsize; | ||
280 | |||
281 | if (!efi_enabled(EFI_BOOT)) { | ||
282 | pr_info("EFI services will not be available.\n"); | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | if (efi_runtime_disabled()) { | ||
287 | pr_info("EFI runtime services will be disabled.\n"); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | pr_info("Remapping and enabling EFI services.\n"); | ||
292 | |||
293 | mapsize = memmap.map_end - memmap.map; | ||
294 | memmap.map = (__force void *)ioremap_cache(memmap.phys_map, | ||
295 | mapsize); | ||
296 | if (!memmap.map) { | ||
297 | pr_err("Failed to remap EFI memory map\n"); | ||
298 | return -ENOMEM; | ||
299 | } | ||
300 | memmap.map_end = memmap.map + mapsize; | ||
301 | efi.memmap = &memmap; | ||
302 | |||
303 | efi.systab = (__force void *)ioremap_cache(efi_system_table, | ||
304 | sizeof(efi_system_table_t)); | ||
305 | if (!efi.systab) { | ||
306 | pr_err("Failed to remap EFI System Table\n"); | ||
307 | return -ENOMEM; | ||
308 | } | ||
309 | set_bit(EFI_SYSTEM_TABLES, &efi.flags); | ||
310 | |||
311 | if (!efi_virtmap_init()) { | ||
312 | pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); | ||
313 | return -ENOMEM; | ||
314 | } | ||
315 | |||
316 | /* Set up runtime services function pointers */ | ||
317 | efi_native_runtime_setup(); | ||
318 | set_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
319 | |||
320 | efi.runtime_version = efi.systab->hdr.revision; | ||
321 | |||
322 | return 0; | 40 | return 0; |
323 | } | 41 | } |
324 | early_initcall(arm64_enable_runtime_services); | ||
325 | 42 | ||
326 | static int __init arm64_dmi_init(void) | 43 | static int __init arm64_dmi_init(void) |
327 | { | 44 | { |
@@ -337,23 +54,6 @@ static int __init arm64_dmi_init(void) | |||
337 | } | 54 | } |
338 | core_initcall(arm64_dmi_init); | 55 | core_initcall(arm64_dmi_init); |
339 | 56 | ||
340 | static void efi_set_pgd(struct mm_struct *mm) | ||
341 | { | ||
342 | switch_mm(NULL, mm, NULL); | ||
343 | } | ||
344 | |||
345 | void efi_virtmap_load(void) | ||
346 | { | ||
347 | preempt_disable(); | ||
348 | efi_set_pgd(&efi_mm); | ||
349 | } | ||
350 | |||
351 | void efi_virtmap_unload(void) | ||
352 | { | ||
353 | efi_set_pgd(current->active_mm); | ||
354 | preempt_enable(); | ||
355 | } | ||
356 | |||
357 | /* | 57 | /* |
358 | * UpdateCapsule() depends on the system being shutdown via | 58 | * UpdateCapsule() depends on the system being shutdown via |
359 | * ResetSystem(). | 59 | * ResetSystem(). |
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 17bf39ac83ba..ac4d7cbbdd2d 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c | |||
@@ -120,7 +120,7 @@ static void __init zone_sizes_init(unsigned long min, unsigned long max) | |||
120 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID | 120 | #ifdef CONFIG_HAVE_ARCH_PFN_VALID |
121 | int pfn_valid(unsigned long pfn) | 121 | int pfn_valid(unsigned long pfn) |
122 | { | 122 | { |
123 | return memblock_is_memory(pfn << PAGE_SHIFT); | 123 | return memblock_is_map_memory(pfn << PAGE_SHIFT); |
124 | } | 124 | } |
125 | EXPORT_SYMBOL(pfn_valid); | 125 | EXPORT_SYMBOL(pfn_valid); |
126 | #endif | 126 | #endif |
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 873e363048c6..f336a775c353 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c | |||
@@ -372,6 +372,8 @@ static void __init map_mem(void) | |||
372 | 372 | ||
373 | if (start >= end) | 373 | if (start >= end) |
374 | break; | 374 | break; |
375 | if (memblock_is_nomap(reg)) | ||
376 | continue; | ||
375 | 377 | ||
376 | if (ARM64_SWAPPER_USES_SECTION_MAPS) { | 378 | if (ARM64_SWAPPER_USES_SECTION_MAPS) { |
377 | /* | 379 | /* |
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index ec379a4164cc..62e654f255f4 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile | |||
@@ -18,3 +18,7 @@ obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o | |||
18 | obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o | 18 | obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o |
19 | obj-$(CONFIG_EFI_STUB) += libstub/ | 19 | obj-$(CONFIG_EFI_STUB) += libstub/ |
20 | obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o | 20 | obj-$(CONFIG_EFI_FAKE_MEMMAP) += fake_mem.o |
21 | |||
22 | arm-obj-$(CONFIG_EFI) := arm-init.o arm-runtime.o | ||
23 | obj-$(CONFIG_ARM) += $(arm-obj-y) | ||
24 | obj-$(CONFIG_ARM64) += $(arm-obj-y) | ||
diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c new file mode 100644 index 000000000000..9e15d571b53c --- /dev/null +++ b/drivers/firmware/efi/arm-init.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * Extensible Firmware Interface | ||
3 | * | ||
4 | * Based on Extensible Firmware Interface Specification version 2.4 | ||
5 | * | ||
6 | * Copyright (C) 2013 - 2015 Linaro Ltd. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/efi.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/memblock.h> | ||
17 | #include <linux/mm_types.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/of_fdt.h> | ||
20 | |||
21 | #include <asm/efi.h> | ||
22 | |||
23 | struct efi_memory_map memmap; | ||
24 | |||
25 | u64 efi_system_table; | ||
26 | |||
27 | static int __init is_normal_ram(efi_memory_desc_t *md) | ||
28 | { | ||
29 | if (md->attribute & EFI_MEMORY_WB) | ||
30 | return 1; | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | /* | ||
35 | * Translate a EFI virtual address into a physical address: this is necessary, | ||
36 | * as some data members of the EFI system table are virtually remapped after | ||
37 | * SetVirtualAddressMap() has been called. | ||
38 | */ | ||
39 | static phys_addr_t efi_to_phys(unsigned long addr) | ||
40 | { | ||
41 | efi_memory_desc_t *md; | ||
42 | |||
43 | for_each_efi_memory_desc(&memmap, md) { | ||
44 | if (!(md->attribute & EFI_MEMORY_RUNTIME)) | ||
45 | continue; | ||
46 | if (md->virt_addr == 0) | ||
47 | /* no virtual mapping has been installed by the stub */ | ||
48 | break; | ||
49 | if (md->virt_addr <= addr && | ||
50 | (addr - md->virt_addr) < (md->num_pages << EFI_PAGE_SHIFT)) | ||
51 | return md->phys_addr + addr - md->virt_addr; | ||
52 | } | ||
53 | return addr; | ||
54 | } | ||
55 | |||
56 | static int __init uefi_init(void) | ||
57 | { | ||
58 | efi_char16_t *c16; | ||
59 | void *config_tables; | ||
60 | size_t table_size; | ||
61 | char vendor[100] = "unknown"; | ||
62 | int i, retval; | ||
63 | |||
64 | efi.systab = early_memremap(efi_system_table, | ||
65 | sizeof(efi_system_table_t)); | ||
66 | if (efi.systab == NULL) { | ||
67 | pr_warn("Unable to map EFI system table.\n"); | ||
68 | return -ENOMEM; | ||
69 | } | ||
70 | |||
71 | set_bit(EFI_BOOT, &efi.flags); | ||
72 | if (IS_ENABLED(CONFIG_64BIT)) | ||
73 | set_bit(EFI_64BIT, &efi.flags); | ||
74 | |||
75 | /* | ||
76 | * Verify the EFI Table | ||
77 | */ | ||
78 | if (efi.systab->hdr.signature != EFI_SYSTEM_TABLE_SIGNATURE) { | ||
79 | pr_err("System table signature incorrect\n"); | ||
80 | retval = -EINVAL; | ||
81 | goto out; | ||
82 | } | ||
83 | if ((efi.systab->hdr.revision >> 16) < 2) | ||
84 | pr_warn("Warning: EFI system table version %d.%02d, expected 2.00 or greater\n", | ||
85 | efi.systab->hdr.revision >> 16, | ||
86 | efi.systab->hdr.revision & 0xffff); | ||
87 | |||
88 | /* Show what we know for posterity */ | ||
89 | c16 = early_memremap(efi_to_phys(efi.systab->fw_vendor), | ||
90 | sizeof(vendor) * sizeof(efi_char16_t)); | ||
91 | if (c16) { | ||
92 | for (i = 0; i < (int) sizeof(vendor) - 1 && *c16; ++i) | ||
93 | vendor[i] = c16[i]; | ||
94 | vendor[i] = '\0'; | ||
95 | early_memunmap(c16, sizeof(vendor) * sizeof(efi_char16_t)); | ||
96 | } | ||
97 | |||
98 | pr_info("EFI v%u.%.02u by %s\n", | ||
99 | efi.systab->hdr.revision >> 16, | ||
100 | efi.systab->hdr.revision & 0xffff, vendor); | ||
101 | |||
102 | table_size = sizeof(efi_config_table_64_t) * efi.systab->nr_tables; | ||
103 | config_tables = early_memremap(efi_to_phys(efi.systab->tables), | ||
104 | table_size); | ||
105 | if (config_tables == NULL) { | ||
106 | pr_warn("Unable to map EFI config table array.\n"); | ||
107 | retval = -ENOMEM; | ||
108 | goto out; | ||
109 | } | ||
110 | retval = efi_config_parse_tables(config_tables, efi.systab->nr_tables, | ||
111 | sizeof(efi_config_table_t), NULL); | ||
112 | |||
113 | early_memunmap(config_tables, table_size); | ||
114 | out: | ||
115 | early_memunmap(efi.systab, sizeof(efi_system_table_t)); | ||
116 | return retval; | ||
117 | } | ||
118 | |||
119 | /* | ||
120 | * Return true for RAM regions we want to permanently reserve. | ||
121 | */ | ||
122 | static __init int is_reserve_region(efi_memory_desc_t *md) | ||
123 | { | ||
124 | switch (md->type) { | ||
125 | case EFI_LOADER_CODE: | ||
126 | case EFI_LOADER_DATA: | ||
127 | case EFI_BOOT_SERVICES_CODE: | ||
128 | case EFI_BOOT_SERVICES_DATA: | ||
129 | case EFI_CONVENTIONAL_MEMORY: | ||
130 | case EFI_PERSISTENT_MEMORY: | ||
131 | return 0; | ||
132 | default: | ||
133 | break; | ||
134 | } | ||
135 | return is_normal_ram(md); | ||
136 | } | ||
137 | |||
138 | static __init void reserve_regions(void) | ||
139 | { | ||
140 | efi_memory_desc_t *md; | ||
141 | u64 paddr, npages, size; | ||
142 | |||
143 | if (efi_enabled(EFI_DBG)) | ||
144 | pr_info("Processing EFI memory map:\n"); | ||
145 | |||
146 | for_each_efi_memory_desc(&memmap, md) { | ||
147 | paddr = md->phys_addr; | ||
148 | npages = md->num_pages; | ||
149 | |||
150 | if (efi_enabled(EFI_DBG)) { | ||
151 | char buf[64]; | ||
152 | |||
153 | pr_info(" 0x%012llx-0x%012llx %s", | ||
154 | paddr, paddr + (npages << EFI_PAGE_SHIFT) - 1, | ||
155 | efi_md_typeattr_format(buf, sizeof(buf), md)); | ||
156 | } | ||
157 | |||
158 | memrange_efi_to_native(&paddr, &npages); | ||
159 | size = npages << PAGE_SHIFT; | ||
160 | |||
161 | if (is_normal_ram(md)) | ||
162 | early_init_dt_add_memory_arch(paddr, size); | ||
163 | |||
164 | if (is_reserve_region(md)) { | ||
165 | memblock_mark_nomap(paddr, size); | ||
166 | if (efi_enabled(EFI_DBG)) | ||
167 | pr_cont("*"); | ||
168 | } | ||
169 | |||
170 | if (efi_enabled(EFI_DBG)) | ||
171 | pr_cont("\n"); | ||
172 | } | ||
173 | |||
174 | set_bit(EFI_MEMMAP, &efi.flags); | ||
175 | } | ||
176 | |||
177 | void __init efi_init(void) | ||
178 | { | ||
179 | struct efi_fdt_params params; | ||
180 | |||
181 | /* Grab UEFI information placed in FDT by stub */ | ||
182 | if (!efi_get_fdt_params(¶ms)) | ||
183 | return; | ||
184 | |||
185 | efi_system_table = params.system_table; | ||
186 | |||
187 | memmap.phys_map = params.mmap; | ||
188 | memmap.map = early_memremap(params.mmap, params.mmap_size); | ||
189 | if (memmap.map == NULL) { | ||
190 | /* | ||
191 | * If we are booting via UEFI, the UEFI memory map is the only | ||
192 | * description of memory we have, so there is little point in | ||
193 | * proceeding if we cannot access it. | ||
194 | */ | ||
195 | panic("Unable to map EFI memory map.\n"); | ||
196 | } | ||
197 | memmap.map_end = memmap.map + params.mmap_size; | ||
198 | memmap.desc_size = params.desc_size; | ||
199 | memmap.desc_version = params.desc_ver; | ||
200 | |||
201 | if (uefi_init() < 0) | ||
202 | return; | ||
203 | |||
204 | reserve_regions(); | ||
205 | early_memunmap(memmap.map, params.mmap_size); | ||
206 | memblock_mark_nomap(params.mmap & PAGE_MASK, | ||
207 | PAGE_ALIGN(params.mmap_size + | ||
208 | (params.mmap & ~PAGE_MASK))); | ||
209 | } | ||
diff --git a/drivers/firmware/efi/arm-runtime.c b/drivers/firmware/efi/arm-runtime.c new file mode 100644 index 000000000000..6ae21e41a429 --- /dev/null +++ b/drivers/firmware/efi/arm-runtime.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * Extensible Firmware Interface | ||
3 | * | ||
4 | * Based on Extensible Firmware Interface Specification version 2.4 | ||
5 | * | ||
6 | * Copyright (C) 2013, 2014 Linaro Ltd. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/efi.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/memblock.h> | ||
17 | #include <linux/mm_types.h> | ||
18 | #include <linux/preempt.h> | ||
19 | #include <linux/rbtree.h> | ||
20 | #include <linux/rwsem.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | |||
25 | #include <asm/cacheflush.h> | ||
26 | #include <asm/efi.h> | ||
27 | #include <asm/mmu.h> | ||
28 | #include <asm/pgalloc.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | |||
31 | extern u64 efi_system_table; | ||
32 | |||
33 | static struct mm_struct efi_mm = { | ||
34 | .mm_rb = RB_ROOT, | ||
35 | .mm_users = ATOMIC_INIT(2), | ||
36 | .mm_count = ATOMIC_INIT(1), | ||
37 | .mmap_sem = __RWSEM_INITIALIZER(efi_mm.mmap_sem), | ||
38 | .page_table_lock = __SPIN_LOCK_UNLOCKED(efi_mm.page_table_lock), | ||
39 | .mmlist = LIST_HEAD_INIT(efi_mm.mmlist), | ||
40 | }; | ||
41 | |||
42 | static bool __init efi_virtmap_init(void) | ||
43 | { | ||
44 | efi_memory_desc_t *md; | ||
45 | |||
46 | efi_mm.pgd = pgd_alloc(&efi_mm); | ||
47 | init_new_context(NULL, &efi_mm); | ||
48 | |||
49 | for_each_efi_memory_desc(&memmap, md) { | ||
50 | phys_addr_t phys = md->phys_addr; | ||
51 | int ret; | ||
52 | |||
53 | if (!(md->attribute & EFI_MEMORY_RUNTIME)) | ||
54 | continue; | ||
55 | if (md->virt_addr == 0) | ||
56 | return false; | ||
57 | |||
58 | ret = efi_create_mapping(&efi_mm, md); | ||
59 | if (!ret) { | ||
60 | pr_info(" EFI remap %pa => %p\n", | ||
61 | &phys, (void *)(unsigned long)md->virt_addr); | ||
62 | } else { | ||
63 | pr_warn(" EFI remap %pa: failed to create mapping (%d)\n", | ||
64 | &phys, ret); | ||
65 | return false; | ||
66 | } | ||
67 | } | ||
68 | return true; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Enable the UEFI Runtime Services if all prerequisites are in place, i.e., | ||
73 | * non-early mapping of the UEFI system table and virtual mappings for all | ||
74 | * EFI_MEMORY_RUNTIME regions. | ||
75 | */ | ||
76 | static int __init arm_enable_runtime_services(void) | ||
77 | { | ||
78 | u64 mapsize; | ||
79 | |||
80 | if (!efi_enabled(EFI_BOOT)) { | ||
81 | pr_info("EFI services will not be available.\n"); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | if (efi_runtime_disabled()) { | ||
86 | pr_info("EFI runtime services will be disabled.\n"); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | pr_info("Remapping and enabling EFI services.\n"); | ||
91 | |||
92 | mapsize = memmap.map_end - memmap.map; | ||
93 | memmap.map = (__force void *)ioremap_cache(memmap.phys_map, | ||
94 | mapsize); | ||
95 | if (!memmap.map) { | ||
96 | pr_err("Failed to remap EFI memory map\n"); | ||
97 | return -ENOMEM; | ||
98 | } | ||
99 | memmap.map_end = memmap.map + mapsize; | ||
100 | efi.memmap = &memmap; | ||
101 | |||
102 | efi.systab = (__force void *)ioremap_cache(efi_system_table, | ||
103 | sizeof(efi_system_table_t)); | ||
104 | if (!efi.systab) { | ||
105 | pr_err("Failed to remap EFI System Table\n"); | ||
106 | return -ENOMEM; | ||
107 | } | ||
108 | set_bit(EFI_SYSTEM_TABLES, &efi.flags); | ||
109 | |||
110 | if (!efi_virtmap_init()) { | ||
111 | pr_err("No UEFI virtual mapping was installed -- runtime services will not be available\n"); | ||
112 | return -ENOMEM; | ||
113 | } | ||
114 | |||
115 | /* Set up runtime services function pointers */ | ||
116 | efi_native_runtime_setup(); | ||
117 | set_bit(EFI_RUNTIME_SERVICES, &efi.flags); | ||
118 | |||
119 | efi.runtime_version = efi.systab->hdr.revision; | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | early_initcall(arm_enable_runtime_services); | ||
124 | |||
125 | void efi_virtmap_load(void) | ||
126 | { | ||
127 | preempt_disable(); | ||
128 | efi_set_pgd(&efi_mm); | ||
129 | } | ||
130 | |||
131 | void efi_virtmap_unload(void) | ||
132 | { | ||
133 | efi_set_pgd(current->active_mm); | ||
134 | preempt_enable(); | ||
135 | } | ||
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 027ca212179f..cffa89b3317b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <linux/io.h> | 25 | #include <linux/io.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | 27 | ||
28 | #include <asm/efi.h> | ||
29 | |||
28 | struct efi __read_mostly efi = { | 30 | struct efi __read_mostly efi = { |
29 | .mps = EFI_INVALID_TABLE_ADDR, | 31 | .mps = EFI_INVALID_TABLE_ADDR, |
30 | .acpi = EFI_INVALID_TABLE_ADDR, | 32 | .acpi = EFI_INVALID_TABLE_ADDR, |
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 3c0467d3688c..8cf9ccbf42d5 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile | |||
@@ -34,6 +34,7 @@ $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE | |||
34 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ | 34 | lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o string.o \ |
35 | $(patsubst %.c,lib-%.o,$(arm-deps)) | 35 | $(patsubst %.c,lib-%.o,$(arm-deps)) |
36 | 36 | ||
37 | lib-$(CONFIG_ARM) += arm32-stub.o | ||
37 | lib-$(CONFIG_ARM64) += arm64-stub.o | 38 | lib-$(CONFIG_ARM64) += arm64-stub.o |
38 | CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 39 | CFLAGS_arm64-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
39 | 40 | ||
@@ -67,3 +68,11 @@ quiet_cmd_stubcopy = STUBCPY $@ | |||
67 | $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \ | 68 | $(OBJDUMP) -r $@ | grep $(STUBCOPY_RELOC-y) \ |
68 | && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ | 69 | && (echo >&2 "$@: absolute symbol references not allowed in the EFI stub"; \ |
69 | rm -f $@; /bin/false); else /bin/false; fi | 70 | rm -f $@; /bin/false); else /bin/false; fi |
71 | |||
72 | # | ||
73 | # ARM discards the .data section because it disallows r/w data in the | ||
74 | # decompressor. So move our .data to .data.efistub, which is preserved | ||
75 | # explicitly by the decompressor linker script. | ||
76 | # | ||
77 | STUBCOPY_FLAGS-$(CONFIG_ARM) += --rename-section .data=.data.efistub | ||
78 | STUBCOPY_RELOC-$(CONFIG_ARM) := R_ARM_ABS | ||
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c index 950c87f5d279..3397902e4040 100644 --- a/drivers/firmware/efi/libstub/arm-stub.c +++ b/drivers/firmware/efi/libstub/arm-stub.c | |||
@@ -303,8 +303,10 @@ fail: | |||
303 | * The value chosen is the largest non-zero power of 2 suitable for this purpose | 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 | 304 | * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can |
305 | * be mapped efficiently. | 305 | * be mapped efficiently. |
306 | * Since 32-bit ARM could potentially execute with a 1G/3G user/kernel split, | ||
307 | * map everything below 1 GB. | ||
306 | */ | 308 | */ |
307 | #define EFI_RT_VIRTUAL_BASE 0x40000000 | 309 | #define EFI_RT_VIRTUAL_BASE SZ_512M |
308 | 310 | ||
309 | static int cmp_mem_desc(const void *l, const void *r) | 311 | static int cmp_mem_desc(const void *l, const void *r) |
310 | { | 312 | { |
diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c new file mode 100644 index 000000000000..495ebd657e38 --- /dev/null +++ b/drivers/firmware/efi/libstub/arm32-stub.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2013 Linaro Ltd; <roy.franz@linaro.org> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | */ | ||
9 | #include <linux/efi.h> | ||
10 | #include <asm/efi.h> | ||
11 | |||
12 | efi_status_t handle_kernel_image(efi_system_table_t *sys_table, | ||
13 | unsigned long *image_addr, | ||
14 | unsigned long *image_size, | ||
15 | unsigned long *reserve_addr, | ||
16 | unsigned long *reserve_size, | ||
17 | unsigned long dram_base, | ||
18 | efi_loaded_image_t *image) | ||
19 | { | ||
20 | unsigned long nr_pages; | ||
21 | efi_status_t status; | ||
22 | /* Use alloc_addr to tranlsate between types */ | ||
23 | efi_physical_addr_t alloc_addr; | ||
24 | |||
25 | /* | ||
26 | * Verify that the DRAM base address is compatible with the ARM | ||
27 | * boot protocol, which determines the base of DRAM by masking | ||
28 | * off the low 27 bits of the address at which the zImage is | ||
29 | * loaded. These assumptions are made by the decompressor, | ||
30 | * before any memory map is available. | ||
31 | */ | ||
32 | dram_base = round_up(dram_base, SZ_128M); | ||
33 | |||
34 | /* | ||
35 | * Reserve memory for the uncompressed kernel image. This is | ||
36 | * all that prevents any future allocations from conflicting | ||
37 | * with the kernel. Since we can't tell from the compressed | ||
38 | * image how much DRAM the kernel actually uses (due to BSS | ||
39 | * size uncertainty) we allocate the maximum possible size. | ||
40 | * Do this very early, as prints can cause memory allocations | ||
41 | * that may conflict with this. | ||
42 | */ | ||
43 | alloc_addr = dram_base; | ||
44 | *reserve_size = MAX_UNCOMP_KERNEL_SIZE; | ||
45 | nr_pages = round_up(*reserve_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE; | ||
46 | status = sys_table->boottime->allocate_pages(EFI_ALLOCATE_ADDRESS, | ||
47 | EFI_LOADER_DATA, | ||
48 | nr_pages, &alloc_addr); | ||
49 | if (status != EFI_SUCCESS) { | ||
50 | *reserve_size = 0; | ||
51 | pr_efi_err(sys_table, "Unable to allocate memory for uncompressed kernel.\n"); | ||
52 | return status; | ||
53 | } | ||
54 | *reserve_addr = alloc_addr; | ||
55 | |||
56 | /* | ||
57 | * Relocate the zImage, so that it appears in the lowest 128 MB | ||
58 | * memory window. | ||
59 | */ | ||
60 | *image_size = image->image_size; | ||
61 | status = efi_relocate_kernel(sys_table, image_addr, *image_size, | ||
62 | *image_size, | ||
63 | dram_base + MAX_UNCOMP_KERNEL_SIZE, 0); | ||
64 | if (status != EFI_SUCCESS) { | ||
65 | pr_efi_err(sys_table, "Failed to relocate kernel.\n"); | ||
66 | efi_free(sys_table, *reserve_size, *reserve_addr); | ||
67 | *reserve_size = 0; | ||
68 | return status; | ||
69 | } | ||
70 | |||
71 | /* | ||
72 | * Check to see if we were able to allocate memory low enough | ||
73 | * in memory. The kernel determines the base of DRAM from the | ||
74 | * address at which the zImage is loaded. | ||
75 | */ | ||
76 | if (*image_addr + *image_size > dram_base + ZIMAGE_OFFSET_LIMIT) { | ||
77 | pr_efi_err(sys_table, "Failed to relocate kernel, no low memory available.\n"); | ||
78 | efi_free(sys_table, *reserve_size, *reserve_addr); | ||
79 | *reserve_size = 0; | ||
80 | efi_free(sys_table, *image_size, *image_addr); | ||
81 | *image_size = 0; | ||
82 | return EFI_LOAD_ERROR; | ||
83 | } | ||
84 | return EFI_SUCCESS; | ||
85 | } | ||
diff --git a/include/linux/memblock.h b/include/linux/memblock.h index 24daf8fc4d7c..fec66f86eeff 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h | |||
@@ -25,6 +25,7 @@ enum { | |||
25 | MEMBLOCK_NONE = 0x0, /* No special request */ | 25 | MEMBLOCK_NONE = 0x0, /* No special request */ |
26 | MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ | 26 | MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ |
27 | MEMBLOCK_MIRROR = 0x2, /* mirrored region */ | 27 | MEMBLOCK_MIRROR = 0x2, /* mirrored region */ |
28 | MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */ | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct memblock_region { | 31 | struct memblock_region { |
@@ -82,6 +83,7 @@ bool memblock_overlaps_region(struct memblock_type *type, | |||
82 | int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); | 83 | int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); |
83 | int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); | 84 | int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); |
84 | int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); | 85 | int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); |
86 | int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); | ||
85 | ulong choose_memblock_flags(void); | 87 | ulong choose_memblock_flags(void); |
86 | 88 | ||
87 | /* Low level functions */ | 89 | /* Low level functions */ |
@@ -184,6 +186,11 @@ static inline bool memblock_is_mirror(struct memblock_region *m) | |||
184 | return m->flags & MEMBLOCK_MIRROR; | 186 | return m->flags & MEMBLOCK_MIRROR; |
185 | } | 187 | } |
186 | 188 | ||
189 | static inline bool memblock_is_nomap(struct memblock_region *m) | ||
190 | { | ||
191 | return m->flags & MEMBLOCK_NOMAP; | ||
192 | } | ||
193 | |||
187 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | 194 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP |
188 | int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, | 195 | int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, |
189 | unsigned long *end_pfn); | 196 | unsigned long *end_pfn); |
@@ -319,6 +326,7 @@ phys_addr_t memblock_start_of_DRAM(void); | |||
319 | phys_addr_t memblock_end_of_DRAM(void); | 326 | phys_addr_t memblock_end_of_DRAM(void); |
320 | void memblock_enforce_memory_limit(phys_addr_t memory_limit); | 327 | void memblock_enforce_memory_limit(phys_addr_t memory_limit); |
321 | int memblock_is_memory(phys_addr_t addr); | 328 | int memblock_is_memory(phys_addr_t addr); |
329 | int memblock_is_map_memory(phys_addr_t addr); | ||
322 | int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); | 330 | int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); |
323 | int memblock_is_reserved(phys_addr_t addr); | 331 | int memblock_is_reserved(phys_addr_t addr); |
324 | bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); | 332 | bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); |
diff --git a/mm/memblock.c b/mm/memblock.c index d300f1329814..07ff069fef25 100644 --- a/mm/memblock.c +++ b/mm/memblock.c | |||
@@ -822,6 +822,17 @@ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) | |||
822 | return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR); | 822 | return memblock_setclr_flag(base, size, 1, MEMBLOCK_MIRROR); |
823 | } | 823 | } |
824 | 824 | ||
825 | /** | ||
826 | * memblock_mark_nomap - Mark a memory region with flag MEMBLOCK_NOMAP. | ||
827 | * @base: the base phys addr of the region | ||
828 | * @size: the size of the region | ||
829 | * | ||
830 | * Return 0 on success, -errno on failure. | ||
831 | */ | ||
832 | int __init_memblock memblock_mark_nomap(phys_addr_t base, phys_addr_t size) | ||
833 | { | ||
834 | return memblock_setclr_flag(base, size, 1, MEMBLOCK_NOMAP); | ||
835 | } | ||
825 | 836 | ||
826 | /** | 837 | /** |
827 | * __next_reserved_mem_region - next function for for_each_reserved_region() | 838 | * __next_reserved_mem_region - next function for for_each_reserved_region() |
@@ -913,6 +924,10 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, | |||
913 | if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) | 924 | if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) |
914 | continue; | 925 | continue; |
915 | 926 | ||
927 | /* skip nomap memory unless we were asked for it explicitly */ | ||
928 | if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m)) | ||
929 | continue; | ||
930 | |||
916 | if (!type_b) { | 931 | if (!type_b) { |
917 | if (out_start) | 932 | if (out_start) |
918 | *out_start = m_start; | 933 | *out_start = m_start; |
@@ -1022,6 +1037,10 @@ void __init_memblock __next_mem_range_rev(u64 *idx, int nid, ulong flags, | |||
1022 | if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) | 1037 | if ((flags & MEMBLOCK_MIRROR) && !memblock_is_mirror(m)) |
1023 | continue; | 1038 | continue; |
1024 | 1039 | ||
1040 | /* skip nomap memory unless we were asked for it explicitly */ | ||
1041 | if (!(flags & MEMBLOCK_NOMAP) && memblock_is_nomap(m)) | ||
1042 | continue; | ||
1043 | |||
1025 | if (!type_b) { | 1044 | if (!type_b) { |
1026 | if (out_start) | 1045 | if (out_start) |
1027 | *out_start = m_start; | 1046 | *out_start = m_start; |
@@ -1519,6 +1538,15 @@ int __init_memblock memblock_is_memory(phys_addr_t addr) | |||
1519 | return memblock_search(&memblock.memory, addr) != -1; | 1538 | return memblock_search(&memblock.memory, addr) != -1; |
1520 | } | 1539 | } |
1521 | 1540 | ||
1541 | int __init_memblock memblock_is_map_memory(phys_addr_t addr) | ||
1542 | { | ||
1543 | int i = memblock_search(&memblock.memory, addr); | ||
1544 | |||
1545 | if (i == -1) | ||
1546 | return false; | ||
1547 | return !memblock_is_nomap(&memblock.memory.regions[i]); | ||
1548 | } | ||
1549 | |||
1522 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP | 1550 | #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP |
1523 | int __init_memblock memblock_search_pfn_nid(unsigned long pfn, | 1551 | int __init_memblock memblock_search_pfn_nid(unsigned long pfn, |
1524 | unsigned long *start_pfn, unsigned long *end_pfn) | 1552 | unsigned long *start_pfn, unsigned long *end_pfn) |