Суть: читаю группу секторов путем READ DMA (C8h). До 128к (256 секторов) все хорошо, прерывания дожидаюсь в рамках 0.2 с (таймаут 10 тиков, частоту таймера не менял). Операция завершается успешно, состояние IDE/BM в норме. Далее я делаю PRDT на бОльший объем (например, 257 секторов), запускаю первый обмен на 256 (максимум)... и прерывание не приходит ни сразу, ни через 10 минут. Состояние BM/IDE: - qemu: BMActive=0, BMInt=1 (но прерывания нет!!), IDEBusy=IDEDRDY=IDEDRQ=1 - vmware: BMActive=1, BMInt=0, IDE аналогично qemu При записи BMInt=BMError=1 (т.е. сбросе этих флагов) имеем у qemu все по нулям, у vmware ничего не меняется. У меня есть смутное подозрение, что я что-то кому-то забываю сказать. Но т.к. момент, когда объем трансфера в PRDT превышает таковой у IDE-команды, нигде толком не описан, что делать я не знаю. Прерывание вообще должно приходить в такой ситуации? По идее должно, т.к. оно приходит по завершению IDE-команды, а она, по идее, завершается после передачи 256 секторов. Если нет, то как узнать о ее завершении? Поллинг? Но тогда о каком DMA может идти речь, я с тем же успехом могу через PIO работать. Я, конечно, пойду снова (в 15 раз) искать ошибку, но если кто знает, в чем дело - плс, поделитесь. Так же интересно, как запускать продолжение передачи. Т.е. у ВМ должно быть active/int = 1/1, а что потом? Просто подавать следующую команду винту? ВМ будет нас "ждать"? зы Да, в данной ситуации сектора реально считываются, т.е. передача таки происходит.
Переделал. Теперь, если винт не умеет LBA48, я с него читаю кусками по 128к и не больше. Все работает. Если винт умеет LBA48, я пытаюсь читать по 65536 секторов (32М), но и тут какие-то чудеса. Опять не приходит прерывание. Опытным путем выяснил, что затык (у qemu, vmware делает вид, что не умеет LBA48) начинается при пересечении PRDT границы в 4к (реальный режим у меня). Т.е., на "страницу" помещается 512 PRD, если каждая описывает 4к передачи, то имеем затык после 4096 секторов (4097 не пролазят). Если каждая описывает 8к, то затык, соотв., на 8192 и т.д. Собсна, это почему так? В спецификации четко сказано - таблица не более 64к, не пересекает 64к. У меня она лежит по 80000h. Имхо, ровнее некуда.
active/int = 1/1 означает, что для команды слишком много данных. Я вообще не понял, как ты собирался прочитать больше 256 секторов в режиме DMA/LBA28. Я надеюсь, для DMA/LBA48 ты используешь команду 25h, а не 0C8h. Попробуй все буферы (и таблицу и конечные буферы) разместить выше границы 16 мег.
Эээ... разве? Для случая 1/1 Т.е. PRD еще есть, а винт трансфер закончил. Именно так и собирался - например, таблица описывает 256к передачи, следовательно, необходимо 2 команды винту в рамках этой таблицы. Но так или наче 1/1 я не дождался, как и прерывания. LBA48 - да, 25h. Выше 16 метров попробую, хотя не уверен, что это что-то даст. Хм... кстати не помешает просто потаскать PRDT по оперативе.
Vic3Dexe, если не секрет прикрепи пожалуйста кусок кода где 48битовую команду в регистры записываешь (особенно, что касаемо LBA и счетчика секторов), имею подозрение, что ошибка именно там. Если диск поддерживает LBA48 я читаю по мегабайту (по 32 я подумал, что многовато), при этом никакой разницы при работе BM относительно LBA28 не увидел. И еще ключевой вопрос: при использовании DMA READ48 (именно 48, а не 28) при чтении блоками до 257 секторов все нормально работает? Просто, насколько я понял, в первом сообщении речь шла о DMA READ28. Но все же отмечу, что если с 28битовыми командами нормально прерывания приходят, то крайне маловероятно, что причина в BM. У меня подобная ситуация на PIIX происходила, все точно тоже самое практически, а оказалось, что 48битовые команды неправильно передаю.
Код (Text): mov eax,65536 cmp dword [IDEInfo.LBACount],eax ; cmovb eax,dword [IDEInfo.LBACount] ;<---- вот это вот остатки, оно тут уже не надо sub dword [IDEInfo.LBACount],eax ; mov ebx,eax mov dx,IDE_SECT_COUNT_REG xchg al,ah ;count 15:8 call IDEWritePort xchg al,ah ;count 7:0 out dx,al mov eax,dword [IDEInfo.LBAStart+4] mov dx,IDE_LBA_1 call IDEWritePort ;LBA 39:32 mov al,ah mov dx,IDE_LBA_2 call IDEWritePort ;LBA 47:40 mov eax,dword [IDEInfo.LBAStart] rol eax,8 mov dx,IDE_LBA_0 call IDEWritePort ;LBA 31:24 shr eax,8 out dx,al ;LBA 7:0 shr eax,8 mov dx,IDE_LBA_1 call IDEWritePort ;LBA 15:8 mov al,ah mov dx,IDE_LBA_2 call IDEWritePort ;LBA 23:16 mov dx,IDE_CMD_REG mov ax,25h call IDEWritePort Я без проблем читаю то число секторов, которое описывается PRDT в рамках 4к памяти, т.е. 512 PRD. Если PRD больше, то наступает облом. При этом от собственно объема передачи ничего не зависит - я читал и 4096 и 32768 секторов (соотв. каждая PRD описывала либо 4к либо 32к передачи). В первом сообщении была проблема другого харакетра, я, видимо, толком это не объяснил, сорри. Просто голова уже пухнет. При LBA28 у меня не получалось включить BM передачу больше, чем передача винта. Т.е. BM прошу прочитать 512 секторов, винт столько не может за раз - я пытался дать 2 команды READ_DMA (C8), но уже после первой не было прерывания. Я забил и сделал кусками по 256 секторов (128к и у ВМ и у винта). А мне вот кажется, что грабли у qemu... Код (Text): static int dma_buf_prepare(BMDMAState *bm, int is_write) ...... for(;;) { if (bm->cur_prd_len == 0) { /* end of table (with a fail safe of one page) */ if (bm->cur_prd_last || (bm->cur_addr - bm->addr) >= 4096) <======= <censored>!!!! Что за <censored>???? return s->io_buffer_size != 0; cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8); bm->cur_addr += 8; prd.addr = le32_to_cpu(prd.addr); prd.size = le32_to_cpu(prd.size); len = prd.size & 0xfffe; if (len == 0) len = 0x10000; bm->cur_prd_len = len; bm->cur_prd_addr = prd.addr; bm->cur_prd_last = (prd.size & 0x80000000); }
Vic3Dexe, посмотрел код - вроде все правильно, я примерно также делаю. Единственное, что смутило: У тебя получается IDEWritePort в DX возвращает уже физ. адрес порта? Я честно говоря даже не знаю, возможно ли это. Откуда идея? И также думаю, что заметного прироста скорости чтения это не добавит (если именно в этом цель). При LBA28 у меня аналогично. Вполне может быть, я никогда qemu не пользовался. Я предлагаю тебе скинуть ссыль на свою версию qemu, я попробую на ней мой драйвер потестить, у меня при LBA48 читается по мегабайту и один PRD описывает 64К (ну на границах может быть ессно меньше). Только не обещаю, что сегодня, т.к. в частности надо еще с ним разобраться. А на реальном то железе пробовал тестировать? Чего-то я не пойму. Ну к примеру, если один PRD будет описывать 64К, то можно с помощью 512 PRD аж целых 32М описать, или я чего-то недопонимаю? Хотя я тоже не припомню никакого ограничения в 4Кб на PRDT.
Да, он dx не сохраняет, т.е. возвращается уже база+смещение до конкретного регистра. Эта идея из SFF8038 (Bus Master Programming Interface for IDE ATA Controllers Rev 1.0), я приводил выдержку оттуда парой постов выше про комбинацию int/active = 1/1 в состоянии ВМ. Цель была не в скорости (может быть и дало бы прирост, не знаю), цель была один раз построить PRDT и работать по ней, чем перестраивать каждые 128к. Впрочем, это легко решается/обходится, поэтому проехали. http://homepage3.nifty.com/takeda-toshiya/qemu/qemu-0.12.2-windows.zip под вынь, под другие оси хз где собраное взять, сырцы тут http://qemu.org Т.е. у тебя 1M/64k = аж 16 PRD. Так и у меня работает. Попробуй сделать таблицу на >512 PRD. Да пока не найду где. Единственная тестовая машина с IDE-винтом - fuji 6.4G, там LBA48 точно нет. А на остальных двух машинах сплошные САТА, там, ессно, ничерта не работает. Все верно, но во-1 я планирую, что PRD будет описывать только 4к (размер страницы в ПМ/лонг), во-2 я не могу понять - то ли у меня неуловимый баг в коде, то ли я ищу то, чего нет. Задал вопрос qemu-шникам по поводу их самодеятельности, ждем ответа.
Вообще-то не ессно, они вполне могут работать в режиме эмуляции IDE (пока еще вроде она не выпилена окончательно), только порты берутся из конфигурационного пространства контроллера IDE, подробнее - http://ru.osdev.wikia.com/wiki/HDD, правда в этой статье не оговорено пары незначительных отличий, а именно то, что у такого контроллера может не быть альтернативного регистра состояния и в обработчике прерывания надо обязательно сбрасывать соотв. бит прерывания канала IDE (статусный регистр IDE), иначе контроллер будет слать прерывания "до победного", независимо от состояния бита прерывания в блоке командных регистров ATA.
Давно уже нужно было попробовать на реале. И SATA - это не причина. В эмуляторах может быть недоработка по причине того, что "4 кб по 4 кб" наиболее типичная ситуация - отсюда и получилось в начале 512х8 = 4096 секторов (2 мб).
Та же самая проблема только на реальном железе: Контроллер Intel 82801G, HDD - WD 80G. Тестировал на примере из книги Кулакова "Программирование на аппаратном уровне" (листинг 11_07) и на примере, найденном на этом форуме: Код (Text): codesg segment assume cs:codesg, ds:codesg .486p org 100h start: jmp short begin ;------------------------------------------------ base_IO dw 8438h ; база ввода/вывода харда device db 0A0h ; это мастер base_BM dw 8400h ; база БусМастера ;------------------------------------------------ sect db 0FFh ; кол-во секторов для трансфера segm dw 5678h ; сегмент ОЗУ для трансфера offs dw 9ABCh ; смещение в сегменте ;------------------------------------------------ align 4 base_DTP dd ? ; база дескрипторов всегда выравнена dw ? dw ? dd ? dw ? dw ? ;------------------------------------------------ begin: push cs pop ds ; !!!!! smsw ax test al,1 jz short lab0 int 3 ;------------------------------------------------ lab0: cmp sect,0 jnz short lab1 int 3 ;------------------------------------------------ lab1: test byte ptr offs,1 jz short lab2 int 3 ;------------------------------------------------ lab2: mov al,device or al,40h mov dx,base_IO add dx,6 out dx,al inc dx lab3: in al,dx test al,80h jnz lab3 mov al,0 sub dx,6 out dx,al inc dx mov al,sect out dx,al mov al,0 inc dx out dx,al inc dx out dx,al inc dx out dx,al mov al,0C8h inc dx inc dx out dx,al mov si,offset base_DTP movzx ebx,segm shl ebx,4 movzx eax,offs add ebx,eax mov [si],ebx mov al,sect cmp al,80h jna short lab4 sub al,80h mov dword ptr [si+4],0 add ebx,10000h add si,8 mov [si],ebx lab4: shl ax,9 mov [si+4],ax mov ah,80h mov [si+6],ax mov al,6 mov dx,base_BM add dx,2 out dx,al xor eax,eax mov ax,cs add dx,2 shl eax,4 add eax,offset base_DTP out dx,eax mov al,9 sub dx,4 out dx,al add dx,2 lab5: in al,dx test al,4 jz lab5 test al,2 jz short lab6 int 3 ;------------------------------------------------ lab6: ;;; out dx,al mov al,8 sub dx,2 out dx,al mov dx,base_IO add dx,7 lab7: in al,dx test al,1 jz short good int 3 ;------------------------------------------------ good: nop ;;; ////////////////// ;;; ////////////////// ;;; ////////////////// nop int 3 ;------------------------------------------------ codesg ends end start Результат один - BMInt всегда = 0, и когда объем трансфера в PRDT превышает таковой у IDE-команды, и когда они равны. Данные при этом передаются. Может ли это быть особенностью данного конкретного контроллера? Или BMInt вообще на SATA не устанавливается после окончания передачи? Будет ли корректно отслеживать окончание трансфера по BMActive=0 при отключенных прерываниях? И если на диске есть сбойный сектор, где возникнет ошибка - при посылке команды 0C8h? И еще, может кто-нибудь посоветует какой-нибудь мануал поновее по этой теме? Programming Interface for Bus Master IDE Controller Revision 1.0 прочитал, судя по нему все делаю правильно.