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 (2484B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Jump label s390 support
      4 *
      5 * Copyright IBM Corp. 2011
      6 * Author(s): Jan Glauber <jang@linux.vnet.ibm.com>
      7 */
      8#include <linux/uaccess.h>
      9#include <linux/jump_label.h>
     10#include <linux/module.h>
     11#include <asm/text-patching.h>
     12#include <asm/ipl.h>
     13
     14struct insn {
     15	u16 opcode;
     16	s32 offset;
     17} __packed;
     18
     19static void jump_label_make_nop(struct jump_entry *entry, struct insn *insn)
     20{
     21	/* brcl 0,offset */
     22	insn->opcode = 0xc004;
     23	insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;
     24}
     25
     26static void jump_label_make_branch(struct jump_entry *entry, struct insn *insn)
     27{
     28	/* brcl 15,offset */
     29	insn->opcode = 0xc0f4;
     30	insn->offset = (jump_entry_target(entry) - jump_entry_code(entry)) >> 1;
     31}
     32
     33static void jump_label_bug(struct jump_entry *entry, struct insn *expected,
     34			   struct insn *new)
     35{
     36	unsigned char *ipc = (unsigned char *)jump_entry_code(entry);
     37	unsigned char *ipe = (unsigned char *)expected;
     38	unsigned char *ipn = (unsigned char *)new;
     39
     40	pr_emerg("Jump label code mismatch at %pS [%px]\n", ipc, ipc);
     41	pr_emerg("Found:    %6ph\n", ipc);
     42	pr_emerg("Expected: %6ph\n", ipe);
     43	pr_emerg("New:      %6ph\n", ipn);
     44	panic("Corrupted kernel text");
     45}
     46
     47static struct insn orignop = {
     48	.opcode = 0xc004,
     49	.offset = JUMP_LABEL_NOP_OFFSET >> 1,
     50};
     51
     52static void jump_label_transform(struct jump_entry *entry,
     53				 enum jump_label_type type,
     54				 int init)
     55{
     56	void *code = (void *)jump_entry_code(entry);
     57	struct insn old, new;
     58
     59	if (type == JUMP_LABEL_JMP) {
     60		jump_label_make_nop(entry, &old);
     61		jump_label_make_branch(entry, &new);
     62	} else {
     63		jump_label_make_branch(entry, &old);
     64		jump_label_make_nop(entry, &new);
     65	}
     66	if (init) {
     67		if (memcmp(code, &orignop, sizeof(orignop)))
     68			jump_label_bug(entry, &orignop, &new);
     69	} else {
     70		if (memcmp(code, &old, sizeof(old)))
     71			jump_label_bug(entry, &old, &new);
     72	}
     73	s390_kernel_write(code, &new, sizeof(new));
     74}
     75
     76void arch_jump_label_transform(struct jump_entry *entry,
     77			       enum jump_label_type type)
     78{
     79	jump_label_transform(entry, type, 0);
     80	text_poke_sync();
     81}
     82
     83bool arch_jump_label_transform_queue(struct jump_entry *entry,
     84				     enum jump_label_type type)
     85{
     86	jump_label_transform(entry, type, 0);
     87	return true;
     88}
     89
     90void arch_jump_label_transform_apply(void)
     91{
     92	text_poke_sync();
     93}
     94
     95void __init_or_module arch_jump_label_transform_static(struct jump_entry *entry,
     96						       enum jump_label_type type)
     97{
     98	jump_label_transform(entry, type, 1);
     99	text_poke_sync();
    100}