SVM patch to cleanup IOIO handling, do not use "real" mode but rather

the correct "bitness".

Signed-off-by: Tom Woller <thomas.woller@amd.com>
Signed-off-by: Mats Petersson <mats.petersson@amd.com>
This commit is contained in:
kaf24@firebug.cl.cam.ac.uk committed 2006-05-17 23:50:23 +01:00
1 parent 5280374fbb
commit 2f01b51566
1 file changed
+109 -62
+109 -62
View File
@@ -1118,19 +1118,17 @@ static void svm_dr_access (struct vcpu *v, unsigned int reg, unsigned int type,
}
static unsigned int check_for_null_selector(struct vmcb_struct *vmcb,
unsigned int dir, unsigned long *base, unsigned int real)
static void svm_get_prefix_info(struct vmcb_struct *vmcb,
unsigned int dir, segment_selector_t **seg, unsigned int *asize)
{
unsigned char inst[MAX_INST_LEN];
segment_selector_t seg;
int i;
memset(inst, 0, MAX_INST_LEN);
if (inst_copy_from_guest(inst, svm_rip2pointer(vmcb), sizeof(inst))
!= MAX_INST_LEN)
{
printk("check_for_null_selector: get guest instruction failed\n");
printk("%s: get guest instruction failed\n", __func__);
domain_crash_synchronous();
}
@@ -1142,7 +1140,6 @@ static unsigned int check_for_null_selector(struct vmcb_struct *vmcb,
case 0xf2: /* REPNZ */
case 0xf0: /* LOCK */
case 0x66: /* data32 */
case 0x67: /* addr32 */
#if __x86_64__
/* REX prefixes */
case 0x40:
@@ -1164,79 +1161,127 @@ static unsigned int check_for_null_selector(struct vmcb_struct *vmcb,
case 0x4f:
#endif
continue;
case 0x67: /* addr32 */
*asize ^= 48; /* Switch 16/32 bits */
continue;
case 0x2e: /* CS */
seg = vmcb->cs;
break;
*seg = &vmcb->cs;
continue;
case 0x36: /* SS */
seg = vmcb->ss;
break;
*seg = &vmcb->ss;
continue;
case 0x26: /* ES */
seg = vmcb->es;
break;
*seg = &vmcb->es;
continue;
case 0x64: /* FS */
seg = vmcb->fs;
break;
*seg = &vmcb->fs;
continue;
case 0x65: /* GS */
seg = vmcb->gs;
break;
*seg = &vmcb->gs;
continue;
case 0x3e: /* DS */
/* FALLTHROUGH */
seg = vmcb->ds;
break;
*seg = &vmcb->ds;
continue;
default:
if (dir == IOREQ_READ) /* IN/INS instruction? */
seg = vmcb->es;
else
seg = vmcb->ds;
break;
}
if (base)
*base = seg.base;
return seg.attributes.fields.p;
return;
}
ASSERT(0);
return 0;
}
/* Get the address of INS/OUTS instruction */
static inline unsigned long svm_get_io_address(struct vmcb_struct *vmcb,
struct cpu_user_regs *regs, unsigned int dir, unsigned int real)
static inline int svm_get_io_address(struct vmcb_struct *vmcb,
struct cpu_user_regs *regs, unsigned int dir,
unsigned long *count, unsigned long *addr)
{
unsigned long addr = 0;
unsigned long base = 0;
unsigned long reg;
unsigned int asize = 0;
unsigned int isize;
int long_mode;
ioio_info_t info;
segment_selector_t *seg = NULL;
check_for_null_selector(vmcb, dir, &base, real);
info.bytes = vmcb->exitinfo1;
/* If we're in long mode, we shouldn't check the segment presence and limit */
long_mode = vmcb->cs.attributes.fields.l && vmcb->efer & EFER_LMA;
/* d field of cs.attributes is 1 for 32-bit, 0 for 16 or 64 bit.
* l field combined with EFER_LMA -> longmode says whether it's 16 or 64 bit.
*/
asize = (long_mode)?64:((vmcb->cs.attributes.fields.db)?32:16);
/* The ins/outs instructions are single byte, so if we have got more
* than one byte (+ maybe rep-prefix), we have some prefix so we need
* to figure out what it is...
*/
isize = vmcb->exitinfo2 - vmcb->rip;
if (info.fields.rep)
isize --;
if (isize > 1)
{
svm_get_prefix_info(vmcb, dir, &seg, &asize);
}
ASSERT(dir == IOREQ_READ || dir == IOREQ_WRITE);
if (dir == IOREQ_WRITE)
{
if (real)
addr = (regs->esi & 0xFFFF) + base;
else
addr = regs->esi + base;
reg = regs->esi;
if (!seg) /* If no prefix, used DS. */
seg = &vmcb->ds;
}
else
{
if (real)
addr = (regs->edi & 0xFFFF) + base;
else
addr = regs->edi + base;
reg = regs->edi;
seg = &vmcb->es; /* Note: This is ALWAYS ES. */
}
return addr;
/* If the segment isn't present, give GP fault! */
if (!long_mode && !seg->attributes.fields.p)
{
svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
return 0;
}
if (asize == 16)
{
*addr = (reg & 0xFFFF);
*count = regs->ecx & 0xffff;
}
else
{
*addr = reg;
*count = regs->ecx;
}
if (!long_mode) {
if (*addr > seg->limit)
{
svm_inject_exception(vmcb, TRAP_gp_fault, 1, seg->sel);
return 0;
}
else
{
*addr += seg->base;
}
}
return 1;
}
static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs)
{
struct mmio_op *mmio_opp;
unsigned long eip, cs, eflags, cr0;
unsigned long port;
unsigned int real, size, dir;
unsigned int port;
unsigned int size, dir;
ioio_info_t info;
struct vmcb_struct *vmcb = v->arch.hvm_svm.vmcb;
ASSERT(vmcb);
@@ -1244,10 +1289,6 @@ static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs)
mmio_opp->instr = INSTR_PIO;
mmio_opp->flags = 0;
eip = vmcb->rip;
cs = vmcb->cs.sel;
eflags = vmcb->rflags;
info.bytes = vmcb->exitinfo1;
port = info.fields.port; /* port used to be addr */
@@ -1259,27 +1300,33 @@ static void svm_io_instruction(struct vcpu *v, struct cpu_user_regs *regs)
else
size = 1;
cr0 = vmcb->cr0;
real = (eflags & X86_EFLAGS_VM) || !(cr0 & X86_CR0_PE);
HVM_DBG_LOG(DBG_LEVEL_IO,
"svm_io_instruction: port 0x%lx real %d, eip=%lx:%lx, "
"svm_io_instruction: port 0x%x eip=%lx:%lx, "
"exit_qualification = %lx",
(unsigned long) port, real, cs, eip, (unsigned long)info.bytes);
port, vmcb->cs.sel, vmcb->rip, (unsigned long)info.bytes);
/* string instruction */
if (info.fields.str)
{
unsigned long addr, count = 1;
unsigned long addr, count;
int sign = regs->eflags & EF_DF ? -1 : 1;
/* Need the original rip, here. */
addr = svm_get_io_address(vmcb, regs, dir, real);
if (!svm_get_io_address(vmcb, regs, dir, &count, &addr))
{
/* We failed to get a valid address, so don't do the IO operation -
* it would just get worse if we do! Hopefully the guest is handing
* gp-faults...
*/
return;
}
/* "rep" prefix */
if (info.fields.rep)
{
mmio_opp->flags |= REPZ;
count = real ? regs->ecx & 0xFFFF : regs->ecx;
}
else
{
count = 1;
}
/*
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.