linux源码entry_32.S中interrupt数组的分析
interrupt被定义在arch/x86/kernel/entry_32.S中;
下面,我们来详细理解一下entry_32.S中定义interrupt的这段代码:.section .init.rodata,"a" //定义一个段,.init.rodata表示该段可以被读写操作,"a"表示需要为该段分配内存
ENTRY(interrupt) //定义数据段的入口为interrupt
.text //是告诉连接器,这部分数据是程序代码
.p2align 5 //advances the location counter until it a multiple of 32. If the location counter is already a multiple of 32, no change is needed. //按32字节对齐
///.p2align指定下一行代码的对齐方式,第1参数表示按2的多少次幂字节对齐,第2参数表示对齐是跨越的位置用什么数据来填充,第3字节表示最多允许跨越多少字节。
.p2align CONFIG_X86_L1_CACHE_SHIFT //如果上一行.p2align 5没有执行,那么执行这一条:按2的CONFIG_X86_L1_CACHE_SHIFT次幂的字节对齐,其中CONFIG_X86_L1_CACHE_SHIFT是在内核配置中设定的
ENTRY(irq_entries_start) //代码段的入口定义为irq_entries_start
RING0_INT_FRAME //宏展开:.macro RING0_INT_FRAME //# can't unwind into user space anyway
CFI_STARTPROC simple #define CFI_STARTPROC .cfi_startproc //用在每个函数的开始,用于初始化一些内部数据结构
CFI_SIGNAL_FRAME //#define CFI_SIGNAL_FRAME .cfi_signal_frame;作用和上面一句类似
CFI_DEF_CFA esp, 3*4 #define CFI_DEF_CFA .cfi_def_cfa //定义计算CFA的规则
/*CFI_OFFSET cs, -2*4;*/
CFI_OFFSET eip, -3*4 //#define CFI_OFFSET .cfi_offset //xx reg ,offset reg中的值保存在offset中,offset是CFA的
.endm
NOTE:
通用Flash存储器接口(CFI)是一种由Intel、AMD、Sharp和Fujutsu共同制订的规格,是为了提高由不同的供应商现在或者将来所提供的Flash器件的互换性的工业行业广大成果之一。CFI使得用户只需要一套驱动程序就可以识别并使用各种类型的Flash产品,因为器件的所有识别信息,诸如存储器大小、字节/字配置、块配置、必须的供电电压和时序信息等,都直接保存在芯片上。
vector=FIRST_EXTERNAL_VECTOR //#define FIRST_EXTERNAL_VECTOR 0x20 在irq_verctors.h中,定义了0~31号内部中断
.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7 //.rept表示循环,#define NR_VECTORS 256,为256-32+6=230;230/7=32
.balign 32 //按32字节对齐
NOTE:
.balign[wl] abs-expr, abs-expr, abs-expr
增
加位置计数器(在当前子段)使它指向规定的存储边界。第一个表达式参数(结果必须是纯粹的数字)是必需参数:边界基准,单位为字节。例
如,'.balign
8'向后移动位置计数器直至计数器的值等于8的倍数。如果位置计数器已经是8的倍数,则无需移动。第2个表达式参数(结果必须是纯粹的数字)给出填充字节
的值,用这个值填充位置计数器越过的地方。第2个参数(和逗点)可以省略。如果省略它,填充字节的值通常是0。但在某些系统上,如果本段标识为包含代码,
而填充值被省略,则使用no-op指令填充空白区。第3个参数的结果也必须是纯粹的数字,这个参数是可选的。如果存在第3个参数,它代表本对齐命令允许跳
过字节数的最大值。如果完成这个对齐需要跳过的字节数比规定的最大值还多,则根本无法完成对齐。您可以在边界基准参数后简单地使用两个逗号,以省略填充值
参数(第二参数);如果您在想在适当的时候,对齐操作自动使用no-op指令填充,本方法将非常奏效。
.balignw
和.balignl是.balign命令的变化形式。.balignw使用2个字节来填充空白区。.balignl使用4字节来填充。例
如,.balignw
4,0x368d将地址对齐到4的倍数,如果它跳过2个字节,GAS将使用0x368d填充这2个字节(字节的确切存放位置视处理器的存储方式而定)。
如果它跳过1或3个字节,则填充值不明确。
.rept 7 //加上前面的那个rept,则需要循环32*7=224次,这有点类似于两个for循环,在每次进行内循环时都要进行32字节的对齐操作
.if vector < NR_VECTORS //vector=0x20;NR_VECCTORS=256;
.if vector <> FIRST_EXTERNAL_VECTOR
CFI_ADJUST_CFA_OFFSET -4 //#define CFI_ADJUST_CFA_OFFSET .cfi_adjust_cfa_offset //xx offset 修改计算CFA的规则,修改前面一个offset。达到按4字节对齐
.endif
1: pushl $(~vector+0x80) /* Note: always in signed byte range */ ????
CFI_ADJUST_CFA_OFFSET 4 //4字节对齐
.if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6 //当vector=41,48 等等时,if为假,则不jmp到标号2执行,而这样的情况总共有32次:我不知道为什么??
jmp 2f //数字定义的标号为临时标号,可以任意重复定义,例如:"2f"代表正向第一次出现的标号"2:",3b代表反向第一次出现的标号"3:"
.endif
.previous //.previous使汇编器返回到该自定义段之前的段进行汇编,则回到上面的数据段
.long 1b //在数据段中执行标号1的操作
.text //回到代码段
vector=vector+1 //vector增加1
.endif
.endr
2: jmp common_interrupt
.endr //结束224次循环
END(irq_entries_start) //结束代码段
.previous //返回数据段,结束数据段的interrupt
END(interrupt)
.previous //返回定义数据段之前定义的那个段
common_interrupt:
addl $-0x80,(%esp) /* Adjust vector into the [-256,-1] range */
SAVE_ALL 保存系统寄存器信息
TRACE_IRQS_OFF //在irqflags.h # define TRACE_IRQS_OFF /
jal trace_hardirqs_off
movl %esp,%eax
call do_IRQ
jmp ret_from_intr //返回linux源码entry_32.S中interrupt数组的分析