tests/linux: use Akaros's CFLAGS
[akaros.git] / user / vmm / virtio_mmio.c
1 /* Virtio MMIO bindings
2  *
3  * Copyright (c) 2011 Linaro Limited
4  * Copyright (C) 1991-2016, the Linux Kernel authors
5  * Copyright (c) 2016 Google Inc.
6  *
7  * Author:
8  *  Peter Maydell <peter.maydell@linaro.org>
9  *  Rusty Russell <rusty@rustcorp.com.au>
10  *  Michael Taufen <mtaufen@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License as
14  * published by the Free Software Foundation; either version 2 of
15  * the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * Akaros's virtio_mmio (this file) is inspired by QEMU's virtio-mmio.c
23  * and Linux's lguest.c.  Both of QEMU's virtio-mmio.c and Linux's
24  * lguest.c are released under the GNU General Public License version 2
25  * or later.  Their original files were heavily modified for Akaros.
26  *
27  * Original linux/tools/lguest/lguest.c:
28  *   https://github.com/torvalds/linux/blob/v4.5/tools/lguest/lguest.c
29  *   most recent hash on the file as of v4.5 tag:
30  *     e523caa601f4a7c2fa1ecd040db921baf7453798
31  *
32  * Original virtio-mmio.c:
33  *   https://github.com/qemu/qemu/blob/v2.5.0/hw/virtio/virtio-mmio.c
34  *   most recent hash on the file as of v2.5.0 tag:
35  *     ab223c9518e8c7eb542ef3133de1a34475b69790
36  *
37  * TODO: This needs major refactoring/reformatting.
38  */
39
40 #include <parlib/stdio.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <sys/eventfd.h>
44 #include <vmm/virtio_config.h>
45 #include <vmm/virtio_mmio.h>
46
47 #define VIRT_MAGIC 0x74726976 /* 'virt' */
48
49 #define VIRT_MMIO_VERSION 0x2
50
51 #define VIRT_MMIO_VENDOR 0x52414B41 /* 'AKAR' */
52
53 void virtio_mmio_set_vring_irq(struct virtio_mmio_dev *mmio_dev)
54 {
55         mmio_dev->isr |= VIRTIO_MMIO_INT_VRING;
56 }
57
58 void virtio_mmio_set_cfg_irq(struct virtio_mmio_dev *mmio_dev)
59 {
60         mmio_dev->isr |= VIRTIO_MMIO_INT_CONFIG;
61 }
62
63 static void virtio_mmio_reset_cfg(struct virtio_mmio_dev *mmio_dev)
64 {
65         if (!mmio_dev->vqdev->cfg || mmio_dev->vqdev->cfg_sz == 0)
66                 VIRTIO_DEV_WARNX(mmio_dev->vqdev,
67                         "Attempt to reset the device-specific configuration space, but the device does not provide it. Generally, this region is required, so you should probably do something about that.");
68
69         // If a default device-specific configuration is provided, copy that
70         // into the device-specific configuration space. Otherwise, clear the
71         // device-specific configuration space.
72         if (mmio_dev->vqdev->cfg_d)
73                 memcpy(mmio_dev->vqdev->cfg, mmio_dev->vqdev->cfg_d,
74                            mmio_dev->vqdev->cfg_sz);
75         else
76                 memset(mmio_dev->vqdev->cfg, 0x0, mmio_dev->vqdev->cfg_sz);
77
78         // Increment the ConfigGeneration, since the config space just got
79         // reset.  We can't simply set it to 0, because we must ensure that it
80         // changes when the config space changes and it might currently be set
81         // to 0.
82         mmio_dev->cfg_gen++;
83 }
84
85 // TODO: virtio_mmio_reset could use a careful audit. We have not yet
86 //       encountered a scenario where the driver resets the device
87 //       while lots of things are in-flight; thus far we have only seen
88 //       device resets prior to the first initialization sequence.
89 static void virtio_mmio_reset(struct virtio_mmio_dev *mmio_dev)
90 {
91         int i;
92
93         if (!mmio_dev->vqdev)
94                 return;
95
96         // Clear any driver-activated feature bits
97         mmio_dev->vqdev->dri_feat = 0;
98
99         // virtio-v1.0-cs04 s2.1.2 Device Status Field
100         // The device MUST initialize device status to 0 upon reset
101         mmio_dev->status = 0;
102
103         // virtio-v1.0-cs04 s4.2.2.1 MMIO Device Register Layout
104         // Upon reset, the device MUST clear all bits in InterruptStatus
105         mmio_dev->isr = 0;
106
107         // virtio-v1.0-cs04 s4.2.2.1 MMIO Device Register Layout
108         // Upon reset, the device MUST clear...ready bits in the QueueReady
109         // register for all queues in the device.
110         for (i = 0; i < mmio_dev->vqdev->num_vqs; ++i) {
111                 if (mmio_dev->vqdev->vqs[i].srv_th) {
112                 // FIXME! PLEASE, FIXME!
113                 // TODO: For now we are going to make device resets an error
114                 // once service threads exist on the queues. This is obviously
115                 // not sustainable, because the driver needs to be able to reset
116                 // the device after certain errors occur.
117                 //
118                 //       In the future, when we actually decide how we want
119                 //       to clean up the threads, the sequence might look
120                 //       something like this:
121                 //       1. Ask the queue's service thread to exit and wait
122                 //          for it to finish and exit.
123                 //       2. Once it has exited, close the queue's eventfd
124                 //          and set both the eventfd and srv_th fields to 0.
125                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
126                                 "The driver reset the device after queue service threads had started running. This is NOT a restriction imposed by virtio! We just haven't implemented something that will kill service threads yet.");
127                 }
128
129                 mmio_dev->vqdev->vqs[i].qready = 0;
130                 mmio_dev->vqdev->vqs[i].last_avail = 0;
131         }
132
133         virtio_mmio_reset_cfg(mmio_dev);
134 }
135
136 uint32_t virtio_mmio_rd(struct virtual_machine *unused_vm,
137                         struct virtio_mmio_dev *mmio_dev,
138                         uint64_t gpa, uint8_t size)
139 {
140         uint64_t offset = gpa - mmio_dev->addr;
141         uint8_t *target; // target of read from device-specific config space
142         const char *err; // returned err strings
143
144         // Return 0 for all registers except the magic number,
145         // the mmio version, and the device vendor when either
146         // there is no vqdev or no vqs on the vqdev.
147         if (!mmio_dev->vqdev || mmio_dev->vqdev->num_vqs == 0) {
148                 switch (offset) {
149                 case VIRTIO_MMIO_MAGIC_VALUE:
150                         return VIRT_MAGIC;
151                 case VIRTIO_MMIO_VERSION:
152                         return VIRT_MMIO_VERSION;
153                 case VIRTIO_MMIO_VENDOR_ID:
154                         return VIRT_MMIO_VENDOR;
155                 default:
156                         return 0;
157                 }
158         }
159
160         // virtio-v1.0-cs04 s4.2.3.1.1 Device Initialization (MMIO section)
161         if (mmio_dev->vqdev->dev_id == 0
162                 && offset != VIRTIO_MMIO_MAGIC_VALUE
163                 && offset != VIRTIO_MMIO_VERSION
164                 && offset != VIRTIO_MMIO_DEVICE_ID)
165                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
166                         "Attempt to read from a register not MagicValue, Version, or DeviceID on a device whose DeviceID is 0x0\n"
167                         "  See virtio-v1.0-cs04 s4.2.3.1.1 Device Initialization");
168
169         // Now we know that the host provided a vqdev. As soon as the driver
170         // tries to read the magic number, we know it's considering the device.
171         // This is a great time to validate the features the host is providing.
172         // The host must provide a valid combination of features, or we crash
173         // here until the offered feature combination is made valid.
174         if (offset == VIRTIO_MMIO_MAGIC_VALUE) {
175                 // NOTE: If you ever decide to change this to a warning instead
176                 // of an error, you might want to return an invalid magic value
177                 // here to tell the driver that it is poking at a bad device.
178                 err = virtio_validate_feat(mmio_dev->vqdev,
179                                            mmio_dev->vqdev->dev_feat);
180                 if (err)
181                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
182                                 "The feature combination offered by the device is not valid. This must be fixed before the device can be used.\n"
183                                 "  Validation Error: %s", err);
184         }
185
186
187         // Warn if FAILED status bit is set.
188         // virtio-v1.0-cs04 s2.1.1 Device Status Field
189         if (mmio_dev->status & VIRTIO_CONFIG_S_FAILED)
190                 VIRTIO_DRI_WARNX(mmio_dev->vqdev,
191                         "The FAILED status bit is set. The driver should probably reset the device before continuing.\n"
192                         "  See virtio-v1.0-cs04 s2.1.1 Device Status Field");
193
194         // TODO: I could only do a limited amount of testing on the device-
195         //       specific config space, because I was limited to seeing what
196         //       the guest driver for the console device would do. You may
197         //       run into issues when you implement virtio-net, since that
198         //       does more with the device-specific config.
199         if (offset >= VIRTIO_MMIO_CONFIG) {
200                 offset -= VIRTIO_MMIO_CONFIG;
201
202                 if (!mmio_dev->vqdev->cfg || mmio_dev->vqdev->cfg_sz == 0) {
203                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
204                                 "Driver attempted to read the device-specific configuration space, but the device failed to provide it.");
205                 }
206
207                 // virtio-v1.0-cs04 s3.1.1 Device Initialization
208                 if (!(mmio_dev->status & VIRTIO_CONFIG_S_DRIVER)) {
209                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
210                                 "Driver attempted to read the device-specific configuration space before setting the DRIVER status bit.\n"
211                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
212                 }
213
214                 if ((offset + size) > mmio_dev->vqdev->cfg_sz
215                         || (offset + size) < offset) {
216                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
217                                 "Attempt to read invalid offset of the device specific  configuration space, or (offset + read width) wrapped around.");
218                 }
219
220                 target = (uint8_t*)((uint64_t)mmio_dev->vqdev->cfg + offset);
221
222                 // TODO: Check that size matches the size of the field at offset
223                 //       for the given device? i.e. virtio_console_config.rows
224                 //       should only be accessible via a 16 bit read or write.
225                 //       I haven't done this yet, it will be a significant
226                 //       undertaking and maintenance commitment, because you
227                 //       will have to do it for every virtio device you
228                 //       want to use in the future.
229                 switch (size) {
230                 case 1:
231                         return *((uint8_t*)target);
232                 case 2:
233                         if ((uint64_t)target % 2 != 0)
234                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
235                                         "The driver must use 16 bit aligned reads for reading from 16 bit values in the device-specific configuration space.\n"
236                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
237                         return *((uint16_t*)target);
238                 case 4:
239                         if ((uint64_t)target % 4 != 0)
240                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
241                                         "The driver must use 32 bit aligned reads for reading from 32 or 64 bit values in the device-specific configuration space.\n"
242                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
243                         return *((uint32_t*)target);
244                 default:
245                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
246                                 "The driver must use 8, 16, or 32 bit wide and aligned reads for reading from the device-specific configuration space.\n"
247                                 "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
248                 }
249         }
250
251         // virtio-v1.0-cs04 4.2.2.2 MMIO Device Register Layout
252         if (size != 4 || (offset % 4) != 0) {
253                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
254                         "The driver must only use 32 bit wide and aligned reads for reading the control registers on the MMIO transport.\n"
255                         "  See virtio-v1.0-cs04 4.2.2.2 MMIO Device Register Layout");
256         }
257
258         // virtio-v1.0-cs04 Table 4.1
259         switch (offset) {
260         // Magic value
261         // 0x74726976 (a Little Endian equivalent of the “virt” string).
262         case VIRTIO_MMIO_MAGIC_VALUE:
263                 return VIRT_MAGIC;
264
265         // Device version number
266         // 0x2. Note: Legacy devices (see 4.2.4 Legacy interface) used 0x1.
267         case VIRTIO_MMIO_VERSION:
268                 return VIRT_MMIO_VERSION;
269
270         // Virtio Subsystem Device ID (see virtio-v1.0-cs04 sec. 5 for values)
271         // Value 0x0 is used to define a system memory map with placeholder
272         // devices at static, well known addresses.
273         case VIRTIO_MMIO_DEVICE_ID:
274                 return mmio_dev->vqdev->dev_id;
275
276         // Virtio Subsystem Vendor ID
277         case VIRTIO_MMIO_VENDOR_ID:
278                 return VIRT_MMIO_VENDOR;
279
280         // Flags representing features the device supports
281         case VIRTIO_MMIO_DEVICE_FEATURES:
282                 if (!(mmio_dev->status & VIRTIO_CONFIG_S_DRIVER))
283                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
284                                  "Attempt to read device features before setting the DRIVER status bit.\n"
285                                  "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
286
287                 // high 32 bits requested
288                 if (mmio_dev->dev_feat_sel)
289                         return mmio_dev->vqdev->dev_feat >> 32;
290                 return mmio_dev->vqdev->dev_feat; // low 32 bits requested
291
292         // Maximum virtual queue size
293         // Returns the maximum size (number of elements) of the queue the device
294         // is ready to process or zero (0x0) if the queue is not available.
295         // Applies to the queue selected by writing to QueueSel.
296         case VIRTIO_MMIO_QUEUE_NUM_MAX:
297         // TODO: Are there other cases that count as "queue not available"?
298         // NOTE: !qready does not count as "queue not available".
299                 if (mmio_dev->qsel >= mmio_dev->vqdev->num_vqs)
300                         return 0;
301                 return mmio_dev->vqdev->vqs[mmio_dev->qsel].qnum_max;
302
303         // Virtual queue ready bit
304         // Applies to the queue selected by writing to QueueSel.
305         case VIRTIO_MMIO_QUEUE_READY:
306                 if (mmio_dev->qsel >= mmio_dev->vqdev->num_vqs)
307                         return 0;
308                 return mmio_dev->vqdev->vqs[mmio_dev->qsel].qready;
309
310         // Interrupt status
311         // Bit mask of events that caused the device interrupt to be asserted.
312         // bit 0: Used Ring Update
313         // bit 1: Configuration Change
314         case VIRTIO_MMIO_INTERRUPT_STATUS:
315                 return mmio_dev->isr;
316
317         // Device status
318         case VIRTIO_MMIO_STATUS:
319                 return mmio_dev->status;
320
321         // Configuration atomicity value
322         // Contains a version for the device-specific configuration space
323         // The driver checks this version before and after accessing the config
324         // space, and if the values don't match it repeats the access.
325         case VIRTIO_MMIO_CONFIG_GENERATION:
326                 return mmio_dev->cfg_gen;
327
328         // Write-only register offsets:
329         case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
330         case VIRTIO_MMIO_DRIVER_FEATURES:
331         case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
332         case VIRTIO_MMIO_QUEUE_SEL:
333         case VIRTIO_MMIO_QUEUE_NUM:
334         case VIRTIO_MMIO_QUEUE_NOTIFY:
335         case VIRTIO_MMIO_INTERRUPT_ACK:
336         case VIRTIO_MMIO_QUEUE_DESC_LOW:
337         case VIRTIO_MMIO_QUEUE_DESC_HIGH:
338         case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
339         case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
340         case VIRTIO_MMIO_QUEUE_USED_LOW:
341         case VIRTIO_MMIO_QUEUE_USED_HIGH:
342                 // Read of write-only register
343                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
344                         "Attempt to read write-only device register offset 0x%x.",
345                         offset);
346                 return 0;
347         default:
348                 // Bad register offset
349                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
350                         "Attempt to read invalid device register offset 0x%x.",
351                         offset);
352                 return 0;
353         }
354
355         return 0;
356 }
357
358 void virtio_mmio_wr(struct virtual_machine *vm,
359                     struct virtio_mmio_dev *mmio_dev, uint64_t gpa,
360                     uint8_t size, uint32_t *value)
361 {
362         uint64_t offset = gpa - mmio_dev->addr;
363         struct virtio_vq *notified_queue;
364         uint8_t *target; // target of write to device-specific config space
365         void *temp_ptr; // for facilitating bitwise ops on pointers
366         const char *err; // returned err strings
367
368         if (!mmio_dev->vqdev) {
369                 // If there is no vqdev on the mmio_dev,
370                 // we just make all registers write-ignored.
371                 return;
372         }
373
374         // virtio-v1.0-cs04 s4.2.3.1.1 Device Initialization (MMIO)
375         if (mmio_dev->vqdev->dev_id == 0)
376                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
377                         "Attempt to write to a device whose DeviceID is 0x0.\n"
378                         "  See virtio-v1.0-cs04 s4.2.3.1.1 Device Initialization");
379
380         // Warn if FAILED and trying to do something that is definitely not a
381         // reset.  virtio-v1.0-cs04 s2.1.1 Device Status Field
382         if (offset != VIRTIO_MMIO_STATUS
383                 && (mmio_dev->status & VIRTIO_CONFIG_S_FAILED))
384                 VIRTIO_DRI_WARNX(mmio_dev->vqdev,
385                         "The FAILED status bit is set. The driver should probably reset the device before continuing.\n"
386                         "  See virtio-v1.0-cs04 s2.1.1 Device Status Field");
387
388         // TODO: I could only do a limited amount of testing on the device-
389         //       specific config space, because I was limited to seeing what
390         //       the guest driver for the console device would do. You may
391         //       run into issues when you implement virtio-net, since that
392         //       does more with the device-specific config. (In fact, I don't
393         //       think the guest driver ever even tried to write the
394         //       device-specific config space for the console, so this section
395         //       is entirely untested)
396         if (offset >= VIRTIO_MMIO_CONFIG) {
397                 offset -= VIRTIO_MMIO_CONFIG;
398
399                 if (!mmio_dev->vqdev->cfg || mmio_dev->vqdev->cfg_sz == 0) {
400                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
401                                 "Driver attempted to write to the device-specific configuration space, but the device failed to provide it.");
402                 }
403
404                 // virtio-v1.0-cs04 s3.1.1 Device Initialization
405                 if (!(mmio_dev->status & VIRTIO_CONFIG_S_FEATURES_OK)) {
406                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
407                                 "Driver attempted to write the device-specific configuration space before setting the FEATURES_OK status bit.\n"
408                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
409                 }
410
411                 if ((offset + size) > mmio_dev->vqdev->cfg_sz
412                         || (offset + size) < offset) {
413                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
414                                 "Attempt to write invalid offset of the device specific configuration space, or (offset + write width) wrapped around.");
415                 }
416
417                 target = (uint8_t*)((uint64_t)mmio_dev->vqdev->cfg + offset);
418
419                 // TODO: Check that size matches the size of the field at offset
420                 //       for the given device? i.e. virtio_console_config.rows
421                 //       should only be accessible via a 16 bit read or write.
422                 //       I haven't done this yet, it will be a significant
423                 //       undertaking and maintenance commitment, because you
424                 //       will have to do it for every virtio device you
425                 //       want to use in the future.
426                 switch (size) {
427                 case 1:
428                         *((uint8_t*)target) = *((uint8_t*)value);
429                         break;
430                 case 2:
431                         if ((uint64_t)target % 2 != 0)
432                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
433                                         "The driver must use 16 bit aligned writes for writing to 16 bit values in the device-specific configuration space.\n"
434                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
435                         *((uint16_t*)target) = *((uint16_t*)value);
436                         break;
437                 case 4:
438                         if ((uint64_t)target % 4 != 0)
439                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
440                                         "The driver must use 32 bit aligned writes for writing to 32 or 64 bit values in the device-specific configuration space.\n"
441                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
442                         *((uint32_t*)target) = *((uint32_t*)value);
443                         break;
444                 default:
445                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
446                                 "The driver must use 8, 16, or 32 bit wide and aligned writes for writing to the device-specific configuration space.\n"
447                                 "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout");
448                 }
449
450                 // Increment cfg_gen because the device-specific config changed
451                 mmio_dev->cfg_gen++;
452
453                 // Notify the driver that the device-specific config changed
454                 virtio_mmio_set_cfg_irq(mmio_dev);
455                 if (mmio_dev->poke_guest)
456                         mmio_dev->poke_guest(mmio_dev->vec, mmio_dev->dest);
457
458                 return;
459         }
460
461         // virtio-v1.0-cs04 4.2.2.2 MMIO Device Register Layout
462         if (size != 4 || (offset % 4) != 0) {
463                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
464                         "The driver must only use 32 bit wide and aligned writes for writing the control registers on the MMIO transport.\n"
465                         "  See virtio-v1.0-cs04 4.2.2.2 MMIO Device Register Layout");
466         }
467
468         // virtio-v1.0-cs04 Table 4.1
469         switch (offset) {
470
471         // Device (host) features word selection.
472         case VIRTIO_MMIO_DEVICE_FEATURES_SEL:
473                 mmio_dev->dev_feat_sel = *value;
474                 break;
475
476         // Device feature flags activated by the driver
477         case VIRTIO_MMIO_DRIVER_FEATURES:
478                 // virtio-v1.0-cs04 s3.1.1 Device Initialization
479                 if (mmio_dev->status & VIRTIO_CONFIG_S_FEATURES_OK) {
480                         // NOTE: The spec just says the driver isn't allowed to
481                         // accept NEW feature bits after setting FEATURES_OK.
482                         // Although the language makes it seem like it might be
483                         // fine to let the driver un-accept features after it
484                         // sets FEATURES_OK, this would require very careful
485                         // handling, so for now we just don't allow the driver
486                         // to write to the DriverFeatures register after
487                         // FEATURES_OK is set.
488                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
489                                 "The driver may not accept (i.e. activate) new feature bits  offered by the device after setting FEATURES_OK.\n"
490                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
491                 } else if (mmio_dev->dri_feat_sel) {
492                         // clear high 32 bits
493                         mmio_dev->vqdev->dri_feat &= 0xffffffff;
494                         // write high 32 bits
495                         mmio_dev->vqdev->dri_feat |= ((uint64_t)(*value) << 32);
496                 } else {
497                         // clear low 32 bits
498                         mmio_dev->vqdev->dri_feat &= ((uint64_t)0xffffffff <<
499                                                       32);
500                         // write low 32 bits
501                         mmio_dev->vqdev->dri_feat |= *value;
502                 }
503                 break;
504
505         // Activated (guest) features word selection
506         case VIRTIO_MMIO_DRIVER_FEATURES_SEL:
507                 mmio_dev->dri_feat_sel = *value;
508                 break;
509
510         // Virtual queue index
511         // Selects the virtual queue that QueueNumMax, QueueNum, QueueReady,
512         // QueueDescLow, QueueDescHigh, QueueAvailLow, QueueAvailHigh,
513         // QueueUsedLow and QueueUsedHigh apply to. The index number of the
514         // first queue is zero (0x0).
515         case VIRTIO_MMIO_QUEUE_SEL:
516         // NOTE: We must allow the driver to write whatever they want to
517         //       QueueSel, because QueueNumMax contians 0x0 for invalid
518         //       QueueSel indices.
519                 mmio_dev->qsel = *value;
520                 break;
521
522         // Virtual queue size
523         // The queue size is the number of elements in the queue, thus in the
524         // Descriptor Table, the Available Ring and the Used Ring. Writes
525         // notify the device what size queue the driver will use.
526         // This applies to the queue selected by writing to QueueSel.
527         case VIRTIO_MMIO_QUEUE_NUM:
528                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
529                         // virtio-v1.0-cs04 4.2.2.2 MMIO Device Register Layout
530                         if (*value <=
531                             mmio_dev->vqdev->vqs[mmio_dev->qsel].qnum_max)
532                                 mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.num =
533                                         *value;
534                         else if ((*value != 0) && (*value & ((*value) - 1)))
535                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
536                                         "The driver may only write powers of 2 to the QueueNum register.\n"
537                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
538                         else
539                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
540                                         "Attempt to write value greater than QueueNumMax to QueueNum register.");
541                 } else {
542                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
543                                 "Attempt to write QueueNum register for invalid QueueSel. QueueSel was %u, but the number of queues is %u.",
544                                 mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
545                 }
546                 break;
547
548         // Virtual queue ready bit
549         // Writing one (0x1) to this register notifies the device that it can
550         // execute requests from the virtual queue selected by QueueSel.
551         case VIRTIO_MMIO_QUEUE_READY:
552                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
553                         // NOTE: For now, anything that is not a toggle between
554                         // 0x1 and 0x0 will bounce with no effect whatsoever.
555                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready == 0x0
556                                 && *value == 0x1) {
557                                 // Driver is trying to write 0x1 QueueReady when
558                                 // the queue is currently disabled (QueueReady
559                                 // is 0x0). We validate the vring the driver
560                                 // provided, set up an eventfd for the queue,
561                                 // set qready on the queue to 0x1, and then
562                                 // launch the service thread for the queue.
563
564                                 // Check that the host actually provided a
565                                 // service function
566                                 if (!mmio_dev->vqdev->vqs[mmio_dev->qsel].srv_fn) {
567                                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
568                                                 "The host must provide a service function for each queue on the device before the driver writes 0x1 to QueueReady. No service function found for queue %u."
569                                                 , mmio_dev->qsel);
570                                 }
571
572                                 virtio_check_vring(
573                                         &mmio_dev->vqdev->vqs[mmio_dev->qsel]);
574
575                                 mmio_dev->vqdev->vqs[mmio_dev->qsel].eventfd =
576                                         eventfd(0, 0);
577                                 mmio_dev->vqdev->vqs[mmio_dev->qsel].qready =
578                                         0x1;
579
580                                 mmio_dev->vqdev->vqs[mmio_dev->qsel].srv_th =
581                                                 vmm_run_task(vm,
582                                                                 mmio_dev->vqdev->vqs[mmio_dev->qsel].srv_fn,
583                                                                 &mmio_dev->vqdev->vqs[mmio_dev->qsel]);
584                                 if (!mmio_dev->vqdev->vqs[mmio_dev->qsel].srv_th) {
585                                         VIRTIO_DEV_ERRX(mmio_dev->vqdev,
586                                                 "vm_run_task failed when trying to start service thread after driver wrote 0x1 to QueueReady.");
587                                 }
588                         } else if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready == 0x1
589                                        && *value == 0x0) {
590                                 // Driver is trying to revoke QueueReady while
591                                 // the queue is currently enabled (QueueReady is
592                                 // 0x1).
593                                 // TODO: For now we are going to just make this
594                                 // an error.  In the future, when we actually
595                                 // decide how we want to clean up the threads,
596                                 // the sequence might look something like this:
597                                 //       1. Ask the queue's service thread to
598                                 //       exit and wait for it to finish and
599                                 //       exit.
600                                 //       2. Once it has exited, close the
601                                 //       queue's eventfd and set both the
602                                 //       eventfd and srv_th fields to 0.
603                                 //       3. Finally, write 0x0 to QueueReady.
604                                 VIRTIO_DEV_ERRX(mmio_dev->vqdev,
605                                         "Our (Akaros) MMIO device does not currently allow the driver to revoke QueueReady (i.e. change QueueReady from 0x1 to 0x0). The driver tried to revoke it, so whatever you are doing might require this ability.");
606                         }
607
608                 } else {
609                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
610                                 "Attempt to write QueueReady register for invalid QueueSel. QueueSel was %u, but the number of queues is %u.",
611                                 mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
612                 }
613                 break;
614
615         // Queue notifier
616         // Writing a queue index to this register notifies the device that
617         // there are new buffers to process in that queue.
618         case VIRTIO_MMIO_QUEUE_NOTIFY:
619                 if (!(mmio_dev->status & VIRTIO_CONFIG_S_DRIVER_OK))
620                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
621                                 "Attempt to notify the device before setting the DRIVER_OK status bit.\n"
622                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
623                 else if (*value < mmio_dev->vqdev->num_vqs) {
624                         notified_queue = &mmio_dev->vqdev->vqs[*value];
625
626                         // kick the queue's service thread
627                         if (notified_queue->eventfd > 0)
628                                 eventfd_write(notified_queue->eventfd, 1);
629                         else
630                                 VIRTIO_DEV_ERRX(mmio_dev->vqdev,
631                                         "You need to provide a valid eventfd on your virtio_vq so that it can be kicked when the driver writes to QueueNotify.");
632                 }
633                 break;
634
635         // Interrupt acknowledge
636         // Writing a value with bits set as defined in InterruptStatus to this
637         // register notifies the device that events causing the interrupt have
638         // been handled.
639         case VIRTIO_MMIO_INTERRUPT_ACK:
640                 if (*value & ~0x3)
641                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
642                                 "Attempt to set undefined bits in InterruptACK register.\n"
643                                 "  See virtio-v1.0-cs04 s4.2.2.1 MMIO Device Register Layout");
644                 mmio_dev->isr &= ~(*value);
645                 break;
646
647         // Device status
648         // Writing non-zero values to this register sets the status flags.
649         // Writing zero (0x0) to this register triggers a device reset.
650         case VIRTIO_MMIO_STATUS:
651                 if (*value == 0)
652                         virtio_mmio_reset(mmio_dev);
653                 else if (mmio_dev->status & ~(*value)) {
654                         // virtio-v1.0-cs04 s2.1.1. driver must NOT clear a
655                         // status bit
656                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
657                                 "The driver must not clear any device status bits, except as a result of resetting the device.\n"
658                                 "  See virtio-v1.0-cs04 s2.1.1 Device Status Field");
659                 } else if (mmio_dev->status & VIRTIO_CONFIG_S_FAILED
660                         &&   mmio_dev->status != *value) {
661                         // virtio-v1.0-cs04 s2.1.1. MUST reset before re-init if
662                         // FAILED
663                         // NOTE: This fails if the driver tries to *change* the
664                         // status after the FAILED bit is set. The driver can
665                         // set the same status again all it wants.
666                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
667                                 "The driver must reset the device after setting the FAILED status bit, before attempting to re-initialize the device.\n"
668                                 "  See virtio-v1.0-cs04 s2.1.1 Device Status Field");
669                 }
670
671                 // NOTE: If a bit is not set in value, then at this point it
672                 //       CANNOT be set in status either, because if it were
673                 //       set in status, we would have just crashed with an
674                 //       error due to the attempt to clear a status bit.
675
676                 // Now we check that status bits are set in the correct
677                 // sequence during device initialization as described
678                 // in virtio-v1.0-cs04 s3.1.1 Device Initialization
679
680                 else if ((*value & VIRTIO_CONFIG_S_DRIVER)
681                           && !(*value & VIRTIO_CONFIG_S_ACKNOWLEDGE)) {
682                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
683                                 "Tried to set DRIVER status bit before setting ACKNOWLEDGE feature bit.\n"
684                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
685                 } else if ((*value & VIRTIO_CONFIG_S_FEATURES_OK)
686                          && !((*value & VIRTIO_CONFIG_S_ACKNOWLEDGE)
687                                    && (*value & VIRTIO_CONFIG_S_DRIVER))) {
688                         // All those parentheses... Lisp must be making a
689                         // comeback.
690                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
691                                 "Tried to set FEATURES_OK status bit before setting both ACKNOWLEDGE and DRIVER status bits.\n"
692                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
693                 } else if ((*value & VIRTIO_CONFIG_S_DRIVER_OK)
694                          && !((*value & VIRTIO_CONFIG_S_ACKNOWLEDGE)
695                                    && (*value & VIRTIO_CONFIG_S_DRIVER)
696                                    && (*value & VIRTIO_CONFIG_S_FEATURES_OK))) {
697                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
698                                 "Tried to set DRIVER_OK status bit before setting all of ACKNOWLEDGE, DRIVER, and FEATURES_OK status bits.\n"
699                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
700                 }
701
702                 // NOTE: For now, we allow the driver to set all status bits up
703                 //       through FEATURES_OK in one fell swoop. The driver is,
704                 //       however, required to re-read FEATURES_OK after setting
705                 //       it to be sure that the driver-activated features are a
706                 //       subset of those supported by the device, so it must
707                 //       make an additional write to set DRIVER_OK.
708
709                 else if ((*value & VIRTIO_CONFIG_S_DRIVER_OK)
710                          && !(mmio_dev->status & VIRTIO_CONFIG_S_FEATURES_OK)) {
711                         VIRTIO_DRI_ERRX(mmio_dev->vqdev,
712                                 "The driver may not set FEATURES_OK and DRIVER_OK status bits simultaneously. It must read back FEATURES_OK after setting it to ensure that its activated features are supported by the device before setting DRIVER_OK.\n"
713                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
714                 } else {
715                         // NOTE: Don't set the FEATURES_OK bit unless the driver
716                         //       activated a valid subset of the supported
717                         //       features prior to attempting to set
718                         //       FEATURES_OK.
719                         if (!(mmio_dev->status & VIRTIO_CONFIG_S_FEATURES_OK)
720                             && (*value & VIRTIO_CONFIG_S_FEATURES_OK)) {
721
722                                 err = virtio_validate_feat(mmio_dev->vqdev,
723                                                   mmio_dev->vqdev->dri_feat);
724
725                                 if ((mmio_dev->vqdev->dri_feat
726                                         & ~mmio_dev->vqdev->dev_feat)) {
727                                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
728                                                 "The driver did not accept (e.g. activate) a subset of the features offered by the device prior to attempting to set the FEATURES_OK status bit. The bit will remain unset.\n"
729                                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization");
730                                         *value &= ~VIRTIO_CONFIG_S_FEATURES_OK;
731                                 } else if (err) {
732                                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
733                                                 "The driver did not accept (e.g. activate) a valid combination of the features offered by the device prior to attempting to set the FEATURES_OK status bit. The bit will remain unset.\n"
734                                                 "  See virtio-v1.0-cs04 s3.1.1 Device Initialization\n"
735                                                 "  Validation Error: %s", err);
736                                         *value &= ~VIRTIO_CONFIG_S_FEATURES_OK;
737                                 }
738                         }
739                         // Device status is only a byte wide.
740                         mmio_dev->status = *value & 0xff;
741                 }
742                 break;
743
744         // Queue's Descriptor Table 64 bit long physical address, low 32
745         case VIRTIO_MMIO_QUEUE_DESC_LOW:
746                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
747                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
748                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
749                                         "Attempt to access QueueDescLow on queue %d, which has nonzero QueueReady.\n"
750                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
751                                         , mmio_dev->qsel);
752
753                         // clear low bits
754                         temp_ptr = (void *)
755                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.desc
756                           & ((uint64_t)0xffffffff << 32));
757                         // write low bits
758                         temp_ptr = (void *) ((uint64_t)temp_ptr | *value);
759
760                         // virtio-v1.0-cs04 s2.4 Virtqueues
761                         if ((uint64_t)temp_ptr % 16)
762                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
763                                         "Physical address of guest's descriptor table (%p) is misaligned. Address should be a multiple of 16.\n"
764                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
765
766                         // assign the new value to the queue desc
767                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.desc =
768                                 temp_ptr;
769                 } else {
770                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
771                                 "Attempt to write QueueDescLow register for invalid QueueSel. QueueSel was %u, but the number of queues is %u.",
772                                 mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
773                 }
774                 break;
775
776         // Queue's Descriptor Table 64 bit long physical address, high 32
777         case VIRTIO_MMIO_QUEUE_DESC_HIGH:
778                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
779                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
780                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
781                                         "Attempt to access QueueDescHigh on queue %d, which has nonzero QueueReady.\n"
782                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
783                                         , mmio_dev->qsel);
784
785                         // clear high bits
786                         temp_ptr = (void *)
787                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.desc
788                           & ((uint64_t)0xffffffff));
789                         // write high bits
790                         temp_ptr = (void *) ((uint64_t)temp_ptr
791                                           | ((uint64_t)(*value) << 32));
792
793                         // virtio-v1.0-cs04 s2.4 Virtqueues
794                         if ((uint64_t)temp_ptr % 16)
795                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
796                                         "Physical address of guest's descriptor table (%p) is misaligned. Address should be a multiple of 16.\n"
797                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
798
799                         // assign the new value to the queue desc
800                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.desc = temp_ptr;
801                 } else {
802                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
803                                 "Attempt to write QueueDescHigh register for invalid QueueSel. QueueSel was %u, but the number of queues is %u."
804                                 , mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
805                 }
806                 break;
807
808         // Queue's Available Ring 64 bit long physical address, low 32
809         case VIRTIO_MMIO_QUEUE_AVAIL_LOW:
810                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
811                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
812                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
813                                         "Attempt to access QueueAvailLow on queue %d, which has nonzero QueueReady.\n"
814                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
815                                         , mmio_dev->qsel);
816
817                         // clear low bits
818                         temp_ptr = (void *)
819                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.avail
820                           & ((uint64_t)0xffffffff << 32));
821                         // write low bits
822                         temp_ptr = (void *) ((uint64_t)temp_ptr | *value);
823
824                         // virtio-v1.0-cs04 s2.4 Virtqueues
825                         if ((uint64_t)temp_ptr % 2)
826                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
827                                         "Physical address of guest's available ring (%p) is misaligned. Address should be a multiple of 2.\n"
828                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
829
830                         // assign the new value to the queue avail
831                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.avail = temp_ptr;
832                 } else {
833                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
834                                 "Attempt to write QueueAvailLow register for invalid QueueSel. QueueSel was %u, but the number of queues is %u."
835                                 , mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
836                 }
837                 break;
838
839         // Queue's Available Ring 64 bit long physical address, high 32
840         case VIRTIO_MMIO_QUEUE_AVAIL_HIGH:
841                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
842                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
843                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
844                                         "Attempt to access QueueAvailHigh on queue %d, which has nonzero QueueReady.\n"
845                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
846                                         , mmio_dev->qsel);
847
848                         // clear high bits
849                         temp_ptr = (void *)
850                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.avail
851                          &  ((uint64_t)0xffffffff));
852                         // write high bits
853                         temp_ptr = (void *) ((uint64_t)temp_ptr
854                                           | ((uint64_t)(*value) << 32));
855
856                         // virtio-v1.0-cs04 s2.4 Virtqueues
857                         if ((uint64_t)temp_ptr % 2)
858                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
859                                         "Physical address of guest's available ring (%p) is misaligned. Address should be a multiple of 2.\n"
860                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
861
862                         // assign the new value to the queue avail
863                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.avail = temp_ptr;
864                 } else {
865                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
866                                 "Attempt to write QueueAvailHigh register for invalid QueueSel. QueueSel was %u, but the number of queues is %u."
867                                 , mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
868                 }
869                 break;
870
871         // Queue's Used Ring 64 bit long physical address, low 32
872         case VIRTIO_MMIO_QUEUE_USED_LOW:
873                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
874                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
875                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
876                                         "Attempt to access QueueUsedLow on queue %d, which has nonzero QueueReady.\n"
877                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
878                                         , mmio_dev->qsel);
879
880                         // clear low bits
881                         temp_ptr = (void *)
882                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.used
883                           & ((uint64_t)0xffffffff << 32));
884                         // write low bits
885                         temp_ptr = (void *) ((uint64_t)temp_ptr | *value);
886
887                         // virtio-v1.0-cs04 s2.4 Virtqueues
888                         if ((uint64_t)temp_ptr % 4)
889                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
890                                         "Physical address of guest's used ring (%p) is misaligned. Address should be a multiple of 4.\n"
891                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
892
893                         // assign the new value to the queue used
894                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.used = temp_ptr;
895                 } else {
896                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
897                                 "Attempt to write QueueUsedLow register for invalid QueueSel. QueueSel was %u, but the number of queues is %u."
898                                 , mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
899                 }
900                 break;
901
902         // Queue's Used Ring 64 bit long physical address, high 32
903         case VIRTIO_MMIO_QUEUE_USED_HIGH:
904                 if (mmio_dev->qsel < mmio_dev->vqdev->num_vqs) {
905                         if (mmio_dev->vqdev->vqs[mmio_dev->qsel].qready != 0)
906                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
907                                         "Attempt to access QueueUsedHigh on queue %d, which has nonzero QueueReady.\n"
908                                         "  See virtio-v1.0-cs04 s4.2.2.2 MMIO Device Register Layout"
909                                         , mmio_dev->qsel);
910
911                         // clear high bits
912                         temp_ptr = (void *)
913                             ((uint64_t)mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.used
914                           & ((uint64_t)0xffffffff));
915                         // write high bits
916                         temp_ptr = (void *) ((uint64_t)temp_ptr
917                                           | ((uint64_t)(*value) << 32));
918
919                         // virtio-v1.0-cs04 s2.4 Virtqueues
920                         if ((uint64_t)temp_ptr % 4)
921                                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
922                                         "Physical address of guest's used ring (%p) is misaligned. Address should be a multiple of 4.\n"
923                                         "  See virtio-v1.0-cs04 s2.4 Virtqueues");
924
925                         // assign the new value to the queue used
926                         mmio_dev->vqdev->vqs[mmio_dev->qsel].vring.used = temp_ptr;
927                 } else {
928                         VIRTIO_DRI_WARNX(mmio_dev->vqdev,
929                                 "Attempt to write QueueUsedHigh register for invalid QueueSel. QueueSel was %u, but the number of queues is %u."
930                                 , mmio_dev->qsel, mmio_dev->vqdev->num_vqs);
931                 }
932                 break;
933
934         // Read-only register offsets:
935         case VIRTIO_MMIO_MAGIC_VALUE:
936         case VIRTIO_MMIO_VERSION:
937         case VIRTIO_MMIO_DEVICE_ID:
938         case VIRTIO_MMIO_VENDOR_ID:
939         case VIRTIO_MMIO_DEVICE_FEATURES:
940         case VIRTIO_MMIO_QUEUE_NUM_MAX:
941         case VIRTIO_MMIO_INTERRUPT_STATUS:
942         case VIRTIO_MMIO_CONFIG_GENERATION:
943                 // Write to read-only register
944                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
945                         "Attempt to write read-only device register offset 0x%x.",
946                         offset);
947                 break;
948         default:
949                 // Bad register offset
950                 VIRTIO_DRI_ERRX(mmio_dev->vqdev,
951                         "Attempt to write invalid device register offset 0x%x.",
952                         offset);
953                 break;
954         }
955 }