diff options
Diffstat (limited to 'scripts')
232 files changed, 17261 insertions, 10037 deletions
diff --git a/scripts/.gitignore b/scripts/.gitignore index 76ea271abb..8c653d184f 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -1,5 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-only + bin2c -mkimage fix_size bareboxenv bareboxcrc32 @@ -8,10 +9,10 @@ bareboximd kallsyms kwbimage kwboot +kwboot-target gen_netx_image omap_signGP mk-omap-image -s5p_cksum mkublheader zynq_mkimage socfpga_mkimage @@ -19,14 +20,20 @@ bareboxenv-target kernel-install-target bareboxcrc32-target bareboximd-target -bareboxstate -bareboxstate-target mk-am35xx-spi-image mxsimage mxsboot mxs-usb-loader /omap3-usb-loader omap4_usbboot +omap4_usbboot-target omap3-usb-loader +omap3-usb-loader-target +rk-usb-loader +rk-usb-loader-target +rkimage mips-relocs rsatoc +stm32image +mvebuimg +prelink-riscv diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index 919f286162..eeb459f8fa 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 #### # kbuild: Generic definitions @@ -24,10 +25,18 @@ depfile = $(subst $(comma),_,$(dot-target).d) basetarget = $(basename $(notdir $@)) ### +# real prerequisites without phony targets +real-prereqs = $(filter-out $(PHONY), $^) + +### # Escape single quote for use in echo statements escsq = $(subst $(squote),'\$(squote)',$1) ### +# Quote a string to pass it to C files. foo => '"foo"' +stringify = $(squote)$(quote)$1$(quote)$(squote) + +### # Easy method for doing a status message kecho := : quiet_kecho := echo @@ -37,11 +46,11 @@ kecho := $($(quiet)kecho) ### # filechk is used to check if the content of a generated file is updated. # Sample usage: -# define filechk_sample -# echo $KERNELRELEASE -# endef -# version.h : Makefile +# +# filechk_sample = echo $(KERNELRELEASE) +# version.h: FORCE # $(call filechk,sample) +# # The rule defined shall write to stdout the content of the new file. # The existing file will be compared with the new one. # - If no file exist it is created @@ -50,32 +59,31 @@ kecho := $($(quiet)kecho) # - stdin is piped in from the first prerequisite ($<) so one has # to specify a valid file as first prerequisite (often the kbuild file) define filechk - $(Q)set -e; \ - $(kecho) ' CHK $@'; \ - mkdir -p $(dir $@); \ - $(filechk_$(1)) < $< > $@.tmp; \ - if [ -r $@ ] && cmp -s $@ $@.tmp; then \ - rm -f $@.tmp; \ - else \ - $(kecho) ' UPD $@'; \ - mv -f $@.tmp $@; \ + $(Q)set -e; \ + mkdir -p $(dir $@); \ + trap "rm -f $(dot-target).tmp" EXIT; \ + { $(filechk_$(1)); } > $(dot-target).tmp; \ + if [ ! -r $@ ] || ! cmp -s $@ $(dot-target).tmp; then \ + $(kecho) ' UPD $@'; \ + mv -f $(dot-target).tmp $@; \ fi endef ###### # gcc support functions -# See documentation in Documentation/kbuild/makefiles.txt +# See documentation in Documentation/kbuild/makefiles.rst # cc-cross-prefix # Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-) -# Return first prefix where a prefix$(CC) is found in PATH. -# If no $(CC) found in PATH with listed prefixes return nothing -cc-cross-prefix = \ - $(word 1, $(foreach c,$(1), \ - $(shell set -e; \ - if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \ - echo $(c); \ - fi))) +# Return first <prefix> where a <prefix>gcc is found in PATH. +# If no gcc found in PATH with listed prefixes return nothing +# +# Note: '2>/dev/null' is here to force Make to invoke a shell. Otherwise, it +# would try to directly execute the shell builtin 'command'. This workaround +# should be kept for a long time since this issue was fixed only after the +# GNU Make 4.2.1 release. +cc-cross-prefix = $(firstword $(foreach c, $(1), \ + $(if $(shell command -v -- $(c)gcc 2>/dev/null), $(c)))) # output directory for tests below TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) @@ -97,29 +105,29 @@ try-run = $(shell set -e; \ # Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) as-option = $(call try-run,\ - $(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) + $(CC) $(KBUILD_CFLAGS) $(1) -c -xassembler /dev/null -o "$$TMP",$(1),$(2)) # as-instr # Usage: cflags-y += $(call as-instr,instr,option1,option2) as-instr = $(call try-run,\ - /bin/echo -e "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) + printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -xassembler -o "$$TMP" -,$(2),$(3)) # cc-option # Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) cc-option = $(call try-run,\ - $(CC) -Werror $(KBUILD_CPPFLAGS) $(CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) + $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",$(1),$(2)) # cc-option-yn # Usage: flag := $(call cc-option-yn,-march=winchip-c6) cc-option-yn = $(call try-run,\ - $(CC) -Werror $(KBUILD_CPPFLAGS) $(CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) + $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(1) -c -xc /dev/null -o "$$TMP",y,n) # cc-disable-warning # Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) cc-disable-warning = $(call try-run,\ - $(CC) -Werror $(KBUILD_CPPFLAGS) $(CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) + $(CC) -Werror $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -xc /dev/null -o "$$TMP",-Wno-$(strip $(1))) # cc-version # Usage gcc-ver := $(call cc-version) @@ -130,7 +138,7 @@ cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3)) # ld-option -# Usage: LDFLAGS += $(call ld-option, -X) +# Usage: KBUILD_LDFLAGS += $(call ld-option, -X) ld-option = $(call try-run,\ $(CC) -x c /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) @@ -140,18 +148,13 @@ ld-option = $(call try-run,\ # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= # Usage: # $(Q)$(MAKE) $(build)=dir -build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj +build := -f $(srctree)/scripts/Makefile.build obj ### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj= -# Usage: -# $(Q)$(MAKE) $(modbuiltin)=dir -modbuiltin := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.modbuiltin obj - -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= # Usage: # $(Q)$(MAKE) $(clean)=dir -clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj +clean := -f $(srctree)/scripts/Makefile.clean obj # Prefix -I with $(srctree) if it is not an absolute path. # skip if -I has no parameter @@ -167,10 +170,7 @@ echo-cmd = $(if $($(quiet)cmd_$(1)),\ echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) # printing commands -cmd = @$(echo-cmd) $(cmd_$(1)) - -# Add $(obj)/ for paths that are not absolute -objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) +cmd = @set -e; $(echo-cmd) $(cmd_$(1)) ### # if_changed - execute command if any prerequisite is newer than @@ -178,15 +178,15 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) # if_changed_dep - as if_changed, but uses fixdep to reveal dependencies # including used config symbols # if_changed_rule - as if_changed but execute rule instead -# See Documentation/kbuild/makefiles.txt for more info +# See Documentation/kbuild/makefiles.rst for more info ifneq ($(KBUILD_NOCMDDEP),1) -# Check if both arguments are the same including their order. Result is empty +# Check if both commands are the same including their order. Result is empty # string if equal. User may override this check using make KBUILD_NOCMDDEP=1 -arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \ +cmd-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \ $(subst $(space),$(space_escape),$(strip $(cmd_$1)))) else -arg-check = $(if $(strip $(cmd_$@)),,1) +cmd-check = $(if $(strip $(cmd_$@)),,1) endif # Replace >$< with >$$< to preserve $ when reloading the .cmd file @@ -197,34 +197,33 @@ endif # (needed for the shell) make-cmd = $(call escsq,$(subst $(pound),$$(pound),$(subst $$,$$$$,$(cmd_$(1))))) -# Find any prerequisites that is newer than target or that does not exist. +# Find any prerequisites that are newer than target or that do not exist. +# (This is not true for now; $? should contain any non-existent prerequisites, +# but it does not work as expected when .SECONDARY is present. This seems a bug +# of GNU Make.) # PHONY targets skipped in both cases. -any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) +newer-prereqs = $(filter-out $(PHONY),$?) # Execute command if command has changed or prerequisite(s) are updated. -# -if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ - @set -e; \ - $(echo-cmd) $(cmd_$(1)); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) +if_changed = $(if $(newer-prereqs)$(cmd-check), \ + $(cmd); \ + printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) # Execute the command and also postprocess generated .d dependencies file. -if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ - @set -e; \ - $(echo-cmd) $(cmd_$(1)); \ - scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd) +if_changed_dep = $(if $(newer-prereqs)$(cmd-check),$(cmd_and_fixdep),@:) + +cmd_and_fixdep = \ + $(cmd); \ + scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).cmd;\ + rm -f $(depfile) # Usage: $(call if_changed_rule,foo) # Will check if $(cmd_foo) or any of the prerequisites changed, # and if so will execute $(rule_foo). -if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \ - @set -e; \ - $(rule_$(1))) +if_changed_rule = $(if $(newer-prereqs)$(cmd-check),$(rule_$(1)),@:) ### -# why - tell why a a target got build +# why - tell why a target got built # enabled by make V=2 # Output (listed in the order they are checked): # (1) - due to target is PHONY @@ -246,8 +245,8 @@ ifeq ($(KBUILD_VERBOSE),2) why = \ $(if $(filter $@, $(PHONY)),- due to target is PHONY, \ $(if $(wildcard $@), \ - $(if $(strip $(any-prereq)),- due to: $(any-prereq), \ - $(if $(arg-check), \ + $(if $(newer-prereqs),- due to: $(newer-prereqs), \ + $(if $(cmd-check), \ $(if $(cmd_$@),- due to command line change, \ $(if $(filter $@, $(targets)), \ - due to missing .cmd file, \ @@ -263,55 +262,6 @@ why = \ echo-why = $(call escsq, $(strip $(why))) endif -############################################################################### -# -# When a Kconfig string contains a filename, it is suitable for -# passing to shell commands. It is surrounded by double-quotes, and -# any double-quotes or backslashes within it are escaped by -# backslashes. -# -# This is no use for dependencies or $(wildcard). We need to strip the -# surrounding quotes and the escaping from quotes and backslashes, and -# we *do* need to escape any spaces in the string. So, for example: -# -# Usage: $(eval $(call config_filename,FOO)) -# -# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option, -# transformed as described above to be suitable for use within the -# makefile. -# -# Also, if the filename is a relative filename and exists in the source -# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to -# be prefixed to *both* command invocation and dependencies. -# -# Note: We also print the filenames in the quiet_cmd_foo text, and -# perhaps ought to have a version specially escaped for that purpose. -# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good -# enough. It'll strip the quotes in the common case where there's no -# space and it's a simple filename, and it'll retain the quotes when -# there's a space. There are some esoteric cases in which it'll print -# the wrong thing, but we don't really care. The actual dependencies -# and commands *do* get it right, with various combinations of single -# and double quotes, backslashes and spaces in the filenames. -# -############################################################################### -# -define config_filename -ifneq ($$(CONFIG_$(1)),"") -$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) -ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME))) -else -ifeq ($$(wildcard $$($(1)_FILENAME)),) -ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),) -$(1)_SRCPREFIX := $(srctree)/ -endif -endif -endif -endif -endef -# -############################################################################### - # delete partially updated (i.e. corrupted) files on error .DELETE_ON_ERROR: diff --git a/scripts/Kconfig b/scripts/Kconfig index 20530b9ae3..4034f020d0 100644 --- a/scripts/Kconfig +++ b/scripts/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + menu "Host Tools" config COMPILE_HOST_TOOLS @@ -7,11 +9,67 @@ config COMPILE_HOST_TOOLS on some config options. If you say yes here, the host tools that are not needed can be selected, too. - This is usefull for compile coverage testing and for packaging the + This is useful for compile coverage testing and for packaging the host tools. source "scripts/imx/Kconfig" +config SOCFPGA_MKIMAGE + bool "SoCFPGA mkimage" if COMPILE_HOST_TOOLS + depends on ARCH_SOCFPGA || COMPILE_HOST_TOOLS + default y if ARCH_SOCFPGA + help + This enables building the image creation tool for SoCFPGA + +config ZYNQ_MKIMAGE + bool "Zynq mkimage" if COMPILE_HOST_TOOLS + depends on ARCH_ZYNQ || COMPILE_HOST_TOOLS + default y if ARCH_ZYNQ + 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 + default y if ARCH_MXS + help + This enables building the host tools for Freescale MXS SoCs + +config LAYERSCAPE_PBLIMAGE + bool "Layerscape PBL image tool" if COMPILE_HOST_TOOLS + depends on ARCH_LAYERSCAPE || COMPILE_HOST_TOOLS + default y if ARCH_LAYERSCAPE + help + This enables building the PBL image tool for Freescale Layerscape SoCs + +config STM32_IMAGE + bool "STM32MP image tool" if COMPILE_HOST_TOOLS + depends on ARCH_STM32MP || COMPILE_HOST_TOOLS + default y if ARCH_STM32MP + help + This enables building the image creation tool for STM32MP SoCs + +config RK_IMAGE + bool "Rockchip image tool" if COMPILE_HOST_TOOLS + 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 + +config OMAP_IMAGE + bool "TI OMAP image tools" if COMPILE_HOST_TOOLS + depends on ARCH_OMAP || COMPILE_HOST_TOOLS + default y if ARCH_OMAP + help + This enables building the image creation tools for TI OMAP SoCs + config MVEBU_HOSTTOOLS bool "mvebu hosttools" if COMPILE_HOST_TOOLS depends on ARCH_MVEBU || COMPILE_HOST_TOOLS @@ -20,15 +78,6 @@ config MVEBU_HOSTTOOLS This enables building the tools kwbimage to create an image suitable for Marvell mvebu machines and kwboot to boot via UART. -config MXS_HOSTTOOLS - bool "mxs hosttools" if COMPILE_HOST_TOOLS - depends on ARCH_MXS || COMPILE_HOST_TOOLS - default y if ARCH_MXS - help - This builds the tools mxsimage and mxsboot which are needed to - create bootable image files for mxs. You need openssl development - files to compile this tool. - config OMAP3_USB_LOADER bool "omap3 USB loader" depends on ARCH_OMAP3 || COMPILE_HOST_TOOLS @@ -48,4 +97,96 @@ config OMAP4_HOSTTOOL_USBBOOT You need libusb-1.0 to compile this tool. +config RK_USB_LOADER + bool "Rockchip USB loader" + depends on ARCH_ROCKCHIP || COMPILE_HOST_TOOLS + help + Say Y here to build the rockchip usb loader tool. + + You need libusb-1.0 to compile this tool. + +config QOICONV + bool "QOI image format conversion" if COMPILE_HOST_TOOLS + 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" + +config IMD_TARGET + bool "build bareboximd target tool" + depends on IMD + +config KERNEL_INSTALL_TARGET + bool + prompt "Build kernel-install utility for the target" + help + Enable this to compile the kernel-install script using the cross + compiler. The utility for the target will be under + scripts/kernel-install-target + +config BAREBOXENV_TARGET + bool + prompt "build bareboxenv tool for target" + help + 'bareboxenv' is a tool to access the barebox environment from a running Linux + system. Say yes here to build it for the target. + +config BAREBOXCRC32_TARGET + bool + prompt "build bareboxcrc32 tool for target" + help + 'bareboxcrc32' is a userspacetool to generate the crc32 checksums the same way + barebox does. Say yes here to build it for the target. + +config HAS_TARGET_LIBUSB_1_0 + def_bool $(success,$(CROSS_PKG_CONFIG) --exists libusb-1.0) + help + Ensure $(CROSS_PKG_CONFIG) is set to a valid pkg-config + binary that knows about libusb-1.0 compiled for the + target architecture. + +config MVEBU_KWBOOT_TARGET + bool "kwboot target tool" + help + Say Y here to build the kwboot tool for the target + to bootstrap over UART. + +config ARCH_IMX_USBLOADER_TARGET + depends on HAS_TARGET_LIBUSB_1_0 + bool "imx-usb-loader for target" + help + Say Y here to build the imx-usb-loader tool for the target. + The cross toolchain needs libusb-1.0 to compile this tool. + +config OMAP3_USB_LOADER_TARGET + bool "omap3 USB loader for target" + depends on HAS_TARGET_LIBUSB_1_0 + help + Say Y here to build the omap3 usb loader tool for the target. + The cross toolchain needs libusb-1.0 to compile this tool. + + +config OMAP4_USBBOOT_TARGET + bool "omap4 usbboot for target" + depends on HAS_TARGET_LIBUSB_1_0 + help + Say Y here to build the omap4 usb loader tool for the target. + The cross toolchain needs libusb-1.0 to compile this tool. + +config RK_USB_LOADER_TARGET + bool "Rockchip USB loader for target" + depends on HAS_TARGET_LIBUSB_1_0 + help + Say Y here to build the rockchip usb loader tool for the target. + The cross toolchain needs libusb-1.0 to compile this tool. + endmenu diff --git a/scripts/Kconfig.include b/scripts/Kconfig.include new file mode 100644 index 0000000000..a5fe72c504 --- /dev/null +++ b/scripts/Kconfig.include @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Kconfig helper macros + +# Convenient variables +comma := , +quote := " +squote := ' +empty := +space := $(empty) $(empty) +dollar := $ +right_paren := ) +left_paren := ( + +# $(if-success,<command>,<then>,<else>) +# Return <then> if <command> exits with 0, <else> otherwise. +if-success = $(shell,{ $(1); } >/dev/null 2>&1 && echo "$(2)" || echo "$(3)") + +# $(success,<command>) +# Return y if <command> exits with 0, n otherwise +success = $(if-success,$(1),y,n) + +# $(failure,<command>) +# Return n if <command> exits with 0, y otherwise +failure = $(if-success,$(1),n,y) + +# $(cc-option,<flag>) +# Return y if the compiler supports <flag>, n otherwise +cc-option = $(success,mkdir .tmp_$$$$; trap "rm -rf .tmp_$$$$" EXIT; $(CC) -Werror $(CLANG_FLAGS) $(1) -c -x c /dev/null -o .tmp_$$$$/tmp.o) + +# $(ld-option,<flag>) +# Return y if the linker supports <flag>, n otherwise +ld-option = $(success,$(LD) -v $(1)) + +# $(as-instr,<instr>) +# Return y if the assembler supports <instr>, n otherwise +as-instr = $(success,printf "%b\n" "$(1)" | $(CC) $(CLANG_FLAGS) -c -x assembler -o /dev/null -) + +# check if $(CC) and $(LD) exist +$(error-if,$(failure,command -v $(CC)),compiler '$(CC)' not found) +$(error-if,$(failure,command -v $(LD)),linker '$(LD)' not found) + +# Fail if the linker is gold as it's not capable of linking the kernel proper +$(error-if,$(success, $(LD) -v | grep -q gold), gold linker '$(LD)' not supported) + +# machine bit flags +# $(m32-flag): -m32 if the compiler supports it, or an empty string otherwise. +# $(m64-flag): -m64 if the compiler supports it, or an empty string otherwise. +cc-option-bit = $(if-success,$(CC) -Werror $(1) -E -x c /dev/null -o /dev/null,$(1)) +m32-flag := $(cc-option-bit,-m32) +m64-flag := $(cc-option-bit,-m64) diff --git a/scripts/Makefile b/scripts/Makefile index 16bb513fbb..20da6fc5e7 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -1,63 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-only + ### # scripts contains sources for various helper programs used throughout # barebox for the build process. -# --------------------------------------------------------------------------- -# kallsyms: Find all symbols in barebox -hostprogs-y += bin2c -hostprogs-y += mkimage -hostprogs-y += fix_size -hostprogs-y += bareboxenv -hostprogs-y += bareboxcrc32 -hostprogs-y += kernel-install -hostprogs-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS) += rsatoc -HOSTCFLAGS_rsatoc = `pkg-config --cflags openssl` -HOSTLDLIBS_rsatoc = `pkg-config --libs openssl` -hostprogs-$(CONFIG_IMD) += bareboximd -hostprogs-$(CONFIG_KALLSYMS) += kallsyms -hostprogs-$(CONFIG_MIPS) += mips-relocs -hostprogs-$(CONFIG_MVEBU_HOSTTOOLS) += kwbimage kwboot mvebuimg -hostprogs-$(CONFIG_ARCH_OMAP) += omap_signGP mk-omap-image -hostprogs-$(CONFIG_ARCH_S5PCxx) += s5p_cksum -hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader -hostprogs-$(CONFIG_ARCH_ZYNQ) += zynq_mkimage -hostprogs-$(CONFIG_ARCH_SOCFPGA) += socfpga_mkimage -hostprogs-$(CONFIG_MXS_HOSTTOOLS)+= mxsimage mxsboot -hostprogs-$(CONFIG_ARCH_LAYERSCAPE) += pblimage -hostprogs-$(CONFIG_ARCH_STM32MP) += stm32image -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` -hostprogs-$(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` -hostprogs-$(CONFIG_OMAP4_HOSTTOOL_USBBOOT) += omap4_usbboot +hostprogs-always-y += bin2c +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_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 +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.o = `$(PKG_CONFIG) --cflags openssl` +HOSTLDLIBS_rkimage = `$(PKG_CONFIG) --libs openssl` +KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/ +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` +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` +hostprogs-always-$(CONFIG_RK_USB_LOADER) += rk-usb-loader + +userprogs-always-$(CONFIG_BAREBOXENV_TARGET) += bareboxenv-target +userprogs-always-$(CONFIG_KERNEL_INSTALL_TARGET) += kernel-install-target +userprogs-always-$(CONFIG_BAREBOXCRC32_TARGET) += bareboxcrc32-target +userprogs-always-$(CONFIG_IMD_TARGET) += bareboximd-target +userprogs-always-$(CONFIG_OMAP3_USB_LOADER_TARGET) += omap3-usb-loader-target +userprogs-always-$(CONFIG_OMAP4_USBBOOT_TARGET) += omap4_usbboot-target +userprogs-always-$(CONFIG_MVEBU_KWBOOT_TARGET) += kwboot-target +userprogs-always-$(CONFIG_RK_USB_LOADER_TARGET) += rk-usb-loader-target + +omap3-usb-loader-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0` +omap3-usb-loader-target-userldlibs += `$(CROSS_PKG_CONFIG) --libs libusb-1.0` +omap4_usbboot-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0` +omap4_usbboot-target-userldlibs += -lpthread `$(CROSS_PKG_CONFIG) --libs libusb-1.0` +rk-usb-loader-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0` +rk-usb-loader-target-userldlibs += `$(CROSS_PKG_CONFIG) --libs libusb-1.0` + +userccflags += -I $(srctree)/$(src)/include -isystem $(srctree)/scripts/include subdir-y += mod subdir-y += imx -subdir-$(CONFIG_X86) += setupmbr subdir-$(CONFIG_DTC) += dtc subdir-$(CONFIG_ARCH_TEGRA) += tegra -targetprogs-$(CONFIG_BAREBOXENV_TARGET) += bareboxenv-target -targetprogs-$(CONFIG_KERNEL_INSTALL_TARGET) += kernel-install-target -targetprogs-$(CONFIG_BAREBOXCRC32_TARGET) += bareboxcrc32-target -targetprogs-$(CONFIG_IMD_TARGET) += bareboximd-target - # Let clean descend into subdirs -subdir- += basic kconfig setupmbr - -quiet_cmd_csingle = CC $@ - cmd_csingle = $(CC) -Wp,-MD,$(depfile) $(TARGETCFLAGS) $(CFLAGS) -o $@ $< - -__targetprogs := $(sort $(targetprogs-y) $(targetprogs-m)) -target-csingle := $(foreach m,$(__targetprogs),$(if $($(m)-objs),,$(m))) -__targetprogs := $(addprefix $(obj)/,$(__targetprogs)) -target-csingle := $(addprefix $(obj)/,$(target-csingle)) -TARGETCFLAGS += -I$(srctree)/scripts/include/ - -always := $(hostprogs-y) $(hostprogs-m) $(targetprogs-y) - -$(target-csingle): %-target: %.c FORCE - $(call if_changed_dep,csingle) +subdir- += basic kconfig diff --git a/scripts/Makefile.build b/scripts/Makefile.build index db687d5f9e..25347eee01 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -16,6 +16,8 @@ lib-y := lib-m := pbl-y := always := +always-y := +always-m := targets := subdir-y := subdir-m := @@ -43,17 +45,14 @@ include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-di include scripts/Makefile.lib # Do not include host rules unless needed -ifneq ($(hostprogs-y)$(hostprogs-m),) +ifneq ($(hostprogs),) include scripts/Makefile.host endif -ifneq ($(KBUILD_SRC),) -# Create output directory if not already present -_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) - -# Create directories for object files if directory does not exist -# Needed when obj-y := dir/file.o syntax is used -_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d))) +# Do not include userprogs rules unless needed. +userprogs := $(sort $(userprogs)) +ifneq ($(userprogs),) +include scripts/Makefile.userprogs endif ifndef obj @@ -67,12 +66,12 @@ lib-target := $(obj)/lib.a endif ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(lib-target) $(pbl-y)),) -builtin-target := $(obj)/built-in.o +builtin-target := $(obj)/built-in.a endif ifeq ($(CONFIG_PBL_IMAGE), y) ifneq ($(strip $(pbl-y) $(builtin-target)),) -pbl-target := $(obj)/built-in-pbl.o +pbl-target := $(obj)/built-in.pbl.a endif endif @@ -80,37 +79,21 @@ endif __build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(pbl-target) $(extra-y)) \ $(if $(KBUILD_MODULES),$(obj-m)) \ - $(subdir-ym) $(always) + $(subdir-ym) $(always-y) @: # Linus' kernel sanity checking tool ifeq ($(KBUILD_CHECKSRC),1) quiet_cmd_checksrc = CHECK $< - cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; + cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< else ifeq ($(KBUILD_CHECKSRC),2) quiet_cmd_force_checksrc = CHECK $< - cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; + cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< endif # Compile C sources (.c) # --------------------------------------------------------------------------- -# Default is built-in, unless we know otherwise -modkern_cflags := $(CFLAGS_KERNEL) -quiet_modtag := $(empty) $(empty) - -$(real-objs-m) : modkern_cflags := $(CFLAGS_MODULE) -$(real-objs-m:.o=.i) : modkern_cflags := $(CFLAGS_MODULE) -$(real-objs-m:.o=.s) : modkern_cflags := $(CFLAGS_MODULE) -$(real-objs-m:.o=.lst): modkern_cflags := $(CFLAGS_MODULE) - -$(real-objs-m) : quiet_modtag := [M] -$(real-objs-m:.o=.i) : quiet_modtag := [M] -$(real-objs-m:.o=.s) : quiet_modtag := [M] -$(real-objs-m:.o=.lst): quiet_modtag := [M] - -$(obj-m) : quiet_modtag := [M] - # Default for not multi-part modules modname = $(basetarget) @@ -135,80 +118,23 @@ cmd_cc_i_c = $(CPP) $(c_flags) -o $@ $< %.i: %.c FORCE $(call if_changed_dep,cc_i_c) -quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_c = \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) -T $@ >/dev/null; \ - test -s $@ || rm -f $@ - -%.symtypes : %.c FORCE - $(call if_changed_dep,cc_symtypes_c) - # C (.c) files # The C file is compiled and updated dependency information is generated. # (See cmd_cc_o_c + relevant part of rule_cc_o_c) quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ -quiet_cmd_pbl_cc_o_c = PBLCC $@ - -ifndef CONFIG_MODVERSIONS -cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< -cmd_pbl_cc_o_c = $(CC) -D__PBL__ $(c_flags) $(PBL_CPPFLAGS) -c -o $@ $< - -else -# When module versioning is enabled the following steps are executed: -# o compile a .tmp_<file>.o from <file>.c -# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does -# not export symbols, we just rename .tmp_<file>.o to <file>.o and -# are done. -# o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate <file>.o from .tmp_<file>.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms - -cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< -cmd_modversions = \ - if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) $(if $(KBUILD_SYMTYPES), \ - -T $(@D)/$(@F:.o=.symtypes)) -a $(ARCH) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ - else \ - mv -f $(@D)/.tmp_$(@F) $@; \ - fi; -endif + cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< define rule_cc_o_c - $(call echo-cmd,checksrc) $(cmd_checksrc) \ - $(call echo-cmd,cc_o_c) $(cmd_cc_o_c); \ - $(cmd_modversions) \ - scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,cc_o_c)' > \ - $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd -endef - -define rule_pbl_cc_o_c - $(call echo-cmd,checksrc) $(cmd_checksrc) \ - $(call echo-cmd,pbl_cc_o_c) $(cmd_pbl_cc_o_c); \ - $(cmd_modversions) \ - scripts/basic/fixdep $(depfile) $@ '$(call make-cmd,pbl_cc_o_c)' > \ - $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd + $(call cmd,checksrc) + $(call cmd_and_fixdep,cc_o_c) endef # Built-in and composite module parts -pbl-%.o: %.c FORCE +%.pbl.o: %.c FORCE $(call cmd,force_checksrc) - $(call if_changed_rule,pbl_cc_o_c) + $(call if_changed_rule,cc_o_c) %.o: %.c FORCE $(call cmd,force_checksrc) @@ -232,11 +158,6 @@ quiet_cmd_cc_lst_c = MKLST $@ # Compile assembler sources (.S) # --------------------------------------------------------------------------- -modkern_aflags := $(AFLAGS_KERNEL) - -$(real-objs-m) : modkern_aflags := $(AFLAGS_MODULE) -$(real-objs-m:.o=.s): modkern_aflags := $(AFLAGS_MODULE) - quiet_cmd_as_s_S = CPP $(quiet_modtag) $@ cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< @@ -246,17 +167,15 @@ cmd_as_s_S = $(CPP) $(a_flags) -o $@ $< quiet_cmd_as_o_S = AS $(quiet_modtag) $@ cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< -quiet_cmd_pbl_as_o_S = PBLAS $@ -cmd_pbl_as_o_S = $(CC) -D__PBL__ $(a_flags) $(PBL_CPPFLAGS) -c -o $@ $< - -pbl-%.o: %.S FORCE - $(call if_changed_dep,pbl_as_o_S) +%.pbl.o: %.S FORCE + $(call if_changed_dep,as_o_S) %.o: %.S FORCE $(call if_changed_dep,as_o_S) -targets += $(real-objs-y) $(real-objs-m) $(lib-y) $(pbl-y) -targets += $(extra-y) $(MAKECMDGOALS) $(always) +targets += $(filter-out $(subdir-obj-y), $(real-obj-y)) $(real-obj-m) $(lib-y) +targets += $(pbl-y) +targets += $(extra-y) $(always-y) $(MAKECMDGOALS) # Linker scripts preprocessor (.lds.S -> .lds) # --------------------------------------------------------------------------- @@ -273,33 +192,20 @@ quiet_cmd_cpp_lds_S = LDS $@ $(sort $(subdir-obj-y)): $(subdir-ym) ; # -# Rule to compile a set of .o files into one .o file +# Rule to compile a set of .o files into one .a file (without symbol table) # -ifdef builtin-target -quiet_cmd_link_o_target = LD $@ -# If the list of objects to link is empty, just create an empty built-in.o -cmd_link_o_target = $(if $(strip $(obj-y)),\ - $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\ - rm -f $@; $(AR) rcs $@) +quiet_cmd_ar_builtin = AR $(quiet_modtag) $@ + cmd_ar_builtin = rm -f $@; $(AR) cDPrST $@ $(real-prereqs) -$(builtin-target): $(obj-y) FORCE - $(call if_changed,link_o_target) +$(builtin-target): $(real-obj-y) FORCE + $(call if_changed,ar_builtin) targets += $(builtin-target) -endif # builtin-target - -ifdef pbl-target -quiet_cmd_pbl_link_o_target = PBLLD $@ -# If the list of objects to link is empty, just create an empty built-in-pbl.o -cmd_pbl_link_o_target = $(if $(strip $(pbl-y)),\ - $(LD) $(ld_flags) -r -o $@ $(filter $(pbl-y), $^),\ - rm -f $@; $(AR) rcs $@) $(pbl-target): $(pbl-y) FORCE - $(call if_changed,pbl_link_o_target) + $(call if_changed,ar_builtin) targets += $(pbl-target) -endif # pbl-target # # Rule to compile a set of .o files into one .a file @@ -352,10 +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.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) @@ -378,11 +288,19 @@ FORCE: # optimization, we don't need to read them if the target does not # exist, we will rebuild anyway in that case. -targets := $(wildcard $(sort $(targets))) -cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) +existing-targets := $(wildcard $(sort $(targets))) -ifneq ($(cmd_files),) - include $(cmd_files) +-include $(foreach f,$(existing-targets),$(dir $(f)).$(notdir $(f)).cmd) + +ifdef building_out_of_srctree +# Create directories for object files if they do not exist +obj-dirs := $(sort $(obj) $(patsubst %/,%, $(dir $(targets)))) +# If targets exist, their directories apparently exist. Skip mkdir. +existing-dirs := $(sort $(patsubst %/,%, $(dir $(existing-targets)))) +obj-dirs := $(strip $(filter-out $(existing-dirs), $(obj-dirs))) +ifneq ($(obj-dirs),) +$(shell mkdir -p $(obj-dirs)) +endif endif .PHONY: $(PHONY) diff --git a/scripts/Makefile.clean b/scripts/Makefile.clean index 41712f8975..3c4519fa8a 100644 --- a/scripts/Makefile.clean +++ b/scripts/Makefile.clean @@ -35,9 +35,12 @@ subdir-ymn := $(addprefix $(obj)/,$(subdir-ymn)) # build a list of files to remove, usually relative to the current # directory -__clean-files := $(extra-y) $(extra-m) $(extra-) \ - $(always) $(targets) $(clean-files) \ - $(hostprogs-y) $(hostprogs-m) $(hostprogs-) +__clean-files := \ + $(clean-files) $(targets) $(hostprogs) $(userprogs) \ + $(extra-y) $(extra-m) $(extra-) \ + $(always-y) $(always-m) $(always-) \ + $(hostprogs-always-y) $(hostprogs-always-m) $(hostprogs-always-) \ + $(userprogs-always-y) $(userprogs-always-m) $(userprogs-always-) # as clean-files is given relative to the current directory, this adds # a $(obj) prefix, except for absolute paths @@ -46,28 +49,15 @@ __clean-files := $(wildcard \ $(addprefix $(obj)/, $(filter-out /%, $(__clean-files))) \ $(filter /%, $(__clean-files))) -# as clean-dirs is given relative to the current directory, this adds -# a $(obj) prefix, except for absolute paths - -__clean-dirs := $(wildcard \ - $(addprefix $(obj)/, $(filter-out /%, $(clean-dirs))) \ - $(filter /%, $(clean-dirs))) - # ========================================================================== quiet_cmd_clean = CLEAN $(obj) - cmd_clean = rm -f $(__clean-files) -quiet_cmd_cleandir = CLEAN $(__clean-dirs) - cmd_cleandir = rm -rf $(__clean-dirs) - + cmd_clean = rm -rf $(__clean-files) __clean: $(subdir-ymn) ifneq ($(strip $(__clean-files)),) +$(call cmd,clean) endif -ifneq ($(strip $(__clean-dirs)),) - +$(call cmd,cleandir) -endif @: diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 8a88cbc9ae..038b3054ab 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -1,3 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0 + +# LEX +# --------------------------------------------------------------------------- +quiet_cmd_flex = LEX $@ + cmd_flex = $(LEX) -o$@ -L $< + +$(obj)/%.lex.c: $(src)/%.l FORCE + $(call if_changed,flex) + +# YACC +# --------------------------------------------------------------------------- +quiet_cmd_bison = YACC $(basename $@).[ch] + cmd_bison = $(YACC) -o $(basename $@).c --defines=$(basename $@).h -t -l $< + +$(obj)/%.tab.c $(obj)/%.tab.h: $(src)/%.y FORCE + $(call if_changed,bison) + # ========================================================================== # Building binaries on the host system # Binaries are used during the compilation of the kernel, for example @@ -5,22 +23,22 @@ # # Both C and C++ are supported, but preferred language is C for such utilities. # -# Sample syntax (see Documentation/kbuild/makefiles.txt for reference) -# hostprogs-y := bin2hex +# Sample syntax (see Documentation/kbuild/makefiles.rst for reference) +# hostprogs := bin2hex # Will compile bin2hex.c and create an executable named bin2hex # -# hostprogs-y := lxdialog +# hostprogs := lxdialog # lxdialog-objs := checklist.o lxdialog.o # Will compile lxdialog.c and checklist.c, and then link the executable # lxdialog, based on checklist.o and lxdialog.o # -# hostprogs-y := qconf +# hostprogs := qconf # qconf-cxxobjs := qconf.o # qconf-objs := menu.o # Will compile qconf as a C++ program, and menu as a C program. # They are linked as C++ code to the executable qconf -__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) +__hostprogs := $(sort $(hostprogs)) # C code # Executables compiled from a single .c file @@ -58,17 +76,15 @@ host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) host-objdirs := $(addprefix $(obj)/,$(host-objdirs)) -obj-dirs += $(host-objdirs) - ##### # Handle options to gcc. Support building with separate output directory -_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ - $(HOSTCFLAGS_$(basetarget).o) -_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ - $(HOSTCXXFLAGS_$(basetarget).o) +_hostc_flags = $(KBUILD_HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ + $(HOSTCFLAGS_$(target-stem).o) +_hostcxx_flags = $(KBUILD_HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ + $(HOSTCXXFLAGS_$(target-stem).o) -ifeq ($(KBUILD_SRC),) +ifndef building_out_of_srctree __hostc_flags = $(_hostc_flags) __hostcxx_flags = $(_hostcxx_flags) else @@ -85,17 +101,17 @@ hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags) # Create executable from a single .c file # host-csingle -> Executable quiet_cmd_host-csingle = HOSTCC $@ - cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(HOSTLDFLAGS) -o $@ $< \ - $(HOST_LOADLIBES) $(HOSTLDLIBS_$(@F)) + cmd_host-csingle = $(HOSTCC) $(hostc_flags) $(KBUILD_HOSTLDFLAGS) -o $@ $< \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-csingle): $(obj)/%: $(src)/%.c FORCE $(call if_changed_dep,host-csingle) # Link an executable based on list of .o files, all plain c # host-cmulti -> executable quiet_cmd_host-cmulti = HOSTLD $@ - cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ - $(addprefix $(obj)/,$($(@F)-objs)) \ - $(HOST_LOADLIBES) $(HOSTLDLIBS_$(@F)) + cmd_host-cmulti = $(HOSTCC) $(KBUILD_HOSTLDFLAGS) -o $@ \ + $(addprefix $(obj)/, $($(target-stem)-objs)) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-cmulti): FORCE $(call if_changed,host-cmulti) $(call multi_depend, $(host-cmulti), , -objs) @@ -110,10 +126,10 @@ $(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE # Link an executable based on list of .o files, a mixture of .c and .cc # host-cxxmulti -> executable quiet_cmd_host-cxxmulti = HOSTLD $@ - cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \ + cmd_host-cxxmulti = $(HOSTCXX) $(KBUILD_HOSTLDFLAGS) -o $@ \ $(foreach o,objs cxxobjs,\ - $(addprefix $(obj)/,$($(@F)-$(o)))) \ - $(HOST_LOADLIBES) $(HOSTLDLIBS_$(@F)) + $(addprefix $(obj)/, $($(target-stem)-$(o)))) \ + $(KBUILD_HOSTLDLIBS) $(HOSTLDLIBS_$(target-stem)) $(host-cxxmulti): FORCE $(call if_changed,host-cxxmulti) $(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) diff --git a/scripts/Makefile.kasan b/scripts/Makefile.kasan new file mode 100644 index 0000000000..83f6aa543d --- /dev/null +++ b/scripts/Makefile.kasan @@ -0,0 +1,17 @@ + # SPDX-License-Identifier: GPL-2.0 +ifdef CONFIG_KASAN +CFLAGS_KASAN_NOSANITIZE := -fno-builtin +KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET) +endif + +CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address + +cc-param = $(call cc-option, -mllvm -$(1), $(call cc-option, --param $(1))) + +CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) \ + $(call cc-param,asan-globals=1) \ + $(call cc-param,asan-instrument-allocas=1) + +ifndef CONFIG_CPU_64 +CFLAGS_KASAN += $(call cc-param,asan-stack=1) +endif diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 9aa8be535f..6b1f0ccbc0 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -1,3 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# Backward compatibility +asflags-y += $(EXTRA_AFLAGS) +ccflags-y += $(EXTRA_CFLAGS) +cppflags-y += $(EXTRA_CPPFLAGS) +ldflags-y += $(EXTRA_LDFLAGS) +always-y += $(always) +hostprogs += $(hostprogs-y) $(hostprogs-m) + # Figure out what we need to build from the various variables # =========================================================================== @@ -11,19 +20,9 @@ obj-m := $(filter-out $(obj-y),$(obj-m)) lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) - -pbl-y += $(pbl-dtb-y) -obj-y += $(obj-dtb-y) -extra-y += $(patsubst %.dtb.o,%.dtb.S,$(obj-dtb-y)) -extra-y += $(patsubst %.dtb.o,%.dtb,$(obj-dtb-y)) -extra-y += $(patsubst %.dtb.o,%.dtb.S,$(pbl-dtb-y)) -extra-y += $(patsubst %.dtb.o,%.dtb,$(pbl-dtb-y)) -extra-y += $(patsubst %.dtb.o,%.dtb.S,$(lwl-dtb-y)) -extra-y += $(patsubst %.dtb.o,%.dtb,$(lwl-dtb-y)) - # Handle objects in subdirs # --------------------------------------------------------------------------- -# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o +# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.a # and add the directory to the list of dirs to descend into: $(subdir-y) # o if we encounter foo/ in $(obj-m), remove it from $(obj-m) # and add the directory to the list of dirs to descend into: $(subdir-m) @@ -31,29 +30,29 @@ extra-y += $(patsubst %.dtb.o,%.dtb,$(lwl-dtb-y)) # lowlevel is present in the PBL if enabled # otherwise in barebox ifeq ($(CONFIG_PBL_IMAGE), y) -pbl-y += $(lwl-y) $(lwl-dtb-y) +pbl-y += $(lwl-y) else -obj-y += $(lwl-y) $(lwl-dtb-y) +obj-y += $(lwl-y) endif obj-y += $(obj-pbl-y) pbl-y += $(obj-pbl-y) -# add pbl- prefix to the target -pbl-y := $(shell echo $(pbl-y) | sed -e 's%\(\([^ \t]\+/\)*\)\([^ \t]*\.o\)%\2pbl-\3%g') +# pbl objects are suffixed with .pbl.o +pbl-y := $(patsubst %.o,%.pbl.o,$(pbl-y)) # add subdir from $(obj-y) too so we do not need to have the dir define in # both $(obj-y) and $(pbl-y) __pbl-y := $(filter-out $(pbl-y), $(filter %/, $(obj-y))) pbl-y += $(__pbl-y) -pbl-y := $(sort $(patsubst %/, %/built-in-pbl.o, $(pbl-y))) +pbl-y := $(sort $(patsubst %/, %/built-in.pbl.a, $(pbl-y))) __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) subdir-y += $(__subdir-y) __subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m))) subdir-m += $(__subdir-m) -obj-y := $(patsubst %/, %/built-in.o, $(obj-y)) +obj-y := $(patsubst %/, %/built-in.a, $(obj-y)) obj-m := $(filter-out %/, $(obj-m)) # Subdirectories we need to descend into @@ -74,37 +73,54 @@ multi-objs := $(multi-objs-y) $(multi-objs-m) # $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to # tell kbuild to descend -__subdir-obj-y := $(filter %/built-in-pbl.o, $(pbl-y)) -subdir-obj-y := $(filter %/built-in.o, $(obj-y)) +__subdir-obj-y := $(filter %/built-in.pbl.a, $(pbl-y)) +subdir-obj-y := $(filter %/built-in.a, $(obj-y)) subdir-obj-y += $(__subdir-obj-y) -# $(obj-dirs) is a list of directories that contain object files -obj-dirs := $(dir $(multi-objs) $(obj-y) $(pbl-y)) +obj-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y)) +extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX),$(bbenv-y)) +extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).S,$(bbenv-y)) +extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y)) + +# Replace multi-part objects by their individual parts, +# including built-in.a from subdirectories +real-obj-y := $(foreach m, $(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) +real-obj-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)) $($(m:.o=-))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m))) + +always-y += $(always-m) -# Replace multi-part objects by their individual parts, look at local dir only -real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y) -real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) +# hostprogs-always-y += foo +# ... is a shorthand for +# hostprogs += foo +# always-y += foo +hostprogs += $(hostprogs-always-y) $(hostprogs-always-m) +always-y += $(hostprogs-always-y) $(hostprogs-always-m) + +# userprogs-always-y is likewise. +userprogs += $(userprogs-always-y) $(userprogs-always-m) +always-y += $(userprogs-always-y) $(userprogs-always-m) # Add subdir path extra-y := $(addprefix $(obj)/,$(extra-y)) -always := $(addprefix $(obj)/,$(always)) +always-y := $(addprefix $(obj)/,$(always-y)) targets := $(addprefix $(obj)/,$(targets)) obj-y := $(addprefix $(obj)/,$(obj-y)) obj-m := $(addprefix $(obj)/,$(obj-m)) lib-y := $(addprefix $(obj)/,$(lib-y)) pbl-y := $(addprefix $(obj)/,$(pbl-y)) subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y)) -real-objs-y := $(addprefix $(obj)/,$(real-objs-y)) -real-objs-m := $(addprefix $(obj)/,$(real-objs-m)) +real-obj-y := $(addprefix $(obj)/,$(real-obj-y)) +real-obj-m := $(addprefix $(obj)/,$(real-obj-m)) single-used-m := $(addprefix $(obj)/,$(single-used-m)) multi-used-y := $(addprefix $(obj)/,$(multi-used-y)) multi-used-m := $(addprefix $(obj)/,$(multi-used-m)) multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y)) multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m)) subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) -obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) -bbenv-y := $(addprefix $(obj)/,$(bbenv-y)) + +# target with $(obj)/ and its suffix stripped +target-stem = $(basename $(patsubst $(obj)/%,%,$@)) # These flags are needed for modversions and compiling, so we define them here # already @@ -118,9 +134,19 @@ basename_flags = -D"KBUILD_BASENAME=KBUILD_STR($(call name-fix,$(basetarget)))" modname_flags = $(if $(filter 1,$(words $(modname))),\ -D"KBUILD_MODNAME=KBUILD_STR($(call name-fix,$(modname)))") -_c_flags = $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$(basetarget).o) -_a_flags = $(AFLAGS) $(EXTRA_AFLAGS) $(AFLAGS_$(basetarget).o) -_cpp_flags = $(CPPFLAGS) $(EXTRA_CPPFLAGS) $(CPPFLAGS_$(@F)) +_c_flags = $(KBUILD_CFLAGS) $(ccflags-y) $(CFLAGS_$(target-stem).o) +_a_flags = $(KBUILD_AFLAGS) $(asflags-y) $(AFLAGS_$(target-stem).o) +_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(target-stem).lds) + +# +# Enable address sanitizer flags for kernel except some files or directories +# we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE) +# +ifeq ($(CONFIG_KASAN),y) +_c_flags += $(if $(part-of-pbl),, $(if $(patsubst n%,, \ + $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ + $(CFLAGS_KASAN), $(CFLAGS_KASAN_NOSANITIZE))) +endif ifeq ($(CONFIG_UBSAN),y) _CFLAGS_UBSAN = $(eval _CFLAGS_UBSAN := $(CFLAGS_UBSAN))$(_CFLAGS_UBSAN) @@ -130,10 +156,29 @@ _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 '/'). -ifeq ($(KBUILD_SRC),) +ifndef building_out_of_srctree __c_flags = $(_c_flags) __a_flags = $(_a_flags) __cpp_flags = $(_cpp_flags) @@ -148,22 +193,39 @@ __a_flags = $(call flags,_a_flags) __cpp_flags = $(call flags,_cpp_flags) endif -c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(CPPFLAGS) \ - $(__c_flags) $(modkern_cflags) \ +part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y) +part-of-pbl = $(if $(filter $(basename $@).o, $(pbl-y))$(filter $@, $(pbl-target)),y) +quiet_modtag = $(if $(part-of-pbl),[P],$(if $(part-of-module),[M], )) + +pbl_cppflags = $(if $(part-of-pbl), -D__PBL__ $(PBL_CPPFLAGS)) + +modkern_cflags = \ + $(if $(part-of-module), \ + $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ + $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags)) + +modkern_aflags = $(if $(part-of-module), \ + $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE), \ + $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL)) + +c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ + $(__c_flags) $(modkern_cflags) $(pbl_cppflags) \ -D"KBUILD_STR(s)=\#s" $(basename_flags) $(modname_flags) -a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(CPPFLAGS) \ - $(__a_flags) $(modkern_aflags) +a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(KBUILD_CPPFLAGS) \ + $(__a_flags) $(modkern_aflags) $(pbl_cppflags) cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(__cpp_flags) -ld_flags = $(LDFLAGS) $(EXTRA_LDFLAGS) +ld_flags = $(KBUILD_LDFLAGS) $(ldflags-y) dtc_cpp_flags = -Wp,-MD,$(depfile).pre -nostdinc \ + -Wp,-MT,$(basename $(notdir $@)).o \ -I$(srctree)/arch/$(SRCARCH)/dts/include \ - -I$(srctree)/dts/include \ -I$(srctree)/include \ + -I$(srctree)/dts/include \ -I$(srctree)/dts/src/ \ + $(DTC_CPP_FLAGS_$(basetarget)$(suffix $@)) \ -undef -D__DTS__ ifdef CONFIG_BOOTM_FITIMAGE_PUBKEY @@ -185,31 +247,15 @@ $(foreach m, $(notdir $1), \ $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) endef -# LEX -# --------------------------------------------------------------------------- -quiet_cmd_flex = LEX $@ - cmd_flex = $(LEX) -o$@ -L $< - -$(obj)/%.lex.c: $(src)/%.l FORCE - $(call if_changed,flex) - -# YACC -# --------------------------------------------------------------------------- -quiet_cmd_bison = YACC $@ - cmd_bison = $(YACC) -o$@ -t -l $< - -$(obj)/%.tab.c: $(src)/%.y FORCE - $(call if_changed,bison) - -quiet_cmd_bison_h = YACC $@ - cmd_bison_h = $(YACC) -o/dev/null --defines=$@ -t -l $< - -$(obj)/%.tab.h: $(src)/%.y FORCE - $(call if_changed,bison_h) - # Shipped files # =========================================================================== +quiet_cmd_0size = 0SIZE $@ +cmd_0size = : > $@ + +quiet_cmd_delete = DELETE $@ + cmd_delete = rm -f $@ + quiet_cmd_shipped = SHIPPED $@ cmd_shipped = cat $< > $@ @@ -227,11 +273,22 @@ $(obj)/%:: $(src)/%_shipped # and add target to extra-y so that we know we have to # read in the saved command line +# Prelinking +# --------------------------------------------------------------------------- + +ifneq ($(CONFIG_RISCV),) +quiet_cmd_prelink__ = PRELINK $@ + cmd_prelink__ = $(objtree)/scripts/prelink-riscv $@ +endif + +quiet_cmd_prelink__ ?= + cmd_prelink__ ?= + # Linking # --------------------------------------------------------------------------- quiet_cmd_ld = LD $@ -cmd_ld = $(LD) $(LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) \ +cmd_ld = $(LD) $(KBUILD_LDFLAGS) $(EXTRA_LDFLAGS) $(LDFLAGS_$(@F)) \ $(filter-out FORCE,$^) -o $@ # Objcopy @@ -240,6 +297,27 @@ cmd_ld = $(LD) $(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 # --------------------------------------------------------------------------- @@ -288,44 +366,56 @@ 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 $@ -cmd_dtc = $(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) -obj-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y)) -extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX),$(bbenv-y)) -extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).S,$(bbenv-y)) -extra-y += $(patsubst %,%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).o,$(bbenv-y)) - 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'; \ @@ -339,6 +429,9 @@ cmd_env_S = \ $(obj)/%.bbenv$(DEFAULT_COMPRESSION_SUFFIX).S: $(src)/%.bbenv$(DEFAULT_COMPRESSION_SUFFIX) FORCE $(call if_changed,env_S) +quiet_cmd_envgen = ENVGEN $@ +cmd_envgen=$(srctree)/scripts/genenv $(objtree) $(objtree) $@ $2 + quiet_cmd_env = ENV $@ cmd_env=$(srctree)/scripts/genenv $(srctree) $(objtree) $@ $< @@ -394,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 # --------------------------------------------------------------------------- @@ -471,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:'; \ @@ -486,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 \ @@ -494,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) @@ -542,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.modpost b/scripts/Makefile.modpost index 78e6edd925..78e4ed7189 100644 --- a/scripts/Makefile.modpost +++ b/scripts/Makefile.modpost @@ -97,7 +97,7 @@ targets += $(modules:.ko=.mod.o) # Step 6), final link of the modules quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = $(LD) -r $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ + cmd_ld_ko_o = $(LD) -r $(KBUILD_LDFLAGS) $(LDFLAGS_MODULE) -o $@ \ $(filter-out FORCE,$^) $(modules): %.ko :%.o %.mod.o FORCE 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/Makefile.userprogs b/scripts/Makefile.userprogs new file mode 100644 index 0000000000..fb41529733 --- /dev/null +++ b/scripts/Makefile.userprogs @@ -0,0 +1,45 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Build userspace programs for the target system +# + +# Executables compiled from a single .c file +user-csingle := $(foreach m, $(userprogs), $(if $($(m)-objs),,$(m))) + +# Executables linked based on several .o files +user-cmulti := $(foreach m, $(userprogs), $(if $($(m)-objs),$(m))) + +# Objects compiled from .c files +user-cobjs := $(sort $(foreach m, $(userprogs), $($(m)-objs))) + +user-csingle := $(addprefix $(obj)/, $(user-csingle)) +user-cmulti := $(addprefix $(obj)/, $(user-cmulti)) +user-cobjs := $(addprefix $(obj)/, $(user-cobjs)) + +user_ccflags = -Wp,-MMD,$(depfile) $(KBUILD_USERCFLAGS) $(userccflags) \ + $($(target-stem)-userccflags) +user_ldflags = $(KBUILD_USERLDFLAGS) $(userldflags) $($(target-stem)-userldflags) + +# Create an executable from a single .c file +quiet_cmd_user_cc_c = CC [U] $@ + cmd_user_cc_c = $(CC) $(user_ccflags) $(user_ldflags) -o $@ $< \ + $($(target-stem)-userldlibs) +$(user-csingle): $(obj)/%: $(src)/%.c FORCE + $(call if_changed_dep,user_cc_c) + +# Link an executable based on list of .o files +quiet_cmd_user_ld = LD [U] $@ + cmd_user_ld = $(CC) $(user_ldflags) -o $@ \ + $(addprefix $(obj)/, $($(target-stem)-objs)) \ + $($(target-stem)-userldlibs) +$(user-cmulti): FORCE + $(call if_changed,user_ld) +$(call multi_depend, $(user-cmulti), , -objs) + +# Create .o file from a .c file +quiet_cmd_user_cc_o_c = CC [U] $@ + cmd_user_cc_o_c = $(CC) $(user_ccflags) -c -o $@ $< +$(user-cobjs): $(obj)/%.o: $(src)/%.c FORCE + $(call if_changed_dep,user_cc_o_c) + +targets += $(user-csingle) $(user-cmulti) $(user-cobjs) diff --git a/scripts/bareboxcrc32-target.c b/scripts/bareboxcrc32-target.c new file mode 100644 index 0000000000..6c09c9f763 --- /dev/null +++ b/scripts/bareboxcrc32-target.c @@ -0,0 +1 @@ +#include "bareboxcrc32.c" diff --git a/scripts/bareboxcrc32.c b/scripts/bareboxcrc32.c index 1b105a452b..6d39fa047d 100644 --- a/scripts/bareboxcrc32.c +++ b/scripts/bareboxcrc32.c @@ -1,21 +1,7 @@ -/* - * bareboxcrc32.c - generate crc32 checksum in little endian - * - * Copyright (c) 2013 Michael Grzeschik <mgr@pengutronix.de> - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2013 Michael Grzeschik <mgr@pengutronix.de> + +/* bareboxcrc32.c - generate crc32 checksum in little endian */ #include <stdio.h> #include <sys/types.h> diff --git a/scripts/bareboxenv-target.c b/scripts/bareboxenv-target.c new file mode 100644 index 0000000000..caf1759205 --- /dev/null +++ b/scripts/bareboxenv-target.c @@ -0,0 +1 @@ +#include "bareboxenv.c" diff --git a/scripts/bareboxenv.c b/scripts/bareboxenv.c index c512a105ef..e954447015 100644 --- a/scripts/bareboxenv.c +++ b/scripts/bareboxenv.c @@ -1,21 +1,7 @@ -/* - * bareboxenv.c - generate or read a barebox environment archive - * - * Copyright (c) 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2007 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix + +/* bareboxenv.c - generate or read a barebox environment archive */ #include <stdio.h> #include <sys/types.h> @@ -34,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. @@ -104,6 +90,7 @@ static char *concat_subpath_file(const char *path, const char *f) #include "../include/envfs.h" #include "../crypto/crc32.c" #include "../lib/make_directory.c" +#include "../common/envfs-core.c" #include "../common/environment.c" static void usage(char *prgname) @@ -111,6 +98,12 @@ static void usage(char *prgname) printf( "Usage : %s [OPTION] DIRECTORY FILE\n" "Load a barebox environment sector into a directory or\n" "save a directory into a barebox environment sector\n" +#ifndef __BAREBOX__ + "\n" + "Attention:\n" + "Depending on your environment backend storage you need to\n" + "erase FILE before you save the new environment.\n" +#endif "\n" "options:\n" " -s save (directory -> environment sector)\n" diff --git a/scripts/bareboximd-target.c b/scripts/bareboximd-target.c new file mode 100644 index 0000000000..903adee53d --- /dev/null +++ b/scripts/bareboximd-target.c @@ -0,0 +1 @@ +#include "bareboximd.c" diff --git a/scripts/bareboximd.c b/scripts/bareboximd.c index 5ef91831c4..ab47ad27e4 100644 --- a/scripts/bareboximd.c +++ b/scripts/bareboximd.c @@ -1,29 +1,9 @@ -/* - * (C) Copyright 2014 Sascha Hauer, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) -#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2014 Sascha Hauer, Pengutronix #include <stdio.h> #include <sys/types.h> #include <stdint.h> -#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> @@ -33,7 +13,10 @@ #include <errno.h> #include <stdarg.h> #include <linux/err.h> +#include <linux/kernel.h> +#include "common.h" +#include "common.c" #include "../include/image-metadata.h" #define eprintf(args...) fprintf(stderr, ## args) @@ -57,15 +40,25 @@ int imd_command_setenv(const char *variable_name, const char *value) return -EINVAL; } -static int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size) +static inline void read_file_2_free(void *buf) +{ + /* + * Can't free() here because buffer might be mmapped. No need + * to do anything as we are exitting in a moment anyway. + */ +} + +static unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) { - off_t fsize; - ssize_t rsize; - int ret, fd; - void *buf; + return strtoul(cp, endp, base); +} - *size = 0; - *outbuf = NULL; +static int imd_read_file(const char *filename, size_t *size, void **outbuf, + bool allow_mmap) +{ + void *buf = MAP_FAILED; + int fd, ret; + size_t fsize; fd = open(filename, O_RDONLY); if (fd < 0) { @@ -80,55 +73,25 @@ static int read_file_2(const char *filename, size_t *size, void **outbuf, size_t goto close; } - if (fsize < max_size) - max_size = fsize; + if (allow_mmap) + buf = mmap(NULL, fsize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - if (lseek(fd, 0, SEEK_SET) == -1) { - fprintf(stderr, "Cannot seek to start %s: %s\n", filename, strerror(errno)); - ret = -errno; - goto close; - } - - buf = malloc(max_size); - if (!buf) { - fprintf(stderr, "Cannot allocate memory\n"); - ret = -ENOMEM; - goto close; + if (buf == MAP_FAILED) { + close(fd); + return read_file_2(filename, size, outbuf, 0x100000); } *outbuf = buf; - while (*size < max_size) { - rsize = read(fd, buf, max_size-*size); - if (rsize == 0) { - ret = -EIO; - goto free; - } else if (rsize < 0) { - if (errno == EAGAIN) - continue; - else { - ret = -errno; - goto free; - } - } /* ret > 0 */ - buf += rsize; - *size += rsize; - } + *size = fsize; - ret = 0; - goto close; -free: - *outbuf = NULL; - free(buf); + return 0; close: close(fd); return ret; } -static unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) -{ - return strtoul(cp, endp, base); -} - +#include "../include/xfuncs.h" +#include "../crypto/crc32.c" #include "../common/imd.c" static void usage(const char *prgname) @@ -140,6 +103,9 @@ static void usage(const char *prgname) "Options:\n" "-t <type> only show information of <type>\n" "-n <no> for tags with multiple strings only show string <no>\n" +"-v Be verbose\n" +"-V Verify checksum of FILE\n" +"-c Create checksum for FILE and write it to the crc32 tag\n" "\n" "Without options all information available is printed. Valid types are:\n" "release, build, model, of_compatible\n", diff --git a/scripts/basic/.gitignore b/scripts/basic/.gitignore index dc24f5f4c7..961c91c8a8 100644 --- a/scripts/basic/.gitignore +++ b/scripts/basic/.gitignore @@ -1,2 +1,2 @@ -docproc -fixdep +# SPDX-License-Identifier: GPL-2.0-only +/fixdep diff --git a/scripts/basic/Makefile b/scripts/basic/Makefile index 9e92d899a5..eeb6a38c55 100644 --- a/scripts/basic/Makefile +++ b/scripts/basic/Makefile @@ -1,15 +1,5 @@ -### -# Makefile.basic list the most basic programs used during the build process. -# The programs listed herein is what is needed to do the basic stuff, -# such as fix dependency file. -# This initial step is needed to avoid files to be recompiled -# when barebox configuration changes (which is what happens when -# .config is included by main Makefile. -# --------------------------------------------------------------------------- -# fixdep: Used to generate dependency information during build process +# SPDX-License-Identifier: GPL-2.0-only +# +# fixdep: used to generate dependency information during build process -hostprogs-y := fixdep -always := $(hostprogs-y) - -# fixdep is needed to compile other host programs -$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep +hostprogs-always-y += fixdep diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index facbd603ad..44e887cff4 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -34,7 +34,7 @@ * the config symbols are rebuilt. * * So if the user changes his CONFIG_HIS_DRIVER option, only the objects - * which depend on "include/config/his/driver.h" will be rebuilt, + * which depend on "include/config/HIS_DRIVER" will be rebuilt, * so most likely only his driver ;-) * * The idea above dates, by the way, back to Michael E Chastain, AFAIK. @@ -74,14 +74,9 @@ * * and then basically copies the .<target>.d file to stdout, in the * process filtering out the dependency on autoconf.h and adding - * dependencies on include/config/my/option.h for every + * dependencies on include/config/MY_OPTION for every * CONFIG_MY_OPTION encountered in any of the prerequisites. * - * It will also filter out all the dependencies on *.ver. We need - * to make sure that the generated version checksum are globally up - * to date before even starting the recursive build, so it's too late - * at this point anyway. - * * We don't even try to really parse the header files, but * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will * be picked up as well. It's not a problem with respect to @@ -99,6 +94,7 @@ #include <unistd.h> #include <fcntl.h> #include <string.h> +#include <stdarg.h> #include <stdlib.h> #include <stdio.h> #include <ctype.h> @@ -110,31 +106,29 @@ static void usage(void) } /* - * Print out a dependency path from a symbol name + * In the intended usage of this program, the stdout is redirected to .*.cmd + * files. The return value of printf() must be checked to catch any error, + * e.g. "No space left on device". */ -static void print_dep(const char *m, int slen, const char *dir) +static void xprintf(const char *format, ...) { - int c, prev_c = '/', i; + va_list ap; + int ret; - printf(" $(wildcard %s/", dir); - for (i = 0; i < slen; i++) { - c = m[i]; - if (c == '_') - c = '/'; - else - c = tolower(c); - if (c != '/' || prev_c != '/') - putchar(c); - prev_c = c; + va_start(ap, format); + ret = vprintf(format, ap); + if (ret < 0) { + perror("fixdep"); + exit(1); } - printf(".h) \\\n"); + va_end(ap); } struct item { struct item *next; unsigned int len; unsigned int hash; - char name[0]; + char name[]; }; #define HASHSZ 256 @@ -194,7 +188,8 @@ static void use_config(const char *m, int slen) return; define_config(m, slen, hash); - print_dep(m, slen, "include/config"); + /* Print out a dependency path from a symbol name. */ + xprintf(" $(wildcard include/config/%.*s) \\\n", slen, m); } /* test if s ends in sub */ @@ -220,7 +215,7 @@ static void parse_config_file(const char *p) } p += 7; q = p; - while (*q && (isalnum(*q) || *q == '_')) + while (isalnum(*q) || *q == '_') q++; if (str_ends_with(p, q - p, "_MODULE")) r = q - 7; @@ -268,8 +263,7 @@ static void *read_file(const char *filename) static int is_ignored_file(const char *s, int len) { return str_ends_with(s, len, "include/generated/autoconf.h") || - str_ends_with(s, len, "include/generated/autoksyms.h") || - str_ends_with(s, len, ".ver"); + str_ends_with(s, len, "include/generated/autoksyms.h"); } /* @@ -324,13 +318,13 @@ static void parse_dep_file(char *m, const char *target) */ if (!saw_any_target) { saw_any_target = 1; - printf("source_%s := %s\n\n", - target, m); - printf("deps_%s := \\\n", target); + xprintf("source_%s := %s\n\n", + target, m); + xprintf("deps_%s := \\\n", target); } is_first_dep = 0; } else { - printf(" %s \\\n", m); + xprintf(" %s \\\n", m); } buf = read_file(m); @@ -353,8 +347,8 @@ static void parse_dep_file(char *m, const char *target) exit(1); } - printf("\n%s: $(deps_%s)\n\n", target, target); - printf("$(deps_%s):\n", target); + xprintf("\n%s: $(deps_%s)\n\n", target, target); + xprintf("$(deps_%s):\n", target); } int main(int argc, char *argv[]) @@ -369,7 +363,7 @@ int main(int argc, char *argv[]) target = argv[2]; cmdline = argv[3]; - printf("cmd_%s := %s\n\n", target, cmdline); + xprintf("cmd_%s := %s\n\n", target, cmdline); buf = read_file(depfile); parse_dep_file(buf, target); 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/canon-a1100-image b/scripts/canon-a1100-image deleted file mode 100755 index 6c08d7493a..0000000000 --- a/scripts/canon-a1100-image +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -e - -IFILE=$1 -OFILE=$2 - -dd if=/dev/zero bs=4M count=1 of=$OFILE 2>/dev/null -dd if=$IFILE of=$OFILE conv=notrunc 2>/dev/null - -# 0xffff0000: fe 3f f0 ea b 0xffc00000 -echo -n -e "\xfe\x3f\xf0\xea" | dd of=$OFILE bs=64K seek=63 conv=notrunc 2>/dev/null diff --git a/scripts/check_size b/scripts/check_size index 8530435d3a..76608eccce 100755 --- a/scripts/check_size +++ b/scripts/check_size @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash symbol="$1" file="$2" diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 65c2cfad45..dccc3c3fe7 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -885,10 +885,10 @@ sub is_maintained_obsolete { sub is_SPDX_License_valid { my ($license) = @_; - return 1 if (!$tree || which("python") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git")); + return 1 if (!$tree || which("python3") eq "" || !(-e "$root/scripts/spdxcheck.py") || !(-e "$root/.git")); my $root_path = abs_path($root); - my $status = `cd "$root_path"; echo "$license" | python scripts/spdxcheck.py -`; + my $status = `cd "$root_path"; echo "$license" | python3 scripts/spdxcheck.py -`; return 0 if ($status ne ""); return 1; } @@ -3010,7 +3010,7 @@ sub process { # linux device tree files my $dt_path = $root . "/dts/Bindings/"; - my $vp_file = $dt_path . "vendor-prefixes.txt"; ++ my $vp_file = $dt_path . "vendor-prefixes.yaml"; # barebox-specific bindings $dt_path = $dt_path . " " . $root . "/Documentation/devicetree/bindings/"; @@ -3028,7 +3028,7 @@ sub process { next if $compat !~ /^([a-zA-Z0-9\-]+)\,/; my $vendor = $1; - `grep -Eq "^$vendor\\b" $vp_file`; ++ `grep -Eq "\\"\\^\Q$vendor\E,\\.\\*\\":" $vp_file`; if ( $? >> 8 ) { WARN("UNDOCUMENTED_DT_STRING", "DT compatible string vendor \"$vendor\" appears un-documented -- check $vp_file\n" . $herecurr); @@ -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/clang-tools/gen_compile_commands.py b/scripts/clang-tools/gen_compile_commands.py new file mode 100755 index 0000000000..7ed3919f45 --- /dev/null +++ b/scripts/clang-tools/gen_compile_commands.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) Google LLC, 2018 +# +# Author: Tom Roeder <tmroeder@google.com> +# +"""A tool for generating compile_commands.json in the Linux kernel.""" + +import argparse +import json +import logging +import os +import sys +import re +import subprocess + +_DEFAULT_OUTPUT = 'compile_commands.json' +_DEFAULT_LOG_LEVEL = 'WARNING' + +_FILENAME_PATTERN = r'^\..*\.cmd$' +_LINE_PATTERN = r'^cmd_[^ ]*\.o := (.* )([^ ]*\.c)$' +_VALID_LOG_LEVELS = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] + + +def parse_arguments(): + """Sets up and parses command-line arguments. + + Returns: + log_level: A logging level to filter log output. + directory: The work directory where the objects were built. + ar: Command used for parsing .a archives. + output: Where to write the compile-commands JSON file. + paths: The list of files/directories to handle to find .cmd files. + """ + usage = 'Creates a compile_commands.json database from kernel .cmd files' + parser = argparse.ArgumentParser(description=usage) + + directory_help = ('specify the output directory used for the kernel build ' + '(defaults to the working directory)') + parser.add_argument('-d', '--directory', type=str, default='.', + help=directory_help) + + output_help = ('path to the output command database (defaults to ' + + _DEFAULT_OUTPUT + ')') + parser.add_argument('-o', '--output', type=str, default=_DEFAULT_OUTPUT, + help=output_help) + + log_level_help = ('the level of log messages to produce (defaults to ' + + _DEFAULT_LOG_LEVEL + ')') + parser.add_argument('--log_level', choices=_VALID_LOG_LEVELS, + default=_DEFAULT_LOG_LEVEL, help=log_level_help) + + ar_help = 'command used for parsing .a archives' + parser.add_argument('-a', '--ar', type=str, default='llvm-ar', help=ar_help) + + paths_help = ('directories to search or files to parse ' + '(files should be *.o, *.a, or modules.order). ' + 'If nothing is specified, the current directory is searched') + parser.add_argument('paths', type=str, nargs='*', help=paths_help) + + args = parser.parse_args() + + return (args.log_level, + os.path.abspath(args.directory), + args.output, + args.ar, + args.paths if len(args.paths) > 0 else [args.directory]) + + +def cmdfiles_in_dir(directory): + """Generate the iterator of .cmd files found under the directory. + + Walk under the given directory, and yield every .cmd file found. + + Args: + directory: The directory to search for .cmd files. + + Yields: + The path to a .cmd file. + """ + + filename_matcher = re.compile(_FILENAME_PATTERN) + + for dirpath, _, filenames in os.walk(directory): + for filename in filenames: + if filename_matcher.match(filename): + yield os.path.join(dirpath, filename) + + +def to_cmdfile(path): + """Return the path of .cmd file used for the given build artifact + + Args: + Path: file path + + Returns: + The path to .cmd file + """ + dir, base = os.path.split(path) + return os.path.join(dir, '.' + base + '.cmd') + + +def cmdfiles_for_o(obj): + """Generate the iterator of .cmd files associated with the object + + Yield the .cmd file used to build the given object + + Args: + obj: The object path + + Yields: + The path to .cmd file + """ + yield to_cmdfile(obj) + + +def cmdfiles_for_a(archive, ar): + """Generate the iterator of .cmd files associated with the archive. + + Parse the given archive, and yield every .cmd file used to build it. + + Args: + archive: The archive to parse + + Yields: + The path to every .cmd file found + """ + for obj in subprocess.check_output([ar, '-t', archive]).decode().split(): + yield to_cmdfile(obj) + + +def cmdfiles_for_modorder(modorder): + """Generate the iterator of .cmd files associated with the modules.order. + + Parse the given modules.order, and yield every .cmd file used to build the + contained modules. + + Args: + modorder: The modules.order file to parse + + Yields: + The path to every .cmd file found + """ + with open(modorder) as f: + for line in f: + ko = line.rstrip() + base, ext = os.path.splitext(ko) + if ext != '.ko': + sys.exit('{}: module path must end with .ko'.format(ko)) + mod = base + '.mod' + # The first line of *.mod lists the objects that compose the module. + with open(mod) as m: + for obj in m.readline().split(): + yield to_cmdfile(obj) + + +def process_line(root_directory, command_prefix, file_path): + """Extracts information from a .cmd line and creates an entry from it. + + Args: + root_directory: The directory that was searched for .cmd files. Usually + used directly in the "directory" entry in compile_commands.json. + command_prefix: The extracted command line, up to the last element. + file_path: The .c file from the end of the extracted command. + Usually relative to root_directory, but sometimes absolute. + + Returns: + An entry to append to compile_commands. + + Raises: + ValueError: Could not find the extracted file based on file_path and + root_directory or file_directory. + """ + # The .cmd files are intended to be included directly by Make, so they + # escape the pound sign '#', either as '\#' or '$(pound)' (depending on the + # kernel version). The compile_commands.json file is not interepreted + # by Make, so this code replaces the escaped version with '#'. + prefix = command_prefix.replace('\#', '#').replace('$(pound)', '#') + + # Use os.path.abspath() to normalize the path resolving '.' and '..' . + abs_path = os.path.abspath(os.path.join(root_directory, file_path)) + if not os.path.exists(abs_path): + raise ValueError('File %s not found' % abs_path) + return { + 'directory': root_directory, + 'file': abs_path, + 'command': prefix + file_path, + } + + +def main(): + """Walks through the directory and finds and parses .cmd files.""" + log_level, directory, output, ar, paths = parse_arguments() + + level = getattr(logging, log_level) + logging.basicConfig(format='%(levelname)s: %(message)s', level=level) + + line_matcher = re.compile(_LINE_PATTERN) + + compile_commands = [] + + for path in paths: + # If 'path' is a directory, handle all .cmd files under it. + # Otherwise, handle .cmd files associated with the file. + # Most of built-in objects are linked via archives (built-in.a or lib.a) + # but some objects are linked to vmlinux directly. + # Modules are listed in modules.order. + if os.path.isdir(path): + cmdfiles = cmdfiles_in_dir(path) + elif path.endswith('.o'): + cmdfiles = cmdfiles_for_o(path) + elif path.endswith('.a'): + cmdfiles = cmdfiles_for_a(path, ar) + elif path.endswith('modules.order'): + cmdfiles = cmdfiles_for_modorder(path) + else: + sys.exit('{}: unknown file type'.format(path)) + + for cmdfile in cmdfiles: + with open(cmdfile, 'rt') as f: + result = line_matcher.match(f.readline()) + if result: + try: + entry = process_line(directory, result.group(1), + result.group(2)) + compile_commands.append(entry) + except ValueError as err: + logging.info('Could not add line from %s: %s', + cmdfile, err) + + with open(output, 'wt') as f: + json.dump(compile_commands, f, indent=2, sort_keys=True) + + +if __name__ == '__main__': + main() diff --git a/scripts/common.c b/scripts/common.c new file mode 100644 index 0000000000..49c468a1ea --- /dev/null +++ b/scripts/common.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <stdio.h> +#include <stdint.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> + +#include "common.h" +#include "compiler.h" + +int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size) +{ + off_t fsize; + ssize_t read_size, now; + int ret, fd; + void *buf; + + *size = 0; + *outbuf = NULL; + + fd = open(filename, O_RDONLY | O_BINARY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); + return -errno; + } + + fsize = lseek(fd, 0, SEEK_END); + if (fsize == -1) { + fprintf(stderr, "Cannot get size %s: %s\n", filename, strerror(errno)); + ret = -errno; + goto close; + } + + if (max_size < fsize) + read_size = max_size; + else + read_size = fsize; + + if (lseek(fd, 0, SEEK_SET) == -1) { + fprintf(stderr, "Cannot seek to start %s: %s\n", filename, strerror(errno)); + ret = -errno; + goto close; + } + + buf = malloc(read_size); + if (!buf) { + fprintf(stderr, "Cannot allocate memory\n"); + ret = -ENOMEM; + goto close; + } + + *outbuf = buf; + + while (read_size) { + now = read(fd, buf, read_size); + if (now == 0) { + ret = -EIO; + goto free; + } + + if (now < 0) { + ret = -errno; + goto free; + } + + buf += now; + *size += now; + read_size -= now; + } + + ret = 0; + goto close; +free: + free(*outbuf); + *outbuf = NULL; +close: + close(fd); + return ret; +} + +void *read_file(const char *filename, size_t *size) +{ + int ret; + void *buf; + + ret = read_file_2(filename, size, &buf, (size_t)-1); + if (!ret) + return buf; + + errno = -ret; + + return NULL; +} + +int write_file(const char *filename, const void *buf, size_t size) +{ + int fd, ret = 0; + int now; + + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); + return -errno; + } + + while (size) { + now = write(fd, buf, size); + if (now < 0) { + fprintf(stderr, "Cannot write to %s: %s\n", filename, + strerror(errno)); + ret = -errno; + goto out; + } + size -= now; + buf += now; + } + +out: + close(fd); + + return ret; +} + +int read_full(int fd, void *buf, size_t size) +{ + size_t insize = size; + int now; + int total = 0; + + while (size) { + now = read(fd, buf, size); + if (now == 0) + return total; + if (now < 0) + return now; + total += now; + size -= now; + buf += now; + } + + return insize; +} + +int write_full(int fd, const void *buf, size_t size) +{ + size_t insize = size; + int now; + + while (size) { + now = write(fd, buf, size); + if (now <= 0) + return now; + size -= now; + buf += now; + } + + return insize; +} diff --git a/scripts/common.h b/scripts/common.h new file mode 100644 index 0000000000..399729c338 --- /dev/null +++ b/scripts/common.h @@ -0,0 +1,10 @@ +#ifndef __COMMON_H +#define __COMMON_H + +int read_file_2(const char *filename, size_t *size, void **outbuf, size_t max_size); +void *read_file(const char *filename, size_t *size); +int write_file(const char *filename, const void *buf, size_t size); +int read_full(int fd, void *buf, size_t size); +int write_full(int fd, const void *buf, size_t size); + +#endif /* __COMMON_H */ diff --git a/scripts/compiler.h b/scripts/compiler.h index 0ad25f9e8d..925cad21b6 100644 --- a/scripts/compiler.h +++ b/scripts/compiler.h @@ -61,7 +61,39 @@ 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> # include <byteswap.h> #endif @@ -127,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/config b/scripts/config new file mode 100755 index 0000000000..ff88e2faef --- /dev/null +++ b/scripts/config @@ -0,0 +1,230 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 +# Manipulate options in a .config file from the command line + +myname=${0##*/} + +# If no prefix forced, use the default CONFIG_ +CONFIG_="${CONFIG_-CONFIG_}" + +# We use an uncommon delimiter for sed substitutions +SED_DELIM=$(echo -en "\001") + +usage() { + cat >&2 <<EOL +Manipulate options in a .config file from the command line. +Usage: +$myname options command ... +commands: + --enable|-e option Enable option + --disable|-d option Disable option + --module|-m option Turn option into a module + --set-str option string + Set option to "string" + --set-val option value + Set option to value + --undefine|-u option Undefine option + --state|-s option Print state of option (n,y,m,undef) + + --enable-after|-E beforeopt option + Enable option directly after other option + --disable-after|-D beforeopt option + Disable option directly after other option + --module-after|-M beforeopt option + Turn option into module directly after other option + + commands can be repeated multiple times + +options: + --file config-file .config file to change (default .config) + --keep-case|-k Keep next symbols' case (dont' upper-case it) + +$myname doesn't check the validity of the .config file. This is done at next +make time. + +By default, $myname will upper-case the given symbol. Use --keep-case to keep +the case of all following symbols unchanged. + +$myname uses 'CONFIG_' as the default symbol prefix. Set the environment +variable CONFIG_ to the prefix to use. Eg.: CONFIG_="FOO_" $myname ... +EOL + exit 1 +} + +checkarg() { + ARG="$1" + if [ "$ARG" = "" ] ; then + usage + fi + case "$ARG" in + ${CONFIG_}*) + ARG="${ARG/${CONFIG_}/}" + ;; + esac + if [ "$MUNGE_CASE" = "yes" ] ; then + ARG="`echo $ARG | tr a-z A-Z`" + fi +} + +txt_append() { + local anchor="$1" + local insert="$2" + local infile="$3" + local tmpfile="$infile.swp" + + # sed append cmd: 'a\' + newline + text + newline + cmd="$(printf "a\\%b$insert" "\n")" + + sed -e "/$anchor/$cmd" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" +} + +txt_subst() { + local before="$1" + local after="$2" + local infile="$3" + local tmpfile="$infile.swp" + + sed -e "s$SED_DELIM$before$SED_DELIM$after$SED_DELIM" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" +} + +txt_delete() { + local text="$1" + local infile="$2" + local tmpfile="$infile.swp" + + sed -e "/$text/d" "$infile" >"$tmpfile" + # replace original file with the edited one + mv "$tmpfile" "$infile" +} + +set_var() { + local name=$1 new=$2 before=$3 + + name_re="^($name=|# $name is not set)" + before_re="^($before=|# $before is not set)" + if test -n "$before" && grep -Eq "$before_re" "$FN"; then + txt_append "^$before=" "$new" "$FN" + txt_append "^# $before is not set" "$new" "$FN" + elif grep -Eq "$name_re" "$FN"; then + txt_subst "^$name=.*" "$new" "$FN" + txt_subst "^# $name is not set" "$new" "$FN" + else + echo "$new" >>"$FN" + fi +} + +undef_var() { + local name=$1 + + txt_delete "^$name=" "$FN" + txt_delete "^# $name is not set" "$FN" +} + +if [ "$1" = "--file" ]; then + FN="$2" + if [ "$FN" = "" ] ; then + usage + fi + shift 2 +else + FN=.config +fi + +if [ "$1" = "" ] ; then + usage +fi + +MUNGE_CASE=yes +while [ "$1" != "" ] ; do + CMD="$1" + shift + case "$CMD" in + --keep-case|-k) + MUNGE_CASE=no + continue + ;; + --refresh) + ;; + --*-after|-E|-D|-M) + checkarg "$1" + A=$ARG + checkarg "$2" + B=$ARG + shift 2 + ;; + -*) + checkarg "$1" + shift + ;; + esac + case "$CMD" in + --enable|-e) + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=y" + ;; + + --disable|-d) + set_var "${CONFIG_}$ARG" "# ${CONFIG_}$ARG is not set" + ;; + + --module|-m) + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=m" + ;; + + --set-str) + # sed swallows one level of escaping, so we need double-escaping + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=\"${1//\"/\\\\\"}\"" + shift + ;; + + --set-val) + set_var "${CONFIG_}$ARG" "${CONFIG_}$ARG=$1" + shift + ;; + --undefine|-u) + undef_var "${CONFIG_}$ARG" + ;; + + --state|-s) + if grep -q "# ${CONFIG_}$ARG is not set" $FN ; then + echo n + else + V="$(grep "^${CONFIG_}$ARG=" $FN)" + if [ $? != 0 ] ; then + echo undef + else + V="${V/#${CONFIG_}$ARG=/}" + V="${V/#\"/}" + V="${V/%\"/}" + V="${V//\\\"/\"}" + echo "${V}" + fi + fi + ;; + + --enable-after|-E) + set_var "${CONFIG_}$B" "${CONFIG_}$B=y" "${CONFIG_}$A" + ;; + + --disable-after|-D) + set_var "${CONFIG_}$B" "# ${CONFIG_}$B is not set" "${CONFIG_}$A" + ;; + + --module-after|-M) + set_var "${CONFIG_}$B" "${CONFIG_}$B=m" "${CONFIG_}$A" + ;; + + # undocumented because it ignores --file (fixme) + --refresh) + yes "" | make oldconfig + ;; + + *) + echo "bad command: $CMD" >&2 + usage + ;; + esac +done 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/dfuboot.sh b/scripts/dfuboot.sh index 524113b613..9847579ced 100755 --- a/scripts/dfuboot.sh +++ b/scripts/dfuboot.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash DEVICETREE= KERNEL= diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore index 2c0d6a1bf3..0079e3f1b5 100644 --- a/scripts/dtc/.gitignore +++ b/scripts/dtc/.gitignore @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + dtc fdtget diff --git a/scripts/dtc/Makefile b/scripts/dtc/Makefile index 69b0f6a0e0..721e8e2b8c 100644 --- a/scripts/dtc/Makefile +++ b/scripts/dtc/Makefile @@ -1,8 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # scripts/dtc makefile -hostprogs-$(CONFIG_DTC) := dtc fdtget -always := $(hostprogs-y) +hostprogs-always-$(CONFIG_DTC) += dtc fdtget dtc-objs := dtc.o flattree.o fstree.o data.o livetree.o treesource.o \ srcpos.o checks.o util.o @@ -15,7 +14,7 @@ libfdt-objs := $(libfdt-objs:%.o=libfdt/%.o) fdtget-objs += fdtget.o $(libfdt-objs) util.o # Source files need to get at the userspace version of libfdt_env.h to compile -HOST_EXTRACFLAGS := -I$(src)/libfdt +HOST_EXTRACFLAGS += -I$(src)/libfdt ifeq ($(wildcard /usr/include/yaml.h),) ifneq ($(CHECK_DTBS),) 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 5c6c3fd557..de60a70b6b 100644 --- a/scripts/dtc/dtc-lexer.l +++ b/scripts/dtc/dtc-lexer.l @@ -23,7 +23,6 @@ LINECOMMENT "//".*\n #include "srcpos.h" #include "dtc-parser.tab.h" -YYLTYPE yylloc; extern bool treesource_error; /* CAUTION: this will stop working if we ever use yyless() or yyunput() */ @@ -58,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 # */ @@ -201,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/extract_symbol_offset b/scripts/extract_symbol_offset index 78b866830e..d0ea22434a 100755 --- a/scripts/extract_symbol_offset +++ b/scripts/extract_symbol_offset @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash symbol="$1" file="$2" diff --git a/scripts/fiptool_fwconfig b/scripts/fiptool_fwconfig new file mode 100755 index 0000000000..f76f450b04 --- /dev/null +++ b/scripts/fiptool_fwconfig @@ -0,0 +1,39 @@ +#!/bin/sh + +set -e + +# adjust bl33 load address in existing FIP + +FDTGET=${FDTGET:-fdtget} +FDTPUT=${FDTPUT:-fdtput} + +if [ "$1" != "-l" ] || [ "$#" -ne 3 ]; then + echo "USAGE: $0 -l NT_LOAD_ADDR FIP" 1>&2 + exit 1 +fi + +NEW_LOAD_ADDR=$(($2)) +FIP=$3 +FWCONFIG=".$FIP.fw-config.bin" + +fiptool unpack --fw-config "$FWCONFIG" --force "$FIP" + +MAX_SIZE="$($FDTGET -t u $FWCONFIG /dtb-registry/nt_fw max-size)" +set $($FDTGET -t u $FWCONFIG /dtb-registry/nt_fw load-address) +ENTRY=$1 +OLD_LOAD_ADDR=$2 + +if [ $NEW_LOAD_ADDR -lt $OLD_LOAD_ADDR ] || + [ $NEW_LOAD_ADDR -ge $((OLD_LOAD_ADDR + MAX_SIZE)) ]; then + printf "New load address 0x%08x out of bounds [0x%08x-0x%08x)\n" \ + $NEW_LOAD_ADDR $OLD_LOAD_ADDR $((OLD_LOAD_ADDR + MAX_SIZE)) 1>&2 + exit 1 +fi + +$FDTPUT -t u $FWCONFIG /dtb-registry/nt_fw load-address $ENTRY $NEW_LOAD_ADDR +$FDTPUT -t u $FWCONFIG /dtb-registry/nt_fw max-size \ + $((MAX_SIZE + OLD_LOAD_ADDR - NEW_LOAD_ADDR)) + +fiptool update $FIP --fw-config $FWCONFIG + +rm $FWCONFIG diff --git a/scripts/gcc-64bitptr.sh b/scripts/gcc-64bitptr.sh new file mode 100755 index 0000000000..7fb05703b8 --- /dev/null +++ b/scripts/gcc-64bitptr.sh @@ -0,0 +1,9 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-only + +cat << "END" | $@ -x c - -c -o /dev/null +int main(void) +{ + return sizeof(struct { int:-!(sizeof(void *) == 8); }); +} +END diff --git a/scripts/gcc-version.sh b/scripts/gcc-version.sh new file mode 100755 index 0000000000..ae35343253 --- /dev/null +++ b/scripts/gcc-version.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# gcc-version gcc-command +# +# Print the gcc version of `gcc-command' in a 5 or 6-digit form +# such as `29503' for gcc-2.95.3, `30301' for gcc-3.3.1, etc. + +compiler="$*" + +if [ ${#compiler} -eq 0 ]; then + echo "Error: No compiler specified." >&2 + printf "Usage:\n\t$0 <gcc-command>\n" >&2 + exit 1 +fi + +MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) +MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) +PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) +printf "%d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL diff --git a/scripts/gen-dtb-s b/scripts/gen-dtb-s index b2dd253c27..d6fbdd5aaf 100755 --- a/scripts/gen-dtb-s +++ b/scripts/gen-dtb-s @@ -1,10 +1,12 @@ -#!/bin/bash +#!/usr/bin/env bash 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,23 +51,29 @@ 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 "#if defined(CONFIG_USE_COMPRESSED_DTB) && defined(__PBL__)" echo ".section .dtbz.rodata.${name},\"a\"" echo ".balign STRUCT_ALIGNMENT" echo ".global __dtb_z_${name}_start" echo "__dtb_z_${name}_start:" -printf ".word 0x%08x\n" 0x7b66bcbd -printf ".word 0x%08x\n" $compressed -printf ".word 0x%08x\n" $uncompressed -echo ".incbin \"$dtb.lzo\"" +printf ".int 0x%08x\n" 0x7b66bcbd +printf ".int 0x%08x\n" $compressed +printf ".int 0x%08x\n" $uncompressed +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/genenv b/scripts/genenv index 5ebe699632..454f2327b2 100755 --- a/scripts/genenv +++ b/scripts/genenv @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # Generate the default environment file from a list of directories # usage: genenv <basedir> <objdir> <target> <dir>... 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/.gitignore b/scripts/imx/.gitignore index 84e6f2b406..dce5c3306c 100644 --- a/scripts/imx/.gitignore +++ b/scripts/imx/.gitignore @@ -1,2 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + imx-usb-loader +imx-usb-loader-target imx-image diff --git a/scripts/imx/Kconfig b/scripts/imx/Kconfig index ef83fa14dd..759f5521a5 100644 --- a/scripts/imx/Kconfig +++ b/scripts/imx/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + config ARCH_IMX_USBLOADER depends on ARCH_MXS || ARCH_IMX || COMPILE_HOST_TOOLS bool "imx-usb-loader" diff --git a/scripts/imx/Makefile b/scripts/imx/Makefile index e7af2c98ef..739641b477 100644 --- a/scripts/imx/Makefile +++ b/scripts/imx/Makefile @@ -1,18 +1,28 @@ -hostprogs-$(CONFIG_ARCH_IMX_IMXIMAGE) += imx-image -hostprogs-$(CONFIG_ARCH_IMX_USBLOADER) += imx-usb-loader +# SPDX-License-Identifier: GPL-2.0-only -always := $(hostprogs-y) +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` -HOSTCFLAGS_imx.o = -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 += `$(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)/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 +imx-usb-loader-target-objs := imx-usb-loader-target.o imx-target.o imx-image-objs := imx-image.o imx.o + +userprogs-always-$(CONFIG_ARCH_IMX_USBLOADER_TARGET) += imx-usb-loader-target + +userccflags += -I $(srctree)/$(src)/include -isystem $(srctree)/scripts/include 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/README b/scripts/imx/README index d573d3a6be..99155af013 100644 --- a/scripts/imx/README +++ b/scripts/imx/README @@ -22,7 +22,7 @@ end up at 0x80001000 from where it is then executed. Example config file, suitable for an Eukra cpuimx35: soc imx35 -dcdofs 0x400 +ivtofs 0x400 loadaddr 0x80000000 wm 32 0x53F80004 0x00821000 wm 32 0x53F80004 0x00821000 diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index a9323f8ba3..9ba60dbc5b 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -1,20 +1,6 @@ -/* - * (C) Copyright 2013 Sascha Hauer, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2013 Sascha Hauer, Pengutronix + #define _GNU_SOURCE #include <stdio.h> #include <unistd.h> @@ -28,16 +14,19 @@ #include <fcntl.h> #include <linux/kernel.h> #include <sys/file.h> -#include <mach/imx_cpu_types.h> #include "../compiler.h" +#include "../common.h" #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)) +#include "../common.c" + /* * Conservative DCD element limit set to restriction v2 header size to * HEADER_SIZE @@ -46,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; /* @@ -242,7 +231,7 @@ static size_t add_header_v1(struct config_data *data, void *buf) { struct imx_flash_header *hdr; int dcdsize = curdcd * sizeof(uint32_t); - int offset = data->image_dcd_offset; + int offset = data->image_ivt_offset; uint32_t loadaddr = data->image_load_addr; uint32_t imagesize = data->load_size; @@ -307,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_dcd_offset; uint32_t loadaddr = data->image_load_addr; uint32_t imagesize = data->load_size; @@ -320,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); } @@ -332,8 +322,13 @@ 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->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); + /* IMX_CPU_IMX8MQ is a special case with fixed offset */ + if (data->cpu_type == IMX_CPU_IMX8MQ) + hdr->entry = loadaddr + HEADER_LEN; + else + hdr->entry = loadaddr + header_len; + if (dcdsize) + hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header); if (create_usb_image) { dcd_ptr_content = hdr->dcd_ptr; dcd_ptr_offset = offsetof(struct imx_flash_header_v2, dcd_ptr) + offset; @@ -350,8 +345,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 @@ -359,19 +356,128 @@ 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; } - hdr->dcd_header.tag = TAG_DCD_HEADER; - hdr->dcd_header.length = htobe16(sizeof(uint32_t) + dcdsize); - hdr->dcd_header.version = DCD_VERSION; - buf += sizeof(*hdr); - memcpy(buf, dcdtable, dcdsize); + if (dcdsize) { + hdr->dcd_header.tag = TAG_DCD_HEADER; + hdr->dcd_header.length = htobe16(sizeof(uint32_t) + dcdsize); + hdr->dcd_header.version = DCD_VERSION; + memcpy(buf, dcdtable, dcdsize); + } 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" @@ -447,41 +553,42 @@ static int write_mem_v2(uint32_t addr, uint32_t val, int width, int set_bits, in return 0; } -static int xread(int fd, void *buf, int len) +static void xread(int fd, void *buf, int len) { int ret; while (len) { ret = read(fd, buf, len); - if (ret < 0) - return ret; + if (ret < 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + exit(1); + } + if (!ret) - return EOF; + return; buf += ret; len -= ret; } - - return 0; } -static int xwrite(int fd, void *buf, int len) +static void xwrite(int fd, void *buf, int len) { int ret; while (len) { ret = write(fd, buf, len); - if (ret < 0) - return ret; + if (ret < 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + exit(1); + } buf += ret; len -= ret; } - - return 0; } static void write_dcd(const char *outfile) { - int outfd, ret; + int outfd; int dcdsize = curdcd * sizeof(uint32_t); outfd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); @@ -491,11 +598,7 @@ static void write_dcd(const char *outfile) exit(1); } - ret = xwrite(outfd, dcdtable, dcdsize); - if (ret < 0) { - perror("write"); - exit(1); - } + xwrite(outfd, dcdtable, dcdsize); } static int check(const struct config_data *data, uint32_t cmd, uint32_t addr, @@ -565,12 +668,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; @@ -579,7 +683,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); @@ -616,11 +724,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; @@ -648,7 +756,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); @@ -694,16 +802,14 @@ static int hab_sign(struct config_data *data) csf_space); } - ret = xread(fd, buf, s.st_size); - if (ret < 0) { - fprintf(stderr, "read failed: %s\n", strerror(errno)); - return -errno; - } + xread(fd, buf, s.st_size); + + close(fd); /* - * For i.MX8, write into the reserved CSF section + * For i.MX8M, write into the reserved CSF section */ - if (data->cpu_type == IMX_CPU_IMX8MQ) + if (cpu_is_mx8m(data)) outfd = open(data->outfile, O_WRONLY); else outfd = open(data->outfile, O_WRONLY | O_APPEND); @@ -714,13 +820,18 @@ static int hab_sign(struct config_data *data) exit(1); } - if (data->cpu_type == IMX_CPU_IMX8MQ) { + if (cpu_is_mx8m(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; @@ -730,11 +841,7 @@ static int hab_sign(struct config_data *data) } } - ret = xwrite(outfd, buf, csf_space); - if (ret < 0) { - fprintf(stderr, "write failed: %s\n", strerror(errno)); - return -errno; - } + xwrite(outfd, buf, csf_space); ret = close(outfd); if (ret) { @@ -745,41 +852,9 @@ static int hab_sign(struct config_data *data) return 0; } -static void *xread_file(const char *filename, size_t *size) -{ - int fd, ret; - void *buf; - struct stat s; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno)); - exit(1); - } - - ret = fstat(fd, &s); - if (ret) { - fprintf(stderr, "Cannot stat %s: %s\n", filename, strerror(errno)); - exit(1); - } - - *size = s.st_size; - buf = malloc(*size); - if (!buf) { - perror("malloc"); - exit(1); - } - - xread(fd, buf, *size); - - close(fd); - - return buf; -} - static bool cpu_is_aarch64(const struct config_data *data) { - return data->cpu_type == IMX_CPU_IMX8MQ; + return cpu_is_mx8m(data); } int main(int argc, char *argv[]) @@ -792,13 +867,12 @@ 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 i, header_copies; - int add_barebox_header; + bool add_barebox_header = false; uint32_t barebox_image_size = 0; struct config_data data = { - .image_dcd_offset = 0xffffffff, + .image_ivt_offset = 0xffffffff, .write_mem = write_mem, .check = check, .nop = nop, @@ -825,16 +899,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; @@ -886,7 +960,7 @@ int main(int argc, char *argv[]) exit(1); if (data.max_load_size && (data.encrypt_image || data.csf) - && data.cpu_type != IMX_CPU_IMX8MQ) { + && !cpu_is_mx8m(&data)) { fprintf(stderr, "Specifying max_load_size is incompatible with HAB signing/encrypting\n"); exit(1); } @@ -896,11 +970,11 @@ int main(int argc, char *argv[]) create_usb_image = 0; } - if (data.image_dcd_offset == 0xffffffff) { + if (data.image_ivt_offset == 0xffffffff) { if (create_usb_image) - data.image_dcd_offset = 0x0; + data.image_ivt_offset = 0x0; else - data.image_dcd_offset = FLASH_HEADER_OFFSET; + data.image_ivt_offset = FLASH_HEADER_OFFSET; } if (!data.header_version) { @@ -924,14 +998,14 @@ int main(int argc, char *argv[]) case 1: barebox_image_size = add_header_v1(&data, buf); if (data.srkfile) { - ret = add_srk(buf, data.image_dcd_offset, data.image_load_addr, + ret = add_srk(buf, data.image_ivt_offset, data.image_load_addr, data.srkfile); if (ret) exit(1); } break; case 2: - if (data.image_dcd_offset + sizeof(struct imx_flash_header_v2) + + if (data.image_ivt_offset + sizeof(struct imx_flash_header_v2) + MAX_DCD * sizeof(u32) > HEADER_LEN) { fprintf(stderr, "i.MX v2 header exceeds SW limit set by imx-image\n"); exit(1); @@ -939,14 +1013,17 @@ int main(int argc, char *argv[]) if (data.signed_hdmi_firmware_file) { free(buf); - buf = xread_file(data.signed_hdmi_firmware_file, + buf = read_file(data.signed_hdmi_firmware_file, &signed_hdmi_firmware_size); + if (!buf) + exit(1); signed_hdmi_firmware_size = roundup(signed_hdmi_firmware_size, PLUGIN_HDMI_SIZE); header_len += signed_hdmi_firmware_size; + barebox_image_size += signed_hdmi_firmware_size; buf = realloc(buf, header_len); @@ -956,8 +1033,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", @@ -982,7 +1061,9 @@ int main(int argc, char *argv[]) bb_header[0] = data.first_opcode; bb_header[ARM_HEAD_SIZE_INDEX] = barebox_image_size; - infile = xread_file(imagename, &insize); + infile = read_file(imagename, &insize); + if (!infile) + exit(1); outfd = open(data.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (outfd < 0) { @@ -991,44 +1072,55 @@ int main(int argc, char *argv[]) exit(1); } - header_copies = (data.cpu_type == IMX_CPU_IMX35) ? 2 : 1; - - for (i = 0; i < header_copies; i++) { - ret = xwrite(outfd, add_barebox_header ? bb_header : buf, - sizeof_bb_header); - if (ret < 0) { - perror("write"); + if (data.cpu_type == IMX_CPU_IMX35) { + xwrite(outfd, buf, header_len); + xwrite(outfd, buf, header_len); + } else { + if (add_barebox_header && + data.image_ivt_offset + data.header_gap < sizeof_bb_header) { + fprintf(stderr, "barebox header conflicts with IVT\n"); exit(1); } - if (lseek(outfd, data.header_gap, SEEK_CUR) < 0) { + if (lseek(outfd, data.header_gap, SEEK_SET) < 0) { perror("lseek"); exit(1); } - ret = xwrite(outfd, buf + sizeof_bb_header, - header_len - sizeof_bb_header); + xwrite(outfd, buf, header_len); + } + + if (add_barebox_header) { + ret = pwrite(outfd, bb_header, sizeof_bb_header, 0); if (ret < 0) { - perror("write"); + fprintf(stderr, "pwrite failed: %s\n", strerror(errno)); exit(1); } + if (data.cpu_type == IMX_CPU_IMX35) { + ret = pwrite(outfd, bb_header, sizeof_bb_header, header_len); + if (ret < 0) { + fprintf(stderr, "pwrite failed: %s\n", strerror(errno)); + exit(1); + } + } } - ret = xwrite(outfd, infile, insize); - if (ret) { - perror("write"); - exit(1); - } + 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); - ret = xwrite(outfd, buf, now); - if (ret) { - perror("write"); - exit(1); + xwrite(outfd, buf, now); } } @@ -1039,15 +1131,22 @@ 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) { uint32_t *dcd; - infile = xread_file(data.outfile, &insize); + infile = read_file(data.outfile, &insize); + if (!infile) + exit(1); dcd = infile + dcd_ptr_offset; *dcd = dcd_ptr_content; @@ -1058,11 +1157,7 @@ int main(int argc, char *argv[]) exit(1); } - ret = xwrite(outfd, infile, insize); - if (ret < 0) { - perror("write"); - exit (1); - } + xwrite(outfd, infile, insize); close(outfd); } diff --git a/scripts/imx/imx-target.c b/scripts/imx/imx-target.c new file mode 100644 index 0000000000..4062eed6f6 --- /dev/null +++ b/scripts/imx/imx-target.c @@ -0,0 +1 @@ +#include "imx.c" diff --git a/scripts/imx/imx-usb-loader-target.c b/scripts/imx/imx-usb-loader-target.c new file mode 100644 index 0000000000..f2050aec17 --- /dev/null +++ b/scripts/imx/imx-usb-loader-target.c @@ -0,0 +1 @@ +#include "imx-usb-loader.c" diff --git a/scripts/imx/imx-usb-loader.c b/scripts/imx/imx-usb-loader.c index 70883bf883..91a15345a2 100644 --- a/scripts/imx/imx-usb-loader.c +++ b/scripts/imx/imx-usb-loader.c @@ -31,21 +31,25 @@ #include <stdlib.h> #include <libusb.h> #include <getopt.h> -#include <arpa/inet.h> #include <linux/kernel.h> +#include "../common.h" #include "../compiler.h" #include "imx.h" -#define get_min(a, b) (((a) < (b)) ? (a) : (b)) +#include "../common.c" -#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define get_min(a, b) (((a) < (b)) ? (a) : (b)) #define FT_APP 0xaa #define FT_CSF 0xcc #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. @@ -54,7 +58,7 @@ int verbose; static struct libusb_device_handle *usb_dev_handle; -static struct usb_id *usb_id; +static const struct mach_id *mach_id; struct mach_id { struct mach_id * next; @@ -72,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 { @@ -81,11 +87,6 @@ struct usb_work { unsigned char plug; }; -struct usb_id { - const struct mach_id *mach_id; - struct usb_work *work; -}; - static const struct mach_id imx_ids[] = { { .vid = 0x066f, @@ -186,11 +187,42 @@ 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.MX8M", + .name = "i.MX8MQ", .header_type = HDR_MX53, .mode = MODE_HID, .max_transfer = 1024, + }, { + .vid = 0x1fc9, + .pid = 0x0134, + .name = "i.MX8MM", + .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, }, }; @@ -262,7 +294,8 @@ static void list_imx_device_types(void) } } -static int device_location_equal(libusb_device *device, const char *location) +static int device_location_equal(libusb_device *device, const char *location, + struct libusb_device_descriptor desc) { uint8_t port_path[MAX_USB_PORTS]; uint8_t dev_bus; @@ -309,8 +342,9 @@ static int device_location_equal(libusb_device *device, const char *location) /* walked the full path, all elements match */ if (path_step == path_len) result = 1; - else - fprintf(stderr, " excluded by device path option\n"); + else if (verbose) + fprintf(stderr, "USB device [%04x:%04x] excluded by device path option\n", + desc.idVendor, desc.idProduct); done: free(loc); @@ -338,7 +372,7 @@ static libusb_device *find_imx_dev(libusb_device **devs, const struct mach_id ** return NULL; } - if (location && !device_location_equal(dev, location)) { + if (location && !device_location_equal(dev, location, desc)) { libusb_close(usb_dev_handle); usb_dev_handle = NULL; continue; @@ -402,61 +436,6 @@ static void dump_bytes(const void *src, unsigned cnt, unsigned addr) } } -static long get_file_size(FILE *xfile) -{ - long size; - fseek(xfile, 0, SEEK_END); - size = ftell(xfile); - rewind(xfile); - - return size; -} - -static int read_file(const char *name, unsigned char **buffer, unsigned *size) -{ - FILE *xfile; - unsigned fsize; - int cnt; - unsigned char *buf; - xfile = fopen(name, "rb"); - if (!xfile) { - printf("error, can not open input file: %s\n", name); - return -5; - } - - fsize = get_file_size(xfile); - if (fsize < 0x20) { - printf("error, file: %s is too small\n", name); - fclose(xfile); - return -2; - } - - buf = malloc(ALIGN(fsize, 4)); - if (!buf) { - printf("error, out of memory\n"); - fclose(xfile); - return -2; - } - - cnt = fread(buf, 1 , fsize, xfile); - if (cnt < fsize) { - printf("error, cannot read %s\n", name); - fclose(xfile); - free(buf); - return -1; - } - - if (size) - *size = fsize; - - if (buffer) - *buffer = buf; - else - free(buf); - - return 0; -} - /* * HID Class-Specific Requests values. See section 7.2 of the HID specifications */ @@ -497,11 +476,11 @@ static int read_file(const char *name, unsigned char **buffer, unsigned *size) * 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 > usb_id->mach_id->max_transfer) - cnt = usb_id->mach_id->max_transfer; + if (cnt > mach_id->max_transfer) + cnt = mach_id->max_transfer; if (verbose > 4) { printf("report=%i\n", report); @@ -509,26 +488,37 @@ static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) dump_bytes(p, cnt, 0); } - if (usb_id->mach_id->mode == MODE_BULK) { + if (mach_id->mode == MODE_BULK) { *last_trans = 0; 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); @@ -555,13 +545,13 @@ static int transfer(int report, unsigned char *p, unsigned cnt, int *last_trans) return err; } -int do_status(void) +static int do_status(void) { int last_trans; 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, @@ -571,8 +561,7 @@ 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); @@ -595,7 +584,7 @@ int do_status(void) break; } - if (usb_id->mach_id->mode == MODE_HID) { + if (mach_id->mode == MODE_HID) { err = transfer(4, tmp, sizeof(tmp), &last_trans); if (err) printf("4 in err=%i, last_trans=%i %02x %02x %02x %02x\n", @@ -621,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); @@ -653,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; @@ -686,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); @@ -706,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); @@ -763,7 +743,33 @@ static int modify_memory(unsigned addr, unsigned val, int width, int set_bits, i return write_memory(addr, val, 4); } -static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char type) +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) { static struct sdp_command dl_command = { .cmd = SDP_WRITE_FILE, @@ -778,18 +784,15 @@ static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char typ 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; @@ -802,33 +805,21 @@ static int load_file(void *buf, unsigned len, unsigned dladdr, unsigned char typ retry = 0; - if (usb_id->mach_id->mode == MODE_BULK) { + if (mach_id->mode == MODE_BULK) { err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) printf("in err=%i, last_trans=%i %02x %02x %02x %02x\n", err, last_trans, tmp[0], tmp[1], tmp[2], tmp[3]); } - p = buf; - cnt = len; - - while (1) { - int now = get_min(cnt, usb_id->mach_id->max_transfer); + err = send_buf(buf, len); + if (err) + return err; - if (!now) - break; + if (mode_barebox) + return transfer_size; - 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; - } - - if (usb_id->mach_id->mode == MODE_HID) { + if (mach_id->mode == MODE_HID) { err = transfer(3, tmp, sizeof(tmp), &last_trans); if (err) printf("3 in err=%i, last_trans=%i %02x %02x %02x %02x\n", @@ -858,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; @@ -888,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) @@ -912,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; @@ -928,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; @@ -967,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. @@ -980,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; @@ -1009,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; } @@ -1041,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", @@ -1054,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); @@ -1222,13 +1212,13 @@ static int is_header(const unsigned char *p) const struct imx_flash_header_v2 *hdr = (const struct imx_flash_header_v2 *)p; - switch (usb_id->mach_id->header_type) { + switch (mach_id->header_type) { case HDR_MX51: if (ohdr->app_code_barker == 0xb1) return 1; break; case HDR_MX53: - if (hdr->header.tag == TAG_IVT_HEADER && hdr->header.version == IVT_VERSION) + if (hdr->header.tag == TAG_IVT_HEADER && (hdr->header.version == IVT_VERSION || hdr->header.version == 0x41)) return 1; } @@ -1242,7 +1232,7 @@ static int perform_dcd(unsigned char *p, const unsigned char *file_start, struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; int ret = 0; - switch (usb_id->mach_id->header_type) { + switch (mach_id->header_type) { case HDR_MX51: ret = write_dcd_table_old(ohdr, file_start, cnt); ohdr->dcd_block_len = 0; @@ -1259,11 +1249,11 @@ static int perform_dcd(unsigned char *p, const unsigned char *file_start, } static int get_dl_start(const unsigned char *p, const unsigned char *file_start, - unsigned cnt, unsigned *dladdr, unsigned *max_length, unsigned *plugin, + unsigned cnt, size_t *firststage_len, unsigned *plugin, unsigned *header_addr) { const unsigned char *file_end = file_start + cnt; - switch (usb_id->mach_id->header_type) { + switch (mach_id->header_type) { case HDR_MX51: { struct imx_flash_header *ohdr = (struct imx_flash_header *)p; @@ -1271,31 +1261,31 @@ static int get_dl_start(const unsigned char *p, const unsigned char *file_start, unsigned char* dcd; int err = get_dcd_range_old(ohdr, file_start, cnt, &dcd, &dcd_end); - *dladdr = ohdr->app_dest; *header_addr = ohdr->dcd_ptr_ptr - offsetof(struct imx_flash_header, dcd); *plugin = 0; if (err >= 0) - *max_length = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); + *firststage_len = dcd_end[0] | (dcd_end[1] << 8) | (dcd_end[2] << 16) | (dcd_end[3] << 24); break; } 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; - *dladdr = hdr->self; *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; } - *dladdr = ((struct imx_boot_data *)bd)->start; - *max_length = ((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; } @@ -1303,12 +1293,28 @@ static int get_dl_start(const unsigned char *p, const unsigned char *file_start, return 0; } +static int get_payload_start(const unsigned char *p, uint32_t *ofs) +{ + struct imx_flash_header_v2 *hdr = (struct imx_flash_header_v2 *)p; + + switch (mach_id->header_type) { + case HDR_MX51: + return -EINVAL; + + case HDR_MX53: + *ofs = hdr->entry - hdr->self; + return 0; + } + + return -EINVAL; +} + static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, - unsigned *p_dladdr, unsigned *p_max_length, unsigned *p_plugin, + size_t *p_firststage_len, unsigned *p_plugin, unsigned *p_header_addr) { int ret; - unsigned header_max = 0x800; + unsigned header_max = 0x10000; unsigned header_inc = 0x400; unsigned header_offset = 0; int header_cnt = 0; @@ -1319,7 +1325,7 @@ static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, if (!is_header(p)) continue; - ret = get_dl_start(p, buf, cnt, p_dladdr, p_max_length, p_plugin, p_header_addr); + ret = get_dl_start(p, buf, cnt, p_firststage_len, p_plugin, p_header_addr); if (ret < 0) { printf("!!get_dl_start returned %i\n", ret); return ret; @@ -1336,7 +1342,7 @@ static int process_header(struct usb_work *curr, unsigned char *buf, int cnt, if (*p_plugin && (!curr->plug) && (!header_cnt)) { header_cnt++; - header_max = header_offset + *p_max_length + 0x400; + header_max = header_offset + *p_firststage_len + 0x400; if (header_max > cnt - 32) header_max = cnt - 32; printf("header_max=%x\n", header_max); @@ -1353,66 +1359,60 @@ 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; unsigned char type; - unsigned fsize = 0; + size_t fsize = 0; unsigned header_offset; - unsigned file_base; unsigned char *buf = NULL; unsigned char *image; unsigned char *verify_buffer = NULL; - unsigned dladdr = 0; - unsigned max_length; + size_t firststage_len; unsigned plugin = 0; unsigned header_addr = 0; - unsigned skip = 0; - ret = read_file(curr->filename, &buf, &fsize); - if (ret < 0) - return ret; + buf = read_file(curr->filename, &fsize); + if (!buf) + return -errno; - max_length = fsize; + firststage_len = fsize; - ret = process_header(curr, buf, fsize, - &dladdr, &max_length, &plugin, &header_addr); + ret = process_header(curr, buf, fsize, &firststage_len, &plugin, &header_addr); if (ret < 0) goto cleanup; 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; goto cleanup; } - if (!dladdr) { - printf("unknown load address\n"); - ret = -3; - goto cleanup; - } - - file_base = header_addr - header_offset; - - if (usb_id->mach_id->mode == MODE_BULK) { - /* No jump command, dladdr should point to header */ - dladdr = header_addr; - } - - if (file_base > dladdr) { - max_length -= (file_base - dladdr); - dladdr = file_base; - } - - skip = dladdr - file_base; - - image = buf + skip; - fsize -= skip; - - if (fsize > max_length) - fsize = max_length; + /* skip over the imx-image-part */ + image = buf + header_offset; + fsize -= header_offset; type = FT_APP; @@ -1427,16 +1427,16 @@ static int do_irom_download(struct usb_work *curr, int verify) memcpy(verify_buffer, image, 64); - if ((type == FT_APP) && (usb_id->mach_id->mode != MODE_HID)) { + if ((type == FT_APP) && (mach_id->mode != MODE_HID)) { type = FT_LOAD_ONLY; verify = 2; } } - printf("loading binary file(%s) to 0x%08x, skip=0x%x, fsize=%u type=%d...\n", - curr->filename, dladdr, skip, fsize, type); + 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, fsize, dladdr, type); + ret = load_file(image, min(fsize, firststage_len), header_addr, type, false); if (ret < 0) goto cleanup; @@ -1445,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, dladdr); + ret = verify_memory(image, min(fsize, firststage_len), header_addr); if (ret < 0) { printf("verifying failed\n"); goto cleanup; @@ -1459,14 +1459,14 @@ static int do_irom_download(struct usb_work *curr, int verify) * so we load part of the image again with type FT_APP * this time. */ - ret = load_file(verify_buffer, 64, dladdr, FT_APP); + ret = load_file(verify_buffer, 64, header_addr, FT_APP, false); if (ret < 0) goto cleanup; } } - if (usb_id->mach_id->mode == MODE_HID && type == FT_APP) { + if (mach_id->mode == MODE_HID && type == FT_APP) { printf("jumping to 0x%08x\n", header_addr); ret = sdp_jump_address(header_addr); @@ -1474,6 +1474,19 @@ static int do_irom_download(struct usb_work *curr, int verify) return ret; } + if (firststage_len < fsize) { + uint32_t ofs; + + ret = get_payload_start(image, &ofs); + if (ret) { + printf("Cannot get offset of payload\n"); + goto cleanup; + } + printf("Loading full image from offset %u\n", ofs); + printf("Note: This needs board support on the other end\n"); + load_file(image + ofs, fsize - ofs, 0, 0, true); + } + ret = 0; cleanup: free(verify_buffer); @@ -1488,65 +1501,43 @@ 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, usb_id->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) { - unsigned fsize = 0; + size_t fsize = 0; unsigned char *buf = NULL; - int ret; - ret = read_file(curr->filename, &buf, &fsize); - if (ret < 0) - return ret; + buf = read_file(curr->filename, &fsize); + 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) { @@ -1569,13 +1560,17 @@ 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[]) { - const struct mach_id *mach; libusb_device **devs; libusb_device *dev; int r; @@ -1589,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; @@ -1602,6 +1607,7 @@ int main(int argc, char *argv[]) break; case 'h': usage(argv[0]); + exit(EXIT_SUCCESS); case 'd': devtype = optarg; break; @@ -1615,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) { @@ -1631,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; @@ -1647,7 +1653,7 @@ int main(int argc, char *argv[]) goto out; } - dev = find_imx_dev(devs, &mach, devpath, devtype); + dev = find_imx_dev(devs, &mach_id, devpath, devtype); if (!dev) { fprintf(stderr, "no supported device found\n"); goto out; @@ -1666,23 +1672,20 @@ int main(int argc, char *argv[]) goto out; } - usb_id = malloc(sizeof(*usb_id)); - if (!usb_id) { - perror("malloc"); - exit(1); - } - - usb_id->mach_id = mach; - - if (mach->dev_type == DEV_MXS) { - ret = mxs_work(&w); + if (mach_id->dev_type == DEV_MXS) { + 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) { @@ -1699,9 +1702,6 @@ int main(int argc, char *argv[]) ret = 0; out: - if (usb_id) - free(usb_id); - if (usb_dev_handle) libusb_close(usb_dev_handle); diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index b3e8d62ba8..5ccc116cfe 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -1,20 +1,5 @@ -/* - * (C) Copyright 2016 Sascha Hauer, Pengutronix - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2016 Sascha Hauer, Pengutronix #define _GNU_SOURCE #include <stdio.h> @@ -24,7 +9,6 @@ #include <errno.h> #include <sys/stat.h> #include <linux/kernel.h> -#include <mach/imx_cpu_types.h> #include "imx.h" @@ -36,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; @@ -215,16 +216,22 @@ static int do_loadaddr(struct config_data *data, int argc, char *argv[]) return 0; } -static int do_dcd_offset(struct config_data *data, int argc, char *argv[]) +static int do_ivt_offset(struct config_data *data, int argc, char *argv[]) { if (argc < 2) return -EINVAL; - data->image_dcd_offset = strtoul(argv[1], NULL, 0); + data->image_ivt_offset = strtoul(argv[1], NULL, 0); return 0; } +static int do_dcdofs_error(struct config_data *data, int argc, char *argv[]) +{ + fprintf(stderr, "ERROR: misnomer dcdofs has been renamed to ivtofs. imxcfg must be adapted.\n"); + return -EINVAL; +} + struct soc_type { char *name; int header_version; @@ -243,6 +250,9 @@ static struct soc_type socs[] = { { .name = "imx53", .header_version = 2, .cpu_type = IMX_CPU_IMX53, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx6", .header_version = 2, .cpu_type = IMX_CPU_IMX6, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, { .name = "imx7", .header_version = 2, .cpu_type = IMX_CPU_IMX7, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, + { .name = "imx8mm", .header_version = 2, .cpu_type = IMX_CPU_IMX8MM, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, + { .name = "imx8mn", .header_version = 2, .cpu_type = IMX_CPU_IMX8MN, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, + { .name = "imx8mp", .header_version = 2, .cpu_type = IMX_CPU_IMX8MP, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, { .name = "imx8mq", .header_version = 2, .cpu_type = IMX_CPU_IMX8MQ, .header_gap = SZ_32K, .first_opcode = 0x14000000 /* b 0x0000 (offset computed) */}, { .name = "vf610", .header_version = 2, .cpu_type = IMX_CPU_VF610, .header_gap = 0, .first_opcode = 0xea0003fe /* b 0x1000 */}, }; @@ -271,7 +281,7 @@ static int do_soc(struct config_data *data, int argc, char *argv[]) } } - fprintf(stderr, "unkown SoC type \"%s\". Known SoCs are:\n", soc); + fprintf(stderr, "unknown SoC type \"%s\". Known SoCs are:\n", soc); for (i = 0; i < ARRAY_SIZE(socs); i++) fprintf(stderr, "%s ", socs[i].name); fprintf(stderr, "\n"); @@ -289,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->csf_space < len) + if (!data->hab_qspi_support) + return 0; + + data->flexspi_csf = strcata(data->flexspi_csf, str); + if (!data->flexspi_csf) return -ENOMEM; - strcat(data->csf, str); + return 0; +} - data->csf_space -= len; +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; + + if (!flexspi_csf_str) + return 0; + + data->flexspi_csf = strcata(data->flexspi_csf, flexspi_csf_str); + if (!data->flexspi_csf) + return -ENOMEM; return 0; } @@ -307,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) @@ -332,22 +371,48 @@ 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[]) { - const char *type; - char *str; + char *str, *flexspi_str = NULL; int ret; + int i; uint32_t signed_size = data->load_size; - uint32_t offset = 0; + 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; - if (argc < 2) - type = "full"; - else - type = argv[1]; - /* * In case of encrypted image we reduce signed area to beginning * of encrypted area. @@ -358,43 +423,83 @@ 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 && data->cpu_type == IMX_CPU_IMX8MQ) { - 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 (!strcmp(type, "full")) { - ret = asprintf(&str, "Blocks = 0x%08x 0x%08x 0x%08x \"%s\"\n", - data->image_load_addr, offset, signed_size, - data->outfile); - } else if (!strcmp(type, "from-dcdofs")) { - ret = asprintf(&str, "Blocks = 0x%08x 0x%x %d \"%s\"\n", - data->image_load_addr + data->image_dcd_offset, - data->image_dcd_offset, - signed_size - data->image_dcd_offset, - data->outfile); - } else if (!strcmp(type, "skip-mbr")) { - ret = asprintf(&str, - "Blocks = 0x%08x 0 440 \"%s\", \\\n" - " 0x%08x 512 %d \"%s\"\n", - data->image_load_addr, data->outfile, - data->image_load_addr + 512, - signed_size - 512, data->outfile); + 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 hab_blocks option: %s\n", type); + fprintf(stderr, "Invalid signed size area 0x%08x\n", + signed_size); return -EINVAL; } 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; - return 0; + for (i = 1; i < argc; i++) { + uint32_t addr; + uint32_t off; + uint32_t size; + char *b; + char *e; + + b = argv[i]; + if (*b == '"') // remove leading qoute + b++; + if (!*b || *b == '"') + continue; // skip if empty + + off = strtoul(b, &e, 0); + if (*e != '+') { + fprintf(stderr, "failed to find '+' in '%s'\n", b); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + b = e + 1; + size = strtoul(b, &e, 0); + if (*e != '@') { + fprintf(stderr, "failed to find '@' in '%s'\n", b); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + b = e + 1; + addr = strtoul(b, &e, 0); + if (*e && *e != '"') { // ignore trailing qoute + fprintf(stderr, "unexpected char at the end: '%c'\n", *e); + fprintf(stderr, "format off+size@addr expected, but given: %s\n", argv[i]); + return -EINVAL; + } + + ret = asprintf(&str, ", 0x%08x 0x%08x 0x%08x \"%s\"", addr, off, size, data->outfile); + if (ret < 0) + return -ENOMEM; + + ret = hab_add_str(data, str); + free(str); + if (ret) + return ret; + } + + return hab_add_str(data, "\n"); } static int do_hab_encrypt(struct config_data *data, int argc, char *argv[]) @@ -586,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", @@ -606,8 +743,11 @@ struct command cmds[] = { .name = "loadaddr", .parse = do_loadaddr, }, { + .name = "ivtofs", + .parse = do_ivt_offset, + }, { .name = "dcdofs", - .parse = do_dcd_offset, + .parse = do_dcdofs_error, }, { .name = "soc", .parse = do_soc, @@ -636,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, }, }; @@ -649,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); @@ -663,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; } @@ -673,13 +824,16 @@ static char *readcmd(struct config_data *data, FILE *f) } } -int parse_config(struct config_data *data, const char *filename) +int parse_config(struct config_data *data, const char *_filename) { FILE *f; int lineno = 0; char *line = NULL, *tmp; char *argv[MAXARGS]; int nargs, i, ret = 0; + char *filename; + + filename = strdup(_filename); f = fopen(filename, "r"); if (!f) { @@ -695,8 +849,17 @@ int parse_config(struct config_data *data, const char *filename) lineno++; tmp = strchr(line, '#'); - if (tmp) - *tmp = 0; + if (tmp) { + char *endptr; + long linenum = strtol(tmp + 1, &endptr, 10); + if (strncmp(endptr, " \"", 2) == 0 && endptr[2]) { + free(filename); + lineno = linenum - 1; + filename = strdup(endptr + 2); + filename[strlen(filename) - 1] = '\0'; + } + *tmp = '\0'; + } nargs = parse_line(line, argv); if (!nargs) @@ -708,8 +871,8 @@ int parse_config(struct config_data *data, const char *filename) if (!strcmp(cmds[i].name, argv[0])) { ret = cmds[i].parse(data, nargs, argv); if (ret) { - fprintf(stderr, "error in line %d: %s\n", - lineno, strerror(-ret)); + fprintf(stderr, "%s:%d: %s\n", + filename, lineno, strerror(-ret)); goto cleanup; } break; @@ -724,5 +887,6 @@ int parse_config(struct config_data *data, const char *filename) cleanup: fclose(f); + free(filename); return ret; } diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h index 20fb1e876e..65697a9b0d 100644 --- a/scripts/imx/imx.h +++ b/scripts/imx/imx.h @@ -1,4 +1,31 @@ -#include <mach/imx-header.h> +#include <imx/imx-header.h> +#include <imx/imx_cpu_types.h> + +static inline int cpu_is_mx8m(const struct config_data *data) +{ + switch (data->cpu_type) { + case IMX_CPU_IMX8MQ: + case IMX_CPU_IMX8MM: + case IMX_CPU_IMX8MN: + case IMX_CPU_IMX8MP: + return true; + default: + return false; + } +} + +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/include/asm-generic/barrier.h b/scripts/include/asm-generic/barrier.h index 47b933903e..2e78c3f328 100644 --- a/scripts/include/asm-generic/barrier.h +++ b/scripts/include/asm-generic/barrier.h @@ -1,3 +1,6 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* SPDX-FileCopyrightText: 2007 Red Hat (David Howells <dhowells@redhat.com>) */ + /* * Copied from the kernel sources to tools/perf/: * @@ -5,14 +8,6 @@ * * It should be possible to use these on really simple architectures, * but it serves more as a starting point for new ports. - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. */ #ifndef __TOOLS_LINUX_ASM_GENERIC_BARRIER_H #define __TOOLS_LINUX_ASM_GENERIC_BARRIER_H diff --git a/scripts/include/asm-generic/bitops/__ffs.h b/scripts/include/asm-generic/bitops/__ffs.h index c94175015a..15ffaa12c5 100644 --- a/scripts/include/asm-generic/bitops/__ffs.h +++ b/scripts/include/asm-generic/bitops/__ffs.h @@ -2,6 +2,7 @@ #define _TOOLS_LINUX_ASM_GENERIC_BITOPS___FFS_H_ #include <asm/types.h> +#include <asm-generic/bitsperlong.h> /** * __ffs - find first bit in word. @@ -13,7 +14,7 @@ static __always_inline unsigned long __ffs(unsigned long word) { int num = 0; -#if __BITS_PER_LONG == 64 +#if BITS_PER_LONG == 64 if ((word & 0xffffffff) == 0) { num += 32; word >>= 32; diff --git a/scripts/include/asm-generic/bitops/arch_hweight.h b/scripts/include/asm-generic/bitops/arch_hweight.h deleted file mode 100644 index 318bb2b202..0000000000 --- a/scripts/include/asm-generic/bitops/arch_hweight.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../../include/asm-generic/bitops/arch_hweight.h" diff --git a/scripts/include/asm-generic/bitops/atomic.h b/scripts/include/asm-generic/bitops/atomic.h index 4bccd7c3d5..03fe804024 100644 --- a/scripts/include/asm-generic/bitops/atomic.h +++ b/scripts/include/asm-generic/bitops/atomic.h @@ -2,21 +2,22 @@ #define _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ #include <asm/types.h> +#include <asm-generic/bitsperlong.h> static inline void set_bit(int nr, unsigned long *addr) { - addr[nr / __BITS_PER_LONG] |= 1UL << (nr % __BITS_PER_LONG); + addr[nr / BITS_PER_LONG] |= 1UL << (nr % BITS_PER_LONG); } static inline void clear_bit(int nr, unsigned long *addr) { - addr[nr / __BITS_PER_LONG] &= ~(1UL << (nr % __BITS_PER_LONG)); + addr[nr / BITS_PER_LONG] &= ~(1UL << (nr % BITS_PER_LONG)); } static __always_inline int test_bit(unsigned int nr, const unsigned long *addr) { - return ((1UL << (nr % __BITS_PER_LONG)) & - (((unsigned long *)addr)[nr / __BITS_PER_LONG])) != 0; + return ((1UL << (nr % BITS_PER_LONG)) & + (((unsigned long *)addr)[nr / BITS_PER_LONG])) != 0; } #endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_ATOMIC_H_ */ diff --git a/scripts/include/asm-generic/bitops/const_hweight.h b/scripts/include/asm-generic/bitops/const_hweight.h deleted file mode 100644 index 0afd644aff..0000000000 --- a/scripts/include/asm-generic/bitops/const_hweight.h +++ /dev/null @@ -1 +0,0 @@ -#include "../../../../include/asm-generic/bitops/const_hweight.h" diff --git a/scripts/include/asm-generic/bitops/hweight.h b/scripts/include/asm-generic/bitops/hweight.h index 290120c01a..eb95ca33d5 100644 --- a/scripts/include/asm-generic/bitops/hweight.h +++ b/scripts/include/asm-generic/bitops/hweight.h @@ -1,7 +1,6 @@ #ifndef _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ #define _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ -#include <asm-generic/bitops/arch_hweight.h> -#include <asm-generic/bitops/const_hweight.h> +#include "../../../../include/asm-generic/bitops/hweight.h" #endif /* _TOOLS_LINUX_ASM_GENERIC_BITOPS_HWEIGHT_H_ */ diff --git a/scripts/include/asm-generic/bitsperlong.h b/scripts/include/asm-generic/bitsperlong.h new file mode 100644 index 0000000000..eb2dfd9065 --- /dev/null +++ b/scripts/include/asm-generic/bitsperlong.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __BITS_PER_LONG_H_ +#define __BITS_PER_LONG_H_ + +#ifndef __WORDSIZE +#define __WORDSIZE (__SIZEOF_LONG__ * 8) +#endif + +#define BITS_PER_LONG __WORDSIZE + +#endif diff --git a/scripts/include/linux/bitops.h b/scripts/include/linux/bitops.h index 5ad9ee1dd7..60f5c5b4f9 100644 --- a/scripts/include/linux/bitops.h +++ b/scripts/include/linux/bitops.h @@ -4,12 +4,7 @@ #include <asm/types.h> #include <linux/kernel.h> #include <linux/compiler.h> - -#ifndef __WORDSIZE -#define __WORDSIZE (__SIZEOF_LONG__ * 8) -#endif - -#define BITS_PER_LONG __WORDSIZE +#include <asm-generic/bitsperlong.h> #define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) #define BIT_WORD(nr) ((nr) / BITS_PER_LONG) @@ -19,10 +14,6 @@ #define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32)) #define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE) -extern unsigned int __sw_hweight8(unsigned int w); -extern unsigned int __sw_hweight16(unsigned int w); -extern unsigned int __sw_hweight32(unsigned int w); -extern unsigned long __sw_hweight64(__u64 w); /* * Include this here because some architectures need generic_ffs/fls in diff --git a/scripts/include/linux/kernel.h b/scripts/include/linux/kernel.h index 5d94e984f1..f3083ff354 100644 --- a/scripts/include/linux/kernel.h +++ b/scripts/include/linux/kernel.h @@ -6,7 +6,10 @@ #include <stdlib.h> #include <assert.h> +#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) +#define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) diff --git a/scripts/include/linux/log2.h b/scripts/include/linux/log2.h index 41446668cc..abc38f4c63 100644 --- a/scripts/include/linux/log2.h +++ b/scripts/include/linux/log2.h @@ -1,13 +1,7 @@ -/* Integer base 2 logarithm calculation - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* SPDX-FileCopyrightText: 2006 Red Hat (David Howells <dhowells@redhat.com>) */ + +/* Integer base 2 logarithm calculation */ #ifndef _TOOLS_LINUX_LOG2_H #define _TOOLS_LINUX_LOG2_H diff --git a/scripts/kconfig-lint.py b/scripts/kconfig-lint.py new file mode 100755 index 0000000000..a154e9ccca --- /dev/null +++ b/scripts/kconfig-lint.py @@ -0,0 +1,329 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2019 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 AND ISC + +""" +Linter for the Zephyr Kconfig files. Pass --help to see +available checks. By default, all checks are enabled. + +Some of the checks rely on heuristics and can get tripped up +by things like preprocessor magic, so manual checking is +still needed. 'git grep' is handy. +""" + +import argparse +import os +import re +import shlex +import subprocess +import sys +import tempfile + +TOP_DIR = os.path.join(os.path.dirname(__file__), "..") + +import kconfiglib + + +def main(): + init_kconfig() + + args = parse_args() + if args.checks: + checks = args.checks + else: + # Run all checks if no checks were specified + checks = (check_always_n, + check_unused, + check_undefined, + check_pointless_menuconfigs, + check_missing_config_prefix) + + first = True + for check in checks: + if not first: + print() + first = False + check() + + +def parse_args(): + # args.checks is set to a list of check functions to run + + parser = argparse.ArgumentParser( + formatter_class=argparse.RawTextHelpFormatter, + description=__doc__) + + parser.add_argument( + "-n", "--check-always-n", + action="append_const", dest="checks", const=check_always_n, + help="""\ +List symbols that can never be anything but n/empty. These +are detected as symbols with no prompt or defaults that +aren't selected or implied. +""") + + parser.add_argument( + "-u", "--check-unused", + action="append_const", dest="checks", const=check_unused, + help="""\ +List symbols that might be unused. + +Heuristic: + + - Isn't referenced in Kconfig + - Isn't referenced as CONFIG_<NAME> outside Kconfig + (besides possibly as CONFIG_<NAME>=<VALUE>) + - Isn't selecting/implying other symbols + - Isn't a choice symbol + +C preprocessor magic can trip up this check.""") + + parser.add_argument( + "-U", "--check-undefined", + action="append_const", dest="checks", const=check_undefined, + help="""\ +List symbols that are used in a Kconfig file but are undefined +""") + + parser.add_argument( + "-m", "--check-pointless-menuconfigs", + action="append_const", dest="checks", const=check_pointless_menuconfigs, + help="""\ +List symbols defined with 'menuconfig' where the menu is +empty due to the symbol not being followed by stuff that +depends on it""") + + parser.add_argument( + "-p", "--check-missing-config-prefix", + action="append_const", dest="checks", const=check_missing_config_prefix, + help="""\ +Look for references like + + #if MACRO + #if(n)def MACRO + defined(MACRO) + IS_ENABLED(MACRO) + +where MACRO is the name of a defined Kconfig symbol but +doesn't have a CONFIG_ prefix. Could be a typo. + +Macros that are #define'd somewhere are not flagged.""") + + return parser.parse_args() + + +def check_always_n(): + print_header("Symbols that can't be anything but n/empty") + for sym in kconf.unique_defined_syms: + if not has_prompt(sym) and not is_selected_or_implied(sym) and \ + not has_defaults(sym): + print(name_and_locs(sym)) + + +def check_unused(): + print_header("Symbols that look unused") + referenced = referenced_sym_names() + for sym in kconf.unique_defined_syms: + if not is_selecting_or_implying(sym) and not sym.choice and \ + sym.name not in referenced: + print(name_and_locs(sym)) + +def check_undefined(): + print_header("Symbols that are used, but undefined") + for name, sym in kconf.syms.items(): + if not sym.nodes: + # Undefined symbol. We skip some of the uninteresting ones. + + # Due to how Kconfig works, integer literals show up as symbols + # (from e.g. 'default 1'). Skip those. + try: + int(name, 0) + continue + except ValueError: + # Interesting undefined symbol + print(name) + + +def check_pointless_menuconfigs(): + print_header("menuconfig symbols with empty menus") + for node in kconf.node_iter(): + if node.is_menuconfig and not node.list and \ + isinstance(node.item, kconfiglib.Symbol): + print("{0.item.name:40} {0.filename}:{0.linenr}".format(node)) + + +def check_missing_config_prefix(): + print_header("Symbol references that might be missing a CONFIG_ prefix") + + # Paths to modules + modpaths = [TOP_DIR] + + # Gather #define'd macros that might overlap with symbol names, so that + # they don't trigger false positives + defined = set() + for modpath in modpaths: + regex = r"#\s*define\s+([A-Z0-9_]+)\b" + defines = run(("git", "grep", "--extended-regexp", regex), + cwd=modpath, check=False) + # Could pass --only-matching to git grep as well, but it was added + # pretty recently (2018) + defined.update(re.findall(regex, defines)) + + # Filter out symbols whose names are #define'd too. Preserve definition + # order to make the output consistent. + syms = [sym for sym in kconf.unique_defined_syms + if sym.name not in defined] + + # grep for symbol references in #ifdef/defined() that are missing a CONFIG_ + # prefix. Work around an "argument list too long" error from 'git grep' by + # checking symbols in batches. + for batch in split_list(syms, 200): + # grep for '#if((n)def) <symbol>', 'defined(<symbol>', and + # 'IS_ENABLED(<symbol>', with a missing CONFIG_ prefix + regex = r"(?:#\s*if(?:n?def)\s+|\bdefined\s*\(\s*|IS_ENABLED\(\s*)(?:" + \ + "|".join(sym.name for sym in batch) + r")\b" + cmd = ("git", "grep", "--line-number", "-I", "--perl-regexp", regex) + + for modpath in modpaths: + print(run(cmd, cwd=modpath, check=False), end="") + + +def split_list(lst, batch_size): + # check_missing_config_prefix() helper generator that splits a list into + # equal-sized batches (possibly with a shorter batch at the end) + + for i in range(0, len(lst), batch_size): + yield lst[i:i + batch_size] + + +def print_header(s): + print(s + "\n" + len(s)*"=") + + +def init_kconfig(): + global kconf + + os.environ.update( + srctree=TOP_DIR, + KCONFIG_DOC_MODE="1", + ARCH_DIR="arch", + SRCARCH="*") + + kconf = kconfiglib.Kconfig(suppress_traceback=True) + + +def referenced_sym_names(): + # Returns the names of all symbols referenced inside and outside the + # Kconfig files (that we can detect), without any "CONFIG_" prefix + + return referenced_in_kconfig() | referenced_outside_kconfig() + + +def referenced_in_kconfig(): + # Returns the names of all symbols referenced inside the Kconfig files + + return {ref.name + for node in kconf.node_iter() + for ref in node.referenced + if isinstance(ref, kconfiglib.Symbol)} + + +def referenced_outside_kconfig(): + # Returns the names of all symbols referenced outside the Kconfig files + + regex = r"\bCONFIG_[A-Z0-9_]+\b" + + res = set() + + # 'git grep' all modules + for modpath in [TOP_DIR]: + for line in run(("git", "grep", "-h", "-I", "--extended-regexp", regex), + cwd=modpath).splitlines(): + # Don't record lines starting with "CONFIG_FOO=" or "# CONFIG_FOO=" + # as references, so that symbols that are only assigned in .config + # files are not included + if re.match(r"[\s#]*CONFIG_[A-Z0-9_]+=.*", line): + continue + + # Could pass --only-matching to git grep as well, but it was added + # pretty recently (2018) + for match in re.findall(regex, line): + res.add(match[7:]) # Strip "CONFIG_" + + return res + + +def has_prompt(sym): + return any(node.prompt for node in sym.nodes) + + +def is_selected_or_implied(sym): + return sym.rev_dep is not kconf.n or sym.weak_rev_dep is not kconf.n + + +def has_defaults(sym): + return bool(sym.defaults) + + +def is_selecting_or_implying(sym): + return sym.selects or sym.implies + + +def name_and_locs(sym): + # Returns a string with the name and definition location(s) for 'sym' + + return "{:40} {}".format( + sym.name, + ", ".join("{0.filename}:{0.linenr}".format(node) for node in sym.nodes)) + + +def run(cmd, cwd=TOP_DIR, check=True): + # Runs 'cmd' with subprocess, returning the decoded stdout output. 'cwd' is + # the working directory. It defaults to the top-level Zephyr directory. + # Exits with an error if the command exits with a non-zero return code if + # 'check' is True. + + cmd_s = " ".join(shlex.quote(word) for word in cmd) + + try: + process = subprocess.Popen( + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd) + except OSError as e: + err("Failed to run '{}': {}".format(cmd_s, e)) + + stdout, stderr = process.communicate() + # errors="ignore" temporarily works around + # https://github.com/zephyrproject-rtos/esp-idf/pull/2 + stdout = stdout.decode("utf-8", errors="ignore") + stderr = stderr.decode("utf-8") + if check and process.returncode: + err("""\ +'{}' exited with status {}. + +===stdout=== +{} +===stderr=== +{}""".format(cmd_s, process.returncode, stdout, stderr)) + + if stderr: + warn("'{}' wrote to stderr:\n{}".format(cmd_s, stderr)) + + return stdout + + +def err(msg): + sys.exit(executable() + "error: " + msg) + + +def warn(msg): + print(executable() + "warning: " + msg, file=sys.stderr) + + +def executable(): + cmd = sys.argv[0] # Empty string if missing + return cmd + ": " if cmd else "" + + +if __name__ == "__main__": + main() diff --git a/scripts/kconfig/.gitignore b/scripts/kconfig/.gitignore index b5bf92f66d..500e7424b3 100644 --- a/scripts/kconfig/.gitignore +++ b/scripts/kconfig/.gitignore @@ -1,14 +1,5 @@ -# -# Generated files -# -*.moc -*conf-cfg - -# -# configuration programs -# -conf -mconf -nconf -qconf -gconf +# SPDX-License-Identifier: GPL-2.0-only +/conf +/[gmnq]conf +/[gmnq]conf-cfg +/qconf-moc.cc diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index 7656e1137b..5a215880b2 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -3,9 +3,6 @@ # Kernel configuration targets # These targets are used from top-level makefile -PHONY += xconfig gconfig menuconfig config localmodconfig localyesconfig \ - build_menuconfig build_nconfig build_gconfig build_xconfig - ifdef KBUILD_KCONFIG Kconfig := $(KBUILD_KCONFIG) else @@ -20,43 +17,48 @@ ifeq ($(quiet),silent_) silent := -s endif +export KCONFIG_DEFCONFIG_LIST := +ifndef cross_compiling +kernel-release := $(shell uname -r) +KCONFIG_DEFCONFIG_LIST += \ + /lib/modules/$(kernel-release)/.config \ + /etc/kernel-config \ + /boot/config-$(kernel-release) +endif +KCONFIG_DEFCONFIG_LIST += arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) + # We need this, in case the user has it in its environment unexport CONFIG_ -xconfig: $(obj)/qconf - $< $(silent) $(Kconfig) - -gconfig: $(obj)/gconf - $< $(silent) $(Kconfig) - -menuconfig: $(obj)/mconf - $< $(silent) $(Kconfig) - -config: $(obj)/conf - $< $(silent) --oldaskconfig $(Kconfig) +config-prog := conf +menuconfig-prog := mconf +nconfig-prog := nconf +gconfig-prog := gconf +xconfig-prog := qconf -nconfig: $(obj)/nconf - $< $(silent) $(Kconfig) +define config_rule +PHONY += $(1) +$(1): $(obj)/$($(1)-prog) + $(Q)$$< $(silent) $(Kconfig) -build_menuconfig: $(obj)/mconf +PHONY += build_$(1) +build_$(1): $(obj)/$($(1)-prog) +endef -build_nconfig: $(obj)/nconf - -build_gconfig: $(obj)/gconf - -build_xconfig: $(obj)/qconf +$(foreach c, config menuconfig nconfig gconfig xconfig, $(eval $(call config_rule,$(c)))) +PHONY += localmodconfig localyesconfig localyesconfig localmodconfig: $(obj)/conf - $(Q)perl $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config - $(Q)if [ -f .config ]; then \ - cmp -s .tmp.config .config || \ - (mv -f .config .config.old.1; \ - mv -f .tmp.config .config; \ - $< $(silent) --oldconfig $(Kconfig); \ - mv -f .config.old.1 .config.old) \ - else \ - mv -f .tmp.config .config; \ - $< $(silent) --oldconfig $(Kconfig); \ + $(Q)$(PERL) $(srctree)/$(src)/streamline_config.pl --$@ $(srctree) $(Kconfig) > .tmp.config + $(Q)if [ -f .config ]; then \ + cmp -s .tmp.config .config || \ + (mv -f .config .config.old.1; \ + mv -f .tmp.config .config; \ + $< $(silent) --oldconfig $(Kconfig); \ + mv -f .config.old.1 .config.old) \ + else \ + mv -f .tmp.config .config; \ + $< $(silent) --oldconfig $(Kconfig); \ fi $(Q)rm -f .tmp.config @@ -66,16 +68,18 @@ localyesconfig localmodconfig: $(obj)/conf # syncconfig has become an internal implementation detail and is now # deprecated for external use simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ - alldefconfig randconfig listnewconfig olddefconfig syncconfig + alldefconfig randconfig listnewconfig olddefconfig syncconfig \ + helpnewconfig yes2modconfig mod2yesconfig + PHONY += $(simple-targets) $(simple-targets): $(obj)/conf - $< $(silent) --$@ $(Kconfig) + $(Q)$< $(silent) --$@ $(Kconfig) PHONY += savedefconfig defconfig savedefconfig: $(obj)/conf - $< $(silent) --$@=defconfig $(Kconfig) + $(Q)$< $(silent) --$@=defconfig $(Kconfig) defconfig: $(obj)/conf ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),) @@ -96,25 +100,18 @@ configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/c $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles) $(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig -PHONY += kvmconfig -kvmconfig: kvm_guest.config - @: - -PHONY += xenconfig -xenconfig: xen.config - @: - PHONY += tinyconfig tinyconfig: - $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config + $(Q)KCONFIG_ALLCONFIG=kernel/configs/tiny-base.config $(MAKE) -f $(srctree)/Makefile allnoconfig + $(Q)$(MAKE) -f $(srctree)/Makefile tiny.config # CHECK: -o cache_dir=<path> working? PHONY += testconfig testconfig: $(obj)/conf - $(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \ + $(Q)$(PYTHON3) -B -m pytest $(srctree)/$(src)/tests \ -o cache_dir=$(abspath $(obj)/tests/.cache) \ $(if $(findstring 1,$(KBUILD_VERBOSE)),--capture=no) -clean-dirs += tests/.cache +clean-files += tests/.cache # Help text used by make help help: @@ -125,7 +122,9 @@ help: @echo ' gconfig - Update current config utilising a GTK+ based front-end' @echo ' oldconfig - Update current config utilising a provided .config as base' @echo ' localmodconfig - Update current config disabling modules not loaded' + @echo ' except those preserved by LMC_KEEP environment variable' @echo ' localyesconfig - Update current config converting local mods to core' + @echo ' except those preserved by LMC_KEEP environment variable' @echo ' defconfig - New config with default from ARCH supplied defconfig' @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' @echo ' allnoconfig - New config where all options are answered with no' @@ -133,29 +132,30 @@ help: @echo ' allmodconfig - New config selecting modules when possible' @echo ' alldefconfig - New config with all symbols set to default' @echo ' randconfig - New config with random answer to all options' + @echo ' yes2modconfig - Change answers from yes to mod if possible' + @echo ' mod2yesconfig - Change answers from mod to yes if possible' @echo ' listnewconfig - List new options' + @echo ' helpnewconfig - List new options and help text' @echo ' olddefconfig - Same as oldconfig but sets new symbols to their' @echo ' default value without prompting' - @echo ' kvmconfig - Enable additional options for kvm guest kernel support' - @echo ' xenconfig - Enable additional options for xen dom0 and guest kernel support' @echo ' tinyconfig - Configure the tiniest possible kernel' @echo ' testconfig - Run Kconfig unit tests (requires python3 and pytest)' # =========================================================================== # object files used by all kconfig flavours -common-objs := confdata.o expr.o lexer.lex.o parser.tab.o preprocess.o \ - symbol.o +common-objs := confdata.o expr.o lexer.lex.o menu.o parser.tab.o \ + preprocess.o symbol.o util.o $(obj)/lexer.lex.o: $(obj)/parser.tab.h HOSTCFLAGS_lexer.lex.o := -I $(srctree)/$(src) HOSTCFLAGS_parser.tab.o := -I $(srctree)/$(src) # conf: Used for defconfig, oldconfig and related targets -hostprogs-y += conf +hostprogs += conf conf-objs := conf.o $(common-objs) # nconf: Used for the nconfig target based on ncurses -hostprogs-y += nconf +hostprogs += nconf nconf-objs := nconf.o nconf.gui.o $(common-objs) HOSTLDLIBS_nconf = $(shell . $(obj)/nconf-cfg && echo $$libs) @@ -165,35 +165,38 @@ HOSTCFLAGS_nconf.gui.o = $(shell . $(obj)/nconf-cfg && echo $$cflags) $(obj)/nconf.o $(obj)/nconf.gui.o: $(obj)/nconf-cfg # mconf: Used for the menuconfig target based on lxdialog -hostprogs-y += mconf -lxdialog := checklist.o inputbox.o menubox.o textbox.o util.o yesno.o -mconf-objs := mconf.o $(addprefix lxdialog/, $(lxdialog)) $(common-objs) +hostprogs += mconf +lxdialog := $(addprefix lxdialog/, \ + checklist.o inputbox.o menubox.o textbox.o util.o yesno.o) +mconf-objs := mconf.o $(lxdialog) $(common-objs) HOSTLDLIBS_mconf = $(shell . $(obj)/mconf-cfg && echo $$libs) $(foreach f, mconf.o $(lxdialog), \ $(eval HOSTCFLAGS_$f = $$(shell . $(obj)/mconf-cfg && echo $$$$cflags))) -$(obj)/mconf.o: $(obj)/mconf-cfg -$(addprefix $(obj)/lxdialog/, $(lxdialog)): $(obj)/mconf-cfg +$(addprefix $(obj)/, mconf.o $(lxdialog)): $(obj)/mconf-cfg # qconf: Used for the xconfig target based on Qt -hostprogs-y += qconf -qconf-cxxobjs := qconf.o +hostprogs += qconf +qconf-cxxobjs := qconf.o qconf-moc.o qconf-objs := images.o $(common-objs) HOSTLDLIBS_qconf = $(shell . $(obj)/qconf-cfg && echo $$libs) HOSTCXXFLAGS_qconf.o = $(shell . $(obj)/qconf-cfg && echo $$cflags) +HOSTCXXFLAGS_qconf-moc.o = $(shell . $(obj)/qconf-cfg && echo $$cflags) -$(obj)/qconf.o: $(obj)/qconf-cfg $(obj)/qconf.moc +$(obj)/qconf.o: $(obj)/qconf-cfg quiet_cmd_moc = MOC $@ - cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) -i $< -o $@ + cmd_moc = $(shell . $(obj)/qconf-cfg && echo $$moc) $< -o $@ + +$(obj)/qconf-moc.cc: $(src)/qconf.h $(obj)/qconf-cfg FORCE + $(call if_changed,moc) -$(obj)/%.moc: $(src)/%.h $(obj)/qconf-cfg - $(call cmd,moc) +targets += qconf-moc.cc # gconf: Used for the gconfig target based on GTK+ -hostprogs-y += gconf +hostprogs += gconf gconf-objs := gconf.o images.o $(common-objs) HOSTLDLIBS_gconf = $(shell . $(obj)/gconf-cfg && echo $$libs) diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 40e16e871a..bfa1ea8f5f 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -11,7 +11,6 @@ #include <time.h> #include <unistd.h> #include <getopt.h> -#include <sys/stat.h> #include <sys/time.h> #include <errno.h> @@ -32,10 +31,13 @@ enum input_mode { defconfig, savedefconfig, listnewconfig, + helpnewconfig, olddefconfig, + yes2modconfig, + mod2yesconfig, }; static enum input_mode input_mode = oldaskconfig; - +static int input_mode_opt; static int indent = 1; static int tty_stdio; static int sync_kconfig; @@ -80,10 +82,243 @@ static void xfgets(char *str, int size, FILE *in) printf("%s", str); } -static int conf_askvalue(struct symbol *sym, const char *def) +static void set_randconfig_seed(void) +{ + unsigned int seed; + char *env; + bool seed_set = false; + + env = getenv("KCONFIG_SEED"); + if (env && *env) { + char *endp; + + seed = strtol(env, &endp, 0); + if (*endp == '\0') + seed_set = true; + } + + if (!seed_set) { + struct timeval now; + + /* + * Use microseconds derived seed, compensate for systems where it may + * be zero. + */ + gettimeofday(&now, NULL); + seed = (now.tv_sec + 1) * (now.tv_usec + 1); + } + + printf("KCONFIG_SEED=0x%X\n", seed); + srand(seed); +} + +static bool randomize_choice_values(struct symbol *csym) +{ + struct property *prop; + struct symbol *sym; + struct expr *e; + int cnt, def; + + /* + * If choice is mod then we may have more items selected + * and if no then no-one. + * In both cases stop. + */ + if (csym->curr.tri != yes) + return false; + + prop = sym_get_choice_prop(csym); + + /* count entries in choice block */ + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) + cnt++; + + /* + * find a random value and set it to yes, + * set the rest to no so we have only one set + */ + def = rand() % cnt; + + cnt = 0; + expr_list_for_each_sym(prop->expr, e, sym) { + if (def == cnt++) { + sym->def[S_DEF_USER].tri = yes; + csym->def[S_DEF_USER].val = sym; + } else { + sym->def[S_DEF_USER].tri = no; + } + sym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + sym->flags &= ~SYMBOL_VALID; + } + csym->flags |= SYMBOL_DEF_USER; + /* clear VALID to get value calculated */ + csym->flags &= ~SYMBOL_VALID; + + return true; +} + +enum conf_def_mode { + def_default, + def_yes, + def_mod, + def_y2m, + def_m2y, + def_no, + def_random +}; + +static bool conf_set_all_new_symbols(enum conf_def_mode mode) { - enum symbol_type type = sym_get_type(sym); + struct symbol *sym, *csym; + int i, cnt; + /* + * can't go as the default in switch-case below, otherwise gcc whines + * about -Wmaybe-uninitialized + */ + int pby = 50; /* probability of bool = y */ + int pty = 33; /* probability of tristate = y */ + int ptm = 33; /* probability of tristate = m */ + bool has_changed = false; + + if (mode == def_random) { + int n, p[3]; + char *env = getenv("KCONFIG_PROBABILITY"); + + n = 0; + while (env && *env) { + char *endp; + int tmp = strtol(env, &endp, 10); + + if (tmp >= 0 && tmp <= 100) { + p[n++] = tmp; + } else { + errno = ERANGE; + perror("KCONFIG_PROBABILITY"); + exit(1); + } + env = (*endp == ':') ? endp + 1 : endp; + if (n >= 3) + break; + } + switch (n) { + case 1: + pby = p[0]; + ptm = pby / 2; + pty = pby - ptm; + break; + case 2: + pty = p[0]; + ptm = p[1]; + pby = pty + ptm; + break; + case 3: + pby = p[0]; + pty = p[1]; + ptm = p[2]; + break; + } + + if (pty + ptm > 100) { + errno = ERANGE; + perror("KCONFIG_PROBABILITY"); + exit(1); + } + } + + for_all_symbols(i, sym) { + if (sym_has_value(sym) || sym->flags & SYMBOL_VALID) + continue; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: + has_changed = true; + switch (mode) { + case def_yes: + sym->def[S_DEF_USER].tri = yes; + break; + case def_mod: + sym->def[S_DEF_USER].tri = mod; + break; + case def_no: + sym->def[S_DEF_USER].tri = no; + break; + case def_random: + sym->def[S_DEF_USER].tri = no; + cnt = rand() % 100; + if (sym->type == S_TRISTATE) { + if (cnt < pty) + sym->def[S_DEF_USER].tri = yes; + else if (cnt < pty + ptm) + sym->def[S_DEF_USER].tri = mod; + } else if (cnt < pby) + sym->def[S_DEF_USER].tri = yes; + break; + default: + continue; + } + if (!(sym_is_choice(sym) && mode == def_random)) + sym->flags |= SYMBOL_DEF_USER; + break; + default: + break; + } + } + + sym_clear_all_valid(); + + /* + * We have different type of choice blocks. + * If curr.tri equals to mod then we can select several + * choice symbols in one block. + * In this case we do nothing. + * If curr.tri equals yes then only one symbol can be + * selected in a choice block and we set it to yes, + * and the rest to no. + */ + if (mode != def_random) { + for_all_symbols(i, csym) { + if ((sym_is_choice(csym) && !sym_has_value(csym)) || + sym_is_choice_value(csym)) + csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; + } + } + + for_all_symbols(i, csym) { + if (sym_has_value(csym) || !sym_is_choice(csym)) + continue; + + sym_calc_value(csym); + if (mode == def_random) + has_changed |= randomize_choice_values(csym); + else { + set_all_choice_values(csym); + has_changed = true; + } + } + + return has_changed; +} + +static void conf_rewrite_mod_or_yes(enum conf_def_mode mode) +{ + struct symbol *sym; + int i; + tristate old_val = (mode == def_y2m) ? yes : mod; + tristate new_val = (mode == def_y2m) ? mod : yes; + + for_all_symbols(i, sym) { + if (sym_get_type(sym) == S_TRISTATE && + sym->def[S_DEF_USER].tri == old_val) + sym->def[S_DEF_USER].tri = new_val; + } + sym_clear_all_valid(); +} + +static int conf_askvalue(struct symbol *sym, const char *def) +{ if (!sym_has_value(sym)) printf("(NEW) "); @@ -105,24 +340,12 @@ static int conf_askvalue(struct symbol *sym, const char *def) return 0; } /* fall through */ - case oldaskconfig: + default: fflush(stdout); xfgets(line, sizeof(line), stdin); - return 1; - default: break; } - switch (type) { - case S_INT: - case S_HEX: - case S_STRING: - printf("%s\n", def); - return 1; - default: - ; - } - printf("%s", line); return 1; } @@ -135,7 +358,7 @@ static int conf_string(struct menu *menu) printf("%*s%s ", indent - 1, "", menu->prompt->text); printf("(%s) ", sym->name); def = sym_get_string_value(sym); - if (sym_get_string_value(sym)) + if (def) printf("[%s] ", def); if (!conf_askvalue(sym, def)) return 0; @@ -417,29 +640,37 @@ static void check_conf(struct menu *menu) return; sym = menu->sym; - if (sym && !sym_has_value(sym)) { - if (sym_is_changeable(sym) || - (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { - if (input_mode == listnewconfig) { - if (sym->name) { - const char *str; - - if (sym->type == S_STRING) { - str = sym_get_string_value(sym); - str = sym_escape_string_value(str); - printf("%s%s=%s\n", CONFIG_, sym->name, str); - free((void *)str); - } else { - str = sym_get_string_value(sym); - printf("%s%s=%s\n", CONFIG_, sym->name, str); - } + if (sym && !sym_has_value(sym) && + (sym_is_changeable(sym) || + (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes))) { + + switch (input_mode) { + case listnewconfig: + if (sym->name) { + const char *str; + + if (sym->type == S_STRING) { + str = sym_get_string_value(sym); + str = sym_escape_string_value(str); + printf("%s%s=%s\n", CONFIG_, sym->name, str); + free((void *)str); + } else { + str = sym_get_string_value(sym); + printf("%s%s=%s\n", CONFIG_, sym->name, str); } - } else { - if (!conf_cnt++) - printf("*\n* Restart config...\n*\n"); - rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); } + break; + case helpnewconfig: + printf("-----\n"); + print_help(menu); + printf("-----\n"); + break; + default: + if (!conf_cnt++) + printf("*\n* Restart config...\n*\n"); + rootEntry = menu_get_parent_menu(menu); + conf(rootEntry); + break; } } @@ -448,27 +679,37 @@ static void check_conf(struct menu *menu) } static struct option long_opts[] = { - {"oldaskconfig", no_argument, NULL, oldaskconfig}, - {"oldconfig", no_argument, NULL, oldconfig}, - {"syncconfig", no_argument, NULL, syncconfig}, - {"defconfig", required_argument, NULL, defconfig}, - {"savedefconfig", required_argument, NULL, savedefconfig}, - {"allnoconfig", no_argument, NULL, allnoconfig}, - {"allyesconfig", no_argument, NULL, allyesconfig}, - {"allmodconfig", no_argument, NULL, allmodconfig}, - {"alldefconfig", no_argument, NULL, alldefconfig}, - {"randconfig", no_argument, NULL, randconfig}, - {"listnewconfig", no_argument, NULL, listnewconfig}, - {"olddefconfig", no_argument, NULL, olddefconfig}, + {"help", no_argument, NULL, 'h'}, + {"silent", no_argument, NULL, 's'}, + {"oldaskconfig", no_argument, &input_mode_opt, oldaskconfig}, + {"oldconfig", no_argument, &input_mode_opt, oldconfig}, + {"syncconfig", no_argument, &input_mode_opt, syncconfig}, + {"defconfig", required_argument, &input_mode_opt, defconfig}, + {"savedefconfig", required_argument, &input_mode_opt, savedefconfig}, + {"allnoconfig", no_argument, &input_mode_opt, allnoconfig}, + {"allyesconfig", no_argument, &input_mode_opt, allyesconfig}, + {"allmodconfig", no_argument, &input_mode_opt, allmodconfig}, + {"alldefconfig", no_argument, &input_mode_opt, alldefconfig}, + {"randconfig", no_argument, &input_mode_opt, randconfig}, + {"listnewconfig", no_argument, &input_mode_opt, listnewconfig}, + {"helpnewconfig", no_argument, &input_mode_opt, helpnewconfig}, + {"olddefconfig", no_argument, &input_mode_opt, olddefconfig}, + {"yes2modconfig", no_argument, &input_mode_opt, yes2modconfig}, + {"mod2yesconfig", no_argument, &input_mode_opt, mod2yesconfig}, {NULL, 0, NULL, 0} }; static void conf_usage(const char *progname) { - - printf("Usage: %s [-s] [option] <kconfig-file>\n", progname); - printf("[option] is _one_ of the following:\n"); + printf("Usage: %s [options] <kconfig-file>\n", progname); + printf("\n"); + printf("Generic options:\n"); + printf(" -h, --help Print this message and exit.\n"); + printf(" -s, --silent Do not print log.\n"); + printf("\n"); + printf("Mode options:\n"); printf(" --listnewconfig List new options\n"); + printf(" --helpnewconfig List new options and help text\n"); printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); printf(" --oldconfig Update a configuration using a provided .config as base\n"); printf(" --syncconfig Similar to oldconfig but generates configuration in\n" @@ -481,6 +722,9 @@ static void conf_usage(const char *progname) printf(" --allmodconfig New config where all options are answered with mod\n"); printf(" --alldefconfig New config with all symbols set to default\n"); printf(" --randconfig New config with random answer to all options\n"); + printf(" --yes2modconfig Change answers from yes to mod if possible\n"); + printf(" --mod2yesconfig Change answers from mod to yes if possible\n"); + printf(" (If none of the above is given, --oldaskconfig is the default)\n"); } int main(int ac, char **av) @@ -492,62 +736,38 @@ int main(int ac, char **av) tty_stdio = isatty(0) && isatty(1); - while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) { - if (opt == 's') { - conf_set_message_callback(NULL); - continue; - } - input_mode = (enum input_mode)opt; + while ((opt = getopt_long(ac, av, "hs", long_opts, NULL)) != -1) { switch (opt) { - case syncconfig: - /* - * syncconfig is invoked during the build stage. - * Suppress distracting "configuration written to ..." - */ - conf_set_message_callback(NULL); - sync_kconfig = 1; + case 'h': + conf_usage(progname); + exit(1); break; - case defconfig: - case savedefconfig: - defconfig_file = optarg; + case 's': + conf_set_message_callback(NULL); break; - case randconfig: - { - struct timeval now; - unsigned int seed; - char *seed_env; - - /* - * Use microseconds derived seed, - * compensate for systems where it may be zero - */ - gettimeofday(&now, NULL); - seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); - - seed_env = getenv("KCONFIG_SEED"); - if( seed_env && *seed_env ) { - char *endp; - int tmp = (int)strtol(seed_env, &endp, 0); - if (*endp == '\0') { - seed = tmp; - } + case 0: + input_mode = input_mode_opt; + switch (input_mode) { + case syncconfig: + /* + * syncconfig is invoked during the build stage. + * Suppress distracting + * "configuration written to ..." + */ + conf_set_message_callback(NULL); + sync_kconfig = 1; + break; + case defconfig: + case savedefconfig: + defconfig_file = optarg; + break; + case randconfig: + set_randconfig_seed(); + break; + default: + break; } - fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); - srand(seed); - break; - } - case oldaskconfig: - case oldconfig: - case allnoconfig: - case allyesconfig: - case allmodconfig: - case alldefconfig: - case listnewconfig: - case olddefconfig: - break; - case '?': - conf_usage(progname); - exit(1); + default: break; } } @@ -556,8 +776,7 @@ int main(int ac, char **av) conf_usage(progname); exit(1); } - name = av[optind]; - conf_parse(name); + conf_parse(av[optind]); //zconfdump(stdout); switch (input_mode) { @@ -576,7 +795,10 @@ int main(int ac, char **av) case oldaskconfig: case oldconfig: case listnewconfig: + case helpnewconfig: case olddefconfig: + case yes2modconfig: + case mod2yesconfig: conf_read(NULL); break; case allnoconfig: @@ -650,6 +872,12 @@ int main(int ac, char **av) break; case savedefconfig: break; + case yes2modconfig: + conf_rewrite_mod_or_yes(def_y2m); + break; + case mod2yesconfig: + conf_rewrite_mod_or_yes(def_m2y); + break; case oldaskconfig: rootEntry = &rootmenu; conf(&rootmenu); @@ -657,6 +885,7 @@ int main(int ac, char **av) /* fall through */ case oldconfig: case listnewconfig: + case helpnewconfig: case syncconfig: /* Update until a loop caused no more changes */ do { @@ -675,7 +904,7 @@ int main(int ac, char **av) defconfig_file); return 1; } - } else if (input_mode != listnewconfig) { + } else if (input_mode != listnewconfig && input_mode != helpnewconfig) { if (!no_conf_write && conf_write(NULL)) { fprintf(stderr, "\n*** Error during writing of the configuration.\n\n"); exit(1); diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index 3569d2dec3..cf72680cd7 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -5,6 +5,7 @@ #include <sys/mman.h> #include <sys/stat.h> +#include <sys/types.h> #include <ctype.h> #include <errno.h> #include <fcntl.h> @@ -32,7 +33,7 @@ static bool is_dir(const char *path) struct stat st; if (stat(path, &st)) - return 0; + return false; return S_ISDIR(st.st_mode); } @@ -129,19 +130,14 @@ static size_t depfile_prefix_len; static int conf_touch_dep(const char *name) { int fd, ret; - const char *s; - char *d, c; + char *d; - /* check overflow: prefix + name + ".h" + '\0' must fit in buffer. */ - if (depfile_prefix_len + strlen(name) + 3 > sizeof(depfile_path)) + /* check overflow: prefix + name + '\0' must fit in buffer. */ + if (depfile_prefix_len + strlen(name) + 1 > sizeof(depfile_path)) return -1; d = depfile_path + depfile_prefix_len; - s = name; - - while ((c = *s++)) - *d++ = (c == '_') ? '/' : tolower(c); - strcpy(d, ".h"); + strcpy(d, name); /* Assume directory path already exists. */ fd = open(depfile_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); @@ -359,28 +355,46 @@ int conf_read_simple(const char *name, int def) if (name) { in = zconf_fopen(name); } else { - struct property *prop; + char *env; name = conf_get_configname(); in = zconf_fopen(name); if (in) goto load; - sym_add_change_count(1); - if (!sym_defconfig_list) + conf_set_changed(true); + + env = getenv("KCONFIG_DEFCONFIG_LIST"); + if (!env) return 1; - for_all_defaults(sym_defconfig_list, prop) { - if (expr_calc_value(prop->visible.expr) == no || - prop->expr->type != E_SYMBOL) - continue; - sym_calc_value(prop->expr->left.sym); - name = sym_get_string_value(prop->expr->left.sym); - in = zconf_fopen(name); + while (1) { + bool is_last; + + while (isspace(*env)) + env++; + + if (!*env) + break; + + p = env; + while (*p && !isspace(*p)) + p++; + + is_last = (*p == '\0'); + + *p = '\0'; + + in = zconf_fopen(env); if (in) { conf_message("using defaults found in %s", - name); + env); goto load; } + + if (is_last) + break; + + env = p + 1; } } if (!in) @@ -425,7 +439,7 @@ load: if (def == S_DEF_USER) { sym = sym_find(line + 2 + strlen(CONFIG_)); if (!sym) { - sym_add_change_count(1); + conf_set_changed(true); continue; } } else { @@ -464,11 +478,11 @@ load: * Reading from include/config/auto.conf * If CONFIG_FOO previously existed in * auto.conf but it is missing now, - * include/config/foo.h must be touched. + * include/config/FOO must be touched. */ conf_touch_dep(line + strlen(CONFIG_)); else - sym_add_change_count(1); + conf_set_changed(true); continue; } @@ -516,7 +530,7 @@ int conf_read(const char *name) int conf_unsaved = 0; int i; - sym_set_change_count(0); + conf_set_changed(false); if (conf_read_simple(name, S_DEF_USER)) { sym_calc_value(modules_sym); @@ -574,7 +588,8 @@ int conf_read(const char *name) } } - sym_add_change_count(conf_warnings || conf_unsaved); + if (conf_warnings || conf_unsaved) + conf_set_changed(true); return 0; } @@ -710,25 +725,6 @@ static struct conf_printer header_printer_cb = .print_comment = header_print_comment, }; -/* - * Tristate printer - * - * This printer is used when generating the `include/config/tristate.conf' file. - */ -static void -tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - if (sym->type == S_TRISTATE && *value != 'n') - fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); -} - -static struct conf_printer tristate_printer_cb = -{ - .print_symbol = tristate_print_symbol, - .print_comment = kconfig_print_comment, -}; - static void conf_write_symbol(FILE *fp, struct symbol *sym, struct conf_printer *printer, void *printer_arg) { @@ -938,7 +934,7 @@ next: if (is_same(name, tmpname)) { conf_message("No change to %s", name); unlink(tmpname); - sym_set_change_count(0); + conf_set_changed(false); return 0; } @@ -950,7 +946,7 @@ next: conf_message("configuration written to %s", name); - sym_set_change_count(0); + conf_set_changed(false); return 0; } @@ -1062,7 +1058,7 @@ int conf_write_autoconf(int overwrite) struct symbol *sym; const char *name; const char *autoconf_name = conf_get_autoconfig_name(); - FILE *out, *tristate, *out_h; + FILE *out, *out_h; int i; if (!overwrite && is_present(autoconf_name)) @@ -1077,23 +1073,13 @@ int conf_write_autoconf(int overwrite) if (!out) return 1; - tristate = fopen(".tmpconfig_tristate", "w"); - if (!tristate) { - fclose(out); - return 1; - } - out_h = fopen(".tmpconfig.h", "w"); if (!out_h) { fclose(out); - fclose(tristate); return 1; } conf_write_heading(out, &kconfig_printer_cb, NULL); - - conf_write_heading(tristate, &tristate_printer_cb, NULL); - conf_write_heading(out_h, &header_printer_cb, NULL); for_all_symbols(i, sym) { @@ -1101,15 +1087,11 @@ int conf_write_autoconf(int overwrite) if (!(sym->flags & SYMBOL_WRITE) || !sym->name) continue; - /* write symbol to auto.conf, tristate and header files */ + /* write symbols to auto.conf and autoconf.h */ conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); - - conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); } fclose(out); - fclose(tristate); fclose(out_h); name = getenv("KCONFIG_AUTOHEADER"); @@ -1120,14 +1102,6 @@ int conf_write_autoconf(int overwrite) if (rename(".tmpconfig.h", name)) return 1; - name = getenv("KCONFIG_TRISTATE"); - if (!name) - name = "include/config/tristate.conf"; - if (make_parent_dir(name)) - return 1; - if (rename(".tmpconfig_tristate", name)) - return 1; - if (make_parent_dir(autoconf_name)) return 1; /* @@ -1140,26 +1114,20 @@ int conf_write_autoconf(int overwrite) return 0; } -static int sym_change_count; +static bool conf_changed; static void (*conf_changed_callback)(void); -void sym_set_change_count(int count) +void conf_set_changed(bool val) { - int _sym_change_count = sym_change_count; - sym_change_count = count; - if (conf_changed_callback && - (bool)_sym_change_count != (bool)count) + if (conf_changed_callback && conf_changed != val) conf_changed_callback(); -} -void sym_add_change_count(int count) -{ - sym_set_change_count(count + sym_change_count); + conf_changed = val; } bool conf_get_changed(void) { - return sym_change_count; + return conf_changed; } void conf_set_changed_callback(void (*fn)(void)) @@ -1167,54 +1135,6 @@ void conf_set_changed_callback(void (*fn)(void)) conf_changed_callback = fn; } -static bool randomize_choice_values(struct symbol *csym) -{ - struct property *prop; - struct symbol *sym; - struct expr *e; - int cnt, def; - - /* - * If choice is mod then we may have more items selected - * and if no then no-one. - * In both cases stop. - */ - if (csym->curr.tri != yes) - return false; - - prop = sym_get_choice_prop(csym); - - /* count entries in choice block */ - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) - cnt++; - - /* - * find a random value and set it to yes, - * set the rest to no so we have only one set - */ - def = (rand() % cnt); - - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) { - if (def == cnt++) { - sym->def[S_DEF_USER].tri = yes; - csym->def[S_DEF_USER].val = sym; - } - else { - sym->def[S_DEF_USER].tri = no; - } - sym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - sym->flags &= ~SYMBOL_VALID; - } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID); - - return true; -} - void set_all_choice_values(struct symbol *csym) { struct property *prop; @@ -1234,131 +1154,3 @@ void set_all_choice_values(struct symbol *csym) /* clear VALID to get value calculated */ csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); } - -bool conf_set_all_new_symbols(enum conf_def_mode mode) -{ - struct symbol *sym, *csym; - int i, cnt, pby, pty, ptm; /* pby: probability of bool = y - * pty: probability of tristate = y - * ptm: probability of tristate = m - */ - - pby = 50; pty = ptm = 33; /* can't go as the default in switch-case - * below, otherwise gcc whines about - * -Wmaybe-uninitialized */ - if (mode == def_random) { - int n, p[3]; - char *env = getenv("KCONFIG_PROBABILITY"); - n = 0; - while( env && *env ) { - char *endp; - int tmp = strtol( env, &endp, 10 ); - if( tmp >= 0 && tmp <= 100 ) { - p[n++] = tmp; - } else { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - env = (*endp == ':') ? endp+1 : endp; - if( n >=3 ) { - break; - } - } - switch( n ) { - case 1: - pby = p[0]; ptm = pby/2; pty = pby-ptm; - break; - case 2: - pty = p[0]; ptm = p[1]; pby = pty + ptm; - break; - case 3: - pby = p[0]; pty = p[1]; ptm = p[2]; - break; - } - - if( pty+ptm > 100 ) { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - } - bool has_changed = false; - - for_all_symbols(i, sym) { - if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) - continue; - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - has_changed = true; - switch (mode) { - case def_yes: - sym->def[S_DEF_USER].tri = yes; - break; - case def_mod: - sym->def[S_DEF_USER].tri = mod; - break; - case def_no: - if (sym->flags & SYMBOL_ALLNOCONFIG_Y) - sym->def[S_DEF_USER].tri = yes; - else - sym->def[S_DEF_USER].tri = no; - break; - case def_random: - sym->def[S_DEF_USER].tri = no; - cnt = rand() % 100; - if (sym->type == S_TRISTATE) { - if (cnt < pty) - sym->def[S_DEF_USER].tri = yes; - else if (cnt < (pty+ptm)) - sym->def[S_DEF_USER].tri = mod; - } else if (cnt < pby) - sym->def[S_DEF_USER].tri = yes; - break; - default: - continue; - } - if (!(sym_is_choice(sym) && mode == def_random)) - sym->flags |= SYMBOL_DEF_USER; - break; - default: - break; - } - - } - - sym_clear_all_valid(); - - /* - * We have different type of choice blocks. - * If curr.tri equals to mod then we can select several - * choice symbols in one block. - * In this case we do nothing. - * If curr.tri equals yes then only one symbol can be - * selected in a choice block and we set it to yes, - * and the rest to no. - */ - if (mode != def_random) { - for_all_symbols(i, csym) { - if ((sym_is_choice(csym) && !sym_has_value(csym)) || - sym_is_choice_value(csym)) - csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; - } - } - - for_all_symbols(i, csym) { - if (sym_has_value(csym) || !sym_is_choice(csym)) - continue; - - sym_calc_value(csym); - if (mode == def_random) - has_changed = randomize_choice_values(csym); - else { - set_all_choice_values(csym); - has_changed = true; - } - } - - return has_changed; -} diff --git a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c index 77ffff3a05..81ebf8108c 100644 --- a/scripts/kconfig/expr.c +++ b/scripts/kconfig/expr.c @@ -13,7 +13,6 @@ #define DEBUG_EXPR 0 -static int expr_eq(struct expr *e1, struct expr *e2); static struct expr *expr_eliminate_yn(struct expr *e); struct expr *expr_alloc_symbol(struct symbol *sym) @@ -250,10 +249,17 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) * equals some operand in the other (operands do not need to appear in the same * order), recursively. */ -static int expr_eq(struct expr *e1, struct expr *e2) +int expr_eq(struct expr *e1, struct expr *e2) { int res, old_count; + /* + * A NULL expr is taken to be yes, but there's also a different way to + * represent yes. expr_is_yes() checks for either representation. + */ + if (!e1 || !e2) + return expr_is_yes(e1) && expr_is_yes(e2); + if (e1->type != e2->type) return 0; switch (e1->type) { diff --git a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h index 017843c9a4..9c9caca5bd 100644 --- a/scripts/kconfig/expr.h +++ b/scripts/kconfig/expr.h @@ -156,9 +156,6 @@ struct symbol { /* choice values need to be set before calculating this symbol value */ #define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 -/* Set symbol to y if allnoconfig; used for symbols that hide others */ -#define SYMBOL_ALLNOCONFIG_Y 0x200000 - #define SYMBOL_MAXLENGTH 256 #define SYMBOL_HASHSIZE 9973 @@ -191,7 +188,6 @@ enum prop_type { struct property { struct property *next; /* next property - null if last */ - struct symbol *sym; /* the symbol for which the property is associated */ enum prop_type type; /* type of property */ const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ struct expr_value visible; @@ -282,15 +278,12 @@ struct jump_key { int index; }; -#define JUMP_NB 9 - extern struct file *file_list; extern struct file *current_file; struct file *lookup_file(const char *name); extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; -extern struct symbol *sym_defconfig_list; extern int cdebug; struct expr *expr_alloc_symbol(struct symbol *sym); struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); @@ -301,6 +294,7 @@ struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); struct expr *expr_copy(const struct expr *org); void expr_free(struct expr *e); void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); +int expr_eq(struct expr *e1, struct expr *e2); tristate expr_calc_value(struct expr *e); struct expr *expr_trans_bool(struct expr *e); struct expr *expr_eliminate_dups(struct expr *e); diff --git a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c index e36b342f10..17adabfd6e 100644 --- a/scripts/kconfig/gconf.c +++ b/scripts/kconfig/gconf.c @@ -3,10 +3,6 @@ * Copyright (C) 2002-2003 Romain Lievin <roms@tilp.info> */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - #include <stdlib.h> #include "lkc.h" #include "images.h" @@ -18,6 +14,7 @@ #include <stdio.h> #include <string.h> +#include <strings.h> #include <unistd.h> #include <time.h> @@ -1047,8 +1044,13 @@ static gchar **fill_row(struct menu *menu) g_free(row[i]); bzero(row, sizeof(row)); + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + row[COL_OPTION] = - g_strdup_printf("%s %s", menu_get_prompt(menu), + g_strdup_printf("%s %s %s %s", + ptype == P_COMMENT ? "***" : "", + menu_get_prompt(menu), + ptype == P_COMMENT ? "***" : "", sym && !sym_has_value(sym) ? "(NEW)" : ""); if (opt_mode == OPT_ALL && !menu_is_visible(menu)) @@ -1059,7 +1061,6 @@ static gchar **fill_row(struct menu *menu) else row[COL_COLOR] = g_strdup("Black"); - ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; switch (ptype) { case P_MENU: row[COL_PIXBUF] = (gchar *) xpm_menu; @@ -1451,9 +1452,6 @@ int main(int ac, char *av[]) gtk_init(&ac, &av); glade_init(); - //add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps"); - //add_pixmap_directory (PACKAGE_SOURCE_DIR "/pixmaps"); - /* Determine GUI path */ env = getenv(SRCTREE); if (env) diff --git a/scripts/kconfig/images.c b/scripts/kconfig/images.c index b4fa0e4a63..2f9afffa5d 100644 --- a/scripts/kconfig/images.c +++ b/scripts/kconfig/images.c @@ -5,7 +5,7 @@ #include "images.h" -const char *xpm_load[] = { +const char * const xpm_load[] = { "22 22 5 1", ". c None", "# c #000000", @@ -35,7 +35,7 @@ const char *xpm_load[] = { "###############.......", "......................"}; -const char *xpm_save[] = { +const char * const xpm_save[] = { "22 22 5 1", ". c None", "# c #000000", @@ -65,7 +65,7 @@ const char *xpm_save[] = { "..##################..", "......................"}; -const char *xpm_back[] = { +const char * const xpm_back[] = { "22 22 3 1", ". c None", "# c #000083", @@ -93,7 +93,7 @@ const char *xpm_back[] = { "......................", "......................"}; -const char *xpm_tree_view[] = { +const char * const xpm_tree_view[] = { "22 22 2 1", ". c None", "# c #000000", @@ -120,7 +120,7 @@ const char *xpm_tree_view[] = { "......................", "......................"}; -const char *xpm_single_view[] = { +const char * const xpm_single_view[] = { "22 22 2 1", ". c None", "# c #000000", @@ -147,7 +147,7 @@ const char *xpm_single_view[] = { "......................", "......................"}; -const char *xpm_split_view[] = { +const char * const xpm_split_view[] = { "22 22 2 1", ". c None", "# c #000000", @@ -174,7 +174,7 @@ const char *xpm_split_view[] = { "......................", "......................"}; -const char *xpm_symbol_no[] = { +const char * const xpm_symbol_no[] = { "12 12 2 1", " c white", ". c black", @@ -191,7 +191,7 @@ const char *xpm_symbol_no[] = { " .......... ", " "}; -const char *xpm_symbol_mod[] = { +const char * const xpm_symbol_mod[] = { "12 12 2 1", " c white", ". c black", @@ -208,7 +208,7 @@ const char *xpm_symbol_mod[] = { " .......... ", " "}; -const char *xpm_symbol_yes[] = { +const char * const xpm_symbol_yes[] = { "12 12 2 1", " c white", ". c black", @@ -225,7 +225,7 @@ const char *xpm_symbol_yes[] = { " .......... ", " "}; -const char *xpm_choice_no[] = { +const char * const xpm_choice_no[] = { "12 12 2 1", " c white", ". c black", @@ -242,7 +242,7 @@ const char *xpm_choice_no[] = { " .... ", " "}; -const char *xpm_choice_yes[] = { +const char * const xpm_choice_yes[] = { "12 12 2 1", " c white", ". c black", @@ -259,7 +259,7 @@ const char *xpm_choice_yes[] = { " .... ", " "}; -const char *xpm_menu[] = { +const char * const xpm_menu[] = { "12 12 2 1", " c white", ". c black", @@ -276,7 +276,7 @@ const char *xpm_menu[] = { " .......... ", " "}; -const char *xpm_menu_inv[] = { +const char * const xpm_menu_inv[] = { "12 12 2 1", " c white", ". c black", @@ -293,7 +293,7 @@ const char *xpm_menu_inv[] = { " .......... ", " "}; -const char *xpm_menuback[] = { +const char * const xpm_menuback[] = { "12 12 2 1", " c white", ". c black", @@ -310,7 +310,7 @@ const char *xpm_menuback[] = { " .......... ", " "}; -const char *xpm_void[] = { +const char * const xpm_void[] = { "12 12 2 1", " c white", ". c black", diff --git a/scripts/kconfig/images.h b/scripts/kconfig/images.h index d8ff614bd0..7212dec200 100644 --- a/scripts/kconfig/images.h +++ b/scripts/kconfig/images.h @@ -10,21 +10,21 @@ extern "C" { #endif -extern const char *xpm_load[]; -extern const char *xpm_save[]; -extern const char *xpm_back[]; -extern const char *xpm_tree_view[]; -extern const char *xpm_single_view[]; -extern const char *xpm_split_view[]; -extern const char *xpm_symbol_no[]; -extern const char *xpm_symbol_mod[]; -extern const char *xpm_symbol_yes[]; -extern const char *xpm_choice_no[]; -extern const char *xpm_choice_yes[]; -extern const char *xpm_menu[]; -extern const char *xpm_menu_inv[]; -extern const char *xpm_menuback[]; -extern const char *xpm_void[]; +extern const char * const xpm_load[]; +extern const char * const xpm_save[]; +extern const char * const xpm_back[]; +extern const char * const xpm_tree_view[]; +extern const char * const xpm_single_view[]; +extern const char * const xpm_split_view[]; +extern const char * const xpm_symbol_no[]; +extern const char * const xpm_symbol_mod[]; +extern const char * const xpm_symbol_yes[]; +extern const char * const xpm_choice_no[]; +extern const char * const xpm_choice_yes[]; +extern const char * const xpm_menu[]; +extern const char * const xpm_menu_inv[]; +extern const char * const xpm_menuback[]; +extern const char * const xpm_void[]; #ifdef __cplusplus } diff --git a/scripts/kconfig/internal.h b/scripts/kconfig/internal.h new file mode 100644 index 0000000000..2f7298c21b --- /dev/null +++ b/scripts/kconfig/internal.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef INTERNAL_H +#define INTERNAL_H + +struct menu; + +extern struct menu *current_menu, *current_entry; + +#endif /* INTERNAL_H */ diff --git a/scripts/kconfig/lexer.l b/scripts/kconfig/lexer.l index 6354c905b0..312cbad2d3 100644 --- a/scripts/kconfig/lexer.l +++ b/scripts/kconfig/lexer.l @@ -12,7 +12,6 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <unistd.h> #include "lkc.h" #include "parser.tab.h" @@ -36,7 +35,7 @@ struct buffer { YY_BUFFER_STATE state; }; -struct buffer *current_buf; +static struct buffer *current_buf; static int last_ts, first_ts; @@ -92,7 +91,6 @@ n [A-Za-z0-9_-] [ \t]* /* whitespaces */ \\\n /* escaped new line */ \n return T_EOL; -"allnoconfig_y" return T_ALLNOCONFIG_Y; "bool" return T_BOOL; "choice" return T_CHOICE; "comment" return T_COMMENT; @@ -100,12 +98,11 @@ n [A-Za-z0-9_-] "def_bool" return T_DEF_BOOL; "def_tristate" return T_DEF_TRISTATE; "default" return T_DEFAULT; -"defconfig_list" return T_DEFCONFIG_LIST; "depends" return T_DEPENDS; "endchoice" return T_ENDCHOICE; "endif" return T_ENDIF; "endmenu" return T_ENDMENU; -"help"|"---help---" return T_HELP; +"help" return T_HELP; "hex" return T_HEX; "if" return T_IF; "imply" return T_IMPLY; @@ -115,7 +112,6 @@ n [A-Za-z0-9_-] "menuconfig" return T_MENUCONFIG; "modules" return T_MODULES; "on" return T_ON; -"option" return T_OPTION; "optional" return T_OPTIONAL; "prompt" return T_PROMPT; "range" return T_RANGE; diff --git a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h index 4fb16f3166..fa8c010aa6 100644 --- a/scripts/kconfig/lkc.h +++ b/scripts/kconfig/lkc.h @@ -6,6 +6,10 @@ #ifndef LKC_H #define LKC_H +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + #include "expr.h" #ifdef __cplusplus @@ -16,10 +20,6 @@ extern "C" { #define SRCTREE "srctree" -#ifndef PACKAGE -#define PACKAGE "linux" -#endif - #ifndef CONFIG_ #define CONFIG_ "CONFIG_" #endif @@ -30,14 +30,6 @@ static inline const char *CONFIG_prefix(void) #undef CONFIG_ #define CONFIG_ CONFIG_prefix() -enum conf_def_mode { - def_default, - def_yes, - def_mod, - def_no, - def_random -}; - extern int yylineno; void zconfdump(FILE *out); void zconf_starthelp(void); @@ -49,9 +41,6 @@ const char *zconf_curname(void); /* confdata.c */ const char *conf_get_configname(void); -void sym_set_change_count(int count); -void sym_add_change_count(int count); -bool conf_set_all_new_symbols(enum conf_def_mode mode); void set_all_choice_values(struct symbol *csym); /* confdata.c and expr.c */ @@ -63,23 +52,6 @@ static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) fprintf(stderr, "Error in writing or end of file.\n"); } -/* menu.c */ -void _menu_init(void); -void menu_warn(struct menu *menu, const char *fmt, ...); -struct menu *menu_add_menu(void); -void menu_end_menu(void); -void menu_add_entry(struct symbol *sym); -void menu_add_dep(struct expr *dep); -void menu_add_visibility(struct expr *dep); -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_add_option_modules(void); -void menu_add_option_defconfig_list(void); -void menu_add_option_allnoconfig_y(void); -void menu_finalize(struct menu *parent); -void menu_set_type(int type); - /* util.c */ struct file *file_lookup(const char *name); void *xmalloc(size_t size); @@ -106,13 +78,39 @@ void str_append(struct gstr *gs, const char *s); void str_printf(struct gstr *gs, const char *fmt, ...); const char *str_get(struct gstr *gs); +/* menu.c */ +void _menu_init(void); +void menu_warn(struct menu *menu, const char *fmt, ...); +struct menu *menu_add_menu(void); +void menu_end_menu(void); +void menu_add_entry(struct symbol *sym); +void menu_add_dep(struct expr *dep); +void menu_add_visibility(struct expr *dep); +struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); +void menu_finalize(struct menu *parent); +void menu_set_type(int type); + +extern struct menu rootmenu; + +bool menu_is_empty(struct menu *menu); +bool menu_is_visible(struct menu *menu); +bool menu_has_prompt(struct menu *menu); +const char *menu_get_prompt(struct menu *menu); +struct menu *menu_get_root_menu(struct menu *menu); +struct menu *menu_get_parent_menu(struct menu *menu); +bool menu_has_help(struct menu *menu); +const char *menu_get_help(struct menu *menu); +struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); +void menu_get_ext_help(struct menu *menu, struct gstr *help); + /* symbol.c */ void sym_clear_all_valid(void); struct symbol *sym_choice_default(struct symbol *sym); struct property *sym_get_range_prop(struct symbol *sym); const char *sym_get_string_default(struct symbol *sym); struct symbol *sym_check_deps(struct symbol *sym); -struct property *prop_alloc(enum prop_type type, struct symbol *sym); struct symbol *prop_get_symbol(struct property *prop); static inline tristate sym_get_tristate_value(struct symbol *sym) diff --git a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h index f9ab98238a..a11626bdc4 100644 --- a/scripts/kconfig/lkc_proto.h +++ b/scripts/kconfig/lkc_proto.h @@ -8,24 +8,11 @@ int conf_read_simple(const char *name, int); int conf_write_defconfig(const char *name); int conf_write(const char *name); int conf_write_autoconf(int overwrite); +void conf_set_changed(bool val); bool conf_get_changed(void); void conf_set_changed_callback(void (*fn)(void)); void conf_set_message_callback(void (*fn)(const char *s)); -/* menu.c */ -extern struct menu rootmenu; - -bool menu_is_empty(struct menu *menu); -bool menu_is_visible(struct menu *menu); -bool menu_has_prompt(struct menu *menu); -const char * menu_get_prompt(struct menu *menu); -struct menu * menu_get_root_menu(struct menu *menu); -struct menu * menu_get_parent_menu(struct menu *menu); -bool menu_has_help(struct menu *menu); -const char * menu_get_help(struct menu *menu); -struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); -void menu_get_ext_help(struct menu *menu, struct gstr *help); - /* symbol.c */ extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c index 1b490d4af0..3f78fb2651 100644 --- a/scripts/kconfig/lxdialog/util.c +++ b/scripts/kconfig/lxdialog/util.c @@ -363,7 +363,7 @@ void print_title(WINDOW *dialog, const char *title, int width) /* * Print a string of text in a window, automatically wrap around to the * next line if the string is too long to fit on one line. Newline - * characters '\n' are propperly processed. We start on a new line + * characters '\n' are properly processed. We start on a new line * if there is no room for at least 4 nonblanks following a double-space. */ void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x) @@ -541,7 +541,7 @@ int first_alpha(const char *string, const char *exempt) * lxdialog suggest <ESC> <ESC> which is correctly translated to two * times esc. But then we need to ignore the second esc to avoid stepping * out one menu too much. Filter away all escaped key sequences since - * keypad(FALSE) turn off ncurses support for escape sequences - and thats + * keypad(FALSE) turn off ncurses support for escape sequences - and that's * needed to make notimeout() do as expected. */ int on_key_esc(WINDOW *win) diff --git a/scripts/kconfig/mconf-cfg.sh b/scripts/kconfig/mconf-cfg.sh index c812872d7f..b520e407a8 100755 --- a/scripts/kconfig/mconf-cfg.sh +++ b/scripts/kconfig/mconf-cfg.sh @@ -33,7 +33,9 @@ if [ -f /usr/include/ncurses/ncurses.h ]; then exit 0 fi -if [ -f /usr/include/ncurses.h ]; then +# As a final fallback before giving up, check if $HOSTCC knows of a default +# ncurses installation (e.g. from a vendor-specific sysroot). +if echo '#include <ncurses.h>' | ${HOSTCC} -E - >/dev/null 2>&1; then echo cflags=\"-D_GNU_SOURCE\" echo libs=\"-lncurses\" exit 0 @@ -44,4 +46,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" +echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* ncurses installed in a non-default location." +echo >&2 "*" exit 1 diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 49c26ea9dd..9d3cf51056 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -15,12 +15,15 @@ #include <stdarg.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <signal.h> #include <unistd.h> #include "lkc.h" #include "lxdialog/dialog.h" +#define JUMP_NB 9 + static const char mconf_readme[] = "Overview\n" "--------\n" @@ -296,17 +299,12 @@ static char filename[PATH_MAX+1]; static void set_config_filename(const char *config_filename) { static char menu_backtitle[PATH_MAX+128]; - int size; - size = snprintf(menu_backtitle, sizeof(menu_backtitle), - "%s - %s", config_filename, rootmenu.prompt->text); - if (size >= sizeof(menu_backtitle)) - menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; + snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", + config_filename, rootmenu.prompt->text); set_dialog_backtitle(menu_backtitle); - size = snprintf(filename, sizeof(filename), "%s", config_filename); - if (size >= sizeof(filename)) - filename[sizeof(filename)-1] = '\0'; + snprintf(filename, sizeof(filename), "%s", config_filename); } struct subtitle_part { @@ -907,7 +905,7 @@ static void conf_load(void) return; if (!conf_read(dialog_input_result)) { set_config_filename(dialog_input_result); - sym_set_change_count(1); + conf_set_changed(true); return; } show_textbox(NULL, "File does not exist!", 5, 38); diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index d9d1646985..606ba8a63c 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -9,6 +9,7 @@ #include <string.h> #include "lkc.h" +#include "internal.h" static const char nohelp_text[] = "There is no help available for this option."; @@ -65,7 +66,8 @@ void menu_add_entry(struct symbol *sym) struct menu *menu_add_menu(void) { last_entry_ptr = ¤t_entry->list; - return current_menu = current_entry; + current_menu = current_entry; + return current_menu; } void menu_end_menu(void) @@ -124,61 +126,76 @@ void menu_set_type(int type) sym_type_name(sym->type), sym_type_name(type)); } -static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) +static struct property *menu_add_prop(enum prop_type type, struct expr *expr, + struct expr *dep) { - struct property *prop = prop_alloc(type, current_entry->sym); + struct property *prop; + prop = xmalloc(sizeof(*prop)); + memset(prop, 0, sizeof(*prop)); + prop->type = type; + prop->file = current_file; + prop->lineno = zconf_lineno(); prop->menu = current_entry; prop->expr = expr; prop->visible.expr = dep; - if (prompt) { - if (isspace(*prompt)) { - prop_warn(prop, "leading whitespace ignored"); - while (isspace(*prompt)) - prompt++; - } - if (current_entry->prompt && current_entry != &rootmenu) - prop_warn(prop, "prompt redefined"); + /* append property to the prop list of symbol */ + if (current_entry->sym) { + struct property **propp; - /* Apply all upper menus' visibilities to actual prompts. */ - if(type == P_PROMPT) { - struct menu *menu = current_entry; + for (propp = ¤t_entry->sym->prop; + *propp; + propp = &(*propp)->next) + ; + *propp = prop; + } - while ((menu = menu->parent) != NULL) { - struct expr *dup_expr; + return prop; +} - if (!menu->visibility) - continue; - /* - * Do not add a reference to the - * menu's visibility expression but - * use a copy of it. Otherwise the - * expression reduction functions - * will modify expressions that have - * multiple references which can - * cause unwanted side effects. - */ - dup_expr = expr_copy(menu->visibility); +struct property *menu_add_prompt(enum prop_type type, char *prompt, + struct expr *dep) +{ + struct property *prop = menu_add_prop(type, NULL, dep); - prop->visible.expr - = expr_alloc_and(prop->visible.expr, - dup_expr); - } - } + if (isspace(*prompt)) { + prop_warn(prop, "leading whitespace ignored"); + while (isspace(*prompt)) + prompt++; + } + if (current_entry->prompt) + prop_warn(prop, "prompt redefined"); + + /* Apply all upper menus' visibilities to actual prompts. */ + if (type == P_PROMPT) { + struct menu *menu = current_entry; + + while ((menu = menu->parent) != NULL) { + struct expr *dup_expr; - current_entry->prompt = prop; + if (!menu->visibility) + continue; + /* + * Do not add a reference to the menu's visibility + * expression but use a copy of it. Otherwise the + * expression reduction functions will modify + * expressions that have multiple references which + * can cause unwanted side effects. + */ + dup_expr = expr_copy(menu->visibility); + + prop->visible.expr = expr_alloc_and(prop->visible.expr, + dup_expr); + } } + + current_entry->prompt = prop; prop->text = prompt; return prop; } -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) -{ - return menu_add_prop(type, prompt, NULL, dep); -} - void menu_add_visibility(struct expr *expr) { current_entry->visibility = expr_alloc_and(current_entry->visibility, @@ -187,34 +204,12 @@ void menu_add_visibility(struct expr *expr) void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) { - menu_add_prop(type, NULL, expr, dep); + menu_add_prop(type, expr, dep); } void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) { - menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); -} - -void menu_add_option_modules(void) -{ - if (modules_sym) - zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", - current_entry->sym->name, modules_sym->name); - modules_sym = current_entry->sym; -} - -void menu_add_option_defconfig_list(void) -{ - if (!sym_defconfig_list) - sym_defconfig_list = current_entry->sym; - else if (sym_defconfig_list != current_entry->sym) - zconf_error("trying to redefine defconfig symbol"); - sym_defconfig_list->flags |= SYMBOL_NO_WRITE; -} - -void menu_add_option_allnoconfig_y(void) -{ - current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; + menu_add_prop(type, expr_alloc_symbol(sym), dep); } static int menu_validate_number(struct symbol *sym, struct symbol *sym2) @@ -326,12 +321,10 @@ void menu_finalize(struct menu *parent) * choice value symbols. */ parentdep = expr_alloc_symbol(sym); - } else if (parent->prompt) - /* Menu node for 'menu' */ - parentdep = parent->prompt->visible.expr; - else - /* Menu node for 'if' */ + } else { + /* Menu node for 'menu', 'if' */ parentdep = parent->dep; + } /* For each child menu node... */ for (menu = parent->list; menu; menu = menu->next) { @@ -698,6 +691,21 @@ const char *menu_get_help(struct menu *menu) return ""; } +static void get_def_str(struct gstr *r, struct menu *menu) +{ + str_printf(r, "Defined at %s:%d\n", + menu->file->name, menu->lineno); +} + +static void get_dep_str(struct gstr *r, struct expr *expr, const char *prefix) +{ + if (!expr_is_yes(expr)) { + str_append(r, prefix); + expr_gstr_print(expr, r); + str_append(r, "\n"); + } +} + static void get_prompt_str(struct gstr *r, struct property *prop, struct list_head *head) { @@ -705,7 +713,20 @@ static void get_prompt_str(struct gstr *r, struct property *prop, struct menu *submenu[8], *menu, *location = NULL; struct jump_key *jump = NULL; - str_printf(r, "Prompt: %s\n", prop->text); + str_printf(r, " Prompt: %s\n", prop->text); + + get_dep_str(r, prop->menu->dep, " Depends on: "); + /* + * Most prompts in Linux have visibility that exactly matches their + * dependencies. For these, we print only the dependencies to improve + * readability. However, prompts with inline "if" expressions and + * prompts with a parent that has a "visible if" expression have + * differing dependencies and visibility. In these rare cases, we + * print both. + */ + if (!expr_eq(prop->menu->dep, prop->visible.expr)) + get_dep_str(r, prop->visible.expr, " Visible if: "); + menu = prop->menu->parent; for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { bool accessible = menu_is_visible(menu); @@ -755,18 +776,6 @@ static void get_prompt_str(struct gstr *r, struct property *prop, } } -/* - * get property of type P_SYMBOL - */ -static struct property *get_symbol_prop(struct symbol *sym) -{ - struct property *prop = NULL; - - for_all_properties(sym, prop, P_SYMBOL) - break; - return prop; -} - static void get_symbol_props_str(struct gstr *r, struct symbol *sym, enum prop_type tok, const char *prefix) { @@ -806,32 +815,34 @@ static void get_symbol_str(struct gstr *r, struct symbol *sym, } } } - for_all_prompts(sym, prop) - get_prompt_str(r, prop, head); - - prop = get_symbol_prop(sym); - if (prop) { - str_printf(r, " Defined at %s:%d\n", prop->menu->file->name, - prop->menu->lineno); - if (!expr_is_yes(prop->visible.expr)) { - str_append(r, " Depends on: "); - expr_gstr_print(prop->visible.expr, r); - str_append(r, "\n"); + + /* Print the definitions with prompts before the ones without */ + for_all_properties(sym, prop, P_SYMBOL) { + if (prop->menu->prompt) { + get_def_str(r, prop->menu); + get_prompt_str(r, prop->menu->prompt, head); + } + } + + for_all_properties(sym, prop, P_SYMBOL) { + if (!prop->menu->prompt) { + get_def_str(r, prop->menu); + get_dep_str(r, prop->menu->dep, " Depends on: "); } } - get_symbol_props_str(r, sym, P_SELECT, " Selects: "); + get_symbol_props_str(r, sym, P_SELECT, "Selects: "); if (sym->rev_dep.expr) { - expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, " Selected by [y]:\n"); - expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, " Selected by [m]:\n"); - expr_gstr_print_revdep(sym->rev_dep.expr, r, no, " Selected by [n]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, yes, "Selected by [y]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, mod, "Selected by [m]:\n"); + expr_gstr_print_revdep(sym->rev_dep.expr, r, no, "Selected by [n]:\n"); } - get_symbol_props_str(r, sym, P_IMPLY, " Implies: "); + get_symbol_props_str(r, sym, P_IMPLY, "Implies: "); if (sym->implied.expr) { - expr_gstr_print_revdep(sym->implied.expr, r, yes, " Implied by [y]:\n"); - expr_gstr_print_revdep(sym->implied.expr, r, mod, " Implied by [m]:\n"); - expr_gstr_print_revdep(sym->implied.expr, r, no, " Implied by [n]:\n"); + expr_gstr_print_revdep(sym->implied.expr, r, yes, "Implied by [y]:\n"); + expr_gstr_print_revdep(sym->implied.expr, r, mod, "Implied by [m]:\n"); + expr_gstr_print_revdep(sym->implied.expr, r, no, "Implied by [n]:\n"); } str_append(r, "\n\n"); diff --git a/scripts/kconfig/merge_config.sh b/scripts/kconfig/merge_config.sh index d924c51d28..63c8565206 100755 --- a/scripts/kconfig/merge_config.sh +++ b/scripts/kconfig/merge_config.sh @@ -13,12 +13,12 @@ # Copyright (c) 2009-2010 Wind River Systems, Inc. # Copyright 2011 Linaro +set -e + clean_up() { rm -f $TMP_FILE rm -f $MERGE_FILE - exit } -trap clean_up HUP INT TERM usage() { echo "Usage: $0 [OPTIONS] [CONFIG [...]]" @@ -110,6 +110,9 @@ TMP_FILE=$(mktemp ./.tmp.config.XXXXXXXXXX) MERGE_FILE=$(mktemp ./.merge_tmp.config.XXXXXXXXXX) echo "Using $INITFILE as base" + +trap clean_up EXIT + cat $INITFILE > $TMP_FILE # Merge files, printing warnings on overridden values @@ -155,7 +158,6 @@ if [ "$RUNMAKE" = "false" ]; then echo "#" echo "# merged configuration written to $KCONFIG_CONFIG (needs make)" echo "#" - clean_up exit fi @@ -177,7 +179,7 @@ make KCONFIG_ALLCONFIG=$TMP_FILE $OUTPUT_ARG $ALLTARGET for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do REQUESTED_VAL=$(grep -w -e "$CFG" $TMP_FILE) - ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG") + ACTUAL_VAL=$(grep -w -e "$CFG" "$KCONFIG_CONFIG" || true) if [ "x$REQUESTED_VAL" != "x$ACTUAL_VAL" ] ; then echo "Value requested for $CFG not in final .config" echo "Requested value: $REQUESTED_VAL" @@ -185,5 +187,3 @@ for CFG in $(sed -n -e "$SED_CONFIG_EXP1" -e "$SED_CONFIG_EXP2" $TMP_FILE); do echo "" fi done - -clean_up diff --git a/scripts/kconfig/nconf-cfg.sh b/scripts/kconfig/nconf-cfg.sh index 001559ef0a..c212255070 100755 --- a/scripts/kconfig/nconf-cfg.sh +++ b/scripts/kconfig/nconf-cfg.sh @@ -44,4 +44,7 @@ echo >&2 "* Unable to find the ncurses package." echo >&2 "* Install ncurses (ncurses-devel or libncurses-dev" echo >&2 "* depending on your distribution)." echo >&2 "*" +echo >&2 "* You may also need to install pkg-config to find the" +echo >&2 "* ncurses installed in a non-default location." +echo >&2 "*" exit 1 diff --git a/scripts/kconfig/nconf.c b/scripts/kconfig/nconf.c index b7c1ef7571..7b371bd7fb 100644 --- a/scripts/kconfig/nconf.c +++ b/scripts/kconfig/nconf.c @@ -8,6 +8,7 @@ #define _GNU_SOURCE #endif #include <string.h> +#include <strings.h> #include <stdlib.h> #include "lkc.h" @@ -267,7 +268,7 @@ static int mwin_max_cols; static MENU *curses_menu; static ITEM *curses_menu_items[MAX_MENU_ITEMS]; static struct mitem k_menu_items[MAX_MENU_ITEMS]; -static int items_num; +static unsigned int items_num; static int global_exit; /* the currently selected button */ static const char *current_instructions = menu_instructions; @@ -369,18 +370,18 @@ static void print_function_line(void) int lines = getmaxy(stdscr); for (i = 0; i < function_keys_num; i++) { - (void) wattrset(main_window, attributes[FUNCTION_HIGHLIGHT]); + wattrset(main_window, attr_function_highlight); mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].key_str); - (void) wattrset(main_window, attributes[FUNCTION_TEXT]); + wattrset(main_window, attr_function_text); offset += strlen(function_keys[i].key_str); mvwprintw(main_window, lines-3, offset, "%s", function_keys[i].func); offset += strlen(function_keys[i].func) + skip; } - (void) wattrset(main_window, attributes[NORMAL]); + wattrset(main_window, attr_normal); } /* help */ @@ -495,16 +496,20 @@ typedef enum {MATCH_TINKER_PATTERN_UP, MATCH_TINKER_PATTERN_DOWN, /* return the index of the matched item, or -1 if no such item exists */ static int get_mext_match(const char *match_str, match_f flag) { - int match_start = item_index(current_item(curses_menu)); - int index; + int match_start, index; + + /* Do not search if the menu is empty (i.e. items_num == 0) */ + match_start = item_index(current_item(curses_menu)); + if (match_start == ERR) + return -1; if (flag == FIND_NEXT_MATCH_DOWN) ++match_start; else if (flag == FIND_NEXT_MATCH_UP) --match_start; + match_start = (match_start + items_num) % items_num; index = match_start; - index = (index + items_num) % items_num; while (true) { char *str = k_menu_items[index].str; if (strcasestr(str, match_str) != NULL) @@ -626,19 +631,12 @@ static int item_is_tag(char tag) static char filename[PATH_MAX+1]; static char menu_backtitle[PATH_MAX+128]; -static const char *set_config_filename(const char *config_filename) +static void set_config_filename(const char *config_filename) { - int size; + snprintf(menu_backtitle, sizeof(menu_backtitle), "%s - %s", + config_filename, rootmenu.prompt->text); - size = snprintf(menu_backtitle, sizeof(menu_backtitle), - "%s - %s", config_filename, rootmenu.prompt->text); - if (size >= sizeof(menu_backtitle)) - menu_backtitle[sizeof(menu_backtitle)-1] = '\0'; - - size = snprintf(filename, sizeof(filename), "%s", config_filename); - if (size >= sizeof(filename)) - filename[sizeof(filename)-1] = '\0'; - return menu_backtitle; + snprintf(filename, sizeof(filename), "%s", config_filename); } /* return = 0 means we are successful. @@ -754,7 +752,6 @@ static void build_conf(struct menu *menu) switch (ptype) { case P_MENU: child_count++; - prompt = prompt; if (single_menu_mode) { item_make(menu, 'm', "%s%*c%s", @@ -956,16 +953,15 @@ static void show_menu(const char *prompt, const char *instructions, current_instructions = instructions; clear(); - (void) wattrset(main_window, attributes[NORMAL]); - print_in_middle(stdscr, 1, 0, getmaxx(stdscr), + print_in_middle(stdscr, 1, getmaxx(stdscr), menu_backtitle, - attributes[MAIN_HEADING]); + attr_main_heading); - (void) wattrset(main_window, attributes[MAIN_MENU_BOX]); + wattrset(main_window, attr_main_menu_box); box(main_window, 0, 0); - (void) wattrset(main_window, attributes[MAIN_MENU_HEADING]); + wattrset(main_window, attr_main_menu_heading); mvwprintw(main_window, 0, 3, " %s ", prompt); - (void) wattrset(main_window, attributes[NORMAL]); + wattrset(main_window, attr_normal); set_menu_items(curses_menu, curses_menu_items); @@ -1068,7 +1064,6 @@ static int do_match(int key, struct match_state *state, int *ans) static void conf(struct menu *menu) { struct menu *submenu = NULL; - const char *prompt = menu_get_prompt(menu); struct symbol *sym; int res; int current_index = 0; @@ -1086,9 +1081,8 @@ static void conf(struct menu *menu) if (!child_count) break; - show_menu(prompt ? prompt : "Main Menu", - menu_instructions, - current_index, &last_top_row); + show_menu(menu_get_prompt(menu), menu_instructions, + current_index, &last_top_row); keypad((menu_win(curses_menu)), TRUE); while (!global_exit) { if (match_state.in_search) { @@ -1404,7 +1398,7 @@ static void conf_load(void) return; if (!conf_read(dialog_input_result)) { set_config_filename(dialog_input_result); - sym_set_change_count(1); + conf_set_changed(true); return; } btn_dialog(main_window, "File does not exist!", 0); @@ -1523,9 +1517,9 @@ int main(int ac, char **av) menu_opts_on(curses_menu, O_NONCYCLIC); menu_opts_on(curses_menu, O_IGNORECASE); set_menu_mark(curses_menu, " "); - set_menu_fore(curses_menu, attributes[MAIN_MENU_FORE]); - set_menu_back(curses_menu, attributes[MAIN_MENU_BACK]); - set_menu_grey(curses_menu, attributes[MAIN_MENU_GREY]); + set_menu_fore(curses_menu, attr_main_menu_fore); + set_menu_back(curses_menu, attr_main_menu_back); + set_menu_grey(curses_menu, attr_main_menu_grey); set_config_filename(conf_get_configname()); setup_windows(); diff --git a/scripts/kconfig/nconf.gui.c b/scripts/kconfig/nconf.gui.c index 77f525a861..9aedf40f1d 100644 --- a/scripts/kconfig/nconf.gui.c +++ b/scripts/kconfig/nconf.gui.c @@ -7,169 +7,120 @@ #include "nconf.h" #include "lkc.h" -/* a list of all the different widgets we use */ -attributes_t attributes[ATTR_MAX+1] = {0}; - -/* available colors: - COLOR_BLACK 0 - COLOR_RED 1 - COLOR_GREEN 2 - COLOR_YELLOW 3 - COLOR_BLUE 4 - COLOR_MAGENTA 5 - COLOR_CYAN 6 - COLOR_WHITE 7 - */ -static void set_normal_colors(void) -{ - init_pair(NORMAL, -1, -1); - init_pair(MAIN_HEADING, COLOR_MAGENTA, -1); - - /* FORE is for the selected item */ - init_pair(MAIN_MENU_FORE, -1, -1); - /* BACK for all the rest */ - init_pair(MAIN_MENU_BACK, -1, -1); - init_pair(MAIN_MENU_GREY, -1, -1); - init_pair(MAIN_MENU_HEADING, COLOR_GREEN, -1); - init_pair(MAIN_MENU_BOX, COLOR_YELLOW, -1); - - init_pair(SCROLLWIN_TEXT, -1, -1); - init_pair(SCROLLWIN_HEADING, COLOR_GREEN, -1); - init_pair(SCROLLWIN_BOX, COLOR_YELLOW, -1); - - init_pair(DIALOG_TEXT, -1, -1); - init_pair(DIALOG_BOX, COLOR_YELLOW, -1); - init_pair(DIALOG_MENU_BACK, COLOR_YELLOW, -1); - init_pair(DIALOG_MENU_FORE, COLOR_RED, -1); - - init_pair(INPUT_BOX, COLOR_YELLOW, -1); - init_pair(INPUT_HEADING, COLOR_GREEN, -1); - init_pair(INPUT_TEXT, -1, -1); - init_pair(INPUT_FIELD, -1, -1); - - init_pair(FUNCTION_HIGHLIGHT, -1, -1); - init_pair(FUNCTION_TEXT, COLOR_YELLOW, -1); -} - -/* available attributes: - A_NORMAL Normal display (no highlight) - A_STANDOUT Best highlighting mode of the terminal. - A_UNDERLINE Underlining - A_REVERSE Reverse video - A_BLINK Blinking - A_DIM Half bright - A_BOLD Extra bright or bold - A_PROTECT Protected mode - A_INVIS Invisible or blank mode - A_ALTCHARSET Alternate character set - A_CHARTEXT Bit-mask to extract a character - COLOR_PAIR(n) Color-pair number n - */ -static void normal_color_theme(void) -{ - /* automatically add color... */ -#define mkattr(name, attr) do { \ -attributes[name] = attr | COLOR_PAIR(name); } while (0) - mkattr(NORMAL, NORMAL); - mkattr(MAIN_HEADING, A_BOLD | A_UNDERLINE); - - mkattr(MAIN_MENU_FORE, A_REVERSE); - mkattr(MAIN_MENU_BACK, A_NORMAL); - mkattr(MAIN_MENU_GREY, A_NORMAL); - mkattr(MAIN_MENU_HEADING, A_BOLD); - mkattr(MAIN_MENU_BOX, A_NORMAL); - - mkattr(SCROLLWIN_TEXT, A_NORMAL); - mkattr(SCROLLWIN_HEADING, A_BOLD); - mkattr(SCROLLWIN_BOX, A_BOLD); - - mkattr(DIALOG_TEXT, A_BOLD); - mkattr(DIALOG_BOX, A_BOLD); - mkattr(DIALOG_MENU_FORE, A_STANDOUT); - mkattr(DIALOG_MENU_BACK, A_NORMAL); - - mkattr(INPUT_BOX, A_NORMAL); - mkattr(INPUT_HEADING, A_BOLD); - mkattr(INPUT_TEXT, A_NORMAL); - mkattr(INPUT_FIELD, A_UNDERLINE); - - mkattr(FUNCTION_HIGHLIGHT, A_BOLD); - mkattr(FUNCTION_TEXT, A_REVERSE); -} - -static void no_colors_theme(void) -{ - /* automatically add highlight, no color */ -#define mkattrn(name, attr) { attributes[name] = attr; } - - mkattrn(NORMAL, NORMAL); - mkattrn(MAIN_HEADING, A_BOLD | A_UNDERLINE); - - mkattrn(MAIN_MENU_FORE, A_STANDOUT); - mkattrn(MAIN_MENU_BACK, A_NORMAL); - mkattrn(MAIN_MENU_GREY, A_NORMAL); - mkattrn(MAIN_MENU_HEADING, A_BOLD); - mkattrn(MAIN_MENU_BOX, A_NORMAL); - - mkattrn(SCROLLWIN_TEXT, A_NORMAL); - mkattrn(SCROLLWIN_HEADING, A_BOLD); - mkattrn(SCROLLWIN_BOX, A_BOLD); - - mkattrn(DIALOG_TEXT, A_NORMAL); - mkattrn(DIALOG_BOX, A_BOLD); - mkattrn(DIALOG_MENU_FORE, A_STANDOUT); - mkattrn(DIALOG_MENU_BACK, A_NORMAL); - - mkattrn(INPUT_BOX, A_BOLD); - mkattrn(INPUT_HEADING, A_BOLD); - mkattrn(INPUT_TEXT, A_NORMAL); - mkattrn(INPUT_FIELD, A_UNDERLINE); - - mkattrn(FUNCTION_HIGHLIGHT, A_BOLD); - mkattrn(FUNCTION_TEXT, A_REVERSE); -} +int attr_normal; +int attr_main_heading; +int attr_main_menu_box; +int attr_main_menu_fore; +int attr_main_menu_back; +int attr_main_menu_grey; +int attr_main_menu_heading; +int attr_scrollwin_text; +int attr_scrollwin_heading; +int attr_scrollwin_box; +int attr_dialog_text; +int attr_dialog_menu_fore; +int attr_dialog_menu_back; +int attr_dialog_box; +int attr_input_box; +int attr_input_heading; +int attr_input_text; +int attr_input_field; +int attr_function_text; +int attr_function_highlight; + +#define COLOR_ATTR(_at, _fg, _bg, _hl) \ + { .attr = &(_at), .has_color = true, .color_fg = _fg, .color_bg = _bg, .highlight = _hl } +#define NO_COLOR_ATTR(_at, _hl) \ + { .attr = &(_at), .has_color = false, .highlight = _hl } +#define COLOR_DEFAULT -1 + +struct nconf_attr_param { + int *attr; + bool has_color; + int color_fg; + int color_bg; + int highlight; +}; + +static const struct nconf_attr_param color_theme_params[] = { + COLOR_ATTR(attr_normal, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_main_heading, COLOR_MAGENTA, COLOR_DEFAULT, A_BOLD | A_UNDERLINE), + COLOR_ATTR(attr_main_menu_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_main_menu_fore, COLOR_DEFAULT, COLOR_DEFAULT, A_REVERSE), + COLOR_ATTR(attr_main_menu_back, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_main_menu_grey, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_main_menu_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_scrollwin_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_scrollwin_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_scrollwin_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_dialog_text, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_dialog_menu_fore, COLOR_RED, COLOR_DEFAULT, A_STANDOUT), + COLOR_ATTR(attr_dialog_menu_back, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_dialog_box, COLOR_YELLOW, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_input_box, COLOR_YELLOW, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_input_heading, COLOR_GREEN, COLOR_DEFAULT, A_BOLD), + COLOR_ATTR(attr_input_text, COLOR_DEFAULT, COLOR_DEFAULT, A_NORMAL), + COLOR_ATTR(attr_input_field, COLOR_DEFAULT, COLOR_DEFAULT, A_UNDERLINE), + COLOR_ATTR(attr_function_text, COLOR_YELLOW, COLOR_DEFAULT, A_REVERSE), + COLOR_ATTR(attr_function_highlight, COLOR_DEFAULT, COLOR_DEFAULT, A_BOLD), + { /* sentinel */ } +}; + +static const struct nconf_attr_param no_color_theme_params[] = { + NO_COLOR_ATTR(attr_normal, A_NORMAL), + NO_COLOR_ATTR(attr_main_heading, A_BOLD | A_UNDERLINE), + NO_COLOR_ATTR(attr_main_menu_box, A_NORMAL), + NO_COLOR_ATTR(attr_main_menu_fore, A_STANDOUT), + NO_COLOR_ATTR(attr_main_menu_back, A_NORMAL), + NO_COLOR_ATTR(attr_main_menu_grey, A_NORMAL), + NO_COLOR_ATTR(attr_main_menu_heading, A_BOLD), + NO_COLOR_ATTR(attr_scrollwin_text, A_NORMAL), + NO_COLOR_ATTR(attr_scrollwin_heading, A_BOLD), + NO_COLOR_ATTR(attr_scrollwin_box, A_BOLD), + NO_COLOR_ATTR(attr_dialog_text, A_NORMAL), + NO_COLOR_ATTR(attr_dialog_menu_fore, A_STANDOUT), + NO_COLOR_ATTR(attr_dialog_menu_back, A_NORMAL), + NO_COLOR_ATTR(attr_dialog_box, A_BOLD), + NO_COLOR_ATTR(attr_input_box, A_BOLD), + NO_COLOR_ATTR(attr_input_heading, A_BOLD), + NO_COLOR_ATTR(attr_input_text, A_NORMAL), + NO_COLOR_ATTR(attr_input_field, A_UNDERLINE), + NO_COLOR_ATTR(attr_function_text, A_REVERSE), + NO_COLOR_ATTR(attr_function_highlight, A_BOLD), + { /* sentinel */ } +}; void set_colors(void) { - start_color(); - use_default_colors(); - set_normal_colors(); + const struct nconf_attr_param *p; + int pair = 0; + if (has_colors()) { - normal_color_theme(); + start_color(); + use_default_colors(); + p = color_theme_params; } else { - /* give defaults */ - no_colors_theme(); + p = no_color_theme_params; } -} + for (; p->attr; p++) { + int attr = p->highlight; + + if (p->has_color) { + pair++; + init_pair(pair, p->color_fg, p->color_bg); + attr |= COLOR_PAIR(pair); + } + + *p->attr = attr; + } +} /* this changes the windows attributes !!! */ -void print_in_middle(WINDOW *win, - int starty, - int startx, - int width, - const char *string, - chtype color) -{ int length, x, y; - float temp; - - - if (win == NULL) - win = stdscr; - getyx(win, y, x); - if (startx != 0) - x = startx; - if (starty != 0) - y = starty; - if (width == 0) - width = 80; - - length = strlen(string); - temp = (width - length) / 2; - x = startx + (int)temp; - (void) wattrset(win, color); - mvwprintw(win, y, x, "%s", string); - refresh(); +void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs) +{ + wattrset(win, attrs); + mvwprintw(win, y, (width - strlen(str)) / 2, "%s", str); } int get_line_no(const char *text) @@ -294,14 +245,14 @@ int btn_dialog(WINDOW *main_window, const char *msg, int btn_num, ...) msg_win = derwin(win, win_rows-2, msg_width, 1, 1+(total_width+2-msg_width)/2); - set_menu_fore(menu, attributes[DIALOG_MENU_FORE]); - set_menu_back(menu, attributes[DIALOG_MENU_BACK]); + set_menu_fore(menu, attr_dialog_menu_fore); + set_menu_back(menu, attr_dialog_menu_back); - (void) wattrset(win, attributes[DIALOG_BOX]); + wattrset(win, attr_dialog_box); box(win, 0, 0); /* print message */ - (void) wattrset(msg_win, attributes[DIALOG_TEXT]); + wattrset(msg_win, attr_dialog_text); fill_window(msg_win, msg); set_menu_win(menu, win); @@ -405,16 +356,16 @@ int dialog_inputbox(WINDOW *main_window, form_win = derwin(win, 1, prompt_width, prompt_lines+3, 2); keypad(form_win, TRUE); - (void) wattrset(form_win, attributes[INPUT_FIELD]); + wattrset(form_win, attr_input_field); - (void) wattrset(win, attributes[INPUT_BOX]); + wattrset(win, attr_input_box); box(win, 0, 0); - (void) wattrset(win, attributes[INPUT_HEADING]); + wattrset(win, attr_input_heading); if (title) mvwprintw(win, 0, 3, "%s", title); /* print message */ - (void) wattrset(prompt_win, attributes[INPUT_TEXT]); + wattrset(prompt_win, attr_input_text); fill_window(prompt_win, prompt); mvwprintw(form_win, 0, 0, "%*s", prompt_width, " "); @@ -576,7 +527,7 @@ void show_scroll_win(WINDOW *main_window, /* create the pad */ pad = newpad(total_lines+10, total_cols+10); - (void) wattrset(pad, attributes[SCROLLWIN_TEXT]); + wattrset(pad, attr_scrollwin_text); fill_window(pad, text); win_lines = min(total_lines+4, lines-2); @@ -591,9 +542,9 @@ void show_scroll_win(WINDOW *main_window, win = newwin(win_lines, win_cols, y, x); keypad(win, TRUE); /* show the help in the help window, and show the help panel */ - (void) wattrset(win, attributes[SCROLLWIN_BOX]); + wattrset(win, attr_scrollwin_box); box(win, 0, 0); - (void) wattrset(win, attributes[SCROLLWIN_HEADING]); + wattrset(win, attr_scrollwin_heading); mvwprintw(win, 0, 3, " %s ", title); panel = new_panel(win); @@ -604,10 +555,9 @@ void show_scroll_win(WINDOW *main_window, text_cols, 0); print_in_middle(win, text_lines+2, - 0, text_cols, "<OK>", - attributes[DIALOG_MENU_FORE]); + attr_dialog_menu_fore); wrefresh(win); res = wgetch(win); diff --git a/scripts/kconfig/nconf.h b/scripts/kconfig/nconf.h index fa5245eb93..6f925bc74e 100644 --- a/scripts/kconfig/nconf.h +++ b/scripts/kconfig/nconf.h @@ -32,30 +32,26 @@ typeof(b) _b = b;\ _a < _b ? _a : _b; }) -typedef enum { - NORMAL = 1, - MAIN_HEADING, - MAIN_MENU_BOX, - MAIN_MENU_FORE, - MAIN_MENU_BACK, - MAIN_MENU_GREY, - MAIN_MENU_HEADING, - SCROLLWIN_TEXT, - SCROLLWIN_HEADING, - SCROLLWIN_BOX, - DIALOG_TEXT, - DIALOG_MENU_FORE, - DIALOG_MENU_BACK, - DIALOG_BOX, - INPUT_BOX, - INPUT_HEADING, - INPUT_TEXT, - INPUT_FIELD, - FUNCTION_TEXT, - FUNCTION_HIGHLIGHT, - ATTR_MAX -} attributes_t; -extern attributes_t attributes[]; +extern int attr_normal; +extern int attr_main_heading; +extern int attr_main_menu_box; +extern int attr_main_menu_fore; +extern int attr_main_menu_back; +extern int attr_main_menu_grey; +extern int attr_main_menu_heading; +extern int attr_scrollwin_text; +extern int attr_scrollwin_heading; +extern int attr_scrollwin_box; +extern int attr_dialog_text; +extern int attr_dialog_menu_fore; +extern int attr_dialog_menu_back; +extern int attr_dialog_box; +extern int attr_input_box; +extern int attr_input_heading; +extern int attr_input_text; +extern int attr_input_field; +extern int attr_function_text; +extern int attr_function_highlight; typedef enum { F_HELP = 1, @@ -72,12 +68,7 @@ typedef enum { void set_colors(void); /* this changes the windows attributes !!! */ -void print_in_middle(WINDOW *win, - int starty, - int startx, - int width, - const char *string, - chtype color); +void print_in_middle(WINDOW *win, int y, int width, const char *str, int attrs); int get_line_length(const char *line); int get_line_no(const char *text); const char *get_line(const char *text, int line_no); diff --git a/scripts/kconfig/parser.y b/scripts/kconfig/parser.y index 60936c7686..2af7ce4e15 100644 --- a/scripts/kconfig/parser.y +++ b/scripts/kconfig/parser.y @@ -12,6 +12,7 @@ #include <stdbool.h> #include "lkc.h" +#include "internal.h" #define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) @@ -28,7 +29,7 @@ static bool zconf_endtoken(const char *tokenname, struct symbol *symbol_hash[SYMBOL_HASHSIZE]; -static struct menu *current_menu, *current_entry; +struct menu *current_menu, *current_entry; %} @@ -45,7 +46,6 @@ static struct menu *current_menu, *current_entry; %token <string> T_HELPTEXT %token <string> T_WORD %token <string> T_WORD_QUOTE -%token T_ALLNOCONFIG_Y %token T_BOOL %token T_CHOICE %token T_CLOSE_PAREN @@ -53,7 +53,6 @@ static struct menu *current_menu, *current_entry; %token T_COMMENT %token T_CONFIG %token T_DEFAULT -%token T_DEFCONFIG_LIST %token T_DEF_BOOL %token T_DEF_TRISTATE %token T_DEPENDS @@ -71,7 +70,6 @@ static struct menu *current_menu, *current_entry; %token T_MODULES %token T_ON %token T_OPEN_PAREN -%token T_OPTION %token T_OPTIONAL %token T_PLUS_EQUAL %token T_PROMPT @@ -90,7 +88,6 @@ static struct menu *current_menu, *current_entry; %left T_LESS T_LESS_EQUAL T_GREATER T_GREATER_EQUAL %nonassoc T_NOT -%type <string> prompt %type <symbol> nonconst_symbol %type <symbol> symbol %type <type> type logic_type default @@ -113,27 +110,31 @@ input: mainmenu_stmt stmt_list | stmt_list; /* mainmenu entry */ -mainmenu_stmt: T_MAINMENU prompt T_EOL +mainmenu_stmt: T_MAINMENU T_WORD_QUOTE T_EOL { menu_add_prompt(P_MENU, $2, NULL); }; stmt_list: /* empty */ - | stmt_list common_stmt + | stmt_list assignment_stmt | stmt_list choice_stmt + | stmt_list comment_stmt + | stmt_list config_stmt + | stmt_list if_stmt | stmt_list menu_stmt + | stmt_list menuconfig_stmt + | stmt_list source_stmt | stmt_list T_WORD error T_EOL { zconf_error("unknown statement \"%s\"", $2); } | stmt_list error T_EOL { zconf_error("invalid statement"); } ; -common_stmt: - if_stmt - | comment_stmt - | config_stmt - | menuconfig_stmt - | source_stmt - | assignment_stmt +stmt_list_in_choice: + /* empty */ + | stmt_list_in_choice comment_stmt + | stmt_list_in_choice config_stmt + | stmt_list_in_choice if_stmt_in_choice + | stmt_list_in_choice error T_EOL { zconf_error("invalid statement"); } ; /* config/menuconfig entry */ @@ -181,7 +182,7 @@ config_option: type prompt_stmt_opt T_EOL $1); }; -config_option: T_PROMPT prompt if_expr T_EOL +config_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); @@ -215,19 +216,12 @@ config_option: T_RANGE symbol symbol if_expr T_EOL printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); }; -config_option: T_OPTION T_MODULES T_EOL -{ - menu_add_option_modules(); -}; - -config_option: T_OPTION T_DEFCONFIG_LIST T_EOL +config_option: T_MODULES T_EOL { - menu_add_option_defconfig_list(); -}; - -config_option: T_OPTION T_ALLNOCONFIG_Y T_EOL -{ - menu_add_option_allnoconfig_y(); + if (modules_sym) + zconf_error("symbol '%s' redefines option 'modules' already defined by symbol '%s'", + current_entry->sym->name, modules_sym->name); + modules_sym = current_entry->sym; }; /* choice entry */ @@ -255,7 +249,7 @@ choice_end: end } }; -choice_stmt: choice_entry choice_block choice_end +choice_stmt: choice_entry stmt_list_in_choice choice_end ; choice_option_list: @@ -265,7 +259,7 @@ choice_option_list: | choice_option_list help ; -choice_option: T_PROMPT prompt if_expr T_EOL +choice_option: T_PROMPT T_WORD_QUOTE if_expr T_EOL { menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); @@ -306,11 +300,6 @@ default: | T_DEF_BOOL { $$ = S_BOOLEAN; } | T_DEF_TRISTATE { $$ = S_TRISTATE; } -choice_block: - /* empty */ - | choice_block common_stmt -; - /* if entry */ if_entry: T_IF expr T_EOL @@ -332,9 +321,12 @@ if_end: end if_stmt: if_entry stmt_list if_end ; +if_stmt_in_choice: if_entry stmt_list_in_choice if_end +; + /* menu entry */ -menu: T_MENU prompt T_EOL +menu: T_MENU T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_MENU, $2, NULL); @@ -363,7 +355,7 @@ menu_option_list: | menu_option_list depends ; -source_stmt: T_SOURCE prompt T_EOL +source_stmt: T_SOURCE T_WORD_QUOTE T_EOL { printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); zconf_nextfile($2); @@ -372,7 +364,7 @@ source_stmt: T_SOURCE prompt T_EOL /* comment entry */ -comment: T_COMMENT prompt T_EOL +comment: T_COMMENT T_WORD_QUOTE T_EOL { menu_add_entry(NULL); menu_add_prompt(P_COMMENT, $2, NULL); @@ -429,15 +421,11 @@ visible: T_VISIBLE if_expr T_EOL prompt_stmt_opt: /* empty */ - | prompt if_expr + | T_WORD_QUOTE if_expr { menu_add_prompt(P_PROMPT, $1, $2); }; -prompt: T_WORD - | T_WORD_QUOTE -; - end: T_ENDMENU T_EOL { $$ = "menu"; } | T_ENDCHOICE T_EOL { $$ = "choice"; } | T_ENDIF T_EOL { $$ = "if"; } @@ -520,7 +508,7 @@ void conf_parse(const char *name) } if (yynerrs) exit(1); - sym_set_change_count(1); + conf_set_changed(true); } static bool zconf_endtoken(const char *tokenname, @@ -665,7 +653,7 @@ static void print_symbol(FILE *out, struct menu *menu) break; case P_SYMBOL: fputs( " symbol ", out); - fprintf(out, "%s\n", prop->sym->name); + fprintf(out, "%s\n", prop->menu->sym->name); break; default: fprintf(out, " unknown prop %d!\n", prop->type); @@ -726,6 +714,3 @@ void zconfdump(FILE *out) } } } - -#include "util.c" -#include "menu.c" diff --git a/scripts/kconfig/preprocess.c b/scripts/kconfig/preprocess.c index 0243086fb1..0590f86df6 100644 --- a/scripts/kconfig/preprocess.c +++ b/scripts/kconfig/preprocess.c @@ -114,7 +114,7 @@ static char *do_error_if(int argc, char *argv[]) if (!strcmp(argv[0], "y")) pperror("%s", argv[1]); - return NULL; + return xstrdup(""); } static char *do_filename(int argc, char *argv[]) diff --git a/scripts/kconfig/qconf-cfg.sh b/scripts/kconfig/qconf-cfg.sh index 02ccc0ae10..fa564cd795 100755 --- a/scripts/kconfig/qconf-cfg.sh +++ b/scripts/kconfig/qconf-cfg.sh @@ -2,7 +2,6 @@ # SPDX-License-Identifier: GPL-2.0 PKG="Qt5Core Qt5Gui Qt5Widgets" -PKG2="QtCore QtGui" if [ -z "$(command -v pkg-config)" ]; then echo >&2 "*" @@ -12,21 +11,14 @@ if [ -z "$(command -v pkg-config)" ]; then fi if pkg-config --exists $PKG; then - echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets)\" + echo cflags=\"-std=c++11 -fPIC $(pkg-config --cflags $PKG)\" echo libs=\"$(pkg-config --libs $PKG)\" echo moc=\"$(pkg-config --variable=host_bins Qt5Core)/moc\" exit 0 fi -if pkg-config --exists $PKG2; then - echo cflags=\"$(pkg-config --cflags $PKG2)\" - echo libs=\"$(pkg-config --libs $PKG2)\" - echo moc=\"$(pkg-config --variable=moc_location QtCore)\" - exit 0 -fi - echo >&2 "*" -echo >&2 "* Could not find Qt via pkg-config." -echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH" +echo >&2 "* Could not find Qt5 via pkg-config." +echo >&2 "* Please install Qt5 and make sure it's in PKG_CONFIG_PATH" echo >&2 "*" exit 1 diff --git a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc index 82773cc35d..78087b2d9a 100644 --- a/scripts/kconfig/qconf.cc +++ b/scripts/kconfig/qconf.cc @@ -4,34 +4,25 @@ * Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com> */ -#include <qglobal.h> - -#include <QMainWindow> -#include <QList> -#include <qtextbrowser.h> #include <QAction> +#include <QApplication> +#include <QCloseEvent> +#include <QDebug> +#include <QDesktopWidget> #include <QFileDialog> +#include <QLabel> +#include <QLayout> +#include <QList> #include <QMenu> - -#include <qapplication.h> -#include <qdesktopwidget.h> -#include <qtoolbar.h> -#include <qlayout.h> -#include <qsplitter.h> -#include <qlineedit.h> -#include <qlabel.h> -#include <qpushbutton.h> -#include <qmenubar.h> -#include <qmessagebox.h> -#include <qregexp.h> -#include <qevent.h> +#include <QMenuBar> +#include <QMessageBox> +#include <QToolBar> #include <stdlib.h> #include "lkc.h" #include "qconf.h" -#include "qconf.moc" #include "images.h" @@ -40,11 +31,6 @@ static ConfigSettings *configSettings; QAction *ConfigMainWindow::saveAction; -static inline QString qgettext(const char* str) -{ - return QString::fromLocal8Bit(str); -} - ConfigSettings::ConfigSettings() : QSettings("kernel.org", "qconf") { @@ -88,14 +74,13 @@ bool ConfigSettings::writeSizes(const QString& key, const QList<int>& value) return true; } - -/* - * set the new data - * TODO check the value - */ -void ConfigItem::okRename(int col) -{ -} +QIcon ConfigItem::symbolYesIcon; +QIcon ConfigItem::symbolModIcon; +QIcon ConfigItem::symbolNoIcon; +QIcon ConfigItem::choiceYesIcon; +QIcon ConfigItem::choiceNoIcon; +QIcon ConfigItem::menuIcon; +QIcon ConfigItem::menubackIcon; /* * update the displayed of a menu entry @@ -111,14 +96,14 @@ void ConfigItem::updateMenu(void) list = listView(); if (goParent) { - setPixmap(promptColIdx, list->menuBackPix); + setIcon(promptColIdx, menubackIcon); prompt = ".."; goto set_prompt; } sym = menu->sym; prop = menu->prompt; - prompt = qgettext(menu_get_prompt(menu)); + prompt = menu_get_prompt(menu); if (prop) switch (prop->type) { case P_MENU: @@ -128,15 +113,16 @@ void ConfigItem::updateMenu(void) */ if (sym && list->rootEntry == menu) break; - setPixmap(promptColIdx, list->menuPix); + setIcon(promptColIdx, menuIcon); } else { if (sym) break; - setPixmap(promptColIdx, QIcon()); + setIcon(promptColIdx, QIcon()); } goto set_prompt; case P_COMMENT: - setPixmap(promptColIdx, QIcon()); + setIcon(promptColIdx, QIcon()); + prompt = "*** " + prompt + " ***"; goto set_prompt; default: ; @@ -144,7 +130,7 @@ void ConfigItem::updateMenu(void) if (!sym) goto set_prompt; - setText(nameColIdx, QString::fromLocal8Bit(sym->name)); + setText(nameColIdx, sym->name); type = sym_get_type(sym); switch (type) { @@ -153,57 +139,37 @@ void ConfigItem::updateMenu(void) char ch; if (!sym_is_changeable(sym) && list->optMode == normalOpt) { - setPixmap(promptColIdx, QIcon()); - setText(noColIdx, QString::null); - setText(modColIdx, QString::null); - setText(yesColIdx, QString::null); + setIcon(promptColIdx, QIcon()); break; } expr = sym_get_tristate_value(sym); switch (expr) { case yes: if (sym_is_choice_value(sym) && type == S_BOOLEAN) - setPixmap(promptColIdx, list->choiceYesPix); + setIcon(promptColIdx, choiceYesIcon); else - setPixmap(promptColIdx, list->symbolYesPix); - setText(yesColIdx, "Y"); + setIcon(promptColIdx, symbolYesIcon); ch = 'Y'; break; case mod: - setPixmap(promptColIdx, list->symbolModPix); - setText(modColIdx, "M"); + setIcon(promptColIdx, symbolModIcon); ch = 'M'; break; default: if (sym_is_choice_value(sym) && type == S_BOOLEAN) - setPixmap(promptColIdx, list->choiceNoPix); + setIcon(promptColIdx, choiceNoIcon); else - setPixmap(promptColIdx, list->symbolNoPix); - setText(noColIdx, "N"); + setIcon(promptColIdx, symbolNoIcon); ch = 'N'; break; } - if (expr != no) - setText(noColIdx, sym_tristate_within_range(sym, no) ? "_" : 0); - if (expr != mod) - setText(modColIdx, sym_tristate_within_range(sym, mod) ? "_" : 0); - if (expr != yes) - setText(yesColIdx, sym_tristate_within_range(sym, yes) ? "_" : 0); setText(dataColIdx, QChar(ch)); break; case S_INT: case S_HEX: case S_STRING: - const char* data; - - data = sym_get_string_value(sym); - - setText(dataColIdx, data); - if (type == S_STRING) - prompt = QString("%1: %2").arg(prompt).arg(data); - else - prompt = QString("(%2) %1").arg(prompt).arg(data); + setText(dataColIdx, sym_get_string_value(sym)); break; } if (!sym_has_value(sym) && visible) @@ -244,6 +210,17 @@ void ConfigItem::init(void) if (list->mode != fullMode) setExpanded(true); sym_calc_value(menu->sym); + + if (menu->sym) { + enum symbol_type type = menu->sym->type; + + // Allow to edit "int", "hex", and "string" in-place in + // the data column. Unfortunately, you cannot specify + // the flags per column. Set ItemIsEditable for all + // columns here, and check the column in createEditor(). + if (type == S_INT || type == S_HEX || type == S_STRING) + setFlags(flags() | Qt::ItemIsEditable); + } } updateMenu(); } @@ -264,53 +241,67 @@ ConfigItem::~ConfigItem(void) } } -ConfigLineEdit::ConfigLineEdit(ConfigView* parent) - : Parent(parent) +QWidget *ConfigItemDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const { - connect(this, SIGNAL(editingFinished()), SLOT(hide())); -} + ConfigItem *item; -void ConfigLineEdit::show(ConfigItem* i) -{ - item = i; - if (sym_get_string_value(item->menu->sym)) - setText(QString::fromLocal8Bit(sym_get_string_value(item->menu->sym))); - else - setText(QString::null); - Parent::show(); - setFocus(); + // Only the data column is editable + if (index.column() != dataColIdx) + return nullptr; + + // You cannot edit invisible menus + item = static_cast<ConfigItem *>(index.internalPointer()); + if (!item || !item->menu || !menu_is_visible(item->menu)) + return nullptr; + + return QStyledItemDelegate::createEditor(parent, option, index); } -void ConfigLineEdit::keyPressEvent(QKeyEvent* e) +void ConfigItemDelegate::setModelData(QWidget *editor, + QAbstractItemModel *model, + const QModelIndex &index) const { - switch (e->key()) { - case Qt::Key_Escape: - break; - case Qt::Key_Return: - case Qt::Key_Enter: - sym_set_string_value(item->menu->sym, text().toLatin1()); - parent()->updateList(item); - break; - default: - Parent::keyPressEvent(e); - return; + QLineEdit *lineEdit; + ConfigItem *item; + struct symbol *sym; + bool success; + + lineEdit = qobject_cast<QLineEdit *>(editor); + // If this is not a QLineEdit, use the parent's default. + // (does this happen?) + if (!lineEdit) + goto parent; + + item = static_cast<ConfigItem *>(index.internalPointer()); + if (!item || !item->menu) + goto parent; + + sym = item->menu->sym; + if (!sym) + goto parent; + + success = sym_set_string_value(sym, lineEdit->text().toUtf8().data()); + if (success) { + ConfigList::updateListForAll(); + } else { + QMessageBox::information(editor, "qconf", + "Cannot set the data (maybe due to out of range).\n" + "Setting the old value."); + lineEdit->setText(sym_get_string_value(sym)); } - e->accept(); - parent()->list->setFocus(); - hide(); + +parent: + QStyledItemDelegate::setModelData(editor, model, index); } -ConfigList::ConfigList(ConfigView* p, const char *name) - : Parent(p), +ConfigList::ConfigList(QWidget *parent, const char *name) + : QTreeWidget(parent), updateAll(false), - symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), - choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), - menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), - showName(false), showRange(false), showData(false), mode(singleMode), optMode(normalOpt), + showName(false), mode(singleMode), optMode(normalOpt), rootEntry(0), headerPopup(0) { - int i; - setObjectName(name); setSortingEnabled(false); setRootIsDecorated(true); @@ -318,26 +309,34 @@ ConfigList::ConfigList(ConfigView* p, const char *name) setVerticalScrollMode(ScrollPerPixel); setHorizontalScrollMode(ScrollPerPixel); - setHeaderLabels(QStringList() << "Option" << "Name" << "N" << "M" << "Y" << "Value"); + setHeaderLabels(QStringList() << "Option" << "Name" << "Value"); - connect(this, SIGNAL(itemSelectionChanged(void)), - SLOT(updateSelection(void))); + connect(this, &ConfigList::itemSelectionChanged, + this, &ConfigList::updateSelection); if (name) { configSettings->beginGroup(name); showName = configSettings->value("/showName", false).toBool(); - showRange = configSettings->value("/showRange", false).toBool(); - showData = configSettings->value("/showData", false).toBool(); optMode = (enum optionMode)configSettings->value("/optionMode", 0).toInt(); configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + connect(configApp, &QApplication::aboutToQuit, + this, &ConfigList::saveSettings); } - addColumn(promptColIdx); + showColumn(promptColIdx); + + setItemDelegate(new ConfigItemDelegate(this)); + + allLists.append(this); reinit(); } +ConfigList::~ConfigList() +{ + allLists.removeOne(this); +} + bool ConfigList::menuSkip(struct menu *menu) { if (optMode == normalOpt && menu_is_visible(menu)) @@ -351,21 +350,22 @@ bool ConfigList::menuSkip(struct menu *menu) void ConfigList::reinit(void) { - removeColumn(dataColIdx); - removeColumn(yesColIdx); - removeColumn(modColIdx); - removeColumn(noColIdx); - removeColumn(nameColIdx); + hideColumn(nameColIdx); if (showName) - addColumn(nameColIdx); - if (showRange) { - addColumn(noColIdx); - addColumn(modColIdx); - addColumn(yesColIdx); - } - if (showData) - addColumn(dataColIdx); + showColumn(nameColIdx); + + updateListAll(); +} + +void ConfigList::setOptionMode(QAction *action) +{ + if (action == showNormalAction) + optMode = normalOpt; + else if (action == showAllAction) + optMode = allOpt; + else + optMode = promptOpt; updateListAll(); } @@ -375,8 +375,6 @@ void ConfigList::saveSettings(void) if (!objectName().isEmpty()) { configSettings->beginGroup(objectName()); configSettings->setValue("/showName", showName); - configSettings->setValue("/showRange", showRange); - configSettings->setValue("/showData", showData); configSettings->setValue("/optionMode", (int)optMode); configSettings->endGroup(); } @@ -415,15 +413,15 @@ void ConfigList::updateSelection(void) emit menuSelected(menu); } -void ConfigList::updateList(ConfigItem* item) +void ConfigList::updateList() { ConfigItem* last = 0; + ConfigItem *item; if (!rootEntry) { if (mode != listMode) goto update; QTreeWidgetItemIterator it(this); - ConfigItem* item; while (*it) { item = (ConfigItem*)(*it); @@ -445,7 +443,7 @@ void ConfigList::updateList(ConfigItem* item) } if ((mode == singleMode || (mode == symbolMode && !(rootEntry->flags & MENU_ROOT))) && rootEntry->sym && rootEntry->prompt) { - item = last ? last->nextSibling() : firstChild(); + item = last ? last->nextSibling() : nullptr; if (!item) item = new ConfigItem(this, last, rootEntry, true); else @@ -457,11 +455,33 @@ void ConfigList::updateList(ConfigItem* item) return; } update: - updateMenuList(this, rootEntry); + updateMenuList(rootEntry); update(); resizeColumnToContents(0); } +void ConfigList::updateListForAll() +{ + QListIterator<ConfigList *> it(allLists); + + while (it.hasNext()) { + ConfigList *list = it.next(); + + list->updateList(); + } +} + +void ConfigList::updateListAllForAll() +{ + QListIterator<ConfigList *> it(allLists); + + while (it.hasNext()) { + ConfigList *list = it.next(); + + list->updateList(); + } +} + void ConfigList::setValue(ConfigItem* item, tristate val) { struct symbol* sym; @@ -482,7 +502,7 @@ void ConfigList::setValue(ConfigItem* item, tristate val) return; if (oldval == no && item->menu->list) item->setExpanded(true); - parent()->updateList(item); + ConfigList::updateListForAll(); break; } } @@ -516,12 +536,9 @@ void ConfigList::changeValue(ConfigItem* item) item->setExpanded(true); } if (oldexpr != newexpr) - parent()->updateList(item); + ConfigList::updateListForAll(); break; - case S_INT: - case S_HEX: - case S_STRING: - parent()->lineEdit->show(item); + default: break; } } @@ -535,11 +552,11 @@ void ConfigList::setRootMenu(struct menu *menu) type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; if (type != P_MENU) return; - updateMenuList(this, 0); + updateMenuList(0); rootEntry = menu; updateListAll(); if (currentItem()) { - currentItem()->setSelected(hasFocus()); + setSelected(currentItem(), hasFocus()); scrollToItem(currentItem()); } } @@ -627,7 +644,7 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu) last = item; continue; } - hide: +hide: if (item && item->menu == child) { last = parent->firstChild(); if (last == item) @@ -639,7 +656,7 @@ void ConfigList::updateMenuList(ConfigItem *parent, struct menu* menu) } } -void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu) +void ConfigList::updateMenuList(struct menu *menu) { struct menu* child; ConfigItem* item; @@ -648,19 +665,19 @@ void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu) enum prop_type type; if (!menu) { - while (parent->topLevelItemCount() > 0) + while (topLevelItemCount() > 0) { - delete parent->takeTopLevelItem(0); + delete takeTopLevelItem(0); } return; } - last = (ConfigItem*)parent->topLevelItem(0); + last = (ConfigItem *)topLevelItem(0); if (last && !last->goParent) last = 0; for (child = menu->list; child; child = child->next) { - item = last ? last->nextSibling() : (ConfigItem*)parent->topLevelItem(0); + item = last ? last->nextSibling() : (ConfigItem *)topLevelItem(0); type = child->prompt ? child->prompt->type : P_UNKNOWN; switch (mode) { @@ -681,7 +698,7 @@ void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu) if (!child->sym && !child->list && !child->prompt) continue; if (!item || item->menu != child) - item = new ConfigItem(parent, last, child, visible); + item = new ConfigItem(this, last, child, visible); else item->testUpdateMenu(visible); @@ -692,9 +709,9 @@ void ConfigList::updateMenuList(ConfigList *parent, struct menu* menu) last = item; continue; } - hide: +hide: if (item && item->menu == child) { - last = (ConfigItem*)parent->topLevelItem(0); + last = (ConfigItem *)topLevelItem(0); if (last == item) last = 0; else while (last->nextSibling() != item) @@ -736,7 +753,10 @@ void ConfigList::keyPressEvent(QKeyEvent* ev) type = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (type == P_MENU && rootEntry != menu && mode != fullMode && mode != menuMode) { - emit menuSelected(menu); + if (mode == menuMode) + emit menuSelected(menu); + else + emit itemSelected(menu); break; } case Qt::Key_Space: @@ -782,7 +802,7 @@ void ConfigList::mouseReleaseEvent(QMouseEvent* e) idx = header()->logicalIndexAt(x); switch (idx) { case promptColIdx: - icon = item->pixmap(promptColIdx); + icon = item->icon(promptColIdx); if (!icon.isNull()) { int off = header()->sectionPosition(0) + visualRect(indexAt(p)).x() + 4; // 4 is Hardcoded image offset. There might be a way to do it properly. if (x >= off && x < off + icon.availableSizes().first().width()) { @@ -793,22 +813,14 @@ void ConfigList::mouseReleaseEvent(QMouseEvent* e) break; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; if (ptype == P_MENU && rootEntry != menu && - mode != fullMode && mode != menuMode) + mode != fullMode && mode != menuMode && + mode != listMode) emit menuSelected(menu); else changeValue(item); } } break; - case noColIdx: - setValue(item, no); - break; - case modColIdx: - setValue(item, mod); - break; - case yesColIdx: - setValue(item, yes); - break; case dataColIdx: changeValue(item); break; @@ -828,7 +840,7 @@ void ConfigList::mouseMoveEvent(QMouseEvent* e) void ConfigList::mouseDoubleClickEvent(QMouseEvent* e) { - QPoint p = e->pos(); // TODO: Check if this works(was contentsToViewport). + QPoint p = e->pos(); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; enum prop_type ptype; @@ -843,9 +855,12 @@ void ConfigList::mouseDoubleClickEvent(QMouseEvent* e) if (!menu) goto skip; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) - emit menuSelected(menu); - else if (menu->sym) + if (ptype == P_MENU && mode != listMode) { + if (mode == singleMode) + emit itemSelected(menu); + else if (mode == symbolMode) + emit menuSelected(menu); + } else if (menu->sym) changeValue(item); skip: @@ -861,7 +876,7 @@ void ConfigList::focusInEvent(QFocusEvent *e) ConfigItem* item = (ConfigItem *)currentItem(); if (item) { - item->setSelected(true); + setSelected(item, true); menu = item->menu; } emit gotFocus(menu); @@ -869,114 +884,38 @@ void ConfigList::focusInEvent(QFocusEvent *e) void ConfigList::contextMenuEvent(QContextMenuEvent *e) { - if (e->y() <= header()->geometry().bottom()) { - if (!headerPopup) { - QAction *action; - - headerPopup = new QMenu(this); - action = new QAction("Show Name", this); - action->setCheckable(true); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowName(bool))); - connect(parent(), SIGNAL(showNameChanged(bool)), - action, SLOT(setOn(bool))); - action->setChecked(showName); - headerPopup->addAction(action); - action = new QAction("Show Range", this); - action->setCheckable(true); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowRange(bool))); - connect(parent(), SIGNAL(showRangeChanged(bool)), - action, SLOT(setOn(bool))); - action->setChecked(showRange); - headerPopup->addAction(action); - action = new QAction("Show Data", this); - action->setCheckable(true); - connect(action, SIGNAL(toggled(bool)), - parent(), SLOT(setShowData(bool))); - connect(parent(), SIGNAL(showDataChanged(bool)), - action, SLOT(setOn(bool))); - action->setChecked(showData); - headerPopup->addAction(action); - } - headerPopup->exec(e->globalPos()); - e->accept(); - } else - e->ignore(); -} - -ConfigView*ConfigView::viewList; -QAction *ConfigView::showNormalAction; -QAction *ConfigView::showAllAction; -QAction *ConfigView::showPromptAction; - -ConfigView::ConfigView(QWidget* parent, const char *name) - : Parent(parent) -{ - setObjectName(name); - QVBoxLayout *verticalLayout = new QVBoxLayout(this); - verticalLayout->setContentsMargins(0, 0, 0, 0); - - list = new ConfigList(this); - verticalLayout->addWidget(list); - lineEdit = new ConfigLineEdit(this); - lineEdit->hide(); - verticalLayout->addWidget(lineEdit); - - this->nextView = viewList; - viewList = this; -} - -ConfigView::~ConfigView(void) -{ - ConfigView** vp; - - for (vp = &viewList; *vp; vp = &(*vp)->nextView) { - if (*vp == this) { - *vp = nextView; - break; - } + if (!headerPopup) { + QAction *action; + + headerPopup = new QMenu(this); + action = new QAction("Show Name", this); + action->setCheckable(true); + connect(action, &QAction::toggled, + this, &ConfigList::setShowName); + connect(this, &ConfigList::showNameChanged, + action, &QAction::setChecked); + action->setChecked(showName); + headerPopup->addAction(action); } -} -void ConfigView::setOptionMode(QAction *act) -{ - if (act == showNormalAction) - list->optMode = normalOpt; - else if (act == showAllAction) - list->optMode = allOpt; - else - list->optMode = promptOpt; - - list->updateListAll(); + headerPopup->exec(e->globalPos()); + e->accept(); } -void ConfigView::setShowName(bool b) +void ConfigList::setShowName(bool on) { - if (list->showName != b) { - list->showName = b; - list->reinit(); - emit showNameChanged(b); - } -} + if (showName == on) + return; -void ConfigView::setShowRange(bool b) -{ - if (list->showRange != b) { - list->showRange = b; - list->reinit(); - emit showRangeChanged(b); - } + showName = on; + reinit(); + emit showNameChanged(on); } -void ConfigView::setShowData(bool b) -{ - if (list->showData != b) { - list->showData = b; - list->reinit(); - emit showDataChanged(b); - } -} +QList<ConfigList *> ConfigList::allLists; +QAction *ConfigList::showNormalAction; +QAction *ConfigList::showAllAction; +QAction *ConfigList::showPromptAction; void ConfigList::setAllOpen(bool open) { @@ -989,34 +928,31 @@ void ConfigList::setAllOpen(bool open) } } -void ConfigView::updateList(ConfigItem* item) -{ - ConfigView* v; - - for (v = viewList; v; v = v->nextView) - v->list->updateList(item); -} - -void ConfigView::updateListAll(void) -{ - ConfigView* v; - - for (v = viewList; v; v = v->nextView) - v->list->updateListAll(); -} - ConfigInfoView::ConfigInfoView(QWidget* parent, const char *name) : Parent(parent), sym(0), _menu(0) { setObjectName(name); - + setOpenLinks(false); if (!objectName().isEmpty()) { configSettings->beginGroup(objectName()); setShowDebug(configSettings->value("/showDebug", false).toBool()); configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); + connect(configApp, &QApplication::aboutToQuit, + this, &ConfigInfoView::saveSettings); } + + contextMenu = createStandardContextMenu(); + QAction *action = new QAction("Show Debug Info", contextMenu); + + action->setCheckable(true); + connect(action, &QAction::toggled, + this, &ConfigInfoView::setShowDebug); + connect(this, &ConfigInfoView::showDebugChanged, + action, &QAction::setChecked); + action->setChecked(showDebug()); + contextMenu->addSeparator(); + contextMenu->addAction(action); } void ConfigInfoView::saveSettings(void) @@ -1071,108 +1007,119 @@ void ConfigInfoView::symbolInfo(void) void ConfigInfoView::menuInfo(void) { struct symbol* sym; - QString head, debug, help; + QString info; + QTextStream stream(&info); sym = _menu->sym; if (sym) { if (_menu->prompt) { - head += "<big><b>"; - head += print_filter(_menu->prompt->text); - head += "</b></big>"; + stream << "<big><b>"; + stream << print_filter(_menu->prompt->text); + stream << "</b></big>"; if (sym->name) { - head += " ("; + stream << " ("; if (showDebug()) - head += QString().sprintf("<a href=\"s%p\">", sym); - head += print_filter(sym->name); + stream << "<a href=\"s" << sym->name << "\">"; + stream << print_filter(sym->name); if (showDebug()) - head += "</a>"; - head += ")"; + stream << "</a>"; + stream << ")"; } } else if (sym->name) { - head += "<big><b>"; + stream << "<big><b>"; if (showDebug()) - head += QString().sprintf("<a href=\"s%p\">", sym); - head += print_filter(sym->name); + stream << "<a href=\"s" << sym->name << "\">"; + stream << print_filter(sym->name); if (showDebug()) - head += "</a>"; - head += "</b></big>"; + stream << "</a>"; + stream << "</b></big>"; } - head += "<br><br>"; + stream << "<br><br>"; if (showDebug()) - debug = debug_info(sym); + stream << debug_info(sym); struct gstr help_gstr = str_new(); + menu_get_ext_help(_menu, &help_gstr); - help = print_filter(str_get(&help_gstr)); + stream << print_filter(str_get(&help_gstr)); str_free(&help_gstr); } else if (_menu->prompt) { - head += "<big><b>"; - head += print_filter(_menu->prompt->text); - head += "</b></big><br><br>"; + stream << "<big><b>"; + stream << print_filter(_menu->prompt->text); + stream << "</b></big><br><br>"; if (showDebug()) { if (_menu->prompt->visible.expr) { - debug += " dep: "; - expr_print(_menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); - debug += "<br><br>"; + stream << " dep: "; + expr_print(_menu->prompt->visible.expr, + expr_print_help, &stream, E_NONE); + stream << "<br><br>"; } + + stream << "defined at " << _menu->file->name << ":" + << _menu->lineno << "<br><br>"; } } - if (showDebug()) - debug += QString().sprintf("defined at %s:%d<br><br>", _menu->file->name, _menu->lineno); - setText(head + debug + help); + setText(info); } QString ConfigInfoView::debug_info(struct symbol *sym) { QString debug; + QTextStream stream(&debug); - debug += "type: "; - debug += print_filter(sym_type_name(sym->type)); + stream << "type: "; + stream << print_filter(sym_type_name(sym->type)); if (sym_is_choice(sym)) - debug += " (choice)"; + stream << " (choice)"; debug += "<br>"; if (sym->rev_dep.expr) { - debug += "reverse dep: "; - expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; + stream << "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &stream, E_NONE); + stream << "<br>"; } for (struct property *prop = sym->prop; prop; prop = prop->next) { switch (prop->type) { case P_PROMPT: case P_MENU: - debug += QString().sprintf("prompt: <a href=\"m%p\">", prop->menu); - debug += print_filter(prop->text); - debug += "</a><br>"; + stream << "prompt: <a href=\"m" << sym->name << "\">"; + stream << print_filter(prop->text); + stream << "</a><br>"; break; case P_DEFAULT: case P_SELECT: case P_RANGE: - debug += prop_get_type_name(prop->type); - debug += ": "; - expr_print(prop->expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; + case P_COMMENT: + case P_IMPLY: + case P_SYMBOL: + stream << prop_get_type_name(prop->type); + stream << ": "; + expr_print(prop->expr, expr_print_help, + &stream, E_NONE); + stream << "<br>"; break; case P_CHOICE: if (sym_is_choice(sym)) { - debug += "choice: "; - expr_print(prop->expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; + stream << "choice: "; + expr_print(prop->expr, expr_print_help, + &stream, E_NONE); + stream << "<br>"; } break; default: - debug += "unknown property: "; - debug += prop_get_type_name(prop->type); - debug += "<br>"; + stream << "unknown property: "; + stream << prop_get_type_name(prop->type); + stream << "<br>"; } if (prop->visible.expr) { - debug += " dep: "; - expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; + stream << " dep: "; + expr_print(prop->visible.expr, expr_print_help, + &stream, E_NONE); + stream << "<br>"; } } - debug += "<br>"; + stream << "<br>"; return debug; } @@ -1210,88 +1157,125 @@ QString ConfigInfoView::print_filter(const QString &str) void ConfigInfoView::expr_print_help(void *data, struct symbol *sym, const char *str) { - QString* text = reinterpret_cast<QString*>(data); - QString str2 = print_filter(str); + QTextStream *stream = reinterpret_cast<QTextStream *>(data); if (sym && sym->name && !(sym->flags & SYMBOL_CONST)) { - *text += QString().sprintf("<a href=\"s%p\">", sym); - *text += str2; - *text += "</a>"; - } else - *text += str2; + *stream << "<a href=\"s" << sym->name << "\">"; + *stream << print_filter(str); + *stream << "</a>"; + } else { + *stream << print_filter(str); + } } -QMenu* ConfigInfoView::createStandardContextMenu(const QPoint & pos) +void ConfigInfoView::clicked(const QUrl &url) { - QMenu* popup = Parent::createStandardContextMenu(pos); - QAction* action = new QAction("Show Debug Info", popup); - action->setCheckable(true); - connect(action, SIGNAL(toggled(bool)), SLOT(setShowDebug(bool))); - connect(this, SIGNAL(showDebugChanged(bool)), action, SLOT(setOn(bool))); - action->setChecked(showDebug()); - popup->addSeparator(); - popup->addAction(action); - return popup; + QByteArray str = url.toEncoded(); + const std::size_t count = str.size(); + char *data = new char[count + 1]; + struct symbol **result; + struct menu *m = NULL; + + if (count < 1) { + delete[] data; + return; + } + + memcpy(data, str.constData(), count); + data[count] = '\0'; + + /* Seek for exact match */ + data[0] = '^'; + strcat(data, "$"); + result = sym_re_search(data); + if (!result) { + delete[] data; + return; + } + + sym = *result; + + /* Seek for the menu which holds the symbol */ + for (struct property *prop = sym->prop; prop; prop = prop->next) { + if (prop->type != P_PROMPT && prop->type != P_MENU) + continue; + m = prop->menu; + break; + } + + if (!m) { + /* Symbol is not visible as a menu */ + symbolInfo(); + emit showDebugChanged(true); + } else { + emit menuSelected(m); + } + + free(result); + delete[] data; } -void ConfigInfoView::contextMenuEvent(QContextMenuEvent *e) +void ConfigInfoView::contextMenuEvent(QContextMenuEvent *event) { - Parent::contextMenuEvent(e); + contextMenu->popup(event->globalPos()); + event->accept(); } -ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow* parent, const char *name) +ConfigSearchWindow::ConfigSearchWindow(ConfigMainWindow *parent) : Parent(parent), result(NULL) { - setObjectName(name); + setObjectName("search"); setWindowTitle("Search Config"); QVBoxLayout* layout1 = new QVBoxLayout(this); layout1->setContentsMargins(11, 11, 11, 11); layout1->setSpacing(6); - QHBoxLayout* layout2 = new QHBoxLayout(0); + + QHBoxLayout* layout2 = new QHBoxLayout(); layout2->setContentsMargins(0, 0, 0, 0); layout2->setSpacing(6); layout2->addWidget(new QLabel("Find:", this)); editField = new QLineEdit(this); - connect(editField, SIGNAL(returnPressed()), SLOT(search())); + connect(editField, &QLineEdit::returnPressed, + this, &ConfigSearchWindow::search); layout2->addWidget(editField); searchButton = new QPushButton("Search", this); searchButton->setAutoDefault(false); - connect(searchButton, SIGNAL(clicked()), SLOT(search())); + connect(searchButton, &QPushButton::clicked, + this, &ConfigSearchWindow::search); layout2->addWidget(searchButton); layout1->addLayout(layout2); split = new QSplitter(this); split->setOrientation(Qt::Vertical); - list = new ConfigView(split, name); - list->list->mode = listMode; - info = new ConfigInfoView(split, name); - connect(list->list, SIGNAL(menuChanged(struct menu *)), - info, SLOT(setInfo(struct menu *))); - connect(list->list, SIGNAL(menuChanged(struct menu *)), - parent, SLOT(setMenuLink(struct menu *))); + list = new ConfigList(split, "search"); + list->mode = listMode; + info = new ConfigInfoView(split, "search"); + connect(list, &ConfigList::menuChanged, + info, &ConfigInfoView::setInfo); + connect(list, &ConfigList::menuChanged, + parent, &ConfigMainWindow::setMenuLink); layout1->addWidget(split); - if (name) { - QVariant x, y; - int width, height; - bool ok; + QVariant x, y; + int width, height; + bool ok; - configSettings->beginGroup(name); - width = configSettings->value("/window width", parent->width() / 2).toInt(); - height = configSettings->value("/window height", parent->height() / 2).toInt(); - resize(width, height); - x = configSettings->value("/window x"); - y = configSettings->value("/window y"); - if ((x.isValid())&&(y.isValid())) - move(x.toInt(), y.toInt()); - QList<int> sizes = configSettings->readSizes("/split", &ok); - if (ok) - split->setSizes(sizes); - configSettings->endGroup(); - connect(configApp, SIGNAL(aboutToQuit()), SLOT(saveSettings())); - } + configSettings->beginGroup("search"); + width = configSettings->value("/window width", parent->width() / 2).toInt(); + height = configSettings->value("/window height", parent->height() / 2).toInt(); + resize(width, height); + x = configSettings->value("/window x"); + y = configSettings->value("/window y"); + if (x.isValid() && y.isValid()) + move(x.toInt(), y.toInt()); + QList<int> sizes = configSettings->readSizes("/split", &ok); + if (ok) + split->setSizes(sizes); + configSettings->endGroup(); + connect(configApp, &QApplication::aboutToQuit, + this, &ConfigSearchWindow::saveSettings); } void ConfigSearchWindow::saveSettings(void) @@ -1314,7 +1298,7 @@ void ConfigSearchWindow::search(void) ConfigItem *lastItem = NULL; free(result); - list->list->clear(); + list->clear(); info->clear(); result = sym_re_search(editField->text().toLatin1()); @@ -1322,7 +1306,7 @@ void ConfigSearchWindow::search(void) return; for (p = result; *p; p++) { for_all_prompts((*p), prop) - lastItem = new ConfigItem(list->list, lastItem, prop->menu, + lastItem = new ConfigItem(list, lastItem, prop->menu, menu_is_visible(prop->menu)); } } @@ -1333,7 +1317,6 @@ void ConfigSearchWindow::search(void) ConfigMainWindow::ConfigMainWindow(void) : searchWindow(0) { - QMenuBar* menu; bool ok = true; QVariant x, y; int width, height; @@ -1354,97 +1337,123 @@ ConfigMainWindow::ConfigMainWindow(void) if ((x.isValid())&&(y.isValid())) move(x.toInt(), y.toInt()); - split1 = new QSplitter(this); + // set up icons + ConfigItem::symbolYesIcon = QIcon(QPixmap(xpm_symbol_yes)); + ConfigItem::symbolModIcon = QIcon(QPixmap(xpm_symbol_mod)); + ConfigItem::symbolNoIcon = QIcon(QPixmap(xpm_symbol_no)); + ConfigItem::choiceYesIcon = QIcon(QPixmap(xpm_choice_yes)); + ConfigItem::choiceNoIcon = QIcon(QPixmap(xpm_choice_no)); + ConfigItem::menuIcon = QIcon(QPixmap(xpm_menu)); + ConfigItem::menubackIcon = QIcon(QPixmap(xpm_menuback)); + + QWidget *widget = new QWidget(this); + QVBoxLayout *layout = new QVBoxLayout(widget); + setCentralWidget(widget); + + split1 = new QSplitter(widget); split1->setOrientation(Qt::Horizontal); - setCentralWidget(split1); + split1->setChildrenCollapsible(false); - menuView = new ConfigView(split1, "menu"); - menuList = menuView->list; + menuList = new ConfigList(widget, "menu"); - split2 = new QSplitter(split1); + split2 = new QSplitter(widget); + split2->setChildrenCollapsible(false); split2->setOrientation(Qt::Vertical); // create config tree - configView = new ConfigView(split2, "config"); - configList = configView->list; + configList = new ConfigList(widget, "config"); + + helpText = new ConfigInfoView(widget, "help"); - helpText = new ConfigInfoView(split2, "help"); + layout->addWidget(split2); + split2->addWidget(split1); + split1->addWidget(configList); + split1->addWidget(menuList); + split2->addWidget(helpText); setTabOrder(configList, helpText); configList->setFocus(); - menu = menuBar(); - toolBar = new QToolBar("Tools", this); - addToolBar(toolBar); - backAction = new QAction(QPixmap(xpm_back), "Back", this); - connect(backAction, SIGNAL(triggered(bool)), SLOT(goBack())); - backAction->setEnabled(false); + connect(backAction, &QAction::triggered, + this, &ConfigMainWindow::goBack); + QAction *quitAction = new QAction("&Quit", this); quitAction->setShortcut(Qt::CTRL + Qt::Key_Q); - connect(quitAction, SIGNAL(triggered(bool)), SLOT(close())); + connect(quitAction, &QAction::triggered, + this, &ConfigMainWindow::close); + QAction *loadAction = new QAction(QPixmap(xpm_load), "&Load", this); loadAction->setShortcut(Qt::CTRL + Qt::Key_L); - connect(loadAction, SIGNAL(triggered(bool)), SLOT(loadConfig())); + connect(loadAction, &QAction::triggered, + this, &ConfigMainWindow::loadConfig); + saveAction = new QAction(QPixmap(xpm_save), "&Save", this); saveAction->setShortcut(Qt::CTRL + Qt::Key_S); - connect(saveAction, SIGNAL(triggered(bool)), SLOT(saveConfig())); + connect(saveAction, &QAction::triggered, + this, &ConfigMainWindow::saveConfig); + conf_set_changed_callback(conf_changed); + // Set saveAction's initial state conf_changed(); configname = xstrdup(conf_get_configname()); QAction *saveAsAction = new QAction("Save &As...", this); - connect(saveAsAction, SIGNAL(triggered(bool)), SLOT(saveConfigAs())); + connect(saveAsAction, &QAction::triggered, + this, &ConfigMainWindow::saveConfigAs); QAction *searchAction = new QAction("&Find", this); searchAction->setShortcut(Qt::CTRL + Qt::Key_F); - connect(searchAction, SIGNAL(triggered(bool)), SLOT(searchConfig())); + connect(searchAction, &QAction::triggered, + this, &ConfigMainWindow::searchConfig); singleViewAction = new QAction(QPixmap(xpm_single_view), "Single View", this); singleViewAction->setCheckable(true); - connect(singleViewAction, SIGNAL(triggered(bool)), SLOT(showSingleView())); + connect(singleViewAction, &QAction::triggered, + this, &ConfigMainWindow::showSingleView); splitViewAction = new QAction(QPixmap(xpm_split_view), "Split View", this); splitViewAction->setCheckable(true); - connect(splitViewAction, SIGNAL(triggered(bool)), SLOT(showSplitView())); + connect(splitViewAction, &QAction::triggered, + this, &ConfigMainWindow::showSplitView); fullViewAction = new QAction(QPixmap(xpm_tree_view), "Full View", this); fullViewAction->setCheckable(true); - connect(fullViewAction, SIGNAL(triggered(bool)), SLOT(showFullView())); + connect(fullViewAction, &QAction::triggered, + this, &ConfigMainWindow::showFullView); QAction *showNameAction = new QAction("Show Name", this); showNameAction->setCheckable(true); - connect(showNameAction, SIGNAL(toggled(bool)), configView, SLOT(setShowName(bool))); - showNameAction->setChecked(configView->showName()); - QAction *showRangeAction = new QAction("Show Range", this); - showRangeAction->setCheckable(true); - connect(showRangeAction, SIGNAL(toggled(bool)), configView, SLOT(setShowRange(bool))); - QAction *showDataAction = new QAction("Show Data", this); - showDataAction->setCheckable(true); - connect(showDataAction, SIGNAL(toggled(bool)), configView, SLOT(setShowData(bool))); + connect(showNameAction, &QAction::toggled, + configList, &ConfigList::setShowName); + showNameAction->setChecked(configList->showName); QActionGroup *optGroup = new QActionGroup(this); optGroup->setExclusive(true); - connect(optGroup, SIGNAL(triggered(QAction*)), configView, - SLOT(setOptionMode(QAction *))); - connect(optGroup, SIGNAL(triggered(QAction *)), menuView, - SLOT(setOptionMode(QAction *))); - - configView->showNormalAction = new QAction("Show Normal Options", optGroup); - configView->showAllAction = new QAction("Show All Options", optGroup); - configView->showPromptAction = new QAction("Show Prompt Options", optGroup); - configView->showNormalAction->setCheckable(true); - configView->showAllAction->setCheckable(true); - configView->showPromptAction->setCheckable(true); + connect(optGroup, &QActionGroup::triggered, + configList, &ConfigList::setOptionMode); + connect(optGroup, &QActionGroup::triggered, + menuList, &ConfigList::setOptionMode); + + ConfigList::showNormalAction = new QAction("Show Normal Options", optGroup); + ConfigList::showNormalAction->setCheckable(true); + ConfigList::showAllAction = new QAction("Show All Options", optGroup); + ConfigList::showAllAction->setCheckable(true); + ConfigList::showPromptAction = new QAction("Show Prompt Options", optGroup); + ConfigList::showPromptAction->setCheckable(true); QAction *showDebugAction = new QAction("Show Debug Info", this); showDebugAction->setCheckable(true); - connect(showDebugAction, SIGNAL(toggled(bool)), helpText, SLOT(setShowDebug(bool))); + connect(showDebugAction, &QAction::toggled, + helpText, &ConfigInfoView::setShowDebug); showDebugAction->setChecked(helpText->showDebug()); QAction *showIntroAction = new QAction("Introduction", this); - connect(showIntroAction, SIGNAL(triggered(bool)), SLOT(showIntro())); + connect(showIntroAction, &QAction::triggered, + this, &ConfigMainWindow::showIntro); QAction *showAboutAction = new QAction("About", this); - connect(showAboutAction, SIGNAL(triggered(bool)), SLOT(showAbout())); + connect(showAboutAction, &QAction::triggered, + this, &ConfigMainWindow::showAbout); // init tool bar + QToolBar *toolBar = addToolBar("Tools"); toolBar->addAction(backAction); toolBar->addSeparator(); toolBar->addAction(loadAction); @@ -1454,53 +1463,55 @@ ConfigMainWindow::ConfigMainWindow(void) toolBar->addAction(splitViewAction); toolBar->addAction(fullViewAction); - // create config menu - QMenu* config = menu->addMenu("&File"); - config->addAction(loadAction); - config->addAction(saveAction); - config->addAction(saveAsAction); - config->addSeparator(); - config->addAction(quitAction); + // create file menu + QMenu *menu = menuBar()->addMenu("&File"); + menu->addAction(loadAction); + menu->addAction(saveAction); + menu->addAction(saveAsAction); + menu->addSeparator(); + menu->addAction(quitAction); // create edit menu - QMenu* editMenu = menu->addMenu("&Edit"); - editMenu->addAction(searchAction); + menu = menuBar()->addMenu("&Edit"); + menu->addAction(searchAction); // create options menu - QMenu* optionMenu = menu->addMenu("&Option"); - optionMenu->addAction(showNameAction); - optionMenu->addAction(showRangeAction); - optionMenu->addAction(showDataAction); - optionMenu->addSeparator(); - optionMenu->addActions(optGroup->actions()); - optionMenu->addSeparator(); - optionMenu->addAction(showDebugAction); + menu = menuBar()->addMenu("&Option"); + menu->addAction(showNameAction); + menu->addSeparator(); + menu->addActions(optGroup->actions()); + menu->addSeparator(); + menu->addAction(showDebugAction); // create help menu - menu->addSeparator(); - QMenu* helpMenu = menu->addMenu("&Help"); - helpMenu->addAction(showIntroAction); - helpMenu->addAction(showAboutAction); - - connect(configList, SIGNAL(menuChanged(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(configList, SIGNAL(menuSelected(struct menu *)), - SLOT(changeMenu(struct menu *))); - connect(configList, SIGNAL(parentSelected()), - SLOT(goBack())); - connect(menuList, SIGNAL(menuChanged(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(menuSelected(struct menu *)), - SLOT(changeMenu(struct menu *))); - - connect(configList, SIGNAL(gotFocus(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(gotFocus(struct menu *)), - helpText, SLOT(setInfo(struct menu *))); - connect(menuList, SIGNAL(gotFocus(struct menu *)), - SLOT(listFocusChanged(void))); - connect(helpText, SIGNAL(menuSelected(struct menu *)), - SLOT(setMenuLink(struct menu *))); + menu = menuBar()->addMenu("&Help"); + menu->addAction(showIntroAction); + menu->addAction(showAboutAction); + + connect(helpText, &ConfigInfoView::anchorClicked, + helpText, &ConfigInfoView::clicked); + + connect(configList, &ConfigList::menuChanged, + helpText, &ConfigInfoView::setInfo); + connect(configList, &ConfigList::menuSelected, + this, &ConfigMainWindow::changeMenu); + connect(configList, &ConfigList::itemSelected, + this, &ConfigMainWindow::changeItens); + connect(configList, &ConfigList::parentSelected, + this, &ConfigMainWindow::goBack); + connect(menuList, &ConfigList::menuChanged, + helpText, &ConfigInfoView::setInfo); + connect(menuList, &ConfigList::menuSelected, + this, &ConfigMainWindow::changeMenu); + + connect(configList, &ConfigList::gotFocus, + helpText, &ConfigInfoView::setInfo); + connect(menuList, &ConfigList::gotFocus, + helpText, &ConfigInfoView::setInfo); + connect(menuList, &ConfigList::gotFocus, + this, &ConfigMainWindow::listFocusChanged); + connect(helpText, &ConfigInfoView::menuSelected, + this, &ConfigMainWindow::setMenuLink); QString listMode = configSettings->value("/listMode", "symbol").toString(); if (listMode == "single") @@ -1539,7 +1550,7 @@ void ConfigMainWindow::loadConfig(void) free(configname); configname = xstrdup(name); - ConfigView::updateListAll(); + ConfigList::updateListAllForAll(); } bool ConfigMainWindow::saveConfig(void) @@ -1578,17 +1589,18 @@ void ConfigMainWindow::saveConfigAs(void) void ConfigMainWindow::searchConfig(void) { if (!searchWindow) - searchWindow = new ConfigSearchWindow(this, "search"); + searchWindow = new ConfigSearchWindow(this); searchWindow->show(); } -void ConfigMainWindow::changeMenu(struct menu *menu) +void ConfigMainWindow::changeItens(struct menu *menu) { configList->setRootMenu(menu); - if (configList->rootEntry->parent == &rootmenu) - backAction->setEnabled(false); - else - backAction->setEnabled(true); +} + +void ConfigMainWindow::changeMenu(struct menu *menu) +{ + menuList->setRootMenu(menu); } void ConfigMainWindow::setMenuLink(struct menu *menu) @@ -1608,22 +1620,26 @@ void ConfigMainWindow::setMenuLink(struct menu *menu) return; list->setRootMenu(parent); break; - case symbolMode: + case menuMode: if (menu->flags & MENU_ROOT) { - configList->setRootMenu(menu); + menuList->setRootMenu(menu); configList->clearSelection(); - list = menuList; - } else { list = configList; + } else { parent = menu_get_parent_menu(menu->parent); if (!parent) return; - item = menuList->findConfigItem(parent); + + /* Select the config view */ + item = configList->findConfigItem(parent); if (item) { - item->setSelected(true); - menuList->scrollToItem(item); + configList->setSelected(item, true); + configList->scrollToItem(item); } - list->setRootMenu(parent); + + menuList->setRootMenu(parent); + menuList->clearSelection(); + list = menuList; } break; case fullMode: @@ -1636,9 +1652,10 @@ void ConfigMainWindow::setMenuLink(struct menu *menu) if (list) { item = list->findConfigItem(menu); if (item) { - item->setSelected(true); + list->setSelected(item, true); list->scrollToItem(item); list->setFocus(); + helpText->setInfo(menu); } } } @@ -1651,25 +1668,10 @@ void ConfigMainWindow::listFocusChanged(void) void ConfigMainWindow::goBack(void) { - ConfigItem* item, *oldSelection; - - configList->setParentMenu(); if (configList->rootEntry == &rootmenu) - backAction->setEnabled(false); - - if (menuList->selectedItems().count() == 0) return; - item = (ConfigItem*)menuList->selectedItems().first(); - oldSelection = item; - while (item) { - if (item->menu == configList->rootEntry) { - oldSelection->setSelected(false); - item->setSelected(true); - break; - } - item = (ConfigItem*)item->parent(); - } + configList->setParentMenu(); } void ConfigMainWindow::showSingleView(void) @@ -1681,7 +1683,9 @@ void ConfigMainWindow::showSingleView(void) fullViewAction->setEnabled(true); fullViewAction->setChecked(false); - menuView->hide(); + backAction->setEnabled(true); + + menuList->hide(); menuList->setRootMenu(0); configList->mode = singleMode; if (configList->rootEntry == &rootmenu) @@ -1700,17 +1704,19 @@ void ConfigMainWindow::showSplitView(void) fullViewAction->setEnabled(true); fullViewAction->setChecked(false); - configList->mode = symbolMode; + backAction->setEnabled(false); + + configList->mode = menuMode; if (configList->rootEntry == &rootmenu) configList->updateListAll(); else configList->setRootMenu(&rootmenu); configList->setAllOpen(true); configApp->processEvents(); - menuList->mode = menuMode; + menuList->mode = symbolMode; menuList->setRootMenu(&rootmenu); menuList->setAllOpen(true); - menuView->show(); + menuList->show(); menuList->setFocus(); } @@ -1723,7 +1729,9 @@ void ConfigMainWindow::showFullView(void) fullViewAction->setEnabled(false); fullViewAction->setChecked(true); - menuView->hide(); + backAction->setEnabled(false); + + menuList->hide(); menuList->setRootMenu(0); configList->mode = fullMode; if (configList->rootEntry == &rootmenu) @@ -1735,7 +1743,6 @@ void ConfigMainWindow::showFullView(void) /* * ask for saving configuration before quitting - * TODO ask only when something changed */ void ConfigMainWindow::closeEvent(QCloseEvent* e) { @@ -1766,17 +1773,26 @@ void ConfigMainWindow::closeEvent(QCloseEvent* e) void ConfigMainWindow::showIntro(void) { - static const QString str = "Welcome to the qconf graphical configuration tool.\n\n" - "For each option, a blank box indicates the feature is disabled, a check\n" - "indicates it is enabled, and a dot indicates that it is to be compiled\n" - "as a module. Clicking on the box will cycle through the three states.\n\n" - "If you do not see an option (e.g., a device driver) that you believe\n" - "should be present, try turning on Show All Options under the Options menu.\n" - "Although there is no cross reference yet to help you figure out what other\n" - "options must be enabled to support the option you are interested in, you can\n" - "still view the help of a grayed-out option.\n\n" - "Toggling Show Debug Info under the Options menu will show the dependencies,\n" - "which you can then match by examining other options.\n\n"; + static const QString str = + "Welcome to the qconf graphical configuration tool.\n" + "\n" + "For bool and tristate options, a blank box indicates the " + "feature is disabled, a check indicates it is enabled, and a " + "dot indicates that it is to be compiled as a module. Clicking " + "on the box will cycle through the three states. For int, hex, " + "and string options, double-clicking or pressing F2 on the " + "Value cell will allow you to edit the value.\n" + "\n" + "If you do not see an option (e.g., a device driver) that you " + "believe should be present, try turning on Show All Options " + "under the Options menu. Enabling Show Debug Info will help you" + "figure out what other options must be enabled to support the " + "option you are interested in, and hyperlinks will navigate to " + "them.\n" + "\n" + "Toggling Show Debug Info under the Options menu will show the " + "dependencies, which you can then match by examining other " + "options.\n"; QMessageBox::information(this, "qconf", str); } @@ -1784,10 +1800,13 @@ void ConfigMainWindow::showIntro(void) void ConfigMainWindow::showAbout(void) { static const QString str = "qconf is Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>.\n" - "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n\n" - "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n"; + "Copyright (C) 2015 Boris Barbulovski <bbarbulovski@gmail.com>.\n" + "\n" + "Bug reports and feature request can also be entered at http://bugzilla.kernel.org/\n" + "\n" + "Qt Version: "; - QMessageBox::information(this, "qconf", str); + QMessageBox::information(this, "qconf", str + qVersion()); } void ConfigMainWindow::saveSettings(void) @@ -1856,7 +1875,6 @@ int main(int ac, char** av) const char *name; progname = av[0]; - configApp = new QApplication(ac, av); if (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { case 's': @@ -1877,6 +1895,8 @@ int main(int ac, char** av) conf_read(NULL); //zconfdump(stdout); + configApp = new QApplication(ac, av); + configSettings = new ConfigSettings(); configSettings->beginGroup("/kconfig/qconf"); v = new ConfigMainWindow(); diff --git a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h index 45bfe9b2b9..78b0a1dfcd 100644 --- a/scripts/kconfig/qconf.h +++ b/scripts/kconfig/qconf.h @@ -3,23 +3,22 @@ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */ -#include <QTextBrowser> -#include <QTreeWidget> -#include <QMainWindow> +#include <QCheckBox> +#include <QDialog> #include <QHeaderView> -#include <qsettings.h> +#include <QLineEdit> +#include <QMainWindow> #include <QPushButton> #include <QSettings> -#include <QLineEdit> #include <QSplitter> -#include <QCheckBox> -#include <QDialog> +#include <QStyledItemDelegate> +#include <QTextBrowser> +#include <QTreeWidget> + #include "expr.h" -class ConfigView; class ConfigList; class ConfigItem; -class ConfigLineEdit; class ConfigMainWindow; class ConfigSettings : public QSettings { @@ -30,7 +29,7 @@ public: }; enum colIdx { - promptColIdx, nameColIdx, noColIdx, modColIdx, yesColIdx, dataColIdx, colNr + promptColIdx, nameColIdx, dataColIdx }; enum listMode { singleMode, menuMode, symbolMode, fullMode, listMode @@ -43,13 +42,16 @@ class ConfigList : public QTreeWidget { Q_OBJECT typedef class QTreeWidget Parent; public: - ConfigList(ConfigView* p, const char *name = 0); + ConfigList(QWidget *parent, const char *name = 0); + ~ConfigList(); void reinit(void); - ConfigView* parent(void) const - { - return (ConfigView*)Parent::parent(); - } ConfigItem* findConfigItem(struct menu *); + void setSelected(QTreeWidgetItem *item, bool enable) { + for (int i = 0; i < selectedItems().size(); i++) + selectedItems().at(i)->setSelected(false); + + item->setSelected(enable); + } protected: void keyPressEvent(QKeyEvent *e); @@ -63,61 +65,52 @@ protected: public slots: void setRootMenu(struct menu *menu); - void updateList(ConfigItem *item); + void updateList(); void setValue(ConfigItem* item, tristate val); void changeValue(ConfigItem* item); void updateSelection(void); void saveSettings(void); + void setOptionMode(QAction *action); + void setShowName(bool on); + signals: void menuChanged(struct menu *menu); void menuSelected(struct menu *menu); + void itemSelected(struct menu *menu); void parentSelected(void); void gotFocus(struct menu *); + void showNameChanged(bool on); public: void updateListAll(void) { updateAll = true; - updateList(NULL); + updateList(); updateAll = false; } - ConfigList* listView() - { - return this; - } - ConfigItem* firstChild() const - { - return (ConfigItem *)children().first(); - } - void addColumn(colIdx idx) - { - showColumn(idx); - } - void removeColumn(colIdx idx) - { - hideColumn(idx); - } void setAllOpen(bool open); void setParentMenu(void); bool menuSkip(struct menu *); void updateMenuList(ConfigItem *parent, struct menu*); - void updateMenuList(ConfigList *parent, struct menu*); + void updateMenuList(struct menu *menu); bool updateAll; - QPixmap symbolYesPix, symbolModPix, symbolNoPix; - QPixmap choiceYesPix, choiceNoPix; - QPixmap menuPix, menuInvPix, menuBackPix, voidPix; - - bool showName, showRange, showData; + bool showName; enum listMode mode; enum optionMode optMode; struct menu *rootEntry; QPalette disabledColorGroup; QPalette inactivedColorGroup; QMenu* headerPopup; + + static QList<ConfigList *> allLists; + static void updateListForAll(); + static void updateListAllForAll(); + + static QAction *showNormalAction, *showAllAction, *showPromptAction; }; class ConfigItem : public QTreeWidgetItem { @@ -140,7 +133,6 @@ public: } ~ConfigItem(void); void init(void); - void okRename(int col); void updateMenu(void); void testUpdateMenu(bool v); ConfigList* listView() const @@ -165,82 +157,36 @@ public: return ret; } - void setText(colIdx idx, const QString& text) - { - Parent::setText(idx, text); - } - QString text(colIdx idx) const - { - return Parent::text(idx); - } - void setPixmap(colIdx idx, const QIcon &icon) - { - Parent::setIcon(idx, icon); - } - const QIcon pixmap(colIdx idx) const - { - return icon(idx); - } // TODO: Implement paintCell ConfigItem* nextItem; struct menu *menu; bool visible; bool goParent; -}; -class ConfigLineEdit : public QLineEdit { - Q_OBJECT - typedef class QLineEdit Parent; -public: - ConfigLineEdit(ConfigView* parent); - ConfigView* parent(void) const - { - return (ConfigView*)Parent::parent(); - } - void show(ConfigItem *i); - void keyPressEvent(QKeyEvent *e); - -public: - ConfigItem *item; + static QIcon symbolYesIcon, symbolModIcon, symbolNoIcon; + static QIcon choiceYesIcon, choiceNoIcon; + static QIcon menuIcon, menubackIcon; }; -class ConfigView : public QWidget { - Q_OBJECT - typedef class QWidget Parent; -public: - ConfigView(QWidget* parent, const char *name = 0); - ~ConfigView(void); - static void updateList(ConfigItem* item); - static void updateListAll(void); - - bool showName(void) const { return list->showName; } - bool showRange(void) const { return list->showRange; } - bool showData(void) const { return list->showData; } -public slots: - void setShowName(bool); - void setShowRange(bool); - void setShowData(bool); - void setOptionMode(QAction *); -signals: - void showNameChanged(bool); - void showRangeChanged(bool); - void showDataChanged(bool); +class ConfigItemDelegate : public QStyledItemDelegate +{ +private: + struct menu *menu; public: - ConfigList* list; - ConfigLineEdit* lineEdit; - - static ConfigView* viewList; - ConfigView* nextView; - - static QAction *showNormalAction; - static QAction *showAllAction; - static QAction *showPromptAction; + ConfigItemDelegate(QObject *parent = nullptr) + : QStyledItemDelegate(parent) {} + QWidget *createEditor(QWidget *parent, + const QStyleOptionViewItem &option, + const QModelIndex &index) const override; + void setModelData(QWidget *editor, QAbstractItemModel *model, + const QModelIndex &index) const override; }; class ConfigInfoView : public QTextBrowser { Q_OBJECT typedef class QTextBrowser Parent; + QMenu *contextMenu; public: ConfigInfoView(QWidget* parent, const char *name = 0); bool showDebug(void) const { return _showDebug; } @@ -249,6 +195,7 @@ public slots: void setInfo(struct menu *menu); void saveSettings(void); void setShowDebug(bool); + void clicked (const QUrl &url); signals: void showDebugChanged(bool); @@ -260,8 +207,7 @@ protected: QString debug_info(struct symbol *sym); static QString print_filter(const QString &str); static void expr_print_help(void *data, struct symbol *sym, const char *str); - QMenu *createStandardContextMenu(const QPoint & pos); - void contextMenuEvent(QContextMenuEvent *e); + void contextMenuEvent(QContextMenuEvent *event); struct symbol *sym; struct menu *_menu; @@ -272,7 +218,7 @@ class ConfigSearchWindow : public QDialog { Q_OBJECT typedef class QDialog Parent; public: - ConfigSearchWindow(ConfigMainWindow* parent, const char *name = 0); + ConfigSearchWindow(ConfigMainWindow *parent); public slots: void saveSettings(void); @@ -282,7 +228,7 @@ protected: QLineEdit* editField; QPushButton* searchButton; QSplitter* split; - ConfigView* list; + ConfigList *list; ConfigInfoView* info; struct symbol **result; @@ -298,6 +244,7 @@ public: ConfigMainWindow(void); public slots: void changeMenu(struct menu *); + void changeItens(struct menu *); void setMenuLink(struct menu *); void listFocusChanged(void); void goBack(void); @@ -316,12 +263,9 @@ protected: void closeEvent(QCloseEvent *e); ConfigSearchWindow *searchWindow; - ConfigView *menuView; ConfigList *menuList; - ConfigView *configView; ConfigList *configList; ConfigInfoView *helpText; - QToolBar *toolBar; QAction *backAction; QAction *singleViewAction; QAction *splitViewAction; diff --git a/scripts/kconfig/streamline_config.pl b/scripts/kconfig/streamline_config.pl index 08d76d7b3b..911c72a2db 100755 --- a/scripts/kconfig/streamline_config.pl +++ b/scripts/kconfig/streamline_config.pl @@ -21,7 +21,7 @@ # 1. Boot up the kernel that you want to stream line the config on. # 2. Change directory to the directory holding the source of the # kernel that you just booted. -# 3. Copy the configuraton file to this directory as .config +# 3. Copy the configuration file to this directory as .config # 4. Have all your devices that you need modules for connected and # operational (make sure that their corresponding modules are loaded) # 5. Run this script redirecting the output to some other file @@ -56,8 +56,6 @@ sub dprint { print STDERR @_; } -my $config = ".config"; - my $uname = `uname -r`; chomp $uname; @@ -145,6 +143,7 @@ my %depends; my %selects; my %prompts; my %objects; +my %config2kfile; my $var; my $iflevel = 0; my @ifdeps; @@ -203,6 +202,7 @@ sub read_kconfig { if (/^\s*(menu)?config\s+(\S+)\s*$/) { $state = "NEW"; $config = $2; + $config2kfile{"CONFIG_$config"} = $kconfig; # Add depends for 'if' nesting for (my $i = 0; $i < $iflevel; $i++) { @@ -374,7 +374,7 @@ if (defined($lsmod_file)) { $lsmod = "$dir/lsmod"; last; } -} + } if (!defined($lsmod)) { # try just the path $lsmod = "lsmod"; @@ -481,7 +481,7 @@ sub parse_config_depends # The idea is we look at all the configs that select it. If one # is already in our list of configs to enable, then there's nothing # else to do. If there isn't, we pick the first config that was -# enabled in the orignal config and use that. +# enabled in the original config and use that. sub parse_config_selects { my ($config, $p) = @_; @@ -593,6 +593,23 @@ while ($repeat) { } my %setconfigs; +my @preserved_kconfigs; +if (defined($ENV{'LMC_KEEP'})) { + @preserved_kconfigs = split(/:/,$ENV{LMC_KEEP}); +} + +sub in_preserved_kconfigs { + my $kconfig = $config2kfile{$_[0]}; + if (!defined($kconfig)) { + return 0; + } + foreach my $excl (@preserved_kconfigs) { + if($kconfig =~ /^$excl/) { + return 1; + } + } + return 0; +} # Finally, read the .config file and turn off any module enabled that # we could not find a reason to keep enabled. @@ -646,6 +663,11 @@ foreach my $line (@config_file) { } if (/^(CONFIG.*)=(m|y)/) { + if (in_preserved_kconfigs($1)) { + dprint "Preserve config $1"; + print; + next; + } if (defined($configs{$1})) { if ($localyesconfig) { $setconfigs{$1} = 'y'; diff --git a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c index f56eec5ea4..5844d636d3 100644 --- a/scripts/kconfig/symbol.c +++ b/scripts/kconfig/symbol.c @@ -3,11 +3,11 @@ * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> */ +#include <sys/types.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #include <regex.h> -#include <sys/utsname.h> #include "lkc.h" @@ -15,23 +15,28 @@ struct symbol symbol_yes = { .name = "y", .curr = { "y", yes }, .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_mod = { +}; + +struct symbol symbol_mod = { .name = "m", .curr = { "m", mod }, .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_no = { +}; + +struct symbol symbol_no = { .name = "n", .curr = { "n", no }, .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_empty = { +}; + +static struct symbol symbol_empty = { .name = "", .curr = { "", no }, .flags = SYMBOL_VALID, }; -struct symbol *sym_defconfig_list; struct symbol *modules_sym; -tristate modules_val; +static tristate modules_val; enum symbol_type sym_get_type(struct symbol *sym) { @@ -221,7 +226,7 @@ static void sym_calc_visibility(struct symbol *sym) sym_set_changed(sym); } tri = no; - if (sym->implied.expr && sym->dir_dep.tri != no) + if (sym->implied.expr) tri = expr_calc_value(sym->implied.expr); if (tri == mod && sym_get_type(sym) == S_BOOLEAN) tri = yes; @@ -394,6 +399,8 @@ void sym_calc_value(struct symbol *sym) if (sym->implied.tri != no) { sym->flags |= SYMBOL_WRITE; newval.tri = EXPR_OR(newval.tri, sym->implied.tri); + newval.tri = EXPR_AND(newval.tri, + sym->dir_dep.tri); } } calc_newval: @@ -401,8 +408,7 @@ void sym_calc_value(struct symbol *sym) sym_warn_unmet_dep(sym); newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); } - if (newval.tri == mod && - (sym_get_type(sym) == S_BOOLEAN || sym->implied.tri == yes)) + if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) newval.tri = yes; break; case S_STRING: @@ -466,7 +472,7 @@ void sym_clear_all_valid(void) for_all_symbols(i, sym) sym->flags &= ~SYMBOL_VALID; - sym_add_change_count(1); + conf_set_changed(true); sym_calc_value(modules_sym); } @@ -484,8 +490,6 @@ bool sym_tristate_within_range(struct symbol *sym, tristate val) return false; if (sym->visible <= sym->rev_dep.tri) return false; - if (sym->implied.tri == yes && val == mod) - return false; if (sym_is_choice_value(sym) && sym->visible == yes) return val == yes; return val >= sym->rev_dep.tri && val <= sym->visible; @@ -832,7 +836,7 @@ struct symbol *sym_lookup(const char *name, int flags) memset(symbol, 0, sizeof(*symbol)); symbol->name = new_name; symbol->type = S_UNKNOWN; - symbol->flags |= flags; + symbol->flags = flags; symbol->next = symbol_hash[hash]; symbol_hash[hash] = symbol; @@ -1273,28 +1277,6 @@ struct symbol *sym_check_deps(struct symbol *sym) return sym2; } -struct property *prop_alloc(enum prop_type type, struct symbol *sym) -{ - struct property *prop; - struct property **propp; - - prop = xmalloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->sym = sym; - prop->file = current_file; - prop->lineno = zconf_lineno(); - - /* append property to the prop list of symbol */ - if (sym) { - for (propp = &sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; - } - - return prop; -} - struct symbol *prop_get_symbol(struct property *prop) { if (prop->expr && (prop->expr->type == E_SYMBOL || diff --git a/scripts/kconfig/tests/choice/Kconfig b/scripts/kconfig/tests/choice/Kconfig index a412205b1b..0930eb65e9 100644 --- a/scripts/kconfig/tests/choice/Kconfig +++ b/scripts/kconfig/tests/choice/Kconfig @@ -2,7 +2,7 @@ config MODULES bool "Enable loadable module support" - option modules + modules default y choice diff --git a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig index 7106c26bb3..bd970cec07 100644 --- a/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig +++ b/scripts/kconfig/tests/choice_value_with_m_dep/Kconfig @@ -2,7 +2,7 @@ config MODULES def_bool y - option modules + modules config DEP tristate diff --git a/scripts/kconfig/tests/conftest.py b/scripts/kconfig/tests/conftest.py index 0345ef6e32..af8774a569 100644 --- a/scripts/kconfig/tests/conftest.py +++ b/scripts/kconfig/tests/conftest.py @@ -53,6 +53,10 @@ class Conf: # Override 'srctree' environment to make the test as the top directory extra_env['srctree'] = self._test_dir + # Clear KCONFIG_DEFCONFIG_LIST to keep unit tests from being affected + # by the user's environment. + extra_env['KCONFIG_DEFCONFIG_LIST'] = '' + # Run Kconfig in a temporary directory. # This directory is automatically removed when done. with tempfile.TemporaryDirectory() as temp_dir: diff --git a/scripts/kconfig/tests/inter_choice/Kconfig b/scripts/kconfig/tests/inter_choice/Kconfig index 5698a4018d..26c25f6869 100644 --- a/scripts/kconfig/tests/inter_choice/Kconfig +++ b/scripts/kconfig/tests/inter_choice/Kconfig @@ -2,7 +2,7 @@ config MODULES def_bool y - option modules + modules choice prompt "Choice" diff --git a/scripts/kconfig/tests/rand_nested_choice/Kconfig b/scripts/kconfig/tests/rand_nested_choice/Kconfig deleted file mode 100644 index 8350de7f73..0000000000 --- a/scripts/kconfig/tests/rand_nested_choice/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -choice - prompt "choice" - -config A - bool "A" - -config B - bool "B" - -if B -choice - prompt "sub choice" - -config C - bool "C" - -config D - bool "D" - -if D -choice - prompt "subsub choice" - -config E - bool "E" - -endchoice -endif # D - -endchoice -endif # B - -endchoice diff --git a/scripts/kconfig/tests/rand_nested_choice/__init__.py b/scripts/kconfig/tests/rand_nested_choice/__init__.py deleted file mode 100644 index 9e4b2db535..0000000000 --- a/scripts/kconfig/tests/rand_nested_choice/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -""" -Set random values recursively in nested choices. - -Kconfig can create a choice-in-choice structure by using 'if' statement. -randconfig should correctly set random choice values. - -Related Linux commit: 3b9a19e08960e5cdad5253998637653e592a3c29 -""" - - -def test(conf): - for i in range(20): - assert conf.randconfig() == 0 - assert (conf.config_contains('expected_stdout0') or - conf.config_contains('expected_stdout1') or - conf.config_contains('expected_stdout2')) diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout0 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout0 deleted file mode 100644 index 05450f3d4e..0000000000 --- a/scripts/kconfig/tests/rand_nested_choice/expected_stdout0 +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_A=y -# CONFIG_B is not set diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout1 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout1 deleted file mode 100644 index 37ab295841..0000000000 --- a/scripts/kconfig/tests/rand_nested_choice/expected_stdout1 +++ /dev/null @@ -1,4 +0,0 @@ -# CONFIG_A is not set -CONFIG_B=y -CONFIG_C=y -# CONFIG_D is not set diff --git a/scripts/kconfig/tests/rand_nested_choice/expected_stdout2 b/scripts/kconfig/tests/rand_nested_choice/expected_stdout2 deleted file mode 100644 index 849ff47e98..0000000000 --- a/scripts/kconfig/tests/rand_nested_choice/expected_stdout2 +++ /dev/null @@ -1,5 +0,0 @@ -# CONFIG_A is not set -CONFIG_B=y -# CONFIG_C is not set -CONFIG_D=y -CONFIG_E=y diff --git a/scripts/kernel-install-target.c b/scripts/kernel-install-target.c new file mode 100644 index 0000000000..845a96d29b --- /dev/null +++ b/scripts/kernel-install-target.c @@ -0,0 +1 @@ +#include "kernel-install.c" diff --git a/scripts/kwbimage.c b/scripts/kwbimage.c index 6ba4abaa30..370c54c983 100644 --- a/scripts/kwbimage.c +++ b/scripts/kwbimage.c @@ -1,20 +1,10 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2013 Thomas Petazzoni <thomas.petazzoni@free-electrons.com> + /* * Image manipulator for Marvell SoCs * supports Kirkwood, Dove, Armada 370, and Armada XP * - * (C) Copyright 2013 Thomas Petazzoni - * <thomas.petazzoni@free-electrons.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * * This tool allows to extract and create bootable images for Marvell * Kirkwood, Dove, Armada 370, and Armada XP SoCs. It supports two * versions of the bootable image format: version 0 (used on Marvell @@ -48,7 +38,6 @@ #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> -#include <unistd.h> #include <stdlib.h> #include <string.h> #include <libgen.h> @@ -186,7 +175,7 @@ struct image_cfg_element { } type; union { unsigned int version; - unsigned int bootfrom; + int bootfrom; struct { char *file; unsigned int args[BINARY_MAX_ARGS]; @@ -197,7 +186,7 @@ struct image_cfg_element { unsigned int execaddr; unsigned int nandblksz; unsigned int nandbadblklocation; - unsigned int nandeccmode; + int nandeccmode; unsigned int nandpagesz; struct ext_hdr_v0_reg regdata; }; @@ -231,7 +220,7 @@ static const char *image_boot_mode_name(unsigned int id) return NULL; } -int image_boot_mode_id(const char *boot_mode_name) +static int image_boot_mode_id(const char *boot_mode_name) { int i; for (i = 0; boot_modes[i].name; i++) @@ -250,7 +239,7 @@ static const char *image_nand_ecc_mode_name(unsigned int id) return NULL; } -int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) +static int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) { int i; for (i = 0; nand_ecc_modes[i].name; i++) @@ -1017,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")) { @@ -1067,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-target.c b/scripts/kwboot-target.c new file mode 100644 index 0000000000..68cde2d24c --- /dev/null +++ b/scripts/kwboot-target.c @@ -0,0 +1 @@ +#include "kwboot.c" diff --git a/scripts/kwboot.c b/scripts/kwboot.c index 43b8b8cbcd..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 @@ -147,12 +148,11 @@ kwboot_tty_recv(int fd, void *buf, size_t len, int timeo) FD_ZERO(&rfds); FD_SET(fd, &rfds); - tv.tv_sec = 0; tv.tv_usec = timeo * 1000; - if (tv.tv_usec > 1000000) { - tv.tv_sec += tv.tv_usec / 1000000; - tv.tv_usec %= 1000000; - } + + /* normalize timeval */ + tv.tv_sec = tv.tv_usec / 1000000; + tv.tv_usec %= 1000000; do { nfds = select(fd + 1, &rfds, NULL, NULL, &tv); @@ -504,7 +504,7 @@ kwboot_term_pipe(int in, int out, char *quit, int *s) ssize_t nin, nout; char _buf[128], *buf = _buf; - nin = read(in, buf, sizeof(buf)); + nin = read(in, _buf, sizeof(_buf)); if (nin < 0) return -1; 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/mk-omap-image.c b/scripts/mk-omap-image.c index 234b7e37c2..5741b0afbc 100644 --- a/scripts/mk-omap-image.c +++ b/scripts/mk-omap-image.c @@ -1,22 +1,8 @@ -/* - * mk-am35xx-spi-image.c - convert a barebox image for SPI loading on AM35xx - * - * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2012 Jan Luebbe <j.luebbe@pengutronix.de> + +/* mk-am35xx-spi-image.c - convert a barebox image for SPI loading on AM35xx */ + /** * @file * @brief convert a barebox image for SPI loading on AM35xx diff --git a/scripts/mkcompile_h b/scripts/mkcompile_h index 60b20cafc6..49aadc153d 100755 --- a/scripts/mkcompile_h +++ b/scripts/mkcompile_h @@ -54,6 +54,7 @@ fi UTS_VERSION="#$VERSION" CONFIG_FLAGS="" UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" +BUILDSYSTEM_VERSION="$BUILDSYSTEM_VERSION" # Truncate to maximum length @@ -69,6 +70,8 @@ UTS_TRUNCATE="cut -b -$UTS_LEN" echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" + echo \#define BUILDSYSTEM_VERSION \"`echo $BUILDSYSTEM_VERSION`\" + echo \#define BAREBOX_COMPILE_BY \"`echo $BAREBOX_COMPILE_BY | $UTS_TRUNCATE`\" echo \#define BAREBOX_COMPILE_HOST \"`echo $BAREBOX_COMPILE_HOST | $UTS_TRUNCATE`\" diff --git a/scripts/mkimage.c b/scripts/mkimage.c deleted file mode 100644 index 7d283c5509..0000000000 --- a/scripts/mkimage.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * (C) Copyright 2008 Semihalf - * - * (C) Copyright 2000-2004 - * DENX Software Engineering - * Wolfgang Denk, wd@denx.de - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#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/mkmakefile b/scripts/mkmakefile index 84af27bf0f..1cb1747514 100755 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -1,52 +1,17 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0 # Generates a small Makefile used in the root of the output # directory, to allow make to be started from there. # The Makefile also allow for more convinient build of external modules # Usage # $1 - Kernel src directory -# $2 - Output directory -# $3 - version -# $4 - patchlevel - -test ! -r $2/Makefile -o -O $2/Makefile || exit 0 -# Only overwrite automatically generated Makefiles -# (so we do not overwrite kernel Makefile) -if test -e $2/Makefile && ! grep -q Automatically $2/Makefile -then - exit 0 -fi if [ "${quiet}" != "silent_" ]; then - echo " GEN $2/Makefile" + echo " GEN Makefile" fi -cat << EOF > $2/Makefile +cat << EOF > Makefile # Automatically generated by $0: don't edit - -VERSION = $3 -PATCHLEVEL = $4 - -lastword = \$(word \$(words \$(1)),\$(1)) -makedir := \$(dir \$(call lastword,\$(MAKEFILE_LIST))) - -ifeq ("\$(origin V)", "command line") -VERBOSE := \$(V) -endif -ifneq (\$(VERBOSE),1) -Q := @ -endif - -MAKEARGS := -C $1 -MAKEARGS += O=\$(if \$(patsubst /%,,\$(makedir)),\$(CURDIR)/)\$(patsubst %/,%,\$(makedir)) - -MAKEFLAGS += --no-print-directory - -.PHONY: __sub-make \$(MAKECMDGOALS) - -__sub-make: - \$(Q)\$(MAKE) \$(MAKEARGS) \$(MAKECMDGOALS) - -\$(filter-out __sub-make, \$(MAKECMDGOALS)): __sub-make - @: +include $1/Makefile EOF diff --git a/scripts/mkublheader.c b/scripts/mkublheader.c deleted file mode 100644 index 5464a80611..0000000000 --- a/scripts/mkublheader.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * mkublheader.c - produce the header needed to load barebox on OMAP-L138 - * - * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#define _BSD_SOURCE -#define _DEFAULT_SOURCE - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> -#include <stdint.h> -#include <limits.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <getopt.h> -#include <endian.h> - -#define MAGICNUM 0xa1aced00 - -struct ubl_header -{ - uint32_t magicNum; /* Expected magic number */ - uint32_t epAddr; /* Entry point of the user application */ - uint32_t imgSize; /* Number of bytes of the application image */ - uint32_t imgAddr; /* SPI memory offset where application image is located */ - uint32_t ldAddr; /* Address where image is copied to */ -}; - -void usage(char *prgname) -{ - printf( "Usage : %s [OPTION] FILE > HEADER\n" - "\n" - "options:\n" - " -a <address> image flash address\n" - " -e <address> entry point memory address\n" - " -l <address> load memory address\n", - prgname); -} - -int main(int argc, char *argv[]) -{ - struct stat sb; - struct ubl_header uh; - int opt; - uint32_t imgAddr = 0x00040000 + sizeof(uh); - uint32_t epAddr = 0xc1080000, ldAddr = 0xc1080000; - - while((opt = getopt(argc, argv, "ael:")) != -1) { - switch (opt) { - case 'a': - imgAddr = strtoul(optarg, NULL, 0); - break; - case 'e': - epAddr = strtoul(optarg, NULL, 0); - break; - case 'l': - ldAddr = strtoul(optarg, NULL, 0); - break; - } - } - - if (optind >= argc) { - usage(argv[0]); - exit(1); - } - - if (stat(argv[optind], &sb) == -1) { - perror("stat"); - exit(EXIT_FAILURE); - } - - uh.magicNum = htole32(MAGICNUM); - uh.epAddr = htole32(epAddr); - uh.imgSize = htole32((uint32_t)sb.st_size); - uh.imgAddr = htole32(imgAddr); - uh.ldAddr = htole32(ldAddr); - - fwrite(&uh, sizeof(uh), 1, stdout); - - exit(EXIT_SUCCESS); -} diff --git a/scripts/mod/.gitignore b/scripts/mod/.gitignore index a6dd5e27e2..f507ef8560 100644 --- a/scripts/mod/.gitignore +++ b/scripts/mod/.gitignore @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0-only + elfconfig.h mk_elfconfig modpost diff --git a/scripts/mod/Makefile b/scripts/mod/Makefile index c5aa348924..b381877a83 100644 --- a/scripts/mod/Makefile +++ b/scripts/mod/Makefile @@ -1,5 +1,7 @@ -hostprogs-y := modpost mk_elfconfig -always := $(hostprogs-y) empty.o +# SPDX-License-Identifier: GPL-2.0-only + +hostprogs-always-y += modpost mk_elfconfig +always-y += empty.o modpost-objs := modpost.o sumversion.o @@ -8,7 +10,7 @@ modpost-objs := modpost.o sumversion.o $(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h quiet_cmd_elfconfig = MKELF $@ - cmd_elfconfig = $(obj)/mk_elfconfig $(ARCH) < $< > $@ + cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ $(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE $(call if_changed,elfconfig) diff --git a/scripts/mod/mk_elfconfig.c b/scripts/mod/mk_elfconfig.c index db3881f14c..680eade89b 100644 --- a/scripts/mod/mk_elfconfig.c +++ b/scripts/mod/mk_elfconfig.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -9,9 +10,6 @@ main(int argc, char **argv) unsigned char ei[EI_NIDENT]; union { short s; char c[2]; } endian_test; - if (argc != 2) { - fprintf(stderr, "Error: no arch\n"); - } if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) { fprintf(stderr, "Error: input truncated\n"); return 1; @@ -55,12 +53,5 @@ main(int argc, char **argv) else exit(1); - if ((strcmp(argv[1], "v850") == 0) || (strcmp(argv[1], "h8300") == 0) - || (strcmp(argv[1], "blackfin") == 0)) - printf("#define MODULE_SYMBOL_PREFIX \"_\"\n"); - else - printf("#define MODULE_SYMBOL_PREFIX \"\"\n"); - return 0; } - diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c index 795ee8d09b..a42f1e6ce1 100644 --- a/scripts/mod/modpost.c +++ b/scripts/mod/modpost.c @@ -31,6 +31,8 @@ static inline int license_is_gpl_compatible(const char *license) } #endif +#define MODULE_SYMBOL_PREFIX "" + /* Are we using CONFIG_MODVERSIONS? */ int modversions = 0; /* Warn about undefined symbols? (do so if we have vmlinux) */ diff --git a/scripts/mod/sumversion.c b/scripts/mod/sumversion.c index d9cc6901d6..b5f1824a69 100644 --- a/scripts/mod/sumversion.c +++ b/scripts/mod/sumversion.c @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 1997-1998 Andrew Tridgell +// SPDX-FileCopyrightText: Cryptoapi developers. +// SPDX-FileCopyrightText: 2002 David S. Miller <davem@redhat.com> +// SPDX-FileCopyrightText: 2002 James Morris <jmorris@intercode.com.au> + #include <netinet/in.h> #ifdef __sun__ #include <inttypes.h> @@ -20,17 +26,7 @@ * originally based on the public domain implementation written * by Colin Plumb in 1993. * - * Copyright (c) Andrew Tridgell 1997-1998. * Modified by Steve French (sfrench@us.ibm.com) 2002 - * Copyright (c) Cryptoapi developers. - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * */ #define MD4_DIGEST_SIZE 16 #define MD4_HMAC_BLOCK_SIZE 64 diff --git a/scripts/mxsimage.c b/scripts/mxsimage.c index 8a63d76939..cebbab25ad 100644 --- a/scripts/mxsimage.c +++ b/scripts/mxsimage.c @@ -1,10 +1,7 @@ -/* - * Freescale i.MX23/i.MX28 SB image generator - * - * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ +// SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-OpenSSL-exception +// SPDX-FileCopyrightText: 2012-2013 Marek Vasut <marex@denx.de> + +/* Freescale i.MX23/i.MX28 SB image generator */ #include <errno.h> #include <fcntl.h> @@ -18,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; @@ -379,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 @@ -442,20 +411,9 @@ int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *ctx) } #endif -uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len) +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-target.c b/scripts/omap3-usb-loader-target.c new file mode 100644 index 0000000000..c99c261a02 --- /dev/null +++ b/scripts/omap3-usb-loader-target.c @@ -0,0 +1 @@ +#include "omap3-usb-loader.c" diff --git a/scripts/omap3-usb-loader.c b/scripts/omap3-usb-loader.c index ae6f1258df..38cdbfac93 100644 --- a/scripts/omap3-usb-loader.c +++ b/scripts/omap3-usb-loader.c @@ -1,18 +1,8 @@ -/* - * OMAP Loader, a USB uploader application targeted at OMAP3 processors - * Copyright (C) 2008 Martin Mueller <martinmm@pfump.org> - * Copyright (C) 2014 Grant Hernandez <grant.h.hernandez@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2008 Martin Mueller <martinmm@pfump.org> +// SPDX-FileCopyrightText: 2014 Grant Hernandez <grant.h.hernandez@gmail.com> + +/* OMAP Loader, a USB uploader application targeted at OMAP3 processors */ #include <stdio.h> #include <stdlib.h> @@ -29,16 +19,15 @@ #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> #include <libgen.h> /* for basename */ -#include <libusb-1.0/libusb.h> /* the main event */ +#include <libusb.h> /* the main event */ + +#include "common.h" +#include "common.c" /* Device specific defines (OMAP) * Primary source: http://www.ti.com/lit/pdf/sprugn4 @@ -53,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 @@ -335,50 +315,6 @@ found: return handle; } -static unsigned char *read_file(char *path, size_t *readamt) -{ - FILE *fp = fopen(path, "rb"); - - if (!fp) { - log_error("failed to open file \'%s\': %s\n", path, - strerror(errno)); - return NULL; - } - - unsigned char *data = NULL; - size_t allocsize = 0; - size_t iter = 0; - - while (1) { - allocsize += 1024; - data = realloc(data, allocsize); - if (!data) - return NULL; - - size_t readsize = allocsize - iter; - size_t ret = fread(data + iter, sizeof (unsigned char), readsize, fp); - - iter += ret; - - if (ret != readsize) { - if (feof(fp)) { - break; - } else if (ferror(fp)) { - log_error("error file reading file \'%s\': %s\n", - path, strerror(errno)); - free(data); - return NULL; - } - } - } - - /* trim the allocation down to size */ - data = realloc(data, iter); - *readamt = iter; - - return data; -} - static int transfer_first_stage(libusb_device_handle * handle, struct arg_state *args) { unsigned char *buffer = NULL; @@ -394,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; @@ -461,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))) { @@ -470,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; } @@ -835,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/omap4_usbboot-target.c b/scripts/omap4_usbboot-target.c new file mode 100644 index 0000000000..3dd6065337 --- /dev/null +++ b/scripts/omap4_usbboot-target.c @@ -0,0 +1 @@ +#include "omap4_usbboot.c" diff --git a/scripts/omap4_usbboot.c b/scripts/omap4_usbboot.c index 329668d1dd..342efd0c9a 100644 --- a/scripts/omap4_usbboot.c +++ b/scripts/omap4_usbboot.c @@ -1,16 +1,6 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Inspired by: https://github.com/simu/usbboot-omap4.git - */ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* Inspired by: https://github.com/simu/usbboot-omap4.git */ #include <stdio.h> #include <stdlib.h> @@ -43,21 +33,21 @@ #define host_print(fmt, arg...) printf(HFORMAT fmt TFORMAT, \ HOST_FORMAT, ##arg, TARGET_FORMAT) -int usb_write(void *h, void const *data, int len) +static int usb_write(void *h, void const *data, int len) { int actual; return libusb_bulk_transfer(h, 0x01, (void *)data, len, &actual, 5000) ? 0 : actual; } -int usb_read(void *h, void *data, int len) +static int usb_read(void *h, void *data, int len) { int actual; return libusb_bulk_transfer(h, 0x81, data, len, &actual, 5000) ? 0 : actual; } -void panic(struct termios *t_restore) +static void panic(struct termios *t_restore) { tcsetattr(STDIN_FILENO, TCSANOW, t_restore); printf(HFORMAT, HOST_FORMAT); @@ -70,7 +60,7 @@ struct thread_vars { struct termios t_restore; }; -void *listenerTask(void *argument) +static void *listenerTask(void *argument) { struct thread_vars *vars = argument; int c; @@ -88,7 +78,7 @@ void *listenerTask(void *argument) return NULL; } -int read_asic_id(struct libusb_device_handle *usb) +static int read_asic_id(struct libusb_device_handle *usb) { #define LINEWIDTH 16 const uint32_t msg_getid = 0xF0030003; @@ -189,7 +179,7 @@ struct file_data { void *data; }; -int process_file(struct libusb_device_handle *usb, const char *rootfs, +static int process_file(struct libusb_device_handle *usb, const char *rootfs, struct file_data *fd_vector, struct termios *t_restore) { uint32_t i, j, pos, size; @@ -339,7 +329,7 @@ open_ok: return ret; } -int usb_boot(struct libusb_device_handle *usb, +static int usb_boot(struct libusb_device_handle *usb, void *data, unsigned sz, const char *rootfs) { const uint32_t msg_boot = 0xF0030002; diff --git a/scripts/omap_signGP.c b/scripts/omap_signGP.c index ac47fdf089..b89414931e 100644 --- a/scripts/omap_signGP.c +++ b/scripts/omap_signGP.c @@ -1,3 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2010 Texas Instruments Incorporated (http://www.ti.com/) + /** * signGP.c - Read the x-load.bin file and write out the x-load.bin.ift file * @@ -5,17 +8,6 @@ * and the load address. If not entered on command line, file name is * assumed to be x-load.bin in current directory and load address is * 0x40200800. - * - * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 of - * the License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <stdio.h> diff --git a/scripts/pblimage.c b/scripts/pblimage.c index 235af8aa11..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; -} - -uint32_t pbl_crc32(uint32_t in_crc, const char *buf, uint32_t len) +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 @@ 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/prelink-riscv.c b/scripts/prelink-riscv.c new file mode 100644 index 0000000000..c185d3981c --- /dev/null +++ b/scripts/prelink-riscv.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Andes Technology + * Chih-Mao Chen <cmchen@andestech.com> + * + * Statically process runtime relocations on RISC-V ELF images + * so that it can be directly executed when loaded at LMA + * without fixup. Both RV32 and RV64 are supported. + */ + +#include <errno.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <elf.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include "compiler.h" + +#ifndef EM_RISCV +#define EM_RISCV 243 +#endif + +#ifndef R_RISCV_32 +#define R_RISCV_32 1 +#endif + +#ifndef R_RISCV_64 +#define R_RISCV_64 2 +#endif + +#ifndef R_RISCV_RELATIVE +#define R_RISCV_RELATIVE 3 +#endif + +const char *argv0; + +#define die(fmt, ...) \ + do { \ + fprintf(stderr, "%s: " fmt "\n", argv0, ## __VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0) + +#define PRELINK_BYTEORDER le +#define PRELINK_INC_BITS 32 +#include "prelink-riscv.inc" +#undef PRELINK_BYTEORDER +#undef PRELINK_INC_BITS + +#define PRELINK_BYTEORDER le +#define PRELINK_INC_BITS 64 +#include "prelink-riscv.inc" +#undef PRELINK_BYTEORDER +#undef PRELINK_INC_BITS + +#define PRELINK_BYTEORDER be +#define PRELINK_INC_BITS 32 +#include "prelink-riscv.inc" +#undef PRELINK_BYTEORDER +#undef PRELINK_INC_BITS + +#define PRELINK_BYTEORDER be +#define PRELINK_INC_BITS 64 +#include "prelink-riscv.inc" +#undef PRELINK_BYTEORDER +#undef PRELINK_INC_BITS + +int main(int argc, const char *const *argv) +{ + argv0 = argv[0]; + + if (argc < 2) { + fprintf(stderr, "Usage: %s <u-boot>\n", argv0); + exit(EXIT_FAILURE); + } + + int fd = open(argv[1], O_RDWR, 0); + + if (fd < 0) + die("Cannot open %s: %s", argv[1], strerror(errno)); + + struct stat st; + + if (fstat(fd, &st) < 0) + die("Cannot stat %s: %s", argv[1], strerror(errno)); + + void *data = + mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + if (data == MAP_FAILED) + die("Cannot mmap %s: %s", argv[1], strerror(errno)); + + close(fd); + + unsigned char *e_ident = (unsigned char *)data; + + if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) + die("Invalid ELF file %s", argv[1]); + + bool is64 = e_ident[EI_CLASS] == ELFCLASS64; + bool isbe = e_ident[EI_DATA] == ELFDATA2MSB; + + if (is64) { + if (isbe) + prelink_be64(data); + else + prelink_le64(data); + } else { + if (isbe) + prelink_be32(data); + else + prelink_le32(data); + } + + return 0; +} diff --git a/scripts/prelink-riscv.inc b/scripts/prelink-riscv.inc new file mode 100644 index 0000000000..f2b5467f5b --- /dev/null +++ b/scripts/prelink-riscv.inc @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2017 Andes Technology + * Chih-Mao Chen <cmchen@andestech.com> + * + * Statically process runtime relocations on RISC-V ELF images + * so that it can be directly executed when loaded at LMA + * without fixup. Both RV32 and RV64 are supported. + */ + +#define CONCAT_IMPL(x, y) x##y +#define CONCAT(x, y) CONCAT_IMPL(x, y) +#define CONCAT3(x, y, z) CONCAT(CONCAT(x, y), z) + +#define prelink_bonn CONCAT3(prelink_, PRELINK_BYTEORDER, PRELINK_INC_BITS) +#define uintnn_t CONCAT3(uint, PRELINK_INC_BITS, _t) +#define get_offset_bonn CONCAT3(get_offset_, PRELINK_BYTEORDER, PRELINK_INC_BITS) +#define Elf_Ehdr CONCAT3(Elf, PRELINK_INC_BITS, _Ehdr) +#define Elf_Phdr CONCAT3(Elf, PRELINK_INC_BITS, _Phdr) +#define Elf_Rela CONCAT3(Elf, PRELINK_INC_BITS, _Rela) +#define Elf_Sym CONCAT3(Elf, PRELINK_INC_BITS, _Sym) +#define Elf_Dyn CONCAT3(Elf, PRELINK_INC_BITS, _Dyn) +#define Elf_Addr CONCAT3(Elf, PRELINK_INC_BITS, _Addr) +#define ELF_R_TYPE CONCAT3(ELF, PRELINK_INC_BITS, _R_TYPE) +#define ELF_R_SYM CONCAT3(ELF, PRELINK_INC_BITS, _R_SYM) +#define target16_to_cpu CONCAT(PRELINK_BYTEORDER, 16_to_cpu) +#define target32_to_cpu CONCAT(PRELINK_BYTEORDER, 32_to_cpu) +#define target64_to_cpu CONCAT(PRELINK_BYTEORDER, 64_to_cpu) +#define targetnn_to_cpu CONCAT3(PRELINK_BYTEORDER, PRELINK_INC_BITS, _to_cpu) +#define cpu_to_target32 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 32) +#define cpu_to_target64 CONCAT3(cpu_to_, PRELINK_BYTEORDER, 64) + +static void* get_offset_bonn (void* data, Elf_Phdr* phdrs, size_t phnum, Elf_Addr addr) +{ + Elf_Phdr *p; + + for (p = phdrs; p < phdrs + phnum; ++p) + if (targetnn_to_cpu(p->p_vaddr) <= addr && targetnn_to_cpu(p->p_vaddr) + targetnn_to_cpu(p->p_memsz) > addr) + return data + targetnn_to_cpu(p->p_offset) + (addr - targetnn_to_cpu(p->p_vaddr)); + + return NULL; +} + +static void prelink_bonn(void *data) +{ + Elf_Ehdr *ehdr = data; + Elf_Phdr *p; + Elf_Dyn *dyn; + Elf_Rela *r; + + if (target16_to_cpu(ehdr->e_machine) != EM_RISCV) + die("Machine type is not RISC-V"); + + Elf_Phdr *phdrs = data + targetnn_to_cpu(ehdr->e_phoff); + + Elf_Dyn *dyns = NULL; + for (p = phdrs; p < phdrs + target16_to_cpu(ehdr->e_phnum); ++p) { + if (target32_to_cpu(p->p_type) == PT_DYNAMIC) { + dyns = data + targetnn_to_cpu(p->p_offset); + break; + } + } + + if (dyns == NULL) + die("No dynamic section found"); + + Elf_Rela *rela_dyn = NULL; + size_t rela_count = 0; + Elf_Sym *dynsym = NULL; + for (dyn = dyns;; ++dyn) { + if (targetnn_to_cpu(dyn->d_tag) == DT_NULL) + break; + else if (targetnn_to_cpu(dyn->d_tag) == DT_RELA) + rela_dyn = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), + targetnn_to_cpu(dyn->d_un.d_ptr)); + else if (targetnn_to_cpu(dyn->d_tag) == DT_RELASZ) + rela_count = targetnn_to_cpu(dyn->d_un.d_val) / sizeof(Elf_Rela); + else if (targetnn_to_cpu(dyn->d_tag) == DT_SYMTAB) + dynsym = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), + targetnn_to_cpu(dyn->d_un.d_ptr)); + + } + + if (rela_dyn == NULL) + die("No .rela.dyn found"); + + if (dynsym == NULL) + die("No .dynsym found"); + + for (r = rela_dyn; r < rela_dyn + rela_count; ++r) { + void* buf = get_offset_bonn(data, phdrs, target16_to_cpu(ehdr->e_phnum), targetnn_to_cpu(r->r_offset)); + + if (buf == NULL) + continue; + + if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_RELATIVE) + *((uintnn_t*) buf) = r->r_addend; + else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_32) + *((uint32_t*) buf) = cpu_to_target32(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend)); + else if (ELF_R_TYPE(targetnn_to_cpu(r->r_info)) == R_RISCV_64) + *((uint64_t*) buf) = cpu_to_target64(targetnn_to_cpu(dynsym[ELF_R_SYM(targetnn_to_cpu(r->r_info))].st_value) + targetnn_to_cpu(r->r_addend)); + } +} + +#undef prelink_bonn +#undef uintnn_t +#undef get_offset_bonn +#undef Elf_Ehdr +#undef Elf_Phdr +#undef Elf_Rela +#undef Elf_Sym +#undef Elf_Dyn +#undef Elf_Addr +#undef ELF_R_TYPE +#undef ELF_R_SYM +#undef target16_to_cpu +#undef target32_to_cpu +#undef target64_to_cpu +#undef targetnn_to_cpu +#undef cpu_to_target32 +#undef cpu_to_target64 + +#undef CONCAT_IMPL +#undef CONCAT +#undef CONCAT3 diff --git a/scripts/qoiconv.c b/scripts/qoiconv.c new file mode 100644 index 0000000000..081eb1ee06 --- /dev/null +++ b/scripts/qoiconv.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +// SPDX-FileCopyrightText: 2021 Dominic Szablewski + +/* + * Adapted from https://github.com/phoboslab/qoi/blob/master/qoiconv.c + * with the sole modification of removing the png write functionnality + * hence only requiring stb_image.h + */ + +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_NO_LINEAR +#include "stb_image.h" + +#define QOI_IMPLEMENTATION +#include "../lib/gui/qoi.h" + +#define STR_ENDS_WITH(S, E) (strcmp(S + strlen(S) - (sizeof(E)-1), E) == 0) + +int main(int argc, char **argv) { + void *pixels = NULL; + int w, h, channels; + int encoded = 0; + + if (argc < 3) { + puts("Usage: qoiconv <infile> <outfile>"); + puts("Examples:"); + puts(" qoiconv input.png output.qoi"); + exit(1); + } + if (STR_ENDS_WITH(argv[1], ".png")) { + if(!stbi_info(argv[1], &w, &h, &channels)) { + printf("Couldn't read header %s\n", argv[1]); + exit(1); + } + + // Force all odd encodings to be RGBA + if(channels != 3) { + channels = 4; + } + + pixels = (void *)stbi_load(argv[1], &w, &h, NULL, channels); + } + if (pixels == NULL) { + printf("Couldn't load/decode %s\n", argv[1]); + exit(1); + } + if (STR_ENDS_WITH(argv[2], ".qoi")) { + encoded = qoi_write(argv[2], pixels, &(qoi_desc){ + .width = w, + .height = h, + .channels = channels, + .colorspace = QOI_SRGB + }); + } + if (!encoded) { + printf("Couldn't write/encode %s\n", argv[2]); + exit(1); + } + + free(pixels); + return 0; +} diff --git a/scripts/regsubst.pl b/scripts/regsubst.pl index 3b6b8aa2e9..1aaab4f6a2 100755 --- a/scripts/regsubst.pl +++ b/scripts/regsubst.pl @@ -45,10 +45,10 @@ First you have to add the right #include directives to your file: $ cat flash-header-myboard.imxcfg soc imx6 loadaddr 0x20000000 - dcdofs 0x400 + 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 @@ -59,10 +59,10 @@ Then you can process the file with B<regsubst.pl>: $ scripts/regsubst.pl -I arch/arm/mach-imx/include flash-header-myboard.imxcfg soc imx6 loadaddr 0x20000000 - dcdofs 0x400 + 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/rk-usb-loader-target.c b/scripts/rk-usb-loader-target.c new file mode 100644 index 0000000000..fe1540d752 --- /dev/null +++ b/scripts/rk-usb-loader-target.c @@ -0,0 +1 @@ +#include "rk-usb-loader.c" diff --git a/scripts/rk-usb-loader.c b/scripts/rk-usb-loader.c new file mode 100644 index 0000000000..9c2367ed28 --- /dev/null +++ b/scripts/rk-usb-loader.c @@ -0,0 +1,328 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * rk-usb-loader: A tool to USB Bootstrap Rockchip SoCs + * + * This tool bootstraps Rockchip SoCs via USB. It is known to work + * on these SoCs: + * + * - RK3568 + * - RK3566 + * + * rk-usb-loader takes the barebox images the barebox build process + * generates as input. The upload protocol has been taken from the + * rkdevelop tool, but it's not a full replacement of that tool. + */ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <string.h> +#include <stdbool.h> +#include <unistd.h> +#include <getopt.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <libusb.h> + +#include "common.h" +#include "common.c" +#include "rockchip.h" + +static void log_error(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[-] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static void log_info(char *fmt, ...) +{ + va_list va; + + va_start(va, fmt); + fprintf(stdout, "[+] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static int debug; + +static void log_debug(char *fmt, ...) +{ + va_list va; + + if (!debug) + return; + + va_start(va, fmt); + fprintf(stdout, "[D] "); + vfprintf(stdout, fmt, va); + va_end(va); +} + +static libusb_device_handle *rk_usb_open(libusb_context *ctx, uint16_t vendor, uint16_t product) +{ + libusb_device **devlist; + libusb_device_handle *handle; + struct libusb_device_descriptor desc; + ssize_t count, i; + int ret; + + log_info("scanning for USB device matching %04hx:%04hx...\n", + vendor, product); + + while (1) { + if ((count = libusb_get_device_list(ctx, &devlist)) < 0) { + log_error("failed to gather USB device list: %s\n", + libusb_error_name(count)); + return NULL; + } + + for (i = 0; i < count; i++) { + ret = libusb_get_device_descriptor(devlist[i], &desc); + if (ret < 0) { + log_error("failed to get USB device descriptor: %s\n", + libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + if (desc.idVendor != vendor) + continue; + + if (product) { + if (desc.idProduct != product) + continue; + goto found; + } + } + + libusb_free_device_list(devlist, 1); + + /* nothing found yet. have a 10ms nap */ + usleep(10000); + } +found: + + ret = libusb_open(devlist[i], &handle); + if (ret < 0) { + log_error("failed to open USB device %04hx:%04hx: %s\n", + vendor, product, libusb_error_name(ret)); + libusb_free_device_list(devlist, 1); + return NULL; + } + + ret = libusb_claim_interface(handle, 0); + if (ret) { + printf("Claim failed\n"); + return NULL; + } + + log_info("successfully opened %04hx:%04hx\n", vendor, product); + + return handle; +} + +#define poly16_CCITT 0x1021 /* crc-ccitt mask */ + +static uint16_t crc_calculate(uint16_t crc, unsigned char ch) +{ + unsigned int i; + + for (i = 0x80; i != 0; i >>= 1) { + if (crc & 0x8000) { + crc <<= 1; + crc ^= poly16_CCITT; + } else { + crc <<= 1; + } + + if (ch & i) + crc ^= poly16_CCITT; + } + return crc; +} + +static uint16_t crc_ccitt(unsigned char *p, int n) +{ + uint16_t crc = 0xffff; + + while (n--) { + crc = crc_calculate(crc, *p); + p++; + } + + return crc; +} + +static int upload(libusb_device_handle *dev, unsigned int dwRequest, void *buf, int n_bytes) +{ + uint16_t crc; + uint8_t *data; + int sent = 0, ret; + + data = calloc(n_bytes + 5, 1); + memcpy(data, buf, n_bytes); + + crc = crc_ccitt(data, n_bytes); + data[n_bytes] = (crc & 0xff00) >> 8; + data[n_bytes + 1] = crc & 0x00ff; + n_bytes += 2; + + while (sent < n_bytes) { + int now; + + if (n_bytes - sent > 4096) + now = 4096; + else + now = n_bytes - sent; + + ret = libusb_control_transfer(dev, 0x40, 0xC, 0, dwRequest, + data + sent, now, 0); + if (ret != now) { + log_error("DeviceRequest 0x%x failed, err=%d", + dwRequest, ret); + + ret = -EIO; + goto err; + } + sent += now; + } + + ret = 0; +err: + free(data); + + return ret; +} + +static int upload_image(const char *filename) +{ + libusb_context *ctx; + libusb_device_handle *dev; + int ret; + void *buf; + struct newidb *hdr; + int i, n_files; + size_t size; + + buf = read_file(filename, &size); + if (!buf) + exit(1); + + hdr = buf; + + if (hdr->magic != NEWIDB_MAGIC) { + log_error("%s has invalid magic 0x%08x ( != 0x%08x )\n", filename, + hdr->magic, NEWIDB_MAGIC); + exit(1); + } + + ret = libusb_init(&ctx); + if (ret < 0) { + log_error("failed to initialize libusb context: %s\n", + libusb_error_name(ret)); + return ret; + } + + dev = rk_usb_open(ctx, 0x2207, 0x350a); + if (!dev) { + libusb_exit(ctx); + return 1; + } + + n_files = hdr->n_files >> 16; + + if (n_files > 2) { + /* + * This tool is designed for barebox images generated with rkimage. + * These have one blob containing the SDRAM setup sent with the + * CODE471_OPTION and one blob containing the barebox image sent with + * the CODE472_OPTION. + */ + log_error("Invalid image with %d blobs\n", n_files); + ret = -EINVAL; + goto err; + } + + for (i = 0; i < n_files; i++) { + struct newidb_entry *entry = &hdr->entries[i]; + int foffset, fsize, wIndex; + + if (i) + wIndex = 0x472; + else + wIndex = 0x471; + + log_info("Uploading %d/%d\n", i + 1, n_files); + + foffset = (entry->sector & 0xffff) * SECTOR_SIZE; + fsize = (entry->sector >> 16) * SECTOR_SIZE; + + log_debug("image starting at offset 0x%08x, size 0x%08x\n", foffset, fsize); + + ret = upload(dev, wIndex, buf + foffset, fsize); + if (ret) + goto err; + } + + ret = 0; +err: + libusb_close(dev); + libusb_exit(ctx); + + return ret; +} + +static void usage(const char *prgname) +{ + printf( +"Usage: %s [OPTIONS] <IMAGE>\n" +"\n" +"Options:\n" +" -d Enable debugging output\n" +" -h This help\n", + prgname); +} + +static struct option cbootcmd[] = { + {"debug", 0, NULL, 'd'}, + {"help", 0, NULL, 'h'}, + {0, 0, 0, 0}, +}; + +int main(int argc, char **argv) +{ + int opt, ret; + const char *filename; + + while ((opt = getopt_long(argc, argv, "hd", cbootcmd, NULL)) > 0) { + switch (opt) { + case 'h': + usage(argv[0]); + exit(0); + case 'd': + debug = 1; + break; + } + } + + if (argc == optind) { + usage(argv[0]); + exit(1); + } + + filename = argv[optind]; + + ret = upload_image(filename); + if (ret) + exit(1); + + exit(0); +} diff --git a/scripts/rkimage.c b/scripts/rkimage.c new file mode 100644 index 0000000000..551114ed82 --- /dev/null +++ b/scripts/rkimage.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <stdio.h> +#include <unistd.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <time.h> +#include <openssl/evp.h> +#include <errno.h> +#include <stdbool.h> + +#include "common.h" +#include "common.c" +#include "rockchip.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) +#define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) + +static void sha256(const void *buf, int len, void *out) +{ + EVP_MD_CTX *md_ctx; + + 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) +{ + EVP_MD_CTX *md_ctx; + + 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 { + HASH_TYPE_SHA256 = 1, + HASH_TYPE_SHA512 = 2, +} hash_type_t; + +struct rkcode { + const char *path; + size_t size; + void *buf; +}; + +static int n_code; +struct rkcode *code; + +static int create_newidb(struct newidb *idb) +{ + hash_type_t hash_type = HASH_TYPE_SHA256; + bool keep_cert = false; + int image_offset; + int i; + unsigned char *idbu8 = (void *)idb; + + idb->magic = NEWIDB_MAGIC; + idb->n_files = (n_code << 16) | (1 << 7) | (1 << 8); + + if (hash_type == HASH_TYPE_SHA256) + idb->hashtype = (1 << 0); + else if (hash_type == HASH_TYPE_SHA512) + idb->hashtype = (1 << 1); + + if (!keep_cert) + image_offset = 4; + else + image_offset = 8; + + for (i = 0; i < n_code; i++) { + struct newidb_entry *entry = &idb->entries[i]; + struct rkcode *c = &code[i]; + unsigned int image_sector; + + image_sector = c->size / SECTOR_SIZE; + + entry->sector = (image_sector << 16) + image_offset; + entry->unknown_ffffffff = 0xffffffff; + entry->image_number = i + 1; + + if (hash_type == HASH_TYPE_SHA256) + sha256(c->buf, c->size, entry->hash); /* File size padded to sector size */ + else if (hash_type == HASH_TYPE_SHA512) + sha512(c->buf, c->size, entry->hash); + + image_offset += image_sector; + + } + + if (hash_type == HASH_TYPE_SHA256) + sha256(idbu8, 1535, idbu8 + 1536); + else if (hash_type == HASH_TYPE_SHA512) + sha512(idbu8, 1535, idbu8 + 1536); + + return 0; +} + +struct option cbootcmd[] = { + {"help", 0, NULL, 'h'}, + {"o", 1, NULL, 'o'}, + {0, 0, 0, 0}, +}; + +static void usage(const char *prgname) +{ + printf( +"Usage: %s [OPTIONS] <FILES>\n" +"\n" +"Generate a Rockchip boot image from <FILES>\n" +"This tool is suitable for SoCs beginning with rk3568. Older SoCs\n" +"have a different image format.\n" +"\n" +"Options:\n" +" -o <file> Output image to <file>\n" +" -h This help\n", + prgname); +} + +int main(int argc, char *argv[]) +{ + int opt, i, fd; + const char *outfile = NULL; + struct newidb idb = {}; + + while ((opt = getopt_long(argc, argv, "ho:", cbootcmd, NULL)) > 0) { + switch (opt) { + case 'o': + outfile = optarg; + break; + case 'h': + usage(argv[0]); + exit(0); + } + } + + n_code = argc - optind; + if (!n_code) { + usage(argv[0]); + exit(1); + } + + code = calloc(n_code, sizeof(*code)); + if (!code) + exit(1); + + for (i = 0; i < n_code; i++) { + struct stat s; + int fd, ret; + struct rkcode *c = &code[i]; + const char *path = argv[i + optind]; + + fd = open(path, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", path, strerror(errno)); + exit(1); + } + + ret = fstat(fd, &s); + if (ret) + exit(1); + + c->path = path; + c->size = ALIGN(s.st_size, PAGE_SIZE); + c->buf = calloc(c->size, 1); + if (!c->buf) + exit(1); + + read_full(fd, c->buf, s.st_size); + close(fd); + } + + create_newidb(&idb); + + fd = creat(outfile, 0644); + if (fd < 0) { + fprintf(stderr, "Cannot open %s: %s\n", outfile, strerror(errno)); + exit(1); + } + + write_full(fd, &idb, sizeof(idb)); + + for (i = 0; i < n_code; i++) { + struct rkcode *c = &code[i]; + + write_full(fd, c->buf, c->size); + } + + close(fd); + + return 0; +} diff --git a/scripts/rockchip.h b/scripts/rockchip.h new file mode 100644 index 0000000000..8cc14f8f2f --- /dev/null +++ b/scripts/rockchip.h @@ -0,0 +1,35 @@ +#ifndef __ROCKCHIP_H +#define __ROCKCHIP_H + +#define NEWIDB_MAGIC 0x534e4b52 /* 'RKNS' */ + +struct newidb_entry { + uint32_t sector; + uint32_t unknown_ffffffff; + uint32_t unknown1; + uint32_t image_number; + unsigned char unknown2[8]; + unsigned char hash[64]; +}; + +struct newidb { + uint32_t magic; + unsigned char unknown1[4]; + uint32_t n_files; + uint32_t hashtype; + unsigned char unknown2[8]; + unsigned char unknown3[8]; + unsigned char unknown4[88]; + struct newidb_entry entries[4]; + unsigned char unknown5[40]; + unsigned char unknown6[512]; + unsigned char unknown7[16]; + unsigned char unknown8[32]; + unsigned char unknown9[464]; + unsigned char hash[512]; +}; + +#define SECTOR_SIZE 512 +#define PAGE_SIZE 2048 + +#endif /* __ROCKCHIP_H */ diff --git a/scripts/rsatoc.c b/scripts/rsatoc.c index 6473802140..d5943d4a11 100644 --- a/scripts/rsatoc.c +++ b/scripts/rsatoc.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +// SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-OpenSSL-exception /* * rsatoc - utility to convert an RSA key to a C struct * @@ -18,6 +18,8 @@ #include <openssl/evp.h> #include <openssl/engine.h> +static int dts, standalone; + static int rsa_err(const char *msg) { unsigned long sslErr = ERR_get_error(); @@ -56,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. */ @@ -184,8 +190,8 @@ cleanup: /* * rsa_get_params(): - Get the important parameters of an RSA public key */ -int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, - BIGNUM **modulusp, BIGNUM **r_squaredp) +static int rsa_get_params(RSA *key, uint64_t *exponent, uint32_t *n0_invp, + BIGNUM **modulusp, BIGNUM **r_squaredp) { BIGNUM *big1, *big2, *big32, *big2_32; BIGNUM *n, *r, *r_squared, *tmp; @@ -311,6 +317,7 @@ static int print_bignum(BIGNUM *num, int num_bits) BIGNUM *tmp, *big2, *big32, *big2_32; BN_CTX *ctx; int i; + uint32_t *arr; tmp = BN_new(); big2 = BN_new(); @@ -338,16 +345,35 @@ static int print_bignum(BIGNUM *num, int num_bits) BN_set_word(big32, 32L); BN_exp(big2_32, big2, big32, ctx); /* B = 2^32 */ + arr = malloc(num_bits / 32 * sizeof(uint32_t)); + for (i = 0; i < num_bits / 32; i++) { BN_mod(tmp, num, big2_32, ctx); /* n = N mod B */ - if (i % 4) - fprintf(outfilep, " "); - else - fprintf(outfilep, "\n\t"); - fprintf(outfilep, "0x%08lx,", BN_get_word(tmp)); + arr[i] = BN_get_word(tmp); BN_rshift(num, num, 32); /* N = N/B */ } + if (dts) { + for (i = 0; i < num_bits / 32; i++) { + if (i % 4) + fprintf(outfilep, " "); + else + fprintf(outfilep, "\n\t\t\t\t"); + fprintf(outfilep, "0x%08x", arr[num_bits / 32 - 1 - i]); + BN_rshift(num, num, 32); /* N = N/B */ + } + } else { + for (i = 0; i < num_bits / 32; i++) { + if (i % 4) + fprintf(outfilep, " "); + else + fprintf(outfilep, "\n\t"); + fprintf(outfilep, "0x%08x,", arr[i]); + BN_rshift(num, num, 32); /* N = N/B */ + } + } + + free(arr); BN_free(tmp); BN_free(big2); BN_free(big32); @@ -359,7 +385,7 @@ static int print_bignum(BIGNUM *num, int num_bits) static int gen_key(const char *keyname, const char *path) { BIGNUM *modulus, *r_squared; - uint64_t exponent; + uint64_t exponent = 0; uint32_t n0_inv; int ret; int bits; @@ -404,25 +430,49 @@ static int gen_key(const char *keyname, const char *path) bits = BN_num_bits(modulus); - fprintf(outfilep, "\nstatic uint32_t %s_modulus[] = {", key_name_c); - print_bignum(modulus, bits); - fprintf(outfilep, "\n};\n\n"); - - fprintf(outfilep, "static uint32_t %s_rr[] = {", key_name_c); - print_bignum(r_squared, bits); - fprintf(outfilep, "\n};\n\n"); - - 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"); + if (dts) { + fprintf(outfilep, "\t\tkey-%s {\n", key_name_c); + fprintf(outfilep, "\t\t\trsa,r-squared = <"); + print_bignum(r_squared, bits); + fprintf(outfilep, ">;\n"); + fprintf(outfilep, "\t\t\trsa,modulus= <"); + print_bignum(modulus, bits); + fprintf(outfilep, ">;\n"); + fprintf(outfilep, "\t\t\trsa,exponent = <0x%0lx 0x%lx>;\n", + (exponent >> 32) & 0xffffffff, + exponent & 0xffffffff); + fprintf(outfilep, "\t\t\trsa,n0-inverse = <0x%0x>;\n", n0_inv); + fprintf(outfilep, "\t\t\trsa,num-bits = <0x%0x>;\n", bits); + fprintf(outfilep, "\t\t\tkey-name-hint = \"%s\";\n", key_name_c); + fprintf(outfilep, "\t\t};\n"); + } else { + fprintf(outfilep, "\nstatic uint32_t %s_modulus[] = {", key_name_c); + print_bignum(modulus, bits); + fprintf(outfilep, "\n};\n\n"); + + fprintf(outfilep, "static uint32_t %s_rr[] = {", key_name_c); + print_bignum(r_squared, bits); + fprintf(outfilep, "\n};\n\n"); + + 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, "struct rsa_public_key *%sp __attribute__((section(\".rsa_keys.rodata.%s\"))) = &%s;\n", - key_name_c, key_name_c, 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"); + + 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; } @@ -435,11 +485,17 @@ int main(int argc, char *argv[]) outfilep = stdout; - while ((opt = getopt(argc, argv, "o:")) > 0) { + while ((opt = getopt(argc, argv, "o:ds")) > 0) { switch (opt) { case 'o': outfile = optarg; break; + case 'd': + dts = 1; + break; + case 's': + standalone = 1; + break; } } @@ -453,10 +509,24 @@ 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"); + 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++) { keyname = argv[i]; @@ -471,10 +541,12 @@ int main(int argc, char *argv[]) path++; if (!strncmp(path, "__ENV__", 7)) { - path = getenv(path + 7); + const char *orig_path = path; + + path = getenv(orig_path + 7); if (!path) { fprintf(stderr, "%s doesn't contain a path\n", - path + 7); + orig_path + 7); exit(1); } } @@ -482,5 +554,10 @@ int main(int argc, char *argv[]) gen_key(keyname, path); } + if (dts) { + fprintf(outfilep, "\t};\n"); + fprintf(outfilep, "};\n"); + } + exit(0); } diff --git a/scripts/s5p_cksum.c b/scripts/s5p_cksum.c index 06f51e3607..0f53ee1dd2 100644 --- a/scripts/s5p_cksum.c +++ b/scripts/s5p_cksum.c @@ -1,19 +1,5 @@ -/* - * Copyright (C) 2012 Alexey Galakhov - * - * See file CREDITS for list of people who contributed to this - * project. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 Alexey Galakhov #include <stdio.h> #include <stdint.h> 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 cce4706cc1..cbd3883df9 100755 --- a/scripts/setlocalversion +++ b/scripts/setlocalversion @@ -1,8 +1,14 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0 # # This scripts adds local version information from the version # control systems git, mercurial (hg) and subversion (svn). # +# If something goes wrong, send a mail the kernel build mailinglist +# (see MAINTAINERS) and CC Nico Schottelius +# <nico-linuxsetlocalversion -at- schottelius.org>. +# +# usage() { echo "Usage: $0 [--save-scmversion] [srctree]" >&2 @@ -38,11 +44,12 @@ scm_version() fi # Check for git and a git repo. - if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then + if test -z "$(git rev-parse --show-cdup 2>/dev/null)" && + head=$(git rev-parse --verify HEAD 2>/dev/null); then # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore # it, because this version is defined in the top level Makefile. - if [ -z "`git describe --exact-match 2>/dev/null`" ]; then + if [ -z "$(git describe --exact-match 2>/dev/null)" ]; then # If only the short version is requested, don't bother # running further git commands @@ -52,69 +59,36 @@ scm_version() fi # If we are past a tagged commit (like # "v2.6.30-rc5-302-g72357d5"), we pretty print it. - if atag="`git describe 2>/dev/null`"; then - echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' - - # If we don't have a tag at all we print -g{commitish}. - else - printf '%s%s' -g $head + if atag="$(git describe 2>/dev/null)"; then + echo "$atag" | awk -F- '{printf("-%05d", $(NF-1))}' fi - fi - # Is this git on svn? - if git config --get svn-remote.svn.url >/dev/null; then - printf -- '-svn%s' "`git svn find-rev $head`" + # Add -g and exactly 12 hex chars. + printf '%s%s' -g "$(echo $head | cut -c1-12)" fi - # Update index only on r/w media - [ -w . ] && git update-index --refresh --unmerged > /dev/null - - # Check for uncommitted changes - if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then + # Check for uncommitted changes. + # This script must avoid any write attempt to the source tree, + # which might be read-only. + # You cannot use 'git describe --dirty' because it tries to + # create .git/index.lock . + # First, with git-status, but --no-optional-locks is only + # supported in git >= 2.14, so fall back to git-diff-index if + # it fails. Note that git-diff-index does not refresh the + # index, so it may give misleading results. See + # git-update-index(1), git-diff-index(1), and git-status(1). + if { + git --no-optional-locks status -uno --porcelain 2>/dev/null || + git diff-index --name-only HEAD + } | read dummy; then printf '%s' -dirty fi - - # All done with git - return - fi - - # Check for mercurial and a mercurial repo. - if test -d .hg && hgid=`hg id 2>/dev/null`; then - # Do we have an tagged version? If so, latesttagdistance == 1 - if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then - id=`hg log -r . --template '{latesttag}'` - printf '%s%s' -hg "$id" - else - tag=`printf '%s' "$hgid" | cut -d' ' -f2` - if [ -z "$tag" -o "$tag" = tip ]; then - id=`printf '%s' "$hgid" | sed 's/[+ ].*//'` - printf '%s%s' -hg "$id" - fi - fi - - # Are there uncommitted changes? - # These are represented by + after the changeset id. - case "$hgid" in - *+|*+\ *) printf '%s' -dirty ;; - esac - - # All done with mercurial - return - fi - - # Check for svn and a svn repo. - if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then - rev=`echo $rev | awk '{print $NF}'` - printf -- '-svn%s' "$rev" - - # All done with svn - return fi } collect_files() { - local file res + local file res= for file; do case "$file" in @@ -137,13 +111,14 @@ if $scm_only; then exit fi -if test -e include/config/auto.conf; then - . include/config/auto.conf -else - echo "Error: kernelrelease not valid - run 'make prepare' to update it" +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 @@ -151,21 +126,22 @@ 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)" -else - # append a plus sign if the repository is not in a clean - # annotated or signed tagged state (as git describe only - # looks at signed or annotated tags - git tag -a/-s) and - # LOCALVERSION= is not specified - if test "${LOCALVERSION+set}" != "set"; then - scm=$(scm_version --short) - res="$res${scm:++}" - fi +elif [ "${LOCALVERSION+set}" != "set" ]; then + # If the variable LOCALVERSION is not set, append a plus + # sign if the repository is not in a clean annotated or + # signed tagged state (as git describe only looks at signed + # or annotated tags - git tag -a/-s). + # + # If the variable LOCALVERSION is set (including being set + # to an empty string), we don't want to append a plus sign. + scm=$(scm_version --short) + res="$res${scm:++}" fi echo "$res" diff --git a/scripts/setupmbr/.gitignore b/scripts/setupmbr/.gitignore deleted file mode 100644 index a7301f9111..0000000000 --- a/scripts/setupmbr/.gitignore +++ /dev/null @@ -1 +0,0 @@ -setupmbr diff --git a/scripts/setupmbr/Makefile b/scripts/setupmbr/Makefile deleted file mode 100644 index 8680fedce7..0000000000 --- a/scripts/setupmbr/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -HOST_EXTRACFLAGS=-I$(srctree) - -hostprogs-y := setupmbr -always := $(hostprogs-y) diff --git a/scripts/setupmbr/arch.h b/scripts/setupmbr/arch.h deleted file mode 100644 index a720dfe95e..0000000000 --- a/scripts/setupmbr/arch.h +++ /dev/null @@ -1,55 +0,0 @@ - -/* we need the one from the host */ -#include <endian.h> -#include <stdint.h> - -/* Byte-orders. */ -#define swap16(x) \ -({ \ - uint16_t _x = (x); \ - (uint16_t) ((_x << 8) | (_x >> 8)); \ -}) - -#define swap32(x) \ -({ \ - uint32_t _x = (x); \ - (uint32_t) ((_x << 24) \ - | ((_x & (uint32_t) 0xFF00UL) << 8) \ - | ((_x & (uint32_t) 0xFF0000UL) >> 8) \ - | (_x >> 24)); \ -}) - -#define swap64(x) \ -({ \ - uint64_t _x = (x); \ - (uint64_t) ((_x << 56) \ - | ((_x & (uint64_t) 0xFF00ULL) << 40) \ - | ((_x & (uint64_t) 0xFF0000ULL) << 24) \ - | ((_x & (uint64_t) 0xFF000000ULL) << 8) \ - | ((_x & (uint64_t) 0xFF00000000ULL) >> 8) \ - | ((_x & (uint64_t) 0xFF0000000000ULL) >> 24) \ - | ((_x & (uint64_t) 0xFF000000000000ULL) >> 40) \ - | (_x >> 56)); \ -}) - -#if __BYTE_ORDER == __BIG_ENDIAN - -/* Our target is a ia32 machine, always little endian */ - -# define host2target_16(x) swap16(x) -# define host2target_32(x) swap32(x) -# define host2target_64(x) swap64(x) -# define target2host_16(x) swap16(x) -# define target2host_32(x) swap32(x) -# define target2host_64(x) swap64(x) - -#else - -# define host2target_16(x) (x) -# define host2target_32(x) (x) -# define host2target_64(x) (x) -# define target2host_16(x) (x) -# define target2host_32(x) (x) -# define target2host_64(x) (x) - -#endif diff --git a/scripts/setupmbr/setupmbr.c b/scripts/setupmbr/setupmbr.c deleted file mode 100644 index 1487498f1f..0000000000 --- a/scripts/setupmbr/setupmbr.c +++ /dev/null @@ -1,558 +0,0 @@ -/* - * Copyright (C) 2009 Juergen Beisert, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - */ - -/** - * @file - * @brief Write the barebox binary to the MBR and the following disk sectors - * - * Also patch dedicated locations in the image to make it work at runtime - * - * Current restrictions are: - * - only installs into MBR and the sectors after it - * - tested only with QEMU - * - and maybe some others - */ - -#include <stdio.h> -#include <stdlib.h> -#include <stdint.h> -#include <sys/mman.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <assert.h> - -/* include the info from this barebox release */ -#include "../../include/generated/utsrelease.h" -#include "../../arch/x86/mach-i386/include/mach/barebox.lds.h" - -/** define to disable integrity tests and debug messages */ -#define NDEBUG - -/* some infos about our target architecture */ -#include "arch.h" - -/** - * "Disk Address Packet Structure" to be used when calling int13, - * function 0x42 - * - * @note All entries are in target endianess - */ -struct DAPS -{ - uint8_t size; /**< size of this data set, 0 marks it as invalid */ - uint8_t res1; /**< always 0 */ - int8_t count; /**< number of sectors 0...127 to handle */ - uint8_t res2; /**< always 0 */ - uint16_t offset; /**< store address: offset */ - uint16_t segment; /**< store address: segment */ - uint64_t lba; /**< start sector number in LBA */ -} __attribute__ ((packed)); - -/** - * Description of one partition table entry (D*S type) - * - * @note All entries are in target endianess - */ -struct partition_entry { - uint8_t boot_indicator; - uint8_t chs_begin[3]; - uint8_t type; - uint8_t chs_end[3]; - uint32_t partition_start; /* LE */ - uint32_t partition_size; /* LE */ -} __attribute__ ((packed)); - -#ifndef NDEBUG -static void debugout(const struct DAPS *entry, int supress_entry) -{ - if (supress_entry) - printf("DAPS entry: "); - else - printf("DAPS entry % 3u: ", ((unsigned)entry & ( SECTOR_SIZE - 1)) / sizeof(struct DAPS)); - - printf("Size: % 2u, Count: % 3d, Offset: 0x%04hX, Segment: 0x%04hX, LBA: %llu\n", - entry->size, entry->count, - target2host_16(entry->offset), target2host_16(entry->segment), - target2host_64(entry->lba)); -} -#else -# define debugout(x,y) (__ASSERT_VOID_CAST(0)) -#endif - -/** - * Fill *one* DAPS - * @param sector The DAPS to fill - * @param count Sector count - * @param offset Realmode offset in the segment - * @param segment Real mode segment - * @param lba LBA of the first sector to read - * @return 0 on success - */ -static int fill_daps(struct DAPS *sector, unsigned count, unsigned offset, unsigned segment, uint64_t lba) -{ - assert(sector != NULL); - assert(count < 128); - assert(offset < 0x10000); - assert(segment < 0x10000); - - sector->size = sizeof(struct DAPS); - sector->res1 = 0; - sector->count = (int8_t)count; - sector->res2 = 0; - sector->offset = host2target_16(offset); - sector->segment = host2target_16(segment); - sector->lba = host2target_64(lba); - - return 0; -} - -/** - * Mark a DAPS invalid to let the boot loader code stop at this entry. - * @param sector The DAPS to be marked as invalid - * - * Marking as invalid must be done in accordance to the detection method - * the assembler routine in the boot loader uses: - * The current code tests for zero in the first two bytes of the DAPS. - */ -static void invalidate_daps(struct DAPS *sector) -{ - sector->size = MARK_DAPS_INVALID; - sector->res1 = 0; -} - -/** - * Create the indirect sector with the DAPS entries - * @param daps_table Where to store the entries - * @param size Size of the whole image in bytes - * @param pers_sector_count Count of sectors to skip after MBR for the persistent environment storage - * @return 0 on success - * - * This routine calculates the DAPS entries for the case the whole - * barebox images fits into the MBR itself and the sectors after it. - * This means the start of the first partition must keep enough sectors - * unused. - * It also skips 'pers_sector_count' sectors after the MBR for special - * usage if given. - */ -static int barebox_linear_image(struct DAPS *daps_table, off_t size, long pers_sector_count) -{ - unsigned offset = LOAD_AREA, next_offset; - unsigned segment = LOAD_SEGMENT; - unsigned chunk_size, i = 0; - uint64_t lba = 2 + pers_sector_count; - int rc; - - /* - * We can load up to 127 sectors in one chunk. What a bad number... - * So, we will load in chunks of 32 kiB. - */ - - /* at runtime two sectors from the image are already loaded: MBR and indirect */ - size -= 2 * SECTOR_SIZE; - /* and now round up to multiple of sector size */ - size = (size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE - 1); - - /* - * The largest image we can load with this method is: - * (SECTOR_SIZE / sizeof(DAPS) - 1) * 32 kiB - * For a 512 byte sector and a 16 byte DAPS: - * (512 / 16 - 1) * 32 kiB = 992 kiB - * Note: '- 1' to consider one entry is required to pad to a 32 kiB boundary - */ - - if (size >= (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32 * 1024) { - fprintf(stderr, "Image too large to boot. Max size is %zu kiB, image size is %lu kiB\n", - (SECTOR_SIZE / sizeof(struct DAPS) - 1) * 32, size / 1024); - return -1; - } - - if (size > 32 * 1024) { - /* first fill up until the next 32 k boundary */ - next_offset = (offset + 32 * 1024 -1) & ~0x7fff; - chunk_size = next_offset - offset; - if (chunk_size & (SECTOR_SIZE-1)) { - fprintf(stderr, "Unable to pad from %X to %X in multiple of sectors\n", offset, next_offset); - return -1; - } - - rc = fill_daps(&daps_table[i], chunk_size / SECTOR_SIZE, offset, segment, lba); - if (rc != 0) - return -1; - debugout(&daps_table[i], 0); - - /* calculate values to enter the loop for the other entries */ - size -= chunk_size; - i++; - lba += chunk_size / SECTOR_SIZE; - offset += chunk_size; - if (offset >= 0x10000) { - segment += 4096; - offset = 0; - } - - /* - * Now load the remaining image part in 32 kiB chunks - */ - while (size) { - if (size >= 32 * 1024 ) { - if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { - fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); - return -1; - } - rc = fill_daps(&daps_table[i], 64, offset, segment, lba); - if (rc != 0) - return -1; - debugout(&daps_table[i], 0); - - size -= 32 * 1024; - lba += 64; - offset += 32 * 1024; - if (offset >= 0x10000) { - segment += 4096; - offset = 0; - } - i++; - } else { - if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) { - fprintf(stderr, "Internal tool error: Too many DAPS entries!\n"); - return -1; - } - rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); - if (rc != 0) - return -1; - debugout(&daps_table[i], 0); - size = 0; /* finished */ - i++; - } - }; - } else { - /* less than 32 kiB. Very small image... */ - rc = fill_daps(&daps_table[i], size / SECTOR_SIZE, offset, segment, lba); - if (rc != 0) - return -1; - debugout(&daps_table[i], 0); - i++; - } - - /* - * Do not mark an entry as invalid if the buffer is full. The - * boot code stops if all entries of a buffer are read. - */ - if (i >= (SECTOR_SIZE / sizeof(struct DAPS))) - return 0; - - /* mark the last DAPS invalid */ - invalidate_daps(&daps_table[i]); - debugout(&daps_table[i], 0); - - return 0; -} - -/** - * Do some simple sanity checks if this sector could be an MBR - * @param sector Sector with data to check - * @param size Size of the buffer - * @return 0 if successfull - */ -static int check_for_valid_mbr(const uint8_t *sector, off_t size) -{ - if (size < SECTOR_SIZE) { - fprintf(stderr, "MBR too small to be valid\n"); - return -1; - } - - if ((sector[OFFSET_OF_SIGNATURE] != 0x55) || - (sector[OFFSET_OF_SIGNATURE + 1] != 0xAA)) { - fprintf(stderr, "No MBR signature found\n"); - return -1; - } - - /* FIXME: try to check if there is a valid partition table */ - return 0; -} - -/** - * Check space between start of the image and the start of the first partition - * @param hd_image HD image to examine - * @param size Size of the barebox image - * @return 0 on success, -1 if the barebox image is too large - */ -static int check_for_space(const void *hd_image, off_t size) -{ - struct partition_entry *partition; - uint8_t *mbr_disk_sector = (uint8_t*)hd_image; - off_t spare_sector_count; - - assert(hd_image != NULL); - assert(size > 0); - - if (check_for_valid_mbr(hd_image, size) != 0) - return -1; - - /* where to read */ - partition = (struct partition_entry*) &mbr_disk_sector[OFFSET_OF_PARTITION_TABLE]; - - /* TODO describes the first entry always the first partition? */ - spare_sector_count = target2host_32(partition->partition_start); - -#ifdef DEBUG - printf("Debug: Required free sectors for barebox prior first partition: %lu, hd image provides: %lu\n", - (size + SECTOR_SIZE - 1) / SECTOR_SIZE, spare_sector_count); -#endif - spare_sector_count *= SECTOR_SIZE; - if (spare_sector_count < size) { - fprintf(stderr, "Not enough space after MBR to store barebox\n"); - fprintf(stderr, "Move begin of the first partition beyond sector %lu\n", (size + SECTOR_SIZE - 1) / SECTOR_SIZE); - return -1; - } - - return 0; -} - -/** - * Setup the persistent environment storage information - * @param patch_area Where to patch - * @param pers_sector_start Start sector of the persistent environment storage - * @param pers_sector_count Count of sectors for the persistent environment storage - * @return 0 on success - */ -static int store_pers_env_info(void *patch_area, uint64_t pers_sector_start, long pers_sector_count) -{ - uint64_t *start_lba = (uint64_t*)(patch_area + PATCH_AREA_PERS_START); - uint16_t *count_lba = (uint16_t*)(patch_area + PATCH_AREA_PERS_SIZE); - - assert(patch_area != NULL); - assert(pers_sector_count >= 0); - - if (pers_sector_count == 0) { - *count_lba = host2target_16(PATCH_AREA_PERS_SIZE_UNUSED); - return 0; - } - - *start_lba = host2target_64(pers_sector_start); - *count_lba = host2target_16(pers_sector_count); - - return 0; -} - -/** - * Prepare the MBR and indirect sector for runtime - * @param fd_barebox barebox image to use - * @param fd_hd Hard disk image to prepare - * @param pers_sector_count Count of sectors to skip after MBR for the persistent environment storage - * @return 0 on success - * - * This routine expects a prepared hard disk image file with a partition table - * in its first sector. This method only is currently supported. - */ -static int barebox_overlay_mbr(int fd_barebox, int fd_hd, long pers_sector_count) -{ - const void *barebox_image; - void *hd_image; - int rc; - struct stat sb; - struct DAPS *embed; /* part of the MBR */ - struct DAPS *indirect; /* sector with indirect DAPS */ - off_t required_size; - - if (fstat(fd_barebox, &sb) == -1) { - perror("fstat"); - return -1; - } - - /* the barebox image won't be touched */ - barebox_image = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd_barebox, 0); - if (barebox_image == MAP_FAILED) { - perror("mmap"); - return -1; - } - - rc = check_for_valid_mbr(barebox_image, sb.st_size); - if (rc != 0) { - fprintf(stderr, "barebox image seems not valid: Bad MBR signature\n"); - goto on_error_hd; - } - - /* - * the persistent environment storage is in front of the main - * barebox image. To handle both, we need more space in front of the - * the first partition. - */ - required_size = sb.st_size + pers_sector_count * SECTOR_SIZE; - - /* the hd image will be modified */ - hd_image = mmap(NULL, required_size, PROT_READ | PROT_WRITE, - MAP_SHARED, fd_hd, 0); - if (hd_image == MAP_FAILED) { - perror("mmap"); - rc = -1; - goto on_error_hd; - } - - /* check for space */ - rc = check_for_space(hd_image, required_size); - if (rc != 0) - goto on_error_space; - - /* embed barebox's boot code into the disk drive image */ - memcpy(hd_image, barebox_image, OFFSET_OF_PARTITION_TABLE); - - /* - * embed the barebox main image into the disk drive image, - * but keep the persistent environment storage untouched - * (if defined), e.g. store the main image behind this special area. - */ - memcpy(hd_image + ((pers_sector_count + 1) * SECTOR_SIZE), - barebox_image + SECTOR_SIZE, sb.st_size - SECTOR_SIZE); - - /* now, prepare this hard disk image for BIOS based booting */ - embed = hd_image + PATCH_AREA; - indirect = hd_image + ((pers_sector_count + 1) * SECTOR_SIZE); - - /* - * Fill the embedded DAPS to let the basic boot code find the - * indirect sector at runtime - */ -#ifdef DEBUG - printf("Debug: Fill in embedded DAPS\n"); -#endif - rc = fill_daps(embed, 1, INDIRECT_AREA, INDIRECT_SEGMENT, - 1 + pers_sector_count); - if (rc != 0) - goto on_error_space; - debugout(embed, 1); - -#ifdef DEBUG - printf("Debug: Fill in indirect sector\n"); -#endif - /* - * fill the indirect sector with the remaining DAPS to load the - * whole barebox image at runtime - */ - rc = barebox_linear_image(indirect, sb.st_size, pers_sector_count); - if (rc != 0) - goto on_error_space; - - /* - * TODO: Replace the fixed LBA starting number by a calculated one, - * to support barebox as a chained loader in a different start - * sector than the MBR - */ - rc = store_pers_env_info(embed, 1, pers_sector_count); - if (rc != 0) - goto on_error_space; - -on_error_space: - munmap(hd_image, required_size); - -on_error_hd: - munmap((void*)barebox_image, sb.st_size); - - return rc; -} - -static void print_usage(const char *pname) -{ - printf("%s: Preparing a hard disk image for boot with barebox on x86.\n", pname); - printf("Usage is\n %s [options] -m <barebox image> -d <hd image>\n", pname); - printf(" [options] are:\n -s <count> sector count of the persistent environment storage\n"); - printf(" <barebox image> barebox's boot image file\n"); - printf(" <hd image> HD image to store the barebox image\n"); - printf(" If no '-s <x>' was given, barebox occupies sectors 0 to n, else sector 0 and x+1 to n\n"); -} - -int main(int argc, char *argv[]) -{ - int rc = 0, c; - char *barebox_image_filename = NULL, *hd_image_filename = NULL; - int fd_barebox_image = 0, fd_hd_image = 0; - long barebox_pers_size = -1; - - if (argc == 1) { - print_usage(argv[0]); - exit(0); - } - - /* handle command line options first */ - while (1) { - c = getopt(argc, argv, "m:d:s:hv"); - if (c == -1) - break; - - switch (c) { - case 's': - barebox_pers_size = strtol(optarg, NULL, 0); - break; - case 'm': - barebox_image_filename = strdup(optarg); - break; - case 'd': - hd_image_filename = strdup(optarg); - break; - case 'h': - print_usage(argv[0]); - rc = 0; - goto on_error; - case 'v': - printf("setupmbr for u-boot-v%s\n", UTS_RELEASE); - printf("Send bug reports to 'barebox@lists.infradead.org'\n"); - rc = 0; - goto on_error; - } - } - - if (barebox_image_filename == NULL) { - print_usage(argv[0]); - rc = -1; - goto on_error; - } - - fd_barebox_image = open(barebox_image_filename, O_RDONLY); - if (fd_barebox_image == -1) { - fprintf(stderr, "Cannot open '%s' for reading\n", - barebox_image_filename); - rc = -1; - goto on_error; - } - - fd_hd_image = open(hd_image_filename, O_RDWR); - if (fd_hd_image == -1) { - fprintf(stderr, "Cannot open '%s'\n", hd_image_filename); - rc = -1; - goto on_error; - } - - if (barebox_pers_size < 0) - barebox_pers_size = 0; - - rc = barebox_overlay_mbr(fd_barebox_image, fd_hd_image, barebox_pers_size); - -on_error: - if (fd_barebox_image != -1) - close(fd_barebox_image); - if (fd_hd_image != -1) - close(fd_hd_image); - - if (barebox_image_filename != NULL) - free(barebox_image_filename); - if (hd_image_filename != NULL) - free(hd_image_filename); - - return rc; -} diff --git a/scripts/socfpga_get_sequencer b/scripts/socfpga_get_sequencer index 36f67498bc..d21791eee9 100755 --- a/scripts/socfpga_get_sequencer +++ b/scripts/socfpga_get_sequencer @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash if [ "$#" -lt "2" ] then @@ -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 6c748fadb8..e917dcafef 100755 --- a/scripts/socfpga_import_preloader +++ b/scripts/socfpga_import_preloader @@ -1,16 +1,70 @@ -#!/bin/bash +#!/usr/bin/env bash + +usage() { + echo "USAGE: $0 + parameters: + -s|--spl-dir <SPL_GENERATED_DIR> + -i|--isw-handoff <ISW_HANDOFF> + -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/" + exit 1 +} -if [ "$#" -lt "2" ] -then - echo "USAGE: $0 <EMBEDDED_SDK> <ISW_HANDOFF> <BOARD_DIRECTORY>" - echo "EXAMPLE: $0 ~/altera-embedded-sdk/ ~/cv_soc_devkit_ghrd/hps_isw_handoff/soc_system_hps_0/ arch/arm/boards/altera-socdk" +die() { + printf '%s\n' "$1" >&2 exit 1 -fi +} + +generate= +splroot= +embeddedsw= +handoff= +boardroot= + +while :; do + case $1 in + -e|--embedded-sdk) + if [ "$2" ]; then + generate=1 + splroot="$(mktemp -d)" + embeddedsw=${2} + shift + else + die 'ERROR: "--embedded-sdk" requires a non-empty option argument.' + fi + ;; + -s|--spl-dir) + if [ "$2" ]; then + splroot="$2" + shift + else + die 'ERROR: "--spl-dir" requires a non-empty option argument.' + fi + ;; + -i|--isw-handoff) + if [ "$2" ]; then + handoff="$2" + shift + else + die 'ERROR: "--isw-handoff" requires a non-empty option argument.' + fi + ;; + -b|--board) + if [ "$2" ]; then + boardroot="$2" + shift + else + die 'ERROR: "--board" requires a non-empty option argument.' + fi + ;; + *) + break + esac + shift +done -splroot="$(mktemp -d)" -embeddedsw=$1 -handoff=$2 -boardroot=$3 bareboxsrc=. cd ${bareboxsrc} @@ -25,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..." @@ -45,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 @@ -57,7 +114,20 @@ copy_source() { sed -i 's/ $//g' $tgt } -python2.7 ${embeddedsw}/embedded/ip/altera/preloader/scripts/iswgen.py -i ${handoff} -o ${splroot}/ +generate_spl() { + 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 + usage +fi + +if [ $generate ]; then + generate_spl +fi copy_source ${splroot}/iocsr_config_cyclone5.c ${boardroot}/iocsr_config_cyclone5.c copy_source ${splroot}/pinmux_config_cyclone5.c ${boardroot}/pinmux_config.c @@ -69,6 +139,8 @@ copy_source ${handoff}/sequencer_auto_ac_init.c ${boardroot}/sequencer_auto_ac_i copy_source ${handoff}/sequencer_auto_inst_init.c ${boardroot}/sequencer_auto_inst_init.c copy_source ${handoff}/sequencer_defines.h ${boardroot}/sequencer_defines.h -rm -r ${splroot} +if [ $generate ]; then + rm -r ${splroot} +fi echo "DONE" diff --git a/scripts/socfpga_mkimage.c b/scripts/socfpga_mkimage.c index 03150cce8d..0878c3f261 100644 --- a/scripts/socfpga_mkimage.c +++ b/scripts/socfpga_mkimage.c @@ -10,6 +10,10 @@ #include <fcntl.h> #include <endian.h> +#include "common.h" +#include "common.c" +#include "../crypto/crc32.c" + #define VALIDATION_WORD 0x31305341 #define BRANCH_INST 0xea /* ARM opcode for "b" (unconditional branch) */ @@ -65,98 +69,6 @@ static uint32_t bb_header[] = { 0xea00006b, /* entry. b 0x200 (offset may be adjusted) */ }; -static int read_full(int fd, void *buf, size_t size) -{ - size_t insize = size; - int now; - int total = 0; - - while (size) { - now = read(fd, buf, size); - if (now == 0) - return total; - if (now < 0) - return now; - total += now; - size -= now; - buf += now; - } - - return insize; -} - -static int write_full(int fd, void *buf, size_t size) -{ - size_t insize = size; - int now; - - while (size) { - now = write(fd, buf, size); - if (now <= 0) - return now; - size -= now; - buf += now; - } - - return insize; -} - -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 -}; - -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. */ @@ -248,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; @@ -381,17 +293,9 @@ int main(int argc, char *argv[]) if (ret) exit(1); - fd = open(outfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) { - perror("open outfile"); - exit(1); - } - - ret = write_full(fd, buf, s.st_size + 4 + addsize + pad); - if (ret < 0) { - perror("write outfile"); + ret = write_file(outfile, buf, s.st_size + 4 + addsize + pad); + if (ret) exit(1); - } exit(0); } diff --git a/scripts/socfpga_xml_to_config.sh b/scripts/socfpga_xml_to_config.sh index 7e22ebb9e8..2ec2788865 100755 --- a/scripts/socfpga_xml_to_config.sh +++ b/scripts/socfpga_xml_to_config.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash ## TODO: ## - read in mpuclk and nocclk, must be calculated by hand at the moment @@ -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/spdxcheck.py b/scripts/spdxcheck.py index 723bfa4ebf..0f81337394 100755 --- a/scripts/spdxcheck.py +++ b/scripts/spdxcheck.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0 # Copyright Thomas Gleixner <tglx@linutronix.de> @@ -32,7 +32,8 @@ class SPDXdata(object): def read_spdxdata(repo): # The subdirectories of LICENSES in the kernel source - license_dirs = [ "preferred" ] + # Note: exceptions needs to be parsed as last directory. + license_dirs = [ "preferred", "dual", "deprecated", "exceptions" ] lictree = repo.head.commit.tree['LICENSES'] spdx = SPDXdata() @@ -58,13 +59,13 @@ def read_spdxdata(repo): elif l.startswith('SPDX-Licenses:'): for lic in l.split(':')[1].upper().strip().replace(' ', '').replace('\t', '').split(','): if not lic in spdx.licenses: - raise SPDXException(None, 'Exception %s missing license %s' %(ex, lic)) + raise SPDXException(None, 'Exception %s missing license %s' %(exception, lic)) spdx.exceptions[exception].append(lic) elif l.startswith("License-Text:"): if exception: if not len(spdx.exceptions[exception]): - raise SPDXException(el, 'Exception %s is missing SPDX-Licenses' %excid) + raise SPDXException(el, 'Exception %s is missing SPDX-Licenses' %exception) spdx.exception_files += 1 else: spdx.license_files += 1 diff --git a/scripts/stb_image.h b/scripts/stb_image.h new file mode 100644 index 0000000000..cad4fe2901 --- /dev/null +++ b/scripts/stb_image.h @@ -0,0 +1,7752 @@ +/* stb_image - v2.26 - public domain image loader - http://nothings.org/stb + no warranty implied; use at your own risk + + Do this: + #define STB_IMAGE_IMPLEMENTATION + before you include this file in *one* C or C++ file to create the implementation. + + // i.e. it should look like this: + #include ... + #include ... + #include ... + #define STB_IMAGE_IMPLEMENTATION + #include "stb_image.h" + + You can #define STBI_ASSERT(x) before the #include to avoid using assert.h. + And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free + + + QUICK NOTES: + Primarily of interest to game developers and other people who can + avoid problematic images and only need the trivial interface + + JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib) + PNG 1/2/4/8/16-bit-per-channel + + TGA (not sure what subset, if a subset) + BMP non-1bpp, non-RLE + PSD (composited view only, no extra channels, 8/16 bit-per-channel) + + GIF (*comp always reports as 4-channel) + HDR (radiance rgbE format) + PIC (Softimage PIC) + PNM (PPM and PGM binary only) + + Animated GIF still needs a proper API, but here's one way to do it: + http://gist.github.com/urraka/685d9a6340b26b830d49 + + - decode from memory or through FILE (define STBI_NO_STDIO to remove code) + - decode from arbitrary I/O callbacks + - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON) + + Full documentation under "DOCUMENTATION" below. + + +LICENSE + + See end of file for license information. + +RECENT REVISION HISTORY: + + 2.26 (2020-07-13) many minor fixes + 2.25 (2020-02-02) fix warnings + 2.24 (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically + 2.23 (2019-08-11) fix clang static analysis warning + 2.22 (2019-03-04) gif fixes, fix warnings + 2.21 (2019-02-25) fix typo in comment + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings + 2.16 (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes + 2.15 (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-12-04) experimental 16-bit API, only for PNG so far; fixes + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64 + RGB-format JPEG; remove white matting in PSD; + allocate large structures on the stack; + correct channel count for PNG & BMP + 2.10 (2016-01-22) avoid warning introduced in 2.09 + 2.09 (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED + + See end of file for full revision history. + + + ============================ Contributors ========================= + + Image formats Extensions, features + Sean Barrett (jpeg, png, bmp) Jetro Lauha (stbi_info) + Nicolas Schulz (hdr, psd) Martin "SpartanJ" Golini (stbi_info) + Jonathan Dummer (tga) James "moose2000" Brown (iPhone PNG) + Jean-Marc Lienher (gif) Ben "Disch" Wenger (io callbacks) + Tom Seddon (pic) Omar Cornut (1/2/4-bit PNG) + Thatcher Ulrich (psd) Nicolas Guillemot (vertical flip) + Ken Miller (pgm, ppm) Richard Mitton (16-bit PSD) + github:urraka (animated gif) Junggon Kim (PNM comments) + Christopher Forseth (animated gif) Daniel Gibson (16-bit TGA) + socks-the-fox (16-bit PNG) + Jeremy Sawicki (handle all ImageNet JPGs) + Optimizations & bugfixes Mikhail Morozov (1-bit BMP) + Fabian "ryg" Giesen Anael Seghezzi (is-16-bit query) + Arseny Kapoulkine + John-Mark Allen + Carmelo J Fdez-Aguera + + Bug & warning fixes + Marc LeBlanc David Woo Guillaume George Martins Mozeiko + Christpher Lloyd Jerry Jansson Joseph Thomson Blazej Dariusz Roszkowski + Phil Jordan Dave Moore Roy Eltham + Hayaki Saito Nathan Reed Won Chun + Luke Graham Johan Duparc Nick Verigakis the Horde3D community + Thomas Ruf Ronny Chevalier github:rlyeh + Janez Zemva John Bartholomew Michal Cichon github:romigrou + Jonathan Blow Ken Hamada Tero Hanninen github:svdijk + Laurent Gomila Cort Stratton github:snagar + Aruelien Pocheville Sergio Gonzalez Thibault Reuille github:Zelex + Cass Everitt Ryamond Barbiero github:grim210 + Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw + Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus + Josh Tobin Matthew Gregan github:poppolopoppo + Julian Raschke Gregory Mullen Christian Floisand github:darealshinji + Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 + Brad Weinberger Matvey Cherevko [reserved] + Luca Sas Alexander Veselov Zack Middleton [reserved] + Ryan C. Gordon [reserved] [reserved] + DO NOT ADD YOUR NAME HERE + + To add your name to the credits, pick a random blank space in the middle and fill it. + 80% of merge conflicts on stb PRs are due to people adding their name at the end + of the credits. +*/ + +#ifndef STBI_INCLUDE_STB_IMAGE_H +#define STBI_INCLUDE_STB_IMAGE_H + +// DOCUMENTATION +// +// Limitations: +// - no 12-bit-per-channel JPEG +// - no JPEGs with arithmetic coding +// - GIF always returns *comp=4 +// +// Basic usage (see HDR discussion below for HDR usage): +// int x,y,n; +// unsigned char *data = stbi_load(filename, &x, &y, &n, 0); +// // ... process data if not NULL ... +// // ... x = width, y = height, n = # 8-bit components per pixel ... +// // ... replace '0' with '1'..'4' to force that many components per pixel +// // ... but 'n' will always be the number that it would have been if you said 0 +// stbi_image_free(data) +// +// Standard parameters: +// int *x -- outputs image width in pixels +// int *y -- outputs image height in pixels +// int *channels_in_file -- outputs # of image components in image file +// int desired_channels -- if non-zero, # of image components requested in result +// +// The return value from an image loader is an 'unsigned char *' which points +// to the pixel data, or NULL on an allocation failure or if the image is +// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels, +// with each pixel consisting of N interleaved 8-bit components; the first +// pixel pointed to is top-left-most in the image. There is no padding between +// image scanlines or between pixels, regardless of format. The number of +// components N is 'desired_channels' if desired_channels is non-zero, or +// *channels_in_file otherwise. If desired_channels is non-zero, +// *channels_in_file has the number of components that _would_ have been +// output otherwise. E.g. if you set desired_channels to 4, you will always +// get RGBA output, but you can check *channels_in_file to see if it's trivially +// opaque because e.g. there were only 3 channels in the source image. +// +// An output image with N components has the following components interleaved +// in this order in each pixel: +// +// N=#comp components +// 1 grey +// 2 grey, alpha +// 3 red, green, blue +// 4 red, green, blue, alpha +// +// If image loading fails for any reason, the return value will be NULL, +// and *x, *y, *channels_in_file will be unchanged. The function +// stbi_failure_reason() can be queried for an extremely brief, end-user +// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS +// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly +// more user-friendly ones. +// +// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized. +// +// =========================================================================== +// +// UNICODE: +// +// If compiling for Windows and you wish to use Unicode filenames, compile +// with +// #define STBI_WINDOWS_UTF8 +// and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert +// Windows wchar_t filenames to utf8. +// +// =========================================================================== +// +// Philosophy +// +// stb libraries are designed with the following priorities: +// +// 1. easy to use +// 2. easy to maintain +// 3. good performance +// +// Sometimes I let "good performance" creep up in priority over "easy to maintain", +// and for best performance I may provide less-easy-to-use APIs that give higher +// performance, in addition to the easy-to-use ones. Nevertheless, it's important +// to keep in mind that from the standpoint of you, a client of this library, +// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all. +// +// Some secondary priorities arise directly from the first two, some of which +// provide more explicit reasons why performance can't be emphasized. +// +// - Portable ("ease of use") +// - Small source code footprint ("easy to maintain") +// - No dependencies ("ease of use") +// +// =========================================================================== +// +// I/O callbacks +// +// I/O callbacks allow you to read from arbitrary sources, like packaged +// files or some other source. Data read from callbacks are processed +// through a small internal buffer (currently 128 bytes) to try to reduce +// overhead. +// +// The three functions you must define are "read" (reads some bytes of data), +// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end). +// +// =========================================================================== +// +// SIMD support +// +// The JPEG decoder will try to automatically use SIMD kernels on x86 when +// supported by the compiler. For ARM Neon support, you must explicitly +// request it. +// +// (The old do-it-yourself SIMD API is no longer supported in the current +// code.) +// +// On x86, SSE2 will automatically be used when available based on a run-time +// test; if not, the generic C versions are used as a fall-back. On ARM targets, +// the typical path is to have separate builds for NEON and non-NEON devices +// (at least this is true for iOS and Android). Therefore, the NEON support is +// toggled by a build flag: define STBI_NEON to get NEON loops. +// +// If for some reason you do not want to use any of SIMD code, or if +// you have issues compiling it, you can disable it entirely by +// defining STBI_NO_SIMD. +// +// =========================================================================== +// +// HDR image support (disable by defining STBI_NO_HDR) +// +// stb_image supports loading HDR images in general, and currently the Radiance +// .HDR file format specifically. You can still load any file through the existing +// interface; if you attempt to load an HDR file, it will be automatically remapped +// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1; +// both of these constants can be reconfigured through this interface: +// +// stbi_hdr_to_ldr_gamma(2.2f); +// stbi_hdr_to_ldr_scale(1.0f); +// +// (note, do not use _inverse_ constants; stbi_image will invert them +// appropriately). +// +// Additionally, there is a new, parallel interface for loading files as +// (linear) floats to preserve the full dynamic range: +// +// float *data = stbi_loadf(filename, &x, &y, &n, 0); +// +// If you load LDR images through this interface, those images will +// be promoted to floating point values, run through the inverse of +// constants corresponding to the above: +// +// stbi_ldr_to_hdr_scale(1.0f); +// stbi_ldr_to_hdr_gamma(2.2f); +// +// Finally, given a filename (or an open file or memory block--see header +// file for details) containing image data, you can query for the "most +// appropriate" interface to use (that is, whether the image is HDR or +// not), using: +// +// stbi_is_hdr(char *filename); +// +// =========================================================================== +// +// iPhone PNG support: +// +// By default we convert iphone-formatted PNGs back to RGB, even though +// they are internally encoded differently. You can disable this conversion +// by calling stbi_convert_iphone_png_to_rgb(0), in which case +// you will always just get the native iphone "format" through (which +// is BGR stored in RGB). +// +// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per +// pixel to remove any premultiplied alpha *only* if the image file explicitly +// says there's premultiplied data (currently only happens in iPhone images, +// and only if iPhone convert-to-rgb processing is on). +// +// =========================================================================== +// +// ADDITIONAL CONFIGURATION +// +// - You can suppress implementation of any of the decoders to reduce +// your code footprint by #defining one or more of the following +// symbols before creating the implementation. +// +// STBI_NO_JPEG +// STBI_NO_PNG +// STBI_NO_BMP +// STBI_NO_PSD +// STBI_NO_TGA +// STBI_NO_GIF +// STBI_NO_HDR +// STBI_NO_PIC +// STBI_NO_PNM (.ppm and .pgm) +// +// - You can request *only* certain decoders and suppress all other ones +// (this will be more forward-compatible, as addition of new decoders +// doesn't require you to disable them explicitly): +// +// STBI_ONLY_JPEG +// STBI_ONLY_PNG +// STBI_ONLY_BMP +// STBI_ONLY_PSD +// STBI_ONLY_TGA +// STBI_ONLY_GIF +// STBI_ONLY_HDR +// STBI_ONLY_PIC +// STBI_ONLY_PNM (.ppm and .pgm) +// +// - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still +// want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB +// +// - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater +// than that size (in either width or height) without further processing. +// This is to let programs in the wild set an upper bound to prevent +// denial-of-service attacks on untrusted data, as one could generate a +// valid image of gigantic dimensions and force stb_image to allocate a +// huge block of memory and spend disproportionate time decoding it. By +// default this is set to (1 << 24), which is 16777216, but that's still +// very big. + +#ifndef STBI_NO_STDIO +#include <stdio.h> +#endif // STBI_NO_STDIO + +#define STBI_VERSION 1 + +enum +{ + STBI_default = 0, // only used for desired_channels + + STBI_grey = 1, + STBI_grey_alpha = 2, + STBI_rgb = 3, + STBI_rgb_alpha = 4 +}; + +#include <stdlib.h> +typedef unsigned char stbi_uc; +typedef unsigned short stbi_us; + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STBIDEF +#ifdef STB_IMAGE_STATIC +#define STBIDEF static +#else +#define STBIDEF extern +#endif +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// PRIMARY API - works on images of any type +// + +// +// load image by filename, open file, or memory buffer +// + +typedef struct +{ + int (*read) (void *user,char *data,int size); // fill 'data' with 'size' bytes. return number of bytes actually read + void (*skip) (void *user,int n); // skip the next 'n' bytes, or 'unget' the last -n bytes if negative + int (*eof) (void *user); // returns nonzero if we are at end of file/data +} stbi_io_callbacks; + +//////////////////////////////////// +// +// 8-bits-per-channel interface +// + +STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_uc *stbi_load (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_uc *stbi_load_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +// for stbi_load_from_file, file pointer is left pointing immediately after image +#endif + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +#endif + +#ifdef STBI_WINDOWS_UTF8 +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input); +#endif + +//////////////////////////////////// +// +// 16-bits-per-channel interface +// + +STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + +#ifndef STBI_NO_STDIO +STBIDEF stbi_us *stbi_load_16 (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); +STBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); +#endif + +//////////////////////////////////// +// +// float-per-channel interface +// +#ifndef STBI_NO_LINEAR + STBIDEF float *stbi_loadf_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_callbacks (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels); + + #ifndef STBI_NO_STDIO + STBIDEF float *stbi_loadf (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels); + STBIDEF float *stbi_loadf_from_file (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels); + #endif +#endif + +#ifndef STBI_NO_HDR + STBIDEF void stbi_hdr_to_ldr_gamma(float gamma); + STBIDEF void stbi_hdr_to_ldr_scale(float scale); +#endif // STBI_NO_HDR + +#ifndef STBI_NO_LINEAR + STBIDEF void stbi_ldr_to_hdr_gamma(float gamma); + STBIDEF void stbi_ldr_to_hdr_scale(float scale); +#endif // STBI_NO_LINEAR + +// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user); +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len); +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename); +STBIDEF int stbi_is_hdr_from_file(FILE *f); +#endif // STBI_NO_STDIO + + +// get a VERY brief reason for failure +// on most compilers (and ALL modern mainstream compilers) this is threadsafe +STBIDEF const char *stbi_failure_reason (void); + +// free the loaded image -- this is just free() +STBIDEF void stbi_image_free (void *retval_from_stbi_load); + +// get image dimensions & components without fully decoding +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len); +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user); + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info (char const *filename, int *x, int *y, int *comp); +STBIDEF int stbi_info_from_file (FILE *f, int *x, int *y, int *comp); +STBIDEF int stbi_is_16_bit (char const *filename); +STBIDEF int stbi_is_16_bit_from_file(FILE *f); +#endif + + + +// for image formats that explicitly notate that they have premultiplied alpha, +// we just return the colors as stored in the file. set this flag to force +// unpremultiplication. results are undefined if the unpremultiply overflow. +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply); + +// indicate whether we should process iphone images back to canonical format, +// or just pass them through "as-is" +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert); + +// flip the image vertically, so the first pixel in the output array is the bottom left +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip); + +// as above, but only applies to images loaded on the thread that calls the function +// this function is only available if your compiler supports thread-local variables; +// calling it will fail to link if your compiler doesn't +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip); + +// ZLIB client - used by PNG, available for other purposes + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen); +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header); +STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + +STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen); +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen); + + +#ifdef __cplusplus +} +#endif + +// +// +//// end header file ///////////////////////////////////////////////////// +#endif // STBI_INCLUDE_STB_IMAGE_H + +#ifdef STB_IMAGE_IMPLEMENTATION + +#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \ + || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \ + || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \ + || defined(STBI_ONLY_ZLIB) + #ifndef STBI_ONLY_JPEG + #define STBI_NO_JPEG + #endif + #ifndef STBI_ONLY_PNG + #define STBI_NO_PNG + #endif + #ifndef STBI_ONLY_BMP + #define STBI_NO_BMP + #endif + #ifndef STBI_ONLY_PSD + #define STBI_NO_PSD + #endif + #ifndef STBI_ONLY_TGA + #define STBI_NO_TGA + #endif + #ifndef STBI_ONLY_GIF + #define STBI_NO_GIF + #endif + #ifndef STBI_ONLY_HDR + #define STBI_NO_HDR + #endif + #ifndef STBI_ONLY_PIC + #define STBI_NO_PIC + #endif + #ifndef STBI_ONLY_PNM + #define STBI_NO_PNM + #endif +#endif + +#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB) +#define STBI_NO_ZLIB +#endif + + +#include <stdarg.h> +#include <stddef.h> // ptrdiff_t on osx +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +#include <math.h> // ldexp, pow +#endif + +#ifndef STBI_ASSERT +#include <assert.h> +#define STBI_ASSERT(x) assert(x) +#endif + +#ifdef __cplusplus +#define STBI_EXTERN extern "C" +#else +#define STBI_EXTERN extern +#endif + + +#ifndef _MSC_VER + #ifdef __cplusplus + #define stbi_inline inline + #else + #define stbi_inline + #endif +#else + #define stbi_inline __forceinline +#endif + +#ifndef STBI_NO_THREAD_LOCALS + #if defined(__cplusplus) && __cplusplus >= 201103L + #define STBI_THREAD_LOCAL thread_local + #elif defined(__GNUC__) && __GNUC__ < 5 + #define STBI_THREAD_LOCAL __thread + #elif defined(_MSC_VER) + #define STBI_THREAD_LOCAL __declspec(thread) + #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) + #define STBI_THREAD_LOCAL _Thread_local + #endif + + #ifndef STBI_THREAD_LOCAL + #if defined(__GNUC__) + #define STBI_THREAD_LOCAL __thread + #endif + #endif +#endif + +#ifdef _MSC_VER +typedef unsigned short stbi__uint16; +typedef signed short stbi__int16; +typedef unsigned int stbi__uint32; +typedef signed int stbi__int32; +#else +#include <stdint.h> +typedef uint16_t stbi__uint16; +typedef int16_t stbi__int16; +typedef uint32_t stbi__uint32; +typedef int32_t stbi__int32; +#endif + +// should produce compiler error if size is wrong +typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1]; + +#ifdef _MSC_VER +#define STBI_NOTUSED(v) (void)(v) +#else +#define STBI_NOTUSED(v) (void)sizeof(v) +#endif + +#ifdef _MSC_VER +#define STBI_HAS_LROTL +#endif + +#ifdef STBI_HAS_LROTL + #define stbi_lrot(x,y) _lrotl(x,y) +#else + #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (32 - (y)))) +#endif + +#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED)) +// ok +#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED) +// ok +#else +#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)." +#endif + +#ifndef STBI_MALLOC +#define STBI_MALLOC(sz) malloc(sz) +#define STBI_REALLOC(p,newsz) realloc(p,newsz) +#define STBI_FREE(p) free(p) +#endif + +#ifndef STBI_REALLOC_SIZED +#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz) +#endif + +// x86/x64 detection +#if defined(__x86_64__) || defined(_M_X64) +#define STBI__X64_TARGET +#elif defined(__i386) || defined(_M_IX86) +#define STBI__X86_TARGET +#endif + +#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD) +// gcc doesn't support sse2 intrinsics unless you compile with -msse2, +// which in turn means it gets to use SSE2 everywhere. This is unfortunate, +// but previous attempts to provide the SSE2 functions with runtime +// detection caused numerous issues. The way architecture extensions are +// exposed in GCC/Clang is, sadly, not really suited for one-file libs. +// New behavior: if compiled with -msse2, we use SSE2 without any +// detection; if not, we don't use it at all. +#define STBI_NO_SIMD +#endif + +#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD) +// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET +// +// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the +// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant. +// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not +// simultaneously enabling "-mstackrealign". +// +// See https://github.com/nothings/stb/issues/81 for more information. +// +// So default to no SSE2 on 32-bit MinGW. If you've read this far and added +// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2. +#define STBI_NO_SIMD +#endif + +#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) +#define STBI_SSE2 +#include <emmintrin.h> + +#ifdef _MSC_VER + +#if _MSC_VER >= 1400 // not VC6 +#include <intrin.h> // __cpuid +static int stbi__cpuid3(void) +{ + int info[4]; + __cpuid(info,1); + return info[3]; +} +#else +static int stbi__cpuid3(void) +{ + int res; + __asm { + mov eax,1 + cpuid + mov res,edx + } + return res; +} +#endif + +#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + int info3 = stbi__cpuid3(); + return ((info3 >> 26) & 1) != 0; +} +#endif + +#else // assume GCC-style if not VC++ +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) + +#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2) +static int stbi__sse2_available(void) +{ + // If we're even attempting to compile this on GCC/Clang, that means + // -msse2 is on, which means the compiler is allowed to use SSE2 + // instructions at will, and so are we. + return 1; +} +#endif + +#endif +#endif + +// ARM NEON +#if defined(STBI_NO_SIMD) && defined(STBI_NEON) +#undef STBI_NEON +#endif + +#ifdef STBI_NEON +#include <arm_neon.h> +// assume GCC or Clang on ARM targets +#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16))) +#endif + +#ifndef STBI_SIMD_ALIGN +#define STBI_SIMD_ALIGN(type, name) type name +#endif + +#ifndef STBI_MAX_DIMENSIONS +#define STBI_MAX_DIMENSIONS (1 << 24) +#endif + +/////////////////////////////////////////////// +// +// stbi__context struct and start_xxx functions + +// stbi__context structure is our basic context used by all images, so it +// contains all the IO context, plus some basic image information +typedef struct +{ + stbi__uint32 img_x, img_y; + int img_n, img_out_n; + + stbi_io_callbacks io; + void *io_user_data; + + int read_from_callbacks; + int buflen; + stbi_uc buffer_start[128]; + int callback_already_read; + + stbi_uc *img_buffer, *img_buffer_end; + stbi_uc *img_buffer_original, *img_buffer_original_end; +} stbi__context; + + +static void stbi__refill_buffer(stbi__context *s); + +// initialize a memory-decode context +static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len) +{ + s->io.read = NULL; + s->read_from_callbacks = 0; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer; + s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len; +} + +// initialize a callback-based context +static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user) +{ + s->io = *c; + s->io_user_data = user; + s->buflen = sizeof(s->buffer_start); + s->read_from_callbacks = 1; + s->callback_already_read = 0; + s->img_buffer = s->img_buffer_original = s->buffer_start; + stbi__refill_buffer(s); + s->img_buffer_original_end = s->img_buffer_end; +} + +#ifndef STBI_NO_STDIO + +static int stbi__stdio_read(void *user, char *data, int size) +{ + return (int) fread(data,1,size,(FILE*) user); +} + +static void stbi__stdio_skip(void *user, int n) +{ + int ch; + fseek((FILE*) user, n, SEEK_CUR); + ch = fgetc((FILE*) user); /* have to read a byte to reset feof()'s flag */ + if (ch != EOF) { + ungetc(ch, (FILE *) user); /* push byte back onto stream if valid. */ + } +} + +static int stbi__stdio_eof(void *user) +{ + return feof((FILE*) user) || ferror((FILE *) user); +} + +static stbi_io_callbacks stbi__stdio_callbacks = +{ + stbi__stdio_read, + stbi__stdio_skip, + stbi__stdio_eof, +}; + +static void stbi__start_file(stbi__context *s, FILE *f) +{ + stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f); +} + +//static void stop_file(stbi__context *s) { } + +#endif // !STBI_NO_STDIO + +static void stbi__rewind(stbi__context *s) +{ + // conceptually rewind SHOULD rewind to the beginning of the stream, + // but we just rewind to the beginning of the initial buffer, because + // we only use it after doing 'test', which only ever looks at at most 92 bytes + s->img_buffer = s->img_buffer_original; + s->img_buffer_end = s->img_buffer_original_end; +} + +enum +{ + STBI_ORDER_RGB, + STBI_ORDER_BGR +}; + +typedef struct +{ + int bits_per_channel; + int num_channels; + int channel_order; +} stbi__result_info; + +#ifndef STBI_NO_JPEG +static int stbi__jpeg_test(stbi__context *s); +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNG +static int stbi__png_test(stbi__context *s); +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__png_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_BMP +static int stbi__bmp_test(stbi__context *s); +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_TGA +static int stbi__tga_test(stbi__context *s); +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s); +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc); +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp); +static int stbi__psd_is16(stbi__context *s); +#endif + +#ifndef STBI_NO_HDR +static int stbi__hdr_test(stbi__context *s); +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_test(stbi__context *s); +static void *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_GIF +static int stbi__gif_test(stbi__context *s); +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp); +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +#ifndef STBI_NO_PNM +static int stbi__pnm_test(stbi__context *s); +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri); +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp); +#endif + +static +#ifdef STBI_THREAD_LOCAL +STBI_THREAD_LOCAL +#endif +const char *stbi__g_failure_reason; + +STBIDEF const char *stbi_failure_reason(void) +{ + return stbi__g_failure_reason; +} + +#ifndef STBI_NO_FAILURE_STRINGS +static int stbi__err(const char *str) +{ + stbi__g_failure_reason = str; + return 0; +} +#endif + +static void *stbi__malloc(size_t size) +{ + return STBI_MALLOC(size); +} + +// stb_image uses ints pervasively, including for offset calculations. +// therefore the largest decoded image size we can support with the +// current code, even on 64-bit targets, is INT_MAX. this is not a +// significant limitation for the intended use case. +// +// we do, however, need to make sure our size calculations don't +// overflow. hence a few helper functions for size calculations that +// multiply integers together, making sure that they're non-negative +// and no overflow occurs. + +// return 1 if the sum is valid, 0 on overflow. +// negative terms are considered invalid. +static int stbi__addsizes_valid(int a, int b) +{ + if (b < 0) return 0; + // now 0 <= b <= INT_MAX, hence also + // 0 <= INT_MAX - b <= INTMAX. + // And "a + b <= INT_MAX" (which might overflow) is the + // same as a <= INT_MAX - b (no overflow) + return a <= INT_MAX - b; +} + +// returns 1 if the product is valid, 0 on overflow. +// negative factors are considered invalid. +static int stbi__mul2sizes_valid(int a, int b) +{ + if (a < 0 || b < 0) return 0; + if (b == 0) return 1; // mul-by-0 is always safe + // portable way to check for no overflows in a*b + return a <= INT_MAX/b; +} + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// returns 1 if "a*b + add" has no negative terms/factors and doesn't overflow +static int stbi__mad2sizes_valid(int a, int b, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add); +} +#endif + +// returns 1 if "a*b*c + add" has no negative terms/factors and doesn't overflow +static int stbi__mad3sizes_valid(int a, int b, int c, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__addsizes_valid(a*b*c, add); +} + +// returns 1 if "a*b*c*d + add" has no negative terms/factors and doesn't overflow +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add) +{ + return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) && + stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add); +} +#endif + +#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR) +// mallocs with size overflow checking +static void *stbi__malloc_mad2(int a, int b, int add) +{ + if (!stbi__mad2sizes_valid(a, b, add)) return NULL; + return stbi__malloc(a*b + add); +} +#endif + +static void *stbi__malloc_mad3(int a, int b, int c, int add) +{ + if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL; + return stbi__malloc(a*b*c + add); +} + +#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) +static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) +{ + if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL; + return stbi__malloc(a*b*c*d + add); +} +#endif + +// stbi__err - error +// stbi__errpf - error returning pointer to float +// stbi__errpuc - error returning pointer to unsigned char + +#ifdef STBI_NO_FAILURE_STRINGS + #define stbi__err(x,y) 0 +#elif defined(STBI_FAILURE_USERMSG) + #define stbi__err(x,y) stbi__err(y) +#else + #define stbi__err(x,y) stbi__err(x) +#endif + +#define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL)) +#define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL)) + +STBIDEF void stbi_image_free(void *retval_from_stbi_load) +{ + STBI_FREE(retval_from_stbi_load); +} + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp); +#endif + +#ifndef STBI_NO_HDR +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp); +#endif + +static int stbi__vertically_flip_on_load_global = 0; + +STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_global = flag_true_if_should_flip; +} + +#ifndef STBI_THREAD_LOCAL +#define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global +#else +static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set; + +STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip) +{ + stbi__vertically_flip_on_load_local = flag_true_if_should_flip; + stbi__vertically_flip_on_load_set = 1; +} + +#define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \ + ? stbi__vertically_flip_on_load_local \ + : stbi__vertically_flip_on_load_global) +#endif // STBI_THREAD_LOCAL + +static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields + ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed + ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order + ri->num_channels = 0; + + #ifndef STBI_NO_JPEG + if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNG + if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_BMP + if (stbi__bmp_test(s)) return stbi__bmp_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_GIF + if (stbi__gif_test(s)) return stbi__gif_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PSD + if (stbi__psd_test(s)) return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc); + #else + STBI_NOTUSED(bpc); + #endif + #ifndef STBI_NO_PIC + if (stbi__pic_test(s)) return stbi__pic_load(s,x,y,comp,req_comp, ri); + #endif + #ifndef STBI_NO_PNM + if (stbi__pnm_test(s)) return stbi__pnm_load(s,x,y,comp,req_comp, ri); + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri); + return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp); + } + #endif + + #ifndef STBI_NO_TGA + // test tga last because it's a crappy test! + if (stbi__tga_test(s)) + return stbi__tga_load(s,x,y,comp,req_comp, ri); + #endif + + return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt"); +} + +static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi_uc *reduced; + + reduced = (stbi_uc *) stbi__malloc(img_len); + if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling + + STBI_FREE(orig); + return reduced; +} + +static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels) +{ + int i; + int img_len = w * h * channels; + stbi__uint16 *enlarged; + + enlarged = (stbi__uint16 *) stbi__malloc(img_len*2); + if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + + for (i = 0; i < img_len; ++i) + enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff + + STBI_FREE(orig); + return enlarged; +} + +static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel) +{ + int row; + size_t bytes_per_row = (size_t)w * bytes_per_pixel; + stbi_uc temp[2048]; + stbi_uc *bytes = (stbi_uc *)image; + + for (row = 0; row < (h>>1); row++) { + stbi_uc *row0 = bytes + row*bytes_per_row; + stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row; + // swap row0 with row1 + size_t bytes_left = bytes_per_row; + while (bytes_left) { + size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp); + memcpy(temp, row0, bytes_copy); + memcpy(row0, row1, bytes_copy); + memcpy(row1, temp, bytes_copy); + row0 += bytes_copy; + row1 += bytes_copy; + bytes_left -= bytes_copy; + } + } +} + +#ifndef STBI_NO_GIF +static void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel) +{ + int slice; + int slice_size = w * h * bytes_per_pixel; + + stbi_uc *bytes = (stbi_uc *)image; + for (slice = 0; slice < z; ++slice) { + stbi__vertical_flip(bytes, w, h, bytes_per_pixel); + bytes += slice_size; + } +} +#endif + +static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 8) { + result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 8; + } + + // @TODO: move stbi__convert_format to here + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc)); + } + + return (unsigned char *) result; +} + +static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + stbi__result_info ri; + void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16); + + if (result == NULL) + return NULL; + + // it is the responsibility of the loaders to make sure we get either 8 or 16 bit. + STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16); + + if (ri.bits_per_channel != 16) { + result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp); + ri.bits_per_channel = 16; + } + + // @TODO: move stbi__convert_format16 to here + // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision + + if (stbi__vertically_flip_on_load) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16)); + } + + return (stbi__uint16 *) result; +} + +#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR) +static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp) +{ + if (stbi__vertically_flip_on_load && result != NULL) { + int channels = req_comp ? req_comp : *comp; + stbi__vertical_flip(result, *x, *y, channels * sizeof(float)); + } +} +#endif + +#ifndef STBI_NO_STDIO + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide); +STBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default); +#endif + +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) +STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input) +{ + return WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL); +} +#endif + +static FILE *stbi__fopen(char const *filename, char const *mode) +{ + FILE *f; +#if defined(_MSC_VER) && defined(STBI_WINDOWS_UTF8) + wchar_t wMode[64]; + wchar_t wFilename[1024]; + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename))) + return 0; + + if (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode))) + return 0; + +#if _MSC_VER >= 1400 + if (0 != _wfopen_s(&f, wFilename, wMode)) + f = 0; +#else + f = _wfopen(wFilename, wMode); +#endif + +#elif defined(_MSC_VER) && _MSC_VER >= 1400 + if (0 != fopen_s(&f, filename, mode)) + f=0; +#else + f = fopen(filename, mode); +#endif + return f; +} + + +STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + unsigned char *result; + if (!f) return stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__uint16 *result; + stbi__context s; + stbi__start_file(&s,f); + result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp); + if (result) { + // need to 'unget' all the characters in the IO buffer + fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR); + } + return result; +} + +STBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + stbi__uint16 *result; + if (!f) return (stbi_us *) stbi__errpuc("can't fopen", "Unable to open file"); + result = stbi_load_from_file_16(f,x,y,comp,req_comp); + fclose(f); + return result; +} + + +#endif //!STBI_NO_STDIO + +STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user); + return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels); +} + +STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_GIF +STBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + unsigned char *result; + stbi__context s; + stbi__start_mem(&s,buffer,len); + + result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp); + if (stbi__vertically_flip_on_load) { + stbi__vertical_flip_slices( result, *x, *y, *z, *comp ); + } + + return result; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp) +{ + unsigned char *data; + #ifndef STBI_NO_HDR + if (stbi__hdr_test(s)) { + stbi__result_info ri; + float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri); + if (hdr_data) + stbi__float_postprocess(hdr_data,x,y,comp,req_comp); + return hdr_data; + } + #endif + data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp); + if (data) + return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp); + return stbi__errpf("unknown image type", "Image not of any known type, or corrupt"); +} + +STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} + +#ifndef STBI_NO_STDIO +STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp) +{ + float *result; + FILE *f = stbi__fopen(filename, "rb"); + if (!f) return stbi__errpf("can't fopen", "Unable to open file"); + result = stbi_loadf_from_file(f,x,y,comp,req_comp); + fclose(f); + return result; +} + +STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp) +{ + stbi__context s; + stbi__start_file(&s,f); + return stbi__loadf_main(&s,x,y,comp,req_comp); +} +#endif // !STBI_NO_STDIO + +#endif // !STBI_NO_LINEAR + +// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is +// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always +// reports false! + +STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(buffer); + STBI_NOTUSED(len); + return 0; + #endif +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_is_hdr (char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result=0; + if (f) { + result = stbi_is_hdr_from_file(f); + fclose(f); + } + return result; +} + +STBIDEF int stbi_is_hdr_from_file(FILE *f) +{ + #ifndef STBI_NO_HDR + long pos = ftell(f); + int res; + stbi__context s; + stbi__start_file(&s,f); + res = stbi__hdr_test(&s); + fseek(f, pos, SEEK_SET); + return res; + #else + STBI_NOTUSED(f); + return 0; + #endif +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user) +{ + #ifndef STBI_NO_HDR + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user); + return stbi__hdr_test(&s); + #else + STBI_NOTUSED(clbk); + STBI_NOTUSED(user); + return 0; + #endif +} + +#ifndef STBI_NO_LINEAR +static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f; + +STBIDEF void stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; } +STBIDEF void stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; } +#endif + +static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f; + +STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; } +STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; } + + +////////////////////////////////////////////////////////////////////////////// +// +// Common code used by all image loaders +// + +enum +{ + STBI__SCAN_load=0, + STBI__SCAN_type, + STBI__SCAN_header +}; + +static void stbi__refill_buffer(stbi__context *s) +{ + int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen); + s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original); + if (n == 0) { + // at end of file, treat same as if from memory, but need to handle case + // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file + s->read_from_callbacks = 0; + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start+1; + *s->img_buffer = 0; + } else { + s->img_buffer = s->buffer_start; + s->img_buffer_end = s->buffer_start + n; + } +} + +stbi_inline static stbi_uc stbi__get8(stbi__context *s) +{ + if (s->img_buffer < s->img_buffer_end) + return *s->img_buffer++; + if (s->read_from_callbacks) { + stbi__refill_buffer(s); + return *s->img_buffer++; + } + return 0; +} + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +stbi_inline static int stbi__at_eof(stbi__context *s) +{ + if (s->io.read) { + if (!(s->io.eof)(s->io_user_data)) return 0; + // if feof() is true, check if buffer = end + // special case: we've only got the special 0 character at the end + if (s->read_from_callbacks == 0) return 1; + } + + return s->img_buffer >= s->img_buffer_end; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) +// nothing +#else +static void stbi__skip(stbi__context *s, int n) +{ + if (n == 0) return; // already there! + if (n < 0) { + s->img_buffer = s->img_buffer_end; + return; + } + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + s->img_buffer = s->img_buffer_end; + (s->io.skip)(s->io_user_data, n - blen); + return; + } + } + s->img_buffer += n; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM) +// nothing +#else +static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n) +{ + if (s->io.read) { + int blen = (int) (s->img_buffer_end - s->img_buffer); + if (blen < n) { + int res, count; + + memcpy(buffer, s->img_buffer, blen); + + count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen); + res = (count == (n-blen)); + s->img_buffer = s->img_buffer_end; + return res; + } + } + + if (s->img_buffer+n <= s->img_buffer_end) { + memcpy(buffer, s->img_buffer, n); + s->img_buffer += n; + return 1; + } else + return 0; +} +#endif + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static int stbi__get16be(stbi__context *s) +{ + int z = stbi__get8(s); + return (z << 8) + stbi__get8(s); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC) +// nothing +#else +static stbi__uint32 stbi__get32be(stbi__context *s) +{ + stbi__uint32 z = stbi__get16be(s); + return (z << 16) + stbi__get16be(s); +} +#endif + +#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) +// nothing +#else +static int stbi__get16le(stbi__context *s) +{ + int z = stbi__get8(s); + return z + (stbi__get8(s) << 8); +} +#endif + +#ifndef STBI_NO_BMP +static stbi__uint32 stbi__get32le(stbi__context *s) +{ + stbi__uint32 z = stbi__get16le(s); + return z + (stbi__get16le(s) << 16); +} +#endif + +#define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255)) // truncate int to byte without warnings + +#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +////////////////////////////////////////////////////////////////////////////// +// +// generic converter from built-in img_n to req_comp +// individual types do this automatically as much as possible (e.g. jpeg +// does all cases internally since it needs to colorspace convert anyway, +// and it never has alpha, so very few cases ). png can automatically +// interleave an alpha=255 channel, but falls back to this for other cases +// +// assume data buffer is malloced, so malloc a new one and free that one +// only failure mode is malloc failing + +static stbi_uc stbi__compute_y(int r, int g, int b) +{ + return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM) +// nothing +#else +static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + unsigned char *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0); + if (good == NULL) { + STBI_FREE(data); + return stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + unsigned char *src = data + j * x * img_n ; + unsigned char *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 stbi__compute_y_16(int r, int g, int b) +{ + return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8); +} +#endif + +#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) +// nothing +#else +static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y) +{ + int i,j; + stbi__uint16 *good; + + if (req_comp == img_n) return data; + STBI_ASSERT(req_comp >= 1 && req_comp <= 4); + + good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2); + if (good == NULL) { + STBI_FREE(data); + return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory"); + } + + for (j=0; j < (int) y; ++j) { + stbi__uint16 *src = data + j * x * img_n ; + stbi__uint16 *dest = good + j * x * req_comp; + + #define STBI__COMBO(a,b) ((a)*8+(b)) + #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b) + // convert source image with img_n components to one with req_comp components; + // avoid switch per pixel, so use switch per scanline and massive macros + switch (STBI__COMBO(img_n, req_comp)) { + STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break; + STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break; + STBI__CASE(2,1) { dest[0]=src[0]; } break; + STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break; + STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break; + STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break; + STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break; + STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break; + STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break; + STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break; + default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion"); + } + #undef STBI__CASE + } + + STBI_FREE(data); + return good; +} +#endif + +#ifndef STBI_NO_LINEAR +static float *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp) +{ + int i,k,n; + float *output; + if (!data) return NULL; + output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale); + } + } + if (n < comp) { + for (i=0; i < x*y; ++i) { + output[i*comp + n] = data[i*comp + n]/255.0f; + } + } + STBI_FREE(data); + return output; +} +#endif + +#ifndef STBI_NO_HDR +#define stbi__float2int(x) ((int) (x)) +static stbi_uc *stbi__hdr_to_ldr(float *data, int x, int y, int comp) +{ + int i,k,n; + stbi_uc *output; + if (!data) return NULL; + output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0); + if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); } + // compute number of non-alpha components + if (comp & 1) n = comp; else n = comp-1; + for (i=0; i < x*y; ++i) { + for (k=0; k < n; ++k) { + float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + if (k < comp) { + float z = data[i*comp+k] * 255 + 0.5f; + if (z < 0) z = 0; + if (z > 255) z = 255; + output[i*comp + k] = (stbi_uc) stbi__float2int(z); + } + } + STBI_FREE(data); + return output; +} +#endif + +////////////////////////////////////////////////////////////////////////////// +// +// "baseline" JPEG/JFIF decoder +// +// simple implementation +// - doesn't support delayed output of y-dimension +// - simple interface (only one output format: 8-bit interleaved RGB) +// - doesn't try to recover corrupt jpegs +// - doesn't allow partial loading, loading multiple at once +// - still fast on x86 (copying globals into locals doesn't help x86) +// - allocates lots of intermediate memory (full size of all components) +// - non-interleaved case requires this anyway +// - allows good upsampling (see next) +// high-quality +// - upsampled channels are bilinearly interpolated, even across blocks +// - quality integer IDCT derived from IJG's 'slow' +// performance +// - fast huffman; reasonable integer IDCT +// - some SIMD kernels for common paths on targets with SSE2/NEON +// - uses a lot of intermediate memory, could cache poorly + +#ifndef STBI_NO_JPEG + +// huffman decoding acceleration +#define FAST_BITS 9 // larger handles more cases; smaller stomps less cache + +typedef struct +{ + stbi_uc fast[1 << FAST_BITS]; + // weirdly, repacking this into AoS is a 10% speed loss, instead of a win + stbi__uint16 code[256]; + stbi_uc values[256]; + stbi_uc size[257]; + unsigned int maxcode[18]; + int delta[17]; // old 'firstsymbol' - old 'firstcode' +} stbi__huffman; + +typedef struct +{ + stbi__context *s; + stbi__huffman huff_dc[4]; + stbi__huffman huff_ac[4]; + stbi__uint16 dequant[4][64]; + stbi__int16 fast_ac[4][1 << FAST_BITS]; + +// sizes for components, interleaved MCUs + int img_h_max, img_v_max; + int img_mcu_x, img_mcu_y; + int img_mcu_w, img_mcu_h; + +// definition of jpeg image component + struct + { + int id; + int h,v; + int tq; + int hd,ha; + int dc_pred; + + int x,y,w2,h2; + stbi_uc *data; + void *raw_data, *raw_coeff; + stbi_uc *linebuf; + short *coeff; // progressive only + int coeff_w, coeff_h; // number of 8x8 coefficient blocks + } img_comp[4]; + + stbi__uint32 code_buffer; // jpeg entropy-coded buffer + int code_bits; // number of valid bits + unsigned char marker; // marker seen while filling entropy buffer + int nomore; // flag if we saw a marker so must stop + + int progressive; + int spec_start; + int spec_end; + int succ_high; + int succ_low; + int eob_run; + int jfif; + int app14_color_transform; // Adobe APP14 tag + int rgb; + + int scan_n, order[4]; + int restart_interval, todo; + +// kernels + void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]); + void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step); + stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs); +} stbi__jpeg; + +static int stbi__build_huffman(stbi__huffman *h, int *count) +{ + int i,j,k=0; + unsigned int code; + // build size list for each symbol (from JPEG spec) + for (i=0; i < 16; ++i) + for (j=0; j < count[i]; ++j) + h->size[k++] = (stbi_uc) (i+1); + h->size[k] = 0; + + // compute actual symbols (from jpeg spec) + code = 0; + k = 0; + for(j=1; j <= 16; ++j) { + // compute delta to add to code to compute symbol id + h->delta[j] = k - code; + if (h->size[k] == j) { + while (h->size[k] == j) + h->code[k++] = (stbi__uint16) (code++); + if (code-1 >= (1u << j)) return stbi__err("bad code lengths","Corrupt JPEG"); + } + // compute largest code + 1 for this size, preshifted as needed later + h->maxcode[j] = code << (16-j); + code <<= 1; + } + h->maxcode[j] = 0xffffffff; + + // build non-spec acceleration table; 255 is flag for not-accelerated + memset(h->fast, 255, 1 << FAST_BITS); + for (i=0; i < k; ++i) { + int s = h->size[i]; + if (s <= FAST_BITS) { + int c = h->code[i] << (FAST_BITS-s); + int m = 1 << (FAST_BITS-s); + for (j=0; j < m; ++j) { + h->fast[c+j] = (stbi_uc) i; + } + } + } + return 1; +} + +// build a table that decodes both magnitude and value of small ACs in +// one go. +static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h) +{ + int i; + for (i=0; i < (1 << FAST_BITS); ++i) { + stbi_uc fast = h->fast[i]; + fast_ac[i] = 0; + if (fast < 255) { + int rs = h->values[fast]; + int run = (rs >> 4) & 15; + int magbits = rs & 15; + int len = h->size[fast]; + + if (magbits && len + magbits <= FAST_BITS) { + // magnitude code followed by receive_extend code + int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits); + int m = 1 << (magbits - 1); + if (k < m) k += (~0U << magbits) + 1; + // if the result is small enough, we can fit it in fast_ac table + if (k >= -128 && k <= 127) + fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits)); + } + } + } +} + +static void stbi__grow_buffer_unsafe(stbi__jpeg *j) +{ + do { + unsigned int b = j->nomore ? 0 : stbi__get8(j->s); + if (b == 0xff) { + int c = stbi__get8(j->s); + while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes + if (c != 0) { + j->marker = (unsigned char) c; + j->nomore = 1; + return; + } + } + j->code_buffer |= b << (24 - j->code_bits); + j->code_bits += 8; + } while (j->code_bits <= 24); +} + +// (1 << n) - 1 +static const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535}; + +// decode a jpeg huffman value from the bitstream +stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) +{ + unsigned int temp; + int c,k; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + // look at the top FAST_BITS and determine what symbol ID it is, + // if the code is <= FAST_BITS + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + k = h->fast[c]; + if (k < 255) { + int s = h->size[k]; + if (s > j->code_bits) + return -1; + j->code_buffer <<= s; + j->code_bits -= s; + return h->values[k]; + } + + // naive test is to shift the code_buffer down so k bits are + // valid, then test against maxcode. To speed this up, we've + // preshifted maxcode left so that it has (16-k) 0s at the + // end; in other words, regardless of the number of bits, it + // wants to be compared against something shifted to have 16; + // that way we don't need to shift inside the loop. + temp = j->code_buffer >> 16; + for (k=FAST_BITS+1 ; ; ++k) + if (temp < h->maxcode[k]) + break; + if (k == 17) { + // error! code not found + j->code_bits -= 16; + return -1; + } + + if (k > j->code_bits) + return -1; + + // convert the huffman code to the symbol id + c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); + + // convert the id to a symbol + j->code_bits -= k; + j->code_buffer <<= k; + return h->values[c]; +} + +// bias[n] = (-1<<n) + 1 +static const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767}; + +// combined JPEG 'receive' and JPEG 'extend', since baseline +// always extends everything it receives. +stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) +{ + unsigned int k; + int sgn; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + + sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB + k = stbi_lrot(j->code_buffer, n); + if (n < 0 || n >= (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask))) return 0; + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k + (stbi__jbias[n] & ~sgn); +} + +// get some unsigned bits +stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) +{ + unsigned int k; + if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + k = stbi_lrot(j->code_buffer, n); + j->code_buffer = k & ~stbi__bmask[n]; + k &= stbi__bmask[n]; + j->code_bits -= n; + return k; +} + +stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) +{ + unsigned int k; + if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + k = j->code_buffer; + j->code_buffer <<= 1; + --j->code_bits; + return k & 0x80000000; +} + +// given a value that's at position X in the zigzag stream, +// where does it appear in the 8x8 matrix coded as row-major? +static const stbi_uc stbi__jpeg_dezigzag[64+15] = +{ + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63, + // let corrupt input sample past end + 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63 +}; + +// decode one 64-entry block-- +static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant) +{ + int diff,dc,k; + int t; + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + t = stbi__jpeg_huff_decode(j, hdc); + if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + + // 0 all the ac values now so we can do it 32-bits at a time + memset(data,0,64*sizeof(data[0])); + + diff = t ? stbi__extend_receive(j, t) : 0; + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc * dequant[0]); + + // decode AC components, see JPEG spec + k = 1; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) * dequant[zig]); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (rs != 0xf0) break; // end block + k += 16; + } else { + k += r; + // decode into unzigzag'd location + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]); + } + } + } while (k < 64); + return 1; +} + +static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b) +{ + int diff,dc; + int t; + if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + + if (j->succ_high == 0) { + // first scan for DC coefficient, must be first + memset(data,0,64*sizeof(data[0])); // 0 all the ac values now + t = stbi__jpeg_huff_decode(j, hdc); + if (t == -1) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + diff = t ? stbi__extend_receive(j, t) : 0; + + dc = j->img_comp[b].dc_pred + diff; + j->img_comp[b].dc_pred = dc; + data[0] = (short) (dc << j->succ_low); + } else { + // refinement scan for DC coefficient + if (stbi__jpeg_get_bit(j)) + data[0] += (short) (1 << j->succ_low); + } + return 1; +} + +// @OPTIMIZE: store non-zigzagged during the decode passes, +// and only de-zigzag when dequantizing +static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac) +{ + int k; + if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); + + if (j->succ_high == 0) { + int shift = j->succ_low; + + if (j->eob_run) { + --j->eob_run; + return 1; + } + + k = j->spec_start; + do { + unsigned int zig; + int c,r,s; + if (j->code_bits < 16) stbi__grow_buffer_unsafe(j); + c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1); + r = fac[c]; + if (r) { // fast-AC path + k += (r >> 4) & 15; // run + s = r & 15; // combined length + j->code_buffer <<= s; + j->code_bits -= s; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) ((r >> 8) << shift); + } else { + int rs = stbi__jpeg_huff_decode(j, hac); + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r); + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + --j->eob_run; + break; + } + k += 16; + } else { + k += r; + zig = stbi__jpeg_dezigzag[k++]; + data[zig] = (short) (stbi__extend_receive(j,s) << shift); + } + } + } while (k <= j->spec_end); + } else { + // refinement scan for these AC coefficients + + short bit = (short) (1 << j->succ_low); + + if (j->eob_run) { + --j->eob_run; + for (k = j->spec_start; k <= j->spec_end; ++k) { + short *p = &data[stbi__jpeg_dezigzag[k]]; + if (*p != 0) + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } + } else { + k = j->spec_start; + do { + int r,s; + int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh + if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG"); + s = rs & 15; + r = rs >> 4; + if (s == 0) { + if (r < 15) { + j->eob_run = (1 << r) - 1; + if (r) + j->eob_run += stbi__jpeg_get_bits(j, r); + r = 64; // force end of block + } else { + // r=15 s=0 should write 16 0s, so we just do + // a run of 15 0s and then write s (which is 0), + // so we don't have to do anything special here + } + } else { + if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG"); + // sign bit + if (stbi__jpeg_get_bit(j)) + s = bit; + else + s = -bit; + } + + // advance by r + while (k <= j->spec_end) { + short *p = &data[stbi__jpeg_dezigzag[k++]]; + if (*p != 0) { + if (stbi__jpeg_get_bit(j)) + if ((*p & bit)==0) { + if (*p > 0) + *p += bit; + else + *p -= bit; + } + } else { + if (r == 0) { + *p = (short) s; + break; + } + --r; + } + } + } while (k <= j->spec_end); + } + } + return 1; +} + +// take a -128..127 value and stbi__clamp it and convert to 0..255 +stbi_inline static stbi_uc stbi__clamp(int x) +{ + // trick to use a single test to catch both cases + if ((unsigned int) x > 255) { + if (x < 0) return 0; + if (x > 255) return 255; + } + return (stbi_uc) x; +} + +#define stbi__f2f(x) ((int) (((x) * 4096 + 0.5))) +#define stbi__fsh(x) ((x) * 4096) + +// derived from jidctint -- DCT_ISLOW +#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \ + int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \ + p2 = s2; \ + p3 = s6; \ + p1 = (p2+p3) * stbi__f2f(0.5411961f); \ + t2 = p1 + p3*stbi__f2f(-1.847759065f); \ + t3 = p1 + p2*stbi__f2f( 0.765366865f); \ + p2 = s0; \ + p3 = s4; \ + t0 = stbi__fsh(p2+p3); \ + t1 = stbi__fsh(p2-p3); \ + x0 = t0+t3; \ + x3 = t0-t3; \ + x1 = t1+t2; \ + x2 = t1-t2; \ + t0 = s7; \ + t1 = s5; \ + t2 = s3; \ + t3 = s1; \ + p3 = t0+t2; \ + p4 = t1+t3; \ + p1 = t0+t3; \ + p2 = t1+t2; \ + p5 = (p3+p4)*stbi__f2f( 1.175875602f); \ + t0 = t0*stbi__f2f( 0.298631336f); \ + t1 = t1*stbi__f2f( 2.053119869f); \ + t2 = t2*stbi__f2f( 3.072711026f); \ + t3 = t3*stbi__f2f( 1.501321110f); \ + p1 = p5 + p1*stbi__f2f(-0.899976223f); \ + p2 = p5 + p2*stbi__f2f(-2.562915447f); \ + p3 = p3*stbi__f2f(-1.961570560f); \ + p4 = p4*stbi__f2f(-0.390180644f); \ + t3 += p1+p4; \ + t2 += p2+p3; \ + t1 += p2+p4; \ + t0 += p1+p3; + +static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64]) +{ + int i,val[64],*v=val; + stbi_uc *o; + short *d = data; + + // columns + for (i=0; i < 8; ++i,++d, ++v) { + // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing + if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0 + && d[40]==0 && d[48]==0 && d[56]==0) { + // no shortcut 0 seconds + // (1|2|3|4|5|6|7)==0 0 seconds + // all separate -0.047 seconds + // 1 && 2|3 && 4|5 && 6|7: -0.047 seconds + int dcterm = d[0]*4; + v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm; + } else { + STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56]) + // constants scaled things up by 1<<12; let's bring them back + // down, but keep 2 extra bits of precision + x0 += 512; x1 += 512; x2 += 512; x3 += 512; + v[ 0] = (x0+t3) >> 10; + v[56] = (x0-t3) >> 10; + v[ 8] = (x1+t2) >> 10; + v[48] = (x1-t2) >> 10; + v[16] = (x2+t1) >> 10; + v[40] = (x2-t1) >> 10; + v[24] = (x3+t0) >> 10; + v[32] = (x3-t0) >> 10; + } + } + + for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) { + // no fast case since the first 1D IDCT spread components out + STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7]) + // constants scaled things up by 1<<12, plus we had 1<<2 from first + // loop, plus horizontal and vertical each scale by sqrt(8) so together + // we've got an extra 1<<3, so 1<<17 total we need to remove. + // so we want to round that, which means adding 0.5 * 1<<17, + // aka 65536. Also, we'll end up with -128 to 127 that we want + // to encode as 0..255 by adding 128, so we'll add that before the shift + x0 += 65536 + (128<<17); + x1 += 65536 + (128<<17); + x2 += 65536 + (128<<17); + x3 += 65536 + (128<<17); + // tried computing the shifts into temps, or'ing the temps to see + // if any were out of range, but that was slower + o[0] = stbi__clamp((x0+t3) >> 17); + o[7] = stbi__clamp((x0-t3) >> 17); + o[1] = stbi__clamp((x1+t2) >> 17); + o[6] = stbi__clamp((x1-t2) >> 17); + o[2] = stbi__clamp((x2+t1) >> 17); + o[5] = stbi__clamp((x2-t1) >> 17); + o[3] = stbi__clamp((x3+t0) >> 17); + o[4] = stbi__clamp((x3-t0) >> 17); + } +} + +#ifdef STBI_SSE2 +// sse2 integer IDCT. not the fastest possible implementation but it +// produces bit-identical results to the generic C version so it's +// fully "transparent". +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + // This is constructed to match our regular (generic) integer IDCT exactly. + __m128i row0, row1, row2, row3, row4, row5, row6, row7; + __m128i tmp; + + // dot product constant: even elems=x, odd elems=y + #define dct_const(x,y) _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y)) + + // out(0) = c0[even]*x + c0[odd]*y (c0, x, y 16-bit, out 32-bit) + // out(1) = c1[even]*x + c1[odd]*y + #define dct_rot(out0,out1, x,y,c0,c1) \ + __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \ + __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \ + __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \ + __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \ + __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \ + __m128i out1##_h = _mm_madd_epi16(c0##hi, c1) + + // out = in << 12 (in 16-bit, out 32-bit) + #define dct_widen(out, in) \ + __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \ + __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4) + + // wide add + #define dct_wadd(out, a, b) \ + __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_add_epi32(a##_h, b##_h) + + // wide sub + #define dct_wsub(out, a, b) \ + __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \ + __m128i out##_h = _mm_sub_epi32(a##_h, b##_h) + + // butterfly a/b, add bias, then shift by "s" and pack + #define dct_bfly32o(out0, out1, a,b,bias,s) \ + { \ + __m128i abiased_l = _mm_add_epi32(a##_l, bias); \ + __m128i abiased_h = _mm_add_epi32(a##_h, bias); \ + dct_wadd(sum, abiased, b); \ + dct_wsub(dif, abiased, b); \ + out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \ + out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \ + } + + // 8-bit interleave step (for transposes) + #define dct_interleave8(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi8(a, b); \ + b = _mm_unpackhi_epi8(tmp, b) + + // 16-bit interleave step (for transposes) + #define dct_interleave16(a, b) \ + tmp = a; \ + a = _mm_unpacklo_epi16(a, b); \ + b = _mm_unpackhi_epi16(tmp, b) + + #define dct_pass(bias,shift) \ + { \ + /* even part */ \ + dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \ + __m128i sum04 = _mm_add_epi16(row0, row4); \ + __m128i dif04 = _mm_sub_epi16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \ + dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \ + __m128i sum17 = _mm_add_epi16(row1, row7); \ + __m128i sum35 = _mm_add_epi16(row3, row5); \ + dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \ + dct_wadd(x4, y0o, y4o); \ + dct_wadd(x5, y1o, y5o); \ + dct_wadd(x6, y2o, y5o); \ + dct_wadd(x7, y3o, y4o); \ + dct_bfly32o(row0,row7, x0,x7,bias,shift); \ + dct_bfly32o(row1,row6, x1,x6,bias,shift); \ + dct_bfly32o(row2,row5, x2,x5,bias,shift); \ + dct_bfly32o(row3,row4, x3,x4,bias,shift); \ + } + + __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f)); + __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f)); + __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f)); + __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f)); + __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f)); + __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f)); + __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f)); + __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f)); + + // rounding biases in column/row passes, see stbi__idct_block for explanation. + __m128i bias_0 = _mm_set1_epi32(512); + __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17)); + + // load + row0 = _mm_load_si128((const __m128i *) (data + 0*8)); + row1 = _mm_load_si128((const __m128i *) (data + 1*8)); + row2 = _mm_load_si128((const __m128i *) (data + 2*8)); + row3 = _mm_load_si128((const __m128i *) (data + 3*8)); + row4 = _mm_load_si128((const __m128i *) (data + 4*8)); + row5 = _mm_load_si128((const __m128i *) (data + 5*8)); + row6 = _mm_load_si128((const __m128i *) (data + 6*8)); + row7 = _mm_load_si128((const __m128i *) (data + 7*8)); + + // column pass + dct_pass(bias_0, 10); + + { + // 16bit 8x8 transpose pass 1 + dct_interleave16(row0, row4); + dct_interleave16(row1, row5); + dct_interleave16(row2, row6); + dct_interleave16(row3, row7); + + // transpose pass 2 + dct_interleave16(row0, row2); + dct_interleave16(row1, row3); + dct_interleave16(row4, row6); + dct_interleave16(row5, row7); + + // transpose pass 3 + dct_interleave16(row0, row1); + dct_interleave16(row2, row3); + dct_interleave16(row4, row5); + dct_interleave16(row6, row7); + } + + // row pass + dct_pass(bias_1, 17); + + { + // pack + __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7 + __m128i p1 = _mm_packus_epi16(row2, row3); + __m128i p2 = _mm_packus_epi16(row4, row5); + __m128i p3 = _mm_packus_epi16(row6, row7); + + // 8bit 8x8 transpose pass 1 + dct_interleave8(p0, p2); // a0e0a1e1... + dct_interleave8(p1, p3); // c0g0c1g1... + + // transpose pass 2 + dct_interleave8(p0, p1); // a0c0e0g0... + dct_interleave8(p2, p3); // b0d0f0h0... + + // transpose pass 3 + dct_interleave8(p0, p2); // a0b0c0d0... + dct_interleave8(p1, p3); // a4b4c4d4... + + // store + _mm_storel_epi64((__m128i *) out, p0); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p2); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p1); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride; + _mm_storel_epi64((__m128i *) out, p3); out += out_stride; + _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e)); + } + +#undef dct_const +#undef dct_rot +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_interleave8 +#undef dct_interleave16 +#undef dct_pass +} + +#endif // STBI_SSE2 + +#ifdef STBI_NEON + +// NEON integer IDCT. should produce bit-identical +// results to the generic C version. +static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64]) +{ + int16x8_t row0, row1, row2, row3, row4, row5, row6, row7; + + int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f)); + int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f)); + int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f)); + int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f)); + int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f)); + int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f)); + int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f)); + int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f)); + int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f)); + int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f)); + int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f)); + int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f)); + +#define dct_long_mul(out, inq, coeff) \ + int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff) + +#define dct_long_mac(out, acc, inq, coeff) \ + int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \ + int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff) + +#define dct_widen(out, inq) \ + int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \ + int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12) + +// wide add +#define dct_wadd(out, a, b) \ + int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vaddq_s32(a##_h, b##_h) + +// wide sub +#define dct_wsub(out, a, b) \ + int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \ + int32x4_t out##_h = vsubq_s32(a##_h, b##_h) + +// butterfly a/b, then shift using "shiftop" by "s" and pack +#define dct_bfly32o(out0,out1, a,b,shiftop,s) \ + { \ + dct_wadd(sum, a, b); \ + dct_wsub(dif, a, b); \ + out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \ + out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \ + } + +#define dct_pass(shiftop, shift) \ + { \ + /* even part */ \ + int16x8_t sum26 = vaddq_s16(row2, row6); \ + dct_long_mul(p1e, sum26, rot0_0); \ + dct_long_mac(t2e, p1e, row6, rot0_1); \ + dct_long_mac(t3e, p1e, row2, rot0_2); \ + int16x8_t sum04 = vaddq_s16(row0, row4); \ + int16x8_t dif04 = vsubq_s16(row0, row4); \ + dct_widen(t0e, sum04); \ + dct_widen(t1e, dif04); \ + dct_wadd(x0, t0e, t3e); \ + dct_wsub(x3, t0e, t3e); \ + dct_wadd(x1, t1e, t2e); \ + dct_wsub(x2, t1e, t2e); \ + /* odd part */ \ + int16x8_t sum15 = vaddq_s16(row1, row5); \ + int16x8_t sum17 = vaddq_s16(row1, row7); \ + int16x8_t sum35 = vaddq_s16(row3, row5); \ + int16x8_t sum37 = vaddq_s16(row3, row7); \ + int16x8_t sumodd = vaddq_s16(sum17, sum35); \ + dct_long_mul(p5o, sumodd, rot1_0); \ + dct_long_mac(p1o, p5o, sum17, rot1_1); \ + dct_long_mac(p2o, p5o, sum35, rot1_2); \ + dct_long_mul(p3o, sum37, rot2_0); \ + dct_long_mul(p4o, sum15, rot2_1); \ + dct_wadd(sump13o, p1o, p3o); \ + dct_wadd(sump24o, p2o, p4o); \ + dct_wadd(sump23o, p2o, p3o); \ + dct_wadd(sump14o, p1o, p4o); \ + dct_long_mac(x4, sump13o, row7, rot3_0); \ + dct_long_mac(x5, sump24o, row5, rot3_1); \ + dct_long_mac(x6, sump23o, row3, rot3_2); \ + dct_long_mac(x7, sump14o, row1, rot3_3); \ + dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \ + dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \ + dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \ + dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \ + } + + // load + row0 = vld1q_s16(data + 0*8); + row1 = vld1q_s16(data + 1*8); + row2 = vld1q_s16(data + 2*8); + row3 = vld1q_s16(data + 3*8); + row4 = vld1q_s16(data + 4*8); + row5 = vld1q_s16(data + 5*8); + row6 = vld1q_s16(data + 6*8); + row7 = vld1q_s16(data + 7*8); + + // add DC bias + row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0)); + + // column pass + dct_pass(vrshrn_n_s32, 10); + + // 16bit 8x8 transpose + { +// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively. +// whether compilers actually get this is another story, sadly. +#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); } +#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); } + + // pass 1 + dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6 + dct_trn16(row2, row3); + dct_trn16(row4, row5); + dct_trn16(row6, row7); + + // pass 2 + dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4 + dct_trn32(row1, row3); + dct_trn32(row4, row6); + dct_trn32(row5, row7); + + // pass 3 + dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0 + dct_trn64(row1, row5); + dct_trn64(row2, row6); + dct_trn64(row3, row7); + +#undef dct_trn16 +#undef dct_trn32 +#undef dct_trn64 + } + + // row pass + // vrshrn_n_s32 only supports shifts up to 16, we need + // 17. so do a non-rounding shift of 16 first then follow + // up with a rounding shift by 1. + dct_pass(vshrn_n_s32, 16); + + { + // pack and round + uint8x8_t p0 = vqrshrun_n_s16(row0, 1); + uint8x8_t p1 = vqrshrun_n_s16(row1, 1); + uint8x8_t p2 = vqrshrun_n_s16(row2, 1); + uint8x8_t p3 = vqrshrun_n_s16(row3, 1); + uint8x8_t p4 = vqrshrun_n_s16(row4, 1); + uint8x8_t p5 = vqrshrun_n_s16(row5, 1); + uint8x8_t p6 = vqrshrun_n_s16(row6, 1); + uint8x8_t p7 = vqrshrun_n_s16(row7, 1); + + // again, these can translate into one instruction, but often don't. +#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; } +#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); } +#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); } + + // sadly can't use interleaved stores here since we only write + // 8 bytes to each scan line! + + // 8x8 8-bit transpose pass 1 + dct_trn8_8(p0, p1); + dct_trn8_8(p2, p3); + dct_trn8_8(p4, p5); + dct_trn8_8(p6, p7); + + // pass 2 + dct_trn8_16(p0, p2); + dct_trn8_16(p1, p3); + dct_trn8_16(p4, p6); + dct_trn8_16(p5, p7); + + // pass 3 + dct_trn8_32(p0, p4); + dct_trn8_32(p1, p5); + dct_trn8_32(p2, p6); + dct_trn8_32(p3, p7); + + // store + vst1_u8(out, p0); out += out_stride; + vst1_u8(out, p1); out += out_stride; + vst1_u8(out, p2); out += out_stride; + vst1_u8(out, p3); out += out_stride; + vst1_u8(out, p4); out += out_stride; + vst1_u8(out, p5); out += out_stride; + vst1_u8(out, p6); out += out_stride; + vst1_u8(out, p7); + +#undef dct_trn8_8 +#undef dct_trn8_16 +#undef dct_trn8_32 + } + +#undef dct_long_mul +#undef dct_long_mac +#undef dct_widen +#undef dct_wadd +#undef dct_wsub +#undef dct_bfly32o +#undef dct_pass +} + +#endif // STBI_NEON + +#define STBI__MARKER_none 0xff +// if there's a pending marker from the entropy stream, return that +// otherwise, fetch from the stream and get a marker. if there's no +// marker, return 0xff, which is never a valid marker value +static stbi_uc stbi__get_marker(stbi__jpeg *j) +{ + stbi_uc x; + if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; } + x = stbi__get8(j->s); + if (x != 0xff) return STBI__MARKER_none; + while (x == 0xff) + x = stbi__get8(j->s); // consume repeated 0xff fill bytes + return x; +} + +// in each scan, we'll have scan_n components, and the order +// of the components is specified by order[] +#define STBI__RESTART(x) ((x) >= 0xd0 && (x) <= 0xd7) + +// after a restart interval, stbi__jpeg_reset the entropy decoder and +// the dc prediction +static void stbi__jpeg_reset(stbi__jpeg *j) +{ + j->code_bits = 0; + j->code_buffer = 0; + j->nomore = 0; + j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0; + j->marker = STBI__MARKER_none; + j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff; + j->eob_run = 0; + // no more than 1<<31 MCUs if no restart_interal? that's plenty safe, + // since we don't even allow 1<<30 pixels +} + +static int stbi__parse_entropy_coded_data(stbi__jpeg *z) +{ + stbi__jpeg_reset(z); + if (!z->progressive) { + if (z->scan_n == 1) { + int i,j; + STBI_SIMD_ALIGN(short, data[64]); + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + // if it's NOT a restart, then just bail, so we get corrupt data + // rather than no data + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + STBI_SIMD_ALIGN(short, data[64]); + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x)*8; + int y2 = (j*z->img_comp[n].v + y)*8; + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0; + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data); + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } else { + if (z->scan_n == 1) { + int i,j; + int n = z->order[0]; + // non-interleaved data, we just need to process one block at a time, + // in trivial scanline order + // number of blocks to do just depends on how many actual "pixels" this + // component has, independent of interleaved MCU blocking and such + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + if (z->spec_start == 0) { + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } else { + int ha = z->img_comp[n].ha; + if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha])) + return 0; + } + // every data block is an MCU, so countdown the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } else { // interleaved + int i,j,k,x,y; + for (j=0; j < z->img_mcu_y; ++j) { + for (i=0; i < z->img_mcu_x; ++i) { + // scan an interleaved mcu... process scan_n components in order + for (k=0; k < z->scan_n; ++k) { + int n = z->order[k]; + // scan out an mcu's worth of this component; that's just determined + // by the basic H and V specified for the component + for (y=0; y < z->img_comp[n].v; ++y) { + for (x=0; x < z->img_comp[n].h; ++x) { + int x2 = (i*z->img_comp[n].h + x); + int y2 = (j*z->img_comp[n].v + y); + short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w); + if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n)) + return 0; + } + } + } + // after all interleaved components, that's an interleaved MCU, + // so now count down the restart interval + if (--z->todo <= 0) { + if (z->code_bits < 24) stbi__grow_buffer_unsafe(z); + if (!STBI__RESTART(z->marker)) return 1; + stbi__jpeg_reset(z); + } + } + } + return 1; + } + } +} + +static void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant) +{ + int i; + for (i=0; i < 64; ++i) + data[i] *= dequant[i]; +} + +static void stbi__jpeg_finish(stbi__jpeg *z) +{ + if (z->progressive) { + // dequantize and idct the data + int i,j,n; + for (n=0; n < z->s->img_n; ++n) { + int w = (z->img_comp[n].x+7) >> 3; + int h = (z->img_comp[n].y+7) >> 3; + for (j=0; j < h; ++j) { + for (i=0; i < w; ++i) { + short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w); + stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]); + z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data); + } + } + } + } +} + +static int stbi__process_marker(stbi__jpeg *z, int m) +{ + int L; + switch (m) { + case STBI__MARKER_none: // no marker found + return stbi__err("expected marker","Corrupt JPEG"); + + case 0xDD: // DRI - specify restart interval + if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG"); + z->restart_interval = stbi__get16be(z->s); + return 1; + + case 0xDB: // DQT - define quantization table + L = stbi__get16be(z->s)-2; + while (L > 0) { + int q = stbi__get8(z->s); + int p = q >> 4, sixteen = (p != 0); + int t = q & 15,i; + if (p != 0 && p != 1) return stbi__err("bad DQT type","Corrupt JPEG"); + if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG"); + + for (i=0; i < 64; ++i) + z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s)); + L -= (sixteen ? 129 : 65); + } + return L==0; + + case 0xC4: // DHT - define huffman table + L = stbi__get16be(z->s)-2; + while (L > 0) { + stbi_uc *v; + int sizes[16],i,n=0; + int q = stbi__get8(z->s); + int tc = q >> 4; + int th = q & 15; + if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG"); + for (i=0; i < 16; ++i) { + sizes[i] = stbi__get8(z->s); + n += sizes[i]; + } + L -= 17; + if (tc == 0) { + if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; + v = z->huff_dc[th].values; + } else { + if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0; + v = z->huff_ac[th].values; + } + for (i=0; i < n; ++i) + v[i] = stbi__get8(z->s); + if (tc != 0) + stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th); + L -= n; + } + return L==0; + } + + // check for comment block or APP blocks + if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) { + L = stbi__get16be(z->s); + if (L < 2) { + if (m == 0xFE) + return stbi__err("bad COM len","Corrupt JPEG"); + else + return stbi__err("bad APP len","Corrupt JPEG"); + } + L -= 2; + + if (m == 0xE0 && L >= 5) { // JFIF APP0 segment + static const unsigned char tag[5] = {'J','F','I','F','\0'}; + int ok = 1; + int i; + for (i=0; i < 5; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 5; + if (ok) + z->jfif = 1; + } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment + static const unsigned char tag[6] = {'A','d','o','b','e','\0'}; + int ok = 1; + int i; + for (i=0; i < 6; ++i) + if (stbi__get8(z->s) != tag[i]) + ok = 0; + L -= 6; + if (ok) { + stbi__get8(z->s); // version + stbi__get16be(z->s); // flags0 + stbi__get16be(z->s); // flags1 + z->app14_color_transform = stbi__get8(z->s); // color transform + L -= 6; + } + } + + stbi__skip(z->s, L); + return 1; + } + + return stbi__err("unknown marker","Corrupt JPEG"); +} + +// after we see SOS +static int stbi__process_scan_header(stbi__jpeg *z) +{ + int i; + int Ls = stbi__get16be(z->s); + z->scan_n = stbi__get8(z->s); + if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG"); + if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG"); + for (i=0; i < z->scan_n; ++i) { + int id = stbi__get8(z->s), which; + int q = stbi__get8(z->s); + for (which = 0; which < z->s->img_n; ++which) + if (z->img_comp[which].id == id) + break; + if (which == z->s->img_n) return 0; // no match + z->img_comp[which].hd = q >> 4; if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG"); + z->img_comp[which].ha = q & 15; if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG"); + z->order[i] = which; + } + + { + int aa; + z->spec_start = stbi__get8(z->s); + z->spec_end = stbi__get8(z->s); // should be 63, but might be 0 + aa = stbi__get8(z->s); + z->succ_high = (aa >> 4); + z->succ_low = (aa & 15); + if (z->progressive) { + if (z->spec_start > 63 || z->spec_end > 63 || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13) + return stbi__err("bad SOS", "Corrupt JPEG"); + } else { + if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG"); + if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG"); + z->spec_end = 63; + } + } + + return 1; +} + +static int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why) +{ + int i; + for (i=0; i < ncomp; ++i) { + if (z->img_comp[i].raw_data) { + STBI_FREE(z->img_comp[i].raw_data); + z->img_comp[i].raw_data = NULL; + z->img_comp[i].data = NULL; + } + if (z->img_comp[i].raw_coeff) { + STBI_FREE(z->img_comp[i].raw_coeff); + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].coeff = 0; + } + if (z->img_comp[i].linebuf) { + STBI_FREE(z->img_comp[i].linebuf); + z->img_comp[i].linebuf = NULL; + } + } + return why; +} + +static int stbi__process_frame_header(stbi__jpeg *z, int scan) +{ + stbi__context *s = z->s; + int Lf,p,i,q, h_max=1,v_max=1,c; + Lf = stbi__get16be(s); if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG + p = stbi__get8(s); if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline + s->img_y = stbi__get16be(s); if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG + s->img_x = stbi__get16be(s); if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + c = stbi__get8(s); + if (c != 3 && c != 1 && c != 4) return stbi__err("bad component count","Corrupt JPEG"); + s->img_n = c; + for (i=0; i < c; ++i) { + z->img_comp[i].data = NULL; + z->img_comp[i].linebuf = NULL; + } + + if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG"); + + z->rgb = 0; + for (i=0; i < s->img_n; ++i) { + static const unsigned char rgb[3] = { 'R', 'G', 'B' }; + z->img_comp[i].id = stbi__get8(s); + if (s->img_n == 3 && z->img_comp[i].id == rgb[i]) + ++z->rgb; + q = stbi__get8(s); + z->img_comp[i].h = (q >> 4); if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG"); + z->img_comp[i].v = q & 15; if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG"); + z->img_comp[i].tq = stbi__get8(s); if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG"); + } + + if (scan != STBI__SCAN_load) return 1; + + if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err("too large", "Image too large to decode"); + + for (i=0; i < s->img_n; ++i) { + if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h; + if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v; + } + + // compute interleaved mcu info + z->img_h_max = h_max; + z->img_v_max = v_max; + z->img_mcu_w = h_max * 8; + z->img_mcu_h = v_max * 8; + // these sizes can't be more than 17 bits + z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w; + z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h; + + for (i=0; i < s->img_n; ++i) { + // number of effective pixels (e.g. for non-interleaved MCU) + z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max; + z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max; + // to simplify generation, we'll allocate enough memory to decode + // the bogus oversized data from using interleaved MCUs and their + // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't + // discard the extra data until colorspace conversion + // + // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier) + // so these muls can't overflow with 32-bit ints (which we require) + z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8; + z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8; + z->img_comp[i].coeff = 0; + z->img_comp[i].raw_coeff = 0; + z->img_comp[i].linebuf = NULL; + z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15); + if (z->img_comp[i].raw_data == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + // align blocks for idct using mmx/sse + z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15); + if (z->progressive) { + // w2, h2 are multiples of 8 (see above) + z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8; + z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8; + z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15); + if (z->img_comp[i].raw_coeff == NULL) + return stbi__free_jpeg_components(z, i+1, stbi__err("outofmem", "Out of memory")); + z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15); + } + } + + return 1; +} + +// use comparisons since in some cases we handle more than one case (e.g. SOF) +#define stbi__DNL(x) ((x) == 0xdc) +#define stbi__SOI(x) ((x) == 0xd8) +#define stbi__EOI(x) ((x) == 0xd9) +#define stbi__SOF(x) ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2) +#define stbi__SOS(x) ((x) == 0xda) + +#define stbi__SOF_progressive(x) ((x) == 0xc2) + +static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) +{ + int m; + z->jfif = 0; + z->app14_color_transform = -1; // valid values are 0,1,2 + z->marker = STBI__MARKER_none; // initialize cached marker to empty + m = stbi__get_marker(z); + if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG"); + if (scan == STBI__SCAN_type) return 1; + m = stbi__get_marker(z); + while (!stbi__SOF(m)) { + if (!stbi__process_marker(z,m)) return 0; + m = stbi__get_marker(z); + while (m == STBI__MARKER_none) { + // some files have extra padding after their blocks, so ok, we'll scan + if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG"); + m = stbi__get_marker(z); + } + } + z->progressive = stbi__SOF_progressive(m); + if (!stbi__process_frame_header(z, scan)) return 0; + return 1; +} + +// decode image to YCbCr format +static int stbi__decode_jpeg_image(stbi__jpeg *j) +{ + int m; + for (m = 0; m < 4; m++) { + j->img_comp[m].raw_data = NULL; + j->img_comp[m].raw_coeff = NULL; + } + j->restart_interval = 0; + if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0; + m = stbi__get_marker(j); + while (!stbi__EOI(m)) { + if (stbi__SOS(m)) { + if (!stbi__process_scan_header(j)) return 0; + if (!stbi__parse_entropy_coded_data(j)) return 0; + if (j->marker == STBI__MARKER_none ) { + // handle 0s at the end of image data from IP Kamera 9060 + while (!stbi__at_eof(j->s)) { + int x = stbi__get8(j->s); + if (x == 255) { + j->marker = stbi__get8(j->s); + break; + } + } + // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 + } + } else if (stbi__DNL(m)) { + int Ld = stbi__get16be(j->s); + stbi__uint32 NL = stbi__get16be(j->s); + if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); + if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + } else { + if (!stbi__process_marker(j, m)) return 0; + } + m = stbi__get_marker(j); + } + if (j->progressive) + stbi__jpeg_finish(j); + return 1; +} + +// static jfif-centered resampling (across block boundaries) + +typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1, + int w, int hs); + +#define stbi__div4(x) ((stbi_uc) ((x) >> 2)) + +static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + STBI_NOTUSED(out); + STBI_NOTUSED(in_far); + STBI_NOTUSED(w); + STBI_NOTUSED(hs); + return in_near; +} + +static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples vertically for every one in input + int i; + STBI_NOTUSED(hs); + for (i=0; i < w; ++i) + out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2); + return out; +} + +static stbi_uc* stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate two samples horizontally for every one in input + int i; + stbi_uc *input = in_near; + + if (w == 1) { + // if only one sample, can't do any interpolation + out[0] = out[1] = input[0]; + return out; + } + + out[0] = input[0]; + out[1] = stbi__div4(input[0]*3 + input[1] + 2); + for (i=1; i < w-1; ++i) { + int n = 3*input[i]+2; + out[i*2+0] = stbi__div4(n+input[i-1]); + out[i*2+1] = stbi__div4(n+input[i+1]); + } + out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2); + out[i*2+1] = input[w-1]; + + STBI_NOTUSED(in_far); + STBI_NOTUSED(hs); + + return out; +} + +#define stbi__div16(x) ((stbi_uc) ((x) >> 4)) + +static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i,t0,t1; + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + out[0] = stbi__div4(t1+2); + for (i=1; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // need to generate 2x2 samples for every one in input + int i=0,t0,t1; + + if (w == 1) { + out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2); + return out; + } + + t1 = 3*in_near[0] + in_far[0]; + // process groups of 8 pixels for as long as we can. + // note we can't handle the last pixel in a row in this loop + // because we need to handle the filter boundary conditions. + for (; i < ((w-1) & ~7); i += 8) { +#if defined(STBI_SSE2) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + __m128i zero = _mm_setzero_si128(); + __m128i farb = _mm_loadl_epi64((__m128i *) (in_far + i)); + __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i)); + __m128i farw = _mm_unpacklo_epi8(farb, zero); + __m128i nearw = _mm_unpacklo_epi8(nearb, zero); + __m128i diff = _mm_sub_epi16(farw, nearw); + __m128i nears = _mm_slli_epi16(nearw, 2); + __m128i curr = _mm_add_epi16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + __m128i prv0 = _mm_slli_si128(curr, 2); + __m128i nxt0 = _mm_srli_si128(curr, 2); + __m128i prev = _mm_insert_epi16(prv0, t1, 0); + __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + __m128i bias = _mm_set1_epi16(8); + __m128i curs = _mm_slli_epi16(curr, 2); + __m128i prvd = _mm_sub_epi16(prev, curr); + __m128i nxtd = _mm_sub_epi16(next, curr); + __m128i curb = _mm_add_epi16(curs, bias); + __m128i even = _mm_add_epi16(prvd, curb); + __m128i odd = _mm_add_epi16(nxtd, curb); + + // interleave even and odd pixels, then undo scaling. + __m128i int0 = _mm_unpacklo_epi16(even, odd); + __m128i int1 = _mm_unpackhi_epi16(even, odd); + __m128i de0 = _mm_srli_epi16(int0, 4); + __m128i de1 = _mm_srli_epi16(int1, 4); + + // pack and write output + __m128i outv = _mm_packus_epi16(de0, de1); + _mm_storeu_si128((__m128i *) (out + i*2), outv); +#elif defined(STBI_NEON) + // load and perform the vertical filtering pass + // this uses 3*x + y = 4*x + (y - x) + uint8x8_t farb = vld1_u8(in_far + i); + uint8x8_t nearb = vld1_u8(in_near + i); + int16x8_t diff = vreinterpretq_s16_u16(vsubl_u8(farb, nearb)); + int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2)); + int16x8_t curr = vaddq_s16(nears, diff); // current row + + // horizontal filter works the same based on shifted vers of current + // row. "prev" is current row shifted right by 1 pixel; we need to + // insert the previous pixel value (from t1). + // "next" is current row shifted left by 1 pixel, with first pixel + // of next block of 8 pixels added in. + int16x8_t prv0 = vextq_s16(curr, curr, 7); + int16x8_t nxt0 = vextq_s16(curr, curr, 1); + int16x8_t prev = vsetq_lane_s16(t1, prv0, 0); + int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7); + + // horizontal filter, polyphase implementation since it's convenient: + // even pixels = 3*cur + prev = cur*4 + (prev - cur) + // odd pixels = 3*cur + next = cur*4 + (next - cur) + // note the shared term. + int16x8_t curs = vshlq_n_s16(curr, 2); + int16x8_t prvd = vsubq_s16(prev, curr); + int16x8_t nxtd = vsubq_s16(next, curr); + int16x8_t even = vaddq_s16(curs, prvd); + int16x8_t odd = vaddq_s16(curs, nxtd); + + // undo scaling and round, then store with even/odd phases interleaved + uint8x8x2_t o; + o.val[0] = vqrshrun_n_s16(even, 4); + o.val[1] = vqrshrun_n_s16(odd, 4); + vst2_u8(out + i*2, o); +#endif + + // "previous" value for next iter + t1 = 3*in_near[i+7] + in_far[i+7]; + } + + t0 = t1; + t1 = 3*in_near[i] + in_far[i]; + out[i*2] = stbi__div16(3*t1 + t0 + 8); + + for (++i; i < w; ++i) { + t0 = t1; + t1 = 3*in_near[i]+in_far[i]; + out[i*2-1] = stbi__div16(3*t0 + t1 + 8); + out[i*2 ] = stbi__div16(3*t1 + t0 + 8); + } + out[w*2-1] = stbi__div4(t1+2); + + STBI_NOTUSED(hs); + + return out; +} +#endif + +static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs) +{ + // resample with nearest-neighbor + int i,j; + STBI_NOTUSED(in_far); + for (i=0; i < w; ++i) + for (j=0; j < hs; ++j) + out[i*hs+j] = in_near[i]; + return out; +} + +// this is a reduced-precision calculation of YCbCr-to-RGB introduced +// to make sure the code produces the same results in both SIMD and scalar +#define stbi__float2fixed(x) (((int) ((x) * 4096.0f + 0.5f)) << 8) +static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step) +{ + int i; + for (i=0; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} + +#if defined(STBI_SSE2) || defined(STBI_NEON) +static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step) +{ + int i = 0; + +#ifdef STBI_SSE2 + // step == 3 is pretty ugly on the final interleave, and i'm not convinced + // it's useful in practice (you wouldn't use it for textures, for example). + // so just accelerate step == 4 case. + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + __m128i signflip = _mm_set1_epi8(-0x80); + __m128i cr_const0 = _mm_set1_epi16( (short) ( 1.40200f*4096.0f+0.5f)); + __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f)); + __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f)); + __m128i cb_const1 = _mm_set1_epi16( (short) ( 1.77200f*4096.0f+0.5f)); + __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128); + __m128i xw = _mm_set1_epi16(255); // alpha channel + + for (; i+7 < count; i += 8) { + // load + __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i)); + __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i)); + __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i)); + __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128 + __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128 + + // unpack to short (and left-shift cr, cb by 8) + __m128i yw = _mm_unpacklo_epi8(y_bias, y_bytes); + __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased); + __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased); + + // color transform + __m128i yws = _mm_srli_epi16(yw, 4); + __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw); + __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw); + __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1); + __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1); + __m128i rws = _mm_add_epi16(cr0, yws); + __m128i gwt = _mm_add_epi16(cb0, yws); + __m128i bws = _mm_add_epi16(yws, cb1); + __m128i gws = _mm_add_epi16(gwt, cr1); + + // descale + __m128i rw = _mm_srai_epi16(rws, 4); + __m128i bw = _mm_srai_epi16(bws, 4); + __m128i gw = _mm_srai_epi16(gws, 4); + + // back to byte, set up for transpose + __m128i brb = _mm_packus_epi16(rw, bw); + __m128i gxb = _mm_packus_epi16(gw, xw); + + // transpose to interleave channels + __m128i t0 = _mm_unpacklo_epi8(brb, gxb); + __m128i t1 = _mm_unpackhi_epi8(brb, gxb); + __m128i o0 = _mm_unpacklo_epi16(t0, t1); + __m128i o1 = _mm_unpackhi_epi16(t0, t1); + + // store + _mm_storeu_si128((__m128i *) (out + 0), o0); + _mm_storeu_si128((__m128i *) (out + 16), o1); + out += 32; + } + } +#endif + +#ifdef STBI_NEON + // in this version, step=3 support would be easy to add. but is there demand? + if (step == 4) { + // this is a fairly straightforward implementation and not super-optimized. + uint8x8_t signflip = vdup_n_u8(0x80); + int16x8_t cr_const0 = vdupq_n_s16( (short) ( 1.40200f*4096.0f+0.5f)); + int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f)); + int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f)); + int16x8_t cb_const1 = vdupq_n_s16( (short) ( 1.77200f*4096.0f+0.5f)); + + for (; i+7 < count; i += 8) { + // load + uint8x8_t y_bytes = vld1_u8(y + i); + uint8x8_t cr_bytes = vld1_u8(pcr + i); + uint8x8_t cb_bytes = vld1_u8(pcb + i); + int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip)); + int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip)); + + // expand to s16 + int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4)); + int16x8_t crw = vshll_n_s8(cr_biased, 7); + int16x8_t cbw = vshll_n_s8(cb_biased, 7); + + // color transform + int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0); + int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0); + int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1); + int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1); + int16x8_t rws = vaddq_s16(yws, cr0); + int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1); + int16x8_t bws = vaddq_s16(yws, cb1); + + // undo scaling, round, convert to byte + uint8x8x4_t o; + o.val[0] = vqrshrun_n_s16(rws, 4); + o.val[1] = vqrshrun_n_s16(gws, 4); + o.val[2] = vqrshrun_n_s16(bws, 4); + o.val[3] = vdup_n_u8(255); + + // store, interleaving r/g/b/a + vst4_u8(out, o); + out += 8*4; + } + } +#endif + + for (; i < count; ++i) { + int y_fixed = (y[i] << 20) + (1<<19); // rounding + int r,g,b; + int cr = pcr[i] - 128; + int cb = pcb[i] - 128; + r = y_fixed + cr* stbi__float2fixed(1.40200f); + g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000); + b = y_fixed + cb* stbi__float2fixed(1.77200f); + r >>= 20; + g >>= 20; + b >>= 20; + if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; } + if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; } + if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; } + out[0] = (stbi_uc)r; + out[1] = (stbi_uc)g; + out[2] = (stbi_uc)b; + out[3] = 255; + out += step; + } +} +#endif + +// set up the kernels +static void stbi__setup_jpeg(stbi__jpeg *j) +{ + j->idct_block_kernel = stbi__idct_block; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2; + +#ifdef STBI_SSE2 + if (stbi__sse2_available()) { + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; + } +#endif + +#ifdef STBI_NEON + j->idct_block_kernel = stbi__idct_simd; + j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd; + j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd; +#endif +} + +// clean up the temporary component buffers +static void stbi__cleanup_jpeg(stbi__jpeg *j) +{ + stbi__free_jpeg_components(j, j->s->img_n, 0); +} + +typedef struct +{ + resample_row_func resample; + stbi_uc *line0,*line1; + int hs,vs; // expansion factor in each axis + int w_lores; // horizontal pixels pre-expansion + int ystep; // how far through vertical expansion we are + int ypos; // which pre-expansion row we're on +} stbi__resample; + +// fast 0..255 * 0..255 => 0..255 rounded multiplication +static stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y) +{ + unsigned int t = x*y + 128; + return (stbi_uc) ((t + (t >>8)) >> 8); +} + +static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp) +{ + int n, decode_n, is_rgb; + z->s->img_n = 0; // make stbi__cleanup_jpeg safe + + // validate req_comp + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + + // load a jpeg image from whichever source, but leave in YCbCr format + if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; } + + // determine actual number of components to generate + n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1; + + is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif)); + + if (z->s->img_n == 3 && n < 3 && !is_rgb) + decode_n = 1; + else + decode_n = z->s->img_n; + + // resample and color-convert + { + int k; + unsigned int i,j; + stbi_uc *output; + stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL }; + + stbi__resample res_comp[4]; + + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + + // allocate line buffer big enough for upsampling off the edges + // with upsample factor of 4 + z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3); + if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + r->hs = z->img_h_max / z->img_comp[k].h; + r->vs = z->img_v_max / z->img_comp[k].v; + r->ystep = r->vs >> 1; + r->w_lores = (z->s->img_x + r->hs-1) / r->hs; + r->ypos = 0; + r->line0 = r->line1 = z->img_comp[k].data; + + if (r->hs == 1 && r->vs == 1) r->resample = resample_row_1; + else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2; + else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2; + else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel; + else r->resample = stbi__resample_row_generic; + } + + // can't error after this so, this is safe + output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1); + if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); } + + // now go ahead and resample + for (j=0; j < z->s->img_y; ++j) { + stbi_uc *out = output + n * z->s->img_x * j; + for (k=0; k < decode_n; ++k) { + stbi__resample *r = &res_comp[k]; + int y_bot = r->ystep >= (r->vs >> 1); + coutput[k] = r->resample(z->img_comp[k].linebuf, + y_bot ? r->line1 : r->line0, + y_bot ? r->line0 : r->line1, + r->w_lores, r->hs); + if (++r->ystep >= r->vs) { + r->ystep = 0; + r->line0 = r->line1; + if (++r->ypos < z->img_comp[k].y) + r->line1 += z->img_comp[k].w2; + } + } + if (n >= 3) { + stbi_uc *y = coutput[0]; + if (z->s->img_n == 3) { + if (is_rgb) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = y[i]; + out[1] = coutput[1][i]; + out[2] = coutput[2][i]; + out[3] = 255; + out += n; + } + } else { + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else if (z->s->img_n == 4) { + if (z->app14_color_transform == 0) { // CMYK + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(coutput[0][i], m); + out[1] = stbi__blinn_8x8(coutput[1][i], m); + out[2] = stbi__blinn_8x8(coutput[2][i], m); + out[3] = 255; + out += n; + } + } else if (z->app14_color_transform == 2) { // YCCK + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + out[0] = stbi__blinn_8x8(255 - out[0], m); + out[1] = stbi__blinn_8x8(255 - out[1], m); + out[2] = stbi__blinn_8x8(255 - out[2], m); + out += n; + } + } else { // YCbCr + alpha? Ignore the fourth channel for now + z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n); + } + } else + for (i=0; i < z->s->img_x; ++i) { + out[0] = out[1] = out[2] = y[i]; + out[3] = 255; // not used if n==3 + out += n; + } + } else { + if (is_rgb) { + if (n == 1) + for (i=0; i < z->s->img_x; ++i) + *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + else { + for (i=0; i < z->s->img_x; ++i, out += 2) { + out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]); + out[1] = 255; + } + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 0) { + for (i=0; i < z->s->img_x; ++i) { + stbi_uc m = coutput[3][i]; + stbi_uc r = stbi__blinn_8x8(coutput[0][i], m); + stbi_uc g = stbi__blinn_8x8(coutput[1][i], m); + stbi_uc b = stbi__blinn_8x8(coutput[2][i], m); + out[0] = stbi__compute_y(r, g, b); + out[1] = 255; + out += n; + } + } else if (z->s->img_n == 4 && z->app14_color_transform == 2) { + for (i=0; i < z->s->img_x; ++i) { + out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]); + out[1] = 255; + out += n; + } + } else { + stbi_uc *y = coutput[0]; + if (n == 1) + for (i=0; i < z->s->img_x; ++i) out[i] = y[i]; + else + for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; } + } + } + } + stbi__cleanup_jpeg(z); + *out_x = z->s->img_x; + *out_y = z->s->img_y; + if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output + return output; + } +} + +static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + unsigned char* result; + stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); + STBI_NOTUSED(ri); + j->s = s; + stbi__setup_jpeg(j); + result = load_jpeg_image(j, x,y,comp,req_comp); + STBI_FREE(j); + return result; +} + +static int stbi__jpeg_test(stbi__context *s) +{ + int r; + stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); + j->s = s; + stbi__setup_jpeg(j); + r = stbi__decode_jpeg_header(j, STBI__SCAN_type); + stbi__rewind(s); + STBI_FREE(j); + return r; +} + +static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp) +{ + if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) { + stbi__rewind( j->s ); + return 0; + } + if (x) *x = j->s->img_x; + if (y) *y = j->s->img_y; + if (comp) *comp = j->s->img_n >= 3 ? 3 : 1; + return 1; +} + +static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) +{ + int result; + stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); + j->s = s; + result = stbi__jpeg_info_raw(j, x, y, comp); + STBI_FREE(j); + return result; +} +#endif + +// public domain zlib decode v0.2 Sean Barrett 2006-11-18 +// simple implementation +// - all input must be provided in an upfront buffer +// - all output is written to a single output buffer (can malloc/realloc) +// performance +// - fast huffman + +#ifndef STBI_NO_ZLIB + +// fast-way is faster to check than jpeg huffman, but slow way is slower +#define STBI__ZFAST_BITS 9 // accelerate all cases in default tables +#define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1) + +// zlib-style huffman encoding +// (jpegs packs from left, zlib from right, so can't share code) +typedef struct +{ + stbi__uint16 fast[1 << STBI__ZFAST_BITS]; + stbi__uint16 firstcode[16]; + int maxcode[17]; + stbi__uint16 firstsymbol[16]; + stbi_uc size[288]; + stbi__uint16 value[288]; +} stbi__zhuffman; + +stbi_inline static int stbi__bitreverse16(int n) +{ + n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1); + n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2); + n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4); + n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8); + return n; +} + +stbi_inline static int stbi__bit_reverse(int v, int bits) +{ + STBI_ASSERT(bits <= 16); + // to bit reverse n bits, reverse 16 and shift + // e.g. 11 bits, bit reverse and shift away 5 + return stbi__bitreverse16(v) >> (16-bits); +} + +static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num) +{ + int i,k=0; + int code, next_code[16], sizes[17]; + + // DEFLATE spec for generating codes + memset(sizes, 0, sizeof(sizes)); + memset(z->fast, 0, sizeof(z->fast)); + for (i=0; i < num; ++i) + ++sizes[sizelist[i]]; + sizes[0] = 0; + for (i=1; i < 16; ++i) + if (sizes[i] > (1 << i)) + return stbi__err("bad sizes", "Corrupt PNG"); + code = 0; + for (i=1; i < 16; ++i) { + next_code[i] = code; + z->firstcode[i] = (stbi__uint16) code; + z->firstsymbol[i] = (stbi__uint16) k; + code = (code + sizes[i]); + if (sizes[i]) + if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG"); + z->maxcode[i] = code << (16-i); // preshift for inner loop + code <<= 1; + k += sizes[i]; + } + z->maxcode[16] = 0x10000; // sentinel + for (i=0; i < num; ++i) { + int s = sizelist[i]; + if (s) { + int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s]; + stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i); + z->size [c] = (stbi_uc ) s; + z->value[c] = (stbi__uint16) i; + if (s <= STBI__ZFAST_BITS) { + int j = stbi__bit_reverse(next_code[s],s); + while (j < (1 << STBI__ZFAST_BITS)) { + z->fast[j] = fastv; + j += (1 << s); + } + } + ++next_code[s]; + } + } + return 1; +} + +// zlib-from-memory implementation for PNG reading +// because PNG allows splitting the zlib stream arbitrarily, +// and it's annoying structurally to have PNG call ZLIB call PNG, +// we require PNG read all the IDATs and combine them into a single +// memory buffer + +typedef struct +{ + stbi_uc *zbuffer, *zbuffer_end; + int num_bits; + stbi__uint32 code_buffer; + + char *zout; + char *zout_start; + char *zout_end; + int z_expandable; + + stbi__zhuffman z_length, z_distance; +} stbi__zbuf; + +stbi_inline static int stbi__zeof(stbi__zbuf *z) +{ + return (z->zbuffer >= z->zbuffer_end); +} + +stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z) +{ + return stbi__zeof(z) ? 0 : *z->zbuffer++; +} + +static void stbi__fill_bits(stbi__zbuf *z) +{ + do { + if (z->code_buffer >= (1U << z->num_bits)) { + z->zbuffer = z->zbuffer_end; /* treat this as EOF so we fail. */ + return; + } + z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits; + z->num_bits += 8; + } while (z->num_bits <= 24); +} + +stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n) +{ + unsigned int k; + if (z->num_bits < n) stbi__fill_bits(z); + k = z->code_buffer & ((1 << n) - 1); + z->code_buffer >>= n; + z->num_bits -= n; + return k; +} + +static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s,k; + // not resolved by fast table, so compute it the slow way + // use jpeg approach, which requires MSbits at top + k = stbi__bit_reverse(a->code_buffer, 16); + for (s=STBI__ZFAST_BITS+1; ; ++s) + if (k < z->maxcode[s]) + break; + if (s >= 16) return -1; // invalid code! + // code size is s, so: + b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s]; + if ((long unsigned int) b >= sizeof (z->size)) return -1; // some data was corrupt somewhere! + if (z->size[b] != s) return -1; // was originally an assert, but report failure instead. + a->code_buffer >>= s; + a->num_bits -= s; + return z->value[b]; +} + +stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) +{ + int b,s; + if (a->num_bits < 16) { + if (stbi__zeof(a)) { + return -1; /* report error for unexpected end of data. */ + } + stbi__fill_bits(a); + } + b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; + if (b) { + s = b >> 9; + a->code_buffer >>= s; + a->num_bits -= s; + return b & 511; + } + return stbi__zhuffman_decode_slowpath(a, z); +} + +static int stbi__zexpand(stbi__zbuf *z, char *zout, int n) // need to make room for n bytes +{ + char *q; + unsigned int cur, limit, old_limit; + z->zout = zout; + if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG"); + cur = (unsigned int) (z->zout - z->zout_start); + limit = old_limit = (unsigned) (z->zout_end - z->zout_start); + if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory"); + while (cur + n > limit) { + if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory"); + limit *= 2; + } + q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit); + STBI_NOTUSED(old_limit); + if (q == NULL) return stbi__err("outofmem", "Out of memory"); + z->zout_start = q; + z->zout = q + cur; + z->zout_end = q + limit; + return 1; +} + +static const int stbi__zlength_base[31] = { + 3,4,5,6,7,8,9,10,11,13, + 15,17,19,23,27,31,35,43,51,59, + 67,83,99,115,131,163,195,227,258,0,0 }; + +static const int stbi__zlength_extra[31]= +{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; + +static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, +257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; + +static const int stbi__zdist_extra[32] = +{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +static int stbi__parse_huffman_block(stbi__zbuf *a) +{ + char *zout = a->zout; + for(;;) { + int z = stbi__zhuffman_decode(a, &a->z_length); + if (z < 256) { + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes + if (zout >= a->zout_end) { + if (!stbi__zexpand(a, zout, 1)) return 0; + zout = a->zout; + } + *zout++ = (char) z; + } else { + stbi_uc *p; + int len,dist; + if (z == 256) { + a->zout = zout; + return 1; + } + z -= 257; + len = stbi__zlength_base[z]; + if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); + z = stbi__zhuffman_decode(a, &a->z_distance); + if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + dist = stbi__zdist_base[z]; + if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); + if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); + if (zout + len > a->zout_end) { + if (!stbi__zexpand(a, zout, len)) return 0; + zout = a->zout; + } + p = (stbi_uc *) (zout - dist); + if (dist == 1) { // run of one byte; common in images. + stbi_uc v = *p; + if (len) { do *zout++ = v; while (--len); } + } else { + if (len) { do *zout++ = *p++; while (--len); } + } + } + } +} + +static int stbi__compute_huffman_codes(stbi__zbuf *a) +{ + static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; + stbi__zhuffman z_codelength; + stbi_uc lencodes[286+32+137];//padding for maximum single op + stbi_uc codelength_sizes[19]; + int i,n; + + int hlit = stbi__zreceive(a,5) + 257; + int hdist = stbi__zreceive(a,5) + 1; + int hclen = stbi__zreceive(a,4) + 4; + int ntot = hlit + hdist; + + memset(codelength_sizes, 0, sizeof(codelength_sizes)); + for (i=0; i < hclen; ++i) { + int s = stbi__zreceive(a,3); + codelength_sizes[length_dezigzag[i]] = (stbi_uc) s; + } + if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0; + + n = 0; + while (n < ntot) { + int c = stbi__zhuffman_decode(a, &z_codelength); + if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG"); + if (c < 16) + lencodes[n++] = (stbi_uc) c; + else { + stbi_uc fill = 0; + if (c == 16) { + c = stbi__zreceive(a,2)+3; + if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG"); + fill = lencodes[n-1]; + } else if (c == 17) { + c = stbi__zreceive(a,3)+3; + } else if (c == 18) { + c = stbi__zreceive(a,7)+11; + } else { + return stbi__err("bad codelengths", "Corrupt PNG"); + } + if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG"); + memset(lencodes+n, fill, c); + n += c; + } + } + if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG"); + if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0; + return 1; +} + +static int stbi__parse_uncompressed_block(stbi__zbuf *a) +{ + stbi_uc header[4]; + int len,nlen,k; + if (a->num_bits & 7) + stbi__zreceive(a, a->num_bits & 7); // discard + // drain the bit-packed data into header + k = 0; + while (a->num_bits > 0) { + header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check + a->code_buffer >>= 8; + a->num_bits -= 8; + } + if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG"); + // now fill header the normal way + while (k < 4) + header[k++] = stbi__zget8(a); + len = header[1] * 256 + header[0]; + nlen = header[3] * 256 + header[2]; + if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG"); + if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG"); + if (a->zout + len > a->zout_end) + if (!stbi__zexpand(a, a->zout, len)) return 0; + memcpy(a->zout, a->zbuffer, len); + a->zbuffer += len; + a->zout += len; + return 1; +} + +static int stbi__parse_zlib_header(stbi__zbuf *a) +{ + int cmf = stbi__zget8(a); + int cm = cmf & 15; + /* int cinfo = cmf >> 4; */ + int flg = stbi__zget8(a); + if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec + if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png + if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png + // window = 1 << (8 + cinfo)... but who cares, we fully buffer output + return 1; +} + +static const stbi_uc stbi__zdefault_length[288] = +{ + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8 +}; +static const stbi_uc stbi__zdefault_distance[32] = +{ + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5 +}; +/* +Init algorithm: +{ + int i; // use <= to match clearly with spec + for (i=0; i <= 143; ++i) stbi__zdefault_length[i] = 8; + for ( ; i <= 255; ++i) stbi__zdefault_length[i] = 9; + for ( ; i <= 279; ++i) stbi__zdefault_length[i] = 7; + for ( ; i <= 287; ++i) stbi__zdefault_length[i] = 8; + + for (i=0; i <= 31; ++i) stbi__zdefault_distance[i] = 5; +} +*/ + +static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) +{ + int final, type; + if (parse_header) + if (!stbi__parse_zlib_header(a)) return 0; + a->num_bits = 0; + a->code_buffer = 0; + do { + final = stbi__zreceive(a,1); + type = stbi__zreceive(a,2); + if (type == 0) { + if (!stbi__parse_uncompressed_block(a)) return 0; + } else if (type == 3) { + return 0; + } else { + if (type == 1) { + // use fixed code lengths + if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , 288)) return 0; + if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0; + } else { + if (!stbi__compute_huffman_codes(a)) return 0; + } + if (!stbi__parse_huffman_block(a)) return 0; + } + } while (!final); + return 1; +} + +static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header) +{ + a->zout_start = obuf; + a->zout = obuf; + a->zout_end = obuf + olen; + a->z_expandable = exp; + + return stbi__parse_zlib(a, parse_header); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, 1)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen) +{ + return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen); +} + +STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(initial_size); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer + len; + if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 1)) + return (int) (a.zout - a.zout_start); + else + return -1; +} + +STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen) +{ + stbi__zbuf a; + char *p = (char *) stbi__malloc(16384); + if (p == NULL) return NULL; + a.zbuffer = (stbi_uc *) buffer; + a.zbuffer_end = (stbi_uc *) buffer+len; + if (stbi__do_zlib(&a, p, 16384, 1, 0)) { + if (outlen) *outlen = (int) (a.zout - a.zout_start); + return a.zout_start; + } else { + STBI_FREE(a.zout_start); + return NULL; + } +} + +STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen) +{ + stbi__zbuf a; + a.zbuffer = (stbi_uc *) ibuffer; + a.zbuffer_end = (stbi_uc *) ibuffer + ilen; + if (stbi__do_zlib(&a, obuffer, olen, 0, 0)) + return (int) (a.zout - a.zout_start); + else + return -1; +} +#endif + +// public domain "baseline" PNG decoder v0.10 Sean Barrett 2006-11-18 +// simple implementation +// - only 8-bit samples +// - no CRC checking +// - allocates lots of intermediate memory +// - avoids problem of streaming data between subsystems +// - avoids explicit window management +// performance +// - uses stb_zlib, a PD zlib implementation with fast huffman decoding + +#ifndef STBI_NO_PNG +typedef struct +{ + stbi__uint32 length; + stbi__uint32 type; +} stbi__pngchunk; + +static stbi__pngchunk stbi__get_chunk_header(stbi__context *s) +{ + stbi__pngchunk c; + c.length = stbi__get32be(s); + c.type = stbi__get32be(s); + return c; +} + +static int stbi__check_png_header(stbi__context *s) +{ + static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 }; + int i; + for (i=0; i < 8; ++i) + if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG"); + return 1; +} + +typedef struct +{ + stbi__context *s; + stbi_uc *idata, *expanded, *out; + int depth; +} stbi__png; + + +enum { + STBI__F_none=0, + STBI__F_sub=1, + STBI__F_up=2, + STBI__F_avg=3, + STBI__F_paeth=4, + // synthetic filters used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static stbi_uc first_row_filter[5] = +{ + STBI__F_none, + STBI__F_sub, + STBI__F_none, + STBI__F_avg_first, + STBI__F_paeth_first +}; + +static int stbi__paeth(int a, int b, int c) +{ + int p = a + b - c; + int pa = abs(p-a); + int pb = abs(p-b); + int pc = abs(p-c); + if (pa <= pb && pa <= pc) return a; + if (pb <= pc) return b; + return c; +} + +static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; + +// create the png data from post-deflated data +static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) +{ + int bytes = (depth == 16? 2 : 1); + stbi__context *s = a->s; + stbi__uint32 i,j,stride = x*out_n*bytes; + stbi__uint32 img_len, img_width_bytes; + int k; + int img_n = s->img_n; // copy it into a local for later + + int output_bytes = out_n*bytes; + int filter_bytes = img_n*bytes; + int width = x; + + STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1); + a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into + if (!a->out) return stbi__err("outofmem", "Out of memory"); + + if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); + img_width_bytes = (((img_n * x * depth) + 7) >> 3); + img_len = (img_width_bytes + 1) * y; + + // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, + // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros), + // so just check for raw_len < img_len always. + if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *prior; + int filter = *raw++; + + if (filter > 4) + return stbi__err("invalid filter","Corrupt PNG"); + + if (depth < 8) { + if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); + cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place + filter_bytes = 1; + width = img_width_bytes; + } + prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above + + // if first row, use special filter that doesn't sample previous row + if (j == 0) filter = first_row_filter[filter]; + + // handle first byte explicitly + for (k=0; k < filter_bytes; ++k) { + switch (filter) { + case STBI__F_none : cur[k] = raw[k]; break; + case STBI__F_sub : cur[k] = raw[k]; break; + case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; + case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; + case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; + case STBI__F_avg_first : cur[k] = raw[k]; break; + case STBI__F_paeth_first: cur[k] = raw[k]; break; + } + } + + if (depth == 8) { + if (img_n != out_n) + cur[img_n] = 255; // first pixel + raw += img_n; + cur += out_n; + prior += out_n; + } else if (depth == 16) { + if (img_n != out_n) { + cur[filter_bytes] = 255; // first pixel top byte + cur[filter_bytes+1] = 255; // first pixel bottom byte + } + raw += filter_bytes; + cur += output_bytes; + prior += output_bytes; + } else { + raw += 1; + cur += 1; + prior += 1; + } + + // this is a little gross, so that we don't switch per-pixel or per-component + if (depth < 8 || img_n == out_n) { + int nk = (width - 1)*filter_bytes; + #define STBI__CASE(f) \ + case f: \ + for (k=0; k < nk; ++k) + switch (filter) { + // "none" filter turns into a memcpy here; make that explicit. + case STBI__F_none: memcpy(cur, raw, nk); break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; + } + #undef STBI__CASE + raw += nk; + } else { + STBI_ASSERT(img_n+1 == out_n); + #define STBI__CASE(f) \ + case f: \ + for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ + for (k=0; k < filter_bytes; ++k) + switch (filter) { + STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; + STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; + STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; + STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; + STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; + STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; + STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; + } + #undef STBI__CASE + + // the loop above sets the high byte of the pixels' alpha, but for + // 16 bit png files we also need the low byte set. we'll do that here. + if (depth == 16) { + cur = a->out + stride*j; // start at the beginning of the row again + for (i=0; i < x; ++i,cur+=output_bytes) { + cur[filter_bytes+1] = 255; + } + } + } + } + + // we make a separate pass to expand bits to pixels; for performance, + // this could run two scanlines behind the above code, so it won't + // intefere with filtering but will still be in the cache. + if (depth < 8) { + for (j=0; j < y; ++j) { + stbi_uc *cur = a->out + stride*j; + stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; + // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit + // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + + // note that the final byte might overshoot and write more data than desired. + // we can allocate enough data that this never writes out of memory, but it + // could also overwrite the next scanline. can it overwrite non-empty data + // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. + // so we need to explicitly clamp the final ones + + if (depth == 4) { + for (k=x*img_n; k >= 2; k-=2, ++in) { + *cur++ = scale * ((*in >> 4) ); + *cur++ = scale * ((*in ) & 0x0f); + } + if (k > 0) *cur++ = scale * ((*in >> 4) ); + } else if (depth == 2) { + for (k=x*img_n; k >= 4; k-=4, ++in) { + *cur++ = scale * ((*in >> 6) ); + *cur++ = scale * ((*in >> 4) & 0x03); + *cur++ = scale * ((*in >> 2) & 0x03); + *cur++ = scale * ((*in ) & 0x03); + } + if (k > 0) *cur++ = scale * ((*in >> 6) ); + if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); + if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); + } else if (depth == 1) { + for (k=x*img_n; k >= 8; k-=8, ++in) { + *cur++ = scale * ((*in >> 7) ); + *cur++ = scale * ((*in >> 6) & 0x01); + *cur++ = scale * ((*in >> 5) & 0x01); + *cur++ = scale * ((*in >> 4) & 0x01); + *cur++ = scale * ((*in >> 3) & 0x01); + *cur++ = scale * ((*in >> 2) & 0x01); + *cur++ = scale * ((*in >> 1) & 0x01); + *cur++ = scale * ((*in ) & 0x01); + } + if (k > 0) *cur++ = scale * ((*in >> 7) ); + if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); + if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); + if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); + if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); + if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); + if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); + } + if (img_n != out_n) { + int q; + // insert alpha = 255 + cur = a->out + stride*j; + if (img_n == 1) { + for (q=x-1; q >= 0; --q) { + cur[q*2+1] = 255; + cur[q*2+0] = cur[q]; + } + } else { + STBI_ASSERT(img_n == 3); + for (q=x-1; q >= 0; --q) { + cur[q*4+3] = 255; + cur[q*4+2] = cur[q*3+2]; + cur[q*4+1] = cur[q*3+1]; + cur[q*4+0] = cur[q*3+0]; + } + } + } + } + } else if (depth == 16) { + // force the image data from big-endian to platform-native. + // this is done in a separate pass due to the decoding relying + // on the data being untouched, but could probably be done + // per-line during decode if care is taken. + stbi_uc *cur = a->out; + stbi__uint16 *cur16 = (stbi__uint16*)cur; + + for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { + *cur16 = (cur[0] << 8) | cur[1]; + } + } + + return 1; +} + +static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced) +{ + int bytes = (depth == 16 ? 2 : 1); + int out_bytes = out_n * bytes; + stbi_uc *final; + int p; + if (!interlaced) + return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color); + + // de-interlacing + final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0); + for (p=0; p < 7; ++p) { + int xorig[] = { 0,4,0,2,0,1,0 }; + int yorig[] = { 0,0,4,0,2,0,1 }; + int xspc[] = { 8,8,4,4,2,2,1 }; + int yspc[] = { 8,8,8,4,4,2,2 }; + int i,j,x,y; + // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1 + x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p]; + y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p]; + if (x && y) { + stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y; + if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) { + STBI_FREE(final); + return 0; + } + for (j=0; j < y; ++j) { + for (i=0; i < x; ++i) { + int out_y = j*yspc[p]+yorig[p]; + int out_x = i*xspc[p]+xorig[p]; + memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes, + a->out + (j*x+i)*out_bytes, out_bytes); + } + } + STBI_FREE(a->out); + image_data += img_len; + image_data_len -= img_len; + } + } + a->out = final; + + return 1; +} + +static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + // compute color-based transparency, assuming we've + // already got 255 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i=0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 255); + p += 2; + } + } else { + for (i=0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi__uint16 *p = (stbi__uint16*) z->out; + + // compute color-based transparency, assuming we've + // already got 65535 as the alpha value in the output + STBI_ASSERT(out_n == 2 || out_n == 4); + + if (out_n == 2) { + for (i = 0; i < pixel_count; ++i) { + p[1] = (p[0] == tc[0] ? 0 : 65535); + p += 2; + } + } else { + for (i = 0; i < pixel_count; ++i) { + if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2]) + p[3] = 0; + p += 4; + } + } + return 1; +} + +static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n) +{ + stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y; + stbi_uc *p, *temp_out, *orig = a->out; + + p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0); + if (p == NULL) return stbi__err("outofmem", "Out of memory"); + + // between here and free(out) below, exitting would leak + temp_out = p; + + if (pal_img_n == 3) { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p += 3; + } + } else { + for (i=0; i < pixel_count; ++i) { + int n = orig[i]*4; + p[0] = palette[n ]; + p[1] = palette[n+1]; + p[2] = palette[n+2]; + p[3] = palette[n+3]; + p += 4; + } + } + STBI_FREE(a->out); + a->out = temp_out; + + STBI_NOTUSED(len); + + return 1; +} + +static int stbi__unpremultiply_on_load = 0; +static int stbi__de_iphone_flag = 0; + +STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply) +{ + stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply; +} + +STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) +{ + stbi__de_iphone_flag = flag_true_if_should_convert; +} + +static void stbi__de_iphone(stbi__png *z) +{ + stbi__context *s = z->s; + stbi__uint32 i, pixel_count = s->img_x * s->img_y; + stbi_uc *p = z->out; + + if (s->img_out_n == 3) { // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 3; + } + } else { + STBI_ASSERT(s->img_out_n == 4); + if (stbi__unpremultiply_on_load) { + // convert bgr to rgb and unpremultiply + for (i=0; i < pixel_count; ++i) { + stbi_uc a = p[3]; + stbi_uc t = p[0]; + if (a) { + stbi_uc half = a / 2; + p[0] = (p[2] * 255 + half) / a; + p[1] = (p[1] * 255 + half) / a; + p[2] = ( t * 255 + half) / a; + } else { + p[0] = p[2]; + p[2] = t; + } + p += 4; + } + } else { + // convert bgr to rgb + for (i=0; i < pixel_count; ++i) { + stbi_uc t = p[0]; + p[0] = p[2]; + p[2] = t; + p += 4; + } + } + } +} + +#define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d)) + +static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) +{ + stbi_uc palette[1024], pal_img_n=0; + stbi_uc has_trans=0, tc[3]={0}; + stbi__uint16 tc16[3]; + stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0; + int first=1,k,interlace=0, color=0, is_iphone=0; + stbi__context *s = z->s; + + z->expanded = NULL; + z->idata = NULL; + z->out = NULL; + + if (!stbi__check_png_header(s)) return 0; + + if (scan == STBI__SCAN_type) return 1; + + for (;;) { + stbi__pngchunk c = stbi__get_chunk_header(s); + switch (c.type) { + case STBI__PNG_TYPE('C','g','B','I'): + is_iphone = 1; + stbi__skip(s, c.length); + break; + case STBI__PNG_TYPE('I','H','D','R'): { + int comp,filter; + if (!first) return stbi__err("multiple IHDR","Corrupt PNG"); + first = 0; + if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG"); + s->img_x = stbi__get32be(s); + s->img_y = stbi__get32be(s); + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only"); + color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG"); + if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG"); + comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG"); + filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG"); + interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG"); + if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG"); + if (!pal_img_n) { + s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); + if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); + if (scan == STBI__SCAN_header) return 1; + } else { + // if paletted, then pal_n is our final components, and + // img_n is # components to decompress/filter. + s->img_n = 1; + if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); + // if SCAN_header, have to scan to see if we have a tRNS + } + break; + } + + case STBI__PNG_TYPE('P','L','T','E'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG"); + pal_len = c.length / 3; + if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG"); + for (i=0; i < pal_len; ++i) { + palette[i*4+0] = stbi__get8(s); + palette[i*4+1] = stbi__get8(s); + palette[i*4+2] = stbi__get8(s); + palette[i*4+3] = 255; + } + break; + } + + case STBI__PNG_TYPE('t','R','N','S'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG"); + if (pal_img_n) { + if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; } + if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG"); + if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG"); + pal_img_n = 4; + for (i=0; i < c.length; ++i) + palette[i*4+3] = stbi__get8(s); + } else { + if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); + if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); + has_trans = 1; + if (z->depth == 16) { + for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + } else { + for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + } + } + break; + } + + case STBI__PNG_TYPE('I','D','A','T'): { + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); + if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if ((int)(ioff + c.length) < (int)ioff) return 0; + if (ioff + c.length > idata_limit) { + stbi__uint32 idata_limit_old = idata_limit; + stbi_uc *p; + if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096; + while (ioff + c.length > idata_limit) + idata_limit *= 2; + STBI_NOTUSED(idata_limit_old); + p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory"); + z->idata = p; + } + if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG"); + ioff += c.length; + break; + } + + case STBI__PNG_TYPE('I','E','N','D'): { + stbi__uint32 raw_len, bpl; + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if (scan != STBI__SCAN_load) return 1; + if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG"); + // initial guess for decoded data size to avoid unnecessary reallocs + bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component + raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */; + z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone); + if (z->expanded == NULL) return 0; // zlib should set error + STBI_FREE(z->idata); z->idata = NULL; + if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans) + s->img_out_n = s->img_n+1; + else + s->img_out_n = s->img_n; + if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0; + if (has_trans) { + if (z->depth == 16) { + if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0; + } else { + if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0; + } + } + if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2) + stbi__de_iphone(z); + if (pal_img_n) { + // pal_img_n == 3 or 4 + s->img_n = pal_img_n; // record the actual colors we had + s->img_out_n = pal_img_n; + if (req_comp >= 3) s->img_out_n = req_comp; + if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n)) + return 0; + } else if (has_trans) { + // non-paletted image with tRNS -> source image has (constant) alpha + ++s->img_n; + } + STBI_FREE(z->expanded); z->expanded = NULL; + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + return 1; + } + + default: + // if critical, fail + if (first) return stbi__err("first not IHDR", "Corrupt PNG"); + if ((c.type & (1 << 29)) == 0) { + #ifndef STBI_NO_FAILURE_STRINGS + // not threadsafe + static char invalid_chunk[] = "XXXX PNG chunk not known"; + invalid_chunk[0] = STBI__BYTECAST(c.type >> 24); + invalid_chunk[1] = STBI__BYTECAST(c.type >> 16); + invalid_chunk[2] = STBI__BYTECAST(c.type >> 8); + invalid_chunk[3] = STBI__BYTECAST(c.type >> 0); + #endif + return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type"); + } + stbi__skip(s, c.length); + break; + } + // end of PNG chunk, read and skip CRC + stbi__get32be(s); + } +} + +static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri) +{ + void *result=NULL; + if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error"); + if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) { + if (p->depth <= 8) + ri->bits_per_channel = 8; + else if (p->depth == 16) + ri->bits_per_channel = 16; + else + return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth"); + result = p->out; + p->out = NULL; + if (req_comp && req_comp != p->s->img_out_n) { + if (ri->bits_per_channel == 8) + result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + else + result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y); + p->s->img_out_n = req_comp; + if (result == NULL) return result; + } + *x = p->s->img_x; + *y = p->s->img_y; + if (n) *n = p->s->img_n; + } + STBI_FREE(p->out); p->out = NULL; + STBI_FREE(p->expanded); p->expanded = NULL; + STBI_FREE(p->idata); p->idata = NULL; + + return result; +} + +static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi__png p; + p.s = s; + return stbi__do_png(&p, x,y,comp,req_comp, ri); +} + +static int stbi__png_test(stbi__context *s) +{ + int r; + r = stbi__check_png_header(s); + stbi__rewind(s); + return r; +} + +static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp) +{ + if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) { + stbi__rewind( p->s ); + return 0; + } + if (x) *x = p->s->img_x; + if (y) *y = p->s->img_y; + if (comp) *comp = p->s->img_n; + return 1; +} + +static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__png p; + p.s = s; + return stbi__png_info_raw(&p, x, y, comp); +} + +static int stbi__png_is16(stbi__context *s) +{ + stbi__png p; + p.s = s; + if (!stbi__png_info_raw(&p, NULL, NULL, NULL)) + return 0; + if (p.depth != 16) { + stbi__rewind(p.s); + return 0; + } + return 1; +} +#endif + +// Microsoft/Windows BMP image + +#ifndef STBI_NO_BMP +static int stbi__bmp_test_raw(stbi__context *s) +{ + int r; + int sz; + if (stbi__get8(s) != 'B') return 0; + if (stbi__get8(s) != 'M') return 0; + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + stbi__get32le(s); // discard data offset + sz = stbi__get32le(s); + r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124); + return r; +} + +static int stbi__bmp_test(stbi__context *s) +{ + int r = stbi__bmp_test_raw(s); + stbi__rewind(s); + return r; +} + + +// returns 0..31 for the highest set bit +static int stbi__high_bit(unsigned int z) +{ + int n=0; + if (z == 0) return -1; + if (z >= 0x10000) { n += 16; z >>= 16; } + if (z >= 0x00100) { n += 8; z >>= 8; } + if (z >= 0x00010) { n += 4; z >>= 4; } + if (z >= 0x00004) { n += 2; z >>= 2; } + if (z >= 0x00002) { n += 1;/* >>= 1;*/ } + return n; +} + +static int stbi__bitcount(unsigned int a) +{ + a = (a & 0x55555555) + ((a >> 1) & 0x55555555); // max 2 + a = (a & 0x33333333) + ((a >> 2) & 0x33333333); // max 4 + a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits + a = (a + (a >> 8)); // max 16 per 8 bits + a = (a + (a >> 16)); // max 32 per 8 bits + return a & 0xff; +} + +// extract an arbitrarily-aligned N-bit value (N=bits) +// from v, and then make it 8-bits long and fractionally +// extend it to full full range. +static int stbi__shiftsigned(unsigned int v, int shift, int bits) +{ + static unsigned int mul_table[9] = { + 0, + 0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/, + 0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/, + }; + static unsigned int shift_table[9] = { + 0, 0,0,1,0,2,4,6,0, + }; + if (shift < 0) + v <<= -shift; + else + v >>= shift; + STBI_ASSERT(v < 256); + v >>= (8-bits); + STBI_ASSERT(bits >= 0 && bits <= 8); + return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits]; +} + +typedef struct +{ + int bpp, offset, hsz; + unsigned int mr,mg,mb,ma, all_a; + int extra_read; +} stbi__bmp_data; + +static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info) +{ + int hsz; + if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP"); + stbi__get32le(s); // discard filesize + stbi__get16le(s); // discard reserved + stbi__get16le(s); // discard reserved + info->offset = stbi__get32le(s); + info->hsz = hsz = stbi__get32le(s); + info->mr = info->mg = info->mb = info->ma = 0; + info->extra_read = 14; + + if (info->offset < 0) return stbi__errpuc("bad BMP", "bad BMP"); + + if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown"); + if (hsz == 12) { + s->img_x = stbi__get16le(s); + s->img_y = stbi__get16le(s); + } else { + s->img_x = stbi__get32le(s); + s->img_y = stbi__get32le(s); + } + if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP"); + info->bpp = stbi__get16le(s); + if (hsz != 12) { + int compress = stbi__get32le(s); + if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE"); + stbi__get32le(s); // discard sizeof + stbi__get32le(s); // discard hres + stbi__get32le(s); // discard vres + stbi__get32le(s); // discard colorsused + stbi__get32le(s); // discard max important + if (hsz == 40 || hsz == 56) { + if (hsz == 56) { + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + stbi__get32le(s); + } + if (info->bpp == 16 || info->bpp == 32) { + if (compress == 0) { + if (info->bpp == 32) { + info->mr = 0xffu << 16; + info->mg = 0xffu << 8; + info->mb = 0xffu << 0; + info->ma = 0xffu << 24; + info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0 + } else { + info->mr = 31u << 10; + info->mg = 31u << 5; + info->mb = 31u << 0; + } + } else if (compress == 3) { + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->extra_read += 12; + // not documented, but generated by photoshop and handled by mspaint + if (info->mr == info->mg && info->mg == info->mb) { + // ?!?!? + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else + return stbi__errpuc("bad BMP", "bad BMP"); + } + } else { + int i; + if (hsz != 108 && hsz != 124) + return stbi__errpuc("bad BMP", "bad BMP"); + info->mr = stbi__get32le(s); + info->mg = stbi__get32le(s); + info->mb = stbi__get32le(s); + info->ma = stbi__get32le(s); + stbi__get32le(s); // discard color space + for (i=0; i < 12; ++i) + stbi__get32le(s); // discard color space parameters + if (hsz == 124) { + stbi__get32le(s); // discard rendering intent + stbi__get32le(s); // discard offset of profile data + stbi__get32le(s); // discard size of profile data + stbi__get32le(s); // discard reserved + } + } + } + return (void *) 1; +} + + +static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + unsigned int mr=0,mg=0,mb=0,ma=0, all_a; + stbi_uc pal[256][4]; + int psize=0,i,j,width; + int flip_vertically, pad, target; + stbi__bmp_data info; + STBI_NOTUSED(ri); + + info.all_a = 255; + if (stbi__bmp_parse_header(s, &info) == NULL) + return NULL; // error code already set + + flip_vertically = ((int) s->img_y) > 0; + s->img_y = abs((int) s->img_y); + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + mr = info.mr; + mg = info.mg; + mb = info.mb; + ma = info.ma; + all_a = info.all_a; + + if (info.hsz == 12) { + if (info.bpp < 24) + psize = (info.offset - info.extra_read - 24) / 3; + } else { + if (info.bpp < 16) + psize = (info.offset - info.extra_read - info.hsz) >> 2; + } + if (psize == 0) { + STBI_ASSERT(info.offset == s->callback_already_read + (int) (s->img_buffer - s->img_buffer_original)); + if (info.offset != s->callback_already_read + (s->img_buffer - s->buffer_start)) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } + } + + if (info.bpp == 24 && ma == 0xff000000) + s->img_n = 3; + else + s->img_n = ma ? 4 : 3; + if (req_comp && req_comp >= 3) // we can directly decode 3 or 4 + target = req_comp; + else + target = s->img_n; // if they want monochrome, we'll post-convert + + // sanity-check size + if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "Corrupt BMP"); + + out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + if (info.bpp < 16) { + int z=0; + if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); } + for (i=0; i < psize; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + if (info.hsz != 12) stbi__get8(s); + pal[i][3] = 255; + } + stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4)); + if (info.bpp == 1) width = (s->img_x + 7) >> 3; + else if (info.bpp == 4) width = (s->img_x + 1) >> 1; + else if (info.bpp == 8) width = s->img_x; + else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); } + pad = (-width)&3; + if (info.bpp == 1) { + for (j=0; j < (int) s->img_y; ++j) { + int bit_offset = 7, v = stbi__get8(s); + for (i=0; i < (int) s->img_x; ++i) { + int color = (v>>bit_offset)&0x1; + out[z++] = pal[color][0]; + out[z++] = pal[color][1]; + out[z++] = pal[color][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + if((--bit_offset) < 0) { + bit_offset = 7; + v = stbi__get8(s); + } + } + stbi__skip(s, pad); + } + } else { + for (j=0; j < (int) s->img_y; ++j) { + for (i=0; i < (int) s->img_x; i += 2) { + int v=stbi__get8(s),v2=0; + if (info.bpp == 4) { + v2 = v & 15; + v >>= 4; + } + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + if (i+1 == (int) s->img_x) break; + v = (info.bpp == 8) ? stbi__get8(s) : v2; + out[z++] = pal[v][0]; + out[z++] = pal[v][1]; + out[z++] = pal[v][2]; + if (target == 4) out[z++] = 255; + } + stbi__skip(s, pad); + } + } + } else { + int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0; + int z = 0; + int easy=0; + stbi__skip(s, info.offset - info.extra_read - info.hsz); + if (info.bpp == 24) width = 3 * s->img_x; + else if (info.bpp == 16) width = 2*s->img_x; + else /* bpp = 32 and pad = 0 */ width=0; + pad = (-width) & 3; + if (info.bpp == 24) { + easy = 1; + } else if (info.bpp == 32) { + if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000) + easy = 2; + } + if (!easy) { + if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + // right shift amt to put high bit in position #7 + rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr); + gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg); + bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb); + ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma); + if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); } + } + for (j=0; j < (int) s->img_y; ++j) { + if (easy) { + for (i=0; i < (int) s->img_x; ++i) { + unsigned char a; + out[z+2] = stbi__get8(s); + out[z+1] = stbi__get8(s); + out[z+0] = stbi__get8(s); + z += 3; + a = (easy == 2 ? stbi__get8(s) : 255); + all_a |= a; + if (target == 4) out[z++] = a; + } + } else { + int bpp = info.bpp; + for (i=0; i < (int) s->img_x; ++i) { + stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s)); + unsigned int a; + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount)); + out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount)); + a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255); + all_a |= a; + if (target == 4) out[z++] = STBI__BYTECAST(a); + } + } + stbi__skip(s, pad); + } + } + + // if alpha channel is all 0s, replace with all 255s + if (target == 4 && all_a == 0) + for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4) + out[i] = 255; + + if (flip_vertically) { + stbi_uc t; + for (j=0; j < (int) s->img_y>>1; ++j) { + stbi_uc *p1 = out + j *s->img_x*target; + stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target; + for (i=0; i < (int) s->img_x*target; ++i) { + t = p1[i]; p1[i] = p2[i]; p2[i] = t; + } + } + } + + if (req_comp && req_comp != target) { + out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + return out; +} +#endif + +// Targa Truevision - TGA +// by Jonathan Dummer +#ifndef STBI_NO_TGA +// returns STBI_rgb or whatever, 0 on error +static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16) +{ + // only RGB or RGBA (incl. 16bit) or grey allowed + if (is_rgb16) *is_rgb16 = 0; + switch(bits_per_pixel) { + case 8: return STBI_grey; + case 16: if(is_grey) return STBI_grey_alpha; + // fallthrough + case 15: if(is_rgb16) *is_rgb16 = 1; + return STBI_rgb; + case 24: // fallthrough + case 32: return bits_per_pixel/8; + default: return 0; + } +} + +static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp) +{ + int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp; + int sz, tga_colormap_type; + stbi__get8(s); // discard Offset + tga_colormap_type = stbi__get8(s); // colormap type + if( tga_colormap_type > 1 ) { + stbi__rewind(s); + return 0; // only RGB or indexed allowed + } + tga_image_type = stbi__get8(s); // image type + if ( tga_colormap_type == 1 ) { // colormapped (paletted) image + if (tga_image_type != 1 && tga_image_type != 9) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) { + stbi__rewind(s); + return 0; + } + stbi__skip(s,4); // skip image x and y origin + tga_colormap_bpp = sz; + } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE + if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) { + stbi__rewind(s); + return 0; // only RGB or grey allowed, +/- RLE + } + stbi__skip(s,9); // skip colormap specification and image x/y origin + tga_colormap_bpp = 0; + } + tga_w = stbi__get16le(s); + if( tga_w < 1 ) { + stbi__rewind(s); + return 0; // test width + } + tga_h = stbi__get16le(s); + if( tga_h < 1 ) { + stbi__rewind(s); + return 0; // test height + } + tga_bits_per_pixel = stbi__get8(s); // bits per pixel + stbi__get8(s); // ignore alpha bits + if (tga_colormap_bpp != 0) { + if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) { + // when using a colormap, tga_bits_per_pixel is the size of the indexes + // I don't think anything but 8 or 16bit indexes makes sense + stbi__rewind(s); + return 0; + } + tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL); + } else { + tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL); + } + if(!tga_comp) { + stbi__rewind(s); + return 0; + } + if (x) *x = tga_w; + if (y) *y = tga_h; + if (comp) *comp = tga_comp; + return 1; // seems to have passed everything +} + +static int stbi__tga_test(stbi__context *s) +{ + int res = 0; + int sz, tga_color_type; + stbi__get8(s); // discard Offset + tga_color_type = stbi__get8(s); // color type + if ( tga_color_type > 1 ) goto errorEnd; // only RGB or indexed allowed + sz = stbi__get8(s); // image type + if ( tga_color_type == 1 ) { // colormapped (paletted) image + if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9 + stbi__skip(s,4); // skip index of first colormap entry and number of entries + sz = stbi__get8(s); // check bits per palette color entry + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + stbi__skip(s,4); // skip image x and y origin + } else { // "normal" image w/o colormap + if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE + stbi__skip(s,9); // skip colormap specification and image x/y origin + } + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test width + if ( stbi__get16le(s) < 1 ) goto errorEnd; // test height + sz = stbi__get8(s); // bits per pixel + if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index + if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd; + + res = 1; // if we got this far, everything's good and we can return 1 instead of 0 + +errorEnd: + stbi__rewind(s); + return res; +} + +// read 16bit value and convert to 24bit RGB +static void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out) +{ + stbi__uint16 px = (stbi__uint16)stbi__get16le(s); + stbi__uint16 fiveBitMask = 31; + // we have 3 channels with 5bits each + int r = (px >> 10) & fiveBitMask; + int g = (px >> 5) & fiveBitMask; + int b = px & fiveBitMask; + // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later + out[0] = (stbi_uc)((r * 255)/31); + out[1] = (stbi_uc)((g * 255)/31); + out[2] = (stbi_uc)((b * 255)/31); + + // some people claim that the most significant bit might be used for alpha + // (possibly if an alpha-bit is set in the "image descriptor byte") + // but that only made 16bit test images completely translucent.. + // so let's treat all 15 and 16bit TGAs as RGB with no alpha. +} + +static void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + // read in the TGA header stuff + int tga_offset = stbi__get8(s); + int tga_indexed = stbi__get8(s); + int tga_image_type = stbi__get8(s); + int tga_is_RLE = 0; + int tga_palette_start = stbi__get16le(s); + int tga_palette_len = stbi__get16le(s); + int tga_palette_bits = stbi__get8(s); + int tga_x_origin = stbi__get16le(s); + int tga_y_origin = stbi__get16le(s); + int tga_width = stbi__get16le(s); + int tga_height = stbi__get16le(s); + int tga_bits_per_pixel = stbi__get8(s); + int tga_comp, tga_rgb16=0; + int tga_inverted = stbi__get8(s); + // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?) + // image data + unsigned char *tga_data; + unsigned char *tga_palette = NULL; + int i, j; + unsigned char raw_data[4] = {0}; + int RLE_count = 0; + int RLE_repeating = 0; + int read_next_pixel = 1; + STBI_NOTUSED(ri); + STBI_NOTUSED(tga_x_origin); // @TODO + STBI_NOTUSED(tga_y_origin); // @TODO + + if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // do a tiny bit of precessing + if ( tga_image_type >= 8 ) + { + tga_image_type -= 8; + tga_is_RLE = 1; + } + tga_inverted = 1 - ((tga_inverted >> 5) & 1); + + // If I'm paletted, then I'll use the number of bits from the palette + if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16); + else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16); + + if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency + return stbi__errpuc("bad format", "Can't find out TGA pixelformat"); + + // tga info + *x = tga_width; + *y = tga_height; + if (comp) *comp = tga_comp; + + if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0)) + return stbi__errpuc("too large", "Corrupt TGA"); + + tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0); + if (!tga_data) return stbi__errpuc("outofmem", "Out of memory"); + + // skip to the data's starting position (offset usually = 0) + stbi__skip(s, tga_offset ); + + if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) { + for (i=0; i < tga_height; ++i) { + int row = tga_inverted ? tga_height -i - 1 : i; + stbi_uc *tga_row = tga_data + row*tga_width*tga_comp; + stbi__getn(s, tga_row, tga_width * tga_comp); + } + } else { + // do I need to load a palette? + if ( tga_indexed) + { + if (tga_palette_len == 0) { /* you have to have at least one entry! */ + STBI_FREE(tga_data); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + + // any data to skip? (offset usually = 0) + stbi__skip(s, tga_palette_start ); + // load the palette + tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0); + if (!tga_palette) { + STBI_FREE(tga_data); + return stbi__errpuc("outofmem", "Out of memory"); + } + if (tga_rgb16) { + stbi_uc *pal_entry = tga_palette; + STBI_ASSERT(tga_comp == STBI_rgb); + for (i=0; i < tga_palette_len; ++i) { + stbi__tga_read_rgb16(s, pal_entry); + pal_entry += tga_comp; + } + } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) { + STBI_FREE(tga_data); + STBI_FREE(tga_palette); + return stbi__errpuc("bad palette", "Corrupt TGA"); + } + } + // load the data + for (i=0; i < tga_width * tga_height; ++i) + { + // if I'm in RLE mode, do I need to get a RLE stbi__pngchunk? + if ( tga_is_RLE ) + { + if ( RLE_count == 0 ) + { + // yep, get the next byte as a RLE command + int RLE_cmd = stbi__get8(s); + RLE_count = 1 + (RLE_cmd & 127); + RLE_repeating = RLE_cmd >> 7; + read_next_pixel = 1; + } else if ( !RLE_repeating ) + { + read_next_pixel = 1; + } + } else + { + read_next_pixel = 1; + } + // OK, if I need to read a pixel, do it now + if ( read_next_pixel ) + { + // load however much data we did have + if ( tga_indexed ) + { + // read in index, then perform the lookup + int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s); + if ( pal_idx >= tga_palette_len ) { + // invalid index + pal_idx = 0; + } + pal_idx *= tga_comp; + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = tga_palette[pal_idx+j]; + } + } else if(tga_rgb16) { + STBI_ASSERT(tga_comp == STBI_rgb); + stbi__tga_read_rgb16(s, raw_data); + } else { + // read in the data raw + for (j = 0; j < tga_comp; ++j) { + raw_data[j] = stbi__get8(s); + } + } + // clear the reading flag for the next pixel + read_next_pixel = 0; + } // end of reading a pixel + + // copy data + for (j = 0; j < tga_comp; ++j) + tga_data[i*tga_comp+j] = raw_data[j]; + + // in case we're in RLE mode, keep counting down + --RLE_count; + } + // do I need to invert the image? + if ( tga_inverted ) + { + for (j = 0; j*2 < tga_height; ++j) + { + int index1 = j * tga_width * tga_comp; + int index2 = (tga_height - 1 - j) * tga_width * tga_comp; + for (i = tga_width * tga_comp; i > 0; --i) + { + unsigned char temp = tga_data[index1]; + tga_data[index1] = tga_data[index2]; + tga_data[index2] = temp; + ++index1; + ++index2; + } + } + } + // clear my palette, if I had one + if ( tga_palette != NULL ) + { + STBI_FREE( tga_palette ); + } + } + + // swap RGB - if the source data was RGB16, it already is in the right order + if (tga_comp >= 3 && !tga_rgb16) + { + unsigned char* tga_pixel = tga_data; + for (i=0; i < tga_width * tga_height; ++i) + { + unsigned char temp = tga_pixel[0]; + tga_pixel[0] = tga_pixel[2]; + tga_pixel[2] = temp; + tga_pixel += tga_comp; + } + } + + // convert to target component count + if (req_comp && req_comp != tga_comp) + tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height); + + // the things I do to get rid of an error message, and yet keep + // Microsoft's C compilers happy... [8^( + tga_palette_start = tga_palette_len = tga_palette_bits = + tga_x_origin = tga_y_origin = 0; + STBI_NOTUSED(tga_palette_start); + // OK, done + return tga_data; +} +#endif + +// ************************************************************************************************* +// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB + +#ifndef STBI_NO_PSD +static int stbi__psd_test(stbi__context *s) +{ + int r = (stbi__get32be(s) == 0x38425053); + stbi__rewind(s); + return r; +} + +static int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount) +{ + int count, nleft, len; + + count = 0; + while ((nleft = pixelCount - count) > 0) { + len = stbi__get8(s); + if (len == 128) { + // No-op. + } else if (len < 128) { + // Copy next len+1 bytes literally. + len++; + if (len > nleft) return 0; // corrupt data + count += len; + while (len) { + *p = stbi__get8(s); + p += 4; + len--; + } + } else if (len > 128) { + stbi_uc val; + // Next -len+1 bytes in the dest are replicated from next source byte. + // (Interpret len as a negative 8-bit int.) + len = 257 - len; + if (len > nleft) return 0; // corrupt data + val = stbi__get8(s); + count += len; + while (len) { + *p = val; + p += 4; + len--; + } + } + } + + return 1; +} + +static void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc) +{ + int pixelCount; + int channelCount, compression; + int channel, i; + int bitdepth; + int w,h; + stbi_uc *out; + STBI_NOTUSED(ri); + + // Check identifier + if (stbi__get32be(s) != 0x38425053) // "8BPS" + return stbi__errpuc("not PSD", "Corrupt PSD image"); + + // Check file type version. + if (stbi__get16be(s) != 1) + return stbi__errpuc("wrong version", "Unsupported version of PSD image"); + + // Skip 6 reserved bytes. + stbi__skip(s, 6 ); + + // Read the number of channels (R, G, B, A, etc). + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) + return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image"); + + // Read the rows and columns of the image. + h = stbi__get32be(s); + w = stbi__get32be(s); + + if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + // Make sure the depth is 8 bits. + bitdepth = stbi__get16be(s); + if (bitdepth != 8 && bitdepth != 16) + return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit"); + + // Make sure the color mode is RGB. + // Valid options are: + // 0: Bitmap + // 1: Grayscale + // 2: Indexed color + // 3: RGB color + // 4: CMYK color + // 7: Multichannel + // 8: Duotone + // 9: Lab color + if (stbi__get16be(s) != 3) + return stbi__errpuc("wrong color format", "PSD is not in RGB color format"); + + // Skip the Mode Data. (It's the palette for indexed color; other info for other modes.) + stbi__skip(s,stbi__get32be(s) ); + + // Skip the image resources. (resolution, pen tool paths, etc) + stbi__skip(s, stbi__get32be(s) ); + + // Skip the reserved data. + stbi__skip(s, stbi__get32be(s) ); + + // Find out if the data is compressed. + // Known values: + // 0: no compression + // 1: RLE compressed + compression = stbi__get16be(s); + if (compression > 1) + return stbi__errpuc("bad compression", "PSD has an unknown compression format"); + + // Check size + if (!stbi__mad3sizes_valid(4, w, h, 0)) + return stbi__errpuc("too large", "Corrupt PSD"); + + // Create the destination image. + + if (!compression && bitdepth == 16 && bpc == 16) { + out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0); + ri->bits_per_channel = 16; + } else + out = (stbi_uc *) stbi__malloc(4 * w*h); + + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + pixelCount = w*h; + + // Initialize the data to zero. + //memset( out, 0, pixelCount * 4 ); + + // Finally, the image data. + if (compression) { + // RLE as used by .PSD and .TIFF + // Loop until you get the number of unpacked bytes you are expecting: + // Read the next source byte into n. + // If n is between 0 and 127 inclusive, copy the next n+1 bytes literally. + // Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times. + // Else if n is 128, noop. + // Endloop + + // The RLE-compressed data is preceded by a 2-byte data count for each row in the data, + // which we're going to just skip. + stbi__skip(s, h * channelCount * 2 ); + + // Read the RLE data by channel. + for (channel = 0; channel < 4; channel++) { + stbi_uc *p; + + p = out+channel; + if (channel >= channelCount) { + // Fill this channel with default data. + for (i = 0; i < pixelCount; i++, p += 4) + *p = (channel == 3 ? 255 : 0); + } else { + // Read the RLE data. + if (!stbi__psd_decode_rle(s, p, pixelCount)) { + STBI_FREE(out); + return stbi__errpuc("corrupt", "bad RLE data"); + } + } + } + + } else { + // We're at the raw image data. It's each channel in order (Red, Green, Blue, Alpha, ...) + // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image. + + // Read the data by channel. + for (channel = 0; channel < 4; channel++) { + if (channel >= channelCount) { + // Fill this channel with default data. + if (bitdepth == 16 && bpc == 16) { + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + stbi__uint16 val = channel == 3 ? 65535 : 0; + for (i = 0; i < pixelCount; i++, q += 4) + *q = val; + } else { + stbi_uc *p = out+channel; + stbi_uc val = channel == 3 ? 255 : 0; + for (i = 0; i < pixelCount; i++, p += 4) + *p = val; + } + } else { + if (ri->bits_per_channel == 16) { // output bpc + stbi__uint16 *q = ((stbi__uint16 *) out) + channel; + for (i = 0; i < pixelCount; i++, q += 4) + *q = (stbi__uint16) stbi__get16be(s); + } else { + stbi_uc *p = out+channel; + if (bitdepth == 16) { // input bpc + for (i = 0; i < pixelCount; i++, p += 4) + *p = (stbi_uc) (stbi__get16be(s) >> 8); + } else { + for (i = 0; i < pixelCount; i++, p += 4) + *p = stbi__get8(s); + } + } + } + } + } + + // remove weird white matte from PSD + if (channelCount >= 4) { + if (ri->bits_per_channel == 16) { + for (i=0; i < w*h; ++i) { + stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i; + if (pixel[3] != 0 && pixel[3] != 65535) { + float a = pixel[3] / 65535.0f; + float ra = 1.0f / a; + float inv_a = 65535.0f * (1 - ra); + pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a); + pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a); + pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a); + } + } + } else { + for (i=0; i < w*h; ++i) { + unsigned char *pixel = out + 4*i; + if (pixel[3] != 0 && pixel[3] != 255) { + float a = pixel[3] / 255.0f; + float ra = 1.0f / a; + float inv_a = 255.0f * (1 - ra); + pixel[0] = (unsigned char) (pixel[0]*ra + inv_a); + pixel[1] = (unsigned char) (pixel[1]*ra + inv_a); + pixel[2] = (unsigned char) (pixel[2]*ra + inv_a); + } + } + } + } + + // convert to desired output format + if (req_comp && req_comp != 4) { + if (ri->bits_per_channel == 16) + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h); + else + out = stbi__convert_format(out, 4, req_comp, w, h); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + + if (comp) *comp = 4; + *y = h; + *x = w; + + return out; +} +#endif + +// ************************************************************************************************* +// Softimage PIC loader +// by Tom Seddon +// +// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format +// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/ + +#ifndef STBI_NO_PIC +static int stbi__pic_is4(stbi__context *s,const char *str) +{ + int i; + for (i=0; i<4; ++i) + if (stbi__get8(s) != (stbi_uc)str[i]) + return 0; + + return 1; +} + +static int stbi__pic_test_core(stbi__context *s) +{ + int i; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) + return 0; + + for(i=0;i<84;++i) + stbi__get8(s); + + if (!stbi__pic_is4(s,"PICT")) + return 0; + + return 1; +} + +typedef struct +{ + stbi_uc size,type,channel; +} stbi__pic_packet; + +static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest) +{ + int mask=0x80, i; + + for (i=0; i<4; ++i, mask>>=1) { + if (channel & mask) { + if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short"); + dest[i]=stbi__get8(s); + } + } + + return dest; +} + +static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src) +{ + int mask=0x80,i; + + for (i=0;i<4; ++i, mask>>=1) + if (channel&mask) + dest[i]=src[i]; +} + +static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result) +{ + int act_comp=0,num_packets=0,y,chained; + stbi__pic_packet packets[10]; + + // this will (should...) cater for even some bizarre stuff like having data + // for the same channel in multiple packets. + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return stbi__errpuc("bad format","too many packets"); + + packet = &packets[num_packets++]; + + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + + act_comp |= packet->channel; + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (reading packets)"); + if (packet->size != 8) return stbi__errpuc("bad format","packet isn't 8bpp"); + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel? + + for(y=0; y<height; ++y) { + int packet_idx; + + for(packet_idx=0; packet_idx < num_packets; ++packet_idx) { + stbi__pic_packet *packet = &packets[packet_idx]; + stbi_uc *dest = result+y*width*4; + + switch (packet->type) { + default: + return stbi__errpuc("bad format","packet has bad compression type"); + + case 0: {//uncompressed + int x; + + for(x=0;x<width;++x, dest+=4) + if (!stbi__readval(s,packet->channel,dest)) + return 0; + break; + } + + case 1://Pure RLE + { + int left=width, i; + + while (left>0) { + stbi_uc count,value[4]; + + count=stbi__get8(s); + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pure read count)"); + + if (count > left) + count = (stbi_uc) left; + + if (!stbi__readval(s,packet->channel,value)) return 0; + + for(i=0; i<count; ++i,dest+=4) + stbi__copyval(packet->channel,dest,value); + left -= count; + } + } + break; + + case 2: {//Mixed RLE + int left=width; + while (left>0) { + int count = stbi__get8(s), i; + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (mixed read count)"); + + if (count >= 128) { // Repeated + stbi_uc value[4]; + + if (count==128) + count = stbi__get16be(s); + else + count -= 127; + if (count > left) + return stbi__errpuc("bad file","scanline overrun"); + + if (!stbi__readval(s,packet->channel,value)) + return 0; + + for(i=0;i<count;++i, dest += 4) + stbi__copyval(packet->channel,dest,value); + } else { // Raw + ++count; + if (count>left) return stbi__errpuc("bad file","scanline overrun"); + + for(i=0;i<count;++i, dest+=4) + if (!stbi__readval(s,packet->channel,dest)) + return 0; + } + left-=count; + } + break; + } + } + } + } + + return result; +} + +static void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri) +{ + stbi_uc *result; + int i, x,y, internal_comp; + STBI_NOTUSED(ri); + + if (!comp) comp = &internal_comp; + + for (i=0; i<92; ++i) + stbi__get8(s); + + x = stbi__get16be(s); + y = stbi__get16be(s); + + if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + if (stbi__at_eof(s)) return stbi__errpuc("bad file","file too short (pic header)"); + if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc("too large", "PIC image too large to decode"); + + stbi__get32be(s); //skip `ratio' + stbi__get16be(s); //skip `fields' + stbi__get16be(s); //skip `pad' + + // intermediate buffer is RGBA + result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0); + memset(result, 0xff, x*y*4); + + if (!stbi__pic_load_core(s,x,y,comp, result)) { + STBI_FREE(result); + result=0; + } + *px = x; + *py = y; + if (req_comp == 0) req_comp = *comp; + result=stbi__convert_format(result,4,req_comp,x,y); + + return result; +} + +static int stbi__pic_test(stbi__context *s) +{ + int r = stbi__pic_test_core(s); + stbi__rewind(s); + return r; +} +#endif + +// ************************************************************************************************* +// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb + +#ifndef STBI_NO_GIF +typedef struct +{ + stbi__int16 prefix; + stbi_uc first; + stbi_uc suffix; +} stbi__gif_lzw; + +typedef struct +{ + int w,h; + stbi_uc *out; // output buffer (always 4 components) + stbi_uc *background; // The current "background" as far as a gif is concerned + stbi_uc *history; + int flags, bgindex, ratio, transparent, eflags; + stbi_uc pal[256][4]; + stbi_uc lpal[256][4]; + stbi__gif_lzw codes[8192]; + stbi_uc *color_table; + int parse, step; + int lflags; + int start_x, start_y; + int max_x, max_y; + int cur_x, cur_y; + int line_size; + int delay; +} stbi__gif; + +static int stbi__gif_test_raw(stbi__context *s) +{ + int sz; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0; + sz = stbi__get8(s); + if (sz != '9' && sz != '7') return 0; + if (stbi__get8(s) != 'a') return 0; + return 1; +} + +static int stbi__gif_test(stbi__context *s) +{ + int r = stbi__gif_test_raw(s); + stbi__rewind(s); + return r; +} + +static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp) +{ + int i; + for (i=0; i < num_entries; ++i) { + pal[i][2] = stbi__get8(s); + pal[i][1] = stbi__get8(s); + pal[i][0] = stbi__get8(s); + pal[i][3] = transp == i ? 0 : 255; + } +} + +static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info) +{ + stbi_uc version; + if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') + return stbi__err("not GIF", "Corrupt GIF"); + + version = stbi__get8(s); + if (version != '7' && version != '9') return stbi__err("not GIF", "Corrupt GIF"); + if (stbi__get8(s) != 'a') return stbi__err("not GIF", "Corrupt GIF"); + + stbi__g_failure_reason = ""; + g->w = stbi__get16le(s); + g->h = stbi__get16le(s); + g->flags = stbi__get8(s); + g->bgindex = stbi__get8(s); + g->ratio = stbi__get8(s); + g->transparent = -1; + + if (g->w > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + if (g->h > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)"); + + if (comp != 0) *comp = 4; // can't actually tell whether it's 3 or 4 until we parse the comments + + if (is_info) return 1; + + if (g->flags & 0x80) + stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1); + + return 1; +} + +static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp) +{ + stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif)); + if (!stbi__gif_header(s, g, comp, 1)) { + STBI_FREE(g); + stbi__rewind( s ); + return 0; + } + if (x) *x = g->w; + if (y) *y = g->h; + STBI_FREE(g); + return 1; +} + +static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code) +{ + stbi_uc *p, *c; + int idx; + + // recurse to decode the prefixes, since the linked-list is backwards, + // and working backwards through an interleaved image would be nasty + if (g->codes[code].prefix >= 0) + stbi__out_gif_code(g, g->codes[code].prefix); + + if (g->cur_y >= g->max_y) return; + + idx = g->cur_x + g->cur_y; + p = &g->out[idx]; + g->history[idx / 4] = 1; + + c = &g->color_table[g->codes[code].suffix * 4]; + if (c[3] > 128) { // don't render transparent pixels; + p[0] = c[2]; + p[1] = c[1]; + p[2] = c[0]; + p[3] = c[3]; + } + g->cur_x += 4; + + if (g->cur_x >= g->max_x) { + g->cur_x = g->start_x; + g->cur_y += g->step; + + while (g->cur_y >= g->max_y && g->parse > 0) { + g->step = (1 << g->parse) * g->line_size; + g->cur_y = g->start_y + (g->step >> 1); + --g->parse; + } + } +} + +static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g) +{ + stbi_uc lzw_cs; + stbi__int32 len, init_code; + stbi__uint32 first; + stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear; + stbi__gif_lzw *p; + + lzw_cs = stbi__get8(s); + if (lzw_cs > 12) return NULL; + clear = 1 << lzw_cs; + first = 1; + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + bits = 0; + valid_bits = 0; + for (init_code = 0; init_code < clear; init_code++) { + g->codes[init_code].prefix = -1; + g->codes[init_code].first = (stbi_uc) init_code; + g->codes[init_code].suffix = (stbi_uc) init_code; + } + + // support no starting clear code + avail = clear+2; + oldcode = -1; + + len = 0; + for(;;) { + if (valid_bits < codesize) { + if (len == 0) { + len = stbi__get8(s); // start new block + if (len == 0) + return g->out; + } + --len; + bits |= (stbi__int32) stbi__get8(s) << valid_bits; + valid_bits += 8; + } else { + stbi__int32 code = bits & codemask; + bits >>= codesize; + valid_bits -= codesize; + // @OPTIMIZE: is there some way we can accelerate the non-clear path? + if (code == clear) { // clear code + codesize = lzw_cs + 1; + codemask = (1 << codesize) - 1; + avail = clear + 2; + oldcode = -1; + first = 0; + } else if (code == clear + 1) { // end of stream code + stbi__skip(s, len); + while ((len = stbi__get8(s)) > 0) + stbi__skip(s,len); + return g->out; + } else if (code <= avail) { + if (first) { + return stbi__errpuc("no clear code", "Corrupt GIF"); + } + + if (oldcode >= 0) { + p = &g->codes[avail++]; + if (avail > 8192) { + return stbi__errpuc("too many codes", "Corrupt GIF"); + } + + p->prefix = (stbi__int16) oldcode; + p->first = g->codes[oldcode].first; + p->suffix = (code == avail) ? p->first : g->codes[code].first; + } else if (code == avail) + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + + stbi__out_gif_code(g, (stbi__uint16) code); + + if ((avail & codemask) == 0 && avail <= 0x0FFF) { + codesize++; + codemask = (1 << codesize) - 1; + } + + oldcode = code; + } else { + return stbi__errpuc("illegal code in raster", "Corrupt GIF"); + } + } + } +} + +// this function is designed to support animated gifs, although stb_image doesn't support it +// two back is the image from two frames ago, used for a very specific disposal format +static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back) +{ + int dispose; + int first_frame; + int pi; + int pcount; + STBI_NOTUSED(req_comp); + + // on first frame, any non-written pixels get the background colour (non-transparent) + first_frame = 0; + if (g->out == 0) { + if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header + if (!stbi__mad3sizes_valid(4, g->w, g->h, 0)) + return stbi__errpuc("too large", "GIF image is too large"); + pcount = g->w * g->h; + g->out = (stbi_uc *) stbi__malloc(4 * pcount); + g->background = (stbi_uc *) stbi__malloc(4 * pcount); + g->history = (stbi_uc *) stbi__malloc(pcount); + if (!g->out || !g->background || !g->history) + return stbi__errpuc("outofmem", "Out of memory"); + + // image is treated as "transparent" at the start - ie, nothing overwrites the current background; + // background colour is only used for pixels that are not rendered first frame, after that "background" + // color refers to the color that was there the previous frame. + memset(g->out, 0x00, 4 * pcount); + memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent) + memset(g->history, 0x00, pcount); // pixels that were affected previous frame + first_frame = 1; + } else { + // second frame - how do we dispose of the previous one? + dispose = (g->eflags & 0x1C) >> 2; + pcount = g->w * g->h; + + if ((dispose == 3) && (two_back == 0)) { + dispose = 2; // if I don't have an image to revert back to, default to the old background + } + + if (dispose == 3) { // use previous graphic + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 ); + } + } + } else if (dispose == 2) { + // restore what was changed last frame to background before that frame; + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi]) { + memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 ); + } + } + } else { + // This is a non-disposal case eithe way, so just + // leave the pixels as is, and they will become the new background + // 1: do not dispose + // 0: not specified. + } + + // background is what out is after the undoing of the previou frame; + memcpy( g->background, g->out, 4 * g->w * g->h ); + } + + // clear my history; + memset( g->history, 0x00, g->w * g->h ); // pixels that were affected previous frame + + for (;;) { + int tag = stbi__get8(s); + switch (tag) { + case 0x2C: /* Image Descriptor */ + { + stbi__int32 x, y, w, h; + stbi_uc *o; + + x = stbi__get16le(s); + y = stbi__get16le(s); + w = stbi__get16le(s); + h = stbi__get16le(s); + if (((x + w) > (g->w)) || ((y + h) > (g->h))) + return stbi__errpuc("bad Image Descriptor", "Corrupt GIF"); + + g->line_size = g->w * 4; + g->start_x = x * 4; + g->start_y = y * g->line_size; + g->max_x = g->start_x + w * 4; + g->max_y = g->start_y + h * g->line_size; + g->cur_x = g->start_x; + g->cur_y = g->start_y; + + // if the width of the specified rectangle is 0, that means + // we may not see *any* pixels or the image is malformed; + // to make sure this is caught, move the current y down to + // max_y (which is what out_gif_code checks). + if (w == 0) + g->cur_y = g->max_y; + + g->lflags = stbi__get8(s); + + if (g->lflags & 0x40) { + g->step = 8 * g->line_size; // first interlaced spacing + g->parse = 3; + } else { + g->step = g->line_size; + g->parse = 0; + } + + if (g->lflags & 0x80) { + stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1); + g->color_table = (stbi_uc *) g->lpal; + } else if (g->flags & 0x80) { + g->color_table = (stbi_uc *) g->pal; + } else + return stbi__errpuc("missing color table", "Corrupt GIF"); + + o = stbi__process_gif_raster(s, g); + if (!o) return NULL; + + // if this was the first frame, + pcount = g->w * g->h; + if (first_frame && (g->bgindex > 0)) { + // if first frame, any pixel not drawn to gets the background color + for (pi = 0; pi < pcount; ++pi) { + if (g->history[pi] == 0) { + g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be; + memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 ); + } + } + } + + return o; + } + + case 0x21: // Comment Extension. + { + int len; + int ext = stbi__get8(s); + if (ext == 0xF9) { // Graphic Control Extension. + len = stbi__get8(s); + if (len == 4) { + g->eflags = stbi__get8(s); + g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths. + + // unset old transparent + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 255; + } + if (g->eflags & 0x01) { + g->transparent = stbi__get8(s); + if (g->transparent >= 0) { + g->pal[g->transparent][3] = 0; + } + } else { + // don't need transparent + stbi__skip(s, 1); + g->transparent = -1; + } + } else { + stbi__skip(s, len); + break; + } + } + while ((len = stbi__get8(s)) != 0) { + stbi__skip(s, len); + } + break; + } + + case 0x3B: // gif stream termination code + return (stbi_uc *) s; // using '1' causes warning on some compilers + + default: + return stbi__errpuc("unknown code", "Corrupt GIF"); + } + } +} + +static void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp) +{ + if (stbi__gif_test(s)) { + int layers = 0; + stbi_uc *u = 0; + stbi_uc *out = 0; + stbi_uc *two_back = 0; + stbi__gif g; + int stride; + memset(&g, 0, sizeof(g)); + if (delays) { + *delays = 0; + } + + do { + u = stbi__gif_load_next(s, &g, comp, req_comp, two_back); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + + if (u) { + *x = g.w; + *y = g.h; + ++layers; + stride = g.w * g.h * 4; + + if (out) { + void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, 0, layers * stride ); + if (NULL == tmp) { + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + return stbi__errpuc("outofmem", "Out of memory"); + } + else { + out = (stbi_uc*) tmp; + } + + if (delays) { + *delays = (int*) STBI_REALLOC_SIZED( *delays, 0, sizeof(int) * layers ); + } + } else { + out = (stbi_uc*)stbi__malloc( layers * stride ); + if (delays) { + *delays = (int*) stbi__malloc( layers * sizeof(int) ); + } + } + memcpy( out + ((layers - 1) * stride), u, stride ); + if (layers >= 2) { + two_back = out - 2 * stride; + } + + if (delays) { + (*delays)[layers - 1U] = g.delay; + } + } + } while (u != 0); + + // free temp buffer; + STBI_FREE(g.out); + STBI_FREE(g.history); + STBI_FREE(g.background); + + // do the final conversion after loading everything; + if (req_comp && req_comp != 4) + out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h); + + *z = layers; + return out; + } else { + return stbi__errpuc("not GIF", "Image was not as a gif type."); + } +} + +static void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *u = 0; + stbi__gif g; + memset(&g, 0, sizeof(g)); + STBI_NOTUSED(ri); + + u = stbi__gif_load_next(s, &g, comp, req_comp, 0); + if (u == (stbi_uc *) s) u = 0; // end of animated gif marker + if (u) { + *x = g.w; + *y = g.h; + + // moved conversion to after successful load so that the same + // can be done for multiple frames. + if (req_comp && req_comp != 4) + u = stbi__convert_format(u, 4, req_comp, g.w, g.h); + } else if (g.out) { + // if there was an error and we allocated an image buffer, free it! + STBI_FREE(g.out); + } + + // free buffers needed for multiple frame loading; + STBI_FREE(g.history); + STBI_FREE(g.background); + + return u; +} + +static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp) +{ + return stbi__gif_info_raw(s,x,y,comp); +} +#endif + +// ************************************************************************************************* +// Radiance RGBE HDR loader +// originally by Nicolas Schulz +#ifndef STBI_NO_HDR +static int stbi__hdr_test_core(stbi__context *s, const char *signature) +{ + int i; + for (i=0; signature[i]; ++i) + if (stbi__get8(s) != signature[i]) + return 0; + stbi__rewind(s); + return 1; +} + +static int stbi__hdr_test(stbi__context* s) +{ + int r = stbi__hdr_test_core(s, "#?RADIANCE\n"); + stbi__rewind(s); + if(!r) { + r = stbi__hdr_test_core(s, "#?RGBE\n"); + stbi__rewind(s); + } + return r; +} + +#define STBI__HDR_BUFLEN 1024 +static char *stbi__hdr_gettoken(stbi__context *z, char *buffer) +{ + int len=0; + char c = '\0'; + + c = (char) stbi__get8(z); + + while (!stbi__at_eof(z) && c != '\n') { + buffer[len++] = c; + if (len == STBI__HDR_BUFLEN-1) { + // flush to end of line + while (!stbi__at_eof(z) && stbi__get8(z) != '\n') + ; + break; + } + c = (char) stbi__get8(z); + } + + buffer[len] = 0; + return buffer; +} + +static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp) +{ + if ( input[3] != 0 ) { + float f1; + // Exponent + f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8)); + if (req_comp <= 2) + output[0] = (input[0] + input[1] + input[2]) * f1 / 3; + else { + output[0] = input[0] * f1; + output[1] = input[1] * f1; + output[2] = input[2] * f1; + } + if (req_comp == 2) output[1] = 1; + if (req_comp == 4) output[3] = 1; + } else { + switch (req_comp) { + case 4: output[3] = 1; /* fallthrough */ + case 3: output[0] = output[1] = output[2] = 0; + break; + case 2: output[1] = 1; /* fallthrough */ + case 1: output[0] = 0; + break; + } + } +} + +static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int width, height; + stbi_uc *scanline; + float *hdr_data; + int len; + unsigned char count, value; + int i, j, k, c1,c2, z; + const char *headerToken; + STBI_NOTUSED(ri); + + // Check identifier + headerToken = stbi__hdr_gettoken(s,buffer); + if (strcmp(headerToken, "#?RADIANCE") != 0 && strcmp(headerToken, "#?RGBE") != 0) + return stbi__errpf("not HDR", "Corrupt HDR image"); + + // Parse header + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) return stbi__errpf("unsupported format", "Unsupported HDR format"); + + // Parse width and height + // can't use sscanf() if we're not using stdio! + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + height = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) return stbi__errpf("unsupported data layout", "Unsupported HDR format"); + token += 3; + width = (int) strtol(token, NULL, 10); + + if (height > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + if (width > STBI_MAX_DIMENSIONS) return stbi__errpf("too large","Very large image (corrupt?)"); + + *x = width; + *y = height; + + if (comp) *comp = 3; + if (req_comp == 0) req_comp = 3; + + if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0)) + return stbi__errpf("too large", "HDR image is too large"); + + // Read data + hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0); + if (!hdr_data) + return stbi__errpf("outofmem", "Out of memory"); + + // Load image data + // image data is stored as some number of sca + if ( width < 8 || width >= 32768) { + // Read flat data + for (j=0; j < height; ++j) { + for (i=0; i < width; ++i) { + stbi_uc rgbe[4]; + main_decode_loop: + stbi__getn(s, rgbe, 4); + stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp); + } + } + } else { + // Read RLE-encoded data + scanline = NULL; + + for (j = 0; j < height; ++j) { + c1 = stbi__get8(s); + c2 = stbi__get8(s); + len = stbi__get8(s); + if (c1 != 2 || c2 != 2 || (len & 0x80)) { + // not run-length encoded, so we have to actually use THIS data as a decoded + // pixel (note this can't be a valid pixel--one of RGB must be >= 128) + stbi_uc rgbe[4]; + rgbe[0] = (stbi_uc) c1; + rgbe[1] = (stbi_uc) c2; + rgbe[2] = (stbi_uc) len; + rgbe[3] = (stbi_uc) stbi__get8(s); + stbi__hdr_convert(hdr_data, rgbe, req_comp); + i = 1; + j = 0; + STBI_FREE(scanline); + goto main_decode_loop; // yes, this makes no sense + } + len <<= 8; + len |= stbi__get8(s); + if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); } + if (scanline == NULL) { + scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0); + if (!scanline) { + STBI_FREE(hdr_data); + return stbi__errpf("outofmem", "Out of memory"); + } + } + + for (k = 0; k < 4; ++k) { + int nleft; + i = 0; + while ((nleft = width - i) > 0) { + count = stbi__get8(s); + if (count > 128) { + // Run + value = stbi__get8(s); + count -= 128; + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = value; + } else { + // Dump + if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + for (z = 0; z < count; ++z) + scanline[i++ * 4 + k] = stbi__get8(s); + } + } + } + for (i=0; i < width; ++i) + stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp); + } + if (scanline) + STBI_FREE(scanline); + } + + return hdr_data; +} + +static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp) +{ + char buffer[STBI__HDR_BUFLEN]; + char *token; + int valid = 0; + int dummy; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (stbi__hdr_test(s) == 0) { + stbi__rewind( s ); + return 0; + } + + for(;;) { + token = stbi__hdr_gettoken(s,buffer); + if (token[0] == 0) break; + if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1; + } + + if (!valid) { + stbi__rewind( s ); + return 0; + } + token = stbi__hdr_gettoken(s,buffer); + if (strncmp(token, "-Y ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *y = (int) strtol(token, &token, 10); + while (*token == ' ') ++token; + if (strncmp(token, "+X ", 3)) { + stbi__rewind( s ); + return 0; + } + token += 3; + *x = (int) strtol(token, NULL, 10); + *comp = 3; + return 1; +} +#endif // STBI_NO_HDR + +#ifndef STBI_NO_BMP +static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp) +{ + void *p; + stbi__bmp_data info; + + info.all_a = 255; + p = stbi__bmp_parse_header(s, &info); + stbi__rewind( s ); + if (p == NULL) + return 0; + if (x) *x = s->img_x; + if (y) *y = s->img_y; + if (comp) { + if (info.bpp == 24 && info.ma == 0xff000000) + *comp = 3; + else + *comp = info.ma ? 4 : 3; + } + return 1; +} +#endif + +#ifndef STBI_NO_PSD +static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp) +{ + int channelCount, dummy, depth; + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + *y = stbi__get32be(s); + *x = stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 8 && depth != 16) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 3) { + stbi__rewind( s ); + return 0; + } + *comp = 4; + return 1; +} + +static int stbi__psd_is16(stbi__context *s) +{ + int channelCount, depth; + if (stbi__get32be(s) != 0x38425053) { + stbi__rewind( s ); + return 0; + } + if (stbi__get16be(s) != 1) { + stbi__rewind( s ); + return 0; + } + stbi__skip(s, 6); + channelCount = stbi__get16be(s); + if (channelCount < 0 || channelCount > 16) { + stbi__rewind( s ); + return 0; + } + (void) stbi__get32be(s); + (void) stbi__get32be(s); + depth = stbi__get16be(s); + if (depth != 16) { + stbi__rewind( s ); + return 0; + } + return 1; +} +#endif + +#ifndef STBI_NO_PIC +static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp) +{ + int act_comp=0,num_packets=0,chained,dummy; + stbi__pic_packet packets[10]; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) { + stbi__rewind(s); + return 0; + } + + stbi__skip(s, 88); + + *x = stbi__get16be(s); + *y = stbi__get16be(s); + if (stbi__at_eof(s)) { + stbi__rewind( s); + return 0; + } + if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) { + stbi__rewind( s ); + return 0; + } + + stbi__skip(s, 8); + + do { + stbi__pic_packet *packet; + + if (num_packets==sizeof(packets)/sizeof(packets[0])) + return 0; + + packet = &packets[num_packets++]; + chained = stbi__get8(s); + packet->size = stbi__get8(s); + packet->type = stbi__get8(s); + packet->channel = stbi__get8(s); + act_comp |= packet->channel; + + if (stbi__at_eof(s)) { + stbi__rewind( s ); + return 0; + } + if (packet->size != 8) { + stbi__rewind( s ); + return 0; + } + } while (chained); + + *comp = (act_comp & 0x10 ? 4 : 3); + + return 1; +} +#endif + +// ************************************************************************************************* +// Portable Gray Map and Portable Pixel Map loader +// by Ken Miller +// +// PGM: http://netpbm.sourceforge.net/doc/pgm.html +// PPM: http://netpbm.sourceforge.net/doc/ppm.html +// +// Known limitations: +// Does not support comments in the header section +// Does not support ASCII image data (formats P2 and P3) +// Does not support 16-bit-per-channel + +#ifndef STBI_NO_PNM + +static int stbi__pnm_test(stbi__context *s) +{ + char p, t; + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind( s ); + return 0; + } + return 1; +} + +static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri) +{ + stbi_uc *out; + STBI_NOTUSED(ri); + + if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n)) + return 0; + + if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc("too large","Very large image (corrupt?)"); + + *x = s->img_x; + *y = s->img_y; + if (comp) *comp = s->img_n; + + if (!stbi__mad3sizes_valid(s->img_n, s->img_x, s->img_y, 0)) + return stbi__errpuc("too large", "PNM too large"); + + out = (stbi_uc *) stbi__malloc_mad3(s->img_n, s->img_x, s->img_y, 0); + if (!out) return stbi__errpuc("outofmem", "Out of memory"); + stbi__getn(s, out, s->img_n * s->img_x * s->img_y); + + if (req_comp && req_comp != s->img_n) { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (out == NULL) return out; // stbi__convert_format frees input on failure + } + return out; +} + +static int stbi__pnm_isspace(char c) +{ + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +static void stbi__pnm_skip_whitespace(stbi__context *s, char *c) +{ + for (;;) { + while (!stbi__at_eof(s) && stbi__pnm_isspace(*c)) + *c = (char) stbi__get8(s); + + if (stbi__at_eof(s) || *c != '#') + break; + + while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' ) + *c = (char) stbi__get8(s); + } +} + +static int stbi__pnm_isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static int stbi__pnm_getinteger(stbi__context *s, char *c) +{ + int value = 0; + + while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { + value = value*10 + (*c - '0'); + *c = (char) stbi__get8(s); + } + + return value; +} + +static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) +{ + int maxv, dummy; + char c, p, t; + + if (!x) x = &dummy; + if (!y) y = &dummy; + if (!comp) comp = &dummy; + + stbi__rewind(s); + + // Get identifier + p = (char) stbi__get8(s); + t = (char) stbi__get8(s); + if (p != 'P' || (t != '5' && t != '6')) { + stbi__rewind(s); + return 0; + } + + *comp = (t == '6') ? 3 : 1; // '5' is 1-component .pgm; '6' is 3-component .ppm + + c = (char) stbi__get8(s); + stbi__pnm_skip_whitespace(s, &c); + + *x = stbi__pnm_getinteger(s, &c); // read width + stbi__pnm_skip_whitespace(s, &c); + + *y = stbi__pnm_getinteger(s, &c); // read height + stbi__pnm_skip_whitespace(s, &c); + + maxv = stbi__pnm_getinteger(s, &c); // read max value + + if (maxv > 255) + return stbi__err("max value > 255", "PPM image not 8-bit"); + else + return 1; +} +#endif + +static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp) +{ + #ifndef STBI_NO_JPEG + if (stbi__jpeg_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNG + if (stbi__png_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_GIF + if (stbi__gif_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_BMP + if (stbi__bmp_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PIC + if (stbi__pic_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_PNM + if (stbi__pnm_info(s, x, y, comp)) return 1; + #endif + + #ifndef STBI_NO_HDR + if (stbi__hdr_info(s, x, y, comp)) return 1; + #endif + + // test tga last because it's a crappy test! + #ifndef STBI_NO_TGA + if (stbi__tga_info(s, x, y, comp)) + return 1; + #endif + return stbi__err("unknown image type", "Image not of any known type, or corrupt"); +} + +static int stbi__is_16_main(stbi__context *s) +{ + #ifndef STBI_NO_PNG + if (stbi__png_is16(s)) return 1; + #endif + + #ifndef STBI_NO_PSD + if (stbi__psd_is16(s)) return 1; + #endif + + return 0; +} + +#ifndef STBI_NO_STDIO +STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_info_from_file(f, x, y, comp); + fclose(f); + return result; +} + +STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__info_main(&s,x,y,comp); + fseek(f,pos,SEEK_SET); + return r; +} + +STBIDEF int stbi_is_16_bit(char const *filename) +{ + FILE *f = stbi__fopen(filename, "rb"); + int result; + if (!f) return stbi__err("can't fopen", "Unable to open file"); + result = stbi_is_16_bit_from_file(f); + fclose(f); + return result; +} + +STBIDEF int stbi_is_16_bit_from_file(FILE *f) +{ + int r; + stbi__context s; + long pos = ftell(f); + stbi__start_file(&s, f); + r = stbi__is_16_main(&s); + fseek(f,pos,SEEK_SET); + return r; +} +#endif // !STBI_NO_STDIO + +STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__info_main(&s,x,y,comp); +} + +STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len) +{ + stbi__context s; + stbi__start_mem(&s,buffer,len); + return stbi__is_16_main(&s); +} + +STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user) +{ + stbi__context s; + stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user); + return stbi__is_16_main(&s); +} + +#endif // STB_IMAGE_IMPLEMENTATION + +/* + revision history: + 2.20 (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs + 2.19 (2018-02-11) fix warning + 2.18 (2018-01-30) fix warnings + 2.17 (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug + 1-bit BMP + *_is_16_bit api + avoid warnings + 2.16 (2017-07-23) all functions have 16-bit variants; + STBI_NO_STDIO works again; + compilation fixes; + fix rounding in unpremultiply; + optimize vertical flip; + disable raw_len validation; + documentation fixes + 2.15 (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode; + warning fixes; disable run-time SSE detection on gcc; + uniform handling of optional "return" values; + thread-safe initialization of zlib tables + 2.14 (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs + 2.13 (2016-11-29) add 16-bit API, only supported for PNG right now + 2.12 (2016-04-02) fix typo in 2.11 PSD fix that caused crashes + 2.11 (2016-04-02) allocate large structures on the stack + remove white matting for transparent PSD + fix reported channel count for PNG & BMP + re-enable SSE2 in non-gcc 64-bit + support RGB-formatted JPEG + read 16-bit PNGs (only as 8-bit) + 2.10 (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED + 2.09 (2016-01-16) allow comments in PNM files + 16-bit-per-pixel TGA (not bit-per-component) + info() for TGA could break due to .hdr handling + info() for BMP to shares code instead of sloppy parse + can use STBI_REALLOC_SIZED if allocator doesn't support realloc + code cleanup + 2.08 (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA + 2.07 (2015-09-13) fix compiler warnings + partial animated GIF support + limited 16-bpc PSD support + #ifdef unused functions + bug with < 92 byte PIC,PNM,HDR,TGA + 2.06 (2015-04-19) fix bug where PSD returns wrong '*comp' value + 2.05 (2015-04-19) fix bug in progressive JPEG handling, fix warning + 2.04 (2015-04-15) try to re-enable SIMD on MinGW 64-bit + 2.03 (2015-04-12) extra corruption checking (mmozeiko) + stbi_set_flip_vertically_on_load (nguillemot) + fix NEON support; fix mingw support + 2.02 (2015-01-19) fix incorrect assert, fix warning + 2.01 (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2 + 2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG + 2.00 (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg) + progressive JPEG (stb) + PGM/PPM support (Ken Miller) + STBI_MALLOC,STBI_REALLOC,STBI_FREE + GIF bugfix -- seemingly never worked + STBI_NO_*, STBI_ONLY_* + 1.48 (2014-12-14) fix incorrectly-named assert() + 1.47 (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb) + optimize PNG (ryg) + fix bug in interlaced PNG with user-specified channel count (stb) + 1.46 (2014-08-26) + fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG + 1.45 (2014-08-16) + fix MSVC-ARM internal compiler error by wrapping malloc + 1.44 (2014-08-07) + various warning fixes from Ronny Chevalier + 1.43 (2014-07-15) + fix MSVC-only compiler problem in code changed in 1.42 + 1.42 (2014-07-09) + don't define _CRT_SECURE_NO_WARNINGS (affects user code) + fixes to stbi__cleanup_jpeg path + added STBI_ASSERT to avoid requiring assert.h + 1.41 (2014-06-25) + fix search&replace from 1.36 that messed up comments/error messages + 1.40 (2014-06-22) + fix gcc struct-initialization warning + 1.39 (2014-06-15) + fix to TGA optimization when req_comp != number of components in TGA; + fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite) + add support for BMP version 5 (more ignored fields) + 1.38 (2014-06-06) + suppress MSVC warnings on integer casts truncating values + fix accidental rename of 'skip' field of I/O + 1.37 (2014-06-04) + remove duplicate typedef + 1.36 (2014-06-03) + convert to header file single-file library + if de-iphone isn't set, load iphone images color-swapped instead of returning NULL + 1.35 (2014-05-27) + various warnings + fix broken STBI_SIMD path + fix bug where stbi_load_from_file no longer left file pointer in correct place + fix broken non-easy path for 32-bit BMP (possibly never used) + TGA optimization by Arseny Kapoulkine + 1.34 (unknown) + use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case + 1.33 (2011-07-14) + make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements + 1.32 (2011-07-13) + support for "info" function for all supported filetypes (SpartanJ) + 1.31 (2011-06-20) + a few more leak fixes, bug in PNG handling (SpartanJ) + 1.30 (2011-06-11) + added ability to load files via callbacks to accomidate custom input streams (Ben Wenger) + removed deprecated format-specific test/load functions + removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway + error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha) + fix inefficiency in decoding 32-bit BMP (David Woo) + 1.29 (2010-08-16) + various warning fixes from Aurelien Pocheville + 1.28 (2010-08-01) + fix bug in GIF palette transparency (SpartanJ) + 1.27 (2010-08-01) + cast-to-stbi_uc to fix warnings + 1.26 (2010-07-24) + fix bug in file buffering for PNG reported by SpartanJ + 1.25 (2010-07-17) + refix trans_data warning (Won Chun) + 1.24 (2010-07-12) + perf improvements reading from files on platforms with lock-heavy fgetc() + minor perf improvements for jpeg + deprecated type-specific functions so we'll get feedback if they're needed + attempt to fix trans_data warning (Won Chun) + 1.23 fixed bug in iPhone support + 1.22 (2010-07-10) + removed image *writing* support + stbi_info support from Jetro Lauha + GIF support from Jean-Marc Lienher + iPhone PNG-extensions from James Brown + warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva) + 1.21 fix use of 'stbi_uc' in header (reported by jon blow) + 1.20 added support for Softimage PIC, by Tom Seddon + 1.19 bug in interlaced PNG corruption check (found by ryg) + 1.18 (2008-08-02) + fix a threading bug (local mutable static) + 1.17 support interlaced PNG + 1.16 major bugfix - stbi__convert_format converted one too many pixels + 1.15 initialize some fields for thread safety + 1.14 fix threadsafe conversion bug + header-file-only version (#define STBI_HEADER_FILE_ONLY before including) + 1.13 threadsafe + 1.12 const qualifiers in the API + 1.11 Support installable IDCT, colorspace conversion routines + 1.10 Fixes for 64-bit (don't use "unsigned long") + optimized upsampling by Fabian "ryg" Giesen + 1.09 Fix format-conversion for PSD code (bad global variables!) + 1.08 Thatcher Ulrich's PSD code integrated by Nicolas Schulz + 1.07 attempt to fix C++ warning/errors again + 1.06 attempt to fix C++ warning/errors again + 1.05 fix TGA loading to return correct *comp and use good luminance calc + 1.04 default float alpha is 1, not 255; use 'void *' for stbi_image_free + 1.03 bugfixes to STBI_NO_STDIO, STBI_NO_HDR + 1.02 support for (subset of) HDR files, float interface for preferred access to them + 1.01 fix bug: possible bug in handling right-side up bmps... not sure + fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all + 1.00 interface to zlib that skips zlib header + 0.99 correct handling of alpha in palette + 0.98 TGA loader by lonesock; dynamically add loaders (untested) + 0.97 jpeg errors on too large a file; also catch another malloc failure + 0.96 fix detection of invalid v value - particleman@mollyrocket forum + 0.95 during header scan, seek to markers in case of padding + 0.94 STBI_NO_STDIO to disable stdio usage; rename all #defines the same + 0.93 handle jpegtran output; verbose errors + 0.92 read 4,8,16,24,32-bit BMP files of several formats + 0.91 output 24-bit Windows 3.0 BMP files + 0.90 fix a few more warnings; bump version number to approach 1.0 + 0.61 bugfixes due to Marc LeBlanc, Christopher Lloyd + 0.60 fix compiling as c++ + 0.59 fix warnings: merge Dave Moore's -Wall fixes + 0.58 fix bug: zlib uncompressed mode len/nlen was wrong endian + 0.57 fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available + 0.56 fix bug: zlib uncompressed mode len vs. nlen + 0.55 fix bug: restart_interval not initialized to 0 + 0.54 allow NULL for 'int *comp' + 0.53 fix bug in png 3->4; speedup png decoding + 0.52 png handles req_comp=3,4 directly; minor cleanup; jpeg comments + 0.51 obey req_comp requests, 1-component jpegs return as 1-component, + on 'test' only check type, not whether we support this variant + 0.50 (2006-11-19) + first released version +*/ + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/scripts/tags.sh b/scripts/tags.sh index 8ae44642a2..4e18ae5282 100755 --- a/scripts/tags.sh +++ b/scripts/tags.sh @@ -1,70 +1,64 @@ -#!/bin/sh +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only # Generate tags or cscope files # Usage tags.sh <mode> # # mode may be any of: tags, TAGS, cscope # # Uses the following environment variables: -# ARCH, SUBARCH, SRCARCH, srctree, src, obj +# SUBARCH, SRCARCH, srctree if [ "$KBUILD_VERBOSE" = "1" ]; then set -x fi -# This is a duplicate of RCS_FIND_IGNORE without escaped '()' -ignore="( -name SCCS -o -name BitKeeper -o -name .svn -o \ - -name CVS -o -name .pc -o -name .hg -o \ - -name .git ) \ - -prune -o" +# RCS_FIND_IGNORE has escaped ()s -- remove them. +ignore="$(echo "$RCS_FIND_IGNORE" | sed 's|\\||g' )" +# tags and cscope files should also ignore MODVERSION *.mod.c files +ignore="$ignore ( -name *.mod.c ) -prune -o" -# Do not use full path if we do not use O=.. builds -# Use make O=. {tags|cscope} +# Use make KBUILD_ABS_SRCTREE=1 {tags|cscope} # to force full paths for a non-O= build -if [ "${KBUILD_SRC}" = "" ]; then +if [ "${srctree}" = "." -o -z "${srctree}" ]; then tree= else tree=${srctree}/ fi -# Find all available archs -find_all_archs() -{ - ALLSOURCE_ARCHS="" - for arch in `ls ${tree}arch`; do - ALLSOURCE_ARCHS="${ALLSOURCE_ARCHS} "${arch##\/} - done -} +# ignore userspace tools +ignore="$ignore ( -path ${tree}tools ) -prune -o" # Detect if ALLSOURCE_ARCHS is set. If not, we assume SRCARCH if [ "${ALLSOURCE_ARCHS}" = "" ]; then ALLSOURCE_ARCHS=${SRCARCH} elif [ "${ALLSOURCE_ARCHS}" = "all" ]; then - find_all_archs + ALLSOURCE_ARCHS=$(find ${tree}arch/ -mindepth 1 -maxdepth 1 -type d -printf '%f ') fi -# find sources in arch/$ARCH +# find sources in arch/$1 find_arch_sources() { for i in $archincludedir; do prune="$prune -wholename $i -prune -o" done - find ${tree}arch/$1 $ignore $prune -name "$2" -print; + find ${tree}arch/$1 $ignore $prune -name "$2" -not -type l -print; } # find sources in arch/$1/include find_arch_include_sources() { - include=$(find ${tree}arch/$1/ -name include -type d); + include=$(find ${tree}arch/$1/ -name include -type d -print); if [ -n "$include" ]; then archincludedir="$archincludedir $include" - find $include $ignore -name "$2" -print; + find $include $ignore -name "$2" -not -type l -print; fi } # find sources in include/ find_include_sources() { - find ${tree}include $ignore -name config -prune -o -name "$1" -print; + find ${tree}include $ignore -name config -prune -o -name "$1" \ + -not -type l -print; } # find sources in rest of tree @@ -72,8 +66,8 @@ find_include_sources() find_other_sources() { find ${tree}* $ignore \ - \( -name include -o -name arch -o -name '.tmp_*' \) -prune -o \ - -name "$1" -print; + \( -path ${tree}include -o -path ${tree}arch -o -name '.tmp_*' \) -prune -o \ + -name "$1" -not -type l -print; } find_sources() @@ -95,8 +89,37 @@ all_sources() find_other_sources '*.[chS]' } +all_compiled_sources() +{ + for i in $(all_sources); do + case "$i" in + *.[cS]) + j=${i/\.[cS]/\.o} + j="${j#$tree}" + if [ -e $j ]; then + echo $i + fi + ;; + *) + echo $i + ;; + esac + done +} + +all_target_sources() +{ + if [ -n "$COMPILED_SOURCE" ]; then + all_compiled_sources + else + all_sources + fi +} + all_kconfigs() { + find ${tree}arch/ -maxdepth 1 $ignore \ + -name "Kconfig*" -not -type l -print; for arch in $ALLSOURCE_ARCHS; do find_sources $arch 'Kconfig*' done @@ -105,93 +128,159 @@ all_kconfigs() docscope() { - (echo \-k; echo \-q; all_sources) > cscope.files + (echo \-k; echo \-q; all_target_sources) > cscope.files cscope -b -f cscope.out } dogtags() { - all_sources | gtags -i -f - + all_target_sources | gtags -i -f - +} + +# Basic regular expressions with an optional /kind-spec/ for ctags and +# the following limitations: +# - No regex modifiers +# - Use \{0,1\} instead of \?, because etags expects an unescaped ? +# - \s is not working with etags, use a space or [ \t] +# - \w works, but does not match underscores in etags +# - etags regular expressions have to match at the start of a line; +# a ^[^#] is prepended by setup_regex unless an anchor is already present +regex_asm=( + '/^\(ENTRY\|_GLOBAL\)(\([[:alnum:]_\\]*\)).*/\2/' +) +regex_c=( + '/^SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/sys_\1/' + '/^BPF_CALL_[0-9](\([[:alnum:]_]*\).*/\1/' + '/^COMPAT_SYSCALL_DEFINE[0-9](\([[:alnum:]_]*\).*/compat_sys_\1/' + '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1/' + '/^TRACE_EVENT(\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1/' + '/^DEFINE_EVENT([^,)]*, *\([[:alnum:]_]*\).*/trace_\1_rcuidle/' + '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/get_\1_slot/' + '/^DEFINE_INSN_CACHE_OPS(\([[:alnum:]_]*\).*/free_\1_slot/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' + '/^PAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/' + '/^TESTSETFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/' + '/^TESTPAGEFLAG(\([[:alnum:]_]*\).*/Page\1/' + '/^SETPAGEFLAG(\([[:alnum:]_]*\).*/SetPage\1/' + '/\<__SETPAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/' + '/\<TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<__TESTCLEARFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<CLEARPAGEFLAG(\([[:alnum:]_]*\).*/ClearPage\1/' + '/\<__CLEARPAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__SetPage\1/' + '/^__PAGEFLAG(\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^PAGEFLAG_FALSE(\([[:alnum:]_]*\).*/Page\1/' + '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestSetPage\1/' + '/\<TESTSCFLAG(\([[:alnum:]_]*\).*/TestClearPage\1/' + '/\<SETPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/SetPage\1/' + '/\<CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/ClearPage\1/' + '/\<__CLEARPAGEFLAG_NOOP(\([[:alnum:]_]*\).*/__ClearPage\1/' + '/\<TESTCLEARFLAG_FALSE(\([[:alnum:]_]*\).*/TestClearPage\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/Page\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__SetPage\1/' + '/^PAGE_TYPE_OPS(\([[:alnum:]_]*\).*/__ClearPage\1/' + '/^TASK_PFA_TEST([^,]*, *\([[:alnum:]_]*\))/task_\1/' + '/^TASK_PFA_SET([^,]*, *\([[:alnum:]_]*\))/task_set_\1/' + '/^TASK_PFA_CLEAR([^,]*, *\([[:alnum:]_]*\))/task_clear_\1/' + '/^DEF_MMIO_\(IN\|OUT\)_[XD](\([[:alnum:]_]*\),[^)]*)/\2/' + '/^DEBUGGER_BOILERPLATE(\([[:alnum:]_]*\))/\1/' + '/^DEF_PCI_AC_\(\|NO\)RET(\([[:alnum:]_]*\).*/\2/' + '/^PCI_OP_READ(\(\w*\).*[1-4])/pci_bus_read_config_\1/' + '/^PCI_OP_WRITE(\(\w*\).*[1-4])/pci_bus_write_config_\1/' + '/\<DEFINE_\(RT_MUTEX\|MUTEX\|SEMAPHORE\|SPINLOCK\)(\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_\(RAW_SPINLOCK\|RWLOCK\|SEQLOCK\)(\([[:alnum:]_]*\)/\2/v/' + '/\<DECLARE_\(RWSEM\|COMPLETION\)(\([[:alnum:]_]\+\)/\2/v/' + '/\<DECLARE_BITMAP(\([[:alnum:]_]*\)/\1/v/' + '/\(^\|\s\)\(\|L\|H\)LIST_HEAD(\([[:alnum:]_]*\)/\3/v/' + '/\(^\|\s\)RADIX_TREE(\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_PER_CPU([^,]*, *\([[:alnum:]_]*\)/\1/v/' + '/\<DEFINE_PER_CPU_SHARED_ALIGNED([^,]*, *\([[:alnum:]_]*\)/\1/v/' + '/\<DECLARE_WAIT_QUEUE_HEAD(\([[:alnum:]_]*\)/\1/v/' + '/\<DECLARE_\(TASKLET\|WORK\|DELAYED_WORK\)(\([[:alnum:]_]*\)/\2/v/' + '/\(^\s\)OFFSET(\([[:alnum:]_]*\)/\2/v/' + '/\(^\s\)DEFINE(\([[:alnum:]_]*\)/\2/v/' + '/\<\(DEFINE\|DECLARE\)_HASHTABLE(\([[:alnum:]_]*\)/\2/v/' + '/\<DEFINE_ID\(R\|A\)(\([[:alnum:]_]\+\)/\2/' + '/\<DEFINE_WD_CLASS(\([[:alnum:]_]\+\)/\1/' + '/\<ATOMIC_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' + '/\<RAW_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' + '/\<DECLARE_FAULT_ATTR(\([[:alnum:]_]\+\)/\1/' + '/\<BLOCKING_NOTIFIER_HEAD(\([[:alnum:]_]\+\)/\1/' + '/\<DEVICE_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/dev_attr_\2/' + '/\<DRIVER_ATTR_\(RW\|RO\|WO\)(\([[:alnum:]_]\+\)/driver_attr_\2/' + '/\<\(DEFINE\|DECLARE\)_STATIC_KEY_\(TRUE\|FALSE\)\(\|_RO\)(\([[:alnum:]_]\+\)/\4/' +) +regex_kconfig=( + '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/\2/' + '/^[[:blank:]]*\(menu\|\)config[[:blank:]]\+\([[:alnum:]_]\+\)/CONFIG_\2/' +) +setup_regex() +{ + local mode=$1 lang tmp=() r + shift + + regex=() + for lang; do + case "$lang" in + asm) tmp=("${regex_asm[@]}") ;; + c) tmp=("${regex_c[@]}") ;; + kconfig) tmp=("${regex_kconfig[@]}") ;; + esac + for r in "${tmp[@]}"; do + if test "$mode" = "exuberant"; then + regex[${#regex[@]}]="--regex-$lang=${r}b" + else + # Remove ctags /kind-spec/ + case "$r" in + /*/*/?/) + r=${r%?/} + esac + # Prepend ^[^#] unless already anchored + case "$r" in + /^*) ;; + *) + r="/^[^#]*${r#/}" + esac + regex[${#regex[@]}]="--regex=$r" + fi + done + done } exuberant() { - all_sources | xargs $1 -a \ - -I __initdata,__exitdata,__acquires,__releases \ - -I __read_mostly,____cacheline_aligned \ + setup_regex exuberant asm c + all_target_sources | xargs $1 -a \ + -I __initdata,__exitdata,__initconst,__ro_after_init \ + -I __initdata_memblock \ + -I __refdata,__attribute,__maybe_unused,__always_unused \ + -I __acquires,__releases,__deprecated,__always_inline \ + -I __read_mostly,__aligned,____cacheline_aligned \ -I ____cacheline_aligned_in_smp \ + -I __cacheline_aligned,__cacheline_aligned_in_smp \ -I ____cacheline_internodealigned_in_smp \ - -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + -I __used,__packed,__packed2__,__must_check,__must_hold \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL,ACPI_EXPORT_SYMBOL \ -I DEFINE_TRACE,EXPORT_TRACEPOINT_SYMBOL,EXPORT_TRACEPOINT_SYMBOL_GPL \ - --extra=+f --c-kinds=+px \ - --regex-asm='/^(ENTRY|_GLOBAL)\(([^)]*)\).*/\2/' \ - --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/' \ - --regex-c++='/^TRACE_EVENT\(([^,)]*).*/trace_\1/' \ - --regex-c++='/^DEFINE_EVENT\([^,)]*, *([^,)]*).*/trace_\1/' \ - --regex-c++='/PAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex-c++='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex-c++='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex-c++='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex-c++='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex-c++='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex-c++='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex-c++='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex-c++='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex-c++='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex-c++='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex-c++='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex-c++='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex-c++='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \ - --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex-c++='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex-c++='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \ - --regex-c++='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ - --regex-c++='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ - --regex-c++='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ - --regex-c++='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ - --regex-c='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ - --regex-c='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' + -I static,const \ + --extra=+fq --c-kinds=+px --fields=+iaS --langmap=c:+.h \ + "${regex[@]}" + setup_regex exuberant kconfig all_kconfigs | xargs $1 -a \ - --langdef=kconfig --language-force=kconfig \ - --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/\2/' \ - --regex-kconfig='/^[[:blank:]]*(menu|)config[[:blank:]]+([[:alnum:]_]+)/CONFIG_\2/' + --langdef=kconfig --language-force=kconfig "${regex[@]}" + } emacs() { - all_sources | xargs $1 -a \ - --regex='/^(ENTRY|_GLOBAL)(\([^)]*\)).*/\2/' \ - --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/' \ - --regex='/^TRACE_EVENT(\([^,)]*\).*/trace_\1/' \ - --regex='/^DEFINE_EVENT([^,)]*, *\([^,)]*\).*/trace_\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex='/PAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex='/TESTSETFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex='/TESTPAGEFLAG\(([^,)]*).*/Page\1/' \ - --regex='/SETPAGEFLAG\(([^,)]*).*/SetPage\1/' \ - --regex='/__SETPAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex='/TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/__TESTCLEARFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/CLEARPAGEFLAG\(([^,)]*).*/ClearPage\1/' \ - --regex='/__CLEARPAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex='/__PAGEFLAG\(([^,)]*).*/__SetPage\1/' \ - --regex='/__PAGEFLAG\(([^,)]*).*/__ClearPage\1/' \ - --regex='/PAGEFLAG_FALSE\(([^,)]*).*/Page\1/' \ - --regex='/TESTSCFLAG\(([^,)]*).*/TestSetPage\1/' \ - --regex='/TESTSCFLAG\(([^,)]*).*/TestClearPage\1/' \ - --regex='/SETPAGEFLAG_NOOP\(([^,)]*).*/SetPage\1/' \ - --regex='/CLEARPAGEFLAG_NOOP\(([^,)]*).*/ClearPage\1/' \ - --regex='/__CLEARPAGEFLAG_NOOP\(([^,)]*).*/__ClearPage\1/' \ - --regex='/TESTCLEARFLAG_FALSE\(([^,)]*).*/TestClearPage\1/' \ - --regex='/_PE\(([^,)]*).*/PEVENT_ERRNO__\1/' \ - --regex='/PCI_OP_READ\(([a-z]*[a-z]).*[1-4]\)/pci_bus_read_config_\1/' \ - --regex='/PCI_OP_WRITE\(([a-z]*[a-z]).*[1-4]\)/pci_bus_write_config_\1/' + setup_regex emacs asm c + all_target_sources | xargs $1 -a "${regex[@]}" - all_kconfigs | xargs $1 -a \ - --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/' \ - --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/CONFIG_\3/' + setup_regex emacs kconfig + all_kconfigs | xargs $1 -a "${regex[@]}" } xtags() @@ -201,11 +290,10 @@ xtags() elif $1 --version 2>&1 | grep -iq emacs; then emacs $1 else - all_sources | xargs $1 -a - fi + all_target_sources | xargs $1 -a + fi } - # Support um (which uses SUBARCH) if [ "${ARCH}" = "um" ]; then if [ "$SUBARCH" = "i386" ]; then diff --git a/scripts/tegra/.gitignore b/scripts/tegra/.gitignore index 5d5891b243..96cc56e4a7 100644 --- a/scripts/tegra/.gitignore +++ b/scripts/tegra/.gitignore @@ -1 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + cbootimage diff --git a/scripts/tegra/Makefile b/scripts/tegra/Makefile index 8ebc27ca73..2c682786b1 100644 --- a/scripts/tegra/Makefile +++ b/scripts/tegra/Makefile @@ -1,6 +1,6 @@ -hostprogs-$(CONFIG_ARCH_TEGRA) += cbootimage +# SPDX-License-Identifier: GPL-2.0-only -always := $(hostprogs-y) +hostprogs-always-$(CONFIG_ARCH_TEGRA) += cbootimage HOSTLDLIBS_cbootimage = '-lm' diff --git a/scripts/tegra/aes_ref.c b/scripts/tegra/aes_ref.c index 4ae110f996..2258311b03 100644 --- a/scripts/tegra/aes_ref.c +++ b/scripts/tegra/aes_ref.c @@ -12,9 +12,6 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. */ /* advanced encryption standard diff --git a/scripts/tegra/bct_dump.c b/scripts/tegra/bct_dump.c index dbef91382c..bf4c146bac 100644 --- a/scripts/tegra/bct_dump.c +++ b/scripts/tegra/bct_dump.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION #include "cbootimage.h" #include "data_layout.h" diff --git a/scripts/tegra/cbootimage.c b/scripts/tegra/cbootimage.c index 89682eb8b9..7714893d28 100644 --- a/scripts/tegra/cbootimage.c +++ b/scripts/tegra/cbootimage.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * cbootimage.c - Implementation of the cbootimage tool. diff --git a/scripts/tegra/cbootimage.h b/scripts/tegra/cbootimage.h index 46e3b8b3b7..99b37d1563 100644 --- a/scripts/tegra/cbootimage.h +++ b/scripts/tegra/cbootimage.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /* * cbootimage.h - Definitions for the cbootimage code. diff --git a/scripts/tegra/context.c b/scripts/tegra/context.c index 25b322f41b..93a5e33ce1 100644 --- a/scripts/tegra/context.c +++ b/scripts/tegra/context.c @@ -1,25 +1,10 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION #include "cbootimage.h" #include "data_layout.h" #include "set.h" +#include "context.h" void cleanup_context(build_image_context *context) diff --git a/scripts/tegra/context.h b/scripts/tegra/context.h index 6e724718b6..f0f5d0587a 100644 --- a/scripts/tegra/context.h +++ b/scripts/tegra/context.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ #ifndef INCLUDED_CONTEXT_H #define INCLUDED_CONTEXT_H diff --git a/scripts/tegra/crypto.c b/scripts/tegra/crypto.c index e88a255b25..17d422990b 100644 --- a/scripts/tegra/crypto.c +++ b/scripts/tegra/crypto.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * crypto.c - Cryptography support diff --git a/scripts/tegra/crypto.h b/scripts/tegra/crypto.h index d7151e0cd1..db687d0371 100644 --- a/scripts/tegra/crypto.h +++ b/scripts/tegra/crypto.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /* * crypto.h - Definitions for the crypto support. diff --git a/scripts/tegra/data_layout.c b/scripts/tegra/data_layout.c index ba3361ae65..abfbf6efae 100644 --- a/scripts/tegra/data_layout.c +++ b/scripts/tegra/data_layout.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * data_layout.c - Code to manage the layout of data in the boot device. diff --git a/scripts/tegra/data_layout.h b/scripts/tegra/data_layout.h index 9ee8267a62..002a1ab43e 100644 --- a/scripts/tegra/data_layout.h +++ b/scripts/tegra/data_layout.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /* * data_layout.h - Definitions for the cbootimage data layout code. diff --git a/scripts/tegra/nvaes_ref.h b/scripts/tegra/nvaes_ref.h index 76bd6c3a96..7a7e5ec3bf 100644 --- a/scripts/tegra/nvaes_ref.h +++ b/scripts/tegra/nvaes_ref.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ #include "cbootimage.h" #include "string.h" diff --git a/scripts/tegra/parse.c b/scripts/tegra/parse.c index 464ee8ff40..d861deed17 100644 --- a/scripts/tegra/parse.c +++ b/scripts/tegra/parse.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * parse.c - Parsing support for the cbootimage tool diff --git a/scripts/tegra/parse.h b/scripts/tegra/parse.h index 80f42c4269..2d953bb858 100644 --- a/scripts/tegra/parse.h +++ b/scripts/tegra/parse.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /* * parse.h - Definitions for the cbootimage parsing code. diff --git a/scripts/tegra/set.c b/scripts/tegra/set.c index 91269fc96f..9de879f22e 100644 --- a/scripts/tegra/set.c +++ b/scripts/tegra/set.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * set.c - State setting support for the cbootimage tool diff --git a/scripts/tegra/set.h b/scripts/tegra/set.h index 1515fcd740..0b905fd050 100644 --- a/scripts/tegra/set.h +++ b/scripts/tegra/set.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /* * set.h - Definitions for the cbootimage state setting code. diff --git a/scripts/tegra/t114/nvbctlib_t114.c b/scripts/tegra/t114/nvbctlib_t114.c index f7e449aceb..1085146ee0 100644 --- a/scripts/tegra/t114/nvbctlib_t114.c +++ b/scripts/tegra/t114/nvbctlib_t114.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION #include "../cbootimage.h" #include "../parse.h" @@ -830,7 +814,7 @@ t114_set_sdram_param(build_image_context *context, return 0; } -int +static int t114_getbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -865,7 +849,7 @@ t114_getbl_param(u_int32_t set, return 0; } -int +static int t114_setbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -900,7 +884,7 @@ t114_setbl_param(u_int32_t set, return 0; } -int +static int t114_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -984,7 +968,7 @@ t114_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) return 0; } -int +static int t114_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -1012,7 +996,7 @@ t114_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) return 0; } -int +static int t114_bct_set_data(parse_token id, u_int8_t *data, u_int32_t length, @@ -1037,7 +1021,7 @@ t114_bct_set_data(parse_token id, return 0; } -void t114_init_bad_block_table(build_image_context *context) +static void t114_init_bad_block_table(build_image_context *context) { u_int32_t bytes_per_entry; nvboot_badblock_table *table; diff --git a/scripts/tegra/t114/nvboot_bct_t114.h b/scripts/tegra/t114/nvboot_bct_t114.h index e42d14917c..9b8e20ae4a 100644 --- a/scripts/tegra/t114/nvboot_bct_t114.h +++ b/scripts/tegra/t114/nvboot_bct_t114.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ #ifndef INCLUDED_NVBOOT_BCT_T114_H #define INCLUDED_NVBOOT_BCT_T114_H diff --git a/scripts/tegra/t114/nvboot_sdram_param_t114.h b/scripts/tegra/t114/nvboot_sdram_param_t114.h index 85b758fd74..2f8f0407f1 100644 --- a/scripts/tegra/t114/nvboot_sdram_param_t114.h +++ b/scripts/tegra/t114/nvboot_sdram_param_t114.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /** * Defines the SDRAM parameter structure. diff --git a/scripts/tegra/t114/parse_t114.c b/scripts/tegra/t114/parse_t114.c index 17f612e8c8..0f6d4dbcdd 100644 --- a/scripts/tegra/t114/parse_t114.c +++ b/scripts/tegra/t114/parse_t114.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * parse_t114.h - Definitions for the dev/sdram parameters diff --git a/scripts/tegra/t124/nvbctlib_t124.c b/scripts/tegra/t124/nvbctlib_t124.c index 27e5a628af..9cc312b2e4 100644 --- a/scripts/tegra/t124/nvbctlib_t124.c +++ b/scripts/tegra/t124/nvbctlib_t124.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2013 NVIDIA CORPORATION #include "../cbootimage.h" #include "../parse.h" @@ -831,7 +815,7 @@ t124_set_sdram_param(build_image_context *context, return 0; } -int +static int t124_getbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -866,7 +850,7 @@ t124_getbl_param(u_int32_t set, return 0; } -int +static int t124_setbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -901,7 +885,7 @@ t124_setbl_param(u_int32_t set, return 0; } -int +static int t124_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -985,7 +969,7 @@ t124_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) return 0; } -int +static int t124_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -1013,7 +997,7 @@ t124_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) return 0; } -int +static int t124_bct_set_data(parse_token id, u_int8_t *data, u_int32_t length, @@ -1039,7 +1023,7 @@ t124_bct_set_data(parse_token id, return 0; } -void t124_init_bad_block_table(build_image_context *context) +static void t124_init_bad_block_table(build_image_context *context) { u_int32_t bytes_per_entry; nvboot_badblock_table *table; diff --git a/scripts/tegra/t124/nvboot_bct_t124.h b/scripts/tegra/t124/nvboot_bct_t124.h index 8f4b966c00..479ce97654 100644 --- a/scripts/tegra/t124/nvboot_bct_t124.h +++ b/scripts/tegra/t124/nvboot_bct_t124.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2013 NVIDIA CORPORATION */ #ifndef INCLUDED_NVBOOT_BCT_T124_H #define INCLUDED_NVBOOT_BCT_T124_H diff --git a/scripts/tegra/t124/nvboot_sdram_param_t124.h b/scripts/tegra/t124/nvboot_sdram_param_t124.h index 34f537eb51..46adba519b 100644 --- a/scripts/tegra/t124/nvboot_sdram_param_t124.h +++ b/scripts/tegra/t124/nvboot_sdram_param_t124.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2013 NVIDIA CORPORATION */ /** * Defines the SDRAM parameter structure. diff --git a/scripts/tegra/t124/parse_t124.c b/scripts/tegra/t124/parse_t124.c index 0d80867eea..8a63dd2377 100644 --- a/scripts/tegra/t124/parse_t124.c +++ b/scripts/tegra/t124/parse_t124.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2013, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2013 NVIDIA CORPORATION /* * parse_t124.c - The implementation for parsing dev/sdram parameters diff --git a/scripts/tegra/t20/nvbctlib_t20.c b/scripts/tegra/t20/nvbctlib_t20.c index c145d6da95..972c37befe 100644 --- a/scripts/tegra/t20/nvbctlib_t20.c +++ b/scripts/tegra/t20/nvbctlib_t20.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION #include "../cbootimage.h" #include "../parse.h" @@ -419,7 +403,7 @@ t20_get_sdram_param(build_image_context *context, return 0; } -int +static int t20_getbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -454,7 +438,7 @@ t20_getbl_param(u_int32_t set, return 0; } -int +static int t20_setbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -489,7 +473,7 @@ t20_setbl_param(u_int32_t set, return 0; } -int +static int t20_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -568,7 +552,7 @@ t20_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) return 0; } -int +static int t20_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -596,7 +580,7 @@ t20_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) return 0; } -int +static int t20_bct_set_data(parse_token id, u_int8_t *data, u_int32_t length, @@ -618,7 +602,7 @@ t20_bct_set_data(parse_token id, return 0; } -void t20_init_bad_block_table(build_image_context *context) +static void t20_init_bad_block_table(build_image_context *context) { u_int32_t bytes_per_entry; nvboot_badblock_table *table; diff --git a/scripts/tegra/t20/nvboot_bct_t20.h b/scripts/tegra/t20/nvboot_bct_t20.h index 8585cdb543..97ceeed659 100644 --- a/scripts/tegra/t20/nvboot_bct_t20.h +++ b/scripts/tegra/t20/nvboot_bct_t20.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ #ifndef INCLUDED_NVBOOT_BCT_T20_H #define INCLUDED_NVBOOT_BCT_T20_H diff --git a/scripts/tegra/t20/nvboot_sdram_param_t20.h b/scripts/tegra/t20/nvboot_sdram_param_t20.h index 2c385d5e5e..397397a0cd 100644 --- a/scripts/tegra/t20/nvboot_sdram_param_t20.h +++ b/scripts/tegra/t20/nvboot_sdram_param_t20.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /** * Defines the SDRAM parameter structure. diff --git a/scripts/tegra/t20/parse_t20.c b/scripts/tegra/t20/parse_t20.c index 503257547b..c613ecf85e 100644 --- a/scripts/tegra/t20/parse_t20.c +++ b/scripts/tegra/t20/parse_t20.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * parse_t20.c - Parsing code for t20 diff --git a/scripts/tegra/t30/nvbctlib_t30.c b/scripts/tegra/t30/nvbctlib_t30.c index 59b0246fbf..77c4aceb0a 100644 --- a/scripts/tegra/t30/nvbctlib_t30.c +++ b/scripts/tegra/t30/nvbctlib_t30.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION #include "../cbootimage.h" #include "../parse.h" @@ -626,7 +610,7 @@ t30_set_sdram_param(build_image_context *context, return 0; } -int +static int t30_getbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -661,7 +645,7 @@ t30_getbl_param(u_int32_t set, return 0; } -int +static int t30_setbl_param(u_int32_t set, parse_token id, u_int32_t *data, @@ -696,7 +680,7 @@ t30_setbl_param(u_int32_t set, return 0; } -int +static int t30_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -775,7 +759,7 @@ t30_bct_get_value(parse_token id, u_int32_t *data, u_int8_t *bct) return 0; } -int +static int t30_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) { nvboot_config_table *bct_ptr = (nvboot_config_table *)bct; @@ -803,7 +787,7 @@ t30_bct_set_value(parse_token id, u_int32_t data, u_int8_t *bct) return 0; } -int +static int t30_bct_set_data(parse_token id, u_int8_t *data, u_int32_t length, @@ -825,7 +809,7 @@ t30_bct_set_data(parse_token id, return 0; } -void t30_init_bad_block_table(build_image_context *context) +static void t30_init_bad_block_table(build_image_context *context) { u_int32_t bytes_per_entry; nvboot_badblock_table *table; diff --git a/scripts/tegra/t30/nvboot_bct_t30.h b/scripts/tegra/t30/nvboot_bct_t30.h index 39c998e202..5f4997ed8e 100644 --- a/scripts/tegra/t30/nvboot_bct_t30.h +++ b/scripts/tegra/t30/nvboot_bct_t30.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ #ifndef INCLUDED_NVBOOT_BCT_T30_H #define INCLUDED_NVBOOT_BCT_T30_H diff --git a/scripts/tegra/t30/nvboot_sdram_param_t30.h b/scripts/tegra/t30/nvboot_sdram_param_t30.h index 18d77d7139..fb0dffa0a0 100644 --- a/scripts/tegra/t30/nvboot_sdram_param_t30.h +++ b/scripts/tegra/t30/nvboot_sdram_param_t30.h @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION */ /** * Defines the SDRAM parameter structure. diff --git a/scripts/tegra/t30/parse_t30.c b/scripts/tegra/t30/parse_t30.c index 4715f39f57..bd85a96d12 100644 --- a/scripts/tegra/t30/parse_t30.c +++ b/scripts/tegra/t30/parse_t30.c @@ -1,21 +1,5 @@ -/* - * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * See file CREDITS for list of people who contributed to this - * project. - */ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: 2012 NVIDIA CORPORATION /* * parse_t30.h - Definitions for the dev/sdram parameters 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 a096b834d1..9c1e23ef00 100644 --- a/scripts/zynq_mkimage.c +++ b/scripts/zynq_mkimage.c @@ -1,53 +1,283 @@ -/* - * Copyright (C) 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-FileCopyrightText: 2013 Steffen Trumtrar <s.trumtrar@pengutronix.de> #include <endian.h> #include <errno.h> +#include <getopt.h> +#include <linux/kernel.h> +#include <zynq/zynq-flash-header.h> #include <malloc.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> +#include <sys/types.h> + +static char *prgname; static void usage(char *name) { - printf("Usage: %s barebox-flash-image <outfile>\n", name); + fprintf(stderr, "usage: %s [OPTIONS]\n\n" + "-c <config> configuration input file" + "-f <input> input image file\n" + "-o <output> output file\n" + "-h this help\n", prgname); + exit(1); +} + +#define MAXARGS 16 + +static int parse_line(char *line, char *argv[]) +{ + int nargs = 0; + + while (nargs < MAXARGS) { + + /* skip any white space */ + while ((*line == ' ') || (*line == '\t')) + ++line; + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = NULL; + return nargs; + } + + argv[nargs++] = line; /* begin of argument string */ + + /* find end of string */ + while (*line && (*line != ' ') && (*line != '\t')) + ++line; + + if (*line == '\0') { /* end of line, no more args */ + argv[nargs] = NULL; + return nargs; + } + + *line++ = '\0'; /* terminate current arg */ + } + + printf("** Too many args (max. %d) **\n", MAXARGS); + + return nargs; +} + +struct command { + const char *name; + int (*parse)(char *buf, int argc, char *argv[]); +}; + +static int do_cmd_write_mem(char *buf, int argc, char *argv[]) +{ + unsigned int *wordbuf = (unsigned int *)(buf + REGINIT_OFFSET); + static int reginit_offset; + uint32_t addr, val, width; + char *end; + + if (argc != 4) { + fprintf(stderr, "usage: wm [8|16|32] <addr> <val>\n"); + return -EINVAL; + } + + width = strtoul(argv[1], &end, 0); + if (*end != '\0' || width != 32) { + fprintf(stderr, "illegal width token \"%s\"\n", argv[1]); + return -EINVAL; + } + + addr = strtoul(argv[2], &end, 0); + if (*end != '\0') { + fprintf(stderr, "illegal address token \"%s\"\n", argv[2]); + return -EINVAL; + } + + val = strtoul(argv[3], &end, 0); + if (*end != '\0') { + fprintf(stderr, "illegal value token \"%s\"\n", argv[3]); + return -EINVAL; + } + + wordbuf[reginit_offset] = htole32(addr); + wordbuf[reginit_offset + 1] = htole32(val); + wordbuf[reginit_offset + 1] = htole32(val); + + reginit_offset += 2; + + return 0; +} + +struct command cmds[] = { + { + .name = "wm", + .parse = do_cmd_write_mem, + }, +}; + +static char *readcmd(FILE *f) +{ + static char *buf; + char *str; + ssize_t ret; + + if (!buf) { + buf = malloc(4096); + if (!buf) + return NULL; + } + + str = buf; + *str = 0; + + while (1) { + ret = fread(str, 1, 1, f); + if (!ret) + return strlen(buf) ? buf : NULL; + + if (*str == '\n' || *str == ';') { + *str = 0; + return buf; + } + + str++; + } +} + +static int parse_config(char *buf, const char *filename) +{ + FILE *f; + int lineno = 0; + char *line = NULL, *tmp; + char *argv[MAXARGS]; + int nargs, i, ret = 0; + + f = fopen(filename, "r"); + if (!f) { + fprintf(stderr, "Cannot open config file\n"); + exit(1); + } + + while (1) { + line = readcmd(f); + if (!line) + break; + + lineno++; + + tmp = strchr(line, '#'); + if (tmp) + *tmp = 0; + + nargs = parse_line(line, argv); + if (!nargs) + continue; + + ret = -ENOENT; + + for (i = 0; i < ARRAY_SIZE(cmds); i++) { + if (!strcmp(cmds[i].name, argv[0])) { + ret = cmds[i].parse(buf, nargs, argv); + if (ret) { + fprintf(stderr, "error in line %d: %s\n", + lineno, strerror(-ret)); + goto cleanup; + } + break; + } + } + + if (ret == -ENOENT) { + fprintf(stderr, "no such command: %s\n", argv[0]); + goto cleanup; + } + } + +cleanup: + fclose(f); + return ret; +} + +static void add_header(char *buf, unsigned int image_size) +{ + unsigned int *wordbuf = (unsigned int *)buf; + struct zynq_flash_header flash_header = { + .width_det = WIDTH_DETECTION_MAGIC, + .image_id = IMAGE_IDENTIFICATION, + .enc_stat = 0x0, + .user = 0x0, + .flash_offset = IMAGE_OFFSET, + .length = image_size, + .res0 = 0x0, + .start_of_exec = 0x0, + .total_len = image_size, + .res1 = 0x1, + .checksum = 0x0, + .res2 = 0x0, + }; + int i, sum = 0; + + memcpy(wordbuf + 0x8, &flash_header, sizeof(flash_header)); + + for (i = 0x8; i < 0x12; i++) + sum += htole32(wordbuf[i]); + + sum = ~sum; + wordbuf[i] = sum; } int main(int argc, char *argv[]) { FILE *ifile, *ofile; - unsigned int *buf; - const char *infile; - const char *outfile; + char *buf; + const char *infile = NULL, *outfile = NULL, *cfgfile = NULL; struct stat st; - unsigned int i; - unsigned long sum = 0; + int opt, ret; + + prgname = argv[0]; + + while ((opt = getopt(argc, argv, "c:f:ho:")) != -1) { + switch (opt) { + case 'c': + cfgfile = optarg; + break; + case 'f': + infile = optarg; + break; + case 'o': + outfile = optarg; + break; + case 'h': + usage(argv[0]); + default: + exit(1); + } + } + + if (!infile) { + fprintf(stderr, "input file not given\n"); + exit(1); + } - if (argc != 3) { - usage(argv[0]); + if (!outfile) { + fprintf(stderr, "output file not given\n"); exit(1); } - infile = argv[1]; - outfile = argv[2]; + if (!cfgfile) { + fprintf(stderr, "config file not given\n"); + exit(1); + } if (stat(infile, &st) == -1) { perror("stat"); exit(EXIT_FAILURE); } - buf = malloc(st.st_size); + if (st.st_size > 192 * 1024) { + fprintf(stderr, "Image too big, will not fit in OCRAM!\n"); + exit(EXIT_FAILURE); + } + + buf = calloc(st.st_size + IMAGE_OFFSET, sizeof(char)); if (!buf) { fprintf(stderr, "Unable to allocate buffer\n"); return -1; @@ -68,15 +298,19 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - fread(buf, 4, st.st_size, ifile); + ret = fread(buf + IMAGE_OFFSET, sizeof(char), st.st_size, ifile); - for (i = 0x8; i < 0x12; i++) - sum += htole32(buf[i]); + if(ret != st.st_size) { + fprintf(stderr, "Error while reading %s\n", infile); + exit(EXIT_FAILURE); + } - sum = ~sum; - buf[i] = sum; + add_header(buf, st.st_size); + + if (cfgfile) + parse_config(buf, cfgfile); - fwrite(buf, st.st_size / 4, 4, ofile); + fwrite(buf, sizeof(char), st.st_size + IMAGE_OFFSET, ofile); fclose(ofile); fclose(ifile); |