diff options
Diffstat (limited to 'scripts')
88 files changed, 4301 insertions, 5644 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index f78793eab7..8c653d184f 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only bin2c -mkimage fix_size bareboxenv bareboxcrc32 @@ -14,7 +13,6 @@ kwboot-target gen_netx_image omap_signGP mk-omap-image -s5p_cksum mkublheader zynq_mkimage socfpga_mkimage @@ -33,6 +31,7 @@ omap3-usb-loader omap3-usb-loader-target rk-usb-loader rk-usb-loader-target +rkimage mips-relocs rsatoc stm32image diff --git a/scripts/Kconfig b/scripts/Kconfig index 25d57e4b2a..4b675671ee 100644 --- a/scripts/Kconfig +++ b/scripts/Kconfig @@ -28,6 +28,13 @@ config ZYNQ_MKIMAGE help This enables building the image creation tool for Zynq +config IMX9_IMAGE + bool "imx9image" + depends on ARCH_IMX93 || COMPILE_HOST_TOOLS + default y if ARCH_IMX93 + help + This enables building the image tool for NXP i.MX9 SoCs + config MXS_HOSTTOOLS bool "MXS host tools" if COMPILE_HOST_TOOLS depends on ARCH_MXS || COMPILE_HOST_TOOLS @@ -51,8 +58,8 @@ config STM32_IMAGE config RK_IMAGE bool "Rockchip image tool" if COMPILE_HOST_TOOLS - depends on ARCH_ROCKCHIP || COMPILE_HOST_TOOLS - default y if ARCH_ROCKCHIP + depends on ARCH_ROCKCHIP_V8 || COMPILE_HOST_TOOLS + default y if ARCH_ROCKCHIP_V8 help This enables building the image creation tool for Rockchip SoCs @@ -63,13 +70,6 @@ config OMAP_IMAGE help This enables building the image creation tools for TI OMAP SoCs -config S5P_IMAGE - bool "S5P image tool" if COMPILE_HOST_TOOLS - depends on ARCH_S5PCxx || COMPILE_HOST_TOOLS - default y if ARCH_S5PCxx - help - This enables building the image creation tool for S5P SoCs - config DAVINCI_IMAGE bool "Davinci image tool" if COMPILE_HOST_TOOLS depends on ARCH_DAVINCI || COMPILE_HOST_TOOLS @@ -117,6 +117,13 @@ config QOICONV help This enable converting png to qoi images to generate boot logo. +config RSATOC + bool "RSA to C converter" if COMPILE_HOST_TOOLS + help + This utility converts RSA keys in PEM format to either C or + device tree snippets. This requires OpenSSL on the build host + and will be selected by the build system if required. + endmenu menu "Target Tools" diff --git a/scripts/Makefile b/scripts/Makefile index 39d71d4e99..cb1d916439 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -5,42 +5,42 @@ # barebox for the build process. hostprogs-always-y += bin2c -hostprogs-always-y += mkimage hostprogs-always-y += fix_size hostprogs-always-y += bareboxenv hostprogs-always-y += bareboxcrc32 hostprogs-always-y += kernel-install hostprogs-always-$(CONFIG_QOICONV) += qoiconv -hostprogs-always-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS) += rsatoc -HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl` -HOSTLDLIBS_rsatoc = `pkg-config --libs openssl` +hostprogs-always-$(CONFIG_RSATOC) += rsatoc +HOSTCFLAGS_rsatoc.o = `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_rsatoc = `$(PKG_CONFIG) --libs openssl` hostprogs-always-$(CONFIG_IMD) += bareboximd hostprogs-always-$(CONFIG_KALLSYMS) += kallsyms hostprogs-always-$(CONFIG_MIPS) += mips-relocs hostprogs-always-$(CONFIG_MVEBU_HOSTTOOLS) += kwbimage kwboot mvebuimg hostprogs-always-$(CONFIG_OMAP_IMAGE) += omap_signGP mk-omap-image -hostprogs-always-$(CONFIG_S5P_IMAGE) += s5p_cksum hostprogs-always-$(CONFIG_DAVINCI_IMAGE) += mkublheader -HOSTCFLAGS_zynq_mkimage.o = -I$(srctree) -I$(srctree)/arch/arm/mach-zynq/include +HOSTCFLAGS_zynq_mkimage.o = -I$(srctree) -I$(srctree)/include/mach hostprogs-always-$(CONFIG_ZYNQ_MKIMAGE) += zynq_mkimage hostprogs-always-$(CONFIG_SOCFPGA_MKIMAGE) += socfpga_mkimage hostprogs-always-$(CONFIG_MXS_HOSTTOOLS) += mxsimage mxsboot hostprogs-always-$(CONFIG_LAYERSCAPE_PBLIMAGE) += pblimage hostprogs-always-$(CONFIG_STM32_IMAGE) += stm32image +hostprogs-always-$(CONFIG_IMX9_IMAGE) += imx9image hostprogs-always-$(CONFIG_RISCV) += prelink-riscv hostprogs-always-$(CONFIG_RK_IMAGE) += rkimage -HOSTCFLAGS_rkimage = `pkg-config --cflags openssl` -HOSTLDLIBS_rkimage = `pkg-config --libs openssl` +HOSTCFLAGS_rkimage.o = `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_rkimage = `$(PKG_CONFIG) --libs openssl` KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/ -HOSTLDLIBS_mxsimage = `pkg-config --libs openssl` -HOSTCFLAGS_omap3-usb-loader.o = `pkg-config --cflags libusb-1.0` -HOSTLDLIBS_omap3-usb-loader = `pkg-config --libs libusb-1.0` +HOSTCFLAGS_mxsimage.o = `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_mxsimage = `$(PKG_CONFIG) --libs openssl` +HOSTCFLAGS_omap3-usb-loader.o = `$(PKG_CONFIG) --cflags libusb-1.0` +HOSTLDLIBS_omap3-usb-loader = `$(PKG_CONFIG) --libs libusb-1.0` hostprogs-always-$(CONFIG_OMAP3_USB_LOADER) += omap3-usb-loader -HOSTCFLAGS_omap4_usbboot.o = `pkg-config --cflags libusb-1.0` -HOSTLDLIBS_omap4_usbboot = -lpthread `pkg-config --libs libusb-1.0` +HOSTCFLAGS_omap4_usbboot.o = `$(PKG_CONFIG) --cflags libusb-1.0` +HOSTLDLIBS_omap4_usbboot = -lpthread `$(PKG_CONFIG) --libs libusb-1.0` hostprogs-always-$(CONFIG_OMAP4_HOSTTOOL_USBBOOT) += omap4_usbboot -HOSTCFLAGS_rk-usb-loader.o = `pkg-config --cflags libusb-1.0` -HOSTLDLIBS_rk-usb-loader = `pkg-config --libs libusb-1.0` +HOSTCFLAGS_rk-usb-loader.o = `$(PKG_CONFIG) --cflags libusb-1.0` +HOSTLDLIBS_rk-usb-loader = `$(PKG_CONFIG) --libs libusb-1.0` hostprogs-always-$(CONFIG_RK_USB_LOADER) += rk-usb-loader userprogs-always-$(CONFIG_BAREBOXENV_TARGET) += bareboxenv-target diff --git a/scripts/Makefile.build b/scripts/Makefile.build index 1614a1ac58..25347eee01 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -258,12 +258,14 @@ intermediate_targets = $(foreach sfx, $(2), \ $(filter %$(strip $(1)), $(targets)))) # %.asn1.o <- %.asn1.[ch] <- %.asn1 # %.dtb.o <- %.dtb.S <- %.dtb <- %.dts +# %.dtbo.o <- %.dtbo.S <- %.dtbo <- %.dtso # %.dtb.pbl.o <- %.dtb.S <- %.dtb <- %.dts (Barebox only) # %.lex.o <- %.lex.c <- %.l # %.tab.o <- %.tab.[ch] <- %.y targets += $(call intermediate_targets, .asn1.o, .asn1.c .asn1.h) \ - $(call intermediate_targets, .dtb.o, .dtb.S .dtb) \ - $(call intermediate_targets, .dtb.pbl.o, .dtb.S .dtb) \ + $(call intermediate_targets, .dtb.o, .dtb.S .dtb.z .dtb) \ + $(call intermediate_targets, .dtbo.o, .dtbo.S .dtbo.z .dtbo) \ + $(call intermediate_targets, .dtb.pbl.o, .dtb.S .dtb.z .dtb) \ $(call intermediate_targets, .lex.o, .lex.c) \ $(call intermediate_targets, .tab.o, .tab.c .tab.h) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index a830364a8b..6b1f0ccbc0 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -156,6 +156,25 @@ _c_flags += $(if $(patsubst n%,, \ PBL_CPPFLAGS += $(call cc-option,-fno-sanitize=all) endif +ifeq ($(CONFIG_DEBUG_PBL),y) +PBL_CPPFLAGS += -DDEBUG +endif + +_stackp_flags-y := -fno-stack-protector +_stackp_flags-$(CONFIG_STACKPROTECTOR_STRONG) := -fstack-protector-strong +_stackp_flags-$(CONFIG_STACKPROTECTOR_ALL) := -fstack-protector-all + +_stackp_flags_pbl-y := -fno-stack-protector +_stackp_flags_pbl-$(CONFIG_PBL_STACKPROTECTOR_STRONG) := -fstack-protector-strong +_stackp_flags_pbl-$(CONFIG_PBL_STACKPROTECTOR_ALL) := -fstack-protector-all + +_c_flags += $(if $(part-of-pbl),$(_stackp_flags_pbl-y),$(_stackp_flags-y)) + +ifeq ($(CONFIG_PBL_FULLY_PIC),y) +include scripts/Makefile.pic +PBL_CPPFLAGS += $(picflags-y) +endif + # If building barebox in a separate objtree expand all occurrences # of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). @@ -206,7 +225,7 @@ dtc_cpp_flags = -Wp,-MD,$(depfile).pre -nostdinc \ -I$(srctree)/include \ -I$(srctree)/dts/include \ -I$(srctree)/dts/src/ \ - $(DTC_CPP_FLAGS_$(basetarget).dtb) \ + $(DTC_CPP_FLAGS_$(basetarget)$(suffix $@)) \ -undef -D__DTS__ ifdef CONFIG_BOOTM_FITIMAGE_PUBKEY @@ -231,6 +250,12 @@ endef # Shipped files # =========================================================================== +quiet_cmd_0size = 0SIZE $@ +cmd_0size = : > $@ + +quiet_cmd_delete = DELETE $@ + cmd_delete = rm -f $@ + quiet_cmd_shipped = SHIPPED $@ cmd_shipped = cat $< > $@ @@ -272,6 +297,27 @@ cmd_ld = $(LD) $(KBUILD_LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) \ quiet_cmd_objcopy = OBJCOPY $@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ +# Hashing +# --------------------------------------------------------------------------- +# POSIX printf (e.g. dash's) doesn't support \xHH, but octal sequences are fine + +quiet_cmd_sha256bin ?= SHA-BIN $@ + cmd_sha256bin = printf "$(shell sed 's/ .*$$//;s/../0x&\n/g;s/\n$$//' $< | \ + while read -r byte; do printf '\%o' $$byte; done)" > $@ + +quiet_cmd_sha256sum ?= SHA $@ + cmd_sha256sum ?= sha256sum $2 > $@ + +# Decompressor for barebox proper binary when using PBL +# --------------------------------------------------------------------------- + +suffix_y = comp_copy +suffix_$(CONFIG_IMAGE_COMPRESSION_GZIP) = gzip +suffix_$(CONFIG_IMAGE_COMPRESSION_LZO) = lzo +suffix_$(CONFIG_IMAGE_COMPRESSION_LZ4) = lz4 +suffix_$(CONFIG_IMAGE_COMPRESSION_XZKERN) = xzkern +suffix_$(CONFIG_IMAGE_COMPRESSION_NONE) = comp_copy + # Gzip # --------------------------------------------------------------------------- @@ -320,34 +366,47 @@ DTC_FLAGS += -Wno-unit_address_vs_reg \ -Wno-unit_address_format \ -Wno-avoid_unnecessary_addr_size \ -Wno-alias_paths \ - -Wno-alias_paths \ -Wno-graph_child_address \ -Wno-simple_bus_reg \ -Wno-unique_unit_address \ - -Wno-pci_device_reg + -Wno-pci_device_reg \ + -Wno-interrupt_provider ifeq ($(CONFIG_OF_OVERLAY_LIVE), y) -DTC_FLAGS += -@ +DTC_FLAGS.dtb += -@ endif +DTC_FLAGS.dtbo += -Wno-avoid_default_addr_size -Wno-reg_format + # Generate an assembly file to wrap the output of the device tree compiler quiet_cmd_dt_S_dtb = DTB $@ cmd_dt_S_dtb = $(srctree)/scripts/gen-dtb-s $(subst -,_,$(*F)) $< $(CONFIG_IMD) > $@ -$(obj)/%.dtb.S: $(obj)/%.dtb $(srctree)/scripts/gen-dtb-s FORCE +$(obj)/%.dtb.S: $(obj)/%.dtb $(obj)/%.dtb.z $(srctree)/scripts/gen-dtb-s FORCE $(call if_changed,dt_S_dtb) +quiet_cmd_dt_S_dtbo = DTBO $@ +cmd_dt_S_dtbo = $(srctree)/scripts/gen-dtbo-s $(subst -,_,$(*F)) $< > $@ +$(obj)/%.dtbo.S: $(obj)/%.dtbo $(srctree)/scripts/gen-dtbo-s FORCE + $(call if_changed,dt_S_dtbo) + +$(obj)/%.dtb.z: $(obj)/%.dtb FORCE + $(call if_changed,$(suffix_y)) + dts-frags = $(subst $(quote),,$(CONFIG_EXTERNAL_DTS_FRAGMENTS)) quiet_cmd_dtc = DTC $@ -# For compatibility between make 4.2 and 4.3 -cmd_dtc = /usr/bin/env echo -e '$(pound)define $(subst -,_,$(*F))_dts 1\n'$(foreach f,$< $(dts-frags),'$(pound)include "$(f)"\n') | \ - $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) - ; \ +cmd_dtc = $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) \ + -D'$(subst -,_,$(*F))_dts=1' $(foreach f,$< $(2),-include '$(f)') /dev/null ; \ $(objtree)/scripts/dtc/dtc -O dtb -o $@ -b 0 \ - -i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) \ + -i $(srctree)/arch/$(SRCARCH)/dts $(DTC_FLAGS) $(DTC_FLAGS$(suffix $@)) \ -i $(srctree)/dts/src/$(SRCARCH) \ + -i $(srctree)/dts/src/arm/ti/omap \ -d $(depfile).dtc $(dtc-tmp) ; \ cat $(depfile).pre $(depfile).dtc > $(depfile) $(obj)/%.dtb: $(src)/%.dts FORCE + $(call if_changed_dep,dtc,$(dts-frags)) + +$(obj)/%.dtbo: $(src)/%.dtso $(DTC) FORCE $(call if_changed_dep,dtc) dtc-tmp = $(subst $(comma),_,$(dot-target).dts) @@ -355,7 +414,8 @@ dtc-tmp = $(subst $(comma),_,$(dot-target).dts) quiet_cmd_env_S = ENV.S $@ cmd_env_S = \ ( \ - echo '\#include <asm-generic/barebox.lds.h>'; \ + echo '\#include <asm/barebox.lds.h>'; \ + echo '.section .note.GNU-stack,"",%progbits'; \ echo '.section .bbenv.rodata.$(subst -,_,$(*F)),"a"'; \ echo '.balign STRUCT_ALIGNMENT'; \ echo '.global __bbenv_$(subst -,_,$(*F))_start'; \ @@ -427,34 +487,6 @@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ %.lzo: % $(call if_changed,lzo) -# XZ -# --------------------------------------------------------------------------- -# Use xzkern to compress the kernel image and xzmisc to compress other things. -# -# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage -# of the kernel decompressor. A BCJ filter is used if it is available for -# the target architecture. xzkern also appends uncompressed size of the data -# using size_append. The .xz format has the size information available at -# the end of the file too, but it's in more complex format and it's good to -# avoid changing the part of the boot code that reads the uncompressed size. -# Note that the bytes added by size_append will make the xz tool think that -# the file is corrupt. This is expected. -# -# xzmisc doesn't use size_append, so it can be used to create normal .xz -# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very -# big dictionary would increase the memory usage too much in the multi-call -# decompression mode. A BCJ filter isn't used either. -quiet_cmd_xzkern = XZKERN $@ -cmd_xzkern = (cat $(filter-out FORCE,$^) | \ - sh $(srctree)/scripts/xz_wrap.sh && \ - $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -quiet_cmd_xzmisc = XZMISC $@ -cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ - xz --check=crc32 --lzma2=dict=1MiB) > $@ || \ - (rm -f $@ ; false) - # lz4 # --------------------------------------------------------------------------- @@ -504,7 +536,8 @@ quiet_cmd_check_file_size = CHKFILESIZE $2 quiet_cmd_imximage__S_dcd= DCD_S $@ cmd_imximage_S_dcd= \ ( \ - echo '\#include <asm-generic/barebox.lds.h>'; \ + echo '\#include <asm/barebox.lds.h>'; \ + echo '.section .note.GNU-stack,"",%progbits'; \ echo '.balign STRUCT_ALIGNMENT'; \ echo '.global $(subst -,_,$(*F))_start'; \ echo '$(subst -,_,$(*F))_start:'; \ @@ -519,6 +552,11 @@ overwrite-hab-env = $(shell set -e; \ test -n "$$$(1)"; \ echo -D$(1)=\\\"$(shell echo $$$(1))\\\") +overwrite-fit-env = $(shell set -e; \ + test -n "$(CONFIG_BOOTM_FITIMAGE_PUBKEY_ENV)"; \ + test -n "$$$(1)"; \ + echo -D$(1)=\\\"$(shell echo $$$(1))\\\") + imxcfg_cpp_flags = -Wp,-MD,$(depfile) -nostdinc -x assembler-with-cpp \ -I $(srctree)/include -I $(srctree)/arch/arm/mach-imx/include \ -include include/generated/autoconf.h \ @@ -527,7 +565,8 @@ imxcfg_cpp_flags = -Wp,-MD,$(depfile) -nostdinc -x assembler-with-cpp \ $(call overwrite-hab-env,CONFIG_HABV3_IMG_CRT_DER) \ $(call overwrite-hab-env,CONFIG_HABV4_TABLE_BIN) \ $(call overwrite-hab-env,CONFIG_HABV4_CSF_CRT_PEM) \ - $(call overwrite-hab-env,CONFIG_HABV4_IMG_CRT_PEM) + $(call overwrite-hab-env,CONFIG_HABV4_IMG_CRT_PEM) \ + $(call overwrite-fit-env,CONFIG_BOOTM_FITIMAGE_PUBKEY) \ dcd-tmp = $(subst $(comma),_,$(dot-target).dcd.tmp) @@ -575,7 +614,7 @@ quiet_cmd_b64dec = B64DEC $@ # target file. quiet_cmd_rsa_keys = RSAKEY $@ cmd_rsa_keys = \ - $(objtree)/scripts/rsatoc -o $@.tmp $(2) && \ + $(objtree)/scripts/rsatoc -o $@.tmp "$(2)" $(3) && \ if cmp -s $@.tmp $@; then \ rm $@.tmp; \ else \ diff --git a/scripts/Makefile.pic b/scripts/Makefile.pic new file mode 100644 index 0000000000..c30894ba98 --- /dev/null +++ b/scripts/Makefile.pic @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# The stub may be linked into the kernel proper or into a separate boot binary, +# but in either case, it executes before the kernel does (with MMU disabled) so +# things like ftrace and stack-protector are likely to cause trouble if left +# enabled, even if doing so doesn't break the build. +# +picflags-$(CONFIG_X86_64) := -mcmodel=small +picflags-$(CONFIG_X86) += -fPIC -fno-asynchronous-unwind-tables + +ifeq ($(CONFIG_ARM),y) +picflags-$(CONFIG_CPU_32) := -fpic -mno-single-pic-base +picflags-$(CONFIG_CPU_64) := -fpie +endif + +picflags-y += -include $(srctree)/include/linux/hidden.h \ + -D__fully_pic__ \ + -D__NO_FORTIFY \ + -ffreestanding \ + -fno-stack-protector \ + $(call cc-option,-fno-addrsig) \ + -D__DISABLE_EXPORTS diff --git a/scripts/bareboxenv.c b/scripts/bareboxenv.c index f1706a5e17..e954447015 100644 --- a/scripts/bareboxenv.c +++ b/scripts/bareboxenv.c @@ -20,7 +20,7 @@ #include "compiler.h" #define debug(...) -#define printk_once(...) +#define pr_debug_once(...) /* Find out if the last character of a string matches the one given. * Don't underrun the buffer if the string length is 0. diff --git a/scripts/bbremote b/scripts/bbremote index bc5351dbae..1eeabd08d1 100755 --- a/scripts/bbremote +++ b/scripts/bbremote @@ -1,3 +1,3 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 import remote.main diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 36e3d768f3..dccc3c3fe7 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -5981,7 +5981,7 @@ sub process { while ($fmt =~ /(\%[\*\d\.]*p(\w))/g) { $specifier = $1; $extension = $2; - if ($extension !~ /[SsBKRraEhMmIiUDdgVCbGNOxt]/) { + if ($extension !~ /[SsBKRraEehMmIiUDdgVCbGNOxt]/) { $bad_specifier = $specifier; last; } diff --git a/scripts/common.c b/scripts/common.c index e2c53c5aef..49c468a1ea 100644 --- a/scripts/common.c +++ b/scripts/common.c @@ -9,9 +9,9 @@ #include <string.h> #include <errno.h> #include <stdarg.h> -#include <sys/mman.h> #include "common.h" +#include "compiler.h" int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size) { @@ -23,7 +23,7 @@ int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_si *size = 0; *outbuf = NULL; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) { fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); return -errno; @@ -76,8 +76,8 @@ int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_si ret = 0; goto close; free: + free(*outbuf); *outbuf = NULL; - free(buf); close: close(fd); return ret; diff --git a/scripts/compiler.h b/scripts/compiler.h index c932f715c5..925cad21b6 100644 --- a/scripts/compiler.h +++ b/scripts/compiler.h @@ -61,6 +61,37 @@ typedef unsigned int uint; #elif defined(__OpenBSD__) || defined(__FreeBSD__) || \ defined(__NetBSD__) || defined(__DragonFly__) # include <sys/endian.h> +#elif defined _WIN32 +# if defined(_MSC_VER) +# include <stdlib.h> +# define htobe16(x) _byteswap_ushort(x) +# define htole16(x) (x) +# define be16toh(x) _byteswap_ushort(x) +# define le16toh(x) (x) +# define htobe32(x) _byteswap_ulong(x) +# define htole32(x) (x) +# define be32toh(x) _byteswap_ulong(x) +# define le32toh(x) (x) +# define htobe64(x) _byteswap_uint64(x) +# define htole64(x) (x) +# define be64toh(x) _byteswap_uint64(x) +# define le64toh(x) (x) +# elif defined(__GNUC__) || defined(__clang__) +# define htobe16(x) __builtin_bswap16(x) +# define htole16(x) (x) +# define be16toh(x) __builtin_bswap16(x) +# define le16toh(x) (x) +# define htobe32(x) __builtin_bswap32(x) +# define htole32(x) (x) +# define be32toh(x) __builtin_bswap32(x) +# define le32toh(x) (x) +# define htobe64(x) __builtin_bswap64(x) +# define htole64(x) (x) +# define be64toh(x) __builtin_bswap64(x) +# define le64toh(x) (x) +#else +# error platform not supported +#endif #else /* assume Linux */ # include <sys/types.h> # include <endian.h> @@ -128,11 +159,13 @@ typedef uint32_t __u32; # define be64_to_cpu(x) (x) #endif +#ifndef min #define min(x, y) ({ \ typeof(x) _min1 = (x); \ typeof(y) _min2 = (y); \ (void) (&_min1 == &_min2); \ _min1 < _min2 ? _min1 : _min2; }) +#endif static inline void *xmalloc(size_t size) { diff --git a/scripts/container.sh b/scripts/container.sh new file mode 100755 index 0000000000..dff6546c2c --- /dev/null +++ b/scripts/container.sh @@ -0,0 +1,44 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +CONTAINER=${CONTAINER:-ghcr.io/barebox/barebox/barebox-ci:latest} +export KCONFIG_ADD="test/kconfig/disable_target_tools.kconf $KCONFIG_ADD" + +while getopts "c:uh" opt; do + case "$opt" in + h) + echo "usage: $0 [-c CONTAINER] [command...]" + echo "This script mounts the working directory into a container" + echo "and runs the specified command inside or /bin/bash if no" + echo "command was specified." + echo "OPTIONS:" + echo " -c <container> container image to use (default: $CONTAINER)" + echo " -u pull container image updates" + echo " -h This help text" + + exit 0 + ;; + u) + update=1 + ;; + c) + CONTAINER="$OPTARG" + ;; + esac +done + +shift $((OPTIND-1)) + +[ -n "$update" ] && podman pull "$CONTAINER" + +volumes="-v $PWD:$PWD:z" +pwd_real=$(realpath $PWD) +if [ "$(realpath --no-symlinks $PWD)" != "$pwd_real" ]; then + volumes="$volumes -v $pwd_real:$pwd_real:z" +fi + +exec podman run -it $volumes --rm \ + -e TERM -e ARCH -e CONFIG -e JOBS -e LOGDIR -e REGEX \ + -e KBUILD_OUTPUT -e LG_BUILDDIR \ + -e KCONFIG_ADD -w "$PWD" --userns=keep-id \ + -- "$CONTAINER" "${@:-/bin/bash}" diff --git a/scripts/dtc/checks.c b/scripts/dtc/checks.c index 756f0fa920..69f2649e6e 100644 --- a/scripts/dtc/checks.c +++ b/scripts/dtc/checks.c @@ -143,6 +143,14 @@ static void check_nodes_props(struct check *c, struct dt_info *dti, struct node check_nodes_props(c, dti, child); } +static bool is_multiple_of(int multiple, int divisor) +{ + if (divisor == 0) + return multiple == 0; + else + return (multiple % divisor) == 0; +} + static bool run_check(struct check *c, struct dt_info *dti) { struct node *dt = dti->dt; @@ -297,19 +305,20 @@ ERROR(duplicate_property_names, check_duplicate_property_names, NULL); #define LOWERCASE "abcdefghijklmnopqrstuvwxyz" #define UPPERCASE "ABCDEFGHIJKLMNOPQRSTUVWXYZ" #define DIGITS "0123456789" -#define PROPNODECHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" +#define NODECHARS LOWERCASE UPPERCASE DIGITS ",._+-@" +#define PROPCHARS LOWERCASE UPPERCASE DIGITS ",._+*#?-" #define PROPNODECHARSSTRICT LOWERCASE UPPERCASE DIGITS ",-" static void check_node_name_chars(struct check *c, struct dt_info *dti, struct node *node) { - int n = strspn(node->name, c->data); + size_t n = strspn(node->name, c->data); if (n < strlen(node->name)) FAIL(c, dti, node, "Bad character '%c' in node name", node->name[n]); } -ERROR(node_name_chars, check_node_name_chars, PROPNODECHARS "@"); +ERROR(node_name_chars, check_node_name_chars, NODECHARS); static void check_node_name_chars_strict(struct check *c, struct dt_info *dti, struct node *node) @@ -330,6 +339,20 @@ static void check_node_name_format(struct check *c, struct dt_info *dti, } ERROR(node_name_format, check_node_name_format, NULL, &node_name_chars); +static void check_node_name_vs_property_name(struct check *c, + struct dt_info *dti, + struct node *node) +{ + if (!node->parent) + return; + + if (get_property(node->parent, node->name)) { + FAIL(c, dti, node, "node name and property name conflict"); + } +} +WARNING(node_name_vs_property_name, check_node_name_vs_property_name, + NULL, &node_name_chars); + static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, struct node *node) { @@ -352,7 +375,7 @@ static void check_unit_address_vs_reg(struct check *c, struct dt_info *dti, FAIL(c, dti, node, "node has a reg or ranges property, but no unit name"); } else { if (unitname[0]) - FAIL(c, dti, node, "node has a unit name, but no reg property"); + FAIL(c, dti, node, "node has a unit name, but no reg or ranges property"); } } WARNING(unit_address_vs_reg, check_unit_address_vs_reg, NULL); @@ -363,14 +386,14 @@ static void check_property_name_chars(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - int n = strspn(prop->name, c->data); + size_t n = strspn(prop->name, c->data); if (n < strlen(prop->name)) FAIL_PROP(c, dti, node, prop, "Bad character '%c' in property name", prop->name[n]); } } -ERROR(property_name_chars, check_property_name_chars, PROPNODECHARS); +ERROR(property_name_chars, check_property_name_chars, PROPCHARS); static void check_property_name_chars_strict(struct check *c, struct dt_info *dti, @@ -380,7 +403,7 @@ static void check_property_name_chars_strict(struct check *c, for_each_property(node, prop) { const char *name = prop->name; - int n = strspn(name, c->data); + size_t n = strspn(name, c->data); if (n == strlen(prop->name)) continue; @@ -497,7 +520,7 @@ static cell_t check_phandle_prop(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { FAIL_PROP(c, dti, node, prop, "bad value (0x%x) in %s property", phandle, prop->name); return 0; @@ -556,7 +579,7 @@ static void check_name_properties(struct check *c, struct dt_info *dti, if (!prop) return; /* No name property, that's fine */ - if ((prop->val.len != node->basenamelen+1) + if ((prop->val.len != node->basenamelen + 1U) || (memcmp(prop->val.val, node->name, node->basenamelen) != 0)) { FAIL(c, dti, node, "\"name\" property is incorrect (\"%s\" instead" " of base node name)", prop->val.val); @@ -657,7 +680,6 @@ ERROR(omit_unused_nodes, fixup_omit_unused_nodes, NULL, &phandle_references, &pa */ WARNING_IF_NOT_CELL(address_cells_is_cell, "#address-cells"); WARNING_IF_NOT_CELL(size_cells_is_cell, "#size-cells"); -WARNING_IF_NOT_CELL(interrupt_cells_is_cell, "#interrupt-cells"); WARNING_IF_NOT_STRING(device_type_is_string, "device_type"); WARNING_IF_NOT_STRING(model_is_string, "model"); @@ -672,8 +694,7 @@ static void check_names_is_string_list(struct check *c, struct dt_info *dti, struct property *prop; for_each_property(node, prop) { - const char *s = strrchr(prop->name, '-'); - if (!s || !streq(s, "-names")) + if (!strends(prop->name, "-names")) continue; c->data = prop->name; @@ -753,7 +774,7 @@ static void check_reg_format(struct check *c, struct dt_info *dti, size_cells = node_size_cells(node->parent); entrylen = (addr_cells + size_cells) * sizeof(cell_t); - if (!entrylen || (prop->val.len % entrylen) != 0) + if (!is_multiple_of(prop->val.len, entrylen)) FAIL_PROP(c, dti, node, prop, "property has invalid length (%d bytes) " "(#address-cells == %d, #size-cells == %d)", prop->val.len, addr_cells, size_cells); @@ -765,13 +786,15 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, { struct property *prop; int c_addr_cells, p_addr_cells, c_size_cells, p_size_cells, entrylen; + const char *ranges = c->data; - prop = get_property(node, "ranges"); + prop = get_property(node, ranges); if (!prop) return; if (!node->parent) { - FAIL_PROP(c, dti, node, prop, "Root node has a \"ranges\" property"); + FAIL_PROP(c, dti, node, prop, "Root node has a \"%s\" property", + ranges); return; } @@ -783,23 +806,24 @@ static void check_ranges_format(struct check *c, struct dt_info *dti, if (prop->val.len == 0) { if (p_addr_cells != c_addr_cells) - FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " + FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its " "#address-cells (%d) differs from %s (%d)", - c_addr_cells, node->parent->fullpath, + ranges, c_addr_cells, node->parent->fullpath, p_addr_cells); if (p_size_cells != c_size_cells) - FAIL_PROP(c, dti, node, prop, "empty \"ranges\" property but its " + FAIL_PROP(c, dti, node, prop, "empty \"%s\" property but its " "#size-cells (%d) differs from %s (%d)", - c_size_cells, node->parent->fullpath, + ranges, c_size_cells, node->parent->fullpath, p_size_cells); - } else if ((prop->val.len % entrylen) != 0) { - FAIL_PROP(c, dti, node, prop, "\"ranges\" property has invalid length (%d bytes) " + } else if (!is_multiple_of(prop->val.len, entrylen)) { + FAIL_PROP(c, dti, node, prop, "\"%s\" property has invalid length (%d bytes) " "(parent #address-cells == %d, child #address-cells == %d, " - "#size-cells == %d)", prop->val.len, + "#size-cells == %d)", ranges, prop->val.len, p_addr_cells, c_addr_cells, c_size_cells); } } -WARNING(ranges_format, check_ranges_format, NULL, &addr_size_cells); +WARNING(ranges_format, check_ranges_format, "ranges", &addr_size_cells); +WARNING(dma_ranges_format, check_ranges_format, "dma-ranges", &addr_size_cells); static const struct bus_type pci_bus = { .name = "PCI", @@ -868,7 +892,7 @@ static void check_pci_device_bus_num(struct check *c, struct dt_info *dti, struc } else { cells = (cell_t *)prop->val.val; min_bus = fdt32_to_cpu(cells[0]); - max_bus = fdt32_to_cpu(cells[0]); + max_bus = fdt32_to_cpu(cells[1]); } if ((bus_num < min_bus) || (bus_num > max_bus)) FAIL_PROP(c, dti, node, prop, "PCI bus number %d out of range, expected (%d - %d)", @@ -888,10 +912,8 @@ static void check_pci_device_reg(struct check *c, struct dt_info *dti, struct no return; prop = get_property(node, "reg"); - if (!prop) { - FAIL(c, dti, node, "missing PCI reg property"); + if (!prop) return; - } cells = (cell_t *)prop->val.val; if (cells[1] || cells[2]) @@ -1019,6 +1041,9 @@ static void check_i2c_bus_bridge(struct check *c, struct dt_info *dti, struct no } WARNING(i2c_bus_bridge, check_i2c_bus_bridge, NULL, &addr_size_cells); +#define I2C_OWN_SLAVE_ADDRESS (1U << 30) +#define I2C_TEN_BIT_ADDRESS (1U << 31) + static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node *node) { struct property *prop; @@ -1041,6 +1066,8 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node } reg = fdt32_to_cpu(*cells); + /* Ignore I2C_OWN_SLAVE_ADDRESS */ + reg &= ~I2C_OWN_SLAVE_ADDRESS; snprintf(unit_addr, sizeof(unit_addr), "%x", reg); if (!streq(unitname, unit_addr)) FAIL(c, dti, node, "I2C bus unit address format error, expected \"%s\"", @@ -1048,10 +1075,15 @@ static void check_i2c_bus_reg(struct check *c, struct dt_info *dti, struct node for (len = prop->val.len; len > 0; len -= 4) { reg = fdt32_to_cpu(*(cells++)); - if (reg > 0x3ff) + /* Ignore I2C_OWN_SLAVE_ADDRESS */ + reg &= ~I2C_OWN_SLAVE_ADDRESS; + + if ((reg & I2C_TEN_BIT_ADDRESS) && ((reg & ~I2C_TEN_BIT_ADDRESS) > 0x3ff)) FAIL_PROP(c, dti, node, prop, "I2C address must be less than 10-bits, got \"0x%x\"", reg); - + else if (reg > 0x7f) + FAIL_PROP(c, dti, node, prop, "I2C address must be less than 7-bits, got \"0x%x\". Set I2C_TEN_BIT_ADDRESS for 10 bit addresses or fix the property", + reg); } } WARNING(i2c_bus_reg, check_i2c_bus_reg, NULL, ®_format, &i2c_bus_bridge); @@ -1190,7 +1222,7 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d if (!node->parent || node->addr_cells < 0 || node->size_cells < 0) return; - if (get_property(node, "ranges") || !node->children) + if (get_property(node, "ranges") || get_property(node, "dma-ranges") || !node->children) return; for_each_child(node, child) { @@ -1200,7 +1232,7 @@ static void check_avoid_unnecessary_addr_size(struct check *c, struct dt_info *d } if (!has_reg) - FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\" or child \"reg\" property"); + FAIL(c, dti, node, "unnecessary #address-cells/#size-cells without \"ranges\", \"dma-ranges\" or child \"reg\" property"); } WARNING(avoid_unnecessary_addr_size, check_avoid_unnecessary_addr_size, NULL, &avoid_default_addr_size); @@ -1350,15 +1382,15 @@ struct provider { }; static void check_property_phandle_args(struct check *c, - struct dt_info *dti, - struct node *node, - struct property *prop, - const struct provider *provider) + struct dt_info *dti, + struct node *node, + struct property *prop, + const struct provider *provider) { struct node *root = dti->dt; - int cell, cellsize = 0; + unsigned int cell, cellsize = 0; - if (prop->val.len % sizeof(cell_t)) { + if (!is_multiple_of(prop->val.len, sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "property size (%d) is invalid, expected multiple of %zu", prop->val.len, sizeof(cell_t)); @@ -1368,14 +1400,15 @@ static void check_property_phandle_args(struct check *c, for (cell = 0; cell < prop->val.len / sizeof(cell_t); cell += cellsize + 1) { struct node *provider_node; struct property *cellprop; - int phandle; + cell_t phandle; + unsigned int expected; phandle = propval_cell_n(prop, cell); /* * Some bindings use a cell value 0 or -1 to skip over optional * entries when each index position has a specific definition. */ - if (phandle == 0 || phandle == -1) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with external references */ if (dti->dtsflags & DTSF_PLUGIN) break; @@ -1418,10 +1451,12 @@ static void check_property_phandle_args(struct check *c, break; } - if (prop->val.len < ((cell + cellsize + 1) * sizeof(cell_t))) { + expected = (cell + cellsize + 1) * sizeof(cell_t); + if ((expected <= cell) || prop->val.len < expected) { FAIL_PROP(c, dti, node, prop, - "property size (%d) too small for cell size %d", + "property size (%d) too small for cell size %u", prop->val.len, cellsize); + break; } } } @@ -1441,7 +1476,8 @@ static void check_provider_cells_property(struct check *c, } #define WARNING_PROPERTY_PHANDLE_CELLS(nm, propname, cells_name, ...) \ static struct provider nm##_provider = { (propname), (cells_name), __VA_ARGS__ }; \ - WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &phandle_references); + WARNING_IF_NOT_CELL(nm##_is_cell, cells_name); \ + WARNING(nm##_property, check_provider_cells_property, &nm##_provider, &nm##_is_cell, &phandle_references); WARNING_PROPERTY_PHANDLE_CELLS(clocks, "clocks", "#clock-cells"); WARNING_PROPERTY_PHANDLE_CELLS(cooling_device, "cooling-device", "#cooling-cells"); @@ -1462,24 +1498,17 @@ WARNING_PROPERTY_PHANDLE_CELLS(thermal_sensors, "thermal-sensors", "#thermal-sen static bool prop_is_gpio(struct property *prop) { - char *str; - /* * *-gpios and *-gpio can appear in property names, * so skip over any false matches (only one known ATM) */ - if (strstr(prop->name, "nr-gpio")) + if (strends(prop->name, ",nr-gpios")) return false; - str = strrchr(prop->name, '-'); - if (str) - str++; - else - str = prop->name; - if (!(streq(str, "gpios") || streq(str, "gpio"))) - return false; - - return true; + return strends(prop->name, "-gpios") || + streq(prop->name, "gpios") || + strends(prop->name, "-gpio") || + streq(prop->name, "gpio"); } static void check_gpios_property(struct check *c, @@ -1514,13 +1543,10 @@ static void check_deprecated_gpio_property(struct check *c, struct property *prop; for_each_property(node, prop) { - char *str; - if (!prop_is_gpio(prop)) continue; - str = strstr(prop->name, "gpio"); - if (!streq(str, "gpio")) + if (!strends(prop->name, "gpio")) continue; FAIL_PROP(c, dti, node, prop, @@ -1544,6 +1570,113 @@ static bool node_is_interrupt_provider(struct node *node) return false; } + +static void check_interrupt_provider(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct property *prop; + bool irq_provider = node_is_interrupt_provider(node); + + prop = get_property(node, "#interrupt-cells"); + if (irq_provider && !prop) { + FAIL(c, dti, node, + "Missing '#interrupt-cells' in interrupt provider"); + return; + } + + if (!irq_provider && prop) { + FAIL(c, dti, node, + "'#interrupt-cells' found, but node is not an interrupt provider"); + return; + } +} +WARNING(interrupt_provider, check_interrupt_provider, NULL, &interrupts_extended_is_cell); + +static void check_interrupt_map(struct check *c, + struct dt_info *dti, + struct node *node) +{ + struct node *root = dti->dt; + struct property *prop, *irq_map_prop; + size_t cellsize, cell, map_cells; + + irq_map_prop = get_property(node, "interrupt-map"); + if (!irq_map_prop) + return; + + if (node->addr_cells < 0) { + FAIL(c, dti, node, + "Missing '#address-cells' in interrupt-map provider"); + return; + } + cellsize = node_addr_cells(node); + cellsize += propval_cell(get_property(node, "#interrupt-cells")); + + prop = get_property(node, "interrupt-map-mask"); + if (prop && (prop->val.len != (cellsize * sizeof(cell_t)))) + FAIL_PROP(c, dti, node, prop, + "property size (%d) is invalid, expected %zu", + prop->val.len, cellsize * sizeof(cell_t)); + + if (!is_multiple_of(irq_map_prop->val.len, sizeof(cell_t))) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) is invalid, expected multiple of %zu", + irq_map_prop->val.len, sizeof(cell_t)); + return; + } + + map_cells = irq_map_prop->val.len / sizeof(cell_t); + for (cell = 0; cell < map_cells; ) { + struct node *provider_node; + struct property *cellprop; + int phandle; + size_t parent_cellsize; + + if ((cell + cellsize) >= map_cells) { + FAIL_PROP(c, dti, node, irq_map_prop, + "property size (%d) too small, expected > %zu", + irq_map_prop->val.len, (cell + cellsize) * sizeof(cell_t)); + break; + } + cell += cellsize; + + phandle = propval_cell_n(irq_map_prop, cell); + if (!phandle_is_valid(phandle)) { + /* Give up if this is an overlay with external references */ + if (!(dti->dtsflags & DTSF_PLUGIN)) + FAIL_PROP(c, dti, node, irq_map_prop, + "Cell %zu is not a phandle(%d)", + cell, phandle); + break; + } + + provider_node = get_node_by_phandle(root, phandle); + if (!provider_node) { + FAIL_PROP(c, dti, node, irq_map_prop, + "Could not get phandle(%d) node for (cell %zu)", + phandle, cell); + break; + } + + cellprop = get_property(provider_node, "#interrupt-cells"); + if (cellprop) { + parent_cellsize = propval_cell(cellprop); + } else { + FAIL(c, dti, node, "Missing property '#interrupt-cells' in node %s or bad phandle (referred from interrupt-map[%zu])", + provider_node->fullpath, cell); + break; + } + + cellprop = get_property(provider_node, "#address-cells"); + if (cellprop) + parent_cellsize += propval_cell(cellprop); + + cell += 1 + parent_cellsize; + } +} +WARNING(interrupt_map, check_interrupt_map, NULL, &phandle_references, &addr_size_cells, &interrupt_provider); + static void check_interrupts_property(struct check *c, struct dt_info *dti, struct node *node) @@ -1551,13 +1684,13 @@ static void check_interrupts_property(struct check *c, struct node *root = dti->dt; struct node *irq_node = NULL, *parent = node; struct property *irq_prop, *prop = NULL; - int irq_cells, phandle; + cell_t irq_cells, phandle; irq_prop = get_property(node, "interrupts"); if (!irq_prop) return; - if (irq_prop->val.len % sizeof(cell_t)) + if (!is_multiple_of(irq_prop->val.len, sizeof(cell_t))) FAIL_PROP(c, dti, node, irq_prop, "size (%d) is invalid, expected multiple of %zu", irq_prop->val.len, sizeof(cell_t)); @@ -1570,7 +1703,7 @@ static void check_interrupts_property(struct check *c, prop = get_property(parent, "interrupt-parent"); if (prop) { phandle = propval_cell(prop); - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { /* Give up if this is an overlay with * external references */ if (dti->dtsflags & DTSF_PLUGIN) @@ -1601,12 +1734,12 @@ static void check_interrupts_property(struct check *c, prop = get_property(irq_node, "#interrupt-cells"); if (!prop) { - FAIL(c, dti, irq_node, "Missing #interrupt-cells in interrupt-parent"); + /* We warn about that already in another test. */ return; } irq_cells = propval_cell(prop); - if (irq_prop->val.len % (irq_cells * sizeof(cell_t))) { + if (!is_multiple_of(irq_prop->val.len, irq_cells * sizeof(cell_t))) { FAIL_PROP(c, dti, node, prop, "size is (%d), expected multiple of %d", irq_prop->val.len, (int)(irq_cells * sizeof(cell_t))); @@ -1717,7 +1850,7 @@ WARNING(graph_port, check_graph_port, NULL, &graph_nodes); static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, struct node *endpoint) { - int phandle; + cell_t phandle; struct node *node; struct property *prop; @@ -1727,7 +1860,7 @@ static struct node *get_remote_endpoint(struct check *c, struct dt_info *dti, phandle = propval_cell(prop); /* Give up if this is an overlay with external references */ - if (phandle == 0 || phandle == -1) + if (!phandle_is_valid(phandle)) return NULL; node = get_node_by_phandle(dti->dt, phandle); @@ -1763,7 +1896,7 @@ WARNING(graph_endpoint, check_graph_endpoint, NULL, &graph_nodes); static struct check *check_table[] = { &duplicate_node_names, &duplicate_property_names, &node_name_chars, &node_name_format, &property_name_chars, - &name_is_string, &name_properties, + &name_is_string, &name_properties, &node_name_vs_property_name, &duplicate_label, @@ -1771,7 +1904,7 @@ static struct check *check_table[] = { &phandle_references, &path_references, &omit_unused_nodes, - &address_cells_is_cell, &size_cells_is_cell, &interrupt_cells_is_cell, + &address_cells_is_cell, &size_cells_is_cell, &device_type_is_string, &model_is_string, &status_is_string, &label_is_string, @@ -1780,7 +1913,7 @@ static struct check *check_table[] = { &property_name_chars_strict, &node_name_chars_strict, - &addr_size_cells, ®_format, &ranges_format, + &addr_size_cells, ®_format, &ranges_format, &dma_ranges_format, &unit_address_vs_reg, &unit_address_format, @@ -1806,25 +1939,43 @@ static struct check *check_table[] = { &chosen_node_is_root, &chosen_node_bootargs, &chosen_node_stdout_path, &clocks_property, + &clocks_is_cell, &cooling_device_property, + &cooling_device_is_cell, &dmas_property, + &dmas_is_cell, &hwlocks_property, + &hwlocks_is_cell, &interrupts_extended_property, + &interrupts_extended_is_cell, &io_channels_property, + &io_channels_is_cell, &iommus_property, + &iommus_is_cell, &mboxes_property, + &mboxes_is_cell, &msi_parent_property, + &msi_parent_is_cell, &mux_controls_property, + &mux_controls_is_cell, &phys_property, + &phys_is_cell, &power_domains_property, + &power_domains_is_cell, &pwms_property, + &pwms_is_cell, &resets_property, + &resets_is_cell, &sound_dai_property, + &sound_dai_is_cell, &thermal_sensors_property, + &thermal_sensors_is_cell, &deprecated_gpio_property, &gpios_property, &interrupts_property, + &interrupt_provider, + &interrupt_map, &alias_paths, @@ -1848,7 +1999,7 @@ static void enable_warning_error(struct check *c, bool warn, bool error) static void disable_warning_error(struct check *c, bool warn, bool error) { - int i; + unsigned int i; /* Lowering level, also lower it for things this is the prereq * for */ @@ -1869,7 +2020,7 @@ static void disable_warning_error(struct check *c, bool warn, bool error) void parse_checks_option(bool warn, bool error, const char *arg) { - int i; + unsigned int i; const char *name = arg; bool enable = true; @@ -1896,7 +2047,7 @@ void parse_checks_option(bool warn, bool error, const char *arg) void process_checks(bool force, struct dt_info *dti) { - int i; + unsigned int i; int error = 0; for (i = 0; i < ARRAY_SIZE(check_table); i++) { diff --git a/scripts/dtc/data.c b/scripts/dtc/data.c index 0a43b6de32..14734233ad 100644 --- a/scripts/dtc/data.c +++ b/scripts/dtc/data.c @@ -21,10 +21,10 @@ void data_free(struct data d) free(d.val); } -struct data data_grow_for(struct data d, int xlen) +struct data data_grow_for(struct data d, unsigned int xlen) { struct data nd; - int newsize; + unsigned int newsize; if (xlen == 0) return d; @@ -84,7 +84,7 @@ struct data data_copy_file(FILE *f, size_t maxlen) while (!feof(f) && (d.len < maxlen)) { size_t chunksize, ret; - if (maxlen == -1) + if (maxlen == (size_t)-1) chunksize = 4096; else chunksize = maxlen - d.len; diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l index b3b7270300..de60a70b6b 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -57,7 +57,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); push_input_file(name); } -<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)? { +<*>^"#"(line)?[ \t]+[0-9]+[ \t]+{STRING}([ \t]+[0-9]+)* { char *line, *fnstart, *fnend; struct data fn; /* skip text before line # */ @@ -200,7 +200,7 @@ static void PRINTF(1, 2) lexical_error(const char *fmt, ...); return DT_LABEL_REF; } -<*>"&{/"{PATHCHAR}*\} { /* new-style path reference */ +<*>"&{"{PATHCHAR}*\} { /* new-style path reference */ yytext[yyleng-1] = '\0'; DPRINT("Ref: %s\n", yytext+2); yylval.labelref = xstrdup(yytext+2); diff --git a/scripts/dtc/dtc-parser.y b/scripts/dtc/dtc-parser.y index 2ed4dc1f07..bff1337ec2 100644 --- a/scripts/dtc/dtc-parser.y +++ b/scripts/dtc/dtc-parser.y @@ -2,6 +2,8 @@ /* * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation. 2005. */ +%locations + %{ #include <stdio.h> #include <inttypes.h> @@ -17,8 +19,16 @@ extern void yyerror(char const *s); treesource_error = true; \ } while (0) +#define YYERROR_CALL(msg) yyerror(msg) + extern struct dt_info *parser_output; extern bool treesource_error; + +static bool is_ref_relative(const char *ref) +{ + return ref[0] != '/' && strchr(&ref[1], '/'); +} + %} %union { @@ -165,6 +175,8 @@ devicetree: */ if (!($<flags>-1 & DTSF_PLUGIN)) ERROR(&@2, "Label or path %s not found", $1); + else if (is_ref_relative($1)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $1); $$ = add_orphan_node( name_node(build_node(NULL, NULL, NULL), ""), @@ -174,6 +186,9 @@ devicetree: { struct node *target = get_node_by_ref($1, $3); + if (($<flags>-1 & DTSF_PLUGIN) && is_ref_relative($3)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $3); + if (target) { add_label(&target->labels, $2); merge_nodes(target, $4); @@ -189,6 +204,8 @@ devicetree: * so $-1 is what we want (plugindecl) */ if ($<flags>-1 & DTSF_PLUGIN) { + if (is_ref_relative($2)) + ERROR(&@2, "Label-relative reference %s not supported in plugin", $2); add_orphan_node($1, $3, $2); } else { struct node *target = get_node_by_ref($1, $2); @@ -387,9 +404,14 @@ arrayprefix: * within the mask to one (i.e. | in the * mask), all bits are one. */ - if (($2 > mask) && (($2 | mask) != -1ULL)) - ERROR(&@2, "Value out of range for" - " %d-bit array element", $1.bits); + if (($2 > mask) && (($2 | mask) != -1ULL)) { + char *loc = srcpos_string(&@2); + fprintf(stderr, + "WARNING: %s: Value 0x%016" PRIx64 + " truncated to 0x%0*" PRIx64 "\n", + loc, $2, $1.bits / 4, ($2 & mask)); + free(loc); + } } $$.data = data_append_integer($1.data, $2, $1.bits); @@ -472,8 +494,8 @@ integer_rela: ; integer_shift: - integer_shift DT_LSHIFT integer_add { $$ = $1 << $3; } - | integer_shift DT_RSHIFT integer_add { $$ = $1 >> $3; } + integer_shift DT_LSHIFT integer_add { $$ = ($3 < 64) ? ($1 << $3) : 0; } + | integer_shift DT_RSHIFT integer_add { $$ = ($3 < 64) ? ($1 >> $3) : 0; } | integer_add ; diff --git a/scripts/dtc/dtc.c b/scripts/dtc/dtc.c index bdb3f59456..bc786c543b 100644 --- a/scripts/dtc/dtc.c +++ b/scripts/dtc/dtc.c @@ -12,7 +12,7 @@ * Command line options */ int quiet; /* Level of quietness */ -int reservenum; /* Number of memory reservation slots */ +unsigned int reservenum;/* Number of memory reservation slots */ int minsize; /* Minimum blob size */ int padsize; /* Additional padding to blob */ int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -122,6 +122,8 @@ static const char *guess_type_by_name(const char *fname, const char *fallback) return "dts"; if (!strcasecmp(s, ".yaml")) return "yaml"; + if (!strcasecmp(s, ".dtbo")) + return "dtb"; if (!strcasecmp(s, ".dtb")) return "dtb"; return fallback; @@ -195,7 +197,7 @@ int main(int argc, char *argv[]) depname = optarg; break; case 'R': - reservenum = strtol(optarg, NULL, 0); + reservenum = strtoul(optarg, NULL, 0); break; case 'S': minsize = strtol(optarg, NULL, 0); diff --git a/scripts/dtc/dtc.h b/scripts/dtc/dtc.h index 6e74ecea55..0a1f549910 100644 --- a/scripts/dtc/dtc.h +++ b/scripts/dtc/dtc.h @@ -35,7 +35,7 @@ * Command line options */ extern int quiet; /* Level of quietness */ -extern int reservenum; /* Number of memory reservation slots */ +extern unsigned int reservenum; /* Number of memory reservation slots */ extern int minsize; /* Minimum blob size */ extern int padsize; /* Additional padding to blob */ extern int alignsize; /* Additional padding to blob accroding to the alignsize */ @@ -51,10 +51,56 @@ extern int annotate; /* annotate .dts with input source location */ typedef uint32_t cell_t; +static inline bool phandle_is_valid(cell_t phandle) +{ + return phandle != 0 && phandle != ~0U; +} + +static inline uint16_t dtb_ld16(const void *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint16_t)bp[0] << 8) + | bp[1]; +} + +static inline uint32_t dtb_ld32(const void *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint32_t)bp[0] << 24) + | ((uint32_t)bp[1] << 16) + | ((uint32_t)bp[2] << 8) + | bp[3]; +} + +static inline uint64_t dtb_ld64(const void *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint64_t)bp[0] << 56) + | ((uint64_t)bp[1] << 48) + | ((uint64_t)bp[2] << 40) + | ((uint64_t)bp[3] << 32) + | ((uint64_t)bp[4] << 24) + | ((uint64_t)bp[5] << 16) + | ((uint64_t)bp[6] << 8) + | bp[7]; +} #define streq(a, b) (strcmp((a), (b)) == 0) #define strstarts(s, prefix) (strncmp((s), (prefix), strlen(prefix)) == 0) #define strprefixeq(a, n, b) (strlen(b) == (n) && (memcmp(a, b, n) == 0)) +static inline bool strends(const char *str, const char *suffix) +{ + unsigned int len, suffix_len; + + len = strlen(str); + suffix_len = strlen(suffix); + if (len < suffix_len) + return false; + return streq(str + len - suffix_len, suffix); +} #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) @@ -70,17 +116,23 @@ enum markertype { TYPE_UINT64, TYPE_STRING, }; + +static inline bool is_type_marker(enum markertype type) +{ + return type >= TYPE_UINT8; +} + extern const char *markername(enum markertype markertype); struct marker { enum markertype type; - int offset; + unsigned int offset; char *ref; struct marker *next; }; struct data { - int len; + unsigned int len; char *val; struct marker *markers; }; @@ -94,11 +146,26 @@ struct data { for_each_marker(m) \ if ((m)->type == (t)) -size_t type_marker_length(struct marker *m); +static inline struct marker *next_type_marker(struct marker *m) +{ + for_each_marker(m) + if (is_type_marker(m->type)) + break; + return m; +} + +static inline size_t type_marker_length(struct marker *m) +{ + struct marker *next = next_type_marker(m->next); + + if (next) + return next->offset - m->offset; + return 0; +} void data_free(struct data d); -struct data data_grow_for(struct data d, int xlen); +struct data data_grow_for(struct data d, unsigned int xlen); struct data data_copy_mem(const char *mem, int len); struct data data_copy_escape_string(const char *s, int len); @@ -222,7 +289,7 @@ void append_to_property(struct node *node, const char *get_unitname(struct node *node); struct property *get_property(struct node *node, const char *propname); cell_t propval_cell(struct property *prop); -cell_t propval_cell_n(struct property *prop, int n); +cell_t propval_cell_n(struct property *prop, unsigned int n); struct property *get_property_by_label(struct node *tree, const char *label, struct node **node); struct marker *get_marker_label(struct node *tree, const char *label, diff --git a/scripts/dtc/fdtget.c b/scripts/dtc/fdtget.c index 777582e2d4..dd709854be 100644 --- a/scripts/dtc/fdtget.c +++ b/scripts/dtc/fdtget.c @@ -62,8 +62,14 @@ static int show_cell_list(struct display_info *disp, const char *data, int len, for (i = 0; i < len; i += size, p += size) { if (i) printf(" "); - value = size == 4 ? fdt32_ld((const fdt32_t *)p) : - size == 2 ? (*p << 8) | p[1] : *p; + switch (size) { + case 4: value = fdt32_ld((const fdt32_t *)p); break; + case 2: value = fdt16_ld((const fdt16_t *)p); break; + case 1: + default: + value = *p; + break; + } printf(fmt, value); } @@ -91,6 +97,11 @@ static int show_data(struct display_info *disp, const char *data, int len) if (len == 0) return 0; + if (disp->type == 'r') { + fwrite(data, 1, len, stdout); + return 0; + } + is_string = (disp->type) == 's' || (!disp->type && util_is_printable_string(data, len)); if (is_string) { diff --git a/scripts/dtc/flattree.c b/scripts/dtc/flattree.c index bd6977eedc..95e43d32c3 100644 --- a/scripts/dtc/flattree.c +++ b/scripts/dtc/flattree.c @@ -124,7 +124,8 @@ static void asm_emit_cell(void *e, cell_t val) { FILE *f = e; - fprintf(f, "\t.byte 0x%02x; .byte 0x%02x; .byte 0x%02x; .byte 0x%02x\n", + fprintf(f, "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n" + "\t.byte\t0x%02x\n" "\t.byte\t0x%02x\n", (val >> 24) & 0xff, (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); } @@ -134,9 +135,9 @@ static void asm_emit_string(void *e, const char *str, int len) FILE *f = e; if (len != 0) - fprintf(f, "\t.string\t\"%.*s\"\n", len, str); + fprintf(f, "\t.asciz\t\"%.*s\"\n", len, str); else - fprintf(f, "\t.string\t\"%s\"\n", str); + fprintf(f, "\t.asciz\t\"%s\"\n", str); } static void asm_emit_align(void *e, int a) @@ -149,14 +150,14 @@ static void asm_emit_align(void *e, int a) static void asm_emit_data(void *e, struct data d) { FILE *f = e; - int off = 0; + unsigned int off = 0; struct marker *m = d.markers; for_each_marker_of_type(m, LABEL) emit_offset_label(f, m->ref, m->offset); while ((d.len - off) >= sizeof(uint32_t)) { - asm_emit_cell(e, fdt32_to_cpu(*((fdt32_t *)(d.val+off)))); + asm_emit_cell(e, dtb_ld32(d.val + off)); off += sizeof(uint32_t); } @@ -219,7 +220,7 @@ static struct emitter asm_emitter = { static int stringtable_insert(struct data *d, const char *str) { - int i; + unsigned int i; /* FIXME: do this more efficiently? */ @@ -295,7 +296,7 @@ static struct data flatten_reserve_list(struct reserve_info *reservelist, { struct reserve_info *re; struct data d = empty_data; - int j; + unsigned int j; for (re = reservelist; re; re = re->next) { d = data_append_re(d, re->address, re->size); @@ -345,7 +346,7 @@ static void make_fdt_header(struct fdt_header *fdt, void dt_to_blob(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data blob = empty_data; struct data reservebuf = empty_data; struct data dtbuf = empty_data; @@ -438,7 +439,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) while (p < (strbuf.val + strbuf.len)) { len = strlen(p); - fprintf(f, "\t.string \"%s\"\n", p); + fprintf(f, "\t.asciz \"%s\"\n", p); p += len+1; } } @@ -446,7 +447,7 @@ static void dump_stringtable_asm(FILE *f, struct data strbuf) void dt_to_asm(FILE *f, struct dt_info *dti, int version) { struct version_info *vi = NULL; - int i; + unsigned int i; struct data strbuf = empty_data; struct reserve_info *re; const char *symprefix = "dt"; diff --git a/scripts/dtc/fstree.c b/scripts/dtc/fstree.c index 9871689b4a..5e59594ab3 100644 --- a/scripts/dtc/fstree.c +++ b/scripts/dtc/fstree.c @@ -30,7 +30,7 @@ static struct node *read_fstree(const char *dirname) tmpname = join_path(dirname, de->d_name); - if (lstat(tmpname, &st) < 0) + if (stat(tmpname, &st) < 0) die("stat(%s): %s\n", tmpname, strerror(errno)); if (S_ISREG(st.st_mode)) { diff --git a/scripts/dtc/libfdt/Makefile.libfdt b/scripts/dtc/libfdt/Makefile.libfdt index e54639738c..b6d8fc02dd 100644 --- a/scripts/dtc/libfdt/Makefile.libfdt +++ b/scripts/dtc/libfdt/Makefile.libfdt @@ -8,7 +8,7 @@ LIBFDT_soname = libfdt.$(SHAREDLIB_EXT).1 LIBFDT_INCLUDES = fdt.h libfdt.h libfdt_env.h LIBFDT_VERSION = version.lds LIBFDT_SRCS = fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c fdt_empty_tree.c \ - fdt_addresses.c fdt_overlay.c + fdt_addresses.c fdt_overlay.c fdt_check.c LIBFDT_OBJS = $(LIBFDT_SRCS:%.c=%.o) LIBFDT_LIB = libfdt-$(DTC_VERSION).$(SHAREDLIB_EXT) diff --git a/scripts/dtc/libfdt/fdt.c b/scripts/dtc/libfdt/fdt.c index d6ce7c052d..20c6415b9c 100644 --- a/scripts/dtc/libfdt/fdt.c +++ b/scripts/dtc/libfdt/fdt.c @@ -19,15 +19,25 @@ int32_t fdt_ro_probe_(const void *fdt) { uint32_t totalsize = fdt_totalsize(fdt); + if (can_assume(VALID_DTB)) + return totalsize; + + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ - if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; - if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) - return -FDT_ERR_BADVERSION; + if (!can_assume(LATEST)) { + if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + if (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION) + return -FDT_ERR_BADVERSION; + } } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { /* Unfinished sequential-write blob */ - if (fdt_size_dt_struct(fdt) == 0) + if (!can_assume(VALID_INPUT) && fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; } else { return -FDT_ERR_BADMAGIC; @@ -70,58 +80,79 @@ size_t fdt_header_size_(uint32_t version) return FDT_V17_SIZE; } +size_t fdt_header_size(const void *fdt) +{ + return can_assume(LATEST) ? FDT_V17_SIZE : + fdt_header_size_(fdt_version(fdt)); +} + int fdt_check_header(const void *fdt) { size_t hdrsize; + /* The device tree must be at an 8-byte aligned address */ + if ((uintptr_t)fdt & 7) + return -FDT_ERR_ALIGNMENT; + if (fdt_magic(fdt) != FDT_MAGIC) return -FDT_ERR_BADMAGIC; + if (!can_assume(LATEST)) { + if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) + || (fdt_last_comp_version(fdt) > + FDT_LAST_SUPPORTED_VERSION)) + return -FDT_ERR_BADVERSION; + if (fdt_version(fdt) < fdt_last_comp_version(fdt)) + return -FDT_ERR_BADVERSION; + } hdrsize = fdt_header_size(fdt); - if ((fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) - || (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)) - return -FDT_ERR_BADVERSION; - if (fdt_version(fdt) < fdt_last_comp_version(fdt)) - return -FDT_ERR_BADVERSION; - - if ((fdt_totalsize(fdt) < hdrsize) - || (fdt_totalsize(fdt) > INT_MAX)) - return -FDT_ERR_TRUNCATED; - - /* Bounds check memrsv block */ - if (!check_off_(hdrsize, fdt_totalsize(fdt), fdt_off_mem_rsvmap(fdt))) - return -FDT_ERR_TRUNCATED; + if (!can_assume(VALID_DTB)) { + if ((fdt_totalsize(fdt) < hdrsize) + || (fdt_totalsize(fdt) > INT_MAX)) + return -FDT_ERR_TRUNCATED; - /* Bounds check structure block */ - if (fdt_version(fdt) < 17) { + /* Bounds check memrsv block */ if (!check_off_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_struct(fdt))) + fdt_off_mem_rsvmap(fdt))) return -FDT_ERR_TRUNCATED; - } else { + + /* Bounds check structure block */ + if (!can_assume(LATEST) && fdt_version(fdt) < 17) { + if (!check_off_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } else { + if (!check_block_(hdrsize, fdt_totalsize(fdt), + fdt_off_dt_struct(fdt), + fdt_size_dt_struct(fdt))) + return -FDT_ERR_TRUNCATED; + } + + /* Bounds check strings block */ if (!check_block_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_struct(fdt), - fdt_size_dt_struct(fdt))) + fdt_off_dt_strings(fdt), + fdt_size_dt_strings(fdt))) return -FDT_ERR_TRUNCATED; } - /* Bounds check strings block */ - if (!check_block_(hdrsize, fdt_totalsize(fdt), - fdt_off_dt_strings(fdt), fdt_size_dt_strings(fdt))) - return -FDT_ERR_TRUNCATED; - return 0; } const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { - unsigned absoffset = offset + fdt_off_dt_struct(fdt); + unsigned int uoffset = offset; + unsigned int absoffset = offset + fdt_off_dt_struct(fdt); - if ((absoffset < offset) - || ((absoffset + len) < absoffset) - || (absoffset + len) > fdt_totalsize(fdt)) + if (offset < 0) return NULL; - if (fdt_version(fdt) >= 0x11) - if (((offset + len) < offset) + if (!can_assume(VALID_INPUT)) + if ((absoffset < uoffset) + || ((absoffset + len) < absoffset) + || (absoffset + len) > fdt_totalsize(fdt)) + return NULL; + + if (can_assume(LATEST) || fdt_version(fdt) >= 0x11) + if (((uoffset + len) < uoffset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; @@ -131,13 +162,13 @@ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const fdt32_t *tagp, *lenp; - uint32_t tag; + uint32_t tag, len, sum; int offset = startoffset; const char *p; *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); - if (!tagp) + if (!can_assume(VALID_DTB) && !tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; @@ -149,19 +180,27 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); - if (!p) + if (!can_assume(VALID_DTB) && !p) return FDT_END; /* premature end */ break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); - if (!lenp) + if (!can_assume(VALID_DTB) && !lenp) + return FDT_END; /* premature end */ + + len = fdt32_to_cpu(*lenp); + sum = len + offset; + if (!can_assume(VALID_DTB) && + (INT_MAX <= sum || sum < (uint32_t) offset)) return FDT_END; /* premature end */ + /* skip-name offset, length and value */ - offset += sizeof(struct fdt_property) - FDT_TAGSIZE - + fdt32_to_cpu(*lenp); - if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && - ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) + offset += sizeof(struct fdt_property) - FDT_TAGSIZE + len; + + if (!can_assume(LATEST) && + fdt_version(fdt) < 0x10 && len >= 8 && + ((offset - len) % 8) != 0) offset += 4; break; @@ -183,8 +222,11 @@ uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) int fdt_check_node_offset_(const void *fdt, int offset) { - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE) return -FDT_ERR_BADOFFSET; return offset; @@ -192,8 +234,11 @@ int fdt_check_node_offset_(const void *fdt, int offset) int fdt_check_prop_offset_(const void *fdt, int offset) { - if ((offset < 0) || (offset % FDT_TAGSIZE) - || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) + if (!can_assume(VALID_INPUT) + && ((offset < 0) || (offset % FDT_TAGSIZE))) + return -FDT_ERR_BADOFFSET; + + if (fdt_next_tag(fdt, offset, &offset) != FDT_PROP) return -FDT_ERR_BADOFFSET; return offset; @@ -281,9 +326,12 @@ const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) int fdt_move(const void *fdt, void *buf, int bufsize) { + if (!can_assume(VALID_INPUT) && bufsize < 0) + return -FDT_ERR_NOSPACE; + FDT_RO_PROBE(fdt); - if (fdt_totalsize(fdt) > bufsize) + if (fdt_totalsize(fdt) > (unsigned int)bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); diff --git a/scripts/dtc/libfdt/fdt.h b/scripts/dtc/libfdt/fdt.h index f2e68807f2..0c91aa7f67 100644 --- a/scripts/dtc/libfdt/fdt.h +++ b/scripts/dtc/libfdt/fdt.h @@ -35,14 +35,14 @@ struct fdt_reserve_entry { struct fdt_node_header { fdt32_t tag; - char name[0]; + char name[]; }; struct fdt_property { fdt32_t tag; fdt32_t len; fdt32_t nameoff; - char data[0]; + char data[]; }; #endif /* !__ASSEMBLY */ diff --git a/scripts/dtc/libfdt/fdt_addresses.c b/scripts/dtc/libfdt/fdt_addresses.c index 9a82cd0ba2..c40ba094f1 100644 --- a/scripts/dtc/libfdt/fdt_addresses.c +++ b/scripts/dtc/libfdt/fdt_addresses.c @@ -73,7 +73,7 @@ int fdt_appendprop_addrrange(void *fdt, int parent, int nodeoffset, /* check validity of address */ prop = data; if (addr_cells == 1) { - if ((addr > UINT32_MAX) || ((UINT32_MAX + 1 - addr) < size)) + if ((addr > UINT32_MAX) || (((uint64_t) UINT32_MAX + 1 - addr) < size)) return -FDT_ERR_BADVALUE; fdt32_st(prop, (uint32_t)addr); diff --git a/scripts/dtc/libfdt/fdt_overlay.c b/scripts/dtc/libfdt/fdt_overlay.c index be71873366..5c0c3981b8 100644 --- a/scripts/dtc/libfdt/fdt_overlay.c +++ b/scripts/dtc/libfdt/fdt_overlay.c @@ -40,37 +40,22 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) return fdt32_to_cpu(*val); } -/** - * overlay_get_target - retrieves the offset of a fragment's target - * @fdt: Base device tree blob - * @fdto: Device tree overlay blob - * @fragment: node offset of the fragment in the overlay - * @pathp: pointer which receives the path of the target (or NULL) - * - * overlay_get_target() retrieves the target offset in the base - * device tree of a fragment, no matter how the actual targeting is - * done (through a phandle or a path) - * - * returns: - * the targeted node offset in the base device tree - * Negative error code on error - */ -static int overlay_get_target(const void *fdt, const void *fdto, - int fragment, char const **pathp) +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp) { uint32_t phandle; const char *path = NULL; int path_len = 0, ret; /* Try first to do a phandle based lookup */ - phandle = overlay_get_target_phandle(fdto, fragment); + phandle = overlay_get_target_phandle(fdto, fragment_offset); if (phandle == (uint32_t)-1) return -FDT_ERR_BADPHANDLE; /* no phandle, try path */ if (!phandle) { /* And then a path based lookup */ - path = fdt_getprop(fdto, fragment, "target-path", &path_len); + path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len); if (path) ret = fdt_path_offset(fdt, path); else @@ -241,6 +226,7 @@ static int overlay_update_local_node_references(void *fdto, if (fixup_len % sizeof(uint32_t)) return -FDT_ERR_BADOVERLAY; + fixup_len /= sizeof(uint32_t); tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); if (!tree_val) { @@ -250,7 +236,7 @@ static int overlay_update_local_node_references(void *fdto, return tree_len; } - for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + for (i = 0; i < fixup_len; i++) { fdt32_t adj_val; uint32_t poffset; @@ -635,7 +621,7 @@ static int overlay_merge(void *fdt, void *fdto) if (overlay < 0) return overlay; - target = overlay_get_target(fdt, fdto, fragment, NULL); + target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL); if (target < 0) return target; @@ -752,7 +738,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) { /* /<fragment-name>/__overlay__/<relative-subnode-path> */ rel_path = s + len; - rel_path_len = e - rel_path; + rel_path_len = e - rel_path - 1; } else if ((e - s) == len && (memcmp(s, "/__overlay__", len - 1) == 0)) { /* /<fragment-name>/__overlay__ */ @@ -778,7 +764,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) return -FDT_ERR_BADOVERLAY; /* get the target of the fragment */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; @@ -800,7 +786,7 @@ static int overlay_symbol_update(void *fdt, void *fdto) if (!target_path) { /* again in case setprop_placeholder changed it */ - ret = overlay_get_target(fdt, fdto, fragment, &target_path); + ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; diff --git a/scripts/dtc/libfdt/fdt_ro.c b/scripts/dtc/libfdt/fdt_ro.c index a5c2797cde..9f6c551a22 100644 --- a/scripts/dtc/libfdt/fdt_ro.c +++ b/scripts/dtc/libfdt/fdt_ro.c @@ -33,36 +33,47 @@ static int fdt_nodename_eq_(const void *fdt, int offset, const char *fdt_get_string(const void *fdt, int stroffset, int *lenp) { - int32_t totalsize = fdt_ro_probe_(fdt); - uint32_t absoffset = stroffset + fdt_off_dt_strings(fdt); + int32_t totalsize; + uint32_t absoffset; size_t len; int err; const char *s, *n; + if (can_assume(VALID_INPUT)) { + s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; + + if (lenp) + *lenp = strlen(s); + return s; + } + totalsize = fdt_ro_probe_(fdt); err = totalsize; if (totalsize < 0) goto fail; err = -FDT_ERR_BADOFFSET; - if (absoffset >= totalsize) + absoffset = stroffset + fdt_off_dt_strings(fdt); + if (absoffset >= (unsigned)totalsize) goto fail; len = totalsize - absoffset; if (fdt_magic(fdt) == FDT_MAGIC) { if (stroffset < 0) goto fail; - if (fdt_version(fdt) >= 17) { - if (stroffset >= fdt_size_dt_strings(fdt)) + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { + if ((unsigned)stroffset >= fdt_size_dt_strings(fdt)) goto fail; if ((fdt_size_dt_strings(fdt) - stroffset) < len) len = fdt_size_dt_strings(fdt) - stroffset; } } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { - if ((stroffset >= 0) - || (stroffset < -fdt_size_dt_strings(fdt))) + unsigned int sw_stroffset = -stroffset; + + if ((stroffset >= 0) || + (sw_stroffset > fdt_size_dt_strings(fdt))) goto fail; - if ((-stroffset) < len) - len = -stroffset; + if (sw_stroffset < len) + len = sw_stroffset; } else { err = -FDT_ERR_INTERNAL; goto fail; @@ -148,13 +159,16 @@ int fdt_generate_phandle(const void *fdt, uint32_t *phandle) static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n) { - int offset = n * sizeof(struct fdt_reserve_entry); - int absoffset = fdt_off_mem_rsvmap(fdt) + offset; + unsigned int offset = n * sizeof(struct fdt_reserve_entry); + unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset; - if (absoffset < fdt_off_mem_rsvmap(fdt)) - return NULL; - if (absoffset > fdt_totalsize(fdt) - sizeof(struct fdt_reserve_entry)) - return NULL; + if (!can_assume(VALID_INPUT)) { + if (absoffset < fdt_off_mem_rsvmap(fdt)) + return NULL; + if (absoffset > fdt_totalsize(fdt) - + sizeof(struct fdt_reserve_entry)) + return NULL; + } return fdt_mem_rsv_(fdt, n); } @@ -164,11 +178,11 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) FDT_RO_PROBE(fdt); re = fdt_mem_rsv(fdt, n); - if (!re) + if (!can_assume(VALID_INPUT) && !re) return -FDT_ERR_BADOFFSET; - *address = fdt64_ld(&re->address); - *size = fdt64_ld(&re->size); + *address = fdt64_ld_(&re->address); + *size = fdt64_ld_(&re->size); return 0; } @@ -178,7 +192,7 @@ int fdt_num_mem_rsv(const void *fdt) const struct fdt_reserve_entry *re; for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) { - if (fdt64_ld(&re->size) == 0) + if (fdt64_ld_(&re->size) == 0) return i; } return -FDT_ERR_TRUNCATED; @@ -295,7 +309,7 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) nameptr = nh->name; - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { /* * For old FDT versions, match the naming conventions of V16: * give only the leaf name (after all /). The actual tree @@ -346,7 +360,8 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, int err; const struct fdt_property *prop; - if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { + if (!can_assume(VALID_INPUT) && + (err = fdt_check_prop_offset_(fdt, offset)) < 0) { if (lenp) *lenp = err; return NULL; @@ -355,7 +370,7 @@ static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, prop = fdt_offset_ptr_(fdt, offset); if (lenp) - *lenp = fdt32_ld(&prop->len); + *lenp = fdt32_ld_(&prop->len); return prop; } @@ -367,7 +382,7 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; @@ -388,11 +403,12 @@ static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; - if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) { + prop = fdt_get_property_by_offset_(fdt, offset, lenp); + if (!can_assume(LIBFDT_FLAWLESS) && !prop) { offset = -FDT_ERR_INTERNAL; break; } - if (fdt_string_eq_(fdt, fdt32_ld(&prop->nameoff), + if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; @@ -413,7 +429,7 @@ const struct fdt_property *fdt_get_property_namelen(const void *fdt, { /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ - if (fdt_version(fdt) < 0x10) { + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; @@ -444,8 +460,8 @@ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, return NULL; /* Handle realignment */ - if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && - fdt32_ld(&prop->len) >= 8) + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -461,19 +477,24 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, if (namep) { const char *name; int namelen; - name = fdt_get_string(fdt, fdt32_ld(&prop->nameoff), - &namelen); - if (!name) { - if (lenp) - *lenp = namelen; - return NULL; + + if (!can_assume(VALID_INPUT)) { + name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff), + &namelen); + *namep = name; + if (!name) { + if (lenp) + *lenp = namelen; + return NULL; + } + } else { + *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff)); } - *namep = name; } /* Handle realignment */ - if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && - fdt32_ld(&prop->len) >= 8) + if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 && + (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8) return prop->data + 4; return prop->data; } @@ -498,7 +519,7 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) return 0; } - return fdt32_ld(php); + return fdt32_ld_(php); } const char *fdt_get_alias_namelen(const void *fdt, @@ -598,10 +619,12 @@ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, } } - if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) - return -FDT_ERR_BADOFFSET; - else if (offset == -FDT_ERR_BADOFFSET) - return -FDT_ERR_BADSTRUCTURE; + if (!can_assume(VALID_INPUT)) { + if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) + return -FDT_ERR_BADOFFSET; + else if (offset == -FDT_ERR_BADOFFSET) + return -FDT_ERR_BADSTRUCTURE; + } return offset; /* error from fdt_next_node() */ } @@ -613,7 +636,8 @@ int fdt_node_depth(const void *fdt, int nodeoffset) err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); if (err) - return (err < 0) ? err : -FDT_ERR_INTERNAL; + return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err : + -FDT_ERR_INTERNAL; return nodedepth; } @@ -658,7 +682,7 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { int offset; - if ((phandle == 0) || (phandle == -1)) + if ((phandle == 0) || (phandle == ~0U)) return -FDT_ERR_BADPHANDLE; FDT_RO_PROBE(fdt); @@ -833,66 +857,3 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, return offset; /* error from fdt_next_node() */ } - -int fdt_check_full(const void *fdt, size_t bufsize) -{ - int err; - int num_memrsv; - int offset, nextoffset = 0; - uint32_t tag; - unsigned depth = 0; - const void *prop; - const char *propname; - - if (bufsize < FDT_V1_SIZE) - return -FDT_ERR_TRUNCATED; - err = fdt_check_header(fdt); - if (err != 0) - return err; - if (bufsize < fdt_totalsize(fdt)) - return -FDT_ERR_TRUNCATED; - - num_memrsv = fdt_num_mem_rsv(fdt); - if (num_memrsv < 0) - return num_memrsv; - - while (1) { - offset = nextoffset; - tag = fdt_next_tag(fdt, offset, &nextoffset); - - if (nextoffset < 0) - return nextoffset; - - switch (tag) { - case FDT_NOP: - break; - - case FDT_END: - if (depth != 0) - return -FDT_ERR_BADSTRUCTURE; - return 0; - - case FDT_BEGIN_NODE: - depth++; - if (depth > INT_MAX) - return -FDT_ERR_BADSTRUCTURE; - break; - - case FDT_END_NODE: - if (depth == 0) - return -FDT_ERR_BADSTRUCTURE; - depth--; - break; - - case FDT_PROP: - prop = fdt_getprop_by_offset(fdt, offset, &propname, - &err); - if (!prop) - return err; - break; - - default: - return -FDT_ERR_INTERNAL; - } - } -} diff --git a/scripts/dtc/libfdt/fdt_rw.c b/scripts/dtc/libfdt/fdt_rw.c index 8795947c00..3621d3651d 100644 --- a/scripts/dtc/libfdt/fdt_rw.c +++ b/scripts/dtc/libfdt/fdt_rw.c @@ -24,14 +24,16 @@ static int fdt_blocks_misordered_(const void *fdt, static int fdt_rw_probe_(void *fdt) { + if (can_assume(VALID_DTB)) + return 0; FDT_RO_PROBE(fdt); - if (fdt_version(fdt) < 17) + if (!can_assume(LATEST) && fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; - if (fdt_version(fdt) > 17) + if (!can_assume(LATEST) && fdt_version(fdt) > 17) fdt_set_version(fdt, 17); return 0; @@ -44,7 +46,7 @@ static int fdt_rw_probe_(void *fdt) return err_; \ } -static inline int fdt_data_size_(void *fdt) +static inline unsigned int fdt_data_size_(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } @@ -52,15 +54,16 @@ static inline int fdt_data_size_(void *fdt) static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; - char *end = (char *)fdt + fdt_data_size_(fdt); + unsigned int dsize = fdt_data_size_(fdt); + size_t soff = p - (char *)fdt; - if (((p + oldlen) < p) || ((p + oldlen) > end)) + if ((oldlen < 0) || (soff + oldlen < soff) || (soff + oldlen > dsize)) return -FDT_ERR_BADOFFSET; - if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) + if ((p < (char *)fdt) || (dsize + newlen < (unsigned)oldlen)) return -FDT_ERR_BADOFFSET; - if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) + if (dsize - oldlen + newlen > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; - memmove(p + newlen, p + oldlen, end - p - oldlen); + memmove(p + newlen, p + oldlen, ((char *)fdt + dsize) - (p + oldlen)); return 0; } @@ -112,6 +115,15 @@ static int fdt_splice_string_(void *fdt, int newlen) return 0; } +/** + * fdt_find_add_string_() - Find or allocate a string + * + * @fdt: pointer to the device tree to check/adjust + * @s: string to find/add + * @allocated: Set to 0 if the string was found, 1 if not found and so + * allocated. Ignored if can_assume(NO_ROLLBACK) + * @return offset of string in the string table (whether found or added) + */ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); @@ -120,7 +132,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) int len = strlen(s) + 1; int err; - *allocated = 0; + if (!can_assume(NO_ROLLBACK)) + *allocated = 0; p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); if (p) @@ -132,7 +145,8 @@ static int fdt_find_add_string_(void *fdt, const char *s, int *allocated) if (err) return err; - *allocated = 1; + if (!can_assume(NO_ROLLBACK)) + *allocated = 1; memcpy(new, s, len); return (new - strtab); @@ -206,7 +220,8 @@ static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, err = fdt_splice_struct_(fdt, *prop, 0, proplen); if (err) { - if (allocated) + /* Delete the string if we failed to add it */ + if (!can_assume(NO_ROLLBACK) && allocated) fdt_del_last_string_(fdt, name); return err; } @@ -334,7 +349,10 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, return offset; /* Try to place the new node after the parent's properties */ - fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ + tag = fdt_next_tag(fdt, parentoffset, &nextoffset); + /* the fdt_subnode_offset_namelen() should ensure this never hits */ + if (!can_assume(LIBFDT_FLAWLESS) && (tag != FDT_BEGIN_NODE)) + return -FDT_ERR_INTERNAL; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); @@ -376,7 +394,9 @@ int fdt_del_node(void *fdt, int nodeoffset) } static void fdt_packblocks_(const char *old, char *new, - int mem_rsv_size, int struct_size) + int mem_rsv_size, + int struct_size, + int strings_size) { int mem_rsv_off, struct_off, strings_off; @@ -391,8 +411,7 @@ static void fdt_packblocks_(const char *old, char *new, fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); - memmove(new + strings_off, old + fdt_off_dt_strings(old), - fdt_size_dt_strings(old)); + memmove(new + strings_off, old + fdt_off_dt_strings(old), strings_size); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } @@ -411,17 +430,20 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); - if (fdt_version(fdt) >= 17) { + if (can_assume(LATEST) || fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); - } else { + } else if (fdt_version(fdt) == 16) { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; if (struct_size < 0) return struct_size; + } else { + return -FDT_ERR_BADVERSION; } - if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { + if (can_assume(LIBFDT_ORDER) || + !fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) @@ -449,7 +471,8 @@ int fdt_open_into(const void *fdt, void *buf, int bufsize) return -FDT_ERR_NOSPACE; } - fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); + fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size, + fdt_size_dt_strings(fdt)); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); @@ -469,7 +492,8 @@ int fdt_pack(void *fdt) mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); - fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); + fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt), + fdt_size_dt_strings(fdt)); fdt_set_totalsize(fdt, fdt_data_size_(fdt)); return 0; diff --git a/scripts/dtc/libfdt/fdt_strerror.c b/scripts/dtc/libfdt/fdt_strerror.c index 768db66ead..d852b77e81 100644 --- a/scripts/dtc/libfdt/fdt_strerror.c +++ b/scripts/dtc/libfdt/fdt_strerror.c @@ -39,8 +39,9 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), FDT_ERRTABENT(FDT_ERR_BADFLAGS), + FDT_ERRTABENT(FDT_ERR_ALIGNMENT), }; -#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) +#define FDT_ERRTABSIZE ((int)(sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))) const char *fdt_strerror(int errval) { @@ -48,7 +49,7 @@ const char *fdt_strerror(int errval) return "<valid offset/length>"; else if (errval == 0) return "<no error>"; - else if (errval > -FDT_ERRTABSIZE) { + else if (-errval < FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) diff --git a/scripts/dtc/libfdt/fdt_sw.c b/scripts/dtc/libfdt/fdt_sw.c index 76bea22f73..4c569ee7eb 100644 --- a/scripts/dtc/libfdt/fdt_sw.c +++ b/scripts/dtc/libfdt/fdt_sw.c @@ -12,10 +12,13 @@ static int fdt_sw_probe_(void *fdt) { - if (fdt_magic(fdt) == FDT_MAGIC) - return -FDT_ERR_BADSTATE; - else if (fdt_magic(fdt) != FDT_SW_MAGIC) - return -FDT_ERR_BADMAGIC; + if (!can_assume(VALID_INPUT)) { + if (fdt_magic(fdt) == FDT_MAGIC) + return -FDT_ERR_BADSTATE; + else if (fdt_magic(fdt) != FDT_SW_MAGIC) + return -FDT_ERR_BADMAGIC; + } + return 0; } @@ -29,7 +32,7 @@ static int fdt_sw_probe_(void *fdt) /* 'memrsv' state: Initial state after fdt_create() * * Allowed functions: - * fdt_add_reservmap_entry() + * fdt_add_reservemap_entry() * fdt_finish_reservemap() [moves to 'struct' state] */ static int fdt_sw_probe_memrsv_(void *fdt) @@ -38,7 +41,7 @@ static int fdt_sw_probe_memrsv_(void *fdt) if (err) return err; - if (fdt_off_dt_strings(fdt) != 0) + if (!can_assume(VALID_INPUT) && fdt_off_dt_strings(fdt) != 0) return -FDT_ERR_BADSTATE; return 0; } @@ -64,7 +67,8 @@ static int fdt_sw_probe_struct_(void *fdt) if (err) return err; - if (fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) + if (!can_assume(VALID_INPUT) && + fdt_off_dt_strings(fdt) != fdt_totalsize(fdt)) return -FDT_ERR_BADSTATE; return 0; } @@ -89,8 +93,8 @@ static inline uint32_t sw_flags(void *fdt) static void *fdt_grab_space_(void *fdt, size_t len) { - int offset = fdt_size_dt_struct(fdt); - int spaceleft; + unsigned int offset = fdt_size_dt_struct(fdt); + unsigned int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); @@ -104,8 +108,8 @@ static void *fdt_grab_space_(void *fdt, size_t len) int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags) { - const size_t hdrsize = FDT_ALIGN(sizeof(struct fdt_header), - sizeof(struct fdt_reserve_entry)); + const int hdrsize = FDT_ALIGN(sizeof(struct fdt_header), + sizeof(struct fdt_reserve_entry)); void *fdt = buf; if (bufsize < hdrsize) @@ -148,13 +152,17 @@ int fdt_resize(void *fdt, void *buf, int bufsize) FDT_SW_PROBE(fdt); + if (bufsize < 0) + return -FDT_ERR_NOSPACE; + headsize = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); - if ((headsize + tailsize) > fdt_totalsize(fdt)) + if (!can_assume(VALID_DTB) && + headsize + tailsize > fdt_totalsize(fdt)) return -FDT_ERR_INTERNAL; - if ((headsize + tailsize) > bufsize) + if ((headsize + tailsize) > (unsigned)bufsize) return -FDT_ERR_NOSPACE; oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; @@ -242,18 +250,18 @@ int fdt_end_node(void *fdt) static int fdt_add_string_(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); - int strtabsize = fdt_size_dt_strings(fdt); - int len = strlen(s) + 1; - int struct_top, offset; + unsigned int strtabsize = fdt_size_dt_strings(fdt); + unsigned int len = strlen(s) + 1; + unsigned int struct_top, offset; - offset = -strtabsize - len; + offset = strtabsize + len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); - if (fdt_totalsize(fdt) + offset < struct_top) + if (fdt_totalsize(fdt) - offset < struct_top) return 0; /* no more room :( */ - memcpy(strtab + offset, s, len); + memcpy(strtab - offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); - return offset; + return -offset; } /* Must only be used to roll back in case of error */ @@ -369,7 +377,7 @@ int fdt_finish(void *fdt) fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); /* And fix up fields that were keeping intermediate state. */ - fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); + fdt_set_last_comp_version(fdt, FDT_LAST_COMPATIBLE_VERSION); fdt_set_magic(fdt, FDT_MAGIC); return 0; diff --git a/scripts/dtc/libfdt/fdt_wip.c b/scripts/dtc/libfdt/fdt_wip.c index f64139e0b3..c2d7566a67 100644 --- a/scripts/dtc/libfdt/fdt_wip.c +++ b/scripts/dtc/libfdt/fdt_wip.c @@ -23,7 +23,7 @@ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, if (!propval) return proplen; - if (proplen < (len + idx)) + if ((unsigned)proplen < (len + idx)) return -FDT_ERR_NOSPACE; memcpy((char *)propval + idx, val, len); diff --git a/scripts/dtc/libfdt/libfdt.h b/scripts/dtc/libfdt/libfdt.h index 7b5ffd13a8..77ccff1991 100644 --- a/scripts/dtc/libfdt/libfdt.h +++ b/scripts/dtc/libfdt/libfdt.h @@ -9,7 +9,12 @@ #include "libfdt_env.h" #include "fdt.h" +#ifdef __cplusplus +extern "C" { +#endif + #define FDT_FIRST_SUPPORTED_VERSION 0x02 +#define FDT_LAST_COMPATIBLE_VERSION 0x10 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ @@ -97,7 +102,11 @@ /* FDT_ERR_BADFLAGS: The function was passed a flags field that * contains invalid flags or an invalid combination of flags. */ -#define FDT_ERR_MAX 18 +#define FDT_ERR_ALIGNMENT 19 + /* FDT_ERR_ALIGNMENT: The device tree base address is not 8-byte + * aligned. */ + +#define FDT_ERR_MAX 19 /* constants */ #define FDT_MAX_PHANDLE 0xfffffffe @@ -118,11 +127,16 @@ static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /* - * Alignment helpers: - * These helpers access words from a device tree blob. They're - * built to work even with unaligned pointers on platforms (ike - * ARM) that don't like unaligned loads and stores + * External helpers to access words from a device tree blob. They're built + * to work even with unaligned pointers on platforms (such as ARMv5) that don't + * like unaligned loads and stores. */ +static inline uint16_t fdt16_ld(const fdt16_t *p) +{ + const uint8_t *bp = (const uint8_t *)p; + + return ((uint16_t)bp[0] << 8) | bp[1]; +} static inline uint32_t fdt32_ld(const fdt32_t *p) { @@ -136,7 +150,7 @@ static inline uint32_t fdt32_ld(const fdt32_t *p) static inline void fdt32_st(void *property, uint32_t value) { - uint8_t *bp = property; + uint8_t *bp = (uint8_t *)property; bp[0] = value >> 24; bp[1] = (value >> 16) & 0xff; @@ -160,7 +174,7 @@ static inline uint64_t fdt64_ld(const fdt64_t *p) static inline void fdt64_st(void *property, uint64_t value) { - uint8_t *bp = property; + uint8_t *bp = (uint8_t *)property; bp[0] = value >> 56; bp[1] = (value >> 48) & 0xff; @@ -180,23 +194,23 @@ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode - * * @fdt: FDT blob * @offset: Offset of node to check - * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none + * + * Return: offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode + * @fdt: FDT blob + * @offset: Offset of previous subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. * - * @fdt: FDT blob - * @offset: Offset of previous subnode - * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more - * subnodes + * Return: offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more + * subnodes */ int fdt_next_subnode(const void *fdt, int offset); @@ -221,7 +235,6 @@ int fdt_next_subnode(const void *fdt, int offset); * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. - * */ #define fdt_for_each_subnode(node, fdt, parent) \ for (node = fdt_first_subnode(fdt, parent); \ @@ -265,16 +278,21 @@ fdt_set_hdr_(size_dt_struct); /** * fdt_header_size - return the size of the tree's header * @fdt: pointer to a flattened device tree + * + * Return: size of DTB header in bytes + */ +size_t fdt_header_size(const void *fdt); + +/** + * fdt_header_size_ - internal function to get header size from a version number + * @version: devicetree version number + * + * Return: size of DTB header in bytes */ size_t fdt_header_size_(uint32_t version); -static inline size_t fdt_header_size(const void *fdt) -{ - return fdt_header_size_(fdt_version(fdt)); -} /** * fdt_check_header - sanity check a device tree header - * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what @@ -399,8 +417,7 @@ static inline uint32_t fdt_get_max_phandle(const void *fdt) * highest phandle value in the device tree blob) will be returned in the * @phandle parameter. * - * Returns: - * 0 on success or a negative error-code on failure + * Return: 0 on success or a negative error-code on failure */ int fdt_generate_phandle(const void *fdt, uint32_t *phandle); @@ -420,9 +437,11 @@ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: pointers to 64-bit variables + * @n: index of reserve map entry + * @address: pointer to 64-bit variable to hold the start address + * @size: pointer to 64-bit variable to hold the size of the entry * - * On success, *address and *size will contain the address and size of + * On success, @address and @size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * @@ -445,6 +464,8 @@ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. + * + * Return: offset of the subnode or -FDT_ERR_NOTFOUND if name not found. */ #ifndef SWIG /* Not available in Python */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, @@ -484,6 +505,8 @@ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); * * Identical to fdt_path_offset(), but only consider the first namelen * characters of path as the path name. + * + * Return: offset of the node or negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); @@ -583,9 +606,9 @@ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * - * @property_offset: property offset (int, lvalue) - * @fdt: FDT blob (const void *) - * @node: node offset (int) + * @property: property offset (int, lvalue) + * @fdt: FDT blob (const void *) + * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * @@ -637,6 +660,13 @@ int fdt_next_property_offset(const void *fdt, int offset); const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp); +static inline struct fdt_property *fdt_get_property_by_offset_w(void *fdt, + int offset, + int *lenp) +{ + return (struct fdt_property *)(uintptr_t) + fdt_get_property_by_offset(fdt, offset, lenp); +} /** * fdt_get_property_namelen - find a property based on substring @@ -648,6 +678,9 @@ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, * * Identical to fdt_get_property(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the structure representing the property, or NULL + * if not found */ #ifndef SWIG /* Not available in Python */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, @@ -740,6 +773,8 @@ const void *fdt_getprop_by_offset(const void *fdt, int offset, * * Identical to fdt_getprop(), but only examine the first namelen * characters of name for matching the property name. + * + * Return: pointer to the property's value or NULL on error */ #ifndef SWIG /* Not available in Python */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, @@ -761,10 +796,10 @@ static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property - * named 'name' of the node at offset nodeoffset (this will be a + * named @name of the node at offset @nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). - * If lenp is non-NULL, the length of the property value is also - * returned, in the integer pointed to by lenp. + * If @lenp is non-NULL, the length of the property value is also + * returned, in the integer pointed to by @lenp. * * returns: * pointer to the property's value @@ -809,8 +844,11 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); * @name: name of the alias th look up * @namelen: number of characters of name to consider * - * Identical to fdt_get_alias(), but only examine the first namelen - * characters of name for matching the alias name. + * Identical to fdt_get_alias(), but only examine the first @namelen + * characters of @name for matching the alias name. + * + * Return: a pointer to the expansion of the alias named @name, if it exists, + * NULL otherwise */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, @@ -823,7 +861,7 @@ const char *fdt_get_alias_namelen(const void *fdt, * @name: name of the alias th look up * * fdt_get_alias() retrieves the value of a given alias. That is, the - * value of the property named 'name' in the node /aliases. + * value of the property named @name in the node /aliases. * * returns: * a pointer to the expansion of the alias named 'name', if it exists @@ -999,14 +1037,13 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** - * fdt_node_check_compatible: check a node's compatible property + * fdt_node_check_compatible - check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * - * * fdt_node_check_compatible() returns 0 if the given node contains a - * 'compatible' property with the given string as one of its elements, + * @compatible property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: @@ -1070,7 +1107,7 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, * one or more strings, each terminated by \0, as is found in a device tree * "compatible" property. * - * @return: 1 if the string is found in the list, 0 not found, or invalid list + * Return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); @@ -1079,7 +1116,8 @@ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list - * @return: + * + * Return: * the number of strings in the given property * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist @@ -1099,7 +1137,7 @@ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); * small-valued cell properties, such as #address-cells, when searching for * the empty string. * - * @return: + * return: * the index of the string in the list of strings * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist or does not contain @@ -1123,7 +1161,7 @@ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, * If non-NULL, the length of the string (on success) or a negative error-code * (on failure) will be stored in the integer pointer to by lenp. * - * @return: + * Return: * A pointer to the string at the given index in the string list or NULL on * failure. On success the length of the string will be stored in the memory * location pointed to by the lenp parameter, if non-NULL. On failure one of @@ -1212,6 +1250,8 @@ int fdt_size_cells(const void *fdt, int nodeoffset); * starting from the given index, and using only the first characters * of the name. It is useful when you want to manipulate only one value of * an array and you have a string that doesn't end with \0. + * + * Return: 0 on success, negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, @@ -1325,8 +1365,13 @@ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, /** * fdt_setprop_inplace_cell - change the value of a single-cell property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node containing the property + * @name: name of the property to change the value of + * @val: new value of the 32-bit cell * * This is an alternative name for fdt_setprop_inplace_u32() + * Return: 0 on success, negative libfdt error number otherwise. */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1398,7 +1443,7 @@ int fdt_nop_node(void *fdt, int nodeoffset); /** * fdt_create_with_flags - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * @flags: a valid combination of FDT_CREATE_FLAG_ flags, or 0. * @@ -1416,7 +1461,7 @@ int fdt_create_with_flags(void *buf, int bufsize, uint32_t flags); /** * fdt_create - begin creation of a new fdt - * @fdt: pointer to memory allocated where fdt will be created + * @buf: pointer to memory allocated where fdt will be created * @bufsize: size of the memory space at fdt * * fdt_create() is equivalent to fdt_create_with_flags() with flags=0. @@ -1481,7 +1526,8 @@ int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob - * @address, @size: 64-bit values (native endian) + * @address: 64-bit start address of the reserve map entry + * @size: 64-bit size of the reserved region * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. @@ -1686,8 +1732,14 @@ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, /** * fdt_setprop_cell - set a property to a single cell value + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value for the property (native endian) * * This is an alternative name for fdt_setprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1858,8 +1910,14 @@ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, /** * fdt_appendprop_cell - append a single cell value to a property + * @fdt: pointer to the device tree blob + * @nodeoffset: offset of the node whose property to change + * @name: name of the property to change + * @val: 32-bit integer value to append to the property (native endian) * * This is an alternative name for fdt_appendprop_u32() + * + * Return: 0 on success, negative libfdt error value otherwise. */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) @@ -1962,13 +2020,16 @@ int fdt_delprop(void *fdt, int nodeoffset, const char *name); * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node - * @name: name of the subnode to locate + * @name: name of the subnode to create * @namelen: number of characters of name to consider * - * Identical to fdt_add_subnode(), but use only the first namelen - * characters of name as the name of the new node. This is useful for + * Identical to fdt_add_subnode(), but use only the first @namelen + * characters of @name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. + * + * Return: structure block offset of the created subnode (>=0), + * negative libfdt error value otherwise */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, @@ -1987,7 +2048,7 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset, * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. - + * * returns: * structure block offset of the created nodeequested subnode (>=0), on * success @@ -2062,10 +2123,32 @@ int fdt_del_node(void *fdt, int nodeoffset); */ int fdt_overlay_apply(void *fdt, void *fdto); +/** + * fdt_overlay_target_offset - retrieves the offset of a fragment's target + * @fdt: Base device tree blob + * @fdto: Device tree overlay blob + * @fragment_offset: node offset of the fragment in the overlay + * @pathp: pointer which receives the path of the target (or NULL) + * + * fdt_overlay_target_offset() retrieves the target offset in the base + * device tree of a fragment, no matter how the actual targeting is + * done (through a phandle or a path) + * + * returns: + * the targeted node offset in the base device tree + * Negative error code on error + */ +int fdt_overlay_target_offset(const void *fdt, const void *fdto, + int fragment_offset, char const **pathp); + /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ const char *fdt_strerror(int errval); +#ifdef __cplusplus +} +#endif + #endif /* LIBFDT_H */ diff --git a/scripts/dtc/libfdt/libfdt_internal.h b/scripts/dtc/libfdt/libfdt_internal.h index 741eeb3150..16bda1906a 100644 --- a/scripts/dtc/libfdt/libfdt_internal.h +++ b/scripts/dtc/libfdt/libfdt_internal.h @@ -10,10 +10,10 @@ #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) -int fdt_ro_probe_(const void *fdt); +int32_t fdt_ro_probe_(const void *fdt); #define FDT_RO_PROBE(fdt) \ { \ - int totalsize_; \ + int32_t totalsize_; \ if ((totalsize_ = fdt_ro_probe_(fdt)) < 0) \ return totalsize_; \ } @@ -46,6 +46,147 @@ static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); } +/* + * Internal helpers to access tructural elements of the device tree + * blob (rather than for exaple reading integers from within property + * values). We assume that we are either given a naturally aligned + * address for the platform or if we are not, we are on a platform + * where unaligned memory reads will be handled in a graceful manner. + * If not the external helpers fdtXX_ld() from libfdt.h can be used + * instead. + */ +static inline uint32_t fdt32_ld_(const fdt32_t *p) +{ + return fdt32_to_cpu(*p); +} + +static inline uint64_t fdt64_ld_(const fdt64_t *p) +{ + return fdt64_to_cpu(*p); +} + #define FDT_SW_MAGIC (~FDT_MAGIC) +/**********************************************************************/ +/* Checking controls */ +/**********************************************************************/ + +#ifndef FDT_ASSUME_MASK +#define FDT_ASSUME_MASK 0 +#endif + +/* + * Defines assumptions which can be enabled. Each of these can be enabled + * individually. For maximum safety, don't enable any assumptions! + * + * For minimal code size and no safety, use ASSUME_PERFECT at your own risk. + * You should have another method of validating the device tree, such as a + * signature or hash check before using libfdt. + * + * For situations where security is not a concern it may be safe to enable + * ASSUME_SANE. + */ +enum { + /* + * This does essentially no checks. Only the latest device-tree + * version is correctly handled. Inconsistencies or errors in the device + * tree may cause undefined behaviour or crashes. Invalid parameters + * passed to libfdt may do the same. + * + * If an error occurs when modifying the tree it may leave the tree in + * an intermediate (but valid) state. As an example, adding a property + * where there is insufficient space may result in the property name + * being added to the string table even though the property itself is + * not added to the struct section. + * + * Only use this if you have a fully validated device tree with + * the latest supported version and wish to minimise code size. + */ + ASSUME_PERFECT = 0xff, + + /* + * This assumes that the device tree is sane. i.e. header metadata + * and basic hierarchy are correct. + * + * With this assumption enabled, normal device trees produced by libfdt + * and the compiler should be handled safely. Malicious device trees and + * complete garbage may cause libfdt to behave badly or crash. Truncated + * device trees (e.g. those only partially loaded) can also cause + * problems. + * + * Note: Only checks that relate exclusively to the device tree itself + * (not the parameters passed to libfdt) are disabled by this + * assumption. This includes checking headers, tags and the like. + */ + ASSUME_VALID_DTB = 1 << 0, + + /* + * This builds on ASSUME_VALID_DTB and further assumes that libfdt + * functions are called with valid parameters, i.e. not trigger + * FDT_ERR_BADOFFSET or offsets that are out of bounds. It disables any + * extensive checking of parameters and the device tree, making various + * assumptions about correctness. + * + * It doesn't make sense to enable this assumption unless + * ASSUME_VALID_DTB is also enabled. + */ + ASSUME_VALID_INPUT = 1 << 1, + + /* + * This disables checks for device-tree version and removes all code + * which handles older versions. + * + * Only enable this if you know you have a device tree with the latest + * version. + */ + ASSUME_LATEST = 1 << 2, + + /* + * This assumes that it is OK for a failed addition to the device tree, + * due to lack of space or some other problem, to skip any rollback + * steps (such as dropping the property name from the string table). + * This is safe to enable in most circumstances, even though it may + * leave the tree in a sub-optimal state. + */ + ASSUME_NO_ROLLBACK = 1 << 3, + + /* + * This assumes that the device tree components appear in a 'convenient' + * order, i.e. the memory reservation block first, then the structure + * block and finally the string block. + * + * This order is not specified by the device-tree specification, + * but is expected by libfdt. The device-tree compiler always created + * device trees with this order. + * + * This assumption disables a check in fdt_open_into() and removes the + * ability to fix the problem there. This is safe if you know that the + * device tree is correctly ordered. See fdt_blocks_misordered_(). + */ + ASSUME_LIBFDT_ORDER = 1 << 4, + + /* + * This assumes that libfdt itself does not have any internal bugs. It + * drops certain checks that should never be needed unless libfdt has an + * undiscovered bug. + * + * This can generally be considered safe to enable. + */ + ASSUME_LIBFDT_FLAWLESS = 1 << 5, +}; + +/** + * can_assume_() - check if a particular assumption is enabled + * + * @mask: Mask to check (ASSUME_...) + * @return true if that assumption is enabled, else false + */ +static inline bool can_assume_(int mask) +{ + return FDT_ASSUME_MASK & mask; +} + +/** helper macros for checking assumptions */ +#define can_assume(_assume) can_assume_(ASSUME_ ## _assume) + #endif /* LIBFDT_INTERNAL_H */ diff --git a/scripts/dtc/livetree.c b/scripts/dtc/livetree.c index 032df5878c..f46a098d5a 100644 --- a/scripts/dtc/livetree.c +++ b/scripts/dtc/livetree.c @@ -438,7 +438,7 @@ cell_t propval_cell(struct property *prop) return fdt32_to_cpu(*((fdt32_t *)prop->val.val)); } -cell_t propval_cell_n(struct property *prop, int n) +cell_t propval_cell_n(struct property *prop, unsigned int n) { assert(prop->val.len / sizeof(cell_t) >= n); return fdt32_to_cpu(*((fdt32_t *)prop->val.val + n)); @@ -526,7 +526,7 @@ struct node *get_node_by_path(struct node *tree, const char *path) p = strchr(path, '/'); for_each_child(tree, child) { - if (p && strprefixeq(path, p - path, child->name)) + if (p && strprefixeq(path, (size_t)(p - path), child->name)) return get_node_by_path(child, p+1); else if (!p && streq(path, child->name)) return child; @@ -559,7 +559,7 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) { struct node *child, *node; - if ((phandle == 0) || (phandle == -1)) { + if (!phandle_is_valid(phandle)) { assert(generate_fixups); return NULL; } @@ -581,12 +581,39 @@ struct node *get_node_by_phandle(struct node *tree, cell_t phandle) struct node *get_node_by_ref(struct node *tree, const char *ref) { + struct node *target = tree; + const char *label = NULL, *path = NULL; + if (streq(ref, "/")) return tree; - else if (ref[0] == '/') - return get_node_by_path(tree, ref); + + if (ref[0] == '/') + path = ref; else - return get_node_by_label(tree, ref); + label = ref; + + if (label) { + const char *slash = strchr(label, '/'); + char *buf = NULL; + + if (slash) { + buf = xstrndup(label, slash - label); + label = buf; + path = slash + 1; + } + + target = get_node_by_label(tree, label); + + free(buf); + + if (!target) + return NULL; + } + + if (path) + target = get_node_by_path(target, path); + + return target; } cell_t get_node_phandle(struct node *root, struct node *node) @@ -594,7 +621,7 @@ cell_t get_node_phandle(struct node *root, struct node *node) static cell_t phandle = 1; /* FIXME: ick, static local */ struct data d = empty_data; - if ((node->phandle != 0) && (node->phandle != -1)) + if (phandle_is_valid(node->phandle)) return node->phandle; while (get_node_by_phandle(root, phandle)) @@ -892,6 +919,12 @@ static void add_fixup_entry(struct dt_info *dti, struct node *fn, /* m->ref can only be a REF_PHANDLE, but check anyway */ assert(m->type == REF_PHANDLE); + /* The format only permits fixups for references to label, not + * references to path */ + if (strchr(m->ref, '/')) + die("Can't generate fixup for reference to path &{%s}\n", + m->ref); + /* there shouldn't be any ':' in the arguments */ if (strchr(node->fullpath, ':') || strchr(prop->name, ':')) die("arguments should not contain ':'\n"); diff --git a/scripts/dtc/srcpos.c b/scripts/dtc/srcpos.c index f5205fb9c1..4fdb22a019 100644 --- a/scripts/dtc/srcpos.c +++ b/scripts/dtc/srcpos.c @@ -20,7 +20,7 @@ struct search_path { static struct search_path *search_path_head, **search_path_tail; /* Detect infinite include recursion. */ -#define MAX_SRCFILE_DEPTH (100) +#define MAX_SRCFILE_DEPTH (200) static int srcfile_depth; /* = 0 */ static char *get_dirname(const char *path) diff --git a/scripts/dtc/treesource.c b/scripts/dtc/treesource.c index c9d980c8ab..33fedee82d 100644 --- a/scripts/dtc/treesource.c +++ b/scripts/dtc/treesource.c @@ -110,13 +110,13 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) fprintf(f, "%02"PRIx8, *(const uint8_t*)p); break; case 2: - fprintf(f, "0x%02"PRIx16, fdt16_to_cpu(*(const fdt16_t*)p)); + fprintf(f, "0x%02"PRIx16, dtb_ld16(p)); break; case 4: - fprintf(f, "0x%02"PRIx32, fdt32_to_cpu(*(const fdt32_t*)p)); + fprintf(f, "0x%02"PRIx32, dtb_ld32(p)); break; case 8: - fprintf(f, "0x%02"PRIx64, fdt64_to_cpu(*(const fdt64_t*)p)); + fprintf(f, "0x%02"PRIx64, dtb_ld64(p)); break; } if (p + width < end) @@ -124,27 +124,6 @@ static void write_propval_int(FILE *f, const char *p, size_t len, size_t width) } } -static bool has_data_type_information(struct marker *m) -{ - return m->type >= TYPE_UINT8; -} - -static struct marker *next_type_marker(struct marker *m) -{ - while (m && !has_data_type_information(m)) - m = m->next; - return m; -} - -size_t type_marker_length(struct marker *m) -{ - struct marker *next = next_type_marker(m->next); - - if (next) - return next->offset - m->offset; - return 0; -} - static const char *delim_start[] = { [TYPE_UINT8] = "[", [TYPE_UINT16] = "/bits/ 16 <", @@ -183,7 +162,7 @@ static enum markertype guess_value_type(struct property *prop) nnotcelllbl++; } - if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul < (len-nnul)) + if ((p[len-1] == '\0') && (nnotstring == 0) && (nnul <= (len-nnul)) && (nnotstringlbl == 0)) { return TYPE_STRING; } else if (((len % sizeof(cell_t)) == 0) && (nnotcelllbl == 0)) { @@ -229,26 +208,39 @@ static void write_propval(FILE *f, struct property *prop) size_t chunk_len = (m->next ? m->next->offset : len) - m->offset; size_t data_len = type_marker_length(m) ? : len - m->offset; const char *p = &prop->val.val[m->offset]; + struct marker *m_phandle; - if (has_data_type_information(m)) { + if (is_type_marker(m->type)) { emit_type = m->type; fprintf(f, " %s", delim_start[emit_type]); } else if (m->type == LABEL) fprintf(f, " %s:", m->ref); - else if (m->offset) - fputc(' ', f); - if (emit_type == TYPE_NONE) { - assert(chunk_len == 0); + if (emit_type == TYPE_NONE || chunk_len == 0) continue; - } switch(emit_type) { case TYPE_UINT16: write_propval_int(f, p, chunk_len, 2); break; case TYPE_UINT32: - write_propval_int(f, p, chunk_len, 4); + m_phandle = prop->val.markers; + for_each_marker_of_type(m_phandle, REF_PHANDLE) + if (m->offset == m_phandle->offset) + break; + + if (m_phandle) { + if (m_phandle->ref[0] == '/') + fprintf(f, "&{%s}", m_phandle->ref); + else + fprintf(f, "&%s", m_phandle->ref); + if (chunk_len > 4) { + fputc(' ', f); + write_propval_int(f, p + 4, chunk_len - 4, 4); + } + } else { + write_propval_int(f, p, chunk_len, 4); + } break; case TYPE_UINT64: write_propval_int(f, p, chunk_len, 8); diff --git a/scripts/dtc/update-dtc-source.sh b/scripts/dtc/update-dtc-source.sh index 604ed254f5..141d362942 100755 --- a/scripts/dtc/update-dtc-source.sh +++ b/scripts/dtc/update-dtc-source.sh @@ -46,7 +46,7 @@ last_dtc_ver=$(get_last_dtc_version) # Build DTC cd $DTC_LINUX_PATH git ls-files . | grep -vE '^(update-dtc-source\.sh|Makefile|\.gitignore)$' | xargs git rm -mkdir libfdt +mkdir -p libfdt cd $DTC_UPSTREAM_PATH make clean make check diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c index 48af961dcc..507f0120cd 100644 --- a/scripts/dtc/util.c +++ b/scripts/dtc/util.c @@ -13,6 +13,7 @@ #include <stdarg.h> #include <string.h> #include <assert.h> +#include <inttypes.h> #include <errno.h> #include <fcntl.h> @@ -32,6 +33,17 @@ char *xstrdup(const char *s) return d; } +char *xstrndup(const char *s, size_t n) +{ + size_t len = strnlen(s, n) + 1; + char *d = xmalloc(len); + + memcpy(d, s, len - 1); + d[len - 1] = '\0'; + + return d; +} + int xavsprintf_append(char **strp, const char *fmt, va_list ap) { int n, size = 0; /* start with 128 bytes */ @@ -352,11 +364,11 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size) } /* we should now have a type */ - if ((*fmt == '\0') || !strchr("iuxs", *fmt)) + if ((*fmt == '\0') || !strchr("iuxsr", *fmt)) return -1; /* convert qualifier (bhL) to byte size */ - if (*fmt != 's') + if (*fmt != 's' && *fmt != 'r') *size = qualifier == 'b' ? 1 : qualifier == 'h' ? 2 : qualifier == 'l' ? 4 : -1; @@ -393,7 +405,7 @@ void utilfdt_print_data(const char *data, int len) printf(" = <"); for (i = 0, len /= 4; i < len; i++) - printf("0x%08x%s", fdt32_to_cpu(cell[i]), + printf("0x%08" PRIx32 "%s", fdt32_to_cpu(cell[i]), i < (len - 1) ? " " : ""); printf(">"); } else { diff --git a/scripts/dtc/util.h b/scripts/dtc/util.h index ca5cb52928..9d38edee97 100644 --- a/scripts/dtc/util.h +++ b/scripts/dtc/util.h @@ -2,6 +2,7 @@ #ifndef UTIL_H #define UTIL_H +#include <stdlib.h> #include <stdarg.h> #include <stdbool.h> #include <getopt.h> @@ -12,7 +13,11 @@ */ #ifdef __GNUC__ +#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4) +#define PRINTF(i, j) __attribute__((format (gnu_printf, i, j))) +#else #define PRINTF(i, j) __attribute__((format (printf, i, j))) +#endif #define NORETURN __attribute__((noreturn)) #else #define PRINTF(i, j) @@ -56,6 +61,7 @@ static inline void *xrealloc(void *p, size_t len) } extern char *xstrdup(const char *s); +extern char *xstrndup(const char *s, size_t len); extern int PRINTF(2, 3) xasprintf(char **strp, const char *fmt, ...); extern int PRINTF(2, 3) xasprintf_append(char **strp, const char *fmt, ...); @@ -138,6 +144,7 @@ int utilfdt_write_err(const char *filename, const void *blob); * i signed integer * u unsigned integer * x hex + * r raw * * TODO: Implement ll modifier (8 bytes) * TODO: Implement o type (octal) @@ -155,7 +162,7 @@ int utilfdt_decode_type(const char *fmt, int *type, int *size); */ #define USAGE_TYPE_MSG \ - "<type>\ts=string, i=int, u=unsigned, x=hex\n" \ + "<type>\ts=string, i=int, u=unsigned, x=hex, r=raw\n" \ "\tOptional modifier prefix:\n" \ "\t\thh or b=byte, h=2 byte, l=4 byte (default)"; diff --git a/scripts/dtc/version_gen.h b/scripts/dtc/version_gen.h index 5c04ba938c..f8facf85fb 100644 --- a/scripts/dtc/version_gen.h +++ b/scripts/dtc/version_gen.h @@ -1 +1 @@ -#define DTC_VERSION "DTC 1.5.0" +#define DTC_VERSION "DTC 1.7.0" diff --git a/scripts/dtc/yamltree.c b/scripts/dtc/yamltree.c index 5b6ea8ea86..55908c829c 100644 --- a/scripts/dtc/yamltree.c +++ b/scripts/dtc/yamltree.c @@ -29,11 +29,12 @@ char *yaml_error_name[] = { (emitter)->problem, __func__, __LINE__); \ }) -static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, char *data, int len, int width) +static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, + char *data, unsigned int seq_offset, unsigned int len, int width) { yaml_event_t event; void *tag; - int off, start_offset = markers->offset; + unsigned int off; switch(width) { case 1: tag = "!u8"; break; @@ -59,21 +60,21 @@ static void yaml_propval_int(yaml_emitter_t *emitter, struct marker *markers, ch sprintf(buf, "0x%"PRIx8, *(uint8_t*)(data + off)); break; case 2: - sprintf(buf, "0x%"PRIx16, fdt16_to_cpu(*(fdt16_t*)(data + off))); + sprintf(buf, "0x%"PRIx16, dtb_ld16(data + off)); break; case 4: - sprintf(buf, "0x%"PRIx32, fdt32_to_cpu(*(fdt32_t*)(data + off))); + sprintf(buf, "0x%"PRIx32, dtb_ld32(data + off)); m = markers; is_phandle = false; for_each_marker_of_type(m, REF_PHANDLE) { - if (m->offset == (start_offset + off)) { + if (m->offset == (seq_offset + off)) { is_phandle = true; break; } } break; case 8: - sprintf(buf, "0x%"PRIx64, fdt64_to_cpu(*(fdt64_t*)(data + off))); + sprintf(buf, "0x%"PRIx64, dtb_ld64(data + off)); break; } @@ -112,8 +113,9 @@ static void yaml_propval_string(yaml_emitter_t *emitter, char *str, int len) static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) { yaml_event_t event; - int len = prop->val.len; + unsigned int len = prop->val.len; struct marker *m = prop->val.markers; + struct marker *markers = prop->val.markers; /* Emit the property name */ yaml_scalar_event_initialize(&event, NULL, @@ -151,19 +153,19 @@ static void yaml_propval(yaml_emitter_t *emitter, struct property *prop) switch(m->type) { case TYPE_UINT16: - yaml_propval_int(emitter, m, data, chunk_len, 2); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 2); break; case TYPE_UINT32: - yaml_propval_int(emitter, m, data, chunk_len, 4); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 4); break; case TYPE_UINT64: - yaml_propval_int(emitter, m, data, chunk_len, 8); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 8); break; case TYPE_STRING: yaml_propval_string(emitter, data, chunk_len); break; default: - yaml_propval_int(emitter, m, data, chunk_len, 1); + yaml_propval_int(emitter, markers, data, m->offset, chunk_len, 1); break; } } diff --git a/scripts/gen-dtb-s b/scripts/gen-dtb-s index 1027db2804..d6fbdd5aaf 100755 --- a/scripts/gen-dtb-s +++ b/scripts/gen-dtb-s @@ -4,7 +4,9 @@ name=$1 dtb=$2 imd=$3 -echo "#include <asm-generic/barebox.lds.h>" +echo "#include <asm/barebox.lds.h>" +echo "#include <asm-generic/pointer.h>" +echo ".section .note.GNU-stack,\"\",%progbits" le32() { printf ".byte 0x%02x, 0x%02x, 0x%02x, 0x%02x\n" \ @@ -49,16 +51,16 @@ echo "__dtb_${name}_start:" echo ".incbin \"$dtb\"" echo "__dtb_${name}_end:" echo ".global __dtb_${name}_end" +if [ "$imd" = "y" ]; then + echo ".balign ASM_SZPTR" + echo "ASM_PTR __barebox_imd_OF_${name}" +fi echo ".balign STRUCT_ALIGNMENT" -lzop -f -9 $dtb -o $dtb.lzo -if [ $? != 0 ]; then - exit 1 -fi -compressed=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" $dtb.lzo) +compressed=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" $dtb.z) uncompressed=$(${CONFIG_SHELL} "${srctree}/scripts/file-size.sh" $dtb) -echo "#ifdef CONFIG_USE_COMPRESSED_DTB" +echo "#if defined(CONFIG_USE_COMPRESSED_DTB) && defined(__PBL__)" echo ".section .dtbz.rodata.${name},\"a\"" echo ".balign STRUCT_ALIGNMENT" echo ".global __dtb_z_${name}_start" @@ -66,8 +68,12 @@ echo "__dtb_z_${name}_start:" printf ".int 0x%08x\n" 0x7b66bcbd printf ".int 0x%08x\n" $compressed printf ".int 0x%08x\n" $uncompressed -echo ".incbin \"$dtb.lzo\"" +echo ".incbin \"$dtb.z\"" echo "__dtb_z_${name}_end:" echo ".global __dtb_z_${name}_end" +if [ "$imd" = "y" ]; then + echo ".balign ASM_SZPTR" + echo "ASM_PTR __barebox_imd_OF_${name}" +fi echo ".balign STRUCT_ALIGNMENT" echo "#endif" diff --git a/scripts/gen-dtbo-s b/scripts/gen-dtbo-s new file mode 100755 index 0000000000..a7e272a089 --- /dev/null +++ b/scripts/gen-dtbo-s @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +name=$1 +dtbo=$2 + +echo "#include <asm/barebox.lds.h>" +echo ".section .note.GNU-stack,\"\",%progbits" + +echo ".section .dtb.rodata.${name}_dtbo,\"a\"" +echo ".balign STRUCT_ALIGNMENT" +echo ".global __dtbo_${name}_start" +echo "__dtbo_${name}_start:" +echo ".incbin \"$dtbo\"" +echo "__dtbo_${name}_end:" +echo ".global __dtbo_${name}_end" diff --git a/scripts/get_maintainer.pl b/scripts/get_maintainer.pl index 7c0d503334..abc2dead2b 100755 --- a/scripts/get_maintainer.pl +++ b/scripts/get_maintainer.pl @@ -2,10 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-only # Dummy get_maintainer.pl script for checkpatch.pl to use -die "USAGE: get_maintainer.pl --status\n" unless grep /--status/, @ARGV; - print <<'EOT' Sascha Hauer <s.hauer@pengutronix.de> (maintainer:BAREBOX) barebox@lists.infradead.org (open list:BAREBOX) -Maintained EOT diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile index d62277bb54..739641b477 100644 --- a/scripts/imx/Makefile +++ b/scripts/imx/Makefile @@ -3,20 +3,20 @@ hostprogs-always-$(CONFIG_ARCH_IMX_IMXIMAGE) += imx-image hostprogs-always-$(CONFIG_ARCH_IMX_USBLOADER) += imx-usb-loader -HOSTCFLAGS_imx-usb-loader.o = `pkg-config --cflags libusb-1.0` -HOSTLDLIBS_imx-usb-loader = `pkg-config --libs libusb-1.0` +HOSTCFLAGS_imx-usb-loader.o = `$(PKG_CONFIG) --cflags libusb-1.0` -include $(objtree)/include/generated/utsrelease.h +HOSTLDLIBS_imx-usb-loader = `$(PKG_CONFIG) --libs libusb-1.0` -imx-usb-loader-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0` +imx-usb-loader-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0` -include $(objtree)/include/generated/utsrelease.h imx-usb-loader-target-userldlibs += `$(CROSS_PKG_CONFIG) --libs libusb-1.0` -HOSTCFLAGS_imx.o = -I$(srctree)/arch/arm/mach-imx/include -imx-target-userccflags += -I$(srctree)/arch/arm/mach-imx/include -HOSTCFLAGS_imx-image.o = -I$(srctree) -I$(srctree)/arch/arm/mach-imx/include -HOSTCFLAGS_imx-usb-loader.o += -I$(srctree) -I$(srctree)/arch/arm/mach-imx/include -imx-usb-loader-target-userccflags += -I$(srctree) -I$(srctree)/arch/arm/mach-imx/include +HOSTCFLAGS_imx.o = -I$(srctree)/include/mach +imx-target-userccflags += -I$(srctree)/include/mach +HOSTCFLAGS_imx-image.o = -I$(srctree) -I$(srctree)/include/mach +HOSTCFLAGS_imx-usb-loader.o += -I$(srctree) -I$(srctree)/include/mach +imx-usb-loader-target-userccflags += -I$(srctree) -I$(srctree)/include/mach ifdef CONFIG_ARCH_IMX_IMXIMAGE_SSL_SUPPORT -HOSTCFLAGS_imx-image.o += -DIMXIMAGE_SSL_SUPPORT -HOSTLDLIBS_imx-image = `pkg-config --libs openssl` +HOSTCFLAGS_imx-image.o += -DIMXIMAGE_SSL_SUPPORT `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_imx-image = `$(PKG_CONFIG) --libs openssl` endif imx-usb-loader-objs := imx-usb-loader.o imx.o diff --git a/scripts/imx/Makefile.mingw64 b/scripts/imx/Makefile.mingw64 new file mode 100644 index 0000000000..e012d833f1 --- /dev/null +++ b/scripts/imx/Makefile.mingw64 @@ -0,0 +1,48 @@ +ifeq ($(strip $(LIBUSB_DIR)),) +$(error Please specify LIBUSB_DIR e.g. LIBUSB_DIR=~/libusb-1.0.26-binaries) +endif + +CC := x86_64-w64-mingw32-gcc +ifeq ($(shell which $(CC)),) +$(error "No $(CC) in $(PATH) found") +endif + +LIBUSB_MINGW := $(LIBUSB_DIR)/libusb-MinGW-x64 +ifeq ($(wildcard $(strip $(LIBUSB_MINGW))),) +$(error "$(LIBUSB_MINGW) not found") +endif + +src := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))) + +# Do we want to change the working directory? +ifeq ("$(origin O)", "command line") + OUTPUT := $(O) +else + OUTPUT := $(src)/imx-usb-loader-windows +endif # ifneq ($(OUTPUT),) + +# Make's built-in functions such as $(abspath ...), $(realpath ...) cannot +# expand a shell special character '~'. We use a somewhat tedious way here. +obj := $(shell mkdir -p $(OUTPUT) && cd $(OUTPUT) && pwd) +$(if $(obj),, \ + $(error failed to create output directory "$(OUTPUT)")) + +# $(realpath ...) resolves symlinks +obj := $(realpath $(obj)) + +CPPFLAGS := -I $(LIBUSB_MINGW)/include/libusb-1.0 -I $(src)/../include/ -I $(src)/../../include/mach/ +LDFLAGS := -L $(LIBUSB_MINGW)/lib -lusb-1.0 -static + +OBJECTS := $(addprefix $(obj)/, imx.o imx-usb-loader.o) + +$(obj)/%.o: $(src)/%.c + @$(CC) -c -o $@ $< $(CPPFLAGS) + +$(obj)/imx-usb-loader.exe: $(OBJECTS) + @$(CC) -o $@ $(OBJECTS) $(LDFLAGS) + +all: $(obj)/imx-usb-loader.exe + +.PHONY: clean +clean: + @rm -rf $(obj) diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index 439912a805..bc2e7af5d6 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -20,6 +20,7 @@ #include "imx.h" #include <include/filetype.h> +#include <include/linux/sizes.h> #define FLASH_HEADER_OFFSET 0x400 #define ARM_HEAD_SIZE_INDEX (ARM_HEAD_SIZE_OFFSET / sizeof(uint32_t)) @@ -34,7 +35,7 @@ static uint32_t dcdtable[MAX_DCD]; static int curdcd; -static int create_usb_image; +static bool create_usb_image; static char *prgname; /* @@ -295,11 +296,12 @@ static int write_mem_v1(uint32_t addr, uint32_t val, int width, int set_bits, in * ============================================================================ */ -static size_t add_header_v2(const struct config_data *data, void *buf) +static size_t +add_header_v2(const struct config_data *data, void *buf, uint32_t offset, + size_t header_len, unsigned int csf_slot) { struct imx_flash_header_v2 *hdr; int dcdsize = curdcd * sizeof(uint32_t); - int offset = data->image_ivt_offset; uint32_t loadaddr = data->image_load_addr; uint32_t imagesize = data->load_size; @@ -308,7 +310,7 @@ static size_t add_header_v2(const struct config_data *data, void *buf) * Restrict the imagesize to the PBL if given. * Also take the alignment for CSF into account. */ - imagesize = roundup(data->pbl_code_size + HEADER_LEN, 0x4); + imagesize = roundup(data->pbl_code_size + header_len, 0x4); if (data->csf) imagesize = roundup(imagesize, 0x1000); } @@ -320,7 +322,7 @@ static size_t add_header_v2(const struct config_data *data, void *buf) hdr->header.length = htobe16(32); hdr->header.version = IVT_VERSION; - hdr->entry = loadaddr + HEADER_LEN; + hdr->entry = loadaddr + header_len; if (dcdsize) hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); if (create_usb_image) { @@ -339,8 +341,10 @@ static size_t add_header_v2(const struct config_data *data, void *buf) hdr->boot_data.size = imagesize; if (data->sign_image) { - hdr->csf = loadaddr + imagesize; + hdr->csf = loadaddr + imagesize + (csf_slot * CSF_LEN); hdr->boot_data.size += CSF_LEN; + if (data->flexspi_csf) + hdr->boot_data.size += CSF_LEN; } else if (data->pbl_code_size && data->csf) { /* * For i.MX8 the CSF space is added via the linker script, so @@ -348,6 +352,8 @@ static size_t add_header_v2(const struct config_data *data, void *buf) * signing is not. */ hdr->boot_data.size += CSF_LEN; + if (data->flexspi_csf) + hdr->boot_data.size += CSF_LEN; } buf += sizeof(*hdr); @@ -362,6 +368,112 @@ static size_t add_header_v2(const struct config_data *data, void *buf) return imagesize; } +#define LUT_PAD_1 0 +#define LUT_PAD_2 1 +#define LUT_PAD_4 2 +#define LUT_PAD_8 3 + +static size_t add_flexspi_fcfb_header(const struct config_data *data, void *buf) +{ + uint32_t fcfb_offset = data->image_flexspi_fcfb_offset; + const struct imx_fcfb_nor nor_conf = { + .memcfg = { + .tag = htobe32(FCFB_HEAD_TAG), + .version = htole32(FCFB_VERSION), + .read_sample = FCFB_SAMLPE_CLK_SRC_INTERNAL, + /* flash CS hold time, recommended by RM */ + .datahold = 0x03, + /* flash CS setup time, recommended by RM */ + .datasetup = 0x03, + /* 3 - Hyperflash, 12/13 serial NAND, 0 - other */ + .coladdrwidth = 0, + .devcfgenable = 0, + .cmd_enable = 0, + .controllermisc = 0, + .dev_type = FCFB_DEVTYPE_SERIAL_NOR, + .sflash_pad = FCFB_SFLASH_PADS_SINGLE, + .serial_clk = FCFB_SERIAL_CLK_FREQ_50MHZ, + .sflashA1 = htole32(SZ_256M), + .lut.seq[0] = { + .instr = { + htole16(LUT_DEF(LUT_CMD, LUT_PAD_1, 0x0b)), + htole16(LUT_DEF(LUT_ADDR, LUT_PAD_1, 24)), + htole16(LUT_DEF(LUT_DUMMY, LUT_PAD_1, 8)), + htole16(LUT_DEF(LUT_NXP_READ, LUT_PAD_1, 4)), + htole16(LUT_DEF(LUT_STOP, LUT_PAD_1, 0)), + }, + }, + }, + }; + + buf += fcfb_offset; + memcpy(buf, &nor_conf, sizeof(nor_conf)); + + return sizeof(nor_conf); +} + +static size_t +add_flexspi_header(const struct config_data *data, void **_buf, size_t *header_len) +{ + uint32_t ivt_offset = data->image_flexspi_ivt_offset; + size_t size; + size_t len; + void *buf; + + if (!flexspi_image(data)) + return 0; + + if (data->signed_hdmi_firmware_file) { + free(*_buf); + fprintf(stderr, "Signed HDMI firmware and FlexSPI compatible image is not supported!\n"); + exit(1); + } + + /* + * Extend the header to be able to build build one image which can be + * used for: USB/SD/eMMC/eMMC-Boot/QSPI/barebox-chainload. + */ + buf = realloc(*_buf, *header_len + FLEXSPI_HEADER_LEN); + if (!buf) + exit(1); + + *_buf = buf; + + size = add_flexspi_fcfb_header(data, buf); + + /* + * The following table list the offsets we need to ensure for + * the one image approach. + * + * | i.MX8MM | i.MX8MN/P | + * -----------------------------+---------+-----------+ + * SD/eMMC primary image offset | 0 | 0/32K | + * FlexSPI primary image offset | 0 | 4K | + * SD/eMMC-IVT offset | 1K | 0 | + * SD/eMMC-IVT image entry | 8K | 8K | + * FlexSPI-IVT offset | 4K | 0 | + * FlexSPI-IVT image entry | 8K | 4K | + * + * According the above table the rom-loader for i.MX8MM will + * search for the image on the same place (8K). On the other + * hand the rom-loader for the i.MX8MN/P will look for it at + * 8K for SD/eMMC case or at 4K for FlexSPI case. + */ + len = *header_len; + if (data->cpu_type == IMX_CPU_IMX8MM) + len += FLEXSPI_HEADER_LEN; + + if (data->cpu_type == IMX_CPU_IMX8MP || + data->cpu_type == IMX_CPU_IMX8MN) + buf += SZ_4K; + + size += add_header_v2(data, buf, ivt_offset, len, 1); + + *header_len += FLEXSPI_HEADER_LEN; + + return size; +} + static void usage(const char *prgname) { fprintf(stderr, "usage: %s [OPTIONS]\n\n" @@ -552,12 +664,13 @@ static int nop(const struct config_data *data) * The cst is expected to be executable as 'cst' or if exists, the content * of the environment variable 'CST' is used. */ -static int hab_sign(struct config_data *data) +static int hab_sign(struct config_data *data, const char *csfcmds, + unsigned int csf_slot) { int fd, outfd, ret, lockfd; char *csffile, *command; struct stat s; - char *cst; + char *cst, *cstopts; void *buf; size_t csf_space = CSF_LEN; unsigned int offset = 0; @@ -566,7 +679,11 @@ static int hab_sign(struct config_data *data) if (!cst) cst = "cst"; - ret = asprintf(&csffile, "%s.csfbin", data->outfile); + cstopts = getenv("CST_EXTRA_CMDLINE_OPTIONS"); + if (!cstopts) + cstopts = ""; + + ret = asprintf(&csffile, "%s.slot%u.csfbin", data->outfile, csf_slot); if (ret < 0) exit(1); @@ -603,11 +720,11 @@ static int hab_sign(struct config_data *data) if (ret == -1) return -EINVAL; else if (ret == 0) - ret = asprintf(&command, "%s -o %s -i /dev/stdin", - cst, csffile); + ret = asprintf(&command, "%s -o %s -i /dev/stdin %s", + cst, csffile, cstopts); else - ret = asprintf(&command, "%s -o %s;", - cst, csffile); + ret = asprintf(&command, "%s -o %s %s;", + cst, csffile, cstopts); if (ret < 0) return -ENOMEM; @@ -635,7 +752,7 @@ static int hab_sign(struct config_data *data) return -errno; } - fwrite(data->csf, 1, strlen(data->csf) + 1, f); + fwrite(csfcmds, 1, strlen(csfcmds) + 1, f); pclose(f); @@ -683,6 +800,8 @@ static int hab_sign(struct config_data *data) xread(fd, buf, s.st_size); + close(fd); + /* * For i.MX8M, write into the reserved CSF section */ @@ -702,8 +821,13 @@ static int hab_sign(struct config_data *data) * For i.MX8 insert the CSF data into the reserved CSF area * right behind the PBL */ - offset = roundup(data->header_gap + data->pbl_code_size + - HEADER_LEN, 0x1000); + offset = data->header_gap + data->pbl_code_size + HEADER_LEN; + if (flexspi_image(data)) + offset += FLEXSPI_HEADER_LEN; + + offset += csf_slot * CSF_LEN; + + offset = roundup(offset, 0x1000); if (data->signed_hdmi_firmware_file) offset += PLUGIN_HDMI_SIZE; @@ -739,9 +863,9 @@ int main(int argc, char *argv[]) void *infile; struct stat s; int outfd; - int dcd_only = 0; + bool dcd_only = false; int now = 0; - int add_barebox_header = 0; + bool add_barebox_header = false; uint32_t barebox_image_size = 0; struct config_data data = { .image_ivt_offset = 0xffffffff, @@ -771,16 +895,16 @@ int main(int argc, char *argv[]) data.pbl_code_size = strtoul(optarg, NULL, 0); break; case 'b': - add_barebox_header = 1; + add_barebox_header = true; break; case 'd': - dcd_only = 1; + dcd_only = true; break; case 's': data.sign_image = 1; break; case 'u': - create_usb_image = 1; + create_usb_image = true; break; case 'e': data.encrypt_image = 1; @@ -904,8 +1028,10 @@ int main(int argc, char *argv[]) } } + barebox_image_size += add_flexspi_header(&data, &buf, &header_len); barebox_image_size += add_header_v2(&data, buf + - signed_hdmi_firmware_size); + signed_hdmi_firmware_size, + data.image_ivt_offset, header_len, 0); break; default: fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n", @@ -976,12 +1102,21 @@ int main(int argc, char *argv[]) xwrite(outfd, infile, insize); - /* pad until next 4k boundary */ - now = 4096 - (insize % 4096); - if (data.csf && now) { - memset(buf, 0x5a, now); + /* + * The alignment may be required on ARMv7 SoCs like i.MX6/7 for HAB + * boot. On newer SoCs like i.MX8MP/N this cause libusb communication + * errors while uploading images because these machines request the + * exact amount of required bytes and move on afterwards while the host + * tool still try to send the whole (padded) file size. + */ + if (!cpu_is_mx8m(&data)) { + /* pad until next 4k boundary */ + now = 4096 - (insize % 4096); + if (data.csf && now) { + memset(buf, 0x5a, now); - xwrite(outfd, buf, now); + xwrite(outfd, buf, now); + } } ret = close(outfd); @@ -991,9 +1126,14 @@ int main(int argc, char *argv[]) } if (data.csf && data.sign_image) { - ret = hab_sign(&data); + ret = hab_sign(&data, data.csf, 0); if (ret) exit(1); + if (data.flexspi_csf) { + ret = hab_sign(&data, data.flexspi_csf, 1); + if (ret) + exit(1); + } } if (create_usb_image) { diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c index 69df9bbe92..91a15345a2 100644 --- a/scripts/imx/imx-usb-loader.c +++ b/scripts/imx/imx-usb-loader.c @@ -31,7 +31,6 @@ #include <stdlib.h> #include <libusb.h> #include <getopt.h> -#include <arpa/inet.h> #include <linux/kernel.h> #include "../common.h" @@ -47,6 +46,10 @@ #define FT_DCD 0xee #define FT_LOAD_ONLY 0x00 +#ifndef UTS_RELEASE +#define UTS_RELEASE "unknown" +#endif + /* * comment from libusb: * As per the USB 3.0 specs, the current maximum limit for the depth is 7. @@ -73,7 +76,9 @@ struct mach_id { unsigned short max_transfer; #define DEV_IMX 0 #define DEV_MXS 1 +#define DEV_IMX9 2 unsigned char dev_type; + unsigned char hid_endpoint; }; struct usb_work { @@ -182,6 +187,22 @@ static const struct mach_id imx_ids[] = { .max_transfer = 1024, }, { .vid = 0x1fc9, + .pid = 0x0146, + .name = "i.MX8MP", + .header_type = HDR_MX53, + .max_transfer = 1020, + .mode = MODE_HID, + .hid_endpoint = 1, + }, { + .vid = 0x1fc9, + .pid = 0x013e, + .name = "i.MX8MN", + .header_type = HDR_MX53, + .max_transfer = 1020, + .dev_type = MODE_HID, + .hid_endpoint = 1, + }, { + .vid = 0x1fc9, .pid = 0x012b, .name = "i.MX8MQ", .header_type = HDR_MX53, @@ -194,6 +215,14 @@ static const struct mach_id imx_ids[] = { .header_type = HDR_MX53, .mode = MODE_HID, .max_transfer = 1024, + }, { + .vid = 0x1fc9, + .pid = 0x014e, + .name = "i.MX9", + .mode = MODE_HID, + .max_transfer = 1020, + .hid_endpoint = 1, + .dev_type = DEV_IMX9, }, }; @@ -447,7 +476,7 @@ static void dump_bytes(const void *src, unsigned cnt, unsigned addr) * EP2IN - bulk in * (max packet size of 512 bytes) */ -static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) +static int transfer(int report, void *p, unsigned cnt, int *last_trans) { int err; if (cnt > mach_id->max_transfer) @@ -464,21 +493,32 @@ static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) err = libusb_bulk_transfer(usb_dev_handle, (report < 3) ? 1 : 2 + EP_IN, p, cnt, last_trans, 1000); } else { - unsigned char tmp[1028]; + unsigned char tmp[1028] = { 0 }; tmp[0] = (unsigned char)report; if (report < 3) { memcpy(&tmp[1], p, cnt); - err = libusb_control_transfer(usb_dev_handle, - CTRL_OUT, - HID_SET_REPORT, - (HID_REPORT_TYPE_OUTPUT << 8) | report, - 0, - tmp, cnt + 1, 1000); - *last_trans = (err > 0) ? err - 1 : 0; - if (err > 0) - err = 0; + + if (report == 2) + cnt = mach_id->max_transfer; + + if (mach_id->hid_endpoint) { + int trans; + err = libusb_interrupt_transfer(usb_dev_handle, + mach_id->hid_endpoint, tmp, cnt + 1, &trans, 1000); + *last_trans = trans - 1; + } else { + err = libusb_control_transfer(usb_dev_handle, + CTRL_OUT, + HID_SET_REPORT, + (HID_REPORT_TYPE_OUTPUT << 8) | report, + 0, + tmp, cnt + 1, 1000); + *last_trans = (err > 0) ? err - 1 : 0; + if (err > 0) + err = 0; + } } else { *last_trans = 0; memset(&tmp[1], 0, cnt); @@ -511,7 +551,7 @@ static int do_status(void) unsigned char tmp[64]; int retry = 0; int err; - static const struct sdp_command status_command = { + static struct sdp_command status_command = { .cmd = SDP_ERROR_STATUS, .addr = 0, .format = 0, @@ -521,8 +561,7 @@ static int do_status(void) }; for (;;) { - err = transfer(1, (unsigned char *) &status_command, 16, - &last_trans); + err = transfer(1, &status_command, 16, &last_trans); if (verbose > 2) printf("report 1, wrote %i bytes, err=%i\n", last_trans, err); @@ -571,12 +610,11 @@ static int read_memory(unsigned addr, void *dest, unsigned cnt) int err; int rem; unsigned char tmp[64]; - read_reg_command.addr = htonl(addr); - read_reg_command.cnt = htonl(cnt); + read_reg_command.addr = htobe32(addr); + read_reg_command.cnt = htobe32(cnt); for (;;) { - err = transfer(1, (unsigned char *) &read_reg_command, 16, - &last_trans); + err = transfer(1, &read_reg_command, 16, &last_trans); if (!err) break; printf("read_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -603,17 +641,10 @@ static int read_memory(unsigned addr, void *dest, unsigned cnt) err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem); break; } - if ((last_trans > rem) || (last_trans > 64)) { - if ((last_trans == 64) && (rem < 64)) { - /* Last transfer is expected to be too large for HID */ - } else { - printf("err: %02x %02x %02x %02x cnt=%u rem=%d last_trans=%i\n", - tmp[0], tmp[1], tmp[2], tmp[3], cnt, rem, last_trans); - } + + if (last_trans > rem) last_trans = rem; - if (last_trans > 64) - last_trans = 64; - } + memcpy(dest, tmp, last_trans); dest += last_trans; rem -= last_trans; @@ -636,8 +667,8 @@ static int write_memory(unsigned addr, unsigned val, int width) .rsvd = 0, }; - write_reg_command.addr = htonl(addr); - write_reg_command.cnt = htonl(4); + write_reg_command.addr = htobe32(addr); + write_reg_command.cnt = htobe32(4); if (verbose > 1) printf("write memory reg: 0x%08x val: 0x%08x width: %d\n", addr, val, width); @@ -656,11 +687,10 @@ static int write_memory(unsigned addr, unsigned val, int width) return -1; } - write_reg_command.data = htonl(val); + write_reg_command.data = htobe32(val); for (;;) { - err = transfer(1, (unsigned char *) &write_reg_command, 16, - &last_trans); + err = transfer(1, &write_reg_command, 16, &last_trans); if (!err) break; printf("write_reg_command err=%i, last_trans=%i\n", err, last_trans); @@ -713,6 +743,31 @@ static int modify_memory(unsigned addr, unsigned val, int width, int set_bits, i return write_memory(addr, val, 4); } +static int send_buf(void *buf, unsigned len) +{ + void *p = buf; + int cnt = len; + int err; + + while (1) { + int now = get_min(cnt, mach_id->max_transfer); + + if (now <= 0) + break; + + err = transfer(2, p, now, &now); + if (err) { + printf("dl_command err=%i, last_trans=%i\n", err, now); + return err; + } + + p += now; + cnt -= now; + } + + return 0; +} + static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char type, bool mode_barebox) { @@ -729,18 +784,15 @@ static int load_file(void *buf, unsigned len, unsigned dladdr, int retry = 0; unsigned transfer_size = 0; unsigned char tmp[64]; - void *p; - int cnt; len = ALIGN(len, 4); - dl_command.addr = htonl(dladdr); - dl_command.cnt = htonl(len); + dl_command.addr = htobe32(dladdr); + dl_command.cnt = htobe32(len); dl_command.rsvd = type; for (;;) { - err = transfer(1, (unsigned char *) &dl_command, 16, - &last_trans); + err = transfer(1, &dl_command, 16, &last_trans); if (!err) break; @@ -760,24 +812,9 @@ static int load_file(void *buf, unsigned len, unsigned dladdr, err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); } - p = buf; - cnt = len; - - while (1) { - int now = get_min(cnt, mach_id->max_transfer); - - if (!now) - break; - - err = transfer(2, p, now, &now); - if (err) { - printf("dl_command err=%i, last_trans=%i\n", err, last_trans); - return err; - } - - p += now; - cnt -= now; - } + err = send_buf(buf, len); + if (err) + return err; if (mode_barebox) return transfer_size; @@ -812,11 +849,10 @@ static int sdp_jump_address(unsigned addr) int last_trans, err; int retry = 0; - jump_command.addr = htonl(addr); + jump_command.addr = htobe32(addr); for (;;) { - err = transfer(1, (unsigned char *) &jump_command, 16, - &last_trans); + err = transfer(1, &jump_command, 16, &last_trans); if (!err) break; @@ -842,10 +878,10 @@ static int do_dcd_v2_cmd_write(const unsigned char *dcd) int set_bits = 0, clear_bits = 0; int idx, bytes; struct imx_dcd_v2_write *recs = (struct imx_dcd_v2_write *) dcd; - int num_rec = (ntohs(recs->length) - 4) / + int num_rec = (be16toh(recs->length) - 4) / sizeof(struct imx_dcd_v2_write_rec); printf("DCD write: sub dcd length: 0x%04x, flags: 0x%02x\n", - ntohs(recs->length), recs->param); + be16toh(recs->length), recs->param); if (recs->param & PARAMETER_FLAG_MASK) { if (recs->param & PARAMETER_FLAG_SET) @@ -866,8 +902,8 @@ static int do_dcd_v2_cmd_write(const unsigned char *dcd) for (idx = 0; idx < num_rec; idx++) { const struct imx_dcd_v2_write_rec *record = &recs->data[idx]; - int ret = modify_memory(ntohl(record->addr), - ntohl(record->val), bytes, + int ret = modify_memory(be32toh(record->addr), + be32toh(record->val), bytes, set_bits, clear_bits); if (ret < 0) return ret; @@ -882,13 +918,13 @@ static int do_dcd_v2_cmd_check(const unsigned char *dcd) int bytes; enum imx_dcd_v2_check_cond cond; struct imx_dcd_v2_check *check = (struct imx_dcd_v2_check *) dcd; - switch (ntohs(check->length)) { + switch (be16toh(check->length)) { case 12: /* poll indefinitely */ poll_count = 0xffffffff; break; case 16: - poll_count = ntohl(check->count); + poll_count = be32toh(check->count); if (poll_count == 0) /* this command behaves as for NOP */ return 0; @@ -921,10 +957,10 @@ static int do_dcd_v2_cmd_check(const unsigned char *dcd) return -1; } - mask = ntohl(check->mask); + mask = be32toh(check->mask); fprintf(stderr, "DCD check condition %i on address 0x%x\n", - cond, ntohl(check->addr)); + cond, be32toh(check->addr)); /* Reduce the poll count to some arbitrary practical limit. Polling via SRP commands will be much slower compared to polling when DCD is interpreted by the SOC microcode. @@ -934,7 +970,7 @@ static int do_dcd_v2_cmd_check(const unsigned char *dcd) while (poll_count > 0) { uint32_t data = 0; - int ret = read_memory(ntohl(check->addr), &data, bytes); + int ret = read_memory(be32toh(check->addr), &data, bytes); if (ret < 0) return ret; @@ -963,7 +999,7 @@ static int do_dcd_v2_cmd_check(const unsigned char *dcd) fprintf(stderr, "Error: timeout waiting for DCD check condition %i " "on address 0x%08x to match 0x%08x\n", cond, - ntohl(check->addr), ntohl(check->mask)); + be32toh(check->addr), be32toh(check->mask)); return -1; } @@ -995,7 +1031,7 @@ static int process_dcd_table_ivt(const struct imx_flash_header_v2 *hdr, fprintf(stderr, "Error: Unknown DCD header tag\n"); return -1; } - m_length = ntohs(dcd_hdr->length); + m_length = be16toh(dcd_hdr->length); dcd_end = dcd + m_length; if (dcd_end > file_end) { fprintf(stderr, "Error: DCD length %08x exceeds EOF\n", @@ -1008,7 +1044,7 @@ static int process_dcd_table_ivt(const struct imx_flash_header_v2 *hdr, while (dcd < dcd_end) { int ret = 0; struct imx_ivt_header *cmd_hdr = (struct imx_ivt_header *) dcd; - unsigned s_length = ntohs(cmd_hdr->length); + unsigned s_length = be16toh(cmd_hdr->length); if (dcd + s_length > file_end) { fprintf(stderr, "Error: DCD length %08x exceeds EOF\n", s_length); @@ -1234,19 +1270,22 @@ static int get_dl_start(const unsigned char *p, const unsigned char *file_start, } case HDR_MX53: { - unsigned char *bd; + unsigned char *_bd; struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; + struct imx_boot_data *bd; *header_addr = hdr->self; - bd = hdr->boot_data_ptr + cvt_dest_to_src; - if ((bd < file_start) || ((bd + 4) > file_end)) { + _bd = hdr->boot_data_ptr + cvt_dest_to_src; + if ((_bd < file_start) || ((_bd + 4) > file_end)) { printf("bad boot_data_ptr %08x\n", hdr->boot_data_ptr); return -1; } - *firststage_len = ((struct imx_boot_data *)bd)->size; - *plugin = ((struct imx_boot_data *)bd)->plugin; - ((struct imx_boot_data *)bd)->plugin = 0; + bd = (void *)_bd; + + *firststage_len = bd->size - (hdr->self - bd->start); + *plugin = bd->plugin; + bd->plugin = 0; break; } @@ -1320,6 +1359,23 @@ static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, return -ENODEV; } +static int imx9_load_file(struct usb_work *curr) +{ + void *buf; + size_t fsize = 0; + int ret; + + buf = read_file(curr->filename, &fsize); + if (!buf) + return -errno; + + ret = send_buf(buf, fsize); + if (ret) + return ret; + + return ret; +} + static int do_irom_download(struct usb_work *curr, int verify) { int ret; @@ -1345,6 +1401,9 @@ static int do_irom_download(struct usb_work *curr, int verify) header_offset = ret; + if (mach_id->hid_endpoint) + return send_buf(buf + header_offset, fsize - header_offset); + if (plugin && (!curr->plug)) { printf("Only plugin header found\n"); ret = -1; @@ -1377,7 +1436,7 @@ static int do_irom_download(struct usb_work *curr, int verify) printf("loading binary file(%s) to 0x%08x, firststage_len=%zu type=%d, hdroffset=%u...\n", curr->filename, header_addr, firststage_len, type, header_offset); - ret = load_file(image, firststage_len, header_addr, type, false); + ret = load_file(image, min(fsize, firststage_len), header_addr, type, false); if (ret < 0) goto cleanup; @@ -1386,7 +1445,7 @@ static int do_irom_download(struct usb_work *curr, int verify) if (verify) { printf("verifying file...\n"); - ret = verify_memory(image, fsize, header_addr); + ret = verify_memory(image, min(fsize, firststage_len), header_addr); if (ret < 0) { printf("verifying failed\n"); goto cleanup; @@ -1442,53 +1501,33 @@ static int write_mem(const struct config_data *data, uint32_t addr, return modify_memory(addr, val, width, set_bits, clear_bits); } -/* MXS section */ -static int mxs_load_file(libusb_device_handle *dev, uint8_t *data, int size) +static int mxs_load_buf(uint8_t *data, int size) { static struct mxs_command dl_command; int last_trans, err; - void *p; - int cnt; - dl_command.sign = htonl(0x424c5443); /* Signature: BLTC */ - dl_command.tag = htonl(0x1); - dl_command.size = htonl(size); + dl_command.sign = htobe32(0x424c5443); /* Signature: BLTC */ + dl_command.tag = htobe32(0x1); + dl_command.size = htobe32(size); dl_command.flags = 0; dl_command.rsvd[0] = 0; dl_command.rsvd[1] = 0; dl_command.cmd = MXS_CMD_FW_DOWNLOAD; - dl_command.dw_size = htonl(size); + dl_command.dw_size = htobe32(size); - err = transfer(1, (unsigned char *) &dl_command, 20, &last_trans); + err = transfer(1, &dl_command, 20, &last_trans); if (err) { printf("transfer error at init step: err=%i, last_trans=%i\n", err, last_trans); return err; } - p = data; - cnt = size; - - while (1) { - int now = get_min(cnt, mach_id->max_transfer); - - if (!now) - break; - - err = transfer(2, p, now, &now); - if (err) { - printf("dl_command err=%i, last_trans=%i\n", err, now); - return err; - } - - p += now; - cnt -= now; - } + err = send_buf(data, size); return err; } -static int mxs_work(struct usb_work *curr) +static int mxs_load_file(struct usb_work *curr) { size_t fsize = 0; unsigned char *buf = NULL; @@ -1497,9 +1536,8 @@ static int mxs_work(struct usb_work *curr) if (!buf) return -errno; - return mxs_load_file(usb_dev_handle, buf, fsize); + return mxs_load_buf(buf, fsize); } -/* end of mxs section */ static int parse_initfile(const char *filename) { @@ -1522,8 +1560,13 @@ static void usage(const char *prgname) "-p <devpath> Specify device path: <bus>-<port>[.<port>]...\n" "-s skip DCD included in image\n" "-v verbose (give multiple times to increase)\n" + "--version display version number\n" "-h this help\n", prgname); - exit(1); +} + +static void version(const char *prgname) +{ + fprintf(stderr, "%s %s\n", prgname, UTS_RELEASE); } int main(int argc, char *argv[]) @@ -1541,10 +1584,20 @@ int main(int argc, char *argv[]) char *initfile = NULL; char *devpath = NULL; char *devtype = NULL; + int opt_version = 0; + struct option long_options[] = { + {"version", no_argument, &opt_version, 1}, + { } + }; w.do_dcd_once = 1; - while ((opt = getopt(argc, argv, "cvhd:i:p:s")) != -1) { + while ((opt = getopt_long(argc, argv, "cvhd:i:p:s", long_options, NULL)) != -1) { + if (opt_version) { + version(argv[0]); + exit(EXIT_SUCCESS); + } + switch (opt) { case 'c': verify = 1; @@ -1554,6 +1607,7 @@ int main(int argc, char *argv[]) break; case 'h': usage(argv[0]); + exit(EXIT_SUCCESS); case 'd': devtype = optarg; break; @@ -1567,13 +1621,13 @@ int main(int argc, char *argv[]) w.do_dcd_once = 0; break; default: - exit(1); + exit(EXIT_FAILURE); } } if (devtype && strcmp(devtype, "list") == 0) { list_imx_device_types(); - exit(0); + exit(EXIT_SUCCESS); } if (devtype && !devpath) { @@ -1583,7 +1637,7 @@ int main(int argc, char *argv[]) if (optind == argc) { fprintf(stderr, "no filename given\n"); usage(argv[0]); - exit(1); + exit(EXIT_FAILURE); } w.plug = 1; @@ -1619,14 +1673,19 @@ int main(int argc, char *argv[]) } if (mach_id->dev_type == DEV_MXS) { - ret = mxs_work(&w); + ret = mxs_load_file(&w); + goto out; + } else if (mach_id->dev_type == DEV_IMX9) { + ret = imx9_load_file(&w); goto out; } - err = do_status(); - if (err) { - printf("status failed\n"); - goto out; + if (!mach_id->hid_endpoint) { + err = do_status(); + if (err) { + printf("status failed\n"); + goto out; + } } if (initfile) { diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index 87560ad27d..5ccc116cfe 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -20,6 +20,23 @@ */ #define ENCRYPT_OFFSET (HEADER_LEN + 0x10) +static char *strcata(char *str, const char *add) +{ + size_t size = (str ? strlen(str) : 0) + strlen(add) + 1; + bool need_init = str ? false : true; + + str = realloc(str, size); + if (!str) + return NULL; + + if (need_init) + memset(str, 0, size); + + strcat(str, add); + + return str; +} + static int parse_line(char *line, char *argv[]) { int nargs = 0; @@ -282,16 +299,53 @@ static int do_max_load_size(struct config_data *data, int argc, char *argv[]) return 0; } +static int do_hab_qspi(struct config_data *data, int argc, char *argv[]) +{ + /* + * Force 'hab_qspi' to specified before any 'hab' to ensure correct CSF + * generation. + */ + if (data->csf) { + fprintf(stderr, + "'hab_qspi' must be specified before any 'hab' command\n"); + return -EINVAL; + } + + data->hab_qspi_support = true; + + return 0; +} + static int hab_add_str(struct config_data *data, const char *str) { - int len = strlen(str); + data->csf = strcata(data->csf, str); + if (!data->csf) + return -ENOMEM; + + if (!data->hab_qspi_support) + return 0; + + data->flexspi_csf = strcata(data->flexspi_csf, str); + if (!data->flexspi_csf) + return -ENOMEM; - if (data->csf_space < len) + return 0; +} + +static int hab_add_barebox_blocks(struct config_data *data, + const char *csf_str, + const char *flexspi_csf_str) +{ + data->csf = strcata(data->csf, csf_str); + if (!data->csf) return -ENOMEM; - strcat(data->csf, str); + if (!flexspi_csf_str) + return 0; - data->csf_space -= len; + data->flexspi_csf = strcata(data->flexspi_csf, flexspi_csf_str); + if (!data->flexspi_csf) + return -ENOMEM; return 0; } @@ -300,14 +354,6 @@ static int do_hab(struct config_data *data, int argc, char *argv[]) { int i, ret; - if (!data->csf) { - data->csf_space = 0x10000; - - data->csf = calloc(data->csf_space + 1, 1); - if (!data->csf) - return -ENOMEM; - } - for (i = 1; i < argc; i++) { ret = hab_add_str(data, argv[i]); if (ret) @@ -325,13 +371,44 @@ static int do_hab(struct config_data *data, int argc, char *argv[]) return 0; } +static void +imx8m_get_offset_size(struct config_data *data, + uint32_t *offset, uint32_t *signed_size, + uint32_t *flexspi_offset, uint32_t *flexspi_signed_size) +{ + unsigned int hdrlen = HEADER_LEN; + + if (flexspi_image(data)) + hdrlen += FLEXSPI_HEADER_LEN; + + *signed_size = roundup(data->pbl_code_size + hdrlen, 0x1000); + *flexspi_signed_size = roundup(data->pbl_code_size + FLEXSPI_HEADER_LEN, + 0x1000); + + *offset += data->header_gap; + *flexspi_offset += data->header_gap; + /* + * Starting with i.MX8MP/N the FlexSPI IVT offset is 0x0 but the primary + * image offset is at 0x1000. + */ + if (data->cpu_type != IMX_CPU_IMX8MM) + *flexspi_offset += HEADER_LEN; + + if (data->signed_hdmi_firmware_file) { + *offset += PLUGIN_HDMI_SIZE; + *flexspi_offset += PLUGIN_HDMI_SIZE; + } +} + static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) { - char *str; + char *str, *flexspi_str = NULL; int ret; int i; uint32_t signed_size = data->load_size; + uint32_t flexspi_signed_size = signed_size; uint32_t offset = data->image_ivt_offset; + uint32_t flexspi_offset = data->image_flexspi_ivt_offset; if (!data->csf) return -EINVAL; @@ -346,17 +423,21 @@ static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) /* * Ensure we only sign the PBL for i.MX8MQ */ - if (data->pbl_code_size && cpu_is_mx8m(data)) { - offset += data->header_gap; - signed_size = roundup(data->pbl_code_size + HEADER_LEN, 0x1000); - if (data->signed_hdmi_firmware_file) - offset += PLUGIN_HDMI_SIZE; - } + if (data->pbl_code_size && cpu_is_mx8m(data)) + imx8m_get_offset_size(data, &offset, &signed_size, + &flexspi_offset, &flexspi_signed_size); if (signed_size > 0) { ret = asprintf(&str, "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"", data->image_load_addr + data->image_ivt_offset, offset, signed_size - data->image_ivt_offset, data->outfile); + if (data->flexspi_csf) + ret |= asprintf(&flexspi_str, + "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"", + data->image_load_addr + + data->image_flexspi_ivt_offset, + flexspi_offset, flexspi_signed_size, + data->outfile); } else { fprintf(stderr, "Invalid signed size area 0x%08x\n", signed_size); @@ -366,8 +447,9 @@ static int do_hab_blocks(struct config_data *data, int argc, char *argv[]) if (ret < 0) return -ENOMEM; - ret = hab_add_str(data, str); + ret = hab_add_barebox_blocks(data, str, flexspi_str); free(str); + free(flexspi_str); if (ret) return ret; @@ -609,6 +691,38 @@ do_signed_hdmi_firmware(struct config_data *data, int argc, char *argv[]) return 0; } +static int do_flexspi_ivtofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + if (data->csf) { + fprintf(stderr, "#include <mach/imx/flexspi-imx8m*-cfg.h> must be placed in front " + "of #include <mach/imx/habv4-imx8-gencsf.h>\n"); + return -EINVAL; + } + + data->image_flexspi_ivt_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + +static int do_flexspi_fcfbofs(struct config_data *data, int argc, char *argv[]) +{ + if (argc < 2) + return -EINVAL; + + if (data->csf) { + fprintf(stderr, "#include <mach/imx/flexspi-imx8m*-cfg.h> must be placed in front " + "of #include <mach/imx/habv4-imx8-gencsf.h>\n"); + return -EINVAL; + } + + data->image_flexspi_fcfb_offset = strtoul(argv[1], NULL, 0); + + return 0; +} + struct command cmds[] = { { .name = "wm", @@ -662,11 +776,20 @@ struct command cmds[] = { .name = "hab_encrypt_blocks", .parse = do_hab_encrypt_blocks, }, { + .name = "hab_qspi", + .parse = do_hab_qspi, + }, { .name = "super_root_key", .parse = do_super_root_key, }, { .name = "signed_hdmi_firmware", .parse = do_signed_hdmi_firmware, + }, { + .name = "flexspi_fcfbofs", + .parse = do_flexspi_fcfbofs, + }, { + .name = "flexspi_ivtofs", + .parse = do_flexspi_ivtofs, }, }; @@ -675,6 +798,7 @@ static char *readcmd(struct config_data *data, FILE *f) static char *buf; char *str; ssize_t ret; + int inquotes = 0; if (!buf) { buf = malloc(4096); @@ -689,8 +813,9 @@ static char *readcmd(struct config_data *data, FILE *f) ret = fread(str, 1, 1, f); if (!ret) return strlen(buf) ? buf : NULL; - - if (*str == '\n' || *str == ';') { + if (*str == '"') { + inquotes = !inquotes; + } else if ((*str == '\n' || *str == ';') && !inquotes) { *str = 0; return buf; } diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h index 77dea7c54a..65697a9b0d 100644 --- a/scripts/imx/imx.h +++ b/scripts/imx/imx.h @@ -1,6 +1,6 @@ -#include <mach/imx-header.h> -#include <mach/imx_cpu_types.h> +#include <imx/imx-header.h> +#include <imx/imx_cpu_types.h> static inline int cpu_is_mx8m(const struct config_data *data) { @@ -15,4 +15,17 @@ static inline int cpu_is_mx8m(const struct config_data *data) } } +static inline bool flexspi_image(const struct config_data *data) +{ + /* + * | FlexSPI-FCFB | FlexSPI-IVT + * ----------------------------------------- + * i.MX8MM | 0x0 | 0x1000 + * i.MX8MN/P | 0x400 | 0x0 + */ + + return data->image_flexspi_ivt_offset || + data->image_flexspi_fcfb_offset; +} + int parse_config(struct config_data *data, const char *filename); diff --git a/scripts/imx9image.c b/scripts/imx9image.c new file mode 100644 index 0000000000..53fb879882 --- /dev/null +++ b/scripts/imx9image.c @@ -0,0 +1,2179 @@ +/* + * Copyright (C) 2016 Freescale Semiconductor, Inc. + * + * Copyright 2017 NXP + * + * SPDX-License-Identifier: GPL-2.0+ + * derived from u-boot's mkimage utility + * + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include <stddef.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <getopt.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <stdbool.h> +#include <inttypes.h> +#include <linux/kernel.h> + +#include "../include/soc/imx9/flash_header.h" +#include "compiler.h" + +typedef enum option_type { + NO_IMG = 0, + DCD, + SCFW, + SECO, + M4, + AP, + OUTPUT, + SCD, + CSF, + FLAG, + DEVICE, + NEW_CONTAINER, + APPEND, + DATA, + PARTITION, + FILEOFF, + MSG_BLOCK, + DUMMY_V2X, + SENTINEL, + UPOWER, + FCB +} option_type_t; + +typedef struct { + option_type_t option; + char* filename; + uint64_t src; + uint64_t dst; + uint64_t entry;/* image entry address or general purpose num */ + uint64_t ext; + uint64_t mu; + uint64_t part; +} image_t; + +typedef enum REVISION_TYPE { + NO_REV = 0, + A0, + B0 +} rev_type_t; + +typedef enum SOC_TYPE { + NONE = 0, + QX, + QM, + DXL, + ULP, + IMX9, +} soc_type_t; + +#define CORE_SC 0x1 +#define CORE_CM4_0 0x2 +#define CORE_CM4_1 0x3 +#define CORE_CA53 0x4 +#define CORE_CA35 0x4 +#define CORE_CA72 0x5 +#define CORE_SECO 0x6 +#define CORE_V2X_P 0x9 +#define CORE_V2X_S 0xA + +#define CORE_ULP_CM33 0x1 +#define CORE_ULP_CA35 0x2 +#define CORE_ULP_UPOWER 0x4 +#define CORE_ULP_SENTINEL 0x6 + +#define SC_R_OTP 357U +#define SC_R_DEBUG 354U +#define SC_R_ROM_0 236U +#define SC_R_PWM_0 191U +#define SC_R_SNVS 356U +#define SC_R_DC_0 32U + +#define IMG_TYPE_CSF 0x01 /* CSF image type */ +#define IMG_TYPE_SCD 0x02 /* SCD image type */ +#define IMG_TYPE_EXEC 0x03 /* Executable image type */ +#define IMG_TYPE_DATA 0x04 /* Data image type */ +#define IMG_TYPE_DCD_DDR 0x05 /* DCD/DDR image type */ +#define IMG_TYPE_SECO 0x06 /* SECO image type */ +#define IMG_TYPE_SENTINEL 0x06 /* SENTINEL image type */ +#define IMG_TYPE_PROV 0x07 /* Provisioning image type */ +#define IMG_TYPE_DEK 0x08 /* DEK validation type */ +#define IMG_TYPE_FCB_CHK 0x08 /* The FCB copy image */ +#define IMG_TYPE_PRIM_V2X 0x0B /* Primary V2X FW image */ +#define IMG_TYPE_SEC_V2X 0x0C /* Secondary V2X FW image*/ +#define IMG_TYPE_V2X_ROM 0x0D /* V2X ROM Patch image */ +#define IMG_TYPE_V2X_DUMMY 0x0E /* V2X Dummy image */ + +#define IMG_TYPE_SHIFT 0 +#define IMG_TYPE_MASK 0x1f +#define IMG_TYPE(x) (((x) & IMG_TYPE_MASK) >> IMG_TYPE_SHIFT) + +#define BOOT_IMG_FLAGS_CORE_MASK 0xF +#define BOOT_IMG_FLAGS_CORE_SHIFT 0x04 +#define BOOT_IMG_FLAGS_CPU_RID_MASK 0x3FF0 +#define BOOT_IMG_FLAGS_CPU_RID_SHIFT 4 +#define BOOT_IMG_FLAGS_MU_RID_MASK 0xFFC000 +#define BOOT_IMG_FLAGS_MU_RID_SHIFT 14 +#define BOOT_IMG_FLAGS_PARTITION_ID_MASK 0x1F000000 +#define BOOT_IMG_FLAGS_PARTITION_ID_SHIFT 24 + +#define SC_R_A35_0 508 +#define SC_R_A53_0 1 +#define SC_R_A72_0 6 +#define SC_R_MU_0A 213 +#define SC_R_MU_3A 216 +#define SC_R_M4_0_PID0 278 +#define SC_R_M4_0_MU_1A 297 +#define SC_R_M4_1_PID0 298 +#define SC_R_M4_1_MU_1A 317 +#define PARTITION_ID_M4 0 +#define PARTITION_ID_AP 1 +#define PARTITION_ID_AP2 3 + +/* Command tags and parameters */ +#define HAB_DATA_WIDTH_BYTE 1 /* 8-bit value */ +#define HAB_DATA_WIDTH_HALF 2 /* 16-bit value */ +#define HAB_DATA_WIDTH_WORD 4 /* 32-bit value */ +#define HAB_CMD_WRT_DAT_MSK 1 /* mask/value flag */ +#define HAB_CMD_WRT_DAT_SET 2 /* set/clear flag */ +#define HAB_CMD_CHK_DAT_SET 2 /* set/clear flag */ +#define HAB_CMD_CHK_DAT_ANY 4 /* any/all flag */ +#define HAB_CMD_WRT_DAT_FLAGS_WIDTH 5 /* flags field width */ +#define HAB_CMD_WRT_DAT_FLAGS_SHIFT 3 /* flags field offset */ +#define HAB_CMD_WRT_DAT_BYTES_WIDTH 3 /* bytes field width */ +#define HAB_CMD_WRT_DAT_BYTES_SHIFT 0 /* bytes field offset */ + +#define IVT_VER 0x01 +#define IVT_VERSION 0x43 +#define DCD_HEADER_TAG 0xD2 +#define DCD_VERSION 0x43 +#define DCD_WRITE_DATA_COMMAND_TAG 0xCC +#define DCD_WRITE_DATA_PARAM (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x4 */ +#define DCD_WRITE_CLR_BIT_PARAM ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0xC */ +#define DCD_WRITE_SET_BIT_PARAM ((HAB_CMD_WRT_DAT_MSK << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_WRT_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x1C */ +#define DCD_CHECK_DATA_COMMAND_TAG 0xCF +#define DCD_CHECK_BITS_CLR_PARAM (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT) /* 0x04 */ +#define DCD_CHECK_BITS_SET_PARAM ((HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x14 */ +#define DCD_CHECK_ANY_BIT_CLR_PARAM ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x24 */ +#define DCD_CHECK_ANY_BIT_SET_PARAM ((HAB_CMD_CHK_DAT_ANY << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_CMD_CHK_DAT_SET << HAB_CMD_WRT_DAT_FLAGS_SHIFT) | (HAB_DATA_WIDTH_WORD << HAB_CMD_WRT_DAT_BYTES_SHIFT)) /* 0x34 */ + +#define IVT_OFFSET_NAND (0x400) +#define IVT_OFFSET_I2C (0x400) +#define IVT_OFFSET_FLEXSPI (0x1000) +#define IVT_OFFSET_SD (0x400) +#define IVT_OFFSET_SATA (0x400) +#define IVT_OFFSET_EMMC (0x400) + +#define CSF_DATA_SIZE (0x4000) +#define INITIAL_LOAD_ADDR_SCU_ROM 0x2000e000 +#define INITIAL_LOAD_ADDR_AP_ROM 0x00110000 +#define INITIAL_LOAD_ADDR_FLEXSPI 0x08000000 +#define IMG_AUTO_ALIGN 0x10 + +#define UNDEFINED 0xFFFFFFFF + +#define OCRAM_START 0x00100000 +#define OCRAM_END 0x00400000 + +#define MAX_NUM_SRK_RECORDS 4 + +#define IVT_HEADER_TAG_B0 0x87 +#define IVT_VERSION_B0 0x00 + +#define IMG_FLAG_HASH_SHA256 0x000 +#define IMG_FLAG_HASH_SHA384 0x100 +#define IMG_FLAG_HASH_SHA512 0x200 +#define IMG_FLAG_HASH_SM3 0x300 + +#define IMG_FLAG_ENCRYPTED_MASK 0x400 +#define IMG_FLAG_ENCRYPTED_SHIFT 0x0A + +#define IMG_FLAG_BOOTFLAGS_MASK 0xFFFF0000 +#define IMG_FLAG_BOOTFLAGS_SHIFT 0x10 + +#define IMG_ARRAY_ENTRY_SIZE 128 +#define HEADER_IMG_ARRAY_OFFSET 0x10 + +#define HASH_STR_SHA_256 "sha256" +#define HASH_STR_SHA_384 "sha384" +#define HASH_STR_SHA_512 "sha512" +#define HASH_STR_SM3 "sm3" + +#define HASH_TYPE_SHA_256 256 +#define HASH_TYPE_SHA_384 384 +#define HASH_TYPE_SHA_512 512 +#define HASH_TYPE_SM3 003 + +#define IMAGE_HASH_ALGO_DEFAULT HASH_TYPE_SHA_384 +#define IMAGE_HASH_ALGO_DEFAULT_NAME HASH_STR_SHA_384 +#define IMAGE_PADDING_DEFAULT 0x1000 + +#define DCD_ENTRY_ADDR_IN_SCFW 0x240 + +#define CONTAINER_ALIGNMENT 0x400 +#define CONTAINER_FLAGS_DEFAULT 0x10 +#define CONTAINER_FUSE_DEFAULT 0x0 + +#define SIGNATURE_BLOCK_HEADER_LENGTH 0x10 + +#define BOOT_IMG_META_MU_RID_SHIFT 10 +#define BOOT_IMG_META_PART_ID_SHIFT 20 + +#define IMAGE_TYPE_MASK 0xF + +#define CORE_ID_SHIFT 0x4 +#define CORE_ID_MASK 0xF + +#define HASH_TYPE_SHIFT 0x8 +#define HASH_TYPE_MASK 0x7 + +#define IMAGE_ENCRYPTED_SHIFT 0x11 +#define IMAGE_ENCRYPTED_MASK 0x1 + +#define IMAGE_A35_DEFAULT_META(PART, SC_R_MU) \ + (((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT | \ + SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A35_0) + +#define IMAGE_A53_DEFAULT_META(PART, SC_R_MU) \ + (((PART == 0 ) ? PARTITION_ID_AP : PART) << BOOT_IMG_META_PART_ID_SHIFT | \ + SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | \ + SC_R_A53_0) + +#define IMAGE_A72_DEFAULT_META(PART, SC_R_MU) \ + (((PART == 0 ) ? PARTITION_ID_AP2 : PART) << BOOT_IMG_META_PART_ID_SHIFT | \ + SC_R_MU << BOOT_IMG_META_MU_RID_SHIFT | SC_R_A72_0) + +#define IMAGE_M4_0_DEFAULT_META(PART) \ + (((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT | \ + SC_R_M4_0_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_0_PID0) + +#define IMAGE_M4_1_DEFAULT_META(PART) \ + (((PART == 0) ? PARTITION_ID_M4 : PART) << BOOT_IMG_META_PART_ID_SHIFT | \ + SC_R_M4_1_MU_1A << BOOT_IMG_META_MU_RID_SHIFT | SC_R_M4_1_PID0) + +#define CONTAINER_IMAGE_ARRAY_START_OFFSET 0x2000 + +uint32_t scfw_flags = 0; + +static uint32_t custom_partition = 0; + +static void copy_file_aligned(int ifd, const char *datafile, int offset, int align) +{ + int dfd; + struct stat sbuf; + unsigned char *ptr; + uint8_t zeros[0x4000]; + int size; + int ret; + + if (align > 0x4000) { + fprintf (stderr, "Wrong alignment requested %d\n", + align); + exit (EXIT_FAILURE); + } + + memset(zeros, 0, sizeof(zeros)); + + if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { + fprintf (stderr, "Can't open %s: %s\n", + datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf (stderr, "Can't stat %s: %s\n", + datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (sbuf.st_size == 0) + goto close; + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == MAP_FAILED) { + fprintf (stderr, "Can't read %s: %s\n", + datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + size = sbuf.st_size; + ret = lseek(ifd, offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "%s: lseek error %s\n", + __func__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (write(ifd, ptr, size) != size) { + fprintf (stderr, "Write error %s\n", + strerror(errno)); + exit (EXIT_FAILURE); + } + + align = ALIGN(size, align) - size; + + if (write(ifd, (char *)&zeros, align) != align) { + fprintf(stderr, "Write error: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + + (void) munmap((void *)ptr, sbuf.st_size); +close: + (void) close (dfd); + +} + +static void set_imx_hdr_v3(struct imx_header_v3 *imxhdr, uint32_t dcd_len, + uint32_t flash_offset, uint32_t hdr_base, uint32_t cont_id) +{ + struct flash_header_v3 *fhdr_v3 = &imxhdr->fhdr[cont_id]; + + /* Set magic number */ + fhdr_v3->tag = IVT_HEADER_TAG_B0; + fhdr_v3->version = IVT_VERSION_B0; +} + +static void set_image_hash(struct boot_img *img, char *filename, uint32_t hash_type, int size) +{ + FILE *fp = NULL; + char sha_command[512]; + char digest_type[10]; + char hash[2 * HASH_MAX_LEN + 1]; + int digest_length = 0; + int i; + + switch (hash_type) { + case HASH_TYPE_SHA_256: + img->hab_flags |= IMG_FLAG_HASH_SHA256; + strcpy(digest_type, "sha256sum" ); + digest_length = 64; + break; + case HASH_TYPE_SHA_384: + img->hab_flags |= IMG_FLAG_HASH_SHA384; + strcpy(digest_type, "sha384sum" ); + digest_length = 96; + break; + case HASH_TYPE_SHA_512: + img->hab_flags |= IMG_FLAG_HASH_SHA512; + strcpy(digest_type, "sha512sum" ); + digest_length = 128; + break; + case HASH_TYPE_SM3: + img->hab_flags |= IMG_FLAG_HASH_SM3; + strcpy(digest_type, "sm3sum" ); + digest_length = 64; + break; + default: + fprintf(stderr, "Wrong hash type selected (%d) !!!\n\n", + hash_type); + exit(EXIT_FAILURE); + break; + } + + if (!size || !filename) + sprintf(sha_command, "%s /dev/null", digest_type); + else + sprintf(sha_command, "cat \'%s\' /dev/zero | dd status=none bs=1 count=%d | %s", + filename, size, digest_type); + + memset(img->hash, 0, HASH_MAX_LEN); + + fp = popen(sha_command, "r"); + if (fp == NULL) { + fprintf(stderr, "Failed to run command hash\n" ); + exit(EXIT_FAILURE); + } + + if (fgets(hash, digest_length + 1, fp) == NULL) { + fprintf(stderr, "Failed to hash file: %s\n", filename ? filename : "<none>"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < strlen(hash)/2; i++) + sscanf(hash + 2*i, "%02hhx", &img->hash[i]); + + pclose(fp); +} + +#define append(p, s, l) do {memcpy(p, (uint8_t *)s, l); p += l; } while (0) + +static uint8_t *flatten_container_header(struct imx_header_v3 *imx_header, + uint8_t containers_count, + uint32_t *size_out, uint32_t file_offset) +{ + uint8_t *flat = NULL; + uint8_t *ptr = NULL; + uint16_t size = 0; + int i; + + /* Compute size of all container headers */ + for (i = 0; i < containers_count; i++) { + + struct flash_header_v3 *container = &imx_header->fhdr[i]; + + container->sig_blk_offset = HEADER_IMG_ARRAY_OFFSET + + container->num_images * IMG_ARRAY_ENTRY_SIZE; + + container->length = HEADER_IMG_ARRAY_OFFSET + + (IMG_ARRAY_ENTRY_SIZE * container->num_images) + sizeof(struct sig_blk_hdr); + + /* Print info needed by CST to sign the container header */ + printf("CST: CONTAINER %d offset: 0x%x\n", i, file_offset + size); + printf("CST: CONTAINER %d: Signature Block: offset is at 0x%x\n", i, + file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH); + + printf("\tOffsets = \t0x%x \t0x%x\n", file_offset + size, + file_offset + size + container->length - SIGNATURE_BLOCK_HEADER_LENGTH); + + size += ALIGN(container->length, container->padding); + } + + flat = calloc(size, sizeof(uint8_t)); + if (!flat) { + fprintf(stderr, "Failed to allocate memory (%d)\n", size); + exit(EXIT_FAILURE); + } + + ptr = flat; + *size_out = size; + + for (i = 0; i < containers_count; i++) { + struct flash_header_v3 *container = &imx_header->fhdr[i]; + uint32_t container_start_offset = ptr - flat; + int j; + + /* Append container header */ + append(ptr, container, HEADER_IMG_ARRAY_OFFSET); + + /* Adjust images offset to start from container headers start */ + for (j = 0; j < container->num_images; j++) + container->img[j].offset -= container_start_offset + file_offset; + + /* Append each image array entry */ + for (j = 0; j < container->num_images; j++) + append(ptr, &container->img[j], sizeof(struct boot_img)); + + append(ptr, &container->sig_blk_hdr, sizeof(struct sig_blk_hdr)); + + /* Padding for container (if necessary) */ + ptr += ALIGN(container->length, container->padding) - container->length; + } + + return flat; +} + +static uint64_t read_dcd_offset(char *filename) +{ + int dfd; + struct stat sbuf; + uint8_t *ptr; + uint64_t offset = 0; + + dfd = open(filename, O_RDONLY|O_BINARY); + if (dfd < 0) { + fprintf(stderr, "Can't open %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf(stderr, "Can't stat %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr, "Can't read %s: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + offset = *(uint32_t *)(ptr + DCD_ENTRY_ADDR_IN_SCFW); + + (void) munmap((void *)ptr, sbuf.st_size); + (void) close(dfd); + + return offset; +} + +static uint32_t get_hash_algo(char *images_hash) +{ + uint32_t hash_algo; + const char *hash_name; + + if (!images_hash) { + hash_algo = IMAGE_HASH_ALGO_DEFAULT; + hash_name = IMAGE_HASH_ALGO_DEFAULT_NAME; + } else if (!strcmp(images_hash, HASH_STR_SHA_256)) { + hash_algo = HASH_TYPE_SHA_256; + hash_name = HASH_STR_SHA_256; + } else if (!strcmp(images_hash, HASH_STR_SHA_384)) { + hash_algo = HASH_TYPE_SHA_384; + hash_name = HASH_STR_SHA_384; + } else if (!strcmp(images_hash, HASH_STR_SHA_512)) { + hash_algo = HASH_TYPE_SHA_512; + hash_name = HASH_STR_SHA_512; + } else if (!strcmp(images_hash, HASH_STR_SM3)) { + hash_algo = HASH_TYPE_SM3; + hash_name = HASH_STR_SM3; + } else { + fprintf(stderr, + "\nERROR: %s is an invalid hash argument\n" + " Expected values: %s, %s, %s, %s\n\n", + images_hash, HASH_STR_SHA_256, HASH_STR_SHA_384, + HASH_STR_SHA_512, HASH_STR_SM3); + exit(EXIT_FAILURE); + } + + printf("image hash type:\t%s\n", hash_name); + return hash_algo; +} + +static void set_image_array_entry(struct flash_header_v3 *container, soc_type_t soc, + const image_t *image_stack, uint32_t offset, + uint32_t size, char *tmp_filename, bool dcd_skip, char *images_hash) +{ + uint64_t entry = image_stack->entry; + uint64_t dst = image_stack->dst; + uint64_t core = image_stack->ext; + uint32_t meta; + char *tmp_name = ""; + option_type_t type = image_stack->option; + struct boot_img *img = &container->img[container->num_images]; + + if (container->num_images >= MAX_NUM_IMGS) { + fprintf(stderr, "Error: Container allows 8 images at most\n"); + exit(EXIT_FAILURE); + } + + img->offset = offset; /* Is re-adjusted later */ + img->size = size; + + set_image_hash(img, tmp_filename, get_hash_algo(images_hash), size); + + switch (type) { + case SECO: + if (container->num_images > 0) { + fprintf(stderr, "Error: SECO container only allows 1 image\n"); + exit(EXIT_FAILURE); + } + + img->hab_flags |= IMG_TYPE_SECO; + img->hab_flags |= CORE_SECO << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "SECO"; + img->dst = 0x20C00000; + img->entry = 0x20000000; + + break; + case SENTINEL: + if (container->num_images > 0) { + fprintf(stderr, "Error: SENTINEL container only allows 1 image\n"); + exit(EXIT_FAILURE); + } + + img->hab_flags |= IMG_TYPE_SENTINEL; + img->hab_flags |= CORE_ULP_SENTINEL << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "SENTINEL"; + img->dst = 0XE7FE8000; /* S400 IRAM base */ + img->entry = 0XE7FE8000; + + break; + case AP: + if ((soc == QX || soc == DXL) && core == CORE_CA35) + meta = IMAGE_A35_DEFAULT_META(image_stack->part, image_stack->mu); + else if (soc == QM && core == CORE_CA53) + meta = IMAGE_A53_DEFAULT_META(image_stack->part, image_stack->mu); + else if (soc == QM && core == CORE_CA72) + meta = IMAGE_A72_DEFAULT_META(image_stack->part, image_stack->mu); + else if (((soc == ULP) || (soc == IMX9)) && core == CORE_CA35) + meta = 0; + else { + fprintf(stderr, "Error: invalid AP core id: %" PRIi64 "\n", core); + exit(EXIT_FAILURE); + } + img->hab_flags |= IMG_TYPE_EXEC; + if ((soc == ULP) || (soc == IMX9)) + img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT; + else + img->hab_flags |= CORE_CA53 << BOOT_IMG_FLAGS_CORE_SHIFT; /* On B0, only core id = 4 is valid */ + tmp_name = "AP"; + img->dst = entry; + img->entry = entry; + img->meta = meta; + custom_partition = 0; + break; + case M4: + if ((soc == ULP) || (soc == IMX9)) { + core = CORE_ULP_CM33; + meta = 0; + } else if (core == 0) { + core = CORE_CM4_0; + meta = IMAGE_M4_0_DEFAULT_META(custom_partition); + } else if (core == 1) { + core = CORE_CM4_1; + meta = IMAGE_M4_1_DEFAULT_META(custom_partition); + } else { + fprintf(stderr, "Error: invalid m4 core id: %" PRIi64 "\n", core); + exit(EXIT_FAILURE); + } + + img->hab_flags |= IMG_TYPE_EXEC; + img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "M4"; + if ((entry & 0x7) != 0) + fprintf(stderr, "\n\nWarning: M4 Destination address is not 8 byte aligned\n\n"); + + if (dst) + img->dst = dst; + else + img->dst = entry; + + img->entry = entry; + img->meta = meta; + custom_partition = 0; + break; + case DATA: + img->hab_flags |= IMG_TYPE_DATA; + if ((soc == ULP) || (soc == IMX9)) + if (core == CORE_CM4_0) + img->hab_flags |= CORE_ULP_CM33 << BOOT_IMG_FLAGS_CORE_SHIFT; + else + img->hab_flags |= CORE_ULP_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT; + else + img->hab_flags |= core << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "DATA"; + img->dst = entry; + break; + case MSG_BLOCK: + img->hab_flags |= IMG_TYPE_DATA; + img->hab_flags |= CORE_CA35 << BOOT_IMG_FLAGS_CORE_SHIFT; + img->meta = core << BOOT_IMG_META_MU_RID_SHIFT; + tmp_name = "MSG_BLOCK"; + img->dst = entry; + break; + case SCFW: + img->hab_flags |= scfw_flags & 0xFFFF0000; + img->hab_flags |= IMG_TYPE_EXEC; + img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "SCFW"; + img->dst = 0x1FFE0000; + img->entry = 0x1FFE0000; + + /* Lets add the DCD now */ + if (!dcd_skip) { + container->num_images++; + img = &container->img[container->num_images]; + img->hab_flags |= IMG_TYPE_DCD_DDR; + img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT; + set_image_hash(img, "/dev/null", IMAGE_HASH_ALGO_DEFAULT, 0); + img->offset = offset + img->size; + img->entry = read_dcd_offset(tmp_filename); + img->dst = img->entry - 1; + } + break; + case UPOWER: + if (soc == ULP) { + img->hab_flags |= IMG_TYPE_EXEC; + img->hab_flags |= CORE_ULP_UPOWER << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "UPOWER"; + img->dst = 0x28300200; /* UPOWER code RAM */ + img->entry = 0x28300200; + } + break; + case DUMMY_V2X: + img->hab_flags |= IMG_TYPE_V2X_DUMMY; + img->hab_flags |= CORE_SC << BOOT_IMG_FLAGS_CORE_SHIFT; + tmp_name = "V2X Dummy"; + img->dst = entry; + img->entry = entry; + img->size = 0; /* dummy image has no size */ + break; + case FCB: + img->hab_flags |= IMG_TYPE_FCB_CHK; + img->dst = entry; + tmp_name = "FCB"; + break; + default: + fprintf(stderr, "unrecognized image type (%d)\n", type); + exit(EXIT_FAILURE); + } + + printf("%s file_offset = 0x%x size = 0x%x\n", tmp_name, offset, size); + + container->num_images++; +} + +static void set_container(struct flash_header_v3 *container, uint16_t sw_version, + uint32_t alignment, uint32_t flags, uint16_t fuse_version) +{ + container->sig_blk_hdr.tag = 0x90; + container->sig_blk_hdr.length = sizeof(struct sig_blk_hdr); + container->sw_version = sw_version; + container->padding = alignment; + container->fuse_version = fuse_version; + container->flags = flags; + printf("flags:\t\t\t0x%x\n", container->flags); +} + +static int get_container_image_start_pos(image_t *image_stack, uint32_t align, soc_type_t soc, + uint32_t *scu_cont_hdr_off) +{ + image_t *img_sp = image_stack; + /* 8K total container header */ + int file_off = CONTAINER_IMAGE_ARRAY_START_OFFSET, ofd = -1; + struct flash_header_v3 header; + + while (img_sp->option != NO_IMG) { + if (img_sp->option != APPEND) { + img_sp++; + continue; + } + + ofd = open(img_sp->filename, O_RDONLY); + if (ofd < 0) { + printf("Failure open first container file %s\n", img_sp->filename); + break; + } + + if (soc == DXL) { + /* Skip SECO container, jump to V2X container */ + if (lseek(ofd, CONTAINER_ALIGNMENT, SEEK_SET) < 0) { + printf("Failure Skip SECO header \n"); + exit(EXIT_FAILURE); + } + } + + if (read(ofd, &header, sizeof(header)) != sizeof(header)) { + printf("Failure Read header \n"); + exit(EXIT_FAILURE); + } + + close(ofd); + + if (header.tag != IVT_HEADER_TAG_B0) { + printf("header tag mismatch %x\n", header.tag); + } else if (header.num_images == 0) { + printf("image num is 0 \n"); + } else { + file_off = header.img[header.num_images - 1].offset + header.img[header.num_images - 1].size; + if (soc == DXL) { + file_off += CONTAINER_ALIGNMENT; + *scu_cont_hdr_off = CONTAINER_ALIGNMENT + ALIGN(header.length, CONTAINER_ALIGNMENT); + } else { + *scu_cont_hdr_off = ALIGN(header.length, CONTAINER_ALIGNMENT); + } + file_off = ALIGN(file_off, align); + } + + img_sp++; + } + + return file_off; +} + +static void check_file(struct stat *sbuf, char *filename) +{ + int tmp_fd = open(filename, O_RDONLY | O_BINARY); + + if (tmp_fd < 0) { + fprintf(stderr, "%s: Can't open: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (fstat(tmp_fd, sbuf) < 0) { + fprintf(stderr, "%s: Can't stat: %s\n", filename, strerror(errno)); + exit(EXIT_FAILURE); + } + + close(tmp_fd); +} + +static void copy_file(int ifd, const char *datafile, int pad, int offset) +{ + int dfd; + struct stat sbuf; + unsigned char *ptr; + int tail; + uint8_t zeros[4096]; + int size, ret; + + memset(zeros, 0, sizeof(zeros)); + + if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { + fprintf(stderr, "Can't open %s: %s\n", datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (fstat(dfd, &sbuf) < 0) { + fprintf(stderr, "Can't stat %s: %s\n", datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + if (sbuf.st_size == 0) + goto close; + + ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); + if (ptr == MAP_FAILED) { + fprintf(stderr, "Can't read %s: %s\n", datafile, strerror(errno)); + exit (EXIT_FAILURE); + } + + size = sbuf.st_size; + ret = lseek(ifd, offset, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (write(ifd, ptr, size) != size) { + fprintf(stderr, "Write error %s\n", strerror(errno)); + exit (EXIT_FAILURE); + } + + tail = size % 4; + pad = pad - size; + if ((pad == 1) && (tail != 0)) { + + if (write(ifd, zeros, 4 - tail) != 4 - tail) { + fprintf(stderr, "Write error on %s\n", strerror(errno)); + exit (EXIT_FAILURE); + } + } else if (pad > 1) { + while (pad > 0) { + int todo = sizeof(zeros); + + if (todo > pad) + todo = pad; + if (write(ifd, (char *)&zeros, todo) != todo) { + fprintf(stderr, "Write error: %s\n", + strerror(errno)); + exit(EXIT_FAILURE); + } + pad -= todo; + } + } + + (void) munmap((void *)ptr, sbuf.st_size); +close: + (void) close (dfd); +} + +static int pblsize; + +static int build_container_qx_qm_b0(soc_type_t soc, uint32_t sector_size, uint32_t ivt_offset, + char *out_file, bool emmc_fastboot, image_t *image_stack, + bool dcd_skip, uint8_t fuse_version, uint16_t sw_version, + char *images_hash) +{ + int file_off, ofd = -1; + unsigned int dcd_len = 0; + struct imx_header_v3 imx_header = {}; + image_t *img_sp = image_stack; + struct stat sbuf; + uint32_t size = 0; + uint32_t file_padding = 0; + int ret; + const char *platform; + + int container = -1; + int cont_img_count = 0; /* indexes to arrange the container */ + + if (image_stack == NULL) { + fprintf(stderr, "Empty image stack "); + exit(EXIT_FAILURE); + } + + switch (soc) { + case QX: platform = "i.MX8QXP B0"; break; + case QM: platform = "i.MX8QM B0"; break; + case DXL: platform = "i.MX8DXL A0"; break; + case ULP: platform = "i.MX8ULP A0"; break; + case IMX9: platform = "i.MX9"; break; + default: + exit(EXIT_FAILURE); + } + + printf("Platform:\t\t%s\n", platform); + + set_imx_hdr_v3(&imx_header, dcd_len, ivt_offset, INITIAL_LOAD_ADDR_SCU_ROM, 0); + set_imx_hdr_v3(&imx_header, 0, ivt_offset, INITIAL_LOAD_ADDR_AP_ROM, 1); + + printf("ivt_offset:\t\t0x%x\n", ivt_offset); + + file_off = get_container_image_start_pos(image_stack, sector_size, soc, &file_padding); + printf("container image offset (aligned): 0x%x\n", file_off); + + printf("csf_off:\t\t0x%x\n", ivt_offset + file_off); + + /* step through image stack and generate the header */ + img_sp = image_stack; + + while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */ + int isize; + switch (img_sp->option) { + case FCB: + case AP: + case M4: + case SCFW: + case DATA: + case UPOWER: + case MSG_BLOCK: + case SENTINEL: + if (container < 0) { + fprintf(stderr, "No container found\n"); + exit(EXIT_FAILURE); + } + check_file(&sbuf, img_sp->filename); + isize = ALIGN(sbuf.st_size, sector_size); + if (pblsize && isize > ALIGN(pblsize, 1024)) + isize = ALIGN(pblsize, 1024); + set_image_array_entry(&imx_header.fhdr[container], + soc, + img_sp, + file_off, + isize, + img_sp->filename, + dcd_skip, + images_hash); + img_sp->src = file_off; + + file_off += ALIGN(sbuf.st_size, sector_size); + cont_img_count++; + break; + + case DUMMY_V2X: + if (container < 0) { + fprintf(stderr, "No container found\n"); + exit(EXIT_FAILURE); + } + set_image_array_entry(&imx_header.fhdr[container], + soc, + img_sp, + file_off, + 0, + NULL, + dcd_skip, + images_hash); + img_sp->src = file_off; + + cont_img_count++; + break; + + case SECO: + if (container < 0) { + fprintf(stderr, "No container found\n"); + exit(EXIT_FAILURE); + } + check_file(&sbuf, img_sp->filename); + set_image_array_entry(&imx_header.fhdr[container], + soc, + img_sp, + file_off, + sbuf.st_size, + img_sp->filename, + dcd_skip, + "sha384"); + img_sp->src = file_off; + + file_off += sbuf.st_size; + cont_img_count++; + break; + + case NEW_CONTAINER: + container++; + set_container(&imx_header.fhdr[container], sw_version, + CONTAINER_ALIGNMENT, + CONTAINER_FLAGS_DEFAULT, + fuse_version); + cont_img_count = 0; /* reset img count when moving to new container */ + scfw_flags = 0; + break; + + case APPEND: + /* nothing to do here, the container is appended in the output */ + break; + case FLAG: + /* override the flags for scfw in current container */ + scfw_flags = img_sp->entry & 0xFFFF0000;/* mask off bottom 16 bits */ + break; + case FILEOFF: + if (file_off > img_sp->dst) { + fprintf(stderr, "FILEOFF address less than current file offset!!!\n"); + exit(EXIT_FAILURE); + } + if (img_sp->dst != ALIGN(img_sp->dst, sector_size)) { + fprintf(stderr, "FILEOFF address is not aligned to sector size!!!\n"); + exit(EXIT_FAILURE); + } + file_off = img_sp->dst; + break; + case PARTITION: /* keep custom partition until next executable image */ + custom_partition = img_sp->entry; /* use a global var for default behaviour */ + break; + default: + fprintf(stderr, "unrecognized option in input stack (%d)\n", img_sp->option); + exit(EXIT_FAILURE); + } + img_sp++;/* advance index */ + } + + /* Open output file */ + ofd = open(out_file, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); + if (ofd < 0) { + fprintf(stderr, "%s: Can't open: %s\n", + out_file, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Append container (if specified) */ + img_sp = image_stack; + while (img_sp->option != NO_IMG) { + if (img_sp->option == APPEND) + copy_file(ofd, img_sp->filename, 0, 0); + + img_sp++; + } + + /* Add padding or skip appended container */ + ret = lseek(ofd, file_padding, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "%s: lseek error %s\n", __func__, strerror(errno)); + exit(EXIT_FAILURE); + } + + /* Note: Image offset are not contained in the image */ + uint8_t *tmp = flatten_container_header(&imx_header, container + 1, &size, file_padding); + /* Write image header */ + if (write(ofd, tmp, size) != size) { + fprintf(stderr, "error writing image hdr\n"); + exit(1); + } + + /* Clean-up memory used by the headers */ + free(tmp); + + if (emmc_fastboot) + ivt_offset = 0; /*set ivt offset to 0 if emmc */ + + /* step through the image stack again this time copying images to final bin */ + img_sp = image_stack; + while (img_sp->option != NO_IMG) { /* stop once we reach null terminator */ + if (img_sp->option == M4 || + img_sp->option == AP || + img_sp->option == DATA || + img_sp->option == SCD || + img_sp->option == SCFW || + img_sp->option == SECO || + img_sp->option == MSG_BLOCK || + img_sp->option == UPOWER || + img_sp->option == SENTINEL || + img_sp->option == FCB) { + copy_file_aligned(ofd, img_sp->filename, img_sp->src, sector_size); + } + img_sp++; + } + + /* Close output file */ + close(ofd); + return 0; +} + +static struct img_flags parse_image_flags(uint32_t flags, char *flag_list, soc_type_t soc) +{ + struct img_flags img_flags; + + strcpy(flag_list, "("); + + /* first extract the image type */ + strcat(flag_list, "IMG TYPE: "); + img_flags.type = flags & IMAGE_TYPE_MASK; + + switch (img_flags.type) { + + case 0x3: + strcat(flag_list, "Executable"); + break; + case 0x4: + strcat(flag_list, "Data"); + break; + case 0x5: + strcat(flag_list, "DDR Init"); + break; + case 0x6: + if ((soc == ULP) || (soc == IMX9)) + strcat(flag_list, "SENTINEL"); + else + strcat(flag_list, "SECO"); + break; + case 0x7: + strcat(flag_list, "Provisioning"); + break; + case 0x8: + if (soc == IMX9) + strcat(flag_list, "FCB Check"); + else + strcat(flag_list, "DEK validation"); + break; + case 0xB: + strcat(flag_list, "Primary V2X FW image"); + break; + case 0xC: + strcat(flag_list, "Secondary V2X FW image"); + break; + case 0xD: + strcat(flag_list, "V2X ROM Patch image"); + break; + case 0xE: + strcat(flag_list, "V2X Dummy image"); + break; + default: + strcat(flag_list, "Invalid img type"); + break; + } + strcat(flag_list, " | "); + + /* next get the core id */ + strcat(flag_list, "CORE ID: "); + img_flags.core_id = (flags >> CORE_ID_SHIFT) & CORE_ID_MASK; + + if ((soc == ULP) || (soc == IMX9)) { + switch (img_flags.core_id) { + case CORE_ULP_CM33: + strcat(flag_list, "CORE_CM33"); + break; + case CORE_ULP_SENTINEL: + strcat(flag_list, "CORE_SENTINEL"); + break; + case CORE_ULP_UPOWER: + strcat(flag_list, "CORE_UPOWER"); + break; + case CORE_ULP_CA35: + if (soc == IMX9) + strcat(flag_list, "CORE_CA55"); + else + strcat(flag_list, "CORE_CA35"); + break; + default: + strcat(flag_list, "Invalid core id"); + break; + } + } else { + switch (img_flags.core_id) { + case CORE_SC: + strcat(flag_list, "CORE_SC"); + break; + case CORE_CM4_0: + strcat(flag_list, "CORE_CM4_0"); + break; + case CORE_CM4_1: + strcat(flag_list, "CORE_CM4_1"); + break; + case CORE_CA53: + strcat(flag_list, "CORE_CA53"); + break; + case CORE_CA72: + strcat(flag_list, "CORE_CA72"); + break; + case CORE_SECO: + strcat(flag_list, "CORE_SECO"); + break; + case CORE_V2X_P: + strcat(flag_list, "CORE_V2X_P"); + break; + case CORE_V2X_S: + strcat(flag_list, "CORE_V2X_S"); + break; + default: + strcat(flag_list, "Invalid core id"); + break; + } + } + strcat(flag_list, " | "); + + /* next get the hash type */ + strcat(flag_list, "HASH TYPE: "); + img_flags.hash_type = (flags >> HASH_TYPE_SHIFT) & HASH_TYPE_MASK; + + switch (img_flags.hash_type) { + case 0x0: + strcat(flag_list, "SHA256"); + break; + case 0x1: + strcat(flag_list, "SHA384"); + break; + case 0x2: + strcat(flag_list, "SHA512"); + break; + case 0x3: + strcat(flag_list, "SM3"); + break; + default: + break; + } + strcat(flag_list, " | "); + + /* lastly, read the encrypted bit */ + strcat(flag_list, "ENCRYPTED: "); + img_flags.encrypted = (flags >> IMAGE_ENCRYPTED_SHIFT) & IMAGE_ENCRYPTED_MASK; + + if (img_flags.encrypted) + strcat(flag_list, "YES"); + else + strcat(flag_list, "NO"); + + /* terminate flag string */ + strcat(flag_list, ")"); + + return img_flags; +} + +static void print_image_array_fields(struct flash_header_v3 *container_hdrs, soc_type_t soc, bool app_cntr) +{ + struct boot_img img; /* image array entry */ + struct img_flags img_flags; /* image hab flags */ + int hash_length = 0; + char img_name[32]; /* scfw, bootloader, etc. */ + char hash_name[8]; /* sha256, sha384, or sha512 */ + char flag_string[128]; /* text representation of image hab flags */ + int i; + + for (i = 0; i < container_hdrs->num_images; i++) { + /* get the next image array entry */ + img = container_hdrs->img[i]; + + /* get the image flags */ + img_flags = parse_image_flags(img.hab_flags, flag_string, soc); + + /* determine the type of image */ + switch (img_flags.type) { + case 0x3: + if ((soc == ULP) || (soc == IMX9)) { + if (img_flags.core_id == CORE_ULP_UPOWER) + strcpy(img_name, "uPower FW"); + else if ((img_flags.core_id == CORE_ULP_CA35)) + if (app_cntr) + strcpy(img_name, "A core Image"); + else + strcpy(img_name, "Bootloader"); + else if ((img_flags.core_id == CORE_ULP_CM33)) + strcpy(img_name, "M33"); + + } else { + if (img_flags.core_id == CORE_SC) + strcpy(img_name, "SCFW"); + else if ((img_flags.core_id == CORE_CA53) || (img_flags.core_id == CORE_CA72)) + if (app_cntr) + strcpy(img_name, "A core Image"); + else + strcpy(img_name, "Bootloader"); + else if (img_flags.core_id == CORE_CM4_0) + strcpy(img_name, "M4_0"); + else if (img_flags.core_id == CORE_CM4_1) + strcpy(img_name, "M4_1"); + } + break; + case 0x4: + strcpy(img_name, "Data"); + break; + case 0x5: + strcpy(img_name, "DDR Init"); + break; + case 0x6: + if ((soc == ULP) || (soc == IMX9)) + strcpy(img_name, "SENTINEL FW"); + else + strcpy(img_name, "SECO FW"); + break; + case 0x7: + strcpy(img_name, "Provisioning"); + break; + case 0x8: + if (soc == IMX9) + strcpy(img_name, "FCB Check"); + else + strcpy(img_name, "DEK Validation"); + break; + case 0xB: + strcpy(img_name, "Primary V2X FW image"); + break; + case 0xC: + strcpy(img_name, "Secondary V2X FW image"); + break; + case 0xD: + strcpy(img_name, "V2X ROM Patch image"); + break; + case 0xE: + strcpy(img_name, "V2X Dummy image"); + break; + default: + strcpy(img_name, "Unknown image"); + break; + } + + /* get the image hash type */ + switch (img_flags.hash_type) { + case 0x0: + hash_length = 256 / 8; + strcpy(hash_name, "SHA256"); + break; + case 0x1: + hash_length = 384 / 8; + strcpy(hash_name, "SHA384"); + break; + case 0x2: + hash_length = 512 / 8; + strcpy(hash_name, "SHA512"); + break; + case 0x3: + hash_length = 256 / 8; + strcpy(hash_name, "SM3"); + break; + default: + strcpy(hash_name, "Unknown"); + break; + } + + /* print the image array fields */ + printf("%sIMAGE %d (%s)%s\n", "\x1B[33m", i+1, img_name, "\x1B[37m"); + printf("Offset: %#X\n", img.offset); + printf("Size: %#X (%d)\n", img.size, img.size); + printf("Load Addr: %#lX\n", img.dst); + printf("Entry Addr: %#lX\n", img.entry); + printf("Flags: %#X %s\n", img.hab_flags, flag_string); + + /* only print metadata and hash if the image isn't DDR init */ + if (img_flags.type != 0x5) { + int j; + + printf("Metadata: %#X\n", img.meta); + + /* print the image hash */ + printf("Hash: "); + for (j = 0; j < hash_length; j++) + printf("%02x", img.hash[j]); + + printf(" (%s)\n", hash_name); + + } + printf("\n"); + } +} + +static void print_container_hdr_fields(struct flash_header_v3 *container_hdrs, int num_cntrs, + soc_type_t soc, bool app_cntr) +{ + int i; + + for (i = 0; i < num_cntrs; i++) { + printf("\n"); + printf("*********************************\n"); + printf("* *\n"); + if (app_cntr) + printf("* APP CONTAINER %-2d *\n", i + 1); + else + printf("* ROM CONTAINER %-2d *\n", i + 1); + printf("* *\n"); + printf("*********************************\n\n"); + printf("%16s", "Length: "); + printf("%#X (%d)\n", container_hdrs->length, container_hdrs->length); + printf("%16s", "Tag: "); + printf("%#X\n", container_hdrs->tag); + printf("%16s", "Version: "); + printf("%#X\n", container_hdrs->version); + printf("%16s", "Flags: "); + printf("%#X\n", container_hdrs->flags); + printf("%16s", "Num images: "); + printf("%d\n", container_hdrs->num_images); + printf("%16s", "Fuse version: "); + printf("%#X\n", container_hdrs->fuse_version); + printf("%16s", "SW version: "); + printf("%#X\n", container_hdrs->sw_version); + printf("%16s", "Sig blk offset: "); + printf("%#X\n\n", container_hdrs->sig_blk_offset); + + print_image_array_fields(container_hdrs, soc, app_cntr); + + container_hdrs++; + } +} + +static int get_container_size(struct flash_header_v3 *phdr) +{ + uint8_t i = 0; + uint32_t max_offset = 0, img_end; + + max_offset = phdr->length; + + for (i = 0; i < phdr->num_images; i++) { + img_end = phdr->img[i].offset + phdr->img[i].size; + if (img_end > max_offset) + max_offset = img_end; + } + + if (phdr->sig_blk_offset != 0) { + uint16_t len = phdr->sig_blk_hdr.length; + + if (phdr->sig_blk_offset + len > max_offset) + max_offset = phdr->sig_blk_offset + len; + } + + return max_offset; +} + +static int search_app_container(struct flash_header_v3 *container_hdrs, int num_cntrs, int ifd, + struct flash_header_v3 *app_container_hdr) +{ + int off[MAX_NUM_OF_CONTAINER]; + int end = 0, last = 0; + int img_array_entries = 0; + ssize_t rd_err; + off_t err; + int i; + + off[0] = 0; + + for (i = 0; i < num_cntrs; i++) { + end = get_container_size(&container_hdrs[i]); + if (end + off[i] > last) + last = end + off[i]; + + if ((i + 1) < num_cntrs) + off[i + 1] = off[i] + ALIGN(container_hdrs[i].length, CONTAINER_ALIGNMENT); + } + + /* Check app container tag at each 1KB beginning until 16KB */ + last = ALIGN(last, 0x400); + for (i = 0; i < 16; i++) { + last = last + (i * 0x400); + err = lseek(ifd, last, SEEK_SET); + if (err < 0) + break; + + rd_err = read(ifd, (void *)app_container_hdr, 16); + if (rd_err < 0) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + + /* check that the current container has a valid tag */ + if (app_container_hdr->tag != IVT_HEADER_TAG_B0) + continue; + + if (app_container_hdr->num_images > MAX_NUM_IMGS) { + fprintf(stderr, "This container includes %d images, beyond max 8 images\n", + app_container_hdr->num_images); + exit(EXIT_FAILURE); + } + + /* compute the size of the image array */ + img_array_entries = app_container_hdr->num_images * sizeof(struct boot_img); + + /* read in the full image array */ + rd_err = read(ifd, (void *)&app_container_hdr->img, img_array_entries); + if (rd_err < 0) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + + /* read in signature block header */ + if (app_container_hdr->sig_blk_offset != 0) { + lseek(ifd, last + app_container_hdr->sig_blk_offset, SEEK_SET); + rd_err = read(ifd, (void *)&app_container_hdr->sig_blk_hdr, sizeof(struct sig_blk_hdr)); + if (rd_err == -1) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + } + + return last; + } + + return 0; +} + +static int extract_container_images(struct flash_header_v3 *container_hdr, char *ifname, int num_cntrs, + int ifd, soc_type_t soc, int app_cntr_off) +{ + uint32_t img_offset = 0; /* image offset from container header */ + uint32_t img_size = 0; /* image size */ + uint32_t file_off = 0; /* current offset within container binary */ + const uint32_t pad = 0; + int ofd = 0; + int ret = 0; + uint32_t seco_off = 0; + char dd_cmd[512]; /* dd cmd to extract each image from container binary */ + struct stat buf; + FILE *f_ptr = NULL; /* file pointer to the dd process */ + char *mem_ptr; /* pointer to input container in memory */ + int i, j; + + printf("Extracting container images...\n"); + + /* create output directory if it does not exist */ + if (stat("extracted_imgs", &buf) == -1) + mkdir("extracted_imgs", S_IRWXU|S_IRWXG|S_IRWXO); + + /* open container binary and map to memory */ + fstat(ifd, &buf); + mem_ptr = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, ifd, 0); + + for (i = 0; i < num_cntrs; i++) { + for (j = 0; j < container_hdr->num_images; j++) { + + /* first get the image offset and size from the container header */ + img_offset = container_hdr->img[j].offset; + img_size = container_hdr->img[j].size; + + if (!img_size) { + /* check for images with zero size (DDR Init) */ + continue; + } else if (app_cntr_off > 0) { + sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/app_container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc", + ifname, i+1, j+1, app_cntr_off+img_offset, img_size); + printf("APP Container %d Image %d -> extracted_imgs/app_container%d_img%d.bin\n", i+1, j+1, i+1, j+1); + + } else if ((i == 0) && (soc != DXL)) { /* first container is always SECO FW */ + int k; + + /* open output file */ + ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO); + + /* first copy container header to output image */ + ret = write(ofd, (void *)mem_ptr, 1024); + if (ret < 0) + fprintf(stderr, "Error writing to output file\n"); + + + /* next, pad the output with zeros until the start of the image */ + for (k = 0; k < (img_offset-CONTAINER_ALIGNMENT)/4; k++) + ret = write(ofd, (void *)&pad, 4); + + /* now write the fw image to the output file */ + ret = write(ofd, (void *)(mem_ptr+img_offset), img_size); + if (ret < 0) + fprintf(stderr, "Error writing to output file\n"); + + /* close output file and unmap input file */ + close(ofd); + + printf("Container %d Image %d -> extracted_imgs/ahab-container.img\n", i+1, j+1); + + } else if ((i < 2 ) && (soc == DXL)) { /* Second Container is Always V2X for DXL */ + if (i == 0) { + /* open output file */ + ofd = open("extracted_imgs/ahab-container.img", O_CREAT|O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO); + + /* first copy container header to output image */ + ret = write(ofd, (void *)mem_ptr, 0x400); + if (ret < 0) + fprintf(stderr, "Error writing to output file1\n"); + + /* For DXL go to next container to copy header */ + seco_off = img_offset; + continue; + } else if (i == 1 && j == 0) { + int k; + + /* copy v2x container header and seco fw */ + ret = write(ofd,(void *) mem_ptr + file_off, container_hdr->length); + if (ret < 0) + fprintf(stderr, "Error writing to output file2\n"); + + + /* next, pad the output with zeros until the start of SECO image */ + for (k = 0; k < (seco_off - (file_off + container_hdr->length)) / 4; k++) + ret = write(ofd, (void *)&pad, 4); + + /* now write the SECO fw image to the output file */ + ret = write(ofd, (void *)(mem_ptr+seco_off), file_off + img_offset - seco_off); + if (ret < 0) + fprintf(stderr, "Error writing to output file3: %x\n",ret); + } + + /* now write the next image to the output file */ + ret = write(ofd, (void *)(mem_ptr + file_off + img_offset), img_size); + if (ret < 0) + fprintf(stderr, "Error writing to output file4: %x\n",ret); + + /* Iterate through V2X container for other images */ + if (j < (container_hdr->num_images - 1)) + continue; + + /* close output file and unmap input file */ + close(ofd); + + + printf("Container %d Image %d -> extracted_imgs/v2x-container.img\n", i+1, j+1); + + } else { + sprintf(dd_cmd, "dd status=none if=%s of=extracted_imgs/container%d_img%d.bin ibs=1 skip=%d count=%d conv=notrunc", + ifname, i+1, j+1, file_off+img_offset, img_size); + printf("Container %d Image %d -> extracted_imgs/container%d_img%d.bin\n", i+1, j+1, i+1, j+1); + } + + /* run dd command to extract current image from container */ + fprintf(stderr, "FOOO: %s\n", dd_cmd); + f_ptr = popen(dd_cmd, "r"); + if (f_ptr == NULL) { + fprintf(stderr, "Failed to extract image\n"); + exit(EXIT_FAILURE); + } + + /* close the pipe */ + pclose(f_ptr); + } + + file_off += ALIGN(container_hdr->length, CONTAINER_ALIGNMENT); + container_hdr++; + } + + munmap((void *)mem_ptr, buf.st_size); + printf("Done\n\n"); + return 0; +} + +static int parse_container_hdrs_qx_qm_b0(char *ifname, bool extract, soc_type_t soc, off_t file_off) +{ + int ifd; /* container file descriptor */ + int max_containers = (soc == DXL) ? 3 : 2; + int cntr_num = 0; /* number of containers in binary */ + int img_array_entries = 0; /* number of images in container */ + ssize_t rd_err; + struct flash_header_v3 container_headers[MAX_NUM_OF_CONTAINER]; + struct flash_header_v3 app_container_header; + int app_cntr_off; + + /* initialize region of memory where flash header will be stored */ + memset((void *)container_headers, 0, sizeof(container_headers)); + + /* open container binary */ + ifd = open(ifname, O_RDONLY|O_BINARY); + + if (file_off) /* inital offset within container binary */ + lseek(ifd, file_off, SEEK_SET); + + while (cntr_num < max_containers) { + + /* read in next container header up to the image array */ + rd_err = read(ifd, (void *)&container_headers[cntr_num], 16); + if (rd_err == -1) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + + /* check that the current container has a valid tag */ + if (container_headers[cntr_num].tag != IVT_HEADER_TAG_B0) + break; + + if (container_headers[cntr_num].num_images > MAX_NUM_IMGS) { + fprintf(stderr, "This container includes %d images, beyond max 8 images\n", + container_headers[cntr_num].num_images); + exit(EXIT_FAILURE); + } + + /* compute the size of the image array */ + img_array_entries = container_headers[cntr_num].num_images * sizeof(struct boot_img); + + /* read in the full image array */ + rd_err = read(ifd, (void *)&container_headers[cntr_num].img, img_array_entries); + if (rd_err == -1) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + + if (container_headers[cntr_num].sig_blk_offset != 0) { + /* read in signature block header */ + lseek(ifd, file_off + container_headers[cntr_num].sig_blk_offset, SEEK_SET); + rd_err = read(ifd, (void *)&container_headers[cntr_num].sig_blk_hdr, sizeof(struct sig_blk_hdr)); + if (rd_err == -1) { + fprintf(stderr, "Error reading from input binary\n"); + exit(EXIT_FAILURE); + } + } + + /* seek to next container in binary */ + file_off += ALIGN(container_headers[cntr_num].length, CONTAINER_ALIGNMENT); + lseek(ifd, file_off, SEEK_SET); + + /* increment current container count */ + cntr_num++; + } + + + print_container_hdr_fields(container_headers, cntr_num, soc, false); + + if (extract) + extract_container_images(container_headers, ifname, cntr_num, ifd, soc, 0); + + app_cntr_off = search_app_container(container_headers, cntr_num, ifd, &app_container_header); + + if (app_cntr_off > 0) { + print_container_hdr_fields(&app_container_header, 1, soc, true); + if (extract) + extract_container_images(&app_container_header, ifname, 1, ifd, soc, app_cntr_off); + } + + close(ifd); + + return 0; + +} + +#define IMG_STACK_SIZE 32 /* max of 32 images for commandline images */ + +/* + * Read commandline parameters and construct the header in order + * + * This will then construct the image according to the header and + * + * parameters passed in + * + */ +int main(int argc, char **argv) +{ + int c; + char *ofname = NULL; + char *ifname = NULL; + bool output = false; + bool dcd_skip = false; + bool emmc_fastboot = false; + bool extract = false; + bool parse = false; + + int container = -1; + image_t param_stack[IMG_STACK_SIZE];/* stack of input images */ + int p_idx = 0;/* param index counter */ + off_t file_off = 0; + + uint32_t ivt_offset = IVT_OFFSET_SD; + uint32_t sector_size = 0x400; /* default sector size */ + soc_type_t soc = NONE; /* Initially No SOC defined */ + + uint8_t fuse_version = 0; + uint16_t sw_version = 0; + char *images_hash = NULL; + + static struct option long_options[] = { + {"scfw", required_argument, NULL, 'f'}, + {"seco", required_argument, NULL, 'O'}, + {"m4", required_argument, NULL, 'm'}, + {"ap", required_argument, NULL, 'a'}, + {"dcd", required_argument, NULL, 'd'}, + {"out", required_argument, NULL, 'o'}, + {"flags", required_argument, NULL, 'l'}, + {"scd", required_argument, NULL, 'x'}, + {"csf", required_argument, NULL, 'z'}, + {"dev", required_argument, NULL, 'e'}, + {"soc", required_argument, NULL, 's'}, + {"dummy",required_argument, NULL, 'y'}, + {"container", no_argument, NULL, 'c'}, + {"partition", required_argument, NULL, 'p'}, + {"append", no_argument, NULL, 'A'}, + {"data", required_argument, NULL, 'D'}, + {"fileoff", required_argument, NULL, 'P'}, + {"msg_blk", required_argument, NULL, 'M'}, + {"fuse_version", required_argument, NULL, 'u'}, + {"sw_version", required_argument, NULL, 'v'}, + {"images_hash", required_argument, NULL, 'h'}, + {"extract", required_argument, NULL, 'X'}, + {"parse", required_argument, NULL, 'R'}, + {"sentinel", required_argument, NULL, 'i'}, + {"upower", required_argument, NULL, 'w'}, + {"fcb", required_argument, NULL, 'b'}, + {"padding", required_argument, NULL, 'G'}, + {"pblsize", required_argument, NULL, 0x1000}, + {NULL, 0, NULL, 0} + }; + + /* scan in parameters in order */ + while (1) { + /* getopt_long stores the option index here. */ + int option_index = 0; + + c = getopt_long_only (argc, argv, ":f:m:a:d:o:l:x:z:e:p:cu:v:h:i:w:", + long_options, &option_index); + + /* Detect the end of the options. */ + if (c == -1) + break; + + switch (c) { + case 0: + fprintf(stderr, "option %s", long_options[option_index].name); + if (optarg) + fprintf(stderr, " with arg %s", optarg); + fprintf(stderr, "\n"); + break; + case 'A': + param_stack[p_idx].option = APPEND; + param_stack[p_idx++].filename = argv[optind++]; + break; + case 'p': + printf("PARTITION:\t%s\n", optarg); + param_stack[p_idx].option = PARTITION; + param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0); + break; + case 's': + if (!strncmp(optarg, "QX", 2)) { + soc = QX; + } else if (!strncmp(optarg, "QM", 2)) { + soc = QM; + } else if (!strncmp(optarg, "DXL", 3)) { + soc = DXL; + } else if (!strncmp(optarg, "ULP", 3)) { + soc = ULP; + } else if (!strncmp(optarg, "IMX9", 4)) { + soc = IMX9; + } else { + printf("unrecognized SOC: %s \n",optarg); + exit(EXIT_FAILURE); + } + printf("SOC: %s \n",optarg); + break; + case 'b': + printf("FCB:\t%s\n", optarg); + param_stack[p_idx].option = FCB; + param_stack[p_idx].filename = optarg; + if (optind < argc && *argv[optind] != '-') { + param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0); + p_idx++; + } else { + fprintf(stderr, "\n-fcb option require Two arguments: filename, load address in hex\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'i': + printf("SENTINEL:\t%s\n", optarg); + param_stack[p_idx].option = SENTINEL; + param_stack[p_idx++].filename = optarg; + break; + case 'w': + printf("UPOWER:\t%s\n", optarg); + param_stack[p_idx].option = UPOWER; + param_stack[p_idx++].filename = optarg; + break; + case 'f': + printf("SCFW:\t%s\n", optarg); + param_stack[p_idx].option = SCFW; + param_stack[p_idx++].filename = optarg; + break; + case 'O': + printf("SECO:\t%s\n", optarg); + param_stack[p_idx].option = SECO; + param_stack[p_idx++].filename = optarg; + break; + case 'd': + printf("DCD:\t%s\n", optarg); + if (soc == DXL) { + if (!strncmp(optarg, "skip", 4)) { + dcd_skip = true; + } else { + fprintf(stderr, "\n-dcd option requires argument skip\n\n"); + exit(EXIT_FAILURE); + } + } else if ((soc == ULP) || (soc == IMX9)) { + fprintf(stderr, "\n-dcd option is not used on ULP and IMX9\n\n"); + exit(EXIT_FAILURE); + } else { + param_stack[p_idx].option = DCD; + param_stack[p_idx].filename = optarg; + p_idx++; + } + break; + case 'D': + if ((soc == DXL) || (soc == ULP) || (soc == IMX9)) { + printf("Data:\t%s", optarg); + param_stack[p_idx].option = DATA; + param_stack[p_idx].filename = optarg; + if ((optind < argc && *argv[optind] != '-') && + (optind+1 < argc && *argv[optind+1] != '-' )) { + if (!strncmp(argv[optind], "a53", 3)) + param_stack[p_idx].ext = CORE_CA53; + else if (!strncmp(argv[optind], "a55", 3)) + param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */ + else if (!strncmp(argv[optind], "a35", 3)) + param_stack[p_idx].ext = CORE_CA35; + else if (!strncmp(argv[optind], "a72", 3)) + param_stack[p_idx].ext = CORE_CA72; + else if (!strncmp(argv[optind], "m4_1", 4)) + param_stack[p_idx].ext = CORE_CM4_1; + else if (!strncmp(argv[optind], "m4", 2)) + param_stack[p_idx].ext = CORE_CM4_0; + else { + fprintf(stderr, "ERROR: incorrect core ID for --data option: %s\n", argv[optind]); + exit(EXIT_FAILURE); + } + printf("\tcore: %s\n", argv[optind++]); + param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0); + } else { + fprintf(stderr, "\n-data option require THREE arguments: filename, core: a55/a35/a53/a72/m4_0/m4_1, load address in hex\n\n"); + exit(EXIT_FAILURE); + } + p_idx++; + } else { + fprintf(stderr, "\n-data option is only used with -rev B0, or DXL or ULP or IMX9 soc.\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'm': + printf("CM4:\t%s", optarg); + param_stack[p_idx].option = M4; + param_stack[p_idx].filename = optarg; + if ((optind < argc && *argv[optind] != '-') && + (optind + 1 < argc &&*argv[optind+1] != '-' )) { + param_stack[p_idx].ext = strtol(argv[optind++], NULL, 0); + param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0); + param_stack[p_idx].dst = 0; + printf("\tcore: %" PRIi64, param_stack[p_idx].ext); + printf(" entry addr: 0x%08" PRIx64 , param_stack[p_idx].entry); + if (optind < argc && *argv[optind] != '-') { + param_stack[p_idx].dst = (uint32_t) strtoll(argv[optind++], NULL, 0); + printf(" load addr: 0x%08" PRIx64 , param_stack[p_idx].dst); + } + printf("\n"); + p_idx++; + } else { + fprintf(stderr, "\n-m4 option require FOUR arguments: filename, core: 0/1, entry address in hex, load address in hex(optional)\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'a': + printf("AP:\t%s", optarg); + param_stack[p_idx].option = AP; + param_stack[p_idx].filename = optarg; + if ((optind < argc && *argv[optind] != '-') && + (optind + 1 < argc &&*argv[optind+1] != '-' )) { + if (!strncmp(argv[optind], "a53", 3)) + param_stack[p_idx].ext = CORE_CA53; + else if (!strncmp(argv[optind], "a55", 3)) + param_stack[p_idx].ext = CORE_CA35; /* fake id for a55 */ + else if (!strncmp(argv[optind], "a35", 3)) + param_stack[p_idx].ext = CORE_CA35; + else if (!strncmp(argv[optind], "a72", 3)) + param_stack[p_idx].ext = CORE_CA72; + else { + fprintf(stderr, "ERROR: AP Core not found %s\n", argv[optind+2]); + exit(EXIT_FAILURE); + } + printf("\tcore: %s", argv[optind++]); + + param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0); + param_stack[p_idx].mu = SC_R_MU_0A; + param_stack[p_idx].part = 1; + + if (optind < argc && *argv[optind] != '-') { + if (!strncmp(argv[optind], "mu0", 3)) + param_stack[p_idx].mu = SC_R_MU_0A; + else if (!strncmp(argv[optind], "mu3", 3)) + param_stack[p_idx].mu = SC_R_MU_3A; + else { + fprintf(stderr, "ERROR: MU number %s not found\n", argv[optind]); + exit(EXIT_FAILURE); + } + printf("\tMU: %s ", argv[optind++]); + } + if (optind < argc && *argv[optind] != '-') { + if (!strncmp(argv[optind], "pt", 2) && + (argv[optind][2] > '0') && + (argv[optind][2] != '2') && + (argv[optind][2] <= '9')) { + char str[2]; + str[0] = argv[optind][2]; + str[1] = '\0'; + param_stack[p_idx].part = strtoll(str, NULL, 0); + } else { + fprintf(stderr, "ERROR: partition number %s not found\n", argv[optind]); + exit(EXIT_FAILURE); + } + printf("\tPartition: %s ", argv[optind++]); + } + printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry); + } else { + fprintf(stderr, "\n-ap option require THREE arguments: filename, a35/a53/a72, start address in hex\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'l': + printf("FLAG:\t%s\n", optarg); + param_stack[p_idx].option = FLAG; + param_stack[p_idx++].entry = (uint32_t) strtoll(optarg, NULL, 0); + break; + case 'o': + printf("Output:\t%s\n", optarg); + ofname = optarg; + output = true; + break; + case 'x': + printf("SCD:\t%s\n", optarg); + param_stack[p_idx].option = SCD; + param_stack[p_idx++].filename = optarg; + break; + case 'z': + printf("CSF:\t%s\n", optarg); + param_stack[p_idx].option = CSF; + param_stack[p_idx++].filename = optarg; + break; + case 'e': + printf("BOOT DEVICE:\t%s\n", optarg); + if (!strcmp(optarg, "flexspi")) { + ivt_offset = IVT_OFFSET_FLEXSPI; + } else if (!strcmp(optarg, "sd")) { + ivt_offset = IVT_OFFSET_SD; + } else if (!strcmp(optarg, "nand")) { + sector_size = 0x8000;/* sector size for NAND */ + if ((soc == DXL) || (soc == IMX9)) { + if (optind < argc && *argv[optind] != '-') { + if (!strcmp(argv[optind], "4K")) { + sector_size = 0x1000; + } else if (!strcmp(argv[optind], "8K")) { + sector_size = 0x2000; + } else if (!strcmp(argv[optind], "16K")) { + sector_size = 0x4000; + } else + printf("\nwrong nand page size:\r\n 4K\r\n8K\r\n16K\n\n"); + } else { + printf("\n-dev nand requires the page size:\r\n 4K\r\n8K\r\n16K\n\n"); + } + } + } else if (!strcmp(optarg, "emmc_fast")) { + ivt_offset = IVT_OFFSET_EMMC; + emmc_fastboot = true;/* emmc boot */ + } else { + printf("\n-dev option, Valid boot devices are:\r\n sd\r\nflexspi\r\nnand\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'c': + printf("New Container: \t%d\n",++container); + param_stack[p_idx++].option = NEW_CONTAINER; + break; + case ':': + fprintf(stderr, "option %c missing arguments\n", optopt); + exit(EXIT_FAILURE); + break; + case 'P': + printf("FILEOFF:\t%s\n", optarg); + param_stack[p_idx].option = FILEOFF; + param_stack[p_idx++].dst = (uint64_t) strtoll(optarg, NULL, 0); + break; + case 'M': + printf("MSG BLOCK:\t%s", optarg); + param_stack[p_idx].option = MSG_BLOCK; + param_stack[p_idx].filename = optarg; + if ((optind < argc && *argv[optind] != '-') && + (optind+1 < argc &&*argv[optind + 1] != '-' )) { + if (!strncmp(argv[optind], "fuse", 4)) + param_stack[p_idx].ext = SC_R_OTP; + else if (!strncmp(argv[optind], "debug", 5)) + param_stack[p_idx].ext = SC_R_DEBUG; + else if (!strncmp(argv[optind], "field", 5)) + param_stack[p_idx].ext = SC_R_ROM_0; + else if (!strncmp(argv[optind], "zero", 4)) + param_stack[p_idx].ext = SC_R_PWM_0; + else if (!strncmp(argv[optind], "patch", 5)) + param_stack[p_idx].ext = SC_R_SNVS; + else if (!strncmp(argv[optind], "degrade", 7)) + param_stack[p_idx].ext = SC_R_DC_0; + else { + fprintf(stderr, "ERROR: MSG type not found %s\n", argv[optind+2]); + exit(EXIT_FAILURE); + } + printf("\ttype: %s", argv[optind++]); + + param_stack[p_idx].entry = (uint32_t) strtoll(argv[optind++], NULL, 0); + + printf(" addr: 0x%08" PRIx64 "\n", param_stack[p_idx++].entry); + } else { + fprintf(stderr, "\nmsg block option require THREE arguments: filename, debug/fuse/field/patch, start address in hex\n\n"); + exit(EXIT_FAILURE); + } + break; + case 'u': + fuse_version = (uint8_t) (strtoll(optarg, NULL, 0) & 0xFF); + break; + case 'v': + sw_version = (uint16_t) (strtoll(optarg, NULL, 0) & 0xFFFF); + break; + case 'h': + images_hash = optarg; + break; + case 'X': + printf("Input container binary to be deconstructed: %s\n", optarg); + ifname = optarg; + extract = true; + break; + case 'R': + printf("Input container binary to be parsed: %s\n", optarg); + ifname = optarg; + parse = true; + break; + case 'y': + printf("Dummy V2X image at:\t%s\n", optarg); + param_stack[p_idx].option = DUMMY_V2X; + param_stack[p_idx++].entry = (uint64_t) strtoll(optarg, NULL, 0); + break; + case 'G': + printf("Padding length:\t%s bytes\n", optarg); + file_off = atoi(optarg); + break; + case 0x1000: + pblsize = atoi(optarg); + break; + case '?': + default: + /* invalid option */ + fprintf(stderr, "option '%c' is invalid: ignored\n", + optopt); + exit(EXIT_FAILURE); + } + } + + if (!parse) { + printf("CONTAINER FUSE VERSION:\t0x%02x\n", fuse_version); + printf("CONTAINER SW VERSION:\t0x%04x\n", sw_version); + } + + param_stack[p_idx].option = NO_IMG; /* null terminate the img stack */ + + if (soc == NONE) { + fprintf(stderr, " No SOC defined"); + exit(EXIT_FAILURE); + } + + if (parse || extract) { + parse_container_hdrs_qx_qm_b0(ifname, extract, soc, file_off); + return 0; + } + + if (container < 0) { + /* check to make sure there is at least 1 container defined */ + fprintf(stderr, " No Container defined"); + exit(EXIT_FAILURE); + } + + if (!output) { + fprintf(stderr, "mandatory args scfw and output file name missing! abort\n"); + exit(EXIT_FAILURE); + } + + build_container_qx_qm_b0(soc, sector_size, ivt_offset, ofname, emmc_fastboot, + (image_t *) param_stack, dcd_skip, fuse_version, + sw_version, images_hash); + + printf("DONE.\n"); + printf("Note: Please copy image to offset: IVT_OFFSET + IMAGE_OFFSET\n"); + + return 0; +} + diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index f9d052752d..370c54c983 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -1006,6 +1006,7 @@ static int image_create_config_parse_oneline(char *line, char *configpath) { char *keyword, *saveptr; + int ret; keyword = strtok_r(line, " ", &saveptr); if (!strcmp(keyword, "VERSION")) { @@ -1056,10 +1057,16 @@ static int image_create_config_parse_oneline(char *line, int argi = 0; el->type = IMAGE_CFG_BINARY; - if (*value == '/') + if (*value == '/') { el->binary.file = strdup(value); - else - asprintf(&el->binary.file, "%s/%s", configpath, value); + } else { + ret = asprintf(&el->binary.file, "%s/%s", configpath, value); + if (ret < 0) { + fprintf(stderr, "Cannot allocate memory\n"); + return -1; + } + } + while (1) { value = strtok_r(NULL, " ", &saveptr); if (!value) diff --git a/scripts/kwboot.c b/scripts/kwboot.c index 1cbb456935..2a4f6bc5fc 100644 --- a/scripts/kwboot.c +++ b/scripts/kwboot.c @@ -22,6 +22,7 @@ #include <termios.h> #include <sys/mman.h> #include <sys/stat.h> +#include <sys/select.h> /* * Marvell BootROM UART Sensing diff --git a/scripts/list-defconfigs.sh b/scripts/list-defconfigs.sh new file mode 100755 index 0000000000..eeae9fbfdc --- /dev/null +++ b/scripts/list-defconfigs.sh @@ -0,0 +1,15 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only +# +# Output json formatted defconfig list for Github Action consumption + +ARCH=${@:-*} + +cd arch + +archs=$(for arch in $ARCH; do + ls -1 $arch/configs | xargs -i printf '{ "arch": "%s", "config": "%s" }\n' \ + "$arch" "{}" | paste -sd ',' - +done | paste -sd ',' -) + +echo '{ "include" : '" [ $archs ] }" diff --git a/scripts/mkimage.c b/scripts/mkimage.c deleted file mode 100644 index a76c061aee..0000000000 --- a/scripts/mkimage.c +++ /dev/null @@ -1,776 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-FileCopyrightText: 2008 Semihalf -// SPDX-FileCopyrightText: 2000-2004 DENX Software Engineering (Wolfgang Denk <wd@denx.de>) - -#include <sys/stat.h> -#include <time.h> -#include <unistd.h> - -#include "compiler.h" - -#include "../include/image.h" -#include "../common/image.c" - -char *cmdname; - -#include "../crypto/crc32.c" - -//extern unsigned long crc32 (unsigned long crc, const char *buf, unsigned int len); - -static void copy_file (int, const char *, int); -static void usage (void); -static int get_table_entry (table_entry_t *, char *, char *); -static int get_arch(char *); -static int get_comp(char *); -static int get_os (char *); -static int get_type(char *); - - -char *datafile; -char *imagefile; - -int dflag = 0; -int eflag = 0; -int lflag = 0; -int vflag = 0; -int xflag = 0; -int opt_os = IH_OS_LINUX; -int opt_arch = IH_ARCH_PPC; -int opt_type = IH_TYPE_KERNEL; -int opt_comp = IH_COMP_GZIP; - -image_header_t header; -image_header_t *hdr = &header; - -static inline uint32_t image_get_header_size(void) -{ - return sizeof(image_header_t); -} - -#define image_get_hdr_u32(x) \ -static inline uint32_t image_get_##x(const image_header_t *hdr) \ -{ \ - return uimage_to_cpu(hdr->ih_##x); \ -} - -image_get_hdr_u32(magic); /* image_get_magic */ -image_get_hdr_u32(hcrc); /* image_get_hcrc */ -image_get_hdr_u32(time); /* image_get_time */ -image_get_hdr_u32(size); /* image_get_size */ -image_get_hdr_u32(load); /* image_get_load */ -image_get_hdr_u32(ep); /* image_get_ep */ -image_get_hdr_u32(dcrc); /* image_get_dcrc */ - -#define image_get_hdr_u8(x) \ -static inline uint8_t image_get_##x(const image_header_t *hdr) \ -{ \ - return hdr->ih_##x; \ -} -image_get_hdr_u8(os); /* image_get_os */ -image_get_hdr_u8(arch); /* image_get_arch */ -image_get_hdr_u8(type); /* image_get_type */ -image_get_hdr_u8(comp); /* image_get_comp */ - -static inline char *image_get_name(const image_header_t *hdr) -{ - return (char*)hdr->ih_name; -} - -static inline uint32_t image_get_data_size(const image_header_t *hdr) -{ - return image_get_size(hdr); -} - -/** - * image_get_data - get image payload start address - * @hdr: image header - * - * image_get_data() returns address of the image payload. For single - * component images it is image data start. For multi component - * images it points to the null terminated table of sub-images sizes. - * - * returns: - * image payload data start address - */ -static inline ulong image_get_data(const image_header_t *hdr) -{ - return ((ulong)hdr + image_get_header_size()); -} - -static inline uint32_t image_get_image_size(const image_header_t *hdr) -{ - return (image_get_size(hdr) + image_get_header_size()); -} - -static inline ulong image_get_image_end(const image_header_t *hdr) -{ - return ((ulong)hdr + image_get_image_size(hdr)); -} - -#define image_set_hdr_u32(x) \ -static inline void image_set_##x(image_header_t *hdr, uint32_t val) \ -{ \ - hdr->ih_##x = cpu_to_uimage(val); \ -} - -image_set_hdr_u32(magic); /* image_set_magic */ -image_set_hdr_u32(hcrc); /* image_set_hcrc */ -image_set_hdr_u32(time); /* image_set_time */ -image_set_hdr_u32(size); /* image_set_size */ -image_set_hdr_u32(load); /* image_set_load */ -image_set_hdr_u32(ep); /* image_set_ep */ -image_set_hdr_u32(dcrc); /* image_set_dcrc */ - -#define image_set_hdr_u8(x) \ -static inline void image_set_##x(image_header_t *hdr, uint8_t val) \ -{ \ - hdr->ih_##x = val; \ -} - -image_set_hdr_u8(os); /* image_set_os */ -image_set_hdr_u8(arch); /* image_set_arch */ -image_set_hdr_u8(type); /* image_set_type */ -image_set_hdr_u8(comp); /* image_set_comp */ - -static inline void image_set_name(image_header_t *hdr, const char *name) -{ - strncpy(image_get_name(hdr), name, IH_NMLEN - 1); -} - -/** - * image_multi_count - get component (sub-image) count - * @hdr: pointer to the header of the multi component image - * - * image_multi_count() returns number of components in a multi - * component image. - * - * Note: no checking of the image type is done, caller must pass - * a valid multi component image. - * - * returns: - * number of components - */ -static ulong image_multi_count(void *data) -{ - ulong i, count = 0; - uint32_t *size; - - /* get start of the image payload, which in case of multi - * component images that points to a table of component sizes */ - size = (uint32_t *)data; - - /* count non empty slots */ - for (i = 0; size[i]; ++i) - count++; - - return count; -} - -/** - * image_multi_getimg - get component data address and size - * @hdr: pointer to the header of the multi component image - * @idx: index of the requested component - * @data: pointer to a ulong variable, will hold component data address - * @len: pointer to a ulong variable, will hold component size - * - * image_multi_getimg() returns size and data address for the requested - * component in a multi component image. - * - * Note: no checking of the image type is done, caller must pass - * a valid multi component image. - * - * returns: - * data address and size of the component, if idx is valid - * 0 in data and len, if idx is out of range - */ -static void image_multi_getimg(void *data, ulong idx, - ulong *img_data, ulong *len) -{ - int i; - uint32_t *size; - ulong offset, count, tmp_img_data; - - /* get number of component */ - count = image_multi_count(data); - - /* get start of the image payload, which in case of multi - * component images that points to a table of component sizes */ - size = (uint32_t *)data; - - /* get address of the proper component data start, which means - * skipping sizes table (add 1 for last, null entry) */ - tmp_img_data = (ulong)data + (count + 1) * sizeof (uint32_t); - - if (idx < count) { - *len = uimage_to_cpu(size[idx]); - offset = 0; - - /* go over all indices preceding requested component idx */ - for (i = 0; i < idx; i++) { - /* add up i-th component size, rounding up to 4 bytes */ - offset += (uimage_to_cpu(size[i]) + 3) & ~3 ; - } - - /* calculate idx-th component data address */ - *img_data = tmp_img_data + offset; - } else { - *len = 0; - *img_data = 0; - } -} - -static void image_print_type(const image_header_t *hdr) -{ - const char *os, *arch, *type, *comp; - - os = image_get_os_name(image_get_os(hdr)); - arch = image_get_arch_name(image_get_arch(hdr)); - type = image_get_type_name(image_get_type(hdr)); - comp = image_get_comp_name(image_get_comp(hdr)); - - printf ("%s %s %s (%s)\n", arch, os, type, comp); -} - -static void image_print_time(time_t timestamp) -{ - printf("%s", ctime(×tamp)); -} - -static void image_print_size(uint32_t size) -{ - printf("%d Bytes = %.2f kB = %.2f MB\n", - size, (double)size / 1.024e3, - (double)size / 1.048576e6); -} - -static void image_print_contents(const image_header_t *hdr, void *data) -{ - int type; - - printf("Image Name: %.*s\n", IH_NMLEN, image_get_name(hdr)); - printf("Created: "); - image_print_time((time_t)image_get_time(hdr)); - printf ("Image Type: "); - image_print_type(hdr); - printf ("Data Size: "); - image_print_size(image_get_data_size(hdr)); - printf ("Load Address: %08x\n", image_get_load(hdr)); - printf ("Entry Point: %08x\n", image_get_ep(hdr)); - - type = image_get_type(hdr); - if (data && (type == IH_TYPE_MULTI || type == IH_TYPE_SCRIPT)) { - int i; - ulong img_data, len; - ulong count = image_multi_count(data); - - printf ("Contents:\n"); - for (i = 0; i < count; i++) { - image_multi_getimg(data, i, &img_data, &len); - - printf(" Image %d: ", i); - image_print_size(len); - - if (image_get_type(hdr) != IH_TYPE_SCRIPT && i > 0) { - /* - * the user may need to know offsets - * if planning to do something with - * multiple files - */ - printf(" Offset = 0x%08lx\n", img_data); - } - } - } -} - -int -main (int argc, char **argv) -{ - int ifd; - uint32_t checksum; - uint32_t addr; - uint32_t ep; - struct stat sbuf; - char *ptr; - char *name = ""; - - cmdname = *argv; - - addr = ep = 0; - - while (--argc > 0 && **++argv == '-') { - while (*++*argv) { - switch (**argv) { - case 'l': - lflag = 1; - break; - case 'A': - if ((--argc <= 0) || - (opt_arch = get_arch(*++argv)) < 0) - usage (); - goto NXTARG; - case 'C': - if ((--argc <= 0) || - (opt_comp = get_comp(*++argv)) < 0) - usage (); - goto NXTARG; - case 'O': - if ((--argc <= 0) || - (opt_os = get_os(*++argv)) < 0) - usage (); - goto NXTARG; - case 'T': - if ((--argc <= 0) || - (opt_type = get_type(*++argv)) < 0) - usage (); - goto NXTARG; - - case 'a': - if (--argc <= 0) - usage (); - addr = strtoul (*++argv, (char **)&ptr, 16); - if (*ptr) { - fprintf (stderr, - "%s: invalid load address %s\n", - cmdname, *argv); - exit (EXIT_FAILURE); - } - goto NXTARG; - case 'd': - if (--argc <= 0) - usage (); - datafile = *++argv; - dflag = 1; - goto NXTARG; - case 'e': - if (--argc <= 0) - usage (); - ep = strtoul (*++argv, (char **)&ptr, 16); - if (*ptr) { - fprintf (stderr, - "%s: invalid entry point %s\n", - cmdname, *argv); - exit (EXIT_FAILURE); - } - eflag = 1; - goto NXTARG; - case 'n': - if (--argc <= 0) - usage (); - name = *++argv; - goto NXTARG; - case 'v': - vflag++; - break; - case 'x': - xflag++; - break; - default: - usage (); - } - } -NXTARG: ; - } - - if ((argc != 1) || ((lflag ^ dflag) == 0)) - usage(); - - if (!eflag) { - ep = addr; - /* If XIP, entry point must be after the barebox header */ - if (xflag) - ep += sizeof(image_header_t); - } - - /* - * If XIP, ensure the entry point is equal to the load address plus - * the size of the barebox header. - */ - if (xflag) { - if (ep != addr + sizeof(image_header_t)) { - fprintf (stderr, - "%s: For XIP, the entry point must be the load addr + %lu\n", - cmdname, - (unsigned long)sizeof(image_header_t)); - exit (EXIT_FAILURE); - } - } - - imagefile = *argv; - - if (lflag) { - ifd = open(imagefile, O_RDONLY|O_BINARY); - } else { - ifd = open(imagefile, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666); - } - - if (ifd < 0) { - fprintf (stderr, "%s: Can't open %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if (lflag) { - int len; - char *data; - /* - * list header information of existing image - */ - if (fstat(ifd, &sbuf) < 0) { - fprintf (stderr, "%s: Can't stat %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { - fprintf (stderr, - "%s: Bad size: \"%s\" is no valid image\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - ptr = mmap(0, sbuf.st_size, - PROT_READ, MAP_SHARED, ifd, 0); - if ((caddr_t)ptr == (caddr_t)-1) { - fprintf (stderr, "%s: Can't read %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - /* - * create copy of header so that we can blank out the - * checksum field for checking - this can't be done - * on the PROT_READ mapped data. - */ - memcpy (hdr, ptr, sizeof(image_header_t)); - - if (image_get_magic(hdr) != IH_MAGIC) { - fprintf (stderr, - "%s: Bad Magic Number: \"%s\" is no valid image\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - data = (char *)hdr; - len = image_get_header_size(); - - checksum = image_get_hcrc(hdr); - image_set_hcrc(hdr, 0); /* clear for re-calculation */ - - if (crc32 (0, (unsigned char *)data, len) != checksum) { - fprintf (stderr, - "%s: ERROR: \"%s\" has bad header checksum!\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - data = (char *)(ptr + image_get_header_size()); - len = sbuf.st_size - image_get_header_size() ; - - if (crc32 (0, (unsigned char *)data, len) != image_get_dcrc(hdr)) { - fprintf (stderr, - "%s: ERROR: \"%s\" has corrupted data!\n", - cmdname, imagefile); - exit (EXIT_FAILURE); - } - - /* for multi-file images we need the data part, too */ - image_print_contents((image_header_t *)ptr, - (void*)image_get_data((image_header_t *)ptr)); - - (void) munmap((void *)ptr, sbuf.st_size); - (void) close (ifd); - - exit (EXIT_SUCCESS); - } - - /* - * Must be -w then: - * - * write dummy header, to be fixed later - */ - memset (hdr, 0, image_get_header_size()); - - if (write(ifd, hdr, image_get_header_size()) != image_get_header_size()) { - fprintf (stderr, "%s: Write error on %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if ((opt_type == IH_TYPE_MULTI) || - (opt_type == IH_TYPE_SCRIPT)) { - char *file = datafile; - uint32_t size; - - for (;;) { - char *sep = NULL; - - if (file) { - if ((sep = strchr(file, ':')) != NULL) { - *sep = '\0'; - } - - if (stat (file, &sbuf) < 0) { - fprintf (stderr, "%s: Can't stat %s: %s\n", - cmdname, file, strerror(errno)); - exit (EXIT_FAILURE); - } - size = htonl(sbuf.st_size); - } else { - size = 0; - } - - if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) { - fprintf (stderr, "%s: Write error on %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if (!file) { - break; - } - - if (sep) { - *sep = ':'; - file = sep + 1; - } else { - file = NULL; - } - } - - file = datafile; - - for (;;) { - char *sep = strchr(file, ':'); - if (sep) { - *sep = '\0'; - copy_file (ifd, file, 1); - *sep++ = ':'; - file = sep; - } else { - copy_file (ifd, file, 0); - break; - } - } - } else { - copy_file (ifd, datafile, 0); - } - - /* We're a bit of paranoid */ -#if defined(_POSIX_SYNCHRONIZED_IO) && \ - !defined(__sun__) && \ - !defined(__FreeBSD__) && \ - !defined(__OpenBSD__) && \ - !defined(__APPLE__) - (void) fdatasync (ifd); -#else - (void) fsync (ifd); -#endif - - if (fstat(ifd, &sbuf) < 0) { - fprintf (stderr, "%s: Can't stat %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - ptr = mmap(0, sbuf.st_size, - PROT_READ|PROT_WRITE, MAP_SHARED, ifd, 0); - if (ptr == MAP_FAILED) { - fprintf (stderr, "%s: Can't map %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - hdr = (image_header_t *)ptr; - - checksum = crc32 (0, - (unsigned char *)(ptr + image_get_header_size()), - sbuf.st_size - image_get_header_size() - ); - - /* Build new header */ - image_set_magic(hdr, IH_MAGIC); - image_set_time(hdr, sbuf.st_mtime); - image_set_size(hdr, sbuf.st_size - image_get_header_size()); - image_set_load(hdr, addr); - image_set_ep(hdr, ep); - image_set_dcrc(hdr, checksum); - image_set_os(hdr, opt_os); - image_set_arch(hdr, opt_arch); - image_set_type(hdr, opt_type); - image_set_comp(hdr, opt_comp); - - image_set_name(hdr, name); - - checksum = crc32(0,(unsigned char *)hdr, image_get_header_size()); - - image_set_hcrc(hdr, checksum); - - image_print_contents(hdr, (void*)image_get_data(hdr)); - - (void) munmap((void *)ptr, sbuf.st_size); - - /* We're a bit of paranoid */ -#if defined(_POSIX_SYNCHRONIZED_IO) && \ - !defined(__sun__) && \ - !defined(__FreeBSD__) && \ - !defined(__OpenBSD__) && \ - !defined(__APPLE__) - (void) fdatasync (ifd); -#else - (void) fsync (ifd); -#endif - - if (close(ifd)) { - fprintf (stderr, "%s: Write error on %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - exit (EXIT_SUCCESS); -} - -static void -copy_file (int ifd, const char *datafile, int pad) -{ - int dfd; - struct stat sbuf; - unsigned char *ptr; - int tail; - int zero = 0; - int offset = 0; - int size; - - if (vflag) { - fprintf (stderr, "Adding Image %s\n", datafile); - } - - if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 0) { - fprintf (stderr, "%s: Can't open %s: %s\n", - cmdname, datafile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if (fstat(dfd, &sbuf) < 0) { - fprintf (stderr, "%s: Can't stat %s: %s\n", - cmdname, datafile, strerror(errno)); - exit (EXIT_FAILURE); - } - - ptr = (unsigned char *)mmap(0, sbuf.st_size, - PROT_READ, MAP_SHARED, dfd, 0); - if (ptr == (unsigned char *)MAP_FAILED) { - fprintf (stderr, "%s: Can't read %s: %s\n", - cmdname, datafile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if (xflag) { - unsigned char *p = NULL; - /* - * XIP: do not append the image_header_t at the - * beginning of the file, but consume the space - * reserved for it. - */ - - if ((unsigned)sbuf.st_size < image_get_header_size()) { - fprintf (stderr, - "%s: Bad size: \"%s\" is too small for XIP\n", - cmdname, datafile); - exit (EXIT_FAILURE); - } - - for (p = ptr; p < ptr + image_get_header_size(); p++) { - if ( *p != 0xff ) { - fprintf (stderr, - "%s: Bad file: \"%s\" has invalid buffer for XIP\n", - cmdname, datafile); - exit (EXIT_FAILURE); - } - } - - offset = image_get_header_size(); - } - - size = sbuf.st_size - offset; - if (write(ifd, ptr + offset, size) != size) { - fprintf (stderr, "%s: Write error on %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - - if (pad && ((tail = size % 4) != 0)) { - - if (write(ifd, (char *)&zero, 4-tail) != 4-tail) { - fprintf (stderr, "%s: Write error on %s: %s\n", - cmdname, imagefile, strerror(errno)); - exit (EXIT_FAILURE); - } - } - - (void) munmap((void *)ptr, sbuf.st_size); - (void) close (dfd); -} - -void -usage () -{ - fprintf (stderr, "Usage: %s -l image\n" - " -l ==> list image header information\n" - " %s [-x] -A arch -O os -T type -C comp " - "-a addr -e ep -n name -d data_file[:data_file...] image\n", - cmdname, cmdname); - fprintf (stderr, " -A ==> set architecture to 'arch'\n" - " -O ==> set operating system to 'os'\n" - " -T ==> set image type to 'type'\n" - " -C ==> set compression type 'comp'\n" - " -a ==> set load address to 'addr' (hex)\n" - " -e ==> set entry point to 'ep' (hex)\n" - " -n ==> set image name to 'name'\n" - " -d ==> use image data from 'datafile'\n" - " -x ==> set XIP (execute in place)\n" - ); - exit (EXIT_FAILURE); -} - -static int get_arch(char *name) -{ - return (get_table_entry(arch_name, "CPU", name)); -} - - -static int get_comp(char *name) -{ - return (get_table_entry(comp_name, "Compression", name)); -} - - -static int get_os (char *name) -{ - return (get_table_entry(os_name, "OS", name)); -} - - -static int get_type(char *name) -{ - return (get_table_entry(type_name, "Image", name)); -} - -static int get_table_entry (table_entry_t *table, char *msg, char *name) -{ - table_entry_t *t; - int first = 1; - - for (t=table; t->id>=0; ++t) { - if (t->sname && strcasecmp(t->sname, name)==0) - return (t->id); - } - fprintf (stderr, "\nInvalid %s Type - valid names are", msg); - for (t=table; t->id>=0; ++t) { - if (t->sname == NULL) - continue; - fprintf (stderr, "%c %s", (first) ? ':' : ',', t->sname); - first = 0; - } - fprintf (stderr, "\n"); - return (-1); -} diff --git a/scripts/mxsimage.c b/scripts/mxsimage.c index d33c4c8a0a..cebbab25ad 100644 --- a/scripts/mxsimage.c +++ b/scripts/mxsimage.c @@ -15,6 +15,10 @@ #include <arpa/inet.h> #include <linux/kernel.h> +#include "common.h" +#include "common.c" +#include "../crypto/crc32.c" + #define SB_BLOCK_SIZE 16 static char *prepfile; @@ -376,38 +380,6 @@ struct sb_image_ctx { * JTAG/SPI2_EEPROM/SD_SSP0/SD_SSP1 */ -static uint32_t crc_table[256]; -static int crc_table_valid; - -static void make_crc_table(void) -{ - uint32_t mask; - int i, j; - uint32_t poly; /* polynomial exclusive-or pattern */ - - if (crc_table_valid) - return; - - /* - * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10 - * + x11 + x12 + x16 + x22 + x23 + x26 + x32. - */ - poly = 0x04c11db7; - - for (i = 0; i < 256; i++) { - mask = i << 24; - for (j = 0; j < 8; j++) { - if (mask & 0x80000000) - mask = (mask << 1) ^ poly; - else - mask <<= 1; - } - crc_table[i] = mask; - } - - crc_table_valid = 1; -} - /* * OpenSSL 1.1.0 and newer compatibility functions: * https://wiki.openssl.org/index.php/1.1_API_Changes @@ -441,18 +413,7 @@ int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) static uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len) { - uint32_t crc32_val; - int i; - - make_crc_table(); - - crc32_val = ~in_crc; - - for (i = 0; i < len; i++) - crc32_val = (crc32_val << 8) ^ - crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)]; - - return crc32_val; + return crc32_be(~in_crc, buf, len); } /* * AES libcrypto diff --git a/scripts/omap3-usb-loader.c b/scripts/omap3-usb-loader.c index a8d626c32f..38cdbfac93 100644 --- a/scripts/omap3-usb-loader.c +++ b/scripts/omap3-usb-loader.c @@ -19,10 +19,6 @@ #define PROG_NAME "OMAP Loader" #define VERSION "1.0.0" -#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) -#define OMAP_IS_BIG_ENDIAN -#endif - #include <unistd.h> /* for usleep and friends */ #include <getopt.h> #include <errno.h> @@ -46,15 +42,6 @@ #define OMAP_USB_BULK_OUT 0x01 #define OMAP_ASIC_ID_LEN 69 -#ifdef OMAP_IS_BIG_ENDIAN -#define cpu_to_le32(v) (((v & 0xff) << 24) | ((v & 0xff00) << 8) | \ - ((v & 0xff0000) >> 8) | ((v & 0xff000000) >> 24)) -#define le32_to_cpu(v) cpu_to_le32(v) -#else -#define cpu_to_le32(v) (v) -#define le32_to_cpu(v) (v) -#endif - /* * taken from x-loader/drivers/usb/usb.c * All credit to Martin Mueller @@ -343,7 +330,7 @@ static int transfer_first_stage(libusb_device_handle * handle, struct arg_state /* TODO determine buffer size based on endpoint */ buffer = calloc(bufsize, sizeof (unsigned char)); - filelen = cpu_to_le32(file->size); + filelen = file->size; data = file->data; dbuf = data; @@ -410,6 +397,8 @@ static int transfer_first_stage(libusb_device_handle * handle, struct arg_state goto fail; } + filelen = cpu_to_le32(filelen); + /* send the length of the first file (little endian) */ if (!omap_usb_write (handle, (unsigned char *) &filelen, sizeof (filelen))) { @@ -419,9 +408,9 @@ static int transfer_first_stage(libusb_device_handle * handle, struct arg_state } /* send the file! */ - if (!omap_usb_write(handle, data, filelen)) { + if (!omap_usb_write(handle, data, file->size)) { log_error("failed to send file \'%s\' (size %u)\n", - file->basename, filelen); + file->basename, file->size); goto fail; } @@ -784,7 +773,7 @@ int main(int argc, char *argv[]) file.addr = OMAP_BASE_ADDRESS; /* commit the file object with the processor specified base address */ - args->files = realloc(args->files, filecount); + args->files = realloc(args->files, filecount * sizeof(*args->files)); args->numfiles = filecount; args->files[filecount - 1] = malloc(sizeof (file)); memcpy(args->files[filecount - 1], &file, sizeof (file)); diff --git a/scripts/pblimage.c b/scripts/pblimage.c index 3c3625cdd5..ef09b0f960 100644 --- a/scripts/pblimage.c +++ b/scripts/pblimage.c @@ -14,8 +14,13 @@ #include <getopt.h> #include <endian.h> #include <byteswap.h> +#include <stdbool.h> +#include <linux/kernel.h> + +#include "common.h" +#include "common.c" +#include "../crypto/crc32.c" -#define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #define PBL_ACS_CONT_CMD 0x81000000 #define PBL_ADDR_24BIT_MASK 0x00ffffff @@ -36,10 +41,6 @@ #define BAREBOX_START (128 * 1024) /* - * Initialize to an invalid value. - */ -static uint32_t next_pbl_cmd = 0x82000000; -/* * need to store all bytes in memory for calculating crc32, then write the * bytes to image file for PBL boot. */ @@ -52,68 +53,42 @@ static int out_fd; static int in_fd; static int spiimage; -static uint32_t pbl_cmd_initaddr; static uint32_t pbi_crc_cmd1; static uint32_t pbi_crc_cmd2; -enum arch { - ARCH_ARM, - ARCH_POWERPC, +enum soc_type { + SOC_TYPE_INVALID = -1, + SOC_TYPE_LS1046A, + SOC_TYPE_LS1028A, +}; + +struct soc_type_entry { + const char *name; + bool big_endian; +}; + +static struct soc_type_entry socs[] = { + [SOC_TYPE_LS1046A] = { + .name = "ls1046a", + .big_endian = true, + }, + [SOC_TYPE_LS1028A] = { + .name = "ls1028a", + .big_endian = false, + }, }; -enum arch architecture = ARCH_ARM; +static enum soc_type soc_type = SOC_TYPE_INVALID; + static char *rcwfile; static char *pbifile; static char *outfile; static unsigned long loadaddr = 0x10000000; static char *infile; -static uint32_t crc_table[256]; -static int crc_table_valid; - -static void make_crc_table(void) -{ - uint32_t mask; - int i, j; - uint32_t poly; /* polynomial exclusive-or pattern */ - - if (crc_table_valid) - return; - - /* - * the polynomial used by PBL is 1 + x1 + x2 + x4 + x5 + x7 + x8 + x10 - * + x11 + x12 + x16 + x22 + x23 + x26 + x32. - */ - poly = 0x04c11db7; - - for (i = 0; i < 256; i++) { - mask = i << 24; - for (j = 0; j < 8; j++) { - if (mask & 0x80000000) - mask = (mask << 1) ^ poly; - else - mask <<= 1; - } - crc_table[i] = mask; - } - - crc_table_valid = 1; -} - static uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len) { - uint32_t crc32_val; - int i; - - make_crc_table(); - - crc32_val = ~in_crc; - - for (i = 0; i < len; i++) - crc32_val = (crc32_val << 8) ^ - crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)]; - - return crc32_val; + return crc32_be(~in_crc, buf, len); } /* @@ -122,10 +97,8 @@ static uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len) * "xxxxxx" is the offset. Calculate the start offset by subtracting the size of * the image from the top of the allowable 24-bit range. */ -static void generate_pbl_cmd(void) +static void generate_pbl_cmd(uint32_t val) { - uint32_t val = next_pbl_cmd; - next_pbl_cmd += 0x40; int i; for (i = 3; i >= 0; i--) { @@ -165,9 +138,16 @@ static void check_get_hexval(const char *filename, int lineno, char *token) exit(EXIT_FAILURE); } - for (i = 3; i >= 0; i--) { - *pmem_buf++ = (hexval >> (i * 8)) & 0xff; - pbl_size++; + if (socs[soc_type].big_endian) { + for (i = 3; i >= 0; i--) { + *pmem_buf++ = (hexval >> (i * 8)) & 0xff; + pbl_size++; + } + } else { + for (i = 0; i < 4; i++) { + *pmem_buf++ = (hexval >> (i * 8)) & 0xff; + pbl_size++; + } } } @@ -231,22 +211,57 @@ static void add_end_cmd(void) static void pbl_load_image(void) { int size; + unsigned int n; uint64_t *buf64 = (void *)mem_buf; + uint32_t *buf32 = (void *)mem_buf; /* parse the rcw.cfg file. */ pbl_parser(rcwfile); + if (soc_type == SOC_TYPE_LS1028A) { + uint32_t chksum = 0; + int i; + + for (i = 0; i < 34; i++) + chksum += buf32[i]; + + buf32[0x22] = chksum; + pbl_size += 4; + pmem_buf += 4; + } + /* parse the pbi.cfg file. */ if (pbifile) pbl_parser(pbifile); - next_pbl_cmd = pbl_cmd_initaddr - image_size; - while (next_pbl_cmd < pbl_cmd_initaddr) { - generate_pbl_cmd(); - pbl_fget(64, in_fd); - } + if (soc_type == SOC_TYPE_LS1046A) { + for (n = 0; n < image_size; n += 0x40) { + uint32_t pbl_cmd; - add_end_cmd(); + pbl_cmd = (loadaddr & PBL_ADDR_24BIT_MASK) | PBL_ACS_CONT_CMD; + pbl_cmd += n; + generate_pbl_cmd(pbl_cmd); + pbl_fget(64, in_fd); + } + + add_end_cmd(); + } else if (soc_type == SOC_TYPE_LS1028A) { + buf32 = (void *)pmem_buf; + + buf32[0] = 0x80000008; + buf32[1] = 0x2000; + buf32[2] = 0x18010000; + buf32[3] = image_size; + buf32[4] = 0x80ff0000; + pbl_size += 20; + pmem_buf += 20; + + read(in_fd, mem_buf + 0x1000, image_size); + pbl_size = 0x1000 + image_size; + printf("%s imagesize: %d\n", rcwfile, image_size); + } else { + exit(EXIT_FAILURE); + } if (spiimage) { int i; @@ -284,7 +299,12 @@ static int pblimage_check_params(void) } /* For the variable size, pad it to 64 byte boundary */ - image_size = roundup(pbl_end, 64); + if (soc_type == SOC_TYPE_LS1046A) + image_size = roundup(pbl_end, 64); + else if (soc_type == SOC_TYPE_LS1028A) + image_size = roundup(pbl_end, 512); + else + exit(EXIT_FAILURE); if (image_size > MAX_PBL_SIZE) { fprintf(stderr, "Error: pbl size %d in %s exceeds maximum size %d\n", @@ -292,19 +312,9 @@ static int pblimage_check_params(void) exit(EXIT_FAILURE); } - if (architecture == ARCH_ARM) { - pbi_crc_cmd1 = 0x61; - pbi_crc_cmd2 = 0; - pbl_cmd_initaddr = loadaddr & PBL_ADDR_24BIT_MASK; - pbl_cmd_initaddr |= PBL_ACS_CONT_CMD; - pbl_cmd_initaddr += image_size; - } else { - pbi_crc_cmd1 = 0x13; - pbi_crc_cmd2 = 0x80; - pbl_cmd_initaddr = 0x82000000; - } + pbi_crc_cmd1 = 0x61; + pbi_crc_cmd2 = 0; - next_pbl_cmd = pbl_cmd_initaddr; return 0; }; @@ -347,10 +357,11 @@ static int copy_fd(int in, int out) int main(int argc, char *argv[]) { - int opt, ret; + int opt, ret, i; off_t pos; + char *cputypestr = NULL; - while ((opt = getopt(argc, argv, "i:r:p:o:m:s")) != -1) { + while ((opt = getopt(argc, argv, "i:r:p:o:m:sc:")) != -1) { switch (opt) { case 'i': infile = optarg; @@ -370,6 +381,9 @@ int main(int argc, char *argv[]) case 's': spiimage = 1; break; + case 'c': + cputypestr = optarg; + break; default: exit(EXIT_FAILURE); } @@ -390,6 +404,26 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } + if (!cputypestr) { + fprintf(stderr, "No CPU type given\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < ARRAY_SIZE(socs); i++) { + if (!strcmp(socs[i].name, cputypestr)) { + soc_type = i; + break; + } + } + + if (soc_type == SOC_TYPE_INVALID) { + fprintf(stderr, "Invalid CPU type %s. Valid types are:\n", cputypestr); + for (i = 0; i < ARRAY_SIZE(socs); i++) + printf(" %s\n", socs[i].name); + + exit(EXIT_FAILURE); + } + pblimage_check_params(); out_fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); diff --git a/scripts/regsubst.pl b/scripts/regsubst.pl index 026c4eed2f..1aaab4f6a2 100755 --- a/scripts/regsubst.pl +++ b/scripts/regsubst.pl @@ -47,8 +47,8 @@ First you have to add the right #include directives to your file: loadaddr 0x20000000 ivtofs 0x400 - #include <mach/imx6-ddr-regs.h> - #include <mach/imx6dl-ddr-regs.h> + #include <mach/imx/imx6-ddr-regs.h> + #include <mach/imx/imx6dl-ddr-regs.h> wm 32 0x020e0774 0x000C0000 wm 32 0x020e0754 0x00000000 @@ -61,8 +61,8 @@ Then you can process the file with B<regsubst.pl>: loadaddr 0x20000000 ivtofs 0x400 - #include <mach/imx6-ddr-regs.h> - #include <mach/imx6dl-ddr-regs.h> + #include <mach/imx/imx6-ddr-regs.h> + #include <mach/imx/imx6dl-ddr-regs.h> wm 32 MX6_IOM_GRP_DDR_TYPE 0x000C0000 wm 32 MX6_IOM_GRP_DDRPKE 0x00000000 diff --git a/scripts/remote/controller.py b/scripts/remote/controller.py index b4493591dd..a3ae260558 100644 --- a/scripts/remote/controller.py +++ b/scripts/remote/controller.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function @@ -8,7 +8,7 @@ import logging import sys import os from threading import Thread -from Queue import Queue, Empty +from queue import Queue, Empty from .ratpfs import RatpFSServer from .messages import * from .ratp import RatpError @@ -105,7 +105,7 @@ class Controller(Thread): self.rxq = None self.conn.connect(timeout=5.0) self._txq = Queue() - self._stop = False + self._stopit = False self.fsserver = RatpFSServer() def _send(self, bbpkt): @@ -147,24 +147,24 @@ class Controller(Thread): return 0 def command(self, cmd): - self._send(BBPacketCommand(cmd=cmd)) + self._send(BBPacketCommand(cmd=cmd.encode())) r = self._expect(BBPacketCommandReturn, timeout=None) logging.info("Command: %r", r) return r.exit_code def getenv(self, varname): - self._send(BBPacketGetenv(varname=varname)) + self._send(BBPacketGetenv(varname=varname.encode())) r = self._expect(BBPacketGetenvReturn) return r.text def md(self, path, addr, size): - self._send(BBPacketMd(path=path, addr=addr, size=size)) + self._send(BBPacketMd(path=path.encode(), addr=addr, size=size)) r = self._expect(BBPacketMdReturn) logging.info("Md return: %r", r) return (r.exit_code,r.data) def mw(self, path, addr, data): - self._send(BBPacketMw(path=path, addr=addr, data=data)) + self._send(BBPacketMw(path=path.encode(), addr=addr, data=data)) r = self._expect(BBPacketMwReturn) logging.info("Mw return: %r", r) return (r.exit_code,r.written) @@ -208,7 +208,7 @@ class Controller(Thread): def run(self): assert self.rxq is not None try: - while not self._stop: + while not self._stopit: # receive pkt = self.conn.recv() if pkt: @@ -235,15 +235,16 @@ class Controller(Thread): Thread.start(self) def stop(self): - self._stop = True + self._stopit = True self.join() - self._stop = False + self._stopit = False self.rxq = None def send_async(self, pkt): self._txq.put(pkt) def send_async_console(self, text): + assert isinstance(text, bytes) self._txq.put(BBPacketConsoleMsg(text=text)) def send_async_ping(self): diff --git a/scripts/remote/main.py b/scripts/remote/main.py index cef5d92ee2..5aa176fdc4 100644 --- a/scripts/remote/main.py +++ b/scripts/remote/main.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 from __future__ import absolute_import, division, print_function @@ -7,7 +7,7 @@ import os import argparse import binascii import logging -from Queue import Queue +from queue import Queue from .ratp import RatpError try: @@ -48,7 +48,7 @@ def get_controller(args): def handle_run(args): ctrl = get_controller(args) - ctrl.export(args.export) + ctrl.export(args.export.encode()) res = ctrl.command(' '.join(args.arg)) if res: res = 1 @@ -160,10 +160,10 @@ def handle_listen(args): def handle_console(args): queue = Queue() ctrl = get_controller(args) - ctrl.export(args.export) + ctrl.export(args.export.encode()) ctrl.start(queue) - ctrl.send_async_console('\r') - cons = ConsoleInput(queue, exit='\x14') # CTRL-T + ctrl.send_async_console(b'\r') + cons = ConsoleInput(queue, exit=b'\x14') # CTRL-T cons.start() try: while True: @@ -206,6 +206,7 @@ parser.add_argument('--port', type=str, default=os.environ.get('BBREMOTE_PORT', parser.add_argument('--baudrate', type=int, default=os.environ.get('BBREMOTE_BAUDRATE', 115200)) parser.add_argument('--export', type=str, default=os.environ.get('BBREMOTE_EXPORT', None)) parser.add_argument('-w', '--wait', action='count', default=0) +parser.set_defaults(func=None) subparsers = parser.add_subparsers(help='sub-command help') parser_run = subparsers.add_parser('run', help="run a barebox command") @@ -277,6 +278,11 @@ parser_console.set_defaults(func=handle_console) args = parser.parse_args() logging.basicConfig(level=VERBOSITY[args.verbose], format='%(levelname)-8s %(module)-8s %(funcName)-16s %(message)s') + +if args.func is None: + parser.print_help() + exit(1) + try: res = args.func(args) exit(res) diff --git a/scripts/remote/messages.py b/scripts/remote/messages.py index abd331c8b6..de15e72ed5 100644 --- a/scripts/remote/messages.py +++ b/scripts/remote/messages.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function @@ -35,18 +35,20 @@ class BBType(object): class BBPacket(object): - def __init__(self, p_type=0, p_flags=0, payload="", raw=None): + def __init__(self, p_type=0, p_flags=0, payload=b"", raw=None): self.p_type = p_type self.p_flags = p_flags if raw is not None: self.unpack(raw) else: + assert isinstance(payload, bytes) self.payload = payload def __repr__(self): return "BBPacket(%i, %i)" % (self.p_type, self.p_flags) def _unpack_payload(self, data): + assert isinstance(data, bytes) self.payload = data def _pack_payload(self): @@ -63,6 +65,7 @@ class BBPacket(object): class BBPacketCommand(BBPacket): def __init__(self, raw=None, cmd=None): + assert isinstance(cmd, bytes) self.cmd = cmd super(BBPacketCommand, self).__init__(BBType.command, raw=raw) @@ -70,6 +73,7 @@ class BBPacketCommand(BBPacket): return "BBPacketCommand(cmd=%r)" % self.cmd def _unpack_payload(self, payload): + assert isinstance(payload, bytes) self.cmd = payload def _pack_payload(self): @@ -94,6 +98,8 @@ class BBPacketCommandReturn(BBPacket): class BBPacketConsoleMsg(BBPacket): def __init__(self, raw=None, text=None): + if text is not None: + assert isinstance(text, bytes) self.text = text super(BBPacketConsoleMsg, self).__init__(BBType.consolemsg, raw=raw) @@ -101,6 +107,7 @@ class BBPacketConsoleMsg(BBPacket): return "BBPacketConsoleMsg(text=%r)" % self.text def _unpack_payload(self, payload): + assert isinstance(payload, bytes) self.text = payload def _pack_payload(self): @@ -125,6 +132,7 @@ class BBPacketPong(BBPacket): class BBPacketGetenv(BBPacket): def __init__(self, raw=None, varname=None): + assert isinstance(varname, bytes) self.varname = varname super(BBPacketGetenv, self).__init__(BBType.getenv, raw=raw) @@ -132,6 +140,7 @@ class BBPacketGetenv(BBPacket): return "BBPacketGetenv(varname=%r)" % self.varname def _unpack_payload(self, payload): + assert isinstance(payload, bytes) self.varname = payload def _pack_payload(self): @@ -148,6 +157,7 @@ class BBPacketGetenvReturn(BBPacket): return "BBPacketGetenvReturn(varvalue=%s)" % self.text def _unpack_payload(self, payload): + assert isinstance(payload, bytes) self.text = payload def _pack_payload(self): @@ -172,6 +182,7 @@ class BBPacketFSReturn(BBPacket): class BBPacketMd(BBPacket): def __init__(self, raw=None, path=None, addr=None, size=None): + assert isinstance(path, bytes) self.path = path self.addr = addr self.size = size @@ -214,6 +225,7 @@ class BBPacketMdReturn(BBPacket): class BBPacketMw(BBPacket): def __init__(self, raw=None, path=None, addr=None, data=None): + assert isinstance(path, bytes) self.path = path self.addr = addr self.data = data diff --git a/scripts/remote/missing.py b/scripts/remote/missing.py index 67c2dfa8c0..9ed86bc10e 100644 --- a/scripts/remote/missing.py +++ b/scripts/remote/missing.py @@ -25,4 +25,4 @@ def monotonic(): return t.tv_sec + t.tv_nsec * 1e-9 if __name__ == "__main__": - print monotonic() + print(monotonic()) diff --git a/scripts/remote/ratp.py b/scripts/remote/ratp.py index 44f3e2f40a..956c788234 100644 --- a/scripts/remote/ratp.py +++ b/scripts/remote/ratp.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function @@ -345,7 +345,7 @@ class RatpConnection(object): if r.c_rst or r.c_fin: return False - if r.c_syn: + if r.c_syn and not r.c_ack: s = RatpPacket(flags='RA') s.c_sn = r.c_an s.c_an = (r.c_sn + 1) % 2 @@ -593,7 +593,7 @@ class RatpConnection(object): # reassemble if r.c_eor: logging.info("Reassembling %i frames", len(self._rx_buf)) - self._rx_queue.append(''.join(self._rx_buf)) + self._rx_queue.append(b''.join(self._rx_buf)) self._rx_buf = [] s = RatpPacket(flags='A') diff --git a/scripts/remote/ratpfs.py b/scripts/remote/ratpfs.py index 91ca044540..3e05cf2418 100644 --- a/scripts/remote/ratpfs.py +++ b/scripts/remote/ratpfs.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function @@ -36,7 +36,9 @@ class RatpFSError(ValueError): class RatpFSPacket(object): - def __init__(self, type=RatpFSType.invalid, payload="", raw=None): + def __init__(self, type=RatpFSType.invalid, payload=b'', raw=None): + if payload is not None: + assert isinstance(payload, bytes) if raw is not None: type, = struct.unpack('!B', raw[:1]) self.type = RatpFSType(type) @@ -57,9 +59,11 @@ class RatpFSPacket(object): class RatpFSServer(object): def __init__(self, path=None): - self.path = path if path: + assert isinstance(path, bytes) self.path = os.path.abspath(os.path.expanduser(path)) + else: + self.path = path self.next_handle = 1 # 0 is invalid self.files = {} self.mounted = False @@ -71,11 +75,13 @@ class RatpFSServer(object): return handle def _resolve(self, path): - components = path.split('/') + assert isinstance(path, bytes) + components = path.split(b'/') components = [x for x in components if x and x != '..'] return os.path.join(self.path, *components) def handle_stat(self, path): + assert isinstance(path, bytes) try: logging.info("path: %r", path) @@ -97,7 +103,7 @@ class RatpFSServer(object): os.O_TRUNC) path = params[4:] try: - f = os.open(self._resolve(path), flags, 0666) + f = os.open(self._resolve(path), flags, 0o666) except OSError as e: return struct.pack('!II', 0, e.errno) h = self._alloc_handle() @@ -118,24 +124,25 @@ class RatpFSServer(object): f = self.files[h] pos = os.lseek(f, pos, os.SEEK_SET) assert os.write(f, payload) == len(payload) - return "" + return b"" def handle_readdir(self, path): - res = "" + assert isinstance(path, bytes) + res = b"" for x in os.listdir(self._resolve(path)): - res += x+'\0' + res += x+b'\0' return res def handle_close(self, params): h, = struct.unpack('!I', params[:4]) os.close(self.files.pop(h)) - return "" + return b"" def handle_truncate(self, params): h, size = struct.unpack('!II', params) f = self.files[h] os.ftruncate(f, size) - return "" + return b"" def handle(self, bbcall): assert isinstance(bbcall, BBPacketFS) diff --git a/scripts/remote/threadstdio.py b/scripts/remote/threadstdio.py index db249892ac..d8ad71413c 100644 --- a/scripts/remote/threadstdio.py +++ b/scripts/remote/threadstdio.py @@ -1,11 +1,11 @@ -#!/usr/bin/python2 +#!/usr/bin/env python3 import os import sys import termios import atexit from threading import Thread -from Queue import Queue, Empty +from queue import Queue, Empty class ConsoleInput(Thread): def __init__(self, queue, exit='\x14'): diff --git a/scripts/rkimage.c b/scripts/rkimage.c index 6e68d508ac..551114ed82 100644 --- a/scripts/rkimage.c +++ b/scripts/rkimage.c @@ -9,7 +9,7 @@ #include <stdint.h> #include <string.h> #include <time.h> -#include <openssl/sha.h> +#include <openssl/evp.h> #include <errno.h> #include <stdbool.h> @@ -22,20 +22,24 @@ static void sha256(const void *buf, int len, void *out) { - SHA256_CTX sha256; + EVP_MD_CTX *md_ctx; - SHA256_Init(&sha256); - SHA256_Update(&sha256, buf, len); - SHA256_Final(out, &sha256); + md_ctx = EVP_MD_CTX_new(); + EVP_DigestInit(md_ctx, EVP_sha256()); + EVP_DigestUpdate(md_ctx, buf, len); + EVP_DigestFinal(md_ctx, out, NULL); + EVP_MD_CTX_free(md_ctx); } static void sha512(const void *buf, int len, void *out) { - SHA512_CTX sha512; + EVP_MD_CTX *md_ctx; - SHA512_Init(&sha512); - SHA512_Update(&sha512, buf, len); - SHA512_Final(out, &sha512); + md_ctx = EVP_MD_CTX_new(); + EVP_DigestInit(md_ctx, EVP_sha512()); + EVP_DigestUpdate(md_ctx, buf, len); + EVP_DigestFinal(md_ctx, out, NULL); + EVP_MD_CTX_free(md_ctx); } typedef enum { diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index d7f6dad7f0..d5943d4a11 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -18,7 +18,7 @@ #include <openssl/evp.h> #include <openssl/engine.h> -static int dts; +static int dts, standalone; static int rsa_err(const char *msg) { @@ -58,17 +58,21 @@ static int rsa_pem_get_pub_key(const char *path, RSA **rsap) /* Read the certificate */ cert = NULL; if (!PEM_read_X509(f, &cert, NULL, NULL)) { - rsa_err("Couldn't read certificate"); - ret = -EINVAL; - goto err_cert; - } - - /* Get the public key from the certificate. */ - key = X509_get_pubkey(cert); - if (!key) { - rsa_err("Couldn't read public key\n"); - ret = -EINVAL; - goto err_pubkey; + rewind(f); + key = PEM_read_PUBKEY(f, NULL, NULL, NULL); + if (!key) { + rsa_err("Couldn't read certificate"); + ret = -EINVAL; + goto err_cert; + } + } else { + /* Get the public key from the certificate. */ + key = X509_get_pubkey(cert); + if (!key) { + rsa_err("Couldn't read public key\n"); + ret = -EINVAL; + goto err_pubkey; + } } /* Convert to a RSA_style key. */ @@ -450,17 +454,24 @@ static int gen_key(const char *keyname, const char *path) print_bignum(r_squared, bits); fprintf(outfilep, "\n};\n\n"); - fprintf(outfilep, "static struct rsa_public_key %s = {\n", key_name_c); + if (standalone) { + fprintf(outfilep, "struct rsa_public_key __key_%s;\n", key_name_c); + fprintf(outfilep, "struct rsa_public_key __key_%s = {\n", key_name_c); + } else { + fprintf(outfilep, "static struct rsa_public_key %s = {\n", key_name_c); + } + fprintf(outfilep, "\t.len = %d,\n", bits / 32); fprintf(outfilep, "\t.n0inv = 0x%0x,\n", n0_inv); fprintf(outfilep, "\t.modulus = %s_modulus,\n", key_name_c); fprintf(outfilep, "\t.rr = %s_rr,\n", key_name_c); fprintf(outfilep, "\t.exponent = 0x%0lx,\n", exponent); fprintf(outfilep, "\t.key_name_hint = \"%s\",\n", keyname); - fprintf(outfilep, "};\n\n"); + fprintf(outfilep, "};\n"); - fprintf(outfilep, "struct rsa_public_key *%sp __attribute__((section(\".rsa_keys.rodata.%s\"))) = &%s;\n", - key_name_c, key_name_c, key_name_c); + if (!standalone) + fprintf(outfilep, "\nstruct rsa_public_key *%sp __attribute__((section(\".rsa_keys.rodata.%s\"))) = &%s;\n", + key_name_c, key_name_c, key_name_c); } return 0; @@ -474,7 +485,7 @@ int main(int argc, char *argv[]) outfilep = stdout; - while ((opt = getopt(argc, argv, "o:d")) > 0) { + while ((opt = getopt(argc, argv, "o:ds")) > 0) { switch (opt) { case 'o': outfile = optarg; @@ -482,6 +493,9 @@ int main(int argc, char *argv[]) case 'd': dts = 1; break; + case 's': + standalone = 1; + break; } } @@ -495,14 +509,22 @@ int main(int argc, char *argv[]) } if (optind == argc) { - fprintf(stderr, "Usage: %s <key_name_hint>:<crt> ...\n", argv[0]); + fprintf(stderr, "Usage: %s [-ods] <key_name_hint>:<crt> ...\n", argv[0]); + fprintf(stderr, "\t-o FILE\twrite output into FILE instead of stdout\n"); + fprintf(stderr, "\t-d\tgenerate device tree snippet instead of C code\n"); + fprintf(stderr, "\t-s\tgenerate standalone key outside FIT image keyring\n"); exit(1); } if (dts) { fprintf(outfilep, "/dts-v1/;\n"); fprintf(outfilep, "/ {\n"); - fprintf(outfilep, "\tsignature {\n"); + if (standalone) + fprintf(outfilep, "\tsignature-standalone {\n"); + else + fprintf(outfilep, "\tsignature {\n"); + } else if (standalone) { + fprintf(outfilep, "#include <rsa.h>\n"); } for (i = optind; i < argc; i++) { diff --git a/scripts/serial/__init__.py b/scripts/serial/__init__.py deleted file mode 100644 index 33ae52ec11..0000000000 --- a/scripts/serial/__init__.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python - -# portable serial port access with python -# this is a wrapper module for different platform implementations -# -# (C) 2001-2010 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -VERSION = '2.7' - -import sys - -if sys.platform == 'cli': - from serial.serialcli import * -else: - import os - # chose an implementation, depending on os - if os.name == 'nt': #sys.platform == 'win32': - from serial.serialwin32 import * - elif os.name == 'posix': - from serial.serialposix import * - elif os.name == 'java': - from serial.serialjava import * - else: - raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,)) - - -protocol_handler_packages = [ - 'serial.urlhandler', - ] - -def serial_for_url(url, *args, **kwargs): - """\ - Get an instance of the Serial class, depending on port/url. The port is not - opened when the keyword parameter 'do_not_open' is true, by default it - is. All other parameters are directly passed to the __init__ method when - the port is instantiated. - - The list of package names that is searched for protocol handlers is kept in - ``protocol_handler_packages``. - - e.g. we want to support a URL ``foobar://``. A module - ``my_handlers.protocol_foobar`` is provided by the user. Then - ``protocol_handler_packages.append("my_handlers")`` would extend the search - path so that ``serial_for_url("foobar://"))`` would work. - """ - # check remove extra parameter to not confuse the Serial class - do_open = 'do_not_open' not in kwargs or not kwargs['do_not_open'] - if 'do_not_open' in kwargs: del kwargs['do_not_open'] - # the default is to use the native version - klass = Serial # 'native' implementation - # check port type and get class - try: - url_nocase = url.lower() - except AttributeError: - # it's not a string, use default - pass - else: - if '://' in url_nocase: - protocol = url_nocase.split('://', 1)[0] - for package_name in protocol_handler_packages: - module_name = '%s.protocol_%s' % (package_name, protocol,) - try: - handler_module = __import__(module_name) - except ImportError: - pass - else: - klass = sys.modules[module_name].Serial - break - else: - raise ValueError('invalid URL, protocol %r not known' % (protocol,)) - else: - klass = Serial # 'native' implementation - # instantiate and open when desired - instance = klass(None, *args, **kwargs) - instance.port = url - if do_open: - instance.open() - return instance diff --git a/scripts/serial/rfc2217.py b/scripts/serial/rfc2217.py deleted file mode 100644 index b65edd55c8..0000000000 --- a/scripts/serial/rfc2217.py +++ /dev/null @@ -1,1327 +0,0 @@ -#! python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see __init__.py -# -# This module implements a RFC2217 compatible client. RF2217 descibes a -# protocol to access serial ports over TCP/IP and allows setting the baud rate, -# modem control lines etc. -# -# (C) 2001-2013 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -# TODO: -# - setting control line -> answer is not checked (had problems with one of the -# severs). consider implementing a compatibility mode flag to make check -# conditional -# - write timeout not implemented at all - -############################################################################## -# observations and issues with servers -#============================================================================= -# sredird V2.2.1 -# - http://www.ibiblio.org/pub/Linux/system/serial/ sredird-2.2.2.tar.gz -# - does not acknowledge SET_CONTROL (RTS/DTR) correctly, always responding -# [105 1] instead of the actual value. -# - SET_BAUDRATE answer contains 4 extra null bytes -> probably for larger -# numbers than 2**32? -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: while true; do nc -l -p 7000 -c "sredird debug /dev/ttyUSB0 /var/lock/sredir"; done -#============================================================================= -# telnetcpcd (untested) -# - http://ftp.wayne.edu/kermit/sredird/telnetcpcd-1.09.tar.gz -# - To get the signature [COM_PORT_OPTION] w/o data has to be sent. -#============================================================================= -# ser2net -# - does not negotiate BINARY or COM_PORT_OPTION for his side but at least -# acknowledges that the client activates these options -# - The configuration may be that the server prints a banner. As this client -# implementation does a flushInput on connect, this banner is hidden from -# the user application. -# - NOTIFY_MODEMSTATE: the poll interval of the server seems to be one -# second. -# - To get the signature [COM_PORT_OPTION 0] has to be sent. -# - run a server: run ser2net daemon, in /etc/ser2net.conf: -# 2000:telnet:0:/dev/ttyS0:9600 remctl banner -############################################################################## - -# How to identify ports? pySerial might want to support other protocols in the -# future, so lets use an URL scheme. -# for RFC2217 compliant servers we will use this: -# rfc2217://<host>:<port>[/option[/option...]] -# -# options: -# - "debug" print diagnostic messages -# - "ign_set_control": do not look at the answers to SET_CONTROL -# - "poll_modem": issue NOTIFY_MODEMSTATE requests when CTS/DTR/RI/CD is read. -# Without this option it expects that the server sends notifications -# automatically on change (which most servers do and is according to the -# RFC). -# the order of the options is not relevant - -from serial.serialutil import * -import time -import struct -import socket -import threading -import Queue -import logging - -# port string is expected to be something like this: -# rfc2217://host:port -# host may be an IP or including domain, whatever. -# port is 0...65535 - -# map log level names to constants. used in fromURL() -LOGGER_LEVELS = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - } - - -# telnet protocol characters -IAC = to_bytes([255]) # Interpret As Command -DONT = to_bytes([254]) -DO = to_bytes([253]) -WONT = to_bytes([252]) -WILL = to_bytes([251]) -IAC_DOUBLED = to_bytes([IAC, IAC]) - -SE = to_bytes([240]) # Subnegotiation End -NOP = to_bytes([241]) # No Operation -DM = to_bytes([242]) # Data Mark -BRK = to_bytes([243]) # Break -IP = to_bytes([244]) # Interrupt process -AO = to_bytes([245]) # Abort output -AYT = to_bytes([246]) # Are You There -EC = to_bytes([247]) # Erase Character -EL = to_bytes([248]) # Erase Line -GA = to_bytes([249]) # Go Ahead -SB = to_bytes([250]) # Subnegotiation Begin - -# selected telnet options -BINARY = to_bytes([0]) # 8-bit data path -ECHO = to_bytes([1]) # echo -SGA = to_bytes([3]) # suppress go ahead - -# RFC2217 -COM_PORT_OPTION = to_bytes([44]) - -# Client to Access Server -SET_BAUDRATE = to_bytes([1]) -SET_DATASIZE = to_bytes([2]) -SET_PARITY = to_bytes([3]) -SET_STOPSIZE = to_bytes([4]) -SET_CONTROL = to_bytes([5]) -NOTIFY_LINESTATE = to_bytes([6]) -NOTIFY_MODEMSTATE = to_bytes([7]) -FLOWCONTROL_SUSPEND = to_bytes([8]) -FLOWCONTROL_RESUME = to_bytes([9]) -SET_LINESTATE_MASK = to_bytes([10]) -SET_MODEMSTATE_MASK = to_bytes([11]) -PURGE_DATA = to_bytes([12]) - -SERVER_SET_BAUDRATE = to_bytes([101]) -SERVER_SET_DATASIZE = to_bytes([102]) -SERVER_SET_PARITY = to_bytes([103]) -SERVER_SET_STOPSIZE = to_bytes([104]) -SERVER_SET_CONTROL = to_bytes([105]) -SERVER_NOTIFY_LINESTATE = to_bytes([106]) -SERVER_NOTIFY_MODEMSTATE = to_bytes([107]) -SERVER_FLOWCONTROL_SUSPEND = to_bytes([108]) -SERVER_FLOWCONTROL_RESUME = to_bytes([109]) -SERVER_SET_LINESTATE_MASK = to_bytes([110]) -SERVER_SET_MODEMSTATE_MASK = to_bytes([111]) -SERVER_PURGE_DATA = to_bytes([112]) - -RFC2217_ANSWER_MAP = { - SET_BAUDRATE: SERVER_SET_BAUDRATE, - SET_DATASIZE: SERVER_SET_DATASIZE, - SET_PARITY: SERVER_SET_PARITY, - SET_STOPSIZE: SERVER_SET_STOPSIZE, - SET_CONTROL: SERVER_SET_CONTROL, - NOTIFY_LINESTATE: SERVER_NOTIFY_LINESTATE, - NOTIFY_MODEMSTATE: SERVER_NOTIFY_MODEMSTATE, - FLOWCONTROL_SUSPEND: SERVER_FLOWCONTROL_SUSPEND, - FLOWCONTROL_RESUME: SERVER_FLOWCONTROL_RESUME, - SET_LINESTATE_MASK: SERVER_SET_LINESTATE_MASK, - SET_MODEMSTATE_MASK: SERVER_SET_MODEMSTATE_MASK, - PURGE_DATA: SERVER_PURGE_DATA, -} - -SET_CONTROL_REQ_FLOW_SETTING = to_bytes([0]) # Request Com Port Flow Control Setting (outbound/both) -SET_CONTROL_USE_NO_FLOW_CONTROL = to_bytes([1]) # Use No Flow Control (outbound/both) -SET_CONTROL_USE_SW_FLOW_CONTROL = to_bytes([2]) # Use XON/XOFF Flow Control (outbound/both) -SET_CONTROL_USE_HW_FLOW_CONTROL = to_bytes([3]) # Use HARDWARE Flow Control (outbound/both) -SET_CONTROL_REQ_BREAK_STATE = to_bytes([4]) # Request BREAK State -SET_CONTROL_BREAK_ON = to_bytes([5]) # Set BREAK State ON -SET_CONTROL_BREAK_OFF = to_bytes([6]) # Set BREAK State OFF -SET_CONTROL_REQ_DTR = to_bytes([7]) # Request DTR Signal State -SET_CONTROL_DTR_ON = to_bytes([8]) # Set DTR Signal State ON -SET_CONTROL_DTR_OFF = to_bytes([9]) # Set DTR Signal State OFF -SET_CONTROL_REQ_RTS = to_bytes([10]) # Request RTS Signal State -SET_CONTROL_RTS_ON = to_bytes([11]) # Set RTS Signal State ON -SET_CONTROL_RTS_OFF = to_bytes([12]) # Set RTS Signal State OFF -SET_CONTROL_REQ_FLOW_SETTING_IN = to_bytes([13]) # Request Com Port Flow Control Setting (inbound) -SET_CONTROL_USE_NO_FLOW_CONTROL_IN = to_bytes([14]) # Use No Flow Control (inbound) -SET_CONTROL_USE_SW_FLOW_CONTOL_IN = to_bytes([15]) # Use XON/XOFF Flow Control (inbound) -SET_CONTROL_USE_HW_FLOW_CONTOL_IN = to_bytes([16]) # Use HARDWARE Flow Control (inbound) -SET_CONTROL_USE_DCD_FLOW_CONTROL = to_bytes([17]) # Use DCD Flow Control (outbound/both) -SET_CONTROL_USE_DTR_FLOW_CONTROL = to_bytes([18]) # Use DTR Flow Control (inbound) -SET_CONTROL_USE_DSR_FLOW_CONTROL = to_bytes([19]) # Use DSR Flow Control (outbound/both) - -LINESTATE_MASK_TIMEOUT = 128 # Time-out Error -LINESTATE_MASK_SHIFTREG_EMPTY = 64 # Transfer Shift Register Empty -LINESTATE_MASK_TRANSREG_EMPTY = 32 # Transfer Holding Register Empty -LINESTATE_MASK_BREAK_DETECT = 16 # Break-detect Error -LINESTATE_MASK_FRAMING_ERROR = 8 # Framing Error -LINESTATE_MASK_PARTIY_ERROR = 4 # Parity Error -LINESTATE_MASK_OVERRUN_ERROR = 2 # Overrun Error -LINESTATE_MASK_DATA_READY = 1 # Data Ready - -MODEMSTATE_MASK_CD = 128 # Receive Line Signal Detect (also known as Carrier Detect) -MODEMSTATE_MASK_RI = 64 # Ring Indicator -MODEMSTATE_MASK_DSR = 32 # Data-Set-Ready Signal State -MODEMSTATE_MASK_CTS = 16 # Clear-To-Send Signal State -MODEMSTATE_MASK_CD_CHANGE = 8 # Delta Receive Line Signal Detect -MODEMSTATE_MASK_RI_CHANGE = 4 # Trailing-edge Ring Detector -MODEMSTATE_MASK_DSR_CHANGE = 2 # Delta Data-Set-Ready -MODEMSTATE_MASK_CTS_CHANGE = 1 # Delta Clear-To-Send - -PURGE_RECEIVE_BUFFER = to_bytes([1]) # Purge access server receive data buffer -PURGE_TRANSMIT_BUFFER = to_bytes([2]) # Purge access server transmit data buffer -PURGE_BOTH_BUFFERS = to_bytes([3]) # Purge both the access server receive data buffer and the access server transmit data buffer - - -RFC2217_PARITY_MAP = { - PARITY_NONE: 1, - PARITY_ODD: 2, - PARITY_EVEN: 3, - PARITY_MARK: 4, - PARITY_SPACE: 5, -} -RFC2217_REVERSE_PARITY_MAP = dict((v,k) for k,v in RFC2217_PARITY_MAP.items()) - -RFC2217_STOPBIT_MAP = { - STOPBITS_ONE: 1, - STOPBITS_ONE_POINT_FIVE: 3, - STOPBITS_TWO: 2, -} -RFC2217_REVERSE_STOPBIT_MAP = dict((v,k) for k,v in RFC2217_STOPBIT_MAP.items()) - -# Telnet filter states -M_NORMAL = 0 -M_IAC_SEEN = 1 -M_NEGOTIATE = 2 - -# TelnetOption and TelnetSubnegotiation states -REQUESTED = 'REQUESTED' -ACTIVE = 'ACTIVE' -INACTIVE = 'INACTIVE' -REALLY_INACTIVE = 'REALLY_INACTIVE' - -class TelnetOption(object): - """Manage a single telnet option, keeps track of DO/DONT WILL/WONT.""" - - def __init__(self, connection, name, option, send_yes, send_no, ack_yes, ack_no, initial_state, activation_callback=None): - """\ - Initialize option. - :param connection: connection used to transmit answers - :param name: a readable name for debug outputs - :param send_yes: what to send when option is to be enabled. - :param send_no: what to send when option is to be disabled. - :param ack_yes: what to expect when remote agrees on option. - :param ack_no: what to expect when remote disagrees on option. - :param initial_state: options initialized with REQUESTED are tried to - be enabled on startup. use INACTIVE for all others. - """ - self.connection = connection - self.name = name - self.option = option - self.send_yes = send_yes - self.send_no = send_no - self.ack_yes = ack_yes - self.ack_no = ack_no - self.state = initial_state - self.active = False - self.activation_callback = activation_callback - - def __repr__(self): - """String for debug outputs""" - return "%s:%s(%s)" % (self.name, self.active, self.state) - - def process_incoming(self, command): - """\ - A DO/DONT/WILL/WONT was received for this option, update state and - answer when needed. - """ - if command == self.ack_yes: - if self.state is REQUESTED: - self.state = ACTIVE - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is ACTIVE: - pass - elif self.state is INACTIVE: - self.state = ACTIVE - self.connection.telnetSendOption(self.send_yes, self.option) - self.active = True - if self.activation_callback is not None: - self.activation_callback() - elif self.state is REALLY_INACTIVE: - self.connection.telnetSendOption(self.send_no, self.option) - else: - raise ValueError('option in illegal state %r' % self) - elif command == self.ack_no: - if self.state is REQUESTED: - self.state = INACTIVE - self.active = False - elif self.state is ACTIVE: - self.state = INACTIVE - self.connection.telnetSendOption(self.send_no, self.option) - self.active = False - elif self.state is INACTIVE: - pass - elif self.state is REALLY_INACTIVE: - pass - else: - raise ValueError('option in illegal state %r' % self) - - -class TelnetSubnegotiation(object): - """\ - A object to handle subnegotiation of options. In this case actually - sub-sub options for RFC 2217. It is used to track com port options. - """ - - def __init__(self, connection, name, option, ack_option=None): - if ack_option is None: ack_option = option - self.connection = connection - self.name = name - self.option = option - self.value = None - self.ack_option = ack_option - self.state = INACTIVE - - def __repr__(self): - """String for debug outputs.""" - return "%s:%s" % (self.name, self.state) - - def set(self, value): - """\ - Request a change of the value. a request is sent to the server. if - the client needs to know if the change is performed he has to check the - state of this object. - """ - self.value = value - self.state = REQUESTED - self.connection.rfc2217SendSubnegotiation(self.option, self.value) - if self.connection.logger: - self.connection.logger.debug("SB Requesting %s -> %r" % (self.name, self.value)) - - def isReady(self): - """\ - Check if answer from server has been received. when server rejects - the change, raise a ValueError. - """ - if self.state == REALLY_INACTIVE: - raise ValueError("remote rejected value for option %r" % (self.name)) - return self.state == ACTIVE - # add property to have a similar interface as TelnetOption - active = property(isReady) - - def wait(self, timeout=3): - """\ - Wait until the subnegotiation has been acknowledged or timeout. It - can also throw a value error when the answer from the server does not - match the value sent. - """ - timeout_time = time.time() + timeout - while time.time() < timeout_time: - if self.isReady(): - break - time.sleep(0.001) # prevent 100% CPU load - else: - raise SerialException("timeout while waiting for option %r" % (self.name)) - - def checkAnswer(self, suboption): - """\ - Check an incoming subnegotiation block. The parameter already has - cut off the header like sub option number and com port option value. - """ - if self.value == suboption[:len(self.value)]: - self.state = ACTIVE - else: - # error propagation done in isReady - self.state = REALLY_INACTIVE - if self.connection.logger: - self.connection.logger.debug("SB Answer %s -> %r -> %s" % (self.name, suboption, self.state)) - - -class RFC2217Serial(SerialBase): - """Serial port implementation for RFC 2217 remote serial ports.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - self.logger = None - self._ignore_set_control_answer = False - self._poll_modem_state = False - self._network_timeout = 3 - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self._isOpen: - raise SerialException("Port is already open.") - try: - self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._socket.connect(self.fromURL(self.portstr)) - self._socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) - except Exception, msg: - self._socket = None - raise SerialException("Could not open port %s: %s" % (self.portstr, msg)) - - self._socket.settimeout(5) # XXX good value? - - # use a thread save queue as buffer. it also simplifies implementing - # the read timeout - self._read_buffer = Queue.Queue() - # to ensure that user writes does not interfere with internal - # telnet/rfc2217 options establish a lock - self._write_lock = threading.Lock() - # name the following separately so that, below, a check can be easily done - mandadory_options = [ - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED), - ] - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, REQUESTED), - ] + mandadory_options - # RFC 2217 specific states - # COM port settings - self._rfc2217_port_settings = { - 'baudrate': TelnetSubnegotiation(self, 'baudrate', SET_BAUDRATE, SERVER_SET_BAUDRATE), - 'datasize': TelnetSubnegotiation(self, 'datasize', SET_DATASIZE, SERVER_SET_DATASIZE), - 'parity': TelnetSubnegotiation(self, 'parity', SET_PARITY, SERVER_SET_PARITY), - 'stopsize': TelnetSubnegotiation(self, 'stopsize', SET_STOPSIZE, SERVER_SET_STOPSIZE), - } - # There are more subnegotiation objects, combine all in one dictionary - # for easy access - self._rfc2217_options = { - 'purge': TelnetSubnegotiation(self, 'purge', PURGE_DATA, SERVER_PURGE_DATA), - 'control': TelnetSubnegotiation(self, 'control', SET_CONTROL, SERVER_SET_CONTROL), - } - self._rfc2217_options.update(self._rfc2217_port_settings) - # cache for line and modem states that the server sends to us - self._linestate = 0 - self._modemstate = None - self._modemstate_expires = 0 - # RFC 2217 flow control between server and client - self._remote_suspend_flow = False - - self._thread = threading.Thread(target=self._telnetReadLoop) - self._thread.setDaemon(True) - self._thread.setName('pySerial RFC 2217 reader thread for %s' % (self._port,)) - self._thread.start() - - # negotiate Telnet/RFC 2217 -> send initial requests - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnetSendOption(option.send_yes, option.option) - # now wait until important options are negotiated - timeout_time = time.time() + self._network_timeout - while time.time() < timeout_time: - if sum(o.active for o in mandadory_options) == sum(o.state != INACTIVE for o in mandadory_options): - break - time.sleep(0.001) # prevent 100% CPU load - else: - raise SerialException("Remote does not seem to support RFC2217 or BINARY mode %r" % mandadory_options) - if self.logger: - self.logger.info("Negotiated options: %s" % self._telnet_options) - - # fine, go on, set RFC 2271 specific things - self._reconfigurePort() - # all things set up get, now a clean start - self._isOpen = True - if not self._rtscts: - self.setRTS(True) - self.setDTR(True) - self.flushInput() - self.flushOutput() - - def _reconfigurePort(self): - """Set communication parameters on opened port.""" - if self._socket is None: - raise SerialException("Can only operate on open ports") - - # if self._timeout != 0 and self._interCharTimeout is not None: - # XXX - - if self._writeTimeout is not None: - raise NotImplementedError('writeTimeout is currently not supported') - # XXX - - # Setup the connection - # to get good performance, all parameter changes are sent first... - if not isinstance(self._baudrate, (int, long)) or not 0 < self._baudrate < 2**32: - raise ValueError("invalid baudrate: %r" % (self._baudrate)) - self._rfc2217_port_settings['baudrate'].set(struct.pack('!I', self._baudrate)) - self._rfc2217_port_settings['datasize'].set(struct.pack('!B', self._bytesize)) - self._rfc2217_port_settings['parity'].set(struct.pack('!B', RFC2217_PARITY_MAP[self._parity])) - self._rfc2217_port_settings['stopsize'].set(struct.pack('!B', RFC2217_STOPBIT_MAP[self._stopbits])) - - # and now wait until parameters are active - items = self._rfc2217_port_settings.values() - if self.logger: - self.logger.debug("Negotiating settings: %s" % (items,)) - timeout_time = time.time() + self._network_timeout - while time.time() < timeout_time: - if sum(o.active for o in items) == len(items): - break - time.sleep(0.001) # prevent 100% CPU load - else: - raise SerialException("Remote does not accept parameter change (RFC2217): %r" % items) - if self.logger: - self.logger.info("Negotiated settings: %s" % (items,)) - - if self._rtscts and self._xonxoff: - raise ValueError('xonxoff and rtscts together are not supported') - elif self._rtscts: - self.rfc2217SetControl(SET_CONTROL_USE_HW_FLOW_CONTROL) - elif self._xonxoff: - self.rfc2217SetControl(SET_CONTROL_USE_SW_FLOW_CONTROL) - else: - self.rfc2217SetControl(SET_CONTROL_USE_NO_FLOW_CONTROL) - - def close(self): - """Close port""" - if self._isOpen: - if self._socket: - try: - self._socket.shutdown(socket.SHUT_RDWR) - self._socket.close() - except: - # ignore errors. - pass - self._socket = None - if self._thread: - self._thread.join() - self._isOpen = False - # in case of quick reconnects, give the server some time - time.sleep(0.3) - - def makeDeviceName(self, port): - raise SerialException("there is no sensible way to turn numbers into URLs") - - def fromURL(self, url): - """extract host and port from an URL string""" - if url.lower().startswith("rfc2217://"): url = url[10:] - try: - # is there a "path" (our options)? - if '/' in url: - # cut away options - url, options = url.split('/', 1) - # process options now, directly altering self - for option in options.split('/'): - if '=' in option: - option, value = option.split('=', 1) - else: - value = None - if option == 'logging': - logging.basicConfig() # XXX is that good to call it here? - self.logger = logging.getLogger('pySerial.rfc2217') - self.logger.setLevel(LOGGER_LEVELS[value]) - self.logger.debug('enabled logging') - elif option == 'ign_set_control': - self._ignore_set_control_answer = True - elif option == 'poll_modem': - self._poll_modem_state = True - elif option == 'timeout': - self._network_timeout = float(value) - else: - raise ValueError('unknown option: %r' % (option,)) - # get host and port - host, port = url.split(':', 1) # may raise ValueError because of unpacking - port = int(port) # and this if it's not a number - if not 0 <= port < 65536: raise ValueError("port not in range 0...65535") - except ValueError, e: - raise SerialException('expected a string in the form "[rfc2217://]<host>:<port>[/option[/option...]]": %s' % e) - return (host, port) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def inWaiting(self): - """Return the number of characters currently in the input buffer.""" - if not self._isOpen: raise portNotOpenError - return self._read_buffer.qsize() - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self._isOpen: raise portNotOpenError - data = bytearray() - try: - while len(data) < size: - if self._thread is None: - raise SerialException('connection failed (reader thread died)') - data.append(self._read_buffer.get(True, self._timeout)) - except Queue.Empty: # -> timeout - pass - return bytes(data) - - def write(self, data): - """\ - Output the given string over the serial port. Can block if the - connection is blocked. May raise SerialException if the connection is - closed. - """ - if not self._isOpen: raise portNotOpenError - self._write_lock.acquire() - try: - try: - self._socket.sendall(to_bytes(data).replace(IAC, IAC_DOUBLED)) - except socket.error, e: - raise SerialException("connection failed (socket error): %s" % e) # XXX what exception if socket connection fails - finally: - self._write_lock.release() - return len(data) - - def flushInput(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self._isOpen: raise portNotOpenError - self.rfc2217SendPurge(PURGE_RECEIVE_BUFFER) - # empty read buffer - while self._read_buffer.qsize(): - self._read_buffer.get(False) - - def flushOutput(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self._isOpen: raise portNotOpenError - self.rfc2217SendPurge(PURGE_TRANSMIT_BUFFER) - - def sendBreak(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self._isOpen: raise portNotOpenError - self.setBreak(True) - time.sleep(duration) - self.setBreak(False) - - def setBreak(self, level=True): - """\ - Set break: Controls TXD. When active, to transmitting is - possible. - """ - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('set BREAK to %s' % ('inactive', 'active')[bool(level)]) - if level: - self.rfc2217SetControl(SET_CONTROL_BREAK_ON) - else: - self.rfc2217SetControl(SET_CONTROL_BREAK_OFF) - - def setRTS(self, level=True): - """Set terminal status line: Request To Send.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('set RTS to %s' % ('inactive', 'active')[bool(level)]) - if level: - self.rfc2217SetControl(SET_CONTROL_RTS_ON) - else: - self.rfc2217SetControl(SET_CONTROL_RTS_OFF) - - def setDTR(self, level=True): - """Set terminal status line: Data Terminal Ready.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('set DTR to %s' % ('inactive', 'active')[bool(level)]) - if level: - self.rfc2217SetControl(SET_CONTROL_DTR_ON) - else: - self.rfc2217SetControl(SET_CONTROL_DTR_OFF) - - def getCTS(self): - """Read terminal status line: Clear To Send.""" - if not self._isOpen: raise portNotOpenError - return bool(self.getModemState() & MODEMSTATE_MASK_CTS) - - def getDSR(self): - """Read terminal status line: Data Set Ready.""" - if not self._isOpen: raise portNotOpenError - return bool(self.getModemState() & MODEMSTATE_MASK_DSR) - - def getRI(self): - """Read terminal status line: Ring Indicator.""" - if not self._isOpen: raise portNotOpenError - return bool(self.getModemState() & MODEMSTATE_MASK_RI) - - def getCD(self): - """Read terminal status line: Carrier Detect.""" - if not self._isOpen: raise portNotOpenError - return bool(self.getModemState() & MODEMSTATE_MASK_CD) - - # - - - platform specific - - - - # None so far - - # - - - RFC2217 specific - - - - - def _telnetReadLoop(self): - """Read loop for the socket.""" - mode = M_NORMAL - suboption = None - try: - while self._socket is not None: - try: - data = self._socket.recv(1024) - except socket.timeout: - # just need to get out of recv form time to time to check if - # still alive - continue - except socket.error, e: - # connection fails -> terminate loop - if self.logger: - self.logger.debug("socket error in reader thread: %s" % (e,)) - break - if not data: break # lost connection - for byte in data: - if mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - mode = M_IAC_SEEN - else: - # store data in read buffer or sub option buffer - # depending on state - if suboption is not None: - suboption.append(byte) - else: - self._read_buffer.put(byte) - elif mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if suboption is not None: - suboption.append(IAC) - else: - self._read_buffer.put(IAC) - mode = M_NORMAL - elif byte == SB: - # sub option start - suboption = bytearray() - mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnetProcessSubnegotiation(bytes(suboption)) - suboption = None - mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - telnet_command = byte - mode = M_NEGOTIATE - else: - # other telnet commands - self._telnetProcessCommand(byte) - mode = M_NORMAL - elif mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnetNegotiateOption(telnet_command, byte) - mode = M_NORMAL - finally: - self._thread = None - if self.logger: - self.logger.debug("read thread terminated") - - # - incoming telnet commands and options - - def _telnetProcessCommand(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: %r" % (command,)) - - def _telnetNegotiateOption(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnetSendOption((command == WILL and DONT or WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: %r" % (option,)) - - - def _telnetProcessSubnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if suboption[1:2] == SERVER_NOTIFY_LINESTATE and len(suboption) >= 3: - self._linestate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_LINESTATE: %s" % self._linestate) - elif suboption[1:2] == SERVER_NOTIFY_MODEMSTATE and len(suboption) >= 3: - self._modemstate = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: %s" % self._modemstate) - # update time when we think that a poll would make sense - self._modemstate_expires = time.time() + 0.3 - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - self._remote_suspend_flow = False - else: - for item in self._rfc2217_options.values(): - if item.ack_option == suboption[1:2]: - #~ print "processing COM_PORT_OPTION: %r" % list(suboption[1:]) - item.checkAnswer(bytes(suboption[2:])) - break - else: - if self.logger: - self.logger.warning("ignoring COM_PORT_OPTION: %r" % (suboption,)) - else: - if self.logger: - self.logger.warning("ignoring subnegotiation: %r" % (suboption,)) - - # - outgoing telnet commands and options - - def _internal_raw_write(self, data): - """internal socket write with no data escaping. used to send telnet stuff.""" - self._write_lock.acquire() - try: - self._socket.sendall(data) - finally: - self._write_lock.release() - - def telnetSendOption(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self._internal_raw_write(to_bytes([IAC, action, option])) - - def rfc2217SendSubnegotiation(self, option, value=''): - """Subnegotiation of RFC2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self._internal_raw_write(to_bytes([IAC, SB, COM_PORT_OPTION, option] + list(value) + [IAC, SE])) - - def rfc2217SendPurge(self, value): - item = self._rfc2217_options['purge'] - item.set(value) # transmit desired purge type - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217SetControl(self, value): - item = self._rfc2217_options['control'] - item.set(value) # transmit desired control type - if self._ignore_set_control_answer: - # answers are ignored when option is set. compatibility mode for - # servers that answer, but not the expected one... (or no answer - # at all) i.e. sredird - time.sleep(0.1) # this helps getting the unit tests passed - else: - item.wait(self._network_timeout) # wait for acknowledge from the server - - def rfc2217FlowServerReady(self): - """\ - check if server is ready to receive data. block for some time when - not. - """ - #~ if self._remote_suspend_flow: - #~ wait--- - - def getModemState(self): - """\ - get last modem state (cached value. If value is "old", request a new - one. This cache helps that we don't issue to many requests when e.g. all - status lines, one after the other is queried by the user (getCTS, getDSR - etc.) - """ - # active modem state polling enabled? is the value fresh enough? - if self._poll_modem_state and self._modemstate_expires < time.time(): - if self.logger: - self.logger.debug('polling modem state') - # when it is older, request an update - self.rfc2217SendSubnegotiation(NOTIFY_MODEMSTATE) - timeout_time = time.time() + self._network_timeout - while time.time() < timeout_time: - # when expiration time is updated, it means that there is a new - # value - if self._modemstate_expires > time.time(): - if self.logger: - self.logger.warning('poll for modem state failed') - break - time.sleep(0.001) # prevent 100% CPU load - # even when there is a timeout, do not generate an error just - # return the last known value. this way we can support buggy - # servers that do not respond to polls, but send automatic - # updates. - if self._modemstate is not None: - if self.logger: - self.logger.debug('using cached modem state') - return self._modemstate - else: - # never received a notification from the server - raise SerialException("remote sends no NOTIFY_MODEMSTATE") - - -# assemble Serial class with the platform specific implementation and the base -# for file-like behavior. for Python 2.6 and newer, that provide the new I/O -# library, derive from io.RawIOBase -try: - import io -except ImportError: - # classic version with our own file-like emulation - class Serial(RFC2217Serial, FileLike): - pass -else: - # io library present - class Serial(RFC2217Serial, io.RawIOBase): - pass - - -############################################################################# -# The following is code that helps implementing an RFC 2217 server. - -class PortManager(object): - """\ - This class manages the state of Telnet and RFC 2217. It needs a serial - instance and a connection to work with. Connection is expected to implement - a (thread safe) write function, that writes the string to the network. - """ - - def __init__(self, serial_port, connection, logger=None): - self.serial = serial_port - self.connection = connection - self.logger = logger - self._client_is_rfc2217 = False - - # filter state machine - self.mode = M_NORMAL - self.suboption = None - self.telnet_command = None - - # states for modem/line control events - self.modemstate_mask = 255 - self.last_modemstate = None - self.linstate_mask = 0 - - # all supported telnet options - self._telnet_options = [ - TelnetOption(self, 'ECHO', ECHO, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'we-SGA', SGA, WILL, WONT, DO, DONT, REQUESTED), - TelnetOption(self, 'they-SGA', SGA, DO, DONT, WILL, WONT, INACTIVE), - TelnetOption(self, 'we-BINARY', BINARY, WILL, WONT, DO, DONT, INACTIVE), - TelnetOption(self, 'they-BINARY', BINARY, DO, DONT, WILL, WONT, REQUESTED), - TelnetOption(self, 'we-RFC2217', COM_PORT_OPTION, WILL, WONT, DO, DONT, REQUESTED, self._client_ok), - TelnetOption(self, 'they-RFC2217', COM_PORT_OPTION, DO, DONT, WILL, WONT, INACTIVE, self._client_ok), - ] - - # negotiate Telnet/RFC2217 -> send initial requests - if self.logger: - self.logger.debug("requesting initial Telnet/RFC 2217 options") - for option in self._telnet_options: - if option.state is REQUESTED: - self.telnetSendOption(option.send_yes, option.option) - # issue 1st modem state notification - - def _client_ok(self): - """\ - callback of telnet option. It gets called when option is activated. - This one here is used to detect when the client agrees on RFC 2217. A - flag is set so that other functions like check_modem_lines know if the - client is OK. - """ - # The callback is used for we and they so if one party agrees, we're - # already happy. it seems not all servers do the negotiation correctly - # and i guess there are incorrect clients too.. so be happy if client - # answers one or the other positively. - self._client_is_rfc2217 = True - if self.logger: - self.logger.info("client accepts RFC 2217") - # this is to ensure that the client gets a notification, even if there - # was no change - self.check_modem_lines(force_notification=True) - - # - outgoing telnet commands and options - - def telnetSendOption(self, action, option): - """Send DO, DONT, WILL, WONT.""" - self.connection.write(to_bytes([IAC, action, option])) - - def rfc2217SendSubnegotiation(self, option, value=''): - """Subnegotiation of RFC 2217 parameters.""" - value = value.replace(IAC, IAC_DOUBLED) - self.connection.write(to_bytes([IAC, SB, COM_PORT_OPTION, option] + list(value) + [IAC, SE])) - - # - check modem lines, needs to be called periodically from user to - # establish polling - - def check_modem_lines(self, force_notification=False): - modemstate = ( - (self.serial.getCTS() and MODEMSTATE_MASK_CTS) | - (self.serial.getDSR() and MODEMSTATE_MASK_DSR) | - (self.serial.getRI() and MODEMSTATE_MASK_RI) | - (self.serial.getCD() and MODEMSTATE_MASK_CD) - ) - # check what has changed - deltas = modemstate ^ (self.last_modemstate or 0) # when last is None -> 0 - if deltas & MODEMSTATE_MASK_CTS: - modemstate |= MODEMSTATE_MASK_CTS_CHANGE - if deltas & MODEMSTATE_MASK_DSR: - modemstate |= MODEMSTATE_MASK_DSR_CHANGE - if deltas & MODEMSTATE_MASK_RI: - modemstate |= MODEMSTATE_MASK_RI_CHANGE - if deltas & MODEMSTATE_MASK_CD: - modemstate |= MODEMSTATE_MASK_CD_CHANGE - # if new state is different and the mask allows this change, send - # notification. suppress notifications when client is not rfc2217 - if modemstate != self.last_modemstate or force_notification: - if (self._client_is_rfc2217 and (modemstate & self.modemstate_mask)) or force_notification: - self.rfc2217SendSubnegotiation( - SERVER_NOTIFY_MODEMSTATE, - to_bytes([modemstate & self.modemstate_mask]) - ) - if self.logger: - self.logger.info("NOTIFY_MODEMSTATE: %s" % (modemstate,)) - # save last state, but forget about deltas. - # otherwise it would also notify about changing deltas which is - # probably not very useful - self.last_modemstate = modemstate & 0xf0 - - # - outgoing data escaping - - def escape(self, data): - """\ - This generator function is for the user. All outgoing data has to be - properly escaped, so that no IAC character in the data stream messes up - the Telnet state machine in the server. - - socket.sendall(escape(data)) - """ - for byte in data: - if byte == IAC: - yield IAC - yield IAC - else: - yield byte - - # - incoming data filter - - def filter(self, data): - """\ - Handle a bunch of incoming bytes. This is a generator. It will yield - all characters not of interest for Telnet/RFC 2217. - - The idea is that the reader thread pushes data from the socket through - this filter: - - for byte in filter(socket.recv(1024)): - # do things like CR/LF conversion/whatever - # and write data to the serial port - serial.write(byte) - - (socket error handling code left as exercise for the reader) - """ - for byte in data: - if self.mode == M_NORMAL: - # interpret as command or as data - if byte == IAC: - self.mode = M_IAC_SEEN - else: - # store data in sub option buffer or pass it to our - # consumer depending on state - if self.suboption is not None: - self.suboption.append(byte) - else: - yield byte - elif self.mode == M_IAC_SEEN: - if byte == IAC: - # interpret as command doubled -> insert character - # itself - if self.suboption is not None: - self.suboption.append(byte) - else: - yield byte - self.mode = M_NORMAL - elif byte == SB: - # sub option start - self.suboption = bytearray() - self.mode = M_NORMAL - elif byte == SE: - # sub option end -> process it now - self._telnetProcessSubnegotiation(bytes(self.suboption)) - self.suboption = None - self.mode = M_NORMAL - elif byte in (DO, DONT, WILL, WONT): - # negotiation - self.telnet_command = byte - self.mode = M_NEGOTIATE - else: - # other telnet commands - self._telnetProcessCommand(byte) - self.mode = M_NORMAL - elif self.mode == M_NEGOTIATE: # DO, DONT, WILL, WONT was received, option now following - self._telnetNegotiateOption(self.telnet_command, byte) - self.mode = M_NORMAL - - # - incoming telnet commands and options - - def _telnetProcessCommand(self, command): - """Process commands other than DO, DONT, WILL, WONT.""" - # Currently none. RFC2217 only uses negotiation and subnegotiation. - if self.logger: - self.logger.warning("ignoring Telnet command: %r" % (command,)) - - def _telnetNegotiateOption(self, command, option): - """Process incoming DO, DONT, WILL, WONT.""" - # check our registered telnet options and forward command to them - # they know themselves if they have to answer or not - known = False - for item in self._telnet_options: - # can have more than one match! as some options are duplicated for - # 'us' and 'them' - if item.option == option: - item.process_incoming(command) - known = True - if not known: - # handle unknown options - # only answer to positive requests and deny them - if command == WILL or command == DO: - self.telnetSendOption((command == WILL and DONT or WONT), option) - if self.logger: - self.logger.warning("rejected Telnet option: %r" % (option,)) - - - def _telnetProcessSubnegotiation(self, suboption): - """Process subnegotiation, the data between IAC SB and IAC SE.""" - if suboption[0:1] == COM_PORT_OPTION: - if self.logger: - self.logger.debug('received COM_PORT_OPTION: %r' % (suboption,)) - if suboption[1:2] == SET_BAUDRATE: - backup = self.serial.baudrate - try: - (baudrate,) = struct.unpack("!I", suboption[2:6]) - if baudrate != 0: - self.serial.baudrate = baudrate - except ValueError, e: - if self.logger: - self.logger.error("failed to set baud rate: %s" % (e,)) - self.serial.baudrate = backup - else: - if self.logger: - self.logger.info("%s baud rate: %s" % (baudrate and 'set' or 'get', self.serial.baudrate)) - self.rfc2217SendSubnegotiation(SERVER_SET_BAUDRATE, struct.pack("!I", self.serial.baudrate)) - elif suboption[1:2] == SET_DATASIZE: - backup = self.serial.bytesize - try: - (datasize,) = struct.unpack("!B", suboption[2:3]) - if datasize != 0: - self.serial.bytesize = datasize - except ValueError, e: - if self.logger: - self.logger.error("failed to set data size: %s" % (e,)) - self.serial.bytesize = backup - else: - if self.logger: - self.logger.info("%s data size: %s" % (datasize and 'set' or 'get', self.serial.bytesize)) - self.rfc2217SendSubnegotiation(SERVER_SET_DATASIZE, struct.pack("!B", self.serial.bytesize)) - elif suboption[1:2] == SET_PARITY: - backup = self.serial.parity - try: - parity = struct.unpack("!B", suboption[2:3])[0] - if parity != 0: - self.serial.parity = RFC2217_REVERSE_PARITY_MAP[parity] - except ValueError, e: - if self.logger: - self.logger.error("failed to set parity: %s" % (e,)) - self.serial.parity = backup - else: - if self.logger: - self.logger.info("%s parity: %s" % (parity and 'set' or 'get', self.serial.parity)) - self.rfc2217SendSubnegotiation( - SERVER_SET_PARITY, - struct.pack("!B", RFC2217_PARITY_MAP[self.serial.parity]) - ) - elif suboption[1:2] == SET_STOPSIZE: - backup = self.serial.stopbits - try: - stopbits = struct.unpack("!B", suboption[2:3])[0] - if stopbits != 0: - self.serial.stopbits = RFC2217_REVERSE_STOPBIT_MAP[stopbits] - except ValueError, e: - if self.logger: - self.logger.error("failed to set stop bits: %s" % (e,)) - self.serial.stopbits = backup - else: - if self.logger: - self.logger.info("%s stop bits: %s" % (stopbits and 'set' or 'get', self.serial.stopbits)) - self.rfc2217SendSubnegotiation( - SERVER_SET_STOPSIZE, - struct.pack("!B", RFC2217_STOPBIT_MAP[self.serial.stopbits]) - ) - elif suboption[1:2] == SET_CONTROL: - if suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING: - if self.serial.xonxoff: - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif self.serial.rtscts: - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - else: - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL: - self.serial.xonxoff = False - self.serial.rtscts = False - if self.logger: - self.logger.info("changed flow control to None") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_NO_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTROL: - self.serial.xonxoff = True - if self.logger: - self.logger.info("changed flow control to XON/XOFF") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_SW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTROL: - self.serial.rtscts = True - if self.logger: - self.logger.info("changed flow control to RTS/CTS") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_USE_HW_FLOW_CONTROL) - elif suboption[2:3] == SET_CONTROL_REQ_BREAK_STATE: - if self.logger: - self.logger.warning("requested break state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_BREAK_ON: - self.serial.setBreak(True) - if self.logger: - self.logger.info("changed BREAK to active") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_ON) - elif suboption[2:3] == SET_CONTROL_BREAK_OFF: - self.serial.setBreak(False) - if self.logger: - self.logger.info("changed BREAK to inactive") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_BREAK_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_DTR: - if self.logger: - self.logger.warning("requested DTR state - not implemented") - pass # XXX needs cached value - elif suboption[2:3] == SET_CONTROL_DTR_ON: - self.serial.setDTR(True) - if self.logger: - self.logger.info("changed DTR to active") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_ON) - elif suboption[2:3] == SET_CONTROL_DTR_OFF: - self.serial.setDTR(False) - if self.logger: - self.logger.info("changed DTR to inactive") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_DTR_OFF) - elif suboption[2:3] == SET_CONTROL_REQ_RTS: - if self.logger: - self.logger.warning("requested RTS state - not implemented") - pass # XXX needs cached value - #~ self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_ON: - self.serial.setRTS(True) - if self.logger: - self.logger.info("changed RTS to active") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_ON) - elif suboption[2:3] == SET_CONTROL_RTS_OFF: - self.serial.setRTS(False) - if self.logger: - self.logger.info("changed RTS to inactive") - self.rfc2217SendSubnegotiation(SERVER_SET_CONTROL, SET_CONTROL_RTS_OFF) - #~ elif suboption[2:3] == SET_CONTROL_REQ_FLOW_SETTING_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_NO_FLOW_CONTROL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_SW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_HW_FLOW_CONTOL_IN: - #~ elif suboption[2:3] == SET_CONTROL_USE_DCD_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DTR_FLOW_CONTROL: - #~ elif suboption[2:3] == SET_CONTROL_USE_DSR_FLOW_CONTROL: - elif suboption[1:2] == NOTIFY_LINESTATE: - # client polls for current state - self.rfc2217SendSubnegotiation( - SERVER_NOTIFY_LINESTATE, - to_bytes([0]) # sorry, nothing like that implemented - ) - elif suboption[1:2] == NOTIFY_MODEMSTATE: - if self.logger: - self.logger.info("request for modem state") - # client polls for current state - self.check_modem_lines(force_notification=True) - elif suboption[1:2] == FLOWCONTROL_SUSPEND: - if self.logger: - self.logger.info("suspend") - self._remote_suspend_flow = True - elif suboption[1:2] == FLOWCONTROL_RESUME: - if self.logger: - self.logger.info("resume") - self._remote_suspend_flow = False - elif suboption[1:2] == SET_LINESTATE_MASK: - self.linstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("line state mask: 0x%02x" % (self.linstate_mask,)) - elif suboption[1:2] == SET_MODEMSTATE_MASK: - self.modemstate_mask = ord(suboption[2:3]) # ensure it is a number - if self.logger: - self.logger.info("modem state mask: 0x%02x" % (self.modemstate_mask,)) - elif suboption[1:2] == PURGE_DATA: - if suboption[2:3] == PURGE_RECEIVE_BUFFER: - self.serial.flushInput() - if self.logger: - self.logger.info("purge in") - self.rfc2217SendSubnegotiation(SERVER_PURGE_DATA, PURGE_RECEIVE_BUFFER) - elif suboption[2:3] == PURGE_TRANSMIT_BUFFER: - self.serial.flushOutput() - if self.logger: - self.logger.info("purge out") - self.rfc2217SendSubnegotiation(SERVER_PURGE_DATA, PURGE_TRANSMIT_BUFFER) - elif suboption[2:3] == PURGE_BOTH_BUFFERS: - self.serial.flushInput() - self.serial.flushOutput() - if self.logger: - self.logger.info("purge both") - self.rfc2217SendSubnegotiation(SERVER_PURGE_DATA, PURGE_BOTH_BUFFERS) - else: - if self.logger: - self.logger.error("undefined PURGE_DATA: %r" % list(suboption[2:])) - else: - if self.logger: - self.logger.error("undefined COM_PORT_OPTION: %r" % list(suboption[1:])) - else: - if self.logger: - self.logger.warning("unknown subnegotiation: %r" % (suboption,)) - - -# simple client test -if __name__ == '__main__': - import sys - s = Serial('rfc2217://localhost:7000', 115200) - sys.stdout.write('%s\n' % s) - - #~ s.baudrate = 1898 - - sys.stdout.write("write...\n") - s.write("hello\n") - s.flush() - sys.stdout.write("read: %s\n" % s.read(5)) - - #~ s.baudrate = 19200 - #~ s.databits = 7 - s.close() diff --git a/scripts/serial/serialcli.py b/scripts/serial/serialcli.py deleted file mode 100644 index 9ab3876206..0000000000 --- a/scripts/serial/serialcli.py +++ /dev/null @@ -1,284 +0,0 @@ -#! python -# Python Serial Port Extension for Win32, Linux, BSD, Jython and .NET/Mono -# serial driver for .NET/Mono (IronPython), .NET >= 2 -# see __init__.py -# -# (C) 2008 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -import clr -import System -import System.IO.Ports -from serial.serialutil import * - - -def device(portnum): - """Turn a port number into a device name""" - return System.IO.Ports.SerialPort.GetPortNames()[portnum] - - -# must invoke function with byte array, make a helper to convert strings -# to byte arrays -sab = System.Array[System.Byte] -def as_byte_array(string): - return sab([ord(x) for x in string]) # XXX will require adaption when run with a 3.x compatible IronPython - -class IronSerial(SerialBase): - """Serial port implementation for .NET/Mono.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self._isOpen: - raise SerialException("Port is already open.") - try: - self._port_handle = System.IO.Ports.SerialPort(self.portstr) - except Exception, msg: - self._port_handle = None - raise SerialException("could not open port %s: %s" % (self.portstr, msg)) - - self._reconfigurePort() - self._port_handle.Open() - self._isOpen = True - if not self._rtscts: - self.setRTS(True) - self.setDTR(True) - self.flushInput() - self.flushOutput() - - def _reconfigurePort(self): - """Set communication parameters on opened port.""" - if not self._port_handle: - raise SerialException("Can only operate on a valid port handle") - - #~ self._port_handle.ReceivedBytesThreshold = 1 - - if self._timeout is None: - self._port_handle.ReadTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.ReadTimeout = int(self._timeout*1000) - - # if self._timeout != 0 and self._interCharTimeout is not None: - # timeouts = (int(self._interCharTimeout * 1000),) + timeouts[1:] - - if self._writeTimeout is None: - self._port_handle.WriteTimeout = System.IO.Ports.SerialPort.InfiniteTimeout - else: - self._port_handle.WriteTimeout = int(self._writeTimeout*1000) - - - # Setup the connection info. - try: - self._port_handle.BaudRate = self._baudrate - except IOError, e: - # catch errors from illegal baudrate settings - raise ValueError(str(e)) - - if self._bytesize == FIVEBITS: - self._port_handle.DataBits = 5 - elif self._bytesize == SIXBITS: - self._port_handle.DataBits = 6 - elif self._bytesize == SEVENBITS: - self._port_handle.DataBits = 7 - elif self._bytesize == EIGHTBITS: - self._port_handle.DataBits = 8 - else: - raise ValueError("Unsupported number of data bits: %r" % self._bytesize) - - if self._parity == PARITY_NONE: - self._port_handle.Parity = getattr(System.IO.Ports.Parity, 'None') # reserved keyword in Py3k - elif self._parity == PARITY_EVEN: - self._port_handle.Parity = System.IO.Ports.Parity.Even - elif self._parity == PARITY_ODD: - self._port_handle.Parity = System.IO.Ports.Parity.Odd - elif self._parity == PARITY_MARK: - self._port_handle.Parity = System.IO.Ports.Parity.Mark - elif self._parity == PARITY_SPACE: - self._port_handle.Parity = System.IO.Ports.Parity.Space - else: - raise ValueError("Unsupported parity mode: %r" % self._parity) - - if self._stopbits == STOPBITS_ONE: - self._port_handle.StopBits = System.IO.Ports.StopBits.One - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - self._port_handle.StopBits = System.IO.Ports.StopBits.OnePointFive - elif self._stopbits == STOPBITS_TWO: - self._port_handle.StopBits = System.IO.Ports.StopBits.Two - else: - raise ValueError("Unsupported number of stop bits: %r" % self._stopbits) - - if self._rtscts and self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSendXOnXOff - elif self._rtscts: - self._port_handle.Handshake = System.IO.Ports.Handshake.RequestToSend - elif self._xonxoff: - self._port_handle.Handshake = System.IO.Ports.Handshake.XOnXOff - else: - self._port_handle.Handshake = getattr(System.IO.Ports.Handshake, 'None') # reserved keyword in Py3k - - #~ def __del__(self): - #~ self.close() - - def close(self): - """Close port""" - if self._isOpen: - if self._port_handle: - try: - self._port_handle.Close() - except System.IO.Ports.InvalidOperationException: - # ignore errors. can happen for unplugged USB serial devices - pass - self._port_handle = None - self._isOpen = False - - def makeDeviceName(self, port): - try: - return device(port) - except TypeError, e: - raise SerialException(str(e)) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def inWaiting(self): - """Return the number of characters currently in the input buffer.""" - if not self._port_handle: raise portNotOpenError - return self._port_handle.BytesToRead - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self._port_handle: raise portNotOpenError - # must use single byte reads as this is the only way to read - # without applying encodings - data = bytearray() - while size: - try: - data.append(self._port_handle.ReadByte()) - except System.TimeoutException, e: - break - else: - size -= 1 - return bytes(data) - - def write(self, data): - """Output the given string over the serial port.""" - if not self._port_handle: raise portNotOpenError - #~ if not isinstance(data, (bytes, bytearray)): - #~ raise TypeError('expected %s or bytearray, got %s' % (bytes, type(data))) - try: - # must call overloaded method with byte array argument - # as this is the only one not applying encodings - self._port_handle.Write(as_byte_array(data), 0, len(data)) - except System.TimeoutException, e: - raise writeTimeoutError - return len(data) - - def flushInput(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self._port_handle: raise portNotOpenError - self._port_handle.DiscardInBuffer() - - def flushOutput(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self._port_handle: raise portNotOpenError - self._port_handle.DiscardOutBuffer() - - def sendBreak(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self._port_handle: raise portNotOpenError - import time - self._port_handle.BreakState = True - time.sleep(duration) - self._port_handle.BreakState = False - - def setBreak(self, level=True): - """ - Set break: Controls TXD. When active, to transmitting is possible. - """ - if not self._port_handle: raise portNotOpenError - self._port_handle.BreakState = bool(level) - - def setRTS(self, level=True): - """Set terminal status line: Request To Send""" - if not self._port_handle: raise portNotOpenError - self._port_handle.RtsEnable = bool(level) - - def setDTR(self, level=True): - """Set terminal status line: Data Terminal Ready""" - if not self._port_handle: raise portNotOpenError - self._port_handle.DtrEnable = bool(level) - - def getCTS(self): - """Read terminal status line: Clear To Send""" - if not self._port_handle: raise portNotOpenError - return self._port_handle.CtsHolding - - def getDSR(self): - """Read terminal status line: Data Set Ready""" - if not self._port_handle: raise portNotOpenError - return self._port_handle.DsrHolding - - def getRI(self): - """Read terminal status line: Ring Indicator""" - if not self._port_handle: raise portNotOpenError - #~ return self._port_handle.XXX - return False #XXX an error would be better - - def getCD(self): - """Read terminal status line: Carrier Detect""" - if not self._port_handle: raise portNotOpenError - return self._port_handle.CDHolding - - # - - platform specific - - - - - # none - - -# assemble Serial class with the platform specific implementation and the base -# for file-like behavior. for Python 2.6 and newer, that provide the new I/O -# library, derive from io.RawIOBase -try: - import io -except ImportError: - # classic version with our own file-like emulation - class Serial(IronSerial, FileLike): - pass -else: - # io library present - class Serial(IronSerial, io.RawIOBase): - pass - - -# Nur Testfunktion!! -if __name__ == '__main__': - import sys - - s = Serial(0) - sys.stdio.write('%s\n' % s) - - s = Serial() - sys.stdio.write('%s\n' % s) - - - s.baudrate = 19200 - s.databits = 7 - s.close() - s.port = 0 - s.open() - sys.stdio.write('%s\n' % s) - diff --git a/scripts/serial/serialposix.py b/scripts/serial/serialposix.py deleted file mode 100644 index 359ad1b877..0000000000 --- a/scripts/serial/serialposix.py +++ /dev/null @@ -1,730 +0,0 @@ -#!/usr/bin/env python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# module for serial IO for POSIX compatible systems, like Linux -# see __init__.py -# -# (C) 2001-2010 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt -# -# parts based on code from Grant B. Edwards <grante@visi.com>: -# ftp://ftp.visi.com/users/grante/python/PosixSerial.py -# -# references: http://www.easysw.com/~mike/serial/serial.html - -import sys, os, fcntl, termios, struct, select, errno, time -from serial.serialutil import * - -# Do check the Python version as some constants have moved. -if (sys.hexversion < 0x020100f0): - import TERMIOS -else: - TERMIOS = termios - -if (sys.hexversion < 0x020200f0): - import FCNTL -else: - FCNTL = fcntl - -# try to detect the OS so that a device can be selected... -# this code block should supply a device() and set_special_baudrate() function -# for the platform -plat = sys.platform.lower() - -if plat[:5] == 'linux': # Linux (confirmed) - - def device(port): - return '/dev/ttyS%d' % port - - TCGETS2 = 0x802C542A - TCSETS2 = 0x402C542B - BOTHER = 0o010000 - - def set_special_baudrate(port, baudrate): - # right size is 44 on x86_64, allow for some growth - import array - buf = array.array('i', [0] * 64) - - try: - # get serial_struct - FCNTL.ioctl(port.fd, TCGETS2, buf) - # set custom speed - buf[2] &= ~TERMIOS.CBAUD - buf[2] |= BOTHER - buf[9] = buf[10] = baudrate - - # set serial_struct - res = FCNTL.ioctl(port.fd, TCSETS2, buf) - except IOError, e: - raise ValueError('Failed to set custom baud rate (%s): %s' % (baudrate, e)) - - baudrate_constants = { - 0: 0000000, # hang up - 50: 0000001, - 75: 0000002, - 110: 0000003, - 134: 0000004, - 150: 0000005, - 200: 0000006, - 300: 0000007, - 600: 0000010, - 1200: 0000011, - 1800: 0000012, - 2400: 0000013, - 4800: 0000014, - 9600: 0000015, - 19200: 0000016, - 38400: 0000017, - 57600: 0010001, - 115200: 0010002, - 230400: 0010003, - 460800: 0010004, - 500000: 0010005, - 576000: 0010006, - 921600: 0010007, - 1000000: 0010010, - 1152000: 0010011, - 1500000: 0010012, - 2000000: 0010013, - 2500000: 0010014, - 3000000: 0010015, - 3500000: 0010016, - 4000000: 0010017 - } - -elif plat == 'cygwin': # cygwin/win32 (confirmed) - - def device(port): - return '/dev/com%d' % (port + 1) - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = { - 128000: 0x01003, - 256000: 0x01005, - 500000: 0x01007, - 576000: 0x01008, - 921600: 0x01009, - 1000000: 0x0100a, - 1152000: 0x0100b, - 1500000: 0x0100c, - 2000000: 0x0100d, - 2500000: 0x0100e, - 3000000: 0x0100f - } - -elif plat[:7] == 'openbsd': # OpenBSD - - def device(port): - return '/dev/cua%02d' % port - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:3] == 'bsd' or \ - plat[:7] == 'freebsd': - - def device(port): - return '/dev/cuad%d' % port - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:6] == 'darwin': # OS X - - version = os.uname()[2].split('.') - # Tiger or above can support arbitrary serial speeds - if int(version[0]) >= 8: - def set_special_baudrate(port, baudrate): - # use IOKit-specific call to set up high speeds - import array, fcntl - buf = array.array('i', [baudrate]) - IOSSIOSPEED = 0x80045402 #_IOW('T', 2, speed_t) - fcntl.ioctl(port.fd, IOSSIOSPEED, buf, 1) - else: # version < 8 - def set_special_baudrate(port, baudrate): - raise ValueError("baud rate not supported") - - def device(port): - return '/dev/cuad%d' % port - - baudrate_constants = {} - - -elif plat[:6] == 'netbsd': # NetBSD 1.6 testing by Erk - - def device(port): - return '/dev/dty%02d' % port - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:4] == 'irix': # IRIX (partially tested) - - def device(port): - return '/dev/ttyf%d' % (port+1) #XXX different device names depending on flow control - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:2] == 'hp': # HP-UX (not tested) - - def device(port): - return '/dev/tty%dp0' % (port+1) - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:5] == 'sunos': # Solaris/SunOS (confirmed) - - def device(port): - return '/dev/tty%c' % (ord('a')+port) - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -elif plat[:3] == 'aix': # AIX - - def device(port): - return '/dev/tty%d' % (port) - - def set_special_baudrate(port, baudrate): - raise ValueError("sorry don't know how to handle non standard baud rate on this platform") - - baudrate_constants = {} - -else: - # platform detection has failed... - sys.stderr.write("""\ -don't know how to number ttys on this system. -! Use an explicit path (eg /dev/ttyS1) or send this information to -! the author of this module: - -sys.platform = %r -os.name = %r -serialposix.py version = %s - -also add the device name of the serial port and where the -counting starts for the first serial port. -e.g. 'first serial port: /dev/ttyS0' -and with a bit luck you can get this module running... -""" % (sys.platform, os.name, VERSION)) - # no exception, just continue with a brave attempt to build a device name - # even if the device name is not correct for the platform it has chances - # to work using a string with the real device name as port parameter. - def device(portum): - return '/dev/ttyS%d' % portnum - def set_special_baudrate(port, baudrate): - raise SerialException("sorry don't know how to handle non standard baud rate on this platform") - baudrate_constants = {} - #~ raise Exception, "this module does not run on this platform, sorry." - -# whats up with "aix", "beos", .... -# they should work, just need to know the device names. - - -# load some constants for later use. -# try to use values from TERMIOS, use defaults from linux otherwise -TIOCMGET = hasattr(TERMIOS, 'TIOCMGET') and TERMIOS.TIOCMGET or 0x5415 -TIOCMBIS = hasattr(TERMIOS, 'TIOCMBIS') and TERMIOS.TIOCMBIS or 0x5416 -TIOCMBIC = hasattr(TERMIOS, 'TIOCMBIC') and TERMIOS.TIOCMBIC or 0x5417 -TIOCMSET = hasattr(TERMIOS, 'TIOCMSET') and TERMIOS.TIOCMSET or 0x5418 - -#TIOCM_LE = hasattr(TERMIOS, 'TIOCM_LE') and TERMIOS.TIOCM_LE or 0x001 -TIOCM_DTR = hasattr(TERMIOS, 'TIOCM_DTR') and TERMIOS.TIOCM_DTR or 0x002 -TIOCM_RTS = hasattr(TERMIOS, 'TIOCM_RTS') and TERMIOS.TIOCM_RTS or 0x004 -#TIOCM_ST = hasattr(TERMIOS, 'TIOCM_ST') and TERMIOS.TIOCM_ST or 0x008 -#TIOCM_SR = hasattr(TERMIOS, 'TIOCM_SR') and TERMIOS.TIOCM_SR or 0x010 - -TIOCM_CTS = hasattr(TERMIOS, 'TIOCM_CTS') and TERMIOS.TIOCM_CTS or 0x020 -TIOCM_CAR = hasattr(TERMIOS, 'TIOCM_CAR') and TERMIOS.TIOCM_CAR or 0x040 -TIOCM_RNG = hasattr(TERMIOS, 'TIOCM_RNG') and TERMIOS.TIOCM_RNG or 0x080 -TIOCM_DSR = hasattr(TERMIOS, 'TIOCM_DSR') and TERMIOS.TIOCM_DSR or 0x100 -TIOCM_CD = hasattr(TERMIOS, 'TIOCM_CD') and TERMIOS.TIOCM_CD or TIOCM_CAR -TIOCM_RI = hasattr(TERMIOS, 'TIOCM_RI') and TERMIOS.TIOCM_RI or TIOCM_RNG -#TIOCM_OUT1 = hasattr(TERMIOS, 'TIOCM_OUT1') and TERMIOS.TIOCM_OUT1 or 0x2000 -#TIOCM_OUT2 = hasattr(TERMIOS, 'TIOCM_OUT2') and TERMIOS.TIOCM_OUT2 or 0x4000 -if hasattr(TERMIOS, 'TIOCINQ'): - TIOCINQ = TERMIOS.TIOCINQ -else: - TIOCINQ = hasattr(TERMIOS, 'FIONREAD') and TERMIOS.FIONREAD or 0x541B -TIOCOUTQ = hasattr(TERMIOS, 'TIOCOUTQ') and TERMIOS.TIOCOUTQ or 0x5411 - -TIOCM_zero_str = struct.pack('I', 0) -TIOCM_RTS_str = struct.pack('I', TIOCM_RTS) -TIOCM_DTR_str = struct.pack('I', TIOCM_DTR) - -TIOCSBRK = hasattr(TERMIOS, 'TIOCSBRK') and TERMIOS.TIOCSBRK or 0x5427 -TIOCCBRK = hasattr(TERMIOS, 'TIOCCBRK') and TERMIOS.TIOCCBRK or 0x5428 - -CMSPAR = 010000000000 # Use "stick" (mark/space) parity - - -class PosixSerial(SerialBase): - """\ - Serial port class POSIX implementation. Serial port configuration is - done with termios and fcntl. Runs on Linux and many other Un*x like - systems. - """ - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened.""" - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self._isOpen: - raise SerialException("Port is already open.") - self.fd = None - # open - try: - self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK) - except OSError, msg: - self.fd = None - raise SerialException(msg.errno, "could not open port %s: %s" % (self._port, msg)) - #~ fcntl.fcntl(self.fd, FCNTL.F_SETFL, 0) # set blocking - - try: - self._reconfigurePort() - except: - try: - os.close(self.fd) - except: - # ignore any exception when closing the port - # also to keep original exception that happened when setting up - pass - self.fd = None - raise - else: - self._isOpen = True - self.flushInput() - - - def _reconfigurePort(self): - """Set communication parameters on opened port.""" - if self.fd is None: - raise SerialException("Can only operate on a valid file descriptor") - custom_baud = None - - vmin = vtime = 0 # timeout is done via select - if self._interCharTimeout is not None: - vmin = 1 - vtime = int(self._interCharTimeout * 10) - try: - orig_attr = termios.tcgetattr(self.fd) - iflag, oflag, cflag, lflag, ispeed, ospeed, cc = orig_attr - except termios.error, msg: # if a port is nonexistent but has a /dev file, it'll fail here - raise SerialException("Could not configure port: %s" % msg) - # set up raw mode / no echo / binary - cflag |= (TERMIOS.CLOCAL|TERMIOS.CREAD) - lflag &= ~(TERMIOS.ICANON|TERMIOS.ECHO|TERMIOS.ECHOE|TERMIOS.ECHOK|TERMIOS.ECHONL| - TERMIOS.ISIG|TERMIOS.IEXTEN) #|TERMIOS.ECHOPRT - for flag in ('ECHOCTL', 'ECHOKE'): # netbsd workaround for Erk - if hasattr(TERMIOS, flag): - lflag &= ~getattr(TERMIOS, flag) - - oflag &= ~(TERMIOS.OPOST) - iflag &= ~(TERMIOS.INLCR|TERMIOS.IGNCR|TERMIOS.ICRNL|TERMIOS.IGNBRK) - if hasattr(TERMIOS, 'IUCLC'): - iflag &= ~TERMIOS.IUCLC - if hasattr(TERMIOS, 'PARMRK'): - iflag &= ~TERMIOS.PARMRK - - # setup baud rate - try: - ispeed = ospeed = getattr(TERMIOS, 'B%s' % (self._baudrate)) - except AttributeError: - try: - ispeed = ospeed = baudrate_constants[self._baudrate] - except KeyError: - #~ raise ValueError('Invalid baud rate: %r' % self._baudrate) - # may need custom baud rate, it isn't in our list. - ispeed = ospeed = getattr(TERMIOS, 'B38400') - try: - custom_baud = int(self._baudrate) # store for later - except ValueError: - raise ValueError('Invalid baud rate: %r' % self._baudrate) - else: - if custom_baud < 0: - raise ValueError('Invalid baud rate: %r' % self._baudrate) - - # setup char len - cflag &= ~TERMIOS.CSIZE - if self._bytesize == 8: - cflag |= TERMIOS.CS8 - elif self._bytesize == 7: - cflag |= TERMIOS.CS7 - elif self._bytesize == 6: - cflag |= TERMIOS.CS6 - elif self._bytesize == 5: - cflag |= TERMIOS.CS5 - else: - raise ValueError('Invalid char len: %r' % self._bytesize) - # setup stop bits - if self._stopbits == STOPBITS_ONE: - cflag &= ~(TERMIOS.CSTOPB) - elif self._stopbits == STOPBITS_ONE_POINT_FIVE: - cflag |= (TERMIOS.CSTOPB) # XXX same as TWO.. there is no POSIX support for 1.5 - elif self._stopbits == STOPBITS_TWO: - cflag |= (TERMIOS.CSTOPB) - else: - raise ValueError('Invalid stop bit specification: %r' % self._stopbits) - # setup parity - iflag &= ~(TERMIOS.INPCK|TERMIOS.ISTRIP) - if self._parity == PARITY_NONE: - cflag &= ~(TERMIOS.PARENB|TERMIOS.PARODD) - elif self._parity == PARITY_EVEN: - cflag &= ~(TERMIOS.PARODD) - cflag |= (TERMIOS.PARENB) - elif self._parity == PARITY_ODD: - cflag |= (TERMIOS.PARENB|TERMIOS.PARODD) - elif self._parity == PARITY_MARK and plat[:5] == 'linux': - cflag |= (TERMIOS.PARENB|CMSPAR|TERMIOS.PARODD) - elif self._parity == PARITY_SPACE and plat[:5] == 'linux': - cflag |= (TERMIOS.PARENB|CMSPAR) - cflag &= ~(TERMIOS.PARODD) - else: - raise ValueError('Invalid parity: %r' % self._parity) - # setup flow control - # xonxoff - if hasattr(TERMIOS, 'IXANY'): - if self._xonxoff: - iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) #|TERMIOS.IXANY) - else: - iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF|TERMIOS.IXANY) - else: - if self._xonxoff: - iflag |= (TERMIOS.IXON|TERMIOS.IXOFF) - else: - iflag &= ~(TERMIOS.IXON|TERMIOS.IXOFF) - # rtscts - if hasattr(TERMIOS, 'CRTSCTS'): - if self._rtscts: - cflag |= (TERMIOS.CRTSCTS) - else: - cflag &= ~(TERMIOS.CRTSCTS) - elif hasattr(TERMIOS, 'CNEW_RTSCTS'): # try it with alternate constant name - if self._rtscts: - cflag |= (TERMIOS.CNEW_RTSCTS) - else: - cflag &= ~(TERMIOS.CNEW_RTSCTS) - # XXX should there be a warning if setting up rtscts (and xonxoff etc) fails?? - - # buffer - # vmin "minimal number of characters to be read. 0 for non blocking" - if vmin < 0 or vmin > 255: - raise ValueError('Invalid vmin: %r ' % vmin) - cc[TERMIOS.VMIN] = vmin - # vtime - if vtime < 0 or vtime > 255: - raise ValueError('Invalid vtime: %r' % vtime) - cc[TERMIOS.VTIME] = vtime - # activate settings - if [iflag, oflag, cflag, lflag, ispeed, ospeed, cc] != orig_attr: - termios.tcsetattr(self.fd, TERMIOS.TCSANOW, [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]) - - # apply custom baud rate, if any - if custom_baud is not None: - set_special_baudrate(self, custom_baud) - - def close(self): - """Close port""" - if self._isOpen: - if self.fd is not None: - os.close(self.fd) - self.fd = None - self._isOpen = False - - def makeDeviceName(self, port): - return device(port) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def inWaiting(self): - """Return the number of characters currently in the input buffer.""" - #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCINQ, TIOCM_zero_str) - return struct.unpack('I',s)[0] - - # select based implementation, proved to work on many systems - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self._isOpen: raise portNotOpenError - read = bytearray() - while len(read) < size: - try: - ready,_,_ = select.select([self.fd],[],[], self._timeout) - # If select was used with a timeout, and the timeout occurs, it - # returns with empty lists -> thus abort read operation. - # For timeout == 0 (non-blocking operation) also abort when there - # is nothing to read. - if not ready: - break # timeout - buf = os.read(self.fd, size-len(read)) - # read should always return some data as select reported it was - # ready to read when we get to this point. - if not buf: - # Disconnected devices, at least on Linux, show the - # behavior that they are always ready to read immediately - # but reading returns nothing. - raise SerialException('device reports readiness to read but returned no data (device disconnected or multiple access on port?)') - read.extend(buf) - except OSError, e: - # this is for Python 3.x where select.error is a subclass of OSError - # ignore EAGAIN errors. all other errors are shown - if e.errno != errno.EAGAIN: - raise SerialException('read failed: %s' % (e,)) - except select.error, e: - # this is for Python 2.x - # ignore EAGAIN errors. all other errors are shown - # see also http://www.python.org/dev/peps/pep-3151/#select - if e[0] != errno.EAGAIN: - raise SerialException('read failed: %s' % (e,)) - return bytes(read) - - def write(self, data): - """Output the given string over the serial port.""" - if not self._isOpen: raise portNotOpenError - d = to_bytes(data) - tx_len = len(d) - if self._writeTimeout is not None and self._writeTimeout > 0: - timeout = time.time() + self._writeTimeout - else: - timeout = None - while tx_len > 0: - try: - n = os.write(self.fd, d) - if timeout: - # when timeout is set, use select to wait for being ready - # with the time left as timeout - timeleft = timeout - time.time() - if timeleft < 0: - raise writeTimeoutError - _, ready, _ = select.select([], [self.fd], [], timeleft) - if not ready: - raise writeTimeoutError - else: - # wait for write operation - _, ready, _ = select.select([], [self.fd], [], None) - if not ready: - raise SerialException('write failed (select)') - d = d[n:] - tx_len -= n - except OSError, v: - if v.errno != errno.EAGAIN: - raise SerialException('write failed: %s' % (v,)) - return len(data) - - def flush(self): - """\ - Flush of file like objects. In this case, wait until all data - is written. - """ - self.drainOutput() - - def flushInput(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self._isOpen: raise portNotOpenError - termios.tcflush(self.fd, TERMIOS.TCIFLUSH) - - def flushOutput(self): - """\ - Clear output buffer, aborting the current output and discarding all - that is in the buffer. - """ - if not self._isOpen: raise portNotOpenError - termios.tcflush(self.fd, TERMIOS.TCOFLUSH) - - def sendBreak(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self._isOpen: raise portNotOpenError - termios.tcsendbreak(self.fd, int(duration/0.25)) - - def setBreak(self, level=1): - """\ - Set break: Controls TXD. When active, no transmitting is possible. - """ - if self.fd is None: raise portNotOpenError - if level: - fcntl.ioctl(self.fd, TIOCSBRK) - else: - fcntl.ioctl(self.fd, TIOCCBRK) - - def setRTS(self, level=1): - """Set terminal status line: Request To Send""" - if not self._isOpen: raise portNotOpenError - if level: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_RTS_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_RTS_str) - - def setDTR(self, level=1): - """Set terminal status line: Data Terminal Ready""" - if not self._isOpen: raise portNotOpenError - if level: - fcntl.ioctl(self.fd, TIOCMBIS, TIOCM_DTR_str) - else: - fcntl.ioctl(self.fd, TIOCMBIC, TIOCM_DTR_str) - - def getCTS(self): - """Read terminal status line: Clear To Send""" - if not self._isOpen: raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I',s)[0] & TIOCM_CTS != 0 - - def getDSR(self): - """Read terminal status line: Data Set Ready""" - if not self._isOpen: raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I',s)[0] & TIOCM_DSR != 0 - - def getRI(self): - """Read terminal status line: Ring Indicator""" - if not self._isOpen: raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I',s)[0] & TIOCM_RI != 0 - - def getCD(self): - """Read terminal status line: Carrier Detect""" - if not self._isOpen: raise portNotOpenError - s = fcntl.ioctl(self.fd, TIOCMGET, TIOCM_zero_str) - return struct.unpack('I',s)[0] & TIOCM_CD != 0 - - # - - platform specific - - - - - - def outWaiting(self): - """Return the number of characters currently in the output buffer.""" - #~ s = fcntl.ioctl(self.fd, TERMIOS.FIONREAD, TIOCM_zero_str) - s = fcntl.ioctl(self.fd, TIOCOUTQ, TIOCM_zero_str) - return struct.unpack('I',s)[0] - - def drainOutput(self): - """internal - not portable!""" - if not self._isOpen: raise portNotOpenError - termios.tcdrain(self.fd) - - def nonblocking(self): - """internal - not portable!""" - if not self._isOpen: raise portNotOpenError - fcntl.fcntl(self.fd, FCNTL.F_SETFL, os.O_NONBLOCK) - - def fileno(self): - """\ - For easier use of the serial port instance with select. - WARNING: this function is not portable to different platforms! - """ - if not self._isOpen: raise portNotOpenError - return self.fd - - def setXON(self, level=True): - """\ - Manually control flow - when software flow control is enabled. - This will send XON (true) and XOFF (false) to the other device. - WARNING: this function is not portable to different platforms! - """ - if not self.hComPort: raise portNotOpenError - if enable: - termios.tcflow(self.fd, TERMIOS.TCION) - else: - termios.tcflow(self.fd, TERMIOS.TCIOFF) - - def flowControlOut(self, enable): - """\ - Manually control flow of outgoing data - when hardware or software flow - control is enabled. - WARNING: this function is not portable to different platforms! - """ - if not self._isOpen: raise portNotOpenError - if enable: - termios.tcflow(self.fd, TERMIOS.TCOON) - else: - termios.tcflow(self.fd, TERMIOS.TCOOFF) - - -# assemble Serial class with the platform specific implementation and the base -# for file-like behavior. for Python 2.6 and newer, that provide the new I/O -# library, derive from io.RawIOBase -try: - import io -except ImportError: - # classic version with our own file-like emulation - class Serial(PosixSerial, FileLike): - pass -else: - # io library present - class Serial(PosixSerial, io.RawIOBase): - pass - -class PosixPollSerial(Serial): - """\ - Poll based read implementation. Not all systems support poll properly. - However this one has better handling of errors, such as a device - disconnecting while it's in use (e.g. USB-serial unplugged). - """ - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if self.fd is None: raise portNotOpenError - read = bytearray() - poll = select.poll() - poll.register(self.fd, select.POLLIN|select.POLLERR|select.POLLHUP|select.POLLNVAL) - if size > 0: - while len(read) < size: - # print "\tread(): size",size, "have", len(read) #debug - # wait until device becomes ready to read (or something fails) - for fd, event in poll.poll(self._timeout*1000): - if event & (select.POLLERR|select.POLLHUP|select.POLLNVAL): - raise SerialException('device reports error (poll)') - # we don't care if it is select.POLLIN or timeout, that's - # handled below - buf = os.read(self.fd, size - len(read)) - read.extend(buf) - if ((self._timeout is not None and self._timeout >= 0) or - (self._interCharTimeout is not None and self._interCharTimeout > 0)) and not buf: - break # early abort on timeout - return bytes(read) - - -if __name__ == '__main__': - s = Serial(0, - baudrate=19200, # baud rate - bytesize=EIGHTBITS, # number of data bits - parity=PARITY_EVEN, # enable parity checking - stopbits=STOPBITS_ONE, # number of stop bits - timeout=3, # set a timeout value, None for waiting forever - xonxoff=0, # enable software flow control - rtscts=0, # enable RTS/CTS flow control - ) - s.setRTS(1) - s.setDTR(1) - s.flushInput() - s.flushOutput() - s.write('hello') - sys.stdout.write('%r\n' % s.read(5)) - sys.stdout.write('%s\n' % s.inWaiting()) - del s - diff --git a/scripts/serial/serialutil.py b/scripts/serial/serialutil.py deleted file mode 100644 index af0d2f6402..0000000000 --- a/scripts/serial/serialutil.py +++ /dev/null @@ -1,572 +0,0 @@ -#! python -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see __init__.py -# -# (C) 2001-2010 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -# compatibility for older Python < 2.6 -try: - bytes - bytearray -except (NameError, AttributeError): - # Python older than 2.6 do not have these types. Like for Python 2.6 they - # should behave like str. For Python older than 3.0 we want to work with - # strings anyway, only later versions have a true bytes type. - bytes = str - # bytearray is a mutable type that is easily turned into an instance of - # bytes - class bytearray(list): - # for bytes(bytearray()) usage - def __str__(self): return ''.join(self) - def __repr__(self): return 'bytearray(%r)' % ''.join(self) - # append automatically converts integers to characters - def append(self, item): - if isinstance(item, str): - list.append(self, item) - else: - list.append(self, chr(item)) - # += - def __iadd__(self, other): - for byte in other: - self.append(byte) - return self - - def __getslice__(self, i, j): - return bytearray(list.__getslice__(self, i, j)) - - def __getitem__(self, item): - if isinstance(item, slice): - return bytearray(list.__getitem__(self, item)) - else: - return ord(list.__getitem__(self, item)) - - def __eq__(self, other): - if isinstance(other, basestring): - other = bytearray(other) - return list.__eq__(self, other) - -# ``memoryview`` was introduced in Python 2.7 and ``bytes(some_memoryview)`` -# isn't returning the contents (very unfortunate). Therefore we need special -# cases and test for it. Ensure that there is a ``memoryview`` object for older -# Python versions. This is easier than making every test dependent on its -# existence. -try: - memoryview -except (NameError, AttributeError): - # implementation does not matter as we do not realy use it. - # it just must not inherit from something else we might care for. - class memoryview: - pass - - -# all Python versions prior 3.x convert ``str([17])`` to '[17]' instead of '\x11' -# so a simple ``bytes(sequence)`` doesn't work for all versions -def to_bytes(seq): - """convert a sequence to a bytes type""" - if isinstance(seq, bytes): - return seq - elif isinstance(seq, bytearray): - return bytes(seq) - elif isinstance(seq, memoryview): - return seq.tobytes() - else: - b = bytearray() - for item in seq: - b.append(item) # this one handles int and str for our emulation and ints for Python 3.x - return bytes(b) - -# create control bytes -XON = to_bytes([17]) -XOFF = to_bytes([19]) - -CR = to_bytes([13]) -LF = to_bytes([10]) - - -PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE = 'N', 'E', 'O', 'M', 'S' -STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO = (1, 1.5, 2) -FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS = (5, 6, 7, 8) - -PARITY_NAMES = { - PARITY_NONE: 'None', - PARITY_EVEN: 'Even', - PARITY_ODD: 'Odd', - PARITY_MARK: 'Mark', - PARITY_SPACE: 'Space', -} - - -class SerialException(IOError): - """Base class for serial port related exceptions.""" - - -class SerialTimeoutException(SerialException): - """Write timeouts give an exception""" - - -writeTimeoutError = SerialTimeoutException('Write timeout') -portNotOpenError = SerialException('Attempting to use a port that is not open') - - -class FileLike(object): - """\ - An abstract file like class. - - This class implements readline and readlines based on read and - writelines based on write. - This class is used to provide the above functions for to Serial - port objects. - - Note that when the serial port was opened with _NO_ timeout that - readline blocks until it sees a newline (or the specified size is - reached) and that readlines would never return and therefore - refuses to work (it raises an exception in this case)! - """ - - def __init__(self): - self.closed = True - - def close(self): - self.closed = True - - # so that ports are closed when objects are discarded - def __del__(self): - """Destructor. Calls close().""" - # The try/except block is in case this is called at program - # exit time, when it's possible that globals have already been - # deleted, and then the close() call might fail. Since - # there's nothing we can do about such failures and they annoy - # the end users, we suppress the traceback. - try: - self.close() - except: - pass - - def writelines(self, sequence): - for line in sequence: - self.write(line) - - def flush(self): - """flush of file like objects""" - pass - - # iterator for e.g. "for line in Serial(0): ..." usage - def next(self): - line = self.readline() - if not line: raise StopIteration - return line - - def __iter__(self): - return self - - def readline(self, size=None, eol=LF): - """\ - Read a line which is terminated with end-of-line (eol) character - ('\n' by default) or until timeout. - """ - leneol = len(eol) - line = bytearray() - while True: - c = self.read(1) - if c: - line += c - if line[-leneol:] == eol: - break - if size is not None and len(line) >= size: - break - else: - break - return bytes(line) - - def readlines(self, sizehint=None, eol=LF): - """\ - Read a list of lines, until timeout. - sizehint is ignored. - """ - if self.timeout is None: - raise ValueError("Serial port MUST have enabled timeout for this function!") - leneol = len(eol) - lines = [] - while True: - line = self.readline(eol=eol) - if line: - lines.append(line) - if line[-leneol:] != eol: # was the line received with a timeout? - break - else: - break - return lines - - def xreadlines(self, sizehint=None): - """\ - Read lines, implemented as generator. It will raise StopIteration on - timeout (empty read). sizehint is ignored. - """ - while True: - line = self.readline() - if not line: break - yield line - - # other functions of file-likes - not used by pySerial - - #~ readinto(b) - - def seek(self, pos, whence=0): - raise IOError("file is not seekable") - - def tell(self): - raise IOError("file is not seekable") - - def truncate(self, n=None): - raise IOError("file is not seekable") - - def isatty(self): - return False - - -class SerialBase(object): - """\ - Serial port base class. Provides __init__ function and properties to - get/set port settings. - """ - - # default values, may be overridden in subclasses that do not support all values - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, - 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, - 3000000, 3500000, 4000000) - BYTESIZES = (FIVEBITS, SIXBITS, SEVENBITS, EIGHTBITS) - PARITIES = (PARITY_NONE, PARITY_EVEN, PARITY_ODD, PARITY_MARK, PARITY_SPACE) - STOPBITS = (STOPBITS_ONE, STOPBITS_ONE_POINT_FIVE, STOPBITS_TWO) - - def __init__(self, - port = None, # number of device, numbering starts at - # zero. if everything fails, the user - # can specify a device string, note - # that this isn't portable anymore - # port will be opened if one is specified - baudrate=9600, # baud rate - bytesize=EIGHTBITS, # number of data bits - parity=PARITY_NONE, # enable parity checking - stopbits=STOPBITS_ONE, # number of stop bits - timeout=None, # set a timeout value, None to wait forever - xonxoff=False, # enable software flow control - rtscts=False, # enable RTS/CTS flow control - writeTimeout=None, # set a timeout for writes - dsrdtr=False, # None: use rtscts setting, dsrdtr override if True or False - interCharTimeout=None # Inter-character timeout, None to disable - ): - """\ - Initialize comm port object. If a port is given, then the port will be - opened immediately. Otherwise a Serial port object in closed state - is returned. - """ - - self._isOpen = False - self._port = None # correct value is assigned below through properties - self._baudrate = None # correct value is assigned below through properties - self._bytesize = None # correct value is assigned below through properties - self._parity = None # correct value is assigned below through properties - self._stopbits = None # correct value is assigned below through properties - self._timeout = None # correct value is assigned below through properties - self._writeTimeout = None # correct value is assigned below through properties - self._xonxoff = None # correct value is assigned below through properties - self._rtscts = None # correct value is assigned below through properties - self._dsrdtr = None # correct value is assigned below through properties - self._interCharTimeout = None # correct value is assigned below through properties - - # assign values using get/set methods using the properties feature - self.port = port - self.baudrate = baudrate - self.bytesize = bytesize - self.parity = parity - self.stopbits = stopbits - self.timeout = timeout - self.writeTimeout = writeTimeout - self.xonxoff = xonxoff - self.rtscts = rtscts - self.dsrdtr = dsrdtr - self.interCharTimeout = interCharTimeout - - if port is not None: - self.open() - - def isOpen(self): - """Check if the port is opened.""" - return self._isOpen - - # - - - - - - - - - - - - - - - - - - - - - - - - - - # TODO: these are not really needed as the is the BAUDRATES etc. attribute... - # maybe i remove them before the final release... - - def getSupportedBaudrates(self): - return [(str(b), b) for b in self.BAUDRATES] - - def getSupportedByteSizes(self): - return [(str(b), b) for b in self.BYTESIZES] - - def getSupportedStopbits(self): - return [(str(b), b) for b in self.STOPBITS] - - def getSupportedParities(self): - return [(PARITY_NAMES[b], b) for b in self.PARITIES] - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def setPort(self, port): - """\ - Change the port. The attribute portstr is set to a string that - contains the name of the port. - """ - - was_open = self._isOpen - if was_open: self.close() - if port is not None: - if isinstance(port, basestring): - self.portstr = port - else: - self.portstr = self.makeDeviceName(port) - else: - self.portstr = None - self._port = port - self.name = self.portstr - if was_open: self.open() - - def getPort(self): - """\ - Get the current port setting. The value that was passed on init or using - setPort() is passed back. See also the attribute portstr which contains - the name of the port as a string. - """ - return self._port - - port = property(getPort, setPort, doc="Port setting") - - - def setBaudrate(self, baudrate): - """\ - Change baud rate. It raises a ValueError if the port is open and the - baud rate is not possible. If the port is closed, then the value is - accepted and the exception is raised when the port is opened. - """ - try: - b = int(baudrate) - except TypeError: - raise ValueError("Not a valid baudrate: %r" % (baudrate,)) - else: - if b <= 0: - raise ValueError("Not a valid baudrate: %r" % (baudrate,)) - self._baudrate = b - if self._isOpen: self._reconfigurePort() - - def getBaudrate(self): - """Get the current baud rate setting.""" - return self._baudrate - - baudrate = property(getBaudrate, setBaudrate, doc="Baud rate setting") - - - def setByteSize(self, bytesize): - """Change byte size.""" - if bytesize not in self.BYTESIZES: raise ValueError("Not a valid byte size: %r" % (bytesize,)) - self._bytesize = bytesize - if self._isOpen: self._reconfigurePort() - - def getByteSize(self): - """Get the current byte size setting.""" - return self._bytesize - - bytesize = property(getByteSize, setByteSize, doc="Byte size setting") - - - def setParity(self, parity): - """Change parity setting.""" - if parity not in self.PARITIES: raise ValueError("Not a valid parity: %r" % (parity,)) - self._parity = parity - if self._isOpen: self._reconfigurePort() - - def getParity(self): - """Get the current parity setting.""" - return self._parity - - parity = property(getParity, setParity, doc="Parity setting") - - - def setStopbits(self, stopbits): - """Change stop bits size.""" - if stopbits not in self.STOPBITS: raise ValueError("Not a valid stop bit size: %r" % (stopbits,)) - self._stopbits = stopbits - if self._isOpen: self._reconfigurePort() - - def getStopbits(self): - """Get the current stop bits setting.""" - return self._stopbits - - stopbits = property(getStopbits, setStopbits, doc="Stop bits setting") - - - def setTimeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - try: - timeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: %r" % (timeout,)) - if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,)) - self._timeout = timeout - if self._isOpen: self._reconfigurePort() - - def getTimeout(self): - """Get the current timeout setting.""" - return self._timeout - - timeout = property(getTimeout, setTimeout, doc="Timeout setting for read()") - - - def setWriteTimeout(self, timeout): - """Change timeout setting.""" - if timeout is not None: - if timeout < 0: raise ValueError("Not a valid timeout: %r" % (timeout,)) - try: - timeout + 1 #test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: %r" % timeout) - - self._writeTimeout = timeout - if self._isOpen: self._reconfigurePort() - - def getWriteTimeout(self): - """Get the current timeout setting.""" - return self._writeTimeout - - writeTimeout = property(getWriteTimeout, setWriteTimeout, doc="Timeout setting for write()") - - - def setXonXoff(self, xonxoff): - """Change XON/XOFF setting.""" - self._xonxoff = xonxoff - if self._isOpen: self._reconfigurePort() - - def getXonXoff(self): - """Get the current XON/XOFF setting.""" - return self._xonxoff - - xonxoff = property(getXonXoff, setXonXoff, doc="XON/XOFF setting") - - def setRtsCts(self, rtscts): - """Change RTS/CTS flow control setting.""" - self._rtscts = rtscts - if self._isOpen: self._reconfigurePort() - - def getRtsCts(self): - """Get the current RTS/CTS flow control setting.""" - return self._rtscts - - rtscts = property(getRtsCts, setRtsCts, doc="RTS/CTS flow control setting") - - def setDsrDtr(self, dsrdtr=None): - """Change DsrDtr flow control setting.""" - if dsrdtr is None: - # if not set, keep backwards compatibility and follow rtscts setting - self._dsrdtr = self._rtscts - else: - # if defined independently, follow its value - self._dsrdtr = dsrdtr - if self._isOpen: self._reconfigurePort() - - def getDsrDtr(self): - """Get the current DSR/DTR flow control setting.""" - return self._dsrdtr - - dsrdtr = property(getDsrDtr, setDsrDtr, "DSR/DTR flow control setting") - - def setInterCharTimeout(self, interCharTimeout): - """Change inter-character timeout setting.""" - if interCharTimeout is not None: - if interCharTimeout < 0: raise ValueError("Not a valid timeout: %r" % interCharTimeout) - try: - interCharTimeout + 1 # test if it's a number, will throw a TypeError if not... - except TypeError: - raise ValueError("Not a valid timeout: %r" % interCharTimeout) - - self._interCharTimeout = interCharTimeout - if self._isOpen: self._reconfigurePort() - - def getInterCharTimeout(self): - """Get the current inter-character timeout setting.""" - return self._interCharTimeout - - interCharTimeout = property(getInterCharTimeout, setInterCharTimeout, doc="Inter-character timeout setting for read()") - - # - - - - - - - - - - - - - - - - - - - - - - - - - - _SETTINGS = ('baudrate', 'bytesize', 'parity', 'stopbits', 'xonxoff', - 'dsrdtr', 'rtscts', 'timeout', 'writeTimeout', 'interCharTimeout') - - def getSettingsDict(self): - """\ - Get current port settings as a dictionary. For use with - applySettingsDict. - """ - return dict([(key, getattr(self, '_'+key)) for key in self._SETTINGS]) - - def applySettingsDict(self, d): - """\ - apply stored settings from a dictionary returned from - getSettingsDict. it's allowed to delete keys from the dictionary. these - values will simply left unchanged. - """ - for key in self._SETTINGS: - if d[key] != getattr(self, '_'+key): # check against internal "_" value - setattr(self, key, d[key]) # set non "_" value to use properties write function - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def __repr__(self): - """String representation of the current port settings and its state.""" - return "%s<id=0x%x, open=%s>(port=%r, baudrate=%r, bytesize=%r, parity=%r, stopbits=%r, timeout=%r, xonxoff=%r, rtscts=%r, dsrdtr=%r)" % ( - self.__class__.__name__, - id(self), - self._isOpen, - self.portstr, - self.baudrate, - self.bytesize, - self.parity, - self.stopbits, - self.timeout, - self.xonxoff, - self.rtscts, - self.dsrdtr, - ) - - - # - - - - - - - - - - - - - - - - - - - - - - - - - # compatibility with io library - - def readable(self): return True - def writable(self): return True - def seekable(self): return False - def readinto(self, b): - data = self.read(len(b)) - n = len(data) - try: - b[:n] = data - except TypeError, err: - import array - if not isinstance(b, array.array): - raise err - b[:n] = array.array('b', data) - return n - - -if __name__ == '__main__': - import sys - s = SerialBase() - sys.stdout.write('port name: %s\n' % s.portstr) - sys.stdout.write('baud rates: %s\n' % s.getSupportedBaudrates()) - sys.stdout.write('byte sizes: %s\n' % s.getSupportedByteSizes()) - sys.stdout.write('parities: %s\n' % s.getSupportedParities()) - sys.stdout.write('stop bits: %s\n' % s.getSupportedStopbits()) - sys.stdout.write('%s\n' % s) diff --git a/scripts/serial/tools/__init__.py b/scripts/serial/tools/__init__.py deleted file mode 100644 index 0efe34b218..0000000000 --- a/scripts/serial/tools/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# empty #
\ No newline at end of file diff --git a/scripts/serial/tools/list_ports.py b/scripts/serial/tools/list_ports.py deleted file mode 100644 index d373a5566d..0000000000 --- a/scripts/serial/tools/list_ports.py +++ /dev/null @@ -1,103 +0,0 @@ -#!/usr/bin/env python - -# portable serial port access with python -# this is a wrapper module for different platform implementations of the -# port enumeration feature -# -# (C) 2011-2013 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -"""\ -This module will provide a function called comports that returns an -iterable (generator or list) that will enumerate available com ports. Note that -on some systems non-existent ports may be listed. - -Additionally a grep function is supplied that can be used to search for ports -based on their descriptions or hardware ID. -""" - -import sys, os, re - -# chose an implementation, depending on os -#~ if sys.platform == 'cli': -#~ else: -import os -# chose an implementation, depending on os -if os.name == 'nt': #sys.platform == 'win32': - from serial.tools.list_ports_windows import * -elif os.name == 'posix': - from serial.tools.list_ports_posix import * -#~ elif os.name == 'java': -else: - raise ImportError("Sorry: no implementation for your platform ('%s') available" % (os.name,)) - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def grep(regexp): - """\ - Search for ports using a regular expression. Port name, description and - hardware ID are searched. The function returns an iterable that returns the - same tuples as comport() would do. - """ - r = re.compile(regexp, re.I) - for port, desc, hwid in comports(): - if r.search(port) or r.search(desc) or r.search(hwid): - yield port, desc, hwid - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -def main(): - import optparse - - parser = optparse.OptionParser( - usage = "%prog [options] [<regexp>]", - description = "Miniterm - A simple terminal program for the serial port." - ) - - parser.add_option("--debug", - help="print debug messages and tracebacks (development mode)", - dest="debug", - default=False, - action='store_true') - - parser.add_option("-v", "--verbose", - help="show more messages (can be given multiple times)", - dest="verbose", - default=1, - action='count') - - parser.add_option("-q", "--quiet", - help="suppress all messages", - dest="verbose", - action='store_const', - const=0) - - (options, args) = parser.parse_args() - - - hits = 0 - # get iteraror w/ or w/o filter - if args: - if len(args) > 1: - parser.error('more than one regexp not supported') - print "Filtered list with regexp: %r" % (args[0],) - iterator = sorted(grep(args[0])) - else: - iterator = sorted(comports()) - # list them - for port, desc, hwid in iterator: - print("%-20s" % (port,)) - if options.verbose > 1: - print(" desc: %s" % (desc,)) - print(" hwid: %s" % (hwid,)) - hits += 1 - if options.verbose: - if hits: - print("%d ports found" % (hits,)) - else: - print("no ports found") - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# test -if __name__ == '__main__': - main() diff --git a/scripts/serial/tools/list_ports_linux.py b/scripts/serial/tools/list_ports_linux.py deleted file mode 100644 index 955761eaa4..0000000000 --- a/scripts/serial/tools/list_ports_linux.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python
-
-# portable serial port access with python
-#
-# This is a module that gathers a list of serial ports including details on
-# GNU/Linux systems
-#
-# (C) 2011-2013 Chris Liechti <cliechti@gmx.net>
-# this is distributed under a free software license, see license.txt
-
-import glob
-import sys
-import os
-import re
-
-try:
- import subprocess
-except ImportError:
- def popen(argv):
- try:
- si, so = os.popen4(' '.join(argv))
- return so.read().strip()
- except:
- raise IOError('lsusb failed')
-else:
- def popen(argv):
- try:
- return subprocess.check_output(argv, stderr=subprocess.STDOUT).strip()
- except:
- raise IOError('lsusb failed')
-
-
-# The comports function is expected to return an iterable that yields tuples of
-# 3 strings: port name, human readable description and a hardware ID.
-#
-# as currently no method is known to get the second two strings easily, they
-# are currently just identical to the port name.
-
-# try to detect the OS so that a device can be selected...
-plat = sys.platform.lower()
-
-def read_line(filename):
- """\
- Helper function to read a single line from a file.
- Returns None on errors..
- """
- try:
- f = open(filename)
- line = f.readline().strip()
- f.close()
- return line
- except IOError:
- return None
-
-def re_group(regexp, text):
- """search for regexp in text, return 1st group on match"""
- if sys.version < '3':
- m = re.search(regexp, text)
- else:
- # text is bytes-like
- m = re.search(regexp, text.decode('ascii', 'replace'))
- if m: return m.group(1)
-
-
-# try to extract descriptions from sysfs. this was done by experimenting,
-# no guarantee that it works for all devices or in the future...
-
-def usb_sysfs_hw_string(sysfs_path):
- """given a path to a usb device in sysfs, return a string describing it"""
- bus, dev = os.path.basename(os.path.realpath(sysfs_path)).split('-')
- snr = read_line(sysfs_path+'/serial')
- if snr:
- snr_txt = ' SNR=%s' % (snr,)
- else:
- snr_txt = ''
- return 'USB VID:PID=%s:%s%s' % (
- read_line(sysfs_path+'/idVendor'),
- read_line(sysfs_path+'/idProduct'),
- snr_txt
- )
-
-def usb_lsusb_string(sysfs_path):
- base = os.path.basename(os.path.realpath(sysfs_path))
- bus = base.split('-')[0]
- try:
- dev = int(read_line(os.path.join(sysfs_path, 'devnum')))
- desc = popen(['lsusb', '-v', '-s', '%s:%s' % (bus, dev)])
- # descriptions from device
- iManufacturer = re_group('iManufacturer\s+\w+ (.+)', desc)
- iProduct = re_group('iProduct\s+\w+ (.+)', desc)
- iSerial = re_group('iSerial\s+\w+ (.+)', desc) or ''
- # descriptions from kernel
- idVendor = re_group('idVendor\s+0x\w+ (.+)', desc)
- idProduct = re_group('idProduct\s+0x\w+ (.+)', desc)
- # create descriptions. prefer text from device, fall back to the others
- return '%s %s %s' % (iManufacturer or idVendor, iProduct or idProduct, iSerial)
- except IOError:
- return base
-
-def describe(device):
- """\
- Get a human readable description.
- For USB-Serial devices try to run lsusb to get a human readable description.
- For USB-CDC devices read the description from sysfs.
- """
- base = os.path.basename(device)
- # USB-Serial devices
- sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
- if os.path.exists(sys_dev_path):
- sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
- return usb_lsusb_string(sys_usb)
- # USB-CDC devices
- sys_dev_path = '/sys/class/tty/%s/device/interface' % (base,)
- if os.path.exists(sys_dev_path):
- return read_line(sys_dev_path)
- # USB Product Information
- sys_dev_path = '/sys/class/tty/%s/device' % (base,)
- if os.path.exists(sys_dev_path):
- product_name_file = os.path.dirname(os.path.realpath(sys_dev_path)) + "/product"
- if os.path.exists(product_name_file):
- return read_line(product_name_file)
- return base
-
-def hwinfo(device):
- """Try to get a HW identification using sysfs"""
- base = os.path.basename(device)
- if os.path.exists('/sys/class/tty/%s/device' % (base,)):
- # PCI based devices
- sys_id_path = '/sys/class/tty/%s/device/id' % (base,)
- if os.path.exists(sys_id_path):
- return read_line(sys_id_path)
- # USB-Serial devices
- sys_dev_path = '/sys/class/tty/%s/device/driver/%s' % (base, base)
- if os.path.exists(sys_dev_path):
- sys_usb = os.path.dirname(os.path.dirname(os.path.realpath(sys_dev_path)))
- return usb_sysfs_hw_string(sys_usb)
- # USB-CDC devices
- if base.startswith('ttyACM'):
- sys_dev_path = '/sys/class/tty/%s/device' % (base,)
- if os.path.exists(sys_dev_path):
- return usb_sysfs_hw_string(sys_dev_path + '/..')
- return 'n/a' # XXX directly remove these from the list?
-
-def comports():
- devices = glob.glob('/dev/ttyS*') + glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*')
- return [(d, describe(d), hwinfo(d)) for d in devices]
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-# test
-if __name__ == '__main__':
- for port, desc, hwid in sorted(comports()):
- print "%s: %s [%s]" % (port, desc, hwid)
diff --git a/scripts/serial/urlhandler/__init__.py b/scripts/serial/urlhandler/__init__.py deleted file mode 100644 index 0efe34b218..0000000000 --- a/scripts/serial/urlhandler/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# empty #
\ No newline at end of file diff --git a/scripts/serial/urlhandler/protocol_hwgrep.py b/scripts/serial/urlhandler/protocol_hwgrep.py deleted file mode 100644 index 62cda43aa7..0000000000 --- a/scripts/serial/urlhandler/protocol_hwgrep.py +++ /dev/null @@ -1,45 +0,0 @@ -#! python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see __init__.py -# -# This module implements a special URL handler that uses the port listing to -# find ports by searching the string descriptions. -# -# (C) 2011 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt -# -# URL format: hwgrep://regexp - -import serial -import serial.tools.list_ports - -class Serial(serial.Serial): - """Just inherit the native Serial port implementation and patch the open function.""" - - def setPort(self, value): - """translate port name before storing it""" - if isinstance(value, basestring) and value.startswith('hwgrep://'): - serial.Serial.setPort(self, self.fromURL(value)) - else: - serial.Serial.setPort(self, value) - - def fromURL(self, url): - """extract host and port from an URL string""" - if url.lower().startswith("hwgrep://"): url = url[9:] - # use a for loop to get the 1st element from the generator - for port, desc, hwid in serial.tools.list_ports.grep(url): - return port - else: - raise serial.SerialException('no ports found matching regexp %r' % (url,)) - - # override property - port = property(serial.Serial.getPort, setPort, doc="Port setting") - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -if __name__ == '__main__': - #~ s = Serial('hwgrep://ttyS0') - s = Serial(None) - s.port = 'hwgrep://ttyS0' - print s - diff --git a/scripts/serial/urlhandler/protocol_loop.py b/scripts/serial/urlhandler/protocol_loop.py deleted file mode 100644 index a414839761..0000000000 --- a/scripts/serial/urlhandler/protocol_loop.py +++ /dev/null @@ -1,279 +0,0 @@ -#! python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see __init__.py -# -# This module implements a loop back connection receiving itself what it sent. -# -# The purpose of this module is.. well... You can run the unit tests with it. -# and it was so easy to implement ;-) -# -# (C) 2001-2011 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt -# -# URL format: loop://[option[/option...]] -# options: -# - "debug" print diagnostic messages - -from serial.serialutil import * -import threading -import time -import logging - -# map log level names to constants. used in fromURL() -LOGGER_LEVELS = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - } - - -class LoopbackSerial(SerialBase): - """Serial port implementation that simulates a loop back connection in plain software.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - if self._isOpen: - raise SerialException("Port is already open.") - self.logger = None - self.buffer_lock = threading.Lock() - self.loop_buffer = bytearray() - self.cts = False - self.dsr = False - - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - # not that there is anything to open, but the function applies the - # options found in the URL - self.fromURL(self.port) - - # not that there anything to configure... - self._reconfigurePort() - # all things set up get, now a clean start - self._isOpen = True - if not self._rtscts: - self.setRTS(True) - self.setDTR(True) - self.flushInput() - self.flushOutput() - - def _reconfigurePort(self): - """\ - Set communication parameters on opened port. For the loop:// - protocol all settings are ignored! - """ - # not that's it of any real use, but it helps in the unit tests - if not isinstance(self._baudrate, (int, long)) or not 0 < self._baudrate < 2**32: - raise ValueError("invalid baudrate: %r" % (self._baudrate)) - if self.logger: - self.logger.info('_reconfigurePort()') - - def close(self): - """Close port""" - if self._isOpen: - self._isOpen = False - # in case of quick reconnects, give the server some time - time.sleep(0.3) - - def makeDeviceName(self, port): - raise SerialException("there is no sensible way to turn numbers into URLs") - - def fromURL(self, url): - """extract host and port from an URL string""" - if url.lower().startswith("loop://"): url = url[7:] - try: - # process options now, directly altering self - for option in url.split('/'): - if '=' in option: - option, value = option.split('=', 1) - else: - value = None - if not option: - pass - elif option == 'logging': - logging.basicConfig() # XXX is that good to call it here? - self.logger = logging.getLogger('pySerial.loop') - self.logger.setLevel(LOGGER_LEVELS[value]) - self.logger.debug('enabled logging') - else: - raise ValueError('unknown option: %r' % (option,)) - except ValueError, e: - raise SerialException('expected a string in the form "[loop://][option[/option...]]": %s' % e) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def inWaiting(self): - """Return the number of characters currently in the input buffer.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - # attention the logged value can differ from return value in - # threaded environments... - self.logger.debug('inWaiting() -> %d' % (len(self.loop_buffer),)) - return len(self.loop_buffer) - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self._isOpen: raise portNotOpenError - if self._timeout is not None: - timeout = time.time() + self._timeout - else: - timeout = None - data = bytearray() - while size > 0: - self.buffer_lock.acquire() - try: - block = to_bytes(self.loop_buffer[:size]) - del self.loop_buffer[:size] - finally: - self.buffer_lock.release() - data += block - size -= len(block) - # check for timeout now, after data has been read. - # useful for timeout = 0 (non blocking) read - if timeout and time.time() > timeout: - break - return bytes(data) - - def write(self, data): - """\ - Output the given string over the serial port. Can block if the - connection is blocked. May raise SerialException if the connection is - closed. - """ - if not self._isOpen: raise portNotOpenError - # ensure we're working with bytes - data = to_bytes(data) - # calculate aprox time that would be used to send the data - time_used_to_send = 10.0*len(data) / self._baudrate - # when a write timeout is configured check if we would be successful - # (not sending anything, not even the part that would have time) - if self._writeTimeout is not None and time_used_to_send > self._writeTimeout: - time.sleep(self._writeTimeout) # must wait so that unit test succeeds - raise writeTimeoutError - self.buffer_lock.acquire() - try: - self.loop_buffer += data - finally: - self.buffer_lock.release() - return len(data) - - def flushInput(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('flushInput()') - self.buffer_lock.acquire() - try: - del self.loop_buffer[:] - finally: - self.buffer_lock.release() - - def flushOutput(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('flushOutput()') - - def sendBreak(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self._isOpen: raise portNotOpenError - - def setBreak(self, level=True): - """\ - Set break: Controls TXD. When active, to transmitting is - possible. - """ - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('setBreak(%r)' % (level,)) - - def setRTS(self, level=True): - """Set terminal status line: Request To Send""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('setRTS(%r) -> state of CTS' % (level,)) - self.cts = level - - def setDTR(self, level=True): - """Set terminal status line: Data Terminal Ready""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('setDTR(%r) -> state of DSR' % (level,)) - self.dsr = level - - def getCTS(self): - """Read terminal status line: Clear To Send""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('getCTS() -> state of RTS (%r)' % (self.cts,)) - return self.cts - - def getDSR(self): - """Read terminal status line: Data Set Ready""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('getDSR() -> state of DTR (%r)' % (self.dsr,)) - return self.dsr - - def getRI(self): - """Read terminal status line: Ring Indicator""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getRI()') - return False - - def getCD(self): - """Read terminal status line: Carrier Detect""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getCD()') - return True - - # - - - platform specific - - - - # None so far - - -# assemble Serial class with the platform specific implementation and the base -# for file-like behavior. for Python 2.6 and newer, that provide the new I/O -# library, derive from io.RawIOBase -try: - import io -except ImportError: - # classic version with our own file-like emulation - class Serial(LoopbackSerial, FileLike): - pass -else: - # io library present - class Serial(LoopbackSerial, io.RawIOBase): - pass - - -# simple client test -if __name__ == '__main__': - import sys - s = Serial('loop://') - sys.stdout.write('%s\n' % s) - - sys.stdout.write("write...\n") - s.write("hello\n") - s.flush() - sys.stdout.write("read: %s\n" % s.read(5)) - - s.close() diff --git a/scripts/serial/urlhandler/protocol_rfc2217.py b/scripts/serial/urlhandler/protocol_rfc2217.py deleted file mode 100644 index 981ba45fea..0000000000 --- a/scripts/serial/urlhandler/protocol_rfc2217.py +++ /dev/null @@ -1,11 +0,0 @@ -#! python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see ../__init__.py -# -# This is a thin wrapper to load the rfc2271 implementation. -# -# (C) 2011 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt - -from serial.rfc2217 import Serial diff --git a/scripts/serial/urlhandler/protocol_socket.py b/scripts/serial/urlhandler/protocol_socket.py deleted file mode 100644 index dc5992342c..0000000000 --- a/scripts/serial/urlhandler/protocol_socket.py +++ /dev/null @@ -1,291 +0,0 @@ -#! python -# -# Python Serial Port Extension for Win32, Linux, BSD, Jython -# see __init__.py -# -# This module implements a simple socket based client. -# It does not support changing any port parameters and will silently ignore any -# requests to do so. -# -# The purpose of this module is that applications using pySerial can connect to -# TCP/IP to serial port converters that do not support RFC 2217. -# -# (C) 2001-2011 Chris Liechti <cliechti@gmx.net> -# this is distributed under a free software license, see license.txt -# -# URL format: socket://<host>:<port>[/option[/option...]] -# options: -# - "debug" print diagnostic messages - -from serial.serialutil import * -import time -import socket -import select -import logging - -# map log level names to constants. used in fromURL() -LOGGER_LEVELS = { - 'debug': logging.DEBUG, - 'info': logging.INFO, - 'warning': logging.WARNING, - 'error': logging.ERROR, - } - -POLL_TIMEOUT = 2 - -class SocketSerial(SerialBase): - """Serial port implementation for plain sockets.""" - - BAUDRATES = (50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200) - - def open(self): - """\ - Open port with current settings. This may throw a SerialException - if the port cannot be opened. - """ - self.logger = None - if self._port is None: - raise SerialException("Port must be configured before it can be used.") - if self._isOpen: - raise SerialException("Port is already open.") - try: - # XXX in future replace with create_connection (py >=2.6) - self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._socket.connect(self.fromURL(self.portstr)) - except Exception, msg: - self._socket = None - raise SerialException("Could not open port %s: %s" % (self.portstr, msg)) - - self._socket.settimeout(POLL_TIMEOUT) # used for write timeout support :/ - - # not that there anything to configure... - self._reconfigurePort() - # all things set up get, now a clean start - self._isOpen = True - if not self._rtscts: - self.setRTS(True) - self.setDTR(True) - self.flushInput() - self.flushOutput() - - def _reconfigurePort(self): - """\ - Set communication parameters on opened port. For the socket:// - protocol all settings are ignored! - """ - if self._socket is None: - raise SerialException("Can only operate on open ports") - if self.logger: - self.logger.info('ignored port configuration change') - - def close(self): - """Close port""" - if self._isOpen: - if self._socket: - try: - self._socket.shutdown(socket.SHUT_RDWR) - self._socket.close() - except: - # ignore errors. - pass - self._socket = None - self._isOpen = False - # in case of quick reconnects, give the server some time - time.sleep(0.3) - - def makeDeviceName(self, port): - raise SerialException("there is no sensible way to turn numbers into URLs") - - def fromURL(self, url): - """extract host and port from an URL string""" - if url.lower().startswith("socket://"): url = url[9:] - try: - # is there a "path" (our options)? - if '/' in url: - # cut away options - url, options = url.split('/', 1) - # process options now, directly altering self - for option in options.split('/'): - if '=' in option: - option, value = option.split('=', 1) - else: - value = None - if option == 'logging': - logging.basicConfig() # XXX is that good to call it here? - self.logger = logging.getLogger('pySerial.socket') - self.logger.setLevel(LOGGER_LEVELS[value]) - self.logger.debug('enabled logging') - else: - raise ValueError('unknown option: %r' % (option,)) - # get host and port - host, port = url.split(':', 1) # may raise ValueError because of unpacking - port = int(port) # and this if it's not a number - if not 0 <= port < 65536: raise ValueError("port not in range 0...65535") - except ValueError, e: - raise SerialException('expected a string in the form "[rfc2217://]<host>:<port>[/option[/option...]]": %s' % e) - return (host, port) - - # - - - - - - - - - - - - - - - - - - - - - - - - - - def inWaiting(self): - """Return the number of characters currently in the input buffer.""" - if not self._isOpen: raise portNotOpenError - # Poll the socket to see if it is ready for reading. - # If ready, at least one byte will be to read. - lr, lw, lx = select.select([self._socket], [], [], 0) - return len(lr) - - def read(self, size=1): - """\ - Read size bytes from the serial port. If a timeout is set it may - return less characters as requested. With no timeout it will block - until the requested number of bytes is read. - """ - if not self._isOpen: raise portNotOpenError - data = bytearray() - if self._timeout is not None: - timeout = time.time() + self._timeout - else: - timeout = None - while len(data) < size and (timeout is None or time.time() < timeout): - try: - # an implementation with internal buffer would be better - # performing... - t = time.time() - block = self._socket.recv(size - len(data)) - duration = time.time() - t - if block: - data.extend(block) - else: - # no data -> EOF (connection probably closed) - break - except socket.timeout: - # just need to get out of recv from time to time to check if - # still alive - continue - except socket.error, e: - # connection fails -> terminate loop - raise SerialException('connection failed (%s)' % e) - return bytes(data) - - def write(self, data): - """\ - Output the given string over the serial port. Can block if the - connection is blocked. May raise SerialException if the connection is - closed. - """ - if not self._isOpen: raise portNotOpenError - try: - self._socket.sendall(to_bytes(data)) - except socket.error, e: - # XXX what exception if socket connection fails - raise SerialException("socket connection failed: %s" % e) - return len(data) - - def flushInput(self): - """Clear input buffer, discarding all that is in the buffer.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored flushInput') - - def flushOutput(self): - """\ - Clear output buffer, aborting the current output and - discarding all that is in the buffer. - """ - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored flushOutput') - - def sendBreak(self, duration=0.25): - """\ - Send break condition. Timed, returns to idle state after given - duration. - """ - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored sendBreak(%r)' % (duration,)) - - def setBreak(self, level=True): - """Set break: Controls TXD. When active, to transmitting is - possible.""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored setBreak(%r)' % (level,)) - - def setRTS(self, level=True): - """Set terminal status line: Request To Send""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored setRTS(%r)' % (level,)) - - def setDTR(self, level=True): - """Set terminal status line: Data Terminal Ready""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('ignored setDTR(%r)' % (level,)) - - def getCTS(self): - """Read terminal status line: Clear To Send""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getCTS()') - return True - - def getDSR(self): - """Read terminal status line: Data Set Ready""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getDSR()') - return True - - def getRI(self): - """Read terminal status line: Ring Indicator""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getRI()') - return False - - def getCD(self): - """Read terminal status line: Carrier Detect""" - if not self._isOpen: raise portNotOpenError - if self.logger: - self.logger.info('returning dummy for getCD()') - return True - - # - - - platform specific - - - - - # works on Linux and probably all the other POSIX systems - def fileno(self): - """Get the file handle of the underlying socket for use with select""" - return self._socket.fileno() - - -# assemble Serial class with the platform specific implementation and the base -# for file-like behavior. for Python 2.6 and newer, that provide the new I/O -# library, derive from io.RawIOBase -try: - import io -except ImportError: - # classic version with our own file-like emulation - class Serial(SocketSerial, FileLike): - pass -else: - # io library present - class Serial(SocketSerial, io.RawIOBase): - pass - - -# simple client test -if __name__ == '__main__': - import sys - s = Serial('socket://localhost:7000') - sys.stdout.write('%s\n' % s) - - sys.stdout.write("write...\n") - s.write("hello\n") - s.flush() - sys.stdout.write("read: %s\n" % s.read(5)) - - s.close() diff --git a/scripts/setlocalversion b/scripts/setlocalversion index 6b54e46a0f..cbd3883df9 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -111,13 +111,14 @@ if $scm_only; then exit fi -if test -e include/config/auto.conf; then - . include/config/auto.conf -else +if ! test -e include/config/auto.conf; then echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2 exit 1 fi +# version string from CONFIG_LOCALVERSION +config_localversion=$(sed -n 's/^CONFIG_LOCALVERSION=\(.*\)$/\1/p' include/config/auto.conf) + # localversion* files in the build and source directory res="$(collect_files localversion*)" if test ! "$srctree" -ef .; then @@ -125,10 +126,10 @@ if test ! "$srctree" -ef .; then fi # CONFIG_LOCALVERSION and LOCALVERSION (if set) -res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" +res="${res}${config_localversion}${LOCALVERSION}" # scm version string if not at a tagged commit -if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then +if grep -q "^CONFIG_LOCALVERSION_AUTO=y$" include/config/auto.conf; then # full scm version string res="$res$(scm_version)" elif [ "${LOCALVERSION+set}" != "set" ]; then diff --git a/scripts/socfpga_get_sequencer b/scripts/socfpga_get_sequencer index 5405bfa6ba..d21791eee9 100755 --- a/scripts/socfpga_get_sequencer +++ b/scripts/socfpga_get_sequencer @@ -43,7 +43,7 @@ copy_source() { echo " Fixing include paths..." # Fix include pathes - sed -i 's/#include <sdram.h>/#include <mach\/cyclone5-sdram.h>/g' $tgt + sed -i 's/#include <sdram.h>/#include <mach\/socfpga\/cyclone5-sdram.h>/g' $tgt sed -i 's/#include "sequencer_auto.h"//g' $tgt sed -i 's/#include "sequencer.h"/#include "cyclone5-sequencer.h"/g' $tgt @@ -54,7 +54,7 @@ copy_source() { sed -i 's/[ \t]\+$//' $tgt echo " Running coccinelle cleanups..." - spatch -sp_file scripts/coccinelle/misc/altera_sequencer.cocci -in_place arch/arm/mach-socfpga/include/mach + spatch -sp_file scripts/coccinelle/misc/altera_sequencer.cocci -in_place include/mach/socfpga echo " Cleanup header..." sed -i 's/^static void rw_mgr_mem_calibrate_eye_diag_aid(void);$//g' $tgt @@ -65,20 +65,20 @@ copy_source() { sed -i 's/^static void rw_mgr_decr_vfifo_auto(uint32_t grp);$//g' $tgt } -copy_source ${ubootsrc}/board/altera/socfpga/sdram/sequencer.c arch/arm/mach-socfpga/include/mach/cyclone5-sequencer.c -sed -i 's/static int sdram_calibration(void)/static int socfpga_mem_calibration(void)/g' arch/arm/mach-socfpga/include/mach/cyclone5-sequencer.c +copy_source ${ubootsrc}/board/altera/socfpga/sdram/sequencer.c include/mach/socfpga/cyclone5-sequencer.c +sed -i 's/static int sdram_calibration(void)/static int socfpga_mem_calibration(void)/g' include/mach/socfpga/cyclone5-sequencer.c -copy_source ${ubootsrc}/board/altera/socfpga/sdram/sequencer.h arch/arm/mach-socfpga/include/mach/cyclone5-sequencer.h -copy_source ${ubootsrc}/board/altera/socfpga/sdram/tclrpt.h arch/arm/mach-socfpga/include/mach/tclrpt.h -copy_source ${ubootsrc}/board/altera/socfpga/sdram/sdram_io.h arch/arm/mach-socfpga/include/mach/sdram_io.h -cat <<'EOF' >> arch/arm/mach-socfpga/include/mach/sdram_io.h +copy_source ${ubootsrc}/board/altera/socfpga/sdram/sequencer.h include/mach/socfpga/cyclone5-sequencer.h +copy_source ${ubootsrc}/board/altera/socfpga/sdram/tclrpt.h include/mach/socfpga/tclrpt.h +copy_source ${ubootsrc}/board/altera/socfpga/sdram/sdram_io.h include/mach/socfpga/sdram_io.h +cat <<'EOF' >> include/mach/socfpga/sdram_io.h #define write_register(BASE, OFFSET, DATA) \ writel(DATA, ((BASE) + (OFFSET))) #define read_register(BASE, OFFSET) \ readl((BASE) + (OFFSET)) #define HPS_SDR_BASE 0xffc20000 EOF -copy_source ${ubootsrc}/board/altera/socfpga/sdram/system.h arch/arm/mach-socfpga/include/mach/system.h +copy_source ${ubootsrc}/board/altera/socfpga/sdram/system.h include/mach/socfpga/system.h echo "DONE" diff --git a/scripts/socfpga_import_preloader b/scripts/socfpga_import_preloader index 2bec9f2d21..e917dcafef 100755 --- a/scripts/socfpga_import_preloader +++ b/scripts/socfpga_import_preloader @@ -8,7 +8,7 @@ usage() { -b|--board <BOARD_DIRECTORY> optional: -e|--embedded-sdk <ALTERA_EMBEDDED_SDK>" - echo "EXAMPLE: $0 -i ~/cv_soc_devkit_ghrd/hps_isw_handoff/soc_system_hps_0/ -b arch/arm/boards/altera-socdk -e ~/altera-embedded-sdk/" + echo "EXAMPLE: $0 -i ~/cv_soc_devkit_ghrd/hps_isw_handoff/soc_system_hps_0/ -b arch/arm/boards/altera-socdk -e ~/altera-embedded-sdk/" exit 1 } @@ -79,6 +79,9 @@ copy_source() { cp $src $tgt + dos2unix $tgt + + echo " Fixing conditional compilation..." unifdef -D HCX_COMPAT_MODE=1 -D ENABLE_INST_ROM_WRITE=1 $tgt -o $tgt echo " Fixing extern/static keywords..." @@ -99,9 +102,9 @@ copy_source() { sed -i 's/alt_8/int8_t/g' $tgt sed -i 's/#include "alt_types.h"//g' $tgt - echo " Fixing include pathes..." + echo " Fixing include paths..." # Fix include pathes - sed -i 's/#include <iocsr_config_cyclone5.h>/#include <mach\/cyclone5-scan-manager.h>/g' $tgt + sed -i 's/#include <iocsr_config_cyclone5.h>/#include <mach\/socfpga\/cyclone5-scan-manager.h>/g' $tgt sed -i 's/#include <pinmux_config.h>/#include <common.h>/g' $tgt sed -i 's/#include "sequencer_auto.h"//g' $tgt sed -i 's/#include "sequencer_defines.h"//g' $tgt @@ -112,7 +115,10 @@ copy_source() { } generate_spl() { - python2.7 ${embeddedsw}/embedded/ip/altera/preloader/scripts/iswgen.py -i ${handoff} -o ${splroot}/ + USE_SOCEDS_PYTHON=1 SOCEDS_DESTROY_PATH=1 \ + ${embeddedsw}/embedded/embedded_command_shell.sh python \ + ${embeddedsw}/embedded/ip/altera/preloader/scripts/iswgen.py \ + -i ${handoff} -o ${splroot}/ } if [ -z $splroot ] || [ -z $boardroot ] || [ -z $handoff ]; then diff --git a/scripts/socfpga_mkimage.c b/scripts/socfpga_mkimage.c index e88e75962f..0878c3f261 100644 --- a/scripts/socfpga_mkimage.c +++ b/scripts/socfpga_mkimage.c @@ -12,6 +12,7 @@ #include "common.h" #include "common.c" +#include "../crypto/crc32.c" #define VALIDATION_WORD 0x31305341 @@ -68,62 +69,6 @@ static uint32_t bb_header[] = { 0xea00006b, /* entry. b 0x200 (offset may be adjusted) */ }; -static const uint32_t crc_table[256] = { - 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, - 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, - 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7, - 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, - 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, - 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, - 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef, - 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, - 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, - 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, - 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0, - 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, - 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, - 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, - 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08, - 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, - 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, - 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, - 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050, - 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, - 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, - 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, - 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1, - 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, - 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, - 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, - 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9, - 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, - 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, - 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, - 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71, - 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, - 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, - 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, - 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e, - 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, - 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, - 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, - 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676, - 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, - 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, - 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, - 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 -}; - -static uint32_t crc32(uint32_t crc, void *_buf, int length) -{ - uint8_t *buf = _buf; - - while (length--) - crc = crc << 8 ^ crc_table[(crc >> 24 ^ *(buf++)) & 0xff]; - - return crc; -} - /* Create an ARM relative branch instuction * branch is where the instruction will be placed and dest points to where * it should branch too. */ @@ -215,7 +160,7 @@ static int add_socfpga_header(void *buf, size_t size, unsigned start_addr, unsig crc = buf + size - sizeof(uint32_t); - *crc = crc32(0xffffffff, buf, size - sizeof(uint32_t)); + *crc = crc32_be(0xffffffff, buf, size - sizeof(uint32_t)); *crc ^= 0xffffffff; return 0; diff --git a/scripts/socfpga_xml_to_config.sh b/scripts/socfpga_xml_to_config.sh index 3bb0dd283b..2ec2788865 100755 --- a/scripts/socfpga_xml_to_config.sh +++ b/scripts/socfpga_xml_to_config.sh @@ -41,7 +41,7 @@ pll_config() { sed -e "s/^/\t./g" | sort` - echo "#include <mach/arria10-clock-manager.h>" > $tgt + echo "#include <mach/socfpga/arria10-clock-manager.h>" > $tgt echo >> $tgt echo "static struct arria10_mainpll_cfg mainpll_cfg = {" >> $tgt echo "$MAINPLL" >> $tgt @@ -74,6 +74,14 @@ pinmux_config() { # FIXME: Either find solution how to parse these values too or replace # script with something that goes more in the direction of a programming # language + # 21:19 RTRIM + # 18:17 INPUT_BUF_EN + # 16 WK_PU_EN + # 13 PU_SLW_RT + # 12:8 PU_DRV_STRG + # 5 PD_SLW_RT + # 4:0 PD_DRV_STRG + DEDICATED_FIXME="[arria10_pincfg_dedicated_io_bank] = FIXME, [arria10_pincfg_dedicated_io_1] = FIXME, [arria10_pincfg_dedicated_io_2] = FIXME, @@ -99,7 +107,7 @@ pinmux_config() { sed -e "s/\.sel' value='/] = /g" | \ sed -e "s/' \/>/,/g"` - echo "#include <mach/arria10-pinmux.h>" > $tgt + echo "#include <mach/socfpga/arria10-pinmux.h>" > $tgt echo >> $tgt echo "static uint32_t pinmux[] = {" >> $tgt echo "$SHARED" >> $tgt diff --git a/scripts/xz_wrap.sh b/scripts/xz_wrap.sh index 7a2d372f48..02823bc1df 100755 --- a/scripts/xz_wrap.sh +++ b/scripts/xz_wrap.sh @@ -16,8 +16,17 @@ case $SRCARCH in x86) BCJ=--x86 ;; powerpc) BCJ=--powerpc ;; ia64) BCJ=--ia64; LZMA2OPTS=pb=4 ;; - arm) BCJ=--arm ;; + arm) BCJ=--arm$S64 ;; sparc) BCJ=--sparc ;; esac +if grep -q '^CONFIG_THUMB2_BAREBOX=y$' include/config/auto.conf; then + BCJ=--armthumb +fi + +# clear BCJ filter if unsupported +if [ -n "${BCJ}" ]; then + xz -H | grep -q -- $BCJ || BCJ= +fi + exec xz --check=crc32 $BCJ --lzma2=$LZMA2OPTS,dict=32MiB diff --git a/scripts/zynq_mkimage.c b/scripts/zynq_mkimage.c index b611d5c69b..9c1e23ef00 100644 --- a/scripts/zynq_mkimage.c +++ b/scripts/zynq_mkimage.c @@ -5,7 +5,7 @@ #include <errno.h> #include <getopt.h> #include <linux/kernel.h> -#include <mach/zynq-flash-header.h> +#include <zynq/zynq-flash-header.h> #include <malloc.h> #include <stdint.h> #include <stdio.h> |