diff options
author | Juergen Gross <jgross@suse.com> | 2017-08-16 19:31:57 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2017-08-24 09:57:28 +0200 |
commit | ecda85e70277ef24e44a1f6bc00243cebd19f985 (patch) | |
tree | cd094195d6ab0ed476ad093236880c8ce145e8e4 /drivers | |
parent | edcb5cf84f05e5d2e2af25422a72ccde359fcca9 (diff) |
x86/lguest: Remove lguest support
Lguest seems to be rather unused these days. It has seen only patches
ensuring it still builds the last two years and its official state is
"Odd Fixes".
Remove it in order to be able to clean up the paravirt code.
Signed-off-by: Juergen Gross <jgross@suse.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: boris.ostrovsky@oracle.com
Cc: lguest@lists.ozlabs.org
Cc: rusty@rustcorp.com.au
Cc: xen-devel@lists.xenproject.org
Link: http://lkml.kernel.org/r/20170816173157.8633-3-jgross@suse.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/Makefile | 1 | ||||
-rw-r--r-- | drivers/block/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/virtio_console.c | 2 | ||||
-rw-r--r-- | drivers/lguest/Kconfig | 13 | ||||
-rw-r--r-- | drivers/lguest/Makefile | 26 | ||||
-rw-r--r-- | drivers/lguest/README | 47 | ||||
-rw-r--r-- | drivers/lguest/core.c | 398 | ||||
-rw-r--r-- | drivers/lguest/hypercalls.c | 304 | ||||
-rw-r--r-- | drivers/lguest/interrupts_and_traps.c | 706 | ||||
-rw-r--r-- | drivers/lguest/lg.h | 258 | ||||
-rw-r--r-- | drivers/lguest/lguest_user.c | 446 | ||||
-rw-r--r-- | drivers/lguest/page_tables.c | 1239 | ||||
-rw-r--r-- | drivers/lguest/segments.c | 228 | ||||
-rw-r--r-- | drivers/lguest/x86/core.c | 724 | ||||
-rw-r--r-- | drivers/lguest/x86/switcher_32.S | 388 | ||||
-rw-r--r-- | drivers/net/Kconfig | 2 | ||||
-rw-r--r-- | drivers/tty/hvc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/virtio/Kconfig | 4 |
19 files changed, 7 insertions, 4785 deletions
diff --git a/drivers/Makefile b/drivers/Makefile index dfdcda00bfe3..d90fdc413648 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -125,7 +125,6 @@ obj-$(CONFIG_ACCESSIBILITY) += accessibility/ obj-$(CONFIG_ISDN) += isdn/ obj-$(CONFIG_EDAC) += edac/ obj-$(CONFIG_EISA) += eisa/ -obj-y += lguest/ obj-$(CONFIG_CPU_FREQ) += cpufreq/ obj-$(CONFIG_CPU_IDLE) += cpuidle/ obj-y += mmc/ diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 8ddc98279c8f..80aaf3420e12 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -470,7 +470,7 @@ config VIRTIO_BLK depends on VIRTIO ---help--- This is the virtual block driver for virtio. It can be used with - lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. + QEMU based VMMs (like KVM or Xen). Say Y or M. config VIRTIO_BLK_SCSI bool "SCSI passthrough request for the Virtio block driver" diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index ccd239ab879f..623714344600 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -161,7 +161,7 @@ config VIRTIO_CONSOLE depends on VIRTIO && TTY select HVC_DRIVER help - Virtio console for use with lguest and other hypervisors. + Virtio console for use with hypervisors. Also serves as a general-purpose serial device for data transfer between the guest and host. Character devices at diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index ad843eb02ae7..4d229dde6522 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -1130,7 +1130,7 @@ static const struct file_operations port_fops = { * We turn the characters into a scatter-gather list, add it to the * output queue and then kick the Host. Then we sit here waiting for * it to finish: inefficient in theory, but in practice - * implementations will do it immediately (lguest's Launcher does). + * implementations will do it immediately. */ static int put_chars(u32 vtermno, const char *buf, int count) { diff --git a/drivers/lguest/Kconfig b/drivers/lguest/Kconfig deleted file mode 100644 index 169172d2ba05..000000000000 --- a/drivers/lguest/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config LGUEST - tristate "Linux hypervisor example code" - depends on X86_32 && EVENTFD && TTY && PCI_DIRECT - select HVC_DRIVER - ---help--- - This is a very simple module which allows you to run - multiple instances of the same Linux kernel, using the - "lguest" command found in the tools/lguest directory. - - Note that "lguest" is pronounced to rhyme with "fell quest", - not "rustyvisor". See tools/lguest/lguest.txt. - - If unsure, say N. If curious, say M. If masochistic, say Y. diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile deleted file mode 100644 index 16f52ee73994..000000000000 --- a/drivers/lguest/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Host requires the other files, which can be a module. -obj-$(CONFIG_LGUEST) += lg.o -lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \ - segments.o lguest_user.o - -lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o - -Preparation Preparation!: PREFIX=P -Guest: PREFIX=G -Drivers: PREFIX=D -Launcher: PREFIX=L -Host: PREFIX=H -Switcher: PREFIX=S -Mastery: PREFIX=M -Beer: - @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" -Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: - @sh ../../tools/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` -Puppy: - @clear - @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" - @sleep 2; clear; printf "\n\n Sit!\n\n"; sleep 1; clear - @printf " __ \n ()'\`; \n /\\|\` \n / | \n(/_)_|_ \n" - @sleep 2; clear; printf "\n\n Stand!\n\n"; sleep 1; clear - @printf " __ \n ()'\`; \n /\\|\` \n /._.= \n /| / \n(_\_)_ \n" - @sleep 2; clear; printf "\n\n Good puppy!\n\n"; sleep 1; clear diff --git a/drivers/lguest/README b/drivers/lguest/README deleted file mode 100644 index b7db39a64c66..000000000000 --- a/drivers/lguest/README +++ /dev/null @@ -1,47 +0,0 @@ -Welcome, friend reader, to lguest. - -Lguest is an adventure, with you, the reader, as Hero. I can't think of many -5000-line projects which offer both such capability and glimpses of future -potential; it is an exciting time to be delving into the source! - -But be warned; this is an arduous journey of several hours or more! And as we -know, all true Heroes are driven by a Noble Goal. Thus I offer a Beer (or -equivalent) to anyone I meet who has completed this documentation. - -So get comfortable and keep your wits about you (both quick and humorous). -Along your way to the Noble Goal, you will also gain masterly insight into -lguest, and hypervisors and x86 virtualization in general. - -Our Quest is in seven parts: (best read with C highlighting turned on) - -I) Preparation - - In which our potential hero is flown quickly over the landscape for a - taste of its scope. Suitable for the armchair coders and other such - persons of faint constitution. - -II) Guest - - Where we encounter the first tantalising wisps of code, and come to - understand the details of the life of a Guest kernel. - -III) Drivers - - Whereby the Guest finds its voice and become useful, and our - understanding of the Guest is completed. - -IV) Launcher - - Where we trace back to the creation of the Guest, and thus begin our - understanding of the Host. - -V) Host - - Where we master the Host code, through a long and tortuous journey. - Indeed, it is here that our hero is tested in the Bit of Despair. - -VI) Switcher - - Where our understanding of the intertwined nature of Guests and Hosts - is completed. - -VII) Mastery - - Where our fully fledged hero grapples with the Great Question: - "What next?" - -make Preparation! -Rusty Russell. diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c deleted file mode 100644 index 395ed1961dbf..000000000000 --- a/drivers/lguest/core.c +++ /dev/null @@ -1,398 +0,0 @@ -/*P:400 - * This contains run_guest() which actually calls into the Host<->Guest - * Switcher and analyzes the return, such as determining if the Guest wants the - * Host to do something. This file also contains useful helper routines. -:*/ -#include <linux/module.h> -#include <linux/stringify.h> -#include <linux/stddef.h> -#include <linux/io.h> -#include <linux/mm.h> -#include <linux/sched/signal.h> -#include <linux/vmalloc.h> -#include <linux/cpu.h> -#include <linux/freezer.h> -#include <linux/highmem.h> -#include <linux/slab.h> -#include <asm/paravirt.h> -#include <asm/pgtable.h> -#include <linux/uaccess.h> -#include <asm/poll.h> -#include <asm/asm-offsets.h> -#include "lg.h" - -unsigned long switcher_addr; -struct page **lg_switcher_pages; -static struct vm_struct *switcher_text_vma; -static struct vm_struct *switcher_stacks_vma; - -/* This One Big lock protects all inter-guest data structures. */ -DEFINE_MUTEX(lguest_lock); - -/*H:010 - * We need to set up the Switcher at a high virtual address. Remember the - * 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 - * it's not a simple one-liner. - */ -static __init int map_switcher(void) -{ - int i, err; - - /* - * 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. - */ - - /* We assume Switcher text fits into a single page. */ - if (end_switcher_text - start_switcher_text > PAGE_SIZE) { - printk(KERN_ERR "lguest: switcher text too large (%zu)\n", - end_switcher_text - start_switcher_text); - return -EINVAL; - } - - /* - * We allocate an array of struct page pointers. map_vm_area() wants - * this, rather than just an array of pages. - */ - lg_switcher_pages = kmalloc(sizeof(lg_switcher_pages[0]) - * TOTAL_SWITCHER_PAGES, - GFP_KERNEL); - if (!lg_switcher_pages) { - err = -ENOMEM; - goto out; - } - - /* - * Now we actually allocate the pages. The Guest will see these pages, - * so we make sure they're zeroed. - */ - for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) { - lg_switcher_pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO); - if (!lg_switcher_pages[i]) { - err = -ENOMEM; - goto free_some_pages; - } - } - - /* - * Copy in the compiled-in Switcher code (from x86/switcher_32.S). - * It goes in the first page, which we map in momentarily. - */ - memcpy(kmap(lg_switcher_pages[0]), start_switcher_text, - end_switcher_text - start_switcher_text); - kunmap(lg_switcher_pages[0]); - - /* - * We place the Switcher underneath the fixmap area, which is the - * highest virtual address we can get. This is important, since we - * tell the Guest it can't access this memory, so we want its ceiling - * as high as possible. - */ - switcher_addr = FIXADDR_START - TOTAL_SWITCHER_PAGES*PAGE_SIZE; - - /* - * Now we reserve the "virtual memory area"s we want. We might - * not get them in theory, but in practice it's worked so far. - * - * We want the switcher text to be read-only and executable, and - * the stacks to be read-write and non-executable. - */ - switcher_text_vma = __get_vm_area(PAGE_SIZE, VM_ALLOC|VM_NO_GUARD, - switcher_addr, - switcher_addr + PAGE_SIZE); - - if (!switcher_text_vma) { - err = -ENOMEM; - printk("lguest: could not map switcher pages high\n"); - goto free_pages; - } - - switcher_stacks_vma = __get_vm_area(SWITCHER_STACK_PAGES * PAGE_SIZE, - VM_ALLOC|VM_NO_GUARD, - switcher_addr + PAGE_SIZE, - switcher_addr + TOTAL_SWITCHER_PAGES * PAGE_SIZE); - if (!switcher_stacks_vma) { - err = -ENOMEM; - printk("lguest: could not map switcher pages high\n"); - goto free_text_vma; - } - - /* - * This code actually sets up the pages we've allocated to appear at - * switcher_addr. map_vm_area() takes the vma we allocated above, the - * kind of pages we're mapping (kernel text pages and kernel writable - * pages respectively), and a pointer to our array of struct pages. - */ - err = map_vm_area(switcher_text_vma, PAGE_KERNEL_RX, lg_switcher_pages); - if (err) { - printk("lguest: text map_vm_area failed: %i\n", err); - goto free_vmas; - } - - err = map_vm_area(switcher_stacks_vma, PAGE_KERNEL, - lg_switcher_pages + SWITCHER_TEXT_PAGES); - if (err) { - printk("lguest: stacks map_vm_area failed: %i\n", err); - goto free_vmas; - } - - /* - * Now the Switcher is mapped at the right address, we can't fail! - */ - printk(KERN_INFO "lguest: mapped switcher at %p\n", - switcher_text_vma->addr); - /* And we succeeded... */ - return 0; - -free_vmas: - /* Undoes map_vm_area and __get_vm_area */ - vunmap(switcher_stacks_vma->addr); -free_text_vma: - vunmap(switcher_text_vma->addr); -free_pages: - i = TOTAL_SWITCHER_PAGES; -free_some_pages: - for (--i; i >= 0; i--) - __free_pages(lg_switcher_pages[i], 0); - kfree(lg_switcher_pages); -out: - return err; -} -/*:*/ - -/* Cleaning up the mapping when the module is unloaded is almost... too easy. */ -static void unmap_switcher(void) -{ - unsigned int i; - - /* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */ - vunmap(switcher_text_vma->addr); - vunmap(switcher_stacks_vma->addr); - /* Now we just need to free the pages we copied the switcher into */ - for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) - __free_pages(lg_switcher_pages[i], 0); - kfree(lg_switcher_pages); -} - -/*H:032 - * Dealing With Guest Memory. - * - * Before we go too much further into the Host, we need to grok the routines - * we use to deal with Guest memory. - * - * When the Guest gives us (what it thinks is) a physical address, we can use - * the normal copy_from_user() & copy_to_user() on the corresponding place in - * the memory region allocated by the Launcher. - * - * 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 - * positive by overflowing, too. - */ -bool lguest_address_ok(const struct lguest *lg, - unsigned long addr, unsigned long len) -{ - return addr+len <= lg->pfn_limit * PAGE_SIZE && (addr+len >= addr); -} - -/* - * This routine copies memory from the Guest. Here we can see how useful the - * kill_lguest() routine we met in the Launcher can be: we return a random - * value (all zeroes) instead of needing to return an error. - */ -void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes) -{ - if (!lguest_address_ok(cpu->lg, addr, bytes) - || copy_from_user(b, cpu->lg->mem_base + addr, bytes) != 0) { - /* copy_from_user should do this, but as we rely on it... */ - memset(b, 0, bytes); - kill_guest(cpu, "bad read address %#lx len %u", addr, bytes); - } -} - -/* This is the write (copy into Guest) version. */ -void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b, - unsigned bytes) -{ - 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); -} -/*:*/ - -/*H:030 - * Let's jump straight to the the main loop which runs the Guest. - * Remember, this is called by the Launcher reading /dev/lguest, and we keep - * going around and around until something interesting happens. - */ -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; - bool more; - - /* First we run any hypercalls the Guest wants done. */ - if (cpu->hcall) - do_hypercalls(cpu); - - /* 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); - } - - /* - * All long-lived kernel loops need to check with this horrible - * thing called the freezer. If the Host is trying to suspend, - * it stops us. - */ - try_to_freeze(); - - /* Check for signals */ - if (signal_pending(current)) - return -ERESTARTSYS; - - /* - * Check if there are any interrupts which can be delivered now: - * if so, this sets up the hander to be executed when we next - * run the Guest. - */ - irq = interrupt_pending(cpu, &more); - if (irq < LGUEST_IRQS) - try_deliver_interrupt(cpu, irq, more); - - /* - * Just make absolutely sure the Guest is still alive. One of - * those hypercalls could have been fatal, for example. - */ - if (cpu->lg->dead) - break; - - /* - * If the Guest asked to be stopped, we sleep. The Guest's - * clock timer will wake us. - */ - if (cpu->halted) { - set_current_state(TASK_INTERRUPTIBLE); - /* - * Just before we sleep, make sure no interrupt snuck in - * which we should be doing. - */ - if (interrupt_pending(cpu, &more) < LGUEST_IRQS) - set_current_state(TASK_RUNNING); - else - schedule(); - continue; - } - - /* - * OK, now we're ready to jump into the Guest. First we put up - * the "Do Not Disturb" sign: - */ - local_irq_disable(); - - /* Actually run the Guest until something happens. */ - lguest_arch_run_guest(cpu); - - /* Now we're ready to be interrupted or moved to other CPUs */ - local_irq_enable(); - - /* Now we deal with whatever happened to the Guest. */ - lguest_arch_handle_trap(cpu); - } - - /* Special case: Guest is 'dead' but wants a reboot. */ - if (cpu->lg->dead == ERR_PTR(-ERESTART)) - return -ERESTART; - - /* The Guest is dead => "No such file or directory" */ - return -ENOENT; -} - -/*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. - */ -static int __init init(void) -{ - int err; - - /* Lguest can't run under Xen, VMI or itself. It does Tricky Stuff. */ - if (get_kernel_rpl() != 0) { - printk("lguest is afraid of being a guest\n"); - return -EPERM; - } - - /* First we put the Switcher up in very high virtual memory. */ - err = map_switcher(); - if (err) - goto out; - - /* We might need to reserve an interrupt vector. */ - err = init_interrupts(); - if (err) - goto unmap; - - /* /dev/lguest needs to be registered. */ - err = lguest_device_init(); - if (err) - goto free_interrupts; - - /* Finally we do some architecture-specific setup. */ - lguest_arch_host_init(); - - /* All good! */ - return 0; - -free_interrupts: - free_interrupts(); -unmap: - unmap_switcher(); -out: - return err; -} - -/* Cleaning up is just the same code, backwards. With a little French. */ -static void __exit fini(void) -{ - lguest_device_remove(); - free_interrupts(); - unmap_switcher(); - - lguest_arch_host_fini(); -} -/*:*/ - -/* - * The Host side of lguest can be a module. This is a nice way for people to - * play with it. - */ -module_init(init); -module_exit(fini); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Rusty Russell <rusty@rustcorp.com.au>"); diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c deleted file mode 100644 index 601f81c04873..000000000000 --- a/drivers/lguest/hypercalls.c +++ /dev/null @@ -1,304 +0,0 @@ -/*P:500 - * Just as userspace programs request kernel operations through a system - * call, the Guest requests Host operations through a "hypercall". You might - * notice this nomenclature doesn't really follow any logic, but the name has - * been around for long enough that we're stuck with it. As you'd expect, this - * code is basically a one big switch statement. -:*/ - -/* Copyright (C) 2006 Rusty Russell IBM Corporation - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ -#include <linux/uaccess.h> -#include <linux/syscalls.h> -#include <linux/mm.h> -#include <linux/ktime.h> -#include <asm/page.h> -#include <asm/pgtable.h> -#include "lg.h" - -/*H:120 - * This is the core hypercall routine: where the Guest gets what it wants. - * Or gets killed. Or, in the case of LHCALL_SHUTDOWN, both. - */ -static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args) -{ - switch (args->arg0) { - case LHCALL_FLUSH_ASYNC: - /* - * This call does nothing, except by breaking out of the Guest - * it makes us process all the asynchronous hypercalls. - */ - break; - case LHCALL_SEND_INTERRUPTS: - /* - * This call does nothing too, but by breaking out of the Guest - * it makes us process any pending interrupts. - */ - break; - case LHCALL_LGUEST_INIT: - /* - * You can't get here unless you're already initialized. Don't - * do that. - */ - kill_guest(cpu, "already have lguest_data"); - break; - case LHCALL_SHUTDOWN: { - char msg[128]; - /* - * Shutdown is such a trivial hypercall that we do it in five - * lines right here. - * - * If the lgread fails, it will call kill_guest() itself; the - * kill_guest() with the message will be ignored. - */ - __lgread(cpu, msg, args->arg1, sizeof(msg)); - msg[sizeof(msg)-1] = '\0'; - kill_guest(cpu, "CRASH: %s", msg); - if (args->arg2 == LGUEST_SHUTDOWN_RESTART) - cpu->lg->dead = ERR_PTR(-ERESTART); - break; - } - case LHCALL_FLUSH_TLB: - /* FLUSH_TLB comes in two flavors, depending on the argument: */ - if (args->arg1) - guest_pagetable_clear_all(cpu); - else - guest_pagetable_flush_user(cpu); - break; - - /* - * All these calls simply pass the arguments through to the right - * routines. - */ - case LHCALL_NEW_PGTABLE: - guest_new_pagetable(cpu, args->arg1); - break; - case LHCALL_SET_STACK: - guest_set_stack(cpu, args->arg1, args->arg2, args->arg3); - break; - case LHCALL_SET_PTE: -#ifdef CONFIG_X86_PAE - guest_set_pte(cpu, args->arg1, args->arg2, - __pte(args->arg3 | (u64)args->arg4 << 32)); -#else - guest_set_pte(cpu, args->arg1, args->arg2, __pte(args->arg3)); -#endif - break; - case LHCALL_SET_PGD: - guest_set_pgd(cpu->lg, args->arg1, args->arg2); - break; -#ifdef CONFIG_X86_PAE - case LHCALL_SET_PMD: - guest_set_pmd(cpu->lg, args->arg1, args->arg2); - break; -#endif - case LHCALL_SET_CLOCKEVENT: - guest_set_clockevent(cpu, args->arg1); - break; - case LHCALL_HALT: - /* Similarly, this sets the halted flag for run_guest(). */ - cpu->halted = 1; - break; - default: - /* It should be an architecture-specific hypercall. */ - if (lguest_arch_do_hcall(cpu, args)) - kill_guest(cpu, "Bad hypercall %li\n", args->arg0); - } -} - -/*H:124 - * Asynchronous hypercalls are easy: we just look in the array in the - * Guest's "struct lguest_data" to see if any new ones are marked "ready". - * - * We are careful to do these in order: obviously we respect the order the - * Guest put them in the ring, but we also promise the Guest that they will - * happen before any normal hypercall (which is why we check this before - * checking for a normal hcall). - */ -static void do_async_hcalls(struct lg_cpu *cpu) -{ - unsigned int i; - u8 st[LHCALL_RING_SIZE]; - - /* For simplicity, we copy the entire call status array in at once. */ - if (copy_from_user(&st, &cpu->lg->lguest_data->hcall_status, sizeof(st))) - return; - - /* We process "struct lguest_data"s hcalls[] ring once. */ - for (i = 0; i < ARRAY_SIZE(st); i++) { - struct hcall_args args; - /* - * We remember where we were up to from last time. This makes - * sure that the hypercalls are done in the order the Guest - * places them in the ring. - */ - unsigned int n = cpu->next_hcall; - - /* 0xFF means there's no call here (yet). */ - if (st[n] == 0xFF) - break; - - /* - * OK, we have hypercall. Increment the "next_hcall" cursor, - * and wrap back to 0 if we reach the end. - */ - if (++cpu->next_hcall == LHCALL_RING_SIZE) - cpu->next_hcall = 0; - - /* - * Copy the hypercall arguments into a local copy of the - * hcall_args struct. - */ - if (copy_from_user(&args, &cpu->lg->lguest_data->hcalls[n], - sizeof(struct hcall_args))) { - kill_guest(cpu, "Fetching async hypercalls"); - break; - } - - /* Do the hypercall, same as a normal one. */ - do_hcall(cpu, &args); - - /* Mark the hypercall done. */ - if (put_user(0xFF, &cpu->lg->lguest_data->hcall_status[n])) { - kill_guest(cpu, "Writing result for async hypercall"); - break; - } - - /* - * Stop doing hypercalls if they want to notify the Launcher: - * it needs to service this first. - */ - if (cpu->pending.trap) - break; - } -} - -/* - * Last of all, we look at what happens first of all. The very first time the - * Guest makes a hypercall, we end up here to set things up: - */ -static void initialize(struct lg_cpu *cpu) -{ - /* - * You can't do anything until you're initialized. The Guest knows the - * rules, so we're unforgiving here. - */ - if (cpu->hcall->arg0 != LHCALL_LGUEST_INIT) { - kill_guest(cpu, "hypercall %li before INIT", cpu->hcall->arg0); - return; - } - - if (lguest_arch_init_hypercalls(cpu)) - kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); - - /* - * The Guest tells us where we're not to deliver interrupts by putting - * the instruction address into "struct lguest_data". - */ - if (get_user(cpu->lg->noirq_iret, &cpu->lg->lguest_data->noirq_iret)) - kill_guest(cpu, "bad guest page %p", cpu->lg->lguest_data); - - /* - * We write the current time into the Guest's data page once so it can - * set its clock. - */ - write_timestamp(cpu); - - /* page_tables.c will also do some setup. */ - page_table_guest_data_init(cpu); - - /* - * This is the one case where the above accesses might have been the - * first write to a Guest page. This may have caused a copy-on-write - * fault, but the old page might be (read-only) in the Guest - * pagetable. - */ - guest_pagetable_clear_all(cpu); -} -/*:*/ - -/*M:013 - * If a Guest reads from a page (so creates a mapping) that it has never - * written to, and then the Launcher writes to it (ie. the output of a virtual - * device), the Guest will still see the old page. In practice, this never - * happens: why would the Guest read a page which it has never written to? But - * a similar scenario might one day bite us, so it's worth mentioning. - * - * Note that if we used a shared anonymous mapping in the Launcher instead of - * mapping /dev/zero private, we wouldn't worry about cop-on-write. And we - * need that to switch the Launcher to processes (away from threads) anyway. -:*/ - -/*H:100 - * Hypercalls - * - * Remember from the Guest, hypercalls come in two flavors: normal and - * asynchronous. This file handles both of types. - */ -void do_hypercalls(struct lg_cpu *cpu) -{ - /* Not initialized yet? This hypercall must do it. */ - if (unlikely(!cpu->lg->lguest_data)) { - /* Set up the "struct lguest_data" */ - initialize(cpu); - /* Hcall is done. */ - cpu->hcall = NULL; - return; - } - - /* - * The Guest has initialized. - * - * Look in the hypercall ring for the async hypercalls: - */ - do_async_hcalls(cpu); - - /* - * If we stopped reading the hypercall ring because the Guest did a - * NOTIFY to the Launcher, we want to return now. Otherwise we do - * the hypercall. - */ - if (!cpu->pending.trap) { - do_hcall(cpu, cpu->hcall); - /* - * Tricky point: we reset the hcall pointer to mark the - * hypercall as "done". We use the hcall pointer rather than - * the trap number to indicate a hypercall is pending. - * Normally it doesn't matter: the Guest will run again and - * update the trap number before we come back here. - * - * However, if we are signalled or the Guest sends I/O to the - * Launcher, the run_guest() loop will exit without running the - * Guest. When it comes back it would try to re-run the - * hypercall. Finding that bug sucked. - */ - cpu->hcall = NULL; - } -} - -/* - * This routine supplies the Guest with time: it's used for wallclock time at - * initial boot and as a rough time source if the TSC isn't available. - */ -void write_timestamp(struct lg_cpu *cpu) -{ - struct timespec now; - ktime_get_real_ts(&now); - if (copy_to_user(&cpu->lg->lguest_data->time, - &now, sizeof(struct timespec))) - kill_guest(cpu, "Writing timestamp"); -} diff --git a/drivers/lguest/interrupts_and_traps.c b/drivers/lguest/interrupts_and_traps.c deleted file mode 100644 index 67392b6ab845..000000000000 --- a/drivers/lguest/interrupts_and_traps.c +++ /dev/null @@ -1,706 +0,0 @@ -/*P:800 - * Interrupts (traps) are complicated enough to earn their own file. - * There are three classes of interrupts: - * - * 1) Real hardware interrupts which occur while we're running the Guest, - * 2) Interrupts for virtual devices attached to the Guest, and - * 3) Traps and faults from the Guest. - * - * Real hardware interrupts must be delivered to the Host, not the Guest. - * Virtual interrupts must be delivered to the Guest, but we make them look - * just like real hardware would deliver them. Traps from the Guest can be set - * up to go directly back into the Guest, but sometimes the Host wants to see - * them first, so we also have a way of "reflecting" them into the Guest as if - * they had been delivered to it directly. -:*/ -#include <linux/uaccess.h> -#include <linux/interrupt.h> -#include <linux/module.h> -#include <linux/sched.h> -#include "lg.h" - -/* Allow Guests to use a non-128 (ie. non-Linux) syscall trap. */ -static unsigned int syscall_vector = IA32_SYSCALL_VECTOR; -module_param(syscall_vector, uint, 0444); - -/* The address of the interrupt handler is split into two bits: */ -static unsigned long idt_address(u32 lo, u32 hi) -{ - return (lo & 0x0000FFFF) | (hi & 0xFFFF0000); -} - -/* - * The "type" of the interrupt handler is a 4 bit field: we only support a - * couple of types. - */ -static int idt_type(u32 lo, u32 hi) -{ - return (hi >> 8) & 0xF; -} - -/* An IDT entry can't be used unless the "present" bit is set. */ -static bool idt_present(u32 lo, u32 hi) -{ - return (hi & 0x8000); -} - -/* - * We need a helper to "push" a value onto the Guest's stack, since that's a - * big part of what delivering an interrupt does. - */ -static void push_guest_stack(struct lg_cpu *cpu, unsigned long *gstack, u32 val) -{ - /* Stack grows upw |