2009-07-31 06:03:45 +08:00
|
|
|
/*P:400
|
|
|
|
* This contains run_guest() which actually calls into the Host<->Guest
|
2007-07-27 01:41:02 +08:00
|
|
|
* Switcher and analyzes the return, such as determining if the Guest wants the
|
2009-07-31 06:03:45 +08:00
|
|
|
* Host to do something. This file also contains useful helper routines.
|
|
|
|
:*/
|
2007-07-19 16:49:23 +08:00
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/stringify.h>
|
|
|
|
#include <linux/stddef.h>
|
|
|
|
#include <linux/io.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <linux/cpu.h>
|
|
|
|
#include <linux/freezer.h>
|
2007-10-22 09:03:28 +08:00
|
|
|
#include <linux/highmem.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2007-07-19 16:49:23 +08:00
|
|
|
#include <asm/paravirt.h>
|
|
|
|
#include <asm/pgtable.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
#include <asm/poll.h>
|
|
|
|
#include <asm/asm-offsets.h>
|
|
|
|
#include "lg.h"
|
|
|
|
|
|
|
|
|
|
|
|
static struct vm_struct *switcher_vma;
|
|
|
|
static struct page **switcher_page;
|
|
|
|
|
|
|
|
/* This One Big lock protects all inter-guest data structures. */
|
|
|
|
DEFINE_MUTEX(lguest_lock);
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*H:010
|
|
|
|
* We need to set up the Switcher at a high virtual address. Remember the
|
2007-07-27 01:41:04 +08:00
|
|
|
* Switcher is a few hundred bytes of assembler code which actually changes the
|
|
|
|
* CPU to run the Guest, and then changes back to the Host when a trap or
|
|
|
|
* interrupt happens.
|
|
|
|
*
|
|
|
|
* The Switcher code must be at the same virtual address in the Guest as the
|
|
|
|
* Host since it will be running as the switchover occurs.
|
|
|
|
*
|
|
|
|
* Trying to map memory at a particular address is an unusual thing to do, so
|
2009-07-31 06:03:45 +08:00
|
|
|
* it's not a simple one-liner.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
static __init int map_switcher(void)
|
|
|
|
{
|
|
|
|
int i, err;
|
|
|
|
struct page **pagep;
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/*
|
|
|
|
* Map the Switcher in to high memory.
|
|
|
|
*
|
|
|
|
* It turns out that if we choose the address 0xFFC00000 (4MB under the
|
|
|
|
* top virtual address), it makes setting up the page tables really
|
|
|
|
* easy.
|
|
|
|
*/
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* We allocate an array of struct page pointers. map_vm_area() wants
|
|
|
|
* this, rather than just an array of pages.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!switcher_page) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Now we actually allocate the pages. The Guest will see these pages,
|
|
|
|
* so we make sure they're zeroed.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
|
2009-08-05 17:42:37 +08:00
|
|
|
switcher_page[i] = alloc_page(GFP_KERNEL|__GFP_ZERO);
|
|
|
|
if (!switcher_page[i]) {
|
2007-07-19 16:49:23 +08:00
|
|
|
err = -ENOMEM;
|
|
|
|
goto free_some_pages;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* First we check that the Switcher won't overlap the fixmap area at
|
2008-03-11 22:35:56 +08:00
|
|
|
* the top of memory. It's currently nowhere near, but it could have
|
2009-07-31 06:03:45 +08:00
|
|
|
* very strange effects if it ever happened.
|
|
|
|
*/
|
2008-03-11 22:35:56 +08:00
|
|
|
if (SWITCHER_ADDR + (TOTAL_SWITCHER_PAGES+1)*PAGE_SIZE > FIXADDR_START){
|
|
|
|
err = -ENOMEM;
|
|
|
|
printk("lguest: mapping switcher would thwack fixmap\n");
|
|
|
|
goto free_pages;
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Now we reserve the "virtual memory area" we want: 0xFFC00000
|
2007-07-27 01:41:04 +08:00
|
|
|
* (SWITCHER_ADDR). We might not get it in theory, but in practice
|
2008-03-11 22:35:56 +08:00
|
|
|
* it's worked so far. The end address needs +1 because __get_vm_area
|
2009-07-31 06:03:45 +08:00
|
|
|
* allocates an extra guard page, so we need space for that.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
|
2008-03-11 22:35:56 +08:00
|
|
|
VM_ALLOC, SWITCHER_ADDR, SWITCHER_ADDR
|
|
|
|
+ (TOTAL_SWITCHER_PAGES+1) * PAGE_SIZE);
|
2007-07-19 16:49:23 +08:00
|
|
|
if (!switcher_vma) {
|
|
|
|
err = -ENOMEM;
|
|
|
|
printk("lguest: could not map switcher pages high\n");
|
|
|
|
goto free_pages;
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* This code actually sets up the pages we've allocated to appear at
|
2007-07-27 01:41:04 +08:00
|
|
|
* SWITCHER_ADDR. map_vm_area() takes the vma we allocated above, the
|
|
|
|
* kind of pages we're mapping (kernel pages), and a pointer to our
|
|
|
|
* array of struct pages. It increments that pointer, but we don't
|
2009-07-31 06:03:45 +08:00
|
|
|
* care.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
pagep = switcher_page;
|
2009-05-31 02:35:49 +08:00
|
|
|
err = map_vm_area(switcher_vma, PAGE_KERNEL_EXEC, &pagep);
|
2007-07-19 16:49:23 +08:00
|
|
|
if (err) {
|
|
|
|
printk("lguest: map_vm_area failed: %i\n", err);
|
|
|
|
goto free_vma;
|
|
|
|
}
|
2007-07-27 01:41:04 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Now the Switcher is mapped at the right address, we can't fail!
|
2011-07-22 13:09:50 +08:00
|
|
|
* Copy in the compiled-in Switcher code (from x86/switcher_32.S).
|
2009-07-31 06:03:45 +08:00
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
memcpy(switcher_vma->addr, start_switcher_text,
|
|
|
|
end_switcher_text - start_switcher_text);
|
|
|
|
|
|
|
|
printk(KERN_INFO "lguest: mapped switcher at %p\n",
|
|
|
|
switcher_vma->addr);
|
2007-07-27 01:41:04 +08:00
|
|
|
/* And we succeeded... */
|
2007-07-19 16:49:23 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
free_vma:
|
|
|
|
vunmap(switcher_vma->addr);
|
|
|
|
free_pages:
|
|
|
|
i = TOTAL_SWITCHER_PAGES;
|
|
|
|
free_some_pages:
|
|
|
|
for (--i; i >= 0; i--)
|
|
|
|
__free_pages(switcher_page[i], 0);
|
|
|
|
kfree(switcher_page);
|
|
|
|
out:
|
|
|
|
return err;
|
|
|
|
}
|
2007-07-27 01:41:04 +08:00
|
|
|
/*:*/
|
2007-07-19 16:49:23 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/* Cleaning up the mapping when the module is unloaded is almost... too easy. */
|
2007-07-19 16:49:23 +08:00
|
|
|
static void unmap_switcher(void)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
|
2007-07-19 16:49:23 +08:00
|
|
|
vunmap(switcher_vma->addr);
|
2007-07-27 01:41:04 +08:00
|
|
|
/* Now we just need to free the pages we copied the switcher into */
|
2007-07-19 16:49:23 +08:00
|
|
|
for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
|
|
|
|
__free_pages(switcher_page[i], 0);
|
2008-07-08 16:29:42 +08:00
|
|
|
kfree(switcher_page);
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
|
|
|
|
2007-10-25 13:02:50 +08:00
|
|
|
/*H:032
|
2007-07-27 01:41:03 +08:00
|
|
|
* Dealing With Guest Memory.
|
|
|
|
*
|
2007-10-25 13:02:50 +08:00
|
|
|
* Before we go too much further into the Host, we need to grok the routines
|
|
|
|
* we use to deal with Guest memory.
|
|
|
|
*
|
2007-07-27 01:41:03 +08:00
|
|
|
* When the Guest gives us (what it thinks is) a physical address, we can use
|
2007-10-22 09:03:26 +08:00
|
|
|
* the normal copy_from_user() & copy_to_user() on the corresponding place in
|
|
|
|
* the memory region allocated by the Launcher.
|
2007-07-27 01:41:03 +08:00
|
|
|
*
|
|
|
|
* But we can't trust the Guest: it might be trying to access the Launcher
|
|
|
|
* code. We have to check that the range is below the pfn_limit the Launcher
|
|
|
|
* gave us. We have to make sure that addr + len doesn't give us a false
|
2009-07-31 06:03:45 +08:00
|
|
|
* positive by overflowing, too.
|
|
|
|
*/
|
2009-03-19 00:38:35 +08:00
|
|
|
bool lguest_address_ok(const struct lguest *lg,
|
|
|
|
unsigned long addr, unsigned long len)
|
2007-07-19 16:49:23 +08:00
|
|
|
{
|
|
|
|
return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* This routine copies memory from the Guest. Here we can see how useful the
|
2007-10-22 09:24:24 +08:00
|
|
|
* kill_lguest() routine we met in the Launcher can be: we return a random
|
2009-07-31 06:03:45 +08:00
|
|
|
* value (all zeroes) instead of needing to return an error.
|
|
|
|
*/
|
2008-01-18 05:19:42 +08:00
|
|
|
void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes)
|
2007-07-19 16:49:23 +08:00
|
|
|
{
|
2008-01-18 05:19:42 +08:00
|
|
|
if (!lguest_address_ok(cpu->lg, addr, bytes)
|
|
|
|
|| copy_from_user(b, cpu->lg->mem_base + addr, bytes) != 0) {
|
2007-07-19 16:49:23 +08:00
|
|
|
/* copy_from_user should do this, but as we rely on it... */
|
|
|
|
memset(b, 0, bytes);
|
2008-01-18 05:19:42 +08:00
|
|
|
kill_guest(cpu, "bad read address %#lx len %u", addr, bytes);
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-03-29 00:05:53 +08:00
|
|
|
/* This is the write (copy into Guest) version. */
|
2008-01-18 05:19:42 +08:00
|
|
|
void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
|
2007-10-22 09:24:24 +08:00
|
|
|
unsigned bytes)
|
2007-07-19 16:49:23 +08:00
|
|
|
{
|
2008-01-18 05:19:42 +08:00
|
|
|
if (!lguest_address_ok(cpu->lg, addr, bytes)
|
|
|
|
|| copy_to_user(cpu->lg->mem_base + addr, b, bytes) != 0)
|
|
|
|
kill_guest(cpu, "bad write address %#lx len %u", addr, bytes);
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
2007-10-22 09:24:24 +08:00
|
|
|
/*:*/
|
2007-07-19 16:49:23 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*H:030
|
|
|
|
* Let's jump straight to the the main loop which runs the Guest.
|
2007-07-27 01:41:04 +08:00
|
|
|
* Remember, this is called by the Launcher reading /dev/lguest, and we keep
|
2009-07-31 06:03:45 +08:00
|
|
|
* going around and around until something interesting happens.
|
|
|
|
*/
|
2008-01-07 21:05:25 +08:00
|
|
|
int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
|
2007-07-19 16:49:23 +08:00
|
|
|
{
|
2007-07-27 01:41:04 +08:00
|
|
|
/* We stop running once the Guest is dead. */
|
2008-01-18 05:19:42 +08:00
|
|
|
while (!cpu->lg->dead) {
|
2009-06-13 12:27:02 +08:00
|
|
|
unsigned int irq;
|
2009-06-13 12:27:02 +08:00
|
|
|
bool more;
|
2009-06-13 12:27:02 +08:00
|
|
|
|
2007-10-22 09:03:30 +08:00
|
|
|
/* First we run any hypercalls the Guest wants done. */
|
2008-01-07 21:05:27 +08:00
|
|
|
if (cpu->hcall)
|
|
|
|
do_hypercalls(cpu);
|
2007-10-22 09:03:30 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* It's possible the Guest did a NOTIFY hypercall to the
|
2009-07-31 06:03:45 +08:00
|
|
|
* Launcher.
|
2009-07-31 06:03:45 +08:00
|
|
|
*/
|
2008-01-07 21:05:36 +08:00
|
|
|
if (cpu->pending_notify) {
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Does it just needs to write to a registered
|
|
|
|
* eventfd (ie. the appropriate virtqueue thread)?
|
|
|
|
*/
|
2009-06-13 12:27:09 +08:00
|
|
|
if (!send_notify_to_eventfd(cpu)) {
|
2009-07-31 06:03:45 +08:00
|
|
|
/* OK, we tell the main Laucher. */
|
2009-06-13 12:27:09 +08:00
|
|
|
if (put_user(cpu->pending_notify, user))
|
|
|
|
return -EFAULT;
|
|
|
|
return sizeof(cpu->pending_notify);
|
|
|
|
}
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* Check for signals */
|
2007-07-19 16:49:23 +08:00
|
|
|
if (signal_pending(current))
|
|
|
|
return -ERESTARTSYS;
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Check if there are any interrupts which can be delivered now:
|
2008-03-29 00:05:53 +08:00
|
|
|
* if so, this sets up the hander to be executed when we next
|
2009-07-31 06:03:45 +08:00
|
|
|
* run the Guest.
|
|
|
|
*/
|
2009-06-13 12:27:02 +08:00
|
|
|
irq = interrupt_pending(cpu, &more);
|
2009-06-13 12:27:02 +08:00
|
|
|
if (irq < LGUEST_IRQS)
|
2009-06-13 12:27:02 +08:00
|
|
|
try_deliver_interrupt(cpu, irq, more);
|
2007-07-19 16:49:23 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* All long-lived kernel loops need to check with this horrible
|
2007-07-27 01:41:04 +08:00
|
|
|
* thing called the freezer. If the Host is trying to suspend,
|
2009-07-31 06:03:45 +08:00
|
|
|
* it stops us.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
try_to_freeze();
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Just make absolutely sure the Guest is still alive. One of
|
|
|
|
* those hypercalls could have been fatal, for example.
|
|
|
|
*/
|
2008-01-18 05:19:42 +08:00
|
|
|
if (cpu->lg->dead)
|
2007-07-19 16:49:23 +08:00
|
|
|
break;
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* If the Guest asked to be stopped, we sleep. The Guest's
|
|
|
|
* clock timer will wake us.
|
|
|
|
*/
|
2008-01-07 21:05:34 +08:00
|
|
|
if (cpu->halted) {
|
2007-07-19 16:49:23 +08:00
|
|
|
set_current_state(TASK_INTERRUPTIBLE);
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* Just before we sleep, make sure no interrupt snuck in
|
|
|
|
* which we should be doing.
|
|
|
|
*/
|
2009-06-13 12:27:10 +08:00
|
|
|
if (interrupt_pending(cpu, &more) < LGUEST_IRQS)
|
2009-06-13 12:27:02 +08:00
|
|
|
set_current_state(TASK_RUNNING);
|
|
|
|
else
|
|
|
|
schedule();
|
2007-07-19 16:49:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* OK, now we're ready to jump into the Guest. First we put up
|
|
|
|
* the "Do Not Disturb" sign:
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
local_irq_disable();
|
|
|
|
|
2007-10-22 09:03:28 +08:00
|
|
|
/* Actually run the Guest until something happens. */
|
2008-01-07 21:05:25 +08:00
|
|
|
lguest_arch_run_guest(cpu);
|
2007-07-27 01:41:04 +08:00
|
|
|
|
|
|
|
/* Now we're ready to be interrupted or moved to other CPUs */
|
2007-07-19 16:49:23 +08:00
|
|
|
local_irq_enable();
|
|
|
|
|
2007-10-22 09:03:28 +08:00
|
|
|
/* Now we deal with whatever happened to the Guest. */
|
2008-01-07 21:05:27 +08:00
|
|
|
lguest_arch_handle_trap(cpu);
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
2007-10-22 09:03:28 +08:00
|
|
|
|
2008-03-29 00:05:53 +08:00
|
|
|
/* Special case: Guest is 'dead' but wants a reboot. */
|
2008-01-18 05:19:42 +08:00
|
|
|
if (cpu->lg->dead == ERR_PTR(-ERESTART))
|
2007-12-28 16:56:24 +08:00
|
|
|
return -ERESTART;
|
2008-03-29 00:05:53 +08:00
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* The Guest is dead => "No such file or directory" */
|
2007-07-19 16:49:23 +08:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/*H:000
|
|
|
|
* Welcome to the Host!
|
|
|
|
*
|
|
|
|
* By this point your brain has been tickled by the Guest code and numbed by
|
|
|
|
* the Launcher code; prepare for it to be stretched by the Host code. This is
|
|
|
|
* the heart. Let's begin at the initialization routine for the Host's lg
|
|
|
|
* module.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
static int __init init(void)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* Lguest can't run under Xen, VMI or itself. It does Tricky Stuff. */
|
2007-07-19 16:49:23 +08:00
|
|
|
if (paravirt_enabled()) {
|
2008-01-18 08:32:50 +08:00
|
|
|
printk("lguest is afraid of being a guest\n");
|
2007-07-19 16:49:23 +08:00
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* First we put the Switcher up in very high virtual memory. */
|
2007-07-19 16:49:23 +08:00
|
|
|
err = map_switcher();
|
|
|
|
if (err)
|
2007-10-22 09:03:35 +08:00
|
|
|
goto out;
|
2007-07-19 16:49:23 +08:00
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* Now we set up the pagetable implementation for the Guests. */
|
2007-07-19 16:49:23 +08:00
|
|
|
err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
|
2007-10-22 09:03:35 +08:00
|
|
|
if (err)
|
|
|
|
goto unmap;
|
2007-07-27 01:41:04 +08:00
|
|
|
|
2007-10-22 09:03:35 +08:00
|
|
|
/* We might need to reserve an interrupt vector. */
|
|
|
|
err = init_interrupts();
|
|
|
|
if (err)
|
|
|
|
goto free_pgtables;
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* /dev/lguest needs to be registered. */
|
2007-07-19 16:49:23 +08:00
|
|
|
err = lguest_device_init();
|
2007-10-22 09:03:35 +08:00
|
|
|
if (err)
|
|
|
|
goto free_interrupts;
|
2007-07-27 01:41:04 +08:00
|
|
|
|
2007-10-22 09:03:28 +08:00
|
|
|
/* Finally we do some architecture-specific setup. */
|
|
|
|
lguest_arch_host_init();
|
2007-07-27 01:41:04 +08:00
|
|
|
|
|
|
|
/* All good! */
|
2007-07-19 16:49:23 +08:00
|
|
|
return 0;
|
2007-10-22 09:03:35 +08:00
|
|
|
|
|
|
|
free_interrupts:
|
|
|
|
free_interrupts();
|
|
|
|
free_pgtables:
|
|
|
|
free_pagetables();
|
|
|
|
unmap:
|
|
|
|
unmap_switcher();
|
|
|
|
out:
|
|
|
|
return err;
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
|
|
|
|
2007-07-27 01:41:04 +08:00
|
|
|
/* Cleaning up is just the same code, backwards. With a little French. */
|
2007-07-19 16:49:23 +08:00
|
|
|
static void __exit fini(void)
|
|
|
|
{
|
|
|
|
lguest_device_remove();
|
2007-10-22 09:03:35 +08:00
|
|
|
free_interrupts();
|
2007-07-19 16:49:23 +08:00
|
|
|
free_pagetables();
|
|
|
|
unmap_switcher();
|
2007-07-27 01:41:04 +08:00
|
|
|
|
2007-10-22 09:03:28 +08:00
|
|
|
lguest_arch_host_fini();
|
2007-07-19 16:49:23 +08:00
|
|
|
}
|
2007-10-22 09:03:28 +08:00
|
|
|
/*:*/
|
2007-07-19 16:49:23 +08:00
|
|
|
|
2009-07-31 06:03:45 +08:00
|
|
|
/*
|
|
|
|
* The Host side of lguest can be a module. This is a nice way for people to
|
|
|
|
* play with it.
|
|
|
|
*/
|
2007-07-19 16:49:23 +08:00
|
|
|
module_init(init);
|
|
|
|
module_exit(fini);
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>");
|