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

grukdump.c (5109B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * SN Platform GRU Driver
      4 *
      5 *            Dump GRU State
      6 *
      7 *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/mm.h>
     12#include <linux/spinlock.h>
     13#include <linux/uaccess.h>
     14#include <linux/delay.h>
     15#include <linux/bitops.h>
     16#include <asm/uv/uv_hub.h>
     17
     18#include <linux/nospec.h>
     19
     20#include "gru.h"
     21#include "grutables.h"
     22#include "gruhandles.h"
     23#include "grulib.h"
     24
     25#define CCH_LOCK_ATTEMPTS	10
     26
     27static int gru_user_copy_handle(void __user **dp, void *s)
     28{
     29	if (copy_to_user(*dp, s, GRU_HANDLE_BYTES))
     30		return -1;
     31	*dp += GRU_HANDLE_BYTES;
     32	return 0;
     33}
     34
     35static int gru_dump_context_data(void *grubase,
     36			struct gru_context_configuration_handle *cch,
     37			void __user *ubuf, int ctxnum, int dsrcnt,
     38			int flush_cbrs)
     39{
     40	void *cb, *cbe, *tfh, *gseg;
     41	int i, scr;
     42
     43	gseg = grubase + ctxnum * GRU_GSEG_STRIDE;
     44	cb = gseg + GRU_CB_BASE;
     45	cbe = grubase + GRU_CBE_BASE;
     46	tfh = grubase + GRU_TFH_BASE;
     47
     48	for_each_cbr_in_allocation_map(i, &cch->cbr_allocation_map, scr) {
     49		if (flush_cbrs)
     50			gru_flush_cache(cb);
     51		if (gru_user_copy_handle(&ubuf, cb))
     52			goto fail;
     53		if (gru_user_copy_handle(&ubuf, tfh + i * GRU_HANDLE_STRIDE))
     54			goto fail;
     55		if (gru_user_copy_handle(&ubuf, cbe + i * GRU_HANDLE_STRIDE))
     56			goto fail;
     57		cb += GRU_HANDLE_STRIDE;
     58	}
     59	if (dsrcnt)
     60		memcpy(ubuf, gseg + GRU_DS_BASE, dsrcnt * GRU_HANDLE_STRIDE);
     61	return 0;
     62
     63fail:
     64	return -EFAULT;
     65}
     66
     67static int gru_dump_tfm(struct gru_state *gru,
     68		void __user *ubuf, void __user *ubufend)
     69{
     70	struct gru_tlb_fault_map *tfm;
     71	int i;
     72
     73	if (GRU_NUM_TFM * GRU_CACHE_LINE_BYTES > ubufend - ubuf)
     74		return -EFBIG;
     75
     76	for (i = 0; i < GRU_NUM_TFM; i++) {
     77		tfm = get_tfm(gru->gs_gru_base_vaddr, i);
     78		if (gru_user_copy_handle(&ubuf, tfm))
     79			goto fail;
     80	}
     81	return GRU_NUM_TFM * GRU_CACHE_LINE_BYTES;
     82
     83fail:
     84	return -EFAULT;
     85}
     86
     87static int gru_dump_tgh(struct gru_state *gru,
     88		void __user *ubuf, void __user *ubufend)
     89{
     90	struct gru_tlb_global_handle *tgh;
     91	int i;
     92
     93	if (GRU_NUM_TGH * GRU_CACHE_LINE_BYTES > ubufend - ubuf)
     94		return -EFBIG;
     95
     96	for (i = 0; i < GRU_NUM_TGH; i++) {
     97		tgh = get_tgh(gru->gs_gru_base_vaddr, i);
     98		if (gru_user_copy_handle(&ubuf, tgh))
     99			goto fail;
    100	}
    101	return GRU_NUM_TGH * GRU_CACHE_LINE_BYTES;
    102
    103fail:
    104	return -EFAULT;
    105}
    106
    107static int gru_dump_context(struct gru_state *gru, int ctxnum,
    108		void __user *ubuf, void __user *ubufend, char data_opt,
    109		char lock_cch, char flush_cbrs)
    110{
    111	struct gru_dump_context_header hdr;
    112	struct gru_dump_context_header __user *uhdr = ubuf;
    113	struct gru_context_configuration_handle *cch, *ubufcch;
    114	struct gru_thread_state *gts;
    115	int try, cch_locked, cbrcnt = 0, dsrcnt = 0, bytes = 0, ret = 0;
    116	void *grubase;
    117
    118	memset(&hdr, 0, sizeof(hdr));
    119	grubase = gru->gs_gru_base_vaddr;
    120	cch = get_cch(grubase, ctxnum);
    121	for (try = 0; try < CCH_LOCK_ATTEMPTS; try++) {
    122		cch_locked =  trylock_cch_handle(cch);
    123		if (cch_locked)
    124			break;
    125		msleep(1);
    126	}
    127
    128	ubuf += sizeof(hdr);
    129	ubufcch = ubuf;
    130	if (gru_user_copy_handle(&ubuf, cch)) {
    131		if (cch_locked)
    132			unlock_cch_handle(cch);
    133		return -EFAULT;
    134	}
    135	if (cch_locked)
    136		ubufcch->delresp = 0;
    137	bytes = sizeof(hdr) + GRU_CACHE_LINE_BYTES;
    138
    139	if (cch_locked || !lock_cch) {
    140		gts = gru->gs_gts[ctxnum];
    141		if (gts && gts->ts_vma) {
    142			hdr.pid = gts->ts_tgid_owner;
    143			hdr.vaddr = gts->ts_vma->vm_start;
    144		}
    145		if (cch->state != CCHSTATE_INACTIVE) {
    146			cbrcnt = hweight64(cch->cbr_allocation_map) *
    147						GRU_CBR_AU_SIZE;
    148			dsrcnt = data_opt ? hweight32(cch->dsr_allocation_map) *
    149						GRU_DSR_AU_CL : 0;
    150		}
    151		bytes += (3 * cbrcnt + dsrcnt) * GRU_CACHE_LINE_BYTES;
    152		if (bytes > ubufend - ubuf)
    153			ret = -EFBIG;
    154		else
    155			ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum,
    156							dsrcnt, flush_cbrs);
    157	}
    158	if (cch_locked)
    159		unlock_cch_handle(cch);
    160	if (ret)
    161		return ret;
    162
    163	hdr.magic = GRU_DUMP_MAGIC;
    164	hdr.gid = gru->gs_gid;
    165	hdr.ctxnum = ctxnum;
    166	hdr.cbrcnt = cbrcnt;
    167	hdr.dsrcnt = dsrcnt;
    168	hdr.cch_locked = cch_locked;
    169	if (copy_to_user(uhdr, &hdr, sizeof(hdr)))
    170		return -EFAULT;
    171
    172	return bytes;
    173}
    174
    175int gru_dump_chiplet_request(unsigned long arg)
    176{
    177	struct gru_state *gru;
    178	struct gru_dump_chiplet_state_req req;
    179	void __user *ubuf;
    180	void __user *ubufend;
    181	int ctxnum, ret, cnt = 0;
    182
    183	if (copy_from_user(&req, (void __user *)arg, sizeof(req)))
    184		return -EFAULT;
    185
    186	/* Currently, only dump by gid is implemented */
    187	if (req.gid >= gru_max_gids)
    188		return -EINVAL;
    189	req.gid = array_index_nospec(req.gid, gru_max_gids);
    190
    191	gru = GID_TO_GRU(req.gid);
    192	ubuf = req.buf;
    193	ubufend = req.buf + req.buflen;
    194
    195	ret = gru_dump_tfm(gru, ubuf, ubufend);
    196	if (ret < 0)
    197		goto fail;
    198	ubuf += ret;
    199
    200	ret = gru_dump_tgh(gru, ubuf, ubufend);
    201	if (ret < 0)
    202		goto fail;
    203	ubuf += ret;
    204
    205	for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) {
    206		if (req.ctxnum == ctxnum || req.ctxnum < 0) {
    207			ret = gru_dump_context(gru, ctxnum, ubuf, ubufend,
    208						req.data_opt, req.lock_cch,
    209						req.flush_cbrs);
    210			if (ret < 0)
    211				goto fail;
    212			ubuf += ret;
    213			cnt++;
    214		}
    215	}
    216
    217	if (copy_to_user((void __user *)arg, &req, sizeof(req)))
    218		return -EFAULT;
    219	return cnt;
    220
    221fail:
    222	return ret;
    223}