Changeset View
Changeset View
Standalone View
Standalone View
head/sys/amd64/vmm/vmm_instruction_emul.c
Show First 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | |||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#else /* !_KERNEL */ | #else /* !_KERNEL */ | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/_iovec.h> | #include <sys/_iovec.h> | ||||
#include <machine/vmm.h> | #include <machine/vmm.h> | ||||
#include <err.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <stdbool.h> | |||||
#include <stdio.h> | |||||
#include <strings.h> | |||||
#include <vmmapi.h> | #include <vmmapi.h> | ||||
#define KASSERT(exp,msg) assert((exp)) | #define KASSERT(exp,msg) assert((exp)) | ||||
#define panic(...) errx(4, __VA_ARGS__) | |||||
#endif /* _KERNEL */ | #endif /* _KERNEL */ | ||||
#include <machine/vmm_instruction_emul.h> | #include <machine/vmm_instruction_emul.h> | ||||
#include <x86/psl.h> | #include <x86/psl.h> | ||||
#include <x86/specialreg.h> | #include <x86/specialreg.h> | ||||
/* struct vie_op.op_type */ | /* struct vie_op.op_type */ | ||||
enum { | enum { | ||||
▲ Show 20 Lines • Show All 1,827 Lines • ▼ Show 20 Lines | vie_calculate_gla(enum vm_cpu_mode cpu_mode, enum vm_reg_name seg, | ||||
* Truncate 'firstoff' to the effective address size before adding | * Truncate 'firstoff' to the effective address size before adding | ||||
* it to the segment base. | * it to the segment base. | ||||
*/ | */ | ||||
firstoff &= vie_size2mask(addrsize); | firstoff &= vie_size2mask(addrsize); | ||||
*gla = (segbase + firstoff) & vie_size2mask(glasize); | *gla = (segbase + firstoff) & vie_size2mask(glasize); | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef _KERNEL | |||||
void | void | ||||
vie_init(struct vie *vie, const char *inst_bytes, int inst_length) | vie_init(struct vie *vie, const char *inst_bytes, int inst_length) | ||||
{ | { | ||||
KASSERT(inst_length >= 0 && inst_length <= VIE_INST_SIZE, | KASSERT(inst_length >= 0 && inst_length <= VIE_INST_SIZE, | ||||
("%s: invalid instruction length (%d)", __func__, inst_length)); | ("%s: invalid instruction length (%d)", __func__, inst_length)); | ||||
bzero(vie, sizeof(struct vie)); | bzero(vie, sizeof(struct vie)); | ||||
vie->base_register = VM_REG_LAST; | vie->base_register = VM_REG_LAST; | ||||
vie->index_register = VM_REG_LAST; | vie->index_register = VM_REG_LAST; | ||||
vie->segment_register = VM_REG_LAST; | vie->segment_register = VM_REG_LAST; | ||||
if (inst_length) { | if (inst_length) { | ||||
bcopy(inst_bytes, vie->inst, inst_length); | bcopy(inst_bytes, vie->inst, inst_length); | ||||
vie->num_valid = inst_length; | vie->num_valid = inst_length; | ||||
} | } | ||||
} | } | ||||
#ifdef _KERNEL | |||||
static int | static int | ||||
pf_error_code(int usermode, int prot, int rsvd, uint64_t pte) | pf_error_code(int usermode, int prot, int rsvd, uint64_t pte) | ||||
{ | { | ||||
int error_code = 0; | int error_code = 0; | ||||
if (pte & PG_V) | if (pte & PG_V) | ||||
error_code |= PGEX_P; | error_code |= PGEX_P; | ||||
if (prot & VM_PROT_WRITE) | if (prot & VM_PROT_WRITE) | ||||
▲ Show 20 Lines • Show All 258 Lines • ▼ Show 20 Lines | vmm_fetch_instruction(struct vm *vm, int vcpuid, struct vm_guest_paging *paging, | ||||
if (error || *faultptr) | if (error || *faultptr) | ||||
return (error); | return (error); | ||||
vm_copyin(vm, vcpuid, copyinfo, vie->inst, inst_length); | vm_copyin(vm, vcpuid, copyinfo, vie->inst, inst_length); | ||||
vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo)); | vm_copy_teardown(vm, vcpuid, copyinfo, nitems(copyinfo)); | ||||
vie->num_valid = inst_length; | vie->num_valid = inst_length; | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif /* _KERNEL */ | |||||
static int | static int | ||||
vie_peek(struct vie *vie, uint8_t *x) | vie_peek(struct vie *vie, uint8_t *x) | ||||
{ | { | ||||
if (vie->num_processed < vie->num_valid) { | if (vie->num_processed < vie->num_valid) { | ||||
*x = vie->inst[vie->num_processed]; | *x = vie->inst[vie->num_processed]; | ||||
return (0); | return (0); | ||||
▲ Show 20 Lines • Show All 406 Lines • ▼ Show 20 Lines | for (i = 0; i < n; i++) { | ||||
u.buf[i] = x; | u.buf[i] = x; | ||||
vie_advance(vie); | vie_advance(vie); | ||||
} | } | ||||
vie->displacement = u.u64; | vie->displacement = u.u64; | ||||
return (0); | return (0); | ||||
} | } | ||||
#ifdef _KERNEL | |||||
/* | /* | ||||
* Verify that the 'guest linear address' provided as collateral of the nested | * Verify that the 'guest linear address' provided as collateral of the nested | ||||
* page table fault matches with our instruction decoding. | * page table fault matches with our instruction decoding. | ||||
*/ | */ | ||||
static int | static int | ||||
verify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie, | verify_gla(struct vm *vm, int cpuid, uint64_t gla, struct vie *vie, | ||||
enum vm_cpu_mode cpu_mode) | enum vm_cpu_mode cpu_mode) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | printf("verify_gla mismatch: segbase(0x%0lx)" | ||||
"disp(0x%0lx), gla(0x%0lx), gla2(0x%0lx)\n", | "disp(0x%0lx), gla(0x%0lx), gla2(0x%0lx)\n", | ||||
segbase, base, vie->scale, idx, vie->displacement, | segbase, base, vie->scale, idx, vie->displacement, | ||||
gla, gla2); | gla, gla2); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif /* _KERNEL */ | |||||
int | int | ||||
#ifdef _KERNEL | |||||
vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, | vmm_decode_instruction(struct vm *vm, int cpuid, uint64_t gla, | ||||
enum vm_cpu_mode cpu_mode, int cs_d, struct vie *vie) | enum vm_cpu_mode cpu_mode, int cs_d, struct vie *vie) | ||||
#else | |||||
vmm_decode_instruction(enum vm_cpu_mode cpu_mode, int cs_d, struct vie *vie) | |||||
#endif | |||||
{ | { | ||||
if (decode_prefixes(vie, cpu_mode, cs_d)) | if (decode_prefixes(vie, cpu_mode, cs_d)) | ||||
return (-1); | return (-1); | ||||
if (decode_opcode(vie)) | if (decode_opcode(vie)) | ||||
return (-1); | return (-1); | ||||
if (decode_modrm(vie, cpu_mode)) | if (decode_modrm(vie, cpu_mode)) | ||||
return (-1); | return (-1); | ||||
if (decode_sib(vie)) | if (decode_sib(vie)) | ||||
return (-1); | return (-1); | ||||
if (decode_displacement(vie)) | if (decode_displacement(vie)) | ||||
return (-1); | return (-1); | ||||
if (decode_immediate(vie)) | if (decode_immediate(vie)) | ||||
return (-1); | return (-1); | ||||
if (decode_moffset(vie)) | if (decode_moffset(vie)) | ||||
return (-1); | return (-1); | ||||
#ifdef _KERNEL | |||||
if ((vie->op.op_flags & VIE_OP_F_NO_GLA_VERIFICATION) == 0) { | if ((vie->op.op_flags & VIE_OP_F_NO_GLA_VERIFICATION) == 0) { | ||||
if (verify_gla(vm, cpuid, gla, vie, cpu_mode)) | if (verify_gla(vm, cpuid, gla, vie, cpu_mode)) | ||||
return (-1); | return (-1); | ||||
} | } | ||||
#endif | |||||
vie->decoded = 1; /* success */ | vie->decoded = 1; /* success */ | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif /* _KERNEL */ |