2012年(135)
分类:
2012-09-19 11:50:45
原文地址:U-BOOT全线移植(2) 作者:iibull
关于u-boot的移植如下,由于u-boot的软件设计体系非常清晰,它的移植工作并不复杂,相信各位的代码阅读功力不错的话,参照如下就可以完成。
×××××××××××××××××××××××××××××××××××
If the system board that you have is not listed, then you will need to port U-Boot to your hardware platform. To do this, follow these steps:
1. Add a new configuration option for your board to the toplevel "Makefile" and to the "MAKEALL" script, using the existing entries as examples. Note that here and at many other places boards and other names are listed in alphabetical sort order. Please keep this order.
2. Create a new directory to hold your board specific code. Add any files you need. In your board directory, you will need at least the "Makefile", a ".c", "flash.c" and "u-boot.lds".
3. Create a new configuration file "include/configs/.h" for your board
4. If you're porting U-Boot to a new CPU, then also create a new directory to hold your CPU specific code. Add any files you need.
5. Run "make _config" with your new name.
6. Type "make", and you should get a working "u-boot.srec" file
7. Debug and solve any problems that might arise. [Of course, this last step is much harder than it sounds.]
××××××××××××××××××××××××××××××××××××
(一)在board文件夹下面建立自己的开发板的文件夹。一般的,要选取与自己的开发板硬件设置最为接近的型号。在u-boot-1.1.1中,已经支持at91rm9200,所以可以选取at91rm9200dk作为模板进行修改。设置你的开发板的名字,随意即可,我的设置为:myboard。
[root@dding u-boot-1.1.1]$ cd board
[root@dding board]$ cp -R at91rm9200dk/ myboard/
[root@dding board]$ cd myboard
[root@dding myboard]$ ls
at91rm9200dk.c config.mk flash.c Makefile u-boot.lds
(二)可以看到,这里共有5个文件。首先,要修改主文件的名字,即要把at91rm9200dk.c更改为myboard.c。其次,要更改config.mk中TEXT_BASE的数值,其为uboot在RAM中的运行地址。注意,由于at91rm9200中是由boot.bin将uboot映象直接拷贝到RAM中了,TEXT_BASE值必须和boot.bin拷贝的地址一致。否则uboot发现运行地址和链接地址不同时会再次执行自拷贝过程,可能将自己覆盖。由于接下来,因为在at91rm9200dk用的是AMD的flash,而我的开发板上用的是Intel的28F128J3A,那么需要另外找Intel的flash.C,以减少工作量。在strong ARM构架里有xm250,它的flash是Intel的,修改的东西并不是很多。需要注意的是,xm250的flash位宽是32,而我的位宽是16,要根据这个进行相应的修改。最后,修改Makefile,主要是修改生成文件的名字。具体操作如下:
[root@dding myboard]$ mv at91rm9200dk.c myboard.c
[root@dding myboard]$ cat config.mk
TEXT_BASE = 0x21f80000
[root@dding myboard]$ vi config.mk
修改成:TEXT_BASE = 0x21f00000,然后保存退出。
[root@dding myboard]$ vi Makefile
include $(TOPDIR)/config.mk
LIB = lib$(BOARD).a
OBJS := myboard.o flash.o
SOBJS :=
$(LIB): $(OBJS) $(SOBJS)
$(AR) crv $@ $(OBJS) $(SOBJS)
clean:
rm -f $(SOBJS) $(OBJS)
[root@dding myboard]$ rm flash.c
[root@dding myboard]$ cp ../xm250/flash.c ./
[root@dding myboard]$ ls
config.mk flash.c Makefile myboard.c u-boot.lds
[root@dding myboard]$ vi flash.c
34 #undef FLASH_PORT_WIDTH32 /*不定义位宽32*/
35 #define FLASH_PORT_WIDTH16 /*定义位宽16*/
216 switch (value) {
217
218 case (FPW) INTEL_ID_28F128J3A: /*就是这个芯片*/
219 info->flash_id += FLASH_28F128J3A;
220 info->sector_count = 128;
221 info->size = 0x01000000;
222 break; /* => 16 MB */
223
224 case (FPW) INTEL_ID_28F640J3A:
225 info->flash_id += FLASH_28F640J3A;
226 info->sector_count = 64;
227 info->size = 0x00800000;
228 break; /* => 8 MB */
[root@dding myboard]$ cd ../..
[root@dding u-boot-1.1.1]$ vi Makefile
#########################################################################
## AT91RM9200 Systems
#########################################################################
at91rm9200dk_config : unconfig
@./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk
myboard_config : unconfig
@./mkconfig $(@:_config=) arm at91rm9200 myboard
#########################################################################
在这里,可以在命令模式下输入“/at91rm9200”快速查找at91rm9200dk,仿照它的例子,写出自己板子的配置。注意的是,第二行开头要用TAB键,不是空格,否则报错。选项arm表示目标板架构,at91rm9200表示CPU中对应的目录,myboard是你自己的开发板名字,对应board下的目录。
(三)修改主要的配置文件。配置选项比较多,主要是配置cpu,波特率,flash和sdram的类型大小,环境变量的偏移量等等,容易出错。应该首先了解硬件情况,仔细对应芯片资料进行修改。见上面的《AT91RM9200开发板的存储器情况》
[root@dding u-boot-1.1.1]$ cd include/configs
[root@dding configs]$ cp at91rm9200dk.h myboard.h
[root@dding configs]$ vi myboard.h
#define CONFIG_ myboard 1 /* on an myboard Board */
#undef CONFIG_USE_IRQ /* we don't need IRQ/FIQ stuff */
#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 128*1024)
#define CONFIG_BAUDRATE 115200
#define CONFIG_BOOTDELAY 3 // u-boot延时等待时间
/* #define CONFIG_ENV_OVERWRITE 1 */
#define CONFIG_COMMANDS \
((CONFIG_CMD_DFL | \
CFG_CMD_DHCP ) & \
~(CFG_CMD_BDI | \
CFG_CMD_IMI | \
CFG_CMD_AUTOSCRIPT | \
CFG_CMD_FPGA | \
CFG_CMD_MISC | \
CFG_CMD_LOADS ))
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */
#include
#define CONFIG_NR_DRAM_BANKS 1 // sdram banks,我的是一个,通常都是一个
#define PHYS_SDRAM 0x20000000 // sdram起始地址,at91rm9200统一为0x20000000
#define PHYS_SDRAM_SIZE 0x2000000 /* 32 M */
// sdram容量32MB,需要根据实际情况修改,芯片为两片三星的16位×16M K4S281632F
#define CFG_MEMTEST_START PHYS_SDRAM
#define CFG_MEMTEST_END CFG_MEMTEST_START + PHYS_SDRAM_SIZE – 0x10 0000
SDRAM的高端部分此时运行着U-boot,测试时不能对自身进行
#define CONFIG_DRIVER_ETHER 支持以太网驱动
#define CONFIG_NET_RETRY_COUNT 20
// flash为intel的16M 28F128J3A in 128 Sectors
#define PHYS_FLASH_1 0x10000000 //起始地址,at91rm9200统一为0x10000000
#define PHYS_FLASH_SIZE 0x100 0000 /* 16M main flash */
#define CFG_FLASH_BASE PHYS_FLASH_1 // PHYS_FLASH_1 flash起始地址别名
#define CFG_MAX_FLASH_BANKS 1 // flash最大banks数
#define CFG_MAX_FLASH_SECT 128 //扇区总数
#define CFG_FLASH_ERASE_TOUT (2*CFG_HZ) /* Timeout for Flash Erase */
#define CFG_FLASH_WRITE_TOUT (2*CFG_HZ) /* Timeout for Flash Write */
PHYS_FLASH_SIZE和CFG_MAX_FLASH_SECT通常都未用,因此上述错误没有体现出来
#define CFG_ENV_IS_IN_FLASH 1 // 环境变量保存在flash中
#define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x20000×127) // 环境变量在flash中的地址
#define CFG_ENV_SIZE 0x20000 // 环境变量的大小,一个sector
#define CFG_LOAD_ADDR 0x21000000 /* default load address */
// 内核印象默认的加载地址,需要与自启动的参数匹配下
// 关于U-boot的启动代码等大小和地址对任何CPU都无需改动,但是实际往flash中存储时需要按照此地址来进行
//boot.bin 0x1000 0000
//u-boot.gz 0x1001 0000
#define CFG_BOOT_SIZE 0x6000 /* 24 KBytes */ // boot.bin的大小
#define CFG_U_BOOT_BASE (PHYS_FLASH_1 + 0x10000) // u-boot.gz的存放位置,此位置不能随意更改,必须和boot.bin中的地址一致
#define CFG_U_BOOT_SIZE 0x10000 /* 64 KBytes */ // u-boot.gz占据的flash空间,半个sector
#define CFG_BAUDRATE_TABLE {115200 , 19200, 38400, 57600, 9600 }
#define CFG_PROMPT "Uboot> " /* Monitor Command Prompt */ // U-boot的提示符,可随意更改
#define CFG_CBSIZE 256 /* Console I/O Buffer Size */
#define CFG_MAXARGS 16 /* max number of command args */
#define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */
四、编译u-boot
[root@dding configs]$ cd ../..
[root@dding u-boot-1.1.1]$ make myboard_config
Configuring for myboard board...
[root@dding u-boot-1.1.1]$ make CROSS_COMPILE=arm-linux-
生成三个文件:u-boot.bin, u-boot, u-boot.srec
u-boot.bin is a raw binary image
u-boot is an image in ELF binary format
u-boot.srec is in Motorola S-Record format (objcopy -O srec -R.note -R.comment -S [inputfile] [outfile]
u-boot ELF格式的文件,可以被大多数Debug程序识别;
u-boot.bin—二进制bin文件,纯粹的U-BOOT二进制执行代码,不保存ELF格式和调试信息。这个文件一般用于烧录到用户开发板中;
u-boot.srec— Motorola S-Record格式,可以通过串行口下载到开发板中。
然后把生成的u-boot.bin保存,并且压缩一下得到u-boot.bin.gz。
一种方式是通过JTAG口将u-boot.bin烧写到Flash的零地址,复位后就可以启动系统了。此时无需boot.bin。
但是对于at91rm9200,我们是通过boot.bin来过渡的,烧写的是u-boot.bin.gz。以上工作完成我们可以通过串口将u-boot.bin下载到主板的SDRAM中,它会自动执行, 并出现uboot>
这里我们可以通过串口把boot.bin, u-boot.bin.gz下载到主板,再用u-boot的提供的写flash功能分别把boot.bin, u-boot.bin.gz写入到flash中,完成以上工作后,对主板跳线选择片外启动,板子复位后会自动启动u-boot。其首先运行boot.bin,其将u-boot.bin.gz解压缩到RAM中为u-boot.bin,并跳转至u-boot.bin开始执行。
4.1.1 非压缩内核Image 1) 运行地址!=链接地址0x20008000,不能启动 Uboot> tftp 21000000 Image;tftp 21100000 ramdisk;go 21000000 。。。。 done Bytes transferred = 6993691 (6ab71b hex) ## Starting application at 0x21000000 ... Error: a 在哪提示的? 2) 运行地址=链接地址0x20008000,不能启动,难道是ramdisk的问题 Uboot> tftp 20008000 Image;tftp 21100000 ramdisk;go 20008000 。。。。 done Bytes transferred = 6993691 (6ab71b hex) ## Starting application at 0x21000000 ... Error: a 4.1.2 压缩内核zImage 1) 运行地址!=链接地址0x20008000,能启动,内核自解压成功,但是解压后的内核运行错误 Uboot> tftp 21000000 zImage;tftp 21100000 ramdisk;go 21000000 。。。。。。。。。。。 done Bytes transferred = 6993691 (6ab71b hex) ## Starting application at 0x21000000 ... Uncompressing Linux............................................................. done, booting the kernel. €?~??鄜屈 2) 运行地址==链接地址0x20008000,能启动,内核自解压成功,但是解压后的内核运行错误 Uboot> tftp 20008000 zImage;tftp 21100000 ramdisk; go 20008000 ## Starting application at 0x20008000 ... Uncompressing Linux............................................................. done, booting the kernel. €?~??鄜屈 上面的ramdisk都是添加了uboot的头的,去掉头部再试试。去掉了还是不行,go方法的ramdisk的地址是怎么设置的??要详细看下uboot在ramdisk这块是如何跟内核交互的? 通过mkimage这个tool可以给zImage添加一个header: typedef struct image_header { uint32_t ih_magic; /* Image Header Magic Number */ uint32_t ih_hcrc; /* Image Header CRC Checksum */ uint32_t ih_time; /* Image Creation Timestamp */ uint32_t ih_size; /* Image Data Size */ uint32_t ih_load; /* Data Load Address */ uint32_t ih_ep; /* Entry Point Address */ uint32_t ih_dcrc; /* Image Data CRC Checksum */ uint8_t ih_os; /* Operating System */ uint8_t ih_arch; /* CPU architecture */ uint8_t ih_type; /* Image Type */ uint8_t ih_comp; /* Compression Type */ uint8_t ih_name[IH_NMLEN]; /* Image Name */ } image_header_t; 此header是如何生成的?利用u-boot里面的mkimage工具来生成uImage (u-boot源码包/tools/mkimage.c ) 这里解释一下参数的意义: -A ==> set architecture to 'arch' -O ==> set operating system to 'os' -T ==> set image type to 'type' “kernel或是ramdisk” -C ==> set compression type 'comp' -a ==> set load address to 'addr' (hex) -e ==> set entry point to 'ep' (hex)(内核启动时在此位置查询完整的内核印象) -n ==> set image name to 'name' -d ==> use image data from 'datafile' -x ==> set XIP (execute in place,即不进行文件的拷贝,在当前位置执行) 对于ARM linux内核映象用法: -A arm -------- 架构是arm Bootm命令在/common/cmd_bootm.c中do_bootm函数 》》》》》》》》》》》获取当前内核的地址,默认地址或者bootm的第一个参数 默认的加载地址或传递给bootm命令(优先)与实际的内核存放地址需要一致 if (argc < 2) { addr = load_addr; // load_addr = CFG_LOAD_ADDR; } else { addr = simple_strtoul(argv[1], NULL, 16); } printf ("## Booting image at %08lx ...\n", addr); 》》》》》》》》》》》》获得image头,没有mkimage的就返回了 memmove (&header, (char *)addr, sizeof(image_header_t)); 》》》》》》》》》》》》打印头部信息 print_image_hdr ((image_header_t *)addr); 实例: Image Name: dd-kernel-2.4.19 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 869574 Bytes = 849.2 kB Load Address: 20008000 Entry Point: 20008000 》》》》》》》》》》》》校验image头部 printf (" Verifying Checksum ... "); printf ("OK\n"); 》》》》》》》》》》》》检查image支持的体系结构即—A 选项是否为arm或者ppc等 》》》》》》》》》》》》检查image的类型 TYPE_MULTI 是否指内核与文件系统一起,内核后面有个分界线 switch (hdr->ih_type) case IH_TYPE_KERNEL: name = "Kernel Image"; break; case IH_TYPE_MULTI: 》》》》》》》》》》判断内核的压缩类型 此处的内核是否压缩非zImage和Image的概念,而是指内核在被mkimage处理前是否用gunzip等压缩过 switch (hdr->ih_comp) { case IH_COMP_NONE: // 非压缩内核 if(ntohl(hdr->ih_load) == addr) { // 当前内核存放的地址与-a指定的一致,则不搬动,-e必须必-a大0x40 printf (" XIP %s ... ", name); } else { //当前内核存放的地址与-a指定的不一致,则将内核搬到-a地址,此时-a与-e必相同 memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); 。。。。 case IH_COMP_GZIP: printf (" Uncompressing %s ... ", name); if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, //压缩内核,将除去头部的内核解压到-a 指定的地址了,要求-a与-e相同 // 为防止解压缩时覆盖,对于压缩内核,内核存放地址最好在—a后面 (uchar *)data, (int *)&len) != 0) { do_reset (cmdtp, flag, argc, argv); } break; 》》》》》》》》》》》》》》》》判断操作系统类型 switch (hdr->ih_os) { default: /* handled by (original) Linux case */ case IH_OS_LINUX: do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); //前四个为传给bootm的,addr为内核最初的存放地址,没有用处 break; #ifdef CONFIG_PPC static boot_os_Fcn do_bootm_linux; #else extern boot_os_Fcn do_bootm_linux; 由上可知,对于ppc和其他体系结构的do_bootm_linux函数实现是不一样的 》》》》》》》》》》》》》》启动Linux内核 do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], ulong addr, ulong *len_ptr, int verify) 》》》》》》》》》》》》获取命令行参数 if ((s = getenv("bootargs")) == NULL) s = ""; strcpy (cmdline, s); 》》》》》》》》》》》》赋内核启动地址 kernel = (void (*)(bd_t *, ulong, ulong, ulong, ulong))hdr->ih_ep; 注意,对于压缩过的内核,会将内核解压到-a指定的地址,此时-a 与-e 地址必须相同 》》》》》》》》》》》判断bootm的命令参数中是否有initrd if (argc >= 3) { addr = simple_strtoul(argv[2], NULL, 16); printf ("## Loading RAMDisk Image at %08lx ...\n", addr); 若有initrd则赋值,否则为0 》》》》》》》》》》》》》》》启动Linux内核 /* * Linux Kernel Parameters: * r3: ptr to board info data * r4: initrd_start or 0 if no initrd * r5: initrd_end - unused if r4 is 0 * r6: Start of command line string * r7: End of command line string */ //*kbd = *(gd->bd); 在上面赋值的 (*kernel) (kbd, initrd _start, initrd_end, cmd_start, cmd_end); 启动流程的总结: 对于非gzip压缩的内核,bootm命令会首先判断bootm xxxx 这个指定的地址xxxx是否与-a指定的加载地址相同。 (1)如果不同的话会从这个地址开始提取出这个64byte的头部,对其进行分析,然后把去掉头部的内核复制到-a指定的load地址中去运行之(此时-e选型必须同-a) (2)如果相同的话那就让其原封不动的放在那,但-e指定的入口地址会推后64byte,以跳过这64byte的头部。 对于gzip压缩过的内核,因为u-boot要对其解压,因此运行地址是不能等于-a指定的地址的,且必须有一定的间隔,否则解压到-a的内核会覆盖当前运行的程序。此时要求-a等于-e指定的地址。 1> mkimage 如何指定入口参数 ( -e 0xxxxxx) 2> mkimage 指定了入口参数后, 你用tftpboot 下载kernel到哪个地址? 3> -c 如何指定? u-boot里面的解压和内核自解压的区别: u-boot 里面的解压实际上是bootm 实现的 , 把 mkimage -C bzip2或者gzip 生成的 uImage进行解压 ; 而kernel的自解压是对zImage进行解压,发生在bootm解压之后。 U-boot 对内核添加头部时,前面已经用gzip压缩过一次内核了,而不是指原有的内核印象是否是压缩内核。指uImage 本身被压缩了,即对原来的zImage/Image添加了U-boot的压缩方式,使得生成的uImage变小了。此时-c gzip 若没有对zImage/Image用gzip命令压缩过,则-c none。 综合上面分析,mkimage的影响因子为: -e,内核的入口地址是否与-a相同 Tftpaddr,即将内核加载到RAM中运行的地址,决定是否搬运或解压内核 -c,内核是否经过gzip压缩过,决定了是搬运还是解压 另外内核本身为非压缩的Image或zImage也是一个影响因子。组合情况共2^4 =16种 4.5.1 非压缩的Image内核 (1)Mkimage 之前用gzip对Image进行压缩 <1> -a=-e = 0x20008000,tftpaddr= 0x21000000 解压到-a指定的地址,成功启动 Uboot> tftp 21000000 uImage-zip-8000;tftp 21100000 ramdisk;bootm 21000000 ## Booting image at 21000000 ... Image Name: dd-kernel-2.4.19-zip-8000 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 869629 Bytes = 849.2 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK Uncompressing Kernel Image ... OK Starting kernel ... Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #42 四 10月 11 14:15:35 CST 2007 AT91RM9200DK login: root <2> -a=-e = 0x20008000, tftpaddr= 0x20008000 解压失败,启动失败 Uboot> tftp 20008000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000 Uboot> tftp 20008000 uImage-zip-8000;tftp 21100000 ramdisk;bootm 20008000 ## Booting image at 20008000 ... Image Name: dd-kernel-2.4.19-zip-8000 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 869629 Bytes = 849.2 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK Uncompressing Kernel Image ... Error: inflate() returned -3 GUNZIP ERROR - must RESET board to recover 由于当前运行地址tftpaddr与解压缩后的地址-a重合了,导致解压缩失败,因此二者必须相隔一定的距离 <3> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x21000000 能够解压到-a地址,但-e指定的入口不对,启动失败 Uboot> tftp 21000000 uImage-zip-8040;tftp 21100000 ramdisk;bootm 21000000 TFTP from server 192.168.0.12; our IP address is 192.168.0.15 Filename 'uImage-zip-8040'. Load address: 0x21000000 。。。。。。。。。 ## Booting image at 21000000 ... Image Name: dd-kernel-2.4.19-zip-8040 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 869629 Bytes = 849.2 kB Load Address: 20008000 Entry Point: 20008040 Verifying Checksum ... OK Uncompressing Kernel Image ... OK Starting kernel ... 死了 <4> -a=-e = 0x20008000, tftpaddr= 0x20008000 解压失败,入口也不对,启动失败 (2)Mkimage 之前未对Image进行压缩 <1> -a=-e = 0x20008000 tftpaddr= 0x21000000 搬动到-a指定的地址,成功启动 Uboot> tftp 21000000 uImage-nzip-8000;tftp 21100000 ramdisk;bootm 21000000 ## Booting image at 21000000 ... Image Name: dd-kernel-2.4.19-nzip-8000 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1873059 Bytes = 1.8 MB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... Bad Data CRC 为什么总是校验失败呢?当前的内核印象为1.8M,难道太大了,后面的ramdisk将其覆盖?? 下面未拷贝ramdisk,校验成功,成功启动,无法安装跟文件系统,是因为无ramdisk。说明上面确实是覆盖了,因此要对于大的内核印象要合理设置tftpaddr的地址和ramdisk的地址 Addr(ramdisk)= 0x2110 0000 Addr(tftpaddr)= 0x2100 0000 Addr(ramdisk)-Addr(tftpaddr)= 0x10 0000 = 1M < 1.8M Uboot> tftp 21000000 uImage-nzip-8000;bootm 21000000 ## Booting image at 21000000 ... Image Name: dd-kernel-2.4.19-nzip-8000 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1873059 Bytes = 1.8 MB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK OK Starting kernel ... Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #44 四 10月 11 17:27:24 CST 2007 。。。。。。。 Kernel panic: VFS: Unable to mount root fs on 01:00 Addr(ramdisk)- 2M = 0x20f0 0000 = Addr(tftpaddr)成功启动 Uboot> tftp 20f00000 uImage-nzip-8000;tftp 21100000 ramdisk;bootm 20f00000 ## Booting image at 20f00000 ... Image Name: dd-kernel-2.4.19-nzip-8000 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1873059 Bytes = 1.8 MB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK OK Starting kernel ... Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #44 四 10月 11 17:27:24 CST 2007 AT91RM9200DK login: root <2> -a=-e = 0x20008000, tftpaddr= 0x20008000 不搬动,但-e地址不对,失败 <3> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x20008000 不搬动,但未成功启动,入口地址对的啊????? Uboot> tftp 20008000 uImage-nzip-8040;tftp 21100000 ramdisk;bootm 20008000 ## Booting image at 20008000 ... Image Name: dd-kernel-2.4.19-nzip-8040 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 1873059 Bytes = 1.8 MB Load Address: 20008000 Entry Point: 20008040 Verifying Checksum ... OK XIP Kernel Image ... OK Starting kernel ...死了???? <4> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x21000000 搬动,但-e地址不对,失败 4.5.2 压缩的zImage内核 (1)Mkimage 之前用gzip对zImage进行压缩,即-c gzip <1> -a=-e = 0x20008000,tftpaddr= 0x21000000 解压到-a指定的地址,成功启动 Uboot> tftp 21000000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 21000000 TFTP from server 192.168.0.12; our IP address is 192.168.0.15 Filename 'uImage-zip-zImage-8000'. Load address: 0x21000000 ## Booting image at 21000000 ... Image Name: dd-zip-zImage-8000 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 876753 Bytes = 856.2 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK Uncompressing Kernel Image ... OK // U-boot对内核解压 Starting kernel ... Uncompressing Linux..............压缩内核zImage自解压......................... done, booting the kernel. Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43 四 10月 AT91RM9200DK login: root [root@AT91RM9200DK /root]$ls <2> -a=-e = 0x20008000, tftpaddr= 0x20008000 解压失败,启动失败 Uboot> tftp 20008000 uImage-zip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000 TFTP from server 192.168.0.12; our IP address is 192.168.0.15 Filename 'uImage-zip-zImage-8000'. Load address: 0x20008000 ## Booting image at 20008000 ... Image Name: dd-zip-zImage-8000 Image Type: ARM Linux Kernel Image (gzip compressed) Data Size: 876753 Bytes = 856.2 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK Uncompressing Kernel Image ... Error: inflate() returned -3 GUNZIP ERROR - must RESET board to recover 由于当前运行地址tftpaddr与解压缩后的地址-a重合了,导致解压缩失败,因此二者必须相隔一定的距离 <3> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x21000000,失败 Uboot> tftp 21000000 uImage-zip-zImage-8040;tftp 21000000 ramdisk;bootm 21000000 TFTP from server 192.168.0.12; our IP address is 192.168.0.15 Filename 'uImage-zip-zImage-8040'. Load address: 0x21000000 。。。。。。。。。 ## Booting image at 21000000 ... Bad Magic Number 难道对于压缩内核,幻数对的条件是-a==-e地址??即压缩内核默认-a==-e?? 此法肯定失败,但问题出在这,还真不对啊,不试了,感兴趣的朋友可以玩下 (2)Mkimage 之前未对zImage进行压缩,即-c none <1> -a=-e = 0x20008000 tftpaddr= 0x21000000 搬动到-a指定的地址,成功启动 Uboot> tftp 21000000 uImage-nzip-zImage-8000;tftp 21100000 ramdisk;bootm 21000000 ## Booting image at 21000000 ... Image Name: dd-nzip-zImage-8000 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 881748 Bytes = 861.1 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK OK Starting kernel ... Uncompressing Linux............................................................. done, booting the kernel. Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43 四 10月 11 14:25:14 CST 2007 AT91RM9200DK login: <2> -a=-e = 0x20008000, tftpaddr= 0x20008000 不搬动,但-e地址不对,失败 Uboot> tftp 20008000 uImage-nzip-zImage-8000;tftp 21100000 ramdisk;bootm 20008000 ## Booting image at 20008000 ... Image Name: dd-nzip-zImage-8000 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 881748 Bytes = 861.1 kB Load Address: 20008000 Entry Point: 20008000 Verifying Checksum ... OK XIP Kernel Image ... OK Starting kernel ... 死了。。。 <3> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x20008000 不搬动,成功启动 Uboot> tftp 20008000 uImage-nzip-zImage-8040;tftp 21100000 ramdisk;bootm 20008000 ## Booting image at 20008000 ... Image Name: dd-nzip-zImage-8040 Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 881748 Bytes = 861.1 kB Load Address: 20008000 Entry Point: 20008040 Verifying Checksum ... OK XIP Kernel Image ... OK Starting kernel ... Uncompressing Linux............................................................. done, booting the kernel. Linux version 2.4.19-rmk7 (root@dding) (gcc version 2.95.3 20010315 (release)) #43 四 10月 11 14:25:14 CST 2007 AT91RM9200DK login: <4> -a=0x20008000,-e = 0x20008040 ,tftpaddr= 0x21000000 搬动,但-e地址不对,失败 4.5.3 关于压缩及非压缩内核bootm启动的全面总结 由上面的16个例子,我们可以看出,能够启动内核的由以下几种情况: 各种情况对应的统一ramdiskaddr= 0x21100000 <1>非压缩的Image内核: -a=-e = 0x20008000 ,–c=none,tftpaddr= 0x20f00000 此法主要由于内核太大,导致tftpaddr做了一定的修正 -a= 0x20008000 ,-e = 0x20008040,–c=none,tftpaddr=0x20008000 此法理论上可行,但我未试验成功,有兴趣的朋友可以探究下 对于非压缩的Image内核,mkimage之前不压缩的话,内核印象较大,此法不常用 -a=-e = 0x20008000 ,–c=gzip,tftpaddr= 0x21000000 –c=gzip压缩内核必须解压,只有这种情况成功;其他解压覆盖或者-e入口不对 <2>压缩的zImage内核: -a=-e = 0x20008000 ,–c=none,tftpaddr= 0x21000000 -a= 0x20008000 ,-e = 0x20008040,–c=none,tftpaddr=0x20008000 -a=-e = 0x20008000 ,–c=gzip,tftpaddr= 0x21000000 –c=gzip压缩内核必须解压,只有这种情况成功;其他解压覆盖或者-e入口不对 zImage已经压缩过一次了,一般无需再压缩,此法不常用 常见方法: <1>非压缩的Image内核: -a=-e = 0x20008000 ,–c=gzip,tftpaddr= 0x21000000 <2>压缩的zImage内核: -a=-e = 0x20008000 ,–c=none,tftpaddr= 0x21000000 -a= 0x20008000 ,-e = 0x20008040,–c=none,tftpaddr=0x20008000 待续: U-boot如何向Linux内核传递命令行参数? Go引导内核的详细方法? #生成uImage 的mkImage 命令行,其中需要关注的就是-a 与 -e 参数。 Ramdisk与initrd怎么传给内核? U-boot如何引导Linux内核启动?
命令引导未用mkimage生成的内核
4.2 Mkimage参数意义解析
-O linux -------- 操作系统是linux
-T kernel -------- 类型是kernel
-C none/bzip/gzip -------- 压缩类型
-a 20008000 ---- image的载入地址(hex),通常为0xX00008000
-e 200080XX---- 内核的入口地址(hex),XX为0x40或者0x00
-n linux-XXX --- image的名字,任意
-d nameXXX ---- 无头信息的image文件名,你的源内核文件
uImageXXX ---- 加了头信息之后的image文件名,任意取的流程分析
如何用mkimage生成uImage
命令引导mkimage生成的内核全程解析
#参数-a:指明uImage 加载的SDRAM 地址,内核默认指定加载地址为0x30008000 。
# u-boot 引导时,bootm 命令跳到与上相同位置执行,检查完镜像头后,它会跳到内核真正的入口点开
始执 。
#参数-e:指明uImage 中刨去镜像头后真正的内核入口地址。
# 镜像头为0x40 长,故此处指定为0x30008040 。
# u-boot 引导时,go 命令可以直接指定此位置。go 命令不检查镜像头。
quiet_cmd_uimage = UIMAGE $@
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
-C none -a $(ZRELADDR) -e 0x30008040 \
-n 'Linux-$(KERNELRELEASE)' -d $< $@