Ubuntu下arm交叉編譯環境的創建及基於s3c2410的linux2.6.22移植

 

經歷近2周的時間,查閱大量的參考資料和貼子,終於成功將linux2.6.22移植到ARM2410上。中間走了不少彎路,不過走彎路也是一種收穫,因爲可以碰到和解決許多問題,增長知識。因爲linux版本問題以及開發平臺的不同,網上的很多文章並不完全適合自己的板子,需要自己摸索和修改。寫這點東西算是對前一階段工作的總結,以免將來忘記。

移植大體的步驟主要有:

(1)       交叉編譯環境的建立(我的主機系統是ubuntu7.04);

(2)       開發板(我用的是博創的2410NAND flash 分區管理;

(3)       LCD、網卡驅動的移植;

(4)       linux內核配置和編譯;

(5)       rootfs的製作;

(6)       完成linux的啓動和文件系統的掛載。

下面我會按照步驟逐一介紹。

一、   交叉編譯環境的建立

建立交叉編譯環境就是在宿主機(也就是pc機)的系統上建立一個模擬ARM的工作環境,使得在這個環境下編譯產生的程序能夠順利的在ARM上的系統內運行。主要工作包括binutilsgcc以及glibc的編譯生成,還有一些環境變量的設置。

(1)      準備工作:

下載源代碼包:    binutils-2.18.tar.bz2gcc-4.2.1.tar.bz2glibc-2.6.1.tar.bz2glibc-ports-2.6.1.tar.gzlinux-2.6.22.tar.bz2

補丁包:              binutils-2.18-genscripts_multilib-1.patch

                            binutils-2.18-posix-1.patch

                            gcc-4.2.1-cross_search_paths-1.patch

                            gcc-4.2.1-posix-1.patch

                            gcc-4.2.1-specs-1.patch

                            glibc-2.6.1-cross_hacks-1.patch

                            glibc-2.6.1-hppa_nptl-1.patch

glibc-2.6.1-libgcc_eh-1.patch

glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch

glibc-2.6.1-sysdep_cancel-1.patch

glibc-csu.patch

注:Binutils 是一組開發工具,包括連接器,彙編器和其他用於目標文件和檔案的工具;

GCCC編譯器,用來將C代碼編譯成彙編代碼;

Glibc就是gcc編譯時需要的庫了,glibc-ports是提供glibcARM的支持;

Linux-2.6.22.tar.bz2是內核源代碼包。

需要注意的是gccglibc以及linux內核版本需要保持對應。如果用比較老的編譯器去編譯新的內核,或者用新的編譯器編譯老版本的內核,會出現一些莫名其妙的錯誤。另外補丁包也是必備的,否則編譯過程中也會出錯。剛開始我就深受其害。

(2)      工作目錄的建立:

目錄的結構可以參考《Building.Embedded.Linux.Systems》。推薦整個目錄放到/usr/local下,這樣所有的用戶都有訪問權限。我當初沒經驗,直接放到home下了,後來會有些用戶權限的小麻煩。這裏給出我的目錄結構:

$root@host:/home#  ls

arm  host

其中host是我的普通登陸用戶帳號目錄,arm就是工作目錄了。爲了方便,我平時用root登陸。

$root@host:/home# cd  arm

$root@host:/home/arm# mkdir build-tools kernel rootfs tmp tools

其中編譯交叉工具時的主要工作都在build-tools目錄下完成,kernel目錄用來存放內核源代碼,rootfs目錄是用來建立啓動根文件系統的(後面會詳細介紹),tmp是臨時文件存放目錄,tools目錄就是最終生成的編譯器gccglibc存放的地方。

(3)      設置環境變量:

$root@host:/home/arm# export PRJROOT=/home/arm

$root@host:/home/arm# TARGET=arm-linux

$root@host:/home/arm# PREFIX=${PRJROOT}/tools

$root@host:/home/arm# TARGET_PREFIX=${PREFIX}/${TARGET}

$root@host:/home/arm# PATH=${PREFIX}/bin:${PATH}

其中TARGET定義了交叉工具的工作平臺類型,PREFIX指定交叉工具的最終安裝目錄,PATH指定系統尋找交叉工具可執行文件所在的路徑。

(4)      編譯前的準備:

$root@host:/home/arm# cd ${PRJROOT}/build-tools

$root@host:/home/arm/build-tools# mkdir build-binutils build-boot-gcc build-glibc build-gcc build-glibc-headers patch

將源碼包放到這個目錄下

$root@host:/home/arm/build-tools# ls

build-boot-gcc   build-glibc      build-binutils   build-gcc build-glibc-headers patch

binutils-2.18.tar.bz2   gcc-4.2.1.tar.bz2    glibc-2.6.1.tar.bz2  glibc-ports-2.6.1.tar.gz

將補丁放到patch目錄下:

$root@host:/home/arm/build-tools# cd patch

$root@host:/home/arm/build-tools/patch# ls

binutils-2.18-genscripts_multilib-1.patch      binutils-2.18-posix-1.patch

              gcc-4.2.1-cross_search_paths-1.patch        gcc-4.2.1-posix-1.patch

                  glibc-2.6.1-cross_hacks-1.patch

glibc-2.6.1-hppa_nptl-1.patch                            glibc-2.6.1-libgcc_eh-1.patch

glibc-2.6.1-RTLD_SINGLE_THREAD_P-1.patch

glibc-2.6.1-sysdep_cancel-1.patch                     glibc-csu.patch

將內核源碼包放到${PRJROOT}/kernel目錄下

$root@host:/home/arm# cd kernel

$root@host:/home/arm/kernel# ls

linux-2.6.22.tar.bz2

(5)      開始編譯

編譯的過程主要有6個步驟;

a.       內核頭文件的生成

b.       Binary utilties的生成

c.       Glibc頭文件的生成

d.       第一階段gcc的生成

e.       glibc庫文件的生成

f.        完整編譯工具的生成

  注:生成第一階段gcc主要是用來生成glibc庫文件。

1、 生成內核頭文件

$root@host:/home/arm/kernel# tar xvjf linux-2.6.22.tar.bz2

$root@host:/home/arm/kernel# cd linux-2.6.22

$root@host:/home/arm/kernel/linux-2.6.22#

make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig

其中menuconfig指定了配置界面,可用的還有config(全字符界面) xconfigxwindow下的圖形界面)。Ubuntu需要安裝tk8.4以支持xconfig。另外需要將mawk卸載,安裝gawk。(mawkbug

linux2.6的內核提供了對s3c2410的支持。在system中選上s3c2410系列就可以了。配置完畢退出保存。

$root@host:/home/arm/kernel/linux-2.6.22# cd include

$root@host:/home/arm/kernel/linux-2.6.22/include# cd linux

$root@host:/home/arm/kernel/linux-2.6.22/include/linux# ls version.h autoconf.h

version.h autoconf.h

2個文件在後面的編譯中會用到。如果沒有,退到內目錄下make version.h就可以了。

下面建立鏈接:

$root@host:/home/arm/kernel/linux-2.6.22/include# ln –s asm-arm asm

$root@host:/home/arm/kernel/linux-2.6.22/include# ln -s asm/arch-s3c2410 asm/arch

將內核頭文件拷貝到最終安裝目錄下:

$root@host:/home/arm/kernel/linux-2.6.22/include# mkdir –p ${TARGET_PREFIX}/include

$root@host:/home/arm/kernel/linux-2.6.22/include# cp –rd asm-arm ${TARGET_PREFIX}/include

$root@host:/home/arm/kernel/linux-2.6.22/include#

cp –r asm- ${TARGET_PREFIX}/include

$root@host:/home/arm/kernel/linux-2.6.22/include# cp –r linux ${TARGET_PREFIX}/include

$root@host:/home/arm/kernel/linux-2.6.22/include# cp –d asm ${TARGET_PREFIX}/include

 

至此內核頭文件建立完畢。

2、 建立Binary utilities:

binutils是一些二進制工具的集合,其中常用的是as arld

$root@host:/home/arm/kernel/include# cd ${PRJROOT}/build-tools

$root@host:/home/arm/build-tools# tar xvjf binutils-2.18.tar.bz2

$root@host:/home/arm/build-tools# cd build-binutils

$root@host:/home/arm/build-tools/build-binutils#

patch –Np1 –i /home/arm/build-tools/patch/binutils-2.18*

$root@host:/home/arm/build-tools/build-binutils#

../binutils-2.18/configure --target=${TARGET} –prefix=${PREFIX}

$root@host:/home/arm/build-tools/build-binutils# make

$root@host:/home/arm/build-tools/build-binutils# make install

${PREFIX}/bin下應該生成一些以arm-linux開頭的文件

$root@host:/home/arm/build-tools/build-binutils# ls ${PREFIX}/bin

3、 生成glibc頭文件:

$root@host:/home/arm/build-tools/build-binutils# cd ..

$root@host:/home/arm/build-tools/# tar xvjf glibc-2.6.1.tar.bz2

$root@host:/home/arm/build-tools/#

tar xvzf glibc-ports-2.6.1.tar.gz --directory ./glibc-2.6.1/

$root@host:/home/arm/build-tools/# cd glibc-2.6.1

$root@host:/home/arm/build-tools/glibc-2.6.1# mv glibc-ports-2.6.1 ports –v

打上補丁:

$root@host:/home/arm/build-tools/glibc-2.6.1#

patch –Np1 –i /home/arm/build-tools/patch/glibc-2.6.1-*patch

$root@host:/home/arm/build-tools/glibc-2.6.1# cd ..

$root@host:/home/arm/build-tools/# cd build-glibc-headers

這裏需要添加對NPTL線程庫的支持:

$root@host:/home/arm/build-tools/build-glibc-headers# 

echo “libc_cv_forced_unwind=yes”>>config.cache

echo “libc_cv_c_cleanup=yes”>>config.cache

echo “libc_cv_arm_tls=yes”>>config.cache

注:如果編譯中出現”cannot compute long double size”,添加:

echo “ac_cv_sizeof_long_double=12”>>config.cache

$root@host:/home/arm/build-tools/build-glibc-headers#

../glibc-2.6.1/configure --host=${TARGET} --prefix=”/usr” --enable-add-ons

--with-headers=${TARGET_PREFIX}/include --cache-file=config.cache

$root@host:/home/arm/build-tools/build-glibc-headers#

make cross-compiling=yes install_root=${TARGET_PREFIX} prefix=””

install-headers

$root@host:/home/arm/build-tools/build-glibc-headers#

mkdir –p ${TARGET_PREFIX}/include/gnu

$root@host:/home/arm/build-tools/build-glibc-headers#

touch ${TARGET_PREFIX}/include/gnu/stubs.h

注:如果編譯過程中出現找不到頭文件的錯誤,可以根據錯誤提示的文件名用touch命令在相應目錄下建立一個空文件,一般就可以編譯通過了。

4、 生成第一階段gcc

$root@host:/home/arm/build-tools/# tar xvjf gcc-4.2.1.tar.bz2

打補丁:

$root@host:/home/arm/build-tools/# cd gcc-4.2.1

$root@host:/home/arm/build-tools/gcc-4.2.1# 

patch –Np1 –i /home/arm/build-tools/patch/gcc-4.2.1-*

$root@host:/home/arm/build-tools/ gcc-4.2.1# cd ..

$root@host:/home/arm/build-tools/# cd build-boot-gcc

$root@host:/home/arm/build-tools/build-boot-gcc#

../gcc-4.2.1/configure --target=${TARGET} --prefix=${PREFIX}  --with-headers=${TARGET_PREFIX}/include

--with-newlib --enable-languages=c --disable-threads --disable-shared

$root@host:/home/arm/build-tools/build-boot-gcc # make all-gcc

$root@host:/home/arm/build-tools/build-boot-gcc # make install-gcc

${PREFIX}/bin下會生成 arm-linux-開頭的文件:

$root@host:/home/arm/build-tools/build-boot-gcc # ls ${PREFIX}/bin

5、 生成glibc庫文件:

$root@host:/home/arm/build-tools/build-boot-gcc # cd ..

$root@host:/home/arm/build-tools# cd build-glibc

$root@host:/home/arm/build-tools/build-glibc# CC=arm-linux-gcc ../glibc-2.6.1/configure --host=$TARGET --prefix=”/usr”

      --enable-add-ons --with-headers=${TARGET_PREFIX}/include

--cache-file=config.cache

這裏的config.cache與前面編譯glibc頭文件時的config.cache完全相同。

$root@host:/home/arm/build-tools/build-glibc# make

$root@host:/home/arm/build-tools/build-glibc#

make install_root=${TARGET_PREFIX} prefix=”” install

libc.so作出修改:

$root@host:/home/arm/build-tools/build-glibc# cd ${TARGET_PREFIX}/lib

$root@host:/home/arm/tools/arm-linux/lib#  cat libc.so

/* GNU ld script

   Use the shared library, but some functions are only in

   the static library, so try that secondarily.  */

OUTPUT_FORMAT(elf32-littlearm)

GROUP ( /lib/libc.so.6 /lib/libc_nonshared.a  AS_NEEDED ( /lib/ld-linux.so.2 ) )

GROUP這一行的內容改爲:

GROUP ( libc.so.6 libc_nonshared.a  AS_NEEDED ( ld-linux.so.2 ) )

              $root@host:/home/arm/tools/arm-linux/lib#  cat libpthread.so

              /* GNU ld script

            Use the shared library, but some functions are only in

            the static library, so try that secondarily.  */

OUTPUT_FORMAT(elf32-littlearm)

GROUP ( /lib/libpthread.so.0 /lib/libpthread_nonshared.a )

              GROUP這一行的內容改爲:

              GROUP (libpthread.so.0  libpthread_nonshared.a )

6、 生成完整的編譯工具:

$root@host:/home/arm/tools/arm-linux/lib# cd ${PRJROOT}/build-tools/build-gcc

$root@host:/home/arm/build-tools/build-gcc#

../gcc-4.2.1/configure --target=$TARGET --prefix=${PREFIX}  --enable-shared

--enable-languages=c,c++ --with-threads=posix

              $root@host:/home/arm/build-tools/build-glibc# make all

              $root@host:/home/arm/build-tools/build-glibc# make install

 

 

二、 NAND flash 分區管理

這塊2410板自帶了vivi,啓動之後可以進到vivi的提示符下:

vivi>

查看分區情況:

vivi> part show

mtdpart info. (6 partitions)

 

name                            offset                           size                       flag 

vivi                              :0x00000000                 0x00020000           0            128k

param                       :0x00020000                 0x00010000           0            64k

kernel                        :0x00030000                 0x00200000           0            2M

root                            :0x00230000                 0x00300000           4            3M

yaffs                           :0x00530000                 0x03a00000           8            58M

使用part命令可以添加、刪除各個mtd分區。

另外還有一種分區格式:BON,具體用法參照bon命令幫助即可。2.6內核對mtd分區格式支持的很好,所以這裏採用了mtd分區方式。

       其中vivibootloader區,param是存放啓動參數設置區,kernel是內核鏡像文件區,root是啓動文件系統區,yaffs是文件系統區,可以視情況修改這些區域的大小。

三、  網卡和LCD驅動的移植

1.  網卡驅動移植:

這塊板使用的是DM9000的網卡芯片,驅動的源代碼在內核源代碼的目錄中可以找到:

$root@host:/home/arm/#  cd kernel/linux-2.6.22

$root@host:/home/arm/kernel/linux-2.6.22# cd drivers/net

$root@host:/home/arm/kernel/linux-2.6.22/drivers/net# ls dm*

dm9000.c              dm9000.h

修改dm9000.c

$root@host:/home/arm/kernel/linux-2.6.22# vi dm9000.c

      找到函數:

static int dm9000_probe(struct platform_device *pdev)

{

       ……….

       int ret=0;

       int iosize;

       int i;

       u32 idval

//添加下面數組,前6個數作爲網卡的mac地址,注意不能和現有的網卡衝突

       unsigned char ne_defethadder[]={0x08,0x08,0x08,0x08,0x12,0x27,0}

       ………………………….

       ………………………….

       /* Set Node Address */

       for (i = 0; i < 6; i++)

              ndev->dev_addr[i] = db->srom[i];

 

       if (!is_valid_ether_addr(ndev->dev_addr)) {

              /* try reading from mac */

 

              for (i = 0; i < 6; i++)

              //修改mac地址

              //     ndev->dev_addr[i] = ior(db, i+DM9000_PAR);

                     ndev->dev_addr[i]=ne_defethaddr[i];

              ………………………

              ……………………….

       }

退出保存。

修改smdk2410.c

$root@host:/home/arm/kernel/linux-2.6.22# cd arch/arm/mach-s3c2410

$root@host:/home/arm/kernel/linux-2.6.22/arch/arm/mach-s3c2410#

vi mach-smdk2410.c

mach-smdk2410.c中添加如下內容:

…………

#include <asm/plat-s3c24xx/common-smdk.h>

//添加:

#include <linux/dm9000.h>

…………

………….

#define UCON S3C2410_UCON_DEFAULT

#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB

#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE

//添加:

 

static struct resource s3c_d9k_resource[]=

{

       [0]={

              .start      =0x10000000,

              .end =0x10000000,

              .flags=IORESOURCE_MEM

       },

       [1]={

              .start      =0x10000000+0x2,

              .end =0x10000000+0x2,      

              .flags=IORESOURCE_MEM

       },

       [2]={

              .start      =IRQ_EINT2,             

              .end =IRQ_EINT2,

              .flags     =IORESOURCE_IRQ

       }

};

static struct dm9000_plat_data s3c_device_d9k_platdata = {

        .flags= DM9000_PLATF_16BITONLY

};

 

struct platform_device s3c_device_d9k = {

        .name= "dm9000",

        .id= 0,

        .num_resources= ARRAY_SIZE(s3c_d9k_resource),

        .resource= s3c_d9k_resource,

        .dev= {

                .platform_data = &s3c_device_d9k_platdata,

        }

};

………………….

………………….

static struct platform_device *smdk2410_devices[] __initdata = {

       &s3c_device_usb,

       //啓動lcd

       &s3c_device_lcd,

       &s3c_device_wdt,

       &s3c_device_i2c,

       &s3c_device_iis,

       //添加

       &s3c_device_d9k

       //&s3c_device_ts,

};

需要注意的是起始地址和中斷號的選擇。這塊板上DM9000芯片的INT引腳接的是EINT2CMD引腳接的是A1CS引腳接的是nGCS2,所以DM9000index端口地址是0x10000000data端口地址是0x10000000+0x00000002,據此設置結構resource s3c_d9k_resource中的參數。最後在內核編譯時加上對DM9000驅動的支持就可以了,具體見內核配置和編譯。

2.  LCD驅動移植:

繼續在mach-smdk2410.c中添加如下內容:

………….

#include <asm/arch/fb.h>

#include <asm/arch/regs-gpio.h>

#include <asm/arch/regs-lcd.h>

………….

………….

static struct s3c2410fb_mach_info smdk2410_lcdcfg __initdata={

       .type=S3C2410_LCDCON1_TFT,

       .fixed_syncs= 0,

       .regs={

              .lcdcon1=       S3C2410_LCDCON1_TFT16BPP|

                            S3C2410_LCDCON1_TFT |

                            S3C2410_LCDCON1_CLKVAL(0X01),     /*HCLK/4*/

              .lcdcon2=       S3C2410_LCDCON2_VBPD(18)|       /*19*/

                            S3C2410_LCDCON2_LINEVAL(479)|

                            S3C2410_LCDCON2_VFPD(10)|       /*11*/

                            S3C2410_LCDCON2_VSPW(14),      /*15*/

              .lcdcon3=       S3C2410_LCDCON3_HBPD(43)|

                            S3C2410_LCDCON3_HOZVAL(639)|       /*640*/

                            S3C2410_LCDCON3_HFPD(115),     /*116*/

              .lcdcon4=       S3C2410_LCDCON4_MVAL(0)  |

                            S3C2410_LCDCON4_HSPW(95),      /*96*/

              .lcdcon5=       S3C2410_LCDCON5_FRM565   |

                            S3C2410_LCDCON5_INVVLINE|

                            S3C2410_LCDCON5_INVVFRAME|

                            S3C2410_LCDCON5_PWREN|

                            S3C2410_LCDCON5_HWSWP,

       },

       .lpcsel=   ((0XCE6)&~7)|1<<4,//0x0,

       .gpccon= 0xAA8002A8,//0xaaaaaaaa,

       .gpccon_mask=     0xFFC003FC,//0xffffffff,

       .gpcup=         0xF81E,//0xffffffff,

       .gpcup_mask=      0xF81E,//0xffffffff,

       .gpdcon= 0xAA80AAA0,//0xaaaaaaaa,

       .gpdcon_mask=    0xFFC0FFF0,//0x0,

       .gpcup=         0xF8FC,//0xffffffff,

       .gpcup_mask=      0xF8FC,//0xffffffff,

      

       .width=          640,//240,

       .height= 480,//320,

       .xres=            {640,640,640},//{240,240,240}, .min .max .defval

       .yres=            {480,480,480},//{320,320,320},

       .bpp=             {16,16,16},   //{16,16,16}, 

};

……………

……………

static void __init smdk2410_init(void)

{

       s3c24xx_fb_set_platdata(&smdk2410_lcdcfg);

       platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));

       smdk_machine_init();

}

………………..

注:註釋掉drivers/char/vt.cblank_screen_t(unsigned long dummy)的函數內容,否則lcd會在10分鐘左右關掉顯示。

最後在內核編譯時需要選中對LCD的支持,具體見內核配置和編譯。

 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章