/* * Alternative inline assembly for SMP. * * The LOCK_PREFIX macro defined here replaces the LOCK and * LOCK_PREFIX macros used everywhere in the source tree. * * SMP alternatives use the same data structures as the other * alternatives and the X86_FEATURE_UP flag to indicate the case of a * UP system running a SMP kernel. The existing apply_alternatives() * works fine for patching a SMP kernel for UP. * * The SMP alternative tables can be kept after boot and contain both * UP and SMP versions of the instructions to allow switching back to * SMP at runtime, when hotplugging in a new CPU, which is especially * useful in virtualized environments. * * The very common lock prefix is handled as special case in a * separate table which is a pure address list without replacement ptr * and size information. That keeps the table sizes small.
*/
/* * The patching flags are part of the upper bits of the @ft_flags parameter when * specifying them. The split is currently like this: * * [31... flags ...16][15... CPUID feature bit ...0] * * but since this is all hidden in the macros argument being split, those fields can be * extended in the future to fit in a u64 or however the need arises.
*/ struct alt_instr {
s32 instr_offset; /* original instruction */
s32 repl_offset; /* offset to replacement instruction */
union { struct {
u32 cpuid: 16; /* CPUID bit set for replacement */
u32 flags: 16; /* patching control flags */
};
u32 ft_flags;
};
u8 instrlen; /* length of original instruction */
u8 replacementlen; /* length of new instruction */
} __packed;
/* * Alternative instructions for different CPU types or capabilities. * * This allows to use optimized instructions even on generic binary * kernels. * * length of oldinstr must be longer or equal the length of newinstr * It can be padded with nops as needed. * * For non barrier like inlines please define new variants * without volatile and memory clobber.
*/ #define alternative(oldinstr, newinstr, ft_flags) \
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) : : : "memory")
/* * Alternative inline assembly with input. * * Peculiarities: * No memory clobber here. * Argument numbers start with 1. * Leaving an unused argument 0 to keep API compatibility.
*/ #define alternative_input(oldinstr, newinstr, ft_flags, input...) \
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) \
: : "i" (0), ## input)
/* Like alternative_input, but with a single output argument */ #define alternative_io(oldinstr, newinstr, ft_flags, output, input...) \
asm_inline volatile(ALTERNATIVE(oldinstr, newinstr, ft_flags) \
: output : "i" (0), ## input)
/* * Like alternative_io, but for replacing a direct call with another one. * * Use the %c operand modifier which is the generic way to print a bare * constant expression with all syntax-specific punctuation omitted. %P * is the x86-specific variant which can handle constants too, for * historical reasons, but it should be used primarily for PIC * references: i.e., if used for a function, it would add the PLT * suffix.
*/ #define alternative_call(oldfunc, newfunc, ft_flags, output, input, clobbers...) \
asm_inline volatile(ALTERNATIVE("call %c[old]", "call %c[new]", ft_flags) \
: ALT_OUTPUT_SP(output) \
: [old] "i" (oldfunc), [new] "i" (newfunc) \
COMMA(input) \
: clobbers)
/* * Like alternative_call, but there are two features and respective functions. * If CPU has feature2, function2 is used. * Otherwise, if CPU has feature1, function1 is used. * Otherwise, old function is used.
*/ #define alternative_call_2(oldfunc, newfunc1, ft_flags1, newfunc2, ft_flags2, \
output, input, clobbers...) \
asm_inline volatile(ALTERNATIVE_2("call %c[old]", "call %c[new1]", ft_flags1, \ "call %c[new2]", ft_flags2) \
: ALT_OUTPUT_SP(output) \
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
[new2] "i" (newfunc2) \
COMMA(input) \
: clobbers)
/* * Issue one struct alt_instr descriptor entry (need to put it into * the section .altinstructions, see below). This entry contains * enough information for the alternatives patching code to patch an * instruction. See apply_alternatives().
*/
.macro altinstr_entry orig alt ft_flags orig_len alt_len
.long \orig - .
.long \alt - .
.4byte \ft_flags
.byte \orig_len
.byte \alt_len
.endm
.macro ALT_CALL_INSTR
call BUG_func
.endm
/* * Define an alternative between two instructions. If @feature is * present, early code in apply_alternatives() replaces @oldinstr with * @newinstr. ".skip" directive takes care of proper instruction padding * in case @newinstr is longer than @oldinstr.
*/ #define __ALTERNATIVE(oldinst, newinst, flag) \
740: \
oldinst ; \
741: \
.skip -(((744f-743f)-(741b-740b)) > 0) * ((744f-743f)-(741b-740b)),0x90 ;\
742: \
.pushsection .altinstructions,"a" ; \
altinstr_entry 740b,743f,flag,742b-740b,744f-743f ; \
.popsection ; \
.pushsection .altinstr_replacement,"ax" ; \
743: \
newinst ; \
744: \
.popsection ;
.macro ALTERNATIVE oldinstr, newinstr, ft_flags
__ALTERNATIVE(\oldinstr, \newinstr, \ft_flags)
.endm
/* * Same as ALTERNATIVE macro above but for two alternatives. If CPU * has @feature1, it replaces @oldinstr with @newinstr1. If CPU has * @feature2, it replaces @oldinstr with @feature2.
*/
.macro ALTERNATIVE_2 oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2
__ALTERNATIVE(__ALTERNATIVE(\oldinstr, \newinstr1, \ft_flags1),
\newinstr2, \ft_flags2)
.endm
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.