static int paravirt_put_chars(u32 vtermno, const char *buf, int count) { kvm_hypercall3(KVM_HC_MIPS_CONSOLE_OUTPUT, vtermno, (unsigned long)buf, count); return count; }
/*G:037 async_hcall() is pretty simple: I'm quite proud of it really. We have a * ring buffer of stored hypercalls which the Host will run though next time we * do a normal hypercall. Each entry in the ring has 4 slots for the hypercall * arguments, and a "hcall_status" word which is 0 if the call is ready to go, * and 255 once the Host has finished with it. * * If we come around to a slot which hasn't been finished, then the table is * full and we just make the hypercall directly. This has the nice side * effect of causing the Host to run all the stored calls in the ring buffer * which empties it for next time! */ static void async_hcall(unsigned long call, unsigned long arg1, unsigned long arg2, unsigned long arg3) { /* Note: This code assumes we're uniprocessor. */ static unsigned int next_call; unsigned long flags; /* Disable interrupts if not already disabled: we don't want an * interrupt handler making a hypercall while we're already doing * one! */ local_irq_save(flags); if (lguest_data.hcall_status[next_call] != 0xFF) { /* Table full, so do normal hcall which will flush table. */ kvm_hypercall3(call, arg1, arg2, arg3); } else { lguest_data.hcalls[next_call].arg0 = call; lguest_data.hcalls[next_call].arg1 = arg1; lguest_data.hcalls[next_call].arg2 = arg2; lguest_data.hcalls[next_call].arg3 = arg3; /* Arguments must all be written before we mark it to go */ wmb(); lguest_data.hcall_status[next_call] = 0; if (++next_call == LHCALL_RING_SIZE) next_call = 0; } local_irq_restore(flags); }
/* * Emit one character to the boot console. */ int prom_putchar(char c) { kvm_hypercall3(KVM_HC_MIPS_CONSOLE_OUTPUT, 0 /* port 0 */, (unsigned long)&c, 1 /* len == 1 */); return 1; }
/* * For a single GDT entry which changes, we do the lazy thing: alter our GDT, * then tell the Host to reload the entire thing. This operation is so rare * that this naive implementation is reasonable. */ static void lguest_write_gdt_entry(struct desc_struct *dt, int entrynum, const void *desc, int type) { native_write_gdt_entry(dt, entrynum, desc, type); /* Tell Host about this new entry. */ kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, entrynum, dt[entrynum].a, dt[entrynum].b); }
/* * The Global Descriptor Table. * * The Intel architecture defines another table, called the Global Descriptor * Table (GDT). You tell the CPU where it is (and its size) using the "lgdt" * instruction, and then several other instructions refer to entries in the * table. There are three entries which the Switcher needs, so the Host simply * controls the entire thing and the Guest asks it to make changes using the * LOAD_GDT hypercall. * * This is the exactly like the IDT code. */ static void lguest_load_gdt(const struct desc_ptr *desc) { unsigned int i; struct desc_struct *gdt = (void *)desc->address; for (i = 0; i < (desc->size+1)/8; i++) kvm_hypercall3(LHCALL_LOAD_GDT_ENTRY, i, gdt[i].a, gdt[i].b); }
static void lazy_hcall3(unsigned long call, unsigned long arg1, unsigned long arg2, unsigned long arg3) { if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) kvm_hypercall3(call, arg1, arg2, arg3); else async_hcall(call, arg1, arg2, arg3, 0); }
/*G:034 * The Interrupt Descriptor Table (IDT). * * The IDT tells the processor what to do when an interrupt comes in. Each * entry in the table is a 64-bit descriptor: this holds the privilege level, * address of the handler, and... well, who cares? The Guest just asks the * Host to make the change anyway, because the Host controls the real IDT. */ static void lguest_write_idt_entry(gate_desc *dt, int entrynum, const gate_desc *g) { /* The gate_desc structure is 8 bytes long: we hand it to the Host in * two 32-bit chunks. The whole 32-bit kernel used to hand descriptors * around like this; typesafety wasn't a big concern in Linux's early * years. */ u32 *desc = (u32 *)g; /* Keep the local copy up to date. */ native_write_idt_entry(dt, entrynum, g); /* Tell Host about this new entry. */ kvm_hypercall3(LHCALL_LOAD_IDT_ENTRY, entrynum, desc[0], desc[1]); }
static void kvm_mmu_op(void *buffer, unsigned len) { int r; unsigned long a1, a2; do { a1 = __pa(buffer); a2 = 0; /* on i386 __pa() always returns <4G */ r = kvm_hypercall3(KVM_HC_MMU_OP, len, a1, a2); buffer += r; len -= r; } while (len); }