Linux驱动开发 uboot启动的第一阶段

第一部分(放在start.s中,汇编)

uboot第一阶段主要做了:

1.定义入口,2.设置异常向量,3.设置CPU为SVC模式,4.初始化内存控制器(MMU),5.跳转到lowlevel_init函数,6.初始化堆栈。

1.定义入口

(1)在uboot中因为有汇编阶段参与,因此不能直接找main.c。

不简单的头文件包含

1)#include 。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。(详见mkconfig脚本)。这个文件的内容其实是包含了一个头文件:#include ".

因此之后在分析start.S文件时,主要要考虑的就是x210_sd.h文件

2)#include 。include/version.h中包含了include/version_autogenerated.h,这个头文件就是配置过程中自动生成的。里面就一行内容:#define U_BOOT_VERSION “U-Boot 1.3.4”。在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的

2.设置异常向量

(1)异常向量表是硬件决定的,软件只是参照硬件的设计来实现它。
(2)异常向量表中每种异常都应该被处理,否则真遇到了这种异常就跑飞了。但是我们在uboot中并未非常细致的处理各种异常。
(3)复位异常处的代码是:b reset,因此在CPU复位后真正去执行的有效代码是reset处的代码,因此reset符号处才是真正的有意义的代码开始的地方。

异常:当硬件发生故障的时候CPU会强制PC指针指向对应的异常入口执行代码(异常入口一般为异常处理函数)

ARM处理器有七种异常:分别是复位,未定义指令异常,软件中断异常,预取指异常,数据中止,普通中断异常,快速中断异常

3.设置CPU为SVC模式(设置CPU速度、时钟频率和中断控制寄存器)

(1)msr cpsr_c, #0xd3 将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式。
(2)其实ARM CPU在复位时默认就会进入SVC模式,但是这里还是使用软件将其置为SVC模式。整个uboot工作时CPU一直处于SVC模式。

4.初始化内存控制器(MMU)

(1)什么是虚拟地址物理地址
     1)物理地址是CPU设计时指定的,物理地址是硬件编码的,是设计生产时确定好的,一旦确定了就不能改了,物理地址是无法通过编程修改的,是多少就是多少,只能通过查询数据手册获得并操作。
     2)虚拟地址意思就是在我们软件操作和硬件被操作之间增加一个层次,叫做虚拟地址映射层。有了虚拟地址映射后,软件操作只需要给虚拟地址,硬件操作还是用原来的物理地址,映射层建立一个虚拟地址到物理地址的映射表。当我们软件运行的时候,软件中使用的虚拟地址在映射表中查询得到对应的物理地址再发给硬件去执行(虚拟地址到物理地址的映射是不可能通过软件来实现的)。

(2)MMU单元的作用
    1)MMU就是(内存管理单元)。MMU实际上是SOC中一个硬件单元,它的主要功能就是实现虚拟地址到物理地址的映射
    2)MMU单片在CP15协处理器中进行控制,也就是说要操控MMU进行虚拟地址映射,方法就是对cp15协处理器的寄存器进行编程。

(3)设置L2、L1cache和MMU
    1)bl disable_l2cache // 禁止L2 cache
    2)bl set_l2cache_auxctrl_cycle // l2 cache相关初始化
    3)bl enable_l2cache // 使能l2 cache
    4)刷新L1 cache的icache和dcache。
    5)关闭MMU
总结:上面这5步都是和CPU的cache和mmu有关的,不用去细看,大概知道即可。
 

5.跳转到lowlevel_init函数

在uboot/board/samsumg/x210/lowlevel_init.S中

(1)关看门狗

(2)供电锁存:owlevel_init.S的第100-104行,开发板供电锁存。

(3)时钟初始化system_clock_init:
      1)使用SI搜索功能,确定这个函数就在当前文件的205行,一直到第385行。这个初始化时钟的过程和裸机中初始化的过程一样的,只是更加完整而且是用汇编代码写的。
      2)在x210_sd.h中300行到428行,都是和时钟相关的配置值。这些宏定义就决定了210的时钟配置是多少。也就是说代码在lowlevel_init.S中都写好了,但是代码的设置值都被宏定义在x210_sd.h中了。因此,如果移植时需要更改CPU的时钟设置,根本不需要动代码,只需要在x210_sd.h中更改配置值即可。

6.初始化堆栈

第一次DDR初始化mem_ctrl_asm_init
      1)该函数用来初始化DDR
      2)函数位置在uboot/cpu/s5pc11x/s5pc110/cpu_init.S文件中。

      3)配置值中其他配置值参考裸机中的解释即可明白,有一个和裸机中讲的不一样。DMC0_MEMCONFIG_0,在裸机中配置值为0x20E01323;在uboot中配置为0x30F01313.这个配置不同就导致结果不同。

      5)之前在裸机中时配置为2开头的地址,当时并没有说可以配置为3开头。从分析九鼎移植的uboot可以看出:DMC0上允许的地址范围是20000000-3FFFFFFF(一共是512MB),而我们实际只接了256MB物理内存,SoC允许我们给这256MB挑选地址范围。
      6)总结一下:在uboot中,可用的物理地址范围为:0x30000000-0x4FFFFFFF。一共512MB,其中30000000-3FFFFFFF为DMC0,40000000-4FFFFFFF为DMC1。
      7)我们需要的内存配置值在x210_sd.h的438行到468行之间。分析的时候要注意条件编译的条件,配置头文件中考虑了不同时钟配置下的内存配置值,这个的主要目的是让不同时钟需求的客户都能找到合适自己的内存配置值。
      8)在uboot中DMC0和DMC1都工作了,所以在裸机中只要把uboot中的配置值和配置代码全部移植过去,应该是能够让DMC0和DMC1都工作的。

第二次:之前在调用lowlevel_init程序前设置过1次栈(start.S 284-287行),那时候因为DDR尚未初始化,因此程序执行都是在SRAM中,所以在SRAM中分配了一部分内存作为栈。

本次因为DDR已经被初始化了,因此要把栈挪移到DDR中,所以要重新设置栈,这是第二次(start.S 297-299行);这里实际设置的栈的地址是33E00000,刚好在uboot的代码段的下面紧挨着,因为arm中都是满减栈,所以在uboot代码段下面设置栈,即使栈溢出不会影响到uboot的代码。

为什么要再次设置栈?DDR已经初始化了,已经有大片内存可以用了,没必要再把栈放在SRAM中可怜兮兮的了;原来SRAM中内存大小空间有限,栈放在那里要注意不能使用过多的栈否则栈会溢出,我们及时将栈迁移到DDR中也是为了尽可能避免栈使用时候的小心翼翼。

第三次:

(1)第三次设置栈。这次设置栈还是在DDR中,之前虽然已经在DDR中设置过一次栈了,但是本次设置栈的目的是将栈放在比较合适(安全,紧凑而不浪费内存)的地方。
(2)我们实际将栈设置在uboot起始地址上方2MB处,这样安全的栈空间是:2MB-uboot大小-0x1000=1.8MB左右。这个空间既没有太浪费内存,又足够安全。



 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式_笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值