OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 3:20 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Problem with reading from ata[solved]
PostPosted: Sat Feb 02, 2019 2:16 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
Good day,
I have problem. My method for reading ata doesnt work. It stuck in command "while ( ( (inb(0x1F7) & ATA_SR_DRQ)==1 ) ) {}" . I have detected hard disc on primary master. I use Virtualbox. Please why virtualbox doesnt respond data from hard disc?

Code:
void ata_sector(uint16_t base, uint8_t type, uint64_t addr, uint8_t drive) {
    uint16_t tmpword=0;

    ata_base=base;

    ata_error=UNDETECTED;

    drive=inb(ata_base+ATA_PORT_STATUS);
    if(drive==0xFF) {
        ata_error=DETECTED;
        tp("ata is undetected");
        return;
    }

    tmpword=inb(ata_base+ATA_PORT_STATUS);
    if(drive==ATA_MASTER) {
    outb(ata_base+ATA_PORT_DRV, 0xE0);
    }
    else { // ATA_SLAVE
    outb(ata_base+ATA_PORT_DRV, 0xF0);
    }

    if ( ( (inb(ATA_PORT_STATUS) & ATA_SR_ERR)==1 ) ) {  //error?
        tp("ata error 2");
        return;
    }

    //PIO28
    outb(ata_base+ATA_PORT_FEATURES, 0x00); 
    outb(ata_base+ATA_PORT_SCT_COUNT, 0x01); 
    outb(ata_base+ATA_PORT_SCT_NUMBER, (unsigned char)addr); 
    outb(ata_base+ATA_PORT_CYL_LOW, (unsigned char)(addr >> 8)); 
    outb(ata_base+ATA_PORT_CYL_HIGH, (unsigned char)(addr >> 16));

    if(type==ATA_READ) {
    outb(ata_base+ATA_PORT_COMMAND, ATA_CMD_READ_PIO);  // Send command
    }
    else {
    outb(ata_base+ATA_PORT_COMMAND, ATA_CMD_WRITE_PIO);
    }

    // waiting for data
    while ( ( (inb(0x1F7) & ATA_SR_DRQ)==1 ) ) {}
   
    for (uint8_t idx = 0; idx < 255; idx++)
    {
        if(type==ATA_READ) {
            buffer[idx] = inw(ata_base + ATA_PORT_DATA);
        }
        else {
            tmpword=(unsigned short)buffer[idx];
            outw(ata_base + ATA_PORT_DATA, tmpword);
        }
    }
}


I am reading data with command "ata_sector(0x1F0, ATA_READ, 1, ATA_MASTER);" Please help me.

PS sorry for my bad english

_________________
https://github.com/VendelinSlezak/BleskOS


Last edited by Klakap on Thu Feb 07, 2019 1:01 pm, edited 1 time in total.

Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Sat Feb 02, 2019 2:32 pm 
Offline
Member
Member
User avatar

Joined: Mon Jul 13, 2009 5:52 am
Posts: 99
Location: Denmark
Hi Klakap,

This while loop does not make any sense:
Code:
while ( ( (inb(0x1F7) & ATA_SR_DRQ)==1 ) ) {}


ATA_SR_DRQ is bit 3 (i.e. 0x08) which means that "inb(0x1F7) & ATA_SR_DRQ" either returns 0x00 or 0x08, but never one. For this reason, the while loop will always exit immediately.

In fact, you make this mistake several times in the posted code.


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Sat Feb 02, 2019 5:05 pm 
Offline
Member
Member

Joined: Wed Aug 30, 2017 8:24 am
Posts: 1593
In addition to what ziti pointed out, it is generally a bad idea to have busy wait loops without any kind of relaxation and timeout. I'm thinking something like

Code:
uint64_t to = clock() + ticks_from_ms(1000);
while ((inb(0x1f7) & ATA_SR_DRQ) && clock() < to) {
  asm("pause");
}


Of course, now you will have to check if DRQ is actually gone after the loop. Or you put the above in a function and formulate it a bit differently

Code:
int wait_for_drq0(int port) {
uint64_t to = clock() + ticks_from_ms(1000);
for (;;) {
  if (!(inb(port) & ATA_SR_DRQ)) return 0;
  if (clock >= to) return -ETIMEDOUT;
  asm ("pause");
}

_________________
Carpe diem!


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 11:30 am 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
Very thank you for help. But I have next problem. I make little change in my code(I am using emulator, not real hardware, then now I dont make timeout code):

Code:
void ata_sector(uint16_t base, uint8_t type, uint64_t addr, uint8_t drive) {
    uint16_t tmpword=0;

    if(drive==ATA_MASTER) {
    outb(base+ATA_PORT_DRV, 0xE0);
    }
    else { // ATA_SLAVE
    outb(base+ATA_PORT_DRV, 0xF0);
    }

    if ( ( (inb(base + ATA_PORT_STATUS) & ATA_SR_ERR)==ATA_SR_ERR ) ) {
        tp("ata error 2");
        return;
    }

    //PIO28
    outb(base+ATA_PORT_FEATURES, 0x00);
    outb(base+ATA_PORT_SCT_COUNT, 0x01);
    outb(base+ATA_PORT_SCT_NUMBER, (unsigned char)addr);
    outb(base+ATA_PORT_CYL_LOW, (unsigned char)(addr >> 8));
    outb(base+ATA_PORT_CYL_HIGH, (unsigned char)(addr >> 16));
    //type
    if(type==ATA_READ) {
    outb(base+ATA_PORT_COMMAND, ATA_CMD_READ_PIO);  // Send command
    }
    else {
    outb(base+ATA_PORT_COMMAND, ATA_CMD_WRITE_PIO);
    }

    //wait
    while (!(inb(0x1F7) & 0x08)) {}

    for (uint8_t idx = 0; idx < 255; idx++)
    {
        if(type==ATA_READ) {
            buffer[idx] = inw(base + ATA_PORT_DATA);
        }
        else {
            tmpword=(unsigned short)buffer[idx];
            outw(base + ATA_PORT_DATA, tmpword);
        }
    }

}


But the output is still 256. I try start thic code in Bochs and in terminal is lot of
Code:
00095230497e[DEV  ] write to port 0x01f0 with len 1 ignored

in write and in read:
Code:
00095230869e[DEV  ] read from port 0x01f0 with len 1 returns 0xff


Please, what is wrong? I dont see any error in my code, but emulators dont write or read from hard disc image.

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 12:03 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
Your "inw" and "outw" functions are wrong. They should be using words, but they're using bytes.


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 12:26 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
Thank you for answer, but Virtualbox now still send 0 (I was try something write and nothing happend) and in Bochs is output 255 and in terminal is the same as I write.

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 12:44 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
If Bochs is still displaying those errors, it means your "inw" and "outw" functions are still wrong.


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 12:49 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
But I am change "inw" and "outw" on "inb" and "outb".

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 12:58 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
I think you've misunderstood something. You should be using "inw" and "outw" to read/write to ATA_PORT_DATA. The problem is your "inw" and "outw" don't work.


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 1:04 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
My "inw" and "outw" code:
Code:
static inline uint16_t inw(uint16_t port)
{
    uint16_t ret;
    asm volatile ( "inb %1, %0"
                   : "=a"(ret)
                   : "Nd"(port) );
    return ret;
}

static inline void outw(uint16_t port, uint16_t val)
{
    asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );
}


Please what is wrong?

//EDIT: Bochs send to data port number 511

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Mon Feb 04, 2019 1:33 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5099
Klakap wrote:
Code:
    asm volatile ( "inb %1, %0"
    asm volatile ( "outb %0, %1" : : "a"(val), "Nd"(port) );

Shouldn't those be "inw" and "outw"?


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Tue Feb 05, 2019 1:45 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
Very thank you! Now, Bochs dont respond any messages, but I cant write anything. Output is still 0. Too same in qemu. Please whats wrong?

//EDIT: Virtualbox output is strange:
Image

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Wed Feb 06, 2019 3:37 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Hi,
Klakap wrote:
Code:
    //wait
    while (!(inb(0x1F7) & 0x08)) {}

Here you are waiting for the DRQ bit to become set. What if it never becomes set? You will wait here for a long time...

Klakap wrote:
Code:
    for (uint8_t idx = 0; idx < 255; idx++)
    {
        if(type==ATA_READ) {
            buffer[idx] = inw(base + ATA_PORT_DATA);
        }
        else {
            tmpword=(unsigned short)buffer[idx];
            outw(base + ATA_PORT_DATA, tmpword);
        }
    }

There are a lot of errors with that block of code. Is uint8_t an 8-bit unsigned byte? If so, idx will never get to the last word you want to write (or read). If you check for below 255, the last word is ignored. The controller will always wait for that last word to be read/written unless you issue another command or a reset. Changing to:
Code:
    for (uint8_t idx = 0; idx < 256; idx++)

will cause a lot more problems than you think. Hint: it is okay to use machine-sized integers within 'for' loops, i.e.: the 'int' keyword.

Also, what type (and size) is buffer? If buffer is a 16-bit word sized, then your read is okay, and your write is okay too, but why the tmpword? With the tmpword, this tells me that your buffer is probably a byte sized buffer and if so, you got all kinds of problems. First, on the read, you overwrite the high byte of every previous word written. Second, on the read (and write) you point to the next indexed byte, not word.

What size is your buffer? When I ask size, what size is an element of that buffer? Byte, Word, DWord, etc.?

-Ben
http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata
PostPosted: Thu Feb 07, 2019 1:01 pm 
Offline
Member
Member

Joined: Sat Mar 10, 2018 10:16 am
Posts: 296
Very thank you for your advice! I am change code and Bochs now working good without any error. I am very pleased with it. I have only one question. When I start this code in qemu or Virtualbox, first ata read/write command work good. Second command is stuck on while. Please why?

My code:
Code:
uint16_t buffer[255];

void ata_sector(uint16_t base, uint8_t type, uint64_t addr, uint8_t drive) {
    if(drive==ATA_MASTER) {
    outb(base+ATA_PORT_DRV, 0xE0);
    }
    else { // ATA_SLAVE
    outb(base+ATA_PORT_DRV, 0xF0);
    }

    if ( ( (inb(base + ATA_PORT_STATUS) & ATA_SR_ERR)==ATA_SR_ERR ) ) {
        tp("ata error 2");
        return;
    }

    //PIO28
    outb(base+ATA_PORT_FEATURES, 0x00);
    outb(base+ATA_PORT_SCT_COUNT, 0x01);
    outb(base+ATA_PORT_SCT_NUMBER, (unsigned char)addr);
    outb(base+ATA_PORT_CYL_LOW, (unsigned char)(addr >> 8));
    outb(base+ATA_PORT_CYL_HIGH, (unsigned char)(addr >> 16));
    //type
    if(type==ATA_READ) {
    outb(base+ATA_PORT_COMMAND, 0x20);  // Send command
    }
    else {
    outb(base+ATA_PORT_COMMAND, 0x30);
    }

    //wait
    while (!(inb(base+ATA_PORT_STATUS) & 0x08)) {}

    for (int idx = 0; idx < 256; idx++)
    {
        if(type==ATA_READ) {
            buffer[idx] = inw(base + ATA_PORT_DATA);
        }
        else {
            outw(base + ATA_PORT_DATA, buffer[idx]);
        }
    }

}

_________________
https://github.com/VendelinSlezak/BleskOS


Top
 Profile  
 
 Post subject: Re: Problem with reading from ata[solved]
PostPosted: Thu Feb 07, 2019 6:11 pm 
Offline
Member
Member
User avatar

Joined: Sat Nov 22, 2014 6:33 pm
Posts: 934
Location: USA
Real quick, I have only a minute, but your buffer is short by a word. If you are reading 256 words, your buffer needs to be 256 words as well.

Also, you don't need to keep selecting the drive. Keep an account of which drive is selected. Then if you call this routine and the desired drive is already selected, skip the selection. This will save time with the read/write process. Of course if you are using 28-bit LBA's you must write to the ADDRESS (DEV_HEAD) register anyway. In this case, keep a byte representation of this register. After calculation of the new value, if it is the same as the old value, skip the write.

As for the stuck on the second read/write, did you acknowledge the interrupt by reading from the status register? The controller will not become ready until you acknowledge the interrupt, even if you have interrupts off.

Hope this helps,
Ben
- http://www.fysnet.net/osdesign_book_series.htm


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 47 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group