; Arguments: ; ah Bus Number (0 .. 255) ; al Device Number (0 .. 31) ; ; Returns: ; - true/false (eax) pci_device_exists: push dword esi sub esp, 8 mov esi, esp mov [esi], edx mov [esi + 4], eax .make_address: xor eax, eax ; Enable Bit or al, 1 ; Make space for 8 Reserved Bits and 8 Bytes of bus number. shl eax, 15 ; Bus Number mov al, [esi + 5] ; Device Number ; Make space for device number shl eax, 5 mov dl, [esi + 4] and dl, 0x1f or al, dl shl eax, 11 .input_output: mov dx, PCI_CONFIG_ADDRESS_PORT out dx, eax mov dx, PCI_CONFIG_DATA_PORT in eax, dx cmp ax, 0xffff jne .device_found .not_a_device: mov edx, [esi] add esp, 8 pop dword esi xor eax, eax ret .device_found: mov edx, [esi] add esp, 8 pop dword esi mov eax, 1 ret ; Arguments: ; [FURTHEST FROM EBP] ; 3. U16 PCI Device Class & Subclass ; (Higher byte: Class, lower byte: Subclass) ; 2. U16 PCI Device Address ; (Higher byte: Bus Address, ; lower byte: Device Address) ; 1. Ptr32 Pointer to PCI driver area of 65536 bytes ; [NEAREST TO EBP] pci_append_device: push dword esi sub esp, 64 mov esi, esp mov [esi + (64 - 4)], eax mov [esi + (64 - 8)], ebx mov [esi + (64 - 12)], ecx mov [esi + (64 - 20)], edi .get_device_count: mov ebx, [ebp - 4] xor ecx, ecx mov cx, [ebx + PCI_DEVICE_COUNT_OFFSET] mov [esi + 4], cx .calculate_device_offset: ; Every device slot has 16 bytes, multiply index with 16 shl ecx, 4 ; Point into driver device area (add device area start on top) mov ebx, [ebp - 4] add ebx, PCI_DEVICE_AREA_OFFSET add ebx, ecx .set_device: mov cx, [ebp - 6] mov [ebx], cx mov cx, [ebp - 8] mov [ebx + 2], cx .increment_device_count: mov ebx, [ebp - 4] inc word [ebx + PCI_DEVICE_COUNT_OFFSET] .epilog: mov eax, [esi + (64 - 4)] mov ebx, [esi + (64 - 8)] mov ecx, [esi + (64 - 12)] mov edi, [esi + (64 - 20)] add esp, 64 pop dword esi ret ; Arguments: ; [FURTHER FROM EBP] ; 2. U16 Device Number ; 1. U16 Bus Number ; [NEAREST TO EBP] ; ; Returns: ; ax PCI Device Class & Subclass ; (Higher byte: Class, lower byte: Subclass) pci_get_device_class_at_address: push dword esi sub esp, 64 mov esi, esp mov [esi + (64 - 8)], ebx mov [esi + (64 - 12)], ecx mov [esi + (64 - 16)], edx mov [esi + (64 - 20)], edi .create_address: xor eax, eax ; Enable Bit or al, 1 ; Make space for 8 Reserved Bits and 8 Bytes of bus number. shl eax, 15 ; Bus Number mov al, [ebp - 2] ; Device Number ; Make space for device number shl eax, 5 mov dl, [ebp - 4] and dl, 0x1f or al, dl shl eax, 11 ; Include the register offset of the configuration space ; register which contains the class and subclass or eax, 8 .input_output: mov dx, PCI_CONFIG_ADDRESS_PORT out dx, eax mov dx, PCI_CONFIG_DATA_PORT in eax, dx ; Remove the parts of the register which aren't part of the ; PCI class- and subclass-code shr eax, 16 .epilog: mov ebx, [esi + (64 - 8)] mov ecx, [esi + (64 - 12)] mov edx, [esi + (64 - 16)] mov edi, [esi + (64 - 20)] add esp, 64 pop dword esi ret ; Arguments: ; [FURTHER FROM EBP] ; 2. U32 Bus Number (0 .. 255) ; 1. Ptr32 Pointer to PCI driver area of 65536 bytes ; [NEAREST TO EBP] ; ; Returns: ; - Number of devics on the bus (eax) pci_enumerate_bus: push dword esi sub esp, 64 mov esi, esp mov [esi + (64 - 8)], ebx mov [esi + (64 - 12)], ecx mov [esi + (64 - 16)], edx mov [esi + (64 - 20)], edi ; [esi]: Device-in-bus Index ; [esi + 4]: Number of existing devices ; [esi + 8]: Bus number ; [esi + 12]: PCI driver area pointer mov [esi], dword 0 mov [esi + 4], dword 0 mov eax, [ebp - 8] mov [esi + 8], eax mov eax, [ebp - 4] mov [esi + 12], eax .initialize_device_loop: .device_loop: cmp [esi], dword 32 jae .epilog .test_whether_device_exists: mov ah, [esi + 8] ; Bus Number mov al, [esi] ; Device Number mov [esi + 16], ax push ebp mov ebp, esp call pci_device_exists mov esp, ebp pop ebp cmp ax, 0 je .no_device .append_device: mov al, [esi + 8] mov ah, [esi] ; Device Number in DX xor dx, dx mov dl, ah xor ah, ah push ebp mov ebp, esp push ax push dx call pci_get_device_class_at_address mov esp, ebp pop ebp mov cx, ax mov ax, [esi + 16] push ebp mov ebp, esp push dword [esi + 12] push ax push cx call pci_append_device mov esp, ebp pop ebp mov ebx, [ebp - 4] .no_device: inc dword [esi] jmp .device_loop .epilog: mov ebx, [esi + (64 - 8)] mov ecx, [esi + (64 - 12)] mov edx, [esi + (64 - 16)] mov edi, [esi + (64 - 20)] mov eax, [esi + 4] add esp, 64 pop dword esi ret ; Arguments: ; [FURTHEST FROM EBP] ; 2. U32 Maximum number of devices to enumerate ; (0 to eliminate limit) ; 1. Ptr32 Pointer to PCI driver area of 65536 bytes ; [NEAREST TO EBP] ; Returns: ; eax: Number of devices read pci_enumerate: push dword esi sub esp, 64 mov esi, esp mov [esi + (64 - 4)], eax mov [esi + (64 - 8)], ebx mov [esi + (64 - 12)], ecx mov [esi + (64 - 16)], edx mov [esi + (64 - 20)], edi ; [esi]: Number of devices found ; ecx: Bus Index mov edx, [ebp - 4] mov [esi + 4], edx ; Set the device count to 0 explicitly, just for safety. mov ebx, [ebp - 4] add ebx, PCI_DEVICE_COUNT_OFFSET mov [ebx], word 0 .bus_loop: xor ecx, ecx mov [esi], dword 0 .bus_loop_body: ; Test whether the device count is unlimited, ; ignore the device count check if it is. cmp [ebp - 8], dword 0 je .call_bus_enumerator mov edx, [esi] cmp edx, [ebp - 8] jae .epilog .call_bus_enumerator: push ebp mov ebp, esp push dword [esi + 4] push ecx call pci_enumerate_bus mov esp, ebp pop ebp ; Add the number of devices found on the bus ; to the number of devices found in total. add [esi], eax mov ebx, [esi + 4] add [ebx + PCI_DEVICE_COUNT_OFFSET], ax ; Go to the next bus (if there is one) inc ecx cmp ecx, 256 jb .bus_loop_body .epilog: mov ebx, [esi + (64 - 8)] mov ecx, [esi + (64 - 12)] mov edx, [esi + (64 - 16)] mov edi, [esi + (64 - 20)] mov eax, [esi] add esp, 64 pop dword esi ret