Moin,
um etwas Assembler zu lernen habe ich mir (mit einigen Anleitungen für ganz simple Bootloader) ein kleines bootfähiges Programm geschrieben, welches 3 Sachen macht:
- einen Text ausgeben
- in einer Schleife alle Tastatureingaben ausgeben
- wenn ESC gedrückt wird noch einen Text ausgeben und beenden
Das funktioniert auch, bis auf dass die Enter-Taste nur einen Carriage Return ausgibt und keinen Zeilenumbruch macht. Das wollte ich ändern, indem ich prüfe, ob die Enter-Taste gedrückt wurde und wenn ja, erst der Zeilenumbruch ausgegeben wird (0x0A) und dann im Anschluss der Carriage Return (0x0D). Hier ein Ausschnitt:
Linebreak:
mov ah,0x0E ; Print-Funktion nutzen (0x0e)
mov al,0x0A ; Zeilenumbruch ausgeben
int 0x10 ; Interrupt auslösen
ret
Main:
mov ah,00h ; auf Tastendruck warten
int 0x16 ; Interrupt auslösen
cmp al,0x1B ; ESC gedrückt?
je Ende ; => zum Ende springen
push ax ; ax sichern (al = 0x0D)
cmp al,0x0D ; Enter gedrückt?
je Linebreak ; => Zeilenumbruch (0x0A) ausgeben
pop ax ; ax wiederherstellen (damit sollte al wieder 0x0D sein)
mov ah,0x0E ; Print-Funktion einstellen
int 0x10 ; Interrupt auslösen
jmp Main ; Main-Schleife
Das funktioniert nur so lange, bis man Enter drückt. Ist das der Fall wird nur der Zeilenumbruch ausgegeben (0x0A), und dann friert das Programm ein. Ich habe nach einigem hin- und herprobieren keine Idee mehr, was ich falsch mache. Ich habe auch keine Idee, wie ich das debuggen könnte, und hoffe jetzt, dass ihr mir helfen könnt.
Noch einige Informationen zu meinen Tools: Ich nutze zum Kompilieren nasm und zum Testen qemu:
$ nasm -f bin boot.asm -o boot.img
$ qemu-system-x86_64 -fda boot.img
Hier ist der vollständige Code:
;****************************************
; boot.asm - Einfacher Bootloader
;
; 2016 - marco@misterunknown.de
;****************************************
BITS 16 ; 16-Bit Real-Mode
org 0x7C00 ; Wir werden vom BIOS an diese Adresse geladen.
Start: jmp Loader ; Loader
msga db "Testausgabe",10,13,0
msgb db 13,10,13,10,"Ende",13,10,0
;**************************************
; Funktionen
;**************************************
Print:
lodsb ; lädt das nächste Byte von SI nach AL
or al,al ; ist AL null?
jz PrintDone ; wenn ja, dann gehe zu PrintDone
mov ah,0x0E ; Print-Funktion nutzen (0x0e)
int 0x10 ; Interrupt auslösen
jmp Print ; Rücksprungmarke aufrufen
PrintDone:
ret
Linebreak:
mov ah,0x0E ; Print-Funktion nutzen (0x0e)
mov al,0x0A ; Zeilenumbruch ausgeben
int 0x10 ; Interrupt auslösen
ret
;**************************************
; Loader
;**************************************
Loader:
xor ax,ax ; schneller Weg um das Register zu nullen
mov al,03h ; in den Text-Modus wechseln (löscht gleichzeitig den Bildschirm)
int 0x10 ; Interrupt auslösen
mov si,msga ; Nachricht in source-Register laden
call Print ; Print-Funktion aufrufen
;**************************************
; Hauptschleife
;**************************************
Main:
mov ah,00h ; auf Tastendruck warten
int 0x16 ; Interrupt auslösen
cmp al,0x1B ; ESC gedrückt?
je Ende ; => zum Ende springen
push ax ; ax sichern (al = 0x0D)
cmp al,0x0D ; Enter gedrückt?
je Linebreak ; => Zeilenumbruch (0x0A) ausgeben
pop ax ; ax wiederherstellen (damit sollte al wieder 0x0D sein)
mov ah,0x0E ; Print-Funktion einstellen
int 0x10 ; Interrupt auslösen
jmp Main ; Main-Schleife
Ende:
mov si,msgb
call Print
cli ; Interrupts leeren
hlt ; System anhalten
times 510 - ($ - $$) db 0 ; Das Programm muss 512 Bytes groß werden. Dazu wird mit Nullen aufgefüllt.
; 510 kommt daher, weil hinten noch die 2 Byte lange Signatur folgt.
dw 0xAA55 ; Signatur des Bootloaders
; vim: syn=nasm