2 * Copyright (c) 2014 ETH Zurich.
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Universitaetsstrasse 6, CH-8092 Zurich. Attn: Systems Group.
10 #include <barrelfish/barrelfish.h>
12 #include <virtio/virtio.h>
13 #include <virtio/virtio_device.h>
16 #include "backends/virtio_mmio.h"
17 #include "backends/virtio_pci.h"
22 * \brief initializes a new VirtIO device based on the values passed with the
23 * device init struct. The device registers have already to be mapped. *
25 * \param dev device structure to initialize
26 * \param init additional information passed for the init process
27 * \param dev_regs memory location of the device registers
29 errval_t virtio_device_open(struct virtio_device **dev,
30 struct virtio_device_setup *init)
32 errval_t err = SYS_ERR_OK;
34 if (init->dev_reg == NULL || init->dev_reg_size == 0) {
36 * XXX: does this also hold for the PCI
38 return VIRTIO_ERR_DEVICE_REGISTER;
41 switch (init->backend) {
42 case VIRTIO_DEVICE_BACKEND_PCI:
44 * TODO: intialize the PCI device backend
46 assert(!"NYI: handling of the PCI backend\n");
48 case VIRTIO_DEVICE_BACKEND_MMIO:
49 err = virtio_device_mmio_init(dev, init);
51 case VIRTIO_DEVICE_BACKEND_IO:
53 * TODO: intialize the IO device backend
55 assert(!"NYI: handling of the IO backend\n");
58 err = VIRTIO_ERR_BACKEND;
62 if (err_is_fail(err)) {
66 struct virtio_device *vdev = *dev;
68 /* 1. Reset the device. */
69 err = virtio_device_reset(vdev);
70 if (err_is_fail(err)) {
74 /* 2. Set the ACKNOWLEDGE status bit: the guest OS has notice the device.*/
75 err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_ACKNOWLEDGE);
76 if (err_is_fail(err)) {
80 /* 3. Set the DRIVER status bit: the guest OS knows how to drive the device.*/
81 err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_DRIVER);
82 if (err_is_fail(err)) {
86 /* 4. Read device feature bits, and write the subset of feature bits understood by the OS and driver to the
87 device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration
88 fields to check that it can support the device before accepting it.*/
89 err = virtio_device_feature_negotiate(vdev);
90 if (err_is_fail(err)) {
94 /* 5. Set the FEATURES_OK status bit. The driver MUST not accept new feature bits after this step.*/
95 err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_FEATURES_OK);
96 if (err_is_fail(err)) {
100 /* 6. Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not
101 support our subset of features and the device is unusable.*/
103 err = virtio_device_get_status(vdev, &status);
104 assert(err_is_ok(err));
106 if (!virtio_mmio_status_features_ok_extract(status)) {
110 /* 7. Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup,
111 reading and possibly writing the device’s virtio configuration space, and population of virtqueues.*/
112 err = virtio_device_specific_setup(vdev);
113 if (err_is_fail(err)) {
116 /* 8. Set the DRIVER_OK status bit. At this point the device is “live”. */
117 err = virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_DRIVER_OK);
118 assert(err_is_ok(err));
120 if (init->device_setup) {
121 return init->device_setup(vdev);
126 failed: virtio_device_set_status(vdev, VIRTIO_DEVICE_STATUS_FAILED);
132 * \brief initializes a new VirtIO device based on the values passed with the
133 * device init struct. The supplied cap contains the memory range of the
136 * \param dev device structure to initialize
137 * \param init additional information passed for the init process
138 * \param dev_cap capability representing the device registers
140 errval_t virtio_device_open_with_cap(struct virtio_device **dev,
141 struct virtio_device_setup *init,
142 struct capref dev_cap)
146 assert(!capref_is_null(dev_cap));
148 struct frame_identity id;
149 err = invoke_frame_identify(dev_cap, &id);
150 if (err_is_fail(err)) {
151 VIRTIO_DEBUG_DEV("ERROR: could not identify the device frame.\n");
155 init->dev_reg_size = (1UL << id.bits);
157 err = vspace_map_one_frame_attr(&init->dev_reg, init->dev_reg_size, dev_cap,
158 VIRTIO_VREGION_FLAGS_DEVICE,
160 if (err_is_fail(err)) {
161 VIRTIO_DEBUG_DEV("ERROR: mapping the device register frame failed.\n");
162 init->dev_reg = NULL;
163 init->dev_reg_size = 0;
167 VIRTIO_DEBUG_DEV("mapped device registers: [0x%016lx] -> [0x%016lx]\n",
169 (uintptr_t )init->dev_reg);
171 err = virtio_device_init(dev, init);
172 if (err_is_fail(err)) {
173 vspace_unmap(init->dev_reg);