首页 > 系统相关 >linux中断子系统(一) - 注册系统中断处理函数

linux中断子系统(一) - 注册系统中断处理函数

时间:2022-10-31 17:38:58浏览次数:32  
标签:IRQ set 中断 irq init linux irqno arch 处理函数



重要的宏

内核中使用宏MACHINE_START、MACHINE_END来定义一个machine_desc结构,machine_desc中定义了:机器类型,起始I/O物理地址,bootloader传入的参数地址,中断初始化函数,I/O映射函数等,在文件arch/arm/mach-s3c2440/mach-mini2440.c中

MACHINE_START(MINI2440, "FriendlyARM Mini2440 development board")
.phys_io = S3C2410_PA_UART,
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
.boot_params = S3C2410_SDRAM_PA + 0x100,

.init_irq = s3c24xx_init_irq,
.map_io = mini2440_map_io,
.init_machine = mini2440_machine_init,
.timer = &s3c24xx_timer,
MACHINE_END

找到宏MACHINE_START定义原型在arch/arm/include/asm/mach/arch.h中

/*
* Set of macros to define architecture features. This is built into
* a table by the linker.
*/
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,

#define MACHINE_END \
};

可以看出,所有的machine_desc结构体都处于”.arch.info.init”段中,根据链接脚本arch/arm/kernel/vmlinux.lds.S,这些machine_desc结构体被链接到起始地址为__arch_info_begin,结束地址为__arch_info_end的地方。


s3c24xx_init_irq

MACHINE_SATRT和MACHINE_END宏定义中有个初始化中断的函数s3c24xx_init_irq,定义在arch/arm/plat-s3c24xx/irq.c文件中

void __init s3c24xx_init_irq(void)
{
/* first, clear all interrupts pending... */
...
/* register the main interrupts */
for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */
switch (irqno) {
/* deal with the special IRQs (cascaded) */
case IRQ_EINT4t7:
case IRQ_EINT8t23:
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, handle_level_irq);
break;

default:
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}
}

/* setup the cascade irq handlers */
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);

/* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
irqdbf("registering irq %d (ext int)\n", irqno);
set_irq_chip(irqno, &s3c_irq_eint0t4);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}

for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {
irqdbf("registering irq %d (extended s3c irq)\n", irqno);
set_irq_chip(irqno, &s3c_irqext_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}

/* register the uart interrupts */
irqdbf("s3c2410: registering external interrupts\n");
for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
irqdbf("registering irq %d (s3c uart0 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart0);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}

for (irqno = IRQ_S3CUART_RX1; irqno <= IRQ_S3CUART_ERR1; irqno++) {
irqdbf("registering irq %d (s3c uart1 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart1);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}

for (irqno = IRQ_S3CUART_RX2; irqno <= IRQ_S3CUART_ERR2; irqno++) {
irqdbf("registering irq %d (s3c uart2 irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_uart2);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}

for (irqno = IRQ_TC; irqno <= IRQ_ADC; irqno++) {
irqdbf("registering irq %d (s3c adc irq)\n", irqno);
set_irq_chip(irqno, &s3c_irq_adc);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
}

irqdbf("s3c2410: registered interrupt handlers\n");
}

对于系统中断的注册,基本就3个函数,后面有文章会详细描述:
set_irq_chip
set_irq_handler
set_irq_chained_handler

以上已经注册了从EINT0开始到INT_ADC的所有中断的系统中断处理函数,另外因为EINT4_7, EINT8_23, INT_UART0, INT_UART1, INT_UART2, INT_ADC还包含子中断,所以他们除了本身要设置系统中断处理函数外,还要设置级联中断处理函数和子中断的系统中断处理函数。

可以看出
a. 对于单一中断,系统中断处理函数注册的一般形式为:
set_irq_chip(irqno, &s3c_irq_chip);
set_irq_handler(irqno, handle_edge_irq);
set_irq_flags(irqno, IRQF_VALID);
b. 对于包含子中断的情况,系统中断处理函数的注册的一般形式:
1) 父中断本身要设置系统中断处理函数
set_irq_chip(IRQ_UART0, &s3c_irq_level_chip);
set_irq_handler(IRQ_UART0, handle_level_irq);
2) 父中断设置级联中断处理函数
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
3) 子中断设置系统中断处理函数
for (irqno = IRQ_S3CUART_RX0; irqno <= IRQ_S3CUART_ERR0; irqno++) {
set_irq_chip(irqno, &s3c_irq_uart0);
set_irq_handler(irqno, handle_level_irq);
set_irq_flags(irqno, IRQF_VALID);
}
实际上,b中step2设置级联中断处理函数已经将b中step1设置的系统中断处理函数给覆盖掉了,他们都是赋值给desc->handle_irq的。所以当父中断来了之后,首先执行的是级联中断处理函数,在级联中断处理函数中根据子中断的情况进行分发,执行对应的子中断系统处理函数。


系统起来何时调用s3c24xx_init_irq

start_kernel
setup_arch(&command_line); (arch/arm/kernel/setup.c)
mdesc = setup_machine(machine_arch_type);
lookup_machine_type//寻找特定mdesc
init_arch_irq = mdesc->init_irq;//使用mdesc->init_irq初始化函数指针init_arch_irq
...
early_irq_init (kernel/irq/handle.c)
init_IRQ (与特定体系结构相关,在arch/arm/kernel/irq.c中)
init_arch_irq

函数指针void (*init_arch_irq)(void) __initdata = NULL;
在setup_arch函数中被初始化为mdesc->init_irq(所以这个init_arch_irq归根到底就是上面的s3c24xx_init_irq),在init_IRQ函数中被调用。

至于在setup_arch函数中lookup_machine_type如何找到特定的struct machine_desc的呢? 在arch/arm/kernel/head-common.S中定义:

__lookup_machine_type:
adr r3, 4b
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
ENDPROC(__lookup_machine_type)

根据uboot中传来的在r1寄存器中的机器类型ID和链接在.arch.info.init段中的machine_desc结构中的成员nr作比较,如果相等,表示找到了匹配的machine_desc结构,于是返回machine_desc的地址(存于r5中),如果__arch_info_begin到__arch_info_end之间的所有nr成员都不等于r1寄存器,则返回0(存于r5中)。


标签:IRQ,set,中断,irq,init,linux,irqno,arch,处理函数
From: https://blog.51cto.com/u_15854579/5810521

相关文章

  • linux字符设备内核源码
    文件位于fs/chr_dev.c重要的结构体structcdev{structkobjectkobj;structmodule*owner;conststructfile_operations*ops;structlist_headlist;......
  • linux内核资料
    Documentation搜集一下看到过的Documentation1、关于gnumakefile的使用说明Documentation/Kbuild/makefiles.txt2、介绍kernel各个参数及其意义Documentation/kernel......
  • PetaLinux 工程中隐藏的Linux特性
    KR260的PetaLinuxBSP工程里,默认使能了Linux内核的OF_OVERLAY等特性。使用PetaLinux配置Linux内核,禁止OF_OVERLAY等特性。在生成的配置文件user_2022-10-31-06-59-00.cfg......
  • linux漏洞修复——tomcat
    检测到的漏洞修复方式一般分为两种:修改配置文件、升级组件规避漏洞,一般紧急规避是选择前一种方式。1.tomcat隐藏版本信息a.cd /usr/tomcat9/lib/cp catalina.jar......
  • javascript日期处理函数的一些问题
    问题1:newDate(字符串)产生的日期对象,在某些情形下,可能会自动增加1天。猜测是和时区有关,浏览器没有默认当前时区?这是一个坑。问题2:setDate()设置日期后不准确的问题。比如......
  • linux文档编辑的命令都有哪些?linux命令详解
    在Linux系统中,所有的操作都是需要执行命令才能完成的,可以说,命令的掌握程度对于Linux运维工程师来说至关重要,本篇文章将为大家介绍几个Linux文档编辑命令,以下是详细的内容:1......
  • Linux下漏洞整改方案
    一.nginx版本漏洞Nginx默认是显示版本号curl-Ihttp://192.168.252.135:8000/----后面为nginx站点地址这样暴露出来的版本号就容易变成攻击者可利用的信息。所以,从安......
  • linux控制cpu占用率
    之前在<编程之美>上提到说控制cpu的使用率使能在任务管理器上画一条正弦线现在下面提供一个在Linux平台上实现的控制cpu频率在某个值​cpu_load.c​​#include<iostream......
  • linux cpu使用率
    限制某个进程的cpu使用率cd/sys/fs/cgroup/cpumkdircg1//在cpu目录下创建一个cpu控制族群,这时会在这个目录下自动生成几个文件,其中,限制cpu使用率主要和两个文件有关:......
  • linux下PS1命令提示符
    PS1PS1就是用来设置命令提示符的环境变量以下是PS1中可以使用的转义字符\d:代表日期,格式为weekdaymonthdate,例如:"MonAug1"\H:完整的主机名称。例如:我的机器名称为......