天天看點

讓Android運作在SD卡上1.  Android啟動流程2.  如何讓Android運作在SD卡上3.  VT6080實做從SD卡啟動

首先介紹原理,最後介紹具體怎麼實作。

1.  Android啟動流程

eloader,uboot存儲在SPI Flash上面。SPI FLash在開機時會被SoC映射到某位址,然後依次啟動eloader,uboot。

uboot啟動後,将會啟動kernel。

1.1.kernel在哪裡呢?

1.1.1.    kernel可以在boot.img中

boot.img是Android搞出來的一種檔案布局格式。boot.img包括三大部分,kernel、ramdisk和cmdline。

ramdisk中包括了Android需要的根目錄,核心包括init,init.rc等。

cmdline是傳遞給核心的參數。uboot中有環境變量bootargs也是傳遞給核心的參數。誰優先呢?需要根據不同平台的uboot來看。不同廠家實作不一樣。

各Android平台下的uboot中增加了對boot.img的解析功能。可以從boot.img的布局中解析出核心、ramdisk及cmdline來。

1.1.2.    kernel可以在某個檔案系統裡

檔案系統必須布局在某個分區。分區可以存在于sd卡,emmc上,甚至是u盤。也就是kernel存在于某種儲存設備的分區上。uboot需要支援分區上的檔案系統,能夠從檔案系統中将kernel讀到記憶體裡。

以上兩種方式的kernel,檔案封裝格式方式不一樣。

1.2.kernel的兩種檔案封裝格式

對于boot.img中的kernel,就是普通的zImage格式,而對于在檔案系統裡存儲的,kernel是uImage方式,此uImage通過mkimage方式産生,請參考後文内容。

zImage就是經過普通壓縮的vmlinux。uImage是把zImage再次封裝後的形式。u的意思是uboot再次解析的意思。

uboot通過各種努力,從不同地方找到了kernel了,這各種努力,根據在kernel存儲在哪裡有不同的行為。

1.3.kernel如何被執行起來并找到根分區

根據kernel存儲在哪裡來分别描述:

1.3.1.   kernel在boot.img中– booti

boot.img如何被uboot找到呢?

又分為兩種情況:

1.3.1.1. boot.img dd 到boot分區。

一般來說,無論是emmc,還是nand,都會有一個boot分區存在。boot.img會被同linux 指令dd一樣的方式寫入到這個分區裡。

uboot可以找到這個分區,然後讀出boot.img裡的内容。是以uboot需要支援emmc的讀寫,sd卡的讀寫,nand的讀寫,甚至u盤的讀寫。這些讀寫都是按扇區方式讀寫的。

1.3.1.2. 從分區直接讀--booti boot

這種啟動方式,uboot的啟動參數是booti boot。

booti指令首先根據分區名稱找到boot分區位置,然後讀入到記憶體中,記憶體中的内容,就是boot.img。

解析boot.img,得到核心,并得到ramdisk,cmdline。

uboot中有一個重要的環境變量bootargs,不同的uboot版本,會讓cmdline和bootargs較量來決定什麼值傳遞給kernel。

最重要的boot args是指定了根分區及init。

kernel會以此為依據找到根分區及init。

1.3.1.3. boot.img存在某檔案系統中--booti address

boot.img不是直接按二進制方式寫入到某個分區,不像dd一樣。而是存在分區的檔案系統中。比如存在SD卡第一個fat32檔案系統分區中,或者emmc第15個ext4檔案系統中。

這種啟動方式,首先需要将boot.img加載到記憶體,然後uboot從這個位址啟動。boot.img就可以存在sd,emmc,nand,u盤等分區的檔案系統中,需要首先被ext4load,fatload等加載到記憶體中。

加載到記憶體後,uboot的booti指令可以從這個記憶體位址啟動。

booti address

1.3.2.   kernel在分區檔案系統中-bootm

這時候,kernel需要是uImage封裝方式。并且需要被uboot提供的ext4load,fatload等方式将uImage加載到記憶體,然後被uboot的bootm來啟動。

1.3.3.   kernel如何找到根分區

kernel需要找到根分區,這個是通過uboot傳遞給kernel的cmdline指定的。VT6080一般都是指定一個實際分區。也可以是ramdisk。

kernel啟動了,也找到了根分區,如何啟動Android系統呢?

1.4.Android的啟動

在根分區有一個init程序及Init.rc,kernel從根分區啟動init,init解析init.rc。

在init.rc及其include進來的rc檔案裡,我們需要建立system目錄及data目錄。

init.rc會通過mount_all指令,挂載system分區到/system,data分區到/data.

system裡存儲的,就是android系統,主要包括framework。

找到system和data目錄,基本上Android就能夠啟動了。

system目錄是system分區的挂載點。一般是在刷機的時候,将system.img刷在system分區。是以system.img刷到system分區的時候,是帶着檔案系統刷過去的,也就是system.img一般是ext4的img,和boot.img不一樣的格式。

2.  如何讓Android運作在SD卡上

讓Android運作在SD卡上,就是從SD卡啟動的意思了。根據前面介紹,我們知道必須具備以下條件:

1.uboot能夠支援sd卡讀寫。(mmcread/write)

2.uboot可以讀取sd卡分區上的檔案。(ext4load,fatload mmc0:1)

3.uImage在SD卡分區上。對于VT6080,還需要一個dtb檔案。

4.kernel啟動後,能夠驅動sd卡(mmc支援)及sd卡上的檔案系統。

5.kernel啟動後,根據核心參數,将SD卡分區當作系統的根分區。

6.SD卡分區中有init,有system,data目錄。

3.  VT6080實做從SD卡啟動

0.sd卡格式化成ext4

1.編譯核心,找到uImage及dtb檔案(arch/arm/boot/)

2.編譯Android。

3.拷貝android輸出檔案到sd根目錄:

3.1    out../root/*

3.2    out../system

注意一個是root下的所有檔案,一個是整個system目錄。

4.拷貝核心uImage,dtb檔案到sd卡根目錄。

5.修改init.rc,init.elite1000.rc,fstab.elite1000等檔案中對system,userdata分區的挂載動作,都去掉。因為sd卡根目錄下已經有了system目錄了。

6.将s3g GFX driver安裝到sd根目錄。

7.修改uboot參數

setenv bootcmd 'ext4load mmc 0:1 0x0 scriptcmd; ifiminfo 0x0; then source 0; else run bootcmd_mmc; fi'

--uboot啟動後,首先運作bootcmd指令。這行意思是找sd卡上有沒有scriptcmd檔案,有的話就執行它。沒有就運作bootcmd_mmc

--是以sd卡上不能存在scriptcmd檔案。這個檔案是安裝bootloader及android的時候用的。

setenv bootcmd_mmc '

    run bootargs_mmc&& 

    ext4load mmc 0:1 0x6000000elite1000-emmc.dtb; 

    ext4load mmc 0:1 0x2800000uImage; 

    if iminfo 0x2800000; then bootm0x2800000 - 0x6000000; 

    else run bootcmd_emmc; 

    fi'

--首先設定mmc啟動的參數。下文解釋

--加載dtb和核心到記憶體。

--如果記憶體中核心image符合uImage的封裝格式,運作之,否則,從emmc啟動。

setenv bootargs_mmc '

    setenv bootargs 

        ${kernelargs} 

       androidboot.serialno=${androidno} 

       root=/dev/mmcblk0p1 rootwait 

        rootflags=errors=remount-ro,commit=0 

       rootfstype=ext4 rw 

       ${mtdparts} 

        init=/initrw'

bootargs_mmc指令就是設定bootargs參數,這個參數被uboot解釋并傳遞給kernel。

kernelargs是傳遞給kernel的參數。

root=,這是訓示根分區在哪裡。

    mmcblk0

        vt6080上有3個mmc控制器。sd卡是mmc 0,emmc是mmc2,mmc1沒有使用。這裡的0,1,2編号是uboot中使用的。

        linux裡如何編号還不清楚。

        這裡的mmcblk0是在linux核心中使用的,這裡指的是sd卡

    mmcblk0p1,p1指的是sd卡上的第一個分區。分區編号從1數起。

setenv kernelargs 'console=ttyS1,115200n8rootdelay=1'

setenv androidno '030a3d8408e49475'

setenv mtdparts 'mtdparts=nand:4M(secureboot),4M(secureos),4M(audiofirmware),2M(uboot_env),4M(uboot),4M(boot_logo),4M(nvram),12M(devicetree),32M(otaloader),32M(iploader),16M(device_info),16M(misc),16M(boot),16M(recovery),384M(system),32M(package),384M(cache),-(data)'

setenv bootargs_mmc 'setenv bootargs ${kernelargs} androidboot.serialno=${androidno} root=/dev/mmcblk0p1 rootwaitrootflags=errors=remount-ro,commit=0 rootfstype=ext4 rw ${mtdparts} init=/initrw'

setenv bootcmd_mmc 'run bootargs_mmc &&ext4load mmc 0:1 0x6000000 elite1000-emmc.dtb; ext4load mmc 0:1 0x2800000uImage; if iminfo 0x2800000; then bootm 0x2800000 - 0x6000000; else runbootcmd_emmc; fi'

setenv bootcmd 'ext4load mmc 0:1 0x0 scriptcmd; ifiminfo 0x0; then source 0; else run bootcmd_mmc; fi'

以上就是uboot參數。可以在uboot指令行環境輸入執行。注意最後要saveenv。

8.重新開機。android将會從sd卡啟動了。

從zImage建立uImage:

mkimage -A arm -O linux -T kernel -C none -a02008000 -e 02008000 -n Linux-3.4.6 -d zImage uImage

列印資訊:

Image Name: Linux-3.4.6

Created: Mon Dec 29 17:21:36 2014

Image Type: ARM Linux Kernel Image (uncompressed)

Data Size: 3857160 Bytes = 3766.76 kB = 3.68 MB

Load Address: 0x02008000

Entry Point: 0x02008000

如何從image安裝方式改變成從SD卡啟動

1.使用工具splite_bootimg.pl,分解boot.img,得到kernel和Ramdisk

2.使用mkimage工具将kenrel轉換成uImage

3.将ramdisk解壓到目錄ramdisk:

# mkdir ramdisk

# cd ramdisk

# gzip -dc ../*-ramdisk.gz | cpio -i

4.修改fstab.elite1000或者init.rc,移除system分區的挂載,因為system也會存在于SD卡。

5.将system.img挂載到某目錄,如挂載到/home/brilly/system:

使用Android編譯後得到的host工具simg2img工具将system.img轉換成ext4檔案系統的image

#simg2img system.img system.ext4

#mount -t ext4 -o loop system.ext4/home/brilly/system

6.ext4格式化sd卡。

7.拷貝ramdisk目錄所有檔案到SD根目錄

8.拷貝system目錄所有檔案到SD根目錄下的system目錄。

9.拷貝uImage到SD根目錄。

繼續閱讀