Created
April 2, 2020 18:04
-
-
Save skejeton/c5b485b193926879d9ec86f66f5072b1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <inc/drivers/ide/ide.h> | |
Byte atapiPacket[12]; | |
UInt8 IDERead(IDEDevice *dev, UInt8 offset) | |
{ | |
unsigned char result; | |
if (offset > 0x07 && offset < 0x0C) | |
IDEWrite(dev, ATA_REG_CONTROL, 0x80 | dev->channel->nIEN); | |
if (offset < 0x08) | |
result = InB(dev->channel->base + offset - 0x00); | |
else if (offset < 0x0C) | |
result = InB(dev->channel->base + offset - 0x06); | |
else if (offset < 0x0E) | |
result = InB((dev->channel->base+0x206) + offset - 0x0A); | |
if (offset > 0x07 && offset < 0x0C) | |
IDEWrite(dev, ATA_REG_CONTROL, dev->channel->nIEN); | |
return result; | |
} | |
void IDEWrite(IDEDevice *dev, UInt8 offset, UInt8 data) | |
{ | |
if (offset > 0x07 && offset < 0x0C) | |
IDEWrite(dev, ATA_REG_CONTROL, 0x80 | dev->channel->nIEN); | |
if (offset < 0x08) | |
OutB(dev->channel->base + offset - 0x00, data); | |
else if (offset < 0x0C) | |
OutB(dev->channel->base + offset - 0x06, data); | |
else if (offset < 0x0E) | |
OutB((dev->channel->base+0x206) + offset - 0x0A, data); | |
if (offset > 0x07 && offset < 0x0C) | |
IDEWrite(dev, ATA_REG_CONTROL, dev->channel->nIEN); | |
} | |
UInt8 IDEPoll(IDEDevice *dev, bool acheck) | |
{ | |
for (int i = 0; i < 4; i++) | |
IDERead(dev->channel->base, ATA_REG_ALTSTATUS); | |
while (IDERead(dev->channel->base, ATA_REG_STATUS) & ATA_BIT_BSY); | |
if (acheck) | |
{ | |
UInt8 state = IDERead(dev->channel->base, ATA_REG_STATUS); | |
TVMPrintA(ToHex(state)); | |
if (state & ATA_BIT_ERR) | |
return ATAERR_ERR; | |
if (state & ATA_BIT_DEVF) | |
return ATAERR_DEVF; | |
if ((state & ATA_BIT_DRQ) == 0) | |
return ATAERR_DRQ; | |
} | |
return ATAERR_NOERR; | |
} | |
void IDESleep(int ms) | |
{ | |
PITSleep(ms); | |
} | |
UInt16 IDEPrintError(IDEDevice *dev, UInt16 err) | |
{ | |
if (err == 0) return 0; | |
TVMPrintA("========================================="); | |
TVMPrintA("IDE Error: "); | |
if (err == ATAERR_DEVF) | |
TVMPrintA("Device fault"); | |
else if (err == ATAERR_ERR) | |
{ | |
TVMPrintA("ERR"); | |
UInt8 errType = IDERead(dev->channel, ATA_REG_ERROR); | |
if (errType & ATA_IERR_AMNF) TVMPrintA("No address mark"); | |
if (errType & ATA_IERR_TK0NF) TVMPrintA("Track 0 not found"); | |
if (errType & ATA_IERR_ABRT) TVMPrintA("Command aborted"); | |
if (errType & ATA_IERR_MCR) TVMPrintA("Media change request"); | |
if (errType & ATA_IERR_IDNF) TVMPrintA("Id mark not found"); | |
if (errType & ATA_IERR_MC) TVMPrintA("Media changed"); | |
if (errType & ATA_IERR_UNC) TVMPrintA("Uncorrectable data"); | |
if (errType & ATA_IERR_BBK) TVMPrintA("Bad block"); | |
} | |
if (err == ATAERR_DRQ) | |
TVMPrintA("Reads nothing"); | |
TVMPrintA("On"); | |
TVMPrintA(dev->channel->isPrimary ? "Primary" : "Secondary"); | |
TVMPrintA(dev->isMaster ? "Master" : "Slave"); | |
TVMPrintA(ToHex(IDERead(dev, ATA_REG_STATUS))); | |
TVMPrintA("========================================="); | |
return err; | |
} | |
IDEDevice* IDECreateATADeviceInstance(PCIDeviceDescriptor *dev, bool primary, bool master) | |
{ | |
IDEDevice *res = NEW(IDEDevice, 1); | |
IDEChannel *ch = NEW(IDEChannel, 1); | |
UInt8 status; | |
res->channel = ch; | |
res->channel->isPrimary = primary; | |
if (primary) | |
{ | |
res->channel->base = ((UInt32)dev->bars[0]->address) + 0x1F0 * (!((UInt32)dev->bars[0]->address)); | |
res->channel->busMaster = (UInt32)dev->bars[4]->address; | |
} | |
else | |
{ | |
res->channel->base = ((UInt32)dev->bars[2]->address) + 0x170 * (!((UInt32)dev->bars[2]->address)); | |
res->channel->busMaster = ((UInt32)dev->bars[4]->address) + 8; | |
} | |
res->exists = true; | |
res->isMaster = master; | |
// Disable irqs | |
IDEWrite(res, ATA_REG_CONTROL, 2); | |
UInt8 error; | |
// Identify device | |
IDEWrite(res, ATA_REG_HDDEVSEL, 0xA0 | ((!master) << 4)); | |
// Wait | |
IDESleep(10); | |
IDEWrite(res, ATA_REG_COMMAND, 0xEC); // Identify command | |
// Wait | |
IDESleep(10); | |
if (IDERead(res, ATA_REG_STATUS) == 0) return NULL; | |
while(1) | |
{ | |
status = IDERead(res, ATA_REG_STATUS); | |
if ((status & ATA_BIT_ERR)) | |
{ | |
error = 1; | |
break; | |
} // If Err, Device is not ATA. | |
if (!(status & ATA_BIT_BSY) && (status & ATA_BIT_DRQ)) | |
{ | |
break; | |
} // Everything is right. | |
} | |
res->type = ATA_TYPE_ATA; | |
// Error happened, must be atapi device then | |
if (error != 0) | |
{ | |
// Check if device is ATAPI | |
UInt8 sig1 = IDERead(res, ATA_REG_LBA1); | |
UInt8 sig2 = IDERead(res, ATA_REG_LBA2); | |
res->type = ATA_TYPE_ATAPI; | |
if (sig1 == 0x14 && sig2 == 0xeb) | |
IDEWrite(res, ATA_REG_COMMAND, 0xA1); // Identify Packet command | |
IDESleep(10); | |
} | |
res->channel->nIEN = true; | |
// TODO: Read buffer | |
//////////////////// | |
return res; | |
} | |
UInt8 IDEATAPIRead(IDEDevice *dev, UInt32 lba, Byte *buffer) | |
{ | |
TVMPrintA("============= Entering read ============="); | |
UInt8 error; | |
IDEWrite(dev, ATA_REG_CONTROL, dev->channel->nIEN = ataLock = 0); | |
atapiPacket[ 0] = 0xA8; | |
atapiPacket[ 1] = 0x0; | |
atapiPacket[ 2] = (lba >> 24) & 0xFF; | |
atapiPacket[ 3] = (lba >> 16) & 0xFF; | |
atapiPacket[ 4] = (lba >> 8) & 0xFF; | |
atapiPacket[ 5] = (lba >> 0) & 0xFF; | |
atapiPacket[ 6] = 0x0; | |
atapiPacket[ 7] = 0x0; | |
atapiPacket[ 8] = 0x0; | |
atapiPacket[ 9] = 1; // Number of sectors | |
atapiPacket[10] = 0x0; | |
atapiPacket[11] = 0x0; | |
// IDEWrite(dev->channel->base, ATA_REG_CONTROL, dev->channel->nIEN = ataLock = 0); | |
// IDEWrite(dev, ATA_REG_HDDEVSEL, dev->isMaster << 4); | |
IDEWrite(dev, ATA_REG_HDDEVSEL, (!dev->isMaster) << 4); | |
// Delay | |
for(int i = 0; i < 4; i++) | |
IDERead(dev, ATA_REG_ALTSTATUS); | |
// PIO mode | |
IDEWrite(dev, ATA_REG_FEATURES, 0); | |
// Size of buffer | |
IDEWrite(dev, ATA_REG_LBA1, ATAPI_SECTOR_SIZE & 0xFF); | |
IDEWrite(dev, ATA_REG_LBA2, (ATAPI_SECTOR_SIZE >> 8)); | |
// Send packet | |
IDEWrite(dev, ATA_REG_COMMAND, 0xA0); // Packet command | |
if (error = IDEPoll(dev, true)) return error; | |
asm volatile("rep outsw" : : "c"(6), "d"(dev->channel->base), "S"(atapiPacket)); // Send Packet Data | |
// Wait for irq | |
while (!ataLock) { | |
asm("hlt"); | |
} | |
ataLock = false; | |
TVMPrintA("got past irq"); | |
if (error = IDEPoll(dev, true)) return error; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <inc/types.h> | |
#include <inc/port.h> | |
#include <inc/io.h> | |
#include <inc/pci/pci.h> | |
#include <inc/irq_handlers.h> | |
// Based on https://wiki.osdev.org/PCI_IDE_Controller | |
#define ATA_BIT_BSY 0x80 // Busy | |
#define ATA_BIT_DRDY 0x40 // Drive ready | |
#define ATA_BIT_DEVF 0x20 // Drive write fault | |
#define ATA_BIT_DSC 0x10 // Drive seek complete | |
#define ATA_BIT_DRQ 0x08 // Data request ready | |
#define ATA_BIT_CORR 0x04 // Corrected data | |
#define ATA_BIT_IDX 0x02 // Index | |
#define ATA_BIT_ERR 0x01 // Error | |
#define ATA_REG_DATA 0x00 | |
#define ATA_REG_ERROR 0x01 | |
#define ATA_REG_FEATURES 0x01 | |
#define ATA_REG_SECCOUNT0 0x02 | |
#define ATA_REG_LBA0 0x03 | |
#define ATA_REG_LBA1 0x04 | |
#define ATA_REG_LBA2 0x05 | |
#define ATA_REG_HDDEVSEL 0x06 | |
#define ATA_REG_COMMAND 0x07 | |
#define ATA_REG_STATUS 0x07 | |
#define ATA_REG_CONTROL 0x0C | |
#define ATA_REG_ALTSTATUS 0x0C | |
#define ATAERR_NOERR 0 | |
#define ATAERR_ERR 1 | |
#define ATAERR_DEVF 2 | |
#define ATAERR_DRQ 3 | |
#define ATA_IERR_BBK 0x80 // Bad block | |
#define ATA_IERR_UNC 0x40 // Uncorrectable data | |
#define ATA_IERR_MC 0x20 // Media changed | |
#define ATA_IERR_IDNF 0x10 // ID mark not found | |
#define ATA_IERR_MCR 0x08 // Media change request | |
#define ATA_IERR_ABRT 0x04 // Command aborted | |
#define ATA_IERR_TK0NF 0x02 // Track 0 not found | |
#define ATA_IERR_AMNF 0x01 // No address mark | |
#define ATA_TYPE_ATAPI 0 | |
#define ATA_TYPE_ATA 1 | |
#define ATAPI_SECTOR_SIZE 2048 | |
typedef struct | |
{ | |
bool isPrimary; | |
UInt16 base; | |
UInt16 busMaster; | |
UInt8 nIEN; | |
} IDEChannel; | |
typedef struct | |
{ | |
UInt8 type; | |
IDEChannel *channel; | |
bool exists; | |
bool isMaster; | |
UInt16 signature; | |
UInt16 features; | |
UInt32 commands; | |
UInt32 capacity; | |
Byte model[41]; | |
} IDEDevice; | |
UInt8 IDERead(IDEDevice *dev, UInt8 offset); | |
void IDEWrite(IDEDevice *dev, UInt8 offset, UInt8 data); | |
UInt8 IDEPoll(IDEDevice *dev, bool acheck); | |
UInt16 IDEPrintError(IDEDevice *dev, UInt16 err); | |
IDEDevice* IDECreateATADeviceInstance(PCIDeviceDescriptor *dev, bool primary, bool master); | |
UInt8 IDEATAPIRead(IDEDevice *dev, UInt32 lba, Byte *buffer); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
bool ataLock = false; | |
void IRQ14Handler(void) | |
{ | |
ataLock = true; | |
TVMPrint("PRIMARY", 0x70, 0); | |
OutB(0xA0, 0x20); | |
OutB(0x20, 0x20); //EOI | |
} | |
void IRQ15Handler(void) | |
{ | |
ataLock = true; | |
TVMPrint("SECONDARY", 0x70, 0); | |
OutB(0xA0, 0x20); | |
OutB(0x20, 0x20); //EOI | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment