历史上的今天
今天是:2024年12月23日(星期一)
2021年12月23日 | Tiny4412模式跳转
2021-12-23 来源:eefocus
Tiny4412模式跳转
ARM体系的CPU有以下7种工作模式:
1、用户模式(Usr):用于正常执行程序;
2、快速中断模式(FIQ):用于高速数据传输;
3、外部中断模式(IRQ):用于通常的中断处理;
4、管理模式(svc):操作系统使用的保护模式;
5、数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于虚拟存储以及存储保护;
6、系统模式(sys):运行具有特权的操作系统任务;
7、未定义指令中止模式(und):当未定义的指令执行时进入该模式,可用于支持硬件;
如下图:

要进行模式跳转,就需要要有异常事件在触发它进行模式跳转,在ARM中,异常有如下几种:

(1)在异常向量表中,需要注意的是未定义指令(undefined),软中断(swi)是发生在译码阶段,其他五种都发生在执行阶段;ARM中的流水线分为:取值,译码,执行,仿存,回写这五步,当一条指令正在执行时,它的下一条指令正在译码,下下一条在取值,pc指向的是正在取值的那条指令,在模式跳转要回去的时候这点需要认真考虑;
(2)通过上图我们可以看出要是发生undefined,它就会自动跳到0x0000004这个地址去执行,那如果我们在这个地址放一段代码,到时候就可以知道有没有发生异常,是不是跳到0x0000004这个;思想就是这样,但是现在有遇到一个新的问题,因为在这个三星公司将0x00000000—0x00010000为iROM,这个地址是只能读,不能改,因此我们就要需开启mmu,把0x00000004映射到其他空闲的地址上去:
下面是代码:
1 int (*printf)(char *, ...) = 0xc3e114d8;
2 void enable_mmu();
3 void memcpy(unsigned long *dest, unsigned long *source, int len);
4 void init_table(unsigned long *addr);
5 unsigned long swi_init();
6
7 int main()
8 {
9 unsigned long source = swi_init();
10 printf("source is %xn", source);
11
12 memcpy(0x60000004, source, 0x1000);
13 enable_mmu();
14
15 __asm__ __volatile__ (
16 ".word 0xffffffffn"
17 );
18
19 printf("welcom backn");
20 }
21
22 unsigned long swi_init()
23 {
24 unsigned long addr;
25 __asm__ __volatile__ (
26 "ldr %0, =start n"
27 : "=r" (addr)
28 );
29
30 return addr;
31 }
32
33 void memcpy(unsigned long *dest, unsigned long *source, int len)
34 {
35 int i = 0;
36 for(i = 0; i < len; i++) {
37 dest[i] = source[i];
38 }
39 }
40
41 void enable_mmu()
42 {
43 /*构建表*/
44 unsigned long addr = 0x50000000;
45 init_table(addr);
46 /*打开mmu*/
47 unsigned long mmu = 0;
48 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
49 __asm__ __volatile__ (
50 "mov r0, #3n"
51 "MCR p15, 0, r0, c3, c0, 0n"//设置为管理员
52 "MCR p15, 0, %0, c2, c0, 0n"//设置表的地址
53 "MCR p15, 0, %1, c1, c0, 0n"//开启mmu
54 :
55 : "r" (addr), "r" (mmu)
56 :
57 );
58
59 }
60
61 __asm__ (
62
63 "start: n"
64 "mov sp, #0x47000000n"
65 "stmdb sp!, {r0-r12, lr}n"
66
67 "ldr r3, datan"
68 "ldr r0, =str_undn"
69 "blx r3n"
70
71 /*跳回去代码*/
72 "mov sp, #0x47000000n"
73 "ldmdb sp, {r0-r12, pc}^n"//
74
75 "data:n"
76 ".word 0xc3e114d8n"
77
78 "str_und:n"
79 ".asciz "this is undefined\n"n"
80 ".align 2n"
81 );
82
83 void init_table(unsigned long *addr)
84 {
85 unsigned long va = 0;
86 unsigned long phys = 0;
87
88 //0x40000000-0x80000000 -> 0x40000000-0x80000000
89 for(va = 0x40000000; va < 0x80000000; va += 0x100000) {
90 phys = va;
91 addr[va >> 20] = phys | 2;
92 }
93
94 //0x10000000-0x14000000 -> 0x10000000-0x140000000
95 for(va = 0x10000000; va < 0x14000000; va += 0x100000) {
96 phys = va;
97 addr[va >> 20] = phys | 2;
98 }
99 //0x10000000-0x14000000 -> 0x10000000-0x140000000
100 for(va = 0x0; va < 0x10000000; va += 0x100000) {
101 phys = va + 0x60000000;
102 addr[va >> 20] = phys | 2;
103 }
104
105 }
在开发板运行结果如下:

总结一下:当一个模式发生跳转是,需要三步:(1)将pc存到lr中,pc->lr;(2)将cpsr存到spsr,cpsr-spsr;(3)初始化sp;第一二步由系统硬件自动完成,第三部需要我们手动完成;
模式跳回去的时候逆过过来就ok,初始化sp,将lr还给pc,spsr还给cpsr,注意需要同时一起还,73行
上面代码还有一问题就是,要是几个异常一起发生怎么办,因为我们不能控制它每次执法生一个吧,cpu留给我们处理每个异常的只有4个字节,那么我们就需要进行二级跳转了,下面贴出二级跳转代码:
1 int (*printf)(char *, ...) = 0xc3e114d8;
2 void enable_mmu();
3 void init_table(unsigned long *addr);
4 void memcpy(unsigned char *dest, unsigned char *src, int len);
5 extern unsigned long vector_start;
6
7 int main()
8 {
9 memcpy(0x70000000, vector_start, 0x1000);
10 enable_mmu();
11
12 __asm__ __volatile__(
13 ".word 0x77777777n"
14 "mov r3, #3n"
15 "ldr r0, [r3]n"
16 );
17
18 printf("welcom backn");
19
20 return 0;
21 }
22
23 void memcpy(unsigned char *dest, unsigned char *src, int len)
24 {
25 int i = 0;
26 for(i = 0; i < len; i++) {
27 dest[i] = src[i];
28 }
29 }
30
31 void enable_mmu()
32 {
33 //step 1: creat ttb
34 unsigned long addr = 0x50000000;
35 init_table(addr);
36 //step 2: enable mmu
37 unsigned long mmu = 0;
38 mmu = 1 | (1 << 1) | (1 << 3) | (1 << 8);
39 __asm__ __volatile__ (
40 "mov r0, #3n"
41 "MCR p15, 0, r0, c3, c0, 0n"//set manage
42 "MCR p15, 0, %0, c2, c0, 0n"//set ttb
43 "MCR p15, 0, %1, c1, c0, 0n"//enable mmu
44 :
45 : "r" (addr), "r" (mmu)
46 :
47 );
48
49 }
50
51 __asm__(
52
53 "vector: n"
54 " b resetn"
55 " b undn"
56 " b swin"
57 " b pre_abtn"
58 " b data_abtn"
59 " .word 0x0n"
60 " b irqn"
61 " b fiqn"
62
63 "reset:n"
64
65 "und:n"
66 /*模式跳转进来分三步:
67 *(1)将pc存到lr,pc->lr
68 *(2)将cpsr存到spsr
69 *(3)初始化sp
70 *前两部系统硬件帮我们完成,第三步需要我们手动配置*/
71 " mov sp, #0x47000000n"
72 " stmdb sp!, {r0-r12, lr}n"
73
74 " ldr r3, shown"
75 " ldr r0, =str_undn"
76 " blx r3n"
77
78 /*回去的时候逆回去就ok*,^表示同时还回去*/
79 " mov sp, #0x47000000n"
80 " ldmdb sp, {r0-r12, pc}^ n"
81
82 "swi:n"
83
84 " mov sp, #0x47000000n"
85 " stmdb sp!, {r0-r12, lr}n"
86
87 " ldr r3, shown"
88 " ldr r0, =str_swin"
89 " blx r3n"
90
91 " mov sp, #0x47000000n"
92 " ldmdb sp, {r0-r12, pc}^ n"
93 "pre_abt:n"
94
95 "data_abt:n"
96
97 " mov sp, #0x47000000n"
98 " sub lr, lr, #4n"//这句需要好好理解
上一篇:Tiny4412中断介绍
下一篇:Tiny4412之按键驱动
史海拾趣
|
摘要:随着信息技术的快速发展,无线网络技术的应用越来越广泛,但是无线网络传输的效率一直比较低。针对这 种情况提出了一种提高无线局域网传输效率的技术。先在原理上讨论了使用包融合技术在无线局域网中使用的可 行性,然后通过在NS2 下的模拟 ...… 查看全部问答> |
|
看指令表有关与十进制指令 DADD.B 将十进制的进位位和源操作数加至目的操作数 语法 DADD.B src, dst 操作 src + dst + C -> dst (十进制) 有点不理解,大侠,斑竹指点 例如: CLRC ;复位进位位 CLR R5 DADD.B #99, R5 那 ...… 查看全部问答> |
|
三星的eMMC iNAND(型号KLM2G1DEHE)大概还有50片左右,DDR3 SDRAM(型号K4B2G0846C)大概30片的样子都是BGA封装,冰点吐血价5元每片,照例上图 淘宝小店:http://shop34118588.taobao.com/… 查看全部问答> |




