PMON分析(4)- 引导内核

固件在完成上述相关CPU、设备环境初始化后,将完成它最后的使命就是引导内核,在initmips最后条用main,对你没有看错,就是那个main。

1、main函数

1> 获取环境变量ShowBootMenu,如设置了bootlist,则进入函数load_menu_list函数,在usb设备(U盘)、CD-ROM、sata盘中查找boot.cfg文件(把欲引导的内核的目录和传给内核的参数以一定的格式放在 boot.cfg 的文件),如找到,则执行do_cmd(load),引导内核完成启动。

2> 如没有找到boot.cfg文件,则获取环境变量al,运行autorun加载/dev/fs/iso9600@cd0/boot/vmlinux或者/dev/fs/ext2@wd0/boot/vmlinux下放置的内核,如下面没有内核,则进入pmon命令行。

3> 如进入命令行,则检测输入命令并判断是否为定义好的cmd命令,执行前面初始化好的cmd处理函数。

2、引导内核过程

do_cmd(“load /dev/fs/ext2@wd0/boot/vmlinux’)和do_cmd(“g console=tty root=/dev/hda1 no_auto_cmd’)简单的说,第一个调用会把那个 vmlinux 文件放到内存上某个位置,g 会执行那个文件。

CmdList的初始化???

 

bl -d ide /dev/fs/ext2@wd0/boot/boot.cfg =====> cmd_menu_list处理函数

cmd_menu_list =>show_main=>load_list_menu

show_main函数解析bl -d ide /dev/fs/ext2@wd0/boot/boot.cfg获取path值:

path:/dev/fs/ext2@wd0/boot/boot.cfg,调用load_list_menu。

在load_list_menu函数中,通过路径打开传入的cfg文件,并在menu_list_read函数中,将cfg文件中的信息保存,(1)将title、内核、参数、initrd以及root信息保存在全局结构体数组menu_items中。(2)将全局选项(如下menu_options)保存到全局变量menu_option中。

MenuOptions menu_options[] = {

        {"showmenu", 0, 0, "1"}, //是否给用户显示菜单

        {"default", 0, 0, "0"}, //默认执行的菜单

        {"timeout", 0, 0, "5"},//菜单原则事件

        {"password", 0, 1, ""},

        {"md5_enable", 0, 0, "0"},      /* 1-md5 */

};

typedef struct _Menu_Item_

{       

        char title      [MENU_TITLE_BUF_LEN + 1];       //Title of menu item, display on screen.

        char * kernel ; //kernel file to load.

        char * args     ;       //arguments for kernel.

        char * initrd ; //initrd file for kernel, maybe empty.

        char * root;    //ROOT device from args.

}Menu_Item;

 

typedef struct menu_option

{

        char option [OPTION_LEN + 1];

        int set_type;                           /* 0-unset£¬1-set */

        int use_default;         /* use defualt value, 0-if value don't used, use default, 1- must set */

        char value      [GLOBAL_VALUE_LEN + 1];

}MenuOptions;

show_main函数继续执行,从全局选项(如下menu_options)中获取默认启动的菜单条目以及菜单超时的默认时间。清屏并执行draw_main函数。

draw_main函数在屏幕上显示可选择的启动菜单以及提示信息。以后等待用户输入。当输入c时,退出菜单回到pmon命令行。当获取到上下键选择菜单,则根据选择得到启动的内核对应的条目。

最后调用do_cmd_boot_load函数加载启动内核。

do_cmd_boot_load=>boot_load=>boot_load_from_menu分别通过load_kernel_from_menu以及load_initrd_from_menu加载内核以及initrd。最后通过boot_run_from_menu函数运行内核。

1、在load_kernel_from_menu函数中,根据菜单选择的内核条目,传入对应的menu_items结构体数组成员。之后调用boot_kernel函数。

在boot_kernel函数中,根据传入的内核路径打开内核文件描述符。通过函数exec函数调用ep = (*p->loader) (fd, buf, n, flags))。这里的函数指针为Load_elf()函数在../pmon/loaders/exec_elf.c中

static void init_exec()

{

        /*

         * Install ram based file system.

         */

        exec_init(&srec_exec);

}

函数初始化。数据结构:

typedef struct ExecType {

        char *execname;

        long (*loader) __P((int , char *, int *, int ));

        int flags;

        SLIST_ENTRY(ExecType)   i_next;

} ExecType;

通过函数load_srec函数加载内核。内核入口Entry address is 80c02dd0。

  1. load_initrd_from_menu函数调用boot_initrd函数通过exec将initrd加载地址为0x84000000的内存中。
  2. 最后调用boot_run_from_menu函数,构造启动引导命令:g root=/dev/sda1 console=tty no_console_suspend console=ttyS0,115200 rw。执行do_cmd,跳转到相应注册到pmon的命令处理函数,这里跳转到cmd_go函数中来引导内核。

在cmd_go函数中,clientav指向命令行参数。调用initstack函数,进行一些重要的初始化。

在initstack函数中。计算传参长度以及bp长度设置栈大小。初始化struct boot_params(2k没有用)。调用setup_dtb(ac, av);解析dtb。

在setup_dtb函数中,检查DTB的地址以及checksum是否正常。将DTB数据拷贝到前面设置好的堆栈中。更新设备树中关于/chosen节点的数据,将命令行参数将其覆盖。

initstack函数返回,打印32个通用寄存器的值。设置状态寄存器以及硬件相关设置。更新配置pcie。执行goclient函数将控制权交给内核。至此pmon执行完毕。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值