-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
162a895
commit d252da8
Showing
3 changed files
with
251 additions
and
0 deletions.
There are no files selected for viewing
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#include "ide.h" | ||
|
||
channels chnls = {0}; | ||
ide_devices devices = {0}; | ||
uint8_t ide_buf[2048] = {0}; | ||
volatile static uint8_t ide_irq_invoked = 0; | ||
static uint8_t atapi_packet[12] = {ATAPI_CMD_READ, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||
|
||
uint8_t ide_read(uint8_t channel, uint8_t reg) { | ||
uint8_t result; | ||
|
||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, notice it's busy | ||
ide_write(channel, ATA_REG_CONTROL, ATA_SR_BSY | chnls[channel].nIEN); | ||
if (reg < 0x08) | ||
result = port_byte_in(chnls[channel].base + reg); | ||
else if (reg < 0x0C) | ||
result = port_byte_in(chnls[channel].base + reg - 0x06); | ||
else if (reg < 0x0E) | ||
result = port_byte_in(chnls[channel].crtl + reg - 0x0A); | ||
else if (reg < 0x16) | ||
result = port_byte_in(chnls[channel].bmide + reg - 0x0E); | ||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, not busy anymore | ||
ide_write(channel, ATA_REG_CONTROL, chnls[channel].nIEN); | ||
|
||
return result; | ||
} | ||
|
||
void ide_write(uint8_t channel, uint8_t reg, uint8_t data) { | ||
|
||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, notice it's busy | ||
ide_write(channel, ATA_REG_CONTROL, ATA_SR_BSY | chnls[channel].nIEN); | ||
if (reg < 0x08) | ||
port_byte_out(chnls[channel].base + reg, data); | ||
else if (reg < 0x0C) | ||
port_byte_out(chnls[channel].base + reg - 0x06, data); | ||
else if (reg < 0x0E) | ||
port_byte_out(chnls[channel].crtl + reg - 0x0A, data); | ||
else if (reg < 0x16) | ||
port_byte_out(chnls[channel].bmide + reg - 0x0E, data); | ||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, not busy anymore | ||
ide_write(channel, ATA_REG_CONTROL, chnls[channel].nIEN); | ||
} | ||
|
||
void ide_read_buffer(uint8_t channel, uint8_t reg, uint32_t buffer, uint32_t quads) { | ||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, notice it's busy | ||
ide_write(channel, ATA_REG_CONTROL, ATA_SR_BSY | chnls[channel].nIEN); | ||
asm("pushw %es; pushw %ax; movw %ds, %ax; movw %ax, %es; popw %ax;"); | ||
if (reg < 0x08) | ||
insl(chnls[channel].base + reg, (void*)buffer, quads); | ||
else if (reg < 0x0C) | ||
insl(chnls[channel].base + reg - 0x06, (void*)buffer, quads); | ||
else if (reg < 0x0E) | ||
insl(chnls[channel].crtl + reg - 0x0A, (void*)buffer, quads); | ||
else if (reg < 0x16) | ||
insl(chnls[channel].bmide + reg - 0x0E, (void*)buffer, quads); | ||
asm("popw %es;"); | ||
if (reg > 0x07 && reg < 0x0C) // If secondary channel register, not busy anymore | ||
ide_write(channel, ATA_REG_CONTROL, chnls[channel].nIEN); | ||
} | ||
|
||
uint8_t ide_polling(uint8_t channel, uint32_t advanced_check) { | ||
// (Part I) Delay 400 nsec for BSY to be set | ||
for (uint8_t i = 0; i < 4; i++) ide_read(channel, ATA_REG_ALTSTATUS); | ||
// (Part II) Wait for BSY to be cleared | ||
while (ide_read(channel, ATA_REG_STATUS) & ATA_SR_BSY); | ||
if (advanced_check) { | ||
uint8_t state = ide_read(channel, ATA_REG_STATUS); | ||
if (state & ATA_SR_ERR) return 2; // Error | ||
if (state & ATA_SR_DF) return 1; // Device Fault | ||
if (!(state & ATA_SR_DRQ)) return 3; // Data RQ not set | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
uint8_t ide_print_error(uint32_t drive, uint8_t err) { | ||
if (!err) return err; | ||
printf("IDE:"); | ||
switch (err) { | ||
case 1: | ||
printf("Device Fault\n"); | ||
err = 19; | ||
break; | ||
case 2: { | ||
uint8_t st = ide_read(devices[drive].channel, ATA_REG_ERROR); | ||
if (st & ATA_ER_AMNF) {printf("- No Address Mark Found\n "); err = 7;} | ||
if (st & ATA_ER_TK0NF) {printf("- No Media or Media Error\n "); err = 3;} | ||
if (st & ATA_ER_ABRT) {printf("- Command Aborted\n "); err = 20;} | ||
if (st & ATA_ER_MCR) {printf("- No Media or Media Error\n "); err = 3;} | ||
if (st & ATA_ER_IDNF) {printf("- ID mark not Found\n "); err = 21;} | ||
if (st & ATA_ER_MC) {printf("- No Media or Media Error\n "); err = 3;} | ||
if (st & ATA_ER_UNC) {printf("- Uncorrectable Data Error\n "); err = 22;} | ||
if (st & ATA_ER_BBK) {printf("- Bad Sectors\n "); err = 13;} | ||
} | ||
case 3: | ||
printf("- Reads Nothing\n"); | ||
err = 23; | ||
break; | ||
case 4: | ||
printf("- [%s %s] %s\n", | ||
(const char *[]){"Primary", "Secondary"}[devices[drive].channel], // Use the channel as an index into the array | ||
(const char *[]){"Master", "Slave"}[devices[drive].drive], // Same as above, using the drive | ||
devices[drive].model); | ||
} | ||
return err; | ||
} | ||
|
||
void ide_init(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2, uint32_t BAR3, uint32_t BAR4) { | ||
//TODO: https://wiki.osdev.org/PCI_IDE_Controller#Read/Write_From_ATA_Drive | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
#ifndef IDE_H | ||
#define IDE_H | ||
|
||
/* IDE (Integrated Drive Electronics) */ | ||
|
||
#include <stdint.h> | ||
#include "../../drivers/utils.h" | ||
#include "../../lib/stdio/stdio.h" | ||
|
||
/* Status */ | ||
#define ATA_SR_BSY 0x80 // Busy | ||
#define ATA_SR_DRDY 0x40 // Drive ready | ||
#define ATA_SR_DF 0x20 // Drive write fault | ||
#define ATA_SR_DSC 0x10 // Drive seek complete | ||
#define ATA_SR_DRQ 0x08 // Data request ready | ||
#define ATA_SR_CORR 0x04 // Corrected data | ||
#define ATA_SR_IDX 0x02 // Index | ||
#define ATA_SR_ERR 0x01 // Error | ||
|
||
/* Errors */ | ||
#define ATA_ER_BBK 0x80 // Bad block | ||
#define ATA_ER_UNC 0x40 // Uncorrectable data | ||
#define ATA_ER_MC 0x20 // Media changed | ||
#define ATA_ER_IDNF 0x10 // ID mark not found | ||
#define ATA_ER_MCR 0x08 // Media change request | ||
#define ATA_ER_ABRT 0x04 // Command aborted | ||
#define ATA_ER_TK0NF 0x02 // Track 0 not found | ||
#define ATA_ER_AMNF 0x01 // No address mark | ||
|
||
/* Commands */ | ||
#define ATA_CMD_READ_PIO 0x20 | ||
#define ATA_CMD_READ_PIO_EXT 0x24 | ||
#define ATA_CMD_READ_DMA 0xC8 | ||
#define ATA_CMD_READ_DMA_EXT 0x25 | ||
#define ATA_CMD_WRITE_PIO 0x30 | ||
#define ATA_CMD_WRITE_PIO_EXT 0x34 | ||
#define ATA_CMD_WRITE_DMA 0xCA | ||
#define ATA_CMD_WRITE_DMA_EXT 0x35 | ||
#define ATA_CMD_CACHE_FLUSH 0xE7 | ||
#define ATA_CMD_CACHE_FLUSH_EXT 0xEA | ||
#define ATA_CMD_PACKET 0xA0 | ||
#define ATA_CMD_IDENTIFY_PACKET 0xA1 | ||
#define ATA_CMD_IDENTIFY 0xEC | ||
|
||
// These are specific commands for ATAPI | ||
#define ATAPI_CMD_READ 0xA8 | ||
#define ATAPI_CMD_EJECT 0x1B | ||
|
||
/* Indentificators to read from identification space */ | ||
/* (after ATA_CMD_IDENTIFY or ATA_CMD_IDENTIFY_PACKET write in port Status/Commands) */ | ||
#define ATA_IDENT_DEVICETYPE 0 | ||
#define ATA_IDENT_CYLINDERS 2 | ||
#define ATA_IDENT_HEADS 6 | ||
#define ATA_IDENT_SECTORS 12 | ||
#define ATA_IDENT_SERIAL 20 | ||
#define ATA_IDENT_MODEL 54 | ||
#define ATA_IDENT_CAPABILITIES 98 | ||
#define ATA_IDENT_FIELDVALID 106 | ||
#define ATA_IDENT_MAX_LBA 120 | ||
#define ATA_IDENT_COMMANDSETS 164 | ||
#define ATA_IDENT_MAX_LBA_EXT 200 | ||
|
||
/* Interface type */ | ||
#define IDE_ATA 0x00 | ||
#define IDE_ATAPI 0x01 | ||
|
||
#define ATA_MASTER 0x00 | ||
#define ATA_SLAVE 0x01 | ||
|
||
/* Task File (ports that are offsets from BAR0 and/or BAR2)*/ | ||
#define ATA_REG_DATA 0x00 // RW | ||
#define ATA_REG_ERROR 0x01 // RO | ||
#define ATA_REG_FEATURES 0x01 // WO | ||
#define ATA_REG_SECCOUNT0 0x02 // RW | ||
#define ATA_REG_LBA0 0x03 // RW (LBA == Logical Block Addressing) | ||
#define ATA_REG_LBA1 0x04 // RW | ||
#define ATA_REG_LBA2 0x05 // RW | ||
#define ATA_REG_HDDEVSEL 0x06 // RW, used to select a drive in channel | ||
#define ATA_REG_COMMAND 0x07 // WO | ||
#define ATA_REG_STATUS 0x07 // RO | ||
#define ATA_REG_SECCOUNT1 0x08 // | ||
#define ATA_REG_LBA3 0x09 // | ||
#define ATA_REG_LBA4 0x0A // | ||
#define ATA_REG_LBA5 0x0B // | ||
#define ATA_REG_CONTROL 0x0C // WO | ||
#define ATA_REG_ALTSTATUS 0x0C // RO | ||
#define ATA_REG_DEVADDRESS 0x0D // ? | ||
|
||
// Channels: | ||
#define ATA_PRIMARY 0x00 | ||
#define ATA_SECONDARY 0x01 | ||
|
||
// Directions: | ||
#define ATA_READ 0x00 | ||
#define ATA_WRITE 0x01 | ||
|
||
typedef struct ide_channel_registers { | ||
uint16_t base; // I/O Base | ||
uint16_t crtl; // Control Base | ||
uint16_t bmide;// Bus Master IDE | ||
uint8_t nIEN; // (No Interrupt) | ||
|
||
} channels[2]; | ||
|
||
typedef struct ide_device { | ||
uint8_t reserved; // 0 (Empty) or 1 (Drive really exists) | ||
uint8_t channel; // 0 (primary channel) or 1 (secondary channel) | ||
uint8_t drive; // 0 (Master Drive) or 1 (Slave Drive) | ||
uint16_t type; // 0 (ATA) or 1 (ATAPI) | ||
uint16_t signature;// Drive signature | ||
uint16_t capabilities; // features | ||
uint32_t command_sets; | ||
uint32_t size; | ||
uint8_t model[41];// model of the drive in string | ||
} ide_devices[4]; | ||
|
||
/* | ||
BAR0: Base address of primary channel in PCI native mode (8 ports) | ||
BAR1: Base address of primary channel control port in PCI native mode (4 ports) | ||
BAR2: Base address of secondary channel in PCI native mode (8 ports) | ||
BAR3: Base address of secondary channel control port in PCI native mode (4 ports) | ||
BAR4: Bus master IDE (16 ports, 8 for each channel) | ||
*/ | ||
|
||
uint8_t ide_read(uint8_t channel, uint8_t reg); | ||
void ide_write(uint8_t channel, uint8_t reg, uint8_t data); | ||
void ide_read_buffer(uint8_t channel, uint8_t reg, uint32_t buffer, uint32_t quads); | ||
uint8_t ide_polling(uint8_t channel, uint32_t advanced_check); | ||
uint8_t ide_print_error(uint32_t drive, uint8_t err); | ||
void ide_init(uint32_t BAR0, uint32_t BAR1, uint32_t BAR2, uint32_t BAR3, uint32_t BAR4); | ||
|
||
#endif |