Commit 15045275 authored by Rusty Russell's avatar Rusty Russell

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
address.

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 <rusty@rustcorp.com.au>
parent 0ca49ca9
# Host requires the other files, which can be a module. # Host requires the other files, which can be a module.
obj-$(CONFIG_LGUEST) += lg.o obj-$(CONFIG_LGUEST) += lg.o
lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.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 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) ...@@ -202,13 +202,12 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
if (lg->hcall) if (lg->hcall)
do_hypercalls(lg); do_hypercalls(lg);
/* 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. */ * Launcher, in which case we return from the read() now. */
if (lg->dma_is_pending) { if (lg->pending_notify) {
if (put_user(lg->pending_dma, user) || if (put_user(lg->pending_notify, user))
put_user(lg->pending_key, user+1))
return -EFAULT; return -EFAULT;
return sizeof(unsigned long)*2; return sizeof(lg->pending_notify);
} }
/* Check for signals */ /* Check for signals */
...@@ -288,9 +287,6 @@ static int __init init(void) ...@@ -288,9 +287,6 @@ static int __init init(void)
if (err) if (err)
goto unmap; goto unmap;
/* The I/O subsystem needs some things initialized. */
lguest_io_init();
/* We might need to reserve an interrupt vector. */ /* We might need to reserve an interrupt vector. */
err = init_interrupts(); err = init_interrupts();
if (err) if (err)
......
...@@ -60,22 +60,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -60,22 +60,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
else else
guest_pagetable_flush_user(lg); guest_pagetable_flush_user(lg);
break; break;
case LHCALL_BIND_DMA:
/* 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);
break;
/* All these calls simply pass the arguments through to the right /* All these calls simply pass the arguments through to the right
* routines. */ * routines. */
case LHCALL_SEND_DMA:
send_dma(lg, args->arg1, args->arg2);
break;
case LHCALL_NEW_PGTABLE: case LHCALL_NEW_PGTABLE:
guest_new_pagetable(lg, args->arg1); guest_new_pagetable(lg, args->arg1);
break; break;
...@@ -99,6 +86,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -99,6 +86,9 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
/* Similarly, this sets the halted flag for run_guest(). */ /* Similarly, this sets the halted flag for run_guest(). */
lg->halted = 1; lg->halted = 1;
break; break;
case LHCALL_NOTIFY:
lg->pending_notify = args->arg1;
break;
default: default:
if (lguest_arch_do_hcall(lg, args)) if (lguest_arch_do_hcall(lg, args))
kill_guest(lg, "Bad hypercall %li\n", args->arg0); kill_guest(lg, "Bad hypercall %li\n", args->arg0);
...@@ -156,9 +146,9 @@ static void do_async_hcalls(struct lguest *lg) ...@@ -156,9 +146,9 @@ static void do_async_hcalls(struct lguest *lg)
break; break;
} }
/* Stop doing hypercalls if we've just done a DMA to the /* Stop doing hypercalls if they want to notify the Launcher:
* Launcher: it needs to service this first. */ * it needs to service this first. */
if (lg->dma_is_pending) if (lg->pending_notify)
break; break;
} }
} }
...@@ -220,9 +210,9 @@ void do_hypercalls(struct lguest *lg) ...@@ -220,9 +210,9 @@ void do_hypercalls(struct lguest *lg)
do_async_hcalls(lg); do_async_hcalls(lg);
/* If we stopped reading the hypercall ring because the Guest did a /* 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. */ * the hypercall. */
if (!lg->dma_is_pending) { if (!lg->pending_notify) {
do_hcall(lg, lg->hcall); do_hcall(lg, lg->hcall);
/* Tricky point: we reset the hcall pointer to mark the /* Tricky point: we reset the hcall pointer to mark the
* hypercall as "done". We use the hcall pointer rather than * hypercall as "done". We use the hcall pointer rather than
......
This diff is collapsed.
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/stringify.h> #include <linux/stringify.h>
#include <linux/futex.h>
#include <linux/lguest.h> #include <linux/lguest.h>
#include <linux/lguest_launcher.h> #include <linux/lguest_launcher.h>
#include <linux/wait.h> #include <linux/wait.h>
...@@ -17,17 +16,6 @@ ...@@ -17,17 +16,6 @@
void free_pagetables(void); void free_pagetables(void);
int init_pagetables(struct page **switcher_page, unsigned int pages); 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 struct pgdir
{ {
unsigned long gpgdir; unsigned long gpgdir;
...@@ -90,15 +78,11 @@ struct lguest ...@@ -90,15 +78,11 @@ struct lguest
struct task_struct *wake; struct task_struct *wake;
unsigned long noirq_start, noirq_end; unsigned long noirq_start, noirq_end;
int dma_is_pending; unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
unsigned long pending_dma; /* struct lguest_dma */
unsigned long pending_key; /* address they're sending to */
unsigned int stack_pages; unsigned int stack_pages;
u32 tsc_khz; u32 tsc_khz;
struct lguest_dma_info dma[LGUEST_MAX_DMA];
/* Dead? */ /* Dead? */
const char *dead; const char *dead;
...@@ -184,15 +168,6 @@ extern char start_switcher_text[], end_switcher_text[], switch_to_guest[]; ...@@ -184,15 +168,6 @@ extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
int lguest_device_init(void); int lguest_device_init(void);
void lguest_device_remove(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: */ /* hypercalls.c: */
void do_hypercalls(struct lguest *lg); void do_hypercalls(struct lguest *lg);
void write_timestamp(struct lguest *lg); void write_timestamp(struct lguest *lg);
......
...@@ -2,37 +2,12 @@ ...@@ -2,37 +2,12 @@
* controls and communicates with the Guest. For example, the first write will * 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 * 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 * 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 * or the Guest doing a NOTIFY out to the Launcher. :*/
* DMA buffer registered by the Guest and to send the Guest an interrupt. :*/
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/fs.h> #include <linux/fs.h>
#include "lg.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 /*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 * Waker sets writes LHREQ_BREAK and the value "1" to /dev/lguest. The
* Launcher then writes LHREQ_BREAK and "0" to release the Waker. */ * 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) ...@@ -102,10 +77,10 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
return len; 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. */ * clear the flag. */
if (lg->dma_is_pending) if (lg->pending_notify)
lg->dma_is_pending = 0; lg->pending_notify = 0;
/* Run the Guest until something interesting happens. */ /* Run the Guest until something interesting happens. */
return run_guest(lg, (unsigned long __user *)user); return run_guest(lg, (unsigned long __user *)user);
...@@ -216,7 +191,7 @@ static int initialize(struct file *file, const unsigned long __user *input) ...@@ -216,7 +191,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
/*L:010 The first operation the Launcher does must be a write. All writes /*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 * 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 * 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, static ssize_t write(struct file *file, const char __user *in,
size_t size, loff_t *off) size_t size, loff_t *off)
{ {
...@@ -245,8 +220,6 @@ static ssize_t write(struct file *file, const char __user *in, ...@@ -245,8 +220,6 @@ static ssize_t write(struct file *file, const char __user *in,
switch (req) { switch (req) {
case LHREQ_INITIALIZE: case LHREQ_INITIALIZE:
return initialize(file, input); return initialize(file, input);
case LHREQ_GETDMA:
return user_get_dma(lg, input);
case LHREQ_IRQ: case LHREQ_IRQ:
return user_send_irq(lg, input); return user_send_irq(lg, input);
case LHREQ_BREAK: case LHREQ_BREAK:
...@@ -276,8 +249,6 @@ static int close(struct inode *inode, struct file *file) ...@@ -276,8 +249,6 @@ static int close(struct inode *inode, struct file *file)
mutex_lock(&lguest_lock); mutex_lock(&lguest_lock);
/* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */ /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
hrtimer_cancel(&lg->hrt); hrtimer_cancel(&lg->hrt);
/* Free any DMA buffers the Guest had bound. */
release_all_dma(lg);
/* Free up the shadow page tables for the Guest. */ /* Free up the shadow page tables for the Guest. */
free_guest_pagetable(lg); free_guest_pagetable(lg);
/* Now all the memory cleanups are done, it's safe to release the /* Now all the memory cleanups are done, it's safe to release the
......
...@@ -13,11 +13,10 @@ ...@@ -13,11 +13,10 @@
#define LHCALL_TS 8 #define LHCALL_TS 8
#define LHCALL_SET_CLOCKEVENT 9 #define LHCALL_SET_CLOCKEVENT 9
#define LHCALL_HALT 10 #define LHCALL_HALT 10
#define LHCALL_BIND_DMA 12
#define LHCALL_SEND_DMA 13
#define LHCALL_SET_PTE 14 #define LHCALL_SET_PTE 14
#define LHCALL_SET_PMD 15 #define LHCALL_SET_PMD 15
#define LHCALL_LOAD_TLS 16 #define LHCALL_LOAD_TLS 16
#define LHCALL_NOTIFY 17
/*G:031 First, how does our Guest contact the Host to ask for privileged /*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", * operations? There are two ways: the direct way is to make a "hypercall",
......
...@@ -10,40 +10,6 @@ ...@@ -10,40 +10,6 @@
/* How many devices? Assume each one wants up to two dma arrays per device. */ /* How many devices? Assume each one wants up to two dma arrays per device. */
#define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2) #define LGUEST_MAX_DEVICES (LGUEST_MAX_DMA/2)
/*D:200
* 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;
__u16 len[LGUEST_MAX_DMA_SECTIONS];
unsigned long addr[LGUEST_MAX_DMA_SECTIONS];
};
/*:*/
/* Where the Host expects the Guest to SEND_DMA console output to. */ /* Where the Host expects the Guest to SEND_DMA console output to. */
#define LGUEST_CONSOLE_DMA_KEY 0 #define LGUEST_CONSOLE_DMA_KEY 0
...@@ -95,7 +61,7 @@ struct lguest_device_desc { ...@@ -95,7 +61,7 @@ struct lguest_device_desc {
enum lguest_req enum lguest_req
{ {
LHREQ_INITIALIZE, /* + pfnlimit, pgdir, start, pageoffset */ 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_IRQ, /* + irq */
LHREQ_BREAK, /* + on/off flag (on blocks until someone does off) */ 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