uboot源码分析——启动linux内核

来源:互联网 发布:知乎top50 编辑:程序博客网 时间:2024/05/29 03:57

如果板子启动以后不按任何键,将会默认启动Linux内核。

我们回到/common/main.c中,首先

s = getenv ("bootcmd");

然后

run_command (s, 0);

bootcmd是一个环境变量,它的值对应一些命令,用来启动linux

"bootcmd="CONFIG_BOOTCOMMAND "\0"

/include/configs/mini2440.h

#define CONFIG_BOOTCOMMAND"nfs 0x30008000 192.168.0.1:/home/tekkaman/working/nfs/zImage.img;bootm"

Nfs这种情况先不讨论,更一般的是这种:

#define CONFIG_BOOTCOMMAND"nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0;bootm"

这是两个命令,先看nand read.jffs2 0x30007FC0 kernel,这个命令的作用是从nandflashkernel分区中读取数据到SDRAM中的0x30007FC0

对于mini2440,将整块nandflash分成了很多个区:

/include/configs/mini2440.h

#define MTDPARTS_DEFAULT "mtdparts=nandflash0:384k(bootloader)," \"128k(params)," \"5m(kernel)," \"-(root)" 

所以从nand0地址开始:384KBuboot128KBparams5M的内核,然后是root

   还有另一条命令bootm,解析bootmuboot最终执行do_bootm函数(uboot怎么样对命令解析并执行的,前面讲过了)。

/common/cmd_bootm.c

/*******************************************************************//* bootm - boot application image from image in memory *//*******************************************************************/ 
<p>int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])</p><p>{</p><p>...</p><p>}</p>

参数:

cmdtp,命令结构体指针,指向bootm对应的命令结构体

flag,不了解

argc,参数的个数

argv,指向参数

 

do_bootm中首先会进行一些relocateddo_bootm_subcommand的操作,这些我们不关心,直接看bootm_start函数。

/common/cmd_bootm.c

static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){...}

参数不用介绍了,在这个文件中定义了一个全局的结构体变量

static bootm_headers_t images; /* pointers to os/initrd/fdt images */

/include/images.h

/* * Legacy and FIT format headers used by do_bootm() and do_bootm_<os>() * routines. */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. */<span style="color:#ff0000;">image_header_t*legacy_hdr_os;</span> /* image header pointer */<span style="color:#ff0000;">image_header_tlegacy_hdr_os_copy;</span>/* header copy */<span style="color:#ff0000;">ulong legacy_hdr_valid;</span>#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 */#endif #ifndef USE_HOSTCCimage_info_tos; /* os image info */ulong ep; /* entry point of OS */ ulong rd_start, rd_end;/* ramdisk start/end */ #ifdef CONFIG_OF_LIBFDTchar *ft_addr;/* flat dev tree address */#endifulong ft_len; /* length of flat device tree */ ulong initrd_start;ulong initrd_end;ulong cmdline_start;ulong cmdline_end;bd_t *kbd;#endif <span style="color:#ff0000;">int verify;</span> /* getenv("verify")[0] != 'n' */ #defineBOOTM_STATE_START(0x00000001)#defineBOOTM_STATE_LOADOS(0x00000002)#defineBOOTM_STATE_RAMDISK(0x00000004)#defineBOOTM_STATE_FDT (0x00000008)#defineBOOTM_STATE_OS_CMDLINE(0x00000010)#defineBOOTM_STATE_OS_BD_T(0x00000020)#defineBOOTM_STATE_OS_PREP(0x00000040)#defineBOOTM_STATE_OS_GO(0x00000080)int state; #ifndef USE_HOSTCCstruct lmblmb; /* for memory mgmt */#endif} bootm_headers_t;

我用红色标注了一些比较重要的成员。

看一下image_header_t结构体:

/* * Legacy format image header, * all data in network byte order (aka natural aka bigendian). */typedef struct image_header {uint32_tih_magic;/* Image Header Magic Number*/uint32_tih_hcrc;/* Image Header CRC Checksum*/uint32_tih_time;/* Image Creation Timestamp*/uint32_tih_size;/* Image Data Size */<span style="color:#ff0000;">uint32_tih_load;/* Data Load  Address */</span><span style="color:#ff0000;">uint32_tih_ep; /* Entry Point Address */</span>uint32_tih_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;


再回到bootm_start函数

首先将images清零,然后得到环境变量verify的值并判断是yes还是no,返回给images.verify


lmb_init(&images.lmb); mem_start = getenv_bootm_low();mem_size = getenv_bootm_size(); lmb_add(&images.lmb, (phys_addr_t)mem_start, mem_size); arch_lmb_reserve(&images.lmb);board_lmb_reserve(&images.lmb);

这几行是lmbLogical memory blocks)的相关操作

lmb_init(&images.lmb);images.lmb进行一些初始化,这个成员是干嘛的?可能以后会用到。(Logical memory blocks

mem_start = getenv_bootm_low(); mem_size = getenv_bootm_size();分别得到SDRAM的起始地址和大小。

Lmb的内容先略过,以后用到再说。

 

接下来执行

/* get kernel image header, start address and length */os_hdr = boot_get_kernel (cmdtp, flag, argc, argv,&images, &images.os.image_start, &images.os.image_len);

注释已经说得很明白了get kernel image header, start address and length 

首先判断if (argc < 2),如果是一个的话img_addr就采用默认的load_addr

ulong load_addr = CONFIG_SYS_LOAD_ADDR;/* Default Load Address */#defineCONFIG_SYS_LOAD_ADDR 0x30008000/* default load address*/

否则就将第二个参数转换成16进制的unsigned long

所以img_addr保存的是image的起始地址。

因为没有dataflash,所以 genimg_get_image (img_addr),不执行。

然后执行genimg_get_format,返回Image的格式。IMAGE_FORMAT_LEGACY或者IMAGE_FORMAT_FIT

如果返回的不是IMAGE_FORMAT_LEGACY,那么printf ("Wrong Image Type for %s command\n", cmdtp->name);

否则执行image_get_kernel函数,这个函数中有一些函数image_check_magicimage_check_hcrcimage_print_contentsimage_check_target_arch,这里做了一些检查和校验(magic numberCRC、架构),打印了一些image的相关信息。

然后执行image_get_type返回image的类型,这里应该是IH_TYPE_KERNELos_dataos_len作为输出参数,实参是&images.os.image_start,&images.os.image_len得到真正的Image(没有头部)的起始地址和长度

然后把image的头部拷贝到images->legacy_hdr_os_copy,这么做是防止kernel解压的时候将头部覆盖。

然后将images->legacy_hdr_os指向image

跳出boot_get_kernel,然后根据genimg_get_format (os_hdr)得到image的格式,对images.os的成员进行赋值。

然后执行images.ep = image_get_ep (&images.legacy_hdr_os_copy);得到entry point

最后执行images.os.start = (ulong)os_hdr;os_hdr是前面返回的load address

bootm_start函数执行完毕,返回do_bootm



然后disable_interruptsicache_disabledcache_disable

执行

bootm_load_os(images.os, &load_end, 1);

参数:

images.osos相关的结构体,前面有对它的初始化

load_end前面定义为0,这里显然是作为输出参数。

1表示boot_progress

根据os.comp的类型来解压缩,将镜像的数据从images.os.image_start复制到images.os.load  打印:Loading Kernel Image ... OK  

接下来看非常重要的一步:

boot_fn = boot_os[images.os.os];


先看boot_fndo_bootm中定义

boot_os_fn*boot_fn;

看一下boot_os_fn

/* *  Continue booting an OS image; caller already has: *  - copied image header to global variable `header' *  - checked header magic number, checksums (both header & image), *  - verified image architecture (PPC) and type (KERNEL or MULTI), *  - loaded (first part of) image to header load address, *  - disabled interrupts. */typedef int boot_os_fn (int flag, int argc, char *argv[],bootm_headers_t *images); /* pointers to os/initrd/fdt */

所以boot_fn是一个函数指针,参数是:

int flag

int argc

char *argv[]

bootm_headers_t *images


再看boot_os,他是一个函数指针数组

static boot_os_fn *boot_os[] = {#ifdef CONFIG_BOOTM_LINUX[IH_OS_LINUX] = do_bootm_linux,#endif#ifdef CONFIG_BOOTM_NETBSD[IH_OS_NETBSD] = do_bootm_netbsd,#endif#ifdef CONFIG_LYNXKDI[IH_OS_LYNXOS] = do_bootm_lynxkdi,#endif#ifdef CONFIG_BOOTM_RTEMS[IH_OS_RTEMS] = do_bootm_rtems,#endif#if defined(CONFIG_CMD_ELF)[IH_OS_VXWORKS] = do_bootm_vxworks,[IH_OS_QNX] = do_bootm_qnxelf,#endif#ifdef CONFIG_INTEGRITY[IH_OS_INTEGRITY] = do_bootm_integrity,#endif};

boot_os[images.os.os]就表示do_bootm_linux

所以boot_fn指向函数do_bootm_linux

boot_fn(0, argc, argv, &images);

就是执行do_bootm_linux(0, argc, argv, &images);

do_bootm_linux函数,

首先定义了一个函数指针

void(*theKernel)(int zero, int arch, uint params);

Commandline指向bootargs的值。

theKernel = (void (*)(int, int, uint))images->ep; //将入口地址ep赋值给theKernel 

接下来是设置tag

#if defined (CONFIG_SETUP_MEMORY_TAGS) || \    defined (CONFIG_CMDLINE_TAG) || \    defined (CONFIG_INITRD_TAG) || \    defined (CONFIG_SERIAL_TAG) || \    defined (CONFIG_REVISION_TAG) || \    defined (CONFIG_LCD) || \    defined (CONFIG_VFD)setup_start_tag (bd);#ifdef CONFIG_SERIAL_TAGsetup_serial_tag (¶ms);#endif#ifdef CONFIG_REVISION_TAGsetup_revision_tag (¶ms);#endif#ifdef CONFIG_SETUP_MEMORY_TAGSsetup_memory_tags (bd);#endif#ifdef CONFIG_CMDLINE_TAGsetup_commandline_tag (bd, commandline);#endif#ifdef CONFIG_INITRD_TAGif (images->rd_start && images->rd_end)setup_initrd_tag (bd, images->rd_start, images->rd_end);#endif#if defined (CONFIG_VFD) || defined (CONFIG_LCD)setup_videolfb_tag ((gd_t *) gd);#endifsetup_end_tag (bd);#endif /* we assume that the kernel is in place */printf ("\nStarting kernel ...\n\n"); //#ifdef CONFIG_USB_DEVICE#if 0{extern void udc_disconnect (void);udc_disconnect ();}#endif

 

设置完参数以后调用theKernel (0, machid, bd->bi_boot_params);

到入口地址启动内核。

 

 

 

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 下载旧版本微信闪退登陆不了怎么办 企业微信一直登录失败怎么办 360浏览器9.1经常卡死怎么办 手机版爱奇艺看电影屏幕变小怎么办 找不到旧版本米聊怎么办 苹果id被锁了怎么办 新浪微博支付宝解绑失败怎么办 阿里妈妈升级看不到引流人数怎么办 阿里妈妈账号被冻结怎么办 微博昵称到次数怎么办 五星好评之后忘记截图了怎么办 评价后忘了截图怎么办 好评率太低不能买东西了怎么办 淘宝评价被删了怎么办 淘宝店铺有流量没有成交怎么办 淘宝好评被删了怎么办 淘宝评论被系统删除怎么办 淘宝被商家删除评价怎么办 淘宝评价管理商家删除了怎么办 淘宝商家删除评价我该怎么办 我的评价隐藏了怎么办 淘宝把评论删了怎么办 淘宝虚假交易被删除评价怎么办 淘宝好评评错了怎么办 被淘宝骗了好评怎么办 美团好评被删了怎么办 卖家收到好评内容是差评怎么办 淘宝收货电话写错了怎么办 淘宝评价写错了怎么办 饿了么商家差评怎么办 淘宝不给补差价怎么办 淘宝顾客给差评怎么办 淘宝买家账号体检违规怎么办 买家淘宝账户体检中心违规怎么办 淘宝卖家电话骚扰该怎么办 手机欠费销户了怎么办 想下载好多个淘宝怎么办 送快递不记得路怎么办 淘宝物流弄丢了怎么办 邮政快递碰上难缠客户怎么办 举证工伤对方不签收怎么办