Page 1 of 2
ATA_IDENTIFY
Posted: Wed Mar 30, 2016 7:21 am
by ahmedfme
Hi,
i am trying to use some codes from other OSes to get ATA working in my code.
i am using below code to send IDENTIFY command
Code: Select all
outportb(io + ATA_REG_SECCOUNT0, 0);
outportb(io + ATA_REG_LBA0, 0);
outportb(io + ATA_REG_LBA1, 0);
outportb(io + ATA_REG_LBA2, 0);
/* Now, send IDENTIFY */
Printf("Sending IDENTIFY to port 0x%X\n",io);
outportb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
Printf("Sent IDENTIFY\n");
/* Now, read status port */
uint8_t status = inportb(io + ATA_REG_STATUS);
Printf("\nThe status right now is %d", status);
if (status)
{
Printf("\nNow Polling... _IRQP = %d , _IRQS= %d",_IRQP,_IRQS);
/* Now, poll untill BSY is clear. */
while (inportb(io + ATA_REG_STATUS) & ATA_SR_BSY != 0);
//while (!_IRQP || !_IRQS){}
Printf("\nFinished Polling... _IRQP = %d , _IRQS= %d", _IRQP, _IRQ
when running this code it always hang up after sending the command.
some times it writes on screen "Sen" without completing the word and hang up.
there is no panic catched ..
any isea why it is hanging up?
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 8:12 am
by BrightLight
I don't see any code for selecting a device. Every ATA channel can have two devices.
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 8:43 am
by ahmedfme
here is the full function code
Code: Select all
uint8_t ide_identify(uint8_t bus, uint8_t drive)
{
uint16_t io = 0;
ide_select_drive(bus, drive);
if (bus == ATA_PRIMARY) io = ATA_PRIMARY_IO;
else io = ATA_SECONDARY_IO;
/* ATA specs say these values must be zero before sending IDENTIFY */
outportb(io + ATA_REG_SECCOUNT0, 0);
outportb(io + ATA_REG_LBA0, 0);
outportb(io + ATA_REG_LBA1, 0);
outportb(io + ATA_REG_LBA2, 0);
/* Now, send IDENTIFY */
Printf("Sending IDENTIFY to port 0x%X\n",io);
outportb(io + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
Printf("Sent IDENTIFY\n");
/* Now, read status port */
uint8_t status = inportb(io + ATA_REG_STATUS);
Printf("\nThe status right now is %d", status);
if (status)
{
Printf("\nNow Polling... _IRQP = %d , _IRQS= %d",_IRQP,_IRQS);
/* Now, poll untill BSY is clear. */
while (inportb(io + ATA_REG_STATUS) & ATA_SR_BSY != 0);
//while (!_IRQP || !_IRQS){}
Printf("\nFinished Polling... _IRQP = %d , _IRQS= %d", _IRQP, _IRQS);
if (_IRQP) {_IRQP = false; }
if (_IRQS) { _IRQS = false; }
pm_stat_read: status = inportb(io + ATA_REG_STATUS);
if (status & ATA_SR_ERR)
{
Printf("\n%s%s has ERR set. Disabled.\n", bus == ATA_PRIMARY ? "Primary" : "Secondary", drive == ATA_PRIMARY ? " master" : " slave");
return 0;
}
while (!(status & ATA_SR_DRQ)) goto pm_stat_read;
Printf("\n%s%s is online.\n", bus == ATA_PRIMARY ? "Primary" : "Secondary", drive == ATA_PRIMARY ? " master" : " slave");
/* Now, actually read the data */
for (int i = 0; i<256; i++)
{
*(uint16_t *)(ide_buf + i * 2) = inportw(io + ATA_REG_DATA);
}
}
}
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 8:44 am
by ahmedfme
and drive select function code is here
Code: Select all
void ide_select_drive(uint8_t bus, uint8_t i)
{
if (bus == ATA_PRIMARY)
if (i == ATA_MASTER)
outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xA0);
else outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xB0);
else
if (i == ATA_MASTER)
outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xA0);
else outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xB0);
}
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 10:23 am
by BrightLight
It doesn't really look like something is wrong. Run it in Bochs and check the log messages.
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 3:53 pm
by ahmedfme
I have tried but unfortunately Bochs can't loade my bootloader "Neptune" because it doesn't support int 15h Function AX=0088
Re: ATA_IDENTIFY
Posted: Wed Mar 30, 2016 5:46 pm
by Octocontrabass
Why are you using INT 0x15 AH=0x00? That function doesn't do anything useful on modern PCs.
Maybe what you really want is INT 0x15 AH=0x88.
Re: ATA_IDENTIFY
Posted: Thu Mar 31, 2016 9:11 am
by BrightLight
Octocontrabass wrote:Maybe what you really want is INT 0x15 AH=0x88.
Even so, INT 0x15 EAX = 0xE820 should be used for detecting memory. It is supported on almost all real hardware and all emulators.
Re: ATA_IDENTIFY
Posted: Tue Apr 05, 2016 9:29 am
by alexg
ahmedfme wrote:and drive select function code is here
Code: Select all
void ide_select_drive(uint8_t bus, uint8_t i)
{
if (bus == ATA_PRIMARY)
if (i == ATA_MASTER)
outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xA0);
else outportb(ATA_PRIMARY_IO + ATA_REG_HDDEVSEL, 0xB0);
else
if (i == ATA_MASTER)
outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xA0);
else outportb(ATA_SECONDARY_IO + ATA_REG_HDDEVSEL, 0xB0);
}
You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).
Re: ATA_IDENTIFY
Posted: Tue Apr 05, 2016 12:22 pm
by BrightLight
alexg wrote:You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).
No. That code is correct.
OSDev Wiki wrote:To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port.
Re: ATA_IDENTIFY
Posted: Fri Apr 08, 2016 11:56 am
by alexg
omarrx024 wrote:alexg wrote:You are setting bits 7 and 5 (which are undefined => you should not touch them) besides the device select, I think you want to set bit 6 (which sets LBA addressing mode).
No. That code is correct.
OSDev Wiki wrote:To use the IDENTIFY command, select a target drive by sending 0xA0 for the master drive, or 0xB0 for the slave, to the "drive select" IO port.
I'm sorry, when I posted the reply I was pretty much in a hurry and I saw the fact that the ide_select_drive function specifies CHS addressing, but you're right, it's irrelevant for the IDENTIFY command. However, if LBA addressing will be used, the function should be modified to also set bit 6.
Regarding the quote from OSDev Wiki, I would appreciate you'd use an official specification when contradicting someone -
http://www.t13.org/documents/uploadeddo ... lume_1.pdf ( see 6.17 IDENTIFY DEVICE bits 7 and 5 are obsolete, so it is enough to write 0x10 for the slave and 0x0 for the master ).
Re: ATA_IDENTIFY
Posted: Fri Apr 08, 2016 1:12 pm
by BrightLight
Well, writing 0xA0 and 0xB0 for the master and slave respectively works on Bochs, QEMU, VMware, VirtualBox, one real ATA hard drive and a SATA hard drive with IDE emulation.
Re: ATA_IDENTIFY
Posted: Fri Apr 08, 2016 2:24 pm
by Octocontrabass
alexg wrote:Regarding the quote from OSDev Wiki, I would appreciate you'd use an official specification when contradicting someone -
http://www.t13.org/documents/uploadeddo ... lume_1.pdf ( see 6.17 IDENTIFY DEVICE bits 7 and 5 are obsolete, so it is enough to write 0x10 for the slave and 0x0 for the master ).
This version of the ATA specification (section 5.2.
says bits 7 and 5 should be set for backwards compatibility.
Re: ATA_IDENTIFY
Posted: Sat Apr 09, 2016 6:32 am
by alexg
You said you are not running your OS on Bochs, what are you running it on?
I've just ran my OS on a real machine and the ATA registers are not exposed by the IDE controller at the standard locations and I have to read the values from the PCI IDE Controller bars (see
http://wiki.osdev.org/PCI_IDE_Controller).
Edit: also make sure from your BIOS that the SATA configuration mode is set to IDE and not ACHI.
Re: ATA_IDENTIFY
Posted: Sun Apr 10, 2016 10:06 pm
by neon
Hello,
I have tried but unfortunately Bochs can't loade my bootloader "Neptune" because it doesn't support int 15h Function AX=0088
It should be noted that this was a copy of our old boot loader, which used int 15h function 88h to calculate the
mem_lower and
mem_upper fields of the multiboot information structure. The boot loader uses int 15h function e820h for the memory map fields which is what you really want. So, if you want to suppress the error,
clear bit 0 of the multiboot header flags field. This will tell the boot loader to ignore the mem_* fields. In any case though, the software should still continue to run despite the error.