diff options
author | Luis R. Rodriguez <mcgrof@kernel.org> | 2016-06-28 11:19:52 -0700 |
---|---|---|
committer | Luis R. Rodriguez <mcgrof@kernel.org> | 2016-06-29 17:29:05 -0700 |
commit | 923a4eb88b45bc947812a394d3acb92dd4f4bbf3 (patch) | |
tree | 4700cb2a70cbba307c29cd9c52c5e45abd93c0d2 | |
parent | 3adf023d2a05a89f4851bd49fd6a3be78bb7f77f (diff) | |
download | linker-tables-923a4eb88b45bc947812a394d3acb92dd4f4bbf3.tar.gz |
synth: add partially static shift right demo
This demos the use of "partially static" variables, they like
consts, however we modify them early in boot time and provide
functions that do the handy work for us. The handy work of
processing them is accomplished through kernel's alternatives.
To this end we add an example simple alternatives processing
mechanism, its architecture is rather simple given it simply relies
on the linker table with structural data, and updates it as needed.
We demo a partially static function which shifts a variable to
the right by certain amount of times, the amount of times we
shift is determined through a function passed early in boot,
and as such can be dynamic.
Without alternatives processed you'd get:
Synthetics: ps_shr(0XDEADBEEF) returns: 0xDEADBEEF
After alternatives is processed you get:
Synthetics: ps_shr(0XDEADBEEF) returns: 0x0000DEAD
Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/alternative.c | 31 | ||||
-rw-r--r-- | drivers/synth/main.c | 13 | ||||
-rw-r--r-- | include/linux/ps_const.h | 42 |
4 files changed, 87 insertions, 0 deletions
@@ -42,6 +42,7 @@ OBJS = \ arch/x86/kernel/head64.c \ kasan.o\ memory.o \ + arch/x86/kernel/alternative.o \ arch/x86/kernel/init.o \ kernel/locking/mutex.o \ kernel/locking/spinlock.o \ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c new file mode 100644 index 0000000..ed80a82 --- /dev/null +++ b/arch/x86/kernel/alternative.c @@ -0,0 +1,31 @@ +#include <asm/x86_init_fn.h> + +#include <linux/kernel.h> +#include <linux/ps_const.h> + +void apply_alternatives_linker_tables(void) +{ + unsigned int num_consts = LINUX_SECTION_SIZE(ps_set_const_table); + struct ps_set_const *ps_const; + + if (!num_consts) + return; + + pr_debug("Number of init entries: %d\n", num_consts); + + LINKTABLE_FOR_EACH(ps_const, ps_set_const_table) { + switch(ps_const->type) { + case SET_CONST_U8: + *ps_const->count = (__u8) ps_const->func(); + break; + case SET_CONST_U16: + *ps_const->count = (__u16) ps_const->func(); + break; + case SET_CONST_U32: + *ps_const->count = (__u16) ps_const->func(); + break; + } + } +} + +x86_init_early_pc(apply_alternatives_linker_tables); diff --git a/drivers/synth/main.c b/drivers/synth/main.c index 4899e67..e776f6f 100644 --- a/drivers/synth/main.c +++ b/drivers/synth/main.c @@ -2,17 +2,30 @@ #include <linux/module.h> #include <linux/kernel.h> +#include <linux/ps_const.h> + #include "common.h" #include "synth.h" +DEFINE_LINKTABLE_INIT_DATA(struct ps_set_const, ps_set_const_table); + +unsigned int get_demo_shr(void) +{ + return 16; +} + static int synth_init(void) { int synth_or; int val = 2; + unsigned int reg; synth_or = synth_init_or(val); pr_info("synth_init_or(%d) returns: 0x%08X\n", val, synth_or); + reg = ps_shr(0xDEADBEEF, get_demo_shr); + pr_info("ps_shr(0x%08X, get_demo_shr) returns: 0x%08X\n", 0xDEADBEEF, reg); + return 0; } module_init(synth_init); diff --git a/include/linux/ps_const.h b/include/linux/ps_const.h new file mode 100644 index 0000000..1747421 --- /dev/null +++ b/include/linux/ps_const.h @@ -0,0 +1,42 @@ +#ifndef __PS_CONST +#define __PS_CONST + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/tables.h> + +/* Helpers for partially static settings */ + +enum ps_static_type { + SET_CONST_U8 = 0, + SET_CONST_U16, + SET_CONST_U32, +}; + +struct ps_set_const { + unsigned int *count; + enum ps_static_type type; + unsigned int (*func)(void); +}; + +DECLARE_LINKTABLE(struct ps_set_const, ps_set_const_table); + +/* + * ps_ stands for "partially static", so we "partialloy static shift right" + * You can optimize this for your architecture. + * + * ps_shr(unsigned int in, unsigned char (*func)(void)) + */ +#ifndef ps_shr +#define ps_shr(_in, _func) \ +({ \ + static unsigned int _count; \ + static LINKTABLE_INIT_DATA(ps_set_const_table, 01) \ + __ps_shr##__func = \ + { &_count, SET_CONST_U8, (_func) }; \ + \ + (_in) >> _count; \ +}) +#endif /* ps_shr */ + +#endif /* __PS_CONST */ |