单片机
返回首页

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

2024-07-25 来源:cnblogs

本次移植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,异常中断向量表,复位后异常向量处理


//声明一个全局标量,在cpu/arm920t/u-boot.lds中有定义,即代码的入口地址,也是编译地址

_start: b   start_code

   ldr pc, _undefined_instruction

   ldr pc, _software_interrupt

   ldr pc, _prefetch_abort

   ldr pc, _data_abort

   ldr pc, _not_used

   ldr pc, _irq

   ldr pc, _fiq


_undefined_instruction: .word undefined_instruction  //.word 定义一个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


   .balignl 16,0xdeadbeef//将地址偏移为16的整数倍,空余的内容填上0xdeadbeef,这个数即“Magic Number”,可用判断当前u-boot执行位置



_TEXT_BASE:

   .word   TEXT_BASE    //在config.mk中有定义,即u-boot自启时flash从定向到sdram的地址

.globl _armboot_start   //声明一个全局变量,之后要调用

_armboot_start:

   .word _start


/*

 * These are defined in the board-specific linker script.

 */


.globl _bss_start                   //连接脚本u-boot.lds中有定义

_bss_start:

   .word __bss_start


.globl _bss_end //连接脚本u-boot.lds中有定义

_bss_end:

  .word _end


#ifdef CONFIG_USE_IRQ           //堆栈设置

/* IRQ stack memory (calculated at run-time) */


.globl IRQ_STACK_START

IRQ_STACK_START:

  .word   0x0badc0de


/* IRQ stack memory (calculated at run-time) */


.globl FIQ_STACK_START

FIQ_STACK_START:

   .word 0x0badc0de


#endif

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


/*

 * the actual start code

 */


start_code:

    /*

     * set the cpu to SVC32 mode  

     */

                              //设置管理模式  31  30  29  28      7   6   4    3    2    1    0  

    mrs r0, cpsr              //    CPSR      N   Z   C   V       I   F   M4   M3   M2   M1   M0

    bic r0, r0, #0x1f         //                                          1    0    0    1    1

    orr r0, r0, #0xd3  

    msr cpsr, r0           // CPSR为状态寄存器,用于设置系统运行状态,只能用MSR MRS指令


#if defined(CONFIG_AT91RM9200DK) || defined(CONFIG_AT91RM9200EK)   //系统中断重定向于RAM中,以便快速响应中断,搬运的代码为4*16bytes

/*  relocate exception table */

    ldr r0, =_start

    ldr r1, =0x0

    mov r2, #16

copyex: 

    subs r2, r2, #1

    ldr r3, [r0], #4 

    str r3, [r1], #4 

    bne copyex

#endif


//关闭看门狗

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)

    /* turn off the watchdog */


#if defined(CONFIG_S3C2400)    

#define pWTCON    0x15300000

#define INTMSK    0x14400008  /* Interupt-Controller base addresses */

#define CLKDIVN   0x14800014  /* clock divisor register */

#else //查阅s3c2440的datesheet中指出寄存器地址

#define pWTCON    0x53000000 

#define INTMSK    0x4A000008  /* Interupt-Controller base addresses */

#define INTSUBMSK 0x4A00001C

#define CLKDIVN   0x4C000014  /* clock divisor register */

#endif


#define CLK_CTL_BASE 0x4C000000    //添加时钟分频寄存器地址,用于时钟分频设置

#define MDIV_405 0x7f<<12

#define PSDIV_405 0x21

#define MDIV_200 0xa1<<12

#define PSDIV_200 0x31

    ldr r0, =pWTCON

    mov r1, #0x0

    str r1, [r0] /*  mask all IRQs by setting all bits in the INTMR - default */

    mov r1, #0xffffffff                                //ARM920T有32个中断源,禁止所有中断,32位中断屏蔽寄存器置位 

    ldr r0, =INTMSK 

    str r1, [r0]

#if defined(CONFIG_S3C2440)||defined(CONFIG_S3C2410) /* add by zhou */ 

    ldr r1, =0x7ff //屏蔽所有的中断源,S3C2440中寄存器只有前15位有效,故0x7ff置位INTSUNMSK 

    ldr r0, =INTSUBMSK 

    str r1, [r0]

#endif

//设置时钟频率

#if defined(CONFIG_S3C2440)

    mov  r1, #5

    str  r1, [r0]


    mrc  p15, 0, r1, c1, c0, 0 

    orr  r1, r1, #0xc0000000

    mcr  p15, 0, r1, c1, c0, 0 


    mov  r1, #CLK_CTL_BASE //S3C2440系统主频为405MHZ,USB为48MHZ,要求MPLLCON = (0x7f<<12) | (0x02<<4) | (0x01) = 0x7f021

    mov  r2, #MDIV_405

    add  r2, r2, #PSDIV_405

    str  r2, [r1, #0x04]   

#else


    /* FCLK:HCLK:PCLK = 1:2:4 */

    /* default FCLK is 120 MHz ! */

    ldr r0, =CLKDIVN

    mov r1, #3

    str r1, [r0]


    mrc p15, 0, r1, c1, c0, 0

    orr r1, r1, #0xc0000000

    mcr p15, 0, r1, c1, c0, 0



    mov r1, #CLK_CTL_BASE

    mov r2, #MDIV_200

    add r2, r2,#PSDIV_200

    str r2, [r1,#0x04]


#endif

#endif /* (CONFIG_S3C2400) || (CONFIG_S3C2410) || (CONFIG_S3C2440) */


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

   /*******************************************

     * we do sys-critical inits only at reboot,

     * not when booting from ram!

     ******************************************/


#ifndef CONFIG_SKIP_LOWLEVEL_INIT

    bl  cpu_init_crit  //关闭MMU和CACHE,并调用lowlevel_init.S完成SDRAM和NANDFLASH的初始化

#endif

...........

...........

...........

/*

 *************************************************************************

 *

 * CPU_init_critical registers

 *

 * setup important registers

 * setup memory timing

 *

 *************************************************************************

 */


#ifndef CONFIG_SKIP_LOWLEVEL_INIT

cpu_init_crit:

    /*

     * flush v4 I/D caches

     */

    mov r0, #0       //具体设置看下图,详细参考CP15指令:http://blog.csdn.net/gooogleman/article/details/3635238

    mcr p15, 0, r0, c7, c7, 0 //向c7写入0将使ICache与DCache 无效flush v3/v4 cache 

    mcr p15, 0, r0, c8, c7, 0  //向c8写入0将使TLB失效 flush v4 TLB 


    /*

     * disable MMU stuff and caches     //协处理器CP15的C1处理器可以设置MMU和caches,具体参考下图

     */

    mrc p15, 0, r0, c1, c0, 0  

    bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)

    bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)

    orr r0, r0, #0x00000002 @ set bit 2 (A) Align

    orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache

    mcr p15, 0, r0, c1, c0, 0


    /*

     * before relocating, we have to setup RAM timing

     * because memory timing is board-dependend, you will

     * find a lowlevel_init.S in your board directory.

     */

    mov ip, lr       //由于有两层调用,需要把lr保存到ip,以防止破坏


    bl  lowlevel_init //调用c函数,初始化FLASH和SDRAM,为代码重定向做准备


    mov lr, ip 

    mov pc, lr      //返回

#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

代码重定向基本思路:


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


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


//代码重定向部分

/***************CHECK_CODE_POSITION******************************/


    adr r0, _start      /* r0 <- current position of code   */   //检查代码是否在已经SDRAM中运行,是则设置堆栈,并跳入c代码部分

    ldr r1, _TEXT_BASE      /* test if we run from flash or RAM */  //_start为u-boot的真正运行地址,_TEXT_BASE为FLASH加载到SDRAM的地址,在config.mk中定义为0x33f80000

    cmp r0, r1          /* don't reloc during debug         */      //若相等,说明已经在SDRAM中运行,设置堆栈,并且调转到第二阶段的C函数

    beq stack_setup //若不相等,则要判断是从NORFLASF或NANDFLASH启动


/***************CHECK_CODE_POSITION******************************/


/***************CHECK_BOOT_FLASH********************************/


    ldr r1, =((4<<28)|(3<<4)|(3<<2))  /*address in 4000003c*/

    mov r0, #0     //NANDFLASH的启动原理,启动时4K SRAM,即Stepping Stone,会映射到nGCS0,0x0000 0000地址,同时它还是会被映射到0x4000 0000地址 

    str r0,[r1]    //而NORFLASH支持片上运行,并会被一直挂载到nGCS0,0x0000 0000,具体可以参照NANDFLASH启动原理


    mov r1, #0x3c   /*address in 0x3c*/ //NANDFLASH启动时,因为地址为16倍数对齐,此时0x0000 003c 和 0x4000 003c都为唯一确定的0xdeadbeef,即'Magic Mumber'

    ldr r0, [r1]    //当0x4000 003c清零,若0x0000 003c读出也是零,则u-boot代码从NANDFLASH启动,否则从NORFLASH

    cmp r0, #0

    bne relocate



    /*recover 0x4000003c */

    ldr r0, =(0xdeadbeef)     //若在NANDFLASH启动,必须保证代码和前4K拷贝到SRAM一致,否则会进入死循环

    ldr r1, =((4<<28)|(3<<4)|(3<<2))

    str r0, [r1]


/***************CHECK_BOOT_FLASH********************************/


/***************NAND_BOOT********************************/


#ifdef  CONFIG_S3C2440 //支持S3C2440的NANDFLASH

#define LENGTH_UBOOT  0x60000

#define NAND_CTL_BASE 0x4E000000


/* Offset */

#define oNFCONF 0x00

#define oNFCONT 0x04

#define oNFCMD  0x08

#define oNFSTAT 0x20


    mov  r1, #NAND_CTL_BASE //NAND Flash配置寄存器设置

    ldr  r2, =( (7<<12)|(7<<8)|(7<<4)|(0<<0) )

    str  r2, [r1, #oNFCONF]

    ldr  r2, [r1, #oNFCONF]


    ldr  r2, =( (1<<4)|(0<<1)|(1<<0) ) /* @ Active low CE Control */

    str  r2, [r1, #oNFCONT]     //NAND Flash控制寄存器设置

    ldr  r2, [r1, #oNFCONT]


    ldr  r2, =(0x6)     /*  @ RnB Clear */ //NAND Flash状态寄存器设置

    str  r2, [r1, #oNFSTAT]

    ldr  r2, [r1, #oNFSTAT]


    mov  r2, #0xff //NAND Flash命令寄存器设置

    strb r2, [r1, #oNFCMD]

    mov  r3, #0 


    nand1:

    add  r3, r3, #0x1

    cmp  r3, #0xa

    blt  nand1


nand2:

    ldr r2, [r1, #oNFSTAT]

    tst r2, #0x4

    beq nand2 

    ldr r2, [r1, #oNFCONT]

    orr r2, r2, #0x2

    str r2, [r1, #oNFCONT] 


/* get read to call C functions (for nand_read()) */

     ldr sp, DW_STACK_START

     mov fp, #0


 /* copy U-Boot to RAM */

     ldr r0, =TEXT_BASE //汇编调用c函数nand_read_ll,第一个参数存于r0搬运到内存地址

     mov r1, #0x0     //第二个参数存于r1,NANDFLASH中u-boot地址

     mov r2, #LENGTH_UBOOT /第三个参数存于r2,u-boot的总大小

     bl nand_read_ll //在nand_read.c定义,支持不同NANDFLASH芯片代码拷贝

     tst r0, #0x0 //r0是存放函数返回的参数,返回值为0则正确拷贝,否则进入死循环 

     beq ok_nand_read


bad_nand_read:

loop2:

    b loop2

ok_nand_read: //前4K代码比较,即判定Stepping Stone中4k代码和c函数搬运的代码是否一致 

    mov r0, #0 

    ldr r1, =TEXT_BASE 

    mov r2, #0x400 /* 4 bytes * 1024 = 4Kbytes */

go_next: 

    ldr r3, [r0], #4 //r3存放NANDFLASH上u-boot的代码

    ldr r4, [r1], #4 //r4为在内存中的u-boot代码 

    teq r3, r4

    bne notmatch //不一致则进入死循环

    subs r2, r2, #4

    beq stack_setup

    bne go_next


notmatch:

loop3:

    b loop3

#endif


#ifdef CONFIG_S3C2410

/* Offset */

#define oNFCONF 0x00

#define oNFCMD  0x04

#define oNFSTAT 0x10



    mov  r1, #NAND_CTL_BASE

    ldr  r2, =0xf830

    str  r2, [r1, #oNFCONF]

    ldr  r2, [r1, #oNFCONF]

    bic  r2,  r2, #0x800     /* enable chip  */

    str  r2, [r1, #oNFCONF]

    mov  r2, #0xff        /*  @ RESET command  +  strb  r2, [r1, #oNFCMD] */

    strb r2, [r1, #oNFCMD]

    mov  r3, #0 



nand1:

    add  r3, r3, #0x1

    cmp  r3, #0xa

    blt  nand1



nand2:

    ldr  r2, [r1, #oNFSTAT] /* @ wait ready */

    tst  r2, #0x1

    beq  nand2



    ldr  r2, [r1, #oNFCONF]

    orr  r2,  r2, #0x800   /*@ disable chip */

    str  r2, [r1, #oNFCONF]



    /*    @ get read to call C functions (for nand_read()) */

    ldr  sp, DW_STACK_START    /* @ setup stack pointer */

    mov  fp, #0                /* @ no previous frame, so fp=0 */



    /*  @ copy U-Boot to RAM */

    ldr r0, =TEXT_BASE

    mov r1, #0x0

    mov r2, #LENGTH_UBOOT

    bl nand_read_ll

    tst r0, #0x0

    beq ok_nand_read

bad_nand_read:

loop2:

    b  loop2  /*@ infinite loop */


ok_nand_read:

/*     @ verify */

    mov r0, #0 

    ldr r1, =TEXT_BASE

    mov r2, #0x400 /* @ 4 bytes * 1024 = 4K-bytes */



go_next:

    ldr  r3, [r0], #4

    ldr  r4, [r1], #4

    teq  r3, r4

    bne  notmatch

    subs r2, r2, #4

    beq  stack_setup

    bne  go_next



notmatch:

loop3:

    b    loop3  /*@ infinite loop */

#endif


/***************** NAND_BOOT ************************************************/


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

 /* Set up the stack */

stack_setup:

    ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */

    sub r0, r0, #CONFIG_SYS_MALLOC_LEN  /* malloc area              */

    sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /* bdinfo                 */

#ifdef CONFIG_USE_IRQ

    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)

#endif

    sub sp, r0, #12     /* leave 3 words for abort-stack    */


clear_bss: //将未初始化.bss段初始化0

    ldr r0, _bss_start      /* find start of bss segment        */

    ldr r1, _bss_end        /* stop here                        */

    mov r2, #0x00000000     /* clear                            */


clbss_l:

    str r2, [r0]        /* clear loop...                    */

    add r0, r0, #4

    cmp r0, r1

    ble clbss_l


    ldr pc, _start_armboot  //跳到第二阶段c函数,进一步初始化板子硬件


_start_armboot: .word start_armboot


#define STACK_BASE 0x33f00000    //为nand_read_ll函数调用设置堆栈

#define STACK_SIZE 0x10000


  .align 2

DW_STACK_START: .word  STACK_BASE+STACK_SIZE-4


4,异常向量处理代码

/*************************************************************************

 *

 * Interrupt handling

 *

 *************************************************************************

 */

......


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章