1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright IBM Corp. 2015
4 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
5 */
6
7 #include <linux/kernel.h>
8 #include <asm/processor.h>
9 #include <asm/lowcore.h>
10 #include <asm/ebcdic.h>
11 #include <asm/irq.h>
12 #include <asm/sections.h>
13 #include <asm/mem_detect.h>
14 #include "sclp.h"
15 #include "sclp_rw.h"
16
17 static struct read_info_sccb __bootdata(sclp_info_sccb);
18 static int __bootdata(sclp_info_sccb_valid);
19 char *sclp_early_sccb = (char *) EARLY_SCCB_OFFSET;
20 int sclp_init_state = sclp_init_state_uninitialized;
21 /*
22 * Used to keep track of the size of the event masks. Qemu until version 2.11
23 * only supports 4 and needs a workaround.
24 */
25 bool sclp_mask_compat_mode;
26
sclp_early_wait_irq(void)27 void sclp_early_wait_irq(void)
28 {
29 unsigned long psw_mask, addr;
30 psw_t psw_ext_save, psw_wait;
31 union ctlreg0 cr0, cr0_new;
32
33 __ctl_store(cr0.val, 0, 0);
34 cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK;
35 cr0_new.lap = 0;
36 cr0_new.sssm = 1;
37 __ctl_load(cr0_new.val, 0, 0);
38
39 psw_ext_save = S390_lowcore.external_new_psw;
40 psw_mask = __extract_psw();
41 S390_lowcore.external_new_psw.mask = psw_mask;
42 psw_wait.mask = psw_mask | PSW_MASK_EXT | PSW_MASK_WAIT;
43 S390_lowcore.ext_int_code = 0;
44
45 do {
46 asm volatile(
47 " larl %[addr],0f\n"
48 " stg %[addr],%[psw_wait_addr]\n"
49 " stg %[addr],%[psw_ext_addr]\n"
50 " lpswe %[psw_wait]\n"
51 "0:\n"
52 : [addr] "=&d" (addr),
53 [psw_wait_addr] "=Q" (psw_wait.addr),
54 [psw_ext_addr] "=Q" (S390_lowcore.external_new_psw.addr)
55 : [psw_wait] "Q" (psw_wait)
56 : "cc", "memory");
57 } while (S390_lowcore.ext_int_code != EXT_IRQ_SERVICE_SIG);
58
59 S390_lowcore.external_new_psw = psw_ext_save;
60 __ctl_load(cr0.val, 0, 0);
61 }
62
sclp_early_cmd(sclp_cmdw_t cmd,void * sccb)63 int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb)
64 {
65 unsigned long flags;
66 int rc;
67
68 raw_local_irq_save(flags);
69 rc = sclp_service_call(cmd, sccb);
70 if (rc)
71 goto out;
72 sclp_early_wait_irq();
73 out:
74 raw_local_irq_restore(flags);
75 return rc;
76 }
77
78 struct write_sccb {
79 struct sccb_header header;
80 struct msg_buf msg;
81 } __packed;
82
83 /* Output multi-line text using SCLP Message interface. */
sclp_early_print_lm(const char * str,unsigned int len)84 static void sclp_early_print_lm(const char *str, unsigned int len)
85 {
86 unsigned char *ptr, *end, ch;
87 unsigned int count, offset;
88 struct write_sccb *sccb;
89 struct msg_buf *msg;
90 struct mdb *mdb;
91 struct mto *mto;
92 struct go *go;
93
94 sccb = (struct write_sccb *) sclp_early_sccb;
95 end = (unsigned char *) sccb + EARLY_SCCB_SIZE - 1;
96 memset(sccb, 0, sizeof(*sccb));
97 ptr = (unsigned char *) &sccb->msg.mdb.mto;
98 offset = 0;
99 do {
100 for (count = sizeof(*mto); offset < len; count++) {
101 ch = str[offset++];
102 if ((ch == 0x0a) || (ptr + count > end))
103 break;
104 ptr[count] = _ascebc[ch];
105 }
106 mto = (struct mto *) ptr;
107 memset(mto, 0, sizeof(*mto));
108 mto->length = count;
109 mto->type = 4;
110 mto->line_type_flags = LNTPFLGS_ENDTEXT;
111 ptr += count;
112 } while ((offset < len) && (ptr + sizeof(*mto) <= end));
113 len = ptr - (unsigned char *) sccb;
114 sccb->header.length = len - offsetof(struct write_sccb, header);
115 msg = &sccb->msg;
116 msg->header.type = EVTYP_MSG;
117 msg->header.length = len - offsetof(struct write_sccb, msg.header);
118 mdb = &msg->mdb;
119 mdb->header.type = 1;
120 mdb->header.tag = 0xD4C4C240;
121 mdb->header.revision_code = 1;
122 mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header);
123 go = &mdb->go;
124 go->length = sizeof(*go);
125 go->type = 1;
126 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
127 }
128
129 struct vt220_sccb {
130 struct sccb_header header;
131 struct {
132 struct evbuf_header header;
133 char data[];
134 } msg;
135 } __packed;
136
137 /* Output multi-line text using SCLP VT220 interface. */
sclp_early_print_vt220(const char * str,unsigned int len)138 static void sclp_early_print_vt220(const char *str, unsigned int len)
139 {
140 struct vt220_sccb *sccb;
141
142 sccb = (struct vt220_sccb *) sclp_early_sccb;
143 if (sizeof(*sccb) + len >= EARLY_SCCB_SIZE)
144 len = EARLY_SCCB_SIZE - sizeof(*sccb);
145 memset(sccb, 0, sizeof(*sccb));
146 memcpy(&sccb->msg.data, str, len);
147 sccb->header.length = sizeof(*sccb) + len;
148 sccb->msg.header.length = sizeof(sccb->msg) + len;
149 sccb->msg.header.type = EVTYP_VT220MSG;
150 sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb);
151 }
152
sclp_early_set_event_mask(struct init_sccb * sccb,sccb_mask_t receive_mask,sccb_mask_t send_mask)153 int sclp_early_set_event_mask(struct init_sccb *sccb,
154 sccb_mask_t receive_mask,
155 sccb_mask_t send_mask)
156 {
157 retry:
158 memset(sccb, 0, sizeof(*sccb));
159 sccb->header.length = sizeof(*sccb);
160 if (sclp_mask_compat_mode)
161 sccb->mask_length = SCLP_MASK_SIZE_COMPAT;
162 else
163 sccb->mask_length = sizeof(sccb_mask_t);
164 sccb_set_recv_mask(sccb, receive_mask);
165 sccb_set_send_mask(sccb, send_mask);
166 if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb))
167 return -EIO;
168 if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) {
169 sclp_mask_compat_mode = true;
170 goto retry;
171 }
172 if (sccb->header.response_code != 0x20)
173 return -EIO;
174 return 0;
175 }
176
sclp_early_con_check_linemode(struct init_sccb * sccb)177 unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb)
178 {
179 if (!(sccb_get_sclp_send_mask(sccb) & EVTYP_OPCMD_MASK))
180 return 0;
181 if (!(sccb_get_sclp_recv_mask(sccb) & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK)))
182 return 0;
183 return 1;
184 }
185
sclp_early_con_check_vt220(struct init_sccb * sccb)186 unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb)
187 {
188 if (sccb_get_sclp_send_mask(sccb) & EVTYP_VT220MSG_MASK)
189 return 1;
190 return 0;
191 }
192
sclp_early_setup(int disable,int * have_linemode,int * have_vt220)193 static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220)
194 {
195 unsigned long receive_mask, send_mask;
196 struct init_sccb *sccb;
197 int rc;
198
199 BUILD_BUG_ON(sizeof(struct init_sccb) > PAGE_SIZE);
200
201 *have_linemode = *have_vt220 = 0;
202 sccb = (struct init_sccb *) sclp_early_sccb;
203 receive_mask = disable ? 0 : EVTYP_OPCMD_MASK;
204 send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK;
205 rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask);
206 if (rc)
207 return rc;
208 *have_linemode = sclp_early_con_check_linemode(sccb);
209 *have_vt220 = !!(sccb_get_send_mask(sccb) & EVTYP_VT220MSG_MASK);
210 return rc;
211 }
212
213 /*
214 * Output one or more lines of text on the SCLP console (VT220 and /
215 * or line-mode).
216 */
__sclp_early_printk(const char * str,unsigned int len)217 void __sclp_early_printk(const char *str, unsigned int len)
218 {
219 int have_linemode, have_vt220;
220
221 if (sclp_init_state != sclp_init_state_uninitialized)
222 return;
223 if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0)
224 return;
225 if (have_linemode)
226 sclp_early_print_lm(str, len);
227 if (have_vt220)
228 sclp_early_print_vt220(str, len);
229 sclp_early_setup(1, &have_linemode, &have_vt220);
230 }
231
sclp_early_printk(const char * str)232 void sclp_early_printk(const char *str)
233 {
234 __sclp_early_printk(str, strlen(str));
235 }
236
sclp_early_read_info(void)237 int __init sclp_early_read_info(void)
238 {
239 int i;
240 struct read_info_sccb *sccb = &sclp_info_sccb;
241 sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
242 SCLP_CMDW_READ_SCP_INFO};
243
244 for (i = 0; i < ARRAY_SIZE(commands); i++) {
245 memset(sccb, 0, sizeof(*sccb));
246 sccb->header.length = sizeof(*sccb);
247 sccb->header.function_code = 0x80;
248 sccb->header.control_mask[2] = 0x80;
249 if (sclp_early_cmd(commands[i], sccb))
250 break;
251 if (sccb->header.response_code == 0x10) {
252 sclp_info_sccb_valid = 1;
253 return 0;
254 }
255 if (sccb->header.response_code != 0x1f0)
256 break;
257 }
258 return -EIO;
259 }
260
sclp_early_get_info(struct read_info_sccb * info)261 int __init sclp_early_get_info(struct read_info_sccb *info)
262 {
263 if (!sclp_info_sccb_valid)
264 return -EIO;
265
266 *info = sclp_info_sccb;
267 return 0;
268 }
269
sclp_early_get_memsize(unsigned long * mem)270 int __init sclp_early_get_memsize(unsigned long *mem)
271 {
272 unsigned long rnmax;
273 unsigned long rnsize;
274 struct read_info_sccb *sccb = &sclp_info_sccb;
275
276 if (!sclp_info_sccb_valid)
277 return -EIO;
278
279 rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
280 rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
281 rnsize <<= 20;
282 *mem = rnsize * rnmax;
283 return 0;
284 }
285
sclp_early_get_hsa_size(unsigned long * hsa_size)286 int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
287 {
288 if (!sclp_info_sccb_valid)
289 return -EIO;
290
291 *hsa_size = 0;
292 if (sclp_info_sccb.hsa_size)
293 *hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
294 return 0;
295 }
296
297 #define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL
298
add_mem_detect_block(u64 start,u64 end)299 void __weak __init add_mem_detect_block(u64 start, u64 end) {}
sclp_early_read_storage_info(void)300 int __init sclp_early_read_storage_info(void)
301 {
302 struct read_storage_sccb *sccb = (struct read_storage_sccb *)sclp_early_sccb;
303 int rc, id, max_id = 0;
304 unsigned long rn, rzm;
305 sclp_cmdw_t command;
306 u16 sn;
307
308 if (!sclp_info_sccb_valid)
309 return -EIO;
310
311 if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
312 return -EOPNOTSUPP;
313
314 rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
315 rzm <<= 20;
316
317 for (id = 0; id <= max_id; id++) {
318 memset(sclp_early_sccb, 0, EARLY_SCCB_SIZE);
319 sccb->header.length = EARLY_SCCB_SIZE;
320 command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
321 rc = sclp_early_cmd(command, sccb);
322 if (rc)
323 goto fail;
324
325 max_id = sccb->max_id;
326 switch (sccb->header.response_code) {
327 case 0x0010:
328 for (sn = 0; sn < sccb->assigned; sn++) {
329 if (!sccb->entries[sn])
330 continue;
331 rn = sccb->entries[sn] >> 16;
332 add_mem_detect_block((rn - 1) * rzm, rn * rzm);
333 }
334 break;
335 case 0x0310:
336 case 0x0410:
337 break;
338 default:
339 goto fail;
340 }
341 }
342
343 return 0;
344 fail:
345 mem_detect.count = 0;
346 return -EIO;
347 }
348