U-boot-2014.04移植到MINI2440(4) 第一启动阶段start.S等详细分析

发布者:532829319hmk最新更新时间:2022-06-21 来源: eefocus关键字:U-boot  移植  MINI2440  start 手机看文章 扫描二维码
随时随地手机看文章

u-boot的启动阶段分为两个,第一部分主要为start.S文件,帖子尽可能的分析了每一行代码的意思,查看了很多手册,分析的目的也是为了学习吧,写博客也是想给自己的学习留下点东西,这些东西网上其实很多,但是感觉看别人写的和字自己分析写一遍,差别好大。转载请注明出处,下面进入正题。


第11行:


#include //由kbuild自动生成,且不管


#include   //include下包含其他通用头文件的头文件


#include     //很多体系架构下都有这个各自体系的配置头文件


一.start_code及CPSR分析


第24行:


.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


这里从_start开始,第一句,b   start_code意义是跳转到start_code这部分。我们切过去看。


在第79行:


start_code:


      /*


       * set the cpu to SVC32 mode


       */


      mrs r0, cpsr


      bic  r0, r0, #0x1f


      orr   r0, r0, #0xd3


      msr cpsr, r0


这部分是将cpu设置成SVC32模式,我们知道arm有7种工作模式,这里设置为等级最高,一般我们是工作在usr模式。


mrs       r0,cpsr


将状态寄存器cpsr的内容送到通用寄存器r0中


bic r0, r0, #0x1f


这句话起始就是对r0的低5位清零。bic指令的意思对 Rn 中的值和 Operand2 值的反码按位进行逻辑“与”运算。


orr  r0, r0,#0xd3


这里是设置r0里面的低5位为10011,即svc模式,同时关闭irq和fiq。


msr       cpsr,r0


将r0的值写回给cpsr。


这里我们看一下s3c2440的datasheet:

这里给出了CPSR寄存器各个位的定义,我们这里着重关心低八位,0到5位设置工作模式,下面的图里面给出了各个模式对应的位应该设置为何值。5,6,7三位分别对应状态位,fiq和irq,上面给r0赋值0xd3就是11010011,对应进去一目了然。

二.关中断,时钟设置分析


下面第102行:


#ifdef CONFIG_S3C24X0


      /* turn offthe watchdog */


 


# if defined(CONFIG_S3C2400)


#  define pWTCON       0x15300000


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


#  defineCLKDIVN     0x14800014 /* clock divisor register */


#else


#  define pWTCON       0x53000000


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


#  defineINTSUBMSK       0x4A00001C


#  defineCLKDIVN     0x4C000014       /* clock divisor register */


# endif


这段的功能是定义看门狗,中断和子中断以及分频器的寄存器地址,此处我们的是s3c2440,可以看看数据手册,以INTMSK为例。·

INTMSK的基地址果然是0x4A000008.


    下面,第116行:


      ldr   r0, =pWTCON


      mov       r1, #0x0


      str   r1, [r0]


ldr这里使用了伪指令,是将pWTCON的地址写到r0里面。mov讲0赋给r1,最后str是将r1的值放到r0代表的地址的内存里面去。这段话其实就是对pWTCON清零来关闭看门狗。


第123行:


mov      r1,#0xffffffff


ldr  r0, =INTMSK


str  r1, [r0]


参考上一段话,因为中断控制寄存器都是置一清零的,这里是关闭所有的中断。


第133行:


#if defined(CONFIG_S3C2440)


      ldr   r1, =0x7fff


      ldr   r0, =INTSUBMSK


      str   r1, [r0]


#endif


这部分是屏蔽子中断,2440的子中断控制寄存器只有低15位有效,别的位保留,所以这里为0x7fff。


第139行:


#if defined(CONFIG_S3C2440)


#define MPLLCON 0x4c000004


#define UPLLCON 0x4c000008


#define CAMDIVN 0x4c000018


      ldrr0,=CAMDIVN


      mov r1,#0


      str r1,[r0]


      ldrr0,=CLKDIVN


      movr1,#0x05


      str r1,[r0]


      mrcp15,0,r0,c1,c0,0


      orrr1,r1,#0xc0000000


      mcrp15,0,r0,c1,c0,0


      ldrr0,=UPLLCON


      ldrr1,=0x38022


      str r1,[r0]


      nop


      nop


      nop


      nop


      nop  


      nop


      nop


      ldrr0,=MPLLCON


      ldrr1,=0x5c011


      str r1,[r0]


#else


上面这段主要做了三个时钟的设置,第一个关闭了为摄像头的分频器,第二个设置USB的时钟频率为48M,第三设置系统的时钟频率为400MHZ.具体的为什么,我们来看看。


CLKDIVN寄存器参看数据手册如下:

mov r1,#0x05也就是0101,由于我们设置了CAMDIV均为0,因此对应的PCLK:HCLK:FCLK=1:2:8,分频系数已经设置好。


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


orr r1,r1,#0xc0000000


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


此处为将协处理器p15的寄存器中的数据传送到ARM处理器的寄存器r0中,其中1是协处理器操作码1,0是协处理器操作码2,c1存放第一个操作数的协处理器寄存器,c0存放第二个操作数的协处理器寄存器。最终目的是将arm从快速总线模式转换为异步总线模式。


ldr r0,=UPLLCON


ldr r1,=0x38022


str r1,[r0]


这里设置USB的时钟频率为48M,具体的参照手册。


ldr r0,=MPLLCON


ldr r1,=0x5c011


str r1,[r0]


这里最终将系统时钟频率设置为400M,MPLLCON是控制FCLK和Fin之间的关系,查看数据手册如下:

这里给出了m,p,s三个参数是如何来的,我们再看

这里设置为0x5c011也就是0101 1100 0000 0001 0001,根据数据位,可以计算得到s=1,p=1+2=3,m=172+8=100,又因为我们的晶振为12MHZ,所以mpll=fclk=(2*100*12)/(3*2)=400MHZ。


三.cpu_init_crit及MMU CP15协处理器配置分析


下面,第186行:


#ifndef CONFIG_SKIP_LOWLEVEL_INIT


      bl    cpu_init_crit


#endif


如果没有定义CONFIG_SKIP_LOWLEVEL_INIT,那就跳转到cpu_init_crit这个函数,这里使用了bl,也就是下一条指令的执行地址,存放在lr链接寄存器里面,说明子函数运行结束之后,使用mov pc lr,程序还是要回到这里继续执行,切过去,第212行:


       /*


        *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


首先来看看mcr和mrc这两个指令吧,查到如下:


MRC {条件}协处理器编码,协处理器操作码1,目的寄存器,源寄存器1,源寄存器2,{协处理器操作码2} 

  MCR {条件}协处理器编码,协处理器操作码1,源寄存器,目的寄存器1,目的寄存器2,{协处理器操作码2} 


arm的cp15协处理器时只能够被mcr和mrc两个指令操作的,这里我们查看datasheet:

这里由于是cp15,所以8到11位是1111,各个位对应的意思也可以去datesheet查到。这里不赘述了。


       mcr p15,0, r0, c7, c7, 0    /* flush v3/v4 cache*/


       mcr p15,0, r0, c8, c7, 0    /* flush v4 TLB */


这里先对r0清零以后,再对c7和c8进行清零,而c7和c8分别对应什么呢,可以继续看下手册里面的寄存器编号:

image.png

    可以看到表格里面c7,c8在MMU中的作用是告诉缓存和写缓存控制以及TLB控制,其实c7和c8是两个只写寄存器,这里就是清除cache和写缓存,以及清除TLB就是这么做的。


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


    这段呢,其实就很明了了,首先将c0和c1的值读给r0,然后分别清除对应的位,分别是0到2位,7位,8,9,13位,这些位是干嘛的呢?为什么要清楚这些位。查找datasheet看到c1,下面有两个表格,清除的位和下面用orr指令设置的位我都标注出来了。


image.png

image.png

    可以看到表格里面c7,c8在MMU中的作用是告诉缓存和写缓存控制以及TLB控制,其实c7和c8是两个只写寄存器,这里就是清除cache和写缓存,以及清除TLB就是这么做的。


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


    这段呢,其实就很明了了,首先将c0和c1的值读给r0,然后分别清除对应的位,分别是0到2位,7位,8,9,13位,这些位是干嘛的呢?为什么要清楚这些位。查找datasheet看到c1,下面有两个表格,清除的位和下面用orr指令设置的位我都标注出来了。

image.png

image.png

总结一下这一步具体做了哪些事情,首先禁止MMU,禁止对齐检查,禁止整个cache,选择为小尾数,取消系统保护,取消rom保护,禁止指令cache,选择低端的异常中断向量。然后再设置对齐检查,因为我们的ALIGN是四字节对齐的,然后再使能指令cache。看来简单的禁止MMU不是那么简单的。。。


 


四.lowlevel_init.S分析


第235行:


      mov       ip, lr


 


      bl    lowlevel_init


首先,ip是一个内部调用暂时寄存器,我们现在是在cpu_init_crit函数里面,而一开始从start_code跳转到cpu_init_crit里面的时候,lr保存的是从cpu_init_crit用于返回到start_code的地址,这里再跳转到lowlevel_init的时候我们需要将lr的值暂存到ip里面,待会儿从lowlevel_init回来的时候,再用ip把保存的地址还给lr,这样我们再进行跳转就回到start_code里面去了。说白了,就是函数的嵌套调用方法。


下面我们切换到lowlevel_init中去,这个文件在board/mini2440/mini2440下,打开。


第114行:


lowlevel_init:


      /* memorycontrol configuration */


      /* make r0relative the current location so that it */


      /* readsSMRDATA out of FLASH rather than memory ! */


      ldr     r0, =SMRDATA


      ldr   r1, =CONFIG_SYS_TEXT_BASE


      sub  r0, r0, r1


三段注释部分说的是这部分是内存控制的配置,请使r0相对当前位置从FLASH读出SMRDATA,而不是从存储器里面。(暂时不明白啥意思)


    ldr    r0, =SMRDATA


这里是一个伪指令,SMRDATA使用了后面的在low文件最后的.ltorg伪指令,将其作为了一个数据缓冲池,而SMRDATA就是数据缓冲池的名称。见文件最后第132行开始:


.ltorg


/* the literal pools origin */


 


SMRDATA:


    .word(0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))


    .word((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))


    .word((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))


    .word((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))


    .word((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))


    .word((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))


    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))


    .word((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))


    .word((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))


    .word((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)

[1] [2]
关键字:U-boot  移植  MINI2440  start 引用地址:U-boot-2014.04移植到MINI2440(4) 第一启动阶段start.S等详细分析

上一篇:U-boot-2014.04移植到MINI2440(1) 初步探索移植
下一篇:U-boot-2014.04移植到MINI2440(2) Readme翻译分析

推荐阅读最新更新时间:2024-10-24 05:26

U-boot-2014.04移植MINI2440(4) 第一启动阶段start.S等详细分析
u-boot的启动阶段分为两个,第一部分主要为start.S文件,帖子尽可能的分析了每一行代码的意思,查看了很多手册,分析的目的也是为了学习吧,写博客也是想给自己的学习留下点东西,这些东西网上其实很多,但是感觉看别人写的和字自己分析写一遍,差别好大。转载请注明出处,下面进入正题。 第11行: #include asm-offsets.h //由kbuild自动生成,且不管 #include common.h //include下包含其他通用头文件的头文件 #include config.h //很多体系架构下都有这个各自体系的配置头文件 一.start_code及CPSR分析 第24行: .glo
[单片机]
U-boot-2014.04<font color='red'>移植</font>到<font color='red'>MINI2440</font>(4) <font color='red'>第一</font><font color='red'>启动</font><font color='red'>阶段</font><font color='red'>start</font>.<font color='red'>S</font>等详细分析
U-boot 在 mini2440-S3C2440 上的移植(3)-第一阶段:探索启动代码
1.本文以mini2440开发板为例: u-boot属于两阶段的Bootloader,第一阶段文件为CPU/arm920t/start.S和board/mini2440/lowlevel_init.S,前者是平台相关的,后者是开发板相关的; U-boot第一阶段代码: 1.硬件设备初始化 该部分完成:将CPU的工作模式设置为管理模式;关闭WATCHDOG; 设置FCLK;HCLK;PCLK的比例,关闭MMU;CACHE 参考代码:cpu/arm920t/start.S 2.为加载Bootloader的第二阶段代码准备RAM空间;所谓准备RAM空间,就是初始化内存芯片,参考代码start.S中调用的lowlevel_init.S函数
[单片机]
TQ2440 学习笔记—— 30、移植U-BootU-Boot启动过程第一阶段源码分析】
使用u-boot 从NOR Flash 启动,前面说过u-boot 属于两个阶段的Bootloader ,第一阶段的文件为cpu/arm920t/start.S 和 board/EmbedSky/lowlevel_init.S, 前者是平台相关的,后者是开发板相关的。 一、u-boot 第一阶段代码分析 (1)硬件设备初始化 依次完成如下设置:将CPU 的工作模式设为管理模式(svc),关闭WATCHDOG ,设置FCLK、HCLK、PCLK 的比例(即设置CLKDIVN寄存器),关闭MMU、CACHE。部分代码如下: (2)为加载Bootloader 的第二阶段代码准备RAM 空间 所谓准备RAM 空间,就
[单片机]
TQ2440 学习笔记—— 30、<font color='red'>移植</font><font color='red'>U-Boot</font>【<font color='red'>U-Boot</font> 的<font color='red'>启动</font>过程<font color='red'>第一</font><font color='red'>阶段</font>源码分析】
mini2440 u-boot linux 内核启动,移植较新(Linux3.19)内核至mini2440开发板(一)
s3c24xx-nand s3c2440-nand: Tacls=1, 9ns Twrph0=3 29ns, Twrph1=2 19ns s3c24xx-nand s3c2440-nand: NAND soft ECC nand: device found, Manufacturer ID: 0xec, Chip ID: 0xda nand: Samsung NAND 256MiB 3,3V 8-bit nand: 256 MiB, SLC, erase size: 128 KiB, page size: 2048, OOB size: 64 Creating 5 MTD partitions on nand : 0x000000
[单片机]
TQ2440 学习笔记—— 31、移植U-BootU-Boot启动过程第二阶段源码分析】
二、U-Boot第二阶段代码分析 U-Boot 第二阶段流程图 移植U-Boot 的主要工作在于对硬件的初始化、驱动,所以下面的重点放在硬件的操作上。 (1)初始化本阶段要使用到的硬件设备 最主要的是设置系统时钟、初始化串口,只要这两个设置好了就可以从串口看到打印信息。 board_init 函数设置MPLL、改变系统时钟,它是开发板相关的函数,在board/EmbedSky/EmbedSky.c 中实现。 board_init 函数还保存了机器类型ID,这将在调用内核时传给内核代码如下: 串口的初始化函数主要是 serial_init,它设置 UART 控制器,是CPU 相关的函数,在cpuarm92
[单片机]
TQ2440 学习笔记—— 31、<font color='red'>移植</font><font color='red'>U-Boot</font>【<font color='red'>U-Boot</font> 的<font color='red'>启动</font>过程第二<font color='red'>阶段</font>源码分析】
U-boot-2014.04移植MINI2440(11) 第二启动阶段分析
回顾一下u-boot启动其一阶段做了哪些事: 第一:设置CPU为SVC模式 第二:关闭看门狗 第三:关中断和子中断 第四:设置时钟 第五:MMU关闭,清除cache和TLB,使能地址对齐检查等 第六:初始化SDRAM 在我前面的分析里,第一阶段的最后,通过bl _main,跳到了arch/arm/lib/crt0.S里面去了,从这里开始时第二阶段的入口,下面从这里开始分析。 文件:crt0.S 先看看该文件对_main的描述,在第18行,有一个_main execution sequence is:下面有五步,其实就是对_main的执行流程的一个介绍,我翻译一下: 1
[单片机]
u-boot 第一阶段启动流程
一、u-boot启动流程 第一步: S5pc100中IROM中的代码 自动将NAND FLASH的前16KB拷贝到SRAM的0x34000 ,然后bootload的第一部分开始执行,初始化DRAM。 第二步: bootload将nandflash中所有的bootload拷贝到DRAM中。 第三步: 跳转到DRAM中开始执行bootload的第二部分代码。 二、第一阶段启动流程 裁剪之后的start.S文件如下: .globl _start _start: b reset /***********************************设
[单片机]
<font color='red'>u-boot</font> <font color='red'>第一</font><font color='red'>阶段</font><font color='red'>启动</font>流程
移植u-boot 1.1.6到TQ2440开发板-第一阶段
最近买了一个TQ2440开发板,奈何天嵌只给出了编译好的文件,没有给源码,小弟从头开始移植Uboot 移植u-boot 1.1.6到TQ2440开发板-第一阶段 主要修改、配置源代码、编译源代码 TQ2440开发板信息: CPU:S3C2440 ARM核:arm920t SDRAM:64M Nor Flash:2M Nand Flash:64M 网卡:DM9000 第一步:下载 uboot 1 . 1 . 6源码 之前都是从CSDN上下载,发现下载的都不是真正的官方发布的源码,给大家提供一个官网 ftp://ftp.denx.de/pub/u-boot 格式为u-boot-1.1.6.tar.bz
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved