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(&notify_cap->cap.bar);
176             notify_multiplier = io_read_32(&notify_cap->notify_off_multiplier);
177             notify_base = io_read_32(&notify_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