2010-02-07 139 views
7

外的代碼:訪問標籤的功能

/* 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); 
} 

這是一個小的,合作的,非搶佔內核上下文轉換器。 contextswitch()dispatcher()調用,加載進程的堆棧指針。一旦%esp和其他通用寄存器被載入,調用iret並且用戶進程開始運行。

我需要設置一箇中斷以返回contextswitch()之後的iret之後的位置,這樣我就可以恢復內核上下文並將系統調用的值返回到dispatcher()

如何從函數外部訪問內存地址_entry_point

回答

3

經過一段時間與海灣合作委員會玩,我已經得到了答案。

向下裝配靜音GCC警告關於未使用的標籤。

所以,

_entry_point: 

被替換

asm volatile("_entry_point:"); 

void contextinit() { 
    set_evec_(49, &&_entry_point); 
} 

被替換

void contextinit() { 
    long x; 
    asm("movl $_entry_point, %%eax\n" 
     "movl %%eax, %0": "=g" (x) : : "%eax"); 
    set_evec(49, x); 
} 
4

開關周圍的功能的實現:使它看起來是這樣的:從用戶到內核

  • 上下文切換;
  • 調用內核例程;
  • 上下文從內核切換回用戶。

然後你可以設置中斷從一開始就運行該功能。需要有一個「當前用戶進程」的全局指針 - 在進程間切換,由「調入內核例程」運行的內核代碼只是改變該變量以指向不同的進程。

對於引導後運行的初始進程,您需要一個特殊情況 - 從內核到用戶模式的初始切換。然後,上述功能應該能夠處理它。

+0

這是一個好主意,如果我沒有已經已經寫假設調度和過程控制代碼另一種模式,我可能會使用它。 –

1

除了使用內聯彙編訪問_entry_point,你也可以將它定義爲一個功能,如:

asm volatile("_entry_point:"); 

void contextinit() { 
    extern void _entry_point(); 
    set_evec(49, (long)&_entry_point); 
}