diff options
author | Avi Kivity <avi@qumranet.com> | 2008-06-22 09:22:51 -0400 |
---|---|---|
committer | Avi Kivity <avi@qumranet.com> | 2008-07-20 05:42:35 -0400 |
commit | 7a5b56dfd3a682a51fc84682290d5147872a8e99 (patch) | |
tree | f7b6f0e746df3c43ab8317d1c4b585334808e5fb /arch/x86/kvm/x86_emulate.c | |
parent | 0adc8675d645940139d12477e5e05b8a0a7a1117 (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.c | 96 |
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 | ||
525 | static void set_seg_override(struct decode_cache *c, int seg) | ||
526 | { | ||
527 | c->has_seg_override = true; | ||
528 | c->seg_override = seg; | ||
529 | } | ||
530 | |||
531 | static 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 | |||
539 | static 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 | |||
548 | static unsigned long es_base(struct x86_emulate_ctxt *ctxt) | ||
549 | { | ||
550 | return seg_base(ctxt, VCPU_SREG_ES); | ||
551 | } | ||
552 | |||
553 | static unsigned long ss_base(struct x86_emulate_ctxt *ctxt) | ||
554 | { | ||
555 | return seg_base(ctxt, VCPU_SREG_SS); | ||
556 | } | ||
557 | |||
525 | static int do_fetch_insn_byte(struct x86_emulate_ctxt *ctxt, | 558 | static 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, |