1*32b2cf11SSong Liu // SPDX-License-Identifier: GPL-2.0
2*32b2cf11SSong Liu /*
3*32b2cf11SSong Liu * An x86 alternative whose replacement code is part of the patched function's
4*32b2cf11SSong Liu * checksum.
5*32b2cf11SSong Liu *
6*32b2cf11SSong Liu * checksum_update_insn() walks insn->alts after hashing the instruction
7*32b2cf11SSong Liu * itself, hashing the alternative's type and, when the replacement forms a
8*32b2cf11SSong Liu * group, its feature number and every instruction in it. So editing only the
9*32b2cf11SSong Liu * replacement -- code the CPU may or may not ever run -- has to move the
10*32b2cf11SSong Liu * function's checksum.
11*32b2cf11SSong Liu *
12*32b2cf11SSong Liu * It is reached through objtool's own alternative handling, so the object has
13*32b2cf11SSong Liu * to go through the check pass first: insn->alts is built there, not by the
14*32b2cf11SSong Liu * compiler.
15*32b2cf11SSong Liu *
16*32b2cf11SSong Liu * struct alt_instr is written out by hand as in empty_alternative.c: s32
17*32b2cf11SSong Liu * instr_offset, s32 repl_offset, u32 ft_flags, u8 instrlen, u8 replacementlen.
18*32b2cf11SSong Liu *
19*32b2cf11SSong Liu * Variants, applied to the patched build only:
20*32b2cf11SSong Liu *
21*32b2cf11SSong Liu * ALT_REPL the replacement instruction changes; the original does not
22*32b2cf11SSong Liu * ALT_FEATURE the feature number changes; no code changes at all
23*32b2cf11SSong Liu */
24*32b2cf11SSong Liu
25*32b2cf11SSong Liu static const char __modinfo[]
26*32b2cf11SSong Liu __attribute__((section(".modinfo"), used, aligned(1))) = "\0name=vmlinux";
27*32b2cf11SSong Liu
28*32b2cf11SSong Liu /*
29*32b2cf11SSong Liu * Both spellings are two bytes, because a replacement may not be longer than
30*32b2cf11SSong Liu * the instruction it replaces: "xchg %ax, %ax" is 66 90 and two nops are
31*32b2cf11SSong Liu * 90 90. The original below is padded to match.
32*32b2cf11SSong Liu */
33*32b2cf11SSong Liu #if defined(PATCHED) && defined(ALT_REPL)
34*32b2cf11SSong Liu #define REPL_INSN " nop\n\t nop\n\t"
35*32b2cf11SSong Liu #else
36*32b2cf11SSong Liu #define REPL_INSN " xchg %ax, %ax\n\t"
37*32b2cf11SSong Liu #endif
38*32b2cf11SSong Liu
39*32b2cf11SSong Liu #if defined(PATCHED) && defined(ALT_FEATURE)
40*32b2cf11SSong Liu #define FEATURE "7"
41*32b2cf11SSong Liu #else
42*32b2cf11SSong Liu #define FEATURE "3"
43*32b2cf11SSong Liu #endif
44*32b2cf11SSong Liu
target(int x)45*32b2cf11SSong Liu int target(int x)
46*32b2cf11SSong Liu {
47*32b2cf11SSong Liu asm volatile(
48*32b2cf11SSong Liu "661: nop\n\t"
49*32b2cf11SSong Liu " nop\n\t"
50*32b2cf11SSong Liu "662:\n\t"
51*32b2cf11SSong Liu ".pushsection .altinstr_replacement, \"ax\"\n\t"
52*32b2cf11SSong Liu ".globl target_repl\n\t"
53*32b2cf11SSong Liu "target_repl:\n\t"
54*32b2cf11SSong Liu REPL_INSN
55*32b2cf11SSong Liu "target_repl_end:\n\t"
56*32b2cf11SSong Liu ".popsection\n\t"
57*32b2cf11SSong Liu ".pushsection .altinstructions, \"aM\", @progbits, 14\n\t"
58*32b2cf11SSong Liu ".long 661b - .\n\t"
59*32b2cf11SSong Liu ".long target_repl - .\n\t"
60*32b2cf11SSong Liu ".long " FEATURE "\n\t"
61*32b2cf11SSong Liu ".byte 662b - 661b\n\t"
62*32b2cf11SSong Liu ".byte target_repl_end - target_repl\n\t"
63*32b2cf11SSong Liu ".popsection\n\t");
64*32b2cf11SSong Liu
65*32b2cf11SSong Liu return x + 1;
66*32b2cf11SSong Liu }
67