/******************************************************************************************/
在主函数 main_loop中下面两行是启动内核的过程
# ifdef CONFIG_MENUKEY
if (menukey == CONFIG_MENUKEY) {
s = getenv("menucmd"); 1
if (s) {
# ifndef CFG_HUSH_PARSER
run_command (s, 0); 2
#endif
}
}
#endif
其中 getenv函数获取的 run_command要执行的指令就是bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0中的指令
下面这条指令是从nand读取内核:从哪里读?—从kernel分区中读取 == 0x00060000
读到哪里去?—0x30007FC0
分区的名字不重要,分的名字仅仅代表的是,起始地址和长度而已
nand read.jffs2 0x30007FC0 0x00060000 == nand read.jffs2 0x30007FC0 0x00060000 0x00200000;
读取的大小是 0x00200000 2M
使用 nand read.jffs2 可以不用页对其就能够进行读取的操作
bootm 0x30007FC0
0x30007FC0改地址只要不破,对咋堆栈等一些其他的信息就行,可以在随意放入改动,其值会
赋值给uimage的内核地址成员,因为uimage的头部中有加载地址和入口地址,所以地址可以随便放
内核的加载地址是: 30008000
0x30008000 - 0x30007FC0 = 0x40 = 64字节
将环境变量中下载内核的地址设置为 0x30007FC0 之后,下载的内核就可以不用移动直接使用了
因为uimage的头部信息刚好是64字节:
#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; /* 加载地址 表示内核运行的时候要先放在那里*/
uint32_t ih_ep; /* 进入地址,要运行内核直接跳到这个地址就行了*/
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;
总共 4*7+4+32 = 64字节
可以使用 mtd 命令查看;
OpenJTAG> mtd
device nand0 <nandflash0>, # parts = 4
#: name size offset mask_flags
0: bootloader 0x00040000 0x00000000 0
1: params 0x00020000 0x00040000 0
2: kernel 0x00200000 0x00060000 0
3: root 0x0fda0000 0x00260000 0
active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000
defaults:
mtdids : nand0=nandflash0
mtdparts: mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)
注:
因为在嵌入式linux中没有PC机中那种非常庞大的文件管理系统,因此采用在源码中将分区写死的形式
为嵌入式linux中的文件进行分区
文件中一般会有此种定义:
```bash
#define MTDPARTS_DEFAULT “mtdparts=nandflash0:256k@0(bootloader),”
“128k(params),”
“2m(kernel),”
“-(root)”
嵌入式内核: uimage=头部+真正的内核
头部是一个结构体:
```c
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; /* 加载地址 表示内核运行的时候要先放在那里*/
uint32_t ih_ep; /* 进入地址,要运行内核直接跳到这个地址就行了*/
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;
1.然后会按照头部信息移动内核到合适的地址
2.启动内核
do_bootm_linux
u-boot 设置内核启动参数
然后跳到内核启动地址启动内核
u-boot和内核的参数交互使用的是将参数放置在和内核约定好的地址(按照双方约定好的格式进行)
定义的格式是TAG,地址是30000100
定义的TAG如下:
#ifdef CONFIG_INITRD_TAG
static void setup_initrd_tag (bd_t *bd, ulong initrd_start, ulong initrd_end)
{
/* an ATAG_INITRD node tells the kernel where the compressed
* ramdisk can be found. ATAG_RDIMG is a better name, actually.
*/
params->hdr.tag = ATAG_INITRD2;
params->hdr.size = tag_size (tag_initrd);
params->u.initrd.start = initrd_start;
params->u.initrd.size = initrd_end - initrd_start;
params = tag_next (params);
}
#endif /* CONFIG_INITRD_TAG */
#if defined (CONFIG_VFD) || defined (CONFIG_LCD)
extern ulong calc_fbsize (void);
static void setup_videolfb_tag (gd_t *gd)
{
/* An ATAG_VIDEOLFB node tells the kernel where and how large
* the framebuffer for video was allocated (among other things).
* Note that a _physical_ address is passed !
*
* We only use it to pass the address and size, the other entries
* in the tag_videolfb are not of interest.
*/
params->hdr.tag = ATAG_VIDEOLFB;
params->hdr.size = tag_size (tag_videolfb);
params->u.videolfb.lfb_base = (u32) gd->fb_base;
/* Fb size is calculated according to parameters for our panel
*/
params->u.videolfb.lfb_size = calc_fbsize();
params = tag_next (params);
}
#endif /* CONFIG_VFD || CONFIG_LCD */
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG) || \
defined (CONFIG_VFD) || \
defined (CONFIG_LCD)
static void setup_start_tag (bd_t *bd);
# ifdef CONFIG_SETUP_MEMORY_TAGS
static void setup_memory_tags (bd_t *bd);
# endif
static void setup_commandline_tag (bd_t *bd, char *commandline);
#if 0
static void setup_ramdisk_tag (bd_t *bd);
#endif
# ifdef CONFIG_INITRD_TAG
static void setup_initrd_tag (bd_t *bd, ulong initrd_start,
ulong initrd_end);
# endif
static void setup_end_tag (bd_t *bd);
# if defined (CONFIG_VFD) || defined (CONFIG_LCD)
static void setup_videolfb_tag (gd_t *gd);
# endif
===============================================================================
主要是下面四个函数:
setup_memory_tags (bd_t *bd);
setup_memory_tags (bd_t *bd);
setup_commandline_tag (bd_t *bd, char *commandline);
setup_end_tag (bd_t *bd);
函数体如下:
setup_start_tag 函数的作用是将 地址执行的前五个字节放置上相关信息
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params; // bd->bi_boot_params = 30000100
//gd->bd->bi_boot_params = 0x30000100; 参数放置在 30000100的地址处
params->hdr.tag = ATAG_CORE; //#define ATAG_CORE 0x54410001
params->hdr.size = tag_size (tag_core); // 等于 5
//#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
// >> 2 右移 2 相当于除以4
struct tag_header {
u32 size;
u32 tag;
};
+
struct tag_core {
u32 flags; /* bit 0 = read-only */
u32 pagesize;
u32 rootdev;
};
= 20字节
除以4之后刚好是5
struct tag_core {
u32 flags; /* bit 0 = read-only */
u32 pagesize;
u32 rootdev;
};
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;
};
接下来就是将下面的参数按照顺序装进内存中去
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
做了一件事就是讲 先后移动 5 个字节
//#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
}==========================================================================================================
setup_memory_tags 函数体如下:
static void setup_memory_tags (bd_t *bd)
{
int i;
===========================================================
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;
}
==============================================================
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);
}
}
===================================================================================
setup_commandline_tag函数:
char *commandline = getenv (“bootargs”);
bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
init=/linuxrc 第一个应用程序是 linuxrc
root=/dev/mtdblock3 根文件系统位于第四个flash分区
console=ttySAC0 指定打印信息输出的地方 ttySAC0 --> 串口 0
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 == '\0')
return;
params->hdr.tag = ATAG_CMDLINE; //54410009
params->hdr.size =
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
=======================================================================================
setup_end_tag (bd_t *bd);函数:
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
=========================================================================================================
在这里设置好之后内核会到这个地址来读取这份参数:
注:使用sourceinsight搜索变量的时候,将 search method设置成 --> Regular expression
内核启动;
//在这里启动内核
//bi_arch_number 机器 ID
//运行该函数之后 控制权就交给了 内核
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);