diff --git a/i386/loader/src-asm/drivers/pci/driver.asm b/i386/loader/src-asm/drivers/pci/driver.asm new file mode 100755 index 0000000..3be6296 --- /dev/null +++ b/i386/loader/src-asm/drivers/pci/driver.asm @@ -0,0 +1,64 @@ + +PCI_CONFIG_ADDRESS_PORT equ 0x0cf8 +PCI_CONFIG_DATA_PORT equ 0x0cfc + +PCI_DEVICE_COUNT_OFFSET equ 0xffe +PCI_DEVICE_AREA_OFFSET equ 0x1000 + +; [FURTHEST FROM BP] +; 0. Ptr32 Pointer to 65536B slot for PCI driver +; [NEAREST TO BP] +initialize_pci_driver: + 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 + +.body: + mov ebx, [ebp - 4] + push ebp + mov ebp, esp + push ebx + push dword 0 ; No Maximum Device Limit + call pci_enumerate + mov esp, ebp + pop ebp + + mov ebx, [ebp - 4] + add ebx, PCI_DEVICE_COUNT_OFFSET + + push ebp + mov ebp, esp + push ebx + push dword 2 + push dword 0 + push dword 0 + call write_hexadecimal_string + mov esp, ebp + pop ebp + + ; todo(wip): Remove this once the PCI Driver + ; is debugged completely. + + cli + hlt + +.epilog: + mov eax, [esi + (64 - 4)] + 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 +.storage: + dd 0 + +%include "drivers/pci/enumerate.asm" diff --git a/i386/loader/src-asm/drivers/pci/enumerate.asm b/i386/loader/src-asm/drivers/pci/enumerate.asm new file mode 100755 index 0000000..6a17bf9 --- /dev/null +++ b/i386/loader/src-asm/drivers/pci/enumerate.asm @@ -0,0 +1,250 @@ + +; 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 + shl eax, 5 ; Make space for device number + mov dl, [esi + 4] + and dl, 0x1f + or al, dl + shl eax, 11 + +.io_task: + 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. U32 PCI Device Class & Subclass +; (Higher byte: Class, lower byte: Subclass) +; 2. U32 PCI 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 cx, 4 + ; Point into driver device area (add device area start on top) + add ecx, ebx + add ecx, PCI_DEVICE_COUNT_OFFSET + mov ebx, ecx + +.set_device: + mov ecx, [ebp - 8] + mov [ebx], ecx + mov ecx, [ebp - 12] + mov [ebx + 4], ecx + +increment_device_count: + +.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. 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 - 20)], edi + ; [esi]: Device-in-bus Index + ; [esi + 4]: Number of existing devices + ; [esi + 8]: Bus number + mov [esi], dword 0 + mov [esi + 4], dword 0 + mov eax, [ebp - 8] + mov [esi + 8], eax +.initialize_device_loop: + +.device_loop: + cmp [esi], dword 32 + jae .epilog + +.test_whether_device_exists: + push ebp + mov ebp, esp + mov ah, [esi + 8] ; Bus Number + mov al, [esi] ; Device Number + call pci_device_exists + mov esp, ebp + pop ebp + + cmp ax, 0 + je .no_device + +.call_append_device: + push ebp + mov ebp, esp + push dword [esi + 8] + push dword 0xcafebabe + push dword 0xdeadbeef + call pci_append_device + mov esp, ebp + pop ebp + + mov eax, [esi + 4] + inc eax + mov [esi + 4], eax + +.no_device: + mov ecx, [esi] + inc ecx + mov [esi], ecx + jmp .device_loop + +.epilog: + mov ebx, [esi + (64 - 8)] + mov ecx, [esi + (64 - 12)] + 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] +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 + +.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 \ No newline at end of file