前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >04.uboot分析之uboot启动内核

04.uboot分析之uboot启动内核

作者头像
嵌入式与Linux那些事
发布2021-05-20 15:04:28
1.4K0
发布2021-05-20 15:04:28
举报

首先要明确: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)"
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-01 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档