int13h read question

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

int13h read question

Post by Khronos »

Hello, I´m writting my own bootloader and I have a question.

Code: Select all

[bits 16]
[ORG 0]

jmp short start
nop	; No Operation (1 byte)

OEMLabel:							db "KERNEL  "		; 8 characters padded with spaces
BytesPerSector:  					dw 512				; Bytes per sector
SectorsPerCluster: 					db 1				; Sectors per cluster
ReservedSectors: 					dw 1				; Reserved Sectors (for sector 0)
NumberOfFATs: 						db 2				; Number of FAT´s
MaxRootEntries: 					dw 224				; Number of Root Entries

NumberOfSectors: 					dw 2880				; Number of sectors
DeviceDescriptor: 					db 0xF0				; Device Descriptor 0xF0 => 1.44 MB floppy image
SectorsPerFAT: 						dw 9				; Sectors Per FAT
SectorsPerTrack: 					dw 18				; Sectors Per Track
Sides: 								dw 2				; Sides of disk
HiddenSectors: 						dd 0				; Number of Hidden Sectors
LengthOfSectors:					dd 0				; Length of sectors
DriveNo: 							db 0				; Drive Number (0 or 1)
Flags: 								db 0				; Additional flags
Signature: 							db 0x14				; Signature, some number of 1 byte
VolumeID:							dd 0xAABBCCDD		; Volume ID
VolumeLabel: 						db "DISCO TANIS "	; 11 characters padded with spaces
FileSystem: 						db "FAT12   "		; 8 characters padded with spaces

;**********************************************************;
; Entry Point
; Reset the floppy disk.
; Calculate the root directory CHS address and jump to 
; read_root_directory.
;**********************************************************;
start:
	jmp 07C0h:stage_1

stage_1:
	mov ax, cs
	mov ds, ax
	mov es, ax

	mov si, StringMsg
	call print_string

	xor ah, ah ; Ah = 0, reset function
	mov dl, BYTE [DriveNo]
	int 13h ; Reset Floppy Disk

	xor ax, ax

	add ax, WORD [SectorsPerFAT]
	mul BYTE [NumberOfFATs]
	add ax, WORD [ReservedSectors]
	; AX = (SectorsPerFAT * NumberOfFATs) + ReservedSectors

	call lba2chs

	jmp short read_root_directory

read_root_directory:
	; We have already calculated the CH = Cilynder, CL = sector and
	; DH = Head.
	mov ax, 1000h
	mov es, ax
	mov bx, 0

	mov ah, 02h	; Read mode
	mov al, 0Fh ; Sectors to read (512 bytes each sector)
	mov dl, BYTE [DriveNo]
	
	int 13h ;Call the interruption!
	jc .root_dir_read_error

	mov si, [1000h]
	mov dx, 512
	call print_n

        ...
My print_n function:

Code: Select all

;**********************************************************;
; Print a string in screen
; SI => String pointer
; DX => Number of characters to print
;**********************************************************;
print_n:
	push ax
	push bx
	push cx

	mov ah, 0Eh

	xor cx, cx

	.loop:
	mov al, [si]
	int 10h
	inc cx
	cmp cx, dx
	je short .end_loop
	
	inc si
	jmp short .loop

	.end_loop:
	pop ax
	pop bx
	pop cx
	ret
My question is at this pointer:

Code: Select all

mov si, [1000h]
mov dx, 512
call print_n
How can I access to the memory read by the int 13h?

Sorry for my poor English.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: int13h read question

Post by bluemoon »

Khronos wrote:How can I access to the memory read by the int 13h?
You provide the buffer for INT13, and you read(or process) the memory by mov, jumps,call, or any operation like add.
Which part do you have no idea?
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

Re: int13h read question

Post by Khronos »

Hi bluemoon, thanks for your answer. When I do this

Code: Select all

mov si, [1000h]
mov dx, 512
call print_n
The function prints the stage1 memory block, not the root directory. I have problems with bx, es:ds parameter to int13h. Can someone put an example clode?
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: int13h read question

Post by bluemoon »

BIOS INT13 read logical sectors, it do not interpret any file system, *you* have to do it.
Basically you take the values from the superblock (BPB), calculate the relative sector index (IIRC, for FAT16 root dir = volume start + reserved sector count + (FAT_size * number of FAT), for FAT32 the root directory location is pointed by extended BPB fields)
Check the wiki (BOTH osdev and the wikipedia) for detail.
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

Re: int13h read question

Post by Khronos »

Yes, I know It, but my problem is working with the memory :(
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: int13h read question

Post by bluemoon »

Sound like a seriously difficult problem. But have you tried:

Code: Select all

struc BPB                 ; BIOS Paramater Block (At Boot Record)
                resb  3   ; JMP
    BPB_name    resb  8   ; Volume OEM Name eg. "mkdosfs"
    BPB_bps     resw  1   ; Bytes per Sector
    BPB_spc     resb  1   ; Sectors per Cluster
    BPB_res     resw  1   ; Reserved sector before 1st FAT
    BPB_nfat    resb  1   ; number of FATs
    BPB_maxroot resw  1   ; max number of root entry
    BPB_total1  resw  1   ; total sectors, if 0 use total2
    BPB_media   resb  1   ; media descriptor, F8 for HDD
    BPB_spf     resw  1   ; sectors per FAT
    BPB_spt     resw  1   ; sectors per track (63)
    BPB_head    resw  1   ; num of head
    BPB_lba     resd  1   ; starting sector of this vol
    BPB_total2  resd  1   ; total sectors if total1 == 0
endstruc

; assume CS/DS/ES are zero with traditional practice
  mov si, buffer
  mov eax, [si + BPB_lba]
  movzx   ebx, word [si + BPB_res]       ; bx = sectors for [reserved]
...
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

Re: int13h read question

Post by Khronos »

How do you define "buffer" in your code?
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: int13h read question

Post by Combuster »

Does it matter? Where did you load your stuff to?
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
azblue
Member
Member
Posts: 147
Joined: Sat Feb 27, 2010 8:55 pm

Re: int13h read question

Post by azblue »

you're loading the sector here:

Code: Select all

	mov ax, 1000h
	mov es, ax
	mov bx, 0
And trying to read it here:

Code: Select all

	mov si, [1000h]
	mov dx, 512
	call print_n

        ...


You're loading the sector to 1000:0000 (logical address 10000h)

Then you're trying to read from 7c0:1000 (logical address 8c00h)

You're reading from somewhere totally different from where you loading the sector.
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

Re: int13h read question

Post by Khronos »

I understand, thank you. Then, how can I change my address position?

The 16-bit assembler is new for me :oops:
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: int13h read question

Post by bluemoon »

This is not a good idea to learn assembly and os development at once.
Nable
Member
Member
Posts: 453
Joined: Tue Nov 08, 2011 11:35 am

Re: int13h read question

Post by Nable »

dougal
Posts: 1
Joined: Sun Jul 22, 2012 2:42 pm

Re: int13h read question

Post by dougal »

Khronos wrote:I understand, thank you. Then, how can I change my address position?

The 16-bit assembler is new for me :oops:
azblue is correct, try this:

Code: Select all

[bits 16]
[ORG 0]

jmp short start
nop   ; No Operation (1 byte)

OEMLabel:                     db "KERNEL  "      ; 8 characters padded with spaces
BytesPerSector:                 dw 512            ; Bytes per sector
SectorsPerCluster:                db 1            ; Sectors per cluster
ReservedSectors:                dw 1            ; Reserved Sectors (for sector 0)
NumberOfFATs:                   db 2            ; Number of FAT´s
MaxRootEntries:                dw 224            ; Number of Root Entries

NumberOfSectors:                dw 2880            ; Number of sectors
DeviceDescriptor:                db 0xF0            ; Device Descriptor 0xF0 => 1.44 MB floppy image
SectorsPerFAT:                   dw 9            ; Sectors Per FAT
SectorsPerTrack:                dw 18            ; Sectors Per Track
Sides:                         dw 2            ; Sides of disk
HiddenSectors:                   dd 0            ; Number of Hidden Sectors
LengthOfSectors:               dd 0            ; Length of sectors
DriveNo:                      db 0            ; Drive Number (0 or 1)
Flags:                         db 0            ; Additional flags
Signature:                      db 0x14            ; Signature, some number of 1 byte
VolumeID:                     dd 0xAABBCCDD      ; Volume ID
VolumeLabel:                   db "DISCO TANIS "   ; 11 characters padded with spaces
FileSystem:                   db "FAT12   "      ; 8 characters padded with spaces

;**********************************************************;
; Entry Point
; Reset the floppy disk.
; Calculate the root directory CHS address and jump to 
; read_root_directory.
;**********************************************************;
start:
   jmp 07C0h:stage_1

stage_1:
   mov ax, cs
   mov ds, ax
   mov es, ax

   mov si, StringMsg
   call print_string

   xor ah, ah ; Ah = 0, reset function
   mov dl, BYTE [DriveNo]
   int 13h ; Reset Floppy Disk

   xor ax, ax

   add ax, WORD [SectorsPerFAT]
   mul BYTE [NumberOfFATs]
   add ax, WORD [ReservedSectors]
   ; AX = (SectorsPerFAT * NumberOfFATs) + ReservedSectors

   call lba2chs

   jmp short read_root_directory

read_root_directory:
   ; We have already calculated the CH = Cilynder, CL = sector and
   ; DH = Head.
   mov bx, 1000h  ; I removed the modification of ES, assuming that you want to load the root directory at 7c0h:1000h, which is where you attempt to read it

   mov ah, 02h   ; Read mode
   mov al, 0Fh ; Sectors to read (512 bytes each sector)
   mov dl, BYTE [DriveNo]
   
   int 13h ;Call the interruption!
   jc .root_dir_read_error

   mov si, 1000h     ;Notice that I removed the brackets around 1000h
   mov dx, 512
   call print_n
Khronos wrote:

Code: Select all

mov si, [1000h]
mov dx, 512
call print_n
The function prints the stage1 memory block, not the root directory. I have problems with bx, es:ds parameter to int13h. Can someone put an example clode?
Take the brackets off of the 1000h. They imply to your assembler that you want to move a word from DS:1000h (07c0h:1000h @ this point) into SI, and since that part of memory is most probably uninitialised by your OS, you are loading 0000h into SI, which explains why your code was printing the stage1 memory block, because it was printing from 07c0h:0000h, where your bootsector is loaded, not 07c0h:1000.
Khronos
Posts: 23
Joined: Sat Jul 21, 2012 5:29 am

Re: int13h read question

Post by Khronos »

Well, after hours and hours of hard programming I have finished my Stage_1 bootloader. Thanks for all the advices and help.

This is the final stage_1 nasm source:

Code: Select all

; Developed by Khronos

[bits 16] ; Real mode

[ORG 0] ; Origin address

jmp short start ; 2 bytes
nop ; No Operation (1 byte)

OEMLabel:							db "KERNEL  "		; 8 characters padded with spaces
BytesPerSector:  					dw 512				; Bytes per sector
SectorsPerCluster: 					db 1				; Sectors per cluster
ReservedSectors: 					dw 1				; Reserved Sectors (for sector 0)
NumberOfFATs: 						db 2				; Number of FAT´s
MaxRootEntries: 					dw 224				; Number of Root Entries

NumberOfSectors: 					dw 2880				; Number of sectors
DeviceDescriptor: 					db 0xF0				; Device Descriptor 0xF0 => 1.44 MB floppy image
SectorsPerFAT: 						dw 9				; Sectors Per FAT
SectorsPerTrack: 					dw 18				; Sectors Per Track
Sides: 								dw 2				; Sides of disk
HiddenSectors: 						dd 0				; Number of Hidden Sectors
LengthOfSectors:					dd 0				; Length of sectors
DriveNo: 							db 0				; Drive Number (0 or 1)
Flags: 								db 0				; Additional flags
Signature: 							db 0x14				; Signature, some number of 1 byte
VolumeID:							dd 0xAABBCCDD		; Volume ID
VolumeLabel: 						db "DISCO TANIS "	; 11 characters padded with spaces
FileSystem: 						db "FAT12   "		; 8 characters padded with spaces


start:
	jmp 07C0h:stage_1 ; CS = 07C0h

;*******************************************************************
;* STAGE 1
;*******************************************************************
stage_1:
	mov ax, cs
	mov es, ax ; ES = 07C0h
	mov ds, ax ; DS = 07C0h

	mov si, BootMsg
	call print_string ; Print Boot Message

	xor ah, ah ; Ah = 0, reset function
	xor dl, dl ; DL = 0, Drive number 0
	int 13h ; Reset Floppy Disk

	jnc short read_root_directory ; If no errors, jump read_root_directory

	jmp reboot ; else, reboot!


; Root Directory starts at LBA 19 with
; 15 sectors of size
read_root_directory:
	mov ax, 1000h
    mov es, ax ; ES = 1000h

	;Vamos a leer el sector número 1
	mov ax, 19 ; 19 = Root Directory
	call lba2chs ; LBA to CHS

	mov ah, 02h ; Read function
	mov al, 0Fh ; Sectors to read
	xor bx, bx ; ES:BX = 1000h:0000
	xor dl, dl ; DL = 0, Drive 0

	int 13h ;Read!

	jnc short find_file ; If no errors, jump find_file

	jmp reboot ; else, reboot!

find_file:
	mov ax, 1000h
	mov ds, ax ; DS = 1000h
	
	mov bx, 4640 ; bx = (0Fh * 512) + 32
	mov cx, -32
	.loop:
		mov dl, 1 ; DL = FALSE

		sub bx, 32 ; BX - 32
		or bx, bx
		jz .endloop ; If BX = 0 then, jump .endloop

		add cx, 32 ; CX += 32
		mov si, cx

		lodsb ; mov al, [SI]; inc si
		cmp al, 'S'
		jne short .loop

		lodsb
		cmp al, 'T'
		jne short .loop

		lodsb
		cmp al, 'A'
		jne short .loop

		lodsb
		cmp al, 'G'
		jne short .loop

		lodsb
		cmp al, 'E'
		jne short .loop

		lodsb
		cmp al, '_'
		jne short .loop

		lodsb
		cmp al, '2'
		jne short .loop

		lodsb
		cmp al, ' '
		jne short .loop

		lodsb
		cmp al, 'B'
		jne short .loop

		lodsb
		cmp al, 'I'
		jne short .loop

		lodsb
		cmp al, 'N'
		jne short .loop

		xor dl, dl ; DL = TRUE
		add si, 0Fh ; SI current Pos + 15
		mov cx, [si] ; Get the Starting Cluster

	.endloop:

	or dl, dl
	jz short read_fat ; If DL = TRUE then, jump read_fat

	jmp reboot ; else, reboot!

read_fat:
	; We will overwrite the Root Directory with the FAT
	mov ax, 1000h
	mov es, ax ; ES = 1000h

	mov ax, 1 ; LBA = 1
	push cx ; We save the Starting Cluster

	call lba2chs

	mov ah, 02h ; Function 02h: Read
	mov al, 9 ; Sectors to read = SectorsPerFAT
	xor dl, dl ; Drive = 0
	xor bx, bx ; 1000h:0000

	int 13h

	jnc short read_data ; if no errors, then jump read_data

	jmp reboot ; else, reboot!

read_data:
	; FAT cluster 0 = media descriptor = 0F0h
	; FAT cluster 1 = file cluster = 0FFh
	; Cluster start = ((cluster number) - 2) * SectorsPerCluster + (start of user)
	;               = (cluster number) + 31

	pop cx ; Restore the Starting Cluster

	xor bx, bx ; BX = 0
	push bx ; Push!

	mov bx, 3000h
	mov es, bx ; ES:BX = 3000h:0000
	; Segment where we will load the stage_2
	.loop:
		mov si, 0000h ; SI Pointer to 1000h:0000

		mov ax, cx ; AX = CX
		mov bx, 2 ; BX = 2
		div bl ; AH = AX MOD BL

		or ah, ah
		jz short .par ; If remainder = 0 then, jump .par
		.impar:	; d = (n - 1 / 2) * 3 + 1
			mov ax, cx ; AX = CX
			dec ax
			shr ax, 1
			mov bx, 3 ; BX = 3
			mul bx ; AX * 3
			inc ax

			add si, ax ; SI + AX
			mov dx, [si] ; We get the 16 bits of FAT, but we only need 12 bits

			shr dx, 4 ; DX >> 4
			jmp short .next

		.par: ; d = (n / 2) * 3
			mov ax, cx ; AX = CX
			shr ax, 1
			mov bx, 3 ; BX = 3
			mul bx ; AX * 3		

			add si, ax ; SI + AX
			mov dx, [si] ; We get the 16 bits of FAT, but we only need 12 bits
				
			and dx, 0x0FFF ; DX AND 0FFFh
		.next:
					
			mov ax, 31 ; AX = 31
			add ax, cx ; AX = AX + CX (Starting or next cluster)
	
			pop bx ; Restore BX
			
			push dx ; Save next cluster
			call lba2chs
			mov ah, 02h ; Read function
			mov al, 1 ; 1 sector to read
			xor dl, dl ; Drive = 0

			int 13h	

			pop dx ; Restore next cluster	

			cmp dx, 0x0FF8 ; Compare Next Cluster with 0x0FF8
			jae short execute ; if dx >= 0x0FFF8 then, jump execute

			add bx, 512 ; BX = BX + 512
			push bx ; Save BX
			
			mov cx, dx
			jmp short .loop

execute:
	jmp 3000h:0000



;**********************************************************;
; Print a string in screen
; SI => String pointer with NULL terminator
;**********************************************************;
print_string:
	pusha
	mov ah, 0Eh

	.loop:
	mov al, [si]
	or al, al
	jz short .end_loop
	int 10h
	inc si
	jmp short .loop

	.end_loop:

	mov al, 13
	int 10h
	mov al, 10
	int 10h

	popa
	ret

;**********************************************************;
; Convert LBA address to CHS address
; AX => LBA address
;
; CH <= Cylinder
; DH <= Head
; CL <= Sector
;**********************************************************;
lba2chs:
	push bx ; Push bx
	mov bx, ax ; Copy LBA in BX
	
	;AX has the LBA value
	mov dl, 18 ; BL = Sectors Per Track
	div dl
	xchg ax, bx
	;BL = Temp = LBA / (Sectors Per Track)
	;BH = LBA % (Sectors Per Track)
	mov cl, bh
	inc cl ; CL = Sector = [LBA % (Sectors Per Track)] + 1

	xor ax, ax ; AX = 0
	mov al, bl ; AL = Temp = LBA / (Sectors Per Track)
	mov dx, 2 
	div dl
	;AL = LBA / (Number of Heads)
	;AH = LBA % (Number of Heads)
	mov dh, ah ; Head
	mov ch, al ; Cylinder

	pop bx
	ret


;**********************************************************;
; Print a error message, then wait for a keypress and reboot
;**********************************************************;
reboot:
	mov ax, 07C0h
	mov ds, ax ; DS = 07C0h

	mov si, Error
	call print_string

	mov si, Reboot
	call print_string

	mov ax, 0
	int 16h				; Wait for keystroke
	mov ax, 0
	int 19h				; Reboot the system


;**********************************************************;
; Variables
;**********************************************************;
BootMsg:								db "Loading...", 0

Error:									db "Missing or corrupt STAGE_2.BIN!", 0
Reboot:									db "Press any key to reboot...", 0


;**********************************************************;
; EOF
;**********************************************************;

times 510-($-$$) db 0 ; Fill with zero´s
dw 0xAA55 ; Bootloader signature
The stage_2 source:

Code: Select all

;*******************************************************************
;* STAGE 2
;*******************************************************************

[bits 16]
[ORG 0]

stage2:
	mov ax, 3000h	
	mov ds, ax
	mov es, ax			
	mov fs, ax			
	mov gs, ax

	mov si, HelloString
	call print_string2
	jmp test
	

print_string2:
	pusha
	mov ah, 0Eh

	.loop:
	mov al, [si]
	or al, al
	jz short .end_loop
	int 10h
	inc si
	jmp short .loop

	.end_loop:

	mov al, 13
	int 10h
	mov al, 10
	int 10h

	popa
	ret

times 512 db 'A'
times 512 db 'B'

test:
	mov si, TestString
	call print_string2
	jmp $

times 512 db 'C'
times 2048 db 'D'

HelloString:							db "Hello from Stage_2!", 0
TestString:								db "This is a test", 0
Now, I will be activate large mode and begin the C kernel.

Please post the errors of my code or other advices. Thanks.
Post Reply