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

jump_label.c (2494B)


      1/*
      2 * This file is subject to the terms and conditions of the GNU General Public
      3 * License.  See the file "COPYING" in the main directory of this archive
      4 * for more details.
      5 *
      6 * Copyright (c) 2010 Cavium Networks, Inc.
      7 */
      8
      9#include <linux/jump_label.h>
     10#include <linux/kernel.h>
     11#include <linux/memory.h>
     12#include <linux/mutex.h>
     13#include <linux/types.h>
     14#include <linux/cpu.h>
     15
     16#include <asm/cacheflush.h>
     17#include <asm/inst.h>
     18
     19/*
     20 * Define parameters for the standard MIPS and the microMIPS jump
     21 * instruction encoding respectively:
     22 *
     23 * - the ISA bit of the target, either 0 or 1 respectively,
     24 *
     25 * - the amount the jump target address is shifted right to fit in the
     26 *   immediate field of the machine instruction, either 2 or 1,
     27 *
     28 * - the mask determining the size of the jump region relative to the
     29 *   delay-slot instruction, either 256MB or 128MB,
     30 *
     31 * - the jump target alignment, either 4 or 2 bytes.
     32 */
     33#define J_ISA_BIT	IS_ENABLED(CONFIG_CPU_MICROMIPS)
     34#define J_RANGE_SHIFT	(2 - J_ISA_BIT)
     35#define J_RANGE_MASK	((1ul << (26 + J_RANGE_SHIFT)) - 1)
     36#define J_ALIGN_MASK	((1ul << J_RANGE_SHIFT) - 1)
     37
     38void arch_jump_label_transform(struct jump_entry *e,
     39			       enum jump_label_type type)
     40{
     41	union mips_instruction *insn_p;
     42	union mips_instruction insn;
     43	long offset;
     44
     45	insn_p = (union mips_instruction *)msk_isa16_mode(e->code);
     46
     47	/* Target must have the right alignment and ISA must be preserved. */
     48	BUG_ON((e->target & J_ALIGN_MASK) != J_ISA_BIT);
     49
     50	if (type == JUMP_LABEL_JMP) {
     51		if (!IS_ENABLED(CONFIG_CPU_MICROMIPS) && MIPS_ISA_REV >= 6) {
     52			offset = e->target - ((unsigned long)insn_p + 4);
     53			offset >>= 2;
     54
     55			/*
     56			 * The branch offset must fit in the instruction's 26
     57			 * bit field.
     58			 */
     59			WARN_ON((offset >= BIT(25)) ||
     60				(offset < -(long)BIT(25)));
     61
     62			insn.j_format.opcode = bc6_op;
     63			insn.j_format.target = offset;
     64		} else {
     65			/*
     66			 * Jump only works within an aligned region its delay
     67			 * slot is in.
     68			 */
     69			WARN_ON((e->target & ~J_RANGE_MASK) !=
     70				((e->code + 4) & ~J_RANGE_MASK));
     71
     72			insn.j_format.opcode = J_ISA_BIT ? mm_j32_op : j_op;
     73			insn.j_format.target = e->target >> J_RANGE_SHIFT;
     74		}
     75	} else {
     76		insn.word = 0; /* nop */
     77	}
     78
     79	mutex_lock(&text_mutex);
     80	if (IS_ENABLED(CONFIG_CPU_MICROMIPS)) {
     81		insn_p->halfword[0] = insn.word >> 16;
     82		insn_p->halfword[1] = insn.word;
     83	} else
     84		*insn_p = insn;
     85
     86	flush_icache_range((unsigned long)insn_p,
     87			   (unsigned long)insn_p + sizeof(*insn_p));
     88
     89	mutex_unlock(&text_mutex);
     90}