1
2
3
4
5
6
7
8
9
10
11#include "libc.h"
12#include "s390-ccw.h"
13#include "s390-arch.h"
14#include "dasd-ipl.h"
15#include "helper.h"
16
17static char prefix_page[PAGE_SIZE * 2]
18 __attribute__((__aligned__(PAGE_SIZE * 2)));
19
20static void enable_prefixing(void)
21{
22 memcpy(&prefix_page, lowcore, 4096);
23 set_prefix(ptr2u32(&prefix_page));
24}
25
26static void disable_prefixing(void)
27{
28 set_prefix(0);
29
30 memcpy((void *)&lowcore->subchannel_id, prefix_page + 0xB8, 12);
31}
32
33static bool is_read_tic_ccw_chain(Ccw0 *ccw)
34{
35 Ccw0 *next_ccw = ccw + 1;
36
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);
40}
41
42static bool dynamic_cp_fixup(uint32_t ccw_addr, uint32_t *next_cpa)
43{
44 Ccw0 *cur_ccw = (Ccw0 *)(uint64_t)ccw_addr;
45 Ccw0 *tic_ccw;
46
47 while (true) {
48
49 if (cur_ccw->cmd_code == CCW_CMD_TIC &&
50 cur_ccw->cda == ptr2u32(cur_ccw) - 8) {
51 cur_ccw += 1;
52 continue;
53 }
54
55 if (!cur_ccw->chain) {
56 break;
57 }
58 if (is_read_tic_ccw_chain(cur_ccw)) {
59
60
61
62
63
64
65 tic_ccw = cur_ccw + 1;
66 *next_cpa = tic_ccw->cda;
67 cur_ccw->chain = 0;
68 return true;
69 }
70 cur_ccw += 1;
71 }
72 return false;
73}
74
75static int run_dynamic_ccw_program(SubChannelId schid, uint16_t cutype,
76 uint32_t cpa)
77{
78 bool has_next;
79 uint32_t next_cpa = 0;
80 int rc;
81
82 do {
83 has_next = dynamic_cp_fixup(cpa, &next_cpa);
84
85 print_int("executing ccw chain at ", cpa);
86 enable_prefixing();
87 rc = do_cio(schid, cutype, cpa, CCW_FMT0);
88 disable_prefixing();
89
90 if (rc) {
91 break;
92 }
93 cpa = next_cpa;
94 } while (has_next);
95
96 return rc;
97}
98
99static void make_readipl(void)
100{
101 Ccw0 *ccwIplRead = (Ccw0 *)0x00;
102
103
104 memset(ccwIplRead, 0, sizeof(Ccw0));
105
106
107 ccwIplRead->cmd_code = CCW_CMD_READ_IPL;
108 ccwIplRead->cda = 0x00;
109 ccwIplRead->chain = 0;
110 ccwIplRead->count = 0x18;
111}
112
113static void run_readipl(SubChannelId schid, uint16_t cutype)
114{
115 if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
116 panic("dasd-ipl: Failed to run Read IPL channel program\n");
117 }
118}
119
120
121
122
123
124static void check_ipl1(void)
125{
126 Ccw0 *ccwread = (Ccw0 *)0x08;
127 Ccw0 *ccwtic = (Ccw0 *)0x10;
128
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");
132 }
133}
134
135static void check_ipl2(uint32_t ipl2_addr)
136{
137 Ccw0 *ccw = u32toptr(ipl2_addr);
138
139 if (ipl2_addr == 0x00) {
140 panic("IPL2 address invalid. Is this disk really bootable?\n");
141 }
142 if (ccw->cmd_code == 0x00) {
143 panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
144 }
145}
146
147static uint32_t read_ipl2_addr(void)
148{
149 Ccw0 *ccwtic = (Ccw0 *)0x10;
150
151 return ccwtic->cda;
152}
153
154static void ipl1_fixup(void)
155{
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;
162
163
164 memcpy(ccwRead, (void *)0x08, 16);
165
166
167 ccwRead->chain = 0x00;
168
169 ccwSeek->cmd_code = CCW_CMD_DASD_SEEK;
170 ccwSeek->cda = ptr2u32(seekData);
171 ccwSeek->chain = 1;
172 ccwSeek->count = sizeof(*seekData);
173 seekData->reserved = 0x00;
174 seekData->cyl = 0x00;
175 seekData->head = 0x00;
176
177 ccwSearchID->cmd_code = CCW_CMD_DASD_SEARCH_ID_EQ;
178 ccwSearchID->cda = ptr2u32(searchData);
179 ccwSearchID->chain = 1;
180 ccwSearchID->count = sizeof(*searchData);
181 searchData->cyl = 0;
182 searchData->head = 0;
183 searchData->record = 2;
184
185
186 ccwSearchTic->cmd_code = CCW_CMD_TIC;
187 ccwSearchTic->cda = ptr2u32(ccwSearchID);
188}
189
190static void run_ipl1(SubChannelId schid, uint16_t cutype)
191 {
192 uint32_t startAddr = 0x08;
193
194 if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
195 panic("dasd-ipl: Failed to run IPL1 channel program\n");
196 }
197}
198
199static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
200{
201 if (run_dynamic_ccw_program(schid, cutype, addr)) {
202 panic("dasd-ipl: Failed to run IPL2 channel program\n");
203 }
204}
205
206
207
208
209
210void dasd_ipl(SubChannelId schid, uint16_t cutype)
211{
212 PSWLegacy *pswl = (PSWLegacy *) 0x00;
213 uint32_t ipl2_addr;
214
215
216 make_readipl();
217 run_readipl(schid, cutype);
218 ipl2_addr = read_ipl2_addr();
219 check_ipl1();
220
221
222
223
224
225 ipl1_fixup();
226 run_ipl1(schid, cutype);
227 check_ipl2(ipl2_addr);
228
229
230
231
232 run_ipl2(schid, cutype, ipl2_addr);
233
234
235 pswl->mask |= PSW_MASK_EAMODE;
236 pswl->addr |= PSW_MASK_BAMODE;
237 jump_to_low_kernel();
238}
239