[solved] I have a problem reading Hard Disk.

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
User avatar
trinopoty
Member
Member
Posts: 87
Joined: Wed Feb 09, 2011 2:21 am
Location: Raipur, India

[solved] I have a problem reading Hard Disk.

Post by trinopoty »

Hello,
This is my first post, so please pardon me for any mistakes.
I am writing a basic function to read hard disk for my kernel. Below is the code.

Code: Select all

extern void outPort(unsigned short port, unsigned char data);
extern unsigned char inPort(unsigned short port);

bool HardDisk::ReadDisk(unsigned char *buffer, unsigned short NoOfSectors, unsigned __int32 LBA, unsigned char drive)
{
	unsigned short base_port = 0;
	if(drive > 1)
	{
		base_port = 0x0170;
		drive-=2;
	}
	else
		base_port = 0x01F0;

	LBA = LBA & 0x0FFFFFFF;

	unsigned char status = inPort(base_port+6);	
	// I dont want to declare another variable to hold the drive/head register data.
	status = status | (drive << 4);
	outPort(base_port + 6, status);
	status = inPort(base_port + 7);	// delay
	status = inPort(base_port + 7);	// delay
	status = inPort(base_port + 7);	// delay
	status = inPort(base_port + 7);	// delay
	outPort(base_port+7, 0x08);	// reset disk
	while(true)
	{
		if((status & IDE_READY) == IDE_READY)
			break;
		if(((status & IDE_ERROR) == IDE_ERROR) || ((status & IDE_DRIVEFAULT) == IDE_DRIVEFAULT))
			outPort(base_port+7, 0x08);
	}

	while(NoOfSectors > 0)
	{
		status = inPort(base_port + 6);
		status = status | 0x40 | (unsigned char)(LBA >> 24);
		outPort(base_port + 6, status);
		outPort(base_port + 2, 0x01);
		outPort(base_port + 3, (unsigned char)LBA);
		outPort(base_port + 4, (unsigned char)(LBA >> 8));
		outPort(base_port + 5, (unsigned char)(LBA >> 16));
		outPort(base_port + 7, 0x20);

		while(true)
		{
			status = inPort(base_port + 7);
			if(((status & IDE_READY) == IDE_READY) && ((status & IDE_BUSY) == 0) && ((status & IDE_DATAREADY) == IDE_DATAREADY))
				break;
			if(((status & IDE_ERROR) == IDE_ERROR) || ((status & IDE_DRIVEFAULT) == IDE_DRIVEFAULT))
				outPort(base_port+7, 0x08);
		}
		__asm
		{
			mov edi, dword ptr [buffer]
			mov dx, word ptr [base_port]
			mov ecx, 0x100
			cld
			rep insw
		}
		NoOfSectors -= 1;
		buffer += 0x200;
		LBA += 1;
		__asm
		{
			nop
			nop
			nop
			nop
			nop
		}
	}
	return true;
}
The function works fine the first time but then reads either all 0x00 or all 0xFF after the first time.
Can anyone tell me the problem in the code.

if 'drive' is 0 or 1 it means IDE 0:0 or IDE 0:1 respectively, if 'drive' is 2 or 3 it means IDE 1:0 or IDE 1:1 respectively.
Last edited by trinopoty on Mon Mar 21, 2011 8:51 am, edited 1 time in total.
Always give a difficult task to a lazy person. He will find an easy way to do it.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: I have a problen reading Hard Disk in Protected Mode.

Post by Solar »

Machete Debugging, a.k.a. "reduce the problem".

Don't look at this function as an atomic entity.

Trace what calls to this function are being made, and their parameters

Then take a notebook and a pencil, step through your function, and note down what your function does with the parameters, and what calls it should make. Does it look as it should work, or did you already find a problem?

Put traces in the inPort() and outPort() functions. Do the actual calls match expectations? Does the result of those calls match expectations? (Perhaps it's not ReadDisk() that is broken, but other code.)

Do the same for the inline ASM code: Do actual traces meet expectations?

Reduce. Isolate. Identify. Looking at two screenful of code and trying to hypnotize the error seldom works. Posting two screenful of code usually gives generic debugging answers, like this one, since we cannot reproduce your problem to put those traces and do that reducing ourselves. ;-)
Every good solution is obvious once you've found it.
User avatar
trinopoty
Member
Member
Posts: 87
Joined: Wed Feb 09, 2011 2:21 am
Location: Raipur, India

Re: I have a problen reading Hard Disk in Protected Mode.

Post by trinopoty »

Well it works the first time it is used, that means there is no problem with the existing code. And I am calling the code with the right paramaters. The inPort() and outPort() works as expected, I have tested them. I tried calling the function ReadDisk() with known data in known sectors, but still the same result ie. it works the first time.

Is there some other command(s) I need to send to some port between two reads.
User avatar
bewing
Member
Member
Posts: 1401
Joined: Wed Feb 07, 2007 1:45 pm
Location: Eugene, OR, US

Re: I have a problen reading Hard Disk in Protected Mode.

Post by bewing »

I assume that you are doing this on real hardware, and not in an emulator?

After you read each sector, try putting in some extra IO port reads, to make more of a delay. 4 nop's may not delay anything at all.
User avatar
trinopoty
Member
Member
Posts: 87
Joined: Wed Feb 09, 2011 2:21 am
Location: Raipur, India

Re: I have a problen reading Hard Disk in Protected Mode.

Post by trinopoty »

I assume that you are doing this on real hardware, and not in an emulator?

After you read each sector, try putting in some extra IO port reads, to make more of a delay. 4 nop's may not delay anything at all.
I am testing this on VmWare Workstation v6.0.
Also I usually read 1 sector at a time and call many functions between two reads which takes more than 400 ns.
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: [solved] I have a problem reading Hard Disk.

Post by Creature »

I've actually had the same problem for quite some time. With me it wasn't just the second read that would fail, it would be all "even" reads (i.e. the first read succeeds, second read fails, third read succeeds, fourth read fails, etc.). I'm not even sure if I fixed the problem either. It occurred on real hardware as wel as on QEMU, but not on Bochs.

But it's been quite some time since I've been busy with my OS, so I may be wrong about some details. The point I wanted to make is that I also had no idea how to solve the problem and everything seemed to be correct. I had read through different implementations of others (tried things I seemed to have forgotten) and found nothing that fixed it.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
Post Reply