diff options
author | Gleb Natapov <gleb@redhat.com> | 2010-03-18 09:20:27 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2010-05-17 05:16:31 -0400 |
commit | 7b262e90fc20a49fddf3dad94c8cead1f0439751 (patch) | |
tree | c64306065ff392590cf89808807fb82a65499650 /arch/x86/kvm/emulate.c | |
parent | 5cd21917da245fbe98bd443de2c7f519b3df6814 (diff) |
KVM: x86 emulator: introduce pio in string read ahead.
To optimize "rep ins" instruction do IO in big chunks ahead of time
instead of doing it only when required during instruction emulation.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'arch/x86/kvm/emulate.c')
-rw-r--r-- | arch/x86/kvm/emulate.c | 46 |
1 files changed, 41 insertions, 5 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 6de6ad1610d8..ab3fff5bf7c4 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -1257,6 +1257,36 @@ done: | |||
1257 | return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; | 1257 | return (rc == X86EMUL_UNHANDLEABLE) ? -1 : 0; |
1258 | } | 1258 | } |
1259 | 1259 | ||
1260 | static int pio_in_emulated(struct x86_emulate_ctxt *ctxt, | ||
1261 | struct x86_emulate_ops *ops, | ||
1262 | unsigned int size, unsigned short port, | ||
1263 | void *dest) | ||
1264 | { | ||
1265 | struct read_cache *rc = &ctxt->decode.io_read; | ||
1266 | |||
1267 | if (rc->pos == rc->end) { /* refill pio read ahead */ | ||
1268 | struct decode_cache *c = &ctxt->decode; | ||
1269 | unsigned int in_page, n; | ||
1270 | unsigned int count = c->rep_prefix ? | ||
1271 | address_mask(c, c->regs[VCPU_REGS_RCX]) : 1; | ||
1272 | in_page = (ctxt->eflags & EFLG_DF) ? | ||
1273 | offset_in_page(c->regs[VCPU_REGS_RDI]) : | ||
1274 | PAGE_SIZE - offset_in_page(c->regs[VCPU_REGS_RDI]); | ||
1275 | n = min(min(in_page, (unsigned int)sizeof(rc->data)) / size, | ||
1276 | count); | ||
1277 | if (n == 0) | ||
1278 | n = 1; | ||
1279 | rc->pos = rc->end = 0; | ||
1280 | if (!ops->pio_in_emulated(size, port, rc->data, n, ctxt->vcpu)) | ||
1281 | return 0; | ||
1282 | rc->end = n * size; | ||
1283 | } | ||
1284 | |||
1285 | memcpy(dest, rc->data + rc->pos, size); | ||
1286 | rc->pos += size; | ||
1287 | return 1; | ||
1288 | } | ||
1289 | |||
1260 | static u32 desc_limit_scaled(struct desc_struct *desc) | 1290 | static u32 desc_limit_scaled(struct desc_struct *desc) |
1261 | { | 1291 | { |
1262 | u32 limit = get_desc_limit(desc); | 1292 | u32 limit = get_desc_limit(desc); |
@@ -2622,8 +2652,8 @@ special_insn: | |||
2622 | kvm_inject_gp(ctxt->vcpu, 0); | 2652 | kvm_inject_gp(ctxt->vcpu, 0); |
2623 | goto done; | 2653 | goto done; |
2624 | } | 2654 | } |
2625 | if (!ops->pio_in_emulated(c->dst.bytes, c->regs[VCPU_REGS_RDX], | 2655 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, |
2626 | &c->dst.val, 1, ctxt->vcpu)) | 2656 | c->regs[VCPU_REGS_RDX], &c->dst.val)) |
2627 | goto done; /* IO is needed, skip writeback */ | 2657 | goto done; /* IO is needed, skip writeback */ |
2628 | break; | 2658 | break; |
2629 | case 0x6e: /* outsb */ | 2659 | case 0x6e: /* outsb */ |
@@ -2839,8 +2869,8 @@ special_insn: | |||
2839 | kvm_inject_gp(ctxt->vcpu, 0); | 2869 | kvm_inject_gp(ctxt->vcpu, 0); |
2840 | goto done; | 2870 | goto done; |
2841 | } | 2871 | } |
2842 | if (!ops->pio_in_emulated(c->dst.bytes, c->src.val, | 2872 | if (!pio_in_emulated(ctxt, ops, c->dst.bytes, c->src.val, |
2843 | &c->dst.val, 1, ctxt->vcpu)) | 2873 | &c->dst.val)) |
2844 | goto done; /* IO is needed */ | 2874 | goto done; /* IO is needed */ |
2845 | break; | 2875 | break; |
2846 | case 0xee: /* out al,dx */ | 2876 | case 0xee: /* out al,dx */ |
@@ -2928,8 +2958,14 @@ writeback: | |||
2928 | string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst); | 2958 | string_addr_inc(ctxt, es_base(ctxt), VCPU_REGS_RDI, &c->dst); |
2929 | 2959 | ||
2930 | if (c->rep_prefix && (c->d & String)) { | 2960 | if (c->rep_prefix && (c->d & String)) { |
2961 | struct read_cache *rc = &ctxt->decode.io_read; | ||
2931 | register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); | 2962 | register_address_increment(c, &c->regs[VCPU_REGS_RCX], -1); |
2932 | if (!(c->regs[VCPU_REGS_RCX] & 0x3ff)) | 2963 | /* |
2964 | * Re-enter guest when pio read ahead buffer is empty or, | ||
2965 | * if it is not used, after each 1024 iteration. | ||
2966 | */ | ||
2967 | if ((rc->end == 0 && !(c->regs[VCPU_REGS_RCX] & 0x3ff)) || | ||
2968 | (rc->end != 0 && rc->end == rc->pos)) | ||
2933 | ctxt->restart = false; | 2969 | ctxt->restart = false; |
2934 | } | 2970 | } |
2935 | 2971 | ||