TA的每日心情 | 开心 2024-11-20 21:23 |
---|
签到天数: 597 天 连续签到: 1 天 [LV.9]以坛为家II
|
本帖最后由 robe.zhang 于 2019-6-9 14:38 编辑
本文基于 米尔 mys_y6ull 开发板 uboot 源码 2016.03 版本:
uboot 启动 kernel 的指令是:bootz 0x83000000 - 0x84000000
bootz 是 uboot 的一个命令,可以在源码 uboot/cmd/bootm.c 中找到,如下:
U_BOOT_CMD(
bootz, CONFIG_SYS_MAXARGS, 1, do_bootz,
"boot Linux zImage image from memory", bootz_help_text
);
0x83000000 是 kernel 地址
- 是 initrd image 地址
0x84000000 是 fdt 地址
U_BOOT_CMD 是个宏,经过一系列分析:
- #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
- _usage, _help, _comp) \
- { #_name, _maxargs, _rep, _cmd, _usage, \
- _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
- #define U_BOOT_CMD_MKENT(_name, _maxargs, _rep, _cmd, _usage, _help) \
- U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
- _usage, _help, NULL)
- #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
- ll_entry_declare(cmd_tbl_t, _name, cmd) = \
- U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, \
- _usage, _help, _comp);
- #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) \
- U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
-
- #define ll_entry_declare(_type, _name, _list) \
- _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \
- __attribute__((unused, \
- section(".u_boot_list_2_"#_list"_2_"#_name)))
-
- # define _CMD_HELP(x) x,
- # define _CMD_COMPLETE(x) x,
- struct cmd_tbl_s {
- char *name; /* Command Name */
- int maxargs; /* maximum number of arguments */
- int repeatable; /* autorepeat allowed? */
- /* Implementation function */
- int (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
- char *usage; /* Usage message (short) */
- #ifdef CONFIG_SYS_LONGHELP
- char *help; /* Help message (long) */
- #endif
- #ifdef CONFIG_AUTO_COMPLETE
- /* do auto completion on the arguments */
- int (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
- #endif
- };
- typedef struct cmd_tbl_s cmd_tbl_t;
- U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)
- = U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
- = ll_entry_declare(cmd_tbl_t, _name, cmd) = U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp);
- = _type _u_boot_list_2_##_list##_2_##_name __aligned(4) __attribute__((unused, section(".u_boot_list_2_"#_list"_2_"#_name)))
- = U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp);
- = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
- = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _help, _comp, }
- U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help) // U_BOOT_CMD 宏定义,是 U_BOOT_CMD_COMPLETE 的一个特例
- = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _help, _comp, }
- U_BOOT_CMD_COMPLETE // U_BOOT_CMD_COMPLETE 多一个参数
复制代码 其实还需要从 uboot main_loop 中分析,更清楚看到 U_BOOT_CMD 定义的宏是如何被调用使用的。
得出的结论是:bootz 命令实际执行的是 do_bootz 函数,继续追踪:
- // ================================== bootz 解析
- bootz 0x83000000 - 0x84000000
- int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
- {
- int ret;
- /* Consume 'bootz' */
- argc--; argv++; 调整 argc | argv 参数,去掉 bootz
- if (bootz_start(cmdtp, flag, argc, argv, &images)) 清空 image ,设置 verify,states,设置 image->ep 入口地址
- 获取 ramdisk,fdt,设置 image.rd_addr / rd_len / image.ft_addr / ft_len
- return 1;
- /*
- * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
- * disable interrupts ourselves
- */
- bootm_disable_interrupts(); 关中断,关网口,关usb
- images.os.os = IH_OS_LINUX;
- ret = do_bootm_states(cmdtp, flag, argc, argv, 设置 boot_fn = do_bootm_linux
- BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO | 设置 tag,开始tag,串口,commandline(bootargs),revision(cpuver), memory, initrd, board(空), end tag ---- (BOOTM_STATE_OS_PREP)
- BOOTM_STATE_OS_GO, 获取 machid(env), 获取 ft_addr/tag 地址,进入kernel_entry(0, machid, r2); ---- (BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO)
- &images, 1);
- return ret;
- }
复制代码 详细内容看注释,最终调用 boot_jump_linux 函数,boot_jump_linux 又调用 kernel_entry(0, machid, r2); ,进入 kernel 程序的入口,之后就开始运行 kernel 代码了
- static void boot_jump_linux(bootm_headers_t *images, int flag)
- {
- #ifdef CONFIG_ARM64
- void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
- void *res2);
- int fake = (flag & BOOTM_STATE_OS_FAKE_GO);
- kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
- void *res2))images->ep;
- debug("## Transferring control to Linux (at address %lx)...\n",
- (ulong) kernel_entry);
- bootstage_mark(BOOTSTAGE_ID_RUN_OS);
- announce_and_cleanup(fake);
- if (!fake) {
- do_nonsec_virt_switch();
- kernel_entry(images->ft_addr, NULL, NULL, NULL);
- }
- #else
- 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);
- kernel_entry = (void (*)(int, int, uint))images->ep;
- s = getenv("machid");
- if (s) {
- if (strict_strtoul(s, 16, &machid) < 0) {
- debug("strict_strtoul failed!\n");
- return;
- }
- printf("Using machid 0x%lx from environment\n", machid);
- }
- debug("## Transferring control to Linux (at address %08lx)" \
- "...\n", (ulong) kernel_entry);
- bootstage_mark(BOOTSTAGE_ID_RUN_OS);
- announce_and_cleanup(fake);
- if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
- r2 = (unsigned long)images->ft_addr;
- else
- r2 = gd->bd->bi_boot_params;
- if (!fake) {
- #ifdef CONFIG_ARMV7_NONSEC
- if (armv7_boot_nonsec()) {
- armv7_init_nonsec();
- secure_ram_addr(_do_nonsec_entry)(kernel_entry,
- 0, machid, r2);
- } else
- #endif
- kernel_entry(0, machid, r2);
- }
- #endif
- }
复制代码 代码中用到的两个结构体,要给是 image , 一个是 tag,如下:
- // ================================
- typedef struct bootm_headers {
- /*
- * Legacy os image header, if it is a multi component image
- * then boot_get_ramdisk() and get_fdt() will attempt to get
- * data from second and third component accordingly.
- */
- image_header_t *legacy_hdr_os; /* image header pointer */
- image_header_t legacy_hdr_os_copy; /* header copy */
- ulong legacy_hdr_valid;
- #if defined(CONFIG_FIT)
- const char *fit_uname_cfg; /* configuration node unit name */
- void *fit_hdr_os; /* os FIT image header */
- const char *fit_uname_os; /* os subimage node unit name */
- int fit_noffset_os; /* os subimage node offset */
- void *fit_hdr_rd; /* init ramdisk FIT image header */
- const char *fit_uname_rd; /* init ramdisk subimage node unit name */
- int fit_noffset_rd; /* init ramdisk subimage node offset */
- void *fit_hdr_fdt; /* FDT blob FIT image header */
- const char *fit_uname_fdt; /* FDT blob subimage node unit name */
- int fit_noffset_fdt;/* FDT blob subimage node offset */
- void *fit_hdr_setup; /* x86 setup FIT image header */
- const char *fit_uname_setup; /* x86 setup subimage node name */
- int fit_noffset_setup;/* x86 setup subimage node offset */
- #endif
- #ifndef USE_HOSTCC
- image_info_t os; /* os image info */
- ulong ep; /* entry point of OS */
- ulong rd_start, rd_end;/* ramdisk start/end */
- char *ft_addr; /* flat dev tree address */
- ulong ft_len; /* length of flat device tree */
- ulong initrd_start;
- ulong initrd_end;
- ulong cmdline_start;
- ulong cmdline_end;
- bd_t *kbd;
- #endif
- int verify; /* getenv("verify")[0] != 'n' */
- #define BOOTM_STATE_START (0x00000001)
- #define BOOTM_STATE_FINDOS (0x00000002)
- #define BOOTM_STATE_FINDOTHER (0x00000004)
- #define BOOTM_STATE_LOADOS (0x00000008)
- #define BOOTM_STATE_RAMDISK (0x00000010)
- #define BOOTM_STATE_FDT (0x00000020)
- #define BOOTM_STATE_OS_CMDLINE (0x00000040)
- #define BOOTM_STATE_OS_BD_T (0x00000080)
- #define BOOTM_STATE_OS_PREP (0x00000100)
- #define BOOTM_STATE_OS_FAKE_GO (0x00000200) /* 'Almost' run the OS */
- #define BOOTM_STATE_OS_GO (0x00000400)
- int state;
- #ifdef CONFIG_LMB
- struct lmb lmb; /* for memory mgmt */
- #endif
- } bootm_headers_t;
- // -----------------------------------
- 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;
- // -----------------------------------
- typedef struct image_info {
- ulong start, end; /* start/end of blob */
- ulong image_start, image_len; /* start of image within blob, len of image */
- ulong load; /* load addr for the image */
- uint8_t comp, type, os; /* compression, type of image, os type */
- uint8_t arch; /* CPU architecture */
- } image_info_t;
- // -----------------------------------
- struct lmb {
- struct lmb_region memory;
- struct lmb_region reserved;
- };
- // -----------------------------------
- struct lmb_region {
- unsigned long cnt;
- phys_size_t size;
- struct lmb_property region[MAX_LMB_REGIONS+1];
- };
- // -----------------------------------
- struct lmb_property {
- phys_addr_t base;
- phys_size_t size;
- };
- // -----------------------------------
- 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_revision revision;
- struct tag_videolfb videolfb;
- struct tag_cmdline cmdline;
- /*
- * Acorn specific
- */
- struct tag_acorn acorn;
- /*
- * DC21285 specific
- */
- struct tag_memclk memclk;
- } u;
- };
- struct tag_header {
- u32 size;
- u32 tag;
- };
- struct tag_core {
- u32 flags; /* bit 0 = read-only */
- u32 pagesize;
- u32 rootdev;
- };
- struct tag_mem32 {
- u32 size;
- u32 start; /* physical start address */
- };
- struct tag_videotext {
- u8 x;
- u8 y;
- u16 video_page;
- u8 video_mode;
- u8 video_cols;
- u16 video_ega_bx;
- u8 video_lines;
- u8 video_isvga;
- u16 video_points;
- };
- struct tag_ramdisk {
- u32 flags; /* bit 0 = load, bit 1 = prompt */
- u32 size; /* decompressed ramdisk size in _kilo_ bytes */
- u32 start; /* starting block of floppy-based RAM disk image */
- };
- struct tag_initrd {
- u32 start; /* physical start address */
- u32 size; /* size of compressed ramdisk image in bytes */
- };
- struct tag_serialnr {
- u32 low;
- u32 high;
- };
- struct tag_revision {
- u32 rev;
- };
- struct tag_videolfb {
- u16 lfb_width;
- u16 lfb_height;
- u16 lfb_depth;
- u16 lfb_linelength;
- u32 lfb_base;
- u32 lfb_size;
- u8 red_size;
- u8 red_pos;
- u8 green_size;
- u8 green_pos;
- u8 blue_size;
- u8 blue_pos;
- u8 rsvd_size;
- u8 rsvd_pos;
- };
- struct tag_cmdline {
- char cmdline[1]; /* this is the minimum size */
- };
- struct tag_acorn {
- u32 memc_control_reg;
- u32 vram_pages;
- u8 sounddefault;
- u8 adfsdrives;
- };
- struct tag_memclk {
- u32 fmemclk;
- };
复制代码 <完>
看有的嵌入式培训教程中,往 uboot 添加自己的命令,也会当作培训的内容
其实从本帖来看,可以更深层次的知道如何往 uboot 添加自己的命令。
1,添加一个 name.c 文件, name 自己选 // 添加命令的源码文件
2,修改 makefile ,把 name.c 添加作为目标 // 添加到 uboot 程序中
3,打开 name.c 文件,使用 U_BOOT_CMD 定义一个自己的命令。 // 第一个参数就是 uboot 中使用的命令名字,第四个参数是函数名,函数也要自己实现
uboot 中添加自己的命令就完成了。编译后进 uboot 看看有么有自己的命令,会不会执行。
============= demo
1,添加 robe.c 文件
2,修改 makefile 文件,添加 robe.o 目标
3,编码实现 robe 命令
4,编译 uboot,烧录:
5,启动 uboot 查看有没有 robe 命令
6,运行 robe 命令看看会不会执行
本贴从更深层次分析 uboot 命令的实现,知道如何实现的之后,不用什么教程跟着感觉添加 CMD 命令就可以。
<完>
|
|