免费注册 查看新帖 |

Chinaunix

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

arm-linux(kernel-2.6.13)的启动过程(1.4/2) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-10-10 19:46 |只看该作者 |倒序浏览
arm-linux(kernel-2.6.13)的启动过程(1.4/2)
回到 setup_arch()
    request_standard_resources(&meminfo, mdesc);
在看这段代码前,先学学resource结构体。
/*
* Resources are tree-like, allowing
* nesting etc..
*/resource有点像树形结构,允许像鸟巢那样。
struct resource {
    const char *name;
    unsigned long start, end;
    unsigned long flags;
    struct resource *parent, *sibling, *child;//说的就是这里了,父亲,儿子,兄弟。
};
内容包括,本io资源的名字,起始,结束物理地址,标志(表征该io资源的类型,很多很多类型)。
/*
* Standard memory resources
*/
static struct resource mem_res[] = {
    { "Video RAM",   0,     0,     IORESOURCE_MEM            },
    { "Kernel text", 0,     0,     IORESOURCE_MEM            },
    { "Kernel data", 0,     0,     IORESOURCE_MEM            }
};
#define video_ram   mem_res[0]
#define kernel_code mem_res[1] //内核代码段io资源
#define kernel_data mem_res[2] //内核数据段io资源
request_standard_resources的内容如下:
static void __init
request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc)
{
    struct resource *res;
    int i;
    kernel_code.start   = virt_to_phys(&_text);
    kernel_code.end     = virt_to_phys(&_etext - 1);
    kernel_data.start   = virt_to_phys(&__data_start);
    kernel_data.end     = virt_to_phys(&_end - 1);
取得代码段 数据段 物理地址,这里的代码段不包括init段了,lds里描述说是真正的代码段。
难道init段的内容可以被覆盖???
    for (i = 0; i nr_banks; i++) {
        unsigned long virt_start, virt_end;
        if (mi->bank.size == 0)
            continue;
        virt_start = __phys_to_virt(mi->bank.start); //取得本ram的起始和结束虚拟地址
        virt_end   = virt_start + mi->bank.size - 1;
        res = alloc_bootmem_low(sizeof(*res));
//分配resource结构大小的内存空间,经过页对齐(向上),结构得到了一个内存页,这就是内存的页管理策略。
        res->name  = "System RAM";
        res->start = __virt_to_phys(virt_start);
        res->end   = __virt_to_phys(virt_end);
        res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
为系统的ram也建立了一个资源结构体,表征系统的ram资源。
        request_resource(&iomem_resource, res);
然后申请这个"System RAM"资源,他的总根是iomem_resource
        if (kernel_code.start >= res->start &&
            kernel_code.end end)
            request_resource(res, &kernel_code);
        if (kernel_data.start >= res->start &&
            kernel_data.end end)
            request_resource(res, &kernel_data);
    }
申请内核代码,数据段 所在ram的io资源,他们作为刚才申请的"System RAM"的子资源,也就是
iomem_resource -> "System RAM" -> kernel_code
                                     |
                                  kernel_data
这样的关系,"System RAM"的子资源是kernel_code,kernel_data与kernel_code是sibling关系,他们的parent都是"System RAM"。
    if (mdesc->video_start) {
        video_ram.start = mdesc->video_start;
        video_ram.end   = mdesc->video_end;
        request_resource(&iomem_resource, &video_ram);
    }
如果有视频缓冲区的话,显然arm没有。在后面分析request_resource函数。
可以看出,对io资源的申请,这里不需要验证冲突与否,因为这里肯定不会冲突。
    /*
     * Some machines don't have the possibility of ever
     * possessing lp0, lp1 or lp2
     */
    if (mdesc->reserve_lp0)
        request_resource(&ioport_resource, &lp0);
    if (mdesc->reserve_lp1)
        request_resource(&ioport_resource, &lp1);
    if (mdesc->reserve_lp2)
        request_resource(&ioport_resource, &lp2);
}
看看这个函数
request_resource,在这之前,现看看下面两个resource结构。
struct resource ioport_resource = {
    .name    = "PCI IO",
    .start    = 0x0000,
    .end    = IO_SPACE_LIMIT,
    .flags    = IORESOURCE_IO,
};
#define IO_SPACE_LIMIT 0xffffffff
EXPORT_SYMBOL(ioport_resource);
struct resource iomem_resource = {
    .name    = "PCI mem",
    .start    = 0UL,
    .end    = ~0UL,
    .flags    = IORESOURCE_MEM,
};
EXPORT_SYMBOL(iomem_resource);
static DEFINE_RWLOCK(resource_lock);
上面的两个resource数据结构是io内存,和io端口的总根,其他的io资源都是他们派生出来的。
int request_resource(struct resource *root, struct resource *new)
{
    struct resource *conflict;
    write_lock(&resource_lock); //加写入锁
    conflict = __request_resource(root, new); 这个是主体,在后面
    write_unlock(&resource_lock);
    return conflict ? -EBUSY : 0;
}
/* Return the conflict entry if you can't request it */
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
    unsigned long start = new->start;
    unsigned long end = new->end;
    struct resource *tmp, **p;
    if (end start)
        return root;
    if (end > root->end)
        return root;
申请的资源必须在根resouce的区域内。
    p = &root->child; //取得子资源的地址
    for (;;) {
        tmp = *p; //取得子资源的内容
        if (!tmp || tmp->start > end) {
//如果还没有子资源,那就太好了,直接方进去
//如果有了子资源,但是等待加入到子资源的资源 在现有 子资源的前面,也可以加进来,这时候,子资源的指针,指向刚才加入的那个子资源。
            new->sibling = tmp;
            *p = new;
            new->parent = root;
            return NULL;
        }
到了这里说明待加入的子资源在现有子资源的后面。
        p = &tmp->sibling; //取得现有子资源的兄弟指针
        if (tmp->end child指向 最前面的子资源。
回到 setup_arch()
    cpu_init();
struct stack {
    u32 irq[3];
    u32 abt[3];
    u32 und[3];
} ____cacheline_aligned;
static struct stack stacks[NR_CPUS];
这个stacks是什么时候初始化的呢???
不会全是0吧?
去看看,
c03311ec :
    ...
c0331200 : //可见stacks是256字节对齐的。
c0331248 :
物理地址应该是30331200
lzd> md 0x30331200                                                              
30331200: 00000000 00000000 00000000 00000000    ................   这里就是stacks的内容了            
30331210: 00000000 00000000 00000000 00000000    ................               
30331220: 00000000 00000000 00000000 00000000    ................               
30331230: 00000000 00000000 00000000 00000000    ................               
30331240: c025dada c026b200 6e696f6e 64727469    ..%...&.noinitrd   命令行的内容,没错的         
30331250: 6f6f7220 642f3d74 6d2f7665 6c626474     root=/dev/mtdbl               
30331260: 326b636f 696e6920 6c2f3d74 78756e69    ock2 init=/linux               
30331270: 63206372 6f736e6f 743d656c 41537974    rc console=ttySA               
30331280: 00003043 00000000 00000000 00000000    C0..............
stacks里的内容确实是0。
/*
* cpu_init - initialise one CPU.
*
* cpu_init dumps the cache information, initialises SMP specific
* information, and sets up the per-CPU stacks.
*/
void cpu_init(void)
{
    unsigned int cpu = smp_processor_id(); //单处理器,返回0
    struct stack *stk = &stacks[cpu];
    if (cpu >= NR_CPUS) {
        printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
        BUG();
    }
    dump_cpu_info(cpu);
    /*
     * setup stacks for re-entrant exception handlers
     */
    __asm__ (
    "msr    cpsr_c, %1\n\t" //进入irq模式
    "add    sp, %0, %2\n\t" //设置irq堆栈
    "msr    cpsr_c, %3\n\t" //进入abt模式
    "add    sp, %0, %4\n\t" //设置abt堆栈
    "msr    cpsr_c, %5\n\t"
    "add    sp, %0, %6\n\t"
    "msr    cpsr_c, %7" //返回到管理模式
        :
        : "r" (stk),
          "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
          "I" (offsetof(struct stack, irq[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
          "I" (offsetof(struct stack, abt[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
          "I" (offsetof(struct stack, und[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
        : "r14");
} //我对上面的内容感到苦恼,这些堆栈被设置到那里了阿?可以那样设置吗???
天阿,我发现自己还不知道sp在那里呢?找。
在head.S中
    .long    init_thread_union + THREAD_START_SP @ sp
    ...
    ldmia    r3, {r4, r5, r6, sp} //在这里设置的sp,天啊,当时没弄清楚饿 :-(
    ...
    b    start_kernel
init_thread_union是一个thread_union联合,在这里,他被用作thread_info结构体,并得到了初始化。
union thread_union init_thread_union
    __attribute__((__section__(".init.task"))) =
        { INIT_THREAD_INFO(init_task) };
在lds中。
.data : AT(__data_loc) {
        __data_start = .;    /* address in memory */
        /*
         * first, the init task union, aligned
         * to an 8192 byte boundary.
         */
        *(.init.task)
堆栈在这里,这个东西可不能乱设阿。
这个 thread_union 有2个页面大小哦,因为后面的stack是8k,取大的。
union thread_union {
    struct thread_info thread_info;
    unsigned long stack[THREAD_SIZE/sizeof(long)];
};
下面的就是初始化的任务数据结构。
struct task_struct init_task = INIT_TASK(init_task);
EXPORT_SYMBOL(init_task);
#define init_thread_info    (init_thread_union.thread_info)
#define init_stack        (init_thread_union.stack)
#define INIT_THREAD_INFO(tsk)                        \
{                                    \
    .task        = &tsk,                        \
    .exec_domain    = &default_exec_domain,                \
    .flags        = 0,                        \
    .preempt_count    = 1,                        \
    .addr_limit    = KERNEL_DS,                    \
    .cpu_domain    = domain_val(DOMAIN_USER, DOMAIN_MANAGER) |    \
              domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |    \
              domain_val(DOMAIN_IO, DOMAIN_CLIENT),        \
    .restart_block    = {                        \
        .fn    = do_no_restart_syscall,            \
    },                                \
}
#define THREAD_SIZE        8192
#define THREAD_START_SP        (THREAD_SIZE - 8)
所以堆栈指针就出来了。
    .long    init_thread_union + THREAD_START_SP @ sp
也就是说,sp的位置在 init_thread_union + 8192 - 8 的位置。
至于具体在那里?在下面
而且在init_thread_union地址处的几个内存空间中是有数据的,就是初始化INIT_THREAD_INFO(tsk)的数据。
如下验证:
c02a4000 :
c02a4000:    00000000     andeq    r0, r0, r0 //    .flags = 0
c02a4004:    00000001     andeq    r0, r0, r1 //    .preempt_count
c02a4008:    00000000     andeq    r0, r0, r0
c02a400c:    c02a60c0     eorgt    r6, sl, r0, asr #1
c02a4010:    c02aa040     eorgt    sl, sl, r0, asr #32
c02a4014:    00000000     andeq    r0, r0, r0
c02a4018:    0000001f     andeq    r0, r0, pc, lsl r0
    ...
c02a4180:    c0052300     andgt    r2, r5, r0, lsl #6
    ...
c02a6000 : //一直到这里才有数据哦,也就是2也页面的大小的堆栈。
回到 setup_arch()
    /*
     * Set up various architecture-specific pointers
     */
    init_arch_irq = mdesc->init_irq;
    system_timer = mdesc->timer;
    init_machine = mdesc->init_machine;
    conswitchp = &dummy_con;
}
设置下面的全局量
void (*init_arch_irq)(void) __initdata = NULL;
struct sys_timer *system_timer;
static void (*init_machine)(void) __initdata;
const struct consw *conswitchp;
为以后的初始化作准备。
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/93291/showart_2067369.html

论坛徽章:
0
2 [报告]
发表于 2011-12-28 00:09 |只看该作者
兄弟  你有个地方好像漏掉没说了啊。。。。。。。。
void cpu_init(void)
{
    unsigned int cpu = smp_processor_id(); //单处理器,返回0
    struct stack *stk = &stacks[cpu];
    if (cpu >= NR_CPUS) {
        printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu);
        BUG();
    }
    dump_cpu_info(cpu);
    /*
     * setup stacks for re-entrant exception handlers
     */
    __asm__ (
    "msr    cpsr_c, %1\n\t" //进入irq模式
    "add    sp, %0, %2\n\t" //设置irq堆栈
    "msr    cpsr_c, %3\n\t" //进入abt模式
    "add    sp, %0, %4\n\t" //设置abt堆栈
    "msr    cpsr_c, %5\n\t"
    "add    sp, %0, %6\n\t"
    "msr    cpsr_c, %7" //返回到管理模式
        :
        : "r" (stk),
          "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),
          "I" (offsetof(struct stack, irq[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE),
          "I" (offsetof(struct stack, abt[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
          "I" (offsetof(struct stack, und[0])),
          "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
        : "r14";
} //我对上面的内容感到苦恼,这些堆栈被设置到那里了阿?可以那样设置吗???
天阿,我发现自己还不知道sp在那里呢?找

你刚刚还苦恼呢,其实我也苦恼这里啊。。。。。。。。。。
你下面都去说sp了 ,,怎么苦恼的地方就不说了呢????????
求解!!!!!!

论坛徽章:
0
3 [报告]
发表于 2011-12-28 00:11 |只看该作者

论坛徽章:
0
4 [报告]
发表于 2013-05-10 16:29 |只看该作者
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP