移植Linux内核平台相关之 中断

Will0 2011-04-30

前言:

在移植Linux的时候,需要加入一段平台相关的代码。而在这部分代码中,中断是一个重要的环节。所以我们需要去了解linux内核的中断处理结构是怎样的,然后才能在适当的地方加上平台相关的代码。在不同的linux内核版本中,可能中断处理的结构不尽相同,这就要具体问题具体去分析了,本文主要是介绍在移植linux2.6.38.4到龙芯soc3210的时候,得出的一些关于中断处理的经验和体会,在此分享。

从./init/main.c中的start_kernel开始

init_IRQ为初始化中断IRQ的函数入口,进入之后,可以看到:

arch_init_irq()

从函数名可以看出,该函数是与平台相关的,也就是我们需要实现的函数。

然而,我们需要怎样去实现这个函数呢,也就是说,要在这个函数里干些什么事呢,这就是移植的重点,也是本文的重点。

根据龙芯3210的设计(实际上就是MIPS的中断设计)上分析中断的处理过程:

CPU发生中断后,首先会跳转到异常入口地址,如果是中断,那么开始执行中断处理。在中断处理里,读取原因寄存器cause,判断IP位是否有置位的,再根据IP7~IP0的的不同置位去执行不同类型的中断例程,在同一种类型的中断处理里,又根据中断状态寄存器来判断具体发生了什么中断,然后再去执行这个中断的服务程序。

根据以上的处理过程,看linux的代码的实现过程:

在trap_init函数里设置异常处理代码:

set_handler(0x180, &except_vec3_generic, 0x80);

把except_vec3_generic函数指针放在地址为CKSEG0 + 0x180处,这个地址就是中断异常的入口地址。

再来看except_vec3_generic函数,这是一个汇编函数,在./arch/mips/kernel/genex.S中定义:

 52 NESTED(except_vec3_generic, 0, sp)
 53         .set    push
 54         .set    noat
 55 #if R5432_CP0_INTERRUPT_WAR
 56         mfc0    k0, CP0_INDEX       
 57 #endif
 58         mfc0    k1, CP0_CAUSE       
 59         andi    k1, k1, 0x7c
 60 #ifdef CONFIG_64BIT
 61         dsll    k1, k1, 1
 62 #endif
 63         PTR_L   k0, exception_handlers(k1)  
 64         jr      k0
 65         .set    pop
 66         END(except_vec3_generic)

从代码中可以看出,读取Cause寄存器中的ExcCode的值,以此为索引,从数组exception_handlers中找到要执行的处理例程的函数指针并执行,如果是中断异常,索引为0,也就是执行exception_handlers[0]函数。

从函数except_vec3_generic中可以知道,现在需要给exception_handlers[0]赋值,在trap_init函数中:

set_except_vector(0, rollback ? rollback_handle_int : handle_int);

其中rollback为0,也就是说exception_handlers[0] = handle_int。

再来看handle_int:

164         .align  5
165 BUILD_ROLLBACK_PROLOGUE handle_int
166 NESTED(handle_int, PT_SIZE, sp)
167 #ifdef CONFIG_TRACE_IRQFLAGS
168         /*
169          * Check to see if the interrupted code has just disabled
170          * interrupts and ignore this interrupt for now if so.
171          *
172          * local_irq_disable() disables interrupts and then calls
173          * trace_hardirqs_off() to track the state. If an interrupt is taken
174          * after interrupts are disabled but before the state is updated
175          * it will appear to restore_all that it is incorrectly returning with
176          * interrupts disabled
177          */
178         .set    push
179         .set    noat
180         mfc0    k0, CP0_STATUS
181 #if defined(CONFIG_CPU_R3000) || defined(CONFIG_CPU_TX39XX)
182         and     k0, ST0_IEP
183         bnez    k0, 1f
184
185         mfc0    k0, CP0_EPC
186         .set    noreorder
187         j       k0
188         rfe
189 #else
190         and     k0, ST0_IE
191         bnez    k0, 1f
192
193         eret
194 #endif
195 1:
196         .set pop
197 #endif
198         SAVE_ALL
199         CLI
200         TRACE_IRQS_OFF
201
202         LONG_L  s0, TI_REGS($28)
203         LONG_S  sp, TI_REGS($28)
204         PTR_LA  ra, ret_from_irq
205         j       plat_irq_dispatch
206         END(handle_int)

可以看到,最后handle_int会跳转到plat_irq_dispatch执行。根据中断处理过程,plat_irq_dispatch要实现中断类型的判断和执行具体的中断服务程序。这些明显是平台相关的,也就是移植中需要实现的平台相关的代码。

相关推荐