Merge git://git.denx.de/u-boot-dm
This commit is contained in:
		
						commit
						36737f22b7
					
				
							
								
								
									
										57
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										57
									
								
								Makefile
								
								
								
								
							|  | @ -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),) | ||||
|  |  | |||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
|  |  | |||
|  | @ -0,0 +1,8 @@ | |||
| / { | ||||
| 	host1x@50000000 { | ||||
| 		u-boot,dm-pre-reloc; | ||||
| 		dc@54200000 { | ||||
| 			u-boot,dm-pre-reloc; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
|  |  | |||
|  | @ -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 | ||||
|  | @ -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 | ||||
|  | @ -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) ; \
 | ||||
|  |  | |||
|  | @ -0,0 +1 @@ | |||
| *.pyc | ||||
|  | @ -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 | ||||
|  | @ -0,0 +1 @@ | |||
| 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) | ||||
|  | @ -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) | ||||
|  | @ -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 | ||||
|  | @ -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)) | ||||
|  | @ -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]} | ||||
|  | @ -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 | ||||
|  | @ -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 | ||||
|  | @ -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' | ||||
|  | @ -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]} | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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 | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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 | ||||
|  | @ -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' | ||||
|  | @ -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 | ||||
|  | @ -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:]) | ||||
|  | @ -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' | ||||
|  | @ -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' | ||||
|  | @ -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) | ||||
|  | @ -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)]) | ||||
|  | @ -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) | ||||
|  | @ -0,0 +1,5 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
|  | @ -0,0 +1,6 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| }; | ||||
|  | @ -0,0 +1,9 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,11 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		not-a-valid-type { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,11 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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 { | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,12 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			align = <23>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,12 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			align = <5>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,12 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			align-size = <55>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			pos = <5>; | ||||
| 			align = <4>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			size = <5>; | ||||
| 			align-size = <4>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,16 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 
 | ||||
| 		u-boot-align { | ||||
| 			type = "u-boot"; | ||||
| 			pos = <3>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,12 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 			size = <3>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <3>; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <7>; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		align-size = <16>; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,14 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <7>; | ||||
| 		align-size = <8>; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		align-size = <131>; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,16 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		pad-byte = <0xff>; | ||||
| 		u-boot-spl { | ||||
| 		}; | ||||
| 
 | ||||
| 		u-boot { | ||||
| 			pos = <12>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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 { | ||||
| 			}; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,12 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		blob { | ||||
| 			filename = "blobfile"; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,15 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot { | ||||
| 		}; | ||||
| 
 | ||||
| 		u-boot-spl { | ||||
| 			pos = <0>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,14 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot-nodtb { | ||||
| 		}; | ||||
| 
 | ||||
| 		u-boot-dtb { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <16>; | ||||
| 
 | ||||
| 		intel-vga { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <16>; | ||||
| 
 | ||||
| 		x86-start16 { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,11 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		u-boot-img { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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 { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,11 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		_testing { | ||||
| 		}; | ||||
|         }; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <16>; | ||||
| 
 | ||||
| 		intel-fsp { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -0,0 +1,13 @@ | |||
| /dts-v1/; | ||||
| 
 | ||||
| / { | ||||
| 	#address-cells = <1>; | ||||
| 	#size-cells = <1>; | ||||
| 
 | ||||
| 	binman { | ||||
| 		size = <16>; | ||||
| 
 | ||||
| 		intel-cmc { | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
|  | @ -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>; | ||||
| 		}; | ||||
| 	}; | ||||
| }; | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							|  | @ -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}; | ||||
										
											Binary file not shown.
										
									
								
							|  | @ -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}; | ||||
|  | @ -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) | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										254
									
								
								tools/ifdtool.c
								
								
								
								
							
							
						
						
									
										254
									
								
								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; | ||||
| 		} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue