04.uboot分析之uboot启动内核

2021-05-20 15:04:28 浏览数 (1)

首先要明确:uboot目标是从flash读出内核(nand read.jffs2 0x30007FC0 kernel;),启动它(bootm 0x30007FC0)。

代码语言:javascript复制
/*从NAND读出内核:从哪里读,从kernel分区读
				放到哪里去:0x30007FC0(可以随便放)
nand read.jffs2  0x30007FC0  0x00060000 0x00200000*/
nand read.jffs2 0x30007FC0 kernel;
/*flash上存放的内核为uimage,uimage为头部 真正的内核*/
bootm 0x30007FC0

/*image_header 如下*/
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		*/
	/*bootm先读出头部,知道加载地址和入口地址。当真正的内核不位于加载地址时,会自动把内核放到加载地址,然后跳转到入口地址执行。*/
	/*所以可以随便放内核到某个地址。我们开发板的加载地址0x30008000	*/*/
	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;

/* Copy header so we can blank CRC field for re-calculation 读出头部*/
memmove (&header, (char *)addr, sizeof(image_header_t));

/**/
/* !(CONFIG_HW_WATCHDOG || CONFIG_WATCHDOG) data为真正内核,移动到ih_load地址 */
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

/*另外一种情况,不需要移动内核,内核刚好位于ih_load地址*/
/*为什么是0x30007FC0地址?0x30008000-0x30007FC0=64字节。头部刚好为64字节。 0x30007FC0 64字节刚好为加载地址0x30008000。不需要再次移动*/
		if(ntohl(hdr->ih_load) == data) {
			printf ("   XIP %s ... ", name);
		}

/*综上,bootm做的事情:1.移动内核到合适的地方(加载地址);2.启动。(do_bootm_linux)*/
/*内核也位于加载地址了,是不是就可以在入口地址启动内核了?不是!PC机启动时BIOS会检测内存,flash告诉内核*/
/*同样uboot也要告诉内核一些启动参数;之后才会跳到入口地址启动内核*/

	theKernel = (void (*)(int, int, uint))addr;
	/*hdr->ih_ep头部入口地址*/
	theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
	/*启动内核*/
	theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

/*启动内核:1.设置参数2.跳转到入口地址去*/
/*如何设置参数*/
/*uboot把内核读进来之后就启动他然后跳转到内核去,uboot就不存在了。uboot和内核之间如何交互数据。*/
/*在某个地址(和内核约定好的,开发板0x30000100)按某种格式(TAG)保存数据,内核启动后再去读出来。*/
	setup_start_tag (bd);
	setup_memory_tags (bd);
	setup_commandline_tag (bd, commandline);
	setup_end_tag (bd);

static void setup_start_tag (bd_t *bd)
{
	params = (struct tag *) bd->bi_boot_params;

	params->hdr.tag = ATAG_CORE;
	params->hdr.size = tag_size (tag_core);

	params->u.core.flags = 0;
	params->u.core.pagesize = 0;
	params->u.core.rootdev = 0;

	params = tag_next (params);

struct tag {
	struct tag_header hdr;
	union {
		struct tag_core core;
		struct tag_mem_range mem_range;
		struct tag_cmdline cmdline;
		struct tag_clock clock;
		struct tag_ethernet ethernet;
	} u;
};
}

分区概念: PC机可以给硬盘分区,但是嵌入式linux的flash没有分区表。所以我们只能在代码写死bootloader分区,kernel分区,root分区等。所谓的ubbot的分区,我们关心地址。在100ask24x0.h中已经写死,如下:

代码语言:javascript复制
/*分区位于nandflash0上,从0到256k为bootloader;接下来的128k为存放环境变量的params;接下来2m为kernel;剩下的为root。起始地址和大小很重要!*/
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," 
                            "128k(params)," 
                            "2m(kernel)," 
                            "-(root)"

0 人点赞