2013-02-02 75 views
5

मैं नस्ल में एक साधारण x86 लिनक्स बूटलोडर बनाने की कोशिश कर रहा हूं।लिनक्स x86 बूटलोडर

लिनक्स bzImage पहले से शुरू होने वाले डिस्क विभाजन sda1 पर संग्रहीत है।

मैंने 0x7E00 से शुरू होने वाली स्मृति में bzImage (15 सेक्टर) से वास्तविक मोड कोड पढ़ा है। हालांकि जब मैं कोड में कूदता हूं तो यह बस लटकता है, कुछ भी नहीं होता है।

मैंने एसडीए पर मास्टर बूट रिकॉर्ड के लिए कोड बनाया है। मैं शायद सबसे अच्छा हूं अगर मैं पूरी चीज संलग्न करता हूं। मैं जानना चाहता हूं कि यह दूर कूदने के निर्देश के बाद क्यों लटकता है।

[BITS 16] 

%define BOOTSEG 0x7C0 
%define BOOTADDR (BOOTSEG * 0x10) 

%define HDRSEG (BOOTSEG + 0x20) 
%define HDRADDR (HDRSEG * 0x10) 

%define KERNSEG (HDRSEG + 0x20) 

[ORG BOOTADDR] 
entry_section: 
    cli 
    jmp  start 
start: 
    ; Clear segments 
    xor  ax, ax 
    mov  ds, ax 
    mov  es, ax 
    mov  gs, ax 
    mov  fs, ax 
    mov  ss, ax 
    mov  sp, BOOTADDR ; Lots of room for it to grow down from here 

    ; Read all 15 sectors of realmode code in the kernel 
    mov  ah, 0x42 
    mov  si, dap 
    mov  dl, 0x80 
    int  0x13 
    jc bad 

    ; Test magic number of kernel header 
    mov  eax, dword [HDRADDR + 0x202] 
    cmp  eax, 'HdrS' 
    jne  bad 

    ; Test jump instruction is there 
    mov  al, byte [KERNSEG * 16] 
    cmp  al, 0xEB 
    jne  bad 

    xor  ax, ax  ; Kernel entry code will set ds = ax 
    xor  bx, bx  ; Will also set ss = dx 
    jmp  dword KERNSEG:0 

; Simple function to report an error and halt 
bad: 
    mov  al, "B" 
    call putc 
    jmp  halt 

; Param: char in al 
putc: 
    mov  ah, 0X0E  
    mov  bh, 0x0F 
    xor  bl, bl 
    int  0x10 
    ret 

halt: 
    hlt 
    jmp  halt 

; Begin data section 
dap:    ; Disk address packet 
    db 0x10   ; Size of dap in bytes 
    db 0    ; Unused 
    dw 15    ; Number of sectors to read 
    dw 0    ; Offset where to place data 
    dw HDRSEG   ; Segment where to place data 
    dd 0x3F   ; Low order of start addres in sectors 
    dd 0    ; High order of start address in sectors 

; End data section 

times 446-($-$$) db 0 ; Padding to make the MBR 512 bytes 

; Hardcoded partition entries 
part_boot: 
    dw 0x0180, 0x0001, 0xFE83, 0x3c3f, 0x003F, 0x0000, 0xF3BE, 0x000E 
part_sda2: 
    dw 0x0000, 0x3D01, 0xFE83, 0xFFFF, 0xF3FD, 0x000E, 0x5AF0, 0x01B3 
part_sda3: 
    dw 0xFE00, 0xFFFF, 0xFE83, 0xFFFF, 0x4EED, 0x01C2, 0xb113, 0x001D 
part_sda4: 
    dw 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 

dw 0xAA55 ; Magic number at relative address 510 
mbrend:  ; Relative address 512 
+0

क्या आपने GRUB और LILO के कार्यान्वयन का अध्ययन किया था? –

+0

मैंने लिलो के कार्यान्वयन को देखा है और ऐसा लगता है जैसे वे लिनक्स कोड में उसी तरह कूदते हैं। यद्यपि उनके कोड को पढ़ने के लिए मुश्किल है। – Druesukker

+0

क्या आपने कोड के माध्यम से कदम उठाने और लटकने का कारण देखने के लिए डीबगर का उपयोग किया था? – Jester

उत्तर

1

मान लिया जाये कि अपने कोड एक बूट लोडर है (और इसलिए एक एमबीआर नहीं है):

  • कभी IRQs को निष्क्रिय जब तक आप के लिए है। BIOS को उन्हें सही तरीके से कार्य करने की आवश्यकता है, और उन्हें कुछ BIOS फ़ंक्शंस के अंदर भी सक्षम कर देगा (उदा। डिस्क कार्यों के अंदर "क्षेत्र स्थानांतरित" आईआरक्यू के लिए प्रतीक्षा करना)। चूंकि आपका कोड केवल वास्तविक मोड कोड पर नियंत्रण लोड कर रहा है और गुजर रहा है (उदा। और संरक्षित मोड में कोई स्विच नहीं है या कुछ भी शामिल है) आपके पास अपने पूरे बूट लोडर में कहीं भी आईआरक्यू को अक्षम करने का कोई कारण नहीं है।
  • असली मोड एड्रेसिंग के लिए, यह 0x0000: 0x7C00 का उपयोग 0x07C0: 0x0000 के बजाय आमतौर पर क्लीनर/आसान है। आप दोनों को मिश्रण करने का प्रयास कर रहे हैं (उदाहरण के लिए पूर्व के लिए सेगमेंट रजिस्ट्रार सेट करें लेकिन बाद में बोटेसेग और एचडीआरएसईजी परिभाषित करें)।
  • विभाजन तालिका में "विस्तारित विभाजन" है और "प्राथमिक विभाजन" नहीं है और इसलिए आपकी विभाजन तालिका गलत है (और शायद खाली/खाली होनी चाहिए)।
  • बूट लोडर को किसी भी विशिष्ट/हार्ड-कोडित "प्रारंभिक एलबीए" (विभाजन के लिए "प्रारंभिक एलबीए" नहीं मानना ​​चाहिए कि ओएस इंस्टॉल होने पर अंतिम उपयोगकर्ता को अपनी डिस्क को विभाजित करने की तरह कैसा महसूस होता है)। आपको एमबीआर की प्राथमिक विभाजन तालिका से विभाजन के "प्रारंभिक एलबीए" को निर्धारित करने की आवश्यकता है, जिसे आम तौर पर उम्मीद है कि एमबीआर ने डीएस: एसआई को अपने विभाजन की विभाजन तालिका प्रविष्टि को इंगित किया है।
  • आपको यह नहीं मानना ​​चाहिए कि आप "BIOS डिवाइस 0x80" से बूट कर रहे हैं। एमबीआर को डीएल सेट को सही डिवाइस नंबर पर छोड़ देना चाहिए, और ऐसा कोई कारण नहीं होना चाहिए कि आपका कोड क्यों काम नहीं करना चाहिए (उदा।) ओएस दूसरी हार्ड ड्राइव या कुछ और पर स्थापित है।
  • आपका हार्ड-कोडित "प्रारंभ करने वाला एलबीए पढ़ने" (डीएपी में) गलत है। ऐतिहासिक कारणों से प्रति ट्रैक 63 क्षेत्र हैं और आपका विभाजन 64 वें क्षेत्र में शुरू होता है। इसका मतलब है कि एलबीए सेक्टर 0x3F विभाजन में पहला क्षेत्र है (जो आपका बूट लोडर है) और कर्नेल का पहला क्षेत्र नहीं है।मुझे लगता है कि कर्नेल का पहला क्षेत्र एलबीए सेक्टर 0x40 (विभाजन का दूसरा क्षेत्र) हो सकता है।
  • "क्षेत्रों की संख्या" को या तो हार्ड-कोड नहीं किया जाना चाहिए। आप कर्नेल की शुरुआत लोड करना चाहते हैं और इसकी जांच करना चाहते हैं, और यह निर्धारित करना चाहते हैं कि उस से कहां से लोड करना है।
  • आमतौर पर 512 बाइट्स (वास्तव में 446 बाइट्स की तरह) एक सभ्य बूट लोडर के लिए बहुत कम है। बूट लोडर के पहले 512 बाइट्स को शेष बूट लोडर को लोड करना चाहिए (प्रत्येक अतिरिक्त बाइट को त्रुटि प्रबंधन में सुधार के लिए इस्तेमाल किया गया है - उदाहरण के लिए puts("Read error while trying to load boot loader") सिर्फ putc('B'))। बाकी सब कुछ (कर्नेल के टुकड़े लोड करना, वीडियो मोड सेट करना, "वास्तविक मोड कर्नेल हेडर" फ़ील्ड इत्यादि में सही मान निर्धारित करना) अतिरिक्त क्षेत्रों में होना चाहिए और पहले क्षेत्र में नहीं होना चाहिए।

ध्यान दें कि जिस तरह से कंप्यूटर बूटों को ध्यान से डिजाइन किया गया है, कोई भी एमबीआर किसी भी डिस्क के किसी भी विभाजन पर किसी भी ओएस को चेनलोड कर सकता है; और एमबीआर कुछ बड़ा (उदा। बूट प्रबंधक) का हिस्सा हो सकता है जो एकाधिक ओएस को स्थापित करने की अनुमति देता है (उदाहरण के लिए जहां उपयोगकर्ता एक सुंदर मेनू या कुछ चुन सकता है कि एमबीआर के कोड को कौन सा विभाजन चुनना चाहिए)। यह डिज़ाइन उपयोगकर्ता को एमबीआर (या बूट मैनेजर) को किसी भी समय किसी भी स्थापित ओएस को प्रभावित किए बिना किसी अन्य चीज़ के साथ बदलने की अनुमति देता है (या उनके सभी स्थापित ओएस को फिक्सिंग की आवश्यकता होती है)। एक साधारण उदाहरण के लिए, उपयोगकर्ता को 12 अलग-अलग विभाजन होने में सक्षम होना चाहिए जिसमें सभी में आपका बूट लोडर और लिनक्स का एक अलग/स्वतंत्र संस्करण हो, और उसके बाद कोई भी बूट मैनेजर स्थापित करें (जैसे GRUB, Plop, GAG, MasterBooter, आदि) कि वे किसी भी समय चाहते हैं।

क्यों आपका कोड लटकता है, यह बहुत महत्वपूर्ण नहीं है कि सभी कोड को फिर भी लिखा जाना चाहिए। यदि आप उत्सुक हैं, तो मैं दृढ़ता से इसे एक एमुलेटर के अंदर एक डीबगर (जैसे बोच) के साथ चलाने की अनुशंसा करता हूं ताकि आप यह जांच सकें कि क्या हुआ है (उदाहरण के लिए 0x00007E00 पर स्मृति को डंप करें, यह देखने के लिए कि इसमें क्या है, एकल चरण जेएमपी देखें कि क्या निष्पादित किया जा रहा है, आदि)।

1

टिप्पणी कोड से मेल नहीं खाता है!

xor bx, bx ; Will also set ss = dx

मैं गंभीरता से संदेह है कि अगर आपकी समस्या है ...

अस्वीकरण: मैं यह नहीं किया है! मैं "चिकन" हूं और फ्लॉपी से हमेशा अपना बूटिन किया है।

एमबीआर में जो देखने की "उम्मीद" है, वह खुद को रास्ते से बाहर ले जाने के लिए है, और फिर सक्रिय विभाजन पर पहले सेक्टर को 7C00h पर फिर से लोड करें, और फिर वहां कूदें। यह "असली बूटलोडर" बाकी लोड करता है। मैं bzImage के लेआउट से परिचित नहीं हूं - शायद यह 7E00h पर लोड हो जाएगा ...

मुझे लगता है कि मैं अपने सिर पर हूं। मैं मेरे कोट मिल जाएगा ...

+0

टिप्पणी से मेल खाने के अलावा, 'ax' और 'bx' कोर्नेलसे नहीं होना चाहिए, शून्य नहीं? –

+0

मुझे लगता है कि समस्या शुरुआत में सेगमेंट रजिस्टरों को साफ़ कर रही थी। एक और समस्या कूदने से पहले सेगमेंट रजिस्टरों को ठीक से सेट नहीं कर रही थी। उन्हें = केआरएनएचडीआर को सीएस को छोड़कर करना चाहिए जो = KERNSEG होना चाहिए। उत्तर के लिए धन्यवाद जो अब अपेक्षित है। – Druesukker