aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorNadav Har'El <nyh@il.ibm.com>2011-05-25 16:04:56 -0400
committerAvi Kivity <avi@redhat.com>2011-07-12 04:45:11 -0400
commit064aea774768749c6fd308b37818ea3a9600583d (patch)
tree2661c607089ed44b71f6478d376de6ae571da37f /arch/x86/kvm/vmx.c
parentb87a51ae2893a5907f796eadb4beb60747a69209 (diff)
KVM: nVMX: Decoding memory operands of VMX instructions
This patch includes a utility function for decoding pointer operands of VMX instructions issued by L1 (a guest hypervisor) Signed-off-by: Nadav Har'El <nyh@il.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 487952b20217..74afd8660930 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -4343,6 +4343,59 @@ static int handle_vmoff(struct kvm_vcpu *vcpu)
4343} 4343}
4344 4344
4345/* 4345/*
4346 * Decode the memory-address operand of a vmx instruction, as recorded on an
4347 * exit caused by such an instruction (run by a guest hypervisor).
4348 * On success, returns 0. When the operand is invalid, returns 1 and throws
4349 * #UD or #GP.
4350 */
4351static int get_vmx_mem_address(struct kvm_vcpu *vcpu,
4352 unsigned long exit_qualification,
4353 u32 vmx_instruction_info, gva_t *ret)
4354{
4355 /*
4356 * According to Vol. 3B, "Information for VM Exits Due to Instruction
4357 * Execution", on an exit, vmx_instruction_info holds most of the
4358 * addressing components of the operand. Only the displacement part
4359 * is put in exit_qualification (see 3B, "Basic VM-Exit Information").
4360 * For how an actual address is calculated from all these components,
4361 * refer to Vol. 1, "Operand Addressing".
4362 */
4363 int scaling = vmx_instruction_info & 3;
4364 int addr_size = (vmx_instruction_info >> 7) & 7;
4365 bool is_reg = vmx_instruction_info & (1u << 10);
4366 int seg_reg = (vmx_instruction_info >> 15) & 7;
4367 int index_reg = (vmx_instruction_info >> 18) & 0xf;
4368 bool index_is_valid = !(vmx_instruction_info & (1u << 22));
4369 int base_reg = (vmx_instruction_info >> 23) & 0xf;
4370 bool base_is_valid = !(vmx_instruction_info & (1u << 27));
4371
4372 if (is_reg) {
4373 kvm_queue_exception(vcpu, UD_VECTOR);
4374 return 1;
4375 }
4376
4377 /* Addr = segment_base + offset */
4378 /* offset = base + [index * scale] + displacement */
4379 *ret = vmx_get_segment_base(vcpu, seg_reg);
4380 if (base_is_valid)
4381 *ret += kvm_register_read(vcpu, base_reg);
4382 if (index_is_valid)
4383 *ret += kvm_register_read(vcpu, index_reg)<<scaling;
4384 *ret += exit_qualification; /* holds the displacement */
4385
4386 if (addr_size == 1) /* 32 bit */
4387 *ret &= 0xffffffff;
4388
4389 /*
4390 * TODO: throw #GP (and return 1) in various cases that the VM*
4391 * instructions require it - e.g., offset beyond segment limit,
4392 * unusable or unreadable/unwritable segment, non-canonical 64-bit
4393 * address, and so on. Currently these are not checked.
4394 */
4395 return 0;
4396}
4397
4398/*
4346 * The exit handlers return 1 if the exit was handled fully and guest execution 4399 * The exit handlers return 1 if the exit was handled fully and guest execution
4347 * may resume. Otherwise they set the kvm_run parameter to indicate what needs 4400 * may resume. Otherwise they set the kvm_run parameter to indicate what needs
4348 * to be done to userspace and return 0. 4401 * to be done to userspace and return 0.