免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1845 | 回复: 0
打印 上一主题 下一主题

s3c2410 uboot启动分析 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-03 18:41 |只看该作者 |倒序浏览

[color="#000066"]本文以流行的Samsung公司的S3C2410,openmoko平台和u-boot-1.3.2(2008.5 发布)为例,介绍如何在ZIX嵌入式开发环境下探索u-boot启动过程。
虽然u-boot已经广泛应用,由于其相对的复杂性使用户在了解其内部机理和进行u-boot的移植工作时还是会碰到困难。u-boot已有一些分析文档,但多数和真正的代码不能同步或者版本老旧,难以将概念和现实的代码匹配——即[color="#ab0000"]硬件板上跑的代码在文档资料中却看不到,更无法紧密的跟踪。本文涉及的代码基于在s3c2410硬件运行的成熟u-boot-1.3.2代码,版本较新,提供的特性非常丰富,而且在
forum.linuxbj.com
可以
自由浏览

下载
。此u-boot代表了业界的较高水平,可以直接构建新版的嵌入式产品设计,有较高的应用价值。
u-boot总的启动流程如下
->reset
-> 设置CPU模式
-> 关闭看门狗/中断
-> 设置处理器时钟/片上总线
-> 初始化调试串口
-> MMU/外部总线/SDRAM等初始化
-> rom代码/数据搬移到ram
-> 初始化函数调用栈
-> 初始化外围设备/参数
-> 启动完毕,进入main_loop循环
嵌入式系统离不开bootloader初始化硬件以及引导操作系统。
现在,专用的嵌入式板子运行嵌入式Linux系统已经变得非常流行,u-boot是一种非常适合此类系统的bootloader。
u-boot主要提供以下功能:
  • 设置目标板硬件参数并初始化;
  • 为操作系统传递必要信息;
  • 执行交互式的底层操作;
  • 智能化装载操作系统;
  • 引导和运行的固件程序;
  • 支持大容量存储和USB接口


利用ZIX开发环境,能够通过比较直观的方式观察u-boot内部,而且可以将代码调试和分析同时进行,是一种了解、移植u-boot的强大工具。
使用arm工具链编译u-boot源代码,得到可以烧录的u-boot.bin文件。
在ZIX开发环境里,可以将u-boot.bin载入s3c2410板运行,并利用gdb调试。
gdb能通过JTAG接口访问硬件,也可以通过TCP/IP访问虚拟硬件。  建立好调试连接,即可通过gdb操纵u-boot启动过程,下面可以跟随代码的执行顺序,了解从上点开始,究竟哪些操作被执行。
s3c2410复位之后,pc指针会指向0x0地址。在u-boot代码中,该0x0地址是一个向量表,
第一条指令跳转branch到复位代码start_code。 位于cpu/arm920t/start.S汇编语言文件
第53行
:
.globl _start  _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
复位指令跳转之后来到
第154行
,开始执行arm920t处理器的基本初始化。
首先修改当前程序状态寄存器CPSR,使处理器进入Supervisor|32 bit ARM模式,
并关闭ARM9TDMI中断和快速中断,这是通过设置CPSR相应掩码实现的:
start_code:
    /*
     * set the cpu to SVC32 mode
     */  
    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0  
紧接着,将S3C2410特有的WTCON寄存器清零,此举仅为关闭看门狗,代码位置是
234行

    ldr r0, =pWTCON
    mov r1, #0x0
    str r1, [r0]
然后
在241行
,将S3C2410中断控制器INTMSK寄存器置为全1,
INTSUBMSK置为0x7ff,禁止全部中断源。
S3C2410手册
358页起对此有详细描述:
    mov r1, #0xffffffff  
    ldr r0, =INTMSK
    str r1, [r0]  
# if defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440) || defined(CONFIG_S3C2442) || \  
  defined(CONFIG_S3C2443)  
    ldr r1, =INTSUBMSK_val  
    ldr r0, =INTSUBMSK  
    str r1, [r0]  
# endif  
接下来
在259行
,访问arm920t控制寄存器CP15,并置位最高两位[31,30]。
此两位置为0b11后,处理器时钟被设置为异步模式,允许处理器异步访问总线:
    mrc p15, 0, r1, c1, c0, 0
    orr r1, r1, #0xc0000000
    mcr p15, 0, r1, c1, c0, 0
至此arm920t相关的配置完成,后面开始设定S3C2410时钟合成参数。
通过设置UPLL,MPLL和CLKDIVN三个寄存器(在
S3C2410手册
237页起讲述),
得到需要的处理器工作频率,分别
在308行

    ldr r0, =UPLLCON  
    ldr r1, =UPLLCON_val
    str r1, [r0]
321行

    ldr r1, =MPLLCON_val  
    str r1, [r0, #-4]    /* MPLLCON */
    /* FCLK:HCLK:PCLK = 1:2:4 */
    ldr r0, =CLKDIVN
    mov r1, #CLKDIVN_val
    str r1, [r0]
S3C2410的UART0得到初始化,以便于尽早通过UART0打印信息。
此段代码从
332行
开始,其中涉及到的寄存器读者可参考
S3C2410手册
293页起:
    /* enable uart */
    ldr r0, =0x4c00000c /* clkcon */
    ldr r1, =0x7fff0 /* all clocks on */
    str r1, [r0]
    /* gpio UART0 init */
    ldr r0, =0x56000070
    mov r1, #0xaa
    str r1, [r0]
    /* init uart */
    ldr r0, =0x50000000
    mov r1, #0x03
    str r1, [r0]
    ldr r1, =0x245
    str r1, [r0, #0x04]
    mov r1, #0x01
    str r1, [r0, #0x08]
    mov r1, #0x00
    str r1, [r0, #0x0c]
    mov r1, #0x1a
    str r1, [r0, #0x28]
完成UART0设置之后,根据不同的编译时选项和运行时参数,代码会在
360行
进入相应的分支,分别是
  • 从nand启动,代码执行lowlevel_init,主要是清除cpu cache,以及关闭mmu和i-cache,
        并且根据板极硬件配置初始化外部存储器总线和GPIO,最后把代码从nand flash中拷贝到ram中并继续执行。
  • 从nor启动,与第1种情况相比,仅仅把代码拷贝部分简化,将DATA段从flash中拷贝到ram中,其余相同
  • 从ram启动,因为u-boot已经处于配置好的ram中,
        所以会跳过所有cache,mmu,sdram,nand和nor相关代码,跳转到done_relocate执行
    下面以最复杂的nand启动情况为例分析。首先会跳转到
    572行
    执行cpu_init_crit,
    通过操作CP15完成flush处理器arm920t的cache和tlb,并关闭mmu和i-cache:
    cpu_init_crit:
        /*
         * flush v4 I/D caches
         */  
        mov r0, #0
        mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
        mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */   
        /*
         * disable MMU stuff and 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
    然后跳转到board/neo1973/common/lowlevel_init.S文件的
    139行
    执行,
    进行总线数据宽度、时序、SDRAM控制、GPIO等配置,配置完毕后会返回start.S继续执行。
    因为该代码是与板相关,故放在board目录里面。由于代码较多,只粘贴开始部分:
        /* memory control configuration */  
        /* make r0 relative the current location so that it */  
        /* reads SMRDATA out of FLASH rather than memory ! */
        adr r0, SMRDATA  
        ldr r1, =BWSCON /* Bus Width Status Controller */
        add r2, r0, #13*4
    完成板级设置后,在cpu/arm920t/start.S的
    373行
    判断代码自身的执行位置。如果从stepping stone内执行,
    并且u-boot配置为nand boot模式,则跳转到nand_load拷贝代码:
        ldr r1, =BWSCON /* Z = CPU booted from NAND */
        ldr r1, [r1]
        tst r1, #6 /* BWSCON[2:1] = OM[1:0] */
        teqeq r0, #0 /* Z &= running at address 0 */
        beq nand_load

    417行
    是nand_load代码,首先会跳转到
    614行
    执行may_resume
    以检测系统是从待机模式唤醒还是上电启动。如果唤醒,则会根据之前保存的现场进行相应处理,
    本文不做更多叙述;如果是启动,则会返回nand_load继续执行。在nand_load里初始化s3c2410的nand controller,
    涉及存储器映射和寄存器NFCONF等,参见
    S3C2410手册
    215页起。同样,仅粘贴开始部分的代码:
        mov r1, #S3C2410_NAND_BASE
        ldr r2, =0xf842 @ initial value enable tacls=3,rph0=6,rph1=0
        str r2, [r1, #oNFCONF]
        ldr r2, [r1, #oNFCONF]
        bic r2, r2, #0x800 @ enable chip

    451行
    继续根据配置设定栈指针,为后面调用C函数执行拷贝作准备:
        ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
        sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
        sub r0, r0, #CFG_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 */
    然后在
    460行
    ,将SDRAM中的目标地址存入r0,0x0地址存入r1,u-boot长度存入r2,
    跳入cpu/arm920t/s3c24x0/nand_read.c文件
    第154行
    执行nand_read_ll函数,该函数接受前面3个寄存器中的值作为参数,并将返回值放回r0:
        ldr r0, _TEXT_BASE
        mov r1, #0x0
        mov r2, #CFG_UBOOT_SIZE
        bl nand_read_ll

    nand_read_ll函数中实现了nand
    flash访问代码,并且支持自动跳过坏块的特性,函数循环执行nand页面读取并存入SDRAM,直到u-boot全部拷贝完,并返回0,该C代码留给
    读者自己阅读。nand_read_ll返回0后,会跳转到ok_nand_read,并
    482行
    对拷贝的头4K字节进行校验:
        @ verify
        mov r0, #0
        @ldr r1, =0x33f00000
        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 done_nand_read
        bne go_next
    校验通过后代码
    506行
    ,在地址为_booted_from_nand的SDRAM位置保存1,以便告诉上层软件本次启动是从nand引导:
    done_nand_read:
        ldr r0, _booted_from_nand
        mov r1, #1
        strb r1, [r0]
    然后在
    518行
    ,将中断向量表拷贝到0x0:
        mov r0, #0
        ldr r1, _TEXT_BASE
        mov r2, #0x40
    irqvec_cpy_next:
        ldr r3, [r1], #4
        str r3, [r0], #4
        subs r2, r2, #4
        bne irqvec_cpy_next

    532行
    ,设置栈指针:
        ldr r0, _TEXT_BASE    /* upper 128 KiB: relocated uboot */
        sub r0, r0, #CFG_MALLOC_LEN    /* malloc area */
        sub r0, r0, #CFG_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 */

    541行
    ,清除bss段并跳转到真正的C函数start_armboot,进入更高级的硬件初始化代码,[color="#8b0000"]汇编初始化部分也全部完成使命
        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
    start_armboot函数位于lib_arm/board.c文件
    第277行

    首先初始化globel_data类型的变量gd。该变量是一个结构,其成员大多是板子的一些基本设置,如序列号、ip地址、mac地址等(欲知结构的原
    型可参考include/asm-arm/globel_data.h和include/asm-arm/u-boot.h):
             gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
             /* compiler optimization barrier needed for GCC >= 3.4 */
             __asm__ __volatile__("": : :"memory");
             memset ((void*)gd, 0, sizeof (gd_t));
             gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
             memset (gd->bd, 0, sizeof (bd_t));
    然后在一个for循环中从init_sequence地址开始,逐个调用初始化C函数至NULL为止。这些routine函数按调用顺序分别是
  • cpu_init() ——在common/main.c文件,执行初始化中断栈操作
  • board_init() ——在board/neo1973/gta01/gta01.c文件中,执行板级初始化,主要是更新GPIO和PLL设置
  • interrupt_init() ——在/cpu/arm920t/s3c24x0/interrupts.c文件中,执行时钟中断初始化
  • env_init() ——在common/env_nand.c文件中,设置缺省环境变量
  • init_baudrate() ——在lib_arm/board.c文件中,将环境变量中的baudrate存入bd_info结构bd
  • serial_init() ——在common/serial.c文件中,调用驱动中真正的init()初始化串口
  • console_init_f() ——在common/console.c文件中,更新global_data结构gd的have_console标记为1
  • display_banner() ——在lib_arm/board.c文件中,打印u-boot banner,输出版本、运行地址等信息。比如在控制台看到的
  • init_func_i2c() ——在lib_arm/board.c文件中,初始化i2c总线
  • dram_init() ——在board/neo1973/gta01/gta01.c文件中,填充bd->bi_dram[0]的start和size成员,用来描述u-boot可用的ram
  • display_dram_config() ——在board/neo1973/gta01/gta01.c文件中,打印当前ram配置。在控制台能够看到相应的 DRAM:  128 MB
    利用gdb可以清晰的看到调用过程:
             for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
                      if ((*init_fnc_ptr)() != 0) {
                               hang ();
                      }
             }
    接着是一些可选外设的初始化,如显示屏、nor、nand、dataflash、网卡等,此过程执行后[color="#8b0000"]全部初始化工作完成。下面仅粘贴nor代码:
    #ifndef CFG_NO_FLASH
             /* configure available FLASH banks */
             size = flash_init ();
             display_flash_config (size);
    #endif /* CFG_NO_FLASH */
    之后在
    457行
    进入无限循环,调用common/main.c文件的
    278行
    main_loop()函数,u-boot完成启动过程。main_loop提供一个交互式命令行,可通过串口或usb控制台操作,也可以进一步引导操作系统:
             for (;;) {
                      main_loop ();
             }
    原文地址:http://forum.linuxbj.com/node/2
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/101219/showart_2110521.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP