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 @   水三丫  阅读(276)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)
点击右上角即可分享
微信分享提示