1d9f5ab7bSJason Baron /* 2d9f5ab7bSJason Baron * jump label x86 support 3d9f5ab7bSJason Baron * 4d9f5ab7bSJason Baron * Copyright (C) 2009 Jason Baron <jbaron@redhat.com> 5d9f5ab7bSJason Baron * 6d9f5ab7bSJason Baron */ 7d9f5ab7bSJason Baron #include <linux/jump_label.h> 8d9f5ab7bSJason Baron #include <linux/memory.h> 9d9f5ab7bSJason Baron #include <linux/uaccess.h> 10d9f5ab7bSJason Baron #include <linux/module.h> 11d9f5ab7bSJason Baron #include <linux/list.h> 12d9f5ab7bSJason Baron #include <linux/jhash.h> 13d9f5ab7bSJason Baron #include <linux/cpu.h> 14d9f5ab7bSJason Baron #include <asm/kprobes.h> 15d9f5ab7bSJason Baron #include <asm/alternative.h> 16d9f5ab7bSJason Baron 17d9f5ab7bSJason Baron #ifdef HAVE_JUMP_LABEL 18d9f5ab7bSJason Baron 19d9f5ab7bSJason Baron union jump_code_union { 20d9f5ab7bSJason Baron char code[JUMP_LABEL_NOP_SIZE]; 21d9f5ab7bSJason Baron struct { 22d9f5ab7bSJason Baron char jump; 23d9f5ab7bSJason Baron int offset; 24d9f5ab7bSJason Baron } __attribute__((packed)); 25d9f5ab7bSJason Baron }; 26d9f5ab7bSJason Baron 27e71a5be1SJeremy Fitzhardinge static void __jump_label_transform(struct jump_entry *entry, 28e71a5be1SJeremy Fitzhardinge enum jump_label_type type, 29e71a5be1SJeremy Fitzhardinge void *(*poker)(void *, const void *, size_t)) 30d9f5ab7bSJason Baron { 31d9f5ab7bSJason Baron union jump_code_union code; 32d9f5ab7bSJason Baron 33d9f5ab7bSJason Baron if (type == JUMP_LABEL_ENABLE) { 34d9f5ab7bSJason Baron code.jump = 0xe9; 35d9f5ab7bSJason Baron code.offset = entry->target - 36d9f5ab7bSJason Baron (entry->code + JUMP_LABEL_NOP_SIZE); 37d9f5ab7bSJason Baron } else 38dc326fcaSH. Peter Anvin memcpy(&code, ideal_nops[NOP_ATOMIC5], JUMP_LABEL_NOP_SIZE); 39e71a5be1SJeremy Fitzhardinge 40*51b2c07bSJiri Kosina /* 41*51b2c07bSJiri Kosina * Make text_poke_bp() a default fallback poker. 42*51b2c07bSJiri Kosina * 43*51b2c07bSJiri Kosina * At the time the change is being done, just ignore whether we 44*51b2c07bSJiri Kosina * are doing nop -> jump or jump -> nop transition, and assume 45*51b2c07bSJiri Kosina * always nop being the 'currently valid' instruction 46*51b2c07bSJiri Kosina * 47*51b2c07bSJiri Kosina */ 48*51b2c07bSJiri Kosina if (poker) 49e71a5be1SJeremy Fitzhardinge (*poker)((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE); 50*51b2c07bSJiri Kosina else 51*51b2c07bSJiri Kosina text_poke_bp((void *)entry->code, &code, JUMP_LABEL_NOP_SIZE, 52*51b2c07bSJiri Kosina (void *)entry->code + JUMP_LABEL_NOP_SIZE); 53e71a5be1SJeremy Fitzhardinge } 54e71a5be1SJeremy Fitzhardinge 55e71a5be1SJeremy Fitzhardinge void arch_jump_label_transform(struct jump_entry *entry, 56e71a5be1SJeremy Fitzhardinge enum jump_label_type type) 57e71a5be1SJeremy Fitzhardinge { 58d9f5ab7bSJason Baron get_online_cpus(); 59d9f5ab7bSJason Baron mutex_lock(&text_mutex); 60*51b2c07bSJiri Kosina __jump_label_transform(entry, type, NULL); 61d9f5ab7bSJason Baron mutex_unlock(&text_mutex); 62d9f5ab7bSJason Baron put_online_cpus(); 63d9f5ab7bSJason Baron } 64d9f5ab7bSJason Baron 659cdbe1cbSPeter Zijlstra __init_or_module void arch_jump_label_transform_static(struct jump_entry *entry, 66e71a5be1SJeremy Fitzhardinge enum jump_label_type type) 67e71a5be1SJeremy Fitzhardinge { 68e71a5be1SJeremy Fitzhardinge __jump_label_transform(entry, type, text_poke_early); 69e71a5be1SJeremy Fitzhardinge } 70e71a5be1SJeremy Fitzhardinge 71d9f5ab7bSJason Baron #endif 72