Commit 19f1537b authored by Rusty Russell's avatar Rusty Russell

Lguest support for Virtio

This makes lguest able to use the virtio devices.

We change the device descriptor page from a simple array to a variable
length "type, config_len, status, config data..." format, and
implement virtio_config_ops to read from that config data.

We use the virtio ring implementation for an efficient Guest <-> Host
virtqueue mechanism, and the new LHCALL_NOTIFY hypercall to kick the
host when it changes.

We also use LHCALL_NOTIFY on kernel addresses for very very early
console output.  We could have another hypercall, but this hack works
quite well.
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 15045275
......@@ -2,8 +2,13 @@ config LGUEST_GUEST
bool "Lguest guest support"
select PARAVIRT
depends on !X86_PAE
select VIRTIO
select VIRTIO_RING
select VIRTIO_CONSOLE
help
Lguest is a tiny in-kernel hypervisor. Selecting this will
allow your kernel to boot under lguest. This option will increase
your kernel size by about 6k. If in doubt, say N.
If you say Y here, make sure you say Y (or M) to the virtio block
and net drivers which lguest needs.
......@@ -55,6 +55,7 @@
#include <linux/clockchips.h>
#include <linux/lguest.h>
#include <linux/lguest_launcher.h>
#include <linux/virtio_console.h>
#include <asm/paravirt.h>
#include <asm/param.h>
#include <asm/page.h>
......@@ -849,6 +850,23 @@ static __init char *lguest_memory_setup(void)
return "LGUEST";
}
/* Before virtqueues are set up, we use LHCALL_NOTIFY on normal memory to
* produce console output. */
static __init int early_put_chars(u32 vtermno, const char *buf, int count)
{
char scratch[17];
unsigned int len = count;
if (len > sizeof(scratch) - 1)
len = sizeof(scratch) - 1;
scratch[len] = '\0';
memcpy(scratch, buf, len);
hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0);
/* This routine returns the number of bytes actually written. */
return len;
}
/*G:050
* Patching (Powerfully Placating Performance Pedants)
*
......@@ -1048,6 +1066,9 @@ __init void lguest_init(void *boot)
* adapted for lguest's use. */
add_preferred_console("hvc", 0, NULL);
/* Register our very early console. */
virtio_cons_early_init(early_put_chars);
/* Last of all, we set the power management poweroff hook to point to
* the Guest routine to power off. */
pm_power_off = lguest_power_off;
......
# Guest requires the device configuration and probing code.
obj-$(CONFIG_LGUEST_GUEST) += lguest_device.o
# 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 \
......
This diff is collapsed.
......@@ -22,37 +22,28 @@
* complex burden for the Host and suboptimal for the Guest, so we have our own
* "lguest" bus and simple drivers.
*
* Devices are described by an array of LGUEST_MAX_DEVICES of these structs,
* placed by the Launcher just above the top of physical memory:
* Devices are described by a simplified ID, a status byte, and some "config"
* bytes which describe this device's configuration. This is placed by the
* Launcher just above the top of physical memory:
*/
struct lguest_device_desc {
/* The device type: console, network, disk etc. */
__u16 type;
#define LGUEST_DEVICE_T_CONSOLE 1
#define LGUEST_DEVICE_T_NET 2
#define LGUEST_DEVICE_T_BLOCK 3
/* The specific features of this device: these depends on device type
* except for LGUEST_DEVICE_F_RANDOMNESS. */
__u16 features;
#define LGUEST_NET_F_NOCSUM 0x4000 /* Don't bother checksumming */
#define LGUEST_DEVICE_F_RANDOMNESS 0x8000 /* IRQ is fairly random */
/* This is how the Guest reports status of the device: the Host can set
* LGUEST_DEVICE_S_REMOVED to indicate removal, but the rest are only
* ever manipulated by the Guest, and only ever set. */
__u16 status;
/* 256 and above are device specific. */
#define LGUEST_DEVICE_S_ACKNOWLEDGE 1 /* We have seen device. */
#define LGUEST_DEVICE_S_DRIVER 2 /* We have found a driver */
#define LGUEST_DEVICE_S_DRIVER_OK 4 /* Driver says OK! */
#define LGUEST_DEVICE_S_REMOVED 8 /* Device has gone away. */
#define LGUEST_DEVICE_S_REMOVED_ACK 16 /* Driver has been told. */
#define LGUEST_DEVICE_S_FAILED 128 /* Something actually failed */
/* The device type: console, network, disk etc. Type 0 terminates. */
__u8 type;
/* The number of bytes of the config array. */
__u8 config_len;
/* A status byte, written by the Guest. */
__u8 status;
__u8 config[0];
};
/* Each device exists somewhere in Guest physical memory, over some
* number of pages. */
__u16 num_pages;
/*D:135 This is how we expect the device configuration field for a virtqueue
* (type VIRTIO_CONFIG_F_VIRTQUEUE) to be laid out: */
struct lguest_vqconfig {
/* The number of entries in the virtio_ring */
__u16 num;
/* The interrupt we get when something happens. */
__u16 irq;
/* The page number of the virtio ring for this device. */
__u32 pfn;
};
/*:*/
......
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