常用一些東西
- 本文介紹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
- 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;
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類型合法性以及獲取一些信息
- 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函數,在這個函數中你對後面的參數解析啥的,就可以進行配置了。