基于内核栈切换的进程切换

转载自https://www.lanqiao.cn/courses/reports/1420124/

1 在 kernel/.sched.c 中修改

在适当位置定义全局变量 tss

/* start */
struct tss_struct *tss = &(init_task.task.tss);
/* end */

修改 schedule() 函数中的 switch_to() 调用:

 switch_to(task[next],_LDT(next));

2 在 include/linux/sched.h 中修改

在头部声明两个函数

/* add */
void switch_to(struct task_struct *, int);
void first_return_from_kernel();
/* end */

在 struct task_struct 结构体增加变量 kernelstack,这里增加到第四行,也就是李治军老师说的位置12

long state;     /* -1 unrunnable, 0 runnable, >0 stopped */
        long counter;
        long priority;
        long kernelstack;
        long signal;

将原来的#define INIT_TASK
/* state etc / { 0,15,15,
/ signals / 0,{{},},0,
更改为#define INIT_TASK
/ state etc / { 0,15,15,PAGE_SIZE+(long)&init_task ,
/ signals */ 0,{{},},0, \

最后要将 switch_to 的宏实现注释掉

3 增加和修改硬编码,主要是我们在 task_struct 中增加了一个变量,因此需要改变这里变量的位置,修改kernel/system_call.s

ESP0 = 4
state   = 0             # these are offsets into the task-struct.
counter = 4
priority = 8
KERNEL_STACK = 12
signal  = 12 + 4
sigaction = 16 + 4      # MUST be 16 (=len of sigaction)
blocked = (33*16 + 4)

增加全局标识符,使汇编函数变成全局函数

.globl first_return_from_kernel,switch_to

增加 switch_to 和 first_return_from_kernel 的实现

switch_to:
    pushl %ebp
    movl %esp,%ebp
    pushl %ecx
    pushl %ebx
    pushl %eax
    pushl %es
    pushl %gs
    pushl %esi
    pushl %edi
    pushl %edx
    movl 8(%ebp),%ebx
    cmpl %ebx,current
    je 1f
# Switch PCB
    movl %ebx,%eax
    xchgl %eax,current
# Overrides of kernel stack pointers in TSS
    movl tss,%ecx
    addl $4096,%ebx
    movl %ebx,ESP0(%ecx)
# Switch kernel stack
   movl %esp,KERNEL_STACK(%eax)
   movl 8(%ebp),%ebx
   movl KERNEL_STACK(%ebx),%esp
# Switch LDT
    movl 12(%ebp),%ecx
    lldt %cx
    movl $0x17,%ecx
    mov %cx,%fs
    cmpl %eax,last_task_used_math
    jne 1f
    clts

1: popl %edx
    popl %edi
    popl %esi
    popl %gs
    popl %es
    popl %eax
    popl %ebx
    popl %ecx
    popl %ebp
ret

first_return_from_kernel:
    popl %edx
    popl %edi
    popl %esi
    pop %gs
    pop %fs
    pop %es
    pop %ds
    iret

4 修改fork.c 同样,这里需要将一些栈添加进去:

这里修改copy_process函数。第一,添加变量krnstack;第二,krnstack指向一些栈。以下为修改后的copy_process。

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;

        long *krnstack;

        p = (struct task_struct *) get_free_page();
        if (!p)
                return -EAGAIN;
        task[nr] = p;
        *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;
        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;
        }

     krnstack = (long*)(PAGE_SIZE + (long)p);//stack pionter
    *(--krnstack) = ss & 0xffff;
    *(--krnstack) = esp;
    *(--krnstack) = eflags;
    *(--krnstack) = cs & 0xffff;
    *(--krnstack) = eip;
    // stack for schedule
    *(--krnstack) = ds & 0xffff;
    *(--krnstack) = es & 0xffff;
    *(--krnstack) = fs & 0xffff;
    *(--krnstack) = gs & 0xffff;
    *(--krnstack) = esi;
    *(--krnstack) = edi;
    *(--krnstack) = edx;
    *(--krnstack) = first_return_from_kernel;
    *(--krnstack) = ebp;
    *(--krnstack) = ecx;
    *(--krnstack) = ebx;
    *(--krnstack) = 0; //0 for res
    *(--krnstack) = es;
    *(--krnstack) = gs;
    *(--krnstack) = esi;
    *(--krnstack) = edi;
    *(--krnstack) = edx;
    p->kernelstack = krnstack;

        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;
}

运行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值