diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-13 01:43:42 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2015-02-13 01:45:49 -0500 |
commit | c97eb679ef70dbb4482e66b9d192fc9e5bc6e0d6 (patch) | |
tree | 2b654642fd4920069e6c39ab3b4e513202e5af9e /tools | |
parent | 8dc425ffdd20b3462cfb43eb4f94a7ed8296dd63 (diff) |
tools/lguest: insert driver references from the 1.0 spec (4.1 Virtio Over PCI)
As a demonstration, the lguest launcher is pretty strict, trying to
catch badly behaved drivers. Document this precisely.
A good implementation would *NOT* crash the guest when these happened!
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/lguest/lguest.c | 59 |
1 files changed, 57 insertions, 2 deletions
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index 10a72b810127..80dc6346030e 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -1211,7 +1211,12 @@ static bool valid_bar_access(struct device *d, | |||
1211 | && cfg_access->cap.length != 4) | 1211 | && cfg_access->cap.length != 4) |
1212 | return false; | 1212 | return false; |
1213 | 1213 | ||
1214 | /* Offset must be multiple of length */ | 1214 | /* |
1215 | * 4.1.4.7.2: | ||
1216 | * | ||
1217 | * The driver MUST NOT write a cap.offset which is not a multiple of | ||
1218 | * cap.length (ie. all accesses MUST be aligned). | ||
1219 | */ | ||
1215 | if (cfg_access->cap.offset % cfg_access->cap.length != 0) | 1220 | if (cfg_access->cap.offset % cfg_access->cap.length != 0) |
1216 | return false; | 1221 | return false; |
1217 | 1222 | ||
@@ -1342,7 +1347,13 @@ static bool pci_data_iowrite(u16 port, u32 mask, u32 val) | |||
1342 | return true; | 1347 | return true; |
1343 | } | 1348 | } |
1344 | 1349 | ||
1345 | /* Complain about other writes. */ | 1350 | /* |
1351 | * 4.1.4.1: | ||
1352 | * | ||
1353 | * The driver MUST NOT write into any field of the capability | ||
1354 | * structure, with the exception of those with cap_type | ||
1355 | * VIRTIO_PCI_CAP_PCI_CFG... | ||
1356 | */ | ||
1346 | return false; | 1357 | return false; |
1347 | } | 1358 | } |
1348 | 1359 | ||
@@ -1789,6 +1800,12 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1789 | restore_vq_config(&d->mmio->cfg, vq); | 1800 | restore_vq_config(&d->mmio->cfg, vq); |
1790 | goto write_through16; | 1801 | goto write_through16; |
1791 | case offsetof(struct virtio_pci_mmio, cfg.queue_size): | 1802 | case offsetof(struct virtio_pci_mmio, cfg.queue_size): |
1803 | /* | ||
1804 | * 4.1.4.3.2: | ||
1805 | * | ||
1806 | * The driver MUST NOT write a value which is not a power of 2 | ||
1807 | * to queue_size. | ||
1808 | */ | ||
1792 | if (val & (val-1)) | 1809 | if (val & (val-1)) |
1793 | errx(1, "%s: invalid queue size %u\n", d->name, val); | 1810 | errx(1, "%s: invalid queue size %u\n", d->name, val); |
1794 | if (d->mmio->cfg.queue_enable) | 1811 | if (d->mmio->cfg.queue_enable) |
@@ -1799,11 +1816,22 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1799 | errx(1, "%s: attempt to set MSIX vector to %u", | 1816 | errx(1, "%s: attempt to set MSIX vector to %u", |
1800 | d->name, val); | 1817 | d->name, val); |
1801 | case offsetof(struct virtio_pci_mmio, cfg.queue_enable): | 1818 | case offsetof(struct virtio_pci_mmio, cfg.queue_enable): |
1819 | /* | ||
1820 | * 4.1.4.3.2: | ||
1821 | * | ||
1822 | * The driver MUST NOT write a 0 to queue_enable. | ||
1823 | */ | ||
1802 | if (val != 1) | 1824 | if (val != 1) |
1803 | errx(1, "%s: setting queue_enable to %u", d->name, val); | 1825 | errx(1, "%s: setting queue_enable to %u", d->name, val); |
1804 | d->mmio->cfg.queue_enable = val; | 1826 | d->mmio->cfg.queue_enable = val; |
1805 | save_vq_config(&d->mmio->cfg, | 1827 | save_vq_config(&d->mmio->cfg, |
1806 | vq_by_num(d, d->mmio->cfg.queue_select)); | 1828 | vq_by_num(d, d->mmio->cfg.queue_select)); |
1829 | /* | ||
1830 | * 4.1.4.3.2: | ||
1831 | * | ||
1832 | * The driver MUST configure the other virtqueue fields before | ||
1833 | * enabling the virtqueue with queue_enable. | ||
1834 | */ | ||
1807 | enable_virtqueue(d, vq_by_num(d, d->mmio->cfg.queue_select)); | 1835 | enable_virtqueue(d, vq_by_num(d, d->mmio->cfg.queue_select)); |
1808 | goto write_through16; | 1836 | goto write_through16; |
1809 | case offsetof(struct virtio_pci_mmio, cfg.queue_notify_off): | 1837 | case offsetof(struct virtio_pci_mmio, cfg.queue_notify_off): |
@@ -1814,6 +1842,12 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1814 | case offsetof(struct virtio_pci_mmio, cfg.queue_avail_hi): | 1842 | case offsetof(struct virtio_pci_mmio, cfg.queue_avail_hi): |
1815 | case offsetof(struct virtio_pci_mmio, cfg.queue_used_lo): | 1843 | case offsetof(struct virtio_pci_mmio, cfg.queue_used_lo): |
1816 | case offsetof(struct virtio_pci_mmio, cfg.queue_used_hi): | 1844 | case offsetof(struct virtio_pci_mmio, cfg.queue_used_hi): |
1845 | /* | ||
1846 | * 4.1.4.3.2: | ||
1847 | * | ||
1848 | * The driver MUST configure the other virtqueue fields before | ||
1849 | * enabling the virtqueue with queue_enable. | ||
1850 | */ | ||
1817 | if (d->mmio->cfg.queue_enable) | 1851 | if (d->mmio->cfg.queue_enable) |
1818 | errx(1, "%s: changing queue on live device", | 1852 | errx(1, "%s: changing queue on live device", |
1819 | d->name); | 1853 | d->name); |
@@ -1837,9 +1871,23 @@ static void emulate_mmio_write(struct device *d, u32 off, u32 val, u32 mask) | |||
1837 | } | 1871 | } |
1838 | /* Fall through... */ | 1872 | /* Fall through... */ |
1839 | default: | 1873 | default: |
1874 | /* | ||
1875 | * 4.1.4.3.2: | ||
1876 | * | ||
1877 | * The driver MUST NOT write to device_feature, num_queues, | ||
1878 | * config_generation or queue_notify_off. | ||
1879 | */ | ||
1840 | errx(1, "%s: Unexpected write to offset %u", d->name, off); | 1880 | errx(1, "%s: Unexpected write to offset %u", d->name, off); |
1841 | } | 1881 | } |
1842 | 1882 | ||
1883 | |||
1884 | /* | ||
1885 | * 4.1.3.1: | ||
1886 | * | ||
1887 | * The driver MUST access each field using the “natural” access | ||
1888 | * method, i.e. 32-bit accesses for 32-bit fields, 16-bit accesses for | ||
1889 | * 16-bit fields and 8-bit accesses for 8-bit fields. | ||
1890 | */ | ||
1843 | write_through32: | 1891 | write_through32: |
1844 | if (mask != 0xFFFFFFFF) { | 1892 | if (mask != 0xFFFFFFFF) { |
1845 | errx(1, "%s: non-32-bit write to offset %u (%#x)", | 1893 | errx(1, "%s: non-32-bit write to offset %u (%#x)", |
@@ -1923,6 +1971,13 @@ static u32 emulate_mmio_read(struct device *d, u32 off, u32 mask) | |||
1923 | goto read_through8; | 1971 | goto read_through8; |
1924 | } | 1972 | } |
1925 | 1973 | ||
1974 | /* | ||
1975 | * 4.1.3.1: | ||
1976 | * | ||
1977 | * The driver MUST access each field using the “natural” access | ||
1978 | * method, i.e. 32-bit accesses for 32-bit fields, 16-bit accesses for | ||
1979 | * 16-bit fields and 8-bit accesses for 8-bit fields. | ||
1980 | */ | ||
1926 | read_through32: | 1981 | read_through32: |
1927 | if (mask != 0xFFFFFFFF) | 1982 | if (mask != 0xFFFFFFFF) |
1928 | errx(1, "%s: non-32-bit read to offset %u (%#x)", | 1983 | errx(1, "%s: non-32-bit read to offset %u (%#x)", |