source: mainline/kernel/generic/src/main/main.c@ 384c488

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 384c488 was b24786a3, checked in by Jakub Vana <jakub.vana@…>, 17 years ago

On Itanium there is nead to preserve at least gp when switching APs to separate stack. Safer way is to save all context and to do it on all platforms.

  • Property mode set to 100644
File size: 9.2 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 main
30 * @{
31 */
32
33/**
34 * @file
35 * @brief Main initialization kernel function for all processors.
36 *
37 * During kernel boot, all processors, after architecture dependent
38 * initialization, start executing code found in this file. After
39 * bringing up all subsystems, control is passed to scheduler().
40 *
41 * The bootstrap processor starts executing main_bsp() while
42 * the application processors start executing main_ap().
43 *
44 * @see scheduler()
45 * @see main_bsp()
46 * @see main_ap()
47 */
48
49#include <arch/asm.h>
50#include <context.h>
51#include <print.h>
52#include <panic.h>
53#include <debug.h>
54#include <config.h>
55#include <time/clock.h>
56#include <time/timeout.h>
57#include <proc/scheduler.h>
58#include <proc/thread.h>
59#include <proc/task.h>
60#include <proc/tasklet.h>
61#include <main/kinit.h>
62#include <main/version.h>
63#include <console/kconsole.h>
64#include <console/console.h>
65#include <cpu.h>
66#include <align.h>
67#include <interrupt.h>
68#include <mm/frame.h>
69#include <mm/page.h>
70#include <genarch/mm/page_pt.h>
71#include <mm/tlb.h>
72#include <mm/as.h>
73#include <mm/slab.h>
74#include <synch/waitq.h>
75#include <synch/futex.h>
76#include <arch/arch.h>
77#include <arch.h>
78#include <arch/faddr.h>
79#include <ipc/ipc.h>
80#include <macros.h>
81#include <adt/btree.h>
82#include <smp/smp.h>
83#include <ddi/ddi.h>
84
85
86/** Global configuration structure. */
87config_t config;
88
89/** Initial user-space tasks */
90init_t init = {
91 .cnt = 0
92};
93
94/** Boot allocations. */
95ballocs_t ballocs = {
96 .base = NULL,
97 .size = 0
98};
99
100context_t ctx;
101
102/*
103 * These 'hardcoded' variables will be intialized by
104 * the linker or the low level assembler code with
105 * appropriate sizes and addresses.
106 */
107
108/**< Virtual address of where the kernel is loaded. */
109uintptr_t hardcoded_load_address = 0;
110/**< Size of the kernel code in bytes. */
111size_t hardcoded_ktext_size = 0;
112/**< Size of the kernel data in bytes. */
113size_t hardcoded_kdata_size = 0;
114/**< Lowest safe stack virtual address. */
115uintptr_t stack_safe = 0;
116
117void main_bsp(void);
118void main_ap(void);
119
120/*
121 * These two functions prevent stack from underflowing during the
122 * kernel boot phase when SP is set to the very top of the reserved
123 * space. The stack could get corrupted by a fooled compiler-generated
124 * pop sequence otherwise.
125 */
126static void main_bsp_separated_stack(void);
127#ifdef CONFIG_SMP
128static void main_ap_separated_stack(void);
129#endif
130
131#define CONFIG_STACK_SIZE ((1 << STACK_FRAMES) * STACK_SIZE)
132
133/** Main kernel routine for bootstrap CPU.
134 *
135 * The code here still runs on the boot stack, which knows nothing about
136 * preemption counts. Because of that, this function cannot directly call
137 * functions that disable or enable preemption (e.g. spinlock_lock()). The
138 * primary task of this function is to calculate address of a new stack and
139 * switch to it.
140 *
141 * Assuming interrupts_disable().
142 *
143 */
144void main_bsp(void)
145{
146 config.cpu_count = 1;
147 config.cpu_active = 1;
148
149 config.base = hardcoded_load_address;
150 config.kernel_size = ALIGN_UP(hardcoded_ktext_size +
151 hardcoded_kdata_size, PAGE_SIZE);
152 config.stack_size = CONFIG_STACK_SIZE;
153
154 /* Initialy the stack is placed just after the kernel */
155 config.stack_base = config.base + config.kernel_size;
156
157 /* Avoid placing stack on top of init */
158 count_t i;
159 for (i = 0; i < init.cnt; i++) {
160 if (PA_overlaps(config.stack_base, config.stack_size,
161 init.tasks[i].addr, init.tasks[i].size))
162 config.stack_base = ALIGN_UP(init.tasks[i].addr +
163 init.tasks[i].size, config.stack_size);
164 }
165
166 /* Avoid placing stack on top of boot allocations. */
167 if (ballocs.size) {
168 if (PA_overlaps(config.stack_base, config.stack_size,
169 ballocs.base, ballocs.size))
170 config.stack_base = ALIGN_UP(ballocs.base +
171 ballocs.size, PAGE_SIZE);
172 }
173
174 if (config.stack_base < stack_safe)
175 config.stack_base = ALIGN_UP(stack_safe, PAGE_SIZE);
176
177 context_save(&ctx);
178 context_set(&ctx, FADDR(main_bsp_separated_stack), config.stack_base,
179 THREAD_STACK_SIZE);
180 context_restore(&ctx);
181 /* not reached */
182}
183
184
185/** Main kernel routine for bootstrap CPU using new stack.
186 *
187 * Second part of main_bsp().
188 *
189 */
190void main_bsp_separated_stack(void)
191{
192 /* Keep this the first thing. */
193 the_initialize(THE);
194
195 LOG();
196
197 version_print();
198
199 LOG("\nconfig.base=%#" PRIp " config.kernel_size=%" PRIs
200 "\nconfig.stack_base=%#" PRIp " config.stack_size=%" PRIs,
201 config.base, config.kernel_size, config.stack_base,
202 config.stack_size);
203
204
205 /*
206 * kconsole data structures must be initialized very early
207 * because other subsystems will register their respective
208 * commands.
209 */
210 LOG_EXEC(kconsole_init());
211
212 /*
213 * Exception handler initialization, before architecture
214 * starts adding its own handlers
215 */
216 LOG_EXEC(exc_init());
217
218 /*
219 * Memory management subsystems initialization.
220 */
221 LOG_EXEC(arch_pre_mm_init());
222 LOG_EXEC(frame_init());
223
224 /* Initialize at least 1 memory segment big enough for slab to work. */
225 LOG_EXEC(slab_cache_init());
226 LOG_EXEC(btree_init());
227 LOG_EXEC(as_init());
228 LOG_EXEC(page_init());
229 LOG_EXEC(tlb_init());
230 LOG_EXEC(ddi_init());
231 LOG_EXEC(tasklet_init());
232 LOG_EXEC(arch_post_mm_init());
233 LOG_EXEC(arch_pre_smp_init());
234 LOG_EXEC(smp_init());
235
236 /* Slab must be initialized after we know the number of processors. */
237 LOG_EXEC(slab_enable_cpucache());
238
239 printf("Detected %" PRIc " CPU(s), %" PRIu64" MiB free memory\n",
240 config.cpu_count, SIZE2MB(zone_total_size()));
241
242 LOG_EXEC(cpu_init());
243
244 LOG_EXEC(calibrate_delay_loop());
245 LOG_EXEC(clock_counter_init());
246 LOG_EXEC(timeout_init());
247 LOG_EXEC(scheduler_init());
248 LOG_EXEC(task_init());
249 LOG_EXEC(thread_init());
250 LOG_EXEC(futex_init());
251
252 if (init.cnt > 0) {
253 count_t i;
254 for (i = 0; i < init.cnt; i++)
255 printf("init[%" PRIc "].addr=%#" PRIp ", init[%" PRIc
256 "].size=%#" PRIs "\n", i, init.tasks[i].addr, i,
257 init.tasks[i].size);
258 } else
259 printf("No init binaries found\n");
260
261 LOG_EXEC(ipc_init());
262 LOG_EXEC(klog_init());
263
264 /*
265 * Create kernel task.
266 */
267 task_t *kernel = task_create(AS_KERNEL, "kernel");
268 if (!kernel)
269 panic("Can't create kernel task\n");
270
271 /*
272 * Create the first thread.
273 */
274 thread_t *kinit_thread = thread_create(kinit, NULL, kernel, 0, "kinit",
275 true);
276 if (!kinit_thread)
277 panic("Can't create kinit thread\n");
278 LOG_EXEC(thread_ready(kinit_thread));
279
280 /*
281 * This call to scheduler() will return to kinit,
282 * starting the thread of kernel threads.
283 */
284 scheduler();
285 /* not reached */
286}
287
288
289#ifdef CONFIG_SMP
290/** Main kernel routine for application CPUs.
291 *
292 * Executed by application processors, temporary stack
293 * is at ctx.sp which was set during BSP boot.
294 * This function passes control directly to
295 * main_ap_separated_stack().
296 *
297 * Assuming interrupts_disable()'d.
298 *
299 */
300void main_ap(void)
301{
302 /*
303 * Incrementing the active CPU counter will guarantee that the
304 * *_init() functions can find out that they need to
305 * do initialization for AP only.
306 */
307 config.cpu_active++;
308
309 /*
310 * The THE structure is well defined because ctx.sp is used as stack.
311 */
312 the_initialize(THE);
313
314 arch_pre_mm_init();
315 frame_init();
316 page_init();
317 tlb_init();
318 arch_post_mm_init();
319
320 cpu_init();
321 calibrate_delay_loop();
322 arch_post_cpu_init();
323
324 the_copy(THE, (the_t *) CPU->stack);
325
326 /*
327 * If we woke kmp up before we left the kernel stack, we could
328 * collide with another CPU coming up. To prevent this, we
329 * switch to this cpu's private stack prior to waking kmp up.
330 */
331 context_save(&CPU->saved_context);
332 context_set(&CPU->saved_context, FADDR(main_ap_separated_stack),
333 (uintptr_t) CPU->stack, CPU_STACK_SIZE);
334 context_restore(&CPU->saved_context);
335 /* not reached */
336}
337
338
339/** Main kernel routine for application CPUs using new stack.
340 *
341 * Second part of main_ap().
342 *
343 */
344void main_ap_separated_stack(void)
345{
346 /*
347 * Configure timeouts for this cpu.
348 */
349 timeout_init();
350
351 waitq_wakeup(&ap_completion_wq, WAKEUP_FIRST);
352 scheduler();
353 /* not reached */
354}
355#endif /* CONFIG_SMP */
356
357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.