source: mainline/kernel/generic/src/main/kinit.c@ 0366d09d

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0366d09d was 7c5320c, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 years ago

Use the semaphore interface instead of waitq in some places

Since we already have an underused semaphore API in the kernel,
it would be worthwhile to use it in places where the baseline
semaphore semantics are needed. It makes the function of the
calls obvious even to people unfamiliar with the details of
waitq API.

  • Property mode set to 100644
File size: 8.1 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup kernel_generic
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Kernel initialization thread.
36 *
37 * This file contains kinit kernel thread which carries out
38 * high level system initialization.
39 *
40 * This file is responsible for finishing SMP configuration
41 * and creation of userspace init tasks.
42 */
43
44#include <assert.h>
45#include <main/kinit.h>
46#include <config.h>
47#include <arch.h>
48#include <proc/scheduler.h>
49#include <proc/task.h>
50#include <proc/thread.h>
51#include <proc/program.h>
52#include <panic.h>
53#include <halt.h>
54#include <cpu.h>
55#include <arch/asm.h>
56#include <mm/page.h>
57#include <arch/mm/page.h>
58#include <mm/as.h>
59#include <mm/frame.h>
60#include <mm/km.h>
61#include <stdio.h>
62#include <log.h>
63#include <mem.h>
64#include <console/console.h>
65#include <interrupt.h>
66#include <console/kconsole.h>
67#include <security/perm.h>
68#include <lib/rd.h>
69#include <ipc/ipc.h>
70#include <str.h>
71#include <sysinfo/stats.h>
72#include <sysinfo/sysinfo.h>
73#include <align.h>
74#include <stdlib.h>
75
76#ifdef CONFIG_SMP
77#include <smp/smp.h>
78#endif /* CONFIG_SMP */
79
80#include <synch/waitq.h>
81#include <synch/spinlock.h>
82
83#define ALIVE_CHARS 4
84
85#ifdef CONFIG_KCONSOLE
86static char alive[ALIVE_CHARS] = "-\\|/";
87#endif
88
89#define INIT_PREFIX "init:"
90#define INIT_PREFIX_LEN 5
91
92/** Kernel initialization thread.
93 *
94 * kinit takes care of higher level kernel
95 * initialization (i.e. thread creation,
96 * userspace initialization etc.).
97 *
98 * @param arg Not used.
99 */
100void kinit(void *arg)
101{
102 thread_t *thread;
103
104 /*
105 * Detach kinit as nobody will call thread_join_timeout() on it.
106 */
107 thread_detach(THREAD);
108
109 interrupts_disable();
110
111#ifdef CONFIG_SMP
112 if (config.cpu_count > 1) {
113 semaphore_initialize(&ap_completion_semaphore, 0);
114
115 /*
116 * Create the kmp thread and wait for its completion.
117 * cpu1 through cpuN-1 will come up consecutively and
118 * not mess together with kcpulb threads.
119 * Just a beautification.
120 */
121 thread = thread_create(kmp, NULL, TASK,
122 THREAD_FLAG_UNCOUNTED, "kmp");
123 if (!thread)
124 panic("Unable to create kmp thread.");
125
126 thread_wire(thread, &cpus[0]);
127 thread_ready(thread);
128 thread_join(thread);
129 thread_detach(thread);
130
131 /*
132 * For each CPU, create its load balancing thread.
133 */
134 unsigned int i;
135
136 for (i = 0; i < config.cpu_count; i++) {
137 thread = thread_create(kcpulb, NULL, TASK,
138 THREAD_FLAG_UNCOUNTED, "kcpulb");
139 if (thread != NULL) {
140 thread_wire(thread, &cpus[i]);
141 thread_ready(thread);
142 } else
143 log(LF_OTHER, LVL_ERROR,
144 "Unable to create kcpulb thread for cpu%u", i);
145 }
146 }
147#endif /* CONFIG_SMP */
148
149 /*
150 * At this point SMP, if present, is configured.
151 */
152 ARCH_OP(post_smp_init);
153
154 /* Start thread computing system load */
155 thread = thread_create(kload, NULL, TASK, THREAD_FLAG_NONE,
156 "kload");
157 if (thread != NULL)
158 thread_ready(thread);
159 else
160 log(LF_OTHER, LVL_ERROR, "Unable to create kload thread");
161
162#ifdef CONFIG_KCONSOLE
163 if (stdin) {
164 /*
165 * Create kernel console.
166 */
167 thread = thread_create(kconsole_thread, NULL, TASK,
168 THREAD_FLAG_NONE, "kconsole");
169 if (thread != NULL)
170 thread_ready(thread);
171 else
172 log(LF_OTHER, LVL_ERROR,
173 "Unable to create kconsole thread");
174 }
175#endif /* CONFIG_KCONSOLE */
176
177 /*
178 * Store the default stack size in sysinfo so that uspace can create
179 * stack with this default size.
180 */
181 sysinfo_set_item_val("default.stack_size", NULL, STACK_SIZE_USER);
182
183 interrupts_enable();
184
185 /*
186 * Create user tasks, load RAM disk images.
187 */
188 size_t i;
189 program_t programs[CONFIG_INIT_TASKS];
190
191 // FIXME: do not propagate arguments through sysinfo
192 // but pass them directly to the tasks
193 for (i = 0; i < init.cnt; i++) {
194 const char *arguments = init.tasks[i].arguments;
195 if (str_length(arguments) == 0)
196 continue;
197 if (str_length(init.tasks[i].name) == 0)
198 continue;
199 size_t arguments_size = str_size(arguments);
200
201 void *arguments_copy = malloc(arguments_size);
202 if (arguments_copy == NULL)
203 continue;
204 memcpy(arguments_copy, arguments, arguments_size);
205
206 char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
207 snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
208 "init_args.%s", init.tasks[i].name);
209
210 sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
211 }
212
213 for (i = 0; i < init.cnt; i++) {
214 if (init.tasks[i].paddr % FRAME_SIZE) {
215 log(LF_OTHER, LVL_ERROR,
216 "init[%zu]: Address is not frame aligned", i);
217 programs[i].task = NULL;
218 continue;
219 }
220
221 /*
222 * Construct task name from the 'init:' prefix and the
223 * name stored in the init structure (if any).
224 */
225
226 char namebuf[TASK_NAME_BUFLEN];
227
228 const char *name = init.tasks[i].name;
229 if (name[0] == 0)
230 name = "<unknown>";
231
232 static_assert(TASK_NAME_BUFLEN >= INIT_PREFIX_LEN, "");
233 str_cpy(namebuf, TASK_NAME_BUFLEN, INIT_PREFIX);
234 str_cpy(namebuf + INIT_PREFIX_LEN,
235 TASK_NAME_BUFLEN - INIT_PREFIX_LEN, name);
236
237 /*
238 * Create virtual memory mappings for init task images.
239 */
240 uintptr_t page = km_map(init.tasks[i].paddr,
241 init.tasks[i].size, PAGE_SIZE,
242 PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
243 assert(page);
244
245 if (str_cmp(name, "loader") == 0) {
246 /* Register image as the program loader */
247 if (program_loader == NULL) {
248 program_loader = (void *) page;
249 log(LF_OTHER, LVL_NOTE, "Program loader at %p",
250 program_loader);
251 } else {
252 log(LF_OTHER, LVL_ERROR,
253 "init[%zu]: Second binary named \"loader\""
254 " present.", i);
255 }
256
257 programs[i].task = NULL;
258 continue;
259 }
260
261 errno_t rc = program_create_from_image((void *) page, namebuf,
262 &programs[i]);
263
264 if (rc == 0) {
265 assert(programs[i].task != NULL);
266
267 /*
268 * Set permissions to init userspace tasks.
269 */
270 perm_set(programs[i].task,
271 PERM_PERM | PERM_MEM_MANAGER |
272 PERM_IO_MANAGER | PERM_IRQ_REG);
273
274 if (!ipc_box_0) {
275 ipc_box_0 = &programs[i].task->answerbox;
276 /*
277 * Hold the first task so that
278 * ipc_box_0 remains a valid pointer
279 * even if the first task exits for
280 * whatever reason.
281 */
282 task_hold(programs[i].task);
283 }
284
285 } else if (i == init.cnt - 1) {
286 /*
287 * Assume the last task is the RAM disk.
288 */
289 init_rd((void *) init.tasks[i].paddr, init.tasks[i].size);
290 } else {
291 log(LF_OTHER, LVL_ERROR,
292 "init[%zu]: Init binary load failed "
293 "(error %s, loader status %s)", i,
294 str_error_name(rc), str_error_name(programs[i].loader_status));
295 }
296 }
297
298 /*
299 * Run user tasks.
300 */
301 for (i = 0; i < init.cnt; i++) {
302 if (programs[i].task != NULL)
303 program_ready(&programs[i]);
304 }
305
306#ifdef CONFIG_KCONSOLE
307 if (!stdin) {
308 thread_sleep(10);
309 printf("kinit: No stdin\nKernel alive: .");
310
311 unsigned int i = 0;
312 while (true) {
313 printf("\b%c", alive[i % ALIVE_CHARS]);
314 thread_sleep(1);
315 i++;
316 }
317 }
318#endif /* CONFIG_KCONSOLE */
319}
320
321/** @}
322 */
Note: See TracBrowser for help on using the repository browser.