]>
Commit | Line | Data |
---|---|---|
df75a4e2 FZ |
1 | /* |
2 | * s390 IPL device | |
3 | * | |
c3347ed0 | 4 | * Copyright 2015, 2020 IBM Corp. |
df75a4e2 | 5 | * Author(s): Zhang Fan <[email protected]> |
c3347ed0 | 6 | * Janosch Frank <[email protected]> |
df75a4e2 FZ |
7 | * |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or (at | |
9 | * your option) any later version. See the COPYING file in the top-level | |
10 | * directory. | |
11 | */ | |
12 | ||
13 | #ifndef HW_S390_IPL_H | |
14 | #define HW_S390_IPL_H | |
15 | ||
db3b2566 | 16 | #include "cpu.h" |
fbc1384c | 17 | #include "exec/address-spaces.h" |
a27bd6c7 | 18 | #include "hw/qdev-core.h" |
db3b2566 | 19 | |
c3347ed0 JF |
20 | struct IPLBlockPVComp { |
21 | uint64_t tweak_pref; | |
22 | uint64_t addr; | |
23 | uint64_t size; | |
24 | } QEMU_PACKED; | |
25 | typedef struct IPLBlockPVComp IPLBlockPVComp; | |
26 | ||
27 | struct IPLBlockPV { | |
28 | uint8_t reserved18[87]; /* 0x18 */ | |
29 | uint8_t version; /* 0x6f */ | |
30 | uint32_t reserved70; /* 0x70 */ | |
31 | uint32_t num_comp; /* 0x74 */ | |
32 | uint64_t pv_header_addr; /* 0x78 */ | |
33 | uint64_t pv_header_len; /* 0x80 */ | |
34 | struct IPLBlockPVComp components[]; | |
35 | } QEMU_PACKED; | |
36 | typedef struct IPLBlockPV IPLBlockPV; | |
37 | ||
04ca4b92 | 38 | struct IplBlockCcw { |
118ee80f | 39 | uint8_t reserved0[85]; |
3041e3be | 40 | uint8_t ssid; |
04ca4b92 AY |
41 | uint16_t devno; |
42 | uint8_t vm_flags; | |
43 | uint8_t reserved3[3]; | |
44 | uint32_t vm_parm_len; | |
45 | uint8_t nss_name[8]; | |
46 | uint8_t vm_parm[64]; | |
47 | uint8_t reserved4[8]; | |
48 | } QEMU_PACKED; | |
49 | typedef struct IplBlockCcw IplBlockCcw; | |
50 | ||
51 | struct IplBlockFcp { | |
52 | uint8_t reserved1[305 - 1]; | |
53 | uint8_t opt; | |
54 | uint8_t reserved2[3]; | |
55 | uint16_t reserved3; | |
56 | uint16_t devno; | |
57 | uint8_t reserved4[4]; | |
58 | uint64_t wwpn; | |
59 | uint64_t lun; | |
60 | uint32_t bootprog; | |
61 | uint8_t reserved5[12]; | |
62 | uint64_t br_lba; | |
63 | uint32_t scp_data_len; | |
64 | uint8_t reserved6[260]; | |
65 | uint8_t scp_data[]; | |
66 | } QEMU_PACKED; | |
67 | typedef struct IplBlockFcp IplBlockFcp; | |
68 | ||
e468b673 AY |
69 | struct IplBlockQemuScsi { |
70 | uint32_t lun; | |
71 | uint16_t target; | |
72 | uint16_t channel; | |
73 | uint8_t reserved0[77]; | |
74 | uint8_t ssid; | |
75 | uint16_t devno; | |
76 | } QEMU_PACKED; | |
77 | typedef struct IplBlockQemuScsi IplBlockQemuScsi; | |
78 | ||
bd1badf4 FA |
79 | #define DIAG308_FLAGS_LP_VALID 0x80 |
80 | ||
04ca4b92 AY |
81 | union IplParameterBlock { |
82 | struct { | |
83 | uint32_t len; | |
84 | uint8_t reserved0[3]; | |
85 | uint8_t version; | |
86 | uint32_t blk0_len; | |
87 | uint8_t pbt; | |
88 | uint8_t flags; | |
89 | uint16_t reserved01; | |
90 | uint8_t loadparm[8]; | |
91 | union { | |
92 | IplBlockCcw ccw; | |
93 | IplBlockFcp fcp; | |
c3347ed0 | 94 | IPLBlockPV pv; |
e468b673 | 95 | IplBlockQemuScsi scsi; |
04ca4b92 AY |
96 | }; |
97 | } QEMU_PACKED; | |
98 | struct { | |
99 | uint8_t reserved1[110]; | |
100 | uint16_t devno; | |
101 | uint8_t reserved2[88]; | |
102 | uint8_t reserved_ext[4096 - 200]; | |
103 | } QEMU_PACKED; | |
104 | } QEMU_PACKED; | |
105 | typedef union IplParameterBlock IplParameterBlock; | |
df75a4e2 | 106 | |
bd1badf4 | 107 | int s390_ipl_set_loadparm(uint8_t *loadparm); |
feacc6c2 | 108 | void s390_ipl_update_diag308(IplParameterBlock *iplb); |
c3347ed0 JF |
109 | int s390_ipl_prepare_pv_header(void); |
110 | int s390_ipl_pv_unpack(void); | |
db3b2566 | 111 | void s390_ipl_prepare_cpu(S390CPU *cpu); |
df75a4e2 | 112 | IplParameterBlock *s390_ipl_get_iplb(void); |
c3347ed0 | 113 | IplParameterBlock *s390_ipl_get_iplb_pv(void); |
a30fb811 DH |
114 | |
115 | enum s390_reset { | |
116 | /* default is a reset not triggered by a CPU e.g. issued by QMP */ | |
117 | S390_RESET_EXTERNAL = 0, | |
118 | S390_RESET_REIPL, | |
119 | S390_RESET_MODIFIED_CLEAR, | |
120 | S390_RESET_LOAD_NORMAL, | |
c3347ed0 | 121 | S390_RESET_PV, |
a30fb811 DH |
122 | }; |
123 | void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type); | |
124 | void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type); | |
125 | void s390_ipl_clear_reset_request(void); | |
df75a4e2 | 126 | |
118ee80f CW |
127 | #define QIPL_ADDRESS 0xcc |
128 | ||
26b2a2a4 CW |
129 | /* Boot Menu flags */ |
130 | #define QIPL_FLAG_BM_OPTS_CMD 0x80 | |
53b310ce | 131 | #define QIPL_FLAG_BM_OPTS_ZIPL 0x40 |
26b2a2a4 | 132 | |
118ee80f CW |
133 | /* |
134 | * The QEMU IPL Parameters will be stored at absolute address | |
135 | * 204 (0xcc) which means it is 32-bit word aligned but not | |
136 | * double-word aligned. | |
137 | * Placement of data fields in this area must account for | |
138 | * their alignment needs. E.g., netboot_start_address must | |
139 | * have an offset of 4 + n * 8 bytes within the struct in order | |
140 | * to keep it double-word aligned. | |
141 | * The total size of the struct must never exceed 28 bytes. | |
142 | * This definition must be kept in sync with the defininition | |
143 | * in pc-bios/s390-ccw/iplb.h. | |
144 | */ | |
145 | struct QemuIplParameters { | |
26b2a2a4 CW |
146 | uint8_t qipl_flags; |
147 | uint8_t reserved1[3]; | |
118ee80f | 148 | uint64_t netboot_start_addr; |
26b2a2a4 CW |
149 | uint32_t boot_menu_timeout; |
150 | uint8_t reserved2[12]; | |
118ee80f CW |
151 | } QEMU_PACKED; |
152 | typedef struct QemuIplParameters QemuIplParameters; | |
153 | ||
04fccf10 DH |
154 | #define TYPE_S390_IPL "s390-ipl" |
155 | #define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL) | |
156 | ||
157 | struct S390IPLState { | |
158 | /*< private >*/ | |
159 | DeviceState parent_obj; | |
3b8afb41 | 160 | IplParameterBlock iplb; |
c3347ed0 | 161 | IplParameterBlock iplb_pv; |
3b8afb41 | 162 | QemuIplParameters qipl; |
04fccf10 | 163 | uint64_t start_addr; |
bb099546 | 164 | uint64_t compat_start_addr; |
04fccf10 | 165 | uint64_t bios_start_addr; |
bb099546 | 166 | uint64_t compat_bios_start_addr; |
04fccf10 | 167 | bool enforce_bios; |
04fccf10 | 168 | bool iplb_valid; |
c3347ed0 | 169 | bool iplb_valid_pv; |
f38b5b7f | 170 | bool netboot; |
a30fb811 DH |
171 | /* reset related properties don't have to be migrated or reset */ |
172 | enum s390_reset reset_type; | |
173 | int reset_cpu_index; | |
04fccf10 DH |
174 | |
175 | /*< public >*/ | |
176 | char *kernel; | |
177 | char *initrd; | |
178 | char *cmdline; | |
179 | char *firmware; | |
5f31ade0 | 180 | char *netboot_fw; |
04fccf10 DH |
181 | uint8_t cssid; |
182 | uint8_t ssid; | |
183 | uint16_t devno; | |
04ca4b92 | 184 | bool iplbext_migration; |
04fccf10 DH |
185 | }; |
186 | typedef struct S390IPLState S390IPLState; | |
3b8afb41 | 187 | QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); |
04fccf10 | 188 | |
9b39d294 JF |
189 | #define DIAG_308_RC_OK 0x0001 |
190 | #define DIAG_308_RC_NO_CONF 0x0102 | |
191 | #define DIAG_308_RC_INVALID 0x0402 | |
c3347ed0 JF |
192 | #define DIAG_308_RC_NO_PV_CONF 0x0902 |
193 | #define DIAG_308_RC_INVAL_FOR_PV 0x0a02 | |
9b39d294 JF |
194 | |
195 | #define DIAG308_RESET_MOD_CLR 0 | |
196 | #define DIAG308_RESET_LOAD_NORM 1 | |
197 | #define DIAG308_LOAD_CLEAR 3 | |
198 | #define DIAG308_LOAD_NORMAL_DUMP 4 | |
199 | #define DIAG308_SET 5 | |
200 | #define DIAG308_STORE 6 | |
c3347ed0 JF |
201 | #define DIAG308_PV_SET 8 |
202 | #define DIAG308_PV_STORE 9 | |
203 | #define DIAG308_PV_START 10 | |
9b39d294 | 204 | |
9946a911 AY |
205 | #define S390_IPL_TYPE_FCP 0x00 |
206 | #define S390_IPL_TYPE_CCW 0x02 | |
c3347ed0 | 207 | #define S390_IPL_TYPE_PV 0x05 |
e468b673 | 208 | #define S390_IPL_TYPE_QEMU_SCSI 0xff |
9946a911 | 209 | |
6aed9589 | 210 | #define S390_IPLB_HEADER_LEN 8 |
c3347ed0 | 211 | #define S390_IPLB_MIN_PV_LEN 148 |
04ca4b92 | 212 | #define S390_IPLB_MIN_CCW_LEN 200 |
9946a911 | 213 | #define S390_IPLB_MIN_FCP_LEN 384 |
e468b673 | 214 | #define S390_IPLB_MIN_QEMU_SCSI_LEN 200 |
9946a911 AY |
215 | |
216 | static inline bool iplb_valid_len(IplParameterBlock *iplb) | |
217 | { | |
218 | return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock); | |
219 | } | |
220 | ||
c3347ed0 JF |
221 | static inline bool ipl_valid_pv_components(IplParameterBlock *iplb) |
222 | { | |
223 | IPLBlockPV *ipib_pv = &iplb->pv; | |
224 | int i; | |
225 | ||
226 | if (ipib_pv->num_comp == 0) { | |
227 | return false; | |
228 | } | |
229 | ||
230 | for (i = 0; i < ipib_pv->num_comp; i++) { | |
231 | /* Addr must be 4k aligned */ | |
232 | if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) { | |
233 | return false; | |
234 | } | |
235 | ||
236 | /* Tweak prefix is monotonically increasing with each component */ | |
237 | if (i < ipib_pv->num_comp - 1 && | |
238 | ipib_pv->components[i].tweak_pref >= | |
239 | ipib_pv->components[i + 1].tweak_pref) { | |
240 | return false; | |
241 | } | |
242 | } | |
243 | return true; | |
244 | } | |
245 | ||
246 | static inline bool ipl_valid_pv_header(IplParameterBlock *iplb) | |
247 | { | |
248 | IPLBlockPV *ipib_pv = &iplb->pv; | |
249 | ||
250 | if (ipib_pv->pv_header_len > 2 * TARGET_PAGE_SIZE) { | |
251 | return false; | |
252 | } | |
253 | ||
254 | if (!address_space_access_valid(&address_space_memory, | |
255 | ipib_pv->pv_header_addr, | |
256 | ipib_pv->pv_header_len, | |
257 | false, | |
258 | MEMTXATTRS_UNSPECIFIED)) { | |
259 | return false; | |
260 | } | |
261 | ||
262 | return true; | |
263 | } | |
264 | ||
265 | static inline bool iplb_valid_pv(IplParameterBlock *iplb) | |
266 | { | |
267 | if (iplb->pbt != S390_IPL_TYPE_PV || | |
268 | be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN) { | |
269 | return false; | |
270 | } | |
271 | if (!ipl_valid_pv_header(iplb)) { | |
272 | return false; | |
273 | } | |
274 | return ipl_valid_pv_components(iplb); | |
275 | } | |
276 | ||
94c21436 | 277 | static inline bool iplb_valid(IplParameterBlock *iplb) |
9946a911 | 278 | { |
94c21436 JF |
279 | switch (iplb->pbt) { |
280 | case S390_IPL_TYPE_FCP: | |
281 | return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN; | |
282 | case S390_IPL_TYPE_CCW: | |
283 | return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN; | |
284 | default: | |
285 | return false; | |
286 | } | |
9946a911 | 287 | } |
04ca4b92 | 288 | |
df75a4e2 | 289 | #endif |