1 /*
2 * Copyright (c) 2019 LK Trusty Authors. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <arch/virtio-base.h>
25 #include <assert.h>
26 #include <pci.h>
27 #include <utils.h>
28 #include <virtio-device.h>
29 #include <virtio-pci.h>
30 #include <virtio.h>
31
32 /* Queue notification base address */
33 static uint64_t notify_base;
34
35 /*
36 * Queue notification multiplier, notify_multiplier is combined with the
37 * queue notify offset to derive the Queue Notify address within a BAR for
38 * a virtqueue.
39 */
40 static uint32_t notify_multiplier;
41
virtio_set_features(struct virtio_config * vio,uint64_t features)42 void virtio_set_features(struct virtio_config* vio, uint64_t features) {
43 struct virtio_pci_common_cfg* vio_pci = (struct virtio_pci_common_cfg*)vio;
44
45 io_write_32(&vio_pci->guest_features_sel, 0);
46 io_write_32(&vio_pci->guest_features, features & 0xFFFF);
47 io_write_32(&vio_pci->guest_features_sel, 1);
48 io_write_32(&vio_pci->guest_features, features >> 32);
49 }
50
virtio_get_features(struct virtio_config * vio)51 uint64_t virtio_get_features(struct virtio_config* vio) {
52 struct virtio_pci_common_cfg* vio_pci = (struct virtio_pci_common_cfg*)vio;
53 uint64_t features;
54
55 io_write_32(&vio_pci->host_features_sel, 1);
56 features = io_read_32(&vio_pci->host_features);
57 features <<= 32;
58 io_write_32(&vio_pci->host_features_sel, 0);
59 features |= io_read_32(&vio_pci->host_features);
60 return features;
61 }
62
vq_attach(struct virtq * vq,uint16_t idx)63 void vq_attach(struct virtq* vq, uint16_t idx) {
64 struct virtio_pci_common_cfg* vio_pci =
65 (struct virtio_pci_common_cfg*)vq->vio;
66
67 vq->queue_id = idx;
68 io_write_16(&vio_pci->queue_sel, idx);
69 io_write_16(&vio_pci->queue_size, vq->num_bufs);
70
71 io_write_64(&vio_pci->queue_desc, (uint64_t)&vq->raw->desc);
72 io_write_64(&vio_pci->queue_avail, (uint64_t)&vq->raw->avail);
73 io_write_64(&vio_pci->queue_used, (uint64_t)&vq->raw->used);
74
75 io_write_16(&vio_pci->queue_enable, 1);
76 }
77
vq_kick(struct virtq * vq)78 void vq_kick(struct virtq* vq) {
79 struct virtio_pci_common_cfg* vio_pci =
80 (struct virtio_pci_common_cfg*)vq->vio;
81 uint16_t notify_off;
82 uint64_t notify_addr;
83
84 io_write_16(&vio_pci->queue_sel, vq->queue_id);
85
86 notify_off = io_read_16(&vio_pci->queue_notify_off);
87
88 notify_addr = notify_base + notify_off * notify_multiplier;
89 io_write_32((void*)notify_addr, vq->queue_id);
90 }
91
virtio_or_status(struct virtio_config * vio,uint32_t flags)92 void virtio_or_status(struct virtio_config* vio, uint32_t flags) {
93 struct virtio_pci_common_cfg* vio_pci = (struct virtio_pci_common_cfg*)vio;
94 uint8_t old_status = io_read_8(&vio_pci->device_status);
95
96 io_write_8(&vio_pci->device_status, old_status | flags);
97 }
98
virtio_get_status(struct virtio_config * vio)99 uint32_t virtio_get_status(struct virtio_config* vio) {
100 struct virtio_pci_common_cfg* vio_pci = (struct virtio_pci_common_cfg*)vio;
101
102 return io_read_8(&vio_pci->device_status);
103 }
104
virtio_reset_device(struct virtio_config * vio)105 void virtio_reset_device(struct virtio_config* vio) {
106 struct virtio_pci_common_cfg* vio_pci = (struct virtio_pci_common_cfg*)vio;
107
108 io_write_8(&vio_pci->device_status, 0);
109 }
110
virtio_set_guest_page_size(struct virtio_config * vio,uint32_t size)111 void virtio_set_guest_page_size(struct virtio_config* vio, uint32_t size) {}
112
virtio_console_probe_pcie_mmio(void)113 static void* virtio_console_probe_pcie_mmio(void) {
114 uint8_t cap_offset;
115 uint8_t common_bar;
116 uint8_t notify_bar;
117 uint16_t cmd_val;
118 uint64_t virtio_cfg;
119 uint64_t base_addr;
120 struct pci_type0_config* cfg;
121
122 /*
123 * PCI Express extends the Configuration Space to 4096 bytes per Function as
124 * compared to 256 bytes allowed by PCI Local Bus Specification
125 */
126 for (base_addr = VIRT_PCIE_ECAM_HIGH_BASE;
127 base_addr < VIRT_PCIE_ECAM_HIGH_BASE + VIRT_PCIE_ECAM_HIGH_SIZE;
128 base_addr += PAGE_SIZE) {
129 cfg = (struct pci_type0_config*)base_addr;
130 if ((VIRTIO_DEVICE_VENDOR_ID == cfg->vendor_id) &&
131 (VIRTIO_PCI_DEVICE_CONSOLE_ID == cfg->device_id)) {
132 break;
133 }
134 }
135
136 if (base_addr == VIRT_PCIE_ECAM_HIGH_BASE + VIRT_PCIE_ECAM_HIGH_SIZE) {
137 log_msg("Error: No virtio console device found!\n");
138 return NULL;
139 }
140
141 /* Make sure Capabilities List bit is set */
142 if (!(cfg->status & (1 << STATUS_CAP_LIST_BIT_POSITION))) {
143 log_msg("Error: Virtio console capabilities list unsupport!\n");
144 return NULL;
145 }
146
147 /* Enable Memory Space access */
148 cmd_val = io_read_16(&cfg->command);
149 cmd_val |= 1 << CMD_MEM_SPACE_BIT_POSITION;
150 io_write_16(&cfg->command, cmd_val);
151
152 /* Get capabilities start offset */
153 cap_offset = cfg->capabilities_pointer;
154
155 /*
156 * Traverse capabilites linked list to find common configuration
157 * and notification settings. Common configuration and notification
158 * should share same BAR with different offset.
159 */
160 do {
161 struct virtio_pci_cap* virtio_cap =
162 (struct virtio_pci_cap*)(base_addr + cap_offset);
163 uint8_t type = io_read_8(&virtio_cap->cfg_type);
164
165 if (VIRTIO_PCI_CAP_COMMON_CFG == type) {
166 common_bar = io_read_8(&virtio_cap->bar);
167 virtio_cfg = io_read_32(&virtio_cap->offset);
168 virtio_cfg += VIRT_CONSOLE_BAR_ADDR;
169 }
170
171 if (VIRTIO_PCI_CAP_NOTIFY_CFG == type) {
172 struct virtio_pci_notify_cap* notify_cap =
173 (struct virtio_pci_notify_cap*)virtio_cap;
174
175 notify_bar = io_read_8(¬ify_cap->cap.bar);
176 notify_multiplier = io_read_32(¬ify_cap->notify_off_multiplier);
177 notify_base = io_read_32(¬ify_cap->cap.offset);
178 notify_base += VIRT_CONSOLE_BAR_ADDR;
179 }
180
181 cap_offset = io_read_8(&virtio_cap->cap_next);
182 } while (0 != cap_offset);
183
184 assert(common_bar == notify_bar);
185
186 /* Set 64-bit BAR address */
187 io_write_64((uint64_t*)((uint64_t)&cfg->base_addr_reg0 + common_bar * 4),
188 VIRT_CONSOLE_BAR_ADDR | 0x4);
189
190 return (void*)virtio_cfg;
191 }
192
virtio_probe_console(void)193 struct virtio_config* virtio_probe_console(void) {
194 return virtio_console_probe_pcie_mmio();
195 }
196