xref: /kvm-unit-tests/lib/s390x/sclp-console.c (revision d1e2a8e2d0d5856f1a6ce23ea3f044a1532eab40)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3  * SCLP line mode and ASCII console driver
4  * Some parts taken from the Linux kernel.
5  *
6  * Copyright (c) 2013 Alexander Graf <agraf@suse.de>
7  *
8  * Copyright IBM Corp. 1999
9  * Author(s): Martin Peschke <mpeschke@de.ibm.com>
10  *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
11  */
12 
13 #include <libcflat.h>
14 #include <string.h>
15 #include <asm/page.h>
16 #include <asm/arch_def.h>
17 #include <asm/io.h>
18 #include <asm/spinlock.h>
19 #include "hardware.h"
20 #include "sclp.h"
21 
22 /*
23  * ASCII (IBM PC 437) -> EBCDIC 037
24  */
25 static uint8_t _ascebc[256] = {
26  /*00 NUL   SOH   STX   ETX   EOT   ENQ   ACK   BEL */
27      0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
28  /*08  BS    HT    LF    VT    FF    CR    SO    SI */
29  /*              ->NL                               */
30      0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
31  /*10 DLE   DC1   DC2   DC3   DC4   NAK   SYN   ETB */
32      0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
33  /*18 CAN    EM   SUB   ESC    FS    GS    RS    US */
34  /*                               ->IGS ->IRS ->IUS */
35      0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
36  /*20  SP     !     "     #     $     %     &     ' */
37      0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
38  /*28   (     )     *     +     ,     -    .      / */
39      0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
40  /*30   0     1     2     3     4     5     6     7 */
41      0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
42  /*38   8     9     :     ;     <     =     >     ? */
43      0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
44  /*40   @     A     B     C     D     E     F     G */
45      0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
46  /*48   H     I     J     K     L     M     N     O */
47      0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
48  /*50   P     Q     R     S     T     U     V     W */
49      0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
50  /*58   X     Y     Z     [     \     ]     ^     _ */
51      0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
52  /*60   `     a     b     c     d     e     f     g */
53      0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
54  /*68   h     i     j     k     l     m     n     o */
55      0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
56  /*70   p     q     r     s     t     u     v     w */
57      0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
58  /*78   x     y     z     {     |     }     ~    DL */
59      0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
60  /*80*/
61      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
62  /*88*/
63      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
64  /*90*/
65      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
66  /*98*/
67      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
68  /*A0*/
69      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
70  /*A8*/
71      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
72  /*B0*/
73      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
74  /*B8*/
75      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
76  /*C0*/
77      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
78  /*C8*/
79      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
80  /*D0*/
81      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
82  /*D8*/
83      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
84  /*E0        sz	*/
85      0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
86  /*E8*/
87      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
88  /*F0*/
89      0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
90  /*F8*/
91      0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
92 };
93 
94 static const uint8_t _ebcasc[] = {
95 	0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
96 	0x07, 0x07, 0x07, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
97 	0x10, 0x11, 0x12, 0x13, 0x07, 0x0A, 0x08, 0x07,
98 	0x18, 0x19, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
99 	0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
100 	0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
101 	0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
102 	0x07, 0x07, 0x07, 0x07, 0x14, 0x15, 0x07, 0x1A,
103 	0x20, 0xFF, 0x83, 0x84, 0x85, 0xA0, 0x07, 0x86,
104 	0x87, 0xA4, 0x5B, 0x2E, 0x3C, 0x28, 0x2B, 0x21,
105 	0x26, 0x82, 0x88, 0x89, 0x8A, 0xA1, 0x8C, 0x07,
106 	0x8D, 0xE1, 0x5D, 0x24, 0x2A, 0x29, 0x3B, 0x5E,
107 	0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
108 	0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
109 	0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
110 	0x70, 0x60, 0x3A, 0x23, 0x40, 0x27, 0x3D, 0x22,
111 	0x07, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
112 	0x68, 0x69, 0xAE, 0xAF, 0x07, 0x07, 0x07, 0xF1,
113 	0xF8, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70,
114 	0x71, 0x72, 0xA6, 0xA7, 0x91, 0x07, 0x92, 0x07,
115 	0xE6, 0x7E, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
116 	0x79, 0x7A, 0xAD, 0xAB, 0x07, 0x07, 0x07, 0x07,
117 	0x9B, 0x9C, 0x9D, 0xFA, 0x07, 0x07, 0x07, 0xAC,
118 	0xAB, 0x07, 0xAA, 0x7C, 0x07, 0x07, 0x07, 0x07,
119 	0x7B, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
120 	0x48, 0x49, 0x07, 0x93, 0x94, 0x95, 0xA2, 0x07,
121 	0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
122 	0x51, 0x52, 0x07, 0x96, 0x81, 0x97, 0xA3, 0x98,
123 	0x5C, 0xF6, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
124 	0x59, 0x5A, 0xFD, 0x07, 0x99, 0x07, 0x07, 0x07,
125 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
126 	0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07,
127 };
128 
129 static bool lpar_ascii_compat;
130 
131 static char lm_buff[120];
132 static unsigned char lm_buff_off;
133 static struct spinlock lm_buff_lock;
134 
135 static char read_buf[4096];
136 static int read_index = sizeof(read_buf) - 1;
137 static int read_buf_length = 0;
138 
sclp_print_ascii(const char * str)139 static void sclp_print_ascii(const char *str)
140 {
141 	int len = strlen(str);
142 	WriteEventData *sccb = (void *)_sccb;
143 	char *str_dest = (char *)&sccb->msg;
144 	int src_ind, dst_ind;
145 
146 	sclp_mark_busy();
147 	memset(sccb, 0, sizeof(*sccb));
148 
149 	for (src_ind = 0, dst_ind = 0;
150 	     src_ind < len && dst_ind < (PAGE_SIZE / 2);
151 	     src_ind++, dst_ind++) {
152 		str_dest[dst_ind] = str[src_ind];
153 		/* Add a \r to the \n for HMC ASCII console */
154 		if (str[src_ind] == '\n' && lpar_ascii_compat) {
155 			dst_ind++;
156 			str_dest[dst_ind] = '\r';
157 		}
158 	}
159 
160 	/* Len might have changed because of the compat behavior */
161 	len = dst_ind;
162 	sccb->h.length = offsetof(WriteEventData, msg) + len;
163 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
164 	sccb->ebh.length = sizeof(EventBufferHeader) + len;
165 	sccb->ebh.type = SCLP_EVENT_ASCII_CONSOLE_DATA;
166 
167 	sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
168 }
169 
lm_print(const char * buff,int len)170 static void lm_print(const char *buff, int len)
171 {
172 	unsigned char *ptr, *end, ch;
173 	unsigned int count, offset;
174 	struct WriteEventData *sccb;
175 	struct mdb *mdb;
176 	struct mto *mto;
177 	struct go *go;
178 
179 	sclp_mark_busy();
180 	sccb = (struct WriteEventData *) _sccb;
181 	end = (unsigned char *) sccb + 4096 - 1;
182 	memset(sccb, 0, sizeof(*sccb));
183 	ptr = (unsigned char *) &sccb->msg.mdb.mto;
184 	offset = 0;
185 	do {
186 		for (count = sizeof(*mto); offset < len; count++) {
187 			ch = buff[offset++];
188 			if (ch == 0x0a || ptr + count > end)
189 				break;
190 			ptr[count] = _ascebc[ch];
191 		}
192 		mto = (struct mto *) ptr;
193 		mto->length = count;
194 		mto->type = 4;
195 		mto->line_type_flags = LNTPFLGS_ENDTEXT;
196 		ptr += count;
197 	} while (offset < len && ptr + sizeof(*mto) <= end);
198 	len = ptr - (unsigned char *) sccb;
199 	sccb->h.length = len - offsetof(struct WriteEventData, h);
200 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
201 	sccb->ebh.type = EVTYP_MSG;
202 	sccb->ebh.length = len - offsetof(struct WriteEventData, ebh);
203 	mdb = &sccb->msg.mdb;
204 	mdb->header.type = 1;
205 	mdb->header.tag = 0xD4C4C240;
206 	mdb->header.revision_code = 1;
207 	mdb->header.length = len - offsetof(struct WriteEventData, msg.mdb.header);
208 	go = &mdb->go;
209 	go->length = sizeof(*go);
210 	go->type = 1;
211 	sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
212 }
213 
214 
215 /*
216  * In contrast to the ascii console, linemode produces a new
217  * line with every write of data. The report() function uses
218  * several printf() calls to generate a line of data which
219  * would all end up on different lines.
220  *
221  * Hence we buffer here until we encounter a \n or the buffer
222  * is full. That means that linemode output can look a bit
223  * different from ascii and that it takes a bit longer for
224  * lines to appear.
225  */
sclp_print_lm(const char * str)226 static void sclp_print_lm(const char *str)
227 {
228 	int i;
229 	const int len = strlen(str);
230 
231 	spin_lock(&lm_buff_lock);
232 
233 	for (i = 0; i < len; i++) {
234 		lm_buff[lm_buff_off++] = str[i];
235 
236 		/* Buffer full or newline? */
237 		if (str[i] == '\n' || lm_buff_off == (ARRAY_SIZE(lm_buff) - 1)) {
238 			lm_print(lm_buff, lm_buff_off);
239 			lm_buff_off = 0;
240 		}
241 	}
242 	spin_unlock(&lm_buff_lock);
243 }
244 
245 /*
246  * SCLP needs to be initialized by setting a send and receive mask,
247  * indicating which messages the control program (we) want(s) to
248  * send/receive.
249  */
sclp_write_event_mask(int receive_mask,int send_mask)250 static void sclp_write_event_mask(int receive_mask, int send_mask)
251 {
252 	WriteEventMask *sccb = (void *)_sccb;
253 
254 	sclp_mark_busy();
255 	memset(_sccb, 0, sizeof(*sccb));
256 	sccb->h.length = sizeof(WriteEventMask);
257 	sccb->h.function_code = SCLP_FC_NORMAL_WRITE;
258 	sccb->mask_length = sizeof(sccb_mask_t);
259 
260 	sccb->cp_receive_mask = receive_mask;
261 	sccb->cp_send_mask = send_mask;
262 
263 	sclp_service_call(SCLP_CMD_WRITE_EVENT_MASK, sccb);
264 	assert(sccb->h.response_code == SCLP_RC_NORMAL_COMPLETION);
265 }
266 
sclp_console_enable_read(void)267 static void sclp_console_enable_read(void)
268 {
269 	sclp_write_event_mask(SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_OPCMD,
270 			      SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
271 }
272 
sclp_console_disable_read(void)273 static void sclp_console_disable_read(void)
274 {
275 	sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
276 }
277 
sclp_console_setup(void)278 void sclp_console_setup(void)
279 {
280 	lpar_ascii_compat = detect_host() == HOST_IS_LPAR;
281 
282 	/* We send ASCII and line mode. */
283 	sclp_write_event_mask(0, SCLP_EVENT_MASK_MSG_ASCII | SCLP_EVENT_MASK_MSG);
284 	/* Hard terminal reset to clear screen for HMC ASCII console */
285 	if (lpar_ascii_compat)
286 		sclp_print_ascii("\ec");
287 }
288 
sclp_print(const char * str)289 void sclp_print(const char *str)
290 {
291 	/*
292 	 * z/VM advertises a vt220 console which is not functional:
293 	 * (response code 05F0, "not active because of the state of
294 	 * the machine"). Hence testing the masks would only work if
295 	 * we also use stsi data to distinguish z/VM.
296 	 *
297 	 * Let's rather print on all available consoles.
298 	 */
299 	if (strlen(str) > (PAGE_SIZE / 2)) {
300 		sclp_print_ascii("Warning: Printing is limited to 2KB of data.");
301 		sclp_print_lm("Warning: Printing is limited to 2KB of data.");
302 		return;
303 	}
304 	sclp_print_ascii(str);
305 	sclp_print_lm(str);
306 }
307 
console_read_ascii(struct EventBufferHeader * ebh,int * len)308 static char *console_read_ascii(struct EventBufferHeader *ebh, int *len)
309 {
310 	struct ReadEventDataAsciiConsole *evdata = (void *)ebh;
311 	const int max_event_buffer_len = SCCB_SIZE - offsetof(ReadEventDataAsciiConsole, ebh);
312 	const int event_buffer_ascii_recv_header_len = offsetof(ReadEventDataAsciiConsole, data);
313 
314 	assert(ebh->length <= max_event_buffer_len);
315 	assert(ebh->length > event_buffer_ascii_recv_header_len);
316 
317 	*len = ebh->length - event_buffer_ascii_recv_header_len;
318 	return evdata->data;
319 }
320 
321 
sclp_find_gds_vector(void * start,void * end,uint16_t id)322 static struct gds_vector *sclp_find_gds_vector(void *start, void *end, uint16_t id)
323 {
324 	struct gds_vector *v;
325 
326 	for (v = start; (void *)v < end; v = (void *)v + v->length)
327 		if (v->gds_id == id)
328 			return v;
329 	return NULL;
330 }
331 
sclp_eval_selfdeftextmsg(struct gds_subvector * sv)332 static struct gds_subvector *sclp_eval_selfdeftextmsg(struct gds_subvector *sv)
333 {
334 	void *end;
335 
336 	end = (void *)sv + sv->length;
337 	for (sv = sv + 1; (void *)sv < end; sv = (void *)sv + sv->length)
338 		if (sv->key == 0x30)
339 			return sv;
340 	return NULL;
341 }
342 
sclp_eval_textcmd(struct gds_vector * v)343 static struct gds_subvector *sclp_eval_textcmd(struct gds_vector *v)
344 {
345 	struct gds_subvector *sv;
346 	void *end;
347 
348 	end = (void *)v + v->length;
349 	for (sv = (struct gds_subvector *)(v + 1); (void *)sv < end;
350 	     sv = (void *)sv + sv->length)
351 		if (sv->key == GDS_KEY_SELFDEFTEXTMSG)
352 			return sclp_eval_selfdeftextmsg(sv);
353 	return NULL;
354 }
355 
sclp_eval_cpmsu(struct gds_vector * v)356 static struct gds_subvector *sclp_eval_cpmsu(struct gds_vector *v)
357 {
358 	void *end;
359 
360 	end = (void *)v + v->length;
361 	for (v = v + 1; (void *)v < end; v = (void *)v + v->length)
362 		if (v->gds_id == GDS_ID_TEXTCMD)
363 			return sclp_eval_textcmd(v);
364 	return NULL;
365 }
366 
sclp_eval_mdsmu(struct gds_vector * v)367 static struct gds_subvector *sclp_eval_mdsmu(struct gds_vector *v)
368 {
369 	v = sclp_find_gds_vector(v + 1, (void *)v + v->length, GDS_ID_CPMSU);
370 	if (v)
371 		return sclp_eval_cpmsu(v);
372 	return NULL;
373 }
374 
console_read_lm(struct EventBufferHeader * ebh,int * len)375 static char *console_read_lm(struct EventBufferHeader *ebh, int *len)
376 {
377 	struct gds_vector *v = (void *)ebh + sizeof(*ebh);
378 	struct gds_subvector *sv;
379 
380 	v = sclp_find_gds_vector(v, (void *)ebh + ebh->length,
381 				 GDS_ID_MDSMU);
382 	if (!v)
383 		return NULL;
384 
385 	sv = sclp_eval_mdsmu(v);
386 	if (!sv)
387 		return NULL;
388 
389 	*len = sv->length - (sizeof(*sv));
390 	return (char *)(sv + 1);
391 }
392 
ebc_to_asc(char * data,int len)393 static void ebc_to_asc(char *data, int len)
394 {
395 	int i;
396 
397 	for (i = 0; i < len; i++)
398 		data[i] = _ebcasc[(uint8_t)data[i]];
399 }
400 
console_refill_read_buffer(void)401 static int console_refill_read_buffer(void)
402 {
403 	struct SCCBHeader *sccb = (struct SCCBHeader *)_sccb;
404 	struct EventBufferHeader *ebh = (void *)_sccb + sizeof(struct SCCBHeader);
405 	char *data;
406 	int ret = -1, len;
407 
408 	sclp_console_enable_read();
409 
410 	sclp_mark_busy();
411 	memset(_sccb, 0, SCCB_SIZE);
412 	sccb->length = PAGE_SIZE;
413 	sccb->function_code = SCLP_UNCONDITIONAL_READ;
414 	sccb->control_mask[2] = SCLP_CM2_VARIABLE_LENGTH_RESPONSE;
415 
416 	sclp_service_call(SCLP_CMD_READ_EVENT_DATA, sccb);
417 
418 	if (sccb->response_code == SCLP_RC_NO_EVENT_BUFFERS_STORED)
419 		goto out;
420 
421 	switch (ebh->type) {
422 	case SCLP_EVENT_OP_CMD:
423 		data = console_read_lm(ebh, &len);
424 		if (data)
425 			ebc_to_asc(data, len);
426 		break;
427 	case SCLP_EVENT_ASCII_CONSOLE_DATA:
428 		data = console_read_ascii(ebh, &len);
429 		break;
430 	default:
431 		goto out;
432 	}
433 
434 	if (!data)
435 		goto out;
436 
437 	assert(len <= sizeof(read_buf));
438 	memcpy(read_buf, data, len);
439 
440 	read_index = 0;
441 	ret = 0;
442 
443 out:
444 	sclp_console_disable_read();
445 
446 	return ret;
447 }
448 
__getchar(void)449 int __getchar(void)
450 {
451 	int ret;
452 
453 	if (read_index >= read_buf_length) {
454 		ret = console_refill_read_buffer();
455 		if (ret < 0)
456 			return ret;
457 	}
458 
459 	return read_buf[read_index++];
460 }
461