OSDev.org

The Place to Start for Operating System Developers
It is currently Sat Apr 27, 2024 7:54 am

All times are UTC - 6 hours




Post new topic Reply to topic  [ 3 posts ] 
Author Message
 Post subject: Reading data from ATA disk not working
PostPosted: Fri Jan 26, 2024 8:23 am 
Offline

Joined: Fri Jan 26, 2024 8:09 am
Posts: 2
Hello,
I've been trying to read data from ATA disk in PIO mode. Everything goes seemingly right, but when i check buffer with read data, only every second byte is read (ie. bytes 88 16 EC 7C read from my boot sector turn to 88 00 EC 00). I've tried to compare it with other drivers, but nothing really seems off with mine.

My code:

kernel.c
Code:
#include "kernel.h"

void kernel_main(){
    tty_set_color(GET_COLOR(COLOR_WHITE, COLOR_BLACK));
    tty_fill_screen();
    error_t error = ata_init(0);
    if(error == SUCCESS) tty_print("Success", 0);
    else {tty_print("Error ", 0); tty_print_number(error, 6);}

    error = ata_load_sectors(0, 1, (word*) 0x5000);
    if(error == SUCCESS) tty_print("Success", 80);
    else {tty_print("Error ", 80); tty_print_number(error, 86);}

    /* Print out first 4 bytes as integer */
    tty_print_number(*(int*) 0x5000, 160);
}




ata.c
Code:

#include "ata.h"

static int disk_number = -1;

#define ATA_ERROR_CHECK() {error_t error = ata_error_check(); \
                            if(error < 0) return error;}

#define ATA_WAIT_READY() {error_t error = ata_wait_for_ready(); \
                            if(error < 0) return error;}

error_t ata_wait_for_ready();
error_t ata_handle_error();
error_t ata_error_check();

error_t ata_init(int disk){
    if(disk < 0 || disk > 1) return ATA_INVALID_DISK_NUMBER_ERR;
    ports_IO_writeB(ATA_IO_REG_DRIVE_HEAD, disk == 0 ? 0xA0 : 0xB0);
    ports_IO_writeB(ATA_IO_REG_SECTOR_COUNT, 0);
    ports_IO_writeB(ATA_IO_REG_LBA_LOW, 0);
    ports_IO_writeB(ATA_IO_REG_LBA_MID, 0);
    ports_IO_writeB(ATA_IO_REG_LBA_HIGH, 0);

    /* 0xEC: IDENTIFY */
    ports_IO_writeB(ATA_IO_REG_CMD_STATUS, 0xEC);
   
    byte status = ports_IO_readB(ATA_IO_REG_CMD_STATUS);
   
    /* IDENTIFY command returning 0 means disk is not present */
    if(status == 0) return ATA_DISK_NOT_PRESENT_ERR;

    /* Wait for BUSY flag to clear */
    while(status >> 7){
        status = ports_IO_readB(ATA_IO_REG_CMD_STATUS);
    }

    /* If ports 0x1F4 or 0x1F5 are non-zero device is non-ATA */
    if(ports_IO_readB(ATA_IO_REG_LBA_MID) != 0) return ATA_DISK_NOT_ATA_ERR;
    if(ports_IO_readB(ATA_IO_REG_LBA_HIGH) != 0) return ATA_DISK_NOT_ATA_ERR;

    ATA_WAIT_READY()

    /* Read data about disk specification */
    uint16_t* disk_spec = (uint16_t*) 0x1500;
    for(int i = 0; i < 256; i++){
        disk_spec[i] = ports_IO_readW(ATA_IO_REG_DATA);
    }

    ATA_ERROR_CHECK()

    disk_number = disk;
    return SUCCESS;
}

/* Load sectors from disk
* @param LBA_adress 28-bit adress (sector number)
* @param sector_count number of sectors to read (up to 256)
* @param buffer pointer to buffer (should be at least sector_count * 512 bytes)
* @return error code
*/
error_t ata_load_sectors(uint32_t LBA_adress, byte sector_count, word* buffer){
    if(disk_number < 0) return ATA_NOT_INITIALIZED_ERR;
    if(!ATA_VERIFY_ADRESS(LBA_adress)) return ATA_INVALID_ADRESS_ERR;

    /* Select drive 0 + LBA adressing */
    byte port_write_data = (LBA_adress & 0xF000000 >> 24) | 0b11100000;
    ports_IO_writeB(ATA_IO_REG_DRIVE_HEAD, port_write_data);

    ports_IO_writeB(ATA_IO_REG_SECTOR_COUNT, sector_count);
    ports_IO_writeB(ATA_IO_REG_LBA_LOW, LBA_adress & 0xFF);
    ports_IO_writeB(ATA_IO_REG_LBA_MID, (LBA_adress & 0xFF00) >> 8);
    ports_IO_writeB(ATA_IO_REG_LBA_HIGH, (LBA_adress & 0xFF0000) >> 16);

    /* 0x20: read sector(s) */
    ports_IO_writeB(ATA_IO_REG_CMD_STATUS, 0x20);

    ATA_WAIT_READY()

    int transfer_length = 256*sector_count;
    for(int i = 0; i < transfer_length; i++){
        word temp = ports_IO_readW(ATA_IO_REG_DATA);
        buffer[i] = temp;
    }

    ATA_ERROR_CHECK()

    return SUCCESS;
}

error_t ata_wait_for_ready(){

    // TODO: replace polling with IRQ
    int repeats = 0;
    while (true){
        byte status = ports_IO_readB(ATA_IO_REG_CMD_STATUS);
        if((status & 0b1000) >> 3) return SUCCESS;
        if(repeats++ < 4) continue;
        if(status & 0b1) return ata_handle_error();
        if(status & 0b00100000 >> 5) return ATA_DRIVE_FAULT_ERR;
    }
}

error_t ata_handle_error(){
    byte status = ports_IO_readB(ATA_IO_REG_ERROR);
    switch(status){
        case 0x01: return ATA_ADDR_MARK_NOT_FOUND_ERR;
        case 0x02: return ATA_ADDR_TRK_ZERO_NOT_FOUND_ERR;
        case 0x04: return ATA_ABORTED_ERR;
        case 0x08: return ATA_MEDIA_CHANGE_REQUEST_ERR;
        case 0x10: return ATA_ID_NOT_FOUND_ERR;
        case 0x20: return ATA_MEDIA_CHANGED_ERR;
        case 0x40: return ATA_UNCORRECTABLE_DATA_ERROR_ERR;
        case 0x80: return ATA_BAD_BLOCK_DETECTED_ERR;
    }
    return ATA_GENERIC_ERR;
}

error_t ata_error_check(){
    byte status = ports_IO_readB(ATA_IO_REG_CMD_STATUS);
    if(status & 0b1) return ata_handle_error();
    return SUCCESS;
}


ports.c
Code:
#include "ports.h"

byte ports_IO_readB (uint16_t port) {
    byte result;
    asm volatile ("in %%dx, %%al" : "=a" (result) : "d" (port));
    return result;
}

void ports_IO_writeB (uint16_t port, byte data) {
    asm volatile ("out %%al, %%dx" : : "a" (data), "d" (port));
}

word ports_IO_readW (uint16_t port) {
    byte result;
    asm volatile ("in %%dx, %%ax" : "=a" (result) : "d" (port));
    return result;
}

void ports_IO_writeW (uint16_t port, word data) {
    asm volatile ("out %%ax, %%dx" : : "a" (data), "d" (port));
}


Thanks for your help :)


Top
 Profile  
 
 Post subject: Re: Reading data from ATA disk not working
PostPosted: Sun Jan 28, 2024 11:44 am 
Offline

Joined: Tue Feb 22, 2011 12:53 pm
Posts: 8
Looks like a copy-paste error in ports_IO_readW: "byte result" should be "word result".


Top
 Profile  
 
 Post subject: Re: Reading data from ATA disk not working
PostPosted: Tue Jan 30, 2024 9:15 am 
Offline

Joined: Fri Jan 26, 2024 8:09 am
Posts: 2
Yes, that was it, thank you so much


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: No registered users and 11 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