Linux0.11版源代码分析——init/main.c

  Linux0.11版源代码中,main.c在代码中的位置十分重要,完成系统的初始化,并启动进程。涉及到进程、内存管理、文件管理等等。尽管这部分代码看起来十分简单,但是分析起来,难度很大。

  目前基本完成该部分代码的分析,但内容比较多,此处仅记录该文件的基本分析注释,相关部分的分析整理后再发布。

/*
 *  linux/init/main.c
 *
 *  (C) 1991  Linus Torvalds
 */

#define __LIBRARY__
#include <unistd.h>
#include <time.h>

/*
 * we need this inline - forking from kernel space will result
 * in NO COPY ON WRITE (!!!), until an execve is executed. This
 * is no problem, but for the stack. This is handled by not letting
 * main() use the stack at all after fork(). Thus, no function
 * calls - which means inline code for fork too, as otherwise we
 * would use the stack upon exit from 'fork()'.
 *
 * Actually only pause and fork are needed inline, so that there
 * won't be any messing with the stack from main(), but we define
 * some others too.
 */
 /*
 我们需要这些内联函数,从内核空间创建进程导致没有写时复制
 直到一个execve被调用。处理方法是在fork调用后不让main使用任何堆栈。
 否则我们从fork退出时要调用堆栈。

 实际上,只有pause和fork需要使用内联函数,这样保证不会弄乱堆栈,
 实际上我们也定义了一些其它函数。
 */
static inline _syscall0(int,fork)
static inline _syscall0(int,pause)
static inline _syscall1(int,setup,void *,BIOS)
static inline _syscall0(int,sync)

#include <linux/tty.h>
#include <linux/sched.h>
#include <linux/head.h>
#include <asm/system.h>
#include <asm/io.h>

#include <stddef.h>
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

#include <linux/fs.h>

//静态字符型数组
static char printbuf[1024];

//格式化输出
extern int vsprintf();
//初始化
extern void init(void);
//块设备初始化
extern void blk_dev_init(void);
//字符设备初始化
extern void chr_dev_init(void);
//硬盘初始化
extern void hd_init(void);
//软驱初始化
extern void floppy_init(void);
//内存初始化
extern void mem_init(long start, long end);
//虚拟盘初始化
extern long rd_init(long mem_start, int length);
//内核时间。计算系统开机时间
extern long kernel_mktime(struct tm * tm);
//内核启动时间
extern long startup_time;

/*
 * This is set up by the setup-routine at boot-time
 */
 //这些数据是在内核引导时间设置的
 //此宏是1MB内存以后的扩展内存大小
#define EXT_MEM_K (*(unsigned short *)0x90002)
//硬盘参数表32字节内容
#define DRIVE_INFO (*(struct drive_info *)0x90080)
//根文件系统所在设备号
#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)

/*
 * Yeah, yeah, it's ugly, but I cannot find how to do this correctly
 * and this seems to work. I anybody has more info on the real-time
 * clock I'd be interested. Most of this was trial and error, and some
 * bios-listing reading. Urghh.
 */
//是的,这很丑,但是我没有发现它们有错误并且看起来能工作。
//有关于实时时钟的资料我都很高兴去,这些都是试出来的

//定义
#define CMOS_READ(addr) ({ \
outb_p(0x80|addr,0x70); \
inb_p(0x71); \
})

//定义宏将BCD转为十进制
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)

//计算开机时间
static void time_init(void)
{
    struct tm time;

    do {
        time.tm_sec = CMOS_READ(0);
        time.tm_min = CMOS_READ(2);
        time.tm_hour = CMOS_READ(4);
        time.tm_mday = CMOS_READ(7);
        time.tm_mon = CMOS_READ(8);
        time.tm_year = CMOS_READ(9);
    } while (time.tm_sec != CMOS_READ(0));
    BCD_TO_BIN(time.tm_sec);
    BCD_TO_BIN(time.tm_min);
    BCD_TO_BIN(time.tm_hour);
    BCD_TO_BIN(time.tm_mday);
    BCD_TO_BIN(time.tm_mon);
    BCD_TO_BIN(time.tm_year);
    time.tm_mon--;
    startup_time = kernel_mktime(&time);
}

//
static long memory_end = 0;
static long buffer_memory_end = 0;
static long main_memory_start = 0;

struct drive_info { char dummy[32]; } drive_info;

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;
//硬盘信息,目前尚未初始化。在init中被初始化
     drive_info = DRIVE_INFO;
//内存大小
    memory_end = (1<<20) + (EXT_MEM_K<<10);
//忽略小于4kb的内存
    memory_end &= 0xfffff000;
//如果内存大于16m,则内存大小为16m
    if (memory_end > 16*1024*1024)
        memory_end = 16*1024*1024;
    //如果内存大于12m,则设置缓冲区末端为4m
    if (memory_end > 12*1024*1024) 
        buffer_memory_end = 4*1024*1024;
    //如果内存大于6m则缓冲区末端设为2m,否则设为1m
    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初始化
    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();
}

//格式化输出
static int printf(const char *fmt, ...)
{
    va_list args;
    int i;

    va_start(args, fmt);
    write(1,printbuf,i=vsprintf(printbuf, fmt, args));
    va_end(args);
    return i;
}

//参数定义
static char * argv_rc[] = { "/bin/sh", NULL };
static char * envp_rc[] = { "HOME=/", NULL };

static char * argv[] = { "-/bin/sh",NULL };
static char * envp[] = { "HOME=/usr/root", NULL };

//初始化
void init(void)
{
//定义局部变量
    int pid,i;

//设置硬盘参数
    setup((void *) &drive_info);
//打开dev/tty0
    (void) open("/dev/tty0",O_RDWR,0);
//复制句柄
    (void) dup(0);
//复制句柄
    (void) dup(0);
    printf("%d buffers = %d bytes buffer space\n\r",NR_BUFFERS,
        NR_BUFFERS*BLOCK_SIZE);
    printf("Free mem: %d bytes\n\r",memory_end-main_memory_start);
    //
    if (!(pid=fork())) {
        close(0);
        if (open("/etc/rc",O_RDONLY,0))
            _exit(1);
        execve("/bin/sh",argv_rc,envp_rc);
        _exit(2);
    }
    if (pid>0)
        while (pid != wait(&i))
            /* nothing */;
    while (1) {
        if ((pid=fork())<0) {
            printf("Fork failed in init\r\n");
            continue;
        }
        if (!pid) {
            close(0);close(1);close(2);
            setsid();
            (void) open("/dev/tty0",O_RDWR,0);
            (void) dup(0);
            (void) dup(0);
            _exit(execve("/bin/sh",argv,envp));
        }
        while (1)
            if (pid == wait(&i))
                break;
        printf("\n\rchild %d died with code %04x\n\r",pid,i);
        sync();
    }
    _exit(0);    /* NOTE! _exit, not exit() */
}

 

转载于:https://www.cnblogs.com/xfwei/archive/2012/09/09/2677251.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值