aboutsummaryrefslogtreecommitdiff
path: root/kernel/util/init.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/util/init.c')
-rw-r--r--kernel/util/init.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/kernel/util/init.c b/kernel/util/init.c
new file mode 100644
index 0000000..d1bc0d8
--- /dev/null
+++ b/kernel/util/init.c
@@ -0,0 +1,142 @@
+#include "kernel.h"
+
+#include "mm/kmalloc.h"
+
+#include "util/debug.h"
+#include "util/init.h"
+#include "util/list.h"
+#include "util/string.h"
+
+static int _init_search_count = 0;
+
+struct init_function
+{
+ init_func_t if_func;
+ const char *if_name;
+ list_link_t if_link;
+
+ int if_search;
+ int if_called;
+ list_t if_deps;
+};
+
+struct init_depends
+{
+ const char *id_name;
+ list_link_t id_link;
+};
+
+static void _init_call(list_t *funcs, struct init_function *func)
+{
+ list_iterate(&func->if_deps, dep, struct init_depends, id_link)
+ {
+ struct init_function *found = NULL;
+ list_iterate(funcs, f, struct init_function, if_link)
+ {
+ if (strcmp(dep->id_name, f->if_name) == 0)
+ {
+ found = f;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ panic("'%s' dependency for '%s' does not exist", dep->id_name,
+ func->if_name);
+ }
+
+ if (func->if_search == found->if_search)
+ {
+ panic("circular dependency between '%s' and '%s'", func->if_name,
+ found->if_name);
+ }
+
+ dbg(DBG_INIT, "'%s' depends on '%s': ", func->if_name, found->if_name);
+ if (!found->if_called)
+ {
+ dbgq(DBG_INIT, "calling\n");
+ found->if_search = func->if_search;
+ _init_call(funcs, found);
+ }
+ else
+ {
+ dbgq(DBG_INIT, "already called\n");
+ }
+ }
+
+ KASSERT(!func->if_called);
+
+ dbg(DBG_INIT, "Calling %s (0x%p)\n", func->if_name, func->if_func);
+ func->if_func();
+ func->if_called = 1;
+}
+
+void init_call_all()
+{
+ list_t funcs;
+ char *buf, *end;
+
+ list_init(&funcs);
+ buf = (char *)&kernel_start_init;
+ end = (char *)&kernel_end_init;
+
+ while (buf < end)
+ {
+ struct init_function *curr = kmalloc(sizeof(*curr));
+ KASSERT(NULL != curr);
+
+ list_insert_tail(&funcs, &curr->if_link);
+ list_init(&curr->if_deps);
+
+ KASSERT(NULL != *(uintptr_t *)buf);
+ curr->if_func = (init_func_t) * (uintptr_t *)buf;
+ curr->if_name = buf + sizeof(curr->if_func);
+ curr->if_search = 0;
+ curr->if_called = 0;
+
+ buf += sizeof(curr->if_func) + strlen(curr->if_name) + 1;
+
+ while ((NULL == *(uintptr_t *)buf) && (buf < end))
+ {
+ struct init_depends *dep = kmalloc(sizeof(*dep));
+ KASSERT(NULL != dep);
+
+ list_insert_tail(&curr->if_deps, &dep->id_link);
+
+ dep->id_name = buf + sizeof(curr->if_func);
+ buf += sizeof(curr->if_func) + strlen(dep->id_name) + 1;
+ }
+ }
+
+ KASSERT(buf == end);
+
+ dbg(DBG_INIT, "Initialization functions and dependencies:\n");
+ list_iterate(&funcs, func, struct init_function, if_link)
+ {
+ dbgq(DBG_INIT, "%s (0x%p): ", func->if_name, func->if_func);
+ list_iterate(&func->if_deps, dep, struct init_depends, id_link)
+ {
+ dbgq(DBG_INIT, "%s ", dep->id_name);
+ }
+ dbgq(DBG_INIT, "\n");
+ }
+
+ list_iterate(&funcs, func, struct init_function, if_link)
+ {
+ if (!func->if_called)
+ {
+ func->if_search = ++_init_search_count;
+ _init_call(&funcs, func);
+ }
+ }
+
+ list_iterate(&funcs, func, struct init_function, if_link)
+ {
+ list_iterate(&func->if_deps, dep, struct init_depends, id_link)
+ {
+ kfree(dep);
+ }
+ kfree(func);
+ }
+}