1df75a4e2SFan Zhang /*
2df75a4e2SFan Zhang * s390 IPL device
3df75a4e2SFan Zhang *
4c3347ed0SJanosch Frank * Copyright 2015, 2020 IBM Corp.
5df75a4e2SFan Zhang * Author(s): Zhang Fan <bjfanzh@cn.ibm.com>
6c3347ed0SJanosch Frank * Janosch Frank <frankja@linux.ibm.com>
7df75a4e2SFan Zhang *
8df75a4e2SFan Zhang * This work is licensed under the terms of the GNU GPL, version 2 or (at
9df75a4e2SFan Zhang * your option) any later version. See the COPYING file in the top-level
10df75a4e2SFan Zhang * directory.
11df75a4e2SFan Zhang */
12df75a4e2SFan Zhang
13df75a4e2SFan Zhang #ifndef HW_S390_IPL_H
14df75a4e2SFan Zhang #define HW_S390_IPL_H
15df75a4e2SFan Zhang
16db3b2566SDavid Hildenbrand #include "cpu.h"
17fbc1384cSChristian Borntraeger #include "exec/address-spaces.h"
18a27bd6c7SMarkus Armbruster #include "hw/qdev-core.h"
19ba3658adSJared Rossi #include "hw/s390x/ipl/qipl.h"
20db1015e9SEduardo Habkost #include "qom/object.h"
21db3b2566SDavid Hildenbrand
22bd1badf4SFarhan Ali #define DIAG308_FLAGS_LP_VALID 0x80
230927875eSJared Rossi #define MAX_BOOT_DEVS 8 /* Max number of devices that may have a bootindex */
24bd1badf4SFarhan Ali
25bb185de4SJared Rossi void s390_ipl_convert_loadparm(char *ascii_lp, uint8_t *ebcdic_lp);
26bb185de4SJared Rossi void s390_ipl_fmt_loadparm(uint8_t *loadparm, char *str, Error **errp);
27*455e3bc3SJared Rossi void s390_rebuild_iplb(uint16_t index, IplParameterBlock *iplb);
28feacc6c2SDavid Hildenbrand void s390_ipl_update_diag308(IplParameterBlock *iplb);
297af51621SThomas Huth int s390_ipl_prepare_pv_header(Error **errp);
30c3347ed0SJanosch Frank int s390_ipl_pv_unpack(void);
31db3b2566SDavid Hildenbrand void s390_ipl_prepare_cpu(S390CPU *cpu);
32df75a4e2SFan Zhang IplParameterBlock *s390_ipl_get_iplb(void);
33c3347ed0SJanosch Frank IplParameterBlock *s390_ipl_get_iplb_pv(void);
34a30fb811SDavid Hildenbrand
35a30fb811SDavid Hildenbrand enum s390_reset {
36a30fb811SDavid Hildenbrand /* default is a reset not triggered by a CPU e.g. issued by QMP */
37a30fb811SDavid Hildenbrand S390_RESET_EXTERNAL = 0,
38a30fb811SDavid Hildenbrand S390_RESET_REIPL,
39a30fb811SDavid Hildenbrand S390_RESET_MODIFIED_CLEAR,
40a30fb811SDavid Hildenbrand S390_RESET_LOAD_NORMAL,
41c3347ed0SJanosch Frank S390_RESET_PV,
42a30fb811SDavid Hildenbrand };
43a30fb811SDavid Hildenbrand void s390_ipl_reset_request(CPUState *cs, enum s390_reset reset_type);
44a30fb811SDavid Hildenbrand void s390_ipl_get_reset_request(CPUState **cs, enum s390_reset *reset_type);
45a30fb811SDavid Hildenbrand void s390_ipl_clear_reset_request(void);
46df75a4e2SFan Zhang
47118ee80fSCollin L. Walling #define QIPL_ADDRESS 0xcc
48118ee80fSCollin L. Walling
4926b2a2a4SCollin L. Walling /* Boot Menu flags */
5026b2a2a4SCollin L. Walling #define QIPL_FLAG_BM_OPTS_CMD 0x80
5153b310ceSCollin L. Walling #define QIPL_FLAG_BM_OPTS_ZIPL 0x40
5226b2a2a4SCollin L. Walling
5304fccf10SDavid Hildenbrand #define TYPE_S390_IPL "s390-ipl"
548063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(S390IPLState, S390_IPL)
5504fccf10SDavid Hildenbrand
5604fccf10SDavid Hildenbrand struct S390IPLState {
5704fccf10SDavid Hildenbrand /*< private >*/
5804fccf10SDavid Hildenbrand DeviceState parent_obj;
593b8afb41SThomas Huth IplParameterBlock iplb;
60c3347ed0SJanosch Frank IplParameterBlock iplb_pv;
613b8afb41SThomas Huth QemuIplParameters qipl;
6204fccf10SDavid Hildenbrand uint64_t start_addr;
63bb099546SDavid Hildenbrand uint64_t compat_start_addr;
6404fccf10SDavid Hildenbrand uint64_t bios_start_addr;
65bb099546SDavid Hildenbrand uint64_t compat_bios_start_addr;
6604fccf10SDavid Hildenbrand bool enforce_bios;
6704fccf10SDavid Hildenbrand bool iplb_valid;
68c3347ed0SJanosch Frank bool iplb_valid_pv;
69*455e3bc3SJared Rossi bool rebuilt_iplb;
70*455e3bc3SJared Rossi uint16_t iplb_index;
71a30fb811SDavid Hildenbrand /* reset related properties don't have to be migrated or reset */
72a30fb811SDavid Hildenbrand enum s390_reset reset_type;
73a30fb811SDavid Hildenbrand int reset_cpu_index;
7404fccf10SDavid Hildenbrand
7504fccf10SDavid Hildenbrand /*< public >*/
7604fccf10SDavid Hildenbrand char *kernel;
7704fccf10SDavid Hildenbrand char *initrd;
7804fccf10SDavid Hildenbrand char *cmdline;
7904fccf10SDavid Hildenbrand char *firmware;
8004fccf10SDavid Hildenbrand uint8_t cssid;
8104fccf10SDavid Hildenbrand uint8_t ssid;
8204fccf10SDavid Hildenbrand uint16_t devno;
8304ca4b92SAlexander Yarygin bool iplbext_migration;
8404fccf10SDavid Hildenbrand };
853b8afb41SThomas Huth QEMU_BUILD_BUG_MSG(offsetof(S390IPLState, iplb) & 3, "alignment of iplb wrong");
8604fccf10SDavid Hildenbrand
879b39d294SJanosch Frank #define DIAG_308_RC_OK 0x0001
889b39d294SJanosch Frank #define DIAG_308_RC_NO_CONF 0x0102
899b39d294SJanosch Frank #define DIAG_308_RC_INVALID 0x0402
90c3347ed0SJanosch Frank #define DIAG_308_RC_NO_PV_CONF 0x0902
91c3347ed0SJanosch Frank #define DIAG_308_RC_INVAL_FOR_PV 0x0a02
929b39d294SJanosch Frank
939b39d294SJanosch Frank #define DIAG308_RESET_MOD_CLR 0
949b39d294SJanosch Frank #define DIAG308_RESET_LOAD_NORM 1
959b39d294SJanosch Frank #define DIAG308_LOAD_CLEAR 3
969b39d294SJanosch Frank #define DIAG308_LOAD_NORMAL_DUMP 4
979b39d294SJanosch Frank #define DIAG308_SET 5
989b39d294SJanosch Frank #define DIAG308_STORE 6
99c3347ed0SJanosch Frank #define DIAG308_PV_SET 8
100c3347ed0SJanosch Frank #define DIAG308_PV_STORE 9
101c3347ed0SJanosch Frank #define DIAG308_PV_START 10
1029b39d294SJanosch Frank
1039946a911SAlexander Yarygin #define S390_IPL_TYPE_FCP 0x00
1049946a911SAlexander Yarygin #define S390_IPL_TYPE_CCW 0x02
105c3347ed0SJanosch Frank #define S390_IPL_TYPE_PV 0x05
106e468b673SAlexander Yarygin #define S390_IPL_TYPE_QEMU_SCSI 0xff
1079946a911SAlexander Yarygin
1086aed9589SAlexander Yarygin #define S390_IPLB_HEADER_LEN 8
109c3347ed0SJanosch Frank #define S390_IPLB_MIN_PV_LEN 148
11004ca4b92SAlexander Yarygin #define S390_IPLB_MIN_CCW_LEN 200
1119946a911SAlexander Yarygin #define S390_IPLB_MIN_FCP_LEN 384
112e468b673SAlexander Yarygin #define S390_IPLB_MIN_QEMU_SCSI_LEN 200
1139946a911SAlexander Yarygin
iplb_valid_len(IplParameterBlock * iplb)1149946a911SAlexander Yarygin static inline bool iplb_valid_len(IplParameterBlock *iplb)
1159946a911SAlexander Yarygin {
1169946a911SAlexander Yarygin return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
1179946a911SAlexander Yarygin }
1189946a911SAlexander Yarygin
ipl_valid_pv_components(IplParameterBlock * iplb)119c3347ed0SJanosch Frank static inline bool ipl_valid_pv_components(IplParameterBlock *iplb)
120c3347ed0SJanosch Frank {
121c3347ed0SJanosch Frank IPLBlockPV *ipib_pv = &iplb->pv;
122c3347ed0SJanosch Frank int i;
123c3347ed0SJanosch Frank
124c3347ed0SJanosch Frank if (ipib_pv->num_comp == 0) {
125c3347ed0SJanosch Frank return false;
126c3347ed0SJanosch Frank }
127c3347ed0SJanosch Frank
128c3347ed0SJanosch Frank for (i = 0; i < ipib_pv->num_comp; i++) {
129c3347ed0SJanosch Frank /* Addr must be 4k aligned */
130c3347ed0SJanosch Frank if (ipib_pv->components[i].addr & ~TARGET_PAGE_MASK) {
131c3347ed0SJanosch Frank return false;
132c3347ed0SJanosch Frank }
133c3347ed0SJanosch Frank
134c3347ed0SJanosch Frank /* Tweak prefix is monotonically increasing with each component */
135c3347ed0SJanosch Frank if (i < ipib_pv->num_comp - 1 &&
136c3347ed0SJanosch Frank ipib_pv->components[i].tweak_pref >=
137c3347ed0SJanosch Frank ipib_pv->components[i + 1].tweak_pref) {
138c3347ed0SJanosch Frank return false;
139c3347ed0SJanosch Frank }
140c3347ed0SJanosch Frank }
141c3347ed0SJanosch Frank return true;
142c3347ed0SJanosch Frank }
143c3347ed0SJanosch Frank
ipl_valid_pv_header(IplParameterBlock * iplb)144c3347ed0SJanosch Frank static inline bool ipl_valid_pv_header(IplParameterBlock *iplb)
145c3347ed0SJanosch Frank {
146c3347ed0SJanosch Frank IPLBlockPV *ipib_pv = &iplb->pv;
147c3347ed0SJanosch Frank
148c3347ed0SJanosch Frank if (ipib_pv->pv_header_len > 2 * TARGET_PAGE_SIZE) {
149c3347ed0SJanosch Frank return false;
150c3347ed0SJanosch Frank }
151c3347ed0SJanosch Frank
152c3347ed0SJanosch Frank if (!address_space_access_valid(&address_space_memory,
153c3347ed0SJanosch Frank ipib_pv->pv_header_addr,
154c3347ed0SJanosch Frank ipib_pv->pv_header_len,
155c3347ed0SJanosch Frank false,
156c3347ed0SJanosch Frank MEMTXATTRS_UNSPECIFIED)) {
157c3347ed0SJanosch Frank return false;
158c3347ed0SJanosch Frank }
159c3347ed0SJanosch Frank
160c3347ed0SJanosch Frank return true;
161c3347ed0SJanosch Frank }
162c3347ed0SJanosch Frank
iplb_valid_pv(IplParameterBlock * iplb)163c3347ed0SJanosch Frank static inline bool iplb_valid_pv(IplParameterBlock *iplb)
164c3347ed0SJanosch Frank {
165c3347ed0SJanosch Frank if (iplb->pbt != S390_IPL_TYPE_PV ||
166c3347ed0SJanosch Frank be32_to_cpu(iplb->len) < S390_IPLB_MIN_PV_LEN) {
167c3347ed0SJanosch Frank return false;
168c3347ed0SJanosch Frank }
169c3347ed0SJanosch Frank if (!ipl_valid_pv_header(iplb)) {
170c3347ed0SJanosch Frank return false;
171c3347ed0SJanosch Frank }
172c3347ed0SJanosch Frank return ipl_valid_pv_components(iplb);
173c3347ed0SJanosch Frank }
174c3347ed0SJanosch Frank
iplb_valid(IplParameterBlock * iplb)17594c21436SJanosch Frank static inline bool iplb_valid(IplParameterBlock *iplb)
1769946a911SAlexander Yarygin {
177*455e3bc3SJared Rossi uint32_t len = be32_to_cpu(iplb->len);
178*455e3bc3SJared Rossi
17994c21436SJanosch Frank switch (iplb->pbt) {
18094c21436SJanosch Frank case S390_IPL_TYPE_FCP:
181*455e3bc3SJared Rossi return len >= S390_IPLB_MIN_FCP_LEN;
18294c21436SJanosch Frank case S390_IPL_TYPE_CCW:
183*455e3bc3SJared Rossi return len >= S390_IPLB_MIN_CCW_LEN;
184*455e3bc3SJared Rossi case S390_IPL_TYPE_QEMU_SCSI:
18594c21436SJanosch Frank default:
18694c21436SJanosch Frank return false;
1879946a911SAlexander Yarygin }
1889946a911SAlexander Yarygin }
18904ca4b92SAlexander Yarygin
190df75a4e2SFan Zhang #endif
191