Page 1 of 1

Print being screwy (Real mode assembler)

Posted: Fri Jan 13, 2012 11:28 am
by Unkn0wn1
Alright, for my current project (A simple OS in real mode( BIOS ISRs)), I am currently testing printing to the screen. It works fine in my loader, but then, when I attempt to write a newline (0x0D, 0x0A), and then some text, the following happens - Bochs full snapshot


Plex86/Bochs VGABios (PCI) 0.7a 30 Oct 2011
This VGA/VBE Bios is released under the GNU LGPL

Please visit :
. http://bochs.sourceforge.net
. http://www.nongnu.org/vgabios

Bochs VBE Display Adapter enabled

Bochs BIOS - build: 11/24/11
$Revision: 10789 $ $Date: 2011-11-24 17:03:51 +0100 (Do, 24. Nov 2011) $
Options: apmbios pcibios pnpbios eltorito rombios32


Press F12 for boot menu.

Booting from Floppy...
Hello from FIND's loader :) ¸À úŽÐ¼ß

My print string is as follows

Code: Select all

printStr:	; Output string in SI to screen
	pusha

	mov ah, 0Eh			; int 10h teletype function

.repeat:
	lodsb				; Get char from string
	cmp al, 0
	je .done			; If char is zero, end of string
	int 10h				; Otherwise, print it
	jmp short .repeat

.done:
	popa
	ret
The code that calls it is this

Code: Select all

mov si, newline
call printStr
mov si, helloStr
call printStr
Assuming a generic, null-terminated hello string as helloStr, and newline DB'd as 0x0D, 0x0A, 0

What have I done wrong?

Re: Print being screwy (Real mode assembler)

Posted: Fri Jan 13, 2012 11:44 am
by bluemoon
1. BX is not set.

Code: Select all

Teletype output	AH=0Eh	AL = Character, BH = Page Number, BL = Color (only in graphic mode)
2. Single-step to verify si points to your string. I guess it's ORG-related issue but can't be sure without seeing full source.

3. It may also be possible that the kernel is not probably loaded. Again, can't be sure without seeing how the loader work.

Re: Print being screwy (Real mode assembler)

Posted: Fri Jan 13, 2012 11:57 am
by Unkn0wn1
The loader? Here's the source, if it's any help.

Code: Select all

;All this does is reads and execs the kernel of
;FIND
;(c) 2011 Ben Jackson


	BITS 16

	jmp short bootloader_start	; Jump past disk description section
	nop				; Pad out before disk description


; ------------------------------------------------------------------
; Disk description table, to make it a valid floppy
; Values for 3.5inch 1440KB floppy

OEMLabel		db "FINDBOOT"	; Disk label
BytesPerSector		dw 512		; Bytes per sector
SectorsPerCluster	db 1		; Sectors per cluster
ReservedForBoot		dw 1		; Reserved sectors for boot record
NumberOfFats		db 2		; Number of copies of the FAT
RootDirEntries		dw 224		; Number of entries in root dir
					; (224 * 32 = 7168 = 14 sectors to read)
LogicalSectors		dw 2880		; Number of logical sectors
MediumByte		db 0F0h		; Medium descriptor byte
SectorsPerFat		dw 9		; Sectors per FAT
SectorsPerTrack		dw 18		; Sectors per track (36/cylinder)
Sides			dw 2		; Number of sides/heads
HiddenSectors		dd 0		; Number of hidden sectors
LargeSectors		dd 0		; Number of LBA sectors
DriveNo			dw 0		; Drive No: 0
Signature		db 41		; Drive signature: 41 for floppy
VolumeID		dd 00000000h	; Volume ID: any number
VolumeLabel		db "FIND       "; Volume Label: any 11 chars
FileSystem		db "FAT12   "	; File system type: don't change!


; ------------------------------------------------------------------
; Main bootloader code

bootloader_start:
	mov ax, 07C0h			; Set up 4K of stack space above buffer
	add ax, 544			; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
	cli				; Disable interrupts while changing stack
	mov ss, ax
	mov sp, 4096
	sti				; Restore interrupts

	mov ax, 07C0h			; Set data segment to where we're loaded
	mov ds, ax

	; NOTE: A few early BIOSes are reported to improperly set DL

	mov byte [bootdev], dl		; Save boot device number

	mov eax, 0			; Needed for some older BIOSes
	mov si, bstr
	call print_string

; First, we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33

floppy_ok:				; Ready to read first block of data
	mov ax, 19			; Root dir starts at logical sector 19
	call l2hts

	mov si, buffer			; Set ES:BX to point to our buffer (see end of code)
	mov bx, ds
	mov es, bx
	mov bx, si

	mov ah, 2			; Params for int 13h: read floppy sectors
	mov al, 14			; And read 14 of them

	pusha				; Prepare to enter loop


read_root_dir:
	popa				; In case registers are altered by int 13h
	pusha

	stc				; A few BIOSes do not set properly on error
	int 13h				; Read sectors using BIOS

	jnc search_dir			; If read went OK, skip ahead
	call reset_floppy		; Otherwise, reset floppy controller and try again
	jnc read_root_dir		; Floppy reset OK?

	jmp reboot			; If not, fatal double error


search_dir:
	popa

	mov ax, ds			; Root dir is now in [buffer]
	mov es, ax			; Set DI to this info
	mov di, buffer

	mov cx, word [RootDirEntries]	; Search all (224) entries
	mov ax, 0			; Searching at offset 0


next_root_entry:
	xchg cx, dx			; We use CX in the inner loop...

	mov si, kern_filename		; Start searching for kernel filename
	mov cx, 11
	rep cmpsb
	je found_file_to_load		; Pointer DI will be at offset 11

	add ax, 32			; Bump searched entries by 1 (32 bytes per entry)

	mov di, buffer			; Point to next entry
	add di, ax

	xchg dx, cx			; Get the original CX back
	loop next_root_entry

	mov si, file_not_found		; If kernel is not found, bail out
	call print_string
	jmp reboot


found_file_to_load:			; Fetch cluster and load FAT into RAM
	mov ax, word [es:di+0Fh]	; Offset 11 + 15 = 26, contains 1st cluster
	mov word [cluster], ax

	mov ax, 1			; Sector 1 = first sector of first FAT
	call l2hts

	mov di, buffer			; ES:BX points to our buffer
	mov bx, di

	mov ah, 2			; int 13h params: read (FAT) sectors
	mov al, 9			; All 9 sectors of 1st FAT

	pusha				; Prepare to enter loop


read_fat:
	popa				; In case registers are altered by int 13h
	pusha

	stc
	int 13h				; Read sectors using the BIOS

	jnc read_fat_ok			; If read went OK, skip ahead
	call reset_floppy		; Otherwise, reset floppy controller and try again
	jnc read_fat			; Floppy reset OK?

	mov si, disk_error		; If not, print error message and reboot
	call print_string
	jmp reboot			; Fatal double error


read_fat_ok:
	popa

	mov ax, 2000h			; Segment where we'll load the kernel
	mov es, ax
	mov bx, 0

	mov ah, 2			; int 13h floppy read params
	mov al, 1

	push ax				; Save in case we (or int calls) lose it


; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
;               = (cluster number) + 31

load_file_sector:
	mov ax, word [cluster]		; Convert sector to logical
	add ax, 31

	call l2hts			; Make appropriate params for int 13h

	mov ax, 2000h			; Set buffer past what we've already read
	mov es, ax
	mov bx, word [pointer]

	pop ax				; Save in case we (or int calls) lose it
	push ax

	stc
	int 13h

	jnc calculate_next_cluster	; If there's no error...

	call reset_floppy		; Otherwise, reset floppy and retry
	jmp load_file_sector


	; In the FAT, cluster values are stored in 12 bits, so we have to
	; do a bit of maths to work out whether we're dealing with a byte
	; and 4 bits of the next byte -- or the last 4 bits of one byte
	; and then the subsequent byte!

calculate_next_cluster:
	mov ax, [cluster]
	mov dx, 0
	mov bx, 3
	mul bx
	mov bx, 2
	div bx				; DX = [cluster] mod 2
	mov si, buffer
	add si, ax			; AX = word in FAT for the 12 bit entry
	mov ax, word [ds:si]

	or dx, dx			; If DX = 0 [cluster] is even; if DX = 1 then it's odd

	jz even				; If [cluster] is even, drop last 4 bits of word
					; with next cluster; if odd, drop first 4 bits

odd:
	shr ax, 4			; Shift out first 4 bits (they belong to another entry)
	jmp short next_cluster_cont


even:
	and ax, 0FFFh			; Mask out final 4 bits


next_cluster_cont:
	mov word [cluster], ax		; Store cluster

	cmp ax, 0FF8h			; FF8h = end of file marker in FAT12
	jae end

	add word [pointer], 512		; Increase buffer pointer 1 sector length
	jmp load_file_sector


end:					; We've got the file to load!
	pop ax				; Clean up the stack (AX was pushed earlier)
	mov dl, byte [bootdev]		; Provide kernel with boot device info

	jmp 2000h:0000h			; Jump to entry point of loaded kernel!


; ------------------------------------------------------------------
; BOOTLOADER SUBROUTINES

reboot:
	mov ah, 00h
	int 16h
	int 19h
	cli	;Clear interrupts to stop triplefault if int 19h failed
	hlt	;Halt the CPU

print_string:				; Output string in SI to screen
	pusha

	mov ah, 0Eh			; int 10h teletype function

.repeat:
	lodsb				; Get char from string
	cmp al, 0
	je .done			; If char is zero, end of string
	int 10h				; Otherwise, print it
	jmp short .repeat

.done:
	popa
	ret


reset_floppy:		; IN: [bootdev] = boot device; OUT: carry set on error
	push ax
	push dx
	mov ax, 0
	mov dl, byte [bootdev]
	stc
	int 13h
	pop dx
	pop ax
	ret


l2hts:			; Calculate head, track and sector settings for int 13h
			; IN: logical sector in AX, OUT: correct registers for int 13h
	push bx
	push ax

	mov bx, ax			; Save logical sector

	mov dx, 0			; First the sector
	div word [SectorsPerTrack]
	add dl, 01h			; Physical sectors start at 1
	mov cl, dl			; Sectors belong in CL for int 13h
	mov ax, bx

	mov dx, 0			; Now calculate the head
	div word [SectorsPerTrack]
	mov dx, 0
	div word [Sides]
	mov dh, dl			; Head/side
	mov ch, al			; Track

	pop ax
	pop bx

	mov dl, byte [bootdev]		; Set correct device

	ret


; ------------------------------------------------------------------
; STRINGS AND VARIABLES

	kern_filename	db "KERNEL  BIN"	; Kernel filename
	bstr		db "Hello from FIND's loader :)", 0
	disk_error	db "Floppy error! Press any key...", 0
	file_not_found	db "FIND can't find kernel!", 0
	

	bootdev		db 0 	; Boot device number
	cluster		dw 0 	; Cluster of the file we want to load
	pointer		dw 0 	; Pointer into Buffer, for loading kernel


; ------------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START

	times 510-($-$$) db 0	; Pad remainder of boot sector with zeros
	dw 0AA55h		; Boot signature (DO NOT CHANGE!)


buffer:				; Disk buffer begins (8k after this, stack starts)


; ==================================================================


Re: Print being screwy (Real mode assembler)

Posted: Fri Jan 13, 2012 1:53 pm
by djmauretto
Try This:

Code: Select all

;All this does is reads and execs the kernel of
;FIND
;(c) 2011 Ben Jackson


   jmp 	short bootloader_start   	; Jump past disk description section
   nop            			; Pad out before disk description


; ------------------------------------------------------------------
; Disk description table, to make it a valid floppy
; Values for 3.5inch 1440KB floppy

OEMLabel      		db "FINDBOOT"   ; Disk label
BytesPerSector      	dw 512      	; Bytes per sector
SectorsPerCluster   	db 1      	; Sectors per cluster
ReservedForBoot      	dw 1      	; Reserved sectors for boot record
NumberOfFats      	db 2      	; Number of copies of the FAT
RootDirEntries      	dw 224      	; Number of entries in root dir
               				; (224 * 32 = 7168 = 14 sectors to read)
LogicalSectors      	dw 2880      	; Number of logical sectors
MediumByte      	db 0F0h      	; Medium descriptor byte
SectorsPerFat      	dw 9      	; Sectors per FAT
SectorsPerTrack      	dw 18      	; Sectors per track (36/cylinder)
Sides         		dw 2      	; Number of sides/heads
HiddenSectors      	dd 0      	; Number of hidden sectors
LargeSectors      	dd 0      	; Number of LBA sectors
DriveNo         	dw 0      	; Drive No: 0
Signature     	 	db 41      	; Drive signature: 41 for floppy
VolumeID      		dd 00000000h   	; Volume ID: any number
VolumeLabel      	db "FIND       "; Volume Label: any 11 chars
FileSystem      	db "FAT12   "   ; File system type: don't change!


; ------------------------------------------------------------------
; Main bootloader code

bootloader_start:

   	mov 	ax, 07C0h         	; Set up 4K of stack space above buffer
   	add 	ax, 544         	; 8k buffer = 512 paragraphs + 32 paragraphs (loader)
   	cli            			; Disable interrupts while changing stack
   	mov 	ss, ax			
   	mov 	sp, 4096		
   	sti            			; Restore interrupts

   	mov 	ax, 07C0h         	; Set data segment to where we're loaded
   	mov 	ds, ax

   ; NOTE: A few early BIOSes are reported to improperly set DL

  	mov 	[bootdev], dl      	; Save boot device number

   	mov 	si, bstr
   	call 	print_string

; First, we need to load the root directory from the disk. Technical details:
; Start of root = ReservedForBoot + NumberOfFats * SectorsPerFat = logical 19
; Number of root = RootDirEntries * 32 bytes/entry / 512 bytes/sector = 14
; Start of user data = (start of root) + (number of root) = logical 33

floppy_ok:            			; Ready to read first block of data

   	mov 	ax, 19         		; Root dir starts at logical sector 19
   	call 	l2hts

   	mov 	si, buffer      	; Set ES:BX to point to our buffer (see end of code)
   	mov 	bx, ds
   	mov 	es, bx
   	mov 	bx, si

   	mov 	ah, 2         		; Params for int 13h: read floppy sectors
   	mov 	al, 14         		; And read 14 of them

   	pusha            		; Prepare to enter loop


read_root_dir:

   	popa            		; In case registers are altered by int 13h
   	pusha

   	stc            			; A few BIOSes do not set properly on error
   	int 	13h            		; Read sectors using BIOS

  	jnc 	search_dir         	; If read went OK, skip ahead
   	call 	reset_floppy      	; Otherwise, reset floppy controller and try again
   	jnc 	read_root_dir      	; Floppy reset OK?

   	jmp 	reboot         		; If not, fatal double error


search_dir:

   	popa

   	mov 	ax, ds         		; Root dir is now in [buffer]
   	mov 	es, ax         		; Set DI to this info
   	mov 	di, buffer

   	mov 	cx, [RootDirEntries]   	; Search all (224) entries
   	xor 	ax, ax         		; Searching at offset 0


next_root_entry:

   	xchg 	cx, dx         		; We use CX in the inner loop...

   	mov 	si, kern_filename      	; Start searching for kernel filename
   	mov 	cx, 11
   	rep 	cmpsb
   	je 	found_file_to_load      ; Pointer DI will be at offset 11

   	add 	ax, 32         		; Bump searched entries by 1 (32 bytes per entry)

   	mov 	di, buffer         	; Point to next entry
   	add 	di, ax

   	xchg 	dx, cx         		; Get the original CX back
   	loop 	next_root_entry

   	mov 	si, file_not_found      ; If kernel is not found, bail out
   	call	print_string
   	jmp 	reboot


found_file_to_load:         		; Fetch cluster and load FAT into RAM

   	mov 	ax, word [es:di+0Fh]   	; Offset 11 + 15 = 26, contains 1st cluster
   	mov 	[cluster], ax

   	mov 	ax, 1         		; Sector 1 = first sector of first FAT
   	call 	l2hts

   	mov 	di, buffer         	; ES:BX points to our buffer
   	mov 	bx, di

   	mov 	ah, 2         		; int 13h params: read (FAT) sectors
   	mov 	al, 9         		; All 9 sectors of 1st FAT

   	pusha            		; Prepare to enter loop


read_fat:
   	
	popa            		; In case registers are altered by int 13h
   	pusha

   	stc
   	int 	13h            		; Read sectors using the BIOS

   	jnc 	read_fat_ok         	; If read went OK, skip ahead
   	call 	reset_floppy      	; Otherwise, reset floppy controller and try again
   	jnc 	read_fat         	; Floppy reset OK?

   	mov 	si, disk_error      	; If not, print error message and reboot
   	call 	print_string
   	jmp 	reboot         		; Fatal double error


read_fat_ok:

   	popa

   	mov 	ax, 2000h         	; Segment where we'll load the kernel
   	mov 	es, ax
   	xor	bx, bx

   	mov 	ah, 2         		; int 13h floppy read params
   	mov 	al, 1

   	push 	ax            		; Save in case we (or int calls) lose it


; Now we must load the FAT from the disk. Here's how we find out where it starts:
; FAT cluster 0 = media descriptor = 0F0h
; FAT cluster 1 = filler cluster = 0FFh
; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
;               = (cluster number) + 31

load_file_sector:

   	mov 	ax, [cluster]      	; Convert sector to logical
   	add 	ax, 31

   	call 	l2hts         		; Make appropriate params for int 13h

   	mov 	ax, 2000h         	; Set buffer past what we've already read
   	mov 	es, ax
   	mov 	bx, [pointer]

   	pop 	ax            		; Save in case we (or int calls) lose it
  	push 	ax

   	stc
   	int 	13h

   	jnc 	calculate_next_cluster  ; If there's no error...

   	call 	reset_floppy      	; Otherwise, reset floppy and retry
   	jmp 	load_file_sector


   ; In the FAT, cluster values are stored in 12 bits, so we have to
   ; do a bit of maths to work out whether we're dealing with a byte
   ; and 4 bits of the next byte -- or the last 4 bits of one byte
   ; and then the subsequent byte!

calculate_next_cluster:
   	
	mov 	ax, [cluster]
   	xor	dx,dx
   	mov 	bx, 3
   	mul 	bx
   	mov 	bx, 2
   	div 	bx            		; DX = [cluster] mod 2
   	mov 	si, buffer
   	add 	si, ax         		; AX = word in FAT for the 12 bit entry
   	mov 	ax, word [ds:si]

   	test 	dx, dx         		; If DX = 0 [cluster] is even; if DX = 1 then it's odd

   	jz 	even            	; If [cluster] is even, drop last 4 bits of word
               				; with next cluster; if odd, drop first 4 bits

odd:

   	shr 	ax, 4         		; Shift out first 4 bits (they belong to another entry)
   	jmp 	short next_cluster_cont


even:

   	and 	ax, 0FFFh         	; Mask out final 4 bits

next_cluster_cont:

   	mov 	[cluster], ax      	; Store cluster
   	cmp 	ax, 0FF8h         	; FF8h = end of file marker in FAT12
   	jae 	.end

   	add 	[pointer], 512      	; Increase buffer pointer 1 sector length
   	jmp 	load_file_sector


.end:               			; We've got the file to load!
   	pop 	ax            		; Clean up the stack (AX was pushed earlier)
   	mov 	dl, [bootdev]      	; Provide kernel with boot device info

   	jmp 	2000h:0000h         	; Jump to entry point of loaded kernel!


; ------------------------------------------------------------------
; BOOTLOADER SUBROUTINES

reboot:
   	xor	ax,ax
   	int 	16h
   	int 	19h
   	cli   				; Clear interrupts to stop triplefault if int 19h failed
@@:
	hlt   				; Halt the CPU
	jmp	@b

print_string:            		; Output string in SI to screen

   	pusha

.repeat:

   	lodsb            		; Get char from string
   	test 	al, al
   	je 	.done         		; If char is zero, end of string
	mov	bx,7
   	mov 	ah, 0Eh         	; int 10h teletype function
   	int 	10h            		; Otherwise, print it
   	jmp 	short .repeat

.done:

   	popa
   	ret


reset_floppy:      			; IN: [bootdev] = boot device; OUT: carry set on error
   
	push 	ax
   	push 	dx
   	xor	ax, ax
   	mov 	dl, [bootdev]
   	stc
   	int 	13h
   	pop 	dx
   	pop 	ax
   	ret


l2hts:         					; Calculate head, track and sector settings for int 13h
         					; IN: logical sector in AX, OUT: correct registers for int 13h
   	push 	bx
   	push 	ax

   	mov 	bx, ax         			; Save logical sector

   	mov 	dx, 0         			; First the sector
   	div 	[SectorsPerTrack]
   	add 	dl, 01h         		; Physical sectors start at 1
   	mov 	cl, dl        			; Sectors belong in CL for int 13h
   	mov 	ax, bx

   	mov 	dx, 0         			; Now calculate the head
   	div 	[SectorsPerTrack]
   	mov 	dx, 0
   	div 	[Sides]
  	mov 	dh, dl         			; Head/side
   	mov 	ch, al         			; Track

  	pop 	ax
   	pop 	bx

   	mov 	dl,[bootdev]      		; Set correct device

   	ret


; ------------------------------------------------------------------
; STRINGS AND VARIABLES

   kern_filename   	db "KERNEL  BIN"   ; Kernel filename
   bstr      		db "Hello from FIND's loader :)",13,10, 0
   disk_error   	db "Floppy error! Press any key...",13,10, 0
   file_not_found   	db "FIND can't find kernel!",13,10, 0
   

   bootdev      	db 0    		; Boot device number
   cluster      	dw 0    		; Cluster of the file we want to load
   pointer      	dw 0    		; Pointer into Buffer, for loading kernel


; ------------------------------------------------------------------
; END OF BOOT SECTOR AND BUFFER START

   times 510-($-$$) 	db 0    		; Pad remainder of boot sector with zeros
   dw 0AA55h      				; Boot signature (DO NOT CHANGE!)


buffer:            				; Disk buffer begins (8k after this, stack starts)


; ==================================================================

Re: Print being screwy (Real mode assembler)

Posted: Fri Jan 13, 2012 3:44 pm
by Unkn0wn1
Finally got newlines, hacked in real mode ASM barebones print to my kernel,as it's more efficient than my current one. Newlines may work now, but it still prints some really screwy messages in the kernel, gonna debug it tommorrow probably, too tired now. Will try new loader shortly though

It's gotta be a bug in loading the kernel, I've worked out. All the printing works fine in the loader, then dies in the kernel -- for 'Hello!' it prints ð ß
Oh, and NASM doesn't like the edits - more debugging for me, yay!

Re: Print being screwy (Real mode assembler)

Posted: Sat Jan 14, 2012 2:09 am
by Unkn0wn1
Just tried the MikeOS loader, same problem...

I wonder why it works for their kernel but not mine :evil:
EDIT: I have no ORG in the kernel nor setting up for it.
is that the problem?

EDIT2: Got it! It WAS an ORG problem after all that!
well, time to get to work on the kernel!
Yay, I have strcmp and getting input done. Command lines FTW!
Oh, and BTW the name of my project, FIND, stands for: FIND Is Not DOS :lol:

Re: Print being screwy (Real mode assembler)

Posted: Sat Jan 14, 2012 1:14 pm
by VolTeK
You do realize what org is meant to do right?


If you do not.. your going to have TONS more problems that you wont be able to understand very, very soon.

Re: Print being screwy (Real mode assembler)

Posted: Sat Jan 14, 2012 2:59 pm
by Unkn0wn1
Basically tells the program it's origin address in RAM, right? it was being screwy probably because it couldn't find the right data due to not having a clue where the data was

Re: Print being screwy (Real mode assembler)

Posted: Sat Jan 14, 2012 3:18 pm
by VolTeK
Edit: Wrong forum, wrong thread #-o

Re: Print being screwy (Real mode assembler)

Posted: Sat Jan 14, 2012 3:21 pm
by Unkn0wn1
Qemu? :( I use Bochs myself...
Anyway, the problem's sorted now

@XOP's edit: 'Oops' :)