From: John Hodge Date: Wed, 20 Jan 2010 02:55:45 +0000 (+0800) Subject: Moved ATA driver out of Kernel tree X-Git-Tag: rel0.06~317 X-Git-Url: https://git.ucc.asn.au/?p=tpg%2Facess2.git;a=commitdiff_plain;h=6249939b47bd8520ef4c1b8fdb8eeb11cc052d57 Moved ATA driver out of Kernel tree - Also changed VER3 macro to VER2 for compatability with MODULE_DEFINE --- diff --git a/Kernel/Makefile.BuildNum b/Kernel/Makefile.BuildNum index 911235d7..cf092370 100644 --- a/Kernel/Makefile.BuildNum +++ b/Kernel/Makefile.BuildNum @@ -1 +1 @@ -BUILD_NUM = 1386 +BUILD_NUM = 1387 diff --git a/Kernel/drv/ata_x86.c b/Kernel/drv/ata_x86.c deleted file mode 100644 index 9974f42b..00000000 --- a/Kernel/drv/ata_x86.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Acess2 IDE Harddisk Driver - * drv/ide.c - */ -#define DEBUG 0 -#include -#include -#include -#include -#include -#include -#include - -// --- Flags --- -#define START_BEFORE_CMD 0 - -// === CONSTANTS === -#define MAX_ATA_DISKS 4 -#define SECTOR_SIZE 512 -#define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE) - -#define IDE_PRI_BASE 0x1F0 -#define IDE_SEC_BASE 0x170 - -#define IDE_PRDT_LAST 0x8000 -/** - \enum HddControls - \brief Commands to be sent to HDD_CMD -*/ -enum HddControls { - HDD_PIO_R28 = 0x20, - HDD_PIO_R48 = 0x24, - HDD_DMA_R48 = 0x25, - HDD_PIO_W28 = 0x30, - HDD_PIO_W48 = 0x34, - HDD_DMA_W48 = 0x35, - HDD_DMA_R28 = 0xC8, - HDD_DMA_W28 = 0xCA, -}; - -// === STRUCTURES === -typedef struct { - Uint32 PBufAddr; - Uint16 Bytes; - Uint16 Flags; -} tPRDT_Ent; -typedef struct { - Uint16 Flags; // 1 - Uint16 Usused1[9]; // 10 - char SerialNum[20]; // 20 - Uint16 Usused2[3]; // 23 - char FirmwareVer[8]; // 27 - char ModelNumber[40]; // 47 - Uint16 SectPerInt; // 48 - and with 0xFF to get true value; - Uint16 Unused3; // 49 - Uint16 Capabilities[2]; // 51 - Uint16 Unused4[2]; // 53 - Uint16 ValidExtData; // 54 - Uint16 Unused5[5]; // 59 - Uint16 SizeOfRWMultiple; // 60 - Uint32 Sectors28; // 62 - Uint16 Unused6[100-62]; - Uint64 Sectors48; - Uint16 Unused7[256-104]; -} tIdentify; -typedef struct { - Uint8 BootCode[0x1BE]; - struct { - Uint8 Boot; - Uint8 Unused1; // Also CHS Start - Uint16 StartHi; // Also CHS Start - Uint8 SystemID; - Uint8 Unused2; // Also CHS Length - Uint16 LengthHi; // Also CHS Length - Uint32 LBAStart; - Uint32 LBALength; - } __attribute__ ((packed)) Parts[4]; - Uint16 BootFlag; // = 0xAA 55 -} __attribute__ ((packed)) tMBR; - -typedef struct { - Uint64 Start; - Uint64 Length; - char Name[4]; - tVFS_Node Node; -} tATA_Partition; -typedef struct { - Uint64 Sectors; - char Name[2]; - tVFS_Node Node; - int NumPartitions; - tATA_Partition *Partitions; -} tATA_Disk; - -// === PROTOTYPES === - int ATA_Install(); - int ATA_SetupIO(); -void ATA_SetupPartitions(); -void ATA_SetupVFS(); - int ATA_ScanDisk(int Disk); -void ATA_ParseGPT(int Disk); -void ATA_ParseMBR(int Disk); -void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length); -Uint16 ATA_GetBasePort(int Disk); -// Filesystem Interface -char *ATA_ReadDir(tVFS_Node *Node, int Pos); -tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name); -Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); -Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); - int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data); -// Read/Write Interface/Quantiser -Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); -Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); -// Read/Write DMA - int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); - int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); -// IRQs -void ATA_IRQHandlerPri(int unused); -void ATA_IRQHandlerSec(int unused); -// Controller IO -Uint8 ATA_int_BusMasterReadByte(int Ofs); -void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value); -void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value); - -// === GLOBALS === -MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL); -tDevFS_Driver gATA_DriverInfo = { - NULL, "ata", - { - .NumACLs = 1, - .Size = -1, - .Flags = VFS_FFLAG_DIRECTORY, - .ACLs = &gVFS_ACL_EveryoneRX, - .ReadDir = ATA_ReadDir, - .FindDir = ATA_FindDir - } -}; -tATA_Disk gATA_Disks[MAX_ATA_DISKS]; - int giATA_NumNodes; -tVFS_Node **gATA_Nodes; -Uint16 gATA_BusMasterBase = 0; -Uint8 *gATA_BusMasterBasePtr = 0; - int gATA_IRQPri = 14; - int gATA_IRQSec = 15; - int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller -Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata"))); - int gaATA_IRQs[2] = {0}; -tPRDT_Ent gATA_PRDTs[2] = { - {0, 512, IDE_PRDT_LAST}, - {0, 512, IDE_PRDT_LAST} -}; - -// === CODE === -/** - * \fn int ATA_Install() - */ -int ATA_Install() -{ - int ret; - - ret = ATA_SetupIO(); - if(ret != 1) return ret; - - ATA_SetupPartitions(); - - ATA_SetupVFS(); - - if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 ) - return MODULE_INIT_FAILURE; - - return MODULE_INIT_SUCCESS; -} - -/** - * \fn int ATA_SetupIO() - * \brief Sets up the ATA controller's DMA mode - */ -int ATA_SetupIO() -{ - int ent; - tPAddr addr; - - ENTER(""); - - // Get IDE Controller's PCI Entry - ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1); - LOG("ent = %i", ent); - gATA_BusMasterBase = PCI_GetBAR4( ent ); - if( gATA_BusMasterBase == 0 ) { - Warning("It seems that there is no Bus Master Controller on this machine. Get one"); - LEAVE('i', MODULE_INIT_FAILURE); - return MODULE_INIT_FAILURE; - } - if( !(gATA_BusMasterBase & 1) ) - { - if( gATA_BusMasterBase < 0x100000 ) - gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase); - else - gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) ); - LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr); - } - else { - // Bit 0 is left set as a flag to other functions - LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1); - } - - IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri ); - IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec ); - - gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] ); - gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] ); - - LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr); - - addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] ); - LOG("addr = 0x%x", addr); - ATA_int_BusMasterWriteDWord(4, addr); - addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] ); - LOG("addr = 0x%x", addr); - ATA_int_BusMasterWriteDWord(12, addr); - - outb(IDE_PRI_BASE+1, 1); - outb(IDE_SEC_BASE+1, 1); - - LEAVE('i', MODULE_INIT_SUCCESS); - return MODULE_INIT_SUCCESS; -} - -/** - * \fn void ATA_SetupPartitions() - */ -void ATA_SetupPartitions() -{ - int i; - for( i = 0; i < MAX_ATA_DISKS; i ++ ) - { - if( !ATA_ScanDisk(i) ) { - gATA_Disks[i].Name[0] = '\0'; // Mark as unused - continue; - } - } -} - -/** - * \fn void ATA_SetupVFS() - * \brief Sets up the ATA drivers VFS information and registers with DevFS - */ -void ATA_SetupVFS() -{ - int i, j, k; - - // Count number of nodes needed - giATA_NumNodes = 0; - for( i = 0; i < MAX_ATA_DISKS; i++ ) - { - if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore - giATA_NumNodes ++; - giATA_NumNodes += gATA_Disks[i].NumPartitions; - } - - // Allocate Node space - gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) ); - - // Set nodes - k = 0; - for( i = 0; i < MAX_ATA_DISKS; i++ ) - { - if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore - gATA_Nodes[ k++ ] = &gATA_Disks[i].Node; - for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ ) - gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node; - } - - gATA_DriverInfo.RootNode.Size = giATA_NumNodes; -} - -/** - * \fn int ATA_ScanDisk(int Disk) - */ -int ATA_ScanDisk(int Disk) -{ - Uint16 buf[256]; - tIdentify *identify = (void*)buf; - tMBR *mbr = (void*)buf; - Uint16 base; - Uint8 val; - int i; - tVFS_Node *node; - - ENTER("iDisk", Disk); - - base = ATA_GetBasePort( Disk ); - - LOG("base = 0x%x", base); - - // Send Disk Selector - if(Disk == 1 || Disk == 3) - outb(base+6, 0xB0); - else - outb(base+6, 0xA0); - - // Send IDENTIFY - outb(base+7, 0xEC); - val = inb(base+7); // Read status - if(val == 0) { - LEAVE('i', 0); - return 0; // Disk does not exist - } - - // Poll until BSY clears and DRQ sets or ERR is set - while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7); - - if(val & 1) { - LEAVE('i', 0); - return 0; // Error occured, so return false - } - - // Read Data - for(i=0;i<256;i++) buf[i] = inw(base); - - // Populate Disk Structure - if(identify->Sectors48 != 0) - gATA_Disks[ Disk ].Sectors = identify->Sectors48; - else - gATA_Disks[ Disk ].Sectors = identify->Sectors28; - - - LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors); - - if( gATA_Disks[ Disk ].Sectors / (2048*1024) ) - Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk, - gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024)); - else if( gATA_Disks[ Disk ].Sectors / 2048 ) - Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk, - gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048); - else - Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk, - gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2); - - // Create Name - gATA_Disks[ Disk ].Name[0] = 'A'+Disk; - gATA_Disks[ Disk ].Name[1] = '\0'; - - // Get pointer to vfs node and populate it - node = &gATA_Disks[ Disk ].Node; - node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE; - node->NumACLs = 0; // Means Superuser only can access it - node->Inode = (Disk << 8) | 0xFF; - node->ImplPtr = gATA_Disks[ Disk ].Name; - - node->ATime = node->MTime - = node->CTime = now(); - - node->Read = ATA_ReadFS; - node->Write = ATA_WriteFS; - node->IOCtl = ATA_IOCtl; - - - // --- Scan Partitions --- - LOG("Reading MBR"); - // Read Boot Sector - ATA_ReadDMA( Disk, 0, 1, mbr ); - - // Check for a GPT table - if(mbr->Parts[0].SystemID == 0xEE) - ATA_ParseGPT(Disk); - else // No? Just parse the MBR - ATA_ParseMBR(Disk); - - LEAVE('i', 0); - return 1; -} - -/** - * \fn void ATA_ParseGPT(int Disk) - * \brief Parses the GUID Partition Table - */ -void ATA_ParseGPT(int Disk) -{ - ///\todo Support GPT Disks - Warning("GPT Disks are currently unsupported"); -} - -/** - * \fn void ATA_ParseMBR(int Disk) - */ -void ATA_ParseMBR(int Disk) -{ - int i, j = 0, k = 4; - tMBR mbr; - Uint64 extendedLBA; - - ENTER("iDisk", Disk); - - // Read Boot Sector - ATA_ReadDMA( Disk, 0, 1, &mbr ); - - // Count Partitions - gATA_Disks[Disk].NumPartitions = 0; - extendedLBA = 0; - for( i = 0; i < 4; i ++ ) - { - if( mbr.Parts[i].SystemID == 0 ) continue; - if( - mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28 - || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48 - ) - { - if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) { - LOG("Extended Partition"); - if(extendedLBA != 0) { - Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); - continue; - } - extendedLBA = mbr.Parts[i].LBAStart; - continue; - } - LOG("Primary Partition"); - - gATA_Disks[Disk].NumPartitions ++; - continue; - } - // Invalid Partition, so don't count it - } - while(extendedLBA != 0) - { - if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 ) - break; // Stop on Errors - - extendedLBA = 0; - - if( mbr.Parts[0].SystemID == 0 ) continue; - if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28 - || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48 - ) - { - if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) - extendedLBA = mbr.Parts[0].LBAStart; - else - gATA_Disks[Disk].NumPartitions ++; - } - - if( mbr.Parts[1].SystemID == 0 ) continue; - if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28 - || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48 - ) - { - if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { - if(extendedLBA == 0) { - Warning("Disk %i has twp forward link in the extended partition", - Disk); - break; - } - extendedLBA = mbr.Parts[1].LBAStart; - } - else { - if(extendedLBA != 0) { - Warning("Disk %i lacks a forward link in the extended partition", - Disk); - break; - } - gATA_Disks[Disk].NumPartitions ++; - } - } - } - LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions); - - // Create patition array - gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) ); - - // --- Fill Partition Info --- - extendedLBA = 0; - for( i = 0; i < 4; i ++ ) - { - Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID); - if( mbr.Parts[i].SystemID == 0 ) continue; - if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28 - { - if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) { - if(extendedLBA != 0) { - Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); - continue; - } - extendedLBA = mbr.Parts[1].LBAStart; - continue; - } - // Create Partition - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i, - mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength - ); - j ++; - continue; - } - if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48 - { - if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) { - if(extendedLBA != 0) { - Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); - continue; - } - extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart; - continue; - } - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i, - (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart, - (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength - ); - j ++; - } - // Invalid Partition, so don't count it - } - // Scan extended partition - while(extendedLBA != 0) - { - if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 ) - break; // Stop on Errors - - extendedLBA = 0; - - // Check first entry (should be partition) - if( mbr.Parts[0].SystemID != 0) - { - if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28 - { - // Forward Link to next Extended partition entry - if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) - extendedLBA = mbr.Parts[0].LBAStart; - else { - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, - mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength - ); - j ++; k ++; - } - } - else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48 - { - if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) - extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart; - else { - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, - (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart, - (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength - ); - j ++; k ++; - } - } - } - - // Check second entry (should be forward link) - if( mbr.Parts[1].SystemID != 0) - { - if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28 - { - if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { - if(extendedLBA == 0) { - Warning("Disk %i has twp forward link in the extended partition", - Disk); - break; - } - extendedLBA = mbr.Parts[1].LBAStart; - } - else - { - if(extendedLBA != 0) { - Warning("Disk %i lacks a forward link in the extended partition", - Disk); - break; - } - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, - mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength - ); - j ++; k ++; - } - - } - else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48 - { - if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { - if(extendedLBA == 0) { - Warning("Disk %i has twp forward link in the extended partition", - Disk); - break; - } - extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart; - } - else - { - if(extendedLBA != 0) { - Warning("Disk %i lacks a forward link in the extended partition", - Disk); - break; - } - ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, - (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart, - (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength - ); - j ++; k ++; - } - } - } - } - - LEAVE('-'); -} - -/** - * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length) - * \brief Fills a parition's information structure - */ -void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length) -{ - ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length); - Part->Start = Start; - Part->Length = Length; - Part->Name[0] = 'A'+Disk; - if(Num >= 10) { - Part->Name[1] = '1'+Num/10; - Part->Name[2] = '1'+Num%10; - Part->Name[3] = '\0'; - } else { - Part->Name[1] = '1'+Num; - Part->Name[2] = '\0'; - } - Part->Node.NumACLs = 0; // Only root can read/write raw block devices - Part->Node.Inode = (Disk << 8) | Num; - Part->Node.ImplPtr = Part->Name; - - Part->Node.Read = ATA_ReadFS; - Part->Node.Write = ATA_WriteFS; - Part->Node.IOCtl = ATA_IOCtl; - LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node); - LEAVE('-'); -} - -/** - * \fn Uint16 ATA_GetPortBase(int Disk) - * \brief Returns the base port for a given disk - */ -Uint16 ATA_GetBasePort(int Disk) -{ - switch(Disk) - { - case 0: case 1: return IDE_PRI_BASE; - case 2: case 3: return IDE_SEC_BASE; - } - return 0; -} - -/** - * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos) - */ -char *ATA_ReadDir(tVFS_Node *Node, int Pos) -{ - if(Pos >= giATA_NumNodes || Pos < 0) return NULL; - return strdup( gATA_Nodes[Pos]->ImplPtr ); -} - -/** - * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name) - */ -tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name) -{ - int part; - // Check first character - if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS) - return NULL; - // Raw Disk - if(Name[1] == '\0') { - if( gATA_Disks[Name[0]-'A'].Sectors == 0 ) - return NULL; - return &gATA_Disks[Name[0]-'A'].Node; - } - - // Partitions - if(Name[1] < '0' || '9' < Name[1]) return NULL; - if(Name[2] == '\0') { // <= 9 - part = Name[1] - '0'; - part --; - return &gATA_Disks[Name[0]-'A'].Partitions[part].Node; - } - // > 9 - if('0' > Name[2] || '9' < Name[2]) return NULL; - if(Name[3] != '\0') return NULL; - - part = (Name[1] - '0') * 10; - part += Name[2] - '0'; - part --; - return &gATA_Disks[Name[0]-'A'].Partitions[part].Node; - -} - -/** - * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - */ -Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - int disk = Node->Inode >> 8; - int part = Node->Inode & 0xFF; - - // Raw Disk Access - if(part == 0xFF) - { - if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) - return 0; - if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE ) - Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset; - } - // Partition - else - { - if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) - return 0; - if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) - Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset; - Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE; - } - - //Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer); - return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk); -} - -/** - * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) - */ -Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) -{ - int disk = Node->Inode >> 8; - int part = Node->Inode & 0xFF; - - // Raw Disk Access - if(part == 0xFF) - { - if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) - return 0; - if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE ) - Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset; - } - // Partition - else - { - if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) - return 0; - if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) - Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset; - Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE; - } - - Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer); - Debug_HexDump("ATA_WriteFS", Buffer, Length); - return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk); -} - -/** - * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data) - * \brief IO Control Funtion - */ -int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data) -{ - switch(Id) - { - case DRV_IOCTL_TYPE: return DRV_TYPE_DISK; - } - return 0; -} - -// --- Disk Access --- -/** - * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) - */ -Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) -{ - int ret; - Uint offset; - Uint done = 0; - - // Pass straight on to ATA_ReadDMAPage if we can - if(Count <= MAX_DMA_SECTORS) - { - ret = ATA_ReadDMA(Disk, Address, Count, Buffer); - if(ret == 0) return 0; - return Count; - } - - // Else we will have to break up the transfer - offset = 0; - while(Count > MAX_DMA_SECTORS) - { - ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset); - // Check for errors - if(ret != 1) return done; - // Change Position - done += MAX_DMA_SECTORS; - Count -= MAX_DMA_SECTORS; - offset += MAX_DMA_SECTORS*SECTOR_SIZE; - } - - ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset); - if(ret != 1) return 0; - return done+Count; -} - -/** - * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) - */ -Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) -{ - int ret; - Uint offset; - Uint done = 0; - - // Pass straight on to ATA_WriteDMA if we can - if(Count <= MAX_DMA_SECTORS) - { - ret = ATA_WriteDMA(Disk, Address, Count, Buffer); - if(ret == 0) return 0; - return Count; - } - - // Else we will have to break up the transfer - offset = 0; - while(Count > MAX_DMA_SECTORS) - { - ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset); - // Check for errors - if(ret != 1) return done; - // Change Position - done += MAX_DMA_SECTORS; - Count -= MAX_DMA_SECTORS; - offset += MAX_DMA_SECTORS*SECTOR_SIZE; - } - - ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset); - if(ret != 1) return 0; - return done+Count; -} - -/** - * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) - */ -int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) -{ - int cont = (Disk>>1)&1; // Controller ID - int disk = Disk & 1; - Uint16 base; - - ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer); - - // Check if the count is small enough - if(Count > MAX_DMA_SECTORS) { - Warning("Passed too many sectors for a bulk DMA read (%i > %i)", - Count, MAX_DMA_SECTORS); - LEAVE('i'); - return 0; - } - - // Get exclusive access to the disk controller - LOCK( &giaATA_ControllerLock[ cont ] ); - - // Set Size - gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; - - // Get Port Base - base = ATA_GetBasePort(Disk); - - // Reset IRQ Flag - gaATA_IRQs[cont] = 0; - - // Set up transfer - outb(base+0x01, 0x00); - if( Address > 0x0FFFFFFF ) // Use LBA48 - { - outb(base+0x6, 0x40 | (disk << 4)); - outb(base+0x2, 0 >> 8); // Upper Sector Count - outb(base+0x3, Address >> 24); // Low 2 Addr - outb(base+0x3, Address >> 28); // Mid 2 Addr - outb(base+0x3, Address >> 32); // High 2 Addr - } - else - { - outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr - } - - outb(base+0x02, (Uint8) Count); // Sector Count - outb(base+0x03, (Uint8) Address); // Low Addr - outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr - outb(base+0x05, (Uint8) (Address >> 16)); // High Addr - - LOG("Starting Transfer"); - #if START_BEFORE_CMD - // Start transfer - ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start - if( Address > 0x0FFFFFFF ) - outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48) - else - outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28) - #else - if( Address > 0x0FFFFFFF ) - outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48) - else - outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28) - // Start transfer - ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start - #endif - - // Wait for transfer to complete - //ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 ); - while( gaATA_IRQs[cont] == 0 ) { - //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 ); - //LOG("val = 0x%02x", val); - Threads_Yield(); - } - - // Complete Transfer - ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop - - LOG("Transfer Completed & Acknowledged"); - - // Copy to destination buffer - memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE ); - - // Release controller lock - RELEASE( &giaATA_ControllerLock[ cont ] ); - - LEAVE('i', 1); - return 1; -} - -/** - * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) - */ -int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) -{ - int cont = (Disk>>1)&1; // Controller ID - int disk = Disk & 1; - Uint16 base; - - // Check if the count is small enough - if(Count > MAX_DMA_SECTORS) return 0; - - // Get exclusive access to the disk controller - LOCK( &giaATA_ControllerLock[ cont ] ); - - // Set Size - gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; - - // Get Port Base - base = ATA_GetBasePort(Disk); - - // Set up transfer - outb(base+0x01, 0x00); - if( Address > 0x0FFFFFFF ) // Use LBA48 - { - outb(base+0x6, 0x40 | (disk << 4)); - outb(base+0x2, 0 >> 8); // Upper Sector Count - outb(base+0x3, Address >> 24); // Low 2 Addr - outb(base+0x3, Address >> 28); // Mid 2 Addr - outb(base+0x3, Address >> 32); // High 2 Addr - } - else - { - outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr - } - - outb(base+0x02, (Uint8) Count); // Sector Count - outb(base+0x03, (Uint8) Address); // Low Addr - outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr - outb(base+0x05, (Uint8) (Address >> 16)); // High Addr - if( Address > 0x0FFFFFFF ) - outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48) - else - outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28) - - // Reset IRQ Flag - gaATA_IRQs[cont] = 0; - - // Copy to output buffer - memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE ); - - // Start transfer - ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start - - // Wait for transfer to complete - while( gaATA_IRQs[cont] == 0 ) Threads_Yield(); - - // Complete Transfer - ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop - - // Release controller lock - RELEASE( &giaATA_ControllerLock[ cont ] ); - - return 1; -} - -/** - * \fn void ATA_IRQHandlerPri(int unused) - */ -void ATA_IRQHandlerPri(int unused) -{ - Uint8 val; - - // IRQ bit set for Primary Controller - val = ATA_int_BusMasterReadByte( 0x2 ); - LOG("IRQ val = 0x%x", val); - if(val & 4) { - LOG("IRQ hit (val = 0x%x)", val); - ATA_int_BusMasterWriteByte( 0x2, 4 ); - gaATA_IRQs[0] = 1; - return ; - } -} - -/** - * \fn void ATA_IRQHandlerSec(int unused) - */ -void ATA_IRQHandlerSec(int unused) -{ - Uint8 val; - // IRQ bit set for Secondary Controller - val = ATA_int_BusMasterReadByte( 0xA ); - if(val & 4) { - LOG("IRQ hit (val = 0x%x)", val); - ATA_int_BusMasterWriteByte( 0xA, 4 ); - gaATA_IRQs[1] = 1; - return ; - } -} - -/** - * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs) - */ -Uint8 ATA_int_BusMasterReadByte(int Ofs) -{ - if( gATA_BusMasterBase & 1 ) - return inb( (gATA_BusMasterBase & ~1) + Ofs ); - else - return *(Uint8*)(gATA_BusMasterBasePtr + Ofs); -} - -/** - * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value) - * \brief Writes a byte to a Bus Master Register - */ -void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value) -{ - if( gATA_BusMasterBase & 1 ) - outb( (gATA_BusMasterBase & ~1) + Ofs, Value ); - else - *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value; -} - -/** - * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value) - * \brief Writes a dword to a Bus Master Register - */ -void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value) -{ - - if( gATA_BusMasterBase & 1 ) - outd( (gATA_BusMasterBase & ~1) + Ofs, Value ); - else - *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value; -} diff --git a/Kernel/include/acess.h b/Kernel/include/acess.h index a87aaec1..d4df34bc 100644 --- a/Kernel/include/acess.h +++ b/Kernel/include/acess.h @@ -27,7 +27,7 @@ typedef Sint64 tTimestamp; #define STR(x) #x #define EXPAND_STR(x) STR(x) -#define VER3(major,minor,patch) ((((major)&0xFF)<<16)|(((minor)&0xFF)<<8)|((patch)&0xFF)) +#define VER2(major,minor) ((((major)&0xFF)<<8)|((minor)&0xFF)) /** * \} */ diff --git a/Makefile.cfg b/Makefile.cfg index 9363ff68..be0194f0 100644 --- a/Makefile.cfg +++ b/Makefile.cfg @@ -24,8 +24,8 @@ ifeq ($(ARCHDIR),) endif FILESYSTEMS = fat -DRIVERS = ata_x86 -MODULES = FS_Ext2 FDD NE2000 BochsGA IPStack +DRIVERS = +MODULES = ATA FS_Ext2 FDD NE2000 BochsGA IPStack DYNMODS = USB UDI #DISTROOT = /mnt/AcessHDD/Acess2 diff --git a/Modules/ATA/Makefile b/Modules/ATA/Makefile new file mode 100644 index 00000000..a697f66b --- /dev/null +++ b/Modules/ATA/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = ata_x86.o +NAME = ATA + +-include ../Makefile.tpl diff --git a/Modules/ATA/ata_x86.c b/Modules/ATA/ata_x86.c new file mode 100644 index 00000000..9974f42b --- /dev/null +++ b/Modules/ATA/ata_x86.c @@ -0,0 +1,1062 @@ +/* + * Acess2 IDE Harddisk Driver + * drv/ide.c + */ +#define DEBUG 0 +#include +#include +#include +#include +#include +#include +#include + +// --- Flags --- +#define START_BEFORE_CMD 0 + +// === CONSTANTS === +#define MAX_ATA_DISKS 4 +#define SECTOR_SIZE 512 +#define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE) + +#define IDE_PRI_BASE 0x1F0 +#define IDE_SEC_BASE 0x170 + +#define IDE_PRDT_LAST 0x8000 +/** + \enum HddControls + \brief Commands to be sent to HDD_CMD +*/ +enum HddControls { + HDD_PIO_R28 = 0x20, + HDD_PIO_R48 = 0x24, + HDD_DMA_R48 = 0x25, + HDD_PIO_W28 = 0x30, + HDD_PIO_W48 = 0x34, + HDD_DMA_W48 = 0x35, + HDD_DMA_R28 = 0xC8, + HDD_DMA_W28 = 0xCA, +}; + +// === STRUCTURES === +typedef struct { + Uint32 PBufAddr; + Uint16 Bytes; + Uint16 Flags; +} tPRDT_Ent; +typedef struct { + Uint16 Flags; // 1 + Uint16 Usused1[9]; // 10 + char SerialNum[20]; // 20 + Uint16 Usused2[3]; // 23 + char FirmwareVer[8]; // 27 + char ModelNumber[40]; // 47 + Uint16 SectPerInt; // 48 - and with 0xFF to get true value; + Uint16 Unused3; // 49 + Uint16 Capabilities[2]; // 51 + Uint16 Unused4[2]; // 53 + Uint16 ValidExtData; // 54 + Uint16 Unused5[5]; // 59 + Uint16 SizeOfRWMultiple; // 60 + Uint32 Sectors28; // 62 + Uint16 Unused6[100-62]; + Uint64 Sectors48; + Uint16 Unused7[256-104]; +} tIdentify; +typedef struct { + Uint8 BootCode[0x1BE]; + struct { + Uint8 Boot; + Uint8 Unused1; // Also CHS Start + Uint16 StartHi; // Also CHS Start + Uint8 SystemID; + Uint8 Unused2; // Also CHS Length + Uint16 LengthHi; // Also CHS Length + Uint32 LBAStart; + Uint32 LBALength; + } __attribute__ ((packed)) Parts[4]; + Uint16 BootFlag; // = 0xAA 55 +} __attribute__ ((packed)) tMBR; + +typedef struct { + Uint64 Start; + Uint64 Length; + char Name[4]; + tVFS_Node Node; +} tATA_Partition; +typedef struct { + Uint64 Sectors; + char Name[2]; + tVFS_Node Node; + int NumPartitions; + tATA_Partition *Partitions; +} tATA_Disk; + +// === PROTOTYPES === + int ATA_Install(); + int ATA_SetupIO(); +void ATA_SetupPartitions(); +void ATA_SetupVFS(); + int ATA_ScanDisk(int Disk); +void ATA_ParseGPT(int Disk); +void ATA_ParseMBR(int Disk); +void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length); +Uint16 ATA_GetBasePort(int Disk); +// Filesystem Interface +char *ATA_ReadDir(tVFS_Node *Node, int Pos); +tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name); +Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); + int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data); +// Read/Write Interface/Quantiser +Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); +Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk); +// Read/Write DMA + int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); + int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer); +// IRQs +void ATA_IRQHandlerPri(int unused); +void ATA_IRQHandlerSec(int unused); +// Controller IO +Uint8 ATA_int_BusMasterReadByte(int Ofs); +void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value); +void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0032, i386ATA, ATA_Install, NULL, NULL); +tDevFS_Driver gATA_DriverInfo = { + NULL, "ata", + { + .NumACLs = 1, + .Size = -1, + .Flags = VFS_FFLAG_DIRECTORY, + .ACLs = &gVFS_ACL_EveryoneRX, + .ReadDir = ATA_ReadDir, + .FindDir = ATA_FindDir + } +}; +tATA_Disk gATA_Disks[MAX_ATA_DISKS]; + int giATA_NumNodes; +tVFS_Node **gATA_Nodes; +Uint16 gATA_BusMasterBase = 0; +Uint8 *gATA_BusMasterBasePtr = 0; + int gATA_IRQPri = 14; + int gATA_IRQSec = 15; + int giaATA_ControllerLock[2] = {0}; //!< Spinlocks for each controller +Uint8 gATA_Buffers[2][4096] __attribute__ ((section(".padata"))); + int gaATA_IRQs[2] = {0}; +tPRDT_Ent gATA_PRDTs[2] = { + {0, 512, IDE_PRDT_LAST}, + {0, 512, IDE_PRDT_LAST} +}; + +// === CODE === +/** + * \fn int ATA_Install() + */ +int ATA_Install() +{ + int ret; + + ret = ATA_SetupIO(); + if(ret != 1) return ret; + + ATA_SetupPartitions(); + + ATA_SetupVFS(); + + if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 ) + return MODULE_INIT_FAILURE; + + return MODULE_INIT_SUCCESS; +} + +/** + * \fn int ATA_SetupIO() + * \brief Sets up the ATA controller's DMA mode + */ +int ATA_SetupIO() +{ + int ent; + tPAddr addr; + + ENTER(""); + + // Get IDE Controller's PCI Entry + ent = PCI_GetDeviceByClass(0x0101, 0xFFFF, -1); + LOG("ent = %i", ent); + gATA_BusMasterBase = PCI_GetBAR4( ent ); + if( gATA_BusMasterBase == 0 ) { + Warning("It seems that there is no Bus Master Controller on this machine. Get one"); + LEAVE('i', MODULE_INIT_FAILURE); + return MODULE_INIT_FAILURE; + } + if( !(gATA_BusMasterBase & 1) ) + { + if( gATA_BusMasterBase < 0x100000 ) + gATA_BusMasterBasePtr = (void*)(0xC0000000|gATA_BusMasterBase); + else + gATA_BusMasterBasePtr = (void*)( MM_MapHWPage( gATA_BusMasterBase, 1 ) + (gATA_BusMasterBase&0xFFF) ); + LOG("gATA_BusMasterBasePtr = %p", gATA_BusMasterBasePtr); + } + else { + // Bit 0 is left set as a flag to other functions + LOG("gATA_BusMasterBase = 0x%x", gATA_BusMasterBase & ~1); + } + + IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri ); + IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec ); + + gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[0] ); + gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (Uint)&gATA_Buffers[1] ); + + LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr); + + addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[0] ); + LOG("addr = 0x%x", addr); + ATA_int_BusMasterWriteDWord(4, addr); + addr = MM_GetPhysAddr( (Uint)&gATA_PRDTs[1] ); + LOG("addr = 0x%x", addr); + ATA_int_BusMasterWriteDWord(12, addr); + + outb(IDE_PRI_BASE+1, 1); + outb(IDE_SEC_BASE+1, 1); + + LEAVE('i', MODULE_INIT_SUCCESS); + return MODULE_INIT_SUCCESS; +} + +/** + * \fn void ATA_SetupPartitions() + */ +void ATA_SetupPartitions() +{ + int i; + for( i = 0; i < MAX_ATA_DISKS; i ++ ) + { + if( !ATA_ScanDisk(i) ) { + gATA_Disks[i].Name[0] = '\0'; // Mark as unused + continue; + } + } +} + +/** + * \fn void ATA_SetupVFS() + * \brief Sets up the ATA drivers VFS information and registers with DevFS + */ +void ATA_SetupVFS() +{ + int i, j, k; + + // Count number of nodes needed + giATA_NumNodes = 0; + for( i = 0; i < MAX_ATA_DISKS; i++ ) + { + if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore + giATA_NumNodes ++; + giATA_NumNodes += gATA_Disks[i].NumPartitions; + } + + // Allocate Node space + gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) ); + + // Set nodes + k = 0; + for( i = 0; i < MAX_ATA_DISKS; i++ ) + { + if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore + gATA_Nodes[ k++ ] = &gATA_Disks[i].Node; + for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ ) + gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node; + } + + gATA_DriverInfo.RootNode.Size = giATA_NumNodes; +} + +/** + * \fn int ATA_ScanDisk(int Disk) + */ +int ATA_ScanDisk(int Disk) +{ + Uint16 buf[256]; + tIdentify *identify = (void*)buf; + tMBR *mbr = (void*)buf; + Uint16 base; + Uint8 val; + int i; + tVFS_Node *node; + + ENTER("iDisk", Disk); + + base = ATA_GetBasePort( Disk ); + + LOG("base = 0x%x", base); + + // Send Disk Selector + if(Disk == 1 || Disk == 3) + outb(base+6, 0xB0); + else + outb(base+6, 0xA0); + + // Send IDENTIFY + outb(base+7, 0xEC); + val = inb(base+7); // Read status + if(val == 0) { + LEAVE('i', 0); + return 0; // Disk does not exist + } + + // Poll until BSY clears and DRQ sets or ERR is set + while( ((val & 0x80) || !(val & 0x08)) && !(val & 1)) val = inb(base+7); + + if(val & 1) { + LEAVE('i', 0); + return 0; // Error occured, so return false + } + + // Read Data + for(i=0;i<256;i++) buf[i] = inw(base); + + // Populate Disk Structure + if(identify->Sectors48 != 0) + gATA_Disks[ Disk ].Sectors = identify->Sectors48; + else + gATA_Disks[ Disk ].Sectors = identify->Sectors28; + + + LOG("gATA_Disks[ Disk ].Sectors = 0x%x", gATA_Disks[ Disk ].Sectors); + + if( gATA_Disks[ Disk ].Sectors / (2048*1024) ) + Log("Disk %i: 0x%llx Sectors (%i GiB)", Disk, + gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / (2048*1024)); + else if( gATA_Disks[ Disk ].Sectors / 2048 ) + Log("Disk %i: 0x%llx Sectors (%i MiB)", Disk, + gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2048); + else + Log("Disk %i: 0x%llx Sectors (%i KiB)", Disk, + gATA_Disks[ Disk ].Sectors, gATA_Disks[ Disk ].Sectors / 2); + + // Create Name + gATA_Disks[ Disk ].Name[0] = 'A'+Disk; + gATA_Disks[ Disk ].Name[1] = '\0'; + + // Get pointer to vfs node and populate it + node = &gATA_Disks[ Disk ].Node; + node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE; + node->NumACLs = 0; // Means Superuser only can access it + node->Inode = (Disk << 8) | 0xFF; + node->ImplPtr = gATA_Disks[ Disk ].Name; + + node->ATime = node->MTime + = node->CTime = now(); + + node->Read = ATA_ReadFS; + node->Write = ATA_WriteFS; + node->IOCtl = ATA_IOCtl; + + + // --- Scan Partitions --- + LOG("Reading MBR"); + // Read Boot Sector + ATA_ReadDMA( Disk, 0, 1, mbr ); + + // Check for a GPT table + if(mbr->Parts[0].SystemID == 0xEE) + ATA_ParseGPT(Disk); + else // No? Just parse the MBR + ATA_ParseMBR(Disk); + + LEAVE('i', 0); + return 1; +} + +/** + * \fn void ATA_ParseGPT(int Disk) + * \brief Parses the GUID Partition Table + */ +void ATA_ParseGPT(int Disk) +{ + ///\todo Support GPT Disks + Warning("GPT Disks are currently unsupported"); +} + +/** + * \fn void ATA_ParseMBR(int Disk) + */ +void ATA_ParseMBR(int Disk) +{ + int i, j = 0, k = 4; + tMBR mbr; + Uint64 extendedLBA; + + ENTER("iDisk", Disk); + + // Read Boot Sector + ATA_ReadDMA( Disk, 0, 1, &mbr ); + + // Count Partitions + gATA_Disks[Disk].NumPartitions = 0; + extendedLBA = 0; + for( i = 0; i < 4; i ++ ) + { + if( mbr.Parts[i].SystemID == 0 ) continue; + if( + mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 // LBA 28 + || mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 // LBA 48 + ) + { + if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) { + LOG("Extended Partition"); + if(extendedLBA != 0) { + Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); + continue; + } + extendedLBA = mbr.Parts[i].LBAStart; + continue; + } + LOG("Primary Partition"); + + gATA_Disks[Disk].NumPartitions ++; + continue; + } + // Invalid Partition, so don't count it + } + while(extendedLBA != 0) + { + if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 ) + break; // Stop on Errors + + extendedLBA = 0; + + if( mbr.Parts[0].SystemID == 0 ) continue; + if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 // LBA 28 + || mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 // LBA 48 + ) + { + if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) + extendedLBA = mbr.Parts[0].LBAStart; + else + gATA_Disks[Disk].NumPartitions ++; + } + + if( mbr.Parts[1].SystemID == 0 ) continue; + if( mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 // LBA 28 + || mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 // LBA 48 + ) + { + if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { + if(extendedLBA == 0) { + Warning("Disk %i has twp forward link in the extended partition", + Disk); + break; + } + extendedLBA = mbr.Parts[1].LBAStart; + } + else { + if(extendedLBA != 0) { + Warning("Disk %i lacks a forward link in the extended partition", + Disk); + break; + } + gATA_Disks[Disk].NumPartitions ++; + } + } + } + LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions); + + // Create patition array + gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) ); + + // --- Fill Partition Info --- + extendedLBA = 0; + for( i = 0; i < 4; i ++ ) + { + Log("mbr.Parts[%i].SystemID = 0x%02x", i, mbr.Parts[i].SystemID); + if( mbr.Parts[i].SystemID == 0 ) continue; + if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) // LBA 28 + { + if( mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 5 ) { + if(extendedLBA != 0) { + Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); + continue; + } + extendedLBA = mbr.Parts[1].LBAStart; + continue; + } + // Create Partition + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i, + mbr.Parts[i].LBAStart, mbr.Parts[i].LBALength + ); + j ++; + continue; + } + if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) // LBA 48 + { + if( mbr.Parts[i].SystemID == 0xF || mbr.Parts[i].SystemID == 5 ) { + if(extendedLBA != 0) { + Warning("Disk %i has multiple extended partitions, ignoring rest", Disk); + continue; + } + extendedLBA = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart; + continue; + } + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, i, + (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart, + (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength + ); + j ++; + } + // Invalid Partition, so don't count it + } + // Scan extended partition + while(extendedLBA != 0) + { + if( ATA_ReadDMA( Disk, extendedLBA, 1, &mbr ) != 0 ) + break; // Stop on Errors + + extendedLBA = 0; + + // Check first entry (should be partition) + if( mbr.Parts[0].SystemID != 0) + { + if( mbr.Parts[0].Boot == 0x0 || mbr.Parts[0].Boot == 0x80 ) // LBA 28 + { + // Forward Link to next Extended partition entry + if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) + extendedLBA = mbr.Parts[0].LBAStart; + else { + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, + mbr.Parts[0].LBAStart, mbr.Parts[0].LBALength + ); + j ++; k ++; + } + } + else if( mbr.Parts[0].Boot == 0x1 || mbr.Parts[0].Boot == 0x81 ) // LBA 48 + { + if(mbr.Parts[0].SystemID == 0xF || mbr.Parts[0].SystemID == 0x7) + extendedLBA = (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart; + else { + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, + (mbr.Parts[0].StartHi << 16) | mbr.Parts[0].LBAStart, + (mbr.Parts[0].LengthHi << 16) | mbr.Parts[0].LBALength + ); + j ++; k ++; + } + } + } + + // Check second entry (should be forward link) + if( mbr.Parts[1].SystemID != 0) + { + if(mbr.Parts[1].Boot == 0x0 || mbr.Parts[1].Boot == 0x80 ) // LBA 28 + { + if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { + if(extendedLBA == 0) { + Warning("Disk %i has twp forward link in the extended partition", + Disk); + break; + } + extendedLBA = mbr.Parts[1].LBAStart; + } + else + { + if(extendedLBA != 0) { + Warning("Disk %i lacks a forward link in the extended partition", + Disk); + break; + } + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, + mbr.Parts[1].LBAStart, mbr.Parts[1].LBALength + ); + j ++; k ++; + } + + } + else if( mbr.Parts[1].Boot == 0x1 || mbr.Parts[1].Boot == 0x81 ) // LBA 48 + { + if(mbr.Parts[1].SystemID == 0xF || mbr.Parts[1].SystemID == 0x7) { + if(extendedLBA == 0) { + Warning("Disk %i has twp forward link in the extended partition", + Disk); + break; + } + extendedLBA = (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart; + } + else + { + if(extendedLBA != 0) { + Warning("Disk %i lacks a forward link in the extended partition", + Disk); + break; + } + ATA_int_MakePartition( &gATA_Disks[Disk].Partitions[j], Disk, k, + (mbr.Parts[1].StartHi << 16) | mbr.Parts[1].LBAStart, + (mbr.Parts[1].LengthHi << 16) | mbr.Parts[1].LBALength + ); + j ++; k ++; + } + } + } + } + + LEAVE('-'); +} + +/** + * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length) + * \brief Fills a parition's information structure + */ +void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length) +{ + ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length); + Part->Start = Start; + Part->Length = Length; + Part->Name[0] = 'A'+Disk; + if(Num >= 10) { + Part->Name[1] = '1'+Num/10; + Part->Name[2] = '1'+Num%10; + Part->Name[3] = '\0'; + } else { + Part->Name[1] = '1'+Num; + Part->Name[2] = '\0'; + } + Part->Node.NumACLs = 0; // Only root can read/write raw block devices + Part->Node.Inode = (Disk << 8) | Num; + Part->Node.ImplPtr = Part->Name; + + Part->Node.Read = ATA_ReadFS; + Part->Node.Write = ATA_WriteFS; + Part->Node.IOCtl = ATA_IOCtl; + LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node); + LEAVE('-'); +} + +/** + * \fn Uint16 ATA_GetPortBase(int Disk) + * \brief Returns the base port for a given disk + */ +Uint16 ATA_GetBasePort(int Disk) +{ + switch(Disk) + { + case 0: case 1: return IDE_PRI_BASE; + case 2: case 3: return IDE_SEC_BASE; + } + return 0; +} + +/** + * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos) + */ +char *ATA_ReadDir(tVFS_Node *Node, int Pos) +{ + if(Pos >= giATA_NumNodes || Pos < 0) return NULL; + return strdup( gATA_Nodes[Pos]->ImplPtr ); +} + +/** + * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name) + */ +tVFS_Node *ATA_FindDir(tVFS_Node *Node, char *Name) +{ + int part; + // Check first character + if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS) + return NULL; + // Raw Disk + if(Name[1] == '\0') { + if( gATA_Disks[Name[0]-'A'].Sectors == 0 ) + return NULL; + return &gATA_Disks[Name[0]-'A'].Node; + } + + // Partitions + if(Name[1] < '0' || '9' < Name[1]) return NULL; + if(Name[2] == '\0') { // <= 9 + part = Name[1] - '0'; + part --; + return &gATA_Disks[Name[0]-'A'].Partitions[part].Node; + } + // > 9 + if('0' > Name[2] || '9' < Name[2]) return NULL; + if(Name[3] != '\0') return NULL; + + part = (Name[1] - '0') * 10; + part += Name[2] - '0'; + part --; + return &gATA_Disks[Name[0]-'A'].Partitions[part].Node; + +} + +/** + * \fn Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + */ +Uint64 ATA_ReadFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + int disk = Node->Inode >> 8; + int part = Node->Inode & 0xFF; + + // Raw Disk Access + if(part == 0xFF) + { + if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE ) + Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset; + } + // Partition + else + { + if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset; + Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE; + } + + //Log("ATA_ReadFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer); + return DrvUtil_ReadBlock(Offset, Length, Buffer, ATA_ReadRaw, SECTOR_SIZE, disk); +} + +/** + * \fn Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + */ +Uint64 ATA_WriteFS(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + int disk = Node->Inode >> 8; + int part = Node->Inode & 0xFF; + + // Raw Disk Access + if(part == 0xFF) + { + if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE ) + Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset; + } + // Partition + else + { + if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + return 0; + if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) + Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset; + Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE; + } + + Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer); + Debug_HexDump("ATA_WriteFS", Buffer, Length); + return DrvUtil_WriteBlock(Offset, Length, Buffer, ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, disk); +} + +/** + * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data) + * \brief IO Control Funtion + */ +int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data) +{ + switch(Id) + { + case DRV_IOCTL_TYPE: return DRV_TYPE_DISK; + } + return 0; +} + +// --- Disk Access --- +/** + * \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) + */ +Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) +{ + int ret; + Uint offset; + Uint done = 0; + + // Pass straight on to ATA_ReadDMAPage if we can + if(Count <= MAX_DMA_SECTORS) + { + ret = ATA_ReadDMA(Disk, Address, Count, Buffer); + if(ret == 0) return 0; + return Count; + } + + // Else we will have to break up the transfer + offset = 0; + while(Count > MAX_DMA_SECTORS) + { + ret = ATA_ReadDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset); + // Check for errors + if(ret != 1) return done; + // Change Position + done += MAX_DMA_SECTORS; + Count -= MAX_DMA_SECTORS; + offset += MAX_DMA_SECTORS*SECTOR_SIZE; + } + + ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset); + if(ret != 1) return 0; + return done+Count; +} + +/** + * \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) + */ +Uint ATA_WriteRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk) +{ + int ret; + Uint offset; + Uint done = 0; + + // Pass straight on to ATA_WriteDMA if we can + if(Count <= MAX_DMA_SECTORS) + { + ret = ATA_WriteDMA(Disk, Address, Count, Buffer); + if(ret == 0) return 0; + return Count; + } + + // Else we will have to break up the transfer + offset = 0; + while(Count > MAX_DMA_SECTORS) + { + ret = ATA_WriteDMA(Disk, Address+offset, MAX_DMA_SECTORS, Buffer+offset); + // Check for errors + if(ret != 1) return done; + // Change Position + done += MAX_DMA_SECTORS; + Count -= MAX_DMA_SECTORS; + offset += MAX_DMA_SECTORS*SECTOR_SIZE; + } + + ret = ATA_WriteDMA(Disk, Address+offset, Count, Buffer+offset); + if(ret != 1) return 0; + return done+Count; +} + +/** + * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) + */ +int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) +{ + int cont = (Disk>>1)&1; // Controller ID + int disk = Disk & 1; + Uint16 base; + + ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer); + + // Check if the count is small enough + if(Count > MAX_DMA_SECTORS) { + Warning("Passed too many sectors for a bulk DMA read (%i > %i)", + Count, MAX_DMA_SECTORS); + LEAVE('i'); + return 0; + } + + // Get exclusive access to the disk controller + LOCK( &giaATA_ControllerLock[ cont ] ); + + // Set Size + gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; + + // Get Port Base + base = ATA_GetBasePort(Disk); + + // Reset IRQ Flag + gaATA_IRQs[cont] = 0; + + // Set up transfer + outb(base+0x01, 0x00); + if( Address > 0x0FFFFFFF ) // Use LBA48 + { + outb(base+0x6, 0x40 | (disk << 4)); + outb(base+0x2, 0 >> 8); // Upper Sector Count + outb(base+0x3, Address >> 24); // Low 2 Addr + outb(base+0x3, Address >> 28); // Mid 2 Addr + outb(base+0x3, Address >> 32); // High 2 Addr + } + else + { + outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr + } + + outb(base+0x02, (Uint8) Count); // Sector Count + outb(base+0x03, (Uint8) Address); // Low Addr + outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr + outb(base+0x05, (Uint8) (Address >> 16)); // High Addr + + LOG("Starting Transfer"); + #if START_BEFORE_CMD + // Start transfer + ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start + if( Address > 0x0FFFFFFF ) + outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48) + else + outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28) + #else + if( Address > 0x0FFFFFFF ) + outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48) + else + outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28) + // Start transfer + ATA_int_BusMasterWriteByte( cont << 3, 9 ); // Read and start + #endif + + // Wait for transfer to complete + //ATA_int_BusMasterWriteByte( (cont << 3) + 2, 0x4 ); + while( gaATA_IRQs[cont] == 0 ) { + //Uint8 val = ATA_int_BusMasterReadByte( (cont << 3) + 2, 0x4 ); + //LOG("val = 0x%02x", val); + Threads_Yield(); + } + + // Complete Transfer + ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop + + LOG("Transfer Completed & Acknowledged"); + + // Copy to destination buffer + memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE ); + + // Release controller lock + RELEASE( &giaATA_ControllerLock[ cont ] ); + + LEAVE('i', 1); + return 1; +} + +/** + * \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) + */ +int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer) +{ + int cont = (Disk>>1)&1; // Controller ID + int disk = Disk & 1; + Uint16 base; + + // Check if the count is small enough + if(Count > MAX_DMA_SECTORS) return 0; + + // Get exclusive access to the disk controller + LOCK( &giaATA_ControllerLock[ cont ] ); + + // Set Size + gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE; + + // Get Port Base + base = ATA_GetBasePort(Disk); + + // Set up transfer + outb(base+0x01, 0x00); + if( Address > 0x0FFFFFFF ) // Use LBA48 + { + outb(base+0x6, 0x40 | (disk << 4)); + outb(base+0x2, 0 >> 8); // Upper Sector Count + outb(base+0x3, Address >> 24); // Low 2 Addr + outb(base+0x3, Address >> 28); // Mid 2 Addr + outb(base+0x3, Address >> 32); // High 2 Addr + } + else + { + outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F)); //Disk,Magic,High addr + } + + outb(base+0x02, (Uint8) Count); // Sector Count + outb(base+0x03, (Uint8) Address); // Low Addr + outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr + outb(base+0x05, (Uint8) (Address >> 16)); // High Addr + if( Address > 0x0FFFFFFF ) + outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48) + else + outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28) + + // Reset IRQ Flag + gaATA_IRQs[cont] = 0; + + // Copy to output buffer + memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE ); + + // Start transfer + ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start + + // Wait for transfer to complete + while( gaATA_IRQs[cont] == 0 ) Threads_Yield(); + + // Complete Transfer + ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop + + // Release controller lock + RELEASE( &giaATA_ControllerLock[ cont ] ); + + return 1; +} + +/** + * \fn void ATA_IRQHandlerPri(int unused) + */ +void ATA_IRQHandlerPri(int unused) +{ + Uint8 val; + + // IRQ bit set for Primary Controller + val = ATA_int_BusMasterReadByte( 0x2 ); + LOG("IRQ val = 0x%x", val); + if(val & 4) { + LOG("IRQ hit (val = 0x%x)", val); + ATA_int_BusMasterWriteByte( 0x2, 4 ); + gaATA_IRQs[0] = 1; + return ; + } +} + +/** + * \fn void ATA_IRQHandlerSec(int unused) + */ +void ATA_IRQHandlerSec(int unused) +{ + Uint8 val; + // IRQ bit set for Secondary Controller + val = ATA_int_BusMasterReadByte( 0xA ); + if(val & 4) { + LOG("IRQ hit (val = 0x%x)", val); + ATA_int_BusMasterWriteByte( 0xA, 4 ); + gaATA_IRQs[1] = 1; + return ; + } +} + +/** + * \fn Uint8 ATA_int_BusMasterReadByte(int Ofs) + */ +Uint8 ATA_int_BusMasterReadByte(int Ofs) +{ + if( gATA_BusMasterBase & 1 ) + return inb( (gATA_BusMasterBase & ~1) + Ofs ); + else + return *(Uint8*)(gATA_BusMasterBasePtr + Ofs); +} + +/** + * \fn void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value) + * \brief Writes a byte to a Bus Master Register + */ +void ATA_int_BusMasterWriteByte(int Ofs, Uint8 Value) +{ + if( gATA_BusMasterBase & 1 ) + outb( (gATA_BusMasterBase & ~1) + Ofs, Value ); + else + *(Uint8*)(gATA_BusMasterBasePtr + Ofs) = Value; +} + +/** + * \fn void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value) + * \brief Writes a dword to a Bus Master Register + */ +void ATA_int_BusMasterWriteDWord(int Ofs, Uint32 Value) +{ + + if( gATA_BusMasterBase & 1 ) + outd( (gATA_BusMasterBase & ~1) + Ofs, Value ); + else + *(Uint32*)(gATA_BusMasterBasePtr + Ofs) = Value; +} diff --git a/Modules/IPStack/main.c b/Modules/IPStack/main.c index 831000a4..5f34d9a1 100644 --- a/Modules/IPStack/main.c +++ b/Modules/IPStack/main.c @@ -3,7 +3,7 @@ * - Stack Initialisation */ #define DEBUG 0 -#define VERSION VER3(0,10,0) +#define VERSION VER2(0,10) #include "ipstack.h" #include "link.h" #include