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命令即可启动,步骤包括:
- 使用iminfo命令,查看memory中存在的images和configurations。
- 使用bootm命令,执行默认配置,或者指定配置。
使用默认配置启动的话,可以直接使用bootm:
bootm 0x100000
选择其它配置的话,可以指定配置名:
bootm 0x100000#config@2
内存区域划分要求
- 内核镜像加载地址不能冲掉U-Boot代码段
- 内核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}