您好,欢迎访问三七文档
当前位置:首页 > 临时分类 > mips的uboot移植与分析
mips的uboot移植与分析=96要注意mips具有流水线可见性,所以跟在跳转指令后的下一条指令,在执行跳转到的地方前,都会执行,这个叫分支延迟。但是编译器会隐藏该特性,但可以通过设置”.setnoreorder”来禁止编译器重新组织代码顺序。每个板子都有自己的lds文件。这个主要是用来说明编译生成的指令,及运行过程中用到的数据放置的位置。这个可以参考ld的手册。比如board/dbau1×00/u-boot.lds。OUTPUT_FORMAT(“elf32-tradbigmips”,“elf32-tradbigmips”,“elf32-tradbigmips”)/*这里是生成格式为elf。大端,mips*/OUTPUT_ARCH(mips)/*平台为mips*/ENTRY(_start)/*入口点为_start*/SECTIONS{.=0×00000000;.=ALIGN(4);.text:/*这个是程序存放的地方*/{*(.text)}.=ALIGN(4);/*表示以4字节对齐*/.rodata:{*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))}.=ALIGN(4);.data:{*(.data)}.=.;_gp=ALIGN(16)+0×7ff0;.got:{__got_start=.;/*表示该处地址的值给__got_start*/*(.got)__got_end=.;}.sdata:{*(.sdata)}.u_boot_cmd:{__u_boot_cmd_start=.;*(.u_boot_cmd)__u_boot_cmd_end=.;}uboot_end_data=.;num_got_entries=(__got_end–__got_start)2;.=ALIGN(4);.sbss(NOLOAD):{*(.sbss)}.bss(NOLOAD):{*(.bss).=ALIGN(4);}uboot_end=.;}下面来分析cpu/mips/start.S首先从_start开始。前面是128个字(不是字节),是留给异常入口点的。1.最前面两个分别是硬复位和软复位,这两个都跳到reset处。2.下面就是清一些CP0(协处理器0,mips对CPU的控制都是通过它实现的)的一些主要位。3.然后是关闭cache4.下面这个比较有意思。为什么还非要跳一下呢?这样就可以知道代码的位置,而不是标号值。比如可能在RAM中或ROM中。bal1fnop.word_gp1:lwgp,0(ra)5.这里执行lowlevel_init。这是第一个需要我们自己定义的函数。由于没有初始化堆栈,这里只能用汇编。我们看到在jalr后跟了个nop,这就是分支延迟槽了,在这里什么也没有执行。6.下面执行了mips_cache_reset,它会来清理数据和指令的cache,并设置为正确的值。然后就可以打开cache了。7.由于我们的内存可能还没有始初化(有些人会有lowlevel_init中初始化,但有的人没有这样做)。但我们使用C函数的话,就需要堆栈,所以需要一个内存空间。于是这里执行了mips_cache_lock,将cache的地址锁定,就是将cache当内存用了。然后我们将堆栈的地址设定在我们锁定的cache的最高地址(因为堆栈是向下生长的)。这时我们就可以用C函数了,当然你还用不了malloc,也不可以太多的浪费堆栈。8.这里就跑到C的初始化函数中去了--board_init_f。对于mips,board_init_f在lib_mips/board.c下。在board_init_f()函数中,主要完成了一些功能初始化,和划分RAM。/*所以最后RAM中是这样子的—RAM0×0000,0000—…………—^SP^——bootparams—CONFIG_SYS_BOOTPARAMS_LENbd-bi_boot_params—GlobalData—sizeof(gd_t)gd—BoardInfo—sizeof(bd_t)gd-bd=bd—mallco(+env)—CONFIG_SYS_MALLOC_LEN+CONFIG_ENV_SIZE—ubootcode—16kB—RAMend—*/再看一下都初始化了什么功能。初始化的函数都在init_fnc_t*init_sequence[]里。init_fnc_t*init_sequence[]={board_early_init_f,/*一些必要,需在之前做的初始化,如想使用需定义CONFIG_BOARD_EARLY_INIT_F*/timer_init,/*初始化时钟计数,cp0的*/env_init,/*环境变量保存在flash中*/#ifdefCONFIG_INCA_IPincaip_set_cpuclk,/*根据cpuclk环境变量设定CPU主频*/#endifinit_baudrate,/*根据baudrate环境变量设定gd-baudrate*/serial_init,/*设定串口速率,需要我们自己写(包括其它serial的)*/console_init_f,/*设置gd-have_console=1,有CONFIG_SILENT_CONSOLE则查看silent*/display_banner,/*打印uboot信息*/checkboard,/*检测板子,可以在这打印设备信息,需要我们自己写*/init_func_ram,/*设置gd-ram_size,initdram需要我们自己写*/NULL,/*最后这个空必须留着,检查结束*/};最后这个函数调用了relocate_code(addr_sp,id,addr)。注意,这个函数,准确的说不是函数(因为不能返回),是不返回的。现在我们又回到start.S中了。我们可以看到,这里和C语言传递参数是用a0,a1,a2。relocate_code的工作就是将代码搬移到RAM中执行。这里做的工作是:1.移动gp指针2.复制代码到RAM中3.刷新一下cache4.跳到RAM代码当中去(in_ram)in_ram的主要工作是:更新GOT;清空BSS段;最后跳到board_init_r。我们可以看到board_init_r最后一个参数是在分支延迟槽中赋值的。这其实这里主要说一下GOTs(globaloffsettables)这个东东,这是uboot能跳转到不同空间运行的原理。uboot编译时用到了PIC(position-independentcode)(也可以说成position-independentexecutable(PIE))。这个其实是很早之前,在没有MMU的年代引进来的东西。为了在没有MMU时,不同进程也能同时运行,就需要他们的运行地址可以改变。GOTs用来保存所有的全局变量地址,所以我们只要改变GOTs的值就可以了。gp就是指向GOTs位置的指针。这个功能需要在gcc编译时指定-fpic。然后就像我们看到的,我们只要改变GOTs里的值,加上地址偏移就可以了。下面再看一下board_init_r。这里的工作:1.复制cmd段的信息过来。这里只复制了cmd,name,usage,usage。帮助信息的字符串还在flash中。2.然后是初始化malloc功能。注意这里env有malloc的方式分配到了空间,并复制到RAM。3.再就是stdio,串口,入口函数,以及全局变最根据env的初始化了。4.再接着就是网络的初始化。eth_initialize(gd-bd)。对于mips,如果设了CONFIG_NET_MULTI。我们需要自己写board_eth_init和cpu_eth_init两个函数。只有前者返回值小于0时,我们才需要执行后者。5.最后进入main_loop()。以太网驱动移植对于mips,如果设了CONFIG_NET_MULTI。会用到board_eth_init()和cpu_eth_init()两个函数。只有前者返回值小于0时,才会执行后者。这里要初始化结构体eth_device,然后使用eth_register()注册网络设备。主要要设定init,halt,send,recv四个函数,及其它一些变量。如支持mii读写命令还需使用miiphy_register()注册mii读写的两个函数。当注册完成后,U-Boot不会自动调用init,而是只有当用到网络设备时,才后调用。每次使用网络接口时,是先调用halt之后,才调用init。当我们使用命令make(型号)_config时,会产生以下效果。(1)将include/asm软链接到include/asm-(ARCH)。(2)修改include/config.h文件,增加#include和#include。(3)在include/config.mk设置变量ARCH,CPU,BOARD,VENDOR。编译时,Makefile会包含进几个目录的config.mk文件。board/xxx/(xxx/)config.mk在前面已经介绍过了。在lib_xxx/config.mk中会指定交叉编译器,及增加平台相关的编译参数。在cpu/xxx/config.mk会指定体系结构的相关参数,如大小端。
本文标题:mips的uboot移植与分析
链接地址:https://www.777doc.com/doc-7845781 .html