]>
Commit | Line | Data |
---|---|---|
3d672205 TH |
1 | /* |
2 | * S390x DIAG instruction helper functions | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | */ | |
14 | ||
15 | #include "qemu/osdep.h" | |
16 | #include "cpu.h" | |
b6b47223 | 17 | #include "s390x-internal.h" |
3d672205 TH |
18 | #include "hw/watchdog/wdt_diag288.h" |
19 | #include "sysemu/cpus.h" | |
20 | #include "hw/s390x/ipl.h" | |
19c69829 | 21 | #include "hw/s390x/s390-virtio-ccw.h" |
1fc66ac1 | 22 | #include "sysemu/kvm.h" |
67043607 | 23 | #include "kvm/kvm_s390x.h" |
f5f9c6ea | 24 | #include "target/s390x/kvm/pv.h" |
cc37d98b RH |
25 | #include "qemu/error-report.h" |
26 | ||
3d672205 | 27 | |
3d672205 TH |
28 | int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3) |
29 | { | |
30 | uint64_t func = env->regs[r1]; | |
31 | uint64_t timeout = env->regs[r1 + 1]; | |
32 | uint64_t action = env->regs[r3]; | |
33 | Object *obj; | |
34 | DIAG288State *diag288; | |
35 | DIAG288Class *diag288_class; | |
36 | ||
37 | if (r1 % 2 || action != 0) { | |
38 | return -1; | |
39 | } | |
40 | ||
41 | /* Timeout must be more than 15 seconds except for timer deletion */ | |
42 | if (func != WDT_DIAG288_CANCEL && timeout < 15) { | |
43 | return -1; | |
44 | } | |
45 | ||
46 | obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL); | |
47 | if (!obj) { | |
48 | return -1; | |
49 | } | |
50 | ||
51 | diag288 = DIAG288(obj); | |
52 | diag288_class = DIAG288_GET_CLASS(diag288); | |
53 | return diag288_class->handle_timer(diag288, func, timeout); | |
54 | } | |
55 | ||
0b7fd817 JF |
56 | static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr, |
57 | uintptr_t ra, bool write) | |
58 | { | |
c3347ed0 JF |
59 | /* Handled by the Ultravisor */ |
60 | if (s390_is_pv()) { | |
61 | return 0; | |
62 | } | |
0b7fd817 JF |
63 | if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) { |
64 | s390_program_interrupt(env, PGM_SPECIFICATION, ra); | |
65 | return -1; | |
66 | } | |
67 | if (!address_space_access_valid(&address_space_memory, addr, | |
68 | sizeof(IplParameterBlock), write, | |
69 | MEMTXATTRS_UNSPECIFIED)) { | |
70 | s390_program_interrupt(env, PGM_ADDRESSING, ra); | |
71 | return -1; | |
72 | } | |
73 | return 0; | |
74 | } | |
75 | ||
968db419 | 76 | void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra) |
3d672205 | 77 | { |
c3347ed0 | 78 | bool valid; |
dc79e928 | 79 | CPUState *cs = env_cpu(env); |
9c61e112 | 80 | S390CPU *cpu = S390_CPU(cs); |
3d672205 TH |
81 | uint64_t addr = env->regs[r1]; |
82 | uint64_t subcode = env->regs[r3]; | |
83 | IplParameterBlock *iplb; | |
84 | ||
85 | if (env->psw.mask & PSW_MASK_PSTATE) { | |
77b703f8 | 86 | s390_program_interrupt(env, PGM_PRIVILEGED, ra); |
3d672205 TH |
87 | return; |
88 | } | |
89 | ||
0b7fd817 | 90 | if (subcode & ~0x0ffffULL) { |
77b703f8 | 91 | s390_program_interrupt(env, PGM_SPECIFICATION, ra); |
3d672205 TH |
92 | return; |
93 | } | |
94 | ||
c3347ed0 JF |
95 | if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) { |
96 | s390_program_interrupt(env, PGM_SPECIFICATION, ra); | |
97 | return; | |
98 | } | |
99 | ||
3d672205 | 100 | switch (subcode) { |
0b7fd817 | 101 | case DIAG308_RESET_MOD_CLR: |
a30fb811 | 102 | s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR); |
3d672205 | 103 | break; |
0b7fd817 | 104 | case DIAG308_RESET_LOAD_NORM: |
a30fb811 | 105 | s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL); |
3d672205 | 106 | break; |
0b7fd817 JF |
107 | case DIAG308_LOAD_CLEAR: |
108 | /* Well we still lack the clearing bit... */ | |
a30fb811 | 109 | s390_ipl_reset_request(cs, S390_RESET_REIPL); |
3d672205 | 110 | break; |
0b7fd817 | 111 | case DIAG308_SET: |
c3347ed0 | 112 | case DIAG308_PV_SET: |
0b7fd817 | 113 | if (diag308_parm_check(env, r1, addr, ra, false)) { |
3d672205 TH |
114 | return; |
115 | } | |
96f64aa8 | 116 | iplb = g_new0(IplParameterBlock, 1); |
9c61e112 JF |
117 | if (!s390_is_pv()) { |
118 | cpu_physical_memory_read(addr, iplb, sizeof(iplb->len)); | |
119 | } else { | |
120 | s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len)); | |
121 | } | |
122 | ||
3d672205 TH |
123 | if (!iplb_valid_len(iplb)) { |
124 | env->regs[r1 + 1] = DIAG_308_RC_INVALID; | |
125 | goto out; | |
126 | } | |
127 | ||
9c61e112 JF |
128 | if (!s390_is_pv()) { |
129 | cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len)); | |
130 | } else { | |
131 | s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len)); | |
132 | } | |
3d672205 | 133 | |
c3347ed0 JF |
134 | valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb); |
135 | if (!valid) { | |
3d672205 TH |
136 | env->regs[r1 + 1] = DIAG_308_RC_INVALID; |
137 | goto out; | |
138 | } | |
139 | ||
140 | s390_ipl_update_diag308(iplb); | |
141 | env->regs[r1 + 1] = DIAG_308_RC_OK; | |
142 | out: | |
143 | g_free(iplb); | |
144 | return; | |
0b7fd817 | 145 | case DIAG308_STORE: |
c3347ed0 | 146 | case DIAG308_PV_STORE: |
0b7fd817 | 147 | if (diag308_parm_check(env, r1, addr, ra, true)) { |
3d672205 TH |
148 | return; |
149 | } | |
c3347ed0 JF |
150 | if (subcode == DIAG308_PV_STORE) { |
151 | iplb = s390_ipl_get_iplb_pv(); | |
152 | } else { | |
153 | iplb = s390_ipl_get_iplb(); | |
154 | } | |
9c61e112 JF |
155 | if (!iplb) { |
156 | env->regs[r1 + 1] = DIAG_308_RC_NO_CONF; | |
157 | return; | |
158 | } | |
159 | ||
160 | if (!s390_is_pv()) { | |
3d672205 | 161 | cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len)); |
3d672205 | 162 | } else { |
9c61e112 | 163 | s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len)); |
3d672205 | 164 | } |
9c61e112 | 165 | env->regs[r1 + 1] = DIAG_308_RC_OK; |
3d672205 | 166 | return; |
c3347ed0 JF |
167 | case DIAG308_PV_START: |
168 | iplb = s390_ipl_get_iplb_pv(); | |
169 | if (!iplb) { | |
170 | env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF; | |
171 | return; | |
172 | } | |
173 | ||
1fc66ac1 | 174 | if (kvm_enabled() && kvm_s390_get_hpage_1m()) { |
c3347ed0 JF |
175 | error_report("Protected VMs can currently not be backed with " |
176 | "huge pages"); | |
177 | env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV; | |
178 | return; | |
179 | } | |
180 | ||
181 | s390_ipl_reset_request(cs, S390_RESET_PV); | |
182 | break; | |
3d672205 | 183 | default: |
77b703f8 | 184 | s390_program_interrupt(env, PGM_SPECIFICATION, ra); |
3d672205 TH |
185 | break; |
186 | } | |
187 | } |