Improvements to AHCI driver and part of a IDE PIO driver.
This commit is contained in:
parent
696101f277
commit
fdb5c1b2c8
@ -18,8 +18,9 @@ src_amd64 = [
|
|||||||
"amd64/pmap.c",
|
"amd64/pmap.c",
|
||||||
"amd64/lapic.c",
|
"amd64/lapic.c",
|
||||||
"amd64/ioapic.c",
|
"amd64/ioapic.c",
|
||||||
"dev/x86/vgacons.c",
|
|
||||||
"dev/x86/debugcons.c",
|
"dev/x86/debugcons.c",
|
||||||
|
"dev/x86/vgacons.c",
|
||||||
|
"dev/x86/ide.c",
|
||||||
]
|
]
|
||||||
|
|
||||||
src_common = [
|
src_common = [
|
||||||
|
@ -87,5 +87,6 @@ void Machine_Init()
|
|||||||
IOAPIC_Init();
|
IOAPIC_Init();
|
||||||
|
|
||||||
PCI_Init();
|
PCI_Init();
|
||||||
|
IDE_Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
void
|
||||||
AHCI_DumpPort(AHCI *ahci, int port)
|
AHCI_DumpPort(AHCI *ahci, int port)
|
||||||
{
|
{
|
||||||
@ -351,6 +363,8 @@ AHCI_IdentifyPort(AHCI *ahci, int port)
|
|||||||
kprintf("AHCI: Identify Succeeded Port %d\n", port);
|
kprintf("AHCI: Identify Succeeded Port %d\n", port);
|
||||||
Debug_PrintHex((const char *)&ident, 512, 0, 512);
|
Debug_PrintHex((const char *)&ident, 512, 0, 512);
|
||||||
AHCI_DumpPort(ahci, port);
|
AHCI_DumpPort(ahci, port);
|
||||||
|
uint64_t val = (uint64_t)&ident;
|
||||||
|
Debug_PrintHex((const char *)&val, 8, 0, 8);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -377,6 +391,10 @@ AHCI_ResetPort(AHCI *ahci, int port)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset interrupts
|
||||||
|
p->is = 0xFFFFFFFF;
|
||||||
|
p->is = 0x00000000;
|
||||||
|
|
||||||
// Reset error
|
// Reset error
|
||||||
p->serr = 0xFFFFFFFF;
|
p->serr = 0xFFFFFFFF;
|
||||||
p->serr = 0x00000000;
|
p->serr = 0x00000000;
|
||||||
@ -406,9 +424,23 @@ void
|
|||||||
AHCI_Reset(AHCI *ahci)
|
AHCI_Reset(AHCI *ahci)
|
||||||
{
|
{
|
||||||
int port;
|
int port;
|
||||||
|
volatile AHCIHostControl *hc = ahci->hc;
|
||||||
|
|
||||||
// Enable AHCI and Interrupts
|
AHCI_Dump(ahci);
|
||||||
ahci->hc->ghc = AHCI_GHC_AE | AHCI_GHC_IE;
|
|
||||||
|
// 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
|
// Reset ports
|
||||||
for (port = 0; port < AHCI_MAX_PORTS; port++)
|
for (port = 0; port < AHCI_MAX_PORTS; port++)
|
||||||
@ -417,12 +449,18 @@ AHCI_Reset(AHCI *ahci)
|
|||||||
AHCI_ResetPort(ahci, port);
|
AHCI_ResetPort(ahci, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX: Clear interrupts
|
||||||
|
|
||||||
|
// Enable Interrupts
|
||||||
|
hc->ghc = AHCI_GHC_IE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AHCI_Configure(PCIDevice dev)
|
AHCI_Configure(PCIDevice dev)
|
||||||
{
|
{
|
||||||
AHCI *ahci = (AHCI *)PAlloc_AllocPage();
|
AHCI *ahci = (AHCI *)PAlloc_AllocPage();
|
||||||
|
volatile AHCIHostControl *hc;
|
||||||
|
|
||||||
PCI_Configure(&dev);
|
PCI_Configure(&dev);
|
||||||
|
|
||||||
@ -445,10 +483,17 @@ AHCI_Configure(PCIDevice dev)
|
|||||||
// XXX: Register IRQ
|
// XXX: Register IRQ
|
||||||
|
|
||||||
// Setup
|
// Setup
|
||||||
ahci->hc = dev.bars[AHCI_ABAR].base;
|
hc = dev.bars[AHCI_ABAR].base;
|
||||||
|
ahci->hc = hc;
|
||||||
|
|
||||||
uint32_t ports = ahci->hc->pi;
|
// Disable Interrupts
|
||||||
uint32_t vers = ahci->hc->vs;
|
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",
|
kprintf("AHCI: Version %d.%d, Ports: 0x%08x\n",
|
||||||
vers >> 16, vers & 0xFFFF, ports);
|
vers >> 16, vers & 0xFFFF, ports);
|
||||||
|
190
sys/dev/x86/ide.c
Normal file
190
sys/dev/x86/ide.c
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <kassert.h>
|
||||||
|
#include <sga.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user