OK, this has the big virtio 1.0 implementation, as specified by OASIS.
On top of tht is the major rework of lguest, to use PCI and virtio 1.0, to double-check the implementation. Then comes the inevitable fixes and cleanups from that work. Thanks, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJU5B9cAAoJENkgDmzRrbjxPacP/jajliXX353JJ/g/hkZ6oDN5 o7FhELBKiUMr7enVZYwj2BBYk5OM36nB9pQkiqHMSbjJGoS5IK70enxb4YRxSHBn YCLblZMNqutGS0kclZ9DDysztjAhxH7CvLM6pMZ7eHP0f3+FM/QhbxHfbG9DTBUH 2U/nybvd3M/+YBe7ptwQdrH8aOCAD6RTIsXellfm99dNMK6K/5lqnWQ98WSXmNXq vyvdaAQsqqUkmxtajjcBumaCH4/SehOJJjUqojCMsR3aBkgOBWDZJURMek+KA5Dt X996fBsTAlvTtCUKRrmLTb2ScDH7fu+jwbWRqMYDk8zpEr3XqiLTTPV4/TiHGmi7 Wiw3g1wIY1YbETlZyongB5MIoVyUfmDAd+bT8nBsj3KIITD84gOUQFDMl6d63c0I z6A9Pu/UzpJGsXZT3WoFLi6TO67QyhOseqZnhS4wBgLabjxffNM7yov9RVKUVH/n JHunnpUk2iTtSgscBarOBz5867dstuurnaUIspZthVBo6y6N0z+GrU+agJ8Y4DXx mvwzeYLhQH2208PjxPFiah/kA/gHNm1m678TbpS+CUsgmpQiJ4gTwtazDSi4TwZY Hs9T9GulkzpZIzEyKL3qG2TsfyDhW5Avn+GvKInAT9+Fkig4BnP3DUONBxcwGZ78 eI3FDUWsE36NqE5ECWmz =ivCe -----END PGP SIGNATURE----- Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux Pull virtio updates from Rusty Russell: "OK, this has the big virtio 1.0 implementation, as specified by OASIS. On top of tht is the major rework of lguest, to use PCI and virtio 1.0, to double-check the implementation. Then comes the inevitable fixes and cleanups from that work" * tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (80 commits) virtio: don't set VIRTIO_CONFIG_S_DRIVER_OK twice. virtio_net: unconditionally define struct virtio_net_hdr_v1. tools/lguest: don't use legacy definitions for net device in example launcher. virtio: Don't expose legacy net features when VIRTIO_NET_NO_LEGACY defined. tools/lguest: use common error macros in the example launcher. tools/lguest: give virtqueues names for better error messages tools/lguest: more documentation and checking of virtio 1.0 compliance. lguest: don't look in console features to find emerg_wr. tools/lguest: don't start devices until DRIVER_OK status set. tools/lguest: handle indirect partway through chain. tools/lguest: insert driver references from the 1.0 spec (4.1 Virtio Over PCI) tools/lguest: insert device references from the 1.0 spec (4.1 Virtio Over PCI) tools/lguest: rename virtio_pci_cfg_cap field to match spec. tools/lguest: fix features_accepted logic in example launcher. tools/lguest: handle device reset correctly in example launcher. virtual: Documentation: simplify and generalize paravirt_ops.txt lguest: remove NOTIFY call and eventfd facility. lguest: remove NOTIFY facility from demonstration launcher. lguest: use the PCI console device's emerg_wr for early boot messages. lguest: always put console in PCI slot #1. ...
This commit is contained in:
commit
53861af9a1
43 changed files with 3367 additions and 1605 deletions
|
|
@ -1,137 +0,0 @@
|
|||
Paravirt_ops on IA64
|
||||
====================
|
||||
21 May 2008, Isaku Yamahata <yamahata@valinux.co.jp>
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
The aim of this documentation is to help with maintainability and/or to
|
||||
encourage people to use paravirt_ops/IA64.
|
||||
|
||||
paravirt_ops (pv_ops in short) is a way for virtualization support of
|
||||
Linux kernel on x86. Several ways for virtualization support were
|
||||
proposed, paravirt_ops is the winner.
|
||||
On the other hand, now there are also several IA64 virtualization
|
||||
technologies like kvm/IA64, xen/IA64 and many other academic IA64
|
||||
hypervisors so that it is good to add generic virtualization
|
||||
infrastructure on Linux/IA64.
|
||||
|
||||
|
||||
What is paravirt_ops?
|
||||
---------------------
|
||||
It has been developed on x86 as virtualization support via API, not ABI.
|
||||
It allows each hypervisor to override operations which are important for
|
||||
hypervisors at API level. And it allows a single kernel binary to run on
|
||||
all supported execution environments including native machine.
|
||||
Essentially paravirt_ops is a set of function pointers which represent
|
||||
operations corresponding to low level sensitive instructions and high
|
||||
level functionalities in various area. But one significant difference
|
||||
from usual function pointer table is that it allows optimization with
|
||||
binary patch. It is because some of these operations are very
|
||||
performance sensitive and indirect call overhead is not negligible.
|
||||
With binary patch, indirect C function call can be transformed into
|
||||
direct C function call or in-place execution to eliminate the overhead.
|
||||
|
||||
Thus, operations of paravirt_ops are classified into three categories.
|
||||
- simple indirect call
|
||||
These operations correspond to high level functionality so that the
|
||||
overhead of indirect call isn't very important.
|
||||
|
||||
- indirect call which allows optimization with binary patch
|
||||
Usually these operations correspond to low level instructions. They
|
||||
are called frequently and performance critical. So the overhead is
|
||||
very important.
|
||||
|
||||
- a set of macros for hand written assembly code
|
||||
Hand written assembly codes (.S files) also need paravirtualization
|
||||
because they include sensitive instructions or some of code paths in
|
||||
them are very performance critical.
|
||||
|
||||
|
||||
The relation to the IA64 machine vector
|
||||
---------------------------------------
|
||||
Linux/IA64 has the IA64 machine vector functionality which allows the
|
||||
kernel to switch implementations (e.g. initialization, ipi, dma api...)
|
||||
depending on executing platform.
|
||||
We can replace some implementations very easily defining a new machine
|
||||
vector. Thus another approach for virtualization support would be
|
||||
enhancing the machine vector functionality.
|
||||
But paravirt_ops approach was taken because
|
||||
- virtualization support needs wider support than machine vector does.
|
||||
e.g. low level instruction paravirtualization. It must be
|
||||
initialized very early before platform detection.
|
||||
|
||||
- virtualization support needs more functionality like binary patch.
|
||||
Probably the calling overhead might not be very large compared to the
|
||||
emulation overhead of virtualization. However in the native case, the
|
||||
overhead should be eliminated completely.
|
||||
A single kernel binary should run on each environment including native,
|
||||
and the overhead of paravirt_ops on native environment should be as
|
||||
small as possible.
|
||||
|
||||
- for full virtualization technology, e.g. KVM/IA64 or
|
||||
Xen/IA64 HVM domain, the result would be
|
||||
(the emulated platform machine vector. probably dig) + (pv_ops).
|
||||
This means that the virtualization support layer should be under
|
||||
the machine vector layer.
|
||||
|
||||
Possibly it might be better to move some function pointers from
|
||||
paravirt_ops to machine vector. In fact, Xen domU case utilizes both
|
||||
pv_ops and machine vector.
|
||||
|
||||
|
||||
IA64 paravirt_ops
|
||||
-----------------
|
||||
In this section, the concrete paravirt_ops will be discussed.
|
||||
Because of the architecture difference between ia64 and x86, the
|
||||
resulting set of functions is very different from x86 pv_ops.
|
||||
|
||||
- C function pointer tables
|
||||
They are not very performance critical so that simple C indirect
|
||||
function call is acceptable. The following structures are defined at
|
||||
this moment. For details see linux/include/asm-ia64/paravirt.h
|
||||
- struct pv_info
|
||||
This structure describes the execution environment.
|
||||
- struct pv_init_ops
|
||||
This structure describes the various initialization hooks.
|
||||
- struct pv_iosapic_ops
|
||||
This structure describes hooks to iosapic operations.
|
||||
- struct pv_irq_ops
|
||||
This structure describes hooks to irq related operations
|
||||
- struct pv_time_op
|
||||
This structure describes hooks to steal time accounting.
|
||||
|
||||
- a set of indirect calls which need optimization
|
||||
Currently this class of functions correspond to a subset of IA64
|
||||
intrinsics. At this moment the optimization with binary patch isn't
|
||||
implemented yet.
|
||||
struct pv_cpu_op is defined. For details see
|
||||
linux/include/asm-ia64/paravirt_privop.h
|
||||
Mostly they correspond to ia64 intrinsics 1-to-1.
|
||||
Caveat: Now they are defined as C indirect function pointers, but in
|
||||
order to support binary patch optimization, they will be changed
|
||||
using GCC extended inline assembly code.
|
||||
|
||||
- a set of macros for hand written assembly code (.S files)
|
||||
For maintenance purpose, the taken approach for .S files is single
|
||||
source code and compile multiple times with different macros definitions.
|
||||
Each pv_ops instance must define those macros to compile.
|
||||
The important thing here is that sensitive, but non-privileged
|
||||
instructions must be paravirtualized and that some privileged
|
||||
instructions also need paravirtualization for reasonable performance.
|
||||
Developers who modify .S files must be aware of that. At this moment
|
||||
an easy checker is implemented to detect paravirtualization breakage.
|
||||
But it doesn't cover all the cases.
|
||||
|
||||
Sometimes this set of macros is called pv_cpu_asm_op. But there is no
|
||||
corresponding structure in the source code.
|
||||
Those macros mostly 1:1 correspond to a subset of privileged
|
||||
instructions. See linux/include/asm-ia64/native/inst.h.
|
||||
And some functions written in assembly also need to be overrided so
|
||||
that each pv_ops instance have to define some macros. Again see
|
||||
linux/include/asm-ia64/native/inst.h.
|
||||
|
||||
|
||||
Those structures must be initialized very early before start_kernel.
|
||||
Probably initialized in head.S using multi entry point or some other trick.
|
||||
For native case implementation see linux/arch/ia64/kernel/paravirt.c.
|
||||
|
|
@ -2,6 +2,9 @@ Virtualization support in the Linux kernel.
|
|||
|
||||
00-INDEX
|
||||
- this file.
|
||||
|
||||
paravirt_ops.txt
|
||||
- Describes the Linux kernel pv_ops to support different hypervisors
|
||||
kvm/
|
||||
- Kernel Virtual Machine. See also http://linux-kvm.org
|
||||
uml/
|
||||
|
|
|
|||
32
Documentation/virtual/paravirt_ops.txt
Normal file
32
Documentation/virtual/paravirt_ops.txt
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
Paravirt_ops
|
||||
============
|
||||
|
||||
Linux provides support for different hypervisor virtualization technologies.
|
||||
Historically different binary kernels would be required in order to support
|
||||
different hypervisors, this restriction was removed with pv_ops.
|
||||
Linux pv_ops is a virtualization API which enables support for different
|
||||
hypervisors. It allows each hypervisor to override critical operations and
|
||||
allows a single kernel binary to run on all supported execution environments
|
||||
including native machine -- without any hypervisors.
|
||||
|
||||
pv_ops provides a set of function pointers which represent operations
|
||||
corresponding to low level critical instructions and high level
|
||||
functionalities in various areas. pv-ops allows for optimizations at run
|
||||
time by enabling binary patching of the low-ops critical operations
|
||||
at boot time.
|
||||
|
||||
pv_ops operations are classified into three categories:
|
||||
|
||||
- simple indirect call
|
||||
These operations correspond to high level functionality where it is
|
||||
known that the overhead of indirect call isn't very important.
|
||||
|
||||
- indirect call which allows optimization with binary patch
|
||||
Usually these operations correspond to low level critical instructions. They
|
||||
are called frequently and are performance critical. The overhead is
|
||||
very important.
|
||||
|
||||
- a set of macros for hand written assembly code
|
||||
Hand written assembly codes (.S files) also need paravirtualization
|
||||
because they include sensitive instructions or some of code paths in
|
||||
them are very performance critical.
|
||||
|
|
@ -7302,7 +7302,7 @@ M: Alok Kataria <akataria@vmware.com>
|
|||
M: Rusty Russell <rusty@rustcorp.com.au>
|
||||
L: virtualization@lists.linux-foundation.org
|
||||
S: Supported
|
||||
F: Documentation/ia64/paravirt_ops.txt
|
||||
F: Documentation/virtual/paravirt_ops.txt
|
||||
F: arch/*/kernel/paravirt*
|
||||
F: arch/*/include/asm/paravirt.h
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
/* ASB2305 PCI I/O mapping handler
|
||||
*
|
||||
* Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public Licence
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Create a virtual mapping cookie for a PCI BAR (memory or IO)
|
||||
*/
|
||||
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
|
||||
{
|
||||
resource_size_t start = pci_resource_start(dev, bar);
|
||||
resource_size_t len = pci_resource_len(dev, bar);
|
||||
unsigned long flags = pci_resource_flags(dev, bar);
|
||||
|
||||
if (!len || !start)
|
||||
return NULL;
|
||||
|
||||
if ((flags & IORESOURCE_IO) || (flags & IORESOURCE_MEM)) {
|
||||
if (flags & IORESOURCE_CACHEABLE && !(flags & IORESOURCE_IO))
|
||||
return ioremap(start, len);
|
||||
else
|
||||
return ioremap_nocache(start, len);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(pci_iomap);
|
||||
|
|
@ -16,6 +16,7 @@
|
|||
struct zpci_iomap_entry {
|
||||
u32 fh;
|
||||
u8 bar;
|
||||
u16 count;
|
||||
};
|
||||
|
||||
extern struct zpci_iomap_entry *zpci_iomap_start;
|
||||
|
|
|
|||
|
|
@ -259,7 +259,10 @@ void __iowrite64_copy(void __iomem *to, const void *from, size_t count)
|
|||
}
|
||||
|
||||
/* Create a virtual mapping cookie for a PCI BAR */
|
||||
void __iomem *pci_iomap(struct pci_dev *pdev, int bar, unsigned long max)
|
||||
void __iomem *pci_iomap_range(struct pci_dev *pdev,
|
||||
int bar,
|
||||
unsigned long offset,
|
||||
unsigned long max)
|
||||
{
|
||||
struct zpci_dev *zdev = get_zdev(pdev);
|
||||
u64 addr;
|
||||
|
|
@ -270,14 +273,27 @@ void __iomem *pci_iomap(struct pci_dev *pdev, int bar, unsigned long max)
|
|||
|
||||
idx = zdev->bars[bar].map_idx;
|
||||
spin_lock(&zpci_iomap_lock);
|
||||
zpci_iomap_start[idx].fh = zdev->fh;
|
||||
zpci_iomap_start[idx].bar = bar;
|
||||
if (zpci_iomap_start[idx].count++) {
|
||||
BUG_ON(zpci_iomap_start[idx].fh != zdev->fh ||
|
||||
zpci_iomap_start[idx].bar != bar);
|
||||
} else {
|
||||
zpci_iomap_start[idx].fh = zdev->fh;
|
||||
zpci_iomap_start[idx].bar = bar;
|
||||
}
|
||||
/* Detect overrun */
|
||||
BUG_ON(!zpci_iomap_start[idx].count);
|
||||
spin_unlock(&zpci_iomap_lock);
|
||||
|
||||
addr = ZPCI_IOMAP_ADDR_BASE | ((u64) idx << 48);
|
||||
return (void __iomem *) addr;
|
||||
return (void __iomem *) addr + offset;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_iomap);
|
||||
EXPORT_SYMBOL_GPL(pci_iomap_range);
|
||||
|
||||
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
|
||||
{
|
||||
return pci_iomap_range(dev, bar, 0, maxlen);
|
||||
}
|
||||
EXPORT_SYMBOL(pci_iomap);
|
||||
|
||||
void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
|
||||
{
|
||||
|
|
@ -285,8 +301,12 @@ void pci_iounmap(struct pci_dev *pdev, void __iomem *addr)
|
|||
|
||||
idx = (((__force u64) addr) & ~ZPCI_IOMAP_ADDR_BASE) >> 48;
|
||||
spin_lock(&zpci_iomap_lock);
|
||||
zpci_iomap_start[idx].fh = 0;
|
||||
zpci_iomap_start[idx].bar = 0;
|
||||
/* Detect underrun */
|
||||
BUG_ON(!zpci_iomap_start[idx].count);
|
||||
if (!--zpci_iomap_start[idx].count) {
|
||||
zpci_iomap_start[idx].fh = 0;
|
||||
zpci_iomap_start[idx].bar = 0;
|
||||
}
|
||||
spin_unlock(&zpci_iomap_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_iounmap);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
#define LHCALL_SET_PTE 14
|
||||
#define LHCALL_SET_PGD 15
|
||||
#define LHCALL_LOAD_TLS 16
|
||||
#define LHCALL_NOTIFY 17
|
||||
#define LHCALL_LOAD_GDT_ENTRY 18
|
||||
#define LHCALL_SEND_INTERRUPTS 19
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,9 @@
|
|||
#include <linux/virtio_console.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/virtio_pci.h>
|
||||
#include <asm/acpi.h>
|
||||
#include <asm/apic.h>
|
||||
#include <asm/lguest.h>
|
||||
#include <asm/paravirt.h>
|
||||
|
|
@ -71,6 +74,8 @@
|
|||
#include <asm/stackprotector.h>
|
||||
#include <asm/reboot.h> /* for struct machine_ops */
|
||||
#include <asm/kvm_para.h>
|
||||
#include <asm/pci_x86.h>
|
||||
#include <asm/pci-direct.h>
|
||||
|
||||
/*G:010
|
||||
* Welcome to the Guest!
|
||||
|
|
@ -831,6 +836,24 @@ static struct irq_chip lguest_irq_controller = {
|
|||
.irq_unmask = enable_lguest_irq,
|
||||
};
|
||||
|
||||
static int lguest_enable_irq(struct pci_dev *dev)
|
||||
{
|
||||
u8 line = 0;
|
||||
|
||||
/* We literally use the PCI interrupt line as the irq number. */
|
||||
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &line);
|
||||
irq_set_chip_and_handler_name(line, &lguest_irq_controller,
|
||||
handle_level_irq, "level");
|
||||
dev->irq = line;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We don't do hotplug PCI, so this shouldn't be called. */
|
||||
static void lguest_disable_irq(struct pci_dev *dev)
|
||||
{
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This sets up the Interrupt Descriptor Table (IDT) entry for each hardware
|
||||
* interrupt (except 128, which is used for system calls), and then tells the
|
||||
|
|
@ -1181,25 +1204,136 @@ static __init char *lguest_memory_setup(void)
|
|||
return "LGUEST";
|
||||
}
|
||||
|
||||
/* Offset within PCI config space of BAR access capability. */
|
||||
static int console_cfg_offset = 0;
|
||||
static int console_access_cap;
|
||||
|
||||
/* Set up so that we access off in bar0 (on bus 0, device 1, function 0) */
|
||||
static void set_cfg_window(u32 cfg_offset, u32 off)
|
||||
{
|
||||
write_pci_config_byte(0, 1, 0,
|
||||
cfg_offset + offsetof(struct virtio_pci_cap, bar),
|
||||
0);
|
||||
write_pci_config(0, 1, 0,
|
||||
cfg_offset + offsetof(struct virtio_pci_cap, length),
|
||||
4);
|
||||
write_pci_config(0, 1, 0,
|
||||
cfg_offset + offsetof(struct virtio_pci_cap, offset),
|
||||
off);
|
||||
}
|
||||
|
||||
static void write_bar_via_cfg(u32 cfg_offset, u32 off, u32 val)
|
||||
{
|
||||
/*
|
||||
* We could set this up once, then leave it; nothing else in the *
|
||||
* kernel should touch these registers. But if it went wrong, that
|
||||
* would be a horrible bug to find.
|
||||
*/
|
||||
set_cfg_window(cfg_offset, off);
|
||||
write_pci_config(0, 1, 0,
|
||||
cfg_offset + sizeof(struct virtio_pci_cap), val);
|
||||
}
|
||||
|
||||
static void probe_pci_console(void)
|
||||
{
|
||||
u8 cap, common_cap = 0, device_cap = 0;
|
||||
/* Offset within BAR0 */
|
||||
u32 device_offset;
|
||||
u32 device_len;
|
||||
|
||||
/* Avoid recursive printk into here. */
|
||||
console_cfg_offset = -1;
|
||||
|
||||
if (!early_pci_allowed()) {
|
||||
printk(KERN_ERR "lguest: early PCI access not allowed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* We expect a console PCI device at BUS0, slot 1. */
|
||||
if (read_pci_config(0, 1, 0, 0) != 0x10431AF4) {
|
||||
printk(KERN_ERR "lguest: PCI device is %#x!\n",
|
||||
read_pci_config(0, 1, 0, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Find the capabilities we need (must be in bar0) */
|
||||
cap = read_pci_config_byte(0, 1, 0, PCI_CAPABILITY_LIST);
|
||||
while (cap) {
|
||||
u8 vndr = read_pci_config_byte(0, 1, 0, cap);
|
||||
if (vndr == PCI_CAP_ID_VNDR) {
|
||||
u8 type, bar;
|
||||
u32 offset, length;
|
||||
|
||||
type = read_pci_config_byte(0, 1, 0,
|
||||
cap + offsetof(struct virtio_pci_cap, cfg_type));
|
||||
bar = read_pci_config_byte(0, 1, 0,
|
||||
cap + offsetof(struct virtio_pci_cap, bar));
|
||||
offset = read_pci_config(0, 1, 0,
|
||||
cap + offsetof(struct virtio_pci_cap, offset));
|
||||
length = read_pci_config(0, 1, 0,
|
||||
cap + offsetof(struct virtio_pci_cap, length));
|
||||
|
||||
switch (type) {
|
||||
case VIRTIO_PCI_CAP_DEVICE_CFG:
|
||||
if (bar == 0) {
|
||||
device_cap = cap;
|
||||
device_offset = offset;
|
||||
device_len = length;
|
||||
}
|
||||
break;
|
||||
case VIRTIO_PCI_CAP_PCI_CFG:
|
||||
console_access_cap = cap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
cap = read_pci_config_byte(0, 1, 0, cap + PCI_CAP_LIST_NEXT);
|
||||
}
|
||||
if (!device_cap || !console_access_cap) {
|
||||
printk(KERN_ERR "lguest: No caps (%u/%u/%u) in console!\n",
|
||||
common_cap, device_cap, console_access_cap);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we can't check features, until we've set the DRIVER
|
||||
* status bit. We don't want to do that until we have a real driver,
|
||||
* so we just check that the device-specific config has room for
|
||||
* emerg_wr. If it doesn't support VIRTIO_CONSOLE_F_EMERG_WRITE
|
||||
* it should ignore the access.
|
||||
*/
|
||||
if (device_len < (offsetof(struct virtio_console_config, emerg_wr)
|
||||
+ sizeof(u32))) {
|
||||
printk(KERN_ERR "lguest: console missing emerg_wr field\n");
|
||||
return;
|
||||
}
|
||||
|
||||
console_cfg_offset = device_offset;
|
||||
printk(KERN_INFO "lguest: Console via virtio-pci emerg_wr\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* We will eventually use the virtio console device to produce console output,
|
||||
* but before that is set up we use LHCALL_NOTIFY on normal memory to produce
|
||||
* console output.
|
||||
* but before that is set up we use the virtio PCI console's backdoor mmio
|
||||
* access and the "emergency" write facility (which is legal even before the
|
||||
* device is configured).
|
||||
*/
|
||||
static __init int early_put_chars(u32 vtermno, const char *buf, int count)
|
||||
{
|
||||
char scratch[17];
|
||||
unsigned int len = count;
|
||||
/* If we couldn't find PCI console, forget it. */
|
||||
if (console_cfg_offset < 0)
|
||||
return count;
|
||||
|
||||
/* We use a nul-terminated string, so we make a copy. Icky, huh? */
|
||||
if (len > sizeof(scratch) - 1)
|
||||
len = sizeof(scratch) - 1;
|
||||
scratch[len] = '\0';
|
||||
memcpy(scratch, buf, len);
|
||||
hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0, 0);
|
||||
if (unlikely(!console_cfg_offset)) {
|
||||
probe_pci_console();
|
||||
if (console_cfg_offset < 0)
|
||||
return count;
|
||||
}
|
||||
|
||||
/* This routine returns the number of bytes actually written. */
|
||||
return len;
|
||||
write_bar_via_cfg(console_access_cap,
|
||||
console_cfg_offset
|
||||
+ offsetof(struct virtio_console_config, emerg_wr),
|
||||
buf[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1399,14 +1533,6 @@ __init void lguest_init(void)
|
|||
/* Hook in our special panic hypercall code. */
|
||||
atomic_notifier_chain_register(&panic_notifier_list, &paniced);
|
||||
|
||||
/*
|
||||
* The IDE code spends about 3 seconds probing for disks: if we reserve
|
||||
* all the I/O ports up front it can't get them and so doesn't probe.
|
||||
* Other device drivers are similar (but less severe). This cuts the
|
||||
* kernel boot time on my machine from 4.1 seconds to 0.45 seconds.
|
||||
*/
|
||||
paravirt_disable_iospace();
|
||||
|
||||
/*
|
||||
* This is messy CPU setup stuff which the native boot code does before
|
||||
* start_kernel, so we have to do, too:
|
||||
|
|
@ -1436,6 +1562,13 @@ __init void lguest_init(void)
|
|||
/* Register our very early console. */
|
||||
virtio_cons_early_init(early_put_chars);
|
||||
|
||||
/* Don't let ACPI try to control our PCI interrupts. */
|
||||
disable_acpi();
|
||||
|
||||
/* We control them ourselves, by overriding these two hooks. */
|
||||
pcibios_enable_irq = lguest_enable_irq;
|
||||
pcibios_disable_irq = lguest_disable_irq;
|
||||
|
||||
/*
|
||||
* Last of all, we set the power management poweroff hook to point to
|
||||
* the Guest routine to power off, and the reboot hook to our restart
|
||||
|
|
|
|||
|
|
@ -28,8 +28,7 @@ struct virtio_blk_vq {
|
|||
char name[VQ_NAME_LEN];
|
||||
} ____cacheline_aligned_in_smp;
|
||||
|
||||
struct virtio_blk
|
||||
{
|
||||
struct virtio_blk {
|
||||
struct virtio_device *vdev;
|
||||
|
||||
/* The disk structure for the kernel. */
|
||||
|
|
@ -52,8 +51,7 @@ struct virtio_blk
|
|||
struct virtio_blk_vq *vqs;
|
||||
};
|
||||
|
||||
struct virtblk_req
|
||||
{
|
||||
struct virtblk_req {
|
||||
struct request *req;
|
||||
struct virtio_blk_outhdr out_hdr;
|
||||
struct virtio_scsi_inhdr in_hdr;
|
||||
|
|
@ -575,6 +573,12 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
u16 min_io_size;
|
||||
u8 physical_block_exp, alignment_offset;
|
||||
|
||||
if (!vdev->config->get) {
|
||||
dev_err(&vdev->dev, "%s failure: config access disabled\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS),
|
||||
GFP_KERNEL);
|
||||
if (err < 0)
|
||||
|
|
|
|||
|
|
@ -1986,7 +1986,10 @@ static int virtcons_probe(struct virtio_device *vdev)
|
|||
bool multiport;
|
||||
bool early = early_put_chars != NULL;
|
||||
|
||||
if (!vdev->config->get) {
|
||||
/* We only need a config space if features are offered */
|
||||
if (!vdev->config->get &&
|
||||
(virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)
|
||||
|| virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT))) {
|
||||
dev_err(&vdev->dev, "%s failure: config access disabled\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,3 @@
|
|||
# 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 \
|
||||
|
|
|
|||
|
|
@ -208,6 +208,14 @@ void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
|
|||
*/
|
||||
int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
|
||||
{
|
||||
/* If the launcher asked for a register with LHREQ_GETREG */
|
||||
if (cpu->reg_read) {
|
||||
if (put_user(*cpu->reg_read, user))
|
||||
return -EFAULT;
|
||||
cpu->reg_read = NULL;
|
||||
return sizeof(*cpu->reg_read);
|
||||
}
|
||||
|
||||
/* We stop running once the Guest is dead. */
|
||||
while (!cpu->lg->dead) {
|
||||
unsigned int irq;
|
||||
|
|
@ -217,21 +225,12 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
|
|||
if (cpu->hcall)
|
||||
do_hypercalls(cpu);
|
||||
|
||||
/*
|
||||
* It's possible the Guest did a NOTIFY hypercall to the
|
||||
* 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 Launcher. */
|
||||
if (put_user(cpu->pending_notify, user))
|
||||
return -EFAULT;
|
||||
return sizeof(cpu->pending_notify);
|
||||
}
|
||||
/* Do we have to tell the Launcher about a trap? */
|
||||
if (cpu->pending.trap) {
|
||||
if (copy_to_user(user, &cpu->pending,
|
||||
sizeof(cpu->pending)))
|
||||
return -EFAULT;
|
||||
return sizeof(cpu->pending);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -117,9 +117,6 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
|
|||
/* Similarly, this sets the halted flag for run_guest(). */
|
||||
cpu->halted = 1;
|
||||
break;
|
||||
case LHCALL_NOTIFY:
|
||||
cpu->pending_notify = args->arg1;
|
||||
break;
|
||||
default:
|
||||
/* It should be an architecture-specific hypercall. */
|
||||
if (lguest_arch_do_hcall(cpu, args))
|
||||
|
|
@ -189,7 +186,7 @@ static void do_async_hcalls(struct lg_cpu *cpu)
|
|||
* Stop doing hypercalls if they want to notify the Launcher:
|
||||
* it needs to service this first.
|
||||
*/
|
||||
if (cpu->pending_notify)
|
||||
if (cpu->pending.trap)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +277,7 @@ void do_hypercalls(struct lg_cpu *cpu)
|
|||
* NOTIFY to the Launcher, we want to return now. Otherwise we do
|
||||
* the hypercall.
|
||||
*/
|
||||
if (!cpu->pending_notify) {
|
||||
if (!cpu->pending.trap) {
|
||||
do_hcall(cpu, cpu->hcall);
|
||||
/*
|
||||
* Tricky point: we reset the hcall pointer to mark the
|
||||
|
|
|
|||
|
|
@ -50,7 +50,10 @@ struct lg_cpu {
|
|||
/* Bitmap of what has changed: see CHANGED_* above. */
|
||||
int changed;
|
||||
|
||||
unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
|
||||
/* Pending operation. */
|
||||
struct lguest_pending pending;
|
||||
|
||||
unsigned long *reg_read; /* register from LHREQ_GETREG */
|
||||
|
||||
/* At end of a page shared mapped over lguest_pages in guest. */
|
||||
unsigned long regs_page;
|
||||
|
|
@ -78,24 +81,18 @@ struct lg_cpu {
|
|||
struct lg_cpu_arch arch;
|
||||
};
|
||||
|
||||
struct lg_eventfd {
|
||||
unsigned long addr;
|
||||
struct eventfd_ctx *event;
|
||||
};
|
||||
|
||||
struct lg_eventfd_map {
|
||||
unsigned int num;
|
||||
struct lg_eventfd map[];
|
||||
};
|
||||
|
||||
/* The private info the thread maintains about the guest. */
|
||||
struct lguest {
|
||||
struct lguest_data __user *lguest_data;
|
||||
struct lg_cpu cpus[NR_CPUS];
|
||||
unsigned int nr_cpus;
|
||||
|
||||
/* Valid guest memory pages must be < this. */
|
||||
u32 pfn_limit;
|
||||
|
||||
/* Device memory is >= pfn_limit and < device_limit. */
|
||||
u32 device_limit;
|
||||
|
||||
/*
|
||||
* This provides the offset to the base of guest-physical memory in the
|
||||
* Launcher.
|
||||
|
|
@ -110,8 +107,6 @@ struct lguest {
|
|||
unsigned int stack_pages;
|
||||
u32 tsc_khz;
|
||||
|
||||
struct lg_eventfd_map *eventfds;
|
||||
|
||||
/* Dead? */
|
||||
const char *dead;
|
||||
};
|
||||
|
|
@ -197,8 +192,10 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu);
|
|||
void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
|
||||
unsigned long vaddr, pte_t val);
|
||||
void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
|
||||
bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
|
||||
bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode,
|
||||
unsigned long *iomem);
|
||||
void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
|
||||
bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr);
|
||||
unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
|
||||
void page_table_guest_data_init(struct lg_cpu *cpu);
|
||||
|
||||
|
|
@ -210,6 +207,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu);
|
|||
int lguest_arch_init_hypercalls(struct lg_cpu *cpu);
|
||||
int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args);
|
||||
void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start);
|
||||
unsigned long *lguest_arch_regptr(struct lg_cpu *cpu, size_t reg_off, bool any);
|
||||
|
||||
/* <arch>/switcher.S: */
|
||||
extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
|
||||
|
|
|
|||
|
|
@ -1,540 +0,0 @@
|
|||
/*P:050
|
||||
* Lguest guests use a very simple method to describe devices. It's a
|
||||
* series of device descriptors contained just above the top of normal Guest
|
||||
* memory.
|
||||
*
|
||||
* We use the standard "virtio" device infrastructure, which provides us with a
|
||||
* console, a network and a block driver. Each one expects some configuration
|
||||
* information and a "virtqueue" or two to send and receive data.
|
||||
:*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/lguest_launcher.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/virtio_ring.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/paravirt.h>
|
||||
#include <asm/lguest_hcall.h>
|
||||
|
||||
/* The pointer to our (page) of device descriptions. */
|
||||
static void *lguest_devices;
|
||||
|
||||
/*
|
||||
* For Guests, device memory can be used as normal memory, so we cast away the
|
||||
* __iomem to quieten sparse.
|
||||
*/
|
||||
static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
|
||||
{
|
||||
return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
|
||||
}
|
||||
|
||||
static inline void lguest_unmap(void *addr)
|
||||
{
|
||||
iounmap((__force void __iomem *)addr);
|
||||
}
|
||||
|
||||
/*D:100
|
||||
* Each lguest device is just a virtio device plus a pointer to its entry
|
||||
* in the lguest_devices page.
|
||||
*/
|
||||
struct lguest_device {
|
||||
struct virtio_device vdev;
|
||||
|
||||
/* The entry in the lguest_devices page for this device. */
|
||||
struct lguest_device_desc *desc;
|
||||
};
|
||||
|
||||
/*
|
||||
* Since the virtio infrastructure hands us a pointer to the virtio_device all
|
||||
* the time, it helps to have a curt macro to get a pointer to the struct
|
||||
* lguest_device it's enclosed in.
|
||||
*/
|
||||
#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)
|
||||
|
||||
/*D:130
|
||||
* Device configurations
|
||||
*
|
||||
* The configuration information for a device consists of one or more
|
||||
* virtqueues, a feature bitmap, and some configuration bytes. The
|
||||
* configuration bytes don't really matter to us: the Launcher sets them up, and
|
||||
* the driver will look at them during setup.
|
||||
*
|
||||
* A convenient routine to return the device's virtqueue config array:
|
||||
* immediately after the descriptor.
|
||||
*/
|
||||
static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
|
||||
{
|
||||
return (void *)(desc + 1);
|
||||
}
|
||||
|
||||
/* The features come immediately after the virtqueues. */
|
||||
static u8 *lg_features(const struct lguest_device_desc *desc)
|
||||
{
|
||||
return (void *)(lg_vq(desc) + desc->num_vq);
|
||||
}
|
||||
|
||||
/* The config space comes after the two feature bitmasks. */
|
||||
static u8 *lg_config(const struct lguest_device_desc *desc)
|
||||
{
|
||||
return lg_features(desc) + desc->feature_len * 2;
|
||||
}
|
||||
|
||||
/* The total size of the config page used by this device (incl. desc) */
|
||||
static unsigned desc_size(const struct lguest_device_desc *desc)
|
||||
{
|
||||
return sizeof(*desc)
|
||||
+ desc->num_vq * sizeof(struct lguest_vqconfig)
|
||||
+ desc->feature_len * 2
|
||||
+ desc->config_len;
|
||||
}
|
||||
|
||||
/* This gets the device's feature bits. */
|
||||
static u64 lg_get_features(struct virtio_device *vdev)
|
||||
{
|
||||
unsigned int i;
|
||||
u32 features = 0;
|
||||
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
|
||||
u8 *in_features = lg_features(desc);
|
||||
|
||||
/* We do this the slow but generic way. */
|
||||
for (i = 0; i < min(desc->feature_len * 8, 32); i++)
|
||||
if (in_features[i / 8] & (1 << (i % 8)))
|
||||
features |= (1 << i);
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
/*
|
||||
* To notify on reset or feature finalization, we (ab)use the NOTIFY
|
||||
* hypercall, with the descriptor address of the device.
|
||||
*/
|
||||
static void status_notify(struct virtio_device *vdev)
|
||||
{
|
||||
unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
|
||||
|
||||
hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* The virtio core takes the features the Host offers, and copies the ones
|
||||
* supported by the driver into the vdev->features array. Once that's all
|
||||
* sorted out, this routine is called so we can tell the Host which features we
|
||||
* understand and accept.
|
||||
*/
|
||||
static int lg_finalize_features(struct virtio_device *vdev)
|
||||
{
|
||||
unsigned int i, bits;
|
||||
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
|
||||
/* Second half of bitmap is features we accept. */
|
||||
u8 *out_features = lg_features(desc) + desc->feature_len;
|
||||
|
||||
/* Give virtio_ring a chance to accept features. */
|
||||
vring_transport_features(vdev);
|
||||
|
||||
/* Make sure we don't have any features > 32 bits! */
|
||||
BUG_ON((u32)vdev->features != vdev->features);
|
||||
|
||||
/*
|
||||
* Since lguest is currently x86-only, we're little-endian. That
|
||||
* means we could just memcpy. But it's not time critical, and in
|
||||
* case someone copies this code, we do it the slow, obvious way.
|
||||
*/
|
||||
memset(out_features, 0, desc->feature_len);
|
||||
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
|
||||
for (i = 0; i < bits; i++) {
|
||||
if (__virtio_test_bit(vdev, i))
|
||||
out_features[i / 8] |= (1 << (i % 8));
|
||||
}
|
||||
|
||||
/* Tell Host we've finished with this device's feature negotiation */
|
||||
status_notify(vdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Once they've found a field, getting a copy of it is easy. */
|
||||
static void lg_get(struct virtio_device *vdev, unsigned int offset,
|
||||
void *buf, unsigned len)
|
||||
{
|
||||
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
|
||||
|
||||
/* Check they didn't ask for more than the length of the config! */
|
||||
BUG_ON(offset + len > desc->config_len);
|
||||
memcpy(buf, lg_config(desc) + offset, len);
|
||||
}
|
||||
|
||||
/* Setting the contents is also trivial. */
|
||||
static void lg_set(struct virtio_device *vdev, unsigned int offset,
|
||||
const void *buf, unsigned len)
|
||||
{
|
||||
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
|
||||
|
||||
/* Check they didn't ask for more than the length of the config! */
|
||||
BUG_ON(offset + len > desc->config_len);
|
||||
memcpy(lg_config(desc) + offset, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* The operations to get and set the status word just access the status field
|
||||
* of the device descriptor.
|
||||
*/
|
||||
static u8 lg_get_status(struct virtio_device *vdev)
|
||||
{
|
||||
return to_lgdev(vdev)->desc->status;
|
||||
}
|
||||
|
||||
static void lg_set_status(struct virtio_device *vdev, u8 status)
|
||||
{
|
||||
BUG_ON(!status);
|
||||
to_lgdev(vdev)->desc->status = status;
|
||||
|
||||
/* Tell Host immediately if we failed. */
|
||||
if (status & VIRTIO_CONFIG_S_FAILED)
|
||||
status_notify(vdev);
|
||||
}
|
||||
|
||||
static void lg_reset(struct virtio_device *vdev)
|
||||
{
|
||||
/* 0 status means "reset" */
|
||||
to_lgdev(vdev)->desc->status = 0;
|
||||
status_notify(vdev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Virtqueues
|
||||
*
|
||||
* The other piece of infrastructure virtio needs is a "virtqueue": a way of
|
||||
* the Guest device registering buffers for the other side to read from or
|
||||
* write into (ie. send and receive buffers). Each device can have multiple
|
||||
* virtqueues: for example the console driver uses one queue for sending and
|
||||
* another for receiving.
|
||||
*
|
||||
* Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
|
||||
* already exists in virtio_ring.c. We just need to connect it up.
|
||||
*
|
||||
* We start with the information we need to keep about each virtqueue.
|
||||
*/
|
||||
|
||||
/*D:140 This is the information we remember about each virtqueue. */
|
||||
struct lguest_vq_info {
|
||||
/* A copy of the information contained in the device config. */
|
||||
struct lguest_vqconfig config;
|
||||
|
||||
/* The address where we mapped the virtio ring, so we can unmap it. */
|
||||
void *pages;
|
||||
};
|
||||
|
||||
/*
|
||||
* When the virtio_ring code wants to prod the Host, it calls us here and we
|
||||
* make a hypercall. We hand the physical address of the virtqueue so the Host
|
||||
* knows which virtqueue we're talking about.
|
||||
*/
|
||||
static bool lg_notify(struct virtqueue *vq)
|
||||
{
|
||||
/*
|
||||
* We store our virtqueue information in the "priv" pointer of the
|
||||
* virtqueue structure.
|
||||
*/
|
||||
struct lguest_vq_info *lvq = vq->priv;
|
||||
|
||||
hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* An extern declaration inside a C file is bad form. Don't do it. */
|
||||
extern int lguest_setup_irq(unsigned int irq);
|
||||
|
||||
/*
|
||||
* This routine finds the Nth virtqueue described in the configuration of
|
||||
* this device and sets it up.
|
||||
*
|
||||
* This is kind of an ugly duckling. It'd be nicer to have a standard
|
||||
* representation of a virtqueue in the configuration space, but it seems that
|
||||
* everyone wants to do it differently. The KVM coders want the Guest to
|
||||
* allocate its own pages and tell the Host where they are, but for lguest it's
|
||||
* simpler for the Host to simply tell us where the pages are.
|
||||
*/
|
||||
static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
|
||||
unsigned index,
|
||||
void (*callback)(struct virtqueue *vq),
|
||||
const char *name)
|
||||
{
|
||||
struct lguest_device *ldev = to_lgdev(vdev);
|
||||
struct lguest_vq_info *lvq;
|
||||
struct virtqueue *vq;
|
||||
int err;
|
||||
|
||||
if (!name)
|
||||
return NULL;
|
||||
|
||||
/* We must have this many virtqueues. */
|
||||
if (index >= ldev->desc->num_vq)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
|
||||
if (!lvq)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
/*
|
||||
* Make a copy of the "struct lguest_vqconfig" entry, which sits after
|
||||
* the descriptor. We need a copy because the config space might not
|
||||
* be aligned correctly.
|
||||
*/
|
||||
memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
|
||||
|
||||
printk("Mapping virtqueue %i addr %lx\n", index,
|
||||
(unsigned long)lvq->config.pfn << PAGE_SHIFT);
|
||||
/* Figure out how many pages the ring will take, and map that memory */
|
||||
lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
|
||||
DIV_ROUND_UP(vring_size(lvq->config.num,
|
||||
LGUEST_VRING_ALIGN),
|
||||
PAGE_SIZE));
|
||||
if (!lvq->pages) {
|
||||
err = -ENOMEM;
|
||||
goto free_lvq;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, tell virtio_ring.c to set up a virtqueue now we know its size
|
||||
* and we've got a pointer to its pages. Note that we set weak_barriers
|
||||
* to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu
|
||||
* barriers.
|
||||
*/
|
||||
vq = vring_new_virtqueue(index, lvq->config.num, LGUEST_VRING_ALIGN, vdev,
|
||||
true, lvq->pages, lg_notify, callback, name);
|
||||
if (!vq) {
|
||||
err = -ENOMEM;
|
||||
goto unmap;
|
||||
}
|
||||
|
||||
/* Make sure the interrupt is allocated. */
|
||||
err = lguest_setup_irq(lvq->config.irq);
|
||||
if (err)
|
||||
goto destroy_vring;
|
||||
|
||||
/*
|
||||
* Tell the interrupt for this virtqueue to go to the virtio_ring
|
||||
* interrupt handler.
|
||||
*
|
||||
* FIXME: We used to have a flag for the Host to tell us we could use
|
||||
* the interrupt as a source of randomness: it'd be nice to have that
|
||||
* back.
|
||||
*/
|
||||
err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
|
||||
dev_name(&vdev->dev), vq);
|
||||
if (err)
|
||||
goto free_desc;
|
||||
|
||||
/*
|
||||
* Last of all we hook up our 'struct lguest_vq_info" to the
|
||||
* virtqueue's priv pointer.
|
||||
*/
|
||||
vq->priv = lvq;
|
||||
return vq;
|
||||
|
||||
free_desc:
|
||||
irq_free_desc(lvq->config.irq);
|
||||
destroy_vring:
|
||||
vring_del_virtqueue(vq);
|
||||
unmap:
|
||||
lguest_unmap(lvq->pages);
|
||||
free_lvq:
|
||||
kfree(lvq);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
/*:*/
|
||||
|
||||
/* Cleaning up a virtqueue is easy */
|
||||
static void lg_del_vq(struct virtqueue *vq)
|
||||
{
|
||||
struct lguest_vq_info *lvq = vq->priv;
|
||||
|
||||
/* Release the interrupt */
|
||||
free_irq(lvq->config.irq, vq);
|
||||
/* Tell virtio_ring.c to free the virtqueue. */
|
||||
vring_del_virtqueue(vq);
|
||||
/* Unmap the pages containing the ring. */
|
||||
lguest_unmap(lvq->pages);
|
||||
/* Free our own queue information. */
|
||||
kfree(lvq);
|
||||
}
|
||||
|
||||
static void lg_del_vqs(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtqueue *vq, *n;
|
||||
|
||||
list_for_each_entry_safe(vq, n, &vdev->vqs, list)
|
||||
lg_del_vq(vq);
|
||||
}
|
||||
|
||||
static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
|
||||
struct virtqueue *vqs[],
|
||||
vq_callback_t *callbacks[],
|
||||
const char *names[])
|
||||
{
|
||||
struct lguest_device *ldev = to_lgdev(vdev);
|
||||
int i;
|
||||
|
||||
/* We must have this many virtqueues. */
|
||||
if (nvqs > ldev->desc->num_vq)
|
||||
return -ENOENT;
|
||||
|
||||
for (i = 0; i < nvqs; ++i) {
|
||||
vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
|
||||
if (IS_ERR(vqs[i]))
|
||||
goto error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
lg_del_vqs(vdev);
|
||||
return PTR_ERR(vqs[i]);
|
||||
}
|
||||
|
||||
static const char *lg_bus_name(struct virtio_device *vdev)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
/* The ops structure which hooks everything together. */
|
||||
static const struct virtio_config_ops lguest_config_ops = {
|
||||
.get_features = lg_get_features,
|
||||
.finalize_features = lg_finalize_features,
|
||||
.get = lg_get,
|
||||
.set = lg_set,
|
||||
.get_status = lg_get_status,
|
||||
.set_status = lg_set_status,
|
||||
.reset = lg_reset,
|
||||
.find_vqs = lg_find_vqs,
|
||||
.del_vqs = lg_del_vqs,
|
||||
.bus_name = lg_bus_name,
|
||||
};
|
||||
|
||||
/*
|
||||
* The root device for the lguest virtio devices. This makes them appear as
|
||||
* /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2.
|
||||
*/
|
||||
static struct device *lguest_root;
|
||||
|
||||
/*D:120
|
||||
* This is the core of the lguest bus: actually adding a new device.
|
||||
* It's a separate function because it's neater that way, and because an
|
||||
* earlier version of the code supported hotplug and unplug. They were removed
|
||||
* early on because they were never used.
|
||||
*
|
||||
* As Andrew Tridgell says, "Untested code is buggy code".
|
||||
*
|
||||
* It's worth reading this carefully: we start with a pointer to the new device
|
||||
* descriptor in the "lguest_devices" page, and the offset into the device
|
||||
* descriptor page so we can uniquely identify it if things go badly wrong.
|
||||
*/
|
||||
static void add_lguest_device(struct lguest_device_desc *d,
|
||||
unsigned int offset)
|
||||
{
|
||||
struct lguest_device *ldev;
|
||||
|
||||
/* Start with zeroed memory; Linux's device layer counts on it. */
|
||||
ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
|
||||
if (!ldev) {
|
||||
printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
|
||||
offset, d->type);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This devices' parent is the lguest/ dir. */
|
||||
ldev->vdev.dev.parent = lguest_root;
|
||||
/*
|
||||
* The device type comes straight from the descriptor. There's also a
|
||||
* device vendor field in the virtio_device struct, which we leave as
|
||||
* 0.
|
||||
*/
|
||||
ldev->vdev.id.device = d->type;
|
||||
/*
|
||||
* We have a simple set of routines for querying the device's
|
||||
* configuration information and setting its status.
|
||||
*/
|
||||
ldev->vdev.config = &lguest_config_ops;
|
||||
/* And we remember the device's descriptor for lguest_config_ops. */
|
||||
ldev->desc = d;
|
||||
|
||||
/*
|
||||
* register_virtio_device() sets up the generic fields for the struct
|
||||
* virtio_device and calls device_register(). This makes the bus
|
||||
* infrastructure look for a matching driver.
|
||||
*/
|
||||
if (register_virtio_device(&ldev->vdev) != 0) {
|
||||
printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
|
||||
offset, d->type);
|
||||
kfree(ldev);
|
||||
}
|
||||
}
|
||||
|
||||
/*D:110
|
||||
* scan_devices() simply iterates through the device page. The type 0 is
|
||||
* reserved to mean "end of devices".
|
||||
*/
|
||||
static void scan_devices(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct lguest_device_desc *d;
|
||||
|
||||
/* We start at the page beginning, and skip over each entry. */
|
||||
for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
|
||||
d = lguest_devices + i;
|
||||
|
||||
/* Once we hit a zero, stop. */
|
||||
if (d->type == 0)
|
||||
break;
|
||||
|
||||
printk("Device at %i has size %u\n", i, desc_size(d));
|
||||
add_lguest_device(d, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*D:105
|
||||
* Fairly early in boot, lguest_devices_init() is called to set up the
|
||||
* lguest device infrastructure. We check that we are a Guest by checking
|
||||
* pv_info.name: there are other ways of checking, but this seems most
|
||||
* obvious to me.
|
||||
*
|
||||
* So we can access the "struct lguest_device_desc"s easily, we map that memory
|
||||
* and store the pointer in the global "lguest_devices". Then we register a
|
||||
* root device from which all our devices will hang (this seems to be the
|
||||
* correct sysfs incantation).
|
||||
*
|
||||
* Finally we call scan_devices() which adds all the devices found in the
|
||||
* lguest_devices page.
|
||||
*/
|
||||
static int __init lguest_devices_init(void)
|
||||
{
|
||||
if (strcmp(pv_info.name, "lguest") != 0)
|
||||
return 0;
|
||||
|
||||
lguest_root = root_device_register("lguest");
|
||||
if (IS_ERR(lguest_root))
|
||||
panic("Could not register lguest root");
|
||||
|
||||
/* Devices are in a single page above top of "normal" mem */
|
||||
lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
|
||||
|
||||
scan_devices();
|
||||
return 0;
|
||||
}
|
||||
/* We do this after core stuff, but before the drivers. */
|
||||
postcore_initcall(lguest_devices_init);
|
||||
|
||||
/*D:150
|
||||
* At this point in the journey we used to now wade through the lguest
|
||||
* devices themselves: net, block and console. Since they're all now virtio
|
||||
* devices rather than lguest-specific, I've decided to ignore them. Mostly,
|
||||
* they're kind of boring. But this does mean you'll never experience the
|
||||
* thrill of reading the forbidden love scene buried deep in the block driver.
|
||||
*
|
||||
* "make Launcher" beckons, where we answer questions like "Where do Guests
|
||||
* come from?", and "What do you do when someone asks for optimization?".
|
||||
*/
|
||||
|
|
@ -2,175 +2,62 @@
|
|||
* launcher controls and communicates with the Guest. For example,
|
||||
* the first write will tell us the Guest's memory layout and entry
|
||||
* point. A read will run the Guest until something happens, such as
|
||||
* a signal or the Guest doing a NOTIFY out to the Launcher. There is
|
||||
* also a way for the Launcher to attach eventfds to particular NOTIFY
|
||||
* values instead of returning from the read() call.
|
||||
* a signal or the Guest accessing a device.
|
||||
:*/
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/eventfd.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include "lg.h"
|
||||
|
||||
/*L:056
|
||||
* Before we move on, let's jump ahead and look at what the kernel does when
|
||||
* it needs to look up the eventfds. That will complete our picture of how we
|
||||
* use RCU.
|
||||
*
|
||||
* The notification value is in cpu->pending_notify: we return true if it went
|
||||
* to an eventfd.
|
||||
*/
|
||||
bool send_notify_to_eventfd(struct lg_cpu *cpu)
|
||||
{
|
||||
unsigned int i;
|
||||
struct lg_eventfd_map *map;
|
||||
|
||||
/*
|
||||
* This "rcu_read_lock()" helps track when someone is still looking at
|
||||
* the (RCU-using) eventfds array. It's not actually a lock at all;
|
||||
* indeed it's a noop in many configurations. (You didn't expect me to
|
||||
* explain all the RCU secrets here, did you?)
|
||||
*/
|
||||
rcu_read_lock();
|
||||
/*
|
||||
* rcu_dereference is the counter-side of rcu_assign_pointer(); it
|
||||
* makes sure we don't access the memory pointed to by
|
||||
* cpu->lg->eventfds before cpu->lg->eventfds is set. Sounds crazy,
|
||||
* but Alpha allows this! Paul McKenney points out that a really
|
||||
* aggressive compiler could have the same effect:
|
||||
* http://lists.ozlabs.org/pipermail/lguest/2009-July/001560.html
|
||||
*
|
||||
* So play safe, use rcu_dereference to get the rcu-protected pointer:
|
||||
*/
|
||||
map = rcu_dereference(cpu->lg->eventfds);
|
||||
/*
|
||||
* Simple array search: even if they add an eventfd while we do this,
|
||||
* we'll continue to use the old array and just won't see the new one.
|
||||
*/
|
||||
for (i = 0; i < map->num; i++) {
|
||||
if (map->map[i].addr == cpu->pending_notify) {
|
||||
eventfd_signal(map->map[i].event, 1);
|
||||
cpu->pending_notify = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* We're done with the rcu-protected variable cpu->lg->eventfds. */
|
||||
rcu_read_unlock();
|
||||
|
||||
/* If we cleared the notification, it's because we found a match. */
|
||||
return cpu->pending_notify == 0;
|
||||
}
|
||||
|
||||
/*L:055
|
||||
* One of the more tricksy tricks in the Linux Kernel is a technique called
|
||||
* Read Copy Update. Since one point of lguest is to teach lguest journeyers
|
||||
* about kernel coding, I use it here. (In case you're curious, other purposes
|
||||
* include learning about virtualization and instilling a deep appreciation for
|
||||
* simplicity and puppies).
|
||||
*
|
||||
* We keep a simple array which maps LHCALL_NOTIFY values to eventfds, but we
|
||||
* add new eventfds without ever blocking readers from accessing the array.
|
||||
* The current Launcher only does this during boot, so that never happens. But
|
||||
* Read Copy Update is cool, and adding a lock risks damaging even more puppies
|
||||
* than this code does.
|
||||
*
|
||||
* We allocate a brand new one-larger array, copy the old one and add our new
|
||||
* element. Then we make the lg eventfd pointer point to the new array.
|
||||
* That's the easy part: now we need to free the old one, but we need to make
|
||||
* sure no slow CPU somewhere is still looking at it. That's what
|
||||
* synchronize_rcu does for us: waits until every CPU has indicated that it has
|
||||
* moved on to know it's no longer using the old one.
|
||||
*
|
||||
* If that's unclear, see http://en.wikipedia.org/wiki/Read-copy-update.
|
||||
*/
|
||||
static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
|
||||
{
|
||||
struct lg_eventfd_map *new, *old = lg->eventfds;
|
||||
|
||||
/*
|
||||
* We don't allow notifications on value 0 anyway (pending_notify of
|
||||
* 0 means "nothing pending").
|
||||
*/
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Replace the old array with the new one, carefully: others can
|
||||
* be accessing it at the same time.
|
||||
*/
|
||||
new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
|
||||
GFP_KERNEL);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
|
||||
/* First make identical copy. */
|
||||
memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
|
||||
new->num = old->num;
|
||||
|
||||
/* Now append new entry. */
|
||||
new->map[new->num].addr = addr;
|
||||
new->map[new->num].event = eventfd_ctx_fdget(fd);
|
||||
if (IS_ERR(new->map[new->num].event)) {
|
||||
int err = PTR_ERR(new->map[new->num].event);
|
||||
kfree(new);
|
||||
return err;
|
||||
}
|
||||
new->num++;
|
||||
|
||||
/*
|
||||
* Now put new one in place: rcu_assign_pointer() is a fancy way of
|
||||
* doing "lg->eventfds = new", but it uses memory barriers to make
|
||||
* absolutely sure that the contents of "new" written above is nailed
|
||||
* down before we actually do the assignment.
|
||||
*
|
||||
* We have to think about these kinds of things when we're operating on
|
||||
* live data without locks.
|
||||
*/
|
||||
rcu_assign_pointer(lg->eventfds, new);
|
||||
|
||||
/*
|
||||
* We're not in a big hurry. Wait until no one's looking at old
|
||||
* version, then free it.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
kfree(old);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*L:052
|
||||
* Receiving notifications from the Guest is usually done by attaching a
|
||||
* particular LHCALL_NOTIFY value to an event filedescriptor. The eventfd will
|
||||
* become readable when the Guest does an LHCALL_NOTIFY with that value.
|
||||
*
|
||||
* This is really convenient for processing each virtqueue in a separate
|
||||
* thread.
|
||||
*/
|
||||
static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
|
||||
The Launcher can get the registers, and also set some of them.
|
||||
*/
|
||||
static int getreg_setup(struct lg_cpu *cpu, const unsigned long __user *input)
|
||||
{
|
||||
unsigned long addr, fd;
|
||||
int err;
|
||||
unsigned long which;
|
||||
|
||||
if (get_user(addr, input) != 0)
|
||||
/* We re-use the ptrace structure to specify which register to read. */
|
||||
if (get_user(which, input) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* We set up the cpu register pointer, and their next read will
|
||||
* actually get the value (instead of running the guest).
|
||||
*
|
||||
* The last argument 'true' says we can access any register.
|
||||
*/
|
||||
cpu->reg_read = lguest_arch_regptr(cpu, which, true);
|
||||
if (!cpu->reg_read)
|
||||
return -ENOENT;
|
||||
|
||||
/* And because this is a write() call, we return the length used. */
|
||||
return sizeof(unsigned long) * 2;
|
||||
}
|
||||
|
||||
static int setreg(struct lg_cpu *cpu, const unsigned long __user *input)
|
||||
{
|
||||
unsigned long which, value, *reg;
|
||||
|
||||
/* We re-use the ptrace structure to specify which register to read. */
|
||||
if (get_user(which, input) != 0)
|
||||
return -EFAULT;
|
||||
input++;
|
||||
if (get_user(fd, input) != 0)
|
||||
if (get_user(value, input) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* Just make sure two callers don't add eventfds at once. We really
|
||||
* only need to lock against callers adding to the same Guest, so using
|
||||
* the Big Lguest Lock is overkill. But this is setup, not a fast path.
|
||||
*/
|
||||
mutex_lock(&lguest_lock);
|
||||
err = add_eventfd(lg, addr, fd);
|
||||
mutex_unlock(&lguest_lock);
|
||||
/* The last argument 'false' means we can't access all registers. */
|
||||
reg = lguest_arch_regptr(cpu, which, false);
|
||||
if (!reg)
|
||||
return -ENOENT;
|
||||
|
||||
return err;
|
||||
*reg = value;
|
||||
|
||||
/* And because this is a write() call, we return the length used. */
|
||||
return sizeof(unsigned long) * 3;
|
||||
}
|
||||
|
||||
/*L:050
|
||||
|
|
@ -194,6 +81,23 @@ static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*L:053
|
||||
* Deliver a trap: this is used by the Launcher if it can't emulate
|
||||
* an instruction.
|
||||
*/
|
||||
static int trap(struct lg_cpu *cpu, const unsigned long __user *input)
|
||||
{
|
||||
unsigned long trapnum;
|
||||
|
||||
if (get_user(trapnum, input) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
if (!deliver_trap(cpu, trapnum))
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*L:040
|
||||
* Once our Guest is initialized, the Launcher makes it run by reading
|
||||
* from /dev/lguest.
|
||||
|
|
@ -237,8 +141,8 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
|
|||
* If we returned from read() last time because the Guest sent I/O,
|
||||
* clear the flag.
|
||||
*/
|
||||
if (cpu->pending_notify)
|
||||
cpu->pending_notify = 0;
|
||||
if (cpu->pending.trap)
|
||||
cpu->pending.trap = 0;
|
||||
|
||||
/* Run the Guest until something interesting happens. */
|
||||
return run_guest(cpu, (unsigned long __user *)user);
|
||||
|
|
@ -319,7 +223,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
|
|||
/* "struct lguest" contains all we (the Host) know about a Guest. */
|
||||
struct lguest *lg;
|
||||
int err;
|
||||
unsigned long args[3];
|
||||
unsigned long args[4];
|
||||
|
||||
/*
|
||||
* We grab the Big Lguest lock, which protects against multiple
|
||||
|
|
@ -343,21 +247,15 @@ static int initialize(struct file *file, const unsigned long __user *input)
|
|||
goto unlock;
|
||||
}
|
||||
|
||||
lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
|
||||
if (!lg->eventfds) {
|
||||
err = -ENOMEM;
|
||||
goto free_lg;
|
||||
}
|
||||
lg->eventfds->num = 0;
|
||||
|
||||
/* Populate the easy fields of our "struct lguest" */
|
||||
lg->mem_base = (void __user *)args[0];
|
||||
lg->pfn_limit = args[1];
|
||||
lg->device_limit = args[3];
|
||||
|
||||
/* This is the first cpu (cpu 0) and it will start booting at args[2] */
|
||||
err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
|
||||
if (err)
|
||||
goto free_eventfds;
|
||||
goto free_lg;
|
||||
|
||||
/*
|
||||
* Initialize the Guest's shadow page tables. This allocates
|
||||
|
|
@ -378,8 +276,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
|
|||
free_regs:
|
||||
/* FIXME: This should be in free_vcpu */
|
||||
free_page(lg->cpus[0].regs_page);
|
||||
free_eventfds:
|
||||
kfree(lg->eventfds);
|
||||
free_lg:
|
||||
kfree(lg);
|
||||
unlock:
|
||||
|
|
@ -432,8 +328,12 @@ static ssize_t write(struct file *file, const char __user *in,
|
|||
return initialize(file, input);
|
||||
case LHREQ_IRQ:
|
||||
return user_send_irq(cpu, input);
|
||||
case LHREQ_EVENTFD:
|
||||
return attach_eventfd(lg, input);
|
||||
case LHREQ_GETREG:
|
||||
return getreg_setup(cpu, input);
|
||||
case LHREQ_SETREG:
|
||||
return setreg(cpu, input);
|
||||
case LHREQ_TRAP:
|
||||
return trap(cpu, input);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -478,11 +378,6 @@ static int close(struct inode *inode, struct file *file)
|
|||
mmput(lg->cpus[i].mm);
|
||||
}
|
||||
|
||||
/* Release any eventfds they registered. */
|
||||
for (i = 0; i < lg->eventfds->num; i++)
|
||||
eventfd_ctx_put(lg->eventfds->map[i].event);
|
||||
kfree(lg->eventfds);
|
||||
|
||||
/*
|
||||
* If lg->dead doesn't contain an error code it will be NULL or a
|
||||
* kmalloc()ed string, either of which is ok to hand to kfree().
|
||||
|
|
|
|||
|
|
@ -250,6 +250,16 @@ static void release_pte(pte_t pte)
|
|||
}
|
||||
/*:*/
|
||||
|
||||
static bool gpte_in_iomem(struct lg_cpu *cpu, pte_t gpte)
|
||||
{
|
||||
/* We don't handle large pages. */
|
||||
if (pte_flags(gpte) & _PAGE_PSE)
|
||||
return false;
|
||||
|
||||
return (pte_pfn(gpte) >= cpu->lg->pfn_limit
|
||||
&& pte_pfn(gpte) < cpu->lg->device_limit);
|
||||
}
|
||||
|
||||
static bool check_gpte(struct lg_cpu *cpu, pte_t gpte)
|
||||
{
|
||||
if ((pte_flags(gpte) & _PAGE_PSE) ||
|
||||
|
|
@ -374,8 +384,14 @@ static pte_t *find_spte(struct lg_cpu *cpu, unsigned long vaddr, bool allocate,
|
|||
*
|
||||
* If we fixed up the fault (ie. we mapped the address), this routine returns
|
||||
* true. Otherwise, it was a real fault and we need to tell the Guest.
|
||||
*
|
||||
* There's a corner case: they're trying to access memory between
|
||||
* pfn_limit and device_limit, which is I/O memory. In this case, we
|
||||
* return false and set @iomem to the physical address, so the the
|
||||
* Launcher can handle the instruction manually.
|
||||
*/
|
||||
bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
|
||||
bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode,
|
||||
unsigned long *iomem)
|
||||
{
|
||||
unsigned long gpte_ptr;
|
||||
pte_t gpte;
|
||||
|
|
@ -383,6 +399,8 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
|
|||
pmd_t gpmd;
|
||||
pgd_t gpgd;
|
||||
|
||||
*iomem = 0;
|
||||
|
||||
/* We never demand page the Switcher, so trying is a mistake. */
|
||||
if (vaddr >= switcher_addr)
|
||||
return false;
|
||||
|
|
@ -459,6 +477,12 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
|
|||
if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
|
||||
return false;
|
||||
|
||||
/* If they're accessing io memory, we expect a fault. */
|
||||
if (gpte_in_iomem(cpu, gpte)) {
|
||||
*iomem = (pte_pfn(gpte) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that the Guest PTE flags are OK, and the page number is below
|
||||
* the pfn_limit (ie. not mapping the Launcher binary).
|
||||
|
|
@ -553,7 +577,9 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
|
|||
*/
|
||||
void pin_page(struct lg_cpu *cpu, unsigned long vaddr)
|
||||
{
|
||||
if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2))
|
||||
unsigned long iomem;
|
||||
|
||||
if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2, &iomem))
|
||||
kill_guest(cpu, "bad stack page %#lx", vaddr);
|
||||
}
|
||||
/*:*/
|
||||
|
|
@ -647,7 +673,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu)
|
|||
/*:*/
|
||||
|
||||
/* We walk down the guest page tables to get a guest-physical address */
|
||||
unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
|
||||
bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr)
|
||||
{
|
||||
pgd_t gpgd;
|
||||
pte_t gpte;
|
||||
|
|
@ -656,31 +682,47 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
|
|||
#endif
|
||||
|
||||
/* Still not set up? Just map 1:1. */
|
||||
if (unlikely(cpu->linear_pages))
|
||||
return vaddr;
|
||||
if (unlikely(cpu->linear_pages)) {
|
||||
*paddr = vaddr;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* First step: get the top-level Guest page table entry. */
|
||||
gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
|
||||
/* Toplevel not present? We can't map it in. */
|
||||
if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) {
|
||||
kill_guest(cpu, "Bad address %#lx", vaddr);
|
||||
return -1UL;
|
||||
}
|
||||
if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
|
||||
goto fail;
|
||||
|
||||
#ifdef CONFIG_X86_PAE
|
||||
gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
|
||||
if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) {
|
||||
kill_guest(cpu, "Bad address %#lx", vaddr);
|
||||
return -1UL;
|
||||
}
|
||||
if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
|
||||
goto fail;
|
||||
gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
|
||||
#else
|
||||
gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
|
||||
#endif
|
||||
if (!(pte_flags(gpte) & _PAGE_PRESENT))
|
||||
kill_guest(cpu, "Bad address %#lx", vaddr);
|
||||
goto fail;
|
||||
|
||||
return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
|
||||
*paddr = pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
|
||||
return true;
|
||||
|
||||
fail:
|
||||
*paddr = -1UL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the version we normally use: kills the Guest if it uses a
|
||||
* bad address
|
||||
*/
|
||||
unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
|
||||
{
|
||||
unsigned long paddr;
|
||||
|
||||
if (!__guest_pa(cpu, vaddr, &paddr))
|
||||
kill_guest(cpu, "Bad address %#lx", vaddr);
|
||||
return paddr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -912,7 +954,8 @@ static void __guest_set_pte(struct lg_cpu *cpu, int idx,
|
|||
* now. This shaves 10% off a copy-on-write
|
||||
* micro-benchmark.
|
||||
*/
|
||||
if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
|
||||
if ((pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED))
|
||||
&& !gpte_in_iomem(cpu, gpte)) {
|
||||
if (!check_gpte(cpu, gpte))
|
||||
return;
|
||||
set_pte(spte,
|
||||
|
|
|
|||
|
|
@ -182,6 +182,52 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
|
|||
}
|
||||
/*:*/
|
||||
|
||||
unsigned long *lguest_arch_regptr(struct lg_cpu *cpu, size_t reg_off, bool any)
|
||||
{
|
||||
switch (reg_off) {
|
||||
case offsetof(struct pt_regs, bx):
|
||||
return &cpu->regs->ebx;
|
||||
case offsetof(struct pt_regs, cx):
|
||||
return &cpu->regs->ecx;
|
||||
case offsetof(struct pt_regs, dx):
|
||||
return &cpu->regs->edx;
|
||||
case offsetof(struct pt_regs, si):
|
||||
return &cpu->regs->esi;
|
||||
case offsetof(struct pt_regs, di):
|
||||
return &cpu->regs->edi;
|
||||
case offsetof(struct pt_regs, bp):
|
||||
return &cpu->regs->ebp;
|
||||
case offsetof(struct pt_regs, ax):
|
||||
return &cpu->regs->eax;
|
||||
case offsetof(struct pt_regs, ip):
|
||||
return &cpu->regs->eip;
|
||||
case offsetof(struct pt_regs, sp):
|
||||
return &cpu->regs->esp;
|
||||
}
|
||||
|
||||
/* Launcher can read these, but we don't allow any setting. */
|
||||
if (any) {
|
||||
switch (reg_off) {
|
||||
case offsetof(struct pt_regs, ds):
|
||||
return &cpu->regs->ds;
|
||||
case offsetof(struct pt_regs, es):
|
||||
return &cpu->regs->es;
|
||||
case offsetof(struct pt_regs, fs):
|
||||
return &cpu->regs->fs;
|
||||
case offsetof(struct pt_regs, gs):
|
||||
return &cpu->regs->gs;
|
||||
case offsetof(struct pt_regs, cs):
|
||||
return &cpu->regs->cs;
|
||||
case offsetof(struct pt_regs, flags):
|
||||
return &cpu->regs->eflags;
|
||||
case offsetof(struct pt_regs, ss):
|
||||
return &cpu->regs->ss;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*M:002
|
||||
* There are hooks in the scheduler which we can register to tell when we
|
||||
* get kicked off the CPU (preempt_notifier_register()). This would allow us
|
||||
|
|
@ -269,110 +315,73 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
|
|||
* usually attached to a PC.
|
||||
*
|
||||
* When the Guest uses one of these instructions, we get a trap (General
|
||||
* Protection Fault) and come here. We see if it's one of those troublesome
|
||||
* instructions and skip over it. We return true if we did.
|
||||
* Protection Fault) and come here. We queue this to be sent out to the
|
||||
* Launcher to handle.
|
||||
*/
|
||||
static int emulate_insn(struct lg_cpu *cpu)
|
||||
|
||||
/*
|
||||
* The eip contains the *virtual* address of the Guest's instruction:
|
||||
* we copy the instruction here so the Launcher doesn't have to walk
|
||||
* the page tables to decode it. We handle the case (eg. in a kernel
|
||||
* module) where the instruction is over two pages, and the pages are
|
||||
* virtually but not physically contiguous.
|
||||
*
|
||||
* The longest possible x86 instruction is 15 bytes, but we don't handle
|
||||
* anything that strange.
|
||||
*/
|
||||
static void copy_from_guest(struct lg_cpu *cpu,
|
||||
void *dst, unsigned long vaddr, size_t len)
|
||||
{
|
||||
u8 insn;
|
||||
unsigned int insnlen = 0, in = 0, small_operand = 0;
|
||||
/*
|
||||
* The eip contains the *virtual* address of the Guest's instruction:
|
||||
* walk the Guest's page tables to find the "physical" address.
|
||||
*/
|
||||
unsigned long physaddr = guest_pa(cpu, cpu->regs->eip);
|
||||
size_t to_page_end = PAGE_SIZE - (vaddr % PAGE_SIZE);
|
||||
unsigned long paddr;
|
||||
|
||||
/*
|
||||
* This must be the Guest kernel trying to do something, not userspace!
|
||||
* The bottom two bits of the CS segment register are the privilege
|
||||
* level.
|
||||
*/
|
||||
if ((cpu->regs->cs & 3) != GUEST_PL)
|
||||
return 0;
|
||||
BUG_ON(len > PAGE_SIZE);
|
||||
|
||||
/* Decoding x86 instructions is icky. */
|
||||
insn = lgread(cpu, physaddr, u8);
|
||||
|
||||
/*
|
||||
* Around 2.6.33, the kernel started using an emulation for the
|
||||
* cmpxchg8b instruction in early boot on many configurations. This
|
||||
* code isn't paravirtualized, and it tries to disable interrupts.
|
||||
* Ignore it, which will Mostly Work.
|
||||
*/
|
||||
if (insn == 0xfa) {
|
||||
/* "cli", or Clear Interrupt Enable instruction. Skip it. */
|
||||
cpu->regs->eip++;
|
||||
return 1;
|
||||
/* If it goes over a page, copy in two parts. */
|
||||
if (len > to_page_end) {
|
||||
/* But make sure the next page is mapped! */
|
||||
if (__guest_pa(cpu, vaddr + to_page_end, &paddr))
|
||||
copy_from_guest(cpu, dst + to_page_end,
|
||||
vaddr + to_page_end,
|
||||
len - to_page_end);
|
||||
else
|
||||
/* Otherwise fill with zeroes. */
|
||||
memset(dst + to_page_end, 0, len - to_page_end);
|
||||
len = to_page_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* 0x66 is an "operand prefix". It means a 16, not 32 bit in/out.
|
||||
*/
|
||||
if (insn == 0x66) {
|
||||
small_operand = 1;
|
||||
/* The instruction is 1 byte so far, read the next byte. */
|
||||
insnlen = 1;
|
||||
insn = lgread(cpu, physaddr + insnlen, u8);
|
||||
}
|
||||
/* This will kill the guest if it isn't mapped, but that
|
||||
* shouldn't happen. */
|
||||
__lgread(cpu, dst, guest_pa(cpu, vaddr), len);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can ignore the lower bit for the moment and decode the 4 opcodes
|
||||
* we need to emulate.
|
||||
*/
|
||||
switch (insn & 0xFE) {
|
||||
case 0xE4: /* in <next byte>,%al */
|
||||
insnlen += 2;
|
||||
in = 1;
|
||||
break;
|
||||
case 0xEC: /* in (%dx),%al */
|
||||
insnlen += 1;
|
||||
in = 1;
|
||||
break;
|
||||
case 0xE6: /* out %al,<next byte> */
|
||||
insnlen += 2;
|
||||
break;
|
||||
case 0xEE: /* out %al,(%dx) */
|
||||
insnlen += 1;
|
||||
break;
|
||||
default:
|
||||
/* OK, we don't know what this is, can't emulate. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it was an "IN" instruction, they expect the result to be read
|
||||
* into %eax, so we change %eax. We always return all-ones, which
|
||||
* traditionally means "there's nothing there".
|
||||
*/
|
||||
if (in) {
|
||||
/* Lower bit tells means it's a 32/16 bit access */
|
||||
if (insn & 0x1) {
|
||||
if (small_operand)
|
||||
cpu->regs->eax |= 0xFFFF;
|
||||
else
|
||||
cpu->regs->eax = 0xFFFFFFFF;
|
||||
} else
|
||||
cpu->regs->eax |= 0xFF;
|
||||
}
|
||||
/* Finally, we've "done" the instruction, so move past it. */
|
||||
cpu->regs->eip += insnlen;
|
||||
/* Success! */
|
||||
return 1;
|
||||
static void setup_emulate_insn(struct lg_cpu *cpu)
|
||||
{
|
||||
cpu->pending.trap = 13;
|
||||
copy_from_guest(cpu, cpu->pending.insn, cpu->regs->eip,
|
||||
sizeof(cpu->pending.insn));
|
||||
}
|
||||
|
||||
static void setup_iomem_insn(struct lg_cpu *cpu, unsigned long iomem_addr)
|
||||
{
|
||||
cpu->pending.trap = 14;
|
||||
cpu->pending.addr = iomem_addr;
|
||||
copy_from_guest(cpu, cpu->pending.insn, cpu->regs->eip,
|
||||
sizeof(cpu->pending.insn));
|
||||
}
|
||||
|
||||
/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
|
||||
void lguest_arch_handle_trap(struct lg_cpu *cpu)
|
||||
{
|
||||
unsigned long iomem_addr;
|
||||
|
||||
switch (cpu->regs->trapnum) {
|
||||
case 13: /* We've intercepted a General Protection Fault. */
|
||||
/*
|
||||
* Check if this was one of those annoying IN or OUT
|
||||
* instructions which we need to emulate. If so, we just go
|
||||
* back into the Guest after we've done it.
|
||||
*/
|
||||
/* Hand to Launcher to emulate those pesky IN and OUT insns */
|
||||
if (cpu->regs->errcode == 0) {
|
||||
if (emulate_insn(cpu))
|
||||
return;
|
||||
setup_emulate_insn(cpu);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 14: /* We've intercepted a Page Fault. */
|
||||
|
|
@ -387,9 +396,16 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
|
|||
* whether kernel or userspace code.
|
||||
*/
|
||||
if (demand_page(cpu, cpu->arch.last_pagefault,
|
||||
cpu->regs->errcode))
|
||||
cpu->regs->errcode, &iomem_addr))
|
||||
return;
|
||||
|
||||
/* Was this an access to memory mapped IO? */
|
||||
if (iomem_addr) {
|
||||
/* Tell Launcher, let it handle it. */
|
||||
setup_iomem_insn(cpu, iomem_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, it's really not there (or not OK): the Guest needs to
|
||||
* know. We write out the cr2 value so it knows where the
|
||||
|
|
|
|||
|
|
@ -1710,6 +1710,12 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|||
struct virtnet_info *vi;
|
||||
u16 max_queue_pairs;
|
||||
|
||||
if (!vdev->config->get) {
|
||||
dev_err(&vdev->dev, "%s failure: config access disabled\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!virtnet_validate_features(vdev))
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue