diff options
author | Thomas Huth <thuth@linux.vnet.ibm.com> | 2013-06-20 11:22:04 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2013-06-20 17:32:39 -0400 |
commit | 953ed88d10444c0e139a2333b6cd96ce01aa94dc (patch) | |
tree | 89579d65e96ce247b41ae2b2fe788250bb80a94c /arch/s390/kvm | |
parent | 133608f392ce2e11481317e3d0b02044710a5956 (diff) |
KVM: s390: Reworked LCTL and LCTLG instructions
LCTL and LCTLG are also privileged instructions, thus there is no need for
treating them separately from the other instructions in priv.c. So this
patch moves these two instructions to priv.c, adds a check for supervisor
state and simplifies the "handle_eb" instruction decoding by merging the
two eb_handlers jump tables from intercept.c and priv.c into one table only.
Signed-off-by: Thomas Huth <thuth@linux.vnet.ibm.com>
Acked-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/s390/kvm')
-rw-r--r-- | arch/s390/kvm/intercept.c | 85 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 3 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 78 |
3 files changed, 81 insertions, 85 deletions
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index f0b8be0cc08d..5ee56e5acc23 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -22,87 +22,6 @@ | |||
22 | #include "trace.h" | 22 | #include "trace.h" |
23 | #include "trace-s390.h" | 23 | #include "trace-s390.h" |
24 | 24 | ||
25 | static int handle_lctlg(struct kvm_vcpu *vcpu) | ||
26 | { | ||
27 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
28 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
29 | u64 useraddr; | ||
30 | int reg, rc; | ||
31 | |||
32 | vcpu->stat.instruction_lctlg++; | ||
33 | |||
34 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); | ||
35 | |||
36 | if (useraddr & 7) | ||
37 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
38 | |||
39 | reg = reg1; | ||
40 | |||
41 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
42 | useraddr); | ||
43 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); | ||
44 | |||
45 | do { | ||
46 | rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], | ||
47 | (u64 __user *) useraddr); | ||
48 | if (rc) | ||
49 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
50 | useraddr += 8; | ||
51 | if (reg == reg3) | ||
52 | break; | ||
53 | reg = (reg + 1) % 16; | ||
54 | } while (1); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int handle_lctl(struct kvm_vcpu *vcpu) | ||
59 | { | ||
60 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
61 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
62 | u64 useraddr; | ||
63 | u32 val = 0; | ||
64 | int reg, rc; | ||
65 | |||
66 | vcpu->stat.instruction_lctl++; | ||
67 | |||
68 | useraddr = kvm_s390_get_base_disp_rs(vcpu); | ||
69 | |||
70 | if (useraddr & 3) | ||
71 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
72 | |||
73 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
74 | useraddr); | ||
75 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); | ||
76 | |||
77 | reg = reg1; | ||
78 | do { | ||
79 | rc = get_guest(vcpu, val, (u32 __user *) useraddr); | ||
80 | if (rc) | ||
81 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
82 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
83 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
84 | useraddr += 4; | ||
85 | if (reg == reg3) | ||
86 | break; | ||
87 | reg = (reg + 1) % 16; | ||
88 | } while (1); | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static const intercept_handler_t eb_handlers[256] = { | ||
93 | [0x2f] = handle_lctlg, | ||
94 | [0x8a] = kvm_s390_handle_priv_eb, | ||
95 | }; | ||
96 | |||
97 | static int handle_eb(struct kvm_vcpu *vcpu) | ||
98 | { | ||
99 | intercept_handler_t handler; | ||
100 | |||
101 | handler = eb_handlers[vcpu->arch.sie_block->ipb & 0xff]; | ||
102 | if (handler) | ||
103 | return handler(vcpu); | ||
104 | return -EOPNOTSUPP; | ||
105 | } | ||
106 | 25 | ||
107 | static const intercept_handler_t instruction_handlers[256] = { | 26 | static const intercept_handler_t instruction_handlers[256] = { |
108 | [0x01] = kvm_s390_handle_01, | 27 | [0x01] = kvm_s390_handle_01, |
@@ -110,10 +29,10 @@ static const intercept_handler_t instruction_handlers[256] = { | |||
110 | [0x83] = kvm_s390_handle_diag, | 29 | [0x83] = kvm_s390_handle_diag, |
111 | [0xae] = kvm_s390_handle_sigp, | 30 | [0xae] = kvm_s390_handle_sigp, |
112 | [0xb2] = kvm_s390_handle_b2, | 31 | [0xb2] = kvm_s390_handle_b2, |
113 | [0xb7] = handle_lctl, | 32 | [0xb7] = kvm_s390_handle_lctl, |
114 | [0xb9] = kvm_s390_handle_b9, | 33 | [0xb9] = kvm_s390_handle_b9, |
115 | [0xe5] = kvm_s390_handle_e5, | 34 | [0xe5] = kvm_s390_handle_e5, |
116 | [0xeb] = handle_eb, | 35 | [0xeb] = kvm_s390_handle_eb, |
117 | }; | 36 | }; |
118 | 37 | ||
119 | static int handle_noop(struct kvm_vcpu *vcpu) | 38 | static int handle_noop(struct kvm_vcpu *vcpu) |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index 15795b8f8ff5..028ca9fd2158 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -132,7 +132,8 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | |||
132 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | 132 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); |
133 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); | 133 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); |
134 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); | 134 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); |
135 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu); | 135 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu); |
136 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu); | ||
136 | 137 | ||
137 | /* implemented in sigp.c */ | 138 | /* implemented in sigp.c */ |
138 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); | 139 | int kvm_s390_handle_sigp(struct kvm_vcpu *vcpu); |
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 4b8fb6cc3c45..c7603f5b4c28 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -590,11 +590,87 @@ int kvm_s390_handle_b9(struct kvm_vcpu *vcpu) | |||
590 | return -EOPNOTSUPP; | 590 | return -EOPNOTSUPP; |
591 | } | 591 | } |
592 | 592 | ||
593 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) | ||
594 | { | ||
595 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
596 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
597 | u64 useraddr; | ||
598 | u32 val = 0; | ||
599 | int reg, rc; | ||
600 | |||
601 | vcpu->stat.instruction_lctl++; | ||
602 | |||
603 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
604 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
605 | |||
606 | useraddr = kvm_s390_get_base_disp_rs(vcpu); | ||
607 | |||
608 | if (useraddr & 3) | ||
609 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
610 | |||
611 | VCPU_EVENT(vcpu, 5, "lctl r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
612 | useraddr); | ||
613 | trace_kvm_s390_handle_lctl(vcpu, 0, reg1, reg3, useraddr); | ||
614 | |||
615 | reg = reg1; | ||
616 | do { | ||
617 | rc = get_guest(vcpu, val, (u32 __user *) useraddr); | ||
618 | if (rc) | ||
619 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
620 | vcpu->arch.sie_block->gcr[reg] &= 0xffffffff00000000ul; | ||
621 | vcpu->arch.sie_block->gcr[reg] |= val; | ||
622 | useraddr += 4; | ||
623 | if (reg == reg3) | ||
624 | break; | ||
625 | reg = (reg + 1) % 16; | ||
626 | } while (1); | ||
627 | |||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static int handle_lctlg(struct kvm_vcpu *vcpu) | ||
632 | { | ||
633 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
634 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
635 | u64 useraddr; | ||
636 | int reg, rc; | ||
637 | |||
638 | vcpu->stat.instruction_lctlg++; | ||
639 | |||
640 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
641 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
642 | |||
643 | useraddr = kvm_s390_get_base_disp_rsy(vcpu); | ||
644 | |||
645 | if (useraddr & 7) | ||
646 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
647 | |||
648 | reg = reg1; | ||
649 | |||
650 | VCPU_EVENT(vcpu, 5, "lctlg r1:%x, r3:%x, addr:%llx", reg1, reg3, | ||
651 | useraddr); | ||
652 | trace_kvm_s390_handle_lctl(vcpu, 1, reg1, reg3, useraddr); | ||
653 | |||
654 | do { | ||
655 | rc = get_guest(vcpu, vcpu->arch.sie_block->gcr[reg], | ||
656 | (u64 __user *) useraddr); | ||
657 | if (rc) | ||
658 | return kvm_s390_inject_program_int(vcpu, PGM_ADDRESSING); | ||
659 | useraddr += 8; | ||
660 | if (reg == reg3) | ||
661 | break; | ||
662 | reg = (reg + 1) % 16; | ||
663 | } while (1); | ||
664 | |||
665 | return 0; | ||
666 | } | ||
667 | |||
593 | static const intercept_handler_t eb_handlers[256] = { | 668 | static const intercept_handler_t eb_handlers[256] = { |
669 | [0x2f] = handle_lctlg, | ||
594 | [0x8a] = handle_io_inst, | 670 | [0x8a] = handle_io_inst, |
595 | }; | 671 | }; |
596 | 672 | ||
597 | int kvm_s390_handle_priv_eb(struct kvm_vcpu *vcpu) | 673 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) |
598 | { | 674 | { |
599 | intercept_handler_t handler; | 675 | intercept_handler_t handler; |
600 | 676 | ||