; Arguments: ; [Furthest from EBP] ; 2. U16 Function (0 .. 7) ; 1. U16 Device Number (0 .. 31) ; 0. U16 Bus Number (0 .. 255) ; [Nearest to EBP] ; ; Returns: ; eax: If there is NO device at the location: 0 ; If there IS a device at the location: 1 pci_check_device_exists: .prolog: push esi sub esp, 32 mov [esi + 24], ebx mov [esi + 28], edx .gather_arguments: mov ax, [ebp - 2] mov [esi + 4], al mov ax, [ebp - 4] and al, 0x1f mov [esi + 5], al mov ax, [ebp - 6] and al, 0x07 mov [esi + 6], al ; Configuration Space Address (4 bytes): ; [Highest Bit] ; 5. Enable Bit (1) ; 4. Reserved (8) ; 3. Bus Number (8) ; 2. Device Number (4) ; 1. Function Number (3) ; 0. Register Offset (8) ; [Lowest Bit] .make_address: xor edx, edx ; Set the Enable Bit inc edx ; Make space for 8 Reserved Bits and 8 Bits for the Bus Number. shl edx, 15 ; Bus Number mov dl, [esi + 4] ; Device Number shl edx, 5 or dl, [esi + 5] ; Function Number shl edx, 3 or edx, [esi + 6] ; Make place for the register offset (which isn't used here). shl edx, 8 mov eax, edx mov dx, PCI_CONFIG_ADDRESS_PORT out dx, eax mov dx, PCI_CONFIG_DATA_PORT in eax, dx cmp ax, 0xffff je .no_device xor eax, eax inc eax jmp .epilog .no_device: xor eax, eax .epilog: mov ebx, [esi + 24] mov edx, [esi + 28] add esp, 32 pop esi 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 ; (Lower byte: Subclass, Higher byte: Class) 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 xchg ah, al .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. U16 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 ; CH: Bus Number ; CL: Device index within bus ; [esi + 4]: Number of existing devices ; [esi + 12]: PCI driver area pointer mov [esi], dword 0 mov [esi + 4], dword 0 .initialize_device_loop: mov ch, [ebp - 4] xor cl, cl .device_loop: cmp cl, 32 jae .epilog .test_whether_device_exists: mov ax, [ebp - 6] ; Bus Number mov dx, cx and dx, 0xff push ebp mov ebp, esp push ax ; Bus Number push dx ; Device Index push word 0 ; Function Number call pci_check_device_exists mov esp, ebp pop ebp cmp ax, 0 je .no_device .call_append_device: mov bx, cx and bx, 0xff mov ax, cx shr ax, 8 push ebp mov ebp, esp push ax ; Bus Number push bx ; Device Index call pci_get_device_class_at_address mov esp, ebp pop ebp mov edx, [ebp - 4] push ebp mov ebp, esp push edx ; Pointer to PCI Driver Area push cx ; Device Address push ax ; Class, Subclass call pci_append_device mov esp, ebp pop ebp mov ebx, [ebp - 4] .no_device: inc cl 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: .prolog: 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 .get_arguments: ; [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