2010-02-07 19 views
7

Kod:Dostęp etykietę z poza funkcją

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

Jest to przełącznik kontekst dla małej, spółdzielni, jądra zakaz poboru. contextswitch() jest wywoływane przez dispatcher() ze wskaźnikiem stosu procesu do załadowania. Po załadowaniu% esp i innych rejestrów ogólnego przeznaczenia, wywoływana jest nazwa iret i rozpoczyna się proces użytkownika.

muszę skonfigurować przerwanie, aby powrócić do punktu, w contextswitch() po iret więc mogę przywrócić kontekst jądra i zwracają wartość syscall do dispatcher().

Jak uzyskać dostęp do adresu pamięci _entry_point spoza funkcji?

Odpowiedz

3

Po krótkiej zabawie z GCC otrzymałem odpowiedź.

Upuszczanie do wyciszenia montażowego Ostrzeżenia GCC o nieużywanych etykietach.

Więc

_entry_point: 

otrzymuje z

asm volatile("_entry_point:"); 

i

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

otrzymuje z

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

Przełącznik realizacja funkcji wokół: sprawiają, że wygląda tak:

  • przełączania kontekstu od użytkownika do jądra;
  • Zadzwoń do procedur jądra;
  • Przełącznik kontekstu z powrotem z jądra do użytkownika.

Następnie wystarczy ustawić przerwanie, aby uruchomić funkcję od początku. Musi istnieć globalny wskaźnik dla "bieżącego procesu użytkownika" - aby przełączać się między procesami, kod jądra uruchamiany przez "Call into rin-dry" po prostu zmienia tę zmienną, by wskazywała na inny proces.

Będziesz potrzebował jednego specjalnego przypadku - do początkowego przełączenia z jądra do trybu użytkownika dla początkowego procesu uruchomionego po rozruchu. Potem jednak powyższa funkcja powinna być w stanie sobie z tym poradzić.

+0

Jest to dobry pomysł, a jeśli nie mają już kod dyspozytor i kontrola procesu już napisane przy założeniu, drugi model, mógłbym go użyć. –

1

Poza tym przy użyciu zestawu inline aby uzyskać dostęp do _entry_point, można również zdefiniować go jako funkcji, takich jak:

asm volatile("_entry_point:"); 

void contextinit() { 
    extern void _entry_point(); 
    set_evec(49, (long)&_entry_point); 
} 
Powiązane problemy