aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/x86_emulate.c
diff options
context:
space:
mode:
authorAvi Kivity <avi@qumranet.com>2008-06-22 09:22:51 -0400
committerAvi Kivity <avi@qumranet.com>2008-07-20 05:42:35 -0400
commit7a5b56dfd3a682a51fc84682290d5147872a8e99 (patch)
treef7b6f0e746df3c43ab8317d1c4b585334808e5fb /arch/x86/kvm/x86_emulate.c
parent0adc8675d645940139d12477e5e05b8a0a7a1117 (diff)
KVM: x86 emulator: lazily evaluate segment registers
Instead of prefetching all segment bases before emulation, read them at the last moment. Since most of them are unneeded, we save some cycles on Intel machines where this is a bit expensive. Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'arch/x86/kvm/x86_emulate.c')
-rw-r--r--arch/x86/kvm/x86_emulate.c96
1 files changed, 57 insertions, 39 deletions
diff --git a/arch/x86/kvm/x86_emulate.c b/arch/x86/kvm/x86_emulate.c
index 38926b7da64..18ca25c2d4a 100644
--- a/arch/x86/kvm/x86_emulate.c
+++ b/arch/x86/kvm/x86_emulate.c
@@ -522,6 +522,39 @@ static inline void jmp_rel(struct decode_cache *c, int rel)
522 register_address_increment(c, &c->eip, rel); 522 register_address_increment(c, &c->eip, rel);
523} 523}
524 524
525static void set_seg_override(struct decode_cache *c, int seg)
526{
527 c->has_seg_override = true;
528 c->seg_override = seg;
529}
530
531static unsigned long seg_base(struct x86_emulate_ctxt *ctxt, int seg)
532{
533 if (ctxt->mode == X86EMUL_MODE_PROT64 && seg < VCPU_SREG_FS)
534 return 0;
535
536 return kvm_x86_ops->get_segment_base(ctxt->vcpu, seg);
537}
538
539static unsigned long seg_override_base(struct x86_emulate_ctxt *ctxt,
540 struct decode_cache *c)
541{
542 if (!c->has_seg_override)
543 return 0;
544
545 return seg_base(ctxt, c->seg_override);
546}
547
548static unsigned long es_base(struct x86_emulate_ctxt *ctxt)
549{
550 return seg_base(ctxt, VCPU_SREG_ES);
551}
552
553static unsigned long ss_base(struct x86_emulate_ctxt *ctxt)
554{
555 return seg_base(ctxt, VCPU_SREG_SS);
556}
557
525static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, 558static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt,
526 struct x86_emulate_ops *ops, 559 struct x86_emulate_ops *ops,
527 unsigned long linear, u8 *dest) 560 unsigned long linear, u8 *dest)
@@ -735,8 +768,8 @@ static int decode_modrm(struct x86_emulate_ctxt *ctxt,
735 } 768 }
736 if (c->modrm_rm == 2 || c->modrm_rm == 3 || 769 if (c->modrm_rm == 2 || c->modrm_rm == 3 ||
737 (c->modrm_rm == 6 && c->modrm_mod != 0)) 770 (c->modrm_rm == 6 && c->modrm_mod != 0))
738 if (!c->override_base) 771 if (!c->has_seg_override)
739 c->override_base = &ctxt->ss_base; 772 set_seg_override(c, VCPU_SREG_SS);
740 c->modrm_ea = (u16)c->modrm_ea; 773 c->modrm_ea = (u16)c->modrm_ea;
741 } else { 774 } else {
742 /* 32/64-bit ModR/M decode. */ 775 /* 32/64-bit ModR/M decode. */
@@ -807,6 +840,7 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
807 840
808 memset(c, 0, sizeof(struct decode_cache)); 841 memset(c, 0, sizeof(struct decode_cache));
809 c->eip = ctxt->vcpu->arch.rip; 842 c->eip = ctxt->vcpu->arch.rip;
843 ctxt->cs_base = seg_base(ctxt, VCPU_SREG_CS);
810 memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs); 844 memcpy(c->regs, ctxt->vcpu->arch.regs, sizeof c->regs);
811 845
812 switch (mode) { 846 switch (mode) {
@@ -845,23 +879,15 @@ x86_decode_insn(struct x86_emulate_ctxt *ctxt, struct x86_emulate_ops *ops)
845 /* switch between 2/4 bytes */ 879 /* switch between 2/4 bytes */
846 c->ad_bytes = def_ad_bytes ^ 6; 880 c->ad_bytes = def_ad_bytes ^ 6;
847 break; 881 break;
882 case 0x26: /* ES override */
848 case 0x2e: /* CS override */ 883 case 0x2e: /* CS override */
849 c->override_base = &ctxt->cs_base; 884 case 0x36: /* SS override */
850 break;
851 case 0x3e: /* DS override */ 885 case 0x3e: /* DS override */
852 c->override_base = &ctxt->ds_base; 886 set_seg_override(c, (c->b >> 3) & 3);
853 break;
854 case 0x26: /* ES override */
855 c->override_base = &ctxt->es_base;
856 break; 887 break;
857 case 0x64: /* FS override */ 888 case 0x64: /* FS override */
858 c->override_base = &ctxt->fs_base;
859 break;
860 case 0x65: /* GS override */ 889 case 0x65: /* GS override */
861 c->override_base = &ctxt->gs_base; 890 set_seg_override(c, c->b & 7);
862 break;
863 case 0x36: /* SS override */
864 c->override_base = &ctxt->ss_base;
865 break; 891 break;
866 case 0x40 ... 0x4f: /* REX */ 892 case 0x40 ... 0x4f: /* REX */
867 if (mode != X86EMUL_MODE_PROT64) 893 if (mode != X86EMUL_MODE_PROT64)
@@ -933,15 +959,11 @@ done_prefixes:
933 if (rc) 959 if (rc)
934 goto done; 960 goto done;
935 961
936 if (!c->override_base) 962 if (!c->has_seg_override)
937 c->override_base = &ctxt->ds_base; 963 set_seg_override(c, VCPU_SREG_DS);
938 if (mode == X86EMUL_MODE_PROT64 &&
939 c->override_base != &ctxt->fs_base &&
940 c->override_base != &ctxt->gs_base)
941 c->override_base = NULL;
942 964
943 if (c->override_base && !(!c->twobyte && c->b == 0x8d)) 965 if (!(!c->twobyte && c->b == 0x8d))
944 c->modrm_ea += *c->override_base; 966 c->modrm_ea += seg_override_base(ctxt, c);
945 967
946 if (c->ad_bytes != 8) 968 if (c->ad_bytes != 8)
947 c->modrm_ea = (u32)c->modrm_ea; 969 c->modrm_ea = (u32)c->modrm_ea;
@@ -1043,7 +1065,7 @@ static inline void emulate_push(struct x86_emulate_ctxt *ctxt)
1043 c->dst.bytes = c->op_bytes; 1065 c->dst.bytes = c->op_bytes;
1044 c->dst.val = c->src.val; 1066 c->dst.val = c->src.val;
1045 register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); 1067 register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes);
1046 c->dst.ptr = (void *) register_address(c, ctxt->ss_base, 1068 c->dst.ptr = (void *) register_address(c, ss_base(ctxt),
1047 c->regs[VCPU_REGS_RSP]); 1069 c->regs[VCPU_REGS_RSP]);
1048} 1070}
1049 1071
@@ -1053,7 +1075,7 @@ static inline int emulate_grp1a(struct x86_emulate_ctxt *ctxt,
1053 struct decode_cache *c = &ctxt->decode; 1075 struct decode_cache *c = &ctxt->decode;
1054 int rc; 1076 int rc;
1055 1077
1056 rc = ops->read_std(register_address(c, ctxt->ss_base, 1078 rc = ops->read_std(register_address(c, ss_base(ctxt),
1057 c->regs[VCPU_REGS_RSP]), 1079 c->regs[VCPU_REGS_RSP]),
1058 &c->dst.val, c->dst.bytes, ctxt->vcpu); 1080 &c->dst.val, c->dst.bytes, ctxt->vcpu);
1059 if (rc != 0) 1081 if (rc != 0)
@@ -1375,11 +1397,11 @@ special_insn:
1375 register_address_increment(c, &c->regs[VCPU_REGS_RSP], 1397 register_address_increment(c, &c->regs[VCPU_REGS_RSP],
1376 -c->op_bytes); 1398 -c->op_bytes);
1377 c->dst.ptr = (void *) register_address( 1399 c->dst.ptr = (void *) register_address(
1378 c, ctxt->ss_base, c->regs[VCPU_REGS_RSP]); 1400 c, ss_base(ctxt), c->regs[VCPU_REGS_RSP]);
1379 break; 1401 break;
1380 case 0x58 ... 0x5f: /* pop reg */ 1402 case 0x58 ... 0x5f: /* pop reg */
1381 pop_instruction: 1403 pop_instruction:
1382 if ((rc = ops->read_std(register_address(c, ctxt->ss_base, 1404 if ((rc = ops->read_std(register_address(c, ss_base(ctxt),
1383 c->regs[VCPU_REGS_RSP]), c->dst.ptr, 1405 c->regs[VCPU_REGS_RSP]), c->dst.ptr,
1384 c->op_bytes, ctxt->vcpu)) != 0) 1406 c->op_bytes, ctxt->vcpu)) != 0)
1385 goto done; 1407 goto done;
@@ -1405,7 +1427,7 @@ special_insn:
1405 c->rep_prefix ? 1427 c->rep_prefix ?
1406 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, 1428 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
1407 (ctxt->eflags & EFLG_DF), 1429 (ctxt->eflags & EFLG_DF),
1408 register_address(c, ctxt->es_base, 1430 register_address(c, es_base(ctxt),
1409 c->regs[VCPU_REGS_RDI]), 1431 c->regs[VCPU_REGS_RDI]),
1410 c->rep_prefix, 1432 c->rep_prefix,
1411 c->regs[VCPU_REGS_RDX]) == 0) { 1433 c->regs[VCPU_REGS_RDX]) == 0) {
@@ -1421,9 +1443,8 @@ special_insn:
1421 c->rep_prefix ? 1443 c->rep_prefix ?
1422 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1, 1444 address_mask(c, c->regs[VCPU_REGS_RCX]) : 1,
1423 (ctxt->eflags & EFLG_DF), 1445 (ctxt->eflags & EFLG_DF),
1424 register_address(c, c->override_base ? 1446 register_address(c,
1425 *c->override_base : 1447 seg_override_base(ctxt, c),
1426 ctxt->ds_base,
1427 c->regs[VCPU_REGS_RSI]), 1448 c->regs[VCPU_REGS_RSI]),
1428 c->rep_prefix, 1449 c->rep_prefix,
1429 c->regs[VCPU_REGS_RDX]) == 0) { 1450 c->regs[VCPU_REGS_RDX]) == 0) {
@@ -1559,11 +1580,10 @@ special_insn:
1559 c->dst.type = OP_MEM; 1580 c->dst.type = OP_MEM;
1560 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1581 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1561 c->dst.ptr = (unsigned long *)register_address(c, 1582 c->dst.ptr = (unsigned long *)register_address(c,
1562 ctxt->es_base, 1583 es_base(ctxt),
1563 c->regs[VCPU_REGS_RDI]); 1584 c->regs[VCPU_REGS_RDI]);
1564 if ((rc = ops->read_emulated(register_address(c, 1585 if ((rc = ops->read_emulated(register_address(c,
1565 c->override_base ? *c->override_base : 1586 seg_override_base(ctxt, c),
1566 ctxt->ds_base,
1567 c->regs[VCPU_REGS_RSI]), 1587 c->regs[VCPU_REGS_RSI]),
1568 &c->dst.val, 1588 &c->dst.val,
1569 c->dst.bytes, ctxt->vcpu)) != 0) 1589 c->dst.bytes, ctxt->vcpu)) != 0)
@@ -1579,8 +1599,7 @@ special_insn:
1579 c->src.type = OP_NONE; /* Disable writeback. */ 1599 c->src.type = OP_NONE; /* Disable writeback. */
1580 c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1600 c->src.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1581 c->src.ptr = (unsigned long *)register_address(c, 1601 c->src.ptr = (unsigned long *)register_address(c,
1582 c->override_base ? *c->override_base : 1602 seg_override_base(ctxt, c),
1583 ctxt->ds_base,
1584 c->regs[VCPU_REGS_RSI]); 1603 c->regs[VCPU_REGS_RSI]);
1585 if ((rc = ops->read_emulated((unsigned long)c->src.ptr, 1604 if ((rc = ops->read_emulated((unsigned long)c->src.ptr,
1586 &c->src.val, 1605 &c->src.val,
@@ -1591,7 +1610,7 @@ special_insn:
1591 c->dst.type = OP_NONE; /* Disable writeback. */ 1610 c->dst.type = OP_NONE; /* Disable writeback. */
1592 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1611 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1593 c->dst.ptr = (unsigned long *)register_address(c, 1612 c->dst.ptr = (unsigned long *)register_address(c,
1594 ctxt->es_base, 1613 es_base(ctxt),
1595 c->regs[VCPU_REGS_RDI]); 1614 c->regs[VCPU_REGS_RDI]);
1596 if ((rc = ops->read_emulated((unsigned long)c->dst.ptr, 1615 if ((rc = ops->read_emulated((unsigned long)c->dst.ptr,
1597 &c->dst.val, 1616 &c->dst.val,
@@ -1615,7 +1634,7 @@ special_insn:
1615 c->dst.type = OP_MEM; 1634 c->dst.type = OP_MEM;
1616 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1635 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1617 c->dst.ptr = (unsigned long *)register_address(c, 1636 c->dst.ptr = (unsigned long *)register_address(c,
1618 ctxt->es_base, 1637 es_base(ctxt),
1619 c->regs[VCPU_REGS_RDI]); 1638 c->regs[VCPU_REGS_RDI]);
1620 c->dst.val = c->regs[VCPU_REGS_RAX]; 1639 c->dst.val = c->regs[VCPU_REGS_RAX];
1621 register_address_increment(c, &c->regs[VCPU_REGS_RDI], 1640 register_address_increment(c, &c->regs[VCPU_REGS_RDI],
@@ -1627,8 +1646,7 @@ special_insn:
1627 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes; 1646 c->dst.bytes = (c->d & ByteOp) ? 1 : c->op_bytes;
1628 c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX]; 1647 c->dst.ptr = (unsigned long *)&c->regs[VCPU_REGS_RAX];
1629 if ((rc = ops->read_emulated(register_address(c, 1648 if ((rc = ops->read_emulated(register_address(c,
1630 c->override_base ? *c->override_base : 1649 seg_override_base(ctxt, c),
1631 ctxt->ds_base,
1632 c->regs[VCPU_REGS_RSI]), 1650 c->regs[VCPU_REGS_RSI]),
1633 &c->dst.val, 1651 &c->dst.val,
1634 c->dst.bytes, 1652 c->dst.bytes,