IDE Bus master, не приходит прерывание

Тема в разделе "WASM.OS.DEVEL", создана пользователем Vic3Dexe, 18 июн 2011.

  1. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    Суть: читаю группу секторов путем 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, а что потом? Просто подавать следующую команду винту? ВМ будет нас "ждать"?

    зы Да, в данной ситуации сектора реально считываются, т.е. передача таки происходит.
     
  2. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    Переделал. Теперь, если винт не умеет LBA48, я с него читаю кусками по 128к и не больше. Все работает.
    Если винт умеет LBA48, я пытаюсь читать по 65536 секторов (32М), но и тут какие-то чудеса. Опять не приходит прерывание.
    Опытным путем выяснил, что затык (у qemu, vmware делает вид, что не умеет LBA48) начинается при пересечении PRDT границы в 4к (реальный режим у меня). Т.е., на "страницу" помещается 512 PRD, если каждая описывает 4к передачи, то имеем затык после 4096 секторов (4097 не пролазят). Если каждая описывает 8к, то затык, соотв., на 8192 и т.д.

    Собсна, это почему так? В спецификации четко сказано - таблица не более 64к, не пересекает 64к. У меня она лежит по 80000h. Имхо, ровнее некуда.
     
  3. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    active/int = 1/1 означает, что для команды слишком много данных. Я вообще не понял, как ты собирался прочитать больше 256 секторов в режиме DMA/LBA28. Я надеюсь, для DMA/LBA48 ты используешь команду 25h, а не 0C8h. Попробуй все буферы (и таблицу и конечные буферы) разместить выше границы 16 мег.
     
  4. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    Эээ... разве? Для случая 1/1
    Т.е. PRD еще есть, а винт трансфер закончил. Именно так и собирался - например, таблица описывает 256к передачи, следовательно, необходимо 2 команды винту в рамках этой таблицы. Но так или наче 1/1 я не дождался, как и прерывания.

    LBA48 - да, 25h.

    Выше 16 метров попробую, хотя не уверен, что это что-то даст. Хм... кстати не помешает просто потаскать PRDT по оперативе.
     
  5. shm

    shm New Member

    Публикаций:
    0
    Регистрация:
    18 сен 2010
    Сообщения:
    93
    Vic3Dexe, если не секрет прикрепи пожалуйста кусок кода где 48битовую команду в регистры записываешь (особенно, что касаемо LBA и счетчика секторов), имею подозрение, что ошибка именно там. Если диск поддерживает LBA48 я читаю по мегабайту (по 32 я подумал, что многовато), при этом никакой разницы при работе BM относительно LBA28 не увидел. И еще ключевой вопрос: при использовании DMA READ48 (именно 48, а не 28) при чтении блоками до 257 секторов все нормально работает? Просто, насколько я понял, в первом сообщении речь шла о DMA READ28. Но все же отмечу, что если с 28битовыми командами нормально прерывания приходят, то крайне маловероятно, что причина в BM. У меня подобная ситуация на PIIX происходила, все точно тоже самое практически, а оказалось, что 48битовые команды неправильно передаю.
     
  6. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    Код (Text):
    1.                         mov             eax,65536
    2.                         cmp             dword [IDEInfo.LBACount],eax  ;
    3.                         cmovb           eax,dword [IDEInfo.LBACount] ;<---- вот это вот остатки, оно тут уже не надо
    4.                         sub             dword [IDEInfo.LBACount],eax   ;
    5.                         mov             ebx,eax
    6.                         mov             dx,IDE_SECT_COUNT_REG
    7.                         xchg            al,ah                                   ;count 15:8
    8.                         call            IDEWritePort
    9.                         xchg            al,ah                                   ;count 7:0
    10.                         out             dx,al
    11.  
    12.                         mov             eax,dword [IDEInfo.LBAStart+4]
    13.                         mov             dx,IDE_LBA_1
    14.                         call            IDEWritePort                            ;LBA 39:32
    15.                         mov             al,ah
    16.                         mov             dx,IDE_LBA_2
    17.                         call            IDEWritePort                            ;LBA 47:40
    18.                         mov             eax,dword [IDEInfo.LBAStart]
    19.                         rol             eax,8
    20.                         mov             dx,IDE_LBA_0
    21.                         call            IDEWritePort                            ;LBA 31:24
    22.                         shr             eax,8
    23.                         out             dx,al                                   ;LBA 7:0
    24.                         shr             eax,8
    25.                         mov             dx,IDE_LBA_1
    26.                         call            IDEWritePort                            ;LBA 15:8
    27.                         mov             al,ah
    28.                         mov             dx,IDE_LBA_2
    29.                         call            IDEWritePort                            ;LBA 23:16
    30.                         mov             dx,IDE_CMD_REG
    31.                         mov             ax,25h
    32.                         call            IDEWritePort
    Я без проблем читаю то число секторов, которое описывается PRDT в рамках 4к памяти, т.е. 512 PRD. Если PRD больше, то наступает облом. При этом от собственно объема передачи ничего не зависит - я читал и 4096 и 32768 секторов (соотв. каждая PRD описывала либо 4к либо 32к передачи).
    В первом сообщении была проблема другого харакетра, я, видимо, толком это не объяснил, сорри. Просто голова уже пухнет.
    При LBA28 у меня не получалось включить BM передачу больше, чем передача винта. Т.е. BM прошу прочитать 512 секторов, винт столько не может за раз - я пытался дать 2 команды READ_DMA (C8), но уже после первой не было прерывания.
    Я забил и сделал кусками по 256 секторов (128к и у ВМ и у винта).
    А мне вот кажется, что грабли у qemu...
    Код (Text):
    1. static int dma_buf_prepare(BMDMAState *bm, int is_write)
    2. ......
    3. for(;;) {
    4.         if (bm->cur_prd_len == 0) {
    5.             /* end of table (with a fail safe of one page) */
    6.             if (bm->cur_prd_last ||
    7.                 (bm->cur_addr - bm->addr) >= 4096)          <======= <censored>!!!! Что за <censored>????
    8.                 return s->io_buffer_size != 0;
    9.             cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
    10.             bm->cur_addr += 8;
    11.             prd.addr = le32_to_cpu(prd.addr);
    12.             prd.size = le32_to_cpu(prd.size);
    13.             len = prd.size & 0xfffe;
    14.             if (len == 0)
    15.                 len = 0x10000;
    16.             bm->cur_prd_len = len;
    17.             bm->cur_prd_addr = prd.addr;
    18.             bm->cur_prd_last = (prd.size & 0x80000000);
    19.         }
     
  7. shm

    shm New Member

    Публикаций:
    0
    Регистрация:
    18 сен 2010
    Сообщения:
    93
    Vic3Dexe, посмотрел код - вроде все правильно, я примерно также делаю. Единственное, что смутило:
    У тебя получается IDEWritePort в DX возвращает уже физ. адрес порта?
    Я честно говоря даже не знаю, возможно ли это. Откуда идея? И также думаю, что заметного прироста скорости чтения это не добавит (если именно в этом цель).
    При LBA28 у меня аналогично.
    Вполне может быть, я никогда qemu не пользовался. Я предлагаю тебе скинуть ссыль на свою версию qemu, я попробую на ней мой драйвер потестить, у меня при LBA48 читается по мегабайту и один PRD описывает 64К (ну на границах может быть ессно меньше). Только не обещаю, что сегодня, т.к. в частности надо еще с ним разобраться. А на реальном то железе пробовал тестировать?
    Чего-то я не пойму. Ну к примеру, если один PRD будет описывать 64К, то можно с помощью 512 PRD аж целых 32М описать, или я чего-то недопонимаю? Хотя я тоже не припомню никакого ограничения в 4Кб на PRDT.
     
  8. shm

    shm New Member

    Публикаций:
    0
    Регистрация:
    18 сен 2010
    Сообщения:
    93
    Вот только ограничение.
     
  9. Vic3Dexe

    Vic3Dexe New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2009
    Сообщения:
    53
    Да, он 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-шникам по поводу их самодеятельности, ждем ответа.
     
  10. shm

    shm New Member

    Публикаций:
    0
    Регистрация:
    18 сен 2010
    Сообщения:
    93
    Вообще-то не ессно, они вполне могут работать в режиме эмуляции IDE (пока еще вроде она не выпилена окончательно), только порты берутся из конфигурационного пространства контроллера IDE, подробнее - http://ru.osdev.wikia.com/wiki/HDD, правда в этой статье не оговорено пары незначительных отличий, а именно то, что у такого контроллера может не быть альтернативного регистра состояния и в обработчике прерывания надо обязательно сбрасывать соотв. бит прерывания канала IDE (статусный регистр IDE), иначе контроллер будет слать прерывания "до победного", независимо от состояния бита прерывания в блоке командных регистров ATA.
     
  11. shm

    shm New Member

    Публикаций:
    0
    Регистрация:
    18 сен 2010
    Сообщения:
    93
    Попробую, но скорее всего уже не сегодня.
     
  12. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Давно уже нужно было попробовать на реале. И SATA - это не причина. В эмуляторах может быть недоработка по причине того, что "4 кб по 4 кб" наиболее типичная ситуация - отсюда и получилось в начале 512х8 = 4096 секторов (2 мб).
     
  13. 1G0R

    1G0R New Member

    Публикаций:
    0
    Регистрация:
    14 дек 2011
    Сообщения:
    1
    Та же самая проблема только на реальном железе:
    Контроллер Intel 82801G, HDD - WD 80G.
    Тестировал на примере из книги Кулакова "Программирование на аппаратном уровне" (листинг 11_07) и на примере, найденном на этом форуме:
    Код (Text):
    1. codesg        segment
    2.                  assume  cs:codesg, ds:codesg
    3.  
    4.                 .486p
    5.  
    6.                 org     100h
    7.  
    8. start:
    9.                 jmp     short begin
    10. ;------------------------------------------------
    11. base_IO         dw      8438h           ; база ввода/вывода харда
    12. device          db      0A0h            ; это мастер
    13. base_BM         dw      8400h           ; база БусМастера
    14. ;------------------------------------------------
    15. sect            db      0FFh            ; кол-во секторов для трансфера
    16. segm            dw      5678h           ; сегмент ОЗУ для трансфера
    17. offs            dw      9ABCh           ; смещение в сегменте
    18. ;------------------------------------------------
    19.                 align   4
    20.  
    21. base_DTP        dd      ?               ; база дескрипторов всегда выравнена
    22.                 dw      ?
    23.                 dw      ?
    24.  
    25.                 dd      ?
    26.                 dw      ?
    27.                 dw      ?
    28. ;------------------------------------------------
    29.  
    30. begin:
    31.                 push    cs
    32.                 pop     ds                      ;       !!!!!
    33.  
    34.                 smsw    ax
    35.  
    36.                 test    al,1
    37.                 jz      short lab0
    38.  
    39.                 int     3
    40. ;------------------------------------------------
    41. lab0:
    42.                 cmp     sect,0
    43.                 jnz     short lab1
    44.  
    45.                 int     3
    46. ;------------------------------------------------
    47. lab1:
    48.                 test    byte ptr offs,1
    49.                 jz      short lab2
    50.  
    51.                 int     3
    52. ;------------------------------------------------
    53. lab2:
    54.                 mov     al,device
    55.                 or      al,40h
    56.                 mov     dx,base_IO
    57.                 add     dx,6
    58.                 out     dx,al
    59.  
    60.                 inc     dx
    61. lab3:
    62.                 in      al,dx
    63.  
    64.                 test    al,80h
    65.                 jnz     lab3
    66.  
    67.                 mov     al,0
    68.                 sub     dx,6
    69.                 out     dx,al
    70.  
    71.                 inc     dx
    72.                 mov     al,sect
    73.                 out     dx,al
    74.  
    75.                 mov     al,0
    76.                 inc     dx
    77.                 out     dx,al
    78.  
    79.                 inc     dx
    80.                 out     dx,al
    81.  
    82.                 inc     dx
    83.                 out     dx,al
    84.  
    85.                 mov     al,0C8h
    86.                 inc     dx
    87.                 inc     dx
    88.                 out     dx,al
    89.  
    90.                 mov     si,offset base_DTP
    91.  
    92.                 movzx   ebx,segm
    93.                 shl     ebx,4
    94.                 movzx   eax,offs
    95.                 add     ebx,eax
    96.                 mov     [si],ebx
    97.  
    98.                 mov     al,sect
    99.  
    100.                 cmp     al,80h
    101.                 jna     short lab4
    102.  
    103.                 sub     al,80h
    104.                 mov     dword ptr [si+4],0
    105.                 add     ebx,10000h
    106.                 add     si,8
    107.                 mov     [si],ebx
    108. lab4:
    109.                 shl     ax,9
    110.                 mov     [si+4],ax
    111.                 mov     ah,80h
    112.                 mov     [si+6],ax
    113.  
    114.                 mov     al,6
    115.                 mov     dx,base_BM
    116.                 add     dx,2
    117.                 out     dx,al
    118.  
    119.                 xor     eax,eax
    120.                 mov     ax,cs
    121.                 add     dx,2
    122.                 shl     eax,4
    123.                 add     eax,offset base_DTP
    124.                 out     dx,eax
    125.  
    126.                 mov     al,9
    127.                 sub     dx,4
    128.                 out     dx,al
    129.  
    130.                 add     dx,2
    131. lab5:
    132.                 in      al,dx
    133.  
    134.                 test    al,4
    135.                 jz      lab5
    136.  
    137.                 test    al,2
    138.                 jz      short lab6
    139.  
    140.                 int     3
    141. ;------------------------------------------------
    142. lab6:
    143. ;;;             out     dx,al
    144.  
    145.                 mov     al,8
    146.                 sub     dx,2
    147.                 out     dx,al
    148.  
    149.                 mov     dx,base_IO
    150.                 add     dx,7
    151. lab7:
    152.                 in      al,dx
    153.  
    154.                 test    al,1
    155.                 jz      short good
    156.  
    157.                 int     3
    158. ;------------------------------------------------
    159. good:
    160.                 nop
    161.  
    162. ;;;             //////////////////
    163. ;;;             //////////////////
    164. ;;;             //////////////////
    165.  
    166.                 nop
    167.  
    168.                 int     3
    169. ;------------------------------------------------
    170.  
    171. codesg          ends
    172.  
    173.                 end     start
    Результат один - BMInt всегда = 0, и когда объем трансфера в PRDT превышает таковой у IDE-команды, и когда они равны.
    Данные при этом передаются.
    Может ли это быть особенностью данного конкретного контроллера? Или BMInt вообще на SATA не устанавливается после окончания передачи? Будет ли корректно отслеживать окончание трансфера по BMActive=0 при отключенных прерываниях? И если на диске есть сбойный сектор, где возникнет ошибка - при посылке команды 0C8h?


    И еще, может кто-нибудь посоветует какой-нибудь мануал поновее по этой теме?
    Programming Interface for Bus Master IDE Controller Revision 1.0 прочитал, судя по нему все делаю правильно.