diff options
author | Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> | 2011-04-12 11:29:09 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2011-05-11 07:57:08 -0400 |
commit | 4179bb02fd3e87183e5f698495dfcb80df187889 (patch) | |
tree | 8e896121d38dc7dc6d7eb6acd6c5cb762cabd2c6 | |
parent | 575e7c1417d41dd72ddf2a49965f833ce9352e92 (diff) |
KVM: x86 emulator: Make emulate_push() store the value directly
PUSH emulation stores the value by calling writeback() after setting
the dst operand appropriately in emulate_push().
This writeback() using dst is not needed at all because we know the
target is the stack. So this patch makes emulate_push() call, newly
introduced, segmented_write() directly.
By this, many inlined writeback()'s are removed.
Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp>
Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r-- | arch/x86/kvm/emulate.c | 87 |
1 files changed, 34 insertions, 53 deletions
diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index 1e0e3f8156f8..4f4d9bc6178a 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c | |||
@@ -1345,17 +1345,19 @@ static inline int writeback(struct x86_emulate_ctxt *ctxt, | |||
1345 | return X86EMUL_CONTINUE; | 1345 | return X86EMUL_CONTINUE; |
1346 | } | 1346 | } |
1347 | 1347 | ||
1348 | static inline void emulate_push(struct x86_emulate_ctxt *ctxt, | 1348 | static int emulate_push(struct x86_emulate_ctxt *ctxt, |
1349 | struct x86_emulate_ops *ops) | 1349 | struct x86_emulate_ops *ops) |
1350 | { | 1350 | { |
1351 | struct decode_cache *c = &ctxt->decode; | 1351 | struct decode_cache *c = &ctxt->decode; |
1352 | struct segmented_address addr; | ||
1352 | 1353 | ||
1353 | c->dst.type = OP_MEM; | ||
1354 | c->dst.bytes = c->op_bytes; | ||
1355 | c->dst.val = c->src.val; | ||
1356 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); | 1354 | register_address_increment(c, &c->regs[VCPU_REGS_RSP], -c->op_bytes); |
1357 | c->dst.addr.mem.ea = register_address(c, c->regs[VCPU_REGS_RSP]); | 1355 | addr.ea = register_address(c, c->regs[VCPU_REGS_RSP]); |
1358 | c->dst.addr.mem.seg = VCPU_SREG_SS; | 1356 | addr.seg = VCPU_SREG_SS; |
1357 | |||
1358 | /* Disable writeback. */ | ||
1359 | c->dst.type = OP_NONE; | ||
1360 | return segmented_write(ctxt, addr, &c->src.val, c->op_bytes); | ||
1359 | } | 1361 | } |
1360 | 1362 | ||
1361 | static int emulate_pop(struct x86_emulate_ctxt *ctxt, | 1363 | static int emulate_pop(struct x86_emulate_ctxt *ctxt, |
@@ -1417,14 +1419,14 @@ static int emulate_popf(struct x86_emulate_ctxt *ctxt, | |||
1417 | return rc; | 1419 | return rc; |
1418 | } | 1420 | } |
1419 | 1421 | ||
1420 | static void emulate_push_sreg(struct x86_emulate_ctxt *ctxt, | 1422 | static int emulate_push_sreg(struct x86_emulate_ctxt *ctxt, |
1421 | struct x86_emulate_ops *ops, int seg) | 1423 | struct x86_emulate_ops *ops, int seg) |
1422 | { | 1424 | { |
1423 | struct decode_cache *c = &ctxt->decode; | 1425 | struct decode_cache *c = &ctxt->decode; |
1424 | 1426 | ||
1425 | c->src.val = ops->get_segment_selector(seg, ctxt->vcpu); | 1427 | c->src.val = ops->get_segment_selector(seg, ctxt->vcpu); |
1426 | 1428 | ||
1427 | emulate_push(ctxt, ops); | 1429 | return emulate_push(ctxt, ops); |
1428 | } | 1430 | } |
1429 | 1431 | ||
1430 | static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, | 1432 | static int emulate_pop_sreg(struct x86_emulate_ctxt *ctxt, |
@@ -1454,18 +1456,13 @@ static int emulate_pusha(struct x86_emulate_ctxt *ctxt, | |||
1454 | (reg == VCPU_REGS_RSP) ? | 1456 | (reg == VCPU_REGS_RSP) ? |
1455 | (c->src.val = old_esp) : (c->src.val = c->regs[reg]); | 1457 | (c->src.val = old_esp) : (c->src.val = c->regs[reg]); |
1456 | 1458 | ||
1457 | emulate_push(ctxt, ops); | 1459 | rc = emulate_push(ctxt, ops); |
1458 | |||
1459 | rc = writeback(ctxt, ops); | ||
1460 | if (rc != X86EMUL_CONTINUE) | 1460 | if (rc != X86EMUL_CONTINUE) |
1461 | return rc; | 1461 | return rc; |
1462 | 1462 | ||
1463 | ++reg; | 1463 | ++reg; |
1464 | } | 1464 | } |
1465 | 1465 | ||
1466 | /* Disable writeback. */ | ||
1467 | c->dst.type = OP_NONE; | ||
1468 | |||
1469 | return rc; | 1466 | return rc; |
1470 | } | 1467 | } |
1471 | 1468 | ||
@@ -1503,27 +1500,22 @@ int emulate_int_real(struct x86_emulate_ctxt *ctxt, | |||
1503 | 1500 | ||
1504 | /* TODO: Add limit checks */ | 1501 | /* TODO: Add limit checks */ |
1505 | c->src.val = ctxt->eflags; | 1502 | c->src.val = ctxt->eflags; |
1506 | emulate_push(ctxt, ops); | 1503 | rc = emulate_push(ctxt, ops); |
1507 | rc = writeback(ctxt, ops); | ||
1508 | if (rc != X86EMUL_CONTINUE) | 1504 | if (rc != X86EMUL_CONTINUE) |
1509 | return rc; | 1505 | return rc; |
1510 | 1506 | ||
1511 | ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC); | 1507 | ctxt->eflags &= ~(EFLG_IF | EFLG_TF | EFLG_AC); |
1512 | 1508 | ||
1513 | c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu); | 1509 | c->src.val = ops->get_segment_selector(VCPU_SREG_CS, ctxt->vcpu); |
1514 | emulate_push(ctxt, ops); | 1510 | rc = emulate_push(ctxt, ops); |
1515 | rc = writeback(ctxt, ops); | ||
1516 | if (rc != X86EMUL_CONTINUE) | 1511 | if (rc != X86EMUL_CONTINUE) |
1517 | return rc; | 1512 | return rc; |
1518 | 1513 | ||
1519 | c->src.val = c->eip; | 1514 | c->src.val = c->eip; |
1520 | emulate_push(ctxt, ops); | 1515 | rc = emulate_push(ctxt, ops); |
1521 | rc = writeback(ctxt, ops); | ||
1522 | if (rc != X86EMUL_CONTINUE) | 1516 | if (rc != X86EMUL_CONTINUE) |
1523 | return rc; | 1517 | return rc; |
1524 | 1518 | ||
1525 | c->dst.type = OP_NONE; | ||
1526 | |||
1527 | ops->get_idt(&dt, ctxt->vcpu); | 1519 | ops->get_idt(&dt, ctxt->vcpu); |
1528 | 1520 | ||
1529 | eip_addr = dt.address + (irq << 2); | 1521 | eip_addr = dt.address + (irq << 2); |
@@ -1713,6 +1705,7 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, | |||
1713 | struct x86_emulate_ops *ops) | 1705 | struct x86_emulate_ops *ops) |
1714 | { | 1706 | { |
1715 | struct decode_cache *c = &ctxt->decode; | 1707 | struct decode_cache *c = &ctxt->decode; |
1708 | int rc = X86EMUL_CONTINUE; | ||
1716 | 1709 | ||
1717 | switch (c->modrm_reg) { | 1710 | switch (c->modrm_reg) { |
1718 | case 0: /* inc */ | 1711 | case 0: /* inc */ |
@@ -1726,17 +1719,17 @@ static inline int emulate_grp45(struct x86_emulate_ctxt *ctxt, | |||
1726 | old_eip = c->eip; | 1719 | old_eip = c->eip; |
1727 | c->eip = c->src.val; | 1720 | c->eip = c->src.val; |
1728 | c->src.val = old_eip; | 1721 | c->src.val = old_eip; |
1729 | emulate_push(ctxt, ops); | 1722 | rc = emulate_push(ctxt, ops); |
1730 | break; | 1723 | break; |
1731 | } | 1724 | } |
1732 | case 4: /* jmp abs */ | 1725 | case 4: /* jmp abs */ |
1733 | c->eip = c->src.val; | 1726 | c->eip = c->src.val; |
1734 | break; | 1727 | break; |
1735 | case 6: /* push */ | 1728 | case 6: /* push */ |
1736 | emulate_push(ctxt, ops); | 1729 | rc = emulate_push(ctxt, ops); |
1737 | break; | 1730 | break; |
1738 | } | 1731 | } |
1739 | return X86EMUL_CONTINUE; | 1732 | return rc; |
1740 | } | 1733 | } |
1741 | 1734 | ||
1742 | static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt, | 1735 | static inline int emulate_grp9(struct x86_emulate_ctxt *ctxt, |
@@ -2380,7 +2373,7 @@ static int emulator_do_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2380 | c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; | 2373 | c->op_bytes = c->ad_bytes = (next_tss_desc.type & 8) ? 4 : 2; |
2381 | c->lock_prefix = 0; | 2374 | c->lock_prefix = 0; |
2382 | c->src.val = (unsigned long) error_code; | 2375 | c->src.val = (unsigned long) error_code; |
2383 | emulate_push(ctxt, ops); | 2376 | ret = emulate_push(ctxt, ops); |
2384 | } | 2377 | } |
2385 | 2378 | ||
2386 | return ret; | 2379 | return ret; |
@@ -2400,11 +2393,8 @@ int emulator_task_switch(struct x86_emulate_ctxt *ctxt, | |||
2400 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, | 2393 | rc = emulator_do_task_switch(ctxt, ops, tss_selector, reason, |
2401 | has_error_code, error_code); | 2394 | has_error_code, error_code); |
2402 | 2395 | ||
2403 | if (rc == X86EMUL_CONTINUE) { | 2396 | if (rc == X86EMUL_CONTINUE) |
2404 | rc = writeback(ctxt, ops); | 2397 | ctxt->eip = c->eip; |
2405 | if (rc == X86EMUL_CONTINUE) | ||
2406 | ctxt->eip = c->eip; | ||
2407 | } | ||
2408 | 2398 | ||
2409 | return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; | 2399 | return (rc == X86EMUL_UNHANDLEABLE) ? EMULATION_FAILED : EMULATION_OK; |
2410 | } | 2400 | } |
@@ -2422,8 +2412,7 @@ static void string_addr_inc(struct x86_emulate_ctxt *ctxt, unsigned seg, | |||
2422 | 2412 | ||
2423 | static int em_push(struct x86_emulate_ctxt *ctxt) | 2413 | static int em_push(struct x86_emulate_ctxt *ctxt) |
2424 | { | 2414 | { |
2425 | emulate_push(ctxt, ctxt->ops); | 2415 | return emulate_push(ctxt, ctxt->ops); |
2426 | return X86EMUL_CONTINUE; | ||
2427 | } | 2416 | } |
2428 | 2417 | ||
2429 | static int em_das(struct x86_emulate_ctxt *ctxt) | 2418 | static int em_das(struct x86_emulate_ctxt *ctxt) |
@@ -2483,20 +2472,12 @@ static int em_call_far(struct x86_emulate_ctxt *ctxt) | |||
2483 | memcpy(&c->eip, c->src.valptr, c->op_bytes); | 2472 | memcpy(&c->eip, c->src.valptr, c->op_bytes); |
2484 | 2473 | ||
2485 | c->src.val = old_cs; | 2474 | c->src.val = old_cs; |
2486 | emulate_push(ctxt, ctxt->ops); | 2475 | rc = emulate_push(ctxt, ctxt->ops); |
2487 | rc = writeback(ctxt, ctxt->ops); | ||
2488 | if (rc != X86EMUL_CONTINUE) | 2476 | if (rc != X86EMUL_CONTINUE) |
2489 | return rc; | 2477 | return rc; |
2490 | 2478 | ||
2491 | c->src.val = old_eip; | 2479 | c->src.val = old_eip; |
2492 | emulate_push(ctxt, ctxt->ops); | 2480 | return emulate_push(ctxt, ctxt->ops); |
2493 | rc = writeback(ctxt, ctxt->ops); | ||
2494 | if (rc != X86EMUL_CONTINUE) | ||
2495 | return rc; | ||
2496 | |||
2497 | c->dst.type = OP_NONE; | ||
2498 | |||
2499 | return X86EMUL_CONTINUE; | ||
2500 | } | 2481 | } |
2501 | 2482 | ||
2502 | static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) | 2483 | static int em_ret_near_imm(struct x86_emulate_ctxt *ctxt) |
@@ -3625,7 +3606,7 @@ special_insn: | |||
3625 | emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); | 3606 | emulate_2op_SrcV("add", c->src, c->dst, ctxt->eflags); |
3626 | break; | 3607 | break; |
3627 | case 0x06: /* push es */ | 3608 | case 0x06: /* push es */ |
3628 | emulate_push_sreg(ctxt, ops, VCPU_SREG_ES); | 3609 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_ES); |
3629 | break; | 3610 | break; |
3630 | case 0x07: /* pop es */ | 3611 | case 0x07: /* pop es */ |
3631 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES); | 3612 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_ES); |
@@ -3635,14 +3616,14 @@ special_insn: | |||
3635 | emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); | 3616 | emulate_2op_SrcV("or", c->src, c->dst, ctxt->eflags); |
3636 | break; | 3617 | break; |
3637 | case 0x0e: /* push cs */ | 3618 | case 0x0e: /* push cs */ |
3638 | emulate_push_sreg(ctxt, ops, VCPU_SREG_CS); | 3619 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_CS); |
3639 | break; | 3620 | break; |
3640 | case 0x10 ... 0x15: | 3621 | case 0x10 ... 0x15: |
3641 | adc: /* adc */ | 3622 | adc: /* adc */ |
3642 | emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags); | 3623 | emulate_2op_SrcV("adc", c->src, c->dst, ctxt->eflags); |
3643 | break; | 3624 | break; |
3644 | case 0x16: /* push ss */ | 3625 | case 0x16: /* push ss */ |
3645 | emulate_push_sreg(ctxt, ops, VCPU_SREG_SS); | 3626 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_SS); |
3646 | break; | 3627 | break; |
3647 | case 0x17: /* pop ss */ | 3628 | case 0x17: /* pop ss */ |
3648 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS); | 3629 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_SS); |
@@ -3652,7 +3633,7 @@ special_insn: | |||
3652 | emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags); | 3633 | emulate_2op_SrcV("sbb", c->src, c->dst, ctxt->eflags); |
3653 | break; | 3634 | break; |
3654 | case 0x1e: /* push ds */ | 3635 | case 0x1e: /* push ds */ |
3655 | emulate_push_sreg(ctxt, ops, VCPU_SREG_DS); | 3636 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_DS); |
3656 | break; | 3637 | break; |
3657 | case 0x1f: /* pop ds */ | 3638 | case 0x1f: /* pop ds */ |
3658 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS); | 3639 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_DS); |
@@ -3789,7 +3770,7 @@ special_insn: | |||
3789 | break; | 3770 | break; |
3790 | case 0x9c: /* pushf */ | 3771 | case 0x9c: /* pushf */ |
3791 | c->src.val = (unsigned long) ctxt->eflags; | 3772 | c->src.val = (unsigned long) ctxt->eflags; |
3792 | emulate_push(ctxt, ops); | 3773 | rc = emulate_push(ctxt, ops); |
3793 | break; | 3774 | break; |
3794 | case 0x9d: /* popf */ | 3775 | case 0x9d: /* popf */ |
3795 | c->dst.type = OP_REG; | 3776 | c->dst.type = OP_REG; |
@@ -3864,7 +3845,7 @@ special_insn: | |||
3864 | long int rel = c->src.val; | 3845 | long int rel = c->src.val; |
3865 | c->src.val = (unsigned long) c->eip; | 3846 | c->src.val = (unsigned long) c->eip; |
3866 | jmp_rel(c, rel); | 3847 | jmp_rel(c, rel); |
3867 | emulate_push(ctxt, ops); | 3848 | rc = emulate_push(ctxt, ops); |
3868 | break; | 3849 | break; |
3869 | } | 3850 | } |
3870 | case 0xe9: /* jmp rel */ | 3851 | case 0xe9: /* jmp rel */ |
@@ -4157,7 +4138,7 @@ twobyte_insn: | |||
4157 | c->dst.val = test_cc(c->b, ctxt->eflags); | 4138 | c->dst.val = test_cc(c->b, ctxt->eflags); |
4158 | break; | 4139 | break; |
4159 | case 0xa0: /* push fs */ | 4140 | case 0xa0: /* push fs */ |
4160 | emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); | 4141 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_FS); |
4161 | break; | 4142 | break; |
4162 | case 0xa1: /* pop fs */ | 4143 | case 0xa1: /* pop fs */ |
4163 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS); | 4144 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_FS); |
@@ -4174,7 +4155,7 @@ twobyte_insn: | |||
4174 | emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags); | 4155 | emulate_2op_cl("shld", c->src2, c->src, c->dst, ctxt->eflags); |
4175 | break; | 4156 | break; |
4176 | case 0xa8: /* push gs */ | 4157 | case 0xa8: /* push gs */ |
4177 | emulate_push_sreg(ctxt, ops, VCPU_SREG_GS); | 4158 | rc = emulate_push_sreg(ctxt, ops, VCPU_SREG_GS); |
4178 | break; | 4159 | break; |
4179 | case 0xa9: /* pop gs */ | 4160 | case 0xa9: /* pop gs */ |
4180 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS); | 4161 | rc = emulate_pop_sreg(ctxt, ops, VCPU_SREG_GS); |