Loading arch/x86/include/asm/lguest_hcall.h +4 −20 Original line number Original line Diff line number Diff line Loading @@ -26,36 +26,20 @@ #ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__ #include <asm/hw_irq.h> #include <asm/hw_irq.h> #include <asm/kvm_para.h> /*G:031 But first, how does our Guest contact the Host to ask for privileged /*G:031 But first, how does our Guest contact the Host to ask for privileged * operations? There are two ways: the direct way is to make a "hypercall", * operations? There are two ways: the direct way is to make a "hypercall", * to make requests of the Host Itself. * to make requests of the Host Itself. * * * Our hypercall mechanism uses the highest unused trap code (traps 32 and * We use the KVM hypercall mechanism. Eighteen hypercalls are * above are used by real hardware interrupts). Fifteen hypercalls are * available: the hypercall number is put in the %eax register, and the * available: the hypercall number is put in the %eax register, and the * arguments (when required) are placed in %edx, %ebx and %ecx. If a return * arguments (when required) are placed in %ebx, %ecx and %edx. If a return * value makes sense, it's returned in %eax. * value makes sense, it's returned in %eax. * * * Grossly invalid calls result in Sudden Death at the hands of the vengeful * Grossly invalid calls result in Sudden Death at the hands of the vengeful * Host, rather than returning failure. This reflects Winston Churchill's * Host, rather than returning failure. This reflects Winston Churchill's * definition of a gentleman: "someone who is only rude intentionally". */ * definition of a gentleman: "someone who is only rude intentionally". */ static inline unsigned long hcall(unsigned long call, unsigned long arg1, unsigned long arg2, unsigned long arg3) { /* "int" is the Intel instruction to trigger a trap. */ asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY) /* The call in %eax (aka "a") might be overwritten */ : "=a"(call) /* The arguments are in %eax, %edx, %ebx & %ecx */ : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3) /* "memory" means this might write somewhere in memory. * This isn't true for all calls, but it's safe to tell * gcc that it might happen so it doesn't get clever. */ : "memory"); return call; } /*:*/ /*:*/ /* Can't use our min() macro here: needs to be a constant */ /* Can't use our min() macro here: needs to be a constant */ Loading @@ -64,7 +48,7 @@ hcall(unsigned long call, #define LHCALL_RING_SIZE 64 #define LHCALL_RING_SIZE 64 struct hcall_args { struct hcall_args { /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */ /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */ unsigned long arg0, arg2, arg3, arg1; unsigned long arg0, arg1, arg2, arg3; }; }; #endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */ Loading arch/x86/lguest/boot.c +49 −29 Original line number Original line Diff line number Diff line Loading @@ -107,7 +107,7 @@ static void async_hcall(unsigned long call, unsigned long arg1, local_irq_save(flags); local_irq_save(flags); if (lguest_data.hcall_status[next_call] != 0xFF) { if (lguest_data.hcall_status[next_call] != 0xFF) { /* Table full, so do normal hcall which will flush table. */ /* Table full, so do normal hcall which will flush table. */ hcall(call, arg1, arg2, arg3); kvm_hypercall3(call, arg1, arg2, arg3); } else { } else { lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg1 = arg1; lguest_data.hcalls[next_call].arg1 = arg1; Loading @@ -134,13 +134,32 @@ static void async_hcall(unsigned long call, unsigned long arg1, * * * So, when we're in lazy mode, we call async_hcall() to store the call for * So, when we're in lazy mode, we call async_hcall() to store the call for * future processing: */ * future processing: */ static void lazy_hcall(unsigned long call, static void lazy_hcall1(unsigned long call, unsigned long arg1) { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall1(call, arg1); else async_hcall(call, arg1, 0, 0); } static void lazy_hcall2(unsigned long call, unsigned long arg1, unsigned long arg2) { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall2(call, arg1, arg2); else async_hcall(call, arg1, arg2, 0); } static void lazy_hcall3(unsigned long call, unsigned long arg1, unsigned long arg1, unsigned long arg2, unsigned long arg2, unsigned long arg3) unsigned long arg3) { { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) hcall(call, arg1, arg2, arg3); kvm_hypercall3(call, arg1, arg2, arg3); else else async_hcall(call, arg1, arg2, arg3); async_hcall(call, arg1, arg2, arg3); } } Loading @@ -150,7 +169,7 @@ static void lazy_hcall(unsigned long call, static void lguest_leave_lazy_mode(void) static void lguest_leave_lazy_mode(void) { { paravirt_leave_lazy(paravirt_get_lazy_mode()); paravirt_leave_lazy(paravirt_get_lazy_mode()); hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0); kvm_hypercall0(LHCALL_FLUSH_ASYNC); } } /*G:033 /*G:033 Loading Loading @@ -229,7 +248,7 @@ static void lguest_write_idt_entry(gate_desc *dt, /* Keep the local copy up to date. */ /* Keep the local copy up to date. */ native_write_idt_entry(dt, entrynum, g); native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ /* Tell Host about this new entry. */ hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); } } /* Changing to a different IDT is very rare: we keep the IDT up-to-date every /* Changing to a different IDT is very rare: we keep the IDT up-to-date every Loading @@ -241,7 +260,7 @@ static void lguest_load_idt(const struct desc_ptr *desc) struct desc_struct *idt = (void *)desc->address; struct desc_struct *idt = (void *)desc->address; for (i = 0; i < (desc->size+1)/8; i++) for (i = 0; i < (desc->size+1)/8; i++) hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); } } /* /* Loading @@ -262,7 +281,7 @@ static void lguest_load_idt(const struct desc_ptr *desc) static void lguest_load_gdt(const struct desc_ptr *desc) static void lguest_load_gdt(const struct desc_ptr *desc) { { BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES); BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES); hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0); kvm_hypercall2(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES); } } /* For a single GDT entry which changes, we do the lazy thing: alter our GDT, /* For a single GDT entry which changes, we do the lazy thing: alter our GDT, Loading @@ -272,7 +291,7 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, const void *desc, int type) const void *desc, int type) { { native_write_gdt_entry(dt, entrynum, desc, type); native_write_gdt_entry(dt, entrynum, desc, type); hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0); kvm_hypercall2(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES); } } /* OK, I lied. There are three "thread local storage" GDT entries which change /* OK, I lied. There are three "thread local storage" GDT entries which change Loading @@ -284,7 +303,7 @@ static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) * can't handle us removing entries we're currently using. So we clear * can't handle us removing entries we're currently using. So we clear * the GS register here: if it's needed it'll be reloaded anyway. */ * the GS register here: if it's needed it'll be reloaded anyway. */ lazy_load_gs(0); lazy_load_gs(0); lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0); lazy_hcall2(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu); } } /*G:038 That's enough excitement for now, back to ploughing through each of /*G:038 That's enough excitement for now, back to ploughing through each of Loading Loading @@ -382,7 +401,7 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx, static unsigned long current_cr0; static unsigned long current_cr0; static void lguest_write_cr0(unsigned long val) static void lguest_write_cr0(unsigned long val) { { lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0); lazy_hcall1(LHCALL_TS, val & X86_CR0_TS); current_cr0 = val; current_cr0 = val; } } Loading @@ -396,7 +415,7 @@ static unsigned long lguest_read_cr0(void) * the vowels have been optimized out. */ * the vowels have been optimized out. */ static void lguest_clts(void) static void lguest_clts(void) { { lazy_hcall(LHCALL_TS, 0, 0, 0); lazy_hcall1(LHCALL_TS, 0); current_cr0 &= ~X86_CR0_TS; current_cr0 &= ~X86_CR0_TS; } } Loading @@ -418,7 +437,7 @@ static bool cr3_changed = false; static void lguest_write_cr3(unsigned long cr3) static void lguest_write_cr3(unsigned long cr3) { { lguest_data.pgdir = cr3; lguest_data.pgdir = cr3; lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0); lazy_hcall1(LHCALL_NEW_PGTABLE, cr3); cr3_changed = true; cr3_changed = true; } } Loading Loading @@ -493,7 +512,7 @@ static void lguest_write_cr4(unsigned long val) static void lguest_pte_update(struct mm_struct *mm, unsigned long addr, static void lguest_pte_update(struct mm_struct *mm, unsigned long addr, pte_t *ptep) pte_t *ptep) { { lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low); lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low); } } static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, Loading @@ -509,8 +528,8 @@ static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) { { *pmdp = pmdval; *pmdp = pmdval; lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK, lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK, (__pa(pmdp)&(PAGE_SIZE-1))/4, 0); (__pa(pmdp) & (PAGE_SIZE - 1)) / 4); } } /* There are a couple of legacy places where the kernel sets a PTE, but we /* There are a couple of legacy places where the kernel sets a PTE, but we Loading @@ -526,7 +545,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval) { { *ptep = pteval; *ptep = pteval; if (cr3_changed) if (cr3_changed) lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 1); } } /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on Loading @@ -542,7 +561,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval) static void lguest_flush_tlb_single(unsigned long addr) static void lguest_flush_tlb_single(unsigned long addr) { { /* Simply set it to zero: if it was not, it will fault back in. */ /* Simply set it to zero: if it was not, it will fault back in. */ lazy_hcall(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0); lazy_hcall3(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0); } } /* This is what happens after the Guest has removed a large number of entries. /* This is what happens after the Guest has removed a large number of entries. Loading @@ -550,7 +569,7 @@ static void lguest_flush_tlb_single(unsigned long addr) * have changed, ie. virtual addresses below PAGE_OFFSET. */ * have changed, ie. virtual addresses below PAGE_OFFSET. */ static void lguest_flush_tlb_user(void) static void lguest_flush_tlb_user(void) { { lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 0); } } /* This is called when the kernel page tables have changed. That's not very /* This is called when the kernel page tables have changed. That's not very Loading @@ -558,7 +577,7 @@ static void lguest_flush_tlb_user(void) * slow), so it's worth separating this from the user flushing above. */ * slow), so it's worth separating this from the user flushing above. */ static void lguest_flush_tlb_kernel(void) static void lguest_flush_tlb_kernel(void) { { lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 1); } } /* /* Loading Loading @@ -695,7 +714,7 @@ static int lguest_clockevent_set_next_event(unsigned long delta, } } /* Please wake us this far in the future. */ /* Please wake us this far in the future. */ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0); kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta); return 0; return 0; } } Loading @@ -706,7 +725,7 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN: /* A 0 argument shuts the clock down. */ /* A 0 argument shuts the clock down. */ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0); kvm_hypercall0(LHCALL_SET_CLOCKEVENT); break; break; case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_ONESHOT: /* This is what we expect. */ /* This is what we expect. */ Loading Loading @@ -781,7 +800,7 @@ static void lguest_time_init(void) static void lguest_load_sp0(struct tss_struct *tss, static void lguest_load_sp0(struct tss_struct *tss, struct thread_struct *thread) struct thread_struct *thread) { { lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->sp0, lazy_hcall3(LHCALL_SET_STACK, __KERNEL_DS | 0x1, thread->sp0, THREAD_SIZE / PAGE_SIZE); THREAD_SIZE / PAGE_SIZE); } } Loading Loading @@ -855,7 +874,7 @@ static void set_lguest_basic_apic_ops(void) /* STOP! Until an interrupt comes in. */ /* STOP! Until an interrupt comes in. */ static void lguest_safe_halt(void) static void lguest_safe_halt(void) { { hcall(LHCALL_HALT, 0, 0, 0); kvm_hypercall0(LHCALL_HALT); } } /* The SHUTDOWN hypercall takes a string to describe what's happening, and /* The SHUTDOWN hypercall takes a string to describe what's happening, and Loading @@ -865,7 +884,8 @@ static void lguest_safe_halt(void) * rather than virtual addresses, so we use __pa() here. */ * rather than virtual addresses, so we use __pa() here. */ static void lguest_power_off(void) static void lguest_power_off(void) { { hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF); } } /* /* Loading @@ -875,7 +895,7 @@ static void lguest_power_off(void) */ */ static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) { { hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF); /* The hcall won't return, but to keep gcc happy, we're "done". */ /* The hcall won't return, but to keep gcc happy, we're "done". */ return NOTIFY_DONE; return NOTIFY_DONE; } } Loading Loading @@ -916,7 +936,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) len = sizeof(scratch) - 1; len = sizeof(scratch) - 1; scratch[len] = '\0'; scratch[len] = '\0'; memcpy(scratch, buf, len); memcpy(scratch, buf, len); hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0); kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch)); /* This routine returns the number of bytes actually written. */ /* This routine returns the number of bytes actually written. */ return len; return len; Loading @@ -926,7 +946,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) * Launcher to reboot us. */ * Launcher to reboot us. */ static void lguest_restart(char *reason) static void lguest_restart(char *reason) { { hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART); } } /*G:050 /*G:050 Loading arch/x86/lguest/i386_head.S +2 −2 Original line number Original line Diff line number Diff line Loading @@ -27,8 +27,8 @@ ENTRY(lguest_entry) /* We make the "initialization" hypercall now to tell the Host about /* We make the "initialization" hypercall now to tell the Host about * us, and also find out where it put our page tables. */ * us, and also find out where it put our page tables. */ movl $LHCALL_LGUEST_INIT, %eax movl $LHCALL_LGUEST_INIT, %eax movl $lguest_data - __PAGE_OFFSET, %edx movl $lguest_data - __PAGE_OFFSET, %ebx int $LGUEST_TRAP_ENTRY .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */ /* Set up the initial stack so we can run C code. */ /* Set up the initial stack so we can run C code. */ movl $(init_thread_union+THREAD_SIZE),%esp movl $(init_thread_union+THREAD_SIZE),%esp Loading drivers/lguest/interrupts_and_traps.c +4 −3 Original line number Original line Diff line number Diff line Loading @@ -288,9 +288,10 @@ static int direct_trap(unsigned int num) /* The Host needs to see page faults (for shadow paging and to save the /* The Host needs to see page faults (for shadow paging and to save the * fault address), general protection faults (in/out emulation) and * fault address), general protection faults (in/out emulation) and * device not available (TS handling), and of course, the hypercall * device not available (TS handling), invalid opcode fault (kvm hcall), * trap. */ * and of course, the hypercall trap. */ return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY; return num != 14 && num != 13 && num != 7 && num != 6 && num != LGUEST_TRAP_ENTRY; } } /*:*/ /*:*/ Loading drivers/lguest/lguest_device.c +2 −2 Original line number Original line Diff line number Diff line Loading @@ -161,7 +161,7 @@ static void set_status(struct virtio_device *vdev, u8 status) /* We set the status. */ /* We set the status. */ to_lgdev(vdev)->desc->status = status; to_lgdev(vdev)->desc->status = status; hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset); } } static void lg_set_status(struct virtio_device *vdev, u8 status) static void lg_set_status(struct virtio_device *vdev, u8 status) Loading Loading @@ -209,7 +209,7 @@ static void lg_notify(struct virtqueue *vq) * virtqueue structure. */ * virtqueue structure. */ struct lguest_vq_info *lvq = vq->priv; struct lguest_vq_info *lvq = vq->priv; hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0); kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT); } } /* An extern declaration inside a C file is bad form. Don't do it. */ /* An extern declaration inside a C file is bad form. Don't do it. */ Loading Loading
arch/x86/include/asm/lguest_hcall.h +4 −20 Original line number Original line Diff line number Diff line Loading @@ -26,36 +26,20 @@ #ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__ #include <asm/hw_irq.h> #include <asm/hw_irq.h> #include <asm/kvm_para.h> /*G:031 But first, how does our Guest contact the Host to ask for privileged /*G:031 But first, how does our Guest contact the Host to ask for privileged * operations? There are two ways: the direct way is to make a "hypercall", * operations? There are two ways: the direct way is to make a "hypercall", * to make requests of the Host Itself. * to make requests of the Host Itself. * * * Our hypercall mechanism uses the highest unused trap code (traps 32 and * We use the KVM hypercall mechanism. Eighteen hypercalls are * above are used by real hardware interrupts). Fifteen hypercalls are * available: the hypercall number is put in the %eax register, and the * available: the hypercall number is put in the %eax register, and the * arguments (when required) are placed in %edx, %ebx and %ecx. If a return * arguments (when required) are placed in %ebx, %ecx and %edx. If a return * value makes sense, it's returned in %eax. * value makes sense, it's returned in %eax. * * * Grossly invalid calls result in Sudden Death at the hands of the vengeful * Grossly invalid calls result in Sudden Death at the hands of the vengeful * Host, rather than returning failure. This reflects Winston Churchill's * Host, rather than returning failure. This reflects Winston Churchill's * definition of a gentleman: "someone who is only rude intentionally". */ * definition of a gentleman: "someone who is only rude intentionally". */ static inline unsigned long hcall(unsigned long call, unsigned long arg1, unsigned long arg2, unsigned long arg3) { /* "int" is the Intel instruction to trigger a trap. */ asm volatile("int $" __stringify(LGUEST_TRAP_ENTRY) /* The call in %eax (aka "a") might be overwritten */ : "=a"(call) /* The arguments are in %eax, %edx, %ebx & %ecx */ : "a"(call), "d"(arg1), "b"(arg2), "c"(arg3) /* "memory" means this might write somewhere in memory. * This isn't true for all calls, but it's safe to tell * gcc that it might happen so it doesn't get clever. */ : "memory"); return call; } /*:*/ /*:*/ /* Can't use our min() macro here: needs to be a constant */ /* Can't use our min() macro here: needs to be a constant */ Loading @@ -64,7 +48,7 @@ hcall(unsigned long call, #define LHCALL_RING_SIZE 64 #define LHCALL_RING_SIZE 64 struct hcall_args { struct hcall_args { /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */ /* These map directly onto eax, ebx, ecx, edx in struct lguest_regs */ unsigned long arg0, arg2, arg3, arg1; unsigned long arg0, arg1, arg2, arg3; }; }; #endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */ Loading
arch/x86/lguest/boot.c +49 −29 Original line number Original line Diff line number Diff line Loading @@ -107,7 +107,7 @@ static void async_hcall(unsigned long call, unsigned long arg1, local_irq_save(flags); local_irq_save(flags); if (lguest_data.hcall_status[next_call] != 0xFF) { if (lguest_data.hcall_status[next_call] != 0xFF) { /* Table full, so do normal hcall which will flush table. */ /* Table full, so do normal hcall which will flush table. */ hcall(call, arg1, arg2, arg3); kvm_hypercall3(call, arg1, arg2, arg3); } else { } else { lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg1 = arg1; lguest_data.hcalls[next_call].arg1 = arg1; Loading @@ -134,13 +134,32 @@ static void async_hcall(unsigned long call, unsigned long arg1, * * * So, when we're in lazy mode, we call async_hcall() to store the call for * So, when we're in lazy mode, we call async_hcall() to store the call for * future processing: */ * future processing: */ static void lazy_hcall(unsigned long call, static void lazy_hcall1(unsigned long call, unsigned long arg1) { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall1(call, arg1); else async_hcall(call, arg1, 0, 0); } static void lazy_hcall2(unsigned long call, unsigned long arg1, unsigned long arg2) { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall2(call, arg1, arg2); else async_hcall(call, arg1, arg2, 0); } static void lazy_hcall3(unsigned long call, unsigned long arg1, unsigned long arg1, unsigned long arg2, unsigned long arg2, unsigned long arg3) unsigned long arg3) { { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) hcall(call, arg1, arg2, arg3); kvm_hypercall3(call, arg1, arg2, arg3); else else async_hcall(call, arg1, arg2, arg3); async_hcall(call, arg1, arg2, arg3); } } Loading @@ -150,7 +169,7 @@ static void lazy_hcall(unsigned long call, static void lguest_leave_lazy_mode(void) static void lguest_leave_lazy_mode(void) { { paravirt_leave_lazy(paravirt_get_lazy_mode()); paravirt_leave_lazy(paravirt_get_lazy_mode()); hcall(LHCALL_FLUSH_ASYNC, 0, 0, 0); kvm_hypercall0(LHCALL_FLUSH_ASYNC); } } /*G:033 /*G:033 Loading Loading @@ -229,7 +248,7 @@ static void lguest_write_idt_entry(gate_desc *dt, /* Keep the local copy up to date. */ /* Keep the local copy up to date. */ native_write_idt_entry(dt, entrynum, g); native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ /* Tell Host about this new entry. */ hcall(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); } } /* Changing to a different IDT is very rare: we keep the IDT up-to-date every /* Changing to a different IDT is very rare: we keep the IDT up-to-date every Loading @@ -241,7 +260,7 @@ static void lguest_load_idt(const struct desc_ptr *desc) struct desc_struct *idt = (void *)desc->address; struct desc_struct *idt = (void *)desc->address; for (i = 0; i < (desc->size+1)/8; i++) for (i = 0; i < (desc->size+1)/8; i++) hcall(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, i, idt[i].a, idt[i].b); } } /* /* Loading @@ -262,7 +281,7 @@ static void lguest_load_idt(const struct desc_ptr *desc) static void lguest_load_gdt(const struct desc_ptr *desc) static void lguest_load_gdt(const struct desc_ptr *desc) { { BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES); BUG_ON((desc->size + 1) / 8 != GDT_ENTRIES); hcall(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES, 0); kvm_hypercall2(LHCALL_LOAD_GDT, __pa(desc->address), GDT_ENTRIES); } } /* For a single GDT entry which changes, we do the lazy thing: alter our GDT, /* For a single GDT entry which changes, we do the lazy thing: alter our GDT, Loading @@ -272,7 +291,7 @@ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, const void *desc, int type) const void *desc, int type) { { native_write_gdt_entry(dt, entrynum, desc, type); native_write_gdt_entry(dt, entrynum, desc, type); hcall(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES, 0); kvm_hypercall2(LHCALL_LOAD_GDT, __pa(dt), GDT_ENTRIES); } } /* OK, I lied. There are three "thread local storage" GDT entries which change /* OK, I lied. There are three "thread local storage" GDT entries which change Loading @@ -284,7 +303,7 @@ static void lguest_load_tls(struct thread_struct *t, unsigned int cpu) * can't handle us removing entries we're currently using. So we clear * can't handle us removing entries we're currently using. So we clear * the GS register here: if it's needed it'll be reloaded anyway. */ * the GS register here: if it's needed it'll be reloaded anyway. */ lazy_load_gs(0); lazy_load_gs(0); lazy_hcall(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu, 0); lazy_hcall2(LHCALL_LOAD_TLS, __pa(&t->tls_array), cpu); } } /*G:038 That's enough excitement for now, back to ploughing through each of /*G:038 That's enough excitement for now, back to ploughing through each of Loading Loading @@ -382,7 +401,7 @@ static void lguest_cpuid(unsigned int *ax, unsigned int *bx, static unsigned long current_cr0; static unsigned long current_cr0; static void lguest_write_cr0(unsigned long val) static void lguest_write_cr0(unsigned long val) { { lazy_hcall(LHCALL_TS, val & X86_CR0_TS, 0, 0); lazy_hcall1(LHCALL_TS, val & X86_CR0_TS); current_cr0 = val; current_cr0 = val; } } Loading @@ -396,7 +415,7 @@ static unsigned long lguest_read_cr0(void) * the vowels have been optimized out. */ * the vowels have been optimized out. */ static void lguest_clts(void) static void lguest_clts(void) { { lazy_hcall(LHCALL_TS, 0, 0, 0); lazy_hcall1(LHCALL_TS, 0); current_cr0 &= ~X86_CR0_TS; current_cr0 &= ~X86_CR0_TS; } } Loading @@ -418,7 +437,7 @@ static bool cr3_changed = false; static void lguest_write_cr3(unsigned long cr3) static void lguest_write_cr3(unsigned long cr3) { { lguest_data.pgdir = cr3; lguest_data.pgdir = cr3; lazy_hcall(LHCALL_NEW_PGTABLE, cr3, 0, 0); lazy_hcall1(LHCALL_NEW_PGTABLE, cr3); cr3_changed = true; cr3_changed = true; } } Loading Loading @@ -493,7 +512,7 @@ static void lguest_write_cr4(unsigned long val) static void lguest_pte_update(struct mm_struct *mm, unsigned long addr, static void lguest_pte_update(struct mm_struct *mm, unsigned long addr, pte_t *ptep) pte_t *ptep) { { lazy_hcall(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low); lazy_hcall3(LHCALL_SET_PTE, __pa(mm->pgd), addr, ptep->pte_low); } } static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, Loading @@ -509,8 +528,8 @@ static void lguest_set_pte_at(struct mm_struct *mm, unsigned long addr, static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) static void lguest_set_pmd(pmd_t *pmdp, pmd_t pmdval) { { *pmdp = pmdval; *pmdp = pmdval; lazy_hcall(LHCALL_SET_PMD, __pa(pmdp)&PAGE_MASK, lazy_hcall2(LHCALL_SET_PMD, __pa(pmdp) & PAGE_MASK, (__pa(pmdp)&(PAGE_SIZE-1))/4, 0); (__pa(pmdp) & (PAGE_SIZE - 1)) / 4); } } /* There are a couple of legacy places where the kernel sets a PTE, but we /* There are a couple of legacy places where the kernel sets a PTE, but we Loading @@ -526,7 +545,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval) { { *ptep = pteval; *ptep = pteval; if (cr3_changed) if (cr3_changed) lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 1); } } /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on /* Unfortunately for Lguest, the pv_mmu_ops for page tables were based on Loading @@ -542,7 +561,7 @@ static void lguest_set_pte(pte_t *ptep, pte_t pteval) static void lguest_flush_tlb_single(unsigned long addr) static void lguest_flush_tlb_single(unsigned long addr) { { /* Simply set it to zero: if it was not, it will fault back in. */ /* Simply set it to zero: if it was not, it will fault back in. */ lazy_hcall(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0); lazy_hcall3(LHCALL_SET_PTE, lguest_data.pgdir, addr, 0); } } /* This is what happens after the Guest has removed a large number of entries. /* This is what happens after the Guest has removed a large number of entries. Loading @@ -550,7 +569,7 @@ static void lguest_flush_tlb_single(unsigned long addr) * have changed, ie. virtual addresses below PAGE_OFFSET. */ * have changed, ie. virtual addresses below PAGE_OFFSET. */ static void lguest_flush_tlb_user(void) static void lguest_flush_tlb_user(void) { { lazy_hcall(LHCALL_FLUSH_TLB, 0, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 0); } } /* This is called when the kernel page tables have changed. That's not very /* This is called when the kernel page tables have changed. That's not very Loading @@ -558,7 +577,7 @@ static void lguest_flush_tlb_user(void) * slow), so it's worth separating this from the user flushing above. */ * slow), so it's worth separating this from the user flushing above. */ static void lguest_flush_tlb_kernel(void) static void lguest_flush_tlb_kernel(void) { { lazy_hcall(LHCALL_FLUSH_TLB, 1, 0, 0); lazy_hcall1(LHCALL_FLUSH_TLB, 1); } } /* /* Loading Loading @@ -695,7 +714,7 @@ static int lguest_clockevent_set_next_event(unsigned long delta, } } /* Please wake us this far in the future. */ /* Please wake us this far in the future. */ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0); kvm_hypercall1(LHCALL_SET_CLOCKEVENT, delta); return 0; return 0; } } Loading @@ -706,7 +725,7 @@ static void lguest_clockevent_set_mode(enum clock_event_mode mode, case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_UNUSED: case CLOCK_EVT_MODE_SHUTDOWN: case CLOCK_EVT_MODE_SHUTDOWN: /* A 0 argument shuts the clock down. */ /* A 0 argument shuts the clock down. */ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0); kvm_hypercall0(LHCALL_SET_CLOCKEVENT); break; break; case CLOCK_EVT_MODE_ONESHOT: case CLOCK_EVT_MODE_ONESHOT: /* This is what we expect. */ /* This is what we expect. */ Loading Loading @@ -781,7 +800,7 @@ static void lguest_time_init(void) static void lguest_load_sp0(struct tss_struct *tss, static void lguest_load_sp0(struct tss_struct *tss, struct thread_struct *thread) struct thread_struct *thread) { { lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->sp0, lazy_hcall3(LHCALL_SET_STACK, __KERNEL_DS | 0x1, thread->sp0, THREAD_SIZE / PAGE_SIZE); THREAD_SIZE / PAGE_SIZE); } } Loading Loading @@ -855,7 +874,7 @@ static void set_lguest_basic_apic_ops(void) /* STOP! Until an interrupt comes in. */ /* STOP! Until an interrupt comes in. */ static void lguest_safe_halt(void) static void lguest_safe_halt(void) { { hcall(LHCALL_HALT, 0, 0, 0); kvm_hypercall0(LHCALL_HALT); } } /* The SHUTDOWN hypercall takes a string to describe what's happening, and /* The SHUTDOWN hypercall takes a string to describe what's happening, and Loading @@ -865,7 +884,8 @@ static void lguest_safe_halt(void) * rather than virtual addresses, so we use __pa() here. */ * rather than virtual addresses, so we use __pa() here. */ static void lguest_power_off(void) static void lguest_power_off(void) { { hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF); } } /* /* Loading @@ -875,7 +895,7 @@ static void lguest_power_off(void) */ */ static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) { { hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF); /* The hcall won't return, but to keep gcc happy, we're "done". */ /* The hcall won't return, but to keep gcc happy, we're "done". */ return NOTIFY_DONE; return NOTIFY_DONE; } } Loading Loading @@ -916,7 +936,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) len = sizeof(scratch) - 1; len = sizeof(scratch) - 1; scratch[len] = '\0'; scratch[len] = '\0'; memcpy(scratch, buf, len); memcpy(scratch, buf, len); hcall(LHCALL_NOTIFY, __pa(scratch), 0, 0); kvm_hypercall1(LHCALL_NOTIFY, __pa(scratch)); /* This routine returns the number of bytes actually written. */ /* This routine returns the number of bytes actually written. */ return len; return len; Loading @@ -926,7 +946,7 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count) * Launcher to reboot us. */ * Launcher to reboot us. */ static void lguest_restart(char *reason) static void lguest_restart(char *reason) { { hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0); kvm_hypercall2(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART); } } /*G:050 /*G:050 Loading
arch/x86/lguest/i386_head.S +2 −2 Original line number Original line Diff line number Diff line Loading @@ -27,8 +27,8 @@ ENTRY(lguest_entry) /* We make the "initialization" hypercall now to tell the Host about /* We make the "initialization" hypercall now to tell the Host about * us, and also find out where it put our page tables. */ * us, and also find out where it put our page tables. */ movl $LHCALL_LGUEST_INIT, %eax movl $LHCALL_LGUEST_INIT, %eax movl $lguest_data - __PAGE_OFFSET, %edx movl $lguest_data - __PAGE_OFFSET, %ebx int $LGUEST_TRAP_ENTRY .byte 0x0f,0x01,0xc1 /* KVM_HYPERCALL */ /* Set up the initial stack so we can run C code. */ /* Set up the initial stack so we can run C code. */ movl $(init_thread_union+THREAD_SIZE),%esp movl $(init_thread_union+THREAD_SIZE),%esp Loading
drivers/lguest/interrupts_and_traps.c +4 −3 Original line number Original line Diff line number Diff line Loading @@ -288,9 +288,10 @@ static int direct_trap(unsigned int num) /* The Host needs to see page faults (for shadow paging and to save the /* The Host needs to see page faults (for shadow paging and to save the * fault address), general protection faults (in/out emulation) and * fault address), general protection faults (in/out emulation) and * device not available (TS handling), and of course, the hypercall * device not available (TS handling), invalid opcode fault (kvm hcall), * trap. */ * and of course, the hypercall trap. */ return num != 14 && num != 13 && num != 7 && num != LGUEST_TRAP_ENTRY; return num != 14 && num != 13 && num != 7 && num != 6 && num != LGUEST_TRAP_ENTRY; } } /*:*/ /*:*/ Loading
drivers/lguest/lguest_device.c +2 −2 Original line number Original line Diff line number Diff line Loading @@ -161,7 +161,7 @@ static void set_status(struct virtio_device *vdev, u8 status) /* We set the status. */ /* We set the status. */ to_lgdev(vdev)->desc->status = status; to_lgdev(vdev)->desc->status = status; hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); kvm_hypercall1(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset); } } static void lg_set_status(struct virtio_device *vdev, u8 status) static void lg_set_status(struct virtio_device *vdev, u8 status) Loading Loading @@ -209,7 +209,7 @@ static void lg_notify(struct virtqueue *vq) * virtqueue structure. */ * virtqueue structure. */ struct lguest_vq_info *lvq = vq->priv; struct lguest_vq_info *lvq = vq->priv; hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0); kvm_hypercall1(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT); } } /* An extern declaration inside a C file is bad form. Don't do it. */ /* An extern declaration inside a C file is bad form. Don't do it. */ Loading