PC stürzt nach Übergang in den Protected Mode ab
-
Hi!
Ich versuch mir grad nen Kernel in C zu schreiben, da das aber nicht von Anfang an möglich ist, muss halt der Anfang in Assembler sein. Leider hab ich davon nur wenig Ahnung und weiß einfach nicht, warum der PC rummuckt, wenn ich in den Protected Mode gehen will...
Er startet einfach immer wieder neu und nichts passiert, keine Fehlermeldung, keine Ausgabe.
[BITS 16] ; Global declaration of star global start ; Jump over the GDT jmp start ; Null-Desc NULL_Desc: dd 0 dd 0 ; Code-Desc CODE_Desc: dw 0xFFFF ;Segmentgröße Byte 0/1 dw 0 ;Segmentbasisadresse Byte 0/1 db 0 ;Segmentbasisadresse Byte 2 db 10011010b ;Zugriffsberechtigungen db 11001111b ;Zusatz + Segmentgröße Bits 16 - 19 db 0 ;Segmentbasisadresse Byte 3 ; Data-Desc DATA_Desc: dw 0xFFFF dw 0 db 0 db 0x92 db 0xCF db 0 ; GDT gdt: Limit dw 0 Base dd 0 ; Start start: ; Turn off any interrupts cli ; Set EAX and DS to the code segment mov eax, cs mov ds, ax ; Work with EAX to reach the linear address of the segment shl eax, 4 mov [CODE_Desc+2], ax ;Lineare Adresse des Codesegmentes als mov [DATA_Desc+2], ax ;Startadresse des Code- und Datendeskriptors shr eax, 16 ;eintragen mov [CODE_Desc+4], al mov [DATA_Desc+4], al ; Calculate the starting-address of the GDT mov eax, cs shl eax, 4 add eax, NULL_Desc mov [Base], eax mov [Limit], WORD gdt - NULL_Desc -1
Bis hier hin geht das ganze noch...
; Change into the Protected Mode mov eax, cr0 or eax, 1 mov cr0, eax db 0xea dw PMODE dw 0x8 [BITS 32] PMODE: PMODE: mov WORD [CODE_Desc+2], 0 ;Code Segmentstartaddresse auf 0 setzen mov WORD [DATA_Desc+2], 0 ;Daten Segmentstartadresse auf 0 setzen mov BYTE [CODE_Desc+4], 0 ;Code Segmentstartaddresse auf 0 setzen mov BYTE [DATA_Desc+4], 0 ;Daten Segmentstartadresse auf 0 setzen mov eax, 2 shl eax, 3 mov ds, ax ;Daten- Stack- und Extrasegment mit mov ss, ax ;Datensegmentdeskriptor laden mov es, ax mov eax, 0 ;FS und GS mit Null-Deskriptor laden mov fs, ax mov gs, ax mov esp, 0x1FFFFF ;Stack auf unterhalb der 2 MB Grenze setzen ; Print Boot-Messages mov si, msg call putstr mov si, msg_boot call putstr call getkey jmp reboot stop: jmp stop msg db "Welcome to SampleOS",13,10,0 msg_boot db "Press any key...",10,0 ; Print a string putstr: lodsb ; Byte laden or al,al jz short putstrd ; 0-Byte? -> Ende! mov ah,0x0E ; Funktion 0x0E mov bx,0x0007 ; Atrribut-Byte int 0x10 ; schreiben jmp putstr ; naechstes Byte putstrd: retn ; Waiting for key pressing getkey: mov ah, 0 ; Funktion 0 int 016h ; Ausfuehren ret ; Reboot reboot: db 0EAh dw 0000h dw 0FFFFh times 512-($-$$) db 0
PS: Zum Booten benutzte ich nur den VMware Player, dürfte aber keinen Unterschied zum richtigen Boot darstellen.
Und bitte fangt jetzt nicht damit an: wenn du noch nicht mal Assembler kannst, dann brauchst du auch nicht versuchen ein Kernel zu proggen. Ich weiß sehrwohl wie schwierig das ist, da man die komplette Laufzeitbibliothek neuschreiben muss. Und es soll ja auch nur als Hobby gedacht seint
.
Und schon man Thx im voraus.
-
Aehm... "wenn du noch nicht mal Assembler kannst, dann brauchst du auch nicht versuchen ein Kernel zu proggen." SCNR
Ne, grundsaetzlich nicht schlecht (und sogar noch was gelernt: mir war vorher nicht praesent, dass man die 16Bit Segmentregister offenbar auch direkt in 32Bit-Register schieben kann .Keine Ahnung von VMWare, aber erstmal ist dein Code kein gueltiger Bootsektor (falls es das denn darstellen sollte).
Dann funktionieren die meisten BIOS-Interrupts (inklusive der, die du in deinem Code verwendest ;)) im PM nicht.
Und zuletzt denke ich, dass du deinen Code sicher vereinfachen koenntest, wenn du deine Deskriptoren nicht erst zur Laufzeit berechnest, sondern die Werte schon vorher festlegst. Sollte bei einem selbst geschriebenen Kernel schliesslich drin sein.
-
Wie gesagt, ich hab noch nicht viel Ahnung von Assembler.
Der Code ist aus nem Tutorial gezogen. Könntest du mir vlt. ein Bespiel zeigen, mit dem man mindestens in den Protected Mode kommt und den Kernel in C proggen kann? Das Linken funzt ja schon: Bootloader+Kompilierter Kernel in ASM+Kompilierter Kernel in C. Nur stürzt er halt immer ab.
-
Ne, habe kein Beispiel zur Hand (FAQ darfst du selbst durchstoebern), aber falls du dich nicht naeher mit Asm beschaeftigen willst, nimm doch zB. Grub. Der kann dir AFAIK die meiste Arbeit schon abnehmen, so dass du gleich in einer Hochsprache loslegen kannst.
-
Klingt gut, das mit dem grub und gleich hochsprache. Hast du - Nubou-T - dafür ein Dewdurial? Danke
-
Hm, es macht mit Sicherheit einen Unterschied ob man unter
VMWare versucht in den Protected Mode zu Wechseln, oder
ob man von einem echten DOS gebootet hat.
-
GAST158 schrieb:
Hm, es macht mit Sicherheit einen Unterschied ob man unter
VMWare versucht in den Protected Mode zu Wechseln, oder
ob man von einem echten DOS gebootet hat.Und der wäre? Windows und Linux kann man doch auch booten und da befindet sich der virtuelle Prozessor auch erst im Real-Mode.
-
Dr. C++ schrieb:
GAST158 schrieb:
Hm, es macht mit Sicherheit einen Unterschied ob man unter
VMWare versucht in den Protected Mode zu Wechseln, oder
ob man von einem echten DOS gebootet hat.Und der wäre? Windows und Linux kann man doch auch booten und da befindet sich der virtuelle Prozessor auch erst im Real-Mode.
Der Unterschied ist meiner Meinung nach der, daß unter VMWare nicht alle Befehle des Prozessors erlaubt sind bzw. evtl. die nicht erlaubten nur emuliert werden. LMSW (Load Machine Status Word) ist möglicherweise z.B. so ein Kandidat. Was spricht dagegen mal ein echtes DOS zu booten und ES auszuprobieren ? Es gibt natürlich noch viele andere Gründe, die für den
Absturz in Frage kommen. Ich sehe z.B. nirgends die Interrupt Descriptorentabelle. Du sperrst zwar die Interrupts, aber ich weiß nicht ob das reicht. Ich glaube ich habe hier noch irgendwo ein uraltes Programm rumfliegen, daß in den Protected Mode wechselt und NICHT abstürzt
Da müßte ich mal ein paar alte Disketten durchforsten ...
-
So, Meister, ich hab das Beispiel gefunden (auf einer Diskette die satte 16 Jahre alt ist). Mit der Routine "START" kommst du in den Protected Mode
und auch wieder zurück:.286p
LOC_DES_TAB1 SEGMENT
DB 0, 0, 0, 0, 0, 0, 0, 0 ; NULLSELEKTOR
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
LOC_DES_TAB1 ENDSGLOB_DES_TAB SEGMENT
DB 0, 0, 0, 0, 0, 0, 0, 0 ; NULLSELEKTOR
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 255,255,0, 0, 10,147, 0, 0
DB 255,255,0,128, 11,147, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
GLOB_DES_TAB ENDSINTR_DES_TAB SEGMENT
DB 0, 0, 0, 0, 0, 0, 0, 0 ; NULLSELEKTOR
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
DB 0, 0, 0, 0, 0, 0, 0, 0
INTR_DES_TAB ENDSFEHLER SEGMENT
I0 DB 'Divisionsfehler'
I2 DB 'NMI$'
FEHLER ENDSSTAPEL SEGMENT STACK
DW 256 DUP (0)
STAPEL ENDSPROCODE SEGMENT
ASSUME CS: PROCODETABLE DW ?, ?, ?
DOSRETURN: MOV AX,4C00H
INT 21HSTART: CLI
MOV AH,159+64 ; A20 FREISCHALTEN
CALL WAIT8042
JNZ WEITER
MOV AL,0D1H
OUT [64H],AL
CALL WAIT8042
JNZ WEITER
MOV AL,AH
OUT [60H],AL
CALL WAIT8042
WEITER: MOV AL,08FH ; CMOS-BYTE IN UHR SETZEN
OUT [70H],AL
AAD ; 14 TAKTE WARTEN
MOV AL,9
OUT [71H],ALPUSHF
PUSH CS
PUSH OFFSET DOSRETURN ; FšR RETURN NACH EINEM INT 15H
SUB SP,20
MOV AX,0 ; REAL-MODE-STACKZEIGER MERKEN
MOV DS,AX
MOV DS:[0469H],SS
MOV DS:[0467H],SPPUSHF
MOV DI,SP
AND SS:[DI],1111110011111111b ; CLI UND TRAPFLAG LSCHEN
POPFMOV AX,GLOB_DES_TAB
MOV ES,AX
MOV SI,0
MOV BP,SI ; OFFSET IN GDTSEG = 0
LEA DI,[SI+8]
MOV DX,6*8
MOV BL,0
CALL DESKRIP
LGDT QWORD PTR ES:[SI+08H]MOV AX,SS
MOV BP,0
LEA DI,[SI+28H]
MOV DX,0FFFFH
MOV BL,93H
CALL DESKRIPMOV WORD PTR CS:TABLE,2048 ; 6 BYTES FUER DIE
MOV AX,INTR_DES_TAB ; INITIALISIERUNG DES IDTR
MOV BX,10 ; VORBEREITEN
MUL BX
MOV WORD PTR CS:TABLE+2,AX
MOV BYTE PTR CS:TABLE+3,DL
LIDT QWORD PTR CS:TABLEMOV AX,PROCODE ; PM-CODE-SEGMENT
MOV BP,0
MOV DX,0FFFFH
MOV BL,9BH
LEA DI,[SI+20H]
CALL DESKRIPSMSW AX
OR AL,1
LMSW AX
DB 0EAH
DW OFFSET PM_START
DW 0020H ; JMP 0020:PM_STARTPM_START: MOV AX,28H
MOV SS,AX
MOV AX,18H
MOV ES,AX
MOV AX,10H
MOV DS,AXMOV ax,65+16*256;
MOV cx,1000
XOR di,di
REP stoswMOV WORD PTR CS:TABLE,0 ;
LIDT QWORD PTR CS:TABLE ; IDT-LŽNGE AUF 0 UND INT 8
INT 8DESKRIP PROC NEAR
MOV WORD PTR ES:[DI+6],0
MOV ES:[DI+5],BL
MOV ES:[DI],DX
MOV BX,10H
MUL BX
ADD AX,BP
ADC DX,0
MOV ES:[DI+2],AX
MOV ES:[DI+4],DL
RET
DESKRIP ENDPWAIT8042 PROC NEAR
XOR CX,CX
INPUT: IN AL,[64H]
AND AL,02
JZ OK8042
LOOP INPUT
INC CX
OK8042: RET
WAIT8042 ENDPPROCODE ENDS
END START