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_sdias.c (6735B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * SCLP "store data in absolute storage"
      4 *
      5 * Copyright IBM Corp. 2003, 2013
      6 * Author(s): Michael Holzheu
      7 */
      8
      9#define KMSG_COMPONENT "sclp_sdias"
     10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
     11
     12#include <linux/completion.h>
     13#include <linux/sched.h>
     14#include <asm/sclp.h>
     15#include <asm/debug.h>
     16#include <asm/ipl.h>
     17
     18#include "sclp_sdias.h"
     19#include "sclp.h"
     20#include "sclp_rw.h"
     21
     22#define TRACE(x...) debug_sprintf_event(sdias_dbf, 1, x)
     23
     24#define SDIAS_RETRIES 300
     25
     26static struct debug_info *sdias_dbf;
     27
     28static struct sclp_register sclp_sdias_register = {
     29	.send_mask = EVTYP_SDIAS_MASK,
     30};
     31
     32static struct sdias_sccb *sclp_sdias_sccb;
     33static struct sdias_evbuf sdias_evbuf;
     34
     35static DECLARE_COMPLETION(evbuf_accepted);
     36static DECLARE_COMPLETION(evbuf_done);
     37static DEFINE_MUTEX(sdias_mutex);
     38
     39/*
     40 * Called by SCLP base when read event data has been completed (async mode only)
     41 */
     42static void sclp_sdias_receiver_fn(struct evbuf_header *evbuf)
     43{
     44	memcpy(&sdias_evbuf, evbuf,
     45	       min_t(unsigned long, sizeof(sdias_evbuf), evbuf->length));
     46	complete(&evbuf_done);
     47	TRACE("sclp_sdias_receiver_fn done\n");
     48}
     49
     50/*
     51 * Called by SCLP base when sdias event has been accepted
     52 */
     53static void sdias_callback(struct sclp_req *request, void *data)
     54{
     55	complete(&evbuf_accepted);
     56	TRACE("callback done\n");
     57}
     58
     59static int sdias_sclp_send(struct sclp_req *req)
     60{
     61	struct sdias_sccb *sccb = sclp_sdias_sccb;
     62	int retries;
     63	int rc;
     64
     65	for (retries = SDIAS_RETRIES; retries; retries--) {
     66		TRACE("add request\n");
     67		rc = sclp_add_request(req);
     68		if (rc) {
     69			/* not initiated, wait some time and retry */
     70			set_current_state(TASK_INTERRUPTIBLE);
     71			TRACE("add request failed: rc = %i\n",rc);
     72			schedule_timeout(msecs_to_jiffies(500));
     73			continue;
     74		}
     75		/* initiated, wait for completion of service call */
     76		wait_for_completion(&evbuf_accepted);
     77		if (req->status == SCLP_REQ_FAILED) {
     78			TRACE("sclp request failed\n");
     79			continue;
     80		}
     81		/* if not accepted, retry */
     82		if (!(sccb->evbuf.hdr.flags & 0x80)) {
     83			TRACE("sclp request failed: flags=%x\n",
     84			      sccb->evbuf.hdr.flags);
     85			continue;
     86		}
     87		/*
     88		 * for the sync interface the response is in the initial sccb
     89		 */
     90		if (!sclp_sdias_register.receiver_fn) {
     91			memcpy(&sdias_evbuf, &sccb->evbuf, sizeof(sdias_evbuf));
     92			TRACE("sync request done\n");
     93			return 0;
     94		}
     95		/* otherwise we wait for completion */
     96		wait_for_completion(&evbuf_done);
     97		TRACE("request done\n");
     98		return 0;
     99	}
    100	return -EIO;
    101}
    102
    103/*
    104 * Get number of blocks (4K) available in the HSA
    105 */
    106int sclp_sdias_blk_count(void)
    107{
    108	struct sdias_sccb *sccb = sclp_sdias_sccb;
    109	struct sclp_req request;
    110	int rc;
    111
    112	mutex_lock(&sdias_mutex);
    113
    114	memset(sccb, 0, sizeof(*sccb));
    115	memset(&request, 0, sizeof(request));
    116
    117	sccb->hdr.length = sizeof(*sccb);
    118	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
    119	sccb->evbuf.hdr.type = EVTYP_SDIAS;
    120	sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
    121	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
    122	sccb->evbuf.event_id = 4712;
    123	sccb->evbuf.dbs = 1;
    124
    125	request.sccb = sccb;
    126	request.command = SCLP_CMDW_WRITE_EVENT_DATA;
    127	request.status = SCLP_REQ_FILLED;
    128	request.callback = sdias_callback;
    129
    130	rc = sdias_sclp_send(&request);
    131	if (rc) {
    132		pr_err("sclp_send failed for get_nr_blocks\n");
    133		goto out;
    134	}
    135	if (sccb->hdr.response_code != 0x0020) {
    136		TRACE("send failed: %x\n", sccb->hdr.response_code);
    137		rc = -EIO;
    138		goto out;
    139	}
    140
    141	switch (sdias_evbuf.event_status) {
    142		case 0:
    143			rc = sdias_evbuf.blk_cnt;
    144			break;
    145		default:
    146			pr_err("SCLP error: %x\n", sdias_evbuf.event_status);
    147			rc = -EIO;
    148			goto out;
    149	}
    150	TRACE("%i blocks\n", rc);
    151out:
    152	mutex_unlock(&sdias_mutex);
    153	return rc;
    154}
    155
    156/*
    157 * Copy from HSA to absolute storage (not reentrant):
    158 *
    159 * @dest     : Address of buffer where data should be copied
    160 * @start_blk: Start Block (beginning with 1)
    161 * @nr_blks  : Number of 4K blocks to copy
    162 *
    163 * Return Value: 0 : Requested 'number' of blocks of data copied
    164 *		 <0: ERROR - negative event status
    165 */
    166int sclp_sdias_copy(void *dest, int start_blk, int nr_blks)
    167{
    168	struct sdias_sccb *sccb = sclp_sdias_sccb;
    169	struct sclp_req request;
    170	int rc;
    171
    172	mutex_lock(&sdias_mutex);
    173
    174	memset(sccb, 0, sizeof(*sccb));
    175	memset(&request, 0, sizeof(request));
    176
    177	sccb->hdr.length = sizeof(*sccb);
    178	sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
    179	sccb->evbuf.hdr.type = EVTYP_SDIAS;
    180	sccb->evbuf.hdr.flags = 0;
    181	sccb->evbuf.event_qual = SDIAS_EQ_STORE_DATA;
    182	sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
    183	sccb->evbuf.event_id = 4712;
    184	sccb->evbuf.asa_size = SDIAS_ASA_SIZE_64;
    185	sccb->evbuf.event_status = 0;
    186	sccb->evbuf.blk_cnt = nr_blks;
    187	sccb->evbuf.asa = __pa(dest);
    188	sccb->evbuf.fbn = start_blk;
    189	sccb->evbuf.lbn = 0;
    190	sccb->evbuf.dbs = 1;
    191
    192	request.sccb	 = sccb;
    193	request.command  = SCLP_CMDW_WRITE_EVENT_DATA;
    194	request.status	 = SCLP_REQ_FILLED;
    195	request.callback = sdias_callback;
    196
    197	rc = sdias_sclp_send(&request);
    198	if (rc) {
    199		pr_err("sclp_send failed: %x\n", rc);
    200		goto out;
    201	}
    202	if (sccb->hdr.response_code != 0x0020) {
    203		TRACE("copy failed: %x\n", sccb->hdr.response_code);
    204		rc = -EIO;
    205		goto out;
    206	}
    207
    208	switch (sdias_evbuf.event_status) {
    209	case SDIAS_EVSTATE_ALL_STORED:
    210		TRACE("all stored\n");
    211		break;
    212	case SDIAS_EVSTATE_PART_STORED:
    213		TRACE("part stored: %i\n", sdias_evbuf.blk_cnt);
    214		break;
    215	case SDIAS_EVSTATE_NO_DATA:
    216		TRACE("no data\n");
    217		fallthrough;
    218	default:
    219		pr_err("Error from SCLP while copying hsa. Event status = %x\n",
    220		       sdias_evbuf.event_status);
    221		rc = -EIO;
    222	}
    223out:
    224	mutex_unlock(&sdias_mutex);
    225	return rc;
    226}
    227
    228static int __init sclp_sdias_register_check(void)
    229{
    230	int rc;
    231
    232	rc = sclp_register(&sclp_sdias_register);
    233	if (rc)
    234		return rc;
    235	if (sclp_sdias_blk_count() == 0) {
    236		sclp_unregister(&sclp_sdias_register);
    237		return -ENODEV;
    238	}
    239	return 0;
    240}
    241
    242static int __init sclp_sdias_init_sync(void)
    243{
    244	TRACE("Try synchronous mode\n");
    245	sclp_sdias_register.receive_mask = 0;
    246	sclp_sdias_register.receiver_fn = NULL;
    247	return sclp_sdias_register_check();
    248}
    249
    250static int __init sclp_sdias_init_async(void)
    251{
    252	TRACE("Try asynchronous mode\n");
    253	sclp_sdias_register.receive_mask = EVTYP_SDIAS_MASK;
    254	sclp_sdias_register.receiver_fn = sclp_sdias_receiver_fn;
    255	return sclp_sdias_register_check();
    256}
    257
    258int __init sclp_sdias_init(void)
    259{
    260	if (!is_ipl_type_dump())
    261		return 0;
    262	sclp_sdias_sccb = (void *) __get_free_page(GFP_KERNEL | GFP_DMA);
    263	BUG_ON(!sclp_sdias_sccb);
    264	sdias_dbf = debug_register("dump_sdias", 4, 1, 4 * sizeof(long));
    265	debug_register_view(sdias_dbf, &debug_sprintf_view);
    266	debug_set_level(sdias_dbf, 6);
    267	if (sclp_sdias_init_sync() == 0)
    268		goto out;
    269	if (sclp_sdias_init_async() == 0)
    270		goto out;
    271	TRACE("init failed\n");
    272	free_page((unsigned long) sclp_sdias_sccb);
    273	return -ENODEV;
    274out:
    275	TRACE("init done\n");
    276	return 0;
    277}