linux源代码剖析之kernel

kernel

asm.s
/*

  • asm.s contains the low-level code for most hardware faults.
  • page_exception is handled by the mm, so that isn’t here. This
  • file also handles (hopefully) fpu-exceptions due to TS-bit, as
  • the fpu must be properly saved/resored. This hasn’t been tested.
    */

.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
.globl _device_not_available,_double_fault,_coprocessor_segment_overrun
.globl _invalid_TSS,_segment_not_present,_stack_segment
.globl _general_protection,_coprocessor_error,_reserved

_divide_error:
pushl $_do_divide_error
no_error_code:
xchgl %eax,(%esp)
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
pushl $0 # “error code”
lea 44(%esp),%edx
pushl %edx
movl $0x10,%edx
mov %dx,%ds
mov %dx,%es
mov %dx,%fs
call *%eax
addl $8,%esp
pop %fs
pop %es
pop %ds
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %eax
iret

_debug:
pushl $_do_int3 # _do_debug
jmp no_error_code

_nmi:
pushl $_do_nmi
jmp no_error_code

_int3:
pushl $_do_int3
jmp no_error_code

_overflow:
pushl $_do_overflow
jmp no_error_code

_bounds:
pushl $_do_bounds
jmp no_error_code

_invalid_op:
pushl $_do_invalid_op
jmp no_error_code

math_emulate:
popl %eax
pushl $_do_device_not_available
jmp no_error_code
_device_not_available:
pushl %eax
movl %cr0,%eax
bt $2,%eax # EM (math emulation bit)
jc math_emulate
clts # clear TS so that we can use math
movl _current,%eax
cmpl _last_task_used_math,%eax
je 1f # shouldn’t happen really …
pushl %ecx
pushl %edx
push %ds
movl $0x10,%eax
mov %ax,%ds
call _math_state_restore
pop %ds
popl %edx
popl %ecx
1: popl %eax
iret

_coprocessor_segment_overrun:
pushl $_do_coprocessor_segment_overrun
jmp no_error_code

_reserved:
pushl $_do_reserved
jmp no_error_code

_coprocessor_error:
pushl $_do_coprocessor_error
jmp no_error_code

_double_fault:
pushl $_do_double_fault
error_code:
xchgl %eax,4(%esp) # error code <-> %eax
xchgl %ebx,(%esp) # &function <-> %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
push %ds
push %es
push %fs
pushl %eax # error code
lea 44(%esp),%eax # offset
pushl %eax
movl $0x10,%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
call *%ebx
addl $8,%esp
pop %fs
pop %es
pop %ds
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
popl %eax
iret

_invalid_TSS:
pushl $_do_invalid_TSS
jmp error_code

_segment_not_present:
pushl $_do_segment_not_present
jmp error_code

_stack_segment:
pushl $_do_stack_segment
jmp error_code

_general_protection:
pushl $_do_general_protection
jmp error_code



console.c
/*

  • console.c
  • This module implements the console io functions
  • ‘void con_init(void)’
  • ‘void con_write(struct tty_queue * queue)’
  • Hopefully this will be a rather complete VT102 implementation.

*/

/*

  • NOTE!!! We sometimes disable and enable interrupts for a short while
  • (to put a word in video IO), but this will work even for keyboard
  • interrupts. We know interrupts aren’t enabled when getting a keyboard
  • interrupt, as we use trap-gates. Hopefully all is well.
    */

#include <linux/sched.h>
#include <linux/tty.h>
#include <asm/io.h>
#include <asm/system.h>

#define SCREEN_START 0xb8000
#define SCREEN_END 0xc0000
#define LINES 25
#define COLUMNS 80
#define NPAR 16

extern void keyboard_interrupt(void);

static unsigned long origin=SCREEN_START;
static unsigned long scr_end=SCREEN_START+LINESCOLUMNS2;
static unsigned long pos;
static unsigned long x,y;
static unsigned long top=0,bottom=LINES;
static unsigned long lines=LINES,columns=COLUMNS;
static unsigned long state=0;
static unsigned long npar,par[NPAR];
static unsigned long ques=0;
static unsigned char attr=0x07;

/*

  • this is what the terminal answers to a ESC-Z or csi0c
  • query (= vt100 response).
    */
    #define RESPONSE “\033[?1;2c”

static inline void gotoxy(unsigned int new_x,unsigned int new_y)
{
if (new_x>=columns || new_y>=lines)
return;
x=new_x;
y=new_y;
pos=origin+((y*columns+x)<<1);
}

static inline void set_origin(void)
{
cli();
outb_p(12,0x3d4);
outb_p(0xff&((origin-SCREEN_START)>>9),0x3d5);
outb_p(13,0x3d4);
outb_p(0xff&((origin-SCREEN_START)>>1),0x3d5);
sti();
}

static void scrup(void)
{
if (!top && bottom==lines) {
origin += columns<<1;
pos += columns<<1;
scr_end += columns<<1;
if (scr_end>SCREEN_END) {
asm(“cld\n\t”
“rep\n\t”
“movsl\n\t”
“movl _columns,%1\n\t”
“rep\n\t”
“stosw”
::“a” (0x0720),
“c” ((lines-1)*columns>>1),
“D” (SCREEN_START),
“S” (origin)
:“cx”,“di”,“si”);
scr_end -= origin-SCREEN_START;
pos -= origin-SCREEN_START;
origin = SCREEN_START;
} else {
asm(“cld\n\t”
“rep\n\t”
“stosl”
::“a” (0x07200720),
“c” (columns>>1),
“D” (scr_end-(columns<<1))
:“cx”,“di”);
}
set_origin();
} else {
asm(“cld\n\t”
“rep\n\t”
“movsl\n\t”
“movl _columns,%%ecx\n\t”
“rep\n\t”
“stosw”
::“a” (0x0720),
“c” ((bottom-top-1)*columns>>1),
“D” (origin+(columns<<1)top),
“S” (origin+(columns<<1)
(top+1))
:“cx”,“di”,“si”);
}
}

static void scrdown(void)
{
asm(“std\n\t”
“rep\n\t”
“movsl\n\t”
“addl $2,%%edi\n\t” /* %edi has been decremented by 4 */
“movl _columns,%%ecx\n\t”
“rep\n\t”
“stosw”
::“a” (0x0720),
“c” ((bottom-top-1)*columns>>1),
“D” (origin+(columns<<1)bottom-4),
“S” (origin+(columns<<1)
(bottom-1)-4)
:“ax”,“cx”,“di”,“si”);
}

static void lf(void)
{
if (y+1<bottom) {
y++;
pos += columns<<1;
return;
}
scrup();
}

static void ri(void)
{
if (y>top) {
y–;
pos -= columns<<1;
return;
}
scrdown();
}

static void cr(void)
{
pos -= x<<1;
x=0;
}

static void del(void)
{
if (x) {
pos -= 2;
x–;
*(unsigned short *)pos = 0x0720;
}
}

static void csi_J(int par)
{
long count asm(“cx”);
long start asm(“di”);

switch (par) {
	case 0:	/* erase from cursor to end of display */
		count = (scr_end-pos)>>1;
		start = pos;
		break;
	case 1:	/* erase from start to cursor */
		count = (pos-origin)>>1;
		start = origin;
		break;
	case 2: /* erase whole display */
		count = columns*lines;
		start = origin;
		break;
	default:
		return;
}
__asm__("cld\n\t"
	"rep\n\t"
	"stosw\n\t"
	::"c" (count),
	"D" (start),"a" (0x0720)
	:"cx","di");

}

static void csi_K(int par)
{
long count asm(“cx”);
long start asm(“di”);

switch (par) {
	case 0:	/* erase from cursor to end of line */
		if (x>=columns)
			return;
		count = columns-x;
		start = pos;
		break;
	case 1:	/* erase from start of line to cursor */
		start = pos - (x<<1);
		count = (x<columns)?x:columns;
		break;
	case 2: /* erase whole line */
		start = pos - (x<<1);
		count = columns;
		break;
	default:
		return;
}
__asm__("cld\n\t"
	"rep\n\t"
	"stosw\n\t"
	::"c" (count),
	"D" (start),"a" (0x0720)
	:"cx","di");

}

void csi_m(void)
{
int i;

for (i=0;i<=npar;i++)
	switch (par[i]) {
		case 0:attr=0x07;break;
		case 1:attr=0x0f;break;
		case 4:attr=0x0f;break;
		case 7:attr=0x70;break;
		case 27:attr=0x07;break;
	}

}

static inline void set_cursor(void)
{
cli();
outb_p(14,0x3d4);
outb_p(0xff&((pos-SCREEN_START)>>9),0x3d5);
outb_p(15,0x3d4);
outb_p(0xff&((pos-SCREEN_START)>>1),0x3d5);
sti();
}

static void respond(struct tty_struct * tty)
{
char * p = RESPONSE;

cli();
while (*p) {
	PUTCH(*p,tty->read_q);
	p++;
}
sti();
copy_to_cooked(tty);

}

static void insert_char(void)
{
int i=x;
unsigned short tmp,old=0x0720;
unsigned short * p = (unsigned short *) pos;

while (i++<columns) {
	tmp=*p;
	*p=old;
	old=tmp;
	p++;
}

}

static void insert_line(void)
{
int oldtop,oldbottom;

oldtop=top;
oldbottom=bottom;
top=y;
bottom=lines;
scrdown();
top=oldtop;
bottom=oldbottom;

}

static void delete_char(void)
{
int i;
unsigned short * p = (unsigned short *) pos;

if (x>=columns)
	return;
i = x;
while (++i < columns) {
	*p = *(p+1);
	p++;
}
*p=0x0720;

}

static void delete_line(void)
{
int oldtop,oldbottom;

oldtop=top;
oldbottom=bottom;
top=y;
bottom=lines;
scrup();
top=oldtop;
bottom=oldbottom;

}

static void csi_at(int nr)
{
if (nr>columns)
nr=columns;
else if (!nr)
nr=1;
while (nr–)
insert_char();
}

static void csi_L(int nr)
{
if (nr>lines)
nr=lines;
else if (!nr)
nr=1;
while (nr–)
insert_line();
}

static void csi_P(int nr)
{
if (nr>columns)
nr=columns;
else if (!nr)
nr=1;
while (nr–)
delete_char();
}

static void csi_M(int nr)
{
if (nr>lines)
nr=lines;
else if (!nr)
nr=1;
while (nr–)
delete_line();
}

static int saved_x=0;
static int saved_y=0;

static void save_cur(void)
{
saved_x=x;
saved_y=y;
}

static void restore_cur(void)
{
x=saved_x;
y=saved_y;
pos=origin+((y*columns+x)<<1);
}

void con_write(struct tty_struct * tty)
{
int nr;
char c;

nr = CHARS(tty->write_q);
while (nr--) {
	GETCH(tty->write_q,c);
	switch(state) {
		case 0:
			if (c>31 && c<127) {
				if (x>=columns) {
					x -= columns;
					pos -= columns<<1;
					lf();
				}
				__asm__("movb _attr,%%ah\n\t"
					"movw %%ax,%1\n\t"
					::"a" (c),"m" (*(short *)pos)
					:"ax");
				pos += 2;
				x++;
			} else if (c==27)
				state=1;
			else if (c==10 || c==11 || c==12)
				lf();
			else if (c==13)
				cr();
			else if (c==ERASE_CHAR(tty))
				del();
			else if (c==8) {
				if (x) {
					x--;
					pos -= 2;
				}
			} else if (c==9) {
				c=8-(x&7);
				x += c;
				pos += c<<1;
				if (x>columns) {
					x -= columns;
					pos -= columns<<1;
					lf();
				}
				c=9;
			}
			break;
		case 1:
			state=0;
			if (c=='[')
				state=2;
			else if (c=='E')
				gotoxy(0,y+1);
			else if (c=='M')
				ri();
			else if (c=='D')
				lf();
			else if (c=='Z')
				respond(tty);
			else if (x=='7')
				save_cur();
			else if (x=='8')
				restore_cur();
			break;
		case 2:
			for(npar=0;npar<NPAR;npar++)
				par[npar]=0;
			npar=0;
			state=3;
			if (ques=(c=='?'))
				break;
		case 3:
			if (c==';' && npar<NPAR-1) {
				npar++;
				break;
			} else if (c>='0' && c<='9') {
				par[npar]=10*par[npar]+c-'0';
				break;
			} else state=4;
		case 4:
			state=0;
			switch(c) {
				case 'G': case '`':
					if (par[0]) par[0]--;
					gotoxy(par[0],y);
					break;
				case 'A':
					if (!par[0]) par[0]++;
					gotoxy(x,y-par[0]);
					break;
				case 'B': case 'e':
					if (!par[0]) par[0]++;
					gotoxy(x,y+par[0]);
					break;
				case 'C': case 'a':
					if (!par[0]) par[0]++;
					gotoxy(x+par[0],y);
					break;
				case 'D':
					if (!par[0]) par[0]++;
					gotoxy(x-par[0],y);
					break;
				case 'E':
					if (!par[0]) par[0]++;
					gotoxy(0,y+par[0]);
					break;
				case 'F':
					if (!par[0]) par[0]++;
					gotoxy(0,y-par[0]);
					break;
				case 'd':
					if (par[0]) par[0]--;
					gotoxy(x,par[0]);
					break;
				case 'H': case 'f':
					if (par[0]) par[0]--;
					if (par[1]) par[1]--;
					gotoxy(par[1],par[0]);
					break;
				case 'J':
					csi_J(par[0]);
					break;
				case 'K':
					csi_K(par[0]);
					break;
				case 'L':
					csi_L(par[0]);
					break;
				case 'M':
					csi_M(par[0]);
					break;
				case 'P':
					csi_P(par[0]);
					break;
				case '@':
					csi_at(par[0]);
					break;
				case 'm':
					csi_m();
					break;
				case 'r':
					if (par[0]) par[0]--;
					if (!par[1]) par[1]=lines;
					if (par[0] < par[1] &&
					    par[1] <= lines) {
						top=par[0];
						bottom=par[1];
					}
					break;
				case 's':
					save_cur();
					break;
				case 'u':
					restore_cur();
					break;
			}
	}
}
set_cursor();

}

/*

  • void con_init(void);

  • This routine initalizes console interrupts, and does nothing

  • else. If you want the screen to clear, call tty_write with

  • the appropriate escape-sequece.
    */
    void con_init(void)
    {
    register unsigned char a;

    gotoxy(*(unsigned char )(0x90000+510),(unsigned char *)(0x90000+511));
    set_trap_gate(0x21,&keyboard_interrupt);
    outb_p(inb_p(0x21)&0xfd,0x21);
    a=inb_p(0x61);
    outb_p(a|0x80,0x61);
    outb(a,0x61);
    }



exit.c
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>

#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <asm/segment.h>

int sys_pause(void);
int sys_close(int fd);

void release(struct task_struct * p)
{
int i;

if (!p)
	return;
for (i=1 ; i<NR_TASKS ; i++)
	if (task[i]==p) {
		task[i]=NULL;
		free_page((long)p);
		schedule();
		return;
	}
panic("trying to release non-existent task");

}

static inline void send_sig(long sig,struct task_struct * p,int priv)
{
if (!p || sig<1 || sig>32)
return;
if (priv ||
current->uidp->uid ||
current->euid
p->uid ||
current->uidp->euid ||
current->euid
p->euid)
p->signal |= (1<<(sig-1));
}

void do_kill(long pid,long sig,int priv)
{
struct task_struct **p = NR_TASKS + task;

if (!pid) while (--p > &FIRST_TASK) {
	if (*p && (*p)->pgrp == current->pid)
		send_sig(sig,*p,priv);
} else if (pid>0) while (--p > &FIRST_TASK) {
	if (*p && (*p)->pid == pid)
		send_sig(sig,*p,priv);
} else if (pid == -1) while (--p > &FIRST_TASK)
	send_sig(sig,*p,priv);
else while (--p > &FIRST_TASK)
	if (*p && (*p)->pgrp == -pid)
		send_sig(sig,*p,priv);

}

int sys_kill(int pid,int sig)
{
do_kill(pid,sig,!(current->uid || current->euid));
return 0;
}

int do_exit(long code)
{
int i;

free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
for (i=0 ; i<NR_TASKS ; i++)
	if (task[i] && task[i]->father == current->pid)
		task[i]->father = 0;
for (i=0 ; i<NR_OPEN ; i++)
	if (current->filp[i])
		sys_close(i);
iput(current->pwd);
current->pwd=NULL;
iput(current->root);
current->root=NULL;
if (current->leader && current->tty >= 0)
	tty_table[current->tty].pgrp = 0;
if (last_task_used_math == current)
	last_task_used_math = NULL;
if (current->father) {
	current->state = TASK_ZOMBIE;
	do_kill(current->father,SIGCHLD,1);
	current->exit_code = code;
} else
	release(current);
schedule();
return (-1);	/* just to suppress warnings */

}

int sys_exit(int error_code)
{
return do_exit((error_code&0xff)<<8);
}

int sys_waitpid(pid_t pid,int * stat_addr, int options)
{
int flag=0;
struct task_struct ** p;

verify_area(stat_addr,4);

repeat:
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p)
if (*p && *p != current &&
(pid==-1 || (*p)->pidpid ||
(pid
0 && (*p)->pgrpcurrent->pgrp) ||
(pid<0 && (*p)->pgrp
-pid)))
if ((*p)->father == current->pid) {
flag=1;
if ((*p)->state==TASK_ZOMBIE) {
put_fs_long((*p)->exit_code,
(unsigned long *) stat_addr);
current->cutime += (*p)->utime;
current->cstime += (*p)->stime;
flag = (*p)->pid;
release(*p);
return flag;
}
}
if (flag) {
if (options & WNOHANG)
return 0;
sys_pause();
if (!(current->signal &= ~(1<<(SIGCHLD-1))))
goto repeat;
else
return -EINTR;
}
return -ECHILD;
}



fork.c
/*

  • ‘fork.c’ contains the h
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

低调的小哥哥

你的关注就是我为你服务的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值