diff options
136 files changed, 4432 insertions, 632 deletions
@@ -903,6 +903,12 @@ u-boot.ldr: u-boot $(LDR) -T $(CONFIG_CPU) -c $@ $< $(LDR_FLAGS) $(BOARD_SIZE_CHECK) +# binman +# --------------------------------------------------------------------------- +quiet_cmd_binman = BINMAN $@ +cmd_binman = $(srctree)/tools/binman/binman -d u-boot.dtb -O . \ + -I . -I $(srctree)/board/$(BOARDDIR) $< + OBJCOPYFLAGS_u-boot.ldr.hex := -I binary -O ihex OBJCOPYFLAGS_u-boot.ldr.srec := -I binary -O srec @@ -1047,50 +1053,11 @@ endif # x86 uses a large ROM. We fill it with 0xff, put the 16-bit stuff (including # reset vector) at the top, Intel ME descriptor at the bottom, and U-Boot in -# the middle. +# the middle. This is handled by binman based on an image description in the +# board's device tree. ifneq ($(CONFIG_X86_RESET_VECTOR),) rom: u-boot.rom FORCE -IFDTOOL=$(objtree)/tools/ifdtool -IFDTOOL_FLAGS = -f 0:$(objtree)/u-boot.dtb -IFDTOOL_FLAGS += -m 0x$(shell $(NM) u-boot |grep _dt_ucode_base_size |cut -d' ' -f1) -IFDTOOL_FLAGS += -U $(CONFIG_SYS_TEXT_BASE):$(objtree)/u-boot-nodtb.bin -IFDTOOL_FLAGS += -w $(CONFIG_SYS_X86_START16):$(objtree)/u-boot-x86-16bit.bin -IFDTOOL_FLAGS += -C - -ifneq ($(CONFIG_HAVE_INTEL_ME),) -IFDTOOL_ME_FLAGS = -D $(srctree)/board/$(BOARDDIR)/descriptor.bin -IFDTOOL_ME_FLAGS += -i ME:$(srctree)/board/$(BOARDDIR)/me.bin -endif - -ifneq ($(CONFIG_HAVE_MRC),) -IFDTOOL_FLAGS += -w $(CONFIG_X86_MRC_ADDR):$(srctree)/board/$(BOARDDIR)/mrc.bin -endif - -ifneq ($(CONFIG_HAVE_FSP),) -IFDTOOL_FLAGS += -w $(CONFIG_FSP_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_FSP_FILE) -endif - -ifneq ($(CONFIG_HAVE_CMC),) -IFDTOOL_FLAGS += -w $(CONFIG_CMC_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_CMC_FILE) -endif - -ifneq ($(CONFIG_HAVE_VGA_BIOS),) -IFDTOOL_FLAGS += -w $(CONFIG_VGA_BIOS_ADDR):$(srctree)/board/$(BOARDDIR)/$(CONFIG_VGA_BIOS_FILE) -endif - -ifneq ($(CONFIG_HAVE_REFCODE),) -IFDTOOL_FLAGS += -w $(CONFIG_X86_REFCODE_ADDR):refcode.bin -endif - -quiet_cmd_ifdtool = IFDTOOL $@ -cmd_ifdtool = $(IFDTOOL) -c -r $(CONFIG_ROM_SIZE) u-boot.tmp; -ifneq ($(CONFIG_HAVE_INTEL_ME),) -cmd_ifdtool += $(IFDTOOL) $(IFDTOOL_ME_FLAGS) u-boot.tmp; -endif -cmd_ifdtool += $(IFDTOOL) $(IFDTOOL_FLAGS) u-boot.tmp; -cmd_ifdtool += mv u-boot.tmp $@ - refcode.bin: $(srctree)/board/$(BOARDDIR)/refcode.bin FORCE $(call if_changed,copy) @@ -1100,7 +1067,7 @@ cmd_ldr = $(LD) $(LDFLAGS_$(@F)) \ u-boot.rom: u-boot-x86-16bit.bin u-boot.bin FORCE \ $(if $(CONFIG_HAVE_REFCODE),refcode.bin) - $(call if_changed,ifdtool) + $(call if_changed,binman) OBJCOPYFLAGS_u-boot-x86-16bit.bin := -O binary -j .start16 -j .resetvec u-boot-x86-16bit.bin: u-boot FORCE @@ -1108,10 +1075,8 @@ u-boot-x86-16bit.bin: u-boot FORCE endif ifneq ($(CONFIG_ARCH_SUNXI),) -OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \ - --pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff -u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE - $(call if_changed,pad_cat) +u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE + $(call if_changed,binman) endif ifneq ($(CONFIG_TEGRA),) diff --git a/arch/arm/cpu/armv8/zynqmp/Kconfig b/arch/arm/cpu/armv8/zynqmp/Kconfig index f354aae..e175e6e 100644 --- a/arch/arm/cpu/armv8/zynqmp/Kconfig +++ b/arch/arm/cpu/armv8/zynqmp/Kconfig @@ -43,6 +43,7 @@ config SYS_CONFIG_NAME config BOOT_INIT_FILE string "boot.bin init register filename" + depends on SPL default "" help Add register writes to boot.bin format (max 256 pairs). diff --git a/arch/arm/dts/s5pc1xx-goni.dts b/arch/arm/dts/s5pc1xx-goni.dts index 7bbfe59..e80132d 100644 --- a/arch/arm/dts/s5pc1xx-goni.dts +++ b/arch/arm/dts/s5pc1xx-goni.dts @@ -19,6 +19,7 @@ serial2 = "/serial@e2900800"; console = "/serial@e2900800"; pinctrl0 = &pinctrl0; + i2c3 = &i2c_pmic; }; pinctrl0: pinctrl@e0200000 { @@ -32,4 +33,168 @@ id = <2>; }; + i2c_pmic: i2c-pmic { + compatible = "i2c-gpio"; + gpios = <&gpj4 0 0>, /* sda */ + <&gpj4 3 0>; /* scl */ + i2c-gpio,delay-us = <2>; /* ~100 kHz */ + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + pmic@66 { + compatible = "maxim,max8998"; + reg = <0x66 0 0>; + + voltage-regulators { + ldo2_reg: LDO2 { + regulator-compatible = "LDO2"; + regulator-name = "VALIVE_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo3_reg: LDO3 { + regulator-compatible = "LDO3"; + regulator-name = "VUSB+MIPI_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-always-on; + }; + + ldo4_reg: LDO4 { + regulator-compatible = "LDO4"; + regulator-name = "VADC_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo5_reg: LDO5 { + regulator-compatible = "LDO5"; + regulator-name = "VTF_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo6_reg: LDO6 { + regulator-compatible = "LDO6"; + regulator-name = "VCC_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo7_reg: LDO7 { + regulator-compatible = "LDO7"; + regulator-name = "VLCD_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + ldo8_reg: LDO8 { + regulator-compatible = "LDO8"; + regulator-name = "VUSB+VDAC_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo9_reg: LDO9 { + regulator-compatible = "LDO9"; + regulator-name = "VCC+VCAM_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo10_reg: LDO10 { + regulator-compatible = "LDO10"; + regulator-name = "VPLL_1.1V"; + regulator-min-microvolt = <1100000>; + regulator-max-microvolt = <1100000>; + regulator-boot-on; + }; + + ldo11_reg: LDO11 { + regulator-compatible = "LDO11"; + regulator-name = "CAM_IO_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo12_reg: LDO12 { + regulator-compatible = "LDO12"; + regulator-name = "CAM_ISP_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + ldo13_reg: LDO13 { + regulator-compatible = "LDO13"; + regulator-name = "CAM_A_2.8V"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + }; + + ldo14_reg: LDO14 { + regulator-compatible = "LDO14"; + regulator-name = "CAM_CIF_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo15_reg: LDO15 { + regulator-compatible = "LDO15"; + regulator-name = "CAM_AF_3.3V"; + regulator-min-microvolt = <3300000>; + regulator-max-microvolt = <3300000>; + }; + + ldo16_reg: LDO16 { + regulator-compatible = "LDO16"; + regulator-name = "VMIPI_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + }; + + ldo17_reg: LDO17 { + regulator-compatible = "LDO17"; + regulator-name = "CAM_8M_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-compatible = "BUCK1"; + regulator-name = "VARM_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + buck2_reg: BUCK2 { + regulator-compatible = "BUCK2"; + regulator-name = "VINT_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + }; + + buck3_reg: BUCK3 { + regulator-compatible = "BUCK3"; + regulator-name = "VCC_1.8V"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-always-on; + }; + + buck4_reg: BUCK4 { + regulator-compatible = "BUCK4"; + regulator-name = "CAM_CORE_1.2V"; + regulator-min-microvolt = <1200000>; + regulator-max-microvolt = <1200000>; + regulator-always-on; + }; + }; + }; + }; + }; diff --git a/arch/arm/dts/sunxi-u-boot.dtsi b/arch/arm/dts/sunxi-u-boot.dtsi new file mode 100644 index 0000000..5adfd9b --- /dev/null +++ b/arch/arm/dts/sunxi-u-boot.dtsi @@ -0,0 +1,14 @@ +#include <config.h> + +/ { + binman { + filename = "u-boot-sunxi-with-spl.bin"; + pad-byte = <0xff>; + blob { + filename = "spl/sunxi-spl.bin"; + }; + u-boot-img { + pos = <CONFIG_SPL_PAD_TO>; + }; + }; +}; diff --git a/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi b/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi new file mode 100644 index 0000000..fff1d78 --- /dev/null +++ b/arch/arm/dts/tegra124-nyan-big-u-boot.dtsi @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/ { + host1x@50000000 { + u-boot,dm-pre-reloc; + dc@54200000 { + u-boot,dm-pre-reloc; + }; + }; +}; diff --git a/arch/arm/dts/tegra124-nyan-big.dts b/arch/arm/dts/tegra124-nyan-big.dts index 3758395..62f89d0 100644 --- a/arch/arm/dts/tegra124-nyan-big.dts +++ b/arch/arm/dts/tegra124-nyan-big.dts @@ -27,9 +27,7 @@ }; host1x@50000000 { - u-boot,dm-pre-reloc; dc@54200000 { - u-boot,dm-pre-reloc; display-timings { timing@0 { clock-frequency = <69500000>; diff --git a/arch/arm/dts/tegra20-u-boot.dtsi b/arch/arm/dts/tegra20-u-boot.dtsi new file mode 100644 index 0000000..9b9835d --- /dev/null +++ b/arch/arm/dts/tegra20-u-boot.dtsi @@ -0,0 +1,8 @@ +/ { + host1x@50000000 { + u-boot,dm-pre-reloc; + dc@54200000 { + u-boot,dm-pre-reloc; + }; + }; +}; diff --git a/arch/arm/dts/tegra20.dtsi b/arch/arm/dts/tegra20.dtsi index 84bb1b0..e21ee25 100644 --- a/arch/arm/dts/tegra20.dtsi +++ b/arch/arm/dts/tegra20.dtsi @@ -10,7 +10,6 @@ interrupt-parent = <&lic>; host1x@50000000 { - u-boot,dm-pre-reloc; compatible = "nvidia,tegra20-host1x", "simple-bus"; reg = <0x50000000 0x00024000>; interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>, /* syncpt */ @@ -78,7 +77,6 @@ }; dc@54200000 { - u-boot,dm-pre-reloc; compatible = "nvidia,tegra20-dc"; reg = <0x54200000 0x00040000>; interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>; diff --git a/arch/arm/dts/zynq-7000.dtsi b/arch/arm/dts/zynq-7000.dtsi index 6df0329..668f54e 100644 --- a/arch/arm/dts/zynq-7000.dtsi +++ b/arch/arm/dts/zynq-7000.dtsi @@ -16,7 +16,7 @@ #address-cells = <1>; #size-cells = <0>; - cpu@0 { + cpu0: cpu@0 { compatible = "arm,cortex-a9"; device_type = "cpu"; reg = <0>; @@ -30,7 +30,7 @@ >; }; - cpu@1 { + cpu1: cpu@1 { compatible = "arm,cortex-a9"; device_type = "cpu"; reg = <1>; diff --git a/arch/arm/dts/zynqmp.dtsi b/arch/arm/dts/zynqmp.dtsi index ab5c243..de1f160 100644 --- a/arch/arm/dts/zynqmp.dtsi +++ b/arch/arm/dts/zynqmp.dtsi @@ -7,6 +7,7 @@ * * SPDX-License-Identifier: GPL-2.0+ */ + / { compatible = "xlnx,zynqmp"; #address-cells = <2>; diff --git a/arch/arm/include/asm/arch-zynqmp/hardware.h b/arch/arm/include/asm/arch-zynqmp/hardware.h index 5908c50..041b43c 100644 --- a/arch/arm/include/asm/arch-zynqmp/hardware.h +++ b/arch/arm/include/asm/arch-zynqmp/hardware.h @@ -18,8 +18,6 @@ #define ARASAN_NAND_BASEADDR 0xFF100000 -#define ZYNQMP_SATA_BASEADDR 0xFD0C0000 - #define ZYNQMP_USB0_XHCI_BASEADDR 0xFE200000 #define ZYNQMP_USB1_XHCI_BASEADDR 0xFE300000 diff --git a/arch/arm/mach-mvebu/armada8k/cpu.c b/arch/arm/mach-mvebu/armada8k/cpu.c index 2719d68..2325e9a 100644 --- a/arch/arm/mach-mvebu/armada8k/cpu.c +++ b/arch/arm/mach-mvebu/armada8k/cpu.c @@ -21,7 +21,33 @@ DECLARE_GLOBAL_DATA_PTR; #define RFU_GLOBAL_SW_RST (MVEBU_RFU_BASE + 0x84) #define RFU_SW_RESET_OFFSET 0 +/* + * The following table includes all memory regions for Armada 7k and + * 8k SoCs. The Armada 7k is missing the CP110 slave regions here. Lets + * define these regions at the beginning of the struct so that they + * can be easier removed later dynamically if an Armada 7k device is detected. + * For a detailed memory map, please see doc/mvebu/armada-8k-memory.txt + */ +#define ARMADA_7K8K_COMMON_REGIONS_START 2 static struct mm_region mvebu_mem_map[] = { + /* Armada 80x0 memory regions include the CP1 (slave) units */ + { + /* SRAM, MMIO regions - CP110 slave region */ + .phys = 0xf4000000UL, + .virt = 0xf4000000UL, + .size = 0x02000000UL, /* 32MiB internal registers */ + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE + }, + { + /* PCI CP1 regions */ + .phys = 0xfa000000UL, + .virt = 0xfa000000UL, + .size = 0x04000000UL, /* 64MiB CP110 slave PCI space */ + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE + }, + /* Armada 80x0 and 70x0 common memory regions start here */ { /* RAM */ .phys = 0x0UL, @@ -47,29 +73,35 @@ static struct mm_region mvebu_mem_map[] = { PTE_BLOCK_NON_SHARE }, { - /* SRAM, MMIO regions - CP110 slave region */ - .phys = 0xf4000000UL, - .virt = 0xf4000000UL, - .size = 0x02000000UL, /* 32MiB internal registers */ + /* PCI CP0 regions */ + .phys = 0xf6000000UL, + .virt = 0xf6000000UL, + .size = 0x04000000UL, /* 64MiB CP110 master PCI space */ .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE }, { - /* PCI regions */ - .phys = 0xf8000000UL, - .virt = 0xf8000000UL, - .size = 0x08000000UL, /* 128MiB PCI space (master & slave) */ - .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | - PTE_BLOCK_NON_SHARE - }, - { - /* List terminator */ 0, } }; struct mm_region *mem_map = mvebu_mem_map; +void enable_caches(void) +{ + /* + * Armada 7k is not equipped with the CP110 slave CP. In case this + * code runs on an Armada 7k device, lets remove the CP110 slave + * entries from the memory mapping by moving the start to the + * common regions. + */ + if (of_machine_is_compatible("marvell,armada7040")) + mem_map = &mvebu_mem_map[ARMADA_7K8K_COMMON_REGIONS_START]; + + icache_enable(); + dcache_enable(); +} + void reset_cpu(ulong ignored) { u32 reg; diff --git a/arch/powerpc/cpu/mpc85xx/fdt.c b/arch/powerpc/cpu/mpc85xx/fdt.c index 12001f8..67140ba 100644 --- a/arch/powerpc/cpu/mpc85xx/fdt.c +++ b/arch/powerpc/cpu/mpc85xx/fdt.c @@ -180,6 +180,39 @@ static inline void ft_fixup_l3cache(void *blob, int off) #define ft_fixup_l3cache(x, y) #endif +#if defined(CONFIG_L2_CACHE) || \ + defined(CONFIG_BACKSIDE_L2_CACHE) || \ + defined(CONFIG_SYS_FSL_QORIQ_CHASSIS2) +static inline void ft_fixup_l2cache_compatible(void *blob, int off) +{ + int len; + struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr())); + + if (cpu) { + char buf[40]; + + if (isdigit(cpu->name[0])) { + /* MPCxxxx, where xxxx == 4-digit number */ + len = sprintf(buf, "fsl,mpc%s-l2-cache-controller", + cpu->name) + 1; + } else { + /* Pxxxx or Txxxx, where xxxx == 4-digit number */ + len = sprintf(buf, "fsl,%c%s-l2-cache-controller", + tolower(cpu->name[0]), cpu->name + 1) + 1; + } + + /* + * append "cache" after the NULL character that the previous + * sprintf wrote. This is how a device tree stores multiple + * strings in a property. + */ + len += sprintf(buf + len, "cache") + 1; + + fdt_setprop(blob, off, "compatible", buf, len); + } +} +#endif + #if defined(CONFIG_L2_CACHE) /* return size in kilobytes */ static inline u32 l2cache_size(void) @@ -215,9 +248,8 @@ static inline u32 l2cache_size(void) static inline void ft_fixup_l2cache(void *blob) { - int len, off; + int off; u32 *ph; - struct cpu_type *cpu = identify_cpu(SVR_SOC_VER(get_svr())); const u32 line_size = 32; const u32 num_ways = 8; @@ -243,28 +275,7 @@ static inline void ft_fixup_l2cache(void *blob) return ; } - if (cpu) { - char buf[40]; - - if (isdigit(cpu->name[0])) { - /* MPCxxxx, where xxxx == 4-digit number */ - len = sprintf(buf, "fsl,mpc%s-l2-cache-controller", - cpu->name) + 1; - } else { - /* Pxxxx or Txxxx, where xxxx == 4-digit number */ - len = sprintf(buf, "fsl,%c%s-l2-cache-controller", - tolower(cpu->name[0]), cpu->name + 1) + 1; - } - - /* - * append "cache" after the NULL character that the previous - * sprintf wrote. This is how a device tree stores multiple - * strings in a property. - */ - len += sprintf(buf + len, "cache") + 1; - - fdt_setprop(blob, off, "compatible", buf, len); - } + ft_fixup_l2cache_compatible(blob, off); fdt_setprop(blob, off, "cache-unified", NULL, 0); fdt_setprop_cell(blob, off, "cache-block-size", line_size); fdt_setprop_cell(blob, off, "cache-size", size); @@ -337,7 +348,7 @@ static inline void ft_fixup_l2cache(void *blob) fdt_setprop_cell(blob, l2_off, "cache-size", size); fdt_setprop_cell(blob, l2_off, "cache-sets", num_sets); fdt_setprop_cell(blob, l2_off, "cache-level", 2); - fdt_setprop(blob, l2_off, "compatible", "cache", 6); + ft_fixup_l2cache_compatible(blob, l2_off); } if (l3_off < 0) { diff --git a/arch/x86/dts/emulation-u-boot.dtsi b/arch/x86/dts/emulation-u-boot.dtsi new file mode 100644 index 0000000..56d34af --- /dev/null +++ b/arch/x86/dts/emulation-u-boot.dtsi @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <u-boot.dtsi> + +#ifdef CONFIG_ROM_SIZE +/ { + binman { + u-boot-with-ucode-ptr { + optional-ucode; + }; + }; +}; +#endif diff --git a/arch/x86/dts/u-boot.dtsi b/arch/x86/dts/u-boot.dtsi new file mode 100644 index 0000000..724913f --- /dev/null +++ b/arch/x86/dts/u-boot.dtsi @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2016 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <config.h> + +#ifdef CONFIG_ROM_SIZE +/ { + binman { + filename = "u-boot.rom"; + end-at-4gb; + sort-by-pos; + pad-byte = <0xff>; + size = <CONFIG_ROM_SIZE>; +#ifdef CONFIG_HAVE_INTEL_ME + intel-descriptor { + }; + intel-me { + }; +#endif + u-boot-with-ucode-ptr { + pos = <CONFIG_SYS_TEXT_BASE>; + }; + u-boot-dtb-with-ucode { + }; + u-boot-ucode { + align = <16>; + }; +#ifdef CONFIG_HAVE_MRC + intel-mrc { + pos = <CONFIG_X86_MRC_ADDR>; + }; +#endif +#ifdef CONFIG_HAVE_FSP + intel-fsp { + pos = <CONFIG_FSP_ADDR>; + }; +#endif +#ifdef CONFIG_HAVE_CMC + intel-cmc { + pos = <CONFIG_CMC_ADDR>; + }; +#endif +#ifdef CONFIG_HAVE_VGA_BIOS + intel-vga { + pos = <CONFIG_VGA_BIOS_ADDR>; + }; +#endif +#ifdef CONFIG_HAVE_REFCODE + intel-refcode { + pos = <CONFIG_X86_REFCODE_ADDR>; + }; +#endif + x86-start16 { + pos = <CONFIG_SYS_X86_START16>; + }; + }; +}; +#endif diff --git a/board/xilinx/zynq/board.c b/board/xilinx/zynq/board.c index 2c86940..5cd9bbf 100644 --- a/board/xilinx/zynq/board.c +++ b/board/xilinx/zynq/board.c @@ -124,121 +124,15 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) } #if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) -/* - * fdt_get_reg - Fill buffer by information from DT - */ -static phys_size_t fdt_get_reg(const void *fdt, int nodeoffset, void *buf, - const u32 *cell, int n) -{ - int i = 0, b, banks; - int parent_offset = fdt_parent_offset(fdt, nodeoffset); - int address_cells = fdt_address_cells(fdt, parent_offset); - int size_cells = fdt_size_cells(fdt, parent_offset); - char *p = buf; - u64 val; - u64 vals; - - debug("%s: addr_cells=%x, size_cell=%x, buf=%p, cell=%p\n", - __func__, address_cells, size_cells, buf, cell); - - /* Check memory bank setup */ - banks = n % (address_cells + size_cells); - if (banks) - panic("Incorrect memory setup cells=%d, ac=%d, sc=%d\n", - n, address_cells, size_cells); - - banks = n / (address_cells + size_cells); - - for (b = 0; b < banks; b++) { - debug("%s: Bank #%d:\n", __func__, b); - if (address_cells == 2) { - val = cell[i + 1]; - val <<= 32; - val |= cell[i]; - val = fdt64_to_cpu(val); - debug("%s: addr64=%llx, ptr=%p, cell=%p\n", - __func__, val, p, &cell[i]); - *(phys_addr_t *)p = val; - } else { - debug("%s: addr32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_addr_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_addr_t); - i += address_cells; - - debug("%s: pa=%p, i=%x, size=%zu\n", __func__, p, i, - sizeof(phys_addr_t)); - - if (size_cells == 2) { - vals = cell[i + 1]; - vals <<= 32; - vals |= cell[i]; - vals = fdt64_to_cpu(vals); - - debug("%s: size64=%llx, ptr=%p, cell=%p\n", - __func__, vals, p, &cell[i]); - *(phys_size_t *)p = vals; - } else { - debug("%s: size32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_size_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_size_t); - i += size_cells; - - debug("%s: ps=%p, i=%x, size=%zu\n", - __func__, p, i, sizeof(phys_size_t)); - } - - /* Return the first address size */ - return *(phys_size_t *)((char *)buf + sizeof(phys_addr_t)); -} - -#define FDT_REG_SIZE sizeof(u32) -/* Temp location for sharing data for storing */ -/* Up to 64-bit address + 64-bit size */ -static u8 tmp[CONFIG_NR_DRAM_BANKS * 16]; - void dram_init_banksize(void) { - int bank; - - memcpy(&gd->bd->bi_dram[0], &tmp, sizeof(tmp)); - - for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - debug("Bank #%d: start %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].start); - debug("Bank #%d: size %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].size); - } + fdtdec_setup_memory_banksize(); } int dram_init(void) { - int node, len; - const void *blob = gd->fdt_blob; - const u32 *cell; - - memset(&tmp, 0, sizeof(tmp)); - - /* find or create "/memory" node. */ - node = fdt_subnode_offset(blob, 0, "memory"); - if (node < 0) { - printf("%s: Can't get memory node\n", __func__); - return node; - } - - /* Get pointer to cells and lenght of it */ - cell = fdt_getprop(blob, node, "reg", &len); - if (!cell) { - printf("%s: Can't get reg property\n", __func__); - return -1; - } - - gd->ram_size = fdt_get_reg(blob, node, &tmp, cell, len / FDT_REG_SIZE); - - debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; zynq_ddrc_init(); diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index cef1f6a..4e5871b 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -180,121 +180,15 @@ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr) } #if !defined(CONFIG_SYS_SDRAM_BASE) && !defined(CONFIG_SYS_SDRAM_SIZE) -/* - * fdt_get_reg - Fill buffer by information from DT - */ -static phys_size_t fdt_get_reg(const void *fdt, int nodeoffset, void *buf, - const u32 *cell, int n) -{ - int i = 0, b, banks; - int parent_offset = fdt_parent_offset(fdt, nodeoffset); - int address_cells = fdt_address_cells(fdt, parent_offset); - int size_cells = fdt_size_cells(fdt, parent_offset); - char *p = buf; - u64 val; - u64 vals; - - debug("%s: addr_cells=%x, size_cell=%x, buf=%p, cell=%p\n", - __func__, address_cells, size_cells, buf, cell); - - /* Check memory bank setup */ - banks = n % (address_cells + size_cells); - if (banks) - panic("Incorrect memory setup cells=%d, ac=%d, sc=%d\n", - n, address_cells, size_cells); - - banks = n / (address_cells + size_cells); - - for (b = 0; b < banks; b++) { - debug("%s: Bank #%d:\n", __func__, b); - if (address_cells == 2) { - val = cell[i + 1]; - val <<= 32; - val |= cell[i]; - val = fdt64_to_cpu(val); - debug("%s: addr64=%llx, ptr=%p, cell=%p\n", - __func__, val, p, &cell[i]); - *(phys_addr_t *)p = val; - } else { - debug("%s: addr32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_addr_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_addr_t); - i += address_cells; - - debug("%s: pa=%p, i=%x, size=%zu\n", __func__, p, i, - sizeof(phys_addr_t)); - - if (size_cells == 2) { - vals = cell[i + 1]; - vals <<= 32; - vals |= cell[i]; - vals = fdt64_to_cpu(vals); - - debug("%s: size64=%llx, ptr=%p, cell=%p\n", - __func__, vals, p, &cell[i]); - *(phys_size_t *)p = vals; - } else { - debug("%s: size32=%x, ptr=%p\n", - __func__, fdt32_to_cpu(cell[i]), p); - *(phys_size_t *)p = fdt32_to_cpu(cell[i]); - } - p += sizeof(phys_size_t); - i += size_cells; - - debug("%s: ps=%p, i=%x, size=%zu\n", - __func__, p, i, sizeof(phys_size_t)); - } - - /* Return the first address size */ - return *(phys_size_t *)((char *)buf + sizeof(phys_addr_t)); -} - -#define FDT_REG_SIZE sizeof(u32) -/* Temp location for sharing data for storing */ -/* Up to 64-bit address + 64-bit size */ -static u8 tmp[CONFIG_NR_DRAM_BANKS * 16]; - void dram_init_banksize(void) { - int bank; - - memcpy(&gd->bd->bi_dram[0], &tmp, sizeof(tmp)); - - for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { - debug("Bank #%d: start %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].start); - debug("Bank #%d: size %llx\n", bank, - (unsigned long long)gd->bd->bi_dram[bank].size); - } + fdtdec_setup_memory_banksize(); } int dram_init(void) { - int node, len; - const void *blob = gd->fdt_blob; - const u32 *cell; - - memset(&tmp, 0, sizeof(tmp)); - - /* find or create "/memory" node. */ - node = fdt_subnode_offset(blob, 0, "memory"); - if (node < 0) { - printf("%s: Can't get memory node\n", __func__); - return node; - } - - /* Get pointer to cells and lenght of it */ - cell = fdt_getprop(blob, node, "reg", &len); - if (!cell) { - printf("%s: Can't get reg property\n", __func__); - return -1; - } - - gd->ram_size = fdt_get_reg(blob, node, &tmp, cell, len / FDT_REG_SIZE); - - debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); + if (fdtdec_setup_memory_size() != 0) + return -EINVAL; return 0; } @@ -311,17 +205,6 @@ void reset_cpu(ulong addr) { } -#ifdef CONFIG_SCSI_AHCI_PLAT -void scsi_init(void) -{ -#if defined(CONFIG_SATA_CEVA) - init_sata(0); -#endif - ahci_init((void __iomem *)ZYNQMP_SATA_BASEADDR); - scsi_scan(1); -} -#endif - int board_late_init(void) { u32 reg = 0; diff --git a/common/board_r.c b/common/board_r.c index 5496f45..a373352 100644 --- a/common/board_r.c +++ b/common/board_r.c @@ -620,7 +620,7 @@ static int initr_ambapp_print(void) } #endif -#if defined(CONFIG_SCSI) +#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI) static int initr_scsi(void) { puts("SCSI: "); @@ -923,7 +923,7 @@ init_fnc_t init_sequence_r[] = { initr_ambapp_print, #endif #endif -#ifdef CONFIG_SCSI +#if defined(CONFIG_SCSI) && !defined(CONFIG_DM_SCSI) INIT_FUNC_WATCHDOG_RESET initr_scsi, #endif diff --git a/common/image.c b/common/image.c index bd07e86..909dbed 100644 --- a/common/image.c +++ b/common/image.c @@ -1375,11 +1375,10 @@ int boot_get_fpga(int argc, char * const argv[], bootm_headers_t *images, img_len, BIT_PARTIAL); } - printf(" Programming %s bitstream... ", name); if (err) - printf("failed\n"); - else - printf("OK\n"); + return err; + + printf(" Programming %s bitstream... OK\n", name); break; default: printf("The given image format is not supported (corrupt?)\n"); diff --git a/common/miiphyutil.c b/common/miiphyutil.c index aca18db..8eb0f76 100644 --- a/common/miiphyutil.c +++ b/common/miiphyutil.c @@ -107,6 +107,18 @@ int mdio_register(struct mii_dev *bus) return 0; } +int mdio_register_seq(struct mii_dev *bus, int seq) +{ + int ret; + + /* Setup a unique name for each mdio bus */ + ret = snprintf(bus->name, MDIO_NAME_LEN, "eth%d", seq); + if (ret < 0) + return ret; + + return mdio_register(bus); +} + int mdio_unregister(struct mii_dev *bus) { if (!bus) diff --git a/common/scsi.c b/common/scsi.c index 04add62..e7efa5a 100644 --- a/common/scsi.c +++ b/common/scsi.c @@ -10,7 +10,10 @@ #include <inttypes.h> #include <pci.h> #include <scsi.h> +#include <dm/device-internal.h> +#include <dm/uclass-internal.h> +#if !defined(CONFIG_DM_SCSI) #ifdef CONFIG_SCSI_DEV_LIST #define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST #else @@ -31,6 +34,7 @@ #endif #define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID} #endif +#endif #if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT) const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST }; @@ -39,11 +43,13 @@ static ccb tempccb; /* temporary scsi command buffer */ static unsigned char tempbuff[512]; /* temporary data buffer */ +#if !defined(CONFIG_DM_SCSI) static int scsi_max_devs; /* number of highest available scsi device */ static int scsi_curr_dev; /* current device */ static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE]; +#endif /* almost the maximum amount of the scsi_ext command.. */ #define SCSI_MAX_READ_BLK 0xFFFF @@ -444,6 +450,7 @@ static void scsi_init_dev_desc_priv(struct blk_desc *dev_desc) #endif } +#if !defined(CONFIG_DM_SCSI) /** * scsi_init_dev_desc - initialize all SCSI specific blk_desc properties * @@ -460,6 +467,7 @@ static void scsi_init_dev_desc(struct blk_desc *dev_desc, int devnum) scsi_init_dev_desc_priv(dev_desc); } +#endif /** * scsi_detect_dev - Detect scsi device @@ -540,6 +548,73 @@ removable: * (re)-scan the scsi bus and reports scsi device info * to the user if mode = 1 */ +#if defined(CONFIG_DM_SCSI) +int scsi_scan(int mode) +{ + unsigned char i, lun; + struct uclass *uc; + struct udevice *dev; /* SCSI controller */ + int ret; + + if (mode == 1) + printf("scanning bus for devices...\n"); + + ret = uclass_get(UCLASS_SCSI, &uc); + if (ret) + return ret; + + uclass_foreach_dev(dev, uc) { + struct scsi_platdata *plat; /* scsi controller platdata */ + + /* probe SCSI controller driver */ + ret = device_probe(dev); + if (ret) + return ret; + + /* Get controller platdata */ + plat = dev_get_platdata(dev); + + for (i = 0; i < plat->max_id; i++) { + for (lun = 0; lun < plat->max_lun; lun++) { + struct udevice *bdev; /* block device */ + /* block device description */ + struct blk_desc *bdesc; + char str[10]; + + /* + * Create only one block device and do detection + * to make sure that there won't be a lot of + * block devices created + */ + snprintf(str, sizeof(str), "id%dlun%d", i, lun); + ret = blk_create_devicef(dev, "scsi_blk", + str, IF_TYPE_SCSI, + -1, 0, 0, &bdev); + if (ret) { + debug("Can't create device\n"); + return ret; + } + bdesc = dev_get_uclass_platdata(bdev); + + scsi_init_dev_desc_priv(bdesc); + bdesc->lun = lun; + ret = scsi_detect_dev(i, bdesc); + if (ret) { + device_unbind(bdev); + continue; + } + + if (mode == 1) { + printf(" Device %d: ", 0); + dev_print(bdesc); + } /* if mode */ + } /* next LUN */ + } + } + + return 0; +} +#else int scsi_scan(int mode) { unsigned char i, lun; @@ -576,6 +651,7 @@ int scsi_scan(int mode) #endif return 0; } +#endif #ifdef CONFIG_BLK static const struct blk_ops scsi_blk_ops = { diff --git a/configs/s5p_goni_defconfig b/configs/s5p_goni_defconfig index 4cbf022..aa61ef4 100644 --- a/configs/s5p_goni_defconfig +++ b/configs/s5p_goni_defconfig @@ -29,3 +29,6 @@ CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_G_DNL_MANUFACTURER="Samsung" CONFIG_G_DNL_VENDOR_NUM=0x04e8 CONFIG_G_DNL_PRODUCT_NUM=0x6601 +CONFIG_DM_PMIC=y +CONFIG_DM_PMIC_MAX8998=y +CONFIG_DM_I2C_GPIO=y diff --git a/configs/xilinx_zynqmp_ep_defconfig b/configs/xilinx_zynqmp_ep_defconfig index f261e22..b223e11 100644 --- a/configs/xilinx_zynqmp_ep_defconfig +++ b/configs/xilinx_zynqmp_ep_defconfig @@ -42,6 +42,8 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_DM_SCSI=y +CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y CONFIG_FPGA_XILINX=y CONFIG_FPGA_ZYNQMPPL=y diff --git a/configs/xilinx_zynqmp_zcu102_defconfig b/configs/xilinx_zynqmp_zcu102_defconfig index 021e0ff..9f2df49 100644 --- a/configs/xilinx_zynqmp_zcu102_defconfig +++ b/configs/xilinx_zynqmp_zcu102_defconfig @@ -34,6 +34,8 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_DM_SCSI=y +CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y CONFIG_FPGA_XILINX=y CONFIG_FPGA_ZYNQMPPL=y diff --git a/configs/xilinx_zynqmp_zcu102_revB_defconfig b/configs/xilinx_zynqmp_zcu102_revB_defconfig index 34062bd..b2b1720 100644 --- a/configs/xilinx_zynqmp_zcu102_revB_defconfig +++ b/configs/xilinx_zynqmp_zcu102_revB_defconfig @@ -34,6 +34,8 @@ CONFIG_OF_EMBED=y CONFIG_NET_RANDOM_ETHADDR=y CONFIG_SPL_DM=y CONFIG_SPL_DM_SEQ_ALIAS=y +CONFIG_DM_SCSI=y +CONFIG_SATA_CEVA=y CONFIG_DFU_RAM=y CONFIG_FPGA_XILINX=y CONFIG_FPGA_ZYNQMPPL=y diff --git a/doc/mvebu/armada-8k-memory.txt b/doc/mvebu/armada-8k-memory.txt new file mode 100644 index 0000000..064518e --- /dev/null +++ b/doc/mvebu/armada-8k-memory.txt @@ -0,0 +1,56 @@ + Memory Layout on Armada-8k SoC's + ================================ + +The below desribes the physical memory layout for Marvell's Armada-8k SoC's. + +This assumes that the SoC includes Dual CP configuration, in case the flavor is using +a single CP configuration, then all secondary-CP mappings are invalid. + +All "Reserved" areas below, are kept for future usage. + +Start End Use +-------------------------------------------------------------------------- +0x00000000 0xEFFFFFFF DRAM + +0xF0000000 0xF0FFFFFF AP Internal registers space + +0xF1000000 0xF1FFFFFF Reserved. + +0xF2000000 0xF3FFFFFF CP-0 Internal (configuration) registers + space. + +0xF4000000 0xF5FFFFFF CP-1 Internal (configuration) registers + space. + +0xF6000000 0xF6FFFFFF CP-0 / PCIe#0 Memory space. + +0xF7000000 0xF7FFFFFF CP-0 / PCIe#1 Memory space. + +0xF8000000 0xF8FFFFFF CP-0 / PCIe#2 Memory space. + +0xF9000000 0xF900FFFF CP-0 / PCIe#0 IO space. + +0xF9010000 0xF901FFFF CP-0 / PCIe#1 IO space. + +0xF9020000 0xF902FFFF CP-0 / PCIe#2 IO space. + +0xF9030000 0xF9FFFFFF Reserved. + +0xFA000000 0xFAFFFFFF CP-1 / PCIe#0 Memory space. + +0xFB000000 0xFBFFFFFF CP-1 / PCIe#1 Memory space. + +0xFC000000 0xFCFFFFFF CP-1 / PCIe#2 Memory space. + +0xFD000000 0xFD00FFFF CP-1 / PCIe#0 IO space. + +0xFD010000 0xFD01FFFF CP-1 / PCIe#1 IO space. + +0xFD020000 0xFD02FFFF CP-1 / PCIe#2 IO space. + +0xFD030000 0xFFEFFFFF Reserved. + +0xFFF00000 0xFFFFFFFF Bootrom + +0x100000000 <DRAM Size>-1 DRAM + diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index fe5aa07..88e66e2 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -19,6 +19,15 @@ config AHCI operations at present. The block device interface has not been converted to driver model. +config DM_SCSI + bool "Support SCSI controllers with driver model" + depends on BLK + help + This option enables the SCSI (Small Computer System Interface) uclass + which supports SCSI and SATA HDDs. For every device configuration + (IDs/LUNs) a block device is created with RAW read/write and + filesystem support. + config BLOCK_CACHE bool "Use block device cache" default n @@ -27,3 +36,16 @@ config BLOCK_CACHE This is most useful when accessing filesystems under U-Boot since it will prevent repeated reads from directory structures and other filesystem data structures. + +menu "SATA/SCSI device support" + +config SATA_CEVA + bool "Ceva Sata controller" + depends on AHCI + depends on DM_SCSI + help + This option enables Ceva Sata controller hard IP available on Xilinx + ZynqMP. Support up to 2 external devices. Complient with SATA 3.1 and + AHCI 1.3 specifications with hot-plug detect feature. + +endmenu diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 436b79f..a72feec 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -12,6 +12,7 @@ obj-y += blk_legacy.o endif obj-$(CONFIG_AHCI) += ahci-uclass.o +obj-$(CONFIG_DM_SCSI) += scsi-uclass.o obj-$(CONFIG_SCSI_AHCI) += ahci.o obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o obj-$(CONFIG_FSL_SATA) += fsl_sata.o diff --git a/drivers/block/ahci.c b/drivers/block/ahci.c index 5139989..3fa14a7 100644 --- a/drivers/block/ahci.c +++ b/drivers/block/ahci.c @@ -168,7 +168,7 @@ int ahci_reset(void __iomem *base) static int ahci_host_init(struct ahci_probe_ent *probe_ent) { -#ifndef CONFIG_SCSI_AHCI_PLAT +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # ifdef CONFIG_DM_PCI struct udevice *dev = probe_ent->dev; struct pci_child_platdata *pplat = dev_get_parent_platdata(dev); @@ -198,7 +198,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) writel(cap_save, mmio + HOST_CAP); writel_with_flush(0xf, mmio + HOST_PORTS_IMPL); -#ifndef CONFIG_SCSI_AHCI_PLAT +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) # ifdef CONFIG_DM_PCI if (pplat->vendor == PCI_VENDOR_ID_INTEL) { u16 tmp16; @@ -327,6 +327,7 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL); tmp = readl(mmio + HOST_CTL); debug("HOST_CTL 0x%x\n", tmp); +#if !defined(CONFIG_DM_SCSI) #ifndef CONFIG_SCSI_AHCI_PLAT # ifdef CONFIG_DM_PCI dm_pci_read_config16(dev, PCI_COMMAND, &tmp16); @@ -338,14 +339,15 @@ static int ahci_host_init(struct ahci_probe_ent *probe_ent) pci_write_config_word(pdev, PCI_COMMAND, tmp16); # endif #endif +#endif return 0; } static void ahci_print_info(struct ahci_probe_ent *probe_ent) { -#ifndef CONFIG_SCSI_AHCI_PLAT -# ifdef CONFIG_DM_PCI +#if !defined(CONFIG_SCSI_AHCI_PLAT) && !defined(CONFIG_DM_SCSI) +# if defined(CONFIG_DM_PCI) struct udevice *dev = probe_ent->dev; # else pci_dev_t pdev = probe_ent->dev; @@ -372,7 +374,7 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) else speed_s = "?"; -#ifdef CONFIG_SCSI_AHCI_PLAT +#if defined(CONFIG_SCSI_AHCI_PLAT) || defined(CONFIG_DM_SCSI) scc_s = "SATA"; #else # ifdef CONFIG_DM_PCI @@ -424,13 +426,15 @@ static void ahci_print_info(struct ahci_probe_ent *probe_ent) } #ifndef CONFIG_SCSI_AHCI_PLAT -# ifdef CONFIG_DM_PCI +# if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) static int ahci_init_one(struct udevice *dev) # else static int ahci_init_one(pci_dev_t dev) # endif { +#if !defined(CONFIG_DM_SCSI) u16 vendor; +#endif int rc; probe_ent = malloc(sizeof(struct ahci_probe_ent)); @@ -450,6 +454,7 @@ static int ahci_init_one(pci_dev_t dev) probe_ent->pio_mask = 0x1f; probe_ent->udma_mask = 0x7f; /*Fixme,assume to support UDMA6 */ +#if !defined(CONFIG_DM_SCSI) #ifdef CONFIG_DM_PCI probe_ent->mmio_base = dm_pci_map_bar(dev, PCI_BASE_ADDRESS_5, PCI_REGION_MEM); @@ -473,6 +478,10 @@ static int ahci_init_one(pci_dev_t dev) if (vendor == 0x197b) pci_write_config_byte(dev, 0x41, 0xa1); #endif +#else + struct scsi_platdata *plat = dev_get_platdata(dev); + probe_ent->mmio_base = (void *)plat->base; +#endif debug("ahci mmio_base=0x%p\n", probe_ent->mmio_base); /* initialize adapter */ @@ -954,14 +963,17 @@ int scsi_exec(ccb *pccb) } - +#if defined(CONFIG_DM_SCSI) +void scsi_low_level_init(int busdevfunc, struct udevice *dev) +#else void scsi_low_level_init(int busdevfunc) +#endif { int i; u32 linkmap; #ifndef CONFIG_SCSI_AHCI_PLAT -# ifdef CONFIG_DM_PCI +# if defined(CONFIG_DM_PCI) struct udevice *dev; int ret; @@ -969,6 +981,8 @@ void scsi_low_level_init(int busdevfunc) if (ret) return; ahci_init_one(dev); +# elif defined(CONFIG_DM_SCSI) + ahci_init_one(dev); # else ahci_init_one(busdevfunc); # endif diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 2e041c2..38cb938 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -26,7 +26,7 @@ static const char *if_typename_str[IF_TYPE_COUNT] = { static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { [IF_TYPE_IDE] = UCLASS_INVALID, - [IF_TYPE_SCSI] = UCLASS_INVALID, + [IF_TYPE_SCSI] = UCLASS_SCSI, [IF_TYPE_ATAPI] = UCLASS_INVALID, [IF_TYPE_USB] = UCLASS_MASS_STORAGE, [IF_TYPE_DOC] = UCLASS_INVALID, diff --git a/drivers/block/sata_ceva.c b/drivers/block/sata_ceva.c index dcc3b90..9b54664 100644 --- a/drivers/block/sata_ceva.c +++ b/drivers/block/sata_ceva.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <dm.h> #include <netdev.h> #include <ahci.h> #include <scsi.h> @@ -73,10 +74,9 @@ #define DRV_NAME "ahci-ceva" #define CEVA_FLAG_BROKEN_GEN2 1 -int init_sata(int dev) +static int ceva_init_sata(ulong mmio) { ulong tmp; - ulong mmio = ZYNQMP_SATA_BASEADDR; int i; /* @@ -111,3 +111,40 @@ int init_sata(int dev) } return 0; } + +static int sata_ceva_probe(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + ceva_init_sata(plat->base); + return 0; +} + +static const struct udevice_id sata_ceva_ids[] = { + { .compatible = "ceva,ahci-1v84" }, + { } +}; + +static int sata_ceva_ofdata_to_platdata(struct udevice *dev) +{ + struct scsi_platdata *plat = dev_get_platdata(dev); + + plat->base = dev_get_addr(dev); + if (plat->base == FDT_ADDR_T_NONE) + return -EINVAL; + + /* Hardcode number for ceva sata controller */ + plat->max_lun = 1; /* Actually two but untested */ + plat->max_id = 2; + + return 0; +} + +U_BOOT_DRIVER(ceva_host_blk) = { + .name = "ceva_sata", + .id = UCLASS_SCSI, + .of_match = sata_ceva_ids, + .probe = sata_ceva_probe, + .ofdata_to_platdata = sata_ceva_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct scsi_platdata), +}; diff --git a/drivers/block/scsi-uclass.c b/drivers/block/scsi-uclass.c new file mode 100644 index 0000000..05da6cd --- /dev/null +++ b/drivers/block/scsi-uclass.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 Google, Inc + * Written by Simon Glass <sjg@chromium.org> + * Copyright (c) 2016 Xilinx, Inc + * Written by Michal Simek + * + * Based on ahci-uclass.c + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <scsi.h> + +static int scsi_post_probe(struct udevice *dev) +{ + debug("%s: device %p\n", __func__, dev); + scsi_low_level_init(0, dev); + return 0; +} + +UCLASS_DRIVER(scsi) = { + .id = UCLASS_SCSI, + .name = "scsi", + .post_probe = scsi_post_probe, +}; diff --git a/drivers/gpio/zynq_gpio.c b/drivers/gpio/zynq_gpio.c index 8a448c9..64579a1 100644 --- a/drivers/gpio/zynq_gpio.c +++ b/drivers/gpio/zynq_gpio.c @@ -325,7 +325,6 @@ static const struct dm_gpio_ops gpio_zynq_ops = { .get_value = zynq_gpio_get_value, .set_value = zynq_gpio_set_value, .get_function = zynq_gpio_get_function, - }; static const struct udevice_id zynq_gpio_ids[] = { diff --git a/drivers/i2c/mv_i2c.c b/drivers/i2c/mv_i2c.c index 7f52fa2..c780272 100644 --- a/drivers/i2c/mv_i2c.c +++ b/drivers/i2c/mv_i2c.c @@ -270,7 +270,7 @@ static int __i2c_read(struct mv_i2c *base, uchar chip, u8 *addr, int alen, msg.condition = I2C_COND_NORMAL; msg.acknack = I2C_ACKNAK_WAITACK; msg.direction = I2C_WRITE; - msg.data = *(addr++); + msg.data = addr[alen]; if (i2c_transfer(base, &msg)) return -1; } @@ -341,7 +341,7 @@ static int __i2c_write(struct mv_i2c *base, uchar chip, u8 *addr, int alen, msg.condition = I2C_COND_NORMAL; msg.acknack = I2C_ACKNAK_WAITACK; msg.direction = I2C_WRITE; - msg.data = *(addr++); + msg.data = addr[alen]; if (i2c_transfer(base, &msg)) return -1; } diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index 5e84a41..9983913 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -83,7 +83,7 @@ config PIC32_SDHCI config ZYNQ_SDHCI bool "Arasan SDHCI controller support" - depends on DM_MMC && OF_CONTROL + depends on DM_MMC && OF_CONTROL && BLK && DM_MMC_OPS help Support for Arasan SDHCI host controller on Zynq/ZynqMP ARM SoCs platform diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile index d850758..94da954 100644 --- a/drivers/mmc/Makefile +++ b/drivers/mmc/Makefile @@ -52,7 +52,6 @@ obj-$(CONFIG_SDHCI) += sdhci.o obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_SH_SDHI) += sh_sdhi.o obj-$(CONFIG_SOCFPGA_DWMMC) += socfpga_dw_mmc.o -obj-$(CONFIG_SPEAR_SDHCI) += spear_sdhci.o obj-$(CONFIG_TEGRA_MMC) += tegra_mmc.o obj-$(CONFIG_MMC_UNIPHIER) += uniphier-sd.o obj-$(CONFIG_ZYNQ_SDHCI) += zynq_sdhci.o diff --git a/drivers/mmc/spear_sdhci.c b/drivers/mmc/spear_sdhci.c deleted file mode 100644 index 06179cd..0000000 --- a/drivers/mmc/spear_sdhci.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * (C) Copyright 2012 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> -#include <sdhci.h> - -int spear_sdhci_init(u32 regbase, u32 max_clk, u32 min_clk, u32 quirks) -{ - struct sdhci_host *host = NULL; - host = (struct sdhci_host *)malloc(sizeof(struct sdhci_host)); - if (!host) { - printf("sdhci host malloc fail!\n"); - return 1; - } - - host->name = "sdhci"; - host->ioaddr = (void *)regbase; - host->quirks = quirks; - - add_sdhci(host, max_clk, min_clk); - return 0; -} diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index 5de06ef..51c7426 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -648,9 +648,8 @@ static int axi_emac_probe(struct udevice *dev) priv->bus->read = axiemac_miiphy_read; priv->bus->write = axiemac_miiphy_write; priv->bus->priv = priv; - strcpy(priv->bus->name, "axi_emac"); - ret = mdio_register(priv->bus); + ret = mdio_register_seq(priv->bus, dev->seq); if (ret) return ret; diff --git a/drivers/net/xilinx_emaclite.c b/drivers/net/xilinx_emaclite.c index 78ff44c..ea93cf9 100644 --- a/drivers/net/xilinx_emaclite.c +++ b/drivers/net/xilinx_emaclite.c @@ -566,9 +566,8 @@ static int emaclite_probe(struct udevice *dev) emaclite->bus->read = emaclite_miiphy_read; emaclite->bus->write = emaclite_miiphy_write; emaclite->bus->priv = emaclite; - strcpy(emaclite->bus->name, "emaclite"); - ret = mdio_register(emaclite->bus); + ret = mdio_register_seq(emaclite->bus, dev->seq); if (ret) return ret; diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index 526eac6..d2e5e7c 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -647,9 +647,8 @@ static int zynq_gem_probe(struct udevice *dev) priv->bus->read = zynq_gem_miiphy_read; priv->bus->write = zynq_gem_miiphy_write; priv->bus->priv = priv; - strcpy(priv->bus->name, "gem"); - ret = mdio_register(priv->bus); + ret = mdio_register_seq(priv->bus, dev->seq); if (ret) return ret; diff --git a/drivers/power/pmic/Kconfig b/drivers/power/pmic/Kconfig index ce204b3..5e244c8 100644 --- a/drivers/power/pmic/Kconfig +++ b/drivers/power/pmic/Kconfig @@ -54,6 +54,13 @@ config DM_PMIC_MAX77686 This config enables implementation of driver-model pmic uclass features for PMIC MAX77686. The driver implements read/write operations. +config DM_PMIC_MAX8998 + bool "Enable Driver Model for PMIC MAX8998" + depends on DM_PMIC + ---help--- + This config enables implementation of driver-model pmic uclass features + for PMIC MAX8998. The driver implements read/write operations. + config PMIC_PM8916 bool "Enable Driver Model for Qualcomm PM8916 PMIC" depends on DM_PMIC diff --git a/drivers/power/pmic/Makefile b/drivers/power/pmic/Makefile index cd1c694..b4ac7d2 100644 --- a/drivers/power/pmic/Makefile +++ b/drivers/power/pmic/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_DM_PMIC) += pmic-uclass.o obj-$(CONFIG_DM_PMIC_MAX77686) += max77686.o +obj-$(CONFIG_DM_PMIC_MAX8998) += max8998.o obj-$(CONFIG_DM_PMIC_PFUZE100) += pfuze100.o obj-$(CONFIG_PMIC_S2MPS11) += s2mps11.o obj-$(CONFIG_DM_PMIC_SANDBOX) += sandbox.o i2c_pmic_emul.o diff --git a/drivers/power/pmic/max8998.c b/drivers/power/pmic/max8998.c new file mode 100644 index 0000000..3baa8da --- /dev/null +++ b/drivers/power/pmic/max8998.c @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2016 Samsung Electronics + * Jaehoon Chung <jh80.chung@samsung.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <i2c.h> +#include <power/pmic.h> +#include <power/max8998_pmic.h> +#include <errno.h> + +DECLARE_GLOBAL_DATA_PTR; + +static int max8998_reg_count(struct udevice *dev) +{ + return PMIC_NUM_OF_REGS; +} + +static int max8998_write(struct udevice *dev, uint reg, const uint8_t *buff, + int len) +{ + int ret; + + ret = dm_i2c_write(dev, reg, buff, len); + if (ret) + error("write error to device: %p register: %#x!", dev, reg); + + return ret; +} + +static int max8998_read(struct udevice *dev, uint reg, uint8_t *buff, int len) +{ + int ret; + + ret = dm_i2c_read(dev, reg, buff, len); + if (ret) + error("read error from device: %p register: %#x!", dev, reg); + + return ret; +} + +static struct dm_pmic_ops max8998_ops = { + .reg_count = max8998_reg_count, + .read = max8998_read, + .write = max8998_write, +}; + +static const struct udevice_id max8998_ids[] = { + { .compatible = "maxim,max8998" }, + { } +}; + +U_BOOT_DRIVER(pmic_max8998) = { + .name = "max8998_pmic", + .id = UCLASS_PMIC, + .of_match = max8998_ids, + .ops = &max8998_ops, +}; diff --git a/include/ahci.h b/include/ahci.h index a956c6f..4876b41 100644 --- a/include/ahci.h +++ b/include/ahci.h @@ -145,7 +145,7 @@ struct ahci_ioports { }; struct ahci_probe_ent { -#ifdef CONFIG_DM_PCI +#if defined(CONFIG_DM_PCI) || defined(CONFIG_DM_SCSI) struct udevice *dev; #else pci_dev_t dev; diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h index d480990..fb4f6d6 100644 --- a/include/configs/xilinx_zynqmp.h +++ b/include/configs/xilinx_zynqmp.h @@ -181,7 +181,6 @@ #ifdef CONFIG_SATA_CEVA #define CONFIG_LIBATA #define CONFIG_SCSI_AHCI -#define CONFIG_SCSI_AHCI_PLAT #define CONFIG_SYS_SCSI_MAX_SCSI_ID 2 #define CONFIG_SYS_SCSI_MAX_LUN 1 #define CONFIG_SYS_SCSI_MAX_DEVICE (CONFIG_SYS_SCSI_MAX_SCSI_ID * \ diff --git a/include/configs/xilinx_zynqmp_ep.h b/include/configs/xilinx_zynqmp_ep.h index d0ce768..3a572b7 100644 --- a/include/configs/xilinx_zynqmp_ep.h +++ b/include/configs/xilinx_zynqmp_ep.h @@ -16,7 +16,6 @@ #define CONFIG_ZYNQ_SDHCI_MAX_FREQ 52000000 #define CONFIG_ZYNQ_SDHCI_MIN_FREQ (CONFIG_ZYNQ_SDHCI_MAX_FREQ >> 9) #define CONFIG_ZYNQ_EEPROM -#define CONFIG_SATA_CEVA #define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR, \ ZYNQMP_USB1_XHCI_BASEADDR} diff --git a/include/configs/xilinx_zynqmp_zcu102.h b/include/configs/xilinx_zynqmp_zcu102.h index adf2321..8d018da 100644 --- a/include/configs/xilinx_zynqmp_zcu102.h +++ b/include/configs/xilinx_zynqmp_zcu102.h @@ -41,8 +41,6 @@ #define CONFIG_CMD_PCA953X #define CONFIG_CMD_PCA953X_INFO -#define CONFIG_SATA_CEVA - #define CONFIG_ZYNQMP_XHCI_LIST {ZYNQMP_USB0_XHCI_BASEADDR} #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN 1 diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index eb78c4d..8c92d0b 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -66,6 +66,7 @@ enum uclass_id { UCLASS_REMOTEPROC, /* Remote Processor device */ UCLASS_RESET, /* Reset controller device */ UCLASS_RTC, /* Real time clock device */ + UCLASS_SCSI, /* SCSI device */ UCLASS_SERIAL, /* Serial UART */ UCLASS_SPI, /* SPI bus */ UCLASS_SPMI, /* System Power Management Interface bus */ diff --git a/include/fdtdec.h b/include/fdtdec.h index 27887c8..d074478 100644 --- a/include/fdtdec.h +++ b/include/fdtdec.h @@ -976,6 +976,40 @@ struct display_timing { */ int fdtdec_decode_display_timing(const void *blob, int node, int index, struct display_timing *config); + +/** + * fdtdec_setup_memory_size() - decode and setup gd->ram_size + * + * Decode the /memory 'reg' property to determine the size of the first memory + * bank, populate the global data with the size of the first bank of memory. + * + * This function should be called from a boards dram_init(). This helper + * function allows for boards to query the device tree for DRAM size instead of + * hard coding the value in the case where the memory size cannot be detected + * automatically. + * + * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or + * invalid + */ +int fdtdec_setup_memory_size(void); + +/** + * fdtdec_setup_memory_banksize() - decode and populate gd->bd->bi_dram + * + * Decode the /memory 'reg' property to determine the address and size of the + * memory banks. Use this data to populate the global data board info with the + * phys address and size of memory banks. + * + * This function should be called from a boards dram_init_banksize(). This + * helper function allows for boards to query the device tree for memory bank + * information instead of hard coding the information in cases where it cannot + * be detected automatically. + * + * @return 0 if OK, -EINVAL if the /memory node or reg property is missing or + * invalid + */ +int fdtdec_setup_memory_banksize(void); + /** * Set up the device tree ready for use */ diff --git a/include/miiphy.h b/include/miiphy.h index 83141b4..fe8928a 100644 --- a/include/miiphy.h +++ b/include/miiphy.h @@ -48,6 +48,15 @@ void miiphy_listdev(void); struct mii_dev *mdio_alloc(void); void mdio_free(struct mii_dev *bus); int mdio_register(struct mii_dev *bus); + +/** + * mdio_register_seq - Register mdio bus with sequence number + * @bus: mii device structure + * @seq: sequence number + * + * Return: 0 if success, negative value if error + */ +int mdio_register_seq(struct mii_dev *bus, int seq); int mdio_unregister(struct mii_dev *bus); void mdio_list_devices(void); diff --git a/include/sata.h b/include/sata.h index b35359a..d18cc9a 100644 --- a/include/sata.h +++ b/include/sata.h @@ -2,6 +2,7 @@ #define __SATA_H__ #include <part.h> +#if !defined(CONFIG_DM_SCSI) int init_sata(int dev); int reset_sata(int dev); int scan_sata(int dev); @@ -15,5 +16,6 @@ int __sata_stop(void); int sata_port_status(int dev, int port); extern struct blk_desc sata_dev_desc[]; +#endif #endif diff --git a/include/scsi.h b/include/scsi.h index c879678..190dacd 100644 --- a/include/scsi.h +++ b/include/scsi.h @@ -166,8 +166,11 @@ typedef struct SCSI_cmd_block{ void scsi_print_error(ccb *pccb); int scsi_exec(ccb *pccb); void scsi_bus_reset(void); +#if !defined(CONFIG_DM_SCSI) void scsi_low_level_init(int busdevfunc); - +#else +void scsi_low_level_init(int busdevfunc, struct udevice *dev); +#endif /*************************************************************************** * functions residing inside cmd_scsi.c @@ -175,6 +178,21 @@ void scsi_low_level_init(int busdevfunc); void scsi_init(void); int scsi_scan(int mode); +#if defined(CONFIG_DM_SCSI) +/** + * struct scsi_platdata - stores information about SCSI controller + * + * @base: Controller base address + * @max_lun: Maximum number of logical units + * @max_id: Maximum number of target ids + */ +struct scsi_platdata { + unsigned long base; + unsigned long max_lun; + unsigned long max_id; +}; +#endif + #define SCSI_IDENTIFY 0xC0 /* not used */ /* Hardware errors */ diff --git a/lib/fdtdec.c b/lib/fdtdec.c index 4e619c4..81f47ef 100644 --- a/lib/fdtdec.c +++ b/lib/fdtdec.c @@ -1174,6 +1174,62 @@ int fdtdec_decode_display_timing(const void *blob, int parent, int index, return ret; } +int fdtdec_setup_memory_size(void) +{ + int ret, mem; + struct fdt_resource res; + + mem = fdt_path_offset(gd->fdt_blob, "/memory"); + if (mem < 0) { + debug("%s: Missing /memory node\n", __func__); + return -EINVAL; + } + + ret = fdt_get_resource(gd->fdt_blob, mem, "reg", 0, &res); + if (ret != 0) { + debug("%s: Unable to decode first memory bank\n", __func__); + return -EINVAL; + } + + gd->ram_size = (phys_size_t)(res.end - res.start + 1); + debug("%s: Initial DRAM size %llx\n", __func__, (u64)gd->ram_size); + + return 0; +} + +#if defined(CONFIG_NR_DRAM_BANKS) +int fdtdec_setup_memory_banksize(void) +{ + int bank, ret, mem; + struct fdt_resource res; + + mem = fdt_path_offset(gd->fdt_blob, "/memory"); + if (mem < 0) { + debug("%s: Missing /memory node\n", __func__); + return -EINVAL; + } + + for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; bank++) { + ret = fdt_get_resource(gd->fdt_blob, mem, "reg", bank, &res); + if (ret == -FDT_ERR_NOTFOUND) + break; + if (ret != 0) + return -EINVAL; + + gd->bd->bi_dram[bank].start = (phys_addr_t)res.start; + gd->bd->bi_dram[bank].size = + (phys_size_t)(res.end - res.start + 1); + + debug("%s: DRAM Bank #%d: start = 0x%llx, size = 0x%llx\n", + __func__, bank, + (unsigned long long)gd->bd->bi_dram[bank].start, + (unsigned long long)gd->bd->bi_dram[bank].size); + } + + return 0; +} +#endif + int fdtdec_setup(void) { #if CONFIG_IS_ENABLED(OF_CONTROL) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 956a8a9..348de2d 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -164,10 +164,30 @@ cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(UBOOTINCLUDE) \ ld_flags = $(LDFLAGS) $(ldflags-y) +dts_dir = $(srctree)/arch/$(ARCH)/dts + +# Try these files in order to find the U-Boot-specific .dtsi include file +u_boot_dtsi_options = $(wildcard $(dts_dir)/$(basename $(notdir $<))-u-boot.dtsi) \ + $(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_SOC))-u-boot.dtsi) \ + $(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_CPU))-u-boot.dtsi) \ + $(wildcard $(dts_dir)/$(subst $\",,$(CONFIG_SYS_VENDOR))-u-boot.dtsi) \ + $(wildcard $(dts_dir)/u-boot.dtsi) + +# Uncomment for debugging +# $(warning u_boot_dtsi_options: $(u_boot_dtsi_options)) + +# We use the first match +u_boot_dtsi = $(firstword $(u_boot_dtsi_options)) + # Modified for U-Boot dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ -I$(srctree)/arch/$(ARCH)/dts \ -I$(srctree)/arch/$(ARCH)/dts/include \ + -Iinclude \ + -I$(srctree)/include \ + -I$(srctree)/arch/$(ARCH)/include \ + -include $(srctree)/include/linux/kconfig.h \ + -D__ASSEMBLY__ \ -undef -D__DTS__ # Finds the multi-part object the current object will be linked into @@ -288,8 +308,11 @@ $(obj)/%.dtb.S: $(obj)/%.dtb quiet_cmd_dtc = DTC $@ # Modified for U-Boot +# Bring in any U-Boot-specific include after the '/dts-v1/;' header cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ - $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ + cat $< $(if $(u_boot_dtsi),\ + | sed 's%^/ {$$%\#include \"$(u_boot_dtsi)\"\n&%') | \ + $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \ $(DTC) -O dtb -o $@ -b 0 \ -i $(dir $<) $(DTC_FLAGS) \ -d $(depfile).dtc.tmp $(dtc-tmp) ; \ diff --git a/tools/binman/.gitignore b/tools/binman/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/tools/binman/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/tools/binman/README b/tools/binman/README new file mode 100644 index 0000000..cb47e73 --- /dev/null +++ b/tools/binman/README @@ -0,0 +1,541 @@ +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# + +Introduction +------------ + +Firmware often consists of several components which must be packaged together. +For example, we may have SPL, U-Boot, a device tree and an environment area +grouped together and placed in MMC flash. When the system starts, it must be +able to find these pieces. + +So far U-Boot has not provided a way to handle creating such images in a +general way. Each SoC does what it needs to build an image, often packing or +concatenating images in the U-Boot build system. + +Binman aims to provide a mechanism for building images, from simple +SPL + U-Boot combinations, to more complex arrangements with many parts. + + +What it does +------------ + +Binman reads your board's device tree and finds a node which describes the +required image layout. It uses this to work out what to place where. The +output file normally contains the device tree, so it is in principle possible +to read an image and extract its constituent parts. + + +Features +-------- + +So far binman is pretty simple. It supports binary blobs, such as 'u-boot', +'spl' and 'fdt'. It supports empty entries (such as setting to 0xff). It can +place entries at a fixed location in the image, or fit them together with +suitable padding and alignment. It provides a way to process binaries before +they are included, by adding a Python plug-in. The device tree is available +to U-Boot at run-time so that the images can be interpreted. + +Binman does not yet update the device tree with the final location of +everything when it is done. A simple C structure could be generated for +constrained environments like SPL (using dtoc) but this is also not +implemented. + +Binman can also support incorporating filesystems in the image if required. +For example x86 platforms may use CBFS in some cases. + +Binman is intended for use with U-Boot but is designed to be general enough +to be useful in other image-packaging situations. + + +Motivation +---------- + +Packaging of firmware is quite a different task from building the various +parts. In many cases the various binaries which go into the image come from +separate build systems. For example, ARM Trusted Firmware is used on ARMv8 +devices but is not built in the U-Boot tree. If a Linux kernel is included +in the firmware image, it is built elsewhere. + +It is of course possible to add more and more build rules to the U-Boot +build system to cover these cases. It can shell out to other Makefiles and +build scripts. But it seems better to create a clear divide between building +software and packaging it. + +At present this is handled by manual instructions, different for each board, +on how to create images that will boot. By turning these instructions into a +standard format, we can support making valid images for any board without +manual effort, lots of READMEs, etc. + +Benefits: +- Each binary can have its own build system and tool chain without creating +any dependencies between them +- Avoids the need for a single-shot build: individual parts can be updated +and brought in as needed +- Provides for a standard image description available in the build and at +run-time +- SoC-specific image-signing tools can be accomodated +- Avoids cluttering the U-Boot build system with image-building code +- The image description is automatically available at run-time in U-Boot, +SPL. It can be made available to other software also +- The image description is easily readable (it's a text file in device-tree +format) and permits flexible packing of binaries + + +Terminology +----------- + +Binman uses the following terms: + +- image - an output file containing a firmware image +- binary - an input binary that goes into the image + + +Relationship to FIT +------------------- + +FIT is U-Boot's official image format. It supports multiple binaries with +load / execution addresses, compression. It also supports verification +through hashing and RSA signatures. + +FIT was originally designed to support booting a Linux kernel (with an +optional ramdisk) and device tree chosen from various options in the FIT. +Now that U-Boot supports configuration via device tree, it is possible to +load U-Boot from a FIT, with the device tree chosen by SPL. + +Binman considers FIT to be one of the binaries it can place in the image. + +Where possible it is best to put as much as possible in the FIT, with binman +used to deal with cases not covered by FIT. Examples include initial +execution (since FIT itself does not have an executable header) and dealing +with device boundaries, such as the read-only/read-write separation in SPI +flash. + +For U-Boot, binman should not be used to create ad-hoc images in place of +FIT. + + +Relationship to mkimage +----------------------- + +The mkimage tool provides a means to create a FIT. Traditionally it has +needed an image description file: a device tree, like binman, but in a +different format. More recently it has started to support a '-f auto' mode +which can generate that automatically. + +More relevant to binman, mkimage also permits creation of many SoC-specific +image types. These can be listed by running 'mkimage -T list'. Examples +include 'rksd', the Rockchip SD/MMC boot format. The mkimage tool is often +called from the U-Boot build system for this reason. + +Binman considers the output files created by mkimage to be binary blobs +which it can place in an image. Binman does not replace the mkimage tool or +this purpose. It would be possible in some situtions to create a new entry +type for the images in mkimage, but this would not add functionality. It +seems better to use the mkiamge tool to generate binaries and avoid blurring +the boundaries between building input files (mkimage) and packaging then +into a final image (binman). + + +Example use of binman in U-Boot +------------------------------- + +Binman aims to replace some of the ad-hoc image creation in the U-Boot +build system. + +Consider sunxi. It has the following steps: + +1. It uses a custom mksunxiboot tool to build an SPL image called +sunxi-spl.bin. This should probably move into mkimage. + +2. It uses mkimage to package U-Boot into a legacy image file (so that it can +hold the load and execution address) called u-boot.img. + +3. It builds a final output image called u-boot-sunxi-with-spl.bin which +consists of sunxi-spl.bin, some padding and u-boot.img. + +Binman is intended to replace the last step. The U-Boot build system builds +u-boot.bin and sunxi-spl.bin. Binman can then take over creation of +sunxi-spl.bin (by calling mksunxiboot, or hopefully one day mkimage). In any +case, it would then create the image from the component parts. + +This simplifies the U-Boot Makefile somewhat, since various pieces of logic +can be replaced by a call to binman. + + +Example use of binman for x86 +----------------------------- + +In most cases x86 images have a lot of binary blobs, 'black-box' code +provided by Intel which must be run for the platform to work. Typically +these blobs are not relocatable and must be placed at fixed areas in the +firmare image. + +Currently this is handled by ifdtool, which places microcode, FSP, MRC, VGA +BIOS, reference code and Intel ME binaries into a u-boot.rom file. + +Binman is intended to replace all of this, with ifdtool left to handle only +the configuration of the Intel-format descriptor. + + +Running binman +-------------- + +Type: + + binman -b <board_name> + +to build an image for a board. The board name is the same name used when +configuring U-Boot (e.g. for sandbox_defconfig the board name is 'sandbox'). +Binman assumes that the input files for the build are in ../b/<board_name>. + +Or you can specify this explicitly: + + binman -I <build_path> + +where <build_path> is the build directory containing the output of the U-Boot +build. + +(Future work will make this more configurable) + +In either case, binman picks up the device tree file (u-boot.dtb) and looks +for its instructions in the 'binman' node. + +Binman has a few other options which you can see by running 'binman -h'. + + +Image description format +------------------------ + +The binman node is called 'binman'. An example image description is shown +below: + + binman { + filename = "u-boot-sunxi-with-spl.bin"; + pad-byte = <0xff>; + blob { + filename = "spl/sunxi-spl.bin"; + }; + u-boot { + pos = <CONFIG_SPL_PAD_TO>; + }; + }; + + +This requests binman to create an image file called u-boot-sunxi-with-spl.bin +consisting of a specially formatted SPL (spl/sunxi-spl.bin, built by the +normal U-Boot Makefile), some 0xff padding, and a U-Boot legacy image. The +padding comes from the fact that the second binary is placed at +CONFIG_SPL_PAD_TO. If that line were omitted then the U-Boot binary would +immediately follow the SPL binary. + +The binman node describes an image. The sub-nodes describe entries in the +image. Each entry represents a region within the overall image. The name of +the entry (blob, u-boot) tells binman what to put there. For 'blob' we must +provide a filename. For 'u-boot', binman knows that this means 'u-boot.bin'. + +Entries are normally placed into the image sequentially, one after the other. +The image size is the total size of all entries. As you can see, you can +specify the start position of an entry using the 'pos' property. + +Note that due to a device tree requirement, all entries must have a unique +name. If you want to put the same binary in the image multiple times, you can +use any unique name, with the 'type' property providing the type. + +The attributes supported for entries are described below. + +pos: + This sets the position of an entry within the image. The first byte + of the image is normally at position 0. If 'pos' is not provided, + binman sets it to the end of the previous region, or the start of + the image's entry area (normally 0) if there is no previous region. + +align: + This sets the alignment of the entry. The entry position is adjusted + so that the entry starts on an aligned boundary within the image. For + example 'align = <16>' means that the entry will start on a 16-byte + boundary. Alignment shold be a power of 2. If 'align' is not + provided, no alignment is performed. + +size: + This sets the size of the entry. The contents will be padded out to + this size. If this is not provided, it will be set to the size of the + contents. + +pad-before: + Padding before the contents of the entry. Normally this is 0, meaning + that the contents start at the beginning of the entry. This can be + offset the entry contents a little. Defaults to 0. + +pad-after: + Padding after the contents of the entry. Normally this is 0, meaning + that the entry ends at the last byte of content (unless adjusted by + other properties). This allows room to be created in the image for + this entry to expand later. Defaults to 0. + +align-size: + This sets the alignment of the entry size. For example, to ensure + that the size of an entry is a multiple of 64 bytes, set this to 64. + If 'align-size' is not provided, no alignment is performed. + +align-end: + This sets the alignment of the end of an entry. Some entries require + that they end on an alignment boundary, regardless of where they + start. If 'align-end' is not provided, no alignment is performed. + + Note: This is not yet implemented in binman. + +filename: + For 'blob' types this provides the filename containing the binary to + put into the entry. If binman knows about the entry type (like + u-boot-bin), then there is no need to specify this. + +type: + Sets the type of an entry. This defaults to the entry name, but it is + possible to use any name, and then add (for example) 'type = "u-boot"' + to specify the type. + + +The attributes supported for images are described below. Several are similar +to those for entries. + +size: + Sets the image size in bytes, for example 'size = <0x100000>' for a + 1MB image. + +align-size: + This sets the alignment of the image size. For example, to ensure + that the image ends on a 512-byte boundary, use 'align-size = <512>'. + If 'align-size' is not provided, no alignment is performed. + +pad-before: + This sets the padding before the image entries. The first entry will + be positionad after the padding. This defaults to 0. + +pad-after: + This sets the padding after the image entries. The padding will be + placed after the last entry. This defaults to 0. + +pad-byte: + This specifies the pad byte to use when padding in the image. It + defaults to 0. To use 0xff, you would add 'pad-byte = <0xff>'. + +filename: + This specifies the image filename. It defaults to 'image.bin'. + +sort-by-pos: + This causes binman to reorder the entries as needed to make sure they + are in increasing positional order. This can be used when your entry + order may not match the positional order. A common situation is where + the 'pos' properties are set by CONFIG options, so their ordering is + not known a priori. + + This is a boolean property so needs no value. To enable it, add a + line 'sort-by-pos;' to your description. + +multiple-images: + Normally only a single image is generated. To create more than one + image, put this property in the binman node. For example, this will + create image1.bin containing u-boot.bin, and image2.bin containing + both spl/u-boot-spl.bin and u-boot.bin: + + binman { + multiple-images; + image1 { + u-boot { + }; + }; + + image2 { + spl { + }; + u-boot { + }; + }; + }; + +end-at-4gb: + For x86 machines the ROM positions start just before 4GB and extend + up so that the image finished at the 4GB boundary. This boolean + option can be enabled to support this. The image size must be + provided so that binman knows when the image should start. For an + 8MB ROM, the position of the first entry would be 0xfff80000 with + this option, instead of 0 without this option. + + +Examples of the above options can be found in the tests. See the +tools/binman/test directory. + + +Special properties +------------------ + +Some entries support special properties, documented here: + +u-boot-with-ucode-ptr: + optional-ucode: boolean property to make microcode optional. If the + u-boot.bin image does not include microcode, no error will + be generated. + + +Order of image creation +----------------------- + +Image creation proceeds in the following order, for each entry in the image. + +1. GetEntryContents() - the contents of each entry are obtained, normally by +reading from a file. This calls the Entry.ObtainContents() to read the +contents. The default version of Entry.ObtainContents() calls +Entry.GetDefaultFilename() and then reads that file. So a common mechanism +to select a file to read is to override that function in the subclass. The +functions must return True when they have read the contents. Binman will +retry calling the functions a few times if False is returned, allowing +dependencies between the contents of different entries. + +2. GetEntryPositions() - calls Entry.GetPositions() for each entry. This can +return a dict containing entries that need updating. The key should be the +entry name and the value is a tuple (pos, size). This allows an entry to +provide the position and size for other entries. The default implementation +of GetEntryPositions() returns {}. + +3. PackEntries() - calls Entry.Pack() which figures out the position and +size of an entry. The 'current' image position is passed in, and the function +returns the position immediately after the entry being packed. The default +implementation of Pack() is usually sufficient. + +4. CheckSize() - checks that the contents of all the entries fits within +the image size. If the image does not have a defined size, the size is set +large enough to hold all the entries. + +5. CheckEntries() - checks that the entries do not overlap, nor extend +outside the image. + +6. ProcessEntryContents() - this calls Entry.ProcessContents() on each entry. +The default implementatoin does nothing. This can be overriden to adjust the +contents of an entry in some way. For example, it would be possible to create +an entry containing a hash of the contents of some other entries. At this +stage the position and size of entries should not be adjusted. + +7. BuildImage() - builds the image and writes it to a file. This is the final +step. + + +Automatic .dtsi inclusion +------------------------- + +It is sometimes inconvenient to add a 'binman' node to the .dts file for each +board. This can be done by using #include to bring in a common file. Another +approach supported by the U-Boot build system is to automatically include +a common header. You can then put the binman node (and anything else that is +specific to U-Boot, such as u-boot,dm-pre-reloc properies) in that header +file. + +Binman will search for the following files in arch/<arch>/dts: + + <dts>-u-boot.dtsi where <dts> is the base name of the .dts file + <CONFIG_SYS_SOC>-u-boot.dtsi + <CONFIG_SYS_CPU>-u-boot.dtsi + <CONFIG_SYS_VENDOR>-u-boot.dtsi + u-boot.dtsi + +U-Boot will only use the first one that it finds. If you need to include a +more general file you can do that from the more specific file using #include. +If you are having trouble figuring out what is going on, you can uncomment +the 'warning' line in scripts/Makefile.lib to see what it has found: + + # Uncomment for debugging + # $(warning binman_dtsi_options: $(binman_dtsi_options)) + + +Code coverage +------------- + +Binman is a critical tool and is designed to be very testable. Entry +implementations target 100% test coverage. Run 'binman -T' to check this. + +To enable Python test coverage on Debian-type distributions (e.g. Ubuntu): + + $ sudo apt-get install python-pip python-pytest + $ sudo pip install coverage + + +Advanced Features / Technical docs +---------------------------------- + +The behaviour of entries is defined by the Entry class. All other entries are +a subclass of this. An important subclass is Entry_blob which takes binary +data from a file and places it in the entry. In fact most entry types are +subclasses of Entry_blob. + +Each entry type is a separate file in the tools/binman/etype directory. Each +file contains a class called Entry_<type> where <type> is the entry type. +New entry types can be supported by adding new files in that directory. +These will automatically be detected by binman when needed. + +Entry properties are documented in entry.py. The entry subclasses are free +to change the values of properties to support special behaviour. For example, +when Entry_blob loads a file, it sets content_size to the size of the file. +Entry classes can adjust other entries. For example, an entry that knows +where other entries should be positioned can set up those entries' positions +so they don't need to be set in the binman decription. It can also adjust +entry contents. + +Most of the time such essoteric behaviour is not needed, but it can be +essential for complex images. + + +History / Credits +----------------- + +Binman takes a lot of inspiration from a Chrome OS tool called +'cros_bundle_firmware', which I wrote some years ago. That tool was based on +a reasonably simple and sound design but has expanded greatly over the +years. In particular its handling of x86 images is convoluted. + +Quite a few lessons have been learned which are hopefully be applied here. + + +Design notes +------------ + +On the face of it, a tool to create firmware images should be fairly simple: +just find all the input binaries and place them at the right place in the +image. The difficulty comes from the wide variety of input types (simple +flat binaries containing code, packaged data with various headers), packing +requirments (alignment, spacing, device boundaries) and other required +features such as hierarchical images. + +The design challenge is to make it easy to create simple images, while +allowing the more complex cases to be supported. For example, for most +images we don't much care exactly where each binary ends up, so we should +not have to specify that unnecessarily. + +New entry types should aim to provide simple usage where possible. If new +core features are needed, they can be added in the Entry base class. + + +To do +----- + +Some ideas: +- Fill out the device tree to include the final position and size of each + entry (since the input file may not always specify these) +- Use of-platdata to make the information available to code that is unable + to use device tree (such as a very small SPL image) +- Write an image map to a text file +- Allow easy building of images by specifying just the board name +- Produce a full Python binding for libfdt (for upstream) +- Add an option to decode an image into the constituent binaries +- Suppoort hierarchical images (packing of binaries into another binary + which is then placed in the image) +- Support building an image for a board (-b) more completely, with a + configurable build directory +- Consider making binman work with buildman, although if it is used in the + Makefile, this will be automatic +- Implement align-end + +-- +Simon Glass <sjg@chromium.org> +7/7/2016 diff --git a/tools/binman/binman b/tools/binman/binman new file mode 120000 index 0000000..979b7e4 --- /dev/null +++ b/tools/binman/binman @@ -0,0 +1 @@ +binman.py
\ No newline at end of file diff --git a/tools/binman/binman.py b/tools/binman/binman.py new file mode 100755 index 0000000..7fb67cb --- /dev/null +++ b/tools/binman/binman.py @@ -0,0 +1,114 @@ +#!/usr/bin/python + +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Creates binary images from input files controlled by a description +# + +"""See README for more information""" + +import os +import sys +import traceback +import unittest + +# Bring in the patman and dtoc libraries +our_path = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(our_path, '../patman')) +sys.path.append(os.path.join(our_path, '../dtoc')) + +# Also allow entry-type modules to be brought in from the etype directory. +sys.path.append(os.path.join(our_path, 'etype')) + +import cmdline +import command +import control + +def RunTests(): + """Run the functional tests and any embedded doctests""" + import entry_test + import fdt_test + import func_test + import test + import doctest + + result = unittest.TestResult() + for module in []: + suite = doctest.DocTestSuite(module) + suite.run(result) + + sys.argv = [sys.argv[0]] + for module in (func_test.TestFunctional, fdt_test.TestFdt, + entry_test.TestEntry): + suite = unittest.TestLoader().loadTestsFromTestCase(module) + suite.run(result) + + print result + for test, err in result.errors: + print test.id(), err + for test, err in result.failures: + print err + +def RunTestCoverage(): + """Run the tests and check that we get 100% coverage""" + # This uses the build output from sandbox_spl to get _libfdt.so + cmd = ('PYTHONPATH=%s/sandbox_spl/tools coverage run ' + '--include "tools/binman/*.py" --omit "*test*,*binman.py" ' + 'tools/binman/binman.py -t' % options.build_dir) + os.system(cmd) + stdout = command.Output('coverage', 'report') + coverage = stdout.splitlines()[-1].split(' ')[-1] + if coverage != '100%': + print stdout + print "Type 'coverage html' to get a report in htmlcov/index.html" + raise ValueError('Coverage error: %s, but should be 100%%' % coverage) + + +def RunBinman(options, args): + """Main entry point to binman once arguments are parsed + + Args: + options: Command-line options + args: Non-option arguments + """ + ret_code = 0 + + # For testing: This enables full exception traces. + #options.debug = True + + if not options.debug: + sys.tracebacklimit = 0 + + if options.test: + RunTests() + + elif options.test_coverage: + RunTestCoverage() + + elif options.full_help: + pager = os.getenv('PAGER') + if not pager: + pager = 'more' + fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), + 'README') + command.Run(pager, fname) + + else: + try: + ret_code = control.Binman(options, args) + except Exception as e: + print 'binman: %s' % e + if options.debug: + print + traceback.print_exc() + ret_code = 1 + return ret_code + + +if __name__ == "__main__": + (options, args) = cmdline.ParseArgs(sys.argv) + ret_code = RunBinman(options, args) + sys.exit(ret_code) diff --git a/tools/binman/cmdline.py b/tools/binman/cmdline.py new file mode 100644 index 0000000..233d5e1 --- /dev/null +++ b/tools/binman/cmdline.py @@ -0,0 +1,53 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Command-line parser for binman +# + +from optparse import OptionParser + +def ParseArgs(argv): + """Parse the binman command-line arguments + + Args: + argv: List of string arguments + Returns: + Tuple (options, args) with the command-line options and arugments. + options provides access to the options (e.g. option.debug) + args is a list of string arguments + """ + parser = OptionParser() + parser.add_option('-b', '--board', type='string', + help='Board name to build') + parser.add_option('-B', '--build-dir', type='string', default='b', + help='Directory containing the build output') + parser.add_option('-d', '--dt', type='string', + help='Configuration file (.dtb) to use') + parser.add_option('-D', '--debug', action='store_true', + help='Enabling debugging (provides a full traceback on error)') + parser.add_option('-I', '--indir', action='append', + help='Add a path to a directory to use for input files') + parser.add_option('-H', '--full-help', action='store_true', + default=False, help='Display the README file') + parser.add_option('-O', '--outdir', type='string', + action='store', help='Path to directory to use for intermediate and ' + 'output files') + parser.add_option('-p', '--preserve', action='store_true',\ + help='Preserve temporary output directory even if option -O is not ' + 'given') + parser.add_option('-t', '--test', action='store_true', + default=False, help='run tests') + parser.add_option('-T', '--test-coverage', action='store_true', + default=False, help='run tests and check for 100% coverage') + parser.add_option('-v', '--verbosity', default=1, + type='int', help='Control verbosity: 0=silent, 1=progress, 3=full, ' + '4=debug') + + parser.usage += """ + +Create images for a board from a set of binaries. It is controlled by a +description in the board device tree.""" + + return parser.parse_args(argv) diff --git a/tools/binman/control.py b/tools/binman/control.py new file mode 100644 index 0000000..e909678 --- /dev/null +++ b/tools/binman/control.py @@ -0,0 +1,118 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Creates binary images from input files controlled by a description +# + +from collections import OrderedDict +import os +import sys +import tools + +import command +import fdt_select +import fdt_util +from image import Image +import tout + +# List of images we plan to create +# Make this global so that it can be referenced from tests +images = OrderedDict() + +def _ReadImageDesc(binman_node): + """Read the image descriptions from the /binman node + + This normally produces a single Image object called 'image'. But if + multiple images are present, they will all be returned. + + Args: + binman_node: Node object of the /binman node + Returns: + OrderedDict of Image objects, each of which describes an image + """ + images = OrderedDict() + if 'multiple-images' in binman_node.props: + for node in binman_node.subnodes: + images[node.name] = Image(node.name, node) + else: + images['image'] = Image('image', binman_node) + return images + +def _FindBinmanNode(fdt): + """Find the 'binman' node in the device tree + + Args: + fdt: Fdt object to scan + Returns: + Node object of /binman node, or None if not found + """ + for node in fdt.GetRoot().subnodes: + if node.name == 'binman': + return node + return None + +def Binman(options, args): + """The main control code for binman + + This assumes that help and test options have already been dealt with. It + deals with the core task of building images. + + Args: + options: Command line options object + args: Command line arguments (list of strings) + """ + global images + + if options.full_help: + pager = os.getenv('PAGER') + if not pager: + pager = 'more' + fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), + 'README') + command.Run(pager, fname) + return 0 + + # Try to figure out which device tree contains our image description + if options.dt: + dtb_fname = options.dt + else: + board = options.board + if not board: + raise ValueError('Must provide a board to process (use -b <board>)') + board_pathname = os.path.join(options.build_dir, board) + dtb_fname = os.path.join(board_pathname, 'u-boot.dtb') + if not options.indir: + options.indir = ['.'] + options.indir.append(board_pathname) + + try: + tout.Init(options.verbosity) + try: + tools.SetInputDirs(options.indir) + tools.PrepareOutputDir(options.outdir, options.preserve) + fdt = fdt_select.FdtScan(dtb_fname) + node = _FindBinmanNode(fdt) + if not node: + raise ValueError("Device tree '%s' does not have a 'binman' " + "node" % dtb_fname) + images = _ReadImageDesc(node) + for image in images.values(): + # Perform all steps for this image, including checking and + # writing it. This means that errors found with a later + # image will be reported after earlier images are already + # completed and written, but that does not seem important. + image.GetEntryContents() + image.GetEntryPositions() + image.PackEntries() + image.CheckSize() + image.CheckEntries() + image.ProcessEntryContents() + image.BuildImage() + finally: + tools.FinaliseOutputDir() + finally: + tout.Uninit() + + return 0 diff --git a/tools/binman/entry_test.py b/tools/binman/entry_test.py new file mode 100644 index 0000000..8a9ae01 --- /dev/null +++ b/tools/binman/entry_test.py @@ -0,0 +1,27 @@ +# +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Test for the Entry class + +import collections +import unittest + +import entry + +class TestEntry(unittest.TestCase): + def testEntryContents(self): + """Test the Entry bass class""" + base_entry = entry.Entry(None, None, None, read_node=False) + self.assertEqual(True, base_entry.ObtainContents()) + + def testUnknownEntry(self): + """Test that unknown entry types are detected""" + Node = collections.namedtuple('Node', ['name', 'path']) + node = Node('invalid-name', 'invalid-path') + with self.assertRaises(ValueError) as e: + entry.Entry.Create(None, node, node.name) + self.assertIn("Unknown entry type 'invalid-name' in node " + "'invalid-path'", str(e.exception)) diff --git a/tools/binman/etype/_testing.py b/tools/binman/etype/_testing.py new file mode 100644 index 0000000..1783098 --- /dev/null +++ b/tools/binman/etype/_testing.py @@ -0,0 +1,26 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for testing purposes. Not used in real images. +# + +from entry import Entry +import fdt_util +import tools + +class Entry__testing(Entry): + def __init__(self, image, etype, node): + Entry.__init__(self, image, etype, node) + + def ObtainContents(self): + self.data = 'a' + self.contents_size = len(self.data) + return True + + def ReadContents(self): + return True + + def GetPositions(self): + return {'invalid-entry': [1, 2]} diff --git a/tools/binman/etype/blob.py b/tools/binman/etype/blob.py new file mode 100644 index 0000000..def2164 --- /dev/null +++ b/tools/binman/etype/blob.py @@ -0,0 +1,37 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for blobs, which are binary objects read from files +# + +from entry import Entry +import fdt_util +import tools + +class Entry_blob(Entry): + def __init__(self, image, etype, node): + Entry.__init__(self, image, etype, node) + self._filename = fdt_util.GetString(self._node, "filename", self.etype) + + def ObtainContents(self): + self._filename = self.GetDefaultFilename() + self._pathname = tools.GetInputFilename(self._filename) + self.ReadContents() + return True + + def ReadContents(self): + with open(self._pathname) as fd: + # We assume the data is small enough to fit into memory. If this + # is used for large filesystem image that might not be true. + # In that case, Image.BuildImage() could be adjusted to use a + # new Entry method which can read in chunks. Then we could copy + # the data in chunks and avoid reading it all at once. For now + # this seems like an unnecessary complication. + self.data = fd.read() + self.contents_size = len(self.data) + return True + + def GetDefaultFilename(self): + return self._filename diff --git a/tools/binman/etype/entry.py b/tools/binman/etype/entry.py new file mode 100644 index 0000000..67c5734 --- /dev/null +++ b/tools/binman/etype/entry.py @@ -0,0 +1,200 @@ +# Copyright (c) 2016 Google, Inc +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Base class for all entries +# + +# importlib was introduced in Python 2.7 but there was a report of it not +# working in 2.7.12, so we work around this: +# http://lists.denx.de/pipermail/u-boot/2016-October/269729.html +try: + import importlib + have_importlib = True +except: + have_importlib = False + +import fdt_util +import tools + +modules = {} + +class Entry(object): + """An Entry in the image + + An entry corresponds to a single node in the device-tree description + of the image. Each entry ends up being a part of the final image. + Entries can be placed either right next to each other, or with padding + between them. The type of the entry determines the data that is in it. + + This class is not used by itself. All entry objects are subclasses of + Entry. + + Attributes: + image: The image containing this entry + node: The node that created this entry + pos: Absolute position of entry within the image, None if not known + size: Entry size in bytes, None if not known + contents_size: Size of contents in bytes, 0 by default + align: Entry start position alignment, or None + align_size: Entry size alignment, or None + align_end: Entry end position alignment, or None + pad_before: Number of pad bytes before the contents, 0 if none + pad_after: Number of pad bytes after the contents, 0 if none + data: Contents of entry (string of bytes) + """ + def __init__(self, image, etype, node, read_node=True): + self.image = image + self.etype = etype + self._node = node + self.pos = None + self.size = None + self.contents_size = 0 + self.align = None + self.align_size = None + self.align_end = None + self.pad_before = 0 + self.pad_after = 0 + self.pos_unset = False + if read_node: + self.ReadNode() + + @staticmethod + def Create(image, node, etype=None): + """Create a new entry for a node. + + Args: + image: Image object containing this node + node: Node object containing information about the entry to create + etype: Entry type to use, or None to work it out (used for tests) + + Returns: + A new Entry object of the correct type (a subclass of Entry) + """ + if not etype: + etype = fdt_util.GetString(node, 'type', node.name) + module_name = etype.replace('-', '_') + module = modules.get(module_name) + + # Import the module if we have not already done so. + if not module: + try: + if have_importlib: + module = importlib.import_module(module_name) + else: + module = __import__(module_name) + except ImportError: + raise ValueError("Unknown entry type '%s' in node '%s'" % + (etype, node.path)) + modules[module_name] = module + + # Call its constructor to get the object we want. + obj = getattr(module, 'Entry_%s' % module_name) + return obj(image, etype, node) + + def ReadNode(self): + """Read entry information from the node + + This reads all the fields we recognise from the node, ready for use. + """ + self.pos = fdt_util.GetInt(self._node, 'pos') + self.size = fdt_util.GetInt(self._node, 'size') + self.align = fdt_util.GetInt(self._node, 'align') + if tools.NotPowerOfTwo(self.align): + raise ValueError("Node '%s': Alignment %s must be a power of two" % + (self._node.path, self.align)) + self.pad_before = fdt_util.GetInt(self._node, 'pad-before', 0) + self.pad_after = fdt_util.GetInt(self._node, 'pad-after', 0) + self.align_size = fdt_util.GetInt(self._node, 'align-size') + if tools.NotPowerOfTwo(self.align_size): + raise ValueError("Node '%s': Alignment size %s must be a power " + "of two" % (self._node.path, self.align_size)) + self.align_end = fdt_util.GetInt(self._node, 'align-end') + self.pos_unset = fdt_util.GetBool(self._node, 'pos-unset') + + def ObtainContents(self): + """Figure out the contents of an entry. + + Returns: + True if the contents were found, False if another call is needed + after the other entries are processed. + """ + # No contents by default: subclasses can implement this + return True + + def Pack(self, pos): + """Figure out how to pack the entry into the image + + Most of the time the entries are not fully specified. There may be + an alignment but no size. In that case we take the size from the + contents of the entry. + + If an entry has no hard-coded position, it will be placed at @pos. + + Once this function is complete, both the position and size of the + entry will be know. + + Args: + Current image position pointer + + Returns: + New image position pointer (after this entry) + """ + if self.pos is None: + if self.pos_unset: + self.Raise('No position set with pos-unset: should another ' + 'entry provide this correct position?') + self.pos = tools.Align(pos, self.align) + needed = self.pad_before + self.contents_size + self.pad_after + needed = tools.Align(needed, self.align_size) + size = self.size + if not size: + size = needed + new_pos = self.pos + size + aligned_pos = tools.Align(new_pos, self.align_end) + if aligned_pos != new_pos: + size = aligned_pos - self.pos + new_pos = aligned_pos + + if not self.size: + self.size = size + + if self.size < needed: + self.Raise("Entry contents size is %#x (%d) but entry size is " + "%#x (%d)" % (needed, needed, self.size, self.size)) + # Check that the alignment is correct. It could be wrong if the + # and pos or size values were provided (i.e. not calculated), but + # conflict with the provided alignment values + if self.size != tools.Align(self.size, self.align_size): + self.Raise("Size %#x (%d) does not match align-size %#x (%d)" % + (self.size, self.size, self.align_size, self.align_size)) + if self.pos != tools.Align(self.pos, self.align): + self.Raise("Position %#x (%d) does not match align %#x (%d)" % + (self.pos, self.pos, self.align, self.align)) + + return new_pos + + def Raise(self, msg): + """Convenience function to raise an error referencing a node""" + raise ValueError("Node '%s': %s" % (self._node.path, msg)) + + def GetPath(self): + """Get the path of a node + + Returns: + Full path of the node for this entry + """ + return self._node.path + + def GetData(self): + return self.data + + def GetPositions(self): + return {} + + def SetPositionSize(self, pos, size): + self.pos = pos + self.size = size + + def ProcessContents(self): + pass diff --git a/tools/binman/etype/intel_cmc.py b/tools/binman/etype/intel_cmc.py new file mode 100644 index 0000000..9bce8ae --- /dev/null +++ b/tools/binman/etype/intel_cmc.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Chip Microcode binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_cmc(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'cmc.bin' diff --git a/tools/binman/etype/intel_descriptor.py b/tools/binman/etype/intel_descriptor.py new file mode 100644 index 0000000..7f4ea0b --- /dev/null +++ b/tools/binman/etype/intel_descriptor.py @@ -0,0 +1,55 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for 'u-boot' +# + +import struct + +from entry import Entry +from blob import Entry_blob + +FD_SIGNATURE = struct.pack('<L', 0x0ff0a55a) +MAX_REGIONS = 5 + +(REGION_DESCRIPTOR, REGION_BIOS, REGION_ME, REGION_GBE, + REGION_PDATA) = range(5) + +class Region: + def __init__(self, data, frba, region_num): + pos = frba + region_num * 4 + val = struct.unpack('<L', data[pos:pos + 4])[0] + self.base = (val & 0xfff) << 12 + self.limit = ((val & 0x0fff0000) >> 4) | 0xfff + self.size = self.limit - self.base + 1 + +class Entry_intel_descriptor(Entry_blob): + """Intel flash descriptor block (4KB) + + This is placed at the start of flash and provides information about + the SPI flash regions. In particular it provides the base address and + size of the ME region, allowing us to place the ME binary in the right + place. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self._regions = [] + + def GetDefaultFilename(self): + return 'descriptor.bin' + + def GetPositions(self): + pos = self.data.find(FD_SIGNATURE) + if pos == -1: + self.Raise('Cannot find FD signature') + flvalsig, flmap0, flmap1, flmap2 = struct.unpack('<LLLL', + self.data[pos:pos + 16]) + frba = ((flmap0 >> 16) & 0xff) << 4 + for i in range(MAX_REGIONS): + self._regions.append(Region(self.data, frba, i)) + + # Set the offset for ME only, for now, since the others are not used + return {'intel-me': [self._regions[REGION_ME].base, + self._regions[REGION_ME].size]} diff --git a/tools/binman/etype/intel_fsp.py b/tools/binman/etype/intel_fsp.py new file mode 100644 index 0000000..d75be5b --- /dev/null +++ b/tools/binman/etype/intel_fsp.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Firmware Support Package binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_fsp(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'fsp.bin' diff --git a/tools/binman/etype/intel_me.py b/tools/binman/etype/intel_me.py new file mode 100644 index 0000000..45ab50c --- /dev/null +++ b/tools/binman/etype/intel_me.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Management Engine binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_me(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'me.bin' diff --git a/tools/binman/etype/intel_mrc.py b/tools/binman/etype/intel_mrc.py new file mode 100644 index 0000000..f6cedb7 --- /dev/null +++ b/tools/binman/etype/intel_mrc.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for Intel Memory Reference Code binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_mrc(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'mrc.bin' diff --git a/tools/binman/etype/intel_vga.py b/tools/binman/etype/intel_vga.py new file mode 100644 index 0000000..d8f270b --- /dev/null +++ b/tools/binman/etype/intel_vga.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for x86 VGA ROM binary blob +# + +from entry import Entry +from blob import Entry_blob + +class Entry_intel_vga(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'vga.bin' diff --git a/tools/binman/etype/u_boot.py b/tools/binman/etype/u_boot.py new file mode 100644 index 0000000..1fcff73 --- /dev/null +++ b/tools/binman/etype/u_boot.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot binary +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.bin' diff --git a/tools/binman/etype/u_boot_dtb.py b/tools/binman/etype/u_boot_dtb.py new file mode 100644 index 0000000..1122c95 --- /dev/null +++ b/tools/binman/etype/u_boot_dtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot device tree +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_dtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.dtb' diff --git a/tools/binman/etype/u_boot_dtb_with_ucode.py b/tools/binman/etype/u_boot_dtb_with_ucode.py new file mode 100644 index 0000000..fc02c67 --- /dev/null +++ b/tools/binman/etype/u_boot_dtb_with_ucode.py @@ -0,0 +1,78 @@ +# Copyright (c) 2016 Google, Inc +## Written by Simon Glass <sjg@chromium.org> + +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot device tree with the microcode removed +# + +import fdt_select +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_dtb_with_ucode(Entry_blob): + """A U-Boot device tree file, with the microcode removed + + See Entry_u_boot_ucode for full details of the 3 entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.ucode_data = '' + self.collate = False + self.ucode_offset = None + self.ucode_size = None + + def GetDefaultFilename(self): + return 'u-boot.dtb' + + def ObtainContents(self): + Entry_blob.ObtainContents(self) + + # If the image does not need microcode, there is nothing to do + ucode_dest_entry = self.image.FindEntryType('u-boot-spl-with-ucode-ptr') + if not ucode_dest_entry or not ucode_dest_entry.target_pos: + ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr') + if not ucode_dest_entry or not ucode_dest_entry.target_pos: + return True + + # Create a new file to hold the copied device tree + dtb_name = 'u-boot-dtb-with-ucode.dtb' + fname = tools.GetOutputFilename(dtb_name) + with open(fname, 'wb') as fd: + fd.write(self.data) + + # Remove the microcode + fdt = fdt_select.FdtScan(fname) + fdt.Scan() + ucode = fdt.GetNode('/microcode') + if not ucode: + raise self.Raise("No /microcode node found in '%s'" % fname) + + # There's no need to collate it (move all microcode into one place) + # if we only have one chunk of microcode. + self.collate = len(ucode.subnodes) > 1 + for node in ucode.subnodes: + data_prop = node.props.get('data') + if data_prop: + self.ucode_data += ''.join(data_prop.bytes) + if not self.collate: + poffset = data_prop.GetOffset() + if poffset is None: + # We cannot obtain a property offset. Collate instead. + self.collate = True + else: + # Find the offset in the device tree of the ucode data + self.ucode_offset = poffset + 12 + self.ucode_size = len(data_prop.bytes) + if self.collate: + prop = node.DeleteProp('data') + if self.collate: + fdt.Pack() + fdt.Flush() + + # Make this file the contents of this entry + self._pathname = fname + self.ReadContents() + return True diff --git a/tools/binman/etype/u_boot_img.py b/tools/binman/etype/u_boot_img.py new file mode 100644 index 0000000..744f1b4 --- /dev/null +++ b/tools/binman/etype/u_boot_img.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for U-Boot binary +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_img(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot.img' diff --git a/tools/binman/etype/u_boot_nodtb.py b/tools/binman/etype/u_boot_nodtb.py new file mode 100644 index 0000000..3721c3b --- /dev/null +++ b/tools/binman/etype/u_boot_nodtb.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for 'u-boot-nodtb.bin' +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_nodtb(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot-nodtb.bin' diff --git a/tools/binman/etype/u_boot_spl.py b/tools/binman/etype/u_boot_spl.py new file mode 100644 index 0000000..68b0148 --- /dev/null +++ b/tools/binman/etype/u_boot_spl.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for spl/u-boot-spl.bin +# + +from entry import Entry +from blob import Entry_blob + +class Entry_u_boot_spl(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-spl.bin' diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py new file mode 100644 index 0000000..c005f28 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_bss_pad.py @@ -0,0 +1,26 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for BSS padding for spl/u-boot-spl.bin. This padding +# can be added after the SPL binary to ensure that anything concatenated +# to it will appear to SPL to be at the end of BSS rather than the start. +# + +import command +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_spl_bss_pad(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def ObtainContents(self): + fname = tools.GetInputFilename('spl/u-boot-spl') + args = [['nm', fname], ['grep', '__bss_size']] + out = command.RunPipe(args, capture=True).stdout.splitlines() + bss_size = int(out[0].split()[0], 16) + self.data = chr(0) * bss_size + self.contents_size = bss_size diff --git a/tools/binman/etype/u_boot_spl_with_ucode_ptr.py b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py new file mode 100644 index 0000000..764c282 --- /dev/null +++ b/tools/binman/etype/u_boot_spl_with_ucode_ptr.py @@ -0,0 +1,28 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for an SPL binary with an embedded microcode pointer +# + +import struct + +import command +from entry import Entry +from blob import Entry_blob +from u_boot_with_ucode_ptr import Entry_u_boot_with_ucode_ptr +import tools + +class Entry_u_boot_spl_with_ucode_ptr(Entry_u_boot_with_ucode_ptr): + """U-Boot SPL with embedded microcode pointer + + See Entry_u_boot_ucode for full details of the entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.elf_fname = 'spl/u-boot-spl' + + def GetDefaultFilename(self): + return 'spl/u-boot-spl.bin' diff --git a/tools/binman/etype/u_boot_ucode.py b/tools/binman/etype/u_boot_ucode.py new file mode 100644 index 0000000..8fe27ac --- /dev/null +++ b/tools/binman/etype/u_boot_ucode.py @@ -0,0 +1,84 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for a U-Boot binary with an embedded microcode pointer +# + +from entry import Entry +from blob import Entry_blob +import tools + +class Entry_u_boot_ucode(Entry_blob): + """U-Boot microcode block + + U-Boot on x86 needs a single block of microcode. This is collected from + the various microcode update nodes in the device tree. It is also unable + to read the microcode from the device tree on platforms that use FSP + (Firmware Support Package) binaries, because the API requires that the + microcode is supplied before there is any SRAM available to use (i.e. + the FSP sets up the SRAM / cache-as-RAM but does so in the call that + requires the microcode!). To keep things simple, all x86 platforms handle + microcode the same way in U-Boot (even non-FSP platforms). This is that + a table is placed at _dt_ucode_base_size containing the base address and + size of the microcode. This is either passed to the FSP (for FSP + platforms), or used to set up the microcode (for non-FSP platforms). + This all happens in the build system since it is the only way to get + the microcode into a single blob and accessible without SRAM. + + There are two cases to handle. If there is only one microcode blob in + the device tree, then the ucode pointer it set to point to that. This + entry (u-boot-ucode) is empty. If there is more than one update, then + this entry holds the concatenation of all updates, and the device tree + entry (u-boot-dtb-with-ucode) is updated to remove the microcode. This + last step ensures that that the microcode appears in one contiguous + block in the image and is not unnecessarily duplicated in the device + tree. It is referred to as 'collation' here. + + Entry types that have a part to play in handling microcode: + + Entry_u_boot_with_ucode_ptr: + Contains u-boot-nodtb.bin (i.e. U-Boot without the device tree). + It updates it with the address and size of the microcode so that + U-Boot can find it early on start-up. + Entry_u_boot_dtb_with_ucode: + Contains u-boot.dtb. It stores the microcode in a + 'self.ucode_data' property, which is then read by this class to + obtain the microcode if needed. If collation is performed, it + removes the microcode from the device tree. + Entry_u_boot_ucode: + This class. If collation is enabled it reads the microcode from + the Entry_u_boot_dtb_with_ucode entry, and uses it as the + contents of this entry. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def ObtainContents(self): + # If the image does not need microcode, there is nothing to do + ucode_dest_entry = self.image.FindEntryType('u-boot-with-ucode-ptr') + if ucode_dest_entry and not ucode_dest_entry.target_pos: + self.data = '' + return True + + # Get the microcode from the device tree entry + fdt_entry = self.image.FindEntryType('u-boot-dtb-with-ucode') + if not fdt_entry or not fdt_entry.ucode_data: + return False + + if not fdt_entry.collate: + # This section can be empty + self.data = '' + return True + + # Write it out to a file + dtb_name = 'u-boot-ucode.bin' + fname = tools.GetOutputFilename(dtb_name) + with open(fname, 'wb') as fd: + fd.write(fdt_entry.ucode_data) + + self._pathname = fname + self.ReadContents() + + return True diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py new file mode 100644 index 0000000..6f01adb --- /dev/null +++ b/tools/binman/etype/u_boot_with_ucode_ptr.py @@ -0,0 +1,87 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for a U-Boot binary with an embedded microcode pointer +# + +import struct + +import command +from entry import Entry +from blob import Entry_blob +import fdt_util +import tools + +class Entry_u_boot_with_ucode_ptr(Entry_blob): + """U-Boot with embedded microcode pointer + + See Entry_u_boot_ucode for full details of the 3 entries involved in this + process. + """ + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + self.elf_fname = 'u-boot' + self.target_pos = None + + def GetDefaultFilename(self): + return 'u-boot-nodtb.bin' + + def ObtainContents(self): + # Figure out where to put the microcode pointer + fname = tools.GetInputFilename(self.elf_fname) + args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']] + out = (command.RunPipe(args, capture=True, raise_on_error=False). + stdout.splitlines()) + if len(out) == 1: + self.target_pos = int(out[0].split()[0], 16) + elif not fdt_util.GetBool(self._node, 'optional-ucode'): + self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot') + + return Entry_blob.ObtainContents(self) + + def ProcessContents(self): + # If the image does not need microcode, there is nothing to do + if not self.target_pos: + return + + # Get the position of the microcode + ucode_entry = self.image.FindEntryType('u-boot-ucode') + if not ucode_entry: + self.Raise('Cannot find microcode region u-boot-ucode') + + # Check the target pos is in the image. If it is not, then U-Boot is + # being linked incorrectly, or is being placed at the wrong position + # in the image. + # + # The image must be set up so that U-Boot is placed at the + # flash address to which it is linked. For example, if + # CONFIG_SYS_TEXT_BASE is 0xfff00000, and the ROM is 8MB, then + # the U-Boot region must start at position 7MB in the image. In this + # case the ROM starts at 0xff800000, so the position of the first + # entry in the image corresponds to that. + if (self.target_pos < self.pos or + self.target_pos >= self.pos + self.size): + self.Raise('Microcode pointer _dt_ucode_base_size at %08x is ' + 'outside the image ranging from %08x to %08x' % + (self.target_pos, self.pos, self.pos + self.size)) + + # Get the microcode, either from u-boot-ucode or u-boot-dtb-with-ucode. + # If we have left the microcode in the device tree, then it will be + # in the former. If we extracted the microcode from the device tree + # and collated it in one place, it will be in the latter. + if ucode_entry.size: + pos, size = ucode_entry.pos, ucode_entry.size + else: + dtb_entry = self.image.FindEntryType('u-boot-dtb-with-ucode') + if not dtb_entry: + self.Raise('Cannot find microcode region u-boot-dtb-with-ucode') + pos = dtb_entry.pos + dtb_entry.ucode_offset + size = dtb_entry.ucode_size + + # Write the microcode position and size into the entry + pos_and_size = struct.pack('<2L', pos, size) + self.target_pos -= self.pos + self.data = (self.data[:self.target_pos] + pos_and_size + + self.data[self.target_pos + 8:]) diff --git a/tools/binman/etype/x86_start16.py b/tools/binman/etype/x86_start16.py new file mode 100644 index 0000000..a44ea68 --- /dev/null +++ b/tools/binman/etype/x86_start16.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for the 16-bit x86 start-up code for U-Boot +# + +from entry import Entry +from blob import Entry_blob + +class Entry_x86_start16(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'u-boot-x86-16bit.bin' diff --git a/tools/binman/etype/x86_start16_spl.py b/tools/binman/etype/x86_start16_spl.py new file mode 100644 index 0000000..3679a43 --- /dev/null +++ b/tools/binman/etype/x86_start16_spl.py @@ -0,0 +1,17 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Entry-type module for the 16-bit x86 start-up code for U-Boot SPL +# + +from entry import Entry +from blob import Entry_blob + +class Entry_x86_start16_spl(Entry_blob): + def __init__(self, image, etype, node): + Entry_blob.__init__(self, image, etype, node) + + def GetDefaultFilename(self): + return 'spl/u-boot-x86-16bit-spl.bin' diff --git a/tools/binman/fdt_test.py b/tools/binman/fdt_test.py new file mode 100644 index 0000000..1d9494e --- /dev/null +++ b/tools/binman/fdt_test.py @@ -0,0 +1,48 @@ +# +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Test for the fdt modules + +import os +import sys +import tempfile +import unittest + +from fdt_select import FdtScan +import fdt_util +import tools + +class TestFdt(unittest.TestCase): + @classmethod + def setUpClass(self): + self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) + self._indir = tempfile.mkdtemp(prefix='binmant.') + tools.PrepareOutputDir(self._indir, True) + + def TestFile(self, fname): + return os.path.join(self._binman_dir, 'test', fname) + + def GetCompiled(self, fname): + return fdt_util.EnsureCompiled(self.TestFile(fname)) + + def _DeleteProp(self, fdt): + node = fdt.GetNode('/microcode/update@0') + node.DeleteProp('data') + + def testFdtNormal(self): + fname = self.GetCompiled('34_x86_ucode.dts') + fdt = FdtScan(fname) + self._DeleteProp(fdt) + + def testFdtFallback(self): + fname = self.GetCompiled('34_x86_ucode.dts') + fdt = FdtScan(fname, True) + fdt.GetProp('/microcode/update@0', 'data') + self.assertEqual('fred', + fdt.GetProp('/microcode/update@0', 'none', default='fred')) + self.assertEqual('12345678 12345679', + fdt.GetProp('/microcode/update@0', 'data', typespec='x')) + self._DeleteProp(fdt) diff --git a/tools/binman/func_test.py b/tools/binman/func_test.py new file mode 100644 index 0000000..740fa9e --- /dev/null +++ b/tools/binman/func_test.py @@ -0,0 +1,822 @@ +# +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# To run a single test, change to this directory, and: +# +# python -m unittest func_test.TestFunctional.testHelp + +from optparse import OptionParser +import os +import shutil +import struct +import sys +import tempfile +import unittest + +import binman +import cmdline +import command +import control +import entry +import fdt_select +import fdt_util +import tools +import tout + +# Contents of test files, corresponding to different entry types +U_BOOT_DATA = '1234' +U_BOOT_IMG_DATA = 'img' +U_BOOT_SPL_DATA = '567' +BLOB_DATA = '89' +ME_DATA = '0abcd' +VGA_DATA = 'vga' +U_BOOT_DTB_DATA = 'udtb' +X86_START16_DATA = 'start16' +U_BOOT_NODTB_DATA = 'nodtb with microcode pointer somewhere in here' +FSP_DATA = 'fsp' +CMC_DATA = 'cmc' + +class TestFunctional(unittest.TestCase): + """Functional tests for binman + + Most of these use a sample .dts file to build an image and then check + that it looks correct. The sample files are in the test/ subdirectory + and are numbered. + + For each entry type a very small test file is created using fixed + string contents. This makes it easy to test that things look right, and + debug problems. + + In some cases a 'real' file must be used - these are also supplied in + the test/ diurectory. + """ + @classmethod + def setUpClass(self): + # Handle the case where argv[0] is 'python' + self._binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) + self._binman_pathname = os.path.join(self._binman_dir, 'binman') + + # Create a temporary directory for input files + self._indir = tempfile.mkdtemp(prefix='binmant.') + + # Create some test files + TestFunctional._MakeInputFile('u-boot.bin', U_BOOT_DATA) + TestFunctional._MakeInputFile('u-boot.img', U_BOOT_IMG_DATA) + TestFunctional._MakeInputFile('spl/u-boot-spl.bin', U_BOOT_SPL_DATA) + TestFunctional._MakeInputFile('blobfile', BLOB_DATA) + TestFunctional._MakeInputFile('me.bin', ME_DATA) + TestFunctional._MakeInputFile('vga.bin', VGA_DATA) + TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) + TestFunctional._MakeInputFile('u-boot-x86-16bit.bin', X86_START16_DATA) + TestFunctional._MakeInputFile('u-boot-nodtb.bin', U_BOOT_NODTB_DATA) + TestFunctional._MakeInputFile('fsp.bin', FSP_DATA) + TestFunctional._MakeInputFile('cmc.bin', CMC_DATA) + self._output_setup = False + + # ELF file with a '_dt_ucode_base_size' symbol + with open(self.TestFile('u_boot_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('u-boot', fd.read()) + + # Intel flash descriptor file + with open(self.TestFile('descriptor.bin')) as fd: + TestFunctional._MakeInputFile('descriptor.bin', fd.read()) + + @classmethod + def tearDownClass(self): + """Remove the temporary input directory and its contents""" + if self._indir: + shutil.rmtree(self._indir) + self._indir = None + + def setUp(self): + # Enable this to turn on debugging output + # tout.Init(tout.DEBUG) + command.test_result = None + + def tearDown(self): + """Remove the temporary output directory""" + tools._FinaliseForTest() + + def _RunBinman(self, *args, **kwargs): + """Run binman using the command line + + Args: + Arguments to pass, as a list of strings + kwargs: Arguments to pass to Command.RunPipe() + """ + result = command.RunPipe([[self._binman_pathname] + list(args)], + capture=True, capture_stderr=True, raise_on_error=False) + if result.return_code and kwargs.get('raise_on_error', True): + raise Exception("Error running '%s': %s" % (' '.join(args), + result.stdout + result.stderr)) + return result + + def _DoBinman(self, *args): + """Run binman using directly (in the same process) + + Args: + Arguments to pass, as a list of strings + Returns: + Return value (0 for success) + """ + (options, args) = cmdline.ParseArgs(list(args)) + options.pager = 'binman-invalid-pager' + options.build_dir = self._indir + + # For testing, you can force an increase in verbosity here + # options.verbosity = tout.DEBUG + return control.Binman(options, args) + + def _DoTestFile(self, fname): + """Run binman with a given test file + + Args: + fname: Device tree source filename to use (e.g. 05_simple.dts) + """ + return self._DoBinman('-p', '-I', self._indir, + '-d', self.TestFile(fname)) + + def _SetupDtb(self, fname, outfile='u-boot.dtb'): + """Set up a new test device-tree file + + The given file is compiled and set up as the device tree to be used + for ths test. + + Args: + fname: Filename of .dts file to read + outfile: Output filename for compiled device tree binary + + Returns: + Contents of device tree binary + """ + if not self._output_setup: + tools.PrepareOutputDir(self._indir, True) + self._output_setup = True + dtb = fdt_util.EnsureCompiled(self.TestFile(fname)) + with open(dtb) as fd: + data = fd.read() + TestFunctional._MakeInputFile(outfile, data) + return data + + def _DoReadFileDtb(self, fname, use_real_dtb=False): + """Run binman and return the resulting image + + This runs binman with a given test file and then reads the resulting + output file. It is a shortcut function since most tests need to do + these steps. + + Raises an assertion failure if binman returns a non-zero exit code. + + Args: + fname: Device tree source filename to use (e.g. 05_simple.dts) + use_real_dtb: True to use the test file as the contents of + the u-boot-dtb entry. Normally this is not needed and the + test contents (the U_BOOT_DTB_DATA string) can be used. + But in some test we need the real contents. + + Returns: + Tuple: + Resulting image contents + Device tree contents + """ + dtb_data = None + # Use the compiled test file as the u-boot-dtb input + if use_real_dtb: + dtb_data = self._SetupDtb(fname) + + try: + retcode = self._DoTestFile(fname) + self.assertEqual(0, retcode) + + # Find the (only) image, read it and return its contents + image = control.images['image'] + fname = tools.GetOutputFilename('image.bin') + self.assertTrue(os.path.exists(fname)) + with open(fname) as fd: + return fd.read(), dtb_data + finally: + # Put the test file back + if use_real_dtb: + TestFunctional._MakeInputFile('u-boot.dtb', U_BOOT_DTB_DATA) + + def _DoReadFile(self, fname, use_real_dtb=False): + """Helper function which discards the device-tree binary""" + return self._DoReadFileDtb(fname, use_real_dtb)[0] + + @classmethod + def _MakeInputFile(self, fname, contents): + """Create a new test input file, creating directories as needed + + Args: + fname: Filenaem to create + contents: File contents to write in to the file + Returns: + Full pathname of file created + """ + pathname = os.path.join(self._indir, fname) + dirname = os.path.dirname(pathname) + if dirname and not os.path.exists(dirname): + os.makedirs(dirname) + with open(pathname, 'wb') as fd: + fd.write(contents) + return pathname + + @classmethod + def TestFile(self, fname): + return os.path.join(self._binman_dir, 'test', fname) + + def AssertInList(self, grep_list, target): + """Assert that at least one of a list of things is in a target + + Args: + grep_list: List of strings to check + target: Target string + """ + for grep in grep_list: + if grep in target: + return + self.fail("Error: '%' not found in '%s'" % (grep_list, target)) + + def CheckNoGaps(self, entries): + """Check that all entries fit together without gaps + + Args: + entries: List of entries to check + """ + pos = 0 + for entry in entries.values(): + self.assertEqual(pos, entry.pos) + pos += entry.size + + def GetFdtLen(self, dtb): + """Get the totalsize field from a device tree binary + + Args: + dtb: Device tree binary contents + + Returns: + Total size of device tree binary, from the header + """ + return struct.unpack('>L', dtb[4:8])[0] + + def testRun(self): + """Test a basic run with valid args""" + result = self._RunBinman('-h') + + def testFullHelp(self): + """Test that the full help is displayed with -H""" + result = self._RunBinman('-H') + help_file = os.path.join(self._binman_dir, 'README') + self.assertEqual(len(result.stdout), os.path.getsize(help_file)) + self.assertEqual(0, len(result.stderr)) + self.assertEqual(0, result.return_code) + + def testFullHelpInternal(self): + """Test that the full help is displayed with -H""" + try: + command.test_result = command.CommandResult() + result = self._DoBinman('-H') + help_file = os.path.join(self._binman_dir, 'README') + finally: + command.test_result = None + + def testHelp(self): + """Test that the basic help is displayed with -h""" + result = self._RunBinman('-h') + self.assertTrue(len(result.stdout) > 200) + self.assertEqual(0, len(result.stderr)) + self.assertEqual(0, result.return_code) + + # Not yet available. + def testBoard(self): + """Test that we can run it with a specific board""" + self._SetupDtb('05_simple.dts', 'sandbox/u-boot.dtb') + TestFunctional._MakeInputFile('sandbox/u-boot.bin', U_BOOT_DATA) + result = self._DoBinman('-b', 'sandbox') + self.assertEqual(0, result) + + def testNeedBoard(self): + """Test that we get an error when no board ius supplied""" + with self.assertRaises(ValueError) as e: + result = self._DoBinman() + self.assertIn("Must provide a board to process (use -b <board>)", + str(e.exception)) + + def testMissingDt(self): + """Test that an invalid device tree file generates an error""" + with self.assertRaises(Exception) as e: + self._RunBinman('-d', 'missing_file') + # We get one error from libfdt, and a different one from fdtget. + self.AssertInList(["Couldn't open blob from 'missing_file'", + 'No such file or directory'], str(e.exception)) + + def testBrokenDt(self): + """Test that an invalid device tree source file generates an error + + Since this is a source file it should be compiled and the error + will come from the device-tree compiler (dtc). + """ + with self.assertRaises(Exception) as e: + self._RunBinman('-d', self.TestFile('01_invalid.dts')) + self.assertIn("FATAL ERROR: Unable to parse input tree", + str(e.exception)) + + def testMissingNode(self): + """Test that a device tree without a 'binman' node generates an error""" + with self.assertRaises(Exception) as e: + self._DoBinman('-d', self.TestFile('02_missing_node.dts')) + self.assertIn("does not have a 'binman' node", str(e.exception)) + + def testEmpty(self): + """Test that an empty binman node works OK (i.e. does nothing)""" + result = self._RunBinman('-d', self.TestFile('03_empty.dts')) + self.assertEqual(0, len(result.stderr)) + self.assertEqual(0, result.return_code) + + def testInvalidEntry(self): + """Test that an invalid entry is flagged""" + with self.assertRaises(Exception) as e: + result = self._RunBinman('-d', + self.TestFile('04_invalid_entry.dts')) + #print e.exception + self.assertIn("Unknown entry type 'not-a-valid-type' in node " + "'/binman/not-a-valid-type'", str(e.exception)) + + def testSimple(self): + """Test a simple binman with a single file""" + data = self._DoReadFile('05_simple.dts') + self.assertEqual(U_BOOT_DATA, data) + + def testDual(self): + """Test that we can handle creating two images + + This also tests image padding. + """ + retcode = self._DoTestFile('06_dual_image.dts') + self.assertEqual(0, retcode) + + image = control.images['image1'] + self.assertEqual(len(U_BOOT_DATA), image._size) + fname = tools.GetOutputFilename('image1.bin') + self.assertTrue(os.path.exists(fname)) + with open(fname) as fd: + data = fd.read() + self.assertEqual(U_BOOT_DATA, data) + + image = control.images['image2'] + self.assertEqual(3 + len(U_BOOT_DATA) + 5, image._size) + fname = tools.GetOutputFilename('image2.bin') + self.assertTrue(os.path.exists(fname)) + with open(fname) as fd: + data = fd.read() + self.assertEqual(U_BOOT_DATA, data[3:7]) + self.assertEqual(chr(0) * 3, data[:3]) + self.assertEqual(chr(0) * 5, data[7:]) + + def testBadAlign(self): + """Test that an invalid alignment value is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('07_bad_align.dts') + self.assertIn("Node '/binman/u-boot': Alignment 23 must be a power " + "of two", str(e.exception)) + + def testPackSimple(self): + """Test that packing works as expected""" + retcode = self._DoTestFile('08_pack.dts') + self.assertEqual(0, retcode) + self.assertIn('image', control.images) + image = control.images['image'] + entries = image._entries + self.assertEqual(5, len(entries)) + + # First u-boot + self.assertIn('u-boot', entries) + entry = entries['u-boot'] + self.assertEqual(0, entry.pos) + self.assertEqual(len(U_BOOT_DATA), entry.size) + + # Second u-boot, aligned to 16-byte boundary + self.assertIn('u-boot-align', entries) + entry = entries['u-boot-align'] + self.assertEqual(16, entry.pos) + self.assertEqual(len(U_BOOT_DATA), entry.size) + + # Third u-boot, size 23 bytes + self.assertIn('u-boot-size', entries) + entry = entries['u-boot-size'] + self.assertEqual(20, entry.pos) + self.assertEqual(len(U_BOOT_DATA), entry.contents_size) + self.assertEqual(23, entry.size) + + # Fourth u-boot, placed immediate after the above + self.assertIn('u-boot-next', entries) + entry = entries['u-boot-next'] + self.assertEqual(43, entry.pos) + self.assertEqual(len(U_BOOT_DATA), entry.size) + + # Fifth u-boot, placed at a fixed position + self.assertIn('u-boot-fixed', entries) + entry = entries['u-boot-fixed'] + self.assertEqual(61, entry.pos) + self.assertEqual(len(U_BOOT_DATA), entry.size) + + self.assertEqual(65, image._size) + + def testPackExtra(self): + """Test that extra packing feature works as expected""" + retcode = self._DoTestFile('09_pack_extra.dts') + + self.assertEqual(0, retcode) + self.assertIn('image', control.images) + image = control.images['image'] + entries = image._entries + self.assertEqual(5, len(entries)) + + # First u-boot with padding before and after + self.assertIn('u-boot', entries) + entry = entries['u-boot'] + self.assertEqual(0, entry.pos) + self.assertEqual(3, entry.pad_before) + self.assertEqual(3 + 5 + len(U_BOOT_DATA), entry.size) + + # Second u-boot has an aligned size, but it has no effect + self.assertIn('u-boot-align-size-nop', entries) + entry = entries['u-boot-align-size-nop'] + self.assertEqual(12, entry.pos) + self.assertEqual(4, entry.size) + + # Third u-boot has an aligned size too + self.assertIn('u-boot-align-size', entries) + entry = entries['u-boot-align-size'] + self.assertEqual(16, entry.pos) + self.assertEqual(32, entry.size) + + # Fourth u-boot has an aligned end + self.assertIn('u-boot-align-end', entries) + entry = entries['u-boot-align-end'] + self.assertEqual(48, entry.pos) + self.assertEqual(16, entry.size) + + # Fifth u-boot immediately afterwards + self.assertIn('u-boot-align-both', entries) + entry = entries['u-boot-align-both'] + self.assertEqual(64, entry.pos) + self.assertEqual(64, entry.size) + + self.CheckNoGaps(entries) + self.assertEqual(128, image._size) + + def testPackAlignPowerOf2(self): + """Test that invalid entry alignment is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('10_pack_align_power2.dts') + self.assertIn("Node '/binman/u-boot': Alignment 5 must be a power " + "of two", str(e.exception)) + + def testPackAlignSizePowerOf2(self): + """Test that invalid entry size alignment is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('11_pack_align_size_power2.dts') + self.assertIn("Node '/binman/u-boot': Alignment size 55 must be a " + "power of two", str(e.exception)) + + def testPackInvalidAlign(self): + """Test detection of an position that does not match its alignment""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('12_pack_inv_align.dts') + self.assertIn("Node '/binman/u-boot': Position 0x5 (5) does not match " + "align 0x4 (4)", str(e.exception)) + + def testPackInvalidSizeAlign(self): + """Test that invalid entry size alignment is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('13_pack_inv_size_align.dts') + self.assertIn("Node '/binman/u-boot': Size 0x5 (5) does not match " + "align-size 0x4 (4)", str(e.exception)) + + def testPackOverlap(self): + """Test that overlapping regions are detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('14_pack_overlap.dts') + self.assertIn("Node '/binman/u-boot-align': Position 0x3 (3) overlaps " + "with previous entry '/binman/u-boot' ending at 0x4 (4)", + str(e.exception)) + + def testPackEntryOverflow(self): + """Test that entries that overflow their size are detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('15_pack_overflow.dts') + self.assertIn("Node '/binman/u-boot': Entry contents size is 0x4 (4) " + "but entry size is 0x3 (3)", str(e.exception)) + + def testPackImageOverflow(self): + """Test that entries which overflow the image size are detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('16_pack_image_overflow.dts') + self.assertIn("Image '/binman': contents size 0x4 (4) exceeds image " + "size 0x3 (3)", str(e.exception)) + + def testPackImageSize(self): + """Test that the image size can be set""" + retcode = self._DoTestFile('17_pack_image_size.dts') + self.assertEqual(0, retcode) + self.assertIn('image', control.images) + image = control.images['image'] + self.assertEqual(7, image._size) + + def testPackImageSizeAlign(self): + """Test that image size alignemnt works as expected""" + retcode = self._DoTestFile('18_pack_image_align.dts') + self.assertEqual(0, retcode) + self.assertIn('image', control.images) + image = control.images['image'] + self.assertEqual(16, image._size) + + def testPackInvalidImageAlign(self): + """Test that invalid image alignment is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('19_pack_inv_image_align.dts') + self.assertIn("Image '/binman': Size 0x7 (7) does not match " + "align-size 0x8 (8)", str(e.exception)) + + def testPackAlignPowerOf2(self): + """Test that invalid image alignment is detected""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('20_pack_inv_image_align_power2.dts') + self.assertIn("Image '/binman': Alignment size 131 must be a power of " + "two", str(e.exception)) + + def testImagePadByte(self): + """Test that the image pad byte can be specified""" + data = self._DoReadFile('21_image_pad.dts') + self.assertEqual(U_BOOT_SPL_DATA + (chr(0xff) * 9) + U_BOOT_DATA, data) + + def testImageName(self): + """Test that image files can be named""" + retcode = self._DoTestFile('22_image_name.dts') + self.assertEqual(0, retcode) + image = control.images['image1'] + fname = tools.GetOutputFilename('test-name') + self.assertTrue(os.path.exists(fname)) + + image = control.images['image2'] + fname = tools.GetOutputFilename('test-name.xx') + self.assertTrue(os.path.exists(fname)) + + def testBlobFilename(self): + """Test that generic blobs can be provided by filename""" + data = self._DoReadFile('23_blob.dts') + self.assertEqual(BLOB_DATA, data) + + def testPackSorted(self): + """Test that entries can be sorted""" + data = self._DoReadFile('24_sorted.dts') + self.assertEqual(chr(0) * 5 + U_BOOT_SPL_DATA + chr(0) * 2 + + U_BOOT_DATA, data) + + def testPackZeroPosition(self): + """Test that an entry at position 0 is not given a new position""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('25_pack_zero_size.dts') + self.assertIn("Node '/binman/u-boot-spl': Position 0x0 (0) overlaps " + "with previous entry '/binman/u-boot' ending at 0x4 (4)", + str(e.exception)) + + def testPackUbootDtb(self): + """Test that a device tree can be added to U-Boot""" + data = self._DoReadFile('26_pack_u_boot_dtb.dts') + self.assertEqual(U_BOOT_NODTB_DATA + U_BOOT_DTB_DATA, data) + + def testPackX86RomNoSize(self): + """Test that the end-at-4gb property requires a size property""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('27_pack_4gb_no_size.dts') + self.assertIn("Image '/binman': Image size must be provided when " + "using end-at-4gb", str(e.exception)) + + def testPackX86RomOutside(self): + """Test that the end-at-4gb property checks for position boundaries""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('28_pack_4gb_outside.dts') + self.assertIn("Node '/binman/u-boot': Position 0x0 (0) is outside " + "the image starting at 0xfffffff0 (4294967280)", + str(e.exception)) + + def testPackX86Rom(self): + """Test that a basic x86 ROM can be created""" + data = self._DoReadFile('29_x86-rom.dts') + self.assertEqual(U_BOOT_DATA + chr(0) * 3 + U_BOOT_SPL_DATA + + chr(0) * 6, data) + + def testPackX86RomMeNoDesc(self): + """Test that an invalid Intel descriptor entry is detected""" + TestFunctional._MakeInputFile('descriptor.bin', '') + with self.assertRaises(ValueError) as e: + self._DoTestFile('31_x86-rom-me.dts') + self.assertIn("Node '/binman/intel-descriptor': Cannot find FD " + "signature", str(e.exception)) + + def testPackX86RomBadDesc(self): + """Test that the Intel requires a descriptor entry""" + with self.assertRaises(ValueError) as e: + self._DoTestFile('30_x86-rom-me-no-desc.dts') + self.assertIn("Node '/binman/intel-me': No position set with " + "pos-unset: should another entry provide this correct " + "position?", str(e.exception)) + + def testPackX86RomMe(self): + """Test that an x86 ROM with an ME region can be created""" + data = self._DoReadFile('31_x86-rom-me.dts') + self.assertEqual(ME_DATA, data[0x1000:0x1000 + len(ME_DATA)]) + + def testPackVga(self): + """Test that an image with a VGA binary can be created""" + data = self._DoReadFile('32_intel-vga.dts') + self.assertEqual(VGA_DATA, data[:len(VGA_DATA)]) + + def testPackStart16(self): + """Test that an image with an x86 start16 region can be created""" + data = self._DoReadFile('33_x86-start16.dts') + self.assertEqual(X86_START16_DATA, data[:len(X86_START16_DATA)]) + + def testPackUbootMicrocode(self): + """Test that x86 microcode can be handled correctly + + We expect to see the following in the image, in order: + u-boot-nodtb.bin with a microcode pointer inserted at the correct + place + u-boot.dtb with the microcode removed + the microcode + """ + data = self._DoReadFile('34_x86_ucode.dts', True) + + # Now check the device tree has no microcode + second = data[len(U_BOOT_NODTB_DATA):] + fname = tools.GetOutputFilename('test.dtb') + with open(fname, 'wb') as fd: + fd.write(second) + fdt = fdt_select.FdtScan(fname) + ucode = fdt.GetNode('/microcode') + self.assertTrue(ucode) + for node in ucode.subnodes: + self.assertFalse(node.props.get('data')) + + fdt_len = self.GetFdtLen(second) + third = second[fdt_len:] + + # Check that the microcode appears immediately after the Fdt + # This matches the concatenation of the data properties in + # the /microcode/update@xxx nodes in x86_ucode.dts. + ucode_data = struct.pack('>4L', 0x12345678, 0x12345679, 0xabcd0000, + 0x78235609) + self.assertEqual(ucode_data, third[:len(ucode_data)]) + ucode_pos = len(U_BOOT_NODTB_DATA) + fdt_len + + # Check that the microcode pointer was inserted. It should match the + # expected position and size + pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, + len(ucode_data)) + first = data[:len(U_BOOT_NODTB_DATA)] + self.assertEqual('nodtb with microcode' + pos_and_size + + ' somewhere in here', first) + + def _RunPackUbootSingleMicrocode(self, collate): + """Test that x86 microcode can be handled correctly + + We expect to see the following in the image, in order: + u-boot-nodtb.bin with a microcode pointer inserted at the correct + place + u-boot.dtb with the microcode + an empty microcode region + """ + # We need the libfdt library to run this test since only that allows + # finding the offset of a property. This is required by + # Entry_u_boot_dtb_with_ucode.ObtainContents(). + if not fdt_select.have_libfdt: + return + data = self._DoReadFile('35_x86_single_ucode.dts', True) + + second = data[len(U_BOOT_NODTB_DATA):] + + fdt_len = self.GetFdtLen(second) + third = second[fdt_len:] + second = second[:fdt_len] + + if not collate: + ucode_data = struct.pack('>2L', 0x12345678, 0x12345679) + self.assertIn(ucode_data, second) + ucode_pos = second.find(ucode_data) + len(U_BOOT_NODTB_DATA) + + # Check that the microcode pointer was inserted. It should match the + # expected position and size + pos_and_size = struct.pack('<2L', 0xfffffe00 + ucode_pos, + len(ucode_data)) + first = data[:len(U_BOOT_NODTB_DATA)] + self.assertEqual('nodtb with microcode' + pos_and_size + + ' somewhere in here', first) + + def testPackUbootSingleMicrocode(self): + """Test that x86 microcode can be handled correctly with fdt_normal. + """ + self._RunPackUbootSingleMicrocode(False) + + def testPackUbootSingleMicrocodeFallback(self): + """Test that x86 microcode can be handled correctly with fdt_fallback. + + This only supports collating the microcode. + """ + try: + old_val = fdt_select.UseFallback(True) + self._RunPackUbootSingleMicrocode(True) + finally: + fdt_select.UseFallback(old_val) + + def testUBootImg(self): + """Test that u-boot.img can be put in a file""" + data = self._DoReadFile('36_u_boot_img.dts') + self.assertEqual(U_BOOT_IMG_DATA, data) + + def testNoMicrocode(self): + """Test that a missing microcode region is detected""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('37_x86_no_ucode.dts', True) + self.assertIn("Node '/binman/u-boot-dtb-with-ucode': No /microcode " + "node found in ", str(e.exception)) + + def testMicrocodeWithoutNode(self): + """Test that a missing u-boot-dtb-with-ucode node is detected""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('38_x86_ucode_missing_node.dts', True) + self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " + "microcode region u-boot-dtb-with-ucode", str(e.exception)) + + def testMicrocodeWithoutNode2(self): + """Test that a missing u-boot-ucode node is detected""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('39_x86_ucode_missing_node2.dts', True) + self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot find " + "microcode region u-boot-ucode", str(e.exception)) + + def testMicrocodeWithoutPtrInElf(self): + """Test that a U-Boot binary without the microcode symbol is detected""" + # ELF file without a '_dt_ucode_base_size' symbol + if not fdt_select.have_libfdt: + return + try: + with open(self.TestFile('u_boot_no_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('u-boot', fd.read()) + + with self.assertRaises(ValueError) as e: + self._RunPackUbootSingleMicrocode(False) + self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Cannot locate " + "_dt_ucode_base_size symbol in u-boot", str(e.exception)) + + finally: + # Put the original file back + with open(self.TestFile('u_boot_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('u-boot', fd.read()) + + def testMicrocodeNotInImage(self): + """Test that microcode must be placed within the image""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('40_x86_ucode_not_in_image.dts', True) + self.assertIn("Node '/binman/u-boot-with-ucode-ptr': Microcode " + "pointer _dt_ucode_base_size at fffffe14 is outside the " + "image ranging from 00000000 to 0000002e", str(e.exception)) + + def testWithoutMicrocode(self): + """Test that we can cope with an image without microcode (e.g. qemu)""" + with open(self.TestFile('u_boot_no_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('u-boot', fd.read()) + data, dtb = self._DoReadFileDtb('44_x86_optional_ucode.dts', True) + + # Now check the device tree has no microcode + self.assertEqual(U_BOOT_NODTB_DATA, data[:len(U_BOOT_NODTB_DATA)]) + second = data[len(U_BOOT_NODTB_DATA):] + + fdt_len = self.GetFdtLen(second) + self.assertEqual(dtb, second[:fdt_len]) + + used_len = len(U_BOOT_NODTB_DATA) + fdt_len + third = data[used_len:] + self.assertEqual(chr(0) * (0x200 - used_len), third) + + def testUnknownPosSize(self): + """Test that microcode must be placed within the image""" + with self.assertRaises(ValueError) as e: + self._DoReadFile('41_unknown_pos_size.dts', True) + self.assertIn("Image '/binman': Unable to set pos/size for unknown " + "entry 'invalid-entry'", str(e.exception)) + + def testPackFsp(self): + """Test that an image with a FSP binary can be created""" + data = self._DoReadFile('42_intel-fsp.dts') + self.assertEqual(FSP_DATA, data[:len(FSP_DATA)]) + + def testPackCmc(self): + """Test that an image with a FSP binary can be created""" + data = self._DoReadFile('43_intel-cmc.dts') + self.assertEqual(CMC_DATA, data[:len(CMC_DATA)]) diff --git a/tools/binman/image.py b/tools/binman/image.py new file mode 100644 index 0000000..07fc930 --- /dev/null +++ b/tools/binman/image.py @@ -0,0 +1,229 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass <sjg@chromium.org> +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Class for an image, the output of binman +# + +from collections import OrderedDict +from operator import attrgetter + +import entry +from entry import Entry +import fdt_util +import tools + +class Image: + """A Image, representing an output from binman + + An image is comprised of a collection of entries each containing binary + data. The image size must be large enough to hold all of this data. + + This class implements the various operations needed for images. + + Atrtributes: + _node: Node object that contains the image definition in device tree + _name: Image name + _size: Image size in bytes, or None if not known yet + _align_size: Image size alignment, or None + _pad_before: Number of bytes before the first entry starts. This + effectively changes the place where entry position 0 starts + _pad_after: Number of bytes after the last entry ends. The last + entry will finish on or before this boundary + _pad_byte: Byte to use to pad the image where there is no entry + _filename: Output filename for image + _sort: True if entries should be sorted by position, False if they + must be in-order in the device tree description + _skip_at_start: Number of bytes before the first entry starts. These + effecively adjust the starting position of entries. For example, + if _pad_before is 16, then the first entry would start at 16. + An entry with pos = 20 would in fact be written at position 4 + in the image file. + _end_4gb: Indicates that the image ends at the 4GB boundary. This is + used for x86 images, which want to use positions such that a + memory address (like 0xff800000) is the first entry position. + This causes _skip_at_start to be set to the starting memory + address. + _entries: OrderedDict() of entries + """ + def __init__(self, name, node): + self._node = node + self._name = name + self._size = None + self._align_size = None + self._pad_before = 0 + self._pad_after = 0 + self._pad_byte = 0 + self._filename = '%s.bin' % self._name + self._sort = False + self._skip_at_start = 0 + self._end_4gb = False + self._entries = OrderedDict() + + self._ReadNode() + self._ReadEntries() + + def _ReadNode(self): + """Read properties from the image node""" + self._size = fdt_util.GetInt(self._node, 'size') + self._align_size = fdt_util.GetInt(self._node, 'align-size') + if tools.NotPowerOfTwo(self._align_size): + self._Raise("Alignment size %s must be a power of two" % + self._align_size) + self._pad_before = fdt_util.GetInt(self._node, 'pad-before', 0) + self._pad_after = fdt_util.GetInt(self._node, 'pad-after', 0) + self._pad_byte = fdt_util.GetInt(self._node, 'pad-byte', 0) + filename = fdt_util.GetString(self._node, 'filename') + if filename: + self._filename = filename + self._sort = fdt_util.GetBool(self._node, 'sort-by-pos') + self._end_4gb = fdt_util.GetBool(self._node, 'end-at-4gb') + if self._end_4gb and not self._size: + self._Raise("Image size must be provided when using end-at-4gb") + if self._end_4gb: + self._skip_at_start = 0x100000000 - self._size + + def CheckSize(self): + """Check that the image contents does not exceed its size, etc.""" + contents_size = 0 + for entry in self._entries.values(): + contents_size = max(contents_size, entry.pos + entry.size) + + contents_size -= self._skip_at_start + + size = self._size + if not size: + size = self._pad_before + contents_size + self._pad_after + size = tools.Align(size, self._align_size) + + if self._size and contents_size > self._size: + self._Raise("contents size %#x (%d) exceeds image size %#x (%d)" % + (contents_size, contents_size, self._size, self._size)) + if not self._size: + self._size = size + if self._size != tools.Align(self._size, self._align_size): + self._Raise("Size %#x (%d) does not match align-size %#x (%d)" % + (self._size, self._size, self._align_size, self._align_size)) + + def _Raise(self, msg): + """Raises an error for this image + + Args: + msg: Error message to use in the raise string + Raises: + ValueError() + """ + raise ValueError("Image '%s': %s" % (self._node.path, msg)) + + def _ReadEntries(self): + for node in self._node.subnodes: + self._entries[node.name] = Entry.Create(self, node) + + def FindEntryType(self, etype): + """Find an entry type in the image + + Args: + etype: Entry type to find + Returns: + entry matching that type, or None if not found + """ + for entry in self._entries.values(): + if entry.etype == etype: + return entry + return None + + def GetEntryContents(self): + """Call ObtainContents() for each entry + + This calls each entry's ObtainContents() a few times until they all + return True. We stop calling an entry's function once it returns + True. This allows the contents of one entry to depend on another. + + After 3 rounds we give up since it's likely an error. + """ + todo = self._entries.values() + for passnum in range(3): + next_todo = [] + for entry in todo: + if not entry.ObtainContents(): + next_todo.append(entry) + todo = next_todo + if not todo: + break + + def _SetEntryPosSize(self, name, pos, size): + """Set the position and size of an entry + + Args: + name: Entry name to update + pos: New position + size: New size + """ + entry = self._entries.get(name) + if not entry: + self._Raise("Unable to set pos/size for unknown entry '%s'" % name) + entry.SetPositionSize(self._skip_at_start + pos, size) + + def GetEntryPositions(self): + """Handle entries that want to set the position/size of other entries + + This calls each entry's GetPositions() method. If it returns a list + of entries to update, it updates them. + """ + for entry in self._entries.values(): + pos_dict = entry.GetPositions() + for name, info in pos_dict.iteritems(): + self._SetEntryPosSize(name, *info) + + def PackEntries(self): + """Pack all entries into the image""" + pos = self._skip_at_start + for entry in self._entries.values(): + pos = entry.Pack(pos) + + def _SortEntries(self): + """Sort entries by position""" + entries = sorted(self._entries.values(), key=lambda entry: entry.pos) + self._entries.clear() + for entry in entries: + self._entries[entry._node.name] = entry + + def CheckEntries(self): + """Check that entries do not overlap or extend outside the image""" + if self._sort: + self._SortEntries() + pos = 0 + prev_name = 'None' + for entry in self._entries.values(): + if (entry.pos < self._skip_at_start or + entry.pos >= self._skip_at_start + self._size): + entry.Raise("Position %#x (%d) is outside the image starting " + "at %#x (%d)" % + (entry.pos, entry.pos, self._skip_at_start, + self._skip_at_start)) + if entry.pos < pos: + entry.Raise("Position %#x (%d) overlaps with previous entry '%s' " + "ending at %#x (%d)" % + (entry.pos, entry.pos, prev_name, pos, pos)) + pos = entry.pos + entry.size + prev_name = entry.GetPath() + + def ProcessEntryContents(self): + """Call the ProcessContents() method for each entry + + This is intended to adjust the contents as needed by the entry type. + """ + for entry in self._entries.values(): + entry.ProcessContents() + + def BuildImage(self): + """Write the image to a file""" + fname = tools.GetOutputFilename(self._filename) + with open(fname, 'wb') as fd: + fd.write(chr(self._pad_byte) * self._size) + + for entry in self._entries.values(): + data = entry.GetData() + fd.seek(self._pad_before + entry.pos - self._skip_at_start) + fd.write(data) diff --git a/tools/binman/test/01_invalid.dts b/tools/binman/test/01_invalid.dts new file mode 100644 index 0000000..7d00455 --- /dev/null +++ b/tools/binman/test/01_invalid.dts @@ -0,0 +1,5 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; diff --git a/tools/binman/test/02_missing_node.dts b/tools/binman/test/02_missing_node.dts new file mode 100644 index 0000000..3a51ec2 --- /dev/null +++ b/tools/binman/test/02_missing_node.dts @@ -0,0 +1,6 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; +}; diff --git a/tools/binman/test/03_empty.dts b/tools/binman/test/03_empty.dts new file mode 100644 index 0000000..493c9a0 --- /dev/null +++ b/tools/binman/test/03_empty.dts @@ -0,0 +1,9 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + }; +}; diff --git a/tools/binman/test/04_invalid_entry.dts b/tools/binman/test/04_invalid_entry.dts new file mode 100644 index 0000000..b043455 --- /dev/null +++ b/tools/binman/test/04_invalid_entry.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + not-a-valid-type { + }; + }; +}; diff --git a/tools/binman/test/05_simple.dts b/tools/binman/test/05_simple.dts new file mode 100644 index 0000000..3771aa2 --- /dev/null +++ b/tools/binman/test/05_simple.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + }; +}; diff --git a/tools/binman/test/06_dual_image.dts b/tools/binman/test/06_dual_image.dts new file mode 100644 index 0000000..78be16f --- /dev/null +++ b/tools/binman/test/06_dual_image.dts @@ -0,0 +1,22 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + multiple-images; + image1 { + u-boot { + }; + }; + + image2 { + pad-before = <3>; + pad-after = <5>; + + u-boot { + }; + }; + }; +}; diff --git a/tools/binman/test/07_bad_align.dts b/tools/binman/test/07_bad_align.dts new file mode 100644 index 0000000..123bb13 --- /dev/null +++ b/tools/binman/test/07_bad_align.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + align = <23>; + }; + }; +}; diff --git a/tools/binman/test/08_pack.dts b/tools/binman/test/08_pack.dts new file mode 100644 index 0000000..dc63d99 --- /dev/null +++ b/tools/binman/test/08_pack.dts @@ -0,0 +1,30 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + u-boot-align { + type = "u-boot"; + align = <16>; + }; + + u-boot-size { + type = "u-boot"; + size = <23>; + }; + + u-boot-next { + type = "u-boot"; + }; + + u-boot-fixed { + type = "u-boot"; + pos = <61>; + }; + }; +}; diff --git a/tools/binman/test/09_pack_extra.dts b/tools/binman/test/09_pack_extra.dts new file mode 100644 index 0000000..0765707 --- /dev/null +++ b/tools/binman/test/09_pack_extra.dts @@ -0,0 +1,35 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + pad-before = <3>; + pad-after = <5>; + }; + + u-boot-align-size-nop { + type = "u-boot"; + align-size = <4>; + }; + + u-boot-align-size { + type = "u-boot"; + align = <16>; + align-size = <32>; + }; + + u-boot-align-end { + type = "u-boot"; + align-end = <64>; + }; + + u-boot-align-both { + type = "u-boot"; + align= <64>; + align-end = <128>; + }; + }; +}; diff --git a/tools/binman/test/10_pack_align_power2.dts b/tools/binman/test/10_pack_align_power2.dts new file mode 100644 index 0000000..8f6253a --- /dev/null +++ b/tools/binman/test/10_pack_align_power2.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + align = <5>; + }; + }; +}; diff --git a/tools/binman/test/11_pack_align_size_power2.dts b/tools/binman/test/11_pack_align_size_power2.dts new file mode 100644 index 0000000..04f7672 --- /dev/null +++ b/tools/binman/test/11_pack_align_size_power2.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + align-size = <55>; + }; + }; +}; diff --git a/tools/binman/test/12_pack_inv_align.dts b/tools/binman/test/12_pack_inv_align.dts new file mode 100644 index 0000000..1d9d80a --- /dev/null +++ b/tools/binman/test/12_pack_inv_align.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + pos = <5>; + align = <4>; + }; + }; +}; diff --git a/tools/binman/test/13_pack_inv_size_align.dts b/tools/binman/test/13_pack_inv_size_align.dts new file mode 100644 index 0000000..dfafa13 --- /dev/null +++ b/tools/binman/test/13_pack_inv_size_align.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + size = <5>; + align-size = <4>; + }; + }; +}; diff --git a/tools/binman/test/14_pack_overlap.dts b/tools/binman/test/14_pack_overlap.dts new file mode 100644 index 0000000..611cfd9 --- /dev/null +++ b/tools/binman/test/14_pack_overlap.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + u-boot-align { + type = "u-boot"; + pos = <3>; + }; + }; +}; diff --git a/tools/binman/test/15_pack_overflow.dts b/tools/binman/test/15_pack_overflow.dts new file mode 100644 index 0000000..6f65433 --- /dev/null +++ b/tools/binman/test/15_pack_overflow.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + size = <3>; + }; + }; +}; diff --git a/tools/binman/test/16_pack_image_overflow.dts b/tools/binman/test/16_pack_image_overflow.dts new file mode 100644 index 0000000..6ae66f3 --- /dev/null +++ b/tools/binman/test/16_pack_image_overflow.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <3>; + + u-boot { + }; + }; +}; diff --git a/tools/binman/test/17_pack_image_size.dts b/tools/binman/test/17_pack_image_size.dts new file mode 100644 index 0000000..2360eb5 --- /dev/null +++ b/tools/binman/test/17_pack_image_size.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <7>; + + u-boot { + }; + }; +}; diff --git a/tools/binman/test/18_pack_image_align.dts b/tools/binman/test/18_pack_image_align.dts new file mode 100644 index 0000000..16cd2a4 --- /dev/null +++ b/tools/binman/test/18_pack_image_align.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + align-size = <16>; + + u-boot { + }; + }; +}; diff --git a/tools/binman/test/19_pack_inv_image_align.dts b/tools/binman/test/19_pack_inv_image_align.dts new file mode 100644 index 0000000..e5ee87b --- /dev/null +++ b/tools/binman/test/19_pack_inv_image_align.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <7>; + align-size = <8>; + + u-boot { + }; + }; +}; diff --git a/tools/binman/test/20_pack_inv_image_align_power2.dts b/tools/binman/test/20_pack_inv_image_align_power2.dts new file mode 100644 index 0000000..a428c4b --- /dev/null +++ b/tools/binman/test/20_pack_inv_image_align_power2.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + align-size = <131>; + + u-boot { + }; + }; +}; diff --git a/tools/binman/test/21_image_pad.dts b/tools/binman/test/21_image_pad.dts new file mode 100644 index 0000000..daf8385 --- /dev/null +++ b/tools/binman/test/21_image_pad.dts @@ -0,0 +1,16 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + pad-byte = <0xff>; + u-boot-spl { + }; + + u-boot { + pos = <12>; + }; + }; +}; diff --git a/tools/binman/test/22_image_name.dts b/tools/binman/test/22_image_name.dts new file mode 100644 index 0000000..94fc069 --- /dev/null +++ b/tools/binman/test/22_image_name.dts @@ -0,0 +1,21 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + multiple-images; + image1 { + filename = "test-name"; + u-boot { + }; + }; + + image2 { + filename = "test-name.xx"; + u-boot { + }; + }; + }; +}; diff --git a/tools/binman/test/23_blob.dts b/tools/binman/test/23_blob.dts new file mode 100644 index 0000000..7dcff69 --- /dev/null +++ b/tools/binman/test/23_blob.dts @@ -0,0 +1,12 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + blob { + filename = "blobfile"; + }; + }; +}; diff --git a/tools/binman/test/24_sorted.dts b/tools/binman/test/24_sorted.dts new file mode 100644 index 0000000..9f4151c --- /dev/null +++ b/tools/binman/test/24_sorted.dts @@ -0,0 +1,17 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + u-boot { + pos = <10>; + }; + + u-boot-spl { + pos = <5>; + }; + }; +}; diff --git a/tools/binman/test/25_pack_zero_size.dts b/tools/binman/test/25_pack_zero_size.dts new file mode 100644 index 0000000..7d2baad --- /dev/null +++ b/tools/binman/test/25_pack_zero_size.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot { + }; + + u-boot-spl { + pos = <0>; + }; + }; +}; diff --git a/tools/binman/test/26_pack_u_boot_dtb.dts b/tools/binman/test/26_pack_u_boot_dtb.dts new file mode 100644 index 0000000..2707a73 --- /dev/null +++ b/tools/binman/test/26_pack_u_boot_dtb.dts @@ -0,0 +1,14 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-nodtb { + }; + + u-boot-dtb { + }; + }; +}; diff --git a/tools/binman/test/27_pack_4gb_no_size.dts b/tools/binman/test/27_pack_4gb_no_size.dts new file mode 100644 index 0000000..e0b6519 --- /dev/null +++ b/tools/binman/test/27_pack_4gb_no_size.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + u-boot { + pos = <0xfffffff0>; + }; + + u-boot-spl { + pos = <0xfffffff7>; + }; + }; +}; diff --git a/tools/binman/test/28_pack_4gb_outside.dts b/tools/binman/test/28_pack_4gb_outside.dts new file mode 100644 index 0000000..ff468c7 --- /dev/null +++ b/tools/binman/test/28_pack_4gb_outside.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <16>; + u-boot { + pos = <0>; + }; + + u-boot-spl { + pos = <0xfffffff7>; + }; + }; +}; diff --git a/tools/binman/test/29_x86-rom.dts b/tools/binman/test/29_x86-rom.dts new file mode 100644 index 0000000..075ede3 --- /dev/null +++ b/tools/binman/test/29_x86-rom.dts @@ -0,0 +1,19 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <16>; + u-boot { + pos = <0xfffffff0>; + }; + + u-boot-spl { + pos = <0xfffffff7>; + }; + }; +}; diff --git a/tools/binman/test/30_x86-rom-me-no-desc.dts b/tools/binman/test/30_x86-rom-me-no-desc.dts new file mode 100644 index 0000000..4578f66 --- /dev/null +++ b/tools/binman/test/30_x86-rom-me-no-desc.dts @@ -0,0 +1,15 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <16>; + intel-me { + pos-unset; + }; + }; +}; diff --git a/tools/binman/test/31_x86-rom-me.dts b/tools/binman/test/31_x86-rom-me.dts new file mode 100644 index 0000000..b484ab3 --- /dev/null +++ b/tools/binman/test/31_x86-rom-me.dts @@ -0,0 +1,18 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x800000>; + intel-descriptor { + }; + + intel-me { + pos-unset; + }; + }; +}; diff --git a/tools/binman/test/32_intel-vga.dts b/tools/binman/test/32_intel-vga.dts new file mode 100644 index 0000000..1790833 --- /dev/null +++ b/tools/binman/test/32_intel-vga.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + + intel-vga { + }; + }; +}; diff --git a/tools/binman/test/33_x86-start16.dts b/tools/binman/test/33_x86-start16.dts new file mode 100644 index 0000000..2e279de --- /dev/null +++ b/tools/binman/test/33_x86-start16.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + + x86-start16 { + }; + }; +}; diff --git a/tools/binman/test/34_x86_ucode.dts b/tools/binman/test/34_x86_ucode.dts new file mode 100644 index 0000000..64a6c2c --- /dev/null +++ b/tools/binman/test/34_x86_ucode.dts @@ -0,0 +1,29 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + + u-boot-dtb-with-ucode { + }; + + u-boot-ucode { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + update@1 { + data = <0xabcd0000 0x78235609>; + }; + }; +}; diff --git a/tools/binman/test/35_x86_single_ucode.dts b/tools/binman/test/35_x86_single_ucode.dts new file mode 100644 index 0000000..973e97f --- /dev/null +++ b/tools/binman/test/35_x86_single_ucode.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + + u-boot-dtb-with-ucode { + }; + + u-boot-ucode { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + }; +}; diff --git a/tools/binman/test/36_u_boot_img.dts b/tools/binman/test/36_u_boot_img.dts new file mode 100644 index 0000000..aa5a3fe --- /dev/null +++ b/tools/binman/test/36_u_boot_img.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + u-boot-img { + }; + }; +}; diff --git a/tools/binman/test/37_x86_no_ucode.dts b/tools/binman/test/37_x86_no_ucode.dts new file mode 100644 index 0000000..9e12156 --- /dev/null +++ b/tools/binman/test/37_x86_no_ucode.dts @@ -0,0 +1,20 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + + u-boot-dtb-with-ucode { + }; + + u-boot-ucode { + }; + }; +}; diff --git a/tools/binman/test/38_x86_ucode_missing_node.dts b/tools/binman/test/38_x86_ucode_missing_node.dts new file mode 100644 index 0000000..d6cf0d8 --- /dev/null +++ b/tools/binman/test/38_x86_ucode_missing_node.dts @@ -0,0 +1,26 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + + u-boot-ucode { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + update@1 { + data = <0xabcd0000 0x78235609>; + }; + }; +}; diff --git a/tools/binman/test/39_x86_ucode_missing_node2.dts b/tools/binman/test/39_x86_ucode_missing_node2.dts new file mode 100644 index 0000000..b7e26c5 --- /dev/null +++ b/tools/binman/test/39_x86_ucode_missing_node2.dts @@ -0,0 +1,23 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + update@1 { + data = <0xabcd0000 0x78235609>; + }; + }; +}; diff --git a/tools/binman/test/40_x86_ucode_not_in_image.dts b/tools/binman/test/40_x86_ucode_not_in_image.dts new file mode 100644 index 0000000..67d17d3 --- /dev/null +++ b/tools/binman/test/40_x86_ucode_not_in_image.dts @@ -0,0 +1,28 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + size = <0x200>; + u-boot-with-ucode-ptr { + }; + + u-boot-dtb-with-ucode { + }; + + u-boot-ucode { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + update@1 { + data = <0xabcd0000 0x78235609>; + }; + }; +}; diff --git a/tools/binman/test/41_unknown_pos_size.dts b/tools/binman/test/41_unknown_pos_size.dts new file mode 100644 index 0000000..a8e7d8a --- /dev/null +++ b/tools/binman/test/41_unknown_pos_size.dts @@ -0,0 +1,11 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + _testing { + }; + }; +}; diff --git a/tools/binman/test/42_intel-fsp.dts b/tools/binman/test/42_intel-fsp.dts new file mode 100644 index 0000000..e0a1e76 --- /dev/null +++ b/tools/binman/test/42_intel-fsp.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + + intel-fsp { + }; + }; +}; diff --git a/tools/binman/test/43_intel-cmc.dts b/tools/binman/test/43_intel-cmc.dts new file mode 100644 index 0000000..26c456d --- /dev/null +++ b/tools/binman/test/43_intel-cmc.dts @@ -0,0 +1,13 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + size = <16>; + + intel-cmc { + }; + }; +}; diff --git a/tools/binman/test/44_x86_optional_ucode.dts b/tools/binman/test/44_x86_optional_ucode.dts new file mode 100644 index 0000000..abe1322 --- /dev/null +++ b/tools/binman/test/44_x86_optional_ucode.dts @@ -0,0 +1,30 @@ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + binman { + sort-by-pos; + end-at-4gb; + size = <0x200>; + u-boot-with-ucode-ptr { + optional-ucode; + }; + + u-boot-dtb-with-ucode { + }; + + u-boot-ucode { + }; + }; + + microcode { + update@0 { + data = <0x12345678 0x12345679>; + }; + update@1 { + data = <0xabcd0000 0x78235609>; + }; + }; +}; diff --git a/tools/binman/test/descriptor.bin b/tools/binman/test/descriptor.bin Binary files differnew file mode 100644 index 0000000..3d54943 --- /dev/null +++ b/tools/binman/test/descriptor.bin diff --git a/tools/binman/test/u_boot_no_ucode_ptr b/tools/binman/test/u_boot_no_ucode_ptr Binary files differnew file mode 100755 index 0000000..f72462f --- /dev/null +++ b/tools/binman/test/u_boot_no_ucode_ptr diff --git a/tools/binman/test/u_boot_no_ucode_ptr.c b/tools/binman/test/u_boot_no_ucode_ptr.c new file mode 100644 index 0000000..a17bb4c --- /dev/null +++ b/tools/binman/test/u_boot_no_ucode_ptr.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Simple program to create a bad _dt_ucode_base_size symbol to create an + * error when it is used. This is used by binman tests. + * + * Build with: + * cc -march=i386 -m32 -o u_boot_no_ucode_ptr -T u_boot_ucode_ptr.lds \ + -nostdlib u_boot_no_ucode_ptr.c + */ + +static unsigned long not__dt_ucode_base_size[2] + __attribute__((section(".ucode"))) = {1, 2}; diff --git a/tools/binman/test/u_boot_ucode_ptr b/tools/binman/test/u_boot_ucode_ptr Binary files differnew file mode 100755 index 0000000..dbfb184 --- /dev/null +++ b/tools/binman/test/u_boot_ucode_ptr diff --git a/tools/binman/test/u_boot_ucode_ptr.c b/tools/binman/test/u_boot_ucode_ptr.c new file mode 100644 index 0000000..434c9f4 --- /dev/null +++ b/tools/binman/test/u_boot_ucode_ptr.c @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + * + * Simple program to create a _dt_ucode_base_size symbol which can be read + * by 'nm'. This is used by binman tests. + * + * Build with: + * cc -march=i386 -m32 -o u_boot_ucode_ptr -T u_boot_ucode_ptr.lds -nostdlib \ + u_boot_ucode_ptr.c + */ + +static unsigned long _dt_ucode_base_size[2] + __attribute__((section(".ucode"))) = {1, 2}; diff --git a/tools/binman/test/u_boot_ucode_ptr.lds b/tools/binman/test/u_boot_ucode_ptr.lds new file mode 100644 index 0000000..167debf --- /dev/null +++ b/tools/binman/test/u_boot_ucode_ptr.lds @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2016 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") +OUTPUT_ARCH(i386) +ENTRY(_start) + +SECTIONS +{ + . = 0xfffffdf0; + _start = .; + .ucode : { + *(.ucode) + } +} diff --git a/tools/ifdtool.c b/tools/ifdtool.c index 48059c0..195b153 100644 --- a/tools/ifdtool.c +++ b/tools/ifdtool.c @@ -33,16 +33,9 @@ #define FLREG_BASE(reg) ((reg & 0x00000fff) << 12); #define FLREG_LIMIT(reg) (((reg & 0x0fff0000) >> 4) | 0xfff); -enum input_file_type_t { - IF_normal, - IF_fdt, - IF_uboot, -}; - struct input_file { char *fname; unsigned int addr; - enum input_file_type_t type; }; /** @@ -760,219 +753,6 @@ static int write_data(char *image, int size, unsigned int addr, return write_size; } -static int scan_ucode(const void *blob, char *ucode_base, int *countp, - const char **datap, int *data_sizep) -{ - const char *data = NULL; - int node, count; - int data_size; - char *ucode; - - for (node = 0, count = 0, ucode = ucode_base; node >= 0; count++) { - node = fdt_node_offset_by_compatible(blob, node, - "intel,microcode"); - if (node < 0) - break; - - data = fdt_getprop(blob, node, "data", &data_size); - if (!data) { - debug("Missing microcode data in FDT '%s': %s\n", - fdt_get_name(blob, node, NULL), - fdt_strerror(data_size)); - return -ENOENT; - } - - if (ucode_base) - memcpy(ucode, data, data_size); - ucode += data_size; - } - - if (countp) - *countp = count; - if (datap) - *datap = data; - if (data_sizep) - *data_sizep = data_size; - - return ucode - ucode_base; -} - -static int remove_ucode(char *blob) -{ - int node, count; - int ret; - - /* Keep going until we find no more microcode to remove */ - do { - for (node = 0, count = 0; node >= 0;) { - int ret; - - node = fdt_node_offset_by_compatible(blob, node, - "intel,microcode"); - if (node < 0) - break; - - ret = fdt_delprop(blob, node, "data"); - - /* - * -FDT_ERR_NOTFOUND means we already removed the - * data for this one, so we just continue. - * 0 means we did remove it, so offsets may have - * changed and we need to restart our scan. - * Anything else indicates an error we should report. - */ - if (ret == -FDT_ERR_NOTFOUND) - continue; - else if (!ret) - node = 0; - else - return ret; - } - } while (count); - - /* Pack down to remove excees space */ - ret = fdt_pack(blob); - if (ret) - return ret; - - return fdt_totalsize(blob); -} - -static int write_ucode(char *image, int size, struct input_file *fdt, - int fdt_size, unsigned int ucode_ptr, - int collate_ucode) -{ - const char *data = NULL; - char *ucode_buf; - const void *blob; - char *ucode_base; - uint32_t *ptr; - int ucode_size; - int data_size; - int offset; - int count; - int ret; - - blob = (void *)image + (uint32_t)(fdt->addr + size); - - debug("DTB at %lx\n", (char *)blob - image); - - /* Find out about the micrcode we have */ - ucode_size = scan_ucode(blob, NULL, &count, &data, &data_size); - if (ucode_size < 0) - return ucode_size; - if (!count) { - debug("No microcode found in FDT\n"); - return -ENOENT; - } - - if (count > 1 && !collate_ucode) { - fprintf(stderr, - "Cannot handle multiple microcode blocks - please use -C flag to collate them\n"); - return -EMLINK; - } - - /* - * Collect the microcode into a buffer, remove it from the device - * tree and place it immediately above the (now smaller) device tree. - */ - if (collate_ucode && count > 1) { - ucode_buf = malloc(ucode_size); - if (!ucode_buf) { - fprintf(stderr, - "Out of memory for microcode (%d bytes)\n", - ucode_size); - return -ENOMEM; - } - ret = scan_ucode(blob, ucode_buf, NULL, NULL, NULL); - if (ret < 0) - return ret; - - /* Remove the microcode from the device tree */ - ret = remove_ucode((char *)blob); - if (ret < 0) { - debug("Could not remove FDT microcode: %s\n", - fdt_strerror(ret)); - return -EINVAL; - } - debug("Collated %d microcode block(s)\n", count); - debug("Device tree reduced from %x to %x bytes\n", - fdt_size, ret); - fdt_size = ret; - - /* - * Place microcode area immediately above the FDT, aligned - * to a 16-byte boundary. - */ - ucode_base = (char *)(((unsigned long)blob + fdt_size + 15) & - ~15); - - data = ucode_base; - data_size = ucode_size; - memcpy(ucode_base, ucode_buf, ucode_size); - free(ucode_buf); - } - - offset = (uint32_t)(ucode_ptr + size); - ptr = (void *)image + offset; - - ptr[0] = (data - image) - size; - ptr[1] = data_size; - debug("Wrote microcode pointer at %x: addr=%x, size=%x\n", ucode_ptr, - ptr[0], ptr[1]); - - return (collate_ucode ? data + data_size : (char *)blob + fdt_size) - - image; -} - -/** - * write_uboot() - Write U-Boot, device tree and microcode pointer - * - * This writes U-Boot into a place in the flash, followed by its device tree. - * The microcode pointer is written so that U-Boot can find the microcode in - * the device tree very early in boot. - * - * @image: Pointer to image - * @size: Size of image in bytes - * @uboot: Input file information for u-boot.bin - * @fdt: Input file information for u-boot.dtb - * @ucode_ptr: Address in U-Boot where the microcode pointer should be placed - * @return 0 if OK, -ve on error - */ -static int write_uboot(char *image, int size, struct input_file *uboot, - struct input_file *fdt, unsigned int ucode_ptr, - int collate_ucode, int *offset_uboot_top, - int *offset_uboot_start) -{ - int uboot_size, fdt_size; - int uboot_top; - - uboot_size = write_data(image, size, uboot->addr, uboot->fname, 0, 0); - if (uboot_size < 0) - return uboot_size; - fdt->addr = uboot->addr + uboot_size; - debug("U-Boot size %#x, FDT at %#x\n", uboot_size, fdt->addr); - fdt_size = write_data(image, size, fdt->addr, fdt->fname, 0, 0); - if (fdt_size < 0) - return fdt_size; - - uboot_top = (uint32_t)(fdt->addr + size) + fdt_size; - - if (ucode_ptr) { - uboot_top = write_ucode(image, size, fdt, fdt_size, ucode_ptr, - collate_ucode); - if (uboot_top < 0) - return uboot_top; - } - - if (offset_uboot_top && offset_uboot_start) { - *offset_uboot_top = uboot_top; - *offset_uboot_start = (uint32_t)(uboot->addr + size); - } - - return 0; -} - static void print_version(void) { printf("ifdtool v%s -- ", IFDTOOL_VERSION); @@ -1034,7 +814,7 @@ int main(int argc, char *argv[]) int mode_dump = 0, mode_extract = 0, mode_inject = 0; int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0; int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0; - int create = 0, collate_ucode = 0; + int create = 0; char *region_type_string = NULL, *inject_fname = NULL; char *desc_fname = NULL, *addr_str = NULL; int region_type = -1, inputfreq = 0; @@ -1047,14 +827,12 @@ int main(int argc, char *argv[]) char *outfile = NULL; struct stat buf; int size = 0; - unsigned int ucode_ptr = 0; bool have_uboot = false; int bios_fd; char *image; int ret; static struct option long_options[] = { {"create", 0, NULL, 'c'}, - {"collate-microcode", 0, NULL, 'C'}, {"dump", 0, NULL, 'd'}, {"descriptor", 1, NULL, 'D'}, {"em100", 0, NULL, 'e'}, @@ -1062,7 +840,6 @@ int main(int argc, char *argv[]) {"fdt", 1, NULL, 'f'}, {"inject", 1, NULL, 'i'}, {"lock", 0, NULL, 'l'}, - {"microcode", 1, NULL, 'm'}, {"romsize", 1, NULL, 'r'}, {"spifreq", 1, NULL, 's'}, {"unlock", 0, NULL, 'u'}, @@ -1073,15 +850,12 @@ int main(int argc, char *argv[]) {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "cCdD:ef:hi:lm:r:s:uU:vw:x?", + while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lr:s:uU:vw:x?", long_options, &option_index)) != EOF) { switch (opt) { case 'c': create = 1; break; - case 'C': - collate_ucode = 1; - break; case 'd': mode_dump = 1; break; @@ -1119,9 +893,6 @@ int main(int argc, char *argv[]) case 'l': mode_locked = 1; break; - case 'm': - ucode_ptr = strtoul(optarg, NULL, 0); - break; case 'r': rom_size = strtol(optarg, NULL, 0); debug("ROM size %d\n", rom_size); @@ -1166,12 +937,6 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } ifile->addr = strtoll(optarg, NULL, 0); - ifile->type = opt == 'f' ? IF_fdt : - opt == 'U' ? IF_uboot : IF_normal; - if (ifile->type == IF_fdt) - fdt = ifile; - else if (ifile->type == IF_uboot) - have_uboot = true; wr_num++; } else { fprintf(stderr, @@ -1302,18 +1067,9 @@ int main(int argc, char *argv[]) for (wr_idx = 0; wr_idx < wr_num; wr_idx++) { ifile = &input_file[wr_idx]; - if (ifile->type == IF_fdt) { - continue; - } else if (ifile->type == IF_uboot) { - ret = write_uboot(image, size, ifile, fdt, - ucode_ptr, collate_ucode, - &offset_uboot_top, - &offset_uboot_start); - } else { - ret = write_data(image, size, ifile->addr, - ifile->fname, offset_uboot_top, - offset_uboot_start); - } + ret = write_data(image, size, ifile->addr, + ifile->fname, offset_uboot_top, + offset_uboot_start); if (ret < 0) break; } |