add 08_Interrupt/11
107
STM32MP157/doc_pic/08_Interrupt/11_异常向量表的安装与调用.md
Normal file
@@ -0,0 +1,107 @@
|
||||
## 异常向量表的安装与调用
|
||||
|
||||
### 1. 回顾中断的发生、处理过程
|
||||
|
||||
* 中断发生的硬件过程
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
* 中断处理的软件处理流程
|
||||
* CPU执行完当前指令,检查到发生了中断,跳到向量表
|
||||
* 保存现场、执行GIC提供的处理函数、恢复现场
|
||||
|
||||
|
||||
|
||||
### 2. 异常向量表的安装
|
||||
|
||||
#### 2.1 复制向量表
|
||||
|
||||
* 汇编代码
|
||||
|
||||
```c
|
||||
// arch\arm\kernel\head.S
|
||||
1. bl __lookup_processor_type
|
||||
......
|
||||
2. bl __create_page_tables
|
||||
3. ldr r13, =__mmap_switched
|
||||
4. b __enable_mmu
|
||||
b __turn_mmu_on
|
||||
mov r3, r13
|
||||
ret r3
|
||||
5. __mmap_switched: // arch\arm\kernel\head-common.S
|
||||
6. b start_kernel
|
||||
```
|
||||
|
||||
|
||||
|
||||
* 复制向量表
|
||||
|
||||
```c
|
||||
start_kernel // init\main.c
|
||||
setup_arch(&command_line); // arch\arm\kernel\setup.c
|
||||
paging_init(mdesc); // arch\arm\mm\mmu.c
|
||||
devicemaps_init(mdesc); // arch\arm\mm\mmu.c
|
||||
vectors = early_alloc(PAGE_SIZE * 2); // 1.分配新向量表
|
||||
early_trap_init(vectors); // 2.从代码把向量表复制到新向量表
|
||||
|
||||
// 3. 映射新向量表到虚拟地址0xffff0000
|
||||
/*
|
||||
* Create a mapping for the machine vectors at the high-vectors
|
||||
* location (0xffff0000). If we aren't using high-vectors, also
|
||||
* create a mapping at the low-vectors virtual address.
|
||||
*/
|
||||
map.pfn = __phys_to_pfn(virt_to_phys(vectors));
|
||||
map.virtual = 0xffff0000;
|
||||
map.length = PAGE_SIZE;
|
||||
#ifdef CONFIG_KUSER_HELPERS
|
||||
map.type = MT_HIGH_VECTORS;
|
||||
#else
|
||||
map.type = MT_LOW_VECTORS;
|
||||
#endif
|
||||
create_mapping(&map);
|
||||
```
|
||||
|
||||

|
||||
|
||||
#### 2.2 向量表在哪
|
||||
|
||||
上面代码中可以看到代码中向量表位于`__vectors_start`,它在`arch/arm/kernel/vmlinux.lds`中定义:
|
||||
|
||||
```shell
|
||||
__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`,可以找到向量表:
|
||||
|
||||

|
||||
|
||||
### 3. 中断向量
|
||||
|
||||
发生中断时,CPU跳到向量表去执行`b vector_irq`。
|
||||
|
||||
vector_irq函数使用宏来定义:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 4. 处理流程
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 5. 处理函数
|
||||
|
||||

|
||||
81
STM32MP157/doc_pic/08_Interrupt/12_GIC驱动程序分析.md
Normal file
@@ -0,0 +1,81 @@
|
||||
## GIC驱动程序分析
|
||||
|
||||
参考资料:
|
||||
|
||||
* [linux kernel的中断子系统之(七):GIC代码分析](http://www.wowotech.net/irq_subsystem/gic_driver.html)
|
||||
|
||||
### 1. 回顾
|
||||
|
||||
|
||||
|
||||
### 2. 函数调用过程
|
||||
|
||||
```c
|
||||
start_kernel (init\main.c)
|
||||
init_IRQ (arch\arm\kernel\irq.c)
|
||||
irqchip_init (drivers\irqchip\irqchip.c)
|
||||
of_irq_init (drivers\of\irq.c)
|
||||
desc->irq_init_cb = match->data;
|
||||
|
||||
ret = desc->irq_init_cb(desc->dev,
|
||||
desc->interrupt_parent);
|
||||
|
||||
```
|
||||
|
||||
#### 2.1 platform_driver支持多个device
|
||||
|
||||
按照设备树的套路:驱动程序注册platform_driver,它的of_match_table里有多个of_device_id,表示能支持多个设备。
|
||||
|
||||
有多种版本的GIC,在内核为每一类GIC定义一个结构体of_device_id,并放在一个段里:
|
||||
|
||||
```c
|
||||
// drivers\irqchip\irq-gic.c
|
||||
IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
|
||||
IRQCHIP_DECLARE(arm11mp_gic, "arm,arm11mp-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,arm1176jzf-devchip-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
|
||||
IRQCHIP_DECLARE(msm_8660_qgic, "qcom,msm-8660-qgic", gic_of_init);
|
||||
IRQCHIP_DECLARE(msm_qgic2, "qcom,msm-qgic2", gic_of_init);
|
||||
IRQCHIP_DECLARE(pl390, "arm,pl390", gic_of_init);
|
||||
```
|
||||
|
||||
把宏`IRQCHIP_DECLARE`展开:
|
||||
|
||||
```c
|
||||
// include\linux\irqchip.h
|
||||
#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
|
||||
|
||||
#define OF_DECLARE_2(table, name, compat, fn) \
|
||||
_OF_DECLARE(table, name, compat, fn, of_init_fn_2)
|
||||
|
||||
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
|
||||
static const struct of_device_id __of_table_##name \
|
||||
__used __section(__##table##_of_table) \
|
||||
= { .compatible = compat, \
|
||||
.data = (fn == (fn_type)NULL) ? fn : fn }
|
||||
```
|
||||
|
||||
展开示例:
|
||||
|
||||
```c
|
||||
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
|
||||
展开后得到:
|
||||
static const struct of_device_id __of_table_cortex_a7_gic \
|
||||
__used __section(__irqchip_of_table) \
|
||||
= { .compatible = "arm,cortex-a7-gic", \
|
||||
.data = gic_of_init }
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### 2.2 没有定义platform_driver但是套路一样
|
||||
|
||||
`drivers\irqchip\irqchip.c`中并没有定义一个platform_driver,但是套路是一样的。
|
||||
|
||||

|
||||
|
||||
调用过程:
|
||||
|
||||

|
||||
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 425 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 163 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 153 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 24 KiB |