18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci#ifndef _ASM_X86_TEXT_PATCHING_H 38c2ecf20Sopenharmony_ci#define _ASM_X86_TEXT_PATCHING_H 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/types.h> 68c2ecf20Sopenharmony_ci#include <linux/stddef.h> 78c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_cistruct paravirt_patch_site; 108c2ecf20Sopenharmony_ci#ifdef CONFIG_PARAVIRT 118c2ecf20Sopenharmony_civoid apply_paravirt(struct paravirt_patch_site *start, 128c2ecf20Sopenharmony_ci struct paravirt_patch_site *end); 138c2ecf20Sopenharmony_ci#else 148c2ecf20Sopenharmony_cistatic inline void apply_paravirt(struct paravirt_patch_site *start, 158c2ecf20Sopenharmony_ci struct paravirt_patch_site *end) 168c2ecf20Sopenharmony_ci{} 178c2ecf20Sopenharmony_ci#define __parainstructions NULL 188c2ecf20Sopenharmony_ci#define __parainstructions_end NULL 198c2ecf20Sopenharmony_ci#endif 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * Currently, the max observed size in the kernel code is 238c2ecf20Sopenharmony_ci * JUMP_LABEL_NOP_SIZE/RELATIVEJUMP_SIZE, which are 5. 248c2ecf20Sopenharmony_ci * Raise it if needed. 258c2ecf20Sopenharmony_ci */ 268c2ecf20Sopenharmony_ci#define POKE_MAX_OPCODE_SIZE 5 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ciextern void text_poke_early(void *addr, const void *opcode, size_t len); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * Clear and restore the kernel write-protection flag on the local CPU. 328c2ecf20Sopenharmony_ci * Allows the kernel to edit read-only pages. 338c2ecf20Sopenharmony_ci * Side-effect: any interrupt handler running between save and restore will have 348c2ecf20Sopenharmony_ci * the ability to write to read-only pages. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Warning: 378c2ecf20Sopenharmony_ci * Code patching in the UP case is safe if NMIs and MCE handlers are stopped and 388c2ecf20Sopenharmony_ci * no thread can be preempted in the instructions being modified (no iret to an 398c2ecf20Sopenharmony_ci * invalid instruction possible) or if the instructions are changed from a 408c2ecf20Sopenharmony_ci * consistent state to another consistent state atomically. 418c2ecf20Sopenharmony_ci * On the local CPU you need to be protected against NMI or MCE handlers seeing 428c2ecf20Sopenharmony_ci * an inconsistent instruction while you patch. 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciextern void *text_poke(void *addr, const void *opcode, size_t len); 458c2ecf20Sopenharmony_ciextern void text_poke_sync(void); 468c2ecf20Sopenharmony_ciextern void *text_poke_kgdb(void *addr, const void *opcode, size_t len); 478c2ecf20Sopenharmony_ciextern int poke_int3_handler(struct pt_regs *regs); 488c2ecf20Sopenharmony_ciextern void text_poke_bp(void *addr, const void *opcode, size_t len, const void *emulate); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ciextern void text_poke_queue(void *addr, const void *opcode, size_t len, const void *emulate); 518c2ecf20Sopenharmony_ciextern void text_poke_finish(void); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define INT3_INSN_SIZE 1 548c2ecf20Sopenharmony_ci#define INT3_INSN_OPCODE 0xCC 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define RET_INSN_SIZE 1 578c2ecf20Sopenharmony_ci#define RET_INSN_OPCODE 0xC3 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define CALL_INSN_SIZE 5 608c2ecf20Sopenharmony_ci#define CALL_INSN_OPCODE 0xE8 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define JMP32_INSN_SIZE 5 638c2ecf20Sopenharmony_ci#define JMP32_INSN_OPCODE 0xE9 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci#define JMP8_INSN_SIZE 2 668c2ecf20Sopenharmony_ci#define JMP8_INSN_OPCODE 0xEB 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define DISP32_SIZE 4 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic __always_inline int text_opcode_size(u8 opcode) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci int size = 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define __CASE(insn) \ 758c2ecf20Sopenharmony_ci case insn##_INSN_OPCODE: size = insn##_INSN_SIZE; break 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci switch(opcode) { 788c2ecf20Sopenharmony_ci __CASE(INT3); 798c2ecf20Sopenharmony_ci __CASE(RET); 808c2ecf20Sopenharmony_ci __CASE(CALL); 818c2ecf20Sopenharmony_ci __CASE(JMP32); 828c2ecf20Sopenharmony_ci __CASE(JMP8); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#undef __CASE 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return size; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciunion text_poke_insn { 918c2ecf20Sopenharmony_ci u8 text[POKE_MAX_OPCODE_SIZE]; 928c2ecf20Sopenharmony_ci struct { 938c2ecf20Sopenharmony_ci u8 opcode; 948c2ecf20Sopenharmony_ci s32 disp; 958c2ecf20Sopenharmony_ci } __attribute__((packed)); 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic __always_inline 998c2ecf20Sopenharmony_civoid *text_gen_insn(u8 opcode, const void *addr, const void *dest) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci static union text_poke_insn insn; /* per instance */ 1028c2ecf20Sopenharmony_ci int size = text_opcode_size(opcode); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci insn.opcode = opcode; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (size > 1) { 1078c2ecf20Sopenharmony_ci insn.disp = (long)dest - (long)(addr + size); 1088c2ecf20Sopenharmony_ci if (size == 2) { 1098c2ecf20Sopenharmony_ci /* 1108c2ecf20Sopenharmony_ci * Ensure that for JMP9 the displacement 1118c2ecf20Sopenharmony_ci * actually fits the signed byte. 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci BUG_ON((insn.disp >> 31) != (insn.disp >> 7)); 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return &insn.text; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciextern int after_bootmem; 1218c2ecf20Sopenharmony_ciextern __ro_after_init struct mm_struct *poking_mm; 1228c2ecf20Sopenharmony_ciextern __ro_after_init unsigned long poking_addr; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#ifndef CONFIG_UML_X86 1258c2ecf20Sopenharmony_cistatic __always_inline 1268c2ecf20Sopenharmony_civoid int3_emulate_jmp(struct pt_regs *regs, unsigned long ip) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci regs->ip = ip; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic __always_inline 1328c2ecf20Sopenharmony_civoid int3_emulate_push(struct pt_regs *regs, unsigned long val) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci /* 1358c2ecf20Sopenharmony_ci * The int3 handler in entry_64.S adds a gap between the 1368c2ecf20Sopenharmony_ci * stack where the break point happened, and the saving of 1378c2ecf20Sopenharmony_ci * pt_regs. We can extend the original stack because of 1388c2ecf20Sopenharmony_ci * this gap. See the idtentry macro's create_gap option. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * Similarly entry_32.S will have a gap on the stack for (any) hardware 1418c2ecf20Sopenharmony_ci * exception and pt_regs; see FIXUP_FRAME. 1428c2ecf20Sopenharmony_ci */ 1438c2ecf20Sopenharmony_ci regs->sp -= sizeof(unsigned long); 1448c2ecf20Sopenharmony_ci *(unsigned long *)regs->sp = val; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_cistatic __always_inline 1488c2ecf20Sopenharmony_ciunsigned long int3_emulate_pop(struct pt_regs *regs) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci unsigned long val = *(unsigned long *)regs->sp; 1518c2ecf20Sopenharmony_ci regs->sp += sizeof(unsigned long); 1528c2ecf20Sopenharmony_ci return val; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic __always_inline 1568c2ecf20Sopenharmony_civoid int3_emulate_call(struct pt_regs *regs, unsigned long func) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci int3_emulate_push(regs, regs->ip - INT3_INSN_SIZE + CALL_INSN_SIZE); 1598c2ecf20Sopenharmony_ci int3_emulate_jmp(regs, func); 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic __always_inline 1638c2ecf20Sopenharmony_civoid int3_emulate_ret(struct pt_regs *regs) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci unsigned long ip = int3_emulate_pop(regs); 1668c2ecf20Sopenharmony_ci int3_emulate_jmp(regs, ip); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci#endif /* !CONFIG_UML_X86 */ 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#endif /* _ASM_X86_TEXT_PATCHING_H */ 171