如何通过 pci capability id 识别设备

How to identify the device by pci capability id

如何通过pci capability id来识别设备? 这是我的代码:

我尝试访问 34h 并检查第一个循环中是否存在功能 ID 如果存在,则指向下一个指针,但是在获取指针和放地址的步骤中似乎有些问题。

'''

    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

'''

编写此答案时假设此代码正在寻找 PCI Express 功能。

这段代码中有几个问题。

  1. first标签处,应该使用al而不是ah来确定第一个能力的偏移量。
  2. PCI Express 能力的能力 ID 是 10h,而不是 10。
  3. 读取每个功能 header 后,al 包含功能 ID,ah 包含下一个指针。所以 cmp ah, 10 应该是 cmp al, 10h .
  4. nextreg标签处,应该使用ah而不是al来确定下一个能力的偏移量。
  5. 在每次迭代中,它会将 bx 添加到 di 而不会删除之前的偏移量。
  6. 不清楚 edi 被初始化为什么,但如果它没有设置第 31 位,那么这段代码根本不会读取 PCI 配置 space。

这应该有效:

    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. 更好的方法是保留edi中的原始地址而不更改它,并为每个新偏移量使用lea eax, [edi+ebx]

  2. 没有必要用ecx作为循环计数器,逻辑有点绕。可以拉直一点,让流线更清晰。

我会这样写:

    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:

(我不知道 set_curregmem 是什么,所以我没有尝试编写那部分代码。)