diff options
-rw-r--r-- | arch/arm/Kconfig | 12 | ||||
-rw-r--r-- | arch/arm/boot/compressed/.gitignore | 9 | ||||
-rw-r--r-- | arch/arm/boot/compressed/Makefile | 21 | ||||
-rw-r--r-- | arch/arm/boot/compressed/atags_to_fdt.c | 97 | ||||
-rw-r--r-- | arch/arm/boot/compressed/head.S | 32 | ||||
-rw-r--r-- | arch/arm/boot/compressed/libfdt_env.h | 15 |
6 files changed, 184 insertions, 2 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c66e0808c2b1..73c320ea172c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1801,6 +1801,18 @@ config ARM_APPENDED_DTB | |||
1801 | location into r2 of a bootloader provided DTB is always preferable | 1801 | location into r2 of a bootloader provided DTB is always preferable |
1802 | to this option. | 1802 | to this option. |
1803 | 1803 | ||
1804 | config ARM_ATAG_DTB_COMPAT | ||
1805 | bool "Supplement the appended DTB with traditional ATAG information" | ||
1806 | depends on ARM_APPENDED_DTB | ||
1807 | help | ||
1808 | Some old bootloaders can't be updated to a DTB capable one, yet | ||
1809 | they provide ATAGs with memory configuration, the ramdisk address, | ||
1810 | the kernel cmdline string, etc. Such information is dynamically | ||
1811 | provided by the bootloader and can't always be stored in a static | ||
1812 | DTB. To allow a device tree enabled kernel to be used with such | ||
1813 | bootloaders, this option allows zImage to extract the information | ||
1814 | from the ATAG list and store it at run time into the appended DTB. | ||
1815 | |||
1804 | config CMDLINE | 1816 | config CMDLINE |
1805 | string "Default kernel command string" | 1817 | string "Default kernel command string" |
1806 | default "" | 1818 | default "" |
diff --git a/arch/arm/boot/compressed/.gitignore b/arch/arm/boot/compressed/.gitignore index c6028967d336..e0936a148516 100644 --- a/arch/arm/boot/compressed/.gitignore +++ b/arch/arm/boot/compressed/.gitignore | |||
@@ -5,3 +5,12 @@ piggy.lzo | |||
5 | piggy.lzma | 5 | piggy.lzma |
6 | vmlinux | 6 | vmlinux |
7 | vmlinux.lds | 7 | vmlinux.lds |
8 | |||
9 | # borrowed libfdt files | ||
10 | fdt.c | ||
11 | fdt.h | ||
12 | fdt_ro.c | ||
13 | fdt_rw.c | ||
14 | fdt_wip.c | ||
15 | libfdt.h | ||
16 | libfdt_internal.h | ||
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index c20ddc69d950..55f86349d547 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile | |||
@@ -93,19 +93,36 @@ suffix_$(CONFIG_KERNEL_GZIP) = gzip | |||
93 | suffix_$(CONFIG_KERNEL_LZO) = lzo | 93 | suffix_$(CONFIG_KERNEL_LZO) = lzo |
94 | suffix_$(CONFIG_KERNEL_LZMA) = lzma | 94 | suffix_$(CONFIG_KERNEL_LZMA) = lzma |
95 | 95 | ||
96 | # Borrowed libfdt files for the ATAG compatibility mode | ||
97 | |||
98 | libfdt := fdt_rw.c fdt_ro.c fdt_wip.c fdt.c | ||
99 | libfdt_hdrs := fdt.h libfdt.h libfdt_internal.h | ||
100 | |||
101 | libfdt_objs := $(addsuffix .o, $(basename $(libfdt))) | ||
102 | |||
103 | $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/% | ||
104 | $(call cmd,shipped) | ||
105 | |||
106 | $(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \ | ||
107 | $(addprefix $(obj)/,$(libfdt_hdrs)) | ||
108 | |||
109 | ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y) | ||
110 | OBJS += $(libfdt_objs) atags_to_fdt.o | ||
111 | endif | ||
112 | |||
96 | targets := vmlinux vmlinux.lds \ | 113 | targets := vmlinux vmlinux.lds \ |
97 | piggy.$(suffix_y) piggy.$(suffix_y).o \ | 114 | piggy.$(suffix_y) piggy.$(suffix_y).o \ |
98 | font.o font.c head.o misc.o $(OBJS) | 115 | font.o font.c head.o misc.o $(OBJS) |
99 | 116 | ||
100 | # Make sure files are removed during clean | 117 | # Make sure files are removed during clean |
101 | extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S | 118 | extra-y += piggy.gzip piggy.lzo piggy.lzma lib1funcs.S $(libfdt) $(libfdt_hdrs) |
102 | 119 | ||
103 | ifeq ($(CONFIG_FUNCTION_TRACER),y) | 120 | ifeq ($(CONFIG_FUNCTION_TRACER),y) |
104 | ORIG_CFLAGS := $(KBUILD_CFLAGS) | 121 | ORIG_CFLAGS := $(KBUILD_CFLAGS) |
105 | KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) | 122 | KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS)) |
106 | endif | 123 | endif |
107 | 124 | ||
108 | ccflags-y := -fpic -fno-builtin | 125 | ccflags-y := -fpic -fno-builtin -I$(obj) |
109 | asflags-y := -Wa,-march=all | 126 | asflags-y := -Wa,-march=all |
110 | 127 | ||
111 | # Supply kernel BSS size to the decompressor via a linker symbol. | 128 | # Supply kernel BSS size to the decompressor via a linker symbol. |
diff --git a/arch/arm/boot/compressed/atags_to_fdt.c b/arch/arm/boot/compressed/atags_to_fdt.c new file mode 100644 index 000000000000..6ce11c481178 --- /dev/null +++ b/arch/arm/boot/compressed/atags_to_fdt.c | |||
@@ -0,0 +1,97 @@ | |||
1 | #include <asm/setup.h> | ||
2 | #include <libfdt.h> | ||
3 | |||
4 | static int node_offset(void *fdt, const char *node_path) | ||
5 | { | ||
6 | int offset = fdt_path_offset(fdt, node_path); | ||
7 | if (offset == -FDT_ERR_NOTFOUND) | ||
8 | offset = fdt_add_subnode(fdt, 0, node_path); | ||
9 | return offset; | ||
10 | } | ||
11 | |||
12 | static int setprop(void *fdt, const char *node_path, const char *property, | ||
13 | uint32_t *val_array, int size) | ||
14 | { | ||
15 | int offset = node_offset(fdt, node_path); | ||
16 | if (offset < 0) | ||
17 | return offset; | ||
18 | return fdt_setprop(fdt, offset, property, val_array, size); | ||
19 | } | ||
20 | |||
21 | static int setprop_string(void *fdt, const char *node_path, | ||
22 | const char *property, const char *string) | ||
23 | { | ||
24 | int offset = node_offset(fdt, node_path); | ||
25 | if (offset < 0) | ||
26 | return offset; | ||
27 | return fdt_setprop_string(fdt, offset, property, string); | ||
28 | } | ||
29 | |||
30 | static int setprop_cell(void *fdt, const char *node_path, | ||
31 | const char *property, uint32_t val) | ||
32 | { | ||
33 | int offset = node_offset(fdt, node_path); | ||
34 | if (offset < 0) | ||
35 | return offset; | ||
36 | return fdt_setprop_cell(fdt, offset, property, val); | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * Convert and fold provided ATAGs into the provided FDT. | ||
41 | * | ||
42 | * REturn values: | ||
43 | * = 0 -> pretend success | ||
44 | * = 1 -> bad ATAG (may retry with another possible ATAG pointer) | ||
45 | * < 0 -> error from libfdt | ||
46 | */ | ||
47 | int atags_to_fdt(void *atag_list, void *fdt, int total_space) | ||
48 | { | ||
49 | struct tag *atag = atag_list; | ||
50 | uint32_t mem_reg_property[2 * NR_BANKS]; | ||
51 | int memcount = 0; | ||
52 | int ret; | ||
53 | |||
54 | /* make sure we've got an aligned pointer */ | ||
55 | if ((u32)atag_list & 0x3) | ||
56 | return 1; | ||
57 | |||
58 | /* if we get a DTB here we're done already */ | ||
59 | if (*(u32 *)atag_list == fdt32_to_cpu(FDT_MAGIC)) | ||
60 | return 0; | ||
61 | |||
62 | /* validate the ATAG */ | ||
63 | if (atag->hdr.tag != ATAG_CORE || | ||
64 | (atag->hdr.size != tag_size(tag_core) && | ||
65 | atag->hdr.size != 2)) | ||
66 | return 1; | ||
67 | |||
68 | /* let's give it all the room it could need */ | ||
69 | ret = fdt_open_into(fdt, fdt, total_space); | ||
70 | if (ret < 0) | ||
71 | return ret; | ||
72 | |||
73 | for_each_tag(atag, atag_list) { | ||
74 | if (atag->hdr.tag == ATAG_CMDLINE) { | ||
75 | setprop_string(fdt, "/chosen", "bootargs", | ||
76 | atag->u.cmdline.cmdline); | ||
77 | } else if (atag->hdr.tag == ATAG_MEM) { | ||
78 | if (memcount >= sizeof(mem_reg_property)/4) | ||
79 | continue; | ||
80 | mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.start); | ||
81 | mem_reg_property[memcount++] = cpu_to_fdt32(atag->u.mem.size); | ||
82 | } else if (atag->hdr.tag == ATAG_INITRD2) { | ||
83 | uint32_t initrd_start, initrd_size; | ||
84 | initrd_start = atag->u.initrd.start; | ||
85 | initrd_size = atag->u.initrd.size; | ||
86 | setprop_cell(fdt, "/chosen", "linux,initrd-start", | ||
87 | initrd_start); | ||
88 | setprop_cell(fdt, "/chosen", "linux,initrd-end", | ||
89 | initrd_start + initrd_size); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (memcount) | ||
94 | setprop(fdt, "/memory", "reg", mem_reg_property, 4*memcount); | ||
95 | |||
96 | return fdt_pack(fdt); | ||
97 | } | ||
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index ba5c552f8c69..9f5ac11ccd8e 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S | |||
@@ -246,6 +246,38 @@ restart: adr r0, LC0 | |||
246 | cmp lr, r1 | 246 | cmp lr, r1 |
247 | bne dtb_check_done @ not found | 247 | bne dtb_check_done @ not found |
248 | 248 | ||
249 | #ifdef CONFIG_ARM_ATAG_DTB_COMPAT | ||
250 | /* | ||
251 | * OK... Let's do some funky business here. | ||
252 | * If we do have a DTB appended to zImage, and we do have | ||
253 | * an ATAG list around, we want the later to be translated | ||
254 | * and folded into the former here. To be on the safe side, | ||
255 | * let's temporarily move the stack away into the malloc | ||
256 | * area. No GOT fixup has occurred yet, but none of the | ||
257 | * code we're about to call uses any global variable. | ||
258 | */ | ||
259 | add sp, sp, #0x10000 | ||
260 | stmfd sp!, {r0-r3, ip, lr} | ||
261 | mov r0, r8 | ||
262 | mov r1, r6 | ||
263 | sub r2, sp, r6 | ||
264 | bl atags_to_fdt | ||
265 | |||
266 | /* | ||
267 | * If returned value is 1, there is no ATAG at the location | ||
268 | * pointed by r8. Try the typical 0x100 offset from start | ||
269 | * of RAM and hope for the best. | ||
270 | */ | ||
271 | cmp r0, #1 | ||
272 | sub r0, r4, #(TEXT_OFFSET - 0x100) | ||
273 | mov r1, r6 | ||
274 | sub r2, sp, r6 | ||
275 | blne atags_to_fdt | ||
276 | |||
277 | ldmfd sp!, {r0-r3, ip, lr} | ||
278 | sub sp, sp, #0x10000 | ||
279 | #endif | ||
280 | |||
249 | mov r8, r6 @ use the appended device tree | 281 | mov r8, r6 @ use the appended device tree |
250 | 282 | ||
251 | /* | 283 | /* |
diff --git a/arch/arm/boot/compressed/libfdt_env.h b/arch/arm/boot/compressed/libfdt_env.h new file mode 100644 index 000000000000..1f4e71876b00 --- /dev/null +++ b/arch/arm/boot/compressed/libfdt_env.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef _ARM_LIBFDT_ENV_H | ||
2 | #define _ARM_LIBFDT_ENV_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | #include <linux/string.h> | ||
6 | #include <asm/byteorder.h> | ||
7 | |||
8 | #define fdt16_to_cpu(x) be16_to_cpu(x) | ||
9 | #define cpu_to_fdt16(x) cpu_to_be16(x) | ||
10 | #define fdt32_to_cpu(x) be32_to_cpu(x) | ||
11 | #define cpu_to_fdt32(x) cpu_to_be32(x) | ||
12 | #define fdt64_to_cpu(x) be64_to_cpu(x) | ||
13 | #define cpu_to_fdt64(x) cpu_to_be64(x) | ||
14 | |||
15 | #endif | ||