13.1 NOR FLASH 搬运

  • 把程序从 nor flash 上搬运到 SDRAM 中

    • 程序存储在 nor flash 上,运行时将程序搬运到 SDRAM 中运行
  • nor flash 启动:nor flash 的地址从 0x0000 0000 开始,CPU 可以直接在 nor flash 上运行程序
    • 在 nor flash 上运行程序很慢
  • SDRAM:地址为 0x3000 0000,程序烧录在 nor flash 上,运行时,将 nor flash 上的代码搬运至 SDRAM 中运行
  • nor flash 启动:
    • 初始化寄存器
    • 关闭看门狗
    • 设置存储控制器
    • 复制代码到 SDRAM 中
    • 跳转 main 运行:使用 BL MAIN,跳转到 main 函数中运行的时候属于相对跳转,若使用 BL 指令,则 main 函数的地址时相对于 nor flash 的基地址的地址,而 SDRAM 的基地址是 0x30000000,当代码搬运到 SDRAM 中之后,程序跳转不到 main。因此要设置栈,并使用 LDR 跳转
  • 代码与前面 SDRAM 中的代码一样,搬运代码就是 COPYING 开头的代码

13.2 MMU介绍

13.2.1 MMU 特性

  内存管理单元(Memory Management Unit)简称MMU,它负责虚拟地址到物理地址的映射,并提供硬件机制的内存访问权限检查。现在的多用户多进程操作系统通过 MMU 使得各个用户进程都拥有自己独立的地址空间。

  地址映射功能使得各进程拥有“看起来”一样的地址空间,内存访问权限的检查可以保护每个进程所用的内存不会被其他进程破坏。

  S3C2440/2410 有如下特性:

  • 与 ARM V4 兼容的映射长度、域、访问权限检查机制
  • 4种映射长度:段(1MB)、大页(64KB)、小页(4KB)、极小页(1KB)
  • 对每段都可以设置访问权限
  • 大页、小页的每个子页(sub-page,即被映射页的 1/4)都可以单独设置访问权限
  • 硬件实现的 16 个域
  • 指令 TLB(含 64 个条目)、数据TLB(含64个条目)
  • 硬件访问页表(地址映射、权限检查由硬件自动进行)
  • TLB 中条目的替换采用 round-robin 算法(也称 cyclic 算法)
  • 可以使无效整个 TLB
  • 可以单独使无效某个 TLB 条目
  • 可以在 TLB 中锁定某个条目,指令 TLB、数据TLB 相互独立  

  一个程序在运行之前,没由必要全部装入内存,而仅需要将那些当前要运行的部分先装入内存,其余部分在用到的时候再从磁盘调入,而当内存耗光时再将暂时不用的部分调出到磁盘。

  再 32 位的CPU系统中,虚拟内存地址范围位 0~ 0xFFFFFFFF,这个地址范围称为虚拟地址空间,其中的某个地址称为虚拟地址。

  与虚拟地址空间、虚拟地址对应的使物理地址空间、物理地址,他们对应实际的内存

  虚拟地址最终需要转换为物理地址才能读写实际的数据,这通过将虚拟地址空间、物理地址空间划分为同样大小的一块块小空间(称为段或页),然后为这两类小空间建立映射关系。由于虚拟地址空间远大于物理空间,有可能多块虚拟地址空间映射到同一块物理地址空间,或者有些虚拟地址空间没有映射到具体的物理地址空间上去(可以在使用到时再映射)。

  • ARM CPU 上的地址转换过程的三个概念

    • VA:Virtual Address,虚拟地址
    • MVA:Modified Virtual Address,变换后的虚拟地址
    • PA:Physical Address,物理地址

  未启动 MMU 时,CPU核、cache、MMU、外设等所有部件使用的都使物理地址

  启动MMU后,CPU核对外发出虚拟地址VA;VA被转换为MVA供cache、MMU使用,再这里 MVA 被转换为 PA;最后使用PA读写实际设备:

  1. CPU核看到的、用到的只是虚拟地址 VA,至于 VA如何最终落实到物理地址 PA 上,CPU核使不理会的
  2. caches 和 MMU 也是看不见 VA 的,他们利用由 MVA 转换得到 PA
  3. 实际设备看不到 VA、MVA,读写它们时使用的是物理地址PA

  MVA 是除 CPU 核外的其他部分看见的虚拟地址

  

13.2.2 地址映射过程

  

  将一个虚拟地址转换为物理地址,由两个办法,用一个确定的数学公式进行转换或用表格存储虚拟地址对应的物理地址。这类表格称为页表(Page table),页面由一个个条目(Entry)组成;每个条目存储了一段虚拟地址对应的物理地址及其访问权限,或者下一级页表的地址。ARM CPU 中使用的是表格。

  S3C2440/2410 最多用到两级页表:以段(Section,1MB)的方式进行转换时只用到一级页表,以页(Page)的方式进行转换时用到两级页表。

  页的大小由 3 种,大页(64KB)、小页(4KB)、极小页(1KB)。

  条目也称为”描述符“(Descriptor),有段描述符、大页描述符、小页描述符、极小页描述符,主要是用来保存相应的段或页的起始物理地址;粗页描述符、细页描述符用来保存二级页表的物理地址。

  转换过程为:

  1. 根据给定的虚拟地址找到一级页表中的条目
  2. 如果此条目是段描述符,则返回物理地址,转换结束
  3. 否则如果此条目是二级页表描述符,继续利用虚拟地址在此二级页表中找到下一个条目
  4. 如果这第二个条目是页描述符,则返回物理地址,转换结束
  5. 其他情况出错

  

  TTB base 代表一级页表的地址,将它写入协处理器 CP15 的寄存器 C2(称为页表基址寄存器)即可。

13.2.3 权限管理 

  MMU对段和页面进行保护,对段和页面进行保护是由几个因素造成的。它由域的访问控制字段和一级描述符或二级描述符中的 AP 字段,以及 C1 寄存器的 S(表示system),R(表示rom)控制位来共同决定的。
  MMU中的域是指的一些段,大页或者小页的集合。ARM支持最多16个域,每个域的访问控制特性由 CP15 中的寄存器 C3 中的两位来控制。CP15 中的寄存器 C3 的格式如下:

  

   其中每两位控制一个域的访问控制特性,其编码及对应的含义如下:

  

  • 当控制位为00时,此域是没有访问权限的;
  • 当控制位为01时,此时域的属性为“用户”域;
    • 当其域为“用户”域时,存储访问权限控制由AP,S,R来决定。
  • 当控制位为11时,此时域的属性为“系统”域。
    • 当其域为“系统”域时,AP,S,R 的值将会忽略,CPU(无论cpu运行在用户级还是在特权级)可以直接访问存储内容,将不进行存储权限检查。

  当域为“用户”域时,AP,S,R控制访问权限的具体规则如下:

  

  当域为“用户”域时,当CPU运行在“特权级”或“用户级”时,AP,S,R 控制段或页的存储访问权限;

  比如:

  当域为“用户”域时,当CPU运行在“用户级”时,AP=00,S=1,R=0,查表可知,这时CPU没有访问权限;

  当域为“用户”域时,当CPU运行在“特权级”时,AP=00,S=1,R=0,这里CPU只能读存储内容,但不能写,如果写的话将产生错误;

  注意:AP,S,R的决定访问权限的作用只用是在其域为“用户”域的状态。

13.2.3 编程地址映射

  CPU核只关心 发出地址、读写数据,至于是否是虚拟地址还是物理地址,CPU不关心,至于是什么地址,是后面的设备关心的

  写程序的时候的链接地址,也是没有物理地址和虚拟地址之分,只是单纯的地址,链接地址是CPU看到的

  • MMU 操作:

    • 建立地址映射表格,即建立虚拟地址到物理地址的映射
    • 把表格地址告诉 MMU,即把内存地址告诉 MMU
    • 启动MMU

  mmu.lds

1 SECTIONS {
2 firtst 0x00000000 : { head.o init.o }
3 second 0xB0004000 : AT(2048) { leds.o }
4 }

  head.S

 1 @*************************************************************************
2 @ File:head.S
3 @ 功能:设置SDRAM,将第二部分代码复制到SDRAM,设置页表,启动MMU,
4 @ 然后跳到SDRAM继续执行
5 @*************************************************************************
6
7 .text
8 .global _start
9 _start:
10 ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈,指向 SRAM 的顶端
11 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启
12 bl memsetup @ 设置存储控制器以使用SDRAM
13 bl copy_2th_to_sdram @ 将第二部分代码复制到SDRAM
14 bl create_page_table @ 设置页表
15 bl mmu_init @ 启动MMU
16 ldr sp, =0xB4000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址)
17 ldr pc, =0xB0004000 @ 跳到SDRAM中继续执行第二部分代码
18 halt_loop:
19 b halt_loop

  init.c

  1 /*
2 * init.c: 进行一些初始化,在Steppingstone中运行
3 * 它和head.S同属第一部分程序,此时MMU未开启,使用物理地址
4 */
5
6 /* WATCHDOG寄存器 */
7 #define WTCON (*(volatile unsigned long *)0x53000000)
8 /* 存储控制器的寄存器起始地址 */
9 #define MEM_CTL_BASE 0x48000000
10
11
12 /*
13 * 关闭WATCHDOG,否则CPU会不断重启
14 */
15 void disable_watch_dog(void)
16 {
17 WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可
18 }
19
20 /*
21 * 设置存储控制器以使用SDRAM
22 */
23 void memsetup(void)
24 {
25 /* SDRAM 13个寄存器的值 */
26 unsigned long const mem_cfg_val[]={ 0x22011110, //BWSCON
27 0x00000700, //BANKCON0
28 0x00000700, //BANKCON1
29 0x00000700, //BANKCON2
30 0x00000700, //BANKCON3
31 0x00000700, //BANKCON4
32 0x00000700, //BANKCON5
33 0x00018005, //BANKCON6
34 0x00018005, //BANKCON7
35 0x008C07A3, //REFRESH
36 0x000000B1, //BANKSIZE
37 0x00000030, //MRSRB6
38 0x00000030, //MRSRB7
39 };
40 int i = 0;
41 volatile unsigned long *p = (volatile unsigned long *)MEM_CTL_BASE;
42 for(; i < 13; i++)
43 p[i] = mem_cfg_val[i];    //32位CPU中,指针移动一次是4个字节
44 }
45
46 /*
47 * 将第二部分代码复制到SDRAM
48 */
49 void copy_2th_to_sdram(void)
50 {
51 unsigned int *pdwSrc = (unsigned int *)2048;      //链接脚本中指定了 led.o 的存放的地址为 2048
52 unsigned int *pdwDest = (unsigned int *)0x30004000;  // led.o 存放在 SDRAM 中的地址
53
54 while (pdwSrc < (unsigned int *)4096)
55 {
56 *pdwDest = *pdwSrc;
57 pdwDest++;
58 pdwSrc++;
59 }
60 }
61
62 /*
63 * 设置页表
64 */
65 void create_page_table(void)
66 {
67
68 /*
69 * 用于段描述符的一些宏定义
70 */
71 #define MMU_FULL_ACCESS (3 << 10) /* 访问权限 */
72 #define MMU_DOMAIN (0 << 5) /* 属于哪个域 */
73 #define MMU_SPECIAL (1 << 4) /* 必须是1 */
74 #define MMU_CACHEABLE (1 << 3) /* cacheable */
75 #define MMU_BUFFERABLE (1 << 2) /* bufferable */
76 #define MMU_SECTION (2) /* 表示这是段描述符 */
77 #define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
78 MMU_SECTION)
79 #define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | \
80 MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION)
81 #define MMU_SECTION_SIZE 0x00100000
82
83 unsigned long virtuladdr, physicaladdr;
84 unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
85
86 /*
87 * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
88 * 为了在开启MMU后仍能运行第一部分的程序,
89 * 将0~1M的虚拟地址映射到同样的物理地址
90 */
91 virtuladdr = 0;
92 physicaladdr = 0;
93 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
94 MMU_SECDESC_WB;
95
96 /*
97 * 0x56000000是GPIO寄存器的起始物理地址,
98 * GPBCON和GPBDAT这两个寄存器的物理地址0x56000050、0x56000054,
99 * 为了在第二部分程序中能以地址0xA0000050、0xA0000054来操作GPFCON、GPFDAT,
100 * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
101 */
102 virtuladdr = 0xA0000000;
103 physicaladdr = 0x56000000;
104 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
105 MMU_SECDESC;
106
107 /*
108 * SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
109 * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
110 * 总共64M,涉及64个段描述符
111 */
112 virtuladdr = 0xB0000000;
113 physicaladdr = 0x30000000;
114 while (virtuladdr < 0xB4000000)
115 {
116 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
117 MMU_SECDESC_WB;
118 virtuladdr += 0x100000;
119 physicaladdr += 0x100000;
120 }
121 }
122
123 /*
124 * 启动MMU
125 */
126 void mmu_init(void)
127 {
128 unsigned long ttb = 0x30000000;
129
130 __asm__(
131 "mov r0, #0\n"
132 "mcr p15, 0, r0, c7, c7, 0\n" /* 使无效ICaches和DCaches */
133
134 "mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer on v4 */
135 "mcr p15, 0, r0, c8, c7, 0\n" /* 使无效指令、数据TLB */
136
137 "mov r4, %0\n" /* r4 = 页表基址 */
138 "mcr p15, 0, r4, c2, c0, 0\n" /* 设置页表基址寄存器 */
139
140 "mvn r0, #0\n"
141 "mcr p15, 0, r0, c3, c0, 0\n" /* 域访问控制寄存器设为0xFFFFFFFF,
142 * 不进行权限检查
143 */
144 /*
145 * 对于控制寄存器,先读出其值,在这基础上修改感兴趣的位,
146 * 然后再写入
147 */
148 "mrc p15, 0, r0, c1, c0, 0\n" /* 读出控制寄存器的值 */
149
150 /* 控制寄存器的低16位含义为:.RVI ..RS B... .CAM
151 * R : 表示换出Cache中的条目时使用的算法,
152 * 0 = Random replacement;1 = Round robin replacement
153 * V : 表示异常向量表所在的位置,
154 * 0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000
155 * I : 0 = 关闭ICaches;1 = 开启ICaches
156 * R、S : 用来与页表中的描述符一起确定内存的访问权限
157 * B : 0 = CPU为小字节序;1 = CPU为大字节序
158 * C : 0 = 关闭DCaches;1 = 开启DCaches
159 * A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查
160 * M : 0 = 关闭MMU;1 = 开启MMU
161 */
162
163 /*
164 * 先清除不需要的位,往下若需要则重新设置它们
165 */
166 /* .RVI ..RS B... .CAM */
167 "bic r0, r0, #0x3000\n" /* ..11 .... .... .... 清除V、I位 */
168 "bic r0, r0, #0x0300\n" /* .... ..11 .... .... 清除R、S位 */
169 "bic r0, r0, #0x0087\n" /* .... .... 1... .111 清除B/C/A/M */
170
171 /*
172 * 设置需要的位
173 */
174 "orr r0, r0, #0x0002\n" /* .... .... .... ..1. 开启对齐检查 */
175 "orr r0, r0, #0x0004\n" /* .... .... .... .1.. 开启DCaches */
176 "orr r0, r0, #0x1000\n" /* ...1 .... .... .... 开启ICaches */
177 "orr r0, r0, #0x0001\n" /* .... .... .... ...1 使能MMU */
178
179 "mcr p15, 0, r0, c1, c0, 0\n" /* 将修改的值写入控制寄存器 */
180 : /* 无输出 */
181 : "r" (ttb) );
182 }

十三、S3C2440 裸机 — 初始化代码及MMU的更多相关文章

  1. linux上使用J-Link调试S3C2440裸机代码

    linux上使用J-Link调试S3C2440裸机代码 工具: segger的jlink仿真器 segger的jlink for linux 交叉编译工具链里面的arm-xx-linux-xx-gdb ...

  2. 【转载】s3c2440裸机开发调试环境(MDK4.6,Jlink v8,mini2440)

    用于arm裸机程序开发的IDE基本有 以下3个:MDK,IAR,还有ADS.具体它们的具体情况在这里我就不多说了,百度一下就明白了.由于之前开发c51,stm32时候都使用了MDK开发环境,而且MDK ...

  3. s3c2440裸机-时钟编程(二、配置时钟寄存器)

    s3c2440裸机编程-时钟编程(二.配置时钟寄存器) 1.2440时钟时序 下图是2440时钟配置时序: 1.上电后,nRESET复位信号拉低,此时cpu还无法取指令工作. 2.nRESET复位信号 ...

  4. css初始化代码

    最近老有新项目开发,一直在找存留的CSS初始化代码,索性放到这里备份下, @charset "utf-8"; /* -------------------------------- ...

  5. 0023 Java学习笔记-面向对象-初始化代码块

    初始化代码块 在18篇-类的基本要素中说到,类的三大成员:成员变量.构造方法.方法,初始化代码块是类的第4个成员 初始化块用于对类或者对象的初始化, 一个类的初始化块可以有0-多个,按先后顺序执行 跟 ...

  6. 各大门户网站的css初始化代码

    腾讯QQ官网 css样式初始 body,ol,ul,h1,h2,h3,h4,h5,h6,p,th,td,dl,dd,form,fieldset,legend,input,textarea,select ...

  7. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

  8. css初始化代码方案

    (从已经死了一次又一次终于挂掉的百度空间人工抢救出来的,发表日期 2014-06-24) 为了消除各浏览器对css默认的设置,保持网页在各浏览器中的外观保持一致,初始化css就显得非常必要了!很多时候 ...

  9. iOS安全攻防(二十三):Objective-C代码混淆

    iOS安全攻防(二十三):Objective-C代码混淆 class-dump能够非常方便的导出程序头文件,不仅让攻击者了解了程序结构方便逆向,还让着急赶进度时写出的欠完好的程序给同行留下笑柄. 所以 ...

随机推荐

  1. 浏览器端-W3School-JavaScript:JavaScript 事件参考手册

    ylbtech-浏览器端-W3School-JavaScript:JavaScript 事件参考手册 1.返回顶部 1. JavaScript 事件参考手册 事件通常与函数配合使用,这样就可以通过发生 ...

  2. puppeteer - 操作支付宝报“操作频繁”错误的思考

    我这里想要实现的是通过转账到支付宝的方式判断一个手机号是否注册过支付宝.但查询收款人的网络请求很复杂分析不出来,使用 puppteer 也是没有解决 "操作频繁" 的问题(应该还有 ...

  3. Java关键字之static的典型用法分析

    static关键字是java中非常重要的一个关键字,用的好的话可以提高程序的运行性能,优化程序结构.接下来我们来总结一下static关键字及其用法.1.static变量 static变量也称作静态变量 ...

  4. php URL处理函数

    parse_url()    basename()    pathinfo()    dirname() 用法 parse_url() 是一计算机函数,功能是解析一个 URL 并返回一个关联数组,包含 ...

  5. 阶段3 2.Spring_02.程序间耦合_1 编写jdbc的工程代码用于分析程序的耦合

    创建新项目.不选择骨架 打包方式选择是jar 增加mysql的包依赖 创建demo类来讲解程序的耦合 原来里面提供了sql语句.拿到mysql没执行

  6. ibatis使用iterate实现批量插入insert正确写法

    由于想批量入库提升效率,最近实现了ibatis的批量插入,结果一直报错 :StringIndexOutOfBoundsException ,原来是value中的格式不正确. 本人邮箱:techqu@1 ...

  7. matlab2012a过期问题解决办法(转载)

    转载:http://blog.sina.com.cn/s/blog_4a46812b0102x694.html   以前安装过Matlab2013a等高版本,发现自己win7 系统每次重启后,Matl ...

  8. Tensorflow 安装 和 初识

    Windows中 Anaconda,Tensorflow 和 Pycharm的安装和配置   https://blog.csdn.net/zhuiqiuzhuoyue583/article/detai ...

  9. 盒模型 box-sizing 属性

    css3增添了盒模型box-sizing属性,box-sizing属性值可以有下面三个值: content-box:默认值,让元素维持W3C的标准盒模型.元素的宽度/高度(width/height)( ...

  10. Unity 相机

    相机属性 1.相机的Clear属性:Skybo背景会渲染天空盒:solid color背景为颜色:depth only仅仅深度,相当于优先级:Don`t Clear背景是上一帧的图像:2.Projec ...