zoukankan      html  css  js  c++  java
  • u-boot(五)内核启动


    title: u-boot(五)内核启动
    tags: linux
    date: 2018-09-26 19:58:05

    u-boot(五)内核启动

    概述

    启动命令:bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0,具体代码实现的重点是以下:

    1. s=getenv ("bootcmd") 获取环境变量

    2. run_command (s, 0); 启动内核,这个s=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0

    3. s就是先读出内核,再启动内核了

    备注 jffs2是一种文件格式,在这里并不需要文件格式,但是使用这个jffs2 可以不使用页对齐,如果使用nandread,需要考虑页对齐或者块对齐,最终会使用nand_read_opts

    • 我们也可以在u-boot 命令行直接输入boot来启动内核,但是实际的命令是一样的,是在cmd_bootm.c中调用do_bootd>run_command (getenv ("bootcmd"), flag)

    分区空间

    常见的内部空间布局如下:

    Bootloader Boot parameters Kernel Root filesystem
    u-boot,它会在内存的某个地方存放着内核启动的一些参数,也称为tag u-boot 参数,包含传递给内核的一些东西 内核 根文件系统

    嵌入式的FLASH没有实际的分区,所谓分区只是一个名称,具体的地址是写死的. 在include/configs/100ask24x0.h

    #define MTDIDS_DEFAULT "nand0=nandflash0"
    #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," 
                                "128k(params)," 
                                "2m(kernel)," 
                                "-(root)"
    

    这里定义了mtdparts分区,位于nandflash0bootloader大小是256k,从0开始,然后是128k大小的params,接下去是2M的kernel内核,剩余的都是root文件系统.

    内核文件格式

    Flash上存储的内核格式为uImage,包含了一个头部加真正的内核.

    /*
     * all data in network byte order (aka natural aka bigendian)
     */
    #define IH_NMLEN		32	/* Image Name Length		*/
    
    typedef struct image_header {
    	uint32_t	ih_magic;	/* Image Header Magic Number	*/
    	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
    	uint32_t	ih_time;	/* Image Creation Timestamp	*/
    	uint32_t	ih_size;	/* Image Data Size		*/
    	uint32_t	ih_load;	/* Data	 Load  Address		*/
    	uint32_t	ih_ep;		/* Entry Point Address		*/
    	uint32_t	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;
    
    • ih_load表示加载地址,表示内核应该放在哪里
    • ih_ep表示入口地址,表示跳转的地址,也就是内核代码段的入口,广义上的main入口

    内核复制跳转

    bootm会先判断内核是否在加载地址,否则先移动内核到指定的加载地址,然后跳转。

    命令中0x30007FC0 地址可以随便放,只要不破坏已经用到的信息就好, bootm命令如果发现当前内核并不在加载地址,需要移动内核到加载地址。do_bootm函数中memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); 移动内核。

    所以如果ih_load=我们内核的地址的时候,就不需要move,节省时间.jz2440 的加载地址是0x30008000,头部是64字节,所以,0x30008000-64=0x30007FC0,所以我们copy内核到0x30007FC0 .

    内核启动

    //在 bootm命令中有linux内核跳转,//lib_arm/armlinux.c-->do_bootm_linux
    do_bootm_linux  (cmdtp, flag, argc, argv,addr, len_ptr, verify);
    	//theKernel 就是uimage的头部中的入口地址
    	-theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
    	// 设置一些参数
        setup_start_tag (bd);
        setup_memory_tags (bd);
        setup_commandline_tag (bd, commandline);
        setup_end_tag (bd);
    	// 所以内核的入口参数
    	-theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
    
    

    机器ID

    theKernel (0, bd->bi_arch_number, bd->bi_boot_params);中的第二个参数是机器ID,内核通过比对机器ID判断是否支持启动.gd->bd->bi_arch_number = MACH_TYPE_S3C2440;

    启动参数

    内核跳转之前,同样需要设置内核的启动参数.内核的参数是按照tag组织的.也就是在某个地址(0x30000100,在100ask24x0.c中定义),按照某种格式存储,这种格式具体为【size....tagid....tag值】

    mark

    do_bootm_linux中有设置内存,命令行参数等,代码片段如下

    bd_t *bd = gd->bd;
    //设置起始的头
    setup_start_tag (bd);
    //设置内存
    setup_memory_tags (bd);
    setup_commandline_tag (bd, commandline);
    //....
    // 设置结束的id
    setup_end_tag (bd);
    

    具体有以下几种tag,代码中以联合体定义,这样方便使用同一个指针指向它,方便之处见setup_start_tag分析.

    //这个tag 就是一个包含了所有类型tag的一个联合体,是实际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_revision	revision;
    		struct tag_videolfb	videolfb;
    		struct tag_cmdline	cmdline;
    
    		/*
    		 * Acorn specific
    		 */
    		struct tag_acorn	acorn;
    
    		/*
    		 * DC21285 specific
    		 */
    		struct tag_memclk	memclk;
    	} u;
    };
    

    (起始tag)setup_start_tag

    static void setup_start_tag (bd_t *bd)
    {
        // 这个tag 就是一个包含了所有类型tag的一个联合体
        // 使用联合体之后,下面就可以使用 params->具体的tag类型
    	params = (struct tag *) bd->bi_boot_params;
    
    	params->hdr.tag = ATAG_CORE;
    	params->hdr.size = tag_size (tag_core);
        
        //tag_core 也就是接下去这三个参数了
        //tag_size =zise + tag + 实际的值
    	params->u.core.flags = 0;
    	params->u.core.pagesize = 0;
    	params->u.core.rootdev = 0;
        //指向下一个参数
    	params = tag_next (params);
    }
    
    #define tag_next(t)	((struct tag *)((u32 *)(t) + (t)->hdr.size))
    #define tag_size(type)	((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
    // 这里 tag_header就是 size+tag   , type 就是实际的tag的内容
    // tag_size就是包含 id 和 size 和 内容的大小了
    

    因为bd_t *bd = gd->bd;,所以搜索下gd->bd->bi_boot_params,也就是在board/100ask24x0/100ask24x0.c中定义,也就是说参数是放在0x30000100.

    gd->bd->bi_boot_params = 0x30000100;
    

    内存设置

    static void setup_memory_tags (bd_t *bd)
    {
    	int i;
    
    	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
    		params->hdr.tag = ATAG_MEM;
    		params->hdr.size = tag_size (tag_mem32);
    
    		params->u.mem.start = bd->bi_dram[i].start;
    		params->u.mem.size = bd->bi_dram[i].size;
    
    		params = tag_next (params);
    	}
    }
    

    搜索下gd->bd->bi_dram[0],同样在board/100ask24x0/100ask24x0.c定义

    int dram_init (void)
    {
        gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
        gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
    
        return 0;
    }
    #define PHYS_SDRAM_1		0x30000000 /* SDRAM Bank #1 */
    #define PHYS_SDRAM_1_SIZE	0x04000000 /* 64 MB */
    

    这个函数是在lib_arm/board.c中的init_sequence调用,也就是start_armboot中调用,也就是在u-boot(三)第一阶段的C中使用的

    根文件系统,启动程序,串口设备

    char *commandline = getenv ("bootargs");
    setup_commandline_tag (bd, commandline);
    
    static void setup_commandline_tag (bd_t *bd, char *commandline)
    {
    	char *p;
    
    	if (!commandline)
    		return;
    
    	/* eat leading white space */
    	for (p = commandline; *p == ' '; p++);
    
    	/* skip non-existent command lines so the kernel will still
    	 * use its default command line.
    	 */
    	if (*p == '')
    		return;
    
    	params->hdr.tag = ATAG_CMDLINE;
    	params->hdr.size =
    		(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
    
    	strcpy (params->u.cmdline.cmdline, p);
    
    	params = tag_next (params);
    }
    

    设置命令tag,多了参数commandline,源自环境变量bootargs查看下环境变量bootargs,使用print查看,也可搜索下代码

    "bootargs="	CONFIG_BOOTARGS			""
    //include/configs/100ask24x0.h
    #define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0"
    
    • root=/dev/mtdblock3表示根文件系统从第四个FLASH分区开始(从0开始计数)可以往上看分区空间
    • init=/linuxrc指示第一个应用程序
    • console=ttySAC0,内核打印信息从串口0 打印

    (结束)setup_end_tag

    设置结束标志

  • 相关阅读:
    1137. 第 N 个泰波那契数
    486. 预测赢家
    python函数—函数的参数+递归函数
    python函数—调用函数+定义函数
    Seize the day
    数学建模基础学习2-matlab + lingo
    Python基础--使用list和tuple+条件判断+使用dict和set
    经济学人精读丨中国的电子商务
    数学建模基础学习1
    C盘今天爆掉了,罪魁祸首--百度云管家
  • 原文地址:https://www.cnblogs.com/zongzi10010/p/10023681.html
Copyright © 2011-2022 走看看