diff options
author | Avi Kivity <avi@redhat.com> | 2012-08-27 16:46:17 -0400 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2012-08-27 17:38:55 -0400 |
commit | dd856efafe6097a5c9104725c2bca74430423db8 (patch) | |
tree | d074a16680f3a39798f372e16426476aa7f6e1df /arch/x86/kvm/x86.c | |
parent | 66a03505a7fcc70187319ef2318832f4d3c451a6 (diff) |
KVM: x86 emulator: access GPRs on demand
Instead of populating the entire register file, read in registers
as they are accessed, and write back only the modified ones. This
saves a VMREAD and VMWRITE on Intel (for rsp, since it is not usually
used during emulation), and a two 128-byte copies for the registers.
Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/x86.c')
-rw-r--r-- | arch/x86/kvm/x86.c | 45 |
1 files changed, 18 insertions, 27 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 42bbf4187d20..e00050ce7a6a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4313,7 +4313,19 @@ static void emulator_get_cpuid(struct x86_emulate_ctxt *ctxt, | |||
4313 | kvm_cpuid(emul_to_vcpu(ctxt), eax, ebx, ecx, edx); | 4313 | kvm_cpuid(emul_to_vcpu(ctxt), eax, ebx, ecx, edx); |
4314 | } | 4314 | } |
4315 | 4315 | ||
4316 | static ulong emulator_read_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg) | ||
4317 | { | ||
4318 | return kvm_register_read(emul_to_vcpu(ctxt), reg); | ||
4319 | } | ||
4320 | |||
4321 | static void emulator_write_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg, ulong val) | ||
4322 | { | ||
4323 | kvm_register_write(emul_to_vcpu(ctxt), reg, val); | ||
4324 | } | ||
4325 | |||
4316 | static struct x86_emulate_ops emulate_ops = { | 4326 | static struct x86_emulate_ops emulate_ops = { |
4327 | .read_gpr = emulator_read_gpr, | ||
4328 | .write_gpr = emulator_write_gpr, | ||
4317 | .read_std = kvm_read_guest_virt_system, | 4329 | .read_std = kvm_read_guest_virt_system, |
4318 | .write_std = kvm_write_guest_virt_system, | 4330 | .write_std = kvm_write_guest_virt_system, |
4319 | .fetch = kvm_fetch_guest_virt, | 4331 | .fetch = kvm_fetch_guest_virt, |
@@ -4348,14 +4360,6 @@ static struct x86_emulate_ops emulate_ops = { | |||
4348 | .get_cpuid = emulator_get_cpuid, | 4360 | .get_cpuid = emulator_get_cpuid, |
4349 | }; | 4361 | }; |
4350 | 4362 | ||
4351 | static void cache_all_regs(struct kvm_vcpu *vcpu) | ||
4352 | { | ||
4353 | kvm_register_read(vcpu, VCPU_REGS_RAX); | ||
4354 | kvm_register_read(vcpu, VCPU_REGS_RSP); | ||
4355 | kvm_register_read(vcpu, VCPU_REGS_RIP); | ||
4356 | vcpu->arch.regs_dirty = ~0; | ||
4357 | } | ||
4358 | |||
4359 | static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) | 4363 | static void toggle_interruptibility(struct kvm_vcpu *vcpu, u32 mask) |
4360 | { | 4364 | { |
4361 | u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(vcpu, mask); | 4365 | u32 int_shadow = kvm_x86_ops->get_interrupt_shadow(vcpu, mask); |
@@ -4382,12 +4386,10 @@ static void inject_emulated_exception(struct kvm_vcpu *vcpu) | |||
4382 | kvm_queue_exception(vcpu, ctxt->exception.vector); | 4386 | kvm_queue_exception(vcpu, ctxt->exception.vector); |
4383 | } | 4387 | } |
4384 | 4388 | ||
4385 | static void init_decode_cache(struct x86_emulate_ctxt *ctxt, | 4389 | static void init_decode_cache(struct x86_emulate_ctxt *ctxt) |
4386 | const unsigned long *regs) | ||
4387 | { | 4390 | { |
4388 | memset(&ctxt->twobyte, 0, | 4391 | memset(&ctxt->twobyte, 0, |
4389 | (void *)&ctxt->regs - (void *)&ctxt->twobyte); | 4392 | (void *)&ctxt->_regs - (void *)&ctxt->twobyte); |
4390 | memcpy(ctxt->regs, regs, sizeof(ctxt->regs)); | ||
4391 | 4393 | ||
4392 | ctxt->fetch.start = 0; | 4394 | ctxt->fetch.start = 0; |
4393 | ctxt->fetch.end = 0; | 4395 | ctxt->fetch.end = 0; |
@@ -4402,14 +4404,6 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) | |||
4402 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 4404 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
4403 | int cs_db, cs_l; | 4405 | int cs_db, cs_l; |
4404 | 4406 | ||
4405 | /* | ||
4406 | * TODO: fix emulate.c to use guest_read/write_register | ||
4407 | * instead of direct ->regs accesses, can save hundred cycles | ||
4408 | * on Intel for instructions that don't read/change RSP, for | ||
4409 | * for example. | ||
4410 | */ | ||
4411 | cache_all_regs(vcpu); | ||
4412 | |||
4413 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); | 4407 | kvm_x86_ops->get_cs_db_l_bits(vcpu, &cs_db, &cs_l); |
4414 | 4408 | ||
4415 | ctxt->eflags = kvm_get_rflags(vcpu); | 4409 | ctxt->eflags = kvm_get_rflags(vcpu); |
@@ -4421,7 +4415,7 @@ static void init_emulate_ctxt(struct kvm_vcpu *vcpu) | |||
4421 | X86EMUL_MODE_PROT16; | 4415 | X86EMUL_MODE_PROT16; |
4422 | ctxt->guest_mode = is_guest_mode(vcpu); | 4416 | ctxt->guest_mode = is_guest_mode(vcpu); |
4423 | 4417 | ||
4424 | init_decode_cache(ctxt, vcpu->arch.regs); | 4418 | init_decode_cache(ctxt); |
4425 | vcpu->arch.emulate_regs_need_sync_from_vcpu = false; | 4419 | vcpu->arch.emulate_regs_need_sync_from_vcpu = false; |
4426 | } | 4420 | } |
4427 | 4421 | ||
@@ -4441,7 +4435,6 @@ int kvm_inject_realmode_interrupt(struct kvm_vcpu *vcpu, int irq, int inc_eip) | |||
4441 | return EMULATE_FAIL; | 4435 | return EMULATE_FAIL; |
4442 | 4436 | ||
4443 | ctxt->eip = ctxt->_eip; | 4437 | ctxt->eip = ctxt->_eip; |
4444 | memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); | ||
4445 | kvm_rip_write(vcpu, ctxt->eip); | 4438 | kvm_rip_write(vcpu, ctxt->eip); |
4446 | kvm_set_rflags(vcpu, ctxt->eflags); | 4439 | kvm_set_rflags(vcpu, ctxt->eflags); |
4447 | 4440 | ||
@@ -4599,7 +4592,7 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, | |||
4599 | changes registers values during IO operation */ | 4592 | changes registers values during IO operation */ |
4600 | if (vcpu->arch.emulate_regs_need_sync_from_vcpu) { | 4593 | if (vcpu->arch.emulate_regs_need_sync_from_vcpu) { |
4601 | vcpu->arch.emulate_regs_need_sync_from_vcpu = false; | 4594 | vcpu->arch.emulate_regs_need_sync_from_vcpu = false; |
4602 | memcpy(ctxt->regs, vcpu->arch.regs, sizeof ctxt->regs); | 4595 | emulator_invalidate_register_cache(ctxt); |
4603 | } | 4596 | } |
4604 | 4597 | ||
4605 | restart: | 4598 | restart: |
@@ -4637,7 +4630,6 @@ restart: | |||
4637 | toggle_interruptibility(vcpu, ctxt->interruptibility); | 4630 | toggle_interruptibility(vcpu, ctxt->interruptibility); |
4638 | kvm_set_rflags(vcpu, ctxt->eflags); | 4631 | kvm_set_rflags(vcpu, ctxt->eflags); |
4639 | kvm_make_request(KVM_REQ_EVENT, vcpu); | 4632 | kvm_make_request(KVM_REQ_EVENT, vcpu); |
4640 | memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); | ||
4641 | vcpu->arch.emulate_regs_need_sync_to_vcpu = false; | 4633 | vcpu->arch.emulate_regs_need_sync_to_vcpu = false; |
4642 | kvm_rip_write(vcpu, ctxt->eip); | 4634 | kvm_rip_write(vcpu, ctxt->eip); |
4643 | } else | 4635 | } else |
@@ -5591,8 +5583,7 @@ int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | |||
5591 | * that usually, but some bad designed PV devices (vmware | 5583 | * that usually, but some bad designed PV devices (vmware |
5592 | * backdoor interface) need this to work | 5584 | * backdoor interface) need this to work |
5593 | */ | 5585 | */ |
5594 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 5586 | emulator_writeback_register_cache(&vcpu->arch.emulate_ctxt); |
5595 | memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); | ||
5596 | vcpu->arch.emulate_regs_need_sync_to_vcpu = false; | 5587 | vcpu->arch.emulate_regs_need_sync_to_vcpu = false; |
5597 | } | 5588 | } |
5598 | regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX); | 5589 | regs->rax = kvm_register_read(vcpu, VCPU_REGS_RAX); |
@@ -5723,6 +5714,7 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, | |||
5723 | { | 5714 | { |
5724 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; | 5715 | struct x86_emulate_ctxt *ctxt = &vcpu->arch.emulate_ctxt; |
5725 | int ret; | 5716 | int ret; |
5717 | unsigned reg; | ||
5726 | 5718 | ||
5727 | init_emulate_ctxt(vcpu); | 5719 | init_emulate_ctxt(vcpu); |
5728 | 5720 | ||
@@ -5732,7 +5724,6 @@ int kvm_task_switch(struct kvm_vcpu *vcpu, u16 tss_selector, int idt_index, | |||
5732 | if (ret) | 5724 | if (ret) |
5733 | return EMULATE_FAIL; | 5725 | return EMULATE_FAIL; |
5734 | 5726 | ||
5735 | memcpy(vcpu->arch.regs, ctxt->regs, sizeof ctxt->regs); | ||
5736 | kvm_rip_write(vcpu, ctxt->eip); | 5727 | kvm_rip_write(vcpu, ctxt->eip); |
5737 | kvm_set_rflags(vcpu, ctxt->eflags); | 5728 | kvm_set_rflags(vcpu, ctxt->eflags); |
5738 | kvm_make_request(KVM_REQ_EVENT, vcpu); | 5729 | kvm_make_request(KVM_REQ_EVENT, vcpu); |