X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=drivers%2Flguest%2Flg.h;h=662994b776cc8f7414a38b3e221ad5a7b9e82a28;hb=cc6d4fbcef328acdc9fa7023e69f39f753f72fe1;hp=3e2ddfbc816e9fc1396c8fe724e14e1732928502;hpb=5e16e3f0e24dadb79b96b6134cd3303f0d42f0c5;p=linux-2.6 diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h index 3e2ddfbc81..662994b776 100644 --- a/drivers/lguest/lg.h +++ b/drivers/lguest/lg.h @@ -1,66 +1,45 @@ #ifndef _LGUEST_H #define _LGUEST_H -#include - -#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 #include #include -#include #include #include #include #include #include #include -#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 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); +/* /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); + +/* /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) {