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

context.c (7606B)


      1// SPDX-License-Identifier: GPL-2.0+
      2// Copyright 2017 IBM Corp.
      3#include <linux/sched/mm.h>
      4#include "trace.h"
      5#include "ocxl_internal.h"
      6
      7int ocxl_context_alloc(struct ocxl_context **context, struct ocxl_afu *afu,
      8		struct address_space *mapping)
      9{
     10	int pasid;
     11	struct ocxl_context *ctx;
     12
     13	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
     14	if (!ctx)
     15		return -ENOMEM;
     16
     17	ctx->afu = afu;
     18	mutex_lock(&afu->contexts_lock);
     19	pasid = idr_alloc(&afu->contexts_idr, ctx, afu->pasid_base,
     20			afu->pasid_base + afu->pasid_max, GFP_KERNEL);
     21	if (pasid < 0) {
     22		mutex_unlock(&afu->contexts_lock);
     23		kfree(ctx);
     24		return pasid;
     25	}
     26	afu->pasid_count++;
     27	mutex_unlock(&afu->contexts_lock);
     28
     29	ctx->pasid = pasid;
     30	ctx->status = OPENED;
     31	mutex_init(&ctx->status_mutex);
     32	ctx->mapping = mapping;
     33	mutex_init(&ctx->mapping_lock);
     34	init_waitqueue_head(&ctx->events_wq);
     35	mutex_init(&ctx->xsl_error_lock);
     36	mutex_init(&ctx->irq_lock);
     37	idr_init(&ctx->irq_idr);
     38	ctx->tidr = 0;
     39
     40	/*
     41	 * Keep a reference on the AFU to make sure it's valid for the
     42	 * duration of the life of the context
     43	 */
     44	ocxl_afu_get(afu);
     45	*context = ctx;
     46	return 0;
     47}
     48EXPORT_SYMBOL_GPL(ocxl_context_alloc);
     49
     50/*
     51 * Callback for when a translation fault triggers an error
     52 * data:	a pointer to the context which triggered the fault
     53 * addr:	the address that triggered the error
     54 * dsisr:	the value of the PPC64 dsisr register
     55 */
     56static void xsl_fault_error(void *data, u64 addr, u64 dsisr)
     57{
     58	struct ocxl_context *ctx = (struct ocxl_context *) data;
     59
     60	mutex_lock(&ctx->xsl_error_lock);
     61	ctx->xsl_error.addr = addr;
     62	ctx->xsl_error.dsisr = dsisr;
     63	ctx->xsl_error.count++;
     64	mutex_unlock(&ctx->xsl_error_lock);
     65
     66	wake_up_all(&ctx->events_wq);
     67}
     68
     69int ocxl_context_attach(struct ocxl_context *ctx, u64 amr, struct mm_struct *mm)
     70{
     71	int rc;
     72	unsigned long pidr = 0;
     73	struct pci_dev *dev;
     74
     75	// Locks both status & tidr
     76	mutex_lock(&ctx->status_mutex);
     77	if (ctx->status != OPENED) {
     78		rc = -EIO;
     79		goto out;
     80	}
     81
     82	if (mm)
     83		pidr = mm->context.id;
     84
     85	dev = to_pci_dev(ctx->afu->fn->dev.parent);
     86	rc = ocxl_link_add_pe(ctx->afu->fn->link, ctx->pasid, pidr, ctx->tidr,
     87			      amr, pci_dev_id(dev), mm, xsl_fault_error, ctx);
     88	if (rc)
     89		goto out;
     90
     91	ctx->status = ATTACHED;
     92out:
     93	mutex_unlock(&ctx->status_mutex);
     94	return rc;
     95}
     96EXPORT_SYMBOL_GPL(ocxl_context_attach);
     97
     98static vm_fault_t map_afu_irq(struct vm_area_struct *vma, unsigned long address,
     99		u64 offset, struct ocxl_context *ctx)
    100{
    101	u64 trigger_addr;
    102	int irq_id = ocxl_irq_offset_to_id(ctx, offset);
    103
    104	trigger_addr = ocxl_afu_irq_get_addr(ctx, irq_id);
    105	if (!trigger_addr)
    106		return VM_FAULT_SIGBUS;
    107
    108	return vmf_insert_pfn(vma, address, trigger_addr >> PAGE_SHIFT);
    109}
    110
    111static vm_fault_t map_pp_mmio(struct vm_area_struct *vma, unsigned long address,
    112		u64 offset, struct ocxl_context *ctx)
    113{
    114	u64 pp_mmio_addr;
    115	int pasid_off;
    116	vm_fault_t ret;
    117
    118	if (offset >= ctx->afu->config.pp_mmio_stride)
    119		return VM_FAULT_SIGBUS;
    120
    121	mutex_lock(&ctx->status_mutex);
    122	if (ctx->status != ATTACHED) {
    123		mutex_unlock(&ctx->status_mutex);
    124		pr_debug("%s: Context not attached, failing mmio mmap\n",
    125			__func__);
    126		return VM_FAULT_SIGBUS;
    127	}
    128
    129	pasid_off = ctx->pasid - ctx->afu->pasid_base;
    130	pp_mmio_addr = ctx->afu->pp_mmio_start +
    131		pasid_off * ctx->afu->config.pp_mmio_stride +
    132		offset;
    133
    134	ret = vmf_insert_pfn(vma, address, pp_mmio_addr >> PAGE_SHIFT);
    135	mutex_unlock(&ctx->status_mutex);
    136	return ret;
    137}
    138
    139static vm_fault_t ocxl_mmap_fault(struct vm_fault *vmf)
    140{
    141	struct vm_area_struct *vma = vmf->vma;
    142	struct ocxl_context *ctx = vma->vm_file->private_data;
    143	u64 offset;
    144	vm_fault_t ret;
    145
    146	offset = vmf->pgoff << PAGE_SHIFT;
    147	pr_debug("%s: pasid %d address 0x%lx offset 0x%llx\n", __func__,
    148		ctx->pasid, vmf->address, offset);
    149
    150	if (offset < ctx->afu->irq_base_offset)
    151		ret = map_pp_mmio(vma, vmf->address, offset, ctx);
    152	else
    153		ret = map_afu_irq(vma, vmf->address, offset, ctx);
    154	return ret;
    155}
    156
    157static const struct vm_operations_struct ocxl_vmops = {
    158	.fault = ocxl_mmap_fault,
    159};
    160
    161static int check_mmap_afu_irq(struct ocxl_context *ctx,
    162			struct vm_area_struct *vma)
    163{
    164	int irq_id = ocxl_irq_offset_to_id(ctx, vma->vm_pgoff << PAGE_SHIFT);
    165
    166	/* only one page */
    167	if (vma_pages(vma) != 1)
    168		return -EINVAL;
    169
    170	/* check offset validty */
    171	if (!ocxl_afu_irq_get_addr(ctx, irq_id))
    172		return -EINVAL;
    173
    174	/*
    175	 * trigger page should only be accessible in write mode.
    176	 *
    177	 * It's a bit theoretical, as a page mmaped with only
    178	 * PROT_WRITE is currently readable, but it doesn't hurt.
    179	 */
    180	if ((vma->vm_flags & VM_READ) || (vma->vm_flags & VM_EXEC) ||
    181		!(vma->vm_flags & VM_WRITE))
    182		return -EINVAL;
    183	vma->vm_flags &= ~(VM_MAYREAD | VM_MAYEXEC);
    184	return 0;
    185}
    186
    187static int check_mmap_mmio(struct ocxl_context *ctx,
    188			struct vm_area_struct *vma)
    189{
    190	if ((vma_pages(vma) + vma->vm_pgoff) >
    191		(ctx->afu->config.pp_mmio_stride >> PAGE_SHIFT))
    192		return -EINVAL;
    193	return 0;
    194}
    195
    196int ocxl_context_mmap(struct ocxl_context *ctx, struct vm_area_struct *vma)
    197{
    198	int rc;
    199
    200	if ((vma->vm_pgoff << PAGE_SHIFT) < ctx->afu->irq_base_offset)
    201		rc = check_mmap_mmio(ctx, vma);
    202	else
    203		rc = check_mmap_afu_irq(ctx, vma);
    204	if (rc)
    205		return rc;
    206
    207	vma->vm_flags |= VM_IO | VM_PFNMAP;
    208	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    209	vma->vm_ops = &ocxl_vmops;
    210	return 0;
    211}
    212
    213int ocxl_context_detach(struct ocxl_context *ctx)
    214{
    215	struct pci_dev *dev;
    216	int afu_control_pos;
    217	enum ocxl_context_status status;
    218	int rc;
    219
    220	mutex_lock(&ctx->status_mutex);
    221	status = ctx->status;
    222	ctx->status = CLOSED;
    223	mutex_unlock(&ctx->status_mutex);
    224	if (status != ATTACHED)
    225		return 0;
    226
    227	dev = to_pci_dev(ctx->afu->fn->dev.parent);
    228	afu_control_pos = ctx->afu->config.dvsec_afu_control_pos;
    229
    230	mutex_lock(&ctx->afu->afu_control_lock);
    231	rc = ocxl_config_terminate_pasid(dev, afu_control_pos, ctx->pasid);
    232	mutex_unlock(&ctx->afu->afu_control_lock);
    233	trace_ocxl_terminate_pasid(ctx->pasid, rc);
    234	if (rc) {
    235		/*
    236		 * If we timeout waiting for the AFU to terminate the
    237		 * pasid, then it's dangerous to clean up the Process
    238		 * Element entry in the SPA, as it may be referenced
    239		 * in the future by the AFU. In which case, we would
    240		 * checkstop because of an invalid PE access (FIR
    241		 * register 2, bit 42). So leave the PE
    242		 * defined. Caller shouldn't free the context so that
    243		 * PASID remains allocated.
    244		 *
    245		 * A link reset will be required to cleanup the AFU
    246		 * and the SPA.
    247		 */
    248		if (rc == -EBUSY)
    249			return rc;
    250	}
    251	rc = ocxl_link_remove_pe(ctx->afu->fn->link, ctx->pasid);
    252	if (rc) {
    253		dev_warn(&dev->dev,
    254			"Couldn't remove PE entry cleanly: %d\n", rc);
    255	}
    256	return 0;
    257}
    258EXPORT_SYMBOL_GPL(ocxl_context_detach);
    259
    260void ocxl_context_detach_all(struct ocxl_afu *afu)
    261{
    262	struct ocxl_context *ctx;
    263	int tmp;
    264
    265	mutex_lock(&afu->contexts_lock);
    266	idr_for_each_entry(&afu->contexts_idr, ctx, tmp) {
    267		ocxl_context_detach(ctx);
    268		/*
    269		 * We are force detaching - remove any active mmio
    270		 * mappings so userspace cannot interfere with the
    271		 * card if it comes back.  Easiest way to exercise
    272		 * this is to unbind and rebind the driver via sysfs
    273		 * while it is in use.
    274		 */
    275		mutex_lock(&ctx->mapping_lock);
    276		if (ctx->mapping)
    277			unmap_mapping_range(ctx->mapping, 0, 0, 1);
    278		mutex_unlock(&ctx->mapping_lock);
    279	}
    280	mutex_unlock(&afu->contexts_lock);
    281}
    282
    283void ocxl_context_free(struct ocxl_context *ctx)
    284{
    285	mutex_lock(&ctx->afu->contexts_lock);
    286	ctx->afu->pasid_count--;
    287	idr_remove(&ctx->afu->contexts_idr, ctx->pasid);
    288	mutex_unlock(&ctx->afu->contexts_lock);
    289
    290	ocxl_afu_irq_free_all(ctx);
    291	idr_destroy(&ctx->irq_idr);
    292	/* reference to the AFU taken in ocxl_context_alloc() */
    293	ocxl_afu_put(ctx->afu);
    294	kfree(ctx);
    295}
    296EXPORT_SYMBOL_GPL(ocxl_context_free);