OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:02 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: AHCI can't read and write blocks
PostPosted: Thu Jun 09, 2022 10:27 pm 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
I try to use AHCI to visit my sata disk in my os. I can find port 0, rebase the hba memory correctly. I had set port 0's command issue to (1 << slot), waiting the device to respond but not. ci keeps 1, sig keeps 0x101, is and serr keep 0, sstr keeps 0x113 and tfd keeps 0x50. I am confused about it.

My code:
ahci.h:
Code:
#ifndef AHCI_H
#define AHCI_H

#include <bits/stdint-uintn.h>
#include <stdbool.h>

#define FIS_DEV_BITS uint16_t

#define HBA_PxCMD_ST    0x0001
#define HBA_PxCMD_FRE   0x0010
#define HBA_PxCMD_FR    0x4000
#define HBA_PxCMD_CR    0x8000
#define HBA_PxIS_TFES   (1 << 30)

#define ATA_DEV_BUSY 0x80
#define ATA_DEV_DRQ 0x08

#define ATA_CMD_READ_DMA_EX     0x25
#define ATA_CMD_WRITE_DMA_EX     0x35

#define   SATA_SIG_ATA   0x00000101   // SATA drive
#define   SATA_SIG_ATAPI   0xEB140101   // SATAPI drive
#define   SATA_SIG_SEMB   0xC33C0101   // Enclosure management bridge
#define   SATA_SIG_PM   0x96690101   // Port multiplier

#define AHCI_DEV_NULL 0
#define AHCI_DEV_SATA 1
#define AHCI_DEV_SEMB 2
#define AHCI_DEV_PM 3
#define AHCI_DEV_SATAPI 4

#define HBA_PORT_IPM_ACTIVE 1
#define HBA_PORT_DET_PRESENT 3

typedef enum
{
   FIS_TYPE_REG_H2D   = 0x27,   // Register FIS - host to device
   FIS_TYPE_REG_D2H   = 0x34,   // Register FIS - device to host
   FIS_TYPE_DMA_ACT   = 0x39,   // DMA activate FIS - device to host
   FIS_TYPE_DMA_SETUP   = 0x41,   // DMA setup FIS - bidirectional
   FIS_TYPE_DATA      = 0x46,   // Data FIS - bidirectional
   FIS_TYPE_BIST      = 0x58,   // BIST activate FIS - bidirectional
   FIS_TYPE_PIO_SETUP   = 0x5F,   // PIO setup FIS - device to host
   FIS_TYPE_DEV_BITS   = 0xA1,   // Set device bits FIS - device to host
} FIS_TYPE;

typedef struct
{
   // DWORD 0
   uint8_t  fis_type;   // FIS_TYPE_REG_H2D

   uint8_t  pmport:4;   // Port multiplier
   uint8_t  rsv0:3;      // Reserved
   uint8_t  c:1;      // 1: Command, 0: Control

   uint8_t  command;   // Command register
   uint8_t  featurel;   // Feature register, 7:0

   // DWORD 1
   uint8_t  lba0;      // LBA low register, 7:0
   uint8_t  lba1;      // LBA mid register, 15:8
   uint8_t  lba2;      // LBA high register, 23:16
   uint8_t  device;      // Device register

   // DWORD 2
   uint8_t  lba3;      // LBA register, 31:24
   uint8_t  lba4;      // LBA register, 39:32
   uint8_t  lba5;      // LBA register, 47:40
   uint8_t  featureh;   // Feature register, 15:8

   // DWORD 3
   uint8_t  countl;      // Count register, 7:0
   uint8_t  counth;      // Count register, 15:8
   uint8_t  icc;      // Isochronous command completion
   uint8_t  control;   // Control register

   // DWORD 4
   uint8_t  rsv1[4];   // Reserved
} FIS_REG_H2D;

typedef struct
{
   // DWORD 0
   uint8_t  fis_type;    // FIS_TYPE_REG_D2H

   uint8_t  pmport:4;    // Port multiplier
   uint8_t  rsv0:2;      // Reserved
   uint8_t  i:1;         // Interrupt bit
   uint8_t  rsv1:1;      // Reserved

   uint8_t  status;      // Status register
   uint8_t  error;       // Error register

   // DWORD 1
   uint8_t  lba0;        // LBA low register, 7:0
   uint8_t  lba1;        // LBA mid register, 15:8
   uint8_t  lba2;        // LBA high register, 23:16
   uint8_t  device;      // Device register

   // DWORD 2
   uint8_t  lba3;        // LBA register, 31:24
   uint8_t  lba4;        // LBA register, 39:32
   uint8_t  lba5;        // LBA register, 47:40
   uint8_t  rsv2;        // Reserved

   // DWORD 3
   uint8_t  countl;      // Count register, 7:0
   uint8_t  counth;      // Count register, 15:8
   uint8_t  rsv3[2];     // Reserved

   // DWORD 4
   uint8_t  rsv4[4];     // Reserved
} FIS_REG_D2H;

typedef struct
{
   // DWORD 0
   uint8_t  fis_type;   // FIS_TYPE_DATA

   uint8_t  pmport:4;   // Port multiplier
   uint8_t  rsv0:4;      // Reserved

   uint8_t  rsv1[2];   // Reserved

   // DWORD 1 ~ N
   uint32_t data[1];   // Payload
} FIS_DATA;

typedef struct
{
   // DWORD 0
   uint8_t  fis_type;   // FIS_TYPE_PIO_SETUP

   uint8_t  pmport:4;   // Port multiplier
   uint8_t  rsv0:1;      // Reserved
   uint8_t  d:1;      // Data transfer direction, 1 - device to host
   uint8_t  i:1;      // Interrupt bit
   uint8_t  rsv1:1;

   uint8_t  status;      // Status register
   uint8_t  error;      // Error register

   // DWORD 1
   uint8_t  lba0;      // LBA low register, 7:0
   uint8_t  lba1;      // LBA mid register, 15:8
   uint8_t  lba2;      // LBA high register, 23:16
   uint8_t  device;      // Device register

   // DWORD 2
   uint8_t  lba3;      // LBA register, 31:24
   uint8_t  lba4;      // LBA register, 39:32
   uint8_t  lba5;      // LBA register, 47:40
   uint8_t  rsv2;      // Reserved

   // DWORD 3
   uint8_t  countl;      // Count register, 7:0
   uint8_t  counth;      // Count register, 15:8
   uint8_t  rsv3;      // Reserved
   uint8_t  e_status;   // New value of status register

   // DWORD 4
   uint16_t tc;      // Transfer count
   uint8_t  rsv4[2];   // Reserved
} FIS_PIO_SETUP;

typedef struct
{
   // DWORD 0
   uint8_t  fis_type;   // FIS_TYPE_DMA_SETUP

   uint8_t  pmport:4;   // Port multiplier
   uint8_t  rsv0:1;      // Reserved
   uint8_t  d:1;      // Data transfer direction, 1 - device to host
   uint8_t  i:1;      // Interrupt bit
   uint8_t  a:1;            // Auto-activate. Specifies if DMA Activate FIS is needed

        uint8_t  rsved[2];       // Reserved

   //DWORD 1&2

        uint64_t DMAbufferID;    // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
                                 // SATA Spec says host specific and not in Spec. Trying AHCI spec might work.

        //DWORD 3
        uint32_t rsvd;           //More reserved

        //DWORD 4
        uint32_t DMAbufOffset;   //Byte offset into buffer. First 2 bits must be 0

        //DWORD 5
        uint32_t TransferCount;  //Number of bytes to transfer. Bit 0 must be 0

        //DWORD 6
        uint32_t resvd;          //Reserved

} FIS_DMA_SETUP;

typedef volatile struct
{
   uint32_t clb;      // 0x00, command list base address, 1K-byte aligned
   uint32_t clbu;      // 0x04, command list base address upper 32 bits
   uint32_t fb;      // 0x08, FIS base address, 256-byte aligned
   uint32_t fbu;      // 0x0C, FIS base address upper 32 bits
   uint32_t is;      // 0x10, interrupt status
   uint32_t ie;      // 0x14, interrupt enable
   uint32_t cmd;      // 0x18, command and status
   uint32_t rsv0;      // 0x1C, Reserved
   uint32_t tfd;      // 0x20, task file data
   uint32_t sig;      // 0x24, signature
   uint32_t ssts;      // 0x28, SATA status (SCR0:SStatus)
   uint32_t sctl;      // 0x2C, SATA control (SCR2:SControl)
   uint32_t serr;      // 0x30, SATA error (SCR1:SError)
   uint32_t sact;      // 0x34, SATA active (SCR3:SActive)
   uint32_t ci;      // 0x38, command issue
   uint32_t sntf;      // 0x3C, SATA notification (SCR4:SNotification)
   uint32_t fbs;      // 0x40, FIS-based switch control
   uint32_t rsv1[11];   // 0x44 ~ 0x6F, Reserved
   uint32_t vendor[4];   // 0x70 ~ 0x7F, vendor specific
} HBA_PORT;

typedef volatile struct
{
   // 0x00 - 0x2B, Generic Host Control
   uint32_t cap;      // 0x00, Host capability
   uint32_t ghc;      // 0x04, Global host control
   uint32_t is;      // 0x08, Interrupt status
   uint32_t pi;      // 0x0C, Port implemented
   uint32_t vs;      // 0x10, Version
   uint32_t ccc_ctl;   // 0x14, Command completion coalescing control
   uint32_t ccc_pts;   // 0x18, Command completion coalescing ports
   uint32_t em_loc;      // 0x1C, Enclosure management location
   uint32_t em_ctl;      // 0x20, Enclosure management control
   uint32_t cap2;      // 0x24, Host capabilities extended
   uint32_t bohc;      // 0x28, BIOS/OS handoff control and status

   // 0x2C - 0x9F, Reserved
   uint8_t  rsv[0xA0-0x2C];

   // 0xA0 - 0xFF, Vendor specific registers
   uint8_t  vendor[0x100-0xA0];

   // 0x100 - 0x10FF, Port control registers
   HBA_PORT   ports[1];   // 1 ~ 32
} HBA_MEM;

// typedef volatile struct
// {
//    // 0x00
//    FIS_DMA_SETUP   dsfis;      // DMA Setup FIS
//    uint8_t         pad0[4];
// 
//    // 0x20
//    FIS_PIO_SETUP   psfis;      // PIO Setup FIS
//    uint8_t         pad1[12];
// 
//    // 0x40
//    FIS_REG_D2H   rfis;      // Register – Device to Host FIS
//    uint8_t         pad2[4];
// 
//    // 0x58
//    FIS_DEV_BITS   sdbfis;      // Set Device Bit FIS
// 
//    // 0x60
//    uint8_t         ufis[64];
// 
//    // 0xA0
//    uint8_t      rsv[0x100-0xA0];
// } HBA_FIS;

typedef struct
{
   // DW0
   uint8_t  cfl:5;      // Command FIS length in DWORDS, 2 ~ 16
   uint8_t  a:1;      // ATAPI
   uint8_t  w:1;      // Write, 1: H2D, 0: D2H
   uint8_t  p:1;      // Prefetchable

   uint8_t  r:1;      // Reset
   uint8_t  b:1;      // BIST
   uint8_t  c:1;      // Clear busy upon R_OK
   uint8_t  rsv0:1;      // Reserved
   uint8_t  pmp:4;      // Port multiplier port

   uint16_t prdtl;      // Physical region descriptor table length in entries

   // DW1
   volatile
   uint32_t prdbc;      // Physical region descriptor byte count transferred

   // DW2, 3
   uint32_t ctba;      // Command table descriptor base address
   uint32_t ctbau;      // Command table descriptor base address upper 32 bits

   // DW4 - 7
   uint32_t rsv1[4];   // Reserved
} HBA_CMD_HEADER;

typedef struct
{
   uint32_t dba;      // Data base address
   uint32_t dbau;      // Data base address upper 32 bits
   uint32_t rsv0;      // Reserved

   // DW3
   uint32_t dbc:22;      // Byte count, 4M max
   uint32_t rsv1:9;      // Reserved
   uint32_t i:1;      // Interrupt on completion
} HBA_PRDT_ENTRY;

typedef struct tagHBA_CMD_TBL
{
   // 0x00
   uint8_t  cfis[64];   // Command FIS

   // 0x40
   uint8_t  acmd[16];   // ATAPI command, 12 or 16 bytes

   // 0x50
   uint8_t  rsv[48];   // Reserved

   // 0x80
   HBA_PRDT_ENTRY   prdt_entry[1];   // Physical region descriptor table entries, 0 ~ 65535
} HBA_CMD_TBL;

void start_cmd();
void stop_cmd();
void ahci_init(uint64 base);
int read_port(uint32 startl, uint32 starth, uint32 count, uint64 buf);
int write_port(uint32 startl, uint32 starth, uint32 count, uint64 buf);
int find_cmdslot();
void rebase_port();
void start_cmd();
void stop_cmd();
void probe_port(HBA_MEM *abar_temp);


#endif


ahci.c
Code:
#include "kernel/include/xtos.h"
#include "kernel/include/ahci.h"

static HBA_MEM *abar;
static int portno = -1;

#define PORT (abar -> ports + portno)
#define AHCI_BASE (uint64) abar

void ahci_init(uint64 ahci_base) {
    probe_port((HBA_MEM *) ahci_base);
}

// /*
//  Code Reference :  OSDEV
//  */
// void handler_ahci_routine()
// {
//     printf("AHCI INTERRUPT HANDLER\n");
//     if (abar->ports[0].is & HBA_PxIS_TFES)
//         printf("Read disk error\n");
//     printf("\n TFD=[%d]", ((HBA_PORT *) &abar->ports[0])->tfd);
//     printf("\nSSTS =[%d]", ((HBA_PORT *) &abar->ports[0])->ssts);
//     printf("\nIE=[%d]", ((HBA_PORT *) &abar->ports[0])->ie);
//     printf("\nSERR%d", ((HBA_PORT *) &abar->ports[0])->serr);
//     printf("\nIS%d", ((HBA_PORT *) &abar->ports[0])->is);
//     abar->ports[0].is = 0xffff;
//     while (1)
//         ;
// }
/*
Code Reference : OSDEV
*/
int read_port(uint32 startl, uint32 starth, uint32 count,
        uint64 buf)
{
    PORT->is = 0xffff; // Clear pending interrupt bits
    int slot = find_cmdslot(PORT);
    if (slot == -1)
        return -1;
    HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)(PORT->clb | DMWIN_MASK);
    cmdheader += slot;
    cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32); // Command FIS size
    cmdheader->w = 0; // Read from device
    cmdheader->c = 1; // Read from device
    cmdheader->p = 1; // Read from device
    cmdheader->prdtl = (uint16) ((count - 1) >> 4) + 1; // PRDT entries count
    HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)(cmdheader->ctba | DMWIN_MASK);
    int i = 0;
    for (i = 0; i < cmdheader->prdtl - 1; i++)
    {
        cmdtbl->prdt_entry[i].dba = (uint32) (buf & 0xFFFFFFFF);
        cmdtbl->prdt_entry[i].dbau = (uint32) ((buf >> 32) & 0xFFFFFFFF);
        cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes
        cmdtbl->prdt_entry[i].i = 0;
        buf += 4 * 1024; // 4K words
        count -= 16; // 16 sectors
    }
    cmdtbl->prdt_entry[i].dba = (uint32) (buf & 0xFFFFFFFF);
    cmdtbl->prdt_entry[i].dbau = (uint32) ((buf >> 32) & 0xFFFFFFFF);
    cmdtbl->prdt_entry[i].dbc = count << 9; // 512 bytes per sector
    cmdtbl->prdt_entry[i].i = 0;
    FIS_REG_H2D *cmdfis = (FIS_REG_H2D*) (&cmdtbl->cfis);
    cmdfis->fis_type = FIS_TYPE_REG_H2D;
    cmdfis->c = 1; // Command
    cmdfis->command = ATA_CMD_READ_DMA_EX;
    cmdfis->lba0 = (uint8) startl;
    cmdfis->lba1 = (uint8) (startl >> 8);
    cmdfis->lba2 = (uint8) (startl >> 16);
    cmdfis->device = 1 << 6; // LBA mode
    cmdfis->lba3 = (uint8) (startl >> 24);
    cmdfis->lba4 = (uint8) starth;
    cmdfis->lba5 = (uint8) (starth >> 8);
    cmdfis->countl = count & 0xff;
    cmdfis->counth = count >> 8;
   
    int spin = 0;
    while ((PORT->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000)
   {
      spin++;
   }
   if (spin == 1000000)
   {
      printf("Port is hung\n");
      return -1;
   }
    PORT->ci = (1 << slot);
    printf("0x%x 0x%x\n", PORT->ci, PORT->is);
    while (1)
    {
        if ((PORT->ci & (1 << slot)) == 0)
            break;
        if (PORT->is & HBA_PxIS_TFES)
        { // Task file error
            printf("Read disk error\n");
            return -1;
        }
    }
    if (PORT->is & HBA_PxIS_TFES)
    {
        printf("Read disk error\n");
        return -1;
    }
    while (PORT->ci != 0)
    {
        printf("Read disk error\n");
    }
    return 0;
}
/*
Code Reference : OSDEV
*/
int write_port(uint32 startl, uint32 starth, uint32 count,
        uint64 buf)
{
    PORT->is = 0xffff; // Clear pending interrupt bits
    int slot = find_cmdslot(PORT);
    if (slot == -1)
        return -1;
    HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)(PORT->clb | DMWIN_MASK);
    cmdheader += slot;
    cmdheader->cfl = sizeof(FIS_REG_H2D) / sizeof(uint32); // Command FIS size
    cmdheader->w = 1; // Read from device
    cmdheader->c = 1; // Read from device
    cmdheader->p = 1; // Read from device
    cmdheader->prdtl = (uint16) ((count - 1) >> 4) + 1; // PRDT entries count
    HBA_CMD_TBL *cmdtbl = (HBA_CMD_TBL*)(cmdheader->ctba | DMWIN_MASK);
    int i = 0;
    for (i = 0; i < cmdheader->prdtl - 1; i++)
    {
        cmdtbl->prdt_entry[i].dba = (uint32) (buf & 0xFFFFFFFF);
        cmdtbl->prdt_entry[i].dbau = (uint32) ((buf >> 32) & 0xFFFFFFFF);
        cmdtbl->prdt_entry[i].dbc = 8 * 1024 - 1; // 8K bytes
        cmdtbl->prdt_entry[i].i = 0;
        buf += 4 * 1024; // 4K words
        count -= 16; // 16 sectors
    }
    cmdtbl->prdt_entry[i].dba = (uint32) (buf & 0xFFFFFFFF);
    cmdtbl->prdt_entry[i].dbau = (uint32) ((buf >> 32) & 0xFFFFFFFF);
    cmdtbl->prdt_entry[i].dbc = count << 9; // 512 bytes per sector
    cmdtbl->prdt_entry[i].i = 0;
    FIS_REG_H2D *cmdfis = (FIS_REG_H2D*) (&cmdtbl->cfis);
    cmdfis->fis_type = FIS_TYPE_REG_H2D;
    cmdfis->c = 1; // Command
    cmdfis->command = ATA_CMD_WRITE_DMA_EX;
    cmdfis->lba0 = (uint8) startl;
    cmdfis->lba1 = (uint8) (startl >> 8);
    cmdfis->lba2 = (uint8) (startl >> 16);
    cmdfis->device = 1 << 6; // LBA mode
    cmdfis->lba3 = (uint8) (startl >> 24);
    cmdfis->lba4 = (uint8) starth;
    cmdfis->lba5 = (uint8) (starth >> 8);
    cmdfis->countl = count & 0xff;
    cmdfis->counth = count >> 8;
   
    int spin = 0;
    while ((PORT->tfd & (ATA_DEV_BUSY | ATA_DEV_DRQ)) && spin < 1000000)
   {
      spin++;
   }
   if (spin == 1000000)
   {
      printf("Port is hung\n");
      return -1;
   }
   
    PORT->ci = (1 << slot);
    while (1)
    {
        // In some longer duration reads, it may be helpful to spin on the DPS bit
        // in the PxIS port field as well (1 << 5)
        if ((PORT->ci & (1 << slot)) == 0)
            break;
        if (PORT->is & HBA_PxIS_TFES)
        { // Task file error
            printf("Read disk error\n");
            return -1;
        }
    }
    if (PORT->is & HBA_PxIS_TFES)
    {
        printf("Read disk error\n");
        return -1;
    }
    while (PORT->ci != 0)
    {
        printf("Read disk error\n");
    }
    return 0;
}
// To setup command fing a free command list slot
int find_cmdslot()
{
    uint32 slots = (PORT->sact | PORT->ci);
    int num_of_slots = (abar->cap & 0x0f00) >> 8; // Bit 8-12
    int i;
    for (i = 0; i < num_of_slots; i++)
    {
        if ((slots & 1) == 0)
        {
            //      printf("[slot=%d]", i);
            //   if(i==0)
            return i;
            //   break;
        }
        slots >>= 1;
    }
    printf("Cannot find free command list entry\n");
    return -1;
}
// Check device type
static int check_type(HBA_PORT * port)
{
    uint32 ssts = port->ssts;
    uint8 ipm = (ssts >> 8) & 0x0F;
    uint8 det = ssts & 0x0F;
    //printf ("\n ipm %d det %d sig %d", ipm, det, PORT->sig);
    if (det != HBA_PORT_DET_PRESENT) // Check drive status
        return AHCI_DEV_NULL;
    if (ipm != HBA_PORT_IPM_ACTIVE)
        return AHCI_DEV_NULL;
    switch (port->sig)
    {
        case SATA_SIG_ATAPI:
            return AHCI_DEV_SATAPI;
        case SATA_SIG_SEMB:
            return AHCI_DEV_SEMB;
        case SATA_SIG_PM:
            return AHCI_DEV_PM;
        default:
            return AHCI_DEV_SATA;
    }
    return 0;
}
/*
Code Reference : OSDEV
*/
void rebase_port()
{
   stop_cmd(PORT);   // Stop command engine

   // Command list offset: 1K*portno
   // Command list entry size = 32
   // Command list entry maxim count = 32
   // Command list maxim size = 32*32 = 1K per port
   PORT->clb = AHCI_BASE + (portno<<10);
   PORT->clbu = 0;
   memset((void*)((PORT->clb) | DMWIN_MASK) , 0, 1024);

   // FIS offset: 32K+256*portno
   // FIS entry size = 256 bytes per port
   PORT->fb = AHCI_BASE + (32<<10) + (portno<<8);
   PORT->fbu = 0;
   memset((void*)((PORT->fb) | DMWIN_MASK), 0, 256);

   // Command table offset: 40K + 8K*portno
   // Command table size = 256*32 = 8K per port
   HBA_CMD_HEADER *cmdheader = (HBA_CMD_HEADER*)((PORT->clb) | DMWIN_MASK);
   for (int i=0; i<32; i++)
   {
      cmdheader[i].prdtl = 8;   // 8 prdt entries per command table
               // 256 bytes per command table, 64+16+48+16*8
      // Command table offset: 40K + 8K*portno + cmdheader_index*256
      cmdheader[i].ctba = AHCI_BASE + (40<<10) + (portno<<13) + (i<<8);
      cmdheader[i].ctbau = 0;
      memset((void*)(cmdheader[i].ctba | DMWIN_MASK) , 0, 256);
   }

   start_cmd(PORT);   // Start command engine
}

// Start command engine
void start_cmd()
{
   // Wait until CR (bit15) is cleared
   while (PORT->cmd & HBA_PxCMD_CR)
      ;

   // Set FRE (bit4) and ST (bit0)
   PORT->cmd |= HBA_PxCMD_FRE;
   PORT->cmd |= HBA_PxCMD_ST;
}

// Stop command engine
void stop_cmd()
{
   // Clear ST (bit0)
   PORT->cmd &= ~HBA_PxCMD_ST;

   // Clear FRE (bit4)
   PORT->cmd &= ~HBA_PxCMD_FRE;

   // Wait until FR (bit14), CR (bit15) are cleared
   while(1)
   {
      if (PORT->cmd & HBA_PxCMD_FR)
         continue;
      if (PORT->cmd & HBA_PxCMD_CR)
         continue;
      break;
   }

}
/*
Code Reference : OSDEV
*/
void probe_port(HBA_MEM *abar_temp)
{
    printf("Inside probe_port\n");
    // Search disk in impelemented ports
    uint32 pi = abar_temp->pi;
    int i = 0;
    while (i < 32)
    {
        if (pi & 1)
        {
            int dt = check_type((HBA_PORT *) &abar_temp->ports[i]);
            if (dt == AHCI_DEV_SATA)
            {
                printf("\nSATA drive found at port %d\n", i);
                abar = abar_temp;
                portno = i;
                rebase_port();
                printf("DONE AHCI INITIALISATION :: PORT REBASE\n");
                return;
            }
            else if (dt == AHCI_DEV_SATAPI)
            {
                printf("\nSATAPI drive found at port %d\n", i);
            }
            else if (dt == AHCI_DEV_SEMB)
            {
                printf("\nSEMB drive found at port %d\n", i);
            }
            else if (dt == AHCI_DEV_PM)
            {
                printf("\nPM drive found at port %d\n", i);
            }
            else
            {
                printf("\nNo drive found at port %d\n", i);
            }
        }
        pi >>= 1;
        i++;
    }
    printf("probe_port complete\n");
}



Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Tue Jun 14, 2022 10:32 am 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
Does your OS use paging? The example code on the wiki makes no distinction between physical and virtual address, and the AHCI HBA can only access physical addresses.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Wed Jun 22, 2022 7:15 pm 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
Octocontrabass wrote:
Does your OS use paging? The example code on the wiki makes no distinction between physical and virtual address, and the AHCI HBA can only access physical addresses.

I use efi application to start and didn't write any code about paging.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 5:39 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
Is your code 32-bit or 64-bit?


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 6:58 am 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
iansjack wrote:
Is your code 32-bit or 64-bit?

64 bit


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 7:27 am 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
Then you are using paging. UEFI will have set up a simple page table for you.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 10:39 am 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
iansjack wrote:
Then you are using paging. UEFI will have set up a simple page table for you.

Does the default paging affect ahci's work?I think that the virtual address is equal to the real address, so the ahci controller will visit proper registers.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 2:59 pm 
Offline
Member
Member
User avatar

Joined: Sat Mar 31, 2012 3:07 am
Posts: 4591
Location: Chichester, UK
I’m not sure of the answer to that (although I’m sure someone will provide it), but I would expect UEFI to only map those pages it uses. So I would not expect it to map the ahci controller address space.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 6:52 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
UEFI page tables are only guaranteed to identity map addresses listed in the UEFI memory map.

Did you call ExitBootServices()? You need to do that before accessing the AHCI controller.

Is GHC.AE (bit 31) set to 1? The controller won't work correctly if GHC.AE is 0.

In stop_cmd(), you are not waiting for PxCMD.CR to clear before you clear PxCMD.FRE. You must wait for PxCMD.CR to be 0 before you can set PxCMD.FRE to 0.

What is DMWIN_MASK?


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Thu Jun 23, 2022 9:06 pm 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
Octocontrabass wrote:
UEFI page tables are only guaranteed to identity map addresses listed in the UEFI memory map.

Did you call ExitBootServices()? You need to do that before accessing the AHCI controller.

Is GHC.AE (bit 31) set to 1? The controller won't work correctly if GHC.AE is 0.

In stop_cmd(), you are not waiting for PxCMD.CR to clear before you clear PxCMD.FRE. You must wait for PxCMD.CR to be 0 before you can set PxCMD.FRE to 0.

What is DMWIN_MASK?


I called ExitBootServices. GHC.AE is set to 1. I added while (PORT->cmd & HBA_PxCMD_CR); just now but not make sense. DMWIN_MASK is set to 0 now because I don't need it any more.
I have put my code on github: https://github.com/prcups/xtos-x86-clone.git


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Fri Jun 24, 2022 8:38 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
You should detect the AHCI controller instead of hardcoding its address.

In the example code on the wiki, AHCI_BASE refers to a chunk of free memory used by the AHCI driver. It is not ABAR. In a real driver, you should assign memory dynamically instead of using a fixed address.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Sat Jun 25, 2022 6:39 am 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
Octocontrabass wrote:


I know in the end I have to enumerate pci devices to find the correct sata controller. Now I just use pci base address from ACPI and bus/device/function id found at qemu and uefi for test. The address of abar is sata controller's pci base address offset 9 (bar 5).


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Sat Jun 25, 2022 3:28 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
Does it work when AHCI_BASE points to RAM instead of ABAR?


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Sun Jun 26, 2022 7:00 am 
Offline

Joined: Thu Jun 09, 2022 9:48 pm
Posts: 10
Octocontrabass wrote:
Does it work when AHCI_BASE points to RAM instead of ABAR?

Same as before. I create a memory area and transfer its address to AHCI_BASE. Nothing changed.


Top
 Profile  
 
 Post subject: Re: AHCI can't read and write blocks
PostPosted: Sun Jun 26, 2022 4:22 pm 
Offline
Member
Member

Joined: Mon Mar 25, 2013 7:01 pm
Posts: 5100
Really? It successfully reads the disk when I do that. Where are you allocating this memory area?

Have you tried using debug tracing? For example, try adding "-d trace:handle_cmd_*" to your QEMU command line. There's a list of available trace events here.


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: Bing [Bot] and 59 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