Page 1 of 1

hard drive access

Posted: Fri Apr 13, 2007 7:00 am
by supagu
i've ripped some code from on of the os tuts, and im trying to get it to work (vmware)

i have no idea why its working but this is the code:

Code: Select all

#define HD_PORT_DATA         0x1f0
#define HD_PORT_ERROR        0x1f1
#define HD_PORT_SECT_COUNT   0x1f2
#define HD_PORT_SECT_NUM     0x1f3
#define HD_PORT_CYL_LOW      0x1f4
#define HD_PORT_CYL_HIGH     0x1f5
#define HD_PORT_DRV_HEAD     0x1f6
#define HD_PORT_STATUS       0x1f7
#define HD_PORT_COMMAND      0x1f7

#define HD_READ              0x20
#define HD_WRITE             0x30

#define inb(port) (__extension__({	\
unsigned char __res;	\
__asm__ ("inb	%%dx,	%%al\n\t"	\
					 :"=a"(__res)	\
					 :"dx"(port));	\
__res;	\
}))

#define outb(value, port) __asm__ (	\
"outb	%%al,	%%dx\n\t"::"al"(value), "dx"(port))

#define insl(port, buf, nr) \
__asm__ ("cld;rep;insl\n\t"	\
::"d"(port), "D"(buf), "c"(nr))

#define outsl(buf, nr, port) \
__asm__ ("cld;rep;outsl\n\t"	\
::"d"(port), "S" (buf), "c" (nr))

void Read(unsigned int lba, unsigned int sects_to_access, void *buf)
{
	/* lba to chs */
	/* cylinder = LBA / (heads_per_cylinder * sectors_per_track)
	   temp = LBA % (heads_per_cylinder * sectors_per_track)
	   head = temp / sectors_per_track
	   sector = temp % sectors_per_track + 1 */
	unsigned int cyl = lba/(HD0.head * HD0.sect);
	unsigned int head = (lba%(HD0.head*HD0.sect))/HD0.sect;
	unsigned int sect = (lba%(HD0.head*HD0.sect))%HD0.sect+1;

	while ((inb(HD_PORT_STATUS)&0xc0)!=0x40)
		;

	outb(sects_to_access, HD_PORT_SECT_COUNT);
	outb(sect, HD_PORT_SECT_NUM);
	outb(cyl, HD_PORT_CYL_LOW);
	outb(cyl>>8, HD_PORT_CYL_HIGH);
	outb(0xa0|head, HD_PORT_DRV_HEAD);
	outb(HD_READ, HD_PORT_COMMAND);

	while (! (inb(HD_PORT_STATUS)&0x8))
		;

	insl(HD_PORT_DATA, buf, sects_to_access<<7);
}

void Write(unsigned int lba, unsigned int sects_to_access, void *buf)
{
	/* lba to chs */
	/* cylinder = LBA / (heads_per_cylinder * sectors_per_track)
	   temp = LBA % (heads_per_cylinder * sectors_per_track)
	   head = temp / sectors_per_track
	   sector = temp % sectors_per_track + 1 */
	unsigned int cyl = lba/(HD0.head * HD0.sect);
	unsigned int head = (lba%(HD0.head*HD0.sect))/HD0.sect;
	unsigned int sect = (lba%(HD0.head*HD0.sect))%HD0.sect+1;

	while ((inb(HD_PORT_STATUS)&0xc0)!=0x40)
		;

	outb(sects_to_access, HD_PORT_SECT_COUNT);
	outb(sect, HD_PORT_SECT_NUM);
	outb(cyl, HD_PORT_CYL_LOW);
	outb(cyl>>8, HD_PORT_CYL_HIGH);
	outb(0xa0|head, HD_PORT_DRV_HEAD);
	outb(HD_WRITE, HD_PORT_COMMAND);

	while (! (inb(HD_PORT_STATUS)&0x8))
		;

	outsl(buf, sects_to_access<<7, HD_PORT_DATA);
}

sample usage:

Code: Select all

char buffer[512];
	memset(buffer, 'a', 512);
	buffer[511] = '\0';

	Video_PutString("Empty buffer:");
	Video_PutString(buffer);
	Video_PutString("\n");
	HardDrive::Write(45, 1, buffer);

	memset(buffer, 'b', 512);
	buffer[511] = '\0';
	
	HardDrive::Read(45, 1, buffer);
	buffer[511] = '\0';
	Video_PutString("Sector buffer:");
	Video_PutString(buffer);
	Video_PutString("\n");
so output i get:
Empty buffer:
aaaa....
Sector buffer:


so something is happening to the buffer in HardDrive::Read as it should be full of b's.
Any ways, im not sure where the problem lies.

Posted: Sat Apr 14, 2007 8:34 am
by supagu
by the way, i have sata II hard drives, i suspect this could be the problem. Will i have to write a sata driver?

Re: hard drive access

Posted: Sat Apr 14, 2007 11:05 am
by mystran
supagu wrote:i've ripped some code from on of the os tuts, and im trying to get it to work (vmware)
The point of tutorials is to teach stuff, so instead of ripping the code, how about you try to understand it. ;)

It's not too uncommon for tutorials to omit stuff (or only mention it within the text) that you need in order to really run the example code...

As for whatever kind of harddrives you have, if you have SATA drive, but tell your VMWare to emulate an IDE drive, you'll see an IDE drive (and not SATA drive) inside your emulator.

As for actually supporting SATA drivers, I am under the impression that you indeed need a SATA driver to support SATA drives (=BIOSes don't attempt to emualte IDE on SATA like they do for Legacy USB support.. I could be wrong).

Posted: Sat Apr 14, 2007 5:33 pm
by pcmattman
This is nothing more than hard drive access via ports. I did this a couple of weeks ago. However, instead of just copying the code and leaving it there, I spent the time to read through the ATA specs and understand exactly what was going on. In the long run, it meant that I had a more robust system and I understood it.

You must understand exactly what is happening in copied code.

SATA is Serial ATA - ATA specs should have some info about them.

Posted: Mon Apr 16, 2007 2:19 am
by supagu
i generally copy the code first then try to understand it when it works, then i rewrite it, as most tutorials dont come with full os code etc...

anyway when i dump out the PCI device list it came up as having an IDE controller, so im a bit stumped on it.

So this code snippet is using the ATA standard?

Posted: Mon Apr 16, 2007 4:35 am
by pcmattman
supagu wrote:i generally copy the code first then try to understand it when it works, then i rewrite it, as most tutorials dont come with full os code etc...

anyway when i dump out the PCI device list it came up as having an IDE controller, so im a bit stumped on it.

So this code snippet is using the ATA standard?
ATA standard for a hard drive. It'll fail on a CDROM (typically locks the PC).

PCI devices don't necessarily have to be plugged into PCI sockets. They include AGP, for instance. Also be wary of the fact that you may be running the detection in Bochs, try it on a real PC and see if there is an IDE controller.

I recommend reading the ATA specification, and use that to help you out. It has all the commands and such, plus heaps of other info.