本文已参与【新人创作礼】活动,一起开启掘金创作之路。
一、中断的发生、处理过程
- 中断发生的硬件过程
中断处理的过程和中断发生的过程正好相反
- 中断处理的软件处理流程
- CPU执行完当前指令,检查到发生了中断,跳到向量表
- 保存现场、执行GIC提供的处理函数、回复现场
二、异常向量表的安装
对于arm结构来说,异常向量表有两个地址,一个是地址0x00000000,一个是地址0xffff0000。
这个0xffff0000是一个虚拟地址,它需要映射到某个物理的地址,这个物理地址存放的就是异常向量表。
2.1 复制向量表
arch/arm/kernel/entry-armv.S程序入口,需要把这个复制到内核种,并映射:
.section .vectors, "ax", %progbits
.L__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, .L__vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
.data
从源头开始看,对于arm架构,这是第一个运行的文件:
// arch\arm\kernel\head.S
mrc p15, 0, r9, c0, c0 @ get processor id
bl __lookup_processor_type @ r5=procinfo r9=cpuid
//.....
bl __create_page_tables @ 建立虚拟地址和物理地址的映射关系
ldr r13, =__mmap_switched @ address to jump to after @ 记录函数地址
@ mmu has been enabled
//....
1: b __enable_mmu
//....
__enable_mmu:
//....
b __turn_mmu_on @ 打开mmu
ENDPROC(__enable_mmu)
ENTRY(__turn_mmu_on)
//....
mov r3, r13 @ 把r13 赋值给r3
ret r3 @ 返回r3
__turn_mmu_on_end:
ENDPROC(__turn_mmu_on)
__mmap_switched: @开始执行
//....
b start_kernel @进入c函数的start_kernel
ENDPROC(__mmap_switched)
- 复制向量表
// init/main.c
asmlinkage __visible void __init start_kernel(void)
{
//...
setup_arch(&command_line); //设置架构
paging_init(mdesc); // arch/arm/kernel/setup.c 页的初始化
devicemaps_init(mdesc); // arch/arm/mm/mmu.c 设备映射,复制异常向量表的关键
vectors = early_alloc(PAGE_SIZE * 2); //1.分配新向量表 8k内存
early_trap_init(vectors); //2.从代码把向量表复制到新向量表
//3.映射新向量表到虚拟地址0xffff0000
map.pfn = __phys_to_pfn(virt_to_phys(vectors)); //物理地址就是上面分配的
map.virtual = 0xffff0000; //虚拟地址,发生异常时会执行vectors
map.length = PAGE_SIZE;
#ifdef CONFIG_KUSER_HELPERS
map.type = MT_HIGH_VECTORS;
#else
map.type = MT_LOW_VECTORS;
#endif
create_mapping(&map);
//...
}
把vectors的向量,复制到对应的地址。
2.2 向量表在哪
上面代码中可以看到代码中向量表位于__vectors_start,它在arch/arm/kernel/vmlinux.lds中定义:
__vectors_start = .;
.vectors 0xffff0000 : AT(__vectors_start) {
*(.vectors)
}
. = __vectors_start + SIZEOF(.vectors);
__vectors_end = .;
__stubs_start = .;
.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) {
*(.stubs)
}
在代码里搜.vectors,可以找到向量表:
三、中断向量
发生中断时,CPU跳到向量表去执行b vector_irq。
vector_irq函数使用宏来定义: