UBOOT研究学习之配置篇

为了能够在不同的硬件架构上(差异主要是CPU,DDR,FLASH等)进行适配运行,Uboot采用宏来控制编译时代码块的选择。

Uboot早期是通过手动编辑一个config文件来完配置的,但是手动编辑属于开放式操作,容易引入错误,所以从v2014.10-rc1开始,移植了Linux Kernel的Kconfig配置系统,让用户可以轻松的在界面上完成配置的选择和定义,极大提高了工作效率。

本文通过对Uboot的配置流程和Kconfig配置系统的讲解,让你知道配置是怎么生效的以及如何修改和增加配置选项。

注意!!!Uboot规定所有的宏都使用CONFIG_作为前缀,各种关于宏的配置以及转换也是基于CONFIG_完成的,如果新增配置选项,需要遵守该规则。

Uboot配置流程(以sandbox为例)

1.生成初始配置文件.config

当启动一个Kconfig配置界面的时候,每个配置选项的初始值有两个来源,一个是Kconfig文件中通过关键字default描述的,还有一个是当前目录下的.config文件,后者覆盖前者。

因为我们的新硬件架构并不是完全不同的,所以基本上可以以一个已经适配好的已有硬件作为基础来调整配置,比如我们这里选择的是sandbox_defconfig作为基础来生成.config文件:

1
2
3
4
5
6
7
8
9
10
$ make sandbox_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  YACC    scripts/kconfig/zconf.tab.c
  LEX     scripts/kconfig/zconf.lex.c
  HOSTCC  scripts/kconfig/zconf.tab.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#

实际上,.config文件是由宿主机编译出来的conf程序读取./configs/sandbox_defconfig文件和各级Kconfig文件后生成的,我们可以看到.config中的配置项明显比./configs/sandbox_defconfig更多,那是因为还包含了各级目录下的Kconfig文件中的配置选项和默认值。

2. 修改配置文件并更新.config

如果需要根据自己新的硬件架构调整配置选项的值,就需要启动配置界面:

1
$ make menuconfig

menuconfig

menuconfig只是配置界面可选的一种,还有其他选择,比如xconfig(基于QT)、gconfig(基于GTK+)、nconfig(基于ncurses)以及config(基于行字符)。

make help中关于配置界面介绍如下:

1
2
3
4
5
Configuration targets:
    config      - Update current config utilising a line-oriented program
    nconfig         - Update current config utilising a ncurses menu based program
    menuconfig      - Update current config utilising a menu based program
    xconfig     - Update current config utilising a Qt based front-end

因为是通过简单的键盘选中/编辑操作,而且规定了依赖关系,从而避免了不合理配置的引入,极大的保证了配置的可靠性。

3.生成配置相关文件

前面两步只是完成了.config文件,打开.config文件你会发现格式如下:

1
2
3
4
CONFIG_SYS_ARCH="sandbox"
CONFIG_SYS_CPU="sandbox"
CONFIG_SYS_BOARD="sandbox"
CONFIG_SYS_CONFIG_NAME="sandbox"

熟悉C语言的都知道,这并不是C的宏,.config必须转化为相关的头文件才能在编译时生效,make cfg可以完成这个工作。

1
2
3
4
5
6
7
8
$ make cfg NO_SDL=1
scripts/kconfig/conf  --syncconfig Kconfig
  CHK     include/config.h
  UPD     include/config.h
  CFG     u-boot.cfg
  GEN     include/autoconf.mk
  GEN     include/autoconf.mk.dep
make: Nothing to be done for 'cfg'.

使用NO_SDL=1,因为我们是在终端上运行的,不需要使用SDL引擎来显示界面和处理键盘输入。

所有需要平台适配的源码都包含了common.h这个头文件,那这个头文件和.config是怎么发生关系的呢?我们看看包含关系图,如下:

1
2
3
4
./include/generated/autoconf.h # ./scripts/kconfig/conf读取**.config和Kconfig**生成的
    => ./include/linux/kconfig.h 
        => ./include/config.h # 通过Makefile中的依赖关系来自动生成的,具体参考./scripts/Makefile.autoconf的100-115行
            => ./include/common.h # 通用头文件,被包含到具体的各个源码中

通过上述的自动生成和头文件包含关系可以看出,.config中的配置最终会在common.h得以体现,这样就完成了配置的导入和宏编译的控制。

Kconfig语法说明

配置选项的设置和相互之间的依赖关系是通过各层级的Kconfig文件来进行描述的,Kconfig有自己的语法结构,用于表达菜单入口,配置选项以及依赖关系等。

根目录下的Kconfig文件内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
mainmenu "U-Boot $UBOOTVERSION Configuration"

config UBOOTVERSION
        string
        option env="UBOOTVERSION"

# Allow defaults in arch-specific code to override any given here
source "arch/Kconfig"

menu "General setup"

config BROKEN
        bool
        help
          This option cannot be enabled. It is used as dependency
          for broken and incomplete features.

config DEPRECATED
        bool
        help
          This option cannot be enabled.  It it used as a dependency for
          code that relies on deprecated features that will be removed and
          the conversion deadline has passed.

config LOCALVERSION
        string "Local version - append to U-Boot release"
        help
          Append an extra string to the end of your U-Boot version.
          This will show up in your boot log, for example.
          The string you set here will be appended after the contents of
          any files with a filename matching localversion* in your
          object and source tree, in that order.  Your total string can
          be a maximum of 64 characters.

config LOCALVERSION_AUTO
        bool "Automatically append version information to the version string"
        default y
        help
          This will try to automatically determine if the current tree is a
          release tree by looking for Git tags that belong to the current
          top of tree revision.

          A string of the format -gxxxxxxxx will be added to the localversion
          if a Git-based tree is found.  The string generated by this will be
          appended after any matching localversion* files, and after the value
          set in CONFIG_LOCALVERSION.

          (The actual string used here is the first eight characters produced
          by running the command:

            $ git rev-parse --verify HEAD

          which is done within the script "scripts/setlocalversion".)

我们结合menuconfig的图以及上面的Kconfig文件内容,来简单说下Kconfig的语法使用。

1.菜单入口

1
mainmenu "U-Boot $UBOOTVERSION Configuration"

mainmenu为主菜单入口,就是配置界面最顶部显示的内容。后面的字符串为主菜单入口名称,可以可以使用$引用环境变量。

1
2
3
4
5
6
menu "General setup"

config BROKEN
    ...

endmenu

menu为子菜单入口,通过关键字menuendmenu来覆盖所有的配置选项,这两个关键字中间的所有配置选项都是通过这个界面上的子菜单入口进入后进行选择和编辑的。

menuconfig同样是子菜单入口的关键字,和menu不一样的是,它定义的菜单入口可以被选择,然后可以通过if endif来把依赖于这个菜单入口的配置选项罗列出来,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
menuconfig EXPERT
    bool "Configure standard U-Boot features (expert users)"
    default y
    help
      This option allows certain base U-Boot options and settings
      to be disabled or tweaked. This is for specialized
      environments which can tolerate a "non-standard" U-Boot.
      Use this only if you really know what you are doing.

if EXPERT
    config SYS_MALLOC_CLEAR_ON_INIT
    bool "Init with zeros the memory reserved for malloc (slow)"
    default y
    help
      This setting is enabled by default. The reserved malloc
      memory is initialized with zeros, so first malloc calls
      will return the pointer to the zeroed memory. But this
      slows the boot time.

      It is recommended to disable it, when CONFIG_SYS_MALLOC_LEN
      value, has more than few MiB, e.g. when uses bzip2 or bmp logo.
      Then the boot time can be significantly reduced.
      Warning:
      When disabling this, please check if malloc calls, maybe
      should be replaced by calloc - if one expects zeroed memory.

config TOOLS_DEBUG
    bool "Enable debug information for tools"
    help
      Enable generation of debug information for tools such as mkimage.
      This can be used for debugging purposes. With debug information
      it is possible to set breakpoints on particular lines, single-step
      debug through the source code, etc.

endif # EXPERT

2.配置选项

1
2
3
config UBOOTVERSION
        string
        option env="UBOOTVERSION"

Kconfig使用关键字cofnig来定义配置选项,后面通过不同的关键字来定义配置属性,如下:

  • tristate、bool、hex、int、string
    • 配置选项类型
    • 语法: tristate/bool/hex/int/string
    • 后面如果紧跟“自定义提示符”,就可以省去prompt关键字描述
  • prompt
    • 配置选项提示语句
    • 语法:prompt “自定义提示语句”
  • default
    • 后面的值会作为配置选项的默认值
  • depend on
    • 向前依赖
    • 表示该配置选项是否可用是依赖于其他的配置选项的。
  • select
    • 向后依赖
    • 表示该配置选项的选择会导致其他配置选项被自动选择。
    • 界面中使用”{ }” 或者 “- -“来表示
  • option: env表示从环境变量中获取这个配置选项的值。
    • 语法:option env=”ENV_NAME”
  • range: 设置配置选项的合法取值范围,针对int和hex类型
    • 语法:”range” <最小值> <最大值>
  • help or —help—
    • 帮助文档
    • 语法: 关键字下面开始直到空行都是帮助说明的内容

3.多选一

Kconfig使用关键字choice和endchoice来组织一个选择列表,只能选中其中一个。

语法如下:

1
2
3
4
5
6
7
8
9
10
11
choice 
    prompt ""
    help
    ....

    config A
        bool 
    config B
        bool
    ...
endchoice

4.包含其他Kconfig文件

可以使用source关键字来包含其他Kconfig文件,相当于C语言的include。

语法:source “kconfig_file”

参考文章