linux-0.11分析:进程初始化函数init(),第一部分setup((void *) &drive_info) ,第十二篇随笔

进程的初始化函数,init()

先看看这个函吧:

void init(void)
{
	int pid,i;

	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())) {
		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() */
}

这个函数比较复杂,老规矩,一部分一部分来看吧

第一个部分,看看这个函数setup((void *) &drive_info)

#define DRIVE_INFO (*(struct drive_info *)0x90080)
struct drive_info { char dummy[32]; } drive_info;
init(void)
{
	int pid,i;

	setup((void *) &drive_info);
    .......

这里setup传入就是一个drive_info的结构体,可以看到上面宏定义的位置在0x90080,还记得setup.s阶段存入了一个硬盘信息吗?

地址 字节 存储的信息
0x90080 16 hd0硬盘信息
0x90010 16 hd1硬盘信息
static inline _syscall1(int,setup,void *,BIOS)

include文件 -> unistd.h

#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; \
}

翻译一下

int setup(void * BIOS){
    ong __res; \
    __asm__ volatile ("int $0x80" \
        : "=a" (__res) \
        : "0" (__NR_BIOS),"b" ((long)(a))); \			// NR_BIOS = 0
    if (__res >= 0) \
        return (type) __res; \
    errno = -__res; \
    return -1; \
}

目的就是开起了int 0x80中断,去sys_call_table下标为0的函数调用,也就是sys_setup

include文件 -> linux文件 -> sys.h

fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };

kernel文件 -> blk_drv文件 -> hd.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<NR_HD ; 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<NR_HD ; 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);
}
  • 第一部分

    struct hd_i_struct {
        int head,sect,cyl,wpcom,lzone,ctl;
    };
    #ifdef HD_TYPE
    struct hd_i_struct hd_info[] = { HD_TYPE };
    #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
    #else
    struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
    static int NR_HD = 0;
    #endif
    .....
    int sys_setup(void * BIOS)
    {
        .....
    	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;
        }
    }
    

    这里就是把0x90080和0x90010的数据存放到hd_info中,

  • 第二部分

    #define MAX_HD		2
    static struct hd_struct {
    	long start_sect;
    	long nr_sects;
    } hd[5*MAX_HD]={{0,0},};
    
    .....
    int sys_setup(void * BIOS)
    {
        .....
    	for (i=0 ; i<NR_HD ; i++) {
    		hd[i*5].start_sect = 0;
    		hd[i*5].nr_sects = hd_info[i].head*
    					hd_info[i].sect*hd_info[i].cyl;
    	}
        
        for (drive=0 ; drive<NR_HD ; drive++) {
            .....
            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);
        }
        ......
    }
    

    第一个循环在初始化hd

    第二个循环在给hd赋值

    目前我们已经把硬盘的基本信息存入了 hd_info[],把硬盘的分区信息存入了 hd[]

  • 第三部分

    rd_load();
    mount_root();
    return (0);
    

    rd_load这个不重要,就暂时不看了

    mount_root 直译过来就是加载根,再多说几个字是加载根文件系统,有了它之后,操作系统才能从一个根开始找到所有存储在硬盘中的文件,所以它是文件系统的基石

    看看这个函数mount_root

fs文件 -> super.c

#define NR_FILE 64
#define NR_SUPER 8
struct super_block super_block[NR_SUPER];
void mount_root(void)
{
  int i,free;
  struct super_block * p;
  struct m_inode * mi;

  if (32 != sizeof (struct d_inode))
  	panic("bad i-node size");
  for(i=0;i<NR_FILE;i++)
  	file_table[i].f_count=0;
  if (MAJOR(ROOT_DEV) == 2) {
  	printk("Insert root floppy and press ENTER");
  	wait_for_keypress();
  }
  for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
  	p->s_dev = 0;
  	p->s_lock = 0;
  	p->s_wait = NULL;
  }
  if (!(p=read_super(ROOT_DEV)))
  	panic("Unable to mount root");
  if (!(mi=iget(ROOT_DEV,ROOT_INO)))
  	panic("Unable to read root i-node");
  mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */
  p->s_isup = p->s_imount = mi;
  current->pwd = mi;
  current->root = mi;
  free=0;
  i=p->s_nzones;
  while (-- i >= 0)
  	if (!set_bit(i&8191,p->s_zmap[i>>13]->b_data))
  		free++;
  printk("%d/%d free blocks\n\r",free,p->s_nzones);
  free=0;
  i=p->s_ninodes+1;
  while (-- i >= 0)
  	if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
  		free++;
  printk("%d/%d free inodes\n\r",free,p->s_ninodes);
}

比较长,就一部分一部分来看吧

  • 第一部分

    #define NR_FILE 64
    struct file {
    	unsigned short f_mode;
    	unsigned short f_flags;
    	unsigned short f_count;
    	struct m_inode * f_inode;
    	off_t f_pos;
    };
    struct file file_table[NR_FILE];
    
    for(i=0;i<NR_FILE;i++)
    		file_table[i].f_count=0;
    

    这部分很简单了,把64个file_tablef_count属性初始化为0

    这个 file_table 表示进程所使用的文件,进程每使用一个文件,都需要记录在这里,包括文件类型、文件 inode 索引信息等,而这个 f_count 表示被引用的次数,此时还没有引用,所以设置为零。

  • 第二部分

    #define NR_SUPER 8
    struct super_block {
    	unsigned short s_ninodes;
    	unsigned short s_nzones;
    	unsigned short s_imap_blocks;
    	unsigned short s_zmap_blocks;
    	unsigned short s_firstdatazone;
    	unsigned short s_log_zone_size;
    	unsigned long s_max_size;
    	unsigned short s_magic;
    /* These are only in memory */
    	struct buffer_head * s_imap[8];
    	struct buffer_head * s_zmap[8];
    	unsigned short s_dev;
    	struct m_inode * s_isup;
    	struct m_inode * s_imount;
    	unsigned long s_time;
    	struct task_struct * s_wait;
    	unsigned char s_lock;
    	unsigned char s_rd_only;
    	unsigned char s_dirt;
    };
    struct super_block super_block[NR_SUPER];
    
    for(p = &super_block[0] ; p < &super_block[NR_SUPER] ; p++) {
    		p->s_dev = 0;
    		p->s_lock = 0;
    		p->s_wait = NULL;
    	}
    

    这段就是把super_block这个结构体初始化操作

    这个 super_block 存在的意义是,操作系统与一个设备以文件形式进行读写访问时,就需要把这个设备的超级块信息放在这里。

  • 第三部分

    p=read_super(ROOT_DEV)
    mi=iget(ROOT_DEV,ROOT_INO)
    mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */
    p->s_isup = p->s_imount = mi;
    current->pwd = mi;
    current->root = mi;
    free=0;
    i=p->s_nzones;
    free=0;
    

    read_super 就是读取硬盘中的超级块。

    然后把该 inode 设置为当前进程(也就是进程 1)的当前工作目录和根目录。

    current->pwd = mi;current->root = mi;然后记录块位图信息。

    最后记录 inode 位图信息。

posted @ 2022-08-17 09:47  水三丫  阅读(217)  评论(0编辑  收藏  举报