在start_kernel会存在如下调用
start_kernel
setup_arch
early_trap_init
early_irq_init
init_IRQ
local_irq_enable();
1 中断相关的初始化工作
内核配置选项关于中断子系统的配置如下:
CONFIG_GENERIC_HARDIRQS=y
CONFIG_HAVE_SPARSE_IRQ=y
CONFIG_GENERIC_IRQ_SHOW=y
CONFIG_SPARSE_IRQ=y //support sparse irq numbering
1.1 中断向量表初始化
early_trap_init主要完成将中断向量表(__vectors_start, __vectors_end)和中断入口函数表(__stubs_start, __stubs_end)的相关代码copy到内存0xffff0000或者0x00000000处。
void __init early_trap_init(void)
{
#if defined(CONFIG_CPU_USE_DOMAINS)
unsigned long vectors = CONFIG_VECTORS_BASE;
#else
unsigned long vectors = (unsigned long)vectors_page;
#endif
extern char __stubs_start[], __stubs_end[];
extern char __vectors_start[], __vectors_end[];
extern char __kuser_helper_start[], __kuser_helper_end[];
int kuser_sz = __kuser_helper_end - __kuser_helper_start;
/*
* Copy the vectors, stubs and kuser helpers (in entry-armv.S)
* into the vector page, mapped at 0xffff0000, and ensure these
* are visible to the instruction stream.
*/
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);
memcpy((void *)vectors + 0x1000 - kuser_sz, __kuser_helper_start, kuser_sz);
/*
* Do processor specific fixups for the kuser helpers
*/
kuser_get_tls_init(vectors);
/*
* Copy signal return handlers into the vector page, and
* set sigreturn to be a pointer to these.
*/
memcpy((void *)(vectors + KERN_SIGRETURN_CODE - CONFIG_VECTORS_BASE),
sigreturn_codes, sizeof(sigreturn_codes));
memcpy((void *)(vectors + KERN_RESTART_CODE - CONFIG_VECTORS_BASE),
syscall_restart_code, sizeof(syscall_restart_code));
flush_icache_range(vectors, vectors + PAGE_SIZE);
modify_domain(DOMAIN_USER, DOMAIN_CLIENT);
}
1.2 irq_desc的初始化
内核支持sparse irq,因此early_irq_init对应的代码如下。该函数主要是用来初始化irq_desc结构,该结构使用radix tree组织起来。对不支持sparse irq的系统,irq_desc是以数组的形式组织起来的。
int __init early_irq_init(void)
{
int i, initcnt, node = first_online_node;
struct irq_desc *desc;
init_irq_default_affinity();
/* Let arch update nr_irqs and return the nr of preallocated irqs */
initcnt = arch_probe_nr_irqs();
printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
nr_irqs = IRQ_BITMAP_BITS;
if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
initcnt = IRQ_BITMAP_BITS;
if (initcnt > nr_irqs)
nr_irqs = initcnt;
//完成irq_desc的初始化工作
for (i = 0; i < initcnt; i++) {
desc = alloc_desc(i, node);
set_bit(i, allocated_irqs);
irq_insert_desc(i, desc);
}
return arch_early_irq_init(); //直接返回为0
}
该函数完成irq的亲和性的初始化。
static void __init init_irq_default_affinity(void)
{
alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);
cpumask_setall(irq_default_affinity);
}
static inline void cpumask_setall(struct cpumask *dstp)
{
bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits);
}
该函数完成的功能是设置相应的cpumask位为1。
1.3 中断控制器的初始化(GIC的初始化)
init_IRQ函数完成GIC(Generic Interrupt Controller)的初始化工作。
void __init init_IRQ(void)
{
machine_desc->init_irq();
}
1.4 打开中断
local_irq_enable();
最终调用体系结构相关的代码完成中断的使能工作。针对arm v6以上的体系结构:
/arch/arm/include/asm/Irqflags.h
static inline void arch_local_irq_enable(void)
{
asm volatile(
" cpsie i @ arch_local_irq_enable"
:
:
: "memory", "cc");
}