1. /****************************************************************************
  2. *
  3. * ASM with C,MMU,Exception,GIC
  4. *
  5. * 声明:
  6. * 1. 本系列文档是在vim下编辑,请尽量是用vim来阅读,在其它编辑器下可能会
  7. * 不对齐,从而影响阅读.
  8. * 2. 以下所有的shell命令都是在root权限下运行的;
  9. * 3. 文中在需要往文件中写入内容的时候使用了如下2方式:
  10. * 1.如果文件不存在,创建文件;如果存在,以覆盖的方式往文件中添加内容:
  11. * cat > 文件名 << EOF (结束符)
  12. * ...
  13. * 文件内容...
  14. * ...
  15. * EOF (输入遇到EOF,cat指令结束,内容将保存在前面指定的文件中)
  16. * 2.如果文件不存在,创建文件;如果存在,将内容追加到文件尾:
  17. * cat >> 文件名 << EOF (结束符)
  18. * ...
  19. * 文件内容...
  20. * ...
  21. * EOF
  22. *
  23. * 2015-3-7 阴 深圳 尚观 Sbin 曾剑锋
  24. ****************************************************************************/
  25.  
  26. \\\\\\\\\\\\\\\--*目录*--//////////////
  27. | 一. 预热文章;
  28. | 二. C语言中插入ARM汇编;
  29. | 三. U-Boot下汇编裸板开发基本流程;
  30. | 四. U-BootC语言裸板开发基本流程;
  31. | 五. MMU 配置流程;
  32. | 六. Exception 配置及处理;
  33. | 七. 主程序对异常的处理;
  34. \\\\\\\\\\\\\\\\\\\\///////////////////
  35.  
  36. 一. 预热文章:
  37. . Make 命令教程
  38. url: http://www.ruanyifeng.com/blog/2015/02/make.html
  39. . ATPCS和内嵌汇编: arm处理器上函数调用寄存器的使用规则
  40. url: http://bog.csdn.net/yypony/article/details/17633323
  41.  
  42. 二. C语言中插入ARM汇编:
  43. . cat > test.c << EOF
  44. #include <stdio.h>
  45. int main(void)
  46. {
  47. volatile unsigned int a ;
  48. int b ;
  49. __asm__ __volatile__ (
  50. "mov r0, #11 \n" // 如果立即数小于256直接附值
  51. "mov %0, r0 \n"
  52. "mov %1, #125 \n"
  53. :"=r"(a),"=r"(b) // 输出
  54. : // 输入
  55. :"r0" // 已经使用过的寄存器
  56. );
  57. printf("a:%d b:%d \n" , a , b);
  58. return ;
  59. }
  60. EOF
  61. . arm-linux-gcc test.c -o test
  62. . minicom(U-Boot)中运行编译好的test程序: ./test
  63.  
  64. 三. U-Boot下汇编裸板开发基本流程:
  65. . 编译好U-Boot后,在其根目标录下会生成一个System.map文件,这是U-Boot中提供的
  66. 函数及其地址(符号表),我们可以把U-Boot当作一个函数库来使用.
  67. . cat > test.S << EOF
  68. .global _start
  69. _start:
  70. stmfd sp! , {r0-r12 , lr} @寄存器入栈
  71.  
  72. @ 0x43e11434U-Bootprintf地址,这个地址不是固定,这是我编译的U-Boot
  73. @ printf的地址, 因为如果修改了U-Boot的源码,printf地址会变,U-Boot其他
  74. @ 函数地址也会变,所以大家以各自编译U-Boot后产生的System.map文件中的
  75. @ 地址为准.
  76. ldr r1 , =0x43e11434
  77. ldr r0 , =str
  78. mov lr , pc
  79. mov pc , r1
  80.  
  81. ldmfd sp! , {r0-r12 , pc} @寄存器出栈
  82. str:
  83. .string "hello world\n"
  84. .align
  85. EOF
  86. . cat > Makefile << EOF
  87. all:
  88. arm-linux-gcc -c test.S -o test.o
  89. arm-linux-ld -Ttext=0x40008000 test.o -o test # 0x40008000是加载代码的起始地址
  90. arm-linux-objcopy -O binary test test.bin # 获取二进制可运行文件
  91.  
  92. clean:
  93. rm -rf test.o test test.bin
  94. EOF
  95. . make
  96. . test.bin烧入开发板,运行程序,得到结果.
  97. . 如果不使用默认的连接文件,采用自己编写的连接文件,操作如下:
  98. . 获取链接脚本模板: arm-linux-ld --verbose > test.lds ,修改模板文件为如下文件内容:
  99. =============================================================================
  100. /* Script for -z combreloc: combine and sort reloc sections */
  101. OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
  102. "elf32-littlearm")
  103. OUTPUT_ARCH(arm)
  104. ENTRY(_start)
  105. SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
  106. SECTIONS
  107. {
  108. . = 0x40008000 ; /* 运行代码的起始地址 */
  109. .text :
  110. {
  111. test.o(.text) ; /* _start标号在这个文件里 */
  112. *(.text) ;
  113. }
  114. align = ;
  115. }
  116. . 修改Makefile如下: cat > Makefile << EOF
  117. all:
  118. arm-linux-gcc -c test.S -o test.o
  119. arm-linux-ld -T test.lds *.o -o test
  120. arm-linux-objcopy -O binary test test.bin
  121. clean:
  122. rm -rf test.o test test.bin
  123. EOF
  124.  
  125. 四. U-BootC语言裸板开发基本流程:
  126. . 编译好U-Boot后,在其根目标录下会生成一个System.map文件,这是U-Boot中提供的
  127. 函数及其地址(符号表),我们可以把U-Boot当作一个函数库来使用.
  128. . cat > test.c << EOF
  129. int num = ;
  130. int array[] = {};
  131. //0x43e11434是U-Boot中printf地址,这个地址不是固定,如果修改了源码,地址可能会变
  132. int (*printf)(const char *fmt , ...) = (void *)0x43e11434;
  133. int _start(void) // 这里不能是main,因为裸板运行的其实函数是_start,和汇编一样
  134. {
  135. printf("num:%d \n" , num);
  136. int i ;
  137. for(i = ; i < ; i++)
  138. {
  139. printf("array[%d]: %d \n" , i , array[i]);
  140. }
  141.  
  142. return ;
  143. }
  144. EOF
  145. . cat > Makefile << EOF
  146. all:
  147. arm-linux-gcc -c test.c -o test.o -fno-builtin
  148. arm-linux-ld -T test.lds *.o -o test #采用第三部分的lds文件
  149. arm-linux-objcopy -O binary test test.bin
  150. clean:
  151. rm -rf test test.bin *.o
  152. EOF
  153. . make
  154. . test.bin烧入开发板,运行程序,得到结果.
  155.  
  156. 五. MMU 配置流程:
  157. void memset(int *ttb , char ch , int size )
  158. {
  159. int i ;
  160. for(i = ; i < size ; i++) {
  161. ((char *)ttb)[i] = ch;
  162. }
  163. }
  164. void default_map(int *ttb)
  165. {
  166. unsigned int va , pa;
  167. //IROM RAM
  168. for(va = 0x00000000 ; va < 0x10000000 ; va+=0x100000) {
  169. pa = va;
  170. ttb[va >> ] = (pa & 0xfff00000) | ;
  171. }
  172. //SFR
  173. for(va = 0x10000000 ; va < 0x14000000 ; va+=0x100000) {
  174. pa = va;
  175. ttb[va >> ] = (pa & 0xfff00000) | ;
  176. }
  177. //DRAM 内存
  178. for(va = 0x40000000 ; va < 0x80000000 ; va+=0x100000) {
  179. pa = va;
  180. ttb[va >> ] = (pa & 0xfff00000) | ;
  181. }
  182. }
  183. void memory_map(int *ttb , unsigned int va , unsigned int pa)
  184. {
  185. ttb[va >> ] = (pa & 0xfff00000) | ;
  186. }
  187. void enable_mmu(unsigned int virtualaddress , unsigned int physicsaddress)
  188. {
  189. unsigned int systemctl = ;
  190. unsigned int *ttb = (void *)0x73000000 ;
  191. unsigned int *va = (void *)virtualaddress;
  192. unsigned int *pa = (void *)physicsaddress;
  193. //1. 清空ttb所在的地址 16K = 4G/1M*4(最后乘以4是因为每个地址占用4个字节)
  194. memset(ttb, , *);
  195. //2. IROM SFR DRAM
  196. default_map(ttb);
  197. //3. memmap
  198. memory_map(ttb , virtualaddress, physicsaddress);
  199. //4. enable_mmu();
  200. systemctl = | ( << ) | ( << ) | ( << ) ;
  201.  
  202. __asm__ __volatile__ (
  203. //Domain Acess c3 c0
  204. "mvn r0 , #0 \n"
  205. "MCR p15, 0, r0, c3, c0, 0 \n"
  206.  
  207. //write ttb
  208. "MCR p15, 0, %0, c2, c0, 0 \n"
  209.  
  210. //enable mmu system control
  211. "MRC p15, 0, r0, c1, c0, 0 \n"
  212. "orr r0 , r0 , %1 \n"
  213. "MCR p15, 0, r0, c1, c0, 0 \n"
  214. :
  215. :"r"(ttb),"r"(systemctl) //外部传的参数
  216. :"r0"
  217. );
  218. }
  219.  
  220. 六. Exception 配置及处理:
  221. . cat > vector.S << EOF
  222. .global _start
  223. _start:
  224. b reset @复位异常
  225. b undef @指令未定义异常
  226. b svc @软件中断
  227. b PrefetchAbt @取指令异常
  228. b DataAbt @取数据异常
  229. nop @保留
  230. b irq @外部普通中断
  231. b fiq @外部快速中断
  232.  
  233. reset: @执行指令的时候触发的异常,但因为是复位,返回pc指针无效
  234. stmfd sp! , {r0-r12 , lr}
  235.  
  236. ldr r0 , =0x60000000
  237. @保存当前执行位置下+8的地址,也就是下2ldmfd sp! , {r0-r12 , pc}^地址
  238. @所以当执行完r0代表的函数返回时,接着到这个位置执行---
  239. mov lr , pc |
  240. ldr pc , [r0] |
  241. V
  242. ldmfd sp! , {r0-r12 , pc}^ @"^"的意思是指令完成后,把SPSR拷贝到CPSR
  243.  
  244. undef: @指令编译的时候触发的异常,此时的pc指针正好指向异常指令的后面一条指令
  245. stmfd sp! , {r0-r12 , lr}
  246.  
  247. @-------------------test
  248. ldr r0 , =str @获取字符串,第一个参数保存在r0
  249. ldr r2 , =printf @获取printf符号的地址
  250. ldr r1 , [lr , #-] @把发生指令异常指令对应的数字打印出来
  251.  
  252. mov lr , pc
  253. ldr pc , [r2] @获取printf符号地址里的值,并调用对应值的函数(调用printf)
  254. @-------------------test
  255.  
  256. ldr r0 , =0x60000004
  257. mov lr , pc
  258. ldr pc , [r0]
  259.  
  260. ldmfd sp! , {r0-r12 , pc}^
  261.  
  262. svc: @指令编译的时候触发的异常
  263. stmfd sp! , {r0-r12 , lr}
  264.  
  265. @处理函数需要知道SVC指令的调用号,把整条指令当传输传给C函数处理
  266. ldr r0 , [lr , #-]
  267. ldr r2 , =0x60000008
  268. mov lr , pc
  269. ldr pc , [r2]
  270.  
  271. ldmfd sp! , {r0-r12 , pc}^
  272.  
  273. PrefetchAbt: @取指令的时候引发的异常
  274. stmfd sp! , {r0-r12 , lr}
  275.  
  276. ldr r0 , =0x6000000C
  277. mov lr , pc
  278. ldr pc , [r0]
  279.  
  280. ldmfd sp! , {r0-r12 , pc}^
  281.  
  282. DataAbt: @取数据的时候引发的异常
  283. stmfd sp! , {r0-r12 , lr}
  284.  
  285. ldr r0 , =0x60000010
  286. mov lr , pc
  287. ldr pc , [r0]
  288.  
  289. ldmfd sp! , {r0-r12 , pc}^
  290.  
  291. irq: @会执行完当前正在编译的指令,再去处理异常
  292. stmfd sp! , {r0-r12 , lr}
  293.  
  294. ldr r0 , =0x60000014
  295. mov lr , pc
  296. ldr pc , [r0]
  297.  
  298. ldmfd sp! , {r0-r12 , pc}^
  299.  
  300. fiq: @会执行完当前正在编译的指令,再去处理异常
  301. stmfd sp! , {r0-r12 , lr}
  302.  
  303. ldr r0 , =0x60000018
  304. mov lr , pc
  305. ldr pc , [r0]
  306.  
  307. ldmfd sp! , {r0-r12 , pc}^
  308.  
  309. str:
  310. .string "hello world \n"
  311. .align
  312.  
  313. printf:
  314. .word 0x43e11434
  315. EOF
  316.  
  317. 七. 主程序对异常的处理:
  318. int (*printf)(const char *fmt , ...) = (void *)0x43e11434 ;
  319. void do_reset(void);
  320. void do_undef(void);
  321. void do_svc(void);
  322. void do_PrefetchAbt(void);
  323. void do_DataAbt(void);
  324. void do_irq(void);
  325. void do_fiq(void);
  326.  
  327. int _start(void) {
  328. unsigned int *va = (void *)0xfff00000 ;
  329. unsigned int *pa = (void *)0x50000000 ; //这里决定异常向量表从0x500f0000开始
  330.  
  331. /* 对应vector.S中的地址调用 */
  332. *(U32 *)0x60000000 = (U32)do_reset;
  333. *(U32 *)0x60000004 = (U32)do_undef ;
  334. *(U32 *)0x60000008 = (U32)do_svc;
  335. *(U32 *)0x6000000C = (U32)do_PrefetchAbt;
  336. *(U32 *)0x60000010 = (U32)do_DataAbt ;
  337. *(U32 *)0x60000014 = (U32)do_irq ;
  338. *(U32 *)0x60000018 = (U32)do_fiq ;
  339.  
  340. //开启mmu
  341. enable_mmu((int)va , (int)pa);
  342.  
  343. __asm__ __volatile__ (
  344. "mov r0 , r0 \n"
  345. "nop \n"
  346. ".word 0x12345678 \n" //正常的指令
  347. ".word 0x77777777 \n" //异常的指令
  348.  
  349. "swi #0x1234 \n" //软件中断: 以前是swi,现在改成svc
  350. "svc #0x2345 \n"
  351. );
  352.  
  353. //设置cpsr第I位,打开外部中断,要不然GIC无效
  354. __asm__ __volatile__ (
  355. "mrs r0 , cpsr \n"
  356. "bic r0 , r0 , #(1 << 7) \n"
  357. "msr cpsr , r0 \n"
  358. );
  359.  
  360. //---------------------------cpu
  361. //指定哪个CPU接收
  362. ICCICR_CPU0 |= ;
  363.  
  364. //配置CPU的优先级最低
  365. //ICCPMR_CPU0 &= ~0xff ;
  366. ICCPMR_CPU0 |= 0xff ; //数字越小,优先级越高
  367. //开启GIC enable
  368. ICDDCR |= ;
  369. //----------------------------
  370. //设置GIC 1号中断的优先级为0,也就是最高
  371. ICDIPR0_CPU0 &= ~(0xff << );
  372. //指定CPU处理中断
  373. ICDIPTR0_CPU0 |= ( << );
  374. //允许GIC 1号中断
  375. ICDISER0_CPU0 |= << ;
  376. //发1号内部GIC中断
  377. ICDSGIR = ( << ) | ;
  378.  
  379. }
  380. void do_reset(void)
  381. {
  382. printf("this is in reset ... \n");
  383. }
  384. void do_undef(void)
  385. {
  386. printf("this is in do_undef... \n");
  387. }
  388. void do_svc((int SystemCallNo)
  389. {
  390. /* 软件中断的参数在Linux就是系统调用号的意思 */
  391. SystemCallNo &= 0xffffff ; //获取系统调用号
  392. printf("this is in svc...No:%p \n" , SystemCallNo);
  393. }
  394. void do_PrefetchAbt(void)
  395. {
  396. printf("this is in PrefetchAbt... \n");
  397. }
  398. void do_DataAbt(void)
  399. {
  400. printf("this is in DataAbt... \n");
  401. }
  402. void do_irq(void)
  403. {
  404. /* 经测试,不能和其他的中断一起使用,只能作为测试GIC 1号中断这样处理 */
  405. int ID = ICCIAR_CPU0 & 0x3ff ;
  406. int CPUID = ((ICCIAR_CPU0) >> ) & 0x7 ;
  407. printf("this is in irq...ID:%d CPUID:%d \n" , ID , CPUID);
  408.  
  409. }
  410. void do_fiq(void)
  411. {
  412. printf("this is in fiq... \n");
  413. }

Samsung_tiny4412(驱动笔记02)----ASM with C,MMU,Exception,GIC的更多相关文章

  1. Samsung_tiny4412(驱动笔记01)----linux 3.5,U-Boot,Busybox,SD卡启动环境搭建

    /*********************************************************************************** * * linux 3.5,U ...

  2. Samsung_tiny4412(驱动笔记06)----list_head,proc file system,GPIO,ioremap

    /**************************************************************************** * * list_head,proc fil ...

  3. Samsung_tiny4412(驱动笔记05)----Makefile,open,read,write,lseek,poll,ioctl,fasync

    /*********************************************************************************** * * Makefile,op ...

  4. Samsung_tiny4412(驱动笔记04)----volatile,container_of,file_operations,file,inode

    /*********************************************************************************** * * volatile,co ...

  5. Samsung_tiny4412(驱动笔记03)----字符设备驱动基本操作及调用流程

    /*********************************************************************************** * * 字符设备驱动基本操作及 ...

  6. Samsung_tiny4412(驱动笔记10)----mdev,bus,device,driver,platform

    /*********************************************************************************** * * mdev,bus,de ...

  7. Samsung_tiny4412(驱动笔记09)----alloc_pages,kmalloc,vmalloc,kmem_cache,class

    /*********************************************************************************** * * alloc_pages ...

  8. Samsung_tiny4412(驱动笔记07)----spinlock,semaphore,atomic,mutex,completion,interrupt

    /*********************************************************************************** * * spinlock,se ...

  9. Samsung_tiny4412(驱动笔记08)----jiffies,timer,kthread,workqueue,tasklet

    /*********************************************************************************** * * jiffies,tim ...

随机推荐

  1. [luogu P3628] [APIO2010]特别行动队

    [luogu P3628] [APIO2010]特别行动队 题目描述 你有一支由 n 名预备役士兵组成的部队,士兵从 1 到 n 编号,要将他们拆分 成若干特别行动队调入战场.出于默契的考虑,同一支特 ...

  2. CSS:font-family常用字体中英文对照

    CSS:font-family常用字体中英文对照如下: 推荐网址:https://www.cnblogs.com/EnSnail/p/6792853.html 微软雅黑: Microsoft YaHe ...

  3. JDBC、JNDI和DBCP的区别

    JDBC:Java DataBase Connectivity,java连接数据库和执行SQL语句的API. 数据源:Data Source.就是将IP.数据库.用户名.密码封装起来对外只提供一个JN ...

  4. python 学习 模块

    在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就越来越长,越来越不容易 维护, 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少,很 ...

  5. awk 中 fieldwidths使用方法

    AWK中的FIELDWIDTHS是一个很好用的变量,这个变量可以指定字符串按照怎么样的宽度进行展示 实例一: 要求: 032130 032131 146230 035048 222049 095070 ...

  6. ActiveMQ的安装与配置

    ActiveMQ的安装与配置详情 (1)ActiveMQ的简介 MQ: (message queue) ,消息队列,也就是用来处理消息的,(处理JMS的).主要用于大型企业内部或与企业之间的传递数据信 ...

  7. Java遍历集合的几种方法分析(实现原理、算法性能、适用场合)

    概述 Java语言中,提供了一套数据集合框架,其中定义了一些诸如List.Set等抽象数据类型,每个抽象数据类型的各个具体实现,底层又采用了不同的实现方式,比如ArrayList和LinkedList ...

  8. java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result异常的解决方法

    今天在写一个JAVA程序的时候出现了异常:java.lang.ArithmeticException: Non-terminating decimal expansion; no exact repr ...

  9. VCL界面控件DevExpress VCL Controls发布v18.2.4|附下载

    DevExpress VCL Controls是 Devexpress公司旗下最老牌的用户界面套包.所包含的控件有:数据录入,图表,数据分析,导航,布局,网格,日程管理,样式,打印和工作流等,让您快速 ...

  10. 数据结构~trie树(字典树)

    1.概述 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. 我理解字典树是看了这位大佬博客.还不了解字典树的 ...