Обнаружение устройств PCI

Тема в разделе "WASM.OS.DEVEL", создана пользователем BOTOKILLER, 3 авг 2011.

  1. BOTOKILLER

    BOTOKILLER New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2011
    Сообщения:
    10
    Доброго времени суток!!!
    я написал небольшую функцию которая должна сканировать PCI устройства и сохранять их адреса и класс коды в буфер:
    Код (Text):
    1.        
    2.  ;_________________________________________________
    3.         FIND_DEVICES:   ;[ds:edi] - buffer
    4.         mov word [ds:edi], 0h
    5.         xor esi, esi
    6.         inc esi
    7.         xor ecx, ecx                       ;preparing:[ds:edi]-counter, esi = 0(so, it doesnt overwrites counter), cx = 0 (ch = bus, cl = device & function)
    8.  
    9.  
    10.         FD_LOOP:
    11.         mov eax, ecx
    12.         shl eax, 8d                        ;eax = address of device
    13.         bts eax, 31d
    14.         push eax
    15.         call PCI_READ                      ;read pci config space with address in eax
    16.         cmp ax,  0FFFFh                    ;if eax is not FFFFFFFFh
    17.         jne NEXT_DEV                       ;save device address and class,else error
    18.         pop eax                            ;
    19.         mov al, cl
    20.         shl al, 5h
    21.         cmp al, 0h                         ;if function number =! 0,
    22.         jnz INCREM                         ;increment device and xor function
    23.         mov al, cl
    24.         shr al, 3h
    25.         cmp al, 0h
    26.         jnz NBUS                           ;if device number == 0, then no more devices here
    27.         jz RETURN_FD                       ;else next buss
    28.         RT_PT_:
    29.         jmp FD_LOOP
    30.  
    31.         RETURN_FD:
    32.         ret            ;[ds:edi] - filled buffer
    33.  
    34.         NBUS:
    35.         xor cl, cl
    36.         inc ch
    37.         jmp RT_PT_
    38.  
    39.         INCREM:
    40.         and cl, 11111000b
    41.         add cl, 8h
    42.         jmp RT_PT_
    43.  
    44.         NEXT_DEV:
    45.         pop eax
    46.         mov [ds:edi+(esi*4)], eax
    47.         inc esi
    48.         mov al, 8h
    49.         call PCI_READ
    50.         mov [ds:edi+(esi*4)], eax
    51.         inc word [ds:edi]
    52.         inc esi
    53.         inc cx
    54.         jmp RT_PT_
    55.         ;______________________________________
    56.  
    57.  
    58.  
    59.  
    60.  
    61.         ;_________________________________________
    62.         PCI_READ:     ;eax - address
    63.         push dx
    64.         mov dx, 0CF8h
    65.         out dx, eax
    66.         mov dx, 0CFCh
    67.         in eax, dx
    68.         pop dx
    69.         ret           ;eax - data
    70.         ;_________________________________________
    суть кода следующая :
    1.Настроить регистры и обнулить счетчики
    2.Собрать адрес устройства из данных в есх(ch-шина, cl - устройство и функция)
    3.прочитать нулевой регистр устройства
    4.если ID изготовителя =! FFFFh, то устройство присутствует и сохраняем его адрес и класс в буфер , увеличиваем счетчики, идем к пункту 2
    5.если ID изготовителя == FFFFh, то устройства нет, тогда если номер функции не равен нулю, то обнуляем номер функции и увеличиваем номер устройства и идем к пункту 2, если номер функции == 0, и номер устройства =! 0, то увеличиваем номер шины и обнуляем номер устройства и функции и идем к пункту 2, но если номер устройства равен нулю то значит шина пуста и устройств больше нет - возврат.
    так вот, в результате я получаю пустой буфер
    где ошибка??? :dntknw:
     
  2. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    BOTOKILLER
    Возьми Borlan C++ версии 3 или 5. И виртуальную.реальную машину с досом. Скопируй свой код в ассемблерную вставку и и пройдись пошагово.
    Саветую Borlan C++ так как мне там отладчик больше всего нравится.
    Можно также в bochs отлаживать, но это не так удобно.
    Можно также взять turbo debuger.
     
  3. BOTOKILLER

    BOTOKILLER New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2011
    Сообщения:
    10
    Я в дебагере VirtualBox просмотрел, проблема одна - после чтения из PCI постоянно возвращается 0FFFFFFFFh....
     
  4. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Я все через прерывания делаю, и нормально нахожу нужные мне устройства :)
     
  5. BOTOKILLER

    BOTOKILLER New Member

    Публикаций:
    0
    Регистрация:
    22 июл 2011
    Сообщения:
    10
    я пробовал через 1Ah но получилось очень медленно(прям заметно медленно - минуты 2 только прерываниями занималось) :)
     
  6. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Попробуй сделать так: через int 1Ah получи количество шин, а потом делай детект вручную, но только в пределах этих шин.
     
  7. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Phantom_84
    Ему это не поможет. Он в циклах делает ошибки.

    BOTOKILLER
    Постоянно FFFFFFh у тебя возвращаться не может. Потому что у тебя программа только один раз читает из регистра. А дальше выходит на ret. Не раз не зациклившись- т.е всего один проход по году, без циклов.
     
  8. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    А на VMWare не пустой буфер. Виртуалбокс у меня на ubuntu пока не завелся, не проверял.
     
  9. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Весь пункт неправильный.
    сли ID изготовителя == FFFFh, то устройства нет. Это верно а вот остальное нет. Более того я тебе скажу что Device Number соответствует слоту этого устройства. Поэтому 0 вполне может отсутствовать.

    По поводу Bus=0 то это особый случай с которым я не до конца разобрался.
     
  10. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    BOTOKILLER
    Вот правильный алгоритм поиска PCI девайсов:

    Код (Text):
    1. const
    2.   PCI_CONFADR     = $0CF8;
    3.   PCI_CONFDATA    = $0CFC;
    4.  
    5. type
    6.   PPCIDevIf = ^TPCIDevIf;
    7.   TPCIDevIf = packed record
    8.     VendorID: Word;                 // 1106 = VIA ; 8086 = Intel ; 10DE = nVidia
    9.     DeviceID: Word;       // 02
    10.     Command: Word;        // 04
    11.     Status: Word;         // 06
    12.     RevisionID: Byte;     // 08
    13.     ProgIf: Byte;         // 09     // Programming Interface
    14.     SCC: Byte;            // 0A     // Sub Class Code
    15.     BCC: Byte;            // 0B     // Base Class Code
    16.     CLS: Byte;            // 0C     // cache line size
    17.     LT: Byte;             // 0D     // latency timer
    18.     HeaderType: Byte;     // 0E     // Header Type
    19.     BIST: Byte;           // 0F     // Built In Self Test
    20.   end;
    21.  
    22.   PPCIDevIfEx = ^TPCIDevIfEx;
    23.   TPCIDevIfEx = packed record
    24.     case Byte of
    25.       1: (Named: TPCIDevIf);
    26.       2: (Arr8:  array [0..$0F] of Byte);
    27.       3: (Arr32: array [0..3] of DWORD);
    28.   end;
    29.  
    30. function ReadPciCnfD(Addr: DWORD): DWORD;
    31. var
    32.   a: DWORD;
    33. begin
    34.   a := PortInD(PCI_CONFADR);       // get current state
    35.   PortOutD(PCI_CONFADR, Addr);     // read vendorID and deviceID
    36.   Result := PortInD(PCI_CONFDATA); // get requested DWORD of config data
    37.   PortOutD(PCI_CONFADR, a);        // restore configuration control
    38. end;
    39.  
    40. function EnumPCIDevices(var pci: TPCIDevIfArr): Integer;
    41. var
    42.   bus, dev, func, bcount, fcount, id: DWORD;
    43.   vendor: Word;
    44.   Addr, a, c, i, n: DWORD;
    45.   tmp: TPCIDevIfEx;
    46.   bsp: DWORD;
    47. begin
    48.   Result := 0;
    49.   bus := 0;
    50.   dev := 0;
    51.   func := 0;
    52.   SetLength(pci, 16);    // alloc mem for 16 devices
    53.   n := 0;                    // device counter
    54.   bcount := 1;
    55.   while (bus < bcount) do begin     // Begin enumeration at first bus
    56.     for dev:=0 to 31 do begin       // scan up to 32 devices
    57.       func := 0;
    58.       fcount := 1;                  // initially we assume there is only one function
    59.       while (func < fcount) do begin
    60.         Addr := $80000000 or ((bus and $FF) shl 16) or ((dev and $1F) shl 11) or ((func and $07) shl 8);
    61.         a := ReadPciCnfD(Addr);     // read the vendorID and deviceID
    62.         vendor := Word(a);
    63.         if (vendor <> $FFFF) and (vendor <> 0) then begin
    64.           tmp.Arr32[0] := a;
    65.           for i:=1 to High(tmp.Arr32) do begin    // read next DWORD of PCICnf
    66.             tmp.Arr32[i] := ReadPciCnfD(Addr + i*4);
    67.           end;
    68.           bsp := PDWORD(@tmp.Named.ProgIf)^ and $00FFFFFF;
    69.           if tmp.Named.HeaderType and $80 <> 0 then fcount := 8;   // check multifunction
    70.           if bsp = $060100 then fcount := 8;   // Found a bridge!  -> check multifunction
    71.           if (tmp.Named.HeaderType and $7F = 1) or ((tmp.Named.BCC = $06) and (tmp.Named.SCC = $04)) then begin   // Found a bridge!
    72.             Inc(bcount);
    73.           end;
    74.  
    75.           if n >= Length(pci) then SetLength(pci, Length(pci)+16);    // оказывается тут больше 16 девайсов
    76.           // добавляем новый девайс в массив
    77.           pci[n].PCIAddr := Addr;        
    78.           pci[n].PCIHead := tmp;
    79.           Inc(n);
    80.         end;
    81.         Inc(func);
    82.       end;
    83.     end;
    84.     Inc(bus);
    85.   end;
    86.   SetLength(pci, n);    // устанавливаем реальное кол-во девайсов
    87.   Result := n;
    88. end;
    Есть тоже самое и на Сях ...
     
  11. MisHel64

    MisHel64 Member

    Публикаций:
    0
    Регистрация:
    9 мар 2011
    Сообщения:
    182
    Ну не знаю. Все очень быстро работает. На глаз не видно ни каких задержек. Ищи ошибки в своем коде.
     
  12. asmdev

    asmdev New Member

    Публикаций:
    0
    Регистрация:
    11 июл 2006
    Сообщения:
    12
    Код не учитывает multifunction устройства и делает ненужные доступы к PCI из-за этого. Но я не считаю нужным об этом заботится так как на современных компах многие устройства как-раз таки multifunction.

    Код (Text):
    1.   movzx ebp, byte [HIGHEST_PCI_BUS_NUMBER]   ; highest bus # found using bios 1ah
    2.   shl   ebp, 16
    3.   mov   edi, $80000000-256                   ; edi = starting pci bus/device/function
    4.   or    ebp, $8000ff00                       ; ebp = max pci bus/device/function
    5. .nextDevice:
    6.   add   edi, 256
    7.   mov   edx, $cf8
    8.   mov   eax, edi
    9.   cmp   ebp, edi
    10.   jb    .exit
    11.   out   dx, eax
    12.   add   edx, 4
    13.   in    eax, dx
    14.   cmp   ax, $ffff
    15.   jz    .nextDevice
    16.  
    17.   ; eax = device/vendor
    18.   ; edi = bus/device/function
    19.  
    20.   ; read classcode
    21.   mov   edx, $cf8
    22.   lea   eax, [rdi+8]             ; offset for classcode & revision
    23.   out   dx, eax
    24.   add   edx, 4
    25.   in    eax, dx
    26.  
    27.   jmp   .nextDevice
    28.  
    29. .exit: