首先貼出來我的bootargs的設定(注沒有換行符!!!):
setenv bootargs noinitrd mem=64M root=/dev/nfs init=/linuxrc rw nfsroot=10.10.2.59:/opt/rootfs/ ip=10.10.1.156:10.10.2.59:10.10.1.1:255.255.255.0:skdkjzz:eth0:off console=ttyAMA0,115200
Linux編譯生成zImage,但是uboot不能識别,uboot隻能識别uImage的檔案格式,uImage與zImage檔案的差別是uImage比zImage多個檔案頭,我們現在利用uboot的mkimage工具來生成uImage檔案。
通常,u-boot為kernel提供一些kernel無法知道的資訊,比如ramdisk在RAM中的位址。Kernel也必須為U-boot提供必要的資訊,如通過mkimage這個工具(在u-boot代碼的tools目錄中)可以給zImage添加一個header,也就是使得通常編譯的核心zImage添加一個資料頭,把添加頭後的image通常叫uImage,uImage是可以被U-boot直接引導的核心鏡像。那麼如何使用mkimage工具而産生uImage的呢?下面将具體介紹mkimage工具的使用:
1.首先進入u-boot目錄下tools檔案夾下,檢視mkimage的指令參數
[root@localhost tools]# ./mkimage
Usage: ./mkimage -l image
-l ==> list image header information
./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 to 'arch' //用于指定CPU類型,比如ARM
-O ==> set operating system to 'os' //用于指定作業系統,比如Linux
-T ==> set image type to 'type' //用于指定image類型,比如Kernel
-C ==> set compression type 'comp' //指定壓縮類型
-a ==> set load address to 'addr' (hex) //指定image的載入位址
-e ==> set entry point to 'ep' (hex) //核心的入口位址,一般是:image的載入位址+0x40(資訊頭的大小)
-n ==> set image name to 'name' //image在頭結構中的命名
-d ==> use image data from 'datafile' //無頭資訊的image檔案名
-x ==> set XIP (execute in place) //設定執行位置
-a參數後是核心的運作位址,-e參數後是入口位址。
1)如果我們沒用mkimage對核心進行處理的話,那直接把核心下載下傳到0x40008000再運作就行,核心會自解壓運作(不過核心運作需要一個tag來傳遞參數,而這個tag建議是由bootloader提供的,在u-boot下預設是由bootm指令建立的)。
2)如果使用mkimage生成核心鏡像檔案的話,會在核心的前頭加上了64byte的資訊,供建立tag之用。bootm指令會首先判斷bootm xxxx 這個指定的位址xxxx是否與-a指定的加載位址相同。
(1)如果不同的話會從這個位址開始提取出這個64byte的頭部,對其進行分析,然後把去掉頭部的核心複制到-a指定的load位址中去運作之
(2)如果相同的話那就讓其原封不同的放在那,但-e指定的入口位址會推後64byte,以跳過這64byte的頭部。
執行:./mkimage -A arm -O linux -T kernel -C none -a 40008000 -e 40008040 -n linux-2.6.31 -d zImage uImage
生成檔案之後,根據所要選擇啟動的檔案系統,設定uboot的參數:
1、啟動ramdisk檔案系統
setenv bootargs console=ttyAM0,115200 initrd=0x40400000,0x800000 root=/dev/ram0
setenv bootcmd tftp 0x40008000 uImage;bootm 0x40008000
setenv serverip 192.167.10.24
setenv ipaddr 192.167.10.2
2、啟動nfs檔案系統
x86 Linux主機開啟nfs服務,步驟如下:
1、軟硬體環境
VMware 7.0.0,Ubuntu 9.04
2、ubuntu安裝後預設是沒有帶nfs的,使用如下指令安裝:
我直接進的root帳戶。
apt-get install nfs-kernel-server
apt-get install nfs-common
3、虛拟機配置選項裡網卡使用的是橋接,IP位址為192.168.0.1,和主機的192.168.0.11在同一網段,主機是連到路由器的。
4、修改配置檔案
在設定配置檔案之前,先建立共享目錄/home/lah/nfs,nfs共享目錄。修改nfs配置檔案/etc/exports,添加如下一行:
/home/lah/nfs *(rw,sync,no_root_squash)
第一個參數是nfs共享目錄,第二個是你允許的主機IP,這裡設定成所有客戶機都可共享該目錄,括号裡面的rw表示挂接此目錄的客戶機對該目錄有讀寫的權限,no_root_squash 表示允許挂接此目錄的客戶機享有該主機的root 身份。
5、啟動NFS服務并測試
/etc/init.d/portmap start
/etc/init.d/nfs-kernel-server start
現在roo_fs目錄下放入一些檔案,然後通過nfs挂載mnt目錄測試。
mount localhost:/home/lah/nfs /mnt
如果mnt下有/home/lah/nfs目錄下的檔案,則證明nfs服務已經配置好了。
将nfs作為根檔案系統時,開啟的nfs服務的檔案夾不能為空,應該放busybox制作的根檔案系統。
uboot設定bootargs指令的方法
示例:
setenv bootargs console=ttyAM0,115200 noinitrd root=/dev/nfs nfsroot=192.167.10.6:/home/lah/nfs ip=192.167.10.2:192.167.10.6:::forlinux:eth0:
<col>
#setenv bootargs noinitrd console=ttySAC0,115200 init=/linuxrc mem=64M root=/dev/nfs nfsroot=192.168.2.125:/home/hufei/nfsrootip=192.168.2.6:192.168.2.125:192.168.2.125:255.255.255.0:hufei.cublog.cn:eth0:off
initrd, noinitrd:
當你沒有使用ramdisk啟動系統的時候,你需要使用noinitrd這個參數,但是如果使用了的話,就需要指定initrd=r_addr,size, r_addr表示initrd在記憶體中的位置,size表示initrd的大小。
console:
console=tty 使用虛拟序列槽終端裝置 .
console=ttyS[,options] 使用特定的序列槽,options可以是這樣的形式bbbbpnx,這裡bbbb是指序列槽的波特率,p是奇偶位(從來沒有看過使用過),n是指的bits。
console=ttySAC[,options] 同上面。
看你目前的環境,有時用ttyS,有時用ttySAC,網上有人說,這是跟核心的版本有關,2.4用ttyS,2.6用ttySAC,但實際情況是官方文檔中也是使用ttyS,是以應該是跟核心版本沒有關聯的。可以檢視Documentation/serial-console.txt找到相關描述。
init:
init指定的是核心啟起來後,進入系統中運作的第一個腳本,一般init=/linuxrc, 或者init=/etc/preinit,preinit的内容一般是建立console,null裝置節點,運作init程式,挂載一些檔案系統等等操作。請注意,很多初學者以為init=/linuxrc是固定寫法,其實不然,/linuxrc指的是/目錄下面的linuxrc腳本,一般是一個連接配接罷了。如果核心找不到linurc檔案,将會依次搜尋/sbin/init,/etc/init,/bin/init,/bin/sh.
mem:
指定記憶體大小,不是必須的
root:
用來指定rootfs的位置, 常見的情況有:
root=/dev/ram rw
root=/dev/ram0 rw
請注意上面的這兩種設定情況是通用的,我做過測試甚至root=/dev/ram1 rw和root=/dev/ram2 rw也是可以的,網上有人說在某些情況下是不通用的,即必須設定成ram或者ram0,但是目前還沒有遇到,還需要進一步确認,遇到不行的時候可以逐一嘗試。
root=/dev/mtdx rw
root=/dev/mtdblockx rw
root=/dev/mtdblock/x rw
root=31:0x
上面的這幾個在一定情況下是通用的,當然這要看你目前的系統是否支援,不過mtd是字元裝置,而mtdblock是塊裝置,有時候你的挨個的試到底目前的系統支援上面那種情況下,不過root=/dev/mtdblockx rw比較通用。此外,如果直接指定裝置名可以的話,那麼使用此裝置的裝置号也是可以的。
root=/dev/nfs,并非真的裝置,而是一個告訴核心經由網絡取得根檔案系統的旗标。
在檔案系統為基于nfs的檔案系統的時候使用。當然指定root=/dev/nfs之後,還需要指定nfsroot,
nfsroot這個參數告訴核心以哪一台機器,哪個目錄以及哪個網絡檔案系統選項作為根檔案系統使用。參數的格式如下:
nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>]
如果指令列上沒有給定 nfsroot 參數,則将使用‘/tftpboot/%s’預設值。其它選項如下:
<server-ip> --指定網絡檔案系統服務端的網際網路位址(IP address)。如果沒有給定此欄位,則使用由 nfsaddrs 變量(見下面)所決定的值。此參數的用途之一是允許使用不同機器作為反向位址解析協定(RARP) 及網絡檔案系統服務端。通常你可以不管它(設為空白)。
<root-dir> -- 服務端上要作為根挂入的目錄名稱。如果字串中有個‘%s’ 符記(token),此符記将代換為用戶端網際網路位址之ASCII表示法。
<nfs-options> -- 标準的網絡檔案系統選項。所有選項都以逗号分開。如果沒有給定此選項欄位則使用下列的預設值:
port = as given by server portmap daemon
rsize = 1024
wsize = 1024
timeo = 7
retrans = 3
acregmin = 3
acregmax = 60
acdirmin = 30
acdirmax = 60
flags = hard, nointr, noposix, cto, ac
參數nfsaddrs設定網絡通訊所需的各種網絡接口位址。如果沒有給定這個參數,則核心核會試著使用反向位址解析協定以及/或是啟動協定(BOOTP)以找出這些參數。其格式如下:
ip:
下面是U-boot官方文檔提供的IP參數解析:
setenv bootargs ${bootargs}
ip=${ipaddr}:${serverip}:/
${gatewayip}:${netmask}:/
${hostname:${netdev}:off
注意,上面換行的地方均有空格。其中 192.168.2.6是開發闆的IP,192.168.2.125
是PC端(或虛拟機)的 IP,上面的IP根據自己的實際情況修改,不要弄錯了。
nfsaddrs=<my-ip>:<serv-ip>:<gw-ip>:<netmask>:<name>:<dev>:<auto>
<my-ip> -- 用戶端的網際網路位址。如果沒設,此位址将由反向位址解析協定(RARP)或啟動協定來決定。使用何種協定端視配置核心時打開的選項以及 參數而定。如果設定此參數,就不會使用反向位址解析協定或啟動協定。
<serv-ip> -- 網絡檔案系統服務端之網際網路位址。如果使用反向位址解析協定來決定用戶端位址并且設定此參數,則隻接受從指定之服務端傳來的回應。要使用不同的機器作為反向位址解析與網絡檔案系統服務端的話,在此指定你的反向位址解析協定服務端(保持空白)并在 nfsroot 參數(見上述)中指定你的網絡檔案系統服務端。如果此項目空白則使用回答反向位址解析協定或啟動協定之服務端的位址。
<gw-ip> -- 網關(gateway)之網際網路位址,若服務端位於不同的子網絡上時。如果此項目空白則不使用任何網關并假設服務端在本地的(local)網絡上,除非由啟動協定接收到值。
<netmask> -- 本地網絡界面的網絡掩碼。如果為空白,則網絡掩碼由用戶端的網際網路位址導出,除非由啟動協定接收到值。
<name> -- 用戶端的名稱。如果空白,則使用用戶端網際網路位址之 ASCII-标記法,或由啟動協定接收的值。
<dev> -- 要使用的網絡裝置名稱。如果為空白,所有裝置都會用來發出反向位址解析請求,啟動協定請求由最先找到的裝置發出。網絡檔案系統使用接收到反向位址解析協定或啟動協定回應的裝置。如果你隻有一個裝置那你可以不管它。
<auto> -- 用以作為自動配置的方法。如果是 `rarp' 或是 `bootp' 則使用所訓示的協定。如果此值為`both' 或空白,若配置核心時有打開這兩種協定則都使用。 `none' 表示不使用自動配置。這種情況下你必須指定前述欄位中所有必要的值。
此參數可以作為 nfsaddrs 的參數單獨使用(前面沒有任何 `:` 字元),這種情況下會使用自動配置。然而,此種情況不能使用`none'作為值。
===========================================================================================================================
主機說明:
主機guest 為虛拟機redhat9: IP: 59.64.155.122 網關 59.64.155.1
redhat9上已經配置好NFS服務
也已經配置好TFTP服務
NFS服務, TFTP服務都已經啟動
終端采用主機host XP的超級終端
實驗闆說明:
MPC8349itx開發闆: IP: 59.64.155.244 網關 59.64.155.1
開發闆eth0為vsc8201晶片,uboot支援驅動,另一晶片為交換交換晶片vsc7385,單獨子產品驅動。
U-Boot-1.1.3 ; Linux kernel-2.6.13
核心支援NFS分區(即編譯時在File system中選中[*] Root file system on NFS), 以及支援核心IP_PNP(即編譯時在Networking中選中[*] IP: kernel level autoconfiguration)
File systems --->
Network File Systems --->
<*> NFS file system support ## 必選
[*] Provide NFSv3 client support ## 可選
[*] Root file system on NFS ## 必選
Networking --->
[*] Networking support
Networking options --->
[*] IP: kernel level autoconfiguration ## 必選
***************************************************************************
A: NFS啟動挂載根檔案系統
主機上操作:
$ cd /usr/local/mpc8349/
$ ./ltib --preconfig config/platform/mpc8349itx/defconfig-min-fs -f
## 依次進入如下選項選擇(X) NFS only, 根據情況決定是否選擇[ ] read-only root filesystem
--- Target Image Generation
Options --->
--- Choose your root filesystem image type
Target image: (ext2.gz ramdisk) ---> ## 改ramdisk檔案系統為NFS
(X) NFS only
[ ] read-only root filesystem
## 其他情況參考LTIB使用說明()
## 編譯結束後生成的根檔案系統是位于目前安裝目錄下的rootfs (/usr/local/mpc8349/small/rootfs)
$ ln -s /usr/local/mpc8349/small/rootfs /home/liuby/rootfsln ## 建立NFS服務目錄軟連接配接
$ su - root ## 切換到root使用者,需要密碼
# echo "/usr/local/mpc8349/small/rootfs 59.64.155.244(rw,sync,no_root_squash)" > /etc/exports ## NFS 服務配置
# service portmap restart
# service nfs restart
# exportfs -arv ## 修改的NFS配置生效(exportfs參數順序不一樣,顯示有所不同,此順序顯示結果明了)
# exit
實驗闆上操作:
uboot啟動後按鍵進入uboot指令行環境:
=> cp.b fef50000 40000 20000; go 40004 ## 驅動vsc7385晶片
=> set serverip 59.64.155.122 ## 主機位址
=> set ipaddr 59.64.155.244 ## 實驗闆位址
=> set netmask 255.255.255.0
=> set netdev eth0 ## eth0
=> ping 59.64.155.122 ## 測試連通
=> set hostname PowerQUICC
=> set kernaddr fe810000 ## flash中核心起始位址
=> set rootpath /usr/local/mpc8349/small/rootfs ## NFS服務根目錄
=> setenv bootargs root=/dev/nfs rw nfsroot=$serverip:$rootpath ip=$ipaddr:$serverip:$gatewayip:$netmask:$hostname:$netdev:off console=ttyS0,115200
=> bootm $kernaddr
## 如果一切正常,核心啟動後會啟動NFS檔案系統作根檔案系統。
## 測試: 在開發闆上建立一個檔案,在主機上會看到這個檔案生成
同樣可以簡化操作(測試nfs服務軟連接配接目錄):
=> setenv ipaddr 59.64.155.244
=> setenv bootargs root=/dev/nfs rw nfsroot=59.64.155.122:/home/liuby/rootfsln ip=59.64.155.244:59.64.155.122:255.255.255.0 console=ttyS0,115200
=> bootm fe810000 ## 核心鏡像uImage在FLASH中的存儲位址
************************
實驗中遇到一個問題,就是bootm之後核心啟動,NFS啟動挂載檔案系統快完成時出現下面這個錯誤提示
RPC: sendmsg returned error 101
nfs: RPC call returned error 101
後來才發現是檔案系統中的啟動腳本在啟動過程中修改了eth0的ip位址,導緻連接配接不上NFS server
後來再測試又發現試圖挂載非NFS檔案系統目錄時也會出現此問題,并且在主機上執行# showmount 指令結果會顯示有ip位址(實驗闆ip位址)挂載。即: 在ltib編譯檔案系統時選擇ext2.gz ramdisk (非NFS only), 最後使用rootfs目錄,出現同樣的問題。
還有遇到過一個問題,根本無法挂載檔案系統,在啟動時出現下述提示
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
<0>Rebooting in 180 seconds..
後來發現是 /etc/exports 隻有如下一句
/home/liuby/rootfs 59.64.155.244(rw,sync,no_root_squash)
而沒有像下面這樣指定根目錄的通路權限:
/usr/local/mpc8349/small/rootfs 59.64.155.244(rw,sync,no_root_squash)
結論: 必須指定NFS檔案系統所在目錄或其對應的軟連接配接做NFS服務根目錄(見下分析)
在NFS檔案系統中編譯busybox時可以不選擇編譯mount指令(不建議如此)
nfs總結:
如上 /home/liuby/rootfsln是指向/usr/local/mpc8349/small/rootfs的軟連接配接
# echo "/home/liuby/rootfsln 59.64.155.244(rw,sync,no_root_squash)" > /etc/exports
# exportfs -arv ## 會彈出下面的提示
exporting 59.64.155.244:/usr/local/mpc8349/small/rootfs
可見 /etc/exports 中語句 /home/liuby/rootfsln 59.64.155.244(rw,sync,no_root_squash) 和 /usr/local/mpc8349/small/rootfs 59.64.155.244(rw,sync,no_root_squash) 是等效的.
故: 如果想用不同的檔案系統,可以改變這個軟連接配接指向新的檔案系統,這比複制檔案系統或者修改u-boot環境變量友善多了,并且還不用重新配置/etc/exports。
# echo "/home/liuby/rootfsln 59.64.155.244(rw, sync, no_root_squash)" > /etc/exports
$ rm -f /home/liuby/rootfsln
$ ln -s nfs_rootfs_dir_path /home/liuby/rootfsln ## 隻需要建立和修改這個軟連接配接即可
# exportfs -arv ## 配置生效(必須)
在uboot環境變量中隻需設定一次rootpath=/home/liuby/rootfsln, 每次隻需在主機上修改此軟連接配接的指向,即可
注意權限
B: TFTP下載下傳核心和檔案系統鏡像到ram中啟動
在主機上TFTP根目錄為/home/liuby/tftpboot/
$ mkdir /home/liuby/tftpboot/image_dir
$ cd /usr/local/mpc8349/small/
$ ./ltib --preconfig config/platform/mpc8349itx/defconfig-min-fs-modified -f --batch ## 編譯核心和檔案系統鏡像
$ cp -f rootfs/boot/uImage rootfs.ext2.gz.uboot ~/tftpboot/image_dir/ ## 複制核心鏡像和檔案系統鏡像到~/tftpboot/image_dir
$ cd ~/tftpboot/
$ ln -s image_dir/ bootln
=> set netmask 255.255.255.0
=> set tftp_path bootln
=> ping $serverip ## 測試連通
=> setenv loadkernaddr 1000000
=> setenv loadramdaddr 1200000
=> tftpboot $loadkernaddr image_dir/uImage ## 下載下傳核心鏡像到ram
=> tftp $loadramdaddr $tftp_path/rootfs.ext2.gz.uboot ## 下載下傳檔案系統鏡像到ram
=> bootm $loadkernaddr $loadramdaddr ## 啟動ram中核心和檔案系統鏡像
下載下傳不暢時,用CTRL+C來終止回到提示符
tftp總結:
在TFTP服務根目錄下建立目錄存儲鏡像檔案,然後建立軟連接配接指向需要下載下傳的鏡像目錄,這樣可以通過修改連接配接檔案即可,而不用每次修改uboot環境變量了
C: TFTP下載下傳核心鏡像到ram,NFS挂載根檔案系統(target image: NFS only)
主機上利用上面操作的結果,不進行配置。
=> set bootargs root=/dev/nfs rw nfsroot=$serverip:/home/liuby/rootfsln ip=$ipaddr:$serverip:$netmask console=ttyS0,115200
=> tftp 1000000 bootln/uImage ## 下載下傳核心鏡像到ram 位址1000000
=> bootm 1000000
## 測試發現核心啟動,NFS挂載成功
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
簡便方法:
将下面附錄的檔案存儲為.txt檔案,例如取名mpc8349itx_uboot_env.txt
用linux指令unix2dos進行轉換,然後打開windows XP 超級終端,啟動實驗闆進入uboot指令行環境:
點選超級終端界面 "檔案"->"屬性",彈出屬性對話框,點選"設定"->"ASCII碼設定",設定行延遲20ms,字元延遲1ms;然後點選"發送"->"發送文本檔案",選擇"mpc8349itx_uboot_env.txt"發送。
此操作相當于在uboot指令行輸入uboot環境設定參數
執行完操作後儲存了這些設定,以後每次在uboot啟動時不用再敲入一行行的設定參數.
在uboot指令行下執行
=> run flashnfsboot
相當于 A 操作
在uboot指令行執行
=> run tftpramboot
相當于執行 B 操作
=> run tftpnfsboot
相當于執行 C 操作