aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTravis Geiselbrecht <geist@foobox.com>2013-08-02 13:00:11 -0700
committerTravis Geiselbrecht <geist@foobox.com>2013-08-03 15:35:16 -0700
commita40b543556999b3a12250c2149ea657a679fbac6 (patch)
treec75c3748aa09d140c5869cbf7785d82f82c57742
parentc818726b7707ff834b5fe14b3071e5da1c2042bd (diff)
downloadlk-a40b543556999b3a12250c2149ea657a679fbac6.tar.gz
[init] new init hook system
Allows code anywhere in the system to define an init hook which is called at the run level specified. Hooks are guaranteed to be called in order of init level. Within an init level the order of the hooks is not guaranteed.
-rw-r--r--arch/shared_rodata_sections.ld3
-rw-r--r--include/lk/init.h44
-rw-r--r--top/init.c129
-rw-r--r--top/main.c33
-rw-r--r--top/rules.mk1
5 files changed, 191 insertions, 19 deletions
diff --git a/arch/shared_rodata_sections.ld b/arch/shared_rodata_sections.ld
index 2146fb20..3cca8c4a 100644
--- a/arch/shared_rodata_sections.ld
+++ b/arch/shared_rodata_sections.ld
@@ -1,5 +1,8 @@
/* should be included in all lk linker scripts in the .rodata segment */
. = ALIGN(4);
+__lk_init = .;
+KEEP(*(.lk_init))
+__lk_init_end = .;
__drivers = .;
KEEP(*(.drivers))
__drivers_end = .;
diff --git a/include/lk/init.h b/include/lk/init.h
new file mode 100644
index 00000000..b5c8b5ec
--- /dev/null
+++ b/include/lk/init.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include <compiler.h>
+#include <sys/types.h>
+
+/*
+ * LK's init system
+ */
+
+int lk_init_level(uint level);
+
+typedef void (*lk_init_hook)(uint level);
+
+enum lk_init_level {
+ LK_INIT_LEVEL_EARLIEST = 1,
+
+ LK_INIT_LEVEL_ARCH_EARLY = 0x10000,
+ LK_INIT_LEVEL_PLATFORM_EARLY = 0x20000,
+ LK_INIT_LEVEL_TARGET_EARLY = 0x30000,
+ LK_INIT_LEVEL_HEAP = 0x40000,
+ LK_INIT_LEVEL_KERNEL = 0x50000,
+ LK_INIT_LEVEL_THREADING = 0x60000,
+ LK_INIT_LEVEL_ARCH = 0x70000,
+ LK_INIT_LEVEL_PLATFORM = 0x80000,
+ LK_INIT_LEVEL_TARGET = 0x90000,
+ LK_INIT_LEVEL_APPS = 0xa0000,
+
+ LK_INIT_LEVEL_LAST = UINT_MAX,
+};
+
+struct lk_init_struct {
+ uint level;
+ lk_init_hook hook;
+ const char *name;
+};
+
+#define LK_INIT_HOOK(_name, _hook, _level) \
+ const struct lk_init_struct _init_struct_##_name __SECTION(".lk_init") = { \
+ .level = _level, \
+ .hook = _hook, \
+ .name = #_name, \
+ };
+
+// vim: set ts=4 sw=4 expandtab:
diff --git a/top/init.c b/top/init.c
new file mode 100644
index 00000000..949a80dd
--- /dev/null
+++ b/top/init.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2013 Travis Geiselbrecht
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * Global init hook mechanism. Allows code anywhere in the system to define
+ * a init hook that is called at increasing init levels as the system is
+ * initialized.
+ */
+#include <lk/init.h>
+
+#include <compiler.h>
+#include <debug.h>
+
+#define LOCAL_TRACE 0
+#define TRACE_INIT 0
+
+extern const struct lk_init_struct __lk_init[];
+extern const struct lk_init_struct __lk_init_end[];
+
+static uint last_init_level = 0;
+
+int lk_init_level(uint level)
+{
+ LTRACEF("level %#x, last_init_level %#x\n", level, last_init_level);
+
+ uint last_called_level = last_init_level;
+ const struct lk_init_struct *last = NULL;
+ for (;;) {
+ /* search for the lowest uncalled hook to call */
+ LTRACEF("last %p, last_called_level %#x\n", last, last_called_level);
+
+ const struct lk_init_struct *found = NULL;
+ bool seen_last = false;
+ for (const struct lk_init_struct *ptr = __lk_init; ptr != __lk_init_end; ptr++) {
+ LTRACEF("looking at %p (%s) level %#x, seen_last %d\n", ptr, ptr->name, ptr->level, seen_last);
+
+ if (ptr == last)
+ seen_last = true;
+
+ /* reject the easy ones */
+ if (ptr->level > level)
+ continue;
+ if (ptr->level < last_called_level)
+ continue;
+ if (found && found->level <= ptr->level)
+ continue;
+
+ /* keep the lowest one we haven't called yet */
+ if (ptr->level > last_init_level && ptr->level > last_called_level) {
+ found = ptr;
+ continue;
+ }
+
+ /* if we're at the same level as the last one we called and we've
+ * already passed over it this time around, we can mark this one
+ * and early terminate the loop.
+ */
+ if (ptr->level == last_called_level && ptr != last && seen_last) {
+ found = ptr;
+ break;
+ }
+ }
+
+ if (!found)
+ break;
+
+#if TRACE_INIT
+ printf("INIT: calling hook %p (%s) at level %#x\n", found->hook, found->name, found->level);
+#endif
+ found->hook(found->level);
+ last_called_level = found->level;
+ last = found;
+ }
+
+ last_init_level = level;
+
+ return 0;
+}
+
+#if 0
+void test_hook(uint level)
+{
+ LTRACEF("level %#x\n", level);
+}
+void test_hook1(uint level)
+{
+ LTRACEF("level %#x\n", level);
+}
+void test_hook1a(uint level)
+{
+ LTRACEF("level %#x\n", level);
+}
+void test_hook1b(uint level)
+{
+ LTRACEF("level %#x\n", level);
+}
+void test_hook2(uint level)
+{
+ LTRACEF("level %#x\n", level);
+}
+
+LK_INIT_HOOK(test, test_hook, 1);
+LK_INIT_HOOK(test1, test_hook1, 1);
+LK_INIT_HOOK(test2, test_hook2, 2);
+LK_INIT_HOOK(test1a, test_hook1a, 1);
+LK_INIT_HOOK(test1b, test_hook1b, 1);
+#endif
+
+// vim: set ts=4 sw=4 expandtab:
diff --git a/top/main.c b/top/main.c
index 7fcd060a..3ecb2470 100644
--- a/top/main.c
+++ b/top/main.c
@@ -33,10 +33,8 @@
#include <platform.h>
#include <target.h>
#include <lib/heap.h>
-#include <lib/dpc.h>
-#include <lib/fs.h>
-#include <lib/bio.h>
#include <kernel/thread.h>
+#include <lk/init.h>
extern void *__ctor_list;
extern void *__ctor_end;
@@ -72,12 +70,15 @@ void lk_main(void)
thread_init_early();
// early arch stuff
+ lk_init_level(LK_INIT_LEVEL_ARCH_EARLY - 1);
arch_early_init();
// do any super early platform initialization
+ lk_init_level(LK_INIT_LEVEL_PLATFORM_EARLY - 1);
platform_early_init();
// do any super early target initialization
+ lk_init_level(LK_INIT_LEVEL_TARGET_EARLY - 1);
target_early_init();
dprintf(INFO, "welcome to lk\n\n");
@@ -88,11 +89,15 @@ void lk_main(void)
// bring up the kernel heap
dprintf(SPEW, "initializing heap\n");
+ lk_init_level(LK_INIT_LEVEL_HEAP - 1);
heap_init();
// initialize the kernel
+ lk_init_level(LK_INIT_LEVEL_KERNEL - 1);
kernel_init();
+ lk_init_level(LK_INIT_LEVEL_THREADING - 1);
+
// create a thread to complete system initialization
dprintf(SPEW, "creating bootstrap completion thread\n");
thread_t *t = thread_create("bootstrap2", &bootstrap2, NULL, DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
@@ -103,39 +108,29 @@ void lk_main(void)
thread_become_idle();
}
-int main(void);
-
static int bootstrap2(void *arg)
{
dprintf(SPEW, "top of bootstrap2()\n");
+ lk_init_level(LK_INIT_LEVEL_ARCH - 1);
arch_init();
- // initialize the dpc system
-#if WITH_LIB_DPC
- dpc_init();
-#endif
-
- // XXX put this somewhere else
-#if WITH_LIB_BIO
- bio_init();
-#endif
-#if WITH_LIB_FS
- fs_init();
-#endif
-
// initialize the rest of the platform
dprintf(SPEW, "initializing platform\n");
+ lk_init_level(LK_INIT_LEVEL_PLATFORM - 1);
platform_init();
// initialize the target
dprintf(SPEW, "initializing target\n");
+ lk_init_level(LK_INIT_LEVEL_TARGET - 1);
target_init();
dprintf(SPEW, "calling apps_init()\n");
+ lk_init_level(LK_INIT_LEVEL_APPS - 1);
apps_init();
+ lk_init_level(LK_INIT_LEVEL_LAST);
+
return 0;
}
-
diff --git a/top/rules.mk b/top/rules.mk
index 697c4324..c3f8782c 100644
--- a/top/rules.mk
+++ b/top/rules.mk
@@ -10,6 +10,7 @@ MODULE_DEPS := \
kernel
MODULE_SRCS := \
+ $(LOCAL_DIR)/init.c \
$(LOCAL_DIR)/main.c \
include make/module.mk