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

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

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 8.1 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[f761f1eb]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
[8e3bf3e2]29/** @addtogroup main
[b45c443]30 * @{
31 */
32
[9179d0a]33/**
[b45c443]34 * @file
[2f57690]35 * @brief Kernel initialization thread.
[9179d0a]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
[63e27ef]44#include <assert.h>
[f761f1eb]45#include <main/kinit.h>
[2677758]46#include <config.h>
47#include <arch.h>
[f761f1eb]48#include <proc/scheduler.h>
49#include <proc/task.h>
50#include <proc/thread.h>
[c98e6ee]51#include <proc/program.h>
[f761f1eb]52#include <panic.h>
[b2e121a]53#include <halt.h>
[f761f1eb]54#include <cpu.h>
55#include <arch/asm.h>
56#include <mm/page.h>
57#include <arch/mm/page.h>
[20d50a1]58#include <mm/as.h>
[ff3b3197]59#include <mm/frame.h>
[32817cc]60#include <mm/km.h>
[9c0a9b3]61#include <print.h>
[b2fa1204]62#include <log.h>
[44a7ee5]63#include <mem.h>
[ff3b3197]64#include <console/console.h>
[aace6624]65#include <interrupt.h>
[f4338d2]66#include <console/kconsole.h>
[719a208]67#include <security/perm.h>
[d4b5542]68#include <lib/rd.h>
[b3f8fb7]69#include <ipc/ipc.h>
[19f857a]70#include <str.h>
[9dae191e]71#include <sysinfo/stats.h>
[c8cbd39]72#include <sysinfo/sysinfo.h>
[32817cc]73#include <align.h>
[f761f1eb]74
[5f85c91]75#ifdef CONFIG_SMP
[26678e5]76#include <smp/smp.h>
[5f85c91]77#endif /* CONFIG_SMP */
[f761f1eb]78
79#include <synch/waitq.h>
80#include <synch/spinlock.h>
[8a64e81e]81#include <synch/workqueue.h>
[181a746]82#include <synch/rcu.h>
[f761f1eb]83
[c19a4169]84#define ALIVE_CHARS 4
85
[753d851]86#ifdef CONFIG_KCONSOLE
[c19a4169]87static char alive[ALIVE_CHARS] = "-\\|/";
[753d851]88#endif
[c19a4169]89
[da581872]90#define INIT_PREFIX "init:"
91#define INIT_PREFIX_LEN 5
[20f1597]92
[880de6e]93/** Kernel initialization thread.
94 *
95 * kinit takes care of higher level kernel
96 * initialization (i.e. thread creation,
97 * userspace initialization etc.).
98 *
99 * @param arg Not used.
100 */
[f761f1eb]101void kinit(void *arg)
102{
[76fca31]103 thread_t *thread;
[a35b458]104
[2cb5e64]105 /*
106 * Detach kinit as nobody will call thread_join_timeout() on it.
107 */
108 thread_detach(THREAD);
[8a64e81e]109
[22f7769]110 interrupts_disable();
[a35b458]111
[181a746]112 /* Start processing RCU callbacks. RCU is fully functional afterwards. */
113 rcu_kinit_init();
[a35b458]114
[8a64e81e]115 /*
116 * Start processing work queue items. Some may have been queued during boot.
117 */
118 workq_global_worker_init();
[a35b458]119
[2f57690]120#ifdef CONFIG_SMP
[f761f1eb]121 if (config.cpu_count > 1) {
[26678e5]122 waitq_initialize(&ap_completion_wq);
[a35b458]123
[f761f1eb]124 /*
125 * Create the kmp thread and wait for its completion.
126 * cpu1 through cpuN-1 will come up consecutively and
[169c408]127 * not mess together with kcpulb threads.
[f761f1eb]128 * Just a beautification.
129 */
[6eef3c4]130 thread = thread_create(kmp, NULL, TASK,
131 THREAD_FLAG_UNCOUNTED, "kmp");
[76fca31]132 if (thread != NULL) {
[6eef3c4]133 thread_wire(thread, &cpus[0]);
[76fca31]134 thread_ready(thread);
[8e3bf3e2]135 } else
[f651e80]136 panic("Unable to create kmp thread.");
[a35b458]137
[76fca31]138 thread_join(thread);
139 thread_detach(thread);
[a35b458]140
[76cec1e]141 /*
[f761f1eb]142 * For each CPU, create its load balancing thread.
143 */
[7e752b2]144 unsigned int i;
[a35b458]145
[f761f1eb]146 for (i = 0; i < config.cpu_count; i++) {
[6eef3c4]147 thread = thread_create(kcpulb, NULL, TASK,
148 THREAD_FLAG_UNCOUNTED, "kcpulb");
[76fca31]149 if (thread != NULL) {
[6eef3c4]150 thread_wire(thread, &cpus[i]);
[76fca31]151 thread_ready(thread);
[8e3bf3e2]152 } else
[b2fa1204]153 log(LF_OTHER, LVL_ERROR,
154 "Unable to create kcpulb thread for cpu%u", i);
[f761f1eb]155 }
156 }
[5f85c91]157#endif /* CONFIG_SMP */
[a35b458]158
[a83a802]159 /*
160 * At this point SMP, if present, is configured.
161 */
[36df4109]162 ARCH_OP(post_smp_init);
[a35b458]163
[9dae191e]164 /* Start thread computing system load */
[6eef3c4]165 thread = thread_create(kload, NULL, TASK, THREAD_FLAG_NONE,
166 "kload");
[9dae191e]167 if (thread != NULL)
168 thread_ready(thread);
169 else
[b2fa1204]170 log(LF_OTHER, LVL_ERROR, "Unable to create kload thread");
[a35b458]171
[76fca31]172#ifdef CONFIG_KCONSOLE
173 if (stdin) {
174 /*
175 * Create kernel console.
176 */
[6eef3c4]177 thread = thread_create(kconsole_thread, NULL, TASK,
178 THREAD_FLAG_NONE, "kconsole");
[76fca31]179 if (thread != NULL)
180 thread_ready(thread);
181 else
[b2fa1204]182 log(LF_OTHER, LVL_ERROR,
183 "Unable to create kconsole thread");
[76fca31]184 }
185#endif /* CONFIG_KCONSOLE */
[a35b458]186
[0aae87a6]187 /*
188 * Store the default stack size in sysinfo so that uspace can create
189 * stack with this default size.
190 */
[67b152e]191 sysinfo_set_item_val("default.stack_size", NULL, STACK_SIZE_USER);
[a35b458]192
[22f7769]193 interrupts_enable();
[a35b458]194
[49eec93]195 /*
196 * Create user tasks, load RAM disk images.
197 */
[98000fb]198 size_t i;
[c98e6ee]199 program_t programs[CONFIG_INIT_TASKS];
[a35b458]200
[c8cbd39]201 // FIXME: do not propagate arguments through sysinfo
202 // but pass them directly to the tasks
203 for (i = 0; i < init.cnt; i++) {
204 const char *arguments = init.tasks[i].arguments;
205 if (str_length(arguments) == 0)
206 continue;
207 if (str_length(init.tasks[i].name) == 0)
208 continue;
209 size_t arguments_size = str_size(arguments);
210
211 void *arguments_copy = malloc(arguments_size, 0);
212 if (arguments_copy == NULL)
213 continue;
214 memcpy(arguments_copy, arguments, arguments_size);
215
216 char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
217 snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
218 "init_args.%s", init.tasks[i].name);
219
220 sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
221 }
222
[b6b576c]223 for (i = 0; i < init.cnt; i++) {
[32817cc]224 if (init.tasks[i].paddr % FRAME_SIZE) {
[b2fa1204]225 log(LF_OTHER, LVL_ERROR,
226 "init[%zu]: Address is not frame aligned", i);
[2319df3]227 programs[i].task = NULL;
[228b135]228 continue;
229 }
[a35b458]230
[20f1597]231 /*
[da581872]232 * Construct task name from the 'init:' prefix and the
[20f1597]233 * name stored in the init structure (if any).
234 */
[a35b458]235
[2f57690]236 char namebuf[TASK_NAME_BUFLEN];
[a35b458]237
[a000878c]238 const char *name = init.tasks[i].name;
[b60c582]239 if (name[0] == 0)
[2f57690]240 name = "<unknown>";
[a35b458]241
[63e27ef]242 static_assert(TASK_NAME_BUFLEN >= INIT_PREFIX_LEN, "");
[f4b1535]243 str_cpy(namebuf, TASK_NAME_BUFLEN, INIT_PREFIX);
244 str_cpy(namebuf + INIT_PREFIX_LEN,
245 TASK_NAME_BUFLEN - INIT_PREFIX_LEN, name);
[a35b458]246
[32817cc]247 /*
248 * Create virtual memory mappings for init task images.
249 */
[221c9ec]250 uintptr_t page = km_map(init.tasks[i].paddr,
251 init.tasks[i].size,
252 PAGE_READ | PAGE_WRITE | PAGE_CACHEABLE);
[63e27ef]253 assert(page);
[a35b458]254
[b7fd2a0]255 errno_t rc = program_create_from_image((void *) page, namebuf,
[32817cc]256 &programs[i]);
[a35b458]257
[fb48a0e]258 if (rc == 0) {
259 if (programs[i].task != NULL) {
260 /*
[719a208]261 * Set permissions to init userspace tasks.
[fb48a0e]262 */
[719a208]263 perm_set(programs[i].task,
264 PERM_PERM | PERM_MEM_MANAGER |
265 PERM_IO_MANAGER | PERM_IRQ_REG);
[a35b458]266
[a4e23f8c]267 if (!ipc_phone_0) {
[fb48a0e]268 ipc_phone_0 = &programs[i].task->answerbox;
[a4e23f8c]269 /*
270 * Hold the first task so that the
271 * ipc_phone_0 remains a valid pointer
272 * even if the first task exits for
273 * whatever reason.
274 */
275 task_hold(programs[i].task);
276 }
[fb48a0e]277 }
[a35b458]278
[1077d91]279 /*
[fb48a0e]280 * If programs[i].task == NULL then it is
281 * the program loader and it was registered
282 * successfully.
[1077d91]283 */
[fb48a0e]284 } else if (i == init.cnt - 1) {
285 /*
286 * Assume the last task is the RAM disk.
287 */
[221c9ec]288 init_rd((void *) init.tasks[i].paddr, init.tasks[i].size);
[fb48a0e]289 } else
[b2fa1204]290 log(LF_OTHER, LVL_ERROR,
291 "init[%zu]: Init binary load failed "
[62ca560]292 "(error %s, loader status %u)", i,
293 str_error_name(rc), programs[i].loader_status);
[49eec93]294 }
[a35b458]295
[49eec93]296 /*
[566f4cfb]297 * Run user tasks.
[49eec93]298 */
299 for (i = 0; i < init.cnt; i++) {
[566f4cfb]300 if (programs[i].task != NULL)
[c98e6ee]301 program_ready(&programs[i]);
[44c259c]302 }
[a35b458]303
[76fca31]304#ifdef CONFIG_KCONSOLE
[ff3b3197]305 if (!stdin) {
[c19a4169]306 thread_sleep(10);
[eddf924]307 printf("kinit: No stdin\nKernel alive: .");
[a35b458]308
[c19a4169]309 unsigned int i = 0;
310 while (true) {
311 printf("\b%c", alive[i % ALIVE_CHARS]);
[ff3b3197]312 thread_sleep(1);
[76fca31]313 i++;
[ff3b3197]314 }
[f761f1eb]315 }
[76fca31]316#endif /* CONFIG_KCONSOLE */
[f761f1eb]317}
[b45c443]318
[8e3bf3e2]319/** @}
[b45c443]320 */
Note: See TracBrowser for help on using the repository browser.