您的位置:首页 > 其它

u-boot-2009.08移植笔记六,平台TQ2440 .

2013-03-19 21:05 381 查看
六,添加對yaffs2根文件系統的支持,由於我們使用的是NAND flash存儲器,而Yaffs2文件系統

就是專門為這個使用的。至於移植的具體步驟這裡先省略了

七,引導Linux系統

1.在CM2440.h中添加宏

/* for tag(s) to transfer message to kernel */

#define CONFIG_SETUP_MEMORY_TAGS    1

#define CONFIG_CMDLINE_TAG        1

#define CONFIG_INITRD_TAG        1

#define CONFIG_BOOTARGS                 "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200 mem=64M"

Linux内核的启动参数可以由内核默认设定,也可以通过u-boot传递。相对来说,

u-boot传递的灵活性更强,只须设置bootargs环境变量即可。

程序先判断是否定义了CONFIG_CMDLINE_TAG等,才决定是否给内核传递参数

這裡定義了由U-BOOT傳遞啟動參數給Linux

2、更改 mach_type 参数,修改 include/asm-arm/mach_types.h,

#define MACH_TYPE_S3C2440    168

将数值改为和内核的 mach_type 一至。至于内核的 mach_type 可以在内核 linux 源代

码下的 arch/arm/tools 中的 mach_types 文件查看到。

3、用 mkzImage 给 zImage 加头信息

mkimage -n 'linux-2.6.25.8' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000

-d zImage.bin zImage.img

4.還要增加bootm命令

#define CONFIG_BOOTCOMMAND "nand read 0x30008000 0x200000 0x300000; bootm 0x30008000"

編譯下載到NAND,並保存saveenv環境變量,重啟如果成功了,

那就是人品了,呵呵

修改的就這麼多,但是移植過程中卡在這裡的時間也最多

大致出現問題有下面兩種

1.Uncompressing Linux.................................

...... done, booting the kernel.

啟動到這裡停止

2.undefined instruction  

pc : [<30008028>]         ....

Flags: nzCv  IRQs off  FIQs off  Mode SVC_32  

Resetting CPU ...  

然後又複位了

對於第一種情況:

查了些資料,

出现卡死在这里只有三种情况,如下:

1). console设置没有传递到内核

2). u-boot的时钟设置不在405MHz,与Kernel的不一致

3). Machine ID设置的与Kernel不一致

第一種情況我完整的定義了宏,參數應該沒問題,

第三種情況,在nclude/asm-arm/mach-types.h

修改#define MACH_TYPE_S3C2440 168 與TQ提供內核一樣

那可能出現的情況就在第二種了,我查看了TQ的源碼,時鐘設置在400MHZ是可以啟動的

這個問題糾結了 ,結果在在解決下面的問題后這個問題也解決了。

第二種狀況,就更糾結了。系統根本就不能引導

系統不斷複位提示指令出錯

注意看這個宏

#define CONFIG_BOOTCOMMAND "nand read 0x30008000 0x200000 0x300000; bootm 0x30008000"

沒錯啊,搬運Linux內核到鏈接指定0x30008000 運行

    為什麼當時移植U-BOOT-1.1.6到TQ2440時沒有出現這種情況,分析了下源碼

他在EmbedSky.h中有這樣的定義

#define CONFIG_BOOTCOMMAND        "boot_zImage"

而這個命令在lib_arm/boot_zImage.c文件中

函數題如下

int boot_zImage(ulong from, size_t size)

{

    int ret;

    ulong boot_mem_base;    /* base address of bootable memory */

    ulong to;

    ulong mach_type;

   

boot_mem_base = 0x30000000;

   

/* copy kerne image */

   

to = boot_mem_base + LINUX_KERNEL_OFFSET;

    printf("Copy linux kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ... ",

        from, to, size);

    ret = copy_kernel_img(to, (char *)from, size);

........

........

........

}

TQ的源碼中他也是將內核搬運到

to = boot_mem_base + LINUX_KERNEL_OFFSET;//to=0x30008000

這個地址運行的阿

困惑的好久,問題在這

bootm命令只能用来引导经过mkimage构建了镜像头的内核镜像文件以及根文件镜像

,对于没有用mkimage对内核进行处理的话,那直接把内核下载到连接脚本中指定的

加载地址0x30008000再运行就行,内核会自解压运行(不过内核运行需要一个tag

来传递参数,而这个tag是由bootloader提供的,在u-boot下默认是由bootm命

令建立的)。

TQ提供的內核沒有經過mkimage加上頭信息,所以可以直接下載到0x30008000這個地址

運行,而我使用了bootm命令,並且給linux加上了頭信息,在u-boot目錄下tools目錄

命令如下:

mkimage -n 'linux-2.6.25.8' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000

-d zImage.bin zImage.img

加載地址是0x30008000 入口地址也0x30008000 但加上頭信息的內核前面要加上

64B,故實際內核入口地址應該是0x30008040

在以為兄弟博客里找到對bootm命令的分析:
http://blog.csdn.net/liangkaiming/archive/2010/11/04/5986680.aspx

ulong load_addr = CFG_LOAD_ADDR;  /* Default Load Address */

int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

       ......

        if (argc < 2) {

             addr = load_addr;//当bootm命令后面不带地址参数时,将默认的加载地址赋值给addr

        } else {

             addr = simple_strtoul(argv[1], NULL, 16); //如果bootm命令后面带了加载地址,则将该地址赋值给addr,所以最终有用的地址还是bootm命令后附带的地址

        }

        ......

       

        //

        switch (hdr->ih_comp) { //开始判断利用mkimage命令后是否对内核镜像进行了压缩

        case IH_COMP_NONE:  //如果没有被压缩,只是在原有的内核镜像前加了一个头

                 if(ntohl(hdr->ih_load) == addr) { //这步很重要,涉及到我们要讨论的两个地址,我们知道在利用mkimage时指定-a选项后面就是指定的内核加载的地址,这个地址会被存放到镜像头结构的ih_load成员变量中如在smdk2410中ih_load为0x30008000,在这里开始作地址的判断,如果指定的加载地址和之前的addr也就是bootm后面附带的地址相同,则不用将内核镜像搬到其他地方,就在这个地址上执行,这样内核的入口地址就要在加载地址之后的64个字节(因为镜像头占了64个字节),所以入口地址为0x30008040

                       printf ("   XIP %s ... ", name);

                 } else {//如果指定的加载地址和bootm命令后的附加地址不相同,我们看看下面data此时表示的是什么地址:data = addr + sizeof(image_header_t);可以看到如果指定加载地址与bootm命令后地址不相同,则从bootm命令后面地址所在地取出内核镜像的头进行检验,检验完后data指向真正的内核,然后将内核拷贝到指定的加载地址处来进行自解压运行,这个时候内核的入口地址就和加载地址一样,不需要加上40个字节,因为内核镜像前面的40个字节的头已经被取出来了。

                       memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);

                  }

        case IH_COMP_GZIP://如果利用mkimage时对内核镜像进行了压缩,则需要在u-boot内进行第一阶段的解压缩,将解压后的内核镜像存放到指定的加载地址ih_load,然后内核镜像自解压启动

                 printf ("   Uncompressing %s ... ", name);

                 if (gunzip ((void *)ntohl(hdr->ih_load), unc_len,(uchar *)data, &len) != 0) {

                       puts ("GUNZIP ERROR - must RESET board to recover\n");

                       SHOW_BOOT_PROGRESS (-6);

                      do_reset (cmdtp, flag, argc, argv);

                 }

                 break;

     

}

以上對bootm後面帶的參數進行的比較,如果不帶地址參數,就如TQ提供的u-boot源碼

直接將将默认的加载地址赋值给addr

而對於加了頭信息的內核,bootm命令后面带了加载地址,则将该地址赋值给addr,所以

最终有用的地址还是bootm命令后附带的地址

bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址是否相同

(1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之

(2)如果相同的话那就让其原封不同的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。

好了到這裡問題已經清楚了

我們bootm後面跟的是0x30008000,與入口地址是相同的,由於加了頭信息所以這個地址

根本不是我們內核的入口地址

解決方法來了

修改bootm命令,u-boot控制台下

#set bootcmd 'nand read 0x30001000 0x200000 0x300000;bootm 0x30001000'

#saveenv

這個0x30001000地址我隨意給的,試過在其他幾個地址也可以(但覺得也不是任意的)

這個方法就是在0x30001000處提取頭信息,然後將內核複製到0x30008000這個地址開始運行

還有一個辦法就是修改頭信息的的地址

mkimage -n 'linux-2.6.25.8' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040

-d zImage.bin zImage.img

#tftp 0x30008000 zImage.img

#bootm 0x30008000

到此頭痛好幾天的問題解決了

臨近期末,四級又來了。。悲催咯,U-BOOT基本部分完成了,至於源碼還沒仔細分析過,

等考完了才來完善USB,

SD卡,最好做個命令菜單哈哈
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: