移植UBOOT总览

文章目录

移植UBOOT总览

uboot启动流程如下:
1)设置CPU为管理模式
2)关看门狗
3)关中断
4)设置时钟频率
5)关mmu,初始化各个bank
6)进入board_init_f()函数 (初始化定时器,GPIO,串口等,划分内存区域)
7)重定位,复制uboot,然后修改SDRAM上的uboot链接地址
8)清bss
9)跳转到board_init_r()函数,启动流程结束

1、编译烧写u-boot

移植环境

主 机:VMWare–ubuntu16.04
开发板:S3C2440
编译器:arm-linux-gcc-4.3.2.tgz
u-boot:u-boot-2012.04.01.tar.bz2

获取u-boot

从uboot官网下载u-boot-2012.04.01.tar.bz2源码。
在这里插入图片描述

创建si工程

添加源代码吗,先全部添加,再逐个选择:
删除board目录:
添加:\u-boot-2012.04.01\board\samsung\smdk2410

删除arch目录:
添加:\u-boot-2012_project\u-boot-2012.04.01\arch\arm\cpu\arm920t\cpu.c、Makefile、interrupts.c
添加:\u-boot-2012_project\u-boot-2012.04.01\arch\arm\cpu\arm920t\s3c24x0\
添加:\u-boot-2012_project\u-boot-2012.04.01\arch\arm\include\asm\arch-s3c24x0\
添加:\u-boot-2012.04.01\arch\arm\include\asm\只添加顶层目录,去掉勾
添加:\u-boot-2012_project\u-boot-2012.04.01\arch\arm\proc-armv
添加:\u-boot-2012.04.01\arch\arm\lib\

删除include目录:
添加:\u-boot-2012.04.01\include\顶层目录,去掉勾
添加:\u-boot-2012.04.01\include\其中去除config,其他全部加
添加:\u-boot-2012.04.01\include\configs\smdk2410.h

安装arm-linux-gcc-4.3.2交叉编译器

解压

cd /work/tools/
mkdir tmp
tar xjf arm-linux-gcc-4.3.2.tar.bz2 -C tmp/

解压完成,进入tmp目录查看usr/local/arm/4.3.2/bin文件夹,有各种工具链。

cd tmp/usr/local/arm/4.3.2/bin
ls

在这里插入图片描述
将新的工具链解压到根目录并配置环境变量,新的交叉编译工具链就生效了。

cd /work/tools/
sudo tar xjf arm-linux-gcc-4.3.2.tar.bz2  -C /	

为什么要设置环境变量?
因为我们执行ls 命令时,系统会去寻找所执行的命令,去哪里找呢?就在环境变量中。在ubuntu查看环境变量如下
在这里插入图片描述设置新的环境变量

export PATH=/usr/local/arm/4.3.2/bin:.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games

执行

arm-linux-gcc -v

在这里插入图片描述
永久修改环境变量需要修改/etc/environment

sudo vi /etc/environment

修改前

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/work/tools/gcc-3.4.5-glibc-2.3.6/bin"

修改后

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/arm/4.3.2/bin"

重启后即可生效。
再次编译新的uboot

cd /work/sysytem/u-boot-2012.04.01
make distclean
make smdk2410_config
make

编译烧写

将压缩文件添加到ubuntu服务器上去。

tar xjf u-boot-2012.04.01.tar.bz2 u-boot-2012.04.01/
cd u-boot-2012.04.01
make distclean
make smdk2410_config
make

将u-boot.bin文件拷贝会PC机上。
烧写进2440开发板,开发板设置为nor启动:oflash 0 1 1 0 0 .\u-boot.bin
发现没有任何反应,表示这款uboot不支持2440,需要分析代码并修改。

2、分析启动过程之概述

之前分析uboot启动时需要完成下列步骤

1、初始化硬件:关看门狗、设置时钟、设置SDRAM、nand flash
2、如果booloader比较大,把它重定位到SDRAM、清除bss段
3、把内核从nand flash 读到sdram
4、设置要传给内核的参数
5、跳转执行内核

最新的uboot启动过程也应该和上面类似

分析得到最新的uboot 2012.04.1启动过程大概为

1 set the cpu to SVC32 mode
2 turn off the watchdog
3 mask all IRQs by setting all bits in the INTMR
4 设置时钟比例
5 设置内存控制器
6 设置栈,调用C函数board_init_f
7 调用函数数组init_sequence里的各个函数
	7.1 board_early_init_f : 设置系统时钟、设置GPIO 。。。。。。
8 重定位代码:
	8.1 从NOR FLASH把代码复制到SDRAM
	8.2 程序的链接地址是0,访问全局变量、静态变量、调用函数时是使"基于0地址编译得到的地址"
		现在把程序复制到了SDRAM
      	需要修改代码,把"基于0地址编译得到的地址"改为新地址
	8.3程序里有些地址在链接时不能确定,要到运行前才能确定:fixabs
9 clear_bss	
10 调用C函数board_init_r:执行第2阶段的代码

具体分析

我们来分析这个uboot-2012可以一步一步分析Makefile,也可以从启动过程时打印的参数来分析,
先删除uboot:rm u-boot
再来重新编译:make
得到如下信息:
arm-linux-ld
-pie
-T u-boot.lds -Bstatic -Ttext
0x0 $UNDEF_SYM arch/arm/cpu/arm920t/start.o --start-group api/libapi.o arch/arm/cpu/arm920t/libarm920t.o
.。。。。。。
。。。。。。
arm-linux-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

链接时加上 -pie 选项就会生成一个位置无关可执行程序:
在这里插入图片描述
我们之前说的重定位是:
从nor启动直接从nor的0地址运行;
从nand启动,前4k被硬件复制到内存SRAM中,再从内存SRAM的0地址运行将nand上的代码全部复制到SDRAM当中去,之后再去SDRAM中运行程序。
在这里插入图片描述
新的uboot是从nor启动的,所以它的链接地址为0。但是在程序中要修改某个全局变量时,在nor中则不能修改,所以nor启动也要重定位某些代码,把这些要修改的值复制到SDRAM当中,再把之前存在nor上的旧地址改为SDRAM当中的新地址。
在这里插入图片描述
在这里插入图片描述
问:那么怎样知道那些旧地址存在哪里?
答:需要在链接时加上-pie选项,链接之后那些旧地址就会存在特定的段当中,这些段在连接脚本中定义。
在这里插入图片描述
这样我们就可以根据存在这些段当中的信息,把旧地址改为新地址,程序就可以复制到任何地址上去。

1、首先查看arch/arm/cpu/u-boot.lds链接脚本

2、如下图所示,看到uboot最开始会进入_start

在这里插入图片描述

3、_start位于arch/arm/cpu/arm920t/start.S

所以,我们从start.S开始分析uboot启动流程:

.globl _start                                //声明_start全局符号,这个符号会被lds链接脚本用到
_start:    
b     start_code                            //跳转到start_code符号处,0x00
       ldr   pc, _undefined_instruction                    //0x04
       ldr   pc, _software_interrupt                       //0x08
       ldr   pc, _prefetch_abort                           //0x0c
       ldr   pc, _data_abort                               //0x10
       ldr   pc, _not_used                                 //0x14
       ldr   pc, _irq                                      //0x18
       ldr   pc, _fiq                                      //0x20

_undefined_instruction:  .word undefined_instruction
           //定义_undefined_instruction指向undefined_instruction(32位地址)

_software_interrupt:      .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:          .word data_abort
_not_used:             .word not_used
_irq:               .word irq
_fiq:               .word fiq
其中符号保存的地址都在顶层目录/system.map中列出来了

4、从上面看到, _start会跳转到start_code处

start_code:

    /*设置CPSR寄存器,让CPU进入管理模式*/
       mrs  r0, cpsr                 //读出cpsr的值
       bic   r0, r0, #0x1f           //清位
       orr   r0, r0, #0xd3          //位或
       msr  cpsr, r0                 //写入cpsr

#if   defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)
       /*
        * relocate exception table
        */
       ldr   r0, =_start            
       ldr   r1, =0x0                //r1等于异常向量基地址
       mov r2, #16
copyex:
       subs       r2, r2, #1           //减16次,s表示每次减都要更新条件标志位
       ldr   r3, [r0], #4       
       str   r3, [r1], #4      //将_start标号后的16个符号存到异常向量基地址0x0~0x3c处
       bne  copyex             //直到r2减为0
#endif
#ifdef CONFIG_S3C24X0
       /* 关看门狗*/
#  define pWTCON       0x53000000
#  define INTMSK 0x4A000008    /* Interrupt-Controller base addresses */
#  define INTSUBMSK  0x4A00001C
#  define CLKDIVN       0x4C000014    /* clock divisor register */
       ldr   r0, =pWTCON       
       mov r1, #0x0        
       str   r1, [r0]           //关看门狗,使WTCON寄存器=0
       /*关中断*/
       mov r1, #0xffffffff
       ldr   r0, =INTMSK
       str   r1, [r0]                  //关闭所有中断
# if defined(CONFIG_S3C2410)
       ldr   r1, =0x3ff
       ldr   r0, =INTSUBMSK
       str   r1, [r0]                  //关闭次级所有中断
# endif
    /* 设置时钟频率, FCLK:HCLK:PCLK = 1:2:4 ,而FCLK默认为120Mhz*/
       ldr   r0, =CLKDIVN
       mov r1, #3
       str   r1, [r0]
 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
       bl    cpu_init_crit                         //关闭mmu,并初始化各个bank
#endif
call_board_init_f:
       ldr   sp, =(CONFIG_SYS_INIT_SP_ADDR) //CONFIG_SYS_INIT_SP_ADDR=0x30000f80
       bic   sp, sp, #7         //sp=0x30000f80
       ldr   r0,=0x00000000
       bl    board_init_f

上面的CONFIG_SYS_INIT_SP_ADDR =0x30000f80,是通过arm-linux-objdump -D u-boot>u-boot.dis生成反汇编,然后从u-boot.dis得到的,如下图所示:
在这里插入图片描述

3、分析启动过程之内存分布

5、然后进入第一个C函数:board_init_f()

该函数主要工作是:
清空gd指向的结构体、通过init_sequence函数数组,来初始化各个函数以及逐步填充gd结构体,最后划分内存区域,将数据保存在gd里,然后调用relocate_code()对uboot重定位(gd是用来传递给内核的参数)
5.1、具体代码如下所示:

void board_init_f(ulong bootflag) // bootflag=0x00000000
{
       bd_t *bd;
       init_fnc_t **init_fnc_ptr;         //函数指针
       gd_t *id;
       ulong addr, addr_sp;

#ifdef CONFIG_PRAM
       ulong reg;
#endif

       bootstage_mark_name(BOOTSTAGE_ID_START_UBOOT_F, "board_init_f");
       /* Pointer is writable since we allocated a register for it */
       gd = (gd_t *) ((CONFIG_SYS_INIT_SP_ADDR) & ~0x07);

其中gd是一个全局变量,用来传递给内核的参数用的,如下图所示,在arch/arn/include/asm/global_data.h中定义,*gd指向r8寄存器,所以r8专门提供给gd使用
在这里插入图片描述
而CONFIG_SYS_INIT_SP_ADDR,在6节里得到=0x30000f80,所以gd=0x30000f80

5.2、继续来看board_init_f():

__asm__ __volatile__("": : :"memory");           //memory:让cpu重新读取内存的数据

      memset((void *)gd, 0, sizeof(gd_t));        //将0x30000f80地址上的gd_t结构体清0

      gd->mon_len = _bss_end_ofs;  
         // _bss_end_ofs =__bss_end__ - _start,在反汇编找到等于0xae4e0,所以mon_len等于uboot的数据长度
      gd->fdt_blob = (void *)getenv_ulong("fdtcontroladdr", 16, (uintptr_t)gd->fdt_blob);

       for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
            //调用init_sequence[]数组里的各个函数
      {
              if ((*init_fnc_ptr)() != 0)     //执行函数,若函数执行出错,则进入hang()
             {    
           hang ();   //打印错误信息,然后一直while
             }

       }
上面的init_sequence[]数组里存了各个函数,比如有:

    board_early_init_f():设置系统时钟,设置各个GPIO引脚
    timer_init():初始化定时器
    env_init():设置gd的成员变量
    init_baudrate():设置波特率
    dram_init():设置gd->ram_size= 0x04000000(64MB)

5.3、继续来看board_init_f():

addr = CONFIG_SYS_SDRAM_BASE + gd->ram_size;  // addr=0x34000000 
// CONFIG_SYS_SDRAM_BASE:  SDRAM基地址,为0X30000000
// gd->ram_size:          等于0x04000000 

#if !(defined(CONFIG_SYS_ICACHE_OFF) && defined(CONFIG_SYS_DCACHE_OFF))
       /* reserve TLB table */
       addr -= (4096 * 4);        //addr=33FFC000

       addr &= ~(0x10000 - 1);  // addr=33FF0000,   

       gd->tlb_addr = addr;   //将64kB分配给TLB,所以TLB地址为33FF0000~33FFFFFF
#endif

       /* round down to next 4 kB limit */
       addr &= ~(4096 - 1);                    //4kb对齐, addr=33FF0000
       debug("Top of RAM usable for U-Boot at: %08lx\n", addr);

       /*
        * reserve memory for U-Boot code, data & bss
        * round down to next 4 kB limit
        */
       addr -= gd->mon_len; // 在前面分析过gd->mon_len=0xae4e0,
                           //所以addr=33FF0000 -0xae4e0=33F41B20,

       addr &= ~(4096 - 1);  //4095=0xfff,4kb对齐, addr=33F41000
                             //所以分配给uboot各个段的重定位地址为33F41000~33FFFFFF
       debug("Reserving %ldk for U-Boot at: %08lx\n", gd->mon_len >> 10, addr);

#ifndef CONFIG_SPL_BUILD
       addr_sp = addr - TOTAL_MALLOC_LEN; //分配一段malloc空间给addr_sp
                       //TOTAL_MALLOC_LEN=1024*1024*4,所以malloc空间为33BF1000~33F40FFF

       addr_sp -= sizeof (bd_t);            //分配一段bd_t结构体大的空间
    bd = (bd_t *) addr_sp;               //bd指向刚刚分配出来的bd_t结构体
    gd->bd = bd;                         // 0x30000f80处的gd变量的成员bd等于bd_t基地址

    addr_sp -= sizeof (gd_t);              //分配一个gd_t结构体大的空间
    id = (gd_t *) addr_sp;                 //id指向刚刚分配的gd_t结构体
    gd->irq_sp = addr_sp;                 //0x30000f80处的gd变量的成员irq_sp等于gd_t基地址

    addr_sp -= 12;
    addr_sp &= ~0x07;
    ... ...

    relocate_code(addr_sp, id, addr);  //进入relocate_code()函数,重定位代码,以及各个符号
    // addr_sp: 栈顶,该栈顶向上的位置用来存放gd->irq_sp、id 、gd->bd、malloc、uboot、TLB(64kb),
    //id:       存放 gd_t结构体的首地址
    // addr:    等于存放uboot重定位地址33F41000
}

执行完board_init_f()后,最终内存会划分如下图所示:
在这里插入图片描述
其实此时uboot还在flash中运行,然后会进入start.S的relocate_code()里进行uboot重定位

4、分析启动过程之重定位

6、接下来进入重定位

6.1、start.S的relocate_code()代码如下所示
relocate_code:

       mov r4, r0      /* save addr_sp */              // addr_sp栈顶值
       mov r5, r1      /* save addr of gd */           // id值
       mov r6, r2      /* save addr of destination */  // addr值:uboot重定位地址

       /* Set up the stack        */
stack_setup:
       mov sp, r4                //设置栈addr_sp
       adr  r0, _start           //在顶层目录下system.map符号文件中找到_start =0,所以r0=0
       cmp r0, r6                //判断_start(uboot重定位之前的地址)和addr(重定位地址)是否一样
       beq clear_bss             /* skip relocation */ 

       mov r1, r6             /* r1 <- scratch for copy_loop */ //r1= addr(重定位地址)
       ldr   r3, _bss_start_ofs               //_bss_start_ofs=__bss_start - _start(uboot代码大小)
       add r2, r0, r3         /* r2 <- source end address*/   //r2= uboot重定位之前的结束地址

copy_loop:
       ldmia      r0!, {r9-r10}  /* copy from source address [r0] */
                              //将r0处的两个32位数据拷到r9-r10中,然后r0+=8

       stmia      r1!, {r9-r10}  /* copy to   target address [r1]*/
                             //将拷出来的两个数据放入r1(重定位地址)处,然后r1+=8
       cmp r0, r2  /* until source end address [r2]*/   //判断拷贝的数据是否到结束地址
       blo  copy_loop

上面只是把代码复制到SDRAM上,而链接地址内容却没有改变,比如异常向量0x04的代码内容还是0x1e0,
我们以异常向量0x04为例,来看它的反汇编:
在这里插入图片描述
如上图所示,即使uboot在SDRAM运行,由于代码没修改,PC也会跳到0x1e0(flash地址)上

和之前老的uboot有很大区别,以前老的uboot直接是使用的SDRAM链接地址,如下图所示:
在这里插入图片描述
所以,新的uboot采用了动态链接地址的方法,在链接脚本uboot.lds中,可以看到这两个段(.rel.dyn、.dynsym):
在这里插入图片描述
该两个段里,便是保存了各个文件的相对动态信息(.rel.dyn)、动态链接地址的符号(.dynsym)

以上图的.rel.dyn段为例来分析,找到__rel_dyn_start符号处:
在这里插入图片描述
如上图所示,其中0x17表示的是符号的结束标志位,我们以0x20为例来讲解:

在之前,我们讲过0x20里面保存的是异常向量0x04跳转的地址(0x1e0),如下图所示:
在这里插入图片描述
所以,接下来的代码,便会根据0x20里的值0x1e0(flash地址),将SDRAM的33F41000+0x20的内容改为33F41000+0x1e0(SDRAM地址),来改变uboot的链接地址

6.2、重定位的剩余代码,如下所示:

#ifndef CONFIG_SPL_BUILD
       /*
        * fix .rel.dyn relocations
        */
       ldr   r0, _TEXT_BASE             /* r0 <- Text base */  //r0=text段基地址=0
       sub  r9, r6, r0         /* r9 <- relocation offset */   //r9= 重定位后的偏移值=33F41000
       ldr   r10, _dynsym_start_ofs  /* r10 <- sym table ofs */ 
                                          //_dynsym_start_ofs =__dynsym_start - _start=0x73608
                                          //所以r10=动态符号表的起始偏移值=0x73608

       add r10, r10, r0            /* r10 <- sym table in FLASH */
                                       //r10=flash上的动态符号表基地址=0x73608

       ldr   r2, _rel_dyn_start_ofs     /* r2 <- rel dyn start ofs */
                                          //r2=__rel_dyn_start - _start=0x6b568
                                          //所以r2=相对动态信息的起始偏移值=0x6b568

       add r2, r2, r0         /* r2 <- rel dyn start in FLASH */
                                      //r2=flash上的相对动态信息基地址=0x6b568

       ldr   r3, _rel_dyn_end_ofs      /* r3 <- rel dyn end ofs */
                                          // _rel_dyn_end_ofs=__rel_dyn_end - _start=00073608
                                          //所以r3=相对动态信息的结束偏移值=00073608

       add r3, r3, r0         /* r3 <- rel dyn end in FLASH */
                                    //r3=flash上的相对动态信息结束地址=0x6b568

fixloop:
       ldr   r0, [r2]           /* r0 <- location to fix up, IN FLASH! */
                               //以0x20为例,r0=0x6b568地址处的内容= 0x20

       add r0, r0, r9         /* r0 <- location to fix up in RAM */
                                     //r0=33F41000+0x20=33F41020

       ldr   r1, [r2, #4]             //r1= 33F41024地址处的内容=0x17
       and  r7, r1, #0xff       
       cmp r7, #23                  /* relative fixup? */  //0x17=23,所以相等
       beq fixrel                                       //跳到:fixerl

       cmp r7, #2                    /* absolute fixup? */
       beq fixabs
       /* ignore unknown type of fixup */
       b     fixnext
fixabs:
       /* absolute fix: set location to (offset) symbol value */
       mov r1, r1, LSR #4         /* r1 <- symbol index in .dynsym */
       add r1, r10, r1              /* r1 <- address of symbol in table */
       ldr   r1, [r1, #4]             /* r1 <- symbol value */
       add r1, r1, r9         /* r1 <- relocated sym addr */
       b     fixnext

fixrel:
       /* relative fix: increase location by offset */
       ldr   r1, [r0]                  //r1=33F41020地址处的内容=0x1e0
       add r1, r1, r9                //r1=0x1e0+33F41000= 33F411e0

fixnext:
       str   r1, [r0]             //改变链接地址里的内容, 33F41020=33F411e0  (之前为0x1e0)   
       add r2, r2, #8             //r2等于下一个相对动态信息(0x24)的地址
       cmp r2, r3                //若没到尾部__rel_dyn_end,便继续执行: fixloop
       blo  fixloop                 
#endif

7、清除bss段

/*重定位完成后,清除bss段*/
clear_bss:
 #ifndef CONFIG_SPL_BUILD
       ldr   r0, _bss_start_ofs                        //获取flash上的bss段起始位置
       ldr   r1, _bss_end_ofs                          //获取flash上的bss段结束位置
       mov r4, r6                    /* reloc addr */     //获取r6(SDRAM上的uboot基地址)
       add r0, r0, r4                                  //加上重定位偏移值,得到SDRAM上的bss段起始位置
       add r1, r1, r4                                     //得到SDRAM上的bss段结束位置
       mov r2, #0x00000000           /* clear*/

clbss_l:
    str    r2, [r0]           /* clear loop...       */                 //开始清除SDRAM上的bss段
       add r0, r0, #4
       cmp r0, r1
       bne  clbss_l
       bl coloured_LED_init
       bl red_led_on
#endif

8、进入uboot第2阶段

#ifdef CONFIG_NAND_SPL                   //未定义,所以不执行
  ... ...                          
#else                                   //执行else

       ldr   r0, _board_init_r_ofs         //r0=flash上的board_init_r()函数地址偏移值
       adr  r1, _start                    //0
       add lr, r0, r1                     //返回地址lr=flash上的board_init_r()函数
       add lr, lr, r9                     //加上重定位偏移值(r9)后,lr=SDRAM上的board_init_r()函数

       /* setup parameters for board_init_r */
       mov r0, r5             /* gd_t */              //r0=id值
       mov r1, r6             /* dest_addr */         //r1=uboot重定位地址
       /* jump to it ... */
       mov pc, lr              //跳转:  board_init_r()函数

_board_init_r_ofs:
       .word board_init_r - _start        //获取在flash上的board_init_r()函数地址偏移值
#endif

从上面代码看出, 接下来便会进入uboot的board_init_r()函数,该函数会对各个外设初始化、环境变量初始化等。至此uboot的启动过程到此便结束了.

5、修改代码之建新板_时钟_SDRAM_UART

修改U-BOOT代码

5.1、建一个单板

将2410的单板文件夹拷贝成2440

cd board/samsung/
cp smdk2410 smdk2440 -rf

然后将smdk2440下的smdk2410.c改为smdk2440.c,以及修改更改好的Makefile

将2410的头文件拷贝成2440

cd …/…/include/configs/
cp smdk2410.h smdk2440.h

5.2、修改boards.cfg,使uboot支持2440单板

cd …/…
vi boards.cfg
仿照:smdk2410 arm arm920t - samsung s3c24x0
添加:smdk2440 arm arm920t - samsung s3c24x0

添加后,就能够使用make smdk2440_config命令。
(该命令便会调用include/configs/smdk2440.h和board/samsung/smdk2440里的文件来配置uboot)

make smdk2440_config
make

5.3、修改uboot系统时钟

修改代码

在start.S里,uboot只设置了CLKDIVN寄存器
而2440的系统时钟需要设置两个寄存器:MPLLDIVN(设置FCLK频率)、CLKDIVN(设置分频比例),且还要设为异步模式

修改时钟:在start.S里
cpu_init_crit
board_init_f
init_sequence
int board_early_init_f(void) //本来在这里设置时钟,现在改为在start.S里设置时钟
在这里插入图片描述
并修改board\samsung\smdk2440\Smdk2440.c里的board_early_init_f()函数,屏蔽对MPLLDIVN, LOCKTIME寄存器的设置(该函数被start.S->board_init_f()调用,这些寄存器在前面已被设置)

测试

编译出来的uboot非常大,可以先烧写主光盘里的u-boot.bin到nor,然后用这个uboot来烧写新的uboot
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000

打开OpenJTAG,连接:
在这里插入图片描述
在Open On-Chip Debugger界面:
reset halt
halt

mdw 0 读出:ea000013
mdw 4 读出:e59ff014
这两个位置就是u-boot.bin的二进制文件内容

开始一步一步运行:
step 0
step
发现这样看太慢了,生成dis发汇编文件:
arm-linux-objdump -D u-boot > u-boot.dis

查看u-boot.dis文件
搜索:call_board_init_f
在这里插入图片描述
在98出打一个硬件断点:
bp 0x98 4 hw
resume
在这里插入图片描述
mdw 0x30000000 :读地址
读出:ea80ffff
mww 0x30000000 0x12345678 :写地址
mdw 0x30000000 :读地址
读出:1234ffff :只有一半正确
这就可以看出SDRAM的设置有问题,需要修改代码。

接下来便修改bank寄存器

修改SDRAM内存:在lowlevel_init.S 里
在这里插入图片描述
再次编译:make

把u-boot.bin传会pc机,再次烧写:
编译出来的uboot非常大,可以先烧写主光盘里的u-boot.bin到nor,然后用这个uboot来烧写新的uboot
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000

打开OpenJTAG,连接;
在Open On-Chip Debugger界面:
reset
halt
在这里插入图片描述
读写地址:成功
在这里插入图片描述

5.4、乱码,设置UART

重新编译烧写uboot,发现串口已有数据,但是乱码:
在这里插入图片描述

进入arch\arm\cpu\arm920t\s3c24x0\Speed.c下的get_HCLK ()函数

在这里插入图片描述
由于我们没有配置CONFIG_S3C2440宏,所以uboot获取HCLK时钟设置波特率时,用的是CONFIG_S3C2410宏的方法,搜索CONFIG_S3C2410宏,找到位于smdk2440.h:
在这里插入图片描述
然后将smdk2440.h的CONFIG_S3C2410宏 改为: CONFIG_S3C2440宏

编译测试

make时,发现以下几个error:
在这里插入图片描述
进入drivers/mtd/nand/s3c2410_nand.c 的72行:
在这里插入图片描述
其中nand是一个s3c2410_nand结构体:
在这里插入图片描述
该结构体如下所示:
在这里插入图片描述
从上图可以看出,只有定义了CONFIG_S3C2410宏,才能得到该结构体,而我们6.1小节里,使用的是CONFIG_S3C2440宏。且上面的s3c2410_nand结构体和s3c2440_nand结构体的差别也很大,修改s3c2410_nand.c会很麻烦

所以就直接去掉该文件,不让编译器编译即可,步骤如下所示:

1、直接进入s3c2410_nand.c的目录,打开Makefile:
在这里插入图片描述
如上图所示,需要去掉CONFIG_NAND_S3C2410宏定义才行

2、搜索CONFIG_NAND_S3C2410宏,位于include/configs/smdk2440.h:
在这里插入图片描述
如上图所示,我们直接来屏蔽CONFIG_CMD_NAND宏即可,因为该宏下的#ifdef,都是与2410相关的

3、屏蔽include/configs/smdk2440.h下的CONFIG_CMD_NAND宏定义
在这里插入图片描述
上传到服务器,重新编译:
make

把u-boot.bin传会pc机,再次烧写:
编译出来的uboot非常大,可以先烧写主光盘里的u-boot.bin到nor,然后用这个uboot来烧写新的uboot
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000
在这里插入图片描述
发现无乱码了,表示nor启动成功,其中Flash: *** failed ***表示不支持norflash,因为我们只实现了重定位,并没有对nor实现写擦除等命令。

6、修改代码支持NAND启动

修改UBOOT支持NAND启动,原来的代码在链接时加了"-pie"选项, 使得u-boot.bin里多了"(.rel)", “*(.dynsym)”,使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)
1、去掉 "-pie"选项
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie 去掉这行
2、参考"毕业班第1课"的start.S, init.c来修改代码
把init.c放入board/samsung/smdk2440目录, 修改Makefile
修改CONFIG_SYS_TEXT_BASE为0x33f80000
修改start.S
3、修改board_init_f, 把relocate_code去掉
4、修改链接脚本: 把start.S, init.c, lowlevel.S等文件放在最前面

去掉 "-pie"选项

修改vi arch/arm/config.mk:去掉这一行
在这里插入图片描述

参考"毕业班第1课"的start.S, init.c来修改代码

将以前写uboot里的init.c放入board/samsung/smdk2440目录
并检查是否有同名函数名,若函数只在同文件使用,则添加static.并修改Makefile
修改vi board/samsung/smdk2440/Makefile:添加init.o
在这里插入图片描述
修改:smdk2440.h (u-boot-2012_project\u-boot-2012.04.01\include\configs) 42行:
在这里插入图片描述
修改arch/arm/cpu/arm920t/start.S,更改重定位代码
由于nand启动时,2440未初始化之前只有前4K可读写,所以将重定位代码放在start.S的cpu_init_crit(初始化SDRAM)段后面

#ifndef CONFIG_SKIP_LOWLEVEL_INIT
       bl    cpu_init_crit
#endif

//添加以下代码。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
   /* 重定位 */
   ldr   sp, =(CONFIG_SYS_INIT_SP_ADDR)      //等于0x30000f80
   bic   sp, sp, #7       /* 8-byte alignment for ABI compliance */
   
   mov r0,#0              //  源:r0->src
   ldr r1,_TEXT_BASE     //目的:_TEXT_BASE : 0x33f00000
   ldr r2,_bss_start_ofs      //大小:_bss_start_ofs:  __bss_start - _start   (有效代码大小)
   
   bl copy_code_to_sdram //该函数首先会初始化nand控制器,然后复制代码到SDRAM连接地址dest上
   bl clear_bss             //清除bss段(参考自制uboot章节)
ldr pc,=call_board_init_f                 //绝对跳转,跳到SDRAM上执行
//添加以上代码。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

call_board_init_f:
   ldr   r0,=0x00000000
   bl    board_init_f

上面的_TEXT_BASE,在start.S靠前处定义:
在这里插入图片描述
由于它位于靠前处,保证了_TEXT_BASE存在前4k空间里,若直接使用ldr r1,=CONFIG_SYS_TEXT_BASE,编译器可能会将这个宏定义放在SDRAM上,则会出错

修改board_init_f, 把relocate_code去掉

修改:重定位写在前面了,所以我们还要删除start.S后面的relocate_code重定位段,清除BSS段
board_init_r位置处的代码,改为如下所示:

/* void relocate_code (addr_sp, gd, addr_moni)*/
.globl      relocate_code
relocate_code:
       mov r4, r0      /* save addr_sp */       
       mov    sp, r4
       mov r0, r1      /* save addr of gd */
       mov r1, r2      /* save addr of destination */
       bl   board_init_r        //进入uboot第二阶段代码

修改board_init_f()函数(位于arch/arm/lib/board.c)
本节添加的uboot重定位是直接以基地址0x33F00000开始的, 在上一章分析出,board_init_f()函数划分uboot重定位所在区域时,是通过动态划分的.
修改:board.c (u-boot-2012.04.01\arch\arm\lib)
在这里插入图片描述

修改链接脚本: 把start.S, init.c, lowlevel.S等文件放在最前面

修改vi arch/arm/cpu/u-boot.lds:添加
在这里插入图片描述

其他修改

修改common.h (\u-boot-2012.04.01\include)修改:
在这里插入图片描述
修改vi include/common.h:改为unsigned int
在这里插入图片描述
再次make
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
nand erase 0 80000 :共512k
nand write 30000000 0 80000

烧写后,如下图所示:
在这里插入图片描述
nand启动便实现完成了,上面的Flash: *** failed *** 是属于uboot第二阶段函数board_init_r()里的代码,表示不支持nor flash,不能实现读,写,擦除等命令

7、修改代码支持NorFlash

修改UBOOT支持NOR FLASH
修改:drivers\mtd\jedec_flash.c 加上新的型号
修复重定时留下来的BUG:SP要重新设置

修改:board.c (u-boot-2012.04.01\arch\arm\lib)
在这里插入图片描述
修改:cfi_flash.c (u-boot-2012.04.01\drivers\mtd)
在这里插入图片描述
编译:
make

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000

程序出错:
在这里插入图片描述
修改:jedec_flash.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd)
在这里插入图片描述
在这里插入图片描述
其中的NumEraseRegions是擦除区域:
在这里插入图片描述
重新编译下载烧写:
在这里插入图片描述
修改:smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
修改:cfi_flash.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd)
在这里插入图片描述
再次make

把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000
在这里插入图片描述
erase 80000 8ffff
cp.b 30000000 80000 10000
md.b 30000000
md.b 80000

mw.b 30000000 12345678
erase 80000 8ffff
cp.b 30000000 80000 10000
md.b 80000
cmp.b 30000000 80000 10000

erase 80000 8ffff
cp.b 32000000 80000 10000
cmp.b 32000000 80000 10000

重新设置栈:
修改start.S (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\arch\arm\cpu\arm920t)
定义:
在这里插入图片描述
修改:board.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\arch\arm\lib)
函数board_init_f中:
声明:
在这里插入图片描述
使用:
在这里插入图片描述
上传到服务器:
u-boot-2012.04.01\arch\arm\lib\board.c

再次make时出现报错等等:
在这里插入图片描述
在这里插入图片描述
再次烧写出错:把board_init_f改为board_init_r

把u-boot.bin传会pc机,再次烧写:
oflash 0 1 1 0 0 .\u-boot.bin
把服务器上的u-boot.bin传回pc上;
usb 1 30000000,再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000

再次烧写即可:
在这里插入图片描述

8、修改代码支持NandFlash

修改UBOOT支持NAND FLASH
修改:include/configs/smdk2440.h: #define CONFIG_CMD_NAND
把drivers\mtd\nand\s3c2410_nand.c复制为s3c2440_nand.c

分析过程:

nand_init
	nand_init_chip
		board_nand_init
			设置nand_chip结构体, 提供底层的操作函数
		nand_scan
			nand_scan_ident
				nand_set_defaults
					chip->select_chip = nand_select_chip;
					chip->cmdfunc = nand_command;
					chip->read_byte = busw ? nand_read_byte16 : nand_read_byte;
				nand_get_flash_type
					chip->select_chip
					chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
						nand_command()//即可发命令,也可发列地址(页内地址)、行地址(哪一页)
						chip->cmd_ctrl
							s3c2440_hwcontrol
					chip->cmdfunc(mtd, NAND_CMD_READID, 0x00, -1);
					*maf_id = chip->read_byte(mtd);
					*dev_id = chip->read_byte(mtd);

修改:smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
在目录:E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd\nand下:
复制一份2440的文件
在这里插入图片描述
修改:smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
修改:Makefile (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd\nand)
在这里插入图片描述
修改:E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd\nand\s3c2410_nand.c
在这里插入图片描述
修改这三位可以根据单板所使用的nand芯片手册进行设置:0 1 0,也可保持不变
在这里插入图片描述
修改cfg的值:
在这里插入图片描述
把2410改为2440:
在这里插入图片描述
删除这连个函数之间的代码:
在这里插入图片描述
修改:
在这里插入图片描述
为:
在这里插入图片描述
添加:
在这里插入图片描述
把所有的2410_nand改为2440_nand:
在这里插入图片描述
修改函数s3c2440_hwcontrol:
在这里插入图片描述
修改片选函数:s3c2440_nand_select
board_nand_init函数中:
在这里插入图片描述
上传服务器:
在这里插入图片描述
把u-boot.bin传会pc机,再次烧写:
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 3000000 0:再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000
在这里插入图片描述
烧写到nand flash
nand erase 0 80000
nand write 0 0 80000
nand read 30000000 0 80000
cmp.b 0 30000000 80000
在这里插入图片描述
开发版设置为nand启动,重新上电:完成支持nand
即可发现nand启动时不支持读取nor flash
在这里插入图片描述

9、修改代码支持DM9000网卡

修改UBOOT支持DM9000网卡
eth_initialize
board_eth_init
cs8900_initialize

1、先配置dm9000x确定访问地址
CONFIG_DM9000_BASE按照:
开发板中的网卡节2440的片选4:
在这里插入图片描述
2440中片选4的基地址为:
在这里插入图片描述
地址接线为bit2:
在这里插入图片描述
确定DM9000网卡的配置参数:
修改smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
2、设置位宽
lowlevel_init.S (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\board\samsung\smdk2440\)
在这里插入图片描述
在这里插入图片描述
修改smdk2410.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\board\samsung\smdk2440):
在这里插入图片描述
make进行编译,

把u-boot.bin传会pc机,再次烧写:
oflash 0 1 1 0 0 .\u-boot.bin

把服务器上的u-boot.bin传回pc上;
usb 1 30000000:再使用dnw下载u-boot.bin
protect off all :去除nor flash 的写保护
erase 0 7FFFF :0(开始地址)7FFFF(结束地址)共512k
cp.b 30000000 0 80000 :把程序烧写到0地址,烧写大小为0x80000

配置IP:
set ipaddr 192.168.2.66
set ethaddr 00:0c:29:4d:e4:f4
set serverip 192.168.2.22

启动tftp工具:
在这里插入图片描述
下载并启动内核:
tftp 30000000 uImage_4.3
bootm 30000000

10、裁剪和修改默认参数

设置IP:smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
去除不必要的配置:
在这里插入图片描述
在这里插入图片描述
再次make,u-boot.bin只有200k

分区大小:
内核打印出来的分区信息
0x00000000-0x00040000 : “bootloader”
0x00040000-0x00060000 : “params”
0x00060000-0x00260000 : “kernel”
0x00260000-0x10000000 : “root”

修改smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
在这里插入图片描述
make编译,
配置IP:
set ipaddr 192.168.2.66
set ethaddr 00:0c:29:4d:e4:f4
set serverip 192.168.2.22

启动tftp工具:
在这里插入图片描述
下载uboot:
tftp 30000000 u-boot.bin
protect off all
erase 0 3ffff
cp.b 30000000 0 40000

reset重启开发板:
在这里插入图片描述
保存消除错误信息:save
在这里插入图片描述
下载内核:
tftp 3000000 uImage_4.3
在这里插入图片描述
再把内核烧写到nand flash:
nand erase 60000 200000
nand write 30000000 60000 200000

修改smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
修改board.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\arch\arm\lib)
在这里插入图片描述
再次编译:
make distclean
make smdk2440_config
make

下载uboot到nor:
tftp 30000000 u-boot_new.bin
protect off all
erase 0 3ffff
cp.b 30000000 0 40000
reset

从nor烧写uboot到nand:
nand erase 0 40000
nand write 0 0 40000
nand read 30000000 0 40000 //比较是否写入nand
cmp.b 0 30000000 40000

烧写内核到nand:
tftp 30000000 uImage_4.3
nand erase.part kernel
nand write 30000000 kernel

重启进入内核: 没有烧写文件系统就会卡住,有文件系统则会启动进入。
reset

11、支持烧写yaffs映象及制作补丁

烧写内核:
tftp 30000000 uImage_4.3
nand erase.part kernel
nand write 30000000 kernel

烧写JFFS2文件系统:
tftp 30000000 fs_mini_mdev.jffs2
nand erase.part rootfs
nand write.jffs2 30000000 0x00260000 5b89a8
set bootargs console=ttyAC0 root=/dev/mtdblock3 rootfstype=jffs2

烧写YAFFS:
tftp 30000000 fs_mini_mdev.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 889bc0

修改:smdk2440.h (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\include\configs)
在这里插入图片描述
修改nand_util.c (E:\ZDY_ARM练习程序\u-boot-2012_project\u-boot-2012.04.01\drivers\mtd\nand)
在这里插入图片描述
编译:
make clean
make

更新UBOOT:
tftp 30000000 u-boot.bin
protect off all
erase 0 3ffff
cp.b 30000000 0 40000

从nor烧写uboot到nand:
nand erase 0 40000
nand write 0 0 40000
nand read 30000000 0 40000 //比较是否写入nand
cmp.b 0 30000000 40000

烧写内核:
tftp 30000000 uImage_4.3
nand erase.part kernel
nand write 30000000 kernel

烧写YAFFS
tftp 30000000 fs_mini_mdev.yaffs2
nand erase.part rootfs
nand write.yaffs 30000000 260000 889bc0

制作补丁文件:
make distclean
rm u-boot.dis
cd …/
mv u-boot-2012.04.01 u-boot-2012.04.01_zdy
tar xjf u-boot-2012.04.01.tar.bz2
diff -urN u-boot-2012.04.01 u-boot-2012.04.01_zdy > u-boot-2012.04.01_zdy.patch

打补丁:
cd u-boot-2012.04.01
patch -p1 < …/u-boot-2012.04.01_zdy.patch

make distclean
make smdk2440_config
make

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值