Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a007a751 authored by Rusty Russell's avatar Rusty Russell
Browse files

lguest: make Launcher see device status updates



This brings us closer to Real Life, where we'd examine the device
features once it's set the DRIVER_OK status bit.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 9f3f7467
Loading
Loading
Loading
Loading
+35 −15
Original line number Diff line number Diff line
@@ -131,6 +131,9 @@ struct device
	/* Any queues attached to this device */
	struct virtqueue *vq;

	/* Handle status being finalized (ie. feature bits stable). */
	void (*ready)(struct device *me);

	/* Device-specific data. */
	void *priv;
};
@@ -925,14 +928,14 @@ static void enable_fd(int fd, struct virtqueue *vq)
	write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
}

/* When the Guest asks us to reset a device, it's is fairly easy. */
static void reset_device(struct device *dev)
/* When the Guest tells us they updated the status field, we handle it. */
static void update_device_status(struct device *dev)
{
	struct virtqueue *vq;

	/* This is a reset. */
	if (dev->desc->status == 0) {
		verbose("Resetting device %s\n", dev->name);
	/* Clear the status. */
	dev->desc->status = 0;

		/* Clear any features they've acked. */
		memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
@@ -944,6 +947,22 @@ static void reset_device(struct device *dev)
			       vring_size(vq->config.num, getpagesize()));
			vq->last_avail_idx = 0;
		}
	} else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
		warnx("Device %s configuration FAILED", dev->name);
	} else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
		unsigned int i;

		verbose("Device %s OK: offered", dev->name);
		for (i = 0; i < dev->desc->feature_len; i++)
			verbose(" %08x", get_feature_bits(dev)[i]);
		verbose(", accepted");
		for (i = 0; i < dev->desc->feature_len; i++)
			verbose(" %08x", get_feature_bits(dev)
				[dev->desc->feature_len+i]);

		if (dev->ready)
			dev->ready(dev);
	}
}

/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
@@ -954,9 +973,9 @@ static void handle_output(int fd, unsigned long addr)

	/* Check each device and virtqueue. */
	for (i = devices.dev; i; i = i->next) {
		/* Notifications to device descriptors reset the device. */
		/* Notifications to device descriptors update device status. */
		if (from_guest_phys(addr) == i->desc) {
			reset_device(i);
			update_device_status(i);
			return;
		}

@@ -1170,6 +1189,7 @@ static struct device *new_device(const char *name, u16 type, int fd,
	dev->handle_input = handle_input;
	dev->name = name;
	dev->vq = NULL;
	dev->ready = NULL;

	/* Append to device list.  Prepending to a single-linked list is
	 * easier, but the user expects the devices to be arranged on the bus
+13 −7
Original line number Diff line number Diff line
@@ -144,20 +144,26 @@ static u8 lg_get_status(struct virtio_device *vdev)
	return to_lgdev(vdev)->desc->status;
}

/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
 * descriptor address of the device.  A zero status means "reset". */
static void set_status(struct virtio_device *vdev, u8 status)
{
	unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;

	/* We set the status. */
	to_lgdev(vdev)->desc->status = status;
	hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
}

static void lg_set_status(struct virtio_device *vdev, u8 status)
{
	BUG_ON(!status);
	to_lgdev(vdev)->desc->status = status;
	set_status(vdev, status);
}

/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
 * address of the device.  The Host will zero the status and all the
 * features. */
static void lg_reset(struct virtio_device *vdev)
{
	unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;

	hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
	set_status(vdev, 0);
}

/*