2017-01-21 9 views
5

में वास्तविक से सुरक्षित मोड से संक्रमण मैं वर्तमान में ऑपरेटिंग सिस्टम के निम्न स्तर के संगठन का अध्ययन कर रहा हूं। यह स्वीकार करने के लिए कि मैं समझने की कोशिश कर रहा हूं कि लिनक्स कर्नेल कैसे लोड किया जाता है।लिनक्स कर्नेल

एक चीज जिसे मैं समझ नहीं पा रहा हूं वह 16-बिट (वास्तविक मोड) से 32-बिट (संरक्षित मोड) में संक्रमण है। यह this file में होता है।

protected_mode_jump समारोह है कि बाद में मार डाला है 32-बिट कोड के लिए विभिन्न सहायक गणना करता है, तो CR0 reguster

movl %cr0, %edx 
    orb $X86_CR0_PE, %dl # Protected mode 
    movl %edx, %cr0 

में PE बिट सक्षम बनाता है और उसके बाद 32-बिट कोड के लिए लंबी कूद करता है:

# Transition to 32-bit mode 
    .byte 0x66, 0xea  # ljmpl opcode 
2: .long in_pm32   # offset 
    .word __BOOT_CS  # segment 

जहां तक ​​मेरा in_pm32 समझते हैं जो सही protected_mode_jump नीचे घोषित किया जाता है 32-बिट समारोह का पता है:

+०१२३५१६४१०
.code32 
    .section ".text32","ax" 
GLOBAL(in_pm32) 
    # some code 
    # ... 
    # some code 
ENDPROC(in_pm32) 

__BOOT_CS क्षेत्र आधार 0 (GDT पहले से here सेट किया गया है), तो यह है कि इसका मतलब है कि ऑफसेट in_pm32 समारोह के मूल रूप से पूर्ण पता होना चाहिए।

यह मुद्दा है। मशीन कोड पीढ़ी के दौरान असेंबलर/लिंकर को in_pm32 फ़ंक्शन का पूर्ण पता नहीं पता होना चाहिए, क्योंकि यह नहीं जानता कि यह वास्तविक मोड में स्मृति में कहां लोड किया जाएगा (विभिन्न बूटलोडर्स अंतरिक्ष की विभिन्न मात्रा और वास्तविक मोड पर कब्जा कर सकते हैं कर्नेल को बूटलोडर के ठीक बाद लोड किया जाता है)।

इसके अलावा, लिंकर स्क्रिप्ट (setup.ld एक ही फ़ोल्डर में) कोड की उत्पत्ति 0 के रूप में सेट करता है, ऐसा लगता है कि in_pm32 पता वास्तविक मोड कर्नेल की शुरुआत से ऑफ़सेट होगा। इसे 16-बिट कोड के साथ ठीक काम करना चाहिए क्योंकि CS रजिस्टर ठीक से सेट किया गया है, लेकिन जब लंबी कूद होती है तो सीपीयू पहले से ही सुरक्षित मोड में है, इसलिए एक रिश्तेदार ऑफसेट काम नहीं करना चाहिए।

तो मेरे सवाल: क्यों संरक्षित मोड (.byte 0x66, 0xea) में लंबी कूद उचित कोड स्थिति सेट करता है, तो ऑफसेट (.long in_pm32) रिश्तेदार है करता है?

ऐसा लगता है कि मुझे कुछ वाकई महत्वपूर्ण याद आ रहा है।

+1

मैं बिस्तर पर जाने वाला हूं क्योंकि यह 3:30 बजे है। मैंने केवल जेएमपी के बारे में हिस्सा देखा। वह कूद एक 32-बिट एफएआर जेएमपी है जो _CS_ चयनकर्ता सेट करता है। सीआर 0 में संरक्षित मोड बिट को सेट करना वास्तव में आपको एक अर्ध 16-बिट संरक्षित मोड में डाल देता है। 32-बिट संरक्षित मोड में जाने के लिए आपको एक एफएआर जेएमपी करना होगा जो एक चयनकर्ता (__BOOT_CS) और ऑफसेट लेता है और उस पर कूदता है। __BOOT_CS एक चयनकर्ता होना चाहिए जो जीडीटी में 32-बिट कोड सेगमेंट डिस्क्रिप्टर (0 के आधार और 0xffffffff की सीमा के साथ) पर इंगित करता है। जब वह एफएआर जेएमपी पूरा हो जाए तो यह 32-बिट संरक्षित मोड में होगा। –

+1

संक्षेप में कि एफएआर जेएमपी को अर्ध 16-बिट संरक्षित मोड से 32-बिट संरक्षित मोड में प्राप्त करने की आवश्यकता है। –

+0

वास्तव में, '__BOOT_CS' चयनकर्ता आधार 0 है। मुझे लगता है कि इसका मतलब है कि FAR JUMP को वांछित फ़ंक्शन/लेबल का पूर्ण पता लेना चाहिए (क्योंकि' 0 + ऑफ़सेट 'केवल' ऑफ़सेट' होगा)। लेकिन यहां पर एफएआर जंप को सापेक्ष ऑफसेट ('.long in_pm32'' वास्तविक मोड कर्नेल बाइनरी की शुरुआत से 'in_mp32' फ़ंक्शन का पता है) के साथ बुलाया जाता है - और मुझे समझ में नहीं आता कि अंत में 'in_pm32' फ़ंक्शन क्यों निष्पादित किया जाता है। दूर की कूद 0x7C00 + bootloader_size बाइट्स पर मेल नहीं खाई जानी चाहिए। – Alexander

उत्तर

5

ऐसा लगता है कि आपके सवाल का वास्तव में कैसे निम्न पंक्ति में संग्रहीत ऑफसेट संभवतः काम कर सकते हैं, क्योंकि यह खंड, जरूरी नहीं कि स्मृति की शुरुआत की शुरुआत के सापेक्ष है के बारे में है:

2: .long in_pm32   # offset 

यह है सच है कि in_pm32linker script ऑफ़सेट के ऑफसेट के सापेक्ष है। विशेष रूप से लिंकर स्क्रिप्ट है:

. = 0; 
.bstext  : { *(.bstext) } 
.bsdata  : { *(.bsdata) } 

. = 495; 
.header  : { *(.header) } 
.entrytext : { *(.entrytext) } 
.inittext : { *(.inittext) } 
.initdata : { *(.initdata) } 
__end_init = .; 

.text  : { *(.text) } 
.text32  : { *(.text32) } 

वर्चुअल मेमोरी पता, शून्य (और बाद में 495) के लिए निर्धारित है तो एक सोच सकता है कि .text32 खंड में कुछ भी कम स्मृति में तय करना होगा।

xorl %ebx, %ebx 
    movw %cs, %bx 
    shll $4, %ebx 
    addl %ebx, 2f 

[snip] 

    # Transition to 32-bit mode 
    .byte 0x66, 0xea  # ljmpl opcode 
2: .long in_pm32   # offset 
    .word __BOOT_CS  # segment 

अंत कि एक 32-बिट के लिए सीएस चयनकर्ता स्थापित करने के लिए प्रयोग किया जाता है पर एक मैन्युअल रूप से एन्कोड सुदूर जेएमपी नहीं है: यह एक सही अवलोकन यह protected_mode_jump में इन निर्देशों के लिए नहीं किया गया था होगा 32-बिट संरक्षित मोड में संक्रमण को अंतिम रूप देने के लिए कोड डिस्क्रिप्टर। लेकिन निरीक्षण करने के लिए मुख्य बात इन पंक्तियों में विशेष रूप से कर रहे हैं:

xorl %ebx, %ebx 
    movw %cs, %bx 
    shll $4, %ebx 
    addl %ebx, 2f 

यह सीएसमें मूल्य लेता है और बदलाव यह 4 बिट्स (16 से गुणा) द्वारा छोड़ा और उसके बाद लेबल 2f पर संग्रहीत मूल्य में शामिल करता है । इस तरह आप real mode segment:offset जोड़ी लेते हैं और इसे रैखिक पते में परिवर्तित करते हैं (जो इस मामले में भौतिक पते के समान है)। लेबल 2f वास्तव में इस पंक्ति में in_pm32 ऑफसेट:

2: .long in_pm32   # offset 

उन अनुदेश पूरा कर रहे हैं, सुदूर जेएमपी में लंबे शब्द मूल्य in_pm32 समायोजित किया जाएगा (रन टाइम पर) के रैखिक पता जोड़ कर वर्तमान वास्तविक मोड कोड सेगमेंट मान in_pm32 पर। यह .long (DWORD) मान प्रतिस्थापित किया जाएगा (सीएस < < 4) + in_pm32।

यह कोड किसी भी वास्तविक मोड सेगमेंट में स्थानांतरित करने के लिए डिज़ाइन किया गया था। अंतिम रैखिक पता एफएआर जेएमपी से पहले रन टाइम पर गणना की जाती है। यह प्रभावी रूप से स्व-संशोधित कोड है।

संबंधित मुद्दे