代码:
/* ctsw.c : context switcher
*/
#include <kernel.h>
static void *kstack;
extern int set_evec(int, long);
/* contextswitch - saves kernel context, switches to proc */
enum proc_req contextswitch(struct proc_ctrl_blk *proc) {
enum proc_req call;
kprintf("switching to %d\n", getpid(proc));
asm volatile("pushf\n" // save kernel flags
"pusha\n" // save kernel regs
"movl %%esp, %0\n" // save kernel %esp
"movl %1, %%esp\n" // load proc %esp
"popa\n" // load proc regs (from proc stack)
"iret" // switch to proc
: "=g" (kstack)
: "g" (proc->esp)
);
_entry_point:
asm volatile("pusha\n" // save proc regs
"movl %%esp, %0\n" // save proc %esp
"movl %2, %%esp\n" // restore kernel %esp
"movl %%eax, %1\n" // grabs syscall from process
"popa\n" // restore kernel regs (from kstack)
"popf" // restore kernel flags
: "=g" (proc->esp), "=g" (call)
: "g" (kstack)
);
kprintf("back to the kernel!\n");
return call;
}
void contextinit() {
set_evec(49, (long)&&_entry_point);
}
Run Code Online (Sandbox Code Playgroud)
它是一个小型,协作,非抢占式内核的上下文切换器.使用要加载的进程的堆栈指针contextswitch()
调用dispatcher()
.一旦加载了%esp和其他通用寄存器,iret
就会调用它并且用户进程开始运行.
我需要设置一个中断返回点contextswitch()
以后iret
,所以我可以恢复内核上下文并返回系统调用到的值dispatcher()
.
如何_entry_point
从函数外部访问内存地址?
在玩了一会儿 GCC 之后,我得到了答案。
下降到程序集会消除有关未使用标签的 GCC 警告。
所以,
_entry_point:
Run Code Online (Sandbox Code Playgroud)
被替换为
asm volatile("_entry_point:");
Run Code Online (Sandbox Code Playgroud)
和
void contextinit() {
set_evec_(49, &&_entry_point);
}
Run Code Online (Sandbox Code Playgroud)
被替换为
void contextinit() {
long x;
asm("movl $_entry_point, %%eax\n"
"movl %%eax, %0": "=g" (x) : : "%eax");
set_evec(49, x);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
678 次 |
最近记录: |