常用一些東西

  • 本文介紹boot在向內核跳轉的時候如何傳參數的
  • uboot的環境變量
  • uboot跳轉命令
  • bootm 命令解析
  • bootm 的調用關係
  • struct tag *params
  • 內核對bootargs的處理
  • 查看內核cmdline
  • cmd來源
  • 賦值處理
  • 內核對uboot傳進來的tag的函數處理
  • setup_arch->setup_machine_tags
  • early_init_dt_scan_chosen
  • bootargs的應用

本文介紹boot在向內核跳轉的時候如何傳參數的

uboot的環境變量

bootargs=earlyprintk console=ttyS0,115200 rootwait nprofile_irq_duration=on root=/dev/ram0 rootfstype=ramfs rdinit=/linuxrc 
bootcmd=run tftploadk
bootdelay=3
  1. uboot 往內核攜帶的參數就是bootargs攜帶的。

uboot跳轉命令

  1. bootz zimage
    bootm booti 引導uimage image booti引導arm64的image
    語法 bootx kernel rootfs dtb
  2. bootefi, bootp, nboot
    這些啓動的介質不一樣先從某個地方加載完了後再跳轉
    efi分區 網絡 nand
    有些uboot支持文件系統,把內核、dtb打包進文件系統,uboot起來後先掛載文件系統吧內核讀取出來到內存執行,這樣升級直接uboot掛載文件U盤,pc上覆蓋內核文件就可以。
  3. 我們常用的是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;





do_bootm
         

          do_bootm_states
         

          ret = bootm_start(cmdtp, flag, argc, argv)
         

          ret = bootm_find_os(cmdtp, flag, argc, argv)
         

          ret = bootm_find_other(cmdtp, flag, argc, argv)
         

          lag = bootm_disable_interrupts();ret = bootm_load_os(images, 0)

根據uimage的64字節頭,判斷image類型合法性以及獲取一些信息


  1. image_header_t 64字節的頭
  2. 一般kernel類型IMAGE_FORMAT_LEGACY 可以看image 的第一個int 0x27051956
  3. 安卓類型magic ANDR_BOOT_MAGIC “ANDROID!”
  4. 校驗magic,校驗crc

bootm 的調用關係

將uboot kernel rootfs合成一個鏡像_#uboot

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

內核啓動打印有體現

將uboot kernel rootfs合成一個鏡像_Image_02


或者proc

將uboot kernel rootfs合成一個鏡像_賦值_03

cmd來源

  1. 來源於uboot
  2. 來自於內核自身配置—變量
  3. 來源於dts 的chose選項

將uboot kernel rootfs合成一個鏡像_#kernel_04

賦值處理

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 kernel rootfs合成一個鏡像_賦值_05

內核對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
  1. 經過測試boot_command_line的值setup_machine_fdt處理後便有了
  2. 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

將uboot kernel rootfs合成一個鏡像_文件系統_06


mtdparts=fc000000.nor_flash:1920k(linux),128k(fdt),20M(ramdisk),4M(jffs2),38272k(user),256k(env),384k(uboot)

將uboot kernel rootfs合成一個鏡像_#uboot_07

這塊內容參考linux內核模塊化機制 ,當我的cmdline中有console=的字符串是,內核自動調用console_setup函數,在這個函數中你對後面的參數解析啥的,就可以進行配置了。