1 /*
2  * Copyright (c) 2013-2015 Travis Geiselbrecht
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #pragma once
24 
25 #include <compiler.h>
26 #include <sys/types.h>
27 
28 /*
29  * LK's init system
30  */
31 
32 typedef void (*lk_init_hook)(uint level);
33 
34 enum lk_init_level {
35     LK_INIT_LEVEL_EARLIEST = 1,
36 
37     LK_INIT_LEVEL_ARCH_EARLY     = 0x10000,
38     LK_INIT_LEVEL_PLATFORM_EARLY = 0x20000,
39     LK_INIT_LEVEL_TARGET_EARLY   = 0x30000,
40     LK_INIT_LEVEL_HEAP           = 0x40000,
41     LK_INIT_LEVEL_VM             = 0x50000,
42     LK_INIT_LEVEL_KERNEL         = 0x60000,
43     LK_INIT_LEVEL_THREADING      = 0x70000,
44     LK_INIT_LEVEL_ARCH           = 0x80000,
45     LK_INIT_LEVEL_PLATFORM       = 0x90000,
46     LK_INIT_LEVEL_TARGET         = 0xa0000,
47     LK_INIT_LEVEL_APPS           = 0xb0000,
48 
49     LK_INIT_LEVEL_LAST = UINT_MAX,
50 };
51 
52 /**
53  * enum lk_init_flags - Flags specifying init hook type.
54  *
55  * Flags passed to LK_INIT_HOOK_FLAGS to specify when the hook should be called.
56  */
57 enum lk_init_flags {
58     /**
59      * @LK_INIT_FLAG_PRIMARY_CPU: Call init hook when booting primary CPU.
60      */
61     LK_INIT_FLAG_PRIMARY_CPU     = 0x1,
62 
63     /**
64      * @LK_INIT_FLAG_SECONDARY_CPUS: Call init hook when booting secondary CPUs.
65      */
66     LK_INIT_FLAG_SECONDARY_CPUS  = 0x2,
67 
68     /**
69      * @LK_INIT_FLAG_ALL_CPUS: Call init hook when booting any CPU.
70      */
71     LK_INIT_FLAG_ALL_CPUS        = LK_INIT_FLAG_PRIMARY_CPU | LK_INIT_FLAG_SECONDARY_CPUS,
72 
73     /**
74      * @LK_INIT_FLAG_CPU_ENTER_IDLE: Call init hook before a CPU enters idle.
75      *
76      * The CPU may lose state after this, but it should respond to interrupts.
77      */
78     LK_INIT_FLAG_CPU_ENTER_IDLE  = 0x4,
79 
80     /**
81      * @LK_INIT_FLAG_CPU_OFF: Call init hook before a CPU goes offline.
82      *
83      * The CPU may lose state after this, and it should not respond to
84      * interrupts.
85      */
86     LK_INIT_FLAG_CPU_OFF         = 0x8,
87 
88     /**
89      * @LK_INIT_FLAG_CPU_SUSPEND: Call init hook before a CPU loses state.
90      *
91      * Alias to call hook for both LK_INIT_FLAG_CPU_ENTER_IDLE and
92      * LK_INIT_FLAG_CPU_OFF events.
93      */
94     LK_INIT_FLAG_CPU_SUSPEND     = LK_INIT_FLAG_CPU_ENTER_IDLE | LK_INIT_FLAG_CPU_OFF,
95 
96     /**
97      * @LK_INIT_FLAG_CPU_EXIT_IDLE: Call init hook after a CPU exits idle.
98      *
99      * LK_INIT_FLAG_CPU_ENTER_IDLE should have been called before this.
100      */
101     LK_INIT_FLAG_CPU_EXIT_IDLE   = 0x10,
102 
103     /**
104      * @LK_INIT_FLAG_CPU_ON: Call init hook after a CPU turns on.
105      *
106      * LK_INIT_FLAG_CPU_OFF should have been called before this. The first time
107      * a CPU turns on LK_INIT_FLAG_PRIMARY_CPU or LK_INIT_FLAG_SECONDARY_CPUS
108      * is called instead of this.
109      */
110     LK_INIT_FLAG_CPU_ON          = 0x20,
111 
112     /**
113      * @LK_INIT_FLAG_CPU_RESUME: Call init hook after a CPU exits idle.
114      *
115      * Alias to call hook for both LK_INIT_FLAG_CPU_EXIT_IDLE and
116      * LK_INIT_FLAG_CPU_ON events.
117      */
118     LK_INIT_FLAG_CPU_RESUME      = LK_INIT_FLAG_CPU_EXIT_IDLE | LK_INIT_FLAG_CPU_ON,
119 };
120 
121 void lk_init_level(enum lk_init_flags flags, uint start_level, uint stop_level);
122 
lk_primary_cpu_init_level(uint start_level,uint stop_level)123 static inline void lk_primary_cpu_init_level(uint start_level, uint stop_level)
124 {
125     lk_init_level(LK_INIT_FLAG_PRIMARY_CPU, start_level, stop_level);
126 }
127 
lk_init_level_all(enum lk_init_flags flags)128 static inline void lk_init_level_all(enum lk_init_flags flags)
129 {
130     lk_init_level(flags, LK_INIT_LEVEL_EARLIEST, LK_INIT_LEVEL_LAST);
131 }
132 
133 struct lk_init_struct {
134     uint level;
135     uint flags;
136     lk_init_hook hook;
137     const char *name;
138 };
139 
140 #define LK_INIT_HOOK_FLAGS(_name, _hook, _level, _flags) \
141     const struct lk_init_struct _init_struct_##_name __ALIGNED(sizeof(void *)) __attribute__((used)) __attribute__((visibility("default"))) __SECTION(".lk_init") = { \
142         .level = _level, \
143         .flags = _flags, \
144         .hook = _hook, \
145         .name = #_name, \
146     };
147 
148 #define LK_INIT_HOOK(_name, _hook, _level) \
149     LK_INIT_HOOK_FLAGS(_name, _hook, _level, LK_INIT_FLAG_PRIMARY_CPU)
150