lx_emul: generate initcalls during build

Functions registered with 'module_init' (i.e., '__define_initcalls'),
'OF_DECLARE', and 'DECLARE_PCI_FIXUP_CLASS_FINAL' used to be static
constructors and had be explicitly registered using
'exec_static_constructors' before executing any Linux code.

With this commit we remove the constructor attributes from these
functions and create a global function pointer in the form of

__initptr_<name>_<id>_<counter>_<line number of macro>

'import-lx_emul_common.inc' will collect these '__initptr' symbols after
the compile step and generate a 'lx_emul_register_initcalls' function
that executes the functions pointed to. This step is now automatically
performed in 'lx_emul_start_kernel'. This way a call to
'exec_static_constructors' can be omitted in case there are no other
constructors in place.

issue #5096
This commit is contained in:
Sebastian Sumpf 2024-01-10 20:43:07 +01:00 committed by Christian Helmuth
parent f9bff3bc7c
commit 1b4f7ae0d3
7 changed files with 92 additions and 17 deletions

View File

@ -211,3 +211,57 @@ GLOBAL_DEPS += $(wildcard $(addsuffix /linux/*.h,$(SHADOW_INC_DIR))) \
GLOBAL_DEPS += $(wildcard $(addsuffix /linux/*.h,$(SPEC_SHADOW_INC_DIR))) \
$(wildcard $(addsuffix /asm/*.h,$(SPEC_SHADOW_INC_DIR)))
#
# Generate initcall_table.c and create 'lx_emul_register_initcalls' which calls
# global '__initptr_*' functions created by 'module_init'
#
define print_file_header
echo "/*" > $(2);
echo " * \\brief Register initcalls from __initptr_*" >> $(2);
echo " * \\author Automatically generated file - do no edit" >> $(2);
echo " * \\date $(1)" >> $(2);
echo " */" >> $(2);
echo "" >> $(2);
echo "" >> $(2);
endef
define print_declaration
echo "extern void * $(1);" >> $(2);
endef
define print_function_start
echo "" >> $(1)
echo "void lx_emul_register_initcalls(void)" >> $(1);
echo "{" >> $(1);
echo " typedef void (*func)(void);" >> $(1);
endef
define print_call
echo " ((func)$(1))();" >> $(2);
endef
define print_function_end
echo "}" >> $(1);
endef
# 'module_init' calls should only be in C-sources
WAIT_FOR_OBJECTS = $(addsuffix .o,$(basename $(filter-out initcall_table.c,$(SRC_C))))
# retrieve 'initptr_*' using nm from object files
INITCALLS = $(sort $(shell $(NM) -U $(WAIT_FOR_OBJECTS) |\
grep "__initptr" |\
awk '{print $$3}'))
SRC_C += initcall_table.c
initcall_table.c: $(WAIT_FOR_OBJECTS)
$(MSG_CONFIG)$@
@$(call print_file_header,$(shell date +"%F"),$@)
@$(foreach sym,$(INITCALLS),$(call print_declaration,$(sym),$@))
@$(call print_function_start,$@)
@$(foreach sym,$(INITCALLS),$(call print_call,$(sym),$@))
@$(call print_function_end,$@)

View File

@ -20,6 +20,9 @@ extern "C" {
void lx_emul_initcalls(void);
/* this function is generated into 'initcall_table.c' */
void lx_emul_register_initcalls(void);
void lx_emul_register_initcall(int (*initcall)(void), const char * name);
void lx_emul_start_kernel(void * dtb);

View File

@ -27,9 +27,16 @@
#undef ___define_initcall
#undef __define_initcall
#define __define_initcall(fn, id) \
static void __initcall_##fn##id(void)__attribute__((constructor)); \
static void __initcall_##fn##id() { \
lx_emul_register_initcall(fn, __func__); };
/*
* Define local register function and global pointer to function in the form
* '__initptr_<function name>_<id>_<counter>_<line number of macro>'
*/
#define __define_initcall(fn, id) \
static void __initcall_##fn##id(void) { \
lx_emul_register_initcall(fn, __func__); } \
\
void * __PASTE(__initptr_##fn##id##_, \
__PASTE(__COUNTER__, \
__PASTE(_,__LINE__))) = __initcall_##fn##id;
#endif /* _LX_EMUL__SHADOW__LINUX__INIT_H_ */

View File

@ -21,15 +21,19 @@
#undef OF_DECLARE_2
/* used to populate __clk_of_table */
#define OF_DECLARE_1(table, name, compat, fn) \
static void __of_declare_initcall_##name(void) __attribute__((constructor)); \
static void __of_declare_initcall_##name() { \
lx_emul_register_of_##table##_initcall(compat, fn); };
#define OF_DECLARE_1(table, name, compat, fn) \
static void __of_declare_initcall_##name(void) { \
lx_emul_register_of_##table##_initcall(compat, fn); }; \
void * __PASTE(__initptr_of_declare_initcall_##name##_, \
__PASTE(__COUNTER__, \
__PASTE(_, __LINE__))) = __of_declare_initcall_##name;
/* used to populate __irqchip_of_table */
#define OF_DECLARE_2(table, name, compat, fn) \
static void __of_declare_initcall_##name(void) __attribute__((constructor)); \
static void __of_declare_initcall_##name() { \
lx_emul_register_of_##table##_initcall(compat, fn); };
#define OF_DECLARE_2(table, name, compat, fn) \
static void __of_declare_initcall_##name(void) { \
lx_emul_register_of_##table##_initcall(compat, fn); }; \
void * __PASTE(__initptr_of_declare_initcall_##name##_, \
__PASTE(__COUNTER__, \
__PASTE(_, __LINE__))) = __of_declare_initcall_##name;
#endif /* _LX_EMUL__SHADOW__LINUX__OF_H_ */

View File

@ -14,9 +14,13 @@
#undef DECLARE_PCI_FIXUP_CLASS_FINAL
#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class, \
class_shift, hook) \
static void __pci_fixup_final_##hook(struct pci_dev *dev) __attribute__((constructor)); \
static void __pci_fixup_final_##hook(struct pci_dev *dev) { \
lx_emul_register_pci_fixup(hook, __func__); };
class_shift, hook) \
static void __pci_fixup_final_##hook(struct pci_dev *dev) { \
lx_emul_register_pci_fixup(hook, __func__); }; \
void * __PASTE(__initptr_pci_fixup_final_##hook##_, \
__PASTE(__COUNTER__, \
__PASTE(_, __LINE__))) = __pci_fixup_final_##hook;
#endif /* _LINUX__PCI_H_ */

View File

@ -52,6 +52,9 @@ extern "C" void lx_emul_start_kernel(void * dtb)
{
using namespace Lx_kit;
/* register 'module_init' calls and friends */
lx_emul_register_initcalls();
new (env().heap) Task(lx_emul_init_task_function, dtb,
lx_emul_init_task_struct, SWAPPER_PID, "swapper",
env().scheduler, Task::TIME_HANDLER);

View File

@ -44,7 +44,7 @@ SRC_C += lx_emul/shadow/drivers/pci/search.c
SRC_C += lx_emul/shadow/drivers/pci/setup-irq.c
SRC_C += lx_emul/shadow/drivers/pci/setup-res.c
SRC_CC += lx_emul/pci.cc
SRC_CC += lx_emul/pci_bus.c
SRC_C += lx_emul/pci_bus.c
SRC_CC += lx_kit/device.cc
SRC_CC += lx_kit/memory_dma.cc