#include <_stdio.h> #include <alloc.h> #include <hardDrive.h> #include <pci.h> #include <ports.h> #include <stdbool.h> #include <timer.h> #define IDE_DATA_REGISTER 0 #define IDE_ERROR_REGISTER 1 #define IDE_SECTOR_COUNT_REGISTER 2 #define IDE_SECTOR_NUMBER_REGISTER 3 #define IDE_CYLINDER_LOW_REGISTER 4 #define IDE_CYLINDER_HIGH_REGISTER 5 // sector size, drive, head #define IDE_SDH_REGISTER 6 #define IDE_STATUS_REGISTER 7 #define IDE_COMMAND_REGISTER 7 #define IDE_ALTERNATE_STATUS_CONTROL_REGISTER 0 #define IDE_DRIVE_ADDRESS_CONTROL_REGISTER 1 #define IDE_STATUS_BUSY 0x80 #define IDE_STATUS_READY 0x40 #define IDE_STATUS_WRITE_FAULT 0x20 #define IDE_STATUS_SEEK_COMPLETE 0x10 #define IDE_STATUS_DATA_REQUEST 0x08 #define IDE_STATUS_CORRECTED_DATA 0x04 #define IDE_STATUS_INDEX 0x02 #define IDE_STATUS_ERROR 0x01 #define IDE_IDENTIFY_COMMAND 0xEC char *driveTypes[] = { "ISA Compatibility mode-only controller", "PCI native mode-only controller", "ISA Compatibility mode controller", "PCI native mode controller", }; void setupIDEChannels(IdeChannels *channels, PciDevice *pciDevice) { if (pciDevice->programmingInterface & 0x01) { channels->base = pciDevice->bar0; channels->control = pciDevice->bar1; } else { channels->base = 0x1F0; channels->control = 0x3F6; } if (pciDevice->programmingInterface & 0x04) { channels[1].base = pciDevice->bar2; channels[1].control = pciDevice->bar3; } else { channels[1].base = 0x170; channels[1].control = 0x376; } } void ideWriteControlRegister(IdeChannels *channel, uint8_t reg, uint8_t data) { outb(channel->control + reg, data); } void ideWriteRegister(IdeChannels *channel, uint8_t reg, uint16_t data) { outb(channel->base + reg, data); if (data > 0xFF) { // set higher half bit in the control register outb(channel->control, 0x0A); outb(channel->base + reg, data >> 8); outb(channel->control, 0x02); } } uint8_t ideReadControlRegister(IdeChannels *channel, uint8_t reg) { return inb(channel->control + reg); } uint8_t ideReadRegister(IdeChannels *channel, uint16_t reg) { return inw(channel->base + reg); } void ideReadBuffer(IdeChannels *channel, uint32_t *data) { for (uint16_t i = 0; i < 128; i++) { data[i] = ini(channel->base + IDE_DATA_REGISTER); } } void printError(uint16_t); void ideWaitUntilNotBusy(IdeChannels *channel, bool checkErrors) { for (uint8_t i = 0; i < 4; i++) { ideReadControlRegister(channel, 0); } uint16_t status = ideReadRegister(channel, IDE_STATUS_REGISTER); while (status & IDE_STATUS_BUSY) { status = ideReadRegister(channel, IDE_STATUS_REGISTER); } if (checkErrors && status & IDE_STATUS_ERROR) { printf("encountered an error\n"); printError(ideReadRegister(channel, IDE_ERROR_REGISTER)); } } void ideCommand(IdeChannels *channel, uint8_t command) { ideWaitUntilNotBusy(channel, false); ideWriteRegister(channel, IDE_COMMAND_REGISTER, command); } #define CHANNEL &channels[channel] void initializeIDEDrive(PciDevice *pciDevice, ListElement **drives) { uint8_t *buffer = malloc(2048); IdeChannels *channels = malloc(sizeof(IdeChannels) * 2); setupIDEChannels(channels, pciDevice); for (uint8_t channel = 0; channel < 2; channel++) { if (ideReadRegister(CHANNEL, IDE_STATUS_REGISTER) == 0) { // no device continue; } ideWriteControlRegister(CHANNEL, IDE_ALTERNATE_STATUS_CONTROL_REGISTER, 2); for (uint8_t drive = 0; drive < 2; drive++) { ideWaitUntilNotBusy(CHANNEL, true); // set the drive ideWriteRegister(CHANNEL, IDE_SDH_REGISTER, 0xA0 | (drive << 4)); ideWriteRegister(CHANNEL, IDE_SECTOR_COUNT_REGISTER, 0); ideWriteRegister(CHANNEL, IDE_SECTOR_NUMBER_REGISTER, 0); ideWriteRegister(CHANNEL, IDE_CYLINDER_LOW_REGISTER, 0); ideWriteRegister(CHANNEL, IDE_CYLINDER_HIGH_REGISTER, 0); ideCommand(CHANNEL, IDE_IDENTIFY_COMMAND); ideWaitUntilNotBusy(CHANNEL, true); ideReadBuffer(CHANNEL, (void *)buffer); if (*((uint16_t *)buffer) == 0) { // any bit has to be set if it is a real device continue; } char *model = malloc(41); for (int i = 0; i < 40; i += 2) { *((uint16_t *)&model[i]) = buffer[54 + i + 1]; *((uint16_t *)&model[i + 1]) = buffer[54 + i]; } model[40] = 0; HardDrive *hardDrive = malloc(sizeof(HardDrive)); hardDrive->model = model; hardDrive->channels = CHANNEL; hardDrive->channel = channel; hardDrive->drive = drive; hardDrive->type = *(uint16_t *)buffer; hardDrive->cylinders = *(uint16_t *)buffer + 2; hardDrive->heads = *(uint16_t *)buffer + 6; hardDrive->sectors = *(uint16_t *)buffer + 12; hardDrive->capabilities = *(uint16_t *)buffer + 98; hardDrive->commandSets = *(uint32_t *)(buffer + 164); if (hardDrive->commandSets + (1 << 26)) { hardDrive->size = *(uint32_t *)buffer + 200; } else { hardDrive->size = *(uint32_t *)buffer + 120; } listAdd(drives, hardDrive); printf("found a hard drive %i bytes, %i:%i, model: %s\n", hardDrive->size, channel, drive, model); } } free(buffer); } void printError(uint16_t status) { if (status & 0x01) { printf("No address mark\n"); } if (status & 0x02) { printf("Track 0 not found\n"); } if (status & 0x04) { printf("command aborted\n"); } if (status & 0x08) { printf("Media change request\n"); } if (status & 0x10) { printf("ID mark not found\n"); } if (status & 0x20) { printf("Media changed\n"); } if (status & 0x40) { printf("uncorrectable data\n"); } if (status & 0x80) { printf("bad block\n"); } } void driveAccess(HardDrive *hardDrive, uint32_t lba, void *buffer, uint8_t sectorCount, uint8_t direction) { uint8_t accessMode = 0, head = 0, sector = 0, cylinder = 0; uint32_t lbaIo[6] = {0, 0, 0, 0, 0, 0}; if (lba >= 0x10000000) { accessMode = 2; lbaIo[0] = (uint8_t)lba; lbaIo[1] = (lba & 0x0000FF00) >> 8; lbaIo[2] = (lba & 0x00FF0000) >> 16; lbaIo[3] = (lba & 0xFF000000) >> 24; } else if (hardDrive->capabilities & 0x200) { accessMode = 1; lbaIo[0] = (uint8_t)lba; lbaIo[1] = (lba & 0x000FF00) >> 8; lbaIo[2] = (lba & 0x0FF0000) >> 16; head = (lba & 0xF000000) >> 24; } else { sector = (lba % 63) + 1; cylinder = (lba + 1 - sector) / (16 * 63); lbaIo[0] = sector; lbaIo[1] = (uint8_t)cylinder; lbaIo[2] = (cylinder >> 8) & 0xFF; head = (lba + 1 - sector) % (16 * 63) / (63); } ideWaitUntilNotBusy(hardDrive->channels, true); if (accessMode == 0) { // chs ideWriteRegister(hardDrive->channels, IDE_SDH_REGISTER, 0xA0 | (hardDrive->drive << 4)); } else { // lba ideWriteRegister(hardDrive->channels, IDE_SDH_REGISTER, 0xE0 | (hardDrive->drive << 4) | head); } ideWriteRegister(hardDrive->channels, IDE_SECTOR_COUNT_REGISTER, sectorCount); ideWriteRegister(hardDrive->channels, IDE_SECTOR_NUMBER_REGISTER, lbaIo[3] << 8 | lbaIo[0]); ideWriteRegister(hardDrive->channels, IDE_CYLINDER_LOW_REGISTER, lbaIo[4] << 8 | lbaIo[1]); ideWriteRegister(hardDrive->channels, IDE_CYLINDER_HIGH_REGISTER, lbaIo[5] << 8 | lbaIo[2]); uint8_t command = 0; if (direction == 0) { // read if (accessMode == 2) { command = 0x24; } else { command = 0x20; } } else { // write if (accessMode == 2) { command = 0x34; } else { command = 0x30; } } ideCommand(hardDrive->channels, command); ideWaitUntilNotBusy(hardDrive->channels, true); if (direction == 0) { uint16_t status; void *current = buffer; for (uint8_t i = 0; i < sectorCount; i++) { ideWaitUntilNotBusy(hardDrive->channels, true); ideReadBuffer(hardDrive->channels, (void *)buffer); } } } void initializeSATADrive(PciDevice *pciDevice) { // todo } void scanHardDrives() { ListElement *drives = NULL; for (ListElement *current = *getPciDevices(); current; current = current->next) { PciDevice *pciDevice = current->data; if (pciDevice->class != 1) { continue; } switch (pciDevice->subclass) { case 1: initializeIDEDrive(pciDevice, &drives); break; case 6: printf("found a SATA-controller: %i:%i:%i\n", pciDevice->bus, pciDevice->device, pciDevice->function); initializeSATADrive(pciDevice); break; } } void *buffer = malloc(2000); for (ListElement *current = drives; current; current = current->next) { driveAccess(current->data, 0, buffer, 1, 0); printf("data: %x %x %s\n", *(uint32_t *)buffer, *((uint32_t *)buffer + 1), buffer); } free(buffer); }