hard drive access

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
supagu
Member
Member
Posts: 46
Joined: Sat Apr 07, 2007 1:24 am

hard drive access

Post 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.
supagu
Member
Member
Posts: 46
Joined: Sat Apr 07, 2007 1:24 am

Post 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?
User avatar
mystran
Member
Member
Posts: 670
Joined: Thu Mar 08, 2007 11:08 am

Re: hard drive access

Post 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).
The real problem with goto is not with the control transfer, but with environments. Properly tail-recursive closures get both right.
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post 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.
supagu
Member
Member
Posts: 46
Joined: Sat Apr 07, 2007 1:24 am

Post 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?
pcmattman
Member
Member
Posts: 2566
Joined: Sun Jan 14, 2007 9:15 pm
Libera.chat IRC: miselin
Location: Sydney, Australia (I come from a land down under!)
Contact:

Post 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.
Post Reply