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
1197

被折叠的 条评论
为什么被折叠?



