zoukankan      html  css  js  c++  java
  • Linux0.11内核之旅3——main.c(1)

    init/main.c

    首先我们贴上main.c中main函数的代码

    void main(void)        /* This really IS void, no error here. */
    { /* The startup routine assumes (well, ...) this */
    /*
    * Interrupts are still disabled. Do necessary setups, then
    * enable them
    */
    ROOT_DEV = ORIG_ROOT_DEV;
    drive_info = DRIVE_INFO;
    memory_end = (1<<20) + (EXT_MEM_K<<10);
    memory_end &= 0xfffff000;
    if (memory_end > 16*1024*1024)
    memory_end = 16*1024*1024;
    if (memory_end > 12*1024*1024)
    buffer_memory_end = 4*1024*1024;
    else if (memory_end > 6*1024*1024)
    buffer_memory_end = 2*1024*1024;
    else
    buffer_memory_end = 1*1024*1024;
    main_memory_start = buffer_memory_end;
    #ifdef RAMDISK
    main_memory_start += rd_init(main_memory_start, RAMDISK*1024);
    #endif
    mem_init(main_memory_start,memory_end);
    trap_init();
    blk_dev_init();
    chr_dev_init();
    tty_init();
    time_init();
    sched_init();
    buffer_init(buffer_memory_end);
    hd_init();
    floppy_init();
    sti();
    move_to_user_mode();
    if (!fork()) { /* we count on this going ok */
    init();
    }
    /*
    * NOTE!! For any other task 'pause()' would mean we have to get a
    * signal to awaken, but task0 is the sole exception (see 'schedule()')
    * as task 0 gets activated at every idle moment (when no other tasks
    * can run). For task0 'pause()' just means we go check if some other
    * task can run, and if not we return here.
    */
    for(;;) pause();
    }

     

     

    我们从main.c的main函数开始读,首先是

    ROOT_DEV = ORIG_ROOT_DEV;

    我们可以追踪到:

    #define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)

    在内核中有很多类似的宏,我们一层一层解释,首先(unsigned short *)0x901FC 说明这是一个指向unsigned short类型的指针,然后再对该指针解引用,所以ORIG_ROOT_DEV返回的应该是一个unsigned short,也就是两个字节,其内容是0x901FC地址处的内容。关于0x900000x901FF的内容请见下表(表摘自《Linux内核解释》----赵炯)

     

    我们可以看出,0x901FC存放的是根设备号。

    同理,main中的下一句:

    drive_info = DRIVE_INFO;

    我们查看一下DRIVE_INFO的定义:

    #define DRIVE_INFO (*(struct drive_info *)0x90080)

    因此,在drive_info中存储的是第一个硬盘的参数表。

    我们继续看:

        memory_end = (1<<20) + (EXT_MEM_K<<10);
    memory_end &= 0xfffff000;
    if (memory_end > 16*1024*1024)
    memory_end = 16*1024*1024;
    if (memory_end > 12*1024*1024)
    buffer_memory_end = 4*1024*1024;
    else if (memory_end > 6*1024*1024)
    buffer_memory_end = 2*1024*1024;
    else
    buffer_memory_end = 1*1024*1024;
    main_memory_start = buffer_memory_end;

    这段

    以下是对这段代码的详细注释:

    首先我们看

    memory_end = (1<<20) + (EXT_MEM_K<<10);

    1 << 20: 1左移20位,得1MB

    我们转到EXT_MEM_K的定义处:

    #define EXT_MEM_K (*(unsigned short *)0x90002)

    通过查表,发现EXT_MEM_K存储的是系统从1MB开始的扩展内存数值,单位是KB,所以和以字节为单位的1MB相加时需要左移10位。

    接下来是

     

    memory_end &= 0xfffff000; // 忽略不到4KB(1页)的内存

     

    继续

    // 如果内存超过16MB,则按照16MB计算

    // 因为在那个年代,内存如果超过16MB相当于你开了个加长奔驰。。。

    if (memory_end > 16*1024*1024)

    memory_end = 16*1024*1024;

    // 如果内存大于12MB则缓冲区末端为4MB

    if (memory_end > 12*1024*1024)

    buffer_memory_end = 4*1024*1024;

    // 如果内存大于6MB则缓冲区末端为2MB

    else if (memory_end > 6*1024*1024)

    buffer_memory_end = 2*1024*1024;

    // 剩下的情况,也就是内存为0MB---6MB,则缓冲区末端为1MB

    else

    buffer_memory_end = 1*1024*1024;

    // 主内存起始地址 = 缓冲区末端

    main_memory_start = buffer_memory_end;

     

    如果定义了RAMDISK(虚拟磁盘),则主内存相应要减少,同时初始化虚拟磁盘

    #ifdef RAMDISK

    main_memory_start += rd_init(main_memory_start, RAMDISK*1024);

    我们查看rd_init的定义:

    /*
    * Returns amount of memory which needs to be reserved.
    */
    long rd_init(long mem_start, int length)
    {
    int i;
    char *cp;

    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
    rd_start = (char *) mem_start;
    rd_length = length;
    cp = rd_start;
    for (i=0; i < length; i++)
    *cp++ = '\0';
    return(length);
    }

     

    我们看一下其中的blk_dev是什么

    /* blk_dev_struct is:
    * do_request-address
    * next-request
    */
    struct blk_dev_struct blk_dev[NR_BLK_DEV] = {
    { NULL, NULL }, /* no_dev */
    { NULL, NULL }, /* dev mem */
    { NULL, NULL }, /* dev fd */
    { NULL, NULL }, /* dev hd */
    { NULL, NULL }, /* dev ttyx */
    { NULL, NULL }, /* dev tty */
    { NULL, NULL } /* dev lp */
    };

     

    继续往深层走,我们可以看

    struct blk_dev_struct {
    void (*request_fn)(void);
    struct request * current_request;
    };

     

    #define MAJOR_NR 1

     

    #define DEVICE_REQUEST do_rd_request

     

    do_rd_request函数:

    void do_rd_request(void)
    {
    int len;
    char *addr;

    INIT_REQUEST;
    addr = rd_start + (CURRENT->sector << 9);
    len = CURRENT->nr_sectors << 9;
    if ((MINOR(CURRENT->dev) != 1) || (addr+len > rd_start+rd_length)) {
    end_request(0);
    goto repeat;
    }
    if (CURRENT-> cmd == WRITE) {
    (void ) memcpy(addr,
    CURRENT->buffer,
    len);
    } else if (CURRENT->cmd == READ) {
    (void) memcpy(CURRENT->buffer,
    addr,
    len);
    } else
    panic("unknown ramdisk-command");
    end_request(1);
    goto repeat;
    }

     

    我们发现,blk_dev_struct中只是包括两个指针,其中一个是函数指针,另一个是struct request指针,在这里,我们暂时不管这两个指针是做什么的。

     

    但是我们基本上已经明白了

    blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;

    这句了,就是将blk_dev的索引为1的那项的reque_fn函数指针指向do_rd_request函数。好,我们不深究这个,继续。

    让我们回到刚开始的rd_init函数,继续我们的分析:

    rd_start = (char *) mem_start;

    rd_length = length;

     

    没什么可说的,rd_startrd_length就是两个全局变量

    cp = rd_start;

    for (i=0; i < length; i++)

    *cp++ = '\0';

    return(length);

    将虚拟磁盘处的内存全部初始化为0

    OK,我们可以回到main.c了,下一篇继续。

  • 相关阅读:
    SPOJ AMR12B 720
    OUC_TeamTraining_#1 720
    Mac下安装必须软件
    spawn命令和expect
    python基础
    AndroidManifest.xml详解
    Ubuntu系统连接Android真机调试
    Android Studio 快捷键
    linux 解压/压缩命令
    sadasd
  • 原文地址:https://www.cnblogs.com/xiaobo68688/p/2300711.html
Copyright © 2011-2022 走看看