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

iosm_ipc_trace.c (4799B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2020-2021 Intel Corporation.
      4 */
      5
      6#include <linux/wwan.h>
      7#include "iosm_ipc_trace.h"
      8
      9/* sub buffer size and number of sub buffer */
     10#define IOSM_TRC_SUB_BUFF_SIZE 131072
     11#define IOSM_TRC_N_SUB_BUFF 32
     12
     13#define IOSM_TRC_FILE_PERM 0600
     14
     15#define IOSM_TRC_DEBUGFS_TRACE "trace"
     16#define IOSM_TRC_DEBUGFS_TRACE_CTRL "trace_ctrl"
     17
     18/**
     19 * ipc_trace_port_rx - Receive trace packet from cp and write to relay buffer
     20 * @ipc_imem:   Pointer to iosm_imem structure
     21 * @skb:        Pointer to struct sk_buff
     22 */
     23void ipc_trace_port_rx(struct iosm_imem *ipc_imem, struct sk_buff *skb)
     24{
     25	struct iosm_trace *ipc_trace = ipc_imem->trace;
     26
     27	if (ipc_trace->ipc_rchan)
     28		relay_write(ipc_trace->ipc_rchan, skb->data, skb->len);
     29
     30	dev_kfree_skb(skb);
     31}
     32
     33/* Creates relay file in debugfs. */
     34static struct dentry *
     35ipc_trace_create_buf_file_handler(const char *filename,
     36				  struct dentry *parent,
     37				  umode_t mode,
     38				  struct rchan_buf *buf,
     39				  int *is_global)
     40{
     41	*is_global = 1;
     42	return debugfs_create_file(filename, mode, parent, buf,
     43				   &relay_file_operations);
     44}
     45
     46/* Removes relay file from debugfs. */
     47static int ipc_trace_remove_buf_file_handler(struct dentry *dentry)
     48{
     49	debugfs_remove(dentry);
     50	return 0;
     51}
     52
     53static int ipc_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
     54					  void *prev_subbuf,
     55					  size_t prev_padding)
     56{
     57	if (relay_buf_full(buf)) {
     58		pr_err_ratelimited("Relay_buf full dropping traces");
     59		return 0;
     60	}
     61
     62	return 1;
     63}
     64
     65/* Relay interface callbacks */
     66static struct rchan_callbacks relay_callbacks = {
     67	.subbuf_start = ipc_trace_subbuf_start_handler,
     68	.create_buf_file = ipc_trace_create_buf_file_handler,
     69	.remove_buf_file = ipc_trace_remove_buf_file_handler,
     70};
     71
     72/* Copy the trace control mode to user buffer */
     73static ssize_t ipc_trace_ctrl_file_read(struct file *filp, char __user *buffer,
     74					size_t count, loff_t *ppos)
     75{
     76	struct iosm_trace *ipc_trace = filp->private_data;
     77	char buf[16];
     78	int len;
     79
     80	mutex_lock(&ipc_trace->trc_mutex);
     81	len = snprintf(buf, sizeof(buf), "%d\n", ipc_trace->mode);
     82	mutex_unlock(&ipc_trace->trc_mutex);
     83
     84	return simple_read_from_buffer(buffer, count, ppos, buf, len);
     85}
     86
     87/* Open and close the trace channel depending on user input */
     88static ssize_t ipc_trace_ctrl_file_write(struct file *filp,
     89					 const char __user *buffer,
     90					 size_t count, loff_t *ppos)
     91{
     92	struct iosm_trace *ipc_trace = filp->private_data;
     93	unsigned long val;
     94	int ret;
     95
     96	ret = kstrtoul_from_user(buffer, count, 10, &val);
     97	if (ret)
     98		return ret;
     99
    100	mutex_lock(&ipc_trace->trc_mutex);
    101	if (val == TRACE_ENABLE && ipc_trace->mode != TRACE_ENABLE) {
    102		ipc_trace->channel = ipc_imem_sys_port_open(ipc_trace->ipc_imem,
    103							    ipc_trace->chl_id,
    104							    IPC_HP_CDEV_OPEN);
    105		if (!ipc_trace->channel) {
    106			ret = -EIO;
    107			goto unlock;
    108		}
    109		ipc_trace->mode = TRACE_ENABLE;
    110	} else if (val == TRACE_DISABLE && ipc_trace->mode != TRACE_DISABLE) {
    111		ipc_trace->mode = TRACE_DISABLE;
    112		/* close trace channel */
    113		ipc_imem_sys_port_close(ipc_trace->ipc_imem,
    114					ipc_trace->channel);
    115		relay_flush(ipc_trace->ipc_rchan);
    116	}
    117	ret = count;
    118unlock:
    119	mutex_unlock(&ipc_trace->trc_mutex);
    120	return ret;
    121}
    122
    123static const struct file_operations ipc_trace_fops = {
    124	.open = simple_open,
    125	.write = ipc_trace_ctrl_file_write,
    126	.read  = ipc_trace_ctrl_file_read,
    127};
    128
    129/**
    130 * ipc_trace_init - Create trace interface & debugfs entries
    131 * @ipc_imem:   Pointer to iosm_imem structure
    132 *
    133 * Returns: Pointer to trace instance on success else NULL
    134 */
    135struct iosm_trace *ipc_trace_init(struct iosm_imem *ipc_imem)
    136{
    137	struct ipc_chnl_cfg chnl_cfg = { 0 };
    138	struct iosm_trace *ipc_trace;
    139
    140	ipc_chnl_cfg_get(&chnl_cfg, IPC_MEM_CTRL_CHL_ID_3);
    141	ipc_imem_channel_init(ipc_imem, IPC_CTYPE_CTRL, chnl_cfg,
    142			      IRQ_MOD_OFF);
    143
    144	ipc_trace = kzalloc(sizeof(*ipc_trace), GFP_KERNEL);
    145	if (!ipc_trace)
    146		return NULL;
    147
    148	ipc_trace->mode = TRACE_DISABLE;
    149	ipc_trace->dev = ipc_imem->dev;
    150	ipc_trace->ipc_imem = ipc_imem;
    151	ipc_trace->chl_id = IPC_MEM_CTRL_CHL_ID_3;
    152
    153	mutex_init(&ipc_trace->trc_mutex);
    154
    155	ipc_trace->ctrl_file = debugfs_create_file(IOSM_TRC_DEBUGFS_TRACE_CTRL,
    156						   IOSM_TRC_FILE_PERM,
    157						   ipc_imem->debugfs_dir,
    158						   ipc_trace, &ipc_trace_fops);
    159
    160	ipc_trace->ipc_rchan = relay_open(IOSM_TRC_DEBUGFS_TRACE,
    161					  ipc_imem->debugfs_dir,
    162					  IOSM_TRC_SUB_BUFF_SIZE,
    163					  IOSM_TRC_N_SUB_BUFF,
    164					  &relay_callbacks, NULL);
    165
    166	return ipc_trace;
    167}
    168
    169/**
    170 * ipc_trace_deinit - Closing relayfs, removing debugfs entries
    171 * @ipc_trace: Pointer to the iosm_trace data struct
    172 */
    173void ipc_trace_deinit(struct iosm_trace *ipc_trace)
    174{
    175	if (!ipc_trace)
    176		return;
    177
    178	debugfs_remove(ipc_trace->ctrl_file);
    179	relay_close(ipc_trace->ipc_rchan);
    180	mutex_destroy(&ipc_trace->trc_mutex);
    181	kfree(ipc_trace);
    182}