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

时间:2021-06-10 16:36:35

六,添加對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卡,最好做個命令菜單哈哈