在进入讲解linux内存管理的kernel阶段以前,了解一下uboot阶段是如何准备好内存物理设备的,这是非常有意义的。通常进入到linux内核阶段之后,对内存芯片的物理特性寄存器访问是比较少的,强调的是linux在管理上的用法,而大部分必要工作由uboot阶段进行处理,如打开内存功能,配置内存,初始化内存设备,获得内存基本信息等。
    下面以笔记的形式讲述调试uboot内存的方法,分别以ARM芯片和MIPS芯片为基础进行,大家可以将其作为bringup板子时的参考。
    一 分类:内存与CPU的连接方式分为两类,一类是Static OnBoard, 表示板载内存颗粒;一类是DIMM 双列直插模式连接;两者在硬件连接上有不同的地方,这里不是重点,但这两类配置内存的方式是有差别的,前者由启动代码对映射好的关于内存的寄存器进行直接配置,后者是由启动代码读取DIMM上的iic spd数据配置内存的。
    二 内存的配置代码涉及到启动过程,因此我饶有兴趣地向大家讲讲启动过程。
    uboot的开源性会提供一个启动汇编程序start.S, 对于一个具体的芯片,会由此start.S调用分支,执行关于它的一个具体平台platform.S, platform.S当中正包含了如何初始化内存的整个过程。
    1. arm方式的过程,针对static OnBoard方式,当然它也支持DIMM方式。
       uboot的第一个阶段也正是执行该汇编程序的地方,包含start.S, platform.S, ddr2BasicInit/ddr2StaticInit.S....。
       1) 首先它要设置好文本段TEXT_BASE起始值,BSS段起止start/end,为后续定位执行做好准备。
       2) 然后刷新芯片内部I/D-Cache, 该Cache一般均为32K大小,由协处理器CP15管理,关闭MMU和TLB,刷新和关闭的目的是防止cpu使用这些硬件取不对应的数据值,比如没有刷新cache,新的存取操作已经发生,但不是cache原来的命中值,数据已经发生变化但cache仍然保留原样,这样就取出错误的数据和指令。
       3) 然后进入到cpu_init_crit,这个函数通常映射了具体平台platform.S, 执行标签为lowlevel_init,它完成的工作包括:映射CPU寄存器地址,使用CPU寄存器地址配置CPU关于总线的初始化(如MBUS),配置cpu的时钟和MPP调试GPIO口,再转入到内存的调试标签入口_mvDramIfStaticInit/_mvDramIfBasicInit, 这个文件在ddr2/mvDramIfBasicInit.S目录下,如果为static执行_mvDramIfStaticInit直接写配置字就完成,如果为DIMM,则初始化IIC即TWSI,_i2cRead读SPD,最后用读出的值来配置内存_mvDramIfConfig。这部分的执行流程过程如下图1-1所示:

              

                        图1-1 内存配置的启动代码流程图
          下面列出一个关于Marvell 512M static 内存的配置情况如图1-2(这是俺熟读CPU关于内存寄存器配置很多遍得到的结果哦)

1
#define STATIC_SDRAM0_BANK0_SIZE                0x1FFFFFF1 /*   0x1504  *//*0 --> 16*16,  1-->32*16*<br>      #define STATIC_SDRAM_CONFIG                     0x43008c30 /*   0x1400  */<br>      #define STATIC_SDRAM_MODE                       0x00000C52 /*   0x141c  */<br>      #define STATIC_DUNIT_CTRL_LOW                   0x39543000 /*   0x1404  */<br>      #define STATIC_DUNIT_CTRL_HI                    0x0000F1FF /*   0x1424  */<br>      #define STATIC_SDRAM_ADDR_CTRL                  0x0000000d /*   0x1410  */ /*512M*/<br>     #define STATIC_SDRAM_TIME_CTRL_LOW              0x22125451 /*   0x1408  */<br>      #define STATIC_SDRAM_TIME_CTRL_HI               0x00000833 /*   0x140c  */<br>      #define STATIC_SDRAM_ODT_CTRL_LOW               0x003C0000 /*   0x1494  */<br>      #define STATIC_SDRAM_ODT_CTRL_HI                0x00000000 /*   0x1498  */<br>      #define STATIC_SDRAM_DUNIT_ODT_CTRL             0x0000F80F /*   0x149c  */<br>      #define STATIC_SDRAM_EXT_MODE                   0x00000042 /*   0x1420  */<br>      #define STATIC_SDRAM_DDR2_TIMING_LO             0x00085520 /*   0x1428  */<br>      #define STATIC_SDRAM_DDR2_TIMING_HI             0x00008552 /*   0x147C  */<br>

                            图1-2 板载内存配置

4) 完成上面的3)过程,喘口气,它还没跳出第一阶段的圈子,还在汇编程序当中,但它准备好了最关键的设备--内存,后面的程序就可以使用它了。下面就进入uboot引导的关键一步----重定位,代码截图1-3如下:

1
relocate:                               /* relocate U-Boot to RAM           */<br>        adr     r0, _start              /* r0 <- current position of code   */<br>        ldr     r1, _TEXT_BASE          /* test if we run from flash or RAM */<br>        cmp     r0, r1                  /* don't reloc during debug         */<br>        beq     stack_setup<br><br>        ldr     r2, _armboot_start<br>        ldr     r3, _bss_start<br>        sub     r2, r3, r2              /* r2 <- size of armboot            */<br>        add     r2, r0, r2              /* r2 <- source end address         */<br><br>copy_loop:<br>        ldmia   r0!, {r3-r10}           /* copy from source address [r0]    */<br>        stmia   r1!, {r3-r10}           /* copy to   target address [r1]    */<br>        cmp     r0, r2                  /* until source end addreee [r2]    */<br>        ble     copy_loop<br><br>

                            图1-3 start.S中重定位
          重定位的主要作用是将Nand/Nor flash上的代码拷贝到内存上来使用,当然,我们不可以简单理解这种拷贝是由读写flash函数调用来实现的,毕竟此时flash还没有被初始化,一般的理解是:CPU在出厂的时候会烧固件给内部ROM,它是上电可执行代码,像PC机的bios一样会自检等等。一般来讲,CPU内部也是有小部分RAM,当CPU的boot_cs选中外界flash的时候,CPU的flash controller会根据这个片选信号倾泻数据给RAM。重定位的作用正是这部分flash对RAM的倾泻转移到物理内存上,最终交由内存来存放uboot源码。1)步骤正是为了配合重定位来是指示bss和起始执行位置TEXT_BASE的,在Marvell芯片内部,uboot在物理内存重定位的值为0x600000 6M处位置,可用命令md 0x600000查看。
       5) start.S阶段当然还有一些工作需要处理,比如关闭中断,设置异常中断指向重启复位,重新安排stack的位置等等,这些都不是重点,了解即可。
       到此 终于完成了它的第一阶段,现在进入uboot的第二步,我浮光掠影地讲解下第二阶段过程,重点放在内存上。
       1) 第一阶段调用start_armboot指向C语言执行代码区,首先它要从内存上的重定位数据获得不完全配置的全局数据表格和板级信息表格,即获得gd_t和bd_t,这两个类型变量记录了刚启动时的信息,并将要记录作为引导内核和文件系统的参数,如bootargs等等,并且将来还会在启动内核时,由uboot交由kernel时会有所用。
       2) 下面就是各个sequence的初始化,重点关注cpuMapInit和dram_init,对于Marvell芯片源码,cpuMapInit函数是要读取一张表格,这个表格用来映射CPU的地址空间,它包含内存的,设备的,启动boot_cs的,以及PCI设备的映射,由于uboot不分所谓的内核空间用户空间,也就无所谓权限保护的问题,这张表格指定是多少地址就是实际使用该设备的CPU空间地址,可以理解为直接映射,对于Marvell设备来讲,内存是零偏移位置,重要的是不要冲突占用即可。
          dram_init的初始化,实际上由于Static OnBoard原因简化了操作,只是获取该内存的映射地址以及内存的大小,这些映射的设置亦有cpuMapInit完成,然后将内存的一些信息填充到gd_t和bd_t当中。
       3) 补充啰嗦一点,uboot第二阶段最初会关中断初始化的中断计数,待关键的内容初始化完成后(如cpu_init,cpuMap,env),会同GPIO一同打开中断功能。当然uboot的初始化远不止这些,还包括诸如flash初始化,scsi初始化,以太网初始化,定时器初始化等等。
       第二阶段工作的完成,可以告知系统内存是线性而且是直接的映射,CPU可以在内存上做各种简单的应用,可以使用malloc函数分配,当然无法执行繁重的工作,因为它没有回收和分配管理能力。
    2。MIPS方式过程:以spd为例,当然也支持OnBoard方式。
       若以SPD方式来调试板子的bringup,其实相对来说是比较容易的,因为它的大部分信息已经记录在spd内部,读出来配置就可以了,能否成功配置同cpu的内存访问源码有关,通常要检查CPU是否正确指定了spd iic地址,其次,如果源码的健壮性比较差,还要根据CPU的关于内存的片选,内存的延迟机时做适当的调整,因为某些内存是双CS的,内存的rank是偶数,同样,layout会影响信号失真,配置芯片CPU的信号增强也可以提高稳定性。
       下面列出一些我在MIPS平台下的数据如图1-4,大家可以作为参考,至于MIPS的bootloader,与ARM的大同小异,跟着上面一样的思路就可以完整找到具体的步骤,在此不啰嗦了。


代码

Initializing DDR interface 0, DDR Clock 400000000, DDR Reference Clock 50000000
DIMM 0: DDR2 Unbuffered, non-ECCSPD dump for DIMM at TWSI address: 0x50
0 Number of Serial PD Bytes written during module production 0x80
1 Total number of Bytes in Serial PD device 0x08
2 Fundamental Memory Type (FPM, EDO, SDRAM, DDR, DDR2) 0x08
3 Number of Row Addresses on this assembly 0x0e
4 Number of Column Addresses on this assembly 0x0a
5 Number of DIMM Ranks 0x60
6 Data Width of this assembly 0x40
7 Reserved 0x00
8 Voltage Interface Level of this assembly 0x05
9 SDRAM Cycle time at Maximum Supported CAS Latency (CL), CL=X 0x25
10 SDRAM Access from Clock (tAC) 0x40
11 DIMM configuration type (Non-parity, Parity or ECC) 0x00
12 Refresh Rate/Type (tREFI) 0x82
13 Primary SDRAM Width 0x08
14 Error Checking SDRAM Width 0x00
15 Reserved 0x00
16 SDRAM Device Attributes: Burst Lengths Supported 0x0c
17 SDRAM Device Attributes: Number of Banks on SDRAM Device 0x08
18 SDRAM Device Attributes: CAS Latency 0x60
19 Reserved 0x01
20 DIMM Type Information 0x04
21 SDRAM Module Attributes 0x00
22 SDRAM Device Attributes: General 0x07
23 Minimum Clock Cycle at CLX-1 0x30
24 Maximum Data Access Time (tAC) from Clock at CLX-1 0x45
25 Minimum Clock Cycle at CLX-2 0x3d
26 Maximum Data Access Time (tAC) from Clock at CLX-2 0x50
27 Minimum Row Precharge Time (tRP) 0x3c
28 Minimum Row Active to Row Active delay (tRRD) 0x1e
29 Minimum RAS to CAS delay (tRCD) 0x3c
30 Minimum Active to Precharge Time (tRAS) 0x2d
31 Module Rank Density 0x01
32 Address and Command Input Setup Time Before Clock (tIS) 0x17
33 Address and Command Input Hold Time After Clock (tIH) 0x25
34 Data Input Setup Time Before Clock (tDS) 0x05
35 Data Input Hold Time After Clock (tDH) 0x12
36 Write recovery time (tWR) 0x3c
37 Internal write to read command delay (tWTR) 0x1e
38 Internal read to precharge command delay (tRTP) 0x1e
39 Memory Analysis Probe Characteristics 0x00
40 Extension of Byte 41 tRC and Byte 42 tRFC 0x36
41 SDRAM Device Minimum Active to Active/Auto Refresh Time (tRC) 0x39
42 SDRAM Min Auto-Ref to Active/Auto-Ref Command Period (tRFC) 0x7f
43 SDRAM Device Maximum device cycle time (tCKmax) 0x80
44 SDRAM Device maximum skew between DQS and DQ signals (tDQSQ) 0x14
45 SDRAM Device Maximum Read DataHold Skew Factor (tQHS) 0x1e
46 PLL Relock Time 0x00
47 IDD in SPD - To be defined 0x53

                  图1-4 spd 数据读

三。总结:uboot阶段的内存方面并没有管理特征,只是线性直接的映射,重点在于打通内存设备,让内存设备在物理上能够工作起来,并且能接管来自CPU内部RAM的数据重定位,从而执行外部设备的uboot二进制映象。文中提到了许多调试uboot的方法,这是工作的总结,在调试bringup板子上一定用的上。

linux内存管理之uboot第一步的更多相关文章

  1. Linux内存管理原理

    本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址又叫线性地址.linux没有采用分段机制,所以逻辑地址和虚拟地址(线性地址)(在用户态,内核态逻 ...

  2. Linux内存管理原理【转】

    转自:http://www.cnblogs.com/zhaoyl/p/3695517.html 本文以32位机器为准,串讲一些内存管理的知识点. 1. 虚拟地址.物理地址.逻辑地址.线性地址 虚拟地址 ...

  3. Windows内存管理和linux内存管理

    windows内存管理 windows 内存管理方式主要分为:页式管理,段式管理,段页式管理. 页式管理的基本原理是将各进程的虚拟空间划分为若干个长度相等的页:页式管理把内存空间按照页的大小划分成片或 ...

  4. Linux内存管理 (9)mmap(补充)

    之前写过一篇简单的介绍mmap()/munmap()的文章<Linux内存管理 (9)mmap>,比较单薄,这里详细的梳理一下. 从常用的使用者角度介绍两个函数的使用:然后重点是分析内核的 ...

  5. Linux内存管理之mmap详解

    转发之:http://blog.chinaunix.net/uid-26669729-id-3077015.html Linux内存管理之mmap详解 一. mmap系统调用 1. mmap系统调用  ...

  6. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

  7. [转帖]Linux分页机制之概述--Linux内存管理(六)

    Linux分页机制之概述--Linux内存管理(六) 2016年09月01日 19:46:08 JeanCheng 阅读数:5491 标签: linuxkernel内存管理分页架构更多 个人分类: ┈ ...

  8. Linux内存管理 - slab分配器和kmalloc

    本文目的在于分析Linux内存管理机制的slab分配器.内核版本为2.6.31.1. SLAB分配器 内核需要经常分配内存,我们在内核中最常用的分配内存的方式就是kmalloc了.前面讲过的伙伴系统只 ...

  9. Linux内存管理 - buddy系统

    本文目的在于分析Linux内存管理机制中的伙伴系统.内核版本为2.6.31.1. 伙伴系统的概念 在系统运行过程中,经常需要分配一组连续的页,而频繁的申请和释放内存页会导致内存中散布着许多不连续的页, ...

随机推荐

  1. [Go]程序实体

    Go语言中的程序实体包括变量.常量.函数.结构体.接口 1.常见声明变量的方式 package main import ( "flag" "fmt" ) fun ...

  2. kafka直连方式消费多个topic

    一个消费者组可以消费多个topic,以前写过一篇一个消费者消费一个topic的,这次的是一个消费者组通过直连方式消费多个topic,做了小测试,结果是正确的,通过查看zookeeper的客户端,zoo ...

  3. POJ2455 Secret Milking Machine【二分,最大流】

    题目大意:N个点P条边,令存在T条从1到N的路径,求路径上的边权的最大值最小为多少 思路:做了好多二分+最大流的题了,思路很好出 二分出最大边权后建图,跑dinic 问题是....这题是卡常数的好题! ...

  4. 反编译sencha toucha打包的apk文件,修改应用名称支持中文以及去除应用标题栏

    一.去除安卓应用标题栏 sencha touch打包android安装包,去掉标题栏titlebar的简单方法 (有更复杂更好的方法,参看"二.利用反编译修改apk的应用名称为中文" ...

  5. C#的特性学习草稿

    原文发布时间为:2008-11-22 -- 来源于本人的百度文章 [由搬家工具导入] 举个简单的例子: 先定义个特性 从Attribute继承,并标明用法 [AttributeUsage(Attrib ...

  6. SGU 106 The equation【扩展欧几里得】

    先放一张搞笑图.. 我一直wa2,这位不认识的大神一直wa9...这样搞笑的局面持续了一个晚上...最后各wa了10发才A... 题目链接: http://acm.hust.edu.cn/vjudge ...

  7. Spring中实现自定义事件

    原理: 通过扩展ApplicationEvent,创建一个事件类CustomEvent.这个类必须定义一个默认的构造函数,它应该从ApplicationEvent类中继承的构造函数. 一旦定义事件类, ...

  8. CSS 空中飘动的云动画

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. 巧用Drawable 实现Android UI 元素间距效果

    源文地址: 巧用Drawable 实现Android UI 元素间距效果 在大部分的移动UI或者Web UI都是基于网格概念而设计的.这种网格一般都是有一些对其的方块组成,然后它们组合成为一个块.使用 ...

  10. 读书笔记-HBase in Action-第三部分应用-(2)GIS系统

    本章介绍用HBase存储.高效查询地理位置信息. Geohash空间索引 考虑LBS应用中常见的两个问题:1)查找离某地近期的k个地点.2)查找某区域内地点. 假设要用HBase实现高效查找,首先要考 ...