<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > 嵌入式Linux之我行——u-boot-2009.08在2440上的移植詳解(六)

嵌入式Linux之我行——u-boot-2009.08在2440上的移植詳解(六)

作者: 時(shí)間:2016-11-20 來(lái)源:網(wǎng)絡(luò ) 收藏

一、移植環(huán)境

本文引用地址:http://dyxdggzs.com/article/201611/319007.htm
  • 機:VMWare--Fedora 9
  • 開(kāi)發(fā)板:Mini2440--64MB Nand,Kernel:2.6.30.4
  • 編譯器:arm123.com.cn/linux/arm-linux-gcc-4.3.2.tgz" target="_blank">arm-linux-gcc-4.3.2.tgz
  • u-boot:u-boot-2009.08.tar.bz2

二、移植步驟

10)u-boot利用tftp服務(wù)下載內核和利用nfs服務(wù)掛載nfs文件系統。
知識點(diǎn):
  1. tftp服務(wù)的安裝與配置及測試;
  2. nfs服務(wù)的安裝與配置及測試;
  3. u-boot到kernel的參數傳遞(重點(diǎn))。

我們知道使用tftp下載內核和使用nfs掛載文件系統的好處是,當我們重新編譯內核或文件系統后不用重新把這些鏡像文件再燒錄到flash上,而是把這些鏡像文件放到開(kāi)發(fā)主機的tftp或nfs服務(wù)的主目錄下,通過(guò)網(wǎng)絡(luò )來(lái)加載他們,不用頻繁的往flash上燒,這樣一可以保護flash的使用壽命,二可以方便的調試內核或文件系統,提高開(kāi)發(fā)效率??梢?jiàn),讓u-boot實(shí)現這個(gè)功能是一件很有意義的事情。

實(shí)現這樣的功能很簡(jiǎn)單,網(wǎng)上也有很多資料。但有很多細節的東西如果稍不注意就導致失敗,這里就結合本人實(shí)現的過(guò)程進(jìn)行講述和一些問(wèn)題的分析。

  • tftp服務(wù)的安裝與配置及測試

要使用tftp服務(wù)及測試它要安裝兩個(gè)軟件包,一個(gè)就是tftp服務(wù)器,另外一個(gè)就是tftp客戶(hù)端,這里安裝客戶(hù)端只是用于在主機本地測試tftp服務(wù)器是否正常運行的,來(lái)確保u-boot能夠訪(fǎng)問(wèn)tftp服務(wù)(u-boot中已有tftp客戶(hù)端的功能,其實(shí)在前面幾篇中都已經(jīng)使用了tftp下載內核或文件系統到開(kāi)發(fā)板上,如果那里都做到了,這里就可以直接跳過(guò))。

首先使用rpm命令查看你的主機上是否已經(jīng)安裝了tftp服務(wù)器和客戶(hù)端,如果沒(méi)有安裝就去下載這兩個(gè)軟件包進(jìn)行安裝或者可以使用yum命令進(jìn)行在線(xiàn)安裝,yum會(huì )自動(dòng)的去搜索適合你主機平臺的最新軟件包進(jìn)行下載安裝,如果主機已經(jīng)安裝了,則會(huì )提示軟件包已經(jīng)安裝了最新的版本。如下圖所示:

配置tftp服務(wù)器,主要是配置tftp的主目錄及訪(fǎng)問(wèn)權限。因tftp服務(wù)依賴(lài)于xinetd服務(wù),所以一般tftp服務(wù)安裝好后其配置文件一般會(huì )在/etc/xinetd.d/目錄下:

[root@localhosthome]# vi /etc/xinetd.d/tftp

service tftp
{
disable=no
socket_type=dgram
protocol=udp
wait=yes
user=root
server=/usr/sbin/in.tftpd
server_args=-s/home/tftp-root-c//主要是修改這里,指定tftp服務(wù)器的主目錄,-c選項是指可以創(chuàng )建文件
per_source=11
cps=100 2
flags=IPv4
}

創(chuàng )建剛才指定的tftp服務(wù)器主目錄,也要注意主目錄的可讀可寫(xiě)的權限:

[root@localhosthome]#mkdir /home/tftp-root
[root@localhosthome]#chmod 777 /home/tftp-root

啟動(dòng)和測試tftp服務(wù):

[root@localhosthome]#service xinetd restart //重啟xinetd服務(wù)就會(huì )啟動(dòng)其下的所有服務(wù),也包括tftp服務(wù)
[root@localhosthome]#service iptables stop //關(guān)閉防火墻
[root@localhosthome]#tftp 主機IP地址
tftp>get要下載的文件

tftp>put要上傳的文件

tftp>q
[root@localhosthome]#

  • nfs服務(wù)的安裝與配置及測試

以root的身份在控制臺輸入setup,在系統服務(wù)選項中選中nfs服務(wù),如下圖:

配置NFS服務(wù)器的共享主目錄,也要注意權限問(wèn)題:

[root@localhost home]#vi /etc/exports//如果沒(méi)有這個(gè)文件就創(chuàng )建它,添加下面一行配置信息,注意格式一定要正確,否則導致服務(wù)不正常

/home/filesystem *(rw,no_root_squash,sync)

注釋?zhuān)?ldquo;/home/filesystem”是NFS服務(wù)器的主目錄,注意目錄的權限

“*”表示所有的IP都可以訪(fǎng)問(wèn)NFS主目錄

“rw”表示可讀可寫(xiě)

”no_root_squash“表示登入到NFS主機的用戶(hù)如果是ROOT用戶(hù),他就擁有ROOT的權限

“sync”表示同步

[root@localhost home]#service nfs restart//重新啟動(dòng)NFS服務(wù),使配置文件生效

測試NFS服務(wù)是否正常。將事先準備好的文件系統放到NFS主目錄下,如下:

[root@localhost home]# ls /home/filesystem/
bin dev home lib mnt root sum100 tmp var
debug etc hostname linuxrc proc sbin sys usr
[root@localhost home]#

//在主機本地測試NFS服務(wù),將NFS主目錄下的文件系統掛載到/mnt目錄下,192.168.1.101是主機的IP

[root@localhost home]#mount -o nolock -t nfs 192.168.1.101:/home/filesystem /mnt

可以看到/mnt目錄下的內容和NFS主目錄/home/filesystem下的內容完全一致,說(shuō)明NFS服務(wù)正常:

  • u-boot到kernel的參數傳遞

我們知道,在kernel配置選項Boot options中有一個(gè)Default kernel command string參數項,而在u-boot參數中也有一個(gè)bootargs參數項,他們都是供內核啟動(dòng)用的,那他們又有什么區別呢,內核啟動(dòng)時(shí)到底是用哪一個(gè)呢??jì)煞N參數項分別如下圖所示(kernel中的參數指定是從開(kāi)發(fā)板Flash分區上掛載文件系統,u-boot中的參數指定的是從NFS掛載文件系統):

實(shí)際上,內核中的參數項是內核默認提供的,在內核配置時(shí)去指定,而u-boot提供的則在u-boot啟動(dòng)時(shí)傳遞到內核中取代內核提供的參數。所以當u-boot沒(méi)有提供bootargs參數時(shí),內核啟動(dòng)就是用內核配置時(shí)指定的參數,當u-boot提供了bootargs參數時(shí)就使用u-boot的參數。

那么,u-boot是如果將參數信息傳遞到內核中的呢?而內核又是怎么接收u-boot傳遞過(guò)來(lái)的參數呢?這就涉及到一點(diǎn)點(diǎn)ARM寄存器的知識了。

我們知道,ARM有7種工作模式和37個(gè)寄存器(31個(gè)通用寄存器和6個(gè)狀態(tài)寄存器),如下圖:

ARM工作模式之間的轉換就是利用這些寄存器進(jìn)行,而u-boot參數的傳遞也利用了三個(gè)通用寄存器R0、R1和R2。關(guān)于A(yíng)RM工作模式和寄存器在這里就不做講敘了,以后再講,這里你就理解成u-boot在啟動(dòng)的時(shí)候把參數存放到這三個(gè)寄存器中,到內核啟動(dòng)時(shí)再把寄存器中的參數取出,當然,他們并不是就這樣簡(jiǎn)單的操作。下面我們看代碼一一分析。

首先,我們來(lái)分析一下u-boot是怎樣處理和發(fā)送要傳遞的參數,而u-boot要傳遞的參數又有哪些呢?除了我們最容易知道的bootargs(即內核commandline)參數項外,要傳遞的參數還有MACH_TYPE(即我們所說(shuō)的機器碼)、系統根設備信息(標志,頁(yè)面大小)、內存信息(起始地址,大小)、RAMDISK信息(起始地址,大小)、壓縮的RAMDISK根文件系統信息(起始地址,大小)。由此可見(jiàn)要傳遞的參數很多,這時(shí)候,u-boot就提供一種叫做參數鏈表(tagged list)的方式把這些參數組織起來(lái),鏈表結構體定義在:include/asm-arm/setup.h中,而實(shí)現鏈表的組織在lib_arm/bootm.c中:

我們可以看到,鏈表的組織是由一系列函數實(shí)現,u-boot規定,鏈表必須以ATAG_CORE標記開(kāi)始,以ATAG_NONE標記結束,中間就是一些參數標記項,這點(diǎn)從代碼中可以體現出來(lái)。那么在這些函數中有一個(gè)bd的參數是至關(guān)重要的,它是一個(gè)bd_info類(lèi)型的結構體,定義在include/asm-arm/u-boot.h中,而這個(gè)結構體又被一個(gè)global_data類(lèi)型的結構體所引用,定義在include/asm-arm/global_data.h中,如下:

那么,那個(gè)bd參數到底是做什么用的呢?從定義中可以得知,bd記錄了機器碼、u-boot參數鏈表在內存中的地址等信息,那又問(wèn),它在什么地方進(jìn)行記錄的呢?它就在我們自己開(kāi)發(fā)板初始化代碼中記錄的,如:board/samsung/my2440/my2440.c中

注意:bd_t被gd_t所引用,而在global_data.h中我們可以看到,u-boot定義了一個(gè)gd_t的全局指針變量*gd,所以在這里就可以直接使用gd來(lái)設置bd了。

好了,我們還是接著(zhù)分析這個(gè)參數鏈表是如何被傳遞的,組織參數鏈表的系列函數在一個(gè)叫do_bootm_linux的函數中被調用的,還是定義在lib_arm/bootm.c中

從這個(gè)函數中我們可以看到,要使參數傳遞生效必須需要CONFIG_SETUP_MEMORY_TAGS和CONFIG_CMDLINE_TAG這兩個(gè)宏的支持,所以需要在include/configs/my2440.h中定義它們。原來(lái)我就是沒(méi)定義它們,在使用NFS掛載文件系統時(shí)就出現問(wèn)題。同時(shí),theKernel這個(gè)函數指針是u-boot參數傳遞的至關(guān)點(diǎn),我們知道,函數在內存中執行的時(shí)候其實(shí)就是一個(gè)地址,而在代碼中首先將這個(gè)函數指針指向kernel的入口地址,最后還將0、機器碼和u-boot參數項在內存中的地址帶給這個(gè)入口地址,故執行這個(gè)入口地址的時(shí)候即kernel啟動(dòng)的時(shí)候可以有這三個(gè)參數進(jìn)行接收。那么,這個(gè)入口地址(kernel啟動(dòng)地址或者說(shuō)kernel入口地址)是怎么來(lái)的是誰(shuí)指定的,又是多少呢?看代碼,是從一個(gè)bootm_headers_t類(lèi)型的結構體的成員ep取得的,而這個(gè)結構體是從調用do_bootm_linux的地方傳遞過(guò)來(lái)的。bootm_headers_t定義在include/image.h中,do_bootm_linux在common/cmd_bootm.c中被調用,如下:
從代碼中可以清楚的看到對bootm_headers_t的成員ep進(jìn)行了賦值,但是還是不夠直觀(guān)這個(gè)入口地址到底是多少?只知道是使用image_get_ep函數從bootm_headers_t中的legacy_hdr_os_copy上取得的,那它在什么地方被賦值的呢?原來(lái)在image_set_ep函數中,定義在tools/mkimage.c中,如下:
我們再想想,這個(gè)mkimage.c是做什么用的?原來(lái)是用它來(lái)制作u-boot格式的內核——uImage,還記得怎樣使用mkimage來(lái)制作uImage吧,在“u-boot-2009.08在2440上的移植詳解(四)”中講到,如下:

mkimage[-x]-A arch-O os-T type-C comp-a addr-e ep-n name-d data_file[:data_file...]image

選項:
-A:set architecture toarch//用于指定CPU類(lèi)型,比如ARM
-O:set operatingsystemtoos//用于指定操作系統,比如Linux
-T:set image type totype//用于指定image類(lèi)型,比如Kernel
-C:set compression typecomp//指定壓縮類(lèi)型
-a:set load address toaddr(hex)//指定image的載入地址
-e:set entry point toep(hex)//內核的入口地址,一般為image的載入地址+0x40(信息頭的大?。?br />-n:set image name toname//image在頭結構中的命名
-d:use image data fromdatafile//無(wú)頭信息的image文件名
-x:set XIP(execute in place)//設置執行位置

例如:
mkimage-nlinux-2.6.30.4-A arm-O linux-T kernel-C none-a 0x30008000-e 0x30008000-d zImage uImage.img


呵呵,相信此時(shí)的你撥云見(jiàn)日,茅塞頓開(kāi)了吧!這個(gè)入口地址就是0x30008000,這也正是為什么u-boot一定要使用uImage的格式來(lái)啟動(dòng)內核的原因之一。注意:這里有個(gè)kernel入口地址0x30008000,在上面還提到一個(gè)u-boot參數鏈表在內存中的地址0x30000100,試想如果這里指定的kernel入口地址覆蓋了參數鏈表的地址會(huì )怎么樣?

好了,把上面每個(gè)步驟從下往上看就可以知道u-boot參數項在u-boot端的傳遞的整個(gè)流程了,那么,接下來(lái)再分析u-boot參數項在kernel端是怎樣接收的。

kernel啟動(dòng)的流程如下圖所示:
在文件arch/arm/boot/compressed/head.S中,start是zImage的起始點(diǎn),部分代碼如下:

start:
......

.word0x016f2818@ Magic numbers to help the loader
.wordstart@ absolute load/run zImage address
.word_edata@ zImage end address
1:movr7, r1 @ save architecture ID
movr8, r2 @ save atags pointer
......

wont_overwrite:movr0, r4
movr3, r7
bldecompress_kernel
bcall_kernel

......

call_kernel:blcache_clean_flush
blcache_off
movr0, #0@ must be zero
movr1, r7@ restore architecture number
movr2, r8@ restore atags pointer
movpc, r4@ call kernel

......

首先,將u-boot傳遞過(guò)來(lái)的r1(機器碼)、r2(參數鏈表在內在中的物理地址)分別保存到ARM寄存器r7、r8中,再將r7作為參數傳遞給解壓函數decompress_kernel(),在這個(gè)解壓函數中再將r7傳遞給全局變量__machine_arch_type,然后在跳轉到vmlinux入口之前再將r7、r8還原到r1、r2中。

在arch/arm/kernel/head.S文件中,內核vmlinux入口的部分代碼如下:

ENTRY(stext)
setmodePSR_F_BIT|PSR_I_BIT|SVC_MODE,r9 @ ensure svc mode @andirqs disabled
mrcp15,0,r9,c0,c0@ get processor id
bl __lookup_processor_type@ r5=procinfo r9=cpuid
movsr10,r5 @ invalid processor(r5=0)?
beq__error_p @ yes,errorp
bl __lookup_machine_type@ r5=machinfo
movsr8,r5 @ invalid machine(r5=0)?
beq__error_a @ yes,errora
bl __vet_atags
bl __create_page_tables

......


首先從ARM特殊寄存器(CP15)中獲得ARM內核的類(lèi)型,從處理器內核描述符(proc_info_list)表(__proc_info_begin—__proc_info_end)中查詢(xún)有無(wú)此ARM 內核的類(lèi)型,如果無(wú)就出錯退出。處理器內核描述符定義在include/asm-arm/procinfo.h中,具體的函數實(shí)現在 arch/arm/mm/proc-xxx.S中,在編譯連接過(guò)程中將各種處理器內核描述符組合成表。接著(zhù)從機器描述(machine_desc)表(__mach_info_begin—__mach_info_end)中查詢(xún)有無(wú)r1寄存器指定的機器碼,如果沒(méi)有就出錯退出,所以這也說(shuō)明了為什么在u-boot中指定的機器碼一定要與內核中指定的一致,否則內核就無(wú)法啟動(dòng)。機器編號mach_type_xxx在arch/arm/tools/mach-types文件中說(shuō)明,每個(gè)機器描述符中包括一個(gè)唯一的機器編號,機器描述符的定義在 include/asm-arm/mach/arch.h中,具體實(shí)現在arch/arm/mach-xxxx文件夾中,在編譯連接過(guò)程中將基于同一種處理器的不同機器描述符組合成表。例如,S3C2440處理器的機器碼為1008的機器描述符如下所示:

MACHINE_START(SMDK2440,"SMDK2440")

.phys_io=S3C2410_PA_UART,
.io_pg_offst=(((u32)S3C24XX_VA_UART)>>18)&0xfffc,
.boot_params=S3C2410_SDRAM_PA+0x100,//注意:這個(gè)地址就是與u-boot中參數鏈表在內存中的物理地址相對應

.init_irq=s3c24xx_init_irq,
.map_io=smdk2440_map_io,
.init_machine=smdk2440_machine_init,
.timer=&s3c24xx_timer,
MACHINE_END

最后就打開(kāi)MMU,并跳轉到 init/main.c的start_kernel()初始化系統。函數start_kernel()的部分代碼如下:

asmlinkagevoid__init start_kernel(void)
{
......
setup_arch(&command_line);
......
}

函數setup_arch在arch/arm/kernel/setup.c中實(shí)現,部分代碼如下:

void__init setup_arch(char**cmdline_p)
{
......
setup_processor();
mdesc=setup_machine(machine_arch_type);
......
parse_tags(tags);
......
}


setup_processor()函數從處理器內核描述符表中找到匹配的描述符,并初始化一些處理器
變量。setup_machine()用機器編號(在解壓函數decompress_kernel 中被賦值)作為參數返回機器描述符。從機器描述符中獲得內核參數的物理地址,賦值給tags 變量。然后調用parse_tags()函數分析內核參數鏈表,把各個(gè)參數值傳遞給全局變量。這樣內核就收到了u-boot傳遞的參數。

  • tftp下載內核和nfs掛載文件系統

好了,上面tftp服務(wù)和nfs服務(wù)都已經(jīng)準備好了,u-boot到kernel的參數傳遞也沒(méi)問(wèn)題了,接下來(lái)就設置一下u-boot環(huán)境變量中的參數項和kernel的配置選項使之能使用tftp自動(dòng)下載kernal和通過(guò)網(wǎng)絡(luò )自動(dòng)掛載nfs文件系統。u-boot環(huán)境變量設置如下:

bootcmd參數項就是使用tftp把主機tftp主目錄下的uImage下載到開(kāi)發(fā)板SDRAM中的0x31000000位置,接著(zhù)使用bootm命令執行引導內核啟動(dòng)。

而bootargs參數項就是內核啟動(dòng)的命令行參數,u-boot就是把這個(gè)參數項傳遞給了內核,通過(guò)nfs掛載文件系統。這里一定要注意serverip和ipaddr的設置(即服務(wù)器IP或者開(kāi)發(fā)主機IP和開(kāi)發(fā)板的IP)。另外要注意,內核要能使用nfs也要配置相應的選項,如下:

File systems --->
Network File Systems --->
<*> NFS file system support ## 必選
[*] Provide NFSv3 client support ## 可選
[*] Root file systemonNFS ## 必選
Networking --->
[*] Networking support
Networking options --->
[*] IP: kernel level autoconfiguration ## 必選


運行結果如下:

a. tftp下載內核,并引導內核啟動(dòng):

b. u-boot傳遞的命令行參數被內核所接收:

c. 內核通過(guò)nfs掛載文件系統:

d.查看掛載的nfs文件系統,發(fā)現完全與主機nfs服務(wù)器主目錄中的文件系統一致,說(shuō)明成功!



關(guān)鍵詞: Linuxu-boot244

評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>