summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorneel <neel@FreeBSD.org>2014-05-25 00:57:24 +0000
committerneel <neel@FreeBSD.org>2014-05-25 00:57:24 +0000
commitffc6a3825939d41297e840fd814e632c1e9beafa (patch)
tree88b474b3403d076cec0ddc0873ec0df3dbc90f68 /sys
parent505c6cdc05fb89d0866357abe117e92040168175 (diff)
downloadFreeBSD-src-ffc6a3825939d41297e840fd814e632c1e9beafa.zip
FreeBSD-src-ffc6a3825939d41297e840fd814e632c1e9beafa.tar.gz
Do the linear address calculation for the ins/outs emulation using a new
API function 'vie_calculate_gla()'. While the current implementation is simplistic it forms the basis of doing segmentation checks if the guest is in 32-bit protected mode.
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/include/vmm.h1
-rw-r--r--sys/amd64/include/vmm_instruction_emul.h6
-rw-r--r--sys/amd64/vmm/intel/vmx.c1
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c70
-rw-r--r--sys/amd64/vmm/vmm_ioport.c16
5 files changed, 35 insertions, 59 deletions
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h
index 28e2808..b30e42e 100644
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -426,7 +426,6 @@ struct vm_inout_str {
int addrsize;
enum vm_reg_name seg_name;
struct seg_desc seg_desc;
- uint64_t gla; /* may be set to VIE_INVALID_GLA */
};
struct vm_exit {
diff --git a/sys/amd64/include/vmm_instruction_emul.h b/sys/amd64/include/vmm_instruction_emul.h
index 1703feb..5e6862b 100644
--- a/sys/amd64/include/vmm_instruction_emul.h
+++ b/sys/amd64/include/vmm_instruction_emul.h
@@ -67,6 +67,9 @@ int vie_canonical_check(enum vm_cpu_mode cpu_mode, uint64_t gla);
uint64_t vie_size2mask(int size);
+int vie_calculate_gla(enum vm_cpu_mode cpu_mode, int addrsize,
+ enum vm_reg_name seg, struct seg_desc *desc, uint64_t off, uint64_t *gla);
+
#ifdef _KERNEL
/*
* APIs to fetch and decode the instruction from nested page fault handler.
@@ -89,9 +92,6 @@ int vmm_gla2gpa(struct vm *vm, int vcpuid, struct vm_guest_paging *paging,
void vie_init(struct vie *vie);
-uint64_t vie_segbase(enum vm_reg_name segment, enum vm_cpu_mode cpu_mode,
- const struct seg_desc *desc);
-
/*
* Decode the instruction fetched into 'vie' so it can be emulated.
*
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index 8efb667..1509931 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -2012,7 +2012,6 @@ vmx_exit_process(struct vmx *vmx, int vcpu, struct vm_exit *vmexit)
vis->count = inout_str_count(vmx, vcpu, vis->inout.rep);
vis->addrsize = inout_str_addrsize(inst_info);
inout_str_seginfo(vmx, vcpu, inst_info, in, vis);
- vis->gla = vmcs_gla();
}
break;
case EXIT_REASON_CPUID:
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index 0f520d7..8d4f540 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -607,6 +607,38 @@ vie_size2mask(int size)
return (size2mask[size]);
}
+int
+vie_calculate_gla(enum vm_cpu_mode cpu_mode, int addrsize, enum vm_reg_name seg,
+ struct seg_desc *desc, uint64_t offset, uint64_t *gla)
+{
+ uint64_t segbase;
+ int glasize;
+
+ KASSERT(seg >= VM_REG_GUEST_ES && seg <= VM_REG_GUEST_GS,
+ ("%s: invalid segment %d", __func__, seg));
+
+ glasize = (cpu_mode == CPU_MODE_64BIT) ? 8 : 4;
+
+ /*
+ * In 64-bit mode all segments except %fs and %gs have a segment
+ * base address of 0.
+ */
+ if (cpu_mode == CPU_MODE_64BIT && seg != VM_REG_GUEST_FS &&
+ seg != VM_REG_GUEST_GS) {
+ segbase = 0;
+ } else {
+ segbase = desc->base;
+ }
+
+ /*
+ * Truncate 'offset' to the effective address size before adding
+ * it to the segment base.
+ */
+ offset &= vie_size2mask(addrsize);
+ *gla = (segbase + offset) & vie_size2mask(glasize);
+ return (0);
+}
+
#ifdef _KERNEL
void
vie_init(struct vie *vie)
@@ -1271,42 +1303,4 @@ vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla,
return (0);
}
-
-uint64_t
-vie_segbase(enum vm_reg_name seg, enum vm_cpu_mode cpu_mode,
- const struct seg_desc *desc)
-{
- int basesize;
-
- basesize = 4; /* default segment width in bytes */
-
- switch (seg) {
- case VM_REG_GUEST_ES:
- case VM_REG_GUEST_CS:
- case VM_REG_GUEST_SS:
- case VM_REG_GUEST_DS:
- if (cpu_mode == CPU_MODE_64BIT) {
- /*
- * Segments having an implicit base address of 0
- * in 64-bit mode.
- */
- return (0);
- }
- break;
- case VM_REG_GUEST_FS:
- case VM_REG_GUEST_GS:
- if (cpu_mode == CPU_MODE_64BIT) {
- /*
- * In 64-bit mode the FS and GS base address is 8 bytes
- * wide.
- */
- basesize = 8;
- }
- break;
- default:
- panic("%s: invalid segment register %d", __func__, seg);
- }
-
- return (desc->base & size2mask[basesize]);
-}
#endif /* _KERNEL */
diff --git a/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c
index 96f2418..c462625 100644
--- a/sys/amd64/vmm/vmm_ioport.c
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -144,7 +144,6 @@ static int
emulate_inout_str(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu)
{
struct vm_inout_str *vis;
- uint64_t gla, index, segbase;
int in;
vis = &vmexit->u.inout_str;
@@ -182,21 +181,6 @@ emulate_inout_str(struct vm *vm, int vcpuid, struct vm_exit *vmexit, bool *retu)
return (EINVAL);
}
- segbase = vie_segbase(vis->seg_name, vis->paging.cpu_mode,
- &vis->seg_desc);
- index = vis->index & vie_size2mask(vis->addrsize);
- gla = segbase + index;
-
- /*
- * Verify that the computed linear address matches with the one
- * provided by hardware.
- */
- if (vis->gla != VIE_INVALID_GLA) {
- KASSERT(gla == vis->gla, ("%s: gla mismatch "
- "%#lx/%#lx", __func__, gla, vis->gla));
- }
- vis->gla = gla;
-
*retu = true;
return (0); /* Return to userspace to finish emulation */
}
OpenPOWER on IntegriCloud