Скачал себе спецификацию команд ATA/ATAPI Command Set с www.t13.org. В ней все входные данные для команд описываются в виде: Код (Text): Word 00h Feature ... 01h Count ... 02h LBA ... 03h ... 04h ... 05h Device ... А куда эти ворды писать, в какие порты, я так и не понял. Объясните кто знает.
Asvald Для начала можно здесь почитать www.wasm.ru/article.php?article=atazen01 А на t13.org про порты также доки есть.
Из статей "ATA для дZенствующих" я понял что все порты(кроме 1F0/170) 8 битные, как тогда в них записывать слова, последовательно по байту? Куда записывать 28-битный адрес сектора я понял, а куда писать 48-битный при LBA48? И отличается ли еще как-то LBA48 от LBA28 помимо разрядности адреса?
Asvald Да отличается. Вопервых способом адрессации. Во вторых расхождения в командах есть, правда незначительно. Почитай на томже сайте там и про LBA48 расписано. Там чтобы записать вторые 24 нужно установить верхнии биты 28-25 в 111b (пишу по памяти могу путать).
В некоторых источниках(например у Кулакова) пишется, что при чтении из порта 1F7h сбрасывается IRQ14, но не написано когда оно восстанавливается или это нужно делать вручную через порт 0A1h? У меня что-то никак не получается: прерывание генерируется только после первого чтения сектора через команду 20h, при дальнейших выполнениях этой команды(20h) данные с диска читаются, но IRQ14 не возникает.
Код моей процедуры. Код (Text): Prim_base_port = 1F0h Sec_base_port = 170h Prim_base_alter_reg =3f6h Primary = 0 Secondary = 1F0h-170h ATA_StateReg = 7h ATA_CommandReg = 7h ATA_DeviceReg = 6h ATA_BSY = 80h ATA_DRDY = 40h ATA_LBAHighReg =5h ATA_LBAMidReg =4h ATA_LBALowReg =3h ATA_CountReg =2h ATA_FeatureReg =1h ATA_AlterStateReg =3f6h-376h ATA_WAIT_FOR_COMMAND equ 20h,24h ATA_NO_WAIT_FOR_COMAND equ 30h ;Посылает команды ATA устройствам ;Вход: ebx[15:0] - Count 1F2/172 ; ebx[31:16] - Feature 1F1/171 ; edi[31:0] - LBA[31:0] 1F3,1F4,1F5/173,174,175 ; esi[31:16] - LBA[47:32] ; ecx[15:8] - Device 1F6/176 ; ecx[7:0] - Command 1F7/177 ; esi[15:0] - канал Primary/Secondary ; ecx[32] - Если 0- Завершение команды произойдет по прерыванию ; 1- Завершение команды ожидать не нужно, сразу вернуть управление proc ATA_SendCommand mov dx,Prim_base_port sub dx,si ;Выбор канала ATA add dx,ATA_StateReg ;Ждем освобождения канала, если канал свободен, то BSY=0 @@: ;а если занят,то BSY=1 in al,dx test al,ATA_BSY jnz @b mov eax,ecx ;Выбираем устройство на канале и ждем, когда ;оно будет готово к приему команды(DRDY=0) shr eax,8 ;AL=Device sub dx,ATA_StateReg-ATA_DeviceReg out dx, al add dx,ATA_StateReg-ATA_DeviceReg @@: ;Ждем, DRDY=1 и BSY=0 in al,dx test al,ATA_BSY ;BSY=1? jnz @b test al,ATA_DRDY ;DRDY=1? jz @b ;Загружаем LBA в следующей последовательности ;The host shall transmit bits 47:40 to the LBA High register. ;The host shall transmit bits 39:32 to the LBA Mid register. ;The host shall transmit bits 31:24 to the LBA Low register. ;The host shall transmit bits 23:16 to the LBA High register. ;The host shall transmit bits 15:8 to the LBA Mid register. ;The host shall transmit bits 7:0 to the LBA Low register. mov eax,esi shr eax,16 ;AH=LBA[47:40] AL=LBA[39:32] sub dx,ATA_StateReg-ATA_LBAHighReg xchg ah,al out dx,al sub dx,ATA_LBAHighReg-ATA_LBAMidReg xchg ah,al out dx,al mov eax,edi push eax shr eax,16 ;AH=LBA[31:24] AL=LBA[23:16] sub dx,ATA_LBAMidReg-ATA_LBALowReg xchg ah,al out dx,al add dx,ATA_LBAHighReg-ATA_LBALowReg xchg ah,al out dx,al pop eax ;AH=LBA[15:8] AL=LBA[7:0] sub dx,ATA_LBAHighReg-ATA_LBAMidReg xchg ah,al out dx,al sub dx,ATA_LBAMidReg-ATA_LBALowReg xchg ah,al out dx,al sub dx,ATA_LBALowReg-ATA_CountReg ;записываем Count и Feature mov eax,ebx out dx,al xchg ah,al out dx,al ;shr ebx,16 ;sub dx,ATA_CountReg-ATA_FeatureReg ;out dx,bl ;out dx,bh test ecx,10000h jnz @f pop ebp mov eax,[esp] add esp,4 ;Очищаем стек mov [at_caller],eax mov [Wait_Flag],1 @@: mov eax,ecx ;Посылаем команду Al=Command add dx,ATA_CommandReg-ATA_CountReg out dx,al test ecx, 10000h jz @f retrn @@: ;Здесь произойдет прерывание 0Eh(14) сигнализирующее о том, ;что ATA устройство отработало и готово передавать или получать данные jmp $ ;Уходим в бесконечный цикл, но здесь должно быть перекючение на другую задачу retrn Wait_Flag dd 0 ;Флаг сигнализирующий о том, ожидается ли завершение операции at_caller dd 0 ;Адрес вызвавшего кода
Все разобрался, проблема была в обработчике irq14, в котором я некорректно сбрасывал бит в ISR, поэтому все последующие irq14 были запрещены.
Вопрос: процедура чтения секторов написанная для ATA-4 будет ли корректно работать с последующими версиями?
Спасибо за внимание. Еще пара вопросов. Вопрос №2: На какие порты проецируются "Data Port", "Alternate Status register-Device Control register"? Для остальных вроде нашёл: Код (Text): BASE = 0x1F0 DATA_REG = BASE + 0 FEATURES_REG = BASE + 0x1 ERROR_REG = BASE + 0x1 SECTCOUNT_REG = BASE + 0x2 SECTNUM_REG = BASE + 0x3 CHIGH_REG = BASE + 0x4 CLOW_REG = BASE + 0x5 DEVICEHEAD_REG = BASE + 0x6 COMMAND_REG = BASE + 0x7 STATUS_REG = BASE + 0x7 Вопрос №3: В винде для первичного канала указан диапазон ввода/вывода 0x1F0-0x1F7 и 0x3F6. Так вот какой регистр отображается в 0x3F6?
Код (Text): #define HDD_PORT_DR_1 0x1F0 // Регистр данных. Только для PIO, младший байт #define HDD_PORT_DR_2 0x1F1 // Регистр данных. Только для PIO, старший байт, только запись #define HDD_PORT_ER 0x1F1 // Регистр ошибки. Только чтение. Содержит информацию при (SR & HDD_REG_SR_ERR) > 0 #define HDD_PORT_FT 0x1F1 // Регистр свойств. Формат зависит от команды, только запись #define HDD_PORT_SC 0x1F2 // Количество секторов, если 0, то читается 256 секторов #define HDD_PORT_SN 0x1F3 // CHS: номер сектора, LBA: 0-7 биты #define HDD_PORT_CL 0x1F4 // CHS: номер циллиндра, младший байт, LBA: 8-15 биты #define HDD_PORT_CH 0x1F5 // CHS: номер циллиндра, старший байт, LBA: 16-23 биты #define HDD_PORT_DH 0x1F6 // Биты 0-3: CHS: номер головки, LBA: 24-27 биты. Бит 4: номер устройства. Бит 6: 0 - CHS, 1 - LBA #define HDD_PORT_SR 0x1F7 // Регистр состояния, только чтение #define HDD_PORT_CR 0x1F7 // Коммандный регистр, только запись #define HDD_PORT_AC 0x3F6 // Альтернативный регистр состояния, только чтение
Пытаюсь прочитать первый сектор в ring0 и вылетает BSOD. Может кто подскажет что я делаю не так? Код (Text): include '%fasminc%\win32a.inc' format PE GUI entry DriverEntry BASE = 0x1F0 DATA_REG = BASE + 0 FEATURES_REG = BASE + 0x1 ERROR_REG = BASE + 0x1 SECCOUNT_REG = BASE + 0x2 SECNUM_REG = BASE + 0x3 CHIGH_REG = BASE + 0x4 CLOW_REG = BASE + 0x5 DEVICEHEAD_REG = BASE + 0x6 COMMAND_REG = BASE + 0x7 STATUS_REG = BASE + 0x7 DEVICECTRL_REG = 0x3F6 ALTSTATUS_REG = 0x3F6 ATA_READSECTOR = 0x20 STATUS_ERR = 0x1 STATUS_DRQ = 0x8 STATUS_DRDY = 0x40 STATUS_BSY = 0x80 DEVICEHEAD_DEV = 0x10 ;___________________________________________________________________________________________ section '.code' code readable writeable executable proc DriverEntry pDriverObject,pusRegistryPath mov dx, DEVICECTRL_REG ;| mov al, 0x2 ;| - запрет прерываний out dx, al ;| mov dx, STATUS_REG ;| @@: ;| in al, dx ;| test al, STATUS_BSY ;| - ожидание BSY=0 и DRQ=0 jnz @b ;| test al, STATUS_DRQ ;| jnz @b ;| mov dx, DEVICEHEAD_REG ;| in al, dx ;| - выбор Device0 and al, not DEVICEHEAD_DEV ;| out dx, al ;| mov dx, STATUS_REG ;| @@: ;| in al, dx ;| test al, STATUS_BSY ;| - ожидание BSY=0 и DRQ=0 jnz @b ;| test al, STATUS_DRQ ;| jnz @b ;| mov dx, SECCOUNT_REG ;| mov al, 1 ;| - количество секторов out dx, al ;| mov dx, SECNUM_REG ;| mov al, 1 ;| - LBA [0..7] out dx, al ;| mov dx, CLOW_REG ;| xor al, al ;| - LBA [8..15] out dx, al ;| mov dx, CHIGH_REG ;| xor al, al ;| - LBA [17..23] out dx, al ;| mov dx, DEVICEHEAD_REG ;| mov al, 0x40 ;| out dx, al ;| mov dx, STATUS_REG ;| @@: ;| in al, dx ;| test al, STATUS_BSY ;| - ожидание BSY=0 и DRQ=0 jnz @b ;| test al, STATUS_DRQ ;| jnz @b ;| mov dx, COMMAND_REG ;| mov al, ATA_READSECTOR ;| out dx, al ;| mov dx, ALTSTATUS_REG ;| in al, dx ;| mov dx, STATUS_REG ;| @@: ;| in al, dx ;| test al, STATUS_BSY ;| - ожидание BSY=0 и DRQ=1 jnz @b ;| test al, STATUS_DRQ ;| jz @b ;| mov dx, DATA_REG ;| mov edi, buffer ;| mov ecx, 256 ;| - чтение данных cld ;| rep insw ;| mov dx, ALTSTATUS_REG ;| in al, dx ;| mov dx, STATUS_REG ;| in al, dx ;| xor eax,eax not eax ret endp ;___________________________________________________________________________________________ section '.data' data readable writeable buffer rw 256
Код (Text): NTSTATUS ReadSector(ULONG dwType, PVOID pBuffer){ ULONG dwInputType, i; USHORT wInput; if (dwType > READ_TYPE_PIO_END) dwInputType = INPUT_TYPE_DMA; else dwInputType = INPUT_TYPE_PIO; _CLI_; if (!IsControllerFree(HDD_PORT_SR)){ DbgPrint("Controller busy for a long time."); return STATUS_UNSUCCESSFUL; } OUT_PORT(HDD_PORT_DH, 0xE0); if (!IsDriveCmdReady(HDD_PORT_SR)){ DbgPrint("Drive does not ready for a long time."); return STATUS_UNSUCCESSFUL; } OUT_PORT(HDD_PORT_SC, 0x01); OUT_PORT(HDD_PORT_SN, 0x00); OUT_PORT(HDD_PORT_CL, 0x00); OUT_PORT(HDD_PORT_CH, 0x00); if (dwInputType == INPUT_TYPE_DMA) if (!InitDMAChannel()) return STATUS_UNSUCCESSFUL; switch (dwType){ case READ_TYPE_READSECTOR: OUT_PORT(HDD_PORT_CR, HDD_CMD_READSECTOR); break; case READ_TYPE_READSECTOR_RETRY: OUT_PORT(HDD_PORT_CR, HDD_CMD_READSECTOR_RETRY); break; case READ_TYPE_READMULTIPLE: OUT_PORT(HDD_PORT_CR, HDD_CMD_READMULTIPLE); break; } if (dwInputType == INPUT_TYPE_PIO){ if (!IsDriveExcReady(HDD_PORT_SR)){ DbgPrint("Drive does not ready to exchange for a long time."); return STATUS_UNSUCCESSFUL; } for (i = 0; i < 256; i++){ IN_PORTW(HDD_PORT_DR_1, wInput); ((PUSHORT)pBuffer)[i] = wInput; } } _STI_; return STATUS_SUCCESS; }