任务切换

首先我们的中断处理函数过于简单,起码应该保持相关的寄存器,所以System_call.S修改如下:

.globl timer_interrupt
timer_interrupt:
	push %ds
	pushl %edx
	pushl %ecx
	pushl %ebx
	pushl %eax
	movl $0x10, %eax
	mov %ax, %ds
	incl jiffies
	movb $0x20,%al	
	outb %al,$0x20
	call do_timer
	popl %eax
	popl %ebx
	popl %ecx
	popl %edx
	pop %ds
	iret

通过前面的实验我们知道一个任务应该有自己的ldt和tss,另外还应该记录当前的状态,以及标识自己的pid和father

struct task_struct {
	long state;
	long pid,father;
	struct desc_struct ldt[3];
/* tss for this task */
	struct tss_struct tss;
};

下面我们开始构造任务,init_task是任务0,task1是任务1,INIT_TASK纯粹是为了填充结构体方便,task_unio中的stack是任务在内核态的堆栈。

#define INIT_TASK \
{  0,0,0,\
	{ \
		{0,0}, \
/* ldt */	{0x9f,0xc0fa00}, \
		{0x9f,0xc0f200}, \
	}, \
/*tss*/	{\
	}, \
}

#define PAGE_SIZE 4096
union task_union {
	struct task_struct task;
	char stack[PAGE_SIZE];
};
static union task_union init_task = {INIT_TASK,};
static union task_union task1 = {INIT_TASK,};


下面是任务在ring3的堆栈

struct stack_struct{
	char stack[256];
	int  top;
};
struct stack_struct stack0;
struct stack_struct stack1;

在下面我重新整理了gdt,然后填充ldt和tss

void main(void)
{

	disp_str("How old are you?\n");
	set_intr_gate(32,&timer_interrupt);
	_set_gdt_desc(&gdt[1],0x0000,0x7ff,DA_CR+DA_32+DA_LIMIT_4K);
	//堆栈段 0x10
	_set_gdt_desc(&gdt[2],0x0000,0x7ff,DA_DRW+DA_32+DA_LIMIT_4K);
	//视频段 0x18
	_set_gdt_desc(&gdt[3],0xb8000,0x2,DA_DRW+DA_32+DA_DPL3+DA_LIMIT_4K);
	//init_task的LDT  0x28
	_set_gdt_desc(&gdt[5],&init_task.task.ldt[0],0x40,DA_LDT);
	//task1的LDT  0x38
	_set_gdt_desc(&gdt[7],&task1.task.ldt[0],0x40,DA_LDT);

	//填充init_task的TSS
	init_task.task.tss.backlink = 0;
	init_task.task.tss.esp0=PAGE_SIZE+(long)&init_task;
	init_task.task.tss.ss0=0x10;
	init_task.task.tss.eip=&testA;
	init_task.task.tss.esp = &stack0.top;
	init_task.task.tss.flags=0x200;
	init_task.task.tss.es=0x17;
	init_task.task.tss.cs=0xf;
	init_task.task.tss.ss=0x17;
	init_task.task.tss.ds=0x17;
	init_task.task.tss.fs=0x17;
	init_task.task.tss.gs=0x18;
	init_task.task.tss.ldt=0x28;
	init_task.task.tss.trap=0x8000;
	init_task.task.tss.iobase=0x0;
	//init_task的TSS  0x20
	_set_gdt_desc(&gdt[4],&init_task.task.tss,0x68,DA_386TSS+DA_DPL3);
	
	//填充task1的TSS
	task1.task.tss.backlink = 0;
	task1.task.tss.esp0=PAGE_SIZE+(long)&task1;//&stack1_krn_ptr;
	task1.task.tss.ss0=0x10;
	task1.task.tss.eip=&testC;
	task1.task.tss.esp = &stack1.top;
      
	task1.task.tss.flags=0x200;
	task1.task.tss.es=0x17;
	task1.task.tss.cs=0xf;
	task1.task.tss.ss=0x17;
	task1.task.tss.ds=0x17;
	task1.task.tss.fs=0x17;
	task1.task.tss.gs=0x18;
	    
	task1.task.tss.ldt=0x38;
	task1.task.tss.trap=0x8000;
	task1.task.tss.iobase=0x0;
	//task1的TSS  0x30
	_set_gdt_desc(&gdt[6],&task1.task.tss,0x68,DA_386TSS+DA_DPL3);
	//task[1] = &(task1.task);
	ltr();//加载tss
	lldt();//加载ldt
	sti();//开中断
	move_to_user_mode();

	while(1);
}
任务有了就该任务切换了,这个动作我们在do_timer函数中做

int current_task=0;
//task0的tss选择子为0x20;task1的tss选择子为0x30
#define enter_task0() __asm__ ("ljmp $0x20, $0\n\t" :::)
#define enter_task1() __asm__ ("ljmp $0x30, $0\n\t" :::)

void do_timer(void)
{
	if(current_task)
	{
		current_task = 0;
		enter_task0();
	}
	else
	{
		current_task = 1;
		enter_task1();
	}
	disp_str("T");
}


由于重新整理了gdt,所以一些选择子要相应改变,并且添加了相应的宏定义

#define	DA_CR		0x9A
#define	DA_LIMIT_4K	0x8000
#define	DA_386TSS 0x89	
#define DA_LDT  0x82

#define set_registers() \
__asm__ ("movl $0x17,%%eax\n\t" \
	"movw %%ax,%%ds\n\t" \
	"movw %%ax,%%es\n\t" \
	"movw %%ax,%%fs\n\t" \
	"movw $0x18,%%ax\n\t" \
	"movw %%ax,%%gs" \
	:::"ax")

#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
	"pushl $0x17\n\t" \
	"pushl %%eax\n\t" \
	"pushfl\n\t"\
	"pushl $0xf\n\t" \
	"pushl $testA\n\t" \
	"iret\n" \
	:::"ax")
		
#define lldt() \
__asm__ ("movw $0x28,%%ax\n\t" \
	"lldt     %%ax\n\t" \
	:::"ax")
		
#define ltr() \
__asm__ ("movw $0x20,%%ax\n\t" \
	"ltr     %%ax\n\t" \
	:::"ax")
中循环打印一个‘C’
void testC(void)		
{
	while(1){
		disp_str("C");
		delay(2);
	}
}

执行效果如下图,A是任务0打印的,C是任务1打印的,T是do_timer中打印的

任务切换_第1张图片


main.c的完整代码如下:

#include <linux/head.h>
#include <asm/system.h>
#include <asm/io.h>
extern void divide_error(void);
void disp_str(char *info);

#define DA_C    	0x98    
#define DA_32   	0x4000 	
#define	DA_DPL3		0x60
#define	DA_DPL0		0x00
#define	DA_DRWA 	0x93
#define	DA_DRW 		0x92
#define	SA_RPL3  	3 
#define	DA_CR		0x9A
#define	DA_LIMIT_4K	0x8000
#define	DA_386TSS 0x89	
#define DA_LDT  0x82

#define set_registers() \
__asm__ ("movl $0x17,%%eax\n\t" \
	"movw %%ax,%%ds\n\t" \
	"movw %%ax,%%es\n\t" \
	"movw %%ax,%%fs\n\t" \
	"movw $0x18,%%ax\n\t" \
	"movw %%ax,%%gs" \
	:::"ax")

#define move_to_user_mode() \
__asm__ ("movl %%esp,%%eax\n\t" \
	"pushl $0x17\n\t" \
	"pushl %%eax\n\t" \
	"pushfl\n\t"\
	"pushl $0xf\n\t" \
	"pushl $testA\n\t" \
	"iret\n" \
	:::"ax")
		
#define lldt() \
__asm__ ("movw $0x28,%%ax\n\t" \
	"lldt     %%ax\n\t" \
	:::"ax")
		
#define ltr() \
__asm__ ("movw $0x20,%%ax\n\t" \
	"ltr     %%ax\n\t" \
	:::"ax")				
void delay(int time)
{
	int i, j, k;
	for (k = 0; k < time; k++) {
		for (i = 0; i < 10; i++) {
			for (j = 0; j < 10000; j++) {}
		}
	}
}
void testA(void)		
{

	set_registers();
	while(1){
		disp_str("A");
		delay(2);
	}
}
void testC(void)		
{
	while(1){
		disp_str("C");
		delay(2);
	}
}

typedef	unsigned int		u32;
typedef	unsigned short	u16;
typedef	unsigned char		u8;
typedef struct Descriptor		/* ???8 ??a?-?è??*/
{
	u16	limit_low;		/* Limit */
	u16	base_low;		/* Base */
	u8	base_mid;		/* Base */
	u8	attr1;			/* P(1) DPL(2) DT(1) TYPE(4) */
	u8	limit_high_attr2;	/* G(1) D(1) 0(1) AVL(1) LimitHigh(4) */
	u8	base_high;		/* Base */
}DESCRIPTOR;
void _set_gdt_desc(struct desc_struct *descriptor_addr,u32 base,u32 limit,u16 attr)
{
	DESCRIPTOR *descriptor = (DESCRIPTOR *)descriptor_addr;
	descriptor->limit_low	= limit & 0x0FFFF;
	descriptor->base_low		= base & 0x0FFFF;
	descriptor->base_mid		= (base >> 16) & 0x0FF;
	descriptor->attr1			= attr & 0xFF;
	descriptor->limit_high_attr2= ((limit>>16) & 0x0F) | (attr>>8) & 0xF0;
	descriptor->base_high	= (base >> 24) & 0x0FF;
}



typedef struct tss_struct {
	u32	backlink;
	u32	esp0;	/* stack pointer to use during interrupt */
	u32	ss0;	/*   "   segment  "  "    "        "     */
	u32	esp1;
	u32	ss1;
	u32	esp2;
	u32	ss2;
	u32	cr3;
	u32	eip;
	u32	flags;
	u32	eax;
	u32	ecx;
	u32	edx;
	u32	ebx;
	u32	esp;
	u32	ebp;
	u32	esi;
	u32	edi;
	u32	es;
	u32	cs;
	u32	ss;
	u32	ds;
	u32	fs;
	u32	gs;
	u32	ldt;
	u16	trap;
	u16	iobase;		/* I/O位图基址大于或等于TSS段界限,就表示没有I/O许可位图 */
}TSS;

extern void timer_interrupt(void);
long volatile jiffies=0;
int current_task=0;
//task0的tss选择子为0x20;task1的tss选择子为0x30
#define enter_task0() __asm__ ("ljmp $0x20, $0\n\t" :::)
#define enter_task1() __asm__ ("ljmp $0x30, $0\n\t" :::)

void do_timer(void)
{
	if(current_task)
	{
		current_task = 0;
		enter_task0();
	}
	else
	{
		current_task = 1;
		enter_task1();
	}
	disp_str("T");
}


struct task_struct {
	long state;
	long pid,father;
	struct desc_struct ldt[3];
/* tss for this task */
	struct tss_struct tss;
};

#define INIT_TASK \
{  0,0,0,\
	{ \
		{0,0}, \
/* ldt */	{0x9f,0xc0fa00}, \
		{0x9f,0xc0f200}, \
	}, \
/*tss*/	{\
	}, \
}

#define PAGE_SIZE 4096
#define NR_TASKS 64
union task_union {
	struct task_struct task;
	char stack[PAGE_SIZE];
};
static union task_union init_task = {INIT_TASK,};
//struct task_struct *current = &(init_task.task);
//struct task_struct * task[NR_TASKS] = {&(init_task.task), };
static union task_union task1 = {INIT_TASK,};

struct stack_struct{
	char stack[256];
	int  top;
};
struct stack_struct stack0;
struct stack_struct stack1;
void main(void)
{

	disp_str("How old are you?\n");
	set_intr_gate(32,&timer_interrupt);
	_set_gdt_desc(&gdt[1],0x0000,0x7ff,DA_CR+DA_32+DA_LIMIT_4K);
	//堆栈段 0x10
	_set_gdt_desc(&gdt[2],0x0000,0x7ff,DA_DRW+DA_32+DA_LIMIT_4K);
	//视频段 0x18
	_set_gdt_desc(&gdt[3],0xb8000,0x2,DA_DRW+DA_32+DA_DPL3+DA_LIMIT_4K);
	//init_task的LDT  0x28
	_set_gdt_desc(&gdt[5],&init_task.task.ldt[0],0x40,DA_LDT);
	//task1的LDT  0x38
	_set_gdt_desc(&gdt[7],&task1.task.ldt[0],0x40,DA_LDT);

	//填充init_task的TSS
	init_task.task.tss.backlink = 0;
	init_task.task.tss.esp0=PAGE_SIZE+(long)&init_task;
	init_task.task.tss.ss0=0x10;
	init_task.task.tss.eip=&testA;
	init_task.task.tss.esp = &stack0.top;
	init_task.task.tss.flags=0x200;
	init_task.task.tss.es=0x17;
	init_task.task.tss.cs=0xf;
	init_task.task.tss.ss=0x17;
	init_task.task.tss.ds=0x17;
	init_task.task.tss.fs=0x17;
	init_task.task.tss.gs=0x18;
	init_task.task.tss.ldt=0x28;
	init_task.task.tss.trap=0x8000;
	init_task.task.tss.iobase=0x0;
	//init_task的TSS  0x20
	_set_gdt_desc(&gdt[4],&init_task.task.tss,0x68,DA_386TSS+DA_DPL3);
	
	//填充task1的TSS
	task1.task.tss.backlink = 0;
	task1.task.tss.esp0=PAGE_SIZE+(long)&task1;//&stack1_krn_ptr;
	task1.task.tss.ss0=0x10;
	task1.task.tss.eip=&testC;
	task1.task.tss.esp = &stack1.top;
      
	task1.task.tss.flags=0x200;
	task1.task.tss.es=0x17;
	task1.task.tss.cs=0xf;
	task1.task.tss.ss=0x17;
	task1.task.tss.ds=0x17;
	task1.task.tss.fs=0x17;
	task1.task.tss.gs=0x18;
	    
	task1.task.tss.ldt=0x38;
	task1.task.tss.trap=0x8000;
	task1.task.tss.iobase=0x0;
	//task1的TSS  0x30
	_set_gdt_desc(&gdt[6],&task1.task.tss,0x68,DA_386TSS+DA_DPL3);
	//task[1] = &(task1.task);
	ltr();//加载tss
	lldt();//加载ldt
	sti();//开中断
	move_to_user_mode();

	while(1);
}


你可能感兴趣的:(任务切换)