cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sclp_rw.c (11829B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * driver: reading from and writing to system console on S/390 via SCLP
      4 *
      5 * Copyright IBM Corp. 1999, 2009
      6 *
      7 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
      8 *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
      9 */
     10
     11#include <linux/kmod.h>
     12#include <linux/types.h>
     13#include <linux/err.h>
     14#include <linux/string.h>
     15#include <linux/spinlock.h>
     16#include <linux/ctype.h>
     17#include <linux/uaccess.h>
     18
     19#include "sclp.h"
     20#include "sclp_rw.h"
     21
     22/*
     23 * The room for the SCCB (only for writing) is not equal to a pages size
     24 * (as it is specified as the maximum size in the SCLP documentation)
     25 * because of the additional data structure described above.
     26 */
     27#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
     28
     29/* Event type structure for write message and write priority message */
     30static struct sclp_register sclp_rw_event = {
     31	.send_mask = EVTYP_MSG_MASK,
     32};
     33
     34/*
     35 * Setup a sclp write buffer. Gets a page as input (4K) and returns
     36 * a pointer to a struct sclp_buffer structure that is located at the
     37 * end of the input page. This reduces the buffer space by a few
     38 * bytes but simplifies things.
     39 */
     40struct sclp_buffer *
     41sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
     42{
     43	struct sclp_buffer *buffer;
     44	struct sccb_header *sccb;
     45
     46	sccb = (struct sccb_header *) page;
     47	/*
     48	 * We keep the struct sclp_buffer structure at the end
     49	 * of the sccb page.
     50	 */
     51	buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
     52	buffer->sccb = sccb;
     53	buffer->retry_count = 0;
     54	buffer->messages = 0;
     55	buffer->char_sum = 0;
     56	buffer->current_line = NULL;
     57	buffer->current_length = 0;
     58	buffer->columns = columns;
     59	buffer->htab = htab;
     60
     61	/* initialize sccb */
     62	memset(sccb, 0, sizeof(struct sccb_header));
     63	sccb->length = sizeof(struct sccb_header);
     64
     65	return buffer;
     66}
     67
     68/*
     69 * Return a pointer to the original page that has been used to create
     70 * the buffer.
     71 */
     72void *
     73sclp_unmake_buffer(struct sclp_buffer *buffer)
     74{
     75	return buffer->sccb;
     76}
     77
     78/*
     79 * Initialize a new message the end of the provided buffer with
     80 * enough room for max_len characters. Return 0 on success.
     81 */
     82static int
     83sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
     84{
     85	struct sccb_header *sccb;
     86	struct msg_buf *msg;
     87	struct mdb *mdb;
     88	struct go *go;
     89	struct mto *mto;
     90	int msg_size;
     91
     92	/* max size of new message including message text  */
     93	msg_size = sizeof(struct msg_buf) + max_len;
     94
     95	/* check if current buffer sccb can contain the mto */
     96	sccb = buffer->sccb;
     97	if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
     98		return -ENOMEM;
     99
    100	msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
    101	memset(msg, 0, sizeof(struct msg_buf));
    102	msg->header.length = sizeof(struct msg_buf);
    103	msg->header.type = EVTYP_MSG;
    104
    105	mdb = &msg->mdb;
    106	mdb->header.length = sizeof(struct mdb);
    107	mdb->header.type = 1;
    108	mdb->header.tag = 0xD4C4C240;	/* ebcdic "MDB " */
    109	mdb->header.revision_code = 1;
    110
    111	go = &mdb->go;
    112	go->length = sizeof(struct go);
    113	go->type = 1;
    114
    115	mto = &mdb->mto;
    116	mto->length = sizeof(struct mto);
    117	mto->type = 4;	/* message text object */
    118	mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
    119
    120	/* set pointer to first byte after struct mto. */
    121	buffer->current_msg = msg;
    122	buffer->current_line = (char *) (mto + 1);
    123	buffer->current_length = 0;
    124
    125	return 0;
    126}
    127
    128/*
    129 * Finalize message initialized by sclp_initialize_mto(),
    130 * updating the sizes of MTO, enclosing MDB, event buffer and SCCB.
    131 */
    132static void
    133sclp_finalize_mto(struct sclp_buffer *buffer)
    134{
    135	struct sccb_header *sccb;
    136	struct msg_buf *msg;
    137
    138	/*
    139	 * update values of sizes
    140	 * (SCCB, Event(Message) Buffer, Message Data Block)
    141	 */
    142	sccb = buffer->sccb;
    143	msg = buffer->current_msg;
    144	msg->header.length += buffer->current_length;
    145	msg->mdb.header.length += buffer->current_length;
    146	msg->mdb.mto.length += buffer->current_length;
    147	sccb->length += msg->header.length;
    148
    149	/*
    150	 * count number of buffered messages (= number of Message Text
    151	 * Objects) and number of buffered characters
    152	 * for the SCCB currently used for buffering and at all
    153	 */
    154	buffer->messages++;
    155	buffer->char_sum += buffer->current_length;
    156
    157	buffer->current_line = NULL;
    158	buffer->current_length = 0;
    159	buffer->current_msg = NULL;
    160}
    161
    162/*
    163 * processing of a message including escape characters,
    164 * returns number of characters written to the output sccb
    165 * ("processed" means that is not guaranteed that the character have already
    166 *  been sent to the SCLP but that it will be done at least next time the SCLP
    167 *  is not busy)
    168 */
    169int
    170sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
    171{
    172	int spaces, i_msg;
    173	int rc;
    174
    175	/*
    176	 * parse msg for escape sequences (\t,\v ...) and put formated
    177	 * msg into an mto (created by sclp_initialize_mto).
    178	 *
    179	 * We have to do this work ourselfs because there is no support for
    180	 * these characters on the native machine and only partial support
    181	 * under VM (Why does VM interpret \n but the native machine doesn't ?)
    182	 *
    183	 * Depending on i/o-control setting the message is always written
    184	 * immediately or we wait for a final new line maybe coming with the
    185	 * next message. Besides we avoid a buffer overrun by writing its
    186	 * content.
    187	 *
    188	 * RESTRICTIONS:
    189	 *
    190	 * \r and \b work within one line because we are not able to modify
    191	 * previous output that have already been accepted by the SCLP.
    192	 *
    193	 * \t combined with following \r is not correctly represented because
    194	 * \t is expanded to some spaces but \r does not know about a
    195	 * previous \t and decreases the current position by one column.
    196	 * This is in order to a slim and quick implementation.
    197	 */
    198	for (i_msg = 0; i_msg < count; i_msg++) {
    199		switch (msg[i_msg]) {
    200		case '\n':	/* new line, line feed (ASCII)	*/
    201			/* check if new mto needs to be created */
    202			if (buffer->current_line == NULL) {
    203				rc = sclp_initialize_mto(buffer, 0);
    204				if (rc)
    205					return i_msg;
    206			}
    207			sclp_finalize_mto(buffer);
    208			break;
    209		case '\a':	/* bell, one for several times	*/
    210			/* set SCLP sound alarm bit in General Object */
    211			if (buffer->current_line == NULL) {
    212				rc = sclp_initialize_mto(buffer,
    213							 buffer->columns);
    214				if (rc)
    215					return i_msg;
    216			}
    217			buffer->current_msg->mdb.go.general_msg_flags |=
    218				GNRLMSGFLGS_SNDALRM;
    219			break;
    220		case '\t':	/* horizontal tabulator	 */
    221			/* check if new mto needs to be created */
    222			if (buffer->current_line == NULL) {
    223				rc = sclp_initialize_mto(buffer,
    224							 buffer->columns);
    225				if (rc)
    226					return i_msg;
    227			}
    228			/* "go to (next htab-boundary + 1, same line)" */
    229			do {
    230				if (buffer->current_length >= buffer->columns)
    231					break;
    232				/* ok, add a blank */
    233				*buffer->current_line++ = 0x40;
    234				buffer->current_length++;
    235			} while (buffer->current_length % buffer->htab);
    236			break;
    237		case '\f':	/* form feed  */
    238		case '\v':	/* vertical tabulator  */
    239			/* "go to (actual column, actual line + 1)" */
    240			/* = new line, leading spaces */
    241			if (buffer->current_line != NULL) {
    242				spaces = buffer->current_length;
    243				sclp_finalize_mto(buffer);
    244				rc = sclp_initialize_mto(buffer,
    245							 buffer->columns);
    246				if (rc)
    247					return i_msg;
    248				memset(buffer->current_line, 0x40, spaces);
    249				buffer->current_line += spaces;
    250				buffer->current_length = spaces;
    251			} else {
    252				/* one an empty line this is the same as \n */
    253				rc = sclp_initialize_mto(buffer,
    254							 buffer->columns);
    255				if (rc)
    256					return i_msg;
    257				sclp_finalize_mto(buffer);
    258			}
    259			break;
    260		case '\b':	/* backspace  */
    261			/* "go to (actual column - 1, actual line)" */
    262			/* decrement counter indicating position, */
    263			/* do not remove last character */
    264			if (buffer->current_line != NULL &&
    265			    buffer->current_length > 0) {
    266				buffer->current_length--;
    267				buffer->current_line--;
    268			}
    269			break;
    270		case 0x00:	/* end of string  */
    271			/* transfer current line to SCCB */
    272			if (buffer->current_line != NULL)
    273				sclp_finalize_mto(buffer);
    274			/* skip the rest of the message including the 0 byte */
    275			i_msg = count - 1;
    276			break;
    277		default:	/* no escape character	*/
    278			/* do not output unprintable characters */
    279			if (!isprint(msg[i_msg]))
    280				break;
    281			/* check if new mto needs to be created */
    282			if (buffer->current_line == NULL) {
    283				rc = sclp_initialize_mto(buffer,
    284							 buffer->columns);
    285				if (rc)
    286					return i_msg;
    287			}
    288			*buffer->current_line++ = sclp_ascebc(msg[i_msg]);
    289			buffer->current_length++;
    290			break;
    291		}
    292		/* check if current mto is full */
    293		if (buffer->current_line != NULL &&
    294		    buffer->current_length >= buffer->columns)
    295			sclp_finalize_mto(buffer);
    296	}
    297
    298	/* return number of processed characters */
    299	return i_msg;
    300}
    301
    302/*
    303 * Return the number of free bytes in the sccb
    304 */
    305int
    306sclp_buffer_space(struct sclp_buffer *buffer)
    307{
    308	struct sccb_header *sccb;
    309	int count;
    310
    311	sccb = buffer->sccb;
    312	count = MAX_SCCB_ROOM - sccb->length;
    313	if (buffer->current_line != NULL)
    314		count -= sizeof(struct msg_buf) + buffer->current_length;
    315	return count;
    316}
    317
    318/*
    319 * Return number of characters in buffer
    320 */
    321unsigned int
    322sclp_chars_in_buffer(struct sclp_buffer *buffer)
    323{
    324	unsigned int count;
    325
    326	count = buffer->char_sum;
    327	if (buffer->current_line != NULL)
    328		count += buffer->current_length;
    329	return count;
    330}
    331
    332/*
    333 * called by sclp_console_init and/or sclp_tty_init
    334 */
    335int
    336sclp_rw_init(void)
    337{
    338	static int init_done = 0;
    339	int rc;
    340
    341	if (init_done)
    342		return 0;
    343
    344	rc = sclp_register(&sclp_rw_event);
    345	if (rc == 0)
    346		init_done = 1;
    347	return rc;
    348}
    349
    350#define SCLP_BUFFER_MAX_RETRY		1
    351
    352/*
    353 * second half of Write Event Data-function that has to be done after
    354 * interruption indicating completion of Service Call.
    355 */
    356static void
    357sclp_writedata_callback(struct sclp_req *request, void *data)
    358{
    359	int rc;
    360	struct sclp_buffer *buffer;
    361	struct sccb_header *sccb;
    362
    363	buffer = (struct sclp_buffer *) data;
    364	sccb = buffer->sccb;
    365
    366	if (request->status == SCLP_REQ_FAILED) {
    367		if (buffer->callback != NULL)
    368			buffer->callback(buffer, -EIO);
    369		return;
    370	}
    371	/* check SCLP response code and choose suitable action	*/
    372	switch (sccb->response_code) {
    373	case 0x0020 :
    374		/* Normal completion, buffer processed, message(s) sent */
    375		rc = 0;
    376		break;
    377
    378	case 0x0340: /* Contained SCLP equipment check */
    379		if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
    380			rc = -EIO;
    381			break;
    382		}
    383		/* remove processed buffers and requeue rest */
    384		if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
    385			/* not all buffers were processed */
    386			sccb->response_code = 0x0000;
    387			buffer->request.status = SCLP_REQ_FILLED;
    388			rc = sclp_add_request(request);
    389			if (rc == 0)
    390				return;
    391		} else
    392			rc = 0;
    393		break;
    394
    395	case 0x0040: /* SCLP equipment check */
    396	case 0x05f0: /* Target resource in improper state */
    397		if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
    398			rc = -EIO;
    399			break;
    400		}
    401		/* retry request */
    402		sccb->response_code = 0x0000;
    403		buffer->request.status = SCLP_REQ_FILLED;
    404		rc = sclp_add_request(request);
    405		if (rc == 0)
    406			return;
    407		break;
    408	default:
    409		if (sccb->response_code == 0x71f0)
    410			rc = -ENOMEM;
    411		else
    412			rc = -EINVAL;
    413		break;
    414	}
    415	if (buffer->callback != NULL)
    416		buffer->callback(buffer, rc);
    417}
    418
    419/*
    420 * Setup the request structure in the struct sclp_buffer to do SCLP Write
    421 * Event Data and pass the request to the core SCLP loop. Return zero on
    422 * success, non-zero otherwise.
    423 */
    424int
    425sclp_emit_buffer(struct sclp_buffer *buffer,
    426		 void (*callback)(struct sclp_buffer *, int))
    427{
    428	/* add current line if there is one */
    429	if (buffer->current_line != NULL)
    430		sclp_finalize_mto(buffer);
    431
    432	/* Are there messages in the output buffer ? */
    433	if (buffer->messages == 0)
    434		return -EIO;
    435
    436	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
    437	buffer->request.status = SCLP_REQ_FILLED;
    438	buffer->request.callback = sclp_writedata_callback;
    439	buffer->request.callback_data = buffer;
    440	buffer->request.sccb = buffer->sccb;
    441	buffer->callback = callback;
    442	return sclp_add_request(&buffer->request);
    443}