Доброго времени суток!!! я написал небольшую функцию которая должна сканировать PCI устройства и сохранять их адреса и класс коды в буфер: Код (Text): ;_________________________________________________ FIND_DEVICES: ;[ds:edi] - buffer mov word [ds:edi], 0h xor esi, esi inc esi xor ecx, ecx ;preparing:[ds:edi]-counter, esi = 0(so, it doesnt overwrites counter), cx = 0 (ch = bus, cl = device & function) FD_LOOP: mov eax, ecx shl eax, 8d ;eax = address of device bts eax, 31d push eax call PCI_READ ;read pci config space with address in eax cmp ax, 0FFFFh ;if eax is not FFFFFFFFh jne NEXT_DEV ;save device address and class,else error pop eax ; mov al, cl shl al, 5h cmp al, 0h ;if function number =! 0, jnz INCREM ;increment device and xor function mov al, cl shr al, 3h cmp al, 0h jnz NBUS ;if device number == 0, then no more devices here jz RETURN_FD ;else next buss RT_PT_: jmp FD_LOOP RETURN_FD: ret ;[ds:edi] - filled buffer NBUS: xor cl, cl inc ch jmp RT_PT_ INCREM: and cl, 11111000b add cl, 8h jmp RT_PT_ NEXT_DEV: pop eax mov [ds:edi+(esi*4)], eax inc esi mov al, 8h call PCI_READ mov [ds:edi+(esi*4)], eax inc word [ds:edi] inc esi inc cx jmp RT_PT_ ;______________________________________ ;_________________________________________ PCI_READ: ;eax - address push dx mov dx, 0CF8h out dx, eax mov dx, 0CFCh in eax, dx pop dx ret ;eax - data ;_________________________________________ суть кода следующая : 1.Настроить регистры и обнулить счетчики 2.Собрать адрес устройства из данных в есх(ch-шина, cl - устройство и функция) 3.прочитать нулевой регистр устройства 4.если ID изготовителя =! FFFFh, то устройство присутствует и сохраняем его адрес и класс в буфер , увеличиваем счетчики, идем к пункту 2 5.если ID изготовителя == FFFFh, то устройства нет, тогда если номер функции не равен нулю, то обнуляем номер функции и увеличиваем номер устройства и идем к пункту 2, если номер функции == 0, и номер устройства =! 0, то увеличиваем номер шины и обнуляем номер устройства и функции и идем к пункту 2, но если номер устройства равен нулю то значит шина пуста и устройств больше нет - возврат. так вот, в результате я получаю пустой буфер где ошибка???
BOTOKILLER Возьми Borlan C++ версии 3 или 5. И виртуальную.реальную машину с досом. Скопируй свой код в ассемблерную вставку и и пройдись пошагово. Саветую Borlan C++ так как мне там отладчик больше всего нравится. Можно также в bochs отлаживать, но это не так удобно. Можно также взять turbo debuger.
Я в дебагере VirtualBox просмотрел, проблема одна - после чтения из PCI постоянно возвращается 0FFFFFFFFh....
я пробовал через 1Ah но получилось очень медленно(прям заметно медленно - минуты 2 только прерываниями занималось)
Попробуй сделать так: через int 1Ah получи количество шин, а потом делай детект вручную, но только в пределах этих шин.
Phantom_84 Ему это не поможет. Он в циклах делает ошибки. BOTOKILLER Постоянно FFFFFFh у тебя возвращаться не может. Потому что у тебя программа только один раз читает из регистра. А дальше выходит на ret. Не раз не зациклившись- т.е всего один проход по году, без циклов.
Весь пункт неправильный. сли ID изготовителя == FFFFh, то устройства нет. Это верно а вот остальное нет. Более того я тебе скажу что Device Number соответствует слоту этого устройства. Поэтому 0 вполне может отсутствовать. По поводу Bus=0 то это особый случай с которым я не до конца разобрался.
BOTOKILLER Вот правильный алгоритм поиска PCI девайсов: Код (Text): const PCI_CONFADR = $0CF8; PCI_CONFDATA = $0CFC; type PPCIDevIf = ^TPCIDevIf; TPCIDevIf = packed record VendorID: Word; // 1106 = VIA ; 8086 = Intel ; 10DE = nVidia DeviceID: Word; // 02 Command: Word; // 04 Status: Word; // 06 RevisionID: Byte; // 08 ProgIf: Byte; // 09 // Programming Interface SCC: Byte; // 0A // Sub Class Code BCC: Byte; // 0B // Base Class Code CLS: Byte; // 0C // cache line size LT: Byte; // 0D // latency timer HeaderType: Byte; // 0E // Header Type BIST: Byte; // 0F // Built In Self Test end; PPCIDevIfEx = ^TPCIDevIfEx; TPCIDevIfEx = packed record case Byte of 1: (Named: TPCIDevIf); 2: (Arr8: array [0..$0F] of Byte); 3: (Arr32: array [0..3] of DWORD); end; function ReadPciCnfD(Addr: DWORD): DWORD; var a: DWORD; begin a := PortInD(PCI_CONFADR); // get current state PortOutD(PCI_CONFADR, Addr); // read vendorID and deviceID Result := PortInD(PCI_CONFDATA); // get requested DWORD of config data PortOutD(PCI_CONFADR, a); // restore configuration control end; function EnumPCIDevices(var pci: TPCIDevIfArr): Integer; var bus, dev, func, bcount, fcount, id: DWORD; vendor: Word; Addr, a, c, i, n: DWORD; tmp: TPCIDevIfEx; bsp: DWORD; begin Result := 0; bus := 0; dev := 0; func := 0; SetLength(pci, 16); // alloc mem for 16 devices n := 0; // device counter bcount := 1; while (bus < bcount) do begin // Begin enumeration at first bus for dev:=0 to 31 do begin // scan up to 32 devices func := 0; fcount := 1; // initially we assume there is only one function while (func < fcount) do begin Addr := $80000000 or ((bus and $FF) shl 16) or ((dev and $1F) shl 11) or ((func and $07) shl 8); a := ReadPciCnfD(Addr); // read the vendorID and deviceID vendor := Word(a); if (vendor <> $FFFF) and (vendor <> 0) then begin tmp.Arr32[0] := a; for i:=1 to High(tmp.Arr32) do begin // read next DWORD of PCICnf tmp.Arr32[i] := ReadPciCnfD(Addr + i*4); end; bsp := PDWORD(@tmp.Named.ProgIf)^ and $00FFFFFF; if tmp.Named.HeaderType and $80 <> 0 then fcount := 8; // check multifunction if bsp = $060100 then fcount := 8; // Found a bridge! -> check multifunction if (tmp.Named.HeaderType and $7F = 1) or ((tmp.Named.BCC = $06) and (tmp.Named.SCC = $04)) then begin // Found a bridge! Inc(bcount); end; if n >= Length(pci) then SetLength(pci, Length(pci)+16); // оказывается тут больше 16 девайсов // добавляем новый девайс в массив pci[n].PCIAddr := Addr; pci[n].PCIHead := tmp; Inc(n); end; Inc(func); end; end; Inc(bus); end; SetLength(pci, n); // устанавливаем реальное кол-во девайсов Result := n; end; Есть тоже самое и на Сях ...
Код не учитывает multifunction устройства и делает ненужные доступы к PCI из-за этого. Но я не считаю нужным об этом заботится так как на современных компах многие устройства как-раз таки multifunction. Код (Text): movzx ebp, byte [HIGHEST_PCI_BUS_NUMBER] ; highest bus # found using bios 1ah shl ebp, 16 mov edi, $80000000-256 ; edi = starting pci bus/device/function or ebp, $8000ff00 ; ebp = max pci bus/device/function .nextDevice: add edi, 256 mov edx, $cf8 mov eax, edi cmp ebp, edi jb .exit out dx, eax add edx, 4 in eax, dx cmp ax, $ffff jz .nextDevice ; eax = device/vendor ; edi = bus/device/function ; read classcode mov edx, $cf8 lea eax, [rdi+8] ; offset for classcode & revision out dx, eax add edx, 4 in eax, dx jmp .nextDevice .exit: