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:

Code: Select all

mov   ax,   2
int   10h
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:

Code: Select all

mov   ax,   2
int   10h
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.