'How to identify the device by pci capability id

How to identify the device by pci capability id? this is my code:

I try to access 34h and check if the capability id exists on the first loop If it exists, it points to the next pointer, But there seems to be some problems in the steps of getting the pointer and putting the address.

'''

    push eax
    push edi
    push esi

    mov cx,100
    
    ;mov edi,[esi]      
    add edi,52     ;access 34h
    
lopreg:     
    mov eax,edi    ;read
    mov dx,0cf8h
    out dx,eax
    mov dx,0cfch
    in eax,dx
   
    cmp cx,100    ;first time 
    je first
    
    cmp ah,10
    jne nextreg
    jmp ispcie
    
first:
    cmp ah,0
    je  ending
    sub edi,52
    movzx bx,ah
    add di,bx

    loop lopreg
    jmp ending
    
ispcie:
    call set_cur        
    mov ah,09h
    lea dx,regmem        ;print pcie
    int 21h
    jmp ending
    
nextreg:
    cmp al,0
    je ending
    movzx bx,al ;
    add di,bx
    loop lopreg
ending: 
    pop esi
    pop edi
    pop eax
    ret

'''



Solution 1:[1]

This answer is written with the assumption that this code is looking for the PCI Express Capability.

There are several problems in this code.

  1. At the first label, it should use al instead of ah to determine the offset of the first capability.
  2. The Capability ID of the PCI Express capability is 10h, not 10.
  3. After reading each capability header, al contains the capability id and ah contains the next pointer. So cmp ah, 10 should be cmp al, 10h .
  4. At the nextreg label, it should use ah instead of al to determine the offset of the next capability.
  5. On each iteration, it adds bx to di without removing the previous offset.
  6. It's not clear what edi is initialized to, but if it does not have bit 31 set, then this code won't be reading PCI config space at all.

This should work:

    mov cx,100
    
    ;mov edi,[esi]      
    add edi,52     ;access 34h
    
lopreg:     
    mov eax,edi    ;read
    mov dx,0cf8h
    out dx,eax
    mov dx,0cfch
    in eax,dx
   
    cmp cx,100    ;first time 
    je first
    
    cmp al,10h
    jne nextreg
    jmp ispcie
    
first:
    cmp al,0
    je  ending
    sub edi,52
    movzx bx,al
    add di,bx

    loop lopreg
    jmp ending
    
ispcie:
    call set_cur        
    mov ah,09h
    lea dx,regmem        ;print pcie
    int 21h
    jmp ending
    
nextreg:
    cmp ah,0
    je ending
    sub di, bx
    movzx bx,ah
    add di,bx
    loop lopreg

ending:
  1. A better approach is to keep the original address in edi without changing it, and use lea eax, [edi+ebx] for each new offset.

  2. There's no need to use ecx as a loop counter and the logic is a bit convoluted. It can be straightened out a bit to flow more clearly.

Here's how I would write it:

    lea eax,[edi+34h]     
    mov dx,0cf8h
    out dx,eax
    mov dx,0cfch
    in al,dx              ; read offset of first capability
    cmp al,0
    je ending
    movzx ebx,al

lopreg:     
    lea eax,[edi+ebx]     ; offset of next capability is in ebx
    mov dx,0cf8h
    out dx,eax
    mov dx,0cfch
    in eax,dx             ; read capability header

    cmp al,10h            ; check if it is the PCI Express capability
    je ispcie

nextreg:
    cmp ah,0              ; check if it is the end of the capability list
    je ending
    movzx ebx, ah         ; set up ebx with the offset of the next capability
    jmp lopreg

ispcie:
    ; base of device PCI config space is in edi
    ; offset of PCI Express Capability is in ebx
    ...

ending:

(I don't know what set_cur and regmem are so I didn't attempt to write that part of the code.)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 prl