SDFAT32 加载
4 Dec 2024
Read time: 3 minute(s)
SDFAT32 启动方式更为简单,不需要专业的烧录工具进行烧写,只需要将镜像文件复制到 SD 卡即可。
图 3.4 MMC 与 SD 卡启动差异
SDFAT32 是基于 MMC 建立的,加载程序也在 c 中实现,通过使用宏:
SPL_LOAD_IMAGE_METHOD(“MMC2”, 0, BOOT_DEVICE_MMC2, spl_mmc_load_image);
将 spl_mmc_load_image 函数添加到 .u_boot_list_2_spl_image_loader_* 段。
在 board_init_r(gd_t *dummy1, ulong
dummy2)函数中,会调用 devices 从 device 中去选择启动介质,通过启动介质选择对应的加载程序,获取启动镜像。
// source/uboot-2021.10/common/spl/spl.c
boot_from_devices
| // 这里会传递一个空的 info 结构体,以及传递一个启动设备的列表,这里为第一个值为 BOOT_DEVICE_MMC2
|->spl_ll_find_loader(bootdev); // bootdev=BOOT_DEVICE_MMC2,根据 bootdev 查找 spl_load_image 指针
|->spl_load_image(spl_image, loader); // 这里已经获取到对应启动设备的加载器
|->loader->load_image(spl_image, &bootdev); // 调用加载器的实现函数 spl_mmc_load_image
进入到对应启动介质的加载程序中,通过 NAME 指定启动镜像配置文件,从中获取镜像在 SD 卡中的实际地址。
// source/uboot-2021.10/common/spl/spl_fat.c
spl_mmc_load_image
|->spl_mmc_load(spl_image, bootdev,...); // 这里 CONFIG_SPL_FS_LOAD_PAYLOAD_NAME=bootcfg.txt
|->spl_mmc_find_device(&mmc, bootdev->boot_device); // 先找 mmc 设备
|->mmc_init(mmc); // 再进行 mmc 设备的初始化
|->spl_mmc_boot_mode(bootdev->boot_device);
| // 选择启动方式,这里获取到的是 FS 方式启动
|->spl_mmc_do_fs_boot(spl_image, mmc, filename); // filename 为 bootcfg.txt
|->aic_spl_load_image_fat(spl_image, mmc_get_blk_desc(mmc), filename);
|->blk_dread(cur_dev, 0, 1, header);
| // 读取 SD 卡的第 0 块。
|->check_identifier(header); // 检测 SD 卡的分区类型选择启动方式
|->load_image_from_mbr_part_fat32(header, filename); // 以 MBR 分区格式去加载镜像
|->blk_dread(cur_dev, part.lba_start, 1, header);
| // 读取 LBA 起始地址
|->check_identifier(header); // 检测 SD 卡分区类型是否为 FAT32
|->load_image_from_raw_volume_fat32(part.lba_start, header, filename);
| // 获取 BPB 内容
|->load_image_file(header, filename);
|->aic_fat_read_file(filename, (u8 *)header, 0, 1024, &actread);
| // 查找并读取 txt 文件内容到 header 地址
|->boot_cfg_parse_file((u8 *)header, actread, "boot1", ...);
| // 解析 txt 信息,获取 image 名称,解析 Boot 的大小,以及相对
| // image 文件中 Boot 所在的偏移地址
|->aic_fat_read_file(imgname, header, ...); //读取 image 文件的 header
|->spl_parse_image_header(spl_image, header);
| // 解析 Boot 中前 64 个字节内容,设置加载地址
|->aic_fat_read_file(imgname, (u8 *)spl_image->load_addr, ...);
| // 读取 Boot 镜像到 spl_image->load_addr 地址。
|->board_init_r(); // 跳转回 board_init_r()继续执行
读取 Boot 镜像到内存后,跳转回 board_init_r()继续执行
// source/uboot-2021.10/common/spl/spl.c
board_init_r()
|->spl_perform_fixups // vendor hook,用于修改 tree 传递参数
|->jump_to_image_no_args(&spl_image);
|->image_entry = (image_entry_withargs_t)spl_image->entry_point; // 获取 Boot 加载地址
|->set_boot_device(boot_param, aic_get_boot_device()); // 设置启动介质
|->set_boot_reason(boot_param, aic_get_boot_reason()); // 设置启动原因(冷启动或者热启动)
|->image_entry(boot_param, cur_tm); // 进入 Boot 执行,并传递一些参数