Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 1 | /* |
| 2 | * s390 IPL device |
| 3 | * |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 4 | * Copyright 2015, 2020 IBM Corp. |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 5 | * Author(s): Zhang Fan <bjfanzh@cn.ibm.com> |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 6 | * Janosch Frank <frankja@linux.ibm.com> |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 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 | |
David Hildenbrand | db3b256 | 2015-07-21 13:47:32 +0200 | [diff] [blame] | 16 | #include "cpu.h" |
Christian Borntraeger | fbc1384 | 2020-04-06 06:01:58 -0400 | [diff] [blame] | 17 | #include "exec/address-spaces.h" |
Markus Armbruster | a27bd6c | 2019-08-12 07:23:51 +0200 | [diff] [blame] | 18 | #include "hw/qdev-core.h" |
Eduardo Habkost | db1015e | 2020-09-03 16:43:22 -0400 | [diff] [blame] | 19 | #include "qom/object.h" |
David Hildenbrand | db3b256 | 2015-07-21 13:47:32 +0200 | [diff] [blame] | 20 | |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 21 | struct IPLBlockPVComp { |
| 22 | uint64_t tweak_pref; |
| 23 | uint64_t addr; |
| 24 | uint64_t size; |
| 25 | } QEMU_PACKED; |
| 26 | typedef struct IPLBlockPVComp IPLBlockPVComp; |
| 27 | |
| 28 | struct IPLBlockPV { |
| 29 | uint8_t reserved18[87]; /* 0x18 */ |
| 30 | uint8_t version; /* 0x6f */ |
| 31 | uint32_t reserved70; /* 0x70 */ |
| 32 | uint32_t num_comp; /* 0x74 */ |
| 33 | uint64_t pv_header_addr; /* 0x78 */ |
| 34 | uint64_t pv_header_len; /* 0x80 */ |
Daniele Buono | a58cabd | 2020-11-05 17:19:00 -0500 | [diff] [blame] | 35 | struct IPLBlockPVComp components[0]; |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 36 | } QEMU_PACKED; |
| 37 | typedef struct IPLBlockPV IPLBlockPV; |
| 38 | |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 39 | struct IplBlockCcw { |
Collin L. Walling | 118ee80 | 2018-02-23 10:43:11 -0500 | [diff] [blame] | 40 | uint8_t reserved0[85]; |
Alexander Yarygin | 3041e3b | 2015-10-01 20:21:33 +0300 | [diff] [blame] | 41 | uint8_t ssid; |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 42 | uint16_t devno; |
| 43 | uint8_t vm_flags; |
| 44 | uint8_t reserved3[3]; |
| 45 | uint32_t vm_parm_len; |
| 46 | uint8_t nss_name[8]; |
| 47 | uint8_t vm_parm[64]; |
| 48 | uint8_t reserved4[8]; |
| 49 | } QEMU_PACKED; |
| 50 | typedef struct IplBlockCcw IplBlockCcw; |
| 51 | |
| 52 | struct IplBlockFcp { |
| 53 | uint8_t reserved1[305 - 1]; |
| 54 | uint8_t opt; |
| 55 | uint8_t reserved2[3]; |
| 56 | uint16_t reserved3; |
| 57 | uint16_t devno; |
| 58 | uint8_t reserved4[4]; |
| 59 | uint64_t wwpn; |
| 60 | uint64_t lun; |
| 61 | uint32_t bootprog; |
| 62 | uint8_t reserved5[12]; |
| 63 | uint64_t br_lba; |
| 64 | uint32_t scp_data_len; |
| 65 | uint8_t reserved6[260]; |
Daniele Buono | a58cabd | 2020-11-05 17:19:00 -0500 | [diff] [blame] | 66 | uint8_t scp_data[0]; |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 67 | } QEMU_PACKED; |
| 68 | typedef struct IplBlockFcp IplBlockFcp; |
| 69 | |
Alexander Yarygin | e468b67 | 2016-06-09 15:54:10 +0300 | [diff] [blame] | 70 | struct IplBlockQemuScsi { |
| 71 | uint32_t lun; |
| 72 | uint16_t target; |
| 73 | uint16_t channel; |
| 74 | uint8_t reserved0[77]; |
| 75 | uint8_t ssid; |
| 76 | uint16_t devno; |
| 77 | } QEMU_PACKED; |
| 78 | typedef struct IplBlockQemuScsi IplBlockQemuScsi; |
| 79 | |
Farhan Ali | bd1badf | 2016-03-29 16:28:40 +0200 | [diff] [blame] | 80 | #define DIAG308_FLAGS_LP_VALID 0x80 |
| 81 | |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 82 | union IplParameterBlock { |
| 83 | struct { |
| 84 | uint32_t len; |
| 85 | uint8_t reserved0[3]; |
| 86 | uint8_t version; |
| 87 | uint32_t blk0_len; |
| 88 | uint8_t pbt; |
| 89 | uint8_t flags; |
| 90 | uint16_t reserved01; |
| 91 | uint8_t loadparm[8]; |
| 92 | union { |
| 93 | IplBlockCcw ccw; |
| 94 | IplBlockFcp fcp; |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 95 | IPLBlockPV pv; |
Alexander Yarygin | e468b67 | 2016-06-09 15:54:10 +0300 | [diff] [blame] | 96 | IplBlockQemuScsi scsi; |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 97 | }; |
| 98 | } QEMU_PACKED; |
| 99 | struct { |
| 100 | uint8_t reserved1[110]; |
| 101 | uint16_t devno; |
| 102 | uint8_t reserved2[88]; |
| 103 | uint8_t reserved_ext[4096 - 200]; |
| 104 | } QEMU_PACKED; |
| 105 | } QEMU_PACKED; |
| 106 | typedef union IplParameterBlock IplParameterBlock; |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 107 | |
Farhan Ali | bd1badf | 2016-03-29 16:28:40 +0200 | [diff] [blame] | 108 | int s390_ipl_set_loadparm(uint8_t *loadparm); |
David Hildenbrand | feacc6c | 2015-06-25 09:55:55 +0200 | [diff] [blame] | 109 | void s390_ipl_update_diag308(IplParameterBlock *iplb); |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 110 | int s390_ipl_prepare_pv_header(void); |
| 111 | int s390_ipl_pv_unpack(void); |
David Hildenbrand | db3b256 | 2015-07-21 13:47:32 +0200 | [diff] [blame] | 112 | void s390_ipl_prepare_cpu(S390CPU *cpu); |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 113 | IplParameterBlock *s390_ipl_get_iplb(void); |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 114 | IplParameterBlock *s390_ipl_get_iplb_pv(void); |
David Hildenbrand | a30fb81 | 2018-04-24 12:18:59 +0200 | [diff] [blame] | 115 | |
| 116 | enum s390_reset { |
| 117 | /* default is a reset not triggered by a CPU e.g. issued by QMP */ |
| 118 | S390_RESET_EXTERNAL = 0, |
| 119 | S390_RESET_REIPL, |
| 120 | S390_RESET_MODIFIED_CLEAR, |
| 121 | S390_RESET_LOAD_NORMAL, |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 122 | S390_RESET_PV, |
David Hildenbrand | a30fb81 | 2018-04-24 12:18:59 +0200 | [diff] [blame] | 123 | }; |
| 124 | void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type); |
| 125 | void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type); |
| 126 | void s390_ipl_clear_reset_request(void); |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 127 | |
Collin L. Walling | 118ee80 | 2018-02-23 10:43:11 -0500 | [diff] [blame] | 128 | #define QIPL_ADDRESS 0xcc |
| 129 | |
Collin L. Walling | 26b2a2a | 2018-02-23 10:43:12 -0500 | [diff] [blame] | 130 | /* Boot Menu flags */ |
| 131 | #define QIPL_FLAG_BM_OPTS_CMD 0x80 |
Collin L. Walling | 53b310c | 2018-02-23 10:43:18 -0500 | [diff] [blame] | 132 | #define QIPL_FLAG_BM_OPTS_ZIPL 0x40 |
Collin L. Walling | 26b2a2a | 2018-02-23 10:43:12 -0500 | [diff] [blame] | 133 | |
Collin L. Walling | 118ee80 | 2018-02-23 10:43:11 -0500 | [diff] [blame] | 134 | /* |
| 135 | * The QEMU IPL Parameters will be stored at absolute address |
| 136 | * 204 (0xcc) which means it is 32-bit word aligned but not |
| 137 | * double-word aligned. |
| 138 | * Placement of data fields in this area must account for |
| 139 | * their alignment needs. E.g., netboot_start_address must |
| 140 | * have an offset of 4 + n * 8 bytes within the struct in order |
| 141 | * to keep it double-word aligned. |
| 142 | * The total size of the struct must never exceed 28 bytes. |
| 143 | * This definition must be kept in sync with the defininition |
| 144 | * in pc-bios/s390-ccw/iplb.h. |
| 145 | */ |
| 146 | struct QemuIplParameters { |
Collin L. Walling | 26b2a2a | 2018-02-23 10:43:12 -0500 | [diff] [blame] | 147 | uint8_t qipl_flags; |
| 148 | uint8_t reserved1[3]; |
Collin L. Walling | 118ee80 | 2018-02-23 10:43:11 -0500 | [diff] [blame] | 149 | uint64_t netboot_start_addr; |
Collin L. Walling | 26b2a2a | 2018-02-23 10:43:12 -0500 | [diff] [blame] | 150 | uint32_t boot_menu_timeout; |
| 151 | uint8_t reserved2[12]; |
Collin L. Walling | 118ee80 | 2018-02-23 10:43:11 -0500 | [diff] [blame] | 152 | } QEMU_PACKED; |
| 153 | typedef struct QemuIplParameters QemuIplParameters; |
| 154 | |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 155 | #define TYPE_S390_IPL "s390-ipl" |
Eduardo Habkost | 8063396 | 2020-09-16 14:25:19 -0400 | [diff] [blame] | 156 | OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL) |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 157 | |
| 158 | struct S390IPLState { |
| 159 | /*< private >*/ |
| 160 | DeviceState parent_obj; |
Thomas Huth | 3b8afb4 | 2018-09-27 10:23:33 +0200 | [diff] [blame] | 161 | IplParameterBlock iplb; |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 162 | IplParameterBlock iplb_pv; |
Thomas Huth | 3b8afb4 | 2018-09-27 10:23:33 +0200 | [diff] [blame] | 163 | QemuIplParameters qipl; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 164 | uint64_t start_addr; |
David Hildenbrand | bb09954 | 2016-06-09 15:36:41 +0200 | [diff] [blame] | 165 | uint64_t compat_start_addr; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 166 | uint64_t bios_start_addr; |
David Hildenbrand | bb09954 | 2016-06-09 15:36:41 +0200 | [diff] [blame] | 167 | uint64_t compat_bios_start_addr; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 168 | bool enforce_bios; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 169 | bool iplb_valid; |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 170 | bool iplb_valid_pv; |
Farhan Ali | f38b5b7 | 2016-10-20 17:59:20 -0400 | [diff] [blame] | 171 | bool netboot; |
David Hildenbrand | a30fb81 | 2018-04-24 12:18:59 +0200 | [diff] [blame] | 172 | /* reset related properties don't have to be migrated or reset */ |
| 173 | enum s390_reset reset_type; |
| 174 | int reset_cpu_index; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 175 | |
| 176 | /*< public >*/ |
| 177 | char *kernel; |
| 178 | char *initrd; |
| 179 | char *cmdline; |
| 180 | char *firmware; |
Farhan Ali | 5f31ade | 2016-10-21 12:17:08 -0400 | [diff] [blame] | 181 | char *netboot_fw; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 182 | uint8_t cssid; |
| 183 | uint8_t ssid; |
| 184 | uint16_t devno; |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 185 | bool iplbext_migration; |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 186 | }; |
Thomas Huth | 3b8afb4 | 2018-09-27 10:23:33 +0200 | [diff] [blame] | 187 | QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong"); |
David Hildenbrand | 04fccf1 | 2015-10-08 12:32:13 +0200 | [diff] [blame] | 188 | |
Janosch Frank | 9b39d29 | 2020-03-19 09:19:06 -0400 | [diff] [blame] | 189 | #define DIAG_308_RC_OK 0x0001 |
| 190 | #define DIAG_308_RC_NO_CONF 0x0102 |
| 191 | #define DIAG_308_RC_INVALID 0x0402 |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 192 | #define DIAG_308_RC_NO_PV_CONF 0x0902 |
| 193 | #define DIAG_308_RC_INVAL_FOR_PV 0x0a02 |
Janosch Frank | 9b39d29 | 2020-03-19 09:19:06 -0400 | [diff] [blame] | 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 |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 201 | #define DIAG308_PV_SET 8 |
| 202 | #define DIAG308_PV_STORE 9 |
| 203 | #define DIAG308_PV_START 10 |
Janosch Frank | 9b39d29 | 2020-03-19 09:19:06 -0400 | [diff] [blame] | 204 | |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 205 | #define S390_IPL_TYPE_FCP 0x00 |
| 206 | #define S390_IPL_TYPE_CCW 0x02 |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 207 | #define S390_IPL_TYPE_PV 0x05 |
Alexander Yarygin | e468b67 | 2016-06-09 15:54:10 +0300 | [diff] [blame] | 208 | #define S390_IPL_TYPE_QEMU_SCSI 0xff |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 209 | |
Alexander Yarygin | 6aed958 | 2015-07-21 14:10:39 +0300 | [diff] [blame] | 210 | #define S390_IPLB_HEADER_LEN 8 |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 211 | #define S390_IPLB_MIN_PV_LEN 148 |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 212 | #define S390_IPLB_MIN_CCW_LEN 200 |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 213 | #define S390_IPLB_MIN_FCP_LEN 384 |
Alexander Yarygin | e468b67 | 2016-06-09 15:54:10 +0300 | [diff] [blame] | 214 | #define S390_IPLB_MIN_QEMU_SCSI_LEN 200 |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 215 | |
| 216 | static inline bool iplb_valid_len(IplParameterBlock *iplb) |
| 217 | { |
| 218 | return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock); |
| 219 | } |
| 220 | |
Janosch Frank | c3347ed | 2020-03-23 04:36:06 -0400 | [diff] [blame] | 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 | |
Janosch Frank | 94c2143 | 2020-03-10 05:09:50 -0400 | [diff] [blame] | 277 | static inline bool iplb_valid(IplParameterBlock *iplb) |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 278 | { |
Janosch Frank | 94c2143 | 2020-03-10 05:09:50 -0400 | [diff] [blame] | 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 | } |
Alexander Yarygin | 9946a91 | 2015-08-10 13:57:03 +0300 | [diff] [blame] | 287 | } |
Alexander Yarygin | 04ca4b9 | 2015-07-13 15:04:36 +0300 | [diff] [blame] | 288 | |
Fan Zhang | df75a4e | 2015-02-12 18:02:14 +0100 | [diff] [blame] | 289 | #endif |