免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1261 | 回复: 0
打印 上一主题 下一主题

[原创]Linux arm 启动 c语言部分详解第四讲 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-12-16 12:01 |只看该作者 |倒序浏览

Linux arm 启动 c语言部分详解第四讲(from setup_per_cpu_areas();)
Written by leeming
上面的setup_arch花了我们大量的篇幅,现在我们要继续往前推进了。
注:黑色为主线,蓝色为函数的一级展开,红色是注意重要的地方。
//因为我们没有定义CONFIG_SMP,所以这两个函数都为空
       setup_per_cpu_areas();
       smp_prepare_boot_cpu();

       /*
        * 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.
        */
       //和进程初始化有关的函数,进程是任何操作系统的一个大点,因此这部分内容还是很多的,我这次主要是讲解c语言的启动,所以这部分暂时会比较浅的涉及,以后有机会也详细谈到
       sched_init();
{
       runqueue_t *rq;
       int i, j, k;

       for_each_cpu(i) {
              prio_array_t *array;
              //获取每个cpu的运行队列结构体runqurere_t
              rq = cpu_rq(i);
              spin_lock_init(&rq->lock);
              
              rq->nr_running = 0;//该队列中可运行的进程数

              //prio_array_t *active, *expired, arrays[2];
              rq->active = rq->arrays;
              rq->expired = rq->arrays + 1;
              rq->best_expired_prio = MAX_PRIO;

              /*此处删除了smp的内容*/
              
              atomic_set(&rq->nr_iowait, 0);

              //初始化active和expired队列位图,将优先队列中的0-(MAX_PRIO-1)清0
              //将MAX_PRIO对应的置1
              for (j = 0; j
                     array = rq->arrays + j;
                     for (k = 0; k
                            INIT_LIST_HEAD(array->queue + k);
                            __clear_bit(k, array->bitmap);
                     }
                     // delimiter for bitsearch
                     __set_bit(MAX_PRIO, array->bitmap);
              }
       }

       /*
        * The boot idle thread does lazy MMU switching as well:
        */
       atomic_inc(&init_mm.mm_count);
       //啥都没做
       enter_lazy_tlb(&init_mm, current);

       /*
        * Make us the idle thread. Technically, schedule() should not be
        * called from this thread, however somewhere below it might be,
        * but because we are the idle thread, we just pick up running again
        * when this runqueue becomes "idle".
        */
        //初始化当前进程,也就是idle进程
       init_idle(current, smp_processor_id());
}
/*
        * Disable preemption - early bootup scheduling is extremely
        * fragile until we cpu_idle() for the first time.
        */
        //禁止抢占,原因如上
       preempt_disable();
      
       build_all_zonelists();
       //处理器热插拔时的失控函数,类似变频时相应的驱动模块做出的反应,显然嵌入式中不可能用到
       page_alloc_init();
//打印启动参数,也就是我们再setup_arch中获得的参数,这里只是打印,对参数的分析就在printk下面
       printk(KERN_NOTICE "Kernel command line: %s\n", saved_command_line);
       //再次分析参数,之前在setup_arch里面也做了一次,但那次只是得到我们的内存信息
       parse_early_param();
       parse_args("Booting kernel", command_line, __start___param,
                 __stop___param - __start___param,
                 &unknown_bootoption);
      
       sort_main_extable();
       //将中断向量表所在的区域(链接的时候的位置不可能是0xffff0000)的内容搬运至0xffff0000;将中断处理部分的代码搬运至0xffff0200处。
       trap_init();
       rcu_init();
       init_IRQ();
{
       struct irqdesc *desc;
       int irq;

#ifdef CONFIG_SMP
       bad_irq_desc.affinity = CPU_MASK_ALL;
       bad_irq_desc.cpu = smp_processor_id();
#endif

       //NR_IRQS在我们的4020中定义为32个中断,arm本身最多支持128个
       for (irq = 0, desc = irq_desc; irq
       //将这些中断初始化为bad_irq_desc
              *desc = bad_irq_desc;
              INIT_LIST_HEAD(&desc->pend);
       }

       //init_arch_irq是一个全局的函数指针,它初始化的时候是一个空函数
       //但是在setup_arch中把它指向了我们4020的函数,init_arch_irq = mdesc->init_irq;
       //也就是在arch/arm/mach-sep4020/irq.c中的sep4020_init_irq,这里重新对我们所有的中断进行初始化
       init_arch_irq();
}
pidhash_init();
       init_timers();
{
              //这个函数就是timers_nb这个结构体的call函数
       timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
                            (void *)(long)smp_processor_id());
       //这个是用的机制和cpufreq的机制是一样的,通过notifier_chain_register(&cpu_chain, nb)注册的;
       //只不过这里的链是cpu_chain,而cpufreq是其他的链
       register_cpu_notifier(&timers_nb);
       //设置软中断行动函数描述结构变量softirq_vec[=1](系统定时器)的设置
       //也就是设置timer定时器到期之后的处理函数
       open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
}
       //其中函数 hrtimers_init() 和高精度时钟相关
       hrtimers_init();
       //和init_timers最后部分是softirq类似,只不过在那里是初始化=1的时候;
       //在softirq_init中是初始化=6, =0的情况,对于整个软中断来说有以下几种情况
       /*    enum
       {
       HI_SOFTIRQ=0,
       TIMER_SOFTIRQ,
       NET_TX_SOFTIRQ,
       NET_RX_SOFTIRQ,
       BLOCK_SOFTIRQ,
       TASKLET_SOFTIRQ
       };*/
       softirq_init();

       //调用arch/arm/kernel/time.c中的time_init;它首先会检查system_timer这个全局结构体的偏移是否为空
       //system_timer和我们之前在init_IRQ中提到的init_arch_irq类似,也是在setup_arch中赋值的
       //system_timer = mdesc->timer;所以之前一直强调setup_arch是一个非常重要的函数,和我们处理器的移植紧密相关的
       time_init();


至此,虽然start_kernel的函数只分析了一小部分,但是和平台和处理器相关的部分已经基本完毕,相信看完了这几讲,你会清楚的知道对于arch/arm/mach-sep4020中的那些文件为什么要那么写,是不是可以优化(肯定可以),知其然,知其所以然。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/99423/showart_2122678.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP