您的位置:首页 > 运维架构 > Linux

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

2012-09-09 09:18 603 查看
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() */
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: