From fdb5c1b2c81c33799b416574fea397a21c9e5d68 Mon Sep 17 00:00:00 2001 From: Ali Mashtizadeh Date: Sat, 5 Jul 2014 18:46:59 -0700 Subject: [PATCH] Improvements to AHCI driver and part of a IDE PIO driver. --- sys/SConscript | 3 +- sys/amd64/machine.c | 1 + sys/dev/ahci.c | 55 +++++++++++-- sys/dev/x86/ide.c | 190 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 6 deletions(-) create mode 100644 sys/dev/x86/ide.c diff --git a/sys/SConscript b/sys/SConscript index 3f71db2..9caaea5 100644 --- a/sys/SConscript +++ b/sys/SConscript @@ -18,8 +18,9 @@ src_amd64 = [ "amd64/pmap.c", "amd64/lapic.c", "amd64/ioapic.c", - "dev/x86/vgacons.c", "dev/x86/debugcons.c", + "dev/x86/vgacons.c", + "dev/x86/ide.c", ] src_common = [ diff --git a/sys/amd64/machine.c b/sys/amd64/machine.c index 8585678..1c05357 100644 --- a/sys/amd64/machine.c +++ b/sys/amd64/machine.c @@ -87,5 +87,6 @@ void Machine_Init() IOAPIC_Init(); PCI_Init(); + IDE_Init(); } diff --git a/sys/dev/ahci.c b/sys/dev/ahci.c index 7e8b4a4..7cd35ba 100644 --- a/sys/dev/ahci.c +++ b/sys/dev/ahci.c @@ -261,6 +261,18 @@ AHCI_Init(uint32_t bus, uint32_t slot, uint32_t func) } } +void +AHCI_Dump(AHCI *ahci) +{ + volatile AHCIHostControl *hc = ahci->hc; + + kprintf("CAP: 0x%08x\n", hc->cap); + kprintf("GHC: 0x%08x\n", hc->ghc); + kprintf("IS: 0x%08x\n", hc->is); + kprintf("PI: 0x%08x\n", hc->pi); + kprintf("VS: 0x%08x\n", hc->vs); +} + void AHCI_DumpPort(AHCI *ahci, int port) { @@ -351,6 +363,8 @@ AHCI_IdentifyPort(AHCI *ahci, int port) kprintf("AHCI: Identify Succeeded Port %d\n", port); Debug_PrintHex((const char *)&ident, 512, 0, 512); AHCI_DumpPort(ahci, port); + uint64_t val = (uint64_t)&ident; + Debug_PrintHex((const char *)&val, 8, 0, 8); return; } @@ -377,6 +391,10 @@ AHCI_ResetPort(AHCI *ahci, int port) } } + // Reset interrupts + p->is = 0xFFFFFFFF; + p->is = 0x00000000; + // Reset error p->serr = 0xFFFFFFFF; p->serr = 0x00000000; @@ -406,9 +424,23 @@ void AHCI_Reset(AHCI *ahci) { int port; + volatile AHCIHostControl *hc = ahci->hc; - // Enable AHCI and Interrupts - ahci->hc->ghc = AHCI_GHC_AE | AHCI_GHC_IE; + AHCI_Dump(ahci); + + // Reset controller + uint32_t caps = hc->cap; + uint32_t pi = hc->pi; + + hc->ghc |= AHCI_GHC_AE; + hc->ghc |= AHCI_GHC_HR; + while (1) { + if ((hc->ghc & AHCI_GHC_HR) == 0) + break; + } + hc->ghc |= AHCI_GHC_AE; + + AHCI_Dump(ahci); // Reset ports for (port = 0; port < AHCI_MAX_PORTS; port++) @@ -417,12 +449,18 @@ AHCI_Reset(AHCI *ahci) AHCI_ResetPort(ahci, port); } } + + // XXX: Clear interrupts + + // Enable Interrupts + hc->ghc = AHCI_GHC_IE; } void AHCI_Configure(PCIDevice dev) { AHCI *ahci = (AHCI *)PAlloc_AllocPage(); + volatile AHCIHostControl *hc; PCI_Configure(&dev); @@ -445,10 +483,17 @@ AHCI_Configure(PCIDevice dev) // XXX: Register IRQ // Setup - ahci->hc = dev.bars[AHCI_ABAR].base; + hc = dev.bars[AHCI_ABAR].base; + ahci->hc = hc; - uint32_t ports = ahci->hc->pi; - uint32_t vers = ahci->hc->vs; + // Disable Interrupts + hc->ghc &= ~AHCI_GHC_IE; + + // Enable AHCI Controller + hc->ghc |= AHCI_GHC_AE; + + uint32_t ports = hc->pi; + uint32_t vers = hc->vs; kprintf("AHCI: Version %d.%d, Ports: 0x%08x\n", vers >> 16, vers & 0xFFFF, ports); diff --git a/sys/dev/x86/ide.c b/sys/dev/x86/ide.c new file mode 100644 index 0000000..f24ec03 --- /dev/null +++ b/sys/dev/x86/ide.c @@ -0,0 +1,190 @@ + +#include +#include + +#include +#include + +#include "ioport.h" + +/* + * ATA Definitions + */ + +typedef struct ATAIdentifyDevice +{ + uint16_t _rsvd0[10]; // 0-9 + uint8_t serial[20]; // 10-19 - Serial + uint16_t _rsvd1[3]; // 20-22 + uint8_t firmware[8]; // 23-26 - Firmware + uint8_t model[40]; // 27-46 - Model + uint16_t _rsvd2[16]; // 47-62 X + uint16_t dmaMode; // 63 - DMA Mode + uint16_t _rsvd3[11]; // 64-74 X + uint16_t queueDepth; // 75 - Queue Depth + uint16_t sataCap; // 76 - SATA Capabilities + uint16_t ncqCap; // 77 - NCQ Capabilities + uint16_t _rsvd4[8]; // 78-85 + uint16_t deviceFlags; // 86 - Device Flags (48-bit Addressing) + uint16_t deviceFlags2; // 87 - Device Flags 2 (SMART) + uint16_t udmaMode; // 88 - Ultra DMA Mode + uint16_t _rsvd5[11]; // 89-99 + uint64_t lbaSectors; // 100-103 - User Addressable Logical Sectors + uint16_t _rsvd6[151]; // 104-254 + uint16_t chksum; // 255 - Checksum +} ATAIdentifyDevice; + +/* + * IDE Definitions + */ + +#define IDE_PRIMARY_BASE 0x1F0 +#define IDE_PRIMARY_DEVCTL 0x3F6 +#define IDE_PRIMARY_IRQ 14 + +#define IDE_SECONDARY_BASE 0x170 +#define IDE_SECONDARY_DEVCTL 0x376 +#define IDE_SECONDARY_IRQ 15 + +// Port Offsets +#define IDE_DATAPORT 0 +#define IDE_FEATURES 1 +#define IDE_SECTORCOUNT 2 +#define IDE_LBALOW 3 +#define IDE_LBAMID 4 +#define IDE_LBAHIGH 5 +#define IDE_DRIVE 6 +#define IDE_COMMAND 7 /* Write */ +#define IDE_STATUS 7 /* Read */ + +// Drives +#define IDE_DRIVE_MASTER 0xA0 +#define IDE_DRIVE_SLAVE 0xB0 + +// IDE Commands +#define IDE_CMD_READ +#define IDE_CMD_WRITE +#define IDE_CMD_IDENTIFY 0xEC + +// Status +#define IDE_STATUS_ERR 0x01 /* Error */ +#define IDE_STATUS_DRQ 0x08 /* Data Ready */ +#define IDE_STATUS_SRV 0x10 /* Overlapped-mode Service Request */ +#define IDE_STATUS_DF 0x20 /* Drive Fault Error */ +#define IDE_STATUS_RDY 0x40 /* Ready */ +#define IDE_STATUS_BSY 0x80 /* Busy */ + +#define IDE_CONTROL_SRST 0x04 /* Software Reset */ + +typedef struct IDE +{ + uint16_t base; // Base Port + uint16_t devctl; // Device Control +} IDE; + +bool IDE_HasController(IDE *ide); +void IDE_Reset(IDE *ide); +void IDE_Identify(IDE *ide, int drive); + +void +IDE_Init() +{ + IDE ide; + + ASSERT(sizeof(ATAIdentifyDevice) == 512); + + ide.base = IDE_PRIMARY_BASE; + ide.devctl = IDE_PRIMARY_DEVCTL; + + if (!IDE_HasController(&ide)) { + kprintf("IDE: No controller detected\n"); + return; + } + IDE_Reset(&ide); + IDE_Identify(&ide, 0); +} + +bool +IDE_HasController(IDE *ide) +{ + outb(ide->base + IDE_LBALOW, 0x41); + outb(ide->base + IDE_LBAMID, 0x4D); + + if (inb(ide->base + IDE_LBALOW) != 0x41) + return false; + if (inb(ide->base + IDE_LBAMID) != 0x4D) + return false; + + return true; +} + +void +IDE_Reset(IDE *ide) +{ + uint8_t status; + + outb(ide->devctl, IDE_CONTROL_SRST); + outb(ide->devctl, 0); + inb(ide->devctl); + inb(ide->devctl); + inb(ide->devctl); + inb(ide->devctl); + + // XXX: Timeout + while (1) { + status = inb(ide->devctl); + if ((status & (IDE_STATUS_RDY | IDE_STATUS_BSY)) == IDE_STATUS_RDY) + break; + } +} + +void +IDE_Identify(IDE *ide, int drive) +{ + uint8_t driveCode; + uint8_t status; + ATAIdentifyDevice ident; + + ASSERT(drive == 0 || drive == 1); + + if (drive == 0) + driveCode = IDE_DRIVE_MASTER; + else + driveCode = IDE_DRIVE_SLAVE; + + outb(ide->base + IDE_DRIVE, driveCode); + outb(ide->base + IDE_SECTORCOUNT, 0x00); + outb(ide->base + IDE_LBALOW, 0x00); + outb(ide->base + IDE_LBAMID, 0x00); + outb(ide->base + IDE_LBAHIGH, 0x00); + outb(ide->base + IDE_COMMAND, IDE_CMD_IDENTIFY); + + status = inb(ide->base + IDE_STATUS); + if (status == 0) { + kprintf("IDE: No drive %d\n", drive); + return; + } + + kprintf("IDE: Waiting for ready! %08x\n", status); + + // XXX: Need timeout + while (1) { + if ((status & IDE_STATUS_BSY) == 0) + break; + status = inb(ide->base + IDE_STATUS); + } + + if ((status & IDE_STATUS_ERR) != 0) { + kprintf("IDE: Error trying to identify drive %d\n", drive); + return; + } + + kprintf("IDE: Ready!\n"); + + insw(ide->base, (void *)&ident, 256); + + kprintf("IDE: Ready!\n"); + + Debug_PrintHex((const char *)&ident, 512, 0, 512); +} +