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

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

lguest: update commentry



Every so often, after code shuffles, I need to go through and unbitrot
the Lguest Journey (see drivers/lguest/README).  Since we now use RCU in
a simple form in one place I took the opportunity to expand that explanation.

Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
parent 2e04ef76
Loading
Loading
Loading
Loading
+139 −45
Original line number Diff line number Diff line
@@ -49,7 +49,7 @@
#include "linux/virtio_ring.h"
#include "asm/bootparam.h"
/*L:110
 * We can ignore the 39 include files we need for this program, but I do want
 * We can ignore the 42 include files we need for this program, but I do want
 * to draw attention to the use of kernel-style types.
 *
 * As Linus said, "C is a Spartan language, and so should your naming be."  I
@@ -305,6 +305,11 @@ static void *map_zeroed_pages(unsigned int num)
		    PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
	if (addr == MAP_FAILED)
		err(1, "Mmaping %u pages of /dev/zero", num);

	/*
	 * One neat mmap feature is that you can close the fd, and it
	 * stays mapped.
	 */
	close(fd);

	return addr;
@@ -557,7 +562,7 @@ static void tell_kernel(unsigned long start)
}
/*:*/

/*
/*L:200
 * Device Handling.
 *
 * When the Guest gives us a buffer, it sends an array of addresses and sizes.
@@ -608,7 +613,10 @@ static unsigned next_desc(struct vring_desc *desc,
	return next;
}

/* This actually sends the interrupt for this virtqueue */
/*
 * This actually sends the interrupt for this virtqueue, if we've used a
 * buffer.
 */
static void trigger_irq(struct virtqueue *vq)
{
	unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
@@ -629,12 +637,12 @@ static void trigger_irq(struct virtqueue *vq)
}

/*
 * This looks in the virtqueue and for the first available buffer, and converts
 * This looks in the virtqueue for the first available buffer, and converts
 * it to an iovec for convenient access.  Since descriptors consist of some
 * number of output then some number of input descriptors, it's actually two
 * iovecs, but we pack them into one and note how many of each there were.
 *
 * This function returns the descriptor number found.
 * This function waits if necessary, and returns the descriptor number found.
 */
static unsigned wait_for_vq_desc(struct virtqueue *vq,
				 struct iovec iov[],
@@ -644,10 +652,14 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
	struct vring_desc *desc;
	u16 last_avail = lg_last_avail(vq);

	/* There's nothing available? */
	while (last_avail == vq->vring.avail->idx) {
		u64 event;

		/* OK, tell Guest about progress up to now. */
		/*
		 * Since we're about to sleep, now is a good time to tell the
		 * Guest about what we've used up to now.
		 */
		trigger_irq(vq);

		/* OK, now we need to know about added descriptors. */
@@ -734,8 +746,9 @@ static unsigned wait_for_vq_desc(struct virtqueue *vq,
}

/*
 * After we've used one of their buffers, we tell them about it.  We'll then
 * want to send them an interrupt, using trigger_irq().
 * After we've used one of their buffers, we tell the Guest about it.  Sometime
 * later we'll want to send them an interrupt using trigger_irq(); note that
 * wait_for_vq_desc() does that for us if it has to wait.
 */
static void add_used(struct virtqueue *vq, unsigned int head, int len)
{
@@ -782,12 +795,12 @@ static void console_input(struct virtqueue *vq)
	struct console_abort *abort = vq->dev->priv;
	struct iovec iov[vq->vring.num];

	/* Make sure there's a descriptor waiting. */
	/* Make sure there's a descriptor available. */
	head = wait_for_vq_desc(vq, iov, &out_num, &in_num);
	if (out_num)
		errx(1, "Output buffers in console in queue?");

	/* Read it in. */
	/* Read into it.  This is where we usually wait. */
	len = readv(STDIN_FILENO, iov, in_num);
	if (len <= 0) {
		/* Ran out of input? */
@@ -800,6 +813,7 @@ static void console_input(struct virtqueue *vq)
			pause();
	}

	/* Tell the Guest we used a buffer. */
	add_used_and_trigger(vq, head, len);

	/*
@@ -834,15 +848,23 @@ static void console_output(struct virtqueue *vq)
	unsigned int head, out, in;
	struct iovec iov[vq->vring.num];

	/* We usually wait in here, for the Guest to give us something. */
	head = wait_for_vq_desc(vq, iov, &out, &in);
	if (in)
		errx(1, "Input buffers in console output queue?");

	/* writev can return a partial write, so we loop here. */
	while (!iov_empty(iov, out)) {
		int len = writev(STDOUT_FILENO, iov, out);
		if (len <= 0)
			err(1, "Write to stdout gave %i", len);
		iov_consume(iov, out, len);
	}

	/*
	 * We're finished with that buffer: if we're going to sleep,
	 * wait_for_vq_desc() will prod the Guest with an interrupt.
	 */
	add_used(vq, head, 0);
}

@@ -862,15 +884,30 @@ static void net_output(struct virtqueue *vq)
	unsigned int head, out, in;
	struct iovec iov[vq->vring.num];

	/* We usually wait in here for the Guest to give us a packet. */
	head = wait_for_vq_desc(vq, iov, &out, &in);
	if (in)
		errx(1, "Input buffers in net output queue?");
	/*
	 * Send the whole thing through to /dev/net/tun.  It expects the exact
	 * same format: what a coincidence!
	 */
	if (writev(net_info->tunfd, iov, out) < 0)
		errx(1, "Write to tun failed?");

	/*
	 * Done with that one; wait_for_vq_desc() will send the interrupt if
	 * all packets are processed.
	 */
	add_used(vq, head, 0);
}

/* Will reading from this file descriptor block? */
/*
 * Handling network input is a bit trickier, because I've tried to optimize it.
 *
 * First we have a helper routine which tells is if from this file descriptor
 * (ie. the /dev/net/tun device) will block:
 */
static bool will_block(int fd)
{
	fd_set fdset;
@@ -880,7 +917,11 @@ static bool will_block(int fd)
	return select(fd+1, &fdset, NULL, NULL, &zero) != 1;
}

/* This handles packets coming in from the tun device to our Guest. */
/*
 * This handles packets coming in from the tun device to our Guest.  Like all
 * service routines, it gets called again as soon as it returns, so you don't
 * see a while(1) loop here.
 */
static void net_input(struct virtqueue *vq)
{
	int len;
@@ -888,21 +929,38 @@ static void net_input(struct virtqueue *vq)
	struct iovec iov[vq->vring.num];
	struct net_info *net_info = vq->dev->priv;

	/*
	 * Get a descriptor to write an incoming packet into.  This will also
	 * send an interrupt if they're out of descriptors.
	 */
	head = wait_for_vq_desc(vq, iov, &out, &in);
	if (out)
		errx(1, "Output buffers in net input queue?");

	/* Deliver interrupt now, since we're about to sleep. */
	/*
	 * If it looks like we'll block reading from the tun device, send them
	 * an interrupt.
	 */
	if (vq->pending_used && will_block(net_info->tunfd))
		trigger_irq(vq);

	/*
	 * Read in the packet.  This is where we normally wait (when there's no
	 * incoming network traffic).
	 */
	len = readv(net_info->tunfd, iov, in);
	if (len <= 0)
		err(1, "Failed to read from tun.");

	/*
	 * Mark that packet buffer as used, but don't interrupt here.  We want
	 * to wait until we've done as much work as we can.
	 */
	add_used(vq, head, len);
}
/*:*/

/* This is the helper to create threads. */
/* This is the helper to create threads: run the service routine in a loop. */
static int do_thread(void *_vq)
{
	struct virtqueue *vq = _vq;
@@ -950,11 +1008,14 @@ static void reset_device(struct device *dev)
	signal(SIGCHLD, (void *)kill_launcher);
}

/*L:216
 * This actually creates the thread which services the virtqueue for a device.
 */
static void create_thread(struct virtqueue *vq)
{
	/*
	 * Create stack for thread and run it.  Since the stack grows upwards,
	 * we point the stack pointer to the end of this region.
	 * Create stack for thread.  Since the stack grows upwards, we point
	 * the stack pointer to the end of this region.
	 */
	char *stack = malloc(32768);
	unsigned long args[] = { LHREQ_EVENTFD,
@@ -966,17 +1027,22 @@ static void create_thread(struct virtqueue *vq)
		err(1, "Creating eventfd");
	args[2] = vq->eventfd;

	/* Attach an eventfd to this virtqueue: it will go off
	 * when the Guest does an LHCALL_NOTIFY for this vq. */
	/*
	 * Attach an eventfd to this virtqueue: it will go off when the Guest
	 * does an LHCALL_NOTIFY for this vq.
	 */
	if (write(lguest_fd, &args, sizeof(args)) != 0)
		err(1, "Attaching eventfd");

	/* CLONE_VM: because it has to access the Guest memory, and
	 * SIGCHLD so we get a signal if it dies. */
	/*
	 * CLONE_VM: because it has to access the Guest memory, and SIGCHLD so
	 * we get a signal if it dies.
	 */
	vq->thread = clone(do_thread, stack + 32768, CLONE_VM | SIGCHLD, vq);
	if (vq->thread == (pid_t)-1)
		err(1, "Creating clone");
	/* We close our local copy, now the child has it. */

	/* We close our local copy now the child has it. */
	close(vq->eventfd);
}

@@ -1028,7 +1094,10 @@ static void update_device_status(struct device *dev)
	}
}

/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
/*L:215
 * This is the generic routine we call when the Guest uses LHCALL_NOTIFY.  In
 * particular, it's used to notify us of device status changes during boot.
 */
static void handle_output(unsigned long addr)
{
	struct device *i;
@@ -1037,18 +1106,32 @@ static void handle_output(unsigned long addr)
	for (i = devices.dev; i; i = i->next) {
		struct virtqueue *vq;

		/* Notifications to device descriptors update device status. */
		/*
		 * Notifications to device descriptors mean they updated the
		 * device status.
		 */
		if (from_guest_phys(addr) == i->desc) {
			update_device_status(i);
			return;
		}

		/* Devices *can* be used before status is set to DRIVER_OK. */
		/*
		 * Devices *can* be used before status is set to DRIVER_OK.
		 * The original plan was that they would never do this: they
		 * would always finish setting up their status bits before
		 * actually touching the virtqueues.  In practice, we allowed
		 * them to, and they do (eg. the disk probes for partition
		 * tables as part of initialization).
		 *
		 * If we see this, we start the device: once it's running, we
		 * expect the device to catch all the notifications.
		 */
		for (vq = i->vq; vq; vq = vq->next) {
			if (addr != vq->config.pfn*getpagesize())
				continue;
			if (i->running)
				errx(1, "Notification on running %s", i->name);
			/* This just calls create_thread() for each virtqueue */
			start_device(i);
			return;
		}
@@ -1132,6 +1215,11 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
	vq->next = NULL;
	vq->last_avail_idx = 0;
	vq->dev = dev;

	/*
	 * This is the routine the service thread will run, and its Process ID
	 * once it's running.
	 */
	vq->service = service;
	vq->thread = (pid_t)-1;

@@ -1202,7 +1290,8 @@ static void set_config(struct device *dev, unsigned len, const void *conf)

/*
 * This routine does all the creation and setup of a new device, including
 * calling new_dev_desc() to allocate the descriptor and device memory.
 * calling new_dev_desc() to allocate the descriptor and device memory.  We
 * don't actually start the service threads until later.
 *
 * See what I mean about userspace being boring?
 */
@@ -1478,19 +1567,7 @@ static void setup_tun_net(char *arg)
		verbose("device %u: tun %s: %s\n",
			devices.device_num, tapif, arg);
}

/*
 * Our block (disk) device should be really simple: the Guest asks for a block
 * number and we read or write that position in the file.  Unfortunately, that
 * was amazingly slow: the Guest waits until the read is finished before
 * running anything else, even if it could have been doing useful work.
 *
 * We could use async I/O, except it's reputed to suck so hard that characters
 * actually go missing from your code when you try to use it.
 *
 * So this was one reason why lguest now does all virtqueue servicing in
 * separate threads: it's more efficient and more like a real device.
 */
/*:*/

/* This hangs off device->priv. */
struct vblk_info
@@ -1512,8 +1589,16 @@ struct vblk_info
/*L:210
 * The Disk
 *
 * Remember that the block device is handled by a separate I/O thread.  We head
 * straight into the core of that thread here:
 * The disk only has one virtqueue, so it only has one thread.  It is really
 * simple: the Guest asks for a block number and we read or write that position
 * in the file.
 *
 * Before we serviced each virtqueue in a separate thread, that was unacceptably
 * slow: the Guest waits until the read is finished before running anything
 * else, even if it could have been doing useful work.
 *
 * We could have used async I/O, except it's reputed to suck so hard that
 * characters actually go missing from your code when you try to use it.
 */
static void blk_request(struct virtqueue *vq)
{
@@ -1525,7 +1610,10 @@ static void blk_request(struct virtqueue *vq)
	struct iovec iov[vq->vring.num];
	off64_t off;

	/* Get the next request. */
	/*
	 * Get the next request, where we normally wait.  It triggers the
	 * interrupt to acknowledge previously serviced requests (if any).
	 */
	head = wait_for_vq_desc(vq, iov, &out_num, &in_num);

	/*
@@ -1539,6 +1627,10 @@ static void blk_request(struct virtqueue *vq)

	out = convert(&iov[0], struct virtio_blk_outhdr);
	in = convert(&iov[out_num+in_num-1], u8);
	/*
	 * For historical reasons, block operations are expressed in 512 byte
	 * "sectors".
	 */
	off = out->sector * 512;

	/*
@@ -1614,6 +1706,7 @@ static void blk_request(struct virtqueue *vq)
	if (out->type & VIRTIO_BLK_T_BARRIER)
		fdatasync(vblk->fd);

	/* Finished that request. */
	add_used(vq, head, wlen);
}

@@ -1682,9 +1775,8 @@ static void rng_input(struct virtqueue *vq)
		errx(1, "Output buffers in rng?");

	/*
	 * This is why we convert to iovecs: the readv() call uses them, and so
	 * it reads straight into the Guest's buffer.  We loop to make sure we
	 * fill it.
	 * Just like the console write, we loop to cover the whole iovec.
	 * In this case, short reads actually happen quite a bit.
	 */
	while (!iov_empty(iov, in_num)) {
		len = readv(rng_info->rfd, iov, in_num);
@@ -1818,7 +1910,9 @@ int main(int argc, char *argv[])
	devices.lastdev = NULL;
	devices.next_irq = 1;

	/* We're CPU 0.  In fact, that's the only CPU possible right now. */
	cpu_id = 0;

	/*
	 * We need to know how much memory so we can set up the device
	 * descriptor and memory pages for the devices as we parse the command
@@ -1926,7 +2020,7 @@ int main(int argc, char *argv[])
	 */
	tell_kernel(start);

	/* Ensure that we terminate if a child dies. */
	/* Ensure that we terminate if a device-servicing child dies. */
	signal(SIGCHLD, kill_launcher);

	/* If we exit via err(), this kills all the threads, restores tty. */
+4 −4
Original line number Diff line number Diff line
@@ -35,10 +35,10 @@
 * operations?  There are two ways: the direct way is to make a "hypercall",
 * to make requests of the Host Itself.
 *
 * We use the KVM hypercall mechanism. Seventeen hypercalls are
 * available: the hypercall number is put in the %eax register, and the
 * arguments (when required) are placed in %ebx, %ecx, %edx and %esi.
 * If a return value makes sense, it's returned in %eax.
 * We use the KVM hypercall mechanism, though completely different hypercall
 * numbers. Seventeen hypercalls are available: the hypercall number is put in
 * the %eax register, and the arguments (when required) are placed in %ebx,
 * %ecx, %edx and %esi.  If a return value makes sense, it's returned in %eax.
 *
 * Grossly invalid calls result in Sudden Death at the hands of the vengeful
 * Host, rather than returning failure.  This reflects Winston Churchill's
+77 −22
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ static void lazy_hcall1(unsigned long call,
		async_hcall(call, arg1, 0, 0, 0);
}

/* You can imagine what lazy_hcall2, 3 and 4 look like. :*/
static void lazy_hcall2(unsigned long call,
		       unsigned long arg1,
		       unsigned long arg2)
@@ -189,8 +190,10 @@ static void lazy_hcall4(unsigned long call,
}
#endif

/* When lazy mode is turned off reset the per-cpu lazy mode variable and then
 * issue the do-nothing hypercall to flush any stored calls. */
/*G:036
 * When lazy mode is turned off reset the per-cpu lazy mode variable and then
 * issue the do-nothing hypercall to flush any stored calls.
:*/
static void lguest_leave_lazy_mmu_mode(void)
{
	kvm_hypercall0(LHCALL_FLUSH_ASYNC);
@@ -250,13 +253,11 @@ extern void lg_irq_enable(void);
extern void lg_restore_fl(unsigned long flags);

/*M:003
 * Note that we don't check for outstanding interrupts when we re-enable them
 * (or when we unmask an interrupt).  This seems to work for the moment, since
 * interrupts are rare and we'll just get the interrupt on the next timer tick,
 * but now we can run with CONFIG_NO_HZ, we should revisit this.  One way would
 * be to put the "irq_enabled" field in a page by itself, and have the Host
 * write-protect it when an interrupt comes in when irqs are disabled.  There
 * will then be a page fault as soon as interrupts are re-enabled.
 * We could be more efficient in our checking of outstanding interrupts, rather
 * than using a branch.  One way would be to put the "irq_enabled" field in a
 * page by itself, and have the Host write-protect it when an interrupt comes
 * in when irqs are disabled.  There will then be a page fault as soon as
 * interrupts are re-enabled.
 *
 * A better method is to implement soft interrupt disable generally for x86:
 * instead of disabling interrupts, we set a flag.  If an interrupt does come
@@ -568,7 +569,7 @@ static void lguest_write_cr4(unsigned long val)
 * cr3 ---> +---------+
 *	    |  	   --------->+---------+
 *	    |	      |	     | PADDR1  |
 *	  Top-level   |	     | PADDR2  |
 *	  Mid-level   |	     | PADDR2  |
 *	  (PMD) page  |	     | 	       |
 *	    |	      |	   Lower-level |
 *	    |	      |	   (PTE) page  |
@@ -588,23 +589,62 @@ static void lguest_write_cr4(unsigned long val)
 *    Index into top     Index into second      Offset within page
 *  page directory page    pagetable page
 *
 * The kernel spends a lot of time changing both the top-level page directory
 * and lower-level pagetable pages.  The Guest doesn't know physical addresses,
 * so while it maintains these page tables exactly like normal, it also needs
 * to keep the Host informed whenever it makes a change: the Host will create
 * the real page tables based on the Guests'.
 * Now, unfortunately, this isn't the whole story: Intel added Physical Address
 * Extension (PAE) to allow 32 bit systems to use 64GB of memory (ie. 36 bits).
 * These are held in 64-bit page table entries, so we can now only fit 512
 * entries in a page, and the neat three-level tree breaks down.
 *
 * The result is a four level page table:
 *
 * cr3 --> [ 4 Upper  ]
 *	   [   Level  ]
 *	   [  Entries ]
 *	   [(PUD Page)]---> +---------+
 *	 		    |  	   --------->+---------+
 *	 		    |	      |	     | PADDR1  |
 *	 		  Mid-level   |	     | PADDR2  |
 *	 		  (PMD) page  |	     | 	       |
 *	 		    |	      |	   Lower-level |
 *	 		    |	      |	   (PTE) page  |
 *	 		    |	      |	     |	       |
 *	 		      ....    	     	 ....
 *
 *
 * And the virtual address is decoded as:
 *
 *         1 1 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 *      |<-2->|<--- 9 bits ---->|<---- 9 bits --->|<------ 12 bits ------>|
 * Index into    Index into mid    Index into lower    Offset within page
 * top entries   directory page     pagetable page
 *
 * It's too hard to switch between these two formats at runtime, so Linux only
 * supports one or the other depending on whether CONFIG_X86_PAE is set.  Many
 * distributions turn it on, and not just for people with silly amounts of
 * memory: the larger PTE entries allow room for the NX bit, which lets the
 * kernel disable execution of pages and increase security.
 *
 * This was a problem for lguest, which couldn't run on these distributions;
 * then Matias Zabaljauregui figured it all out and implemented it, and only a
 * handful of puppies were crushed in the process!
 *
 * Back to our point: the kernel spends a lot of time changing both the
 * top-level page directory and lower-level pagetable pages.  The Guest doesn't
 * know physical addresses, so while it maintains these page tables exactly
 * like normal, it also needs to keep the Host informed whenever it makes a
 * change: the Host will create the real page tables based on the Guests'.
 */

/*
 * The Guest calls this to set a second-level entry (pte), ie. to map a page
 * into a process' address space.  We set the entry then tell the Host the
 * toplevel and address this corresponds to.  The Guest uses one pagetable per
 * process, so we need to tell the Host which one we're changing (mm->pgd).
 * The Guest calls this after it has set a second-level entry (pte), ie. to map
 * a page into a process' address space.  Wetell the Host the toplevel and
 * address this corresponds to.  The Guest uses one pagetable per process, so
 * we need to tell the Host which one we're changing (mm->pgd).
 */
static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
			       pte_t *ptep)
{
#ifdef CONFIG_X86_PAE
	/* PAE needs to hand a 64 bit page table entry, so it uses two args. */
	lazy_hcall4(LHCALL_SET_PTE, __pa(mm->pgd), addr,
		    ptep->pte_low, ptep->pte_high);
#else
@@ -612,6 +652,7 @@ static void lguest_pte_update(struct mm_struct *mm, unsigned long addr,
#endif
}

/* This is the "set and update" combo-meal-deal version. */
static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr,
			      pte_t *ptep, pte_t pteval)
{
@@ -672,6 +713,11 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval)
}

#ifdef CONFIG_X86_PAE
/*
 * With 64-bit PTE values, we need to be careful setting them: if we set 32
 * bits at a time, the hardware could see a weird half-set entry.  These
 * versions ensure we update all 64 bits at once.
 */
static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
{
	native_set_pte_atomic(ptep, pte);
@@ -679,13 +725,14 @@ static void lguest_set_pte_atomic(pte_t *ptep, pte_t pte)
		lazy_hcall1(LHCALL_FLUSH_TLB, 1);
}

void lguest_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
static void lguest_pte_clear(struct mm_struct *mm, unsigned long addr,
			     pte_t *ptep)
{
	native_pte_clear(mm, addr, ptep);
	lguest_pte_update(mm, addr, ptep);
}

void lguest_pmd_clear(pmd_t *pmdp)
static void lguest_pmd_clear(pmd_t *pmdp)
{
	lguest_set_pmd(pmdp, __pmd(0));
}
@@ -784,6 +831,14 @@ static void __init lguest_init_IRQ(void)
	irq_ctx_init(smp_processor_id());
}

/*
 * With CONFIG_SPARSE_IRQ, interrupt descriptors are allocated as-needed, so
 * rather than set them in lguest_init_IRQ we are called here every time an
 * lguest device needs an interrupt.
 *
 * FIXME: irq_to_desc_alloc_node() can fail due to lack of memory, we should
 * pass that up!
 */
void lguest_setup_irq(unsigned int irq)
{
	irq_to_desc_alloc_node(irq, 0);
@@ -1298,7 +1353,7 @@ __init void lguest_init(void)
	 */
	switch_to_new_gdt(0);

	/* As described in head_32.S, we map the first 128M of memory. */
	/* We actually boot with all memory mapped, but let's say 128MB. */
	max_pfn_mapped = (128*1024*1024) >> PAGE_SHIFT;

	/*
+2 −0
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ send_interrupts:
	 * create one manually here.
	 */
	.byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */
	/* Put eax back the way we found it. */
	popl %eax
	ret

@@ -125,6 +126,7 @@ ENTRY(lg_restore_fl)
	jnz send_interrupts
	/* Again, the normal path has used no extra registers.  Clever, huh? */
	ret
/*:*/

/* These demark the EIP range where host should never deliver interrupts. */
.global lguest_noirq_start
+6 −1
Original line number Diff line number Diff line
@@ -217,10 +217,15 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)

		/*
		 * It's possible the Guest did a NOTIFY hypercall to the
		 * Launcher, in which case we return from the read() now.
		 * Launcher.
		 */
		if (cpu->pending_notify) {
			/*
			 * Does it just needs to write to a registered
			 * eventfd (ie. the appropriate virtqueue thread)?
			 */
			if (!send_notify_to_eventfd(cpu)) {
				/* OK, we tell the main Laucher. */
				if (put_user(cpu->pending_notify, user))
					return -EFAULT;
				return sizeof(cpu->pending_notify);
Loading