1. get_ram_size

get_ram_size只适用于CONFIG_SYS_DDR_SIZE=2^n

1int dram_init(void)
2{
3    gd->ram_size = get_ram_size((long *)CONFIG_SYS_SDRAM_BASE,
4                    CONFIG_SYS_DDR_SIZE);
5    return 0;
6}

2. 多核启动之spintable

U-Boo中需要开启ARMV8_MULTIENTRY,另外CPU_RELEASE_ADDR的值要与内核dtb的cpu-release-addr保持一致。

1#define CPU_RELEASE_ADDR   0x100000

3. FIT

FIT,支持打包多份dtb、randisk、内核镜像,指定每个镜像的地址,且支持压缩,支持多份config U-Boot启动时,可以根据U-Boot的dtb,找到FIT中对应的config,加载config指定的镜像

1/// func: fit_image_load
2if (IMAGE_ENABLE_BEST_MATCH && !fit_uname_config) {
3        cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob());
4} else {
5        cfg_noffset = fit_conf_get_node(fit,
6                                        fit_uname_config);
7}

可以使用dfu工具将生成的.idb文件,下载的memory的某个地址(没有特殊要求,例如0x100000),然后使用bootm命令即可启动,步骤包括:

  1. 使用iminfo命令,查看memory中存在的images和configurations。
  2. 使用bootm命令,执行默认配置,或者指定配置。

使用默认配置启动的话,可以直接使用bootm: bootm 0x100000 选择其它配置的话,可以指定配置名: bootm 0x100000#config@2

内存区域划分要求

  1. 内核镜像加载地址不能冲掉U-Boot代码段
  2. 内核reserve内存区域和FIT镜像指定的镜像加载地址不能冲突

dumpimage

1Usage: dumpimage [-T type] -l image
2          -l ==> list image header information
3          -T ==> parse image file as 'type'
4       dumpimage [-T type] [-p position] [-o outfile] image
5          -T ==> declare image type as 'type'
6          -p ==> 'position' (starting at 0) of the component to extract from image
7          -o ==> extract component to file 'outfile'
8       dumpimage -h ==> print usage information and exit
9       dumpimage -V ==> print version information and exit
  1#!/usr/bin/env python3
  2# -*- coding: utf-8 -*-
  3
  4import os
  5import sys
  6import subprocess
  7import argparse
  8
  9def get_dumpimage():
 10    cmd = 'which dumpimage'
 11    result = subprocess.check_output(cmd, shell=True)
 12    return result.decode('utf-8').strip()
 13
 14class DumpImage():
 15    def __init__(self, bootimg:str, dumpimage_exe:str='dumpimage'):
 16        self.dumpimage_exe = dumpimage_exe
 17        self.bootimg = bootimg
 18        self.buf_list = []
 19
 20    def get_img_list(self):
 21        cmd = f'{self.dumpimage_exe} -l {self.bootimg}'
 22        result = subprocess.check_output(cmd, shell=True)
 23        lines = result.decode('utf-8') # , errors='ignore')
 24
 25        buf = ''
 26        for line in lines.splitlines():
 27            tmp = line.lstrip()
 28
 29            if tmp.startswith('Image '):
 30                self.buf_list.append(buf)
 31                buf = ''
 32
 33            if tmp.startswith('Configuration '):
 34                self.buf_list.append(buf)
 35                buf = ''
 36
 37            if tmp.startswith('Default Configuration:'):
 38                self.buf_list.append(buf)
 39                buf = ''
 40
 41            buf += line + '\n'
 42
 43        self.buf_list.append(buf)
 44
 45    def get_name(self, img_index:int):
 46        for buf in self.buf_list:
 47            buf = buf.lstrip()
 48            if not buf.startswith(f'Image {img_index}'):
 49                continue
 50            line = buf.splitlines()[0]
 51            name = line.split(' ')[-1].lstrip('(').rstrip(')').strip()
 52            return name
 53
 54        return ''
 55
 56    def get_max(self):
 57        n_sum = 0
 58        for buf in self.buf_list:
 59            buf = buf.lstrip()
 60            if not buf.startswith(f'Image {n_sum}'):
 61                continue
 62            n_sum += 1
 63        return n_sum
 64
 65    def save_image(self, img_index:int, outdir:str='./'):
 66        outname = '{}.dump'.format(self.get_name(img_index))
 67        cmd = f'{self.dumpimage_exe} -T flat_dt -p {img_index} -o {outdir}/{outname} {self.bootimg}'
 68        result = subprocess.check_output(cmd, shell=True)
 69
 70        return True
 71
 72
 73def main(args):
 74    dimg_exe = get_dumpimage()
 75    if len(dimg_exe) == 0:
 76        print(f'dumpimage not found: {dimg_exe}')
 77        sys.exit(0)
 78
 79    if not os.path.exists(dimg_exe):
 80        print(f'dumpimage not found: {dimg_exe}')
 81        sys.exit(1)
 82
 83    if args.output:
 84        os.makedirs(args.output, exist_ok=True)
 85
 86    di = DumpImage(args.file, dimg_exe)
 87
 88    di.get_img_list()
 89    n_sum = di.get_max()
 90    for idx in range(n_sum):
 91        di.save_image(idx, args.output)
 92
 93    print(f'{n_sum} images saved.')
 94
 95if __name__ == '__main__':
 96    parser = argparse.ArgumentParser()
 97
 98    parser.add_argument('-o', '--output', default='./', type=str, help='output directory')
 99    parser.add_argument('file', type=str, help='input file')
100
101    args = parser.parse_args()
102    main(args)

3.1. Ramdisk

its文件中,rootfs压缩格式需要是none。

1/// fit_image_load
2if (image_type == IH_TYPE_RAMDISK && comp != IH_COMP_NONE)
3        puts("WARNING: 'compression' nodes for ramdisks are deprecated,"
4                " please fix your .its file!\n");

4. Ramdisk重定位

默认情况下,uboot会对Ramdisk进行重定位,可以使用如下方式取消重定位。

1setenv initrd_high 0xffffffffffffffff

5. Reserve内存

bootm时,uboot会读取内核dtb的reserve区域调用lmb_add进行reserve 核心函数:lmb_add_region 默认最对可reserve内存区域为8,#define MAX_LMB_REGIONS 8(u-boot/include/lmb.h)

6. OF_PLATDATA

OF_PLATDATA适用于SPL和TPL对体积要求比较严格,不能使用完整的DM情况。原理是将设备树内的数据转换为c代码后,将数据直接与可执行文件链接到一起,再在设备的probe函数中解析。这样在spl中,就不存在dtb格式的数据,而是用填充到udev私有数据对应的结构体中。

官方文档: u-boot/doc/driver-model/of-plat.rst

依赖:swig工具

dts中的节点,address-cells和size-cells需要为2(2020.07版,其他版本未知)

1#address-cells = <2>;
2#size-cells = <2>;

自动生成的用于描述dts中节点属性的结构体

1include/generated/dt-structs-gen.h
2struct dtd_XXXX

相关配置项

1CONFIG_SPL_DM
2
3CONFIG_SPL_OF_PLATDATA
4CONFIG_TPL_OF_PLATDATA
5
6
7CONFIG_IS_ENABLED(OF_PLATDATA)
8// 判断CONFIG_SPL_OF_PLATDATA或CONFIG_TPL_OF_PLATDATA是否使能
9// 没有CONFIG_OF_PLATDATA宏

6.1. 使用示例

 1U_BOOT_DRIVER(dmc_rk3399) = {
 2        .name = "rockchip_rk3399_dmc",
 3        .id = UCLASS_RAM,
 4        .of_match = rk3399_dmc_ids,
 5        .ops = &rk3399_dmc_ops,
 6#if defined(CONFIG_TPL_BUILD) || \
 7        (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
 8        .ofdata_to_platdata = rk3399_dmc_ofdata_to_platdata,
 9#endif
10        .probe = rk3399_dmc_probe,
11        .priv_auto_alloc_size = sizeof(struct dram_info),
12#if defined(CONFIG_TPL_BUILD) || \
13        (!defined(CONFIG_TPL) && defined(CONFIG_SPL_BUILD))
14        .platdata_auto_alloc_size = sizeof(struct rockchip_dmc_plat),
15#endif
16};

7. 设备树解析示例

如果在初始化设备树前调用of接口解析,会导致卡死。

1/// doc/driver-model/design.rst
2To reduce the size of SPL and TPL, only the nodes with pre-relocation properties
3('u-boot,dm-pre-reloc', 'u-boot,dm-spl' or 'u-boot,dm-tpl') are keept in their
4device trees (see README.SPL for details); the remaining nodes are always bound.

dts文件

1/ {
2    demo-node {
3        #address-cells = <1>;
4        #size-cells = <0>;
5        u-boot,dm-spl;  /* 在SPL中保留 */
6
7        key-word = <28>;
8    };
9};

C语言解析代码

 1int get_demo_node_value(const void *fdt)
 2{
 3    int demo_node = fdt_path_offset(fdt, "/demo-node");
 4    int val;
 5
 6    if (demo_node < 0)
 7        return demo_node;
 8
 9    val = fdtdec_get_int(fdt, demo_node, "key-word", -1);
10    if (val < 0)
11        return -1;
12
13    return val;
14}