ATA PIO Mode
ATA PIO Mode
Hello,
I'm having trouble with the ata in pio mode. I've read the wiki and decided to setup a simple read function with lba28. For some odd reason anytime I inb or outb grub won't let me boot saying it's a invalid executable but, when I take away that from the function it boots. Here's my code:
void hdd_lba28_read_sector(uint8 port, uint16 LBA, uint8 count, uint8 *buffer)
{
outb((port | 6), 0xE0 | (port << 4) | ((LBA >> 24) & 0x0F));
outb((port | 1), 0);
outb((port | 2), (uint8) count);
outb((port | 3), (uint8) LBA);
outb((port | 4), (uint8) (LBA >> 8));
outb((port | 5), (uint8) (LBA >> 16));
outb((port | 7), 0x20);
while(!((port | 7) & 0x80))
;
uint32 i=0;
while(i < 256)
{
uint16 temp = inw(port);
buffer[i*2]=(uint8) temp;
buffer[i*2+1]=(uint8) (temp >> 8);
i++;
}
}
For some reason I keep on getting smilie faces but the numbers are 8
If you have an idea of why the outb and inb are causing this problem please respond.
Thank You
I'm having trouble with the ata in pio mode. I've read the wiki and decided to setup a simple read function with lba28. For some odd reason anytime I inb or outb grub won't let me boot saying it's a invalid executable but, when I take away that from the function it boots. Here's my code:
void hdd_lba28_read_sector(uint8 port, uint16 LBA, uint8 count, uint8 *buffer)
{
outb((port | 6), 0xE0 | (port << 4) | ((LBA >> 24) & 0x0F));
outb((port | 1), 0);
outb((port | 2), (uint8) count);
outb((port | 3), (uint8) LBA);
outb((port | 4), (uint8) (LBA >> 8));
outb((port | 5), (uint8) (LBA >> 16));
outb((port | 7), 0x20);
while(!((port | 7) & 0x80))
;
uint32 i=0;
while(i < 256)
{
uint16 temp = inw(port);
buffer[i*2]=(uint8) temp;
buffer[i*2+1]=(uint8) (temp >> 8);
i++;
}
}
For some reason I keep on getting smilie faces but the numbers are 8
If you have an idea of why the outb and inb are causing this problem please respond.
Thank You
Re: ATA PIO Mode
Hi,
I've edited your post - the forum software converts 8) to a smiley unless you disable them.
Cheers,
Adam
I've edited your post - the forum software converts 8) to a smiley unless you disable them.
Cheers,
Adam
Re: ATA PIO Mode
Thanks, one problem solved but still need to understand the problem with my code.
Re: ATA PIO Mode
uint16 LBA must be Uint32 LBA
you can't shift 24 if LBA is only 16 bits wide.
you can't shift 24 if LBA is only 16 bits wide.
Re: ATA PIO Mode
Thanks for your reply. I changed uint16 to uint32. That was a stupid mistake but, I still get the same error. I also changed uint8 to uint16 on the port variable. Which I still got the same problem.
Re: ATA PIO Mode
Yes inb and outb are included through my own code
Linking succeeds
It's a elf format
I'm booting of grub
The OS works without the code. It boots enables irqs with setting up isrs and irqs, console functions, and other things. I doubt it's something with grub or my os besides the code its self in the function. I don't even call the function though, it just fails when the os runs with that object file linked but, there are no errors or warning (It's a clean run).
Linking succeeds
It's a elf format
I'm booting of grub
The OS works without the code. It boots enables irqs with setting up isrs and irqs, console functions, and other things. I doubt it's something with grub or my os besides the code its self in the function. I don't even call the function though, it just fails when the os runs with that object file linked but, there are no errors or warning (It's a clean run).
Re: ATA PIO Mode
Hello?
Here's my updated coded:
#include <./Devices/HDD/hdd.h>
#include <types.h>
#include <system.h>
#include <console.h>
#include <HAL.h>
#include <interrupt_number.h>
void hdd_lba28_read_sector(uint32 port, uint32 LBA, uint8 *buffer)
{
outb(port | 6, 0xE0 | (port << 4) | ((LBA >> 24) & 0x0F));
outb(port | 1, 0x00);
outb(port | 2, 0x01);
outb(port | 3, (uint8) LBA);
outb(port | 4, (uint8) (LBA >> 8));
outb(port | 5, (uint8) (LBA >> 16));
outb(port | 7, 0x20);
while(!((port | 7) & 0x08))
;
uint32 i=0;
while(i < 256)
{
uint16 temp = inw(port);
buffer[i*2]=(uint8) temp;
buffer[i*2+1]=(uint8) (temp >> 8);
i++;
}
}
Of course it still doesn't work I've also created a drive detection and controller detection but I decided that it was not necessary because I just want to be able to run my os with this code for now I can run and test it but, I can't load it grub just says:
Booting '[my os name]'
kernel /kernel.bin
Error 13: Invalid or unsupported executable format
Press any key to continue
I'm using Ubuntu
It works when I don't link this code in object format with my os
I'm using grub as a bootloader
my kernel is a elf format
This is ata pio mode lba 28
Please respond...
Thank you
Here's my updated coded:
#include <./Devices/HDD/hdd.h>
#include <types.h>
#include <system.h>
#include <console.h>
#include <HAL.h>
#include <interrupt_number.h>
void hdd_lba28_read_sector(uint32 port, uint32 LBA, uint8 *buffer)
{
outb(port | 6, 0xE0 | (port << 4) | ((LBA >> 24) & 0x0F));
outb(port | 1, 0x00);
outb(port | 2, 0x01);
outb(port | 3, (uint8) LBA);
outb(port | 4, (uint8) (LBA >> 8));
outb(port | 5, (uint8) (LBA >> 16));
outb(port | 7, 0x20);
while(!((port | 7) & 0x08))
;
uint32 i=0;
while(i < 256)
{
uint16 temp = inw(port);
buffer[i*2]=(uint8) temp;
buffer[i*2+1]=(uint8) (temp >> 8);
i++;
}
}
Of course it still doesn't work I've also created a drive detection and controller detection but I decided that it was not necessary because I just want to be able to run my os with this code for now I can run and test it but, I can't load it grub just says:
Booting '[my os name]'
kernel /kernel.bin
Error 13: Invalid or unsupported executable format
Press any key to continue
I'm using Ubuntu
It works when I don't link this code in object format with my os
I'm using grub as a bootloader
my kernel is a elf format
This is ata pio mode lba 28
Please respond...
Thank you
Re: ATA PIO Mode
I figured out one more mistake,
instead of while(!(port | 7, 0x20));
I put while(!(inb(port | 7), 0x20));
the thing that is bothering me is that it's not any mistakes that should make grub say that. I'm only using the plain stage1 and stage2. Should I have added another binary?
instead of while(!(port | 7, 0x20));
I put while(!(inb(port | 7), 0x20));
the thing that is bothering me is that it's not any mistakes that should make grub say that. I'm only using the plain stage1 and stage2. Should I have added another binary?
Re: ATA PIO Mode
I expect your multi boot header has been placed wrongly (not dword aligned?).
See http://wiki.osdev.org/Grub_Error_13
See http://wiki.osdev.org/Grub_Error_13
Re: ATA PIO Mode
this code must work for any of those old ide controllers who still use 0x1f0/0x170 ...
But this code has ==unknown== results for the new motherboards like Intel's AHCI in legacy mode....
you should call it like:
pioreadide(0x1f0,0, sector,1,buffer);
//read from [MASTER(0)/SLAVE(1) - 2nd parameter] drive on first IDE slot (0x1f0);
//pioreadide(port, master0_or_slave1, sector_LBA28, number_of_sectors, buffer_big_enough);
PS:
1)you should test always for BUSY BUS bit to be cleared before writeing CMDs to registers
2)you should test always for DRDY bit to be set before writeing CMDs to registers
3)you should test always for DRQ bit to be set before reading DATA from driver (Data Request bit)
all this bits are in the status register (port+7)
But this code has ==unknown== results for the new motherboards like Intel's AHCI in legacy mode....
Code: Select all
int pioreadide(uint16 port, uint8 typ, uint32 lba,uint16 count,uint8 *buffer) {
int i;
//typ is for selectinh which channel ... Master(0) / Slave(1)
typ &=0x01;
typ <<= 4
inb(port+1); //read error register port
while (inb(port+7)&0x80)==0x80) ; // wait for BUSY BUS bit to clear
while (inb(port+7)&0x40)!=0x40) ; // wait for DRIVE READY bit to be set
switch (port) {
case (0x1F0): outb(0x3f6,0x0a); break;//set nIEN - no interrupts 'cause we do PIO
case (0x170): outb(0x376,0x0a); break;
default :
#ifdef DeviceControlRegister
outb(DeviceControlRegister,0x0a);
#endif
break;
};
//set registers
outb(port+2,count);
outb(port+3,lba & 0xff);
outb(port+4,(lba>>8) & 0xff);
outb(port+5,(lba>>16) & 0xff);
outb(port+6,((((lba>>24) & 0xff)|0x70)&0xEF)|typ);
inb(port+1); //read error port
while ((inb(port+7)&0x80)==0x80) ; //wait until BUSY BIT is cleared
outb(port+7, 0x21); //commands like : 0x20 read with retry / 0x21 read without retry
while (count>0) {
while ((inb(port+7)&0x08)!=0x08) ; //wait until DRQ bit is set : Data ReQuest bit set -> indicates that the drive is ready to transfer data
while (i<256) {
*((uint16 *)&buffer[i<<1])=inw(port);
i++;
};
inb(port+1);
while ((inb(port+7)&0x80)==0x80) ; //wait until BUS BUSY bit to be cleared
count--;
}
switch (port) {
case (0x1F0): outb(0x3f6,0x08); break;//clear nIEN =set interrupts
case (0x170): outb(0x376,0x08); break;
default :
#ifdef DeviceControlRegister
outb(DeviceControlRegister,0x08);
#endif
break;
};
return(count);
}
pioreadide(0x1f0,0, sector,1,buffer);
//read from [MASTER(0)/SLAVE(1) - 2nd parameter] drive on first IDE slot (0x1f0);
//pioreadide(port, master0_or_slave1, sector_LBA28, number_of_sectors, buffer_big_enough);
PS:
1)you should test always for BUSY BUS bit to be cleared before writeing CMDs to registers
2)you should test always for DRDY bit to be set before writeing CMDs to registers
3)you should test always for DRQ bit to be set before reading DATA from driver (Data Request bit)
all this bits are in the status register (port+7)
NOTE: quote taken from : http://www.t13.org/documents/UploadedDo ... -ATA-1.pdfStatus register (port+7) (aka the old 0x1f7/0x177)
(when read)
+=======-=======-=======-=======-=======-=======-=======-=======+
| 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|-------+-------+-------+-------+-------+-------+-------+-------|
| BSY | DRDY | DWF | DSC | DRQ | CORR | IDX | ERR |
+===============================================================+
NOTE 7 - Prior to the definition of this standard, DRDY and DSC were unlatched
real time signals.
- BSY (Busy) is set whenever the drive has access to the Command Block
Registers. The host should not access the Command Block Register when
BSY=1. When BSY=1, a read of any Command Block Register shall return
the contents of the Status Register. This bit is set by the drive
(which may be able to respond at times when the media cannot be
accessed) under the following circumstances:
a) within 400 nsec after the negation of RESET- or after SRST has been
set in the Device Control Register. Following acceptance of a reset
it is recommended that BSY be set for no longer than 30 seconds by
Drive 1 and no longer than 31 seconds by Drive 0.
b) within 400 nsec of a host write of the Command Register with a Read,
Read Long, Read Buffer, Seek, Recalibrate, Initialize Drive
Parameters, Read Verify, Identify Drive, or Execute Drive Diagnostic
command.
c) within 5 usecs following transfer of 512 bytes of data during
execution of a Write, Format Track, or Write Buffer command, or 512
bytes of data and the appropriate number of ECC bytes during the
execution of a Write Long command.
- DRDY (Drive Ready) indicates that the drive is capable of responding to
a command. When there is an error, this bit is not changed until the
Status Register is read by the host, at which time the bit again
indicates the current readiness of the drive. This bit shall be cleared
at power on and remain cleared until the drive is ready to accept a
command.
- DWF (Drive Write Fault) indicates the current write fault status. When
an error occurs, this bit shall not be changed until the Status Register
is read by the host, at which time the bit again indicates the current
write fault status.
- DSC (Drive Seek Complete) indicates that the drive heads are settled
over a track. When an error occurs, this bit shall not be changed until
the Status Register is read by the host, at which time the bit again
indicates the current Seek Complete status.
- DRQ (Data Request) indicates that the drive is ready to transfer a word
or byte of data between the host and the drive.
- CORR (Corrected Data) indicates that a correctable data error was
encountered and the data has been corrected. This condition does not
terminate a data transfer.
- IDX (Index) is set once per disk revolution.
- ERR (Error) indicates that an error occurred during execution of the
previous command. The bits in the Error Register have additional
information regarding the cause of the error.
Information technology -
AT Attachment Interface for Disk Drives
ABSTRACT
This standard defines the AT Attachment Interface. This standard defines an
integrated bus interface between disk drives and host processors. It provides
a common point of attachment for systems manufacturers, system integrators,
and suppliers of intelligent peripherals.
Re: ATA PIO Mode
You should have an ATA IDE compatible driver ... 'cause the new SATA[N] controllers in legacy mode have some ... little [d6v1l] incompatibility issues ... ... don't know why ...
Re: ATA PIO Mode
I think it's more likely that the multiboot header moves out of the first 8k of the executable because the code before it grew. Anyhow, looking at the binary in a hex editor and checking the multiboot header there should help.evoex wrote:I expect your multi boot header has been placed wrongly (not dword aligned?).
See http://wiki.osdev.org/Grub_Error_13
Re: ATA PIO Mode
Thank you so much, you were right the multiboot, it was out of the 8k range that it's supposed to be in. I know I should of looked up the error on the grub website or here but I have gotten this error before and it was just a code problem.
Re: ATA PIO Mode
My code will run but now when I try to read it just prints nothing. I've setup a device detector and there is a harddrive but for some reason when I read a sector of the hard drive when I print out the contents it's nothing. I also tried my writing function and tried to write and then read what I just wrote but I still got nothing. Here's my code:
#include <./Devices/ATA/ATA.h>
#include <types.h>
#include <system.h>
#include <console.h>
#include <HAL.h>
#include <interrupt_number.h>
#define READ_SECTORS 0x20
#define WRITE_SECTORS 0x30
void ata_lba28_read_sector(uint32 drive, uint32 LBA, char* buffer)
{
outb(drive | 1, 0x00);
outb(drive | 2, 0x01);
outb(drive | 3, (uint8) LBA);
outb(drive | 4, (uint8) (LBA >> );
outb(drive | 5, (uint8) (LBA >> 16));
outb(drive | 6, 0xE0 | (drive << 4) | ((LBA >> 24) & 0x0F));
outb(drive | 7, READ_SECTORS);
while(!(inb(drive | 7) & 0x08));
uint16 i=0;
uint16 temp=0;
while(i < 256)
{
temp = inw(drive);
buffer[i*2] = (uint8) temp;
buffer[(i*2)+1] = (uint8) (temp >> ;
i++;
}
}
void ata_lba28_write_sector(uint32 drive, uint32 LBA, char* buffer)
{
outb(drive | 1, 0x00);
outb(drive | 2, 0x01);
outb(drive | 3, (uint8) LBA);
outb(drive | 4, (uint8) (LBA >> );
outb(drive | 5, (uint8) (LBA >> 16));
outb(drive | 6, 0xE0 | (drive << 4) | ((LBA >> 24) & 0x0F));
outb(drive | 7, WRITE_SECTORS);
while(!(inb(drive | 7) & 0x08));
uint16 i=0;
uint16 temp=0;
while(i < 256)
{
temp = buffer[8 + i * 2] | (buffer[8 + i * 2 + 1] << ;
outw(drive, temp);
}
}
uint32 ata_detect_drives()
{
outb(0x1F3, 0x4);
if(inb(0x1F3) == 0x4)
return 0; //success
else
return -1; //fail
}
uint32 ata_detect_controllers()
{
if(ata_detect_drives() == -1)
{
printf_color("WARNING: No Drives detected...\n", 0x04);
}
else
printf_color("Drive detected...\n", 0x02);
outb(0x1F6, 0xA0);
uint32 i=0;
while(i < 50000)
{
i++;
}
uint8 tmp = inb(0x1F7);
if(tmp & 0x40)
{
printf_color("Primary Controller Exists...\n", 0x02);
return 0;
}
else
{
printf_color("WARNING: Primary Doesn't Controller Exists...\n", 0x04);
return -1;
}
}
#include <./Devices/ATA/ATA.h>
#include <types.h>
#include <system.h>
#include <console.h>
#include <HAL.h>
#include <interrupt_number.h>
#define READ_SECTORS 0x20
#define WRITE_SECTORS 0x30
void ata_lba28_read_sector(uint32 drive, uint32 LBA, char* buffer)
{
outb(drive | 1, 0x00);
outb(drive | 2, 0x01);
outb(drive | 3, (uint8) LBA);
outb(drive | 4, (uint8) (LBA >> );
outb(drive | 5, (uint8) (LBA >> 16));
outb(drive | 6, 0xE0 | (drive << 4) | ((LBA >> 24) & 0x0F));
outb(drive | 7, READ_SECTORS);
while(!(inb(drive | 7) & 0x08));
uint16 i=0;
uint16 temp=0;
while(i < 256)
{
temp = inw(drive);
buffer[i*2] = (uint8) temp;
buffer[(i*2)+1] = (uint8) (temp >> ;
i++;
}
}
void ata_lba28_write_sector(uint32 drive, uint32 LBA, char* buffer)
{
outb(drive | 1, 0x00);
outb(drive | 2, 0x01);
outb(drive | 3, (uint8) LBA);
outb(drive | 4, (uint8) (LBA >> );
outb(drive | 5, (uint8) (LBA >> 16));
outb(drive | 6, 0xE0 | (drive << 4) | ((LBA >> 24) & 0x0F));
outb(drive | 7, WRITE_SECTORS);
while(!(inb(drive | 7) & 0x08));
uint16 i=0;
uint16 temp=0;
while(i < 256)
{
temp = buffer[8 + i * 2] | (buffer[8 + i * 2 + 1] << ;
outw(drive, temp);
}
}
uint32 ata_detect_drives()
{
outb(0x1F3, 0x4);
if(inb(0x1F3) == 0x4)
return 0; //success
else
return -1; //fail
}
uint32 ata_detect_controllers()
{
if(ata_detect_drives() == -1)
{
printf_color("WARNING: No Drives detected...\n", 0x04);
}
else
printf_color("Drive detected...\n", 0x02);
outb(0x1F6, 0xA0);
uint32 i=0;
while(i < 50000)
{
i++;
}
uint8 tmp = inb(0x1F7);
if(tmp & 0x40)
{
printf_color("Primary Controller Exists...\n", 0x02);
return 0;
}
else
{
printf_color("WARNING: Primary Doesn't Controller Exists...\n", 0x04);
return -1;
}
}