18fd4dddaSChristophe Leroy // SPDX-License-Identifier: GPL-2.0
28fd4dddaSChristophe Leroy #include <linux/init.h>
38fd4dddaSChristophe Leroy #include <linux/static_call.h>
48fd4dddaSChristophe Leroy #include <linux/bug.h>
58fd4dddaSChristophe Leroy #include <linux/smp.h>
68fd4dddaSChristophe Leroy #include <linux/sort.h>
78fd4dddaSChristophe Leroy #include <linux/slab.h>
88fd4dddaSChristophe Leroy #include <linux/module.h>
98fd4dddaSChristophe Leroy #include <linux/cpu.h>
108fd4dddaSChristophe Leroy #include <linux/processor.h>
118fd4dddaSChristophe Leroy #include <asm/sections.h>
128fd4dddaSChristophe Leroy
138fd4dddaSChristophe Leroy extern struct static_call_site __start_static_call_sites[],
148fd4dddaSChristophe Leroy __stop_static_call_sites[];
158fd4dddaSChristophe Leroy extern struct static_call_tramp_key __start_static_call_tramp_key[],
168fd4dddaSChristophe Leroy __stop_static_call_tramp_key[];
178fd4dddaSChristophe Leroy
18*cd951495SJuergen Gross int static_call_initialized;
197825451fSPeter Zijlstra
207825451fSPeter Zijlstra /*
217825451fSPeter Zijlstra * Must be called before early_initcall() to be effective.
227825451fSPeter Zijlstra */
static_call_force_reinit(void)237825451fSPeter Zijlstra void static_call_force_reinit(void)
247825451fSPeter Zijlstra {
257825451fSPeter Zijlstra if (WARN_ON_ONCE(!static_call_initialized))
267825451fSPeter Zijlstra return;
277825451fSPeter Zijlstra
287825451fSPeter Zijlstra static_call_initialized++;
297825451fSPeter Zijlstra }
308fd4dddaSChristophe Leroy
318fd4dddaSChristophe Leroy /* mutex to protect key modules/sites */
328fd4dddaSChristophe Leroy static DEFINE_MUTEX(static_call_mutex);
338fd4dddaSChristophe Leroy
static_call_lock(void)348fd4dddaSChristophe Leroy static void static_call_lock(void)
358fd4dddaSChristophe Leroy {
368fd4dddaSChristophe Leroy mutex_lock(&static_call_mutex);
378fd4dddaSChristophe Leroy }
388fd4dddaSChristophe Leroy
static_call_unlock(void)398fd4dddaSChristophe Leroy static void static_call_unlock(void)
408fd4dddaSChristophe Leroy {
418fd4dddaSChristophe Leroy mutex_unlock(&static_call_mutex);
428fd4dddaSChristophe Leroy }
438fd4dddaSChristophe Leroy
static_call_addr(struct static_call_site * site)448fd4dddaSChristophe Leroy static inline void *static_call_addr(struct static_call_site *site)
458fd4dddaSChristophe Leroy {
468fd4dddaSChristophe Leroy return (void *)((long)site->addr + (long)&site->addr);
478fd4dddaSChristophe Leroy }
488fd4dddaSChristophe Leroy
__static_call_key(const struct static_call_site * site)498fd4dddaSChristophe Leroy static inline unsigned long __static_call_key(const struct static_call_site *site)
508fd4dddaSChristophe Leroy {
518fd4dddaSChristophe Leroy return (long)site->key + (long)&site->key;
528fd4dddaSChristophe Leroy }
538fd4dddaSChristophe Leroy
static_call_key(const struct static_call_site * site)548fd4dddaSChristophe Leroy static inline struct static_call_key *static_call_key(const struct static_call_site *site)
558fd4dddaSChristophe Leroy {
568fd4dddaSChristophe Leroy return (void *)(__static_call_key(site) & ~STATIC_CALL_SITE_FLAGS);
578fd4dddaSChristophe Leroy }
588fd4dddaSChristophe Leroy
598fd4dddaSChristophe Leroy /* These assume the key is word-aligned. */
static_call_is_init(struct static_call_site * site)608fd4dddaSChristophe Leroy static inline bool static_call_is_init(struct static_call_site *site)
618fd4dddaSChristophe Leroy {
628fd4dddaSChristophe Leroy return __static_call_key(site) & STATIC_CALL_SITE_INIT;
638fd4dddaSChristophe Leroy }
648fd4dddaSChristophe Leroy
static_call_is_tail(struct static_call_site * site)658fd4dddaSChristophe Leroy static inline bool static_call_is_tail(struct static_call_site *site)
668fd4dddaSChristophe Leroy {
678fd4dddaSChristophe Leroy return __static_call_key(site) & STATIC_CALL_SITE_TAIL;
688fd4dddaSChristophe Leroy }
698fd4dddaSChristophe Leroy
static_call_set_init(struct static_call_site * site)708fd4dddaSChristophe Leroy static inline void static_call_set_init(struct static_call_site *site)
718fd4dddaSChristophe Leroy {
728fd4dddaSChristophe Leroy site->key = (__static_call_key(site) | STATIC_CALL_SITE_INIT) -
738fd4dddaSChristophe Leroy (long)&site->key;
748fd4dddaSChristophe Leroy }
758fd4dddaSChristophe Leroy
static_call_site_cmp(const void * _a,const void * _b)768fd4dddaSChristophe Leroy static int static_call_site_cmp(const void *_a, const void *_b)
778fd4dddaSChristophe Leroy {
788fd4dddaSChristophe Leroy const struct static_call_site *a = _a;
798fd4dddaSChristophe Leroy const struct static_call_site *b = _b;
808fd4dddaSChristophe Leroy const struct static_call_key *key_a = static_call_key(a);
818fd4dddaSChristophe Leroy const struct static_call_key *key_b = static_call_key(b);
828fd4dddaSChristophe Leroy
838fd4dddaSChristophe Leroy if (key_a < key_b)
848fd4dddaSChristophe Leroy return -1;
858fd4dddaSChristophe Leroy
868fd4dddaSChristophe Leroy if (key_a > key_b)
878fd4dddaSChristophe Leroy return 1;
888fd4dddaSChristophe Leroy
898fd4dddaSChristophe Leroy return 0;
908fd4dddaSChristophe Leroy }
918fd4dddaSChristophe Leroy
static_call_site_swap(void * _a,void * _b,int size)928fd4dddaSChristophe Leroy static void static_call_site_swap(void *_a, void *_b, int size)
938fd4dddaSChristophe Leroy {
948fd4dddaSChristophe Leroy long delta = (unsigned long)_a - (unsigned long)_b;
958fd4dddaSChristophe Leroy struct static_call_site *a = _a;
968fd4dddaSChristophe Leroy struct static_call_site *b = _b;
978fd4dddaSChristophe Leroy struct static_call_site tmp = *a;
988fd4dddaSChristophe Leroy
998fd4dddaSChristophe Leroy a->addr = b->addr - delta;
1008fd4dddaSChristophe Leroy a->key = b->key - delta;
1018fd4dddaSChristophe Leroy
1028fd4dddaSChristophe Leroy b->addr = tmp.addr + delta;
1038fd4dddaSChristophe Leroy b->key = tmp.key + delta;
1048fd4dddaSChristophe Leroy }
1058fd4dddaSChristophe Leroy
static_call_sort_entries(struct static_call_site * start,struct static_call_site * stop)1068fd4dddaSChristophe Leroy static inline void static_call_sort_entries(struct static_call_site *start,
1078fd4dddaSChristophe Leroy struct static_call_site *stop)
1088fd4dddaSChristophe Leroy {
1098fd4dddaSChristophe Leroy sort(start, stop - start, sizeof(struct static_call_site),
1108fd4dddaSChristophe Leroy static_call_site_cmp, static_call_site_swap);
1118fd4dddaSChristophe Leroy }
1128fd4dddaSChristophe Leroy
static_call_key_has_mods(struct static_call_key * key)1138fd4dddaSChristophe Leroy static inline bool static_call_key_has_mods(struct static_call_key *key)
1148fd4dddaSChristophe Leroy {
1158fd4dddaSChristophe Leroy return !(key->type & 1);
1168fd4dddaSChristophe Leroy }
1178fd4dddaSChristophe Leroy
static_call_key_next(struct static_call_key * key)1188fd4dddaSChristophe Leroy static inline struct static_call_mod *static_call_key_next(struct static_call_key *key)
1198fd4dddaSChristophe Leroy {
1208fd4dddaSChristophe Leroy if (!static_call_key_has_mods(key))
1218fd4dddaSChristophe Leroy return NULL;
1228fd4dddaSChristophe Leroy
1238fd4dddaSChristophe Leroy return key->mods;
1248fd4dddaSChristophe Leroy }
1258fd4dddaSChristophe Leroy
static_call_key_sites(struct static_call_key * key)1268fd4dddaSChristophe Leroy static inline struct static_call_site *static_call_key_sites(struct static_call_key *key)
1278fd4dddaSChristophe Leroy {
1288fd4dddaSChristophe Leroy if (static_call_key_has_mods(key))
1298fd4dddaSChristophe Leroy return NULL;
1308fd4dddaSChristophe Leroy
1318fd4dddaSChristophe Leroy return (struct static_call_site *)(key->type & ~1);
1328fd4dddaSChristophe Leroy }
1338fd4dddaSChristophe Leroy
__static_call_update(struct static_call_key * key,void * tramp,void * func)1348fd4dddaSChristophe Leroy void __static_call_update(struct static_call_key *key, void *tramp, void *func)
1358fd4dddaSChristophe Leroy {
1368fd4dddaSChristophe Leroy struct static_call_site *site, *stop;
1378fd4dddaSChristophe Leroy struct static_call_mod *site_mod, first;
1388fd4dddaSChristophe Leroy
1398fd4dddaSChristophe Leroy cpus_read_lock();
1408fd4dddaSChristophe Leroy static_call_lock();
1418fd4dddaSChristophe Leroy
1428fd4dddaSChristophe Leroy if (key->func == func)
1438fd4dddaSChristophe Leroy goto done;
1448fd4dddaSChristophe Leroy
1458fd4dddaSChristophe Leroy key->func = func;
1468fd4dddaSChristophe Leroy
1478fd4dddaSChristophe Leroy arch_static_call_transform(NULL, tramp, func, false);
1488fd4dddaSChristophe Leroy
1498fd4dddaSChristophe Leroy /*
1508fd4dddaSChristophe Leroy * If uninitialized, we'll not update the callsites, but they still
1518fd4dddaSChristophe Leroy * point to the trampoline and we just patched that.
1528fd4dddaSChristophe Leroy */
1538fd4dddaSChristophe Leroy if (WARN_ON_ONCE(!static_call_initialized))
1548fd4dddaSChristophe Leroy goto done;
1558fd4dddaSChristophe Leroy
1568fd4dddaSChristophe Leroy first = (struct static_call_mod){
1578fd4dddaSChristophe Leroy .next = static_call_key_next(key),
1588fd4dddaSChristophe Leroy .mod = NULL,
1598fd4dddaSChristophe Leroy .sites = static_call_key_sites(key),
1608fd4dddaSChristophe Leroy };
1618fd4dddaSChristophe Leroy
1628fd4dddaSChristophe Leroy for (site_mod = &first; site_mod; site_mod = site_mod->next) {
1638fd4dddaSChristophe Leroy bool init = system_state < SYSTEM_RUNNING;
1648fd4dddaSChristophe Leroy struct module *mod = site_mod->mod;
1658fd4dddaSChristophe Leroy
1668fd4dddaSChristophe Leroy if (!site_mod->sites) {
1678fd4dddaSChristophe Leroy /*
1688fd4dddaSChristophe Leroy * This can happen if the static call key is defined in
1698fd4dddaSChristophe Leroy * a module which doesn't use it.
1708fd4dddaSChristophe Leroy *
1718fd4dddaSChristophe Leroy * It also happens in the has_mods case, where the
1728fd4dddaSChristophe Leroy * 'first' entry has no sites associated with it.
1738fd4dddaSChristophe Leroy */
1748fd4dddaSChristophe Leroy continue;
1758fd4dddaSChristophe Leroy }
1768fd4dddaSChristophe Leroy
1778fd4dddaSChristophe Leroy stop = __stop_static_call_sites;
1788fd4dddaSChristophe Leroy
1798fd4dddaSChristophe Leroy if (mod) {
1808fd4dddaSChristophe Leroy #ifdef CONFIG_MODULES
1818fd4dddaSChristophe Leroy stop = mod->static_call_sites +
1828fd4dddaSChristophe Leroy mod->num_static_call_sites;
1838fd4dddaSChristophe Leroy init = mod->state == MODULE_STATE_COMING;
1848fd4dddaSChristophe Leroy #endif
1858fd4dddaSChristophe Leroy }
1868fd4dddaSChristophe Leroy
1878fd4dddaSChristophe Leroy for (site = site_mod->sites;
1888fd4dddaSChristophe Leroy site < stop && static_call_key(site) == key; site++) {
1898fd4dddaSChristophe Leroy void *site_addr = static_call_addr(site);
1908fd4dddaSChristophe Leroy
1918fd4dddaSChristophe Leroy if (!init && static_call_is_init(site))
1928fd4dddaSChristophe Leroy continue;
1938fd4dddaSChristophe Leroy
1948fd4dddaSChristophe Leroy if (!kernel_text_address((unsigned long)site_addr)) {
1958fd4dddaSChristophe Leroy /*
1968fd4dddaSChristophe Leroy * This skips patching built-in __exit, which
1978fd4dddaSChristophe Leroy * is part of init_section_contains() but is
1988fd4dddaSChristophe Leroy * not part of kernel_text_address().
1998fd4dddaSChristophe Leroy *
2008fd4dddaSChristophe Leroy * Skipping built-in __exit is fine since it
2018fd4dddaSChristophe Leroy * will never be executed.
2028fd4dddaSChristophe Leroy */
2038fd4dddaSChristophe Leroy WARN_ONCE(!static_call_is_init(site),
2048fd4dddaSChristophe Leroy "can't patch static call site at %pS",
2058fd4dddaSChristophe Leroy site_addr);
2068fd4dddaSChristophe Leroy continue;
2078fd4dddaSChristophe Leroy }
2088fd4dddaSChristophe Leroy
2098fd4dddaSChristophe Leroy arch_static_call_transform(site_addr, NULL, func,
2108fd4dddaSChristophe Leroy static_call_is_tail(site));
2118fd4dddaSChristophe Leroy }
2128fd4dddaSChristophe Leroy }
2138fd4dddaSChristophe Leroy
2148fd4dddaSChristophe Leroy done:
2158fd4dddaSChristophe Leroy static_call_unlock();
2168fd4dddaSChristophe Leroy cpus_read_unlock();
2178fd4dddaSChristophe Leroy }
2188fd4dddaSChristophe Leroy EXPORT_SYMBOL_GPL(__static_call_update);
2198fd4dddaSChristophe Leroy
__static_call_init(struct module * mod,struct static_call_site * start,struct static_call_site * stop)2208fd4dddaSChristophe Leroy static int __static_call_init(struct module *mod,
2218fd4dddaSChristophe Leroy struct static_call_site *start,
2228fd4dddaSChristophe Leroy struct static_call_site *stop)
2238fd4dddaSChristophe Leroy {
2248fd4dddaSChristophe Leroy struct static_call_site *site;
2258fd4dddaSChristophe Leroy struct static_call_key *key, *prev_key = NULL;
2268fd4dddaSChristophe Leroy struct static_call_mod *site_mod;
2278fd4dddaSChristophe Leroy
2288fd4dddaSChristophe Leroy if (start == stop)
2298fd4dddaSChristophe Leroy return 0;
2308fd4dddaSChristophe Leroy
2318fd4dddaSChristophe Leroy static_call_sort_entries(start, stop);
2328fd4dddaSChristophe Leroy
2338fd4dddaSChristophe Leroy for (site = start; site < stop; site++) {
2348fd4dddaSChristophe Leroy void *site_addr = static_call_addr(site);
2358fd4dddaSChristophe Leroy
2368fd4dddaSChristophe Leroy if ((mod && within_module_init((unsigned long)site_addr, mod)) ||
2378fd4dddaSChristophe Leroy (!mod && init_section_contains(site_addr, 1)))
2388fd4dddaSChristophe Leroy static_call_set_init(site);
2398fd4dddaSChristophe Leroy
2408fd4dddaSChristophe Leroy key = static_call_key(site);
2418fd4dddaSChristophe Leroy if (key != prev_key) {
2428fd4dddaSChristophe Leroy prev_key = key;
2438fd4dddaSChristophe Leroy
2448fd4dddaSChristophe Leroy /*
2458fd4dddaSChristophe Leroy * For vmlinux (!mod) avoid the allocation by storing
2468fd4dddaSChristophe Leroy * the sites pointer in the key itself. Also see
2478fd4dddaSChristophe Leroy * __static_call_update()'s @first.
2488fd4dddaSChristophe Leroy *
2498fd4dddaSChristophe Leroy * This allows architectures (eg. x86) to call
2508fd4dddaSChristophe Leroy * static_call_init() before memory allocation works.
2518fd4dddaSChristophe Leroy */
2528fd4dddaSChristophe Leroy if (!mod) {
2538fd4dddaSChristophe Leroy key->sites = site;
2548fd4dddaSChristophe Leroy key->type |= 1;
2558fd4dddaSChristophe Leroy goto do_transform;
2568fd4dddaSChristophe Leroy }
2578fd4dddaSChristophe Leroy
2588fd4dddaSChristophe Leroy site_mod = kzalloc(sizeof(*site_mod), GFP_KERNEL);
2598fd4dddaSChristophe Leroy if (!site_mod)
2608fd4dddaSChristophe Leroy return -ENOMEM;
2618fd4dddaSChristophe Leroy
2628fd4dddaSChristophe Leroy /*
2638fd4dddaSChristophe Leroy * When the key has a direct sites pointer, extract
2648fd4dddaSChristophe Leroy * that into an explicit struct static_call_mod, so we
2658fd4dddaSChristophe Leroy * can have a list of modules.
2668fd4dddaSChristophe Leroy */
2678fd4dddaSChristophe Leroy if (static_call_key_sites(key)) {
2688fd4dddaSChristophe Leroy site_mod->mod = NULL;
2698fd4dddaSChristophe Leroy site_mod->next = NULL;
2708fd4dddaSChristophe Leroy site_mod->sites = static_call_key_sites(key);
2718fd4dddaSChristophe Leroy
2728fd4dddaSChristophe Leroy key->mods = site_mod;
2738fd4dddaSChristophe Leroy
2748fd4dddaSChristophe Leroy site_mod = kzalloc(sizeof(*site_mod), GFP_KERNEL);
2758fd4dddaSChristophe Leroy if (!site_mod)
2768fd4dddaSChristophe Leroy return -ENOMEM;
2778fd4dddaSChristophe Leroy }
2788fd4dddaSChristophe Leroy
2798fd4dddaSChristophe Leroy site_mod->mod = mod;
2808fd4dddaSChristophe Leroy site_mod->sites = site;
2818fd4dddaSChristophe Leroy site_mod->next = static_call_key_next(key);
2828fd4dddaSChristophe Leroy key->mods = site_mod;
2838fd4dddaSChristophe Leroy }
2848fd4dddaSChristophe Leroy
2858fd4dddaSChristophe Leroy do_transform:
2868fd4dddaSChristophe Leroy arch_static_call_transform(site_addr, NULL, key->func,
2878fd4dddaSChristophe Leroy static_call_is_tail(site));
2888fd4dddaSChristophe Leroy }
2898fd4dddaSChristophe Leroy
2908fd4dddaSChristophe Leroy return 0;
2918fd4dddaSChristophe Leroy }
2928fd4dddaSChristophe Leroy
addr_conflict(struct static_call_site * site,void * start,void * end)2938fd4dddaSChristophe Leroy static int addr_conflict(struct static_call_site *site, void *start, void *end)
2948fd4dddaSChristophe Leroy {
2958fd4dddaSChristophe Leroy unsigned long addr = (unsigned long)static_call_addr(site);
2968fd4dddaSChristophe Leroy
2978fd4dddaSChristophe Leroy if (addr <= (unsigned long)end &&
2988fd4dddaSChristophe Leroy addr + CALL_INSN_SIZE > (unsigned long)start)
2998fd4dddaSChristophe Leroy return 1;
3008fd4dddaSChristophe Leroy
3018fd4dddaSChristophe Leroy return 0;
3028fd4dddaSChristophe Leroy }
3038fd4dddaSChristophe Leroy
__static_call_text_reserved(struct static_call_site * iter_start,struct static_call_site * iter_stop,void * start,void * end,bool init)3048fd4dddaSChristophe Leroy static int __static_call_text_reserved(struct static_call_site *iter_start,
3058fd4dddaSChristophe Leroy struct static_call_site *iter_stop,
3068fd4dddaSChristophe Leroy void *start, void *end, bool init)
3078fd4dddaSChristophe Leroy {
3088fd4dddaSChristophe Leroy struct static_call_site *iter = iter_start;
3098fd4dddaSChristophe Leroy
3108fd4dddaSChristophe Leroy while (iter < iter_stop) {
3118fd4dddaSChristophe Leroy if (init || !static_call_is_init(iter)) {
3128fd4dddaSChristophe Leroy if (addr_conflict(iter, start, end))
3138fd4dddaSChristophe Leroy return 1;
3148fd4dddaSChristophe Leroy }
3158fd4dddaSChristophe Leroy iter++;
3168fd4dddaSChristophe Leroy }
3178fd4dddaSChristophe Leroy
3188fd4dddaSChristophe Leroy return 0;
3198fd4dddaSChristophe Leroy }
3208fd4dddaSChristophe Leroy
3218fd4dddaSChristophe Leroy #ifdef CONFIG_MODULES
3228fd4dddaSChristophe Leroy
__static_call_mod_text_reserved(void * start,void * end)3238fd4dddaSChristophe Leroy static int __static_call_mod_text_reserved(void *start, void *end)
3248fd4dddaSChristophe Leroy {
3258fd4dddaSChristophe Leroy struct module *mod;
3268fd4dddaSChristophe Leroy int ret;
3278fd4dddaSChristophe Leroy
3288fd4dddaSChristophe Leroy preempt_disable();
3298fd4dddaSChristophe Leroy mod = __module_text_address((unsigned long)start);
3308fd4dddaSChristophe Leroy WARN_ON_ONCE(__module_text_address((unsigned long)end) != mod);
3318fd4dddaSChristophe Leroy if (!try_module_get(mod))
3328fd4dddaSChristophe Leroy mod = NULL;
3338fd4dddaSChristophe Leroy preempt_enable();
3348fd4dddaSChristophe Leroy
3358fd4dddaSChristophe Leroy if (!mod)
3368fd4dddaSChristophe Leroy return 0;
3378fd4dddaSChristophe Leroy
3388fd4dddaSChristophe Leroy ret = __static_call_text_reserved(mod->static_call_sites,
3398fd4dddaSChristophe Leroy mod->static_call_sites + mod->num_static_call_sites,
3408fd4dddaSChristophe Leroy start, end, mod->state == MODULE_STATE_COMING);
3418fd4dddaSChristophe Leroy
3428fd4dddaSChristophe Leroy module_put(mod);
3438fd4dddaSChristophe Leroy
3448fd4dddaSChristophe Leroy return ret;
3458fd4dddaSChristophe Leroy }
3468fd4dddaSChristophe Leroy
tramp_key_lookup(unsigned long addr)3478fd4dddaSChristophe Leroy static unsigned long tramp_key_lookup(unsigned long addr)
3488fd4dddaSChristophe Leroy {
3498fd4dddaSChristophe Leroy struct static_call_tramp_key *start = __start_static_call_tramp_key;
3508fd4dddaSChristophe Leroy struct static_call_tramp_key *stop = __stop_static_call_tramp_key;
3518fd4dddaSChristophe Leroy struct static_call_tramp_key *tramp_key;
3528fd4dddaSChristophe Leroy
3538fd4dddaSChristophe Leroy for (tramp_key = start; tramp_key != stop; tramp_key++) {
3548fd4dddaSChristophe Leroy unsigned long tramp;
3558fd4dddaSChristophe Leroy
3568fd4dddaSChristophe Leroy tramp = (long)tramp_key->tramp + (long)&tramp_key->tramp;
3578fd4dddaSChristophe Leroy if (tramp == addr)
3588fd4dddaSChristophe Leroy return (long)tramp_key->key + (long)&tramp_key->key;
3598fd4dddaSChristophe Leroy }
3608fd4dddaSChristophe Leroy
3618fd4dddaSChristophe Leroy return 0;
3628fd4dddaSChristophe Leroy }
3638fd4dddaSChristophe Leroy
static_call_add_module(struct module * mod)3648fd4dddaSChristophe Leroy static int static_call_add_module(struct module *mod)
3658fd4dddaSChristophe Leroy {
3668fd4dddaSChristophe Leroy struct static_call_site *start = mod->static_call_sites;
3678fd4dddaSChristophe Leroy struct static_call_site *stop = start + mod->num_static_call_sites;
3688fd4dddaSChristophe Leroy struct static_call_site *site;
3698fd4dddaSChristophe Leroy
3708fd4dddaSChristophe Leroy for (site = start; site != stop; site++) {
3718fd4dddaSChristophe Leroy unsigned long s_key = __static_call_key(site);
3728fd4dddaSChristophe Leroy unsigned long addr = s_key & ~STATIC_CALL_SITE_FLAGS;
3738fd4dddaSChristophe Leroy unsigned long key;
3748fd4dddaSChristophe Leroy
3758fd4dddaSChristophe Leroy /*
3768fd4dddaSChristophe Leroy * Is the key is exported, 'addr' points to the key, which
3778fd4dddaSChristophe Leroy * means modules are allowed to call static_call_update() on
3788fd4dddaSChristophe Leroy * it.
3798fd4dddaSChristophe Leroy *
3808fd4dddaSChristophe Leroy * Otherwise, the key isn't exported, and 'addr' points to the
3818fd4dddaSChristophe Leroy * trampoline so we need to lookup the key.
3828fd4dddaSChristophe Leroy *
3838fd4dddaSChristophe Leroy * We go through this dance to prevent crazy modules from
3848fd4dddaSChristophe Leroy * abusing sensitive static calls.
3858fd4dddaSChristophe Leroy */
3868fd4dddaSChristophe Leroy if (!kernel_text_address(addr))
3878fd4dddaSChristophe Leroy continue;
3888fd4dddaSChristophe Leroy
3898fd4dddaSChristophe Leroy key = tramp_key_lookup(addr);
3908fd4dddaSChristophe Leroy if (!key) {
3918fd4dddaSChristophe Leroy pr_warn("Failed to fixup __raw_static_call() usage at: %ps\n",
3928fd4dddaSChristophe Leroy static_call_addr(site));
3938fd4dddaSChristophe Leroy return -EINVAL;
3948fd4dddaSChristophe Leroy }
3958fd4dddaSChristophe Leroy
3968fd4dddaSChristophe Leroy key |= s_key & STATIC_CALL_SITE_FLAGS;
3978fd4dddaSChristophe Leroy site->key = key - (long)&site->key;
3988fd4dddaSChristophe Leroy }
3998fd4dddaSChristophe Leroy
4008fd4dddaSChristophe Leroy return __static_call_init(mod, start, stop);
4018fd4dddaSChristophe Leroy }
4028fd4dddaSChristophe Leroy
static_call_del_module(struct module * mod)4038fd4dddaSChristophe Leroy static void static_call_del_module(struct module *mod)
4048fd4dddaSChristophe Leroy {
4058fd4dddaSChristophe Leroy struct static_call_site *start = mod->static_call_sites;
4068fd4dddaSChristophe Leroy struct static_call_site *stop = mod->static_call_sites +
4078fd4dddaSChristophe Leroy mod->num_static_call_sites;
4088fd4dddaSChristophe Leroy struct static_call_key *key, *prev_key = NULL;
4098fd4dddaSChristophe Leroy struct static_call_mod *site_mod, **prev;
4108fd4dddaSChristophe Leroy struct static_call_site *site;
4118fd4dddaSChristophe Leroy
4128fd4dddaSChristophe Leroy for (site = start; site < stop; site++) {
4138fd4dddaSChristophe Leroy key = static_call_key(site);
414c0abbbe8SThomas Gleixner
415c0abbbe8SThomas Gleixner /*
416c0abbbe8SThomas Gleixner * If the key was not updated due to a memory allocation
417c0abbbe8SThomas Gleixner * failure in __static_call_init() then treating key::sites
418c0abbbe8SThomas Gleixner * as key::mods in the code below would cause random memory
419c0abbbe8SThomas Gleixner * access and #GP. In that case all subsequent sites have
420c0abbbe8SThomas Gleixner * not been touched either, so stop iterating.
421c0abbbe8SThomas Gleixner */
422c0abbbe8SThomas Gleixner if (!static_call_key_has_mods(key))
423c0abbbe8SThomas Gleixner break;
424c0abbbe8SThomas Gleixner
4258fd4dddaSChristophe Leroy if (key == prev_key)
4268fd4dddaSChristophe Leroy continue;
4278fd4dddaSChristophe Leroy
4288fd4dddaSChristophe Leroy prev_key = key;
4298fd4dddaSChristophe Leroy
4308fd4dddaSChristophe Leroy for (prev = &key->mods, site_mod = key->mods;
4318fd4dddaSChristophe Leroy site_mod && site_mod->mod != mod;
4328fd4dddaSChristophe Leroy prev = &site_mod->next, site_mod = site_mod->next)
4338fd4dddaSChristophe Leroy ;
4348fd4dddaSChristophe Leroy
4358fd4dddaSChristophe Leroy if (!site_mod)
4368fd4dddaSChristophe Leroy continue;
4378fd4dddaSChristophe Leroy
4388fd4dddaSChristophe Leroy *prev = site_mod->next;
4398fd4dddaSChristophe Leroy kfree(site_mod);
4408fd4dddaSChristophe Leroy }
4418fd4dddaSChristophe Leroy }
4428fd4dddaSChristophe Leroy
static_call_module_notify(struct notifier_block * nb,unsigned long val,void * data)4438fd4dddaSChristophe Leroy static int static_call_module_notify(struct notifier_block *nb,
4448fd4dddaSChristophe Leroy unsigned long val, void *data)
4458fd4dddaSChristophe Leroy {
4468fd4dddaSChristophe Leroy struct module *mod = data;
4478fd4dddaSChristophe Leroy int ret = 0;
4488fd4dddaSChristophe Leroy
4498fd4dddaSChristophe Leroy cpus_read_lock();
4508fd4dddaSChristophe Leroy static_call_lock();
4518fd4dddaSChristophe Leroy
4528fd4dddaSChristophe Leroy switch (val) {
4538fd4dddaSChristophe Leroy case MODULE_STATE_COMING:
4548fd4dddaSChristophe Leroy ret = static_call_add_module(mod);
4558fd4dddaSChristophe Leroy if (ret) {
456e67534bdSThomas Gleixner pr_warn("Failed to allocate memory for static calls\n");
4578fd4dddaSChristophe Leroy static_call_del_module(mod);
4588fd4dddaSChristophe Leroy }
4598fd4dddaSChristophe Leroy break;
4608fd4dddaSChristophe Leroy case MODULE_STATE_GOING:
4618fd4dddaSChristophe Leroy static_call_del_module(mod);
4628fd4dddaSChristophe Leroy break;
4638fd4dddaSChristophe Leroy }
4648fd4dddaSChristophe Leroy
4658fd4dddaSChristophe Leroy static_call_unlock();
4668fd4dddaSChristophe Leroy cpus_read_unlock();
4678fd4dddaSChristophe Leroy
4688fd4dddaSChristophe Leroy return notifier_from_errno(ret);
4698fd4dddaSChristophe Leroy }
4708fd4dddaSChristophe Leroy
4718fd4dddaSChristophe Leroy static struct notifier_block static_call_module_nb = {
4728fd4dddaSChristophe Leroy .notifier_call = static_call_module_notify,
4738fd4dddaSChristophe Leroy };
4748fd4dddaSChristophe Leroy
4758fd4dddaSChristophe Leroy #else
4768fd4dddaSChristophe Leroy
__static_call_mod_text_reserved(void * start,void * end)4778fd4dddaSChristophe Leroy static inline int __static_call_mod_text_reserved(void *start, void *end)
4788fd4dddaSChristophe Leroy {
4798fd4dddaSChristophe Leroy return 0;
4808fd4dddaSChristophe Leroy }
4818fd4dddaSChristophe Leroy
4828fd4dddaSChristophe Leroy #endif /* CONFIG_MODULES */
4838fd4dddaSChristophe Leroy
static_call_text_reserved(void * start,void * end)4848fd4dddaSChristophe Leroy int static_call_text_reserved(void *start, void *end)
4858fd4dddaSChristophe Leroy {
4868fd4dddaSChristophe Leroy bool init = system_state < SYSTEM_RUNNING;
4878fd4dddaSChristophe Leroy int ret = __static_call_text_reserved(__start_static_call_sites,
4888fd4dddaSChristophe Leroy __stop_static_call_sites, start, end, init);
4898fd4dddaSChristophe Leroy
4908fd4dddaSChristophe Leroy if (ret)
4918fd4dddaSChristophe Leroy return ret;
4928fd4dddaSChristophe Leroy
4938fd4dddaSChristophe Leroy return __static_call_mod_text_reserved(start, end);
4948fd4dddaSChristophe Leroy }
4958fd4dddaSChristophe Leroy
static_call_init(void)4968fd4dddaSChristophe Leroy int __init static_call_init(void)
4978fd4dddaSChristophe Leroy {
4988fd4dddaSChristophe Leroy int ret;
4998fd4dddaSChristophe Leroy
5007825451fSPeter Zijlstra /* See static_call_force_reinit(). */
5017825451fSPeter Zijlstra if (static_call_initialized == 1)
5028fd4dddaSChristophe Leroy return 0;
5038fd4dddaSChristophe Leroy
5048fd4dddaSChristophe Leroy cpus_read_lock();
5058fd4dddaSChristophe Leroy static_call_lock();
5068fd4dddaSChristophe Leroy ret = __static_call_init(NULL, __start_static_call_sites,
5078fd4dddaSChristophe Leroy __stop_static_call_sites);
5088fd4dddaSChristophe Leroy static_call_unlock();
5098fd4dddaSChristophe Leroy cpus_read_unlock();
5108fd4dddaSChristophe Leroy
5118fd4dddaSChristophe Leroy if (ret) {
5128fd4dddaSChristophe Leroy pr_err("Failed to allocate memory for static_call!\n");
5138fd4dddaSChristophe Leroy BUG();
5148fd4dddaSChristophe Leroy }
5158fd4dddaSChristophe Leroy
5168fd4dddaSChristophe Leroy #ifdef CONFIG_MODULES
5177825451fSPeter Zijlstra if (!static_call_initialized)
5188fd4dddaSChristophe Leroy register_module_notifier(&static_call_module_nb);
5198fd4dddaSChristophe Leroy #endif
5207825451fSPeter Zijlstra
5217825451fSPeter Zijlstra static_call_initialized = 1;
5228fd4dddaSChristophe Leroy return 0;
5238fd4dddaSChristophe Leroy }
5248fd4dddaSChristophe Leroy early_initcall(static_call_init);
5258fd4dddaSChristophe Leroy
5268fd4dddaSChristophe Leroy #ifdef CONFIG_STATIC_CALL_SELFTEST
5278fd4dddaSChristophe Leroy
func_a(int x)5288fd4dddaSChristophe Leroy static int func_a(int x)
5298fd4dddaSChristophe Leroy {
5308fd4dddaSChristophe Leroy return x+1;
5318fd4dddaSChristophe Leroy }
5328fd4dddaSChristophe Leroy
func_b(int x)5338fd4dddaSChristophe Leroy static int func_b(int x)
5348fd4dddaSChristophe Leroy {
5358fd4dddaSChristophe Leroy return x+2;
5368fd4dddaSChristophe Leroy }
5378fd4dddaSChristophe Leroy
5388fd4dddaSChristophe Leroy DEFINE_STATIC_CALL(sc_selftest, func_a);
5398fd4dddaSChristophe Leroy
5408fd4dddaSChristophe Leroy static struct static_call_data {
5418fd4dddaSChristophe Leroy int (*func)(int);
5428fd4dddaSChristophe Leroy int val;
5438fd4dddaSChristophe Leroy int expect;
5448fd4dddaSChristophe Leroy } static_call_data [] __initdata = {
5458fd4dddaSChristophe Leroy { NULL, 2, 3 },
5468fd4dddaSChristophe Leroy { func_b, 2, 4 },
5478fd4dddaSChristophe Leroy { func_a, 2, 3 }
5488fd4dddaSChristophe Leroy };
5498fd4dddaSChristophe Leroy
test_static_call_init(void)5508fd4dddaSChristophe Leroy static int __init test_static_call_init(void)
5518fd4dddaSChristophe Leroy {
5528fd4dddaSChristophe Leroy int i;
5538fd4dddaSChristophe Leroy
5548fd4dddaSChristophe Leroy for (i = 0; i < ARRAY_SIZE(static_call_data); i++ ) {
5558fd4dddaSChristophe Leroy struct static_call_data *scd = &static_call_data[i];
5568fd4dddaSChristophe Leroy
5578fd4dddaSChristophe Leroy if (scd->func)
5588fd4dddaSChristophe Leroy static_call_update(sc_selftest, scd->func);
5598fd4dddaSChristophe Leroy
5608fd4dddaSChristophe Leroy WARN_ON(static_call(sc_selftest)(scd->val) != scd->expect);
5618fd4dddaSChristophe Leroy }
5628fd4dddaSChristophe Leroy
5638fd4dddaSChristophe Leroy return 0;
5648fd4dddaSChristophe Leroy }
5658fd4dddaSChristophe Leroy early_initcall(test_static_call_init);
5668fd4dddaSChristophe Leroy
5678fd4dddaSChristophe Leroy #endif /* CONFIG_STATIC_CALL_SELFTEST */
568