2 * S390 IPL (boot) from a real DASD device via vfio framework.
4 * Copyright (c) 2019 Jason J. Herne <jjherne@us.ibm.com>
6 * This work is licensed under the terms of the GNU GPL, version 2 or (at
7 * your option) any later version. See the COPYING file in the top-level
13 #include "s390-arch.h"
17 static char prefix_page
[PAGE_SIZE
* 2]
18 __attribute__((__aligned__(PAGE_SIZE
* 2)));
20 static void enable_prefixing(void)
22 memcpy(&prefix_page
, lowcore
, 4096);
23 set_prefix(ptr2u32(&prefix_page
));
26 static void disable_prefixing(void)
29 /* Copy io interrupt info back to low core */
30 memcpy((void *)&lowcore
->subchannel_id
, prefix_page
+ 0xB8, 12);
33 static bool is_read_tic_ccw_chain(Ccw0
*ccw
)
35 Ccw0
*next_ccw
= ccw
+ 1;
37 return ((ccw
->cmd_code
== CCW_CMD_DASD_READ
||
38 ccw
->cmd_code
== CCW_CMD_DASD_READ_MT
) &&
39 ccw
->chain
&& next_ccw
->cmd_code
== CCW_CMD_TIC
);
42 static bool dynamic_cp_fixup(uint32_t ccw_addr
, uint32_t *next_cpa
)
44 Ccw0
*cur_ccw
= (Ccw0
*)(uint64_t)ccw_addr
;
48 /* Skip over inline TIC (it might not have the chain bit on) */
49 if (cur_ccw
->cmd_code
== CCW_CMD_TIC
&&
50 cur_ccw
->cda
== ptr2u32(cur_ccw
) - 8) {
55 if (!cur_ccw
->chain
) {
58 if (is_read_tic_ccw_chain(cur_ccw
)) {
60 * Breaking a chain of CCWs may alter the semantics or even the
61 * validity of a channel program. The heuristic implemented below
62 * seems to work well in practice for the channel programs
65 tic_ccw
= cur_ccw
+ 1;
66 *next_cpa
= tic_ccw
->cda
;
75 static int run_dynamic_ccw_program(SubChannelId schid
, uint16_t cutype
,
79 uint32_t next_cpa
= 0;
83 has_next
= dynamic_cp_fixup(cpa
, &next_cpa
);
85 print_int("executing ccw chain at ", cpa
);
87 rc
= do_cio(schid
, cutype
, cpa
, CCW_FMT0
);
99 static void make_readipl(void)
101 Ccw0
*ccwIplRead
= (Ccw0
*)0x00;
103 /* Clear out any existing data */
104 memset(ccwIplRead
, 0, sizeof(Ccw0
));
106 /* Create Read IPL ccw at address 0 */
107 ccwIplRead
->cmd_code
= CCW_CMD_READ_IPL
;
108 ccwIplRead
->cda
= 0x00; /* Read into address 0x00 in main memory */
109 ccwIplRead
->chain
= 0; /* Chain flag */
110 ccwIplRead
->count
= 0x18; /* Read 0x18 bytes of data */
113 static void run_readipl(SubChannelId schid
, uint16_t cutype
)
115 if (do_cio(schid
, cutype
, 0x00, CCW_FMT0
)) {
116 panic("dasd-ipl: Failed to run Read IPL channel program\n");
121 * The architecture states that IPL1 data should consist of a psw followed by
122 * format-0 READ and TIC CCWs. Let's sanity check.
124 static void check_ipl1(void)
126 Ccw0
*ccwread
= (Ccw0
*)0x08;
127 Ccw0
*ccwtic
= (Ccw0
*)0x10;
129 if (ccwread
->cmd_code
!= CCW_CMD_DASD_READ
||
130 ccwtic
->cmd_code
!= CCW_CMD_TIC
) {
131 panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
135 static void check_ipl2(uint32_t ipl2_addr
)
137 Ccw0
*ccw
= u32toptr(ipl2_addr
);
139 if (ipl2_addr
== 0x00) {
140 panic("IPL2 address invalid. Is this disk really bootable?\n");
142 if (ccw
->cmd_code
== 0x00) {
143 panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
147 static uint32_t read_ipl2_addr(void)
149 Ccw0
*ccwtic
= (Ccw0
*)0x10;
154 static void ipl1_fixup(void)
156 Ccw0
*ccwSeek
= (Ccw0
*) 0x08;
157 Ccw0
*ccwSearchID
= (Ccw0
*) 0x10;
158 Ccw0
*ccwSearchTic
= (Ccw0
*) 0x18;
159 Ccw0
*ccwRead
= (Ccw0
*) 0x20;
160 CcwSeekData
*seekData
= (CcwSeekData
*) 0x30;
161 CcwSearchIdData
*searchData
= (CcwSearchIdData
*) 0x38;
163 /* move IPL1 CCWs to make room for CCWs needed to locate record 2 */
164 memcpy(ccwRead
, (void *)0x08, 16);
166 /* Disable chaining so we don't TIC to IPL2 channel program */
167 ccwRead
->chain
= 0x00;
169 ccwSeek
->cmd_code
= CCW_CMD_DASD_SEEK
;
170 ccwSeek
->cda
= ptr2u32(seekData
);
172 ccwSeek
->count
= sizeof(*seekData
);
173 seekData
->reserved
= 0x00;
174 seekData
->cyl
= 0x00;
175 seekData
->head
= 0x00;
177 ccwSearchID
->cmd_code
= CCW_CMD_DASD_SEARCH_ID_EQ
;
178 ccwSearchID
->cda
= ptr2u32(searchData
);
179 ccwSearchID
->chain
= 1;
180 ccwSearchID
->count
= sizeof(*searchData
);
182 searchData
->head
= 0;
183 searchData
->record
= 2;
185 /* Go back to Search CCW if correct record not yet found */
186 ccwSearchTic
->cmd_code
= CCW_CMD_TIC
;
187 ccwSearchTic
->cda
= ptr2u32(ccwSearchID
);
190 static void run_ipl1(SubChannelId schid
, uint16_t cutype
)
192 uint32_t startAddr
= 0x08;
194 if (do_cio(schid
, cutype
, startAddr
, CCW_FMT0
)) {
195 panic("dasd-ipl: Failed to run IPL1 channel program\n");
199 static void run_ipl2(SubChannelId schid
, uint16_t cutype
, uint32_t addr
)
201 if (run_dynamic_ccw_program(schid
, cutype
, addr
)) {
202 panic("dasd-ipl: Failed to run IPL2 channel program\n");
207 * Limitations in vfio-ccw support complicate the IPL process. Details can
208 * be found in docs/devel/s390-dasd-ipl.txt
210 void dasd_ipl(SubChannelId schid
, uint16_t cutype
)
212 PSWLegacy
*pswl
= (PSWLegacy
*) 0x00;
215 /* Construct Read IPL CCW and run it to read IPL1 from boot disk */
217 run_readipl(schid
, cutype
);
218 ipl2_addr
= read_ipl2_addr();
222 * Fixup IPL1 channel program to account for vfio-ccw limitations, then run
223 * it to read IPL2 channel program from boot disk.
226 run_ipl1(schid
, cutype
);
227 check_ipl2(ipl2_addr
);
230 * Run IPL2 channel program to read operating system code from boot disk
232 run_ipl2(schid
, cutype
, ipl2_addr
);
234 /* Transfer control to the guest operating system */
235 pswl
->mask
|= PSW_MASK_EAMODE
; /* Force z-mode */
236 pswl
->addr
|= PSW_MASK_BAMODE
; /* ... */
237 jump_to_low_kernel();