标签:
在ARM中,事件发生将会触发中断,然而,中断并不会直接触发CPU,而是在由一个GIC,中断控制器来管理:
其中,中断分为?
Supports three interrupt types:
Private Peripheral Interrupt (PPI)一个中断源对应一个CPU
Software Generated Interrupt (SGI) CPU对应CPU
Shared Peripheral Interrupt (SPI) 一个中断源对应多个CPU
今天的例子是用SGI中断来实现的,在处理中断的时候,主要分三步:
//step 1: cpu cpsr
CPU允许中断
20 __asm__ __volatile__(
21 "mrs r0, cpsr\n"
22 "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开
23 "msr cpsr, r0\n"
24 ::: "r0"
25 );
26
27 //step 2: GIC
GIC
28 ICCICR_CPU0 = 1;//CPU接口控制寄存器
29 ICCPMR_CPU0 = 0xff;//中断优先标志寄存器
30 ICDDCR = 1;//设置本中断的开关
31 ICDIPR0_CPU0 = (0x00 << 0);//本中断的优先级
32 ICDIPTR0_CPU0 = 1;//选择指定的CPU
33 ICDISER0_CPU0 = (1 << 0);//设置本中断开启
34 各个寄存器描述如下:详细见4412 782页
35 //step 3: interrupt source
中断源
36 ICDSGIR = 0 | (1 << 16) | (0 << 24);//SGI控制寄存器CPUTargetList.TargetListFi lte
37 printf("welcome back! \n");
下面是代码:
1 #include"regs.h" 2 3 int (*printf)(char *, ...) = 0xc3e114d8; 4 5 void init_ttb(unsigned long *addr); 6 void enable_mmu(void); 7 unsigned long data_abort_init(); 8 void memcopy(unsigned long* dest,unsigned long* source,int len); 9 void do_irq(); 10 11 int main() 12 { 13 *(unsigned long *)0x66000000 = do_irq; 14 unsigned long source_addr=data_abort_init(); 15 printf("swi_souce addr is %x\n",source_addr); 16 memcopy(0x60000000,source_addr,0x1000); 17 enable_mmu(); 18 19 //step 1: cpu cpsr 20 __asm__ __volatile__( 21 "mrs r0, cpsr\n" 22 "bic r0, r0, #0x80\n"//设置CPSR的I位,将IRQ位打开 23 "msr cpsr, r0\n" 24 ::: "r0" 25 ); 26 27 //step 2: GIC 28 ICCICR_CPU0 = 1;//CPU接口控制寄存器 29 ICCPMR_CPU0 = 0xff;//中断优先标志寄存器 30 ICDDCR = 1;//设置本中断的开关 31 ICDIPR0_CPU0 = (0x00 << 0);//本中断的优先级 32 ICDIPTR0_CPU0 = 1;//选择指定的CPU 33 ICDISER0_CPU0 = (1 << 0);//设置本中断开启 34 35 //step 3: interrupt source 36 ICDSGIR = 0 | (1 << 16) | (0 << 24);//SGI控制寄存器CPUTargetList.TargetListFi lte 37 printf("welcome back! \n"); 38 } 39 40 void do_irq() 41 { 42 unsigned long data = ICCIAR_CPU0; 43 unsigned long irq_id = data & 0x3ff; 44 unsigned long cpu_id = (data >> 10) & 0x7; 45 ICCEOIR_CPU0 = irq_id | (cpu_id << 10); 46 printf("irq is %d, cpu is %d\n", irq_id, cpu_id); 47 } 48 49 void memcopy(unsigned long* dest, unsigned long* source,int len) 50 { 51 int i=0;; 52 for(i=0;i<len;i++) 53 dest[i]=source[i]; 54 } 55 56 unsigned long data_abort_init() 57 { 58 unsigned long source; 59 __asm__ __volatile__( 60 "ldr %0, =voliate_start\n" 61 : "=r" (source) 62 ); 63 return source; 64 } 65 66 __asm__( 67 "voliate_start:\n" 68 //跳转目录 69 " b reset\n" 70 " b undefined\n" 71 " b swi\n" 72 " b pre_abt\n" 73 " b data_abt\n" 74 " .word 0\n"//占位符号,一个位占4个字节 75 " b irq\n" 76 " b fiq\n" 77 "\n" 78 //跳转要分三部: 79 //1:将PC保存到新模式下的lr中; 80 //2:将CPSR保存在SPSR中 81 //3:初始化SP 82 //前两步由硬件完成,而第三部需要手动完成 83 "reset:\n" 84 85 "undefined:\n" 86 "mov sp, #0x66000000\n"//初始化SP 87 "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器 88 //打印一句话 89 "ldr r0, =und_string\n" 90 "ldr r2, show\n" 91 "blx r2\n" 92 //跳回来分两部 93 //1:将CPSR保存在SPSR中 84 85 "undefined:\n" 86 "mov sp, #0x66000000\n"//初始化SP 87 "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器 88 //打印一句话 89 "ldr r0, =und_string\n" 90 "ldr r2, show\n" 91 "blx r2\n" 92 //跳回来分两部 93 //1:将CPSR保存在SPSR中 94 //2:将PC保存到新模式下的lr中; 95 "mov sp, #0x66000000\n"// 96 "ldmea sp, {r0-r12, pc}^\n"// 97 98 "swi:\n" 99 100 "pre_abt:\n" 101 "data_abt:\n" 102 "sub lr, lr, #4\n" 103 "mov sp, #0x66000000\n"//初始化SP 104 "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器 105 //打印一句话 106 "ldr r0, =data_string\n" 107 "ldr r2, show\n" 108 "blx r2\n" 109 //跳回来分两部 110 //1:将CPSR保存在SPSR中 111 //2:将PC保存到新模式下的lr中; 112 "mov sp, #0x66000000\n"// 113 "ldmea sp, {r0-r12, pc}^\n"// 114 115 "irq:\n" 116 "sub lr, lr, #4\n" 117 "mov sp, #0x66000000\n"//初始化SP 118 "stmfd sp!, {r0-r12, lr}\n"//初始化sp,入栈保护寄存器 119 //打印一句话 120 "mov r2, #0x66000000\n" 121 "ldr r1, [r2]\n" 122 "blx r1\n" 123 124 // "ldr r0, =irq_string\n" 125 // "ldr r2, show\n" 126 // "blx r2\n" 127 //跳回来分两部 128 //1:将CPSR保存在SPSR中 129 //2:将PC保存到新模式下的lr中; 130 "mov sp, #0x66000000\n"// 131 "ldmea sp, {r0-r12, pc}^\n"// 132 "fiq:\n" 133 "show:\n" 134 ".word 0xc3e114d8\n" 135 136 "und_string:\n" 137 ".asciz \"This is UND!\\n\" \n" 138 "data_string:\n" 139 ".asciz \"This DATA_ABORT!\\n\" \n" 140 "irq_string:\n" 141 ".asciz \"This IRQ!\\n\" \n" 142 143 ); 144 145 void init_ttb(unsigned long *addr) 146 { 147 unsigned long va = 0;//定义虚拟地址 148 unsigned long pa = 0;//定义物理地址 149 150 //40000000-------80000000 ==== 40000000------80000000 151 for(va=0x40000000; va<=0x80000000; va+=0x100000){ 152 pa = va; 153 addr[va >> 20] = pa | 2; 154 //|2的目的是将0-2位置为10此时将是小页模式4K 155 } 156 157 //00000000-------10000000 ==== 60000000------70000000 158 for(va=0x00000000; va<=0x10000000; va+=0x100000){ 159 pa = va+0x60000000; 160 addr[va >> 20] = pa | 2; 161 } 162 163 //10000000-------14000000 ==== 10000000------14000000 164 for(va=0x10000000; va<=0x14000000; va+=0x100000){ 165 pa = va; 166 addr[va >> 20] = pa | 2; 167 } 168 169 //30000000-------40000000 ==== 50000000------60000000 170 for(va=0x30000000; va<0x40000000; va+=0x100000){ 171 pa = va + 0x20000000; 172 addr[va >> 20] = pa | 2; 173 } 174 } 175 176 void enable_mmu(void) 177 178 { 179 unsigned long addr = 0x70000000; 180 init_ttb(addr); 181 //step:初始化页表 182 183 unsigned long mmu = 1 | (1 << 1) | (1 << 8); 184 //将MMU的第0,1,8位置1 185 __asm__ __volatile__( 186 "mov r0, #3\n" 187 "MCR p15, 0, r0, c3, c0, 0\n"//manager 188 "MCR p15, 0, %0, c2, c0, 0\n"//addr 189 "MCR p15, 0, %1, c1, c0, 0\n"// enable mmu 190 : 191 : "r" (addr), "r" (mmu) 192 : "r0" 193 ); 194 printf("MMU is enable!\n"); 195 } 196
在代码中,主函数其他的部分在前面都已经说了,已不再说。主要是在VICTOR函数中,将处理中断的部分,做成了一个函数,以后更容易修改处理的部分。
void do_irq()
41 {
42 unsigned long data = ICCIAR_CPU0;//取出IRQ ID 和CPU ID
43 unsigned long irq_id = data & 0x3ff;
44 unsigned long cpu_id = (data >> 10) & 0x7;
45 ICCEOIR_CPU0 = irq_id | (cpu_id << 10);//清除CPU
46 printf("irq is %d, cpu is %d\n", irq_id, cpu_id);
47 }
//总的来说,在以前的基础上面,今天主要认识了GIC的配置,更重要的是,中断分为四步:
1,CPU开
2,GIC配置
3,中断源
4,处理中断,清中断
标签:
原文地址:http://www.cnblogs.com/hongzhunzhun/p/4513031.html