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

api.h (3862B)


      1/* SPDX-License-Identifier: GPL-2.0 */
      2/*
      3 * In-kernel FPU support functions
      4 *
      5 *
      6 * Consider these guidelines before using in-kernel FPU functions:
      7 *
      8 *  1. Use kernel_fpu_begin() and kernel_fpu_end() to enclose all in-kernel
      9 *     use of floating-point or vector registers and instructions.
     10 *
     11 *  2. For kernel_fpu_begin(), specify the vector register range you want to
     12 *     use with the KERNEL_VXR_* constants. Consider these usage guidelines:
     13 *
     14 *     a) If your function typically runs in process-context, use the lower
     15 *	  half of the vector registers, for example, specify KERNEL_VXR_LOW.
     16 *     b) If your function typically runs in soft-irq or hard-irq context,
     17 *	  prefer using the upper half of the vector registers, for example,
     18 *	  specify KERNEL_VXR_HIGH.
     19 *
     20 *     If you adhere to these guidelines, an interrupted process context
     21 *     does not require to save and restore vector registers because of
     22 *     disjoint register ranges.
     23 *
     24 *     Also note that the __kernel_fpu_begin()/__kernel_fpu_end() functions
     25 *     includes logic to save and restore up to 16 vector registers at once.
     26 *
     27 *  3. You can nest kernel_fpu_begin()/kernel_fpu_end() by using different
     28 *     struct kernel_fpu states.  Vector registers that are in use by outer
     29 *     levels are saved and restored.  You can minimize the save and restore
     30 *     effort by choosing disjoint vector register ranges.
     31 *
     32 *  5. To use vector floating-point instructions, specify the KERNEL_FPC
     33 *     flag to save and restore floating-point controls in addition to any
     34 *     vector register range.
     35 *
     36 *  6. To use floating-point registers and instructions only, specify the
     37 *     KERNEL_FPR flag.  This flag triggers a save and restore of vector
     38 *     registers V0 to V15 and floating-point controls.
     39 *
     40 * Copyright IBM Corp. 2015
     41 * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
     42 */
     43
     44#ifndef _ASM_S390_FPU_API_H
     45#define _ASM_S390_FPU_API_H
     46
     47#include <linux/preempt.h>
     48#include <asm/asm-extable.h>
     49
     50void save_fpu_regs(void);
     51void load_fpu_regs(void);
     52void __load_fpu_regs(void);
     53
     54static inline int test_fp_ctl(u32 fpc)
     55{
     56	u32 orig_fpc;
     57	int rc;
     58
     59	asm volatile(
     60		"	efpc    %1\n"
     61		"	sfpc	%2\n"
     62		"0:	sfpc	%1\n"
     63		"	la	%0,0\n"
     64		"1:\n"
     65		EX_TABLE(0b,1b)
     66		: "=d" (rc), "=&d" (orig_fpc)
     67		: "d" (fpc), "0" (-EINVAL));
     68	return rc;
     69}
     70
     71#define KERNEL_FPC		1
     72#define KERNEL_VXR_V0V7		2
     73#define KERNEL_VXR_V8V15	4
     74#define KERNEL_VXR_V16V23	8
     75#define KERNEL_VXR_V24V31	16
     76
     77#define KERNEL_VXR_LOW		(KERNEL_VXR_V0V7|KERNEL_VXR_V8V15)
     78#define KERNEL_VXR_MID		(KERNEL_VXR_V8V15|KERNEL_VXR_V16V23)
     79#define KERNEL_VXR_HIGH		(KERNEL_VXR_V16V23|KERNEL_VXR_V24V31)
     80
     81#define KERNEL_VXR		(KERNEL_VXR_LOW|KERNEL_VXR_HIGH)
     82#define KERNEL_FPR		(KERNEL_FPC|KERNEL_VXR_V0V7)
     83
     84struct kernel_fpu;
     85
     86/*
     87 * Note the functions below must be called with preemption disabled.
     88 * Do not enable preemption before calling __kernel_fpu_end() to prevent
     89 * an corruption of an existing kernel FPU state.
     90 *
     91 * Prefer using the kernel_fpu_begin()/kernel_fpu_end() pair of functions.
     92 */
     93void __kernel_fpu_begin(struct kernel_fpu *state, u32 flags);
     94void __kernel_fpu_end(struct kernel_fpu *state, u32 flags);
     95
     96
     97static inline void kernel_fpu_begin(struct kernel_fpu *state, u32 flags)
     98{
     99	preempt_disable();
    100	state->mask = S390_lowcore.fpu_flags;
    101	if (!test_cpu_flag(CIF_FPU))
    102		/* Save user space FPU state and register contents */
    103		save_fpu_regs();
    104	else if (state->mask & flags)
    105		/* Save FPU/vector register in-use by the kernel */
    106		__kernel_fpu_begin(state, flags);
    107	S390_lowcore.fpu_flags |= flags;
    108}
    109
    110static inline void kernel_fpu_end(struct kernel_fpu *state, u32 flags)
    111{
    112	S390_lowcore.fpu_flags = state->mask;
    113	if (state->mask & flags)
    114		/* Restore FPU/vector register in-use by the kernel */
    115		__kernel_fpu_end(state, flags);
    116	preempt_enable();
    117}
    118
    119#endif /* _ASM_S390_FPU_API_H */