Commit 8b5a10fc authored by Jan Beulich's avatar Jan Beulich Committed by H. Peter Anvin

x86: properly annotate alternatives.c

Some of the NOPs tables aren't used on 64-bits, quite some code and
data is needed post-init for module loading only, and a couple of
functions aren't used outside that file (i.e. can be static, and don't
need to be exported).

The change to __INITDATA/__INITRODATA is needed to avoid an assembler
warning.
Signed-off-by: default avatarJan Beulich <jbeulich@novell.com>
LKML-Reference: <4A8BC8A00200007800010823@vpn.id2.novell.com>
Acked-by: default avatarSam Ravnborg <sam@ravnborg.org>
Signed-off-by: default avatarH. Peter Anvin <hpa@zytor.com>
parent c7425314
...@@ -73,8 +73,6 @@ static inline void alternatives_smp_module_del(struct module *mod) {} ...@@ -73,8 +73,6 @@ static inline void alternatives_smp_module_del(struct module *mod) {}
static inline void alternatives_smp_switch(int smp) {} static inline void alternatives_smp_switch(int smp) {}
#endif /* CONFIG_SMP */ #endif /* CONFIG_SMP */
const unsigned char *const *find_nop_table(void);
/* alternative assembly primitive: */ /* alternative assembly primitive: */
#define ALTERNATIVE(oldinstr, newinstr, feature) \ #define ALTERNATIVE(oldinstr, newinstr, feature) \
\ \
...@@ -144,8 +142,6 @@ static inline void apply_paravirt(struct paravirt_patch_site *start, ...@@ -144,8 +142,6 @@ static inline void apply_paravirt(struct paravirt_patch_site *start,
#define __parainstructions_end NULL #define __parainstructions_end NULL
#endif #endif
extern void add_nops(void *insns, unsigned int len);
/* /*
* Clear and restore the kernel write-protection flag on the local CPU. * Clear and restore the kernel write-protection flag on the local CPU.
* Allows the kernel to edit read-only pages. * Allows the kernel to edit read-only pages.
...@@ -161,10 +157,7 @@ extern void add_nops(void *insns, unsigned int len); ...@@ -161,10 +157,7 @@ extern void add_nops(void *insns, unsigned int len);
* Intel's errata. * Intel's errata.
* On the local CPU you need to be protected again NMI or MCE handlers seeing an * On the local CPU you need to be protected again NMI or MCE handlers seeing an
* inconsistent instruction while you patch. * inconsistent instruction while you patch.
* The _early version expects the memory to already be RW.
*/ */
extern void *text_poke(void *addr, const void *opcode, size_t len); extern void *text_poke(void *addr, const void *opcode, size_t len);
extern void *text_poke_early(void *addr, const void *opcode, size_t len);
#endif /* _ASM_X86_ALTERNATIVE_H */ #endif /* _ASM_X86_ALTERNATIVE_H */
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/stringify.h>
#include <linux/kprobes.h> #include <linux/kprobes.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
...@@ -32,7 +33,7 @@ __setup("smp-alt-boot", bootonly); ...@@ -32,7 +33,7 @@ __setup("smp-alt-boot", bootonly);
#define smp_alt_once 1 #define smp_alt_once 1
#endif #endif
static int debug_alternative; static int __initdata_or_module debug_alternative;
static int __init debug_alt(char *str) static int __init debug_alt(char *str)
{ {
...@@ -51,7 +52,7 @@ static int __init setup_noreplace_smp(char *str) ...@@ -51,7 +52,7 @@ static int __init setup_noreplace_smp(char *str)
__setup("noreplace-smp", setup_noreplace_smp); __setup("noreplace-smp", setup_noreplace_smp);
#ifdef CONFIG_PARAVIRT #ifdef CONFIG_PARAVIRT
static int noreplace_paravirt = 0; static int __initdata_or_module noreplace_paravirt = 0;
static int __init setup_noreplace_paravirt(char *str) static int __init setup_noreplace_paravirt(char *str)
{ {
...@@ -64,16 +65,17 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt); ...@@ -64,16 +65,17 @@ __setup("noreplace-paravirt", setup_noreplace_paravirt);
#define DPRINTK(fmt, args...) if (debug_alternative) \ #define DPRINTK(fmt, args...) if (debug_alternative) \
printk(KERN_DEBUG fmt, args) printk(KERN_DEBUG fmt, args)
#ifdef GENERIC_NOP1 #if defined(GENERIC_NOP1) && !defined(CONFIG_X86_64)
/* Use inline assembly to define this because the nops are defined /* Use inline assembly to define this because the nops are defined
as inline assembly strings in the include files and we cannot as inline assembly strings in the include files and we cannot
get them easily into strings. */ get them easily into strings. */
asm("\t.section .rodata, \"a\"\nintelnops: " asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nintelnops: "
GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6 GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6
GENERIC_NOP7 GENERIC_NOP8 GENERIC_NOP7 GENERIC_NOP8
"\t.previous"); "\t.previous");
extern const unsigned char intelnops[]; extern const unsigned char intelnops[];
static const unsigned char *const intel_nops[ASM_NOP_MAX+1] = { static const unsigned char *const __initconst_or_module
intel_nops[ASM_NOP_MAX+1] = {
NULL, NULL,
intelnops, intelnops,
intelnops + 1, intelnops + 1,
...@@ -87,12 +89,13 @@ static const unsigned char *const intel_nops[ASM_NOP_MAX+1] = { ...@@ -87,12 +89,13 @@ static const unsigned char *const intel_nops[ASM_NOP_MAX+1] = {
#endif #endif
#ifdef K8_NOP1 #ifdef K8_NOP1
asm("\t.section .rodata, \"a\"\nk8nops: " asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk8nops: "
K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6 K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
K8_NOP7 K8_NOP8 K8_NOP7 K8_NOP8
"\t.previous"); "\t.previous");
extern const unsigned char k8nops[]; extern const unsigned char k8nops[];
static const unsigned char *const k8_nops[ASM_NOP_MAX+1] = { static const unsigned char *const __initconst_or_module
k8_nops[ASM_NOP_MAX+1] = {
NULL, NULL,
k8nops, k8nops,
k8nops + 1, k8nops + 1,
...@@ -105,13 +108,14 @@ static const unsigned char *const k8_nops[ASM_NOP_MAX+1] = { ...@@ -105,13 +108,14 @@ static const unsigned char *const k8_nops[ASM_NOP_MAX+1] = {
}; };
#endif #endif
#ifdef K7_NOP1 #if defined(K7_NOP1) && !defined(CONFIG_X86_64)
asm("\t.section .rodata, \"a\"\nk7nops: " asm("\t" __stringify(__INITRODATA_OR_MODULE) "\nk7nops: "
K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6 K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
K7_NOP7 K7_NOP8 K7_NOP7 K7_NOP8
"\t.previous"); "\t.previous");
extern const unsigned char k7nops[]; extern const unsigned char k7nops[];
static const unsigned char *const k7_nops[ASM_NOP_MAX+1] = { static const unsigned char *const __initconst_or_module
k7_nops[ASM_NOP_MAX+1] = {
NULL, NULL,
k7nops, k7nops,
k7nops + 1, k7nops + 1,
...@@ -125,12 +129,13 @@ static const unsigned char *const k7_nops[ASM_NOP_MAX+1] = { ...@@ -125,12 +129,13 @@ static const unsigned char *const k7_nops[ASM_NOP_MAX+1] = {
#endif #endif
#ifdef P6_NOP1 #ifdef P6_NOP1
asm("\t.section .rodata, \"a\"\np6nops: " asm("\t" __stringify(__INITRODATA_OR_MODULE) "\np6nops: "
P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6 P6_NOP1 P6_NOP2 P6_NOP3 P6_NOP4 P6_NOP5 P6_NOP6
P6_NOP7 P6_NOP8 P6_NOP7 P6_NOP8
"\t.previous"); "\t.previous");
extern const unsigned char p6nops[]; extern const unsigned char p6nops[];
static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = { static const unsigned char *const __initconst_or_module
p6_nops[ASM_NOP_MAX+1] = {
NULL, NULL,
p6nops, p6nops,
p6nops + 1, p6nops + 1,
...@@ -146,7 +151,7 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = { ...@@ -146,7 +151,7 @@ static const unsigned char *const p6_nops[ASM_NOP_MAX+1] = {
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
extern char __vsyscall_0; extern char __vsyscall_0;
const unsigned char *const *find_nop_table(void) static const unsigned char *const *__init_or_module find_nop_table(void)
{ {
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
boot_cpu_has(X86_FEATURE_NOPL)) boot_cpu_has(X86_FEATURE_NOPL))
...@@ -157,7 +162,7 @@ const unsigned char *const *find_nop_table(void) ...@@ -157,7 +162,7 @@ const unsigned char *const *find_nop_table(void)
#else /* CONFIG_X86_64 */ #else /* CONFIG_X86_64 */
const unsigned char *const *find_nop_table(void) static const unsigned char *const *__init_or_module find_nop_table(void)
{ {
if (boot_cpu_has(X86_FEATURE_K8)) if (boot_cpu_has(X86_FEATURE_K8))
return k8_nops; return k8_nops;
...@@ -172,7 +177,7 @@ const unsigned char *const *find_nop_table(void) ...@@ -172,7 +177,7 @@ const unsigned char *const *find_nop_table(void)
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */
/* Use this to add nops to a buffer, then text_poke the whole buffer. */ /* Use this to add nops to a buffer, then text_poke the whole buffer. */
void add_nops(void *insns, unsigned int len) static void __init_or_module add_nops(void *insns, unsigned int len)
{ {
const unsigned char *const *noptable = find_nop_table(); const unsigned char *const *noptable = find_nop_table();
...@@ -185,10 +190,10 @@ void add_nops(void *insns, unsigned int len) ...@@ -185,10 +190,10 @@ void add_nops(void *insns, unsigned int len)
len -= noplen; len -= noplen;
} }
} }
EXPORT_SYMBOL_GPL(add_nops);
extern struct alt_instr __alt_instructions[], __alt_instructions_end[]; extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
extern u8 *__smp_locks[], *__smp_locks_end[]; extern u8 *__smp_locks[], *__smp_locks_end[];
static void *text_poke_early(void *addr, const void *opcode, size_t len);
/* Replace instructions with better alternatives for this CPU type. /* Replace instructions with better alternatives for this CPU type.
This runs before SMP is initialized to avoid SMP problems with This runs before SMP is initialized to avoid SMP problems with
...@@ -196,7 +201,8 @@ extern u8 *__smp_locks[], *__smp_locks_end[]; ...@@ -196,7 +201,8 @@ extern u8 *__smp_locks[], *__smp_locks_end[];
APs have less capabilities than the boot processor are not handled. APs have less capabilities than the boot processor are not handled.
Tough. Make sure you disable such features by hand. */ Tough. Make sure you disable such features by hand. */
void apply_alternatives(struct alt_instr *start, struct alt_instr *end) void __init_or_module apply_alternatives(struct alt_instr *start,
struct alt_instr *end)
{ {
struct alt_instr *a; struct alt_instr *a;
char insnbuf[MAX_PATCH_LEN]; char insnbuf[MAX_PATCH_LEN];
...@@ -279,9 +285,10 @@ static LIST_HEAD(smp_alt_modules); ...@@ -279,9 +285,10 @@ static LIST_HEAD(smp_alt_modules);
static DEFINE_MUTEX(smp_alt); static DEFINE_MUTEX(smp_alt);
static int smp_mode = 1; /* protected by smp_alt */ static int smp_mode = 1; /* protected by smp_alt */
void alternatives_smp_module_add(struct module *mod, char *name, void __init_or_module alternatives_smp_module_add(struct module *mod,
void *locks, void *locks_end, char *name,
void *text, void *text_end) void *locks, void *locks_end,
void *text, void *text_end)
{ {
struct smp_alt_module *smp; struct smp_alt_module *smp;
...@@ -317,7 +324,7 @@ void alternatives_smp_module_add(struct module *mod, char *name, ...@@ -317,7 +324,7 @@ void alternatives_smp_module_add(struct module *mod, char *name,
mutex_unlock(&smp_alt); mutex_unlock(&smp_alt);
} }
void alternatives_smp_module_del(struct module *mod) void __init_or_module alternatives_smp_module_del(struct module *mod)
{ {
struct smp_alt_module *item; struct smp_alt_module *item;
...@@ -386,8 +393,8 @@ void alternatives_smp_switch(int smp) ...@@ -386,8 +393,8 @@ void alternatives_smp_switch(int smp)
#endif #endif
#ifdef CONFIG_PARAVIRT #ifdef CONFIG_PARAVIRT
void apply_paravirt(struct paravirt_patch_site *start, void __init_or_module apply_paravirt(struct paravirt_patch_site *start,
struct paravirt_patch_site *end) struct paravirt_patch_site *end)
{ {
struct paravirt_patch_site *p; struct paravirt_patch_site *p;
char insnbuf[MAX_PATCH_LEN]; char insnbuf[MAX_PATCH_LEN];
...@@ -485,7 +492,8 @@ void __init alternative_instructions(void) ...@@ -485,7 +492,8 @@ void __init alternative_instructions(void)
* instructions. And on the local CPU you need to be protected again NMI or MCE * instructions. And on the local CPU you need to be protected again NMI or MCE
* handlers seeing an inconsistent instruction while you patch. * handlers seeing an inconsistent instruction while you patch.
*/ */
void *text_poke_early(void *addr, const void *opcode, size_t len) static void *__init_or_module text_poke_early(void *addr, const void *opcode,
size_t len)
{ {
unsigned long flags; unsigned long flags;
local_irq_save(flags); local_irq_save(flags);
......
...@@ -103,8 +103,8 @@ ...@@ -103,8 +103,8 @@
#define __INIT .section ".init.text","ax" #define __INIT .section ".init.text","ax"
#define __FINIT .previous #define __FINIT .previous
#define __INITDATA .section ".init.data","aw" #define __INITDATA .section ".init.data","aw",%progbits
#define __INITRODATA .section ".init.rodata","a" #define __INITRODATA .section ".init.rodata","a",%progbits
#define __FINITDATA .previous #define __FINITDATA .previous
#define __DEVINIT .section ".devinit.text", "ax" #define __DEVINIT .section ".devinit.text", "ax"
...@@ -305,9 +305,17 @@ void __init parse_early_options(char *cmdline); ...@@ -305,9 +305,17 @@ void __init parse_early_options(char *cmdline);
#ifdef CONFIG_MODULES #ifdef CONFIG_MODULES
#define __init_or_module #define __init_or_module
#define __initdata_or_module #define __initdata_or_module
#define __initconst_or_module
#define __INIT_OR_MODULE .text
#define __INITDATA_OR_MODULE .data
#define __INITRODATA_OR_MODULE .section ".rodata","a",%progbits
#else #else
#define __init_or_module __init #define __init_or_module __init
#define __initdata_or_module __initdata #define __initdata_or_module __initdata
#define __initconst_or_module __initconst
#define __INIT_OR_MODULE __INIT
#define __INITDATA_OR_MODULE __INITDATA
#define __INITRODATA_OR_MODULE __INITRODATA
#endif /*CONFIG_MODULES*/ #endif /*CONFIG_MODULES*/
/* Functions marked as __devexit may be discarded at kernel link time, depending /* Functions marked as __devexit may be discarded at kernel link time, depending
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment