summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 15:54:21 -0500
committerTimothy Pearson <tpearson@raptorengineering.com>2017-08-23 15:54:21 -0500
commit0223e595f4033e91e93403a7317bcc9e47676b8f (patch)
tree2ccd7127bc343f82456b76eeb0da2d380f6eaf65 /tools
downloadast2050-uboot-0223e595f4033e91e93403a7317bcc9e47676b8f.zip
ast2050-uboot-0223e595f4033e91e93403a7317bcc9e47676b8f.tar.gz
Initial import of modified u-boot tree
Original upstream URL: git://git.denx.de/u-boot.git Original upstream GIT hash: 62c175fbb8a0f9a926c88294ea9f7e88eb898f6c
Diffstat (limited to 'tools')
-rw-r--r--tools/.gitignore21
-rw-r--r--tools/Makefile302
-rw-r--r--tools/aisimage.c450
-rw-r--r--tools/aisimage.h97
-rw-r--r--tools/bddb/README116
-rw-r--r--tools/bddb/badsubmit.php23
-rw-r--r--tools/bddb/bddb.css207
-rw-r--r--tools/bddb/brlog.php109
-rw-r--r--tools/bddb/browse.php147
-rw-r--r--tools/bddb/config.php16
-rw-r--r--tools/bddb/create_tables.sql90
-rw-r--r--tools/bddb/defs.php710
-rw-r--r--tools/bddb/dodelete.php65
-rw-r--r--tools/bddb/dodellog.php57
-rw-r--r--tools/bddb/doedit.php186
-rw-r--r--tools/bddb/doedlog.php76
-rw-r--r--tools/bddb/donew.php230
-rw-r--r--tools/bddb/donewlog.php86
-rw-r--r--tools/bddb/edit.php131
-rw-r--r--tools/bddb/edlog.php86
-rw-r--r--tools/bddb/execute.php33
-rw-r--r--tools/bddb/index.php38
-rw-r--r--tools/bddb/new.php120
-rw-r--r--tools/bddb/newlog.php54
-rw-r--r--tools/bin2header.c56
-rwxr-xr-xtools/binutils-version.sh20
-rw-r--r--tools/bmp_logo.c203
-rw-r--r--tools/buildman/.gitignore1
-rw-r--r--tools/buildman/README679
-rw-r--r--tools/buildman/board.py167
-rw-r--r--tools/buildman/bsettings.py60
-rw-r--r--tools/buildman/builder.py1445
l---------tools/buildman/buildman1
-rwxr-xr-xtools/buildman/buildman.py126
-rw-r--r--tools/buildman/control.py190
-rw-r--r--tools/buildman/test.py185
-rw-r--r--tools/buildman/toolchain.py185
-rwxr-xr-xtools/checkpatch.pl3709
-rwxr-xr-xtools/checkstack.pl171
-rwxr-xr-xtools/cleanpatch258
-rw-r--r--tools/default_image.c150
-rw-r--r--tools/easylogo/Makefile11
-rw-r--r--tools/easylogo/easylogo.c610
-rw-r--r--tools/easylogo/linux_blackfin.tgabin0 -> 158718 bytes
-rw-r--r--tools/easylogo/linux_logo.tgabin0 -> 19244 bytes
-rw-r--r--tools/easylogo/runme.sh4
-rw-r--r--tools/env/Makefile59
-rw-r--r--tools/env/README61
-rw-r--r--tools/env/fw_env.c1336
-rw-r--r--tools/env/fw_env.config22
-rw-r--r--tools/env/fw_env.h79
-rw-r--r--tools/env/fw_env_main.c156
-rw-r--r--tools/envcrc.c145
-rw-r--r--tools/fdt_host.h27
-rw-r--r--tools/fit_image.c222
-rwxr-xr-xtools/gcc-version.sh32
-rw-r--r--tools/gdb/Makefile74
-rw-r--r--tools/gdb/error.c81
-rw-r--r--tools/gdb/error.h30
-rw-r--r--tools/gdb/gdbcont.c87
-rw-r--r--tools/gdb/gdbsend.c137
-rw-r--r--tools/gdb/remote.c928
-rw-r--r--tools/gdb/remote.h28
-rw-r--r--tools/gdb/serial.c149
-rw-r--r--tools/gdb/serial.h34
-rw-r--r--tools/gen_eth_addr.c50
-rw-r--r--tools/getline.c101
-rw-r--r--tools/getline.h1
-rw-r--r--tools/image-host.c713
-rwxr-xr-xtools/img2brec.sh388
-rw-r--r--tools/img2srec.c372
-rw-r--r--tools/imls/Makefile97
-rw-r--r--tools/imls/README57
-rw-r--r--tools/imls/imls.c269
-rw-r--r--tools/imximage.c576
-rw-r--r--tools/imximage.h181
-rwxr-xr-xtools/jtagconsole39
-rw-r--r--tools/kernel-doc/Makefile38
-rw-r--r--tools/kernel-doc/docproc.c576
-rwxr-xr-xtools/kernel-doc/kernel-doc2557
-rw-r--r--tools/kwbimage.c405
-rw-r--r--tools/kwbimage.h106
-rw-r--r--tools/kwboot.c742
-rw-r--r--tools/logos/atmel.bmpbin0 -> 15478 bytes
-rw-r--r--tools/logos/denx.bmpbin0 -> 15538 bytes
-rw-r--r--tools/logos/esd.bmpbin0 -> 35078 bytes
-rw-r--r--tools/logos/freescale.bmpbin0 -> 46738 bytes
-rw-r--r--tools/logos/intercontrol.bmpbin0 -> 4998 bytes
-rw-r--r--tools/logos/linux_logo_ttcontrol.bmpbin0 -> 11830 bytes
-rw-r--r--tools/logos/linux_logo_ttcontrol_palfin.bmpbin0 -> 20534 bytes
-rw-r--r--tools/logos/ronetix.bmpbin0 -> 5638 bytes
-rw-r--r--tools/logos/syteco.bmpbin0 -> 11414 bytes
-rw-r--r--tools/logos/wandboard.bmpbin0 -> 22390 bytes
-rw-r--r--tools/mingw_support.c139
-rw-r--r--tools/mingw_support.h58
-rw-r--r--tools/mkenvimage.c314
-rw-r--r--tools/mkexynosspl.c122
-rw-r--r--tools/mkimage.c664
-rw-r--r--tools/mkimage.h179
-rw-r--r--tools/mpc86x_clk.c218
-rw-r--r--tools/mxsboot.c687
-rw-r--r--tools/ncb.c38
-rwxr-xr-xtools/netconsole63
-rw-r--r--tools/omap/clocks_get_m_n.c202
-rw-r--r--tools/omapimage.c270
-rw-r--r--tools/omapimage.h50
-rw-r--r--tools/os_support.c28
-rw-r--r--tools/os_support.h35
-rw-r--r--tools/palmtreo680/flash_u-boot.c177
-rw-r--r--tools/patman/.gitignore1
-rw-r--r--tools/patman/README472
-rw-r--r--tools/patman/checkpatch.py190
-rw-r--r--tools/patman/command.py117
-rw-r--r--tools/patman/commit.py88
-rw-r--r--tools/patman/cros_subprocess.py397
-rw-r--r--tools/patman/get_maintainer.py63
-rw-r--r--tools/patman/gitutil.py563
-rw-r--r--tools/patman/patchstream.py474
l---------tools/patman/patman1
-rwxr-xr-xtools/patman/patman.py182
-rw-r--r--tools/patman/project.py43
-rw-r--r--tools/patman/series.py283
-rw-r--r--tools/patman/settings.py284
-rw-r--r--tools/patman/terminal.py96
-rw-r--r--tools/patman/test.py274
-rw-r--r--tools/pblimage.c349
-rw-r--r--tools/pblimage.h36
-rw-r--r--tools/proftool.c611
-rw-r--r--tools/scripts/README67
-rw-r--r--tools/scripts/define2mk.sed35
-rw-r--r--tools/scripts/dot.kermrc16
-rw-r--r--tools/scripts/flash_param60
-rwxr-xr-xtools/scripts/make-asm-offsets27
-rw-r--r--tools/scripts/send_cmd21
-rw-r--r--tools/scripts/send_image26
-rwxr-xr-xtools/setlocalversion177
-rw-r--r--tools/ublimage.c280
-rw-r--r--tools/ublimage.h100
-rw-r--r--tools/ubsha1.c100
-rw-r--r--tools/updater/Makefile105
-rw-r--r--tools/updater/cmd_flash.c417
-rw-r--r--tools/updater/ctype.c56
-rw-r--r--tools/updater/dummy.c1
-rw-r--r--tools/updater/flash.c184
-rw-r--r--tools/updater/flash_hw.c659
-rw-r--r--tools/updater/junk1
-rw-r--r--tools/updater/ppcstring.S216
-rw-r--r--tools/updater/string.c340
-rw-r--r--tools/updater/update.c63
-rw-r--r--tools/updater/utils.c148
-rw-r--r--tools/xway-swap-bytes.c38
151 files changed, 33541 insertions, 0 deletions
diff --git a/tools/.gitignore b/tools/.gitignore
new file mode 100644
index 0000000..a7fee26
--- /dev/null
+++ b/tools/.gitignore
@@ -0,0 +1,21 @@
+/bmp_logo
+/envcrc
+/gen_eth_addr
+/img2srec
+/kwboot
+/mkenvimage
+/mkimage
+/mpc86x_clk
+/mxsboot
+/ncb
+/ncp
+/proftool
+/ubsha1
+/xway-swap-bytes
+/*.exe
+/easylogo/easylogo
+/env/crc32.c
+/env/fw_printenv
+/gdb/gdbcont
+/gdb/gdbsend
+/kernel-doc/docproc
diff --git a/tools/Makefile b/tools/Makefile
new file mode 100644
index 0000000..46159b2
--- /dev/null
+++ b/tools/Makefile
@@ -0,0 +1,302 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+TOOLSUBDIRS = kernel-doc
+
+#
+# Include this after HOSTOS HOSTARCH check
+# so that we can act intelligently.
+#
+include $(TOPDIR)/config.mk
+
+#
+# toolchains targeting win32 generate .exe files
+#
+ifneq (,$(findstring WIN32 ,$(shell $(HOSTCC) -E -dM -xc /dev/null)))
+SFX = .exe
+else
+SFX =
+endif
+
+# Enable all the config-independent tools
+ifneq ($(HOST_TOOLS_ALL),)
+CONFIG_LCD_LOGO = y
+CONFIG_CMD_LOADS = y
+CONFIG_CMD_NET = y
+CONFIG_XWAY_SWAP_BYTES = y
+CONFIG_NETCONSOLE = y
+CONFIG_SHA1_CHECK_UB_IMG = y
+endif
+
+# Merge all the different vars for envcrc into one
+ENVCRC-$(CONFIG_ENV_IS_EMBEDDED) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_DATAFLASH) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_EEPROM) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_FLASH) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_ONENAND) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_NAND) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_NVRAM) = y
+ENVCRC-$(CONFIG_ENV_IS_IN_SPI_FLASH) = y
+CONFIG_BUILD_ENVCRC ?= $(ENVCRC-y)
+
+# Generated executable files
+BIN_FILES-$(CONFIG_LCD_LOGO) += bmp_logo$(SFX)
+BIN_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo$(SFX)
+BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
+BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
+BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
+BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
+BIN_FILES-y += mkenvimage$(SFX)
+BIN_FILES-y += mkimage$(SFX)
+BIN_FILES-$(CONFIG_SMDK5250) += mksmdk5250spl$(SFX)
+BIN_FILES-$(CONFIG_MX23) += mxsboot$(SFX)
+BIN_FILES-$(CONFIG_MX28) += mxsboot$(SFX)
+BIN_FILES-$(CONFIG_NETCONSOLE) += ncb$(SFX)
+BIN_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1$(SFX)
+BIN_FILES-$(CONFIG_KIRKWOOD) += kwboot$(SFX)
+BIN_FILES-y += proftool(SFX)
+
+# Source files which exist outside the tools directory
+EXT_OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += common/env_embedded.o
+EXT_OBJ_FILES-y += common/image.o
+EXT_OBJ_FILES-$(CONFIG_FIT) += common/image-fit.o
+EXT_OBJ_FILES-y += common/image-sig.o
+EXT_OBJ_FILES-y += lib/crc32.o
+EXT_OBJ_FILES-y += lib/md5.o
+EXT_OBJ_FILES-y += lib/sha1.o
+
+# Source files located in the tools directory
+OBJ_FILES-$(CONFIG_LCD_LOGO) += bmp_logo.o
+OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
+NOPED_OBJ_FILES-y += default_image.o
+NOPED_OBJ_FILES-y += proftool.o
+OBJ_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc.o
+NOPED_OBJ_FILES-y += fit_image.o
+OBJ_FILES-$(CONFIG_CMD_NET) += gen_eth_addr.o
+OBJ_FILES-$(CONFIG_CMD_LOADS) += img2srec.o
+OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o
+NOPED_OBJ_FILES-y += aisimage.o
+NOPED_OBJ_FILES-y += kwbimage.o
+NOPED_OBJ_FILES-y += pblimage.o
+NOPED_OBJ_FILES-y += imximage.o
+NOPED_OBJ_FILES-y += image-host.o
+NOPED_OBJ_FILES-y += omapimage.o
+NOPED_OBJ_FILES-y += mkenvimage.o
+NOPED_OBJ_FILES-y += mkimage.o
+OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
+OBJ_FILES-$(CONFIG_MX23) += mxsboot.o
+OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
+OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
+NOPED_OBJ_FILES-y += os_support.o
+OBJ_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1.o
+NOPED_OBJ_FILES-y += ublimage.o
+OBJ_FILES-$(CONFIG_KIRKWOOD) += kwboot.o
+
+# Don't build by default
+#ifeq ($(ARCH),ppc)
+#BIN_FILES-y += mpc86x_clk$(SFX)
+#OBJ_FILES-y += mpc86x_clk.o
+#endif
+
+# Flattened device tree objects
+LIBFDT_OBJ_FILES-y += fdt.o
+LIBFDT_OBJ_FILES-y += fdt_ro.o
+LIBFDT_OBJ_FILES-y += fdt_rw.o
+LIBFDT_OBJ_FILES-y += fdt_strerror.o
+LIBFDT_OBJ_FILES-y += fdt_wip.o
+
+# RSA objects
+RSA_OBJ_FILES-$(CONFIG_FIT_SIGNATURE) += rsa-sign.o
+
+# Generated LCD/video logo
+LOGO_H = $(OBJTREE)/include/bmp_logo.h
+LOGO_DATA_H = $(OBJTREE)/include/bmp_logo_data.h
+LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_H)
+LOGO-$(CONFIG_LCD_LOGO) += $(LOGO_DATA_H)
+LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_H)
+LOGO-$(CONFIG_VIDEO_LOGO) += $(LOGO_DATA_H)
+
+# Generic logo
+ifeq ($(LOGO_BMP),)
+LOGO_BMP= logos/denx.bmp
+
+# Use board logo and fallback to vendor
+ifneq ($(wildcard logos/$(BOARD).bmp),)
+LOGO_BMP= logos/$(BOARD).bmp
+else
+ifneq ($(wildcard logos/$(VENDOR).bmp),)
+LOGO_BMP= logos/$(VENDOR).bmp
+endif
+endif
+
+endif # !LOGO_BMP
+
+# now $(obj) is defined
+HOSTSRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
+HOSTSRCS += $(addprefix $(SRCTREE)/lib/rsa/,$(RSA_OBJ_FILES-y:.o=.c))
+BINS := $(addprefix $(obj),$(sort $(BIN_FILES-y)))
+LIBFDT_OBJS := $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
+RSA_OBJS := $(addprefix $(obj),$(RSA_OBJ_FILES-y))
+
+# We cannot check CONFIG_FIT_SIGNATURE here since it is not set on the host
+FIT_SIG_OBJ_FILES := image-sig.o
+FIT_SIG_OBJS := $(addprefix $(obj),$(FIT_SIG_OBJ_FILES))
+
+HOSTOBJS := $(addprefix $(obj),$(OBJ_FILES-y))
+NOPEDOBJS := $(addprefix $(obj),$(NOPED_OBJ_FILES-y))
+
+#
+# Use native tools and options
+# Define __KERNEL_STRICT_NAMES to prevent typedef overlaps
+#
+HOSTCPPFLAGS = -include $(SRCTREE)/include/libfdt_env.h \
+ -idirafter $(SRCTREE)/include \
+ -idirafter $(OBJTREE)/include2 \
+ -idirafter $(OBJTREE)/include \
+ -I $(SRCTREE)/lib/libfdt \
+ -I $(SRCTREE)/tools \
+ -DCONFIG_SYS_TEXT_BASE=$(CONFIG_SYS_TEXT_BASE) \
+ -DUSE_HOSTCC \
+ -D__KERNEL_STRICT_NAMES
+
+
+all: $(obj).depend $(BINS) $(LOGO-y) subdirs
+
+$(obj)bin2header$(SFX): $(obj)bin2header.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)bmp_logo$(SFX): $(obj)bmp_logo.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)proftool(SFX): $(obj)proftool.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)envcrc$(SFX): $(obj)crc32.o $(obj)env_embedded.o $(obj)envcrc.o $(obj)sha1.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)gen_eth_addr$(SFX): $(obj)gen_eth_addr.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)img2srec$(SFX): $(obj)img2srec.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)xway-swap-bytes$(SFX): $(obj)xway-swap-bytes.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)mkenvimage$(SFX): $(obj)crc32.o $(obj)mkenvimage.o \
+ $(obj)os_support.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)mkimage$(SFX): $(obj)aisimage.o \
+ $(obj)crc32.o \
+ $(obj)default_image.o \
+ $(obj)fit_image.o \
+ $(obj)image-fit.o \
+ $(obj)image.o \
+ $(obj)image-host.o \
+ $(FIT_SIG_OBJS) \
+ $(obj)imximage.o \
+ $(obj)kwbimage.o \
+ $(obj)pblimage.o \
+ $(obj)md5.o \
+ $(obj)mkimage.o \
+ $(obj)os_support.o \
+ $(obj)omapimage.o \
+ $(obj)sha1.o \
+ $(obj)ublimage.o \
+ $(LIBFDT_OBJS) \
+ $(RSA_OBJS)
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^ $(HOSTLIBS)
+ $(HOSTSTRIP) $@
+
+$(obj)mk$(BOARD)spl$(SFX): $(obj)mkexynosspl.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)mpc86x_clk$(SFX): $(obj)mpc86x_clk.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)mxsboot$(SFX): $(obj)mxsboot.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)ncb$(SFX): $(obj)ncb.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+$(obj)ubsha1$(SFX): $(obj)os_support.o $(obj)sha1.o $(obj)ubsha1.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)kwboot$(SFX): $(obj)kwboot.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+# Some of the tool objects need to be accessed from outside the tools directory
+$(obj)%.o: $(SRCTREE)/common/%.c
+ $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/%.c
+ $(HOSTCC) -g $(HOSTCFLAGS) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/libfdt/%.c
+ $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/rsa/%.c
+ $(HOSTCC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+subdirs:
+ifeq ($(TOOLSUBDIRS),)
+ @:
+else
+ @for dir in $(TOOLSUBDIRS) ; do \
+ $(MAKE) \
+ HOSTOS=$(HOSTOS) \
+ HOSTARCH=$(HOSTARCH) \
+ -C $$dir || exit 1 ; \
+ done
+endif
+
+$(LOGO_H): $(obj)bmp_logo $(LOGO_BMP)
+ $(obj)./bmp_logo --gen-info $(LOGO_BMP) > $@
+
+$(LOGO_DATA_H): $(obj)bmp_logo $(LOGO_BMP)
+ $(obj)./bmp_logo --gen-data $(LOGO_BMP) > $@
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/aisimage.c b/tools/aisimage.c
new file mode 100644
index 0000000..659df8c
--- /dev/null
+++ b/tools/aisimage.c
@@ -0,0 +1,450 @@
+/*
+ * (C) Copyright 2011
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Required to obtain the getline prototype from stdio.h */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include "aisimage.h"
+#include <image.h>
+
+#define IS_FNC_EXEC(c) (cmd_table[c].AIS_cmd == AIS_CMD_FNLOAD)
+#define WORD_ALIGN0 4
+#define WORD_ALIGN(len) (((len)+WORD_ALIGN0-1) & ~(WORD_ALIGN0-1))
+#define MAX_CMD_BUFFER 4096
+
+static uint32_t ais_img_size;
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t aisimage_cmds[] = {
+ {CMD_DATA, "DATA", "Reg Write Data"},
+ {CMD_FILL, "FILL", "Fill range with pattern"},
+ {CMD_CRCON, "CRCON", "CRC Enable"},
+ {CMD_CRCOFF, "CRCOFF", "CRC Disable"},
+ {CMD_CRCCHECK, "CRCCHECK", "CRC Validate"},
+ {CMD_JMPCLOSE, "JMPCLOSE", "Jump & Close"},
+ {CMD_JMP, "JMP", "Jump"},
+ {CMD_SEQREAD, "SEQREAD", "Sequential read"},
+ {CMD_PLL0, "PLL0", "PLL0"},
+ {CMD_PLL1, "PLL1", "PLL1"},
+ {CMD_CLK, "CLK", "Clock configuration"},
+ {CMD_DDR2, "DDR2", "DDR2 Configuration"},
+ {CMD_EMIFA, "EMIFA", "EMIFA"},
+ {CMD_EMIFA_ASYNC, "EMIFA_ASYNC", "EMIFA Async"},
+ {CMD_PLL, "PLL", "PLL & Clock configuration"},
+ {CMD_PSC, "PSC", "PSC setup"},
+ {CMD_PINMUX, "PINMUX", "Pinmux setup"},
+ {CMD_BOOTTABLE, "BOOT_TABLE", "Boot table command"},
+ {-1, "", ""},
+};
+
+static struct ais_func_exec {
+ uint32_t index;
+ uint32_t argcnt;
+} ais_func_table[] = {
+ [CMD_PLL0] = {0, 2},
+ [CMD_PLL1] = {1, 2},
+ [CMD_CLK] = {2, 1},
+ [CMD_DDR2] = {3, 8},
+ [CMD_EMIFA] = {4, 5},
+ [CMD_EMIFA_ASYNC] = {5, 5},
+ [CMD_PLL] = {6, 3},
+ [CMD_PSC] = {7, 1},
+ [CMD_PINMUX] = {8, 3}
+};
+
+static struct cmd_table_t {
+ uint32_t nargs;
+ uint32_t AIS_cmd;
+} cmd_table[] = {
+ [CMD_FILL] = { 4, AIS_CMD_FILL},
+ [CMD_CRCON] = { 0, AIS_CMD_ENCRC},
+ [CMD_CRCOFF] = { 0, AIS_CMD_DISCRC},
+ [CMD_CRCCHECK] = { 2, AIS_CMD_ENCRC},
+ [CMD_JMPCLOSE] = { 1, AIS_CMD_JMPCLOSE},
+ [CMD_JMP] = { 1, AIS_CMD_JMP},
+ [CMD_SEQREAD] = { 0, AIS_CMD_SEQREAD},
+ [CMD_PLL0] = { 2, AIS_CMD_FNLOAD},
+ [CMD_PLL1] = { 2, AIS_CMD_FNLOAD},
+ [CMD_CLK] = { 1, AIS_CMD_FNLOAD},
+ [CMD_DDR2] = { 8, AIS_CMD_FNLOAD},
+ [CMD_EMIFA] = { 5, AIS_CMD_FNLOAD},
+ [CMD_EMIFA_ASYNC] = { 5, AIS_CMD_FNLOAD},
+ [CMD_PLL] = { 3, AIS_CMD_FNLOAD},
+ [CMD_PSC] = { 1, AIS_CMD_FNLOAD},
+ [CMD_PINMUX] = { 3, AIS_CMD_FNLOAD},
+ [CMD_BOOTTABLE] = { 4, AIS_CMD_BOOTTBL},
+};
+
+static uint32_t get_cfg_value(char *token, char *name, int linenr)
+{
+ char *endptr;
+ uint32_t value;
+
+ errno = 0;
+ value = strtoul(token, &endptr, 16);
+ if (errno || (token == endptr)) {
+ fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+ name, linenr, token);
+ exit(EXIT_FAILURE);
+ }
+ return value;
+}
+
+static int get_ais_table_id(uint32_t *ptr)
+{
+
+ int i;
+ int func_no;
+
+ for (i = 0; i < ARRAY_SIZE(cmd_table); i++) {
+ if (*ptr == cmd_table[i].AIS_cmd) {
+ if (cmd_table[i].AIS_cmd != AIS_CMD_FNLOAD)
+ return i;
+
+ func_no = ((struct ais_cmd_func *)ptr)->func_args
+ & 0xFFFF;
+ if (func_no == ais_func_table[i].index)
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void aisimage_print_header(const void *hdr)
+{
+ struct ais_header *ais_hdr = (struct ais_header *)hdr;
+ uint32_t *ptr;
+ struct ais_cmd_load *ais_load;
+ int id;
+
+ if (ais_hdr->magic != AIS_MAGIC_WORD) {
+ fprintf(stderr, "Error: - AIS Magic Number not found\n");
+ return;
+ }
+ fprintf(stdout, "Image Type: TI Davinci AIS Boot Image\n");
+ fprintf(stdout, "AIS magic : %08x\n", ais_hdr->magic);
+ ptr = (uint32_t *)&ais_hdr->magic;
+ ptr++;
+
+ while (*ptr != AIS_CMD_JMPCLOSE) {
+ /* Check if we find the image */
+ if (*ptr == AIS_CMD_LOAD) {
+ ais_load = (struct ais_cmd_load *)ptr;
+ fprintf(stdout, "Image at : 0x%08x size 0x%08x\n",
+ ais_load->addr,
+ ais_load->size);
+ ptr = ais_load->data + ais_load->size / sizeof(*ptr);
+ continue;
+ }
+
+ id = get_ais_table_id(ptr);
+ if (id < 0) {
+ fprintf(stderr, "Error: - AIS Image corrupted\n");
+ return;
+ }
+ fprintf(stdout, "AIS cmd : %s\n",
+ get_table_entry_name(aisimage_cmds, NULL, id));
+ ptr += cmd_table[id].nargs + IS_FNC_EXEC(id) + 1;
+ if (((void *)ptr - hdr) > ais_img_size) {
+ fprintf(stderr,
+ "AIS Image not terminated by JMPCLOSE\n");
+ return;
+ }
+ }
+}
+
+static uint32_t *ais_insert_cmd_header(uint32_t cmd, uint32_t nargs,
+ uint32_t *parms, struct image_type_params *tparams,
+ uint32_t *ptr)
+{
+ int i;
+
+ *ptr++ = cmd_table[cmd].AIS_cmd;
+ if (IS_FNC_EXEC(cmd))
+ *ptr++ = ((nargs & 0xFFFF) << 16) + ais_func_table[cmd].index;
+
+ /* Copy parameters */
+ for (i = 0; i < nargs; i++)
+ *ptr++ = cpu_to_le32(parms[i]);
+
+ return ptr;
+
+}
+
+static uint32_t *ais_alloc_buffer(struct mkimage_params *params)
+{
+ int dfd;
+ struct stat sbuf;
+ char *datafile = params->datafile;
+ uint32_t *ptr;
+
+ dfd = open(datafile, O_RDONLY|O_BINARY);
+ if (dfd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ params->cmdname, datafile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (fstat(dfd, &sbuf) < 0) {
+ fprintf(stderr, "%s: Can't stat %s: %s\n",
+ params->cmdname, datafile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Place for header is allocated. The size is taken from
+ * the size of the datafile, that the ais_image_generate()
+ * will copy into the header. Copying the datafile
+ * is not left to the main program, because after the datafile
+ * the header must be terminated with the Jump & Close command.
+ */
+ ais_img_size = WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER;
+ ptr = (uint32_t *)malloc(WORD_ALIGN(sbuf.st_size) + MAX_CMD_BUFFER);
+ if (!ptr) {
+ fprintf(stderr, "%s: malloc return failure: %s\n",
+ params->cmdname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ close(dfd);
+
+ return ptr;
+}
+
+static uint32_t *ais_copy_image(struct mkimage_params *params,
+ uint32_t *aisptr)
+
+{
+ int dfd;
+ struct stat sbuf;
+ char *datafile = params->datafile;
+ void *ptr;
+
+ dfd = open(datafile, O_RDONLY|O_BINARY);
+ if (dfd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ params->cmdname, datafile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (fstat(dfd, &sbuf) < 0) {
+ fprintf(stderr, "%s: Can't stat %s: %s\n",
+ params->cmdname, datafile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+ *aisptr++ = AIS_CMD_LOAD;
+ *aisptr++ = params->ep;
+ *aisptr++ = sbuf.st_size;
+ memcpy((void *)aisptr, ptr, sbuf.st_size);
+ aisptr += WORD_ALIGN(sbuf.st_size) / sizeof(uint32_t);
+
+ (void) munmap((void *)ptr, sbuf.st_size);
+ (void) close(dfd);
+
+ return aisptr;
+
+}
+
+static int aisimage_generate(struct mkimage_params *params,
+ struct image_type_params *tparams)
+{
+ FILE *fd = NULL;
+ char *line = NULL;
+ char *token, *saveptr1, *saveptr2;
+ int lineno = 0;
+ int fld;
+ size_t len;
+ int32_t cmd;
+ uint32_t nargs, cmd_parms[10];
+ uint32_t value, size;
+ char *name = params->imagename;
+ uint32_t *aishdr;
+
+ fd = fopen(name, "r");
+ if (fd == 0) {
+ fprintf(stderr,
+ "Error: %s - Can't open AIS configuration\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * the size of the header is variable and is computed
+ * scanning the configuration file.
+ */
+ tparams->header_size = 0;
+
+ /*
+ * Start allocating a buffer suitable for most command
+ * The buffer is then reallocated if it is too small
+ */
+ aishdr = ais_alloc_buffer(params);
+ tparams->hdr = aishdr;
+ *aishdr++ = AIS_MAGIC_WORD;
+
+ /* Very simple parsing, line starting with # are comments
+ * and are dropped
+ */
+ while ((getline(&line, &len, fd)) > 0) {
+ lineno++;
+
+ token = strtok_r(line, "\r\n", &saveptr1);
+ if (token == NULL)
+ continue;
+
+ /* Check inside the single line */
+ line = token;
+ fld = CFG_COMMAND;
+ cmd = CMD_INVALID;
+ nargs = 0;
+ while (token != NULL) {
+ token = strtok_r(line, " \t", &saveptr2);
+ if (token == NULL)
+ break;
+
+ /* Drop all text starting with '#' as comments */
+ if (token[0] == '#')
+ break;
+
+ switch (fld) {
+ case CFG_COMMAND:
+ cmd = get_table_entry_id(aisimage_cmds,
+ "aisimage commands", token);
+ if (cmd < 0) {
+ fprintf(stderr,
+ "Error: %s[%d] - Invalid command"
+ "(%s)\n", name, lineno, token);
+
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case CFG_VALUE:
+ value = get_cfg_value(token, name, lineno);
+ cmd_parms[nargs++] = value;
+ if (nargs > cmd_table[cmd].nargs) {
+ fprintf(stderr,
+ "Error: %s[%d] - too much arguments:"
+ "(%s) for command %s\n", name,
+ lineno, token,
+ aisimage_cmds[cmd].sname);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ }
+ line = NULL;
+ fld = CFG_VALUE;
+ }
+ if (cmd != CMD_INVALID) {
+ /* Now insert the command into the header */
+ aishdr = ais_insert_cmd_header(cmd, nargs, cmd_parms,
+ tparams, aishdr);
+ }
+
+ }
+ fclose(fd);
+
+ aishdr = ais_copy_image(params, aishdr);
+
+ /* Add Jmp & Close */
+ *aishdr++ = AIS_CMD_JMPCLOSE;
+ *aishdr++ = params->ep;
+
+ size = (aishdr - (uint32_t *)tparams->hdr) * sizeof(uint32_t);
+ tparams->header_size = size;
+
+ return 0;
+}
+
+static int aisimage_check_image_types(uint8_t type)
+{
+ if (type == IH_TYPE_AISIMAGE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static int aisimage_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct ais_header *ais_hdr = (struct ais_header *)ptr;
+
+ if (ais_hdr->magic != AIS_MAGIC_WORD)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ /* Store the total size to remember in print_hdr */
+ ais_img_size = image_size;
+
+ return 0;
+}
+
+static void aisimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+}
+
+int aisimage_check_params(struct mkimage_params *params)
+{
+ if (!params)
+ return CFG_INVALID;
+ if (!strlen(params->imagename)) {
+ fprintf(stderr, "Error: %s - Configuration file not specified, "
+ "it is needed for aisimage generation\n",
+ params->cmdname);
+ return CFG_INVALID;
+ }
+ /*
+ * Check parameters:
+ * XIP is not allowed and verify that incompatible
+ * parameters are not sent at the same time
+ * For example, if list is required a data image must not be provided
+ */
+ return (params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)) ||
+ (params->xflag) || !(strlen(params->imagename));
+}
+
+/*
+ * aisimage parameters
+ */
+static struct image_type_params aisimage_params = {
+ .name = "TI Davinci AIS Boot Image support",
+ .header_size = 0,
+ .hdr = NULL,
+ .check_image_type = aisimage_check_image_types,
+ .verify_header = aisimage_verify_header,
+ .print_header = aisimage_print_header,
+ .set_header = aisimage_set_header,
+ .check_params = aisimage_check_params,
+ .vrec_header = aisimage_generate,
+};
+
+void init_ais_image_type(void)
+{
+ mkimage_register(&aisimage_params);
+}
diff --git a/tools/aisimage.h b/tools/aisimage.h
new file mode 100644
index 0000000..a6372b8
--- /dev/null
+++ b/tools/aisimage.h
@@ -0,0 +1,97 @@
+/*
+ * (C) Copyright 2011
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _AISIMAGE_H_
+#define _AISIMAGE_H_
+
+/* all values are for little endian systems */
+#define AIS_MAGIC_WORD 0x41504954
+#define AIS_FCN_MAX 8
+
+enum {
+ AIS_CMD_LOAD = 0x58535901,
+ AIS_CMD_VALCRC = 0x58535902,
+ AIS_CMD_ENCRC = 0x58535903,
+ AIS_CMD_DISCRC = 0x58535904,
+ AIS_CMD_JMP = 0x58535905,
+ AIS_CMD_JMPCLOSE = 0x58535906,
+ AIS_CMD_BOOTTBL = 0x58535907,
+ AIS_CMD_FILL = 0x5853590A,
+ AIS_CMD_FNLOAD = 0x5853590D,
+ AIS_CMD_SEQREAD = 0x58535963,
+};
+
+struct ais_cmd_load {
+ uint32_t cmd;
+ uint32_t addr;
+ uint32_t size;
+ uint32_t data[1];
+};
+
+struct ais_cmd_func {
+ uint32_t cmd;
+ uint32_t func_args;
+ uint32_t parms[AIS_FCN_MAX];
+};
+
+struct ais_cmd_jmpclose {
+ uint32_t cmd;
+ uint32_t addr;
+};
+
+#define CMD_DATA_STR "DATA"
+
+enum ais_file_cmd {
+ CMD_INVALID,
+ CMD_FILL,
+ CMD_CRCON,
+ CMD_CRCOFF,
+ CMD_CRCCHECK,
+ CMD_JMPCLOSE,
+ CMD_JMP,
+ CMD_SEQREAD,
+ CMD_DATA,
+ CMD_PLL0,
+ CMD_PLL1,
+ CMD_CLK,
+ CMD_DDR2,
+ CMD_EMIFA,
+ CMD_EMIFA_ASYNC,
+ CMD_PLL,
+ CMD_PSC,
+ CMD_PINMUX,
+ CMD_BOOTTABLE
+};
+
+enum aisimage_fld_types {
+ CFG_INVALID = -1,
+ CFG_COMMAND,
+ CFG_VALUE,
+};
+
+struct ais_header {
+ uint32_t magic;
+ char data[1];
+};
+
+#endif /* _AISIMAGE_H_ */
diff --git a/tools/bddb/README b/tools/bddb/README
new file mode 100644
index 0000000..9bee59a
--- /dev/null
+++ b/tools/bddb/README
@@ -0,0 +1,116 @@
+Hymod Board Database
+
+(C) Copyright 2001
+Murray Jensen <Murray.Jensen@csiro.au>
+CSIRO Manufacturing Science and Technology, Preston Lab
+
+25-Jun-01
+
+This stuff is a set of PHP/MySQL scripts to implement a custom board
+database. It will need *extensive* hacking to modify it to keep the
+information about your custom boards that you want, however it is a good
+starting point.
+
+How it is used:
+
+ 1. a board has gone through all the hardware testing etc and is
+ ready to have the flash programmed for the first time - first you
+ go to a web page and fill in information about the board in a form
+ to register it in a database
+
+ 2. the web stuff allocates a (unique) serial number and (optionally)
+ a (locally administered) ethernet address and stores the information
+ in a database using the serial number as the key (can do whole
+ batches of boards in one go and/or use a previously registered board
+ as defaults for the new board(s))
+
+ 3. it then creates a file in the tftp area of a server somewhere
+ containing the board information in a simple text format (one
+ per serial number)
+
+ 4. all hymod boards have an i2c eeprom, and when U-Boot sees that
+ the eeprom is unitialised, it prompts for a serial number and
+ ethernet address (if not set), then transfers the file created
+ in step 3 from the server and initialises the eeprom from its
+ contents
+
+What this means is you can't boot the board until you have allocated a serial
+number, but you don't have to type it all twice - you do it once on the web
+and the board then finds the info it needs to initialise its eeprom. The
+other side of the coin is the reading of the eeprom and how it gets passed
+to Linux (or another O/S).
+
+To see how this is all done for the hymod boards look at the code in the
+"board/hymod" directory and in the file "include/asm/hymod.h". Hymod boards
+can have a mezzanine card which also have an eeprom that needs allocating,
+the same process is used for these as well - just a different i2c address.
+
+Other forms provide the following functions:
+
+ - browsing the board database
+ - editing board information (one at a time)
+ - maintaining/browsing a (simple) per board event log
+
+You will need: MySQL (I use version 3.23.7-alpha), PHP4 (with MySQL
+support enabled) and a web server (I use Apache 1.3.x).
+
+I originally started by using phpMyBuilder (http://kyber.dk/phpMyBuilder)
+but it soon got far more complicated than that could handle (but I left
+the copyright messages in there anyway). Most of the code resides in the
+common defs.php file, which shouldn't need much alteration - all the work
+will be in shaping the front-end php files to your liking.
+
+Here's a quick summary of what needs doing to use it for your boards:
+
+1. get phpMyAdmin (http://phpwizard.net/projects/phpMyAdmin/) - it's an
+ invaluable tool for this sort of stuff (this step is optional of course)
+
+2. edit "bddb.css" to your taste, if you could be bothered - I have no
+ idea what is in there or what it does - I copied it from somewhere else
+ ("user.css" from the phpMyEdit (http://phpmyedit.sourcerforge.net) package,
+ I think) - I figure one day I'll see what sort of things I can change
+ in there.
+
+3. create a mysql database - call it whatever you like
+
+4. edit "create_tables.sql" and modify the "boards" table schema to
+ reflect the information you want to keep about your boards. It may or
+ may not be easier to do this and the next step in phpMyAdmin. Check out
+ the MySQL documentation at http://www.mysql.com/doc/ in particular the
+ column types at http://www.mysql.com/doc/C/o/Column_types.html - Note
+ there is only support for a few data types:
+
+ int - presented as an html text input
+ char/text - presented as an html text input
+ date - presented as an html text input
+ enum - presented as an html radio input
+
+ I also have what I call "enum_multi" which is a set of enums with the
+ same name, but suffixed with a number e.g. fred0, fred1, fred2. These
+ are presented as a number of html select's with a single label "fred"
+ this is useful for board characteristics that have multiple items of
+ the same type e.g. multiple banks of sdram.
+
+5. use the "create_tables.sql" file to create the "boards" table in the
+ database e.g. mysql dbname < create_tables.sql
+
+6. create a user and password for the web server to log into the MySQL
+ database with; give this user select, insert and update privileges
+ to the database created in 3 (and delete, if you want the "delete"
+ functions in the edit forms to work- I have this turned off). phpMyAdmin
+ helps in this step.
+
+7. edit "config.php" and set the variables: $mysql_user, $mysql_pw, $mysql_db,
+ $bddb_cfgdir and $bddb_label - keep the contents of this file secret - it
+ contains the web servers username and password (the three $mysql_* vars
+ are set from the previous step)
+
+8. edit "defs.php" and a. adjust the various enum value arrays and b. edit
+ the function "pg_foot()" to remove my email address :-)
+
+9. do major hacking on the following files: browse.php, doedit.php, donew.php,
+ edit.php and new.php to reflect your database schema - fortunately the
+ hacking is fairly straight-forward, but it is boring and time-consuming.
+
+These notes were written rather hastily - if you find any obvious problems
+please let me know.
diff --git a/tools/bddb/badsubmit.php b/tools/bddb/badsubmit.php
new file mode 100644
index 0000000..5092a31
--- /dev/null
+++ b/tools/bddb/badsubmit.php
@@ -0,0 +1,23 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ require("defs.php");
+ pg_head("$bddb_label - Unknown Submit Type");
+?>
+<center>
+ <font size="+4">
+ <b>
+ The <?php echo "$bddb_label"; ?> form was submitted with an
+ unknown SUBMIT type <?php echo "(value was '$submit')" ?>.
+ <br></br>
+ Perhaps you typed the URL in directly? Click here to go to the
+ home page of the <a href="index.php"><?php echo "$bddb_label"; ?></a>.
+ </b>
+ </font>
+</center>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/bddb.css b/tools/bddb/bddb.css
new file mode 100644
index 0000000..dee2b2e
--- /dev/null
+++ b/tools/bddb/bddb.css
@@ -0,0 +1,207 @@
+BODY {
+ background: #e0ffff;
+ color: #000000;
+ font-family: Arial, Verdana, Helvetica;
+}
+H1 {
+ font-family: "Copperplate Gothic Bold";
+ background: transparent;
+ color: #993300;
+ text-align: center;
+}
+H2, H3, H4, H5 {
+ background: transparent;
+ color: #993300;
+ margin-top: 4%;
+ text-align: center;
+}
+Body.Plain Div.Abstract, Body.Plain P.Abstract {
+ background: #cccc99;
+ color: #333300;
+ border: white;
+ padding: 3%;
+ font-family: Times, Verdana;
+}
+TH.Nav {
+ background: #0000cc;
+ color: #ff9900;
+}
+TH.Menu {
+ background: #3366cc;
+ color: #ff9900;
+}
+A:hover {
+ color: #ff6600;
+}
+A.Menu:hover {
+ color: #ff6600;
+}
+A.HoMe:hover {
+ color: #ff6600;
+}
+A.Menu {
+ background: transparent;
+ color: #ffcc33;
+ font-family: Verdana, Helvetica, Arial;
+ font-size: smaller;
+ text-decoration: none;
+}
+A.Menu:visited {
+ background: transparent;
+ color: #ffcc99;
+}
+A.HoMe {
+ background: transparent;
+ color: #ffcc33;
+ font-family: Verdana, Helvetica, Arial;
+ text-decoration:none;
+}
+A.HoMe:visited {
+ background: transparent;
+ color: #ffcc99;
+}
+TH.Xmp {
+ background: #eeeeee;
+ color: #330066;
+ font-family: courier;
+ font-weight: normal;
+}
+TH.LuT {
+ background: #cccccc;
+ color: #000000;
+}
+TD.LuT {
+ background: #ffffcc;
+ color: #000000;
+ font-size: 85%;
+}
+TH.Info, TD.Info {
+ background: #ffffcc;
+ color: #660000;
+ font-family: "Comic Sans MS", Cursive, Verdana;
+ font-size: smaller;
+}
+Div.Info, P.Info {
+ background: #ffff99;
+ color: #990033;
+ text-align: left;
+ padding: 2%;
+ font-family: "Comic Sans MS", Cursive, Verdana;
+ font-size: 85%;
+ }
+Div.Info A {
+ background: transparent;
+ color: #ff6600;
+}
+.HL {
+ background: #ffff99;
+ color: #000000;
+}
+TD.HL {
+ background: #ccffff;
+ color: #000000;
+}
+Div.Margins {
+ width: 512px;
+ text-align: center;
+}
+TD.Plain {
+ background: #ffffcc;
+ color: #000033;
+}
+.Type {
+ background: #cccccc;
+ color: #660000;
+}
+.Name {
+ background: #eeeeee;
+ color: #660000;
+ vertical-align: top;
+ text-align: right;
+}
+.Value {
+ background: #ffffee;
+ color: #000066;
+}
+.Drop {
+ background: #333366;
+ color: #ffcc33;
+ font-family: "Copperplate Gothic Light", Helvetica, Verdana, Arial;
+}
+A.Button:hover {
+ color: #ff6600;
+}
+A.Button {
+ text-decoration:none;
+ color: #003366;
+ background: #ffcc66;
+}
+.Button {
+ font-size: 9pt;
+ text-align: center;
+ text-decoration:none;
+ color: #003366;
+ background: #ffcc66;
+ margin-bottom: 2pt;
+ border-top: 2px solid #ffff99;
+ border-left: 2px solid #ffff99;
+ border-right: 2px solid #cc9933;
+ border-bottom: 2px solid #cc9933;
+ font-family: Verdana, Arial, "Comic Sans MS";
+}
+.Banner {
+ width: 468;
+ font-size: 12pt;
+ text-align: center;
+ text-decoration:none;
+ color: #003366;
+ background: #ffcc66;
+ border-top: 4px solid #ffff99;
+ border-left: 4px solid #ffff99;
+ border-right: 4px solid #cc9933;
+ border-bottom: 4px solid #cc9933;
+ font-family: Verdana, Arial, "Comic Sans MS";
+}
+TD.Nova, Body.Nova {
+ background: #000000;
+ font-family: "Times New Roman";
+ font-weight: light;
+ color: #ffcc00;
+}
+Body.Nova A.Button {
+ background: gold;
+ color: #003366;
+}
+Body.Nova A.Banner {
+ background: transparent;
+ color: #003366;
+}
+Body.Nova A {
+ background: transparent;
+ text-decoration:none;
+ color: #ffd766;
+}
+Body.Nova H1, Body.Nova H2, Body.Nova H3, Body.Nova H4 {
+ background: transparent;
+ color: white;
+ margin-top: 4%;
+ text-align: center;
+ filter: Blur(Add=1, Direction=0, Strength=8);
+}
+Body.Nova Div.Abstract {
+ background: #000000;
+ color: #ffffff;
+ font-family: Times, Verdana;
+}
+Body.Nova A.Abstract {
+ background: transparent;
+ color: #ffeedd;
+}
+Body.Nova TH.LuT {
+ background: black;
+ color: #ffff99;
+}
+Body.Nova TD.LuT {
+ background: navy;
+ color: #ffff99;
+}
diff --git a/tools/bddb/brlog.php b/tools/bddb/brlog.php
new file mode 100644
index 0000000..fccfbd0
--- /dev/null
+++ b/tools/bddb/brlog.php
@@ -0,0 +1,109 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // list page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Browse Board Log");
+
+ $serno=intval($serno);
+ if ($serno == 0)
+ die("serial number not specified or invalid!");
+
+ function print_cell($str) {
+ if ($str == '')
+ $str = '&nbsp;';
+ echo "\t<td>$str</td>\n";
+ }
+?>
+<table align=center border=1 cellpadding=10>
+<tr>
+<th>serno / edit</th>
+<th>ethaddr</th>
+<th>date</th>
+<th>batch</th>
+<th>type</th>
+<th>rev</th>
+<th>location</th>
+</tr>
+<?php
+ $r=mysql_query("select * from boards where serno=$serno");
+
+ while($row=mysql_fetch_array($r)){
+ foreach ($columns as $key) {
+ if (!key_in_array($key, $row))
+ $row[$key] = '';
+ }
+
+ echo "<tr>\n";
+ print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>");
+ print_cell($row['ethaddr']);
+ print_cell($row['date']);
+ print_cell($row['batch']);
+ print_cell($row['type']);
+ print_cell($row['rev']);
+ print_cell($row['location']);
+ echo "</tr>\n";
+ }
+
+ mysql_free_result($r);
+?>
+</table>
+<hr></hr>
+<p></p>
+<?php
+ $limit=abs(isset($_REQUEST['limit'])?$_REQUEST['limit']:20);
+ $offset=abs(isset($_REQUEST['offset'])?$_REQUEST['offset']:0);
+ $lr=mysql_query("select count(*) as n from log where serno=$serno");
+ $lrow=mysql_fetch_array($lr);
+ if($lrow['n']>$limit){
+ $preoffset=max(0,$offset-$limit);
+ $postoffset=$offset+$limit;
+ echo "<table width=\"100%\">\n<tr align=center>\n";
+ printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\"&lt;\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset);
+ printf("<td><%sa href=\"%s?submit=Log&serno=$serno&offset=%d\"><img border=0 alt=\"&gt;\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset);
+ echo "</tr>\n</table>\n";
+ }
+ mysql_free_result($lr);
+?>
+<table width="100%" border=1 cellpadding=10>
+<tr valign=top>
+<th>logno / edit</th>
+<th>date</th>
+<th>who</th>
+<th width="70%">details</th>
+</tr>
+<?php
+ $r=mysql_query("select * from log where serno=$serno order by logno limit $offset,$limit");
+
+ while($row=mysql_fetch_array($r)){
+ echo "<tr>\n";
+ print_cell("<a href=\"edlog.php?serno=$row[serno]&logno=$row[logno]\">$row[logno]</a>");
+ print_cell($row['date']);
+ print_cell($row['who']);
+ print_cell("<pre>" . urldecode($row['details']) . "</pre>");
+ echo "</tr>\n";
+ }
+
+ mysql_free_result($r);
+?>
+</table>
+<hr></hr>
+<p></p>
+<table width="100%">
+<tr>
+ <td align=center>
+ <a href="newlog.php?serno=<?php echo "$serno"; ?>">Add to Log</a>
+ </td>
+ <td align=center>
+ <a href="index.php">Back to Start</a>
+ </td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/browse.php b/tools/bddb/browse.php
new file mode 100644
index 0000000..675dfab
--- /dev/null
+++ b/tools/bddb/browse.php
@@ -0,0 +1,147 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // list page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ $serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:'';
+
+ $verbose=isset($_REQUEST['verbose'])?intval($_REQUEST['verbose']):0;
+
+ pg_head("$bddb_label - Browse database" . ($verbose?" (verbose)":""));
+?>
+<p></p>
+<?php
+ $limit=isset($_REQUEST['limit'])?abs(intval($_REQUEST['limit'])):20;
+ $offset=isset($_REQUEST['offset'])?abs(intval($_REQUEST['offset'])):0;
+
+ if ($serno == '') {
+
+ $lr=mysql_query("select count(*) as n from boards");
+ $lrow=mysql_fetch_array($lr);
+
+ if($lrow['n']>$limit){
+ $preoffset=max(0,$offset-$limit);
+ $postoffset=$offset+$limit;
+ echo "<table width=\"100%\">\n<tr>\n";
+ printf("<td align=left><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\"&lt;\" src=\"/icons/left.gif\"></a></td>\n", $offset>0?"":"no", $PHP_SELF, $preoffset, $verbose);
+ printf("<td align=right><%sa href=\"%s?submit=Browse&offset=%d&verbose=%d\"><img border=0 alt=\"&gt;\" src=\"/icons/right.gif\"></a></td>\n", $postoffset<$lrow['n']?"":"no", $PHP_SELF, $postoffset, $offset);
+ echo "</tr>\n</table>\n";
+ }
+
+ mysql_free_result($lr);
+ }
+?>
+<table align=center border=1 cellpadding=10>
+<tr>
+<th></th>
+<th>serno / edit</th>
+<th>ethaddr</th>
+<th>date</th>
+<th>batch</th>
+<th>type</th>
+<th>rev</th>
+<th>location</th>
+<?php
+ if ($verbose) {
+ echo "<th>comments</th>\n";
+ echo "<th>sdram</th>\n";
+ echo "<th>flash</th>\n";
+ echo "<th>zbt</th>\n";
+ echo "<th>xlxtyp</th>\n";
+ echo "<th>xlxspd</th>\n";
+ echo "<th>xlxtmp</th>\n";
+ echo "<th>xlxgrd</th>\n";
+ echo "<th>cputyp</th>\n";
+ echo "<th>cpuspd</th>\n";
+ echo "<th>cpmspd</th>\n";
+ echo "<th>busspd</th>\n";
+ echo "<th>hstype</th>\n";
+ echo "<th>hschin</th>\n";
+ echo "<th>hschout</th>\n";
+ }
+?>
+</tr>
+<?php
+ $query = "select * from boards";
+ if ($serno != '') {
+ $pre = " where ";
+ foreach (preg_split("/[\s,]+/", $serno) as $s) {
+ if (preg_match('/^[0-9]+$/',$s))
+ $query .= $pre . "serno=" . $s;
+ else if (preg_match('/^([0-9]+)-([0-9]+)$/',$s,$m)) {
+ $m1 = intval($m[1]); $m2 = intval($m[2]);
+ if ($m2 <= $m1)
+ die("bad serial number range ($s)");
+ $query .= $pre . "(serno>=$m[1] and serno<=$m[2])";
+ }
+ else
+ die("illegal serial number ($s)");
+ $pre = " or ";
+ }
+ }
+ $query .= " order by serno";
+ if ($serno == '')
+ $query .= " limit $offset,$limit";
+
+ $r = mysql_query($query);
+
+ function print_cell($str) {
+ if ($str == '')
+ $str = '&nbsp;';
+ echo "\t<td>$str</td>\n";
+ }
+
+ while($row=mysql_fetch_array($r)){
+ foreach ($columns as $key) {
+ if (!key_in_array($key, $row))
+ $row[$key] = '';
+ }
+
+ echo "<tr>\n";
+ print_cell("<a href=\"brlog.php?serno=$row[serno]\">Log</a>");
+ print_cell("<a href=\"edit.php?serno=$row[serno]\">$row[serno]</a>");
+ print_cell($row['ethaddr']);
+ print_cell($row['date']);
+ print_cell($row['batch']);
+ print_cell($row['type']);
+ print_cell($row['rev']);
+ print_cell($row['location']);
+ if ($verbose) {
+ print_cell("<pre>\n" . urldecode($row['comments']) .
+ "\n\t</pre>");
+ print_cell(gather_enum_multi_print("sdram", 4, $row));
+ print_cell(gather_enum_multi_print("flash", 4, $row));
+ print_cell(gather_enum_multi_print("zbt", 16, $row));
+ print_cell(gather_enum_multi_print("xlxtyp", 4, $row));
+ print_cell(gather_enum_multi_print("xlxspd", 4, $row));
+ print_cell(gather_enum_multi_print("xlxtmp", 4, $row));
+ print_cell(gather_enum_multi_print("xlxgrd", 4, $row));
+ print_cell($row['cputyp']);
+ print_cell($row['cpuspd']);
+ print_cell($row['cpmspd']);
+ print_cell($row['busspd']);
+ print_cell($row['hstype']);
+ print_cell($row['hschin']);
+ print_cell($row['hschout']);
+ }
+ echo "</tr>\n";
+ }
+?>
+</table>
+<p></p>
+<table width="100%">
+<tr>
+ <td align=center><?php
+ printf("<a href=\"%s?submit=Browse&offset=%d&verbose=%d%s\">%s Listing</a>\n", $PHP_SELF, $offset, $verbose?0:1, $serno!=''?"&serno=$serno":'', $verbose?"Terse":"Verbose");
+ ?></td>
+ <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/config.php b/tools/bddb/config.php
new file mode 100644
index 0000000..6725757
--- /dev/null
+++ b/tools/bddb/config.php
@@ -0,0 +1,16 @@
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // mysql database access info
+ $mysql_user="fred";
+ $mysql_pw="apassword";
+ $mysql_db="mydbname";
+
+ // where to put the eeprom config files
+ $bddb_cfgdir = '/tftpboot/bddb';
+
+ // what this database is called
+ $bddb_label = 'Hymod Board Database';
+?>
diff --git a/tools/bddb/create_tables.sql b/tools/bddb/create_tables.sql
new file mode 100644
index 0000000..a2a5788
--- /dev/null
+++ b/tools/bddb/create_tables.sql
@@ -0,0 +1,90 @@
+# phpMyAdmin MySQL-Dump
+# http://phpwizard.net/phpMyAdmin/
+#
+# Host: localhost Database : hymod_bddb
+
+# (C) Copyright 2001
+# Murray Jensen <Murray.Jensen@csiro.au>
+# CSIRO Manufacturing and Infrastructure Technology, Preston Lab
+
+# --------------------------------------------------------
+#
+# Table structure for table 'boards'
+#
+
+DROP TABLE IF EXISTS boards;
+CREATE TABLE boards (
+ serno int(10) unsigned zerofill NOT NULL auto_increment,
+ ethaddr char(17),
+ date date NOT NULL,
+ batch char(32),
+ type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY') NOT NULL,
+ rev tinyint(3) unsigned zerofill NOT NULL,
+ location char(64),
+ comments text,
+ sdram0 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+ sdram1 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+ sdram2 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+ sdram3 enum('32M','64M','128M','256M','512M','1G','2G','4G'),
+ flash0 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+ flash1 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+ flash2 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+ flash3 enum('4M','8M','16M','32M','64M','128M','256M','512M','1G'),
+ zbt0 enum('512K','1M','2M','4M','8M','16M'),
+ zbt1 enum('512K','1M','2M','4M','8M','16M'),
+ zbt2 enum('512K','1M','2M','4M','8M','16M'),
+ zbt3 enum('512K','1M','2M','4M','8M','16M'),
+ zbt4 enum('512K','1M','2M','4M','8M','16M'),
+ zbt5 enum('512K','1M','2M','4M','8M','16M'),
+ zbt6 enum('512K','1M','2M','4M','8M','16M'),
+ zbt7 enum('512K','1M','2M','4M','8M','16M'),
+ zbt8 enum('512K','1M','2M','4M','8M','16M'),
+ zbt9 enum('512K','1M','2M','4M','8M','16M'),
+ zbta enum('512K','1M','2M','4M','8M','16M'),
+ zbtb enum('512K','1M','2M','4M','8M','16M'),
+ zbtc enum('512K','1M','2M','4M','8M','16M'),
+ zbtd enum('512K','1M','2M','4M','8M','16M'),
+ zbte enum('512K','1M','2M','4M','8M','16M'),
+ zbtf enum('512K','1M','2M','4M','8M','16M'),
+ xlxtyp0 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+ xlxtyp1 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+ xlxtyp2 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+ xlxtyp3 enum('XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140'),
+ xlxspd0 enum('6','7','8','4','5','9','10','11','12'),
+ xlxspd1 enum('6','7','8','4','5','9','10','11','12'),
+ xlxspd2 enum('6','7','8','4','5','9','10','11','12'),
+ xlxspd3 enum('6','7','8','4','5','9','10','11','12'),
+ xlxtmp0 enum('COM','IND'),
+ xlxtmp1 enum('COM','IND'),
+ xlxtmp2 enum('COM','IND'),
+ xlxtmp3 enum('COM','IND'),
+ xlxgrd0 enum('NORMAL','ENGSAMP'),
+ xlxgrd1 enum('NORMAL','ENGSAMP'),
+ xlxgrd2 enum('NORMAL','ENGSAMP'),
+ xlxgrd3 enum('NORMAL','ENGSAMP'),
+ cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560'),
+ cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+ cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+ busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ'),
+ hstype enum('AMCC-S2064A','Xilinx-Rockets'),
+ hschin enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'),
+ hschout enum('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16'),
+ PRIMARY KEY (serno),
+ KEY serno (serno),
+ UNIQUE serno_2 (serno)
+);
+
+#
+# Table structure for table 'log'
+#
+
+DROP TABLE IF EXISTS log;
+CREATE TABLE log (
+ logno int(10) unsigned zerofill NOT NULL auto_increment,
+ serno int(10) unsigned zerofill NOT NULL,
+ date date NOT NULL,
+ details text NOT NULL,
+ PRIMARY KEY (logno),
+ KEY logno (logno, serno, date),
+ UNIQUE logno_2 (logno)
+);
diff --git a/tools/bddb/defs.php b/tools/bddb/defs.php
new file mode 100644
index 0000000..b7518e3
--- /dev/null
+++ b/tools/bddb/defs.php
@@ -0,0 +1,710 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // contains mysql user id and password - keep secret
+ require("config.php");
+
+ if (isset($_REQUEST['logout'])) {
+ Header("status: 401 Unauthorized");
+ Header("HTTP/1.0 401 Unauthorized");
+ Header("WWW-authenticate: basic realm=\"$bddb_label\"");
+
+ echo "<html><head><title>" .
+ "Access to '$bddb_label' Denied" .
+ "</title></head>\n";
+ echo "<body bgcolor=#ffffff><br></br><br></br><center><h1>" .
+ "You must be an Authorised User " .
+ "to access the '$bddb_label'" .
+ "</h1>\n</center></body></html>\n";
+ exit;
+ }
+
+ // contents of the various enumerated types - if first item is
+ // empty ('') then the enum is allowed to be null (ie "not null"
+ // is not set on the column)
+
+ // all column names in the database table
+ $columns = array(
+ 'serno','ethaddr','date','batch',
+ 'type','rev','location','comments',
+ 'sdram0','sdram1','sdram2','sdram3',
+ 'flash0','flash1','flash2','flash3',
+ 'zbt0','zbt1','zbt2','zbt3','zbt4','zbt5','zbt6','zbt7',
+ 'zbt8','zbt9','zbta','zbtb','zbtc','zbtd','zbte','zbtf',
+ 'xlxtyp0','xlxtyp1','xlxtyp2','xlxtyp3',
+ 'xlxspd0','xlxspd1','xlxspd2','xlxspd3',
+ 'xlxtmp0','xlxtmp1','xlxtmp2','xlxtmp3',
+ 'xlxgrd0','xlxgrd1','xlxgrd2','xlxgrd3',
+ 'cputyp','cpuspd','cpmspd','busspd',
+ 'hstype','hschin','hschout'
+ );
+
+ // board type
+ $type_vals = array('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY');
+
+ // Xilinx fpga types
+ $xlxtyp_vals = array('','XCV300E','XCV400E','XCV600E','XC2V2000','XC2V3000','XC2V4000','XC2V6000','XC2VP2','XC2VP4','XC2VP7','XC2VP20','XC2VP30','XC2VP50','XC4VFX20','XC4VFX40','XC4VFX60','XC4VFX100','XC4VFX140');
+
+ // Xilinx fpga speeds
+ $xlxspd_vals = array('','6','7','8','4','5','9','10','11','12');
+
+ // Xilinx fpga temperatures (commercial or industrial)
+ $xlxtmp_vals = array('','COM','IND');
+
+ // Xilinx fpga grades (normal or engineering sample)
+ $xlxgrd_vals = array('','NORMAL','ENGSAMP');
+
+ // CPU types
+ $cputyp_vals = array('','MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)','MPC8560');
+
+ // CPU/BUS/CPM clock speeds
+ $clk_vals = array('','33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ','300MHZ','333MHZ','366MHZ','400MHZ','433MHZ','466MHZ','500MHZ','533MHZ','566MHZ','600MHZ','633MHZ','666MHZ','700MHZ','733MHZ','766MHZ','800MHZ','833MHZ','866MHZ','900MHZ','933MHZ','966MHZ','1000MHZ','1033MHZ','1066MHZ','1100MHZ','1133MHZ','1166MHZ','1200MHZ','1233MHZ','1266MHZ','1300MHZ','1333MHZ');
+
+ // sdram sizes (nbits array is for eeprom config file)
+ $sdram_vals = array('','32M','64M','128M','256M','512M','1G','2G','4G');
+ $sdram_nbits = array(0,25,26,27,28,29,30,31,32);
+
+ // flash sizes (nbits array is for eeprom config file)
+ $flash_vals = array('','4M','8M','16M','32M','64M','128M','256M','512M','1G');
+ $flash_nbits = array(0,22,23,24,25,26,27,28,29,30);
+
+ // zbt ram sizes (nbits array is for write into eeprom config file)
+ $zbt_vals = array('','512K','1M','2M','4M','8M','16M');
+ $zbt_nbits = array(0,19,20,21,22,23,24);
+
+ // high-speed serial attributes
+ $hstype_vals = array('','AMCC-S2064A','Xilinx-Rockets');
+ $hschin_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16');
+ $hschout_vals = array('0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16');
+
+ // value filters - used when outputting html
+ function rev_filter($num) {
+ if ($num == 0)
+ return "001";
+ else
+ return sprintf("%03d", $num);
+ }
+
+ function text_filter($str) {
+ return urldecode($str);
+ }
+
+ mt_srand(time() | getmypid());
+
+ // set up MySQL connection
+ mysql_connect("", $mysql_user, $mysql_pw) || die("cannot connect");
+ mysql_select_db($mysql_db) || die("cannot select db");
+
+ // page header
+ function pg_head($title)
+ {
+ echo "<html>\n<head>\n";
+ echo "<link rel=stylesheet href=\"bddb.css\" type=\"text/css\" title=\"style sheet\"></link>\n";
+ echo "<title>$title</title>\n";
+ echo "</head>\n";
+ echo "<body>\n";
+ echo "<center><h1>$title</h1></center>\n";
+ echo "<hr></hr>\n";
+ }
+
+ // page footer
+ function pg_foot()
+ {
+ echo "<hr></hr>\n";
+ echo "<table width=\"100%\"><tr><td align=left>\n<address>" .
+ "If you have any problems, email " .
+ "<a href=\"mailto:Murray.Jensen@csiro.au\">" .
+ "Murray Jensen" .
+ "</a></address>\n" .
+ "</td><td align=right>\n" .
+ "<a href=\"index.php?logout=true\">logout</a>\n" .
+ "</td></tr></table>\n";
+ echo "<p><small><i>Made with " .
+ "<a href=\"http://kyber.dk/phpMyBuilder/\">" .
+ "Kyber phpMyBuilder</a></i></small></p>\n";
+ echo "</body>\n";
+ echo "</html>\n";
+ }
+
+ // some support functions
+
+ if (!function_exists('array_search')) {
+
+ function array_search($needle, $haystack, $strict = false) {
+
+ if (is_array($haystack) && count($haystack)) {
+
+ $ntype = gettype($needle);
+
+ foreach ($haystack as $key => $value) {
+
+ if ($value == $needle && (!$strict ||
+ gettype($value) == $ntype))
+ return $key;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ if (!function_exists('in_array')) {
+
+ function in_array($needle, $haystack, $strict = false) {
+
+ if (is_array($haystack) && count($haystack)) {
+
+ $ntype = gettype($needle);
+
+ foreach ($haystack as $key => $value) {
+
+ if ($value == $needle && (!$strict ||
+ gettype($value) == $ntype))
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ function key_in_array($key, $array) {
+ return in_array($key, array_keys($array), true);
+ }
+
+ function enum_to_index($name, $vals) {
+ $index = array_search($GLOBALS[$name], $vals);
+ if ($vals[0] != '')
+ $index++;
+ return $index;
+ }
+
+ // fetch a value from an array - return empty string is not present
+ function get_key_value($key, $array) {
+ if (key_in_array($key, $array))
+ return $array[$key];
+ else
+ return '';
+ }
+
+ function fprintf() {
+ $n = func_num_args();
+ if ($n < 2)
+ return FALSE;
+ $a = func_get_args();
+ $fp = array_shift($a);
+ $x = "\$s = sprintf";
+ $sep = '(';
+ foreach ($a as $z) {
+ $x .= "$sep'$z'";
+ $sep = ',';
+ }
+ $x .= ');';
+ eval($x);
+ $l = strlen($s);
+ $r = fwrite($fp, $s, $l);
+ if ($r != $l)
+ return FALSE;
+ else
+ return TRUE;
+ }
+
+ // functions to display (print) a database table and its columns
+
+ function begin_table($ncols) {
+ global $table_ncols;
+ $table_ncols = $ncols;
+ echo "<table align=center width=\"100%\""
+ . " border=1 cellpadding=4 cols=$table_ncols>\n";
+ }
+
+ function begin_field($name, $span = 0) {
+ global $table_ncols;
+ echo "<tr valign=top>\n";
+ echo "\t<th align=center>$name</th>\n";
+ if ($span <= 0)
+ $span = $table_ncols - 1;
+ if ($span > 1)
+ echo "\t<td colspan=$span>\n";
+ else
+ echo "\t<td>\n";
+ }
+
+ function cont_field($span = 1) {
+ echo "\t</td>\n";
+ if ($span > 1)
+ echo "\t<td colspan=$span>\n";
+ else
+ echo "\t<td>\n";
+ }
+
+ function end_field() {
+ echo "\t</td>\n";
+ echo "</tr>\n";
+ }
+
+ function end_table() {
+ echo "</table>\n";
+ }
+
+ function print_field($name, $array, $size = 0, $filt='') {
+
+ begin_field($name);
+
+ if (key_in_array($name, $array))
+ $value = $array[$name];
+ else
+ $value = '';
+
+ if ($filt != '')
+ $value = $filt($value);
+
+ echo "\t\t<input name=$name value=\"$value\"";
+ if ($size > 0)
+ echo " size=$size maxlength=$size";
+ echo "></input>\n";
+
+ end_field();
+ }
+
+ function print_field_multiline($name, $array, $cols, $rows, $filt='') {
+
+ begin_field($name);
+
+ if (key_in_array($name, $array))
+ $value = $array[$name];
+ else
+ $value = '';
+
+ if ($filt != '')
+ $value = $filt($value);
+
+ echo "\t\t<textarea name=$name " .
+ "cols=$cols rows=$rows wrap=off>\n";
+ echo "$value";
+ echo "</textarea>\n";
+
+ end_field();
+ }
+
+ // print a mysql ENUM as an html RADIO INPUT
+ function print_enum($name, $array, $vals, $def = -1) {
+
+ begin_field($name);
+
+ if (key_in_array($name, $array))
+ $chk = array_search($array[$name], $vals, FALSE);
+ else
+ $chk = $def;
+
+ $nval = count($vals);
+
+ for ($i = 0; $i < $nval; $i++) {
+
+ $val = $vals[$i];
+ if ($val == '')
+ $pval = "none";
+ else
+ $pval = "$val";
+
+ printf("\t\t<input type=radio name=$name"
+ . " value=\"$val\"%s>$pval</input>\n",
+ $i == $chk ? " checked" : "");
+ }
+
+ end_field();
+ }
+
+ // print a mysql ENUM as an html SELECT INPUT
+ function print_enum_select($name, $array, $vals, $def = -1) {
+
+ begin_field($name);
+
+ echo "\t\t<select name=$name>\n";
+
+ if (key_in_array($name, $array))
+ $chk = array_search($array[$name], $vals, FALSE);
+ else
+ $chk = $def;
+
+ $nval = count($vals);
+
+ for ($i = 0; $i < $nval; $i++) {
+
+ $val = $vals[$i];
+ if ($val == '')
+ $pval = "none";
+ else
+ $pval = "$val";
+
+ printf("\t\t\t<option " .
+ "value=\"%s\"%s>%s</option>\n",
+ $val, $i == $chk ? " selected" : "", $pval);
+ }
+
+ echo "\t\t</select>\n";
+
+ end_field();
+ }
+
+ // print a group of mysql ENUMs (e.g. name0,name1,...) as an html SELECT
+ function print_enum_multi($base, $array, $vals, $cnt, $defs, $grp = 0) {
+
+ global $table_ncols;
+
+ if ($grp <= 0)
+ $grp = $cnt;
+ $ncell = $cnt / $grp;
+ $span = ($table_ncols - 1) / $ncell;
+
+ begin_field($base, $span);
+
+ $nval = count($vals);
+
+ for ($i = 0; $i < $cnt; $i++) {
+
+ if ($i > 0 && ($i % $grp) == 0)
+ cont_field($span);
+
+ $name = sprintf("%s%x", $base, $i);
+
+ echo "\t\t<select name=$name>\n";
+
+ if (key_in_array($name, $array))
+ $ai = array_search($array[$name], $vals, FALSE);
+ else {
+ if (key_in_array($i, $defs))
+ $ai = $defs[$i];
+ else
+ $ai = 0;
+ }
+
+ for ($j = 0; $j < $nval; $j++) {
+
+ $val = $vals[$j];
+ if ($val == '')
+ $pval = "&nbsp;";
+ else
+ $pval = "$val";
+
+ printf("\t\t\t<option " .
+ "value=\"%s\"%s>%s</option>\n",
+ $val,
+ $j == $ai ? " selected" : "",
+ $pval);
+ }
+
+ echo "\t\t</select>\n";
+ }
+
+ end_field();
+ }
+
+ // functions to handle the form input
+
+ // fetch all the parts of an "enum_multi" into a string suitable
+ // for a MySQL query
+ function gather_enum_multi_query($base, $cnt) {
+
+ $retval = '';
+
+ for ($i = 0; $i < $cnt; $i++) {
+
+ $name = sprintf("%s%x", $base, $i);
+
+ if (isset($_REQUEST[$name])) {
+ $retval .= sprintf(", %s='%s'",
+ $name, $_REQUEST[$name]);
+ }
+ }
+
+ return $retval;
+ }
+
+ // fetch all the parts of an "enum_multi" into a string suitable
+ // for a display e.g. in an html table cell
+ function gather_enum_multi_print($base, $cnt, $array) {
+
+ $retval = '';
+
+ for ($i = 0; $i < $cnt; $i++) {
+
+ $name = sprintf("%s%x", $base, $i);
+
+ if ($array[$name] != '') {
+ if ($retval != '')
+ $retval .= ',';
+ $retval .= $array[$name];
+ }
+ }
+
+ return $retval;
+ }
+
+ // fetch all the parts of an "enum_multi" into a string suitable
+ // for writing to the eeprom data file
+ function gather_enum_multi_write($base, $cnt, $vals, $xfrm = array()) {
+
+ $retval = '';
+
+ for ($i = 0; $i < $cnt; $i++) {
+
+ $name = sprintf("%s%x", $base, $i);
+
+ if ($GLOBALS[$name] != '') {
+ if ($retval != '')
+ $retval .= ',';
+ $index = enum_to_index($name, $vals);
+ if ($xfrm != array())
+ $retval .= $xfrm[$index];
+ else
+ $retval .= $index;
+ }
+ }
+
+ return $retval;
+ }
+
+ // count how many parts of an "enum_multi" are actually set
+ function count_enum_multi($base, $cnt) {
+
+ $retval = 0;
+
+ for ($i = 0; $i < $cnt; $i++) {
+
+ $name = sprintf("%s%x", $base, $i);
+
+ if (isset($_REQUEST[$name]))
+ $retval++;
+ }
+
+ return $retval;
+ }
+
+ // ethernet address functions
+
+ // generate a (possibly not unique) random vendor ethernet address
+ // (setting bit 6 in the ethernet address - motorola wise i.e. bit 0
+ // is the most significant bit - means it is not an assigned ethernet
+ // address - it is a "locally administered" address). Also, make sure
+ // it is NOT a multicast ethernet address (by setting bit 7 to 0).
+ // e.g. the first byte of all ethernet addresses generated here will
+ // have 2 in the bottom two bits (incidentally, these are the first
+ // two bits transmitted on the wire, since the octets in ethernet
+ // addresses are transmitted LSB first).
+
+ function gen_eth_addr($serno) {
+
+ $ethaddr_hgh = (mt_rand(0, 65535) & 0xfeff) | 0x0200;
+ $ethaddr_mid = mt_rand(0, 65535);
+ $ethaddr_low = mt_rand(0, 65535);
+
+ return sprintf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx",
+ $ethaddr_hgh >> 8, $ethaddr_hgh & 0xff,
+ $ethaddr_mid >> 8, $ethaddr_mid & 0xff,
+ $ethaddr_low >> 8, $ethaddr_low & 0xff);
+ }
+
+ // check that an ethernet address is valid
+ function eth_addr_is_valid($ethaddr) {
+
+ $ethbytes = split(':', $ethaddr);
+
+ if (count($ethbytes) != 6)
+ return FALSE;
+
+ for ($i = 0; $i < 6; $i++) {
+ $ethbyte = $ethbytes[$i];
+ if (!ereg('^[0-9a-f][0-9a-f]$', $ethbyte))
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ // write a simple eeprom configuration file
+ function write_eeprom_cfg_file() {
+
+ global $sernos, $nsernos, $bddb_cfgdir, $numerrs, $cfgerrs;
+ global $date, $batch, $type_vals, $rev;
+ global $sdram_vals, $sdram_nbits;
+ global $flash_vals, $flash_nbits;
+ global $zbt_vals, $zbt_nbits;
+ global $xlxtyp_vals, $xlxspd_vals, $xlxtmp_vals, $xlxgrd_vals;
+ global $cputyp, $cputyp_vals, $clk_vals;
+ global $hstype, $hstype_vals, $hschin, $hschout;
+
+ $numerrs = 0;
+ $cfgerrs = array();
+
+ for ($i = 0; $i < $nsernos; $i++) {
+
+ $serno = sprintf("%010d", $sernos[$i]);
+
+ $wfp = @fopen($bddb_cfgdir . "/$serno.cfg", "w");
+ if (!$wfp) {
+ $cfgerrs[$i] = 'file create fail';
+ $numerrs++;
+ continue;
+ }
+ set_file_buffer($wfp, 0);
+
+ if (!fprintf($wfp, "serno=%d\n", $sernos[$i])) {
+ $cfgerrs[$i] = 'cfg wr fail (serno)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+
+ if (!fprintf($wfp, "date=%s\n", $date)) {
+ $cfgerrs[$i] = 'cfg wr fail (date)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+
+ if ($batch != '') {
+ if (!fprintf($wfp, "batch=%s\n", $batch)) {
+ $cfgerrs[$i] = 'cfg wr fail (batch)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $typei = enum_to_index("type", $type_vals);
+ if (!fprintf($wfp, "type=%d\n", $typei)) {
+ $cfgerrs[$i] = 'cfg wr fail (type)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+
+ if (!fprintf($wfp, "rev=%d\n", $rev)) {
+ $cfgerrs[$i] = 'cfg wr fail (rev)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+
+ $s = gather_enum_multi_write("sdram", 4,
+ $sdram_vals, $sdram_nbits);
+ if ($s != '') {
+ $b = fprintf($wfp, "sdram=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (sdram)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("flash", 4,
+ $flash_vals, $flash_nbits);
+ if ($s != '') {
+ $b = fprintf($wfp, "flash=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (flash)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("zbt", 16,
+ $zbt_vals, $zbt_nbits);
+ if ($s != '') {
+ $b = fprintf($wfp, "zbt=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (zbt)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("xlxtyp", 4, $xlxtyp_vals);
+ if ($s != '') {
+ $b = fprintf($wfp, "xlxtyp=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (xlxtyp)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("xlxspd", 4, $xlxspd_vals);
+ if ($s != '') {
+ $b = fprintf($wfp, "xlxspd=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (xlxspd)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("xlxtmp", 4, $xlxtmp_vals);
+ if ($s != '') {
+ $b = fprintf($wfp, "xlxtmp=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (xlxtmp)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ $s = gather_enum_multi_write("xlxgrd", 4, $xlxgrd_vals);
+ if ($s != '') {
+ $b = fprintf($wfp, "xlxgrd=%s\n", $s);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (xlxgrd)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ if ($cputyp != '') {
+ $cputypi = enum_to_index("cputyp",$cputyp_vals);
+ $cpuspdi = enum_to_index("cpuspd", $clk_vals);
+ $busspdi = enum_to_index("busspd", $clk_vals);
+ $cpmspdi = enum_to_index("cpmspd", $clk_vals);
+ $b = fprintf($wfp, "cputyp=%d\ncpuspd=%d\n" .
+ "busspd=%d\ncpmspd=%d\n",
+ $cputypi, $cpuspdi, $busspdi, $cpmspdi);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (cputyp)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ if ($hstype != '') {
+ $hstypei = enum_to_index("hstype",$hstype_vals);
+ $b = fprintf($wfp, "hstype=%d\n" .
+ "hschin=%s\nhschout=%s\n",
+ $hstypei, $hschin, $hschout);
+ if (!$b) {
+ $cfgerrs[$i] = 'cfg wr fail (hstype)';
+ fclose($wfp);
+ $numerrs++;
+ continue;
+ }
+ }
+
+ if (!fclose($wfp)) {
+ $cfgerrs[$i] = 'file cls fail';
+ $numerrs++;
+ }
+ }
+
+ return $numerrs;
+ }
+?>
diff --git a/tools/bddb/dodelete.php b/tools/bddb/dodelete.php
new file mode 100644
index 0000000..4839e36
--- /dev/null
+++ b/tools/bddb/dodelete.php
@@ -0,0 +1,65 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // dodelete page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Delete Board Results");
+
+ if (!isset($_REQUEST['serno']))
+ die("the board serial number was not specified");
+ $serno=intval($_REQUEST['serno']);
+
+ mysql_query("delete from boards where serno=$serno");
+
+ if(mysql_errno()) {
+ $errstr = mysql_error();
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $errstr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+ else {
+ echo "\t<font size=+2>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe board with serial number <b>$serno</b> was"
+ . " successfully deleted\n";
+ mysql_query("delete from log where serno=$serno");
+ if (mysql_errno()) {
+ $errstr = mysql_error();
+ echo "\t\t\t<font size=+4>\n";
+ echo "\t\t\t\t<p>\n";
+ echo "\t\t\t\t\tBut the following error occurred " .
+ "when deleting the log entries:\n";
+ echo "\t\t\t\t</p>\n";
+ echo "\t\t\t\t<center>\n";
+ printf("\t\t\t\t\t<b>%s</b>\n", $errstr);
+ echo "\t\t\t\t</center>\n";
+ echo "\t\t\t</font>\n";
+ }
+ echo "\t\t</p>\n";
+ echo "\t</font>\n";
+ }
+?>
+<p>
+<table width="100%">
+<tr>
+ <td align=center>
+ <a href="browse.php">Back to Browse</a>
+ </td>
+ <td align=center>
+ <a href="index.php">Back to Start</a>
+ </td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/dodellog.php b/tools/bddb/dodellog.php
new file mode 100644
index 0000000..9dd78c1
--- /dev/null
+++ b/tools/bddb/dodellog.php
@@ -0,0 +1,57 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // dodelete page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Delete Log Entry Results");
+
+ if (!isset($_REQUEST['serno']))
+ die("the board serial number was not specified");
+ $serno=intval($_REQUEST['serno']);
+
+ if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == 0)
+ die("the log entry number not specified!");
+ $logno=$_REQUEST['logno'];
+
+ mysql_query("delete from log where serno=$serno and logno=$logno");
+
+ if(mysql_errno()) {
+ $errstr = mysql_error();
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $errstr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+ else {
+ echo "\t<font size=+2>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe log entry with log number <b>$logno</b>\n";
+ echo "\t\t\tand serial number <b>$serno</b> ";
+ echo "was successfully deleted\n";
+ echo "\t\t</p>\n";
+ echo "\t</font>\n";
+ }
+?>
+<p>
+<table width="100%">
+<tr>
+ <td align=center>
+ <a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a>
+ </td>
+ <td align=center>
+ <a href="index.php">Back to Start</a>
+ </td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/doedit.php b/tools/bddb/doedit.php
new file mode 100644
index 0000000..13fbb69
--- /dev/null
+++ b/tools/bddb/doedit.php
@@ -0,0 +1,186 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // doedit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Edit Board Results");
+
+ if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+ die("the board serial number was not specified");
+ $serno=intval($_REQUEST['serno']);
+
+ $query="update boards set";
+
+ if (isset($_REQUEST['ethaddr'])) {
+ $ethaddr=$_REQUEST['ethaddr'];
+ if (!eth_addr_is_valid($ethaddr))
+ die("ethaddr is invalid ('$ethaddr')");
+ $query.=" ethaddr='$ethaddr',";
+ }
+
+ if (isset($_REQUEST['date'])) {
+ $date=$_REQUEST['date'];
+ list($y, $m, $d) = split("-", $date);
+ if (!checkdate($m, $d, $y) || $y < 1999)
+ die("date is invalid (input '$date', " .
+ "yyyy-mm-dd '$y-$m-$d')");
+ $query.=" date='$date'";
+ }
+
+ if (isset($_REQUEST['batch'])) {
+ $batch=$_REQUEST['batch'];
+ if (strlen($batch) > 32)
+ die("batch field too long (>32)");
+ $query.=", batch='$batch'";
+ }
+
+ if (isset($_REQUEST['type'])) {
+ $type=$_REQUEST['type'];
+ if (!in_array($type, $type_vals))
+ die("Invalid type ($type) specified");
+ $query.=", type='$type'";
+ }
+
+ if (isset($_REQUEST['rev'])) {
+ $rev=$_REQUEST['rev'];
+ if (($rev = intval($rev)) <= 0 || $rev > 255)
+ die("Revision number is invalid ($rev)");
+ $query.=sprintf(", rev=%d", $rev);
+ }
+
+ if (isset($_REQUEST['location'])) {
+ $location=$_REQUEST['location'];
+ if (strlen($location) > 64)
+ die("location field too long (>64)");
+ $query.=", location='$location'";
+ }
+
+ if (isset($_REQUEST['comments']))
+ $comments=$_REQUEST['comments'];
+ $query.=", comments='" . rawurlencode($comments) . "'";
+
+ $query.=gather_enum_multi_query("sdram", 4);
+
+ $query.=gather_enum_multi_query("flash", 4);
+
+ $query.=gather_enum_multi_query("zbt", 16);
+
+ $query.=gather_enum_multi_query("xlxtyp", 4);
+ $nxlx = count_enum_multi("xlxtyp", 4);
+
+ $query.=gather_enum_multi_query("xlxspd", 4);
+ if (count_enum_multi("xlxspd", 4) != $nxlx)
+ die("number of xilinx speeds not same as number of types");
+
+ $query.=gather_enum_multi_query("xlxtmp", 4);
+ if (count_enum_multi("xlxtmp", 4) != $nxlx)
+ die("number of xilinx temps. not same as number of types");
+
+ $query.=gather_enum_multi_query("xlxgrd", 4);
+ if (count_enum_multi("xlxgrd", 4) != $nxlx)
+ die("number of xilinx grades not same as number of types");
+
+ if (isset($_REQUEST['cputyp'])) {
+ $cputyp=$_REQUEST['cputyp'];
+ $query.=", cputyp='$cputyp'";
+ if (!isset($_REQUEST['cpuspd']) || $_REQUEST['cpuspd'] == '')
+ die("must specify cpu speed if cpu type is defined");
+ $cpuspd=$_REQUEST['cpuspd'];
+ $query.=", cpuspd='$cpuspd'";
+ if (!isset($_REQUEST['cpmspd']) || $_REQUEST['cpmspd'] == '')
+ die("must specify cpm speed if cpu type is defined");
+ $cpmspd=$_REQUEST['cpmspd'];
+ $query.=", cpmspd='$cpmspd'";
+ if (!isset($_REQUEST['busspd']) || $_REQUEST['busspd'] == '')
+ die("must specify bus speed if cpu type is defined");
+ $busspd=$_REQUEST['busspd'];
+ $query.=", busspd='$busspd'";
+ }
+ else {
+ if (isset($_REQUEST['cpuspd']))
+ die("can't specify cpu speed if there is no cpu");
+ if (isset($_REQUEST['cpmspd']))
+ die("can't specify cpm speed if there is no cpu");
+ if (isset($_REQUEST['busspd']))
+ die("can't specify bus speed if there is no cpu");
+ }
+
+ if (isset($_REQUEST['hschin'])) {
+ $hschin=$_REQUEST['hschin'];
+ if (($hschin = intval($hschin)) < 0 || $hschin > 4)
+ die("Invalid number of hs input chans ($hschin)");
+ }
+ else
+ $hschin = 0;
+ if (isset($_REQUEST['hschout'])) {
+ $hschout=$_REQUEST['hschout'];
+ if (($hschout = intval($hschout)) < 0 || $hschout > 4)
+ die("Invalid number of hs output chans ($hschout)");
+ }
+ else
+ $hschout = 0;
+ if (isset($_REQUEST['hstype'])) {
+ $hstype=$_REQUEST['hstype'];
+ $query.=", hstype='$hstype'";
+ }
+ else {
+ if ($_REQUEST['hschin'] != 0)
+ die("number of high-speed input channels must be zero"
+ . " if high-speed chip is not present");
+ if ($_REQUEST['hschout'] != 0)
+ die("number of high-speed output channels must be zero"
+ . " if high-speed chip is not present");
+ }
+ $query.=", hschin='$hschin'";
+ $query.=", hschout='$hschout'";
+
+ $query.=" where serno=$serno";
+
+ mysql_query($query);
+ if(mysql_errno()) {
+ $errstr = mysql_error();
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $errstr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+ else {
+ $sernos = array($serno);
+ $nsernos = 1;
+
+ write_eeprom_cfg_file();
+
+ echo "\t<font size=+2>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe board with serial number <b>$serno</b> was"
+ . " successfully updated";
+ if ($numerrs > 0) {
+ $errstr = $cfgerrs[0];
+ echo "<br>\n\t\t\t";
+ echo "(but the cfg file update failed: $errstr)";
+ }
+ echo "\n";
+ echo "\t\t</p>\n";
+ echo "\t</font>\n";
+ }
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+ <td align=center><a href="browse.php">Back to Browse</a></td>
+ <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/doedlog.php b/tools/bddb/doedlog.php
new file mode 100644
index 0000000..7009aa7
--- /dev/null
+++ b/tools/bddb/doedlog.php
@@ -0,0 +1,76 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // doedit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Edit Log Entry Results");
+
+ if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+ die("the board serial number was not specified");
+ $serno=intval($_REQUEST['serno']);
+
+ if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '')
+ die("log number not specified!");
+ $logno=intval($_REQUEST['logno']);
+
+ $query="update log set";
+
+ if (isset($_REQUEST['date'])) {
+ $date=$_REQUEST['date'];
+ list($y, $m, $d) = split("-", $date);
+ if (!checkdate($m, $d, $y) || $y < 1999)
+ die("date is invalid (input '$date', " .
+ "yyyy-mm-dd '$y-$m-$d')");
+ $query.=" date='$date'";
+ }
+
+ if (isset($_REQUEST['who'])) {
+ $who=$_REQUEST['who'];
+ $query.=", who='" . $who . "'";
+ }
+
+ if (isset($_REQUEST['details'])) {
+ $details=$_REQUEST['details'];
+ $query.=", details='" . rawurlencode($details) . "'";
+ }
+
+ $query.=" where serno=$serno and logno=$logno";
+
+ mysql_query($query);
+ if(mysql_errno()) {
+ $errstr = mysql_error();
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $errstr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+ else {
+ echo "\t<font size=+2>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe log entry with log number <b>$logno</b> and\n";
+ echo "\t\t\tserial number <b>$serno</b> ";
+ echo "was successfully updated\n";
+ echo "\t\t</p>\n";
+ echo "\t</font>\n";
+ }
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+ <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Back to Log</a></td>
+ <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/donew.php b/tools/bddb/donew.php
new file mode 100644
index 0000000..39b2c78
--- /dev/null
+++ b/tools/bddb/donew.php
@@ -0,0 +1,230 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // doedit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Board Registration Results");
+
+ if (isset($_REQUEST['serno'])) {
+ $serno=$_REQUEST['serno'];
+ die("serial number must not be set ($serno) when Creating!");
+ }
+
+ $query="update boards set";
+
+ list($y, $m, $d) = split("-", $date);
+ if (!checkdate($m, $d, $y) || $y < 1999)
+ die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')");
+ $query.=" date='$date'";
+
+ if ($batch != '') {
+ if (strlen($batch) > 32)
+ die("batch field too long (>32)");
+ $query.=", batch='$batch'";
+ }
+
+ if (!in_array($type, $type_vals))
+ die("Invalid type ($type) specified");
+ $query.=", type='$type'";
+
+ if (($rev = intval($rev)) <= 0 || $rev > 255)
+ die("Revision number is invalid ($rev)");
+ $query.=sprintf(", rev=%d", $rev);
+
+ $query.=gather_enum_multi_query("sdram", 4);
+
+ $query.=gather_enum_multi_query("flash", 4);
+
+ $query.=gather_enum_multi_query("zbt", 16);
+
+ $query.=gather_enum_multi_query("xlxtyp", 4);
+ $nxlx = count_enum_multi("xlxtyp", 4);
+
+ $query.=gather_enum_multi_query("xlxspd", 4);
+ if (count_enum_multi("xlxspd", 4) != $nxlx)
+ die("number of xilinx speeds not same as number of types");
+
+ $query.=gather_enum_multi_query("xlxtmp", 4);
+ if (count_enum_multi("xlxtmp", 4) != $nxlx)
+ die("number of xilinx temps. not same as number of types");
+
+ $query.=gather_enum_multi_query("xlxgrd", 4);
+ if (count_enum_multi("xlxgrd", 4) != $nxlx)
+ die("number of xilinx grades not same as number of types");
+
+ if ($cputyp == '') {
+ if ($cpuspd != '')
+ die("can't specify cpu speed if there is no cpu");
+ if ($cpmspd != '')
+ die("can't specify cpm speed if there is no cpu");
+ if ($busspd != '')
+ die("can't specify bus speed if there is no cpu");
+ }
+ else {
+ $query.=", cputyp='$cputyp'";
+ if ($cpuspd == '')
+ die("must specify cpu speed if cpu type is defined");
+ $query.=", cpuspd='$cpuspd'";
+ if ($cpmspd == '')
+ die("must specify cpm speed if cpu type is defined");
+ $query.=", cpmspd='$cpmspd'";
+ if ($busspd == '')
+ die("must specify bus speed if cpu type is defined");
+ $query.=", busspd='$busspd'";
+ }
+
+ if (($hschin = intval($hschin)) < 0 || $hschin > 4)
+ die("Invalid number of hs input chans ($hschin)");
+ if (($hschout = intval($hschout)) < 0 || $hschout > 4)
+ die("Invalid number of hs output chans ($hschout)");
+ if ($hstype == '') {
+ if ($hschin != 0)
+ die("number of high-speed input channels must be zero"
+ . " if high-speed chip is not present");
+ if ($hschout != 0)
+ die("number of high-speed output channels must be zero"
+ . " if high-speed chip is not present");
+ }
+ else
+ $query.=", hstype='$hstype'";
+ $query.=", hschin='$hschin'";
+ $query.=", hschout='$hschout'";
+
+ // echo "final query = '$query'<br>\n";
+
+ $quant = intval($quant);
+ if ($quant <= 0) $quant = 1;
+
+ $sernos = array();
+ if ($geneths)
+ $ethaddrs = array();
+
+ $sqlerr = '';
+
+ while ($quant-- > 0) {
+
+ mysql_query("insert into boards (serno) values (null)");
+ if (mysql_errno()) {
+ $sqlerr = mysql_error();
+ break;
+ }
+
+ $serno = mysql_insert_id();
+ if (!$serno) {
+ $sqlerr = "couldn't allocate new serial number";
+ break;
+ }
+
+ mysql_query($query . " where serno=$serno");
+ if (mysql_errno()) {
+ $sqlerr = mysql_error();
+ break;
+ }
+
+ array_push($sernos, $serno);
+
+ if ($geneths) {
+
+ $ethaddr = gen_eth_addr($serno);
+
+ mysql_query("update boards set ethaddr='$ethaddr'" .
+ " where serno=$serno");
+ if (mysql_errno()) {
+ $sqlerr = mysql_error();
+
+ array_push($ethaddrs,
+ "<font color=#ff0000><b>" .
+ "db save fail" .
+ "</b></font>");
+ break;
+ }
+
+ array_push($ethaddrs, $ethaddr);
+ }
+ }
+
+ $nsernos = count($sernos);
+
+ if ($nsernos > 0) {
+
+ write_eeprom_cfg_file();
+
+ echo "<font size=+2>\n";
+ echo "\t<p>\n";
+ echo "\t\tThe following board serial numbers were"
+ . " successfully allocated";
+ if ($numerrs > 0)
+ echo " (but with $numerrs cfg file error" .
+ ($numerrs > 1 ? "s" : "") . ")";
+ echo ":\n";
+ echo "\t</p>\n";
+
+ echo "</font>\n";
+
+ echo "<table align=center width=\"100%\">\n";
+ echo "<tr>\n";
+ echo "\t<th>Serial Number</th>\n";
+ if ($numerrs > 0)
+ echo "\t<th>Cfg File Errs</th>\n";
+ if ($geneths)
+ echo "\t<th>Ethernet Address</th>\n";
+ echo "</tr>\n";
+
+ for ($i = 0; $i < $nsernos; $i++) {
+
+ $serno = sprintf("%010d", $sernos[$i]);
+
+ echo "<tr>\n";
+
+ echo "\t<td align=center><font size=+2>" .
+ "<b>$serno</b></font></td>\n";
+
+ if ($numerrs > 0) {
+ if (($errstr = $cfgerrs[$i]) == '')
+ $errstr = '&nbsp;';
+ echo "\t<td align=center>" .
+ "<font size=+2 color=#ff0000><b>" .
+ $errstr .
+ "</b></font></td>\n";
+ }
+
+ if ($geneths) {
+ echo "\t<td align=center>" .
+ "<font size=+2 color=#00ff00><b>" .
+ $ethaddrs[$i] .
+ "</b></font></td>\n";
+ }
+
+ echo "</tr>\n";
+ }
+
+ echo "</table>\n";
+ }
+
+ if ($sqlerr != '') {
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following SQL error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $sqlerr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+
+?>
+<p>
+<table align=center width="100%">
+<tr>
+ <td align=center><a href="browse.php">Go to Browse</a></td>
+ <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/donewlog.php b/tools/bddb/donewlog.php
new file mode 100644
index 0000000..7635d29
--- /dev/null
+++ b/tools/bddb/donewlog.php
@@ -0,0 +1,86 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // doedit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Add Log Entry Results");
+
+ if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+ die("serial number not specified!");
+ $serno=intval($_REQUEST['serno']);
+
+ if (isset($_REQUEST['logno'])) {
+ $logno=$_REQUEST['logno'];
+ die("log number must not be set ($logno) when Creating!");
+ }
+
+ $query="update log set serno=$serno";
+
+ list($y, $m, $d) = split("-", $date);
+ if (!checkdate($m, $d, $y) || $y < 1999)
+ die("date is invalid (input '$date', yyyy-mm-dd '$y-$m-$d')");
+ $query.=", date='$date'";
+
+ if (isset($_REQUEST['who'])) {
+ $who=$_REQUEST['who'];
+ $query.=", who='" . $who . "'";
+ }
+
+ if (isset($_REQUEST['details'])) {
+ $details=$_REQUEST['details'];
+ $query.=", details='" . rawurlencode($details) . "'";
+ }
+
+ // echo "final query = '$query'<br>\n";
+
+ $sqlerr = '';
+
+ mysql_query("insert into log (logno) values (null)");
+ if (mysql_errno())
+ $sqlerr = mysql_error();
+ else {
+ $logno = mysql_insert_id();
+ if (!$logno)
+ $sqlerr = "couldn't allocate new serial number";
+ else {
+ mysql_query($query . " where logno=$logno");
+ if (mysql_errno())
+ $sqlerr = mysql_error();
+ }
+ }
+
+ if ($sqlerr == '') {
+ echo "<font size=+2>\n";
+ echo "\t<p>\n";
+ echo "\t\tA log entry with log number '$logno' was " .
+ "added to the board with serial number '$serno'\n";
+ echo "\t</p>\n";
+ echo "</font>\n";
+ }
+ else {
+ echo "\t<font size=+4>\n";
+ echo "\t\t<p>\n";
+ echo "\t\t\tThe following SQL error was encountered:\n";
+ echo "\t\t</p>\n";
+ echo "\t\t<center>\n";
+ printf("\t\t\t<b>%s</b>\n", $sqlerr);
+ echo "\t\t</center>\n";
+ echo "\t</font>\n";
+ }
+
+?>
+<p></p>
+<table width="100%">
+<tr>
+ <td align=center><a href="brlog.php?serno=<?php echo "$serno"; ?>">Go to Browse</a></td>
+ <td align=center><a href="index.php">Back to Start</a></td>
+</tr>
+</table>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/edit.php b/tools/bddb/edit.php
new file mode 100644
index 0000000..dd8c26c
--- /dev/null
+++ b/tools/bddb/edit.php
@@ -0,0 +1,131 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // edit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Edit Board Registration");
+
+ if ($serno == 0)
+ die("serial number not specified or invalid!");
+
+ $pserno = sprintf("%010d", $serno);
+
+ echo "<center><b><font size=+2>";
+ echo "Board Serial Number: $pserno";
+ echo "</font></b></center>\n";
+
+?>
+<p>
+<form action=doedit.php method=POST>
+<?php
+ echo "<input type=hidden name=serno value=$serno>\n";
+
+ $r=mysql_query("select * from boards where serno=$serno");
+ $row=mysql_fetch_array($r);
+ if(!$row) die("no record of serial number '$serno' in database");
+
+ begin_table(5);
+
+ // ethaddr char(17)
+ print_field("ethaddr", $row, 17);
+
+ // date date
+ print_field("date", $row);
+
+ // batch char(32)
+ print_field("batch", $row, 32);
+
+ // type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY')
+ print_enum("type", $row, $type_vals);
+
+ // rev tinyint(3) unsigned zerofill
+ print_field("rev", $row, 3, 'rev_filter');
+
+ // location char(64)
+ print_field("location", $row, 64);
+
+ // comments text
+ print_field_multiline("comments", $row, 60, 10, 'text_filter');
+
+ // sdram[0-3] enum('32M','64M','128M','256M')
+ print_enum_multi("sdram", $row, $sdram_vals, 4, array());
+
+ // flash[0-3] enum('4M','8M','16M','32M','64M')
+ print_enum_multi("flash", $row, $flash_vals, 4, array());
+
+ // zbt[0-f] enum('512K','1M','2M','4M')
+ print_enum_multi("zbt", $row, $zbt_vals, 16, array());
+
+ // xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E')
+ print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(), 1);
+
+ // xlxspd[0-3] enum('6','7','8')
+ print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(), 1);
+
+ // xlxtmp[0-3] enum('COM','IND')
+ print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(), 1);
+
+ // xlxgrd[0-3] enum('NORMAL','ENGSAMP')
+ print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(), 1);
+
+ // cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)')
+ print_enum("cputyp", $row, $cputyp_vals);
+
+ // cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("cpuspd", $row, $clk_vals);
+
+ // cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("cpmspd", $row, $clk_vals);
+
+ // busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("busspd", $row, $clk_vals);
+
+ // hstype enum('AMCC-S2064A')
+ print_enum("hstype", $row, $hstype_vals);
+
+ // hschin enum('0','1','2','3','4')
+ print_enum("hschin", $row, $hschin_vals);
+
+ // hschout enum('0','1','2','3','4')
+ print_enum("hschout", $row, $hschout_vals);
+
+ end_table();
+
+ echo "<p>\n";
+ echo "<center><b>";
+ echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>";
+ echo "<br></br>\n";
+ echo "<tt>[ <a href=\"dodelete.php?serno=$serno\">delete</a> ]</tt>";
+ echo "</b></center>\n";
+ echo "</p>\n";
+?>
+<p>
+<table align=center width="100%">
+<tr>
+ <td align=center>
+ <input type=submit value=Edit>
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td align=center>
+ <input type=reset value=Reset>
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td align=center>
+ <a href="index.php">Back to Start</a>
+ </td>
+</tr>
+</table>
+</p>
+</form>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/edlog.php b/tools/bddb/edlog.php
new file mode 100644
index 0000000..8befd35
--- /dev/null
+++ b/tools/bddb/edlog.php
@@ -0,0 +1,86 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // edit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - Edit Board Log Entry");
+
+ if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+ die("serial number not specified!");
+ $serno=intval($_REQUEST['serno']);
+
+ if (!isset($_REQUEST['logno']) || $_REQUEST['logno'] == '')
+ die("log number not specified!");
+ $logno=intval($_REQUEST['logno']);
+
+ $pserno = sprintf("%010d", $serno);
+ $plogno = sprintf("%010d", $logno);
+
+ echo "<center><b><font size=+2>";
+ echo "Board Serial Number: $pserno, Log Number: $plogno";
+ echo "</font></b></center>\n";
+
+?>
+<p>
+<form action=doedlog.php method=POST>
+<?php
+ echo "<input type=hidden name=serno value=$serno>\n";
+ echo "<input type=hidden name=logno value=$logno>\n";
+
+ $r=mysql_query("select * from log where serno=$serno and logno=$logno");
+ $row=mysql_fetch_array($r);
+ if(!$row)
+ die("no record of log entry with serial number '$serno' " .
+ "and log number '$logno' in database");
+
+ begin_table(3);
+
+ // date date
+ print_field("date", $row);
+
+ // who char(20)
+ print_field("who", $row);
+
+ // details text
+ print_field_multiline("details", $row, 60, 10, 'text_filter');
+
+ end_table();
+
+ echo "<p>\n";
+ echo "<center><b>";
+ echo "<font color=#ff0000>WARNING: NO UNDO ON DELETE!</font>";
+ echo "<br></br>\n";
+ echo "<tt>[ <a href=\"dodellog.php?serno=$serno&logno=$logno\">delete</a> ]</tt>";
+ echo "</b></center>\n";
+ echo "</p>\n";
+?>
+<p>
+<table align=center width="100%">
+<tr>
+ <td align=center>
+ <input type=submit value=Edit>
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td align=center>
+ <input type=reset value=Reset>
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td align=center>
+ <a href="index.php">Back to Start</a>
+ </td>
+</tr>
+</table>
+</p>
+</form>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/execute.php b/tools/bddb/execute.php
new file mode 100644
index 0000000..0b62882
--- /dev/null
+++ b/tools/bddb/execute.php
@@ -0,0 +1,33 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ $serno=isset($_REQUEST['serno'])?$_REQUEST['serno']:'';
+
+ $submit=isset($_REQUEST['submit'])?$_REQUEST['submit']:"[NOT SET]";
+
+ switch ($submit) {
+
+ case "New":
+ require("new.php");
+ break;
+
+ case "Edit":
+ require("edit.php");
+ break;
+
+ case "Browse":
+ require("browse.php");
+ break;
+
+ case "Log":
+ require("brlog.php");
+ break;
+
+ default:
+ require("badsubmit.php");
+ break;
+ }
+?>
diff --git a/tools/bddb/index.php b/tools/bddb/index.php
new file mode 100644
index 0000000..842aed5
--- /dev/null
+++ b/tools/bddb/index.php
@@ -0,0 +1,38 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ require("defs.php");
+ pg_head("$bddb_label");
+?>
+<font size="+4">
+ <form action=execute.php method=POST>
+ <table width="100%" cellspacing=10 cellpadding=10>
+ <tr>
+ <td align=center>
+ <input type=submit name=submit value="New"></input>
+ </td>
+ <td align=center>
+ <input type=submit name=submit value="Edit"></input>
+ </td>
+ <td align=center>
+ <input type=submit name=submit value="Browse"></input>
+ </td>
+ <td align=center>
+ <input type=submit name=submit value="Log"></input>
+ </td>
+ </tr>
+ <tr>
+ <td align=center colspan=4>
+ <b>Serial Number:</b>
+ <input type=text name=serno size=10 maxsize=10 value=""></input>
+ </td>
+ </tr>
+ </table>
+ </form>
+</font>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/new.php b/tools/bddb/new.php
new file mode 100644
index 0000000..30323ff
--- /dev/null
+++ b/tools/bddb/new.php
@@ -0,0 +1,120 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // edit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - New Board Registration");
+?>
+<form action=donew.php method=POST>
+<p></p>
+<?php
+ $serno=intval($serno);
+ // if a serial number was supplied, fetch the record
+ // and use its contents as defaults
+ if ($serno != 0) {
+ $r=mysql_query("select * from boards where serno=$serno");
+ $row=mysql_fetch_array($r);
+ if(!$row)die("no record of serial number '$serno' in database");
+ }
+ else
+ $row = array();
+
+ begin_table(5);
+
+ // date date
+ print_field("date", array('date' => date("Y-m-d")));
+
+ // batch char(32)
+ print_field("batch", $row, 32);
+
+ // type enum('IO','CLP','DSP','INPUT','ALT-INPUT','DISPLAY')
+ print_enum("type", $row, $type_vals, 0);
+
+ // rev tinyint(3) unsigned zerofill
+ print_field("rev", $row, 3, 'rev_filter');
+
+ // sdram[0-3] enum('32M','64M','128M','256M')
+ print_enum_multi("sdram", $row, $sdram_vals, 4, array(2));
+
+ // flash[0-3] enum('4M','8M','16M','32M','64M')
+ print_enum_multi("flash", $row, $flash_vals, 4, array(2));
+
+ // zbt[0-f] enum('512K','1M','2M','4M')
+ print_enum_multi("zbt", $row, $zbt_vals, 16, array(2, 2));
+
+ // xlxtyp[0-3] enum('XCV300E','XCV400E','XCV600E')
+ print_enum_multi("xlxtyp", $row, $xlxtyp_vals, 4, array(1), 1);
+
+ // xlxspd[0-3] enum('6','7','8')
+ print_enum_multi("xlxspd", $row, $xlxspd_vals, 4, array(1), 1);
+
+ // xlxtmp[0-3] enum('COM','IND')
+ print_enum_multi("xlxtmp", $row, $xlxtmp_vals, 4, array(1), 1);
+
+ // xlxgrd[0-3] enum('NORMAL','ENGSAMP')
+ print_enum_multi("xlxgrd", $row, $xlxgrd_vals, 4, array(1), 1);
+
+ // cputyp enum('MPC8260(HIP3)','MPC8260A(HIP4)','MPC8280(HIP7)')
+ print_enum("cputyp", $row, $cputyp_vals, 1);
+
+ // cpuspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("cpuspd", $row, $clk_vals, 4);
+
+ // cpmspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("cpmspd", $row, $clk_vals, 4);
+
+ // busspd enum('33MHZ','66MHZ','100MHZ','133MHZ','166MHZ','200MHZ','233MHZ','266MHZ')
+ print_enum_select("busspd", $row, $clk_vals, 2);
+
+ // hstype enum('AMCC-S2064A')
+ print_enum("hstype", $row, $hstype_vals, 1);
+
+ // hschin enum('0','1','2','3','4')
+ print_enum("hschin", $row, $hschin_vals, 4);
+
+ // hschout enum('0','1','2','3','4')
+ print_enum("hschout", $row, $hschout_vals, 4);
+
+ end_table();
+?>
+<p></p>
+<table width="100%">
+<tr>
+ <td align=center colspan=3>
+ Allocate
+ <input type=text name=quant size=2 maxlength=2 value=" 1">
+ board serial number(s)
+ </td>
+</tr>
+<tr>
+ <td align=center colspan=3>
+ <input type=checkbox name=geneths checked>
+ Generate Ethernet Address(es)
+ </td>
+</tr>
+<tr>
+ <td colspan=3>
+ &nbsp;
+ </td>
+</tr>
+<tr>
+ <td align=center>
+ <input type=submit value="Register Board">
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td align=center>
+ <input type=reset value="Reset Form Contents">
+ </td>
+</tr>
+</table>
+</form>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bddb/newlog.php b/tools/bddb/newlog.php
new file mode 100644
index 0000000..609bb85
--- /dev/null
+++ b/tools/bddb/newlog.php
@@ -0,0 +1,54 @@
+<?php // php pages made with phpMyBuilder <http://kyber.dk/phpMyBuilder> ?>
+<?php
+ // (C) Copyright 2001
+ // Murray Jensen <Murray.Jensen@csiro.au>
+ // CSIRO Manufacturing Science and Technology, Preston Lab
+
+ // edit page (hymod_bddb / boards)
+
+ require("defs.php");
+
+ pg_head("$bddb_label - New Log Entry");
+
+ if (!isset($_REQUEST['serno']) || $_REQUEST['serno'] == '')
+ die("serial number not specified or invalid!");
+ $serno=intval($_REQUEST['serno']);
+
+ if (isset($_REQUEST['logno'])) {
+ $logno=$_REQUEST['logno'];
+ die("log number must not be specified when adding! ($logno)");
+ }
+?>
+<form action=donewlog.php method=POST>
+<p></p>
+<?php
+ echo "<input type=hidden name=serno value=$serno>\n";
+
+ begin_table(3);
+
+ // date date
+ print_field("date", array('date' => date("Y-m-d")));
+
+ // who char(20)
+ print_field("who", array());
+
+ // details text
+ print_field_multiline("details", array(), 60, 10, 'text_filter');
+
+ end_table();
+?>
+<p></p>
+<table width="100%">
+<tr>
+ <td align=center>
+ <input type=submit value="Add Log Entry">
+ </td>
+ <td align=center>
+ <input type=reset value="Reset Form Contents">
+ </td>
+</tr>
+</table>
+</form>
+<?php
+ pg_foot();
+?>
diff --git a/tools/bin2header.c b/tools/bin2header.c
new file mode 100644
index 0000000..390100e
--- /dev/null
+++ b/tools/bin2header.c
@@ -0,0 +1,56 @@
+/* bin2header.c - program to convert binary file into a C structure
+ * definition to be included in a header file.
+ *
+ * (C) Copyright 2008 by Harald Welte <laforge@openmoko.org>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "%s needs one argument: the structure name\n",
+ argv[0]);
+ exit(1);
+ }
+
+ printf("/* bin2header output - automatically generated */\n");
+ printf("unsigned char %s[] = {\n", argv[1]);
+
+ while (1) {
+ int i, nread;
+ unsigned char buf[10];
+ nread = read(0, buf, sizeof(buf));
+ if (nread <= 0)
+ break;
+
+ printf("\t");
+ for (i = 0; i < nread - 1; i++)
+ printf("0x%02x, ", buf[i]);
+
+ printf("0x%02x,\n", buf[nread-1]);
+ }
+
+ printf("};\n");
+
+ exit(0);
+}
diff --git a/tools/binutils-version.sh b/tools/binutils-version.sh
new file mode 100755
index 0000000..d4d9eb4
--- /dev/null
+++ b/tools/binutils-version.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# binutils-version [-p] gas-command
+#
+# Prints the binutils version of `gas-command' in a canonical 4-digit form
+# such as `0222' for binutils 2.22
+#
+
+gas="$*"
+
+if [ ${#gas} -eq 0 ]; then
+ echo "Error: No assembler specified."
+ printf "Usage:\n\t$0 <gas-command>\n"
+ exit 1
+fi
+
+MAJOR=$($gas --version | head -1 | awk '{print $NF}' | cut -d . -f 1)
+MINOR=$($gas --version | head -1 | awk '{print $NF}' | cut -d . -f 2)
+
+printf "%02d%02d\\n" $MAJOR $MINOR
diff --git a/tools/bmp_logo.c b/tools/bmp_logo.c
new file mode 100644
index 0000000..b2ad3d5
--- /dev/null
+++ b/tools/bmp_logo.c
@@ -0,0 +1,203 @@
+#include "compiler.h"
+
+enum {
+ MODE_GEN_INFO,
+ MODE_GEN_DATA
+};
+
+typedef struct bitmap_s { /* bitmap description */
+ uint16_t width;
+ uint16_t height;
+ uint8_t palette[256*3];
+ uint8_t *data;
+} bitmap_t;
+
+#define DEFAULT_CMAP_SIZE 16 /* size of default color map */
+
+void usage(const char *prog)
+{
+ fprintf(stderr, "Usage: %s [--gen-info|--gen-data] file\n", prog);
+}
+
+/*
+ * Neutralize little endians.
+ */
+uint16_t le_short(uint16_t x)
+{
+ uint16_t val;
+ uint8_t *p = (uint8_t *)(&x);
+
+ val = (*p++ & 0xff) << 0;
+ val |= (*p & 0xff) << 8;
+
+ return val;
+}
+
+void skip_bytes (FILE *fp, int n)
+{
+ while (n-- > 0)
+ fgetc (fp);
+}
+
+__attribute__ ((__noreturn__))
+int error (char * msg, FILE *fp)
+{
+ fprintf (stderr, "ERROR: %s\n", msg);
+
+ fclose (fp);
+
+ exit (EXIT_FAILURE);
+}
+
+void gen_info(bitmap_t *b, uint16_t n_colors)
+{
+ printf("/*\n"
+ " * Automatically generated by \"tools/bmp_logo\"\n"
+ " *\n"
+ " * DO NOT EDIT\n"
+ " *\n"
+ " */\n\n\n"
+ "#ifndef __BMP_LOGO_H__\n"
+ "#define __BMP_LOGO_H__\n\n"
+ "#define BMP_LOGO_WIDTH\t\t%d\n"
+ "#define BMP_LOGO_HEIGHT\t\t%d\n"
+ "#define BMP_LOGO_COLORS\t\t%d\n"
+ "#define BMP_LOGO_OFFSET\t\t%d\n\n"
+ "extern unsigned short bmp_logo_palette[];\n"
+ "extern unsigned char bmp_logo_bitmap[];\n\n"
+ "#endif /* __BMP_LOGO_H__ */\n",
+ b->width, b->height, n_colors,
+ DEFAULT_CMAP_SIZE);
+}
+
+int main (int argc, char *argv[])
+{
+ int mode, i, x;
+ FILE *fp;
+ bitmap_t bmp;
+ bitmap_t *b = &bmp;
+ uint16_t data_offset, n_colors;
+
+ if (argc < 3) {
+ usage(argv[0]);
+ exit (EXIT_FAILURE);
+ }
+
+ if (!strcmp(argv[1], "--gen-info"))
+ mode = MODE_GEN_INFO;
+ else if (!strcmp(argv[1], "--gen-data"))
+ mode = MODE_GEN_DATA;
+ else {
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ fp = fopen(argv[2], "rb");
+ if (!fp) {
+ perror(argv[2]);
+ exit (EXIT_FAILURE);
+ }
+
+ if (fgetc (fp) != 'B' || fgetc (fp) != 'M')
+ error ("Input file is not a bitmap", fp);
+
+ /*
+ * read width and height of the image, and the number of colors used;
+ * ignore the rest
+ */
+ skip_bytes (fp, 8);
+ if (fread (&data_offset, sizeof (uint16_t), 1, fp) != 1)
+ error ("Couldn't read bitmap data offset", fp);
+ skip_bytes (fp, 6);
+ if (fread (&b->width, sizeof (uint16_t), 1, fp) != 1)
+ error ("Couldn't read bitmap width", fp);
+ skip_bytes (fp, 2);
+ if (fread (&b->height, sizeof (uint16_t), 1, fp) != 1)
+ error ("Couldn't read bitmap height", fp);
+ skip_bytes (fp, 22);
+ if (fread (&n_colors, sizeof (uint16_t), 1, fp) != 1)
+ error ("Couldn't read bitmap colors", fp);
+ skip_bytes (fp, 6);
+
+ /*
+ * Repair endianess.
+ */
+ data_offset = le_short(data_offset);
+ b->width = le_short(b->width);
+ b->height = le_short(b->height);
+ n_colors = le_short(n_colors);
+
+ /* assume we are working with an 8-bit file */
+ if ((n_colors == 0) || (n_colors > 256 - DEFAULT_CMAP_SIZE)) {
+ /* reserve DEFAULT_CMAP_SIZE color map entries for default map */
+ n_colors = 256 - DEFAULT_CMAP_SIZE;
+ }
+
+ if (mode == MODE_GEN_INFO) {
+ gen_info(b, n_colors);
+ goto out;
+ }
+
+ printf("/*\n"
+ " * Automatically generated by \"tools/bmp_logo\"\n"
+ " *\n"
+ " * DO NOT EDIT\n"
+ " *\n"
+ " */\n\n\n"
+ "#ifndef __BMP_LOGO_DATA_H__\n"
+ "#define __BMP_LOGO_DATA_H__\n\n");
+
+ /* allocate memory */
+ if ((b->data = (uint8_t *)malloc(b->width * b->height)) == NULL)
+ error ("Error allocating memory for file", fp);
+
+ /* read and print the palette information */
+ printf("unsigned short bmp_logo_palette[] = {\n");
+
+ for (i=0; i<n_colors; ++i) {
+ b->palette[(int)(i*3+2)] = fgetc(fp);
+ b->palette[(int)(i*3+1)] = fgetc(fp);
+ b->palette[(int)(i*3+0)] = fgetc(fp);
+ x=fgetc(fp);
+
+ printf ("%s0x0%X%X%X,%s",
+ ((i%8) == 0) ? "\t" : " ",
+ (b->palette[(int)(i*3+0)] >> 4) & 0x0F,
+ (b->palette[(int)(i*3+1)] >> 4) & 0x0F,
+ (b->palette[(int)(i*3+2)] >> 4) & 0x0F,
+ ((i%8) == 7) ? "\n" : ""
+ );
+ }
+
+ /* seek to offset indicated by file header */
+ fseek(fp, (long)data_offset, SEEK_SET);
+
+ /* read the bitmap; leave room for default color map */
+ printf ("\n");
+ printf ("};\n");
+ printf ("\n");
+ printf("unsigned char bmp_logo_bitmap[] = {\n");
+ for (i=(b->height-1)*b->width; i>=0; i-=b->width) {
+ for (x = 0; x < b->width; x++) {
+ b->data[(uint16_t) i + x] = (uint8_t) fgetc (fp) \
+ + DEFAULT_CMAP_SIZE;
+ }
+ }
+
+ for (i=0; i<(b->height*b->width); ++i) {
+ if ((i%8) == 0)
+ putchar ('\t');
+ printf ("0x%02X,%c",
+ b->data[i],
+ ((i%8) == 7) ? '\n' : ' '
+ );
+ }
+ printf ("\n"
+ "};\n\n"
+ "#endif /* __BMP_LOGO_DATA_H__ */\n"
+ );
+
+out:
+ fclose(fp);
+ return 0;
+}
diff --git a/tools/buildman/.gitignore b/tools/buildman/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/tools/buildman/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/tools/buildman/README b/tools/buildman/README
new file mode 100644
index 0000000..7221007
--- /dev/null
+++ b/tools/buildman/README
@@ -0,0 +1,679 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+What is this?
+=============
+
+This tool handles building U-Boot to check that you have not broken it
+with your patch series. It can build each individual commit and report
+which boards fail on which commits, and which errors come up. It aims
+to make full use of multi-processor machines.
+
+A key feature of buildman is its output summary, which allows warnings,
+errors or image size increases in a particular commit or board to be
+quickly identified and the offending commit pinpointed. This can be a big
+help for anyone working with >10 patches at a time.
+
+
+Caveats
+=======
+
+Buildman is still in its infancy. It is already a very useful tool, but
+expect to find problems and send patches.
+
+Buildman can be stopped and restarted, in which case it will continue
+where it left off. This should happen cleanly and without side-effects.
+If not, it is a bug, for which a patch would be welcome.
+
+Buildman gets so tied up in its work that it can ignore the outside world.
+You may need to press Ctrl-C several times to quit it. Also it will print
+out various exceptions when stopped.
+
+
+Theory of Operation
+===================
+
+(please read this section in full twice or you will be perpetually confused)
+
+Buildman is a builder. It is not make, although it runs make. It does not
+produce any useful output on the terminal while building, except for
+progress information. All the output (errors, warnings and binaries if you
+are ask for them) is stored in output directories, which you can look at
+while the build is progressing, or when it is finished.
+
+Buildman produces a concise summary of which boards succeeded and failed.
+It shows which commit introduced which board failure using a simple
+red/green colour coding. Full error information can be requested, in which
+case it is de-duped and displayed against the commit that introduced the
+error. An example workflow is below.
+
+Buildman stores image size information and can report changes in image size
+from commit to commit. An example of this is below.
+
+Buildman starts multiple threads, and each thread builds for one board at
+a time. A thread starts at the first commit, configures the source for your
+board and builds it. Then it checks out the next commit and does an
+incremental build. Eventually the thread reaches the last commit and stops.
+If errors or warnings are found along the way, the thread will reconfigure
+after every commit, and your build will be very slow. This is because a
+file that produces just a warning would not normally be rebuilt in an
+incremental build.
+
+Buildman works in an entirely separate place from your U-Boot repository.
+It creates a separate working directory for each thread, and puts the
+output files in the working directory, organised by commit name and board
+name, in a two-level hierarchy.
+
+Buildman is invoked in your U-Boot directory, the one with the .git
+directory. It clones this repository into a copy for each thread, and the
+threads do not affect the state of your git repository. Any checkouts done
+by the thread affect only the working directory for that thread.
+
+Buildman automatically selects the correct toolchain for each board. You
+must supply suitable toolchains, but buildman takes care of selecting the
+right one.
+
+Buildman always builds a branch, and always builds the upstream commit as
+well, for comparison. It cannot build individual commits at present, unless
+(maybe) you point it at an empty branch. Put all your commits in a branch,
+set the branch's upstream to a valid value, and all will be well. Otherwise
+buildman will perform random actions. Use -n to check what the random
+actions might be.
+
+Buildman is optimised for building many commits at once, for many boards.
+On multi-core machines, Buildman is fast because it uses most of the
+available CPU power. When it gets to the end, or if you are building just
+a few commits or boards, it will be pretty slow. As a tip, if you don't
+plan to use your machine for anything else, you can use -T to increase the
+number of threads beyond the default.
+
+Buildman lets you build all boards, or a subset. Specify the subset using
+the board name, architecture name, SOC name, or anything else in the
+boards.cfg file. So 'at91' will build all AT91 boards (arm), powerpc will
+build all PowerPC boards.
+
+Buildman does not store intermediate object files. It optionally copies
+the binary output into a directory when a build is successful. Size
+information is always recorded. It needs a fair bit of disk space to work,
+typically 250MB per thread.
+
+
+Setting up
+==========
+
+1. Get the U-Boot source. You probably already have it, but if not these
+steps should get you started with a repo and some commits for testing.
+
+$ cd /path/to/u-boot
+$ git clone git://git.denx.de/u-boot.git .
+$ git checkout -b my-branch origin/master
+$ # Add some commits to the branch, reading for testing
+
+2. Create ~/.buildman to tell buildman where to find tool chains. As an
+example:
+
+# Buildman settings file
+
+[toolchain]
+root: /
+rest: /toolchains/*
+eldk: /opt/eldk-4.2
+
+[toolchain-alias]
+x86: i386
+blackfin: bfin
+sh: sh4
+nds32: nds32le
+openrisc: or32
+
+
+This selects the available toolchain paths. Add the base directory for
+each of your toolchains here. Buildman will search inside these directories
+and also in any '/usr' and '/usr/bin' subdirectories.
+
+Make sure the tags (here root: rest: and eldk:) are unique.
+
+The toolchain-alias section indicates that the i386 toolchain should be used
+to build x86 commits.
+
+
+2. Check the available toolchains
+
+Run this check to make sure that you have a toolchain for every architecture.
+
+$ ./tools/buildman/buildman --list-tool-chains
+Scanning for tool chains
+ - scanning path '/'
+ - looking in '/.'
+ - looking in '/bin'
+ - looking in '/usr/bin'
+ - found '/usr/bin/gcc'
+Tool chain test: OK
+ - found '/usr/bin/c89-gcc'
+Tool chain test: OK
+ - found '/usr/bin/c99-gcc'
+Tool chain test: OK
+ - found '/usr/bin/x86_64-linux-gnu-gcc'
+Tool chain test: OK
+ - scanning path '/toolchains/powerpc-linux'
+ - looking in '/toolchains/powerpc-linux/.'
+ - looking in '/toolchains/powerpc-linux/bin'
+ - found '/toolchains/powerpc-linux/bin/powerpc-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/powerpc-linux/usr/bin'
+ - scanning path '/toolchains/nds32le-linux-glibc-v1f'
+ - looking in '/toolchains/nds32le-linux-glibc-v1f/.'
+ - looking in '/toolchains/nds32le-linux-glibc-v1f/bin'
+ - found '/toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/nds32le-linux-glibc-v1f/usr/bin'
+ - scanning path '/toolchains/nios2'
+ - looking in '/toolchains/nios2/.'
+ - looking in '/toolchains/nios2/bin'
+ - found '/toolchains/nios2/bin/nios2-linux-gcc'
+Tool chain test: OK
+ - found '/toolchains/nios2/bin/nios2-linux-uclibc-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/nios2/usr/bin'
+ - found '/toolchains/nios2/usr/bin/nios2-linux-gcc'
+Tool chain test: OK
+ - found '/toolchains/nios2/usr/bin/nios2-linux-uclibc-gcc'
+Tool chain test: OK
+ - scanning path '/toolchains/microblaze-unknown-linux-gnu'
+ - looking in '/toolchains/microblaze-unknown-linux-gnu/.'
+ - looking in '/toolchains/microblaze-unknown-linux-gnu/bin'
+ - found '/toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc'
+Tool chain test: OK
+ - found '/toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/microblaze-unknown-linux-gnu/usr/bin'
+ - scanning path '/toolchains/mips-linux'
+ - looking in '/toolchains/mips-linux/.'
+ - looking in '/toolchains/mips-linux/bin'
+ - found '/toolchains/mips-linux/bin/mips-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/mips-linux/usr/bin'
+ - scanning path '/toolchains/old'
+ - looking in '/toolchains/old/.'
+ - looking in '/toolchains/old/bin'
+ - looking in '/toolchains/old/usr/bin'
+ - scanning path '/toolchains/i386-linux'
+ - looking in '/toolchains/i386-linux/.'
+ - looking in '/toolchains/i386-linux/bin'
+ - found '/toolchains/i386-linux/bin/i386-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/i386-linux/usr/bin'
+ - scanning path '/toolchains/bfin-uclinux'
+ - looking in '/toolchains/bfin-uclinux/.'
+ - looking in '/toolchains/bfin-uclinux/bin'
+ - found '/toolchains/bfin-uclinux/bin/bfin-uclinux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/bfin-uclinux/usr/bin'
+ - scanning path '/toolchains/sparc-elf'
+ - looking in '/toolchains/sparc-elf/.'
+ - looking in '/toolchains/sparc-elf/bin'
+ - found '/toolchains/sparc-elf/bin/sparc-elf-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/sparc-elf/usr/bin'
+ - scanning path '/toolchains/arm-2010q1'
+ - looking in '/toolchains/arm-2010q1/.'
+ - looking in '/toolchains/arm-2010q1/bin'
+ - found '/toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/arm-2010q1/usr/bin'
+ - scanning path '/toolchains/from'
+ - looking in '/toolchains/from/.'
+ - looking in '/toolchains/from/bin'
+ - looking in '/toolchains/from/usr/bin'
+ - scanning path '/toolchains/sh4-gentoo-linux-gnu'
+ - looking in '/toolchains/sh4-gentoo-linux-gnu/.'
+ - looking in '/toolchains/sh4-gentoo-linux-gnu/bin'
+ - found '/toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/sh4-gentoo-linux-gnu/usr/bin'
+ - scanning path '/toolchains/avr32-linux'
+ - looking in '/toolchains/avr32-linux/.'
+ - looking in '/toolchains/avr32-linux/bin'
+ - found '/toolchains/avr32-linux/bin/avr32-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/avr32-linux/usr/bin'
+ - scanning path '/toolchains/m68k-linux'
+ - looking in '/toolchains/m68k-linux/.'
+ - looking in '/toolchains/m68k-linux/bin'
+ - found '/toolchains/m68k-linux/bin/m68k-linux-gcc'
+Tool chain test: OK
+ - looking in '/toolchains/m68k-linux/usr/bin'
+List of available toolchains (17):
+arm : /toolchains/arm-2010q1/bin/arm-none-linux-gnueabi-gcc
+avr32 : /toolchains/avr32-linux/bin/avr32-gcc
+bfin : /toolchains/bfin-uclinux/bin/bfin-uclinux-gcc
+c89 : /usr/bin/c89-gcc
+c99 : /usr/bin/c99-gcc
+i386 : /toolchains/i386-linux/bin/i386-linux-gcc
+m68k : /toolchains/m68k-linux/bin/m68k-linux-gcc
+mb : /toolchains/microblaze-unknown-linux-gnu/bin/mb-linux-gcc
+microblaze: /toolchains/microblaze-unknown-linux-gnu/bin/microblaze-unknown-linux-gnu-gcc
+mips : /toolchains/mips-linux/bin/mips-linux-gcc
+nds32le : /toolchains/nds32le-linux-glibc-v1f/bin/nds32le-linux-gcc
+nios2 : /toolchains/nios2/bin/nios2-linux-gcc
+powerpc : /toolchains/powerpc-linux/bin/powerpc-linux-gcc
+sandbox : /usr/bin/gcc
+sh4 : /toolchains/sh4-gentoo-linux-gnu/bin/sh4-gentoo-linux-gnu-gcc
+sparc : /toolchains/sparc-elf/bin/sparc-elf-gcc
+x86_64 : /usr/bin/x86_64-linux-gnu-gcc
+
+
+You can see that everything is covered, even some strange ones that won't
+be used (c88 and c99). This is a feature.
+
+
+How to run it
+=============
+
+First do a dry run using the -n flag: (replace <branch> with a real, local
+branch with a valid upstream)
+
+$ ./tools/buildman/buildman -b <branch> -n
+
+If it can't detect the upstream branch, try checking out the branch, and
+doing something like 'git branch --set-upstream <branch> upstream/master'
+or something similar.
+
+As an exmmple:
+
+Dry run, so not doing much. But I would do this:
+
+Building 18 commits for 1059 boards (4 threads, 1 job per thread)
+Build directory: ../lcd9b
+ 5bb3505 Merge branch 'master' of git://git.denx.de/u-boot-arm
+ c18f1b4 tegra: Use const for pinmux_config_pingroup/table()
+ 2f043ae tegra: Add display support to funcmux
+ e349900 tegra: fdt: Add pwm binding and node
+ 424a5f0 tegra: fdt: Add LCD definitions for Tegra
+ 0636ccf tegra: Add support for PWM
+ a994fe7 tegra: Add SOC support for display/lcd
+ fcd7350 tegra: Add LCD driver
+ 4d46e9d tegra: Add LCD support to Nvidia boards
+ 991bd48 arm: Add control over cachability of memory regions
+ 54e8019 lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment
+ d92aff7 lcd: Add support for flushing LCD fb from dcache after update
+ dbd0677 tegra: Align LCD frame buffer to section boundary
+ 0cff9b8 tegra: Support control of cache settings for LCD
+ 9c56900 tegra: fdt: Add LCD definitions for Seaboard
+ 5cc29db lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+ cac5a23 tegra: Enable display/lcd support on Seaboard
+ 49ff541 wip
+
+Total boards to build for each commit: 1059
+
+This shows that it will build all 1059 boards, using 4 threads (because
+we have a 4-core CPU). Each thread will run with -j1, meaning that each
+make job will use a single CPU. The list of commits to be built helps you
+confirm that things look about right. Notice that buildman has chosen a
+'base' directory for you, immediately above your source tree.
+
+Buildman works entirely inside the base directory, here ../lcd9b,
+creating a working directory for each thread, and creating output
+directories for each commit and board.
+
+
+Suggested Workflow
+==================
+
+To run the build for real, take off the -n:
+
+$ ./tools/buildman/buildman -b <branch>
+
+Buildman will set up some working directories, and get started. After a
+minute or so it will settle down to a steady pace, with a display like this:
+
+Building 18 commits for 1059 boards (4 threads, 1 job per thread)
+ 528 36 124 /19062 1:13:30 : SIMPC8313_SP
+
+This means that it is building 19062 board/commit combinations. So far it
+has managed to succesfully build 528. Another 36 have built with warnings,
+and 124 more didn't build at all. Buildman expects to complete the process
+in an hour and 15 minutes. Use this time to buy a faster computer.
+
+
+To find out how the build went, ask for a summary with -s. You can do this
+either before the build completes (presumably in another terminal) or or
+afterwards. Let's work through an example of how this is used:
+
+$ ./tools/buildman/buildman -b lcd9b -s
+...
+01: Merge branch 'master' of git://git.denx.de/u-boot-arm
+ powerpc: + galaxy5200_LOWBOOT
+02: tegra: Use const for pinmux_config_pingroup/table()
+03: tegra: Add display support to funcmux
+04: tegra: fdt: Add pwm binding and node
+05: tegra: fdt: Add LCD definitions for Tegra
+06: tegra: Add support for PWM
+07: tegra: Add SOC support for display/lcd
+08: tegra: Add LCD driver
+09: tegra: Add LCD support to Nvidia boards
+10: arm: Add control over cachability of memory regions
+11: lcd: Add CONFIG_LCD_ALIGNMENT to select frame buffer alignment
+12: lcd: Add support for flushing LCD fb from dcache after update
+ arm: + lubbock
+13: tegra: Align LCD frame buffer to section boundary
+14: tegra: Support control of cache settings for LCD
+15: tegra: fdt: Add LCD definitions for Seaboard
+16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+17: tegra: Enable display/lcd support on Seaboard
+18: wip
+
+This shows which commits have succeeded and which have failed. In this case
+the build is still in progress so many boards are not built yet (use -u to
+see which ones). But still we can see a few failures. The galaxy5200_LOWBOOT
+never builds correctly. This could be a problem with our toolchain, or it
+could be a bug in the upstream. The good news is that we probably don't need
+to blame our commits. The bad news is it isn't tested on that board.
+
+Commit 12 broke lubbock. That's what the '+ lubbock' means. The failure
+is never fixed by a later commit, or you would see lubbock again, in green,
+without the +.
+
+To see the actual error:
+
+$ ./tools/buildman/buildman -b <branch> -se lubbock
+...
+12: lcd: Add support for flushing LCD fb from dcache after update
+ arm: + lubbock
++common/libcommon.o: In function `lcd_sync':
++/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
++arm-none-linux-gnueabi-ld: BFD (Sourcery G++ Lite 2010q1-202) 2.19.51.20090709 assertion fail /scratch/julian/2010q1-release-linux-lite/obj/binutils-src-2010q1-202-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:12572
++make: *** [/u-boot/lcd9b/.bm-work/00/build/u-boot] Error 139
+13: tegra: Align LCD frame buffer to section boundary
+14: tegra: Support control of cache settings for LCD
+15: tegra: fdt: Add LCD definitions for Seaboard
+16: lcd: Add CONFIG_CONSOLE_SCROLL_LINES option to speed console
+-/u-boot/lcd9b/.bm-work/00/common/lcd.c:120: undefined reference to `flush_dcache_range'
++/u-boot/lcd9b/.bm-work/00/common/lcd.c:125: undefined reference to `flush_dcache_range'
+17: tegra: Enable display/lcd support on Seaboard
+18: wip
+
+So the problem is in lcd.c, due to missing cache operations. This information
+should be enough to work out what that commit is doing to break these
+boards. (In this case pxa did not have cache operations defined).
+
+If you see error lines marked with - that means that the errors were fixed
+by that commit. Sometimes commits can be in the wrong order, so that a
+breakage is introduced for a few commits and fixed by later commits. This
+shows up clearly with buildman. You can then reorder the commits and try
+again.
+
+At commit 16, the error moves - you can see that the old error at line 120
+is fixed, but there is a new one at line 126. This is probably only because
+we added some code and moved the broken line futher down the file.
+
+If many boards have the same error, then -e will display the error only
+once. This makes the output as concise as possible.
+
+The full build output in this case is available in:
+
+../lcd9b/12_of_18_gd92aff7_lcd--Add-support-for/lubbock/
+
+ done: Indicates the build was done, and holds the return code from make.
+ This is 0 for a good build, typically 2 for a failure.
+
+ err: Output from stderr, if any. Errors and warnings appear here.
+
+ log: Output from stdout. Normally there isn't any since buildman runs
+ in silent mode for now.
+
+ toolchain: Shows information about the toolchain used for the build.
+
+ sizes: Shows image size information.
+
+It is possible to get the build output there also. Use the -k option for
+this. In that case you will also see some output files, like:
+
+ System.map toolchain u-boot u-boot.bin u-boot.map autoconf.mk
+ (also SPL versions u-boot-spl and u-boot-spl.bin if available)
+
+
+Checking Image Sizes
+====================
+
+A key requirement for U-Boot is that you keep code/data size to a minimum.
+Where a new feature increases this noticeably it should normally be put
+behind a CONFIG flag so that boards can leave it off and keep the image
+size more or less the same with each new release.
+
+To check the impact of your commits on image size, use -S. For example:
+
+$ ./tools/buildman/buildman -b us-x86 -sS
+Summary of 10 commits for 1066 boards (4 threads, 1 job per thread)
+01: MAKEALL: add support for per architecture toolchains
+02: x86: Add function to get top of usable ram
+ x86: (for 1/3 boards) text -272.0 rodata +41.0
+03: x86: Add basic cache operations
+04: x86: Permit bootstage and timer data to be used prior to relocation
+ x86: (for 1/3 boards) data +16.0
+05: x86: Add an __end symbol to signal the end of the U-Boot binary
+ x86: (for 1/3 boards) text +76.0
+06: x86: Rearrange the output input to remove BSS
+ x86: (for 1/3 boards) bss -2140.0
+07: x86: Support relocation of FDT on start-up
+ x86: + coreboot-x86
+08: x86: Add error checking to x86 relocation code
+09: x86: Adjust link device tree include file
+10: x86: Enable CONFIG_OF_CONTROL on coreboot
+
+
+You can see that image size only changed on x86, which is good because this
+series is not supposed to change any other board. From commit 7 onwards the
+build fails so we don't get code size numbers. The numbers are fractional
+because they are an average of all boards for that architecture. The
+intention is to allow you to quickly find image size problems introduced by
+your commits.
+
+Note that the 'text' region and 'rodata' are split out. You should add the
+two together to get the total read-only size (reported as the first column
+in the output from binutil's 'size' utility).
+
+A useful option is --step which lets you skip some commits. For example
+--step 2 will show the image sizes for only every 2nd commit (so it will
+compare the image sizes of the 1st, 3rd, 5th... commits). You can also use
+--step 0 which will compare only the first and last commits. This is useful
+for an overview of how your entire series affects code size.
+
+You can also use -d to see a detailed size breakdown for each board. This
+list is sorted in order from largest growth to largest reduction.
+
+It is possible to go a little further with the -B option (--bloat). This
+shows where U-Boot has bloted, breaking the size change down to the function
+level. Example output is below:
+
+$ ./tools/buildman/buildman -b us-mem4 -sSdB
+...
+19: Roll crc32 into hash infrastructure
+ arm: (for 10/10 boards) all -143.4 bss +1.2 data -4.8 rodata -48.2 text -91.6
+ paz00 : all +23 bss -4 rodata -29 text +56
+ u-boot: add: 1/0, grow: 3/-2 bytes: 168/-104 (64)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ ext4fs_read_file 540 568 +28
+ insert_var_value_sub 688 692 +4
+ run_list_real 1996 1992 -4
+ do_mem_crc 168 68 -100
+ trimslice : all -9 bss +16 rodata -29 text +4
+ u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ ext4fs_iterate_dir 672 668 -4
+ ext4fs_read_file 568 548 -20
+ do_mem_crc 168 68 -100
+ whistler : all -9 bss +16 rodata -29 text +4
+ u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ ext4fs_iterate_dir 672 668 -4
+ ext4fs_read_file 568 548 -20
+ do_mem_crc 168 68 -100
+ seaboard : all -9 bss -28 rodata -29 text +48
+ u-boot: add: 1/0, grow: 3/-2 bytes: 160/-104 (56)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ ext4fs_read_file 548 568 +20
+ run_list_real 1996 2000 +4
+ do_nandboot 760 756 -4
+ do_mem_crc 168 68 -100
+ colibri_t20_iris: all -9 rodata -29 text +20
+ u-boot: add: 1/0, grow: 2/-3 bytes: 140/-112 (28)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ read_abs_bbt 204 208 +4
+ do_nandboot 760 756 -4
+ ext4fs_read_file 576 568 -8
+ do_mem_crc 168 68 -100
+ ventana : all -37 bss -12 rodata -29 text +4
+ u-boot: add: 1/0, grow: 1/-3 bytes: 136/-124 (12)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ ext4fs_iterate_dir 672 668 -4
+ ext4fs_read_file 568 548 -20
+ do_mem_crc 168 68 -100
+ harmony : all -37 bss -16 rodata -29 text +8
+ u-boot: add: 1/0, grow: 2/-3 bytes: 140/-124 (16)
+ function old new delta
+ hash_command 80 160 +80
+ crc32_wd_buf - 56 +56
+ nand_write_oob_syndrome 428 432 +4
+ ext4fs_iterate_dir 672 668 -4
+ ext4fs_read_file 568 548 -20
+ do_mem_crc 168 68 -100
+ medcom-wide : all -417 bss +28 data -16 rodata -93 text -336
+ u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288)
+ function old new delta
+ crc32_wd_buf - 56 +56
+ do_fat_read_at 2872 2904 +32
+ hash_algo 16 - -16
+ do_mem_crc 168 68 -100
+ hash_command 420 160 -260
+ tec : all -449 bss -4 data -16 rodata -93 text -336
+ u-boot: add: 1/-1, grow: 1/-2 bytes: 88/-376 (-288)
+ function old new delta
+ crc32_wd_buf - 56 +56
+ do_fat_read_at 2872 2904 +32
+ hash_algo 16 - -16
+ do_mem_crc 168 68 -100
+ hash_command 420 160 -260
+ plutux : all -481 bss +16 data -16 rodata -93 text -388
+ u-boot: add: 1/-1, grow: 1/-3 bytes: 68/-408 (-340)
+ function old new delta
+ crc32_wd_buf - 56 +56
+ do_load_serial_bin 1688 1700 +12
+ hash_algo 16 - -16
+ do_fat_read_at 2904 2872 -32
+ do_mem_crc 168 68 -100
+ hash_command 420 160 -260
+ powerpc: (for 5/5 boards) all +37.4 data -3.2 rodata -41.8 text +82.4
+ MPC8610HPCD : all +55 rodata -29 text +84
+ u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+ function old new delta
+ hash_command - 176 +176
+ do_mem_crc 184 88 -96
+ MPC8641HPCN : all +55 rodata -29 text +84
+ u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+ function old new delta
+ hash_command - 176 +176
+ do_mem_crc 184 88 -96
+ MPC8641HPCN_36BIT: all +55 rodata -29 text +84
+ u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+ function old new delta
+ hash_command - 176 +176
+ do_mem_crc 184 88 -96
+ sbc8641d : all +55 rodata -29 text +84
+ u-boot: add: 1/0, grow: 0/-1 bytes: 176/-96 (80)
+ function old new delta
+ hash_command - 176 +176
+ do_mem_crc 184 88 -96
+ xpedite517x : all -33 data -16 rodata -93 text +76
+ u-boot: add: 1/-1, grow: 0/-1 bytes: 176/-112 (64)
+ function old new delta
+ hash_command - 176 +176
+ hash_algo 16 - -16
+ do_mem_crc 184 88 -96
+...
+
+
+This shows that commit 19 has increased text size for arm (although only one
+board was built) and by 96 bytes for powerpc. This increase was offset in both
+cases by reductions in rodata and data/bss.
+
+Shown below the summary lines is the sizes for each board. Below each board
+is the sizes for each function. This information starts with:
+
+ add - number of functions added / removed
+ grow - number of functions which grew / shrunk
+ bytes - number of bytes of code added to / removed from all functions,
+ plus the total byte change in brackets
+
+The change seems to be that hash_command() has increased by more than the
+do_mem_crc() function has decreased. The function sizes typically add up to
+roughly the text area size, but note that every read-only section except
+rodata is included in 'text', so the function total does not exactly
+correspond.
+
+It is common when refactoring code for the rodata to decrease as the text size
+increases, and vice versa.
+
+
+Other options
+=============
+
+Buildman has various other command line options. Try --help to see them.
+
+
+TODO
+====
+
+This has mostly be written in my spare time as a response to my difficulties
+in testing large series of patches. Apart from tidying up there is quite a
+bit of scope for improvement. Things like better error diffs, easier access
+to log files, error display while building. Also it would be nice it buildman
+could 'hunt' for problems, perhaps by building a few boards for each arch,
+or checking commits for changed files and building only boards which use
+those files.
+
+
+Credits
+=======
+
+Thanks to Grant Grundler <grundler@chromium.org> for his ideas for improving
+the build speed by building all commits for a board instead of the other
+way around.
+
+
+
+Simon Glass
+sjg@chromium.org
+Halloween 2012
+Updated 12-12-12
+Updated 23-02-13
diff --git a/tools/buildman/board.py b/tools/buildman/board.py
new file mode 100644
index 0000000..9f50aba
--- /dev/null
+++ b/tools/buildman/board.py
@@ -0,0 +1,167 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+class Board:
+ """A particular board that we can build"""
+ def __init__(self, target, arch, cpu, board_name, vendor, soc, options):
+ """Create a new board type.
+
+ Args:
+ target: Target name (use make <target>_config to configure)
+ arch: Architecture name (e.g. arm)
+ cpu: Cpu name (e.g. arm1136)
+ board_name: Name of board (e.g. integrator)
+ vendor: Name of vendor (e.g. armltd)
+ soc: Name of SOC, or '' if none (e.g. mx31)
+ options: board-specific options (e.g. integratorcp:CM1136)
+ """
+ self.target = target
+ self.arch = arch
+ self.cpu = cpu
+ self.board_name = board_name
+ self.vendor = vendor
+ self.soc = soc
+ self.props = [self.target, self.arch, self.cpu, self.board_name,
+ self.vendor, self.soc]
+ self.options = options
+ self.build_it = False
+
+
+class Boards:
+ """Manage a list of boards."""
+ def __init__(self):
+ # Use a simple list here, sinc OrderedDict requires Python 2.7
+ self._boards = []
+
+ def AddBoard(self, board):
+ """Add a new board to the list.
+
+ The board's target member must not already exist in the board list.
+
+ Args:
+ board: board to add
+ """
+ self._boards.append(board)
+
+ def ReadBoards(self, fname):
+ """Read a list of boards from a board file.
+
+ Create a board object for each and add it to our _boards list.
+
+ Args:
+ fname: Filename of boards.cfg file
+ """
+ with open(fname, 'r') as fd:
+ for line in fd:
+ if line[0] == '#':
+ continue
+ fields = line.split()
+ if not fields:
+ continue
+ for upto in range(len(fields)):
+ if fields[upto] == '-':
+ fields[upto] = ''
+ while len(fields) < 7:
+ fields.append('')
+
+ board = Board(*fields)
+ self.AddBoard(board)
+
+
+ def GetList(self):
+ """Return a list of available boards.
+
+ Returns:
+ List of Board objects
+ """
+ return self._boards
+
+ def GetDict(self):
+ """Build a dictionary containing all the boards.
+
+ Returns:
+ Dictionary:
+ key is board.target
+ value is board
+ """
+ board_dict = {}
+ for board in self._boards:
+ board_dict[board.target] = board
+ return board_dict
+
+ def GetSelectedDict(self):
+ """Return a dictionary containing the selected boards
+
+ Returns:
+ List of Board objects that are marked selected
+ """
+ board_dict = {}
+ for board in self._boards:
+ if board.build_it:
+ board_dict[board.target] = board
+ return board_dict
+
+ def GetSelected(self):
+ """Return a list of selected boards
+
+ Returns:
+ List of Board objects that are marked selected
+ """
+ return [board for board in self._boards if board.build_it]
+
+ def GetSelectedNames(self):
+ """Return a list of selected boards
+
+ Returns:
+ List of board names that are marked selected
+ """
+ return [board.target for board in self._boards if board.build_it]
+
+ def SelectBoards(self, args):
+ """Mark boards selected based on args
+
+ Args:
+ List of strings specifying boards to include, either named, or
+ by their target, architecture, cpu, vendor or soc. If empty, all
+ boards are selected.
+
+ Returns:
+ Dictionary which holds the number of boards which were selected
+ due to each argument, arranged by argument.
+ """
+ result = {}
+ for arg in args:
+ result[arg] = 0
+ result['all'] = 0
+
+ for board in self._boards:
+ if args:
+ for arg in args:
+ if arg in board.props:
+ if not board.build_it:
+ board.build_it = True
+ result[arg] += 1
+ result['all'] += 1
+ else:
+ board.build_it = True
+ result['all'] += 1
+
+ return result
diff --git a/tools/buildman/bsettings.py b/tools/buildman/bsettings.py
new file mode 100644
index 0000000..7e66c63
--- /dev/null
+++ b/tools/buildman/bsettings.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import ConfigParser
+import os
+
+
+def Setup(fname=''):
+ """Set up the buildman settings module by reading config files
+
+ Args:
+ config_fname: Config filename to read ('' for default)
+ """
+ global settings
+ global config_fname
+
+ settings = ConfigParser.SafeConfigParser()
+ config_fname = fname
+ if config_fname == '':
+ config_fname = '%s/.buildman' % os.getenv('HOME')
+ if config_fname:
+ settings.read(config_fname)
+
+def GetItems(section):
+ """Get the items from a section of the config.
+
+ Args:
+ section: name of section to retrieve
+
+ Returns:
+ List of (name, value) tuples for the section
+ """
+ try:
+ return settings.items(section)
+ except ConfigParser.NoSectionError as e:
+ print e
+ print ("Warning: No tool chains - please add a [toolchain] section "
+ "to your buildman config file %s. See README for details" %
+ config_fname)
+ return []
+ except:
+ raise
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
new file mode 100644
index 0000000..e426442
--- /dev/null
+++ b/tools/buildman/builder.py
@@ -0,0 +1,1445 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# Bloat-o-meter code used here Copyright 2004 Matt Mackall <mpm@selenic.com>
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import collections
+import errno
+from datetime import datetime, timedelta
+import glob
+import os
+import re
+import Queue
+import shutil
+import string
+import sys
+import threading
+import time
+
+import command
+import gitutil
+import terminal
+import toolchain
+
+
+"""
+Theory of Operation
+
+Please see README for user documentation, and you should be familiar with
+that before trying to make sense of this.
+
+Buildman works by keeping the machine as busy as possible, building different
+commits for different boards on multiple CPUs at once.
+
+The source repo (self.git_dir) contains all the commits to be built. Each
+thread works on a single board at a time. It checks out the first commit,
+configures it for that board, then builds it. Then it checks out the next
+commit and builds it (typically without re-configuring). When it runs out
+of commits, it gets another job from the builder and starts again with that
+board.
+
+Clearly the builder threads could work either way - they could check out a
+commit and then built it for all boards. Using separate directories for each
+commit/board pair they could leave their build product around afterwards
+also.
+
+The intent behind building a single board for multiple commits, is to make
+use of incremental builds. Since each commit is built incrementally from
+the previous one, builds are faster. Reconfiguring for a different board
+removes all intermediate object files.
+
+Many threads can be working at once, but each has its own working directory.
+When a thread finishes a build, it puts the output files into a result
+directory.
+
+The base directory used by buildman is normally '../<branch>', i.e.
+a directory higher than the source repository and named after the branch
+being built.
+
+Within the base directory, we have one subdirectory for each commit. Within
+that is one subdirectory for each board. Within that is the build output for
+that commit/board combination.
+
+Buildman also create working directories for each thread, in a .bm-work/
+subdirectory in the base dir.
+
+As an example, say we are building branch 'us-net' for boards 'sandbox' and
+'seaboard', and say that us-net has two commits. We will have directories
+like this:
+
+us-net/ base directory
+ 01_of_02_g4ed4ebc_net--Add-tftp-speed-/
+ sandbox/
+ u-boot.bin
+ seaboard/
+ u-boot.bin
+ 02_of_02_g4ed4ebc_net--Check-tftp-comp/
+ sandbox/
+ u-boot.bin
+ seaboard/
+ u-boot.bin
+ .bm-work/
+ 00/ working directory for thread 0 (contains source checkout)
+ build/ build output
+ 01/ working directory for thread 1
+ build/ build output
+ ...
+u-boot/ source directory
+ .git/ repository
+"""
+
+# Possible build outcomes
+OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = range(4)
+
+# Translate a commit subject into a valid filename
+trans_valid_chars = string.maketrans("/: ", "---")
+
+
+def Mkdir(dirname):
+ """Make a directory if it doesn't already exist.
+
+ Args:
+ dirname: Directory to create
+ """
+ try:
+ os.mkdir(dirname)
+ except OSError as err:
+ if err.errno == errno.EEXIST:
+ pass
+ else:
+ raise
+
+class BuilderJob:
+ """Holds information about a job to be performed by a thread
+
+ Members:
+ board: Board object to build
+ commits: List of commit options to build.
+ """
+ def __init__(self):
+ self.board = None
+ self.commits = []
+
+
+class ResultThread(threading.Thread):
+ """This thread processes results from builder threads.
+
+ It simply passes the results on to the builder. There is only one
+ result thread, and this helps to serialise the build output.
+ """
+ def __init__(self, builder):
+ """Set up a new result thread
+
+ Args:
+ builder: Builder which will be sent each result
+ """
+ threading.Thread.__init__(self)
+ self.builder = builder
+
+ def run(self):
+ """Called to start up the result thread.
+
+ We collect the next result job and pass it on to the build.
+ """
+ while True:
+ result = self.builder.out_queue.get()
+ self.builder.ProcessResult(result)
+ self.builder.out_queue.task_done()
+
+
+class BuilderThread(threading.Thread):
+ """This thread builds U-Boot for a particular board.
+
+ An input queue provides each new job. We run 'make' to build U-Boot
+ and then pass the results on to the output queue.
+
+ Members:
+ builder: The builder which contains information we might need
+ thread_num: Our thread number (0-n-1), used to decide on a
+ temporary directory
+ """
+ def __init__(self, builder, thread_num):
+ """Set up a new builder thread"""
+ threading.Thread.__init__(self)
+ self.builder = builder
+ self.thread_num = thread_num
+
+ def Make(self, commit, brd, stage, cwd, *args, **kwargs):
+ """Run 'make' on a particular commit and board.
+
+ The source code will already be checked out, so the 'commit'
+ argument is only for information.
+
+ Args:
+ commit: Commit object that is being built
+ brd: Board object that is being built
+ stage: Stage of the build. Valid stages are:
+ distclean - can be called to clean source
+ config - called to configure for a board
+ build - the main make invocation - it does the build
+ args: A list of arguments to pass to 'make'
+ kwargs: A list of keyword arguments to pass to command.RunPipe()
+
+ Returns:
+ CommandResult object
+ """
+ return self.builder.do_make(commit, brd, stage, cwd, *args,
+ **kwargs)
+
+ def RunCommit(self, commit_upto, brd, work_dir, do_config, force_build):
+ """Build a particular commit.
+
+ If the build is already done, and we are not forcing a build, we skip
+ the build and just return the previously-saved results.
+
+ Args:
+ commit_upto: Commit number to build (0...n-1)
+ brd: Board object to build
+ work_dir: Directory to which the source will be checked out
+ do_config: True to run a make <board>_config on the source
+ force_build: Force a build even if one was previously done
+
+ Returns:
+ tuple containing:
+ - CommandResult object containing the results of the build
+ - boolean indicating whether 'make config' is still needed
+ """
+ # Create a default result - it will be overwritte by the call to
+ # self.Make() below, in the event that we do a build.
+ result = command.CommandResult()
+ result.return_code = 0
+ out_dir = os.path.join(work_dir, 'build')
+
+ # Check if the job was already completed last time
+ done_file = self.builder.GetDoneFile(commit_upto, brd.target)
+ result.already_done = os.path.exists(done_file)
+ if result.already_done and not force_build:
+ # Get the return code from that build and use it
+ with open(done_file, 'r') as fd:
+ result.return_code = int(fd.readline())
+ err_file = self.builder.GetErrFile(commit_upto, brd.target)
+ if os.path.exists(err_file) and os.stat(err_file).st_size:
+ result.stderr = 'bad'
+ else:
+ # We are going to have to build it. First, get a toolchain
+ if not self.toolchain:
+ try:
+ self.toolchain = self.builder.toolchains.Select(brd.arch)
+ except ValueError as err:
+ result.return_code = 10
+ result.stdout = ''
+ result.stderr = str(err)
+ # TODO(sjg@chromium.org): This gets swallowed, but needs
+ # to be reported.
+
+ if self.toolchain:
+ # Checkout the right commit
+ if commit_upto is not None:
+ commit = self.builder.commits[commit_upto]
+ if self.builder.checkout:
+ git_dir = os.path.join(work_dir, '.git')
+ gitutil.Checkout(commit.hash, git_dir, work_dir,
+ force=True)
+ else:
+ commit = self.builder.commit # Ick, fix this for BuildCommits()
+
+ # Set up the environment and command line
+ env = self.toolchain.MakeEnvironment()
+ Mkdir(out_dir)
+ args = ['O=build', '-s']
+ if self.builder.num_jobs is not None:
+ args.extend(['-j', str(self.builder.num_jobs)])
+ config_args = ['%s_config' % brd.target]
+ config_out = ''
+
+ # If we need to reconfigure, do that now
+ if do_config:
+ result = self.Make(commit, brd, 'distclean', work_dir,
+ 'distclean', *args, env=env)
+ result = self.Make(commit, brd, 'config', work_dir,
+ *(args + config_args), env=env)
+ config_out = result.combined
+ do_config = False # No need to configure next time
+ if result.return_code == 0:
+ result = self.Make(commit, brd, 'build', work_dir, *args,
+ env=env)
+ result.stdout = config_out + result.stdout
+ else:
+ result.return_code = 1
+ result.stderr = 'No tool chain for %s\n' % brd.arch
+ result.already_done = False
+
+ result.toolchain = self.toolchain
+ result.brd = brd
+ result.commit_upto = commit_upto
+ result.out_dir = out_dir
+ return result, do_config
+
+ def _WriteResult(self, result, keep_outputs):
+ """Write a built result to the output directory.
+
+ Args:
+ result: CommandResult object containing result to write
+ keep_outputs: True to store the output binaries, False
+ to delete them
+ """
+ # Fatal error
+ if result.return_code < 0:
+ return
+
+ # Aborted?
+ if result.stderr and 'No child processes' in result.stderr:
+ return
+
+ if result.already_done:
+ return
+
+ # Write the output and stderr
+ output_dir = self.builder._GetOutputDir(result.commit_upto)
+ Mkdir(output_dir)
+ build_dir = self.builder.GetBuildDir(result.commit_upto,
+ result.brd.target)
+ Mkdir(build_dir)
+
+ outfile = os.path.join(build_dir, 'log')
+ with open(outfile, 'w') as fd:
+ if result.stdout:
+ fd.write(result.stdout)
+
+ errfile = self.builder.GetErrFile(result.commit_upto,
+ result.brd.target)
+ if result.stderr:
+ with open(errfile, 'w') as fd:
+ fd.write(result.stderr)
+ elif os.path.exists(errfile):
+ os.remove(errfile)
+
+ if result.toolchain:
+ # Write the build result and toolchain information.
+ done_file = self.builder.GetDoneFile(result.commit_upto,
+ result.brd.target)
+ with open(done_file, 'w') as fd:
+ fd.write('%s' % result.return_code)
+ with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
+ print >>fd, 'gcc', result.toolchain.gcc
+ print >>fd, 'path', result.toolchain.path
+ print >>fd, 'cross', result.toolchain.cross
+ print >>fd, 'arch', result.toolchain.arch
+ fd.write('%s' % result.return_code)
+
+ with open(os.path.join(build_dir, 'toolchain'), 'w') as fd:
+ print >>fd, 'gcc', result.toolchain.gcc
+ print >>fd, 'path', result.toolchain.path
+
+ # Write out the image and function size information and an objdump
+ env = result.toolchain.MakeEnvironment()
+ lines = []
+ for fname in ['u-boot', 'spl/u-boot-spl']:
+ cmd = ['%snm' % self.toolchain.cross, '--size-sort', fname]
+ nm_result = command.RunPipe([cmd], capture=True,
+ capture_stderr=True, cwd=result.out_dir,
+ raise_on_error=False, env=env)
+ if nm_result.stdout:
+ nm = self.builder.GetFuncSizesFile(result.commit_upto,
+ result.brd.target, fname)
+ with open(nm, 'w') as fd:
+ print >>fd, nm_result.stdout,
+
+ cmd = ['%sobjdump' % self.toolchain.cross, '-h', fname]
+ dump_result = command.RunPipe([cmd], capture=True,
+ capture_stderr=True, cwd=result.out_dir,
+ raise_on_error=False, env=env)
+ rodata_size = ''
+ if dump_result.stdout:
+ objdump = self.builder.GetObjdumpFile(result.commit_upto,
+ result.brd.target, fname)
+ with open(objdump, 'w') as fd:
+ print >>fd, dump_result.stdout,
+ for line in dump_result.stdout.splitlines():
+ fields = line.split()
+ if len(fields) > 5 and fields[1] == '.rodata':
+ rodata_size = fields[2]
+
+ cmd = ['%ssize' % self.toolchain.cross, fname]
+ size_result = command.RunPipe([cmd], capture=True,
+ capture_stderr=True, cwd=result.out_dir,
+ raise_on_error=False, env=env)
+ if size_result.stdout:
+ lines.append(size_result.stdout.splitlines()[1] + ' ' +
+ rodata_size)
+
+ # Write out the image sizes file. This is similar to the output
+ # of binutil's 'size' utility, but it omits the header line and
+ # adds an additional hex value at the end of each line for the
+ # rodata size
+ if len(lines):
+ sizes = self.builder.GetSizesFile(result.commit_upto,
+ result.brd.target)
+ with open(sizes, 'w') as fd:
+ print >>fd, '\n'.join(lines)
+
+ # Now write the actual build output
+ if keep_outputs:
+ patterns = ['u-boot', '*.bin', 'u-boot.dtb', '*.map',
+ 'include/autoconf.mk', 'spl/u-boot-spl',
+ 'spl/u-boot-spl.bin']
+ for pattern in patterns:
+ file_list = glob.glob(os.path.join(result.out_dir, pattern))
+ for fname in file_list:
+ shutil.copy(fname, build_dir)
+
+
+ def RunJob(self, job):
+ """Run a single job
+
+ A job consists of a building a list of commits for a particular board.
+
+ Args:
+ job: Job to build
+ """
+ brd = job.board
+ work_dir = self.builder.GetThreadDir(self.thread_num)
+ self.toolchain = None
+ if job.commits:
+ # Run 'make board_config' on the first commit
+ do_config = True
+ commit_upto = 0
+ force_build = False
+ for commit_upto in range(0, len(job.commits), job.step):
+ result, request_config = self.RunCommit(commit_upto, brd,
+ work_dir, do_config,
+ force_build or self.builder.force_build)
+ failed = result.return_code or result.stderr
+ if failed and not do_config:
+ # If our incremental build failed, try building again
+ # with a reconfig.
+ if self.builder.force_config_on_failure:
+ result, request_config = self.RunCommit(commit_upto,
+ brd, work_dir, True, True)
+ do_config = request_config
+
+ # If we built that commit, then config is done. But if we got
+ # an warning, reconfig next time to force it to build the same
+ # files that created warnings this time. Otherwise an
+ # incremental build may not build the same file, and we will
+ # think that the warning has gone away.
+ # We could avoid this by using -Werror everywhere...
+ # For errors, the problem doesn't happen, since presumably
+ # the build stopped and didn't generate output, so will retry
+ # that file next time. So we could detect warnings and deal
+ # with them specially here. For now, we just reconfigure if
+ # anything goes work.
+ # Of course this is substantially slower if there are build
+ # errors/warnings (e.g. 2-3x slower even if only 10% of builds
+ # have problems).
+ if (failed and not result.already_done and not do_config and
+ self.builder.force_config_on_failure):
+ # If this build failed, try the next one with a
+ # reconfigure.
+ # Sometimes if the board_config.h file changes it can mess
+ # with dependencies, and we get:
+ # make: *** No rule to make target `include/autoconf.mk',
+ # needed by `depend'.
+ do_config = True
+ force_build = True
+ else:
+ force_build = False
+ if self.builder.force_config_on_failure:
+ if failed:
+ do_config = True
+ result.commit_upto = commit_upto
+ if result.return_code < 0:
+ raise ValueError('Interrupt')
+
+ # We have the build results, so output the result
+ self._WriteResult(result, job.keep_outputs)
+ self.builder.out_queue.put(result)
+ else:
+ # Just build the currently checked-out build
+ result = self.RunCommit(None, True)
+ result.commit_upto = self.builder.upto
+ self.builder.out_queue.put(result)
+
+ def run(self):
+ """Our thread's run function
+
+ This thread picks a job from the queue, runs it, and then goes to the
+ next job.
+ """
+ alive = True
+ while True:
+ job = self.builder.queue.get()
+ try:
+ if self.builder.active and alive:
+ self.RunJob(job)
+ except Exception as err:
+ alive = False
+ print err
+ self.builder.queue.task_done()
+
+
+class Builder:
+ """Class for building U-Boot for a particular commit.
+
+ Public members: (many should ->private)
+ active: True if the builder is active and has not been stopped
+ already_done: Number of builds already completed
+ base_dir: Base directory to use for builder
+ checkout: True to check out source, False to skip that step.
+ This is used for testing.
+ col: terminal.Color() object
+ count: Number of commits to build
+ do_make: Method to call to invoke Make
+ fail: Number of builds that failed due to error
+ force_build: Force building even if a build already exists
+ force_config_on_failure: If a commit fails for a board, disable
+ incremental building for the next commit we build for that
+ board, so that we will see all warnings/errors again.
+ git_dir: Git directory containing source repository
+ last_line_len: Length of the last line we printed (used for erasing
+ it with new progress information)
+ num_jobs: Number of jobs to run at once (passed to make as -j)
+ num_threads: Number of builder threads to run
+ out_queue: Queue of results to process
+ re_make_err: Compiled regular expression for ignore_lines
+ queue: Queue of jobs to run
+ threads: List of active threads
+ toolchains: Toolchains object to use for building
+ upto: Current commit number we are building (0.count-1)
+ warned: Number of builds that produced at least one warning
+
+ Private members:
+ _base_board_dict: Last-summarised Dict of boards
+ _base_err_lines: Last-summarised list of errors
+ _build_period_us: Time taken for a single build (float object).
+ _complete_delay: Expected delay until completion (timedelta)
+ _next_delay_update: Next time we plan to display a progress update
+ (datatime)
+ _show_unknown: Show unknown boards (those not built) in summary
+ _timestamps: List of timestamps for the completion of the last
+ last _timestamp_count builds. Each is a datetime object.
+ _timestamp_count: Number of timestamps to keep in our list.
+ _working_dir: Base working directory containing all threads
+ """
+ class Outcome:
+ """Records a build outcome for a single make invocation
+
+ Public Members:
+ rc: Outcome value (OUTCOME_...)
+ err_lines: List of error lines or [] if none
+ sizes: Dictionary of image size information, keyed by filename
+ - Each value is itself a dictionary containing
+ values for 'text', 'data' and 'bss', being the integer
+ size in bytes of each section.
+ func_sizes: Dictionary keyed by filename - e.g. 'u-boot'. Each
+ value is itself a dictionary:
+ key: function name
+ value: Size of function in bytes
+ """
+ def __init__(self, rc, err_lines, sizes, func_sizes):
+ self.rc = rc
+ self.err_lines = err_lines
+ self.sizes = sizes
+ self.func_sizes = func_sizes
+
+ def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
+ checkout=True, show_unknown=True, step=1):
+ """Create a new Builder object
+
+ Args:
+ toolchains: Toolchains object to use for building
+ base_dir: Base directory to use for builder
+ git_dir: Git directory containing source repository
+ num_threads: Number of builder threads to run
+ num_jobs: Number of jobs to run at once (passed to make as -j)
+ checkout: True to check out source, False to skip that step.
+ This is used for testing.
+ show_unknown: Show unknown boards (those not built) in summary
+ step: 1 to process every commit, n to process every nth commit
+ """
+ self.toolchains = toolchains
+ self.base_dir = base_dir
+ self._working_dir = os.path.join(base_dir, '.bm-work')
+ self.threads = []
+ self.active = True
+ self.do_make = self.Make
+ self.checkout = checkout
+ self.num_threads = num_threads
+ self.num_jobs = num_jobs
+ self.already_done = 0
+ self.force_build = False
+ self.git_dir = git_dir
+ self._show_unknown = show_unknown
+ self._timestamp_count = 10
+ self._build_period_us = None
+ self._complete_delay = None
+ self._next_delay_update = datetime.now()
+ self.force_config_on_failure = True
+ self._step = step
+
+ self.col = terminal.Color()
+
+ self.queue = Queue.Queue()
+ self.out_queue = Queue.Queue()
+ for i in range(self.num_threads):
+ t = BuilderThread(self, i)
+ t.setDaemon(True)
+ t.start()
+ self.threads.append(t)
+
+ self.last_line_len = 0
+ t = ResultThread(self)
+ t.setDaemon(True)
+ t.start()
+ self.threads.append(t)
+
+ ignore_lines = ['(make.*Waiting for unfinished)', '(Segmentation fault)']
+ self.re_make_err = re.compile('|'.join(ignore_lines))
+
+ def __del__(self):
+ """Get rid of all threads created by the builder"""
+ for t in self.threads:
+ del t
+
+ def _AddTimestamp(self):
+ """Add a new timestamp to the list and record the build period.
+
+ The build period is the length of time taken to perform a single
+ build (one board, one commit).
+ """
+ now = datetime.now()
+ self._timestamps.append(now)
+ count = len(self._timestamps)
+ delta = self._timestamps[-1] - self._timestamps[0]
+ seconds = delta.total_seconds()
+
+ # If we have enough data, estimate build period (time taken for a
+ # single build) and therefore completion time.
+ if count > 1 and self._next_delay_update < now:
+ self._next_delay_update = now + timedelta(seconds=2)
+ if seconds > 0:
+ self._build_period = float(seconds) / count
+ todo = self.count - self.upto
+ self._complete_delay = timedelta(microseconds=
+ self._build_period * todo * 1000000)
+ # Round it
+ self._complete_delay -= timedelta(
+ microseconds=self._complete_delay.microseconds)
+
+ if seconds > 60:
+ self._timestamps.popleft()
+ count -= 1
+
+ def ClearLine(self, length):
+ """Clear any characters on the current line
+
+ Make way for a new line of length 'length', by outputting enough
+ spaces to clear out the old line. Then remember the new length for
+ next time.
+
+ Args:
+ length: Length of new line, in characters
+ """
+ if length < self.last_line_len:
+ print ' ' * (self.last_line_len - length),
+ print '\r',
+ self.last_line_len = length
+ sys.stdout.flush()
+
+ def SelectCommit(self, commit, checkout=True):
+ """Checkout the selected commit for this build
+ """
+ self.commit = commit
+ if checkout and self.checkout:
+ gitutil.Checkout(commit.hash)
+
+ def Make(self, commit, brd, stage, cwd, *args, **kwargs):
+ """Run make
+
+ Args:
+ commit: Commit object that is being built
+ brd: Board object that is being built
+ stage: Stage that we are at (distclean, config, build)
+ cwd: Directory where make should be run
+ args: Arguments to pass to make
+ kwargs: Arguments to pass to command.RunPipe()
+ """
+ cmd = ['make'] + list(args)
+ result = command.RunPipe([cmd], capture=True, capture_stderr=True,
+ cwd=cwd, raise_on_error=False, **kwargs)
+ return result
+
+ def ProcessResult(self, result):
+ """Process the result of a build, showing progress information
+
+ Args:
+ result: A CommandResult object
+ """
+ col = terminal.Color()
+ if result:
+ target = result.brd.target
+
+ if result.return_code < 0:
+ self.active = False
+ command.StopAll()
+ return
+
+ self.upto += 1
+ if result.return_code != 0:
+ self.fail += 1
+ elif result.stderr:
+ self.warned += 1
+ if result.already_done:
+ self.already_done += 1
+ else:
+ target = '(starting)'
+
+ # Display separate counts for ok, warned and fail
+ ok = self.upto - self.warned - self.fail
+ line = '\r' + self.col.Color(self.col.GREEN, '%5d' % ok)
+ line += self.col.Color(self.col.YELLOW, '%5d' % self.warned)
+ line += self.col.Color(self.col.RED, '%5d' % self.fail)
+
+ name = ' /%-5d ' % self.count
+
+ # Add our current completion time estimate
+ self._AddTimestamp()
+ if self._complete_delay:
+ name += '%s : ' % self._complete_delay
+ # When building all boards for a commit, we can print a commit
+ # progress message.
+ if result and result.commit_upto is None:
+ name += 'commit %2d/%-3d' % (self.commit_upto + 1,
+ self.commit_count)
+
+ name += target
+ print line + name,
+ length = 13 + len(name)
+ self.ClearLine(length)
+
+ def _GetOutputDir(self, commit_upto):
+ """Get the name of the output directory for a commit number
+
+ The output directory is typically .../<branch>/<commit>.
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ """
+ commit = self.commits[commit_upto]
+ subject = commit.subject.translate(trans_valid_chars)
+ commit_dir = ('%02d_of_%02d_g%s_%s' % (commit_upto + 1,
+ self.commit_count, commit.hash, subject[:20]))
+ output_dir = os.path.join(self.base_dir, commit_dir)
+ return output_dir
+
+ def GetBuildDir(self, commit_upto, target):
+ """Get the name of the build directory for a commit number
+
+ The build directory is typically .../<branch>/<commit>/<target>.
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ """
+ output_dir = self._GetOutputDir(commit_upto)
+ return os.path.join(output_dir, target)
+
+ def GetDoneFile(self, commit_upto, target):
+ """Get the name of the done file for a commit number
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ """
+ return os.path.join(self.GetBuildDir(commit_upto, target), 'done')
+
+ def GetSizesFile(self, commit_upto, target):
+ """Get the name of the sizes file for a commit number
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ """
+ return os.path.join(self.GetBuildDir(commit_upto, target), 'sizes')
+
+ def GetFuncSizesFile(self, commit_upto, target, elf_fname):
+ """Get the name of the funcsizes file for a commit number and ELF file
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ elf_fname: Filename of elf image
+ """
+ return os.path.join(self.GetBuildDir(commit_upto, target),
+ '%s.sizes' % elf_fname.replace('/', '-'))
+
+ def GetObjdumpFile(self, commit_upto, target, elf_fname):
+ """Get the name of the objdump file for a commit number and ELF file
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ elf_fname: Filename of elf image
+ """
+ return os.path.join(self.GetBuildDir(commit_upto, target),
+ '%s.objdump' % elf_fname.replace('/', '-'))
+
+ def GetErrFile(self, commit_upto, target):
+ """Get the name of the err file for a commit number
+
+ Args:
+ commit_upto: Commit number to use (0..self.count-1)
+ target: Target name
+ """
+ output_dir = self.GetBuildDir(commit_upto, target)
+ return os.path.join(output_dir, 'err')
+
+ def FilterErrors(self, lines):
+ """Filter out errors in which we have no interest
+
+ We should probably use map().
+
+ Args:
+ lines: List of error lines, each a string
+ Returns:
+ New list with only interesting lines included
+ """
+ out_lines = []
+ for line in lines:
+ if not self.re_make_err.search(line):
+ out_lines.append(line)
+ return out_lines
+
+ def ReadFuncSizes(self, fname, fd):
+ """Read function sizes from the output of 'nm'
+
+ Args:
+ fd: File containing data to read
+ fname: Filename we are reading from (just for errors)
+
+ Returns:
+ Dictionary containing size of each function in bytes, indexed by
+ function name.
+ """
+ sym = {}
+ for line in fd.readlines():
+ try:
+ size, type, name = line[:-1].split()
+ except:
+ print "Invalid line in file '%s': '%s'" % (fname, line[:-1])
+ continue
+ if type in 'tTdDbB':
+ # function names begin with '.' on 64-bit powerpc
+ if '.' in name[1:]:
+ name = 'static.' + name.split('.')[0]
+ sym[name] = sym.get(name, 0) + int(size, 16)
+ return sym
+
+ def GetBuildOutcome(self, commit_upto, target, read_func_sizes):
+ """Work out the outcome of a build.
+
+ Args:
+ commit_upto: Commit number to check (0..n-1)
+ target: Target board to check
+ read_func_sizes: True to read function size information
+
+ Returns:
+ Outcome object
+ """
+ done_file = self.GetDoneFile(commit_upto, target)
+ sizes_file = self.GetSizesFile(commit_upto, target)
+ sizes = {}
+ func_sizes = {}
+ if os.path.exists(done_file):
+ with open(done_file, 'r') as fd:
+ return_code = int(fd.readline())
+ err_lines = []
+ err_file = self.GetErrFile(commit_upto, target)
+ if os.path.exists(err_file):
+ with open(err_file, 'r') as fd:
+ err_lines = self.FilterErrors(fd.readlines())
+
+ # Decide whether the build was ok, failed or created warnings
+ if return_code:
+ rc = OUTCOME_ERROR
+ elif len(err_lines):
+ rc = OUTCOME_WARNING
+ else:
+ rc = OUTCOME_OK
+
+ # Convert size information to our simple format
+ if os.path.exists(sizes_file):
+ with open(sizes_file, 'r') as fd:
+ for line in fd.readlines():
+ values = line.split()
+ rodata = 0
+ if len(values) > 6:
+ rodata = int(values[6], 16)
+ size_dict = {
+ 'all' : int(values[0]) + int(values[1]) +
+ int(values[2]),
+ 'text' : int(values[0]) - rodata,
+ 'data' : int(values[1]),
+ 'bss' : int(values[2]),
+ 'rodata' : rodata,
+ }
+ sizes[values[5]] = size_dict
+
+ if read_func_sizes:
+ pattern = self.GetFuncSizesFile(commit_upto, target, '*')
+ for fname in glob.glob(pattern):
+ with open(fname, 'r') as fd:
+ dict_name = os.path.basename(fname).replace('.sizes',
+ '')
+ func_sizes[dict_name] = self.ReadFuncSizes(fname, fd)
+
+ return Builder.Outcome(rc, err_lines, sizes, func_sizes)
+
+ return Builder.Outcome(OUTCOME_UNKNOWN, [], {}, {})
+
+ def GetResultSummary(self, boards_selected, commit_upto, read_func_sizes):
+ """Calculate a summary of the results of building a commit.
+
+ Args:
+ board_selected: Dict containing boards to summarise
+ commit_upto: Commit number to summarize (0..self.count-1)
+ read_func_sizes: True to read function size information
+
+ Returns:
+ Tuple:
+ Dict containing boards which passed building this commit.
+ keyed by board.target
+ List containing a summary of error/warning lines
+ """
+ board_dict = {}
+ err_lines_summary = []
+
+ for board in boards_selected.itervalues():
+ outcome = self.GetBuildOutcome(commit_upto, board.target,
+ read_func_sizes)
+ board_dict[board.target] = outcome
+ for err in outcome.err_lines:
+ if err and not err.rstrip() in err_lines_summary:
+ err_lines_summary.append(err.rstrip())
+ return board_dict, err_lines_summary
+
+ def AddOutcome(self, board_dict, arch_list, changes, char, color):
+ """Add an output to our list of outcomes for each architecture
+
+ This simple function adds failing boards (changes) to the
+ relevant architecture string, so we can print the results out
+ sorted by architecture.
+
+ Args:
+ board_dict: Dict containing all boards
+ arch_list: Dict keyed by arch name. Value is a string containing
+ a list of board names which failed for that arch.
+ changes: List of boards to add to arch_list
+ color: terminal.Colour object
+ """
+ done_arch = {}
+ for target in changes:
+ if target in board_dict:
+ arch = board_dict[target].arch
+ else:
+ arch = 'unknown'
+ str = self.col.Color(color, ' ' + target)
+ if not arch in done_arch:
+ str = self.col.Color(color, char) + ' ' + str
+ done_arch[arch] = True
+ if not arch in arch_list:
+ arch_list[arch] = str
+ else:
+ arch_list[arch] += str
+
+
+ def ColourNum(self, num):
+ color = self.col.RED if num > 0 else self.col.GREEN
+ if num == 0:
+ return '0'
+ return self.col.Color(color, str(num))
+
+ def ResetResultSummary(self, board_selected):
+ """Reset the results summary ready for use.
+
+ Set up the base board list to be all those selected, and set the
+ error lines to empty.
+
+ Following this, calls to PrintResultSummary() will use this
+ information to work out what has changed.
+
+ Args:
+ board_selected: Dict containing boards to summarise, keyed by
+ board.target
+ """
+ self._base_board_dict = {}
+ for board in board_selected:
+ self._base_board_dict[board] = Builder.Outcome(0, [], [], {})
+ self._base_err_lines = []
+
+ def PrintFuncSizeDetail(self, fname, old, new):
+ grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
+ delta, common = [], {}
+
+ for a in old:
+ if a in new:
+ common[a] = 1
+
+ for name in old:
+ if name not in common:
+ remove += 1
+ down += old[name]
+ delta.append([-old[name], name])
+
+ for name in new:
+ if name not in common:
+ add += 1
+ up += new[name]
+ delta.append([new[name], name])
+
+ for name in common:
+ diff = new.get(name, 0) - old.get(name, 0)
+ if diff > 0:
+ grow, up = grow + 1, up + diff
+ elif diff < 0:
+ shrink, down = shrink + 1, down - diff
+ delta.append([diff, name])
+
+ delta.sort()
+ delta.reverse()
+
+ args = [add, -remove, grow, -shrink, up, -down, up - down]
+ if max(args) == 0:
+ return
+ args = [self.ColourNum(x) for x in args]
+ indent = ' ' * 15
+ print ('%s%s: add: %s/%s, grow: %s/%s bytes: %s/%s (%s)' %
+ tuple([indent, self.col.Color(self.col.YELLOW, fname)] + args))
+ print '%s %-38s %7s %7s %+7s' % (indent, 'function', 'old', 'new',
+ 'delta')
+ for diff, name in delta:
+ if diff:
+ color = self.col.RED if diff > 0 else self.col.GREEN
+ msg = '%s %-38s %7s %7s %+7d' % (indent, name,
+ old.get(name, '-'), new.get(name,'-'), diff)
+ print self.col.Color(color, msg)
+
+
+ def PrintSizeDetail(self, target_list, show_bloat):
+ """Show details size information for each board
+
+ Args:
+ target_list: List of targets, each a dict containing:
+ 'target': Target name
+ 'total_diff': Total difference in bytes across all areas
+ <part_name>: Difference for that part
+ show_bloat: Show detail for each function
+ """
+ targets_by_diff = sorted(target_list, reverse=True,
+ key=lambda x: x['_total_diff'])
+ for result in targets_by_diff:
+ printed_target = False
+ for name in sorted(result):
+ diff = result[name]
+ if name.startswith('_'):
+ continue
+ if diff != 0:
+ color = self.col.RED if diff > 0 else self.col.GREEN
+ msg = ' %s %+d' % (name, diff)
+ if not printed_target:
+ print '%10s %-15s:' % ('', result['_target']),
+ printed_target = True
+ print self.col.Color(color, msg),
+ if printed_target:
+ print
+ if show_bloat:
+ target = result['_target']
+ outcome = result['_outcome']
+ base_outcome = self._base_board_dict[target]
+ for fname in outcome.func_sizes:
+ self.PrintFuncSizeDetail(fname,
+ base_outcome.func_sizes[fname],
+ outcome.func_sizes[fname])
+
+
+ def PrintSizeSummary(self, board_selected, board_dict, show_detail,
+ show_bloat):
+ """Print a summary of image sizes broken down by section.
+
+ The summary takes the form of one line per architecture. The
+ line contains deltas for each of the sections (+ means the section
+ got bigger, - means smaller). The nunmbers are the average number
+ of bytes that a board in this section increased by.
+
+ For example:
+ powerpc: (622 boards) text -0.0
+ arm: (285 boards) text -0.0
+ nds32: (3 boards) text -8.0
+
+ Args:
+ board_selected: Dict containing boards to summarise, keyed by
+ board.target
+ board_dict: Dict containing boards for which we built this
+ commit, keyed by board.target. The value is an Outcome object.
+ show_detail: Show detail for each board
+ show_bloat: Show detail for each function
+ """
+ arch_list = {}
+ arch_count = {}
+
+ # Calculate changes in size for different image parts
+ # The previous sizes are in Board.sizes, for each board
+ for target in board_dict:
+ if target not in board_selected:
+ continue
+ base_sizes = self._base_board_dict[target].sizes
+ outcome = board_dict[target]
+ sizes = outcome.sizes
+
+ # Loop through the list of images, creating a dict of size
+ # changes for each image/part. We end up with something like
+ # {'target' : 'snapper9g45, 'data' : 5, 'u-boot-spl:text' : -4}
+ # which means that U-Boot data increased by 5 bytes and SPL
+ # text decreased by 4.
+ err = {'_target' : target}
+ for image in sizes:
+ if image in base_sizes:
+ base_image = base_sizes[image]
+ # Loop through the text, data, bss parts
+ for part in sorted(sizes[image]):
+ diff = sizes[image][part] - base_image[part]
+ col = None
+ if diff:
+ if image == 'u-boot':
+ name = part
+ else:
+ name = image + ':' + part
+ err[name] = diff
+ arch = board_selected[target].arch
+ if not arch in arch_count:
+ arch_count[arch] = 1
+ else:
+ arch_count[arch] += 1
+ if not sizes:
+ pass # Only add to our list when we have some stats
+ elif not arch in arch_list:
+ arch_list[arch] = [err]
+ else:
+ arch_list[arch].append(err)
+
+ # We now have a list of image size changes sorted by arch
+ # Print out a summary of these
+ for arch, target_list in arch_list.iteritems():
+ # Get total difference for each type
+ totals = {}
+ for result in target_list:
+ total = 0
+ for name, diff in result.iteritems():
+ if name.startswith('_'):
+ continue
+ total += diff
+ if name in totals:
+ totals[name] += diff
+ else:
+ totals[name] = diff
+ result['_total_diff'] = total
+ result['_outcome'] = board_dict[result['_target']]
+
+ count = len(target_list)
+ printed_arch = False
+ for name in sorted(totals):
+ diff = totals[name]
+ if diff:
+ # Display the average difference in this name for this
+ # architecture
+ avg_diff = float(diff) / count
+ color = self.col.RED if avg_diff > 0 else self.col.GREEN
+ msg = ' %s %+1.1f' % (name, avg_diff)
+ if not printed_arch:
+ print '%10s: (for %d/%d boards)' % (arch, count,
+ arch_count[arch]),
+ printed_arch = True
+ print self.col.Color(color, msg),
+
+ if printed_arch:
+ print
+ if show_detail:
+ self.PrintSizeDetail(target_list, show_bloat)
+
+
+ def PrintResultSummary(self, board_selected, board_dict, err_lines,
+ show_sizes, show_detail, show_bloat):
+ """Compare results with the base results and display delta.
+
+ Only boards mentioned in board_selected will be considered. This
+ function is intended to be called repeatedly with the results of
+ each commit. It therefore shows a 'diff' between what it saw in
+ the last call and what it sees now.
+
+ Args:
+ board_selected: Dict containing boards to summarise, keyed by
+ board.target
+ board_dict: Dict containing boards for which we built this
+ commit, keyed by board.target. The value is an Outcome object.
+ err_lines: A list of errors for this commit, or [] if there is
+ none, or we don't want to print errors
+ show_sizes: Show image size deltas
+ show_detail: Show detail for each board
+ show_bloat: Show detail for each function
+ """
+ better = [] # List of boards fixed since last commit
+ worse = [] # List of new broken boards since last commit
+ new = [] # List of boards that didn't exist last time
+ unknown = [] # List of boards that were not built
+
+ for target in board_dict:
+ if target not in board_selected:
+ continue
+
+ # If the board was built last time, add its outcome to a list
+ if target in self._base_board_dict:
+ base_outcome = self._base_board_dict[target].rc
+ outcome = board_dict[target]
+ if outcome.rc == OUTCOME_UNKNOWN:
+ unknown.append(target)
+ elif outcome.rc < base_outcome:
+ better.append(target)
+ elif outcome.rc > base_outcome:
+ worse.append(target)
+ else:
+ new.append(target)
+
+ # Get a list of errors that have appeared, and disappeared
+ better_err = []
+ worse_err = []
+ for line in err_lines:
+ if line not in self._base_err_lines:
+ worse_err.append('+' + line)
+ for line in self._base_err_lines:
+ if line not in err_lines:
+ better_err.append('-' + line)
+
+ # Display results by arch
+ if better or worse or unknown or new or worse_err or better_err:
+ arch_list = {}
+ self.AddOutcome(board_selected, arch_list, better, '',
+ self.col.GREEN)
+ self.AddOutcome(board_selected, arch_list, worse, '+',
+ self.col.RED)
+ self.AddOutcome(board_selected, arch_list, new, '*', self.col.BLUE)
+ if self._show_unknown:
+ self.AddOutcome(board_selected, arch_list, unknown, '?',
+ self.col.MAGENTA)
+ for arch, target_list in arch_list.iteritems():
+ print '%10s: %s' % (arch, target_list)
+ if better_err:
+ print self.col.Color(self.col.GREEN, '\n'.join(better_err))
+ if worse_err:
+ print self.col.Color(self.col.RED, '\n'.join(worse_err))
+
+ if show_sizes:
+ self.PrintSizeSummary(board_selected, board_dict, show_detail,
+ show_bloat)
+
+ # Save our updated information for the next call to this function
+ self._base_board_dict = board_dict
+ self._base_err_lines = err_lines
+
+ # Get a list of boards that did not get built, if needed
+ not_built = []
+ for board in board_selected:
+ if not board in board_dict:
+ not_built.append(board)
+ if not_built:
+ print "Boards not built (%d): %s" % (len(not_built),
+ ', '.join(not_built))
+
+
+ def ShowSummary(self, commits, board_selected, show_errors, show_sizes,
+ show_detail, show_bloat):
+ """Show a build summary for U-Boot for a given board list.
+
+ Reset the result summary, then repeatedly call GetResultSummary on
+ each commit's results, then display the differences we see.
+
+ Args:
+ commit: Commit objects to summarise
+ board_selected: Dict containing boards to summarise
+ show_errors: Show errors that occured
+ show_sizes: Show size deltas
+ show_detail: Show detail for each board
+ show_bloat: Show detail for each function
+ """
+ self.commit_count = len(commits)
+ self.commits = commits
+ self.ResetResultSummary(board_selected)
+
+ for commit_upto in range(0, self.commit_count, self._step):
+ board_dict, err_lines = self.GetResultSummary(board_selected,
+ commit_upto, read_func_sizes=show_bloat)
+ msg = '%02d: %s' % (commit_upto + 1, commits[commit_upto].subject)
+ print self.col.Color(self.col.BLUE, msg)
+ self.PrintResultSummary(board_selected, board_dict,
+ err_lines if show_errors else [], show_sizes, show_detail,
+ show_bloat)
+
+
+ def SetupBuild(self, board_selected, commits):
+ """Set up ready to start a build.
+
+ Args:
+ board_selected: Selected boards to build
+ commits: Selected commits to build
+ """
+ # First work out how many commits we will build
+ count = (len(commits) + self._step - 1) / self._step
+ self.count = len(board_selected) * count
+ self.upto = self.warned = self.fail = 0
+ self._timestamps = collections.deque()
+
+ def BuildBoardsForCommit(self, board_selected, keep_outputs):
+ """Build all boards for a single commit"""
+ self.SetupBuild(board_selected)
+ self.count = len(board_selected)
+ for brd in board_selected.itervalues():
+ job = BuilderJob()
+ job.board = brd
+ job.commits = None
+ job.keep_outputs = keep_outputs
+ self.queue.put(brd)
+
+ self.queue.join()
+ self.out_queue.join()
+ print
+ self.ClearLine(0)
+
+ def BuildCommits(self, commits, board_selected, show_errors, keep_outputs):
+ """Build all boards for all commits (non-incremental)"""
+ self.commit_count = len(commits)
+
+ self.ResetResultSummary(board_selected)
+ for self.commit_upto in range(self.commit_count):
+ self.SelectCommit(commits[self.commit_upto])
+ self.SelectOutputDir()
+ Mkdir(self.output_dir)
+
+ self.BuildBoardsForCommit(board_selected, keep_outputs)
+ board_dict, err_lines = self.GetResultSummary()
+ self.PrintResultSummary(board_selected, board_dict,
+ err_lines if show_errors else [])
+
+ if self.already_done:
+ print '%d builds already done' % self.already_done
+
+ def GetThreadDir(self, thread_num):
+ """Get the directory path to the working dir for a thread.
+
+ Args:
+ thread_num: Number of thread to check.
+ """
+ return os.path.join(self._working_dir, '%02d' % thread_num)
+
+ def _PrepareThread(self, thread_num):
+ """Prepare the working directory for a thread.
+
+ This clones or fetches the repo into the thread's work directory.
+
+ Args:
+ thread_num: Thread number (0, 1, ...)
+ """
+ thread_dir = self.GetThreadDir(thread_num)
+ Mkdir(thread_dir)
+ git_dir = os.path.join(thread_dir, '.git')
+
+ # Clone the repo if it doesn't already exist
+ # TODO(sjg@chromium): Perhaps some git hackery to symlink instead, so
+ # we have a private index but uses the origin repo's contents?
+ if self.git_dir:
+ src_dir = os.path.abspath(self.git_dir)
+ if os.path.exists(git_dir):
+ gitutil.Fetch(git_dir, thread_dir)
+ else:
+ print 'Cloning repo for thread %d' % thread_num
+ gitutil.Clone(src_dir, thread_dir)
+
+ def _PrepareWorkingSpace(self, max_threads):
+ """Prepare the working directory for use.
+
+ Set up the git repo for each thread.
+
+ Args:
+ max_threads: Maximum number of threads we expect to need.
+ """
+ Mkdir(self._working_dir)
+ for thread in range(max_threads):
+ self._PrepareThread(thread)
+
+ def _PrepareOutputSpace(self):
+ """Get the output directories ready to receive files.
+
+ We delete any output directories which look like ones we need to
+ create. Having left over directories is confusing when the user wants
+ to check the output manually.
+ """
+ dir_list = []
+ for commit_upto in range(self.commit_count):
+ dir_list.append(self._GetOutputDir(commit_upto))
+
+ for dirname in glob.glob(os.path.join(self.base_dir, '*')):
+ if dirname not in dir_list:
+ shutil.rmtree(dirname)
+
+ def BuildBoards(self, commits, board_selected, show_errors, keep_outputs):
+ """Build all commits for a list of boards
+
+ Args:
+ commits: List of commits to be build, each a Commit object
+ boards_selected: Dict of selected boards, key is target name,
+ value is Board object
+ show_errors: True to show summarised error/warning info
+ keep_outputs: True to save build output files
+ """
+ self.commit_count = len(commits)
+ self.commits = commits
+
+ self.ResetResultSummary(board_selected)
+ Mkdir(self.base_dir)
+ self._PrepareWorkingSpace(min(self.num_threads, len(board_selected)))
+ self._PrepareOutputSpace()
+ self.SetupBuild(board_selected, commits)
+ self.ProcessResult(None)
+
+ # Create jobs to build all commits for each board
+ for brd in board_selected.itervalues():
+ job = BuilderJob()
+ job.board = brd
+ job.commits = commits
+ job.keep_outputs = keep_outputs
+ job.step = self._step
+ self.queue.put(job)
+
+ # Wait until all jobs are started
+ self.queue.join()
+
+ # Wait until we have processed all output
+ self.out_queue.join()
+ print
+ self.ClearLine(0)
diff --git a/tools/buildman/buildman b/tools/buildman/buildman
new file mode 120000
index 0000000..e4fba2d
--- /dev/null
+++ b/tools/buildman/buildman
@@ -0,0 +1 @@
+buildman.py \ No newline at end of file
diff --git a/tools/buildman/buildman.py b/tools/buildman/buildman.py
new file mode 100755
index 0000000..7b05d0f
--- /dev/null
+++ b/tools/buildman/buildman.py
@@ -0,0 +1,126 @@
+#!/usr/bin/python
+#
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+"""See README for more information"""
+
+import multiprocessing
+from optparse import OptionParser
+import os
+import re
+import sys
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../patman'))
+
+# Our modules
+import board
+import builder
+import checkpatch
+import command
+import control
+import doctest
+import gitutil
+import patchstream
+import terminal
+import toolchain
+
+def RunTests():
+ import test
+
+ sys.argv = [sys.argv[0]]
+ suite = unittest.TestLoader().loadTestsFromTestCase(test.TestBuild)
+ result = unittest.TestResult()
+ suite.run(result)
+
+ # TODO: Surely we can just 'print' result?
+ print result
+ for test, err in result.errors:
+ print err
+ for test, err in result.failures:
+ print err
+
+
+parser = OptionParser()
+parser.add_option('-b', '--branch', type='string',
+ help='Branch name to build')
+parser.add_option('-B', '--bloat', dest='show_bloat',
+ action='store_true', default=False,
+ help='Show changes in function code size for each board')
+parser.add_option('-c', '--count', dest='count', type='int',
+ default=-1, help='Run build on the top n commits')
+parser.add_option('-e', '--show_errors', action='store_true',
+ default=False, help='Show errors and warnings')
+parser.add_option('-f', '--force-build', dest='force_build',
+ action='store_true', default=False,
+ help='Force build of boards even if already built')
+parser.add_option('-d', '--detail', dest='show_detail',
+ action='store_true', default=False,
+ help='Show detailed information for each board in summary')
+parser.add_option('-g', '--git', type='string',
+ help='Git repo containing branch to build', default='.')
+parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
+ default=False, help='Display the README file')
+parser.add_option('-j', '--jobs', dest='jobs', type='int',
+ default=None, help='Number of jobs to run at once (passed to make)')
+parser.add_option('-k', '--keep-outputs', action='store_true',
+ default=False, help='Keep all build output files (e.g. binaries)')
+parser.add_option('--list-tool-chains', action='store_true', default=False,
+ help='List available tool chains')
+parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
+ default=False, help="Do a try run (describe actions, but no nothing)")
+parser.add_option('-Q', '--quick', action='store_true',
+ default=False, help='Do a rough build, with limited warning resolution')
+parser.add_option('-s', '--summary', action='store_true',
+ default=False, help='Show a build summary')
+parser.add_option('-S', '--show-sizes', action='store_true',
+ default=False, help='Show image size variation in summary')
+parser.add_option('--step', type='int',
+ default=1, help='Only build every n commits (0=just first and last)')
+parser.add_option('-t', '--test', action='store_true', dest='test',
+ default=False, help='run tests')
+parser.add_option('-T', '--threads', type='int',
+ default=None, help='Number of builder threads to use')
+parser.add_option('-u', '--show_unknown', action='store_true',
+ default=False, help='Show boards with unknown build result')
+
+parser.usage = """buildman -b <branch> [options]
+
+Build U-Boot for all commits in a branch. Use -n to do a dry run"""
+
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+ RunTests()
+elif options.full_help:
+ pager = os.getenv('PAGER')
+ if not pager:
+ pager = 'more'
+ fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
+ command.Run(pager, fname)
+
+# Build selected commits for selected boards
+else:
+ control.DoBuildman(options, args)
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
new file mode 100644
index 0000000..4319ce7
--- /dev/null
+++ b/tools/buildman/control.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2013 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import multiprocessing
+import os
+import sys
+
+import board
+import bsettings
+from builder import Builder
+import gitutil
+import patchstream
+import terminal
+import toolchain
+
+def GetPlural(count):
+ """Returns a plural 's' if count is not 1"""
+ return 's' if count != 1 else ''
+
+def GetActionSummary(is_summary, count, selected, options):
+ """Return a string summarising the intended action.
+
+ Returns:
+ Summary string.
+ """
+ count = (count + options.step - 1) / options.step
+ str = '%s %d commit%s for %d boards' % (
+ 'Summary of' if is_summary else 'Building', count, GetPlural(count),
+ len(selected))
+ str += ' (%d thread%s, %d job%s per thread)' % (options.threads,
+ GetPlural(options.threads), options.jobs, GetPlural(options.jobs))
+ return str
+
+def ShowActions(series, why_selected, boards_selected, builder, options):
+ """Display a list of actions that we would take, if not a dry run.
+
+ Args:
+ series: Series object
+ why_selected: Dictionary where each key is a buildman argument
+ provided by the user, and the value is the boards brought
+ in by that argument. For example, 'arm' might bring in
+ 400 boards, so in this case the key would be 'arm' and
+ the value would be a list of board names.
+ boards_selected: Dict of selected boards, key is target name,
+ value is Board object
+ builder: The builder that will be used to build the commits
+ options: Command line options object
+ """
+ col = terminal.Color()
+ print 'Dry run, so not doing much. But I would do this:'
+ print
+ print GetActionSummary(False, len(series.commits), boards_selected,
+ options)
+ print 'Build directory: %s' % builder.base_dir
+ for upto in range(0, len(series.commits), options.step):
+ commit = series.commits[upto]
+ print ' ', col.Color(col.YELLOW, commit.hash, bright=False),
+ print commit.subject
+ print
+ for arg in why_selected:
+ if arg != 'all':
+ print arg, ': %d boards' % why_selected[arg]
+ print ('Total boards to build for each commit: %d\n' %
+ why_selected['all'])
+
+def DoBuildman(options, args):
+ """The main control code for buildman
+
+ Args:
+ options: Command line options object
+ args: Command line arguments (list of strings)
+ """
+ gitutil.Setup()
+
+ bsettings.Setup()
+ options.git_dir = os.path.join(options.git, '.git')
+
+ toolchains = toolchain.Toolchains()
+ toolchains.Scan(options.list_tool_chains)
+ if options.list_tool_chains:
+ toolchains.List()
+ print
+ return
+
+ # Work out how many commits to build. We want to build everything on the
+ # branch. We also build the upstream commit as a control so we can see
+ # problems introduced by the first commit on the branch.
+ col = terminal.Color()
+ count = options.count
+ if count == -1:
+ if not options.branch:
+ str = 'Please use -b to specify a branch to build'
+ print col.Color(col.RED, str)
+ sys.exit(1)
+ count = gitutil.CountCommitsInBranch(options.git_dir, options.branch)
+ if count is None:
+ str = "Branch '%s' not found or has no upstream" % options.branch
+ print col.Color(col.RED, str)
+ sys.exit(1)
+ count += 1 # Build upstream commit also
+
+ if not count:
+ str = ("No commits found to process in branch '%s': "
+ "set branch's upstream or use -c flag" % options.branch)
+ print col.Color(col.RED, str)
+ sys.exit(1)
+
+ # Work out what subset of the boards we are building
+ boards = board.Boards()
+ boards.ReadBoards(os.path.join(options.git, 'boards.cfg'))
+ why_selected = boards.SelectBoards(args)
+ selected = boards.GetSelected()
+ if not len(selected):
+ print col.Color(col.RED, 'No matching boards found')
+ sys.exit(1)
+
+ # Read the metadata from the commits. First look at the upstream commit,
+ # then the ones in the branch. We would like to do something like
+ # upstream/master~..branch but that isn't possible if upstream/master is
+ # a merge commit (it will list all the commits that form part of the
+ # merge)
+ range_expr = gitutil.GetRangeInBranch(options.git_dir, options.branch)
+ upstream_commit = gitutil.GetUpstream(options.git_dir, options.branch)
+ series = patchstream.GetMetaDataForList(upstream_commit, options.git_dir,
+ 1)
+ # Conflicting tags are not a problem for buildman, since it does not use
+ # them. For example, Series-version is not useful for buildman. On the
+ # other hand conflicting tags will cause an error. So allow later tags
+ # to overwrite earlier ones.
+ series.allow_overwrite = True
+ series = patchstream.GetMetaDataForList(range_expr, options.git_dir, None,
+ series)
+
+ # By default we have one thread per CPU. But if there are not enough jobs
+ # we can have fewer threads and use a high '-j' value for make.
+ if not options.threads:
+ options.threads = min(multiprocessing.cpu_count(), len(selected))
+ if not options.jobs:
+ options.jobs = max(1, (multiprocessing.cpu_count() +
+ len(selected) - 1) / len(selected))
+
+ if not options.step:
+ options.step = len(series.commits) - 1
+
+ # Create a new builder with the selected options
+ output_dir = os.path.join('..', options.branch)
+ builder = Builder(toolchains, output_dir, options.git_dir,
+ options.threads, options.jobs, checkout=True,
+ show_unknown=options.show_unknown, step=options.step)
+ builder.force_config_on_failure = not options.quick
+
+ # For a dry run, just show our actions as a sanity check
+ if options.dry_run:
+ ShowActions(series, why_selected, selected, builder, options)
+ else:
+ builder.force_build = options.force_build
+
+ # Work out which boards to build
+ board_selected = boards.GetSelectedDict()
+
+ print GetActionSummary(options.summary, count, board_selected, options)
+
+ if options.summary:
+ # We can't show function sizes without board details at present
+ if options.show_bloat:
+ options.show_detail = True
+ builder.ShowSummary(series.commits, board_selected,
+ options.show_errors, options.show_sizes,
+ options.show_detail, options.show_bloat)
+ else:
+ builder.BuildBoards(series.commits, board_selected,
+ options.show_errors, options.keep_outputs)
diff --git a/tools/buildman/test.py b/tools/buildman/test.py
new file mode 100644
index 0000000..9330fa5
--- /dev/null
+++ b/tools/buildman/test.py
@@ -0,0 +1,185 @@
+#
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import os
+import shutil
+import sys
+import tempfile
+import time
+import unittest
+
+# Bring in the patman libraries
+our_path = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(our_path, '../patman'))
+
+import board
+import bsettings
+import builder
+import control
+import command
+import commit
+import toolchain
+
+errors = [
+ '''main.c: In function 'main_loop':
+main.c:260:6: warning: unused variable 'joe' [-Wunused-variable]
+''',
+ '''main.c: In function 'main_loop':
+main.c:295:2: error: 'fred' undeclared (first use in this function)
+main.c:295:2: note: each undeclared identifier is reported only once for each function it appears in
+make[1]: *** [main.o] Error 1
+make: *** [common/libcommon.o] Error 2
+Make failed
+''',
+ '''main.c: In function 'main_loop':
+main.c:280:6: warning: unused variable 'mary' [-Wunused-variable]
+''',
+ '''powerpc-linux-ld: warning: dot moved backwards before `.bss'
+powerpc-linux-ld: warning: dot moved backwards before `.bss'
+powerpc-linux-ld: u-boot: section .text lma 0xfffc0000 overlaps previous sections
+powerpc-linux-ld: u-boot: section .rodata lma 0xfffef3ec overlaps previous sections
+powerpc-linux-ld: u-boot: section .reloc lma 0xffffa400 overlaps previous sections
+powerpc-linux-ld: u-boot: section .data lma 0xffffcd38 overlaps previous sections
+powerpc-linux-ld: u-boot: section .u_boot_cmd lma 0xffffeb40 overlaps previous sections
+powerpc-linux-ld: u-boot: section .bootpg lma 0xfffff198 overlaps previous sections
+'''
+]
+
+
+# hash, subject, return code, list of errors/warnings
+commits = [
+ ['1234', 'upstream/master, ok', 0, []],
+ ['5678', 'Second commit, a warning', 0, errors[0:1]],
+ ['9012', 'Third commit, error', 1, errors[0:2]],
+ ['3456', 'Fourth commit, warning', 0, [errors[0], errors[2]]],
+ ['7890', 'Fifth commit, link errors', 1, [errors[0], errors[3]]],
+ ['abcd', 'Sixth commit, fixes all errors', 0, []]
+]
+
+boards = [
+ ['board0', 'arm', 'armv7', 'ARM Board 1', 'Tester', '', ''],
+ ['board1', 'arm', 'armv7', 'ARM Board 2', 'Tester', '', ''],
+ ['board2', 'powerpc', 'powerpc', 'PowerPC board 1', 'Tester', '', ''],
+ ['board3', 'powerpc', 'mpc5xx', 'PowerPC board 2', 'Tester', '', ''],
+ ['board4', 'sandbox', 'sandbox', 'Sandbox board', 'Tester', '', '']
+]
+
+class Options:
+ """Class that holds build options"""
+ pass
+
+class TestBuild(unittest.TestCase):
+ """Test buildman
+
+ TODO: Write tests for the rest of the functionality
+ """
+ def setUp(self):
+ # Set up commits to build
+ self.commits = []
+ sequence = 0
+ for commit_info in commits:
+ comm = commit.Commit(commit_info[0])
+ comm.subject = commit_info[1]
+ comm.return_code = commit_info[2]
+ comm.error_list = commit_info[3]
+ comm.sequence = sequence
+ sequence += 1
+ self.commits.append(comm)
+
+ # Set up boards to build
+ self.boards = board.Boards()
+ for brd in boards:
+ self.boards.AddBoard(board.Board(*brd))
+ self.boards.SelectBoards([])
+
+ # Set up the toolchains
+ bsettings.Setup()
+ self.toolchains = toolchain.Toolchains()
+ self.toolchains.Add('arm-linux-gcc', test=False)
+ self.toolchains.Add('sparc-linux-gcc', test=False)
+ self.toolchains.Add('powerpc-linux-gcc', test=False)
+ self.toolchains.Add('gcc', test=False)
+
+ def Make(self, commit, brd, stage, *args, **kwargs):
+ result = command.CommandResult()
+ boardnum = int(brd.target[-1])
+ result.return_code = 0
+ result.stderr = ''
+ result.stdout = ('This is the test output for board %s, commit %s' %
+ (brd.target, commit.hash))
+ if boardnum >= 1 and boardnum >= commit.sequence:
+ result.return_code = commit.return_code
+ result.stderr = ''.join(commit.error_list)
+ if stage == 'build':
+ target_dir = None
+ for arg in args:
+ if arg.startswith('O='):
+ target_dir = arg[2:]
+
+ if not os.path.isdir(target_dir):
+ os.mkdir(target_dir)
+ #time.sleep(.2 + boardnum * .2)
+
+ result.combined = result.stdout + result.stderr
+ return result
+
+ def testBasic(self):
+ """Test basic builder operation"""
+ output_dir = tempfile.mkdtemp()
+ if not os.path.isdir(output_dir):
+ os.mkdir(output_dir)
+ build = builder.Builder(self.toolchains, output_dir, None, 1, 2,
+ checkout=False, show_unknown=False)
+ build.do_make = self.Make
+ board_selected = self.boards.GetSelectedDict()
+
+ #build.BuildCommits(self.commits, board_selected, False)
+ build.BuildBoards(self.commits, board_selected, False, False)
+ build.ShowSummary(self.commits, board_selected, True, False,
+ False, False)
+
+ def _testGit(self):
+ """Test basic builder operation by building a branch"""
+ base_dir = tempfile.mkdtemp()
+ if not os.path.isdir(base_dir):
+ os.mkdir(base_dir)
+ options = Options()
+ options.git = os.getcwd()
+ options.summary = False
+ options.jobs = None
+ options.dry_run = False
+ #options.git = os.path.join(base_dir, 'repo')
+ options.branch = 'test-buildman'
+ options.force_build = False
+ options.list_tool_chains = False
+ options.count = -1
+ options.git_dir = None
+ options.threads = None
+ options.show_unknown = False
+ options.quick = False
+ options.show_errors = False
+ options.keep_outputs = False
+ args = ['tegra20']
+ control.DoBuildman(options, args)
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tools/buildman/toolchain.py b/tools/buildman/toolchain.py
new file mode 100644
index 0000000..e0a6970
--- /dev/null
+++ b/tools/buildman/toolchain.py
@@ -0,0 +1,185 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import glob
+import os
+
+import bsettings
+import command
+
+class Toolchain:
+ """A single toolchain
+
+ Public members:
+ gcc: Full path to C compiler
+ path: Directory path containing C compiler
+ cross: Cross compile string, e.g. 'arm-linux-'
+ arch: Architecture of toolchain as determined from the first
+ component of the filename. E.g. arm-linux-gcc becomes arm
+ """
+
+ def __init__(self, fname, test, verbose=False):
+ """Create a new toolchain object.
+
+ Args:
+ fname: Filename of the gcc component
+ test: True to run the toolchain to test it
+ """
+ self.gcc = fname
+ self.path = os.path.dirname(fname)
+ self.cross = os.path.basename(fname)[:-3]
+ pos = self.cross.find('-')
+ self.arch = self.cross[:pos] if pos != -1 else 'sandbox'
+
+ env = self.MakeEnvironment()
+
+ # As a basic sanity check, run the C compiler with --version
+ cmd = [fname, '--version']
+ if test:
+ result = command.RunPipe([cmd], capture=True, env=env)
+ self.ok = result.return_code == 0
+ if verbose:
+ print 'Tool chain test: ',
+ if self.ok:
+ print 'OK'
+ else:
+ print 'BAD'
+ print 'Command: ', cmd
+ print result.stdout
+ print result.stderr
+ else:
+ self.ok = True
+ self.priority = self.GetPriority(fname)
+
+ def GetPriority(self, fname):
+ """Return the priority of the toolchain.
+
+ Toolchains are ranked according to their suitability by their
+ filename prefix.
+
+ Args:
+ fname: Filename of toolchain
+ Returns:
+ Priority of toolchain, 0=highest, 20=lowest.
+ """
+ priority_list = ['-elf', '-unknown-linux-gnu', '-linux', '-elf',
+ '-none-linux-gnueabi', '-uclinux', '-none-eabi',
+ '-gentoo-linux-gnu', '-linux-gnueabi', '-le-linux', '-uclinux']
+ for prio in range(len(priority_list)):
+ if priority_list[prio] in fname:
+ return prio
+ return prio
+
+ def MakeEnvironment(self):
+ """Returns an environment for using the toolchain.
+
+ Thie takes the current environment, adds CROSS_COMPILE and
+ augments PATH so that the toolchain will operate correctly.
+ """
+ env = dict(os.environ)
+ env['CROSS_COMPILE'] = self.cross
+ env['PATH'] += (':' + self.path)
+ return env
+
+
+class Toolchains:
+ """Manage a list of toolchains for building U-Boot
+
+ We select one toolchain for each architecture type
+
+ Public members:
+ toolchains: Dict of Toolchain objects, keyed by architecture name
+ paths: List of paths to check for toolchains (may contain wildcards)
+ """
+
+ def __init__(self):
+ self.toolchains = {}
+ self.paths = []
+ for name, value in bsettings.GetItems('toolchain'):
+ if '*' in value:
+ self.paths += glob.glob(value)
+ else:
+ self.paths.append(value)
+
+
+ def Add(self, fname, test=True, verbose=False):
+ """Add a toolchain to our list
+
+ We select the given toolchain as our preferred one for its
+ architecture if it is a higher priority than the others.
+
+ Args:
+ fname: Filename of toolchain's gcc driver
+ test: True to run the toolchain to test it
+ """
+ toolchain = Toolchain(fname, test, verbose)
+ add_it = toolchain.ok
+ if toolchain.arch in self.toolchains:
+ add_it = (toolchain.priority <
+ self.toolchains[toolchain.arch].priority)
+ if add_it:
+ self.toolchains[toolchain.arch] = toolchain
+
+ def Scan(self, verbose):
+ """Scan for available toolchains and select the best for each arch.
+
+ We look for all the toolchains we can file, figure out the
+ architecture for each, and whether it works. Then we select the
+ highest priority toolchain for each arch.
+
+ Args:
+ verbose: True to print out progress information
+ """
+ if verbose: print 'Scanning for tool chains'
+ for path in self.paths:
+ if verbose: print " - scanning path '%s'" % path
+ for subdir in ['.', 'bin', 'usr/bin']:
+ dirname = os.path.join(path, subdir)
+ if verbose: print " - looking in '%s'" % dirname
+ for fname in glob.glob(dirname + '/*gcc'):
+ if verbose: print " - found '%s'" % fname
+ self.Add(fname, True, verbose)
+
+ def List(self):
+ """List out the selected toolchains for each architecture"""
+ print 'List of available toolchains (%d):' % len(self.toolchains)
+ if len(self.toolchains):
+ for key, value in sorted(self.toolchains.iteritems()):
+ print '%-10s: %s' % (key, value.gcc)
+ else:
+ print 'None'
+
+ def Select(self, arch):
+ """Returns the toolchain for a given architecture
+
+ Args:
+ args: Name of architecture (e.g. 'arm', 'ppc_8xx')
+
+ returns:
+ toolchain object, or None if none found
+ """
+ for name, value in bsettings.GetItems('toolchain-alias'):
+ if arch == name:
+ arch = value
+
+ if not arch in self.toolchains:
+ raise ValueError, ("No tool chain found for arch '%s'" % arch)
+ return self.toolchains[arch]
diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl
new file mode 100755
index 0000000..896e2bc
--- /dev/null
+++ b/tools/checkpatch.pl
@@ -0,0 +1,3709 @@
+#!/usr/bin/perl -w
+# (c) 2001, Dave Jones. (the file handling bit)
+# (c) 2005, Joel Schopp <jschopp@austin.ibm.com> (the ugly bit)
+# (c) 2007,2008, Andy Whitcroft <apw@uk.ibm.com> (new conditions, test suite)
+# (c) 2008-2010 Andy Whitcroft <apw@canonical.com>
+# Licensed under the terms of the GNU GPL License version 2
+
+use strict;
+
+my $P = $0;
+$P =~ s@.*/@@g;
+
+my $V = '0.32';
+
+use Getopt::Long qw(:config no_auto_abbrev);
+
+my $quiet = 0;
+my $tree = 1;
+my $chk_signoff = 1;
+my $chk_patch = 1;
+my $tst_only;
+my $emacs = 0;
+my $terse = 0;
+my $file = 0;
+my $check = 0;
+my $summary = 1;
+my $mailback = 0;
+my $summary_file = 0;
+my $show_types = 0;
+my $root;
+my %debug;
+my %ignore_type = ();
+my @ignore = ();
+my $help = 0;
+my $configuration_file = ".checkpatch.conf";
+my $max_line_length = 80;
+
+sub help {
+ my ($exitcode) = @_;
+
+ print << "EOM";
+Usage: $P [OPTION]... [FILE]...
+Version: $V
+
+Options:
+ -q, --quiet quiet
+ --no-tree run without a kernel tree
+ --no-signoff do not check for 'Signed-off-by' line
+ --patch treat FILE as patchfile (default)
+ --emacs emacs compile window format
+ --terse one line per report
+ -f, --file treat FILE as regular source file
+ --subjective, --strict enable more subjective tests
+ --ignore TYPE(,TYPE2...) ignore various comma separated message types
+ --max-line-length=n set the maximum line length, if exceeded, warn
+ --show-types show the message "types" in the output
+ --root=PATH PATH to the kernel tree root
+ --no-summary suppress the per-file summary
+ --mailback only produce a report in case of warnings/errors
+ --summary-file include the filename in summary
+ --debug KEY=[0|1] turn on/off debugging of KEY, where KEY is one of
+ 'values', 'possible', 'type', and 'attr' (default
+ is all off)
+ --test-only=WORD report only warnings/errors containing WORD
+ literally
+ -h, --help, --version display this help and exit
+
+When FILE is - read standard input.
+EOM
+
+ exit($exitcode);
+}
+
+my $conf = which_conf($configuration_file);
+if (-f $conf) {
+ my @conf_args;
+ open(my $conffile, '<', "$conf")
+ or warn "$P: Can't find a readable $configuration_file file $!\n";
+
+ while (<$conffile>) {
+ my $line = $_;
+
+ $line =~ s/\s*\n?$//g;
+ $line =~ s/^\s*//g;
+ $line =~ s/\s+/ /g;
+
+ next if ($line =~ m/^\s*#/);
+ next if ($line =~ m/^\s*$/);
+
+ my @words = split(" ", $line);
+ foreach my $word (@words) {
+ last if ($word =~ m/^#/);
+ push (@conf_args, $word);
+ }
+ }
+ close($conffile);
+ unshift(@ARGV, @conf_args) if @conf_args;
+}
+
+GetOptions(
+ 'q|quiet+' => \$quiet,
+ 'tree!' => \$tree,
+ 'signoff!' => \$chk_signoff,
+ 'patch!' => \$chk_patch,
+ 'emacs!' => \$emacs,
+ 'terse!' => \$terse,
+ 'f|file!' => \$file,
+ 'subjective!' => \$check,
+ 'strict!' => \$check,
+ 'ignore=s' => \@ignore,
+ 'show-types!' => \$show_types,
+ 'max-line-length=i' => \$max_line_length,
+ 'root=s' => \$root,
+ 'summary!' => \$summary,
+ 'mailback!' => \$mailback,
+ 'summary-file!' => \$summary_file,
+
+ 'debug=s' => \%debug,
+ 'test-only=s' => \$tst_only,
+ 'h|help' => \$help,
+ 'version' => \$help
+) or help(1);
+
+help(0) if ($help);
+
+my $exit = 0;
+
+if ($#ARGV < 0) {
+ print "$P: no input files\n";
+ exit(1);
+}
+
+@ignore = split(/,/, join(',',@ignore));
+foreach my $word (@ignore) {
+ $word =~ s/\s*\n?$//g;
+ $word =~ s/^\s*//g;
+ $word =~ s/\s+/ /g;
+ $word =~ tr/[a-z]/[A-Z]/;
+
+ next if ($word =~ m/^\s*#/);
+ next if ($word =~ m/^\s*$/);
+
+ $ignore_type{$word}++;
+}
+
+my $dbg_values = 0;
+my $dbg_possible = 0;
+my $dbg_type = 0;
+my $dbg_attr = 0;
+for my $key (keys %debug) {
+ ## no critic
+ eval "\${dbg_$key} = '$debug{$key}';";
+ die "$@" if ($@);
+}
+
+my $rpt_cleaners = 0;
+
+if ($terse) {
+ $emacs = 1;
+ $quiet++;
+}
+
+if ($tree) {
+ if (defined $root) {
+ if (!top_of_kernel_tree($root)) {
+ die "$P: $root: --root does not point at a valid tree\n";
+ }
+ } else {
+ if (top_of_kernel_tree('.')) {
+ $root = '.';
+ } elsif ($0 =~ m@(.*)/scripts/[^/]*$@ &&
+ top_of_kernel_tree($1)) {
+ $root = $1;
+ }
+ }
+
+ if (!defined $root) {
+ print "Must be run from the top-level dir. of a kernel tree\n";
+ exit(2);
+ }
+}
+
+my $emitted_corrupt = 0;
+
+our $Ident = qr{
+ [A-Za-z_][A-Za-z\d_]*
+ (?:\s*\#\#\s*[A-Za-z_][A-Za-z\d_]*)*
+ }x;
+our $Storage = qr{extern|static|asmlinkage};
+our $Sparse = qr{
+ __user|
+ __kernel|
+ __force|
+ __iomem|
+ __must_check|
+ __init_refok|
+ __kprobes|
+ __ref|
+ __rcu
+ }x;
+
+# Notes to $Attribute:
+# We need \b after 'init' otherwise 'initconst' will cause a false positive in a check
+our $Attribute = qr{
+ const|
+ __percpu|
+ __nocast|
+ __safe|
+ __bitwise__|
+ __packed__|
+ __packed2__|
+ __naked|
+ __maybe_unused|
+ __always_unused|
+ __noreturn|
+ __used|
+ __cold|
+ __noclone|
+ __deprecated|
+ __read_mostly|
+ __kprobes|
+ __(?:mem|cpu|dev|)(?:initdata|initconst|init\b)|
+ ____cacheline_aligned|
+ ____cacheline_aligned_in_smp|
+ ____cacheline_internodealigned_in_smp|
+ __weak
+ }x;
+our $Modifier;
+our $Inline = qr{inline|__always_inline|noinline};
+our $Member = qr{->$Ident|\.$Ident|\[[^]]*\]};
+our $Lval = qr{$Ident(?:$Member)*};
+
+our $Float_hex = qr{(?i)0x[0-9a-f]+p-?[0-9]+[fl]?};
+our $Float_dec = qr{(?i)(?:[0-9]+\.[0-9]*|[0-9]*\.[0-9]+)(?:e-?[0-9]+)?[fl]?};
+our $Float_int = qr{(?i)[0-9]+e-?[0-9]+[fl]?};
+our $Float = qr{$Float_hex|$Float_dec|$Float_int};
+our $Constant = qr{$Float|(?i)(?:0x[0-9a-f]+|[0-9]+)[ul]*};
+our $Assignment = qr{\*\=|/=|%=|\+=|-=|<<=|>>=|&=|\^=|\|=|=};
+our $Compare = qr{<=|>=|==|!=|<|>};
+our $Operators = qr{
+ <=|>=|==|!=|
+ =>|->|<<|>>|<|>|!|~|
+ &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
+ }x;
+
+our $NonptrType;
+our $Type;
+our $Declare;
+
+our $NON_ASCII_UTF8 = qr{
+ [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
+ | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
+ | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
+ | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
+}x;
+
+our $UTF8 = qr{
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
+ | $NON_ASCII_UTF8
+}x;
+
+our $typeTypedefs = qr{(?x:
+ (?:__)?(?:u|s|be|le)(?:8|16|32|64)|
+ atomic_t
+)};
+
+our $logFunctions = qr{(?x:
+ printk(?:_ratelimited|_once|)|
+ [a-z0-9]+_(?:printk|emerg|alert|crit|err|warning|warn|notice|info|debug|dbg|vdbg|devel|cont|WARN)(?:_ratelimited|_once|)|
+ WARN(?:_RATELIMIT|_ONCE|)|
+ panic|
+ debug|
+ printf|
+ MODULE_[A-Z_]+
+)};
+
+our $signature_tags = qr{(?xi:
+ Signed-off-by:|
+ Acked-by:|
+ Tested-by:|
+ Reviewed-by:|
+ Reported-by:|
+ To:|
+ Cc:
+)};
+
+our @typeList = (
+ qr{void},
+ qr{(?:unsigned\s+)?char},
+ qr{(?:unsigned\s+)?short},
+ qr{(?:unsigned\s+)?int},
+ qr{(?:unsigned\s+)?long},
+ qr{(?:unsigned\s+)?long\s+int},
+ qr{(?:unsigned\s+)?long\s+long},
+ qr{(?:unsigned\s+)?long\s+long\s+int},
+ qr{unsigned},
+ qr{float},
+ qr{double},
+ qr{bool},
+ qr{struct\s+$Ident},
+ qr{union\s+$Ident},
+ qr{enum\s+$Ident},
+ qr{${Ident}_t},
+ qr{${Ident}_handler},
+ qr{${Ident}_handler_fn},
+);
+our @modifierList = (
+ qr{fastcall},
+);
+
+our $allowed_asm_includes = qr{(?x:
+ irq|
+ memory
+)};
+# memory.h: ARM has a custom one
+
+sub build_types {
+ my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)";
+ my $all = "(?x: \n" . join("|\n ", @typeList) . "\n)";
+ $Modifier = qr{(?:$Attribute|$Sparse|$mods)};
+ $NonptrType = qr{
+ (?:$Modifier\s+|const\s+)*
+ (?:
+ (?:typeof|__typeof__)\s*\([^\)]*\)|
+ (?:$typeTypedefs\b)|
+ (?:${all}\b)
+ )
+ (?:\s+$Modifier|\s+const)*
+ }x;
+ $Type = qr{
+ $NonptrType
+ (?:(?:\s|\*|\[\])+\s*const|(?:\s|\*|\[\])+|(?:\s*\[\s*\])+)?
+ (?:\s+$Inline|\s+$Modifier)*
+ }x;
+ $Declare = qr{(?:$Storage\s+)?$Type};
+}
+build_types();
+
+
+our $Typecast = qr{\s*(\(\s*$NonptrType\s*\)){0,1}\s*};
+
+# Using $balanced_parens, $LvalOrFunc, or $FuncArg
+# requires at least perl version v5.10.0
+# Any use must be runtime checked with $^V
+
+our $balanced_parens = qr/(\((?:[^\(\)]++|(?-1))*\))/;
+our $LvalOrFunc = qr{($Lval)\s*($balanced_parens{0,1})\s*};
+our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant)};
+
+sub deparenthesize {
+ my ($string) = @_;
+ return "" if (!defined($string));
+ $string =~ s@^\s*\(\s*@@g;
+ $string =~ s@\s*\)\s*$@@g;
+ $string =~ s@\s+@ @g;
+ return $string;
+}
+
+$chk_signoff = 0 if ($file);
+
+my @rawlines = ();
+my @lines = ();
+my $vname;
+for my $filename (@ARGV) {
+ my $FILE;
+ if ($file) {
+ open($FILE, '-|', "diff -u /dev/null $filename") ||
+ die "$P: $filename: diff failed - $!\n";
+ } elsif ($filename eq '-') {
+ open($FILE, '<&STDIN');
+ } else {
+ open($FILE, '<', "$filename") ||
+ die "$P: $filename: open failed - $!\n";
+ }
+ if ($filename eq '-') {
+ $vname = 'Your patch';
+ } else {
+ $vname = $filename;
+ }
+ while (<$FILE>) {
+ chomp;
+ push(@rawlines, $_);
+ }
+ close($FILE);
+ if (!process($filename)) {
+ $exit = 1;
+ }
+ @rawlines = ();
+ @lines = ();
+}
+
+exit($exit);
+
+sub top_of_kernel_tree {
+ my ($root) = @_;
+
+ my @tree_check = (
+ "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile",
+ "README", "Documentation", "arch", "include", "drivers",
+ "fs", "init", "ipc", "kernel", "lib", "scripts",
+ );
+
+ foreach my $check (@tree_check) {
+ if (! -e $root . '/' . $check) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+sub parse_email {
+ my ($formatted_email) = @_;
+
+ my $name = "";
+ my $address = "";
+ my $comment = "";
+
+ if ($formatted_email =~ /^(.*)<(\S+\@\S+)>(.*)$/) {
+ $name = $1;
+ $address = $2;
+ $comment = $3 if defined $3;
+ } elsif ($formatted_email =~ /^\s*<(\S+\@\S+)>(.*)$/) {
+ $address = $1;
+ $comment = $2 if defined $2;
+ } elsif ($formatted_email =~ /(\S+\@\S+)(.*)$/) {
+ $address = $1;
+ $comment = $2 if defined $2;
+ $formatted_email =~ s/$address.*$//;
+ $name = $formatted_email;
+ $name =~ s/^\s+|\s+$//g;
+ $name =~ s/^\"|\"$//g;
+ # If there's a name left after stripping spaces and
+ # leading quotes, and the address doesn't have both
+ # leading and trailing angle brackets, the address
+ # is invalid. ie:
+ # "joe smith joe@smith.com" bad
+ # "joe smith <joe@smith.com" bad
+ if ($name ne "" && $address !~ /^<[^>]+>$/) {
+ $name = "";
+ $address = "";
+ $comment = "";
+ }
+ }
+
+ $name =~ s/^\s+|\s+$//g;
+ $name =~ s/^\"|\"$//g;
+ $address =~ s/^\s+|\s+$//g;
+ $address =~ s/^\<|\>$//g;
+
+ if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+ $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+ $name = "\"$name\"";
+ }
+
+ return ($name, $address, $comment);
+}
+
+sub format_email {
+ my ($name, $address) = @_;
+
+ my $formatted_email;
+
+ $name =~ s/^\s+|\s+$//g;
+ $name =~ s/^\"|\"$//g;
+ $address =~ s/^\s+|\s+$//g;
+
+ if ($name =~ /[^\w \-]/i) { ##has "must quote" chars
+ $name =~ s/(?<!\\)"/\\"/g; ##escape quotes
+ $name = "\"$name\"";
+ }
+
+ if ("$name" eq "") {
+ $formatted_email = "$address";
+ } else {
+ $formatted_email = "$name <$address>";
+ }
+
+ return $formatted_email;
+}
+
+sub which_conf {
+ my ($conf) = @_;
+
+ foreach my $path (split(/:/, ".:$ENV{HOME}:.scripts")) {
+ if (-e "$path/$conf") {
+ return "$path/$conf";
+ }
+ }
+
+ return "";
+}
+
+sub expand_tabs {
+ my ($str) = @_;
+
+ my $res = '';
+ my $n = 0;
+ for my $c (split(//, $str)) {
+ if ($c eq "\t") {
+ $res .= ' ';
+ $n++;
+ for (; ($n % 8) != 0; $n++) {
+ $res .= ' ';
+ }
+ next;
+ }
+ $res .= $c;
+ $n++;
+ }
+
+ return $res;
+}
+sub copy_spacing {
+ (my $res = shift) =~ tr/\t/ /c;
+ return $res;
+}
+
+sub line_stats {
+ my ($line) = @_;
+
+ # Drop the diff line leader and expand tabs
+ $line =~ s/^.//;
+ $line = expand_tabs($line);
+
+ # Pick the indent from the front of the line.
+ my ($white) = ($line =~ /^(\s*)/);
+
+ return (length($line), length($white));
+}
+
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+ my ($in_comment) = @_;
+
+ if ($in_comment) {
+ $sanitise_quote = '*/';
+ } else {
+ $sanitise_quote = '';
+ }
+}
+sub sanitise_line {
+ my ($line) = @_;
+
+ my $res = '';
+ my $l = '';
+
+ my $qlen = 0;
+ my $off = 0;
+ my $c;
+
+ # Always copy over the diff marker.
+ $res = substr($line, 0, 1);
+
+ for ($off = 1; $off < length($line); $off++) {
+ $c = substr($line, $off, 1);
+
+ # Comments we are wacking completly including the begin
+ # and end, all to $;.
+ if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+ $sanitise_quote = '*/';
+
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
+ }
+ if ($sanitise_quote eq '*/' && substr($line, $off, 2) eq '*/') {
+ $sanitise_quote = '';
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
+ }
+ if ($sanitise_quote eq '' && substr($line, $off, 2) eq '//') {
+ $sanitise_quote = '//';
+
+ substr($res, $off, 2, $sanitise_quote);
+ $off++;
+ next;
+ }
+
+ # A \ in a string means ignore the next character.
+ if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+ $c eq "\\") {
+ substr($res, $off, 2, 'XX');
+ $off++;
+ next;
+ }
+ # Regular quotes.
+ if ($c eq "'" || $c eq '"') {
+ if ($sanitise_quote eq '') {
+ $sanitise_quote = $c;
+
+ substr($res, $off, 1, $c);
+ next;
+ } elsif ($sanitise_quote eq $c) {
+ $sanitise_quote = '';
+ }
+ }
+
+ #print "c<$c> SQ<$sanitise_quote>\n";
+ if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+ substr($res, $off, 1, $;);
+ } elsif ($off != 0 && $sanitise_quote eq '//' && $c ne "\t") {
+ substr($res, $off, 1, $;);
+ } elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+ substr($res, $off, 1, 'X');
+ } else {
+ substr($res, $off, 1, $c);
+ }
+ }
+
+ if ($sanitise_quote eq '//') {
+ $sanitise_quote = '';
+ }
+
+ # The pathname on a #include may be surrounded by '<' and '>'.
+ if ($res =~ /^.\s*\#\s*include\s+\<(.*)\>/) {
+ my $clean = 'X' x length($1);
+ $res =~ s@\<.*\>@<$clean>@;
+
+ # The whole of a #error is a string.
+ } elsif ($res =~ /^.\s*\#\s*(?:error|warning)\s+(.*)\b/) {
+ my $clean = 'X' x length($1);
+ $res =~ s@(\#\s*(?:error|warning)\s+).*@$1$clean@;
+ }
+
+ return $res;
+}
+
+sub ctx_statement_block {
+ my ($linenr, $remain, $off) = @_;
+ my $line = $linenr - 1;
+ my $blk = '';
+ my $soff = $off;
+ my $coff = $off - 1;
+ my $coff_set = 0;
+
+ my $loff = 0;
+
+ my $type = '';
+ my $level = 0;
+ my @stack = ();
+ my $p;
+ my $c;
+ my $len = 0;
+
+ my $remainder;
+ while (1) {
+ @stack = (['', 0]) if ($#stack == -1);
+
+ #warn "CSB: blk<$blk> remain<$remain>\n";
+ # If we are about to drop off the end, pull in more
+ # context.
+ if ($off >= $len) {
+ for (; $remain > 0; $line++) {
+ last if (!defined $lines[$line]);
+ next if ($lines[$line] =~ /^-/);
+ $remain--;
+ $loff = $len;
+ $blk .= $lines[$line] . "\n";
+ $len = length($blk);
+ $line++;
+ last;
+ }
+ # Bail if there is no further context.
+ #warn "CSB: blk<$blk> off<$off> len<$len>\n";
+ if ($off >= $len) {
+ last;
+ }
+ if ($level == 0 && substr($blk, $off) =~ /^.\s*#\s*define/) {
+ $level++;
+ $type = '#';
+ }
+ }
+ $p = $c;
+ $c = substr($blk, $off, 1);
+ $remainder = substr($blk, $off);
+
+ #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
+
+ # Handle nested #if/#else.
+ if ($remainder =~ /^#\s*(?:ifndef|ifdef|if)\s/) {
+ push(@stack, [ $type, $level ]);
+ } elsif ($remainder =~ /^#\s*(?:else|elif)\b/) {
+ ($type, $level) = @{$stack[$#stack - 1]};
+ } elsif ($remainder =~ /^#\s*endif\b/) {
+ ($type, $level) = @{pop(@stack)};
+ }
+
+ # Statement ends at the ';' or a close '}' at the
+ # outermost level.
+ if ($level == 0 && $c eq ';') {
+ last;
+ }
+
+ # An else is really a conditional as long as its not else if
+ if ($level == 0 && $coff_set == 0 &&
+ (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+ $remainder =~ /^(else)(?:\s|{)/ &&
+ $remainder !~ /^else\s+if\b/) {
+ $coff = $off + length($1) - 1;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+ #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
+ }
+
+ if (($type eq '' || $type eq '(') && $c eq '(') {
+ $level++;
+ $type = '(';
+ }
+ if ($type eq '(' && $c eq ')') {
+ $level--;
+ $type = ($level != 0)? '(' : '';
+
+ if ($level == 0 && $coff < $soff) {
+ $coff = $off;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff>\n";
+ }
+ }
+ if (($type eq '' || $type eq '{') && $c eq '{') {
+ $level++;
+ $type = '{';
+ }
+ if ($type eq '{' && $c eq '}') {
+ $level--;
+ $type = ($level != 0)? '{' : '';
+
+ if ($level == 0) {
+ if (substr($blk, $off + 1, 1) eq ';') {
+ $off++;
+ }
+ last;
+ }
+ }
+ # Preprocessor commands end at the newline unless escaped.
+ if ($type eq '#' && $c eq "\n" && $p ne "\\") {
+ $level--;
+ $type = '';
+ $off++;
+ last;
+ }
+ $off++;
+ }
+ # We are truly at the end, so shuffle to the next line.
+ if ($off == $len) {
+ $loff = $len + 1;
+ $line++;
+ $remain--;
+ }
+
+ my $statement = substr($blk, $soff, $off - $soff + 1);
+ my $condition = substr($blk, $soff, $coff - $soff + 1);
+
+ #warn "STATEMENT<$statement>\n";
+ #warn "CONDITION<$condition>\n";
+
+ #print "coff<$coff> soff<$off> loff<$loff>\n";
+
+ return ($statement, $condition,
+ $line, $remain + 1, $off - $loff + 1, $level);
+}
+
+sub statement_lines {
+ my ($stmt) = @_;
+
+ # Strip the diff line prefixes and rip blank lines at start and end.
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+ my ($stmt) = @_;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+ my ($stmt) = @_;
+
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*{//;
+ $stmt =~ s/}\s*$//;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+ my @stmt_statements = ($stmt =~ /;/g);
+
+ my $stmt_lines = $#stmt_lines + 2;
+ my $stmt_statements = $#stmt_statements + 1;
+
+ if ($stmt_lines > $stmt_statements) {
+ return $stmt_lines;
+ } else {
+ return $stmt_statements;
+ }
+}
+
+sub ctx_statement_full {
+ my ($linenr, $remain, $off) = @_;
+ my ($statement, $condition, $level);
+
+ my (@chunks);
+
+ # Grab the first conditional/block pair.
+ ($statement, $condition, $linenr, $remain, $off, $level) =
+ ctx_statement_block($linenr, $remain, $off);
+ #print "F: c<$condition> s<$statement> remain<$remain>\n";
+ push(@chunks, [ $condition, $statement ]);
+ if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+ return ($level, $linenr, @chunks);
+ }
+
+ # Pull in the following conditional/block pairs and see if they
+ # could continue the statement.
+ for (;;) {
+ ($statement, $condition, $linenr, $remain, $off, $level) =
+ ctx_statement_block($linenr, $remain, $off);
+ #print "C: c<$condition> s<$statement> remain<$remain>\n";
+ last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+ #print "C: push\n";
+ push(@chunks, [ $condition, $statement ]);
+ }
+
+ return ($level, $linenr, @chunks);
+}
+
+sub ctx_block_get {
+ my ($linenr, $remain, $outer, $open, $close, $off) = @_;
+ my $line;
+ my $start = $linenr - 1;
+ my $blk = '';
+ my @o;
+ my @c;
+ my @res = ();
+
+ my $level = 0;
+ my @stack = ($level);
+ for ($line = $start; $remain > 0; $line++) {
+ next if ($rawlines[$line] =~ /^-/);
+ $remain--;
+
+ $blk .= $rawlines[$line];
+
+ # Handle nested #if/#else.
+ if ($lines[$line] =~ /^.\s*#\s*(?:ifndef|ifdef|if)\s/) {
+ push(@stack, $level);
+ } elsif ($lines[$line] =~ /^.\s*#\s*(?:else|elif)\b/) {
+ $level = $stack[$#stack - 1];
+ } elsif ($lines[$line] =~ /^.\s*#\s*endif\b/) {
+ $level = pop(@stack);
+ }
+
+ foreach my $c (split(//, $lines[$line])) {
+ ##print "C<$c>L<$level><$open$close>O<$off>\n";
+ if ($off > 0) {
+ $off--;
+ next;
+ }
+
+ if ($c eq $close && $level > 0) {
+ $level--;
+ last if ($level == 0);
+ } elsif ($c eq $open) {
+ $level++;
+ }
+ }
+
+ if (!$outer || $level <= 1) {
+ push(@res, $rawlines[$line]);
+ }
+
+ last if ($level == 0);
+ }
+
+ return ($level, @res);
+}
+sub ctx_block_outer {
+ my ($linenr, $remain) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 1, '{', '}', 0);
+ return @r;
+}
+sub ctx_block {
+ my ($linenr, $remain) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+ return @r;
+}
+sub ctx_statement {
+ my ($linenr, $remain, $off) = @_;
+
+ my ($level, @r) = ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+ return @r;
+}
+sub ctx_block_level {
+ my ($linenr, $remain) = @_;
+
+ return ctx_block_get($linenr, $remain, 0, '{', '}', 0);
+}
+sub ctx_statement_level {
+ my ($linenr, $remain, $off) = @_;
+
+ return ctx_block_get($linenr, $remain, 0, '(', ')', $off);
+}
+
+sub ctx_locate_comment {
+ my ($first_line, $end_line) = @_;
+
+ # Catch a comment on the end of the line itself.
+ my ($current_comment) = ($rawlines[$end_line - 1] =~ m@.*(/\*.*\*/)\s*(?:\\\s*)?$@);
+ return $current_comment if (defined $current_comment);
+
+ # Look through the context and try and figure out if there is a
+ # comment.
+ my $in_comment = 0;
+ $current_comment = '';
+ for (my $linenr = $first_line; $linenr < $end_line; $linenr++) {
+ my $line = $rawlines[$linenr - 1];
+ #warn " $line\n";
+ if ($linenr == $first_line and $line =~ m@^.\s*\*@) {
+ $in_comment = 1;
+ }
+ if ($line =~ m@/\*@) {
+ $in_comment = 1;
+ }
+ if (!$in_comment && $current_comment ne '') {
+ $current_comment = '';
+ }
+ $current_comment .= $line . "\n" if ($in_comment);
+ if ($line =~ m@\*/@) {
+ $in_comment = 0;
+ }
+ }
+
+ chomp($current_comment);
+ return($current_comment);
+}
+sub ctx_has_comment {
+ my ($first_line, $end_line) = @_;
+ my $cmt = ctx_locate_comment($first_line, $end_line);
+
+ ##print "LINE: $rawlines[$end_line - 1 ]\n";
+ ##print "CMMT: $cmt\n";
+
+ return ($cmt ne '');
+}
+
+sub raw_line {
+ my ($linenr, $cnt) = @_;
+
+ my $offset = $linenr - 1;
+ $cnt++;
+
+ my $line;
+ while ($cnt) {
+ $line = $rawlines[$offset++];
+ next if (defined($line) && $line =~ /^-/);
+ $cnt--;
+ }
+
+ return $line;
+}
+
+sub cat_vet {
+ my ($vet) = @_;
+ my ($res, $coded);
+
+ $res = '';
+ while ($vet =~ /([^[:cntrl:]]*)([[:cntrl:]]|$)/g) {
+ $res .= $1;
+ if ($2 ne '') {
+ $coded = sprintf("^%c", unpack('C', $2) + 64);
+ $res .= $coded;
+ }
+ }
+ $res =~ s/$/\$/;
+
+ return $res;
+}
+
+my $av_preprocessor = 0;
+my $av_pending;
+my @av_paren_type;
+my $av_pend_colon;
+
+sub annotate_reset {
+ $av_preprocessor = 0;
+ $av_pending = '_';
+ @av_paren_type = ('E');
+ $av_pend_colon = 'O';
+}
+
+sub annotate_values {
+ my ($stream, $type) = @_;
+
+ my $res;
+ my $var = '_' x length($stream);
+ my $cur = $stream;
+
+ print "$stream\n" if ($dbg_values > 1);
+
+ while (length($cur)) {
+ @av_paren_type = ('E') if ($#av_paren_type < 0);
+ print " <" . join('', @av_paren_type) .
+ "> <$type> <$av_pending>" if ($dbg_values > 1);
+ if ($cur =~ /^(\s+)/o) {
+ print "WS($1)\n" if ($dbg_values > 1);
+ if ($1 =~ /\n/ && $av_preprocessor) {
+ $type = pop(@av_paren_type);
+ $av_preprocessor = 0;
+ }
+
+ } elsif ($cur =~ /^(\(\s*$Type\s*)\)/ && $av_pending eq '_') {
+ print "CAST($1)\n" if ($dbg_values > 1);
+ push(@av_paren_type, $type);
+ $type = 'c';
+
+ } elsif ($cur =~ /^($Type)\s*(?:$Ident|,|\)|\(|\s*$)/) {
+ print "DECLARE($1)\n" if ($dbg_values > 1);
+ $type = 'T';
+
+ } elsif ($cur =~ /^($Modifier)\s*/) {
+ print "MODIFIER($1)\n" if ($dbg_values > 1);
+ $type = 'T';
+
+ } elsif ($cur =~ /^(\#\s*define\s*$Ident)(\(?)/o) {
+ print "DEFINE($1,$2)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+ push(@av_paren_type, $type);
+ if ($2 ne '') {
+ $av_pending = 'N';
+ }
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:undef\s*$Ident|include\b))/o) {
+ print "UNDEF($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+ push(@av_paren_type, $type);
+
+ } elsif ($cur =~ /^(\#\s*(?:ifdef|ifndef|if))/o) {
+ print "PRE_START($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+
+ push(@av_paren_type, $type);
+ push(@av_paren_type, $type);
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:else|elif))/o) {
+ print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+
+ push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\#\s*(?:endif))/o) {
+ print "PRE_END($1)\n" if ($dbg_values > 1);
+
+ $av_preprocessor = 1;
+
+ # Assume all arms of the conditional end as this
+ # one does, and continue as if the #endif was not here.
+ pop(@av_paren_type);
+ push(@av_paren_type, $type);
+ $type = 'E';
+
+ } elsif ($cur =~ /^(\\\n)/o) {
+ print "PRECONT($1)\n" if ($dbg_values > 1);
+
+ } elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+ print "ATTR($1)\n" if ($dbg_values > 1);
+ $av_pending = $type;
+ $type = 'N';
+
+ } elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
+ print "SIZEOF($1)\n" if ($dbg_values > 1);
+ if (defined $2) {
+ $av_pending = 'V';
+ }
+ $type = 'N';
+
+ } elsif ($cur =~ /^(if|while|for)\b/o) {
+ print "COND($1)\n" if ($dbg_values > 1);
+ $av_pending = 'E';
+ $type = 'N';
+
+ } elsif ($cur =~/^(case)/o) {
+ print "CASE($1)\n" if ($dbg_values > 1);
+ $av_pend_colon = 'C';
+ $type = 'N';
+
+ } elsif ($cur =~/^(return|else|goto|typeof|__typeof__)\b/o) {
+ print "KEYWORD($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(\()/o) {
+ print "PAREN('$1')\n" if ($dbg_values > 1);
+ push(@av_paren_type, $av_pending);
+ $av_pending = '_';
+ $type = 'N';
+
+ } elsif ($cur =~ /^(\))/o) {
+ my $new_type = pop(@av_paren_type);
+ if ($new_type ne '_') {
+ $type = $new_type;
+ print "PAREN('$1') -> $type\n"
+ if ($dbg_values > 1);
+ } else {
+ print "PAREN('$1')\n" if ($dbg_values > 1);
+ }
+
+ } elsif ($cur =~ /^($Ident)\s*\(/o) {
+ print "FUNC($1)\n" if ($dbg_values > 1);
+ $type = 'V';
+ $av_pending = 'V';
+
+ } elsif ($cur =~ /^($Ident\s*):(?:\s*\d+\s*(,|=|;))?/) {
+ if (defined $2 && $type eq 'C' || $type eq 'T') {
+ $av_pend_colon = 'B';
+ } elsif ($type eq 'E') {
+ $av_pend_colon = 'L';
+ }
+ print "IDENT_COLON($1,$type>$av_pend_colon)\n" if ($dbg_values > 1);
+ $type = 'V';
+
+ } elsif ($cur =~ /^($Ident|$Constant)/o) {
+ print "IDENT($1)\n" if ($dbg_values > 1);
+ $type = 'V';
+
+ } elsif ($cur =~ /^($Assignment)/o) {
+ print "ASSIGN($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~/^(;|{|})/) {
+ print "END($1)\n" if ($dbg_values > 1);
+ $type = 'E';
+ $av_pend_colon = 'O';
+
+ } elsif ($cur =~/^(,)/) {
+ print "COMMA($1)\n" if ($dbg_values > 1);
+ $type = 'C';
+
+ } elsif ($cur =~ /^(\?)/o) {
+ print "QUESTION($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(:)/o) {
+ print "COLON($1,$av_pend_colon)\n" if ($dbg_values > 1);
+
+ substr($var, length($res), 1, $av_pend_colon);
+ if ($av_pend_colon eq 'C' || $av_pend_colon eq 'L') {
+ $type = 'E';
+ } else {
+ $type = 'N';
+ }
+ $av_pend_colon = 'O';
+
+ } elsif ($cur =~ /^(\[)/o) {
+ print "CLOSE($1)\n" if ($dbg_values > 1);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(-(?![->])|\+(?!\+)|\*|\&\&|\&)/o) {
+ my $variant;
+
+ print "OPV($1)\n" if ($dbg_values > 1);
+ if ($type eq 'V') {
+ $variant = 'B';
+ } else {
+ $variant = 'U';
+ }
+
+ substr($var, length($res), 1, $variant);
+ $type = 'N';
+
+ } elsif ($cur =~ /^($Operators)/o) {
+ print "OP($1)\n" if ($dbg_values > 1);
+ if ($1 ne '++' && $1 ne '--') {
+ $type = 'N';
+ }
+
+ } elsif ($cur =~ /(^.)/o) {
+ print "C($1)\n" if ($dbg_values > 1);
+ }
+ if (defined $1) {
+ $cur = substr($cur, length($1));
+ $res .= $type x length($1);
+ }
+ }
+
+ return ($res, $var);
+}
+
+sub possible {
+ my ($possible, $line) = @_;
+ my $notPermitted = qr{(?:
+ ^(?:
+ $Modifier|
+ $Storage|
+ $Type|
+ DEFINE_\S+
+ )$|
+ ^(?:
+ goto|
+ return|
+ case|
+ else|
+ asm|__asm__|
+ do|
+ \#|
+ \#\#|
+ )(?:\s|$)|
+ ^(?:typedef|struct|enum)\b
+ )}x;
+ warn "CHECK<$possible> ($line)\n" if ($dbg_possible > 2);
+ if ($possible !~ $notPermitted) {
+ # Check for modifiers.
+ $possible =~ s/\s*$Storage\s*//g;
+ $possible =~ s/\s*$Sparse\s*//g;
+ if ($possible =~ /^\s*$/) {
+
+ } elsif ($possible =~ /\s/) {
+ $possible =~ s/\s*$Type\s*//g;
+ for my $modifier (split(' ', $possible)) {
+ if ($modifier !~ $notPermitted) {
+ warn "MODIFIER: $modifier ($possible) ($line)\n" if ($dbg_possible);
+ push(@modifierList, $modifier);
+ }
+ }
+
+ } else {
+ warn "POSSIBLE: $possible ($line)\n" if ($dbg_possible);
+ push(@typeList, $possible);
+ }
+ build_types();
+ } else {
+ warn "NOTPOSS: $possible ($line)\n" if ($dbg_possible > 1);
+ }
+}
+
+my $prefix = '';
+
+sub show_type {
+ return !defined $ignore_type{$_[0]};
+}
+
+sub report {
+ if (!show_type($_[1]) ||
+ (defined $tst_only && $_[2] !~ /\Q$tst_only\E/)) {
+ return 0;
+ }
+ my $line;
+ if ($show_types) {
+ $line = "$prefix$_[0]:$_[1]: $_[2]\n";
+ } else {
+ $line = "$prefix$_[0]: $_[2]\n";
+ }
+ $line = (split('\n', $line))[0] . "\n" if ($terse);
+
+ push(our @report, $line);
+
+ return 1;
+}
+sub report_dump {
+ our @report;
+}
+
+sub ERROR {
+ if (report("ERROR", $_[0], $_[1])) {
+ our $clean = 0;
+ our $cnt_error++;
+ }
+}
+sub WARN {
+ if (report("WARNING", $_[0], $_[1])) {
+ our $clean = 0;
+ our $cnt_warn++;
+ }
+}
+sub CHK {
+ if ($check && report("CHECK", $_[0], $_[1])) {
+ our $clean = 0;
+ our $cnt_chk++;
+ }
+}
+
+sub check_absolute_file {
+ my ($absolute, $herecurr) = @_;
+ my $file = $absolute;
+
+ ##print "absolute<$absolute>\n";
+
+ # See if any suffix of this path is a path within the tree.
+ while ($file =~ s@^[^/]*/@@) {
+ if (-f "$root/$file") {
+ ##print "file<$file>\n";
+ last;
+ }
+ }
+ if (! -f _) {
+ return 0;
+ }
+
+ # It is, so see if the prefix is acceptable.
+ my $prefix = $absolute;
+ substr($prefix, -length($file)) = '';
+
+ ##print "prefix<$prefix>\n";
+ if ($prefix ne ".../") {
+ WARN("USE_RELATIVE_PATH",
+ "use relative pathname instead of absolute in changelog text\n" . $herecurr);
+ }
+}
+
+sub pos_last_openparen {
+ my ($line) = @_;
+
+ my $pos = 0;
+
+ my $opens = $line =~ tr/\(/\(/;
+ my $closes = $line =~ tr/\)/\)/;
+
+ my $last_openparen = 0;
+
+ if (($opens == 0) || ($closes >= $opens)) {
+ return -1;
+ }
+
+ my $len = length($line);
+
+ for ($pos = 0; $pos < $len; $pos++) {
+ my $string = substr($line, $pos);
+ if ($string =~ /^($FuncArg|$balanced_parens)/) {
+ $pos += length($1) - 1;
+ } elsif (substr($line, $pos, 1) eq '(') {
+ $last_openparen = $pos;
+ } elsif (index($string, '(') == -1) {
+ last;
+ }
+ }
+
+ return $last_openparen + 1;
+}
+
+sub process {
+ my $filename = shift;
+
+ my $linenr=0;
+ my $prevline="";
+ my $prevrawline="";
+ my $stashline="";
+ my $stashrawline="";
+
+ my $length;
+ my $indent;
+ my $previndent=0;
+ my $stashindent=0;
+
+ our $clean = 1;
+ my $signoff = 0;
+ my $is_patch = 0;
+
+ my $in_header_lines = 1;
+ my $in_commit_log = 0; #Scanning lines before patch
+
+ my $non_utf8_charset = 0;
+
+ our @report = ();
+ our $cnt_lines = 0;
+ our $cnt_error = 0;
+ our $cnt_warn = 0;
+ our $cnt_chk = 0;
+
+ # Trace the real file/line as we go.
+ my $realfile = '';
+ my $realline = 0;
+ my $realcnt = 0;
+ my $here = '';
+ my $in_comment = 0;
+ my $comment_edge = 0;
+ my $first_line = 0;
+ my $p1_prefix = '';
+
+ my $prev_values = 'E';
+
+ # suppression flags
+ my %suppress_ifbraces;
+ my %suppress_whiletrailers;
+ my %suppress_export;
+ my $suppress_statement = 0;
+
+ my %camelcase = ();
+
+ # Pre-scan the patch sanitizing the lines.
+ # Pre-scan the patch looking for any __setup documentation.
+ #
+ my @setup_docs = ();
+ my $setup_docs = 0;
+
+ sanitise_line_reset();
+ my $line;
+ foreach my $rawline (@rawlines) {
+ $linenr++;
+ $line = $rawline;
+
+ if ($rawline=~/^\+\+\+\s+(\S+)/) {
+ $setup_docs = 0;
+ if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
+ $setup_docs = 1;
+ }
+ #next;
+ }
+ if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ $realline=$1-1;
+ if (defined $2) {
+ $realcnt=$3+1;
+ } else {
+ $realcnt=1+1;
+ }
+ $in_comment = 0;
+
+ # Guestimate if this is a continuing comment. Run
+ # the context looking for a comment "edge". If this
+ # edge is a close comment then we must be in a comment
+ # at context start.
+ my $edge;
+ my $cnt = $realcnt;
+ for (my $ln = $linenr + 1; $cnt > 0; $ln++) {
+ next if (defined $rawlines[$ln - 1] &&
+ $rawlines[$ln - 1] =~ /^-/);
+ $cnt--;
+ #print "RAW<$rawlines[$ln - 1]>\n";
+ last if (!defined $rawlines[$ln - 1]);
+ if ($rawlines[$ln - 1] =~ m@(/\*|\*/)@ &&
+ $rawlines[$ln - 1] !~ m@"[^"]*(?:/\*|\*/)[^"]*"@) {
+ ($edge) = $1;
+ last;
+ }
+ }
+ if (defined $edge && $edge eq '*/') {
+ $in_comment = 1;
+ }
+
+ # Guestimate if this is a continuing comment. If this
+ # is the start of a diff block and this line starts
+ # ' *' then it is very likely a comment.
+ if (!defined $edge &&
+ $rawlines[$linenr] =~ m@^.\s*(?:\*\*+| \*)(?:\s|$)@)
+ {
+ $in_comment = 1;
+ }
+
+ ##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+ sanitise_line_reset($in_comment);
+
+ } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
+ # Standardise the strings and chars within the input to
+ # simplify matching -- only bother with positive lines.
+ $line = sanitise_line($rawline);
+ }
+ push(@lines, $line);
+
+ if ($realcnt > 1) {
+ $realcnt-- if ($line =~ /^(?:\+| |$)/);
+ } else {
+ $realcnt = 0;
+ }
+
+ #print "==>$rawline\n";
+ #print "-->$line\n";
+
+ if ($setup_docs && $line =~ /^\+/) {
+ push(@setup_docs, $line);
+ }
+ }
+
+ $prefix = '';
+
+ $realcnt = 0;
+ $linenr = 0;
+ foreach my $line (@lines) {
+ $linenr++;
+
+ my $rawline = $rawlines[$linenr - 1];
+
+#extract the line range in the file after the patch is applied
+ if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ $is_patch = 1;
+ $first_line = $linenr + 1;
+ $realline=$1-1;
+ if (defined $2) {
+ $realcnt=$3+1;
+ } else {
+ $realcnt=1+1;
+ }
+ annotate_reset();
+ $prev_values = 'E';
+
+ %suppress_ifbraces = ();
+ %suppress_whiletrailers = ();
+ %suppress_export = ();
+ $suppress_statement = 0;
+ next;
+
+# track the line number as we move through the hunk, note that
+# new versions of GNU diff omit the leading space on completely
+# blank context lines so we need to count that too.
+ } elsif ($line =~ /^( |\+|$)/) {
+ $realline++;
+ $realcnt-- if ($realcnt != 0);
+
+ # Measure the line length and indent.
+ ($length, $indent) = line_stats($rawline);
+
+ # Track the previous line.
+ ($prevline, $stashline) = ($stashline, $line);
+ ($previndent, $stashindent) = ($stashindent, $indent);
+ ($prevrawline, $stashrawline) = ($stashrawline, $rawline);
+
+ #warn "line<$line>\n";
+
+ } elsif ($realcnt == 1) {
+ $realcnt--;
+ }
+
+ my $hunk_line = ($realcnt != 0);
+
+#make up the handle for any error we report on this line
+ $prefix = "$filename:$realline: " if ($emacs && $file);
+ $prefix = "$filename:$linenr: " if ($emacs && !$file);
+
+ $here = "#$linenr: " if (!$file);
+ $here = "#$realline: " if ($file);
+
+ # extract the filename as it passes
+ if ($line =~ /^diff --git.*?(\S+)$/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+ $in_commit_log = 0;
+ } elsif ($line =~ /^\+\+\+\s+(\S+)/) {
+ $realfile = $1;
+ $realfile =~ s@^([^/]*)/@@;
+ $in_commit_log = 0;
+
+ $p1_prefix = $1;
+ if (!$file && $tree && $p1_prefix ne '' &&
+ -e "$root/$p1_prefix") {
+ WARN("PATCH_PREFIX",
+ "patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
+ }
+
+ if ($realfile =~ m@^include/asm/@) {
+ ERROR("MODIFIED_INCLUDE_ASM",
+ "do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+ }
+ next;
+ }
+
+ $here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
+
+ my $hereline = "$here\n$rawline\n";
+ my $herecurr = "$here\n$rawline\n";
+ my $hereprev = "$here\n$prevrawline\n$rawline\n";
+
+ $cnt_lines++ if ($realcnt != 0);
+
+# Check for incorrect file permissions
+ if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
+ my $permhere = $here . "FILE: $realfile\n";
+ if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) {
+ ERROR("EXECUTE_PERMISSIONS",
+ "do not set execute permissions for source files\n" . $permhere);
+ }
+ }
+
+# Check the patch for a signoff:
+ if ($line =~ /^\s*signed-off-by:/i) {
+ $signoff++;
+ $in_commit_log = 0;
+ }
+
+# Check signature styles
+ if (!$in_header_lines &&
+ $line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
+ my $space_before = $1;
+ my $sign_off = $2;
+ my $space_after = $3;
+ my $email = $4;
+ my $ucfirst_sign_off = ucfirst(lc($sign_off));
+
+ if ($sign_off !~ /$signature_tags/) {
+ WARN("BAD_SIGN_OFF",
+ "Non-standard signature: $sign_off\n" . $herecurr);
+ }
+ if (defined $space_before && $space_before ne "") {
+ WARN("BAD_SIGN_OFF",
+ "Do not use whitespace before $ucfirst_sign_off\n" . $herecurr);
+ }
+ if ($sign_off =~ /-by:$/i && $sign_off ne $ucfirst_sign_off) {
+ WARN("BAD_SIGN_OFF",
+ "'$ucfirst_sign_off' is the preferred signature form\n" . $herecurr);
+ }
+ if (!defined $space_after || $space_after ne " ") {
+ WARN("BAD_SIGN_OFF",
+ "Use a single space after $ucfirst_sign_off\n" . $herecurr);
+ }
+
+ my ($email_name, $email_address, $comment) = parse_email($email);
+ my $suggested_email = format_email(($email_name, $email_address));
+ if ($suggested_email eq "") {
+ ERROR("BAD_SIGN_OFF",
+ "Unrecognized email address: '$email'\n" . $herecurr);
+ } else {
+ my $dequoted = $suggested_email;
+ $dequoted =~ s/^"//;
+ $dequoted =~ s/" </ </;
+ # Don't force email to have quotes
+ # Allow just an angle bracketed address
+ if ("$dequoted$comment" ne $email &&
+ "<$email_address>$comment" ne $email &&
+ "$suggested_email$comment" ne $email) {
+ WARN("BAD_SIGN_OFF",
+ "email address '$email' might be better as '$suggested_email$comment'\n" . $herecurr);
+ }
+ }
+ }
+
+# Check for wrappage within a valid hunk of the file
+ if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
+ ERROR("CORRUPTED_PATCH",
+ "patch seems to be corrupt (line wrapped?)\n" .
+ $herecurr) if (!$emitted_corrupt++);
+ }
+
+# Check for absolute kernel paths.
+ if ($tree) {
+ while ($line =~ m{(?:^|\s)(/\S*)}g) {
+ my $file = $1;
+
+ if ($file =~ m{^(.*?)(?::\d+)+:?$} &&
+ check_absolute_file($1, $herecurr)) {
+ #
+ } else {
+ check_absolute_file($file, $herecurr);
+ }
+ }
+ }
+
+# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
+ if (($realfile =~ /^$/ || $line =~ /^\+/) &&
+ $rawline !~ m/^$UTF8*$/) {
+ my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+ my $blank = copy_spacing($rawline);
+ my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+ my $hereptr = "$hereline$ptr\n";
+
+ CHK("INVALID_UTF8",
+ "Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
+ }
+
+# Check if it's the start of a commit log
+# (not a header line and we haven't seen the patch filename)
+ if ($in_header_lines && $realfile =~ /^$/ &&
+ $rawline !~ /^(commit\b|from\b|[\w-]+:).+$/i) {
+ $in_header_lines = 0;
+ $in_commit_log = 1;
+ }
+
+# Check if there is UTF-8 in a commit log when a mail header has explicitly
+# declined it, i.e defined some charset where it is missing.
+ if ($in_header_lines &&
+ $rawline =~ /^Content-Type:.+charset="(.+)".*$/ &&
+ $1 !~ /utf-8/i) {
+ $non_utf8_charset = 1;
+ }
+
+ if ($in_commit_log && $non_utf8_charset && $realfile =~ /^$/ &&
+ $rawline =~ /$NON_ASCII_UTF8/) {
+ WARN("UTF8_BEFORE_PATCH",
+ "8-bit UTF-8 used in possible commit log\n" . $herecurr);
+ }
+
+# ignore non-hunk lines and lines being removed
+ next if (!$hunk_line || $line =~ /^-/);
+
+#trailing whitespace
+ if ($line =~ /^\+.*\015/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("DOS_LINE_ENDINGS",
+ "DOS line endings\n" . $herevet);
+
+ } elsif ($rawline =~ /^\+.*\S\s+$/ || $rawline =~ /^\+\s+$/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("TRAILING_WHITESPACE",
+ "trailing whitespace\n" . $herevet);
+ $rpt_cleaners = 1;
+ }
+
+# check for Kconfig help text having a real description
+# Only applies when adding the entry originally, after that we do not have
+# sufficient context to determine whether it is indeed long enough.
+ if ($realfile =~ /Kconfig/ &&
+ $line =~ /.\s*config\s+/) {
+ my $length = 0;
+ my $cnt = $realcnt;
+ my $ln = $linenr + 1;
+ my $f;
+ my $is_start = 0;
+ my $is_end = 0;
+ for (; $cnt > 0 && defined $lines[$ln - 1]; $ln++) {
+ $f = $lines[$ln - 1];
+ $cnt-- if ($lines[$ln - 1] !~ /^-/);
+ $is_end = $lines[$ln - 1] =~ /^\+/;
+
+ next if ($f =~ /^-/);
+
+ if ($lines[$ln - 1] =~ /.\s*(?:bool|tristate)\s*\"/) {
+ $is_start = 1;
+ } elsif ($lines[$ln - 1] =~ /.\s*(?:---)?help(?:---)?$/) {
+ $length = -1;
+ }
+
+ $f =~ s/^.//;
+ $f =~ s/#.*//;
+ $f =~ s/^\s+//;
+ next if ($f =~ /^$/);
+ if ($f =~ /^\s*config\s/) {
+ $is_end = 1;
+ last;
+ }
+ $length++;
+ }
+ WARN("CONFIG_DESCRIPTION",
+ "please write a paragraph that describes the config symbol fully\n" . $herecurr) if ($is_start && $is_end && $length < 4);
+ #print "is_start<$is_start> is_end<$is_end> length<$length>\n";
+ }
+
+# discourage the addition of CONFIG_EXPERIMENTAL in Kconfig.
+ if ($realfile =~ /Kconfig/ &&
+ $line =~ /.\s*depends on\s+.*\bEXPERIMENTAL\b/) {
+ WARN("CONFIG_EXPERIMENTAL",
+ "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
+ }
+
+ if (($realfile =~ /Makefile.*/ || $realfile =~ /Kbuild.*/) &&
+ ($line =~ /\+(EXTRA_[A-Z]+FLAGS).*/)) {
+ my $flag = $1;
+ my $replacement = {
+ 'EXTRA_AFLAGS' => 'asflags-y',
+ 'EXTRA_CFLAGS' => 'ccflags-y',
+ 'EXTRA_CPPFLAGS' => 'cppflags-y',
+ 'EXTRA_LDFLAGS' => 'ldflags-y',
+ };
+
+ WARN("DEPRECATED_VARIABLE",
+ "Use of $flag is deprecated, please use \`$replacement->{$flag} instead.\n" . $herecurr) if ($replacement->{$flag});
+ }
+
+# check we are in a valid source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/);
+
+#line length limit
+ if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
+ $rawline !~ /^.\s*\*\s*\@$Ident\s/ &&
+ !($line =~ /^\+\s*$logFunctions\s*\(\s*(?:(KERN_\S+\s*|[^"]*))?"[X\t]*"\s*(?:|,|\)\s*;)\s*$/ ||
+ $line =~ /^\+\s*"[^"]*"\s*(?:\s*|,|\)\s*;)\s*$/) &&
+ $length > $max_line_length)
+ {
+ WARN("LONG_LINE",
+ "line over $max_line_length characters\n" . $herecurr);
+ }
+
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string. Limited to strings used as parameters (those
+# following an open parenthesis), which almost completely eliminates false
+# positives, as well as warning only once per parameter rather than once per
+# line of the string. Make an exception when the previous string ends in a
+# newline (multiple lines in one string constant) or \n\t (common in inline
+# assembly to indent the instruction on the following line).
+ if ($line =~ /^\+\s*"/ &&
+ $prevline =~ /"\s*$/ &&
+ $prevline =~ /\(/ &&
+ $prevrawline !~ /\\n(?:\\t)*"\s*$/) {
+ WARN("SPLIT_STRING",
+ "quoted string split across lines\n" . $hereprev);
+ }
+
+# check for spaces before a quoted newline
+ if ($rawline =~ /^.*\".*\s\\n/) {
+ WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
+ "unnecessary whitespace before a quoted newline\n" . $herecurr);
+ }
+
+# check for adding lines without a newline.
+ if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
+ WARN("MISSING_EOF_NEWLINE",
+ "adding a line without newline at end of file\n" . $herecurr);
+ }
+
+# Blackfin: use hi/lo macros
+ if ($realfile =~ m@arch/blackfin/.*\.S$@) {
+ if ($line =~ /\.[lL][[:space:]]*=.*&[[:space:]]*0x[fF][fF][fF][fF]/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("LO_MACRO",
+ "use the LO() macro, not (... & 0xFFFF)\n" . $herevet);
+ }
+ if ($line =~ /\.[hH][[:space:]]*=.*>>[[:space:]]*16/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("HI_MACRO",
+ "use the HI() macro, not (... >> 16)\n" . $herevet);
+ }
+ }
+
+# check we are in a valid source file C or perl if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c|pl)$/);
+
+# at the beginning of a line any tabs must come first and anything
+# more than 8 must use tabs.
+ if ($rawline =~ /^\+\s* \t\s*\S/ ||
+ $rawline =~ /^\+\s* \s*/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ ERROR("CODE_INDENT",
+ "code indent should use tabs where possible\n" . $herevet);
+ $rpt_cleaners = 1;
+ }
+
+# check for space before tabs.
+ if ($rawline =~ /^\+/ && $rawline =~ / \t/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ WARN("SPACE_BEFORE_TAB",
+ "please, no space before tabs\n" . $herevet);
+ }
+
+# check for && or || at the start of a line
+ if ($rawline =~ /^\+\s*(&&|\|\|)/) {
+ CHK("LOGICAL_CONTINUATIONS",
+ "Logical continuations should be on the previous line\n" . $hereprev);
+ }
+
+# check multi-line statement indentation matches previous line
+ if ($^V && $^V ge 5.10.0 &&
+ $prevline =~ /^\+(\t*)(if \(|$Ident\().*(\&\&|\|\||,)\s*$/) {
+ $prevline =~ /^\+(\t*)(.*)$/;
+ my $oldindent = $1;
+ my $rest = $2;
+
+ my $pos = pos_last_openparen($rest);
+ if ($pos >= 0) {
+ $line =~ /^(\+| )([ \t]*)/;
+ my $newindent = $2;
+
+ my $goodtabindent = $oldindent .
+ "\t" x ($pos / 8) .
+ " " x ($pos % 8);
+ my $goodspaceindent = $oldindent . " " x $pos;
+
+ if ($newindent ne $goodtabindent &&
+ $newindent ne $goodspaceindent) {
+ CHK("PARENTHESIS_ALIGNMENT",
+ "Alignment should match open parenthesis\n" . $hereprev);
+ }
+ }
+ }
+
+ if ($line =~ /^\+.*\*[ \t]*\)[ \t]+/) {
+ CHK("SPACING",
+ "No space is necessary after a cast\n" . $hereprev);
+ }
+
+ if ($realfile =~ m@^(drivers/net/|net/)@ &&
+ $rawline =~ /^\+[ \t]*\/\*[ \t]*$/ &&
+ $prevrawline =~ /^\+[ \t]*$/) {
+ WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+ "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev);
+ }
+
+ if ($realfile =~ m@^(drivers/net/|net/)@ &&
+ $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */
+ $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/
+ $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/
+ $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */
+ WARN("NETWORKING_BLOCK_COMMENT_STYLE",
+ "networking block comments put the trailing */ on a separate line\n" . $herecurr);
+ }
+
+# check for spaces at the beginning of a line.
+# Exceptions:
+# 1) within comments
+# 2) indented preprocessor commands
+# 3) hanging labels
+ if ($rawline =~ /^\+ / && $line !~ /\+ *(?:$;|#|$Ident:)/) {
+ my $herevet = "$here\n" . cat_vet($rawline) . "\n";
+ WARN("LEADING_SPACE",
+ "please, no spaces at the start of a line\n" . $herevet);
+ }
+
+# check we are in a valid C source file if not then ignore this hunk
+ next if ($realfile !~ /\.(h|c)$/);
+
+# discourage the addition of CONFIG_EXPERIMENTAL in #if(def).
+ if ($line =~ /^\+\s*\#\s*if.*\bCONFIG_EXPERIMENTAL\b/) {
+ WARN("CONFIG_EXPERIMENTAL",
+ "Use of CONFIG_EXPERIMENTAL is deprecated. For alternatives, see https://lkml.org/lkml/2012/10/23/580\n");
+ }
+
+# check for RCS/CVS revision markers
+ if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
+ WARN("CVS_KEYWORD",
+ "CVS style keyword markers, these will _not_ be updated\n". $herecurr);
+ }
+
+# Blackfin: don't use __builtin_bfin_[cs]sync
+ if ($line =~ /__builtin_bfin_csync/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("CSYNC",
+ "use the CSYNC() macro in asm/blackfin.h\n" . $herevet);
+ }
+ if ($line =~ /__builtin_bfin_ssync/) {
+ my $herevet = "$here\n" . cat_vet($line) . "\n";
+ ERROR("SSYNC",
+ "use the SSYNC() macro in asm/blackfin.h\n" . $herevet);
+ }
+
+# check for old HOTPLUG __dev<foo> section markings
+ if ($line =~ /\b(__dev(init|exit)(data|const|))\b/) {
+ WARN("HOTPLUG_SECTION",
+ "Using $1 is unnecessary\n" . $herecurr);
+ }
+
+# Check for potential 'bare' types
+ my ($stat, $cond, $line_nr_next, $remain_next, $off_next,
+ $realline_next);
+#print "LINE<$line>\n";
+ if ($linenr >= $suppress_statement &&
+ $realcnt && $line =~ /.\s*\S/) {
+ ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+ ctx_statement_block($linenr, $realcnt, 0);
+ $stat =~ s/\n./\n /g;
+ $cond =~ s/\n./\n /g;
+
+#print "linenr<$linenr> <$stat>\n";
+ # If this statement has no statement boundaries within
+ # it there is no point in retrying a statement scan
+ # until we hit end of it.
+ my $frag = $stat; $frag =~ s/;+\s*$//;
+ if ($frag !~ /(?:{|;)/) {
+#print "skip<$line_nr_next>\n";
+ $suppress_statement = $line_nr_next;
+ }
+
+ # Find the real next line.
+ $realline_next = $line_nr_next;
+ if (defined $realline_next &&
+ (!defined $lines[$realline_next - 1] ||
+ substr($lines[$realline_next - 1], $off_next) =~ /^\s*$/)) {
+ $realline_next++;
+ }
+
+ my $s = $stat;
+ $s =~ s/{.*$//s;
+
+ # Ignore goto labels.
+ if ($s =~ /$Ident:\*$/s) {
+
+ # Ignore functions being called
+ } elsif ($s =~ /^.\s*$Ident\s*\(/s) {
+
+ } elsif ($s =~ /^.\s*else\b/s) {
+
+ # declarations always start with types
+ } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?((?:\s*$Ident)+?)\b(?:\s+$Sparse)?\s*\**\s*(?:$Ident|\(\*[^\)]*\))(?:\s*$Modifier)?\s*(?:;|=|,|\()/s) {
+ my $type = $1;
+ $type =~ s/\s+/ /g;
+ possible($type, "A:" . $s);
+
+ # definitions in global scope can only start with types
+ } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b\s*(?!:)/s) {
+ possible($1, "B:" . $s);
+ }
+
+ # any (foo ... *) is a pointer cast, and foo is a type
+ while ($s =~ /\(($Ident)(?:\s+$Sparse)*[\s\*]+\s*\)/sg) {
+ possible($1, "C:" . $s);
+ }
+
+ # Check for any sort of function declaration.
+ # int foo(something bar, other baz);
+ # void (*store_gdt)(x86_descr_ptr *);
+ if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
+ my ($name_len) = length($1);
+
+ my $ctx = $s;
+ substr($ctx, 0, $name_len + 1, '');
+ $ctx =~ s/\)[^\)]*$//;
+
+ for my $arg (split(/\s*,\s*/, $ctx)) {
+ if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/s || $arg =~ /^($Ident)$/s) {
+
+ possible($1, "D:" . $s);
+ }
+ }
+ }
+
+ }
+
+#
+# Checks which may be anchored in the context.
+#
+
+# Check for switch () and associated case and default
+# statements should be at the same indent.
+ if ($line=~/\bswitch\s*\(.*\)/) {
+ my $err = '';
+ my $sep = '';
+ my @ctx = ctx_block_outer($linenr, $realcnt);
+ shift(@ctx);
+ for my $ctx (@ctx) {
+ my ($clen, $cindent) = line_stats($ctx);
+ if ($ctx =~ /^\+\s*(case\s+|default:)/ &&
+ $indent != $cindent) {
+ $err .= "$sep$ctx\n";
+ $sep = '';
+ } else {
+ $sep = "[...]\n";
+ }
+ }
+ if ($err ne '') {
+ ERROR("SWITCH_CASE_INDENT_LEVEL",
+ "switch and case should be at the same indent\n$hereline$err");
+ }
+ }
+
+# if/while/etc brace do not go on next line, unless defining a do while loop,
+# or if that brace on the next line is for something else
+ if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.\s*\#/) {
+ my $pre_ctx = "$1$2";
+
+ my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
+
+ if ($line =~ /^\+\t{6,}/) {
+ WARN("DEEP_INDENTATION",
+ "Too many leading tabs - consider code refactoring\n" . $herecurr);
+ }
+
+ my $ctx_cnt = $realcnt - $#ctx - 1;
+ my $ctx = join("\n", @ctx);
+
+ my $ctx_ln = $linenr;
+ my $ctx_skip = $realcnt;
+
+ while ($ctx_skip > $ctx_cnt || ($ctx_skip == $ctx_cnt &&
+ defined $lines[$ctx_ln - 1] &&
+ $lines[$ctx_ln - 1] =~ /^-/)) {
+ ##print "SKIP<$ctx_skip> CNT<$ctx_cnt>\n";
+ $ctx_skip-- if (!defined $lines[$ctx_ln - 1] || $lines[$ctx_ln - 1] !~ /^-/);
+ $ctx_ln++;
+ }
+
+ #print "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+ #print "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
+
+ if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+ ERROR("OPEN_BRACE",
+ "that open brace { should be on the previous line\n" .
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+ }
+ if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+ $ctx =~ /\)\s*\;\s*$/ &&
+ defined $lines[$ctx_ln - 1])
+ {
+ my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
+ if ($nindent > $indent) {
+ WARN("TRAILING_SEMICOLON",
+ "trailing semicolon indicates no statements, indent implies otherwise\n" .
+ "$here\n$ctx\n$rawlines[$ctx_ln - 1]\n");
+ }
+ }
+ }
+
+# Check relative indent for conditionals and blocks.
+ if ($line =~ /\b(?:(?:if|while|for)\s*\(|do\b)/ && $line !~ /^.\s*#/ && $line !~ /\}\s*while\s*/) {
+ ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+ ctx_statement_block($linenr, $realcnt, 0)
+ if (!defined $stat);
+ my ($s, $c) = ($stat, $cond);
+
+ substr($s, 0, length($c), '');
+
+ # Make sure we remove the line prefixes as we have
+ # none on the first line, and are going to readd them
+ # where necessary.
+ $s =~ s/\n./\n/gs;
+
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
+
+ # We want to check the first line inside the block
+ # starting at the end of the conditional, so remove:
+ # 1) any blank line termination
+ # 2) any opening brace { on end of the line
+ # 3) any do (...) {
+ my $continuation = 0;
+ my $check = 0;
+ $s =~ s/^.*\bdo\b//;
+ $s =~ s/^\s*{//;
+ if ($s =~ s/^\s*\\//) {
+ $continuation = 1;
+ }
+ if ($s =~ s/^\s*?\n//) {
+ $check = 1;
+ $cond_lines++;
+ }
+
+ # Also ignore a loop construct at the end of a
+ # preprocessor statement.
+ if (($prevline =~ /^.\s*#\s*define\s/ ||
+ $prevline =~ /\\\s*$/) && $continuation == 0) {
+ $check = 0;
+ }
+
+ my $cond_ptr = -1;
+ $continuation = 0;
+ while ($cond_ptr != $cond_lines) {
+ $cond_ptr = $cond_lines;
+
+ # If we see an #else/#elif then the code
+ # is not linear.
+ if ($s =~ /^\s*\#\s*(?:else|elif)/) {
+ $check = 0;
+ }
+
+ # Ignore:
+ # 1) blank lines, they should be at 0,
+ # 2) preprocessor lines, and
+ # 3) labels.
+ if ($continuation ||
+ $s =~ /^\s*?\n/ ||
+ $s =~ /^\s*#\s*?/ ||
+ $s =~ /^\s*$Ident\s*:/) {
+ $continuation = ($s =~ /^.*?\\\n/) ? 1 : 0;
+ if ($s =~ s/^.*?\n//) {
+ $cond_lines++;
+ }
+ }
+ }
+
+ my (undef, $sindent) = line_stats("+" . $s);
+ my $stat_real = raw_line($linenr, $cond_lines);
+
+ # Check if either of these lines are modified, else
+ # this is not this patch's fault.
+ if (!defined($stat_real) ||
+ $stat !~ /^\+/ && $stat_real !~ /^\+/) {
+ $check = 0;
+ }
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
+
+ #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n";
+
+ if ($check && (($sindent % 8) != 0 ||
+ ($sindent <= $indent && $s ne ''))) {
+ WARN("SUSPECT_CODE_INDENT",
+ "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n");
+ }
+ }
+
+ # Track the 'values' across context and added lines.
+ my $opline = $line; $opline =~ s/^./ /;
+ my ($curr_values, $curr_vars) =
+ annotate_values($opline . "\n", $prev_values);
+ $curr_values = $prev_values . $curr_values;
+ if ($dbg_values) {
+ my $outline = $opline; $outline =~ s/\t/ /g;
+ print "$linenr > .$outline\n";
+ print "$linenr > $curr_values\n";
+ print "$linenr > $curr_vars\n";
+ }
+ $prev_values = substr($curr_values, -1);
+
+#ignore lines not being added
+ if ($line=~/^[^\+]/) {next;}
+
+# TEST: allow direct testing of the type matcher.
+ if ($dbg_type) {
+ if ($line =~ /^.\s*$Declare\s*$/) {
+ ERROR("TEST_TYPE",
+ "TEST: is type\n" . $herecurr);
+ } elsif ($dbg_type > 1 && $line =~ /^.+($Declare)/) {
+ ERROR("TEST_NOT_TYPE",
+ "TEST: is not type ($1 is)\n". $herecurr);
+ }
+ next;
+ }
+# TEST: allow direct testing of the attribute matcher.
+ if ($dbg_attr) {
+ if ($line =~ /^.\s*$Modifier\s*$/) {
+ ERROR("TEST_ATTR",
+ "TEST: is attr\n" . $herecurr);
+ } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
+ ERROR("TEST_NOT_ATTR",
+ "TEST: is not attr ($1 is)\n". $herecurr);
+ }
+ next;
+ }
+
+# check for initialisation to aggregates open brace on the next line
+ if ($line =~ /^.\s*{/ &&
+ $prevline =~ /(?:^|[^=])=\s*$/) {
+ ERROR("OPEN_BRACE",
+ "that open brace { should be on the previous line\n" . $hereprev);
+ }
+
+#
+# Checks which are anchored on the added line.
+#
+
+# check for malformed paths in #include statements (uses RAW line)
+ if ($rawline =~ m{^.\s*\#\s*include\s+[<"](.*)[">]}) {
+ my $path = $1;
+ if ($path =~ m{//}) {
+ ERROR("MALFORMED_INCLUDE",
+ "malformed #include filename\n" . $herecurr);
+ }
+ if ($path =~ "^uapi/" && $realfile =~ m@\binclude/uapi/@) {
+ ERROR("UAPI_INCLUDE",
+ "No #include in ...include/uapi/... should use a uapi/ path prefix\n" . $herecurr);
+ }
+ }
+
+# no C99 // comments
+ if ($line =~ m{//}) {
+ ERROR("C99_COMMENTS",
+ "do not use C99 // comments\n" . $herecurr);
+ }
+ # Remove C99 comments.
+ $line =~ s@//.*@@;
+ $opline =~ s@//.*@@;
+
+# EXPORT_SYMBOL should immediately follow the thing it is exporting, consider
+# the whole statement.
+#print "APW <$lines[$realline_next - 1]>\n";
+ if (defined $realline_next &&
+ exists $lines[$realline_next - 1] &&
+ !defined $suppress_export{$realline_next} &&
+ ($lines[$realline_next - 1] =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+ $lines[$realline_next - 1] =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+ # Handle definitions which produce identifiers with
+ # a prefix:
+ # XXX(foo);
+ # EXPORT_SYMBOL(something_foo);
+ my $name = $1;
+ if ($stat =~ /^(?:.\s*}\s*\n)?.([A-Z_]+)\s*\(\s*($Ident)/ &&
+ $name =~ /^${Ident}_$2/) {
+#print "FOO C name<$name>\n";
+ $suppress_export{$realline_next} = 1;
+
+ } elsif ($stat !~ /(?:
+ \n.}\s*$|
+ ^.DEFINE_$Ident\(\Q$name\E\)|
+ ^.DECLARE_$Ident\(\Q$name\E\)|
+ ^.LIST_HEAD\(\Q$name\E\)|
+ ^.(?:$Storage\s+)?$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(|
+ \b\Q$name\E(?:\s+$Attribute)*\s*(?:;|=|\[|\()
+ )/x) {
+#print "FOO A<$lines[$realline_next - 1]> stat<$stat> name<$name>\n";
+ $suppress_export{$realline_next} = 2;
+ } else {
+ $suppress_export{$realline_next} = 1;
+ }
+ }
+ if (!defined $suppress_export{$linenr} &&
+ $prevline =~ /^.\s*$/ &&
+ ($line =~ /EXPORT_SYMBOL.*\((.*)\)/ ||
+ $line =~ /EXPORT_UNUSED_SYMBOL.*\((.*)\)/)) {
+#print "FOO B <$lines[$linenr - 1]>\n";
+ $suppress_export{$linenr} = 2;
+ }
+ if (defined $suppress_export{$linenr} &&
+ $suppress_export{$linenr} == 2) {
+ WARN("EXPORT_SYMBOL",
+ "EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
+ }
+
+# check for global initialisers.
+ if ($line =~ /^.$Type\s*$Ident\s*(?:\s+$Modifier)*\s*=\s*(0|NULL|false)\s*;/) {
+ ERROR("GLOBAL_INITIALISERS",
+ "do not initialise globals to 0 or NULL\n" .
+ $herecurr);
+ }
+# check for static initialisers.
+ if ($line =~ /\bstatic\s.*=\s*(0|NULL|false)\s*;/) {
+ ERROR("INITIALISED_STATIC",
+ "do not initialise statics to 0 or NULL\n" .
+ $herecurr);
+ }
+
+# check for static const char * arrays.
+ if ($line =~ /\bstatic\s+const\s+char\s*\*\s*(\w+)\s*\[\s*\]\s*=\s*/) {
+ WARN("STATIC_CONST_CHAR_ARRAY",
+ "static const char * array should probably be static const char * const\n" .
+ $herecurr);
+ }
+
+# check for static char foo[] = "bar" declarations.
+ if ($line =~ /\bstatic\s+char\s+(\w+)\s*\[\s*\]\s*=\s*"/) {
+ WARN("STATIC_CONST_CHAR_ARRAY",
+ "static char array declaration should probably be static const char\n" .
+ $herecurr);
+ }
+
+# check for declarations of struct pci_device_id
+ if ($line =~ /\bstruct\s+pci_device_id\s+\w+\s*\[\s*\]\s*\=\s*\{/) {
+ WARN("DEFINE_PCI_DEVICE_TABLE",
+ "Use DEFINE_PCI_DEVICE_TABLE for struct pci_device_id\n" . $herecurr);
+ }
+
+# check for new typedefs, only function parameters and sparse annotations
+# make sense.
+ if ($line =~ /\btypedef\s/ &&
+ $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ &&
+ $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ &&
+ $line !~ /\b$typeTypedefs\b/ &&
+ $line !~ /\b__bitwise(?:__|)\b/) {
+ WARN("NEW_TYPEDEFS",
+ "do not add new typedefs\n" . $herecurr);
+ }
+
+# * goes on variable not on type
+ # (char*[ const])
+ while ($line =~ m{(\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\))}g) {
+ #print "AA<$1>\n";
+ my ($from, $to) = ($2, $2);
+
+ # Should start with a space.
+ $to =~ s/^(\S)/ $1/;
+ # Should not end with a space.
+ $to =~ s/\s+$//;
+ # '*'s should not have spaces between.
+ while ($to =~ s/\*\s+\*/\*\*/) {
+ }
+
+ #print "from<$from> to<$to>\n";
+ if ($from ne $to) {
+ ERROR("POINTER_LOCATION",
+ "\"(foo$from)\" should be \"(foo$to)\"\n" . $herecurr);
+ }
+ }
+ while ($line =~ m{(\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident))}g) {
+ #print "BB<$1>\n";
+ my ($from, $to, $ident) = ($2, $2, $3);
+
+ # Should start with a space.
+ $to =~ s/^(\S)/ $1/;
+ # Should not end with a space.
+ $to =~ s/\s+$//;
+ # '*'s should not have spaces between.
+ while ($to =~ s/\*\s+\*/\*\*/) {
+ }
+ # Modifiers should have spaces.
+ $to =~ s/(\b$Modifier$)/$1 /;
+
+ #print "from<$from> to<$to> ident<$ident>\n";
+ if ($from ne $to && $ident !~ /^$Modifier$/) {
+ ERROR("POINTER_LOCATION",
+ "\"foo${from}bar\" should be \"foo${to}bar\"\n" . $herecurr);
+ }
+ }
+
+# # no BUG() or BUG_ON()
+# if ($line =~ /\b(BUG|BUG_ON)\b/) {
+# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n";
+# print "$herecurr";
+# $clean = 0;
+# }
+
+ if ($line =~ /\bLINUX_VERSION_CODE\b/) {
+ WARN("LINUX_VERSION_CODE",
+ "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr);
+ }
+
+# check for uses of printk_ratelimit
+ if ($line =~ /\bprintk_ratelimit\s*\(/) {
+ WARN("PRINTK_RATELIMITED",
+"Prefer printk_ratelimited or pr_<level>_ratelimited to printk_ratelimit\n" . $herecurr);
+ }
+
+# printk should use KERN_* levels. Note that follow on printk's on the
+# same line do not need a level, so we use the current block context
+# to try and find and validate the current printk. In summary the current
+# printk includes all preceding printk's which have no newline on the end.
+# we assume the first bad printk is the one to report.
+ if ($line =~ /\bprintk\((?!KERN_)\s*"/) {
+ my $ok = 0;
+ for (my $ln = $linenr - 1; $ln >= $first_line; $ln--) {
+ #print "CHECK<$lines[$ln - 1]\n";
+ # we have a preceding printk if it ends
+ # with "\n" ignore it, else it is to blame
+ if ($lines[$ln - 1] =~ m{\bprintk\(}) {
+ if ($rawlines[$ln - 1] !~ m{\\n"}) {
+ $ok = 1;
+ }
+ last;
+ }
+ }
+ if ($ok == 0) {
+ WARN("PRINTK_WITHOUT_KERN_LEVEL",
+ "printk() should include KERN_ facility level\n" . $herecurr);
+ }
+ }
+
+ if ($line =~ /\bprintk\s*\(\s*KERN_([A-Z]+)/) {
+ my $orig = $1;
+ my $level = lc($orig);
+ $level = "warn" if ($level eq "warning");
+ my $level2 = $level;
+ $level2 = "dbg" if ($level eq "debug");
+ WARN("PREFER_PR_LEVEL",
+ "Prefer netdev_$level2(netdev, ... then dev_$level2(dev, ... then pr_$level(... to printk(KERN_$orig ...\n" . $herecurr);
+ }
+
+ if ($line =~ /\bpr_warning\s*\(/) {
+ WARN("PREFER_PR_LEVEL",
+ "Prefer pr_warn(... to pr_warning(...\n" . $herecurr);
+ }
+
+ if ($line =~ /\bdev_printk\s*\(\s*KERN_([A-Z]+)/) {
+ my $orig = $1;
+ my $level = lc($orig);
+ $level = "warn" if ($level eq "warning");
+ $level = "dbg" if ($level eq "debug");
+ WARN("PREFER_DEV_LEVEL",
+ "Prefer dev_$level(... to dev_printk(KERN_$orig, ...\n" . $herecurr);
+ }
+
+# function brace can't be on same line, except for #defines of do while,
+# or if closed on same line
+ if (($line=~/$Type\s*$Ident\(.*\).*\s{/) and
+ !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) {
+ ERROR("OPEN_BRACE",
+ "open brace '{' following function declarations go on the next line\n" . $herecurr);
+ }
+
+# open braces for enum, union and struct go on the same line.
+ if ($line =~ /^.\s*{/ &&
+ $prevline =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?\s*$/) {
+ ERROR("OPEN_BRACE",
+ "open brace '{' following $1 go on the same line\n" . $hereprev);
+ }
+
+# missing space after union, struct or enum definition
+ if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
+ WARN("SPACING",
+ "missing space after $1 definition\n" . $herecurr);
+ }
+
+# check for spacing round square brackets; allowed:
+# 1. with a type on the left -- int [] a;
+# 2. at the beginning of a line for slice initialisers -- [0...10] = 5,
+# 3. inside a curly brace -- = { [0...10] = 5 }
+ while ($line =~ /(.*?\s)\[/g) {
+ my ($where, $prefix) = ($-[1], $1);
+ if ($prefix !~ /$Type\s+$/ &&
+ ($where != 0 || $prefix !~ /^.\s+$/) &&
+ $prefix !~ /[{,]\s+$/) {
+ ERROR("BRACKET_SPACE",
+ "space prohibited before open square bracket '['\n" . $herecurr);
+ }
+ }
+
+# check for spaces between functions and their parentheses.
+ while ($line =~ /($Ident)\s+\(/g) {
+ my $name = $1;
+ my $ctx_before = substr($line, 0, $-[1]);
+ my $ctx = "$ctx_before$name";
+
+ # Ignore those directives where spaces _are_ permitted.
+ if ($name =~ /^(?:
+ if|for|while|switch|return|case|
+ volatile|__volatile__|
+ __attribute__|format|__extension__|
+ asm|__asm__)$/x)
+ {
+
+ # cpp #define statements have non-optional spaces, ie
+ # if there is a space between the name and the open
+ # parenthesis it is simply not a parameter group.
+ } elsif ($ctx_before =~ /^.\s*\#\s*define\s*$/) {
+
+ # cpp #elif statement condition may start with a (
+ } elsif ($ctx =~ /^.\s*\#\s*elif\s*$/) {
+
+ # If this whole things ends with a type its most
+ # likely a typedef for a function.
+ } elsif ($ctx =~ /$Type$/) {
+
+ } else {
+ WARN("SPACING",
+ "space prohibited between function name and open parenthesis '('\n" . $herecurr);
+ }
+ }
+
+# check for whitespace before a non-naked semicolon
+ if ($line =~ /^\+.*\S\s+;/) {
+ CHK("SPACING",
+ "space prohibited before semicolon\n" . $herecurr);
+ }
+
+# Check operator spacing.
+ if (!($line=~/\#\s*include/)) {
+ my $ops = qr{
+ <<=|>>=|<=|>=|==|!=|
+ \+=|-=|\*=|\/=|%=|\^=|\|=|&=|
+ =>|->|<<|>>|<|>|=|!|~|
+ &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%|
+ \?|:
+ }x;
+ my @elements = split(/($ops|;)/, $opline);
+ my $off = 0;
+
+ my $blank = copy_spacing($opline);
+
+ for (my $n = 0; $n < $#elements; $n += 2) {
+ $off += length($elements[$n]);
+
+ # Pick up the preceding and succeeding characters.
+ my $ca = substr($opline, 0, $off);
+ my $cc = '';
+ if (length($opline) >= ($off + length($elements[$n + 1]))) {
+ $cc = substr($opline, $off + length($elements[$n + 1]));
+ }
+ my $cb = "$ca$;$cc";
+
+ my $a = '';
+ $a = 'V' if ($elements[$n] ne '');
+ $a = 'W' if ($elements[$n] =~ /\s$/);
+ $a = 'C' if ($elements[$n] =~ /$;$/);
+ $a = 'B' if ($elements[$n] =~ /(\[|\()$/);
+ $a = 'O' if ($elements[$n] eq '');
+ $a = 'E' if ($ca =~ /^\s*$/);
+
+ my $op = $elements[$n + 1];
+
+ my $c = '';
+ if (defined $elements[$n + 2]) {
+ $c = 'V' if ($elements[$n + 2] ne '');
+ $c = 'W' if ($elements[$n + 2] =~ /^\s/);
+ $c = 'C' if ($elements[$n + 2] =~ /^$;/);
+ $c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
+ $c = 'O' if ($elements[$n + 2] eq '');
+ $c = 'E' if ($elements[$n + 2] =~ /^\s*\\$/);
+ } else {
+ $c = 'E';
+ }
+
+ my $ctx = "${a}x${c}";
+
+ my $at = "(ctx:$ctx)";
+
+ my $ptr = substr($blank, 0, $off) . "^";
+ my $hereptr = "$hereline$ptr\n";
+
+ # Pull out the value of this operator.
+ my $op_type = substr($curr_values, $off + 1, 1);
+
+ # Get the full operator variant.
+ my $opv = $op . substr($curr_vars, $off, 1);
+
+ # Ignore operators passed as parameters.
+ if ($op_type ne 'V' &&
+ $ca =~ /\s$/ && $cc =~ /^\s*,/) {
+
+# # Ignore comments
+# } elsif ($op =~ /^$;+$/) {
+
+ # ; should have either the end of line or a space or \ after it
+ } elsif ($op eq ';') {
+ if ($ctx !~ /.x[WEBC]/ &&
+ $cc !~ /^\\/ && $cc !~ /^;/) {
+ ERROR("SPACING",
+ "space required after that '$op' $at\n" . $hereptr);
+ }
+
+ # // is a comment
+ } elsif ($op eq '//') {
+
+ # No spaces for:
+ # ->
+ # : when part of a bitfield
+ } elsif ($op eq '->' || $opv eq ':B') {
+ if ($ctx =~ /Wx.|.xW/) {
+ ERROR("SPACING",
+ "spaces prohibited around that '$op' $at\n" . $hereptr);
+ }
+
+ # , must have a space on the right.
+ } elsif ($op eq ',') {
+ if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+ ERROR("SPACING",
+ "space required after that '$op' $at\n" . $hereptr);
+ }
+
+ # '*' as part of a type definition -- reported already.
+ } elsif ($opv eq '*_') {
+ #warn "'*' is part of type\n";
+
+ # unary operators should have a space before and
+ # none after. May be left adjacent to another
+ # unary operator, or a cast
+ } elsif ($op eq '!' || $op eq '~' ||
+ $opv eq '*U' || $opv eq '-U' ||
+ $opv eq '&U' || $opv eq '&&U') {
+ if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+ ERROR("SPACING",
+ "space required before that '$op' $at\n" . $hereptr);
+ }
+ if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
+ # A unary '*' may be const
+
+ } elsif ($ctx =~ /.xW/) {
+ ERROR("SPACING",
+ "space prohibited after that '$op' $at\n" . $hereptr);
+ }
+
+ # unary ++ and unary -- are allowed no space on one side.
+ } elsif ($op eq '++' or $op eq '--') {
+ if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+ ERROR("SPACING",
+ "space required one side of that '$op' $at\n" . $hereptr);
+ }
+ if ($ctx =~ /Wx[BE]/ ||
+ ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+ ERROR("SPACING",
+ "space prohibited before that '$op' $at\n" . $hereptr);
+ }
+ if ($ctx =~ /ExW/) {
+ ERROR("SPACING",
+ "space prohibited after that '$op' $at\n" . $hereptr);
+ }
+
+
+ # << and >> may either have or not have spaces both sides
+ } elsif ($op eq '<<' or $op eq '>>' or
+ $op eq '&' or $op eq '^' or $op eq '|' or
+ $op eq '+' or $op eq '-' or
+ $op eq '*' or $op eq '/' or
+ $op eq '%')
+ {
+ if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
+ ERROR("SPACING",
+ "need consistent spacing around '$op' $at\n" .
+ $hereptr);
+ }
+
+ # A colon needs no spaces before when it is
+ # terminating a case value or a label.
+ } elsif ($opv eq ':C' || $opv eq ':L') {
+ if ($ctx =~ /Wx./) {
+ ERROR("SPACING",
+ "space prohibited before that '$op' $at\n" . $hereptr);
+ }
+
+ # All the others need spaces both sides.
+ } elsif ($ctx !~ /[EWC]x[CWE]/) {
+ my $ok = 0;
+
+ # Ignore email addresses <foo@bar>
+ if (($op eq '<' &&
+ $cc =~ /^\S+\@\S+>/) ||
+ ($op eq '>' &&
+ $ca =~ /<\S+\@\S+$/))
+ {
+ $ok = 1;
+ }
+
+ # Ignore ?:
+ if (($opv eq ':O' && $ca =~ /\?$/) ||
+ ($op eq '?' && $cc =~ /^:/)) {
+ $ok = 1;
+ }
+
+ if ($ok == 0) {
+ ERROR("SPACING",
+ "spaces required around that '$op' $at\n" . $hereptr);
+ }
+ }
+ $off += length($elements[$n + 1]);
+ }
+ }
+
+# check for multiple assignments
+ if ($line =~ /^.\s*$Lval\s*=\s*$Lval\s*=(?!=)/) {
+ CHK("MULTIPLE_ASSIGNMENTS",
+ "multiple assignments should be avoided\n" . $herecurr);
+ }
+
+## # check for multiple declarations, allowing for a function declaration
+## # continuation.
+## if ($line =~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Ident.*/ &&
+## $line !~ /^.\s*$Type\s+$Ident(?:\s*=[^,{]*)?\s*,\s*$Type\s*$Ident.*/) {
+##
+## # Remove any bracketed sections to ensure we do not
+## # falsly report the parameters of functions.
+## my $ln = $line;
+## while ($ln =~ s/\([^\(\)]*\)//g) {
+## }
+## if ($ln =~ /,/) {
+## WARN("MULTIPLE_DECLARATION",
+## "declaring multiple variables together should be avoided\n" . $herecurr);
+## }
+## }
+
+#need space before brace following if, while, etc
+ if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
+ $line =~ /do{/) {
+ ERROR("SPACING",
+ "space required before the open brace '{'\n" . $herecurr);
+ }
+
+# closing brace should have a space following it when it has anything
+# on the line
+ if ($line =~ /}(?!(?:,|;|\)))\S/) {
+ ERROR("SPACING",
+ "space required after that close brace '}'\n" . $herecurr);
+ }
+
+# check spacing on square brackets
+ if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
+ ERROR("SPACING",
+ "space prohibited after that open square bracket '['\n" . $herecurr);
+ }
+ if ($line =~ /\s\]/) {
+ ERROR("SPACING",
+ "space prohibited before that close square bracket ']'\n" . $herecurr);
+ }
+
+# check spacing on parentheses
+ if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
+ $line !~ /for\s*\(\s+;/) {
+ ERROR("SPACING",
+ "space prohibited after that open parenthesis '('\n" . $herecurr);
+ }
+ if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
+ $line !~ /for\s*\(.*;\s+\)/ &&
+ $line !~ /:\s+\)/) {
+ ERROR("SPACING",
+ "space prohibited before that close parenthesis ')'\n" . $herecurr);
+ }
+
+#goto labels aren't indented, allow a single space however
+ if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
+ !($line=~/^. [A-Za-z\d_]+:/) and !($line=~/^.\s+default:/)) {
+ WARN("INDENTED_LABEL",
+ "labels should not be indented\n" . $herecurr);
+ }
+
+# Return is not a function.
+ if (defined($stat) && $stat =~ /^.\s*return(\s*)(\(.*);/s) {
+ my $spacing = $1;
+ my $value = $2;
+
+ # Flatten any parentheses
+ $value =~ s/\(/ \(/g;
+ $value =~ s/\)/\) /g;
+ while ($value =~ s/\[[^\[\]]*\]/1/ ||
+ $value !~ /(?:$Ident|-?$Constant)\s*
+ $Compare\s*
+ (?:$Ident|-?$Constant)/x &&
+ $value =~ s/\([^\(\)]*\)/1/) {
+ }
+#print "value<$value>\n";
+ if ($value =~ /^\s*(?:$Ident|-?$Constant)\s*$/) {
+ ERROR("RETURN_PARENTHESES",
+ "return is not a function, parentheses are not required\n" . $herecurr);
+
+ } elsif ($spacing !~ /\s+/) {
+ ERROR("SPACING",
+ "space required before the open parenthesis '('\n" . $herecurr);
+ }
+ }
+# Return of what appears to be an errno should normally be -'ve
+ if ($line =~ /^.\s*return\s*(E[A-Z]*)\s*;/) {
+ my $name = $1;
+ if ($name ne 'EOF' && $name ne 'ERROR') {
+ WARN("USE_NEGATIVE_ERRNO",
+ "return of an errno should typically be -ve (return -$1)\n" . $herecurr);
+ }
+ }
+
+# Need a space before open parenthesis after if, while etc
+ if ($line=~/\b(if|while|for|switch)\(/) {
+ ERROR("SPACING", "space required before the open parenthesis '('\n" . $herecurr);
+ }
+
+# Check for illegal assignment in if conditional -- and check for trailing
+# statements after the conditional.
+ if ($line =~ /do\s*(?!{)/) {
+ ($stat, $cond, $line_nr_next, $remain_next, $off_next) =
+ ctx_statement_block($linenr, $realcnt, 0)
+ if (!defined $stat);
+ my ($stat_next) = ctx_statement_block($line_nr_next,
+ $remain_next, $off_next);
+ $stat_next =~ s/\n./\n /g;
+ ##print "stat<$stat> stat_next<$stat_next>\n";
+
+ if ($stat_next =~ /^\s*while\b/) {
+ # If the statement carries leading newlines,
+ # then count those as offsets.
+ my ($whitespace) =
+ ($stat_next =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset =
+ statement_rawlines($whitespace) - 1;
+
+ $suppress_whiletrailers{$line_nr_next +
+ $offset} = 1;
+ }
+ }
+ if (!defined $suppress_whiletrailers{$linenr} &&
+ $line =~ /\b(?:if|while|for)\s*\(/ && $line !~ /^.\s*#/) {
+ my ($s, $c) = ($stat, $cond);
+
+ if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/s) {
+ ERROR("ASSIGN_IN_IF",
+ "do not use assignment in if condition\n" . $herecurr);
+ }
+
+ # Find out what is on the end of the line after the
+ # conditional.
+ substr($s, 0, length($c), '');
+ $s =~ s/\n.*//g;
+ $s =~ s/$;//g; # Remove any comments
+ if (length($c) && $s !~ /^\s*{?\s*\\*\s*$/ &&
+ $c !~ /}\s*while\s*/)
+ {
+ # Find out how long the conditional actually is.
+ my @newlines = ($c =~ /\n/gs);
+ my $cond_lines = 1 + $#newlines;
+ my $stat_real = '';
+
+ $stat_real = raw_line($linenr, $cond_lines)
+ . "\n" if ($cond_lines);
+ if (defined($stat_real) && $cond_lines > 1) {
+ $stat_real = "[...]\n$stat_real";
+ }
+
+ ERROR("TRAILING_STATEMENTS",
+ "trailing statements should be on next line\n" . $herecurr . $stat_real);
+ }
+ }
+
+# Check for bitwise tests written as boolean
+ if ($line =~ /
+ (?:
+ (?:\[|\(|\&\&|\|\|)
+ \s*0[xX][0-9]+\s*
+ (?:\&\&|\|\|)
+ |
+ (?:\&\&|\|\|)
+ \s*0[xX][0-9]+\s*
+ (?:\&\&|\|\||\)|\])
+ )/x)
+ {
+ WARN("HEXADECIMAL_BOOLEAN_TEST",
+ "boolean test with hexadecimal, perhaps just 1 \& or \|?\n" . $herecurr);
+ }
+
+# if and else should not have general statements after it
+ if ($line =~ /^.\s*(?:}\s*)?else\b(.*)/) {
+ my $s = $1;
+ $s =~ s/$;//g; # Remove any comments
+ if ($s !~ /^\s*(?:\sif|(?:{|)\s*\\?\s*$)/) {
+ ERROR("TRAILING_STATEMENTS",
+ "trailing statements should be on next line\n" . $herecurr);
+ }
+ }
+# if should not continue a brace
+ if ($line =~ /}\s*if\b/) {
+ ERROR("TRAILING_STATEMENTS",
+ "trailing statements should be on next line\n" .
+ $herecurr);
+ }
+# case and default should not have general statements after them
+ if ($line =~ /^.\s*(?:case\s*.*|default\s*):/g &&
+ $line !~ /\G(?:
+ (?:\s*$;*)(?:\s*{)?(?:\s*$;*)(?:\s*\\)?\s*$|
+ \s*return\s+
+ )/xg)
+ {
+ ERROR("TRAILING_STATEMENTS",
+ "trailing statements should be on next line\n" . $herecurr);
+ }
+
+ # Check for }<nl>else {, these must be at the same
+ # indent level to be relevant to each other.
+ if ($prevline=~/}\s*$/ and $line=~/^.\s*else\s*/ and
+ $previndent == $indent) {
+ ERROR("ELSE_AFTER_BRACE",
+ "else should follow close brace '}'\n" . $hereprev);
+ }
+
+ if ($prevline=~/}\s*$/ and $line=~/^.\s*while\s*/ and
+ $previndent == $indent) {
+ my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+
+ # Find out what is on the end of the line after the
+ # conditional.
+ substr($s, 0, length($c), '');
+ $s =~ s/\n.*//g;
+
+ if ($s =~ /^\s*;/) {
+ ERROR("WHILE_AFTER_BRACE",
+ "while should follow close brace '}'\n" . $hereprev);
+ }
+ }
+
+#CamelCase
+ while ($line =~ m{($Constant|$Lval)}g) {
+ my $var = $1;
+ if ($var !~ /$Constant/ &&
+ $var =~ /[A-Z]\w*[a-z]|[a-z]\w*[A-Z]/ &&
+ $var !~ /"^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
+ !defined $camelcase{$var}) {
+ $camelcase{$var} = 1;
+ WARN("CAMELCASE",
+ "Avoid CamelCase: <$var>\n" . $herecurr);
+ }
+ }
+
+#no spaces allowed after \ in define
+ if ($line=~/\#\s*define.*\\\s$/) {
+ WARN("WHITESPACE_AFTER_LINE_CONTINUATION",
+ "Whitepspace after \\ makes next lines useless\n" . $herecurr);
+ }
+
+#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
+ if ($tree && $rawline =~ m{^.\s*\#\s*include\s*\<asm\/(.*)\.h\>}) {
+ my $file = "$1.h";
+ my $checkfile = "include/linux/$file";
+ if (-f "$root/$checkfile" &&
+ $realfile ne $checkfile &&
+ $1 !~ /$allowed_asm_includes/)
+ {
+ if ($realfile =~ m{^arch/}) {
+ CHK("ARCH_INCLUDE_LINUX",
+ "Consider using #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ } else {
+ WARN("INCLUDE_LINUX",
+ "Use #include <linux/$file> instead of <asm/$file>\n" . $herecurr);
+ }
+ }
+ }
+
+# multi-statement macros should be enclosed in a do while loop, grab the
+# first statement and ensure its the whole macro if its not enclosed
+# in a known good container
+ if ($realfile !~ m@/vmlinux.lds.h$@ &&
+ $line =~ /^.\s*\#\s*define\s*$Ident(\()?/) {
+ my $ln = $linenr;
+ my $cnt = $realcnt;
+ my ($off, $dstat, $dcond, $rest);
+ my $ctx = '';
+ ($dstat, $dcond, $ln, $cnt, $off) =
+ ctx_statement_block($linenr, $realcnt, 0);
+ $ctx = $dstat;
+ #print "dstat<$dstat> dcond<$dcond> cnt<$cnt> off<$off>\n";
+ #print "LINE<$lines[$ln-1]> len<" . length($lines[$ln-1]) . "\n";
+
+ $dstat =~ s/^.\s*\#\s*define\s+$Ident(?:\([^\)]*\))?\s*//;
+ $dstat =~ s/$;//g;
+ $dstat =~ s/\\\n.//g;
+ $dstat =~ s/^\s*//s;
+ $dstat =~ s/\s*$//s;
+
+ # Flatten any parentheses and braces
+ while ($dstat =~ s/\([^\(\)]*\)/1/ ||
+ $dstat =~ s/\{[^\{\}]*\}/1/ ||
+ $dstat =~ s/\[[^\[\]]*\]/1/)
+ {
+ }
+
+ # Flatten any obvious string concatentation.
+ while ($dstat =~ s/("X*")\s*$Ident/$1/ ||
+ $dstat =~ s/$Ident\s*("X*")/$1/)
+ {
+ }
+
+ my $exceptions = qr{
+ $Declare|
+ module_param_named|
+ MODULE_PARM_DESC|
+ DECLARE_PER_CPU|
+ DEFINE_PER_CPU|
+ __typeof__\(|
+ union|
+ struct|
+ \.$Ident\s*=\s*|
+ ^\"|\"$
+ }x;
+ #print "REST<$rest> dstat<$dstat> ctx<$ctx>\n";
+ if ($dstat ne '' &&
+ $dstat !~ /^(?:$Ident|-?$Constant),$/ && # 10, // foo(),
+ $dstat !~ /^(?:$Ident|-?$Constant);$/ && # foo();
+ $dstat !~ /^[!~-]?(?:$Ident|$Constant)$/ && # 10 // foo() // !foo // ~foo // -foo
+ $dstat !~ /^'X'$/ && # character constants
+ $dstat !~ /$exceptions/ &&
+ $dstat !~ /^\.$Ident\s*=/ && # .foo =
+ $dstat !~ /^do\s*$Constant\s*while\s*$Constant;?$/ && # do {...} while (...); // do {...} while (...)
+ $dstat !~ /^for\s*$Constant$/ && # for (...)
+ $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar()
+ $dstat !~ /^do\s*{/ && # do {...
+ $dstat !~ /^\({/) # ({...
+ {
+ $ctx =~ s/\n*$//;
+ my $herectx = $here . "\n";
+ my $cnt = statement_rawlines($ctx);
+
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";
+ }
+
+ if ($dstat =~ /;/) {
+ ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
+ "Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
+ } else {
+ ERROR("COMPLEX_MACRO",
+ "Macros with complex values should be enclosed in parenthesis\n" . "$herectx");
+ }
+ }
+
+# check for line continuations outside of #defines, preprocessor #, and asm
+
+ } else {
+ if ($prevline !~ /^..*\\$/ &&
+ $line !~ /^\+\s*\#.*\\$/ && # preprocessor
+ $line !~ /^\+.*\b(__asm__|asm)\b.*\\$/ && # asm
+ $line =~ /^\+.*\\$/) {
+ WARN("LINE_CONTINUATIONS",
+ "Avoid unnecessary line continuations\n" . $herecurr);
+ }
+ }
+
+# do {} while (0) macro tests:
+# single-statement macros do not need to be enclosed in do while (0) loop,
+# macro should not end with a semicolon
+ if ($^V && $^V ge 5.10.0 &&
+ $realfile !~ m@/vmlinux.lds.h$@ &&
+ $line =~ /^.\s*\#\s*define\s+$Ident(\()?/) {
+ my $ln = $linenr;
+ my $cnt = $realcnt;
+ my ($off, $dstat, $dcond, $rest);
+ my $ctx = '';
+ ($dstat, $dcond, $ln, $cnt, $off) =
+ ctx_statement_block($linenr, $realcnt, 0);
+ $ctx = $dstat;
+
+ $dstat =~ s/\\\n.//g;
+
+ if ($dstat =~ /^\+\s*#\s*define\s+$Ident\s*${balanced_parens}\s*do\s*{(.*)\s*}\s*while\s*\(\s*0\s*\)\s*([;\s]*)\s*$/) {
+ my $stmts = $2;
+ my $semis = $3;
+
+ $ctx =~ s/\n*$//;
+ my $cnt = statement_rawlines($ctx);
+ my $herectx = $here . "\n";
+
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";
+ }
+
+ if (($stmts =~ tr/;/;/) == 1 &&
+ $stmts !~ /^\s*(if|while|for|switch)\b/) {
+ WARN("SINGLE_STATEMENT_DO_WHILE_MACRO",
+ "Single statement macros should not use a do {} while (0) loop\n" . "$herectx");
+ }
+ if (defined $semis && $semis ne "") {
+ WARN("DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON",
+ "do {} while (0) macros should not be semicolon terminated\n" . "$herectx");
+ }
+ }
+ }
+
+# make sure symbols are always wrapped with VMLINUX_SYMBOL() ...
+# all assignments may have only one of the following with an assignment:
+# .
+# ALIGN(...)
+# VMLINUX_SYMBOL(...)
+ if ($realfile eq 'vmlinux.lds.h' && $line =~ /(?:(?:^|\s)$Ident\s*=|=\s*$Ident(?:\s|$))/) {
+ WARN("MISSING_VMLINUX_SYMBOL",
+ "vmlinux.lds.h needs VMLINUX_SYMBOL() around C-visible symbols\n" . $herecurr);
+ }
+
+# check for redundant bracing round if etc
+ if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
+ my ($level, $endln, @chunks) =
+ ctx_statement_full($linenr, $realcnt, 1);
+ #print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
+ #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+ if ($#chunks > 0 && $level == 0) {
+ my @allowed = ();
+ my $allow = 0;
+ my $seen = 0;
+ my $herectx = $here . "\n";
+ my $ln = $linenr - 1;
+ for my $chunk (@chunks) {
+ my ($cond, $block) = @{$chunk};
+
+ # If the condition carries leading newlines, then count those as offsets.
+ my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset = statement_rawlines($whitespace) - 1;
+
+ $allowed[$allow] = 0;
+ #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
+
+ # We have looked at and allowed this specific line.
+ $suppress_ifbraces{$ln + $offset} = 1;
+
+ $herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+ $ln += statement_rawlines($block) - 1;
+
+ substr($block, 0, length($cond), '');
+
+ $seen++ if ($block =~ /^\s*{/);
+
+ #print "cond<$cond> block<$block> allowed<$allowed[$allow]>\n";
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
+ $allowed[$allow] = 1;
+ }
+ if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
+ $allowed[$allow] = 1;
+ }
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
+ $allowed[$allow] = 1;
+ }
+ $allow++;
+ }
+ if ($seen) {
+ my $sum_allowed = 0;
+ foreach (@allowed) {
+ $sum_allowed += $_;
+ }
+ if ($sum_allowed == 0) {
+ WARN("BRACES",
+ "braces {} are not necessary for any arm of this statement\n" . $herectx);
+ } elsif ($sum_allowed != $allow &&
+ $seen != $allow) {
+ CHK("BRACES",
+ "braces {} should be used on all arms of this statement\n" . $herectx);
+ }
+ }
+ }
+ }
+ if (!defined $suppress_ifbraces{$linenr - 1} &&
+ $line =~ /\b(if|while|for|else)\b/) {
+ my $allowed = 0;
+
+ # Check the pre-context.
+ if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+ #print "APW: ALLOWED: pre<$1>\n";
+ $allowed = 1;
+ }
+
+ my ($level, $endln, @chunks) =
+ ctx_statement_full($linenr, $realcnt, $-[0]);
+
+ # Check the condition.
+ my ($cond, $block) = @{$chunks[0]};
+ #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
+ }
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
+ $allowed = 1;
+ }
+ if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
+ $allowed = 1;
+ }
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
+ $allowed = 1;
+ }
+ # Check the post-context.
+ if (defined $chunks[1]) {
+ my ($cond, $block) = @{$chunks[1]};
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
+ }
+ if ($block =~ /^\s*\{/) {
+ #print "APW: ALLOWED: chunk-1 block<$block>\n";
+ $allowed = 1;
+ }
+ }
+ if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+ my $herectx = $here . "\n";
+ my $cnt = statement_rawlines($block);
+
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";
+ }
+
+ WARN("BRACES",
+ "braces {} are not necessary for single statement blocks\n" . $herectx);
+ }
+ }
+
+# check for unnecessary blank lines around braces
+ if (($line =~ /^..*}\s*$/ && $prevline =~ /^.\s*$/)) {
+ CHK("BRACES",
+ "Blank lines aren't necessary before a close brace '}'\n" . $hereprev);
+ }
+ if (($line =~ /^.\s*$/ && $prevline =~ /^..*{\s*$/)) {
+ CHK("BRACES",
+ "Blank lines aren't necessary after an open brace '{'\n" . $hereprev);
+ }
+
+# no volatiles please
+ my $asm_volatile = qr{\b(__asm__|asm)\s+(__volatile__|volatile)\b};
+ if ($line =~ /\bvolatile\b/ && $line !~ /$asm_volatile/) {
+ WARN("VOLATILE",
+ "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
+ }
+
+# warn about #if 0
+ if ($line =~ /^.\s*\#\s*if\s+0\b/) {
+ CHK("REDUNDANT_CODE",
+ "if this code is redundant consider removing it\n" .
+ $herecurr);
+ }
+
+# check for needless "if (<foo>) fn(<foo>)" uses
+ if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) {
+ my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;';
+ if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) {
+ WARN('NEEDLESS_IF',
+ "$1(NULL) is safe this check is probably not required\n" . $hereprev);
+ }
+ }
+
+# prefer usleep_range over udelay
+ if ($line =~ /\budelay\s*\(\s*(\d+)\s*\)/) {
+ # ignore udelay's < 10, however
+ if (! ($1 < 10) ) {
+ CHK("USLEEP_RANGE",
+ "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt\n" . $line);
+ }
+ }
+
+# warn about unexpectedly long msleep's
+ if ($line =~ /\bmsleep\s*\((\d+)\);/) {
+ if ($1 < 20) {
+ WARN("MSLEEP",
+ "msleep < 20ms can sleep for up to 20ms; see Documentation/timers/timers-howto.txt\n" . $line);
+ }
+ }
+
+# warn about #ifdefs in C files
+# if ($line =~ /^.\s*\#\s*if(|n)def/ && ($realfile =~ /\.c$/)) {
+# print "#ifdef in C files should be avoided\n";
+# print "$herecurr";
+# $clean = 0;
+# }
+
+# warn about spacing in #ifdefs
+ if ($line =~ /^.\s*\#\s*(ifdef|ifndef|elif)\s\s+/) {
+ ERROR("SPACING",
+ "exactly one space required after that #$1\n" . $herecurr);
+ }
+
+# check for spinlock_t definitions without a comment.
+ if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+ $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
+ my $which = $1;
+ if (!ctx_has_comment($first_line, $linenr)) {
+ CHK("UNCOMMENTED_DEFINITION",
+ "$1 definition without comment\n" . $herecurr);
+ }
+ }
+# check for memory barriers without a comment.
+ if ($line =~ /\b(mb|rmb|wmb|read_barrier_depends|smp_mb|smp_rmb|smp_wmb|smp_read_barrier_depends)\(/) {
+ if (!ctx_has_comment($first_line, $linenr)) {
+ CHK("MEMORY_BARRIER",
+ "memory barrier without comment\n" . $herecurr);
+ }
+ }
+# check of hardware specific defines
+ if ($line =~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x__)\b@ && $realfile !~ m@include/asm-@) {
+ CHK("ARCH_DEFINES",
+ "architecture specific defines should be avoided\n" . $herecurr);
+ }
+
+# Check that the storage class is at the beginning of a declaration
+ if ($line =~ /\b$Storage\b/ && $line !~ /^.\s*$Storage\b/) {
+ WARN("STORAGE_CLASS",
+ "storage class should be at the beginning of the declaration\n" . $herecurr)
+ }
+
+# check the location of the inline attribute, that it is between
+# storage class and type.
+ if ($line =~ /\b$Type\s+$Inline\b/ ||
+ $line =~ /\b$Inline\s+$Storage\b/) {
+ ERROR("INLINE_LOCATION",
+ "inline keyword should sit between storage class and type\n" . $herecurr);
+ }
+
+# Check for __inline__ and __inline, prefer inline
+ if ($line =~ /\b(__inline__|__inline)\b/) {
+ WARN("INLINE",
+ "plain inline is preferred over $1\n" . $herecurr);
+ }
+
+# Check for __attribute__ packed, prefer __packed
+ if ($line =~ /\b__attribute__\s*\(\s*\(.*\bpacked\b/) {
+ WARN("PREFER_PACKED",
+ "__packed is preferred over __attribute__((packed))\n" . $herecurr);
+ }
+
+# Check for __attribute__ aligned, prefer __aligned
+ if ($line =~ /\b__attribute__\s*\(\s*\(.*aligned/) {
+ WARN("PREFER_ALIGNED",
+ "__aligned(size) is preferred over __attribute__((aligned(size)))\n" . $herecurr);
+ }
+
+# Check for __attribute__ format(printf, prefer __printf
+ if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*printf/) {
+ WARN("PREFER_PRINTF",
+ "__printf(string-index, first-to-check) is preferred over __attribute__((format(printf, string-index, first-to-check)))\n" . $herecurr);
+ }
+
+# Check for __attribute__ format(scanf, prefer __scanf
+ if ($line =~ /\b__attribute__\s*\(\s*\(\s*format\s*\(\s*scanf\b/) {
+ WARN("PREFER_SCANF",
+ "__scanf(string-index, first-to-check) is preferred over __attribute__((format(scanf, string-index, first-to-check)))\n" . $herecurr);
+ }
+
+# check for sizeof(&)
+ if ($line =~ /\bsizeof\s*\(\s*\&/) {
+ WARN("SIZEOF_ADDRESS",
+ "sizeof(& should be avoided\n" . $herecurr);
+ }
+
+# check for sizeof without parenthesis
+ if ($line =~ /\bsizeof\s+((?:\*\s*|)$Lval|$Type(?:\s+$Lval|))/) {
+ WARN("SIZEOF_PARENTHESIS",
+ "sizeof $1 should be sizeof($1)\n" . $herecurr);
+ }
+
+# check for line continuations in quoted strings with odd counts of "
+ if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+ WARN("LINE_CONTINUATIONS",
+ "Avoid line continuations in quoted strings\n" . $herecurr);
+ }
+
+# check for struct spinlock declarations
+ if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) {
+ WARN("USE_SPINLOCK_T",
+ "struct spinlock should be spinlock_t\n" . $herecurr);
+ }
+
+# Check for misused memsets
+ if ($^V && $^V ge 5.10.0 &&
+ defined $stat &&
+ $stat =~ /^\+(?:.*?)\bmemset\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\,\s*$FuncArg\s*\)/s) {
+
+ my $ms_addr = $2;
+ my $ms_val = $7;
+ my $ms_size = $12;
+
+ if ($ms_size =~ /^(0x|)0$/i) {
+ ERROR("MEMSET",
+ "memset to 0's uses 0 as the 2nd argument, not the 3rd\n" . "$here\n$stat\n");
+ } elsif ($ms_size =~ /^(0x|)1$/i) {
+ WARN("MEMSET",
+ "single byte memset is suspicious. Swapped 2nd/3rd argument?\n" . "$here\n$stat\n");
+ }
+ }
+
+# typecasts on min/max could be min_t/max_t
+ if ($^V && $^V ge 5.10.0 &&
+ defined $stat &&
+ $stat =~ /^\+(?:.*?)\b(min|max)\s*\(\s*$FuncArg\s*,\s*$FuncArg\s*\)/) {
+ if (defined $2 || defined $7) {
+ my $call = $1;
+ my $cast1 = deparenthesize($2);
+ my $arg1 = $3;
+ my $cast2 = deparenthesize($7);
+ my $arg2 = $8;
+ my $cast;
+
+ if ($cast1 ne "" && $cast2 ne "" && $cast1 ne $cast2) {
+ $cast = "$cast1 or $cast2";
+ } elsif ($cast1 ne "") {
+ $cast = $cast1;
+ } else {
+ $cast = $cast2;
+ }
+ WARN("MINMAX",
+ "$call() should probably be ${call}_t($cast, $arg1, $arg2)\n" . "$here\n$stat\n");
+ }
+ }
+
+# check usleep_range arguments
+ if ($^V && $^V ge 5.10.0 &&
+ defined $stat &&
+ $stat =~ /^\+(?:.*?)\busleep_range\s*\(\s*($FuncArg)\s*,\s*($FuncArg)\s*\)/) {
+ my $min = $1;
+ my $max = $7;
+ if ($min eq $max) {
+ WARN("USLEEP_RANGE",
+ "usleep_range should not use min == max args; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+ } elsif ($min =~ /^\d+$/ && $max =~ /^\d+$/ &&
+ $min > $max) {
+ WARN("USLEEP_RANGE",
+ "usleep_range args reversed, use min then max; see Documentation/timers/timers-howto.txt\n" . "$here\n$stat\n");
+ }
+ }
+
+# check for new externs in .c files.
+ if ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*(?:extern\s+)?$Type\s+($Ident)(\s*)\(/s)
+ {
+ my $function_name = $1;
+ my $paren_space = $2;
+
+ my $s = $stat;
+ if (defined $cond) {
+ substr($s, 0, length($cond), '');
+ }
+ if ($s =~ /^\s*;/ &&
+ $function_name ne 'uninitialized_var')
+ {
+ WARN("AVOID_EXTERNS",
+ "externs should be avoided in .c files\n" . $herecurr);
+ }
+
+ if ($paren_space =~ /\n/) {
+ WARN("FUNCTION_ARGUMENTS",
+ "arguments for function declarations should follow identifier\n" . $herecurr);
+ }
+
+ } elsif ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*extern\s+/)
+ {
+ WARN("AVOID_EXTERNS",
+ "externs should be avoided in .c files\n" . $herecurr);
+ }
+
+# checks for new __setup's
+ if ($rawline =~ /\b__setup\("([^"]*)"/) {
+ my $name = $1;
+
+ if (!grep(/$name/, @setup_docs)) {
+ CHK("UNDOCUMENTED_SETUP",
+ "__setup appears un-documented -- check Documentation/kernel-parameters.txt\n" . $herecurr);
+ }
+ }
+
+# check for pointless casting of kmalloc return
+ if ($line =~ /\*\s*\)\s*[kv][czm]alloc(_node){0,1}\b/) {
+ WARN("UNNECESSARY_CASTS",
+ "unnecessary cast may hide bugs, see http://c-faq.com/malloc/mallocnocast.html\n" . $herecurr);
+ }
+
+# check for alloc argument mismatch
+ if ($line =~ /\b(kcalloc|kmalloc_array)\s*\(\s*sizeof\b/) {
+ WARN("ALLOC_ARRAY_ARGS",
+ "$1 uses number as first arg, sizeof is generally wrong\n" . $herecurr);
+ }
+
+# check for multiple semicolons
+ if ($line =~ /;\s*;\s*$/) {
+ WARN("ONE_SEMICOLON",
+ "Statements terminations use 1 semicolon\n" . $herecurr);
+ }
+
+# check for switch/default statements without a break;
+ if ($^V && $^V ge 5.10.0 &&
+ defined $stat &&
+ $stat =~ /^\+[$;\s]*(?:case[$;\s]+\w+[$;\s]*:[$;\s]*|)*[$;\s]*\bdefault[$;\s]*:[$;\s]*;/g) {
+ my $ctx = '';
+ my $herectx = $here . "\n";
+ my $cnt = statement_rawlines($stat);
+ for (my $n = 0; $n < $cnt; $n++) {
+ $herectx .= raw_line($linenr, $n) . "\n";
+ }
+ WARN("DEFAULT_NO_BREAK",
+ "switch default: should use break\n" . $herectx);
+ }
+
+# check for gcc specific __FUNCTION__
+ if ($line =~ /__FUNCTION__/) {
+ WARN("USE_FUNC",
+ "__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr);
+ }
+
+# check for use of yield()
+ if ($line =~ /\byield\s*\(\s*\)/) {
+ WARN("YIELD",
+ "Using yield() is generally wrong. See yield() kernel-doc (sched/core.c)\n" . $herecurr);
+ }
+
+# check for semaphores initialized locked
+ if ($line =~ /^.\s*sema_init.+,\W?0\W?\)/) {
+ WARN("CONSIDER_COMPLETION",
+ "consider using a completion\n" . $herecurr);
+ }
+
+# recommend kstrto* over simple_strto* and strict_strto*
+ if ($line =~ /\b((simple|strict)_(strto(l|ll|ul|ull)))\s*\(/) {
+ WARN("CONSIDER_KSTRTO",
+ "$1 is obsolete, use k$3 instead\n" . $herecurr);
+ }
+
+# check for __initcall(), use device_initcall() explicitly please
+ if ($line =~ /^.\s*__initcall\s*\(/) {
+ WARN("USE_DEVICE_INITCALL",
+ "please use device_initcall() instead of __initcall()\n" . $herecurr);
+ }
+
+# check for various ops structs, ensure they are const.
+ my $struct_ops = qr{acpi_dock_ops|
+ address_space_operations|
+ backlight_ops|
+ block_device_operations|
+ dentry_operations|
+ dev_pm_ops|
+ dma_map_ops|
+ extent_io_ops|
+ file_lock_operations|
+ file_operations|
+ hv_ops|
+ ide_dma_ops|
+ intel_dvo_dev_ops|
+ item_operations|
+ iwl_ops|
+ kgdb_arch|
+ kgdb_io|
+ kset_uevent_ops|
+ lock_manager_operations|
+ microcode_ops|
+ mtrr_ops|
+ neigh_ops|
+ nlmsvc_binding|
+ pci_raw_ops|
+ pipe_buf_operations|
+ platform_hibernation_ops|
+ platform_suspend_ops|
+ proto_ops|
+ rpc_pipe_ops|
+ seq_operations|
+ snd_ac97_build_ops|
+ soc_pcmcia_socket_ops|
+ stacktrace_ops|
+ sysfs_ops|
+ tty_operations|
+ usb_mon_operations|
+ wd_ops}x;
+ if ($line !~ /\bconst\b/ &&
+ $line =~ /\bstruct\s+($struct_ops)\b/) {
+ WARN("CONST_STRUCT",
+ "struct $1 should normally be const\n" .
+ $herecurr);
+ }
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+ if ($line =~ /\bNR_CPUS\b/ &&
+ $line !~ /^.\s*\s*#\s*if\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.\s*\s*#\s*define\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
+ {
+ WARN("NR_CPUS",
+ "usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+ }
+
+# check for %L{u,d,i} in strings
+ my $string;
+ while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+ $string = substr($rawline, $-[1], $+[1] - $-[1]);
+ $string =~ s/%%/__/g;
+ if ($string =~ /(?<!%)%L[udi]/) {
+ WARN("PRINTF_L",
+ "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+ last;
+ }
+ }
+
+# whine mightly about in_atomic
+ if ($line =~ /\bin_atomic\s*\(/) {
+ if ($realfile =~ m@^drivers/@) {
+ ERROR("IN_ATOMIC",
+ "do not use in_atomic in drivers\n" . $herecurr);
+ } elsif ($realfile !~ m@^kernel/@) {
+ WARN("IN_ATOMIC",
+ "use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
+ }
+ }
+
+# check for lockdep_set_novalidate_class
+ if ($line =~ /^.\s*lockdep_set_novalidate_class\s*\(/ ||
+ $line =~ /__lockdep_no_validate__\s*\)/ ) {
+ if ($realfile !~ m@^kernel/lockdep@ &&
+ $realfile !~ m@^include/linux/lockdep@ &&
+ $realfile !~ m@^drivers/base/core@) {
+ ERROR("LOCKDEP",
+ "lockdep_no_validate class is reserved for device->mutex.\n" . $herecurr);
+ }
+ }
+
+ if ($line =~ /debugfs_create_file.*S_IWUGO/ ||
+ $line =~ /DEVICE_ATTR.*S_IWUGO/ ) {
+ WARN("EXPORTED_WORLD_WRITABLE",
+ "Exporting world writable files is usually an error. Consider more restrictive permissions.\n" . $herecurr);
+ }
+ }
+
+ # If we have no input at all, then there is nothing to report on
+ # so just keep quiet.
+ if ($#rawlines == -1) {
+ exit(0);
+ }
+
+ # In mailback mode only produce a report in the negative, for
+ # things that appear to be patches.
+ if ($mailback && ($clean == 1 || !$is_patch)) {
+ exit(0);
+ }
+
+ # This is not a patch, and we are are in 'no-patch' mode so
+ # just keep quiet.
+ if (!$chk_patch && !$is_patch) {
+ exit(0);
+ }
+
+ if (!$is_patch) {
+ ERROR("NOT_UNIFIED_DIFF",
+ "Does not appear to be a unified-diff format patch\n");
+ }
+ if ($is_patch && $chk_signoff && $signoff == 0) {
+ ERROR("MISSING_SIGN_OFF",
+ "Missing Signed-off-by: line(s)\n");
+ }
+
+ print report_dump();
+ if ($summary && !($clean == 1 && $quiet == 1)) {
+ print "$filename " if ($summary_file);
+ print "total: $cnt_error errors, $cnt_warn warnings, " .
+ (($check)? "$cnt_chk checks, " : "") .
+ "$cnt_lines lines checked\n";
+ print "\n" if ($quiet == 0);
+ }
+
+ if ($quiet == 0) {
+
+ if ($^V lt 5.10.0) {
+ print("NOTE: perl $^V is not modern enough to detect all possible issues.\n");
+ print("An upgrade to at least perl v5.10.0 is suggested.\n\n");
+ }
+
+ # If there were whitespace errors which cleanpatch can fix
+ # then suggest that.
+ if ($rpt_cleaners) {
+ print "NOTE: whitespace errors detected, you may wish to use scripts/cleanpatch or\n";
+ print " scripts/cleanfile\n\n";
+ $rpt_cleaners = 0;
+ }
+ }
+
+ if ($quiet == 0 && keys %ignore_type) {
+ print "NOTE: Ignored message types:";
+ foreach my $ignore (sort keys %ignore_type) {
+ print " $ignore";
+ }
+ print "\n\n";
+ }
+
+ if ($clean == 1 && $quiet == 0) {
+ print "$vname has no obvious style problems and is ready for submission.\n"
+ }
+ if ($clean == 0 && $quiet == 0) {
+ print << "EOM";
+$vname has style problems, please review.
+
+If any of these errors are false positives, please report
+them to the maintainer, see CHECKPATCH in MAINTAINERS.
+EOM
+ }
+
+ return $clean;
+}
diff --git a/tools/checkstack.pl b/tools/checkstack.pl
new file mode 100755
index 0000000..c1cdc0a
--- /dev/null
+++ b/tools/checkstack.pl
@@ -0,0 +1,171 @@
+#!/usr/bin/perl
+
+# Check the stack usage of functions
+#
+# Copyright Joern Engel <joern@lazybastard.org>
+# Inspired by Linus Torvalds
+# Original idea maybe from Keith Owens
+# s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de>
+# Mips port by Juan Quintela <quintela@mandrakesoft.com>
+# IA64 port via Andreas Dilger
+# Arm port by Holger Schurig
+# sh64 port by Paul Mundt
+# Random bits by Matt Mackall <mpm@selenic.com>
+# M68k port by Geert Uytterhoeven and Andreas Schwab
+# AVR32 port by Haavard Skinnemoen (Atmel)
+# PARISC port by Kyle McMartin <kyle@parisc-linux.org>
+# sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk>
+#
+# Usage:
+# objdump -d vmlinux | scripts/checkstack.pl [arch]
+#
+# TODO : Port to all architectures (one regex per arch)
+
+use strict;
+
+# check for arch
+#
+# $re is used for two matches:
+# $& (whole re) matches the complete objdump line with the stack growth
+# $1 (first bracket) matches the size of the stack growth
+#
+# $dre is similar, but for dynamic stack redutions:
+# $& (whole re) matches the complete objdump line with the stack growth
+# $1 (first bracket) matches the dynamic amount of the stack growth
+#
+# use anything else and feel the pain ;)
+my (@stack, $re, $dre, $x, $xs);
+{
+ my $arch = shift;
+ if ($arch eq "") {
+ $arch = `uname -m`;
+ chomp($arch);
+ }
+
+ $x = "[0-9a-f]"; # hex character
+ $xs = "[0-9a-f ]"; # hex character or space
+ if ($arch eq 'arm') {
+ #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64
+ $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o;
+ } elsif ($arch eq 'avr32') {
+ #8000008a: 20 1d sub sp,4
+ #80000ca8: fa cd 05 b0 sub sp,sp,1456
+ $re = qr/^.*sub.*sp.*,([0-9]{1,8})/o;
+ } elsif ($arch =~ /^i[3456]86$/) {
+ #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp
+ $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o;
+ $dre = qr/^.*[as][du][db] (%.*),\%esp$/o;
+ } elsif ($arch eq 'x86_64') {
+ # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp
+ $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o;
+ $dre = qr/^.*[as][du][db] (\%.*),\%rsp$/o;
+ } elsif ($arch eq 'ia64') {
+ #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12
+ $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o;
+ } elsif ($arch eq 'm68k') {
+ # 2b6c: 4e56 fb70 linkw %fp,#-1168
+ # 1df770: defc ffe4 addaw #-28,%sp
+ $re = qr/.*(?:linkw %fp,|addaw )#-([0-9]{1,4})(?:,%sp)?$/o;
+ } elsif ($arch eq 'mips64') {
+ #8800402c: 67bdfff0 daddiu sp,sp,-16
+ $re = qr/.*daddiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+ } elsif ($arch eq 'mips') {
+ #88003254: 27bdffe0 addiu sp,sp,-32
+ $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o;
+ } elsif ($arch eq 'parisc' || $arch eq 'parisc64') {
+ $re = qr/.*ldo ($x{1,8})\(sp\),sp/o;
+ } elsif ($arch eq 'ppc') {
+ #c00029f4: 94 21 ff 30 stwu r1,-208(r1)
+ $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o;
+ } elsif ($arch eq 'ppc64') {
+ #XXX
+ $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o;
+ } elsif ($arch eq 'powerpc') {
+ $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o;
+ } elsif ($arch =~ /^s390x?$/) {
+ # 11160: a7 fb ff 60 aghi %r15,-160
+ # or
+ # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15)
+ $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})
+ (?:\(\%r15\))?$/ox;
+ } elsif ($arch =~ /^sh64$/) {
+ #XXX: we only check for the immediate case presently,
+ # though we will want to check for the movi/sub
+ # pair for larger users. -- PFM.
+ #a00048e0: d4fc40f0 addi.l r15,-240,r15
+ $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o;
+ } elsif ($arch =~ /^blackfin$/) {
+ # 0: 00 e8 38 01 LINK 0x4e0;
+ $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o;
+ } elsif ($arch eq 'sparc' || $arch eq 'sparc64') {
+ # f0019d10: 9d e3 bf 90 save %sp, -112, %sp
+ $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o;
+ } else {
+ print("wrong or unknown architecture \"$arch\"\n");
+ exit
+ }
+}
+
+#
+# main()
+#
+my $funcre = qr/^$x* <(.*)>:$/;
+my ($func, $file, $lastslash);
+
+while (my $line = <STDIN>) {
+ if ($line =~ m/$funcre/) {
+ $func = $1;
+ }
+ elsif ($line =~ m/(.*):\s*file format/) {
+ $file = $1;
+ $file =~ s/\.ko//;
+ $lastslash = rindex($file, "/");
+ if ($lastslash != -1) {
+ $file = substr($file, $lastslash + 1);
+ }
+ }
+ elsif ($line =~ m/$re/) {
+ my $size = $1;
+ $size = hex($size) if ($size =~ /^0x/);
+
+ if ($size > 0xf0000000) {
+ $size = - $size;
+ $size += 0x80000000;
+ $size += 0x80000000;
+ }
+ next if ($size > 0x10000000);
+
+ next if $line !~ m/^($xs*)/;
+ my $addr = $1;
+ $addr =~ s/ /0/g;
+ $addr = "0x$addr";
+
+ my $intro = "$addr $func [$file]:";
+ my $padlen = 56 - length($intro);
+ while ($padlen > 0) {
+ $intro .= ' ';
+ $padlen -= 8;
+ }
+ next if ($size < 100);
+ push @stack, "$intro$size\n";
+ }
+ elsif (defined $dre && $line =~ m/$dre/) {
+ my $size = "Dynamic ($1)";
+
+ next if $line !~ m/^($xs*)/;
+ my $addr = $1;
+ $addr =~ s/ /0/g;
+ $addr = "0x$addr";
+
+ my $intro = "$addr $func [$file]:";
+ my $padlen = 56 - length($intro);
+ while ($padlen > 0) {
+ $intro .= ' ';
+ $padlen -= 8;
+ }
+ push @stack, "$intro$size\n";
+ }
+}
+
+# Sort output by size (last field)
+print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack;
diff --git a/tools/cleanpatch b/tools/cleanpatch
new file mode 100755
index 0000000..9680d03
--- /dev/null
+++ b/tools/cleanpatch
@@ -0,0 +1,258 @@
+#!/usr/bin/perl -w
+#
+# Clean a patch file -- or directory of patch files -- of stealth whitespace.
+# WARNING: this can be a highly destructive operation. Use with caution.
+#
+
+use bytes;
+use File::Basename;
+
+# Default options
+$max_width = 79;
+
+# Clean up space-tab sequences, either by removing spaces or
+# replacing them with tabs.
+sub clean_space_tabs($)
+{
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($lo) = '';
+ my $pos = 0;
+ my $nsp = 0;
+ my($i, $c);
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li, $i, 1);
+ if ($c eq "\t") {
+ my $npos = ($pos+$nsp+8) & ~7;
+ my $ntab = ($npos >> 3) - ($pos >> 3);
+ $lo .= "\t" x $ntab;
+ $pos = $npos;
+ $nsp = 0;
+ } elsif ($c eq "\n" || $c eq "\r") {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos = 0;
+ } elsif ($c eq " ") {
+ $nsp++;
+ } else {
+ $lo .= " " x $nsp;
+ $pos += $nsp;
+ $nsp = 0;
+ $lo .= $c;
+ $pos++;
+ }
+ }
+ $lo .= " " x $nsp;
+ return $lo;
+}
+
+# Compute the visual width of a string
+sub strwidth($) {
+ no bytes; # Tab alignment depends on characters
+
+ my($li) = @_;
+ my($c, $i);
+ my $pos = 0;
+ my $mlen = 0;
+
+ for ($i = 0; $i < length($li); $i++) {
+ $c = substr($li,$i,1);
+ if ($c eq "\t") {
+ $pos = ($pos+8) & ~7;
+ } elsif ($c eq "\n") {
+ $mlen = $pos if ($pos > $mlen);
+ $pos = 0;
+ } else {
+ $pos++;
+ }
+ }
+
+ $mlen = $pos if ($pos > $mlen);
+ return $mlen;
+}
+
+$name = basename($0);
+
+@files = ();
+
+while (defined($a = shift(@ARGV))) {
+ if ($a =~ /^-/) {
+ if ($a eq '-width' || $a eq '-w') {
+ $max_width = shift(@ARGV)+0;
+ } else {
+ print STDERR "Usage: $name [-width #] files...\n";
+ exit 1;
+ }
+ } else {
+ push(@files, $a);
+ }
+}
+
+foreach $f ( @files ) {
+ print STDERR "$name: $f\n";
+
+ if (! -f $f) {
+ print STDERR "$f: not a file\n";
+ next;
+ }
+
+ if (!open(FILE, '+<', $f)) {
+ print STDERR "$name: Cannot open file: $f: $!\n";
+ next;
+ }
+
+ binmode FILE;
+
+ # First, verify that it is not a binary file; consider any file
+ # with a zero byte to be a binary file. Is there any better, or
+ # additional, heuristic that should be applied?
+ $is_binary = 0;
+
+ while (read(FILE, $data, 65536) > 0) {
+ if ($data =~ /\0/) {
+ $is_binary = 1;
+ last;
+ }
+ }
+
+ if ($is_binary) {
+ print STDERR "$name: $f: binary file\n";
+ next;
+ }
+
+ seek(FILE, 0, 0);
+
+ $in_bytes = 0;
+ $out_bytes = 0;
+ $lineno = 0;
+
+ @lines = ();
+
+ $in_hunk = 0;
+ $err = 0;
+
+ while ( defined($line = <FILE>) ) {
+ $lineno++;
+ $in_bytes += length($line);
+
+ if (!$in_hunk) {
+ if ($line =~
+ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@/) {
+ $minus_lines = $2;
+ $plus_lines = $4;
+ if ($minus_lines || $plus_lines) {
+ $in_hunk = 1;
+ @hunk_lines = ($line);
+ }
+ } else {
+ push(@lines, $line);
+ $out_bytes += length($line);
+ }
+ } else {
+ # We're in a hunk
+
+ if ($line =~ /^\+/) {
+ $plus_lines--;
+
+ $text = substr($line, 1);
+ $text =~ s/[ \t\r]*$//; # Remove trailing spaces
+ $text = clean_space_tabs($text);
+
+ $l_width = strwidth($text);
+ if ($max_width && $l_width > $max_width) {
+ print STDERR
+ "$f:$lineno: adds line exceeds $max_width ",
+ "characters ($l_width)\n";
+ }
+
+ push(@hunk_lines, '+'.$text);
+ } elsif ($line =~ /^\-/) {
+ $minus_lines--;
+ push(@hunk_lines, $line);
+ } elsif ($line =~ /^ /) {
+ $plus_lines--;
+ $minus_lines--;
+ push(@hunk_lines, $line);
+ } else {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ last;
+ }
+
+ if ($plus_lines < 0 || $minus_lines < 0) {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ last;
+ } elsif ($plus_lines == 0 && $minus_lines == 0) {
+ # End of a hunk. Process this hunk.
+ my $i;
+ my $l;
+ my @h = ();
+ my $adj = 0;
+ my $done = 0;
+
+ for ($i = scalar(@hunk_lines)-1; $i > 0; $i--) {
+ $l = $hunk_lines[$i];
+ if (!$done && $l eq "+\n") {
+ $adj++; # Skip this line
+ } elsif ($l =~ /^[ +]/) {
+ $done = 1;
+ unshift(@h, $l);
+ } else {
+ unshift(@h, $l);
+ }
+ }
+
+ $l = $hunk_lines[0]; # Hunk header
+ undef @hunk_lines; # Free memory
+
+ if ($adj) {
+ die unless
+ ($l =~ /^\@\@\s+\-([0-9]+),([0-9]+)\s+\+([0-9]+),([0-9]+)\s\@\@(.*)$/);
+ my $mstart = $1;
+ my $mlin = $2;
+ my $pstart = $3;
+ my $plin = $4;
+ my $tail = $5; # doesn't include the final newline
+
+ $l = sprintf("@@ -%d,%d +%d,%d @@%s\n",
+ $mstart, $mlin, $pstart, $plin-$adj,
+ $tail);
+ }
+ unshift(@h, $l);
+
+ # Transfer to the output array
+ foreach $l (@h) {
+ $out_bytes += length($l);
+ push(@lines, $l);
+ }
+
+ $in_hunk = 0;
+ }
+ }
+ }
+
+ if ($in_hunk) {
+ print STDERR "$name: $f: malformed patch\n";
+ $err = 1;
+ }
+
+ if (!$err) {
+ if ($in_bytes != $out_bytes) {
+ # Only write to the file if changed
+ seek(FILE, 0, 0);
+ print FILE @lines;
+
+ if ( !defined($where = tell(FILE)) ||
+ !truncate(FILE, $where) ) {
+ die "$name: Failed to truncate modified file: $f: $!\n";
+ }
+ }
+ }
+
+ close(FILE);
+}
diff --git a/tools/default_image.c b/tools/default_image.c
new file mode 100644
index 0000000..e9d0729
--- /dev/null
+++ b/tools/default_image.c
@@ -0,0 +1,150 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
+ * default_image specific code abstracted from mkimage.c
+ * some functions added to address abstraction
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <u-boot/crc.h>
+
+static image_header_t header;
+
+static int image_check_image_types(uint8_t type)
+{
+ if (((type > IH_TYPE_INVALID) && (type < IH_TYPE_FLATDT)) ||
+ (type == IH_TYPE_KERNEL_NOLOAD))
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static int image_check_params(struct mkimage_params *params)
+{
+ return ((params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)));
+}
+
+static int image_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ uint32_t len;
+ const unsigned char *data;
+ uint32_t checksum;
+ image_header_t header;
+ image_header_t *hdr = &header;
+
+ /*
+ * 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 (be32_to_cpu(hdr->ih_magic) != IH_MAGIC) {
+ fprintf(stderr,
+ "%s: Bad Magic Number: \"%s\" is no valid image\n",
+ params->cmdname, params->imagefile);
+ return -FDT_ERR_BADMAGIC;
+ }
+
+ data = (const unsigned char *)hdr;
+ len = sizeof(image_header_t);
+
+ checksum = be32_to_cpu(hdr->ih_hcrc);
+ hdr->ih_hcrc = cpu_to_be32(0); /* clear for re-calculation */
+
+ if (crc32(0, data, len) != checksum) {
+ fprintf(stderr,
+ "%s: ERROR: \"%s\" has bad header checksum!\n",
+ params->cmdname, params->imagefile);
+ return -FDT_ERR_BADSTATE;
+ }
+
+ data = (const unsigned char *)ptr + sizeof(image_header_t);
+ len = image_size - sizeof(image_header_t) ;
+
+ checksum = be32_to_cpu(hdr->ih_dcrc);
+ if (crc32(0, data, len) != checksum) {
+ fprintf(stderr,
+ "%s: ERROR: \"%s\" has corrupted data!\n",
+ params->cmdname, params->imagefile);
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ return 0;
+}
+
+static void image_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ uint32_t checksum;
+
+ image_header_t * hdr = (image_header_t *)ptr;
+
+ checksum = crc32(0,
+ (const unsigned char *)(ptr +
+ sizeof(image_header_t)),
+ sbuf->st_size - sizeof(image_header_t));
+
+ /* Build new header */
+ image_set_magic(hdr, IH_MAGIC);
+ image_set_time(hdr, sbuf->st_mtime);
+ image_set_size(hdr, sbuf->st_size - sizeof(image_header_t));
+ image_set_load(hdr, params->addr);
+ image_set_ep(hdr, params->ep);
+ image_set_dcrc(hdr, checksum);
+ image_set_os(hdr, params->os);
+ image_set_arch(hdr, params->arch);
+ image_set_type(hdr, params->type);
+ image_set_comp(hdr, params->comp);
+
+ image_set_name(hdr, params->imagename);
+
+ checksum = crc32(0, (const unsigned char *)hdr,
+ sizeof(image_header_t));
+
+ image_set_hcrc(hdr, checksum);
+}
+
+/*
+ * Default image type parameters definition
+ */
+static struct image_type_params defimage_params = {
+ .name = "Default Image support",
+ .header_size = sizeof(image_header_t),
+ .hdr = (void*)&header,
+ .check_image_type = image_check_image_types,
+ .verify_header = image_verify_header,
+ .print_header = image_print_contents,
+ .set_header = image_set_header,
+ .check_params = image_check_params,
+};
+
+void init_default_image_type(void)
+{
+ mkimage_register(&defimage_params);
+}
diff --git a/tools/easylogo/Makefile b/tools/easylogo/Makefile
new file mode 100644
index 0000000..d8e28b0
--- /dev/null
+++ b/tools/easylogo/Makefile
@@ -0,0 +1,11 @@
+include $(TOPDIR)/config.mk
+
+all: $(obj)easylogo
+
+$(obj)easylogo: $(SRCTREE)/tools/easylogo/easylogo.c
+ $(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+ rm -f $(obj)easylogo
+
+.PHONY: all clean
diff --git a/tools/easylogo/easylogo.c b/tools/easylogo/easylogo.c
new file mode 100644
index 0000000..4ba86bf
--- /dev/null
+++ b/tools/easylogo/easylogo.c
@@ -0,0 +1,610 @@
+/*
+** Easylogo TGA->header converter
+** ==============================
+** (C) 2000 by Paolo Scaffardi (arsenio@tin.it)
+** AIRVENT SAM s.p.a - RIMINI(ITALY)
+** (C) 2007-2008 Mike Frysinger <vapier@gentoo.org>
+**
+** This is still under construction!
+*/
+
+#include <errno.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#pragma pack(1)
+
+/*#define ENABLE_ASCII_BANNERS */
+
+typedef struct {
+ unsigned char id;
+ unsigned char ColorMapType;
+ unsigned char ImageTypeCode;
+ unsigned short ColorMapOrigin;
+ unsigned short ColorMapLenght;
+ unsigned char ColorMapEntrySize;
+ unsigned short ImageXOrigin;
+ unsigned short ImageYOrigin;
+ unsigned short ImageWidth;
+ unsigned short ImageHeight;
+ unsigned char ImagePixelSize;
+ unsigned char ImageDescriptorByte;
+} tga_header_t;
+
+typedef struct {
+ unsigned char r, g, b;
+} rgb_t;
+
+typedef struct {
+ unsigned char b, g, r;
+} bgr_t;
+
+typedef struct {
+ unsigned char Cb, y1, Cr, y2;
+} yuyv_t;
+
+typedef struct {
+ void *data, *palette;
+ int width, height, pixels, bpp, pixel_size, size, palette_size, yuyv;
+} image_t;
+
+void *xmalloc (size_t size)
+{
+ void *ret = malloc (size);
+ if (!ret) {
+ fprintf (stderr, "\nerror: malloc(%zu) failed: %s",
+ size, strerror(errno));
+ exit (1);
+ }
+ return ret;
+}
+
+void StringUpperCase (char *str)
+{
+ int count = strlen (str);
+ char c;
+
+ while (count--) {
+ c = *str;
+ if ((c >= 'a') && (c <= 'z'))
+ *str = 'A' + (c - 'a');
+ str++;
+ }
+}
+
+void StringLowerCase (char *str)
+{
+ int count = strlen (str);
+ char c;
+
+ while (count--) {
+ c = *str;
+ if ((c >= 'A') && (c <= 'Z'))
+ *str = 'a' + (c - 'A');
+ str++;
+ }
+}
+void pixel_rgb_to_yuyv (rgb_t * rgb_pixel, yuyv_t * yuyv_pixel)
+{
+ unsigned int pR, pG, pB;
+
+ /* Transform (0-255) components to (0-100) */
+ pR = rgb_pixel->r * 100 / 255;
+ pG = rgb_pixel->g * 100 / 255;
+ pB = rgb_pixel->b * 100 / 255;
+
+ /* Calculate YUV values (0-255) from RGB beetween 0-100 */
+ yuyv_pixel->y1 = yuyv_pixel->y2 = 209 * (pR + pG + pB) / 300 + 16;
+ yuyv_pixel->Cb = pB - (pR / 4) - (pG * 3 / 4) + 128;
+ yuyv_pixel->Cr = pR - (pG * 3 / 4) - (pB / 4) + 128;
+
+ return;
+}
+
+void printlogo_rgb (rgb_t * data, int w, int h)
+{
+ int x, y;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++, data++)
+ if ((data->r <
+ 30) /*&&(data->g == 0)&&(data->b == 0) */ )
+ printf (" ");
+ else
+ printf ("X");
+ printf ("\n");
+ }
+}
+
+void printlogo_yuyv (unsigned short *data, int w, int h)
+{
+ int x, y;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++, data++)
+ if (*data == 0x1080) /* Because of inverted on i386! */
+ printf (" ");
+ else
+ printf ("X");
+ printf ("\n");
+ }
+}
+
+static inline unsigned short le16_to_cpu (unsigned short val)
+{
+ union {
+ unsigned char pval[2];
+ unsigned short val;
+ } swapped;
+
+ swapped.val = val;
+ return (swapped.pval[1] << 8) + swapped.pval[0];
+}
+
+int image_load_tga (image_t * image, char *filename)
+{
+ FILE *file;
+ tga_header_t header;
+ int i;
+ unsigned char app;
+ rgb_t *p;
+
+ if ((file = fopen (filename, "rb")) == NULL)
+ return -1;
+
+ fread (&header, sizeof (header), 1, file);
+
+ /* byte swap: tga is little endian, host is ??? */
+ header.ColorMapOrigin = le16_to_cpu (header.ColorMapOrigin);
+ header.ColorMapLenght = le16_to_cpu (header.ColorMapLenght);
+ header.ImageXOrigin = le16_to_cpu (header.ImageXOrigin);
+ header.ImageYOrigin = le16_to_cpu (header.ImageYOrigin);
+ header.ImageWidth = le16_to_cpu (header.ImageWidth);
+ header.ImageHeight = le16_to_cpu (header.ImageHeight);
+
+ image->width = header.ImageWidth;
+ image->height = header.ImageHeight;
+
+ switch (header.ImageTypeCode) {
+ case 2: /* Uncompressed RGB */
+ image->yuyv = 0;
+ image->palette_size = 0;
+ image->palette = NULL;
+ break;
+
+ default:
+ printf ("Format not supported!\n");
+ return -1;
+ }
+
+ image->bpp = header.ImagePixelSize;
+ image->pixel_size = ((image->bpp - 1) / 8) + 1;
+ image->pixels = image->width * image->height;
+ image->size = image->pixels * image->pixel_size;
+ image->data = xmalloc (image->size);
+
+ if (image->bpp != 24) {
+ printf ("Bpp not supported: %d!\n", image->bpp);
+ return -1;
+ }
+
+ fread (image->data, image->size, 1, file);
+
+/* Swapping R and B values */
+
+ p = image->data;
+ for (i = 0; i < image->pixels; i++, p++) {
+ app = p->r;
+ p->r = p->b;
+ p->b = app;
+ }
+
+/* Swapping image */
+
+ if (!(header.ImageDescriptorByte & 0x20)) {
+ unsigned char *temp = xmalloc (image->size);
+ int linesize = image->pixel_size * image->width;
+ void *dest = image->data,
+ *source = temp + image->size - linesize;
+
+ printf ("S");
+ if (temp == NULL) {
+ printf ("Cannot alloc temp buffer!\n");
+ return -1;
+ }
+
+ memcpy (temp, image->data, image->size);
+ for (i = 0; i < image->height;
+ i++, dest += linesize, source -= linesize)
+ memcpy (dest, source, linesize);
+
+ free (temp);
+ }
+#ifdef ENABLE_ASCII_BANNERS
+ printlogo_rgb (image->data, image->width, image->height);
+#endif
+
+ fclose (file);
+ return 0;
+}
+
+void image_free (image_t * image)
+{
+ free (image->data);
+ free (image->palette);
+}
+
+int image_rgb_to_yuyv (image_t * rgb_image, image_t * yuyv_image)
+{
+ rgb_t *rgb_ptr = (rgb_t *) rgb_image->data;
+ yuyv_t yuyv;
+ unsigned short *dest;
+ int count = 0;
+
+ yuyv_image->pixel_size = 2;
+ yuyv_image->bpp = 16;
+ yuyv_image->yuyv = 1;
+ yuyv_image->width = rgb_image->width;
+ yuyv_image->height = rgb_image->height;
+ yuyv_image->pixels = yuyv_image->width * yuyv_image->height;
+ yuyv_image->size = yuyv_image->pixels * yuyv_image->pixel_size;
+ dest = (unsigned short *) (yuyv_image->data =
+ xmalloc (yuyv_image->size));
+ yuyv_image->palette = 0;
+ yuyv_image->palette_size = 0;
+
+ while ((count++) < rgb_image->pixels) {
+ pixel_rgb_to_yuyv (rgb_ptr++, &yuyv);
+
+ if ((count & 1) == 0) /* Was == 0 */
+ memcpy (dest, ((void *) &yuyv) + 2, sizeof (short));
+ else
+ memcpy (dest, (void *) &yuyv, sizeof (short));
+
+ dest++;
+ }
+
+#ifdef ENABLE_ASCII_BANNERS
+ printlogo_yuyv (yuyv_image->data, yuyv_image->width,
+ yuyv_image->height);
+#endif
+ return 0;
+}
+
+int image_rgb888_to_rgb565(image_t *rgb888_image, image_t *rgb565_image)
+{
+ rgb_t *rgb_ptr = (rgb_t *) rgb888_image->data;
+ unsigned short *dest;
+ int count = 0;
+
+ rgb565_image->pixel_size = 2;
+ rgb565_image->bpp = 16;
+ rgb565_image->yuyv = 0;
+ rgb565_image->width = rgb888_image->width;
+ rgb565_image->height = rgb888_image->height;
+ rgb565_image->pixels = rgb565_image->width * rgb565_image->height;
+ rgb565_image->size = rgb565_image->pixels * rgb565_image->pixel_size;
+ dest = (unsigned short *) (rgb565_image->data =
+ xmalloc(rgb565_image->size));
+ rgb565_image->palette = 0;
+ rgb565_image->palette_size = 0;
+
+ while ((count++) < rgb888_image->pixels) {
+
+ *dest++ = ((rgb_ptr->b & 0xF8) << 8) |
+ ((rgb_ptr->g & 0xFC) << 3) |
+ (rgb_ptr->r >> 3);
+ rgb_ptr++;
+ }
+
+ return 0;
+}
+
+enum comp_t {
+ COMP_NONE,
+ COMP_GZIP,
+ COMP_LZMA,
+};
+static enum comp_t compression = COMP_NONE;
+static bool bss_storage = false;
+
+int image_save_header (image_t * image, char *filename, char *varname)
+{
+ FILE *file = fopen (filename, "w");
+ char app[256], str[256] = "", def_name[64];
+ int count = image->size, col = 0;
+ unsigned char *dataptr = image->data;
+
+ if (file == NULL)
+ return -1;
+
+ /* Author information */
+ fprintf (file,
+ "/*\n * Generated by EasyLogo, (C) 2000 by Paolo Scaffardi\n *\n");
+ fprintf (file,
+ " * To use this, include it and call: easylogo_plot(screen,&%s, width,x,y)\n *\n",
+ varname);
+ fprintf (file,
+ " * Where:\t'screen'\tis the pointer to the frame buffer\n");
+ fprintf (file, " *\t\t'width'\tis the screen width\n");
+ fprintf (file, " *\t\t'x'\t\tis the horizontal position\n");
+ fprintf (file, " *\t\t'y'\t\tis the vertical position\n */\n\n");
+
+ /* image compress */
+ if (compression != COMP_NONE) {
+ const char *errstr = NULL;
+ unsigned char *compressed;
+ const char *comp_name;
+ struct stat st;
+ FILE *compfp;
+ size_t filename_len = strlen(filename);
+ char *compfilename = xmalloc(filename_len + 20);
+ char *compcmd = xmalloc(filename_len + 50);
+
+ sprintf(compfilename, "%s.bin", filename);
+ switch (compression) {
+ case COMP_GZIP:
+ strcpy(compcmd, "gzip");
+ comp_name = "GZIP";
+ break;
+ case COMP_LZMA:
+ strcpy(compcmd, "lzma");
+ comp_name = "LZMA";
+ break;
+ default:
+ errstr = "\nerror: unknown compression method";
+ goto done;
+ }
+ strcat(compcmd, " > ");
+ strcat(compcmd, compfilename);
+ compfp = popen(compcmd, "w");
+ if (!compfp) {
+ errstr = "\nerror: popen() failed";
+ goto done;
+ }
+ if (fwrite(image->data, image->size, 1, compfp) != 1) {
+ errstr = "\nerror: writing data to gzip failed";
+ goto done;
+ }
+ if (pclose(compfp)) {
+ errstr = "\nerror: gzip process failed";
+ goto done;
+ }
+
+ compfp = fopen(compfilename, "r");
+ if (!compfp) {
+ errstr = "\nerror: open() on gzip data failed";
+ goto done;
+ }
+ if (stat(compfilename, &st)) {
+ errstr = "\nerror: stat() on gzip file failed";
+ goto done;
+ }
+ compressed = xmalloc(st.st_size);
+ if (fread(compressed, st.st_size, 1, compfp) != 1) {
+ errstr = "\nerror: reading gzip data failed";
+ goto done;
+ }
+ fclose(compfp);
+
+ unlink(compfilename);
+
+ dataptr = compressed;
+ count = st.st_size;
+ fprintf(file, "#define EASYLOGO_ENABLE_%s %i\n\n", comp_name, count);
+ if (bss_storage)
+ fprintf (file, "static unsigned char EASYLOGO_DECOMP_BUFFER[%i];\n\n", image->size);
+
+ done:
+ free(compfilename);
+ free(compcmd);
+
+ if (errstr) {
+ perror (errstr);
+ return -1;
+ }
+ }
+
+ /* Headers */
+ fprintf (file, "#include <video_easylogo.h>\n\n");
+ /* Macros */
+ strcpy (def_name, varname);
+ StringUpperCase (def_name);
+ fprintf (file, "#define DEF_%s_WIDTH\t\t%d\n", def_name,
+ image->width);
+ fprintf (file, "#define DEF_%s_HEIGHT\t\t%d\n", def_name,
+ image->height);
+ fprintf (file, "#define DEF_%s_PIXELS\t\t%d\n", def_name,
+ image->pixels);
+ fprintf (file, "#define DEF_%s_BPP\t\t%d\n", def_name, image->bpp);
+ fprintf (file, "#define DEF_%s_PIXEL_SIZE\t%d\n", def_name,
+ image->pixel_size);
+ fprintf (file, "#define DEF_%s_SIZE\t\t%d\n\n", def_name,
+ image->size);
+ /* Declaration */
+ fprintf (file, "unsigned char DEF_%s_DATA[] = {\n",
+ def_name);
+
+ /* Data */
+ while (count)
+ switch (col) {
+ case 0:
+ sprintf (str, " 0x%02x", *dataptr++);
+ col++;
+ count--;
+ break;
+
+ case 16:
+ fprintf (file, "%s", str);
+ if (count > 0)
+ fprintf (file, ",");
+ fprintf (file, "\n");
+
+ col = 0;
+ break;
+
+ default:
+ strcpy (app, str);
+ sprintf (str, "%s, 0x%02x", app, *dataptr++);
+ col++;
+ count--;
+ break;
+ }
+
+ if (col)
+ fprintf (file, "%s\n", str);
+
+ /* End of declaration */
+ fprintf (file, "};\n\n");
+ /* Variable */
+ fprintf (file, "fastimage_t %s = {\n", varname);
+ fprintf (file, " DEF_%s_DATA,\n", def_name);
+ fprintf (file, " DEF_%s_WIDTH,\n", def_name);
+ fprintf (file, " DEF_%s_HEIGHT,\n", def_name);
+ fprintf (file, " DEF_%s_BPP,\n", def_name);
+ fprintf (file, " DEF_%s_PIXEL_SIZE,\n", def_name);
+ fprintf (file, " DEF_%s_SIZE\n};\n", def_name);
+
+ fclose (file);
+
+ return 0;
+}
+
+#define DEF_FILELEN 256
+
+static void usage (int exit_status)
+{
+ puts (
+ "EasyLogo 1.0 (C) 2000 by Paolo Scaffardi\n"
+ "\n"
+ "Syntax: easylogo [options] inputfile [outputvar [outputfile]]\n"
+ "\n"
+ "Options:\n"
+ " -r Output RGB888 instead of YUYV\n"
+ " -s Output RGB565 instead of YUYV\n"
+ " -g Compress with gzip\n"
+ " -l Compress with lzma\n"
+ " -b Preallocate space in bss for decompressing image\n"
+ " -h Help output\n"
+ "\n"
+ "Where: 'inputfile' is the TGA image to load\n"
+ " 'outputvar' is the variable name to create\n"
+ " 'outputfile' is the output header file (default is 'inputfile.h')"
+ );
+ exit (exit_status);
+}
+
+int main (int argc, char *argv[])
+{
+ int c;
+ bool use_rgb888 = false;
+ bool use_rgb565 = false;
+ char inputfile[DEF_FILELEN],
+ outputfile[DEF_FILELEN], varname[DEF_FILELEN];
+
+ image_t rgb888_logo, rgb565_logo, yuyv_logo;
+
+ while ((c = getopt(argc, argv, "hrsglb")) > 0) {
+ switch (c) {
+ case 'h':
+ usage (0);
+ break;
+ case 'r':
+ use_rgb888 = true;
+ puts("Using 24-bit RGB888 Output Fromat");
+ break;
+ case 's':
+ use_rgb565 = true;
+ puts("Using 16-bit RGB565 Output Fromat");
+ break;
+ case 'g':
+ compression = COMP_GZIP;
+ puts("Compressing with gzip");
+ break;
+ case 'l':
+ compression = COMP_LZMA;
+ puts("Compressing with lzma");
+ break;
+ case 'b':
+ bss_storage = true;
+ puts("Preallocating bss space for decompressing image");
+ break;
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ c = argc - optind;
+ if (c > 4 || c < 1)
+ usage (1);
+
+ strcpy (inputfile, argv[optind]);
+
+ if (c > 1)
+ strcpy (varname, argv[optind + 1]);
+ else {
+ /* transform "input.tga" to just "input" */
+ char *dot;
+ strcpy (varname, inputfile);
+ dot = strchr (varname, '.');
+ if (dot)
+ *dot = '\0';
+ }
+
+ if (c > 2)
+ strcpy (outputfile, argv[optind + 2]);
+ else {
+ /* just append ".h" to input file name */
+ strcpy (outputfile, inputfile);
+ strcat (outputfile, ".h");
+ }
+
+ /* Make sure the output is sent as soon as we printf() */
+ setbuf(stdout, NULL);
+
+ printf ("Doing '%s' (%s) from '%s'...",
+ outputfile, varname, inputfile);
+
+ /* Import TGA logo */
+
+ printf ("L");
+ if (image_load_tga(&rgb888_logo, inputfile) < 0) {
+ printf ("input file not found!\n");
+ exit (1);
+ }
+
+ /* Convert, save, and free the image */
+
+ if (!use_rgb888 && !use_rgb565) {
+ printf ("C");
+ image_rgb_to_yuyv(&rgb888_logo, &yuyv_logo);
+
+ printf("S");
+ image_save_header(&yuyv_logo, outputfile, varname);
+ image_free(&yuyv_logo);
+ } else if (use_rgb565) {
+ printf("C");
+ image_rgb888_to_rgb565(&rgb888_logo, &rgb565_logo);
+
+ printf("S");
+ image_save_header(&rgb565_logo, outputfile, varname);
+ image_free(&rgb565_logo);
+ } else {
+ printf("S");
+ image_save_header(&rgb888_logo, outputfile, varname);
+ }
+
+ /* Free original image and copy */
+
+ image_free(&rgb888_logo);
+
+ printf ("\n");
+
+ return 0;
+}
diff --git a/tools/easylogo/linux_blackfin.tga b/tools/easylogo/linux_blackfin.tga
new file mode 100644
index 0000000..e2bb17b
--- /dev/null
+++ b/tools/easylogo/linux_blackfin.tga
Binary files differ
diff --git a/tools/easylogo/linux_logo.tga b/tools/easylogo/linux_logo.tga
new file mode 100644
index 0000000..ac53def
--- /dev/null
+++ b/tools/easylogo/linux_logo.tga
Binary files differ
diff --git a/tools/easylogo/runme.sh b/tools/easylogo/runme.sh
new file mode 100644
index 0000000..625ebaa
--- /dev/null
+++ b/tools/easylogo/runme.sh
@@ -0,0 +1,4 @@
+#!/bin/sh
+make
+./easylogo linux_logo.tga u_boot_logo video_logo.h
+mv video_logo.h ../../include
diff --git a/tools/env/Makefile b/tools/env/Makefile
new file mode 100644
index 0000000..0e798e0
--- /dev/null
+++ b/tools/env/Makefile
@@ -0,0 +1,59 @@
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+HOSTSRCS := $(SRCTREE)/lib/crc32.c fw_env.c fw_env_main.c
+HOSTSRCS += $(SRCTREE)/lib/ctype.c $(SRCTREE)/lib/linux_string.c
+HOSTSRCS += $(SRCTREE)/common/env_attr.c $(SRCTREE)/common/env_flags.c
+HEADERS := fw_env.h $(OBJTREE)/include/config.h
+
+# Compile for a hosted environment on the target
+HOSTCPPFLAGS = -idirafter $(SRCTREE)/include \
+ -idirafter $(OBJTREE)/include2 \
+ -idirafter $(OBJTREE)/include \
+ -idirafter $(SRCTREE)/tools/env \
+ -DUSE_HOSTCC \
+ -DTEXT_BASE=$(TEXT_BASE)
+
+ifeq ($(MTD_VERSION),old)
+HOSTCPPFLAGS += -DMTD_OLD
+endif
+
+all: $(obj)fw_printenv
+
+# Some files complain if compiled with -pedantic, use HOSTCFLAGS_NOPED
+$(obj)fw_printenv: $(HOSTSRCS) $(HEADERS)
+ $(HOSTCC) $(HOSTCFLAGS_NOPED) $(HOSTLDFLAGS) -o $@ $(HOSTSRCS)
+ $(HOSTSTRIP) $@
+
+clean:
+ rm -f $(obj)fw_printenv
+
+#########################################################################
+
+include $(TOPDIR)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/env/README b/tools/env/README
new file mode 100644
index 0000000..1020b57
--- /dev/null
+++ b/tools/env/README
@@ -0,0 +1,61 @@
+
+This is a demo implementation of a Linux command line tool to access
+the U-Boot's environment variables.
+
+In the current version, there is an issue in cross-compilation.
+In order to cross-compile fw_printenv, run
+ make HOSTCC=<your CC cross-compiler> env
+in the root directory of the U-Boot distribution. For example,
+ make HOSTCC=arm-linux-gcc env
+
+For the run-time utility configuration uncomment the line
+#define CONFIG_FILE "/etc/fw_env.config"
+in fw_env.h.
+
+For building against older versions of the MTD headers (meaning before
+v2.6.8-rc1) it is required to pass the argument "MTD_VERSION=old" to
+make.
+
+See comments in the fw_env.config file for definitions for the
+particular board.
+
+Configuration can also be done via #defines in the fw_env.h file. The
+following lines are relevant:
+
+#define HAVE_REDUND /* For systems with 2 env sectors */
+#define DEVICE1_NAME "/dev/mtd1"
+#define DEVICE2_NAME "/dev/mtd2"
+#define DEVICE1_OFFSET 0x0000
+#define ENV1_SIZE 0x4000
+#define DEVICE1_ESIZE 0x4000
+#define DEVICE1_ENVSECTORS 2
+#define DEVICE2_OFFSET 0x0000
+#define ENV2_SIZE 0x4000
+#define DEVICE2_ESIZE 0x4000
+#define DEVICE2_ENVSECTORS 2
+
+Un-define HAVE_REDUND, if you want to use the utilities on a system
+that does not have support for redundant environment enabled.
+If HAVE_REDUND is undefined, DEVICE2_NAME is ignored,
+as is ENV2_SIZE and DEVICE2_ESIZE.
+
+The DEVICEx_NAME constants define which MTD character devices are to
+be used to access the environment.
+
+The DEVICEx_OFFSET constants define the environment offset within the
+MTD character device.
+
+ENVx_SIZE defines the size in bytes taken by the environment, which
+may be less then flash sector size, if the environment takes less
+then 1 sector.
+
+DEVICEx_ESIZE defines the size of the first sector in the flash
+partition where the environment resides.
+
+DEVICEx_ENVSECTORS defines the number of sectors that may be used for
+this environment instance. On NAND this is used to limit the range
+within which bad blocks are skipped, on NOR it is not used.
+
+To prevent losing changes to the environment and to prevent confusing the MTD
+drivers, a lock file at /var/lock/fw_printenv.lock is used to serialize access
+to the environment.
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
new file mode 100644
index 0000000..01fc1d4
--- /dev/null
+++ b/tools/env/fw_env.c
@@ -0,0 +1,1336 @@
+/*
+ * (C) Copyright 2000-2010
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * (C) Copyright 2008
+ * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <env_flags.h>
+#include <fcntl.h>
+#include <linux/stringify.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifdef MTD_OLD
+# include <stdint.h>
+# include <linux/mtd/mtd.h>
+#else
+# define __user /* nothing */
+# include <mtd/mtd-user.h>
+#endif
+
+#include "fw_env.h"
+
+#define WHITESPACE(c) ((c == '\t') || (c == ' '))
+
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
+
+struct envdev_s {
+ char devname[16]; /* Device name */
+ ulong devoff; /* Device offset */
+ ulong env_size; /* environment size */
+ ulong erase_size; /* device erase size */
+ ulong env_sectors; /* number of environment sectors */
+ uint8_t mtd_type; /* type of the MTD device */
+};
+
+static struct envdev_s envdevices[2] =
+{
+ {
+ .mtd_type = MTD_ABSENT,
+ }, {
+ .mtd_type = MTD_ABSENT,
+ },
+};
+static int dev_current;
+
+#define DEVNAME(i) envdevices[(i)].devname
+#define DEVOFFSET(i) envdevices[(i)].devoff
+#define ENVSIZE(i) envdevices[(i)].env_size
+#define DEVESIZE(i) envdevices[(i)].erase_size
+#define ENVSECTORS(i) envdevices[(i)].env_sectors
+#define DEVTYPE(i) envdevices[(i)].mtd_type
+
+#define CUR_ENVSIZE ENVSIZE(dev_current)
+
+#define ENV_SIZE getenvsize()
+
+struct env_image_single {
+ uint32_t crc; /* CRC32 over data bytes */
+ char data[];
+};
+
+struct env_image_redundant {
+ uint32_t crc; /* CRC32 over data bytes */
+ unsigned char flags; /* active or obsolete */
+ char data[];
+};
+
+enum flag_scheme {
+ FLAG_NONE,
+ FLAG_BOOLEAN,
+ FLAG_INCREMENTAL,
+};
+
+struct environment {
+ void *image;
+ uint32_t *crc;
+ unsigned char *flags;
+ char *data;
+ enum flag_scheme flag_scheme;
+};
+
+static struct environment environment = {
+ .flag_scheme = FLAG_NONE,
+};
+
+static int HaveRedundEnv = 0;
+
+static unsigned char active_flag = 1;
+/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
+static unsigned char obsolete_flag = 0;
+
+#define DEFAULT_ENV_INSTANCE_STATIC
+#include <env_default.h>
+
+static int flash_io (int mode);
+static char *envmatch (char * s1, char * s2);
+static int parse_config (void);
+
+#if defined(CONFIG_FILE)
+static int get_config (char *);
+#endif
+static inline ulong getenvsize (void)
+{
+ ulong rc = CUR_ENVSIZE - sizeof(long);
+
+ if (HaveRedundEnv)
+ rc -= sizeof (char);
+ return rc;
+}
+
+static char *fw_string_blank(char *s, int noblank)
+{
+ int i;
+ int len = strlen(s);
+
+ for (i = 0; i < len; i++, s++) {
+ if ((noblank && !WHITESPACE(*s)) ||
+ (!noblank && WHITESPACE(*s)))
+ break;
+ }
+ if (i == len)
+ return NULL;
+
+ return s;
+}
+
+/*
+ * Search the environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getenv (char *name)
+{
+ char *env, *nxt;
+
+ for (env = environment.data; *env; env = nxt + 1) {
+ char *val;
+
+ for (nxt = env; *nxt; ++nxt) {
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+ return NULL;
+ }
+ }
+ val = envmatch (name, env);
+ if (!val)
+ continue;
+ return val;
+ }
+ return NULL;
+}
+
+/*
+ * Search the default environment for a variable.
+ * Return the value, if found, or NULL, if not found.
+ */
+char *fw_getdefenv(char *name)
+{
+ char *env, *nxt;
+
+ for (env = default_environment; *env; env = nxt + 1) {
+ char *val;
+
+ for (nxt = env; *nxt; ++nxt) {
+ if (nxt >= &default_environment[ENV_SIZE]) {
+ fprintf(stderr, "## Error: "
+ "default environment not terminated\n");
+ return NULL;
+ }
+ }
+ val = envmatch(name, env);
+ if (!val)
+ continue;
+ return val;
+ }
+ return NULL;
+}
+
+/*
+ * Print the current definition of one, or more, or all
+ * environment variables
+ */
+int fw_printenv (int argc, char *argv[])
+{
+ char *env, *nxt;
+ int i, n_flag;
+ int rc = 0;
+
+ if (fw_env_open())
+ return -1;
+
+ if (argc == 1) { /* Print all env variables */
+ for (env = environment.data; *env; env = nxt + 1) {
+ for (nxt = env; *nxt; ++nxt) {
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+ return -1;
+ }
+ }
+
+ printf ("%s\n", env);
+ }
+ return 0;
+ }
+
+ if (strcmp (argv[1], "-n") == 0) {
+ n_flag = 1;
+ ++argv;
+ --argc;
+ if (argc != 2) {
+ fprintf (stderr, "## Error: "
+ "`-n' option requires exactly one argument\n");
+ return -1;
+ }
+ } else {
+ n_flag = 0;
+ }
+
+ for (i = 1; i < argc; ++i) { /* print single env variables */
+ char *name = argv[i];
+ char *val = NULL;
+
+ for (env = environment.data; *env; env = nxt + 1) {
+
+ for (nxt = env; *nxt; ++nxt) {
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf (stderr, "## Error: "
+ "environment not terminated\n");
+ return -1;
+ }
+ }
+ val = envmatch (name, env);
+ if (val) {
+ if (!n_flag) {
+ fputs (name, stdout);
+ putc ('=', stdout);
+ }
+ puts (val);
+ break;
+ }
+ }
+ if (!val) {
+ fprintf (stderr, "## Error: \"%s\" not defined\n", name);
+ rc = -1;
+ }
+ }
+
+ return rc;
+}
+
+int fw_env_close(void)
+{
+ /*
+ * Update CRC
+ */
+ *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE);
+
+ /* write environment back to flash */
+ if (flash_io(O_RDWR)) {
+ fprintf(stderr,
+ "Error: can't write fw_env to flash\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Set/Clear a single variable in the environment.
+ * This is called in sequence to update the environment
+ * in RAM without updating the copy in flash after each set
+ */
+int fw_env_write(char *name, char *value)
+{
+ int len;
+ char *env, *nxt;
+ char *oldval = NULL;
+ int deleting, creating, overwriting;
+
+ /*
+ * search if variable with this name already exists
+ */
+ for (nxt = env = environment.data; *env; env = nxt + 1) {
+ for (nxt = env; *nxt; ++nxt) {
+ if (nxt >= &environment.data[ENV_SIZE]) {
+ fprintf(stderr, "## Error: "
+ "environment not terminated\n");
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ if ((oldval = envmatch (name, env)) != NULL)
+ break;
+ }
+
+ deleting = (oldval && !(value && strlen(value)));
+ creating = (!oldval && (value && strlen(value)));
+ overwriting = (oldval && (value && strlen(value)));
+
+ /* check for permission */
+ if (deleting) {
+ if (env_flags_validate_varaccess(name,
+ ENV_FLAGS_VARACCESS_PREVENT_DELETE)) {
+ printf("Can't delete \"%s\"\n", name);
+ errno = EROFS;
+ return -1;
+ }
+ } else if (overwriting) {
+ if (env_flags_validate_varaccess(name,
+ ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) {
+ printf("Can't overwrite \"%s\"\n", name);
+ errno = EROFS;
+ return -1;
+ } else if (env_flags_validate_varaccess(name,
+ ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) {
+ const char *defval = fw_getdefenv(name);
+
+ if (defval == NULL)
+ defval = "";
+ if (strcmp(oldval, defval)
+ != 0) {
+ printf("Can't overwrite \"%s\"\n", name);
+ errno = EROFS;
+ return -1;
+ }
+ }
+ } else if (creating) {
+ if (env_flags_validate_varaccess(name,
+ ENV_FLAGS_VARACCESS_PREVENT_CREATE)) {
+ printf("Can't create \"%s\"\n", name);
+ errno = EROFS;
+ return -1;
+ }
+ } else
+ /* Nothing to do */
+ return 0;
+
+ if (deleting || overwriting) {
+ if (*++nxt == '\0') {
+ *env = '\0';
+ } else {
+ for (;;) {
+ *env = *nxt++;
+ if ((*env == '\0') && (*nxt == '\0'))
+ break;
+ ++env;
+ }
+ }
+ *++env = '\0';
+ }
+
+ /* Delete only ? */
+ if (!value || !strlen(value))
+ return 0;
+
+ /*
+ * Append new definition at the end
+ */
+ for (env = environment.data; *env || *(env + 1); ++env);
+ if (env > environment.data)
+ ++env;
+ /*
+ * Overflow when:
+ * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment)
+ */
+ len = strlen (name) + 2;
+ /* add '=' for first arg, ' ' for all others */
+ len += strlen(value) + 1;
+
+ if (len > (&environment.data[ENV_SIZE] - env)) {
+ fprintf (stderr,
+ "Error: environment overflow, \"%s\" deleted\n",
+ name);
+ return -1;
+ }
+
+ while ((*env = *name++) != '\0')
+ env++;
+ *env = '=';
+ while ((*++env = *value++) != '\0')
+ ;
+
+ /* end is marked with double '\0' */
+ *++env = '\0';
+
+ return 0;
+}
+
+/*
+ * Deletes or sets environment variables. Returns -1 and sets errno error codes:
+ * 0 - OK
+ * EINVAL - need at least 1 argument
+ * EROFS - certain variables ("ethaddr", "serial#") cannot be
+ * modified or deleted
+ *
+ */
+int fw_setenv(int argc, char *argv[])
+{
+ int i;
+ size_t len;
+ char *name;
+ char *value = NULL;
+
+ if (argc < 2) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fw_env_open()) {
+ fprintf(stderr, "Error: environment not initialized\n");
+ return -1;
+ }
+
+ name = argv[1];
+
+ if (env_flags_validate_env_set_params(argc, argv) < 0)
+ return 1;
+
+ len = 0;
+ for (i = 2; i < argc; ++i) {
+ char *val = argv[i];
+ size_t val_len = strlen(val);
+
+ if (value)
+ value[len - 1] = ' ';
+ value = realloc(value, len + val_len + 1);
+ if (!value) {
+ fprintf(stderr,
+ "Cannot malloc %zu bytes: %s\n",
+ len, strerror(errno));
+ return -1;
+ }
+
+ memcpy(value + len, val, val_len);
+ len += val_len;
+ value[len++] = '\0';
+ }
+
+ fw_env_write(name, value);
+
+ free(value);
+
+ return fw_env_close();
+}
+
+/*
+ * Parse a file and configure the u-boot variables.
+ * The script file has a very simple format, as follows:
+ *
+ * Each line has a couple with name, value:
+ * <white spaces>variable_name<white spaces>variable_value
+ *
+ * Both variable_name and variable_value are interpreted as strings.
+ * Any character after <white spaces> and before ending \r\n is interpreted
+ * as variable's value (no comment allowed on these lines !)
+ *
+ * Comments are allowed if the first character in the line is #
+ *
+ * Returns -1 and sets errno error codes:
+ * 0 - OK
+ * -1 - Error
+ */
+int fw_parse_script(char *fname)
+{
+ FILE *fp;
+ char dump[1024]; /* Maximum line length in the file */
+ char *name;
+ char *val;
+ int lineno = 0;
+ int len;
+ int ret = 0;
+
+ if (fw_env_open()) {
+ fprintf(stderr, "Error: environment not initialized\n");
+ return -1;
+ }
+
+ if (strcmp(fname, "-") == 0)
+ fp = stdin;
+ else {
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "I cannot open %s for reading\n",
+ fname);
+ return -1;
+ }
+ }
+
+ while (fgets(dump, sizeof(dump), fp)) {
+ lineno++;
+ len = strlen(dump);
+
+ /*
+ * Read a whole line from the file. If the line is too long
+ * or is not terminated, reports an error and exit.
+ */
+ if (dump[len - 1] != '\n') {
+ fprintf(stderr,
+ "Line %d not corrected terminated or too long\n",
+ lineno);
+ ret = -1;
+ break;
+ }
+
+ /* Drop ending line feed / carriage return */
+ while (len > 0 && (dump[len - 1] == '\n' ||
+ dump[len - 1] == '\r')) {
+ dump[len - 1] = '\0';
+ len--;
+ }
+
+ /* Skip comment or empty lines */
+ if ((len == 0) || dump[0] == '#')
+ continue;
+
+ /*
+ * Search for variable's name,
+ * remove leading whitespaces
+ */
+ name = fw_string_blank(dump, 1);
+ if (!name)
+ continue;
+
+ /* The first white space is the end of variable name */
+ val = fw_string_blank(name, 0);
+ len = strlen(name);
+ if (val) {
+ *val++ = '\0';
+ if ((val - name) < len)
+ val = fw_string_blank(val, 1);
+ else
+ val = NULL;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Setting %s : %s\n",
+ name, val ? val : " removed");
+#endif
+
+ if (env_flags_validate_type(name, val) < 0) {
+ ret = -1;
+ break;
+ }
+
+ /*
+ * If there is an error setting a variable,
+ * try to save the environment and returns an error
+ */
+ if (fw_env_write(name, val)) {
+ fprintf(stderr,
+ "fw_env_write returns with error : %s\n",
+ strerror(errno));
+ ret = -1;
+ break;
+ }
+
+ }
+
+ /* Close file if not stdin */
+ if (strcmp(fname, "-") != 0)
+ fclose(fp);
+
+ ret |= fw_env_close();
+
+ return ret;
+
+}
+
+/*
+ * Test for bad block on NAND, just returns 0 on NOR, on NAND:
+ * 0 - block is good
+ * > 0 - block is bad
+ * < 0 - failed to test
+ */
+static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart)
+{
+ if (mtd_type == MTD_NANDFLASH) {
+ int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart);
+
+ if (badblock < 0) {
+ perror ("Cannot read bad block mark");
+ return badblock;
+ }
+
+ if (badblock) {
+#ifdef DEBUG
+ fprintf (stderr, "Bad block at 0x%llx, "
+ "skipping\n", *blockstart);
+#endif
+ return badblock;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Read data from flash at an offset into a provided buffer. On NAND it skips
+ * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from
+ * the DEVOFFSET (dev) block. On NOR the loop is only run once.
+ */
+static int flash_read_buf (int dev, int fd, void *buf, size_t count,
+ off_t offset, uint8_t mtd_type)
+{
+ size_t blocklen; /* erase / write length - one block on NAND,
+ 0 on NOR */
+ size_t processed = 0; /* progress counter */
+ size_t readlen = count; /* current read length */
+ off_t top_of_range; /* end of the last block we may use */
+ off_t block_seek; /* offset inside the current block to the start
+ of the data */
+ loff_t blockstart; /* running start of the current block -
+ MEMGETBADBLOCK needs 64 bits */
+ int rc;
+
+ blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev);
+
+ /* Offset inside a block */
+ block_seek = offset - blockstart;
+
+ if (mtd_type == MTD_NANDFLASH) {
+ /*
+ * NAND: calculate which blocks we are reading. We have
+ * to read one block at a time to skip bad blocks.
+ */
+ blocklen = DEVESIZE (dev);
+
+ /*
+ * To calculate the top of the range, we have to use the
+ * global DEVOFFSET (dev), which can be different from offset
+ */
+ top_of_range = ((DEVOFFSET(dev) / blocklen) +
+ ENVSECTORS (dev)) * blocklen;
+
+ /* Limit to one block for the first read */
+ if (readlen > blocklen - block_seek)
+ readlen = blocklen - block_seek;
+ } else {
+ blocklen = 0;
+ top_of_range = offset + count;
+ }
+
+ /* This only runs once on NOR flash */
+ while (processed < count) {
+ rc = flash_bad_block (fd, mtd_type, &blockstart);
+ if (rc < 0) /* block test failed */
+ return -1;
+
+ if (blockstart + block_seek + readlen > top_of_range) {
+ /* End of range is reached */
+ fprintf (stderr,
+ "Too few good blocks within range\n");
+ return -1;
+ }
+
+ if (rc) { /* block is bad */
+ blockstart += blocklen;
+ continue;
+ }
+
+ /*
+ * If a block is bad, we retry in the next block at the same
+ * offset - see common/env_nand.c::writeenv()
+ */
+ lseek (fd, blockstart + block_seek, SEEK_SET);
+
+ rc = read (fd, buf + processed, readlen);
+ if (rc != readlen) {
+ fprintf (stderr, "Read error on %s: %s\n",
+ DEVNAME (dev), strerror (errno));
+ return -1;
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
+ rc, blockstart + block_seek, DEVNAME(dev));
+#endif
+ processed += readlen;
+ readlen = min (blocklen, count - processed);
+ block_seek = 0;
+ blockstart += blocklen;
+ }
+
+ return processed;
+}
+
+/*
+ * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of
+ * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we
+ * erase and write the whole data at once.
+ */
+static int flash_write_buf (int dev, int fd, void *buf, size_t count,
+ off_t offset, uint8_t mtd_type)
+{
+ void *data;
+ struct erase_info_user erase;
+ size_t blocklen; /* length of NAND block / NOR erase sector */
+ size_t erase_len; /* whole area that can be erased - may include
+ bad blocks */
+ size_t erasesize; /* erase / write length - one block on NAND,
+ whole area on NOR */
+ size_t processed = 0; /* progress counter */
+ size_t write_total; /* total size to actually write - excluding
+ bad blocks */
+ off_t erase_offset; /* offset to the first erase block (aligned)
+ below offset */
+ off_t block_seek; /* offset inside the erase block to the start
+ of the data */
+ off_t top_of_range; /* end of the last block we may use */
+ loff_t blockstart; /* running start of the current block -
+ MEMGETBADBLOCK needs 64 bits */
+ int rc;
+
+ blocklen = DEVESIZE (dev);
+
+ top_of_range = ((DEVOFFSET(dev) / blocklen) +
+ ENVSECTORS (dev)) * blocklen;
+
+ erase_offset = (offset / blocklen) * blocklen;
+
+ /* Maximum area we may use */
+ erase_len = top_of_range - erase_offset;
+
+ blockstart = erase_offset;
+ /* Offset inside a block */
+ block_seek = offset - erase_offset;
+
+ /*
+ * Data size we actually have to write: from the start of the block
+ * to the start of the data, then count bytes of data, and to the
+ * end of the block
+ */
+ write_total = ((block_seek + count + blocklen - 1) /
+ blocklen) * blocklen;
+
+ /*
+ * Support data anywhere within erase sectors: read out the complete
+ * area to be erased, replace the environment image, write the whole
+ * block back again.
+ */
+ if (write_total > count) {
+ data = malloc (erase_len);
+ if (!data) {
+ fprintf (stderr,
+ "Cannot malloc %zu bytes: %s\n",
+ erase_len, strerror (errno));
+ return -1;
+ }
+
+ rc = flash_read_buf (dev, fd, data, write_total, erase_offset,
+ mtd_type);
+ if (write_total != rc)
+ return -1;
+
+#ifdef DEBUG
+ fprintf(stderr, "Preserving data ");
+ if (block_seek != 0)
+ fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1);
+ if (block_seek + count != write_total) {
+ if (block_seek != 0)
+ fprintf(stderr, " and ");
+ fprintf(stderr, "0x%lx - 0x%x",
+ block_seek + count, write_total - 1);
+ }
+ fprintf(stderr, "\n");
+#endif
+ /* Overwrite the old environment */
+ memcpy (data + block_seek, buf, count);
+ } else {
+ /*
+ * We get here, iff offset is block-aligned and count is a
+ * multiple of blocklen - see write_total calculation above
+ */
+ data = buf;
+ }
+
+ if (mtd_type == MTD_NANDFLASH) {
+ /*
+ * NAND: calculate which blocks we are writing. We have
+ * to write one block at a time to skip bad blocks.
+ */
+ erasesize = blocklen;
+ } else {
+ erasesize = erase_len;
+ }
+
+ erase.length = erasesize;
+
+ /* This only runs once on NOR flash and SPI-dataflash */
+ while (processed < write_total) {
+ rc = flash_bad_block (fd, mtd_type, &blockstart);
+ if (rc < 0) /* block test failed */
+ return rc;
+
+ if (blockstart + erasesize > top_of_range) {
+ fprintf (stderr, "End of range reached, aborting\n");
+ return -1;
+ }
+
+ if (rc) { /* block is bad */
+ blockstart += blocklen;
+ continue;
+ }
+
+ erase.start = blockstart;
+ ioctl (fd, MEMUNLOCK, &erase);
+ /* These do not need an explicit erase cycle */
+ if (mtd_type != MTD_ABSENT &&
+ mtd_type != MTD_DATAFLASH)
+ if (ioctl (fd, MEMERASE, &erase) != 0) {
+ fprintf (stderr, "MTD erase error on %s: %s\n",
+ DEVNAME (dev),
+ strerror (errno));
+ return -1;
+ }
+
+ if (lseek (fd, blockstart, SEEK_SET) == -1) {
+ fprintf (stderr,
+ "Seek error on %s: %s\n",
+ DEVNAME (dev), strerror (errno));
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize,
+ blockstart);
+#endif
+ if (write (fd, data + processed, erasesize) != erasesize) {
+ fprintf (stderr, "Write error on %s: %s\n",
+ DEVNAME (dev), strerror (errno));
+ return -1;
+ }
+
+ ioctl (fd, MEMLOCK, &erase);
+
+ processed += blocklen;
+ block_seek = 0;
+ blockstart += blocklen;
+ }
+
+ if (write_total > count)
+ free (data);
+
+ return processed;
+}
+
+/*
+ * Set obsolete flag at offset - NOR flash only
+ */
+static int flash_flag_obsolete (int dev, int fd, off_t offset)
+{
+ int rc;
+ struct erase_info_user erase;
+
+ erase.start = DEVOFFSET (dev);
+ erase.length = DEVESIZE (dev);
+ /* This relies on the fact, that obsolete_flag == 0 */
+ rc = lseek (fd, offset, SEEK_SET);
+ if (rc < 0) {
+ fprintf (stderr, "Cannot seek to set the flag on %s \n",
+ DEVNAME (dev));
+ return rc;
+ }
+ ioctl (fd, MEMUNLOCK, &erase);
+ rc = write (fd, &obsolete_flag, sizeof (obsolete_flag));
+ ioctl (fd, MEMLOCK, &erase);
+ if (rc < 0)
+ perror ("Could not set obsolete flag");
+
+ return rc;
+}
+
+static int flash_write (int fd_current, int fd_target, int dev_target)
+{
+ int rc;
+
+ switch (environment.flag_scheme) {
+ case FLAG_NONE:
+ break;
+ case FLAG_INCREMENTAL:
+ (*environment.flags)++;
+ break;
+ case FLAG_BOOLEAN:
+ *environment.flags = active_flag;
+ break;
+ default:
+ fprintf (stderr, "Unimplemented flash scheme %u \n",
+ environment.flag_scheme);
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "Writing new environment at 0x%lx on %s\n",
+ DEVOFFSET (dev_target), DEVNAME (dev_target));
+#endif
+ rc = flash_write_buf(dev_target, fd_target, environment.image,
+ CUR_ENVSIZE, DEVOFFSET(dev_target),
+ DEVTYPE(dev_target));
+ if (rc < 0)
+ return rc;
+
+ if (environment.flag_scheme == FLAG_BOOLEAN) {
+ /* Have to set obsolete flag */
+ off_t offset = DEVOFFSET (dev_current) +
+ offsetof (struct env_image_redundant, flags);
+#ifdef DEBUG
+ fprintf(stderr,
+ "Setting obsolete flag in environment at 0x%lx on %s\n",
+ DEVOFFSET (dev_current), DEVNAME (dev_current));
+#endif
+ flash_flag_obsolete (dev_current, fd_current, offset);
+ }
+
+ return 0;
+}
+
+static int flash_read (int fd)
+{
+ struct mtd_info_user mtdinfo;
+ struct stat st;
+ int rc;
+
+ rc = fstat(fd, &st);
+ if (rc < 0) {
+ fprintf(stderr, "Cannot stat the file %s\n",
+ DEVNAME(dev_current));
+ return -1;
+ }
+
+ if (S_ISCHR(st.st_mode)) {
+ rc = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (rc < 0) {
+ fprintf(stderr, "Cannot get MTD information for %s\n",
+ DEVNAME(dev_current));
+ return -1;
+ }
+ if (mtdinfo.type != MTD_NORFLASH &&
+ mtdinfo.type != MTD_NANDFLASH &&
+ mtdinfo.type != MTD_DATAFLASH &&
+ mtdinfo.type != MTD_UBIVOLUME) {
+ fprintf (stderr, "Unsupported flash type %u on %s\n",
+ mtdinfo.type, DEVNAME(dev_current));
+ return -1;
+ }
+ } else {
+ memset(&mtdinfo, 0, sizeof(mtdinfo));
+ mtdinfo.type = MTD_ABSENT;
+ }
+
+ DEVTYPE(dev_current) = mtdinfo.type;
+
+ rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE,
+ DEVOFFSET (dev_current), mtdinfo.type);
+
+ return (rc != CUR_ENVSIZE) ? -1 : 0;
+}
+
+static int flash_io (int mode)
+{
+ int fd_current, fd_target, rc, dev_target;
+
+ /* dev_current: fd_current, erase_current */
+ fd_current = open (DEVNAME (dev_current), mode);
+ if (fd_current < 0) {
+ fprintf (stderr,
+ "Can't open %s: %s\n",
+ DEVNAME (dev_current), strerror (errno));
+ return -1;
+ }
+
+ if (mode == O_RDWR) {
+ if (HaveRedundEnv) {
+ /* switch to next partition for writing */
+ dev_target = !dev_current;
+ /* dev_target: fd_target, erase_target */
+ fd_target = open (DEVNAME (dev_target), mode);
+ if (fd_target < 0) {
+ fprintf (stderr,
+ "Can't open %s: %s\n",
+ DEVNAME (dev_target),
+ strerror (errno));
+ rc = -1;
+ goto exit;
+ }
+ } else {
+ dev_target = dev_current;
+ fd_target = fd_current;
+ }
+
+ rc = flash_write (fd_current, fd_target, dev_target);
+
+ if (HaveRedundEnv) {
+ if (close (fd_target)) {
+ fprintf (stderr,
+ "I/O error on %s: %s\n",
+ DEVNAME (dev_target),
+ strerror (errno));
+ rc = -1;
+ }
+ }
+ } else {
+ rc = flash_read (fd_current);
+ }
+
+exit:
+ if (close (fd_current)) {
+ fprintf (stderr,
+ "I/O error on %s: %s\n",
+ DEVNAME (dev_current), strerror (errno));
+ return -1;
+ }
+
+ return rc;
+}
+
+/*
+ * s1 is either a simple 'name', or a 'name=value' pair.
+ * s2 is a 'name=value' pair.
+ * If the names match, return the value of s2, else NULL.
+ */
+
+static char *envmatch (char * s1, char * s2)
+{
+ if (s1 == NULL || s2 == NULL)
+ return NULL;
+
+ while (*s1 == *s2++)
+ if (*s1++ == '=')
+ return s2;
+ if (*s1 == '\0' && *(s2 - 1) == '=')
+ return s2;
+ return NULL;
+}
+
+/*
+ * Prevent confusion if running from erased flash memory
+ */
+int fw_env_open(void)
+{
+ int crc0, crc0_ok;
+ unsigned char flag0;
+ void *addr0;
+
+ int crc1, crc1_ok;
+ unsigned char flag1;
+ void *addr1;
+
+ struct env_image_single *single;
+ struct env_image_redundant *redundant;
+
+ if (parse_config ()) /* should fill envdevices */
+ return -1;
+
+ addr0 = calloc(1, CUR_ENVSIZE);
+ if (addr0 == NULL) {
+ fprintf(stderr,
+ "Not enough memory for environment (%ld bytes)\n",
+ CUR_ENVSIZE);
+ return -1;
+ }
+
+ /* read environment from FLASH to local buffer */
+ environment.image = addr0;
+
+ if (HaveRedundEnv) {
+ redundant = addr0;
+ environment.crc = &redundant->crc;
+ environment.flags = &redundant->flags;
+ environment.data = redundant->data;
+ } else {
+ single = addr0;
+ environment.crc = &single->crc;
+ environment.flags = NULL;
+ environment.data = single->data;
+ }
+
+ dev_current = 0;
+ if (flash_io (O_RDONLY))
+ return -1;
+
+ crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+ crc0_ok = (crc0 == *environment.crc);
+ if (!HaveRedundEnv) {
+ if (!crc0_ok) {
+ fprintf (stderr,
+ "Warning: Bad CRC, using default environment\n");
+ memcpy(environment.data, default_environment, sizeof default_environment);
+ }
+ } else {
+ flag0 = *environment.flags;
+
+ dev_current = 1;
+ addr1 = calloc(1, CUR_ENVSIZE);
+ if (addr1 == NULL) {
+ fprintf(stderr,
+ "Not enough memory for environment (%ld bytes)\n",
+ CUR_ENVSIZE);
+ return -1;
+ }
+ redundant = addr1;
+
+ /*
+ * have to set environment.image for flash_read(), careful -
+ * other pointers in environment still point inside addr0
+ */
+ environment.image = addr1;
+ if (flash_io (O_RDONLY))
+ return -1;
+
+ /* Check flag scheme compatibility */
+ if (DEVTYPE(dev_current) == MTD_NORFLASH &&
+ DEVTYPE(!dev_current) == MTD_NORFLASH) {
+ environment.flag_scheme = FLAG_BOOLEAN;
+ } else if (DEVTYPE(dev_current) == MTD_NANDFLASH &&
+ DEVTYPE(!dev_current) == MTD_NANDFLASH) {
+ environment.flag_scheme = FLAG_INCREMENTAL;
+ } else if (DEVTYPE(dev_current) == MTD_DATAFLASH &&
+ DEVTYPE(!dev_current) == MTD_DATAFLASH) {
+ environment.flag_scheme = FLAG_BOOLEAN;
+ } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME &&
+ DEVTYPE(!dev_current) == MTD_UBIVOLUME) {
+ environment.flag_scheme = FLAG_INCREMENTAL;
+ } else {
+ fprintf (stderr, "Incompatible flash types!\n");
+ return -1;
+ }
+
+ crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE);
+ crc1_ok = (crc1 == redundant->crc);
+ flag1 = redundant->flags;
+
+ if (crc0_ok && !crc1_ok) {
+ dev_current = 0;
+ } else if (!crc0_ok && crc1_ok) {
+ dev_current = 1;
+ } else if (!crc0_ok && !crc1_ok) {
+ fprintf (stderr,
+ "Warning: Bad CRC, using default environment\n");
+ memcpy (environment.data, default_environment,
+ sizeof default_environment);
+ dev_current = 0;
+ } else {
+ switch (environment.flag_scheme) {
+ case FLAG_BOOLEAN:
+ if (flag0 == active_flag &&
+ flag1 == obsolete_flag) {
+ dev_current = 0;
+ } else if (flag0 == obsolete_flag &&
+ flag1 == active_flag) {
+ dev_current = 1;
+ } else if (flag0 == flag1) {
+ dev_current = 0;
+ } else if (flag0 == 0xFF) {
+ dev_current = 0;
+ } else if (flag1 == 0xFF) {
+ dev_current = 1;
+ } else {
+ dev_current = 0;
+ }
+ break;
+ case FLAG_INCREMENTAL:
+ if (flag0 == 255 && flag1 == 0)
+ dev_current = 1;
+ else if ((flag1 == 255 && flag0 == 0) ||
+ flag0 >= flag1)
+ dev_current = 0;
+ else /* flag1 > flag0 */
+ dev_current = 1;
+ break;
+ default:
+ fprintf (stderr, "Unknown flag scheme %u \n",
+ environment.flag_scheme);
+ return -1;
+ }
+ }
+
+ /*
+ * If we are reading, we don't need the flag and the CRC any
+ * more, if we are writing, we will re-calculate CRC and update
+ * flags before writing out
+ */
+ if (dev_current) {
+ environment.image = addr1;
+ environment.crc = &redundant->crc;
+ environment.flags = &redundant->flags;
+ environment.data = redundant->data;
+ free (addr0);
+ } else {
+ environment.image = addr0;
+ /* Other pointers are already set */
+ free (addr1);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current));
+#endif
+ }
+ return 0;
+}
+
+
+static int parse_config ()
+{
+ struct stat st;
+
+#if defined(CONFIG_FILE)
+ /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */
+ if (get_config (CONFIG_FILE)) {
+ fprintf (stderr,
+ "Cannot parse config file: %s\n", strerror (errno));
+ return -1;
+ }
+#else
+ strcpy (DEVNAME (0), DEVICE1_NAME);
+ DEVOFFSET (0) = DEVICE1_OFFSET;
+ ENVSIZE (0) = ENV1_SIZE;
+ /* Default values are: erase-size=env-size, #sectors=1 */
+ DEVESIZE (0) = ENVSIZE (0);
+ ENVSECTORS (0) = 1;
+#ifdef DEVICE1_ESIZE
+ DEVESIZE (0) = DEVICE1_ESIZE;
+#endif
+#ifdef DEVICE1_ENVSECTORS
+ ENVSECTORS (0) = DEVICE1_ENVSECTORS;
+#endif
+
+#ifdef HAVE_REDUND
+ strcpy (DEVNAME (1), DEVICE2_NAME);
+ DEVOFFSET (1) = DEVICE2_OFFSET;
+ ENVSIZE (1) = ENV2_SIZE;
+ /* Default values are: erase-size=env-size, #sectors=1 */
+ DEVESIZE (1) = ENVSIZE (1);
+ ENVSECTORS (1) = 1;
+#ifdef DEVICE2_ESIZE
+ DEVESIZE (1) = DEVICE2_ESIZE;
+#endif
+#ifdef DEVICE2_ENVSECTORS
+ ENVSECTORS (1) = DEVICE2_ENVSECTORS;
+#endif
+ HaveRedundEnv = 1;
+#endif
+#endif
+ if (stat (DEVNAME (0), &st)) {
+ fprintf (stderr,
+ "Cannot access MTD device %s: %s\n",
+ DEVNAME (0), strerror (errno));
+ return -1;
+ }
+
+ if (HaveRedundEnv && stat (DEVNAME (1), &st)) {
+ fprintf (stderr,
+ "Cannot access MTD device %s: %s\n",
+ DEVNAME (1), strerror (errno));
+ return -1;
+ }
+ return 0;
+}
+
+#if defined(CONFIG_FILE)
+static int get_config (char *fname)
+{
+ FILE *fp;
+ int i = 0;
+ int rc;
+ char dump[128];
+
+ fp = fopen (fname, "r");
+ if (fp == NULL)
+ return -1;
+
+ while (i < 2 && fgets (dump, sizeof (dump), fp)) {
+ /* Skip incomplete conversions and comment strings */
+ if (dump[0] == '#')
+ continue;
+
+ rc = sscanf (dump, "%s %lx %lx %lx %lx",
+ DEVNAME (i),
+ &DEVOFFSET (i),
+ &ENVSIZE (i),
+ &DEVESIZE (i),
+ &ENVSECTORS (i));
+
+ if (rc < 3)
+ continue;
+
+ if (rc < 4)
+ /* Assume the erase size is the same as the env-size */
+ DEVESIZE(i) = ENVSIZE(i);
+
+ if (rc < 5)
+ /* Default - 1 sector */
+ ENVSECTORS (i) = 1;
+
+ i++;
+ }
+ fclose (fp);
+
+ HaveRedundEnv = i - 1;
+ if (!i) { /* No valid entries found */
+ errno = EINVAL;
+ return -1;
+ } else
+ return 0;
+}
+#endif
diff --git a/tools/env/fw_env.config b/tools/env/fw_env.config
new file mode 100644
index 0000000..90e499d
--- /dev/null
+++ b/tools/env/fw_env.config
@@ -0,0 +1,22 @@
+# Configuration file for fw_(printenv/setenv) utility.
+# Up to two entries are valid, in this case the redundant
+# environment sector is assumed present.
+# Notice, that the "Number of sectors" is ignored on NOR and SPI-dataflash.
+# Futhermore, if the Flash sector size is ommitted, this value is assumed to
+# be the same as the Environment size, which is valid for NOR and SPI-dataflash
+
+# NOR example
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+/dev/mtd1 0x0000 0x4000 0x4000
+/dev/mtd2 0x0000 0x4000 0x4000
+
+# MTD SPI-dataflash example
+# MTD device name Device offset Env. size Flash sector size Number of sectors
+#/dev/mtd5 0x4200 0x4200
+#/dev/mtd6 0x4200 0x4200
+
+# NAND example
+#/dev/mtd0 0x4000 0x4000 0x20000 2
+
+# Block device example
+#/dev/mmcblk0 0xc0000 0x20000
diff --git a/tools/env/fw_env.h b/tools/env/fw_env.h
new file mode 100644
index 0000000..a1a6807
--- /dev/null
+++ b/tools/env/fw_env.h
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2002-2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Pull in the current config to define the default environment */
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* get only #defines from config.h */
+#include <config.h>
+#undef __ASSEMBLY__
+#else
+#include <config.h>
+#endif
+
+/*
+ * To build the utility with the static configuration
+ * comment out the next line.
+ * See included "fw_env.config" sample file
+ * for notes on configuration.
+ */
+#define CONFIG_FILE "/etc/fw_env.config"
+
+#ifndef CONFIG_FILE
+#define HAVE_REDUND /* For systems with 2 env sectors */
+#define DEVICE1_NAME "/dev/mtd1"
+#define DEVICE2_NAME "/dev/mtd2"
+#define DEVICE1_OFFSET 0x0000
+#define ENV1_SIZE 0x4000
+#define DEVICE1_ESIZE 0x4000
+#define DEVICE1_ENVSECTORS 2
+#define DEVICE2_OFFSET 0x0000
+#define ENV2_SIZE 0x4000
+#define DEVICE2_ESIZE 0x4000
+#define DEVICE2_ENVSECTORS 2
+#endif
+
+#ifndef CONFIG_BAUDRATE
+#define CONFIG_BAUDRATE 115200
+#endif
+
+#ifndef CONFIG_BOOTDELAY
+#define CONFIG_BOOTDELAY 5 /* autoboot after 5 seconds */
+#endif
+
+#ifndef CONFIG_BOOTCOMMAND
+#define CONFIG_BOOTCOMMAND \
+ "bootp; " \
+ "setenv bootargs root=/dev/nfs nfsroot=${serverip}:${rootpath} " \
+ "ip=${ipaddr}:${serverip}:${gatewayip}:${netmask}:${hostname}::off; " \
+ "bootm"
+#endif
+
+extern int fw_printenv(int argc, char *argv[]);
+extern char *fw_getenv (char *name);
+extern int fw_setenv (int argc, char *argv[]);
+extern int fw_parse_script(char *fname);
+extern int fw_env_open(void);
+extern int fw_env_write(char *name, char *value);
+extern int fw_env_close(void);
+
+extern unsigned long crc32 (unsigned long, const unsigned char *, unsigned);
diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
new file mode 100644
index 0000000..40ea3f6
--- /dev/null
+++ b/tools/env/fw_env_main.c
@@ -0,0 +1,156 @@
+/*
+ * (C) Copyright 2000-2008
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * Command line user interface to firmware (=U-Boot) environment.
+ *
+ * Implements:
+ * fw_printenv [[ -n name ] | [ name ... ]]
+ * - prints the value of a single environment variable
+ * "name", the ``name=value'' pairs of one or more
+ * environment variables "name", or the whole
+ * environment if no names are specified.
+ * fw_setenv name [ value ... ]
+ * - If a name without any values is given, the variable
+ * with this name is deleted from the environment;
+ * otherwise, all "value" arguments are concatenated,
+ * separated by single blank characters, and the
+ * resulting string is assigned to the environment
+ * variable "name"
+ */
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/file.h>
+#include <unistd.h>
+#include "fw_env.h"
+
+#define CMD_PRINTENV "fw_printenv"
+#define CMD_SETENV "fw_setenv"
+
+static struct option long_options[] = {
+ {"script", required_argument, NULL, 's'},
+ {"help", no_argument, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+};
+
+void usage(void)
+{
+
+ fprintf(stderr, "fw_printenv/fw_setenv, "
+ "a command line interface to U-Boot environment\n\n"
+ "usage:\tfw_printenv [-n] [variable name]\n"
+ "\tfw_setenv [variable name] [variable value]\n"
+ "\tfw_setenv -s [ file ]\n"
+ "\tfw_setenv -s - < [ file ]\n\n"
+ "The file passed as argument contains only pairs "
+ "name / value\n"
+ "Example:\n"
+ "# Any line starting with # is treated as comment\n"
+ "\n"
+ "\t netdev eth0\n"
+ "\t kernel_addr 400000\n"
+ "\t var1\n"
+ "\t var2 The quick brown fox jumps over the "
+ "lazy dog\n"
+ "\n"
+ "A variable without value will be dropped. It is possible\n"
+ "to put any number of spaces between the fields, but any\n"
+ "space inside the value is treated as part of the value "
+ "itself.\n\n"
+ );
+}
+
+int main(int argc, char *argv[])
+{
+ char *p;
+ char *cmdname = *argv;
+ char *script_file = NULL;
+ int c;
+ const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
+ int lockfd = -1;
+ int retval = EXIT_SUCCESS;
+
+ lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (-1 == lockfd) {
+ fprintf(stderr, "Error opening lock file %s\n", lockname);
+ return EXIT_FAILURE;
+ }
+
+ if (-1 == flock(lockfd, LOCK_EX)) {
+ fprintf(stderr, "Error locking file %s\n", lockname);
+ close(lockfd);
+ return EXIT_FAILURE;
+ }
+
+ if ((p = strrchr (cmdname, '/')) != NULL) {
+ cmdname = p + 1;
+ }
+
+ while ((c = getopt_long (argc, argv, "ns:h",
+ long_options, NULL)) != EOF) {
+ switch (c) {
+ case 'n':
+ /* handled in fw_printenv */
+ break;
+ case 's':
+ script_file = optarg;
+ break;
+ case 'h':
+ usage();
+ goto exit;
+ default: /* '?' */
+ fprintf(stderr, "Try `%s --help' for more information."
+ "\n", cmdname);
+ retval = EXIT_FAILURE;
+ goto exit;
+ }
+ }
+
+ if (strcmp(cmdname, CMD_PRINTENV) == 0) {
+ if (fw_printenv(argc, argv) != 0)
+ retval = EXIT_FAILURE;
+ } else if (strcmp(cmdname, CMD_SETENV) == 0) {
+ if (!script_file) {
+ if (fw_setenv(argc, argv) != 0)
+ retval = EXIT_FAILURE;
+ } else {
+ if (fw_parse_script(script_file) != 0)
+ retval = EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr,
+ "Identity crisis - may be called as `" CMD_PRINTENV
+ "' or as `" CMD_SETENV "' but not as `%s'\n",
+ cmdname);
+ retval = EXIT_FAILURE;
+ }
+
+exit:
+ flock(lockfd, LOCK_UN);
+ close(lockfd);
+ return retval;
+}
diff --git a/tools/envcrc.c b/tools/envcrc.c
new file mode 100644
index 0000000..08d2a8f
--- /dev/null
+++ b/tools/envcrc.c
@@ -0,0 +1,145 @@
+/*
+ * (C) Copyright 2001
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef __ASSEMBLY__
+#define __ASSEMBLY__ /* Dirty trick to get only #defines */
+#endif
+#define __ASM_STUB_PROCESSOR_H__ /* don't include asm/processor. */
+#include <config.h>
+#undef __ASSEMBLY__
+
+#if defined(CONFIG_ENV_IS_IN_FLASH)
+# ifndef CONFIG_ENV_ADDR
+# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET)
+# endif
+# ifndef CONFIG_ENV_OFFSET
+# define CONFIG_ENV_OFFSET (CONFIG_ENV_ADDR - CONFIG_SYS_FLASH_BASE)
+# endif
+# if !defined(CONFIG_ENV_ADDR_REDUND) && defined(CONFIG_ENV_OFFSET_REDUND)
+# define CONFIG_ENV_ADDR_REDUND (CONFIG_SYS_FLASH_BASE + CONFIG_ENV_OFFSET_REDUND)
+# endif
+# ifndef CONFIG_ENV_SIZE
+# define CONFIG_ENV_SIZE CONFIG_ENV_SECT_SIZE
+# endif
+# if defined(CONFIG_ENV_ADDR_REDUND) && !defined(CONFIG_ENV_SIZE_REDUND)
+# define CONFIG_ENV_SIZE_REDUND CONFIG_ENV_SIZE
+# endif
+# if (CONFIG_ENV_ADDR >= CONFIG_SYS_MONITOR_BASE) && \
+ ((CONFIG_ENV_ADDR + CONFIG_ENV_SIZE) <= (CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN))
+# define ENV_IS_EMBEDDED
+# endif
+# if defined(CONFIG_ENV_ADDR_REDUND) || defined(CONFIG_ENV_OFFSET_REDUND)
+# define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# endif
+#endif /* CONFIG_ENV_IS_IN_FLASH */
+
+#if defined(ENV_IS_EMBEDDED) && !defined(CONFIG_BUILD_ENVCRC)
+# define CONFIG_BUILD_ENVCRC
+#endif
+
+#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
+# define ENV_HEADER_SIZE (sizeof(uint32_t) + 1)
+#else
+# define ENV_HEADER_SIZE (sizeof(uint32_t))
+#endif
+
+#define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
+
+
+#ifdef CONFIG_BUILD_ENVCRC
+# include <environment.h>
+extern unsigned int env_size;
+extern env_t environment;
+#endif /* CONFIG_BUILD_ENVCRC */
+
+extern uint32_t crc32 (uint32_t, const unsigned char *, unsigned int);
+
+int main (int argc, char **argv)
+{
+#ifdef CONFIG_BUILD_ENVCRC
+ unsigned char pad = 0x00;
+ uint32_t crc;
+ unsigned char *envptr = (unsigned char *)&environment,
+ *dataptr = envptr + ENV_HEADER_SIZE;
+ unsigned int datasize = ENV_SIZE;
+ unsigned int eoe;
+
+ if (argv[1] && !strncmp(argv[1], "--binary", 8)) {
+ int ipad = 0xff;
+ if (argv[1][8] == '=')
+ sscanf(argv[1] + 9, "%i", &ipad);
+ pad = ipad;
+ }
+
+ if (pad) {
+ /* find the end of env */
+ for (eoe = 0; eoe < datasize - 1; ++eoe)
+ if (!dataptr[eoe] && !dataptr[eoe+1]) {
+ eoe += 2;
+ break;
+ }
+ if (eoe < datasize - 1)
+ memset(dataptr + eoe, pad, datasize - eoe);
+ }
+
+ crc = crc32 (0, dataptr, datasize);
+
+ /* Check if verbose mode is activated passing a parameter to the program */
+ if (argc > 1) {
+ if (!strncmp(argv[1], "--binary", 8)) {
+ int le = (argc > 2 ? !strcmp(argv[2], "le") : 1);
+ size_t i, start, end, step;
+ if (le) {
+ start = 0;
+ end = ENV_HEADER_SIZE;
+ step = 1;
+ } else {
+ start = ENV_HEADER_SIZE - 1;
+ end = -1;
+ step = -1;
+ }
+ for (i = start; i != end; i += step)
+ printf("%c", (crc & (0xFF << (i * 8))) >> (i * 8));
+ if (fwrite(dataptr, 1, datasize, stdout) != datasize)
+ fprintf(stderr, "fwrite() failed: %s\n", strerror(errno));
+ } else {
+ printf("CRC32 from offset %08X to %08X of environment = %08X\n",
+ (unsigned int) (dataptr - envptr),
+ (unsigned int) (dataptr - envptr) + datasize,
+ crc);
+ }
+ } else {
+ printf ("0x%08X\n", crc);
+ }
+#else
+ printf ("0\n");
+#endif
+ return EXIT_SUCCESS;
+}
diff --git a/tools/fdt_host.h b/tools/fdt_host.h
new file mode 100644
index 0000000..b08bf86
--- /dev/null
+++ b/tools/fdt_host.h
@@ -0,0 +1,27 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef __FDT_HOST_H__
+#define __FDT_HOST_H__
+
+/* Make sure to include u-boot version of libfdt include files */
+#include "../include/libfdt.h"
+#include "../include/fdt_support.h"
+
+#endif /* __FDT_HOST_H__ */
diff --git a/tools/fit_image.c b/tools/fit_image.c
new file mode 100644
index 0000000..281c2bd
--- /dev/null
+++ b/tools/fit_image.c
@@ -0,0 +1,222 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.de
+ *
+ * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
+ * FIT image specific code abstracted from mkimage.c
+ * some functions added to address abstraction
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <u-boot/crc.h>
+
+static image_header_t header;
+
+static int fit_verify_header (unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ return fdt_check_header ((void *)ptr);
+}
+
+static int fit_check_image_types (uint8_t type)
+{
+ if (type == IH_TYPE_FLATDT)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+int mmap_fdt(struct mkimage_params *params, const char *fname, void **blobp,
+ struct stat *sbuf)
+{
+ void *ptr;
+ int fd;
+
+ /* Load FIT blob into memory (we need to write hashes/signatures) */
+ fd = open(fname, O_RDWR | O_BINARY);
+
+ if (fd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ unlink(fname);
+ return -1;
+ }
+
+ if (fstat(fd, sbuf) < 0) {
+ fprintf(stderr, "%s: Can't stat %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ unlink(fname);
+ return -1;
+ }
+
+ ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if (ptr == MAP_FAILED) {
+ fprintf(stderr, "%s: Can't read %s: %s\n",
+ params->cmdname, fname, strerror(errno));
+ unlink(fname);
+ return -1;
+ }
+
+ /* check if ptr has a valid blob */
+ if (fdt_check_header(ptr)) {
+ fprintf(stderr, "%s: Invalid FIT blob\n", params->cmdname);
+ unlink(fname);
+ return -1;
+ }
+
+ *blobp = ptr;
+ return fd;
+}
+
+/**
+ * fit_handle_file - main FIT file processing function
+ *
+ * fit_handle_file() runs dtc to convert .its to .itb, includes
+ * binary data, updates timestamp property and calculates hashes.
+ *
+ * datafile - .its file
+ * imagefile - .itb file
+ *
+ * returns:
+ * only on success, otherwise calls exit (EXIT_FAILURE);
+ */
+static int fit_handle_file (struct mkimage_params *params)
+{
+ char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
+ char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
+ int tfd, destfd = 0;
+ void *dest_blob = NULL;
+ struct stat sbuf;
+ void *ptr;
+ off_t destfd_size = 0;
+
+ /* Flattened Image Tree (FIT) format handling */
+ debug ("FIT format handling\n");
+
+ /* call dtc to include binary properties into the tmp file */
+ if (strlen (params->imagefile) +
+ strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
+ fprintf (stderr, "%s: Image file name (%s) too long, "
+ "can't create tmpfile",
+ params->imagefile, params->cmdname);
+ return (EXIT_FAILURE);
+ }
+ sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
+
+ /* We either compile the source file, or use the existing FIT image */
+ if (params->datafile) {
+ /* dtc -I dts -O dtb -p 500 datafile > tmpfile */
+ snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
+ MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
+ debug("Trying to execute \"%s\"\n", cmd);
+ } else {
+ snprintf(cmd, sizeof(cmd), "cp %s %s",
+ params->imagefile, tmpfile);
+ }
+ if (system (cmd) == -1) {
+ fprintf (stderr, "%s: system(%s) failed: %s\n",
+ params->cmdname, cmd, strerror(errno));
+ goto err_system;
+ }
+
+ if (params->keydest) {
+ destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
+ if (destfd < 0)
+ goto err_keydest;
+ destfd_size = sbuf.st_size;
+ }
+
+ tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);
+ if (tfd < 0)
+ goto err_mmap;
+
+ /* set hashes for images in the blob */
+ if (fit_add_verification_data(params->keydir,
+ dest_blob, ptr, params->comment,
+ params->require_keys)) {
+ fprintf(stderr, "%s Can't add hashes to FIT blob\n",
+ params->cmdname);
+ goto err_add_hashes;
+ }
+
+ /* for first image creation, add a timestamp at offset 0 i.e., root */
+ if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
+ fprintf (stderr, "%s: Can't add image timestamp\n",
+ params->cmdname);
+ goto err_add_timestamp;
+ }
+ debug ("Added timestamp successfully\n");
+
+ munmap ((void *)ptr, sbuf.st_size);
+ close (tfd);
+ if (dest_blob) {
+ munmap(dest_blob, destfd_size);
+ close(destfd);
+ }
+
+ if (rename (tmpfile, params->imagefile) == -1) {
+ fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
+ params->cmdname, tmpfile, params->imagefile,
+ strerror (errno));
+ unlink (tmpfile);
+ unlink (params->imagefile);
+ return (EXIT_FAILURE);
+ }
+ return (EXIT_SUCCESS);
+
+err_add_timestamp:
+err_add_hashes:
+ munmap(ptr, sbuf.st_size);
+err_mmap:
+ if (dest_blob)
+ munmap(dest_blob, destfd_size);
+err_keydest:
+err_system:
+ unlink(tmpfile);
+ return -1;
+}
+
+static int fit_check_params (struct mkimage_params *params)
+{
+ return ((params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)));
+}
+
+static struct image_type_params fitimage_params = {
+ .name = "FIT Image support",
+ .header_size = sizeof(image_header_t),
+ .hdr = (void*)&header,
+ .verify_header = fit_verify_header,
+ .print_header = fit_print_contents,
+ .check_image_type = fit_check_image_types,
+ .fflag_handle = fit_handle_file,
+ .set_header = NULL, /* FIT images use DTB header */
+ .check_params = fit_check_params,
+};
+
+void init_fit_image_type (void)
+{
+ mkimage_register (&fitimage_params);
+}
diff --git a/tools/gcc-version.sh b/tools/gcc-version.sh
new file mode 100755
index 0000000..debecb5
--- /dev/null
+++ b/tools/gcc-version.sh
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# gcc-version [-p] gcc-command
+#
+# Prints the gcc version of `gcc-command' in a canonical 4-digit form
+# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc.
+#
+# With the -p option, prints the patchlevel as well, for example `029503' for
+# gcc-2.95.3, `030301' for gcc-3.3.1, etc.
+#
+
+if [ "$1" = "-p" ] ; then
+ with_patchlevel=1;
+ shift;
+fi
+
+compiler="$*"
+
+if [ ${#compiler} -eq 0 ]; then
+ echo "Error: No compiler specified."
+ printf "Usage:\n\t$0 <gcc-command>\n"
+ exit 1
+fi
+
+MAJOR=$(echo __GNUC__ | $compiler -E -xc - | tail -n 1)
+MINOR=$(echo __GNUC_MINOR__ | $compiler -E -xc - | tail -n 1)
+if [ "x$with_patchlevel" != "x" ] ; then
+ PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -xc - | tail -n 1)
+ printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL
+else
+ printf "%02d%02d\\n" $MAJOR $MINOR
+fi
diff --git a/tools/gdb/Makefile b/tools/gdb/Makefile
new file mode 100644
index 0000000..90037c7
--- /dev/null
+++ b/tools/gdb/Makefile
@@ -0,0 +1,74 @@
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2000
+# Murray Jensen <Murray.Jensen@csiro.au>
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+BINS = gdbsend gdbcont
+
+COBJS = gdbsend.o gdbcont.o error.o remote.o serial.o
+
+HOSTOBJS := $(addprefix $(obj),$(COBJS))
+HOSTSRCS := $(COBJS:.o=.c)
+BINS := $(addprefix $(obj),$(BINS))
+
+#
+# Use native tools and options
+#
+HOSTCPPFLAGS = -I$(BFD_ROOT_DIR)/include
+
+HOSTOS := $(shell uname -s | sed -e 's/\([Cc][Yy][Gg][Ww][Ii][Nn]\).*/cygwin/')
+
+ifeq ($(HOSTOS),cygwin)
+
+all:
+$(obj).depend:
+
+else # ! CYGWIN
+
+all: $(obj).depend $(BINS)
+
+$(obj)gdbsend: $(obj)gdbsend.o $(obj)error.o $(obj)remote.o $(obj)serial.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+$(obj)gdbcont: $(obj)gdbcont.o $(obj)error.o $(obj)remote.o $(obj)serial.o
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+
+clean:
+ rm -f $(HOSTOBJS)
+
+distclean: clean
+ rm -f $(BINS) $(obj)core $(obj)*.bak $(obj).depend
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
+
+endif # cygwin
diff --git a/tools/gdb/error.c b/tools/gdb/error.c
new file mode 100644
index 0000000..276a00a
--- /dev/null
+++ b/tools/gdb/error.c
@@ -0,0 +1,81 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "error.h"
+
+char *pname;
+
+void
+Warning(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "%s: WARNING: ", pname);
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+}
+
+void
+Error(char *fmt, ...)
+{
+ va_list args;
+
+ fprintf(stderr, "%s: ERROR: ", pname);
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ fprintf(stderr, "\n");
+
+ exit(1);
+}
+
+void
+Perror(char *fmt, ...)
+{
+ va_list args;
+ int e = errno;
+ char *p;
+
+ fprintf(stderr, "%s: ERROR: ", pname);
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ if ((p = strerror(e)) == NULL || *p == '\0')
+ fprintf(stderr, ": Unknown Error (%d)\n", e);
+ else
+ fprintf(stderr, ": %s\n", p);
+
+ exit(1);
+}
diff --git a/tools/gdb/error.h b/tools/gdb/error.h
new file mode 100644
index 0000000..0698213
--- /dev/null
+++ b/tools/gdb/error.h
@@ -0,0 +1,30 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+extern char *pname;
+
+extern void Warning(char *, ...);
+extern void Error(char *, ...);
+extern void Perror(char *, ...);
diff --git a/tools/gdb/gdbcont.c b/tools/gdb/gdbcont.c
new file mode 100644
index 0000000..300545d
--- /dev/null
+++ b/tools/gdb/gdbcont.c
@@ -0,0 +1,87 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+
+char *serialdev = "/dev/term/b";
+speed_t speed = B230400;
+int verbose = 0;
+
+int
+main(int ac, char **av)
+{
+ int c, sfd;
+
+ if ((pname = strrchr(av[0], '/')) == NULL)
+ pname = av[0];
+ else
+ pname++;
+
+ while ((c = getopt(ac, av, "b:p:v")) != EOF)
+ switch (c) {
+
+ case 'b':
+ if ((speed = cvtspeed(optarg)) == B0)
+ Error("can't decode baud rate specified in -b option");
+ break;
+
+ case 'p':
+ serialdev = optarg;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ default:
+ usage:
+ fprintf(stderr, "Usage: %s [-b bps] [-p dev] [-v]\n", pname);
+ exit(1);
+ }
+ if (optind != ac)
+ goto usage;
+
+ if (verbose)
+ fprintf(stderr, "Opening serial port and sending continue...\n");
+
+ if ((sfd = serialopen(serialdev, speed)) < 0)
+ Perror("open of serial device '%s' failed", serialdev);
+
+ remote_desc = sfd;
+ remote_reset();
+ remote_continue();
+
+ if (serialclose(sfd) < 0)
+ Perror("close of serial device '%s' failed", serialdev);
+
+ if (verbose)
+ fprintf(stderr, "Done.\n");
+
+ return (0);
+}
diff --git a/tools/gdb/gdbsend.c b/tools/gdb/gdbsend.c
new file mode 100644
index 0000000..8cd8347
--- /dev/null
+++ b/tools/gdb/gdbsend.c
@@ -0,0 +1,137 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+
+char *serialdev = "/dev/term/b";
+speed_t speed = B230400;
+int verbose = 0, docont = 0;
+unsigned long addr = 0x10000UL;
+
+int
+main(int ac, char **av)
+{
+ int c, sfd, ifd;
+ char *ifn, *image;
+ struct stat ist;
+
+ if ((pname = strrchr(av[0], '/')) == NULL)
+ pname = av[0];
+ else
+ pname++;
+
+ while ((c = getopt(ac, av, "a:b:cp:v")) != EOF)
+ switch (c) {
+
+ case 'a': {
+ char *ep;
+
+ addr = strtol(optarg, &ep, 0);
+ if (ep == optarg || *ep != '\0')
+ Error("can't decode address specified in -a option");
+ break;
+ }
+
+ case 'b':
+ if ((speed = cvtspeed(optarg)) == B0)
+ Error("can't decode baud rate specified in -b option");
+ break;
+
+ case 'c':
+ docont = 1;
+ break;
+
+ case 'p':
+ serialdev = optarg;
+ break;
+
+ case 'v':
+ verbose = 1;
+ break;
+
+ default:
+ usage:
+ fprintf(stderr,
+ "Usage: %s [-a addr] [-b bps] [-c] [-p dev] [-v] imagefile\n",
+ pname);
+ exit(1);
+ }
+
+ if (optind != ac - 1)
+ goto usage;
+ ifn = av[optind++];
+
+ if (verbose)
+ fprintf(stderr, "Opening file and reading image...\n");
+
+ if ((ifd = open(ifn, O_RDONLY)) < 0)
+ Perror("can't open kernel image file '%s'", ifn);
+
+ if (fstat(ifd, &ist) < 0)
+ Perror("fstat '%s' failed", ifn);
+
+ if ((image = (char *)malloc(ist.st_size)) == NULL)
+ Perror("can't allocate %ld bytes for image", ist.st_size);
+
+ if ((c = read(ifd, image, ist.st_size)) < 0)
+ Perror("read of %d bytes from '%s' failed", ist.st_size, ifn);
+
+ if (c != ist.st_size)
+ Error("read of %ld bytes from '%s' failed (%d)", ist.st_size, ifn, c);
+
+ if (close(ifd) < 0)
+ Perror("close of '%s' failed", ifn);
+
+ if (verbose)
+ fprintf(stderr, "Opening serial port and sending image...\n");
+
+ if ((sfd = serialopen(serialdev, speed)) < 0)
+ Perror("open of serial device '%s' failed", serialdev);
+
+ remote_desc = sfd;
+ remote_reset();
+ remote_write_bytes(addr, image, ist.st_size);
+
+ if (docont) {
+ if (verbose)
+ fprintf(stderr, "[continue]");
+ remote_continue();
+ }
+
+ if (serialclose(sfd) < 0)
+ Perror("close of serial device '%s' failed", serialdev);
+
+ if (verbose)
+ fprintf(stderr, "Done.\n");
+
+ return (0);
+}
diff --git a/tools/gdb/remote.c b/tools/gdb/remote.c
new file mode 100644
index 0000000..c76a7ba
--- /dev/null
+++ b/tools/gdb/remote.c
@@ -0,0 +1,928 @@
+/*
+ * taken from gdb/remote.c
+ *
+ * I am only interested in the write to memory stuff - everything else
+ * has been ripped out
+ *
+ * all the copyright notices etc have been left in
+ */
+
+/* enough so that it will compile */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/*nicked from gcc..*/
+
+#ifndef alloca
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not GNU C. */
+#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi)
+#include <alloca.h>
+#else /* not sparc */
+#if defined (MSDOS) && !defined (__TURBOC__)
+#include <malloc.h>
+#else /* not MSDOS, or __TURBOC__ */
+#if defined(_AIX)
+#include <malloc.h>
+ #pragma alloca
+#else /* not MSDOS, __TURBOC__, or _AIX */
+#ifdef __hpux
+#endif /* __hpux */
+#endif /* not _AIX */
+#endif /* not MSDOS, or __TURBOC__ */
+#endif /* not sparc. */
+#endif /* not GNU C. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void* alloca(size_t);
+#ifdef __cplusplus
+}
+#endif
+#endif /* alloca not defined. */
+
+
+#include "serial.h"
+#include "error.h"
+#include "remote.h"
+#define REGISTER_BYTES 0
+#define fprintf_unfiltered fprintf
+#define fprintf_filtered fprintf
+#define fputs_unfiltered fputs
+#define fputs_filtered fputs
+#define fputc_unfiltered fputc
+#define fputc_filtered fputc
+#define printf_unfiltered printf
+#define printf_filtered printf
+#define puts_unfiltered puts
+#define puts_filtered puts
+#define putchar_unfiltered putchar
+#define putchar_filtered putchar
+#define fputstr_unfiltered(a,b,c) fputs((a), (c))
+#define gdb_stdlog stderr
+#define SERIAL_READCHAR(fd,timo) serialreadchar((fd), (timo))
+#define SERIAL_WRITE(fd, addr, len) serialwrite((fd), (addr), (len))
+#define error Error
+#define perror_with_name Perror
+#define gdb_flush fflush
+#define max(a,b) (((a)>(b))?(a):(b))
+#define min(a,b) (((a)<(b))?(a):(b))
+#define target_mourn_inferior() {}
+#define ULONGEST unsigned long
+#define CORE_ADDR unsigned long
+
+static int putpkt (char *);
+static int putpkt_binary(char *, int);
+static void getpkt (char *, int);
+
+static int remote_debug = 0, remote_register_buf_size = 0, watchdog = 0;
+
+int remote_desc = -1, remote_timeout = 10;
+
+static void
+fputstrn_unfiltered(char *s, int n, int x, FILE *fp)
+{
+ while (n-- > 0)
+ fputc(*s++, fp);
+}
+
+void
+remote_reset(void)
+{
+ SERIAL_WRITE(remote_desc, "+", 1);
+}
+
+void
+remote_continue(void)
+{
+ putpkt("c");
+}
+
+/* Remote target communications for serial-line targets in custom GDB protocol
+ Copyright 1988, 91, 92, 93, 94, 95, 96, 97, 98, 1999
+ Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ 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., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+/* *INDENT-OFF* */
+/* Remote communication protocol.
+
+ A debug packet whose contents are <data>
+ is encapsulated for transmission in the form:
+
+ $ <data> # CSUM1 CSUM2
+
+ <data> must be ASCII alphanumeric and cannot include characters
+ '$' or '#'. If <data> starts with two characters followed by
+ ':', then the existing stubs interpret this as a sequence number.
+
+ CSUM1 and CSUM2 are ascii hex representation of an 8-bit
+ checksum of <data>, the most significant nibble is sent first.
+ the hex digits 0-9,a-f are used.
+
+ Receiver responds with:
+
+ + - if CSUM is correct and ready for next packet
+ - - if CSUM is incorrect
+
+ <data> is as follows:
+ Most values are encoded in ascii hex digits. Signal numbers are according
+ to the numbering in target.h.
+
+ Request Packet
+
+ set thread Hct... Set thread for subsequent operations.
+ c = 'c' for thread used in step and
+ continue; t... can be -1 for all
+ threads.
+ c = 'g' for thread used in other
+ operations. If zero, pick a thread,
+ any thread.
+ reply OK for success
+ ENN for an error.
+
+ read registers g
+ reply XX....X Each byte of register data
+ is described by two hex digits.
+ Registers are in the internal order
+ for GDB, and the bytes in a register
+ are in the same order the machine uses.
+ or ENN for an error.
+
+ write regs GXX..XX Each byte of register data
+ is described by two hex digits.
+ reply OK for success
+ ENN for an error
+
+ write reg Pn...=r... Write register n... with value r...,
+ which contains two hex digits for each
+ byte in the register (target byte
+ order).
+ reply OK for success
+ ENN for an error
+ (not supported by all stubs).
+
+ read mem mAA..AA,LLLL AA..AA is address, LLLL is length.
+ reply XX..XX XX..XX is mem contents
+ Can be fewer bytes than requested
+ if able to read only part of the data.
+ or ENN NN is errno
+
+ write mem MAA..AA,LLLL:XX..XX
+ AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is data
+ reply OK for success
+ ENN for an error (this includes the case
+ where only part of the data was
+ written).
+
+ write mem XAA..AA,LLLL:XX..XX
+ (binary) AA..AA is address,
+ LLLL is number of bytes,
+ XX..XX is binary data
+ reply OK for success
+ ENN for an error
+
+ continue cAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ step sAA..AA AA..AA is address to resume
+ If AA..AA is omitted,
+ resume at same address.
+
+ continue with Csig;AA..AA Continue with signal sig (hex signal
+ signal number). If ;AA..AA is omitted,
+ resume at same address.
+
+ step with Ssig;AA..AA Like 'C' but step not continue.
+ signal
+
+ last signal ? Reply the current reason for stopping.
+ This is the same reply as is generated
+ for step or cont : SAA where AA is the
+ signal number.
+
+ detach D Reply OK.
+
+ There is no immediate reply to step or cont.
+ The reply comes when the machine stops.
+ It is SAA AA is the signal number.
+
+ or... TAAn...:r...;n...:r...;n...:r...;
+ AA = signal number
+ n... = register number (hex)
+ r... = register contents
+ n... = `thread'
+ r... = thread process ID. This is
+ a hex integer.
+ n... = other string not starting
+ with valid hex digit.
+ gdb should ignore this n,r pair
+ and go on to the next. This way
+ we can extend the protocol.
+ or... WAA The process exited, and AA is
+ the exit status. This is only
+ applicable for certains sorts of
+ targets.
+ or... XAA The process terminated with signal
+ AA.
+ or (obsolete) NAA;tttttttt;dddddddd;bbbbbbbb
+ AA = signal number
+ tttttttt = address of symbol "_start"
+ dddddddd = base of data section
+ bbbbbbbb = base of bss section.
+ Note: only used by Cisco Systems
+ targets. The difference between this
+ reply and the "qOffsets" query is that
+ the 'N' packet may arrive spontaneously
+ whereas the 'qOffsets' is a query
+ initiated by the host debugger.
+ or... OXX..XX XX..XX is hex encoding of ASCII data. This
+ can happen at any time while the
+ program is running and the debugger
+ should continue to wait for
+ 'W', 'T', etc.
+
+ thread alive TXX Find out if the thread XX is alive.
+ reply OK thread is still alive
+ ENN thread is dead
+
+ remote restart RXX Restart the remote server
+
+ extended ops ! Use the extended remote protocol.
+ Sticky -- only needs to be set once.
+
+ kill request k
+
+ toggle debug d toggle debug flag (see 386 & 68k stubs)
+ reset r reset -- see sparc stub.
+ reserved <other> On other requests, the stub should
+ ignore the request and send an empty
+ response ($#<checksum>). This way
+ we can extend the protocol and GDB
+ can tell whether the stub it is
+ talking to uses the old or the new.
+ search tAA:PP,MM Search backwards starting at address
+ AA for a match with pattern PP and
+ mask MM. PP and MM are 4 bytes.
+ Not supported by all stubs.
+
+ general query qXXXX Request info about XXXX.
+ general set QXXXX=yyyy Set value of XXXX to yyyy.
+ query sect offs qOffsets Get section offsets. Reply is
+ Text=xxx;Data=yyy;Bss=zzz
+
+ Responses can be run-length encoded to save space. A '*' means that
+ the next character is an ASCII encoding giving a repeat count which
+ stands for that many repititions of the character preceding the '*'.
+ The encoding is n+29, yielding a printable character where n >=3
+ (which is where rle starts to win). Don't use an n > 126.
+
+ So
+ "0* " means the same as "0000". */
+/* *INDENT-ON* */
+
+/* This variable (available to the user via "set remotebinarydownload")
+ dictates whether downloads are sent in binary (via the 'X' packet).
+ We assume that the stub can, and attempt to do it. This will be cleared if
+ the stub does not understand it. This switch is still needed, though
+ in cases when the packet is supported in the stub, but the connection
+ does not allow it (i.e., 7-bit serial connection only). */
+static int remote_binary_download = 1;
+
+/* Have we already checked whether binary downloads work? */
+static int remote_binary_checked;
+
+/* Maximum number of bytes to read/write at once. The value here
+ is chosen to fill up a packet (the headers account for the 32). */
+#define MAXBUFBYTES(N) (((N)-32)/2)
+
+/* Having this larger than 400 causes us to be incompatible with m68k-stub.c
+ and i386-stub.c. Normally, no one would notice because it only matters
+ for writing large chunks of memory (e.g. in downloads). Also, this needs
+ to be more than 400 if required to hold the registers (see below, where
+ we round it up based on REGISTER_BYTES). */
+/* Round up PBUFSIZ to hold all the registers, at least. */
+#define PBUFSIZ ((REGISTER_BYTES > MAXBUFBYTES (400)) \
+ ? (REGISTER_BYTES * 2 + 32) \
+ : 400)
+
+
+/* This variable sets the number of bytes to be written to the target
+ in a single packet. Normally PBUFSIZ is satisfactory, but some
+ targets need smaller values (perhaps because the receiving end
+ is slow). */
+
+static int remote_write_size = 0x7fffffff;
+
+/* This variable sets the number of bits in an address that are to be
+ sent in a memory ("M" or "m") packet. Normally, after stripping
+ leading zeros, the entire address would be sent. This variable
+ restricts the address to REMOTE_ADDRESS_SIZE bits. HISTORY: The
+ initial implementation of remote.c restricted the address sent in
+ memory packets to ``host::sizeof long'' bytes - (typically 32
+ bits). Consequently, for 64 bit targets, the upper 32 bits of an
+ address was never sent. Since fixing this bug may cause a break in
+ some remote targets this variable is principly provided to
+ facilitate backward compatibility. */
+
+static int remote_address_size;
+
+/* Convert hex digit A to a number. */
+
+static int
+fromhex (int a)
+{
+ if (a >= '0' && a <= '9')
+ return a - '0';
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else {
+ error ("Reply contains invalid hex digit %d", a);
+ return -1;
+ }
+}
+
+/* Convert number NIB to a hex digit. */
+
+static int
+tohex (int nib)
+{
+ if (nib < 10)
+ return '0' + nib;
+ else
+ return 'a' + nib - 10;
+}
+
+/* Return the number of hex digits in num. */
+
+static int
+hexnumlen (ULONGEST num)
+{
+ int i;
+
+ for (i = 0; num != 0; i++)
+ num >>= 4;
+
+ return max (i, 1);
+}
+
+/* Set BUF to the hex digits representing NUM. */
+
+static int
+hexnumstr (char *buf, ULONGEST num)
+{
+ int i;
+ int len = hexnumlen (num);
+
+ buf[len] = '\0';
+
+ for (i = len - 1; i >= 0; i--)
+ {
+ buf[i] = "0123456789abcdef"[(num & 0xf)];
+ num >>= 4;
+ }
+
+ return len;
+}
+
+/* Mask all but the least significant REMOTE_ADDRESS_SIZE bits. */
+
+static CORE_ADDR
+remote_address_masked (CORE_ADDR addr)
+{
+ if (remote_address_size > 0
+ && remote_address_size < (sizeof (ULONGEST) * 8))
+ {
+ /* Only create a mask when that mask can safely be constructed
+ in a ULONGEST variable. */
+ ULONGEST mask = 1;
+ mask = (mask << remote_address_size) - 1;
+ addr &= mask;
+ }
+ return addr;
+}
+
+/* Determine whether the remote target supports binary downloading.
+ This is accomplished by sending a no-op memory write of zero length
+ to the target at the specified address. It does not suffice to send
+ the whole packet, since many stubs strip the eighth bit and subsequently
+ compute a wrong checksum, which causes real havoc with remote_write_bytes.
+
+ NOTE: This can still lose if the serial line is not eight-bit clean. In
+ cases like this, the user should clear "remotebinarydownload". */
+static void
+check_binary_download (CORE_ADDR addr)
+{
+ if (remote_binary_download && !remote_binary_checked)
+ {
+ char *buf = alloca (PBUFSIZ);
+ char *p;
+ remote_binary_checked = 1;
+
+ p = buf;
+ *p++ = 'X';
+ p += hexnumstr (p, (ULONGEST) addr);
+ *p++ = ',';
+ p += hexnumstr (p, (ULONGEST) 0);
+ *p++ = ':';
+ *p = '\0';
+
+ putpkt_binary (buf, (int) (p - buf));
+ getpkt (buf, 0);
+
+ if (buf[0] == '\0')
+ remote_binary_download = 0;
+ }
+
+ if (remote_debug)
+ {
+ if (remote_binary_download)
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading suppported by target\n");
+ else
+ fprintf_unfiltered (gdb_stdlog,
+ "binary downloading NOT suppported by target\n");
+ }
+}
+
+/* Write memory data directly to the remote machine.
+ This does not inform the data cache; the data cache uses this.
+ MEMADDR is the address in the remote memory space.
+ MYADDR is the address of the buffer in our space.
+ LEN is the number of bytes.
+
+ Returns number of bytes transferred, or 0 for error. */
+
+int
+remote_write_bytes (memaddr, myaddr, len)
+ CORE_ADDR memaddr;
+ char *myaddr;
+ int len;
+{
+ unsigned char *buf = alloca (PBUFSIZ);
+ int max_buf_size; /* Max size of packet output buffer */
+ int origlen;
+ extern int verbose;
+
+ /* Verify that the target can support a binary download */
+ check_binary_download (memaddr);
+
+ /* Chop the transfer down if necessary */
+
+ max_buf_size = min (remote_write_size, PBUFSIZ);
+ if (remote_register_buf_size != 0)
+ max_buf_size = min (max_buf_size, remote_register_buf_size);
+
+ /* Subtract header overhead from max payload size - $M<memaddr>,<len>:#nn */
+ max_buf_size -= 2 + hexnumlen (memaddr + len - 1) + 1 + hexnumlen (len) + 4;
+
+ origlen = len;
+ while (len > 0)
+ {
+ unsigned char *p, *plen;
+ int todo;
+ int i;
+
+ /* construct "M"<memaddr>","<len>":" */
+ /* sprintf (buf, "M%lx,%x:", (unsigned long) memaddr, todo); */
+ memaddr = remote_address_masked (memaddr);
+ p = buf;
+ if (remote_binary_download)
+ {
+ *p++ = 'X';
+ todo = min (len, max_buf_size);
+ }
+ else
+ {
+ *p++ = 'M';
+ todo = min (len, max_buf_size / 2); /* num bytes that will fit */
+ }
+
+ p += hexnumstr ((char *)p, (ULONGEST) memaddr);
+ *p++ = ',';
+
+ plen = p; /* remember where len field goes */
+ p += hexnumstr ((char *)p, (ULONGEST) todo);
+ *p++ = ':';
+ *p = '\0';
+
+ /* We send target system values byte by byte, in increasing byte
+ addresses, each byte encoded as two hex characters (or one
+ binary character). */
+ if (remote_binary_download)
+ {
+ int escaped = 0;
+ for (i = 0;
+ (i < todo) && (i + escaped) < (max_buf_size - 2);
+ i++)
+ {
+ switch (myaddr[i] & 0xff)
+ {
+ case '$':
+ case '#':
+ case 0x7d:
+ /* These must be escaped */
+ escaped++;
+ *p++ = 0x7d;
+ *p++ = (myaddr[i] & 0xff) ^ 0x20;
+ break;
+ default:
+ *p++ = myaddr[i] & 0xff;
+ break;
+ }
+ }
+
+ if (i < todo)
+ {
+ /* Escape chars have filled up the buffer prematurely,
+ and we have actually sent fewer bytes than planned.
+ Fix-up the length field of the packet. */
+
+ /* FIXME: will fail if new len is a shorter string than
+ old len. */
+
+ plen += hexnumstr ((char *)plen, (ULONGEST) i);
+ *plen++ = ':';
+ }
+ }
+ else
+ {
+ for (i = 0; i < todo; i++)
+ {
+ *p++ = tohex ((myaddr[i] >> 4) & 0xf);
+ *p++ = tohex (myaddr[i] & 0xf);
+ }
+ *p = '\0';
+ }
+
+ putpkt_binary ((char *)buf, (int) (p - buf));
+ getpkt ((char *)buf, 0);
+
+ if (buf[0] == 'E')
+ {
+ /* There is no correspondance between what the remote protocol uses
+ for errors and errno codes. We would like a cleaner way of
+ representing errors (big enough to include errno codes, bfd_error
+ codes, and others). But for now just return EIO. */
+ errno = EIO;
+ return 0;
+ }
+
+ /* Increment by i, not by todo, in case escape chars
+ caused us to send fewer bytes than we'd planned. */
+ myaddr += i;
+ memaddr += i;
+ len -= i;
+
+ if (verbose)
+ putc('.', stderr);
+ }
+ return origlen;
+}
+
+/* Stuff for dealing with the packets which are part of this protocol.
+ See comment at top of file for details. */
+
+/* Read a single character from the remote end, masking it down to 7 bits. */
+
+static int
+readchar (int timeout)
+{
+ int ch;
+
+ ch = SERIAL_READCHAR (remote_desc, timeout);
+
+ switch (ch)
+ {
+ case SERIAL_EOF:
+ error ("Remote connection closed");
+ case SERIAL_ERROR:
+ perror_with_name ("Remote communication error");
+ case SERIAL_TIMEOUT:
+ return ch;
+ default:
+ return ch & 0x7f;
+ }
+}
+
+static int
+putpkt (buf)
+ char *buf;
+{
+ return putpkt_binary (buf, strlen (buf));
+}
+
+/* Send a packet to the remote machine, with error checking. The data
+ of the packet is in BUF. The string in BUF can be at most PBUFSIZ - 5
+ to account for the $, # and checksum, and for a possible /0 if we are
+ debugging (remote_debug) and want to print the sent packet as a string */
+
+static int
+putpkt_binary (buf, cnt)
+ char *buf;
+ int cnt;
+{
+ int i;
+ unsigned char csum = 0;
+ char *buf2 = alloca (PBUFSIZ);
+ char *junkbuf = alloca (PBUFSIZ);
+
+ int ch;
+ int tcount = 0;
+ char *p;
+
+ /* Copy the packet into buffer BUF2, encapsulating it
+ and giving it a checksum. */
+
+ if (cnt > BUFSIZ - 5) /* Prosanity check */
+ abort ();
+
+ p = buf2;
+ *p++ = '$';
+
+ for (i = 0; i < cnt; i++)
+ {
+ csum += buf[i];
+ *p++ = buf[i];
+ }
+ *p++ = '#';
+ *p++ = tohex ((csum >> 4) & 0xf);
+ *p++ = tohex (csum & 0xf);
+
+ /* Send it over and over until we get a positive ack. */
+
+ while (1)
+ {
+ int started_error_output = 0;
+
+ if (remote_debug)
+ {
+ *p = '\0';
+ fprintf_unfiltered (gdb_stdlog, "Sending packet: ");
+ fputstrn_unfiltered (buf2, p - buf2, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "...");
+ gdb_flush (gdb_stdlog);
+ }
+ if (SERIAL_WRITE (remote_desc, buf2, p - buf2))
+ perror_with_name ("putpkt: write failed");
+
+ /* read until either a timeout occurs (-2) or '+' is read */
+ while (1)
+ {
+ ch = readchar (remote_timeout);
+
+ if (remote_debug)
+ {
+ switch (ch)
+ {
+ case '+':
+ case SERIAL_TIMEOUT:
+ case '$':
+ if (started_error_output)
+ {
+ putchar_unfiltered ('\n');
+ started_error_output = 0;
+ }
+ }
+ }
+
+ switch (ch)
+ {
+ case '+':
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "Ack\n");
+ return 1;
+ case SERIAL_TIMEOUT:
+ tcount++;
+ if (tcount > 3)
+ return 0;
+ break; /* Retransmit buffer */
+ case '$':
+ {
+ /* It's probably an old response, and we're out of sync.
+ Just gobble up the packet and ignore it. */
+ getpkt (junkbuf, 0);
+ continue; /* Now, go look for + */
+ }
+ default:
+ if (remote_debug)
+ {
+ if (!started_error_output)
+ {
+ started_error_output = 1;
+ fprintf_unfiltered (gdb_stdlog, "putpkt: Junk: ");
+ }
+ fputc_unfiltered (ch & 0177, gdb_stdlog);
+ }
+ continue;
+ }
+ break; /* Here to retransmit */
+ }
+
+#if 0
+ /* This is wrong. If doing a long backtrace, the user should be
+ able to get out next time we call QUIT, without anything as
+ violent as interrupt_query. If we want to provide a way out of
+ here without getting to the next QUIT, it should be based on
+ hitting ^C twice as in remote_wait. */
+ if (quit_flag)
+ {
+ quit_flag = 0;
+ interrupt_query ();
+ }
+#endif
+ }
+}
+
+/* Come here after finding the start of the frame. Collect the rest
+ into BUF, verifying the checksum, length, and handling run-length
+ compression. Returns 0 on any error, 1 on success. */
+
+static int
+read_frame (char *buf)
+{
+ unsigned char csum;
+ char *bp;
+ int c;
+
+ csum = 0;
+ bp = buf;
+
+ while (1)
+ {
+ c = readchar (remote_timeout);
+
+ switch (c)
+ {
+ case SERIAL_TIMEOUT:
+ if (remote_debug)
+ fputs_filtered ("Timeout in mid-packet, retrying\n", gdb_stdlog);
+ return 0;
+ case '$':
+ if (remote_debug)
+ fputs_filtered ("Saw new packet start in middle of old one\n",
+ gdb_stdlog);
+ return 0; /* Start a new packet, count retries */
+ case '#':
+ {
+ unsigned char pktcsum;
+
+ *bp = '\000';
+
+ pktcsum = fromhex (readchar (remote_timeout)) << 4;
+ pktcsum |= fromhex (readchar (remote_timeout));
+
+ if (csum == pktcsum)
+ {
+ return 1;
+ }
+
+ if (remote_debug)
+ {
+ fprintf_filtered (gdb_stdlog,
+ "Bad checksum, sentsum=0x%x, csum=0x%x, buf=",
+ pktcsum, csum);
+ fputs_filtered (buf, gdb_stdlog);
+ fputs_filtered ("\n", gdb_stdlog);
+ }
+ return 0;
+ }
+ case '*': /* Run length encoding */
+ csum += c;
+ c = readchar (remote_timeout);
+ csum += c;
+ c = c - ' ' + 3; /* Compute repeat count */
+
+ if (c > 0 && c < 255 && bp + c - 1 < buf + PBUFSIZ - 1)
+ {
+ memset (bp, *(bp - 1), c);
+ bp += c;
+ continue;
+ }
+
+ *bp = '\0';
+ printf_filtered ("Repeat count %d too large for buffer: ", c);
+ puts_filtered (buf);
+ puts_filtered ("\n");
+ return 0;
+ default:
+ if (bp < buf + PBUFSIZ - 1)
+ {
+ *bp++ = c;
+ csum += c;
+ continue;
+ }
+
+ *bp = '\0';
+ puts_filtered ("Remote packet too long: ");
+ puts_filtered (buf);
+ puts_filtered ("\n");
+
+ return 0;
+ }
+ }
+}
+
+/* Read a packet from the remote machine, with error checking, and
+ store it in BUF. BUF is expected to be of size PBUFSIZ. If
+ FOREVER, wait forever rather than timing out; this is used while
+ the target is executing user code. */
+
+static void
+getpkt (buf, forever)
+ char *buf;
+ int forever;
+{
+ int c;
+ int tries;
+ int timeout;
+ int val;
+
+ strcpy (buf, "timeout");
+
+ if (forever)
+ {
+ timeout = watchdog > 0 ? watchdog : -1;
+ }
+
+ else
+ timeout = remote_timeout;
+
+#define MAX_TRIES 3
+
+ for (tries = 1; tries <= MAX_TRIES; tries++)
+ {
+ /* This can loop forever if the remote side sends us characters
+ continuously, but if it pauses, we'll get a zero from readchar
+ because of timeout. Then we'll count that as a retry. */
+
+ /* Note that we will only wait forever prior to the start of a packet.
+ After that, we expect characters to arrive at a brisk pace. They
+ should show up within remote_timeout intervals. */
+
+ do
+ {
+ c = readchar (timeout);
+
+ if (c == SERIAL_TIMEOUT)
+ {
+ if (forever) /* Watchdog went off. Kill the target. */
+ {
+ target_mourn_inferior ();
+ error ("Watchdog has expired. Target detached.\n");
+ }
+ if (remote_debug)
+ fputs_filtered ("Timed out.\n", gdb_stdlog);
+ goto retry;
+ }
+ }
+ while (c != '$');
+
+ /* We've found the start of a packet, now collect the data. */
+
+ val = read_frame (buf);
+
+ if (val == 1)
+ {
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog, "Packet received: ");
+ fputstr_unfiltered (buf, 0, gdb_stdlog);
+ fprintf_unfiltered (gdb_stdlog, "\n");
+ }
+ SERIAL_WRITE (remote_desc, "+", 1);
+ return;
+ }
+
+ /* Try the whole thing again. */
+ retry:
+ SERIAL_WRITE (remote_desc, "-", 1);
+ }
+
+ /* We have tried hard enough, and just can't receive the packet. Give up. */
+
+ printf_unfiltered ("Ignoring packet error, continuing...\n");
+ SERIAL_WRITE (remote_desc, "+", 1);
+}
diff --git a/tools/gdb/remote.h b/tools/gdb/remote.h
new file mode 100644
index 0000000..f14dacb
--- /dev/null
+++ b/tools/gdb/remote.h
@@ -0,0 +1,28 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+extern int remote_desc, remote_timeout;
+
+extern void remote_reset(void);
+extern void remote_continue(void);
+extern int remote_write_bytes(unsigned long, char *, int);
diff --git a/tools/gdb/serial.c b/tools/gdb/serial.c
new file mode 100644
index 0000000..2f2e529
--- /dev/null
+++ b/tools/gdb/serial.c
@@ -0,0 +1,149 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include "serial.h"
+
+#if defined(__sun__) || \
+ defined(__OpenBSD__) || \
+ defined(__FreeBSD__) || \
+ defined(__NetBSD__) || \
+ defined(__APPLE__)
+static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0, { 0 } };
+#else
+static struct termios tios = { BRKINT, 0, B115200|CS8|CREAD, 0, 0 };
+#endif
+
+static struct speedmap {
+ char *str;
+ speed_t val;
+} speedmap[] = {
+ { "50", B50 }, { "75", B75 }, { "110", B110 },
+ { "134", B134 }, { "150", B150 }, { "200", B200 },
+ { "300", B300 }, { "600", B600 }, { "1200", B1200 },
+ { "1800", B1800 }, { "2400", B2400 }, { "4800", B4800 },
+ { "9600", B9600 }, { "19200", B19200 }, { "38400", B38400 },
+ { "57600", B57600 },
+#ifdef B76800
+ { "76800", B76800 },
+#endif
+ { "115200", B115200 },
+#ifdef B153600
+ { "153600", B153600 },
+#endif
+ { "230400", B230400 },
+#ifdef B307200
+ { "307200", B307200 },
+#endif
+#ifdef B460800
+ { "460800", B460800 }
+#endif
+};
+static int nspeeds = sizeof speedmap / sizeof speedmap[0];
+
+speed_t
+cvtspeed(char *str)
+{
+ struct speedmap *smp = speedmap, *esmp = &speedmap[nspeeds];
+
+ while (smp < esmp) {
+ if (strcmp(str, smp->str) == 0)
+ return (smp->val);
+ smp++;
+ }
+ return B0;
+}
+
+int
+serialopen(char *device, speed_t speed)
+{
+ int fd;
+
+ if (cfsetospeed(&tios, speed) < 0)
+ return -1;
+
+ if ((fd = open(device, O_RDWR)) < 0)
+ return -1;
+
+ if (tcsetattr(fd, TCSAFLUSH, &tios) < 0) {
+ (void)close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+int
+serialreadchar(int fd, int timeout)
+{
+ fd_set fds;
+ struct timeval tv;
+ int n;
+ char ch;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+
+ /* this is a fucking horrible quick hack - fix this */
+
+ if ((n = select(fd + 1, &fds, 0, 0, &tv)) < 0)
+ return SERIAL_ERROR;
+
+ if (n == 0)
+ return SERIAL_TIMEOUT;
+
+ if ((n = read(fd, &ch, 1)) < 0)
+ return SERIAL_ERROR;
+
+ if (n == 0)
+ return SERIAL_EOF;
+
+ return ch;
+}
+
+int
+serialwrite(int fd, char *buf, int len)
+{
+ int n;
+
+ do {
+ n = write(fd, buf, len);
+ if (n < 0)
+ return 1;
+ len -= n;
+ buf += n;
+ } while (len > 0);
+ return 0;
+}
+
+int
+serialclose(int fd)
+{
+ return close(fd);
+}
diff --git a/tools/gdb/serial.h b/tools/gdb/serial.h
new file mode 100644
index 0000000..3ed509e
--- /dev/null
+++ b/tools/gdb/serial.h
@@ -0,0 +1,34 @@
+/*
+ * (C) Copyright 2000
+ * Murray Jensen <Murray.Jensen@csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <termios.h>
+
+#define SERIAL_ERROR -1 /* General error, see errno for details */
+#define SERIAL_TIMEOUT -2
+#define SERIAL_EOF -3
+
+extern speed_t cvtspeed(char *);
+extern int serialopen(char *, speed_t);
+extern int serialreadchar(int, int);
+extern int serialwrite(int, char *, int);
+extern int serialclose(int);
diff --git a/tools/gen_eth_addr.c b/tools/gen_eth_addr.c
new file mode 100644
index 0000000..429b20d
--- /dev/null
+++ b/tools/gen_eth_addr.c
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2001
+ * Murray Jensen <Murray.Jensen@cmst.csiro.au>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+
+int
+main(int argc, char *argv[])
+{
+ unsigned long ethaddr_low, ethaddr_high;
+
+ srand(time(0) | getpid());
+
+ /*
+ * setting the 2nd LSB in the most significant byte of
+ * the address makes it a locally administered ethernet
+ * address
+ */
+ ethaddr_high = (rand() & 0xfeff) | 0x0200;
+ ethaddr_low = rand();
+
+ printf("%02lx:%02lx:%02lx:%02lx:%02lx:%02lx\n",
+ ethaddr_high >> 8, ethaddr_high & 0xff,
+ ethaddr_low >> 24, (ethaddr_low >> 16) & 0xff,
+ (ethaddr_low >> 8) & 0xff, ethaddr_low & 0xff);
+
+ return (0);
+}
diff --git a/tools/getline.c b/tools/getline.c
new file mode 100644
index 0000000..3ba52a3
--- /dev/null
+++ b/tools/getline.c
@@ -0,0 +1,101 @@
+/* getline.c -- Replacement for GNU C library function getline
+
+Copyright (C) 1993, 1996, 2001, 2002 Free Software Foundation, Inc.
+
+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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+/* Written by Jan Brittenson, bson@gnu.ai.mit.edu. */
+
+#include <assert.h>
+#include <stdio.h>
+
+/* Always add at least this many bytes when extending the buffer. */
+#define MIN_CHUNK 64
+
+/* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
+ + OFFSET (and null-terminate it). *LINEPTR is a pointer returned from
+ malloc (or NULL), pointing to *N characters of space. It is realloc'd
+ as necessary. Return the number of characters read (not including the
+ null terminator), or -1 on error or EOF.
+ NOTE: There is another getstr() function declared in <curses.h>. */
+static int getstr(char **lineptr, size_t *n, FILE *stream,
+ char terminator, size_t offset)
+{
+ int nchars_avail; /* Allocated but unused chars in *LINEPTR. */
+ char *read_pos; /* Where we're reading into *LINEPTR. */
+ int ret;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+
+ if (!*lineptr) {
+ *n = MIN_CHUNK;
+ *lineptr = malloc(*n);
+ if (!*lineptr)
+ return -1;
+ }
+
+ nchars_avail = *n - offset;
+ read_pos = *lineptr + offset;
+
+ for (;;) {
+ register int c = getc(stream);
+
+ /* We always want at least one char left in the buffer, since we
+ always (unless we get an error while reading the first char)
+ NUL-terminate the line buffer. */
+
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ if (nchars_avail < 2) {
+ if (*n > MIN_CHUNK)
+ *n *= 2;
+ else
+ *n += MIN_CHUNK;
+
+ nchars_avail = *n + *lineptr - read_pos;
+ *lineptr = realloc(*lineptr, *n);
+ if (!*lineptr)
+ return -1;
+ read_pos = *n - nchars_avail + *lineptr;
+ assert(*n - nchars_avail == read_pos - *lineptr);
+ }
+
+ if (c == EOF || ferror (stream)) {
+ /* Return partial line, if any. */
+ if (read_pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *read_pos++ = c;
+ nchars_avail--;
+
+ if (c == terminator)
+ /* Return the line. */
+ break;
+ }
+
+ /* Done - NUL terminate and return the number of chars read. */
+ *read_pos = '\0';
+
+ ret = read_pos - (*lineptr + offset);
+ return ret;
+}
+
+int getline (char **lineptr, size_t *n, FILE *stream)
+{
+ return getstr(lineptr, n, stream, '\n', 0);
+}
diff --git a/tools/getline.h b/tools/getline.h
new file mode 100644
index 0000000..a2f35b9
--- /dev/null
+++ b/tools/getline.h
@@ -0,0 +1 @@
+int getline(char **lineptr, size_t *n, FILE *stream);
diff --git a/tools/image-host.c b/tools/image-host.c
new file mode 100644
index 0000000..932384b
--- /dev/null
+++ b/tools/image-host.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <version.h>
+
+/**
+ * fit_set_hash_value - set hash value in requested has node
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: hash value to be set
+ * @value_len: hash value length
+ *
+ * fit_set_hash_value() attempts to set hash value in a node at offset
+ * given and returns operation status to the caller.
+ *
+ * returns
+ * 0, on success
+ * -1, on failure
+ */
+static int fit_set_hash_value(void *fit, int noffset, uint8_t *value,
+ int value_len)
+{
+ int ret;
+
+ ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+ if (ret) {
+ printf("Can't set hash '%s' property for '%s' node(%s)\n",
+ FIT_VALUE_PROP, fit_get_name(fit, noffset, NULL),
+ fdt_strerror(ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_process_hash - Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For hash nodes we generate
+ * a hash of the supplised data and store it in the node.
+ *
+ * @fit: pointer to the FIT format image header
+ * @image_name: name of image being processes (used to display errors)
+ * @noffset: subnode offset
+ * @data: data to process
+ * @size: size of data in bytes
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_hash(void *fit, const char *image_name,
+ int noffset, const void *data, size_t size)
+{
+ uint8_t value[FIT_MAX_HASH_LEN];
+ const char *node_name;
+ int value_len;
+ char *algo;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+
+ if (fit_image_hash_get_algo(fit, noffset, &algo)) {
+ printf("Can't get hash algo property for '%s' hash node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ if (calculate_hash(data, size, algo, value, &value_len)) {
+ printf("Unsupported hash algorithm (%s) for '%s' hash node in '%s' image node\n",
+ algo, node_name, image_name);
+ return -1;
+ }
+
+ if (fit_set_hash_value(fit, noffset, value, value_len)) {
+ printf("Can't set hash value for '%s' hash node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_write_sig() - write the signature to a FIT
+ *
+ * This writes the signature and signer data to the FIT.
+ *
+ * @fit: pointer to the FIT format image header
+ * @noffset: hash node offset
+ * @value: signature value to be set
+ * @value_len: signature value length
+ * @comment: Text comment to write (NULL for none)
+ *
+ * returns
+ * 0, on success
+ * -FDT_ERR_..., on failure
+ */
+static int fit_image_write_sig(void *fit, int noffset, uint8_t *value,
+ int value_len, const char *comment, const char *region_prop,
+ int region_proplen)
+{
+ int string_size;
+ int ret;
+
+ /*
+ * Get the current string size, before we update the FIT and add
+ * more
+ */
+ string_size = fdt_size_dt_strings(fit);
+
+ ret = fdt_setprop(fit, noffset, FIT_VALUE_PROP, value, value_len);
+ if (!ret) {
+ ret = fdt_setprop_string(fit, noffset, "signer-name",
+ "mkimage");
+ }
+ if (!ret) {
+ ret = fdt_setprop_string(fit, noffset, "signer-version",
+ PLAIN_VERSION);
+ }
+ if (comment && !ret)
+ ret = fdt_setprop_string(fit, noffset, "comment", comment);
+ if (!ret)
+ ret = fit_set_timestamp(fit, noffset, time(NULL));
+ if (region_prop && !ret) {
+ uint32_t strdata[2];
+
+ ret = fdt_setprop(fit, noffset, "hashed-nodes",
+ region_prop, region_proplen);
+ strdata[0] = 0;
+ strdata[1] = cpu_to_fdt32(string_size);
+ if (!ret) {
+ ret = fdt_setprop(fit, noffset, "hashed-strings",
+ strdata, sizeof(strdata));
+ }
+ }
+
+ return ret;
+}
+
+static int fit_image_setup_sig(struct image_sign_info *info,
+ const char *keydir, void *fit, const char *image_name,
+ int noffset, const char *require_keys)
+{
+ const char *node_name;
+ char *algo_name;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
+ printf("Can't get algo property for '%s' signature node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ memset(info, '\0', sizeof(*info));
+ info->keydir = keydir;
+ info->keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+ info->fit = fit;
+ info->node_offset = noffset;
+ info->algo = image_get_sig_algo(algo_name);
+ info->require_keys = require_keys;
+ if (!info->algo) {
+ printf("Unsupported signature algorithm (%s) for '%s' signature node in '%s' image node\n",
+ algo_name, node_name, image_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_process_sig- Process a single subnode of the images/ node
+ *
+ * Check each subnode and process accordingly. For signature nodes we
+ * generate a signed hash of the supplised data and store it in the node.
+ *
+ * @keydir: Directory containing keys to use for signing
+ * @keydest: Destination FDT blob to write public keys into
+ * @fit: pointer to the FIT format image header
+ * @image_name: name of image being processes (used to display errors)
+ * @noffset: subnode offset
+ * @data: data to process
+ * @size: size of data in bytes
+ * @comment: Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return 0 if ok, -1 on error
+ */
+static int fit_image_process_sig(const char *keydir, void *keydest,
+ void *fit, const char *image_name,
+ int noffset, const void *data, size_t size,
+ const char *comment, int require_keys)
+{
+ struct image_sign_info info;
+ struct image_region region;
+ const char *node_name;
+ uint8_t *value;
+ uint value_len;
+ int ret;
+
+ if (fit_image_setup_sig(&info, keydir, fit, image_name, noffset,
+ require_keys ? "image" : NULL))
+ return -1;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ region.data = data;
+ region.size = size;
+ ret = info.algo->sign(&info, &region, 1, &value, &value_len);
+ if (ret) {
+ printf("Failed to sign '%s' signature node in '%s' image node: %d\n",
+ node_name, image_name, ret);
+
+ /* We allow keys to be missing */
+ if (ret == -ENOENT)
+ return 0;
+ return -1;
+ }
+
+ ret = fit_image_write_sig(fit, noffset, value, value_len, comment,
+ NULL, 0);
+ if (ret) {
+ printf("Can't write signature for '%s' signature node in '%s' image node: %s\n",
+ node_name, image_name, fdt_strerror(ret));
+ return -1;
+ }
+ free(value);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+ info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+ /* Write the public key into the supplied FDT file */
+ if (keydest && info.algo->add_verify_data(&info, keydest)) {
+ printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+ node_name, image_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * fit_image_add_verification_data() - calculate/set verig. data for image node
+ *
+ * This adds hash and signature values for an component image node.
+ *
+ * All existing hash subnodes are checked, if algorithm property is set to
+ * one of the supported hash algorithms, hash value is computed and
+ * corresponding hash node property is set, for example:
+ *
+ * Input component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ * | - data = [binary data]
+ * o hash@1
+ * |- algo = "sha1"
+ *
+ * Output component image node structure:
+ *
+ * o image@1 (at image_noffset)
+ * | - data = [binary data]
+ * o hash@1
+ * |- algo = "sha1"
+ * |- value = sha1(data)
+ *
+ * For signature details, please see doc/uImage.FIT/signature.txt
+ *
+ * @keydir Directory containing *.key and *.crt files (or NULL)
+ * @keydest FDT Blob to write public keys into (NULL if none)
+ * @fit: Pointer to the FIT format image header
+ * @image_noffset: Requested component image node
+ * @comment: Comment to add to signature nodes
+ * @require_keys: Mark all keys as 'required'
+ * @return: 0 on success, <0 on failure
+ */
+int fit_image_add_verification_data(const char *keydir, void *keydest,
+ void *fit, int image_noffset, const char *comment,
+ int require_keys)
+{
+ const char *image_name;
+ const void *data;
+ size_t size;
+ int noffset;
+
+ /* Get image data and data length */
+ if (fit_image_get_data(fit, image_noffset, &data, &size)) {
+ printf("Can't get image data/size\n");
+ return -1;
+ }
+
+ image_name = fit_get_name(fit, image_noffset, NULL);
+
+ /* Process all hash subnodes of the component image node */
+ for (noffset = fdt_first_subnode(fit, image_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *node_name;
+ int ret = 0;
+
+ /*
+ * Check subnode name, must be equal to "hash" or "signature".
+ * Multiple hash nodes require unique unit node
+ * names, e.g. hash@1, hash@2, signature@1, etc.
+ */
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (!strncmp(node_name, FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME))) {
+ ret = fit_image_process_hash(fit, image_name, noffset,
+ data, size);
+ } else if (IMAGE_ENABLE_SIGN && keydir &&
+ !strncmp(node_name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_image_process_sig(keydir, keydest,
+ fit, image_name, noffset, data, size,
+ comment, require_keys);
+ }
+ if (ret)
+ return -1;
+ }
+
+ return 0;
+}
+
+struct strlist {
+ int count;
+ char **strings;
+};
+
+static void strlist_init(struct strlist *list)
+{
+ memset(list, '\0', sizeof(*list));
+}
+
+static void strlist_free(struct strlist *list)
+{
+ int i;
+
+ for (i = 0; i < list->count; i++)
+ free(list->strings[i]);
+ free(list->strings);
+}
+
+static int strlist_add(struct strlist *list, const char *str)
+{
+ char *dup;
+
+ dup = strdup(str);
+ list->strings = realloc(list->strings,
+ (list->count + 1) * sizeof(char *));
+ if (!list || !str)
+ return -1;
+ list->strings[list->count++] = dup;
+
+ return 0;
+}
+
+static const char *fit_config_get_image_list(void *fit, int noffset,
+ int *lenp, int *allow_missingp)
+{
+ static const char default_list[] = FIT_KERNEL_PROP "\0"
+ FIT_FDT_PROP;
+ const char *prop;
+
+ /* If there is an "image" property, use that */
+ prop = fdt_getprop(fit, noffset, "sign-images", lenp);
+ if (prop) {
+ *allow_missingp = 0;
+ return *lenp ? prop : NULL;
+ }
+
+ /* Default image list */
+ *allow_missingp = 1;
+ *lenp = sizeof(default_list);
+
+ return default_list;
+}
+
+static int fit_config_get_hash_list(void *fit, int conf_noffset,
+ int sig_offset, struct strlist *node_inc)
+{
+ int allow_missing;
+ const char *prop, *iname, *end;
+ const char *conf_name, *sig_name;
+ char name[200], path[200];
+ int image_count;
+ int ret, len;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+ sig_name = fit_get_name(fit, sig_offset, NULL);
+
+ /*
+ * Build a list of nodes we need to hash. We always need the root
+ * node and the configuration.
+ */
+ strlist_init(node_inc);
+ snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH, conf_name);
+ if (strlist_add(node_inc, "/") ||
+ strlist_add(node_inc, name))
+ goto err_mem;
+
+ /* Get a list of images that we intend to sign */
+ prop = fit_config_get_image_list(fit, conf_noffset, &len,
+ &allow_missing);
+ if (!prop)
+ return 0;
+
+ /* Locate the images */
+ end = prop + len;
+ image_count = 0;
+ for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+ int noffset;
+ int image_noffset;
+ int hash_count;
+
+ image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+ iname);
+ if (image_noffset < 0) {
+ printf("Failed to find image '%s' in configuration '%s/%s'\n",
+ iname, conf_name, sig_name);
+ if (allow_missing)
+ continue;
+
+ return -ENOENT;
+ }
+
+ ret = fdt_get_path(fit, image_noffset, path, sizeof(path));
+ if (ret < 0)
+ goto err_path;
+ if (strlist_add(node_inc, path))
+ goto err_mem;
+
+ snprintf(name, sizeof(name), "%s/%s", FIT_CONFS_PATH,
+ conf_name);
+
+ /* Add all this image's hashes */
+ hash_count = 0;
+ for (noffset = fdt_first_subnode(fit, image_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *name = fit_get_name(fit, noffset, NULL);
+
+ if (strncmp(name, FIT_HASH_NODENAME,
+ strlen(FIT_HASH_NODENAME)))
+ continue;
+ ret = fdt_get_path(fit, noffset, path, sizeof(path));
+ if (ret < 0)
+ goto err_path;
+ if (strlist_add(node_inc, path))
+ goto err_mem;
+ hash_count++;
+ }
+
+ if (!hash_count) {
+ printf("Failed to find any hash nodes in configuration '%s/%s' image '%s' - without these it is not possible to verify this image\n",
+ conf_name, sig_name, iname);
+ return -ENOMSG;
+ }
+
+ image_count++;
+ }
+
+ if (!image_count) {
+ printf("Failed to find any images for configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMSG;
+ }
+
+ return 0;
+
+err_mem:
+ printf("Out of memory processing configuration '%s/%s'\n", conf_name,
+ sig_name);
+ return -ENOMEM;
+
+err_path:
+ printf("Failed to get path for image '%s' in configuration '%s/%s': %s\n",
+ iname, conf_name, sig_name, fdt_strerror(ret));
+ return -ENOENT;
+}
+
+static int fit_config_get_data(void *fit, int conf_noffset, int noffset,
+ struct image_region **regionp, int *region_countp,
+ char **region_propp, int *region_proplen)
+{
+ char * const exc_prop[] = {"data"};
+ struct strlist node_inc;
+ struct image_region *region;
+ struct fdt_region fdt_regions[100];
+ const char *conf_name, *sig_name;
+ char path[200];
+ int count, i;
+ char *region_prop;
+ int ret, len;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+ sig_name = fit_get_name(fit, conf_noffset, NULL);
+ debug("%s: conf='%s', sig='%s'\n", __func__, conf_name, sig_name);
+
+ /* Get a list of nodes we want to hash */
+ ret = fit_config_get_hash_list(fit, conf_noffset, noffset, &node_inc);
+ if (ret)
+ return ret;
+
+ /* Get a list of regions to hash */
+ count = fdt_find_regions(fit, node_inc.strings, node_inc.count,
+ exc_prop, ARRAY_SIZE(exc_prop),
+ fdt_regions, ARRAY_SIZE(fdt_regions),
+ path, sizeof(path), 1);
+ if (count < 0) {
+ printf("Failed to hash configuration '%s/%s': %s\n", conf_name,
+ sig_name, fdt_strerror(ret));
+ return -EIO;
+ }
+ if (count == 0) {
+ printf("No data to hash for configuration '%s/%s': %s\n",
+ conf_name, sig_name, fdt_strerror(ret));
+ return -EINVAL;
+ }
+
+ /* Build our list of data blocks */
+ region = fit_region_make_list(fit, fdt_regions, count, NULL);
+ if (!region) {
+ printf("Out of memory hashing configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMEM;
+ }
+
+ /* Create a list of all hashed properties */
+ debug("Hash nodes:\n");
+ for (i = len = 0; i < node_inc.count; i++) {
+ debug(" %s\n", node_inc.strings[i]);
+ len += strlen(node_inc.strings[i]) + 1;
+ }
+ region_prop = malloc(len);
+ if (!region_prop) {
+ printf("Out of memory setting up regions for configuration '%s/%s'\n",
+ conf_name, sig_name);
+ return -ENOMEM;
+ }
+ for (i = len = 0; i < node_inc.count;
+ len += strlen(node_inc.strings[i]) + 1, i++)
+ strcpy(region_prop + len, node_inc.strings[i]);
+ strlist_free(&node_inc);
+
+ *region_countp = count;
+ *regionp = region;
+ *region_propp = region_prop;
+ *region_proplen = len;
+
+ return 0;
+}
+
+static int fit_config_process_sig(const char *keydir, void *keydest,
+ void *fit, const char *conf_name, int conf_noffset,
+ int noffset, const char *comment, int require_keys)
+{
+ struct image_sign_info info;
+ const char *node_name;
+ struct image_region *region;
+ char *region_prop;
+ int region_proplen;
+ int region_count;
+ uint8_t *value;
+ uint value_len;
+ int ret;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (fit_config_get_data(fit, conf_noffset, noffset, &region,
+ &region_count, &region_prop, &region_proplen))
+ return -1;
+
+ if (fit_image_setup_sig(&info, keydir, fit, conf_name, noffset,
+ require_keys ? "conf" : NULL))
+ return -1;
+
+ ret = info.algo->sign(&info, region, region_count, &value, &value_len);
+ free(region);
+ if (ret) {
+ printf("Failed to sign '%s' signature node in '%s' conf node\n",
+ node_name, conf_name);
+
+ /* We allow keys to be missing */
+ if (ret == -ENOENT)
+ return 0;
+ return -1;
+ }
+
+ if (fit_image_write_sig(fit, noffset, value, value_len, comment,
+ region_prop, region_proplen)) {
+ printf("Can't write signature for '%s' signature node in '%s' conf node\n",
+ node_name, conf_name);
+ return -1;
+ }
+ free(value);
+ free(region_prop);
+
+ /* Get keyname again, as FDT has changed and invalidated our pointer */
+ info.keyname = fdt_getprop(fit, noffset, "key-name-hint", NULL);
+
+ /* Write the public key into the supplied FDT file */
+ if (keydest && info.algo->add_verify_data(&info, keydest)) {
+ printf("Failed to add verification data for '%s' signature node in '%s' image node\n",
+ node_name, conf_name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int fit_config_add_verification_data(const char *keydir, void *keydest,
+ void *fit, int conf_noffset, const char *comment,
+ int require_keys)
+{
+ const char *conf_name;
+ int noffset;
+
+ conf_name = fit_get_name(fit, conf_noffset, NULL);
+
+ /* Process all hash subnodes of the configuration node */
+ for (noffset = fdt_first_subnode(fit, conf_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ const char *node_name;
+ int ret = 0;
+
+ node_name = fit_get_name(fit, noffset, NULL);
+ if (!strncmp(node_name, FIT_SIG_NODENAME,
+ strlen(FIT_SIG_NODENAME))) {
+ ret = fit_config_process_sig(keydir, keydest,
+ fit, conf_name, conf_noffset, noffset, comment,
+ require_keys);
+ }
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int fit_add_verification_data(const char *keydir, void *keydest, void *fit,
+ const char *comment, int require_keys)
+{
+ int images_noffset, confs_noffset;
+ int noffset;
+ int ret;
+
+ /* Find images parent node offset */
+ images_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH);
+ if (images_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(images_noffset));
+ return images_noffset;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (noffset = fdt_first_subnode(fit, images_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ /*
+ * Direct child node of the images parent node,
+ * i.e. component image node.
+ */
+ ret = fit_image_add_verification_data(keydir, keydest,
+ fit, noffset, comment, require_keys);
+ if (ret)
+ return ret;
+ }
+
+ /* If there are no keys, we can't sign configurations */
+ if (!IMAGE_ENABLE_SIGN || !keydir)
+ return 0;
+
+ /* Find configurations parent node offset */
+ confs_noffset = fdt_path_offset(fit, FIT_CONFS_PATH);
+ if (confs_noffset < 0) {
+ printf("Can't find images parent node '%s' (%s)\n",
+ FIT_IMAGES_PATH, fdt_strerror(confs_noffset));
+ return -ENOENT;
+ }
+
+ /* Process its subnodes, print out component images details */
+ for (noffset = fdt_first_subnode(fit, confs_noffset);
+ noffset >= 0;
+ noffset = fdt_next_subnode(fit, noffset)) {
+ ret = fit_config_add_verification_data(keydir, keydest,
+ fit, noffset, comment,
+ require_keys);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/tools/img2brec.sh b/tools/img2brec.sh
new file mode 100755
index 0000000..0fcdba2
--- /dev/null
+++ b/tools/img2brec.sh
@@ -0,0 +1,388 @@
+#!/bin/sh
+
+# This script converts binary files (u-boot.bin) into so called
+# bootstrap records that are accepted by Motorola's MC9328MX1/L
+# (a.k.a. DragaonBall i.MX) in "Bootstrap Mode"
+#
+# The code for the SynchFlash programming routines is taken from
+# Bootloader\Bin\SyncFlash\programBoot_b.txt contained in
+# Motorolas LINUX_BSP_0_3_8.tar.gz
+#
+# The script could easily extended for AMD flash routines.
+#
+# 2004-06-23 - steven.scholz@imc-berlin.de
+
+#################################################################################
+# From the posting to the U-Boot-Users mailing list, 23 Jun 2004:
+# ===============================================================
+# I just hacked a simple script that converts u-boot.bin into a text file
+# containg processor init code, SynchFlash programming code and U-Boot data in
+# form of so called b-records.
+#
+# This can be used to programm U-Boot into (Synch)Flash using the Bootstrap
+# Mode of the MC9328MX1/L
+#
+# 0AFE1F3410202E2E2E000000002073756363656564/
+# 0AFE1F44102E0A0000206661696C656420210A0000/
+# 0AFE100000
+# ...
+# MX1ADS Sync-flash Programming Utility v0.5 2002/08/21
+#
+# Source address (stored in 0x0AFE0000): 0x0A000000
+# Target address (stored in 0x0AFE0004): 0x0C000000
+# Size (stored in 0x0AFE0008): 0x0001A320
+#
+# Press any key to start programming ...
+# Erasing ...
+# Blank checking ...
+# Programming ...
+# Verifying flash ... succeed.
+#
+# Programming finished.
+#
+# So no need for a BDI2000 anymore... ;-)
+#
+# This is working on my MX1ADS eval board. Hope this could be useful for
+# someone.
+#################################################################################
+
+if [ "$#" -lt 1 -o "$#" -gt 2 ] ; then
+ echo "Usage: $0 infile [outfile]" >&2
+ echo " $0 u-boot.bin [u-boot.brec]" >&2
+ exit 1
+fi
+
+if [ "$#" -ge 1 ] ; then
+ INFILE=$1
+fi
+
+if [ ! -f $INFILE ] ; then
+ echo "Error: file '$INFILE' does not exist." >&2
+ exit 1
+fi
+
+FILESIZE=`filesize $INFILE`
+
+output_init()
+{
+echo "\
+********************************************
+* Initialize I/O Pad Driving Strength *
+********************************************
+0021B80CC4000003AB
+********************************************
+* Initialize SDRAM *
+********************************************
+00221000C492120200 ; pre-charge command
+08200000E4 ; special read
+
+00221000C4A2120200 ; auto-refresh command
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+08000000E4 ; 8 special read
+
+00221000C4B2120200 ; set mode register
+08111800E4 ; special read
+
+00221000C482124200 ; set normal mode
+ "
+}
+
+output_uboot()
+{
+echo "\
+********************************************
+* U-Boot image as bootstrap records *
+* will be stored in SDRAM at 0x0A000000 *
+********************************************
+ "
+
+cat $INFILE | \
+hexdump -v -e "\"0A0%05.5_ax10\" 16/1 \"%02x\"\"\r\n\"" | \
+tr [:lower:] [:upper:]
+}
+
+output_flashprog()
+{
+echo "\
+********************************************
+* Address of arguments to flashProg *
+* ---------------------------------------- *
+* Source : 0x0A000000 *
+* Destination : 0x0C000000 * "
+
+# get the real size of the U-Boot image
+printf "* Size : 0x%08X *\r\n" $FILESIZE
+printf "********************************************\r\n"
+printf "0AFE0000CC0A0000000C000000%08X\r\n" $FILESIZE
+
+#;0AFE0000CC0A0000000C00000000006000
+
+echo "\
+********************************************
+* Flash Program *
+********************************************
+0AFE10001008D09FE5AC0000EA00F0A0E1A42DFE0A
+0AFE1010100080FE0A0DC0A0E100D82DE904B04CE2
+0AFE1020109820A0E318309FE5003093E5033082E0
+0AFE103010003093E5013003E2FF3003E20300A0E1
+0AFE10401000A81BE9A01DFE0A0DC0A0E100D82DE9
+0AFE10501004B04CE204D04DE20030A0E10D304BE5
+0AFE1060109820A0E330309FE5003093E5033082E0
+0AFE107010003093E5013903E2000053E3F7FFFF0A
+0AFE1080104020A0E310309FE5003093E5032082E0
+0AFE1090100D305BE5003082E500A81BE9A01DFE0A
+0AFE10A0100DC0A0E100D82DE904B04CE20000A0E1
+0AFE10B010D7FFFFEB0030A0E1FF3003E2000053E3
+0AFE10C010FAFFFF0A10309FE5003093E5003093E5
+0AFE10D010FF3003E20300A0E100A81BE9A01DFE0A
+0AFE10E0100DC0A0E100D82DE904B04CE204D04DE2
+0AFE10F0100030A0E10D304BE50D305BE52332A0E1
+0AFE1100100E304BE50E305BE5090053E30300009A
+0AFE1110100E305BE5373083E20E304BE5020000EA
+0AFE1120100E305BE5303083E20E304BE50E305BE5
+0AFE1130100300A0E1C3FFFFEB0D305BE50F3003E2
+0AFE1140100E304BE50E305BE5090053E30300009A
+0AFE1150100E305BE5373083E20E304BE5020000EA
+0AFE1160100E305BE5303083E20E304BE50E305BE5
+0AFE1170100300A0E1B3FFFFEB00A81BE90DC0A0E1
+0AFE11801000D82DE904B04CE21CD04DE210000BE5
+0AFE11901014100BE518200BE588009FE5E50200EB
+0AFE11A01010301BE51C300BE514301BE520300BE5
+0AFE11B0100030A0E324300BE524201BE518301BE5
+0AFE11C010030052E10000003A120000EA1C004BE2
+0AFE11D010002090E520104BE2003091E500C093E5
+0AFE11E010043083E2003081E5003092E5042082E2
+0AFE11F010002080E50C0053E10200000A0030A0E3
+0AFE12001028300BE5050000EA24301BE5043083E2
+0AFE12101024300BE5E7FFFFEA0130A0E328300BE5
+0AFE12201028001BE500A81BE9E81EFE0A0DC0A0E1
+0AFE12301000D82DE904B04CE214D04DE210000BE5
+0AFE12401014100BE56C009FE5BA0200EB10301BE5
+0AFE12501018300BE50030A0E31C300BE51C201BE5
+0AFE12601014301BE5030052E10000003A0D0000EA
+0AFE12701018304BE2002093E5001092E5042082E2
+0AFE128010002083E5010071E30200000A0030A0E3
+0AFE12901020300BE5050000EA1C301BE5043083E2
+0AFE12A0101C300BE5ECFFFFEA0130A0E320300BE5
+0AFE12B01020001BE500A81BE9001FFE0A0DC0A0E1
+0AFE12C01000D82DE904B04CE224D04DE20130A0E3
+0AFE12D01024300BE5A4229FE58139A0E3023A83E2
+0AFE12E010003082E59820A0E390329FE5003093E5
+0AFE12F010033082E0003093E5023903E2000053E3
+0AFE1300100300001A74229FE58139A0E3033A83E2
+0AFE131010003082E568029FE5860200EBAF36A0E3
+0AFE1320100E3883E2003093E510300BE554029FE5
+0AFE133010800200EB10301BE5233CA0E1FF3003E2
+0AFE1340100300A0E165FFFFEB10301BE52338A0E1
+0AFE135010FF3003E20300A0E160FFFFEB10301BE5
+0AFE1360102334A0E1FF3003E20300A0E15BFFFFEB
+0AFE13701010305BE50300A0E158FFFFEB0A00A0E3
+0AFE13801030FFFFEB0D00A0E32EFFFFEBAF36A0E3
+0AFE1390100E3883E2043083E2003093E514300BE5
+0AFE13A010E4019FE5630200EB14301BE5233CA0E1
+0AFE13B010FF3003E20300A0E148FFFFEB14301BE5
+0AFE13C0102338A0E1FF3003E20300A0E143FFFFEB
+0AFE13D01014301BE52334A0E1FF3003E20300A0E1
+0AFE13E0103EFFFFEB14305BE50300A0E13BFFFFEB
+0AFE13F0100A00A0E313FFFFEB0D00A0E311FFFFEB
+0AFE140010AF36A0E30E3883E2083083E2003093E5
+0AFE14101018300BE574019FE5460200EB18301BE5
+0AFE142010233CA0E1FF3003E20300A0E12BFFFFEB
+0AFE14301018301BE52338A0E1FF3003E20300A0E1
+0AFE14401026FFFFEB18301BE52334A0E1FF3003E2
+0AFE1450100300A0E121FFFFEB18305BE50300A0E1
+0AFE1460101EFFFFEB0A00A0E3F6FEFFEB0D00A0E3
+0AFE147010F4FEFFEBE6FEFFEB0030A0E1FF3003E2
+0AFE148010000053E30000001A020000EA03FFFFEB
+0AFE1490102D004BE5F6FFFFEAF4009FE5250200EB
+0AFE14A010FEFEFFEB2D004BE5CD0000EBC00000EB
+0AFE14B010E0009FE51F0200EB18301BE528300BE5
+0AFE14C01014301BE52C300BE52C001BE5100100EB
+0AFE14D01028301BE5013643E228300BE52C301BE5
+0AFE14E010013683E22C300BE528301BE5000053E3
+0AFE14F010F4FFFFCAAE0000EB14001BE518101BE5
+0AFE15001049FFFFEB0030A0E1FF3003E2000053E3
+0AFE151010E6FFFF0A80009FE5060200EB10001BE5
+0AFE15201014101BE518201BE5D00000EB10001BE5
+0AFE15301014101BE518201BE50FFFFFEB0030A0E1
+0AFE154010FF3003E2000053E30200000A4C009FE5
+0AFE155010F80100EB010000EA44009FE5F50100EB
+0AFE156010930000EB3C009FE5F20100EB0000A0E3
+0AFE157010A4FEFFEB0030A0E30300A0E100A81BE9
+0AFE158010A01DFE0AA41DFE0AE01DFE0A0C1EFE0A
+0AFE159010381EFE0A641EFE0A181FFE0A281FFE0A
+0AFE15A0103C1FFE0A481FFE0AB41EFE0A0DC0A0E1
+0AFE15B01000D82DE904B04CE204D04DE210000BE5
+0AFE15C01010301BE5013043E210300BE5010073E3
+0AFE15D010FAFFFF1A00A81BE90DC0A0E100D82DE9
+0AFE15E01004B04CE208D04DE210000BE510301BE5
+0AFE15F01014300BE514301BE50300A0E100A81BE9
+0AFE1600100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1610102228A0E3012A82E2042082E2E134A0E3
+0AFE162010023883E2033C83E2003082E50333A0E3
+0AFE163010053983E2003093E510300BE500A81BE9
+0AFE1640100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1650102228A0E3012A82E2042082E29134A0E3
+0AFE166010023883E2033C83E2003082E5C136A0E3
+0AFE167010003093E510300BE52228A0E3012A82E2
+0AFE168010042082E2E134A0E3023883E2033C83E2
+0AFE169010003082E50333A0E3073983E20020A0E3
+0AFE16A010002083E52228A0E3012A82E2042082E2
+0AFE16B0108134A0E3023883E2033C83E2003082E5
+0AFE16C0100333A0E3003093E510300BE5CBFFFFEB
+0AFE16D01010301BE50300A0E100A81BE90DC0A0E1
+0AFE16E01000D82DE904B04CE208D04DE2D3FFFFEB
+0AFE16F0100030A0E110300BE510301BE5023503E2
+0AFE170010000053E30500000A10301BE5073703E2
+0AFE171010000053E30100000A10001BE5ADFFFFEB
+0AFE17201010301BE5803003E2000053E30500000A
+0AFE17301010301BE51C3003E2000053E30100000A
+0AFE17401010001BE5A3FFFFEB10201BE50235A0E3
+0AFE175010803083E2030052E10200001A0130A0E3
+0AFE17601014300BE5010000EA0030A0E314300BE5
+0AFE17701014001BE500A81BE90DC0A0E100D82DE9
+0AFE17801004B04CE204D04DE22228A0E3012A82E2
+0AFE179010042082E29134A0E3023883E2033C83E2
+0AFE17A010003082E5C136A0E3003093E510300BE5
+0AFE17B01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE17C010ECFFFFEB2228A0E3012A82E2042082E2
+0AFE17D0108134A0E3023883E2033C83E2003082E5
+0AFE17E01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE17F01004D04DE22228A0E3012A82E2042082E2
+0AFE1800102238A0E3013A83E2043083E2003093E5
+0AFE181010023183E3003082E52228A0E3012A82E2
+0AFE1820102238A0E3013A83E2003093E5023183E3
+0AFE183010003082E5FA0FA0E35BFFFFEB2228A0E3
+0AFE184010012A82E2042082E2B134A0E3023883E2
+0AFE185010033C83E2003082E50333A0E3233983E2
+0AFE186010033B83E2003093E510300BE500A81BE9
+0AFE1870100DC0A0E100D82DE904B04CE21CD04DE2
+0AFE18801010000BE514100BE518200BE50030A0E3
+0AFE1890101C300BE51C201BE518301BE5030052E1
+0AFE18A0100000003A190000EAB2FFFFEB2228A0E3
+0AFE18B010012A82E2042082E2F134A0E3023883E2
+0AFE18C010033C83E2003082E514201BE51C301BE5
+0AFE18D010031082E010201BE51C301BE5033082E0
+0AFE18E010003093E5003081E57BFFFFEB0030A0E1
+0AFE18F010FF3003E2000053E3FAFFFF0AACFFFFEB
+0AFE1900101C301BE5043083E21C300BE5E0FFFFEA
+0AFE19101000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1920100CD04DE210000BE52228A0E3012A82E2
+0AFE193010042082E28134A0E3023883E2033C83E2
+0AFE194010003082E510301BE5003093E514300BE5
+0AFE1950102228A0E3012A82E2042082E29134A0E3
+0AFE196010023883E2033C83E2003082E510301BE5
+0AFE197010003093E518300BE52228A0E3012A82E2
+0AFE198010042082E2E134A0E3023883E2033C83E2
+0AFE199010003082E50229A0E310301BE5032082E0
+0AFE19A0100030A0E3003082E52228A0E3012A82E2
+0AFE19B010042082E28134A0E3023883E2033C83E2
+0AFE19C010003082E510201BE50D3AA0E3D03083E2
+0AFE19D010033883E1003082E53FFFFFEB0030A0E1
+0AFE19E010FF3003E2000053E3FAFFFF0A70FFFFEB
+0AFE19F01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1A00105CFFFFEB2228A0E3012A82E2042082E2
+0AFE1A1010E134A0E3023883E2033C83E2003082E5
+0AFE1A20100333A0E3033983E20020A0E3002083E5
+0AFE1A30102228A0E3012A82E2042082E28134A0E3
+0AFE1A4010023883E2033C83E2003082E50323A0E3
+0AFE1A5010032982E20339A0E3C03083E2033883E1
+0AFE1A6010003082E500A81BE90DC0A0E100D82DE9
+0AFE1A701004B04CE23FFFFFEB2228A0E3012A82E2
+0AFE1A8010042082E2E134A0E3023883E2033C83E2
+0AFE1A9010003082E50333A0E30A3983E20020A0E3
+0AFE1AA010002083E52228A0E3012A82E2042082E2
+0AFE1AB0108134A0E3023883E2033C83E2003082E5
+0AFE1AC0100323A0E30A2982E20339A0E3C03083E2
+0AFE1AD010033883E1003082E500A81BE90DC0A0E1
+0AFE1AE01000D82DE904B04CE28729A0E3222E82E2
+0AFE1AF0108739A0E3223E83E2003093E51E3CC3E3
+0AFE1B0010003082E58729A0E38E2F82E28739A0E3
+0AFE1B10108E3F83E2003093E51E3CC3E3003082E5
+0AFE1B20108139A0E3823D83E20520A0E3002083E5
+0AFE1B30108129A0E3822D82E2042082E20139A0E3
+0AFE1B4010273083E2003082E58139A0E3823D83E2
+0AFE1B50100C3083E20120A0E3002083E58129A0E3
+0AFE1B6010822D82E2102082E22A3DA0E3013083E2
+0AFE1B7010003082E58139A0E3823D83E2243083E2
+0AFE1B80100F20A0E3002083E58139A0E3823D83E2
+0AFE1B9010283083E28A20A0E3002083E58139A0E3
+0AFE1BA010823D83E22C3083E20820A0E3002083E5
+0AFE1BB01000A81BE90DC0A0E100D82DE904B04CE2
+0AFE1BC0108139A0E3823D83E2183083E2003093E5
+0AFE1BD010013003E2FF3003E20300A0E100A81BE9
+0AFE1BE0100DC0A0E100D82DE904B04CE204D04DE2
+0AFE1BF0100030A0E10D304BE58139A0E3823D83E2
+0AFE1C0010183083E2003093E5013903E2000053E3
+0AFE1C1010F8FFFF0A8139A0E3813D83E20D205BE5
+0AFE1C2010002083E50D305BE50A0053E30A00001A
+0AFE1C30108139A0E3823D83E2183083E2003093E5
+0AFE1C4010013903E2000053E3F8FFFF0A8139A0E3
+0AFE1C5010813D83E20D20A0E3002083E500A81BE9
+0AFE1C60100DC0A0E100D82DE904B04CE20000A0E1
+0AFE1C7010CFFFFFEB0030A0E1FF3003E2000053E3
+0AFE1C8010FAFFFF0A8139A0E3023A83E2003093E5
+0AFE1C9010FF3003E20300A0E100A81BE90DC0A0E1
+0AFE1CA01000D82DE904B04CE204D04DE20030A0E1
+0AFE1CB0100D304BE50D305BE52332A0E10E304BE5
+0AFE1CC0100E305BE5090053E30300009A0E305BE5
+0AFE1CD010373083E20E304BE5020000EA0E305BE5
+0AFE1CE010303083E20E304BE50E305BE50300A0E1
+0AFE1CF010BAFFFFEB0D305BE50F3003E20E304BE5
+0AFE1D00100E305BE5090053E30300009A0E305BE5
+0AFE1D1010373083E20E304BE5020000EA0E305BE5
+0AFE1D2010303083E20E304BE50E305BE50300A0E1
+0AFE1D3010AAFFFFEB00A81BE90DC0A0E100D82DE9
+0AFE1D401004B04CE204D04DE210000BE510301BE5
+0AFE1D50100030D3E5000053E30000001A080000EA
+0AFE1D601010104BE2003091E50320A0E10020D2E5
+0AFE1D7010013083E2003081E50200A0E197FFFFEB
+0AFE1D8008F1FFFFEA00A81BE9
+0AFE1DA4100A0D4D58314144532053796E632D666C
+0AFE1DB4106173682050726F6772616D6D696E6720
+0AFE1DC4105574696C6974792076302E3520323030
+0AFE1DD410322F30382F32310A0D000000536F7572
+0AFE1DE41063652061646472657373202873746F72
+0AFE1DF410656420696E2030783041464530303030
+0AFE1E0410293A2030780000005461726765742061
+0AFE1E1410646472657373202873746F7265642069
+0AFE1E24106E2030783041464530303034293A2030
+0AFE1E34107800000053697A652020202020202020
+0AFE1E44102020202873746F72656420696E203078
+0AFE1E54103041464530303038293A203078000000
+0AFE1E6410507265737320616E79206B657920746F
+0AFE1E74102073746172742070726F6772616D6D69
+0AFE1E84106E67202E2E2E00000A0D45726173696E
+0AFE1E94106720666C617368202E2E2E000A0D5072
+0AFE1EA4106F6772616D6D696E67202E2E2E000000
+0AFE1EB4100A0D50726F6772616D6D696E67206669
+0AFE1EC4106E69736865642E0A0D50726573732027
+0AFE1ED410612720746F20636F6E74696E7565202E
+0AFE1EE4102E2E2E000A0D566572696679696E6720
+0AFE1EF410666C617368202E2E2E0000000A0D426C
+0AFE1F0410616E6B20636865636B696E67202E2E2E
+0AFE1F1410000000000A45726173696E67202E2E2E
+0AFE1F2410000000000A50726F6772616D6D696E67
+0AFE1F3410202E2E2E000000002073756363656564
+0AFE1F44102E0A0000206661696C656420210A0000
+0AFE100000
+ "
+}
+
+#########################################################
+
+if [ "$#" -eq 2 ] ; then
+ output_init > $2
+ output_uboot >> $2
+ output_flashprog >> $2
+else
+ output_init;
+ output_uboot;
+ output_flashprog;
+fi
diff --git a/tools/img2srec.c b/tools/img2srec.c
new file mode 100644
index 0000000..ec76964
--- /dev/null
+++ b/tools/img2srec.c
@@ -0,0 +1,372 @@
+/*************************************************************************
+| COPYRIGHT (c) 2000 BY ABATRON AG
+|*************************************************************************
+|
+| PROJECT NAME: Linux Image to S-record Conversion Utility
+| FILENAME : img2srec.c
+|
+| COMPILER : GCC
+|
+| TARGET OS : LINUX / UNIX
+| TARGET HW : -
+|
+| PROGRAMMER : Abatron / RD
+| CREATION : 07.07.00
+|
+|*************************************************************************
+|
+| DESCRIPTION :
+|
+| Utility to convert a Linux Boot Image to S-record:
+| ==================================================
+|
+| This command line utility can be used to convert a Linux boot image
+| (zimage.initrd) to S-Record format used for flash programming.
+| This conversion takes care of the special sections "IMAGE" and INITRD".
+|
+| img2srec [-o offset] image > image.srec
+|
+|
+| Build the utility:
+| ==================
+|
+| To build the utility use GCC as follows:
+|
+| gcc img2srec.c -o img2srec
+|
+|
+|*************************************************************************
+|
+|
+| UPDATES :
+|
+| DATE NAME CHANGES
+| -----------------------------------------------------------
+| Latest update
+|
+| 07.07.00 aba Initial release
+|
+|*************************************************************************/
+
+/*************************************************************************
+| INCLUDES
+|*************************************************************************/
+
+#include "os_support.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <elf.h>
+#include <unistd.h>
+#include <errno.h>
+
+/*************************************************************************
+| FUNCTIONS
+|*************************************************************************/
+
+static char* ExtractHex (uint32_t* value, char* getPtr)
+{
+ uint32_t num;
+ uint32_t digit;
+ uint8_t c;
+
+ while (*getPtr == ' ') getPtr++;
+ num = 0;
+ for (;;) {
+ c = *getPtr;
+ if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
+ else if ((c >= 'A') && (c <= 'F')) digit = (uint32_t)(c - 'A' + 10);
+ else if ((c >= 'a') && (c <= 'f')) digit = (uint32_t)(c - 'a' + 10);
+ else break;
+ num <<= 4;
+ num += digit;
+ getPtr++;
+ } /* for */
+ *value = num;
+ return getPtr;
+} /* ExtractHex */
+
+static char* ExtractDecimal (uint32_t* value, char* getPtr)
+{
+ uint32_t num;
+ uint32_t digit;
+ uint8_t c;
+
+ while (*getPtr == ' ') getPtr++;
+ num = 0;
+ for (;;) {
+ c = *getPtr;
+ if ((c >= '0') && (c <= '9')) digit = (uint32_t)(c - '0');
+ else break;
+ num *= 10;
+ num += digit;
+ getPtr++;
+ } /* for */
+ *value = num;
+ return getPtr;
+} /* ExtractDecimal */
+
+
+static void ExtractNumber (uint32_t* value, char* getPtr)
+{
+ bool neg = false;;
+
+ while (*getPtr == ' ') getPtr++;
+ if (*getPtr == '-') {
+ neg = true;
+ getPtr++;
+ } /* if */
+ if ((*getPtr == '0') && ((*(getPtr+1) == 'x') || (*(getPtr+1) == 'X'))) {
+ getPtr +=2;
+ (void)ExtractHex(value, getPtr);
+ } /* if */
+ else {
+ (void)ExtractDecimal(value, getPtr);
+ } /* else */
+ if (neg) *value = -(*value);
+} /* ExtractNumber */
+
+
+static uint8_t* ExtractWord(uint16_t* value, uint8_t* buffer)
+{
+ uint16_t x;
+ x = (uint16_t)*buffer++;
+ x = (x<<8) + (uint16_t)*buffer++;
+ *value = x;
+ return buffer;
+} /* ExtractWord */
+
+
+static uint8_t* ExtractLong(uint32_t* value, uint8_t* buffer)
+{
+ uint32_t x;
+ x = (uint32_t)*buffer++;
+ x = (x<<8) + (uint32_t)*buffer++;
+ x = (x<<8) + (uint32_t)*buffer++;
+ x = (x<<8) + (uint32_t)*buffer++;
+ *value = x;
+ return buffer;
+} /* ExtractLong */
+
+
+static uint8_t* ExtractBlock(uint16_t count, uint8_t* data, uint8_t* buffer)
+{
+ while (count--) *data++ = *buffer++;
+ return buffer;
+} /* ExtractBlock */
+
+
+static char* WriteHex(char* pa, uint8_t value, uint16_t* pCheckSum)
+{
+ uint16_t temp;
+
+ static char ByteToHex[] = "0123456789ABCDEF";
+
+ *pCheckSum += value;
+ temp = value / 16;
+ *pa++ = ByteToHex[temp];
+ temp = value % 16;
+ *pa++ = ByteToHex[temp];
+ return pa;
+}
+
+
+static char* BuildSRecord(char* pa, uint16_t sType, uint32_t addr,
+ const uint8_t* data, int nCount)
+{
+ uint16_t addrLen;
+ uint16_t sRLen;
+ uint16_t checkSum;
+ uint16_t i;
+
+ switch (sType) {
+ case 0:
+ case 1:
+ case 9:
+ addrLen = 2;
+ break;
+ case 2:
+ case 8:
+ addrLen = 3;
+ break;
+ case 3:
+ case 7:
+ addrLen = 4;
+ break;
+ default:
+ return pa;
+ } /* switch */
+
+ *pa++ = 'S';
+ *pa++ = (char)(sType + '0');
+ sRLen = addrLen + nCount + 1;
+ checkSum = 0;
+ pa = WriteHex(pa, (uint8_t)sRLen, &checkSum);
+
+ /* Write address field */
+ for (i = 1; i <= addrLen; i++) {
+ pa = WriteHex(pa, (uint8_t)(addr >> (8 * (addrLen - i))), &checkSum);
+ } /* for */
+
+ /* Write code/data fields */
+ for (i = 0; i < nCount; i++) {
+ pa = WriteHex(pa, *data++, &checkSum);
+ } /* for */
+
+ /* Write checksum field */
+ checkSum = ~checkSum;
+ pa = WriteHex(pa, (uint8_t)checkSum, &checkSum);
+ *pa++ = '\0';
+ return pa;
+}
+
+
+static void ConvertELF(char* fileName, uint32_t loadOffset)
+{
+ FILE* file;
+ int i;
+ int rxCount;
+ uint8_t rxBlock[1024];
+ uint32_t loadSize;
+ uint32_t firstAddr;
+ uint32_t loadAddr;
+ uint32_t loadDiff = 0;
+ Elf32_Ehdr elfHeader;
+ Elf32_Shdr sectHeader[32];
+ uint8_t* getPtr;
+ char srecLine[128];
+ char *hdr_name;
+
+
+ /* open file */
+ if ((file = fopen(fileName,"rb")) == NULL) {
+ fprintf (stderr, "Can't open %s: %s\n", fileName, strerror(errno));
+ return;
+ } /* if */
+
+ /* read ELF header */
+ rxCount = fread(rxBlock, 1, sizeof elfHeader, file);
+ getPtr = ExtractBlock(sizeof elfHeader.e_ident, elfHeader.e_ident, rxBlock);
+ getPtr = ExtractWord(&elfHeader.e_type, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_machine, getPtr);
+ getPtr = ExtractLong((uint32_t *)&elfHeader.e_version, getPtr);
+ getPtr = ExtractLong((uint32_t *)&elfHeader.e_entry, getPtr);
+ getPtr = ExtractLong((uint32_t *)&elfHeader.e_phoff, getPtr);
+ getPtr = ExtractLong((uint32_t *)&elfHeader.e_shoff, getPtr);
+ getPtr = ExtractLong((uint32_t *)&elfHeader.e_flags, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_ehsize, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_phentsize, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_phnum, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_shentsize, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_shnum, getPtr);
+ getPtr = ExtractWord(&elfHeader.e_shstrndx, getPtr);
+ if ( (rxCount != sizeof elfHeader)
+ || (elfHeader.e_ident[0] != ELFMAG0)
+ || (elfHeader.e_ident[1] != ELFMAG1)
+ || (elfHeader.e_ident[2] != ELFMAG2)
+ || (elfHeader.e_ident[3] != ELFMAG3)
+ || (elfHeader.e_type != ET_EXEC)
+ ) {
+ fclose(file);
+ fprintf (stderr, "*** illegal file format\n");
+ return;
+ } /* if */
+
+ /* read all section headers */
+ fseek(file, elfHeader.e_shoff, SEEK_SET);
+ for (i = 0; i < elfHeader.e_shnum; i++) {
+ rxCount = fread(rxBlock, 1, sizeof sectHeader[0], file);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_name, rxBlock);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_type, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_flags, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addr, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_offset, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_size, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_link, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_info, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_addralign, getPtr);
+ getPtr = ExtractLong((uint32_t *)&sectHeader[i].sh_entsize, getPtr);
+ if (rxCount != sizeof sectHeader[0]) {
+ fclose(file);
+ fprintf (stderr, "*** illegal file format\n");
+ return;
+ } /* if */
+ } /* for */
+
+ if ((hdr_name = strrchr(fileName, '/')) == NULL) {
+ hdr_name = fileName;
+ } else {
+ ++hdr_name;
+ }
+ /* write start record */
+ (void)BuildSRecord(srecLine, 0, 0, (uint8_t *)hdr_name, strlen(hdr_name));
+ printf("%s\r\n",srecLine);
+
+ /* write data records */
+ firstAddr = ~0;
+ loadAddr = 0;
+ for (i = 0; i < elfHeader.e_shnum; i++) {
+ if ( (sectHeader[i].sh_type == SHT_PROGBITS)
+ && (sectHeader[i].sh_size != 0)
+ ) {
+ loadSize = sectHeader[i].sh_size;
+ if (sectHeader[i].sh_flags != 0) {
+ loadAddr = sectHeader[i].sh_addr;
+ loadDiff = loadAddr - sectHeader[i].sh_offset;
+ } /* if */
+ else {
+ loadAddr = sectHeader[i].sh_offset + loadDiff;
+ } /* else */
+
+ if (loadAddr < firstAddr)
+ firstAddr = loadAddr;
+
+ /* build s-records */
+ loadSize = sectHeader[i].sh_size;
+ fseek(file, sectHeader[i].sh_offset, SEEK_SET);
+ while (loadSize) {
+ rxCount = fread(rxBlock, 1, (loadSize > 32) ? 32 : loadSize, file);
+ if (rxCount < 0) {
+ fclose(file);
+ fprintf (stderr, "*** illegal file format\n");
+ return;
+ } /* if */
+ (void)BuildSRecord(srecLine, 3, loadAddr + loadOffset, rxBlock, rxCount);
+ loadSize -= rxCount;
+ loadAddr += rxCount;
+ printf("%s\r\n",srecLine);
+ } /* while */
+ } /* if */
+ } /* for */
+
+ /* add end record */
+ (void)BuildSRecord(srecLine, 7, firstAddr + loadOffset, 0, 0);
+ printf("%s\r\n",srecLine);
+ fclose(file);
+} /* ConvertELF */
+
+
+/*************************************************************************
+| MAIN
+|*************************************************************************/
+
+int main( int argc, char *argv[ ])
+{
+ uint32_t offset;
+
+ if (argc == 2) {
+ ConvertELF(argv[1], 0);
+ } /* if */
+ else if ((argc == 4) && (strcmp(argv[1], "-o") == 0)) {
+ ExtractNumber(&offset, argv[2]);
+ ConvertELF(argv[3], offset);
+ } /* if */
+ else {
+ fprintf (stderr, "Usage: img2srec [-o offset] <image>\n");
+ } /* if */
+
+ return 0;
+} /* main */
diff --git a/tools/imls/Makefile b/tools/imls/Makefile
new file mode 100644
index 0000000..0caa397
--- /dev/null
+++ b/tools/imls/Makefile
@@ -0,0 +1,97 @@
+#
+# (C) Copyright 2009 Marco Stornelli <marco.stornelli@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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+# Generated executable files
+BIN_FILES-y += imls
+
+# Source files which exist outside the tools/imls directory
+EXT_OBJ_FILES-y += lib/crc32.o
+EXT_OBJ_FILES-y += lib/md5.o
+EXT_OBJ_FILES-y += lib/sha1.o
+EXT_OBJ_FILES-y += common/image.o
+
+# Source files located in the tools/imls directory
+OBJ_FILES-y += imls.o
+
+# Flattened device tree objects
+LIBFDT_OBJ_FILES-y += fdt.o
+LIBFDT_OBJ_FILES-y += fdt_ro.o
+LIBFDT_OBJ_FILES-y += fdt_rw.o
+LIBFDT_OBJ_FILES-y += fdt_strerror.o
+LIBFDT_OBJ_FILES-y += fdt_wip.o
+
+# now $(obj) is defined
+SRCS += $(addprefix $(SRCTREE)/,$(EXT_OBJ_FILES-y:.o=.c))
+SRCS += $(addprefix $(SRCTREE)/tools/,$(OBJ_FILES-y:.o=.c))
+SRCS += $(addprefix $(SRCTREE)/lib/libfdt/,$(LIBFDT_OBJ_FILES-y:.o=.c))
+BINS := $(addprefix $(obj),$(sort $(BIN_FILES-y)))
+LIBFDT_OBJS := $(addprefix $(obj),$(LIBFDT_OBJ_FILES-y))
+
+#
+# Compile for a hosted environment on the target
+# Define __KERNEL_STRICT_NAMES to prevent typedef overlaps
+#
+HOSTCPPFLAGS = -idirafter $(SRCTREE)/include \
+ -idirafter $(OBJTREE)/include2 \
+ -idirafter $(OBJTREE)/include \
+ -I $(SRCTREE)/lib/libfdt \
+ -I $(SRCTREE)/tools \
+ -DUSE_HOSTCC -D__KERNEL_STRICT_NAMES
+
+ifeq ($(MTD_VERSION),old)
+HOSTCPPFLAGS += -DMTD_OLD
+endif
+
+all: $(BINS)
+
+$(obj)imls: $(obj)imls.o $(obj)crc32.o $(obj)image.o $(obj)md5.o \
+ $(obj)sha1.o $(LIBFDT_OBJS)
+ $(CC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(STRIP) $@
+
+# Some files complain if compiled with -pedantic, use HOSTCFLAGS_NOPED
+$(obj)image.o: $(SRCTREE)/common/image.c
+ $(CC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)imls.o: $(SRCTREE)/tools/imls/imls.c
+ $(CC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+# Some of the tool objects need to be accessed from outside the tools/imls directory
+$(obj)%.o: $(SRCTREE)/common/%.c
+ $(CC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/%.c
+ $(CC) -g $(HOSTCFLAGS) -c -o $@ $<
+
+$(obj)%.o: $(SRCTREE)/lib/libfdt/%.c
+ $(CC) -g $(HOSTCFLAGS_NOPED) -c -o $@ $<
+
+clean:
+ rm -rf *.o imls
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/imls/README b/tools/imls/README
new file mode 100644
index 0000000..97d7e32
--- /dev/null
+++ b/tools/imls/README
@@ -0,0 +1,57 @@
+#
+# (C) Copyright 2009 Marco Stornelli <marco.stornelli@gmail.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# The files in this directory are free software; you can redistribute
+# them and/or modify them 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.
+#
+# These files are distributed in the hope that they 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+IMLS
+-------------
+
+imls is an implementation of a Linux command line tool to access
+to raw flash partitions and list images made with mkimage command.
+
+For building against older versions of the MTD headers (meaning before
+v2.6.8-rc1) it is required to pass the argument "MTD_VERSION=old" to
+make.
+
+Usage examples
+--------------
+
+1) Flash with sectors of 128KiB and 32 sectors:
+
+> imls -c 32 -s 131072 /dev/mtd0
+Searching...
+Image Name: foo
+Created: Fri Apr 10 18:11:30 2009
+Image Type: Intel x86 Linux Standalone Program (uncompressed)
+Data Size: 10716 Bytes = 10.46 kB = 0.01 MB
+Load Address: 00000000
+Entry Point: 00000000
+
+2) Flash with sectors of 64KiB and 128 sectors and with a search offset of one
+sector:
+
+> imls -o 1 -c 128 -s 65536 /dev/mtd0
+Searching...
+Image Name: foo
+Created: Fri Apr 10 18:11:30 2009
+Image Type: Intel x86 Linux Standalone Program (uncompressed)
+Data Size: 10716 Bytes = 10.46 kB = 0.01 MB
+Load Address: 00000000
+Entry Point: 00000000
diff --git a/tools/imls/imls.c b/tools/imls/imls.c
new file mode 100644
index 0000000..a982a13
--- /dev/null
+++ b/tools/imls/imls.c
@@ -0,0 +1,269 @@
+/*
+ * (C) Copyright 2009 Marco Stornelli
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <asm/page.h>
+
+#ifdef MTD_OLD
+#include <stdint.h>
+#include <linux/mtd/mtd.h>
+#else
+#define __user /* nothing */
+#include <mtd/mtd-user.h>
+#endif
+
+#include <sha1.h>
+#include <libfdt.h>
+#include <fdt_support.h>
+#include <image.h>
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+extern unsigned long crc32(unsigned long crc, const char *buf, unsigned int len);
+static void usage(void);
+static int image_verify_header(char *ptr, int fd);
+static int flash_bad_block(int fd, uint8_t mtd_type, loff_t start);
+
+char *cmdname;
+char *devicefile;
+
+unsigned int sectorcount = 0;
+int sflag = 0;
+unsigned int sectoroffset = 0;
+unsigned int sectorsize = 0;
+int cflag = 0;
+
+int main (int argc, char **argv)
+{
+ int fd = -1, err = 0, readbyte = 0, j;
+ struct mtd_info_user mtdinfo;
+ char buf[sizeof(image_header_t)];
+ int found = 0;
+
+ cmdname = *argv;
+
+ while (--argc > 0 && **++argv == '-') {
+ while (*++*argv) {
+ switch (**argv) {
+ case 'c':
+ if (--argc <= 0)
+ usage ();
+ sectorcount = (unsigned int)atoi(*++argv);
+ cflag = 1;
+ goto NXTARG;
+ case 'o':
+ if (--argc <= 0)
+ usage ();
+ sectoroffset = (unsigned int)atoi(*++argv);
+ goto NXTARG;
+
+ case 's':
+ if (--argc <= 0)
+ usage ();
+ sectorsize = (unsigned int)atoi(*++argv);
+ sflag = 1;
+ goto NXTARG;
+ default:
+ usage ();
+ }
+ }
+NXTARG: ;
+ }
+
+ if (argc != 1 || cflag == 0 || sflag == 0)
+ usage();
+
+ devicefile = *argv;
+
+ fd = open(devicefile, O_RDONLY);
+ if (fd < 0) {
+ fprintf (stderr, "%s: Can't open %s: %s\n",
+ cmdname, devicefile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ err = ioctl(fd, MEMGETINFO, &mtdinfo);
+ if (err < 0) {
+ fprintf(stderr, "%s: Cannot get MTD information: %s\n",cmdname,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (mtdinfo.type != MTD_NORFLASH && mtdinfo.type != MTD_NANDFLASH) {
+ fprintf(stderr, "%s: Unsupported flash type %u\n",
+ cmdname, mtdinfo.type);
+ exit(EXIT_FAILURE);
+ }
+
+ if (sectorsize * sectorcount != mtdinfo.size) {
+ fprintf(stderr, "%s: Partition size (%d) incompatible with "
+ "sector size and count\n", cmdname, mtdinfo.size);
+ exit(EXIT_FAILURE);
+ }
+
+ if (sectorsize * sectoroffset >= mtdinfo.size) {
+ fprintf(stderr, "%s: Partition size (%d) incompatible with "
+ "sector offset given\n", cmdname, mtdinfo.size);
+ exit(EXIT_FAILURE);
+ }
+
+ if (sectoroffset > sectorcount - 1) {
+ fprintf(stderr, "%s: Sector offset cannot be grater than "
+ "sector count minus one\n", cmdname);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("Searching....\n");
+
+ for (j = sectoroffset; j < sectorcount; ++j) {
+
+ if (lseek(fd, j*sectorsize, SEEK_SET) != j*sectorsize) {
+ fprintf(stderr, "%s: lseek failure: %s\n",
+ cmdname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ err = flash_bad_block(fd, mtdinfo.type, j*sectorsize);
+ if (err < 0)
+ exit(EXIT_FAILURE);
+ if (err)
+ continue; /* Skip and jump to next */
+
+ readbyte = read(fd, buf, sizeof(image_header_t));
+ if (readbyte != sizeof(image_header_t)) {
+ fprintf(stderr, "%s: Can't read from device: %s\n",
+ cmdname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (fdt_check_header(buf)) {
+ /* old-style image */
+ if (image_verify_header(buf, fd)) {
+ found = 1;
+ image_print_contents((image_header_t *)buf);
+ }
+ } else {
+ /* FIT image */
+ fit_print_contents(buf);
+ }
+
+ }
+
+ close(fd);
+
+ if(!found)
+ printf("No images found\n");
+
+ exit(EXIT_SUCCESS);
+}
+
+void usage()
+{
+ fprintf (stderr, "Usage:\n"
+ " %s [-o offset] -s size -c count device\n"
+ " -o ==> number of sectors to use as offset\n"
+ " -c ==> number of sectors\n"
+ " -s ==> size of sectors (byte)\n",
+ cmdname);
+
+ exit(EXIT_FAILURE);
+}
+
+static int image_verify_header(char *ptr, int fd)
+{
+ int len, nread;
+ char *data;
+ uint32_t checksum;
+ image_header_t *hdr = (image_header_t *)ptr;
+ char buf[PAGE_SIZE];
+
+ if (image_get_magic(hdr) != IH_MAGIC)
+ return 0;
+
+ data = (char *)hdr;
+ len = image_get_header_size();
+
+ checksum = image_get_hcrc(hdr);
+ hdr->ih_hcrc = htonl(0); /* clear for re-calculation */
+
+ if (crc32(0, data, len) != checksum) {
+ fprintf(stderr,
+ "%s: Maybe image found but it has bad header checksum!\n",
+ cmdname);
+ return 0;
+ }
+
+ len = image_get_size(hdr);
+ checksum = 0;
+
+ while (len > 0) {
+ nread = read(fd, buf, MIN(len,PAGE_SIZE));
+ if (nread != MIN(len,PAGE_SIZE)) {
+ fprintf(stderr,
+ "%s: Error while reading: %s\n",
+ cmdname, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ checksum = crc32(checksum, buf, nread);
+ len -= nread;
+ }
+
+ if (checksum != image_get_dcrc(hdr)) {
+ fprintf (stderr,
+ "%s: Maybe image found but it has corrupted data!\n",
+ cmdname);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * Test for bad block on NAND, just returns 0 on NOR, on NAND:
+ * 0 - block is good
+ * > 0 - block is bad
+ * < 0 - failed to test
+ */
+static int flash_bad_block(int fd, uint8_t mtd_type, loff_t start)
+{
+ if (mtd_type == MTD_NANDFLASH) {
+ int badblock = ioctl(fd, MEMGETBADBLOCK, &start);
+
+ if (badblock < 0) {
+ fprintf(stderr,"%s: Cannot read bad block mark: %s\n",
+ cmdname, strerror(errno));
+ return badblock;
+ }
+
+ if (badblock) {
+ return badblock;
+ }
+ }
+
+ return 0;
+}
diff --git a/tools/imximage.c b/tools/imximage.c
new file mode 100644
index 0000000..5e8e470
--- /dev/null
+++ b/tools/imximage.c
@@ -0,0 +1,576 @@
+/*
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Required to obtain the getline prototype from stdio.h */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include <image.h>
+#include "imximage.h"
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t imximage_cmds[] = {
+ {CMD_BOOT_FROM, "BOOT_FROM", "boot command", },
+ {CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", },
+ {CMD_DATA, "DATA", "Reg Write Data", },
+ {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", },
+ {-1, "", "", },
+};
+
+/*
+ * Supported Boot options for configuration file
+ * this is needed to set the correct flash offset
+ */
+static table_entry_t imximage_bootops[] = {
+ {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",},
+ {FLASH_OFFSET_NAND, "nand", "NAND Flash", },
+ {FLASH_OFFSET_NOR, "nor", "NOR Flash", },
+ {FLASH_OFFSET_SATA, "sata", "SATA Disk", },
+ {FLASH_OFFSET_SD, "sd", "SD Card", },
+ {FLASH_OFFSET_SPI, "spi", "SPI Flash", },
+ {-1, "", "Invalid", },
+};
+
+/*
+ * IMXIMAGE version definition for i.MX chips
+ */
+static table_entry_t imximage_versions[] = {
+ {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", },
+ {IMXIMAGE_V2, "", " (i.MX53/6 compatible)", },
+ {-1, "", " (Invalid)", },
+};
+
+static struct imx_header imximage_header;
+static uint32_t imximage_version;
+
+static set_dcd_val_t set_dcd_val;
+static set_dcd_rst_t set_dcd_rst;
+static set_imx_hdr_t set_imx_hdr;
+static uint32_t max_dcd_entries;
+static uint32_t *header_size_ptr;
+
+static uint32_t get_cfg_value(char *token, char *name, int linenr)
+{
+ char *endptr;
+ uint32_t value;
+
+ errno = 0;
+ value = strtoul(token, &endptr, 16);
+ if (errno || (token == endptr)) {
+ fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+ name, linenr, token);
+ exit(EXIT_FAILURE);
+ }
+ return value;
+}
+
+static uint32_t detect_imximage_version(struct imx_header *imx_hdr)
+{
+ imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1;
+ imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2;
+ flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+ flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+
+ /* Try to detect V1 */
+ if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) &&
+ (hdr_v1->dcd_table.preamble.barker == DCD_BARKER))
+ return IMXIMAGE_V1;
+
+ /* Try to detect V2 */
+ if ((fhdr_v2->header.tag == IVT_HEADER_TAG) &&
+ (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG))
+ return IMXIMAGE_V2;
+
+ return IMXIMAGE_VER_INVALID;
+}
+
+static void err_imximage_version(int version)
+{
+ fprintf(stderr,
+ "Error: Unsupported imximage version:%d\n", version);
+
+ exit(EXIT_FAILURE);
+}
+
+static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno,
+ int fld, uint32_t value, uint32_t off)
+{
+ dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table;
+
+ switch (fld) {
+ case CFG_REG_SIZE:
+ /* Byte, halfword, word */
+ if ((value != 1) && (value != 2) && (value != 4)) {
+ fprintf(stderr, "Error: %s[%d] - "
+ "Invalid register size " "(%d)\n",
+ name, lineno, value);
+ exit(EXIT_FAILURE);
+ }
+ dcd_v1->addr_data[off].type = value;
+ break;
+ case CFG_REG_ADDRESS:
+ dcd_v1->addr_data[off].addr = value;
+ break;
+ case CFG_REG_VALUE:
+ dcd_v1->addr_data[off].value = value;
+ break;
+ default:
+ break;
+
+ }
+}
+
+static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno,
+ int fld, uint32_t value, uint32_t off)
+{
+ dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table;
+
+ switch (fld) {
+ case CFG_REG_ADDRESS:
+ dcd_v2->addr_data[off].addr = cpu_to_be32(value);
+ break;
+ case CFG_REG_VALUE:
+ dcd_v2->addr_data[off].value = cpu_to_be32(value);
+ break;
+ default:
+ break;
+
+ }
+}
+
+/*
+ * Complete setting up the rest field of DCD of V1
+ * such as barker code and DCD data length.
+ */
+static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len,
+ char *name, int lineno)
+{
+ dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table;
+
+ dcd_v1->preamble.barker = DCD_BARKER;
+ dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t);
+}
+
+/*
+ * Complete setting up the reset field of DCD of V2
+ * such as DCD tag, version, length, etc.
+ */
+static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len,
+ char *name, int lineno)
+{
+ dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table;
+
+ dcd_v2->header.tag = DCD_HEADER_TAG;
+ dcd_v2->header.length = cpu_to_be16(
+ dcd_len * sizeof(dcd_addr_data_t) + 8);
+ dcd_v2->header.version = DCD_VERSION;
+ dcd_v2->write_dcd_command.tag = DCD_COMMAND_TAG;
+ dcd_v2->write_dcd_command.length = cpu_to_be16(
+ dcd_len * sizeof(dcd_addr_data_t) + 4);
+ dcd_v2->write_dcd_command.param = DCD_COMMAND_PARAM;
+}
+
+static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len,
+ uint32_t entry_point, uint32_t flash_offset)
+{
+ imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1;
+ flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+ dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table;
+ uint32_t hdr_base;
+ uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr)
+ - ((char *)imxhdr));
+
+ /* Set magic number */
+ fhdr_v1->app_code_barker = APP_CODE_BARKER;
+
+ hdr_base = entry_point - sizeof(struct imx_header);
+ fhdr_v1->app_dest_ptr = hdr_base - flash_offset;
+ fhdr_v1->app_code_jump_vector = entry_point;
+
+ fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr);
+ fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table);
+
+ /* Security feature are not supported */
+ fhdr_v1->app_code_csf = 0;
+ fhdr_v1->super_root_key = 0;
+ header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4);
+}
+
+static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len,
+ uint32_t entry_point, uint32_t flash_offset)
+{
+ imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2;
+ flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+ uint32_t hdr_base;
+
+ /* Set magic number */
+ fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */
+ fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t));
+ fhdr_v2->header.version = IVT_VERSION; /* 0x40 */
+
+ fhdr_v2->entry = entry_point;
+ fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0;
+ fhdr_v2->self = hdr_base = entry_point - sizeof(struct imx_header);
+
+ fhdr_v2->dcd_ptr = hdr_base + offsetof(imx_header_v2_t, dcd_table);
+ fhdr_v2->boot_data_ptr = hdr_base
+ + offsetof(imx_header_v2_t, boot_data);
+ hdr_v2->boot_data.start = hdr_base - flash_offset;
+
+ /* Security feature are not supported */
+ fhdr_v2->csf = 0;
+ header_size_ptr = &hdr_v2->boot_data.size;
+}
+
+static void set_hdr_func(struct imx_header *imxhdr)
+{
+ switch (imximage_version) {
+ case IMXIMAGE_V1:
+ set_dcd_val = set_dcd_val_v1;
+ set_dcd_rst = set_dcd_rst_v1;
+ set_imx_hdr = set_imx_hdr_v1;
+ max_dcd_entries = MAX_HW_CFG_SIZE_V1;
+ break;
+ case IMXIMAGE_V2:
+ set_dcd_val = set_dcd_val_v2;
+ set_dcd_rst = set_dcd_rst_v2;
+ set_imx_hdr = set_imx_hdr_v2;
+ max_dcd_entries = MAX_HW_CFG_SIZE_V2;
+ break;
+ default:
+ err_imximage_version(imximage_version);
+ break;
+ }
+}
+
+static void print_hdr_v1(struct imx_header *imx_hdr)
+{
+ imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1;
+ flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr;
+ dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table;
+ uint32_t size, length, ver;
+
+ size = dcd_v1->preamble.length;
+ if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) {
+ fprintf(stderr,
+ "Error: Image corrupt DCD size %d exceed maximum %d\n",
+ (uint32_t)(size / sizeof(dcd_type_addr_data_t)),
+ MAX_HW_CFG_SIZE_V1);
+ exit(EXIT_FAILURE);
+ }
+
+ length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t);
+ ver = detect_imximage_version(imx_hdr);
+
+ printf("Image Type: Freescale IMX Boot Image\n");
+ printf("Image Ver: %x", ver);
+ printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver));
+ printf("Data Size: ");
+ genimg_print_size(dcd_v1->addr_data[length].type);
+ printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr);
+ printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector);
+}
+
+static void print_hdr_v2(struct imx_header *imx_hdr)
+{
+ imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2;
+ flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr;
+ dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table;
+ uint32_t size, version;
+
+ size = be16_to_cpu(dcd_v2->header.length) - 8;
+ if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) {
+ fprintf(stderr,
+ "Error: Image corrupt DCD size %d exceed maximum %d\n",
+ (uint32_t)(size / sizeof(dcd_addr_data_t)),
+ MAX_HW_CFG_SIZE_V2);
+ exit(EXIT_FAILURE);
+ }
+
+ version = detect_imximage_version(imx_hdr);
+
+ printf("Image Type: Freescale IMX Boot Image\n");
+ printf("Image Ver: %x", version);
+ printf("%s\n", get_table_entry_name(imximage_versions, NULL, version));
+ printf("Data Size: ");
+ genimg_print_size(hdr_v2->boot_data.size);
+ printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr);
+ printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry);
+}
+
+static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token,
+ char *name, int lineno, int fld, int dcd_len)
+{
+ int value;
+ static int cmd_ver_first = ~0;
+
+ switch (cmd) {
+ case CMD_IMAGE_VERSION:
+ imximage_version = get_cfg_value(token, name, lineno);
+ if (cmd_ver_first == 0) {
+ fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION "
+ "command need be the first before other "
+ "valid command in the file\n", name, lineno);
+ exit(EXIT_FAILURE);
+ }
+ cmd_ver_first = 1;
+ set_hdr_func(imxhdr);
+ break;
+ case CMD_BOOT_FROM:
+ imxhdr->flash_offset = get_table_entry_id(imximage_bootops,
+ "imximage boot option", token);
+ if (imxhdr->flash_offset == -1) {
+ fprintf(stderr, "Error: %s[%d] -Invalid boot device"
+ "(%s)\n", name, lineno, token);
+ exit(EXIT_FAILURE);
+ }
+ if (unlikely(cmd_ver_first != 1))
+ cmd_ver_first = 0;
+ break;
+ case CMD_BOOT_OFFSET:
+ imxhdr->flash_offset = get_cfg_value(token, name, lineno);
+ if (unlikely(cmd_ver_first != 1))
+ cmd_ver_first = 0;
+ break;
+ case CMD_DATA:
+ value = get_cfg_value(token, name, lineno);
+ (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len);
+ if (unlikely(cmd_ver_first != 1))
+ cmd_ver_first = 0;
+ break;
+ }
+}
+
+static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd,
+ char *token, char *name, int lineno, int fld, int *dcd_len)
+{
+ int value;
+
+ switch (fld) {
+ case CFG_COMMAND:
+ *cmd = get_table_entry_id(imximage_cmds,
+ "imximage commands", token);
+ if (*cmd < 0) {
+ fprintf(stderr, "Error: %s[%d] - Invalid command"
+ "(%s)\n", name, lineno, token);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case CFG_REG_SIZE:
+ parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len);
+ break;
+ case CFG_REG_ADDRESS:
+ case CFG_REG_VALUE:
+ if (*cmd != CMD_DATA)
+ return;
+
+ value = get_cfg_value(token, name, lineno);
+ (*set_dcd_val)(imxhdr, name, lineno, fld, value, *dcd_len);
+
+ if (fld == CFG_REG_VALUE) {
+ (*dcd_len)++;
+ if (*dcd_len > max_dcd_entries) {
+ fprintf(stderr, "Error: %s[%d] -"
+ "DCD table exceeds maximum size(%d)\n",
+ name, lineno, max_dcd_entries);
+ exit(EXIT_FAILURE);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name)
+{
+ FILE *fd = NULL;
+ char *line = NULL;
+ char *token, *saveptr1, *saveptr2;
+ int lineno = 0;
+ int fld;
+ size_t len;
+ int dcd_len = 0;
+ int32_t cmd;
+
+ fd = fopen(name, "r");
+ if (fd == 0) {
+ fprintf(stderr, "Error: %s - Can't open DCD file\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Very simple parsing, line starting with # are comments
+ * and are dropped
+ */
+ while ((getline(&line, &len, fd)) > 0) {
+ lineno++;
+
+ token = strtok_r(line, "\r\n", &saveptr1);
+ if (token == NULL)
+ continue;
+
+ /* Check inside the single line */
+ for (fld = CFG_COMMAND, cmd = CMD_INVALID,
+ line = token; ; line = NULL, fld++) {
+ token = strtok_r(line, " \t", &saveptr2);
+ if (token == NULL)
+ break;
+
+ /* Drop all text starting with '#' as comments */
+ if (token[0] == '#')
+ break;
+
+ parse_cfg_fld(imxhdr, &cmd, token, name,
+ lineno, fld, &dcd_len);
+ }
+
+ }
+
+ (*set_dcd_rst)(imxhdr, dcd_len, name, lineno);
+ fclose(fd);
+
+ /* Exit if there is no BOOT_FROM field specifying the flash_offset */
+ if (imxhdr->flash_offset == FLASH_OFFSET_UNDEFINED) {
+ fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name);
+ exit(EXIT_FAILURE);
+ }
+ return dcd_len;
+}
+
+
+static int imximage_check_image_types(uint8_t type)
+{
+ if (type == IH_TYPE_IMXIMAGE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static int imximage_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct imx_header *imx_hdr = (struct imx_header *) ptr;
+
+ if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ return 0;
+}
+
+static void imximage_print_header(const void *ptr)
+{
+ struct imx_header *imx_hdr = (struct imx_header *) ptr;
+ uint32_t version = detect_imximage_version(imx_hdr);
+
+ switch (version) {
+ case IMXIMAGE_V1:
+ print_hdr_v1(imx_hdr);
+ break;
+ case IMXIMAGE_V2:
+ print_hdr_v2(imx_hdr);
+ break;
+ default:
+ err_imximage_version(version);
+ break;
+ }
+}
+
+static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ struct imx_header *imxhdr = (struct imx_header *)ptr;
+ uint32_t dcd_len;
+
+ /*
+ * In order to not change the old imx cfg file
+ * by adding VERSION command into it, here need
+ * set up function ptr group to V1 by default.
+ */
+ imximage_version = IMXIMAGE_V1;
+ /* Be able to detect if the cfg file has no BOOT_FROM tag */
+ imxhdr->flash_offset = FLASH_OFFSET_UNDEFINED;
+ set_hdr_func(imxhdr);
+
+ /* Parse dcd configuration file */
+ dcd_len = parse_cfg_file(imxhdr, params->imagename);
+
+ /* Set the imx header */
+ (*set_imx_hdr)(imxhdr, dcd_len, params->ep, imxhdr->flash_offset);
+
+ /*
+ * ROM bug alert
+ *
+ * MX53 only loads 512 byte multiples in case of SD boot.
+ * MX53 only loads NAND page multiples in case of NAND boot and
+ * supports up to 4096 byte large pages, thus align to 4096.
+ *
+ * The remaining fraction of a block bytes would not be loaded!
+ */
+ *header_size_ptr = ROUND(sbuf->st_size + imxhdr->flash_offset, 4096);
+}
+
+int imximage_check_params(struct mkimage_params *params)
+{
+ if (!params)
+ return CFG_INVALID;
+ if (!strlen(params->imagename)) {
+ fprintf(stderr, "Error: %s - Configuration file not specified, "
+ "it is needed for imximage generation\n",
+ params->cmdname);
+ return CFG_INVALID;
+ }
+ /*
+ * Check parameters:
+ * XIP is not allowed and verify that incompatible
+ * parameters are not sent at the same time
+ * For example, if list is required a data image must not be provided
+ */
+ return (params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)) ||
+ (params->xflag) || !(strlen(params->imagename));
+}
+
+/*
+ * imximage parameters
+ */
+static struct image_type_params imximage_params = {
+ .name = "Freescale i.MX Boot Image support",
+ .header_size = sizeof(struct imx_header),
+ .hdr = (void *)&imximage_header,
+ .check_image_type = imximage_check_image_types,
+ .verify_header = imximage_verify_header,
+ .print_header = imximage_print_header,
+ .set_header = imximage_set_header,
+ .check_params = imximage_check_params,
+};
+
+void init_imx_image_type(void)
+{
+ mkimage_register(&imximage_params);
+}
diff --git a/tools/imximage.h b/tools/imximage.h
new file mode 100644
index 0000000..5c929e4
--- /dev/null
+++ b/tools/imximage.h
@@ -0,0 +1,181 @@
+/*
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _IMXIMAGE_H_
+#define _IMXIMAGE_H_
+
+#define MAX_HW_CFG_SIZE_V2 121 /* Max number of registers imx can set for v2 */
+#define MAX_HW_CFG_SIZE_V1 60 /* Max number of registers imx can set for v1 */
+#define APP_CODE_BARKER 0xB1
+#define DCD_BARKER 0xB17219E9
+
+#define HEADER_OFFSET 0x400
+
+/*
+ * NOTE: This file must be kept in sync with arch/arm/include/asm/\
+ * imx-common/imximage.cfg because tools/imximage.c can not
+ * cross-include headers from arch/arm/ and vice-versa.
+ */
+#define CMD_DATA_STR "DATA"
+#define FLASH_OFFSET_UNDEFINED 0xFFFFFFFF
+#define FLASH_OFFSET_STANDARD 0x400
+#define FLASH_OFFSET_NAND FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_SD FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_SPI FLASH_OFFSET_STANDARD
+#define FLASH_OFFSET_ONENAND 0x100
+#define FLASH_OFFSET_NOR 0x1000
+#define FLASH_OFFSET_SATA FLASH_OFFSET_STANDARD
+
+#define IVT_HEADER_TAG 0xD1
+#define IVT_VERSION 0x40
+#define DCD_HEADER_TAG 0xD2
+#define DCD_COMMAND_TAG 0xCC
+#define DCD_VERSION 0x40
+#define DCD_COMMAND_PARAM 0x4
+
+enum imximage_cmd {
+ CMD_INVALID,
+ CMD_IMAGE_VERSION,
+ CMD_BOOT_FROM,
+ CMD_BOOT_OFFSET,
+ CMD_DATA
+};
+
+enum imximage_fld_types {
+ CFG_INVALID = -1,
+ CFG_COMMAND,
+ CFG_REG_SIZE,
+ CFG_REG_ADDRESS,
+ CFG_REG_VALUE
+};
+
+enum imximage_version {
+ IMXIMAGE_VER_INVALID = -1,
+ IMXIMAGE_V1 = 1,
+ IMXIMAGE_V2
+};
+
+typedef struct {
+ uint32_t type; /* Type of pointer (byte, halfword, word, wait/read) */
+ uint32_t addr; /* Address to write to */
+ uint32_t value; /* Data to write */
+} dcd_type_addr_data_t;
+
+typedef struct {
+ uint32_t barker; /* Barker for sanity check */
+ uint32_t length; /* Device configuration length (without preamble) */
+} dcd_preamble_t;
+
+typedef struct {
+ dcd_preamble_t preamble;
+ dcd_type_addr_data_t addr_data[MAX_HW_CFG_SIZE_V1];
+} dcd_v1_t;
+
+typedef struct {
+ uint32_t app_code_jump_vector;
+ uint32_t app_code_barker;
+ uint32_t app_code_csf;
+ uint32_t dcd_ptr_ptr;
+ uint32_t super_root_key;
+ uint32_t dcd_ptr;
+ uint32_t app_dest_ptr;
+} flash_header_v1_t;
+
+typedef struct {
+ uint32_t length; /* Length of data to be read from flash */
+} flash_cfg_parms_t;
+
+typedef struct {
+ flash_header_v1_t fhdr;
+ dcd_v1_t dcd_table;
+ flash_cfg_parms_t ext_header;
+} imx_header_v1_t;
+
+typedef struct {
+ uint32_t addr;
+ uint32_t value;
+} dcd_addr_data_t;
+
+typedef struct {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t version;
+} __attribute__((packed)) ivt_header_t;
+
+typedef struct {
+ uint8_t tag;
+ uint16_t length;
+ uint8_t param;
+} __attribute__((packed)) write_dcd_command_t;
+
+typedef struct {
+ ivt_header_t header;
+ write_dcd_command_t write_dcd_command;
+ dcd_addr_data_t addr_data[MAX_HW_CFG_SIZE_V2];
+} dcd_v2_t;
+
+typedef struct {
+ uint32_t start;
+ uint32_t size;
+ uint32_t plugin;
+} boot_data_t;
+
+typedef struct {
+ ivt_header_t header;
+ uint32_t entry;
+ uint32_t reserved1;
+ uint32_t dcd_ptr;
+ uint32_t boot_data_ptr;
+ uint32_t self;
+ uint32_t csf;
+ uint32_t reserved2;
+} flash_header_v2_t;
+
+typedef struct {
+ flash_header_v2_t fhdr;
+ boot_data_t boot_data;
+ dcd_v2_t dcd_table;
+} imx_header_v2_t;
+
+/* The header must be aligned to 4k on MX53 for NAND boot */
+struct imx_header {
+ union {
+ imx_header_v1_t hdr_v1;
+ imx_header_v2_t hdr_v2;
+ } header;
+ uint32_t flash_offset;
+} __attribute__((aligned(4096)));
+
+typedef void (*set_dcd_val_t)(struct imx_header *imxhdr,
+ char *name, int lineno,
+ int fld, uint32_t value,
+ uint32_t off);
+
+typedef void (*set_dcd_rst_t)(struct imx_header *imxhdr,
+ uint32_t dcd_len,
+ char *name, int lineno);
+
+typedef void (*set_imx_hdr_t)(struct imx_header *imxhdr, uint32_t dcd_len,
+ uint32_t entry_point, uint32_t flash_offset);
+
+#endif /* _IMXIMAGE_H_ */
diff --git a/tools/jtagconsole b/tools/jtagconsole
new file mode 100755
index 0000000..d404fac
--- /dev/null
+++ b/tools/jtagconsole
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+usage() {
+ (
+ echo "Usage: $0 [board IP] [board port]"
+ echo ""
+ echo "If IP is not specified, 'localhost' will be used"
+ echo "If port is not specified, '2001' will be used"
+ [ -z "$*" ] && exit 0
+ echo ""
+ echo "ERROR: $*"
+ exit 1
+ ) 1>&2
+ exit $?
+}
+
+while [ -n "$1" ] ; do
+ case $1 in
+ -h|--help) usage;;
+ --) break;;
+ -*) usage "Invalid option $1";;
+ *) break;;
+ esac
+ shift
+done
+
+ip=${1:-localhost}
+port=${2:-2001}
+
+if [ -z "${ip}" ] || [ -n "$3" ] ; then
+ usage "Invalid number of arguments"
+fi
+
+trap "stty icanon echo opost intr ^C" 0 2 3 5 10 13 15
+echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T"
+
+stty -icanon -echo -opost intr ^T
+nc ${ip} ${port}
+exit 0
diff --git a/tools/kernel-doc/Makefile b/tools/kernel-doc/Makefile
new file mode 100644
index 0000000..28a3f61
--- /dev/null
+++ b/tools/kernel-doc/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2012 Marek Vasut <marex@denx.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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+all: $(obj)docproc
+
+$(obj)docproc: docproc.c
+ $(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ $(HOSTSTRIP) $@
+
+clean:
+ rm -rf docproc
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/kernel-doc/docproc.c b/tools/kernel-doc/docproc.c
new file mode 100644
index 0000000..d4fc42e
--- /dev/null
+++ b/tools/kernel-doc/docproc.c
@@ -0,0 +1,576 @@
+/*
+ * docproc is a simple preprocessor for the template files
+ * used as placeholders for the kernel internal documentation.
+ * docproc is used for documentation-frontend and
+ * dependency-generator.
+ * The two usages have in common that they require
+ * some knowledge of the .tmpl syntax, therefore they
+ * are kept together.
+ *
+ * documentation-frontend
+ * Scans the template file and call kernel-doc for
+ * all occurrences of ![EIF]file
+ * Beforehand each referenced file is scanned for
+ * any symbols that are exported via these macros:
+ * EXPORT_SYMBOL(), EXPORT_SYMBOL_GPL(), &
+ * EXPORT_SYMBOL_GPL_FUTURE()
+ * This is used to create proper -function and
+ * -nofunction arguments in calls to kernel-doc.
+ * Usage: docproc doc file.tmpl
+ *
+ * dependency-generator:
+ * Scans the template file and list all files
+ * referenced in a format recognized by make.
+ * Usage: docproc depend file.tmpl
+ * Writes dependency information to stdout
+ * in the following format:
+ * file.tmpl src.c src2.c
+ * The filenames are obtained from the following constructs:
+ * !Efilename
+ * !Ifilename
+ * !Dfilename
+ * !Ffilename
+ * !Pfilename
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+/* exitstatus is used to keep track of any failing calls to kernel-doc,
+ * but execution continues. */
+int exitstatus = 0;
+
+typedef void DFL(char *);
+DFL *defaultline;
+
+typedef void FILEONLY(char * file);
+FILEONLY *internalfunctions;
+FILEONLY *externalfunctions;
+FILEONLY *symbolsonly;
+FILEONLY *findall;
+
+typedef void FILELINE(char * file, char * line);
+FILELINE * singlefunctions;
+FILELINE * entity_system;
+FILELINE * docsection;
+
+#define MAXLINESZ 2048
+#define MAXFILES 250
+#define KERNELDOCPATH "tools/kernel-doc/"
+#define KERNELDOC "kernel-doc"
+#define DOCBOOK "-docbook"
+#define LIST "-list"
+#define FUNCTION "-function"
+#define NOFUNCTION "-nofunction"
+#define NODOCSECTIONS "-no-doc-sections"
+
+static char *srctree, *kernsrctree;
+
+static char **all_list = NULL;
+static int all_list_len = 0;
+
+static void consume_symbol(const char *sym)
+{
+ int i;
+
+ for (i = 0; i < all_list_len; i++) {
+ if (!all_list[i])
+ continue;
+ if (strcmp(sym, all_list[i]))
+ continue;
+ all_list[i] = NULL;
+ break;
+ }
+}
+
+static void usage (void)
+{
+ fprintf(stderr, "Usage: docproc {doc|depend} file\n");
+ fprintf(stderr, "Input is read from file.tmpl. Output is sent to stdout\n");
+ fprintf(stderr, "doc: frontend when generating kernel documentation\n");
+ fprintf(stderr, "depend: generate list of files referenced within file\n");
+ fprintf(stderr, "Environment variable SRCTREE: absolute path to sources.\n");
+ fprintf(stderr, " KBUILD_SRC: absolute path to kernel source tree.\n");
+}
+
+/*
+ * Execute kernel-doc with parameters given in svec
+ */
+static void exec_kernel_doc(char **svec)
+{
+ pid_t pid;
+ int ret;
+ char real_filename[PATH_MAX + 1];
+ /* Make sure output generated so far are flushed */
+ fflush(stdout);
+ switch (pid=fork()) {
+ case -1:
+ perror("fork");
+ exit(1);
+ case 0:
+ memset(real_filename, 0, sizeof(real_filename));
+ strncat(real_filename, kernsrctree, PATH_MAX);
+ strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
+ PATH_MAX - strlen(real_filename));
+ execvp(real_filename, svec);
+ fprintf(stderr, "exec ");
+ perror(real_filename);
+ exit(1);
+ default:
+ waitpid(pid, &ret ,0);
+ }
+ if (WIFEXITED(ret))
+ exitstatus |= WEXITSTATUS(ret);
+ else
+ exitstatus = 0xff;
+}
+
+/* Types used to create list of all exported symbols in a number of files */
+struct symbols
+{
+ char *name;
+};
+
+struct symfile
+{
+ char *filename;
+ struct symbols *symbollist;
+ int symbolcnt;
+};
+
+struct symfile symfilelist[MAXFILES];
+int symfilecnt = 0;
+
+static void add_new_symbol(struct symfile *sym, char * symname)
+{
+ sym->symbollist =
+ realloc(sym->symbollist, (sym->symbolcnt + 1) * sizeof(char *));
+ sym->symbollist[sym->symbolcnt++].name = strdup(symname);
+}
+
+/* Add a filename to the list */
+static struct symfile * add_new_file(char * filename)
+{
+ symfilelist[symfilecnt++].filename = strdup(filename);
+ return &symfilelist[symfilecnt - 1];
+}
+
+/* Check if file already are present in the list */
+static struct symfile * filename_exist(char * filename)
+{
+ int i;
+ for (i=0; i < symfilecnt; i++)
+ if (strcmp(symfilelist[i].filename, filename) == 0)
+ return &symfilelist[i];
+ return NULL;
+}
+
+/*
+ * List all files referenced within the template file.
+ * Files are separated by tabs.
+ */
+static void adddep(char * file) { printf("\t%s", file); }
+static void adddep2(char * file, char * line) { line = line; adddep(file); }
+static void noaction(char * line) { line = line; }
+static void noaction2(char * file, char * line) { file = file; line = line; }
+
+/* Echo the line without further action */
+static void printline(char * line) { printf("%s", line); }
+
+/*
+ * Find all symbols in filename that are exported with EXPORT_SYMBOL &
+ * EXPORT_SYMBOL_GPL (& EXPORT_SYMBOL_GPL_FUTURE implicitly).
+ * All symbols located are stored in symfilelist.
+ */
+static void find_export_symbols(char * filename)
+{
+ FILE * fp;
+ struct symfile *sym;
+ char line[MAXLINESZ];
+ if (filename_exist(filename) == NULL) {
+ char real_filename[PATH_MAX + 1];
+ memset(real_filename, 0, sizeof(real_filename));
+ strncat(real_filename, srctree, PATH_MAX);
+ strncat(real_filename, "/", PATH_MAX - strlen(real_filename));
+ strncat(real_filename, filename,
+ PATH_MAX - strlen(real_filename));
+ sym = add_new_file(filename);
+ fp = fopen(real_filename, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "docproc: ");
+ perror(real_filename);
+ exit(1);
+ }
+ while (fgets(line, MAXLINESZ, fp)) {
+ char *p;
+ char *e;
+ if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != NULL) ||
+ ((p = strstr(line, "EXPORT_SYMBOL")) != NULL)) {
+ /* Skip EXPORT_SYMBOL{_GPL} */
+ while (isalnum(*p) || *p == '_')
+ p++;
+ /* Remove parentheses & additional whitespace */
+ while (isspace(*p))
+ p++;
+ if (*p != '(')
+ continue; /* Syntax error? */
+ else
+ p++;
+ while (isspace(*p))
+ p++;
+ e = p;
+ while (isalnum(*e) || *e == '_')
+ e++;
+ *e = '\0';
+ add_new_symbol(sym, p);
+ }
+ }
+ fclose(fp);
+ }
+}
+
+/*
+ * Document all external or internal functions in a file.
+ * Call kernel-doc with following parameters:
+ * kernel-doc -docbook -nofunction function_name1 filename
+ * Function names are obtained from all the src files
+ * by find_export_symbols.
+ * intfunc uses -nofunction
+ * extfunc uses -function
+ */
+static void docfunctions(char * filename, char * type)
+{
+ int i,j;
+ int symcnt = 0;
+ int idx = 0;
+ char **vec;
+
+ for (i=0; i <= symfilecnt; i++)
+ symcnt += symfilelist[i].symbolcnt;
+ vec = malloc((2 + 2 * symcnt + 3) * sizeof(char *));
+ if (vec == NULL) {
+ perror("docproc: ");
+ exit(1);
+ }
+ vec[idx++] = KERNELDOC;
+ vec[idx++] = DOCBOOK;
+ vec[idx++] = NODOCSECTIONS;
+ for (i=0; i < symfilecnt; i++) {
+ struct symfile * sym = &symfilelist[i];
+ for (j=0; j < sym->symbolcnt; j++) {
+ vec[idx++] = type;
+ consume_symbol(sym->symbollist[j].name);
+ vec[idx++] = sym->symbollist[j].name;
+ }
+ }
+ vec[idx++] = filename;
+ vec[idx] = NULL;
+ printf("<!-- %s -->\n", filename);
+ exec_kernel_doc(vec);
+ fflush(stdout);
+ free(vec);
+}
+static void intfunc(char * filename) { docfunctions(filename, NOFUNCTION); }
+static void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
+
+/*
+ * Document specific function(s) in a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function function1 [-function function2]
+ */
+static void singfunc(char * filename, char * line)
+{
+ char *vec[200]; /* Enough for specific functions */
+ int i, idx = 0;
+ int startofsym = 1;
+ vec[idx++] = KERNELDOC;
+ vec[idx++] = DOCBOOK;
+
+ /* Split line up in individual parameters preceded by FUNCTION */
+ for (i=0; line[i]; i++) {
+ if (isspace(line[i])) {
+ line[i] = '\0';
+ startofsym = 1;
+ continue;
+ }
+ if (startofsym) {
+ startofsym = 0;
+ vec[idx++] = FUNCTION;
+ vec[idx++] = &line[i];
+ }
+ }
+ for (i = 0; i < idx; i++) {
+ if (strcmp(vec[i], FUNCTION))
+ continue;
+ consume_symbol(vec[i + 1]);
+ }
+ vec[idx++] = filename;
+ vec[idx] = NULL;
+ exec_kernel_doc(vec);
+}
+
+/*
+ * Insert specific documentation section from a file.
+ * Call kernel-doc with the following parameters:
+ * kernel-doc -docbook -function "doc section" filename
+ */
+static void docsect(char *filename, char *line)
+{
+ char *vec[6]; /* kerneldoc -docbook -function "section" file NULL */
+ char *s;
+
+ for (s = line; *s; s++)
+ if (*s == '\n')
+ *s = '\0';
+
+ if (asprintf(&s, "DOC: %s", line) < 0) {
+ perror("asprintf");
+ exit(1);
+ }
+ consume_symbol(s);
+ free(s);
+
+ vec[0] = KERNELDOC;
+ vec[1] = DOCBOOK;
+ vec[2] = FUNCTION;
+ vec[3] = line;
+ vec[4] = filename;
+ vec[5] = NULL;
+ exec_kernel_doc(vec);
+}
+
+static void find_all_symbols(char *filename)
+{
+ char *vec[4]; /* kerneldoc -list file NULL */
+ pid_t pid;
+ int ret, i, count, start;
+ char real_filename[PATH_MAX + 1];
+ int pipefd[2];
+ char *data, *str;
+ size_t data_len = 0;
+
+ vec[0] = KERNELDOC;
+ vec[1] = LIST;
+ vec[2] = filename;
+ vec[3] = NULL;
+
+ if (pipe(pipefd)) {
+ perror("pipe");
+ exit(1);
+ }
+
+ switch (pid=fork()) {
+ case -1:
+ perror("fork");
+ exit(1);
+ case 0:
+ close(pipefd[0]);
+ dup2(pipefd[1], 1);
+ memset(real_filename, 0, sizeof(real_filename));
+ strncat(real_filename, kernsrctree, PATH_MAX);
+ strncat(real_filename, "/" KERNELDOCPATH KERNELDOC,
+ PATH_MAX - strlen(real_filename));
+ execvp(real_filename, vec);
+ fprintf(stderr, "exec ");
+ perror(real_filename);
+ exit(1);
+ default:
+ close(pipefd[1]);
+ data = malloc(4096);
+ do {
+ while ((ret = read(pipefd[0],
+ data + data_len,
+ 4096)) > 0) {
+ data_len += ret;
+ data = realloc(data, data_len + 4096);
+ }
+ } while (ret == -EAGAIN);
+ if (ret != 0) {
+ perror("read");
+ exit(1);
+ }
+ waitpid(pid, &ret ,0);
+ }
+ if (WIFEXITED(ret))
+ exitstatus |= WEXITSTATUS(ret);
+ else
+ exitstatus = 0xff;
+
+ count = 0;
+ /* poor man's strtok, but with counting */
+ for (i = 0; i < data_len; i++) {
+ if (data[i] == '\n') {
+ count++;
+ data[i] = '\0';
+ }
+ }
+ start = all_list_len;
+ all_list_len += count;
+ all_list = realloc(all_list, sizeof(char *) * all_list_len);
+ str = data;
+ for (i = 0; i < data_len && start != all_list_len; i++) {
+ if (data[i] == '\0') {
+ all_list[start] = str;
+ str = data + i + 1;
+ start++;
+ }
+ }
+}
+
+/*
+ * Parse file, calling action specific functions for:
+ * 1) Lines containing !E
+ * 2) Lines containing !I
+ * 3) Lines containing !D
+ * 4) Lines containing !F
+ * 5) Lines containing !P
+ * 6) Lines containing !C
+ * 7) Default lines - lines not matching the above
+ */
+static void parse_file(FILE *infile)
+{
+ char line[MAXLINESZ];
+ char * s;
+ while (fgets(line, MAXLINESZ, infile)) {
+ if (line[0] == '!') {
+ s = line + 2;
+ switch (line[1]) {
+ case 'E':
+ while (*s && !isspace(*s)) s++;
+ *s = '\0';
+ externalfunctions(line+2);
+ break;
+ case 'I':
+ while (*s && !isspace(*s)) s++;
+ *s = '\0';
+ internalfunctions(line+2);
+ break;
+ case 'D':
+ while (*s && !isspace(*s)) s++;
+ *s = '\0';
+ symbolsonly(line+2);
+ break;
+ case 'F':
+ /* filename */
+ while (*s && !isspace(*s)) s++;
+ *s++ = '\0';
+ /* function names */
+ while (isspace(*s))
+ s++;
+ singlefunctions(line +2, s);
+ break;
+ case 'P':
+ /* filename */
+ while (*s && !isspace(*s)) s++;
+ *s++ = '\0';
+ /* DOC: section name */
+ while (isspace(*s))
+ s++;
+ docsection(line + 2, s);
+ break;
+ case 'C':
+ while (*s && !isspace(*s)) s++;
+ *s = '\0';
+ if (findall)
+ findall(line+2);
+ break;
+ default:
+ defaultline(line);
+ }
+ } else {
+ defaultline(line);
+ }
+ }
+ fflush(stdout);
+}
+
+
+int main(int argc, char *argv[])
+{
+ FILE * infile;
+ int i;
+
+ srctree = getenv("SRCTREE");
+ if (!srctree)
+ srctree = getcwd(NULL, 0);
+ kernsrctree = getenv("KBUILD_SRC");
+ if (!kernsrctree || !*kernsrctree)
+ kernsrctree = srctree;
+ if (argc != 3) {
+ usage();
+ exit(1);
+ }
+ /* Open file, exit on error */
+ infile = fopen(argv[2], "r");
+ if (infile == NULL) {
+ fprintf(stderr, "docproc: ");
+ perror(argv[2]);
+ exit(2);
+ }
+
+ if (strcmp("doc", argv[1]) == 0) {
+ /* Need to do this in two passes.
+ * First pass is used to collect all symbols exported
+ * in the various files;
+ * Second pass generate the documentation.
+ * This is required because some functions are declared
+ * and exported in different files :-((
+ */
+ /* Collect symbols */
+ defaultline = noaction;
+ internalfunctions = find_export_symbols;
+ externalfunctions = find_export_symbols;
+ symbolsonly = find_export_symbols;
+ singlefunctions = noaction2;
+ docsection = noaction2;
+ findall = find_all_symbols;
+ parse_file(infile);
+
+ /* Rewind to start from beginning of file again */
+ fseek(infile, 0, SEEK_SET);
+ defaultline = printline;
+ internalfunctions = intfunc;
+ externalfunctions = extfunc;
+ symbolsonly = printline;
+ singlefunctions = singfunc;
+ docsection = docsect;
+ findall = NULL;
+
+ parse_file(infile);
+
+ for (i = 0; i < all_list_len; i++) {
+ if (!all_list[i])
+ continue;
+ fprintf(stderr, "Warning: didn't use docs for %s\n",
+ all_list[i]);
+ }
+ } else if (strcmp("depend", argv[1]) == 0) {
+ /* Create first part of dependency chain
+ * file.tmpl */
+ printf("%s\t", argv[2]);
+ defaultline = noaction;
+ internalfunctions = adddep;
+ externalfunctions = adddep;
+ symbolsonly = adddep;
+ singlefunctions = adddep2;
+ docsection = adddep2;
+ findall = adddep;
+ parse_file(infile);
+ printf("\n");
+ } else {
+ fprintf(stderr, "Unknown option: %s\n", argv[1]);
+ exit(1);
+ }
+ fclose(infile);
+ fflush(stdout);
+ return exitstatus;
+}
diff --git a/tools/kernel-doc/kernel-doc b/tools/kernel-doc/kernel-doc
new file mode 100755
index 0000000..6347418
--- /dev/null
+++ b/tools/kernel-doc/kernel-doc
@@ -0,0 +1,2557 @@
+#!/usr/bin/perl -w
+
+use strict;
+
+## Copyright (c) 1998 Michael Zucchi, All Rights Reserved ##
+## Copyright (C) 2000, 1 Tim Waugh <twaugh@redhat.com> ##
+## Copyright (C) 2001 Simon Huggins ##
+## Copyright (C) 2005-2012 Randy Dunlap ##
+## Copyright (C) 2012 Dan Luedtke ##
+## ##
+## #define enhancements by Armin Kuster <akuster@mvista.com> ##
+## Copyright (c) 2000 MontaVista Software, Inc. ##
+## ##
+## This software falls under the GNU General Public License. ##
+## Please read the COPYING file for more information ##
+
+# 18/01/2001 - Cleanups
+# Functions prototyped as foo(void) same as foo()
+# Stop eval'ing where we don't need to.
+# -- huggie@earth.li
+
+# 27/06/2001 - Allowed whitespace after initial "/**" and
+# allowed comments before function declarations.
+# -- Christian Kreibich <ck@whoop.org>
+
+# Still to do:
+# - add perldoc documentation
+# - Look more closely at some of the scarier bits :)
+
+# 26/05/2001 - Support for separate source and object trees.
+# Return error code.
+# Keith Owens <kaos@ocs.com.au>
+
+# 23/09/2001 - Added support for typedefs, structs, enums and unions
+# Support for Context section; can be terminated using empty line
+# Small fixes (like spaces vs. \s in regex)
+# -- Tim Jansen <tim@tjansen.de>
+
+# 25/07/2012 - Added support for HTML5
+# -- Dan Luedtke <mail@danrl.de>
+
+#
+# This will read a 'c' file and scan for embedded comments in the
+# style of gnome comments (+minor extensions - see below).
+#
+
+# Note: This only supports 'c'.
+
+# usage:
+# kernel-doc [ -docbook | -html | -html5 | -text | -man | -list ]
+# [ -no-doc-sections ]
+# [ -function funcname [ -function funcname ...] ]
+# c file(s)s > outputfile
+# or
+# [ -nofunction funcname [ -function funcname ...] ]
+# c file(s)s > outputfile
+#
+# Set output format using one of -docbook -html -html5 -text or -man.
+# Default is man.
+# The -list format is for internal use by docproc.
+#
+# -no-doc-sections
+# Do not output DOC: sections
+#
+# -function funcname
+# If set, then only generate documentation for the given function(s) or
+# DOC: section titles. All other functions and DOC: sections are ignored.
+#
+# -nofunction funcname
+# If set, then only generate documentation for the other function(s)/DOC:
+# sections. Cannot be used together with -function (yes, that's a bug --
+# perl hackers can fix it 8))
+#
+# c files - list of 'c' files to process
+#
+# All output goes to stdout, with errors to stderr.
+
+#
+# format of comments.
+# In the following table, (...)? signifies optional structure.
+# (...)* signifies 0 or more structure elements
+# /**
+# * function_name(:)? (- short description)?
+# (* @parameterx: (description of parameter x)?)*
+# (* a blank line)?
+# * (Description:)? (Description of function)?
+# * (section header: (section description)? )*
+# (*)?*/
+#
+# So .. the trivial example would be:
+#
+# /**
+# * my_function
+# */
+#
+# If the Description: header tag is omitted, then there must be a blank line
+# after the last parameter specification.
+# e.g.
+# /**
+# * my_function - does my stuff
+# * @my_arg: its mine damnit
+# *
+# * Does my stuff explained.
+# */
+#
+# or, could also use:
+# /**
+# * my_function - does my stuff
+# * @my_arg: its mine damnit
+# * Description: Does my stuff explained.
+# */
+# etc.
+#
+# Besides functions you can also write documentation for structs, unions,
+# enums and typedefs. Instead of the function name you must write the name
+# of the declaration; the struct/union/enum/typedef must always precede
+# the name. Nesting of declarations is not supported.
+# Use the argument mechanism to document members or constants.
+# e.g.
+# /**
+# * struct my_struct - short description
+# * @a: first member
+# * @b: second member
+# *
+# * Longer description
+# */
+# struct my_struct {
+# int a;
+# int b;
+# /* private: */
+# int c;
+# };
+#
+# All descriptions can be multiline, except the short function description.
+#
+# You can also add additional sections. When documenting kernel functions you
+# should document the "Context:" of the function, e.g. whether the functions
+# can be called form interrupts. Unlike other sections you can end it with an
+# empty line.
+# Example-sections should contain the string EXAMPLE so that they are marked
+# appropriately in DocBook.
+#
+# Example:
+# /**
+# * user_function - function that can only be called in user context
+# * @a: some argument
+# * Context: !in_interrupt()
+# *
+# * Some description
+# * Example:
+# * user_function(22);
+# */
+# ...
+#
+#
+# All descriptive text is further processed, scanning for the following special
+# patterns, which are highlighted appropriately.
+#
+# 'funcname()' - function
+# '$ENVVAR' - environmental variable
+# '&struct_name' - name of a structure (up to two words including 'struct')
+# '@parameter' - name of a parameter
+# '%CONST' - name of a constant.
+
+## init lots of data
+
+my $errors = 0;
+my $warnings = 0;
+my $anon_struct_union = 0;
+
+# match expressions used to find embedded type information
+my $type_constant = '\%([-_\w]+)';
+my $type_func = '(\w+)\(\)';
+my $type_param = '\@(\w+)';
+my $type_struct = '\&((struct\s*)*[_\w]+)';
+my $type_struct_xml = '\\&amp;((struct\s*)*[_\w]+)';
+my $type_env = '(\$\w+)';
+
+# Output conversion substitutions.
+# One for each output format
+
+# these work fairly well
+my %highlights_html = ( $type_constant, "<i>\$1</i>",
+ $type_func, "<b>\$1</b>",
+ $type_struct_xml, "<i>\$1</i>",
+ $type_env, "<b><i>\$1</i></b>",
+ $type_param, "<tt><b>\$1</b></tt>" );
+my $local_lt = "\\\\\\\\lt:";
+my $local_gt = "\\\\\\\\gt:";
+my $blankline_html = $local_lt . "p" . $local_gt; # was "<p>"
+
+# html version 5
+my %highlights_html5 = ( $type_constant, "<span class=\"const\">\$1</span>",
+ $type_func, "<span class=\"func\">\$1</span>",
+ $type_struct_xml, "<span class=\"struct\">\$1</span>",
+ $type_env, "<span class=\"env\">\$1</span>",
+ $type_param, "<span class=\"param\">\$1</span>" );
+my $blankline_html5 = $local_lt . "br /" . $local_gt;
+
+# XML, docbook format
+my %highlights_xml = ( "([^=])\\\"([^\\\"<]+)\\\"", "\$1<quote>\$2</quote>",
+ $type_constant, "<constant>\$1</constant>",
+ $type_func, "<function>\$1</function>",
+ $type_struct_xml, "<structname>\$1</structname>",
+ $type_env, "<envar>\$1</envar>",
+ $type_param, "<parameter>\$1</parameter>" );
+my $blankline_xml = $local_lt . "/para" . $local_gt . $local_lt . "para" . $local_gt . "\n";
+
+# gnome, docbook format
+my %highlights_gnome = ( $type_constant, "<replaceable class=\"option\">\$1</replaceable>",
+ $type_func, "<function>\$1</function>",
+ $type_struct, "<structname>\$1</structname>",
+ $type_env, "<envar>\$1</envar>",
+ $type_param, "<parameter>\$1</parameter>" );
+my $blankline_gnome = "</para><para>\n";
+
+# these are pretty rough
+my %highlights_man = ( $type_constant, "\$1",
+ $type_func, "\\\\fB\$1\\\\fP",
+ $type_struct, "\\\\fI\$1\\\\fP",
+ $type_param, "\\\\fI\$1\\\\fP" );
+my $blankline_man = "";
+
+# text-mode
+my %highlights_text = ( $type_constant, "\$1",
+ $type_func, "\$1",
+ $type_struct, "\$1",
+ $type_param, "\$1" );
+my $blankline_text = "";
+
+# list mode
+my %highlights_list = ( $type_constant, "\$1",
+ $type_func, "\$1",
+ $type_struct, "\$1",
+ $type_param, "\$1" );
+my $blankline_list = "";
+
+# read arguments
+if ($#ARGV == -1) {
+ usage();
+}
+
+my $kernelversion;
+my $dohighlight = "";
+
+my $verbose = 0;
+my $output_mode = "man";
+my $no_doc_sections = 0;
+my %highlights = %highlights_man;
+my $blankline = $blankline_man;
+my $modulename = "Bootloader API";
+my $function_only = 0;
+my $man_date = ('January', 'February', 'March', 'April', 'May', 'June',
+ 'July', 'August', 'September', 'October',
+ 'November', 'December')[(localtime)[4]] .
+ " " . ((localtime)[5]+1900);
+
+# Essentially these are globals.
+# They probably want to be tidied up, made more localised or something.
+# CAVEAT EMPTOR! Some of the others I localised may not want to be, which
+# could cause "use of undefined value" or other bugs.
+my ($function, %function_table, %parametertypes, $declaration_purpose);
+my ($type, $declaration_name, $return_type);
+my ($newsection, $newcontents, $prototype, $brcount, %source_map);
+
+if (defined($ENV{'KBUILD_VERBOSE'})) {
+ $verbose = "$ENV{'KBUILD_VERBOSE'}";
+}
+
+# Generated docbook code is inserted in a template at a point where
+# docbook v3.1 requires a non-zero sequence of RefEntry's; see:
+# http://www.oasis-open.org/docbook/documentation/reference/html/refentry.html
+# We keep track of number of generated entries and generate a dummy
+# if needs be to ensure the expanded template can be postprocessed
+# into html.
+my $section_counter = 0;
+
+my $lineprefix="";
+
+# states
+# 0 - normal code
+# 1 - looking for function name
+# 2 - scanning field start.
+# 3 - scanning prototype.
+# 4 - documentation block
+my $state;
+my $in_doc_sect;
+
+#declaration types: can be
+# 'function', 'struct', 'union', 'enum', 'typedef'
+my $decl_type;
+
+my $doc_special = "\@\%\$\&";
+
+my $doc_start = '^/\*\*\s*$'; # Allow whitespace at end of comment start.
+my $doc_end = '\*/';
+my $doc_com = '\s*\*\s*';
+my $doc_decl = $doc_com . '(\w+)';
+my $doc_sect = $doc_com . '([' . $doc_special . ']?[\w\s]+):(.*)';
+my $doc_content = $doc_com . '(.*)';
+my $doc_block = $doc_com . 'DOC:\s*(.*)?';
+
+my %constants;
+my %parameterdescs;
+my @parameterlist;
+my %sections;
+my @sectionlist;
+my $sectcheck;
+my $struct_actual;
+
+my $contents = "";
+my $section_default = "Description"; # default section
+my $section_intro = "Introduction";
+my $section = $section_default;
+my $section_context = "Context";
+
+my $undescribed = "-- undescribed --";
+
+reset_state();
+
+while ($ARGV[0] =~ m/^-(.*)/) {
+ my $cmd = shift @ARGV;
+ if ($cmd eq "-html") {
+ $output_mode = "html";
+ %highlights = %highlights_html;
+ $blankline = $blankline_html;
+ } elsif ($cmd eq "-html5") {
+ $output_mode = "html5";
+ %highlights = %highlights_html5;
+ $blankline = $blankline_html5;
+ } elsif ($cmd eq "-man") {
+ $output_mode = "man";
+ %highlights = %highlights_man;
+ $blankline = $blankline_man;
+ } elsif ($cmd eq "-text") {
+ $output_mode = "text";
+ %highlights = %highlights_text;
+ $blankline = $blankline_text;
+ } elsif ($cmd eq "-docbook") {
+ $output_mode = "xml";
+ %highlights = %highlights_xml;
+ $blankline = $blankline_xml;
+ } elsif ($cmd eq "-list") {
+ $output_mode = "list";
+ %highlights = %highlights_list;
+ $blankline = $blankline_list;
+ } elsif ($cmd eq "-gnome") {
+ $output_mode = "gnome";
+ %highlights = %highlights_gnome;
+ $blankline = $blankline_gnome;
+ } elsif ($cmd eq "-module") { # not needed for XML, inherits from calling document
+ $modulename = shift @ARGV;
+ } elsif ($cmd eq "-function") { # to only output specific functions
+ $function_only = 1;
+ $function = shift @ARGV;
+ $function_table{$function} = 1;
+ } elsif ($cmd eq "-nofunction") { # to only output specific functions
+ $function_only = 2;
+ $function = shift @ARGV;
+ $function_table{$function} = 1;
+ } elsif ($cmd eq "-v") {
+ $verbose = 1;
+ } elsif (($cmd eq "-h") || ($cmd eq "--help")) {
+ usage();
+ } elsif ($cmd eq '-no-doc-sections') {
+ $no_doc_sections = 1;
+ }
+}
+
+# continue execution near EOF;
+
+sub usage {
+ print "Usage: $0 [ -docbook | -html | -html5 | -text | -man | -list ]\n";
+ print " [ -no-doc-sections ]\n";
+ print " [ -function funcname [ -function funcname ...] ]\n";
+ print " [ -nofunction funcname [ -nofunction funcname ...] ]\n";
+ print " [ -v ]\n";
+ print " c source file(s) > outputfile\n";
+ print " -v : verbose output, more warnings & other info listed\n";
+ exit 1;
+}
+
+# get kernel version from env
+sub get_kernel_version() {
+ my $version = 'unknown kernel version';
+
+ if (defined($ENV{'U_BOOT_VERSION'})) {
+ $version = $ENV{'U_BOOT_VERSION'};
+ }
+ return $version;
+}
+
+##
+# dumps section contents to arrays/hashes intended for that purpose.
+#
+sub dump_section {
+ my $file = shift;
+ my $name = shift;
+ my $contents = join "\n", @_;
+
+ if ($name =~ m/$type_constant/) {
+ $name = $1;
+# print STDERR "constant section '$1' = '$contents'\n";
+ $constants{$name} = $contents;
+ } elsif ($name =~ m/$type_param/) {
+# print STDERR "parameter def '$1' = '$contents'\n";
+ $name = $1;
+ $parameterdescs{$name} = $contents;
+ $sectcheck = $sectcheck . $name . " ";
+ } elsif ($name eq "@\.\.\.") {
+# print STDERR "parameter def '...' = '$contents'\n";
+ $name = "...";
+ $parameterdescs{$name} = $contents;
+ $sectcheck = $sectcheck . $name . " ";
+ } else {
+# print STDERR "other section '$name' = '$contents'\n";
+ if (defined($sections{$name}) && ($sections{$name} ne "")) {
+ print STDERR "Error(${file}:$.): duplicate section name '$name'\n";
+ ++$errors;
+ }
+ $sections{$name} = $contents;
+ push @sectionlist, $name;
+ }
+}
+
+##
+# dump DOC: section after checking that it should go out
+#
+sub dump_doc_section {
+ my $file = shift;
+ my $name = shift;
+ my $contents = join "\n", @_;
+
+ if ($no_doc_sections) {
+ return;
+ }
+
+ if (($function_only == 0) ||
+ ( $function_only == 1 && defined($function_table{$name})) ||
+ ( $function_only == 2 && !defined($function_table{$name})))
+ {
+ dump_section($file, $name, $contents);
+ output_blockhead({'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'module' => $modulename,
+ 'content-only' => ($function_only != 0), });
+ }
+}
+
+##
+# output function
+#
+# parameterdescs, a hash.
+# function => "function name"
+# parameterlist => @list of parameters
+# parameterdescs => %parameter descriptions
+# sectionlist => @list of sections
+# sections => %section descriptions
+#
+
+sub output_highlight {
+ my $contents = join "\n",@_;
+ my $line;
+
+# DEBUG
+# if (!defined $contents) {
+# use Carp;
+# confess "output_highlight got called with no args?\n";
+# }
+
+ if ($output_mode eq "html" || $output_mode eq "html5" ||
+ $output_mode eq "xml") {
+ $contents = local_unescape($contents);
+ # convert data read & converted thru xml_escape() into &xyz; format:
+ $contents =~ s/\\\\\\/\&/g;
+ }
+# print STDERR "contents b4:$contents\n";
+ eval $dohighlight;
+ die $@ if $@;
+# print STDERR "contents af:$contents\n";
+
+# strip whitespaces when generating html5
+ if ($output_mode eq "html5") {
+ $contents =~ s/^\s+//;
+ $contents =~ s/\s+$//;
+ }
+ foreach $line (split "\n", $contents) {
+ if ($line eq ""){
+ print $lineprefix, local_unescape($blankline);
+ } else {
+ $line =~ s/\\\\\\/\&/g;
+ if ($output_mode eq "man" && substr($line, 0, 1) eq ".") {
+ print "\\&$line";
+ } else {
+ print $lineprefix, $line;
+ }
+ }
+ print "\n";
+ }
+}
+
+# output sections in html
+sub output_section_html(%) {
+ my %args = %{$_[0]};
+ my $section;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<h3>$section</h3>\n";
+ print "<blockquote>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</blockquote>\n";
+ }
+}
+
+# output enum in html
+sub output_enum_html(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ print "<h2>enum " . $args{'enum'} . "</h2>\n";
+
+ print "<b>enum " . $args{'enum'} . "</b> {<br>\n";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print " <b>" . $parameter . "</b>";
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",\n";
+ }
+ print "<br>";
+ }
+ print "};<br>\n";
+
+ print "<h3>Constants</h3>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<dt><b>" . $parameter . "</b>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter});
+ }
+ print "</dl>\n";
+ output_section_html(@_);
+ print "<hr>\n";
+}
+
+# output typedef in html
+sub output_typedef_html(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ print "<h2>typedef " . $args{'typedef'} . "</h2>\n";
+
+ print "<b>typedef " . $args{'typedef'} . "</b>\n";
+ output_section_html(@_);
+ print "<hr>\n";
+}
+
+# output struct in html
+sub output_struct_html(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+
+ print "<h2>" . $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "</h2>\n";
+ print "<b>" . $args{'type'} . " " . $args{'struct'} . "</b> {<br>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ if ($parameter =~ /^#/) {
+ print "$parameter<br>\n";
+ next;
+ }
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "&nbsp; &nbsp; <i>$1</i><b>$parameter</b>) <i>($2)</i>;<br>\n";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print "&nbsp; &nbsp; <i>$1</i> <b>$parameter</b>$2;<br>\n";
+ } else {
+ print "&nbsp; &nbsp; <i>$type</i> <b>$parameter</b>;<br>\n";
+ }
+ }
+ print "};<br>\n";
+
+ print "<h3>Members</h3>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt><b>" . $parameter . "</b>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ }
+ print "</dl>\n";
+ output_section_html(@_);
+ print "<hr>\n";
+}
+
+# output function in html
+sub output_function_html(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ print "<h2>" . $args{'function'} . " - " . $args{'purpose'} . "</h2>\n";
+ print "<i>" . $args{'functiontype'} . "</i>\n";
+ print "<b>" . $args{'function'} . "</b>\n";
+ print "(";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "<i>$1</i><b>$parameter</b>) <i>($2)</i>";
+ } else {
+ print "<i>" . $type . "</i> <b>" . $parameter . "</b>";
+ }
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",\n";
+ }
+ }
+ print ")\n";
+
+ print "<h3>Arguments</h3>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt><b>" . $parameter . "</b>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ }
+ print "</dl>\n";
+ output_section_html(@_);
+ print "<hr>\n";
+}
+
+# output DOC: block header in html
+sub output_blockhead_html(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<h3>$section</h3>\n";
+ print "<ul>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</ul>\n";
+ }
+ print "<hr>\n";
+}
+
+# output sections in html5
+sub output_section_html5(%) {
+ my %args = %{$_[0]};
+ my $section;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<section>\n";
+ print "<h1>$section</h1>\n";
+ print "<p>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</p>\n";
+ print "</section>\n";
+ }
+}
+
+# output enum in html5
+sub output_enum_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'enum'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"enum\" id=\"enum:". $html5id . "\">";
+ print "<h1>enum " . $args{'enum'} . "</h1>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"keyword\">enum</span> ";
+ print "<span class=\"identifier\">" . $args{'enum'} . "</span> {";
+ print "</li>\n";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ print "<span class=\"param\">" . $parameter . "</span>";
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "</li>\n";
+ }
+ print "<li>};</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Constants</h1>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output typedef in html5
+sub output_typedef_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'typedef'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"typedef\" id=\"typedef:" . $html5id . "\">\n";
+ print "<h1>typedef " . $args{'typedef'} . "</h1>\n";
+
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"keyword\">typedef</span> ";
+ print "<span class=\"identifier\">" . $args{'typedef'} . "</span>";
+ print "</li>\n";
+ print "</ol>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output struct in html5
+sub output_struct_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $html5id;
+
+ $html5id = $args{'struct'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"struct\" id=\"struct:" . $html5id . "\">\n";
+ print "<hgroup>\n";
+ print "<h1>" . $args{'type'} . " " . $args{'struct'} . "</h1>";
+ print "<h2>". $args{'purpose'} . "</h2>\n";
+ print "</hgroup>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"type\">" . $args{'type'} . "</span> ";
+ print "<span class=\"identifier\">" . $args{'struct'} . "</span> {";
+ print "</li>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ if ($parameter =~ /^#/) {
+ print "<span class=\"param\">" . $parameter ."</span>\n";
+ print "</li>\n";
+ next;
+ }
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"type\">)</span> ";
+ print "(<span class=\"args\">$2</span>);";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"bits\">$2</span>;";
+ } else {
+ print "<span class=\"type\">$type</span> ";
+ print "<span class=\"param\">$parameter</span>;";
+ }
+ print "</li>\n";
+ }
+ print "<li>};</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Members</h1>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output function in html5
+sub output_function_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $html5id;
+
+ $html5id = $args{'function'};
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"function\" id=\"func:". $html5id . "\">\n";
+ print "<hgroup>\n";
+ print "<h1>" . $args{'function'} . "</h1>";
+ print "<h2>" . $args{'purpose'} . "</h2>\n";
+ print "</hgroup>\n";
+ print "<ol class=\"code\">\n";
+ print "<li>";
+ print "<span class=\"type\">" . $args{'functiontype'} . "</span> ";
+ print "<span class=\"identifier\">" . $args{'function'} . "</span> (";
+ print "</li>";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "<li class=\"indent\">";
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "<span class=\"type\">$1</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ print "<span class=\"type\">)</span> ";
+ print "(<span class=\"args\">$2</span>)";
+ } else {
+ print "<span class=\"type\">$type</span> ";
+ print "<span class=\"param\">$parameter</span>";
+ }
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "</li>\n";
+ }
+ print "<li>)</li>\n";
+ print "</ol>\n";
+
+ print "<section>\n";
+ print "<h1>Arguments</h1>\n";
+ print "<p>\n";
+ print "<dl>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "<dt>" . $parameter . "</dt>\n";
+ print "<dd>";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print "</dd>\n";
+ }
+ print "</dl>\n";
+ print "</section>\n";
+ output_section_html5(@_);
+ print "</article>\n";
+}
+
+# output DOC: block header in html5
+sub output_blockhead_html5(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $html5id;
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ $html5id = $section;
+ $html5id =~ s/[^a-zA-Z0-9\-]+/_/g;
+ print "<article class=\"doc\" id=\"doc:". $html5id . "\">\n";
+ print "<h1>$section</h1>\n";
+ print "<p>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</p>\n";
+ }
+ print "</article>\n";
+}
+
+sub output_section_xml(%) {
+ my %args = %{$_[0]};
+ my $section;
+ # print out each section
+ $lineprefix=" ";
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<refsect1>\n";
+ print "<title>$section</title>\n";
+ if ($section =~ m/EXAMPLE/i) {
+ print "<informalexample><programlisting>\n";
+ } else {
+ print "<para>\n";
+ }
+ output_highlight($args{'sections'}{$section});
+ if ($section =~ m/EXAMPLE/i) {
+ print "</programlisting></informalexample>\n";
+ } else {
+ print "</para>\n";
+ }
+ print "</refsect1>\n";
+ }
+}
+
+# output function in XML DocBook
+sub output_function_xml(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $id;
+
+ $id = "API-" . $args{'function'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ print "<refentry id=\"$id\">\n";
+ print "<refentryinfo>\n";
+ print " <title>U-BOOT</title>\n";
+ print " <productname>Bootloader Hackers Manual</productname>\n";
+ print " <date>$man_date</date>\n";
+ print "</refentryinfo>\n";
+ print "<refmeta>\n";
+ print " <refentrytitle><phrase>" . $args{'function'} . "</phrase></refentrytitle>\n";
+ print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+ print "</refmeta>\n";
+ print "<refnamediv>\n";
+ print " <refname>" . $args{'function'} . "</refname>\n";
+ print " <refpurpose>\n";
+ print " ";
+ output_highlight ($args{'purpose'});
+ print " </refpurpose>\n";
+ print "</refnamediv>\n";
+
+ print "<refsynopsisdiv>\n";
+ print " <title>Synopsis</title>\n";
+ print " <funcsynopsis><funcprototype>\n";
+ print " <funcdef>" . $args{'functiontype'} . " ";
+ print "<function>" . $args{'function'} . " </function></funcdef>\n";
+
+ $count = 0;
+ if ($#{$args{'parameterlist'}} >= 0) {
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print " <paramdef>$1<parameter>$parameter</parameter>)\n";
+ print " <funcparams>$2</funcparams></paramdef>\n";
+ } else {
+ print " <paramdef>" . $type;
+ print " <parameter>$parameter</parameter></paramdef>\n";
+ }
+ }
+ } else {
+ print " <void/>\n";
+ }
+ print " </funcprototype></funcsynopsis>\n";
+ print "</refsynopsisdiv>\n";
+
+ # print parameters
+ print "<refsect1>\n <title>Arguments</title>\n";
+ if ($#{$args{'parameterlist'}} >= 0) {
+ print " <variablelist>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print " <varlistentry>\n <term><parameter>$parameter</parameter></term>\n";
+ print " <listitem>\n <para>\n";
+ $lineprefix=" ";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print " </para>\n </listitem>\n </varlistentry>\n";
+ }
+ print " </variablelist>\n";
+ } else {
+ print " <para>\n None\n </para>\n";
+ }
+ print "</refsect1>\n";
+
+ output_section_xml(@_);
+ print "</refentry>\n\n";
+}
+
+# output struct in XML DocBook
+sub output_struct_xml(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $id;
+
+ $id = "API-struct-" . $args{'struct'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ print "<refentry id=\"$id\">\n";
+ print "<refentryinfo>\n";
+ print " <title>U-BOOT</title>\n";
+ print " <productname>Bootloader Hackers Manual</productname>\n";
+ print " <date>$man_date</date>\n";
+ print "</refentryinfo>\n";
+ print "<refmeta>\n";
+ print " <refentrytitle><phrase>" . $args{'type'} . " " . $args{'struct'} . "</phrase></refentrytitle>\n";
+ print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+ print "</refmeta>\n";
+ print "<refnamediv>\n";
+ print " <refname>" . $args{'type'} . " " . $args{'struct'} . "</refname>\n";
+ print " <refpurpose>\n";
+ print " ";
+ output_highlight ($args{'purpose'});
+ print " </refpurpose>\n";
+ print "</refnamediv>\n";
+
+ print "<refsynopsisdiv>\n";
+ print " <title>Synopsis</title>\n";
+ print " <programlisting>\n";
+ print $args{'type'} . " " . $args{'struct'} . " {\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ if ($parameter =~ /^#/) {
+ my $prm = $parameter;
+ # convert data read & converted thru xml_escape() into &xyz; format:
+ # This allows us to have #define macros interspersed in a struct.
+ $prm =~ s/\\\\\\/\&/g;
+ print "$prm\n";
+ next;
+ }
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ defined($args{'parameterdescs'}{$parameter_name}) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print " $1 $parameter) ($2);\n";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print " $1 $parameter$2;\n";
+ } else {
+ print " " . $type . " " . $parameter . ";\n";
+ }
+ }
+ print "};";
+ print " </programlisting>\n";
+ print "</refsynopsisdiv>\n";
+
+ print " <refsect1>\n";
+ print " <title>Members</title>\n";
+
+ if ($#{$args{'parameterlist'}} >= 0) {
+ print " <variablelist>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ defined($args{'parameterdescs'}{$parameter_name}) || next;
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print " <varlistentry>";
+ print " <term>$parameter</term>\n";
+ print " <listitem><para>\n";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print " </para></listitem>\n";
+ print " </varlistentry>\n";
+ }
+ print " </variablelist>\n";
+ } else {
+ print " <para>\n None\n </para>\n";
+ }
+ print " </refsect1>\n";
+
+ output_section_xml(@_);
+
+ print "</refentry>\n\n";
+}
+
+# output enum in XML DocBook
+sub output_enum_xml(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $id;
+
+ $id = "API-enum-" . $args{'enum'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ print "<refentry id=\"$id\">\n";
+ print "<refentryinfo>\n";
+ print " <title>U-BOOT</title>\n";
+ print " <productname>Bootloader Hackers Manual</productname>\n";
+ print " <date>$man_date</date>\n";
+ print "</refentryinfo>\n";
+ print "<refmeta>\n";
+ print " <refentrytitle><phrase>enum " . $args{'enum'} . "</phrase></refentrytitle>\n";
+ print " <manvolnum>9</manvolnum>\n";
+ print " <refmiscinfo class=\"version\">" . $kernelversion . "</refmiscinfo>\n";
+ print "</refmeta>\n";
+ print "<refnamediv>\n";
+ print " <refname>enum " . $args{'enum'} . "</refname>\n";
+ print " <refpurpose>\n";
+ print " ";
+ output_highlight ($args{'purpose'});
+ print " </refpurpose>\n";
+ print "</refnamediv>\n";
+
+ print "<refsynopsisdiv>\n";
+ print " <title>Synopsis</title>\n";
+ print " <programlisting>\n";
+ print "enum " . $args{'enum'} . " {\n";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print " $parameter";
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "\n";
+ }
+ print "};";
+ print " </programlisting>\n";
+ print "</refsynopsisdiv>\n";
+
+ print "<refsect1>\n";
+ print " <title>Constants</title>\n";
+ print " <variablelist>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print " <varlistentry>";
+ print " <term>$parameter</term>\n";
+ print " <listitem><para>\n";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print " </para></listitem>\n";
+ print " </varlistentry>\n";
+ }
+ print " </variablelist>\n";
+ print "</refsect1>\n";
+
+ output_section_xml(@_);
+
+ print "</refentry>\n\n";
+}
+
+# output typedef in XML DocBook
+sub output_typedef_xml(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $id;
+
+ $id = "API-typedef-" . $args{'typedef'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ print "<refentry id=\"$id\">\n";
+ print "<refentryinfo>\n";
+ print " <title>U-BOOT</title>\n";
+ print " <productname>Bootloader Hackers Manual</productname>\n";
+ print " <date>$man_date</date>\n";
+ print "</refentryinfo>\n";
+ print "<refmeta>\n";
+ print " <refentrytitle><phrase>typedef " . $args{'typedef'} . "</phrase></refentrytitle>\n";
+ print " <manvolnum>9</manvolnum>\n";
+ print "</refmeta>\n";
+ print "<refnamediv>\n";
+ print " <refname>typedef " . $args{'typedef'} . "</refname>\n";
+ print " <refpurpose>\n";
+ print " ";
+ output_highlight ($args{'purpose'});
+ print " </refpurpose>\n";
+ print "</refnamediv>\n";
+
+ print "<refsynopsisdiv>\n";
+ print " <title>Synopsis</title>\n";
+ print " <synopsis>typedef " . $args{'typedef'} . ";</synopsis>\n";
+ print "</refsynopsisdiv>\n";
+
+ output_section_xml(@_);
+
+ print "</refentry>\n\n";
+}
+
+# output in XML DocBook
+sub output_blockhead_xml(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ my $id = $args{'module'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ # print out each section
+ $lineprefix=" ";
+ foreach $section (@{$args{'sectionlist'}}) {
+ if (!$args{'content-only'}) {
+ print "<refsect1>\n <title>$section</title>\n";
+ }
+ if ($section =~ m/EXAMPLE/i) {
+ print "<example><para>\n";
+ } else {
+ print "<para>\n";
+ }
+ output_highlight($args{'sections'}{$section});
+ if ($section =~ m/EXAMPLE/i) {
+ print "</para></example>\n";
+ } else {
+ print "</para>";
+ }
+ if (!$args{'content-only'}) {
+ print "\n</refsect1>\n";
+ }
+ }
+
+ print "\n\n";
+}
+
+# output in XML DocBook
+sub output_function_gnome {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+ my $id;
+
+ $id = $args{'module'} . "-" . $args{'function'};
+ $id =~ s/[^A-Za-z0-9]/-/g;
+
+ print "<sect2>\n";
+ print " <title id=\"$id\">" . $args{'function'} . "</title>\n";
+
+ print " <funcsynopsis>\n";
+ print " <funcdef>" . $args{'functiontype'} . " ";
+ print "<function>" . $args{'function'} . " ";
+ print "</function></funcdef>\n";
+
+ $count = 0;
+ if ($#{$args{'parameterlist'}} >= 0) {
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print " <paramdef>$1 <parameter>$parameter</parameter>)\n";
+ print " <funcparams>$2</funcparams></paramdef>\n";
+ } else {
+ print " <paramdef>" . $type;
+ print " <parameter>$parameter</parameter></paramdef>\n";
+ }
+ }
+ } else {
+ print " <void>\n";
+ }
+ print " </funcsynopsis>\n";
+ if ($#{$args{'parameterlist'}} >= 0) {
+ print " <informaltable pgwide=\"1\" frame=\"none\" role=\"params\">\n";
+ print "<tgroup cols=\"2\">\n";
+ print "<colspec colwidth=\"2*\">\n";
+ print "<colspec colwidth=\"8*\">\n";
+ print "<tbody>\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print " <row><entry align=\"right\"><parameter>$parameter</parameter></entry>\n";
+ print " <entry>\n";
+ $lineprefix=" ";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ print " </entry></row>\n";
+ }
+ print " </tbody></tgroup></informaltable>\n";
+ } else {
+ print " <para>\n None\n </para>\n";
+ }
+
+ # print out each section
+ $lineprefix=" ";
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "<simplesect>\n <title>$section</title>\n";
+ if ($section =~ m/EXAMPLE/i) {
+ print "<example><programlisting>\n";
+ } else {
+ }
+ print "<para>\n";
+ output_highlight($args{'sections'}{$section});
+ print "</para>\n";
+ if ($section =~ m/EXAMPLE/i) {
+ print "</programlisting></example>\n";
+ } else {
+ }
+ print " </simplesect>\n";
+ }
+
+ print "</sect2>\n\n";
+}
+
+##
+# output function in man
+sub output_function_man(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ print ".TH \"$args{'function'}\" 9 \"$args{'function'}\" \"$man_date\" \"Bootloader Hacker's Manual\" U-BOOT\n";
+
+ print ".SH NAME\n";
+ print $args{'function'} . " \\- " . $args{'purpose'} . "\n";
+
+ print ".SH SYNOPSIS\n";
+ if ($args{'functiontype'} ne "") {
+ print ".B \"" . $args{'functiontype'} . "\" " . $args{'function'} . "\n";
+ } else {
+ print ".B \"" . $args{'function'} . "\n";
+ }
+ $count = 0;
+ my $parenth = "(";
+ my $post = ",";
+ foreach my $parameter (@{$args{'parameterlist'}}) {
+ if ($count == $#{$args{'parameterlist'}}) {
+ $post = ");";
+ }
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print ".BI \"" . $parenth . $1 . "\" " . $parameter . " \") (" . $2 . ")" . $post . "\"\n";
+ } else {
+ $type =~ s/([^\*])$/$1 /;
+ print ".BI \"" . $parenth . $type . "\" " . $parameter . " \"" . $post . "\"\n";
+ }
+ $count++;
+ $parenth = "";
+ }
+
+ print ".SH ARGUMENTS\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print ".IP \"" . $parameter . "\" 12\n";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ }
+ foreach $section (@{$args{'sectionlist'}}) {
+ print ".SH \"", uc $section, "\"\n";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+##
+# output enum in man
+sub output_enum_man(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ print ".TH \"$args{'module'}\" 9 \"enum $args{'enum'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+ print ".SH NAME\n";
+ print "enum " . $args{'enum'} . " \\- " . $args{'purpose'} . "\n";
+
+ print ".SH SYNOPSIS\n";
+ print "enum " . $args{'enum'} . " {\n";
+ $count = 0;
+ foreach my $parameter (@{$args{'parameterlist'}}) {
+ print ".br\n.BI \" $parameter\"\n";
+ if ($count == $#{$args{'parameterlist'}}) {
+ print "\n};\n";
+ last;
+ }
+ else {
+ print ", \n.br\n";
+ }
+ $count++;
+ }
+
+ print ".SH Constants\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print ".IP \"" . $parameter . "\" 12\n";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ }
+ foreach $section (@{$args{'sectionlist'}}) {
+ print ".SH \"$section\"\n";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+##
+# output struct in man
+sub output_struct_man(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+
+ print ".TH \"$args{'module'}\" 9 \"" . $args{'type'} . " " . $args{'struct'} . "\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+ print ".SH NAME\n";
+ print $args{'type'} . " " . $args{'struct'} . " \\- " . $args{'purpose'} . "\n";
+
+ print ".SH SYNOPSIS\n";
+ print $args{'type'} . " " . $args{'struct'} . " {\n.br\n";
+
+ foreach my $parameter (@{$args{'parameterlist'}}) {
+ if ($parameter =~ /^#/) {
+ print ".BI \"$parameter\"\n.br\n";
+ next;
+ }
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print ".BI \" " . $1 . "\" " . $parameter . " \") (" . $2 . ")" . "\"\n;\n";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print ".BI \" " . $1 . "\ \" " . $parameter . $2 . " \"" . "\"\n;\n";
+ } else {
+ $type =~ s/([^\*])$/$1 /;
+ print ".BI \" " . $type . "\" " . $parameter . " \"" . "\"\n;\n";
+ }
+ print "\n.br\n";
+ }
+ print "};\n.br\n";
+
+ print ".SH Members\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print ".IP \"" . $parameter . "\" 12\n";
+ output_highlight($args{'parameterdescs'}{$parameter_name});
+ }
+ foreach $section (@{$args{'sectionlist'}}) {
+ print ".SH \"$section\"\n";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+##
+# output typedef in man
+sub output_typedef_man(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+
+ print ".TH \"$args{'module'}\" 9 \"$args{'typedef'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+ print ".SH NAME\n";
+ print "typedef " . $args{'typedef'} . " \\- " . $args{'purpose'} . "\n";
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print ".SH \"$section\"\n";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+sub output_blockhead_man(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $count;
+
+ print ".TH \"$args{'module'}\" 9 \"$args{'module'}\" \"$man_date\" \"API Manual\" U-BOOT\n";
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print ".SH \"$section\"\n";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+##
+# output in text
+sub output_function_text(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+ my $start;
+
+ print "Name:\n\n";
+ print $args{'function'} . " - " . $args{'purpose'} . "\n";
+
+ print "\nSynopsis:\n\n";
+ if ($args{'functiontype'} ne "") {
+ $start = $args{'functiontype'} . " " . $args{'function'} . " (";
+ } else {
+ $start = $args{'function'} . " (";
+ }
+ print $start;
+
+ my $count = 0;
+ foreach my $parameter (@{$args{'parameterlist'}}) {
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print $1 . $parameter . ") (" . $2;
+ } else {
+ print $type . " " . $parameter;
+ }
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",\n";
+ print " " x length($start);
+ } else {
+ print ");\n\n";
+ }
+ }
+
+ print "Arguments:\n\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ print $parameter . "\n\t" . $args{'parameterdescs'}{$parameter_name} . "\n";
+ }
+ output_section_text(@_);
+}
+
+#output sections in text
+sub output_section_text(%) {
+ my %args = %{$_[0]};
+ my $section;
+
+ print "\n";
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "$section:\n\n";
+ output_highlight($args{'sections'}{$section});
+ }
+ print "\n\n";
+}
+
+# output enum in text
+sub output_enum_text(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ print "Enum:\n\n";
+
+ print "enum " . $args{'enum'} . " - " . $args{'purpose'} . "\n\n";
+ print "enum " . $args{'enum'} . " {\n";
+ $count = 0;
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "\t$parameter";
+ if ($count != $#{$args{'parameterlist'}}) {
+ $count++;
+ print ",";
+ }
+ print "\n";
+ }
+ print "};\n\n";
+
+ print "Constants:\n\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ print "$parameter\n\t";
+ print $args{'parameterdescs'}{$parameter} . "\n";
+ }
+
+ output_section_text(@_);
+}
+
+# output typedef in text
+sub output_typedef_text(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+ my $count;
+ print "Typedef:\n\n";
+
+ print "typedef " . $args{'typedef'} . " - " . $args{'purpose'} . "\n";
+ output_section_text(@_);
+}
+
+# output struct as text
+sub output_struct_text(%) {
+ my %args = %{$_[0]};
+ my ($parameter);
+
+ print $args{'type'} . " " . $args{'struct'} . " - " . $args{'purpose'} . "\n\n";
+ print $args{'type'} . " " . $args{'struct'} . " {\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ if ($parameter =~ /^#/) {
+ print "$parameter\n";
+ next;
+ }
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ $type = $args{'parametertypes'}{$parameter};
+ if ($type =~ m/([^\(]*\(\*)\s*\)\s*\(([^\)]*)\)/) {
+ # pointer-to-function
+ print "\t$1 $parameter) ($2);\n";
+ } elsif ($type =~ m/^(.*?)\s*(:.*)/) {
+ # bitfield
+ print "\t$1 $parameter$2;\n";
+ } else {
+ print "\t" . $type . " " . $parameter . ";\n";
+ }
+ }
+ print "};\n\n";
+
+ print "Members:\n\n";
+ foreach $parameter (@{$args{'parameterlist'}}) {
+ ($parameter =~ /^#/) && next;
+
+ my $parameter_name = $parameter;
+ $parameter_name =~ s/\[.*//;
+
+ ($args{'parameterdescs'}{$parameter_name} ne $undescribed) || next;
+ print "$parameter\n\t";
+ print $args{'parameterdescs'}{$parameter_name} . "\n";
+ }
+ print "\n";
+ output_section_text(@_);
+}
+
+sub output_blockhead_text(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print " $section:\n";
+ print " -> ";
+ output_highlight($args{'sections'}{$section});
+ }
+}
+
+## list mode output functions
+
+sub output_function_list(%) {
+ my %args = %{$_[0]};
+
+ print $args{'function'} . "\n";
+}
+
+# output enum in list
+sub output_enum_list(%) {
+ my %args = %{$_[0]};
+ print $args{'enum'} . "\n";
+}
+
+# output typedef in list
+sub output_typedef_list(%) {
+ my %args = %{$_[0]};
+ print $args{'typedef'} . "\n";
+}
+
+# output struct as list
+sub output_struct_list(%) {
+ my %args = %{$_[0]};
+
+ print $args{'struct'} . "\n";
+}
+
+sub output_blockhead_list(%) {
+ my %args = %{$_[0]};
+ my ($parameter, $section);
+
+ foreach $section (@{$args{'sectionlist'}}) {
+ print "DOC: $section\n";
+ }
+}
+
+##
+# generic output function for all types (function, struct/union, typedef, enum);
+# calls the generated, variable output_ function name based on
+# functype and output_mode
+sub output_declaration {
+ no strict 'refs';
+ my $name = shift;
+ my $functype = shift;
+ my $func = "output_${functype}_$output_mode";
+ if (($function_only==0) ||
+ ( $function_only == 1 && defined($function_table{$name})) ||
+ ( $function_only == 2 && !defined($function_table{$name})))
+ {
+ &$func(@_);
+ $section_counter++;
+ }
+}
+
+##
+# generic output function - calls the right one based on current output mode.
+sub output_blockhead {
+ no strict 'refs';
+ my $func = "output_blockhead_" . $output_mode;
+ &$func(@_);
+ $section_counter++;
+}
+
+##
+# takes a declaration (struct, union, enum, typedef) and
+# invokes the right handler. NOT called for functions.
+sub dump_declaration($$) {
+ no strict 'refs';
+ my ($prototype, $file) = @_;
+ my $func = "dump_" . $decl_type;
+ &$func(@_);
+}
+
+sub dump_union($$) {
+ dump_struct(@_);
+}
+
+sub dump_struct($$) {
+ my $x = shift;
+ my $file = shift;
+ my $nested;
+
+ if ($x =~ /(struct|union)\s+(\w+)\s*{(.*)}/) {
+ #my $decl_type = $1;
+ $declaration_name = $2;
+ my $members = $3;
+
+ # ignore embedded structs or unions
+ $members =~ s/({.*})//g;
+ $nested = $1;
+
+ # ignore members marked private:
+ $members =~ s/\/\*\s*private:.*?\/\*\s*public:.*?\*\///gos;
+ $members =~ s/\/\*\s*private:.*//gos;
+ # strip comments:
+ $members =~ s/\/\*.*?\*\///gos;
+ $nested =~ s/\/\*.*?\*\///gos;
+ # strip kmemcheck_bitfield_{begin,end}.*;
+ $members =~ s/kmemcheck_bitfield_.*?;//gos;
+ # strip attributes
+ $members =~ s/__aligned\s*\(\d+\)//gos;
+
+ create_parameterlist($members, ';', $file);
+ check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
+
+ output_declaration($declaration_name,
+ 'struct',
+ {'struct' => $declaration_name,
+ 'module' => $modulename,
+ 'parameterlist' => \@parameterlist,
+ 'parameterdescs' => \%parameterdescs,
+ 'parametertypes' => \%parametertypes,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose,
+ 'type' => $decl_type
+ });
+ }
+ else {
+ print STDERR "Error(${file}:$.): Cannot parse struct or union!\n";
+ ++$errors;
+ }
+}
+
+sub dump_enum($$) {
+ my $x = shift;
+ my $file = shift;
+
+ $x =~ s@/\*.*?\*/@@gos; # strip comments.
+ $x =~ s/^#\s*define\s+.*$//; # strip #define macros inside enums
+
+ if ($x =~ /enum\s+(\w+)\s*{(.*)}/) {
+ $declaration_name = $1;
+ my $members = $2;
+
+ foreach my $arg (split ',', $members) {
+ $arg =~ s/^\s*(\w+).*/$1/;
+ push @parameterlist, $arg;
+ if (!$parameterdescs{$arg}) {
+ $parameterdescs{$arg} = $undescribed;
+ print STDERR "Warning(${file}:$.): Enum value '$arg' ".
+ "not described in enum '$declaration_name'\n";
+ }
+
+ }
+
+ output_declaration($declaration_name,
+ 'enum',
+ {'enum' => $declaration_name,
+ 'module' => $modulename,
+ 'parameterlist' => \@parameterlist,
+ 'parameterdescs' => \%parameterdescs,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose
+ });
+ }
+ else {
+ print STDERR "Error(${file}:$.): Cannot parse enum!\n";
+ ++$errors;
+ }
+}
+
+sub dump_typedef($$) {
+ my $x = shift;
+ my $file = shift;
+
+ $x =~ s@/\*.*?\*/@@gos; # strip comments.
+ while (($x =~ /\(*.\)\s*;$/) || ($x =~ /\[*.\]\s*;$/)) {
+ $x =~ s/\(*.\)\s*;$/;/;
+ $x =~ s/\[*.\]\s*;$/;/;
+ }
+
+ if ($x =~ /typedef.*\s+(\w+)\s*;/) {
+ $declaration_name = $1;
+
+ output_declaration($declaration_name,
+ 'typedef',
+ {'typedef' => $declaration_name,
+ 'module' => $modulename,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose
+ });
+ }
+ else {
+ print STDERR "Error(${file}:$.): Cannot parse typedef!\n";
+ ++$errors;
+ }
+}
+
+sub save_struct_actual($) {
+ my $actual = shift;
+
+ # strip all spaces from the actual param so that it looks like one string item
+ $actual =~ s/\s*//g;
+ $struct_actual = $struct_actual . $actual . " ";
+}
+
+sub create_parameterlist($$$) {
+ my $args = shift;
+ my $splitter = shift;
+ my $file = shift;
+ my $type;
+ my $param;
+
+ # temporarily replace commas inside function pointer definition
+ while ($args =~ /(\([^\),]+),/) {
+ $args =~ s/(\([^\),]+),/$1#/g;
+ }
+
+ foreach my $arg (split($splitter, $args)) {
+ # strip comments
+ $arg =~ s/\/\*.*\*\///;
+ # strip leading/trailing spaces
+ $arg =~ s/^\s*//;
+ $arg =~ s/\s*$//;
+ $arg =~ s/\s+/ /;
+
+ if ($arg =~ /^#/) {
+ # Treat preprocessor directive as a typeless variable just to fill
+ # corresponding data structures "correctly". Catch it later in
+ # output_* subs.
+ push_parameter($arg, "", $file);
+ } elsif ($arg =~ m/\(.+\)\s*\(/) {
+ # pointer-to-function
+ $arg =~ tr/#/,/;
+ $arg =~ m/[^\(]+\(\*?\s*(\w*)\s*\)/;
+ $param = $1;
+ $type = $arg;
+ $type =~ s/([^\(]+\(\*?)\s*$param/$1/;
+ save_struct_actual($param);
+ push_parameter($param, $type, $file);
+ } elsif ($arg) {
+ $arg =~ s/\s*:\s*/:/g;
+ $arg =~ s/\s*\[/\[/g;
+
+ my @args = split('\s*,\s*', $arg);
+ if ($args[0] =~ m/\*/) {
+ $args[0] =~ s/(\*+)\s*/ $1/;
+ }
+
+ my @first_arg;
+ if ($args[0] =~ /^(.*\s+)(.*?\[.*\].*)$/) {
+ shift @args;
+ push(@first_arg, split('\s+', $1));
+ push(@first_arg, $2);
+ } else {
+ @first_arg = split('\s+', shift @args);
+ }
+
+ unshift(@args, pop @first_arg);
+ $type = join " ", @first_arg;
+
+ foreach $param (@args) {
+ if ($param =~ m/^(\*+)\s*(.*)/) {
+ save_struct_actual($2);
+ push_parameter($2, "$type $1", $file);
+ }
+ elsif ($param =~ m/(.*?):(\d+)/) {
+ if ($type ne "") { # skip unnamed bit-fields
+ save_struct_actual($1);
+ push_parameter($1, "$type:$2", $file)
+ }
+ }
+ else {
+ save_struct_actual($param);
+ push_parameter($param, $type, $file);
+ }
+ }
+ }
+ }
+}
+
+sub push_parameter($$$) {
+ my $param = shift;
+ my $type = shift;
+ my $file = shift;
+
+ if (($anon_struct_union == 1) && ($type eq "") &&
+ ($param eq "}")) {
+ return; # ignore the ending }; from anon. struct/union
+ }
+
+ $anon_struct_union = 0;
+ my $param_name = $param;
+ $param_name =~ s/\[.*//;
+
+ if ($type eq "" && $param =~ /\.\.\.$/)
+ {
+ if (!defined $parameterdescs{$param} || $parameterdescs{$param} eq "") {
+ $parameterdescs{$param} = "variable arguments";
+ }
+ }
+ elsif ($type eq "" && ($param eq "" or $param eq "void"))
+ {
+ $param="void";
+ $parameterdescs{void} = "no arguments";
+ }
+ elsif ($type eq "" && ($param eq "struct" or $param eq "union"))
+ # handle unnamed (anonymous) union or struct:
+ {
+ $type = $param;
+ $param = "{unnamed_" . $param . "}";
+ $parameterdescs{$param} = "anonymous\n";
+ $anon_struct_union = 1;
+ }
+
+ # warn if parameter has no description
+ # (but ignore ones starting with # as these are not parameters
+ # but inline preprocessor statements);
+ # also ignore unnamed structs/unions;
+ if (!$anon_struct_union) {
+ if (!defined $parameterdescs{$param_name} && $param_name !~ /^#/) {
+
+ $parameterdescs{$param_name} = $undescribed;
+
+ if (($type eq 'function') || ($type eq 'enum')) {
+ print STDERR "Warning(${file}:$.): Function parameter ".
+ "or member '$param' not " .
+ "described in '$declaration_name'\n";
+ }
+ print STDERR "Warning(${file}:$.):" .
+ " No description found for parameter '$param'\n";
+ ++$warnings;
+ }
+ }
+
+ $param = xml_escape($param);
+
+ # strip spaces from $param so that it is one continuous string
+ # on @parameterlist;
+ # this fixes a problem where check_sections() cannot find
+ # a parameter like "addr[6 + 2]" because it actually appears
+ # as "addr[6", "+", "2]" on the parameter list;
+ # but it's better to maintain the param string unchanged for output,
+ # so just weaken the string compare in check_sections() to ignore
+ # "[blah" in a parameter string;
+ ###$param =~ s/\s*//g;
+ push @parameterlist, $param;
+ $parametertypes{$param} = $type;
+}
+
+sub check_sections($$$$$$) {
+ my ($file, $decl_name, $decl_type, $sectcheck, $prmscheck, $nested) = @_;
+ my @sects = split ' ', $sectcheck;
+ my @prms = split ' ', $prmscheck;
+ my $err;
+ my ($px, $sx);
+ my $prm_clean; # strip trailing "[array size]" and/or beginning "*"
+
+ foreach $sx (0 .. $#sects) {
+ $err = 1;
+ foreach $px (0 .. $#prms) {
+ $prm_clean = $prms[$px];
+ $prm_clean =~ s/\[.*\]//;
+ $prm_clean =~ s/__attribute__\s*\(\([a-z,_\*\s\(\)]*\)\)//i;
+ # ignore array size in a parameter string;
+ # however, the original param string may contain
+ # spaces, e.g.: addr[6 + 2]
+ # and this appears in @prms as "addr[6" since the
+ # parameter list is split at spaces;
+ # hence just ignore "[..." for the sections check;
+ $prm_clean =~ s/\[.*//;
+
+ ##$prm_clean =~ s/^\**//;
+ if ($prm_clean eq $sects[$sx]) {
+ $err = 0;
+ last;
+ }
+ }
+ if ($err) {
+ if ($decl_type eq "function") {
+ print STDERR "Warning(${file}:$.): " .
+ "Excess function parameter " .
+ "'$sects[$sx]' " .
+ "description in '$decl_name'\n";
+ ++$warnings;
+ } else {
+ if ($nested !~ m/\Q$sects[$sx]\E/) {
+ print STDERR "Warning(${file}:$.): " .
+ "Excess struct/union/enum/typedef member " .
+ "'$sects[$sx]' " .
+ "description in '$decl_name'\n";
+ ++$warnings;
+ }
+ }
+ }
+ }
+}
+
+##
+# takes a function prototype and the name of the current file being
+# processed and spits out all the details stored in the global
+# arrays/hashes.
+sub dump_function($$) {
+ my $prototype = shift;
+ my $file = shift;
+
+ $prototype =~ s/^static +//;
+ $prototype =~ s/^extern +//;
+ $prototype =~ s/^asmlinkage +//;
+ $prototype =~ s/^inline +//;
+ $prototype =~ s/^__inline__ +//;
+ $prototype =~ s/^__inline +//;
+ $prototype =~ s/^__always_inline +//;
+ $prototype =~ s/^noinline +//;
+ $prototype =~ s/__devinit +//;
+ $prototype =~ s/__init +//;
+ $prototype =~ s/__init_or_module +//;
+ $prototype =~ s/__must_check +//;
+ $prototype =~ s/__weak +//;
+ $prototype =~ s/^#\s*define\s+//; #ak added
+ $prototype =~ s/__attribute__\s*\(\([a-z,]*\)\)//;
+
+ # Yes, this truly is vile. We are looking for:
+ # 1. Return type (may be nothing if we're looking at a macro)
+ # 2. Function name
+ # 3. Function parameters.
+ #
+ # All the while we have to watch out for function pointer parameters
+ # (which IIRC is what the two sections are for), C types (these
+ # regexps don't even start to express all the possibilities), and
+ # so on.
+ #
+ # If you mess with these regexps, it's a good idea to check that
+ # the following functions' documentation still comes out right:
+ # - parport_register_device (function pointer parameters)
+ # - atomic_set (macro)
+ # - pci_match_device, __copy_to_user (long return type)
+
+ if ($prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s*\*+)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\(]*)\)/ ||
+ $prototype =~ m/^()([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+)\s+([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s+\w+\s+\w+\s*\*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/ ||
+ $prototype =~ m/^(\w+\s+\w+\s*\*\s*\w+\s*\*\s*)\s*([a-zA-Z0-9_~:]+)\s*\(([^\{]*)\)/) {
+ $return_type = $1;
+ $declaration_name = $2;
+ my $args = $3;
+
+ create_parameterlist($args, ',', $file);
+ } else {
+ print STDERR "Error(${file}:$.): cannot understand prototype: '$prototype'\n";
+ ++$errors;
+ return;
+ }
+
+ my $prms = join " ", @parameterlist;
+ check_sections($file, $declaration_name, "function", $sectcheck, $prms, "");
+
+ output_declaration($declaration_name,
+ 'function',
+ {'function' => $declaration_name,
+ 'module' => $modulename,
+ 'functiontype' => $return_type,
+ 'parameterlist' => \@parameterlist,
+ 'parameterdescs' => \%parameterdescs,
+ 'parametertypes' => \%parametertypes,
+ 'sectionlist' => \@sectionlist,
+ 'sections' => \%sections,
+ 'purpose' => $declaration_purpose
+ });
+}
+
+sub reset_state {
+ $function = "";
+ %constants = ();
+ %parameterdescs = ();
+ %parametertypes = ();
+ @parameterlist = ();
+ %sections = ();
+ @sectionlist = ();
+ $sectcheck = "";
+ $struct_actual = "";
+ $prototype = "";
+
+ $state = 0;
+}
+
+sub tracepoint_munge($) {
+ my $file = shift;
+ my $tracepointname = 0;
+ my $tracepointargs = 0;
+
+ if ($prototype =~ m/TRACE_EVENT\((.*?),/) {
+ $tracepointname = $1;
+ }
+ if ($prototype =~ m/DEFINE_SINGLE_EVENT\((.*?),/) {
+ $tracepointname = $1;
+ }
+ if ($prototype =~ m/DEFINE_EVENT\((.*?),(.*?),/) {
+ $tracepointname = $2;
+ }
+ $tracepointname =~ s/^\s+//; #strip leading whitespace
+ if ($prototype =~ m/TP_PROTO\((.*?)\)/) {
+ $tracepointargs = $1;
+ }
+ if (($tracepointname eq 0) || ($tracepointargs eq 0)) {
+ print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n".
+ "$prototype\n";
+ } else {
+ $prototype = "static inline void trace_$tracepointname($tracepointargs)";
+ }
+}
+
+sub syscall_munge() {
+ my $void = 0;
+
+ $prototype =~ s@[\r\n\t]+@ @gos; # strip newlines/CR's/tabs
+## if ($prototype =~ m/SYSCALL_DEFINE0\s*\(\s*(a-zA-Z0-9_)*\s*\)/) {
+ if ($prototype =~ m/SYSCALL_DEFINE0/) {
+ $void = 1;
+## $prototype = "long sys_$1(void)";
+ }
+
+ $prototype =~ s/SYSCALL_DEFINE.*\(/long sys_/; # fix return type & func name
+ if ($prototype =~ m/long (sys_.*?),/) {
+ $prototype =~ s/,/\(/;
+ } elsif ($void) {
+ $prototype =~ s/\)/\(void\)/;
+ }
+
+ # now delete all of the odd-number commas in $prototype
+ # so that arg types & arg names don't have a comma between them
+ my $count = 0;
+ my $len = length($prototype);
+ if ($void) {
+ $len = 0; # skip the for-loop
+ }
+ for (my $ix = 0; $ix < $len; $ix++) {
+ if (substr($prototype, $ix, 1) eq ',') {
+ $count++;
+ if ($count % 2 == 1) {
+ substr($prototype, $ix, 1) = ' ';
+ }
+ }
+ }
+}
+
+sub process_state3_function($$) {
+ my $x = shift;
+ my $file = shift;
+
+ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+ if ($x =~ m#\s*/\*\s+MACDOC\s*#io || ($x =~ /^#/ && $x !~ /^#\s*define/)) {
+ # do nothing
+ }
+ elsif ($x =~ /([^\{]*)/) {
+ $prototype .= $1;
+ }
+
+ if (($x =~ /\{/) || ($x =~ /\#\s*define/) || ($x =~ /;/)) {
+ $prototype =~ s@/\*.*?\*/@@gos; # strip comments.
+ $prototype =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+ $prototype =~ s@^\s+@@gos; # strip leading spaces
+ if ($prototype =~ /SYSCALL_DEFINE/) {
+ syscall_munge();
+ }
+ if ($prototype =~ /TRACE_EVENT/ || $prototype =~ /DEFINE_EVENT/ ||
+ $prototype =~ /DEFINE_SINGLE_EVENT/)
+ {
+ tracepoint_munge($file);
+ }
+ dump_function($prototype, $file);
+ reset_state();
+ }
+}
+
+sub process_state3_type($$) {
+ my $x = shift;
+ my $file = shift;
+
+ $x =~ s@[\r\n]+@ @gos; # strip newlines/cr's.
+ $x =~ s@^\s+@@gos; # strip leading spaces
+ $x =~ s@\s+$@@gos; # strip trailing spaces
+ $x =~ s@\/\/.*$@@gos; # strip C99-style comments to end of line
+
+ if ($x =~ /^#/) {
+ # To distinguish preprocessor directive from regular declaration later.
+ $x .= ";";
+ }
+
+ while (1) {
+ if ( $x =~ /([^{};]*)([{};])(.*)/ ) {
+ $prototype .= $1 . $2;
+ ($2 eq '{') && $brcount++;
+ ($2 eq '}') && $brcount--;
+ if (($2 eq ';') && ($brcount == 0)) {
+ dump_declaration($prototype, $file);
+ reset_state();
+ last;
+ }
+ $x = $3;
+ } else {
+ $prototype .= $x;
+ last;
+ }
+ }
+}
+
+# xml_escape: replace <, >, and & in the text stream;
+#
+# however, formatting controls that are generated internally/locally in the
+# kernel-doc script are not escaped here; instead, they begin life like
+# $blankline_html (4 of '\' followed by a mnemonic + ':'), then these strings
+# are converted to their mnemonic-expected output, without the 4 * '\' & ':',
+# just before actual output; (this is done by local_unescape())
+sub xml_escape($) {
+ my $text = shift;
+ if (($output_mode eq "text") || ($output_mode eq "man")) {
+ return $text;
+ }
+ $text =~ s/\&/\\\\\\amp;/g;
+ $text =~ s/\</\\\\\\lt;/g;
+ $text =~ s/\>/\\\\\\gt;/g;
+ return $text;
+}
+
+# convert local escape strings to html
+# local escape strings look like: '\\\\menmonic:' (that's 4 backslashes)
+sub local_unescape($) {
+ my $text = shift;
+ if (($output_mode eq "text") || ($output_mode eq "man")) {
+ return $text;
+ }
+ $text =~ s/\\\\\\\\lt:/</g;
+ $text =~ s/\\\\\\\\gt:/>/g;
+ return $text;
+}
+
+sub process_file($) {
+ my $file;
+ my $identifier;
+ my $func;
+ my $descr;
+ my $in_purpose = 0;
+ my $initial_section_counter = $section_counter;
+
+ if (defined($ENV{'SRCTREE'})) {
+ $file = "$ENV{'SRCTREE'}" . "/" . "@_";
+ }
+ else {
+ $file = "@_";
+ }
+ if (defined($source_map{$file})) {
+ $file = $source_map{$file};
+ }
+
+ if (!open(IN,"<$file")) {
+ print STDERR "Error: Cannot open file $file\n";
+ ++$errors;
+ return;
+ }
+
+ $. = 1;
+
+ $section_counter = 0;
+ while (<IN>) {
+ if ($state == 0) {
+ if (/$doc_start/o) {
+ $state = 1; # next line is always the function name
+ $in_doc_sect = 0;
+ }
+ } elsif ($state == 1) { # this line is the function name (always)
+ if (/$doc_block/o) {
+ $state = 4;
+ $contents = "";
+ if ( $1 eq "" ) {
+ $section = $section_intro;
+ } else {
+ $section = $1;
+ }
+ }
+ elsif (/$doc_decl/o) {
+ $identifier = $1;
+ if (/\s*([\w\s]+?)\s*-/) {
+ $identifier = $1;
+ }
+
+ $state = 2;
+ if (/-(.*)/) {
+ # strip leading/trailing/multiple spaces
+ $descr= $1;
+ $descr =~ s/^\s*//;
+ $descr =~ s/\s*$//;
+ $descr =~ s/\s+/ /;
+ $declaration_purpose = xml_escape($descr);
+ $in_purpose = 1;
+ } else {
+ $declaration_purpose = "";
+ }
+
+ if (($declaration_purpose eq "") && $verbose) {
+ print STDERR "Warning(${file}:$.): missing initial short description on line:\n";
+ print STDERR $_;
+ ++$warnings;
+ }
+
+ if ($identifier =~ m/^struct/) {
+ $decl_type = 'struct';
+ } elsif ($identifier =~ m/^union/) {
+ $decl_type = 'union';
+ } elsif ($identifier =~ m/^enum/) {
+ $decl_type = 'enum';
+ } elsif ($identifier =~ m/^typedef/) {
+ $decl_type = 'typedef';
+ } else {
+ $decl_type = 'function';
+ }
+
+ if ($verbose) {
+ print STDERR "Info(${file}:$.): Scanning doc for $identifier\n";
+ }
+ } else {
+ print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.",
+ " - I thought it was a doc line\n";
+ ++$warnings;
+ $state = 0;
+ }
+ } elsif ($state == 2) { # look for head: lines, and include content
+ if (/$doc_sect/o) {
+ $newsection = $1;
+ $newcontents = $2;
+
+ if (($contents ne "") && ($contents ne "\n")) {
+ if (!$in_doc_sect && $verbose) {
+ print STDERR "Warning(${file}:$.): contents before sections\n";
+ ++$warnings;
+ }
+ dump_section($file, $section, xml_escape($contents));
+ $section = $section_default;
+ }
+
+ $in_doc_sect = 1;
+ $in_purpose = 0;
+ $contents = $newcontents;
+ if ($contents ne "") {
+ while ((substr($contents, 0, 1) eq " ") ||
+ substr($contents, 0, 1) eq "\t") {
+ $contents = substr($contents, 1);
+ }
+ $contents .= "\n";
+ }
+ $section = $newsection;
+ } elsif (/$doc_end/) {
+
+ if (($contents ne "") && ($contents ne "\n")) {
+ dump_section($file, $section, xml_escape($contents));
+ $section = $section_default;
+ $contents = "";
+ }
+ # look for doc_com + <text> + doc_end:
+ if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') {
+ print STDERR "Warning(${file}:$.): suspicious ending line: $_";
+ ++$warnings;
+ }
+
+ $prototype = "";
+ $state = 3;
+ $brcount = 0;
+# print STDERR "end of doc comment, looking for prototype\n";
+ } elsif (/$doc_content/) {
+ # miguel-style comment kludge, look for blank lines after
+ # @parameter line to signify start of description
+ if ($1 eq "") {
+ if ($section =~ m/^@/ || $section eq $section_context) {
+ dump_section($file, $section, xml_escape($contents));
+ $section = $section_default;
+ $contents = "";
+ } else {
+ $contents .= "\n";
+ }
+ $in_purpose = 0;
+ } elsif ($in_purpose == 1) {
+ # Continued declaration purpose
+ chomp($declaration_purpose);
+ $declaration_purpose .= " " . xml_escape($1);
+ } elsif ($section =~ m/^Example/) {
+ $_ =~ s/^\s*\*//;
+ $contents .= $_;
+ } else {
+ $contents .= $1 . "\n";
+ }
+ } else {
+ # i dont know - bad line? ignore.
+ print STDERR "Warning(${file}:$.): bad line: $_";
+ ++$warnings;
+ }
+ } elsif ($state == 3) { # scanning for function '{' (end of prototype)
+ if ($decl_type eq 'function') {
+ process_state3_function($_, $file);
+ } else {
+ process_state3_type($_, $file);
+ }
+ } elsif ($state == 4) {
+ # Documentation block
+ if (/$doc_block/) {
+ dump_doc_section($file, $section, xml_escape($contents));
+ $contents = "";
+ $function = "";
+ %constants = ();
+ %parameterdescs = ();
+ %parametertypes = ();
+ @parameterlist = ();
+ %sections = ();
+ @sectionlist = ();
+ $prototype = "";
+ if ( $1 eq "" ) {
+ $section = $section_intro;
+ } else {
+ $section = $1;
+ }
+ }
+ elsif (/$doc_end/)
+ {
+ dump_doc_section($file, $section, xml_escape($contents));
+ $contents = "";
+ $function = "";
+ %constants = ();
+ %parameterdescs = ();
+ %parametertypes = ();
+ @parameterlist = ();
+ %sections = ();
+ @sectionlist = ();
+ $prototype = "";
+ $state = 0;
+ }
+ elsif (/$doc_content/)
+ {
+ if ( $1 eq "" )
+ {
+ $contents .= $blankline;
+ }
+ else
+ {
+ $contents .= $1 . "\n";
+ }
+ }
+ }
+ }
+ if ($initial_section_counter == $section_counter) {
+ print STDERR "Warning(${file}): no structured comments found\n";
+ if ($output_mode eq "xml") {
+ # The template wants at least one RefEntry here; make one.
+ print "<refentry>\n";
+ print " <refnamediv>\n";
+ print " <refname>\n";
+ print " ${file}\n";
+ print " </refname>\n";
+ print " <refpurpose>\n";
+ print " Document generation inconsistency\n";
+ print " </refpurpose>\n";
+ print " </refnamediv>\n";
+ print " <refsect1>\n";
+ print " <title>\n";
+ print " Oops\n";
+ print " </title>\n";
+ print " <warning>\n";
+ print " <para>\n";
+ print " The template for this document tried to insert\n";
+ print " the structured comment from the file\n";
+ print " <filename>${file}</filename> at this point,\n";
+ print " but none was found.\n";
+ print " This dummy section is inserted to allow\n";
+ print " generation to continue.\n";
+ print " </para>\n";
+ print " </warning>\n";
+ print " </refsect1>\n";
+ print "</refentry>\n";
+ }
+ }
+}
+
+
+$kernelversion = get_kernel_version();
+
+# generate a sequence of code that will splice in highlighting information
+# using the s// operator.
+foreach my $pattern (keys %highlights) {
+# print STDERR "scanning pattern:$pattern, highlight:($highlights{$pattern})\n";
+ $dohighlight .= "\$contents =~ s:$pattern:$highlights{$pattern}:gs;\n";
+}
+
+# Read the file that maps relative names to absolute names for
+# separate source and object directories and for shadow trees.
+if (open(SOURCE_MAP, "<.tmp_filelist.txt")) {
+ my ($relname, $absname);
+ while(<SOURCE_MAP>) {
+ chop();
+ ($relname, $absname) = (split())[0..1];
+ $relname =~ s:^/+::;
+ $source_map{$relname} = $absname;
+ }
+ close(SOURCE_MAP);
+}
+
+foreach (@ARGV) {
+ chomp;
+ process_file($_);
+}
+if ($verbose && $errors) {
+ print STDERR "$errors errors\n";
+}
+if ($verbose && $warnings) {
+ print STDERR "$warnings warnings\n";
+}
+
+exit($errors);
diff --git a/tools/kwbimage.c b/tools/kwbimage.c
new file mode 100644
index 0000000..f327b07
--- /dev/null
+++ b/tools/kwbimage.c
@@ -0,0 +1,405 @@
+/*
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Required to obtain the getline prototype from stdio.h */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include <image.h>
+#include "kwbimage.h"
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t kwbimage_cmds[] = {
+ {CMD_BOOT_FROM, "BOOT_FROM", "boot command", },
+ {CMD_NAND_ECC_MODE, "NAND_ECC_MODE", "NAND mode", },
+ {CMD_NAND_PAGE_SIZE, "NAND_PAGE_SIZE", "NAND size", },
+ {CMD_SATA_PIO_MODE, "SATA_PIO_MODE", "SATA mode", },
+ {CMD_DDR_INIT_DELAY, "DDR_INIT_DELAY", "DDR init dly", },
+ {CMD_DATA, "DATA", "Reg Write Data", },
+ {CMD_INVALID, "", "", },
+};
+
+/*
+ * Supported Boot options for configuration file
+ */
+static table_entry_t kwbimage_bootops[] = {
+ {IBR_HDR_SPI_ID, "spi", "SPI Flash", },
+ {IBR_HDR_NAND_ID, "nand", "NAND Flash", },
+ {IBR_HDR_SATA_ID, "sata", "Sata port", },
+ {IBR_HDR_PEX_ID, "pex", "PCIe port", },
+ {IBR_HDR_UART_ID, "uart", "Serial port", },
+ {-1, "", "Invalid", },
+};
+
+/*
+ * Supported NAND ecc options configuration file
+ */
+static table_entry_t kwbimage_eccmodes[] = {
+ {IBR_HDR_ECC_DEFAULT, "default", "Default mode", },
+ {IBR_HDR_ECC_FORCED_HAMMING, "hamming", "Hamming mode", },
+ {IBR_HDR_ECC_FORCED_RS, "rs", "RS mode", },
+ {IBR_HDR_ECC_DISABLED, "disabled", "ECC Disabled", },
+ {-1, "", "", },
+};
+
+static struct kwb_header kwbimage_header;
+static int datacmd_cnt = 0;
+static char * fname = "Unknown";
+static int lineno = -1;
+
+/*
+ * Report Error if xflag is set in addition to default
+ */
+static int kwbimage_check_params (struct mkimage_params *params)
+{
+ if (!strlen (params->imagename)) {
+ printf ("Error:%s - Configuration file not specified, "
+ "it is needed for kwbimage generation\n",
+ params->cmdname);
+ return CFG_INVALID;
+ }
+ return ((params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)) ||
+ (params->xflag) || !(strlen (params->imagename)));
+}
+
+static uint32_t check_get_hexval (char *token)
+{
+ uint32_t hexval;
+
+ if (!sscanf (token, "%x", &hexval)) {
+ printf ("Error:%s[%d] - Invalid hex data(%s)\n", fname,
+ lineno, token);
+ exit (EXIT_FAILURE);
+ }
+ return hexval;
+}
+
+/*
+ * Generates 8 bit checksum
+ */
+static uint8_t kwbimage_checksum8 (void *start, uint32_t len, uint8_t csum)
+{
+ register uint8_t sum = csum;
+ volatile uint8_t *p = (volatile uint8_t *)start;
+
+ /* check len and return zero checksum if invalid */
+ if (!len)
+ return 0;
+
+ do {
+ sum += *p;
+ p++;
+ } while (--len);
+ return (sum);
+}
+
+/*
+ * Generates 32 bit checksum
+ */
+static uint32_t kwbimage_checksum32 (uint32_t *start, uint32_t len, uint32_t csum)
+{
+ register uint32_t sum = csum;
+ volatile uint32_t *p = start;
+
+ /* check len and return zero checksum if invalid */
+ if (!len)
+ return 0;
+
+ if (len % sizeof(uint32_t)) {
+ printf ("Error:%s[%d] - length is not in multiple of %zu\n",
+ __FUNCTION__, len, sizeof(uint32_t));
+ return 0;
+ }
+
+ do {
+ sum += *p;
+ p++;
+ len -= sizeof(uint32_t);
+ } while (len > 0);
+ return (sum);
+}
+
+static void kwbimage_check_cfgdata (char *token, enum kwbimage_cmd cmdsw,
+ struct kwb_header *kwbhdr)
+{
+ bhr_t *mhdr = &kwbhdr->kwb_hdr;
+ extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
+ int i;
+
+ switch (cmdsw) {
+ case CMD_BOOT_FROM:
+ i = get_table_entry_id (kwbimage_bootops,
+ "Kwbimage boot option", token);
+
+ if (i < 0)
+ goto INVL_DATA;
+
+ mhdr->blockid = i;
+ printf ("Preparing kirkwood boot image to boot "
+ "from %s\n", token);
+ break;
+ case CMD_NAND_ECC_MODE:
+ i = get_table_entry_id (kwbimage_eccmodes,
+ "NAND ecc mode", token);
+
+ if (i < 0)
+ goto INVL_DATA;
+
+ mhdr->nandeccmode = i;
+ printf ("Nand ECC mode = %s\n", token);
+ break;
+ case CMD_NAND_PAGE_SIZE:
+ mhdr->nandpagesize =
+ (uint16_t) check_get_hexval (token);
+ printf ("Nand page size = 0x%x\n", mhdr->nandpagesize);
+ break;
+ case CMD_SATA_PIO_MODE:
+ mhdr->satapiomode =
+ (uint8_t) check_get_hexval (token);
+ printf ("Sata PIO mode = 0x%x\n",
+ mhdr->satapiomode);
+ break;
+ case CMD_DDR_INIT_DELAY:
+ mhdr->ddrinitdelay =
+ (uint16_t) check_get_hexval (token);
+ printf ("DDR init delay = %d msec\n", mhdr->ddrinitdelay);
+ break;
+ case CMD_DATA:
+ exthdr->rcfg[datacmd_cnt].raddr =
+ check_get_hexval (token);
+
+ break;
+ case CMD_INVALID:
+ goto INVL_DATA;
+ default:
+ goto INVL_DATA;
+ }
+ return;
+
+INVL_DATA:
+ printf ("Error:%s[%d] - Invalid data\n", fname, lineno);
+ exit (EXIT_FAILURE);
+}
+
+/*
+ * this function sets the kwbimage header by-
+ * 1. Abstracting input command line arguments data
+ * 2. parses the kwbimage configuration file and update extebded header data
+ * 3. calculates header, extended header and image checksums
+ */
+static void kwdimage_set_ext_header (struct kwb_header *kwbhdr, char* name) {
+ bhr_t *mhdr = &kwbhdr->kwb_hdr;
+ extbhr_t *exthdr = &kwbhdr->kwb_exthdr;
+ FILE *fd = NULL;
+ int j;
+ char *line = NULL;
+ char * token, *saveptr1, *saveptr2;
+ size_t len = 0;
+ enum kwbimage_cmd cmd;
+
+ fname = name;
+ /* set dram register offset */
+ exthdr->dramregsoffs = (intptr_t)&exthdr->rcfg - (intptr_t)mhdr;
+
+ if ((fd = fopen (name, "r")) == 0) {
+ printf ("Error:%s - Can't open\n", fname);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Simple kwimage.cfg file parser */
+ lineno=0;
+ while ((getline (&line, &len, fd)) > 0) {
+ lineno++;
+ token = strtok_r (line, "\r\n", &saveptr1);
+ /* drop all lines with zero tokens (= empty lines) */
+ if (token == NULL)
+ continue;
+
+ for (j = 0, cmd = CMD_INVALID, line = token; ; line = NULL) {
+ token = strtok_r (line, " \t", &saveptr2);
+ if (token == NULL)
+ break;
+ /* Drop all text starting with '#' as comments */
+ if (token[0] == '#')
+ break;
+
+ /* Process rest as valid config command line */
+ switch (j) {
+ case CFG_COMMAND:
+ cmd = get_table_entry_id (kwbimage_cmds,
+ "Kwbimage command", token);
+
+ if (cmd == CMD_INVALID)
+ goto INVL_CMD;
+ break;
+
+ case CFG_DATA0:
+ kwbimage_check_cfgdata (token, cmd, kwbhdr);
+ break;
+
+ case CFG_DATA1:
+ if (cmd != CMD_DATA)
+ goto INVL_CMD;
+
+ exthdr->rcfg[datacmd_cnt].rdata =
+ check_get_hexval (token);
+
+ if (datacmd_cnt > KWBIMAGE_MAX_CONFIG ) {
+ printf ("Error:%s[%d] - Found more "
+ "than max(%zd) allowed "
+ "data configurations\n",
+ fname, lineno,
+ KWBIMAGE_MAX_CONFIG);
+ exit (EXIT_FAILURE);
+ } else
+ datacmd_cnt++;
+ break;
+
+ default:
+ goto INVL_CMD;
+ }
+ j++;
+ }
+ }
+ if (line)
+ free (line);
+
+ fclose (fd);
+ return;
+
+/*
+ * Invalid Command error reporring
+ *
+ * command CMD_DATA needs three strings on a line
+ * whereas other commands need only two.
+ *
+ * if more than two/three (as per command type) are observed,
+ * then error will be reported
+ */
+INVL_CMD:
+ printf ("Error:%s[%d] - Invalid command\n", fname, lineno);
+ exit (EXIT_FAILURE);
+}
+
+static void kwbimage_set_header (void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ struct kwb_header *hdr = (struct kwb_header *)ptr;
+ bhr_t *mhdr = &hdr->kwb_hdr;
+ extbhr_t *exthdr = &hdr->kwb_exthdr;
+ uint32_t checksum;
+ int size;
+
+ /* Build and add image checksum header */
+ checksum = kwbimage_checksum32 ((uint32_t *)ptr, sbuf->st_size, 0);
+
+ size = write (ifd, &checksum, sizeof(uint32_t));
+ if (size != sizeof(uint32_t)) {
+ printf ("Error:%s - Checksum write %d bytes %s\n",
+ params->cmdname, size, params->imagefile);
+ exit (EXIT_FAILURE);
+ }
+
+ sbuf->st_size += sizeof(uint32_t);
+
+ mhdr->blocksize = sbuf->st_size - sizeof(struct kwb_header);
+ mhdr->srcaddr = sizeof(struct kwb_header);
+ mhdr->destaddr= params->addr;
+ mhdr->execaddr =params->ep;
+ mhdr->ext = 0x1; /* header extension appended */
+
+ kwdimage_set_ext_header (hdr, params->imagename);
+ /* calculate checksums */
+ mhdr->checkSum = kwbimage_checksum8 ((void *)mhdr, sizeof(bhr_t), 0);
+ exthdr->checkSum = kwbimage_checksum8 ((void *)exthdr,
+ sizeof(extbhr_t), 0);
+}
+
+static int kwbimage_verify_header (unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct kwb_header *hdr = (struct kwb_header *)ptr;
+ bhr_t *mhdr = &hdr->kwb_hdr;
+ extbhr_t *exthdr = &hdr->kwb_exthdr;
+ uint8_t calc_hdrcsum;
+ uint8_t calc_exthdrcsum;
+
+ calc_hdrcsum = kwbimage_checksum8 ((void *)mhdr,
+ sizeof(bhr_t) - sizeof(uint8_t), 0);
+ if (calc_hdrcsum != mhdr->checkSum)
+ return -FDT_ERR_BADSTRUCTURE; /* mhdr csum not matched */
+
+ calc_exthdrcsum = kwbimage_checksum8 ((void *)exthdr,
+ sizeof(extbhr_t) - sizeof(uint8_t), 0);
+ if (calc_exthdrcsum != exthdr->checkSum)
+ return -FDT_ERR_BADSTRUCTURE; /* exthdr csum not matched */
+
+ return 0;
+}
+
+static void kwbimage_print_header (const void *ptr)
+{
+ struct kwb_header *hdr = (struct kwb_header *) ptr;
+ bhr_t *mhdr = &hdr->kwb_hdr;
+ char *name = get_table_entry_name (kwbimage_bootops,
+ "Kwbimage boot option",
+ (int) mhdr->blockid);
+
+ printf ("Image Type: Kirkwood Boot from %s Image\n", name);
+ printf ("Data Size: ");
+ genimg_print_size (mhdr->blocksize - sizeof(uint32_t));
+ printf ("Load Address: %08x\n", mhdr->destaddr);
+ printf ("Entry Point: %08x\n", mhdr->execaddr);
+}
+
+static int kwbimage_check_image_types (uint8_t type)
+{
+ if (type == IH_TYPE_KWBIMAGE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+/*
+ * kwbimage type parameters definition
+ */
+static struct image_type_params kwbimage_params = {
+ .name = "Kirkwood Boot Image support",
+ .header_size = sizeof(struct kwb_header),
+ .hdr = (void*)&kwbimage_header,
+ .check_image_type = kwbimage_check_image_types,
+ .verify_header = kwbimage_verify_header,
+ .print_header = kwbimage_print_header,
+ .set_header = kwbimage_set_header,
+ .check_params = kwbimage_check_params,
+};
+
+void init_kwb_image_type (void)
+{
+ mkimage_register (&kwbimage_params);
+}
diff --git a/tools/kwbimage.h b/tools/kwbimage.h
new file mode 100644
index 0000000..3d3d5e9
--- /dev/null
+++ b/tools/kwbimage.h
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _KWBIMAGE_H_
+#define _KWBIMAGE_H_
+
+#include <stdint.h>
+
+#define KWBIMAGE_MAX_CONFIG ((0x1dc - 0x20)/sizeof(struct reg_config))
+#define MAX_TEMPBUF_LEN 32
+
+/* NAND ECC Mode */
+#define IBR_HDR_ECC_DEFAULT 0x00
+#define IBR_HDR_ECC_FORCED_HAMMING 0x01
+#define IBR_HDR_ECC_FORCED_RS 0x02
+#define IBR_HDR_ECC_DISABLED 0x03
+
+/* Boot Type - block ID */
+#define IBR_HDR_I2C_ID 0x4D
+#define IBR_HDR_SPI_ID 0x5A
+#define IBR_HDR_NAND_ID 0x8B
+#define IBR_HDR_SATA_ID 0x78
+#define IBR_HDR_PEX_ID 0x9C
+#define IBR_HDR_UART_ID 0x69
+#define IBR_DEF_ATTRIB 0x00
+
+enum kwbimage_cmd {
+ CMD_INVALID,
+ CMD_BOOT_FROM,
+ CMD_NAND_ECC_MODE,
+ CMD_NAND_PAGE_SIZE,
+ CMD_SATA_PIO_MODE,
+ CMD_DDR_INIT_DELAY,
+ CMD_DATA
+};
+
+enum kwbimage_cmd_types {
+ CFG_INVALID = -1,
+ CFG_COMMAND,
+ CFG_DATA0,
+ CFG_DATA1
+};
+
+/* typedefs */
+typedef struct bhr_t {
+ uint8_t blockid; /*0 */
+ uint8_t nandeccmode; /*1 */
+ uint16_t nandpagesize; /*2-3 */
+ uint32_t blocksize; /*4-7 */
+ uint32_t rsvd1; /*8-11 */
+ uint32_t srcaddr; /*12-15 */
+ uint32_t destaddr; /*16-19 */
+ uint32_t execaddr; /*20-23 */
+ uint8_t satapiomode; /*24 */
+ uint8_t rsvd3; /*25 */
+ uint16_t ddrinitdelay; /*26-27 */
+ uint16_t rsvd2; /*28-29 */
+ uint8_t ext; /*30 */
+ uint8_t checkSum; /*31 */
+} bhr_t, *pbhr_t;
+
+struct reg_config {
+ uint32_t raddr;
+ uint32_t rdata;
+};
+
+typedef struct extbhr_t {
+ uint32_t dramregsoffs;
+ uint8_t rsrvd1[0x20 - sizeof(uint32_t)];
+ struct reg_config rcfg[KWBIMAGE_MAX_CONFIG];
+ uint8_t rsrvd2[7];
+ uint8_t checkSum;
+} extbhr_t, *pextbhr_t;
+
+struct kwb_header {
+ bhr_t kwb_hdr;
+ extbhr_t kwb_exthdr;
+};
+
+/*
+ * functions
+ */
+void init_kwb_image_type (void);
+
+#endif /* _KWBIMAGE_H_ */
diff --git a/tools/kwboot.c b/tools/kwboot.c
new file mode 100644
index 0000000..e773f01
--- /dev/null
+++ b/tools/kwboot.c
@@ -0,0 +1,742 @@
+/*
+ * Boot a Marvell Kirkwood SoC, with Xmodem over UART0.
+ *
+ * (c) 2012 Daniel Stodden <daniel.stodden@gmail.com>
+ *
+ * References: marvell.com, "88F6180, 88F6190, 88F6192, and 88F6281
+ * Integrated Controller: Functional Specifications" December 2,
+ * 2008. Chapter 24.2 "BootROM Firmware".
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <termios.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include "kwbimage.h"
+
+#ifdef __GNUC__
+#define PACKED __attribute((packed))
+#else
+#define PACKED
+#endif
+
+/*
+ * Marvell BootROM UART Sensing
+ */
+
+static unsigned char kwboot_msg_boot[] = {
+ 0xBB, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77
+};
+
+#define KWBOOT_MSG_REQ_DELAY 10 /* ms */
+#define KWBOOT_MSG_RSP_TIMEO 50 /* ms */
+
+/*
+ * Xmodem Transfers
+ */
+
+#define SOH 1 /* sender start of block header */
+#define EOT 4 /* sender end of block transfer */
+#define ACK 6 /* target block ack */
+#define NAK 21 /* target block negative ack */
+#define CAN 24 /* target/sender transfer cancellation */
+
+struct kwboot_block {
+ uint8_t soh;
+ uint8_t pnum;
+ uint8_t _pnum;
+ uint8_t data[128];
+ uint8_t csum;
+} PACKED;
+
+#define KWBOOT_BLK_RSP_TIMEO 1000 /* ms */
+
+static int kwboot_verbose;
+
+static void
+kwboot_printv(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (kwboot_verbose) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ fflush(stdout);
+ }
+}
+
+static void
+__spinner(void)
+{
+ const char seq[] = { '-', '\\', '|', '/' };
+ const int div = 8;
+ static int state, bs;
+
+ if (state % div == 0) {
+ fputc(bs, stdout);
+ fputc(seq[state / div % sizeof(seq)], stdout);
+ fflush(stdout);
+ }
+
+ bs = '\b';
+ state++;
+}
+
+static void
+kwboot_spinner(void)
+{
+ if (kwboot_verbose)
+ __spinner();
+}
+
+static void
+__progress(int pct, char c)
+{
+ const int width = 70;
+ static const char *nl = "";
+ static int pos;
+
+ if (pos % width == 0)
+ printf("%s%3d %% [", nl, pct);
+
+ fputc(c, stdout);
+
+ nl = "]\n";
+ pos++;
+
+ if (pct == 100) {
+ while (pos++ < width)
+ fputc(' ', stdout);
+ fputs(nl, stdout);
+ }
+
+ fflush(stdout);
+
+}
+
+static void
+kwboot_progress(int _pct, char c)
+{
+ static int pct;
+
+ if (_pct != -1)
+ pct = _pct;
+
+ if (kwboot_verbose)
+ __progress(pct, c);
+}
+
+static int
+kwboot_tty_recv(int fd, void *buf, size_t len, int timeo)
+{
+ int rc, nfds;
+ fd_set rfds;
+ struct timeval tv;
+ ssize_t n;
+
+ rc = -1;
+
+ 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;
+ }
+
+ do {
+ nfds = select(fd + 1, &rfds, NULL, NULL, &tv);
+ if (nfds < 0)
+ goto out;
+ if (!nfds) {
+ errno = ETIMEDOUT;
+ goto out;
+ }
+
+ n = read(fd, buf, len);
+ if (n < 0)
+ goto out;
+
+ buf = (char *)buf + n;
+ len -= n;
+ } while (len > 0);
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static int
+kwboot_tty_send(int fd, const void *buf, size_t len)
+{
+ int rc;
+ ssize_t n;
+
+ rc = -1;
+
+ do {
+ n = write(fd, buf, len);
+ if (n < 0)
+ goto out;
+
+ buf = (char *)buf + n;
+ len -= n;
+ } while (len > 0);
+
+ rc = tcdrain(fd);
+out:
+ return rc;
+}
+
+static int
+kwboot_tty_send_char(int fd, unsigned char c)
+{
+ return kwboot_tty_send(fd, &c, 1);
+}
+
+static speed_t
+kwboot_tty_speed(int baudrate)
+{
+ switch (baudrate) {
+ case 115200:
+ return B115200;
+ case 57600:
+ return B57600;
+ case 38400:
+ return B38400;
+ case 19200:
+ return B19200;
+ case 9600:
+ return B9600;
+ }
+
+ return -1;
+}
+
+static int
+kwboot_open_tty(const char *path, speed_t speed)
+{
+ int rc, fd;
+ struct termios tio;
+
+ rc = -1;
+
+ fd = open(path, O_RDWR|O_NOCTTY|O_NDELAY);
+ if (fd < 0)
+ goto out;
+
+ memset(&tio, 0, sizeof(tio));
+
+ tio.c_iflag = 0;
+ tio.c_cflag = CREAD|CLOCAL|CS8;
+
+ tio.c_cc[VMIN] = 1;
+ tio.c_cc[VTIME] = 10;
+
+ cfsetospeed(&tio, speed);
+ cfsetispeed(&tio, speed);
+
+ rc = tcsetattr(fd, TCSANOW, &tio);
+ if (rc)
+ goto out;
+
+ rc = fd;
+out:
+ if (rc < 0) {
+ if (fd >= 0)
+ close(fd);
+ }
+
+ return rc;
+}
+
+static int
+kwboot_bootmsg(int tty, void *msg)
+{
+ int rc;
+ char c;
+
+ kwboot_printv("Sending boot message. Please reboot the target...");
+
+ do {
+ rc = tcflush(tty, TCIOFLUSH);
+ if (rc)
+ break;
+
+ rc = kwboot_tty_send(tty, msg, 8);
+ if (rc) {
+ usleep(KWBOOT_MSG_REQ_DELAY * 1000);
+ continue;
+ }
+
+ rc = kwboot_tty_recv(tty, &c, 1, KWBOOT_MSG_RSP_TIMEO);
+
+ kwboot_spinner();
+
+ } while (rc || c != NAK);
+
+ kwboot_printv("\n");
+
+ return rc;
+}
+
+static int
+kwboot_xm_makeblock(struct kwboot_block *block, const void *data,
+ size_t size, int pnum)
+{
+ const size_t blksz = sizeof(block->data);
+ size_t n;
+ int i;
+
+ block->pnum = pnum;
+ block->_pnum = ~block->pnum;
+
+ n = size < blksz ? size : blksz;
+ memcpy(&block->data[0], data, n);
+ memset(&block->data[n], 0, blksz - n);
+
+ block->csum = 0;
+ for (i = 0; i < n; i++)
+ block->csum += block->data[i];
+
+ return n;
+}
+
+static int
+kwboot_xm_sendblock(int fd, struct kwboot_block *block)
+{
+ int rc, retries;
+ char c;
+
+ retries = 16;
+ do {
+ rc = kwboot_tty_send(fd, block, sizeof(*block));
+ if (rc)
+ break;
+
+ rc = kwboot_tty_recv(fd, &c, 1, KWBOOT_BLK_RSP_TIMEO);
+ if (rc)
+ break;
+
+ if (c != ACK)
+ kwboot_progress(-1, '+');
+
+ } while (c == NAK && retries-- > 0);
+
+ rc = -1;
+
+ switch (c) {
+ case ACK:
+ rc = 0;
+ break;
+ case NAK:
+ errno = EBADMSG;
+ break;
+ case CAN:
+ errno = ECANCELED;
+ break;
+ default:
+ errno = EPROTO;
+ break;
+ }
+
+ return rc;
+}
+
+static int
+kwboot_xmodem(int tty, const void *_data, size_t size)
+{
+ const uint8_t *data = _data;
+ int rc, pnum, N, err;
+
+ pnum = 1;
+ N = 0;
+
+ kwboot_printv("Sending boot image...\n");
+
+ do {
+ struct kwboot_block block;
+ int n;
+
+ n = kwboot_xm_makeblock(&block,
+ data + N, size - N,
+ pnum++);
+ if (n < 0)
+ goto can;
+
+ if (!n)
+ break;
+
+ rc = kwboot_xm_sendblock(tty, &block);
+ if (rc)
+ goto out;
+
+ N += n;
+ kwboot_progress(N * 100 / size, '.');
+ } while (1);
+
+ rc = kwboot_tty_send_char(tty, EOT);
+
+out:
+ return rc;
+
+can:
+ err = errno;
+ kwboot_tty_send_char(tty, CAN);
+ errno = err;
+ goto out;
+}
+
+static int
+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));
+ if (nin < 0)
+ return -1;
+
+ if (quit) {
+ int i;
+
+ for (i = 0; i < nin; i++) {
+ if (*buf == quit[*s]) {
+ (*s)++;
+ if (!quit[*s])
+ return 0;
+ buf++;
+ nin--;
+ } else
+ while (*s > 0) {
+ nout = write(out, quit, *s);
+ if (nout <= 0)
+ return -1;
+ (*s) -= nout;
+ }
+ }
+ }
+
+ while (nin > 0) {
+ nout = write(out, buf, nin);
+ if (nout <= 0)
+ return -1;
+ nin -= nout;
+ }
+
+ return 0;
+}
+
+static int
+kwboot_terminal(int tty)
+{
+ int rc, in, s;
+ char *quit = "\34c";
+ struct termios otio, tio;
+
+ rc = -1;
+
+ in = STDIN_FILENO;
+ if (isatty(in)) {
+ rc = tcgetattr(in, &otio);
+ if (!rc) {
+ tio = otio;
+ cfmakeraw(&tio);
+ rc = tcsetattr(in, TCSANOW, &tio);
+ }
+ if (rc) {
+ perror("tcsetattr");
+ goto out;
+ }
+
+ kwboot_printv("[Type Ctrl-%c + %c to quit]\r\n",
+ quit[0]|0100, quit[1]);
+ } else
+ in = -1;
+
+ rc = 0;
+ s = 0;
+
+ do {
+ fd_set rfds;
+ int nfds = 0;
+
+ FD_SET(tty, &rfds);
+ nfds = nfds < tty ? tty : nfds;
+
+ if (in >= 0) {
+ FD_SET(in, &rfds);
+ nfds = nfds < in ? in : nfds;
+ }
+
+ nfds = select(nfds + 1, &rfds, NULL, NULL, NULL);
+ if (nfds < 0)
+ break;
+
+ if (FD_ISSET(tty, &rfds)) {
+ rc = kwboot_term_pipe(tty, STDOUT_FILENO, NULL, NULL);
+ if (rc)
+ break;
+ }
+
+ if (FD_ISSET(in, &rfds)) {
+ rc = kwboot_term_pipe(in, tty, quit, &s);
+ if (rc)
+ break;
+ }
+ } while (quit[s] != 0);
+
+ tcsetattr(in, TCSANOW, &otio);
+out:
+ return rc;
+}
+
+static void *
+kwboot_mmap_image(const char *path, size_t *size, int prot)
+{
+ int rc, fd, flags;
+ struct stat st;
+ void *img;
+
+ rc = -1;
+ fd = -1;
+ img = NULL;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ rc = fstat(fd, &st);
+ if (rc)
+ goto out;
+
+ flags = (prot & PROT_WRITE) ? MAP_PRIVATE : MAP_SHARED;
+
+ img = mmap(NULL, st.st_size, prot, flags, fd, 0);
+ if (img == MAP_FAILED) {
+ img = NULL;
+ goto out;
+ }
+
+ rc = 0;
+ *size = st.st_size;
+out:
+ if (rc && img) {
+ munmap(img, st.st_size);
+ img = NULL;
+ }
+ if (fd >= 0)
+ close(fd);
+
+ return img;
+}
+
+static uint8_t
+kwboot_img_csum8(void *_data, size_t size)
+{
+ uint8_t *data = _data, csum;
+
+ for (csum = 0; size-- > 0; data++)
+ csum += *data;
+
+ return csum;
+}
+
+static int
+kwboot_img_patch_hdr(void *img, size_t size)
+{
+ int rc;
+ bhr_t *hdr;
+ uint8_t csum;
+ const size_t hdrsz = sizeof(*hdr);
+
+ rc = -1;
+ hdr = img;
+
+ if (size < hdrsz) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ csum = kwboot_img_csum8(hdr, hdrsz) - hdr->checkSum;
+ if (csum != hdr->checkSum) {
+ errno = EINVAL;
+ goto out;
+ }
+
+ if (hdr->blockid == IBR_HDR_UART_ID) {
+ rc = 0;
+ goto out;
+ }
+
+ hdr->blockid = IBR_HDR_UART_ID;
+
+ hdr->nandeccmode = IBR_HDR_ECC_DISABLED;
+ hdr->nandpagesize = 0;
+
+ hdr->srcaddr = hdr->ext
+ ? sizeof(struct kwb_header)
+ : sizeof(*hdr);
+
+ hdr->checkSum = kwboot_img_csum8(hdr, hdrsz) - csum;
+
+ rc = 0;
+out:
+ return rc;
+}
+
+static void
+kwboot_usage(FILE *stream, char *progname)
+{
+ fprintf(stream,
+ "Usage: %s -b <image> [ -p ] [ -t ] "
+ "[-B <baud> ] <TTY>\n", progname);
+ fprintf(stream, "\n");
+ fprintf(stream, " -b <image>: boot <image>\n");
+ fprintf(stream, " -p: patch <image> to type 0x69 (uart boot)\n");
+ fprintf(stream, "\n");
+ fprintf(stream, " -t: mini terminal\n");
+ fprintf(stream, "\n");
+ fprintf(stream, " -B <baud>: set baud rate\n");
+ fprintf(stream, "\n");
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *ttypath, *imgpath;
+ int rv, rc, tty, term, prot, patch;
+ void *bootmsg;
+ void *img;
+ size_t size;
+ speed_t speed;
+
+ rv = 1;
+ tty = -1;
+ bootmsg = NULL;
+ imgpath = NULL;
+ img = NULL;
+ term = 0;
+ patch = 0;
+ size = 0;
+ speed = B115200;
+
+ kwboot_verbose = isatty(STDOUT_FILENO);
+
+ do {
+ int c = getopt(argc, argv, "hb:ptB:");
+ if (c < 0)
+ break;
+
+ switch (c) {
+ case 'b':
+ bootmsg = kwboot_msg_boot;
+ imgpath = optarg;
+ break;
+
+ case 'p':
+ patch = 1;
+ break;
+
+ case 't':
+ term = 1;
+ break;
+
+ case 'B':
+ speed = kwboot_tty_speed(atoi(optarg));
+ if (speed == -1)
+ goto usage;
+ break;
+
+ case 'h':
+ rv = 0;
+ default:
+ goto usage;
+ }
+ } while (1);
+
+ if (!bootmsg && !term)
+ goto usage;
+
+ if (patch && !imgpath)
+ goto usage;
+
+ if (argc - optind < 1)
+ goto usage;
+
+ ttypath = argv[optind++];
+
+ tty = kwboot_open_tty(ttypath, speed);
+ if (tty < 0) {
+ perror(ttypath);
+ goto out;
+ }
+
+ if (imgpath) {
+ prot = PROT_READ | (patch ? PROT_WRITE : 0);
+
+ img = kwboot_mmap_image(imgpath, &size, prot);
+ if (!img) {
+ perror(imgpath);
+ goto out;
+ }
+ }
+
+ if (patch) {
+ rc = kwboot_img_patch_hdr(img, size);
+ if (rc) {
+ fprintf(stderr, "%s: Invalid image.\n", imgpath);
+ goto out;
+ }
+ }
+
+ if (bootmsg) {
+ rc = kwboot_bootmsg(tty, bootmsg);
+ if (rc) {
+ perror("bootmsg");
+ goto out;
+ }
+ }
+
+ if (img) {
+ rc = kwboot_xmodem(tty, img, size);
+ if (rc) {
+ perror("xmodem");
+ goto out;
+ }
+ }
+
+ if (term) {
+ rc = kwboot_terminal(tty);
+ if (rc && !(errno == EINTR)) {
+ perror("terminal");
+ goto out;
+ }
+ }
+
+ rv = 0;
+out:
+ if (tty >= 0)
+ close(tty);
+
+ if (img)
+ munmap(img, size);
+
+ return rv;
+
+usage:
+ kwboot_usage(rv ? stderr : stdout, basename(argv[0]));
+ goto out;
+}
diff --git a/tools/logos/atmel.bmp b/tools/logos/atmel.bmp
new file mode 100644
index 0000000..5c659ce
--- /dev/null
+++ b/tools/logos/atmel.bmp
Binary files differ
diff --git a/tools/logos/denx.bmp b/tools/logos/denx.bmp
new file mode 100644
index 0000000..c4cde09
--- /dev/null
+++ b/tools/logos/denx.bmp
Binary files differ
diff --git a/tools/logos/esd.bmp b/tools/logos/esd.bmp
new file mode 100644
index 0000000..a6b4030
--- /dev/null
+++ b/tools/logos/esd.bmp
Binary files differ
diff --git a/tools/logos/freescale.bmp b/tools/logos/freescale.bmp
new file mode 100644
index 0000000..1589e80
--- /dev/null
+++ b/tools/logos/freescale.bmp
Binary files differ
diff --git a/tools/logos/intercontrol.bmp b/tools/logos/intercontrol.bmp
new file mode 100644
index 0000000..cf2a884
--- /dev/null
+++ b/tools/logos/intercontrol.bmp
Binary files differ
diff --git a/tools/logos/linux_logo_ttcontrol.bmp b/tools/logos/linux_logo_ttcontrol.bmp
new file mode 100644
index 0000000..031d3a4
--- /dev/null
+++ b/tools/logos/linux_logo_ttcontrol.bmp
Binary files differ
diff --git a/tools/logos/linux_logo_ttcontrol_palfin.bmp b/tools/logos/linux_logo_ttcontrol_palfin.bmp
new file mode 100644
index 0000000..e3e38d1
--- /dev/null
+++ b/tools/logos/linux_logo_ttcontrol_palfin.bmp
Binary files differ
diff --git a/tools/logos/ronetix.bmp b/tools/logos/ronetix.bmp
new file mode 100644
index 0000000..f956813
--- /dev/null
+++ b/tools/logos/ronetix.bmp
Binary files differ
diff --git a/tools/logos/syteco.bmp b/tools/logos/syteco.bmp
new file mode 100644
index 0000000..9a994fe
--- /dev/null
+++ b/tools/logos/syteco.bmp
Binary files differ
diff --git a/tools/logos/wandboard.bmp b/tools/logos/wandboard.bmp
new file mode 100644
index 0000000..7f288a8
--- /dev/null
+++ b/tools/logos/wandboard.bmp
Binary files differ
diff --git a/tools/mingw_support.c b/tools/mingw_support.c
new file mode 100644
index 0000000..18b69bb
--- /dev/null
+++ b/tools/mingw_support.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * mmap/munmap implementation derived from:
+ * Clamav Native Windows Port : mmap win32 compatibility layer
+ * Copyright (c) 2005-2006 Gianluigi Tiesi <sherpya@netfarm.it>
+ * Parts by Kees Zeelenberg <kzlg@users.sourceforge.net> (LibGW32C)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this software; if not, write to the
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "mingw_support.h"
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <io.h>
+
+int fsync(int fd)
+{
+ return _commit(fd);
+}
+
+void *mmap(void *addr, size_t len, int prot, int flags, int fd, int offset)
+{
+ void *map = NULL;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ DWORD cfm_flags = 0, mvf_flags = 0;
+
+ switch (prot) {
+ case PROT_READ | PROT_WRITE:
+ cfm_flags = PAGE_READWRITE;
+ mvf_flags = FILE_MAP_ALL_ACCESS;
+ break;
+ case PROT_WRITE:
+ cfm_flags = PAGE_READWRITE;
+ mvf_flags = FILE_MAP_WRITE;
+ break;
+ case PROT_READ:
+ cfm_flags = PAGE_READONLY;
+ mvf_flags = FILE_MAP_READ;
+ break;
+ default:
+ return MAP_FAILED;
+ }
+
+ handle = CreateFileMappingA((HANDLE) _get_osfhandle(fd), NULL,
+ cfm_flags, HIDWORD(len), LODWORD(len), NULL);
+ if (!handle)
+ return MAP_FAILED;
+
+ map = MapViewOfFile(handle, mvf_flags, HIDWORD(offset),
+ LODWORD(offset), len);
+ CloseHandle(handle);
+
+ if (!map)
+ return MAP_FAILED;
+
+ return map;
+}
+
+int munmap(void *addr, size_t len)
+{
+ if (!UnmapViewOfFile(addr))
+ return -1;
+
+ return 0;
+}
+
+/* Reentrant string tokenizer. Generic version.
+ Copyright (C) 1991,1996-1999,2001,2004,2007 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ 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, 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. */
+
+/* Parse S into tokens separated by characters in DELIM.
+ If S is NULL, the saved pointer in SAVE_PTR is used as
+ the next starting point. For example:
+ char s[] = "-abc-=-def";
+ char *sp;
+ x = strtok_r(s, "-", &sp); // x = "abc", sp = "=-def"
+ x = strtok_r(NULL, "-=", &sp); // x = "def", sp = NULL
+ x = strtok_r(NULL, "=", &sp); // x = NULL
+ // s = "abc\0-def\0"
+*/
+char *strtok_r(char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+
+ if (s == NULL)
+ s = *save_ptr;
+
+ /* Scan leading delimiters. */
+ s += strspn(s, delim);
+ if (*s == '\0') {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ /* Find the end of the token. */
+ token = s;
+ s = strpbrk (token, delim);
+ if (s == NULL) {
+ /* This token finishes the string. */
+ *save_ptr = memchr(token, '\0', strlen(token));
+ } else {
+ /* Terminate the token and make *SAVE_PTR point past it. */
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+ return token;
+}
+
+#include "getline.c"
diff --git a/tools/mingw_support.h b/tools/mingw_support.h
new file mode 100644
index 0000000..48b8010
--- /dev/null
+++ b/tools/mingw_support.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2008 Extreme Engineering Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this software; if not, write to the
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __MINGW_SUPPORT_H_
+#define __WINGW_SUPPORT_H_ 1
+
+/* Defining __INSIDE_MSYS__ helps to prevent u-boot/mingw overlap */
+#define __INSIDE_MSYS__ 1
+
+#include <windows.h>
+
+/* mmap protections */
+#define PROT_READ 0x1 /* Page can be read */
+#define PROT_WRITE 0x2 /* Page can be written */
+#define PROT_EXEC 0x4 /* Page can be executed */
+#define PROT_NONE 0x0 /* Page can not be accessed */
+
+/* Sharing types (must choose one and only one of these) */
+#define MAP_SHARED 0x01 /* Share changes */
+#define MAP_PRIVATE 0x02 /* Changes are private */
+
+/* File perms */
+#ifndef S_IRGRP
+# define S_IRGRP 0
+#endif
+#ifndef S_IWGRP
+# define S_IWGRP 0
+#endif
+
+/* Windows 64-bit access macros */
+#define LODWORD(x) ((DWORD)((DWORDLONG)(x)))
+#define HIDWORD(x) ((DWORD)(((DWORDLONG)(x) >> 32) & 0xffffffff))
+
+typedef UINT uint;
+typedef ULONG ulong;
+
+int fsync(int fd);
+void *mmap(void *, size_t, int, int, int, int);
+int munmap(void *, size_t);
+char *strtok_r(char *s, const char *delim, char **save_ptr);
+#include "getline.h"
+
+#endif /* __MINGW_SUPPORT_H_ */
diff --git a/tools/mkenvimage.c b/tools/mkenvimage.c
new file mode 100644
index 0000000..5521268
--- /dev/null
+++ b/tools/mkenvimage.c
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2011 Free Electrons
+ * David Wagner <david.wagner@free-electrons.com>
+ *
+ * Inspired from envcrc.c:
+ * (C) Copyright 2001
+ * Paolo Scaffardi, AIRVENT SAM s.p.a - RIMINI(ITALY), arsenio@tin.it
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* We want the GNU version of basename() */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "compiler.h"
+#include <u-boot/crc.h>
+#include <version.h>
+
+#define CRC_SIZE sizeof(uint32_t)
+
+static void usage(const char *exec_name)
+{
+ fprintf(stderr, "%s [-h] [-r] [-b] [-p <byte>] -s <environment partition size> -o <output> <input file>\n"
+ "\n"
+ "This tool takes a key=value input file (same as would a `printenv' show) and generates the corresponding environment image, ready to be flashed.\n"
+ "\n"
+ "\tThe input file is in format:\n"
+ "\t\tkey1=value1\n"
+ "\t\tkey2=value2\n"
+ "\t\t...\n"
+ "\t-r : the environment has multiple copies in flash\n"
+ "\t-b : the target is big endian (default is little endian)\n"
+ "\t-p <byte> : fill the image with <byte> bytes instead of 0xff bytes\n"
+ "\t-V : print version information and exit\n"
+ "\n"
+ "If the input file is \"-\", data is read from standard input\n",
+ exec_name);
+}
+
+long int xstrtol(const char *s)
+{
+ long int tmp;
+
+ errno = 0;
+ tmp = strtol(s, NULL, 0);
+ if (!errno)
+ return tmp;
+
+ if (errno == ERANGE)
+ fprintf(stderr, "Bad integer format: %s\n", s);
+ else
+ fprintf(stderr, "Error while parsing %s: %s\n", s,
+ strerror(errno));
+
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+ uint32_t crc, targetendian_crc;
+ const char *txt_filename = NULL, *bin_filename = NULL;
+ int txt_fd, bin_fd;
+ unsigned char *dataptr, *envptr;
+ unsigned char *filebuf = NULL;
+ unsigned int filesize = 0, envsize = 0, datasize = 0;
+ int bigendian = 0;
+ int redundant = 0;
+ unsigned char padbyte = 0xff;
+
+ int option;
+ int ret = EXIT_SUCCESS;
+
+ struct stat txt_file_stat;
+
+ int fp, ep;
+ const char *prg;
+
+ prg = basename(argv[0]);
+
+ /* Turn off getopt()'s internal error message */
+ opterr = 0;
+
+ /* Parse the cmdline */
+ while ((option = getopt(argc, argv, ":s:o:rbp:hV")) != -1) {
+ switch (option) {
+ case 's':
+ datasize = xstrtol(optarg);
+ break;
+ case 'o':
+ bin_filename = strdup(optarg);
+ if (!bin_filename) {
+ fprintf(stderr, "Can't strdup() the output filename\n");
+ return EXIT_FAILURE;
+ }
+ break;
+ case 'r':
+ redundant = 1;
+ break;
+ case 'b':
+ bigendian = 1;
+ break;
+ case 'p':
+ padbyte = xstrtol(optarg);
+ break;
+ case 'h':
+ usage(prg);
+ return EXIT_SUCCESS;
+ case 'V':
+ printf("%s version %s\n", prg, PLAIN_VERSION);
+ return EXIT_SUCCESS;
+ case ':':
+ fprintf(stderr, "Missing argument for option -%c\n",
+ optopt);
+ usage(prg);
+ return EXIT_FAILURE;
+ default:
+ fprintf(stderr, "Wrong option -%c\n", optopt);
+ usage(prg);
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Check datasize and allocate the data */
+ if (datasize == 0) {
+ fprintf(stderr, "Please specify the size of the environment partition.\n");
+ usage(prg);
+ return EXIT_FAILURE;
+ }
+
+ dataptr = malloc(datasize * sizeof(*dataptr));
+ if (!dataptr) {
+ fprintf(stderr, "Can't alloc %d bytes for dataptr.\n",
+ datasize);
+ return EXIT_FAILURE;
+ }
+
+ /*
+ * envptr points to the beginning of the actual environment (after the
+ * crc and possible `redundant' byte
+ */
+ envsize = datasize - (CRC_SIZE + redundant);
+ envptr = dataptr + CRC_SIZE + redundant;
+
+ /* Pad the environment with the padding byte */
+ memset(envptr, padbyte, envsize);
+
+ /* Open the input file ... */
+ if (optind >= argc || strcmp(argv[optind], "-") == 0) {
+ int readbytes = 0;
+ int readlen = sizeof(*envptr) * 4096;
+ txt_fd = STDIN_FILENO;
+
+ do {
+ filebuf = realloc(filebuf, readlen);
+ if (!filebuf) {
+ fprintf(stderr, "Can't realloc memory for the input file buffer\n");
+ return EXIT_FAILURE;
+ }
+ readbytes = read(txt_fd, filebuf + filesize, readlen);
+ if (errno) {
+ fprintf(stderr, "Error while reading stdin: %s\n",
+ strerror(errno));
+ return EXIT_FAILURE;
+ }
+ filesize += readbytes;
+ } while (readbytes == readlen);
+
+ } else {
+ txt_filename = argv[optind];
+ txt_fd = open(txt_filename, O_RDONLY);
+ if (txt_fd == -1) {
+ fprintf(stderr, "Can't open \"%s\": %s\n",
+ txt_filename, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ /* ... and check it */
+ ret = fstat(txt_fd, &txt_file_stat);
+ if (ret == -1) {
+ fprintf(stderr, "Can't stat() on \"%s\": %s\n",
+ txt_filename, strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ filesize = txt_file_stat.st_size;
+
+ filebuf = mmap(NULL, sizeof(*envptr) * filesize, PROT_READ,
+ MAP_PRIVATE, txt_fd, 0);
+ if (filebuf == MAP_FAILED) {
+ fprintf(stderr, "mmap (%zu bytes) failed: %s\n",
+ sizeof(*envptr) * filesize,
+ strerror(errno));
+ fprintf(stderr, "Falling back to read()\n");
+
+ filebuf = malloc(sizeof(*envptr) * filesize);
+ ret = read(txt_fd, filebuf, sizeof(*envptr) * filesize);
+ if (ret != sizeof(*envptr) * filesize) {
+ fprintf(stderr, "Can't read the whole input file (%zu bytes): %s\n",
+ sizeof(*envptr) * filesize,
+ strerror(errno));
+
+ return EXIT_FAILURE;
+ }
+ }
+ ret = close(txt_fd);
+ }
+ /* The +1 is for the additionnal ending \0. See below. */
+ if (filesize + 1 > envsize) {
+ fprintf(stderr, "The input file is larger than the environment partition size\n");
+ return EXIT_FAILURE;
+ }
+
+ /* Replace newlines separating variables with \0 */
+ for (fp = 0, ep = 0 ; fp < filesize ; fp++) {
+ if (filebuf[fp] == '\n') {
+ if (ep == 0) {
+ /*
+ * Newlines at the beginning of the file ?
+ * Ignore them.
+ */
+ continue;
+ } else if (filebuf[fp-1] == '\\') {
+ /*
+ * Embedded newline in a variable.
+ *
+ * The backslash was added to the envptr; rewind
+ * and replace it with a newline
+ */
+ ep--;
+ envptr[ep++] = '\n';
+ } else {
+ /* End of a variable */
+ envptr[ep++] = '\0';
+ }
+ } else {
+ envptr[ep++] = filebuf[fp];
+ }
+ }
+ /*
+ * Make sure there is a final '\0'
+ * And do it again on the next byte to mark the end of the environment.
+ */
+ if (envptr[ep-1] != '\0') {
+ envptr[ep++] = '\0';
+ /*
+ * The text file doesn't have an ending newline. We need to
+ * check the env size again to make sure we have room for two \0
+ */
+ if (ep >= envsize) {
+ fprintf(stderr, "The environment file is too large for the target environment storage\n");
+ return EXIT_FAILURE;
+ }
+ envptr[ep] = '\0';
+ } else {
+ envptr[ep] = '\0';
+ }
+
+ /* Computes the CRC and put it at the beginning of the data */
+ crc = crc32(0, envptr, envsize);
+ targetendian_crc = bigendian ? cpu_to_be32(crc) : cpu_to_le32(crc);
+
+ memcpy(dataptr, &targetendian_crc, sizeof(targetendian_crc));
+ if (redundant)
+ dataptr[sizeof(targetendian_crc)] = 1;
+
+ if (!bin_filename || strcmp(bin_filename, "-") == 0) {
+ bin_fd = STDOUT_FILENO;
+ } else {
+ bin_fd = creat(bin_filename, S_IRUSR | S_IWUSR | S_IRGRP |
+ S_IWGRP);
+ if (bin_fd == -1) {
+ fprintf(stderr, "Can't open output file \"%s\": %s\n",
+ bin_filename, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (write(bin_fd, dataptr, sizeof(*dataptr) * datasize) !=
+ sizeof(*dataptr) * datasize) {
+ fprintf(stderr, "write() failed: %s\n", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ ret = close(bin_fd);
+
+ return ret;
+}
diff --git a/tools/mkexynosspl.c b/tools/mkexynosspl.c
new file mode 100644
index 0000000..6a8dd93
--- /dev/null
+++ b/tools/mkexynosspl.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <compiler.h>
+
+#define CHECKSUM_OFFSET (14*1024-4)
+#define BUFSIZE (14*1024)
+#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \
+ | S_IWGRP | S_IROTH | S_IWOTH)
+/*
+* Requirement:
+* IROM code reads first 14K bytes from boot device.
+* It then calculates the checksum of 14K-4 bytes and compare with data at
+* 14K-4 offset.
+*
+* This function takes two filenames:
+* IN "u-boot-spl.bin" and
+* OUT "$(BOARD)-spl.bin as filenames.
+* It reads the "u-boot-spl.bin" in 16K buffer.
+* It calculates checksum of 14K-4 Bytes and stores at 14K-4 offset in buffer.
+* It writes the buffer to "$(BOARD)-spl.bin" file.
+*/
+
+int main(int argc, char **argv)
+{
+ unsigned char buffer[BUFSIZE];
+ int i, ifd, ofd;
+ uint32_t checksum = 0;
+ off_t len;
+ ssize_t count;
+ struct stat stat;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ ifd = open(argv[1], O_RDONLY);
+ if (ifd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ argv[0], argv[1], strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
+ if (ifd < 0) {
+ fprintf(stderr, "%s: Can't open %s: %s\n",
+ argv[0], argv[2], strerror(errno));
+ close(ifd);
+ exit(EXIT_FAILURE);
+ }
+
+ if (fstat(ifd, &stat)) {
+ fprintf(stderr, "%s: Unable to get size of %s: %s\n",
+ argv[0], argv[1], strerror(errno));
+ close(ifd);
+ close(ofd);
+ exit(EXIT_FAILURE);
+ }
+
+ len = stat.st_size;
+
+ count = (len < CHECKSUM_OFFSET) ? len : CHECKSUM_OFFSET;
+
+ if (read(ifd, buffer, count) != count) {
+ fprintf(stderr, "%s: Can't read %s: %s\n",
+ argv[0], argv[1], strerror(errno));
+
+ close(ifd);
+ close(ofd);
+
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0, checksum = 0; i < CHECKSUM_OFFSET; i++)
+ checksum += buffer[i];
+
+ checksum = cpu_to_le32(checksum);
+
+ memcpy(&buffer[CHECKSUM_OFFSET], &checksum, sizeof(checksum));
+
+ if (write(ofd, buffer, BUFSIZE) != BUFSIZE) {
+ fprintf(stderr, "%s: Can't write %s: %s\n",
+ argv[0], argv[2], strerror(errno));
+
+ close(ifd);
+ close(ofd);
+
+ exit(EXIT_FAILURE);
+ }
+
+ close(ifd);
+ close(ofd);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/mkimage.c b/tools/mkimage.c
new file mode 100644
index 0000000..d312844
--- /dev/null
+++ b/tools/mkimage.c
@@ -0,0 +1,664 @@
+/*
+ * (C) Copyright 2008 Semihalf
+ *
+ * (C) Copyright 2000-2009
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "mkimage.h"
+#include <image.h>
+#include <version.h>
+
+static void copy_file(int, const char *, int);
+static void usage(void);
+
+/* image_type_params link list to maintain registered image type supports */
+struct image_type_params *mkimage_tparams = NULL;
+
+/* parameters initialized by core will be used by the image type code */
+struct mkimage_params params = {
+ .os = IH_OS_LINUX,
+ .arch = IH_ARCH_PPC,
+ .type = IH_TYPE_KERNEL,
+ .comp = IH_COMP_GZIP,
+ .dtc = MKIMAGE_DEFAULT_DTC_OPTIONS,
+ .imagename = "",
+ .imagename2 = "",
+};
+
+/*
+ * mkimage_register -
+ *
+ * It is used to register respective image generation/list support to the
+ * mkimage core
+ *
+ * the input struct image_type_params is checked and appended to the link
+ * list, if the input structure is already registered, error
+ */
+void mkimage_register (struct image_type_params *tparams)
+{
+ struct image_type_params **tp;
+
+ if (!tparams) {
+ fprintf (stderr, "%s: %s: Null input\n",
+ params.cmdname, __FUNCTION__);
+ exit (EXIT_FAILURE);
+ }
+
+ /* scan the linked list, check for registry and point the last one */
+ for (tp = &mkimage_tparams; *tp != NULL; tp = &(*tp)->next) {
+ if (!strcmp((*tp)->name, tparams->name)) {
+ fprintf (stderr, "%s: %s already registered\n",
+ params.cmdname, tparams->name);
+ return;
+ }
+ }
+
+ /* add input struct entry at the end of link list */
+ *tp = tparams;
+ /* mark input entry as last entry in the link list */
+ tparams->next = NULL;
+
+ debug ("Registered %s\n", tparams->name);
+}
+
+/*
+ * mkimage_get_type -
+ *
+ * It scans all registers image type supports
+ * checks the input type_id for each supported image type
+ *
+ * if successful,
+ * returns respective image_type_params pointer if success
+ * if input type_id is not supported by any of image_type_support
+ * returns NULL
+ */
+struct image_type_params *mkimage_get_type(int type)
+{
+ struct image_type_params *curr;
+
+ for (curr = mkimage_tparams; curr != NULL; curr = curr->next) {
+ if (curr->check_image_type) {
+ if (!curr->check_image_type (type))
+ return curr;
+ }
+ }
+ return NULL;
+}
+
+/*
+ * mkimage_verify_print_header -
+ *
+ * It scans mkimage_tparams link list,
+ * verifies image_header for each supported image type
+ * if verification is successful, prints respective header
+ *
+ * returns negative if input image format does not match with any of
+ * supported image types
+ */
+int mkimage_verify_print_header (void *ptr, struct stat *sbuf)
+{
+ int retval = -1;
+ struct image_type_params *curr;
+
+ for (curr = mkimage_tparams; curr != NULL; curr = curr->next ) {
+ if (curr->verify_header) {
+ retval = curr->verify_header (
+ (unsigned char *)ptr, sbuf->st_size,
+ &params);
+
+ if (retval == 0) {
+ /*
+ * Print the image information
+ * if verify is successful
+ */
+ if (curr->print_header)
+ curr->print_header (ptr);
+ else {
+ fprintf (stderr,
+ "%s: print_header undefined for %s\n",
+ params.cmdname, curr->name);
+ }
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+int
+main (int argc, char **argv)
+{
+ int ifd = -1;
+ struct stat sbuf;
+ char *ptr;
+ int retval = 0;
+ struct image_type_params *tparams = NULL;
+
+ /* Init Freescale PBL Boot image generation/list support */
+ init_pbl_image_type();
+ /* Init Kirkwood Boot image generation/list support */
+ init_kwb_image_type ();
+ /* Init Freescale imx Boot image generation/list support */
+ init_imx_image_type ();
+ /* Init FIT image generation/list support */
+ init_fit_image_type ();
+ /* Init TI OMAP Boot image generation/list support */
+ init_omap_image_type();
+ /* Init Default image generation/list support */
+ init_default_image_type ();
+ /* Init Davinci UBL support */
+ init_ubl_image_type();
+ /* Init Davinci AIS support */
+ init_ais_image_type();
+
+ params.cmdname = *argv;
+ params.addr = params.ep = 0;
+
+ while (--argc > 0 && **++argv == '-') {
+ while (*++*argv) {
+ switch (**argv) {
+ case 'l':
+ params.lflag = 1;
+ break;
+ case 'A':
+ if ((--argc <= 0) ||
+ (params.arch =
+ genimg_get_arch_id (*++argv)) < 0)
+ usage ();
+ goto NXTARG;
+ case 'c':
+ if (--argc <= 0)
+ usage();
+ params.comment = *++argv;
+ goto NXTARG;
+ case 'C':
+ if ((--argc <= 0) ||
+ (params.comp =
+ genimg_get_comp_id (*++argv)) < 0)
+ usage ();
+ goto NXTARG;
+ case 'D':
+ if (--argc <= 0)
+ usage ();
+ params.dtc = *++argv;
+ goto NXTARG;
+
+ case 'O':
+ if ((--argc <= 0) ||
+ (params.os =
+ genimg_get_os_id (*++argv)) < 0)
+ usage ();
+ goto NXTARG;
+ case 'T':
+ if ((--argc <= 0) ||
+ (params.type =
+ genimg_get_type_id (*++argv)) < 0)
+ usage ();
+ goto NXTARG;
+
+ case 'a':
+ if (--argc <= 0)
+ usage ();
+ params.addr = strtoul (*++argv, &ptr, 16);
+ if (*ptr) {
+ fprintf (stderr,
+ "%s: invalid load address %s\n",
+ params.cmdname, *argv);
+ exit (EXIT_FAILURE);
+ }
+ goto NXTARG;
+ case 'd':
+ if (--argc <= 0)
+ usage ();
+ params.datafile = *++argv;
+ params.dflag = 1;
+ goto NXTARG;
+ case 'e':
+ if (--argc <= 0)
+ usage ();
+ params.ep = strtoul (*++argv, &ptr, 16);
+ if (*ptr) {
+ fprintf (stderr,
+ "%s: invalid entry point %s\n",
+ params.cmdname, *argv);
+ exit (EXIT_FAILURE);
+ }
+ params.eflag = 1;
+ goto NXTARG;
+ case 'f':
+ if (--argc <= 0)
+ usage ();
+ params.datafile = *++argv;
+ /* no break */
+ case 'F':
+ /*
+ * The flattened image tree (FIT) format
+ * requires a flattened device tree image type
+ */
+ params.type = IH_TYPE_FLATDT;
+ params.fflag = 1;
+ goto NXTARG;
+ case 'k':
+ if (--argc <= 0)
+ usage();
+ params.keydir = *++argv;
+ goto NXTARG;
+ case 'K':
+ if (--argc <= 0)
+ usage();
+ params.keydest = *++argv;
+ goto NXTARG;
+ case 'n':
+ if (--argc <= 0)
+ usage ();
+ params.imagename = *++argv;
+ goto NXTARG;
+ case 'r':
+ params.require_keys = 1;
+ break;
+ case 'R':
+ if (--argc <= 0)
+ usage();
+ /*
+ * This entry is for the second configuration
+ * file, if only one is not enough.
+ */
+ params.imagename2 = *++argv;
+ goto NXTARG;
+ case 's':
+ params.skipcpy = 1;
+ break;
+ case 'v':
+ params.vflag++;
+ break;
+ case 'V':
+ printf("mkimage version %s\n", PLAIN_VERSION);
+ exit(EXIT_SUCCESS);
+ case 'x':
+ params.xflag++;
+ break;
+ default:
+ usage ();
+ }
+ }
+NXTARG: ;
+ }
+
+ if (argc != 1)
+ usage ();
+
+ /* set tparams as per input type_id */
+ tparams = mkimage_get_type(params.type);
+ if (tparams == NULL) {
+ fprintf (stderr, "%s: unsupported type %s\n",
+ params.cmdname, genimg_get_type_name(params.type));
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * check the passed arguments parameters meets the requirements
+ * as per image type to be generated/listed
+ */
+ if (tparams->check_params)
+ if (tparams->check_params (&params))
+ usage ();
+
+ if (!params.eflag) {
+ params.ep = params.addr;
+ /* If XIP, entry point must be after the U-Boot header */
+ if (params.xflag)
+ params.ep += tparams->header_size;
+ }
+
+ params.imagefile = *argv;
+
+ if (params.fflag){
+ if (tparams->fflag_handle)
+ /*
+ * in some cases, some additional processing needs
+ * to be done if fflag is defined
+ *
+ * For ex. fit_handle_file for Fit file support
+ */
+ retval = tparams->fflag_handle(&params);
+
+ if (retval != EXIT_SUCCESS)
+ exit (retval);
+ }
+
+ if (params.lflag || params.fflag) {
+ ifd = open (params.imagefile, O_RDONLY|O_BINARY);
+ } else {
+ ifd = open (params.imagefile,
+ O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
+ }
+
+ if (ifd < 0) {
+ fprintf (stderr, "%s: Can't open %s: %s\n",
+ params.cmdname, params.imagefile,
+ strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (params.lflag || params.fflag) {
+ /*
+ * list header information of existing image
+ */
+ if (fstat(ifd, &sbuf) < 0) {
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ params.cmdname, params.imagefile,
+ strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if ((unsigned)sbuf.st_size < tparams->header_size) {
+ fprintf (stderr,
+ "%s: Bad size: \"%s\" is not valid image\n",
+ params.cmdname, params.imagefile);
+ exit (EXIT_FAILURE);
+ }
+
+ ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, ifd, 0);
+ if (ptr == MAP_FAILED) {
+ fprintf (stderr, "%s: Can't read %s: %s\n",
+ params.cmdname, params.imagefile,
+ strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ /*
+ * scan through mkimage registry for all supported image types
+ * and verify the input image file header for match
+ * Print the image information for matched image type
+ * Returns the error code if not matched
+ */
+ retval = mkimage_verify_print_header (ptr, &sbuf);
+
+ (void) munmap((void *)ptr, sbuf.st_size);
+ (void) close (ifd);
+
+ exit (retval);
+ }
+
+ /*
+ * In case there an header with a variable
+ * length will be added, the corresponding
+ * function is called. This is responsible to
+ * allocate memory for the header itself.
+ */
+ if (tparams->vrec_header)
+ tparams->vrec_header(&params, tparams);
+ else
+ memset(tparams->hdr, 0, tparams->header_size);
+
+ if (write(ifd, tparams->hdr, tparams->header_size)
+ != tparams->header_size) {
+ fprintf (stderr, "%s: Write error on %s: %s\n",
+ params.cmdname, params.imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (!params.skipcpy) {
+ if (params.type == IH_TYPE_MULTI ||
+ params.type == IH_TYPE_SCRIPT) {
+ char *file = params.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",
+ params.cmdname, file, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+ size = cpu_to_uimage (sbuf.st_size);
+ } else {
+ size = 0;
+ }
+
+ if (write(ifd, (char *)&size, sizeof(size)) != sizeof(size)) {
+ fprintf (stderr, "%s: Write error on %s: %s\n",
+ params.cmdname, params.imagefile,
+ strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (!file) {
+ break;
+ }
+
+ if (sep) {
+ *sep = ':';
+ file = sep + 1;
+ } else {
+ file = NULL;
+ }
+ }
+
+ file = params.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 if (params.type == IH_TYPE_PBLIMAGE) {
+ /* PBL has special Image format, implements its' own */
+ pbl_load_uboot(ifd, &params);
+ } else {
+ copy_file (ifd, params.datafile, 0);
+ }
+ }
+
+ /* We're a bit of paranoid */
+#if defined(_POSIX_SYNCHRONIZED_IO) && \
+ !defined(__sun__) && \
+ !defined(__FreeBSD__) && \
+ !defined(__APPLE__)
+ (void) fdatasync (ifd);
+#else
+ (void) fsync (ifd);
+#endif
+
+ if (fstat(ifd, &sbuf) < 0) {
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ params.cmdname, params.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",
+ params.cmdname, params.imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ /* Setup the image header as per input image type*/
+ if (tparams->set_header)
+ tparams->set_header (ptr, &sbuf, ifd, &params);
+ else {
+ fprintf (stderr, "%s: Can't set header for %s: %s\n",
+ params.cmdname, tparams->name, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ /* Print the image information by processing image header */
+ if (tparams->print_header)
+ tparams->print_header (ptr);
+ else {
+ fprintf (stderr, "%s: Can't print header for %s: %s\n",
+ params.cmdname, tparams->name, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ (void) munmap((void *)ptr, sbuf.st_size);
+
+ /* We're a bit of paranoid */
+#if defined(_POSIX_SYNCHRONIZED_IO) && \
+ !defined(__sun__) && \
+ !defined(__FreeBSD__) && \
+ !defined(__APPLE__)
+ (void) fdatasync (ifd);
+#else
+ (void) fsync (ifd);
+#endif
+
+ if (close(ifd)) {
+ fprintf (stderr, "%s: Write error on %s: %s\n",
+ params.cmdname, params.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;
+ struct image_type_params *tparams = mkimage_get_type (params.type);
+
+ if (params.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",
+ params.cmdname, datafile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (fstat(dfd, &sbuf) < 0) {
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ params.cmdname, datafile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0);
+ if (ptr == MAP_FAILED) {
+ fprintf (stderr, "%s: Can't read %s: %s\n",
+ params.cmdname, datafile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ if (params.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 < tparams->header_size) {
+ fprintf (stderr,
+ "%s: Bad size: \"%s\" is too small for XIP\n",
+ params.cmdname, datafile);
+ exit (EXIT_FAILURE);
+ }
+
+ for (p = ptr; p < ptr + tparams->header_size; p++) {
+ if ( *p != 0xff ) {
+ fprintf (stderr,
+ "%s: Bad file: \"%s\" has invalid buffer for XIP\n",
+ params.cmdname, datafile);
+ exit (EXIT_FAILURE);
+ }
+ }
+
+ offset = tparams->header_size;
+ }
+
+ size = sbuf.st_size - offset;
+ if (write(ifd, ptr + offset, size) != size) {
+ fprintf (stderr, "%s: Write error on %s: %s\n",
+ params.cmdname, params.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",
+ params.cmdname, params.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",
+ params.cmdname);
+ fprintf (stderr, " %s [-x] -A arch -O os -T type -C comp "
+ "-a addr -e ep -n name -d data_file[:data_file...] image\n"
+ " -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",
+ params.cmdname);
+ fprintf(stderr, " %s [-D dtc_options] [-f fit-image.its|-F] fit-image\n",
+ params.cmdname);
+ fprintf(stderr, " -D => set options for device tree compiler\n"
+ " -f => input filename for FIT source\n");
+#ifdef CONFIG_FIT_SIGNATURE
+ fprintf(stderr, "Signing / verified boot options: [-k keydir] [-K dtb] [ -c <comment>] [-r]\n"
+ " -k => set directory containing private keys\n"
+ " -K => write public keys to this .dtb file\n"
+ " -c => add comment in signature node\n"
+ " -F => re-sign existing FIT image\n"
+ " -r => mark keys used as 'required' in dtb\n");
+#else
+ fprintf(stderr, "Signing / verified boot not supported (CONFIG_FIT_SIGNATURE undefined)\n");
+#endif
+ fprintf (stderr, " %s -V ==> print version information and exit\n",
+ params.cmdname);
+
+ exit (EXIT_FAILURE);
+}
diff --git a/tools/mkimage.h b/tools/mkimage.h
new file mode 100644
index 0000000..1d9984e
--- /dev/null
+++ b/tools/mkimage.h
@@ -0,0 +1,179 @@
+/*
+ * (C) Copyright 2000-2004
+ * DENX Software Engineering
+ * Wolfgang Denk, wd@denx.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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _MKIIMAGE_H_
+#define _MKIIMAGE_H_
+
+#include "os_support.h"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <sha1.h>
+#include "fdt_host.h"
+
+#undef MKIMAGE_DEBUG
+
+#ifdef MKIMAGE_DEBUG
+#define debug(fmt,args...) printf (fmt ,##args)
+#else
+#define debug(fmt,args...)
+#endif /* MKIMAGE_DEBUG */
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static inline void *map_sysmem(ulong paddr, unsigned long len)
+{
+ return (void *)(uintptr_t)paddr;
+}
+
+static inline ulong map_to_sysmem(void *ptr)
+{
+ return (ulong)(uintptr_t)ptr;
+}
+
+#define MKIMAGE_TMPFILE_SUFFIX ".tmp"
+#define MKIMAGE_MAX_TMPFILE_LEN 256
+#define MKIMAGE_DEFAULT_DTC_OPTIONS "-I dts -O dtb -p 500"
+#define MKIMAGE_MAX_DTC_CMDLINE_LEN 512
+#define MKIMAGE_DTC "dtc" /* assume dtc is in $PATH */
+
+#define IH_ARCH_DEFAULT IH_ARCH_INVALID
+
+/*
+ * This structure defines all such variables those are initialized by
+ * mkimage main core and need to be referred by image type specific
+ * functions
+ */
+struct mkimage_params {
+ int dflag;
+ int eflag;
+ int fflag;
+ int lflag;
+ int vflag;
+ int xflag;
+ int skipcpy;
+ int os;
+ int arch;
+ int type;
+ int comp;
+ char *dtc;
+ unsigned int addr;
+ unsigned int ep;
+ char *imagename;
+ char *imagename2;
+ char *datafile;
+ char *imagefile;
+ char *cmdname;
+ const char *keydir; /* Directory holding private keys */
+ const char *keydest; /* Destination .dtb for public key */
+ const char *comment; /* Comment to add to signature node */
+ int require_keys; /* 1 to mark signing keys as 'required' */
+};
+
+/*
+ * image type specific variables and callback functions
+ */
+struct image_type_params {
+ /* name is an identification tag string for added support */
+ char *name;
+ /*
+ * header size is local to the specific image type to be supported,
+ * mkimage core treats this as number of bytes
+ */
+ uint32_t header_size;
+ /* Image type header pointer */
+ void *hdr;
+ /*
+ * There are several arguments that are passed on the command line
+ * and are registered as flags in mkimage_params structure.
+ * This callback function can be used to check the passed arguments
+ * are in-lined with the image type to be supported
+ *
+ * Returns 1 if parameter check is successful
+ */
+ int (*check_params) (struct mkimage_params *);
+ /*
+ * This function is used by list command (i.e. mkimage -l <filename>)
+ * image type verification code must be put here
+ *
+ * Returns 0 if image header verification is successful
+ * otherwise, returns respective negative error codes
+ */
+ int (*verify_header) (unsigned char *, int, struct mkimage_params *);
+ /* Prints image information abstracting from image header */
+ void (*print_header) (const void *);
+ /*
+ * The header or image contents need to be set as per image type to
+ * be generated using this callback function.
+ * further output file post processing (for ex. checksum calculation,
+ * padding bytes etc..) can also be done in this callback function.
+ */
+ void (*set_header) (void *, struct stat *, int,
+ struct mkimage_params *);
+ /*
+ * Some image generation support for ex (default image type) supports
+ * more than one type_ids, this callback function is used to check
+ * whether input (-T <image_type>) is supported by registered image
+ * generation/list low level code
+ */
+ int (*check_image_type) (uint8_t);
+ /* This callback function will be executed if fflag is defined */
+ int (*fflag_handle) (struct mkimage_params *);
+ /*
+ * This callback function will be executed for variable size record
+ * It is expected to build this header in memory and return its length
+ * and a pointer to it
+ */
+ int (*vrec_header) (struct mkimage_params *,
+ struct image_type_params *);
+ /* pointer to the next registered entry in linked list */
+ struct image_type_params *next;
+};
+
+/*
+ * Exported functions
+ */
+void mkimage_register (struct image_type_params *tparams);
+
+/*
+ * There is a c file associated with supported image type low level code
+ * for ex. default_image.c, fit_image.c
+ * init is the only function referred by mkimage core.
+ * to avoid a single lined header file, you can define them here
+ *
+ * Supported image types init functions
+ */
+void pbl_load_uboot(int fd, struct mkimage_params *mparams);
+void init_pbl_image_type(void);
+void init_ais_image_type(void);
+void init_kwb_image_type (void);
+void init_imx_image_type (void);
+void init_default_image_type (void);
+void init_fit_image_type (void);
+void init_ubl_image_type(void);
+void init_omap_image_type(void);
+
+#endif /* _MKIIMAGE_H_ */
diff --git a/tools/mpc86x_clk.c b/tools/mpc86x_clk.c
new file mode 100644
index 0000000..8dfbd4e
--- /dev/null
+++ b/tools/mpc86x_clk.c
@@ -0,0 +1,218 @@
+/*
+ * (C) Copyright 2003 Intracom S.A.
+ * Pantelis Antoniou <panto@intracom.gr>
+ *
+ * This little program makes an exhaustive search for the
+ * correct terms of pdf, mfi, mfn, mfd, s, dbrmo, in PLPRCR.
+ * The goal is to produce a gclk2 from a xin input, while respecting
+ * all the restrictions on their combination.
+ *
+ * Generaly you select the first row of the produced table.
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define DPREF_MIN 10000000
+#define DPREF_MAX 32000000
+
+#define DPGDCK_MAX 320000000
+#define DPGDCK_MIN 160000000
+
+#define S_MIN 0
+#define S_MAX 2
+
+#define MFI_MIN 5
+#define MFI_MAX 15
+
+#define MFN_MIN 0
+#define MFN_MAX 15
+
+#define MFD_MIN 0
+#define MFD_MAX 31
+
+#define MF_MIN 5
+#define MF_MAX 15
+
+#define PDF_MIN 0
+#define PDF_MAX 15
+
+#define GCLK2_MAX 150000000
+
+static int calculate (int xin, int target_clock,
+ int ppm, int pdf, int mfi, int mfn, int mfd, int s,
+ int *dprefp, int *dpgdckp, int *jdbckp,
+ int *gclk2p, int *dbrmop)
+{
+ unsigned int dpref, dpgdck, jdbck, gclk2, t1, t2, dbrmo;
+
+ /* valid MFI? */
+ if (mfi < MFI_MIN)
+ return -1;
+
+ /* valid num, denum? */
+ if (mfn > 0 && mfn >= mfd)
+ return -1;
+
+ dpref = xin / (pdf + 1);
+
+ /* valid dpef? */
+ if (dpref < DPREF_MIN || dpref > DPREF_MAX)
+ return -1;
+
+ if (mfn == 0) {
+ dpgdck = (2 * mfi * xin) / (pdf + 1) ;
+ dbrmo = 0;
+ } else {
+ /* 5 <= mfi + (mfn / mfd + 1) <= 15 */
+ t1 = mfd + 1;
+ t2 = mfi * t1 + mfn;
+ if ( MF_MIN * t1 > t2 || MF_MAX * t1 < t2)
+ return -1;
+
+ dpgdck = (unsigned int)(2 * (mfi * mfd + mfi + mfn) *
+ (unsigned int)xin) /
+ ((mfd + 1) * (pdf + 1));
+
+ dbrmo = 10 * mfn < (mfd + 1);
+ }
+
+ /* valid dpgclk? */
+ if (dpgdck < DPGDCK_MIN || dpgdck > DPGDCK_MAX)
+ return -1;
+
+ jdbck = dpgdck >> s;
+ gclk2 = jdbck / 2;
+
+ /* valid gclk2 */
+ if (gclk2 > GCLK2_MAX)
+ return -1;
+
+ t1 = abs(gclk2 - target_clock);
+
+ /* XXX max 1MHz dev. in clock */
+ if (t1 > 1000000)
+ return -1;
+
+ /* dev within range (XXX gclk2 scaled to avoid overflow) */
+ if (t1 * 1000 > (unsigned int)ppm * (gclk2 / 1000))
+ return -1;
+
+ *dprefp = dpref;
+ *dpgdckp = dpgdck;
+ *jdbckp = jdbck;
+ *gclk2p = gclk2;
+ *dbrmop = dbrmo;
+
+ return gclk2;
+}
+
+int conf_clock(int xin, int target_clock, int ppm)
+{
+ int pdf, s, mfn, mfd, mfi;
+ int dpref, dpgdck, jdbck, gclk2, xout, dbrmo;
+ int found = 0;
+
+ /* integer multipliers */
+ for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
+ for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
+ for (s = 0; s <= S_MAX; s++) {
+ xout = calculate(xin, target_clock,
+ ppm, pdf, mfi, 0, 0, s,
+ &dpref, &dpgdck, &jdbck,
+ &gclk2, &dbrmo);
+ if (xout < 0)
+ continue;
+
+ if (found == 0) {
+ printf("pdf mfi mfn mfd s dbrmo dpref dpgdck jdbck gclk2 exact?\n");
+ printf("--- --- --- --- - ----- ----- ------ ----- ----- ------\n");
+ }
+
+ printf("%3d %3d --- --- %1d %5d %9d %9d %9d %9d%s\n",
+ pdf, mfi, s, dbrmo,
+ dpref, dpgdck, jdbck, gclk2,
+ gclk2 == target_clock ? " YES" : "");
+
+ found++;
+ }
+ }
+ }
+
+ /* fractional multipliers */
+ for (pdf = PDF_MIN; pdf <= PDF_MAX; pdf++) {
+ for (mfi = MFI_MIN; mfi <= MFI_MAX; mfi++) {
+ for (mfn = 1; mfn <= MFN_MAX; mfn++) {
+ for (mfd = 1; mfd <= MFD_MAX; mfd++) {
+ for (s = 0; s <= S_MAX; s++) {
+ xout = calculate(xin, target_clock,
+ ppm, pdf, mfi, mfn, mfd, s,
+ &dpref, &dpgdck, &jdbck,
+ &gclk2, &dbrmo);
+ if (xout < 0)
+ continue;
+
+ if (found == 0) {
+ printf("pdf mfi mfn mfd s dbrmo dpref dpgdck jdbck gclk2 exact?\n");
+ printf("--- --- --- --- - ----- ----- ------ ----- ----- ------\n");
+ }
+
+ printf("%3d %3d %3d %3d %1d %5d %9d %9d %9d %9d%s\n",
+ pdf, mfi, mfn, mfd, s,
+ dbrmo, dpref, dpgdck, jdbck, gclk2,
+ gclk2 == target_clock ? " YES" : "");
+
+ found++;
+ }
+ }
+ }
+
+ }
+ }
+
+ return found;
+}
+
+int main(int argc, char *argv[])
+{
+ int xin, want_gclk2, found, ppm = 100;
+
+ if (argc < 3) {
+ fprintf(stderr, "usage: mpc86x_clk <xin> <want_gclk2> [ppm]\n");
+ fprintf(stderr, " default ppm is 100\n");
+ return 10;
+ }
+
+ xin = atoi(argv[1]);
+ want_gclk2 = atoi(argv[2]);
+ if (argc >= 4)
+ ppm = atoi(argv[3]);
+
+ found = conf_clock(xin, want_gclk2, ppm);
+ if (found <= 0) {
+ fprintf(stderr, "cannot produce gclk2 %d from xin %d\n",
+ want_gclk2, xin);
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/mxsboot.c b/tools/mxsboot.c
new file mode 100644
index 0000000..d92c39f
--- /dev/null
+++ b/tools/mxsboot.c
@@ -0,0 +1,687 @@
+/*
+ * Freescale i.MX28 image generator
+ *
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "compiler.h"
+
+/*
+ * Default BCB layout.
+ *
+ * TWEAK this if you have blown any OCOTP fuses.
+ */
+#define STRIDE_PAGES 64
+#define STRIDE_COUNT 4
+
+/*
+ * Layout for 256Mb big NAND with 2048b page size, 64b OOB size and
+ * 128kb erase size.
+ *
+ * TWEAK this if you have different kind of NAND chip.
+ */
+uint32_t nand_writesize = 2048;
+uint32_t nand_oobsize = 64;
+uint32_t nand_erasesize = 128 * 1024;
+
+/*
+ * Sector on which the SigmaTel boot partition (0x53) starts.
+ */
+uint32_t sd_sector = 2048;
+
+/*
+ * Each of the U-Boot bootstreams is at maximum 1MB big.
+ *
+ * TWEAK this if, for some wild reason, you need to boot bigger image.
+ */
+#define MAX_BOOTSTREAM_SIZE (1 * 1024 * 1024)
+
+/* i.MX28 NAND controller-specific constants. DO NOT TWEAK! */
+#define MXS_NAND_DMA_DESCRIPTOR_COUNT 4
+#define MXS_NAND_CHUNK_DATA_CHUNK_SIZE 512
+#define MXS_NAND_METADATA_SIZE 10
+#define MXS_NAND_COMMAND_BUFFER_SIZE 32
+
+struct mx28_nand_fcb {
+ uint32_t checksum;
+ uint32_t fingerprint;
+ uint32_t version;
+ struct {
+ uint8_t data_setup;
+ uint8_t data_hold;
+ uint8_t address_setup;
+ uint8_t dsample_time;
+ uint8_t nand_timing_state;
+ uint8_t rea;
+ uint8_t rloh;
+ uint8_t rhoh;
+ } timing;
+ uint32_t page_data_size;
+ uint32_t total_page_size;
+ uint32_t sectors_per_block;
+ uint32_t number_of_nands; /* Ignored */
+ uint32_t total_internal_die; /* Ignored */
+ uint32_t cell_type; /* Ignored */
+ uint32_t ecc_block_n_ecc_type;
+ uint32_t ecc_block_0_size;
+ uint32_t ecc_block_n_size;
+ uint32_t ecc_block_0_ecc_type;
+ uint32_t metadata_bytes;
+ uint32_t num_ecc_blocks_per_page;
+ uint32_t ecc_block_n_ecc_level_sdk; /* Ignored */
+ uint32_t ecc_block_0_size_sdk; /* Ignored */
+ uint32_t ecc_block_n_size_sdk; /* Ignored */
+ uint32_t ecc_block_0_ecc_level_sdk; /* Ignored */
+ uint32_t num_ecc_blocks_per_page_sdk; /* Ignored */
+ uint32_t metadata_bytes_sdk; /* Ignored */
+ uint32_t erase_threshold;
+ uint32_t boot_patch;
+ uint32_t patch_sectors;
+ uint32_t firmware1_starting_sector;
+ uint32_t firmware2_starting_sector;
+ uint32_t sectors_in_firmware1;
+ uint32_t sectors_in_firmware2;
+ uint32_t dbbt_search_area_start_address;
+ uint32_t badblock_marker_byte;
+ uint32_t badblock_marker_start_bit;
+ uint32_t bb_marker_physical_offset;
+};
+
+struct mx28_nand_dbbt {
+ uint32_t checksum;
+ uint32_t fingerprint;
+ uint32_t version;
+ uint32_t number_bb;
+ uint32_t number_2k_pages_bb;
+};
+
+struct mx28_nand_bbt {
+ uint32_t nand;
+ uint32_t number_bb;
+ uint32_t badblock[510];
+};
+
+struct mx28_sd_drive_info {
+ uint32_t chip_num;
+ uint32_t drive_type;
+ uint32_t tag;
+ uint32_t first_sector_number;
+ uint32_t sector_count;
+};
+
+struct mx28_sd_config_block {
+ uint32_t signature;
+ uint32_t primary_boot_tag;
+ uint32_t secondary_boot_tag;
+ uint32_t num_copies;
+ struct mx28_sd_drive_info drv_info[1];
+};
+
+static inline uint32_t mx28_nand_ecc_size_in_bits(uint32_t ecc_strength)
+{
+ return ecc_strength * 13;
+}
+
+static inline uint32_t mx28_nand_get_ecc_strength(uint32_t page_data_size,
+ uint32_t page_oob_size)
+{
+ if (page_data_size == 2048)
+ return 8;
+
+ if (page_data_size == 4096) {
+ if (page_oob_size == 128)
+ return 8;
+
+ if (page_oob_size == 218)
+ return 16;
+ }
+
+ return 0;
+}
+
+static inline uint32_t mx28_nand_get_mark_offset(uint32_t page_data_size,
+ uint32_t ecc_strength)
+{
+ uint32_t chunk_data_size_in_bits;
+ uint32_t chunk_ecc_size_in_bits;
+ uint32_t chunk_total_size_in_bits;
+ uint32_t block_mark_chunk_number;
+ uint32_t block_mark_chunk_bit_offset;
+ uint32_t block_mark_bit_offset;
+
+ chunk_data_size_in_bits = MXS_NAND_CHUNK_DATA_CHUNK_SIZE * 8;
+ chunk_ecc_size_in_bits = mx28_nand_ecc_size_in_bits(ecc_strength);
+
+ chunk_total_size_in_bits =
+ chunk_data_size_in_bits + chunk_ecc_size_in_bits;
+
+ /* Compute the bit offset of the block mark within the physical page. */
+ block_mark_bit_offset = page_data_size * 8;
+
+ /* Subtract the metadata bits. */
+ block_mark_bit_offset -= MXS_NAND_METADATA_SIZE * 8;
+
+ /*
+ * Compute the chunk number (starting at zero) in which the block mark
+ * appears.
+ */
+ block_mark_chunk_number =
+ block_mark_bit_offset / chunk_total_size_in_bits;
+
+ /*
+ * Compute the bit offset of the block mark within its chunk, and
+ * validate it.
+ */
+ block_mark_chunk_bit_offset = block_mark_bit_offset -
+ (block_mark_chunk_number * chunk_total_size_in_bits);
+
+ if (block_mark_chunk_bit_offset > chunk_data_size_in_bits)
+ return 1;
+
+ /*
+ * Now that we know the chunk number in which the block mark appears,
+ * we can subtract all the ECC bits that appear before it.
+ */
+ block_mark_bit_offset -=
+ block_mark_chunk_number * chunk_ecc_size_in_bits;
+
+ return block_mark_bit_offset;
+}
+
+static inline uint32_t mx28_nand_mark_byte_offset(void)
+{
+ uint32_t ecc_strength;
+ ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+ return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) >> 3;
+}
+
+static inline uint32_t mx28_nand_mark_bit_offset(void)
+{
+ uint32_t ecc_strength;
+ ecc_strength = mx28_nand_get_ecc_strength(nand_writesize, nand_oobsize);
+ return mx28_nand_get_mark_offset(nand_writesize, ecc_strength) & 0x7;
+}
+
+static uint32_t mx28_nand_block_csum(uint8_t *block, uint32_t size)
+{
+ uint32_t csum = 0;
+ int i;
+
+ for (i = 0; i < size; i++)
+ csum += block[i];
+
+ return csum ^ 0xffffffff;
+}
+
+static struct mx28_nand_fcb *mx28_nand_get_fcb(uint32_t size)
+{
+ struct mx28_nand_fcb *fcb;
+ uint32_t bcb_size_bytes;
+ uint32_t stride_size_bytes;
+ uint32_t bootstream_size_pages;
+ uint32_t fw1_start_page;
+ uint32_t fw2_start_page;
+
+ fcb = malloc(nand_writesize);
+ if (!fcb) {
+ printf("MX28 NAND: Unable to allocate FCB\n");
+ return NULL;
+ }
+
+ memset(fcb, 0, nand_writesize);
+
+ fcb->fingerprint = 0x20424346;
+ fcb->version = 0x01000000;
+
+ /*
+ * FIXME: These here are default values as found in kobs-ng. We should
+ * probably retrieve the data from NAND or something.
+ */
+ fcb->timing.data_setup = 80;
+ fcb->timing.data_hold = 60;
+ fcb->timing.address_setup = 25;
+ fcb->timing.dsample_time = 6;
+
+ fcb->page_data_size = nand_writesize;
+ fcb->total_page_size = nand_writesize + nand_oobsize;
+ fcb->sectors_per_block = nand_erasesize / nand_writesize;
+
+ fcb->num_ecc_blocks_per_page = (nand_writesize / 512) - 1;
+ fcb->ecc_block_0_size = 512;
+ fcb->ecc_block_n_size = 512;
+ fcb->metadata_bytes = 10;
+
+ if (nand_writesize == 2048) {
+ fcb->ecc_block_n_ecc_type = 4;
+ fcb->ecc_block_0_ecc_type = 4;
+ } else if (nand_writesize == 4096) {
+ if (nand_oobsize == 128) {
+ fcb->ecc_block_n_ecc_type = 4;
+ fcb->ecc_block_0_ecc_type = 4;
+ } else if (nand_oobsize == 218) {
+ fcb->ecc_block_n_ecc_type = 8;
+ fcb->ecc_block_0_ecc_type = 8;
+ }
+ }
+
+ if (fcb->ecc_block_n_ecc_type == 0) {
+ printf("MX28 NAND: Unsupported NAND geometry\n");
+ goto err;
+ }
+
+ fcb->boot_patch = 0;
+ fcb->patch_sectors = 0;
+
+ fcb->badblock_marker_byte = mx28_nand_mark_byte_offset();
+ fcb->badblock_marker_start_bit = mx28_nand_mark_bit_offset();
+ fcb->bb_marker_physical_offset = nand_writesize;
+
+ stride_size_bytes = STRIDE_PAGES * nand_writesize;
+ bcb_size_bytes = stride_size_bytes * STRIDE_COUNT;
+
+ bootstream_size_pages = (size + (nand_writesize - 1)) /
+ nand_writesize;
+
+ fw1_start_page = 2 * bcb_size_bytes / nand_writesize;
+ fw2_start_page = (2 * bcb_size_bytes + MAX_BOOTSTREAM_SIZE) /
+ nand_writesize;
+
+ fcb->firmware1_starting_sector = fw1_start_page;
+ fcb->firmware2_starting_sector = fw2_start_page;
+ fcb->sectors_in_firmware1 = bootstream_size_pages;
+ fcb->sectors_in_firmware2 = bootstream_size_pages;
+
+ fcb->dbbt_search_area_start_address = STRIDE_PAGES * STRIDE_COUNT;
+
+ return fcb;
+
+err:
+ free(fcb);
+ return NULL;
+}
+
+static struct mx28_nand_dbbt *mx28_nand_get_dbbt(void)
+{
+ struct mx28_nand_dbbt *dbbt;
+
+ dbbt = malloc(nand_writesize);
+ if (!dbbt) {
+ printf("MX28 NAND: Unable to allocate DBBT\n");
+ return NULL;
+ }
+
+ memset(dbbt, 0, nand_writesize);
+
+ dbbt->fingerprint = 0x54424244;
+ dbbt->version = 0x1;
+
+ return dbbt;
+}
+
+static inline uint8_t mx28_nand_parity_13_8(const uint8_t b)
+{
+ uint32_t parity = 0, tmp;
+
+ tmp = ((b >> 6) ^ (b >> 5) ^ (b >> 3) ^ (b >> 2)) & 1;
+ parity |= tmp << 0;
+
+ tmp = ((b >> 7) ^ (b >> 5) ^ (b >> 4) ^ (b >> 2) ^ (b >> 1)) & 1;
+ parity |= tmp << 1;
+
+ tmp = ((b >> 7) ^ (b >> 6) ^ (b >> 5) ^ (b >> 1) ^ (b >> 0)) & 1;
+ parity |= tmp << 2;
+
+ tmp = ((b >> 7) ^ (b >> 4) ^ (b >> 3) ^ (b >> 0)) & 1;
+ parity |= tmp << 3;
+
+ tmp = ((b >> 6) ^ (b >> 4) ^ (b >> 3) ^
+ (b >> 2) ^ (b >> 1) ^ (b >> 0)) & 1;
+ parity |= tmp << 4;
+
+ return parity;
+}
+
+static uint8_t *mx28_nand_fcb_block(struct mx28_nand_fcb *fcb)
+{
+ uint8_t *block;
+ uint8_t *ecc;
+ int i;
+
+ block = malloc(nand_writesize + nand_oobsize);
+ if (!block) {
+ printf("MX28 NAND: Unable to allocate FCB block\n");
+ return NULL;
+ }
+
+ memset(block, 0, nand_writesize + nand_oobsize);
+
+ /* Update the FCB checksum */
+ fcb->checksum = mx28_nand_block_csum(((uint8_t *)fcb) + 4, 508);
+
+ /* Figure 12-11. in iMX28RM, rev. 1, says FCB is at offset 12 */
+ memcpy(block + 12, fcb, sizeof(struct mx28_nand_fcb));
+
+ /* ECC is at offset 12 + 512 */
+ ecc = block + 12 + 512;
+
+ /* Compute the ECC parity */
+ for (i = 0; i < sizeof(struct mx28_nand_fcb); i++)
+ ecc[i] = mx28_nand_parity_13_8(block[i + 12]);
+
+ return block;
+}
+
+static int mx28_nand_write_fcb(struct mx28_nand_fcb *fcb, char *buf)
+{
+ uint32_t offset;
+ uint8_t *fcbblock;
+ int ret = 0;
+ int i;
+
+ fcbblock = mx28_nand_fcb_block(fcb);
+ if (!fcbblock)
+ return -1;
+
+ for (i = 0; i < STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+ offset = i * nand_writesize;
+ memcpy(buf + offset, fcbblock, nand_writesize + nand_oobsize);
+ }
+
+ free(fcbblock);
+ return ret;
+}
+
+static int mx28_nand_write_dbbt(struct mx28_nand_dbbt *dbbt, char *buf)
+{
+ uint32_t offset;
+ int i = STRIDE_PAGES * STRIDE_COUNT;
+
+ for (; i < 2 * STRIDE_PAGES * STRIDE_COUNT; i += STRIDE_PAGES) {
+ offset = i * nand_writesize;
+ memcpy(buf + offset, dbbt, sizeof(struct mx28_nand_dbbt));
+ }
+
+ return 0;
+}
+
+static int mx28_nand_write_firmware(struct mx28_nand_fcb *fcb, int infd,
+ char *buf)
+{
+ int ret;
+ off_t size;
+ uint32_t offset1, offset2;
+
+ size = lseek(infd, 0, SEEK_END);
+ lseek(infd, 0, SEEK_SET);
+
+ offset1 = fcb->firmware1_starting_sector * nand_writesize;
+ offset2 = fcb->firmware2_starting_sector * nand_writesize;
+
+ ret = read(infd, buf + offset1, size);
+ if (ret != size)
+ return -1;
+
+ memcpy(buf + offset2, buf + offset1, size);
+
+ return 0;
+}
+
+void usage(void)
+{
+ printf(
+ "Usage: mxsboot [ops] <type> <infile> <outfile>\n"
+ "Augment BootStream file with a proper header for i.MX28 boot\n"
+ "\n"
+ " <type> type of image:\n"
+ " \"nand\" for NAND image\n"
+ " \"sd\" for SD image\n"
+ " <infile> input file, the u-boot.sb bootstream\n"
+ " <outfile> output file, the bootable image\n"
+ "\n");
+ printf(
+ "For NAND boot, these options are accepted:\n"
+ " -w <size> NAND page size\n"
+ " -o <size> NAND OOB size\n"
+ " -e <size> NAND erase size\n"
+ "\n"
+ "For SD boot, these options are accepted:\n"
+ " -p <sector> Sector where the SGTL partition starts\n"
+ );
+}
+
+static int mx28_create_nand_image(int infd, int outfd)
+{
+ struct mx28_nand_fcb *fcb;
+ struct mx28_nand_dbbt *dbbt;
+ int ret = -1;
+ char *buf;
+ int size;
+ ssize_t wr_size;
+
+ size = nand_writesize * 512 + 2 * MAX_BOOTSTREAM_SIZE;
+
+ buf = malloc(size);
+ if (!buf) {
+ printf("Can not allocate output buffer of %d bytes\n", size);
+ goto err0;
+ }
+
+ memset(buf, 0, size);
+
+ fcb = mx28_nand_get_fcb(MAX_BOOTSTREAM_SIZE);
+ if (!fcb) {
+ printf("Unable to compile FCB\n");
+ goto err1;
+ }
+
+ dbbt = mx28_nand_get_dbbt();
+ if (!dbbt) {
+ printf("Unable to compile DBBT\n");
+ goto err2;
+ }
+
+ ret = mx28_nand_write_fcb(fcb, buf);
+ if (ret) {
+ printf("Unable to write FCB to buffer\n");
+ goto err3;
+ }
+
+ ret = mx28_nand_write_dbbt(dbbt, buf);
+ if (ret) {
+ printf("Unable to write DBBT to buffer\n");
+ goto err3;
+ }
+
+ ret = mx28_nand_write_firmware(fcb, infd, buf);
+ if (ret) {
+ printf("Unable to write firmware to buffer\n");
+ goto err3;
+ }
+
+ wr_size = write(outfd, buf, size);
+ if (wr_size != size) {
+ ret = -1;
+ goto err3;
+ }
+
+ ret = 0;
+
+err3:
+ free(dbbt);
+err2:
+ free(fcb);
+err1:
+ free(buf);
+err0:
+ return ret;
+}
+
+static int mx28_create_sd_image(int infd, int outfd)
+{
+ int ret = -1;
+ uint32_t *buf;
+ int size;
+ off_t fsize;
+ ssize_t wr_size;
+ struct mx28_sd_config_block *cb;
+
+ fsize = lseek(infd, 0, SEEK_END);
+ lseek(infd, 0, SEEK_SET);
+ size = fsize + 4 * 512;
+
+ buf = malloc(size);
+ if (!buf) {
+ printf("Can not allocate output buffer of %d bytes\n", size);
+ goto err0;
+ }
+
+ ret = read(infd, (uint8_t *)buf + 4 * 512, fsize);
+ if (ret != fsize) {
+ ret = -1;
+ goto err1;
+ }
+
+ cb = (struct mx28_sd_config_block *)buf;
+
+ cb->signature = 0x00112233;
+ cb->primary_boot_tag = 0x1;
+ cb->secondary_boot_tag = 0x1;
+ cb->num_copies = 1;
+ cb->drv_info[0].chip_num = 0x0;
+ cb->drv_info[0].drive_type = 0x0;
+ cb->drv_info[0].tag = 0x1;
+ cb->drv_info[0].first_sector_number = sd_sector + 4;
+ cb->drv_info[0].sector_count = (size - 4) / 512;
+
+ wr_size = write(outfd, buf, size);
+ if (wr_size != size) {
+ ret = -1;
+ goto err1;
+ }
+
+ ret = 0;
+
+err1:
+ free(buf);
+err0:
+ return ret;
+}
+
+int parse_ops(int argc, char **argv)
+{
+ int i;
+ int tmp;
+ char *end;
+ enum param {
+ PARAM_WRITE,
+ PARAM_OOB,
+ PARAM_ERASE,
+ PARAM_PART,
+ PARAM_SD,
+ PARAM_NAND
+ };
+ int type;
+
+ if (argc < 4)
+ return -1;
+
+ for (i = 1; i < argc; i++) {
+ if (!strncmp(argv[i], "-w", 2))
+ type = PARAM_WRITE;
+ else if (!strncmp(argv[i], "-o", 2))
+ type = PARAM_OOB;
+ else if (!strncmp(argv[i], "-e", 2))
+ type = PARAM_ERASE;
+ else if (!strncmp(argv[i], "-p", 2))
+ type = PARAM_PART;
+ else /* SD/MMC */
+ break;
+
+ tmp = strtol(argv[++i], &end, 10);
+ if (tmp % 2)
+ return -1;
+ if (tmp <= 0)
+ return -1;
+
+ if (type == PARAM_WRITE)
+ nand_writesize = tmp;
+ if (type == PARAM_OOB)
+ nand_oobsize = tmp;
+ if (type == PARAM_ERASE)
+ nand_erasesize = tmp;
+ if (type == PARAM_PART)
+ sd_sector = tmp;
+ }
+
+ if (strcmp(argv[i], "sd") && strcmp(argv[i], "nand"))
+ return -1;
+
+ if (i + 3 != argc)
+ return -1;
+
+ return i;
+}
+
+int main(int argc, char **argv)
+{
+ int infd, outfd;
+ int ret = 0;
+ int offset;
+
+ offset = parse_ops(argc, argv);
+ if (offset < 0) {
+ usage();
+ ret = 1;
+ goto err1;
+ }
+
+ infd = open(argv[offset + 1], O_RDONLY);
+ if (infd < 0) {
+ printf("Input BootStream file can not be opened\n");
+ ret = 2;
+ goto err1;
+ }
+
+ outfd = open(argv[offset + 2], O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR);
+ if (outfd < 0) {
+ printf("Output file can not be created\n");
+ ret = 3;
+ goto err2;
+ }
+
+ if (!strcmp(argv[offset], "sd"))
+ ret = mx28_create_sd_image(infd, outfd);
+ else if (!strcmp(argv[offset], "nand"))
+ ret = mx28_create_nand_image(infd, outfd);
+
+ close(outfd);
+err2:
+ close(infd);
+err1:
+ return ret;
+}
diff --git a/tools/ncb.c b/tools/ncb.c
new file mode 100644
index 0000000..ec8d8a7
--- /dev/null
+++ b/tools/ncb.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+int main (int argc, char *argv[])
+{
+ int s, len, o, port = 6666;
+ char buf[512];
+ struct sockaddr_in addr;
+ socklen_t addr_len = sizeof addr;
+
+ if (argc > 1)
+ port = atoi (argv[1]);
+
+ s = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ o = 1;
+ len = 4;
+ setsockopt (3, SOL_SOCKET, SO_REUSEADDR, &o, len);
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons (port);
+ addr.sin_addr.s_addr = INADDR_ANY; /* receive broadcasts */
+
+ bind (s, (struct sockaddr *) &addr, sizeof addr);
+
+ for (;;) {
+ len = recvfrom (s, buf, sizeof buf, 0, (struct sockaddr *) &addr, &addr_len);
+ if (len < 0)
+ break;
+ if (write (1, buf, len) != len)
+ fprintf(stderr, "WARNING: serial characters dropped\n");
+ }
+
+ return 0;
+}
diff --git a/tools/netconsole b/tools/netconsole
new file mode 100755
index 0000000..1a0ef22
--- /dev/null
+++ b/tools/netconsole
@@ -0,0 +1,63 @@
+#!/bin/sh
+
+usage() {
+ (
+ echo "Usage: $0 <board-IP> [board-port [board-in-port]]"
+ echo ""
+ echo "If port is not specified, '6666' will be used"
+ [ -z "$*" ] && exit 0
+ echo ""
+ echo "ERROR: $*"
+ exit 1
+ ) 1>&2
+ exit $?
+}
+
+while [ -n "$1" ] ; do
+ case $1 in
+ -h|--help) usage;;
+ --) break;;
+ -*) usage "Invalid option $1";;
+ *) break;;
+ esac
+ shift
+done
+
+ip=$1
+board_out_port=${2:-6666}
+board_in_port=${3:-${board_out_port}}
+
+echo Board out port: ${board_out_port}
+echo Board in port: ${board_in_port}
+
+if [ -z "${ip}" ] || [ -n "$4" ] ; then
+ usage "Invalid number of arguments"
+fi
+
+for nc in netcat nc ; do
+ type ${nc} >/dev/null 2>&1 && break
+done
+
+trap "stty icanon echo intr ^C" 0 2 3 5 10 13 15
+echo "NOTE: the interrupt signal (normally ^C) has been remapped to ^T"
+
+stty -icanon -echo intr ^T
+(
+if type ncb 2>/dev/null ; then
+ # see if ncb is in $PATH
+ exec ncb ${board_out_port}
+
+elif [ -x ${0%/*}/ncb ] ; then
+ # maybe it's in the same dir as the netconsole script
+ exec ${0%/*}/ncb ${board_out_port}
+
+else
+ # blah, just use regular netcat
+ while ${nc} -u -l -p ${board_out_port} < /dev/null ; do
+ :
+ done
+fi
+) &
+pid=$!
+${nc} -u ${ip} ${board_in_port}
+kill ${pid} 2>/dev/null
diff --git a/tools/omap/clocks_get_m_n.c b/tools/omap/clocks_get_m_n.c
new file mode 100644
index 0000000..c27577b
--- /dev/null
+++ b/tools/omap/clocks_get_m_n.c
@@ -0,0 +1,202 @@
+/*
+ * Program for finding M & N values for DPLLs
+ * To be run on Host PC
+ *
+ * (C) Copyright 2010
+ * Texas Instruments, <www.ti.com>
+ *
+ * Aneesh V <aneesh@ti.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <stdlib.h>
+#include <stdio.h>
+typedef unsigned int u32;
+#define MAX_N 127
+
+/*
+ * get_m_n_optimized() - Finds optimal DPLL multiplier(M) and divider(N)
+ * values based on the reference frequency, required output frequency,
+ * maximum tolerance for output frequency etc.
+ *
+ * target_freq_khz - output frequency required in KHz
+ * ref_freq_khz - reference(input) frequency in KHz
+ * m - pointer to computed M value
+ * n - pointer to computed N value
+ * tolerance_khz - tolerance for the output frequency. When the algorithm
+ * succeeds in finding vialble M and N values the corresponding output
+ * frequency will be in the range:
+ * [target_freq_khz - tolerance_khz, target_freq_khz]
+ *
+ * Formula:
+ * Fdpll = (2 * M * Fref) / (N + 1)
+ *
+ * Considerations for lock-time:
+ * - Smaller the N, better lock-time, especially lock-time will be
+ * - For acceptable lock-times:
+ * Fref / (M + 1) >= 1 MHz
+ *
+ * Considerations for power:
+ * - The difference in power for different N values giving the same
+ * output is negligible. So, we optimize for lock-time
+ *
+ * Hard-constraints:
+ * - N can not be greater than 127(7 bit field for representing N)
+ *
+ * Usage:
+ * $ gcc clocks_get_m_n.c
+ * $ ./a.out
+ */
+int get_m_n_optimized(u32 target_freq_khz, u32 ref_freq_khz, u32 *M, u32 *N)
+{
+ u32 freq = target_freq_khz;
+ u32 m_optimal, n_optimal, freq_optimal = 0, freq_old;
+ u32 m, n;
+ n = 1;
+ while (1) {
+ m = target_freq_khz / ref_freq_khz / 2 * n;
+ freq_old = 0;
+ while (1) {
+ freq = ref_freq_khz * 2 * m / n;
+ if (freq > target_freq_khz) {
+ freq = freq_old;
+ m--;
+ break;
+ }
+ m++;
+ freq_old = freq;
+ }
+ if (freq > freq_optimal) {
+ freq_optimal = freq;
+ m_optimal = m;
+ n_optimal = n;
+ }
+ n++;
+ if ((freq_optimal == target_freq_khz) ||
+ ((ref_freq_khz / n) < 1000)) {
+ break;
+ }
+ }
+ n--;
+ *M = m_optimal;
+ *N = n_optimal - 1;
+ printf("ref %d m %d n %d target %d locked %d\n", ref_freq_khz,
+ m_optimal, n_optimal - 1, target_freq_khz, freq_optimal);
+ return 0;
+}
+
+void main(void)
+{
+ u32 m, n;
+ printf("\nMPU - 2000000\n");
+ get_m_n_optimized(2000000, 12000, &m, &n);
+ get_m_n_optimized(2000000, 13000, &m, &n);
+ get_m_n_optimized(2000000, 16800, &m, &n);
+ get_m_n_optimized(2000000, 19200, &m, &n);
+ get_m_n_optimized(2000000, 26000, &m, &n);
+ get_m_n_optimized(2000000, 27000, &m, &n);
+ get_m_n_optimized(2000000, 38400, &m, &n);
+
+ printf("\nMPU - 1200000\n");
+ get_m_n_optimized(1200000, 12000, &m, &n);
+ get_m_n_optimized(1200000, 13000, &m, &n);
+ get_m_n_optimized(1200000, 16800, &m, &n);
+ get_m_n_optimized(1200000, 19200, &m, &n);
+ get_m_n_optimized(1200000, 26000, &m, &n);
+ get_m_n_optimized(1200000, 27000, &m, &n);
+ get_m_n_optimized(1200000, 38400, &m, &n);
+
+ printf("\nMPU - 1584000\n");
+ get_m_n_optimized(1584000, 12000, &m, &n);
+ get_m_n_optimized(1584000, 13000, &m, &n);
+ get_m_n_optimized(1584000, 16800, &m, &n);
+ get_m_n_optimized(1584000, 19200, &m, &n);
+ get_m_n_optimized(1584000, 26000, &m, &n);
+ get_m_n_optimized(1584000, 27000, &m, &n);
+ get_m_n_optimized(1584000, 38400, &m, &n);
+
+ printf("\nCore 1600000\n");
+ get_m_n_optimized(1600000, 12000, &m, &n);
+ get_m_n_optimized(1600000, 13000, &m, &n);
+ get_m_n_optimized(1600000, 16800, &m, &n);
+ get_m_n_optimized(1600000, 19200, &m, &n);
+ get_m_n_optimized(1600000, 26000, &m, &n);
+ get_m_n_optimized(1600000, 27000, &m, &n);
+ get_m_n_optimized(1600000, 38400, &m, &n);
+
+ printf("\nPER 1536000\n");
+ get_m_n_optimized(1536000, 12000, &m, &n);
+ get_m_n_optimized(1536000, 13000, &m, &n);
+ get_m_n_optimized(1536000, 16800, &m, &n);
+ get_m_n_optimized(1536000, 19200, &m, &n);
+ get_m_n_optimized(1536000, 26000, &m, &n);
+ get_m_n_optimized(1536000, 27000, &m, &n);
+ get_m_n_optimized(1536000, 38400, &m, &n);
+
+ printf("\nIVA 1862000\n");
+ get_m_n_optimized(1862000, 12000, &m, &n);
+ get_m_n_optimized(1862000, 13000, &m, &n);
+ get_m_n_optimized(1862000, 16800, &m, &n);
+ get_m_n_optimized(1862000, 19200, &m, &n);
+ get_m_n_optimized(1862000, 26000, &m, &n);
+ get_m_n_optimized(1862000, 27000, &m, &n);
+ get_m_n_optimized(1862000, 38400, &m, &n);
+
+ printf("\nIVA Nitro - 1290000\n");
+ get_m_n_optimized(1290000, 12000, &m, &n);
+ get_m_n_optimized(1290000, 13000, &m, &n);
+ get_m_n_optimized(1290000, 16800, &m, &n);
+ get_m_n_optimized(1290000, 19200, &m, &n);
+ get_m_n_optimized(1290000, 26000, &m, &n);
+ get_m_n_optimized(1290000, 27000, &m, &n);
+ get_m_n_optimized(1290000, 38400, &m, &n);
+
+ printf("\nABE 196608 sys clk\n");
+ get_m_n_optimized(196608, 12000, &m, &n);
+ get_m_n_optimized(196608, 13000, &m, &n);
+ get_m_n_optimized(196608, 16800, &m, &n);
+ get_m_n_optimized(196608, 19200, &m, &n);
+ get_m_n_optimized(196608, 26000, &m, &n);
+ get_m_n_optimized(196608, 27000, &m, &n);
+ get_m_n_optimized(196608, 38400, &m, &n);
+
+ printf("\nABE 196608 32K\n");
+ get_m_n_optimized(196608000/4, 32768, &m, &n);
+
+ printf("\nUSB 1920000\n");
+ get_m_n_optimized(1920000, 12000, &m, &n);
+ get_m_n_optimized(1920000, 13000, &m, &n);
+ get_m_n_optimized(1920000, 16800, &m, &n);
+ get_m_n_optimized(1920000, 19200, &m, &n);
+ get_m_n_optimized(1920000, 26000, &m, &n);
+ get_m_n_optimized(1920000, 27000, &m, &n);
+ get_m_n_optimized(1920000, 38400, &m, &n);
+
+ printf("\nCore ES1 1523712\n");
+ get_m_n_optimized(1524000, 12000, &m, &n);
+ get_m_n_optimized(1524000, 13000, &m, &n);
+ get_m_n_optimized(1524000, 16800, &m, &n);
+ get_m_n_optimized(1524000, 19200, &m, &n);
+ get_m_n_optimized(1524000, 26000, &m, &n);
+ get_m_n_optimized(1524000, 27000, &m, &n);
+
+ /* exact recommendation for SDPs */
+ get_m_n_optimized(1523712, 38400, &m, &n);
+
+}
diff --git a/tools/omapimage.c b/tools/omapimage.c
new file mode 100644
index 0000000..d242cca
--- /dev/null
+++ b/tools/omapimage.c
@@ -0,0 +1,270 @@
+/*
+ * (C) Copyright 2010
+ * Linaro LTD, www.linaro.org
+ * Author: John Rigby <john.rigby@linaro.org>
+ * Based on TI's signGP.c
+ *
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Required to obtain the getline prototype from stdio.h */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include <image.h>
+#include "omapimage.h"
+
+/* Header size is CH header rounded up to 512 bytes plus GP header */
+#define OMAP_CH_HDR_SIZE 512
+#define OMAP_GP_HDR_SIZE (sizeof(struct gp_header))
+#define OMAP_FILE_HDR_SIZE (OMAP_CH_HDR_SIZE+OMAP_GP_HDR_SIZE)
+
+static int do_swap32 = 0;
+
+static uint32_t omapimage_swap32(uint32_t data)
+{
+ uint32_t result = 0;
+ result = (data & 0xFF000000) >> 24;
+ result |= (data & 0x00FF0000) >> 8;
+ result |= (data & 0x0000FF00) << 8;
+ result |= (data & 0x000000FF) << 24;
+ return result;
+}
+
+static uint8_t omapimage_header[OMAP_FILE_HDR_SIZE];
+
+static int omapimage_check_image_types(uint8_t type)
+{
+ if (type == IH_TYPE_OMAPIMAGE)
+ return EXIT_SUCCESS;
+ else {
+ return EXIT_FAILURE;
+ }
+}
+
+/*
+ * Only the simplest image type is currently supported:
+ * TOC pointing to CHSETTINGS
+ * TOC terminator
+ * CHSETTINGS
+ *
+ * padding to OMAP_CH_HDR_SIZE bytes
+ *
+ * gp header
+ * size
+ * load_addr
+ */
+static int valid_gph_size(uint32_t size)
+{
+ return size;
+}
+
+static int valid_gph_load_addr(uint32_t load_addr)
+{
+ return load_addr;
+}
+
+static int omapimage_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct ch_toc *toc = (struct ch_toc *)ptr;
+ struct gp_header *gph = (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE);
+ uint32_t offset, size, gph_size, gph_load_addr;
+
+ while (toc->section_offset != 0xffffffff
+ && toc->section_size != 0xffffffff) {
+ if (do_swap32) {
+ offset = omapimage_swap32(toc->section_offset);
+ size = omapimage_swap32(toc->section_size);
+ } else {
+ offset = toc->section_offset;
+ size = toc->section_size;
+ }
+ if (!offset || !size)
+ return -1;
+ if (offset >= OMAP_CH_HDR_SIZE ||
+ offset+size >= OMAP_CH_HDR_SIZE)
+ return -1;
+ toc++;
+ }
+
+ if (do_swap32) {
+ gph_size = omapimage_swap32(gph->size);
+ gph_load_addr = omapimage_swap32(gph->load_addr);
+ } else {
+ gph_size = gph->size;
+ gph_load_addr = gph->load_addr;
+ }
+
+ if (!valid_gph_size(gph_size))
+ return -1;
+ if (!valid_gph_load_addr(gph_load_addr))
+ return -1;
+
+ return 0;
+}
+
+static void omapimage_print_section(struct ch_settings *chs)
+{
+ const char *section_name;
+
+ if (chs->section_key)
+ section_name = "CHSETTINGS";
+ else
+ section_name = "UNKNOWNKEY";
+
+ printf("%s (%x) "
+ "valid:%x "
+ "version:%x "
+ "reserved:%x "
+ "flags:%x\n",
+ section_name,
+ chs->section_key,
+ chs->valid,
+ chs->version,
+ chs->reserved,
+ chs->flags);
+}
+
+static void omapimage_print_header(const void *ptr)
+{
+ const struct ch_toc *toc = (struct ch_toc *)ptr;
+ const struct gp_header *gph =
+ (struct gp_header *)(ptr+OMAP_CH_HDR_SIZE);
+ uint32_t offset, size, gph_size, gph_load_addr;
+
+ while (toc->section_offset != 0xffffffff
+ && toc->section_size != 0xffffffff) {
+ if (do_swap32) {
+ offset = omapimage_swap32(toc->section_offset);
+ size = omapimage_swap32(toc->section_size);
+ } else {
+ offset = toc->section_offset;
+ size = toc->section_size;
+ }
+
+ if (offset >= OMAP_CH_HDR_SIZE ||
+ offset+size >= OMAP_CH_HDR_SIZE)
+ exit(EXIT_FAILURE);
+
+ printf("Section %s offset %x length %x\n",
+ toc->section_name,
+ toc->section_offset,
+ toc->section_size);
+
+ omapimage_print_section((struct ch_settings *)(ptr+offset));
+ toc++;
+ }
+
+ if (do_swap32) {
+ gph_size = omapimage_swap32(gph->size);
+ gph_load_addr = omapimage_swap32(gph->load_addr);
+ } else {
+ gph_size = gph->size;
+ gph_load_addr = gph->load_addr;
+ }
+
+ if (!valid_gph_size(gph_size)) {
+ fprintf(stderr, "Error: invalid image size %x\n", gph_size);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!valid_gph_load_addr(gph_load_addr)) {
+ fprintf(stderr, "Error: invalid image load address %x\n",
+ gph_load_addr);
+ exit(EXIT_FAILURE);
+ }
+
+ printf("GP Header: Size %x LoadAddr %x\n", gph_size, gph_load_addr);
+}
+
+static int toc_offset(void *hdr, void *member)
+{
+ return member - hdr;
+}
+
+static void omapimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ struct ch_toc *toc = (struct ch_toc *)ptr;
+ struct ch_settings *chs = (struct ch_settings *)
+ (ptr + 2 * sizeof(*toc));
+ struct gp_header *gph = (struct gp_header *)(ptr + OMAP_CH_HDR_SIZE);
+
+ toc->section_offset = toc_offset(ptr, chs);
+ toc->section_size = sizeof(struct ch_settings);
+ strcpy((char *)toc->section_name, "CHSETTINGS");
+
+ chs->section_key = KEY_CHSETTINGS;
+ chs->valid = 0;
+ chs->version = 1;
+ chs->reserved = 0;
+ chs->flags = 0;
+
+ toc++;
+ memset(toc, 0xff, sizeof(*toc));
+
+ gph->size = sbuf->st_size - OMAP_FILE_HDR_SIZE;
+ gph->load_addr = params->addr;
+
+ if (strncmp(params->imagename, "byteswap", 8) == 0) {
+ do_swap32 = 1;
+ int swapped = 0;
+ uint32_t *data = (uint32_t *)ptr;
+
+ while (swapped <= (sbuf->st_size / sizeof(uint32_t))) {
+ *data = omapimage_swap32(*data);
+ swapped++;
+ data++;
+ }
+ }
+}
+
+int omapimage_check_params(struct mkimage_params *params)
+{
+ return (params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag));
+}
+
+/*
+ * omapimage parameters
+ */
+static struct image_type_params omapimage_params = {
+ .name = "TI OMAP CH/GP Boot Image support",
+ .header_size = OMAP_FILE_HDR_SIZE,
+ .hdr = (void *)&omapimage_header,
+ .check_image_type = omapimage_check_image_types,
+ .verify_header = omapimage_verify_header,
+ .print_header = omapimage_print_header,
+ .set_header = omapimage_set_header,
+ .check_params = omapimage_check_params,
+};
+
+void init_omap_image_type(void)
+{
+ mkimage_register(&omapimage_params);
+}
diff --git a/tools/omapimage.h b/tools/omapimage.h
new file mode 100644
index 0000000..719db00
--- /dev/null
+++ b/tools/omapimage.h
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2010
+ * Linaro LTD, www.linaro.org
+ * Author John Rigby <john.rigby@linaro.org>
+ * Based on TI's signGP.c
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _OMAPIMAGE_H_
+#define _OMAPIMAGE_H_
+
+struct ch_toc {
+ uint32_t section_offset;
+ uint32_t section_size;
+ uint8_t unused[12];
+ uint8_t section_name[12];
+};
+
+struct ch_settings {
+ uint32_t section_key;
+ uint8_t valid;
+ uint8_t version;
+ uint16_t reserved;
+ uint32_t flags;
+};
+
+struct gp_header {
+ uint32_t size;
+ uint32_t load_addr;
+};
+
+#define KEY_CHSETTINGS 0xC0C0C0C1
+#endif /* _OMAPIMAGE_H_ */
diff --git a/tools/os_support.c b/tools/os_support.c
new file mode 100644
index 0000000..319c0fe
--- /dev/null
+++ b/tools/os_support.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2009 Extreme Engineering Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this software; if not, write to the
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Include additional files required for supporting different operating systems
+ */
+#include "compiler.h"
+#ifdef __MINGW32__
+#include "mingw_support.c"
+#endif
+#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+#include "getline.c"
+#endif
diff --git a/tools/os_support.h b/tools/os_support.h
new file mode 100644
index 0000000..5bf7add
--- /dev/null
+++ b/tools/os_support.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2009 Extreme Engineering Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this software; if not, write to the
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __OS_SUPPORT_H_
+#define __OS_SUPPORT_H_
+
+#include "compiler.h"
+
+/*
+ * Include additional files required for supporting different operating systems
+ */
+#ifdef __MINGW32__
+#include "mingw_support.h"
+#endif
+
+#if defined(__APPLE__) && __DARWIN_C_LEVEL < 200809L
+#include "getline.h"
+#endif
+
+#endif /* __OS_SUPPORT_H_ */
diff --git a/tools/palmtreo680/flash_u-boot.c b/tools/palmtreo680/flash_u-boot.c
new file mode 100644
index 0000000..3d8296f
--- /dev/null
+++ b/tools/palmtreo680/flash_u-boot.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2013 Mike Dunn <mikedunn@newsguy.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ *
+ * This is a userspace Linux utility that, when run on the Treo 680, will
+ * program u-boot to flash. The docg4 driver *must* be loaded with the
+ * reliable_mode and ignore_badblocks parameters enabled:
+ *
+ * modprobe docg4 ignore_badblocks=1 reliable_mode=1
+ *
+ * This utility writes the concatenated spl + u-boot image to the start of the
+ * mtd device in the format expected by the IPL/SPL. The image file and mtd
+ * device node are passed to the utility as arguments. The blocks must have
+ * been erased beforehand.
+ *
+ * When you compile this, note that it links to libmtd from mtd-utils, so ensure
+ * that your include and lib paths include this.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <mtd/mtd-user.h>
+#include "libmtd.h"
+
+#define RELIABLE_BLOCKSIZE 0x10000 /* block capacity in reliable mode */
+#define STANDARD_BLOCKSIZE 0x40000 /* block capacity in normal mode */
+#define PAGESIZE 512
+#define PAGES_PER_BLOCK 512
+#define OOBSIZE 7 /* available to user (16 total) */
+
+uint8_t ff_oob[OOBSIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+/* this is the magic number the IPL looks for (ASCII "BIPO") */
+uint8_t page0_oob[OOBSIZE] = {'B', 'I', 'P', 'O', 0xff, 0xff, 0xff};
+
+int main(int argc, char * const argv[])
+{
+ int devfd, datafd, num_blocks, block;
+ off_t file_size;
+ libmtd_t mtd_desc;
+ struct mtd_dev_info devinfo;
+ uint8_t *blockbuf;
+ char response[8];
+
+ if (argc != 3) {
+ printf("usage: %s <image file> <mtd dev node>\n", argv[0]);
+ return -EINVAL;
+ }
+
+ mtd_desc = libmtd_open();
+ if (mtd_desc == NULL) {
+ int errsv = errno;
+ fprintf(stderr, "can't initialize libmtd\n");
+ return -errsv;
+ }
+
+ /* open the spl image file and mtd device */
+ datafd = open(argv[1], O_RDONLY);
+ if (datafd == -1) {
+ int errsv = errno;
+ perror(argv[1]);
+ return -errsv;
+ }
+ devfd = open(argv[2], O_WRONLY);
+ if (devfd == -1) {
+ int errsv = errno;
+ perror(argv[2]);
+ return -errsv;
+ }
+ if (mtd_get_dev_info(mtd_desc, argv[2], &devinfo) < 0) {
+ int errsv = errno;
+ perror(argv[2]);
+ return -errsv;
+ }
+
+ /* determine the number of blocks needed by the image */
+ file_size = lseek(datafd, 0, SEEK_END);
+ if (file_size == (off_t)-1) {
+ int errsv = errno;
+ perror("lseek");
+ return -errsv;
+ }
+ num_blocks = (file_size + RELIABLE_BLOCKSIZE - 1) / RELIABLE_BLOCKSIZE;
+ file_size = lseek(datafd, 0, SEEK_SET);
+ if (file_size == (off_t)-1) {
+ int errsv = errno;
+ perror("lseek");
+ return -errsv;
+ }
+ printf("The mtd partition contains %d blocks\n", devinfo.eb_cnt);
+ printf("U-boot will occupy %d blocks\n", num_blocks);
+ if (num_blocks > devinfo.eb_cnt) {
+ fprintf(stderr, "Insufficient blocks on partition\n");
+ return -EINVAL;
+ }
+
+ printf("IMPORTANT: These blocks must be in an erased state!\n");
+ printf("Do you want to proceed?\n");
+ scanf("%s", response);
+ if ((response[0] != 'y') && (response[0] != 'Y')) {
+ printf("Exiting\n");
+ close(devfd);
+ close(datafd);
+ return 0;
+ }
+
+ blockbuf = calloc(RELIABLE_BLOCKSIZE, 1);
+ if (blockbuf == NULL) {
+ int errsv = errno;
+ perror("calloc");
+ return -errsv;
+ }
+
+ for (block = 0; block < num_blocks; block++) {
+ int ofs, page;
+ uint8_t *pagebuf = blockbuf, *buf = blockbuf;
+ uint8_t *oobbuf = page0_oob; /* magic num in oob of 1st page */
+ size_t len = RELIABLE_BLOCKSIZE;
+ int ret;
+
+ /* read data for one block from file */
+ while (len) {
+ ssize_t read_ret = read(datafd, buf, len);
+ if (read_ret == -1) {
+ int errsv = errno;
+ if (errno == EINTR)
+ continue;
+ perror("read");
+ return -errsv;
+ } else if (read_ret == 0) {
+ break; /* EOF */
+ }
+ len -= read_ret;
+ buf += read_ret;
+ }
+
+ printf("Block %d: writing\r", block + 1);
+ fflush(stdout);
+
+ for (page = 0, ofs = 0;
+ page < PAGES_PER_BLOCK;
+ page++, ofs += PAGESIZE) {
+ if (page & 0x04) /* Odd-numbered 2k page */
+ continue; /* skipped in reliable mode */
+
+ ret = mtd_write(mtd_desc, &devinfo, devfd, block, ofs,
+ pagebuf, PAGESIZE, oobbuf, OOBSIZE,
+ MTD_OPS_PLACE_OOB);
+ if (ret) {
+ fprintf(stderr,
+ "\nmtd_write returned %d on block %d, ofs %x\n",
+ ret, block + 1, ofs);
+ return -EIO;
+ }
+ oobbuf = ff_oob; /* oob for subsequent pages */
+
+ if (page & 0x01) /* odd-numbered subpage */
+ pagebuf += PAGESIZE;
+ }
+ }
+
+ printf("\nDone\n");
+
+ close(devfd);
+ close(datafd);
+ free(blockbuf);
+ return 0;
+}
diff --git a/tools/patman/.gitignore b/tools/patman/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/tools/patman/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/tools/patman/README b/tools/patman/README
new file mode 100644
index 0000000..c954989
--- /dev/null
+++ b/tools/patman/README
@@ -0,0 +1,472 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+What is this?
+=============
+
+This tool is a Python script which:
+- Creates patch directly from your branch
+- Cleans them up by removing unwanted tags
+- Inserts a cover letter with change lists
+- Runs the patches through checkpatch.pl and its own checks
+- Optionally emails them out to selected people
+
+It is intended to automate patch creation and make it a less
+error-prone process. It is useful for U-Boot and Linux work so far,
+since it uses the checkpatch.pl script.
+
+It is configured almost entirely by tags it finds in your commits.
+This means that you can work on a number of different branches at
+once, and keep the settings with each branch rather than having to
+git format-patch, git send-email, etc. with the correct parameters
+each time. So for example if you put:
+
+Series-to: fred.blogs@napier.co.nz
+
+in one of your commits, the series will be sent there.
+
+In Linux this will also call get_maintainer.pl on each of your
+patches automatically.
+
+
+How to use this tool
+====================
+
+This tool requires a certain way of working:
+
+- Maintain a number of branches, one for each patch series you are
+working on
+- Add tags into the commits within each branch to indicate where the
+series should be sent, cover letter, version, etc. Most of these are
+normally in the top commit so it is easy to change them with 'git
+commit --amend'
+- Each branch tracks the upstream branch, so that this script can
+automatically determine the number of commits in it (optional)
+- Check out a branch, and run this script to create and send out your
+patches. Weeks later, change the patches and repeat, knowing that you
+will get a consistent result each time.
+
+
+How to configure it
+===================
+
+For most cases of using patman for U-Boot development, patman will
+locate and use the file 'doc/git-mailrc' in your U-Boot directory.
+This contains most of the aliases you will need.
+
+For Linux the 'scripts/get_maintainer.pl' handles figuring out where
+to send patches pretty well.
+
+During the first run patman creates a config file for you by taking the default
+user name and email address from the global .gitconfig file.
+
+To add your own, create a file ~/.patman like this:
+
+>>>>
+# patman alias file
+
+[alias]
+me: Simon Glass <sjg@chromium.org>
+
+u-boot: U-Boot Mailing List <u-boot@lists.denx.de>
+wolfgang: Wolfgang Denk <wd@denx.de>
+others: Mike Frysinger <vapier@gentoo.org>, Fred Bloggs <f.bloggs@napier.net>
+
+<<<<
+
+Aliases are recursive.
+
+The checkpatch.pl in the U-Boot tools/ subdirectory will be located and
+used. Failing that you can put it into your path or ~/bin/checkpatch.pl
+
+
+If you want to change the defaults for patman's command-line arguments,
+you can add a [settings] section to your .patman file. This can be used
+for any command line option by referring to the "dest" for the option in
+patman.py. For reference, the useful ones (at the moment) shown below
+(all with the non-default setting):
+
+>>>
+
+[settings]
+ignore_errors: True
+process_tags: False
+verbose: True
+
+<<<
+
+
+If you want to adjust settings (or aliases) that affect just a single
+project you can add a section that looks like [project_settings] or
+[project_alias]. If you want to use tags for your linux work, you could
+do:
+
+>>>
+
+[linux_settings]
+process_tags: True
+
+<<<
+
+
+How to run it
+=============
+
+First do a dry run:
+
+$ ./tools/patman/patman -n
+
+If it can't detect the upstream branch, try telling it how many patches
+there are in your series:
+
+$ ./tools/patman/patman -n -c5
+
+This will create patch files in your current directory and tell you who
+it is thinking of sending them to. Take a look at the patch files.
+
+$ ./tools/patman/patman -n -c5 -s1
+
+Similar to the above, but skip the first commit and take the next 5. This
+is useful if your top commit is for setting up testing.
+
+
+How to add tags
+===============
+
+To make this script useful you must add tags like the following into any
+commit. Most can only appear once in the whole series.
+
+Series-to: email / alias
+ Email address / alias to send patch series to (you can add this
+ multiple times)
+
+Series-cc: email / alias, ...
+ Email address / alias to Cc patch series to (you can add this
+ multiple times)
+
+Series-version: n
+ Sets the version number of this patch series
+
+Series-prefix: prefix
+ Sets the subject prefix. Normally empty but it can be RFC for
+ RFC patches, or RESEND if you are being ignored.
+
+Series-name: name
+ Sets the name of the series. You don't need to have a name, and
+ patman does not yet use it, but it is convenient to put the branch
+ name here to help you keep track of multiple upstreaming efforts.
+
+Cover-letter:
+This is the patch set title
+blah blah
+more blah blah
+END
+ Sets the cover letter contents for the series. The first line
+ will become the subject of the cover letter
+
+Cover-letter-cc: email / alias
+ Additional email addresses / aliases to send cover letter to (you
+ can add this multiple times)
+
+Series-notes:
+blah blah
+blah blah
+more blah blah
+END
+ Sets some notes for the patch series, which you don't want in
+ the commit messages, but do want to send, The notes are joined
+ together and put after the cover letter. Can appear multiple
+ times.
+
+ Signed-off-by: Their Name <email>
+ A sign-off is added automatically to your patches (this is
+ probably a bug). If you put this tag in your patches, it will
+ override the default signoff that patman automatically adds.
+
+ Tested-by: Their Name <email>
+ Reviewed-by: Their Name <email>
+ Acked-by: Their Name <email>
+ These indicate that someone has tested/reviewed/acked your patch.
+ When you get this reply on the mailing list, you can add this
+ tag to the relevant commit and the script will include it when
+ you send out the next version. If 'Tested-by:' is set to
+ yourself, it will be removed. No one will believe you.
+
+Series-changes: n
+- Guinea pig moved into its cage
+- Other changes ending with a blank line
+<blank line>
+ This can appear in any commit. It lists the changes for a
+ particular version n of that commit. The change list is
+ created based on this information. Each commit gets its own
+ change list and also the whole thing is repeated in the cover
+ letter (where duplicate change lines are merged).
+
+ By adding your change lists into your commits it is easier to
+ keep track of what happened. When you amend a commit, remember
+ to update the log there and then, knowing that the script will
+ do the rest.
+
+ Cc: Their Name <email>
+ This copies a single patch to another email address.
+
+Series-process-log: sort, uniq
+ This tells patman to sort and/or uniq the change logs. It is
+ assumed that each change log entry is only a single line long.
+ Use 'sort' to sort the entries, and 'uniq' to include only
+ unique entries. If omitted, no change log processing is done.
+ Separate each tag with a comma.
+
+Various other tags are silently removed, like these Chrome OS and
+Gerrit tags:
+
+BUG=...
+TEST=...
+Change-Id:
+Review URL:
+Reviewed-on:
+
+
+Exercise for the reader: Try adding some tags to one of your current
+patch series and see how the patches turn out.
+
+
+Where Patches Are Sent
+======================
+
+Once the patches are created, patman sends them using git send-email. The
+whole series is sent to the recipients in Series-to: and Series-cc.
+You can Cc individual patches to other people with the Cc: tag. Tags in the
+subject are also picked up to Cc patches. For example, a commit like this:
+
+>>>>
+commit 10212537b85ff9b6e09c82045127522c0f0db981
+Author: Mike Frysinger <vapier@gentoo.org>
+Date: Mon Nov 7 23:18:44 2011 -0500
+
+ x86: arm: add a git mailrc file for maintainers
+
+ This should make sending out e-mails to the right people easier.
+
+ Cc: sandbox, mikef, ag
+ Cc: afleming
+<<<<
+
+will create a patch which is copied to x86, arm, sandbox, mikef, ag and
+afleming.
+
+If you have a cover letter it will get sent to the union of the CC lists of
+all of the other patches. If you want to sent it to additional people you
+can add a tag:
+
+Cover-letter-cc: <list of addresses>
+
+These people will get the cover letter even if they are not on the To/Cc
+list for any of the patches.
+
+
+Example Work Flow
+=================
+
+The basic workflow is to create your commits, add some tags to the top
+commit, and type 'patman' to check and send them.
+
+Here is an example workflow for a series of 4 patches. Let's say you have
+these rather contrived patches in the following order in branch us-cmd in
+your tree where 'us' means your upstreaming activity (newest to oldest as
+output by git log --oneline):
+
+ 7c7909c wip
+ 89234f5 Don't include standard parser if hush is used
+ 8d640a7 mmc: sparc: Stop using builtin_run_command()
+ 0c859a9 Rename run_command2() to run_command()
+ a74443f sandbox: Rename run_command() to builtin_run_command()
+
+The first patch is some test things that enable your code to be compiled,
+but that you don't want to submit because there is an existing patch for it
+on the list. So you can tell patman to create and check some patches
+(skipping the first patch) with:
+
+ patman -s1 -n
+
+If you want to do all of them including the work-in-progress one, then
+(if you are tracking an upstream branch):
+
+ patman -n
+
+Let's say that patman reports an error in the second patch. Then:
+
+ git rebase -i HEAD~6
+ <change 'pick' to 'edit' in 89234f5>
+ <use editor to make code changes>
+ git add -u
+ git rebase --continue
+
+Now you have an updated patch series. To check it:
+
+ patman -s1 -n
+
+Let's say it is now clean and you want to send it. Now you need to set up
+the destination. So amend the top commit with:
+
+ git commit --amend
+
+Use your editor to add some tags, so that the whole commit message is:
+
+ The current run_command() is really only one of the options, with
+ hush providing the other. It really shouldn't be called directly
+ in case the hush parser is bring used, so rename this function to
+ better explain its purpose.
+
+ Series-to: u-boot
+ Series-cc: bfin, marex
+ Series-prefix: RFC
+ Cover-letter:
+ Unified command execution in one place
+
+ At present two parsers have similar code to execute commands. Also
+ cmd_usage() is called all over the place. This series adds a single
+ function which processes commands called cmd_process().
+ END
+
+ Change-Id: Ica71a14c1f0ecb5650f771a32fecb8d2eb9d8a17
+
+
+You want this to be an RFC and Cc the whole series to the bfin alias and
+to Marek. Two of the patches have tags (those are the bits at the front of
+the subject that say mmc: sparc: and sandbox:), so 8d640a7 will be Cc'd to
+mmc and sparc, and the last one to sandbox.
+
+Now to send the patches, take off the -n flag:
+
+ patman -s1
+
+The patches will be created, shown in your editor, and then sent along with
+the cover letter. Note that patman's tags are automatically removed so that
+people on the list don't see your secret info.
+
+Of course patches often attract comments and you need to make some updates.
+Let's say one person sent comments and you get an Acked-by: on one patch.
+Also, the patch on the list that you were waiting for has been merged,
+so you can drop your wip commit. So you resync with upstream:
+
+ git fetch origin (or whatever upstream is called)
+ git rebase origin/master
+
+and use git rebase -i to edit the commits, dropping the wip one. You add
+the ack tag to one commit:
+
+ Acked-by: Heiko Schocher <hs@denx.de>
+
+update the Series-cc: in the top commit:
+
+ Series-cc: bfin, marex, Heiko Schocher <hs@denx.de>
+
+and remove the Series-prefix: tag since it it isn't an RFC any more. The
+series is now version two, so the series info in the top commit looks like
+this:
+
+ Series-to: u-boot
+ Series-cc: bfin, marex, Heiko Schocher <hs@denx.de>
+ Series-version: 2
+ Cover-letter:
+ ...
+
+Finally, you need to add a change log to the two commits you changed. You
+add change logs to each individual commit where the changes happened, like
+this:
+
+ Series-changes: 2
+ - Updated the command decoder to reduce code size
+ - Wound the torque propounder up a little more
+
+(note the blank line at the end of the list)
+
+When you run patman it will collect all the change logs from the different
+commits and combine them into the cover letter, if you have one. So finally
+you have a new series of commits:
+
+ faeb973 Don't include standard parser if hush is used
+ 1b2f2fe mmc: sparc: Stop using builtin_run_command()
+ cfbe330 Rename run_command2() to run_command()
+ 0682677 sandbox: Rename run_command() to builtin_run_command()
+
+so to send them:
+
+ patman
+
+and it will create and send the version 2 series.
+
+General points:
+
+1. When you change back to the us-cmd branch days or weeks later all your
+information is still there, safely stored in the commits. You don't need
+to remember what version you are up to, who you sent the last lot of patches
+to, or anything about the change logs.
+
+2. If you put tags in the subject, patman will Cc the maintainers
+automatically in many cases.
+
+3. If you want to keep the commits from each series you sent so that you can
+compare change and see what you did, you can either create a new branch for
+each version, or just tag the branch before you start changing it:
+
+ git tag sent/us-cmd-rfc
+ ...later...
+ git tag sent/us-cmd-v2
+
+4. If you want to modify the patches a little before sending, you can do
+this in your editor, but be careful!
+
+5. If you want to run git send-email yourself, use the -n flag which will
+print out the command line patman would have used.
+
+6. It is a good idea to add the change log info as you change the commit,
+not later when you can't remember which patch you changed. You can always
+go back and change or remove logs from commits.
+
+
+Other thoughts
+==============
+
+This script has been split into sensible files but still needs work.
+Most of these are indicated by a TODO in the code.
+
+It would be nice if this could handle the In-reply-to side of things.
+
+The tests are incomplete, as is customary. Use the --test flag to run them,
+and make sure you are in the tools/patman directory first:
+
+ $ cd /path/to/u-boot
+ $ cd tools/patman
+ $ ./patman --test
+
+Error handling doesn't always produce friendly error messages - e.g.
+putting an incorrect tag in a commit may provide a confusing message.
+
+There might be a few other features not mentioned in this README. They
+might be bugs. In particular, tags are case sensitive which is probably
+a bad thing.
+
+
+Simon Glass <sjg@chromium.org>
+v1, v2, 19-Oct-11
+revised v3 24-Nov-11
diff --git a/tools/patman/checkpatch.py b/tools/patman/checkpatch.py
new file mode 100644
index 0000000..83aaf71
--- /dev/null
+++ b/tools/patman/checkpatch.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import collections
+import command
+import gitutil
+import os
+import re
+import sys
+import terminal
+
+def FindCheckPatch():
+ top_level = gitutil.GetTopLevel()
+ try_list = [
+ os.getcwd(),
+ os.path.join(os.getcwd(), '..', '..'),
+ os.path.join(top_level, 'tools'),
+ os.path.join(top_level, 'scripts'),
+ '%s/bin' % os.getenv('HOME'),
+ ]
+ # Look in current dir
+ for path in try_list:
+ fname = os.path.join(path, 'checkpatch.pl')
+ if os.path.isfile(fname):
+ return fname
+
+ # Look upwwards for a Chrome OS tree
+ while not os.path.ismount(path):
+ fname = os.path.join(path, 'src', 'third_party', 'kernel', 'files',
+ 'scripts', 'checkpatch.pl')
+ if os.path.isfile(fname):
+ return fname
+ path = os.path.dirname(path)
+
+ print >> sys.stderr, ('Cannot find checkpatch.pl - please put it in your ' +
+ '~/bin directory or use --no-check')
+ sys.exit(1)
+
+def CheckPatch(fname, verbose=False):
+ """Run checkpatch.pl on a file.
+
+ Returns:
+ namedtuple containing:
+ ok: False=failure, True=ok
+ problems: List of problems, each a dict:
+ 'type'; error or warning
+ 'msg': text message
+ 'file' : filename
+ 'line': line number
+ errors: Number of errors
+ warnings: Number of warnings
+ checks: Number of checks
+ lines: Number of lines
+ stdout: Full output of checkpatch
+ """
+ fields = ['ok', 'problems', 'errors', 'warnings', 'checks', 'lines',
+ 'stdout']
+ result = collections.namedtuple('CheckPatchResult', fields)
+ result.ok = False
+ result.errors, result.warning, result.checks = 0, 0, 0
+ result.lines = 0
+ result.problems = []
+ chk = FindCheckPatch()
+ item = {}
+ result.stdout = command.Output(chk, '--no-tree', fname)
+ #pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ #stdout, stderr = pipe.communicate()
+
+ # total: 0 errors, 0 warnings, 159 lines checked
+ # or:
+ # total: 0 errors, 2 warnings, 7 checks, 473 lines checked
+ re_stats = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)')
+ re_stats_full = re.compile('total: (\\d+) errors, (\d+) warnings, (\d+)'
+ ' checks, (\d+)')
+ re_ok = re.compile('.*has no obvious style problems')
+ re_bad = re.compile('.*has style problems, please review')
+ re_error = re.compile('ERROR: (.*)')
+ re_warning = re.compile('WARNING: (.*)')
+ re_check = re.compile('CHECK: (.*)')
+ re_file = re.compile('#\d+: FILE: ([^:]*):(\d+):')
+
+ for line in result.stdout.splitlines():
+ if verbose:
+ print line
+
+ # A blank line indicates the end of a message
+ if not line and item:
+ result.problems.append(item)
+ item = {}
+ match = re_stats_full.match(line)
+ if not match:
+ match = re_stats.match(line)
+ if match:
+ result.errors = int(match.group(1))
+ result.warnings = int(match.group(2))
+ if len(match.groups()) == 4:
+ result.checks = int(match.group(3))
+ result.lines = int(match.group(4))
+ else:
+ result.lines = int(match.group(3))
+ elif re_ok.match(line):
+ result.ok = True
+ elif re_bad.match(line):
+ result.ok = False
+ err_match = re_error.match(line)
+ warn_match = re_warning.match(line)
+ file_match = re_file.match(line)
+ check_match = re_check.match(line)
+ if err_match:
+ item['msg'] = err_match.group(1)
+ item['type'] = 'error'
+ elif warn_match:
+ item['msg'] = warn_match.group(1)
+ item['type'] = 'warning'
+ elif check_match:
+ item['msg'] = check_match.group(1)
+ item['type'] = 'check'
+ elif file_match:
+ item['file'] = file_match.group(1)
+ item['line'] = int(file_match.group(2))
+
+ return result
+
+def GetWarningMsg(col, msg_type, fname, line, msg):
+ '''Create a message for a given file/line
+
+ Args:
+ msg_type: Message type ('error' or 'warning')
+ fname: Filename which reports the problem
+ line: Line number where it was noticed
+ msg: Message to report
+ '''
+ if msg_type == 'warning':
+ msg_type = col.Color(col.YELLOW, msg_type)
+ elif msg_type == 'error':
+ msg_type = col.Color(col.RED, msg_type)
+ elif msg_type == 'check':
+ msg_type = col.Color(col.MAGENTA, msg_type)
+ return '%s: %s,%d: %s' % (msg_type, fname, line, msg)
+
+def CheckPatches(verbose, args):
+ '''Run the checkpatch.pl script on each patch'''
+ error_count, warning_count, check_count = 0, 0, 0
+ col = terminal.Color()
+
+ for fname in args:
+ result = CheckPatch(fname, verbose)
+ if not result.ok:
+ error_count += result.errors
+ warning_count += result.warnings
+ check_count += result.checks
+ print '%d errors, %d warnings, %d checks for %s:' % (result.errors,
+ result.warnings, result.checks, col.Color(col.BLUE, fname))
+ if (len(result.problems) != result.errors + result.warnings +
+ result.checks):
+ print "Internal error: some problems lost"
+ for item in result.problems:
+ print GetWarningMsg(col, item.get('type', '<unknown>'),
+ item.get('file', '<unknown>'),
+ item.get('line', 0), item.get('msg', 'message'))
+ print
+ #print stdout
+ if error_count or warning_count or check_count:
+ str = 'checkpatch.pl found %d error(s), %d warning(s), %d checks(s)'
+ color = col.GREEN
+ if warning_count:
+ color = col.YELLOW
+ if error_count:
+ color = col.RED
+ print col.Color(color, str % (error_count, warning_count, check_count))
+ return False
+ return True
diff --git a/tools/patman/command.py b/tools/patman/command.py
new file mode 100644
index 0000000..e6af6ed
--- /dev/null
+++ b/tools/patman/command.py
@@ -0,0 +1,117 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import os
+import cros_subprocess
+
+"""Shell command ease-ups for Python."""
+
+class CommandResult:
+ """A class which captures the result of executing a command.
+
+ Members:
+ stdout: stdout obtained from command, as a string
+ stderr: stderr obtained from command, as a string
+ return_code: Return code from command
+ exception: Exception received, or None if all ok
+ """
+ def __init__(self):
+ self.stdout = None
+ self.stderr = None
+ self.return_code = None
+ self.exception = None
+
+
+def RunPipe(pipe_list, infile=None, outfile=None,
+ capture=False, capture_stderr=False, oneline=False,
+ raise_on_error=True, cwd=None, **kwargs):
+ """
+ Perform a command pipeline, with optional input/output filenames.
+
+ Args:
+ pipe_list: List of command lines to execute. Each command line is
+ piped into the next, and is itself a list of strings. For
+ example [ ['ls', '.git'] ['wc'] ] will pipe the output of
+ 'ls .git' into 'wc'.
+ infile: File to provide stdin to the pipeline
+ outfile: File to store stdout
+ capture: True to capture output
+ capture_stderr: True to capture stderr
+ oneline: True to strip newline chars from output
+ kwargs: Additional keyword arguments to cros_subprocess.Popen()
+ Returns:
+ CommandResult object
+ """
+ result = CommandResult()
+ last_pipe = None
+ pipeline = list(pipe_list)
+ user_pipestr = '|'.join([' '.join(pipe) for pipe in pipe_list])
+ while pipeline:
+ cmd = pipeline.pop(0)
+ if last_pipe is not None:
+ kwargs['stdin'] = last_pipe.stdout
+ elif infile:
+ kwargs['stdin'] = open(infile, 'rb')
+ if pipeline or capture:
+ kwargs['stdout'] = cros_subprocess.PIPE
+ elif outfile:
+ kwargs['stdout'] = open(outfile, 'wb')
+ if capture_stderr:
+ kwargs['stderr'] = cros_subprocess.PIPE
+
+ try:
+ last_pipe = cros_subprocess.Popen(cmd, cwd=cwd, **kwargs)
+ except Exception, err:
+ result.exception = err
+ if raise_on_error:
+ raise Exception("Error running '%s': %s" % (user_pipestr, str))
+ result.return_code = 255
+ return result
+
+ if capture:
+ result.stdout, result.stderr, result.combined = (
+ last_pipe.CommunicateFilter(None))
+ if result.stdout and oneline:
+ result.output = result.stdout.rstrip('\r\n')
+ result.return_code = last_pipe.wait()
+ else:
+ result.return_code = os.waitpid(last_pipe.pid, 0)[1]
+ if raise_on_error and result.return_code:
+ raise Exception("Error running '%s'" % user_pipestr)
+ return result
+
+def Output(*cmd):
+ return RunPipe([cmd], capture=True, raise_on_error=False).stdout
+
+def OutputOneLine(*cmd, **kwargs):
+ raise_on_error = kwargs.pop('raise_on_error', True)
+ return (RunPipe([cmd], capture=True, oneline=True,
+ raise_on_error=raise_on_error,
+ **kwargs).stdout.strip())
+
+def Run(*cmd, **kwargs):
+ return RunPipe([cmd], **kwargs).stdout
+
+def RunList(cmd):
+ return RunPipe([cmd], capture=True).stdout
+
+def StopAll():
+ cros_subprocess.stay_alive = False
diff --git a/tools/patman/commit.py b/tools/patman/commit.py
new file mode 100644
index 0000000..468b50c
--- /dev/null
+++ b/tools/patman/commit.py
@@ -0,0 +1,88 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import re
+
+# Separates a tag: at the beginning of the subject from the rest of it
+re_subject_tag = re.compile('([^:\s]*):\s*(.*)')
+
+class Commit:
+ """Holds information about a single commit/patch in the series.
+
+ Args:
+ hash: Commit hash (as a string)
+
+ Variables:
+ hash: Commit hash
+ subject: Subject line
+ tags: List of maintainer tag strings
+ changes: Dict containing a list of changes (single line strings).
+ The dict is indexed by change version (an integer)
+ cc_list: List of people to aliases/emails to cc on this commit
+ """
+ def __init__(self, hash):
+ self.hash = hash
+ self.subject = None
+ self.tags = []
+ self.changes = {}
+ self.cc_list = []
+
+ def AddChange(self, version, info):
+ """Add a new change line to the change list for a version.
+
+ Args:
+ version: Patch set version (integer: 1, 2, 3)
+ info: Description of change in this version
+ """
+ if not self.changes.get(version):
+ self.changes[version] = []
+ self.changes[version].append(info)
+
+ def CheckTags(self):
+ """Create a list of subject tags in the commit
+
+ Subject tags look like this:
+
+ propounder: fort: Change the widget to propound correctly
+
+ Here the tags are propounder and fort. Multiple tags are supported.
+ The list is updated in self.tag.
+
+ Returns:
+ None if ok, else the name of a tag with no email alias
+ """
+ str = self.subject
+ m = True
+ while m:
+ m = re_subject_tag.match(str)
+ if m:
+ tag = m.group(1)
+ self.tags.append(tag)
+ str = m.group(2)
+ return None
+
+ def AddCc(self, cc_list):
+ """Add a list of people to Cc when we send this patch.
+
+ Args:
+ cc_list: List of aliases or email addresses
+ """
+ self.cc_list += cc_list
diff --git a/tools/patman/cros_subprocess.py b/tools/patman/cros_subprocess.py
new file mode 100644
index 0000000..0fc4a06
--- /dev/null
+++ b/tools/patman/cros_subprocess.py
@@ -0,0 +1,397 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# Copyright (c) 2003-2005 by Peter Astrand <astrand@lysator.liu.se>
+# Licensed to PSF under a Contributor Agreement.
+# See http://www.python.org/2.4/license for licensing details.
+
+"""Subprocress execution
+
+This module holds a subclass of subprocess.Popen with our own required
+features, mainly that we get access to the subprocess output while it
+is running rather than just at the end. This makes it easiler to show
+progress information and filter output in real time.
+"""
+
+import errno
+import os
+import pty
+import select
+import subprocess
+import sys
+import unittest
+
+
+# Import these here so the caller does not need to import subprocess also.
+PIPE = subprocess.PIPE
+STDOUT = subprocess.STDOUT
+PIPE_PTY = -3 # Pipe output through a pty
+stay_alive = True
+
+
+class Popen(subprocess.Popen):
+ """Like subprocess.Popen with ptys and incremental output
+
+ This class deals with running a child process and filtering its output on
+ both stdout and stderr while it is running. We do this so we can monitor
+ progress, and possibly relay the output to the user if requested.
+
+ The class is similar to subprocess.Popen, the equivalent is something like:
+
+ Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ But this class has many fewer features, and two enhancement:
+
+ 1. Rather than getting the output data only at the end, this class sends it
+ to a provided operation as it arrives.
+ 2. We use pseudo terminals so that the child will hopefully flush its output
+ to us as soon as it is produced, rather than waiting for the end of a
+ line.
+
+ Use CommunicateFilter() to handle output from the subprocess.
+
+ """
+
+ def __init__(self, args, stdin=None, stdout=PIPE_PTY, stderr=PIPE_PTY,
+ shell=False, cwd=None, env=None, **kwargs):
+ """Cut-down constructor
+
+ Args:
+ args: Program and arguments for subprocess to execute.
+ stdin: See subprocess.Popen()
+ stdout: See subprocess.Popen(), except that we support the sentinel
+ value of cros_subprocess.PIPE_PTY.
+ stderr: See subprocess.Popen(), except that we support the sentinel
+ value of cros_subprocess.PIPE_PTY.
+ shell: See subprocess.Popen()
+ cwd: Working directory to change to for subprocess, or None if none.
+ env: Environment to use for this subprocess, or None to inherit parent.
+ kwargs: No other arguments are supported at the moment. Passing other
+ arguments will cause a ValueError to be raised.
+ """
+ stdout_pty = None
+ stderr_pty = None
+
+ if stdout == PIPE_PTY:
+ stdout_pty = pty.openpty()
+ stdout = os.fdopen(stdout_pty[1])
+ if stderr == PIPE_PTY:
+ stderr_pty = pty.openpty()
+ stderr = os.fdopen(stderr_pty[1])
+
+ super(Popen, self).__init__(args, stdin=stdin,
+ stdout=stdout, stderr=stderr, shell=shell, cwd=cwd, env=env,
+ **kwargs)
+
+ # If we're on a PTY, we passed the slave half of the PTY to the subprocess.
+ # We want to use the master half on our end from now on. Setting this here
+ # does make some assumptions about the implementation of subprocess, but
+ # those assumptions are pretty minor.
+
+ # Note that if stderr is STDOUT, then self.stderr will be set to None by
+ # this constructor.
+ if stdout_pty is not None:
+ self.stdout = os.fdopen(stdout_pty[0])
+ if stderr_pty is not None:
+ self.stderr = os.fdopen(stderr_pty[0])
+
+ # Insist that unit tests exist for other arguments we don't support.
+ if kwargs:
+ raise ValueError("Unit tests do not test extra args - please add tests")
+
+ def CommunicateFilter(self, output):
+ """Interact with process: Read data from stdout and stderr.
+
+ This method runs until end-of-file is reached, then waits for the
+ subprocess to terminate.
+
+ The output function is sent all output from the subprocess and must be
+ defined like this:
+
+ def Output([self,] stream, data)
+ Args:
+ stream: the stream the output was received on, which will be
+ sys.stdout or sys.stderr.
+ data: a string containing the data
+
+ Note: The data read is buffered in memory, so do not use this
+ method if the data size is large or unlimited.
+
+ Args:
+ output: Function to call with each fragment of output.
+
+ Returns:
+ A tuple (stdout, stderr, combined) which is the data received on
+ stdout, stderr and the combined data (interleaved stdout and stderr).
+
+ Note that the interleaved output will only be sensible if you have
+ set both stdout and stderr to PIPE or PIPE_PTY. Even then it depends on
+ the timing of the output in the subprocess. If a subprocess flips
+ between stdout and stderr quickly in succession, by the time we come to
+ read the output from each we may see several lines in each, and will read
+ all the stdout lines, then all the stderr lines. So the interleaving
+ may not be correct. In this case you might want to pass
+ stderr=cros_subprocess.STDOUT to the constructor.
+
+ This feature is still useful for subprocesses where stderr is
+ rarely used and indicates an error.
+
+ Note also that if you set stderr to STDOUT, then stderr will be empty
+ and the combined output will just be the same as stdout.
+ """
+
+ read_set = []
+ write_set = []
+ stdout = None # Return
+ stderr = None # Return
+
+ if self.stdin:
+ # Flush stdio buffer. This might block, if the user has
+ # been writing to .stdin in an uncontrolled fashion.
+ self.stdin.flush()
+ if input:
+ write_set.append(self.stdin)
+ else:
+ self.stdin.close()
+ if self.stdout:
+ read_set.append(self.stdout)
+ stdout = []
+ if self.stderr and self.stderr != self.stdout:
+ read_set.append(self.stderr)
+ stderr = []
+ combined = []
+
+ input_offset = 0
+ while read_set or write_set:
+ try:
+ rlist, wlist, _ = select.select(read_set, write_set, [], 0.2)
+ except select.error, e:
+ if e.args[0] == errno.EINTR:
+ continue
+ raise
+
+ if not stay_alive:
+ self.terminate()
+
+ if self.stdin in wlist:
+ # When select has indicated that the file is writable,
+ # we can write up to PIPE_BUF bytes without risk
+ # blocking. POSIX defines PIPE_BUF >= 512
+ chunk = input[input_offset : input_offset + 512]
+ bytes_written = os.write(self.stdin.fileno(), chunk)
+ input_offset += bytes_written
+ if input_offset >= len(input):
+ self.stdin.close()
+ write_set.remove(self.stdin)
+
+ if self.stdout in rlist:
+ data = ""
+ # We will get an error on read if the pty is closed
+ try:
+ data = os.read(self.stdout.fileno(), 1024)
+ except OSError:
+ pass
+ if data == "":
+ self.stdout.close()
+ read_set.remove(self.stdout)
+ else:
+ stdout.append(data)
+ combined.append(data)
+ if output:
+ output(sys.stdout, data)
+ if self.stderr in rlist:
+ data = ""
+ # We will get an error on read if the pty is closed
+ try:
+ data = os.read(self.stderr.fileno(), 1024)
+ except OSError:
+ pass
+ if data == "":
+ self.stderr.close()
+ read_set.remove(self.stderr)
+ else:
+ stderr.append(data)
+ combined.append(data)
+ if output:
+ output(sys.stderr, data)
+
+ # All data exchanged. Translate lists into strings.
+ if stdout is not None:
+ stdout = ''.join(stdout)
+ else:
+ stdout = ''
+ if stderr is not None:
+ stderr = ''.join(stderr)
+ else:
+ stderr = ''
+ combined = ''.join(combined)
+
+ # Translate newlines, if requested. We cannot let the file
+ # object do the translation: It is based on stdio, which is
+ # impossible to combine with select (unless forcing no
+ # buffering).
+ if self.universal_newlines and hasattr(file, 'newlines'):
+ if stdout:
+ stdout = self._translate_newlines(stdout)
+ if stderr:
+ stderr = self._translate_newlines(stderr)
+
+ self.wait()
+ return (stdout, stderr, combined)
+
+
+# Just being a unittest.TestCase gives us 14 public methods. Unless we
+# disable this, we can only have 6 tests in a TestCase. That's not enough.
+#
+# pylint: disable=R0904
+
+class TestSubprocess(unittest.TestCase):
+ """Our simple unit test for this module"""
+
+ class MyOperation:
+ """Provides a operation that we can pass to Popen"""
+ def __init__(self, input_to_send=None):
+ """Constructor to set up the operation and possible input.
+
+ Args:
+ input_to_send: a text string to send when we first get input. We will
+ add \r\n to the string.
+ """
+ self.stdout_data = ''
+ self.stderr_data = ''
+ self.combined_data = ''
+ self.stdin_pipe = None
+ self._input_to_send = input_to_send
+ if input_to_send:
+ pipe = os.pipe()
+ self.stdin_read_pipe = pipe[0]
+ self._stdin_write_pipe = os.fdopen(pipe[1], 'w')
+
+ def Output(self, stream, data):
+ """Output handler for Popen. Stores the data for later comparison"""
+ if stream == sys.stdout:
+ self.stdout_data += data
+ if stream == sys.stderr:
+ self.stderr_data += data
+ self.combined_data += data
+
+ # Output the input string if we have one.
+ if self._input_to_send:
+ self._stdin_write_pipe.write(self._input_to_send + '\r\n')
+ self._stdin_write_pipe.flush()
+
+ def _BasicCheck(self, plist, oper):
+ """Basic checks that the output looks sane."""
+ self.assertEqual(plist[0], oper.stdout_data)
+ self.assertEqual(plist[1], oper.stderr_data)
+ self.assertEqual(plist[2], oper.combined_data)
+
+ # The total length of stdout and stderr should equal the combined length
+ self.assertEqual(len(plist[0]) + len(plist[1]), len(plist[2]))
+
+ def test_simple(self):
+ """Simple redirection: Get process list"""
+ oper = TestSubprocess.MyOperation()
+ plist = Popen(['ps']).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+
+ def test_stderr(self):
+ """Check stdout and stderr"""
+ oper = TestSubprocess.MyOperation()
+ cmd = 'echo fred >/dev/stderr && false || echo bad'
+ plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], 'bad\r\n')
+ self.assertEqual(plist [1], 'fred\r\n')
+
+ def test_shell(self):
+ """Check with and without shell works"""
+ oper = TestSubprocess.MyOperation()
+ cmd = 'echo test >/dev/stderr'
+ self.assertRaises(OSError, Popen, [cmd], shell=False)
+ plist = Popen([cmd], shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(len(plist [0]), 0)
+ self.assertEqual(plist [1], 'test\r\n')
+
+ def test_list_args(self):
+ """Check with and without shell works using list arguments"""
+ oper = TestSubprocess.MyOperation()
+ cmd = ['echo', 'test', '>/dev/stderr']
+ plist = Popen(cmd, shell=False).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], ' '.join(cmd[1:]) + '\r\n')
+ self.assertEqual(len(plist [1]), 0)
+
+ oper = TestSubprocess.MyOperation()
+
+ # this should be interpreted as 'echo' with the other args dropped
+ cmd = ['echo', 'test', '>/dev/stderr']
+ plist = Popen(cmd, shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], '\r\n')
+
+ def test_cwd(self):
+ """Check we can change directory"""
+ for shell in (False, True):
+ oper = TestSubprocess.MyOperation()
+ plist = Popen('pwd', shell=shell, cwd='/tmp').CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], '/tmp\r\n')
+
+ def test_env(self):
+ """Check we can change environment"""
+ for add in (False, True):
+ oper = TestSubprocess.MyOperation()
+ env = os.environ
+ if add:
+ env ['FRED'] = 'fred'
+ cmd = 'echo $FRED'
+ plist = Popen(cmd, shell=True, env=env).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], add and 'fred\r\n' or '\r\n')
+
+ def test_extra_args(self):
+ """Check we can't add extra arguments"""
+ self.assertRaises(ValueError, Popen, 'true', close_fds=False)
+
+ def test_basic_input(self):
+ """Check that incremental input works
+
+ We set up a subprocess which will prompt for name. When we see this prompt
+ we send the name as input to the process. It should then print the name
+ properly to stdout.
+ """
+ oper = TestSubprocess.MyOperation('Flash')
+ prompt = 'What is your name?: '
+ cmd = 'echo -n "%s"; read name; echo Hello $name' % prompt
+ plist = Popen([cmd], stdin=oper.stdin_read_pipe,
+ shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(len(plist [1]), 0)
+ self.assertEqual(plist [0], prompt + 'Hello Flash\r\r\n')
+
+ def test_isatty(self):
+ """Check that ptys appear as terminals to the subprocess"""
+ oper = TestSubprocess.MyOperation()
+ cmd = ('if [ -t %d ]; then echo "terminal %d" >&%d; '
+ 'else echo "not %d" >&%d; fi;')
+ both_cmds = ''
+ for fd in (1, 2):
+ both_cmds += cmd % (fd, fd, fd, fd, fd)
+ plist = Popen(both_cmds, shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], 'terminal 1\r\n')
+ self.assertEqual(plist [1], 'terminal 2\r\n')
+
+ # Now try with PIPE and make sure it is not a terminal
+ oper = TestSubprocess.MyOperation()
+ plist = Popen(both_cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ shell=True).CommunicateFilter(oper.Output)
+ self._BasicCheck(plist, oper)
+ self.assertEqual(plist [0], 'not 1\n')
+ self.assertEqual(plist [1], 'not 2\n')
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tools/patman/get_maintainer.py b/tools/patman/get_maintainer.py
new file mode 100644
index 0000000..cb11373
--- /dev/null
+++ b/tools/patman/get_maintainer.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import command
+import gitutil
+import os
+
+def FindGetMaintainer():
+ """Look for the get_maintainer.pl script.
+
+ Returns:
+ If the script is found we'll return a path to it; else None.
+ """
+ try_list = [
+ os.path.join(gitutil.GetTopLevel(), 'scripts'),
+ ]
+ # Look in the list
+ for path in try_list:
+ fname = os.path.join(path, 'get_maintainer.pl')
+ if os.path.isfile(fname):
+ return fname
+
+ return None
+
+def GetMaintainer(fname, verbose=False):
+ """Run get_maintainer.pl on a file if we find it.
+
+ We look for get_maintainer.pl in the 'scripts' directory at the top of
+ git. If we find it we'll run it. If we don't find get_maintainer.pl
+ then we fail silently.
+
+ Args:
+ fname: Path to the patch file to run get_maintainer.pl on.
+
+ Returns:
+ A list of email addresses to CC to.
+ """
+ get_maintainer = FindGetMaintainer()
+ if not get_maintainer:
+ if verbose:
+ print "WARNING: Couldn't find get_maintainer.pl"
+ return []
+
+ stdout = command.Output(get_maintainer, '--norolestats', fname)
+ return stdout.splitlines()
diff --git a/tools/patman/gitutil.py b/tools/patman/gitutil.py
new file mode 100644
index 0000000..b7f6739
--- /dev/null
+++ b/tools/patman/gitutil.py
@@ -0,0 +1,563 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import command
+import re
+import os
+import series
+import subprocess
+import sys
+import terminal
+
+import settings
+
+
+def CountCommitsToBranch():
+ """Returns number of commits between HEAD and the tracking branch.
+
+ This looks back to the tracking branch and works out the number of commits
+ since then.
+
+ Return:
+ Number of patches that exist on top of the branch
+ """
+ pipe = [['git', 'log', '--no-color', '--oneline', '--no-decorate',
+ '@{upstream}..'],
+ ['wc', '-l']]
+ stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout
+ patch_count = int(stdout)
+ return patch_count
+
+def GetUpstream(git_dir, branch):
+ """Returns the name of the upstream for a branch
+
+ Args:
+ git_dir: Git directory containing repo
+ branch: Name of branch
+
+ Returns:
+ Name of upstream branch (e.g. 'upstream/master') or None if none
+ """
+ try:
+ remote = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
+ 'branch.%s.remote' % branch)
+ merge = command.OutputOneLine('git', '--git-dir', git_dir, 'config',
+ 'branch.%s.merge' % branch)
+ except:
+ return None
+
+ if remote == '.':
+ return merge
+ elif remote and merge:
+ leaf = merge.split('/')[-1]
+ return '%s/%s' % (remote, leaf)
+ else:
+ raise ValueError, ("Cannot determine upstream branch for branch "
+ "'%s' remote='%s', merge='%s'" % (branch, remote, merge))
+
+
+def GetRangeInBranch(git_dir, branch, include_upstream=False):
+ """Returns an expression for the commits in the given branch.
+
+ Args:
+ git_dir: Directory containing git repo
+ branch: Name of branch
+ Return:
+ Expression in the form 'upstream..branch' which can be used to
+ access the commits. If the branch does not exist, returns None.
+ """
+ upstream = GetUpstream(git_dir, branch)
+ if not upstream:
+ return None
+ return '%s%s..%s' % (upstream, '~' if include_upstream else '', branch)
+
+def CountCommitsInBranch(git_dir, branch, include_upstream=False):
+ """Returns the number of commits in the given branch.
+
+ Args:
+ git_dir: Directory containing git repo
+ branch: Name of branch
+ Return:
+ Number of patches that exist on top of the branch, or None if the
+ branch does not exist.
+ """
+ range_expr = GetRangeInBranch(git_dir, branch, include_upstream)
+ if not range_expr:
+ return None
+ pipe = [['git', '--git-dir', git_dir, 'log', '--oneline', '--no-decorate',
+ range_expr],
+ ['wc', '-l']]
+ result = command.RunPipe(pipe, capture=True, oneline=True)
+ patch_count = int(result.stdout)
+ return patch_count
+
+def CountCommits(commit_range):
+ """Returns the number of commits in the given range.
+
+ Args:
+ commit_range: Range of commits to count (e.g. 'HEAD..base')
+ Return:
+ Number of patches that exist on top of the branch
+ """
+ pipe = [['git', 'log', '--oneline', '--no-decorate', commit_range],
+ ['wc', '-l']]
+ stdout = command.RunPipe(pipe, capture=True, oneline=True).stdout
+ patch_count = int(stdout)
+ return patch_count
+
+def Checkout(commit_hash, git_dir=None, work_tree=None, force=False):
+ """Checkout the selected commit for this build
+
+ Args:
+ commit_hash: Commit hash to check out
+ """
+ pipe = ['git']
+ if git_dir:
+ pipe.extend(['--git-dir', git_dir])
+ if work_tree:
+ pipe.extend(['--work-tree', work_tree])
+ pipe.append('checkout')
+ if force:
+ pipe.append('-f')
+ pipe.append(commit_hash)
+ result = command.RunPipe([pipe], capture=True, raise_on_error=False)
+ if result.return_code != 0:
+ raise OSError, 'git checkout (%s): %s' % (pipe, result.stderr)
+
+def Clone(git_dir, output_dir):
+ """Checkout the selected commit for this build
+
+ Args:
+ commit_hash: Commit hash to check out
+ """
+ pipe = ['git', 'clone', git_dir, '.']
+ result = command.RunPipe([pipe], capture=True, cwd=output_dir)
+ if result.return_code != 0:
+ raise OSError, 'git clone: %s' % result.stderr
+
+def Fetch(git_dir=None, work_tree=None):
+ """Fetch from the origin repo
+
+ Args:
+ commit_hash: Commit hash to check out
+ """
+ pipe = ['git']
+ if git_dir:
+ pipe.extend(['--git-dir', git_dir])
+ if work_tree:
+ pipe.extend(['--work-tree', work_tree])
+ pipe.append('fetch')
+ result = command.RunPipe([pipe], capture=True)
+ if result.return_code != 0:
+ raise OSError, 'git fetch: %s' % result.stderr
+
+def CreatePatches(start, count, series):
+ """Create a series of patches from the top of the current branch.
+
+ The patch files are written to the current directory using
+ git format-patch.
+
+ Args:
+ start: Commit to start from: 0=HEAD, 1=next one, etc.
+ count: number of commits to include
+ Return:
+ Filename of cover letter
+ List of filenames of patch files
+ """
+ if series.get('version'):
+ version = '%s ' % series['version']
+ cmd = ['git', 'format-patch', '-M', '--signoff']
+ if series.get('cover'):
+ cmd.append('--cover-letter')
+ prefix = series.GetPatchPrefix()
+ if prefix:
+ cmd += ['--subject-prefix=%s' % prefix]
+ cmd += ['HEAD~%d..HEAD~%d' % (start + count, start)]
+
+ stdout = command.RunList(cmd)
+ files = stdout.splitlines()
+
+ # We have an extra file if there is a cover letter
+ if series.get('cover'):
+ return files[0], files[1:]
+ else:
+ return None, files
+
+def ApplyPatch(verbose, fname):
+ """Apply a patch with git am to test it
+
+ TODO: Convert these to use command, with stderr option
+
+ Args:
+ fname: filename of patch file to apply
+ """
+ cmd = ['git', 'am', fname]
+ pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = pipe.communicate()
+ re_error = re.compile('^error: patch failed: (.+):(\d+)')
+ for line in stderr.splitlines():
+ if verbose:
+ print line
+ match = re_error.match(line)
+ if match:
+ print GetWarningMsg('warning', match.group(1), int(match.group(2)),
+ 'Patch failed')
+ return pipe.returncode == 0, stdout
+
+def ApplyPatches(verbose, args, start_point):
+ """Apply the patches with git am to make sure all is well
+
+ Args:
+ verbose: Print out 'git am' output verbatim
+ args: List of patch files to apply
+ start_point: Number of commits back from HEAD to start applying.
+ Normally this is len(args), but it can be larger if a start
+ offset was given.
+ """
+ error_count = 0
+ col = terminal.Color()
+
+ # Figure out our current position
+ cmd = ['git', 'name-rev', 'HEAD', '--name-only']
+ pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, stderr = pipe.communicate()
+ if pipe.returncode:
+ str = 'Could not find current commit name'
+ print col.Color(col.RED, str)
+ print stdout
+ return False
+ old_head = stdout.splitlines()[0]
+
+ # Checkout the required start point
+ cmd = ['git', 'checkout', 'HEAD~%d' % start_point]
+ pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ stdout, stderr = pipe.communicate()
+ if pipe.returncode:
+ str = 'Could not move to commit before patch series'
+ print col.Color(col.RED, str)
+ print stdout, stderr
+ return False
+
+ # Apply all the patches
+ for fname in args:
+ ok, stdout = ApplyPatch(verbose, fname)
+ if not ok:
+ print col.Color(col.RED, 'git am returned errors for %s: will '
+ 'skip this patch' % fname)
+ if verbose:
+ print stdout
+ error_count += 1
+ cmd = ['git', 'am', '--skip']
+ pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE)
+ stdout, stderr = pipe.communicate()
+ if pipe.returncode != 0:
+ print col.Color(col.RED, 'Unable to skip patch! Aborting...')
+ print stdout
+ break
+
+ # Return to our previous position
+ cmd = ['git', 'checkout', old_head]
+ pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = pipe.communicate()
+ if pipe.returncode:
+ print col.Color(col.RED, 'Could not move back to head commit')
+ print stdout, stderr
+ return error_count == 0
+
+def BuildEmailList(in_list, tag=None, alias=None, raise_on_error=True):
+ """Build a list of email addresses based on an input list.
+
+ Takes a list of email addresses and aliases, and turns this into a list
+ of only email address, by resolving any aliases that are present.
+
+ If the tag is given, then each email address is prepended with this
+ tag and a space. If the tag starts with a minus sign (indicating a
+ command line parameter) then the email address is quoted.
+
+ Args:
+ in_list: List of aliases/email addresses
+ tag: Text to put before each address
+ alias: Alias dictionary
+ raise_on_error: True to raise an error when an alias fails to match,
+ False to just print a message.
+
+ Returns:
+ List of email addresses
+
+ >>> alias = {}
+ >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+ >>> alias['john'] = ['j.bloggs@napier.co.nz']
+ >>> alias['mary'] = ['Mary Poppins <m.poppins@cloud.net>']
+ >>> alias['boys'] = ['fred', ' john']
+ >>> alias['all'] = ['fred ', 'john', ' mary ']
+ >>> BuildEmailList(['john', 'mary'], None, alias)
+ ['j.bloggs@napier.co.nz', 'Mary Poppins <m.poppins@cloud.net>']
+ >>> BuildEmailList(['john', 'mary'], '--to', alias)
+ ['--to "j.bloggs@napier.co.nz"', \
+'--to "Mary Poppins <m.poppins@cloud.net>"']
+ >>> BuildEmailList(['john', 'mary'], 'Cc', alias)
+ ['Cc j.bloggs@napier.co.nz', 'Cc Mary Poppins <m.poppins@cloud.net>']
+ """
+ quote = '"' if tag and tag[0] == '-' else ''
+ raw = []
+ for item in in_list:
+ raw += LookupEmail(item, alias, raise_on_error=raise_on_error)
+ result = []
+ for item in raw:
+ if not item in result:
+ result.append(item)
+ if tag:
+ return ['%s %s%s%s' % (tag, quote, email, quote) for email in result]
+ return result
+
+def EmailPatches(series, cover_fname, args, dry_run, raise_on_error, cc_fname,
+ self_only=False, alias=None, in_reply_to=None):
+ """Email a patch series.
+
+ Args:
+ series: Series object containing destination info
+ cover_fname: filename of cover letter
+ args: list of filenames of patch files
+ dry_run: Just return the command that would be run
+ raise_on_error: True to raise an error when an alias fails to match,
+ False to just print a message.
+ cc_fname: Filename of Cc file for per-commit Cc
+ self_only: True to just email to yourself as a test
+ in_reply_to: If set we'll pass this to git as --in-reply-to.
+ Should be a message ID that this is in reply to.
+
+ Returns:
+ Git command that was/would be run
+
+ # For the duration of this doctest pretend that we ran patman with ./patman
+ >>> _old_argv0 = sys.argv[0]
+ >>> sys.argv[0] = './patman'
+
+ >>> alias = {}
+ >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+ >>> alias['john'] = ['j.bloggs@napier.co.nz']
+ >>> alias['mary'] = ['m.poppins@cloud.net']
+ >>> alias['boys'] = ['fred', ' john']
+ >>> alias['all'] = ['fred ', 'john', ' mary ']
+ >>> alias[os.getenv('USER')] = ['this-is-me@me.com']
+ >>> series = series.Series()
+ >>> series.to = ['fred']
+ >>> series.cc = ['mary']
+ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+ False, alias)
+ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2'
+ >>> EmailPatches(series, None, ['p1'], True, True, 'cc-fname', False, \
+ alias)
+ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" p1'
+ >>> series.cc = ['all']
+ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+ True, alias)
+ 'git send-email --annotate --to "this-is-me@me.com" --cc-cmd "./patman \
+--cc-cmd cc-fname" cover p1 p2'
+ >>> EmailPatches(series, 'cover', ['p1', 'p2'], True, True, 'cc-fname', \
+ False, alias)
+ 'git send-email --annotate --to "f.bloggs@napier.co.nz" --cc \
+"f.bloggs@napier.co.nz" --cc "j.bloggs@napier.co.nz" --cc \
+"m.poppins@cloud.net" --cc-cmd "./patman --cc-cmd cc-fname" cover p1 p2'
+
+ # Restore argv[0] since we clobbered it.
+ >>> sys.argv[0] = _old_argv0
+ """
+ to = BuildEmailList(series.get('to'), '--to', alias, raise_on_error)
+ if not to:
+ print ("No recipient, please add something like this to a commit\n"
+ "Series-to: Fred Bloggs <f.blogs@napier.co.nz>")
+ return
+ cc = BuildEmailList(series.get('cc'), '--cc', alias, raise_on_error)
+ if self_only:
+ to = BuildEmailList([os.getenv('USER')], '--to', alias, raise_on_error)
+ cc = []
+ cmd = ['git', 'send-email', '--annotate']
+ if in_reply_to:
+ cmd.append('--in-reply-to="%s"' % in_reply_to)
+
+ cmd += to
+ cmd += cc
+ cmd += ['--cc-cmd', '"%s --cc-cmd %s"' % (sys.argv[0], cc_fname)]
+ if cover_fname:
+ cmd.append(cover_fname)
+ cmd += args
+ str = ' '.join(cmd)
+ if not dry_run:
+ os.system(str)
+ return str
+
+
+def LookupEmail(lookup_name, alias=None, raise_on_error=True, level=0):
+ """If an email address is an alias, look it up and return the full name
+
+ TODO: Why not just use git's own alias feature?
+
+ Args:
+ lookup_name: Alias or email address to look up
+ alias: Dictionary containing aliases (None to use settings default)
+ raise_on_error: True to raise an error when an alias fails to match,
+ False to just print a message.
+
+ Returns:
+ tuple:
+ list containing a list of email addresses
+
+ Raises:
+ OSError if a recursive alias reference was found
+ ValueError if an alias was not found
+
+ >>> alias = {}
+ >>> alias['fred'] = ['f.bloggs@napier.co.nz']
+ >>> alias['john'] = ['j.bloggs@napier.co.nz']
+ >>> alias['mary'] = ['m.poppins@cloud.net']
+ >>> alias['boys'] = ['fred', ' john', 'f.bloggs@napier.co.nz']
+ >>> alias['all'] = ['fred ', 'john', ' mary ']
+ >>> alias['loop'] = ['other', 'john', ' mary ']
+ >>> alias['other'] = ['loop', 'john', ' mary ']
+ >>> LookupEmail('mary', alias)
+ ['m.poppins@cloud.net']
+ >>> LookupEmail('arthur.wellesley@howe.ro.uk', alias)
+ ['arthur.wellesley@howe.ro.uk']
+ >>> LookupEmail('boys', alias)
+ ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz']
+ >>> LookupEmail('all', alias)
+ ['f.bloggs@napier.co.nz', 'j.bloggs@napier.co.nz', 'm.poppins@cloud.net']
+ >>> LookupEmail('odd', alias)
+ Traceback (most recent call last):
+ ...
+ ValueError: Alias 'odd' not found
+ >>> LookupEmail('loop', alias)
+ Traceback (most recent call last):
+ ...
+ OSError: Recursive email alias at 'other'
+ >>> LookupEmail('odd', alias, raise_on_error=False)
+ \033[1;31mAlias 'odd' not found\033[0m
+ []
+ >>> # In this case the loop part will effectively be ignored.
+ >>> LookupEmail('loop', alias, raise_on_error=False)
+ \033[1;31mRecursive email alias at 'other'\033[0m
+ \033[1;31mRecursive email alias at 'john'\033[0m
+ \033[1;31mRecursive email alias at 'mary'\033[0m
+ ['j.bloggs@napier.co.nz', 'm.poppins@cloud.net']
+ """
+ if not alias:
+ alias = settings.alias
+ lookup_name = lookup_name.strip()
+ if '@' in lookup_name: # Perhaps a real email address
+ return [lookup_name]
+
+ lookup_name = lookup_name.lower()
+ col = terminal.Color()
+
+ out_list = []
+ if level > 10:
+ msg = "Recursive email alias at '%s'" % lookup_name
+ if raise_on_error:
+ raise OSError, msg
+ else:
+ print col.Color(col.RED, msg)
+ return out_list
+
+ if lookup_name:
+ if not lookup_name in alias:
+ msg = "Alias '%s' not found" % lookup_name
+ if raise_on_error:
+ raise ValueError, msg
+ else:
+ print col.Color(col.RED, msg)
+ return out_list
+ for item in alias[lookup_name]:
+ todo = LookupEmail(item, alias, raise_on_error, level + 1)
+ for new_item in todo:
+ if not new_item in out_list:
+ out_list.append(new_item)
+
+ #print "No match for alias '%s'" % lookup_name
+ return out_list
+
+def GetTopLevel():
+ """Return name of top-level directory for this git repo.
+
+ Returns:
+ Full path to git top-level directory
+
+ This test makes sure that we are running tests in the right subdir
+
+ >>> os.path.realpath(os.path.dirname(__file__)) == \
+ os.path.join(GetTopLevel(), 'tools', 'patman')
+ True
+ """
+ return command.OutputOneLine('git', 'rev-parse', '--show-toplevel')
+
+def GetAliasFile():
+ """Gets the name of the git alias file.
+
+ Returns:
+ Filename of git alias file, or None if none
+ """
+ fname = command.OutputOneLine('git', 'config', 'sendemail.aliasesfile',
+ raise_on_error=False)
+ if fname:
+ fname = os.path.join(GetTopLevel(), fname.strip())
+ return fname
+
+def GetDefaultUserName():
+ """Gets the user.name from .gitconfig file.
+
+ Returns:
+ User name found in .gitconfig file, or None if none
+ """
+ uname = command.OutputOneLine('git', 'config', '--global', 'user.name')
+ return uname
+
+def GetDefaultUserEmail():
+ """Gets the user.email from the global .gitconfig file.
+
+ Returns:
+ User's email found in .gitconfig file, or None if none
+ """
+ uemail = command.OutputOneLine('git', 'config', '--global', 'user.email')
+ return uemail
+
+def Setup():
+ """Set up git utils, by reading the alias files."""
+ # Check for a git alias file also
+ alias_fname = GetAliasFile()
+ if alias_fname:
+ settings.ReadGitAliases(alias_fname)
+
+def GetHead():
+ """Get the hash of the current HEAD
+
+ Returns:
+ Hash of HEAD
+ """
+ return command.OutputOneLine('git', 'show', '-s', '--pretty=format:%H')
+
+if __name__ == "__main__":
+ import doctest
+
+ doctest.testmod()
diff --git a/tools/patman/patchstream.py b/tools/patman/patchstream.py
new file mode 100644
index 0000000..b4337cc
--- /dev/null
+++ b/tools/patman/patchstream.py
@@ -0,0 +1,474 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import os
+import re
+import shutil
+import tempfile
+
+import command
+import commit
+import gitutil
+from series import Series
+
+# Tags that we detect and remove
+re_remove = re.compile('^BUG=|^TEST=|^BRANCH=|^Change-Id:|^Review URL:'
+ '|Reviewed-on:|Commit-\w*:')
+
+# Lines which are allowed after a TEST= line
+re_allowed_after_test = re.compile('^Signed-off-by:')
+
+# Signoffs
+re_signoff = re.compile('^Signed-off-by:')
+
+# The start of the cover letter
+re_cover = re.compile('^Cover-letter:')
+
+# A cover letter Cc
+re_cover_cc = re.compile('^Cover-letter-cc: *(.*)')
+
+# Patch series tag
+re_series = re.compile('^Series-([a-z-]*): *(.*)')
+
+# Commit tags that we want to collect and keep
+re_tag = re.compile('^(Tested-by|Acked-by|Reviewed-by|Cc): (.*)')
+
+# The start of a new commit in the git log
+re_commit = re.compile('^commit ([0-9a-f]*)$')
+
+# We detect these since checkpatch doesn't always do it
+re_space_before_tab = re.compile('^[+].* \t')
+
+# States we can be in - can we use range() and still have comments?
+STATE_MSG_HEADER = 0 # Still in the message header
+STATE_PATCH_SUBJECT = 1 # In patch subject (first line of log for a commit)
+STATE_PATCH_HEADER = 2 # In patch header (after the subject)
+STATE_DIFFS = 3 # In the diff part (past --- line)
+
+class PatchStream:
+ """Class for detecting/injecting tags in a patch or series of patches
+
+ We support processing the output of 'git log' to read out the tags we
+ are interested in. We can also process a patch file in order to remove
+ unwanted tags or inject additional ones. These correspond to the two
+ phases of processing.
+ """
+ def __init__(self, series, name=None, is_log=False):
+ self.skip_blank = False # True to skip a single blank line
+ self.found_test = False # Found a TEST= line
+ self.lines_after_test = 0 # MNumber of lines found after TEST=
+ self.warn = [] # List of warnings we have collected
+ self.linenum = 1 # Output line number we are up to
+ self.in_section = None # Name of start...END section we are in
+ self.notes = [] # Series notes
+ self.section = [] # The current section...END section
+ self.series = series # Info about the patch series
+ self.is_log = is_log # True if indent like git log
+ self.in_change = 0 # Non-zero if we are in a change list
+ self.blank_count = 0 # Number of blank lines stored up
+ self.state = STATE_MSG_HEADER # What state are we in?
+ self.tags = [] # Tags collected, like Tested-by...
+ self.signoff = [] # Contents of signoff line
+ self.commit = None # Current commit
+
+ def AddToSeries(self, line, name, value):
+ """Add a new Series-xxx tag.
+
+ When a Series-xxx tag is detected, we come here to record it, if we
+ are scanning a 'git log'.
+
+ Args:
+ line: Source line containing tag (useful for debug/error messages)
+ name: Tag name (part after 'Series-')
+ value: Tag value (part after 'Series-xxx: ')
+ """
+ if name == 'notes':
+ self.in_section = name
+ self.skip_blank = False
+ if self.is_log:
+ self.series.AddTag(self.commit, line, name, value)
+
+ def CloseCommit(self):
+ """Save the current commit into our commit list, and reset our state"""
+ if self.commit and self.is_log:
+ self.series.AddCommit(self.commit)
+ self.commit = None
+
+ def FormatTags(self, tags):
+ out_list = []
+ for tag in sorted(tags):
+ if tag.startswith('Cc:'):
+ tag_list = tag[4:].split(',')
+ out_list += gitutil.BuildEmailList(tag_list, 'Cc:')
+ else:
+ out_list.append(tag)
+ return out_list
+
+ def ProcessLine(self, line):
+ """Process a single line of a patch file or commit log
+
+ This process a line and returns a list of lines to output. The list
+ may be empty or may contain multiple output lines.
+
+ This is where all the complicated logic is located. The class's
+ state is used to move between different states and detect things
+ properly.
+
+ We can be in one of two modes:
+ self.is_log == True: This is 'git log' mode, where most output is
+ indented by 4 characters and we are scanning for tags
+
+ self.is_log == False: This is 'patch' mode, where we already have
+ all the tags, and are processing patches to remove junk we
+ don't want, and add things we think are required.
+
+ Args:
+ line: text line to process
+
+ Returns:
+ list of output lines, or [] if nothing should be output
+ """
+ # Initially we have no output. Prepare the input line string
+ out = []
+ line = line.rstrip('\n')
+ if self.is_log:
+ if line[:4] == ' ':
+ line = line[4:]
+
+ # Handle state transition and skipping blank lines
+ series_match = re_series.match(line)
+ commit_match = re_commit.match(line) if self.is_log else None
+ cover_cc_match = re_cover_cc.match(line)
+ tag_match = None
+ if self.state == STATE_PATCH_HEADER:
+ tag_match = re_tag.match(line)
+ is_blank = not line.strip()
+ if is_blank:
+ if (self.state == STATE_MSG_HEADER
+ or self.state == STATE_PATCH_SUBJECT):
+ self.state += 1
+
+ # We don't have a subject in the text stream of patch files
+ # It has its own line with a Subject: tag
+ if not self.is_log and self.state == STATE_PATCH_SUBJECT:
+ self.state += 1
+ elif commit_match:
+ self.state = STATE_MSG_HEADER
+
+ # If we are in a section, keep collecting lines until we see END
+ if self.in_section:
+ if line == 'END':
+ if self.in_section == 'cover':
+ self.series.cover = self.section
+ elif self.in_section == 'notes':
+ if self.is_log:
+ self.series.notes += self.section
+ else:
+ self.warn.append("Unknown section '%s'" % self.in_section)
+ self.in_section = None
+ self.skip_blank = True
+ self.section = []
+ else:
+ self.section.append(line)
+
+ # Detect the commit subject
+ elif not is_blank and self.state == STATE_PATCH_SUBJECT:
+ self.commit.subject = line
+
+ # Detect the tags we want to remove, and skip blank lines
+ elif re_remove.match(line):
+ self.skip_blank = True
+
+ # TEST= should be the last thing in the commit, so remove
+ # everything after it
+ if line.startswith('TEST='):
+ self.found_test = True
+ elif self.skip_blank and is_blank:
+ self.skip_blank = False
+
+ # Detect the start of a cover letter section
+ elif re_cover.match(line):
+ self.in_section = 'cover'
+ self.skip_blank = False
+
+ elif cover_cc_match:
+ value = cover_cc_match.group(1)
+ self.AddToSeries(line, 'cover-cc', value)
+
+ # If we are in a change list, key collected lines until a blank one
+ elif self.in_change:
+ if is_blank:
+ # Blank line ends this change list
+ self.in_change = 0
+ elif line == '---' or re_signoff.match(line):
+ self.in_change = 0
+ out = self.ProcessLine(line)
+ else:
+ if self.is_log:
+ self.series.AddChange(self.in_change, self.commit, line)
+ self.skip_blank = False
+
+ # Detect Series-xxx tags
+ elif series_match:
+ name = series_match.group(1)
+ value = series_match.group(2)
+ if name == 'changes':
+ # value is the version number: e.g. 1, or 2
+ try:
+ value = int(value)
+ except ValueError as str:
+ raise ValueError("%s: Cannot decode version info '%s'" %
+ (self.commit.hash, line))
+ self.in_change = int(value)
+ else:
+ self.AddToSeries(line, name, value)
+ self.skip_blank = True
+
+ # Detect the start of a new commit
+ elif commit_match:
+ self.CloseCommit()
+ # TODO: We should store the whole hash, and just display a subset
+ self.commit = commit.Commit(commit_match.group(1)[:8])
+
+ # Detect tags in the commit message
+ elif tag_match:
+ # Remove Tested-by self, since few will take much notice
+ if (tag_match.group(1) == 'Tested-by' and
+ tag_match.group(2).find(os.getenv('USER') + '@') != -1):
+ self.warn.append("Ignoring %s" % line)
+ elif tag_match.group(1) == 'Cc':
+ self.commit.AddCc(tag_match.group(2).split(','))
+ else:
+ self.tags.append(line);
+
+ # Well that means this is an ordinary line
+ else:
+ pos = 1
+ # Look for ugly ASCII characters
+ for ch in line:
+ # TODO: Would be nicer to report source filename and line
+ if ord(ch) > 0x80:
+ self.warn.append("Line %d/%d ('%s') has funny ascii char" %
+ (self.linenum, pos, line))
+ pos += 1
+
+ # Look for space before tab
+ m = re_space_before_tab.match(line)
+ if m:
+ self.warn.append('Line %d/%d has space before tab' %
+ (self.linenum, m.start()))
+
+ # OK, we have a valid non-blank line
+ out = [line]
+ self.linenum += 1
+ self.skip_blank = False
+ if self.state == STATE_DIFFS:
+ pass
+
+ # If this is the start of the diffs section, emit our tags and
+ # change log
+ elif line == '---':
+ self.state = STATE_DIFFS
+
+ # Output the tags (signeoff first), then change list
+ out = []
+ log = self.series.MakeChangeLog(self.commit)
+ out += self.FormatTags(self.tags)
+ out += [line] + log
+ elif self.found_test:
+ if not re_allowed_after_test.match(line):
+ self.lines_after_test += 1
+
+ return out
+
+ def Finalize(self):
+ """Close out processing of this patch stream"""
+ self.CloseCommit()
+ if self.lines_after_test:
+ self.warn.append('Found %d lines after TEST=' %
+ self.lines_after_test)
+
+ def ProcessStream(self, infd, outfd):
+ """Copy a stream from infd to outfd, filtering out unwanting things.
+
+ This is used to process patch files one at a time.
+
+ Args:
+ infd: Input stream file object
+ outfd: Output stream file object
+ """
+ # Extract the filename from each diff, for nice warnings
+ fname = None
+ last_fname = None
+ re_fname = re.compile('diff --git a/(.*) b/.*')
+ while True:
+ line = infd.readline()
+ if not line:
+ break
+ out = self.ProcessLine(line)
+
+ # Try to detect blank lines at EOF
+ for line in out:
+ match = re_fname.match(line)
+ if match:
+ last_fname = fname
+ fname = match.group(1)
+ if line == '+':
+ self.blank_count += 1
+ else:
+ if self.blank_count and (line == '-- ' or match):
+ self.warn.append("Found possible blank line(s) at "
+ "end of file '%s'" % last_fname)
+ outfd.write('+\n' * self.blank_count)
+ outfd.write(line + '\n')
+ self.blank_count = 0
+ self.Finalize()
+
+
+def GetMetaDataForList(commit_range, git_dir=None, count=None,
+ series = Series()):
+ """Reads out patch series metadata from the commits
+
+ This does a 'git log' on the relevant commits and pulls out the tags we
+ are interested in.
+
+ Args:
+ commit_range: Range of commits to count (e.g. 'HEAD..base')
+ git_dir: Path to git repositiory (None to use default)
+ count: Number of commits to list, or None for no limit
+ series: Series object to add information into. By default a new series
+ is started.
+ Returns:
+ A Series object containing information about the commits.
+ """
+ params = ['git', 'log', '--no-color', '--reverse', '--no-decorate',
+ commit_range]
+ if count is not None:
+ params[2:2] = ['-n%d' % count]
+ if git_dir:
+ params[1:1] = ['--git-dir', git_dir]
+ pipe = [params]
+ stdout = command.RunPipe(pipe, capture=True).stdout
+ ps = PatchStream(series, is_log=True)
+ for line in stdout.splitlines():
+ ps.ProcessLine(line)
+ ps.Finalize()
+ return series
+
+def GetMetaData(start, count):
+ """Reads out patch series metadata from the commits
+
+ This does a 'git log' on the relevant commits and pulls out the tags we
+ are interested in.
+
+ Args:
+ start: Commit to start from: 0=HEAD, 1=next one, etc.
+ count: Number of commits to list
+ """
+ return GetMetaDataForList('HEAD~%d' % start, None, count)
+
+def FixPatch(backup_dir, fname, series, commit):
+ """Fix up a patch file, by adding/removing as required.
+
+ We remove our tags from the patch file, insert changes lists, etc.
+ The patch file is processed in place, and overwritten.
+
+ A backup file is put into backup_dir (if not None).
+
+ Args:
+ fname: Filename to patch file to process
+ series: Series information about this patch set
+ commit: Commit object for this patch file
+ Return:
+ A list of errors, or [] if all ok.
+ """
+ handle, tmpname = tempfile.mkstemp()
+ outfd = os.fdopen(handle, 'w')
+ infd = open(fname, 'r')
+ ps = PatchStream(series)
+ ps.commit = commit
+ ps.ProcessStream(infd, outfd)
+ infd.close()
+ outfd.close()
+
+ # Create a backup file if required
+ if backup_dir:
+ shutil.copy(fname, os.path.join(backup_dir, os.path.basename(fname)))
+ shutil.move(tmpname, fname)
+ return ps.warn
+
+def FixPatches(series, fnames):
+ """Fix up a list of patches identified by filenames
+
+ The patch files are processed in place, and overwritten.
+
+ Args:
+ series: The series object
+ fnames: List of patch files to process
+ """
+ # Current workflow creates patches, so we shouldn't need a backup
+ backup_dir = None #tempfile.mkdtemp('clean-patch')
+ count = 0
+ for fname in fnames:
+ commit = series.commits[count]
+ commit.patch = fname
+ result = FixPatch(backup_dir, fname, series, commit)
+ if result:
+ print '%d warnings for %s:' % (len(result), fname)
+ for warn in result:
+ print '\t', warn
+ print
+ count += 1
+ print 'Cleaned %d patches' % count
+ return series
+
+def InsertCoverLetter(fname, series, count):
+ """Inserts a cover letter with the required info into patch 0
+
+ Args:
+ fname: Input / output filename of the cover letter file
+ series: Series object
+ count: Number of patches in the series
+ """
+ fd = open(fname, 'r')
+ lines = fd.readlines()
+ fd.close()
+
+ fd = open(fname, 'w')
+ text = series.cover
+ prefix = series.GetPatchPrefix()
+ for line in lines:
+ if line.startswith('Subject:'):
+ # TODO: if more than 10 patches this should save 00/xx, not 0/xx
+ line = 'Subject: [%s 0/%d] %s\n' % (prefix, count, text[0])
+
+ # Insert our cover letter
+ elif line.startswith('*** BLURB HERE ***'):
+ # First the blurb test
+ line = '\n'.join(text[1:]) + '\n'
+ if series.get('notes'):
+ line += '\n'.join(series.notes) + '\n'
+
+ # Now the change list
+ out = series.MakeChangeLog(None)
+ line += '\n' + '\n'.join(out)
+ fd.write(line)
+ fd.close()
diff --git a/tools/patman/patman b/tools/patman/patman
new file mode 120000
index 0000000..6cc3d7a
--- /dev/null
+++ b/tools/patman/patman
@@ -0,0 +1 @@
+patman.py \ No newline at end of file
diff --git a/tools/patman/patman.py b/tools/patman/patman.py
new file mode 100755
index 0000000..7a317c5
--- /dev/null
+++ b/tools/patman/patman.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+"""See README for more information"""
+
+from optparse import OptionParser
+import os
+import re
+import sys
+import unittest
+
+# Our modules
+import checkpatch
+import command
+import gitutil
+import patchstream
+import project
+import settings
+import terminal
+import test
+
+
+parser = OptionParser()
+parser.add_option('-a', '--no-apply', action='store_false',
+ dest='apply_patches', default=True,
+ help="Don't test-apply patches with git am")
+parser.add_option('-H', '--full-help', action='store_true', dest='full_help',
+ default=False, help='Display the README file')
+parser.add_option('-c', '--count', dest='count', type='int',
+ default=-1, help='Automatically create patches from top n commits')
+parser.add_option('-i', '--ignore-errors', action='store_true',
+ dest='ignore_errors', default=False,
+ help='Send patches email even if patch errors are found')
+parser.add_option('-n', '--dry-run', action='store_true', dest='dry_run',
+ default=False, help="Do a dry run (create but don't email patches)")
+parser.add_option('-p', '--project', default=project.DetectProject(),
+ help="Project name; affects default option values and "
+ "aliases [default: %default]")
+parser.add_option('-r', '--in-reply-to', type='string', action='store',
+ help="Message ID that this series is in reply to")
+parser.add_option('-s', '--start', dest='start', type='int',
+ default=0, help='Commit to start creating patches from (0 = HEAD)')
+parser.add_option('-t', '--ignore-bad-tags', action='store_true',
+ default=False, help='Ignore bad tags / aliases')
+parser.add_option('--test', action='store_true', dest='test',
+ default=False, help='run tests')
+parser.add_option('-v', '--verbose', action='store_true', dest='verbose',
+ default=False, help='Verbose output of errors and warnings')
+parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store',
+ default=None, help='Output cc list for patch file (used by git)')
+parser.add_option('--no-check', action='store_false', dest='check_patch',
+ default=True,
+ help="Don't check for patch compliance")
+parser.add_option('--no-tags', action='store_false', dest='process_tags',
+ default=True, help="Don't process subject tags as aliaes")
+
+parser.usage = """patman [options]
+
+Create patches from commits in a branch, check them and email them as
+specified by tags you place in the commits. Use -n to do a dry run first."""
+
+
+# Parse options twice: first to get the project and second to handle
+# defaults properly (which depends on project).
+(options, args) = parser.parse_args()
+settings.Setup(parser, options.project, '')
+(options, args) = parser.parse_args()
+
+# Run our meagre tests
+if options.test:
+ import doctest
+
+ sys.argv = [sys.argv[0]]
+ suite = unittest.TestLoader().loadTestsFromTestCase(test.TestPatch)
+ result = unittest.TestResult()
+ suite.run(result)
+
+ for module in ['gitutil', 'settings']:
+ suite = doctest.DocTestSuite(module)
+ suite.run(result)
+
+ # TODO: Surely we can just 'print' result?
+ print result
+ for test, err in result.errors:
+ print err
+ for test, err in result.failures:
+ print err
+
+# Called from git with a patch filename as argument
+# Printout a list of additional CC recipients for this patch
+elif options.cc_cmd:
+ fd = open(options.cc_cmd, 'r')
+ re_line = re.compile('(\S*) (.*)')
+ for line in fd.readlines():
+ match = re_line.match(line)
+ if match and match.group(1) == args[0]:
+ for cc in match.group(2).split(', '):
+ cc = cc.strip()
+ if cc:
+ print cc
+ fd.close()
+
+elif options.full_help:
+ pager = os.getenv('PAGER')
+ if not pager:
+ pager = 'more'
+ fname = os.path.join(os.path.dirname(sys.argv[0]), 'README')
+ command.Run(pager, fname)
+
+# Process commits, produce patches files, check them, email them
+else:
+ gitutil.Setup()
+
+ if options.count == -1:
+ # Work out how many patches to send if we can
+ options.count = gitutil.CountCommitsToBranch() - options.start
+
+ col = terminal.Color()
+ if not options.count:
+ str = 'No commits found to process - please use -c flag'
+ print col.Color(col.RED, str)
+ sys.exit(1)
+
+ # Read the metadata from the commits
+ if options.count:
+ series = patchstream.GetMetaData(options.start, options.count)
+ cover_fname, args = gitutil.CreatePatches(options.start, options.count,
+ series)
+
+ # Fix up the patch files to our liking, and insert the cover letter
+ series = patchstream.FixPatches(series, args)
+ if series and cover_fname and series.get('cover'):
+ patchstream.InsertCoverLetter(cover_fname, series, options.count)
+
+ # Do a few checks on the series
+ series.DoChecks()
+
+ # Check the patches, and run them through 'git am' just to be sure
+ if options.check_patch:
+ ok = checkpatch.CheckPatches(options.verbose, args)
+ else:
+ ok = True
+ if options.apply_patches:
+ if not gitutil.ApplyPatches(options.verbose, args,
+ options.count + options.start):
+ ok = False
+
+ cc_file = series.MakeCcFile(options.process_tags, cover_fname,
+ not options.ignore_bad_tags)
+
+ # Email the patches out (giving the user time to check / cancel)
+ cmd = ''
+ if ok or options.ignore_errors:
+ cmd = gitutil.EmailPatches(series, cover_fname, args,
+ options.dry_run, not options.ignore_bad_tags, cc_file,
+ in_reply_to=options.in_reply_to)
+
+ # For a dry run, just show our actions as a sanity check
+ if options.dry_run:
+ series.ShowActions(args, cmd, options.process_tags)
+
+ os.remove(cc_file)
diff --git a/tools/patman/project.py b/tools/patman/project.py
new file mode 100644
index 0000000..4f7b2b3
--- /dev/null
+++ b/tools/patman/project.py
@@ -0,0 +1,43 @@
+# Copyright (c) 2012 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import os.path
+
+import gitutil
+
+def DetectProject():
+ """Autodetect the name of the current project.
+
+ This looks for signature files/directories that are unlikely to exist except
+ in the given project.
+
+ Returns:
+ The name of the project, like "linux" or "u-boot". Returns "unknown"
+ if we can't detect the project.
+ """
+ top_level = gitutil.GetTopLevel()
+
+ if os.path.exists(os.path.join(top_level, "include", "u-boot")):
+ return "u-boot"
+ elif os.path.exists(os.path.join(top_level, "kernel")):
+ return "linux"
+
+ return "unknown"
diff --git a/tools/patman/series.py b/tools/patman/series.py
new file mode 100644
index 0000000..85ed316
--- /dev/null
+++ b/tools/patman/series.py
@@ -0,0 +1,283 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import itertools
+import os
+
+import get_maintainer
+import gitutil
+import terminal
+
+# Series-xxx tags that we understand
+valid_series = ['to', 'cc', 'version', 'changes', 'prefix', 'notes', 'name',
+ 'cover-cc', 'process_log']
+
+class Series(dict):
+ """Holds information about a patch series, including all tags.
+
+ Vars:
+ cc: List of aliases/emails to Cc all patches to
+ commits: List of Commit objects, one for each patch
+ cover: List of lines in the cover letter
+ notes: List of lines in the notes
+ changes: (dict) List of changes for each version, The key is
+ the integer version number
+ allow_overwrite: Allow tags to overwrite an existing tag
+ """
+ def __init__(self):
+ self.cc = []
+ self.to = []
+ self.cover_cc = []
+ self.commits = []
+ self.cover = None
+ self.notes = []
+ self.changes = {}
+ self.allow_overwrite = False
+
+ # Written in MakeCcFile()
+ # key: name of patch file
+ # value: list of email addresses
+ self._generated_cc = {}
+
+ # These make us more like a dictionary
+ def __setattr__(self, name, value):
+ self[name] = value
+
+ def __getattr__(self, name):
+ return self[name]
+
+ def AddTag(self, commit, line, name, value):
+ """Add a new Series-xxx tag along with its value.
+
+ Args:
+ line: Source line containing tag (useful for debug/error messages)
+ name: Tag name (part after 'Series-')
+ value: Tag value (part after 'Series-xxx: ')
+ """
+ # If we already have it, then add to our list
+ name = name.replace('-', '_')
+ if name in self and not self.allow_overwrite:
+ values = value.split(',')
+ values = [str.strip() for str in values]
+ if type(self[name]) != type([]):
+ raise ValueError("In %s: line '%s': Cannot add another value "
+ "'%s' to series '%s'" %
+ (commit.hash, line, values, self[name]))
+ self[name] += values
+
+ # Otherwise just set the value
+ elif name in valid_series:
+ self[name] = value
+ else:
+ raise ValueError("In %s: line '%s': Unknown 'Series-%s': valid "
+ "options are %s" % (commit.hash, line, name,
+ ', '.join(valid_series)))
+
+ def AddCommit(self, commit):
+ """Add a commit into our list of commits
+
+ We create a list of tags in the commit subject also.
+
+ Args:
+ commit: Commit object to add
+ """
+ commit.CheckTags()
+ self.commits.append(commit)
+
+ def ShowActions(self, args, cmd, process_tags):
+ """Show what actions we will/would perform
+
+ Args:
+ args: List of patch files we created
+ cmd: The git command we would have run
+ process_tags: Process tags as if they were aliases
+ """
+ col = terminal.Color()
+ print 'Dry run, so not doing much. But I would do this:'
+ print
+ print 'Send a total of %d patch%s with %scover letter.' % (
+ len(args), '' if len(args) == 1 else 'es',
+ self.get('cover') and 'a ' or 'no ')
+
+ # TODO: Colour the patches according to whether they passed checks
+ for upto in range(len(args)):
+ commit = self.commits[upto]
+ print col.Color(col.GREEN, ' %s' % args[upto])
+ cc_list = list(self._generated_cc[commit.patch])
+
+ # Skip items in To list
+ if 'to' in self:
+ try:
+ map(cc_list.remove, gitutil.BuildEmailList(self.to))
+ except ValueError:
+ pass
+
+ for email in cc_list:
+ if email == None:
+ email = col.Color(col.YELLOW, "<alias '%s' not found>"
+ % tag)
+ if email:
+ print ' Cc: ',email
+ print
+ for item in gitutil.BuildEmailList(self.get('to', '<none>')):
+ print 'To:\t ', item
+ for item in gitutil.BuildEmailList(self.cc):
+ print 'Cc:\t ', item
+ print 'Version: ', self.get('version')
+ print 'Prefix:\t ', self.get('prefix')
+ if self.cover:
+ print 'Cover: %d lines' % len(self.cover)
+ cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
+ all_ccs = itertools.chain(cover_cc, *self._generated_cc.values())
+ for email in set(all_ccs):
+ print ' Cc: ',email
+ if cmd:
+ print 'Git command: %s' % cmd
+
+ def MakeChangeLog(self, commit):
+ """Create a list of changes for each version.
+
+ Return:
+ The change log as a list of strings, one per line
+
+ Changes in v4:
+ - Jog the dial back closer to the widget
+
+ Changes in v3: None
+ Changes in v2:
+ - Fix the widget
+ - Jog the dial
+
+ etc.
+ """
+ final = []
+ process_it = self.get('process_log', '').split(',')
+ process_it = [item.strip() for item in process_it]
+ need_blank = False
+ for change in sorted(self.changes, reverse=True):
+ out = []
+ for this_commit, text in self.changes[change]:
+ if commit and this_commit != commit:
+ continue
+ if 'uniq' not in process_it or text not in out:
+ out.append(text)
+ line = 'Changes in v%d:' % change
+ have_changes = len(out) > 0
+ if 'sort' in process_it:
+ out = sorted(out)
+ if have_changes:
+ out.insert(0, line)
+ else:
+ out = [line + ' None']
+ if need_blank:
+ out.insert(0, '')
+ final += out
+ need_blank = have_changes
+ if self.changes:
+ final.append('')
+ return final
+
+ def DoChecks(self):
+ """Check that each version has a change log
+
+ Print an error if something is wrong.
+ """
+ col = terminal.Color()
+ if self.get('version'):
+ changes_copy = dict(self.changes)
+ for version in range(1, int(self.version) + 1):
+ if self.changes.get(version):
+ del changes_copy[version]
+ else:
+ if version > 1:
+ str = 'Change log missing for v%d' % version
+ print col.Color(col.RED, str)
+ for version in changes_copy:
+ str = 'Change log for unknown version v%d' % version
+ print col.Color(col.RED, str)
+ elif self.changes:
+ str = 'Change log exists, but no version is set'
+ print col.Color(col.RED, str)
+
+ def MakeCcFile(self, process_tags, cover_fname, raise_on_error):
+ """Make a cc file for us to use for per-commit Cc automation
+
+ Also stores in self._generated_cc to make ShowActions() faster.
+
+ Args:
+ process_tags: Process tags as if they were aliases
+ cover_fname: If non-None the name of the cover letter.
+ raise_on_error: True to raise an error when an alias fails to match,
+ False to just print a message.
+ Return:
+ Filename of temp file created
+ """
+ # Look for commit tags (of the form 'xxx:' at the start of the subject)
+ fname = '/tmp/patman.%d' % os.getpid()
+ fd = open(fname, 'w')
+ all_ccs = []
+ for commit in self.commits:
+ list = []
+ if process_tags:
+ list += gitutil.BuildEmailList(commit.tags,
+ raise_on_error=raise_on_error)
+ list += gitutil.BuildEmailList(commit.cc_list,
+ raise_on_error=raise_on_error)
+ list += get_maintainer.GetMaintainer(commit.patch)
+ all_ccs += list
+ print >>fd, commit.patch, ', '.join(list)
+ self._generated_cc[commit.patch] = list
+
+ if cover_fname:
+ cover_cc = gitutil.BuildEmailList(self.get('cover_cc', ''))
+ print >>fd, cover_fname, ', '.join(set(cover_cc + all_ccs))
+
+ fd.close()
+ return fname
+
+ def AddChange(self, version, commit, info):
+ """Add a new change line to a version.
+
+ This will later appear in the change log.
+
+ Args:
+ version: version number to add change list to
+ info: change line for this version
+ """
+ if not self.changes.get(version):
+ self.changes[version] = []
+ self.changes[version].append([commit, info])
+
+ def GetPatchPrefix(self):
+ """Get the patch version string
+
+ Return:
+ Patch string, like 'RFC PATCH v5' or just 'PATCH'
+ """
+ version = ''
+ if self.get('version'):
+ version = ' v%s' % self['version']
+
+ # Get patch name prefix
+ prefix = ''
+ if self.get('prefix'):
+ prefix = '%s ' % self['prefix']
+ return '%sPATCH%s' % (prefix, version)
diff --git a/tools/patman/settings.py b/tools/patman/settings.py
new file mode 100644
index 0000000..084d1b8
--- /dev/null
+++ b/tools/patman/settings.py
@@ -0,0 +1,284 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import ConfigParser
+import os
+import re
+
+import command
+import gitutil
+
+"""Default settings per-project.
+
+These are used by _ProjectConfigParser. Settings names should match
+the "dest" of the option parser from patman.py.
+"""
+_default_settings = {
+ "u-boot": {},
+ "linux": {
+ "process_tags": "False",
+ }
+}
+
+class _ProjectConfigParser(ConfigParser.SafeConfigParser):
+ """ConfigParser that handles projects.
+
+ There are two main goals of this class:
+ - Load project-specific default settings.
+ - Merge general default settings/aliases with project-specific ones.
+
+ # Sample config used for tests below...
+ >>> import StringIO
+ >>> sample_config = '''
+ ... [alias]
+ ... me: Peter P. <likesspiders@example.com>
+ ... enemies: Evil <evil@example.com>
+ ...
+ ... [sm_alias]
+ ... enemies: Green G. <ugly@example.com>
+ ...
+ ... [sm2_alias]
+ ... enemies: Doc O. <pus@example.com>
+ ...
+ ... [settings]
+ ... am_hero: True
+ ... '''
+
+ # Check to make sure that bogus project gets general alias.
+ >>> config = _ProjectConfigParser("zzz")
+ >>> config.readfp(StringIO.StringIO(sample_config))
+ >>> config.get("alias", "enemies")
+ 'Evil <evil@example.com>'
+
+ # Check to make sure that alias gets overridden by project.
+ >>> config = _ProjectConfigParser("sm")
+ >>> config.readfp(StringIO.StringIO(sample_config))
+ >>> config.get("alias", "enemies")
+ 'Green G. <ugly@example.com>'
+
+ # Check to make sure that settings get merged with project.
+ >>> config = _ProjectConfigParser("linux")
+ >>> config.readfp(StringIO.StringIO(sample_config))
+ >>> sorted(config.items("settings"))
+ [('am_hero', 'True'), ('process_tags', 'False')]
+
+ # Check to make sure that settings works with unknown project.
+ >>> config = _ProjectConfigParser("unknown")
+ >>> config.readfp(StringIO.StringIO(sample_config))
+ >>> sorted(config.items("settings"))
+ [('am_hero', 'True')]
+ """
+ def __init__(self, project_name):
+ """Construct _ProjectConfigParser.
+
+ In addition to standard SafeConfigParser initialization, this also loads
+ project defaults.
+
+ Args:
+ project_name: The name of the project.
+ """
+ self._project_name = project_name
+ ConfigParser.SafeConfigParser.__init__(self)
+
+ # Update the project settings in the config based on
+ # the _default_settings global.
+ project_settings = "%s_settings" % project_name
+ if not self.has_section(project_settings):
+ self.add_section(project_settings)
+ project_defaults = _default_settings.get(project_name, {})
+ for setting_name, setting_value in project_defaults.iteritems():
+ self.set(project_settings, setting_name, setting_value)
+
+ def get(self, section, option, *args, **kwargs):
+ """Extend SafeConfigParser to try project_section before section.
+
+ Args:
+ See SafeConfigParser.
+ Returns:
+ See SafeConfigParser.
+ """
+ try:
+ return ConfigParser.SafeConfigParser.get(
+ self, "%s_%s" % (self._project_name, section), option,
+ *args, **kwargs
+ )
+ except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
+ return ConfigParser.SafeConfigParser.get(
+ self, section, option, *args, **kwargs
+ )
+
+ def items(self, section, *args, **kwargs):
+ """Extend SafeConfigParser to add project_section to section.
+
+ Args:
+ See SafeConfigParser.
+ Returns:
+ See SafeConfigParser.
+ """
+ project_items = []
+ has_project_section = False
+ top_items = []
+
+ # Get items from the project section
+ try:
+ project_items = ConfigParser.SafeConfigParser.items(
+ self, "%s_%s" % (self._project_name, section), *args, **kwargs
+ )
+ has_project_section = True
+ except ConfigParser.NoSectionError:
+ pass
+
+ # Get top-level items
+ try:
+ top_items = ConfigParser.SafeConfigParser.items(
+ self, section, *args, **kwargs
+ )
+ except ConfigParser.NoSectionError:
+ # If neither section exists raise the error on...
+ if not has_project_section:
+ raise
+
+ item_dict = dict(top_items)
+ item_dict.update(project_items)
+ return item_dict.items()
+
+def ReadGitAliases(fname):
+ """Read a git alias file. This is in the form used by git:
+
+ alias uboot u-boot@lists.denx.de
+ alias wd Wolfgang Denk <wd@denx.de>
+
+ Args:
+ fname: Filename to read
+ """
+ try:
+ fd = open(fname, 'r')
+ except IOError:
+ print "Warning: Cannot find alias file '%s'" % fname
+ return
+
+ re_line = re.compile('alias\s+(\S+)\s+(.*)')
+ for line in fd.readlines():
+ line = line.strip()
+ if not line or line[0] == '#':
+ continue
+
+ m = re_line.match(line)
+ if not m:
+ print "Warning: Alias file line '%s' not understood" % line
+ continue
+
+ list = alias.get(m.group(1), [])
+ for item in m.group(2).split(','):
+ item = item.strip()
+ if item:
+ list.append(item)
+ alias[m.group(1)] = list
+
+ fd.close()
+
+def CreatePatmanConfigFile(config_fname):
+ """Creates a config file under $(HOME)/.patman if it can't find one.
+
+ Args:
+ config_fname: Default config filename i.e., $(HOME)/.patman
+
+ Returns:
+ None
+ """
+ name = gitutil.GetDefaultUserName()
+ if name == None:
+ name = raw_input("Enter name: ")
+
+ email = gitutil.GetDefaultUserEmail()
+
+ if email == None:
+ email = raw_input("Enter email: ")
+
+ try:
+ f = open(config_fname, 'w')
+ except IOError:
+ print "Couldn't create patman config file\n"
+ raise
+
+ print >>f, "[alias]\nme: %s <%s>" % (name, email)
+ f.close();
+
+def _UpdateDefaults(parser, config):
+ """Update the given OptionParser defaults based on config.
+
+ We'll walk through all of the settings from the parser
+ For each setting we'll look for a default in the option parser.
+ If it's found we'll update the option parser default.
+
+ The idea here is that the .patman file should be able to update
+ defaults but that command line flags should still have the final
+ say.
+
+ Args:
+ parser: An instance of an OptionParser whose defaults will be
+ updated.
+ config: An instance of _ProjectConfigParser that we will query
+ for settings.
+ """
+ defaults = parser.get_default_values()
+ for name, val in config.items('settings'):
+ if hasattr(defaults, name):
+ default_val = getattr(defaults, name)
+ if isinstance(default_val, bool):
+ val = config.getboolean('settings', name)
+ elif isinstance(default_val, int):
+ val = config.getint('settings', name)
+ parser.set_default(name, val)
+ else:
+ print "WARNING: Unknown setting %s" % name
+
+def Setup(parser, project_name, config_fname=''):
+ """Set up the settings module by reading config files.
+
+ Args:
+ parser: The parser to update
+ project_name: Name of project that we're working on; we'll look
+ for sections named "project_section" as well.
+ config_fname: Config filename to read ('' for default)
+ """
+ config = _ProjectConfigParser(project_name)
+ if config_fname == '':
+ config_fname = '%s/.patman' % os.getenv('HOME')
+
+ if not os.path.exists(config_fname):
+ print "No config file found ~/.patman\nCreating one...\n"
+ CreatePatmanConfigFile(config_fname)
+
+ config.read(config_fname)
+
+ for name, value in config.items('alias'):
+ alias[name] = value.split(',')
+
+ _UpdateDefaults(parser, config)
+
+# These are the aliases we understand, indexed by alias. Each member is a list.
+alias = {}
+
+if __name__ == "__main__":
+ import doctest
+
+ doctest.testmod()
diff --git a/tools/patman/terminal.py b/tools/patman/terminal.py
new file mode 100644
index 0000000..337a2a4
--- /dev/null
+++ b/tools/patman/terminal.py
@@ -0,0 +1,96 @@
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+"""Terminal utilities
+
+This module handles terminal interaction including ANSI color codes.
+"""
+
+import os
+import sys
+
+# Selection of when we want our output to be colored
+COLOR_IF_TERMINAL, COLOR_ALWAYS, COLOR_NEVER = range(3)
+
+class Color(object):
+ """Conditionally wraps text in ANSI color escape sequences."""
+ BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
+ BOLD = -1
+ BRIGHT_START = '\033[1;%dm'
+ NORMAL_START = '\033[22;%dm'
+ BOLD_START = '\033[1m'
+ RESET = '\033[0m'
+
+ def __init__(self, colored=COLOR_IF_TERMINAL):
+ """Create a new Color object, optionally disabling color output.
+
+ Args:
+ enabled: True if color output should be enabled. If False then this
+ class will not add color codes at all.
+ """
+ self._enabled = (colored == COLOR_ALWAYS or
+ (colored == COLOR_IF_TERMINAL and os.isatty(sys.stdout.fileno())))
+
+ def Start(self, color, bright=True):
+ """Returns a start color code.
+
+ Args:
+ color: Color to use, .e.g BLACK, RED, etc.
+
+ Returns:
+ If color is enabled, returns an ANSI sequence to start the given color,
+ otherwise returns empty string
+ """
+ if self._enabled:
+ base = self.BRIGHT_START if bright else self.NORMAL_START
+ return base % (color + 30)
+ return ''
+
+ def Stop(self):
+ """Retruns a stop color code.
+
+ Returns:
+ If color is enabled, returns an ANSI color reset sequence, otherwise
+ returns empty string
+ """
+ if self._enabled:
+ return self.RESET
+ return ''
+
+ def Color(self, color, text, bright=True):
+ """Returns text with conditionally added color escape sequences.
+
+ Keyword arguments:
+ color: Text color -- one of the color constants defined in this class.
+ text: The text to color.
+
+ Returns:
+ If self._enabled is False, returns the original text. If it's True,
+ returns text with color escape sequences based on the value of color.
+ """
+ if not self._enabled:
+ return text
+ if color == self.BOLD:
+ start = self.BOLD_START
+ else:
+ base = self.BRIGHT_START if bright else self.NORMAL_START
+ start = base % (color + 30)
+ return start + text + self.RESET
diff --git a/tools/patman/test.py b/tools/patman/test.py
new file mode 100644
index 0000000..8cd2647
--- /dev/null
+++ b/tools/patman/test.py
@@ -0,0 +1,274 @@
+#
+# Copyright (c) 2011 The Chromium OS Authors.
+#
+# 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.
+#
+# 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+import os
+import tempfile
+import unittest
+
+import checkpatch
+import gitutil
+import patchstream
+import series
+
+
+class TestPatch(unittest.TestCase):
+ """Test this program
+
+ TODO: Write tests for the rest of the functionality
+ """
+
+ def testBasic(self):
+ """Test basic filter operation"""
+ data='''
+
+From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 28 Apr 2011 09:58:51 -0700
+Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
+
+This adds functions to enable/disable clocks and reset to on-chip peripherals.
+
+BUG=chromium-os:13875
+TEST=build U-Boot for Seaboard, boot
+
+Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413
+
+Review URL: http://codereview.chromium.org/6900006
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+---
+ arch/arm/cpu/armv7/tegra2/Makefile | 2 +-
+ arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++----
+ arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++
+'''
+ expected='''
+
+From 656c9a8c31fa65859d924cd21da920d6ba537fad Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 28 Apr 2011 09:58:51 -0700
+Subject: [PATCH (resend) 3/7] Tegra2: Add more clock support
+
+This adds functions to enable/disable clocks and reset to on-chip peripherals.
+
+Signed-off-by: Simon Glass <sjg@chromium.org>
+---
+ arch/arm/cpu/armv7/tegra2/Makefile | 2 +-
+ arch/arm/cpu/armv7/tegra2/ap20.c | 57 ++----
+ arch/arm/cpu/armv7/tegra2/clock.c | 163 +++++++++++++++++
+'''
+ out = ''
+ inhandle, inname = tempfile.mkstemp()
+ infd = os.fdopen(inhandle, 'w')
+ infd.write(data)
+ infd.close()
+
+ exphandle, expname = tempfile.mkstemp()
+ expfd = os.fdopen(exphandle, 'w')
+ expfd.write(expected)
+ expfd.close()
+
+ patchstream.FixPatch(None, inname, series.Series(), None)
+ rc = os.system('diff -u %s %s' % (inname, expname))
+ self.assertEqual(rc, 0)
+
+ os.remove(inname)
+ os.remove(expname)
+
+ def GetData(self, data_type):
+ data='''
+From 4924887af52713cabea78420eff03badea8f0035 Mon Sep 17 00:00:00 2001
+From: Simon Glass <sjg@chromium.org>
+Date: Thu, 7 Apr 2011 10:14:41 -0700
+Subject: [PATCH 1/4] Add microsecond boot time measurement
+
+This defines the basics of a new boot time measurement feature. This allows
+logging of very accurate time measurements as the boot proceeds, by using
+an available microsecond counter.
+
+%s
+---
+ README | 11 ++++++++
+ common/bootstage.c | 50 ++++++++++++++++++++++++++++++++++++
+ include/bootstage.h | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ include/common.h | 8 ++++++
+ 5 files changed, 141 insertions(+), 0 deletions(-)
+ create mode 100644 common/bootstage.c
+ create mode 100644 include/bootstage.h
+
+diff --git a/README b/README
+index 6f3748d..f9e4e65 100644
+--- a/README
++++ b/README
+@@ -2026,6 +2026,17 @@ The following options need to be configured:
+ example, some LED's) on your board. At the moment,
+ the following checkpoints are implemented:
+
++- Time boot progress
++ CONFIG_BOOTSTAGE
++
++ Define this option to enable microsecond boot stage timing
++ on supported platforms. For this to work your platform
++ needs to define a function timer_get_us() which returns the
++ number of microseconds since reset. This would normally
++ be done in your SOC or board timer.c file.
++
++ You can add calls to bootstage_mark() to set time markers.
++
+ - Standalone program support:
+ CONFIG_STANDALONE_LOAD_ADDR
+
+diff --git a/common/bootstage.c b/common/bootstage.c
+new file mode 100644
+index 0000000..2234c87
+--- /dev/null
++++ b/common/bootstage.c
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (c) 2011, Google Inc. All rights reserved.
++ *
++ * 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.
++ *
++ * 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., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++
++/*
++ * This module records the progress of boot and arbitrary commands, and
++ * permits accurate timestamping of each. The records can optionally be
++ * passed to kernel in the ATAGs
++ */
++
++#include <common.h>
++
++
++struct bootstage_record {
++ uint32_t time_us;
++ const char *name;
++};
++
++static struct bootstage_record record[BOOTSTAGE_COUNT];
++
++uint32_t bootstage_mark(enum bootstage_id id, const char *name)
++{
++ struct bootstage_record *rec = &record[id];
++
++ /* Only record the first event for each */
++%sif (!rec->name) {
++ rec->time_us = (uint32_t)timer_get_us();
++ rec->name = name;
++ }
++ if (!rec->name &&
++ %ssomething_else) {
++ rec->time_us = (uint32_t)timer_get_us();
++ rec->name = name;
++ }
++%sreturn rec->time_us;
++}
+--
+1.7.3.1
+'''
+ signoff = 'Signed-off-by: Simon Glass <sjg@chromium.org>\n'
+ tab = ' '
+ indent = ' '
+ if data_type == 'good':
+ pass
+ elif data_type == 'no-signoff':
+ signoff = ''
+ elif data_type == 'spaces':
+ tab = ' '
+ elif data_type == 'indent':
+ indent = tab
+ else:
+ print 'not implemented'
+ return data % (signoff, tab, indent, tab)
+
+ def SetupData(self, data_type):
+ inhandle, inname = tempfile.mkstemp()
+ infd = os.fdopen(inhandle, 'w')
+ data = self.GetData(data_type)
+ infd.write(data)
+ infd.close()
+ return inname
+
+ def testGood(self):
+ """Test checkpatch operation"""
+ inf = self.SetupData('good')
+ result = checkpatch.CheckPatch(inf)
+ self.assertEqual(result.ok, True)
+ self.assertEqual(result.problems, [])
+ self.assertEqual(result.errors, 0)
+ self.assertEqual(result.warnings, 0)
+ self.assertEqual(result.checks, 0)
+ self.assertEqual(result.lines, 67)
+ os.remove(inf)
+
+ def testNoSignoff(self):
+ inf = self.SetupData('no-signoff')
+ result = checkpatch.CheckPatch(inf)
+ self.assertEqual(result.ok, False)
+ self.assertEqual(len(result.problems), 1)
+ self.assertEqual(result.errors, 1)
+ self.assertEqual(result.warnings, 0)
+ self.assertEqual(result.checks, 0)
+ self.assertEqual(result.lines, 67)
+ os.remove(inf)
+
+ def testSpaces(self):
+ inf = self.SetupData('spaces')
+ result = checkpatch.CheckPatch(inf)
+ self.assertEqual(result.ok, False)
+ self.assertEqual(len(result.problems), 1)
+ self.assertEqual(result.errors, 0)
+ self.assertEqual(result.warnings, 1)
+ self.assertEqual(result.checks, 0)
+ self.assertEqual(result.lines, 67)
+ os.remove(inf)
+
+ def testIndent(self):
+ inf = self.SetupData('indent')
+ result = checkpatch.CheckPatch(inf)
+ self.assertEqual(result.ok, False)
+ self.assertEqual(len(result.problems), 1)
+ self.assertEqual(result.errors, 0)
+ self.assertEqual(result.warnings, 0)
+ self.assertEqual(result.checks, 1)
+ self.assertEqual(result.lines, 67)
+ os.remove(inf)
+
+
+if __name__ == "__main__":
+ unittest.main()
+ gitutil.RunTests()
diff --git a/tools/pblimage.c b/tools/pblimage.c
new file mode 100644
index 0000000..5f39dc5
--- /dev/null
+++ b/tools/pblimage.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include <image.h>
+#include "pblimage.h"
+
+/*
+ * 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.
+ */
+static unsigned char mem_buf[1000000];
+static unsigned char *pmem_buf = mem_buf;
+static int pbl_size;
+static char *fname = "Unknown";
+static int lineno = -1;
+static struct pbl_header pblimage_header;
+
+static union
+{
+ char c[4];
+ unsigned char l;
+} endian_test = { {'l', '?', '?', 'b'} };
+
+#define ENDIANNESS ((char)endian_test.l)
+
+/*
+ * The PBL can load up to 64 bytes at a time, so we split the U-Boot
+ * image into 64 byte chunks. PBL needs a command for each piece, of
+ * the form "81xxxxxx", where "xxxxxx" is the offset. Calculate the
+ * start offset by subtracting the size of the u-boot image from the
+ * top of the allowable 24-bit range.
+ */
+static void init_next_pbl_cmd(FILE *fp_uboot)
+{
+ struct stat st;
+ int fd = fileno(fp_uboot);
+
+ if (fstat(fd, &st) == -1) {
+ printf("Error: Could not determine u-boot image size. %s\n",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ next_pbl_cmd = 0x82000000 - st.st_size;
+}
+
+static void generate_pbl_cmd(void)
+{
+ uint32_t val = next_pbl_cmd;
+ next_pbl_cmd += 0x40;
+ int i;
+
+ for (i = 3; i >= 0; i--) {
+ *pmem_buf++ = (val >> (i * 8)) & 0xff;
+ pbl_size++;
+ }
+}
+
+static void pbl_fget(size_t size, FILE *stream)
+{
+ unsigned char c;
+ int c_temp;
+
+ while (size && (c_temp = fgetc(stream)) != EOF) {
+ c = (unsigned char)c_temp;
+ *pmem_buf++ = c;
+ pbl_size++;
+ size--;
+ }
+}
+
+/* load split u-boot with PBI command 81xxxxxx. */
+static void load_uboot(FILE *fp_uboot)
+{
+ init_next_pbl_cmd(fp_uboot);
+ while (next_pbl_cmd < 0x82000000) {
+ generate_pbl_cmd();
+ pbl_fget(64, fp_uboot);
+ }
+}
+
+static void check_get_hexval(char *token)
+{
+ uint32_t hexval;
+ int i;
+
+ if (!sscanf(token, "%x", &hexval)) {
+ printf("Error:%s[%d] - Invalid hex data(%s)\n", fname,
+ lineno, token);
+ exit(EXIT_FAILURE);
+ }
+ for (i = 3; i >= 0; i--) {
+ *pmem_buf++ = (hexval >> (i * 8)) & 0xff;
+ pbl_size++;
+ }
+}
+
+static void pbl_parser(char *name)
+{
+ FILE *fd = NULL;
+ char *line = NULL;
+ char *token, *saveptr1, *saveptr2;
+ size_t len = 0;
+
+ fname = name;
+ fd = fopen(name, "r");
+ if (fd == NULL) {
+ printf("Error:%s - Can't open\n", fname);
+ exit(EXIT_FAILURE);
+ }
+
+ while ((getline(&line, &len, fd)) > 0) {
+ lineno++;
+ token = strtok_r(line, "\r\n", &saveptr1);
+ /* drop all lines with zero tokens (= empty lines) */
+ if (token == NULL)
+ continue;
+ for (line = token;; line = NULL) {
+ token = strtok_r(line, " \t", &saveptr2);
+ if (token == NULL)
+ break;
+ /* Drop all text starting with '#' as comments */
+ if (token[0] == '#')
+ break;
+ check_get_hexval(token);
+ }
+ }
+ if (line)
+ free(line);
+ fclose(fd);
+}
+
+static uint32_t crc_table[256];
+
+static void make_crc_table(void)
+{
+ uint32_t mask;
+ int i, j;
+ uint32_t poly; /* polynomial exclusive-or pattern */
+
+ /*
+ * 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;
+ }
+}
+
+unsigned long pbl_crc32(unsigned long crc, const char *buf, uint32_t len)
+{
+ uint32_t crc32_val = 0xffffffff;
+ uint32_t xor = 0x0;
+ int i;
+
+ make_crc_table();
+
+ for (i = 0; i < len; i++)
+ crc32_val = (crc32_val << 8) ^
+ crc_table[(crc32_val >> 24) ^ (*buf++ & 0xff)];
+
+ crc32_val = crc32_val ^ xor;
+ if (crc32_val < 0) {
+ crc32_val += 0xffffffff;
+ crc32_val += 1;
+ }
+ return crc32_val;
+}
+
+static uint32_t reverse_byte(uint32_t val)
+{
+ uint32_t temp;
+ unsigned char *p1;
+ int j;
+
+ temp = val;
+ p1 = (unsigned char *)&temp;
+ for (j = 3; j >= 0; j--)
+ *p1++ = (val >> (j * 8)) & 0xff;
+ return temp;
+}
+
+/* write end command and crc command to memory. */
+static void add_end_cmd(void)
+{
+ uint32_t pbl_end_cmd[4] = {0x09138000, 0x00000000,
+ 0x091380c0, 0x00000000};
+ uint32_t crc32_pbl;
+ int i;
+ unsigned char *p = (unsigned char *)&pbl_end_cmd;
+
+ if (ENDIANNESS == 'l') {
+ for (i = 0; i < 4; i++)
+ pbl_end_cmd[i] = reverse_byte(pbl_end_cmd[i]);
+ }
+
+ for (i = 0; i < 16; i++) {
+ *pmem_buf++ = *p++;
+ pbl_size++;
+ }
+
+ /* Add PBI CRC command. */
+ *pmem_buf++ = 0x08;
+ *pmem_buf++ = 0x13;
+ *pmem_buf++ = 0x80;
+ *pmem_buf++ = 0x40;
+ pbl_size += 4;
+
+ /* calculated CRC32 and write it to memory. */
+ crc32_pbl = pbl_crc32(0, (const char *)mem_buf, pbl_size);
+ *pmem_buf++ = (crc32_pbl >> 24) & 0xff;
+ *pmem_buf++ = (crc32_pbl >> 16) & 0xff;
+ *pmem_buf++ = (crc32_pbl >> 8) & 0xff;
+ *pmem_buf++ = (crc32_pbl) & 0xff;
+ pbl_size += 4;
+
+ if ((pbl_size % 16) != 0) {
+ for (i = 0; i < 8; i++) {
+ *pmem_buf++ = 0x0;
+ pbl_size++;
+ }
+ }
+ if ((pbl_size % 16 != 0)) {
+ printf("Error: Bad size of image file\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+void pbl_load_uboot(int ifd, struct mkimage_params *params)
+{
+ FILE *fp_uboot;
+ int size;
+
+ /* parse the rcw.cfg file. */
+ pbl_parser(params->imagename);
+
+ /* parse the pbi.cfg file. */
+ pbl_parser(params->imagename2);
+
+ fp_uboot = fopen(params->datafile, "r");
+ if (fp_uboot == NULL) {
+ printf("Error: %s open failed\n", params->datafile);
+ exit(EXIT_FAILURE);
+ }
+
+ load_uboot(fp_uboot);
+ add_end_cmd();
+ fclose(fp_uboot);
+ lseek(ifd, 0, SEEK_SET);
+
+ size = pbl_size;
+ if (write(ifd, (const void *)&mem_buf, size) != size) {
+ fprintf(stderr, "Write error on %s: %s\n",
+ params->imagefile, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+}
+
+static int pblimage_check_image_types(uint8_t type)
+{
+ if (type == IH_TYPE_PBLIMAGE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static int pblimage_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct pbl_header *pbl_hdr = (struct pbl_header *) ptr;
+
+ /* Only a few checks can be done: search for magic numbers */
+ if (ENDIANNESS == 'l') {
+ if (pbl_hdr->preamble != reverse_byte(RCW_PREAMBLE))
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (pbl_hdr->rcwheader != reverse_byte(RCW_HEADER))
+ return -FDT_ERR_BADSTRUCTURE;
+ } else {
+ if (pbl_hdr->preamble != RCW_PREAMBLE)
+ return -FDT_ERR_BADSTRUCTURE;
+
+ if (pbl_hdr->rcwheader != RCW_HEADER)
+ return -FDT_ERR_BADSTRUCTURE;
+ }
+ return 0;
+}
+
+static void pblimage_print_header(const void *ptr)
+{
+ printf("Image Type: Freescale PBL Boot Image\n");
+}
+
+static void pblimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ /*nothing need to do, pbl_load_uboot takes care of whole file. */
+}
+
+/* pblimage parameters */
+static struct image_type_params pblimage_params = {
+ .name = "Freescale PBL Boot Image support",
+ .header_size = sizeof(struct pbl_header),
+ .hdr = (void *)&pblimage_header,
+ .check_image_type = pblimage_check_image_types,
+ .verify_header = pblimage_verify_header,
+ .print_header = pblimage_print_header,
+ .set_header = pblimage_set_header,
+};
+
+void init_pbl_image_type(void)
+{
+ pbl_size = 0;
+ mkimage_register(&pblimage_params);
+}
diff --git a/tools/pblimage.h b/tools/pblimage.h
new file mode 100644
index 0000000..514a477
--- /dev/null
+++ b/tools/pblimage.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef PBLIMAGE_H
+#define PBLIMAGE_H
+
+#define RCW_BYTES 64
+#define RCW_PREAMBLE 0xaa55aa55
+#define RCW_HEADER 0x010e0100
+
+struct pbl_header {
+ uint32_t preamble;
+ uint32_t rcwheader;
+ uint8_t rcw_data[RCW_BYTES];
+};
+
+#endif /* PBLIMAGE_H */
diff --git a/tools/proftool.c b/tools/proftool.c
new file mode 100644
index 0000000..aa05e77
--- /dev/null
+++ b/tools/proftool.c
@@ -0,0 +1,611 @@
+/*
+ * Copyright (c) 2013 Google, Inc
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Decode and dump U-Boot profiling information */
+
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include <compiler.h>
+#include <trace.h>
+
+#define MAX_LINE_LEN 500
+
+enum {
+ FUNCF_TRACE = 1 << 0, /* Include this function in trace */
+};
+
+struct func_info {
+ unsigned long offset;
+ const char *name;
+ unsigned long code_size;
+ unsigned long call_count;
+ unsigned flags;
+ /* the section this function is in */
+ struct objsection_info *objsection;
+};
+
+enum trace_line_type {
+ TRACE_LINE_INCLUDE,
+ TRACE_LINE_EXCLUDE,
+};
+
+struct trace_configline_info {
+ struct trace_configline_info *next;
+ enum trace_line_type type;
+ const char *name; /* identifier name / wildcard */
+ regex_t regex; /* Regex to use if name starts with / */
+};
+
+/* The contents of the trace config file */
+struct trace_configline_info *trace_config_head;
+
+struct func_info *func_list;
+int func_count;
+struct trace_call *call_list;
+int call_count;
+int verbose; /* Verbosity level 0=none, 1=warn, 2=notice, 3=info, 4=debug */
+unsigned long text_offset; /* text address of first function */
+
+static void outf(int level, const char *fmt, ...)
+ __attribute__ ((format (__printf__, 2, 3)));
+#define error(fmt, b...) outf(0, fmt, ##b)
+#define warn(fmt, b...) outf(1, fmt, ##b)
+#define notice(fmt, b...) outf(2, fmt, ##b)
+#define info(fmt, b...) outf(3, fmt, ##b)
+#define debug(fmt, b...) outf(4, fmt, ##b)
+
+
+static void outf(int level, const char *fmt, ...)
+{
+ if (verbose >= level) {
+ va_list args;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ }
+}
+
+static void usage(void)
+{
+ fprintf(stderr,
+ "Usage: proftool -cds -v3 <cmd> <profdata>\n"
+ "\n"
+ "Commands\n"
+ " dump-ftrace\t\tDump out textual data in ftrace format\n"
+ "\n"
+ "Options:\n"
+ " -m <map>\tSpecify Systen.map file\n"
+ " -t <trace>\tSpecific trace data file (from U-Boot)\n"
+ " -v <0-4>\tSpecify verbosity\n");
+ exit(EXIT_FAILURE);
+}
+
+static int h_cmp_offset(const void *v1, const void *v2)
+{
+ const struct func_info *f1 = v1, *f2 = v2;
+
+ return (f1->offset / FUNC_SITE_SIZE) - (f2->offset / FUNC_SITE_SIZE);
+}
+
+static int read_system_map(FILE *fin)
+{
+ unsigned long offset, start = 0;
+ struct func_info *func;
+ char buff[MAX_LINE_LEN];
+ char symtype;
+ char symname[MAX_LINE_LEN + 1];
+ int linenum;
+ int alloced;
+
+ for (linenum = 1, alloced = func_count = 0;; linenum++) {
+ int fields = 0;
+
+ if (fgets(buff, sizeof(buff), fin))
+ fields = sscanf(buff, "%lx %c %100s\n", &offset,
+ &symtype, symname);
+ if (fields == 2) {
+ continue;
+ } else if (feof(fin)) {
+ break;
+ } else if (fields < 2) {
+ error("Map file line %d: invalid format\n", linenum);
+ return 1;
+ }
+
+ /* Must be a text symbol */
+ symtype = tolower(symtype);
+ if (symtype != 't' && symtype != 'w')
+ continue;
+
+ if (func_count == alloced) {
+ alloced += 256;
+ func_list = realloc(func_list,
+ sizeof(struct func_info) * alloced);
+ assert(func_list);
+ }
+ if (!func_count)
+ start = offset;
+
+ func = &func_list[func_count++];
+ memset(func, '\0', sizeof(*func));
+ func->offset = offset - start;
+ func->name = strdup(symname);
+ func->flags = FUNCF_TRACE; /* trace by default */
+
+ /* Update previous function's code size */
+ if (func_count > 1)
+ func[-1].code_size = func->offset - func[-1].offset;
+ }
+ notice("%d functions found in map file\n", func_count);
+ text_offset = start;
+ return 0;
+}
+
+static int read_data(FILE *fin, void *buff, int size)
+{
+ int err;
+
+ err = fread(buff, 1, size, fin);
+ if (!err)
+ return 1;
+ if (err != size) {
+ error("Cannot read profile file at pos %ld\n", ftell(fin));
+ return -1;
+ }
+ return 0;
+}
+
+static struct func_info *find_func_by_offset(uint32_t offset)
+{
+ struct func_info key, *found;
+
+ key.offset = offset;
+ found = bsearch(&key, func_list, func_count, sizeof(struct func_info),
+ h_cmp_offset);
+
+ return found;
+}
+
+/* This finds the function which contains the given offset */
+static struct func_info *find_caller_by_offset(uint32_t offset)
+{
+ int low; /* least function that could be a match */
+ int high; /* greated function that could be a match */
+ struct func_info key;
+
+ low = 0;
+ high = func_count - 1;
+ key.offset = offset;
+ while (high > low + 1) {
+ int mid = (low + high) / 2;
+ int result;
+
+ result = h_cmp_offset(&key, &func_list[mid]);
+ if (result > 0)
+ low = mid;
+ else if (result < 0)
+ high = mid;
+ else
+ return &func_list[mid];
+ }
+
+ return low >= 0 ? &func_list[low] : NULL;
+}
+
+static int read_calls(FILE *fin, int count)
+{
+ struct trace_call *call_data;
+ int i;
+
+ notice("call count: %d\n", count);
+ call_list = (struct trace_call *)calloc(count, sizeof(*call_data));
+ if (!call_list) {
+ error("Cannot allocate call_list\n");
+ return -1;
+ }
+ call_count = count;
+
+ call_data = call_list;
+ for (i = 0; i < count; i++, call_data++) {
+ if (read_data(fin, call_data, sizeof(*call_data)))
+ return 1;
+ }
+ return 0;
+}
+
+static int read_profile(FILE *fin, int *not_found)
+{
+ struct trace_output_hdr hdr;
+
+ *not_found = 0;
+ while (!feof(fin)) {
+ int err;
+
+ err = read_data(fin, &hdr, sizeof(hdr));
+ if (err == 1)
+ break; /* EOF */
+ else if (err)
+ return 1;
+
+ switch (hdr.type) {
+ case TRACE_CHUNK_FUNCS:
+ /* Ignored at present */
+ break;
+
+ case TRACE_CHUNK_CALLS:
+ if (read_calls(fin, hdr.rec_count))
+ return 1;
+ break;
+ }
+ }
+ return 0;
+}
+
+static int read_map_file(const char *fname)
+{
+ FILE *fmap;
+ int err = 0;
+
+ fmap = fopen(fname, "r");
+ if (!fmap) {
+ error("Cannot open map file '%s'\n", fname);
+ return 1;
+ }
+ if (fmap) {
+ err = read_system_map(fmap);
+ fclose(fmap);
+ }
+ return err;
+}
+
+static int read_profile_file(const char *fname)
+{
+ int not_found = INT_MAX;
+ FILE *fprof;
+ int err;
+
+ fprof = fopen(fname, "rb");
+ if (!fprof) {
+ error("Cannot open profile data file '%s'\n",
+ fname);
+ return 1;
+ } else {
+ err = read_profile(fprof, &not_found);
+ fclose(fprof);
+ if (err)
+ return err;
+
+ if (not_found) {
+ warn("%d profile functions could not be found in the map file - are you sure that your profile data and map file correspond?\n",
+ not_found);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int regex_report_error(regex_t *regex, int err, const char *op,
+ const char *name)
+{
+ char buf[200];
+
+ regerror(err, regex, buf, sizeof(buf));
+ error("Regex error '%s' in %s '%s'\n", buf, op, name);
+ return -1;
+}
+
+static void check_trace_config_line(struct trace_configline_info *item)
+{
+ struct func_info *func, *end;
+ int err;
+
+ debug("Checking trace config line '%s'\n", item->name);
+ for (func = func_list, end = func + func_count; func < end; func++) {
+ err = regexec(&item->regex, func->name, 0, NULL, 0);
+ debug(" - regex '%s', string '%s': %d\n", item->name,
+ func->name, err);
+ if (err == REG_NOMATCH)
+ continue;
+
+ if (err) {
+ regex_report_error(&item->regex, err, "match",
+ item->name);
+ break;
+ }
+
+ /* It matches, so perform the action */
+ switch (item->type) {
+ case TRACE_LINE_INCLUDE:
+ info(" include %s at %lx\n", func->name,
+ text_offset + func->offset);
+ func->flags |= FUNCF_TRACE;
+ break;
+
+ case TRACE_LINE_EXCLUDE:
+ info(" exclude %s at %lx\n", func->name,
+ text_offset + func->offset);
+ func->flags &= ~FUNCF_TRACE;
+ break;
+ }
+ }
+}
+
+static void check_trace_config(void)
+{
+ struct trace_configline_info *line;
+
+ for (line = trace_config_head; line; line = line->next)
+ check_trace_config_line(line);
+}
+
+/**
+ * Check the functions to see if they each have an objsection. If not, then
+ * the linker must have eliminated them.
+ */
+static void check_functions(void)
+{
+ struct func_info *func, *end;
+ unsigned long removed_code_size = 0;
+ int not_found = 0;
+
+ /* Look for missing functions */
+ for (func = func_list, end = func + func_count; func < end; func++) {
+ if (!func->objsection) {
+ removed_code_size += func->code_size;
+ not_found++;
+ }
+ }
+
+ /* Figure out what functions we want to trace */
+ check_trace_config();
+
+ warn("%d functions removed by linker, %ld code size\n",
+ not_found, removed_code_size);
+}
+
+static int read_trace_config(FILE *fin)
+{
+ char buff[200];
+ int linenum = 0;
+ struct trace_configline_info **tailp = &trace_config_head;
+
+ while (fgets(buff, sizeof(buff), fin)) {
+ int len = strlen(buff);
+ struct trace_configline_info *line;
+ char *saveptr;
+ char *s, *tok;
+ int err;
+
+ linenum++;
+ if (len && buff[len - 1] == '\n')
+ buff[len - 1] = '\0';
+
+ /* skip blank lines and comments */
+ for (s = buff; *s == ' ' || *s == '\t'; s++)
+ ;
+ if (!*s || *s == '#')
+ continue;
+
+ line = (struct trace_configline_info *)calloc(1,
+ sizeof(*line));
+ if (!line) {
+ error("Cannot allocate config line\n");
+ return -1;
+ }
+
+ tok = strtok_r(s, " \t", &saveptr);
+ if (!tok) {
+ error("Invalid trace config data on line %d\n",
+ linenum);
+ return -1;
+ }
+ if (0 == strcmp(tok, "include-func")) {
+ line->type = TRACE_LINE_INCLUDE;
+ } else if (0 == strcmp(tok, "exclude-func")) {
+ line->type = TRACE_LINE_EXCLUDE;
+ } else {
+ error("Unknown command in trace config data line %d\n",
+ linenum);
+ return -1;
+ }
+
+ tok = strtok_r(NULL, " \t", &saveptr);
+ if (!tok) {
+ error("Missing pattern in trace config data line %d\n",
+ linenum);
+ return -1;
+ }
+
+ err = regcomp(&line->regex, tok, REG_NOSUB);
+ if (err) {
+ free(line);
+ return regex_report_error(&line->regex, err, "compile",
+ tok);
+ }
+
+ /* link this new one to the end of the list */
+ line->name = strdup(tok);
+ line->next = NULL;
+ *tailp = line;
+ tailp = &line->next;
+ }
+
+ if (!feof(fin)) {
+ error("Cannot read from trace config file at position %ld\n",
+ ftell(fin));
+ return -1;
+ }
+ return 0;
+}
+
+static int read_trace_config_file(const char *fname)
+{
+ FILE *fin;
+ int err;
+
+ fin = fopen(fname, "r");
+ if (!fin) {
+ error("Cannot open trace_config file '%s'\n", fname);
+ return -1;
+ }
+ err = read_trace_config(fin);
+ fclose(fin);
+ return err;
+}
+
+static void out_func(ulong func_offset, int is_caller, const char *suffix)
+{
+ struct func_info *func;
+
+ func = (is_caller ? find_caller_by_offset : find_func_by_offset)
+ (func_offset);
+
+ if (func)
+ printf("%s%s", func->name, suffix);
+ else
+ printf("%lx%s", func_offset, suffix);
+}
+
+/*
+ * # tracer: function
+ * #
+ * # TASK-PID CPU# TIMESTAMP FUNCTION
+ * # | | | | |
+ * # bash-4251 [01] 10152.583854: path_put <-path_walk
+ * # bash-4251 [01] 10152.583855: dput <-path_put
+ * # bash-4251 [01] 10152.583855: _atomic_dec_and_lock <-dput
+ */
+static int make_ftrace(void)
+{
+ struct trace_call *call;
+ int missing_count = 0, skip_count = 0;
+ int i;
+
+ printf("# tracer: ftrace\n"
+ "#\n"
+ "# TASK-PID CPU# TIMESTAMP FUNCTION\n"
+ "# | | | | |\n");
+ for (i = 0, call = call_list; i < call_count; i++, call++) {
+ struct func_info *func = find_func_by_offset(call->func);
+ ulong time = call->flags & FUNCF_TIMESTAMP_MASK;
+
+ if (TRACE_CALL_TYPE(call) != FUNCF_ENTRY &&
+ TRACE_CALL_TYPE(call) != FUNCF_EXIT)
+ continue;
+ if (!func) {
+ warn("Cannot find function at %lx\n",
+ text_offset + call->func);
+ missing_count++;
+ continue;
+ }
+
+ if (!(func->flags & FUNCF_TRACE)) {
+ debug("Funcion '%s' is excluded from trace\n",
+ func->name);
+ skip_count++;
+ continue;
+ }
+
+ printf("%16s-%-5d [01] %lu.%06lu: ", "uboot", 1,
+ time / 1000000, time % 1000000);
+
+ out_func(call->func, 0, " <- ");
+ out_func(call->caller, 1, "\n");
+ }
+ info("ftrace: %d functions not found, %d excluded\n", missing_count,
+ skip_count);
+
+ return 0;
+}
+
+static int prof_tool(int argc, char * const argv[],
+ const char *prof_fname, const char *map_fname,
+ const char *trace_config_fname)
+{
+ int err = 0;
+
+ if (read_map_file(map_fname))
+ return -1;
+ if (prof_fname && read_profile_file(prof_fname))
+ return -1;
+ if (trace_config_fname && read_trace_config_file(trace_config_fname))
+ return -1;
+
+ check_functions();
+
+ for (; argc; argc--, argv++) {
+ const char *cmd = *argv;
+
+ if (0 == strcmp(cmd, "dump-ftrace"))
+ err = make_ftrace();
+ else
+ warn("Unknown command '%s'\n", cmd);
+ }
+
+ return err;
+}
+
+int main(int argc, char *argv[])
+{
+ const char *map_fname = "System.map";
+ const char *prof_fname = NULL;
+ const char *trace_config_fname = NULL;
+ int opt;
+
+ verbose = 2;
+ while ((opt = getopt(argc, argv, "m:p:t:v:")) != -1) {
+ switch (opt) {
+ case 'm':
+ map_fname = optarg;
+ break;
+
+ case 'p':
+ prof_fname = optarg;
+ break;
+
+ case 't':
+ trace_config_fname = optarg;
+ break;
+
+ case 'v':
+ verbose = atoi(optarg);
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc -= optind; argv += optind;
+ if (argc < 1)
+ usage();
+
+ debug("Debug enabled\n");
+ return prof_tool(argc, argv, prof_fname, map_fname,
+ trace_config_fname);
+}
diff --git a/tools/scripts/README b/tools/scripts/README
new file mode 100644
index 0000000..046c1d4
--- /dev/null
+++ b/tools/scripts/README
@@ -0,0 +1,67 @@
+#
+# (C) Copyright 2001
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# The files in this directory are free software; you can redistribute
+# them and/or modify them 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.
+#
+# These files are distributed in the hope that they 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+This directory contains scripts that help to perform certain actions
+that need to be done frequently when working with U-Boot.
+
+They are meant as EXAMPLE code, so it is very likely that you will
+have to modify them before use.
+
+
+Short description:
+==================
+
+dot.kermrc:
+
+ Example for "~/.kermrc" Kermit init file for use with U-Boot
+
+ by Wolfgang Denk, 24 Jun 2001
+
+flash_param:
+
+ "kermit" script to automatically initialize the environment
+ variables on your target. This is most useful during
+ development when your environment variables are stored in an
+ embedded flash sector which is erased whenever you install a
+ new U-Boot image.
+
+ by Swen Anderson, 10 May 2001
+
+send_cmd:
+
+ send_cmd U_BOOT_COMMAND
+
+ "kermit" script to send a U-Boot command and print the
+ results. When used from a shell with history (like the bash)
+ this indirectly adds kind of history to U-Boot ;-)
+
+ by Swen Anderson, 10 May 2001
+
+send_image:
+
+ send_image FILE_NAME OFFSET
+
+ "kermit" script to automatically download a file to the
+ target using the "loadb" command (kermit binary protocol)
+
+ by Swen Anderson, 10 May 2001
diff --git a/tools/scripts/define2mk.sed b/tools/scripts/define2mk.sed
new file mode 100644
index 0000000..c641edf
--- /dev/null
+++ b/tools/scripts/define2mk.sed
@@ -0,0 +1,35 @@
+#
+# Sed script to parse CPP macros and generate output usable by make
+#
+# It is expected that this script is fed the output of 'gpp -dM'
+# which preprocesses the common.h header files and outputs the final
+# list of CPP macros (and whitespace is sanitized)
+#
+
+# Only process values prefixed with #define CONFIG_
+/^#define CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*/ {
+ # Strip the #define prefix
+ s/#define *//;
+ # Change to form CONFIG_*=VALUE
+ s/ */=/;
+ # Drop trailing spaces
+ s/ *$//;
+ # drop quotes around string values
+ s/="\(.*\)"$/=\1/;
+ # Concatenate string values
+ s/" *"//g;
+ # Assume strings as default - add quotes around values
+ s/=\(..*\)/="\1"/;
+ # but remove again from decimal numbers
+ s/="\([0-9][0-9]*\)"/=\1/;
+ # ... and from hex numbers
+ s/="\(0[Xx][0-9a-fA-F][0-9a-fA-F]*\)"/=\1/;
+ # ... and from configs defined from other configs
+ s/="\(CONFIG_[A-Za-z0-9_][A-Za-z0-9_]*\)"/=$(\1)/;
+ # Change '1' and empty values to "y" (not perfect, but
+ # supports conditional compilation in the makefiles
+ s/=$/=y/;
+ s/=1$/=y/;
+ # print the line
+ p
+}
diff --git a/tools/scripts/dot.kermrc b/tools/scripts/dot.kermrc
new file mode 100644
index 0000000..0fc6c15
--- /dev/null
+++ b/tools/scripts/dot.kermrc
@@ -0,0 +1,16 @@
+set line /dev/ttyS0
+set speed 115200
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+define sz !sz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define rz !rz \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define sx !sx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
+define rx !rx \%1 \%2 \%3 \%4 \%5 \%6 \%7 \%8 \%9 < \v(line) > \v(line)
diff --git a/tools/scripts/flash_param b/tools/scripts/flash_param
new file mode 100644
index 0000000..847f99e
--- /dev/null
+++ b/tools/scripts/flash_param
@@ -0,0 +1,60 @@
+#!/usr/bin/kermit +
+# usage: ./flash_param parameters
+# Parameters: IP Address ETH Address ERIC Number
+# Format: xxx.xxx.xxx.xxx xx:xx:xx:xx:xx:xx xxxx
+
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+#set flow-control none
+set flow-control xon/xoff
+#robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+#robust
+# Milliseconds to pause between each OUTPUT character
+set output pacing 1
+
+out \13
+in 10 =>
+#first erase the environment memory within NVRAM
+out mw f0000000 0 200\13
+in 10 =>
+out reset\13
+in 5 autoboot
+out \13\13
+in 10 =>
+#set additional env parameter
+out setenv ethaddr \%2\13
+in 10 =>
+out setenv serial# ERIC 1.0 \%3\13
+in 10 =>
+out setenv eric_id \%3\13
+in 10 =>
+#out setenv prec_videocard_bus unknown\13
+#in 10 =>
+#out setenv prec_bios_type unknown\13
+#in 10 =>
+out setenv eric_passwd .eRIC.\13
+in 10 =>
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.1.100:192.168.1.254:255.255.255.0\13
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1:192.168.0.1\13
+#out setenv bootargs root=/dev/ram ramdisk_size=8192 init=/sbin/init ip=\%1\13
+out setenv bootargs console=/dev/ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.26:/eric_root_devel ip=\%1:192.168.1.26\13
+in 10 =>
+out setenv bootcmd bootm FFC00000\13
+in 10 =>
+out saveenv\13
+in 10 =>
+out reset\13
+in 5 autoboot
+out \13\13
+in 10 =>
+quit
+exit 0
diff --git a/tools/scripts/make-asm-offsets b/tools/scripts/make-asm-offsets
new file mode 100755
index 0000000..4c33756
--- /dev/null
+++ b/tools/scripts/make-asm-offsets
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# Adapted from Linux kernel's "Kbuild":
+# commit 1cdf25d704f7951d02a04064c97db547d6021872
+# Author: Christoph Lameter <clameter@sgi.com>
+
+mkdir -p $(dirname $2)
+
+# Default sed regexp - multiline due to syntax constraints
+SED_CMD="/^->/{s:->#\(.*\):/* \1 */:; \
+ s:^->\([^ ]*\) [\$#]*\([-0-9]*\) \(.*\):#define \1 (\2) /* \3 */:; \
+ s:^->\([^ ]*\) [\$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \
+ s:->::; p;}"
+
+(set -e
+ echo "#ifndef __ASM_OFFSETS_H__"
+ echo "#define __ASM_OFFSETS_H__"
+ echo "/*"
+ echo " * DO NOT MODIFY."
+ echo " *"
+ echo " * This file was generated by $(basename $0)"
+ echo " *"
+ echo " */"
+ echo ""
+ sed -ne "${SED_CMD}" $1
+ echo ""
+ echo "#endif" ) > $2
diff --git a/tools/scripts/send_cmd b/tools/scripts/send_cmd
new file mode 100644
index 0000000..4131331
--- /dev/null
+++ b/tools/scripts/send_cmd
@@ -0,0 +1,21 @@
+#!/usr/bin/kermit +
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+
+#out \13
+#in 10 =>
+out \%1 \%2 \%3 \%4 \%5 \%6 \%7\13
+in 10 =>
+quit
+exit 0
diff --git a/tools/scripts/send_image b/tools/scripts/send_image
new file mode 100644
index 0000000..9b89d6b
--- /dev/null
+++ b/tools/scripts/send_image
@@ -0,0 +1,26 @@
+#!/usr/bin/kermit +
+# usage: send_image FILE_NAME OFFSET
+# e.g. send_image output.bin 1F00000
+set line /dev/ttyS0
+set speed 115200
+set serial 8N1
+set carrier-watch off
+set handshake none
+set flow-control none
+robust
+set file type bin
+set file name lit
+set rec pack 1000
+set send pack 1000
+set window 5
+set prompt Kermit>
+
+out \13
+in 10 =>
+out loadb \%2 \13
+in 10 download ...
+send \%1
+out \13
+in 10 ## Start Addr
+quit
+exit 0
diff --git a/tools/setlocalversion b/tools/setlocalversion
new file mode 100755
index 0000000..f551b4c
--- /dev/null
+++ b/tools/setlocalversion
@@ -0,0 +1,177 @@
+#!/bin/sh
+#
+# This scripts adds local version information from the version
+# control systems git, mercurial (hg) and subversion (svn).
+#
+# It was originally copied from the Linux kernel v3.2.0-rc4 and modified
+# to support the U-Boot build-system.
+#
+
+usage() {
+ echo "Usage: $0 [--save-scmversion] [srctree]" >&2
+ exit 1
+}
+
+scm_only=false
+srctree=.
+if test "$1" = "--save-scmversion"; then
+ scm_only=true
+ shift
+fi
+if test $# -gt 0; then
+ srctree=$1
+ shift
+fi
+if test $# -gt 0 -o ! -d "$srctree"; then
+ usage
+fi
+
+scm_version()
+{
+ local short
+ short=false
+
+ cd "$srctree"
+ if test -e .scmversion; then
+ cat .scmversion
+ return
+ fi
+ if test "$1" = "--short"; then
+ short=true
+ fi
+
+ # Check for git and a git repo.
+ if test -e .git && head=`git rev-parse --verify --short 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 only the short version is requested, don't bother
+ # running further git commands
+ if $short; then
+ echo "+"
+ return
+ 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
+ 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`"
+ 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 -v "^scripts/package" \
+ | 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
+
+ for file; do
+ case "$file" in
+ *\~*)
+ continue
+ ;;
+ esac
+ if test -e "$file"; then
+ res="$res$(cat "$file")"
+ fi
+ done
+ echo "$res"
+}
+
+if $scm_only; then
+ if test ! -e .scmversion; then
+ res=$(scm_version)
+ echo "$res" >.scmversion
+ fi
+ 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"
+# exit 1
+#fi
+CONFIG_LOCALVERSION=
+CONFIG_LOCALVERSION_AUTO=y
+
+# localversion* files in the build and source directory
+res="$(collect_files localversion*)"
+if test ! "$srctree" -ef .; then
+ res="$res$(collect_files "$srctree"/localversion*)"
+fi
+
+# CONFIG_LOCALVERSION and LOCALVERSION (if set)
+res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}"
+
+# scm version string if not at a tagged commit
+if test "$CONFIG_LOCALVERSION_AUTO" = "y"; 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
+fi
+
+echo "$res"
diff --git a/tools/ublimage.c b/tools/ublimage.c
new file mode 100644
index 0000000..d6b4017
--- /dev/null
+++ b/tools/ublimage.c
@@ -0,0 +1,280 @@
+/*
+ * (C) Copyright 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Based on:
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
+ *
+ * (C) Copyright 2008
+ * Marvell Semiconductor <www.marvell.com>
+ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
+ *
+ * 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.
+ *
+ * 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/* Required to obtain the getline prototype from stdio.h */
+#define _GNU_SOURCE
+
+#include "mkimage.h"
+#include <image.h>
+#include "ublimage.h"
+
+/*
+ * Supported commands for configuration file
+ */
+static table_entry_t ublimage_cmds[] = {
+ {CMD_BOOT_MODE, "MODE", "UBL special modes", },
+ {CMD_ENTRY, "ENTRY", "Entry point addr for bootloader", },
+ {CMD_PAGE, "PAGES",
+ "number of pages (size of bootloader)", },
+ {CMD_ST_BLOCK, "START_BLOCK",
+ "block number where bootloader is present", },
+ {CMD_ST_PAGE, "START_PAGE",
+ "page number where bootloader is present", },
+ {CMD_LD_ADDR, "LD_ADDR",
+ "load addr", },
+ {-1, "", "", },
+};
+
+/*
+ * Supported Boot options for configuration file
+ * this is needed to set the correct flash offset
+ */
+static table_entry_t ublimage_bootops[] = {
+ {UBL_MAGIC_SAFE, "safe", "Safe boot mode", },
+ {-1, "", "Invalid", },
+};
+
+static struct ubl_header ublimage_header;
+
+static uint32_t get_cfg_value(char *token, char *name, int linenr)
+{
+ char *endptr;
+ uint32_t value;
+
+ errno = 0;
+ value = strtoul(token, &endptr, 16);
+ if (errno || (token == endptr)) {
+ fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n",
+ name, linenr, token);
+ exit(EXIT_FAILURE);
+ }
+ return value;
+}
+
+static void print_hdr(struct ubl_header *ubl_hdr)
+{
+ printf("Image Type : Davinci UBL Boot Image\n");
+ printf("UBL magic : %08x\n", ubl_hdr->magic);
+ printf("Entry Point: %08x\n", ubl_hdr->entry);
+ printf("nr of pages: %08x\n", ubl_hdr->pages);
+ printf("start block: %08x\n", ubl_hdr->block);
+ printf("start page : %08x\n", ubl_hdr->page);
+}
+
+static void parse_cfg_cmd(struct ubl_header *ublhdr, int32_t cmd, char *token,
+ char *name, int lineno, int fld, int dcd_len)
+{
+ static int cmd_ver_first = ~0;
+
+ switch (cmd) {
+ case CMD_BOOT_MODE:
+ ublhdr->magic = get_table_entry_id(ublimage_bootops,
+ "ublimage special boot mode", token);
+ if (ublhdr->magic == -1) {
+ fprintf(stderr, "Error: %s[%d] -Invalid boot mode"
+ "(%s)\n", name, lineno, token);
+ exit(EXIT_FAILURE);
+ }
+ ublhdr->magic += UBL_MAGIC_BASE;
+ if (unlikely(cmd_ver_first != 1))
+ cmd_ver_first = 0;
+ break;
+ case CMD_ENTRY:
+ ublhdr->entry = get_cfg_value(token, name, lineno);
+ break;
+ case CMD_PAGE:
+ ublhdr->pages = get_cfg_value(token, name, lineno);
+ break;
+ case CMD_ST_BLOCK:
+ ublhdr->block = get_cfg_value(token, name, lineno);
+ break;
+ case CMD_ST_PAGE:
+ ublhdr->page = get_cfg_value(token, name, lineno);
+ break;
+ case CMD_LD_ADDR:
+ ublhdr->pll_m = get_cfg_value(token, name, lineno);
+ break;
+ }
+}
+
+static void parse_cfg_fld(struct ubl_header *ublhdr, int32_t *cmd,
+ char *token, char *name, int lineno, int fld, int *dcd_len)
+{
+
+ switch (fld) {
+ case CFG_COMMAND:
+ *cmd = get_table_entry_id(ublimage_cmds,
+ "ublimage commands", token);
+ if (*cmd < 0) {
+ fprintf(stderr, "Error: %s[%d] - Invalid command"
+ "(%s)\n", name, lineno, token);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case CFG_REG_VALUE:
+ parse_cfg_cmd(ublhdr, *cmd, token, name, lineno, fld, *dcd_len);
+ break;
+ default:
+ break;
+ }
+}
+static uint32_t parse_cfg_file(struct ubl_header *ublhdr, char *name)
+{
+ FILE *fd = NULL;
+ char *line = NULL;
+ char *token, *saveptr1, *saveptr2;
+ int lineno = 0;
+ int i;
+ char *ptr = (char *)ublhdr;
+ int fld;
+ size_t len;
+ int dcd_len = 0;
+ int32_t cmd;
+ int ublhdrlen = sizeof(struct ubl_header);
+
+ fd = fopen(name, "r");
+ if (fd == 0) {
+ fprintf(stderr, "Error: %s - Can't open DCD file\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Fill header with 0xff */
+ for (i = 0; i < ublhdrlen; i++) {
+ *ptr = 0xff;
+ ptr++;
+ }
+
+ /*
+ * Very simple parsing, line starting with # are comments
+ * and are dropped
+ */
+ while ((getline(&line, &len, fd)) > 0) {
+ lineno++;
+
+ token = strtok_r(line, "\r\n", &saveptr1);
+ if (token == NULL)
+ continue;
+
+ /* Check inside the single line */
+ for (fld = CFG_COMMAND, cmd = CMD_INVALID,
+ line = token; ; line = NULL, fld++) {
+ token = strtok_r(line, " \t", &saveptr2);
+ if (token == NULL)
+ break;
+
+ /* Drop all text starting with '#' as comments */
+ if (token[0] == '#')
+ break;
+
+ parse_cfg_fld(ublhdr, &cmd, token, name,
+ lineno, fld, &dcd_len);
+ }
+ }
+ fclose(fd);
+
+ return dcd_len;
+}
+
+static int ublimage_check_image_types(uint8_t type)
+{
+ if (type == IH_TYPE_UBLIMAGE)
+ return EXIT_SUCCESS;
+ else
+ return EXIT_FAILURE;
+}
+
+static int ublimage_verify_header(unsigned char *ptr, int image_size,
+ struct mkimage_params *params)
+{
+ struct ubl_header *ubl_hdr = (struct ubl_header *)ptr;
+
+ if ((ubl_hdr->magic & 0xFFFFFF00) != UBL_MAGIC_BASE)
+ return -1;
+
+ return 0;
+}
+
+static void ublimage_print_header(const void *ptr)
+{
+ struct ubl_header *ubl_hdr = (struct ubl_header *) ptr;
+
+ print_hdr(ubl_hdr);
+}
+
+static void ublimage_set_header(void *ptr, struct stat *sbuf, int ifd,
+ struct mkimage_params *params)
+{
+ struct ubl_header *ublhdr = (struct ubl_header *)ptr;
+
+ /* Parse configuration file */
+ parse_cfg_file(ublhdr, params->imagename);
+}
+
+int ublimage_check_params(struct mkimage_params *params)
+{
+ if (!params)
+ return CFG_INVALID;
+ if (!strlen(params->imagename)) {
+ fprintf(stderr, "Error: %s - Configuration file not"
+ "specified, it is needed for ublimage generation\n",
+ params->cmdname);
+ return CFG_INVALID;
+ }
+ /*
+ * Check parameters:
+ * XIP is not allowed and verify that incompatible
+ * parameters are not sent at the same time
+ * For example, if list is required a data image must not be provided
+ */
+ return (params->dflag && (params->fflag || params->lflag)) ||
+ (params->fflag && (params->dflag || params->lflag)) ||
+ (params->lflag && (params->dflag || params->fflag)) ||
+ (params->xflag) || !(strlen(params->imagename));
+}
+
+/*
+ * ublimage parameters
+ */
+static struct image_type_params ublimage_params = {
+ .name = "Davinci UBL boot support",
+ .header_size = sizeof(struct ubl_header),
+ .hdr = (void *)&ublimage_header,
+ .check_image_type = ublimage_check_image_types,
+ .verify_header = ublimage_verify_header,
+ .print_header = ublimage_print_header,
+ .set_header = ublimage_set_header,
+ .check_params = ublimage_check_params,
+};
+
+void init_ubl_image_type(void)
+{
+ mkimage_register(&ublimage_params);
+}
diff --git a/tools/ublimage.h b/tools/ublimage.h
new file mode 100644
index 0000000..e440625
--- /dev/null
+++ b/tools/ublimage.h
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2011
+ * Heiko Schocher, DENX Software Engineering, hs@denx.de.
+ *
+ * Vased on:
+ * (C) Copyright 2009
+ * Stefano Babic, DENX Software Engineering, sbabic@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef _UBLIMAGE_H_
+#define _UBLIMAGE_H_
+
+enum ublimage_cmd {
+ CMD_INVALID,
+ CMD_BOOT_MODE,
+ CMD_ENTRY,
+ CMD_PAGE,
+ CMD_ST_BLOCK,
+ CMD_ST_PAGE,
+ CMD_LD_ADDR
+};
+
+enum ublimage_fld_types {
+ CFG_INVALID = -1,
+ CFG_COMMAND,
+ CFG_REG_VALUE
+};
+
+/*
+ * from sprufg5a.pdf Table 110
+ * Used by RBL when doing NAND boot
+ */
+#define UBL_MAGIC_BASE (0xA1ACED00)
+/* Safe boot mode */
+#define UBL_MAGIC_SAFE (0x00)
+/* DMA boot mode */
+#define UBL_MAGIC_DMA (0x11)
+/* I Cache boot mode */
+#define UBL_MAGIC_IC (0x22)
+/* Fast EMIF boot mode */
+#define UBL_MAGIC_FAST (0x33)
+/* DMA + ICache boot mode */
+#define UBL_MAGIC_DMA_IC (0x44)
+/* DMA + ICache + Fast EMIF boot mode */
+#define UBL_MAGIC_DMA_IC_FAST (0x55)
+
+/* Define max UBL image size */
+#define UBL_IMAGE_SIZE (0x00003800u)
+
+/* one NAND block */
+#define UBL_BLOCK_SIZE 2048
+
+/* from sprufg5a.pdf Table 109 */
+struct ubl_header {
+ uint32_t magic; /* Magic Number, see UBL_* defines */
+ uint32_t entry; /* entry point address for bootloader */
+ uint32_t pages; /* number of pages (size of bootloader) */
+ uint32_t block; /*
+ * blocknumber where user bootloader is
+ * present
+ */
+ uint32_t page; /*
+ * page number where user bootloader is
+ * present.
+ */
+ uint32_t pll_m; /*
+ * PLL setting -Multiplier (only valid if
+ * Magic Number indicates PLL enable).
+ */
+ uint32_t pll_n; /*
+ * PLL setting -Divider (only valid if
+ * Magic Number indicates PLL enable).
+ */
+ uint32_t emif; /*
+ * fast EMIF setting (only valid if
+ * Magic Number indicates fast EMIF boot).
+ */
+ /* to fit in one nand block */
+ unsigned char res[UBL_BLOCK_SIZE - 8 * 4];
+};
+
+#endif /* _UBLIMAGE_H_ */
diff --git a/tools/ubsha1.c b/tools/ubsha1.c
new file mode 100644
index 0000000..625e13f
--- /dev/null
+++ b/tools/ubsha1.c
@@ -0,0 +1,100 @@
+/*
+ * (C) Copyright 2007
+ * Heiko Schocher, DENX Software Engineering, <hs@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "os_support.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "sha1.h"
+
+int main (int argc, char **argv)
+{
+ unsigned char output[20];
+ int i, len;
+
+ char *imagefile;
+ char *cmdname = *argv;
+ unsigned char *ptr;
+ unsigned char *data;
+ struct stat sbuf;
+ unsigned char *ptroff;
+ int ifd;
+ int off;
+
+ if (argc > 1) {
+ imagefile = argv[1];
+ ifd = open (imagefile, O_RDWR|O_BINARY);
+ if (ifd < 0) {
+ fprintf (stderr, "%s: Can't open %s: %s\n",
+ cmdname, imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+ if (fstat (ifd, &sbuf) < 0) {
+ fprintf (stderr, "%s: Can't stat %s: %s\n",
+ cmdname, imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+ len = sbuf.st_size;
+ ptr = (unsigned char *)mmap(0, len,
+ PROT_READ, MAP_SHARED, ifd, 0);
+ if (ptr == (unsigned char *)MAP_FAILED) {
+ fprintf (stderr, "%s: Can't read %s: %s\n",
+ cmdname, imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ /* create a copy, so we can blank out the sha1 sum */
+ data = malloc (len);
+ memcpy (data, ptr, len);
+ off = SHA1_SUM_POS;
+ ptroff = &data[len + off];
+ for (i = 0; i < SHA1_SUM_LEN; i++) {
+ ptroff[i] = 0;
+ }
+
+ sha1_csum ((unsigned char *) data, len, (unsigned char *)output);
+
+ printf ("U-Boot sum:\n");
+ for (i = 0; i < 20 ; i++) {
+ printf ("%02X ", output[i]);
+ }
+ printf ("\n");
+ /* overwrite the sum in the bin file, with the actual */
+ lseek (ifd, SHA1_SUM_POS, SEEK_END);
+ if (write (ifd, output, SHA1_SUM_LEN) != SHA1_SUM_LEN) {
+ fprintf (stderr, "%s: Can't write %s: %s\n",
+ cmdname, imagefile, strerror(errno));
+ exit (EXIT_FAILURE);
+ }
+
+ free (data);
+ (void) munmap((void *)ptr, len);
+ (void) close (ifd);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/updater/Makefile b/tools/updater/Makefile
new file mode 100644
index 0000000..e9684cb
--- /dev/null
+++ b/tools/updater/Makefile
@@ -0,0 +1,105 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+LOAD_ADDR = 0x40000
+
+include $(TOPDIR)/config.mk
+
+PROG = $(obj)updater
+IMAGE = $(obj)updater.image
+
+COBJS = update.o flash.o flash_hw.o utils.o cmd_flash.o string.o ctype.o dummy.o
+COBJS_LINKS = stubs.o
+AOBJS = ppcstring.o
+AOBJS_LINKS = memio.o
+
+OBJS := $(addprefix $(obj),$(COBJS) $(COBJS_LINKS) $(AOBJS) $(AOBJS_LINKS))
+SRCS := $(COBJS:.o=.c) $(AOBJS:.o=.S) $(addprefix $(obj), $(COBJS_LINKS:.o:.c) $(AOBJS_LINKS:.o:.S))
+
+CPPFLAGS += -I$(TOPDIR) -I$(TOPDIR)/board/MAI/AmigaOneG3SE
+CFLAGS += -I$(TOPDIR)/board/MAI/AmigaOneG3SE
+AFLAGS += -I$(TOPDIR)/board/MAI/AmigaOneG3SE
+
+DEPS = $(OBJTREE)/u-boot.bin $(OBJTREE)/tools/mkimage
+ifneq ($(DEPS),$(wildcard $(DEPS)))
+$(error "updater: Missing required objects, please run regular build first")
+endif
+
+all: $(obj).depend $(PROG) $(IMAGE)
+
+#########################################################################
+
+$(obj)%.srec: %.o $(LIB)
+ $(LD) -g -Ttext $(LOAD_ADDR) -o $(<:.o=) -e $(<:.o=) $< $(LIB)
+ $(OBJCOPY) -O srec $(<:.o=) $@
+
+$(obj)%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(obj)%.o: %.S
+ $(CC) $(AFLAGS) -c -o $@ $<
+
+$(obj)memio.o: $(obj)memio.S
+ $(CC) $(AFLAGS) -c -o $@ $<
+
+$(obj)memio.S:
+ rm -f $(obj)memio.c
+ ln -s $(SRCTREE)/board/MAI/AmigaOneG3SE/memio.S $(obj)memio.S
+
+$(obj)stubs.o: $(obj)stubs.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+$(obj)stubs.c:
+ rm -f $(obj)stubs.c
+ ln -s $(SRCTREE)/examples/stubs.c $(obj)stubs.c
+
+#########################################################################
+
+$(obj)updater: $(OBJS)
+ $(LD) -g -Ttext $(LOAD_ADDR) -o $(obj)updater -e _main $(OBJS)
+ $(OBJCOPY) -O binary $(obj)updater $(obj)updater.bin
+
+$(obj)updater.image: $(obj)updater $(OBJTREE)/u-boot.bin
+ cat >/tmp/tempimage $(obj)updater.bin junk $(OBJTREE)/u-boot.bin
+ $(OBJTREE)/tools/mkimage -A ppc -O u-boot -T standalone -C none -a $(LOAD_ADDR) \
+ -e `$(NM) $(obj)updater | grep _main | cut --bytes=0-8` \
+ -n "Firmware Updater" -d /tmp/tempimage $(obj)updater.image
+ rm /tmp/tempimage
+ cp $(obj)updater.image /tftpboot
+
+(obj)updater.image2: $(obj)updater $(OBJTREE)/u-boot.bin
+ cat >/tmp/tempimage $(obj)updater.bin junk ../../create_image/image
+ $(OBJTREE)/tools/mkimage -A ppc -O u-boot -T standalone -C none -a $(LOAD_ADDR) \
+ -e `$(NM) $(obj)updater | grep _main | cut --bytes=0-8` \
+ -n "Firmware Updater" -d /tmp/tempimage $(obj)updater.image
+ rm /tmp/tempimage
+ cp $(obj)updater.image /tftpboot
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/tools/updater/cmd_flash.c b/tools/updater/cmd_flash.c
new file mode 100644
index 0000000..957a7c4
--- /dev/null
+++ b/tools/updater/cmd_flash.c
@@ -0,0 +1,417 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * FLASH support
+ */
+#include <common.h>
+#include <command.h>
+#include <flash.h>
+
+#if defined(CONFIG_CMD_FLASH)
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*
+ * The user interface starts numbering for Flash banks with 1
+ * for historical reasons.
+ */
+
+/*
+ * this routine looks for an abbreviated flash range specification.
+ * the syntax is B:SF[-SL], where B is the bank number, SF is the first
+ * sector to erase, and SL is the last sector to erase (defaults to SF).
+ * bank numbers start at 1 to be consistent with other specs, sector numbers
+ * start at zero.
+ *
+ * returns: 1 - correct spec; *pinfo, *psf and *psl are
+ * set appropriately
+ * 0 - doesn't look like an abbreviated spec
+ * -1 - looks like an abbreviated spec, but got
+ * a parsing error, a number out of range,
+ * or an invalid flash bank.
+ */
+static int
+abbrev_spec(char *str, flash_info_t **pinfo, int *psf, int *psl)
+{
+ flash_info_t *fp;
+ int bank, first, last;
+ char *p, *ep;
+
+ if ((p = strchr(str, ':')) == NULL)
+ return 0;
+ *p++ = '\0';
+
+ bank = simple_strtoul(str, &ep, 10);
+ if (ep == str || *ep != '\0' ||
+ bank < 1 || bank > CONFIG_SYS_MAX_FLASH_BANKS ||
+ (fp = &flash_info[bank - 1])->flash_id == FLASH_UNKNOWN)
+ return -1;
+
+ str = p;
+ if ((p = strchr(str, '-')) != NULL)
+ *p++ = '\0';
+
+ first = simple_strtoul(str, &ep, 10);
+ if (ep == str || *ep != '\0' || first >= fp->sector_count)
+ return -1;
+
+ if (p != NULL) {
+ last = simple_strtoul(p, &ep, 10);
+ if (ep == p || *ep != '\0' ||
+ last < first || last >= fp->sector_count)
+ return -1;
+ }
+ else
+ last = first;
+
+ *pinfo = fp;
+ *psf = first;
+ *psl = last;
+
+ return 1;
+}
+int do_flinfo (cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+ ulong bank;
+
+ if (argc == 1) { /* print info for all FLASH banks */
+ for (bank=0; bank <CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ printf ("\nBank # %ld: ", bank+1);
+
+ flash_print_info (&flash_info[bank]);
+ }
+ return 0;
+ }
+
+ bank = simple_strtoul(argv[1], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("\nBank # %ld: ", bank);
+ flash_print_info (&flash_info[bank-1]);
+ return 0;
+}
+int do_flerase(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+ flash_info_t *info;
+ ulong bank, addr_first, addr_last;
+ int n, sect_first, sect_last;
+ int rcode = 0;
+
+ if (argc < 2)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "all") == 0) {
+ for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ printf ("Erase Flash Bank # %ld ", bank);
+ info = &flash_info[bank-1];
+ rcode = flash_erase (info, 0, info->sector_count-1);
+ }
+ return rcode;
+ }
+
+ if ((n = abbrev_spec(argv[1], &info, &sect_first, &sect_last)) != 0) {
+ if (n < 0) {
+ printf("Bad sector specification\n");
+ return 1;
+ }
+ printf ("Erase Flash Sectors %d-%d in Bank # %d ",
+ sect_first, sect_last, (info-flash_info)+1);
+ rcode = flash_erase(info, sect_first, sect_last);
+ return rcode;
+ }
+
+ if (argc != 3)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "bank") == 0) {
+ bank = simple_strtoul(argv[2], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("Erase Flash Bank # %ld ", bank);
+ info = &flash_info[bank-1];
+ rcode = flash_erase (info, 0, info->sector_count-1);
+ return rcode;
+ }
+
+ addr_first = simple_strtoul(argv[1], NULL, 16);
+ addr_last = simple_strtoul(argv[2], NULL, 16);
+
+ if (addr_first >= addr_last)
+ return cmd_usage(cmdtp);
+
+ printf ("Erase Flash from 0x%08lx to 0x%08lx ", addr_first, addr_last);
+ rcode = flash_sect_erase(addr_first, addr_last);
+ return rcode;
+}
+
+int flash_sect_erase (ulong addr_first, ulong addr_last)
+{
+ flash_info_t *info;
+ ulong bank;
+ int s_first, s_last;
+ int erased;
+ int rcode = 0;
+
+ erased = 0;
+
+ for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
+ ulong b_end;
+ int sect;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+
+ b_end = info->start[0] + info->size - 1; /* bank end addr */
+
+ s_first = -1; /* first sector to erase */
+ s_last = -1; /* last sector to erase */
+
+ for (sect=0; sect < info->sector_count; ++sect) {
+ ulong end; /* last address in current sect */
+ short s_end;
+
+ s_end = info->sector_count - 1;
+
+ end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+ if (addr_first > end)
+ continue;
+ if (addr_last < info->start[sect])
+ continue;
+
+ if (addr_first == info->start[sect]) {
+ s_first = sect;
+ }
+ if (addr_last == end) {
+ s_last = sect;
+ }
+ }
+ if (s_first>=0 && s_first<=s_last) {
+ erased += s_last - s_first + 1;
+ rcode = flash_erase (info, s_first, s_last);
+ }
+ }
+ if (erased) {
+ /* printf ("Erased %d sectors\n", erased); */
+ } else {
+ printf ("Error: start and/or end address"
+ " not on sector boundary\n");
+ rcode = 1;
+ }
+ return rcode;
+}
+
+
+int do_protect(cmd_tbl_t *cmdtp, bd_t *bd, int flag, int argc, char *argv[])
+{
+ flash_info_t *info;
+ ulong bank, addr_first, addr_last;
+ int i, p, n, sect_first, sect_last;
+ int rcode = 0;
+
+ if (argc < 3)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[1], "off") == 0)
+ p = 0;
+ else if (strcmp(argv[1], "on") == 0)
+ p = 1;
+ else
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[2], "all") == 0) {
+ for (bank=1; bank<=CONFIG_SYS_MAX_FLASH_BANKS; ++bank) {
+ info = &flash_info[bank-1];
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+ /*printf ("%sProtect Flash Bank # %ld\n", */
+ /* p ? "" : "Un-", bank); */
+
+ for (i=0; i<info->sector_count; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ }
+
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ return rcode;
+ }
+
+ if ((n = abbrev_spec(argv[2], &info, &sect_first, &sect_last)) != 0) {
+ if (n < 0) {
+ printf("Bad sector specification\n");
+ return 1;
+ }
+ /*printf("%sProtect Flash Sectors %d-%d in Bank # %d\n", */
+ /* p ? "" : "Un-", sect_first, sect_last, */
+ /* (info-flash_info)+1); */
+ for (i = sect_first; i <= sect_last; i++) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) puts (" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ return rcode;
+ }
+
+ if (argc != 4)
+ return cmd_usage(cmdtp);
+
+ if (strcmp(argv[2], "bank") == 0) {
+ bank = simple_strtoul(argv[3], NULL, 16);
+ if ((bank < 1) || (bank > CONFIG_SYS_MAX_FLASH_BANKS)) {
+ printf ("Only FLASH Banks # 1 ... # %d supported\n",
+ CONFIG_SYS_MAX_FLASH_BANKS);
+ return 1;
+ }
+ printf ("%sProtect Flash Bank # %ld\n",
+ p ? "" : "Un-", bank);
+ info = &flash_info[bank-1];
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return 1;
+ }
+ for (i=0; i<info->sector_count; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode)
+ puts(" done\n");
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ return rcode;
+ }
+
+ addr_first = simple_strtoul(argv[2], NULL, 16);
+ addr_last = simple_strtoul(argv[3], NULL, 16);
+
+ if (addr_first >= addr_last)
+ return cmd_usage(cmdtp);
+
+ return flash_sect_protect (p, addr_first, addr_last);
+}
+int flash_sect_protect (int p, ulong addr_first, ulong addr_last)
+{
+ flash_info_t *info;
+ ulong bank;
+ int s_first, s_last;
+ int protected, i;
+ int rcode = 0;
+
+ protected = 0;
+
+ for (bank=0,info = &flash_info[0]; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank, ++info) {
+ ulong b_end;
+ int sect;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ continue;
+ }
+
+ b_end = info->start[0] + info->size - 1; /* bank end addr */
+
+ s_first = -1; /* first sector to erase */
+ s_last = -1; /* last sector to erase */
+
+ for (sect=0; sect < info->sector_count; ++sect) {
+ ulong end; /* last address in current sect */
+ short s_end;
+
+ s_end = info->sector_count - 1;
+
+ end = (sect == s_end) ? b_end : info->start[sect + 1] - 1;
+
+ if (addr_first > end)
+ continue;
+ if (addr_last < info->start[sect])
+ continue;
+
+ if (addr_first == info->start[sect]) {
+ s_first = sect;
+ }
+ if (addr_last == end) {
+ s_last = sect;
+ }
+ }
+ if (s_first>=0 && s_first<=s_last) {
+ protected += s_last - s_first + 1;
+ for (i=s_first; i<=s_last; ++i) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (flash_real_protect(info, i, p))
+ rcode = 1;
+ putc ('.');
+#else
+ info->protect[i] = p;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ }
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ if (!rcode) putc ('\n');
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+
+ }
+ if (protected) {
+ /* printf ("%sProtected %d sectors\n", */
+ /* p ? "" : "Un-", protected); */
+ } else {
+ printf ("Error: start and/or end address"
+ " not on sector boundary\n");
+ rcode = 1;
+ }
+ return rcode;
+}
+
+#endif
diff --git a/tools/updater/ctype.c b/tools/updater/ctype.c
new file mode 100644
index 0000000..6ed0468
--- /dev/null
+++ b/tools/updater/ctype.c
@@ -0,0 +1,56 @@
+/*
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+/*
+ * linux/lib/ctype.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#include <linux/ctype.h>
+
+unsigned char _ctype[] = {
+_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
+_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
+_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
+_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
+_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
+_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
+_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
+_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
+_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
+_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
+_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
+_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
+_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
+_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
+_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
+_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
+_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
+_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
diff --git a/tools/updater/dummy.c b/tools/updater/dummy.c
new file mode 100644
index 0000000..9fe5ac1
--- /dev/null
+++ b/tools/updater/dummy.c
@@ -0,0 +1 @@
+volatile int __dummy = 0xDEADBEEF;
diff --git a/tools/updater/flash.c b/tools/updater/flash.c
new file mode 100644
index 0000000..5be5f1b
--- /dev/null
+++ b/tools/updater/flash.c
@@ -0,0 +1,184 @@
+/*
+ * (C) Copyright 2000-2006
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <flash.h>
+
+extern flash_info_t flash_info[]; /* info for FLASH chips */
+
+/*-----------------------------------------------------------------------
+ * Functions
+ */
+
+/*-----------------------------------------------------------------------
+ * Set protection status for monitor sectors
+ *
+ * The monitor is always located in the _first_ Flash bank.
+ * If necessary you have to map the second bank at lower addresses.
+ */
+void
+flash_protect (int flag, ulong from, ulong to, flash_info_t *info)
+{
+ ulong b_end = info->start[0] + info->size - 1; /* bank end address */
+ short s_end = info->sector_count - 1; /* index of last sector */
+ int i;
+
+ /* Do nothing if input data is bad. */
+ if (info->sector_count == 0 || info->size == 0 || to < from) {
+ return;
+ }
+
+ /* There is nothing to do if we have no data about the flash
+ * or the protect range and flash range don't overlap.
+ */
+ if (info->flash_id == FLASH_UNKNOWN ||
+ to < info->start[0] || from > b_end) {
+ return;
+ }
+
+ for (i=0; i<info->sector_count; ++i) {
+ ulong end; /* last address in current sect */
+
+ end = (i == s_end) ? b_end : info->start[i + 1] - 1;
+
+ /* Update protection if any part of the sector
+ * is in the specified range.
+ */
+ if (from <= end && to >= info->start[i]) {
+ if (flag & FLAG_PROTECT_CLEAR) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 0);
+#else
+ info->protect[i] = 0;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ else if (flag & FLAG_PROTECT_SET) {
+#if defined(CONFIG_SYS_FLASH_PROTECTION)
+ flash_real_protect(info, i, 1);
+#else
+ info->protect[i] = 1;
+#endif /* CONFIG_SYS_FLASH_PROTECTION */
+ }
+ }
+ }
+}
+
+/*-----------------------------------------------------------------------
+ */
+
+flash_info_t *
+addr2info (ulong addr)
+{
+#ifndef CONFIG_SPD823TS
+ flash_info_t *info;
+ int i;
+
+ for (i=0, info = &flash_info[0]; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i, ++info) {
+ if (info->flash_id != FLASH_UNKNOWN &&
+ addr >= info->start[0] &&
+ /* WARNING - The '- 1' is needed if the flash
+ * is at the end of the address space, since
+ * info->start[0] + info->size wraps back to 0.
+ * Please don't change this unless you understand this.
+ */
+ addr <= info->start[0] + info->size - 1) {
+ return (info);
+ }
+ }
+#endif /* CONFIG_SPD823TS */
+
+ return (NULL);
+}
+
+/*-----------------------------------------------------------------------
+ * Copy memory to flash.
+ * Make sure all target addresses are within Flash bounds,
+ * and no protected sectors are hit.
+ * Returns:
+ * ERR_OK 0 - OK
+ * ERR_TIMOUT 1 - write timeout
+ * ERR_NOT_ERASED 2 - Flash not erased
+ * ERR_PROTECTED 4 - target range includes protected sectors
+ * ERR_INVAL 8 - target address not in Flash memory
+ * ERR_ALIGN 16 - target address not aligned on boundary
+ * (only some targets require alignment)
+ */
+int
+flash_write (char *src, ulong addr, ulong cnt)
+{
+#ifdef CONFIG_SPD823TS
+ return (ERR_TIMOUT); /* any other error codes are possible as well */
+#else
+ int i;
+ ulong end = addr + cnt - 1;
+ flash_info_t *info_first = addr2info (addr);
+ flash_info_t *info_last = addr2info (end );
+ flash_info_t *info;
+ int j;
+
+ if (cnt == 0) {
+ return (ERR_OK);
+ }
+
+ if (!info_first || !info_last) {
+ return (ERR_INVAL);
+ }
+
+ for (info = info_first; info <= info_last; ++info) {
+ ulong b_end = info->start[0] + info->size; /* bank end addr */
+ short s_end = info->sector_count - 1;
+ for (i=0; i<info->sector_count; ++i) {
+ ulong e_addr = (i == s_end) ? b_end : info->start[i + 1];
+
+ if ((end >= info->start[i]) && (addr < e_addr) &&
+ (info->protect[i] != 0) ) {
+ return (ERR_PROTECTED);
+ }
+ }
+ }
+
+ printf("\rWriting ");
+ for (j=0; j<20; j++) putc(177);
+ printf("\rWriting ");
+
+ /* finally write data to flash */
+ for (info = info_first; info <= info_last && cnt>0; ++info) {
+ ulong len;
+
+ len = info->start[0] + info->size - addr;
+ if (len > cnt)
+ len = cnt;
+
+ if ((i = write_buff(info, src, addr, len)) != 0) {
+ return (i);
+ }
+ cnt -= len;
+ addr += len;
+ src += len;
+ }
+ return (ERR_OK);
+#endif /* CONFIG_SPD823TS */
+}
+
+/*-----------------------------------------------------------------------
+ */
diff --git a/tools/updater/flash_hw.c b/tools/updater/flash_hw.c
new file mode 100644
index 0000000..b5058b3
--- /dev/null
+++ b/tools/updater/flash_hw.c
@@ -0,0 +1,659 @@
+/*
+ * (C) Copyright 2001
+ * Josh Huber <huber@mclx.com>, Mission Critical Linux, Inc.
+ *
+ * (C) Copyright 2002
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.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 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., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <flash.h>
+#include <asm/io.h>
+#include <memio.h>
+
+/*---------------------------------------------------------------------*/
+#undef DEBUG_FLASH
+
+#ifdef DEBUG_FLASH
+#define DEBUGF(fmt,args...) printf(fmt ,##args)
+#else
+#define DEBUGF(fmt,args...)
+#endif
+/*---------------------------------------------------------------------*/
+
+flash_info_t flash_info[];
+
+static ulong flash_get_size (ulong addr, flash_info_t *info);
+static int flash_get_offsets (ulong base, flash_info_t *info);
+static int write_word (flash_info_t *info, ulong dest, ulong data);
+static void flash_reset (ulong addr);
+
+int flash_xd_nest;
+
+static void flash_to_xd(void)
+{
+ unsigned char x;
+
+ flash_xd_nest ++;
+
+ if (flash_xd_nest == 1)
+ {
+ DEBUGF("Flash on XD\n");
+ x = pci_read_cfg_byte(0, 0, 0x74);
+ pci_write_cfg_byte(0, 0, 0x74, x|1);
+ }
+}
+
+static void flash_to_mem(void)
+{
+ unsigned char x;
+
+ flash_xd_nest --;
+
+ if (flash_xd_nest == 0)
+ {
+ DEBUGF("Flash on memory bus\n");
+ x = pci_read_cfg_byte(0, 0, 0x74);
+ pci_write_cfg_byte(0, 0, 0x74, x&0xFE);
+ }
+}
+
+unsigned long flash_init_old(void)
+{
+ int i;
+
+ for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++)
+ {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+
+ return 1;
+}
+
+unsigned long flash_init (void)
+{
+ unsigned int i;
+ unsigned long flash_size = 0;
+
+ flash_xd_nest = 0;
+
+ flash_to_xd();
+
+ /* Init: no FLASHes known */
+ for (i=0; i<CONFIG_SYS_MAX_FLASH_BANKS; ++i) {
+ flash_info[i].flash_id = FLASH_UNKNOWN;
+ flash_info[i].sector_count = 0;
+ flash_info[i].size = 0;
+ }
+
+ DEBUGF("\n## Get flash size @ 0x%08x\n", CONFIG_SYS_FLASH_BASE);
+
+ flash_size = flash_get_size (CONFIG_SYS_FLASH_BASE, flash_info);
+
+ DEBUGF("## Flash bank size: %08lx\n", flash_size);
+
+ if (flash_size) {
+#if CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE && \
+ CONFIG_SYS_MONITOR_BASE < CONFIG_SYS_FLASH_BASE + CONFIG_SYS_FLASH_MAX_SIZE
+ /* monitor protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CONFIG_SYS_MONITOR_BASE,
+ CONFIG_SYS_MONITOR_BASE + CONFIG_SYS_MONITOR_LEN - 1,
+ &flash_info[0]);
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_FLASH
+ /* ENV protection ON by default */
+ flash_protect(FLAG_PROTECT_SET,
+ CONFIG_ENV_ADDR,
+ CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
+ &flash_info[0]);
+#endif
+
+ } else {
+ printf ("Warning: the BOOT Flash is not initialised !");
+ }
+
+ flash_to_mem();
+
+ return flash_size;
+}
+
+/*
+ * The following code cannot be run from FLASH!
+ */
+static ulong flash_get_size (ulong addr, flash_info_t *info)
+{
+ short i;
+ uchar value;
+ uchar *x = (uchar *)addr;
+
+ flash_to_xd();
+
+ /* Write auto select command: read Manufacturer ID */
+ x[0x0555] = 0xAA;
+ __asm__ volatile ("sync\n eieio");
+ x[0x02AA] = 0x55;
+ __asm__ volatile ("sync\n eieio");
+ x[0x0555] = 0x90;
+ __asm__ volatile ("sync\n eieio");
+
+ value = x[0];
+ __asm__ volatile ("sync\n eieio");
+
+ DEBUGF("Manuf. ID @ 0x%08lx: 0x%08x\n", (ulong)addr, value);
+
+ switch (value | (value << 16)) {
+ case AMD_MANUFACT:
+ info->flash_id = FLASH_MAN_AMD;
+ break;
+
+ case FUJ_MANUFACT:
+ info->flash_id = FLASH_MAN_FUJ;
+ break;
+
+ case STM_MANUFACT:
+ info->flash_id = FLASH_MAN_STM;
+ break;
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ info->sector_count = 0;
+ info->size = 0;
+ flash_reset (addr);
+ return 0;
+ }
+
+ value = x[1];
+ __asm__ volatile ("sync\n eieio");
+
+ DEBUGF("Device ID @ 0x%08lx: 0x%08x\n", addr+1, value);
+
+ switch (value) {
+ case AMD_ID_F040B:
+ DEBUGF("Am29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV040B:
+ DEBUGF("Am29LV040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ case AMD_ID_LV400T:
+ DEBUGF("Am29LV400T\n");
+ info->flash_id += FLASH_AM400T;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV400B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM400B;
+ info->sector_count = 11;
+ info->size = 0x00100000;
+ break; /* => 1 MB */
+
+ case AMD_ID_LV800T:
+ DEBUGF("Am29LV800T\n");
+ info->flash_id += FLASH_AM800T;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV800B:
+ DEBUGF("Am29LV400B\n");
+ info->flash_id += FLASH_AM800B;
+ info->sector_count = 19;
+ info->size = 0x00200000;
+ break; /* => 2 MB */
+
+ case AMD_ID_LV160T:
+ DEBUGF("Am29LV160T\n");
+ info->flash_id += FLASH_AM160T;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV160B:
+ DEBUGF("Am29LV160B\n");
+ info->flash_id += FLASH_AM160B;
+ info->sector_count = 35;
+ info->size = 0x00400000;
+ break; /* => 4 MB */
+
+ case AMD_ID_LV320T:
+ DEBUGF("Am29LV320T\n");
+ info->flash_id += FLASH_AM320T;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+
+#if 0
+ /* Has the same ID as AMD_ID_LV320T, to be fixed */
+ case AMD_ID_LV320B:
+ DEBUGF("Am29LV320B\n");
+ info->flash_id += FLASH_AM320B;
+ info->sector_count = 67;
+ info->size = 0x00800000;
+ break; /* => 8 MB */
+#endif
+
+ case AMD_ID_LV033C:
+ DEBUGF("Am29LV033C\n");
+ info->flash_id += FLASH_AM033C;
+ info->sector_count = 64;
+ info->size = 0x01000000;
+ break; /* => 16Mb */
+
+ case STM_ID_F040B:
+ DEBUGF("M29F040B\n");
+ info->flash_id += FLASH_AM040;
+ info->sector_count = 8;
+ info->size = 0x00080000;
+ break; /* => 512 kB */
+
+ default:
+ info->flash_id = FLASH_UNKNOWN;
+ flash_reset (addr);
+ flash_to_mem();
+ return (0); /* => no or unknown flash */
+
+ }
+
+ if (info->sector_count > CONFIG_SYS_MAX_FLASH_SECT) {
+ printf ("** ERROR: sector count %d > max (%d) **\n",
+ info->sector_count, CONFIG_SYS_MAX_FLASH_SECT);
+ info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
+ }
+
+ if (! flash_get_offsets (addr, info)) {
+ flash_reset (addr);
+ flash_to_mem();
+ return 0;
+ }
+
+ /* check for protected sectors */
+ for (i = 0; i < info->sector_count; i++) {
+ /* read sector protection at sector address, (A7 .. A0) = 0x02 */
+ /* D0 = 1 if protected */
+ value = in8(info->start[i] + 2);
+ iobarrier_rw();
+ info->protect[i] = (value & 1) != 0;
+ }
+
+ /*
+ * Reset bank to read mode
+ */
+ flash_reset (addr);
+
+ flash_to_mem();
+
+ return (info->size);
+}
+
+static int flash_get_offsets (ulong base, flash_info_t *info)
+{
+ unsigned int i;
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040:
+ /* set sector offsets for uniform sector type */
+ for (i = 0; i < info->sector_count; i++) {
+ info->start[i] = base + i * info->size /
+ info->sector_count;
+ }
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+int flash_erase (flash_info_t *info, int s_first, int s_last)
+{
+ volatile ulong addr = info->start[0];
+ int flag, prot, sect, l_sect;
+ ulong start, now, last;
+
+ flash_to_xd();
+
+ if (s_first < 0 || s_first > s_last) {
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("- missing\n");
+ } else {
+ printf ("- no sectors to erase\n");
+ }
+ flash_to_mem();
+ return 1;
+ }
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("Can't erase unknown flash type %08lx - aborted\n",
+ info->flash_id);
+ flash_to_mem();
+ return 1;
+ }
+
+ prot = 0;
+ for (sect=s_first; sect<=s_last; ++sect) {
+ if (info->protect[sect]) {
+ prot++;
+ }
+ }
+
+ if (prot) {
+ printf ("- Warning: %d protected sectors will not be erased!\n",
+ prot);
+ } else {
+ printf ("");
+ }
+
+ l_sect = -1;
+
+ /* Disable interrupts which might cause a timeout here */
+ flag = disable_interrupts();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0x80);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+
+ /* Start erase on unprotected sectors */
+ for (sect = s_first; sect<=s_last; sect++) {
+ if (info->protect[sect] == 0) { /* not protected */
+ addr = info->start[sect];
+ out8(addr, 0x30);
+ iobarrier_rw();
+ l_sect = sect;
+ }
+ }
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* wait at least 80us - let's wait 1 ms */
+ udelay (1000);
+
+ /*
+ * We wait for the last triggered sector
+ */
+ if (l_sect < 0)
+ goto DONE;
+
+ start = get_timer (0);
+ last = start;
+ addr = info->start[l_sect];
+
+ DEBUGF ("Start erase timeout: %d\n", CONFIG_SYS_FLASH_ERASE_TOUT);
+
+ while ((in8(addr) & 0x80) != 0x80) {
+ if ((now = get_timer(start)) > CONFIG_SYS_FLASH_ERASE_TOUT) {
+ printf ("Timeout\n");
+ flash_reset (info->start[0]);
+ flash_to_mem();
+ return 1;
+ }
+ /* show that we're waiting */
+ if ((now - last) > 1000) { /* every second */
+ putc ('.');
+ last = now;
+ }
+ iobarrier_rw();
+ }
+
+DONE:
+ /* reset to read mode */
+ flash_reset (info->start[0]);
+ flash_to_mem();
+
+ printf (" done\n");
+ return 0;
+}
+
+/*
+ * Copy memory to flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+ ulong cp, wp, data;
+ int i, l, rc;
+ ulong out_cnt = 0;
+
+ flash_to_xd();
+
+ wp = (addr & ~3); /* get lower word aligned address */
+
+ /*
+ * handle unaligned start bytes
+ */
+ if ((l = addr - wp) != 0) {
+ data = 0;
+ for (i=0, cp=wp; i<l; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+ for (; i<4 && cnt>0; ++i) {
+ data = (data << 8) | *src++;
+ --cnt;
+ ++cp;
+ }
+ for (; cnt==0 && i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ if ((rc = write_word(info, wp, data)) != 0) {
+ flash_to_mem();
+ return (rc);
+ }
+ wp += 4;
+ }
+
+ putc(219);
+
+ /*
+ * handle word aligned part
+ */
+ while (cnt >= 4) {
+ if (out_cnt>26214)
+ {
+ putc(219);
+ out_cnt = 0;
+ }
+ data = 0;
+ for (i=0; i<4; ++i) {
+ data = (data << 8) | *src++;
+ }
+ if ((rc = write_word(info, wp, data)) != 0) {
+ flash_to_mem();
+ return (rc);
+ }
+ wp += 4;
+ cnt -= 4;
+ out_cnt += 4;
+ }
+
+ if (cnt == 0) {
+ flash_to_mem();
+ return (0);
+ }
+
+ /*
+ * handle unaligned tail bytes
+ */
+ data = 0;
+ for (i=0, cp=wp; i<4 && cnt>0; ++i, ++cp) {
+ data = (data << 8) | *src++;
+ --cnt;
+ }
+ for (; i<4; ++i, ++cp) {
+ data = (data << 8) | (*(uchar *)cp);
+ }
+
+ flash_to_mem();
+ return (write_word(info, wp, data));
+}
+
+/*
+ * Write a word to Flash, returns:
+ * 0 - OK
+ * 1 - write timeout
+ * 2 - Flash not erased
+ */
+static int write_word (flash_info_t *info, ulong dest, ulong data)
+{
+ volatile ulong addr = info->start[0];
+ ulong start;
+ int i;
+
+ flash_to_xd();
+
+ /* Check if Flash is (sufficiently) erased */
+ if ((in32(dest) & data) != data) {
+ flash_to_mem();
+ return (2);
+ }
+
+ /* write each byte out */
+ for (i = 0; i < 4; i++) {
+ char *data_ch = (char *)&data;
+ int flag = disable_interrupts();
+
+ out8(addr + 0x555, 0xAA);
+ iobarrier_rw();
+ out8(addr + 0x2AA, 0x55);
+ iobarrier_rw();
+ out8(addr + 0x555, 0xA0);
+ iobarrier_rw();
+ out8(dest+i, data_ch[i]);
+ iobarrier_rw();
+
+ /* re-enable interrupts if necessary */
+ if (flag)
+ enable_interrupts();
+
+ /* data polling for D7 */
+ start = get_timer (0);
+ while ((in8(dest+i) & 0x80) != (data_ch[i] & 0x80)) {
+ if (get_timer(start) > CONFIG_SYS_FLASH_WRITE_TOUT) {
+ flash_reset (addr);
+ flash_to_mem();
+ return (1);
+ }
+ iobarrier_rw();
+ }
+ }
+
+ flash_reset (addr);
+ flash_to_mem();
+ return (0);
+}
+
+/*
+ * Reset bank to read mode
+ */
+static void flash_reset (ulong addr)
+{
+ flash_to_xd();
+ out8(addr, 0xF0); /* reset bank */
+ iobarrier_rw();
+ flash_to_mem();
+}
+
+void flash_print_info (flash_info_t *info)
+{
+ int i;
+
+ if (info->flash_id == FLASH_UNKNOWN) {
+ printf ("missing or unknown FLASH type\n");
+ return;
+ }
+
+ switch (info->flash_id & FLASH_VENDMASK) {
+ case FLASH_MAN_AMD: printf ("AMD "); break;
+ case FLASH_MAN_FUJ: printf ("FUJITSU "); break;
+ case FLASH_MAN_BM: printf ("BRIGHT MICRO "); break;
+ case FLASH_MAN_STM: printf ("SGS THOMSON "); break;
+ default: printf ("Unknown Vendor "); break;
+ }
+
+ switch (info->flash_id & FLASH_TYPEMASK) {
+ case FLASH_AM040: printf ("29F040 or 29LV040 (4 Mbit, uniform sectors)\n");
+ break;
+ case FLASH_AM400B: printf ("AM29LV400B (4 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM400T: printf ("AM29LV400T (4 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM800B: printf ("AM29LV800B (8 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM800T: printf ("AM29LV800T (8 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM160B: printf ("AM29LV160B (16 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM160T: printf ("AM29LV160T (16 Mbit, top boot sector)\n");
+ break;
+ case FLASH_AM320B: printf ("AM29LV320B (32 Mbit, bottom boot sect)\n");
+ break;
+ case FLASH_AM320T: printf ("AM29LV320T (32 Mbit, top boot sector)\n");
+ break;
+ default: printf ("Unknown Chip Type\n");
+ break;
+ }
+
+ if (info->size % 0x100000 == 0) {
+ printf (" Size: %ld MB in %d Sectors\n",
+ info->size / 0x100000, info->sector_count);
+ } else if (info->size % 0x400 == 0) {
+ printf (" Size: %ld KB in %d Sectors\n",
+ info->size / 0x400, info->sector_count);
+ } else {
+ printf (" Size: %ld B in %d Sectors\n",
+ info->size, info->sector_count);
+ }
+
+ printf (" Sector Start Addresses:");
+ for (i=0; i<info->sector_count; ++i) {
+ if ((i % 5) == 0)
+ printf ("\n ");
+ printf (" %08lX%s",
+ info->start[i],
+ info->protect[i] ? " (RO)" : " "
+ );
+ }
+ printf ("\n");
+}
diff --git a/tools/updater/junk b/tools/updater/junk
new file mode 100644
index 0000000..f73285a
--- /dev/null
+++ b/tools/updater/junk
@@ -0,0 +1 @@
+................................................................................................................................................................................................................................................................ \ No newline at end of file
diff --git a/tools/updater/ppcstring.S b/tools/updater/ppcstring.S
new file mode 100644
index 0000000..97023a0
--- /dev/null
+++ b/tools/updater/ppcstring.S
@@ -0,0 +1,216 @@
+/*
+ * String handling functions for PowerPC.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * 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.
+ */
+#include <ppc_asm.tmpl>
+#include <asm/errno.h>
+
+ .globl strcpy
+strcpy:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strncpy
+strncpy:
+ cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r6)
+ bdnzf 2,1b /* dec ctr, branch if ctr != 0 && !cr0.eq */
+ blr
+
+ .globl strcat
+strcat:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r0,1(r5)
+ cmpwi 0,r0,0
+ bne 1b
+ addi r5,r5,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ stbu r0,1(r5)
+ bne 1b
+ blr
+
+ .globl strcmp
+strcmp:
+ addi r5,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r5)
+ cmpwi 1,r3,0
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ beqlr 1
+ beq 1b
+ blr
+
+ .globl strlen
+strlen:
+ addi r4,r3,-1
+1: lbzu r0,1(r4)
+ cmpwi 0,r0,0
+ bne 1b
+ subf r3,r3,r4
+ blr
+
+ .globl memset
+memset:
+ rlwimi r4,r4,8,16,23
+ rlwimi r4,r4,16,0,15
+ addi r6,r3,-4
+ cmplwi 0,r5,4
+ blt 7f
+ stwu r4,4(r6)
+ beqlr
+ andi. r0,r6,3
+ add r5,r0,r5
+ subf r6,r0,r6
+ rlwinm r0,r5,32-2,2,31
+ mtctr r0
+ bdz 6f
+1: stwu r4,4(r6)
+ bdnz 1b
+6: andi. r5,r5,3
+7: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r6,r6,3
+8: stbu r4,1(r6)
+ bdnz 8b
+ blr
+
+ .globl bcopy
+bcopy:
+ mr r6,r3
+ mr r3,r4
+ mr r4,r6
+ b memcpy
+
+ .globl memmove
+memmove:
+ cmplw 0,r3,r4
+ bgt backwards_memcpy
+ /* fall through */
+
+ .globl memcpy
+memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ addi r6,r3,-4
+ addi r4,r4,-4
+ beq 2f /* if less than 8 bytes to do */
+ andi. r0,r6,3 /* get dest word aligned */
+ mtctr r7
+ bne 5f
+1: lwz r7,4(r4)
+ lwzu r8,8(r4)
+ stw r7,4(r6)
+ stwu r8,8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,4(r4)
+ addi r5,r5,-4
+ stwu r0,4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+ addi r4,r4,3
+ addi r6,r6,3
+4: lbzu r0,1(r4)
+ stbu r0,1(r6)
+ bdnz 4b
+ blr
+5: subfic r0,r0,4
+ mtctr r0
+6: lbz r7,4(r4)
+ addi r4,r4,1
+ stb r7,4(r6)
+ addi r6,r6,1
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl backwards_memcpy
+backwards_memcpy:
+ rlwinm. r7,r5,32-3,3,31 /* r0 = r5 >> 3 */
+ add r6,r3,r5
+ add r4,r4,r5
+ beq 2f
+ andi. r0,r6,3
+ mtctr r7
+ bne 5f
+1: lwz r7,-4(r4)
+ lwzu r8,-8(r4)
+ stw r7,-4(r6)
+ stwu r8,-8(r6)
+ bdnz 1b
+ andi. r5,r5,7
+2: cmplwi 0,r5,4
+ blt 3f
+ lwzu r0,-4(r4)
+ subi r5,r5,4
+ stwu r0,-4(r6)
+3: cmpwi 0,r5,0
+ beqlr
+ mtctr r5
+4: lbzu r0,-1(r4)
+ stbu r0,-1(r6)
+ bdnz 4b
+ blr
+5: mtctr r0
+6: lbzu r7,-1(r4)
+ stbu r7,-1(r6)
+ bdnz 6b
+ subf r5,r0,r5
+ rlwinm. r7,r5,32-3,3,31
+ beq 2b
+ mtctr r7
+ b 1b
+
+ .globl memcmp
+memcmp:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r6,r3,-1
+ addi r4,r4,-1
+1: lbzu r3,1(r6)
+ lbzu r0,1(r4)
+ subf. r3,r0,r3
+ bdnzt 2,1b
+ blr
+2: li r3,0
+ blr
+
+ .global memchr
+memchr:
+ cmpwi 0,r5,0
+ ble- 2f
+ mtctr r5
+ addi r3,r3,-1
+1: lbzu r0,1(r3)
+ cmpw 0,r0,r4
+ bdnzf 2,1b
+ beqlr
+2: li r3,0
+ blr
diff --git a/tools/updater/string.c b/tools/updater/string.c
new file mode 100644
index 0000000..954fb01
--- /dev/null
+++ b/tools/updater/string.c
@@ -0,0 +1,340 @@
+/*
+ * linux/lib/string.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+/*
+ * stupid library routines.. The optimized versions should generally be found
+ * as inline code in <asm-xx/string.h>
+ *
+ * These are buggy as well..
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+#include <malloc.h>
+
+#define __HAVE_ARCH_BCOPY
+#define __HAVE_ARCH_MEMCMP
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_STRCAT
+#define __HAVE_ARCH_STRCMP
+#define __HAVE_ARCH_STRCPY
+#define __HAVE_ARCH_STRLEN
+#define __HAVE_ARCH_STRNCPY
+
+char * ___strtok = NULL;
+
+#ifndef __HAVE_ARCH_STRCPY
+char * strcpy(char * dest,const char *src)
+{
+ char *tmp = dest;
+
+ while ((*dest++ = *src++) != '\0')
+ /* nothing */;
+ return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCPY
+char * strncpy(char * dest,const char *src,size_t count)
+{
+ char *tmp = dest;
+
+ while (count-- && (*dest++ = *src++) != '\0')
+ /* nothing */;
+
+ return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCAT
+char * strcat(char * dest, const char * src)
+{
+ char *tmp = dest;
+
+ while (*dest)
+ dest++;
+ while ((*dest++ = *src++) != '\0')
+ ;
+
+ return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCAT
+char * strncat(char *dest, const char *src, size_t count)
+{
+ char *tmp = dest;
+
+ if (count) {
+ while (*dest)
+ dest++;
+ while ((*dest++ = *src++)) {
+ if (--count == 0) {
+ *dest = '\0';
+ break;
+ }
+ }
+ }
+
+ return tmp;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCMP
+int strcmp(const char * cs,const char * ct)
+{
+ register signed char __res;
+
+ while (1) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ }
+
+ return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNCMP
+int strncmp(const char * cs,const char * ct,size_t count)
+{
+ register signed char __res = 0;
+
+ while (count) {
+ if ((__res = *cs - *ct++) != 0 || !*cs++)
+ break;
+ count--;
+ }
+
+ return __res;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRCHR
+char * strchr(const char * s, int c)
+{
+ for(; *s != (char) c; ++s)
+ if (*s == '\0')
+ return NULL;
+ return (char *) s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRRCHR
+char * strrchr(const char * s, int c)
+{
+ const char *p = s + strlen(s);
+ do {
+ if (*p == (char)c)
+ return (char *)p;
+ } while (--p >= s);
+ return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRLEN
+size_t strlen(const char * s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRNLEN
+size_t strnlen(const char * s, size_t count)
+{
+ const char *sc;
+
+ for (sc = s; count-- && *sc != '\0'; ++sc)
+ /* nothing */;
+ return sc - s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRDUP
+char * strdup(const char *s)
+{
+ char *new;
+
+ if ((s == NULL) ||
+ ((new = malloc (strlen(s) + 1)) == NULL) ) {
+ return NULL;
+ }
+
+ strcpy (new, s);
+ return new;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSPN
+size_t strspn(const char *s, const char *accept)
+{
+ const char *p;
+ const char *a;
+ size_t count = 0;
+
+ for (p = s; *p != '\0'; ++p) {
+ for (a = accept; *a != '\0'; ++a) {
+ if (*p == *a)
+ break;
+ }
+ if (*a == '\0')
+ return count;
+ ++count;
+ }
+
+ return count;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRPBRK
+char * strpbrk(const char * cs,const char * ct)
+{
+ const char *sc1,*sc2;
+
+ for( sc1 = cs; *sc1 != '\0'; ++sc1) {
+ for( sc2 = ct; *sc2 != '\0'; ++sc2) {
+ if (*sc1 == *sc2)
+ return (char *) sc1;
+ }
+ }
+ return NULL;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRTOK
+char * strtok(char * s,const char * ct)
+{
+ char *sbegin, *send;
+
+ sbegin = s ? s : ___strtok;
+ if (!sbegin) {
+ return NULL;
+ }
+ sbegin += strspn(sbegin,ct);
+ if (*sbegin == '\0') {
+ ___strtok = NULL;
+ return( NULL );
+ }
+ send = strpbrk( sbegin, ct);
+ if (send && *send != '\0')
+ *send++ = '\0';
+ ___strtok = send;
+ return (sbegin);
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMSET
+void * memset(void * s,char c,size_t count)
+{
+ char *xs = (char *) s;
+
+ while (count--)
+ *xs++ = c;
+
+ return s;
+}
+#endif
+
+#ifndef __HAVE_ARCH_BCOPY
+char * bcopy(const char * src, char * dest, int count)
+{
+ char *tmp = dest;
+
+ while (count--)
+ *tmp++ = *src++;
+
+ return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCPY
+void * memcpy(void * dest,const void *src,size_t count)
+{
+ char *tmp = (char *) dest, *s = (char *) src;
+
+ while (count--)
+ *tmp++ = *s++;
+
+ return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMMOVE
+void * memmove(void * dest,const void *src,size_t count)
+{
+ char *tmp, *s;
+
+ if (dest <= src) {
+ tmp = (char *) dest;
+ s = (char *) src;
+ while (count--)
+ *tmp++ = *s++;
+ }
+ else {
+ tmp = (char *) dest + count;
+ s = (char *) src + count;
+ while (count--)
+ *--tmp = *--s;
+ }
+
+ return dest;
+}
+#endif
+
+#ifndef __HAVE_ARCH_MEMCMP
+int memcmp(const void * cs,const void * ct,size_t count)
+{
+ const unsigned char *su1, *su2;
+ signed char res = 0;
+
+ for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+ if ((res = *su1 - *su2) != 0)
+ break;
+ return res;
+}
+#endif
+
+/*
+ * find the first occurrence of byte 'c', or 1 past the area if none
+ */
+#ifndef __HAVE_ARCH_MEMSCAN
+void * memscan(void * addr, int c, size_t size)
+{
+ unsigned char * p = (unsigned char *) addr;
+
+ while (size) {
+ if (*p == c)
+ return (void *) p;
+ p++;
+ size--;
+ }
+ return (void *) p;
+}
+#endif
+
+#ifndef __HAVE_ARCH_STRSTR
+char * strstr(const char * s1,const char * s2)
+{
+ int l1, l2;
+
+ l2 = strlen(s2);
+ if (!l2)
+ return (char *) s1;
+ l1 = strlen(s1);
+ while (l1 >= l2) {
+ l1--;
+ if (!memcmp(s1,s2,l2))
+ return (char *) s1;
+ s1++;
+ }
+ return NULL;
+}
+#endif
diff --git a/tools/updater/update.c b/tools/updater/update.c
new file mode 100644
index 0000000..18f122a
--- /dev/null
+++ b/tools/updater/update.c
@@ -0,0 +1,63 @@
+#include <common.h>
+#include <exports.h>
+
+extern unsigned long __dummy;
+void do_reset (void);
+void do_updater(void);
+
+void _main(void)
+{
+ int i;
+ printf("U-Boot Firmware Updater\n\n\n");
+ printf("****************************************************\n"
+ "* ATTENTION!! PLEASE READ THIS NOTICE CAREFULLY! *\n"
+ "****************************************************\n\n"
+ "This program will update your computer's firmware.\n"
+ "Do NOT remove the disk, reset the machine, or do\n"
+ "anything that might disrupt functionality. If this\n");
+ printf("Program fails, your computer might be unusable, and\n"
+ "you will need to return your board for reflashing.\n"
+ "If you find this too risky, remove the diskette and\n"
+ "switch off your machine now. Otherwise press the \n"
+ "SPACE key now to start the process\n\n");
+ do
+ {
+ char x;
+ while (!tstc());
+ x = getc();
+ if (x == ' ') break;
+ } while (1);
+
+ do_updater();
+
+ i = 5;
+
+ printf("\nUpdate done. Please remove diskette.\n");
+ printf("The machine will automatically reset in %d seconds\n", i);
+ printf("You can switch off/reset now when the floppy is removed\n\n");
+
+ while (i)
+ {
+ printf("Resetting in %d\r", i);
+ udelay(1000000);
+ i--;
+ }
+ do_reset();
+ while (1);
+}
+
+void do_updater(void)
+{
+ unsigned long *addr = &__dummy + 65;
+ unsigned long flash_size = flash_init();
+ int rc;
+
+ flash_sect_protect(0, 0xFFF00000, 0xFFF7FFFF);
+ printf("Erasing ");
+ flash_sect_erase(0xFFF00000, 0xFFF7FFFF);
+ printf("Writing ");
+ rc = flash_write((uchar *)addr, 0xFFF00000, 0x7FFFF);
+ if (rc != 0) printf("\nFlashing failed due to error %d\n", rc);
+ else printf("\ndone\n");
+ flash_sect_protect(1, 0xFFF00000, 0xFFF7FFFF);
+}
diff --git a/tools/updater/utils.c b/tools/updater/utils.c
new file mode 100644
index 0000000..61a6118
--- /dev/null
+++ b/tools/updater/utils.c
@@ -0,0 +1,148 @@
+#include <common.h>
+#include <asm/processor.h>
+#include <memio.h>
+#include <linux/ctype.h>
+
+static __inline__ unsigned long
+get_msr(void)
+{
+ unsigned long msr;
+
+ asm volatile("mfmsr %0" : "=r" (msr) :);
+ return msr;
+}
+
+static __inline__ void
+set_msr(unsigned long msr)
+{
+ asm volatile("mtmsr %0" : : "r" (msr));
+}
+
+static __inline__ unsigned long
+get_dec(void)
+{
+ unsigned long val;
+
+ asm volatile("mfdec %0" : "=r" (val) :);
+ return val;
+}
+
+
+static __inline__ void
+set_dec(unsigned long val)
+{
+ asm volatile("mtdec %0" : : "r" (val));
+}
+
+
+void
+enable_interrupts(void)
+{
+ set_msr (get_msr() | MSR_EE);
+}
+
+/* returns flag if MSR_EE was set before */
+int
+disable_interrupts(void)
+{
+ ulong msr;
+
+ msr = get_msr();
+ set_msr (msr & ~MSR_EE);
+ return ((msr & MSR_EE) != 0);
+}
+
+u8 in8(u32 port)
+{
+ return in_byte(port);
+}
+
+void out8(u32 port, u8 val)
+{
+ out_byte(port, val);
+}
+
+unsigned long in32(u32 port)
+{
+ return in_long(port);
+}
+
+unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
+{
+ unsigned long result = 0,value;
+
+ if (*cp == '0') {
+ cp++;
+ if ((*cp == 'x') && isxdigit(cp[1])) {
+ base = 16;
+ cp++;
+ }
+ if (!base) {
+ base = 8;
+ }
+ }
+ if (!base) {
+ base = 10;
+ }
+ while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
+ ? toupper(*cp) : *cp)-'A'+10) < base) {
+ result = result*base + value;
+ cp++;
+ }
+ if (endp)
+ *endp = (char *)cp;
+ return result;
+}
+
+long simple_strtol(const char *cp,char **endp,unsigned int base)
+{
+ if(*cp=='-')
+ return -simple_strtoul(cp+1,endp,base);
+ return simple_strtoul(cp,endp,base);
+}
+
+static inline void
+soft_restart(unsigned long addr)
+{
+ /* SRR0 has system reset vector, SRR1 has default MSR value */
+ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */
+
+ __asm__ __volatile__ ("mtspr 26, %0" :: "r" (addr));
+ __asm__ __volatile__ ("li 4, (1 << 6)" ::: "r4");
+ __asm__ __volatile__ ("mtspr 27, 4");
+ __asm__ __volatile__ ("rfi");
+
+ while(1); /* not reached */
+}
+
+void
+do_reset (void)
+{
+ ulong addr;
+ /* flush and disable I/D cache */
+ __asm__ __volatile__ ("mfspr 3, 1008" ::: "r3");
+ __asm__ __volatile__ ("ori 5, 5, 0xcc00" ::: "r5");
+ __asm__ __volatile__ ("ori 4, 3, 0xc00" ::: "r4");
+ __asm__ __volatile__ ("andc 5, 3, 5" ::: "r5");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 4");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+ __asm__ __volatile__ ("mtspr 1008, 5");
+ __asm__ __volatile__ ("isync");
+ __asm__ __volatile__ ("sync");
+
+#ifdef CONFIG_SYS_RESET_ADDRESS
+ addr = CONFIG_SYS_RESET_ADDRESS;
+#else
+ /*
+ * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address,
+ * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid
+ * address. Better pick an address known to be invalid on your
+ * system and assign it to CONFIG_SYS_RESET_ADDRESS.
+ */
+ addr = CONFIG_SYS_MONITOR_BASE - sizeof (ulong);
+#endif
+ soft_restart(addr);
+ while(1); /* not reached */
+}
diff --git a/tools/xway-swap-bytes.c b/tools/xway-swap-bytes.c
new file mode 100644
index 0000000..3a6d82d
--- /dev/null
+++ b/tools/xway-swap-bytes.c
@@ -0,0 +1,38 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifndef BUFSIZ
+# define BUFSIZ 4096
+#endif
+
+#undef BUFSIZ
+# define BUFSIZ 64
+int main (void)
+{
+ short ibuff[BUFSIZ], obuff[BUFSIZ];
+ int rc, i, len;
+
+ while ((rc = read (0, ibuff, sizeof (ibuff))) > 0) {
+ memset (obuff, 0, sizeof (obuff));
+ for (i = 0; i < (rc + 1) / 2; i++) {
+ obuff[i] = ibuff[i ^ 1];
+ }
+
+ len = (rc + 1) & ~1;
+
+ if (write (1, obuff, len) != len) {
+ perror ("read error");
+ return (EXIT_FAILURE);
+ }
+
+ memset (ibuff, 0, sizeof (ibuff));
+ }
+
+ if (rc < 0) {
+ perror ("read error");
+ return (EXIT_FAILURE);
+ }
+ return (EXIT_SUCCESS);
+}
OpenPOWER on IntegriCloud