AR9331中Linux内核启动中与IRQ中断相关的文件

先列出框架,具体后继再来分析。

首先是lds文件,该文件设置了各个section在FLASH或RAM中的先后顺序。

位于~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/kernel/vmlinux.lds

另外一个名字相似的,~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/kernel/vmlinux.lds.S

...#undef mips
#define mips mips
OUTPUT_ARCH(mips)
ENTRY(kernel_entry)
PHDRS {
    text PT_LOAD FLAGS(7);    /* RWX */
    note PT_NOTE FLAGS(4);    /* R__ */
}

#ifdef CONFIG_32BIT
    #ifdef CONFIG_CPU_LITTLE_ENDIAN
        jiffies     = jiffies_64;
    #else
        jiffies     = jiffies_64 + 4;
    #endif
#else
    jiffies     = jiffies_64;
#endif

SECTIONS
{...

表明入口地址为kernel_entry,该符号在:~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/kernel/head.S中定义

...NESTED(kernel_entry, 16, sp)            # kernel entry point

    kernel_entry_setup            # cpu specific setup

    setup_c0_status_pri

    /* We might not get launched at the address the kernel is linked to,
       so we jump there.  */
    PTR_LA    t0, 0f
    jr    t0
0:

#ifdef CONFIG_MIPS_MT_SMTC
    /*
     * In SMTC kernel, "CLI" is thread-specific, in TCStatus.
     * We still need to enable interrupts globally in Status,
     * and clear EXL/ERL.
     *
     * TCContext is used to track interrupt levels under
     * service in SMTC kernel. Clear for boot TC before
     * allowing any interrupts.
     */
    mtc0    zero, CP0_TCCONTEXT

    mfc0    t0, CP0_STATUS
    ori    t0, t0, 0xff1f
    xori    t0, t0, 0x001e
    mtc0    t0, CP0_STATUS
#endif /* CONFIG_MIPS_MT_SMTC */

    PTR_LA        t0, __bss_start        # clear .bss
    LONG_S        zero, (t0)
    PTR_LA        t1, __bss_stop - LONGSIZE
1:
    PTR_ADDIU    t0, LONGSIZE
    LONG_S        zero, (t0)
    bne        t0, t1, 1b

    LONG_S        a0, fw_arg0        # firmware arguments
    LONG_S        a1, fw_arg1
    LONG_S        a2, fw_arg2
    LONG_S        a3, fw_arg3

    MTC0        zero, CP0_CONTEXT    # clear context register
    PTR_LA        $28, init_thread_union
    /* Set the SP after an empty pt_regs.  */
    PTR_LI        sp, _THREAD_SIZE - 32 - PT_SIZE
    PTR_ADDU    sp, $28
    back_to_back_c0_hazard
    set_saved_sp    sp, t0, t1
    PTR_SUBU    sp, 4 * SZREG        # init stack pointer

    j        start_kernel
    END(kernel_entry)...

最终跳到kernel_entry中,该函数在~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/init/main.c中定义:

asmlinkage void __init start_kernel(void)
{
    char * command_line;
    extern const struct kernel_param __start___param[], __stop___param[];

    /*
     * Need to run as early as possible, to initialize the
     * lockdep hash:
     */
    lockdep_init();
    smp_setup_processor_id();
    debug_objects_early_init();

    /*
     * Set up the the initial canary ASAP:
     */
    boot_init_stack_canary();

    cgroup_init_early();

    local_irq_disable();
    early_boot_irqs_disabled = true;

/*
 * Interrupts are still disabled. Do necessary setups, then
 * enable them
 */
    boot_cpu_init();
    page_address_init();
    pr_notice("%s", linux_banner);
    setup_arch(&command_line);
    mm_init_owner(&init_mm, &init_task);
    mm_init_cpumask(&init_mm);
    setup_command_line(command_line);
    setup_nr_cpu_ids();
    setup_per_cpu_areas();
    smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */

    build_all_zonelists(NULL, NULL);
    page_alloc_init();

    pr_notice("Kernel command line: %s\n", boot_command_line);
    parse_early_param();
    parse_args("Booting kernel", static_command_line, __start___param,
           __stop___param - __start___param,
           -1, -1, &unknown_bootoption);

    jump_label_init();

    /*
     * These use large bootmem allocations and must precede
     * kmem_cache_init()
     */
    setup_log_buf(0);
    pidhash_init();
    vfs_caches_init_early();
    sort_main_extable();
    trap_init();
    mm_init();

    /*
     * Set up the scheduler prior starting any interrupts (such as the
     * timer interrupt). Full topology setup happens at smp_init()
     * time - but meanwhile we still have a functioning scheduler.
     */
    sched_init();
    /*
     * Disable preemption - early bootup scheduling is extremely
     * fragile until we cpu_idle() for the first time.
     */
    preempt_disable();
    if (WARN(!irqs_disabled(), "Interrupts were enabled *very* early, fixing it\n"))
        local_irq_disable();
    idr_init_cache();
    perf_event_init();
    rcu_init();
    tick_nohz_init();
    radix_tree_init();
    /* init some links before init_ISA_irqs() */
    early_irq_init();
    init_IRQ();
    tick_init();
    init_timers();
    hrtimers_init();
    softirq_init();
    timekeeping_init();
    time_init();
    profile_init();
    call_function_init();
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");
    early_boot_irqs_disabled = false;
    local_irq_enable();

    kmem_cache_init_late();

    /*
     * HACK ALERT! This is early. We‘re enabling the console before
     * we‘ve done PCI setups etc, and console_init() must be aware of
     * this. But we do want output early, in case something goes wrong.
     */
    console_init();
    if (panic_later)
        panic(panic_later, panic_param);

    lockdep_info();

    /*
     * Need to run this when irqs are enabled, because it wants
     * to self-test [hard/soft]-irqs on/off lock inversion bugs
     * too:
     */
    locking_selftest();

#ifdef CONFIG_BLK_DEV_INITRD
    if (initrd_start && !initrd_below_start_ok &&
        page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) {
        pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n",
            page_to_pfn(virt_to_page((void *)initrd_start)),
            min_low_pfn);
        initrd_start = 0;
    }
#endif
    page_cgroup_init();
    debug_objects_mem_init();
    kmemleak_init();
    setup_per_cpu_pageset();
    numa_policy_init();
    if (late_time_init)
        late_time_init();
    sched_clock_init();
    calibrate_delay();
    pidmap_init();
    anon_vma_init();
#ifdef CONFIG_X86
    if (efi_enabled(EFI_RUNTIME_SERVICES))
        efi_enter_virtual_mode();
#endif
    thread_info_cache_init();
    cred_init();
    fork_init(totalram_pages);
    proc_caches_init();
    buffer_init();
    key_init();
    security_init();
    dbg_late_init();
    vfs_caches_init(totalram_pages);
    signals_init();
    /* rootfs populating might need page-writeback */
    page_writeback_init();
#ifdef CONFIG_PROC_FS
    proc_root_init();
#endif
    cgroup_init();
    cpuset_init();
    taskstats_init_early();
    delayacct_init();

    check_bugs();

    acpi_early_init(); /* before LAPIC and SMP init */
    sfi_init_late();

    if (efi_enabled(EFI_RUNTIME_SERVICES)) {
        efi_late_init();
        efi_free_boot_services();
    }

    ftrace_init();

    /* Do the rest non-__init‘ed, we‘re now alive */
    rest_init();
}

上面调用了两个IRQ初始化函数early_irq_init和init_IRQ,分别在~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/kernel/irq/irqdesc.c和~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/kernel/irq.c中。

early_irq_init函数

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;

    for (i = 0; i < initcnt; i++) {
        desc = alloc_desc(i, node, NULL);
        set_bit(i, allocated_irqs);
        irq_insert_desc(i, desc);
    }
    return arch_early_irq_init();
}

init_IRQ函数

void __init init_IRQ(void)
{
    int i;

#ifdef CONFIG_KGDB
    if (kgdb_early_setup)
        return;
#endif

    for (i = 0; i < NR_IRQS; i++)
        irq_set_noprobe(i);

    arch_init_irq();

#ifdef CONFIG_KGDB
    if (!kgdb_early_setup)
        kgdb_early_setup = 1;
#endif
}

上面调用的arch_init_irq函数位于~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/ath79/irq.c中

arch_init_irq函数

static void __init ath79_misc_irq_init(void)
{
    void __iomem *base = ath79_reset_base;
    int i;

    __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_ENABLE);
    __raw_writel(0, base + AR71XX_RESET_REG_MISC_INT_STATUS);

    if (soc_is_ar71xx() || soc_is_ar913x())
        ath79_misc_irq_chip.irq_mask_ack = ar71xx_misc_irq_mask;
    else if (soc_is_ar724x() ||
         soc_is_ar933x() ||
         soc_is_ar934x() ||
         soc_is_qca953x() ||
         soc_is_qca955x())
        ath79_misc_irq_chip.irq_ack = ar724x_misc_irq_ack;
    else
        BUG();

    for (i = ATH79_MISC_IRQ_BASE;
         i < ATH79_MISC_IRQ_BASE + ATH79_MISC_IRQ_COUNT; i++) {
        irq_set_chip_and_handler(i, &ath79_misc_irq_chip,
                     handle_level_irq);
    }

    irq_set_chained_handler(ATH79_CPU_IRQ(6), ath79_misc_irq_handler);
}
...
void __init arch_init_irq(void)
{
    if (soc_is_ar71xx()) {
        ath79_ip2_handler = ar71xx_ip2_handler;
        ath79_ip3_handler = ar71xx_ip3_handler;
    } else if (soc_is_ar724x()) {
        ath79_ip2_handler = ar724x_ip2_handler;
        ath79_ip3_handler = ar724x_ip3_handler;
    } else if (soc_is_ar913x()) {
        ath79_ip2_handler = ar913x_ip2_handler;
        ath79_ip3_handler = ar913x_ip3_handler;
    } else if (soc_is_ar933x()) {
        ath79_ip2_handler = ar933x_ip2_handler;
        ath79_ip3_handler = ar933x_ip3_handler;
    } else if (soc_is_ar934x()) {
        ath79_ip2_handler = ath79_default_ip2_handler;
        ath79_ip3_handler = ar934x_ip3_handler;
    } else if (soc_is_qca953x()) {
        ath79_ip2_handler = ath79_default_ip2_handler;
        ath79_ip3_handler = ath79_default_ip3_handler;
    } else if (soc_is_qca955x()) {
        ath79_ip2_handler = ath79_default_ip2_handler;
        ath79_ip3_handler = ath79_default_ip3_handler;
    } else {
        BUG();
    }

    cp0_perfcount_irq = ATH79_MISC_IRQ(5);
    mips_cpu_irq_init();
    ath79_misc_irq_init();

    if (soc_is_ar934x())
        ar934x_ip2_irq_init();
    else if (soc_is_qca955x())
        qca955x_irq_init();
}

mips_cpu_irq_init函数位于~/openwrt1407/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/linux-3.10.49/arch/mips/kernel/irq_cpu.c中,ath79_misc_irq_init同在irq.c文件中。

void __init mips_cpu_irq_init(void)
{
    int irq_base = MIPS_CPU_IRQ_BASE;
    int i;

    /* Mask interrupts. */
    clear_c0_status(ST0_IM);
    clear_c0_cause(CAUSEF_IP);

    /* Software interrupts are used for MT/CMT IPI */
    for (i = irq_base; i < irq_base + 2; i++)
        irq_set_chip_and_handler(i, cpu_has_mipsmt ?
                     &mips_mt_cpu_irq_controller :
                     &mips_cpu_irq_controller,
                     handle_percpu_irq);

    for (i = irq_base + 2; i < irq_base + 8; i++)
        irq_set_chip_and_handler(i, &mips_cpu_irq_controller,
                     handle_percpu_irq);
}
时间: 2025-01-18 07:36:37

AR9331中Linux内核启动中与IRQ中断相关的文件的相关文章

Linux内核启动中显示的logo的修改

1.配置内核 使内核启动时加载logo,在源代码的主目录下make menuconfig Device Drivers  ---> Graphics support  ---> 选上 并 进入 Bootup logo --> 选上 Standard 224-color Linux logo [ * ] 代表选中 [   ]代表未选中 [M]代表编译成模块,使用空格键切换 make重新编译内核,这样启动是就会加载启动logo了. 2.然后就是处理开机图片了. 修改"drivers

第02节:Linux 内核驱动中的指定初始化

2.1 什么是指定初始化 在标准 C 中,当我们定义并初始化一个数组时,常用方法如下: int a[10] = {0,1,2,3,4,5,6,7,8}; 按照这种固定的顺序,我们可以依次给 a[0] 和 a[8] 赋值.因为没有对 a[9] 赋值,所以编译器会将 a[9] 默认设置为0.当数组长度比较小时,使用这种方式初始化比较方便.当数组比较大,而且数组里的非零元素并不连续时,这时候再按照固定顺序初始化就比较麻烦了. 比如,我们定义一个数组 b[100],其中 b[10].b[30] 需要初始

Linux内核启动参数

Linux内核启动参数   Console Options                         参数 说明 选项 内核配置/文件   console=Options 用于说明输出设备 ttyn 终端 ttySn[,options], ttyUSB0[,options] 串口uart,io,addr[,options],uart,mmio,addr[,options]&<60;     netconsole=[src-port]@[src-ip]/[dev],[target-por

linux内核启动第二阶段之setup_arch()函数分析-2.6.36

执行setup_arch()函数 回到start_kernel当中,569行,调用setup_arch函数,传给他的参数是那个未被初始化的内部变量command_line.这个setup_arch()函数是start_kernel阶段最重要的一个函数,每个体系都有自己的setup_arch()函数,是体系结构相关的,具体编译哪个体系的setup_arch()函数,由顶层Makefile中的ARCH变量决定: 它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过 bootmem_init

linux内核启动过程学习总结

下面是学习linux内核启动过程的记录 平台是:powerpc mpc8548 + linux2.6.23 内核 通用寄存器的作用r0 :在函数开始时使用r1 :存放堆栈指针,相当于ia32架构中的esp寄存器r2 :存放当前进程的描述符的地址r3 :存放第一个参数和返回地址r4-r10 :存放函数的参数r11 :用在指针的调用和当前一些语言的环境指针r12 :用于存放异常处理r13 :保留做为系统线程IDr14-r31 :作为本地变量,具有非易失性 Linux启动过程描述 第一步:使用Boot

Linux内核启动及根文件系统载入过程

上接博文<u-boot之u-boot-2009.11启动过程分析> Linux内核启动及文件系统载入过程 当u-boot開始运行bootcmd命令,就进入Linux内核启动阶段.与u-boot类似,普通Linux内核的启动过程也能够分为两个阶段,但针对压缩了的内核如uImage就要包含内核自解压过程了.本文以linux-2.6.37版源代码为例分三个阶段来描写叙述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为

Linux内核启动及文件系统加载过程

上接博文<u-boot之u-boot-2009.11启动过程分析> 当u-boot开始执行bootcmd命令,就进入Linux内核启动阶段,与u-boot类似,普通Linux内核的启动过程也可以分为两个阶段,但针对压缩了的内核如uImage就要包括内核自解压过程了.本文以项目中使用的linux-2.6.37版源码为例分三个阶段来描述内核启动全过程.第一阶段为内核自解压过程,第二阶段主要工作是设置ARM处理器工作模式.使能MMU.设置一级页表等,而第三阶段则主要为C代码,包括内核初始化的全部工作

Linux内核启动

Linux内核启动过程概述 Linux的启动代码真的挺大,从汇编到C,从Makefile到LDS文件,需要理解的东西很多.毕竟Linux内核是由很多人,花费了巨大的时间和精力写出来的.而且直到现在,这个世界上仍然有成千上万的程序员在不断完善Linux内核的代码.今天我们主要讲解的是Linux-2.6.22.6这个内核版本.说句实话,博主也不确定自己能够讲好今天这个题目,因为这个题目太大太难.但是博主有信心,将自己学会的内容清楚地告诉大家,希望大家也能够有所收获. 1.启动文件head.S和hea

Linux内核启动及加载根文件系统

</pre></h1><p><span style="font-family:KaiTi_GB2312;font-size:18px;">上接博文<<a target=_blank href="http://blog.csdn.net/gqb_driver/article/details/8931775" style="text-decoration: none; font-family: 'Mi