Reputation: 1581
I am writing a bootloader with nasm. At the moment it is designed to output a welcome string, then record keystrokes while displaying them, printing the stored keystrokes upon finding the enter key, and finally halting.
bits 16
org 0x7C00
start: jmp main
bgetkey: pusha
mov ax, 0
mov ah, 10h
int 16h
mov [.buf], ax
popa
mov ax, [.buf]
ret
.buf dw 0
prints: mov ah, 0x0e
mov al, [si]
cmp al, 0
jz print_end
mov bh, 0x00
mov bl, 0x07
int 0x10
inc si
jmp prints
print_end: ret
main: mov ax, 0x0000 ; set register a
mov ds, ax ;
mov bx, mem
add bx, word 1
mov word [mem], bx
mov si, welcome ; set and prints
call prints ;
type: mov si, qbuf ; set prints ptr
call bgetkey ; capture input
mov [qbuf], al ; set char to sz
call prints ; call print str
mov bx, [mem] ; put chr in mem
cmp bx, stop ; compare loader
je oom ; end and memory
mov byte [bx], al
add bx, byte 1
mov [mem], bx ;
cmp byte [qbuf], 0x0D ; cmpr enter key
jne type ; continue next
mov si, newline ; print newline
call prints ;
mov bx, mem
printmem: cmp byte [bx], 0x00 ; check for zero
je halt ; halt the cpu
mov cl, [bx]
mov byte [qbuf], cl ; buffer and cpy
mov si, qbuf ; pointer to si
call prints ; print the char
inc bx
jmp printmem ; jump beginning
oom: mov si, outomem ; no more memory
call prints ; print message
halt: mov si, halting ; cpu is halting
call prints ; print last msg
hlt ; halt the cpu
welcome db "bootloader", 0x0A, 0x0D, 0x00
newline db 0x0A, 0x00
outomem db "out of memory", 0x0A, 0x0D, 0x00
halting db "halting", 0x00
qbuf dw 0, 0
mem db 0
times 0200h - 2 - ($ - $$)db 0
stop dw 0xAA55
The program is not functioning as desired. It ceaselessly prints the same character after enter is pressed. How is this error corrected?
Upvotes: 0
Views: 160
Reputation: 58822
The immediate problem is that your prints
destroys bx
(because it sets bl
and bh
) so your printmem
loop which requires bx
to be preserved blows up.
However, it also destroys al
so your input loop won't be storing the correct value in memory to start with, either.
Furthermore, while you want mem
to be a pointer to mem + 2
, it is actually a pointer to mem + 1
so you overwrite the pointer with the input. Also, you start printing from mem
and not mem + 2
.
Finally, your input is not terminated by a zero that you are checking for, it's terminated by a 0x0D
(the enter).
A working version could be:
bits 16
org 0x7C00
start: jmp main
bgetkey: pusha
mov ax, 0
mov ah, 10h
int 16h
mov [.buf], ax
popa
mov ax, [.buf]
ret
.buf dw 0
prints: pusha
.loop:
mov ah, 0x0e
mov al, [si]
cmp al, 0
jz print_end
mov bh, 0x00
mov bl, 0x07
int 0x10
inc si
jmp .loop
print_end: popa
ret
main: mov ax, 0x0000 ; set register a
mov ds, ax ;
mov bx, mem
add bx, word 2 ; point to after the pointer :)
mov word [mem], bx
mov si, welcome ; set and prints
call prints ;
type: mov si, qbuf ; set prints ptr
call bgetkey ; capture input
mov [qbuf], al ; set char to sz
call prints ; call print str
mov bx, [mem] ; put chr in mem
cmp bx, stop ; compare loader
je oom ; end and memory
mov byte [bx], al
add bx, byte 1
mov [mem], bx ;
cmp byte [qbuf], 0x0D ; cmpr enter key
jne type ; continue next
mov si, newline ; print newline
call prints ;
mov bx, mem+2 ; start from after the pointer
printmem: cmp byte [bx], 0x0D ; check for end
je halt ; halt the cpu
mov cl, [bx]
mov byte [qbuf], cl ; buffer and cpy
mov si, qbuf ; pointer to si
call prints ; print the char
inc bx
jmp printmem ; jump beginning
oom: mov si, outomem ; no more memory
call prints ; print message
halt: mov si, halting ; cpu is halting
call prints ; print last msg
hlt ; halt the cpu
welcome db "bootloader", 0x0A, 0x0D, 0x00
newline db 0x0A, 0x00
outomem db "out of memory", 0x0A, 0x0D, 0x00
halting db "halting", 0x00
qbuf dw 0, 0
mem db 0
times 0200h - 2 - ($ - $$)db 0
stop dw 0xAA55
PS: Learn to use a debugger.
Upvotes: 3