1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include "qemu/osdep.h"
16#include "cpu.h"
17#include "s390x-internal.h"
18#include "hw/watchdog/wdt_diag288.h"
19#include "sysemu/cpus.h"
20#include "hw/s390x/ipl.h"
21#include "hw/s390x/s390-virtio-ccw.h"
22#include "hw/s390x/pv.h"
23#include "sysemu/kvm.h"
24#include "kvm/kvm_s390x.h"
25
26int handle_diag_288(CPUS390XState *env, uint64_t r1, uint64_t r3)
27{
28 uint64_t func = env->regs[r1];
29 uint64_t timeout = env->regs[r1 + 1];
30 uint64_t action = env->regs[r3];
31 Object *obj;
32 DIAG288State *diag288;
33 DIAG288Class *diag288_class;
34
35 if (r1 % 2 || action != 0) {
36 return -1;
37 }
38
39
40 if (func != WDT_DIAG288_CANCEL && timeout < 15) {
41 return -1;
42 }
43
44 obj = object_resolve_path_type("", TYPE_WDT_DIAG288, NULL);
45 if (!obj) {
46 return -1;
47 }
48
49 diag288 = DIAG288(obj);
50 diag288_class = DIAG288_GET_CLASS(diag288);
51 return diag288_class->handle_timer(diag288, func, timeout);
52}
53
54static int diag308_parm_check(CPUS390XState *env, uint64_t r1, uint64_t addr,
55 uintptr_t ra, bool write)
56{
57
58 if (s390_is_pv()) {
59 return 0;
60 }
61 if ((r1 & 1) || (addr & ~TARGET_PAGE_MASK)) {
62 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
63 return -1;
64 }
65 if (!address_space_access_valid(&address_space_memory, addr,
66 sizeof(IplParameterBlock), write,
67 MEMTXATTRS_UNSPECIFIED)) {
68 s390_program_interrupt(env, PGM_ADDRESSING, ra);
69 return -1;
70 }
71 return 0;
72}
73
74void handle_diag_308(CPUS390XState *env, uint64_t r1, uint64_t r3, uintptr_t ra)
75{
76 bool valid;
77 CPUState *cs = env_cpu(env);
78 S390CPU *cpu = S390_CPU(cs);
79 uint64_t addr = env->regs[r1];
80 uint64_t subcode = env->regs[r3];
81 IplParameterBlock *iplb;
82
83 if (env->psw.mask & PSW_MASK_PSTATE) {
84 s390_program_interrupt(env, PGM_PRIVILEGED, ra);
85 return;
86 }
87
88 if (subcode & ~0x0ffffULL) {
89 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
90 return;
91 }
92
93 if (subcode >= DIAG308_PV_SET && !s390_has_feat(S390_FEAT_UNPACK)) {
94 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
95 return;
96 }
97
98 switch (subcode) {
99 case DIAG308_RESET_MOD_CLR:
100 s390_ipl_reset_request(cs, S390_RESET_MODIFIED_CLEAR);
101 break;
102 case DIAG308_RESET_LOAD_NORM:
103 s390_ipl_reset_request(cs, S390_RESET_LOAD_NORMAL);
104 break;
105 case DIAG308_LOAD_CLEAR:
106
107 s390_ipl_reset_request(cs, S390_RESET_REIPL);
108 break;
109 case DIAG308_SET:
110 case DIAG308_PV_SET:
111 if (diag308_parm_check(env, r1, addr, ra, false)) {
112 return;
113 }
114 iplb = g_new0(IplParameterBlock, 1);
115 if (!s390_is_pv()) {
116 cpu_physical_memory_read(addr, iplb, sizeof(iplb->len));
117 } else {
118 s390_cpu_pv_mem_read(cpu, 0, iplb, sizeof(iplb->len));
119 }
120
121 if (!iplb_valid_len(iplb)) {
122 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
123 goto out;
124 }
125
126 if (!s390_is_pv()) {
127 cpu_physical_memory_read(addr, iplb, be32_to_cpu(iplb->len));
128 } else {
129 s390_cpu_pv_mem_read(cpu, 0, iplb, be32_to_cpu(iplb->len));
130 }
131
132 valid = subcode == DIAG308_PV_SET ? iplb_valid_pv(iplb) : iplb_valid(iplb);
133 if (!valid) {
134 env->regs[r1 + 1] = DIAG_308_RC_INVALID;
135 goto out;
136 }
137
138 s390_ipl_update_diag308(iplb);
139 env->regs[r1 + 1] = DIAG_308_RC_OK;
140out:
141 g_free(iplb);
142 return;
143 case DIAG308_STORE:
144 case DIAG308_PV_STORE:
145 if (diag308_parm_check(env, r1, addr, ra, true)) {
146 return;
147 }
148 if (subcode == DIAG308_PV_STORE) {
149 iplb = s390_ipl_get_iplb_pv();
150 } else {
151 iplb = s390_ipl_get_iplb();
152 }
153 if (!iplb) {
154 env->regs[r1 + 1] = DIAG_308_RC_NO_CONF;
155 return;
156 }
157
158 if (!s390_is_pv()) {
159 cpu_physical_memory_write(addr, iplb, be32_to_cpu(iplb->len));
160 } else {
161 s390_cpu_pv_mem_write(cpu, 0, iplb, be32_to_cpu(iplb->len));
162 }
163 env->regs[r1 + 1] = DIAG_308_RC_OK;
164 return;
165 case DIAG308_PV_START:
166 iplb = s390_ipl_get_iplb_pv();
167 if (!iplb) {
168 env->regs[r1 + 1] = DIAG_308_RC_NO_PV_CONF;
169 return;
170 }
171
172 if (kvm_enabled() && kvm_s390_get_hpage_1m()) {
173 error_report("Protected VMs can currently not be backed with "
174 "huge pages");
175 env->regs[r1 + 1] = DIAG_308_RC_INVAL_FOR_PV;
176 return;
177 }
178
179 s390_ipl_reset_request(cs, S390_RESET_PV);
180 break;
181 default:
182 s390_program_interrupt(env, PGM_SPECIFICATION, ra);
183 break;
184 }
185}
186