kconfig: switch to Kconfig

This commit enables Kconfig.
Going forward, we use Kconfig for the board configuration.
mkconfig will never be used. Nor will include/config.mk be generated.

Kconfig must be adjusted for U-Boot because our situation is
a little more complicated than Linux Kernel.
We have to generate multiple boot images (Normal, SPL, TPL)
from one source tree.
Each image needs its own configuration input.

Usage:

Run "make <board>_defconfig" to do the board configuration.

It will create the .config file and additionally spl/.config, tpl/.config
if SPL, TPL is enabled, respectively.

You can use "make config", "make menuconfig" etc. to create
a new .config or modify the existing one.

Use "make spl/config", "make spl/menuconfig" etc. for spl/.config
and do likewise for tpl/.config file.

The generic syntax of configuration targets for SPL, TPL is:

  <target_image>/<config_command>

Here, <target_image> is either 'spl' or 'tpl'
      <config_command> is 'config', 'menuconfig', 'xconfig', etc.

When the configuration is done, run "make".
(Or "make <board>_defconfig all" will do the configuration and build
in one time.)

For futher information of how Kconfig works in U-Boot,
please read the comment block of scripts/multiconfig.py.

By the way, there is another item worth remarking here:
coexistence of Kconfig and board herder files.

Prior to Kconfig, we used C headers to define a set of configs.

We expect a very long term to migrate from C headers to Kconfig.
Two different infractructure must coexist in the interim.

In our former configuration scheme, include/autoconf.mk was generated
for use in makefiles.
It is still generated under include/, spl/include/, tpl/include/ directory
for the Normal, SPL, TPL image, respectively.

Signed-off-by: Masahiro Yamada <yamada.m@jp.panasonic.com>
Acked-by: Simon Glass <sjg@chromium.org>
diff --git a/scripts/Makefile b/scripts/Makefile
index 68c998e..efe25bf 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -13,4 +13,4 @@
 	@:
 
 # Let clean descend into subdirs
-subdir-	+= basic
+subdir-	+= basic kconfig
diff --git a/scripts/Makefile.autoconf b/scripts/Makefile.autoconf
new file mode 100644
index 0000000..44c3997
--- /dev/null
+++ b/scripts/Makefile.autoconf
@@ -0,0 +1,100 @@
+# This helper makefile is used for creating
+#  - symbolic links (arch/$ARCH/include/asm/arch
+#  - include/autoconf.mk, {spl,tpl}/include/autoconf.mk
+#  - include/config.h
+#
+# When our migration to Kconfig is done
+# (= When we move all CONFIGs from header files to Kconfig)
+# this makefile can be deleted.
+
+# obj is "include" or "spl/include" or "tpl/include"
+# for non-SPL, SPL, TPL, respectively
+include $(obj)/config/auto.conf
+
+include scripts/Kbuild.include
+
+# Need to define CC and CPP again here in case the top Makefile did not
+# include config.mk.  Some architectures expect CROSS_COMPILE to be defined
+# in arch/$(ARCH)/config.mk
+CC		= $(CROSS_COMPILE)gcc
+CPP		= $(CC) -E
+
+include config.mk
+
+UBOOTINCLUDE    := \
+		-I$(obj) \
+		-Iinclude \
+		$(if $(KBUILD_SRC), -I$(srctree)/include) \
+		-I$(srctree)/arch/$(ARCH)/include \
+		-include $(srctree)/include/linux/kconfig.h
+
+c_flags := $(KBUILD_CFLAGS) $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) \
+					$(UBOOTINCLUDE) $(NOSTDINC_FLAGS)
+
+quiet_cmd_autoconf_dep = GEN     $@
+      cmd_autoconf_dep = $(CC) -x c -DDO_DEPS_ONLY -M -MP $(c_flags) \
+	-MQ include/config/auto.conf $(srctree)/include/common.h > $@ || {	\
+		rm $@; false;							\
+	}
+include/autoconf.mk.dep: FORCE
+	$(call cmd,autoconf_dep)
+
+# We are migrating from board headers to Kconfig little by little.
+# In the interim, we use both of
+#  - include/config/auto.conf (generated by Kconfig)
+#  - include/autoconf.mk      (used in the U-Boot conventional configuration)
+# The following rule creates autoconf.mk
+# include/config/auto.conf is grepped in order to avoid duplication of the
+# same CONFIG macros
+quiet_cmd_autoconf = GEN     $@
+      cmd_autoconf = \
+	$(CPP) $(c_flags) -DDO_DEPS_ONLY -dM $(srctree)/include/common.h > $@.tmp && {	\
+		sed -n -f $(srctree)/tools/scripts/define2mk.sed $@.tmp |		\
+		while read line; do							\
+			if ! grep -q "$${line%=*}=" $(obj)/config/auto.conf; then	\
+				echo "$$line";						\
+			fi								\
+		done > $@;								\
+		rm $@.tmp;								\
+	} || {										\
+		rm $@.tmp; false;							\
+	}
+
+$(obj)/autoconf.mk: FORCE
+	$(call cmd,autoconf)
+
+include/autoconf.mk include/autoconf.mk.dep: include/config.h
+
+# include/config.h
+# Prior to Kconfig, it was generated by mkconfig. Now it is created here.
+define filechk_config_h
+	(echo "/* Automatically generated - do not edit */";		\
+	for i in $$(echo $(CONFIG_SYS_EXTRA_OPTIONS) | sed 's/,/ /g'); do \
+		echo \#define CONFIG_$$i				\
+		| sed '/=/ {s/=/	/;q; } ; { s/$$/	1/; }'; \
+	done;								\
+	echo \#define CONFIG_BOARDDIR board/$(if $(VENDOR),$(VENDOR)/)$(BOARD);\
+	echo \#include \<config_cmd_defaults.h\>;			\
+	echo \#include \<config_defaults.h\>;				\
+	echo \#include \<configs/$(CONFIG_SYS_CONFIG_NAME).h\>;		\
+	echo \#include \<asm/config.h\>;				\
+	echo \#include \<config_fallbacks.h\>;				\
+	echo \#include \<config_uncmd_spl.h\>; )
+endef
+
+include/config.h: scripts/Makefile.autoconf create_symlink FORCE
+	$(call filechk,config_h)
+
+# symbolic links
+PHONY += create_symlink
+create_symlink:
+ifneq ($(KBUILD_SRC),)
+	$(Q)mkdir -p include/asm
+endif
+	$(Q)ln -fsn $(srctree)/arch/$(ARCH)/include/asm/arch-$(if $(SOC),$(SOC),$(CPU)) \
+		$(if $(KBUILD_SRC),,arch/$(ARCH)/)include/asm/arch
+
+PHONY += FORCE
+FORCE:
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 04c6f7d..baeaabe 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -3,14 +3,14 @@
 # ==========================================================================
 
 # Modified for U-Boot
-ifeq ($(CONFIG_TPL_BUILD),y)
-  src := $(patsubst tpl/%,%,$(obj))
-else
-  ifeq ($(CONFIG_SPL_BUILD),y)
-    src := $(patsubst spl/%,%,$(obj))
-  else
-    src := $(obj)
-  endif
+prefix := tpl
+src := $(patsubst $(prefix)/%,%,$(obj))
+ifeq ($(obj),$(src))
+prefix := spl
+src := $(patsubst $(prefix)/%,%,$(obj))
+ifeq ($(obj),$(src))
+prefix := .
+endif
 endif
 
 PHONY := __build
@@ -40,18 +40,9 @@
 subdir-ccflags-y :=
 
 # Read auto.conf if it exists, otherwise ignore
--include include/config/auto.conf
-
-# Added for U-Boot: Load U-Boot configuration
-ifeq ($(CONFIG_TPL_BUILD),y)
-  -include include/tpl-autoconf.mk
-else
-  ifeq ($(CONFIG_SPL_BUILD),y)
-    -include include/spl-autoconf.mk
-  else
-    -include include/autoconf.mk
-  endif
-endif
+# Modified for U-Boot
+-include $(prefix)/include/config/auto.conf
+-include $(prefix)/include/autoconf.mk
 
 include scripts/Kbuild.include
 
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index bf677aa..88c01d1 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -21,13 +21,10 @@
 
 include $(srctree)/scripts/Kbuild.include
 
-CONFIG_SPL_BUILD := y
-export CONFIG_SPL_BUILD
+UBOOTINCLUDE := -I$(obj)/include $(UBOOTINCLUDE)
 
-KBUILD_CPPFLAGS += -DCONFIG_SPL_BUILD
-ifeq ($(CONFIG_TPL_BUILD),y)
-KBUILD_CPPFLAGS += -DCONFIG_TPL_BUILD
-endif
+-include $(obj)/include/config/auto.conf
+-include $(obj)/include/autoconf.mk
 
 ifeq ($(CONFIG_TPL_BUILD),y)
 export CONFIG_TPL_BUILD
@@ -36,14 +33,6 @@
 SPL_BIN := u-boot-spl
 endif
 
-include include/config.mk
-
-ifeq ($(CONFIG_TPL_BUILD),y)
-  -include include/tpl-autoconf.mk
-else
-  -include include/spl-autoconf.mk
-endif
-
 include $(srctree)/config.mk
 
 # Enable garbage collection of un-used sections for SPL
@@ -53,20 +42,6 @@
 # FIX ME
 cpp_flags := $(KBUILD_CPPFLAGS) $(PLATFORM_CPPFLAGS) $(UBOOTINCLUDE) \
 							$(NOSTDINC_FLAGS)
-c_flags := $(KBUILD_CFLAGS) $(cpp_flags)
-
-# Auto-generate the spl-autoconf.mk file (which is included by all makefiles for SPL)
-quiet_cmd_autoconf = GEN     $@
-      cmd_autoconf = \
-	$(CPP) $(c_flags) -DDO_DEPS_ONLY -dM $(srctree)/include/common.h > $@.tmp && \
-		sed -n -f $(srctree)/tools/scripts/define2mk.sed $@.tmp > $@; \
-	rm $@.tmp
-
-include/tpl-autoconf.mk: include/config.h
-	$(call cmd,autoconf)
-
-include/spl-autoconf.mk: include/config.h
-	$(call cmd,autoconf)
 
 HAVE_VENDOR_COMMON_LIB = $(if $(wildcard $(srctree)/board/$(VENDOR)/common/Makefile),y,n)
 
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index b304068..1a41723 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -221,7 +221,11 @@
 
 	define_config(m, slen, hash);
 
-	printf("    $(wildcard include/config/");
+	/* printf("    $(wildcard include/config/"); */
+	/* modified for U-Boot */
+	printf("    $(wildcard %sinclude/config/",
+	       strncmp(depfile, "spl/", 4) ?
+	       (strncmp(depfile, "tpl/", 4) ? "" : "tpl/") : "spl/");
 	for (i = 0; i < slen; i++) {
 		c = m[i];
 		if (c == '_')
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index f88d90f..ae6ce66 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -951,6 +951,14 @@
 	FILE *out, *tristate, *out_h;
 	int i;
 
+	/*
+	 * Added for U-Boot SPL/TPL
+	 */
+	name = getenv("KCONFIG_OBJDIR");
+	if (name && name[0])
+		if (chdir(name))
+			return 1;
+
 	sym_clear_all_valid();
 
 	file_write_dep("include/config/auto.conf.cmd");
diff --git a/scripts/multiconfig.py b/scripts/multiconfig.py
new file mode 100755
index 0000000..749abcb
--- /dev/null
+++ b/scripts/multiconfig.py
@@ -0,0 +1,410 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2014, Masahiro Yamada <yamada.m@jp.panasonic.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+"""
+A wrapper script to adjust Kconfig for U-Boot
+
+The biggest difference between Linux Kernel and U-Boot in terms of the
+board configuration is that U-Boot has to configure multiple boot images
+per board: Normal, SPL, TPL.
+We need to expand the functions of Kconfig to handle multiple boot
+images.
+
+Instead of touching various parts under the scripts/kconfig/ directory,
+pushing necessary adjustments into this single script would be better
+for code maintainance. All the make targets related to the configuration
+(make %config) should be invoked via this script.
+
+Let's see what is different from the original Kconfig.
+
+- config, menuconfig, etc.
+
+The commands 'make config', 'make menuconfig', etc. are used to create
+or modify the .config file, which stores configs for Normal boot image.
+
+The location of the one for SPL, TPL image is spl/.config, tpl/.config,
+respectively. Use 'make spl/config', 'make spl/menuconfig', etc.
+to create or modify the spl/.config file, which contains configs
+for SPL image.
+Do likewise for the tpl/.config file.
+The generic syntax for SPL, TPL configuration is
+'make <target_image>/<config_command>'.
+
+- silentoldconfig
+
+The command 'make silentoldconfig' updates .config, if necessary, and
+additionally updates include/generated/autoconf.h and files under
+include/configs/ directory. In U-Boot, it should do the same things for
+SPL, TPL images for boards supporting them.
+Depending on whether CONFIG_SPL, CONFIG_TPL is defined or not,
+'make silentoldconfig' iterates three times at most changing the target
+directory.
+
+To sum up, 'make silentoldconfig' possibly updates
+  - .config, include/generated/autoconf.h, include/config/*
+  - spl/.config, spl/include/generated/autoconf.h, spl/include/config/*
+    (in case CONFIG_SPL=y)
+  - tpl/.config, tpl/include/generated/autoconf.h, tpl/include/config/*
+    (in case CONFIG_TPL=y)
+
+- defconfig, <board>_defconfig
+
+The command 'make <board>_defconfig' creates a new .config based on the
+file configs/<board>_defconfig. The command 'make defconfig' is the same
+but the difference is it uses the file specified with KBUILD_DEFCONFIG
+environment.
+
+We need to create .config, spl/.config, tpl/.config for boards where SPL
+and TPL images are supported. One possible solution for that is to have
+multiple defconfig files per board, but it would produce duplication
+among the defconfigs.
+The approach chosen here is to expand the feature and support
+conditional definition in defconfig, that is, each line in defconfig
+files has the form of:
+<condition>:<macro definition>
+
+The '<condition>:' prefix specifies which image the line is valid for.
+The '<condition>:' is one of:
+  None  - the line is valid only for Normal image
+  S:    - the line is valid only for SPL image
+  T:    - the line is valid only for TPL image
+  ST:   - the line is valid for SPL and TPL images
+  +S:   - the line is valid for Normal and SPL images
+  +T:   - the line is valid for Normal and TPL images
+  +ST:  - the line is valid for Normal, SPL and SPL images
+
+So, if neither CONFIG_SPL nor CONFIG_TPL is defined, the defconfig file
+has no '<condition>:' part and therefore has the same form of that of
+Linux Kernel.
+
+In U-Boot, for example, a defconfig file can be written like this:
+
+  CONFIG_FOO=100
+  S:CONFIG_FOO=200
+  T:CONFIG_FOO=300
+  ST:CONFIG_BAR=y
+  +S:CONFIG_BAZ=y
+  +T:CONFIG_QUX=y
+  +ST:CONFIG_QUUX=y
+
+The defconfig above is parsed by this script and internally divided into
+three temporary defconfig files.
+
+  - Temporary defconfig for Normal image
+     CONFIG_FOO=100
+     CONFIG_BAZ=y
+     CONFIG_QUX=y
+     CONFIG_QUUX=y
+
+  - Temporary defconfig for SPL image
+     CONFIG_FOO=200
+     CONFIG_BAR=y
+     CONFIG_BAZ=y
+     CONFIG_QUUX=y
+
+  - Temporary defconfig for TPL image
+     CONFIG_FOO=300
+     CONFIG_BAR=y
+     CONFIG_QUX=y
+     CONFIG_QUUX=y
+
+They are passed to scripts/kconfig/conf, each is used for generating
+.config, spl/.config, tpl/.config, respectively.
+
+- savedefconfig
+
+This is the reverse operation of 'make defconfig'.
+If neither CONFIG_SPL nor CONFIG_TPL is defined in the .config file,
+it works as 'make savedefconfig' in Linux Kernel: create the minimal set
+of config based on the .config and save it into 'defconfig' file.
+
+If CONFIG_SPL or CONFIG_TPL is defined, the common lines among .config,
+spl/.config, tpl/.config are coalesced together and output to the file
+'defconfig' in the form like:
+
+  CONFIG_FOO=100
+  S:CONFIG_FOO=200
+  T:CONFIG_FOO=300
+  ST:CONFIG_BAR=y
+  +S:CONFIG_BAZ=y
+  +T:CONFIG_QUX=y
+  +ST:CONFIG_QUUX=y
+
+This can be used as an input of 'make <board>_defconfig' command.
+"""
+
+import errno
+import os
+import re
+import subprocess
+import sys
+
+# Constant variables
+SUB_IMAGES = ('spl', 'tpl')
+IMAGES = ('',) + SUB_IMAGES
+SYMBOL_MAP = {'': '+', 'spl': 'S', 'tpl': 'T'}
+PATTERN_SYMBOL = re.compile(r'(\+?)(S?)(T?):(.*)')
+
+# Environment variables (should be defined in the top Makefile)
+# .get('key', 'default_value') method is useful for standalone testing.
+MAKE = os.environ.get('MAKE', 'make')
+srctree = os.environ.get('srctree', '.')
+KCONFIG_CONFIG = os.environ.get('KCONFIG_CONFIG', '.config')
+
+# Useful shorthand
+build = '%s -f %s/scripts/Makefile.build obj=scripts/kconfig %%s' % (MAKE, srctree)
+autoconf = '%s -f %s/scripts/Makefile.autoconf obj=%%s %%s' % (MAKE, srctree)
+
+### helper functions ###
+def mkdirs(*dirs):
+    """Make directories ignoring 'File exists' error."""
+    for d in dirs:
+        try:
+            os.makedirs(d)
+        except OSError as exception:
+            # Ignore 'File exists' error
+            if exception.errno != errno.EEXIST:
+                raise
+
+def rmfiles(*files):
+    """Remove files ignoring 'No such file or directory' error."""
+    for f in files:
+        try:
+            os.remove(f)
+        except OSError as exception:
+            # Ignore 'No such file or directory' error
+            if exception.errno != errno.ENOENT:
+                raise
+
+def rmdirs(*dirs):
+    """Remove directories ignoring 'No such file or directory'
+    and 'Directory not empty' error.
+    """
+    for d in dirs:
+        try:
+            os.rmdir(d)
+        except OSError as exception:
+            # Ignore 'No such file or directory'
+            # and 'Directory not empty' error
+            if exception.errno != errno.ENOENT and \
+               exception.errno != errno.ENOTEMPTY:
+                raise
+
+def error(msg):
+    """Output the given argument to stderr and exit with return code 1."""
+    print >> sys.stderr, msg
+    sys.exit(1)
+
+def run_command(command, callback_on_error=None):
+    """Run the given command in a sub-shell (and exit if it fails).
+
+    Arguments:
+      command: A string of the command
+      callback_on_error: Callback handler invoked just before exit
+                         when the command fails (Default=None)
+    """
+    retcode = subprocess.call(command, shell=True)
+    if retcode:
+        if callback_on_error:
+            callback_on_error()
+        error("'%s' Failed" % command)
+
+def run_make_config(cmd, objdir, callback_on_error=None):
+    """Run the make command in a sub-shell (and exit if it fails).
+
+    Arguments:
+      cmd: Make target such as 'config', 'menuconfig', 'defconfig', etc.
+      objdir: Target directory where the make command is run.
+              Typically '', 'spl', 'tpl' for Normal, SPL, TPL image,
+              respectively.
+      callback_on_error: Callback handler invoked just before exit
+                         when the command fails (Default=None)
+    """
+    # Linux expects defconfig files in arch/$(SRCARCH)/configs/ directory,
+    # but U-Boot puts them in configs/ directory.
+    # Give SRCARCH=.. to fake scripts/kconfig/Makefile.
+    options = 'SRCARCH=.. KCONFIG_OBJDIR=%s' % objdir
+    if objdir:
+        options += ' KCONFIG_CONFIG=%s/%s' % (objdir, KCONFIG_CONFIG)
+        mkdirs(objdir)
+    run_command(build % cmd + ' ' + options, callback_on_error)
+
+def get_enabled_subimages(ignore_error=False):
+    """Parse .config file to detect if CONFIG_SPL, CONFIG_TPL is enabled
+    and return a tuple of enabled subimages.
+
+    Arguments:
+      ignore_error: Specify the behavior when '.config' is not found;
+                    Raise an exception if this flag is False.
+                    Return a null tuple if this flag is True.
+
+    Returns:
+      A tuple of enabled subimages as follows:
+        ()             if neither CONFIG_SPL nor CONFIG_TPL is defined
+        ('spl',)       if CONFIG_SPL is defined but CONFIG_TPL is not
+        ('spl', 'tpl') if both CONFIG_SPL and CONFIG_TPL are defined
+    """
+    enabled = ()
+    match_patterns = [ (img, 'CONFIG_' + img.upper() + '=y\n')
+                                                        for img in SUB_IMAGES ]
+    try:
+        f = open(KCONFIG_CONFIG)
+    except IOError as exception:
+        if not ignore_error or exception.errno != errno.ENOENT:
+            raise
+        return enabled
+    with f:
+        for line in f:
+            for img, pattern in match_patterns:
+                if line == pattern:
+                    enabled += (img,)
+    return enabled
+
+def do_silentoldconfig(cmd):
+    """Run 'make silentoldconfig' for all the enabled images.
+
+    Arguments:
+      cmd: should always be a string 'silentoldconfig'
+    """
+    run_make_config(cmd, '')
+    subimages = get_enabled_subimages()
+    for obj in subimages:
+        mkdirs(os.path.join(obj, 'include', 'config'),
+               os.path.join(obj, 'include', 'generated'))
+        run_make_config(cmd, obj)
+    remove_auto_conf = lambda : rmfiles('include/config/auto.conf')
+    # If the following part failed, include/config/auto.conf should be deleted
+    # so 'make silentoldconfig' will be re-run on the next build.
+    run_command(autoconf %
+                ('include', 'include/autoconf.mk include/autoconf.mk.dep'),
+                remove_auto_conf)
+    # include/config.h has been updated after 'make silentoldconfig'.
+    # We need to touch include/config/auto.conf so it gets newer
+    # than include/config.h.
+    # Otherwise, 'make silentoldconfig' would be invoked twice.
+    os.utime('include/config/auto.conf', None)
+    for obj in subimages:
+        run_command(autoconf % (obj + '/include',
+                                obj + '/include/autoconf.mk'),
+                    remove_auto_conf)
+
+def do_tmp_defconfig(output_lines, img):
+    """Helper function for do_board_defconfig().
+
+    Write the defconfig contents into a file '.tmp_defconfig' and
+    invoke 'make .tmp_defconfig'.
+
+    Arguments:
+      output_lines: A sequence of defconfig lines of each image
+      img: Target image. Typically '', 'spl', 'tpl' for
+           Normal, SPL, TPL images, respectively.
+    """
+    TMP_DEFCONFIG = '.tmp_defconfig'
+    TMP_DIRS = ('arch', 'configs')
+    defconfig_path = os.path.join('configs', TMP_DEFCONFIG)
+    mkdirs(*TMP_DIRS)
+    with open(defconfig_path, 'w') as f:
+        f.write(''.join(output_lines[img]))
+    cleanup = lambda: (rmfiles(defconfig_path), rmdirs(*TMP_DIRS))
+    run_make_config(TMP_DEFCONFIG, img, cleanup)
+    cleanup()
+
+def do_board_defconfig(cmd):
+    """Run 'make <board>_defconfig'.
+
+    Arguments:
+      cmd: should be a string '<board>_defconfig'
+    """
+    defconfig_path = os.path.join(srctree, 'configs', cmd)
+    output_lines = dict([ (img, []) for img in IMAGES ])
+    with open(defconfig_path) as f:
+        for line in f:
+            m = PATTERN_SYMBOL.match(line)
+            if m:
+                for idx, img in enumerate(IMAGES):
+                    if m.group(idx + 1):
+                        output_lines[img].append(m.group(4) + '\n')
+                continue
+            output_lines[''].append(line)
+    do_tmp_defconfig(output_lines, '')
+    for img in get_enabled_subimages():
+        do_tmp_defconfig(output_lines, img)
+
+def do_defconfig(cmd):
+    """Run 'make defconfig'.
+
+    Arguments:
+      cmd: should always be a string 'defconfig'
+    """
+    KBUILD_DEFCONFIG = os.environ['KBUILD_DEFCONFIG']
+    print "*** Default configuration is based on '%s'" % KBUILD_DEFCONFIG
+    do_board_defconfig(KBUILD_DEFCONFIG)
+
+def do_savedefconfig(cmd):
+    """Run 'make savedefconfig'.
+
+    Arguments:
+      cmd: should always be a string 'savedefconfig'
+    """
+    DEFCONFIG = 'defconfig'
+    # Continue even if '.config' does not exist
+    subimages = get_enabled_subimages(True)
+    run_make_config(cmd, '')
+    output_lines = []
+    prefix = {}
+    with open(DEFCONFIG) as f:
+        for line in f:
+            output_lines.append(line)
+            prefix[line] = '+'
+    for img in subimages:
+        run_make_config(cmd, img)
+        unmatched_lines = []
+        with open(DEFCONFIG) as f:
+            for line in f:
+                if line in output_lines:
+                    index = output_lines.index(line)
+                    output_lines[index:index] = unmatched_lines
+                    unmatched_lines = []
+                    prefix[line] += SYMBOL_MAP[img]
+                else:
+                    ummatched_lines.append(line)
+                    prefix[line] = SYMBOL_MAP[img]
+    with open(DEFCONFIG, 'w') as f:
+        for line in output_lines:
+            if prefix[line] == '+':
+                f.write(line)
+            else:
+                f.write(prefix[line] + ':' + line)
+
+def do_others(cmd):
+    """Run the make command other than 'silentoldconfig', 'defconfig',
+    '<board>_defconfig' and 'savedefconfig'.
+
+    Arguments:
+      cmd: Make target in the form of '<target_image>/<config_command>'
+           The field '<target_image>/' is typically empty, 'spl/', 'tpl/'
+           for Normal, SPL, TPL images, respectively.
+           The field '<config_command>' is make target such as 'config',
+           'menuconfig', etc.
+    """
+    objdir, _, cmd = cmd.rpartition('/')
+    run_make_config(cmd, objdir)
+
+cmd_list = {'silentoldconfig': do_silentoldconfig,
+            'defconfig': do_defconfig,
+            'savedefconfig': do_savedefconfig}
+
+def main():
+    cmd = sys.argv[1]
+    if cmd.endswith('_defconfig'):
+        do_board_defconfig(cmd)
+    else:
+        func = cmd_list.get(cmd, do_others)
+        func(cmd)
+
+if __name__ == '__main__':
+    main()