hallöle
ich habe einige zeit nicht mehr an mein "MinOS" kernel gearbeitet... also hab ich mein projekt vorerst geworfen und verfolge das os-dev tutorial von herrn henkes. nun habe ich folgendes problem: ich habe
diesen kernel abgetippt, der sich auch ohne fehlermeldungen kompilieren lässt. allerdings, wenn ich den befehl "help" eingebe, kommt dort die fehlermeldung, das der befehl nicht existiert.
hier ersteinmal meine adaption des kernels:
; MyOS Kernel Vers. 0.0.3 - 11 Juni 2009
;;;;;;;;;;;;;;;;;
; Realmode Code ;
;;;;;;;;;;;;;;;;;
org 0x8000 ; Kernel Startadresse
[BITS 16] ; 16 Bit Code
; RealMode Bereich des Kernels
RealMode:
xor ax, ax ; Segmente einrichten
mov es, ax
mov ds, ax
mov ss, ax
mov sp, ax
mov si, welcome
call print_string
add sp, -0x40 ; Input Buffer auf 64 Zeichen setzen
loop_start:
mov si, prompt ; Eingabeaufforderung Zeigen
call print_string
mov di, sp ; Hole Eingaben
call get_string
jcxz loop_start ; Leere Zeile? Wenn ja, ignorieren und zum Start zurück
mov si, sp
mov di, cmd_hi ; "hi" Kommando
call strcmp
je .helloworld
mov si, sp
mov di, cmd_questionmark ; "?" Kommando
call strcmp
je .help
mov si, sp
mov di, cmd_exit ; "exit" Kommando
call strcmp
je .exit
mov si, sp
mov di, cmd_pm ; "pm (protected mode)" Kommando
call strcmp
je .pm
mov si, badcommand
call print_string
jmp loop_start
.helloworld:
mov si, msg_helloworld
call print_string
jmp loop_start
.help:
mov si, msg_help
call print_string
jmp loop_start
.exit:
mov si, msg_exit
call print_string
xor ax, ax
int 0x16 ; Warte auf Tastendruck
jmp 0xffff: 0x0000 ; Neustart
.pm:
call clrscr
mov si, msg_pm
call print_string
call Waitingloop
cli ; Interrups leeren
lgdt [gdtr] ; Lade die GDT per GDTR (Eingerichtet in der Datei "gdt.asm"
in al, 0x92 ; A20-Gate per schnellen A20 Port 92 einschalten
cmp al, 0xff ; Falls 0xFF zurück gegeben wird, ist der Port nicht Verfügbar...
je .no_fast_A20 ; ... in diesem fall, zu diesem Punkt springen...
; andernfalls geht es hier weiter:
or al, 2 ; A20-Gate Bit setzen (Bit 1)
and al, ~1 ; Init-Bit setzen
out 0x92, al
jmp .A20_done
; Steht kein schneller A20-Gate zur Verfügung...? Dann benutzt der Kernel den Weg über den KBC Chip
.no_fast_A20:
call empty_8042
mov al, 0xD1 ; KBC Kommando: Schreibe auf Output Port
call empty_8042
mov al, 0xDF ; Schreibe dies auf KBC Output Port zum einschalten des A20 Gate
out 0x60, al
call empty_8042
; Umschalten in den A20-Gate beenden
.A20_done:
mov eax, cr0
or eax, 1
mov cr0, eax
jmp 0x8:ProtectedMode
empty_8042:
call Waitingloop
in al, 0x64 ; Kein echter KBC...?
cmp al, 0xFF
je .done
test al, 1 ; something in Input Buffer
jz .no_output
call Waitingloop
in al, 0x60 ; Wenn ja, Buffer lesen...
jmp empty_8042 ; ... dann nocheinmal
.no_output:
test al, 2 ; Kommando Buffer leer?
jnz empty_8042 ; Wenn nein, dann Buffer als nicht leer markieren und zur "Leerungsroutine" springen
.done:
ret
print_string:
mov ah, 0x0E
.loop_start:
lodsb ; Hole ein Byte von SI
test al, al ; Alle Zeichen geholt? Wenn ja, dann...
jz .done ; Funktion verlassen
int 0x10 ; Wenn nein, dann Zeichen ausgeben...
jmp .loop_start ; ... Anschliessend nochmal von vorn
.done:
ret
get_string:
xor cx, cx
.loop_start:
xor ax, ax
int 0x16 ; Auf Tastendruck warten
cmp al, 8 ; Rücktaste gedrückt?
je .backspace ; Wenn ja, entsprechend behandeln
cmp al, 13 ; Entertaste gedrückt?
je .done ; Wenn ja, entsprechend behandeln
cmp cl, 63 ; 63 Zeichen eingegeben?
je .loop_start ; Wenn ja, nur noch Rücktaste und Enter erlauben
mov ah, 0x0E
int 0x10 ; Gebe Zeichen aus
stosb ; Speichere Zeichen in Puffer
inc cx
jmp .loop_start
.backspace:
jcxz .loop_start ; Leer (Keine Zeichen auf dem Bildschirm) ? Wenn ja, Rücktaste ignorieren
dec di
mov byte [di], 0 ; Lösche ein Zeichen
dec cx ; Reduziere Speicherplatz für Zeichenkette
mov ah, 0x0E
int 0x10 ; Rücktaste auf dem Bildschirm zeigen
mov al, ' '
int 0x10 ; Gebe "Rücktastenzeichen" (Leerzeichen) aus
mov al, 8
int 0x10 ; Zeige erneut die Rücktaste auf dem Bildschirm
jmp .loop_start
.done:
mov byte [di], 0 ; NULL terminator
mov ax, 0x0E0D
int 0x10
mov al, 0x0A
int 0x10 ; Neue Zeile
ret
strcmp:
.loop_start:
mov al, [si] ; Hole ein Zeichen von SI
cmp al, [di] ; Sind SI und DI identisch?
jne .done ; Nein? Wir sind fertig
test al, al ; Keine Zeichen mehr zu prüfen?
jz .done ; Wenn ja, sind wir fertig
inc di ; DI um 1 verringern
inc si ; SI um 1 verringern
jmp .loop_start
.done:
ret
clrscr:
; Funktion, um den Bildschirm zu "leeren"
mov ax, 0x0600
xor cx, cx
mov dx, 0x174F
mov bh, 0x07
int 0x10
ret
;;;;;;;;;;;;;;;;;;;;;;;
; Protected Mode Code ;
;;;;;;;;;;;;;;;;;;;;;;;
[Bits 32]
ProtectedMode:
mov ax, 0x10
mov ds, ax ;Daten Desciptor -> Daten, Stack und Extra Segment
mov ss, ax
mov es, ax
xor eax, eax ; NULL Descriptor -> FS und GS
mov fs, ax
mov gs, ax
mov esp, 0x200000 ; Setze Stack Limit auf 2MB
call clrscr_32
mov ah, 0x01
.endlessloop:
call Waitingloop
inc ah
and ah, 0x0f
mov esi, msg_pm2 ; Nachricht "Betriebssystem läuft im Protected Mode"
call PutStr_32
cmp dword [PutStr_Ptr], 25 * 80 * 2 + 0xB8000
jb .endlessloop
mov dword [PutStr_Ptr], 0xB8000 ; Text Zeiger Wrapper
jmp .endlessloop
Waitingloop:
mov ebx, 0x9FFFF
.loop_start:
dec ebx
jnz .loop_start
ret
PutStr_32:
; PM Mode Textausgabe
mov edi, [PutStr_Ptr]
.nextchar:
lodsb
test al, al
jz .end
stosw
jmp .nextchar
.end:
mov [PutStr_Ptr], edi
ret
clrscr_32:
mov edi, 0xb8000
mov [PutStr_Ptr], edi
mov ecx, 40 * 25
mov eax, 0x07200720 ; 2 Werte -> Weisser Text auf schwarzen Hintergrund | 0x20 -> Freier Platz
rep stosd
ret
PutStr_Ptr dd 0xb000
; Man läd die Adresse des Textes, den man haben möchte, über "[PutStr_Ptr]
; für die Textaugaben. Der Text muss NULL terminiert sein.
; you want to print in esi and the attributes in ah
; lodsb loads one byte from esi into al, then increments esi,
; then it checks for a NUL terminator,
; then it moves the char into the write position in video memory,
; then increments edi and writes the attributes,
; loops until it finds NUL pointer at which point it breaks ...
;;;;;;;;;;;;;;;;
; Textausgaben ;
;;;;;;;;;;;;;;;;
welcome db 'MinOS Vers. 0.03', 13, 10, 0
msg_helloworld db 'Hello World on MinOS Vers. 0.03', 13, 10, 0
badcommand db 'Unbekannter Befehl', 13, 10, 0
prompt db '> ', 0
cmd_hi db 'hi', 0
cmd_help db 'help', 0
cmd_questionmark db '?', 0
cmd_exit db 'exit', 0
cmd_pm db 'pm', 0
msg_help db 'Befehle: hi, help, ?, pm, exit', 13, 10, 0
msg_exit db 'Computer wurde herunter gefahren. Du kannst ihm nun ausschalten. Alternativ druecke eine Taste, um ihm neuzustarten.', 13, 10, 0
msg_pm db 'Schalte in den Protected Mode.', 13, 10, 0
msg_pm2 db 'MinOS arbeitet im Protected Mode. ', 0
;;;;;;;;;;;;
; Includes ;
;;;;;;;;;;;;
%include "gdt.asm"
;;;;;;;;;;;;;;;
; Kernel Ende ;
;;;;;;;;;;;;;;;
times 1024-($-$$) hlt
hab ich mich da einfach nur irgendwo vertippt, was nasm nicht anmeckert, weil nasm alles sieht was es sehen muss...? ach ja, ich kompiliere mit nasm, nicht nasmw...
---
[ot]
herr henkes schreibt ein wirklich klasse tutorial. alles ist schön schrittweise strukturiert und erklärt.