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 ccwIplRead->cmd_code = CCW_CMD_READ_IPL;
105 ccwIplRead->cda = 0x00;
106 ccwIplRead->chain = 0;
107 ccwIplRead->count = 0x18;
108}
109
110static void run_readipl(SubChannelId schid, uint16_t cutype)
111{
112 if (do_cio(schid, cutype, 0x00, CCW_FMT0)) {
113 panic("dasd-ipl: Failed to run Read IPL channel program\n");
114 }
115}
116
117
118
119
120
121static void check_ipl1(void)
122{
123 Ccw0 *ccwread = (Ccw0 *)0x08;
124 Ccw0 *ccwtic = (Ccw0 *)0x10;
125
126 if (ccwread->cmd_code != CCW_CMD_DASD_READ ||
127 ccwtic->cmd_code != CCW_CMD_TIC) {
128 panic("dasd-ipl: IPL1 data invalid. Is this disk really bootable?\n");
129 }
130}
131
132static void check_ipl2(uint32_t ipl2_addr)
133{
134 Ccw0 *ccw = u32toptr(ipl2_addr);
135
136 if (ipl2_addr == 0x00) {
137 panic("IPL2 address invalid. Is this disk really bootable?\n");
138 }
139 if (ccw->cmd_code == 0x00) {
140 panic("IPL2 ccw data invalid. Is this disk really bootable?\n");
141 }
142}
143
144static uint32_t read_ipl2_addr(void)
145{
146 Ccw0 *ccwtic = (Ccw0 *)0x10;
147
148 return ccwtic->cda;
149}
150
151static void ipl1_fixup(void)
152{
153 Ccw0 *ccwSeek = (Ccw0 *) 0x08;
154 Ccw0 *ccwSearchID = (Ccw0 *) 0x10;
155 Ccw0 *ccwSearchTic = (Ccw0 *) 0x18;
156 Ccw0 *ccwRead = (Ccw0 *) 0x20;
157 CcwSeekData *seekData = (CcwSeekData *) 0x30;
158 CcwSearchIdData *searchData = (CcwSearchIdData *) 0x38;
159
160
161 memcpy(ccwRead, (void *)0x08, 16);
162
163
164 ccwRead->chain = 0x00;
165
166 ccwSeek->cmd_code = CCW_CMD_DASD_SEEK;
167 ccwSeek->cda = ptr2u32(seekData);
168 ccwSeek->chain = 1;
169 ccwSeek->count = sizeof(*seekData);
170 seekData->reserved = 0x00;
171 seekData->cyl = 0x00;
172 seekData->head = 0x00;
173
174 ccwSearchID->cmd_code = CCW_CMD_DASD_SEARCH_ID_EQ;
175 ccwSearchID->cda = ptr2u32(searchData);
176 ccwSearchID->chain = 1;
177 ccwSearchID->count = sizeof(*searchData);
178 searchData->cyl = 0;
179 searchData->head = 0;
180 searchData->record = 2;
181
182
183 ccwSearchTic->cmd_code = CCW_CMD_TIC;
184 ccwSearchTic->cda = ptr2u32(ccwSearchID);
185}
186
187static void run_ipl1(SubChannelId schid, uint16_t cutype)
188 {
189 uint32_t startAddr = 0x08;
190
191 if (do_cio(schid, cutype, startAddr, CCW_FMT0)) {
192 panic("dasd-ipl: Failed to run IPL1 channel program\n");
193 }
194}
195
196static void run_ipl2(SubChannelId schid, uint16_t cutype, uint32_t addr)
197{
198 if (run_dynamic_ccw_program(schid, cutype, addr)) {
199 panic("dasd-ipl: Failed to run IPL2 channel program\n");
200 }
201}
202
203
204
205
206
207void dasd_ipl(SubChannelId schid, uint16_t cutype)
208{
209 PSWLegacy *pswl = (PSWLegacy *) 0x00;
210 uint32_t ipl2_addr;
211
212
213 make_readipl();
214 run_readipl(schid, cutype);
215 ipl2_addr = read_ipl2_addr();
216 check_ipl1();
217
218
219
220
221
222 ipl1_fixup();
223 run_ipl1(schid, cutype);
224 check_ipl2(ipl2_addr);
225
226
227
228
229 run_ipl2(schid, cutype, ipl2_addr);
230
231
232 pswl->mask |= PSW_MASK_EAMODE;
233 pswl->addr |= PSW_MASK_BAMODE;
234 jump_to_low_kernel();
235}
236