Page 1 of 1

[solved] I have a problem reading Hard Disk.

Posted: Mon Mar 21, 2011 6:17 am
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.

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

Posted: Mon Mar 21, 2011 7:07 am
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. ;-)

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

Posted: Mon Mar 21, 2011 7:24 am
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.

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

Posted: Mon Mar 21, 2011 7:36 am
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.

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

Posted: Mon Mar 21, 2011 7:51 am
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.

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

Posted: Tue Mar 22, 2011 3:35 am
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.