2010-02-07 16 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 कहा जाता है और उपयोगकर्ता प्रक्रिया चलना शुरू हो जाती है।

मैं सेटअप करने के लिए एक अवरोध की जरूरत iret के बाद contextswitch() में बात करने के लिए वापस जाने के लिए तो मैं गिरी संदर्भ बहाल करने और dispatcher() को syscall का मूल्य लौट सकते हैं।

मैं फ़ंक्शन के बाहर से _entry_point के मेमोरी पते का उपयोग कैसे कर सकता हूं?

उत्तर

3

जीसीसी के साथ खेलने के दौरान थोड़ी देर के बाद, मुझे एक जवाब मिला।

असेंबली को छोड़कर अप्रयुक्त लेबल के बारे में जीसीसी चेतावनियां चुप रहती हैं।

तो,

_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); 
} 
संबंधित मुद्दे