diff options
author | Guillaume Thouvenin <guillaume.thouvenin@ext.bull.net> | 2007-11-26 07:49:09 -0500 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-01-30 10:53:15 -0500 |
commit | d7e5117a2568f7407e98ca85155511ecfe4f0631 (patch) | |
tree | 7f9bcd5b42d4ef8f40b396ac3c979399a41dcfab | |
parent | e8d8d7fe8877c594c08f40cc7c013626cfe3e9cc (diff) |
KVM: x86 emulator: cmps instruction
Add emulation for the cmps instruction. This lets OpenBSD boot on kvm.
Signed-off-by: Guillaume Thouvenin <guillaume.thouvenin@ext.bull.net>
Signed-off-by: Avi Kivity <avi@qumranet.com>
-rw-r--r-- | drivers/kvm/x86_emulate.c | 58 |
1 files changed, 56 insertions, 2 deletions
diff --git a/drivers/kvm/x86_emulate.c b/drivers/kvm/x86_emulate.c index 22fdf0ac6615..84e536603f5a 100644 --- a/drivers/kvm/x86_emulate.c +++ b/drivers/kvm/x86_emulate.c | |||
@@ -1535,10 +1535,31 @@ special_insn: | |||
1535 | break; | 1535 | break; |
1536 | } | 1536 | } |
1537 | if (c->rep_prefix) { | 1537 | if (c->rep_prefix) { |
1538 | /* All REP prefixes have the same first termination condition */ | ||
1538 | if (c->regs[VCPU_REGS_RCX] == 0) { | 1539 | if (c->regs[VCPU_REGS_RCX] == 0) { |
1539 | ctxt->vcpu->rip = c->eip; | 1540 | ctxt->vcpu->rip = c->eip; |
1540 | goto done; | 1541 | goto done; |
1541 | } | 1542 | } |
1543 | /* The second termination condition only applies for REPE | ||
1544 | * and REPNE. Test if the repeat string operation prefix is | ||
1545 | * REPE/REPZ or REPNE/REPNZ and if it's the case it tests the | ||
1546 | * corresponding termination condition according to: | ||
1547 | * - if REPE/REPZ and ZF = 0 then done | ||
1548 | * - if REPNE/REPNZ and ZF = 1 then done | ||
1549 | */ | ||
1550 | if ((c->b == 0xa6) || (c->b == 0xa7) || | ||
1551 | (c->b == 0xae) || (c->b == 0xaf)) { | ||
1552 | if ((c->rep_prefix == REPE_PREFIX) && | ||
1553 | ((ctxt->eflags & EFLG_ZF) == 0)) { | ||
1554 | ctxt->vcpu->rip = c->eip; | ||
1555 | goto done; | ||
1556 | } | ||
1557 | if ((c->rep_prefix == REPNE_PREFIX) && | ||
1558 | ((ctxt->eflags & EFLG_ZF) == EFLG_ZF)) { | ||
1559 | ctxt->vcpu->rip = c->eip; | ||
1560 | goto done; | ||
1561 | } | ||
1562 | } | ||
1542 | c->regs[VCPU_REGS_RCX]--; | 1563 | c->regs[VCPU_REGS_RCX]--; |
1543 | c->eip = ctxt->vcpu->rip; | 1564 | c->eip = ctxt->vcpu->rip; |
1544 | } | 1565 | } |
@@ -1564,8 +1585,41 @@ special_insn: | |||
1564 | : c->dst.bytes); | 1585 | : c->dst.bytes); |
1565 | break; | 1586 | break; |
1566 | case 0xa6 ... 0xa7: /* cmps */ | 1587 | case 0xa6 ... 0xa7: /* cmps */ |
1567 | DPRINTF("Urk! I don't handle CMPS.\n"); | 1588 | c->src.type = OP_NONE; /* Disable writeback. */ |
1568 | goto cannot_emulate; | 1589 | c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |
1590 | c->src.ptr = (unsigned long *)register_address( | ||
1591 | c->override_base ? *c->override_base : | ||
1592 | ctxt->ds_base, | ||
1593 | c->regs[VCPU_REGS_RSI]); | ||
1594 | if ((rc = ops->read_emulated((unsigned long)c->src.ptr, | ||
1595 | &c->src.val, | ||
1596 | c->src.bytes, | ||
1597 | ctxt->vcpu)) != 0) | ||
1598 | goto done; | ||
1599 | |||
1600 | c->dst.type = OP_NONE; /* Disable writeback. */ | ||
1601 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | ||
1602 | c->dst.ptr = (unsigned long *)register_address( | ||
1603 | ctxt->es_base, | ||
1604 | c->regs[VCPU_REGS_RDI]); | ||
1605 | if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, | ||
1606 | &c->dst.val, | ||
1607 | c->dst.bytes, | ||
1608 | ctxt->vcpu)) != 0) | ||
1609 | goto done; | ||
1610 | |||
1611 | DPRINTF("cmps: mem1=0x%p mem2=0x%p\n", c->src.ptr, c->dst.ptr); | ||
1612 | |||
1613 | emulate_2op_SrcV("cmp", c->src, c->dst, ctxt->eflags); | ||
1614 | |||
1615 | register_address_increment(c->regs[VCPU_REGS_RSI], | ||
1616 | (ctxt->eflags & EFLG_DF) ? -c->src.bytes | ||
1617 | : c->src.bytes); | ||
1618 | register_address_increment(c->regs[VCPU_REGS_RDI], | ||
1619 | (ctxt->eflags & EFLG_DF) ? -c->dst.bytes | ||
1620 | : c->dst.bytes); | ||
1621 | |||
1622 | break; | ||
1569 | case 0xaa ... 0xab: /* stos */ | 1623 | case 0xaa ... 0xab: /* stos */ |
1570 | c->dst.type = OP_MEM; | 1624 | c->dst.type = OP_MEM; |
1571 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; | 1625 | c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; |