Linux 启动入口

Linux 0.11 源代码

//main函数 linux引导成功后就从这里开始运行
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;//设置操作系统的根文件
 	drive_info = DRIVE_INFO;//设置操作系统驱动参数
	 //解析setup.s代码后获取系统内存参数
	memory_end = (1<<20) + (EXT_MEM_K<<10);
	//取整4k的内存大小
	memory_end &= 0xfffff000;
	if (memory_end > 16*1024*1024)//控制操作系统的最大内存为16M
		memory_end = 16*1024*1024;
	if (memory_end > 12*1024*1024) 
		buffer_memory_end = 4*1024*1024;//设置高速缓冲区的大小,跟块设备有关,跟设备交互的时候,充当缓冲区,写入到块设备中的数据先放在缓冲区里,只有执行sync时才真正写入;这也是为什么要区分块设备驱动和字符设备驱动;块设备写入需要缓冲区,字符设备不需要是直接写入的
	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_init();
	//加载定时器驱动
	time_init();
	//进程间调度初始化
	sched_init();
	//缓冲区初始化
	buffer_init(buffer_memory_end);
	//硬盘初始化
	hd_init();
	//软盘初始化
	floppy_init();
	sti();
	//从内核态切换到用户态,上面的初始化都是在内核态运行的
	//内核态无法被抢占,不能在进程间进行切换,运行不会被干扰
	move_to_user_mode();
	if (!fork()) {	//创建0号进程 fork函数就是用来创建进程的函数	/* we count on this going ok */
		//0号进程是所有进程的父进程
		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.
 */
//0号进程永远不会结束,他会在没有其他进程调用的时候调用,只会执行for(;;) pause();
	for(;;) pause();
}

move_to_user_mode 函数

__asm__ (
	movl %esp,%eax
	pushl $0x17
	pushl %eax
	pushfl
	pushl $0x0f
	pushl $1f
	iret\n
	1:movl $0x17,%eax
	movw %ax,%ds
	movw %ax,%es
	movw %ax,%fs
	movw %ax,%gs
:::"ax")

fork 函数

#define __NR_setup	0	/* used only by init, to get system going */
#define __NR_exit	1
#define __NR_fork	2
#define __NR_read	3
#define __NR_write	4
#define __NR_open	5
#define __NR_close	6

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

#define set_system_gate(n,addr) 
	_set_gate(&idt[n],15,3,addr)

#define _set_gate(gate_addr,type,dpl,addr) 
__asm__ (
    movw %dx,%ax
	movw %0,%dx
	movl %eax,%1 
	movl %edx,%2
	:
	: "i" ((short) (0x8000+(dpl<<13)+(type<<8))), 
	"o" (*((char *) (gate_addr))), 
	"o" (*(4+(char *) (gate_addr))), 
	"d" ((char *) (addr)),
    "a" (0x00080000))        

set_system_gate(0x80,&system_call);

.align 2
_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

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

.align 2
sys_fork:
	call find_empty_process
	testl %eax,%eax
	js 1f
	push %gs
	pushl %esi
	pushl %edi
	pushl %ebp
	pushl %eax
	call copy_process
	addl $20,%esp
1:	ret


// 循环选择遍历选择一个空的数组下标
int find_empty_process(void)
{
	int i;

	repeat:
		if ((++last_pid)<0) last_pid=1;
		for(i=0 ; i<NR_TASKS ; i++)
			if (task[i] && task[i]->pid == last_pid) goto repeat;
	for(i=1 ; i<NR_TASKS ; i++)
		if (!task[i])
			return i;
	return -EAGAIN;
}


/*
 *  Ok, this is the main fork-routine. It copies the system process
 * information (task[nr]) and sets up the necessary registers. It
 * also copies the data segment in it's entirety.
 */
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
		long ebx,long ecx,long edx,
		long fs,long es,long ds,
		long eip,long cs,long eflags,long esp,long ss)
{
	struct task_struct *p;
	int i;
	struct file *f;

	p = (struct task_struct *) get_free_page();
	if (!p)
		return -EAGAIN;
	task[nr] = p;
	
	// NOTE!: the following statement now work with gcc 4.3.2 now, and you
	// must compile _THIS_ memcpy without no -O of gcc.#ifndef GCC4_3
	*p = *current;	/* NOTE! this doesn't copy the supervisor stack */
	p->state = TASK_UNINTERRUPTIBLE;
	p->pid = last_pid;
	p->father = current->pid;
	p->counter = p->priority;
	p->signal = 0;
	p->alarm = 0;
	p->leader = 0;		/* process leadership doesn't inherit */
	p->utime = p->stime = 0;
	p->cutime = p->cstime = 0;
	p->start_time = jiffies;
	p->tss.back_link = 0;
	p->tss.esp0 = PAGE_SIZE + (long) p;
	p->tss.ss0 = 0x10;
	p->tss.eip = eip;
	p->tss.eflags = eflags;
	p->tss.eax = 0;
	p->tss.ecx = ecx;
	p->tss.edx = edx;
	p->tss.ebx = ebx;
	p->tss.esp = esp;
	p->tss.ebp = ebp;
	p->tss.esi = esi;
	p->tss.edi = edi;
	p->tss.es = es & 0xffff;
	p->tss.cs = cs & 0xffff;
	p->tss.ss = ss & 0xffff;
	p->tss.ds = ds & 0xffff;
	p->tss.fs = fs & 0xffff;
	p->tss.gs = gs & 0xffff;
	p->tss.ldt = _LDT(nr);
	p->tss.trace_bitmap = 0x80000000;
	if (last_task_used_math == current)
		__asm__("clts ; fnsave %0"::"m" (p->tss.i387));
	if (copy_mem(nr,p)) {
		task[nr] = NULL;
		free_page((long) p);
		return -EAGAIN;
	}
	for (i=0; i<NR_OPEN;i++)
		if ((f=p->filp[i]))
			f->f_count++;
	if (current->pwd)
		current->pwd->i_count++;
	if (current->root)
		current->root->i_count++;
	if (current->executable)
		current->executable->i_count++;
	set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
	set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
	p->state = TASK_RUNNING;	/* do this last, just in case */
	return last_pid;
}

解析参数

int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,

long ebx,long ecx,long edx,

long fs,long es,long ds,

long eip,long cs,long eflags,long esp,long ss)

// 将如下参数压入栈上

push %ds
push %es
push %fs
pushl %edx
pushl %ecx # push %ebx,%ecx,%edx as parameters
pushl %ebx # to the system call

在调用在之前进行的压栈

push %gs

pushl %esi

pushl %edi

pushl %ebp

pushl %eax

// 这个参数列表是,特权级切换,是需要

long eip,long cs,long eflags,long esp,long ss

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值