网站建设有哪几种形式,最近最新在线观看免费高清完整版,wordpress安装好怎么设置,网站建设哪些会影响价格1 中断概念的引入与处理流程
1.1 中断处理框图 1.2 中断程序的使用
主函数()
while(1)
{do_routine_task();
}中断处理函数()
{handle_interrupt_task();
}如何调用中断处理函数#xff1f; 1.3 ARM对异常(中断)的处理过程
#xff08;1#xff09;初始化
① 设置中断…1 中断概念的引入与处理流程
1.1 中断处理框图 1.2 中断程序的使用
主函数()
while(1)
{do_routine_task();
}中断处理函数()
{handle_interrupt_task();
}如何调用中断处理函数 1.3 ARM对异常(中断)的处理过程
1初始化
① 设置中断源让它可以产生中断
② 设置中断控制器设置屏蔽设置优先级
③ 设置CPU总开关使能中断
2执行常规程序主函数
3产生中断按下按键 — 中断控制器 — CPU
4CPU每执行完一条指令都会检查有无中断异常发生
5发现有异常/中断发生开始处理对于不同的异常跳去不同的地址执行程序。
这些地址上只是一条跳转指令跳去执行某个函数。 6这些函数执行以下工作 2 Linux对中断处理的框架及代码流程简述
2.1 中断处理中汇编相关的部分
2.1.1 异常向量入口: arch\arm\kernel\entry-armv.S .section .vectors, ax, %progbits
.L__vectors_start:W(b) vector_rstW(b) vector_undW(ldr) pc, .L__vectors_start 0x1000W(b) vector_pabtW(b) vector_dabtW(b) vector_addrexcptnW(b) vector_irq // 中断向量入口W(b) vector_fiq2.1.2 中断向量: vector_irq
/** Interrupt dispatcher*/vector_stub irq, IRQ_MODE, 4 // 相当于 vector_irq: ..., // 它会根据SPSR寄存器的值,// 判断被中断时CPU是处于USR状态还是SVC状态, // 然后调用下面的__irq_usr或__irq_svc.long __irq_usr 0 (USR_26 / USR_32).long __irq_invalid 1 (FIQ_26 / FIQ_32).long __irq_invalid 2 (IRQ_26 / IRQ_32).long __irq_svc 3 (SVC_26 / SVC_32).long __irq_invalid 4.long __irq_invalid 5.long __irq_invalid 6.long __irq_invalid 7.long __irq_invalid 8.long __irq_invalid 9.long __irq_invalid a.long __irq_invalid b.long __irq_invalid c.long __irq_invalid d.long __irq_invalid e.long __irq_invalid f
2.1.3 __irq_usr/__irq_svc 这2个函数的处理过程类似:
保存现场调用 irq_handler恢复现场
2.1.4 irq_handler: 将会调用C函数 handle_arch_irq .macro irq_handler
#ifdef CONFIG_GENERIC_IRQ_MULTI_HANDLERldr r1, handle_arch_irqmov r0, spbadr lr, 9997fldr pc, [r1]
#elsearch_irq_handler_default
#endif
9997:.endm
2.1.5 handle_arch_irq的处理过程
读取寄存器获得中断信息: hwirq把hwirq转换为virq调用 irq_desc[virq].handle_irq
[注意] 对于S3C2440s3c24xx_handle_irq 是用于处理中断的C语言入口函数
2.2 中断处理流程总结
1中断处理流程: 假设中断结构如下: sub int controller --- int controller --- cpu
2发生中断时, cpu跳到vector_irq, 保存现场, 调用C函数handle_arch_irq
3handle_arch_irq:
① 读 int controller, 得到hwirq ② 根据hwirq得到virq ③ 调用 irq_desc[virq].handle_irq
4如果该中断没有子中断, irq_desc[virq].handle_irq的操作:
① 取出irq_desc[virq].action链表中的每一个handler, 执行它
② 使用irq_desc[virq].irq_data.chip的函数清中断
5如果该中断是由子中断产生, irq_desc[virq].handle_irq的操作:
① 读 sub int controller, 得到hwirq
② 根据hwirq得到virq
③ 调用 irq_desc[virq].handle_irq
2.3 图示
1CPU中断号硬件中断号 2硬件中断号转换到虚拟中断号的过程 3中断函数调用过程 3 中断号的演变与irq_domain 以前中断号(virq)跟硬件密切相关现在的趋势是中断号跟硬件无关仅仅是一个标号而已。
3.1 以前的中断号映射方法 以前对于每一个硬件中断(hwirq)都预先确定它的中断号(virq)这些中断号一般都写在一个头文件里比如arch\arm\mach-s3c24xx\include\mach\irqs.h使用时
1执行 request_irq(virq, my_handler) : 内核根据virq可以知道对应的硬件中断然后去设置、使能中断等。
2发生硬件中断时 内核读取硬件信息确定hwirq反算出virq然后调用 irq_desc[virq].handle_irq, 最终会用到my_handler。 怎么根据hwirq计算出virq 硬件上有多个intc(中断控制器)对于同一个hwirq数值会对应不同的virq。所以在讲hwirq时应该强调是哪一个intc的hwirq在描述hwirq转换为virq时引入一个概念irq_domain域在这个域里hwirq转换为某一个virq。
3.2 新的中断号映射方法
1当中断控制器越来越多、当中断越来越多上述方法(virq和hwirq固定绑定)有缺陷
增加工作量, 你需要给每一个中断确定它的中断号, 写出对应的宏, 可能有成百上千个你要确保每一个硬件中断对应的中断号互不重复
2有什么方法改进
① hwirq跟virq之间不再绑定
② 要使用某个hwirq时先在irq_desc数组中找到一个空闲项, 它的位置就是virq再在irq_desc[virq]中放置处理函数。
3新中断体系中, 怎么使用中断
① 以前是request_irq发起现在是先在设备树文件中声明想使用哪一个中断(哪一个中断控制器下的哪一个中断)
② 内核解析设备树时会根据中断控制器确定irq_domain根据哪一个中断确定hwirq然后在irq_desc数组中找出一个空闲项它的位置就是virq。并且把virq和hwirq的关系保存在irq_domain中irq_domain.linear_revmap[hwirq] virq;
③ 驱动程序 request_irq(virq, my_handler)
④ 发生硬件中断时内核读取硬件信息确定hwirq确定 virq irq_domain.linear_revmap[hwirq]然后调用 irq_desc[virq].handle_irq最终会用到my_handler
4假设要使用子中断控制器(subintc)的n号中断, 它发生时会导致父中断控制器(intc)的m号中断
① 设备树表明要使用subintc nsubintc表示要使用intc m
② 解析设备树时会为subintc n找到空闲项 irq_desc[virq]sub irq_domain.linear_revmap[n] virq会为intc m 找到空闲项 irq_desc[virq]irq_domain.linear_revmap[m] virq并且设置它的handle_irq为某个分析函数demux_func。
③ 驱动程序 request_irq(virq, my_handler)
④ 发生硬件中断时内核读取intc硬件信息确定hwirq m确定 virq irq_domain.linear_revmap[m]然后调用 irq_desc[m].handle_irq, 即demux_func
⑤ demux_func读取sub intc硬件信息确定hwirq n确定 virq sub irq_domain.linear_revmap[n]然后调用 irq_desc[n].handle_irq, 即my_handler
补充图示
1触发INT4_7中断中的EINT4子中断 2使用子中断EINT4的过程 3注册的中断处理函数保存在irq_desc数组中 4S3C2440中的子中断 4 示例_在S3C2440上使用设备树描述中断体验
4.1 笔记 所用文件在: doc_and_sources_for_device_tree\source_and_images\第5,6课的源码及映像文件(使用了完全版的设备树)\内核补丁及设备树。
先解压原始内核(source_and_images\kernel):
tar xzf linux-4.19-rc3.tar.gz
打上补丁:
cd linux-4.19-rc3
patch -p1 ../linux-4.19-rc3_device_tree_for_irq_jz2440.patch
在内核目录下执行:
export PATHPATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bincp config_ok .config
make uImage // 生成 arch/arm/boot/uImage
make dtbs // 生成 arch/arm/boot/dts/jz2440_irq.dtb
老内核:
/ # cat /proc/interruptsCPU029: 17593 s3c 13 Edge samsung_time_irq42: 0 s3c 26 Edge ohci_hcd:usb143: 0 s3c 27 Edge s3c2440-i2c.074: 86 s3c-level 0 Edge s3c2440-uart75: 561 s3c-level 1 Edge s3c2440-uart83: 0 s3c-level 9 Edge ts_pen84: 0 s3c-level 10 Edge adc87: 0 s3c-level 13 Edge s3c2410-wdt
新内核
nfs 30000000 192.168.1.124:/work/nfs_root/uImage;
nfs 32000000 192.168.1.124:/work/nfs_root/jz2440_irq.dtb;
bootm 30000000 - 32000000
/ # cat /proc/interruptsCPU08: 0 s3c 8 Edge s3c2410-rtc tick13: 936 s3c 13 Edge samsung_time_irq30: 0 s3c 30 Edge s3c2410-rtc alarm32: 15 s3c-level 32 Level 50000000.serial33: 60 s3c-level 33 Level 50000000.serial59: 0 s3c-level 59 Edge 53000000.watchdog
1某个设备要使用中断, 需要在设备树中描述中断, 如何? 它要用哪一个中断这个中断连接到哪一个中断控制器去即: 使用哪一个中断控制器的哪一个中断至少有有2个属性
interrupts // 表示要使用哪一个中断, 中断的触发类型等
interrupt-parent // 这个中断要接到哪一个设备去? 即父中断控制器是谁
2上述的interrupts属性用多少个u32来表示? 这应该由它的父中断控制器来描述在父中断控制器中, 至少有2个属性
interrupt-controller; // 表示自己是一个中断控制器
#interrupt-cells // 表示自己的子设备里应该有几个U32的数据来描述中断
4.2 图示 5 示例_使用设备树描述按键中断
5.1 笔记 在设备树的设备节点中描述“中断的硬件信息”表明使用了”哪一个中断控制器里的哪一个中断及中断触发方式“设备节点会被转换为 platform_device“中断的硬件信息”会转换为中断号保存在platform_device的中断资源里驱动程序从platform_device的中断资源取出中断号就可以request_irq了。
实验
1把002th_buttons_drv/jz2440_irq.dts 放入内核 arch/arm/boot/dts目录在内核根目录下执行
make dtbs // 得到 arch/arm/boot/dts/jz2440_irq.dtb
使用上节视频的uImage或这个jz2440_irq.dtb启动内核。
2编译、测试驱动
① 把 002th_buttons_drv 上传到ubuntu
② 编译驱动:
export PATHPATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/system/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabi/bincd 002th_buttons_drv
make // 得到 buttons.ko
③ 编译测试程序:
export PATH/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/local/arm/4.3.2/bincd 002th_buttons_drvarm-linux-gcc -o buttons_test buttons_test.c
④ 测试
insmod buttons.ko
./buttons_test
然后按键
5.2 图示
1图1 2图2 3图3 4图4 6 内核对设备树中断信息的处理过程
6.1 笔记
6.1.1 第一部分 从硬件结构上看处理过程分上下两个层面中断控制器使用中断的设备从软件结构上看处理过程分左右两个部分在设备树中描述信息在驱动中处理设备树。
1中断控制器这又分为root irq controllergpf 和 gpg irq controller
① root irq controller
在设备树中的描述在内核中的驱动
② 对于S3C2440, 还有: gpf/gpg irq controller
在设备树中的描述(在pinctrl节点里)在内核中的驱动 (在pinctrl驱动中)
2设备的中断
在设备节点中描述(表明使用哪一个中断控制器里的哪一个中断, 及中断触发方式)在内核中的驱动 (在platform_driver.probe中获得IRQ资源, 即中断号)
6.1.2 irq_domain是核心
1每一个中断控制器都有一个irq_domain
2对设备中断信息的解析,
① 需要调用 irq_domain-ops-xlate 即从设备树中获得hwirqtype
② 获取未使用的virq保存irq_domain-linear_revmap[hwirq] virq
③ 在hwirq和virq之间建立联系要调用 irq_domain-ops-map比如根据hwirq的属性设置virq的中断处理函数(是一个分发函数还是可以直接处理中断)
irq_desc[virq].handle_irq 常规函数;
如果这个hwirq有上一级中断假设它的中断号为virq还要设置
irq_desc[virq].handle_irq 中断分发函数;
6.1.3 s3c2440设备树中断相关代码调用关系
1上述处理过程如何触发?
① 内核启动时初始化中断的入口
start_kernel // init/main.cinit_IRQ();if (IS_ENABLED(CONFIG_OF) !machine_desc-init_irq)irqchip_init(); // 一般使用它elsemachine_desc-init_irq();
② 设备树中的中断控制器的处理入口irqchip_init // drivers/irqchip/irqchip.c of_irq_init(__irqchip_of_table); // 对设备树文件中每一个中断控制器节点, 调用对应的处理函数为每一个符合的interrupt-controller节点,分配一个of_intc_desc结构体, desc-irq_init_cb match-data; // IRQCHIP_DECLARE中传入的函数并调用处理函数(先调用root irq controller对应的函数, 再调用子控制器的函数, 再调用更下一级控制器的函数...)
2root irq controller 的驱动调用过程
① 为root irq controller定义处理函数
IRQCHIP_DECLARE(s3c2410_irq, samsung,s3c2410-irq, s3c2410_init_intc_of); //drivers/irqchip/irq-s3c24xx.c
其中
#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 }
展开为 static const struct of_device_id __of_table_s3c2410_irq \__used __section(__irqchip_of_table) \ { .compatible samsung,s3c2410-irq, \.data s3c2410_init_intc_of }
它定义了一个of_device_id结构体, 段属性为__irqchip_of_table, 在编译内核时这些段被放在__irqchip_of_table地址处。 即__irqchip_of_table起始地址处, 放置了一个或多个 of_device_id, 它含有compatible成员; 设备树中的设备节点含有compatible属性, 如果双方的compatible相同, 并且设备节点含有interrupt-controller属性, 则调用of_device_id中的函数来处理该设备节点。
所以: IRQCHIP_DECLARE 是用来声明设备树中的中断控制器的处理函数。
② root irq controller处理函数的执行过程
s3c2410_init_intc_of // drivers/irqchip/irq-s3c24xx.c// 初始化中断控制器: intc, subintcs3c_init_intc_of(np, interrupt_parent, s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));// 为中断控制器创建irq_domaindomain irq_domain_add_linear(np, num_ctrl * 32,s3c24xx_irq_ops_of, NULL);intc-domain domain;// 设置handle_arch_irq, 即中断处理的C语言总入口函数set_handle_irq(s3c24xx_handle_irq); (3) pinctrl系统中gpf/gpg irq controller的驱动调用过程
pinctrl系统的驱动程序
① 源代码: drivers/pinctrl/samsung/pinctrl-samsung.c
static struct platform_driver samsung_pinctrl_driver {.probe samsung_pinctrl_probe,.driver {.name samsung-pinctrl,.of_match_table samsung_pinctrl_dt_match, // 含有 { .compatible samsung,s3c2440-pinctrl, .data s3c2440_of_data },.suppress_bind_attrs true,.pm samsung_pinctrl_pm_ops,},
};
② 设备树中
pinctrl56000000 {reg 0x56000000 0x1000;compatible samsung,s3c2440-pinctrl; // 据此找到驱动
③ 驱动中的操作
samsung_pinctrl_probe // drivers/pinctrl/samsung/pinctrl-samsung.c
最终会调用到 s3c24xx_eint_init // drivers/pinctrl/samsung/pinctrl-s3c24xx.c // eint0,1,2,3的处理函数在处理root irq controller时已经设置; // 设置eint4_7, eint8_23的处理函数(它们是分发函数)for (i 0; i NUM_EINT_IRQ; i) {unsigned int irq;if (handlers[i]) /* add by weidongshanqq.com, 不再设置eint0,1,2,3的处理函数 */{irq irq_of_parse_and_map(eint_np, i);if (!irq) {dev_err(dev, failed to get wakeup EINT IRQ %d\n, i);return -ENXIO;}eint_data-parents[i] irq;irq_set_chained_handler_and_data(irq, handlers[i], eint_data);}}// 为GPF、GPG设置irq_domainfor (i 0; i d-nr_banks; i, bank) {ops (bank-eint_offset 0) ? s3c24xx_gpf_irq_ops: s3c24xx_gpg_irq_ops;bank-irq_domain irq_domain_add_linear(bank-of_node, bank-nr_pins, ops, ddata);}
(4) 使用中断的驱动调用过程
① 在设备节点中描述表明使用哪一个中断控制器里的哪一个中断及中断触发方式”比如 buttons {compatible jz2440_button;eint-pins gpf 0 0, gpf 2 0, gpg 3 0, gpg 11 0;interrupts-extended intc 0 0 0 3,intc 0 0 2 3,gpg 3 3,gpg 11 3;};
② 设备节点会被转换为 platform_device 中断的硬件信息 会转换为中断号保存在platform_device的中断资源里。device_node转换为platform_device, 讲解了设备树中设备节点转换为 platform_device 的过程这里我们只关心里面对中断信息的处理of_device_alloc (drivers/of/platform.c) dev platform_device_alloc(, PLATFORM_DEVID_NONE); // 分配 platform_devicenum_irq of_irq_count(np); // 计算中断数of_irq_to_resource_table(np, res, num_irq) // drivers/of/irq.c, 根据设备节点中的中断信息, 构造中断资源of_irq_to_resourceint irq of_irq_get(dev, index); // 获得virq, 中断号rc of_irq_parse_one(dev, index, oirq); // drivers/of/irq.c, 解析设备树中的中断信息, 保存在of_phandle_args结构体中domain irq_find_host(oirq.np); // 查找irq_domain, 每一个中断控制器都对应一个irq_domainirq_create_of_mapping(oirq); // kernel/irq/irqdomain.c, 创建virq和中断信息的映射irq_create_fwspec_mapping(fwspec);irq_create_fwspec_mapping(fwspec);irq_domain_translate(domain, fwspec, hwirq, type) // 调用irq_domain-ops-xlate, 把设备节点里的中断信息解析为hwirq, typevirq irq_find_mapping(domain, hwirq); // 看看这个hwirq是否已经映射, 如果virq非0就直接返回virq irq_create_mapping(domain, hwirq); // 否则创建映射virq irq_domain_alloc_descs(-1, 1, hwirq, of_node_to_nid(of_node), NULL); // 返回未占用的virqirq_domain_associate(domain, virq, hwirq) // 调用irq_domain-ops-map(domain, virq, hwirq), 做必要的硬件设置
5驱动程序从platform_device的中断资源取出中断号, 就可以request_irq了
6.2 图示
1图1 2图2 3图3 后面稍微有点潦草了哈~~~