issue with int 0x13

Programming, for all ages and all languages.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: issue with int 0x13

Post by BenLunt »

Armature wrote:I've already loaded both the FAT and root Directory into a memory location. I'm not searching for that. I'm searching for a file that's on the disk. As for the value I was getting from the root directory, I said I think I'm getting the wrong one. I think its meant to be 0x001A which would be sector 26
You may be correct, however, my point is, with a starting cluster value of 0x1A00 (6656d), it is irrelevant whether your LBA to CHS code, or your read sector code is correct or not. I would start finding out why I found a cluster number of 6656 to begin with.

- Am I reading the root directory correctly?
- Am I reading from the correct root entry?
- Am I reading from the correct offset within that entry?

Once I have figured out that I have TRUE for all three questions, why am I still getting a cluster number of 6656? If any of those questions are FALSE, then I have found the issue.

I have created a tool to view disk images to help in my development. If you have a 1.44Meg disk image, using a similar tool, you can view the image's boot sector, fat, root, file data area, etc. Doing so will eliminate the possibility of a faulty file system.

Once I have figured out that the file system (image file) is correct, the FAT(s) are correct, and the root directory is valid, I can then move on to finding out why I am reading from the wrong place. For example, once I have a valid starting cluster number (in your case it might be 1Ah (26d)), I can then read from sector (1 + 9 + 9 + 14 + 26 - 2) to get the first sector (cluster) of the file, assuming I have a 1:1 ratio of clusters to sectors. Dump this sector to the screen to see if it matches the sector on the image file (disk).

Ben
- http://www.fysnet.net/osdesign_book_series.htm
Armature
Member
Member
Posts: 33
Joined: Wed Apr 25, 2018 2:44 pm
Libera.chat IRC: idk

Re: issue with int 0x13

Post by Armature »

BenLunt wrote:
Armature wrote:I've already loaded both the FAT and root Directory into a memory location. I'm not searching for that. I'm searching for a file that's on the disk. As for the value I was getting from the root directory, I said I think I'm getting the wrong one. I think its meant to be 0x001A which would be sector 26
You may be correct, however, my point is, with a starting cluster value of 0x1A00 (6656d), it is irrelevant whether your LBA to CHS code, or your read sector code is correct or not. I would start finding out why I found a cluster number of 6656 to begin with.

- Am I reading the root directory correctly?
- Am I reading from the correct root entry?
- Am I reading from the correct offset within that entry?

Once I have figured out that I have TRUE for all three questions, why am I still getting a cluster number of 6656? If any of those questions are FALSE, then I have found the issue.

I have created a tool to view disk images to help in my development. If you have a 1.44Meg disk image, using a similar tool, you can view the image's boot sector, fat, root, file data area, etc. Doing so will eliminate the possibility of a faulty file system.

Once I have figured out that the file system (image file) is correct, the FAT(s) are correct, and the root directory is valid, I can then move on to finding out why I am reading from the wrong place. For example, once I have a valid starting cluster number (in your case it might be 1Ah (26d)), I can then read from sector (1 + 9 + 9 + 14 + 26 - 2) to get the first sector (cluster) of the file, assuming I have a 1:1 ratio of clusters to sectors. Dump this sector to the screen to see if it matches the sector on the image file (disk).

Ben
- http://www.fysnet.net/osdesign_book_series.htm
That program was incredibly useful. It's shown me that the first cluster is actually 0x000F. Which means im getting the completely wrong byte from somewhere but i dont know where now. I tried using a program called sectedit to look at the 512 bytes within the sectors on the disk but i cant open an image, only physical disks. Do you guys know any programs that are able to do that? I'n the mean time I'm going to scower through all my lines of code and follow the logic to see if i've gone wrong somewhere.
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: issue with int 0x13

Post by BenLunt »

Armature wrote:That program was incredibly useful. It's shown me that the first cluster is actually 0x000F. Which means im getting the completely wrong byte from somewhere but i dont know where now. I tried using a program called sectedit to look at the 512 bytes within the sectors on the disk but i cant open an image, only physical disks. Do you guys know any programs that are able to do that? I'n the mean time I'm going to scower through all my lines of code and follow the logic to see if i've gone wrong somewhere.
Another tool that should be in your tool box. Have a look at my dump tool. It allows you to dump any part, given a byte offset, or any sector, giving a sector offset, to multiple output forms. It even has a little bit of error checking on the dump data. It is a tool I add to when I need a new feature or need to parse the data a little different. (I haven't worked on that tool in a while. I think it is still a 32-bit Windows executable, but should still work just fine on later machines)

Ben
- http://www.fysnet.net/osdesign_book_series.htm
Octocontrabass
Member
Member
Posts: 5512
Joined: Mon Mar 25, 2013 7:01 pm

Re: issue with int 0x13

Post by Octocontrabass »

Armature wrote:I tried using a program called sectedit to look at the 512 bytes within the sectors on the disk but i cant open an image, only physical disks. Do you guys know any programs that are able to do that?
I've found HxD to be quite nice. Since it's more of a general-purpose editor than a disk editor, it doesn't display sector boundaries when you're editing a disk image. I like to resize the window to show exactly 512 (0x200) bytes, so I can use page-up and page-down to scroll between sectors.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: issue with int 0x13

Post by Octacone »

Octocontrabass wrote:
Armature wrote:I tried using a program called sectedit to look at the 512 bytes within the sectors on the disk but i cant open an image, only physical disks. Do you guys know any programs that are able to do that?
I've found HxD to be quite nice. Since it's more of a general-purpose editor than a disk editor, it doesn't display sector boundaries when you're editing a disk image. I like to resize the window to show exactly 512 (0x200) bytes, so I can use page-up and page-down to scroll between sectors.
Active @ Disk Editor is simply the best!
I've been using it for years and I'm supper satisfied with it.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
iansjack
Member
Member
Posts: 4685
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: issue with int 0x13

Post by iansjack »

ghex works fine on *nix platforms to edit files, virtual disks, or physical disks.
Armature
Member
Member
Posts: 33
Joined: Wed Apr 25, 2018 2:44 pm
Libera.chat IRC: idk

Re: issue with int 0x13

Post by Armature »

Right, i know its been quite some time since I last posted here, I just started my first year on a Computer Science course at Kings and its honestly a lot more work than anticipated so my little OS project has been laying neglected for quite some time. But, i think i figured out what the issue was after looking over the code with some fresh eyes. So, first things first, I use this piece of code:

Code: Select all

FATFindEntry:			        ;0001)
	pusha				;0002) Preserver all the registers before the function
	mov si, FileName		;0003) Move the name of the file into source index for comparison
	mov bx, ROOTDIR		;0004) move the memory address into the bx register 
	mov ch, 0x0A			;0005) Counter for the letters in an entry
	mov cl, 0xE1			;0006) Counter for the number of file entries 
	push bx				;0007) Preserve the starting address of the file name
.FATFECompareString:		;0008)
	mov ah, [si]			;0009) get a byte, the first character, from the source index
	mov al, [bx]			;0010) get a byte, the first character in the root directory, from the memory address
	inc si				        ;0011) increment the source index for the next character of the file name
	inc bx				;0012) increment the memory address for the next letter u=in the root directory
	call WriteHex 		        ;0000) DEBUGGING Write the letter from the FAT to the console co i can see what byte we are on.
	push ax				;0000) DEBUGGING
	mov al, ah			        ;0000) DEBUGGING
	call WriteHex		        ;0000) DEBUGGING
	pop ax				;0000) DEBUGGING
	cmp al, ah			        ;0013) compare the two values.
	jne .FATFEWrongEntry	;0014) if they're not the same, we have the wrong entry so we jump out of the loop
	cmp ch, 0x00			;0015) check to see if we have reached the last character in the file name
	je .FATFERightEntry		;0016) if it is, we have found the file and jump out of the loop and start getting the block of the first sector
	dec ch				;0017) if not, we mark of the current letter by taking one off the counter
	jmp .FATFECompareString	;0018) then we repeat the loop that compares the filename with the entry in the root directory.
.FATFEWrongEntry:			;0019)
	cmp cl, 0x00			;0020) Check to see if we have checked all the entries in the root directory
	je .FATFEEntryNotFound	;0021) if we have, then we haven't found the entry on the disk so we jump out of the loop
	dec cl				;0022) if we haven't looked at allthe entries, we mark the one we just checked off the list
	mov ch, 0x0A			;0023) reset the counter for checking the entry in the root directory.
	pop bx				;0024) 
	add bx, 0x20			;0025)
	push bx				;0026)
	mov si, FileName		;0027)
	jmp .FATFECompareString	;0028)
.FATFEEntryNotFound:                ;0029)
	pop bx				;0030)
	mov di, FATFEStatus		;0031)
	mov al, 0x00			;0032)
	stosb				;0033)
	popa				        ;0034)
	ret				        ;0035)
.FATFERightEntry:			;0036)
	pop bx				;0037)
	add bx, 0x1A			;0038)
	mov al, [bx]			;0039)
	mov ah, [bx + 1]		;0040)
	mov di, FATOffSet		;0041)
	stosw				;0042)
	add ax, 0x001F			;0043)This converts the next sector to LBA
	mov di, NxtSect			;0044)
	stosw				;0045)
	mov al, 0x01			;0046)
	mov di, FATFEStatus 		;0047)
	stosb				;0048)
	popa				        ;0049)
	ret				        ;0050)

to find the file inside the FAT table. The function is called with SI being set by what ever is calling this function. ROOTDIR is a variable which stores the location of the FAT table, which in my case is always 0x9000, meaning every every entry starts at every 0x0020 interval. As such i know that every Sector value is stored at bytes 0x001A and 0x001B respectively. I know its confusing but it works for me. Now, every time i call this function, the file is found, which is good. This works, however, the issue arose whenever i tried loading the actual data. Whenever i calculated the CHS from the LBA i got some absurd number and as a result I got the Error code 0x01 when calling interrupt 0x13, invalid command. After spending hours going through each individual byte of the FAT making sure that i got them all correct when finding the file, i deduced the issue must be with my LBA to CHS calculations, which is done here:

Code: Select all

ConvertLBAToCHS:		;0049)
	pusha			;0050)Preserve all the registers by moving them to the stack
	xor dx, dx		;0000) Zero out the dx register
	cld			;0000) clear the direction flag
	mov si, NxtSect		;0051)Set the source index to the memory location of the next LBA
	mov ax, FIHPT		;0052)
	mov bx, FISPT		;0053)
	mul bx			;0054)
	mov bx, ax		;0055)
	lodsw			;0056)
	div bx			;0057)
	mov di, CylinderTMP	;0058)
	stosw			;0059) the lower ten bits of AX is the cylinder the data is stored on
	mov ax, dx		;0060) take the remainder from the divide operation and store it in ax
	mov bx, FISPT		;0061) 
	div bx			;0062)
	mov di, Head		;0063)
	stosb			;0064)AL should be the head of the disk.
	inc dx
	mov ax, dx
	mov di, SectorTMP
	mov si, CylinderTMP
	xor ax, ax
	xor bx, bx
	lodsw
	mov word ax, [si]
	shr ax, 6
	mov di, SectorTMP
	mov bx, ax
	lodsw
	shr ax, 10
	shl ax, 10
	or ax, bx
	mov si, CylinderSector
	stosw
	popa
	ret
I know this is long and very inefficient, but at the time I was writing this code, I just wanted it to work, and after spending hours looking through this code, and writing it out by hand to make sure all the maths was correct, I couldn't find an issue here either. So I took a brake and focused on uni work, but then I had the urge to come back again tonight to see if I can fix the issue, and I instantly notice in the LBA calculations, I miss a very important step. I don't clear the upper four bits. Instead of using a 12 bit address, i get a 16 bit address. This extra four bits at the start or end of the sector number must have been throwing off my entire calculations. I haven't tested this yet, its half one in the morning so I need sleep, i just wanted to post this here so I can one, reference this when I inevitably forget what was wrong and break down in tears, and to secondly, get your guys opinion on this. Can you guys spot any other issues in my code? or does that seem to fix it? Ill post another update when I write the code to check if i need to clear the upper four bits of the cluster number or the lower and all that fun stuff. Its at this point in time I really wish i used FAT16 instead of FAT12.
Octocontrabass
Member
Member
Posts: 5512
Joined: Mon Mar 25, 2013 7:01 pm

Re: issue with int 0x13

Post by Octocontrabass »

Armature wrote:Can you guys spot any other issues in my code?
You keep using LODS/STOS instructions in places where you really should be using MOV. I think you've also mixed up the implied address register for them (SI vs DI) in at least one place, too.

Replace them all with MOV. You can't mix up implied registers when there aren't any.

For example, you should replace this:

Code: Select all

	mov di, FATFEStatus		;0031)
	mov al, 0x00			;0032)
	stosb				;0033)
With this:

Code: Select all

	mov byte [FATFEStatus], 0x00
Since this will make your code easier to read, it will be easier to see if there are other problems too.
Armature
Member
Member
Posts: 33
Joined: Wed Apr 25, 2018 2:44 pm
Libera.chat IRC: idk

Re: issue with int 0x13

Post by Armature »

So, its been quite a few months once again but since this whole coronavirus situation has arisen, I've had a tonne more time to work on my little kernel and I have not been able to get my LBA to CHS code to work at all. I did check a few things however, I am reading the right cluster value from root directory. That value is being stored and read corredctly from a buffer. The issue resides within my conversion code. I know this for a fact as the data is read correctly when I use someone elses code. I could just use thier code and call it a day but then whats the point. I have rewritten the code and I have just cannot see the error anywhere. Would any of you be able to help? I have this awful feeling I'm missing something obvious but im just at my wits end. Here's the code:

Code: Select all

pusha					;0050)Preserve all the registers by moving them to the stack
	mov word ax, FIHPT		;0000) C = LBA/(SPT*HPT)
	mov word bx, FISPT		;0000) 
	mul bx					;0000) AX = SPT * HPT
	mov bx, ax				;0000) BX = SPT * HPT
	mov word ax, [NxtSect]	;0000) AX = LBA
	xor dx, dx				;0000) DX = 0x0000
	div bx					;0000) AX/BX  = LBA/(SPT*HPT) AX = C DX = remainder
	push ax					;0000) Temporarily store the Cylinder
	mov ax, dx				;0000) move the rmainder into ax reday for another div
	mov word bx, FISPT		;0000) Set BX to the total number of sectors on a track which is used to calculate the head 
	xor dx, dx				;0000)
	div bx					;0000) AX/BX
	mov word [HeadDrive], ax		;0000)
	inc dx					;0000) DX now equals the value of the sector
	mov bx, dx				;0000) BX now equals the value of the sector
	pop ax					;0000) AX now equals the value of the Cylinder
	mov cx, ax 				;0000) CX now equals the value of the cylinder
	shl cx, 0x006			;0000) The upper byte and the first two bits of the lower byte CX: CCCCCCCC CCSSSSSS
	or cl, bl				;0000) The lower byte or'ed with the upper byte of bx, which should be the sector produces the full CX value
	mov word [CylinderSector], cx
	popa
	ret
The values of the variables are:

Code: Select all

FIBPS equ 0x0200			;0000) The number of bytes in each sector
FISPC equ 0x01				;0000) The number of sectors that exists with in a cluster
FIMT equ 0xF0				;0000) The type of media being read
FISPF equ 0x0009			;0000) The number of sectors that makes up the FAT
FISPT equ 0x0012			;0000) The number of sectors on each track
FIHPT equ 0x0002			;0000) The number of heads on the disk
User avatar
BenLunt
Member
Member
Posts: 941
Joined: Sat Nov 22, 2014 6:33 pm
Location: USA
Contact:

Re: issue with int 0x13

Post by BenLunt »

I am going to modify your code to use the actual values so we get an idea of what is happening, assuming you want to read sector 22 (LBA, zero based):

Code: Select all

   mov ax,2
   mov bx, 18
   mul bx
   ; dx:ax = 36
   mov bx, ax
   ; bx = ax
   mov ax,22
   xor dx, dx
   ; dx:ax = 22
   ; bx = 36
   div bx
   ; ax = 0
   ; dx = 22
   push ax   ; store the cyl
   mov ax, dx
   ; ax = 22
   mov bx,18
   xor dx, dx
   ; dx:ax = 22
   div bx
   ; ax = 1
   ; dx = 4
   mov word [HeadDrive], ax   ; <---- dh = 0 (should be 1)
   inc dx
   ; dx = 5
   mov bx, dx
   ; bx = 5
   pop ax 
   ; ax = 0
   mov cx, ax
   ; cx = 0
   shl cx, 0x006
   ; cx = 0
   or cl, bl
   ; cx = 5
   mov word [CylinderSector], cx

   ; CH = 0 = low eight bits of cylinder number
   ; CL = 5 = sector number 1-63 (bits 0-5)
   ;    = 0 = high two bits of cylinder (bits 6-7, hard disk only)
   ; DH = 0 = head number  <----- error is right here
I don't see your code that (possibly) converts [HeadDrive] to the head/drive value for the interrupt service, but as of this code, DH doesn't included the correct value.

I think your code is correct, you are just not storing the correct value in 'HeadDrive' and/or then not placing the correct value in to DH before the read.

On a different note, you can do this a little bit easier if you use the following:

Code: Select all

  ; Sector   = (LBA mod SPT) + 1
  ; Head     = (LBA  /  SPT) mod Heads
  ; Cylinder = (LBA  /  SPT)  /  Heads
Since a MOD operation uses a DIV, you only have to do the divide of LBA and SPT once.
Then divide that value by HEADs, which will give you the HEAD value (AX) and the CYL value (DX) with one operation.

Code: Select all

  dx:ax = LBA
  div SPT
  Sector = dx + 1
  div Heads
  Head = dx
  Cyl = ax
Ben
Armature
Member
Member
Posts: 33
Joined: Wed Apr 25, 2018 2:44 pm
Libera.chat IRC: idk

Re: issue with int 0x13

Post by Armature »

BenLunt wrote:I am going to modify your code to use the actual values so we get an idea of what is happening, assuming you want to read sector 22 (LBA, zero based):

Code: Select all

   mov ax,2
   mov bx, 18
   mul bx
   ; dx:ax = 36
   mov bx, ax
   ; bx = ax
   mov ax,22
   xor dx, dx
   ; dx:ax = 22
   ; bx = 36
   div bx
   ; ax = 0
   ; dx = 22
   push ax   ; store the cyl
   mov ax, dx
   ; ax = 22
   mov bx,18
   xor dx, dx
   ; dx:ax = 22
   div bx
   ; ax = 1
   ; dx = 4
   mov word [HeadDrive], ax   ; <---- dh = 0 (should be 1)
   inc dx
   ; dx = 5
   mov bx, dx
   ; bx = 5
   pop ax 
   ; ax = 0
   mov cx, ax
   ; cx = 0
   shl cx, 0x006
   ; cx = 0
   or cl, bl
   ; cx = 5
   mov word [CylinderSector], cx

   ; CH = 0 = low eight bits of cylinder number
   ; CL = 5 = sector number 1-63 (bits 0-5)
   ;    = 0 = high two bits of cylinder (bits 6-7, hard disk only)
   ; DH = 0 = head number  <----- error is right here
I don't see your code that (possibly) converts [HeadDrive] to the head/drive value for the interrupt service, but as of this code, DH doesn't included the correct value.

I think your code is correct, you are just not storing the correct value in 'HeadDrive' and/or then not placing the correct value in to DH before the read.

On a different note, you can do this a little bit easier if you use the following:

Code: Select all

  ; Sector   = (LBA mod SPT) + 1
  ; Head     = (LBA  /  SPT) mod Heads
  ; Cylinder = (LBA  /  SPT)  /  Heads
Since a MOD operation uses a DIV, you only have to do the divide of LBA and SPT once.
Then divide that value by HEADs, which will give you the HEAD value (AX) and the CYL value (DX) with one operation.

Code: Select all

  dx:ax = LBA
  div SPT
  Sector = dx + 1
  div Heads
  Head = dx
  Cyl = ax
Ben
Thanks for your response. I noticed this head error but i didnt know why i was getting it. Everytime I thought of just adding one to the value but then i didnt know if that would fix this one issue and break everything else. Or if that was thee main issue in the code. Ill try fixing it and seeing how it works.

I was thinking abuot using the modular and things like that but i didnt want to voer complicate things unescessarily at the moment. I wanted to mmake sure i had the theory and understanding down behind it.
Octocontrabass
Member
Member
Posts: 5512
Joined: Mon Mar 25, 2013 7:01 pm

Re: issue with int 0x13

Post by Octocontrabass »

Code: Select all

	mov word [HeadDrive], ax		;0000)
As already mentioned, this appears to be overwriting the drive number (DL) with the head number (DH). Might I suggest a replacement?

Code: Select all

	mov [HeadDrive+1], al
As x86 is a little-endian architecture, adding 1 to the address of a word allows you to manipulate the high byte of said word.

When you posted a couple weeks ago and deleted your post, I spotted another mistake:

Code: Select all

	shl cx, 0x006			;0000) The upper byte and the first two bits of the lower byte CX: CCCCCCCC CCSSSSSS
CH should contain the lowest 8 bits of the cylinder number, not the highest 8 bits. I have another suggestion for this.

Code: Select all

	xchg cl, ch
	shl cl, 6
You can also save a couple instructions by popping the cylinder value from the stack directly into CX instead of going through AX.
User avatar
BigBuda
Member
Member
Posts: 104
Joined: Fri Sep 03, 2021 5:20 pm

Re: issue with int 0x13

Post by BigBuda »

Why not save some trouble and just go with the extended Int 0x13 functions and the DAP? Unless you're trying to make it work on really old PCs (mostly pre-386 era), the extended functions (in your case, to read, 0x42) works quite well and you'd avoid having to convert between LBA and CHS.
Writing a bootloader in under 15 minutes: https://www.youtube.com/watch?v=0E0FKjvTA0M
nullplan
Member
Member
Posts: 1766
Joined: Wed Aug 30, 2017 8:24 am

Re: issue with int 0x13

Post by nullplan »

BigBuda wrote:Why not save some trouble and just go with the extended Int 0x13 functions and the DAP? Unless you're trying to make it work on really old PCs (mostly pre-386 era), the extended functions (in your case, to read, 0x42) works quite well and you'd avoid having to convert between LBA and CHS.
Doesn't work for floppies on most BIOSes.
Carpe diem!
User avatar
BigBuda
Member
Member
Posts: 104
Joined: Fri Sep 03, 2021 5:20 pm

Re: issue with int 0x13

Post by BigBuda »

nullplan wrote:Doesn't work for floppies on most BIOSes.
That's right. I missed that part of the context.
Writing a bootloader in under 15 minutes: https://www.youtube.com/watch?v=0E0FKjvTA0M
Post Reply