]> err.no Git - linux-2.6/blobdiff - drivers/lguest/lg.h
Introduce "hcall" pointer to indicate pending hypercall.
[linux-2.6] / drivers / lguest / lg.h
index 3e2ddfbc816e9fc1396c8fe724e14e1732928502..662994b776cc8f7414a38b3e221ad5a7b9e82a28 100644 (file)
@@ -1,66 +1,45 @@
 #ifndef _LGUEST_H
 #define _LGUEST_H
 
-#include <asm/desc.h>
-
-#define GDT_ENTRY_LGUEST_CS    10
-#define GDT_ENTRY_LGUEST_DS    11
-#define LGUEST_CS              (GDT_ENTRY_LGUEST_CS * 8)
-#define LGUEST_DS              (GDT_ENTRY_LGUEST_DS * 8)
-
 #ifndef __ASSEMBLY__
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/stringify.h>
-#include <linux/binfmts.h>
 #include <linux/futex.h>
 #include <linux/lguest.h>
 #include <linux/lguest_launcher.h>
 #include <linux/wait.h>
 #include <linux/err.h>
 #include <asm/semaphore.h>
-#include "irq_vectors.h"
 
-#define GUEST_PL 1
-
-struct lguest_regs
-{
-       /* Manually saved part. */
-       unsigned long ebx, ecx, edx;
-       unsigned long esi, edi, ebp;
-       unsigned long gs;
-       unsigned long eax;
-       unsigned long fs, ds, es;
-       unsigned long trapnum, errcode;
-       /* Trap pushed part */
-       unsigned long eip;
-       unsigned long cs;
-       unsigned long eflags;
-       unsigned long esp;
-       unsigned long ss;
-};
+#include <asm/lguest.h>
 
 void free_pagetables(void);
 int init_pagetables(struct page **switcher_page, unsigned int pages);
 
-/* Full 4G segment descriptors, suitable for CS and DS. */
-#define FULL_EXEC_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9b00})
-#define FULL_SEGMENT ((struct desc_struct){0x0000ffff, 0x00cf9300})
-
 struct lguest_dma_info
 {
        struct list_head list;
        union futex_key key;
        unsigned long dmas;
+       struct lguest *owner;
        u16 next_dma;
        u16 num_dmas;
-       u16 guestid;
        u8 interrupt;   /* 0 when not registered */
 };
 
-/* We have separate types for the guest's ptes & pgds and the shadow ptes &
- * pgds.  Since this host might use three-level pagetables and the guest and
- * shadow pagetables don't, we can't use the normal pte_t/pgd_t. */
+/*H:310 The page-table code owes a great debt of gratitude to Andi Kleen.  He
+ * reviewed the original code which used "u32" for all page table entries, and
+ * insisted that it would be far clearer with explicit typing.  I thought it
+ * was overkill, but he was right: it is much clearer than it was before.
+ *
+ * We have separate types for the Guest's ptes & pgds and the shadow ptes &
+ * pgds.  There's already a Linux type for these (pte_t and pgd_t) but they
+ * change depending on kernel config options (PAE). */
+
+/* Each entry is identical: lower 12 bits of flags and upper 20 bits for the
+ * "page frame number" (0 == first physical page, etc).  They are different
+ * types so the compiler will warn us if we mix them improperly. */
 typedef union {
        struct { unsigned flags:12, pfn:20; };
        struct { unsigned long val; } raw;
@@ -77,8 +56,12 @@ typedef union {
        struct { unsigned flags:12, pfn:20; };
        struct { unsigned long val; } raw;
 } gpte_t;
+
+/* We have two convenient macros to convert a "raw" value as handed to us by
+ * the Guest into the correct Guest PGD or PTE type. */
 #define mkgpte(_val) ((gpte_t){.raw.val = _val})
 #define mkgpgd(_val) ((gpgd_t){.raw.val = _val})
+/*:*/
 
 struct pgdir
 {
@@ -86,23 +69,6 @@ struct pgdir
        spgd_t *pgdir;
 };
 
-/* This is a guest-specific page (mapped ro) into the guest. */
-struct lguest_ro_state
-{
-       /* Host information we need to restore when we switch back. */
-       u32 host_cr3;
-       struct Xgt_desc_struct host_idt_desc;
-       struct Xgt_desc_struct host_gdt_desc;
-       u32 host_sp;
-
-       /* Fields which are used when guest is running. */
-       struct Xgt_desc_struct guest_idt_desc;
-       struct Xgt_desc_struct guest_gdt_desc;
-       struct i386_hw_tss guest_tss;
-       struct desc_struct guest_idt[IDT_ENTRIES];
-       struct desc_struct guest_gdt[GDT_ENTRIES];
-};
-
 /* We have two pages shared with guests, per cpu.  */
 struct lguest_pages
 {
@@ -128,8 +94,10 @@ struct lguest
        struct lguest_data __user *lguest_data;
        struct task_struct *tsk;
        struct mm_struct *mm;   /* == tsk->mm, but that becomes NULL on exit */
-       u16 guestid;
        u32 pfn_limit;
+       /* This provides the offset to the base of guest-physical
+        * memory in the Launcher. */
+       void __user *mem_base;
        u32 page_offset;
        u32 cr2;
        int halted;
@@ -138,6 +106,9 @@ struct lguest
        u32 esp1;
        u8 ss1;
 
+       /* If a hypercall was asked for, this points to the arguments. */
+       struct lguest_regs *hcall;
+
        /* Do we need to stop what we're doing and return to userspace? */
        int break_out;
        wait_queue_head_t break_wq;
@@ -166,12 +137,7 @@ struct lguest
        /* Dead? */
        const char *dead;
 
-       /* The GDT entries copied into lguest_ro_state when running. */
-       struct desc_struct gdt[GDT_ENTRIES];
-
-       /* The IDT entries: some copied into lguest_ro_state when running. */
-       struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
-       struct desc_struct syscall_idt;
+       struct lguest_arch arch;
 
        /* Virtual clock device */
        struct hrtimer hrt;
@@ -180,7 +146,6 @@ struct lguest
        DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
 };
 
-extern struct lguest lguests[];
 extern struct mutex lguest_lock;
 
 /* core.c: */
@@ -188,7 +153,6 @@ u32 lgread_u32(struct lguest *lg, unsigned long addr);
 void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val);
 void lgread(struct lguest *lg, void *buf, unsigned long addr, unsigned len);
 void lgwrite(struct lguest *lg, unsigned long, const void *buf, unsigned len);
-int find_free_guest(void);
 int lguest_address_ok(const struct lguest *lg,
                      unsigned long addr, unsigned long len);
 int run_guest(struct lguest *lg, unsigned long __user *user);
@@ -228,6 +192,15 @@ void map_switcher_in_guest(struct lguest *lg, struct lguest_pages *pages);
 int demand_page(struct lguest *info, unsigned long cr2, int errcode);
 void pin_page(struct lguest *lg, unsigned long vaddr);
 
+/* <arch>/core.c: */
+void lguest_arch_host_init(void);
+void lguest_arch_host_fini(void);
+void lguest_arch_run_guest(struct lguest *lg);
+void lguest_arch_handle_trap(struct lguest *lg);
+
+/* <arch>/switcher.S: */
+extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
+
 /* lguest_user.c: */
 int lguest_device_init(void);
 void lguest_device_remove(void);
@@ -243,7 +216,32 @@ unsigned long get_dma_buffer(struct lguest *lg, unsigned long key,
 
 /* hypercalls.c: */
 void do_hypercalls(struct lguest *lg);
-
+void write_timestamp(struct lguest *lg);
+
+/*L:035
+ * Let's step aside for the moment, to study one important routine that's used
+ * widely in the Host code.
+ *
+ * There are many cases where the Guest does something invalid, like pass crap
+ * to a hypercall.  Since only the Guest kernel can make hypercalls, it's quite
+ * acceptable to simply terminate the Guest and give the Launcher a nicely
+ * formatted reason.  It's also simpler for the Guest itself, which doesn't
+ * need to check most hypercalls for "success"; if you're still running, it
+ * succeeded.
+ *
+ * Once this is called, the Guest will never run again, so most Host code can
+ * call this then continue as if nothing had happened.  This means many
+ * functions don't have to explicitly return an error code, which keeps the
+ * code simple.
+ *
+ * It also means that this can be called more than once: only the first one is
+ * remembered.  The only trick is that we still need to kill the Guest even if
+ * we can't allocate memory to store the reason.  Linux has a neat way of
+ * packing error codes into invalid pointers, so we use that here.
+ *
+ * Like any macro which uses an "if", it is safely wrapped in a run-once "do {
+ * } while(0)".
+ */
 #define kill_guest(lg, fmt...)                                 \
 do {                                                           \
        if (!(lg)->dead) {                                      \
@@ -252,6 +250,7 @@ do {                                                                \
                        (lg)->dead = ERR_PTR(-ENOMEM);          \
        }                                                       \
 } while(0)
+/* (End of aside) :*/
 
 static inline unsigned long guest_pa(struct lguest *lg, unsigned long vaddr)
 {