1ebc00ddeSEmil Renner Berthing // SPDX-License-Identifier: GPL-2.0-only 2ebc00ddeSEmil Renner Berthing /* 3ebc00ddeSEmil Renner Berthing * Copyright (C) 2020 Emil Renner Berthing 4ebc00ddeSEmil Renner Berthing * 5ebc00ddeSEmil Renner Berthing * Based on arch/arm64/kernel/jump_label.c 6ebc00ddeSEmil Renner Berthing */ 7ebc00ddeSEmil Renner Berthing #include <linux/jump_label.h> 8ebc00ddeSEmil Renner Berthing #include <linux/kernel.h> 9ebc00ddeSEmil Renner Berthing #include <linux/memory.h> 10ebc00ddeSEmil Renner Berthing #include <linux/mutex.h> 11ebc00ddeSEmil Renner Berthing #include <asm/bug.h> 12ebc00ddeSEmil Renner Berthing #include <asm/patch.h> 13ebc00ddeSEmil Renner Berthing 14ebc00ddeSEmil Renner Berthing #define RISCV_INSN_NOP 0x00000013U 15ebc00ddeSEmil Renner Berthing #define RISCV_INSN_JAL 0x0000006fU 16ebc00ddeSEmil Renner Berthing arch_jump_label_transform(struct jump_entry * entry,enum jump_label_type type)17ebc00ddeSEmil Renner Berthingvoid arch_jump_label_transform(struct jump_entry *entry, 18ebc00ddeSEmil Renner Berthing enum jump_label_type type) 19ebc00ddeSEmil Renner Berthing { 20ebc00ddeSEmil Renner Berthing void *addr = (void *)jump_entry_code(entry); 21ebc00ddeSEmil Renner Berthing u32 insn; 22ebc00ddeSEmil Renner Berthing 23ebc00ddeSEmil Renner Berthing if (type == JUMP_LABEL_JMP) { 24ebc00ddeSEmil Renner Berthing long offset = jump_entry_target(entry) - jump_entry_code(entry); 25ebc00ddeSEmil Renner Berthing 26ebc00ddeSEmil Renner Berthing if (WARN_ON(offset & 1 || offset < -524288 || offset >= 524288)) 27ebc00ddeSEmil Renner Berthing return; 28ebc00ddeSEmil Renner Berthing 29ebc00ddeSEmil Renner Berthing insn = RISCV_INSN_JAL | 30ebc00ddeSEmil Renner Berthing (((u32)offset & GENMASK(19, 12)) << (12 - 12)) | 31ebc00ddeSEmil Renner Berthing (((u32)offset & GENMASK(11, 11)) << (20 - 11)) | 32ebc00ddeSEmil Renner Berthing (((u32)offset & GENMASK(10, 1)) << (21 - 1)) | 33ebc00ddeSEmil Renner Berthing (((u32)offset & GENMASK(20, 20)) << (31 - 20)); 34ebc00ddeSEmil Renner Berthing } else { 35ebc00ddeSEmil Renner Berthing insn = RISCV_INSN_NOP; 36ebc00ddeSEmil Renner Berthing } 37ebc00ddeSEmil Renner Berthing 38ebc00ddeSEmil Renner Berthing mutex_lock(&text_mutex); 39ebc00ddeSEmil Renner Berthing patch_text_nosync(addr, &insn, sizeof(insn)); 40ebc00ddeSEmil Renner Berthing mutex_unlock(&text_mutex); 41ebc00ddeSEmil Renner Berthing } 42