Harddisk Access problem[SOLVED]

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
PinkyNoBrain
Posts: 22
Joined: Mon Oct 29, 2007 10:49 am

Harddisk Access problem[SOLVED]

Post by PinkyNoBrain »

Hello everybody, im at the beggining of implmenting basic hardisk and filesystem supoort for my hobby os and ive hit a brick wall :-( hopefully someone out there can help :-). At this stage im not interested in writting sophisticated drivers so i read the excelent ATA_PIO wiki article on this site and followed its LBA 28-bit mode instructions for reading and writting( i use polling rather than interupts at this stage). I implemented this in my os, ran a few tests and everything seemed to work. Brilliant i thought i can now read and write data from the disk, onto implmenting the filesystem. The filesystem im using is Ext2 i was succesfull in reading the super block, group descripot table and inode table and the root dirs inode, ive verified the data for each was being read correctly by checing it using some filesystem analysis tools. My problem came when accessing the first data block of the file, the read would comlete successfully but all i get back is 0's.

In more detail, the size of on disk blocks is 512b the size of the blocks in the EX2FS is 1024. So to read a FS block i need to multiply the FS block number by 2 to get the corresponding disk block number and read two disk blocks. This approach works fine for the super block, inode table ect but not for the first data block in the root dir. I know that this is the 202 FS block and have used a seporate FS tool to specifically read block 202 and verify the data in it is correct so i know this is the correct block. However when my OS trys to read the two disk blocks starting at 404 all i get back is 0's. The only difference i can see between this and previous reads is that the block address is much higher than the address of the superblock and other structures. I have no idea what the problem could be or where to go from here, any advice would be welcome.

I test my OS through bochs as i dont want to trash a real HD. I am quite happy to post code but will wait to hear where people think the problem is before copying and pasting vast quantaties of it.

Thanks in advance for any help,
Chris
Last edited by PinkyNoBrain on Tue May 27, 2008 2:32 pm, edited 1 time in total.
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Hi,

The fact that you seem to read the superblock et al fine but have problems with a larger sector address makes me immediately think that your LBA conversion routines may be incorrect.

To expand, if you have a shift or mask incorrect in your LBA/ATA code then you may well be able to read smaller sector addresses fine, but when you increase the sector address the bad shift/mask may cause things to go awry.

As a test, and as you said you had a way to check disk data externally, I suggest going through each sector individually, computing a checksum (i.e. add every byte in the sector together and display the result).

Do the same externally to the OS (on your disk image) and see where the disparity starts. This should give you an indication of where to look for your error.

Cheers,

James
PinkyNoBrain
Posts: 22
Joined: Mon Oct 29, 2007 10:49 am

Post by PinkyNoBrain »

Hi James,
thank you for the speady response. I have attempted what you suggested however the problem is slightly complicated by the fact that large amounts of the FS blocks before block 202 are reserved for FS meta data and all their values are 0's. FS block 45 is the last to contain nay data and my OS reads this correctly. 46 to 201 are all zeroed according to my FS tool and OS then we get to 202 where my FS tools sees the correct data but my OS sees nothing. Unfortunalty my write to disk code does not appear to work either(that was going to be my next question) so i dont know of anyway to put data on the disk in the zeroed region to see whats being read correctly.

Bellow is the code i use for reading a sector, writting is almost identical but i send 0x30 instead of 0x20 to 0x1F7.

Code: Select all

unsigned int read_sector(unsigned char drive,unsigned int lba,unsigned char sectorcount,void * b)
{
	unsigned short * buffer =(unsigned short *)b;
	//Use mutex to lock the device to prevent another process comming allong halfway through and changing all the setting
	wait_on_mutex(&hdc_dev_mutex);

	//Setup the device for reading
	outportb(0x1F6,0xE0 | (drive << 4) | ((lba >> 24) & 0x0F));
	outportb(0x1F1,0x00);
	outportb(0x1F2,sectorcount);
	outportb(0x1F3,(unsigned char)lba);
	outportb(0x1F4,(unsigned char)lba>>8);
	outportb(0x1F5,(unsigned char)lba>>16);
	outportb(0x1F7, 0x20);

	//Wait for device to become ready
	while(!(inportb(0x1F7) & 0x08))sleep_process();

	//Read the data from the device int othe buffer
	for(unsigned int x = 0;x < (sectorcount*256);x++)
		buffer[x] = inportw(0x1F0);

	//release the mutex to allow other processes access
	hdc_dev_mutex = 0;
	
	return 0;
}
I assume i am making a stuppid mistake somewhere it is just figuring out where the mistake is. One other thought that crossed my mind is whether the Bochs ATA dirver is ok since ive read that it doesnt support 48bit mode, but since im using 24bit mode this seems unlikely.

thanks again for your response,
Chris
User avatar
JamesM
Member
Member
Posts: 2935
Joined: Tue Jul 10, 2007 5:27 am
Location: York, United Kingdom
Contact:

Post by JamesM »

Hi,

Comparing with my own code everything seems fine.

The only difference I see is that you're spinning until the status register & 0x08 is set (HD_STATUS_BUFFER_NEEDS_SERVICING) and I'm waiting until status register & 0x40 is set (HD_STATUS_READY).

However, in bochs these should both be instant so I doubt that's the problem. One other thing I noticed is that I use explicit masks, and don't rely on the implicit cast.

In this code:

Code: Select all

outportb(0x1F4,(unsigned char)lba>>8); 
I put a mask in there:

Code: Select all

outportb(0x1F4,(unsigned char)((lba>>8)&0xFF));
I know that this seems pedantic but I have seen GCC generate dodgy code without that mask in in the past and it shook me up so much that I mask everywhere.

Maybe give that a try? If not, it's time to see your ext2 code.

Cheers,

James

EDIT: Also, be sure to sanity check your 'drive' parameter, as values other than 0 or 1 will cause borkage.
PinkyNoBrain
Posts: 22
Joined: Mon Oct 29, 2007 10:49 am

Hard Disk Access Problem [SOLVED]

Post by PinkyNoBrain »

James you are a genious, it was the casting as soon ias i changed it to use explicit masks everything worked as expected. Thank you very much for your help mate i would never even have suspected that as the problem :-)
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:

Post by Combuster »

Code: Select all

outportb(0x1F4,(unsigned char)lba>>8); 
nice spot :)
how it works: take lba, make it a char (get the lower 8 bits), shift it (KILL the lower 8 bits you just had), output the value zero.
To fix the order of computation:

Code: Select all

outportb(0x1F4,(unsigned char)(lba>>8)); 
"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 ]
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Post by bewing »

whether the Bochs ATA dirver is ok since ive read that it doesnt support 48bit mode ...
Just wanted to clarify that bochs (at least the recent versions) handles 48bit LBA just fine.
Post Reply