2015-12-11 8 views
7

में लोड हो रहा है क्षेत्रों मैं एक बूटलोडर this का उपयोग कर विकसित करने की कोशिश, लेकिन जब यह चलाया जाता है यह पता चलता है, जबकि:डिस्क पढ़ें त्रुटि स्मृति

disk read error! 

अगर मैं इसे अनदेखा, एक बाद के हिस्से में, यह मुझे गलत स्मृति से पता चलता मानचित्रण। मैंने कुछ अन्य स्रोतों का भी पालन किया लेकिन व्यर्थ में। ऐसा लगता है जैसे मैं सिर्फ वही कर रहा हूं जो वे कर रहे हैं। अगर मैं थोड़ा अलग करता हूं तो हर बार एक नई तरह की त्रुटि उत्पन्न होती है।

क्या मुझे पहले से निर्मित बूटलोडर का उपयोग करना चाहिए या क्या करना चाहिए?

डिस्क लोड त्रुटि के कोड का पालन है:

[org 0x7c00] 

    KERNEL_OFFSET equ 0x1000  
    mov [BOOT_DRIVE], dl   
    mov bp, 0x9000   
    mov sp, bp 
    mov bx, MSG_REAL_MODE  
    call print_string   
    call load_kernel    
    jmp $ 

print_string: 
    pusha 
    mov ah, 0x0e 

loop: 
    mov al,[bx] 
    cmp al, 0 
    je return 
    int 0x10 
    inc bx 
    jmp loop 

return: 
    popa 
    ret 

disk_load: 
    push dx            
    mov ah, 0x02         
    mov al, dh           
    mov ch, 0x00          
    mov dh, 0x00          
    mov cl, 0x02          
    int 0x13           
    jc disk_error         
    pop dx            
    cmp dh, al           
    jne disk_error         
    ret 

disk_error : 
    mov bx, DISK_ERROR_MSG 
    call print_string 
    jmp $ 

DISK_ERROR_MSG db "Disk read error!", 0 

[bits 16] 

load_kernel: 
    mov bx, KERNEL_OFFSET  
    mov dh, 15   
    mov dl, [BOOT_DRIVE]      
    call disk_load             
    ret 

; Global variables 
BOOT_DRIVE  db 0 
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 

; Bootsector padding 
times 510-($-$$) db 0 
dw 0xaa55 

मैं इस आदेश का उपयोग इकट्ठा और मेरे बूटलोडर को चलाने के लिए:

nasm boot.asm -f bin -o boot.bin && qemu-system-i386 boot.bin 

मैं इस बिंदु पर अटक। मेरा बूटलोडर disk read error प्रदर्शित करता है। अगर मैं समय पर इस बिंदु पर अनदेखा करता हूं, तो यह मेरे कर्नेल को निष्पादित करते समय समस्याएं उत्पन्न करता है। ऐसा लगता है कि यह गलत स्मृति मैपिंग का उपयोग करता है।

+0

Plz इस कोड की जाँच करें और मुझे बाहर करने में मदद! –

+0

आपके पास एक समस्या यह है कि जब आपका प्रोग्राम शुरू होता है तो आप _DS_ (डेटा सेगमेंट) को सही तरीके से सेट नहीं करते हैं। आप एसपी भी सेट करते हैं, लेकिन आप वास्तव में वैध _SS_ (स्टैक सेगमेंट) सेट नहीं करते हैं। इससे समस्याएं भी हो सकती हैं। Disk_load में आप _ES_ (विस्तारित सेगमेंट) सेट नहीं करते हैं, जिसे ठीक से सेट करने की आवश्यकता है ताकि स्मृति स्थान जहां डेटा पढ़ा जाता है पूरी तरह से निर्दिष्ट किया गया है (ES: BX पता बफर है)। यदि आप 15 सेल्सियस पढ़ने वाली 720k फ्लॉपी डिस्क बना रहे हैं तो संभवतः काम नहीं करेगा क्योंकि ट्रैक (सिलेंडर) पर अधिकतम सेक्टर 9 है। इससे पढ़ने की समस्याएं पैदा हो सकती हैं। –

+0

शीर्ष पर '[बिट्स 16]' डालने का भी एक अच्छा विचार है कि NASM बूटलोडर –

उत्तर

5

"वह एक सूची बना रहा है, वह इसे दो बार जांचता है ..."

  • आपका बूटलोडर, वास्तविक पता मोड में शुरू होता है, तो यह सबसे अच्छा है 16- का उपयोग करने में अपने कोडांतरक मजबूर करने के लिए बिट कोड आप इसे अपने प्रोग्राम के शीर्ष पर [bits 16] लिखकर NASM में प्राप्त करते हैं।

  • जब आपका बूटलोडर शुरू होता है, तो BIOS इसे रैखिक पता 00007C00h पर रखेगा। यह सेगमेंट और ऑफसेट के संयोजन के संबंध में कई तरीकों से ऐसा कर सकता है।
    जब आपने स्पष्ट रूप से [org 0x7C00] लिखा था (इस तरह) ने इस संयोजन को सेगमेंट भाग शून्य के बराबर होने की उम्मीद की थी। लेकिन बीआईओएस के लिए इसका कोई दायित्व नहीं है! और इसलिए मैन्युअल रूप से सेगमेंट रजिस्ट्रार (डीएस, ईएस, और एसएस) सेट करने के लिए आप पर निर्भर है।

  • BIOS टेलीलेट प्रकार जो आप अपने print_string नियमित रूप से उपयोग करते हैं, पैरामीटर के रूप में बीएल और बीएच का उपयोग करता है। तो आपको अपने टेक्स्ट को संबोधित करने के लिए कभी भी बीएक्स रजिस्टर का उपयोग नहीं करना चाहिए। निश्चित रूप से, कुछ BIOS इन बीएल और बीएच पैरामीटर का उपयोग नहीं करते हैं (और भी अधिक) लेकिन सबसे बड़े दर्शकों के लिए कार्यक्रम विकसित करने का प्रयास करें।

  • जब आपने 0x9000 के साथ एसपी रजिस्टर शुरू किया था तो आपने प्रभावी रूप से एक स्टैक स्थापित किया जो आसानी से बिना देखे, प्रोग्राम के नीचे प्रोग्राम को ओवरराइट कर सकता था! एसएस और एसपी के संयोजन का चयन करना सबसे अच्छा होगा जो आपकी आवश्यकताओं को पूरा करता है और कुछ भी नहीं। एक 4608 बाइट स्टैक जो 7 सी 00h पर बूटसेक्टर के ऊपर रहता है और 9000h पर समाप्त होता है, इसकी आवश्यकता होगी: एसएस = 07E0h एसपी = 1200 एच। 8086 हार्डवेयर पर किसी भी समस्या से बचने के लिए एसएस: एसपी बदलते समय इंटरप्ट को अक्षम करना सबसे अच्छा है।

  • आपने pusha और popa निर्देशों का उपयोग किया था। ये 8086 हार्डवेयर पर मान्य निर्देश नहीं हैं। मजबूत सॉफ़्टवेयर लिखते समय, हमें परीक्षण करना चाहिए कि क्या हार्डवेयर कार्य पर है या नहीं। लेकिन यहां सबसे आसान समाधान केवल एकल रजिस्ट्रार को पुश/पॉप करना है।

  • आपने डिस्क से पढ़े गए BIOS फ़ंक्शन से रिटर्न वैल्यू का अर्थ दिया है, लेकिन जब आप गलत संख्या में सेक्टरों को स्थानांतरित कर देते हैं तो आप निरस्त हो जाते हैं। यह एक गलत दृष्टिकोण है।जब BIOS आपको अपूर्ण हस्तांतरण के बारे में बताता है (यह तब हो सकता है यदि आपका BIOS मल्टीट्रैक सक्षम नहीं है) तो आपको शेष क्षेत्रों की कॉल को दोहराना होगा। स्पष्ट रूप से कुछ पैरामीटर को समायोजित करना होगा: अगला सिर, शायद अगले सिलेंडर, और हमेशा सेक्टर = 1। (एक सही समाधान में BIOS से डिस्क ज्यामिति को पुनर्प्राप्त करना या डिस्क पर मौजूद बीपीबी से इसे पढ़ना शामिल होगा)। मैंने मूल 1.44 एमबी फ्लॉपी ऑपरेशन संभाला।

  • जब डिस्क से पढ़ने के लिए पहली बार सफल नहीं होता तो आप इसे कई बार पुन: प्रयास करना चाहिए। इस तरह के पहली बार विफल रहता है पूरी तरह से सामान्य हैं। पांच retries एक अच्छा मूल्य है। प्रयासों के बीच में आप BIOS फ़ंक्शन को कॉल करते हैं जो डिस्कड्राइव को रीसेट करता है।

  • यकीन QEMU वास्तव में उन अतिरिक्त 15 सेक्टरों आप इस फ़ाइल पैड चाहिए पढ़ सकते हैं तो यह 16 क्षेत्रों के लायक की कुल लंबाई है बनाने के लिए। text आपने इसे भी जोड़ा है!

"यह सब एक साथ लाना"

[bits 16] 
[org 0x7C00] 

KERNEL_OFFSET equ 0x1000 

xor ax, ax 
mov ds, ax 
mov es, ax  
mov [BOOT_DRIVE], dl 
mov ax, 0x07E0 
cli 
mov ss, ax 
mov sp, 0x1200 
sti 
mov si, MSG_REAL_MODE  
call print_string   
call load_kernel    
jmp $ 

print_string: 
    push ax 
    push bx 
    push si 
    mov bx, 0x0007 ;BL=WhiteOnBlack BH=Display page 0 
    mov ah, 0x0E ;Teletype function 
loop: 
    mov al, [si] 
    cmp al, 0 
    je return 
    int 0x10 
    inc si 
    jmp loop 
return: 
    pop si 
    pop bx 
    pop ax 
    ret 

disk_load: 
    mov [SECTORS], dh 
    mov ch, 0x00  ;C=0 
    mov dh, 0x00  ;H=0 
    mov cl, 0x02  ;S=2 
next_group: 
    mov di, 5   ;Max 5 tries 
again: 
    mov ah, 0x02  ;Read sectors 
    mov al, [SECTORS] 
    int 0x13 
    jc maybe_retry 
    sub [SECTORS], al ;Remaining sectors 
    jz ready 
    mov cl, 0x01  ;Always sector 1 
    xor dh, 1   ;Next head on diskette! 
    jnz next_group 
    inc ch   ;Next cylinder 
    jmp next_group 
maybe_retry: 
    mov ah, 0x00  ;Reset diskdrive 
    int 0x13 
    dec di 
    jnz again 
    jmp disk_error 
ready: 
    ret 

disk_error: 
    mov si, DISK_ERROR_MSG 
    call print_string 
    jmp $ 

DISK_ERROR_MSG db "Disk read error!", 0 

load_kernel: 
    mov bx, KERNEL_OFFSET  
    mov dh, 15   
    mov dl, [BOOT_DRIVE]      
    call disk_load             
    ret 

; Global variables 
BOOT_DRIVE  db 0 
SECTORS  db 0 
MSG_REAL_MODE db "Started in 16-bit Real Mode", 0 

; Bootsector padding 
times 510-($-$$) db 0 
dw 0xAA55 

; 15 sector padding 
times 15*256 dw 0xDADA 
+0

_SS: SP_ को अपडेट करने के बारे में बस एक टिप्पणी। आप जो कहते हैं वह वास्तव में हार्डवेयर की विस्तृत विविधता के अनुकूल है, लेकिन सीएलआई/एसटीआई जोड़ी का मुख्य कारण 1 9 80 के दशक से कुछ छोटी गाड़ी 8088 सीपीयू पर एक बग को बाधित करना है। जब आप एक एमओवी निर्देश के साथ _SS_ रजिस्टर को अपडेट करते हैं तो यह लगता है कि _NEXT_ निर्देश के बाद तक इंटरप्ट अक्षम करना है। आमतौर पर यह _SP_ के लिए अद्यतन है। दुर्भाग्य से कुछ बग्गी 8088 सीपीयू पर इंटरप्ट्स अपेक्षित रूप से बंद नहीं हुए थे, इसलिए बग से बचने के लिए स्पष्ट रूप से सीएलआई/एसटीआई का उपयोग किया जाएगा। –

+1

मैंने आपके उत्तर को ऊपर उठाया। एक और थोड़ा अवलोकन करेंगे। आप _AL_ पर पढ़ने वाले क्षेत्रों की संख्या होने पर भरोसा करते हैं।कुछ प्राचीन BIOSes हैं जो केवल _AL_ में एक मान वापस करते हैं यदि CF = 1 (हां, थोड़ा पागल लगता है लेकिन सत्य है)। अधिकांश बूटलोडर्स (वास्तविक हार्डवेयर की विस्तृत सरणी को लक्षित करना) मानते हैं कि मान _AL_ पर भरोसा किया जा सकता है। इसलिए आमतौर पर अधिकांश बूटलोडर्स एक समय में एक सेक्टर पढ़ते हैं, या डिस्क ज्यामिति (या तो बीपीबी या बीडीए से) प्राप्त करते हैं और केवल बहु क्षेत्र पढ़ते हैं जो कभी भी ट्रैक (सिलेंडर) नहीं फैलता है। लेकिन आपका कोड अधिकांश हार्डवेयर (और उन सभी अनुकरणकर्ताओं के साथ काम करेगा जो मुझे पता है)। –

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