得得得、
d
unsigned int TOTAL_TASK=0;//此变量记录了我们总的任务数,初始值为0.
#define FIRST_TSS_ENTRY 4//第一个TSS,存在于gdt中的第4项
#define FIRST_LDT_ENTRY 5//第一个LDT,存在于gdt中的第5项
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))//计算该TSS的选择子
//跳到该任务,实现任务切换
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("movw %%dx,%1\n\t" \
"ljmp %0\n\t" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n))); \
}
我们任务调度很简单,每次时钟中断都切换到下一个任务,依次轮询。我们的do_timer函数变成了这样:
void do_timer(void)
{
current_task++;
if(current_task>TOTAL_TASK-1)
current_task = 0;
switch_to(current_task);
}
由于每个任务填充tss的操作大致相同,所以我们写了一个registe_task函数
void registe_task(union task_union * task,struct stack_struct *stack,void *test)
{
//填充task1的TSS
task->task.tss.backlink = 0;
task->task.tss.esp0=PAGE_SIZE+(long)task;//&stack1_krn_ptr;
task->task.tss.ss0=0x10;
task->task.tss.eip=test;
task->task.tss.esp = &stack->top;
task->task.tss.flags=0x200;
task->task.tss.es=0x17;
task->task.tss.cs=0xf;
task->task.tss.ss=0x17;
task->task.tss.ds=0x17;
task->task.tss.fs=0x17;
task->task.tss.gs=0x18;
task->task.tss.ldt=(FIRST_LDT_ENTRY+TOTAL_TASK*2)*8;
task->task.tss.trap=0x8000;
task->task.tss.iobase=0x0;
//init_task的LDT 0x28
_set_gdt_desc(&gdt[FIRST_LDT_ENTRY+TOTAL_TASK*2],&(task->task.ldt[0]),0x40,DA_LDT);
//task1的TSS 0x30
_set_gdt_desc(&gdt[FIRST_TSS_ENTRY+TOTAL_TASK*2],&(task->task.tss),0x68,DA_386TSS+DA_DPL3);
TOTAL_TASK++;
}
下面是关于堆栈的一些操作,stack_start用于在head.S中设置堆栈
将mov $0xffff,%esp
改为
lss stack_start,%esp //设置系统堆栈 stack_start -->ss:esp
之前这样乱指实际上是很危险的。
long user_stack [ PAGE_SIZE>>2 ] ;
struct {
long * a;
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x20 };
#define set_stack_registers() \
__asm__ ("movl $0x10,%%eax\n\t" \
"movw %%ax,%%ds\n\t" \
"movw %%ax,%%es\n\t" \
"movw %%ax,%%ss\n\t" \
"lss stack_start,%%esp"\
:::"ax")
我们注意task1的初始化,定义一个堆栈stack1,然后定义一个任务task1.
struct stack_struct{
char stack[256];
int top;
};
struct stack_struct stack0;
struct stack_struct stack1;
static union task_union task1 = {INIT_TASK,};
然后在main函数中用registe_task注册任务。
stack_start.b=0x10;
set_stack_registers();
registe_task(&init_task,&stack0,&testA);
registe_task(&task1,&stack1,&testC);
下面附上完整的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;
unsigned int TOTAL_TASK=0;
#define FIRST_TSS_ENTRY 4
#define FIRST_LDT_ENTRY 5
#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
#define switch_to(n) {\
struct {long a,b;} __tmp; \
__asm__("movw %%dx,%1\n\t" \
"ljmp %0\n\t" \
::"m" (*&__tmp.a),"m" (*&__tmp.b), \
"d" (_TSS(n))); \
}
void do_timer(void)
{
#if 1
current_task++;
if(current_task>TOTAL_TASK-1)
current_task = 0;
switch_to(current_task);
#else
if(current_task)
{
current_task = 0;
enter_task0();
}
else
{
current_task = 1;
//enter_task1();
enter_task(0x30);
}
disp_str("T");
#endif
}
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), };
struct stack_struct{
char stack[256];
int top;
};
struct stack_struct stack0;
struct stack_struct stack1;
static union task_union task1 = {INIT_TASK,};
void registe_task(union task_union * task,struct stack_struct *stack,void *test)
{
//填充task1的TSS
task->task.tss.backlink = 0;
task->task.tss.esp0=PAGE_SIZE+(long)task;//&stack1_krn_ptr;
task->task.tss.ss0=0x10;
task->task.tss.eip=test;
task->task.tss.esp = &stack->top;
task->task.tss.flags=0x200;
task->task.tss.es=0x17;
task->task.tss.cs=0xf;
task->task.tss.ss=0x17;
task->task.tss.ds=0x17;
task->task.tss.fs=0x17;
task->task.tss.gs=0x18;
task->task.tss.ldt=(FIRST_LDT_ENTRY+TOTAL_TASK*2)*8;
task->task.tss.trap=0x8000;
task->task.tss.iobase=0x0;
//init_task的LDT 0x28
_set_gdt_desc(&gdt[FIRST_LDT_ENTRY+TOTAL_TASK*2],&(task->task.ldt[0]),0x40,DA_LDT);
//task1的TSS 0x30
_set_gdt_desc(&gdt[FIRST_TSS_ENTRY+TOTAL_TASK*2],&(task->task.tss),0x68,DA_386TSS+DA_DPL3);
TOTAL_TASK++;
}
long user_stack [ PAGE_SIZE>>2 ] ;
struct {
long * a;
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , 0x20 };
#define set_stack_registers() \
__asm__ ("movl $0x10,%%eax\n\t" \
"movw %%ax,%%ds\n\t" \
"movw %%ax,%%es\n\t" \
"movw %%ax,%%ss\n\t" \
"lss stack_start,%%esp"\
:::"ax")
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);
stack_start.b=0x10;
set_stack_registers();
registe_task(&init_task,&stack0,&testA);
registe_task(&task1,&stack1,&testC);
//task[1] = &(task1.task);
ltr();//加载tss
lldt();//加载ldt
sti();//开中断
move_to_user_mode();
while(1);
}