Voxia OS v0.0.1
Hobby Project Operating System Targeting x86-64
Loading...
Searching...
No Matches
virtio.c
Go to the documentation of this file.
1#include "init/init.h"
2#include "ioforge/ioforge.h"
5#include "libk/serial.h"
6#include "type.h"
7#include <virtio/virtio.h>
8#include <str.h>
9#include <hal/pci/pci.h>
10
12
13static void
15 struct ioforge_virtio_device* v) {
16 if (!virtio_cap) {
17 LOG2_WARN("VIRTIO",
18 "device at %d:%d:%d has virtio "
19 "flag but no capability",
20 pci->pci_bus, pci->pci_dev, pci->pci_func);
21 return;
22 }
23
24 uint8_t pci_bus = (uint8_t) pci->pci_bus;
25 uint8_t pci_dev = (uint8_t) pci->pci_dev;
26 uint8_t pci_func = (uint8_t) pci->pci_func;
27
28 auto cap_len = pci_read8(pci_bus, pci_dev, pci_func, virtio_cap + 2);
29 auto next_ptr = pci_read8(pci_bus, pci_dev, pci_func, virtio_cap + 1);
30 auto cap_type = pci_read8(pci_bus, pci_dev, pci_func, virtio_cap + 3);
31 auto bar = pci_read8(pci_bus, pci_dev, pci_func, virtio_cap + 4);
32 auto offset = pci_read32(pci_bus, pci_dev, pci_func, virtio_cap + 8);
33
34 LOG2_INFO("VIRTIO",
35 " virtio cap type %d len %d bar %d "
36 "offset 0x%x",
37 cap_type, cap_len, bar, offset);
38
39 switch (cap_type) {
41
42 uint32_t multiplier =
43 pci_read32(pci_bus, pci_dev, pci_func, virtio_cap + 12);
44
45 auto virtio_common_cap = &v->common_cfg;
46 virtio_common_cap->bar = bar;
47 virtio_common_cap->offset = offset;
48 virtio_common_cap->length = multiplier;
49 virtio_common_cap->cfg_type = VIRTIO_PCI_CAP_COMMON_CFG;
50 virtio_common_cap->cap_next = next_ptr;
51 break;
52 }
54 uint32_t multiplier =
55 pci_read32(pci_bus, pci_dev, pci_func, virtio_cap + 12);
56 auto virtio_notify_cap = &v->notify_cfg;
57 virtio_notify_cap->bar = bar;
58 virtio_notify_cap->offset = offset;
59 virtio_notify_cap->length = multiplier;
60 virtio_notify_cap->cfg_type = VIRTIO_PCI_CAP_NOTIFY_CFG;
61 virtio_notify_cap->cap_next = next_ptr;
62 break;
63 }
65 uint32_t multiplier =
66 pci_read32(pci_bus, pci_dev, pci_func, virtio_cap + 12);
67 auto virtio_isr_cap = &v->isr_cfg;
68 virtio_isr_cap->bar = bar;
69 virtio_isr_cap->offset = offset;
70 virtio_isr_cap->length = multiplier;
71 virtio_isr_cap->cfg_type = VIRTIO_PCI_CAP_ISR_CFG;
72 virtio_isr_cap->cap_next = next_ptr;
73 break;
74 }
75 }
76}
77
78static void for_each_virtio_device(struct ioforge_device* node) {
79 if (!node)
80 return;
81
82 if (node->type == IOFORGE_PCI) {
83 struct ioforge_pci_device* pci =
84 (struct ioforge_pci_device*) node;
85
86 if (pci->base.flags & (uint32_t)IOFORGE_F_VIRTIO) {
87
88 LOG2_INFO("VIRTIO", "found virtio device at %d:%d:%d",
89 pci->pci_bus, pci->pci_dev, pci->pci_func);
90
91 struct ioforge_virtio_device* virtio_device =
93 sizeof(*virtio_device));
94 memset(virtio_device, 0, sizeof(*virtio_device));
95 memcopy(&virtio_device->pci, pci, sizeof(*pci));
96 virtio_device->pci.base.type = IOFORGE_VIRTIO;
97
98 {
99 auto cap_ptr = pci->capability_ptr;
100 uint8_t bus = (uint8_t) pci->pci_bus;
101 uint8_t device = (uint8_t) pci->pci_dev;
102 uint8_t func = (uint8_t) pci->pci_func;
103
104 while (cap_ptr != 0 && cap_ptr >= 0x40
105 && cap_ptr <= 0xFF) {
106 uint8_t cap_id = pci_read8(
107 bus, device, func, cap_ptr);
108 uint8_t next_ptr = pci_read8(
109 bus, device, func, cap_ptr + 1);
110
111 if (cap_id == VIRTIO_PCI_CAP) {
113 pci, cap_ptr,
114 virtio_device);
115 }
116
117 cap_ptr = next_ptr;
118 }
119 }
120
121 if (!virtio_device->common_cfg.bar
122 || !virtio_device->notify_cfg.bar
123 || !virtio_device->isr_cfg.bar) {
125 "VIRTIO",
126 "Missing required VirtIO capabilities");
127 kfree(virtio_device, sizeof(*virtio_device));
128 goto for_each_virtio_next;
129 }
130
131 // check
132 {
133 uint8_t common_bar =
134 virtio_device->common_cfg.bar & 0x7;
135 if (common_bar >= 6
136 || virtio_device->pci.bar[common_bar]
137 .iospace) {
139 "VIRTIO",
140 "Invalid common config BAR: %d",
141 common_bar);
142 return;
143 }
144 }
145 {
146 uint8_t notify_bar =
147 virtio_device->notify_cfg.bar & 0x7;
148 if (notify_bar >= 6
149 || virtio_device->pci.bar[notify_bar]
150 .iospace) {
151 LOG2_ERROR("VIRTIO",
152 "Invalid notify BAR: %d",
153 notify_bar);
154 return;
155 }
156 }
157 {
158 uint8_t isr_bar =
159 virtio_device->isr_cfg.bar & 0x7;
160 if (isr_bar >= 6
161 || virtio_device->pci.bar[isr_bar]
162 .iospace) {
163 LOG2_ERROR("VIRTIO",
164 "Invalid ISR BAR: %d",
165 isr_bar);
166 return;
167 }
168 }
169
170 ioforge_attach(virtio_root, &virtio_device->pci.base);
171 }
172 }
173
174for_each_virtio_next:
177}
178
179INIT(Virtio) {
180 LOG2_INFO("VIRTIO", "virtio init");
181
182 virtio_root = kalloc(sizeof(struct ioforge_device));
183 memset(virtio_root, 0, sizeof(*virtio_root));
184 strcpy((char*) virtio_root->name, "VIRTIO");
187
189 LOG2_INFO("VIRTIO",
190 "scanning for virtio devices under PCI root at 0x%x",
193}
194
197 struct ioforge_device* node = virtio_root->first_child;
198 while (node) {
199 if (node->type == IOFORGE_VIRTIO) {
200 struct ioforge_virtio_device* v =
201 (struct ioforge_virtio_device*) (void*) node;
202 if (v->pci.vendor_id == vendor_id
203 && v->pci.device_id == device_id) {
204 return v;
205 }
206 }
207 node = node->next_sibling;
208 }
209 return NULL;
210}
#define INIT(fn)
Definition init.h:26
static struct ioforge_device * pci_root
Definition ioforge.c:26
struct ioforge_device * ioforge_get_root()
void ioforge_attach(struct ioforge_device *parent, struct ioforge_device *child)
#define IOFORGE_F_VIRTIO
Definition ioforge.h:23
struct ioforge_device * ioforge_get_pci_root()
@ IOFORGE_PCI
Definition ioforge.h:12
@ IOFORGE_ROOT
Definition ioforge.h:11
@ IOFORGE_VIRTIO
Definition ioforge.h:18
struct ioforge_pci_device pci
void kfree(void *ptr, size_t size)
void * kalloc(size_t size)
uint8_t pci_read8(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:67
uint32_t pci_read32(uint8_t bus, uint8_t dev, uint8_t func, uint16_t off)
Definition scan.c:49
#define LOG2_WARN(mod, fmt,...)
Definition serial.h:40
#define LOG2_ERROR(mod, fmt,...)
Definition serial.h:38
#define LOG2_INFO(mod, fmt,...)
Definition serial.h:33
void strcpy(char *dest, const char *src)
void memset(void *ptr, int value, size_t num)
void memcopy(void *dest, void *src, size_t size)
struct ioforge_device * first_child
Definition ioforge.h:36
struct ioforge_device * next_sibling
Definition ioforge.h:37
IoForgeType type
Definition ioforge.h:31
boolean_t iospace
Definition ioforge_pci.h:12
struct ioforge_pci_bar bar[6]
Definition ioforge_pci.h:37
struct ioforge_device base
Definition ioforge_pci.h:16
struct ioforge_pci_device pci
struct virtio_pci_cap notify_cfg
struct virtio_pci_cap isr_cfg
struct virtio_pci_cap common_cfg
uint8_t bar
Definition virtio.h:73
#define NULL
Definition type.h:76
unsigned short uint16_t
Definition type.h:13
unsigned int uint32_t
Definition type.h:19
#define KERNEL_API
Definition type.h:93
unsigned long uintptr_t
Definition type.h:73
unsigned char uint8_t
Definition type.h:7
static void for_each_virtio_device(struct ioforge_device *node)
Definition virtio.c:78
struct ioforge_device * virtio_root
Definition virtio.c:11
static void virtio_scan_capabilities(struct ioforge_pci_device *pci, uint16_t virtio_cap, struct ioforge_virtio_device *v)
Definition virtio.c:14
struct ioforge_virtio_device * find_virtio_device_by_id(uint16_t vendor_id, uint16_t device_id)
#define VIRTIO_PCI_CAP_ISR_CFG
Definition virtio.h:10
uint32_t offset
Definition virtio.h:6
#define VIRTIO_PCI_CAP_NOTIFY_CFG
Definition virtio.h:9
#define VIRTIO_PCI_CAP_COMMON_CFG
Definition virtio.h:8
#define VIRTIO_PCI_CAP
Definition virtio.h:6
uint8_t bar
Definition virtio.h:4
uint8_t cap_len
Definition virtio.h:2
struct device_id device
Definition vnode.h:13