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

pvrusb2-ioread.c (11567B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 *
      4 *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
      5 */
      6
      7#include "pvrusb2-ioread.h"
      8#include "pvrusb2-debug.h"
      9#include <linux/errno.h>
     10#include <linux/string.h>
     11#include <linux/mm.h>
     12#include <linux/slab.h>
     13#include <linux/mutex.h>
     14#include <linux/uaccess.h>
     15
     16#define BUFFER_COUNT 32
     17#define BUFFER_SIZE PAGE_ALIGN(0x4000)
     18
     19struct pvr2_ioread {
     20	struct pvr2_stream *stream;
     21	char *buffer_storage[BUFFER_COUNT];
     22	char *sync_key_ptr;
     23	unsigned int sync_key_len;
     24	unsigned int sync_buf_offs;
     25	unsigned int sync_state;
     26	unsigned int sync_trashed_count;
     27	int enabled;         // Streaming is on
     28	int spigot_open;     // OK to pass data to client
     29	int stream_running;  // Passing data to client now
     30
     31	/* State relevant to current buffer being read */
     32	struct pvr2_buffer *c_buf;
     33	char *c_data_ptr;
     34	unsigned int c_data_len;
     35	unsigned int c_data_offs;
     36	struct mutex mutex;
     37};
     38
     39static int pvr2_ioread_init(struct pvr2_ioread *cp)
     40{
     41	unsigned int idx;
     42
     43	cp->stream = NULL;
     44	mutex_init(&cp->mutex);
     45
     46	for (idx = 0; idx < BUFFER_COUNT; idx++) {
     47		cp->buffer_storage[idx] = kmalloc(BUFFER_SIZE,GFP_KERNEL);
     48		if (!(cp->buffer_storage[idx])) break;
     49	}
     50
     51	if (idx < BUFFER_COUNT) {
     52		// An allocation appears to have failed
     53		for (idx = 0; idx < BUFFER_COUNT; idx++) {
     54			if (!(cp->buffer_storage[idx])) continue;
     55			kfree(cp->buffer_storage[idx]);
     56		}
     57		return -ENOMEM;
     58	}
     59	return 0;
     60}
     61
     62static void pvr2_ioread_done(struct pvr2_ioread *cp)
     63{
     64	unsigned int idx;
     65
     66	pvr2_ioread_setup(cp,NULL);
     67	for (idx = 0; idx < BUFFER_COUNT; idx++) {
     68		if (!(cp->buffer_storage[idx])) continue;
     69		kfree(cp->buffer_storage[idx]);
     70	}
     71}
     72
     73struct pvr2_ioread *pvr2_ioread_create(void)
     74{
     75	struct pvr2_ioread *cp;
     76	cp = kzalloc(sizeof(*cp),GFP_KERNEL);
     77	if (!cp) return NULL;
     78	pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_create id=%p",cp);
     79	if (pvr2_ioread_init(cp) < 0) {
     80		kfree(cp);
     81		return NULL;
     82	}
     83	return cp;
     84}
     85
     86void pvr2_ioread_destroy(struct pvr2_ioread *cp)
     87{
     88	if (!cp) return;
     89	pvr2_ioread_done(cp);
     90	pvr2_trace(PVR2_TRACE_STRUCT,"pvr2_ioread_destroy id=%p",cp);
     91	if (cp->sync_key_ptr) {
     92		kfree(cp->sync_key_ptr);
     93		cp->sync_key_ptr = NULL;
     94	}
     95	kfree(cp);
     96}
     97
     98void pvr2_ioread_set_sync_key(struct pvr2_ioread *cp,
     99			      const char *sync_key_ptr,
    100			      unsigned int sync_key_len)
    101{
    102	if (!cp) return;
    103
    104	if (!sync_key_ptr) sync_key_len = 0;
    105	if ((sync_key_len == cp->sync_key_len) &&
    106	    ((!sync_key_len) ||
    107	     (!memcmp(sync_key_ptr,cp->sync_key_ptr,sync_key_len)))) return;
    108
    109	if (sync_key_len != cp->sync_key_len) {
    110		if (cp->sync_key_ptr) {
    111			kfree(cp->sync_key_ptr);
    112			cp->sync_key_ptr = NULL;
    113		}
    114		cp->sync_key_len = 0;
    115		if (sync_key_len) {
    116			cp->sync_key_ptr = kmalloc(sync_key_len,GFP_KERNEL);
    117			if (cp->sync_key_ptr) {
    118				cp->sync_key_len = sync_key_len;
    119			}
    120		}
    121	}
    122	if (!cp->sync_key_len) return;
    123	memcpy(cp->sync_key_ptr,sync_key_ptr,cp->sync_key_len);
    124}
    125
    126static void pvr2_ioread_stop(struct pvr2_ioread *cp)
    127{
    128	if (!(cp->enabled)) return;
    129	pvr2_trace(PVR2_TRACE_START_STOP,
    130		   "/*---TRACE_READ---*/ pvr2_ioread_stop id=%p",cp);
    131	pvr2_stream_kill(cp->stream);
    132	cp->c_buf = NULL;
    133	cp->c_data_ptr = NULL;
    134	cp->c_data_len = 0;
    135	cp->c_data_offs = 0;
    136	cp->enabled = 0;
    137	cp->stream_running = 0;
    138	cp->spigot_open = 0;
    139	if (cp->sync_state) {
    140		pvr2_trace(PVR2_TRACE_DATA_FLOW,
    141			   "/*---TRACE_READ---*/ sync_state <== 0");
    142		cp->sync_state = 0;
    143	}
    144}
    145
    146static int pvr2_ioread_start(struct pvr2_ioread *cp)
    147{
    148	int stat;
    149	struct pvr2_buffer *bp;
    150	if (cp->enabled) return 0;
    151	if (!(cp->stream)) return 0;
    152	pvr2_trace(PVR2_TRACE_START_STOP,
    153		   "/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
    154	while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
    155		stat = pvr2_buffer_queue(bp);
    156		if (stat < 0) {
    157			pvr2_trace(PVR2_TRACE_DATA_FLOW,
    158				   "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d",
    159				   cp,stat);
    160			pvr2_ioread_stop(cp);
    161			return stat;
    162		}
    163	}
    164	cp->enabled = !0;
    165	cp->c_buf = NULL;
    166	cp->c_data_ptr = NULL;
    167	cp->c_data_len = 0;
    168	cp->c_data_offs = 0;
    169	cp->stream_running = 0;
    170	if (cp->sync_key_len) {
    171		pvr2_trace(PVR2_TRACE_DATA_FLOW,
    172			   "/*---TRACE_READ---*/ sync_state <== 1");
    173		cp->sync_state = 1;
    174		cp->sync_trashed_count = 0;
    175		cp->sync_buf_offs = 0;
    176	}
    177	cp->spigot_open = 0;
    178	return 0;
    179}
    180
    181struct pvr2_stream *pvr2_ioread_get_stream(struct pvr2_ioread *cp)
    182{
    183	return cp->stream;
    184}
    185
    186int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
    187{
    188	int ret;
    189	unsigned int idx;
    190	struct pvr2_buffer *bp;
    191
    192	mutex_lock(&cp->mutex);
    193	do {
    194		if (cp->stream) {
    195			pvr2_trace(PVR2_TRACE_START_STOP,
    196				   "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p",
    197				   cp);
    198			pvr2_ioread_stop(cp);
    199			pvr2_stream_kill(cp->stream);
    200			if (pvr2_stream_get_buffer_count(cp->stream)) {
    201				pvr2_stream_set_buffer_count(cp->stream,0);
    202			}
    203			cp->stream = NULL;
    204		}
    205		if (sp) {
    206			pvr2_trace(PVR2_TRACE_START_STOP,
    207				   "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p",
    208				   cp);
    209			pvr2_stream_kill(sp);
    210			ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
    211			if (ret < 0) {
    212				mutex_unlock(&cp->mutex);
    213				return ret;
    214			}
    215			for (idx = 0; idx < BUFFER_COUNT; idx++) {
    216				bp = pvr2_stream_get_buffer(sp,idx);
    217				pvr2_buffer_set_buffer(bp,
    218						       cp->buffer_storage[idx],
    219						       BUFFER_SIZE);
    220			}
    221			cp->stream = sp;
    222		}
    223	} while (0);
    224	mutex_unlock(&cp->mutex);
    225
    226	return 0;
    227}
    228
    229int pvr2_ioread_set_enabled(struct pvr2_ioread *cp,int fl)
    230{
    231	int ret = 0;
    232	if ((!fl) == (!(cp->enabled))) return ret;
    233
    234	mutex_lock(&cp->mutex);
    235	do {
    236		if (fl) {
    237			ret = pvr2_ioread_start(cp);
    238		} else {
    239			pvr2_ioread_stop(cp);
    240		}
    241	} while (0);
    242	mutex_unlock(&cp->mutex);
    243	return ret;
    244}
    245
    246static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp)
    247{
    248	int stat;
    249
    250	while (cp->c_data_len <= cp->c_data_offs) {
    251		if (cp->c_buf) {
    252			// Flush out current buffer first.
    253			stat = pvr2_buffer_queue(cp->c_buf);
    254			if (stat < 0) {
    255				// Streaming error...
    256				pvr2_trace(PVR2_TRACE_DATA_FLOW,
    257					   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d",
    258					   cp,stat);
    259				pvr2_ioread_stop(cp);
    260				return 0;
    261			}
    262			cp->c_buf = NULL;
    263			cp->c_data_ptr = NULL;
    264			cp->c_data_len = 0;
    265			cp->c_data_offs = 0;
    266		}
    267		// Now get a freshly filled buffer.
    268		cp->c_buf = pvr2_stream_get_ready_buffer(cp->stream);
    269		if (!cp->c_buf) break; // Nothing ready; done.
    270		cp->c_data_len = pvr2_buffer_get_count(cp->c_buf);
    271		if (!cp->c_data_len) {
    272			// Nothing transferred.  Was there an error?
    273			stat = pvr2_buffer_get_status(cp->c_buf);
    274			if (stat < 0) {
    275				// Streaming error...
    276				pvr2_trace(PVR2_TRACE_DATA_FLOW,
    277					   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d",
    278					   cp,stat);
    279				pvr2_ioread_stop(cp);
    280				// Give up.
    281				return 0;
    282			}
    283			// Start over...
    284			continue;
    285		}
    286		cp->c_data_offs = 0;
    287		cp->c_data_ptr = cp->buffer_storage[
    288			pvr2_buffer_get_id(cp->c_buf)];
    289	}
    290	return !0;
    291}
    292
    293static void pvr2_ioread_filter(struct pvr2_ioread *cp)
    294{
    295	unsigned int idx;
    296	if (!cp->enabled) return;
    297	if (cp->sync_state != 1) return;
    298
    299	// Search the stream for our synchronization key.  This is made
    300	// complicated by the fact that in order to be honest with
    301	// ourselves here we must search across buffer boundaries...
    302	mutex_lock(&cp->mutex);
    303	while (1) {
    304		// Ensure we have a buffer
    305		if (!pvr2_ioread_get_buffer(cp)) break;
    306		if (!cp->c_data_len) break;
    307
    308		// Now walk the buffer contents until we match the key or
    309		// run out of buffer data.
    310		for (idx = cp->c_data_offs; idx < cp->c_data_len; idx++) {
    311			if (cp->sync_buf_offs >= cp->sync_key_len) break;
    312			if (cp->c_data_ptr[idx] ==
    313			    cp->sync_key_ptr[cp->sync_buf_offs]) {
    314				// Found the next key byte
    315				(cp->sync_buf_offs)++;
    316			} else {
    317				// Whoops, mismatched.  Start key over...
    318				cp->sync_buf_offs = 0;
    319			}
    320		}
    321
    322		// Consume what we've walked through
    323		cp->c_data_offs += idx;
    324		cp->sync_trashed_count += idx;
    325
    326		// If we've found the key, then update state and get out.
    327		if (cp->sync_buf_offs >= cp->sync_key_len) {
    328			cp->sync_trashed_count -= cp->sync_key_len;
    329			pvr2_trace(PVR2_TRACE_DATA_FLOW,
    330				   "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)",
    331				   cp->sync_trashed_count);
    332			cp->sync_state = 2;
    333			cp->sync_buf_offs = 0;
    334			break;
    335		}
    336
    337		if (cp->c_data_offs < cp->c_data_len) {
    338			// Sanity check - should NEVER get here
    339			pvr2_trace(PVR2_TRACE_ERROR_LEGS,
    340				   "ERROR: pvr2_ioread filter sync problem len=%u offs=%u",
    341				   cp->c_data_len,cp->c_data_offs);
    342			// Get out so we don't get stuck in an infinite
    343			// loop.
    344			break;
    345		}
    346
    347		continue; // (for clarity)
    348	}
    349	mutex_unlock(&cp->mutex);
    350}
    351
    352int pvr2_ioread_avail(struct pvr2_ioread *cp)
    353{
    354	int ret;
    355	if (!(cp->enabled)) {
    356		// Stream is not enabled; so this is an I/O error
    357		return -EIO;
    358	}
    359
    360	if (cp->sync_state == 1) {
    361		pvr2_ioread_filter(cp);
    362		if (cp->sync_state == 1) return -EAGAIN;
    363	}
    364
    365	ret = 0;
    366	if (cp->stream_running) {
    367		if (!pvr2_stream_get_ready_count(cp->stream)) {
    368			// No data available at all right now.
    369			ret = -EAGAIN;
    370		}
    371	} else {
    372		if (pvr2_stream_get_ready_count(cp->stream) < BUFFER_COUNT/2) {
    373			// Haven't buffered up enough yet; try again later
    374			ret = -EAGAIN;
    375		}
    376	}
    377
    378	if ((!(cp->spigot_open)) != (!(ret == 0))) {
    379		cp->spigot_open = (ret == 0);
    380		pvr2_trace(PVR2_TRACE_DATA_FLOW,
    381			   "/*---TRACE_READ---*/ data is %s",
    382			   cp->spigot_open ? "available" : "pending");
    383	}
    384
    385	return ret;
    386}
    387
    388int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
    389{
    390	unsigned int copied_cnt;
    391	unsigned int bcnt;
    392	const char *src;
    393	int stat;
    394	int ret = 0;
    395	unsigned int req_cnt = cnt;
    396
    397	if (!cnt) {
    398		pvr2_trace(PVR2_TRACE_TRAP,
    399			   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.",
    400cp);
    401		return 0;
    402	}
    403
    404	stat = pvr2_ioread_avail(cp);
    405	if (stat < 0) return stat;
    406
    407	cp->stream_running = !0;
    408
    409	mutex_lock(&cp->mutex);
    410	do {
    411
    412		// Suck data out of the buffers and copy to the user
    413		copied_cnt = 0;
    414		if (!buf) cnt = 0;
    415		while (1) {
    416			if (!pvr2_ioread_get_buffer(cp)) {
    417				ret = -EIO;
    418				break;
    419			}
    420
    421			if (!cnt) break;
    422
    423			if (cp->sync_state == 2) {
    424				// We're repeating the sync key data into
    425				// the stream.
    426				src = cp->sync_key_ptr + cp->sync_buf_offs;
    427				bcnt = cp->sync_key_len - cp->sync_buf_offs;
    428			} else {
    429				// Normal buffer copy
    430				src = cp->c_data_ptr + cp->c_data_offs;
    431				bcnt = cp->c_data_len - cp->c_data_offs;
    432			}
    433
    434			if (!bcnt) break;
    435
    436			// Don't run past user's buffer
    437			if (bcnt > cnt) bcnt = cnt;
    438
    439			if (copy_to_user(buf,src,bcnt)) {
    440				// User supplied a bad pointer?
    441				// Give up - this *will* cause data
    442				// to be lost.
    443				ret = -EFAULT;
    444				break;
    445			}
    446			cnt -= bcnt;
    447			buf += bcnt;
    448			copied_cnt += bcnt;
    449
    450			if (cp->sync_state == 2) {
    451				// Update offset inside sync key that we're
    452				// repeating back out.
    453				cp->sync_buf_offs += bcnt;
    454				if (cp->sync_buf_offs >= cp->sync_key_len) {
    455					// Consumed entire key; switch mode
    456					// to normal.
    457					pvr2_trace(PVR2_TRACE_DATA_FLOW,
    458						   "/*---TRACE_READ---*/ sync_state <== 0");
    459					cp->sync_state = 0;
    460				}
    461			} else {
    462				// Update buffer offset.
    463				cp->c_data_offs += bcnt;
    464			}
    465		}
    466
    467	} while (0);
    468	mutex_unlock(&cp->mutex);
    469
    470	if (!ret) {
    471		if (copied_cnt) {
    472			// If anything was copied, return that count
    473			ret = copied_cnt;
    474		} else {
    475			// Nothing copied; suggest to caller that another
    476			// attempt should be tried again later
    477			ret = -EAGAIN;
    478		}
    479	}
    480
    481	pvr2_trace(PVR2_TRACE_DATA_FLOW,
    482		   "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d",
    483		   cp,req_cnt,ret);
    484	return ret;
    485}