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

notif.c (2511B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2015-2021, Linaro Limited
      4 */
      5
      6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      7
      8#include <linux/arm-smccc.h>
      9#include <linux/errno.h>
     10#include <linux/slab.h>
     11#include <linux/spinlock.h>
     12#include <linux/tee_drv.h>
     13#include "optee_private.h"
     14
     15struct notif_entry {
     16	struct list_head link;
     17	struct completion c;
     18	u_int key;
     19};
     20
     21static bool have_key(struct optee *optee, u_int key)
     22{
     23	struct notif_entry *entry;
     24
     25	list_for_each_entry(entry, &optee->notif.db, link)
     26		if (entry->key == key)
     27			return true;
     28
     29	return false;
     30}
     31
     32int optee_notif_wait(struct optee *optee, u_int key)
     33{
     34	unsigned long flags;
     35	struct notif_entry *entry;
     36	int rc = 0;
     37
     38	if (key > optee->notif.max_key)
     39		return -EINVAL;
     40
     41	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
     42	if (!entry)
     43		return -ENOMEM;
     44	init_completion(&entry->c);
     45	entry->key = key;
     46
     47	spin_lock_irqsave(&optee->notif.lock, flags);
     48
     49	/*
     50	 * If the bit is already set it means that the key has already
     51	 * been posted and we must not wait.
     52	 */
     53	if (test_bit(key, optee->notif.bitmap)) {
     54		clear_bit(key, optee->notif.bitmap);
     55		goto out;
     56	}
     57
     58	/*
     59	 * Check if someone is already waiting for this key. If there is
     60	 * it's a programming error.
     61	 */
     62	if (have_key(optee, key)) {
     63		rc = -EBUSY;
     64		goto out;
     65	}
     66
     67	list_add_tail(&entry->link, &optee->notif.db);
     68
     69	/*
     70	 * Unlock temporarily and wait for completion.
     71	 */
     72	spin_unlock_irqrestore(&optee->notif.lock, flags);
     73	wait_for_completion(&entry->c);
     74	spin_lock_irqsave(&optee->notif.lock, flags);
     75
     76	list_del(&entry->link);
     77out:
     78	spin_unlock_irqrestore(&optee->notif.lock, flags);
     79
     80	kfree(entry);
     81
     82	return rc;
     83}
     84
     85int optee_notif_send(struct optee *optee, u_int key)
     86{
     87	unsigned long flags;
     88	struct notif_entry *entry;
     89
     90	if (key > optee->notif.max_key)
     91		return -EINVAL;
     92
     93	spin_lock_irqsave(&optee->notif.lock, flags);
     94
     95	list_for_each_entry(entry, &optee->notif.db, link)
     96		if (entry->key == key) {
     97			complete(&entry->c);
     98			goto out;
     99		}
    100
    101	/* Only set the bit in case there where nobody waiting */
    102	set_bit(key, optee->notif.bitmap);
    103out:
    104	spin_unlock_irqrestore(&optee->notif.lock, flags);
    105
    106	return 0;
    107}
    108
    109int optee_notif_init(struct optee *optee, u_int max_key)
    110{
    111	spin_lock_init(&optee->notif.lock);
    112	INIT_LIST_HEAD(&optee->notif.db);
    113	optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
    114	if (!optee->notif.bitmap)
    115		return -ENOMEM;
    116
    117	optee->notif.max_key = max_key;
    118
    119	return 0;
    120}
    121
    122void optee_notif_uninit(struct optee *optee)
    123{
    124	bitmap_free(optee->notif.bitmap);
    125}