Chinaunix首页 | 论坛 | 博客
  • 博客访问: 61797
  • 博文数量: 10
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 143
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-20 21:24
个人简介

学习是一种修行

文章分类

全部博文(10)

文章存档

2014年(2)

2013年(8)

我的朋友

分类: LINUX

2013-12-30 15:40:15

sched_init(); 中对进程0进行了初始化,当所有都初始完之后,就打开中断,将进程0移动到应用层,
自此进程0开始执行。接着 if (!fork()),创建进程1,并在进程1里执行init();下面看下init代码:
void init(void)
{
        int pid,i;


        setup((void *) &drive_info);
/***************************************************************************************
这个函数是一个系统调用,包括前面if (!fork())的fork,也是系统调用,都是在
内核态执行,定义在文件头
static inline _syscall0(int,fork)和static inline _syscall1(int,setup,void *,BIOS);
static inline _syscall0(int,fork)实体:
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name)); \
if (__res >= 0) \
        return (type) __res; \
errno = -__res; \
return -1; \
}
_syscall1(int,setup,void *,BIOS)实体:
#define _syscall1(type,name,atype,a) \
type name(atype a) \
{ \
long __res; \ 
__asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_##name),"b" ((long)(a))); \
if (__res >= 0) \
        return (type) __res; \
errno = -__res; \
return -1; \
}

通过0x80中断,
#define __NR_setup      0       
#define __NR_fork       2
和这两个宏定义,确定系统调用号,调用fork,setup ;
那么,如何调用系统调用呢?中断0x80会调用
system_call:
        cmpl $nr_system_calls-1,%eax
        ja bad_sys_call
        push %ds
        push %es
        push %fs
        pushl %edx
        pushl %ecx              # push %ebx,%ecx,%edx as parameters
        pushl %ebx              # to the system call
        movl $0x10,%edx         # set up ds,es to kernel space
        mov %dx,%ds
        mov %dx,%es
        movl $0x17,%edx         # fs points to local data space
        mov %dx,%fs
        call sys_call_table(,%eax,4)
        pushl %eax
        movl current,%eax
        cmpl $0,state(%eax)             # state
        jne reschedule
        cmpl $0,counter(%eax)           # counter
        je reschedule
这里的call sys_call_table(,%eax,4)会执行指定c函数,在这里就是执行下面这个系统调用
系统调用:
int sys_setup(void * BIOS)
{
        static int callable = 1;
        int i,drive;
        unsigned char cmos_disks;
        struct partition *p;
        struct buffer_head * bh;


        if (!callable)
                return -1;
        callable = 0;
#ifndef HD_TYPE
        for (drive=0 ; drive<2 ; drive++) {
                hd_info[drive].cyl = *(unsigned short *) BIOS;
                hd_info[drive].head = *(unsigned char *) (2+BIOS);
                hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
                hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
                hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
                hd_info[drive].sect = *(unsigned char *) (14+BIOS);
                BIOS += 16;
        }
        if (hd_info[1].cyl)
                NR_HD=2;
        else
                NR_HD=1;
#endif
        for (i=0 ; i
                hd[i*5].start_sect = 0;
                hd[i*5].nr_sects = hd_info[i].head*
                                hd_info[i].sect*hd_info[i].cyl;
        }
        if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
                if (cmos_disks & 0x0f)
                        NR_HD = 2;
                else
                        NR_HD = 1;
        else
                NR_HD = 0;
        for (i = NR_HD ; i < 2 ; i++) {
                hd[i*5].start_sect = 0;
                hd[i*5].nr_sects = 0;
        }
        for (drive=0 ; drive                 if (!(bh = bread(0x300 + drive*5,0))) {
                        printk("Unable to read partition table of drive %d\n\r",
                                drive);
                        panic("");
                }
                if (bh->b_data[510] != 0x55 || (unsigned char)
                    bh->b_data[511] != 0xAA) {
                        printk("Bad partition table on drive %d\n\r",drive);
                        panic("");
                }
                p = 0x1BE + (void *)bh->b_data;
                for (i=1;i<5;i++,p++) {
                        hd[i+5*drive].start_sect = p->start_sect;
                        hd[i+5*drive].nr_sects = p->nr_sects;
                }
                brelse(bh);
        }
        if (NR_HD)
                printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
        rd_load();
        mount_root();
        return (0);
}
主要是获取硬盘分区信息,并按装文件系统。
所以setup((void *) &drive_info);就是通过系统调用在内核堆栈空间进行取硬盘分区信息,并按装文件系统。
***************************************************************************************/
        (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())) //通过系统调用fork,创建进程2,并在进程2中执行
                close(0);//关掉标准输入
                if (open("/etc/rc",O_RDONLY,0))//打开/etc/rc,作为标准输入
                        _exit(1);//打开失败退出
                execve("/bin/sh",argv_rc,envp_rc);//读取/etc/rc中的命令并在非交互/bin/sh(shell)下执行
                _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));//执行shell后退出
                }
                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() */
//退出函数

}
总结一下,首先通过setup获取硬盘信息,并按装文件系统,接着用终端显示系统信息,然后创建一个子进程,
把标准输入重定位到/etc/rc,通过非交互shell执行/etc/rc里的配置,执行完后,关闭进程,最后再创建一个进
程,初始化shell,初始化完后,关闭此进程,打印进程信息,刷新缓冲区后,推出函数。
阅读(2137) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~