From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Michael S. Tsirkin" Subject: Re: [PATCH kvm-unit-tests 3/4] Add support for calling a function in guest mode Date: Fri, 26 Nov 2010 16:17:48 +0200 Message-ID: <20101126141748.GB6124@redhat.com> References: <1290595933-13122-1-git-send-email-avi@redhat.com> <1290595933-13122-4-git-send-email-avi@redhat.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Cc: Marcelo Tosatti , kvm@vger.kernel.org To: Avi Kivity Return-path: Received: from mx1.redhat.com ([209.132.183.28]:27738 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752473Ab0KZOSA (ORCPT ); Fri, 26 Nov 2010 09:18:00 -0500 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id oAQEHxtg010928 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Fri, 26 Nov 2010 09:18:00 -0500 Content-Disposition: inline In-Reply-To: <1290595933-13122-4-git-send-email-avi@redhat.com> Sender: kvm-owner@vger.kernel.org List-ID: On Wed, Nov 24, 2010 at 12:52:12PM +0200, Avi Kivity wrote: > This patch provides a way to establish an "identity" guest which has > a 1:1 gva->hva translation. This allows the host to switch to guest > mode, call a function in the same address space, and return. > > Because long mode virtual addresses are 47 bits long, and some hosts > have smaller physical addresses, we target 32-bit mode only. On > x86_64 the code needs to be run with 'setarch i386 -3' to limit the > address space to 3GB, so the address space occupied by the local > APIC is left unused. > > Signed-off-by: Avi Kivity > --- > api/identity.cc | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ > api/identity.h | 28 ++++++++++++++++++ > config-x86-common.mak | 2 + > 3 files changed, 106 insertions(+), 0 deletions(-) > create mode 100644 api/identity.cc > create mode 100644 api/identity.h > > diff --git a/api/identity.cc b/api/identity.cc > new file mode 100644 > index 0000000..8e86db1 > --- /dev/null > +++ b/api/identity.cc > @@ -0,0 +1,76 @@ > + > +#include "identity.h" > +#include > + > +namespace identity { > + > +typedef unsigned long ulong; > + > +void setup_vm(kvm::vm& vm) > +{ > + vm.set_memory_region(0, NULL, 0, 3UL << 30); > + vm.set_tss_addr(3UL << 30); > +} > + > +void vcpu::setup_sregs() > +{ > + kvm_sregs sregs = { }; > + kvm_segment dseg = { }; > + dseg.base = 0; dseg.limit = -1U; dseg.type = 3; dseg.present = 1; > + dseg.dpl = 3; dseg.db = 1; dseg.s = 1; dseg.l = 0; dseg.g = 1; > + kvm_segment cseg = dseg; > + cseg.type = 11; > + > + sregs.cs = cseg; asm ("mov %%cs, %0" : "=rm"(sregs.cs.selector)); > + sregs.ds = dseg; asm ("mov %%ds, %0" : "=rm"(sregs.ds.selector)); > + sregs.es = dseg; asm ("mov %%es, %0" : "=rm"(sregs.es.selector)); > + sregs.fs = dseg; asm ("mov %%fs, %0" : "=rm"(sregs.fs.selector)); > + sregs.gs = dseg; asm ("mov %%gs, %0" : "=rm"(sregs.gs.selector)); > + sregs.ss = dseg; asm ("mov %%ss, %0" : "=rm"(sregs.ss.selector)); > + > + uint32_t gsbase; > + asm ("mov %%gs:0, %0" : "=r"(gsbase)); > + sregs.gs.base = gsbase; > + > + sregs.tr.base = reinterpret_cast(&*_stack.begin()); > + sregs.tr.type = 11; > + sregs.tr.s = 0; > + sregs.tr.present = 1; > + > + sregs.cr0 = 0x11; /* PE, ET, !PG */ > + sregs.cr4 = 0; > + sregs.efer = 0; > + sregs.apic_base = 0xfee00000; > + _vcpu.set_sregs(sregs); > +} > + > +void vcpu::thunk(vcpu* zis) > +{ > + zis->_guest_func(); > + asm volatile("outb %%al, %%dx" : : "a"(0), "d"(0)); > +} > + > +void vcpu::setup_regs() > +{ > + kvm_regs regs = {}; > + regs.rflags = 0x3202; > + regs.rsp = reinterpret_cast(&*_stack.end()); > + regs.rsp &= ~15UL; > + ulong* sp = reinterpret_cast(regs.rsp); > + *--sp = reinterpret_cast((char*)this); > + *--sp = 0; > + regs.rsp = reinterpret_cast(sp); > + regs.rip = reinterpret_cast(&vcpu::thunk); > + printf("rip %llx\n", regs.rip); > + _vcpu.set_regs(regs); > +} > + > +vcpu::vcpu(kvm::vcpu& vcpu, boost::function guest_func, > + unsigned long stack_size) > + : _vcpu(vcpu), _guest_func(guest_func), _stack(stack_size) > +{ > + setup_sregs(); > + setup_regs(); > +} > + > +} > diff --git a/api/identity.h b/api/identity.h > new file mode 100644 > index 0000000..025177a > --- /dev/null > +++ b/api/identity.h > @@ -0,0 +1,28 @@ > +#ifndef API_IDENTITY_H > +#define API_IDENTITY_H > + > +#include "kvmxx.h" > +#include This seems to use boost, which is not part of the standard library. Do we want this dependency? We'd need a configure check to verify it's installed. > +#include > + > +namespace identity { > + > +void setup_vm(kvm::vm& vm); > + > +class vcpu { > +public: > + vcpu(kvm::vcpu& vcpu, boost::function guest_func, > + unsigned long stack_size = 256 * 1024); So the thread stack is moved to use the heap instead? Can we use pthread_attr_getstacksize and use the regular thread stack? Good for portability. > +private: > + static void thunk(vcpu* vcpu); > + void setup_regs(); > + void setup_sregs(); > +private: > + kvm::vcpu& _vcpu; > + boost::function _guest_func; > + std::vector _stack; > +}; > + > +} > + > +#endif > diff --git a/config-x86-common.mak b/config-x86-common.mak > index b541c1c..0f3387b 100644 > --- a/config-x86-common.mak > +++ b/config-x86-common.mak > @@ -79,3 +79,5 @@ arch_clean: > $(TEST_DIR)/.*.d $(TEST_DIR)/lib/.*.d $(TEST_DIR)/lib/*.o > > -include $(TEST_DIR)/.*.d lib/.*.d lib/x86/.*.d > + > +api/%.o: CFLAGS += -m32 > \ No newline at end of file > -- > 1.7.1 > > -- > To unsubscribe from this list: send the line "unsubscribe kvm" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html