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

Remove old lguest I/O infrrasructure.

This patch gets rid of the old lguest host I/O infrastructure and
replaces it with a single hypercall "LHCALL_NOTIFY" which takes an

The main change is the removal of io.c: that mainly did inter-guest
I/O, which virtio doesn't yet support.
Signed-off-by: default avatarRusty Russell <>
parent 0ca49ca9
# Host requires the other files, which can be a module.
obj-$(CONFIG_LGUEST) += lg.o
lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \
segments.o io.o lguest_user.o
segments.o lguest_user.o
lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o
......@@ -202,13 +202,12 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
if (lg->hcall)
/* It's possible the Guest did a SEND_DMA hypercall to the
/* It's possible the Guest did a NOTIFY hypercall to the
* Launcher, in which case we return from the read() now. */
if (lg->dma_is_pending) {
if (put_user(lg->pending_dma, user) ||
put_user(lg->pending_key, user+1))
if (lg->pending_notify) {
if (put_user(lg->pending_notify, user))
return -EFAULT;
return sizeof(unsigned long)*2;
return sizeof(lg->pending_notify);
/* Check for signals */
......@@ -288,9 +287,6 @@ static int __init init(void)
if (err)
goto unmap;
/* The I/O subsystem needs some things initialized. */
/* We might need to reserve an interrupt vector. */
err = init_interrupts();
if (err)
......@@ -60,22 +60,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
/* BIND_DMA really wants four arguments, but it's the only call
* which does. So the Guest packs the number of buffers and
* the interrupt number into the final argument, and we decode
* it here. This can legitimately fail, since we currently
* place a limit on the number of DMA pools a Guest can have.
* So we return true or false from this call. */
args->arg0 = bind_dma(lg, args->arg1, args->arg2,
args->arg3 >> 8, args->arg3 & 0xFF);
/* All these calls simply pass the arguments through to the right
* routines. */
send_dma(lg, args->arg1, args->arg2);
guest_new_pagetable(lg, args->arg1);
......@@ -99,6 +86,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
/* Similarly, this sets the halted flag for run_guest(). */
lg->halted = 1;
lg->pending_notify = args->arg1;
if (lguest_arch_do_hcall(lg, args))
kill_guest(lg, "Bad hypercall %li\n", args->arg0);
......@@ -156,9 +146,9 @@ static void do_async_hcalls(struct lguest *lg)
/* Stop doing hypercalls if we've just done a DMA to the
* Launcher: it needs to service this first. */
if (lg->dma_is_pending)
/* Stop doing hypercalls if they want to notify the Launcher:
* it needs to service this first. */
if (lg->pending_notify)
......@@ -220,9 +210,9 @@ void do_hypercalls(struct lguest *lg)
/* If we stopped reading the hypercall ring because the Guest did a
* SEND_DMA to the Launcher, we want to return now. Otherwise we do
* NOTIFY to the Launcher, we want to return now. Otherwise we do
* the hypercall. */
if (!lg->dma_is_pending) {
if (!lg->pending_notify) {
do_hcall(lg, lg->hcall);
/* Tricky point: we reset the hcall pointer to mark the
* hypercall as "done". We use the hcall pointer rather than
This diff is collapsed.
......@@ -5,7 +5,6 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/stringify.h>
#include <linux/futex.h>
#include <linux/lguest.h>
#include <linux/lguest_launcher.h>
#include <linux/wait.h>
......@@ -17,17 +16,6 @@
void free_pagetables(void);
int init_pagetables(struct page **switcher_page, unsigned int pages);
struct lguest_dma_info
struct list_head list;
union futex_key key;
unsigned long dmas;
struct lguest *owner;
u16 next_dma;
u16 num_dmas;
u8 interrupt; /* 0 when not registered */
struct pgdir
unsigned long gpgdir;
......@@ -90,15 +78,11 @@ struct lguest
struct task_struct *wake;
unsigned long noirq_start, noirq_end;
int dma_is_pending;
unsigned long pending_dma; /* struct lguest_dma */
unsigned long pending_key; /* address they're sending to */
unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
unsigned int stack_pages;
u32 tsc_khz;
struct lguest_dma_info dma[LGUEST_MAX_DMA];
/* Dead? */
const char *dead;
......@@ -184,15 +168,6 @@ extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
int lguest_device_init(void);
void lguest_device_remove(void);
/* io.c: */
void lguest_io_init(void);
int bind_dma(struct lguest *lg,
unsigned long key, unsigned long udma, u16 numdmas, u8 interrupt);
void send_dma(struct lguest *info, unsigned long key, unsigned long udma);
void release_all_dma(struct lguest *lg);
unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
unsigned long *interrupt);
/* hypercalls.c: */
void do_hypercalls(struct lguest *lg);
void write_timestamp(struct lguest *lg);
......@@ -2,37 +2,12 @@
* controls and communicates with the Guest. For example, the first write will
* tell us the Guest's memory layout, pagetable, entry point and kernel address
* offset. A read will run the Guest until something happens, such as a signal
* or the Guest doing a DMA out to the Launcher. Writes are also used to get a
* DMA buffer registered by the Guest and to send the Guest an interrupt. :*/
* or the Guest doing a NOTIFY out to the Launcher. :*/
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include "lg.h"
/*L:310 To send DMA into the Guest, the Launcher needs to be able to ask for a
* DMA buffer. This is done by writing LHREQ_GETDMA and the key to
* /dev/lguest. */
static long user_get_dma(struct lguest *lg, const unsigned long __user *input)
unsigned long key, udma, irq;
/* Fetch the key they wrote to us. */
if (get_user(key, input) != 0)
return -EFAULT;
/* Look for a free Guest DMA buffer bound to that key. */
udma = get_dma_buffer(lg, key, &irq);
if (!udma)
return -ENOENT;
/* We need to tell the Launcher what interrupt the Guest expects after
* the buffer is filled. We stash it in udma->used_len. */
lgwrite_u32(lg, udma + offsetof(struct lguest_dma, used_len), irq);
/* The (guest-physical) address of the DMA buffer is returned from
* the write(). */
return udma;
/*L:315 To force the Guest to stop running and return to the Launcher, the
* Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
* Launcher then writes LHREQ_BREAK and "0" to release the Waker. */
......@@ -102,10 +77,10 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
return len;
/* If we returned from read() last time because the Guest sent DMA,
/* If we returned from read() last time because the Guest notified,
* clear the flag. */
if (lg->dma_is_pending)
lg->dma_is_pending = 0;
if (lg->pending_notify)
lg->pending_notify = 0;
/* Run the Guest until something interesting happens. */
return run_guest(lg, (unsigned long __user *)user);
......@@ -216,7 +191,7 @@ unlock:
/*L:010 The first operation the Launcher does must be a write. All writes
* start with a 32 bit number: for the first write this must be
* LHREQ_INITIALIZE to set up the Guest. After that the Launcher can use
* writes of other values to get DMA buffers and send interrupts. */
* writes of other values to send interrupts. */
static ssize_t write(struct file *file, const char __user *in,
size_t size, loff_t *off)
......@@ -245,8 +220,6 @@ static ssize_t write(struct file *file, const char __user *in,
switch (req) {
return initialize(file, input);
return user_get_dma(lg, input);
return user_send_irq(lg, input);
......@@ -276,8 +249,6 @@ static int close(struct inode *inode, struct file *file)
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
/* Free any DMA buffers the Guest had bound. */
/* Free up the shadow page tables for the Guest. */
/* Now all the memory cleanups are done, it's safe to release the
......@@ -13,11 +13,10 @@
#define LHCALL_TS 8
#define LHCALL_HALT 10
#define LHCALL_BIND_DMA 12
#define LHCALL_SEND_DMA 13
#define LHCALL_SET_PTE 14
#define LHCALL_SET_PMD 15
#define LHCALL_LOAD_TLS 16
#define LHCALL_NOTIFY 17
/*G:031 First, how does our Guest contact the Host to ask for privileged
* operations? There are two ways: the direct way is to make a "hypercall",
......@@ -10,40 +10,6 @@
/* How many devices? Assume each one wants up to two dma arrays per device. */
* Lguest I/O
* The lguest I/O mechanism is the only way Guests can talk to devices. There
* are two hypercalls involved: SEND_DMA for output and BIND_DMA for input. In
* each case, "struct lguest_dma" describes the buffer: this contains 16
* addr/len pairs, and if there are fewer buffer elements the len array is
* terminated with a 0.
* I/O is organized by keys: BIND_DMA attaches buffers to a particular key, and
* SEND_DMA transfers to buffers bound to particular key. By convention, keys
* correspond to a physical address within the device's page. This means that
* devices will never accidentally end up with the same keys, and allows the
* Host use The Futex Trick (as we'll see later in our journey).
* SEND_DMA simply indicates a key to send to, and the physical address of the
* "struct lguest_dma" to send. The Host will write the number of bytes
* transferred into the "struct lguest_dma"'s used_len member.
* BIND_DMA indicates a key to bind to, a pointer to an array of "struct
* lguest_dma"s ready for receiving, the size of that array, and an interrupt
* to trigger when data is received. The Host will only allow transfers into
* buffers with a used_len of zero: it then sets used_len to the number of
* bytes transferred and triggers the interrupt for the Guest to process the
* new input. */
struct lguest_dma
/* 0 if free to be used, filled by the Host. */
__u32 used_len;
unsigned long addr[LGUEST_MAX_DMA_SECTIONS];
/* Where the Host expects the Guest to SEND_DMA console output to. */
......@@ -95,7 +61,7 @@ struct lguest_device_desc {
enum lguest_req
LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */
LHREQ_GETDMA, /* + addr (returns &lguest_dma, irq in ->used_len) */
LHREQ_GETDMA, /* No longer used */
LHREQ_IRQ, /* + irq */
LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment