diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/lguest/lguest.c | 140 |
1 files changed, 131 insertions, 9 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index b00263f5febb..10a72b810127 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -673,7 +673,13 @@ static void trigger_irq(struct virtqueue *vq) | |||
673 | return; | 673 | return; |
674 | } | 674 | } |
675 | 675 | ||
676 | /* Set isr to 1 (queue interrupt pending) */ | 676 | /* |
677 | * 4.1.4.5.1: | ||
678 | * | ||
679 | * If MSI-X capability is disabled, the device MUST set the Queue | ||
680 | * Interrupt bit in ISR status before sending a virtqueue notification | ||
681 | * to the driver. | ||
682 | */ | ||
677 | vq->dev->mmio->isr = 0x1; | 683 | vq->dev->mmio->isr = 0x1; |
678 | 684 | ||
679 | /* Send the Guest an interrupt tell them we used something up. */ | 685 | /* Send the Guest an interrupt tell them we used something up. */ |
@@ -1304,11 +1310,19 @@ static bool pci_data_iowrite(u16 port, u32 mask, u32 val) | |||
1304 | } else if (&d->config_words[reg] == &d->config.cfg_access.pci_cfg_data) { | 1310 | } else if (&d->config_words[reg] == &d->config.cfg_access.pci_cfg_data) { |
1305 | u32 write_mask; | 1311 | u32 write_mask; |
1306 | 1312 | ||
1313 | /* | ||
1314 | * 4.1.4.7.1: | ||
1315 | * | ||
1316 | * Upon detecting driver write access to pci_cfg_data, the | ||
1317 | * device MUST execute a write access at offset cap.offset at | ||
1318 | * BAR selected by cap.bar using the first cap.length bytes | ||
1319 | * from pci_cfg_data. | ||
1320 | */ | ||
1321 | |||
1307 | /* Must be bar 0 */ | 1322 | /* Must be bar 0 */ |
1308 | if (!valid_bar_access(d, &d->config.cfg_access)) | 1323 | if (!valid_bar_access(d, &d->config.cfg_access)) |
1309 | return false; | 1324 | return false; |
1310 | 1325 | ||
1311 | /* First copy what they wrote into the window */ | ||
1312 | iowrite(portoff, val, mask, &d->config.cfg_access.pci_cfg_data); | 1326 | iowrite(portoff, val, mask, &d->config.cfg_access.pci_cfg_data); |
1313 | 1327 | ||
1314 | /* | 1328 | /* |
@@ -1346,6 +1360,14 @@ static void pci_data_ioread(u16 port, u32 mask, u32 *val) | |||
1346 | if (&d->config_words[reg] == &d->config.cfg_access.pci_cfg_data) { | 1360 | if (&d->config_words[reg] == &d->config.cfg_access.pci_cfg_data) { |
1347 | u32 read_mask; | 1361 | u32 read_mask; |
1348 | 1362 | ||
1363 | /* | ||
1364 | * 4.1.4.7.1: | ||
1365 | * | ||
1366 | * Upon detecting driver read access to pci_cfg_data, the | ||
1367 | * device MUST execute a read access of length cap.length at | ||
1368 | * offset cap.offset at BAR selected by cap.bar and store the | ||
1369 | * first cap.length bytes in pci_cfg_data. | ||
1370 | */ | ||
1349 | /* Must be bar 0 */ | 1371 | /* Must be bar 0 */ |
1350 | if (!valid_bar_access(d, &d->config.cfg_access)) | 1372 | if (!valid_bar_access(d, &d->config.cfg_access)) |
1351 | errx(1, "Invalid cfg_access to bar%u, offset %u len %u", | 1373 | errx(1, "Invalid cfg_access to bar%u, offset %u len %u", |
@@ -1704,6 +1726,13 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1704 | 1726 | ||
1705 | switch (off) { | 1727 | switch (off) { |
1706 | case offsetof(struct virtio_pci_mmio, cfg.device_feature_select): | 1728 | case offsetof(struct virtio_pci_mmio, cfg.device_feature_select): |
1729 | /* | ||
1730 | * 4.1.4.3.1: | ||
1731 | * | ||
1732 | * The device MUST present the feature bits it is offering in | ||
1733 | * device_feature, starting at bit device_feature_select ∗ 32 | ||
1734 | * for any device_feature_select written by the driver | ||
1735 | */ | ||
1707 | if (val == 0) | 1736 | if (val == 0) |
1708 | d->mmio->cfg.device_feature = d->features; | 1737 | d->mmio->cfg.device_feature = d->features; |
1709 | else if (val == 1) | 1738 | else if (val == 1) |
@@ -1731,12 +1760,23 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1731 | goto write_through32; | 1760 | goto write_through32; |
1732 | case offsetof(struct virtio_pci_mmio, cfg.device_status): | 1761 | case offsetof(struct virtio_pci_mmio, cfg.device_status): |
1733 | verbose("%s: device status -> %#x\n", d->name, val); | 1762 | verbose("%s: device status -> %#x\n", d->name, val); |
1763 | /* | ||
1764 | * 4.1.4.3.1: | ||
1765 | * | ||
1766 | * The device MUST reset when 0 is written to device_status, | ||
1767 | * and present a 0 in device_status once that is done. | ||
1768 | */ | ||
1734 | if (val == 0) | 1769 | if (val == 0) |
1735 | reset_device(d); | 1770 | reset_device(d); |
1736 | goto write_through8; | 1771 | goto write_through8; |
1737 | case offsetof(struct virtio_pci_mmio, cfg.queue_select): | 1772 | case offsetof(struct virtio_pci_mmio, cfg.queue_select): |
1738 | vq = vq_by_num(d, val); | 1773 | vq = vq_by_num(d, val); |
1739 | /* Out of range? Return size 0 */ | 1774 | /* |
1775 | * 4.1.4.3.1: | ||
1776 | * | ||
1777 | * The device MUST present a 0 in queue_size if the virtqueue | ||
1778 | * corresponding to the current queue_select is unavailable. | ||
1779 | */ | ||
1740 | if (!vq) { | 1780 | if (!vq) { |
1741 | d->mmio->cfg.queue_size = 0; | 1781 | d->mmio->cfg.queue_size = 0; |
1742 | goto write_through16; | 1782 | goto write_through16; |
@@ -1841,6 +1881,17 @@ static u32 emulate_mmio_read(struct device *d, u32 off, u32 mask) | |||
1841 | goto read_through16; | 1881 | goto read_through16; |
1842 | case offsetof(struct virtio_pci_mmio, cfg.device_status): | 1882 | case offsetof(struct virtio_pci_mmio, cfg.device_status): |
1843 | case offsetof(struct virtio_pci_mmio, cfg.config_generation): | 1883 | case offsetof(struct virtio_pci_mmio, cfg.config_generation): |
1884 | /* | ||
1885 | * 4.1.4.3.1: | ||
1886 | * | ||
1887 | * The device MUST present a changed config_generation after | ||
1888 | * the driver has read a device-specific configuration value | ||
1889 | * which has changed since any part of the device-specific | ||
1890 | * configuration was last read. | ||
1891 | * | ||
1892 | * This is simple: none of our devices change config, so this | ||
1893 | * is always 0. | ||
1894 | */ | ||
1844 | goto read_through8; | 1895 | goto read_through8; |
1845 | case offsetof(struct virtio_pci_mmio, notify): | 1896 | case offsetof(struct virtio_pci_mmio, notify): |
1846 | goto read_through16; | 1897 | goto read_through16; |
@@ -1848,8 +1899,12 @@ static u32 emulate_mmio_read(struct device *d, u32 off, u32 mask) | |||
1848 | if (mask != 0xFF) | 1899 | if (mask != 0xFF) |
1849 | errx(1, "%s: non-8-bit read from offset %u (%#x)", | 1900 | errx(1, "%s: non-8-bit read from offset %u (%#x)", |
1850 | d->name, off, getreg(eip)); | 1901 | d->name, off, getreg(eip)); |
1851 | /* Read resets the isr */ | ||
1852 | isr = d->mmio->isr; | 1902 | isr = d->mmio->isr; |
1903 | /* | ||
1904 | * 4.1.4.5.1: | ||
1905 | * | ||
1906 | * The device MUST reset ISR status to 0 on driver read. | ||
1907 | */ | ||
1853 | d->mmio->isr = 0; | 1908 | d->mmio->isr = 0; |
1854 | return isr; | 1909 | return isr; |
1855 | case offsetof(struct virtio_pci_mmio, padding): | 1910 | case offsetof(struct virtio_pci_mmio, padding): |
@@ -2008,10 +2063,25 @@ static void set_device_config(struct device *dev, const void *conf, size_t len) | |||
2008 | dev->mmio = realloc(dev->mmio, dev->mmio_size); | 2063 | dev->mmio = realloc(dev->mmio, dev->mmio_size); |
2009 | memcpy(dev->mmio + 1, conf, len); | 2064 | memcpy(dev->mmio + 1, conf, len); |
2010 | 2065 | ||
2066 | /* | ||
2067 | * 4.1.4.6: | ||
2068 | * | ||
2069 | * The device MUST present at least one VIRTIO_PCI_CAP_DEVICE_CFG | ||
2070 | * capability for any device type which has a device-specific | ||
2071 | * configuration. | ||
2072 | */ | ||
2011 | /* Hook up device cfg */ | 2073 | /* Hook up device cfg */ |
2012 | dev->config.cfg_access.cap.cap_next | 2074 | dev->config.cfg_access.cap.cap_next |
2013 | = offsetof(struct pci_config, device); | 2075 | = offsetof(struct pci_config, device); |
2014 | 2076 | ||
2077 | /* | ||
2078 | * 4.1.4.6.1: | ||
2079 | * | ||
2080 | * The offset for the device-specific configuration MUST be 4-byte | ||
2081 | * aligned. | ||
2082 | */ | ||
2083 | assert(dev->config.cfg_access.cap.cap_next % 4 == 0); | ||
2084 | |||
2015 | /* Fix up device cfg field length. */ | 2085 | /* Fix up device cfg field length. */ |
2016 | dev->config.device.length = len; | 2086 | dev->config.device.length = len; |
2017 | 2087 | ||
@@ -2041,7 +2111,12 @@ static void init_pci_config(struct pci_config *pci, u16 type, | |||
2041 | { | 2111 | { |
2042 | size_t bar_offset, bar_len; | 2112 | size_t bar_offset, bar_len; |
2043 | 2113 | ||
2044 | /* Save typing: most thing are happy being zero. */ | 2114 | /* |
2115 | * 4.1.4.4.1: | ||
2116 | * | ||
2117 | * The device MUST either present notify_off_multiplier as an even | ||
2118 | * power of 2, or present notify_off_multiplier as 0. | ||
2119 | */ | ||
2045 | memset(pci, 0, sizeof(*pci)); | 2120 | memset(pci, 0, sizeof(*pci)); |
2046 | 2121 | ||
2047 | /* 4.1.2.1: Devices MUST have the PCI Vendor ID 0x1AF4 */ | 2122 | /* 4.1.2.1: Devices MUST have the PCI Vendor ID 0x1AF4 */ |
@@ -2058,14 +2133,18 @@ static void init_pci_config(struct pci_config *pci, u16 type, | |||
2058 | pci->subclass = subclass; | 2133 | pci->subclass = subclass; |
2059 | 2134 | ||
2060 | /* | 2135 | /* |
2061 | * 4.1.2.1 Non-transitional devices SHOULD have a PCI Revision | 2136 | * 4.1.2.1: |
2062 | * ID of 1 or higher | 2137 | * |
2138 | * Non-transitional devices SHOULD have a PCI Revision ID of 1 or | ||
2139 | * higher | ||
2063 | */ | 2140 | */ |
2064 | pci->revid = 1; | 2141 | pci->revid = 1; |
2065 | 2142 | ||
2066 | /* | 2143 | /* |
2067 | * 4.1.2.1 Non-transitional devices SHOULD have a PCI | 2144 | * 4.1.2.1: |
2068 | * Subsystem Device ID of 0x40 or higher. | 2145 | * |
2146 | * Non-transitional devices SHOULD have a PCI Subsystem Device ID of | ||
2147 | * 0x40 or higher. | ||
2069 | */ | 2148 | */ |
2070 | pci->subsystem_device_id = 0x40; | 2149 | pci->subsystem_device_id = 0x40; |
2071 | 2150 | ||
@@ -2077,17 +2156,48 @@ static void init_pci_config(struct pci_config *pci, u16 type, | |||
2077 | pci->status = (1 << 4); | 2156 | pci->status = (1 << 4); |
2078 | 2157 | ||
2079 | /* Link them in. */ | 2158 | /* Link them in. */ |
2159 | /* | ||
2160 | * 4.1.4.3.1: | ||
2161 | * | ||
2162 | * The device MUST present at least one common configuration | ||
2163 | * capability. | ||
2164 | */ | ||
2080 | pci->capabilities = offsetof(struct pci_config, common); | 2165 | pci->capabilities = offsetof(struct pci_config, common); |
2081 | 2166 | ||
2167 | /* 4.1.4.3.1 ... offset MUST be 4-byte aligned. */ | ||
2168 | assert(pci->capabilities % 4 == 0); | ||
2169 | |||
2082 | bar_offset = offsetof(struct virtio_pci_mmio, cfg); | 2170 | bar_offset = offsetof(struct virtio_pci_mmio, cfg); |
2083 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->cfg); | 2171 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->cfg); |
2084 | init_cap(&pci->common, sizeof(pci->common), VIRTIO_PCI_CAP_COMMON_CFG, | 2172 | init_cap(&pci->common, sizeof(pci->common), VIRTIO_PCI_CAP_COMMON_CFG, |
2085 | bar_offset, bar_len, | 2173 | bar_offset, bar_len, |
2086 | offsetof(struct pci_config, notify)); | 2174 | offsetof(struct pci_config, notify)); |
2087 | 2175 | ||
2176 | /* | ||
2177 | * 4.1.4.4.1: | ||
2178 | * | ||
2179 | * The device MUST present at least one notification capability. | ||
2180 | */ | ||
2088 | bar_offset += bar_len; | 2181 | bar_offset += bar_len; |
2089 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->notify); | 2182 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->notify); |
2183 | |||
2184 | /* | ||
2185 | * 4.1.4.4.1: | ||
2186 | * | ||
2187 | * The cap.offset MUST be 2-byte aligned. | ||
2188 | */ | ||
2189 | assert(pci->common.cap_next % 2 == 0); | ||
2190 | |||
2090 | /* FIXME: Use a non-zero notify_off, for per-queue notification? */ | 2191 | /* FIXME: Use a non-zero notify_off, for per-queue notification? */ |
2192 | /* | ||
2193 | * 4.1.4.4.1: | ||
2194 | * | ||
2195 | * The value cap.length presented by the device MUST be at least 2 and | ||
2196 | * MUST be large enough to support queue notification offsets for all | ||
2197 | * supported queues in all possible configurations. | ||
2198 | */ | ||
2199 | assert(bar_len >= 2); | ||
2200 | |||
2091 | init_cap(&pci->notify.cap, sizeof(pci->notify), | 2201 | init_cap(&pci->notify.cap, sizeof(pci->notify), |
2092 | VIRTIO_PCI_CAP_NOTIFY_CFG, | 2202 | VIRTIO_PCI_CAP_NOTIFY_CFG, |
2093 | bar_offset, bar_len, | 2203 | bar_offset, bar_len, |
@@ -2095,11 +2205,23 @@ static void init_pci_config(struct pci_config *pci, u16 type, | |||
2095 | 2205 | ||
2096 | bar_offset += bar_len; | 2206 | bar_offset += bar_len; |
2097 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->isr); | 2207 | bar_len = sizeof(((struct virtio_pci_mmio *)0)->isr); |
2208 | /* | ||
2209 | * 4.1.4.5.1: | ||
2210 | * | ||
2211 | * The device MUST present at least one VIRTIO_PCI_CAP_ISR_CFG | ||
2212 | * capability. | ||
2213 | */ | ||
2098 | init_cap(&pci->isr, sizeof(pci->isr), | 2214 | init_cap(&pci->isr, sizeof(pci->isr), |
2099 | VIRTIO_PCI_CAP_ISR_CFG, | 2215 | VIRTIO_PCI_CAP_ISR_CFG, |
2100 | bar_offset, bar_len, | 2216 | bar_offset, bar_len, |
2101 | offsetof(struct pci_config, cfg_access)); | 2217 | offsetof(struct pci_config, cfg_access)); |
2102 | 2218 | ||
2219 | /* | ||
2220 | * 4.1.4.7.1: | ||
2221 | * | ||
2222 | * The device MUST present at least one VIRTIO_PCI_CAP_PCI_CFG | ||
2223 | * capability. | ||
2224 | */ | ||
2103 | /* This doesn't have any presence in the BAR */ | 2225 | /* This doesn't have any presence in the BAR */ |
2104 | init_cap(&pci->cfg_access.cap, sizeof(pci->cfg_access), | 2226 | init_cap(&pci->cfg_access.cap, sizeof(pci->cfg_access), |
2105 | VIRTIO_PCI_CAP_PCI_CFG, | 2227 | VIRTIO_PCI_CAP_PCI_CFG, |