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

fiq.c (3715B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 *  linux/arch/arm/kernel/fiq.c
      4 *
      5 *  Copyright (C) 1998 Russell King
      6 *  Copyright (C) 1998, 1999 Phil Blundell
      7 *
      8 *  FIQ support written by Philip Blundell <philb@gnu.org>, 1998.
      9 *
     10 *  FIQ support re-written by Russell King to be more generic
     11 *
     12 * We now properly support a method by which the FIQ handlers can
     13 * be stacked onto the vector.  We still do not support sharing
     14 * the FIQ vector itself.
     15 *
     16 * Operation is as follows:
     17 *  1. Owner A claims FIQ:
     18 *     - default_fiq relinquishes control.
     19 *  2. Owner A:
     20 *     - inserts code.
     21 *     - sets any registers,
     22 *     - enables FIQ.
     23 *  3. Owner B claims FIQ:
     24 *     - if owner A has a relinquish function.
     25 *       - disable FIQs.
     26 *       - saves any registers.
     27 *       - returns zero.
     28 *  4. Owner B:
     29 *     - inserts code.
     30 *     - sets any registers,
     31 *     - enables FIQ.
     32 *  5. Owner B releases FIQ:
     33 *     - Owner A is asked to reacquire FIQ:
     34 *	 - inserts code.
     35 *	 - restores saved registers.
     36 *	 - enables FIQ.
     37 *  6. Goto 3
     38 */
     39#include <linux/module.h>
     40#include <linux/kernel.h>
     41#include <linux/init.h>
     42#include <linux/interrupt.h>
     43#include <linux/seq_file.h>
     44
     45#include <asm/cacheflush.h>
     46#include <asm/cp15.h>
     47#include <asm/fiq.h>
     48#include <asm/irq.h>
     49#include <asm/traps.h>
     50
     51#define FIQ_OFFSET ({					\
     52		extern void *vector_fiq_offset;		\
     53		(unsigned)&vector_fiq_offset;		\
     54	})
     55
     56static unsigned long dfl_fiq_insn;
     57static struct pt_regs dfl_fiq_regs;
     58
     59/* Default reacquire function
     60 * - we always relinquish FIQ control
     61 * - we always reacquire FIQ control
     62 */
     63static int fiq_def_op(void *ref, int relinquish)
     64{
     65	if (!relinquish) {
     66		/* Restore default handler and registers */
     67		local_fiq_disable();
     68		set_fiq_regs(&dfl_fiq_regs);
     69		set_fiq_handler(&dfl_fiq_insn, sizeof(dfl_fiq_insn));
     70		local_fiq_enable();
     71
     72		/* FIXME: notify irq controller to standard enable FIQs */
     73	}
     74
     75	return 0;
     76}
     77
     78static struct fiq_handler default_owner = {
     79	.name	= "default",
     80	.fiq_op = fiq_def_op,
     81};
     82
     83static struct fiq_handler *current_fiq = &default_owner;
     84
     85int show_fiq_list(struct seq_file *p, int prec)
     86{
     87	if (current_fiq != &default_owner)
     88		seq_printf(p, "%*s:              %s\n", prec, "FIQ",
     89			current_fiq->name);
     90
     91	return 0;
     92}
     93
     94void set_fiq_handler(void *start, unsigned int length)
     95{
     96	void *base = vectors_page;
     97	unsigned offset = FIQ_OFFSET;
     98
     99	memcpy(base + offset, start, length);
    100	if (!cache_is_vipt_nonaliasing())
    101		flush_icache_range((unsigned long)base + offset,
    102				   (unsigned long)base + offset + length);
    103	flush_icache_range(0xffff0000 + offset, 0xffff0000 + offset + length);
    104}
    105
    106int claim_fiq(struct fiq_handler *f)
    107{
    108	int ret = 0;
    109
    110	if (current_fiq) {
    111		ret = -EBUSY;
    112
    113		if (current_fiq->fiq_op != NULL)
    114			ret = current_fiq->fiq_op(current_fiq->dev_id, 1);
    115	}
    116
    117	if (!ret) {
    118		f->next = current_fiq;
    119		current_fiq = f;
    120	}
    121
    122	return ret;
    123}
    124
    125void release_fiq(struct fiq_handler *f)
    126{
    127	if (current_fiq != f) {
    128		pr_err("%s FIQ trying to release %s FIQ\n",
    129		       f->name, current_fiq->name);
    130		dump_stack();
    131		return;
    132	}
    133
    134	do
    135		current_fiq = current_fiq->next;
    136	while (current_fiq->fiq_op(current_fiq->dev_id, 0));
    137}
    138
    139static int fiq_start;
    140
    141void enable_fiq(int fiq)
    142{
    143	enable_irq(fiq + fiq_start);
    144}
    145
    146void disable_fiq(int fiq)
    147{
    148	disable_irq(fiq + fiq_start);
    149}
    150
    151EXPORT_SYMBOL(set_fiq_handler);
    152EXPORT_SYMBOL(__set_fiq_regs);	/* defined in fiqasm.S */
    153EXPORT_SYMBOL(__get_fiq_regs);	/* defined in fiqasm.S */
    154EXPORT_SYMBOL(claim_fiq);
    155EXPORT_SYMBOL(release_fiq);
    156EXPORT_SYMBOL(enable_fiq);
    157EXPORT_SYMBOL(disable_fiq);
    158
    159void __init init_FIQ(int start)
    160{
    161	unsigned offset = FIQ_OFFSET;
    162	dfl_fiq_insn = *(unsigned long *)(0xffff0000 + offset);
    163	get_fiq_regs(&dfl_fiq_regs);
    164	fiq_start = start;
    165}