unstack: add shared libraries symbols
[minix.git] / kernel / main.c
blobf107079e3a1078688127b55034f0fddcd9072063
1 /* This file contains the main program of MINIX as well as its shutdown code.
2 * The routine main() initializes the system and starts the ball rolling by
3 * setting up the process table, interrupt vectors, and scheduling each task
4 * to run to initialize itself.
5 * The routine shutdown() does the opposite and brings down MINIX.
7 * The entries into this file are:
8 * main: MINIX main program
9 * prepare_shutdown: prepare to take MINIX down
11 #include "kernel.h"
12 #include <string.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <assert.h>
16 #include <libexec.h>
17 #include <a.out.h>
18 #include <minix/com.h>
19 #include <minix/endpoint.h>
20 #include <machine/vmparam.h>
21 #include <minix/u64.h>
22 #include <minix/type.h>
23 #include "clock.h"
24 #include "hw_intr.h"
25 #include "arch_proto.h"
27 #ifdef CONFIG_SMP
28 #include "smp.h"
29 #endif
30 #ifdef USE_WATCHDOG
31 #include "watchdog.h"
32 #endif
33 #include "spinlock.h"
35 /* dummy for linking */
36 char *** _penviron;
38 /* Prototype declarations for PRIVATE functions. */
39 static void announce(void);
41 void bsp_finish_booting(void)
43 int i;
44 #if SPROFILE
45 sprofiling = 0; /* we're not profiling until instructed to */
46 #endif /* SPROFILE */
47 cprof_procs_no = 0; /* init nr of hash table slots used */
49 cpu_identify();
51 vm_running = 0;
52 krandom.random_sources = RANDOM_SOURCES;
53 krandom.random_elements = RANDOM_ELEMENTS;
55 /* MINIX is now ready. All boot image processes are on the ready queue.
56 * Return to the assembly code to start running the current process.
59 /* it should point somewhere */
60 get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc);
61 get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc);
62 announce(); /* print MINIX startup banner */
65 * we have access to the cpu local run queue, only now schedule the processes.
66 * We ignore the slots for the former kernel tasks
68 for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) {
69 RTS_UNSET(proc_addr(i), RTS_PROC_STOP);
72 * enable timer interrupts and clock task on the boot CPU
74 if (boot_cpu_init_timer(system_hz)) {
75 panic("FATAL : failed to initialize timer interrupts, "
76 "cannot continue without any clock source!");
79 fpu_init();
81 /* Warnings for sanity checks that take time. These warnings are printed
82 * so it's a clear warning no full release should be done with them
83 * enabled.
85 #if DEBUG_SCHED_CHECK
86 FIXME("DEBUG_SCHED_CHECK enabled");
87 #endif
88 #if DEBUG_VMASSERT
89 FIXME("DEBUG_VMASSERT enabled");
90 #endif
91 #if DEBUG_PROC_CHECK
92 FIXME("PROC check enabled");
93 #endif
95 DEBUGEXTRA(("cycles_accounting_init()... "));
96 cycles_accounting_init();
97 DEBUGEXTRA(("done\n"));
99 #ifdef CONFIG_SMP
100 cpu_set_flag(bsp_cpu_id, CPU_IS_READY);
101 machine.processors_count = ncpus;
102 machine.bsp_id = bsp_cpu_id;
103 #else
104 machine.processors_count = 1;
105 machine.bsp_id = 0;
106 #endif
108 /* Kernel may no longer use bits of memory as VM will be running soon */
109 kernel_may_alloc = 0;
111 switch_to_user();
112 NOT_REACHABLE;
115 /*===========================================================================*
116 * kmain *
117 *===========================================================================*/
118 void kmain(kinfo_t *local_cbi)
120 /* Start the ball rolling. */
121 struct boot_image *ip; /* boot image pointer */
122 register struct proc *rp; /* process pointer */
123 register int i, j;
125 /* save a global copy of the boot parameters */
126 memcpy(&kinfo, local_cbi, sizeof(kinfo));
127 memcpy(&kmess, kinfo.kmess, sizeof(kmess));
129 /* We can talk now */
130 printf("MINIX booting\n");
132 /* Kernel may use bits of main memory before VM is started */
133 kernel_may_alloc = 1;
135 assert(sizeof(kinfo.boot_procs) == sizeof(image));
136 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
138 cstart();
140 BKL_LOCK();
142 DEBUGEXTRA(("main()\n"));
144 proc_init();
146 if(NR_BOOT_MODULES != kinfo.mbi.mods_count)
147 panic("expecting %d boot processes/modules, found %d",
148 NR_BOOT_MODULES, kinfo.mbi.mods_count);
150 /* Set up proc table entries for processes in boot image. */
151 for (i=0; i < NR_BOOT_PROCS; ++i) {
152 int schedulable_proc;
153 proc_nr_t proc_nr;
154 int ipc_to_m, kcalls;
155 sys_map_t map;
157 ip = &image[i]; /* process' attributes */
158 DEBUGEXTRA(("initializing %s... ", ip->proc_name));
159 rp = proc_addr(ip->proc_nr); /* get process pointer */
160 ip->endpoint = rp->p_endpoint; /* ipc endpoint */
161 make_zero64(rp->p_cpu_time_left);
162 if(i < NR_TASKS) /* name (tasks only) */
163 strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_name));
165 if(i >= NR_TASKS) {
166 /* Remember this so it can be passed to VM */
167 multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS];
168 ip->start_addr = mb_mod->mod_start;
169 ip->len = mb_mod->mod_end - mb_mod->mod_start;
172 reset_proc_accounting(rp);
174 /* See if this process is immediately schedulable.
175 * In that case, set its privileges now and allow it to run.
176 * Only kernel tasks and the root system process get to run immediately.
177 * All the other system processes are inhibited from running by the
178 * RTS_NO_PRIV flag. They can only be scheduled once the root system
179 * process has set their privileges.
181 proc_nr = proc_nr(rp);
182 schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) ||
183 proc_nr == VM_PROC_NR);
184 if(schedulable_proc) {
185 /* Assign privilege structure. Force a static privilege id. */
186 (void) get_priv(rp, static_priv_id(proc_nr));
188 /* Priviliges for kernel tasks. */
189 if(proc_nr == VM_PROC_NR) {
190 priv(rp)->s_flags = VM_F;
191 priv(rp)->s_trap_mask = SRV_T;
192 ipc_to_m = SRV_M;
193 kcalls = SRV_KC;
194 priv(rp)->s_sig_mgr = SELF;
195 rp->p_priority = SRV_Q;
196 rp->p_quantum_size_ms = SRV_QT;
198 else if(iskerneln(proc_nr)) {
199 /* Privilege flags. */
200 priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
201 /* Allowed traps. */
202 priv(rp)->s_trap_mask = (proc_nr == CLOCK
203 || proc_nr == SYSTEM ? CSK_T : TSK_T);
204 ipc_to_m = TSK_M; /* allowed targets */
205 kcalls = TSK_KC; /* allowed kernel calls */
207 /* Priviliges for the root system process. */
208 else {
209 assert(isrootsysn(proc_nr));
210 priv(rp)->s_flags= RSYS_F; /* privilege flags */
211 priv(rp)->s_trap_mask= SRV_T; /* allowed traps */
212 ipc_to_m = SRV_M; /* allowed targets */
213 kcalls = SRV_KC; /* allowed kernel calls */
214 priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */
215 rp->p_priority = SRV_Q; /* priority queue */
216 rp->p_quantum_size_ms = SRV_QT; /* quantum size */
219 /* Fill in target mask. */
220 memset(&map, 0, sizeof(map));
222 if (ipc_to_m == ALL_M) {
223 for(j = 0; j < NR_SYS_PROCS; j++)
224 set_sys_bit(map, j);
227 fill_sendto_mask(rp, &map);
229 /* Fill in kernel call mask. */
230 for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
231 priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
234 else {
235 /* Don't let the process run for now. */
236 RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
239 /* Arch-specific state initialization. */
240 arch_boot_proc(ip, rp);
242 /* scheduling functions depend on proc_ptr pointing somewhere. */
243 if(!get_cpulocal_var(proc_ptr))
244 get_cpulocal_var(proc_ptr) = rp;
246 /* Process isn't scheduled until VM has set up a pagetable for it. */
247 if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0) {
248 rp->p_rts_flags |= RTS_VMINHIBIT;
249 rp->p_rts_flags |= RTS_BOOTINHIBIT;
252 rp->p_rts_flags |= RTS_PROC_STOP;
253 rp->p_rts_flags &= ~RTS_SLOT_FREE;
254 DEBUGEXTRA(("done\n"));
257 /* update boot procs info for VM */
258 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
260 #define IPCNAME(n) { \
261 assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
262 assert(!ipc_call_names[n]); \
263 ipc_call_names[n] = #n; \
266 arch_post_init();
268 IPCNAME(SEND);
269 IPCNAME(RECEIVE);
270 IPCNAME(SENDREC);
271 IPCNAME(NOTIFY);
272 IPCNAME(SENDNB);
273 IPCNAME(SENDA);
275 /* System and processes initialization */
276 memory_init();
277 DEBUGEXTRA(("system_init()... "));
278 system_init();
279 DEBUGEXTRA(("done\n"));
281 /* The bootstrap phase is over, so we can add the physical
282 * memory used for it to the free list.
284 add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len);
286 #ifdef CONFIG_SMP
287 if (config_no_apic) {
288 BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n"));
289 smp_single_cpu_fallback();
290 } else if (config_no_smp) {
291 BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n"));
292 smp_single_cpu_fallback();
293 } else {
294 smp_init();
296 * if smp_init() returns it means that it failed and we try to finish
297 * single CPU booting
299 bsp_finish_booting();
301 #else
303 * if configured for a single CPU, we are already on the kernel stack which we
304 * are going to use everytime we execute kernel code. We finish booting and we
305 * never return here
307 bsp_finish_booting();
308 #endif
310 NOT_REACHABLE;
313 /*===========================================================================*
314 * announce *
315 *===========================================================================*/
316 static void announce(void)
318 /* Display the MINIX startup banner. */
319 printf("\nMINIX %s.%s. "
320 #ifdef _VCS_REVISION
321 "(" _VCS_REVISION ")\n"
322 #endif
323 "Copyright 2012, Vrije Universiteit, Amsterdam, The Netherlands\n",
324 OS_RELEASE, OS_VERSION);
325 printf("MINIX is open source software, see http://www.minix3.org\n");
328 /*===========================================================================*
329 * prepare_shutdown *
330 *===========================================================================*/
331 void prepare_shutdown(const int how)
333 /* This function prepares to shutdown MINIX. */
334 static timer_t shutdown_timer;
336 /* Continue after 1 second, to give processes a chance to get scheduled to
337 * do shutdown work. Set a watchog timer to call shutdown(). The timer
338 * argument passes the shutdown status.
340 printf("MINIX will now be shut down ...\n");
341 tmr_arg(&shutdown_timer)->ta_int = how;
342 set_timer(&shutdown_timer, get_uptime() + system_hz, minix_shutdown);
345 /*===========================================================================*
346 * shutdown *
347 *===========================================================================*/
348 void minix_shutdown(timer_t *tp)
350 /* This function is called from prepare_shutdown or stop_sequence to bring
351 * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the
352 * monitor), RBT_RESET (hard reset).
354 #ifdef CONFIG_SMP
356 * FIXME
358 * we will need to stop timers on all cpus if SMP is enabled and put them in
359 * such a state that we can perform the whole boot process once restarted from
360 * monitor again
362 if (ncpus > 1)
363 smp_shutdown_aps();
364 #endif
365 hw_intr_disable_all();
366 stop_local_timer();
367 arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC);
370 /*===========================================================================*
371 * cstart *
372 *===========================================================================*/
373 void cstart()
375 /* Perform system initializations prior to calling main(). Most settings are
376 * determined with help of the environment strings passed by MINIX' loader.
378 register char *value; /* value in key=value pair */
379 int h;
381 /* low-level initialization */
382 prot_init();
384 /* determine verbosity */
385 if ((value = env_get(VERBOSEBOOTVARNAME)))
386 verboseboot = atoi(value);
388 /* Get clock tick frequency. */
389 value = env_get("hz");
390 if(value)
391 system_hz = atoi(value);
392 if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */
393 system_hz = DEFAULT_HZ;
395 DEBUGEXTRA(("cstart\n"));
397 /* Record miscellaneous information for user-space servers. */
398 kinfo.nr_procs = NR_PROCS;
399 kinfo.nr_tasks = NR_TASKS;
400 strlcpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
401 strlcpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
403 /* Load average data initialization. */
404 kloadinfo.proc_last_slot = 0;
405 for(h = 0; h < _LOAD_HISTORY; h++)
406 kloadinfo.proc_load_history[h] = 0;
408 #ifdef USE_APIC
409 value = env_get("no_apic");
410 if(value)
411 config_no_apic = atoi(value);
412 else
413 config_no_apic = 1;
414 value = env_get("apic_timer_x");
415 if(value)
416 config_apic_timer_x = atoi(value);
417 else
418 config_apic_timer_x = 1;
419 #endif
421 #ifdef USE_WATCHDOG
422 value = env_get("watchdog");
423 if (value)
424 watchdog_enabled = atoi(value);
425 #endif
427 #ifdef CONFIG_SMP
428 if (config_no_apic)
429 config_no_smp = 1;
430 value = env_get("no_smp");
431 if(value)
432 config_no_smp = atoi(value);
433 else
434 config_no_smp = 0;
435 #endif
436 DEBUGEXTRA(("intr_init(0)\n"));
438 intr_init(0);
440 arch_init();
443 /*===========================================================================*
444 * get_value *
445 *===========================================================================*/
447 char *get_value(
448 const char *params, /* boot monitor parameters */
449 const char *name /* key to look up */
452 /* Get environment value - kernel version of getenv to avoid setting up the
453 * usual environment array.
455 register const char *namep;
456 register char *envp;
458 for (envp = (char *) params; *envp != 0;) {
459 for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
461 if (*namep == '\0' && *envp == '=') return(envp + 1);
462 while (*envp++ != 0)
465 return(NULL);
468 /*===========================================================================*
469 * env_get *
470 *===========================================================================*/
471 char *env_get(const char *name)
473 return get_value(kinfo.param_buf, name);
476 void cpu_print_freq(unsigned cpu)
478 u64_t freq;
480 freq = cpu_get_freq(cpu);
481 printf("CPU %d freq %lu MHz\n", cpu, div64u(freq, 1000000));
484 int is_fpu(void)
486 return get_cpulocal_var(fpu_presence);