* Avi Kivity <[EMAIL PROTECTED]> wrote: > > about the 32-bit side: maybe it gives us a bit more options for > > later if we pick the natural order for 32-bit too: EBX for index, > > EAX, EDX, ECX for the first 3 parameters, with the remaining 3 > > parameters in ESI, EDI, EBP? Most hypercalls will have 0, 1, 2 or 3 > > parameters. > > I don't mind, as long as it's clearly documented.
ok. Below is the current snapshot - hypercall calling convention documented and implemented for both 64-bit and 32-bit on the KVM side, and a small demo call done on the 32-bit guest side. Ingo Index: linux/arch/i386/kernel/paravirt.c =================================================================== --- linux.orig/arch/i386/kernel/paravirt.c +++ linux/arch/i386/kernel/paravirt.c @@ -888,29 +888,40 @@ asm ( " ret \n" ); -extern unsigned char hypercall_addr[4]; +extern unsigned char hypercall_addr[6]; - -static inline int -kvm_hypercall(void *param1, void *param2, void *param3, void *param4) -{ - int ret = -1; - - asm (" call hypercall_addr\n" - : "=g" (ret) - : "eax" (param1), - "ecx" (param2), - "edx" (param3), - "ebp" (param4)); - - return ret; -} +#define hypercall0(nr) \ +({ \ + int __ret; \ + \ + asm (" call hypercall_addr\n" \ + : "=a" (__ret) \ + : "b" (nr) \ + ); \ + __ret; \ +}) + +#define hypercall1(nr, p1) \ +({ \ + int __ret; \ + \ + asm (" call hypercall_addr\n" \ + : "=a" (__ret) \ + : "b" (nr), \ + "a" (p1) \ + ); \ + __ret; \ +}) void test_hypercall(void) { - int ret = kvm_hypercall((void *)1, (void *)2, (void *)3, (void *)4); + int ret; + + ret = hypercall0(__NR_hypercall_load_cr3); + printk(KERN_DEBUG "hypercall test #1, ret: %d\n", ret); - printk(KERN_DEBUG "hypercall test, ret: %d\n", ret); + ret = hypercall1(0xbad, 0xbad); + printk(KERN_DEBUG "hypercall test #2, ret: %d\n", ret); } int kvm_guest_register_para(int cpu) Index: linux/drivers/kvm/kvm.h =================================================================== --- linux.orig/drivers/kvm/kvm.h +++ linux/drivers/kvm/kvm.h @@ -639,4 +639,6 @@ static inline u32 get_rdx_init_val(void) #define TSS_REDIRECTION_SIZE (256 / 8) #define RMODE_TSS_SIZE (TSS_BASE_SIZE + TSS_REDIRECTION_SIZE + TSS_IOPB_SIZE + 1) +extern int kvm_handle_hypercall(struct kvm_vcpu *vcpu); + #endif Index: linux/drivers/kvm/kvm_main.c =================================================================== --- linux.orig/drivers/kvm/kvm_main.c +++ linux/drivers/kvm/kvm_main.c @@ -1138,6 +1138,62 @@ int emulate_instruction(struct kvm_vcpu } EXPORT_SYMBOL_GPL(emulate_instruction); +int hypercall_load_cr3(struct kvm_vcpu *vcpu, unsigned long new_cr3) +{ + printk("not yet\n"); + + return -ENOSYS; +} + +static inline int +kvm_hypercall(struct kvm_vcpu *vcpu, unsigned int nr, + unsigned long p1, unsigned long p2, unsigned long p3, + unsigned long p4, unsigned long p5, unsigned long p6) +{ + int ret = -EINVAL; + + switch (nr) { + case __NR_hypercall_load_cr3: + ret = hypercall_load_cr3(vcpu, p1); + break; + default: + printk(KERN_DEBUG "invalid hypercall %d\n", nr); + } + vcpu->regs[VCPU_REGS_RAX] = ret; + + return 1; +} + +static int kvm_handle_hypercall_32bit(struct kvm_vcpu *vcpu) +{ + int nr = vcpu->regs[VCPU_REGS_RBX]; + unsigned long p1 = vcpu->regs[VCPU_REGS_RAX], + p2 = vcpu->regs[VCPU_REGS_RCX], + p3 = vcpu->regs[VCPU_REGS_RDX], + p4 = vcpu->regs[VCPU_REGS_RSI], + p5 = vcpu->regs[VCPU_REGS_RDI], + p6 = vcpu->regs[VCPU_REGS_RBP]; + + return kvm_hypercall(vcpu, nr, p1, p2, p3, p4, p5, p6); +} + +int kvm_handle_hypercall(struct kvm_vcpu *vcpu) +{ + int nr = vcpu->regs[VCPU_REGS_RAX]; + unsigned long p1 = vcpu->regs[VCPU_REGS_RAX], + p2 = vcpu->regs[VCPU_REGS_RCX], + p3 = vcpu->regs[VCPU_REGS_RDX], + p4 = vcpu->regs[VCPU_REGS_RSI], + p5 = vcpu->regs[VCPU_REGS_RDI], + p6 = vcpu->regs[VCPU_REGS_RBP]; + + if (unlikely(!is_long_mode(vcpu))) + return kvm_handle_hypercall_32bit(vcpu); + + return kvm_hypercall(vcpu, nr, p1, p2, p3, p4, p5, p6); +} +EXPORT_SYMBOL_GPL(kvm_handle_hypercall); + static u64 mk_cr_64(u64 curr_cr, u32 new_val) { return (curr_cr & ~((1ULL << 32) - 1)) | new_val; Index: linux/drivers/kvm/vmx.c =================================================================== --- linux.orig/drivers/kvm/vmx.c +++ linux/drivers/kvm/vmx.c @@ -1032,7 +1032,7 @@ static int vmcs_setup_cr3_cache(struct k cr3_target_values = (msr_val >> 16) & ((1 << 10) - 1); printk(KERN_DEBUG " cr3 target values: %d\n", cr3_target_values); if (cr3_target_values > KVM_CR3_CACHE_SIZE) { - printk(KERN_WARN "KVM: limiting cr3 cache size from %d to %d\n", + printk(KERN_WARNING "KVM: limiting cr3 cache size from %d to %d\n", cr3_target_values, KVM_CR3_CACHE_SIZE); cr3_target_values = KVM_CR3_CACHE_SIZE; } @@ -1726,16 +1726,12 @@ static int handle_halt(struct kvm_vcpu * static int handle_vmcall(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) { kvm_run->exit_reason = KVM_EXIT_DEBUG; - printk(KERN_DEBUG "got vmcall at RIP %08lx\n", vmcs_readl(GUEST_RIP)); - printk(KERN_DEBUG "vmcall params: %08lx, %08lx, %08lx, %08lx\n", - vcpu->regs[VCPU_REGS_RAX], - vcpu->regs[VCPU_REGS_RCX], - vcpu->regs[VCPU_REGS_RDX], - vcpu->regs[VCPU_REGS_RBP]); - vcpu->regs[VCPU_REGS_RAX] = 0; + kvm_handle_hypercall(vcpu); vmcs_writel(GUEST_RIP, vmcs_readl(GUEST_RIP)+3); + return 1; } + /* * The exit handlers return 1 if the exit was handled fully and guest execution * may resume. Otherwise they set the kvm_run parameter to indicate what needs Index: linux/include/linux/kvm_para.h =================================================================== --- linux.orig/include/linux/kvm_para.h +++ linux/include/linux/kvm_para.h @@ -72,4 +72,23 @@ struct kvm_vcpu_para_state { #define KVM_EINVAL EINVAL +/* + * Hypercall calling convention: + * + * Each hypercall may have 0-6 parameters. + * + * 64-bit hypercall index is in RAX, goes from 0 to __NR_hypercalls-1 + * + * 64-bit parameters 1-6 are in the standard gcc x86_64 calling convention + * order: RDI, RSI, RDX, RCX, R8, R9. + * + * 32-bit index is EBX, parameters are: EAX, ECX, EDX, ESI, EDI, EBP. + * (the first 3 are according to the gcc regparm calling convention) + * + * No registers are clobbered by the hypercall, except that the + * return value is in RAX. + */ +#define __NR_hypercall_load_cr3 0 +#define __NR_hypercalls 1 + #endif ------------------------------------------------------------------------- Take Surveys. Earn Cash. Influence the Future of IT Join SourceForge.net's Techsay panel and you'll get the chance to share your opinions on IT & business topics through brief surveys - and earn cash http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel