u-boot移植总结(一)start.S分析

本次移植u-boot-2010.09是基于S3C2440的FL440板子,板子自带NANDFLASH而没有NORFLASH,所以在U-BOOT启动的过程中必须实现从NANDFLASH到SDRAM的重定向。

其中最重要的就是在U-BOOT开始的start.S汇编代码,这段代码要完成工作:

1,异常中断向量表,复位后异常向量处理

2, 跳转到代码实际执行处start_code

3,关闭看门狗WATCHDOG

3,关闭所有中断INTERRUPT

4,设置时钟分频,主要设置寄存器CLKDVN,MPLLCON,UPLLCON

5,关闭MMU和CACHE,并调用lowlevel_init.S完成SDRAM和NANDFLASH的初始化,为代码的重定向做准备

6,设置堆栈,并且跳入第二阶段的C代码

7,异常向量处理代码

 

以下为start.S的分析:

 

1,异常中断向量表,复位后异常向量处理

 

  1. //声明一个全局标量,在cpu/arm920t/u-boot.lds中有定义,即代码的入口地址,也是编译地址  
  2. _start: b   start_code  
  3.    ldr pc, _undefined_instruction  
  4.    ldr pc, _software_interrupt  
  5.    ldr pc, _prefetch_abort  
  6.    ldr pc, _data_abort  
  7.    ldr pc, _not_used  
  8.    ldr pc, _irq  
  9.    ldr pc, _fiq  
  10.   
  11. _undefined_instruction: .word undefined_instruction  //.word 定义一个32位的地址标识  
  12. _software_interrupt:    .word software_interrupt  
  13. _prefetch_abort:        .word prefetch_abort  
  14. _data_abort:            .word data_abort  
  15. _not_used:              .word not_used  
  16. _irq:                   .word irq  
  17. _fiq:                   .word fiq  
  18.   
  19.    .balignl 16,0xdeadbeef//将地址偏移为16的整数倍,空余的内容填上0xdeadbeef,这个数即“Magic Number”,可用判断当前u-boot执行位置  
  20.   
  21.   
  22. _TEXT_BASE:  
  23.    .word   TEXT_BASE    //在config.mk中有定义,即u-boot自启时flash从定向到sdram的地址  
  24. .globl _armboot_start   //声明一个全局变量,之后要调用  
  25. _armboot_start:  
  26.    .word _start  
  27.   
  28. /* 
  29.  * These are defined in the board-specific linker script. 
  30.  */  
  31.   
  32. .globl _bss_start                   //连接脚本u-boot.lds中有定义  
  33. _bss_start:  
  34.    .word __bss_start  
  35.   
  36. .globl _bss_end         //连接脚本u-boot.lds中有定义</span>  
  37. _bss_end:  
  38.   .word _end  
  39.   
  40. #ifdef CONFIG_USE_IRQ           //堆栈设置  
  41. /* IRQ stack memory (calculated at run-time) */  
  42.   
  43. .globl IRQ_STACK_START  
  44. IRQ_STACK_START:  
  45.   .word   0x0badc0de  
  46.   
  47. /* IRQ stack memory (calculated at run-time) */  
  48.   
  49. .globl FIQ_STACK_START  
  50. FIQ_STACK_START:  
  51.    .word 0x0badc0de  
  52.   
  53. #endif  

 


 

 

 

 

 

2, 跳转到代码实际执行处(设置管理模式=>关闭看门狗=>关闭所有中断=>设置时钟分频)

 

  1. /* 
  2.  * the actual start code 
  3.  */  
  4.   
  5. start_code:  
  6.     /* 
  7.      * set the cpu to SVC32 mode   
  8.      */  
  9.                               //设置管理模式  31  30  29  28      7   6   4    3    2    1    0    
  10.     mrs r0, cpsr              //    CPSR      N   Z   C   V       I   F   M4   M3   M2   M1   M0  
  11.     bic r0, r0, #0x1f         //                                          1    0    0    1    1  
  12.     orr r0, r0, #0xd3    
  13.     msr cpsr, r0           // CPSR为状态寄存器,用于设置系统运行状态,只能用MSR MRS指令  
  14.   
  15. #if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)   //系统中断重定向于RAM中,以便快速响应中断,搬运的代码为4*16bytes  
  16. /*  relocate exception table */  
  17.     ldr r0, =_start  
  18.     ldr r1, =0x0  
  19.     mov r2, #16  
  20. copyex:   
  21.     subs r2, r2, #1  
  22.     ldr r3, [r0], #4   
  23.     str r3, [r1], #4   
  24.     bne copyex  
  25. #endif  
  26.   
  27.   
  28.   
  29. //关闭看门狗  
  30. #if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)  
  31.     /* turn off the watchdog */  
  32.   
  33. #if defined(CONFIG_S3C2400)      
  34. #define pWTCON    0x15300000  
  35. #define INTMSK    0x14400008  /* Interupt-Controller base addresses */  
  36. #define CLKDIVN   0x14800014  /* clock divisor register */  
  37. #else       //查阅s3c2440的datesheet中指出寄存器地址  
  38. #define pWTCON    0x53000000   
  39. #define INTMSK    0x4A000008  /* Interupt-Controller base addresses */  
  40. #define INTSUBMSK 0x4A00001C  
  41. #define CLKDIVN   0x4C000014  /* clock divisor register */  
  42. #endif  
  43.   
  44. #define CLK_CTL_BASE 0x4C000000    //添加时钟分频寄存器地址,用于时钟分频设置  
  45. #define MDIV_405 0x7f<<12  
  46. #define PSDIV_405 0x21  
  47. #define MDIV_200 0xa1<<12  
  48. #define PSDIV_200 0x31 </span>  
  49.     ldr r0, =pWTCON   
  50.     mov r1, #0x0  
  51.     str r1, [r0] /*  mask all IRQs by setting all bits in the INTMR - default */  
  52.     mov r1, #0xffffffff                                //ARM920T有32个中断源,禁止所有中断,32位中断屏蔽寄存器置位   
  53.     ldr r0, =INTMSK   
  54.     str r1, [r0]  
  55. #if defined(CONFIG_S3C2440)||defined(CONFIG_S3C2410) /* add by zhou */   
  56.     ldr r1, =0x7ff<span style="white-space:pre">      //屏蔽所有的中断源,S3C2440中寄存器只有前15位有效,故0x7ff置位INTSUNMSK   
  57.     ldr r0, =INTSUBMSK   
  58.     str r1, [r0]  
  59. #endif  
  60. //设置时钟频率  
  61. #if defined(CONFIG_S3C2440)  
  62.     mov  r1, #5  
  63.     str  r1, [r0]  
  64.   
  65.     mrc  p15, 0, r1, c1, c0, 0   
  66.     orr  r1, r1, #0xc0000000  
  67.     mcr  p15, 0, r1, c1, c0, 0   
  68.   
  69.     mov  r1, #CLK_CTL_BASE  //S3C2440系统主频为405MHZ,USB为48MHZ,要求MPLLCON = (0x7f<<12) | (0x02<<4) | (0x01) = 0x7f021  
  70.     mov  r2, #MDIV_405  
  71.     add  r2, r2, #PSDIV_405  
  72.     str  r2, [r1, #0x04]     
  73. #else  
  74.   
  75.     /* FCLK:HCLK:PCLK = 1:2:4 */  
  76.     /* default FCLK is 120 MHz ! */  
  77.     ldr r0, =CLKDIVN  
  78.     mov r1, #3  
  79.     str r1, [r0]  
  80.   
  81.     mrc p15, 0, r1, c1, c0, 0  
  82.     orr r1, r1, #0xc0000000  
  83.     mcr p15, 0, r1, c1, c0, 0  
  84.   
  85.   
  86.     mov r1, #CLK_CTL_BASE  
  87.     mov r2, #MDIV_200  
  88.     add r2, r2,#PSDIV_200  
  89.     str r2, [r1,#0x04]  
  90.   
  91. #endif  
  92. #endif /* (CONFIG_S3C2400) || (CONFIG_S3C2410) || (CONFIG_S3C2440) */  



 

 

 

 

3,关闭MMU和CACHE,并调用lowlevel_init.S完成SDRAM和NANDFLASH的初始化,为代码的重定向做准备

 

  1.    /******************************************* 
  2.      * we do sys-critical inits only at reboot, 
  3.      * not when booting from ram! 
  4.      ******************************************/  
  5.   
  6. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  7.     bl  cpu_init_crit  //关闭MMU和CACHE,并调用lowlevel_init.S完成SDRAM和NANDFLASH的初始化  
  8. #endif  
  9. ...........  
  10. ...........  
  11. ...........  
  12. /* 
  13.  ************************************************************************* 
  14.  * 
  15.  * CPU_init_critical registers 
  16.  * 
  17.  * setup important registers 
  18.  * setup memory timing 
  19.  * 
  20.  ************************************************************************* 
  21.  */  
  22.   
  23. #ifndef CONFIG_SKIP_LOWLEVEL_INIT  
  24. cpu_init_crit:  
  25.     /* 
  26.      * flush v4 I/D caches 
  27.      */  
  28.     mov r0, #0            //具体设置看下图,详细参考CP15指令:http://blog.csdn.net/gooogleman/article/details/3635238  
  29.     mcr p15, 0, r0, c7, c7, 0 //向c7写入0将使ICache与DCache 无效flush v3/v4 cache   
  30.     mcr p15, 0, r0, c8, c7, 0  //向c8写入0将使TLB失效 flush v4 TLB   
  31.   
  32.     /* 
  33.      * disable MMU stuff and caches  <span >   //协处理器CP15的C1处理器可以设置MMU和caches,具体参考下图 
  34.      */  
  35.     mrc p15, 0, r0, c1, c0, 0    
  36.     bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)  
  37.     bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)  
  38.     orr r0, r0, #0x00000002 @ set bit 2 (A) Align  
  39.     orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache  
  40.     mcr p15, 0, r0, c1, c0, 0  
  41.   
  42.     /* 
  43.      * before relocating, we have to setup RAM timing 
  44.      * because memory timing is board-dependend, you will 
  45.      * find a lowlevel_init.S in your board directory. 
  46.      */  
  47.     mov ip, lr       //由于有两层调用,需要把lr保存到ip,以防止破坏  
  48.   
  49.     bl  lowlevel_init   //调用c函数,初始化FLASH和SDRAM,为代码重定向做准备  
  50.   
  51.     mov lr, ip   
  52.     mov pc, lr      //返回  
  53. #endif /* CONFIG_SKIP_LOWLEVEL_INIT */  

 


 

 

 

代码重定向基本思路:

1.内存运行与否,是则设置堆栈,跳入c函数阶段

2.若不在内存运行,判断是在norflash还在nandflash运行

  1. //代码重定向部分  
  2. /***************CHECK_CODE_POSITION******************************/  
  3.   
  4.     adr r0, _start      /* r0 <- current position of code   */   //检查代码是否在已经SDRAM中运行,是则设置堆栈,并跳入c代码部分  
  5.     ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */  //_start为u-boot的真正运行地址,_TEXT_BASE为FLASH加载到SDRAM的地址,在config.mk中定义为0x33f80000  
  6.     cmp r0, r1          /* don't reloc during debug         */      //若相等,说明已经在SDRAM中运行,设置堆栈,并且调转到第二阶段的C函数  
  7.     beq stack_setup                     //若不相等,则要判断是从NORFLASF或NANDFLASH启动  
  8.   
  9. /***************CHECK_CODE_POSITION******************************/  
  10.   
  11. /***************CHECK_BOOT_FLASH********************************/  
  12.   
  13.     ldr r1, =((4<<28)|(3<<4)|(3<<2))  /*address in 4000003c*/  
  14.     mov r0, #0     //NANDFLASH的启动原理,启动时4K SRAM,即Stepping Stone,会映射到nGCS0,0x0000 0000地址,同时它还是会被映射到0x4000 0000地址   
  15.     str r0,[r1]    //而NORFLASH支持片上运行,并会被一直挂载到nGCS0,0x0000 0000,具体可以参照NANDFLASH启动原理  
  16.   
  17.     mov r1, #0x3c   /*address in 0x3c*/ //NANDFLASH启动时,因为地址为16倍数对齐,此时0x0000 003c 和 0x4000 003c都为唯一确定的0xdeadbeef,即"Magic Mumber"  
  18.     ldr r0, [r1]    //当0x4000 003c清零,若0x0000 003c读出也是零,则u-boot代码从NANDFLASH启动,否则从NORFLASH  
  19.     cmp r0, #0  
  20.     bne relocate  
  21.   
  22.   
  23.     /*recover 0x4000003c */  
  24.     ldr r0, =(0xdeadbeef)     //若在NANDFLASH启动,必须保证代码和前4K拷贝到SRAM一致,否则会进入死循环  
  25.     ldr r1, =((4<<28)|(3<<4)|(3<<2))  
  26.     str r0, [r1]  
  27.   
  28. /***************CHECK_BOOT_FLASH********************************/  
  29.   
  30. /***************NAND_BOOT********************************/  
  31.   
  32. #ifdef  CONFIG_S3C2440  //支持S3C2440的NANDFLASH  
  33. #define LENGTH_UBOOT  0x60000  
  34. #define NAND_CTL_BASE 0x4E000000  
  35.   
  36. /* Offset */  
  37. #define oNFCONF 0x00  
  38. #define oNFCONT 0x04  
  39. #define oNFCMD  0x08  
  40. #define oNFSTAT 0x20  
  41.   
  42.     mov  r1, #NAND_CTL_BASE                 //NAND Flash配置寄存器设置  
  43.     ldr  r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )  
  44.     str  r2, [r1, #oNFCONF]  
  45.     ldr  r2, [r1, #oNFCONF]  
  46.   
  47.     ldr  r2, =( (1<<4)|(0<<1)|(1<<0) ) /* @ Active low CE Control */  
  48.     str  r2, [r1, #oNFCONT]     //NAND Flash控制寄存器设置  
  49.     ldr  r2, [r1, #oNFCONT]  
  50.   
  51.     ldr  r2, =(0x6)     /*  @ RnB Clear */      //NAND Flash状态寄存器设置  
  52.     str  r2, [r1, #oNFSTAT]  
  53.     ldr  r2, [r1, #oNFSTAT]  
  54.   
  55.     mov  r2, #0xff              //NAND Flash命令寄存器设置  
  56.     strb r2, [r1, #oNFCMD]  
  57.     mov  r3, #0   
  58.   
  59.     nand1:  
  60.     add  r3, r3, #0x1  
  61.     cmp  r3, #0xa  
  62.     blt  nand1  
  63.   
  64. nand2:  
  65.     ldr r2, [r1, #oNFSTAT]  
  66.     tst r2, #0x4  
  67.     beq nand2   
  68.     ldr r2, [r1, #oNFCONT]  
  69.     orr r2, r2, #0x2  
  70.     str r2, [r1, #oNFCONT]   
  71.   
  72. /* get read to call C functions (for nand_read()) */  
  73.      ldr sp, DW_STACK_START  
  74.      mov fp, #0  
  75.   
  76.  /* copy U-Boot to RAM */  
  77.      ldr r0, =TEXT_BASE //汇编调用c函数nand_read_ll,第一个参数存于r0搬运到内存地址  
  78.      mov r1, #0x0     //第二个参数存于r1,NANDFLASH中u-boot地址  
  79.      mov r2, #LENGTH_UBOOT /第三个参数存于r2,u-boot的总大小  
  80.      bl nand_read_ll //在nand_read.c定义,支持不同NANDFLASH芯片代码拷贝  
  81.      tst r0, #0x0 //r0是存放函数返回的参数,返回值为0则正确拷贝,否则进入死循环   
  82.      beq ok_nand_read  
  83.   
  84. bad_nand_read:  
  85. loop2:  
  86.     b loop2  
  87. ok_nand_read: //前4K代码比较,即判定Stepping Stone中4k代码和c函数搬运的代码是否一致   
  88.     mov r0, #0   
  89.     ldr r1, =TEXT_BASE   
  90.     mov r2, #0x400 /* 4 bytes * 1024 = 4Kbytes */  
  91. go_next:   
  92.     ldr r3, [r0], #4 //r3存放NANDFLASH上u-boot的代码  
  93.     ldr r4, [r1], #4 //r4为在内存中的u-boot代码   
  94.     teq r3, r4  
  95.     bne notmatch //不一致则进入死循环  
  96.     subs r2, r2, #4  
  97.     beq stack_setup  
  98.     bne go_next  
  99.   
  100. notmatch:  
  101. loop3:  
  102.     b loop3  
  103. #endif  
  104.   
  105. #ifdef CONFIG_S3C2410  
  106. /* Offset */  
  107. #define oNFCONF 0x00  
  108. #define oNFCMD  0x04  
  109. #define oNFSTAT 0x10  
  110.   
  111.   
  112.     mov  r1, #NAND_CTL_BASE  
  113.     ldr  r2, =0xf830  
  114.     str  r2, [r1, #oNFCONF]  
  115.     ldr  r2, [r1, #oNFCONF]  
  116.     bic  r2,  r2, #0x800     /* enable chip  */  
  117.     str  r2, [r1, #oNFCONF]  
  118.     mov  r2, #0xff        /*  @ RESET command  +  strb  r2, [r1, #oNFCMD] */  
  119.     strb r2, [r1, #oNFCMD]  
  120.     mov  r3, #0   
  121.   
  122.   
  123. nand1:  
  124.     add  r3, r3, #0x1  
  125.     cmp  r3, #0xa  
  126.     blt  nand1  
  127.   
  128.   
  129. nand2:  
  130.     ldr  r2, [r1, #oNFSTAT] /* @ wait ready */  
  131.     tst  r2, #0x1  
  132.     beq  nand2  
  133.   
  134.   
  135.     ldr  r2, [r1, #oNFCONF]  
  136.     orr  r2,  r2, #0x800   /*@ disable chip */  
  137.     str  r2, [r1, #oNFCONF]  
  138.   
  139.   
  140.     /*    @ get read to call C functions (for nand_read()) */  
  141.     ldr  sp, DW_STACK_START    /* @ setup stack pointer */  
  142.     mov  fp, #0                /* @ no previous frame, so fp=0 */  
  143.   
  144.   
  145.     /*  @ copy U-Boot to RAM */  
  146.     ldr r0, =TEXT_BASE  
  147.     mov r1, #0x0  
  148.     mov r2, #LENGTH_UBOOT  
  149.     bl nand_read_ll  
  150.     tst r0, #0x0  
  151.     beq ok_nand_read  
  152. bad_nand_read:  
  153. loop2:  
  154.     b  loop2  /*@ infinite loop */  
  155.   
  156.   
  157.   
  158.   
  159. ok_nand_read:  
  160. /*     @ verify */  
  161.     mov r0, #0   
  162.     ldr r1, =TEXT_BASE  
  163.     mov r2, #0x400 /* @ 4 bytes * 1024 = 4K-bytes */  
  164.   
  165.   
  166. go_next:  
  167.     ldr  r3, [r0], #4  
  168.     ldr  r4, [r1], #4  
  169.     teq  r3, r4  
  170.     bne  notmatch  
  171.     subs r2, r2, #4  
  172.     beq  stack_setup  
  173.     bne  go_next  
  174.   
  175.   
  176. notmatch:  
  177. loop3:  
  178.     b    loop3  /*@ infinite loop */  
  179. #endif  
  180.   
  181. /***************** NAND_BOOT ************************************************/</span>  

 

 

 

 




3,设置堆栈,并且跳入第二阶段的C代码

 

  1.  /* Set up the stack */  
  2. stack_setup:  
  3.     ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */  
  4.     sub r0, r0, #CONFIG_SYS_MALLOC_LEN  /* malloc area              */  
  5.     sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */  
  6. #ifdef CONFIG_USE_IRQ  
  7.     sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)  
  8. #endif  
  9.     sub sp, r0, #12     /* leave 3 words for abort-stack    */  
  10.   
  11. clear_bss:      //将未初始化.bss段初始化0  
  12.     ldr r0, _bss_start      /* find start of bss segment        */  
  13.     ldr r1, _bss_end        /* stop here                        */  
  14.     mov r2, #0x00000000     /* clear                            */  
  15.   
  16. clbss_l:  
  17.     str r2, [r0]        /* clear loop...                    */  
  18.     add r0, r0, #4  
  19.     cmp r0, r1  
  20.     ble clbss_l  
  21.   
  22.     ldr pc, _start_armboot          //跳到第二阶段c函数,进一步初始化板子硬件  
  23.   
  24. _start_armboot: .word start_armboot  
  25.   
  26. #define STACK_BASE 0x33f00000       //为nand_read_ll函数调用设置堆栈  
  27. #define STACK_SIZE 0x10000  
  28.   
  29.   .align 2  
  30. DW_STACK_START: .word  STACK_BASE+STACK_SIZE-4 </span>  



 



 

 

 

4,异常向量处理代码

 

  1. /************************************************************************* 
  2.  * 
  3.  * Interrupt handling 
  4.  * 
  5.  ************************************************************************* 
  6.  */  
  7. ......  
posted @ 2014-07-07 15:23  jeffkuang  阅读(234)  评论(0)    收藏  举报