Page 1 of 1
printing to screen (strange problem)
Posted: Thu Dec 15, 2011 10:10 am
by mariuszp
I have a strange problem with printing to the screen (in Real Mode). I wrote a function that would clear the screen and then print a message to it. Here's what it looks like:
Code: Select all
;; print a message to the screen
;; in SI = string to print (NUL-terminated)
;; in DL = color attribute to be used
;; DI, ES = destroyed
putmsg:
mov ax, 0xb800
mov es, ax
xor di, di
mov cx, 80*25*2
mov al, 0
rep stosb ; clear the screen
xor di, di
.loop:
lodsb
test al, al
jz .ret
mov ah, dl
stosw
jmp .loop
.ret:
ret
;; STRINGS
str_loading db 'Loading stage2.bin', 0
str_config_fail db 'Nextep loader stage1.bin configuration invalid', 0
str_passing db 'Passing control to stage2.bin', 0
When I then try to use it, e.g. like this:
Code: Select all
mov si, str_passing
mov dl, 0x02
call putmsg
it only works sometimes... normally it prints the first 2 letters of the string and then freezes. but it other cases it works, and that's what I'm confused about.
can anybody see what's wrong here??
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 11:21 am
by evoex
I might be missing something, but I can't find anything wrong with your code. Are you sure the ds register is set up properly?
(I know assembly more or less, but I'm by no means an expert, so I might be miles off)
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 11:58 am
by M2004
Some ideas:
1) Saving used registers onto stack when entering the procedure and
restoring them from the stack when leaving the procedure.
2) Have you set up stack properly?
3) ds register set up as evoex suggested
regards
Mac2004
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 2:11 pm
by DavidCooper
It looks as if it should work. Can you show us how you're setting up a string to print so that we can see if you're lining both DS and SI up on it properly? Could the error be extra zeros creeping into the strings to be printed?
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 2:37 pm
by turdus
Your code seems to be correct, but may I suggest
Code: Select all
;; print a message to the screen
;; in SI = string to print (NUL-terminated)
;; in DL = color attribute to be used
;; DI, ES = destroyed
putmsg:
mov ax, 0xb800
mov es, ax
xor di, di
mov cx, 80*25
;mov ax, 0720h ;would be better
xor ax, ax
rep stosw ; clear the screen
xor di, di
mov ah, dl
;;assuming you don't want to print empty string
.loop:
lodsb
stosw
or al, al
jnz .loop
ret
It's faster and smaller with a few bytes this way (in a stage 1 bootloader every byte matters).
You should clear the screen with white spaces (0720h), can save you many troubles later (why doesn't "inc byte [0b8000h]" work? and alike). Otherwise it seems ok, and should work.
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 3:09 pm
by DavidCooper
I've just tried running the code and it works. I thought it didn't work for a moment and posted a message here telling you to change test al,al into cmp al,0 but I'd typed in the test instruction wrongly - it actually works fine. The problem must be elsewhere.
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 5:44 pm
by Nessphoro
Uh, actually the VRAM is located at 0xB8000
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 8:21 pm
by evoex
Nessphoro wrote:Uh, actually the VRAM is located at 0xB8000
I made the same mistake at first. He's loading 0xB800 in a segment register, so the actual address needs to be calculated as "es*16 + edi", or "0xB8000 + edi".
Re: printing to screen (strange problem)
Posted: Thu Dec 15, 2011 11:28 pm
by eryjus
Two offers:
A) Try explicitly setting the direction flag
B) Double check your DS register to make sure your ds:si address is formatted right
Re: printing to screen (strange problem)
Posted: Fri Dec 16, 2011 12:58 am
by bluemoon
mariuszp wrote:it only works sometimes...
I smell some issue before your print function.
Since the print function is so simple, it either always work or never work. I suspect it is the code before print message that put the machine into random state. Can you describe what you do before print message?
Re: printing to screen (strange problem)
Posted: Fri Dec 16, 2011 8:11 am
by mariuszp
Code: Select all
;; Nextep loader stage 1
;; This file must be put in the boot sector of your boot disk
;; it will load the stage2.bin file, located at the first few
;; sectors of the boot disk.
org 0x7C00
bits 16
ATTR_GREEN equ 0x02
ATTR_RED equ 0x04
ATTR_WHITE equ 0x07
;; make sure the header is not executed
;; (jump over it)
db 0xEB
db ConfigHeader.end-ConfigHeader
ConfigHeader:
.bootdisk db 0x00 ;; 00h=fd0, 01h=fd1, 80h=hd0, 81h=hd1 [offset 2]
.stage2size dw 3 ;; size of the stage2.bin file (in sectors) [offset 3]
.width dw 720 ;; preferred screen width [offset 5]
.height dw 480 ;; preferred screen height [offset 7]
.end:
;; set up the registers correctly
mov ax, 0
mov ds, ax
mov ss, ax
jmp 0:_start
_start:
;; reset the correct video mode (some BIOSes set up a graphics mode to start with)
mov ax, 2
int 10h
;; set up a stack
mov sp, 0x7CFF
;; Make sure everything is OK
mov ax, [ConfigHeader.stage2size]
test ax, ax
jnz ok0
;; if not OK, print an error message
mov si, str_config_fail
mov dl, ATTR_RED
call putmsg
cli
hlt
;; Main loading routine
ok0:
mov si, str_loading
mov dl, ATTR_WHITE
call putmsg
loadloop:
mov ax, 0x7E0
mov es, ax
mov ah, 0x02
mov al, [ConfigHeader.stage2size]
mov cx, 2
mov dh, 0
mov dl, [ConfigHeader.bootdisk]
mov bx, 0
int 13h
jc loadloop ; if failed, retry
;; tell the user we are about to pass control to stage2.bin
mov si, str_passing
mov dl, ATTR_GREEN
call putmsg
;; finally, run stage2.bin!
jmp 0x7E0:0
;; print a message to the screen
;; in SI = string to print (NUL-terminated)
;; in DL = color attribute to be used
;; DI, ES = destroyed
putmsg:
mov ax, 0xb800
mov es, ax
xor di, di
mov cx, 80*25*2
mov al, 0
rep stosb ; clear the screen
xor di, di
.loop:
lodsb
test al, al
jz .ret
mov ah, dl
stosw
jmp .loop
.ret:
ret
;; STRINGS
str_loading db 'Loading stage2.bin', 0
str_config_fail db 'Nextep loader stage1.bin configuration invalid', 0
str_passing db 'Passing control to stage2.bin', 0
times 510 - ($ - $$) db 0
db 0x55, 0xAA
That's the whole code. I think it could actually be a QEMU bug - in my stage 2 loader, which prints without clearing the screen, messages only come up after a
next message is printed. In VirtualBox there is no problem with that stage 2 loader, but there is the same problem with this one, however.
Re: printing to screen (strange problem)
Posted: Fri Dec 16, 2011 8:40 am
by evoex
I believe sp should really be d-word aligned. I'm not completely sure about it, and I haven't read all code (yet), but that may be worth a try.
Also, have you tried removing:
I'm not sure what it does (little experience yet with regards to interrupts); it seems to set the video mode to "2". The interrupt list (
http://www.ctyme.com/intr/rb-0069.htm) doesn't really specify what it does, or I can't really make sense out of it, but it does say "bit 1 Korean (double-byte) characters", which may be what it's doing.
I'd suggest removing that, at least testing it without it. It might even be a bios bug in the debugger you're using, even if it is valid.
Re: printing to screen (strange problem)
Posted: Fri Dec 16, 2011 9:16 am
by Combuster
evoex wrote:Also, have you tried removing:
I'm not sure what it does
At least nothing with korean. It sets the display to 80x25 monochrome text on CGA/EGAs. Which is technically a bug as the comments describe colour values. The correct value is 3 to set the de-facto standard text mode, but should not otherwise break mysteriously.
The stack is however broken when that call gets performed - MOV SS and MOV SP should appear as a pair together otherwise the stack might appear somewhere it shouldn't. Worse, SS:SP=0x00007CFF explicitly puts the stack halfway into your code and really needs fixing.