常用一些东西
本文介绍boot在向内核跳转的时候如何传参数的
uboot的环境变量
bootargs=earlyprintk console=ttyS0,115200 rootwait nprofile_irq_duration=on root=/dev/ram0 rootfstype=ramfs rdinit=/linuxrc
bootcmd=run tftploadk
bootdelay=3
- uboot 往内核携带的参数就是bootargs携带的。
uboot跳转命令
-
bootz zimage
bootm booti 引导uimage image booti引导arm64的image
语法 bootx kernel rootfs dtb -
bootefi, bootp, nboot
这些启动的介质不一样先从某个地方加载完了后再跳转
efi分区 网络 nand
有些uboot支持文件系统,把内核、dtb打包进文件系统,uboot起来后先挂载文件系统吧内核读取出来到内存执行,这样升级直接uboot挂载文件U盘,pc上覆盖内核文件就可以。 -
我们常用的是uimage 用的最多也是bootm
bootm --》uimage内部包含dtb的话就可以直接bootm kernel地址 也能起来
bootm 命令解析
我们一般使用bootm 0x5800000 - 0x56000000 或者直接bootm 0x580000
uboot\cmd\bootm.c
U_BOOT_CMD(
bootm, CONFIG_SYS_MAXARGS, 1, do_bootm,
"boot application image from memory", bootm_help_text
);
do_bootm->
//判断有没有子命令这里发现并没有使用返回值 拿endp判断,因为bootm 0x5800000 后面带数字的话endp返回0 且simple_strtoul返回数值0x5800000
simple_strtoul(argv[0], &endp, 16);
//所以bootm最终调用do_bootm_states函数
int do_bootm_states {
ret = bootm_find_os(cmdtp, flag, argc, argv);//发现kernel判断kernel是什么类型的
}
----------------------------------
typedef struct image_header {
__be32 ih_magic; /* Image Header Magic Number */
__be32 ih_hcrc; /* Image Header CRC Checksum */
__be32 ih_time; /* Image Creation Timestamp */
__be32 ih_size; /* Image Data Size */
__be32 ih_load; /* Data Load Address */
__be32 ih_ep; /* Entry Point Address */
__be32 ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
- image_header_t 64字节的头
- 一般kernel类型IMAGE_FORMAT_LEGACY 可以看image 的第一个int 0x27051956
- 安卓类型magic ANDR_BOOT_MAGIC “ANDROID!”
- 校验magic,校验crc
bootm 的调用关系
static void boot_jump_linux(bootm_headers_t *images, int flag)
{
...
unsigned long machid = gd->bd->bi_arch_number;
char *s;
void (*kernel_entry)(int zero, int arch, uint params);
unsigned long r2;
int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
s = env_get("machid");
if (strict_strtoul(s, 16, &machid)
if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
r2 = (unsigned long)images->ft_addr;
else
r2 = gd->bd->bi_boot_params;
kernel_entry(0, machid, r2);
...
}
struct tag *params
从上面的分析的流程来看最终传给kernek的三个参数r2等于gd->bd->bi_boot_params
而这个参数是一个地址,这个地址是保存了一个struct tag *类型。
在函数setup_start_tag(gd->bd);对其进行了赋值
从函数中得知gd->bd->bi_boot_params的值是个地址,有点类似struct tag 数组的首params总是指向一块新的struct tag空间。
struct tag {
struct tag_header hdr;
union {
struct tag_core core;
struct tag_mem32 mem;
struct tag_videotext videotext;
struct tag_ramdisk ramdisk;
struct tag_initrd initrd;
struct tag_serialnr serialnr;
...
}
}
struct tag_header {
u32 size;
u32 tag; //各种标识
};
eg:
setup_commandline_tag(gd->bd, commandline); -》params->hdr.tag = ATAG_CMDLINE;
setup_revision_tag(¶ms); -》params->hdr.tag = ATAG_REVISION;
/* board revision */
#define ATAG_REVISION 0x54410007
/* command line: \0 terminated string */
#define ATAG_CMDLINE 0x54410009
所以r2在内核看来是设么?
r2是指向一块块struct tag类型的首地址
每一块大小不定,
但每一块中的struct tag_header hdr;成员变量记录了这个块的大小以及块(tag)的类型
内核对bootargs的处理
查看内核cmdline
内核启动打印有体现
或者proc
cmd来源
- 来源于uboot
- 来自于内核自身配置—变量
- 来源于dts 的chose选项
赋值处理
start_kernel-》setup_arch-》mdesc = setup_machine_fdt(__atags_pointer);
-》early_init_dt_scan_nodes();-》of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
-》
early_init_dt_scan_chosen-》p = of_get_flat_dt_prop(node, “bootargs”, &l);
内核对uboot传进来的tag的函数处理
setup_arch->setup_machine_tags
__atags_pointer-->汇编文件中指定等于r2的值
mdesc = setup_machine_fdt(__atags_pointer); 假如config_OF使能走这块
if (!mdesc)
mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);,无dtb走这块
//我们采用dtb只分析setup_machine_fdt
- 经过测试boot_command_line的值setup_machine_fdt处理后便有了
- boot_command_line先存dtb中的bootargs 在然后uboot中的bootargs
early_init_dt_scan_chosen
early_init_dt_scan_chosen{
p = of_get_flat_dt_prop(node, "bootargs", &l);//取dtb中的bootargs
if (p != NULL && l > 0)
strlcpy(data, p, min((int)l, COMMAND_LINE_SIZE));
#ifdef CONFIG_CMDLINE //这块是对CONFIG_CMDLINE 宏的处理
#if defined(CONFIG_CMDLINE_EXTEND)//在dtb中的bootargs追加CONFIG_CMDLINE
strlcat(data, " ", COMMAND_LINE_SIZE);
strlcat(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#elif defined(CONFIG_CMDLINE_FORCE)//完全替换 用CONFIG_CMDLINE(dtb不生效了)
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#else
/* No arguments from boot loader, use kernel's cmdl*/
if (!((char *)data)[0])
strlcpy(data, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif
#endif /* CONFIG_CMDLINE */
}
遗留问题
1.setup_machine_fdt处理后boot_command_line里面有值了,且等于dtb的bootargs + uboot的bootargs
2. 我uboot是不带dtb的,dtb是和kernel绑定的,在接续dtb的时候咋体现的ubootbootargs的
3. p = of_get_flat_dt_prop(node, "bootargs", &l);得到的东西就是含uboot的bootargs不理解
bootargs的应用
取bootargs的一个参数console=
kernel\kernel\printk\printk.c
mtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ramdisk),4M(jffs2),38272k(user),256k(env),384k(uboot)
这块内容参考linux内核模块化机制
,当我的cmdline中有console=的字符串是,内核自动调用console_setup函数,在这个函数中你对后面的参数解析啥的,就可以进行配置了。