查看: 2302|回复: 0

[原创] uboot 如何启动内核解析 + uboot 添加命令

[复制链接]
  • TA的每日心情
    开心
    2024-1-16 17:48
  • 签到天数: 592 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2019-6-9 13:42:46 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 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 是个宏,经过一系列分析:
    1. #define U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,                \
    2.                                 _usage, _help, _comp)                        \
    3.                 { #_name, _maxargs, _rep, _cmd, _usage,                        \
    4.                         _CMD_HELP(_help) _CMD_COMPLETE(_comp) }

    5. #define U_BOOT_CMD_MKENT(_name, _maxargs, _rep, _cmd, _usage, _help)        \
    6.         U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,                \
    7.                                         _usage, _help, NULL)

    8. #define U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp) \
    9.         ll_entry_declare(cmd_tbl_t, _name, cmd) =                        \
    10.                 U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd,        \
    11.                                                 _usage, _help, _comp);

    12. #define U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)                \
    13.         U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
    14.         
    15. #define ll_entry_declare(_type, _name, _list)                                \
    16.         _type _u_boot_list_2_##_list##_2_##_name __aligned(4)                \
    17.                         __attribute__((unused,                                \
    18.                         section(".u_boot_list_2_"#_list"_2_"#_name)))
    19.                         
    20. # define _CMD_HELP(x) x,

    21. # define _CMD_COMPLETE(x) x,

    22. struct cmd_tbl_s {
    23.         char                *name;                /* Command Name                        */
    24.         int                maxargs;        /* maximum number of arguments        */
    25.         int                repeatable;        /* autorepeat allowed?                */
    26.                                         /* Implementation function        */
    27.         int                (*cmd)(struct cmd_tbl_s *, int, int, char * const []);
    28.         char                *usage;                /* Usage message        (short)        */
    29. #ifdef        CONFIG_SYS_LONGHELP
    30.         char                *help;                /* Help  message        (long)        */
    31. #endif
    32. #ifdef CONFIG_AUTO_COMPLETE
    33.         /* do auto completion on the arguments */
    34.         int                (*complete)(int argc, char * const argv[], char last_char, int maxv, char *cmdv[]);
    35. #endif
    36. };

    37. typedef struct cmd_tbl_s        cmd_tbl_t;

    38. U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)
    39. = U_BOOT_CMD_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, NULL)
    40. = ll_entry_declare(cmd_tbl_t, _name, cmd) = U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp);
    41. = _type _u_boot_list_2_##_list##_2_##_name __aligned(4)  __attribute__((unused, section(".u_boot_list_2_"#_list"_2_"#_name)))
    42.                                           = U_BOOT_CMD_MKENT_COMPLETE(_name, _maxargs, _rep, _cmd, _usage, _help, _comp);
    43. = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _CMD_HELP(_help) _CMD_COMPLETE(_comp) }
    44. = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _help, _comp, }


    45. U_BOOT_CMD(_name, _maxargs, _rep, _cmd, _usage, _help)                                                  // U_BOOT_CMD 宏定义,是 U_BOOT_CMD_COMPLETE 的一个特例
    46. = _u_boot_list_2_##_list##_2_##_name = { #_name, _maxargs, _rep, _cmd, _usage, _help, _comp, }

    47. U_BOOT_CMD_COMPLETE                                                                                     // U_BOOT_CMD_COMPLETE 多一个参数
    复制代码
    其实还需要从 uboot main_loop 中分析,更清楚看到 U_BOOT_CMD 定义的宏是如何被调用使用的。
    得出的结论是:bootz 命令实际执行的是 do_bootz 函数,继续追踪:
    1. // ================================== bootz 解析
    2. bootz 0x83000000 - 0x84000000

    3. int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
    4. {
    5.         int ret;

    6.         /* Consume 'bootz' */
    7.         argc--; argv++;                                                                     调整 argc | argv 参数,去掉 bootz

    8.         if (bootz_start(cmdtp, flag, argc, argv, &images))                                  清空 image ,设置 verify,states,设置 image->ep 入口地址
    9.                                                                                             获取 ramdisk,fdt,设置 image.rd_addr / rd_len / image.ft_addr / ft_len
    10.                 return 1;

    11.         /*
    12.          * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
    13.          * disable interrupts ourselves
    14.          */
    15.         bootm_disable_interrupts();                                                         关中断,关网口,关usb

    16.         images.os.os = IH_OS_LINUX;
    17.         ret = do_bootm_states(cmdtp, flag, argc, argv,                                      设置 boot_fn = do_bootm_linux
    18.                               BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |                        设置 tag,开始tag,串口,commandline(bootargs),revision(cpuver), memory, initrd, board(空), end tag   ---- (BOOTM_STATE_OS_PREP)
    19.                               BOOTM_STATE_OS_GO,                                                    获取 machid(env), 获取 ft_addr/tag 地址,进入kernel_entry(0, machid, r2);    ---- (BOOTM_STATE_OS_FAKE_GO | BOOTM_STATE_OS_GO)
    20.                               &images, 1);

    21.         return ret;
    22. }
    复制代码
    详细内容看注释,最终调用 boot_jump_linux 函数,boot_jump_linux 又调用 kernel_entry(0, machid, r2); ,进入 kernel 程序的入口,之后就开始运行 kernel 代码了
    1. static void boot_jump_linux(bootm_headers_t *images, int flag)
    2. {
    3. #ifdef CONFIG_ARM64
    4.         void (*kernel_entry)(void *fdt_addr, void *res0, void *res1,
    5.                         void *res2);
    6.         int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

    7.         kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
    8.                                 void *res2))images->ep;

    9.         debug("## Transferring control to Linux (at address %lx)...\n",
    10.                 (ulong) kernel_entry);
    11.         bootstage_mark(BOOTSTAGE_ID_RUN_OS);

    12.         announce_and_cleanup(fake);

    13.         if (!fake) {
    14.                 do_nonsec_virt_switch();
    15.                 kernel_entry(images->ft_addr, NULL, NULL, NULL);
    16.         }
    17. #else
    18.         unsigned long machid = gd->bd->bi_arch_number;
    19.         char *s;
    20.         void (*kernel_entry)(int zero, int arch, uint params);
    21.         unsigned long r2;
    22.         int fake = (flag & BOOTM_STATE_OS_FAKE_GO);

    23.         kernel_entry = (void (*)(int, int, uint))images->ep;

    24.         s = getenv("machid");
    25.         if (s) {
    26.                 if (strict_strtoul(s, 16, &machid) < 0) {
    27.                         debug("strict_strtoul failed!\n");
    28.                         return;
    29.                 }
    30.                 printf("Using machid 0x%lx from environment\n", machid);
    31.         }

    32.         debug("## Transferring control to Linux (at address %08lx)" \
    33.                 "...\n", (ulong) kernel_entry);
    34.         bootstage_mark(BOOTSTAGE_ID_RUN_OS);
    35.         announce_and_cleanup(fake);

    36.         if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
    37.                 r2 = (unsigned long)images->ft_addr;
    38.         else
    39.                 r2 = gd->bd->bi_boot_params;

    40.         if (!fake) {
    41. #ifdef CONFIG_ARMV7_NONSEC
    42.                 if (armv7_boot_nonsec()) {
    43.                         armv7_init_nonsec();
    44.                         secure_ram_addr(_do_nonsec_entry)(kernel_entry,
    45.                                                           0, machid, r2);
    46.                 } else
    47. #endif
    48.                         kernel_entry(0, machid, r2);
    49.         }
    50. #endif
    51. }
    复制代码
    代码中用到的两个结构体,要给是 image , 一个是 tag,如下:
    1. // ================================
    2. typedef struct bootm_headers {
    3.         /*
    4.          * Legacy os image header, if it is a multi component image
    5.          * then boot_get_ramdisk() and get_fdt() will attempt to get
    6.          * data from second and third component accordingly.
    7.          */
    8.         image_header_t        *legacy_hdr_os;                /* image header pointer */
    9.         image_header_t        legacy_hdr_os_copy;        /* header copy */
    10.         ulong                legacy_hdr_valid;

    11. #if defined(CONFIG_FIT)
    12.         const char        *fit_uname_cfg;        /* configuration node unit name */

    13.         void                *fit_hdr_os;        /* os FIT image header */
    14.         const char        *fit_uname_os;        /* os subimage node unit name */
    15.         int                fit_noffset_os;        /* os subimage node offset */

    16.         void                *fit_hdr_rd;        /* init ramdisk FIT image header */
    17.         const char        *fit_uname_rd;        /* init ramdisk subimage node unit name */
    18.         int                fit_noffset_rd;        /* init ramdisk subimage node offset */

    19.         void                *fit_hdr_fdt;        /* FDT blob FIT image header */
    20.         const char        *fit_uname_fdt;        /* FDT blob subimage node unit name */
    21.         int                fit_noffset_fdt;/* FDT blob subimage node offset */

    22.         void                *fit_hdr_setup;        /* x86 setup FIT image header */
    23.         const char        *fit_uname_setup; /* x86 setup subimage node name */
    24.         int                fit_noffset_setup;/* x86 setup subimage node offset */
    25. #endif

    26. #ifndef USE_HOSTCC
    27.         image_info_t        os;                /* os image info */
    28.         ulong                ep;                /* entry point of OS */

    29.         ulong                rd_start, rd_end;/* ramdisk start/end */

    30.         char                *ft_addr;        /* flat dev tree address */
    31.         ulong                ft_len;                /* length of flat device tree */

    32.         ulong                initrd_start;
    33.         ulong                initrd_end;
    34.         ulong                cmdline_start;
    35.         ulong                cmdline_end;
    36.         bd_t                *kbd;
    37. #endif

    38.         int                verify;                /* getenv("verify")[0] != 'n' */

    39. #define        BOOTM_STATE_START        (0x00000001)
    40. #define        BOOTM_STATE_FINDOS        (0x00000002)
    41. #define        BOOTM_STATE_FINDOTHER        (0x00000004)
    42. #define        BOOTM_STATE_LOADOS        (0x00000008)
    43. #define        BOOTM_STATE_RAMDISK        (0x00000010)
    44. #define        BOOTM_STATE_FDT                (0x00000020)
    45. #define        BOOTM_STATE_OS_CMDLINE        (0x00000040)
    46. #define        BOOTM_STATE_OS_BD_T        (0x00000080)
    47. #define        BOOTM_STATE_OS_PREP        (0x00000100)
    48. #define        BOOTM_STATE_OS_FAKE_GO        (0x00000200)        /* 'Almost' run the OS */
    49. #define        BOOTM_STATE_OS_GO        (0x00000400)
    50.         int                state;

    51. #ifdef CONFIG_LMB
    52.         struct lmb        lmb;                /* for memory mgmt */
    53. #endif
    54. } bootm_headers_t;

    55. // -----------------------------------
    56. typedef struct image_header {
    57.         __be32                ih_magic;        /* Image Header Magic Number        */
    58.         __be32                ih_hcrc;        /* Image Header CRC Checksum        */
    59.         __be32                ih_time;        /* Image Creation Timestamp        */
    60.         __be32                ih_size;        /* Image Data Size                */
    61.         __be32                ih_load;        /* Data         Load  Address                */
    62.         __be32                ih_ep;                /* Entry Point Address                */
    63.         __be32                ih_dcrc;        /* Image Data CRC Checksum        */
    64.         uint8_t                ih_os;                /* Operating System                */
    65.         uint8_t                ih_arch;        /* CPU architecture                */
    66.         uint8_t                ih_type;        /* Image Type                        */
    67.         uint8_t                ih_comp;        /* Compression Type                */
    68.         uint8_t                ih_name[IH_NMLEN];        /* Image Name                */
    69. } image_header_t;

    70. // -----------------------------------
    71. typedef struct image_info {
    72.         ulong                start, end;                /* start/end of blob */
    73.         ulong                image_start, image_len; /* start of image within blob, len of image */
    74.         ulong                load;                        /* load addr for the image */
    75.         uint8_t                comp, type, os;                /* compression, type of image, os type */
    76.         uint8_t                arch;                        /* CPU architecture */
    77. } image_info_t;

    78. // -----------------------------------
    79. struct lmb {
    80.         struct lmb_region memory;
    81.         struct lmb_region reserved;
    82. };

    83. // -----------------------------------
    84. struct lmb_region {
    85.         unsigned long cnt;
    86.         phys_size_t size;
    87.         struct lmb_property region[MAX_LMB_REGIONS+1];
    88. };

    89. // -----------------------------------
    90. struct lmb_property {
    91.         phys_addr_t base;
    92.         phys_size_t size;
    93. };

    94. // -----------------------------------
    95. struct tag {
    96.         struct tag_header hdr;
    97.         union {
    98.                 struct tag_core                core;
    99.                 struct tag_mem32        mem;
    100.                 struct tag_videotext        videotext;
    101.                 struct tag_ramdisk        ramdisk;
    102.                 struct tag_initrd        initrd;
    103.                 struct tag_serialnr        serialnr;
    104.                 struct tag_revision        revision;
    105.                 struct tag_videolfb        videolfb;
    106.                 struct tag_cmdline        cmdline;

    107.                 /*
    108.                  * Acorn specific
    109.                  */
    110.                 struct tag_acorn        acorn;

    111.                 /*
    112.                  * DC21285 specific
    113.                  */
    114.                 struct tag_memclk        memclk;
    115.         } u;
    116. };
    117. struct tag_header {
    118.         u32 size;
    119.         u32 tag;
    120. };
    121. struct tag_core {
    122.         u32 flags;                /* bit 0 = read-only */
    123.         u32 pagesize;
    124.         u32 rootdev;
    125. };
    126. struct tag_mem32 {
    127.         u32        size;
    128.         u32        start;        /* physical start address */
    129. };
    130. struct tag_videotext {
    131.         u8                x;
    132.         u8                y;
    133.         u16                video_page;
    134.         u8                video_mode;
    135.         u8                video_cols;
    136.         u16                video_ega_bx;
    137.         u8                video_lines;
    138.         u8                video_isvga;
    139.         u16                video_points;
    140. };
    141. struct tag_ramdisk {
    142.         u32 flags;        /* bit 0 = load, bit 1 = prompt */
    143.         u32 size;        /* decompressed ramdisk size in _kilo_ bytes */
    144.         u32 start;        /* starting block of floppy-based RAM disk image */
    145. };
    146. struct tag_initrd {
    147.         u32 start;        /* physical start address */
    148.         u32 size;        /* size of compressed ramdisk image in bytes */
    149. };
    150. struct tag_serialnr {
    151.         u32 low;
    152.         u32 high;
    153. };
    154. struct tag_revision {
    155.         u32 rev;
    156. };
    157. struct tag_videolfb {
    158.         u16                lfb_width;
    159.         u16                lfb_height;
    160.         u16                lfb_depth;
    161.         u16                lfb_linelength;
    162.         u32                lfb_base;
    163.         u32                lfb_size;
    164.         u8                red_size;
    165.         u8                red_pos;
    166.         u8                green_size;
    167.         u8                green_pos;
    168.         u8                blue_size;
    169.         u8                blue_pos;
    170.         u8                rsvd_size;
    171.         u8                rsvd_pos;
    172. };
    173. struct tag_cmdline {
    174.         char        cmdline[1];        /* this is the minimum size */
    175. };
    176. struct tag_acorn {
    177.         u32 memc_control_reg;
    178.         u32 vram_pages;
    179.         u8 sounddefault;
    180.         u8 adfsdrives;
    181. };
    182. struct tag_memclk {
    183.         u32 fmemclk;
    184. };
    复制代码
    <完>

    看有的嵌入式培训教程中,往 uboot 添加自己的命令,也会当作培训的内容

    其实从本帖来看,可以更深层次的知道如何往 uboot 添加自己的命令。
    1,添加一个 name.c 文件, name 自己选               // 添加命令的源码文件

    2,修改 makefile ,把 name.c 添加作为目标           // 添加到 uboot 程序中

    3,打开 name.c 文件,使用 U_BOOT_CMD 定义一个自己的命令。      // 第一个参数就是 uboot 中使用的命令名字,第四个参数是函数名,函数也要自己实现
    uboot 中添加自己的命令就完成了。编译后进 uboot 看看有么有自己的命令,会不会执行。

    =============  demo

    1,添加 robe.c 文件
    1.png
    2,修改 makefile 文件,添加 robe.o 目标

    2.png
    3,编码实现 robe 命令

    3.png
    4,编译 uboot,烧录:

    4.png
    5,启动 uboot 查看有没有 robe 命令

    5.png
    6,运行 robe 命令看看会不会执行
    6.png
    本贴从更深层次分析 uboot 命令的实现,知道如何实现的之后,不用什么教程跟着感觉添加 CMD 命令就可以。

    <完>


    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /2 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-20 13:09 , Processed in 0.102531 second(s), 15 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.