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

kc.c (3184B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PPS kernel consumer API
      4 *
      5 * Copyright (C) 2009-2010   Alexander Gordeev <lasaine@lvk.cs.msu.su>
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/device.h>
     13#include <linux/init.h>
     14#include <linux/spinlock.h>
     15#include <linux/pps_kernel.h>
     16
     17#include "kc.h"
     18
     19/*
     20 * Global variables
     21 */
     22
     23/* state variables to bind kernel consumer */
     24static DEFINE_SPINLOCK(pps_kc_hardpps_lock);
     25/* PPS API (RFC 2783): current source and mode for kernel consumer */
     26static struct pps_device *pps_kc_hardpps_dev;	/* unique pointer to device */
     27static int pps_kc_hardpps_mode;		/* mode bits for kernel consumer */
     28
     29/* pps_kc_bind - control PPS kernel consumer binding
     30 * @pps: the PPS source
     31 * @bind_args: kernel consumer bind parameters
     32 *
     33 * This function is used to bind or unbind PPS kernel consumer according to
     34 * supplied parameters. Should not be called in interrupt context.
     35 */
     36int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
     37{
     38	/* Check if another consumer is already bound */
     39	spin_lock_irq(&pps_kc_hardpps_lock);
     40
     41	if (bind_args->edge == 0)
     42		if (pps_kc_hardpps_dev == pps) {
     43			pps_kc_hardpps_mode = 0;
     44			pps_kc_hardpps_dev = NULL;
     45			spin_unlock_irq(&pps_kc_hardpps_lock);
     46			dev_info(pps->dev, "unbound kernel"
     47					" consumer\n");
     48		} else {
     49			spin_unlock_irq(&pps_kc_hardpps_lock);
     50			dev_err(pps->dev, "selected kernel consumer"
     51					" is not bound\n");
     52			return -EINVAL;
     53		}
     54	else
     55		if (pps_kc_hardpps_dev == NULL ||
     56				pps_kc_hardpps_dev == pps) {
     57			pps_kc_hardpps_mode = bind_args->edge;
     58			pps_kc_hardpps_dev = pps;
     59			spin_unlock_irq(&pps_kc_hardpps_lock);
     60			dev_info(pps->dev, "bound kernel consumer: "
     61				"edge=0x%x\n", bind_args->edge);
     62		} else {
     63			spin_unlock_irq(&pps_kc_hardpps_lock);
     64			dev_err(pps->dev, "another kernel consumer"
     65					" is already bound\n");
     66			return -EINVAL;
     67		}
     68
     69	return 0;
     70}
     71
     72/* pps_kc_remove - unbind kernel consumer on PPS source removal
     73 * @pps: the PPS source
     74 *
     75 * This function is used to disable kernel consumer on PPS source removal
     76 * if this source was bound to PPS kernel consumer. Can be called on any
     77 * source safely. Should not be called in interrupt context.
     78 */
     79void pps_kc_remove(struct pps_device *pps)
     80{
     81	spin_lock_irq(&pps_kc_hardpps_lock);
     82	if (pps == pps_kc_hardpps_dev) {
     83		pps_kc_hardpps_mode = 0;
     84		pps_kc_hardpps_dev = NULL;
     85		spin_unlock_irq(&pps_kc_hardpps_lock);
     86		dev_info(pps->dev, "unbound kernel consumer"
     87				" on device removal\n");
     88	} else
     89		spin_unlock_irq(&pps_kc_hardpps_lock);
     90}
     91
     92/* pps_kc_event - call hardpps() on PPS event
     93 * @pps: the PPS source
     94 * @ts: PPS event timestamp
     95 * @event: PPS event edge
     96 *
     97 * This function calls hardpps() when an event from bound PPS source occurs.
     98 */
     99void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
    100		int event)
    101{
    102	unsigned long flags;
    103
    104	/* Pass some events to kernel consumer if activated */
    105	spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
    106	if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
    107		hardpps(&ts->ts_real, &ts->ts_raw);
    108	spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
    109}