From 3cdb5fa08a226a64e3486f7c2a32d044bdfada7d Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 19 Dec 2017 18:30:34 -0700 Subject: [PATCH 01/14] ARM: tegra: don't use CONFIG_SPL_TEXT_BASE when no SPL 64-bit Tegra don't use SPL, and soon won't define CONFIG_SPL_TEXT_BASE when building. Fix the binman .dts file so that it doesn't use undefined values. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/dts/tegra-u-boot.dtsi | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/arch/arm/dts/tegra-u-boot.dtsi b/arch/arm/dts/tegra-u-boot.dtsi index cde591c5fc..4f692ee975 100644 --- a/arch/arm/dts/tegra-u-boot.dtsi +++ b/arch/arm/dts/tegra-u-boot.dtsi @@ -1,5 +1,11 @@ #include +#ifdef CONFIG_SPL_TEXT_BASE +#define U_BOOT_OFFSET (CONFIG_SYS_TEXT_BASE - CONFIG_SPL_TEXT_BASE) +#else +#define U_BOOT_OFFSET 0 +#endif + / { binman { multiple-images; @@ -9,8 +15,7 @@ u-boot-spl { }; u-boot { - pos = <(CONFIG_SYS_TEXT_BASE - - CONFIG_SPL_TEXT_BASE)>; + pos = <(U_BOOT_OFFSET)>; }; }; @@ -21,8 +26,7 @@ u-boot-spl { }; u-boot { - pos = <(CONFIG_SYS_TEXT_BASE - - CONFIG_SPL_TEXT_BASE)>; + pos = <(U_BOOT_OFFSET)>; }; }; @@ -32,8 +36,7 @@ u-boot-spl { }; u-boot-nodtb { - pos = <(CONFIG_SYS_TEXT_BASE - - CONFIG_SPL_TEXT_BASE)>; + pos = <(U_BOOT_OFFSET)>; }; }; }; From 0d1bd150f041b9c5939e2e6be36f91444b10cace Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 19 Dec 2017 18:30:35 -0700 Subject: [PATCH 02/14] ARM: tegra: remove SPL config for non-SPL SoCs No 64-bit Tegra uses SPL. Remove various unused definitions from config headers. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- include/configs/tegra-common.h | 2 ++ include/configs/tegra186-common.h | 5 ----- include/configs/tegra210-common.h | 5 ----- 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index 3cdd9741b2..75e36c0b75 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -84,11 +84,13 @@ CONFIG_SYS_INIT_RAM_SIZE - \ GENERATED_GBL_DATA_SIZE) +#ifndef CONFIG_ARM64 /* Defines for SPL */ #define CONFIG_SPL_FRAMEWORK #define CONFIG_SPL_MAX_FOOTPRINT (CONFIG_SYS_TEXT_BASE - \ CONFIG_SPL_TEXT_BASE) #define CONFIG_SYS_SPL_MALLOC_SIZE 0x00010000 +#endif /* Misc utility code */ #define CONFIG_BOUNCE_BUFFER diff --git a/include/configs/tegra186-common.h b/include/configs/tegra186-common.h index 98e4fc2d25..495d18555f 100644 --- a/include/configs/tegra186-common.h +++ b/include/configs/tegra186-common.h @@ -60,9 +60,4 @@ "fdt_addr_r=0x82000000\0" \ "ramdisk_addr_r=0x82100000\0" -/* Defines for SPL */ -#define CONFIG_SPL_TEXT_BASE 0x80108000 -#define CONFIG_SYS_SPL_MALLOC_START 0x80090000 -#define CONFIG_SPL_STACK 0x800ffffc - #endif diff --git a/include/configs/tegra210-common.h b/include/configs/tegra210-common.h index 4c05576a90..93c9455e8f 100644 --- a/include/configs/tegra210-common.h +++ b/include/configs/tegra210-common.h @@ -60,11 +60,6 @@ "fdt_addr_r=0x82000000\0" \ "ramdisk_addr_r=0x82100000\0" -/* Defines for SPL */ -#define CONFIG_SPL_TEXT_BASE 0x80108000 -#define CONFIG_SYS_SPL_MALLOC_START 0x80090000 -#define CONFIG_SPL_STACK 0x800ffffc - /* For USB EHCI controller */ #define CONFIG_EHCI_IS_TDI #define CONFIG_USB_EHCI_TXFIFO_THRESH 0x10 From e6c904489a6018f44c3b00c9eacc4742887b1f83 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 19 Dec 2017 18:30:36 -0700 Subject: [PATCH 03/14] ARMv8: Allow dynamic early stack pointer U-Boot typically uses a hard-coded value for the stack pointer before relocation. Implement option SYS_INIT_SP_BSS_OFFSET to instead calculate the initial SP at run-time. This is useful to avoid hard-coding addresses into U-Boot, so that can be loaded and executed at arbitrary addresses and thus avoid using arbitrary addresses at runtime. This option's value is the offset added to &_bss_start in order to calculate the stack pointer. This offset should be large enough so that the early malloc region, global data (gd), and early stack usage do not overlap any appended DTB. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/Kconfig | 13 +++++++++++++ arch/arm/lib/crt0_64.S | 3 +++ 2 files changed, 16 insertions(+) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index de323bf4b9..c15acdf85c 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -19,6 +19,19 @@ config POSITION_INDEPENDENT from almost any address. This logic relies on the relocation information that is embedded into the binary to support U-Boot relocating itself to the top-of-RAM later during execution. + +config SYS_INIT_SP_BSS_OFFSET + int + help + U-Boot typically uses a hard-coded value for the stack pointer + before relocation. Define this option to instead calculate the + initial SP at run-time. This is useful to avoid hard-coding addresses + into U-Boot, so that can be loaded and executed at arbitrary + addresses and thus avoid using arbitrary addresses at runtime. This + option's value is the offset added to &_bss_start in order to + calculate the stack pointer. This offset should be large enough so + that the early malloc region, global data (gd), and early stack usage + do not overlap any appended DTB. endif config STATIC_RELA diff --git a/arch/arm/lib/crt0_64.S b/arch/arm/lib/crt0_64.S index 9cb70552fe..a181283e0f 100644 --- a/arch/arm/lib/crt0_64.S +++ b/arch/arm/lib/crt0_64.S @@ -73,6 +73,9 @@ ENTRY(_main) ldr x0, =(CONFIG_TPL_STACK) #elif defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) ldr x0, =(CONFIG_SPL_STACK) +#elif defined(CONFIG_SYS_INIT_SP_BSS_OFFSET) + adr x0, __bss_start + add x0, x0, #CONFIG_SYS_INIT_SP_BSS_OFFSET #else ldr x0, =(CONFIG_SYS_INIT_SP_ADDR) #endif From f097532d279dd7a6ab2d579425d1318051ac1f8d Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 19 Dec 2017 18:30:37 -0700 Subject: [PATCH 04/14] ARM: tegra: use CONFIG_SYS_INIT_SP_BSS_OFFSET Enable CONFIG_SYS_INIT_SP_BSS_OFFSET for all 64-bit Tegra boards. Place the stack/... 512KiB from the end of the U-Boot binary. This should be plenty to accommodate the current DTBs (max 64 KiB), early malloc region (6KiB), stack usage, and plenty of slack, while still not placing it too far away from the U-Boot binary. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/mach-tegra/tegra186/Kconfig | 3 +++ arch/arm/mach-tegra/tegra210/Kconfig | 3 +++ include/configs/tegra-common.h | 2 ++ include/configs/tegra186-common.h | 5 ----- include/configs/tegra210-common.h | 5 ----- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/arm/mach-tegra/tegra186/Kconfig b/arch/arm/mach-tegra/tegra186/Kconfig index b2e53b58ca..479c0955ee 100644 --- a/arch/arm/mach-tegra/tegra186/Kconfig +++ b/arch/arm/mach-tegra/tegra186/Kconfig @@ -21,6 +21,9 @@ endchoice config SYS_SOC default "tegra186" +config SYS_INIT_SP_BSS_OFFSET + default 524288 + source "board/nvidia/p2771-0000/Kconfig" endif diff --git a/arch/arm/mach-tegra/tegra210/Kconfig b/arch/arm/mach-tegra/tegra210/Kconfig index 3637473051..250738aed3 100644 --- a/arch/arm/mach-tegra/tegra210/Kconfig +++ b/arch/arm/mach-tegra/tegra210/Kconfig @@ -40,6 +40,9 @@ endchoice config SYS_SOC default "tegra210" +config SYS_INIT_SP_BSS_OFFSET + default 524288 + source "board/nvidia/e2220-1170/Kconfig" source "board/nvidia/p2371-0000/Kconfig" source "board/nvidia/p2371-2180/Kconfig" diff --git a/include/configs/tegra-common.h b/include/configs/tegra-common.h index 75e36c0b75..2d98a6fa64 100644 --- a/include/configs/tegra-common.h +++ b/include/configs/tegra-common.h @@ -78,11 +78,13 @@ #define CONFIG_SYS_BOOTMAPSZ (256 << 20) /* 256M */ +#ifndef CONFIG_ARM64 #define CONFIG_SYS_INIT_RAM_ADDR CONFIG_STACKBASE #define CONFIG_SYS_INIT_RAM_SIZE CONFIG_SYS_MALLOC_LEN #define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_INIT_RAM_ADDR + \ CONFIG_SYS_INIT_RAM_SIZE - \ GENERATED_GBL_DATA_SIZE) +#endif #ifndef CONFIG_ARM64 /* Defines for SPL */ diff --git a/include/configs/tegra186-common.h b/include/configs/tegra186-common.h index 495d18555f..1c8772a117 100644 --- a/include/configs/tegra186-common.h +++ b/include/configs/tegra186-common.h @@ -14,11 +14,6 @@ */ #define V_NS16550_CLK 408000000 /* 408MHz (pllp_out0) */ -/* - * Miscellaneous configurable options - */ -#define CONFIG_STACKBASE 0x82800000 /* 40MB */ - /*----------------------------------------------------------------------- * Physical Memory Map */ diff --git a/include/configs/tegra210-common.h b/include/configs/tegra210-common.h index 93c9455e8f..35735f3b78 100644 --- a/include/configs/tegra210-common.h +++ b/include/configs/tegra210-common.h @@ -15,11 +15,6 @@ */ #define V_NS16550_CLK 408000000 /* 408MHz (pllp_out0) */ -/* - * Miscellaneous configurable options - */ -#define CONFIG_STACKBASE 0x82800000 /* 40MB */ - /*----------------------------------------------------------------------- * Physical Memory Map */ From 8163faf952c467b01758b8a9a0dc8538e487aa9a Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 3 Jan 2018 14:31:51 -0700 Subject: [PATCH 05/14] ARMv8: add optional Linux kernel image header Allow placing a Linux kernel image header at the start of the U-Boot binary. This is useful since the image header reports the amount of memory (BSS and similar) that U-Boot needs to use, but that isn't part of the binary size. This can be used by the code that loads U-Boot into memory to determine where to load U-Boot, based on other users of memory. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/Kconfig | 17 ++++ .../armv8/linux-kernel-image-header-vars.h | 86 +++++++++++++++++++ arch/arm/cpu/armv8/start.S | 4 +- arch/arm/cpu/armv8/u-boot.lds | 4 + .../include/asm/boot0-linux-kernel-header.h | 49 +++++++++++ 5 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 arch/arm/cpu/armv8/linux-kernel-image-header-vars.h create mode 100644 arch/arm/include/asm/boot0-linux-kernel-header.h diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index c15acdf85c..001ece3cf1 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -32,6 +32,23 @@ config SYS_INIT_SP_BSS_OFFSET calculate the stack pointer. This offset should be large enough so that the early malloc region, global data (gd), and early stack usage do not overlap any appended DTB. + +config LINUX_KERNEL_IMAGE_HEADER + bool + help + Place a Linux kernel image header at the start of the U-Boot binary. + The format of the header is described in the Linux kernel source at + Documentation/arm64/booting.txt. This feature is useful since the + image header reports the amount of memory (BSS and similar) that + U-Boot needs to use, but which isn't part of the binary. + +if LINUX_KERNEL_IMAGE_HEADER +config LNX_KRNL_IMG_TEXT_OFFSET_BASE + hex + help + The value subtracted from CONFIG_SYS_TEXT_BASE to calculate the + TEXT_OFFSET value written in to the Linux kernel image header. +endif endif config STATIC_RELA diff --git a/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h b/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h new file mode 100644 index 0000000000..3e720937f0 --- /dev/null +++ b/arch/arm/cpu/armv8/linux-kernel-image-header-vars.h @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2017 NVIDIA Corporation + * + * Derived from Linux kernel v4.14 files: + * + * arch/arm64/include/asm/assembler.h: + * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S + * Copyright (C) 1996-2000 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * arch/arm64/kernel/head.S: + * Based on arch/arm/kernel/head.S + * Copyright (C) 1994-2002 Russell King + * Copyright (C) 2003-2012 ARM Ltd. + * Authors: Catalin Marinas + * Will Deacon + * + * arch/arm64/kernel/image.h: + * Copyright (C) 2014 ARM Ltd. + * + * SPDX-License-Identifier: GPL-2.0 + */ + +/* + * There aren't any ELF relocations we can use to endian-swap values known only + * at link time (e.g. the subtraction of two symbol addresses), so we must get + * the linker to endian-swap certain values before emitting them. + * + * Note that, in order for this to work when building the ELF64 PIE executable + * (for KASLR), these values should not be referenced via R_AARCH64_ABS64 + * relocations, since these are fixed up at runtime rather than at build time + * when PIE is in effect. So we need to split them up in 32-bit high and low + * words. + */ +#ifdef CONFIG_CPU_BIG_ENDIAN +#define DATA_LE32(data) \ + ((((data) & 0x000000ff) << 24) | \ + (((data) & 0x0000ff00) << 8) | \ + (((data) & 0x00ff0000) >> 8) | \ + (((data) & 0xff000000) >> 24)) +#else +#define DATA_LE32(data) ((data) & 0xffffffff) +#endif + +#define DEFINE_IMAGE_LE64(sym, data) \ + sym##_lo32 = DATA_LE32((data) & 0xffffffff); \ + sym##_hi32 = DATA_LE32((data) >> 32) + +#define __MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define __CODE_DATA_SIZE (__bss_start - _start) +#define __BSS_SIZE (__bss_end - __bss_start) +#ifdef CONFIG_SYS_INIT_SP_BSS_OFFSET +#define __MAX_EXTRA_RAM_USAGE __MAX(__BSS_SIZE, CONFIG_SYS_INIT_SP_BSS_OFFSET) +#else +#define __MAX_EXTRA_RAM_USAGE __BSS_SIZE +#endif +#define __MEM_USAGE (__CODE_DATA_SIZE + __MAX_EXTRA_RAM_USAGE) + +#ifdef CONFIG_CPU_BIG_ENDIAN +#define __HEAD_FLAG_BE 1 +#else +#define __HEAD_FLAG_BE 0 +#endif + +#define __HEAD_FLAG_PAGE_SIZE 1 /* 4K hard-coded */ + +#define __HEAD_FLAG_PHYS_BASE 1 + +#define __HEAD_FLAGS ((__HEAD_FLAG_BE << 0) | \ + (__HEAD_FLAG_PAGE_SIZE << 1) | \ + (__HEAD_FLAG_PHYS_BASE << 3)) + +#define TEXT_OFFSET (CONFIG_SYS_TEXT_BASE - \ + CONFIG_LNX_KRNL_IMG_TEXT_OFFSET_BASE) + +/* + * These will output as part of the Image header, which should be little-endian + * regardless of the endianness of the kernel. While constant values could be + * endian swapped in head.S, all are done here for consistency. + */ +#define HEAD_SYMBOLS \ + DEFINE_IMAGE_LE64(_kernel_size_le, __MEM_USAGE); \ + DEFINE_IMAGE_LE64(_kernel_offset_le, TEXT_OFFSET); \ + DEFINE_IMAGE_LE64(_kernel_flags_le, __HEAD_FLAGS); + + HEAD_SYMBOLS diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S index f385ed40e1..7a98a1c95d 100644 --- a/arch/arm/cpu/armv8/start.S +++ b/arch/arm/cpu/armv8/start.S @@ -19,7 +19,9 @@ .globl _start _start: -#ifdef CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK +#if defined(LINUX_KERNEL_IMAGE_HEADER) +#include +#elif defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) /* * Various SoCs need something special and SoC-specific up front in * order to boot, allow them to set that in their boot0.h file and then diff --git a/arch/arm/cpu/armv8/u-boot.lds b/arch/arm/cpu/armv8/u-boot.lds index 22195b8834..7b76e0f9f0 100644 --- a/arch/arm/cpu/armv8/u-boot.lds +++ b/arch/arm/cpu/armv8/u-boot.lds @@ -159,4 +159,8 @@ SECTIONS /DISCARD/ : { *(.plt*) } /DISCARD/ : { *(.interp*) } /DISCARD/ : { *(.gnu*) } + +#ifdef CONFIG_LINUX_KERNEL_IMAGE_HEADER +#include "linux-kernel-image-header-vars.h" +#endif } diff --git a/arch/arm/include/asm/boot0-linux-kernel-header.h b/arch/arm/include/asm/boot0-linux-kernel-header.h new file mode 100644 index 0000000000..ca28780daa --- /dev/null +++ b/arch/arm/include/asm/boot0-linux-kernel-header.h @@ -0,0 +1,49 @@ +/* + * (C) Copyright 2017 NVIDIA Corporation + * + * Derived from Linux kernel v4.14 files: + * + * arch/arm64/include/asm/assembler.h: + * Based on arch/arm/include/asm/assembler.h, arch/arm/mm/proc-macros.S + * Copyright (C) 1996-2000 Russell King + * Copyright (C) 2012 ARM Ltd. + * + * arch/arm64/kernel/head.S: + * Based on arch/arm/kernel/head.S + * Copyright (C) 1994-2002 Russell King + * Copyright (C) 2003-2012 ARM Ltd. + * Authors: Catalin Marinas + * Will Deacon + * + * arch/arm64/kernel/image.h: + * Copyright (C) 2014 ARM Ltd. + * + * SPDX-License-Identifier: GPL-2.0 + */ + + /* + * Emit a 64-bit absolute little endian symbol reference in a way that + * ensures that it will be resolved at build time, even when building a + * PIE binary. This requires cooperation from the linker script, which + * must emit the lo32/hi32 halves individually. + */ + .macro le64sym, sym + .long \sym\()_lo32 + .long \sym\()_hi32 + .endm + +.globl _start +_start: + /* + * DO NOT MODIFY. Image header expected by Linux boot-loaders. + */ + b reset /* branch to kernel start, magic */ + .long 0 /* reserved */ + le64sym _kernel_offset_le /* Image load offset from start of RAM, little-endian */ + le64sym _kernel_size_le /* Effective size of kernel image, little-endian */ + le64sym _kernel_flags_le /* Informative flags, little-endian */ + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .quad 0 /* reserved */ + .ascii "ARM\x64" /* Magic number */ + .long 0 /* reserved */ From ddecaaf3b9919d3b9b90ada858c1f7ff90c5ed7c Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 3 Jan 2018 14:31:52 -0700 Subject: [PATCH 06/14] ARM: tegra: use LINUX_KERNEL_IMAGE_HEADER Enable CONFIG_LINUX_KERNEL_IMAGE_HEADER for all 64-bit Tegra boards. cboot (the boot SW that runs before U-Boot) will eventually use this information. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/mach-tegra/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig index 51d143687b..fd0082d22a 100644 --- a/arch/arm/mach-tegra/Kconfig +++ b/arch/arm/mach-tegra/Kconfig @@ -60,8 +60,14 @@ config TEGRA_ARMV7_COMMON config TEGRA_ARMV8_COMMON bool "Tegra 64-bit common options" select ARM64 + select LINUX_KERNEL_IMAGE_HEADER select TEGRA_COMMON +if TEGRA_ARMV8_COMMON +config LNX_KRNL_IMG_TEXT_OFFSET_BASE + default 0x80000000 +endif + choice prompt "Tegra SoC select" optional From f6974712173d60830b7b8aa86b8ceac5a7cfd0c6 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 3 Jan 2018 14:32:33 -0700 Subject: [PATCH 07/14] ARM: Tegra186: mem parsing fixes from downstream Apply a few small fixes for the DTB /memory node parsing from NVIDIA's downstream U-Boot: - Allow arbitrary number of DRAM banks. - Correctly calculate the number of DRAM banks. - Clip PCIe memory in the same way as U-Boot CPU memory use. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c index 5224ef641c..5a165a9d8e 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c @@ -16,10 +16,10 @@ extern unsigned long nvtboot_boot_x0; /* * A parsed version of /memory/reg from the DTB that is passed to U-Boot in x0. * - * We only support up to two banks since that's all the binary bootloader - * ever sets. We assume bank 0 is RAM below 4G and bank 1 is RAM above 4G. - * This is all a fairly safe assumption, since the L4T kernel makes the same - * assumptions, so the bootloader is unlikely to change. + * We assume bank 0 is RAM completely below 4G mostly ignore other banks; + * assuming they contain RAM above 4G. This is all a fairly safe assumption, + * since the L4T kernel makes the same assumption, so the bootloader is + * unlikely to change. * * This is written to before relocation, and hence cannot be in .bss, since * .bss overlaps the DTB that's appended to the U-Boot binary. The initializer @@ -29,7 +29,7 @@ extern unsigned long nvtboot_boot_x0; static struct { u64 start; u64 size; -} ram_banks[2] = {{1}}; +} ram_banks[CONFIG_NR_DRAM_BANKS] = {{1}}; int dram_init(void) { @@ -54,7 +54,9 @@ int dram_init(void) hang(); } - len /= (na + ns); + /* Calculate the true # of base/size pairs to read */ + len /= 4; /* Convert bytes to number of cells */ + len /= (na + ns); /* Convert cells to number of banks */ if (len > ARRAY_SIZE(ram_banks)) len = ARRAY_SIZE(ram_banks); @@ -76,11 +78,15 @@ int dram_init_banksize(void) { int i; - for (i = 0; i < 2; i++) { + for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { gd->bd->bi_dram[i].start = ram_banks[i].start; gd->bd->bi_dram[i].size = ram_banks[i].size; } +#ifdef CONFIG_PCI + gd->pci_ram_top = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; +#endif + return 0; } From 15751403b6072acabdd7ccad10013cb80b6c6a34 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Fri, 5 Jan 2018 13:04:54 -0700 Subject: [PATCH 08/14] ARM: bootm: don't assume sp is in DRAM bank 0 arch_lmb_reserve() currently assumes that the stack pointer is within DRAM bank 0. This is not necessarily true. Enhance the code to search through DRAM banks until the bank that does contain SP is found, and then reserve the tail of that bank. Fixes: 2d1916e48bd8 ("ARM: add flat device tree support") Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/lib/bootm.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 5c62d9c144..89740657e0 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -47,7 +47,8 @@ static ulong get_sp(void) void arch_lmb_reserve(struct lmb *lmb) { - ulong sp; + ulong sp, bank_end; + int bank; /* * Booting a (Linux) kernel image @@ -63,8 +64,16 @@ void arch_lmb_reserve(struct lmb *lmb) /* adjust sp by 4K to be safe */ sp -= 4096; - lmb_reserve(lmb, sp, - gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size - sp); + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + if (sp < gd->bd->bi_dram[bank].start) + continue; + bank_end = gd->bd->bi_dram[bank].start + + gd->bd->bi_dram[bank].size; + if (sp >= bank_end) + continue; + lmb_reserve(lmb, sp, bank_end - sp); + break; + } } __weak void board_quiesce_devices(void) From d5859255d9799db8f18ac3487ec3ac9427503edb Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 3 Jan 2018 14:32:34 -0700 Subject: [PATCH 09/14] ARM: Tegra186: search for best RAM bank In the future, the list of DRAM regions passed to U-Boot in the DTB may be quite long and fragmented. Due to this, U-Boot must search through the regions to find the best region to relocate into, rather than relying on the current assumption that the top of bank 0 is a reasonable relocation target. This change implements such searching. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 88 +++++++++++++++++----- 1 file changed, 69 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c index 5a165a9d8e..33e331f4ca 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, NVIDIA CORPORATION. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. * * SPDX-License-Identifier: GPL-2.0+ */ @@ -9,27 +9,51 @@ #include #include +#define SZ_4G 0x100000000ULL + +/* + * Size of a region that's large enough to hold the relocated U-Boot and all + * other allocations made around it (stack, heap, page tables, etc.) + * In practice, running "bdinfo" at the shell prompt, the stack reaches about + * 5MB from the address selected for ram_top as of the time of writing, + * so a 16MB region should be plenty. + */ +#define MIN_USABLE_RAM_SIZE SZ_16M +/* + * The amount of space we expect to require for stack usage. Used to validate + * that all reservations fit into the region selected for the relocation target + */ +#define MIN_USABLE_STACK_SIZE SZ_1M + DECLARE_GLOBAL_DATA_PTR; extern unsigned long nvtboot_boot_x0; /* - * A parsed version of /memory/reg from the DTB that is passed to U-Boot in x0. - * - * We assume bank 0 is RAM completely below 4G mostly ignore other banks; - * assuming they contain RAM above 4G. This is all a fairly safe assumption, - * since the L4T kernel makes the same assumption, so the bootloader is - * unlikely to change. - * - * This is written to before relocation, and hence cannot be in .bss, since - * .bss overlaps the DTB that's appended to the U-Boot binary. The initializer - * forces this into .data and avoids this issue. This also has the nice side- - * effect of the content being valid after relocation. + * These variables are written to before relocation, and hence cannot be + * in.bss, since .bss overlaps the DTB that's appended to the U-Boot binary. + * The section attribute forces this into .data and avoids this issue. This + * also has the nice side-effect of the content being valid after relocation. */ + +/* A parsed version of /memory/reg from the DTB passed to U-Boot in x0 */ static struct { u64 start; u64 size; -} ram_banks[CONFIG_NR_DRAM_BANKS] = {{1}}; +} ram_banks[CONFIG_NR_DRAM_BANKS] __attribute__((section(".data"))); + +/* The number of valid entries in ram_banks[] */ +static int ram_bank_count __attribute__((section(".data"))); + +/* + * The usable top-of-RAM for U-Boot. This is both: + * a) Below 4GB to avoid issues with peripherals that use 32-bit addressing. + * b) At the end of a region that has enough space to hold the relocated U-Boot + * and all other allocations made around it (stack, heap, page tables, etc.) + */ +static u64 ram_top __attribute__((section(".data"))); +/* The base address of the region of RAM that ends at ram_top */ +static u64 region_base __attribute__((section(".data"))); int dram_init(void) { @@ -59,32 +83,58 @@ int dram_init(void) len /= (na + ns); /* Convert cells to number of banks */ if (len > ARRAY_SIZE(ram_banks)) len = ARRAY_SIZE(ram_banks); + ram_bank_count = len; gd->ram_size = 0; - for (i = 0; i < len; i++) { + for (i = 0; i < ram_bank_count; i++) { + u64 bank_end, usable_bank_size; + ram_banks[i].start = fdt_read_number(prop, na); prop += na; ram_banks[i].size = fdt_read_number(prop, ns); prop += ns; gd->ram_size += ram_banks[i].size; + debug("Bank %d: start: %llx size: %llx\n", i, + ram_banks[i].start, ram_banks[i].size); + + bank_end = ram_banks[i].start + ram_banks[i].size; + debug(" end %llx\n", bank_end); + if (bank_end > SZ_4G) + bank_end = SZ_4G; + debug(" end %llx (usable)\n", bank_end); + usable_bank_size = bank_end - ram_banks[i].start; + debug(" size %llx (usable)\n", usable_bank_size); + if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && + (bank_end > ram_top)) { + ram_top = bank_end; + region_base = ram_banks[i].start; + debug("ram top now %llx\n", ram_top); + } + } + if (!ram_top) { + pr_err("Can't find a usable RAM top"); + hang(); } return 0; } -extern unsigned long nvtboot_boot_x0; - int dram_init_banksize(void) { int i; - for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) { + if ((gd->start_addr_sp - region_base) < MIN_USABLE_STACK_SIZE) { + pr_err("Reservations exceed chosen region size"); + hang(); + } + + for (i = 0; i < ram_bank_count; i++) { gd->bd->bi_dram[i].start = ram_banks[i].start; gd->bd->bi_dram[i].size = ram_banks[i].size; } #ifdef CONFIG_PCI - gd->pci_ram_top = gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; + gd->pci_ram_top = ram_top; #endif return 0; @@ -92,5 +142,5 @@ int dram_init_banksize(void) ulong board_get_usable_ram_top(ulong total_size) { - return ram_banks[0].start + ram_banks[0].size; + return ram_top; } From a9819b9e33bd9e8e2bdb694abef78397d8c00e7f Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Wed, 3 Jan 2018 14:32:35 -0700 Subject: [PATCH 10/14] ARM: tegra: p2771-000: increase max DRAM bank count On this platform, there may be up to 1024 unusable chunks of memory. Increase CONFIG_NR_DRAM_BANKS so that U-Boot can remember all the banks required to represent such fragmented memory. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren --- include/configs/p2771-0000.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/configs/p2771-0000.h b/include/configs/p2771-0000.h index 564069a665..5de7ae8c50 100644 --- a/include/configs/p2771-0000.h +++ b/include/configs/p2771-0000.h @@ -29,4 +29,7 @@ /* Crystal is 38.4MHz. clk_m runs at half that rate */ #define COUNTER_FREQUENCY 19200000 +#undef CONFIG_NR_DRAM_BANKS +#define CONFIG_NR_DRAM_BANKS (1024 + 2) + #endif From cdcf55584e7e6b9be92a258d70d4d08a0216dbd0 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Thu, 4 Jan 2018 11:07:14 -0700 Subject: [PATCH 11/14] ARM: Tegra186: don't map memory not in RAM banks Tegra186 currently restricts its DRAM usage to entries in the /memory node in the DTB passed to it. However, the MMU configuration always maps the entire first 2GB of RAM. This could allow the CPU to speculatively access RAM that isn't part of the in-use banks. This patch switches to runtime construction of the table that's used to construct the MMU translation tables, and thus prevents access to RAM that's not part of a valid bank. Note: This patch is intended to prevent access to RAM regions which U-Boot does not need to access, with the primary purpose of avoiding theoretical speculative access to physical regions for which the HW will throw errors (e.g. carve-outs that the CPU has no permission to access at a bus level, bad ECC pages, etc.). In particular, this patch is not deliberately related to the speculation-related security issues that were recently announced. The apparent similarity is a coincidence. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/mach-tegra/arm64-mmu.c | 3 +- arch/arm/mach-tegra/tegra186/nvtboot_mem.c | 76 +++++++++++++++------- 2 files changed, 54 insertions(+), 25 deletions(-) diff --git a/arch/arm/mach-tegra/arm64-mmu.c b/arch/arm/mach-tegra/arm64-mmu.c index a79a5192e0..3a126bdec4 100644 --- a/arch/arm/mach-tegra/arm64-mmu.c +++ b/arch/arm/mach-tegra/arm64-mmu.c @@ -12,7 +12,8 @@ #include #include -static struct mm_region tegra_mem_map[] = { +/* size: IO + NR_DRAM_BANKS + terminator */ +struct mm_region tegra_mem_map[1 + CONFIG_NR_DRAM_BANKS + 1] = { { .virt = 0x0UL, .phys = 0x0UL, diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c index 33e331f4ca..2ca59747d4 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_mem.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_mem.c @@ -8,6 +8,7 @@ #include #include #include +#include #define SZ_4G 0x100000000ULL @@ -28,6 +29,7 @@ DECLARE_GLOBAL_DATA_PTR; extern unsigned long nvtboot_boot_x0; +extern struct mm_region tegra_mem_map[]; /* * These variables are written to before relocation, and hence cannot be @@ -36,12 +38,6 @@ extern unsigned long nvtboot_boot_x0; * also has the nice side-effect of the content being valid after relocation. */ -/* A parsed version of /memory/reg from the DTB passed to U-Boot in x0 */ -static struct { - u64 start; - u64 size; -} ram_banks[CONFIG_NR_DRAM_BANKS] __attribute__((section(".data"))); - /* The number of valid entries in ram_banks[] */ static int ram_bank_count __attribute__((section(".data"))); @@ -62,8 +58,6 @@ int dram_init(void) int node, len, i; const u32 *prop; - memset(ram_banks, 0, sizeof(ram_banks)); - na = fdtdec_get_uint(nvtboot_blob, 0, "#address-cells", 2); ns = fdtdec_get_uint(nvtboot_blob, 0, "#size-cells", 2); @@ -81,36 +75,70 @@ int dram_init(void) /* Calculate the true # of base/size pairs to read */ len /= 4; /* Convert bytes to number of cells */ len /= (na + ns); /* Convert cells to number of banks */ - if (len > ARRAY_SIZE(ram_banks)) - len = ARRAY_SIZE(ram_banks); - ram_bank_count = len; + if (len > CONFIG_NR_DRAM_BANKS) + len = CONFIG_NR_DRAM_BANKS; + /* Parse the /memory node, and save useful entries */ gd->ram_size = 0; - for (i = 0; i < ram_bank_count; i++) { - u64 bank_end, usable_bank_size; + ram_bank_count = 0; + for (i = 0; i < len; i++) { + u64 bank_start, bank_end, bank_size, usable_bank_size; - ram_banks[i].start = fdt_read_number(prop, na); + /* Extract raw memory region data from DTB */ + bank_start = fdt_read_number(prop, na); prop += na; - ram_banks[i].size = fdt_read_number(prop, ns); + bank_size = fdt_read_number(prop, ns); prop += ns; - gd->ram_size += ram_banks[i].size; - debug("Bank %d: start: %llx size: %llx\n", i, - ram_banks[i].start, ram_banks[i].size); + gd->ram_size += bank_size; + bank_end = bank_start + bank_size; + debug("Bank %d: %llx..%llx (+%llx)\n", i, + bank_start, bank_end, bank_size); - bank_end = ram_banks[i].start + ram_banks[i].size; - debug(" end %llx\n", bank_end); + /* + * Align the bank to MMU section size. This is not strictly + * necessary, since the translation table construction code + * handles page granularity without issue. However, aligning + * the MMU entries reduces the size and number of levels in the + * page table, so is worth it. + */ + bank_start = ROUND(bank_start, SZ_2M); + bank_end = bank_end & ~(SZ_2M - 1); + bank_size = bank_end - bank_start; + debug(" aligned: %llx..%llx (+%llx)\n", + bank_start, bank_end, bank_size); + if (bank_end <= bank_start) + continue; + + /* Record data used to create MMU translation tables */ + ram_bank_count++; + /* Index below is deliberately 1-based to skip MMIO entry */ + tegra_mem_map[ram_bank_count].virt = bank_start; + tegra_mem_map[ram_bank_count].phys = bank_start; + tegra_mem_map[ram_bank_count].size = bank_size; + tegra_mem_map[ram_bank_count].attrs = + PTE_BLOCK_MEMTYPE(MT_NORMAL) | PTE_BLOCK_INNER_SHARE; + + /* Determine best bank to relocate U-Boot into */ if (bank_end > SZ_4G) bank_end = SZ_4G; debug(" end %llx (usable)\n", bank_end); - usable_bank_size = bank_end - ram_banks[i].start; + usable_bank_size = bank_end - bank_start; debug(" size %llx (usable)\n", usable_bank_size); if ((usable_bank_size >= MIN_USABLE_RAM_SIZE) && (bank_end > ram_top)) { ram_top = bank_end; - region_base = ram_banks[i].start; + region_base = bank_start; debug("ram top now %llx\n", ram_top); } } + + /* Ensure memory map contains the desired sentinel entry */ + tegra_mem_map[ram_bank_count + 1].virt = 0; + tegra_mem_map[ram_bank_count + 1].phys = 0; + tegra_mem_map[ram_bank_count + 1].size = 0; + tegra_mem_map[ram_bank_count + 1].attrs = 0; + + /* Error out if a relocation target couldn't be found */ if (!ram_top) { pr_err("Can't find a usable RAM top"); hang(); @@ -129,8 +157,8 @@ int dram_init_banksize(void) } for (i = 0; i < ram_bank_count; i++) { - gd->bd->bi_dram[i].start = ram_banks[i].start; - gd->bd->bi_dram[i].size = ram_banks[i].size; + gd->bd->bi_dram[i].start = tegra_mem_map[1 + i].virt; + gd->bd->bi_dram[i].size = tegra_mem_map[1 + i].size; } #ifdef CONFIG_PCI From 026a8b96bd981e306157bbc095f90acd794a3d88 Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 8 Jan 2018 17:41:24 -0700 Subject: [PATCH 12/14] ARM: Tegra186: calculate load addresses at boot In the presence of potentially fragemented memory, we cannot hard-code addresses into environment variables such as kernel_addr_r. Instead, we must calculate those addresses at run-time based on available memory locations. Implement the code to perform such runtime calculation, based on requirements described in environment variables, to allow the user full control over the allocation. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- arch/arm/mach-tegra/tegra186/nvtboot_board.c | 265 ++++++++++++++++++- 1 file changed, 264 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-tegra/tegra186/nvtboot_board.c b/arch/arm/mach-tegra/tegra186/nvtboot_board.c index b94eb424aa..8ecb454443 100644 --- a/arch/arm/mach-tegra/tegra186/nvtboot_board.c +++ b/arch/arm/mach-tegra/tegra186/nvtboot_board.c @@ -1,16 +1,278 @@ /* - * Copyright (c) 2016, NVIDIA CORPORATION. + * Copyright (c) 2016-2018, NVIDIA CORPORATION. * * SPDX-License-Identifier: GPL-2.0+ */ +#include #include #include #include #include +#include + +DECLARE_GLOBAL_DATA_PTR; extern unsigned long nvtboot_boot_x0; +/* + * The following few functions run late during the boot process and dynamically + * calculate the load address of various binaries. To keep track of multiple + * allocations, some writable list of RAM banks must be used. tegra_mem_map[] + * is used for this purpose to avoid making yet another copy of the list of RAM + * banks. This is safe because tegra_mem_map[] is only used once during very + * early boot to create U-Boot's page tables, long before this code runs. If + * this assumption becomes invalid later, we can just fix the code to copy the + * list of RAM banks into some private data structure before running. + */ + +extern struct mm_region tegra_mem_map[]; + +static char *gen_varname(const char *var, const char *ext) +{ + size_t len_var = strlen(var); + size_t len_ext = strlen(ext); + size_t len = len_var + len_ext + 1; + char *varext = malloc(len); + + if (!varext) + return 0; + strcpy(varext, var); + strcpy(varext + len_var, ext); + return varext; +} + +static void mark_ram_allocated(int bank, u64 allocated_start, u64 allocated_end) +{ + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + bool keep_front = allocated_start != bank_start; + bool keep_tail = allocated_end != bank_end; + + if (keep_front && keep_tail) { + /* + * There are CONFIG_NR_DRAM_BANKS DRAM entries in the array, + * starting at index 1 (index 0 is MMIO). So, we are at DRAM + * entry "bank" not "bank - 1" as for a typical 0-base array. + * The number of remaining DRAM entries is therefore + * "CONFIG_NR_DRAM_BANKS - bank". We want to duplicate the + * current entry and shift up the remaining entries, dropping + * the last one. Thus, we must copy one fewer entry than the + * number remaining. + */ + memmove(&tegra_mem_map[bank + 1], &tegra_mem_map[bank], + CONFIG_NR_DRAM_BANKS - bank - 1); + tegra_mem_map[bank].size = allocated_start - bank_start; + bank++; + tegra_mem_map[bank].virt = allocated_end; + tegra_mem_map[bank].phys = allocated_end; + tegra_mem_map[bank].size = bank_end - allocated_end; + } else if (keep_front) { + tegra_mem_map[bank].size = allocated_start - bank_start; + } else if (keep_tail) { + tegra_mem_map[bank].virt = allocated_end; + tegra_mem_map[bank].phys = allocated_end; + tegra_mem_map[bank].size = bank_end - allocated_end; + } else { + /* + * We could move all subsequent banks down in the array but + * that's not necessary for subsequent allocations to work, so + * we skip doing so. + */ + tegra_mem_map[bank].size = 0; + } +} + +static void reserve_ram(u64 start, u64 size) +{ + int bank; + u64 end = start + size; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + + if (end <= bank_start || start > bank_end) + continue; + mark_ram_allocated(bank, start, end); + break; + } +} + +static u64 alloc_ram(u64 size, u64 align, u64 offset) +{ + int bank; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + u64 allocated = ROUND(bank_start, align) + offset; + u64 allocated_end = allocated + size; + + if (allocated_end > bank_end) + continue; + mark_ram_allocated(bank, allocated, allocated_end); + return allocated; + } + return 0; +} + +static void set_calculated_aliases(char *aliases, u64 address) +{ + char *tmp, *alias; + int err; + + aliases = strdup(aliases); + if (!aliases) { + pr_err("strdup(aliases) failed"); + return; + } + + tmp = aliases; + while (true) { + alias = strsep(&tmp, " "); + if (!alias) + break; + debug("%s: alias: %s\n", __func__, alias); + err = env_set_hex(alias, address); + if (err) + pr_err("Could not set %s\n", alias); + } + + free(aliases); +} + +static void set_calculated_env_var(const char *var) +{ + char *var_size; + char *var_align; + char *var_offset; + char *var_aliases; + u64 size; + u64 align; + u64 offset; + char *aliases; + u64 address; + int err; + + var_size = gen_varname(var, "_size"); + if (!var_size) + return; + var_align = gen_varname(var, "_align"); + if (!var_align) + goto out_free_var_size; + var_offset = gen_varname(var, "_offset"); + if (!var_offset) + goto out_free_var_align; + var_aliases = gen_varname(var, "_aliases"); + if (!var_aliases) + goto out_free_var_offset; + + size = env_get_hex(var_size, 0); + if (!size) { + pr_err("%s not set or zero\n", var_size); + goto out_free_var_aliases; + } + align = env_get_hex(var_align, 1); + /* Handle extant variables, but with a value of 0 */ + if (!align) + align = 1; + offset = env_get_hex(var_offset, 0); + aliases = env_get(var_aliases); + + debug("%s: Calc var %s; size=%llx, align=%llx, offset=%llx\n", + __func__, var, size, align, offset); + if (aliases) + debug("%s: Aliases: %s\n", __func__, aliases); + + address = alloc_ram(size, align, offset); + if (!address) { + pr_err("Could not allocate %s\n", var); + goto out_free_var_aliases; + } + debug("%s: Address %llx\n", __func__, address); + + err = env_set_hex(var, address); + if (err) + pr_err("Could not set %s\n", var); + if (aliases) + set_calculated_aliases(aliases, address); + +out_free_var_aliases: + free(var_aliases); +out_free_var_offset: + free(var_offset); +out_free_var_align: + free(var_align); +out_free_var_size: + free(var_size); +} + +#ifdef DEBUG +static void dump_ram_banks(void) +{ + int bank; + + for (bank = 1; bank <= CONFIG_NR_DRAM_BANKS; bank++) { + u64 bank_start = tegra_mem_map[bank].virt; + u64 bank_size = tegra_mem_map[bank].size; + u64 bank_end = bank_start + bank_size; + + if (!bank_size) + continue; + printf("%d: %010llx..%010llx (+%010llx)\n", bank - 1, + bank_start, bank_end, bank_size); + } +} +#endif + +static void set_calculated_env_vars(void) +{ + char *vars, *tmp, *var; + +#ifdef DEBUG + printf("RAM banks before any calculated env. var.s:\n"); + dump_ram_banks(); +#endif + + reserve_ram(nvtboot_boot_x0, fdt_totalsize(nvtboot_boot_x0)); + +#ifdef DEBUG + printf("RAM after reserving cboot DTB:\n"); + dump_ram_banks(); +#endif + + vars = env_get("calculated_vars"); + if (!vars) { + debug("%s: No env var calculated_vars\n", __func__); + return; + } + + vars = strdup(vars); + if (!vars) { + pr_err("strdup(calculated_vars) failed"); + return; + } + + tmp = vars; + while (true) { + var = strsep(&tmp, " "); + if (!var) + break; + debug("%s: var: %s\n", __func__, var); + set_calculated_env_var(var); +#ifdef DEBUG + printf("RAM banks affter allocating %s:\n", var); + dump_ram_banks(); +#endif + } + + free(vars); +} + static int set_fdt_addr(void) { int ret; @@ -60,6 +322,7 @@ static int set_ethaddr_from_nvtboot(void) int tegra_soc_board_init_late(void) { + set_calculated_env_vars(); /* * Ignore errors here; the value may not be used depending on * extlinux.conf or boot script content. From e43effc1d8cb82ed376649ad7d70e9ac0209c18b Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 8 Jan 2018 17:41:25 -0700 Subject: [PATCH 13/14] ARM: Tegra: p2771-0000: use calculate env var feature Request that all environment variables containing hard-coded address be calculated at boot time instead. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- include/configs/p2771-0000.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/include/configs/p2771-0000.h b/include/configs/p2771-0000.h index 5de7ae8c50..29940a63de 100644 --- a/include/configs/p2771-0000.h +++ b/include/configs/p2771-0000.h @@ -24,6 +24,26 @@ /* PCI host support */ +#define BOARD_EXTRA_ENV_SETTINGS \ + "calculated_vars=kernel_addr_r fdt_addr_r scriptaddr pxefile_addr_r " \ + "ramdisk_addr_r\0" \ + "kernel_addr_r_align=00200000\0" \ + "kernel_addr_r_offset=00080000\0" \ + "kernel_addr_r_size=02000000\0" \ + "kernel_addr_r_aliases=loadaddr\0" \ + "fdt_addr_r_align=00200000\0" \ + "fdt_addr_r_offset=00000000\0" \ + "fdt_addr_r_size=00200000\0" \ + "scriptaddr_align=00200000\0" \ + "scriptaddr_offset=00000000\0" \ + "scriptaddr_size=00200000\0" \ + "pxefile_addr_r_align=00200000\0" \ + "pxefile_addr_r_offset=00000000\0" \ + "pxefile_addr_r_size=00200000\0" \ + "ramdisk_addr_r_align=00200000\0" \ + "ramdisk_addr_r_offset=00000000\0" \ + "ramdisk_addr_r_size=02000000\0" + #include "tegra-common-post.h" /* Crystal is 38.4MHz. clk_m runs at half that rate */ From 5fed97af20da955625cc06563a725b49cebb99eb Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Tue, 9 Jan 2018 12:52:14 -0700 Subject: [PATCH 14/14] Makefile: ensure DTB doesn't overflow into initial stack With CONFIG_SYS_INIT_SP_BSS_OFFSET enabled, the initial (pre-relocation) stack is placed some distance after bss_start. The control DTB is appended to the U-Boot binary at bss_start. If the DTB is too large, or the SP BSS offset too small, then the initial stack could corrupt the DTB. Enhance the Makefile to check whether this is likely to occur. Signed-off-by: Stephen Warren Signed-off-by: Tom Warren --- Makefile | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Makefile b/Makefile index d8f419bcd9..52cd6ea721 100644 --- a/Makefile +++ b/Makefile @@ -811,6 +811,10 @@ ifneq ($(CONFIG_BUILD_TARGET),) ALL-y += $(CONFIG_BUILD_TARGET:"%"=%) endif +ifneq ($(CONFIG_SYS_INIT_SP_BSS_OFFSET),) +ALL-y += init_sp_bss_offset_check +endif + LDFLAGS_u-boot += $(LDFLAGS_FINAL) # Avoid 'Not enough room for program headers' error on binutils 2.28 onwards. @@ -939,6 +943,33 @@ binary_size_check: u-boot-nodtb.bin FORCE fi \ fi +ifneq ($(CONFIG_SYS_INIT_SP_BSS_OFFSET),) +ifneq ($(CONFIG_SYS_MALLOC_F_LEN),) +subtract_sys_malloc_f_len = space=$$(($${space} - $(CONFIG_SYS_MALLOC_F_LEN))) +else +subtract_sys_malloc_f_len = true +endif +# The 1/4 margin below is somewhat arbitrary. The likely initial SP usage is +# so low that the DTB could probably use 90%+ of the available space, for +# current values of CONFIG_SYS_INIT_SP_BSS_OFFSET at least. However, let's be +# safe for now and tweak this later if space becomes tight. +# A rejected alternative would be to check that some absolute minimum stack +# space was available. However, since CONFIG_SYS_INIT_SP_BSS_OFFSET is +# deliberately build-specific, to take account of build-to-build stack usage +# differences due to different feature sets, there is no common absolute value +# to check against. +init_sp_bss_offset_check: u-boot.dtb FORCE + @dtb_size=$(shell wc -c u-boot.dtb | awk '{print $$1}') ; \ + space=$(CONFIG_SYS_INIT_SP_BSS_OFFSET) ; \ + $(subtract_sys_malloc_f_len) ; \ + quarter_space=$$(($${space} / 4)) ; \ + if [ $${dtb_size} -gt $${quarter_space} ]; then \ + echo "u-boot.dtb is larger than 1 quarter of " >&2 ; \ + echo "(CONFIG_SYS_INIT_SP_BSS_OFFSET - CONFIG_SYS_MALLOC_F_LEN)" >&2 ; \ + exit 1 ; \ + fi +endif + u-boot-nodtb.bin: u-boot FORCE $(call if_changed,objcopy) $(call DO_STATIC_RELA,$<,$@,$(CONFIG_SYS_TEXT_BASE))