Message ID | 20200320144348.12865-1-geert+renesas@glider.be (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v4] ARM: boot: Obtain start of physical memory from DTB | expand |
20.03.2020 17:43, Geert Uytterhoeven пишет: > Currently, the start address of physical memory is obtained by masking > the program counter with a fixed mask of 0xf8000000. This mask value > was chosen as a balance between the requirements of different platforms. > However, this does require that the start address of physical memory is > a multiple of 128 MiB, precluding booting Linux on platforms where this > requirement is not fulfilled. > > Fix this limitation by obtaining the start address from the DTB instead, > if available (either explicitly passed, or appended to the kernel). > Fall back to the traditional method when needed. > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > i.e. not at a multiple of 128 MiB. > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > v4: > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > decompressor: factor out routine to obtain the inflated image > size"), > > v3: > - Add Reviewed-by, > - Fix ATAGs with appended DTB, > - Add Tested-by, > > v2: > - Use "cmp r0, #-1", instead of "cmn r0, #1", > - Add missing stack setup, > - Support appended DTB. > --- > arch/arm/boot/compressed/Makefile | 6 ++- > arch/arm/boot/compressed/fdt_get_mem_start.c | 52 +++++++++++++++++++ > arch/arm/boot/compressed/head.S | 54 +++++++++++++++++++- > 3 files changed, 110 insertions(+), 2 deletions(-) > create mode 100644 arch/arm/boot/compressed/fdt_get_mem_start.c Thank you very much! It works! Tested-by: Dmitry Osipenko <digetx@gmail.com>
On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven <geert+renesas@glider.be> wrote: > > Currently, the start address of physical memory is obtained by masking > the program counter with a fixed mask of 0xf8000000. This mask value > was chosen as a balance between the requirements of different platforms. > However, this does require that the start address of physical memory is > a multiple of 128 MiB, precluding booting Linux on platforms where this > requirement is not fulfilled. > > Fix this limitation by obtaining the start address from the DTB instead, > if available (either explicitly passed, or appended to the kernel). > Fall back to the traditional method when needed. > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > i.e. not at a multiple of 128 MiB. > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > --- > v4: > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > decompressor: factor out routine to obtain the inflated image > size"), > Apologies for the breakage. I was aware of the existence of this patch, but I didn't realize it was accessing LC0 early on to find the stack pointer value. Reviewed-by: Ard Biesheuvel <ardb@kernel.org> > v3: > - Add Reviewed-by, > - Fix ATAGs with appended DTB, > - Add Tested-by, > > v2: > - Use "cmp r0, #-1", instead of "cmn r0, #1", > - Add missing stack setup, > - Support appended DTB. > --- > arch/arm/boot/compressed/Makefile | 6 ++- > arch/arm/boot/compressed/fdt_get_mem_start.c | 52 +++++++++++++++++++ > arch/arm/boot/compressed/head.S | 54 +++++++++++++++++++- > 3 files changed, 110 insertions(+), 2 deletions(-) > create mode 100644 arch/arm/boot/compressed/fdt_get_mem_start.c > > diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile > index 9c11e7490292f0e0..82e4cee97cb5d905 100644 > --- a/arch/arm/boot/compressed/Makefile > +++ b/arch/arm/boot/compressed/Makefile > @@ -86,12 +86,15 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt))) > $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/% > $(call cmd,shipped) > > -$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \ > +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o fdt_get_mem_start.o): \ > $(addprefix $(obj)/,$(libfdt_hdrs)) > > ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y) > OBJS += $(libfdt_objs) atags_to_fdt.o > endif > +ifeq ($(CONFIG_USE_OF),y) > +OBJS += $(libfdt_objs) fdt_get_mem_start.o > +endif > > targets := vmlinux vmlinux.lds piggy_data piggy.o \ > lib1funcs.o ashldi3.o bswapsdi2.o \ > @@ -115,6 +118,7 @@ CFLAGS_fdt.o := $(nossp-flags-y) > CFLAGS_fdt_ro.o := $(nossp-flags-y) > CFLAGS_fdt_rw.o := $(nossp-flags-y) > CFLAGS_fdt_wip.o := $(nossp-flags-y) > +CFLAGS_fdt_get_mem_start.o := $(nossp-flags-y) > > ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \ > -I$(obj) $(DISABLE_ARM_SSP_PER_TASK_PLUGIN) > diff --git a/arch/arm/boot/compressed/fdt_get_mem_start.c b/arch/arm/boot/compressed/fdt_get_mem_start.c > new file mode 100644 > index 0000000000000000..2c5ac47f656317ee > --- /dev/null > +++ b/arch/arm/boot/compressed/fdt_get_mem_start.c > @@ -0,0 +1,52 @@ > +// SPDX-License-Identifier: GPL-2.0-only > + > +#include <libfdt.h> > + > +static const void *getprop(const void *fdt, const char *node_path, > + const char *property) > +{ > + int offset = fdt_path_offset(fdt, node_path); > + > + if (offset == -FDT_ERR_NOTFOUND) > + return NULL; > + > + return fdt_getprop(fdt, offset, property, NULL); > +} > + > +static uint32_t get_addr_size(const void *fdt) > +{ > + const __be32 *addr_len = getprop(fdt, "/", "#address-cells"); > + > + if (!addr_len) { > + /* default */ > + return 1; > + } > + > + return fdt32_to_cpu(*addr_len); > +} > + > +/* > + * Get the start of physical memory > + */ > + > +unsigned long fdt_get_mem_start(const void *fdt) > +{ > + const __be32 *memory; > + uint32_t addr_size; > + > + if (!fdt) > + return -1; > + > + if (*(__be32 *)fdt != cpu_to_fdt32(FDT_MAGIC)) > + return -1; > + > + /* Find the first memory node */ > + memory = getprop(fdt, "/memory", "reg"); > + if (!memory) > + return -1; > + > + /* There may be multiple cells on LPAE platforms */ > + addr_size = get_addr_size(fdt); > + > + return fdt32_to_cpu(memory[addr_size - 1]); > +} > diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S > index 4f7c6145e31fdc25..e6c06ee19fef2e2d 100644 > --- a/arch/arm/boot/compressed/head.S > +++ b/arch/arm/boot/compressed/head.S > @@ -254,8 +254,58 @@ not_angel: > .text > > #ifdef CONFIG_AUTO_ZRELADDR > +#ifdef CONFIG_USE_OF > /* > - * Find the start of physical memory. As we are executing > + * Find the start of physical memory. > + * Try the DTB first, if available. > + */ > + adr r0, LC0 > + ldr r1, [r0] @ get absolute LC0 > + ldr sp, [r0, #24] @ get stack location > + sub r1, r0, r1 @ compute relocation offset > + add sp, sp, r1 @ apply relocation > + > +#ifdef CONFIG_ARM_APPENDED_DTB > + /* > + * Look for an appended DTB. If found, use it and > + * move stack away from it. > + */ > + ldr r6, [r0, #12] @ get &_edata > + add r6, r6, r1 @ relocate it > + ldmia r6, {r0, r5} @ get DTB signature and size > +#ifndef __ARMEB__ > + ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian > + /* convert DTB size to little endian */ > + eor r2, r5, r5, ror #16 > + bic r2, r2, #0x00ff0000 > + mov r5, r5, ror #8 > + eor r5, r5, r2, lsr #8 > +#else > + ldr r1, =0xd00dfeed > +#endif > + cmp r0, r1 @ do we have a DTB there? > + bne 1f > + > + /* preserve 64-bit alignment */ > + add r5, r5, #7 > + bic r5, r5, #7 > + add sp, sp, r5 @ if so, move stack above DTB > + mov r0, r6 @ and extract memory start from DTB > + b 2f > + > +1: > +#endif /* CONFIG_ARM_APPENDED_DTB */ > + > + mov r0, r8 > +2: > + bl fdt_get_mem_start > + mov r4, r0 > + cmp r0, #-1 > + bne 1f > +#endif /* CONFIG_USE_OF */ > + > + /* > + * Fall back to the traditional method. As we are executing > * without the MMU on, we are in the physical address space. > * We just need to get rid of any offset by aligning the > * address. > @@ -273,6 +323,8 @@ not_angel: > */ > mov r4, pc > and r4, r4, #0xf8000000 > + > +1: > /* Determine final kernel image address. */ > add r4, r4, #TEXT_OFFSET > #else > -- > 2.17.1 >
Hi Ard, On Wed, Mar 25, 2020 at 5:40 PM Ard Biesheuvel <ardb@kernel.org> wrote: > On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven > <geert+renesas@glider.be> wrote: > > Currently, the start address of physical memory is obtained by masking > > the program counter with a fixed mask of 0xf8000000. This mask value > > was chosen as a balance between the requirements of different platforms. > > However, this does require that the start address of physical memory is > > a multiple of 128 MiB, precluding booting Linux on platforms where this > > requirement is not fulfilled. > > > > Fix this limitation by obtaining the start address from the DTB instead, > > if available (either explicitly passed, or appended to the kernel). > > Fall back to the traditional method when needed. > > > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > > i.e. not at a multiple of 128 MiB. > > > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > > --- > > v4: > > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > > decompressor: factor out routine to obtain the inflated image > > size"), > > > > Apologies for the breakage. I was aware of the existence of this > patch, but I didn't realize it was accessing LC0 early on to find the > stack pointer value. No problem, you sent your PR on the same day I posted v2, which was the first version to access LC0. > Reviewed-by: Ard Biesheuvel <ardb@kernel.org> Thanks! Gr{oetje,eeting}s, Geert
On Wed, 25 Mar 2020 at 17:40, Ard Biesheuvel <ardb@kernel.org> wrote: > > On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven > <geert+renesas@glider.be> wrote: > > > > Currently, the start address of physical memory is obtained by masking > > the program counter with a fixed mask of 0xf8000000. This mask value > > was chosen as a balance between the requirements of different platforms. > > However, this does require that the start address of physical memory is > > a multiple of 128 MiB, precluding booting Linux on platforms where this > > requirement is not fulfilled. > > > > Fix this limitation by obtaining the start address from the DTB instead, > > if available (either explicitly passed, or appended to the kernel). > > Fall back to the traditional method when needed. > > > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > > i.e. not at a multiple of 128 MiB. > > > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > > --- > > v4: > > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > > decompressor: factor out routine to obtain the inflated image > > size"), > > > > Apologies for the breakage. I was aware of the existence of this > patch, but I didn't realize it was accessing LC0 early on to find the > stack pointer value. > > Reviewed-by: Ard Biesheuvel <ardb@kernel.org> > OK, so one thing I did notice when playing with this code is that the phys/virt patching code requires that 'PHYS_OFFSET - PAGE_OFFSET' is a multiple of 16 MB, and so this needs to be taken into account by this change as well, given that PHYS_OFFSET is based on the placement of the uncompressed kernel in the physical address space.
Hi Ard, On Tue, Apr 14, 2020 at 10:07 AM Ard Biesheuvel <ardb@kernel.org> wrote: > On Wed, 25 Mar 2020 at 17:40, Ard Biesheuvel <ardb@kernel.org> wrote: > > On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven > > <geert+renesas@glider.be> wrote: > > > Currently, the start address of physical memory is obtained by masking > > > the program counter with a fixed mask of 0xf8000000. This mask value > > > was chosen as a balance between the requirements of different platforms. > > > However, this does require that the start address of physical memory is > > > a multiple of 128 MiB, precluding booting Linux on platforms where this > > > requirement is not fulfilled. > > > > > > Fix this limitation by obtaining the start address from the DTB instead, > > > if available (either explicitly passed, or appended to the kernel). > > > Fall back to the traditional method when needed. > > > > > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > > > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > > > i.e. not at a multiple of 128 MiB. > > > > > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > > > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > > > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > > > --- > > > v4: > > > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > > > decompressor: factor out routine to obtain the inflated image > > > size"), > > > > > > > Apologies for the breakage. I was aware of the existence of this > > patch, but I didn't realize it was accessing LC0 early on to find the > > stack pointer value. > > > > Reviewed-by: Ard Biesheuvel <ardb@kernel.org> > > OK, so one thing I did notice when playing with this code is that the > phys/virt patching code requires that 'PHYS_OFFSET - PAGE_OFFSET' is a > multiple of 16 MB, and so this needs to be taken into account by this > change as well, given that PHYS_OFFSET is based on the placement of > the uncompressed kernel in the physical address space. You mean fdt_get_mem_start() should round up the address to make sure it is a multiple of 16 MiB (assumed PAGE_OFFSET is a multiple of 16 MiB, too)? Can PAGE_OFFSET actually be not a multiple of 16 MiB? Thanks! Gr{oetje,eeting}s, Geert
On Wed, 15 Apr 2020 at 14:45, Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > Hi Ard, > > On Tue, Apr 14, 2020 at 10:07 AM Ard Biesheuvel <ardb@kernel.org> wrote: > > On Wed, 25 Mar 2020 at 17:40, Ard Biesheuvel <ardb@kernel.org> wrote: > > > On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven > > > <geert+renesas@glider.be> wrote: > > > > Currently, the start address of physical memory is obtained by masking > > > > the program counter with a fixed mask of 0xf8000000. This mask value > > > > was chosen as a balance between the requirements of different platforms. > > > > However, this does require that the start address of physical memory is > > > > a multiple of 128 MiB, precluding booting Linux on platforms where this > > > > requirement is not fulfilled. > > > > > > > > Fix this limitation by obtaining the start address from the DTB instead, > > > > if available (either explicitly passed, or appended to the kernel). > > > > Fall back to the traditional method when needed. > > > > > > > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > > > > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > > > > i.e. not at a multiple of 128 MiB. > > > > > > > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > > > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > > > > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > > > > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > > > > --- > > > > v4: > > > > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > > > > decompressor: factor out routine to obtain the inflated image > > > > size"), > > > > > > > > > > Apologies for the breakage. I was aware of the existence of this > > > patch, but I didn't realize it was accessing LC0 early on to find the > > > stack pointer value. > > > > > > Reviewed-by: Ard Biesheuvel <ardb@kernel.org> > > > > OK, so one thing I did notice when playing with this code is that the > > phys/virt patching code requires that 'PHYS_OFFSET - PAGE_OFFSET' is a > > multiple of 16 MB, and so this needs to be taken into account by this > > change as well, given that PHYS_OFFSET is based on the placement of > > the uncompressed kernel in the physical address space. > > You mean fdt_get_mem_start() should round up the address to make sure > it is a multiple of 16 MiB (assumed PAGE_OFFSET is a multiple of 16 MiB, > too)? Yes. > Can PAGE_OFFSET actually be not a multiple of 16 MiB? ARM's Kconfig has config PAGE_OFFSET hex default PHYS_OFFSET if !MMU default 0x40000000 if VMSPLIT_1G default 0x80000000 if VMSPLIT_2G default 0xB0000000 if VMSPLIT_3G_OPT default 0xC0000000 which means that PHYS_OFFSET - PAGE_OFFSET is guaranteed to be 16 MB aligned if PHYS_OFFSET is 16 MB aligned.
Hi Ard, On Wed, Apr 15, 2020 at 2:57 PM Ard Biesheuvel <ardb@kernel.org> wrote: > On Wed, 15 Apr 2020 at 14:45, Geert Uytterhoeven <geert@linux-m68k.org> wrote: > > On Tue, Apr 14, 2020 at 10:07 AM Ard Biesheuvel <ardb@kernel.org> wrote: > > > On Wed, 25 Mar 2020 at 17:40, Ard Biesheuvel <ardb@kernel.org> wrote: > > > > On Fri, 20 Mar 2020 at 15:43, Geert Uytterhoeven > > > > <geert+renesas@glider.be> wrote: > > > > > Currently, the start address of physical memory is obtained by masking > > > > > the program counter with a fixed mask of 0xf8000000. This mask value > > > > > was chosen as a balance between the requirements of different platforms. > > > > > However, this does require that the start address of physical memory is > > > > > a multiple of 128 MiB, precluding booting Linux on platforms where this > > > > > requirement is not fulfilled. > > > > > > > > > > Fix this limitation by obtaining the start address from the DTB instead, > > > > > if available (either explicitly passed, or appended to the kernel). > > > > > Fall back to the traditional method when needed. > > > > > > > > > > This allows to boot Linux on r7s9210/rza2mevb using the 64 MiB of SDRAM > > > > > on the RZA2MEVB sub board, which is located at 0x0C000000 (CS3 space), > > > > > i.e. not at a multiple of 128 MiB. > > > > > > > > > > Suggested-by: Nicolas Pitre <nico@fluxnic.net> > > > > > Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be> > > > > > Reviewed-by: Nicolas Pitre <nico@fluxnic.net> > > > > > Tested-by: Marek Szyprowski <m.szyprowski@samsung.com> > > > > > --- > > > > > v4: > > > > > - Fix stack location after commit 184bf653a7a452c1 ("ARM: > > > > > decompressor: factor out routine to obtain the inflated image > > > > > size"), > > > > > > > > > > > > > Apologies for the breakage. I was aware of the existence of this > > > > patch, but I didn't realize it was accessing LC0 early on to find the > > > > stack pointer value. > > > > > > > > Reviewed-by: Ard Biesheuvel <ardb@kernel.org> > > > > > > OK, so one thing I did notice when playing with this code is that the > > > phys/virt patching code requires that 'PHYS_OFFSET - PAGE_OFFSET' is a > > > multiple of 16 MB, and so this needs to be taken into account by this > > > change as well, given that PHYS_OFFSET is based on the placement of > > > the uncompressed kernel in the physical address space. > > > > You mean fdt_get_mem_start() should round up the address to make sure > > it is a multiple of 16 MiB (assumed PAGE_OFFSET is a multiple of 16 MiB, > > too)? > > Yes. OK. > > Can PAGE_OFFSET actually be not a multiple of 16 MiB? > > ARM's Kconfig has > > config PAGE_OFFSET > hex > default PHYS_OFFSET if !MMU > default 0x40000000 if VMSPLIT_1G > default 0x80000000 if VMSPLIT_2G > default 0xB0000000 if VMSPLIT_3G_OPT > default 0xC0000000 > > which means that PHYS_OFFSET - PAGE_OFFSET is guaranteed to be 16 MB > aligned if PHYS_OFFSET is 16 MB aligned. Ah, I missed the lack of a prompt, and thought this was user-configurable, too. Hence as you talked about the alignment of the difference of the two values only, I wondered if PAGE_OFFSET could be e.g. 0xb0800000, so PHYS_OFFSET has to be offset by 0x800000, too ;-) Gr{oetje,eeting}s, Geert
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile index 9c11e7490292f0e0..82e4cee97cb5d905 100644 --- a/arch/arm/boot/compressed/Makefile +++ b/arch/arm/boot/compressed/Makefile @@ -86,12 +86,15 @@ libfdt_objs := $(addsuffix .o, $(basename $(libfdt))) $(addprefix $(obj)/,$(libfdt) $(libfdt_hdrs)): $(obj)/%: $(srctree)/scripts/dtc/libfdt/% $(call cmd,shipped) -$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o): \ +$(addprefix $(obj)/,$(libfdt_objs) atags_to_fdt.o fdt_get_mem_start.o): \ $(addprefix $(obj)/,$(libfdt_hdrs)) ifeq ($(CONFIG_ARM_ATAG_DTB_COMPAT),y) OBJS += $(libfdt_objs) atags_to_fdt.o endif +ifeq ($(CONFIG_USE_OF),y) +OBJS += $(libfdt_objs) fdt_get_mem_start.o +endif targets := vmlinux vmlinux.lds piggy_data piggy.o \ lib1funcs.o ashldi3.o bswapsdi2.o \ @@ -115,6 +118,7 @@ CFLAGS_fdt.o := $(nossp-flags-y) CFLAGS_fdt_ro.o := $(nossp-flags-y) CFLAGS_fdt_rw.o := $(nossp-flags-y) CFLAGS_fdt_wip.o := $(nossp-flags-y) +CFLAGS_fdt_get_mem_start.o := $(nossp-flags-y) ccflags-y := -fpic $(call cc-option,-mno-single-pic-base,) -fno-builtin \ -I$(obj) $(DISABLE_ARM_SSP_PER_TASK_PLUGIN) diff --git a/arch/arm/boot/compressed/fdt_get_mem_start.c b/arch/arm/boot/compressed/fdt_get_mem_start.c new file mode 100644 index 0000000000000000..2c5ac47f656317ee --- /dev/null +++ b/arch/arm/boot/compressed/fdt_get_mem_start.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <libfdt.h> + +static const void *getprop(const void *fdt, const char *node_path, + const char *property) +{ + int offset = fdt_path_offset(fdt, node_path); + + if (offset == -FDT_ERR_NOTFOUND) + return NULL; + + return fdt_getprop(fdt, offset, property, NULL); +} + +static uint32_t get_addr_size(const void *fdt) +{ + const __be32 *addr_len = getprop(fdt, "/", "#address-cells"); + + if (!addr_len) { + /* default */ + return 1; + } + + return fdt32_to_cpu(*addr_len); +} + +/* + * Get the start of physical memory + */ + +unsigned long fdt_get_mem_start(const void *fdt) +{ + const __be32 *memory; + uint32_t addr_size; + + if (!fdt) + return -1; + + if (*(__be32 *)fdt != cpu_to_fdt32(FDT_MAGIC)) + return -1; + + /* Find the first memory node */ + memory = getprop(fdt, "/memory", "reg"); + if (!memory) + return -1; + + /* There may be multiple cells on LPAE platforms */ + addr_size = get_addr_size(fdt); + + return fdt32_to_cpu(memory[addr_size - 1]); +} diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S index 4f7c6145e31fdc25..e6c06ee19fef2e2d 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -254,8 +254,58 @@ not_angel: .text #ifdef CONFIG_AUTO_ZRELADDR +#ifdef CONFIG_USE_OF /* - * Find the start of physical memory. As we are executing + * Find the start of physical memory. + * Try the DTB first, if available. + */ + adr r0, LC0 + ldr r1, [r0] @ get absolute LC0 + ldr sp, [r0, #24] @ get stack location + sub r1, r0, r1 @ compute relocation offset + add sp, sp, r1 @ apply relocation + +#ifdef CONFIG_ARM_APPENDED_DTB + /* + * Look for an appended DTB. If found, use it and + * move stack away from it. + */ + ldr r6, [r0, #12] @ get &_edata + add r6, r6, r1 @ relocate it + ldmia r6, {r0, r5} @ get DTB signature and size +#ifndef __ARMEB__ + ldr r1, =0xedfe0dd0 @ sig is 0xd00dfeed big endian + /* convert DTB size to little endian */ + eor r2, r5, r5, ror #16 + bic r2, r2, #0x00ff0000 + mov r5, r5, ror #8 + eor r5, r5, r2, lsr #8 +#else + ldr r1, =0xd00dfeed +#endif + cmp r0, r1 @ do we have a DTB there? + bne 1f + + /* preserve 64-bit alignment */ + add r5, r5, #7 + bic r5, r5, #7 + add sp, sp, r5 @ if so, move stack above DTB + mov r0, r6 @ and extract memory start from DTB + b 2f + +1: +#endif /* CONFIG_ARM_APPENDED_DTB */ + + mov r0, r8 +2: + bl fdt_get_mem_start + mov r4, r0 + cmp r0, #-1 + bne 1f +#endif /* CONFIG_USE_OF */ + + /* + * Fall back to the traditional method. As we are executing * without the MMU on, we are in the physical address space. * We just need to get rid of any offset by aligning the * address. @@ -273,6 +323,8 @@ not_angel: */ mov r4, pc and r4, r4, #0xf8000000 + +1: /* Determine final kernel image address. */ add r4, r4, #TEXT_OFFSET #else