segmentless smp fixes
[minix3.git] / kernel / main.c
blob7d92ce437f6f26492aca3393c5bf1466e6776949
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 "proc.h"
24 #include "debug.h"
25 #include "clock.h"
26 #include "hw_intr.h"
27 #include "arch_proto.h"
29 #ifdef CONFIG_SMP
30 #include "smp.h"
31 #endif
32 #ifdef USE_WATCHDOG
33 #include "watchdog.h"
34 #endif
35 #include "spinlock.h"
37 /* dummy for linking */
38 char *** _penviron;
40 /* Prototype declarations for PRIVATE functions. */
41 static void announce(void);
43 void bsp_finish_booting(void)
45 int i;
46 #if SPROFILE
47 sprofiling = 0; /* we're not profiling until instructed to */
48 #endif /* SPROFILE */
49 cprof_procs_no = 0; /* init nr of hash table slots used */
51 cpu_identify();
53 vm_running = 0;
54 krandom.random_sources = RANDOM_SOURCES;
55 krandom.random_elements = RANDOM_ELEMENTS;
57 /* MINIX is now ready. All boot image processes are on the ready queue.
58 * Return to the assembly code to start running the current process.
61 /* it should point somewhere */
62 get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc);
63 get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc);
64 announce(); /* print MINIX startup banner */
67 * we have access to the cpu local run queue, only now schedule the processes.
68 * We ignore the slots for the former kernel tasks
70 for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) {
71 RTS_UNSET(proc_addr(i), RTS_PROC_STOP);
74 * enable timer interrupts and clock task on the boot CPU
76 if (boot_cpu_init_timer(system_hz)) {
77 panic("FATAL : failed to initialize timer interrupts, "
78 "cannot continue without any clock source!");
81 fpu_init();
83 /* Warnings for sanity checks that take time. These warnings are printed
84 * so it's a clear warning no full release should be done with them
85 * enabled.
87 #if DEBUG_SCHED_CHECK
88 FIXME("DEBUG_SCHED_CHECK enabled");
89 #endif
90 #if DEBUG_VMASSERT
91 FIXME("DEBUG_VMASSERT enabled");
92 #endif
93 #if DEBUG_PROC_CHECK
94 FIXME("PROC check enabled");
95 #endif
97 DEBUGEXTRA(("cycles_accounting_init()... "));
98 cycles_accounting_init();
99 DEBUGEXTRA(("done\n"));
101 #ifdef CONFIG_SMP
102 cpu_set_flag(bsp_cpu_id, CPU_IS_READY);
103 machine.processors_count = ncpus;
104 machine.bsp_id = bsp_cpu_id;
105 #else
106 machine.processors_count = 1;
107 machine.bsp_id = 0;
108 #endif
110 /* Kernel may no longer use bits of memory as VM will be running soon */
111 kernel_may_alloc = 0;
113 switch_to_user();
114 NOT_REACHABLE;
117 /*===========================================================================*
118 * kmain *
119 *===========================================================================*/
120 void kmain(kinfo_t *local_cbi)
122 /* Start the ball rolling. */
123 struct boot_image *ip; /* boot image pointer */
124 register struct proc *rp; /* process pointer */
125 register int i, j;
127 /* save a global copy of the boot parameters */
128 memcpy(&kinfo, local_cbi, sizeof(kinfo));
129 memcpy(&kmess, kinfo.kmess, sizeof(kmess));
131 /* We can talk now */
132 printf("MINIX booting\n");
134 /* Kernel may use bits of main memory before VM is started */
135 kernel_may_alloc = 1;
137 assert(sizeof(kinfo.boot_procs) == sizeof(image));
138 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
140 cstart();
142 BKL_LOCK();
144 DEBUGEXTRA(("main()\n"));
146 proc_init();
148 /* Set up proc table entries for processes in boot image. */
149 for (i=0; i < NR_BOOT_PROCS; ++i) {
150 int schedulable_proc;
151 proc_nr_t proc_nr;
152 int ipc_to_m, kcalls;
153 sys_map_t map;
155 ip = &image[i]; /* process' attributes */
156 DEBUGEXTRA(("initializing %s... ", ip->proc_name));
157 rp = proc_addr(ip->proc_nr); /* get process pointer */
158 ip->endpoint = rp->p_endpoint; /* ipc endpoint */
159 make_zero64(rp->p_cpu_time_left);
161 if(i >= NR_TASKS) {
162 /* Remember this so it can be passed to VM */
163 multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS];
164 ip->start_addr = mb_mod->mod_start;
165 ip->len = mb_mod->mod_end - mb_mod->mod_start;
168 reset_proc_accounting(rp);
170 /* See if this process is immediately schedulable.
171 * In that case, set its privileges now and allow it to run.
172 * Only kernel tasks and the root system process get to run immediately.
173 * All the other system processes are inhibited from running by the
174 * RTS_NO_PRIV flag. They can only be scheduled once the root system
175 * process has set their privileges.
177 proc_nr = proc_nr(rp);
178 schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) ||
179 proc_nr == VM_PROC_NR);
180 if(schedulable_proc) {
181 /* Assign privilege structure. Force a static privilege id. */
182 (void) get_priv(rp, static_priv_id(proc_nr));
184 /* Priviliges for kernel tasks. */
185 if(proc_nr == VM_PROC_NR) {
186 priv(rp)->s_flags = VM_F;
187 priv(rp)->s_trap_mask = SRV_T;
188 ipc_to_m = SRV_M;
189 kcalls = SRV_KC;
190 priv(rp)->s_sig_mgr = SELF;
191 rp->p_priority = SRV_Q;
192 rp->p_quantum_size_ms = SRV_QT;
194 else if(iskerneln(proc_nr)) {
195 /* Privilege flags. */
196 priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
197 /* Allowed traps. */
198 priv(rp)->s_trap_mask = (proc_nr == CLOCK
199 || proc_nr == SYSTEM ? CSK_T : TSK_T);
200 ipc_to_m = TSK_M; /* allowed targets */
201 kcalls = TSK_KC; /* allowed kernel calls */
203 /* Priviliges for the root system process. */
204 else if(isrootsysn(proc_nr)) {
205 priv(rp)->s_flags= RSYS_F; /* privilege flags */
206 priv(rp)->s_trap_mask= SRV_T; /* allowed traps */
207 ipc_to_m = SRV_M; /* allowed targets */
208 kcalls = SRV_KC; /* allowed kernel calls */
209 priv(rp)->s_sig_mgr = SRV_SM; /* signal manager */
210 rp->p_priority = SRV_Q; /* priority queue */
211 rp->p_quantum_size_ms = SRV_QT; /* quantum size */
213 /* Priviliges for ordinary process. */
214 else {
215 NOT_REACHABLE;
218 /* Fill in target mask. */
219 memset(&map, 0, sizeof(map));
221 if (ipc_to_m == ALL_M) {
222 for(j = 0; j < NR_SYS_PROCS; j++)
223 set_sys_bit(map, j);
226 fill_sendto_mask(rp, &map);
228 /* Fill in kernel call mask. */
229 for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
230 priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
233 else {
234 /* Don't let the process run for now. */
235 RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
238 /* Arch-specific state initialization. */
239 arch_boot_proc(ip, rp);
241 /* scheduling functions depend on proc_ptr pointing somewhere. */
242 if(!get_cpulocal_var(proc_ptr))
243 get_cpulocal_var(proc_ptr) = rp;
245 /* Process isn't scheduled until VM has set up a pagetable for it. */
246 if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0)
247 rp->p_rts_flags |= RTS_VMINHIBIT;
249 rp->p_rts_flags |= RTS_PROC_STOP;
250 rp->p_rts_flags &= ~RTS_SLOT_FREE;
251 DEBUGEXTRA(("done\n"));
254 /* update boot procs info for VM */
255 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
257 #define IPCNAME(n) { \
258 assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
259 assert(!ipc_call_names[n]); \
260 ipc_call_names[n] = #n; \
263 arch_post_init();
265 IPCNAME(SEND);
266 IPCNAME(RECEIVE);
267 IPCNAME(SENDREC);
268 IPCNAME(NOTIFY);
269 IPCNAME(SENDNB);
270 IPCNAME(SENDA);
272 /* System and processes initialization */
273 memory_init();
274 DEBUGEXTRA(("system_init()... "));
275 system_init();
276 DEBUGEXTRA(("done\n"));
278 /* The bootstrap phase is over, so we can add the physical
279 * memory used for it to the free list.
281 add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len);
283 #ifdef CONFIG_SMP
284 if (config_no_apic) {
285 BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n"));
286 smp_single_cpu_fallback();
287 } else if (config_no_smp) {
288 BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n"));
289 smp_single_cpu_fallback();
290 } else {
291 smp_init();
293 * if smp_init() returns it means that it failed and we try to finish
294 * single CPU booting
296 bsp_finish_booting();
298 #else
300 * if configured for a single CPU, we are already on the kernel stack which we
301 * are going to use everytime we execute kernel code. We finish booting and we
302 * never return here
304 bsp_finish_booting();
305 #endif
307 NOT_REACHABLE;
310 /*===========================================================================*
311 * announce *
312 *===========================================================================*/
313 static void announce(void)
315 /* Display the MINIX startup banner. */
316 printf("\nMINIX %s.%s. "
317 #ifdef _VCS_REVISION
318 "(" _VCS_REVISION ")\n"
319 #endif
320 "Copyright 2012, Vrije Universiteit, Amsterdam, The Netherlands\n",
321 OS_RELEASE, OS_VERSION);
322 printf("MINIX is open source software, see http://www.minix3.org\n");
325 /*===========================================================================*
326 * prepare_shutdown *
327 *===========================================================================*/
328 void prepare_shutdown(const int how)
330 /* This function prepares to shutdown MINIX. */
331 static timer_t shutdown_timer;
333 /* Continue after 1 second, to give processes a chance to get scheduled to
334 * do shutdown work. Set a watchog timer to call shutdown(). The timer
335 * argument passes the shutdown status.
337 printf("MINIX will now be shut down ...\n");
338 tmr_arg(&shutdown_timer)->ta_int = how;
339 set_timer(&shutdown_timer, get_uptime() + system_hz, minix_shutdown);
342 /*===========================================================================*
343 * shutdown *
344 *===========================================================================*/
345 void minix_shutdown(timer_t *tp)
347 /* This function is called from prepare_shutdown or stop_sequence to bring
348 * down MINIX. How to shutdown is in the argument: RBT_HALT (return to the
349 * monitor), RBT_MONITOR (execute given code), RBT_RESET (hard reset).
351 #ifdef CONFIG_SMP
353 * FIXME
355 * we will need to stop timers on all cpus if SMP is enabled and put them in
356 * such a state that we can perform the whole boot process once restarted from
357 * monitor again
359 if (ncpus > 1)
360 smp_shutdown_aps();
361 #endif
362 hw_intr_disable_all();
363 stop_local_timer();
364 arch_shutdown(tp ? tmr_arg(tp)->ta_int : RBT_PANIC);
367 /*===========================================================================*
368 * cstart *
369 *===========================================================================*/
370 void cstart()
372 /* Perform system initializations prior to calling main(). Most settings are
373 * determined with help of the environment strings passed by MINIX' loader.
375 register char *value; /* value in key=value pair */
376 int h;
378 /* low-level initialization */
379 prot_init();
381 /* determine verbosity */
382 if ((value = env_get(VERBOSEBOOTVARNAME)))
383 verboseboot = atoi(value);
385 /* Get clock tick frequency. */
386 value = env_get("hz");
387 if(value)
388 system_hz = atoi(value);
389 if(!value || system_hz < 2 || system_hz > 50000) /* sanity check */
390 system_hz = DEFAULT_HZ;
392 DEBUGEXTRA(("cstart\n"));
394 /* Record miscellaneous information for user-space servers. */
395 kinfo.nr_procs = NR_PROCS;
396 kinfo.nr_tasks = NR_TASKS;
397 strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
398 kinfo.release[sizeof(kinfo.release)-1] = '\0';
399 strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
400 kinfo.version[sizeof(kinfo.version)-1] = '\0';
402 /* Load average data initialization. */
403 kloadinfo.proc_last_slot = 0;
404 for(h = 0; h < _LOAD_HISTORY; h++)
405 kloadinfo.proc_load_history[h] = 0;
407 #ifdef USE_APIC
408 value = env_get("no_apic");
409 if(value)
410 config_no_apic = atoi(value);
411 else
412 config_no_apic = 1;
413 value = env_get("apic_timer_x");
414 if(value)
415 config_apic_timer_x = atoi(value);
416 else
417 config_apic_timer_x = 1;
418 #endif
420 #ifdef USE_WATCHDOG
421 value = env_get("watchdog");
422 if (value)
423 watchdog_enabled = atoi(value);
424 #endif
426 #ifdef CONFIG_SMP
427 if (config_no_apic)
428 config_no_smp = 1;
429 value = env_get("no_smp");
430 if(value)
431 config_no_smp = atoi(value);
432 else
433 config_no_smp = 0;
434 #endif
435 DEBUGEXTRA(("intr_init(0)\n"));
437 intr_init(0);
439 arch_init();
442 /*===========================================================================*
443 * get_value *
444 *===========================================================================*/
446 char *get_value(
447 const char *params, /* boot monitor parameters */
448 const char *name /* key to look up */
451 /* Get environment value - kernel version of getenv to avoid setting up the
452 * usual environment array.
454 register const char *namep;
455 register char *envp;
457 for (envp = (char *) params; *envp != 0;) {
458 for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
460 if (*namep == '\0' && *envp == '=') return(envp + 1);
461 while (*envp++ != 0)
464 return(NULL);
467 /*===========================================================================*
468 * env_get *
469 *===========================================================================*/
470 char *env_get(const char *name)
472 return get_value(kinfo.param_buf, name);
475 void cpu_print_freq(unsigned cpu)
477 u64_t freq;
479 freq = cpu_get_freq(cpu);
480 printf("CPU %d freq %lu MHz\n", cpu, div64u(freq, 1000000));
483 int is_fpu(void)
485 return get_cpulocal_var(fpu_presence);