u-boot移植总结(一)start.S分析
2014-05-29 21:47
344 查看
本次移植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,异常中断向量表,复位后异常向量处理
2, 跳转到代码实际执行处(设置管理模式=>关闭看门狗=>关闭所有中断=>设置时钟分频)
3,关闭MMU和CACHE,并调用lowlevel_init.S完成SDRAM和NANDFLASH的初始化,为代码的重定向做准备
代码重定向基本思路:
1.内存运行与否,是则设置堆栈,跳入c函数阶段
2.若不在内存运行,判断是在norflash还在nandflash运行
3,设置堆栈,并且跳入第二阶段的C代码
4,异常向量处理代码
详细可参考http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/html/uboot_starts_analysis.html
其中最重要的就是在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中有定义</span> _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 </span> 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<span style="white-space:pre"> //屏蔽所有的中断源,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 <span style="color:#ff0000;"> //协处理器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 ************************************************/</span>
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 </span>
4,异常向量处理代码
/************************************************************************* * * Interrupt handling * ************************************************************************* */ ......
详细可参考http://www.crifan.com/files/doc/docbook/uboot_starts_analysis/release/html/uboot_starts_analysis.html
相关文章推荐
- u-boot移植总结(一)start.S分析
- u-boot 在s3c44b0移植总结
- 移植u-boot支持ubi遇到的问题总结
- u-boot移植总结(四)u-boot-2010.09框架分析
- u-boot移植总结(三)(转)S3C2440对Nand Flash操作和电路原理(基于K9F2G08U0A)
- u-boot 在s3c44b0移植总结
- u-boot-2010.3移植到Tiny6410问题总结
- fl2440 uboot 移植总结
- 嵌入式S5PV210 硬件DIY uboot ,kernel ,android移植QQ群(27100460)群委员会2013年年终总结
- U-Boot移植总结
- u-boot 移植 总结
- u-boot 在s3c44b0移植总结
- U-Boot移植(7)总结U-Boot工程的总体结构
- 韦东山老师讲解移植uboot-2012.04.01的笔记总结
- mini6410基于linux2.6.36内核通过NFS启动根文件系统总结(二uboot移植)
- 移植u-boot支持ubi遇到的问题总结
- U-Boot移植(6)总结U-Boot工程的总体结构
- U-Boot移植(18)网卡dm9000aep移植总结
- u-boot移植总结(二)LED点灯调试 和 u-boot加载地址
- 向UBOOT中移植代码总结