一步一步实现一个简单的OS(任务切换)

之前因为工作忙,好长时间没更了。

这次把进程切换里面的寄存器上下文切换详细的说一下吧。感觉有必要


先码几行代码,这样好说

// 任务的寄存器上下文数据结构
/* 
 * 在内存里面的数据结构为
 * 0x00000000 [eip]
 * 0x00000004 [esp]
 * 0x00000008 [ebx]
 * 0x00000012 [ecx]
 * 0x00000016 [edx]
 * 0x00000020 [esi]
 * 0x00000024 [edi]
 * 0x00000028 [ebp]
 */
/*
 * 在C里面的定义为
 */
struct context{
    uint eip;
    uint esp;
    uint ebx;
    uint ecx;
    uint edx;
    uint esi;
    uint edi;
    uint ebp;
};


// 这个是任务0的上下文
struct context task0_con;

void task0()
{
    // 这个代表由任务0切换到任务1
    swtch(&task0_con, &task1_con);
}

// 这个是任务1的上下文
struct context task1_con;

void task1()
{
    // 由任务1切换到任务0
    swtch(&task1_con, &task0_con);
}

swtch:
    mov   eax, dword [esp + 4]

    pop    dword [eax]
    mov    dword [eax + 4], esp
    mov    dword [eax + 8], ebx
    mov    dword [eax + 12], ecx
    mov    dword [eax + 16], edx
    mov    dword [eax + 20], esi
    mov    dword [eax + 24], edi
    mov    dword [eax + 28], ebp

    mov    eax, dword [esp + 4]

    mov    ebp, dword [eax + 28]
    mov    edi, dword [eax + 24]
    mov    esi, dword [eax + 20]
    mov    edx, dword [eax + 16]
    mov    ecx, dword [eax + 12]
    mov    ebx, dword [eax + 8]
    mov    esp, dword [eax + 4]
    push   dword [eax]
    
    ret


下面就模拟一遍吧,

假设当前CPU运行的是任务0(task0):

在调用swtch之前,其堆栈为

task0_stack:

    0x00000400 [0xFFFFFFF0]       ;  0xFFFFFFF0就用来表示任务0(task0)的栈底了


当调用swtch后,其堆栈为

task0_stack (swtch start):

    0x000003F4 [task0 的返回地址]

    0x000003F8 [task0_con]   ; 这里的task0_con指的是地址

    0x000003FC [task1_con]     ; 这里的task1_con指的是地址

    0x00000400 [0xFFFFFFF0]


swtch:

   将 esp + 4中的内容赋值给eax,即 eax <= &task0_con;

   然后把“task0 的返回地址”弹出堆栈,赋值给 dword [eax],即 task0_con.eip = task0 的返回地址

   之后分别吧esp, ebx, ecx, edx, esi, edi, ebp 赋值给 task0_con 中的对应项

赋值完毕之后,也就是CPU执行完swtch的第 10行,

mov    dword [eax + 28], ebp
其堆栈为

task0_stack:

    0x000003F8 [task0_con]   ; 这里的task0_con指的是地址

    0x000003FC [task1_con]     ; 这里的task1_con指的是地址

    0x00000400 [0xFFFFFFF0]


然后把 esp + 4 中的内容赋值给eax,即 eax = &task1_con

之后赋值寄存器,和上面的操作差不多,不过这次是把task1_con中对应寄存器的值赋值给cpu的寄存器中

最后把task1_con.eip压入堆栈,也就是把任务1的返回地址压入堆栈,其堆栈结构为(压栈这一行上面已经把栈顶改为任务1的了,"mov esp, dword [eax + 4]")

task1_stack:

    0x000007FC [task1 的返回地址]

    0x00000800 [0xFFFFFFF1]    ;  0xFFFFFFF1就用来表示任务1(task1)的栈底了


然后ret之后就返回到任务1中执行了,

之后调用swtch时和上面所说的步骤一样,只是切换的方式相反了,由任务1切换到任务0


当然大家也可以在 struct context中加上elfags寄存器,这样就更完美了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值