4
« am: 05. August 2004, 23:45 »
Hallo Leute,
hab ein Problem mit dem PMode!
Wenn mein Kernel geladen wird, schalte ich (im Kernel) in den Protected Mode, dies funktioniert aber nur soweit, dass ich nur bis zum laden der GDT komme und bei den Befehlen:
mov eax, cr0 ; Copy the contents of CR0 into EAX
or eax, 1 ; Set bit 0
mov cr0, eax ; Copy the contents of EAX into CR0
Nachdem diese Befehle ausgeführt wurden, friert der Computer ein!
Hier nochmal der ganze Code:
[bits 16]
; ---------------------------------------------------------
; Unser Kernel
; ---------------------------------------------------------
mov ax, 1000h ; Update die Segmentregister:
mov ds, ax
mov es, ax
start:
mov ax,cs
mov ds,ax
; ---------------------------------------------------------
; Registriere den Interrupt
; ---------------------------------------------------------
push dx
push es
xor ax,ax
mov es,ax
cli
mov word [es:0x80*4], _int0x80
mov [es:0x80*4+2],cs
sti
pop es
pop dx
; ---------------------------------------------------------
mov ah,02h ; CLS
int 0x80
mov ah,01h
mov si,os_info_dlg ;OS Infos anzeigen ...
int 0x80
mov ah,01h
mov si,bootloader_ver
int 0x80
mov ah,01h
mov si,kernel_ver
int 0x80
; Der Ablauf:
; 1. Interrupts deaktivieren
; 2. DS & CS zeigen auf das selbe Segment
; 3. eax um 4 Bits nach links verschieben um die lineare Adresse
; zu erhalten.
; 4. Eintragen des ersten Teils der linearen Adresse
; 5. eax um 16 Bits nach rechts verschieben um den 2. Teil der
; linearen Adresse zu erhalten.
; 6. Den zweiten Teil der linearen Adresse eintragen
cli ; 1
xor ax, ax
mov ds, ax
mov eax, cs ; 2
mov ds, ax ; 2
shl eax, 4 ; 3
mov [CODE_Descriptor+2], ax ; 4
mov [DATA_Descriptor+2], ax ; 4
shr eax, 16 ; 5
mov [CODE_Descriptor+4], al ; 6
mov [DATA_Descriptor+4], al ; 6
; Nun errechnen wird die Basisadresse und das Limit der GDT.
; Um die Basisadresse zu errechnen müssen wir das CS Register
; nach EAX verschieben und wieder 4 Bits nach links. Nun addieren
; wird den Offset von NULL_Desc dazu, da dieser der Startoffset
; der GDT ist.
;
; Um das Limit der GDT zu errechnen, müssen wir den Startoffset
; vom GDT-Offset abziehen.
mov eax, cs
shl eax, 4
add eax, NULL_Descriptor
mov [Base], eax
mov [Limit], WORD gdt - NULL_Descriptor - 1
; Nun können wir das GDT Register laden.
lgdt [gdt]
; CLEAN !!!
; Nachdem wir nun das GDT Register mit den Werten geladen haben,
; können wir in den Protected Mode schalten ... *ENDLICH*
; Dazu müssen wir ...
; 1. CR0-Register in EAX laden
; 2. Das erste Bit (PE Bit [Protection Enable]) auf 1 setzen
; (Sobald es auf 1 gesetzt wird, befindet sich der Prozessor
; im Protected Mode. Wird das Bit gelöscht, befindet sich
; der Prozessor wieder im Real Mode
; ).
; 3. Das CR0-Register mit dem neuen Wert laden!
mov eax, cr0 ; Copy the contents of CR0 into EAX
or eax, 1 ; Set bit 0
mov cr0, eax ; Copy the contents of EAX into CR0
sti
mov ah,01h
mov si,debug_4
int 0x80
cli
; Nachdem nun (fast) alles geschafft ist und wir uns im PMode
; befinden müssen wir nur noch das CS-Register laden und den
; Prefetch von den alten 16Bit Befehlen leeren.
;
; Dies errechen wir mit einem FAR JUMP
db 0xEA ; Bitmuster eines FAR JUMPS
dw PMODE ; Wohin wir springen wollen
dw 0x8 ; Angabe des Selektors für
; das Segment zu dem ge-
; sprungen werden soll.
sti
mov ah,01h
mov si,debug_5
int 0x80
cli
; So nun haben wir es geschafft, wir befinden uns im PMode
; und müssen es nur noch NASM mitteilen.
[bits 32]
PMODE:
sti
mov ah,01h
mov si,debug_6
int 0x80
cli
; Da wir zuvor die Segmentadresse verschoben haben, müssen
; wir diese nun wieder zurückstellen.
mov WORD [CODE_Descriptor+2], 0
mov WORD [DATA_Descriptor+2], 0
mov BYTE [CODE_Descriptor+4], 0
mov BYTE [DATA_Descriptor+4], 0
sti
mov ah,01h
mov si,debug_7
int 0x80
cli
mov ax, 2 ; Index 2 der GDT Table
shl ax, 3 ; Im Selektor bginnt der
; Index erst ab Bit 3
mov ds, ax
mov es, ax
mov ss, ax
mov eax, 0
mov fs, ax ; FS und GS auf einen NULL-
; Descriptor zeigen lassen
mov gs, ax
mov esp, 0x400000 ; Stack-Größe auf 4 MB setzen
jmp 0x8:0x10000 + PMODE2
PMODE2:
sti
mov ah,01h
mov si,debug_7
int 0x80
cli
mov ah,01h
mov si,shutdown_dlg ;Shutdown_dlg
int 0x80
jmp shutdown ;shutdown
; ---------------------------------------------------------
; Variablen
; ----------------------------------------------------------
os_info_dlg db "DDos32 (Dark Disk Operation System) Infos:",13,10,0
bootloader_ver db "Bootloader (asm ver.): 1.0",13,10,0
kernel_ver db "Kernel (asm ver.): 0.2",13,10,0
shutdown_dlg db 13,10,"Dr",129,"cken Sie eine Taste zum herunterfahren...",13,10,0
sommerzeit db "z.Z. haben wir Sommerzeit",0
; DEBUG VARS
debug_1 db "Debug 1",13,10,0
debug_2 db "Debug 2",13,10,0
debug_3 db "Debug 3",13,10,0
debug_4 db "Debug 4",13,10,0
debug_5 db "Debug 5",13,10,0
debug_6 db "Debug 6",13,10,0
debug_7 db "Debug 7",13,10,0
; GDT_START Descriptors
;Deskriptoren
NULL_Descriptor:
; Den NULL_Descriptor braucht man, um Register und aehnliches,
; welche nicht benutzt werden "abzulenken", damit sie keine
; Speicherschutzverlätzung generieren!
;
; Dazu werden 2 DWORD mit dem Wert 0 erstellt.
dd 0
dd 0
CODE_Descriptor:
; Der CODE_Descriptor ist dazu da, um den OS Code zu behandeln.
dw 0xFFFF
dw 0
db 0
db 10011010b
db 00000000b
db 0
DATA_Descriptor:
; Der DATA_Descriptor behandelt unsere Daten, die das OS verwaltet.
dw 0xFFFF
dw 0
db 0
db 10011010b
db 00000000b
db 0
gdt:
; Dies ist unsere GDT (Global Descriptor Table)
Limit dw 0
Base dd 0
; GDT_END
; ---------------------------------------------------------
; Interrupt (0x80)
; ---------------------------------------------------------
_int0x80:
pusha
cmp ah,0x0
je _int0x80_ser0x00
cmp ah,0x1
je _int0x80_ser0x01
cmp ah,0x2
je _int0x80_ser0x02
cmp ah,0x3
je _int0x80_ser0x03
jne _int0x80_end
_int0x80_ser0x00: ; routine 0x00
mov ah,0x0E
mov al,dl
int 10h
jmp _int0x80_end
_int0x80_ser0x01:
lodsb
or al,al
jz _int0x80_ser0x01_end
mov ah,0x0E
int 10h
jmp _int0x80_ser0x01
_int0x80_ser0x01_end:
jmp _int0x80_end
_int0x80_ser0x02:
xor al,al
xor cx,cx
mov dh,25
mov dl,80
mov bh,7
mov ah,6
int 010h
mov bh,0
mov ah,3
int 010h
mov dx,0
mov ah,2
int 010h
jmp _int0x80_end
_int0x80_ser0x03:
mov ah,0
int 016h
jmp _int0x80_end
_int0x80_end:
popa
iret
; ---------------------------------------------------------
shutdown:
mov AX,0x5300
XOR BX,BX
INT 15h ; APM install check
MOV AX,0x5304
XOR BX, BX
INT 15h ; disconnect interface
MOV AX,0x5301
XOR BX, BX
INT 15h ; connect real-mode interface
MOV AX,0x5307
MOV BX,1
MOV CX,3
INT 15h ; powerdown system
(Bis zum Kommentar "CLEAN !!!" läuft alles)