简单的进程切换方法,
1、为每个进程设计一个独立的页目录
2、所有进程共用高2G的线性内存,每个进程独享低2G线性内存(暂时保留前4M)
3、每个进程主线程一个栈
4、在普通函数中调用进程切换函数,
好处,只需切换CR3 和栈,超简单。
主线程检测进程时间片,主动切换。
void create_Process(DWORD entry)
{
DWORD page_sys,page_pyh,page_line,page_stack;
//查找空余进程空余位置
//DWORD * processptelist=(DWORD *)(PTE_BASE+(PROCESS_PDE_LIST>>22<<12)+(PROCESS_PDE_LIST<<10>>22<<2));
int i;
//资源用完
if (process_count_proc>=1024) return;
//每一个进程分配一页物理地址,用作页目录,
//同时该页目录还映射至0x80000000(2G)以上线性地址,
//方便每一个进程都能访问所有页目录(是否须要?节省线性地址)
//申请一页物理内存作为新进程的页目录,
page_pyh=(DWORD)getFreedPagePhysicsMemory();
//申请一页线性地址
page_line=(DWORD)getFreePageVirtual(1);
//将页表映射至线性地址,方面读写,
MapMem(page_pyh,page_line,1);
//所有进程物理前4M地址与线性地址相等(可以减少)
page_sys=PDE_BASE;
((DWORD*)page_line)[0]=((DWORD*)page_sys)[0];
//所有进程物理2G以上地址相同(可以减少)
copymem((char * )(page_line+4*512),(char * )(page_sys+4*512),4*512);
//第0x300项指向自身,从而0xc0000000 可以访问各自的页目录
((DWORD*)page_line)[0x300]=page_pyh;
//为每个进程申请页栈,栈是逆序后入先出,
page_stack=(DWORD)getFreePageVirtual(1)+0x1000-4;
//申请进程信息表
PProcessInfo pi=xos_malloc(sizeof(ProcessInfo));
//进程切换主要是Cr3和栈的切换,其他的代码先保留。
pi->tss.cr3=(DWORD) page_pyh;
pi->regs.cs = (0 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
pi->regs.ds = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
pi->regs.es = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
pi->regs.fs = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
pi->regs.ss = (8 & SA_RPL_MASK & SA_TI_MASK) | SA_TIL | RPL_TASK;
pi->regs.gs = (SELECTOR_KERNEL_GS & SA_RPL_MASK) | RPL_TASK;
pi->regs.eip= (DWORD)entry;
#define offset 20
//设计新进程主线程的栈
pi->regs.ebp=pi->regs.esp= (DWORD)page_stack-offset-8;
//对应swith_process,返回时
//
*(DWORD*)(page_stack-offset-8)=page_stack-12;
*(DWORD*)(page_stack-offset-4)=(DWORD)entry;
//下面数据用不上,先保留
*(DWORD*)(page_stack-12)=page_stack-8;
*(DWORD*)(page_stack-8)= 0x8; //code
*(DWORD*)(page_stack-4)= 0x202; //eflags
*(DWORD*)(page_stack-0)=entry;
//pi->regs.eflags = 0x202; // IF=1, IOPL=1, bit 2 is always 1.
#undef offset
//进程运行时间片
pi->current_tick=TIMER_COUNT;
pi->elapsed_ticks=0;
//加入进程运行列表
add_process(pi);
}
void main_thread(char * file)
{
//当前进程,下一个运行的进程
PProcessInfo next_pi,pi=getCurrentProcess();
do{
if (pi->current_tick>=0)
{
//时间片没用完,继续
pi->current_tick--;
}
else
{
//时间片用完,切换进程
pi->current_tick=TIMER_COUNT;
next_pi=get_next_process(pi);
if (pi==next_pi)
{
//仅一个进程无需切换
}
else
{
//测试函数
TestC(file);
swith_process(pi,next_pi);
}
}
}while(true);
}
void swith_process(PProcessInfo prv_pi,PProcessInfo next_pi)
{
//常规函数调用只需要保存CR3 和esp ebp ,
//如果是中断中切换,可能需要保存所有寄存器(待试验)
//最后两条指令 leave ret(编译后可能有变化)
//等价于:movl %ebp %esp popl %ebp pop %eip
asm("mov %%esp,%0\n\t "\
"mov %1,%%cr3\n\t "\
"mov %2,%%esp\n\t "\
:"=m"(prv_pi->regs.esp) //输出
:"r"(next_pi->tss.cr3),"m"(next_pi->regs.esp)
);
}