日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux-内核启动流程分析

發(fā)布時(shí)間:2025/3/15 linux 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux-内核启动流程分析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
/******************************************************************************************/ 在主函數(shù) main_loop中下面兩行是啟動(dòng)內(nèi)核的過程# ifdef CONFIG_MENUKEYif (menukey == CONFIG_MENUKEY) {s = getenv("menucmd"); 1if (s) { # ifndef CFG_HUSH_PARSERrun_command (s, 0); 2#endif}} #endif

其中 getenv函數(shù)獲取的 run_command要執(zhí)行的指令就是bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0中的指令

下面這條指令是從nand讀取內(nèi)核:從哪里讀?—從kernel分區(qū)中讀取 == 0x00060000
讀到哪里去?—0x30007FC0
分區(qū)的名字不重要,分的名字僅僅代表的是,起始地址和長度而已
nand read.jffs2 0x30007FC0 0x00060000 == nand read.jffs2 0x30007FC0 0x00060000 0x00200000;
讀取的大小是 0x00200000 2M
使用 nand read.jffs2 可以不用頁對(duì)其就能夠進(jìn)行讀取的操作

bootm 0x30007FC0
0x30007FC0改地址只要不破,對(duì)咋堆棧等一些其他的信息就行,可以在隨意放入改動(dòng),其值會(huì)
賦值給uimage的內(nèi)核地址成員,因?yàn)閡image的頭部中有加載地址和入口地址,所以地址可以隨便放
內(nèi)核的加載地址是: 30008000
0x30008000 - 0x30007FC0 = 0x40 = 64字節(jié)
將環(huán)境變量中下載內(nèi)核的地址設(shè)置為 0x30007FC0 之后,下載的內(nèi)核就可以不用移動(dòng)直接使用了
因?yàn)閡image的頭部信息剛好是64字節(jié):

#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; /* 加載地址 表示內(nèi)核運(yùn)行的時(shí)候要先放在那里*/uint32_t ih_ep; /* 進(jìn)入地址,要運(yùn)行內(nèi)核直接跳到這個(gè)地址就行了*/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字節(jié)可以使用 mtd 命令查看;OpenJTAG> mtddevice nand0 <nandflash0>, # parts = 4#: name size offset mask_flags0: bootloader 0x00040000 0x00000000 01: params 0x00020000 0x00040000 02: kernel 0x00200000 0x00060000 03: root 0x0fda0000 0x00260000 0active partition: nand0,0 - (bootloader) 0x00040000 @ 0x00000000defaults: mtdids : nand0=nandflash0 mtdparts: mtdparts=nandflash0:256k@0(bootloader),128k(params),2m(kernel),-(root)

注:
因?yàn)樵谇度胧絣inux中沒有PC機(jī)中那種非常龐大的文件管理系統(tǒng),因此采用在源碼中將分區(qū)寫死的形式
為嵌入式linux中的文件進(jìn)行分區(qū)
文件中一般會(huì)有此種定義:
```bash
#define MTDPARTS_DEFAULT “mtdparts=nandflash0:256k@0(bootloader),”
“128k(params),”
“2m(kernel),”
“-(root)”

嵌入式內(nèi)核: uimage=頭部+真正的內(nèi)核 頭部是一個(gè)結(jié)構(gòu)體: ```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; /* 加載地址 表示內(nèi)核運(yùn)行的時(shí)候要先放在那里*/uint32_t ih_ep; /* 進(jìn)入地址,要運(yùn)行內(nèi)核直接跳到這個(gè)地址就行了*/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.然后會(huì)按照頭部信息移動(dòng)內(nèi)核到合適的地址
2.啟動(dòng)內(nèi)核
do_bootm_linux

u-boot 設(shè)置內(nèi)核啟動(dòng)參數(shù)
然后跳到內(nèi)核啟動(dòng)地址啟動(dòng)內(nèi)核
u-boot和內(nèi)核的參數(shù)交互使用的是將參數(shù)放置在和內(nèi)核約定好的地址(按照雙方約定好的格式進(jìn)行)
定義的格式是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

===============================================================================
主要是下面四個(gè)函數(shù):

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);函數(shù)體如下: setup_start_tag 函數(shù)的作用是將 地址執(zhí)行的前五個(gè)字節(jié)放置上相關(guān)信息 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; 參數(shù)放置在 30000100的地址處params->hdr.tag = ATAG_CORE; //#define ATAG_CORE 0x54410001params->hdr.size = tag_size (tag_core); // 等于 5//#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)// >> 2 右移 2 相當(dāng)于除以4struct tag_header {u32 size;u32 tag; };+struct tag_core {u32 flags; /* bit 0 = read-only */u32 pagesize;u32 rootdev; };= 20字節(jié)除以4之后剛好是5struct 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; };接下來就是將下面的參數(shù)按照順序裝進(jìn)內(nèi)存中去params->u.core.flags = 0;params->u.core.pagesize = 0;params->u.core.rootdev = 0;params = tag_next (params);做了一件事就是講 先后移動(dòng) 5 個(gè)字節(jié) //#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))}==========================================================================================================setup_memory_tags 函數(shù)體如下: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函數(shù):
char *commandline = getenv (“bootargs”);
bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
init=/linuxrc 第一個(gè)應(yīng)用程序是 linuxrc
root=/dev/mtdblock3 根文件系統(tǒng)位于第四個(gè)flash分區(qū)
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);函數(shù):static void setup_end_tag (bd_t *bd) {params->hdr.tag = ATAG_NONE;params->hdr.size = 0; }

=========================================================================================================
在這里設(shè)置好之后內(nèi)核會(huì)到這個(gè)地址來讀取這份參數(shù):

注:使用sourceinsight搜索變量的時(shí)候,將 search method設(shè)置成 --> Regular expression

內(nèi)核啟動(dòng);
//在這里啟動(dòng)內(nèi)核
//bi_arch_number 機(jī)器 ID
//運(yùn)行該函數(shù)之后 控制權(quán)就交給了 內(nèi)核

theKernel (0, bd->bi_arch_number, bd->bi_boot_params);

總結(jié)

以上是生活随笔為你收集整理的linux-内核启动流程分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。