Skip to content

Commit 28976ea

Browse files
author
Ian Seyler
committed
Add MSI helper functions
- add msi.asm - add os_bus_cap_check function
1 parent e0d8b83 commit 28976ea

File tree

4 files changed

+235
-0
lines changed

4 files changed

+235
-0
lines changed

src/drivers.asm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
; Internal
1010
%include "drivers/apic.asm"
1111
%include "drivers/ioapic.asm"
12+
%include "drivers/msi.asm"
1213
%include "drivers/ps2.asm"
1314
%include "drivers/serial.asm"
1415
%include "drivers/timer.asm"

src/drivers/msi.asm

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
; =============================================================================
2+
; BareMetal -- a 64-bit OS written in Assembly for x86-64 systems
3+
; Copyright (C) 2008-2025 Return Infinity -- see LICENSE.TXT
4+
;
5+
; Message Signaled Interrupts (MSI-X and MSI)
6+
; =============================================================================
7+
8+
9+
; -----------------------------------------------------------------------------
10+
; Initialize MSI-X for a device
11+
; IN: RDX = Packed Bus address (as per syscalls/bus.asm)
12+
; AL = Start Vector
13+
msix_init:
14+
push r8
15+
push rdx
16+
push rcx
17+
push rbx
18+
push rax
19+
20+
mov r8b, al
21+
22+
; Check for MSI-X in PCI Capabilities
23+
mov cl, 0x11 ; PCI Capability ID for MSI-X
24+
call os_bus_cap_check
25+
jc msix_init_error
26+
27+
; Enable MSI-X
28+
msix_init_enable:
29+
push rdx
30+
; Enable MSI-X, Mask it, Get Table Size
31+
; Example MSI-X Entry (From QEMU xHCI Controller)
32+
; 000FA011 <- Cap ID 0x11 (MSI-X), next ptr 0xA0, message control 0x000F - Table size is bits 10:0 so 0x0F
33+
; 00003000 <- BIR (2:0) is 0x0 so BAR0, Table Offset (31:3) - 8-byte aligned so clear low 3 bits - 0x3000 in this case
34+
; 00003800 <- Pending Bit BIR (2:0) and Pending Bit Offset (31:3) - 0x3800 in this case
35+
; Message Control - Enable (15), Function Mask (14), Table Size (10:0)
36+
call os_bus_read
37+
mov ecx, eax ; Save for Table Size
38+
bts eax, 31 ; Enable MSI-X
39+
bts eax, 30 ; Set Function Mask
40+
call os_bus_write
41+
shr ecx, 16 ; Shift Message Control to low 16-bits
42+
and cx, 0x7FF ; Keep bits 10:0
43+
; Read the BIR and Table Offset
44+
push rdx
45+
add dl, 1
46+
call os_bus_read
47+
mov ebx, eax ; EBX for the Table Offset
48+
and ebx, 0xFFFFFFF8 ; Clear bits 2:0
49+
and eax, 0x00000007 ; Keep bits 2:0 for the BIR
50+
add al, 0x04 ; Add offset to start of BARs
51+
mov dl, al
52+
call os_bus_read ; Read the BAR address
53+
add rax, rbx ; Add offset to base
54+
sub rax, 0x04
55+
mov rdi, rax
56+
pop rdx
57+
; Configure MSI-X Table
58+
add cx, 1 ; Table Size is 0-indexed
59+
mov ebx, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0)
60+
mov bl, r8b ; Store start vector
61+
msix_init_create_entry:
62+
mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2)
63+
stosd ; Store Message Address Low
64+
shr rax, 32 ; Rotate the high bits to EAX
65+
stosd ; Store Message Address High
66+
mov eax, ebx
67+
inc ebx
68+
stosd ; Store Message Data
69+
xor eax, eax ; Bits 31:1 are reserved, Masked (0) - 1 for masked
70+
stosd ; Store Vector Control
71+
dec cx
72+
cmp cx, 0
73+
jne msix_init_create_entry
74+
75+
; Unmask MSI-X via bus
76+
pop rdx
77+
call os_bus_read
78+
btr eax, 30 ; Clear Function Mask
79+
call os_bus_write
80+
81+
pop rax
82+
pop rbx
83+
pop rcx
84+
pop rdx
85+
pop r8
86+
clc ; Clear the carry flag
87+
ret
88+
89+
msix_init_error:
90+
pop rax
91+
pop rbx
92+
pop rcx
93+
pop rdx
94+
pop r8
95+
stc ; Set the carry flag
96+
ret
97+
; -----------------------------------------------------------------------------
98+
99+
100+
; -----------------------------------------------------------------------------
101+
; Initialize MSI for a device
102+
; IN: RDX = Packed Bus address (as per syscalls/bus.asm)
103+
; AL = Start Vector
104+
msi_init:
105+
push rdx
106+
push rcx
107+
push rbx
108+
push rax
109+
110+
mov bl, al
111+
112+
; Check for MSI in PCI Capabilities
113+
mov cl, 0x05 ; PCI Capability ID for MSI
114+
call os_bus_cap_check
115+
jc msi_init_error
116+
117+
; Enable MSI
118+
msi_init_enable:
119+
push rdx
120+
; Enable MSI
121+
; Example MSI Entry (From Intel test system)
122+
; 00869005 <- Cap ID 0x05 (MSI), next ptr 0x90, message control 0x0x0086 (64-bit, MMC 8)
123+
; 00000000 <- Message Address Low
124+
; 00000000 <- Message Address High
125+
; 00000000 <- Message Data (15:0)
126+
; 00000000 <- Mask (only exists if Per-vector masking is enabled)
127+
; 00000000 <- Pending (only exists if Per-vector masking is enabled)
128+
; Message Control - Per-vector masking (8), 64-bit (7), Multiple Message Enable (6:4), Multiple Message Capable (3:1), Enable (0)
129+
; MME/MMC 000b = 1, 001b = 2, 010b = 4, 011b = 8, 100b = 16, 101b = 32
130+
; Todo - Test bit 7, Check Multiple Message Capable, copy to Multiple Message Enable
131+
add dl, 1
132+
mov rax, [os_LocalAPICAddress] ; 0xFEE for bits 31:20, Dest (19:12), RH (3), DM (2)
133+
call os_bus_write ; Store Message Address Low
134+
add dl, 1
135+
shr rax, 32 ; Rotate the high bits to EAX
136+
call os_bus_write ; Store Message Address High
137+
add dl, 1
138+
mov eax, 0x00004000 ; Trigger Mode (15), Level (14), Delivery Mode (10:8), Vector (7:0)
139+
mov al, bl ; Store start vector
140+
call os_bus_write ; Store Message Data
141+
sub dl, 3
142+
call os_bus_read ; Get Message Control
143+
bts eax, 21 ; Debug - See MME to 8
144+
bts eax, 20 ; Debug - See MME to 8
145+
bts eax, 16 ; Set Enable
146+
call os_bus_write ; Update Message Control
147+
148+
; Unmask MSI via bus
149+
pop rdx
150+
call os_bus_read
151+
btr eax, 30 ; Clear Function Mask
152+
call os_bus_write
153+
154+
msi_init_done:
155+
pop rax
156+
pop rbx
157+
pop rcx
158+
pop rdx
159+
clc ; Clear the carry flag
160+
ret
161+
162+
msi_init_error:
163+
pop rax
164+
pop rbx
165+
pop rcx
166+
pop rdx
167+
stc ; Set the carry flag
168+
ret
169+
; -----------------------------------------------------------------------------
170+
171+
172+
; =============================================================================
173+
; EOF

src/drivers/net/virtio-net.asm

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,27 @@ net_virtio_poll_nodata:
575575
; -----------------------------------------------------------------------------
576576

577577

578+
; -----------------------------------------------------------------------------
579+
; Virtio-net Interrupt
580+
align 8
581+
net_virtio_int:
582+
push rcx
583+
push rax
584+
585+
; Clear pending interrupt (if set)
586+
587+
; Acknowledge the interrupt
588+
mov ecx, APIC_EOI
589+
xor eax, eax
590+
call os_apic_write
591+
592+
pop rax
593+
pop rcx
594+
iretq
595+
; -----------------------------------------------------------------------------
596+
597+
598+
578599
; Variables
579600
virtio_net_notify_offset: dq 0
580601
virtio_net_notify_offset_multiplier: dq 0

src/syscalls/bus.asm

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,5 +139,45 @@ os_bus_read_bar_io:
139139
; -----------------------------------------------------------------------------
140140

141141

142+
; -----------------------------------------------------------------------------
143+
; Check for a device capability
144+
; IN: RDX = Packed Bus address (as per syscalls/bus.asm)
145+
; CL = Capability
146+
; OUT: RDX = Packed Bus address
147+
; Carry clear = Capability found
148+
; Carry set = Capability not found
149+
os_bus_cap_check:
150+
push rax
151+
152+
mov dl, 1
153+
call os_bus_read ; Read register 1 for Status/Command
154+
bt eax, 20 ; Check bit 4 of the Status word (31:16)
155+
jnc os_bus_cap_check_error ; If if doesn't exist then bail out
156+
mov dl, 13
157+
call os_bus_read ; Read register 13 for the Capabilities Pointer (7:0)
158+
and al, 0xFC ; Clear the bottom two bits as they are reserved
159+
os_bus_cap_check_next:
160+
shr al, 2 ; Quick divide by 4
161+
mov dl, al
162+
call os_bus_read
163+
cmp al, cl
164+
je os_bus_cap_check_done
165+
os_bus_cap_check_next_offset:
166+
shr eax, 8 ; Shift pointer to AL
167+
cmp al, 0x00 ; End of linked list?
168+
jne os_bus_cap_check_next ; If not, continue reading, otherwise fall through to error
169+
170+
os_bus_cap_check_error:
171+
pop rax
172+
stc ; Set the carry flag
173+
ret
174+
175+
os_bus_cap_check_done:
176+
pop rax
177+
clc ; Clear the carry flag
178+
ret
179+
; -----------------------------------------------------------------------------
180+
181+
142182
; =============================================================================
143183
; EOF

0 commit comments

Comments
 (0)