AHCI can't read and write blocks

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
prcups
Posts: 10
Joined: Thu Jun 09, 2022 9:48 pm
Contact:

AHCI can't read and write blocks

Post by prcups »

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: Select all

#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: Select all

#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");
}

Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: AHCI can't read and write blocks

Post by Octocontrabass »

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.
prcups
Posts: 10
Joined: Thu Jun 09, 2022 9:48 pm
Contact:

Re: AHCI can't read and write blocks

Post by prcups »

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.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: AHCI can't read and write blocks

Post by iansjack »

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

Re: AHCI can't read and write blocks

Post by prcups »

iansjack wrote:Is your code 32-bit or 64-bit?
64 bit
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: AHCI can't read and write blocks

Post by iansjack »

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

Re: AHCI can't read and write blocks

Post by prcups »

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.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: AHCI can't read and write blocks

Post by iansjack »

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.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: AHCI can't read and write blocks

Post by Octocontrabass »

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?
prcups
Posts: 10
Joined: Thu Jun 09, 2022 9:48 pm
Contact:

Re: AHCI can't read and write blocks

Post by prcups »

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
prcups
Posts: 10
Joined: Thu Jun 09, 2022 9:48 pm
Contact:

Re: AHCI can't read and write blocks

Post by prcups »

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).
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: AHCI can't read and write blocks

Post by Octocontrabass »

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

Re: AHCI can't read and write blocks

Post by prcups »

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.
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: AHCI can't read and write blocks

Post by Octocontrabass »

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.
Post Reply