300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > linux-内核启动流程分析

linux-内核启动流程分析

时间:2023-05-19 17:28:01

相关推荐

linux-内核启动流程分析

/******************************************************************************************/在主函数 main_loop中下面两行是启动内核的过程# ifdef CONFIG_MENUKEYif (menukey == CONFIG_MENUKEY) {s = getenv("menucmd");1if (s) {# ifndef CFG_HUSH_PARSERrun_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_NMLEN32/* Image Name Length*/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*/uint32_tih_load;/* 加载地址 表示内核运行的时候要先放在那里*/uint32_tih_ep;/* 进入地址,要运行内核直接跳到这个地址就行了*/uint32_tih_dcrc;/* Image Data CRC Checksum*/uint8_tih_os;/* Operating System*/uint8_tih_arch;/* CPU architecture*/uint8_tih_type;/* Image Type*/uint8_tih_comp;/* Compression Type*/uint8_tih_name[IH_NMLEN];/* Image Name*/} image_header_t;总共 4*7+4+32 = 64字节可以使用 mtd 命令查看;OpenJTAG> mtddevice nand0 <nandflash0>, # parts = 4#: name size offsetmask_flags0: bootloader0x000400000x0000000001: params 0x000200000x0004000002: kernel 0x002000000x0006000003: root0x0fda00000x002600000active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000defaults:mtdids : nand0=nandflash0mtdparts: 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=头部+真正的内核头部是一个结构体:```ctypedef 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*/uint32_tih_load;/* 加载地址 表示内核运行的时候要先放在那里*/uint32_tih_ep;/* 进入地址,要运行内核直接跳到这个地址就行了*/uint32_tih_dcrc;/* Image Data CRC Checksum*/uint8_tih_os;/* Operating System*/uint8_tih_arch;/* CPU architecture*/uint8_tih_type;/* Image Type*/uint8_tih_comp;/* Compression Type*/uint8_tih_name[IH_NMLEN];/* Image Name*/} image_header_t;

1.然后会按照头部信息移动内核到合适的地址

2.启动内核

do_bootm_linux

u-boot 设置内核启动参数

然后跳到内核启动地址启动内核

u-boot和内核的参数交互使用的是将参数放置在和内核约定好的地址(按照双方约定好的格式进行)

定义的格式是TAG,地址是30000100

定义的TAG如下:

#ifdef CONFIG_INITRD_TAGstatic 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_TAGSstatic void setup_memory_tags (bd_t *bd);# endifstatic void setup_commandline_tag (bd_t *bd, char *commandline);#if 0static void setup_ramdisk_tag (bd_t *bd);#endif# ifdef CONFIG_INITRD_TAGstatic void setup_initrd_tag (bd_t *bd, ulong initrd_start,ulong initrd_end);# endifstatic 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_CORE0x54410001params->hdr.size = tag_size (tag_core); // 等于 5//#define tag_size(type)((sizeof(struct tag_header) + sizeof(struct type)) >> 2)// >> 2 右移 2 相当于除以4struct tag_header {u32 size;u32 tag;};+struct tag_core {u32 flags;/* bit 0 = read-only */u32 pagesize;u32 rootdev;};= 20字节除以4之后刚好是5struct tag_core {u32 flags;/* bit 0 = read-only */u32 pagesize;u32 rootdev;};struct tag {struct tag_header hdr;union {struct tag_corecore;struct tag_mem32mem;struct tag_videotextvideotext;struct tag_ramdiskramdisk;struct tag_initrdinitrd;struct tag_serialnrserialnr;struct tag_revisionrevision;struct tag_videolfbvideolfb;struct tag_cmdlinecmdline;/** Acorn specific*/struct tag_acornacorn;/** DC21285 specific*/struct tag_memclkmemclk;} 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; //54410009params->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);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。