I will put the complete code of my ATA-1 Driver here once I am done writing documentation for it. However, for now, maybe reading my [ATA4IDEReadFromPortsLBA28] function will help someone understand this better:
Code: Select all
; ——————————————————————————————————————————————————
__ATA4IDEReadFromPortsLBA28:
; DWORD __ATA4IDEReadFromPortsLBA28 (DWORD Controller, DWORD Drive, DWORD LBA28,
; DWORD SectorCount, void* Buffer, DWORD MaxBufferLen);
; Returns the number of sectors that were read from the drive
PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
PUSHFD
PUSH EBP
MOV EBP , ESP
; [EBP + 0x20] = Controller
; [EBP + 0x24] = Drive
; [EBP + 0x28] = LBA28
; [EBP + 0x2C] = SectorCount
; [EBP + 0x30] = Buffer
; [EBP + 0x34] = MaxBufferLen
.CheckSectorCount1:
; Sector Count must not be zero
MOV ESI , DWORD PTR [EBP + 0x2C]
TEST ESI , ESI
JNZ .CheckSectorCount2
JMP .Failure
.CheckSectorCount2:
; ESI = [SectorCount]
; Sector count must not be bigger than 255
TEST ESI , 0xFFFFFF00
JZ .CheckBufferLength1
JMP .Failure
.CheckBufferLength1:
; Buffer Length must not be zero
; ESI = [SectorCount]
MOV ECX , DWORD PTR [EBP + 0x34]
TEST ECX , ECX
JNZ .CheckBufferLength2
JMP .Failure
.CheckBufferLength2:
; Buffer length must be equal to or greater than SectorCount * 512
; ECX = [MaxBufferLen]
; ESI = [SectorCount]
SHL ESI , 0x00000009 ; ESI = SectorCount * 512
CMP ECX , ESI
JAE .CheckLBA28
JMP .Failure
.CheckLBA28:
SHR ESI , 0x00000009
; ESI = [SectorCount]
; ECX = [MaxBufferLen]
; LBA28 must not have its leftmost nibble set
MOV EBX , DWORD PTR [EBP + 0x28]
TEST EBX , 0xF0000000
JZ .CheckController
JMP .Failure
.CheckController:
; ESI = [SectorCount]
; ECX = [MaxBufferLen]
; EBX = [LBA28]
MOV EDX , DWORD PTR [EBP + 0x20] ; Controller
TEST EDX , ~(IDE_PRIMARY_CONTROLLER | IDE_SECONDARY_CONTROLLER)
JZ .CheckDrive
JMP .Failure
.CheckDrive:
; ESI = [SectorCount]
; ECX = [MaxBufferLen]
; EBX = [LBA28]
; EDX = [Controller]
MOV EDI , DWORD PTR [EBP + 0x24] ; Drive
TEST EDI , ~(IDE_DRIVE0 | IDE_DRIVE1)
JZ .GetPorts
JMP .Failure
.GetPorts:
; ESI = [SectorCount]
; ECX = [MaxBufferLen]
; EBX = [LBA28]
; EDX = [Controller]
; EDI = [Drive]
MOV EBX , PIDEC_PORT_BASE
TEST EDX , EDX
JZ .PrimaryControllerIsSelected
MOV EBX , SIDEC_PORT_BASE
.PrimaryControllerIsSelected:
; Before we go on, the BSY and DRQ bits in the status register
; must have been set to zero
MOV ECX , IDE_TYPICAL_TIMEOUT
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
XOR EAX , EAX
.CheckBSYAndDRQ1:
NOP
IN AL , DX
AND EAX , (IDE_STATUSREG_DRQ | IDE_STATUSREG_BSY)
JZ .CheckDriveExistence
DEC ECX
JNZ .CheckBSYAndDRQ1
JMP .Failure
.CheckDriveExistence:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
; EDX = Status register's port address
; EDI = [Drive]
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_DRIVEHEAD
MOV EAX , EDI
AND EAX , (IDE_DRIVE0 | IDE_DRIVE1)
SHL EAX , 0x00000004
OUT DX , AL
TIMES 0x04 NOP
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
XOR EAX , EAX
IN AL , DX
TEST EAX , IDE_STATUSREG_DRDY
JNZ .ClearnIEN
JMP .Failure
; The nIEN bit must be cleared in the Device Control Register for
; interrupts to be generated by the device
.ClearnIEN:
XOR EAX , EAX
MOV EDX , IDEC_PORT_DEVICECONTROL
OUT DX , AL
TIMES 0x04 NOP
.SetSectorcount:
MOV EAX , ESI
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_SECTORCOUNT
OUT DX , AL
TIMES 0x04 NOP
.SetLBA0TO7:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
; EDI = [Drive]
MOV EAX , DWORD PTR [EBP + 0x28] ; LBA28
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_LBABITS0TO7
OUT DX , AL
TIMES 0x04 NOP
.SetLBA8TO15:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
; EDI = [Drive]
; EAX = LBA28
SHR EAX , 0x00000008
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_LBABITS8TO15
OUT DX , AL
TIMES 0x04 NOP
.SetLBA16TO23:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
; EDI = [Drive]
; EAX = LBA28 >> 8
SHR EAX , 0x00000008
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_LBABITS16TO23
OUT DX , AL
TIMES 0x04 NOP
.SetLBA24TO27:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
; EDI = [Drive]
; EAX = LBA28 >> 16
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_LBABITS24TO27
SHR EAX , 0x00000008
AND EDI , (IDE_DRIVE0 | IDE_DRIVE1)
SHL EDI , 0x00000004
OR EDI , IDE_DRIVEHEADREG_L
OR EAX , EDI
OUT DX , AL
TIMES 0x04 NOP
.SendReadWithRetryCommand:
; ESI = [SectorCount]
; EBX = The base port address of the selected controller
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_COMMAND
MOV EAX , MIDE_CMD_READSECTORSWR
OUT DX , AL
TIMES 0x04 NOP
.PrepareToReadData:
MOV EDI , DWORD PTR [EBP + 0x30] ; Buffer
; EDI = [Buffer]
; ESI = [SectorCount]
.StartReadingData:
; When the device is ready to transfer the data,
; it will clear BSY and set DRQ
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
MOV ECX , IDE_TYPICAL_TIMEOUT
XOR EAX , EAX
.WaitForBSYAndDRQ:
NOP
IN AL , DX
AND EAX , (IDE_STATUSREG_BSY | IDE_STATUSREG_DRQ)
XOR EAX , IDE_STATUSREG_DRQ
JZ .PrepareToSenseInterrupt
DEC ECX
JNZ .WaitForBSYAndDRQ
JMP .Failure
.PrepareToSenseInterrupt:
MOV EAX , IRQ_PULSE_IRQ14
CMP EBX , PIDEC_PORT_BASE
JE .SenseInterrupt
MOV EAX , IRQ_PULSE_IRQ15
.SenseInterrupt:
INVOKE __WaitForIRQPulse, EAX
.CheckStatusRegister1:
; EDX = Status Register's port address
IN AL , DX
.ReadData:
; EDI = [Buffer]
CLD
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_DATA
MOV ECX , 512 / 2 ; We are reading 2 bytes at a time and one sector after the other
REP INSW
DEC ESI
JNZ .StartReadingData
; Now that the data is read, we should first read the
; Alternate Status Register and ignore the result
; EBX = The base port address of the selected controller
.ReadAlternateStatusRegister:
MOV EDX , IDEC_PORT_ALTERNATESTATUS
IN AL , DX
TIMES 0x04 NOP
; Reading the Status Register is also recommended by ATA-4 specifications
.ReadStatusRegister:
; EBX = The base port address of the selected controller
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
IN AL , DX
TIMES 0x04 NOP
.SetResult:
; [EBP + 0x2C] = SectorCount
MOV EAX , DWORD PTR [EBP + 0x2C]
JMP .EP
.Failure:
XOR EAX , EAX
.EP:
POP EBP
POPFD
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX
RET 0x18
; ——————————————————————————————————————————————————