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 <avi@xxxxxxxxxx> > --- > 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 <stdio.h> > + > +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<ulong>(&*_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<ulong>(&*_stack.end()); > + regs.rsp &= ~15UL; > + ulong* sp = reinterpret_cast<ulong *>(regs.rsp); > + *--sp = reinterpret_cast<ulong>((char*)this); > + *--sp = 0; > + regs.rsp = reinterpret_cast<ulong>(sp); > + regs.rip = reinterpret_cast<ulong>(&vcpu::thunk); > + printf("rip %llx\n", regs.rip); > + _vcpu.set_regs(regs); > +} > + > +vcpu::vcpu(kvm::vcpu& vcpu, boost::function<void ()> 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 <boost/function.hpp> 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 <vector> > + > +namespace identity { > + > +void setup_vm(kvm::vm& vm); > + > +class vcpu { > +public: > + vcpu(kvm::vcpu& vcpu, boost::function<void ()> 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<void ()> _guest_func; > + std::vector<char> _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@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html