From 28976ea7fb2d838ee971e000c1cb2343c500f24e Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Sun, 30 Nov 2025 12:34:34 -0500 Subject: [PATCH 1/7] Add MSI helper functions - add msi.asm - add os_bus_cap_check function --- src/drivers.asm | 1 + src/drivers/msi.asm | 173 +++++++++++++++++++++++++++++++++ src/drivers/net/virtio-net.asm | 21 ++++ src/syscalls/bus.asm | 40 ++++++++ 4 files changed, 235 insertions(+) create mode 100644 src/drivers/msi.asm diff --git a/src/drivers.asm b/src/drivers.asm index 4a662c27..af775984 100644 --- a/src/drivers.asm +++ b/src/drivers.asm @@ -9,6 +9,7 @@ ; Internal %include "drivers/apic.asm" %include "drivers/ioapic.asm" +%include "drivers/msi.asm" %include "drivers/ps2.asm" %include "drivers/serial.asm" %include "drivers/timer.asm" diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm new file mode 100644 index 00000000..3587e75a --- /dev/null +++ b/src/drivers/msi.asm @@ -0,0 +1,173 @@ +; ============================================================================= +; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems +; Copyright (C) 2008-2025 Return Infinity -- see LICENSE.TXT +; +; Message Signaled Interrupts (MSI-X and MSI) +; ============================================================================= + + +; ----------------------------------------------------------------------------- +; Initialize MSI-X for a device +; IN: RDX = Packed Bus address (as per syscalls/bus.asm) +; AL = Start Vector +msix_init: + push r8 + push rdx + push rcx + push rbx + push rax + + mov r8b, al + + ; Check for MSI-X in PCI Capabilities + mov cl, 0x11 ; PCI Capability ID for MSI-X + call os_bus_cap_check + jc msix_init_error + + ; Enable MSI-X +msix_init_enable: + push rdx + ; Enable MSI-X, Mask it, Get Table Size + ; Example MSI-X Entry (From QEMU xHCI Controller) + ; 000FA011 <- Cap ID 0x11 (MSI-X), next ptr 0xA0, message control 0x000F - Table size is bits 10:0 so 0x0F + ; 00003000 <- BIR (2:0) is 0x0 so BAR0, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x3000 in this case + ; 00003800 <- Pending Bit BIR (2:0) and Pending Bit Offset (31:3) - 0x3800 in this case + ; Message Control - Enable (15), Function Mask (14), Table Size (10:0) + call os_bus_read + mov ecx, eax ; Save for Table Size + bts eax, 31 ; Enable MSI-X + bts eax, 30 ; Set Function Mask + call os_bus_write + shr ecx, 16 ; Shift Message Control to low 16-bits + and cx, 0x7FF ; Keep bits 10:0 + ; Read the BIR and Table Offset + push rdx + add dl, 1 + call os_bus_read + mov ebx, eax ; EBX for the Table Offset + and ebx, 0xFFFFFFF8 ; Clear bits 2:0 + and eax, 0x00000007 ; Keep bits 2:0 for the BIR + add al, 0x04 ; Add offset to start of BARs + mov dl, al + call os_bus_read ; Read the BAR address + add rax, rbx ; Add offset to base + sub rax, 0x04 + mov rdi, rax + pop rdx + ; Configure MSI-X Table + add cx, 1 ; Table Size is 0-indexed + mov ebx, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) + mov bl, r8b ; Store start vector +msix_init_create_entry: + mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) + stosd ; Store Message Address Low + shr rax, 32 ; Rotate the high bits to EAX + stosd ; Store Message Address High + mov eax, ebx + inc ebx + stosd ; Store Message Data + xor eax, eax ; Bits 31:1 are reserved, Masked (0) - 1 for masked + stosd ; Store Vector Control + dec cx + cmp cx, 0 + jne msix_init_create_entry + + ; Unmask MSI-X via bus + pop rdx + call os_bus_read + btr eax, 30 ; Clear Function Mask + call os_bus_write + + pop rax + pop rbx + pop rcx + pop rdx + pop r8 + clc ; Clear the carry flag + ret + +msix_init_error: + pop rax + pop rbx + pop rcx + pop rdx + pop r8 + stc ; Set the carry flag + ret +; ----------------------------------------------------------------------------- + + +; ----------------------------------------------------------------------------- +; Initialize MSI for a device +; IN: RDX = Packed Bus address (as per syscalls/bus.asm) +; AL = Start Vector +msi_init: + push rdx + push rcx + push rbx + push rax + + mov bl, al + + ; Check for MSI in PCI Capabilities + mov cl, 0x05 ; PCI Capability ID for MSI + call os_bus_cap_check + jc msi_init_error + + ; Enable MSI +msi_init_enable: + push rdx + ; Enable MSI + ; Example MSI Entry (From Intel test system) + ; 00869005 <- Cap ID 0x05 (MSI), next ptr 0x90, message control 0x0x0086 (64-bit, MMC 8) + ; 00000000 <- Message Address Low + ; 00000000 <- Message Address High + ; 00000000 <- Message Data (15:0) + ; 00000000 <- Mask (only exists if Per-vector masking is enabled) + ; 00000000 <- Pending (only exists if Per-vector masking is enabled) + ; Message Control - Per-vector masking (8), 64-bit (7), Multiple Message Enable (6:4), Multiple Message Capable (3:1), Enable (0) + ; MME/MMC 000b = 1, 001b = 2, 010b = 4, 011b = 8, 100b = 16, 101b = 32 + ; Todo - Test bit 7, Check Multiple Message Capable, copy to Multiple Message Enable + add dl, 1 + mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) + call os_bus_write ; Store Message Address Low + add dl, 1 + shr rax, 32 ; Rotate the high bits to EAX + call os_bus_write ; Store Message Address High + add dl, 1 + mov eax, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) + mov al, bl ; Store start vector + call os_bus_write ; Store Message Data + sub dl, 3 + call os_bus_read ; Get Message Control + bts eax, 21 ; Debug - See MME to 8 + bts eax, 20 ; Debug - See MME to 8 + bts eax, 16 ; Set Enable + call os_bus_write ; Update Message Control + + ; Unmask MSI via bus + pop rdx + call os_bus_read + btr eax, 30 ; Clear Function Mask + call os_bus_write + +msi_init_done: + pop rax + pop rbx + pop rcx + pop rdx + clc ; Clear the carry flag + ret + +msi_init_error: + pop rax + pop rbx + pop rcx + pop rdx + stc ; Set the carry flag + ret +; ----------------------------------------------------------------------------- + + +; ============================================================================= +; EOF \ No newline at end of file diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index 3eaf5855..a8c2355a 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -575,6 +575,27 @@ net_virtio_poll_nodata: ; ----------------------------------------------------------------------------- +; ----------------------------------------------------------------------------- +; Virtio-net Interrupt +align 8 +net_virtio_int: + push rcx + push rax + + ; Clear pending interrupt (if set) + + ; Acknowledge the interrupt + mov ecx, APIC_EOI + xor eax, eax + call os_apic_write + + pop rax + pop rcx + iretq +; ----------------------------------------------------------------------------- + + + ; Variables virtio_net_notify_offset: dq 0 virtio_net_notify_offset_multiplier: dq 0 diff --git a/src/syscalls/bus.asm b/src/syscalls/bus.asm index d6ce67f0..82de5df5 100644 --- a/src/syscalls/bus.asm +++ b/src/syscalls/bus.asm @@ -139,5 +139,45 @@ os_bus_read_bar_io: ; ----------------------------------------------------------------------------- +; ----------------------------------------------------------------------------- +; Check for a device capability +; IN: RDX = Packed Bus address (as per syscalls/bus.asm) +; CL = Capability +; OUT: RDX = Packed Bus address +; Carry clear = Capability found +; Carry set = Capability not found +os_bus_cap_check: + push rax + + mov dl, 1 + call os_bus_read ; Read register 1 for Status/Command + bt eax, 20 ; Check bit 4 of the Status word (31:16) + jnc os_bus_cap_check_error ; If if doesn't exist then bail out + mov dl, 13 + call os_bus_read ; Read register 13 for the Capabilities Pointer (7:0) + and al, 0xFC ; Clear the bottom two bits as they are reserved +os_bus_cap_check_next: + shr al, 2 ; Quick divide by 4 + mov dl, al + call os_bus_read + cmp al, cl + je os_bus_cap_check_done +os_bus_cap_check_next_offset: + shr eax, 8 ; Shift pointer to AL + cmp al, 0x00 ; End of linked list? + jne os_bus_cap_check_next ; If not, continue reading, otherwise fall through to error + +os_bus_cap_check_error: + pop rax + stc ; Set the carry flag + ret + +os_bus_cap_check_done: + pop rax + clc ; Clear the carry flag + ret +; ----------------------------------------------------------------------------- + + ; ============================================================================= ; EOF From 40281f62ccdbaef4bc264a6f9c095021ddedb328 Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Sun, 30 Nov 2025 21:52:16 -0500 Subject: [PATCH 2/7] Fix `msix_init` off by 4 error --- src/drivers/bus/xhci.asm | 4 +- src/drivers/msi.asm | 29 ++++++++----- src/drivers/net/virtio-net.asm | 78 ++++++++++++---------------------- src/sysvar.asm | 1 + 4 files changed, 47 insertions(+), 65 deletions(-) diff --git a/src/drivers/bus/xhci.asm b/src/drivers/bus/xhci.asm index ea743b48..755521b6 100644 --- a/src/drivers/bus/xhci.asm +++ b/src/drivers/bus/xhci.asm @@ -347,7 +347,7 @@ xhci_reset_build_scratchpad: ; ├──────────────────────────────┴───────┤ ; | Ring Segment Base Address Hi | ; ├──────────────────┬───────────────────┤ - ; | RsvdZ | Ring Segment Size | + ; | RsvdZ | Ring Segment Size | ; ├──────────────────┴───────────────────┤ ; | RsvdZ | ; └──────────────────────────────────────┘ @@ -1862,7 +1862,7 @@ xHCI_CC_STALL_ERROR equ 6 xHCI_CC_RESOURCE_ERROR equ 7 xHCI_CC_BANDWIDTH_ERROR equ 8 xHCI_CC_NO_SLOTS_ERROR equ 9 -xHCI_CC_INVALID_STREAM_TYPE_ERROR equ 10 +xHCI_CC_INVALID_STREAM_TYPE_ERROR equ 10 xHCI_CC_SLOT_NOT_ENABLED_ERROR equ 11 xHCI_CC_EP_NOT_ENABLED_ERROR equ 12 xHCI_CC_SHORT_PACKET equ 13 diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm index 3587e75a..16987424 100644 --- a/src/drivers/msi.asm +++ b/src/drivers/msi.asm @@ -10,6 +10,19 @@ ; Initialize MSI-X for a device ; IN: RDX = Packed Bus address (as per syscalls/bus.asm) ; AL = Start Vector +; OUT: Carry flag +; ----------------------------------------------------------------------------- +; Message Control - Enable (15), Function Mask (14), Table Size (10:0) +; +; Example MSI-X Entry (From QEMU xHCI Controller) +; 000FA011 <- Cap ID 0x11 (MSI-X), next ptr 0xA0, message control 0x000F - Table size is bits 10:0 so 0x0F +; 00003000 <- BIR (2:0) is 0x0 so BAR0, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x3000 in this case +; 00003800 <- Pending Bit BIR (2:0) and Pending Bit Offset (31:3) - 0x3800 in this case +; +; Example MSI-X Entry (From QEMU Virtio-Net) +; 00038411 <- Cap ID 0x11 (MSI-X), next ptr 0x84, message control 0x0003 - Table size is bits 10:0 so 3 (n-1 so table size is actually 4) +; 00000001 <- BIR (2:0) is 0x1 so BAR1, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x0 in this case +; 00000801 <- Pending Bit BIR (2:0) is 0x1 so BAR1 and Pending Bit Offset (31:3) is 0x800 msix_init: push r8 push rdx @@ -22,17 +35,12 @@ msix_init: ; Check for MSI-X in PCI Capabilities mov cl, 0x11 ; PCI Capability ID for MSI-X call os_bus_cap_check - jc msix_init_error + jc msix_init_error ; os_bus_cap_check sets carry flag is the cap isn't found + + push rdx ; Save packed bus address - ; Enable MSI-X -msix_init_enable: - push rdx ; Enable MSI-X, Mask it, Get Table Size - ; Example MSI-X Entry (From QEMU xHCI Controller) - ; 000FA011 <- Cap ID 0x11 (MSI-X), next ptr 0xA0, message control 0x000F - Table size is bits 10:0 so 0x0F - ; 00003000 <- BIR (2:0) is 0x0 so BAR0, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x3000 in this case - ; 00003800 <- Pending Bit BIR (2:0) and Pending Bit Offset (31:3) - 0x3800 in this case - ; Message Control - Enable (15), Function Mask (14), Table Size (10:0) +msix_init_enable: call os_bus_read mov ecx, eax ; Save for Table Size bts eax, 31 ; Enable MSI-X @@ -51,7 +59,6 @@ msix_init_enable: mov dl, al call os_bus_read ; Read the BAR address add rax, rbx ; Add offset to base - sub rax, 0x04 mov rdi, rax pop rdx ; Configure MSI-X Table @@ -73,7 +80,7 @@ msix_init_create_entry: jne msix_init_create_entry ; Unmask MSI-X via bus - pop rdx + pop rdx ; Restore packed bus address call os_bus_read btr eax, 30 ; Clear Function Mask call os_bus_write diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index a8c2355a..eddb96ae 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -17,6 +17,8 @@ net_virtio_init: push rbx push rax + push rdx ; Save packed bus address + mov rdi, net_table xor eax, eax mov al, [os_net_icount] @@ -25,7 +27,7 @@ net_virtio_init: mov ax, 0x1AF4 ; Driver tag for virtio-net stosw - push rdi ; Used in msi-x init + push rdi ; Save offset into net_table add rdi, 14 ; Get the Base Memory Address of the device @@ -58,60 +60,9 @@ virtio_net_init_cap_next: call os_bus_read cmp al, VIRTIO_PCI_CAP_VENDOR_CFG je virtio_net_init_cap - cmp al, 0x11 - je virtio_net_init_msix shr eax, 8 jmp virtio_net_init_cap_next_offset -virtio_net_init_msix: - push rdx - - ; Enable MSI-X, Mask it, Get Table Size - call os_bus_read - mov ecx, eax ; Save for Table Size - bts eax, 31 ; Enable MSIX - bts eax, 30 ; Set Function Mask - call os_bus_write - shr ecx, 16 ; Shift Message Control to low 16-bits - and cx, 0x7FF ; Keep bits 10:0 - - ; Read the BIR and Table Offset - push rdx - add dl, 1 - call os_bus_read - mov ebx, eax ; EBX for the Table Offset - and ebx, 0xFFFFFFF8 ; Clear bits 2:0 - and eax, 0x00000007 ; Keep bits 2:0 for the BIR - add al, 0x04 ; Add offset to start of BARs - mov dl, al - call os_bus_read ; Read the BAR address - add rax, rbx ; Add offset to base - mov rdi, rax - pop rdx - - ; Configure MSI-X Table - add cx, 1 ; Table Size is 0-indexed -virtio_net_init_msix_entry: - mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) - stosd ; Store Message Address Low - shr rax, 32 ; Rotate the high bits to EAX - stosd ; Store Message Address High - mov eax, 0x000040AB ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) - stosd ; Store Message Data - xor eax, eax ; Bits 31:1 are reserved, Masked (0) - 1 for masked - stosd ; Store Vector Control - dec cx - cmp cx, 0 - jne virtio_net_init_msix_entry - pop rdx - - ; Unmask MSI-X - call os_bus_read - btc eax, 30 ; Clear Function Mask - call os_bus_write - - jmp virtio_net_init_cap_next_offset - virtio_net_init_cap: rol eax, 8 ; Move Virtio cfg_type to AL cmp al, VIRTIO_PCI_CAP_COMMON_CFG @@ -197,6 +148,27 @@ virtio_net_init_cap_end: mov dl, [os_net_icount] call net_virtio_reset + ; Enable interrupts + pop rdx ; Restore packed bus address +; mov al, 0x40 +; call msix_init +; jc virtio_net_init_no_int + ; Create a gate in the IDT +; mov edi, 0x40 +; mov rax, net_virtio_int +; call create_gate +; mov edi, 0x41 +; mov rax, net_virtio_int +; call create_gate +; mov edi, 0x42 +; mov rax, net_virtio_int +; call create_gate +; mov edi, 0x43 +; mov rax, net_virtio_int +; call create_gate + +virtio_net_init_no_int: + ; Store call addresses sub rdi, 0x28 mov eax, net_virtio_config @@ -583,6 +555,8 @@ net_virtio_int: push rax ; Clear pending interrupt (if set) + mov al, 0xab + call os_debug_dump_al ; Acknowledge the interrupt mov ecx, APIC_EOI diff --git a/src/sysvar.asm b/src/sysvar.asm index e1231ec6..552007a5 100644 --- a/src/sysvar.asm +++ b/src/sysvar.asm @@ -149,6 +149,7 @@ os_PacketBuffers: equ os_SystemVariables + 0xC000 ; 16KiB ; net_table values (per device - 128 bytes) nt_ID: equ 0x00 ; 16-bit Driver ID nt_lock: equ 0x02 ; 16-bit Lock for b_net_tx +nt_interrupt: equ 0x04 ; 16-bit Interrupts enabled flag nt_MAC: equ 0x08 ; 48-bit MAC Address nt_base: equ 0x10 ; 64-bit Base MMIO nt_config: equ 0x18 ; 64-bit Config function address From 25e17f160fa2f784c8cf3c2f7dcb98cedc93747e Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Tue, 2 Dec 2025 12:36:57 -0500 Subject: [PATCH 3/7] `xhci` driver uses `msix` helper function --- src/drivers/bus/xhci.asm | 75 +++------------------------------------- src/drivers/msi.asm | 26 +++++++------- 2 files changed, 18 insertions(+), 83 deletions(-) diff --git a/src/drivers/bus/xhci.asm b/src/drivers/bus/xhci.asm index 755521b6..a0507fb5 100644 --- a/src/drivers/bus/xhci.asm +++ b/src/drivers/bus/xhci.asm @@ -27,77 +27,10 @@ xhci_init: bts eax, 1 ; Enable Memory Space call os_bus_write ; Write updated Status/Command - ; Check for MSI-X in PCI Capabilities -xhci_init_msix_check: - mov dl, 1 - call os_bus_read ; Read register 1 for Status/Command - bt eax, 20 ; Check bit 4 of the Status word (31:16) - jnc xhci_init_error ; If if doesn't exist then bail out - mov dl, 13 - call os_bus_read ; Read register 13 for the Capabilities Pointer (7:0) - and al, 0xFC ; Clear the bottom two bits as they are reserved -xhci_init_msix_check_cap_next: - shr al, 2 ; Quick divide by 4 - mov dl, al - call os_bus_read - cmp al, 0x11 - je xhci_init_msix -xhci_init_msix_check_cap_next_offset: - shr eax, 8 ; Shift pointer to AL - cmp al, 0x00 ; End of linked list? - jne xhci_init_msix_check_cap_next ; If not, continue reading - jmp xhci_init_msi_check ; Otherwise bail out and check for MSI -xhci_init_msix: - push rdx - ; Enable MSI-X, Mask it, Get Table Size - ; Example MSI-X Entry (From QEMU xHCI Controller) - ; 000FA011 <- Cap ID 0x11 (MSI-X), next ptr 0xA0, message control 0x000F - Table size is bits 10:0 so 0x0F - ; 00003000 <- BIR (2:0) is 0x0 so BAR0, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x3000 in this case - ; 00003800 <- Pending Bit BIR (2:0) and Pending Bit Offset (31:3) - 0x3800 in this case - ; Message Control - Enable (15), Function Mask (14), Table Size (10:0) - call os_bus_read - mov ecx, eax ; Save for Table Size - bts eax, 31 ; Enable MSIX - bts eax, 30 ; Set Function Mask - call os_bus_write - shr ecx, 16 ; Shift Message Control to low 16-bits - and cx, 0x7FF ; Keep bits 10:0 - ; Read the BIR and Table Offset - push rdx - add dl, 1 - call os_bus_read - mov ebx, eax ; EBX for the Table Offset - and ebx, 0xFFFFFFF8 ; Clear bits 2:0 - and eax, 0x00000007 ; Keep bits 2:0 for the BIR - add al, 0x04 ; Add offset to start of BARs - mov dl, al - call os_bus_read ; Read the BAR address - add rax, rbx ; Add offset to base - sub rax, 0x04 - mov rdi, rax - pop rdx - ; Configure MSI-X Table - add cx, 1 ; Table Size is 0-indexed - mov ebx, 0x000040A0 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) -xhci_init_msix_entry: - mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) - stosd ; Store Message Address Low - shr rax, 32 ; Rotate the high bits to EAX - stosd ; Store Message Address High - mov eax, ebx - inc ebx - stosd ; Store Message Data - xor eax, eax ; Bits 31:1 are reserved, Masked (0) - 1 for masked - stosd ; Store Vector Control - dec cx - cmp cx, 0 - jne xhci_init_msix_entry - ; Unmask MSI-X - pop rdx - call os_bus_read - btr eax, 30 ; Clear Function Mask - call os_bus_write - jmp xhci_init_msix_msi_done + ; Configure MSI-X (if available) + mov al, 0xA0 + call msix_init + jnc xhci_init_msix_msi_done ; Check for MSI in PCI Capabilities xhci_init_msi_check: diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm index 16987424..d07af39a 100644 --- a/src/drivers/msi.asm +++ b/src/drivers/msi.asm @@ -10,7 +10,7 @@ ; Initialize MSI-X for a device ; IN: RDX = Packed Bus address (as per syscalls/bus.asm) ; AL = Start Vector -; OUT: Carry flag +; OUT: Carry flag (clear on success, set on error) ; ----------------------------------------------------------------------------- ; Message Control - Enable (15), Function Mask (14), Table Size (10:0) ; @@ -59,6 +59,7 @@ msix_init_enable: mov dl, al call os_bus_read ; Read the BAR address add rax, rbx ; Add offset to base + sub rax, 0x04 mov rdi, rax pop rdx ; Configure MSI-X Table @@ -108,6 +109,18 @@ msix_init_error: ; Initialize MSI for a device ; IN: RDX = Packed Bus address (as per syscalls/bus.asm) ; AL = Start Vector +; OUT: Carry flag (clear on success, set on error) +; ----------------------------------------------------------------------------- +; Example MSI Entry (From Intel test system) +; 00869005 <- Cap ID 0x05 (MSI), next ptr 0x90, message control 0x0x0086 (64-bit, MMC 8) +; 00000000 <- Message Address Low +; 00000000 <- Message Address High +; 00000000 <- Message Data (15:0) +; 00000000 <- Mask (only exists if Per-vector masking is enabled) +; 00000000 <- Pending (only exists if Per-vector masking is enabled) +; Message Control - Per-vector masking (8), 64-bit (7), Multiple Message Enable (6:4), Multiple Message Capable (3:1), Enable (0) +; MME/MMC 000b = 1, 001b = 2, 010b = 4, 011b = 8, 100b = 16, 101b = 32 +; Todo - Test bit 7, Check Multiple Message Capable, copy to Multiple Message Enable msi_init: push rdx push rcx @@ -124,17 +137,6 @@ msi_init: ; Enable MSI msi_init_enable: push rdx - ; Enable MSI - ; Example MSI Entry (From Intel test system) - ; 00869005 <- Cap ID 0x05 (MSI), next ptr 0x90, message control 0x0x0086 (64-bit, MMC 8) - ; 00000000 <- Message Address Low - ; 00000000 <- Message Address High - ; 00000000 <- Message Data (15:0) - ; 00000000 <- Mask (only exists if Per-vector masking is enabled) - ; 00000000 <- Pending (only exists if Per-vector masking is enabled) - ; Message Control - Per-vector masking (8), 64-bit (7), Multiple Message Enable (6:4), Multiple Message Capable (3:1), Enable (0) - ; MME/MMC 000b = 1, 001b = 2, 010b = 4, 011b = 8, 100b = 16, 101b = 32 - ; Todo - Test bit 7, Check Multiple Message Capable, copy to Multiple Message Enable add dl, 1 mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) call os_bus_write ; Store Message Address Low From c199aed1211081d5f3be5041ae3bdaad09c548ce Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Tue, 2 Dec 2025 14:33:24 -0500 Subject: [PATCH 4/7] save `rdx` in `msix_init` --- src/drivers/msi.asm | 13 ++++++++++++- src/drivers/net/virtio-net.asm | 29 ++++++++++++++++------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm index d07af39a..fb86fa4d 100644 --- a/src/drivers/msi.asm +++ b/src/drivers/msi.asm @@ -25,6 +25,7 @@ ; 00000801 <- Pending Bit BIR (2:0) is 0x1 so BAR1 and Pending Bit Offset (31:3) is 0x800 msix_init: push r8 + push rdi push rdx push rcx push rbx @@ -55,13 +56,21 @@ msix_init_enable: mov ebx, eax ; EBX for the Table Offset and ebx, 0xFFFFFFF8 ; Clear bits 2:0 and eax, 0x00000007 ; Keep bits 2:0 for the BIR + add al, 0x04 ; Add offset to start of BARs mov dl, al call os_bus_read ; Read the BAR address + +; TODO - Read BAR properly +; push rcx ; Save RCX as os_bus_read_bar returns a value in it +; call os_bus_read_bar ; Read the BAR address +; pop rcx + add rax, rbx ; Add offset to base - sub rax, 0x04 + and eax, 0xFFFFFFF8 ; Clear bits 2:0 of a 32-bit BAR mov rdi, rax pop rdx + ; Configure MSI-X Table add cx, 1 ; Table Size is 0-indexed mov ebx, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) @@ -90,6 +99,7 @@ msix_init_create_entry: pop rbx pop rcx pop rdx + pop rdi pop r8 clc ; Clear the carry flag ret @@ -99,6 +109,7 @@ msix_init_error: pop rbx pop rcx pop rdx + pop rdi pop r8 stc ; Set the carry flag ret diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index eddb96ae..bf8a3d4a 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -150,22 +150,25 @@ virtio_net_init_cap_end: ; Enable interrupts pop rdx ; Restore packed bus address -; mov al, 0x40 -; call msix_init -; jc virtio_net_init_no_int - ; Create a gate in the IDT -; mov edi, 0x40 -; mov rax, net_virtio_int -; call create_gate -; mov edi, 0x41 -; mov rax, net_virtio_int -; call create_gate -; mov edi, 0x42 + mov al, 0xB0 + call msix_init + jc virtio_net_init_no_int + + ; Create gate(s) in the IDT + push rdi + mov edi, 0xB0 + mov rax, net_virtio_int + call create_gate + mov edi, 0xB1 + mov rax, net_virtio_int + call create_gate +; mov edi, 0xB2 ; mov rax, net_virtio_int ; call create_gate -; mov edi, 0x43 +; mov edi, 0xB3 ; mov rax, net_virtio_int ; call create_gate + pop rdi virtio_net_init_no_int: @@ -553,7 +556,7 @@ align 8 net_virtio_int: push rcx push rax - +jmp $ ; Clear pending interrupt (if set) mov al, 0xab call os_debug_dump_al From d4d3a2deed3dbf78d20366c153f61985d1b90c1f Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Tue, 2 Dec 2025 15:42:31 -0500 Subject: [PATCH 5/7] Verified pending bit is set on receive ``` (qemu) xp /16bx 0xfebd1800 00000000febd1800: 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ``` --- src/drivers/msi.asm | 3 +++ src/drivers/net/virtio-net.asm | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm index fb86fa4d..f1952e65 100644 --- a/src/drivers/msi.asm +++ b/src/drivers/msi.asm @@ -23,6 +23,9 @@ ; 00038411 <- Cap ID 0x11 (MSI-X), next ptr 0x84, message control 0x0003 - Table size is bits 10:0 so 3 (n-1 so table size is actually 4) ; 00000001 <- BIR (2:0) is 0x1 so BAR1, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x0 in this case ; 00000801 <- Pending Bit BIR (2:0) is 0x1 so BAR1 and Pending Bit Offset (31:3) is 0x800 +; +; Resulting MSI-X table entry in memory should look similar to: +; 0xXXXXXXXX: FEE00000 00000000 000040XX 00000000 msix_init: push r8 push rdi diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index bf8a3d4a..591ab6e7 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -266,7 +266,7 @@ virtio_net_init_reset_wait: ; reading and possibly writing the device’s virtio configuration space ; population of virtqueues - mov ax, 0x0000 + mov ax, 0xFFFF mov [rsi+VIRTIO_CONFIG_MSIX_VECTOR], ax ; Set up Queue 0 (Receive) @@ -290,9 +290,8 @@ virtio_net_init_reset_wait: rol rax, 32 mov [rsi+VIRTIO_QUEUE_DEVICE+8], eax rol rax, 32 - mov ax, 0x0001 + mov ax, 0x0000 mov [rsi+VIRTIO_QUEUE_MSIX_VECTOR], ax - mov ax, [rsi+VIRTIO_QUEUE_MSIX_VECTOR] mov ax, 1 mov [rsi+VIRTIO_QUEUE_ENABLE], ax From 8bdc835e46531e5407f36c44b7d456283dbdbe3c Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Wed, 3 Dec 2025 12:52:12 -0500 Subject: [PATCH 6/7] Interrupt fires on packet receive --- src/drivers/msi.asm | 2 +- src/drivers/net/virtio-net.asm | 55 ++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/drivers/msi.asm b/src/drivers/msi.asm index f1952e65..db1fd7e7 100644 --- a/src/drivers/msi.asm +++ b/src/drivers/msi.asm @@ -76,7 +76,7 @@ msix_init_enable: ; Configure MSI-X Table add cx, 1 ; Table Size is 0-indexed - mov ebx, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) + xor ebx, ebx ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0) mov bl, r8b ; Store start vector msix_init_create_entry: mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2) diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index 591ab6e7..014846ea 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -17,7 +17,7 @@ net_virtio_init: push rbx push rax - push rdx ; Save packed bus address +; push rdx ; Save packed bus address mov rdi, net_table xor eax, eax @@ -42,9 +42,36 @@ net_virtio_init: mov dl, 0x01 ; Read Status/Command call os_bus_read bts eax, 10 ; Set Interrupt Disable + bts eax, 2 ; Enable Bus Master bts eax, 1 ; Enable Memory Space call os_bus_write + ; Configure MSI-X (if available) + mov al, 0xB0 + call msix_init + jc net_virtio_init_skip_int + + ; Create gate(s) in the IDT + push rdi + sub rdi, 0x1C + mov ax, 0x0001 ; Set flag for nt_interrupt + stosw + mov edi, 0xB0 + mov rax, net_virtio_int + call create_gate + mov edi, 0xB1 + mov rax, net_virtio_int + call create_gate +; mov edi, 0xB2 +; mov rax, net_virtio_int +; call create_gate +; mov edi, 0xB3 +; mov rax, net_virtio_int +; call create_gate + pop rdi + +net_virtio_init_skip_int: + ; Get required values from PCI Capabilities mov dl, 1 call os_bus_read ; Read register 1 for Status/Command @@ -148,30 +175,6 @@ virtio_net_init_cap_end: mov dl, [os_net_icount] call net_virtio_reset - ; Enable interrupts - pop rdx ; Restore packed bus address - mov al, 0xB0 - call msix_init - jc virtio_net_init_no_int - - ; Create gate(s) in the IDT - push rdi - mov edi, 0xB0 - mov rax, net_virtio_int - call create_gate - mov edi, 0xB1 - mov rax, net_virtio_int - call create_gate -; mov edi, 0xB2 -; mov rax, net_virtio_int -; call create_gate -; mov edi, 0xB3 -; mov rax, net_virtio_int -; call create_gate - pop rdi - -virtio_net_init_no_int: - ; Store call addresses sub rdi, 0x28 mov eax, net_virtio_config @@ -555,7 +558,7 @@ align 8 net_virtio_int: push rcx push rax -jmp $ + ; Clear pending interrupt (if set) mov al, 0xab call os_debug_dump_al From 061ee7ddedd7d9cdfca26a4fcfc82c79f6af9ca4 Mon Sep 17 00:00:00 2001 From: Ian Seyler Date: Wed, 3 Dec 2025 15:00:23 -0500 Subject: [PATCH 7/7] Working interrupts for virtio-net --- src/drivers/bus/xhci.asm | 1 + src/drivers/net/virtio-net.asm | 31 ++++++++++--------------------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/drivers/bus/xhci.asm b/src/drivers/bus/xhci.asm index a0507fb5..654f0939 100644 --- a/src/drivers/bus/xhci.asm +++ b/src/drivers/bus/xhci.asm @@ -28,6 +28,7 @@ xhci_init: call os_bus_write ; Write updated Status/Command ; Configure MSI-X (if available) + ; TODO - Keep track of used vectors and increment as needed mov al, 0xA0 call msix_init jnc xhci_init_msix_msi_done diff --git a/src/drivers/net/virtio-net.asm b/src/drivers/net/virtio-net.asm index 014846ea..934689af 100644 --- a/src/drivers/net/virtio-net.asm +++ b/src/drivers/net/virtio-net.asm @@ -17,8 +17,6 @@ net_virtio_init: push rbx push rax -; push rdx ; Save packed bus address - mov rdi, net_table xor eax, eax mov al, [os_net_icount] @@ -47,27 +45,23 @@ net_virtio_init: call os_bus_write ; Configure MSI-X (if available) + ; TODO - Keep track of used vectors and increment as needed mov al, 0xB0 call msix_init jc net_virtio_init_skip_int ; Create gate(s) in the IDT push rdi - sub rdi, 0x1C - mov ax, 0x0001 ; Set flag for nt_interrupt - stosw mov edi, 0xB0 mov rax, net_virtio_int call create_gate - mov edi, 0xB1 - mov rax, net_virtio_int - call create_gate -; mov edi, 0xB2 -; mov rax, net_virtio_int -; call create_gate -; mov edi, 0xB3 -; mov rax, net_virtio_int -; call create_gate + pop rdi + + ; Set flag for interrupts enabled in net_table + push rdi + sub rdi, 0x1C + mov ax, 0x0001 ; Set flag for nt_interrupt + stosw pop rdi net_virtio_init_skip_int: @@ -269,7 +263,7 @@ virtio_net_init_reset_wait: ; reading and possibly writing the device’s virtio configuration space ; population of virtqueues - mov ax, 0xFFFF + mov ax, 0xFFFF ; Disable config interrupts mov [rsi+VIRTIO_CONFIG_MSIX_VECTOR], ax ; Set up Queue 0 (Receive) @@ -293,7 +287,7 @@ virtio_net_init_reset_wait: rol rax, 32 mov [rsi+VIRTIO_QUEUE_DEVICE+8], eax rol rax, 32 - mov ax, 0x0000 + mov ax, 0x0000 ; MSI-X index 0 mov [rsi+VIRTIO_QUEUE_MSIX_VECTOR], ax mov ax, 1 mov [rsi+VIRTIO_QUEUE_ENABLE], ax @@ -559,10 +553,6 @@ net_virtio_int: push rcx push rax - ; Clear pending interrupt (if set) - mov al, 0xab - call os_debug_dump_al - ; Acknowledge the interrupt mov ecx, APIC_EOI xor eax, eax @@ -574,7 +564,6 @@ net_virtio_int: ; ----------------------------------------------------------------------------- - ; Variables virtio_net_notify_offset: dq 0 virtio_net_notify_offset_multiplier: dq 0