ARM big-endian - atags and loader updates
Add a series of patches to update the system to support little-endian boot loaders with big-endian kernels. Mostly fixes for ATAGS parsing and loader magic values.
PATCH 1/6 ARM: add CPU_BE8_BOOT_LE configuration
Add configuration for booting a BE8 system from a LE boot environment.
--- arch/arm/mm/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+)
arch/arm/mm/Kconfig +7 -0
@@ -688,6 +688,13 @@ config CPU_ENDIAN_BE8 help Support for the BE-8 (big-endian) mode on ARMv6 and ARMv7 processors. +config CPU_BE8_BOOT_LE + bool "Boot BE system from LE loader" + depends on CPU_ENDIAN_BE8 + help + Support for running BE-8 (big-endian) from a boot environment that is + running in LE mode. + config CPU_ENDIAN_BE32 bool depends on CPU_BIG_ENDIAN
Signature · 1 line
1.7.10.4
PATCH 1/6 ARM: add CPU_BE8_BOOT_LE configuration
Dear Ben Dooks,
arch/arm/mm/Kconfig config CPU_ENDIAN_BE8 · line 697
Quoted 7 lines · Ben Dooks
arch/arm/mm/Kconfig +7
-0+config CPU_BE8_BOOT_LE + bool "Boot BE system from LE loader" + depends on CPU_ENDIAN_BE8 + help + Support for running BE-8 (big-endian) from a boot environment that is + running in LE mode. +
I'm not sure to understand how this option articulates with the CPU_ENDIAN_BE8 option, because your other patch series ("Initial big-endian support series") in its PATCH 4 ("ARM: set BE8 if LE in head code") already switches the kernel into BE mode even if it's booted from a Little Endian bootloader.
Maybe what you wanted to achieve is:
* The first patch series "Initial big-endian support series" allows to run the kernel big-endian if the bootloader has booted it big-endian.
* The second patch series "ARM big-endian - atags and loader updates", allows to run the kernel big-endian even if the bootloader started it little-endian.
In this case, then the PATCH 4 of your first patch series ("ARM: set BE8 if LE in head code") should be in the second patch series, and the code be conditional under CPU_BE8_BOOT_LE.
Or maybe I'm missing something?
Best regards,
Thomas
Signature · 4 lines
Thomas Petazzoni, Free Electrons Kernel, drivers, real-time and embedded Linux development, consulting, training and support. http://free-electrons.com
PATCH 1/6 ARM: add CPU_BE8_BOOT_LE configuration
Quoted 23 lines · Thomas Petazzoni
Dear Ben Dooks,
arch/arm/mm/Kconfig config CPU_ENDIAN_BE8 · line 697
Quoted 7 lines · Ben Dooks
arch/arm/mm/Kconfig +7
-0+config CPU_BE8_BOOT_LE + bool "Boot BE system from LE loader" + depends on CPU_ENDIAN_BE8 + help + Support for running BE-8 (big-endian) from a boot environment that is + running in LE mode. +I'm not sure to understand how this option articulates with the
CPU_ENDIAN_BE8option, because your other patch series ("Initial big-endian support series") in its PATCH 4 ("ARM: set BE8 if LE in head code") already switches the kernel into BE mode even if it's booted from a Little Endian bootloader.Maybe what you wanted to achieve is:
* The first patch series "Initial big-endian support series" allows to run the kernel big-endian if the bootloader has booted it big-endian.
Quoted 7 lines
* The second patch series "ARM big-endian - atags and loader updates", allows to run the kernel big-endian even if the bootloader started it little-endian.
In this case, then the PATCH 4 of your first patch series ("ARM: set BE8 if LE in head code") should be in the second patch series, and the code be conditional under
CPU_BE8_BOOT_LE.
I suppose the second series should be to allow little endian ATAGS based loaders to boot the kernel. If the loader starts the kernel LE with OF then it is easy to swap to big endian in the head code.
The secondary boots will always require the LE->BE switching as there is no guarantee that if the primary processor started the kernel BE8 that any of the secondary cpus will be started in the same way.
Signature · 2 lines
Ben Dooks http://www.codethink.co.uk/ Senior Engineer Codethink - Providing Genius
PATCH 2/6 ARM: fixup head for atag verification
In reply to Ben DooksIf we booted LE but running BE8, ensure we read ATAGs data from head code in the correct mode.
--- arch/arm/kernel/head-common.S | 8 ++++++++ 1 file changed, 8 insertions(+)
arch/arm/kernel/head-common.S +8 -0
@@ -21,6 +21,12 @@ #define OF_DT_MAGIC 0xedfe0dd0 /* 0xd00dfeed in big-endian */ #endif +#ifdef CONFIG_CPU_BE8_BOOT_LE +#define BE8_LE(x...) x +#else +#define BE8_LE(x...) +#endif + /* * Exception handling. Something went wrong and we can't proceed. We * ought to tell the user, but since we don't have any guarantee that
@@ -53,10 +59,12 @@ __vet_atags: cmp r5, r6 beq 2f #endif +BE8_LE( rev r5, r5 ) cmp r5, #ATAG_CORE_SIZE @ is first tag ATAG_CORE? cmpne r5, #ATAG_CORE_SIZE_EMPTY bne 1f ldr r5, [r2, #4] +BE8_LE( rev r5, r5 ) ldr r6, =ATAG_CORE cmp r5, r6 bne 1f
Signature · 1 line
1.7.10.4
PATCH 3/6 ARM: add atag32_to_cpu() function
In reply to Ben DooksAdd atag32_to_cpu() function to allow code manipulating ATAGs to deal with the case where the boot-loader was in little-endian and Linux is running big-endian.
--- arch/arm/include/uapi/asm/setup.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/arm/include/uapi/asm/setup.h +9 -2
@@ -175,13 +175,20 @@ struct tagtable {#define tag_member_present (tag,member) \ ((unsigned long)(&((struct tag *)0L)->member + 1) \ - <= (tag)->hdr.size * 4) + <= atag32_to_cpu((tag)->hdr.size) * 4) -#define tag_next (t) ((struct tag *)((__u32 *)(t) + (t)->hdr.size)) +#define tag_next (t) ((struct tag *)((__u32 *)(t) + atag32_to_cpu((t)->hdr.size)))#define tag_size (type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)#define for_each_tag (t,base) \ for (t = base; t->hdr.size; t = tag_next(t)) +#ifdef CONFIG_CPU_BE8_BOOT_LE +#define atag32_to_cpu (x) le32_to_cpu(x) +#define cpu_to_atag32 (x) cpu_to_le32(x) +#else +#define cpu_to_atag32 (x) x +#define atag32_to_cpu (x) x +#endif #endif /* _UAPI__ASMARM_SETUP_H */
Signature · 1 line
1.7.10.4
PATCH 4/6 ARM: update atag-to-fdt code to be endian agnostic
In reply to Ben DooksThe atag-to-fdt code can now use the conversion function we introduced previously to avoid it having to know about the endian-ness of the environment which booted the processor.
--- arch/arm/boot/compressed/atags_to_fdt.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
arch/arm/boot/compressed/atags_to_fdt.c +11 -11
@@ -108,9 +108,9 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)return 0 ;/* validate the ATAG */ -if (atag->hdr.tag !=ATAG_CORE || - (atag->hdr.size !=tag_size (tag_core) && - atag->hdr.size !=2 )) +if (atag->hdr.tag !=cpu_to_atag32 (ATAG_CORE ) || + (atag->hdr.size !=cpu_to_atag32 (tag_size (tag_core)) && + atag->hdr.size !=cpu_to_atag32 (2 )))return 1 ;/* let's give it all the room it could need */
@@ -119,7 +119,7 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)return ret;for_each_tag (atag, atag_list) { -if (atag->hdr.tag ==ATAG_CMDLINE ) { +if (atag->hdr.tag ==cpu_to_atag32 (ATAG_CMDLINE )) {/* Append the ATAGS command line to the device tree * command line. * NB: This means that if the same parameter is set in
@@ -132,17 +132,17 @@ int atags_to_fdt(void *atag_list, void *fdt, int total_space)else setprop_string (fdt,"/chosen" ,"bootargs" , atag->u.cmdline.cmdline); - }else if (atag->hdr.tag ==ATAG_MEM ) { + }else if (atag->hdr.tag ==cpu_to_atag32 (ATAG_MEM )) {if (memcount >=sizeof (mem_reg_property)/4 )continue ; -if (!atag->u.mem.size) +if (!atag32_to_cpu (atag->u.mem.size))continue ; - mem_reg_property[memcount++] =cpu_to_fdt32 (atag->u.mem.start); - mem_reg_property[memcount++] =cpu_to_fdt32 (atag->u.mem.size); - }else if (atag->hdr.tag ==ATAG_INITRD2 ) { + mem_reg_property[memcount++] =cpu_to_fdt32 (atag32_to_cpu (atag->u.mem.start)); + mem_reg_property[memcount++] =cpu_to_fdt32 (atag32_to_cpu (atag->u.mem.size)); + }else if (atag->hdr.tag ==cpu_to_atag32 (ATAG_INITRD2 )) {uint32_t initrd_start, initrd_size; - initrd_start = atag->u.initrd.start; - initrd_size = atag->u.initrd.size; + initrd_start =atag32_to_cpu (atag->u.initrd.start); + initrd_size =atag32_to_cpu (atag->u.initrd.size);setprop_cell (fdt,"/chosen" ,"linux,initrd-start" , initrd_start); setprop_cell(fdt, "/chosen", "linux,initrd-end",
Signature · 1 line
1.7.10.4
PATCH 5/6 ARM: fixup atags to be endian agnostic
In reply to Ben DooksUse the atag32_to_cpu() function to allow the main atag handling code to be agnostic of any endian configuration.
--- arch/arm/kernel/atags_parse.c | 51 +++++++++++++++++++++-------------------- arch/arm/kernel/atags_proc.c | 6 ++--- 2 files changed, 29 insertions(+), 28 deletions(-)
arch/arm/kernel/atags_parse.c +26 -25
@@ -43,19 +43,19 @@ static struct {struct tag_mem32 mem;struct tag_header hdr3; } default_tags __initdata = { - { tag_size(tag_core), ATAG_CORE }, - { 1, PAGE_SIZE, 0xff }, - { tag_size(tag_mem32), ATAG_MEM }, - { MEM_SIZE }, - { 0, ATAG_NONE } + { cpu_to_atag32(tag_size(tag_core)), cpu_to_atag32(ATAG_CORE) }, + { cpu_to_atag32(1), atag32_to_cpu(PAGE_SIZE), cpu_to_atag32(0xff) }, + { cpu_to_atag32(tag_size(tag_mem32)), cpu_to_atag32(ATAG_MEM) }, + { cpu_to_atag32(MEM_SIZE) }, + { cpu_to_atag32(0), cpu_to_atag32(ATAG_NONE) } }; static int __init parse_tag_core(const struct tag *tag) { - if (tag->hdr.size > 2) { - if ((tag->u.core.flags & 1) == 0) + if (atag32_to_cpu(tag->hdr.size) > 2) { + if ((atag32_to_cpu(tag->u.core.flags) & 1) == 0) root_mountflags &= ~MS_RDONLY; - ROOT_DEV = old_decode_dev(tag->u.core.rootdev); + ROOT_DEV = old_decode_dev(atag32_to_cpu(tag->u.core.rootdev)); } return 0; }
@@ -64,7 +64,7 @@ __tagtable(ATAG_CORE, parse_tag_core);static int __init parse_tag_mem32 (const struct tag *tag) { -return arm_add_memory (tag->u.mem.start, tag->u.mem.size); +return arm_add_memory (atag32_to_cpu (tag->u.mem.start),atag32_to_cpu (tag->u.mem.size)); }__tagtable (ATAG_MEM , parse_tag_mem32);
@@ -91,13 +91,14 @@ __tagtable(ATAG_VIDEOTEXT, parse_tag_videotext);static int __init parse_tag_ramdisk (const struct tag *tag) {extern int rd_size, rd_image_start, rd_prompt, rd_doload; +unsigned int flags =atag32_to_cpu (tag->u.ramdisk.flags); - rd_image_start = tag->u.ramdisk.start; - rd_doload = (tag->u.ramdisk.flags &1 ) ==0 ; - rd_prompt = (tag->u.ramdisk.flags &2 ) ==0 ; + rd_image_start =atag32_to_cpu (tag->u.ramdisk.start); + rd_doload = (flags &1 ) ==0 ; + rd_prompt = (flags &2 ) ==0 ; -if (tag->u.ramdisk.size) - rd_size = tag->u.ramdisk.size; +if (atag32_to_cpu (tag->u.ramdisk.size)) + rd_size =atag32_to_cpu (tag->u.ramdisk.size);return 0 ; }
@@ -107,8 +108,8 @@ __tagtable(ATAG_RAMDISK, parse_tag_ramdisk);static int __init parse_tag_serialnr (const struct tag *tag) { - system_serial_low = tag->u.serialnr.low; - system_serial_high = tag->u.serialnr.high; + system_serial_low =atag32_to_cpu (tag->u.serialnr.low); + system_serial_high =atag32_to_cpu (tag->u.serialnr.high);return 0 ; }
@@ -116,7 +117,7 @@ __tagtable(ATAG_SERIAL, parse_tag_serialnr);static int __init parse_tag_revision (const struct tag *tag) { - system_rev = tag->u.revision.rev; + system_rev =atag32_to_cpu (tag->u.revision.rev);return 0 ; }
@@ -150,7 +151,7 @@ static int __init parse_tag(const struct tag *tag)struct tagtable *t;for (t = &__tagtable_begin; t < &__tagtable_end; t++) -if (tag->hdr.tag == t->tag) { +if (atag32_to_cpu (tag->hdr.tag) == t->tag) { t->parse (tag);break ; }
@@ -164,17 +165,17 @@ static int __init parse_tag(const struct tag *tag)*/ static void __init parse_tags (const struct tag *t) { -for (; t->hdr.size; t =tag_next (t)) +for_each_tag (t, t)if (!parse_tag (t))printk (KERN_WARNING "Ignoring unrecognised tag 0x%08x\n" , - t->hdr.tag); +atag32_to_cpu (t->hdr.tag)); }static void __init squash_mem_tags (struct tag *tag) { -for (; tag->hdr.size; tag =tag_next (tag)) -if (tag->hdr.tag ==ATAG_MEM ) +for_each_tag (tag, tag) +if (tag->hdr.tag ==atag32_to_cpu (ATAG_MEM )) tag->hdr.tag =ATAG_NONE ; }
@@ -213,10 +214,10 @@ struct machine_desc * __init setup_machine_tags(phys_addr_t __atags_pointer,* If we have the old style parameters, convert them to * a tag list. */ -if (tags->hdr.tag !=ATAG_CORE ) +if (tags->hdr.tag !=atag32_to_cpu (ATAG_CORE ))convert_to_tag_list (tags);#endif -if (tags->hdr.tag !=ATAG_CORE ) { +if (tags->hdr.tag !=atag32_to_cpu (ATAG_CORE )) {early_print ("Warning: Neither atags nor dtb found\n" ); tags = (struct tag *)&default_tags; }
@@ -224,7 +225,7 @@ struct machine_desc * __init setup_machine_tags(phys_addr_t __atags_pointer,if (mdesc->fixup) mdesc->fixup (tags, &from, &meminfo); -if (tags->hdr.tag ==ATAG_CORE ) { +if (tags->hdr.tag ==cpu_to_atag32 (ATAG_CORE )) {if (meminfo.nr_banks !=0 )squash_mem_tags (tags);save_atags (tags);
arch/arm/kernel/atags_proc.c +3 -3
@@ -40,18 +40,18 @@ static int __init init_atags_procfs(void)struct buffer *b;size_t size; -if (tag->hdr.tag !=ATAG_CORE ) { +if (tag->hdr.tag !=cpu_to_atag32 (ATAG_CORE )) {printk (KERN_INFO "No ATAGs?" );return -EINVAL ; } -for (; tag->hdr.size; tag =tag_next (tag)) +for_each_tag (tag, tag) ;/* include the terminating ATAG_NONE */ size = (char *)tag - atags_copy +sizeof (struct tag_header ); -WARN_ON (tag->hdr.tag !=ATAG_NONE ); +WARN_ON (tag->hdr.tag !=cpu_to_atag32 (ATAG_NONE )); b =kmalloc (sizeof (*b) + size,GFP_KERNEL );if (!b)
Signature · 1 line
1.7.10.4
PATCH 6/6 ARM: ensure loader information in LE format for BE kernels
In reply to Ben DooksFrom: Nico Pitre <[email protected]>
If the loader for the system is assuming we are booting a BE kernel from a LE loading environment, then ensure that the magic number and image start/end values are in little endian format.
--- arch/arm/boot/compressed/Makefile | 5 ++++- arch/arm/boot/compressed/head.S | 7 ++++--- arch/arm/boot/compressed/vmlinux.lds.in | 14 ++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-)
arch/arm/boot/compressed/Makefile +4 -1
@@ -194,8 +194,11 @@ CFLAGS_font.o := -Dstatic= $(obj)/font.c: $(FONTC) $(call cmd,shipped) -$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) +$(obj)/vmlinux.lds.S: $(obj)/vmlinux.lds.in arch/arm/boot/Makefile $(KCONFIG_CONFIG) @sed "$(SEDFLAGS)" < $< > $@ +$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.S + $(call if_changed,cpp_lds_S) + $(obj)/hyp-stub.S: $(srctree)/arch/$(SRCARCH)/kernel/hyp-stub.S $(call cmd,shipped)
arch/arm/boot/compressed/head.S +4 -3
@@ -130,9 +130,10 @@ start: THUMB( adr r12, BSYM(1f) ) THUMB( bx r12 ) - .word 0x016f2818 @ Magic numbers to help the loader - .word start @ absolute load/run zImage address - .word _edata @ zImage end address + .word _magic_sig @ Magic numbers to help the loader + .word _magic_start @ absolute load/run zImage address + .word _magic_end @ zImage end address + THUMB( .thumb ) 1: mrs r9, cpsr
arch/arm/boot/compressed/vmlinux.lds.in +14 -0
@@ -7,6 +7,16 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ + +#ifdef CONFIG_CPU_BE8_BOOT_LE +#define ZIMAGE_MAGIC(x) ( (((x) >> 24) & 0x000000ff) | \ + (((x) >> 8) & 0x0000ff00) | \ + (((x) << 8) & 0x00ff0000) | \ + (((x) << 24) & 0xff000000) ) +#else +#define ZIMAGE_MAGIC(x) (x) +#endif + OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS
@@ -57,6 +67,10 @@ SECTIONS .pad : { BYTE(0); . = ALIGN(8); } _edata = .; + _magic_sig = ZIMAGE_MAGIC(0x016f2818); + _magic_start = ZIMAGE_MAGIC(_start); + _magic_end = ZIMAGE_MAGIC(_edata); + . = BSS_START; __bss_start = .; .bss : { *(.bss) }
Signature · 1 line
1.7.10.4
Quoted 3 lines · Ben Dooks
Add a series of patches to update the system to support little-endian boot loaders with big-endian kernels. Mostly fixes for ATAGS parsing and loader magic values.
Russell, would you be prepared to take this series?
Signature · 2 lines
Ben Dooks http://www.codethink.co.uk/ Senior Engineer Codethink - Providing Genius