2024年3月24日发(作者:王典)
uboot
一、uboot是ppcboot和armboot合并而成,现在主流的bootloader为uboot和redboot
二、bootm addr_kernel addr_initrd
三、移植uboot时最好(一定)要找到一个自己板子的原形(即自己的板子是在这个板子上做一些修改而来
的)的版本,这样就可以事半功倍。这样要修改的地方就比较少,也比较容易了。uboot支持很多平台,
与一个具体平台相关的主要有三个地方:
1、./include/configs/xxxxx.h, 主要定义了flash、sdram的起始地址等信息,一般要修改flash的起始
地址、大小,有时候会有位宽等。
2、./board/xxxxx/*, 这个目录下主要有两三个.c文件,主要为该平台的初始化和flash操作的函数。
有时候flash的操作需要修改,不过一般都是找一个现有的支持该flash的驱动,一般情况在uboot
别的./board/平台下就会有现成的,拷贝过了就可以了。
3、./cpu/xxxxxx/arch_xxx/xxxxxx/*, 一般是此cpu的初始等函数。
四、具体移植的时候最多涉及到的会是./include/configs/xxxx.h,如果有现成的平台(uboot现在支持绝大部分
我们常用的平台),可能只需要对着原来的xxxx.h文件,修改几个我们在硬件上修改了的地方,一般会是
flash的起始地址、大小;内存大小(内存的起始地址应该都是0);uboot设置信息保存的地址和长度;console
口和它的波特率;默认的设置;uboot的入口地址等(具体情况可能会有一些变化),如果不是从相同的
平台移植,可能会比较麻烦,因为这时候要修改一些和此cpu相关的一些寄存器、频率和内存等硬件方
面的东西了(也在这个xxxx.h中),虽然这时改动的地方也不多,但是会很痛苦,因为经常不知道要改哪
里或者改为多少。所以可能需要参考cpu的datasheet和到网上找一些资料了并且慢慢试了。
五、另一个常需要修改的地方是flash的驱动,一般会在./board/xxxx/flash.c文件中。这个可以从uboot的别
的./board/目录中拷贝一个支持该flash的驱动过来。
六、在编译uboot前需要配置,这个配置不是执行./configure,也不是make menuconfig。而是先make clobber(清
掉以前的配置),再make xxxxx_config。其中xxxxx_config是在Makefile中有定义的目标。如 make
at91sam9260ek_config,在Makefile中一个这样的目标实际上是执行一条这样的命令:./mkconfig
$(@:_config=) arch cpu xxxx xxx,具体举个例子:
at91sam9260ek_config: unconfig
@./mkconfig $(@:_config=) arm arm926ejs at91sam9260ek null at91sam9260
前面几个参数分别对应arch,cpu,board,这样在编译时它们分别进入下面的目录和文件:
cpu/arm926ejs/, board/at91sam9260ek/和 include/configs/at91sam9260ek.h。这样就可以在Makefile中添
加一个目标编译自己的平台也可以通过查看makefile很容易的知道怎么配置相应的平台。
在make时有时候会提示make examples时出错,这样需要手动在Makefile中去掉编译examples。
另外在编译kernel时提示找不到mkimage这个命令,这个命令是在uboot的tools中,所以需要将这个文
件拷贝到系统路径中,比如/sbin/中。
七、uboot启动系统的过程,在uboot的硬件初始化完成后,就会死循环一直都调用main_loop()函数,这个调
用在相应的cpu平台下的xxx_lib目录下的board.c中(如arm_lib/board.c),而main_loop()函数在common
目录的main.c中,main_loop()实际上一直在检测console的输入,如果到bootdelay减为0时还没有输入,
就会调用环境变量bootcmd后的命令,bootcmd一般为bootm [xxx] [xxx],这样就自动调用bootm来启动
系统了,如果console有输入,这样也可以通过手动输入bootm [xxx] [xxx]来启动系统。这里面最重要的
一个命令就是bootm,函数do_bootm()就是这个命令的具体实现(命令和函数是通过宏U_BOOT_CMD
关联起来的)。函数do_bootm()在common/cmd_bootm.c中,bootm实际上是最少需要一个参数的即系统
img文件在flash中的地方(如bootm fe020000),如果没有参数就用系统默认的值(CFG_LOAD_ADDR)。
do_bootm()做下面几件事:
1> 检测系统img的前0x40字节(即结构image_header_t)来确定img的是否合法和一些信息,如img
的长度、load到内存的地址、类型、压缩方式。
2> 将flash中的系统img的整个内容(除掉0x40byte的头部)通过gunzip()或者是直接拷贝到内存中load
地址。其中img的长度和在内存中的地址均在image_header_t中有指出。如果img没有压缩则是直接拷
贝否则通过gunzip解压。
3> 调用相应的do_bootm_OS,我们这里是do_bootm_linux(),在do_bootm_linux中所作的事情:
a. 将cmd_line放在内存的尽量高的地址空间。
b. 将板子的信息参数放在接着的内存中,以便kernel利用。
c. 如果bootm有两个参数(如bootm fe020000 fe160000),则检测flash中的以第二个参数开始地址
是否是一个合法的ramdisk img,如果是就将它拷贝到紧接着板子信息的内存空间,并记下它的开
始和结束地址到initrd_start和initrd_end,再判断系统img的ARCH是否为ppc,如果不是就认为
错误,reset系统。
d. 如果bootm只有一个参数(非ppc平台常用的命令),则判断系统img是否为一个multifile img, 如果
是就拷贝相应的img作为ramdisk并记下initrd_start和initrd_end,如果不是multifile img而只是
kernel img则表示没有initrd,这样initrd_start和initrd_end的值都设为0。
e. 将系统img的入口地址(Entry Point)作为一个函数指针, 调用此函数执行kernel的内容,其中以板子
参数信息地址、initrd_start、initrd_end、cmd_start、cmd_end做为函数的参数,这样他们就分别通
过寄存器r3、r4、r5、r6、r7传递到kernel了,这样uboot的任务就完成了。(*kernel) (kbd, initrd_start,
initrd_end, cmd_start, cmd_end);
f. 这里有一个问题就是非ppc平台的initrd问题,ppc的initrd可以单独做一个img放在flash中,通
过bootm的第二个参数指定。而对于类似于arm的平台,可以通过将系统img做成一个multifile
的img放在flash中,而这个img包括kernel和initrd,也可以将initrd放在kernel后面作为kernel
的一部分,将kernel img放在flash中了,而对于uboot来说是不需要拷贝(没有)initrd的。这样
initrd放在kernel什么地方需要在编译连接生成kernel时在ld脚本或Makefile中指定,以便kernel
起来后可以找到initrd,通过make bootpImage就可以生成包括initrd的kernel文件。实际上这个
动作是通过arch/arm/boot/bootp/下的几个文件完成的,initrd.S, kernel.S, init.S, Makefile, ,
需要指出的只有INITRD和INITRD_PHYS,INITRD指向我们自己的initrd文件,INITRD_PHYS
可能是用来告诉kernel initrd在内存的什么地方,一般平台发布时就在
arch/arm/mach-xxx/中指定了,一般不要修改或者是参考它来修改,如
arch/arm/mach-at91sam9260/,它是被include到arch/arm/boot/Makefile中的
八、 uboot在s3c2410上的移植,2410支持从nandflash启动,由于nandflash的位宽位8位或16位,
所以是不能直接启动的,要能够启动一定要cpu的特殊支持,我的理解是这样的,2410里面有一
个4k的ram,在上电复位时cpu将nandflash的前4k拷贝到cpu的ram中,然后在ram中执行,
这4k的代码包括读取flash的代码到外部的sdram,然后跳到sdram中去执行,这样系统就引导起
来了。而将uboot移植到s3c2410在启动方面可以选择从nandflash启动,这样就需要移植nandflash
的读写函数,以及修改一下start.S的内容。当然,如果要从norflash启动就没有这么麻烦了,应
该只需要修改一下include/configs/中对应的头文件就可以了。另外,在linux2.6中将cfi接口编译
进去就可以支持norflash了,而nandflash的支持需要另外加nandflash的读写驱动。
九、 uboot默认会将放置env的扇区(块)保护起来,这样就不能擦、写了,需要用protect off来去掉
保护,同样想保护某些flash地址可以用protect on,或者在uboot程序中调用flash_protect()来保护。其具
体的用法为:protect on|off start_addr end_addr如 prtect off d0008000 d0037fff,start_addr好像一定要是某
个扇区的起始,end_addr一定要是某个扇区的结尾地址。
还有一种用法:protect on|off n:s-e,如protect on 1:0-3,表示保护第一块flash的0-3个扇区。
十、uboot启动linux,如果在ppc中,可以直接在bootm后跟kernel和initrd在flash中的地址,而如果
kernel和initrd不在norflash中(即不能直接运行),直接用bootm就不行了,需要将其拷贝到sdram中
再用bootm后跟kernel在sdram中的地址了,又如bootm后只带一个参数,那么initrd就只能放在bootargs
中了,这时也需要先将initrd拷贝到sdram中了,所以一般可以将启动命令设为几个命令一起而不仅仅是
2024年3月24日发(作者:王典)
uboot
一、uboot是ppcboot和armboot合并而成,现在主流的bootloader为uboot和redboot
二、bootm addr_kernel addr_initrd
三、移植uboot时最好(一定)要找到一个自己板子的原形(即自己的板子是在这个板子上做一些修改而来
的)的版本,这样就可以事半功倍。这样要修改的地方就比较少,也比较容易了。uboot支持很多平台,
与一个具体平台相关的主要有三个地方:
1、./include/configs/xxxxx.h, 主要定义了flash、sdram的起始地址等信息,一般要修改flash的起始
地址、大小,有时候会有位宽等。
2、./board/xxxxx/*, 这个目录下主要有两三个.c文件,主要为该平台的初始化和flash操作的函数。
有时候flash的操作需要修改,不过一般都是找一个现有的支持该flash的驱动,一般情况在uboot
别的./board/平台下就会有现成的,拷贝过了就可以了。
3、./cpu/xxxxxx/arch_xxx/xxxxxx/*, 一般是此cpu的初始等函数。
四、具体移植的时候最多涉及到的会是./include/configs/xxxx.h,如果有现成的平台(uboot现在支持绝大部分
我们常用的平台),可能只需要对着原来的xxxx.h文件,修改几个我们在硬件上修改了的地方,一般会是
flash的起始地址、大小;内存大小(内存的起始地址应该都是0);uboot设置信息保存的地址和长度;console
口和它的波特率;默认的设置;uboot的入口地址等(具体情况可能会有一些变化),如果不是从相同的
平台移植,可能会比较麻烦,因为这时候要修改一些和此cpu相关的一些寄存器、频率和内存等硬件方
面的东西了(也在这个xxxx.h中),虽然这时改动的地方也不多,但是会很痛苦,因为经常不知道要改哪
里或者改为多少。所以可能需要参考cpu的datasheet和到网上找一些资料了并且慢慢试了。
五、另一个常需要修改的地方是flash的驱动,一般会在./board/xxxx/flash.c文件中。这个可以从uboot的别
的./board/目录中拷贝一个支持该flash的驱动过来。
六、在编译uboot前需要配置,这个配置不是执行./configure,也不是make menuconfig。而是先make clobber(清
掉以前的配置),再make xxxxx_config。其中xxxxx_config是在Makefile中有定义的目标。如 make
at91sam9260ek_config,在Makefile中一个这样的目标实际上是执行一条这样的命令:./mkconfig
$(@:_config=) arch cpu xxxx xxx,具体举个例子:
at91sam9260ek_config: unconfig
@./mkconfig $(@:_config=) arm arm926ejs at91sam9260ek null at91sam9260
前面几个参数分别对应arch,cpu,board,这样在编译时它们分别进入下面的目录和文件:
cpu/arm926ejs/, board/at91sam9260ek/和 include/configs/at91sam9260ek.h。这样就可以在Makefile中添
加一个目标编译自己的平台也可以通过查看makefile很容易的知道怎么配置相应的平台。
在make时有时候会提示make examples时出错,这样需要手动在Makefile中去掉编译examples。
另外在编译kernel时提示找不到mkimage这个命令,这个命令是在uboot的tools中,所以需要将这个文
件拷贝到系统路径中,比如/sbin/中。
七、uboot启动系统的过程,在uboot的硬件初始化完成后,就会死循环一直都调用main_loop()函数,这个调
用在相应的cpu平台下的xxx_lib目录下的board.c中(如arm_lib/board.c),而main_loop()函数在common
目录的main.c中,main_loop()实际上一直在检测console的输入,如果到bootdelay减为0时还没有输入,
就会调用环境变量bootcmd后的命令,bootcmd一般为bootm [xxx] [xxx],这样就自动调用bootm来启动
系统了,如果console有输入,这样也可以通过手动输入bootm [xxx] [xxx]来启动系统。这里面最重要的
一个命令就是bootm,函数do_bootm()就是这个命令的具体实现(命令和函数是通过宏U_BOOT_CMD
关联起来的)。函数do_bootm()在common/cmd_bootm.c中,bootm实际上是最少需要一个参数的即系统
img文件在flash中的地方(如bootm fe020000),如果没有参数就用系统默认的值(CFG_LOAD_ADDR)。
do_bootm()做下面几件事:
1> 检测系统img的前0x40字节(即结构image_header_t)来确定img的是否合法和一些信息,如img
的长度、load到内存的地址、类型、压缩方式。
2> 将flash中的系统img的整个内容(除掉0x40byte的头部)通过gunzip()或者是直接拷贝到内存中load
地址。其中img的长度和在内存中的地址均在image_header_t中有指出。如果img没有压缩则是直接拷
贝否则通过gunzip解压。
3> 调用相应的do_bootm_OS,我们这里是do_bootm_linux(),在do_bootm_linux中所作的事情:
a. 将cmd_line放在内存的尽量高的地址空间。
b. 将板子的信息参数放在接着的内存中,以便kernel利用。
c. 如果bootm有两个参数(如bootm fe020000 fe160000),则检测flash中的以第二个参数开始地址
是否是一个合法的ramdisk img,如果是就将它拷贝到紧接着板子信息的内存空间,并记下它的开
始和结束地址到initrd_start和initrd_end,再判断系统img的ARCH是否为ppc,如果不是就认为
错误,reset系统。
d. 如果bootm只有一个参数(非ppc平台常用的命令),则判断系统img是否为一个multifile img, 如果
是就拷贝相应的img作为ramdisk并记下initrd_start和initrd_end,如果不是multifile img而只是
kernel img则表示没有initrd,这样initrd_start和initrd_end的值都设为0。
e. 将系统img的入口地址(Entry Point)作为一个函数指针, 调用此函数执行kernel的内容,其中以板子
参数信息地址、initrd_start、initrd_end、cmd_start、cmd_end做为函数的参数,这样他们就分别通
过寄存器r3、r4、r5、r6、r7传递到kernel了,这样uboot的任务就完成了。(*kernel) (kbd, initrd_start,
initrd_end, cmd_start, cmd_end);
f. 这里有一个问题就是非ppc平台的initrd问题,ppc的initrd可以单独做一个img放在flash中,通
过bootm的第二个参数指定。而对于类似于arm的平台,可以通过将系统img做成一个multifile
的img放在flash中,而这个img包括kernel和initrd,也可以将initrd放在kernel后面作为kernel
的一部分,将kernel img放在flash中了,而对于uboot来说是不需要拷贝(没有)initrd的。这样
initrd放在kernel什么地方需要在编译连接生成kernel时在ld脚本或Makefile中指定,以便kernel
起来后可以找到initrd,通过make bootpImage就可以生成包括initrd的kernel文件。实际上这个
动作是通过arch/arm/boot/bootp/下的几个文件完成的,initrd.S, kernel.S, init.S, Makefile, ,
需要指出的只有INITRD和INITRD_PHYS,INITRD指向我们自己的initrd文件,INITRD_PHYS
可能是用来告诉kernel initrd在内存的什么地方,一般平台发布时就在
arch/arm/mach-xxx/中指定了,一般不要修改或者是参考它来修改,如
arch/arm/mach-at91sam9260/,它是被include到arch/arm/boot/Makefile中的
八、 uboot在s3c2410上的移植,2410支持从nandflash启动,由于nandflash的位宽位8位或16位,
所以是不能直接启动的,要能够启动一定要cpu的特殊支持,我的理解是这样的,2410里面有一
个4k的ram,在上电复位时cpu将nandflash的前4k拷贝到cpu的ram中,然后在ram中执行,
这4k的代码包括读取flash的代码到外部的sdram,然后跳到sdram中去执行,这样系统就引导起
来了。而将uboot移植到s3c2410在启动方面可以选择从nandflash启动,这样就需要移植nandflash
的读写函数,以及修改一下start.S的内容。当然,如果要从norflash启动就没有这么麻烦了,应
该只需要修改一下include/configs/中对应的头文件就可以了。另外,在linux2.6中将cfi接口编译
进去就可以支持norflash了,而nandflash的支持需要另外加nandflash的读写驱动。
九、 uboot默认会将放置env的扇区(块)保护起来,这样就不能擦、写了,需要用protect off来去掉
保护,同样想保护某些flash地址可以用protect on,或者在uboot程序中调用flash_protect()来保护。其具
体的用法为:protect on|off start_addr end_addr如 prtect off d0008000 d0037fff,start_addr好像一定要是某
个扇区的起始,end_addr一定要是某个扇区的结尾地址。
还有一种用法:protect on|off n:s-e,如protect on 1:0-3,表示保护第一块flash的0-3个扇区。
十、uboot启动linux,如果在ppc中,可以直接在bootm后跟kernel和initrd在flash中的地址,而如果
kernel和initrd不在norflash中(即不能直接运行),直接用bootm就不行了,需要将其拷贝到sdram中
再用bootm后跟kernel在sdram中的地址了,又如bootm后只带一个参数,那么initrd就只能放在bootargs
中了,这时也需要先将initrd拷贝到sdram中了,所以一般可以将启动命令设为几个命令一起而不仅仅是