diff options
author | David Hildenbrand <dahi@linux.vnet.ibm.com> | 2014-01-23 04:47:13 -0500 |
---|---|---|
committer | Christian Borntraeger <borntraeger@de.ibm.com> | 2014-04-22 07:24:50 -0400 |
commit | aba0750889d012f84a719112997abb7be11bba4b (patch) | |
tree | adf0c6d527dfb844ddfd03a0a460a3c8806e5223 /arch | |
parent | 8712836b30cef5d49bc3bb8bc3da88a40e11e574 (diff) |
KVM: s390: emulate stctl and stctg
Introduce the methods to emulate the stctl and stctg instruction. Added tracing
code.
Signed-off-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/include/asm/kvm_host.h | 2 | ||||
-rw-r--r-- | arch/s390/kvm/intercept.c | 1 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.c | 2 | ||||
-rw-r--r-- | arch/s390/kvm/kvm-s390.h | 1 | ||||
-rw-r--r-- | arch/s390/kvm/priv.c | 73 | ||||
-rw-r--r-- | arch/s390/kvm/trace.h | 25 |
6 files changed, 104 insertions, 0 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h index 5e5a14db8c21..5d9648925a8e 100644 --- a/arch/s390/include/asm/kvm_host.h +++ b/arch/s390/include/asm/kvm_host.h | |||
@@ -175,6 +175,8 @@ struct kvm_vcpu_stat { | |||
175 | u32 exit_instruction; | 175 | u32 exit_instruction; |
176 | u32 instruction_lctl; | 176 | u32 instruction_lctl; |
177 | u32 instruction_lctlg; | 177 | u32 instruction_lctlg; |
178 | u32 instruction_stctl; | ||
179 | u32 instruction_stctg; | ||
178 | u32 exit_program_interruption; | 180 | u32 exit_program_interruption; |
179 | u32 exit_instr_and_program; | 181 | u32 exit_instr_and_program; |
180 | u32 deliver_external_call; | 182 | u32 deliver_external_call; |
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c index 4c3311e41727..c0e6b49191ba 100644 --- a/arch/s390/kvm/intercept.c +++ b/arch/s390/kvm/intercept.c | |||
@@ -29,6 +29,7 @@ static const intercept_handler_t instruction_handlers[256] = { | |||
29 | [0x83] = kvm_s390_handle_diag, | 29 | [0x83] = kvm_s390_handle_diag, |
30 | [0xae] = kvm_s390_handle_sigp, | 30 | [0xae] = kvm_s390_handle_sigp, |
31 | [0xb2] = kvm_s390_handle_b2, | 31 | [0xb2] = kvm_s390_handle_b2, |
32 | [0xb6] = kvm_s390_handle_stctl, | ||
32 | [0xb7] = kvm_s390_handle_lctl, | 33 | [0xb7] = kvm_s390_handle_lctl, |
33 | [0xb9] = kvm_s390_handle_b9, | 34 | [0xb9] = kvm_s390_handle_b9, |
34 | [0xe5] = kvm_s390_handle_e5, | 35 | [0xe5] = kvm_s390_handle_e5, |
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index ae7c1265fcc1..7ae8c26065fb 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c | |||
@@ -52,6 +52,8 @@ struct kvm_stats_debugfs_item debugfs_entries[] = { | |||
52 | { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, | 52 | { "exit_instr_and_program_int", VCPU_STAT(exit_instr_and_program) }, |
53 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, | 53 | { "instruction_lctlg", VCPU_STAT(instruction_lctlg) }, |
54 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, | 54 | { "instruction_lctl", VCPU_STAT(instruction_lctl) }, |
55 | { "instruction_stctl", VCPU_STAT(instruction_stctl) }, | ||
56 | { "instruction_stctg", VCPU_STAT(instruction_stctg) }, | ||
55 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, | 57 | { "deliver_emergency_signal", VCPU_STAT(deliver_emergency_signal) }, |
56 | { "deliver_external_call", VCPU_STAT(deliver_external_call) }, | 58 | { "deliver_external_call", VCPU_STAT(deliver_external_call) }, |
57 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, | 59 | { "deliver_service_signal", VCPU_STAT(deliver_service_signal) }, |
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h index dc506f3782ea..5f00fc1e9785 100644 --- a/arch/s390/kvm/kvm-s390.h +++ b/arch/s390/kvm/kvm-s390.h | |||
@@ -147,6 +147,7 @@ int kvm_s390_handle_e5(struct kvm_vcpu *vcpu); | |||
147 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); | 147 | int kvm_s390_handle_01(struct kvm_vcpu *vcpu); |
148 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); | 148 | int kvm_s390_handle_b9(struct kvm_vcpu *vcpu); |
149 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); | 149 | int kvm_s390_handle_lpsw(struct kvm_vcpu *vcpu); |
150 | int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu); | ||
150 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu); | 151 | int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu); |
151 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu); | 152 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu); |
152 | 153 | ||
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c index 5fb503a6c443..27f9051a78f8 100644 --- a/arch/s390/kvm/priv.c +++ b/arch/s390/kvm/priv.c | |||
@@ -789,6 +789,42 @@ int kvm_s390_handle_lctl(struct kvm_vcpu *vcpu) | |||
789 | return 0; | 789 | return 0; |
790 | } | 790 | } |
791 | 791 | ||
792 | int kvm_s390_handle_stctl(struct kvm_vcpu *vcpu) | ||
793 | { | ||
794 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
795 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
796 | u64 ga; | ||
797 | u32 val; | ||
798 | int reg, rc; | ||
799 | |||
800 | vcpu->stat.instruction_stctl++; | ||
801 | |||
802 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
803 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
804 | |||
805 | ga = kvm_s390_get_base_disp_rs(vcpu); | ||
806 | |||
807 | if (ga & 3) | ||
808 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
809 | |||
810 | VCPU_EVENT(vcpu, 5, "stctl r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); | ||
811 | trace_kvm_s390_handle_stctl(vcpu, 0, reg1, reg3, ga); | ||
812 | |||
813 | reg = reg1; | ||
814 | do { | ||
815 | val = vcpu->arch.sie_block->gcr[reg] & 0x00000000fffffffful; | ||
816 | rc = write_guest(vcpu, ga, &val, sizeof(val)); | ||
817 | if (rc) | ||
818 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
819 | ga += 4; | ||
820 | if (reg == reg3) | ||
821 | break; | ||
822 | reg = (reg + 1) % 16; | ||
823 | } while (1); | ||
824 | |||
825 | return 0; | ||
826 | } | ||
827 | |||
792 | static int handle_lctlg(struct kvm_vcpu *vcpu) | 828 | static int handle_lctlg(struct kvm_vcpu *vcpu) |
793 | { | 829 | { |
794 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | 830 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; |
@@ -825,8 +861,45 @@ static int handle_lctlg(struct kvm_vcpu *vcpu) | |||
825 | return 0; | 861 | return 0; |
826 | } | 862 | } |
827 | 863 | ||
864 | static int handle_stctg(struct kvm_vcpu *vcpu) | ||
865 | { | ||
866 | int reg1 = (vcpu->arch.sie_block->ipa & 0x00f0) >> 4; | ||
867 | int reg3 = vcpu->arch.sie_block->ipa & 0x000f; | ||
868 | u64 ga, val; | ||
869 | int reg, rc; | ||
870 | |||
871 | vcpu->stat.instruction_stctg++; | ||
872 | |||
873 | if (vcpu->arch.sie_block->gpsw.mask & PSW_MASK_PSTATE) | ||
874 | return kvm_s390_inject_program_int(vcpu, PGM_PRIVILEGED_OP); | ||
875 | |||
876 | ga = kvm_s390_get_base_disp_rsy(vcpu); | ||
877 | |||
878 | if (ga & 7) | ||
879 | return kvm_s390_inject_program_int(vcpu, PGM_SPECIFICATION); | ||
880 | |||
881 | reg = reg1; | ||
882 | |||
883 | VCPU_EVENT(vcpu, 5, "stctg r1:%x, r3:%x, addr:%llx", reg1, reg3, ga); | ||
884 | trace_kvm_s390_handle_stctl(vcpu, 1, reg1, reg3, ga); | ||
885 | |||
886 | do { | ||
887 | val = vcpu->arch.sie_block->gcr[reg]; | ||
888 | rc = write_guest(vcpu, ga, &val, sizeof(val)); | ||
889 | if (rc) | ||
890 | return kvm_s390_inject_prog_cond(vcpu, rc); | ||
891 | ga += 8; | ||
892 | if (reg == reg3) | ||
893 | break; | ||
894 | reg = (reg + 1) % 16; | ||
895 | } while (1); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
828 | static const intercept_handler_t eb_handlers[256] = { | 900 | static const intercept_handler_t eb_handlers[256] = { |
829 | [0x2f] = handle_lctlg, | 901 | [0x2f] = handle_lctlg, |
902 | [0x25] = handle_stctg, | ||
830 | }; | 903 | }; |
831 | 904 | ||
832 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) | 905 | int kvm_s390_handle_eb(struct kvm_vcpu *vcpu) |
diff --git a/arch/s390/kvm/trace.h b/arch/s390/kvm/trace.h index a4bf7d78a0db..abf6ba52769e 100644 --- a/arch/s390/kvm/trace.h +++ b/arch/s390/kvm/trace.h | |||
@@ -315,6 +315,31 @@ TRACE_EVENT(kvm_s390_handle_lctl, | |||
315 | __entry->reg1, __entry->reg3, __entry->addr) | 315 | __entry->reg1, __entry->reg3, __entry->addr) |
316 | ); | 316 | ); |
317 | 317 | ||
318 | TRACE_EVENT(kvm_s390_handle_stctl, | ||
319 | TP_PROTO(VCPU_PROTO_COMMON, int g, int reg1, int reg3, u64 addr), | ||
320 | TP_ARGS(VCPU_ARGS_COMMON, g, reg1, reg3, addr), | ||
321 | |||
322 | TP_STRUCT__entry( | ||
323 | VCPU_FIELD_COMMON | ||
324 | __field(int, g) | ||
325 | __field(int, reg1) | ||
326 | __field(int, reg3) | ||
327 | __field(u64, addr) | ||
328 | ), | ||
329 | |||
330 | TP_fast_assign( | ||
331 | VCPU_ASSIGN_COMMON | ||
332 | __entry->g = g; | ||
333 | __entry->reg1 = reg1; | ||
334 | __entry->reg3 = reg3; | ||
335 | __entry->addr = addr; | ||
336 | ), | ||
337 | |||
338 | VCPU_TP_PRINTK("%s: storing cr %x-%x to %016llx", | ||
339 | __entry->g ? "stctg" : "stctl", | ||
340 | __entry->reg1, __entry->reg3, __entry->addr) | ||
341 | ); | ||
342 | |||
318 | TRACE_EVENT(kvm_s390_handle_prefix, | 343 | TRACE_EVENT(kvm_s390_handle_prefix, |
319 | TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address), | 344 | TP_PROTO(VCPU_PROTO_COMMON, int set, u32 address), |
320 | TP_ARGS(VCPU_ARGS_COMMON, set, address), | 345 | TP_ARGS(VCPU_ARGS_COMMON, set, address), |