biospcipci-e

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

  • 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.)