Protected Mode lässt sich nicht aktivieren
-
Hallo,
also ich habe ein real-mode OS gebastelt, was über ein Konsole verfügt und somit Eingaben vom Nutzer entgegen nehmen kann. Der Bootvorgang sieht eigentlich so aus, dass sich im ersten Sektor der Diskette der Bootloader befindet und dieser einfach die Sektoren 2-19 an die Adresse 0X1000:0x0000 im Arbeitsspeicher lädt und an diese Stelle springt und somit mein real-mode OS startet. Das klappt soweit wunderbar. Nun soll, wenn der Nutzer auf der Konsole PM eingibt, der Protected Mode gestartet werden. Allerdings stürzt das System ab und der PC startet sich neu (CPU error wahrscheinlich). Ich weiß leider nicht was ich falsch gemacht habe, da ich das pmode Tutorial befolgt habe, aber vielleicht habe ich ja was übersehen. Hier mal der Code; Code ist an der Stelle 0x1000x0x0000 im Speicher ; Hier befindet sich ganz viel Code von meinem real-mode OS ; Benutzer macht Eingabe 'PM': jmp kernel_pmode: ; Hier sind zum Teil noch weiter Funktionen des real-mode OS ; Hier gehts nun los kernel_pmode: jmp p_start gdt: gdt_null: dd 0x00 dd 0x00 gdt_code: dw 0xFFFF ; Größe von 65535 dw 0x00 db 0x1000 ;Programmcode befindet sich ja momentan an der Stelle 0x1000:0x0000 db 10011010b ;Segment ist im Speicher, hat die Privilegstufe 0, ist ausführbar und lesbar db 11001111b ;Einheit 4096 KB, 80386 Segment db 0x00 gdt_data: dw 0xFFFF ; Größe von 65535 dw 0x00 db 0x1000 ;Programmcode befindet sich ja momentan an der Stelle 0x1000:0x0000 db 10010010b ;Segment ist im Speicher, hat die Privilegstufe 0, lesbar und schreibbar db 11001111b ;Einheit ist 4096 KB, 80386 Segment db 0x00 gdt_end: GDT32: Limit dw gdt_end - gdt - 1 ; Limit (size) BaseAdr dd gdt p_start: lgdt [GDT32] cli mov eax, 000000011h mov cr0, eax ; "FAR-JMP" zu Selektor:Offset (entspricht jmp 8:pmode) db 0eah dw now_in_prot dw 0x08 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 32-Bit protected mode ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; now_in_prot: jmp $
-
gdt_code: dw 0xFFFF ; Größe von 65535 dw 0x00 db 0x1000 ;Programmcode befindet sich ja momentan an der Stelle 0x1000:0x0000
Die letzte Zeile laesst sich so assemblieren? Ueberraschend - muss entweder ein Fehler im Assembler sein, oder wird automatisch als binaer interpraetiert.
Wie auch immer: In beiden faellen kommt mit Sicherheit nicht das raus, was du dir dabei gedacht hast.
Ein byte (angezeigt durch db) hat einen Wertebereich von 0x00 bis 0xFF. 0x1000 passt nicht in ein Byte.
Die Basisadresse wuerde stimmen, wenn du 0x10 eintraegst. ... Das selbe bei gdt_data.GDT32: Limit dw gdt_end - gdt - 1 ; Limit (size) BaseAdr dd gdt
Die -1 gehoert da IMHO nicht hin. Weiters brauchst du dir auch gar nicht gross mit irgendwelchen Label-Frickeleien einen abzubrechen. Das Limit ist einfach die Anzahl deiner Deskriptoren (inkl. des 0.) * 8 - also in deinem Fall 3*8.
Bei der Basisadresse musst du bedenken, dass es sich hier um die 32Bit breite physikalische Adresse deiner GDT handelt. Wenn du in diesem Segment relativ zu Segment 1000h adressierst, spuckt der Assembler hier wahrscheinlich auch ein zu 1000h relatives Offset aus - das ist natuerlich nicht gleich der physikalischen Adresse! Wenn du also 0x10000 zu dem Offset addierst, sollte es stimmen. Was fuer speziellere Anweisungen zum Aendern von relativen Offsets dein Assembler bietet, bitte selbst in der Anleitung nachlesen.mov eax, 000000011h mov cr0, eax
Du solltest es nach Moeglichkeit vermeiden, CR0 so komplett um zu kraempeln.
Besser zuerst cr0 nach eax kopieren, eax mit 1 verodern und dann zurueck nach cr0 schieben.Das ist erstmal alles, was mir aufgefallen ist.
-
Hab nun alles nach deinen Kritikpunkten geändert (übrigens nutze ich NASM mal am Rande erwähnt). Klappt leider immer noch nicht. Könnte es vielleicht Probleme mit der ORG Anweisung geben? Ich meien mein Bootloader ist ja bei ORG 0x7C00 und läd von dort aus mit int 13h die daten nach 0x1000:0x0000. Sollte da vielleicht noch ein zusätzliche org Anweisung in den Kernel? Habe da mal eine drin gehabt (org 0x1000), aber da lief der Kernel dann gar nicht mehr und deswegen habe ich sie wieder weggelassen.
Ein kleiner Fortschriit sollte wohl die Tatsache sein, dass der Rechner nicht sofort rebootet, sondern jetzt ca 3-4 Sekunden scheinbar im protected mode ist (oder darin umschaltet), dann aber trotzdem neustartet.
-
org laesst dich einfach gesagt das aktuelle Offset festlegen.
Wenn du also an den Anfang deines Kernels org 1000h schreibst, bedeutet das praktisch, dass das erste Label das offset 1000h hat. Genaueres steht in der NASM-Anleitung.
Weiters solltest du, wenn du 32Bit-Code ausfuehren willst, dem Assembler auch mitteilen, dass er 32Bit-Code erzeugen soll (siehe wieder Anleitung).
Sonst kann ich keine Fehler entdecken. Jag das alles ggf. doch mal durch bochs oder irgendeinen aehnlichen Debugger.
-
Hi,
also bin die Sache nun mit Bochs durchgegangen und hier ist das Resultat00200832996i[CPU0 ] BxError: instruction with opcode=0xff 00200832996i[CPU0 ] mod was c0, nnn was 7, rm was 7 00200832996i[CPU0 ] WARNING: Encountered an unknown instruction (signalling illegal instruction) 00200832996i[CPU0 ] protected mode 00200832996i[CPU0 ] CS.d_b = 32 bit 00200832996i[CPU0 ] SS.d_b = 16 bit 00200832996i[CPU0 ] EFER = 0x00000000 00200832996i[CPU0 ] | RAX=0000000000000011 RBX=0000000000000001 00200832996i[CPU0 ] | RCX=0000000000000607 RDX=0000000000000e00 00200832996i[CPU0 ] | RSP=000000000000fffc RBP=0000000000000000 00200832996i[CPU0 ] | RSI=00000000ffff0849 RDI=0000000000080000 00200832996i[CPU0 ] | R8=0000000000000000 R9=0000000000000000 00200832996i[CPU0 ] | R10=0000000000000000 R11=0000000000000000 00200832996i[CPU0 ] | R12=0000000000000000 R13=0000000000000000 00200832996i[CPU0 ] | R14=0000000000000000 R15=0000000000000000 00200832996i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf zf af PF cf 00200832996i[CPU0 ] | SEG selector base limit G D 00200832996i[CPU0 ] | SEG sltr(index|ti|rpl) base limit G D 00200832996i[CPU0 ] | CS:0008( 0001| 0| 0) 10010aac 000fffff 1 1 00200832996i[CPU0 ] | DS:1000( 0005| 0| 0) 00010000 0000ffff 0 0 00200832996i[CPU0 ] | SS:9000( 0005| 0| 0) 00090000 0000ffff 0 0 00200832996i[CPU0 ] | ES:0000( 0005| 0| 0) 00000000 0000ffff 0 0 00200832996i[CPU0 ] | FS:0000( 0005| 0| 0) 00000000 0000ffff 0 0 00200832996i[CPU0 ] | GS:0000( 0005| 0| 0) 00000000 0000ffff 0 0 00200832996i[CPU0 ] | MSR_FS_BASE:0000000000000000 00200832996i[CPU0 ] | MSR_GS_BASE:0000000000000000 00200832996i[CPU0 ] | RIP=0000000000000af1 (0000000000000af1) 00200832996i[CPU0 ] | CR0=0x00000011 CR1=0x0 CR2=0x0000000000000000 00200832996i[CPU0 ] | CR3=0x00000000 CR4=0x00000000 00200832996i[CPU0 ] >> (invalid) : FFFF 00200832996e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Und zum besseren Vergleich hier nochmal der modifizierte Quellcode meines OS:
... ... ... ... kernel_pmode: jmp p_start gdt: gdt_null: dd 0x00 dd 0x00 gdt_code: dw 0xFFFF dw 0x00 db 0x10 db 10011010b db 11001111b db 0x10 gdt_data: dw 0xFFFF dw 0x00 db 0x10 db 10010010b db 11001111b db 0x00 gdt_end: GDT32: Limit dw 3 * 8 BaseAdr dd gdt + 0x10000 p_start: mov ax,cs and eax,0FFFFh shl eax,4 add ax,p_start mov word [gdt_code+2],ax shr eax,16 mov byte [gdt_code+4],al mov ax,cs and eax,0FFFFh shl eax,4 add ax,p_start mov word [gdt_data+2],ax shr eax,16 mov byte [gdt_data+4],al lgdt [GDT32] cli mov eax, cr0 or al,1 mov cr0,eax ; "FAR-JMP" db 0eah dw now_in_prot dw 0x08 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 32-Bit protected mode ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; [BITS 32] now_in_prot: jmp $