生活随笔
收集整理的這篇文章主要介紹了
linux-内核启动流程分析
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在主函數(shù) main_loop中下面兩行是啟動(dòng)內(nèi)核的過程
# 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函數(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
typedef struct image_header
{ uint32_t ih_magic
; uint32_t ih_hcrc
; uint32_t ih_time
; uint32_t ih_size
; uint32_t ih_load
; uint32_t ih_ep
; uint32_t ih_dcrc
; uint8_t ih_os
; uint8_t ih_arch
; uint8_t ih_type
; uint8_t ih_comp
; uint8_t ih_name
[ IH_NMLEN
] ;
} image_header_t
;
總共
4 * 7 + 4 + 32 = 64 字節(jié)可以使用 mtd 命令查看;OpenJTAG
> mtddevice 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
: 256 k@
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
)
{ 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 #if defined (CONFIG_VFD) || defined (CONFIG_LCD)
extern ulong calc_fbsize
( void ) ;
static void setup_videolfb_tag
( gd_t
* gd
)
{ params
-> hdr
. tag
= ATAG_VIDEOLFB
; params
-> hdr
. size
= tag_size
( tag_videolfb
) ; params
-> u
. videolfb
. lfb_base
= ( u32
) gd
-> fb_base
; params
-> u
. videolfb
. lfb_size
= calc_fbsize ( ) ; params
= tag_next
( params
) ;
}
#endif #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
; params
-> hdr
. tag
= ATAG_CORE
; params
-> hdr
. size
= tag_size
( tag_core
) ; struct tag_header
{ u32 size
; u32 tag
;
} ; + struct tag_core
{ u32 flags
; u32 pagesize
; u32 rootdev
;
} ; = 20 字節(jié)除以
4 之后剛好是
5 struct tag_core
{ u32 flags
; 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
; struct tag_acorn acorn
; 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é)
} == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == == 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 ; for ( p
= commandline
; * p
== ' ' ; p
++ ) ; if ( * p
== '\0' ) return ; params
-> hdr
. tag
= ATAG_CMDLINE
; 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
) ; 函數(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ò),歡迎將生活随笔 推薦給好友。