aboutsummaryrefslogtreecommitdiff
path: root/kernel/util/init.c
blob: d1bc0d8ca6e004a40358d6196577b94d4f366abd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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);
    }
}