xref: /minix3/minix/kernel/main.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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.
6  *
7  * The entries into this file are:
8  *   main:	    	MINIX main program
9  *   prepare_shutdown:	prepare to take MINIX down
10  */
11 #include "kernel/kernel.h"
12 #include <string.h>
13 #include <stdlib.h>
14 #include <assert.h>
15 #include <minix/com.h>
16 #include <minix/endpoint.h>
17 #include <machine/vmparam.h>
18 #include <minix/u64.h>
19 #include <minix/board.h>
20 #include <minix/type.h>
21 #include <sys/reboot.h>
22 #include "clock.h"
23 #include "direct_utils.h"
24 #include "hw_intr.h"
25 #include "arch_proto.h"
26 
27 #ifdef CONFIG_SMP
28 #include "smp.h"
29 #endif
30 #ifdef USE_WATCHDOG
31 #include "watchdog.h"
32 #endif
33 #include "spinlock.h"
34 
35 /* dummy for linking */
36 char *** _penviron;
37 
38 /* Prototype declarations for PRIVATE functions. */
39 static void announce(void);
40 
41 void bsp_finish_booting(void)
42 {
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 */
48 
49   cpu_identify();
50 
51   vm_running = 0;
52   krandom.random_sources = RANDOM_SOURCES;
53   krandom.random_elements = RANDOM_ELEMENTS;
54 
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.
57    */
58 
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 */
63 
64   /*
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
67    */
68   for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) {
69 	RTS_UNSET(proc_addr(i), RTS_PROC_STOP);
70   }
71   /*
72    * enable timer interrupts and clock task on the boot CPU
73    */
74   if (boot_cpu_init_timer(system_hz)) {
75 	  panic("FATAL : failed to initialize timer interrupts, "
76 			  "cannot continue without any clock source!");
77   }
78 
79   fpu_init();
80 
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.
84  */
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
94 
95   DEBUGEXTRA(("cycles_accounting_init()... "));
96   cycles_accounting_init();
97   DEBUGEXTRA(("done\n"));
98 
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
107 
108 
109   /* Kernel may no longer use bits of memory as VM will be running soon */
110   kernel_may_alloc = 0;
111 
112   switch_to_user();
113   NOT_REACHABLE;
114 }
115 
116 
117 /*===========================================================================*
118  *			kmain 	                             		*
119  *===========================================================================*/
120 void kmain(kinfo_t *local_cbi)
121 {
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;
126   static int bss_test;
127 
128   /* bss sanity check */
129   assert(bss_test == 0);
130   bss_test = 1;
131 
132   /* save a global copy of the boot parameters */
133   memcpy(&kinfo, local_cbi, sizeof(kinfo));
134   memcpy(&kmess, kinfo.kmess, sizeof(kmess));
135 
136    /* We have done this exercise in pre_init so we expect this code
137       to simply work! */
138    machine.board_id = get_board_id_by_name(env_get(BOARDVARNAME));
139 #ifdef __arm__
140   /* We want to initialize serial before we do any output */
141   arch_ser_init();
142 #endif
143   /* We can talk now */
144   printf("MINIX booting\n");
145 
146   /* Kernel may use bits of main memory before VM is started */
147   kernel_may_alloc = 1;
148 
149   assert(sizeof(kinfo.boot_procs) == sizeof(image));
150   memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
151 
152   cstart();
153 
154   BKL_LOCK();
155 
156    DEBUGEXTRA(("main()\n"));
157 
158    proc_init();
159 
160    if(NR_BOOT_MODULES != kinfo.mbi.mi_mods_count)
161    	panic("expecting %d boot processes/modules, found %d",
162 		NR_BOOT_MODULES, kinfo.mbi.mi_mods_count);
163 
164   /* Set up proc table entries for processes in boot image. */
165   for (i=0; i < NR_BOOT_PROCS; ++i) {
166 	int schedulable_proc;
167 	proc_nr_t proc_nr;
168 	int ipc_to_m, kcalls;
169 	sys_map_t map;
170 
171 	ip = &image[i];				/* process' attributes */
172 	DEBUGEXTRA(("initializing %s... ", ip->proc_name));
173 	rp = proc_addr(ip->proc_nr);		/* get process pointer */
174 	ip->endpoint = rp->p_endpoint;		/* ipc endpoint */
175 	rp->p_cpu_time_left = 0;
176 	if(i < NR_TASKS)			/* name (tasks only) */
177 		strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_name));
178 
179 	if(i >= NR_TASKS) {
180 		/* Remember this so it can be passed to VM */
181 		multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS];
182 		ip->start_addr = mb_mod->mod_start;
183 		ip->len = mb_mod->mod_end - mb_mod->mod_start;
184 	}
185 
186 	reset_proc_accounting(rp);
187 
188 	/* See if this process is immediately schedulable.
189 	 * In that case, set its privileges now and allow it to run.
190 	 * Only kernel tasks and the root system process get to run immediately.
191 	 * All the other system processes are inhibited from running by the
192 	 * RTS_NO_PRIV flag. They can only be scheduled once the root system
193 	 * process has set their privileges.
194 	 */
195 	proc_nr = proc_nr(rp);
196 	schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) ||
197 		proc_nr == VM_PROC_NR);
198 	if(schedulable_proc) {
199 	    /* Assign privilege structure. Force a static privilege id. */
200             (void) get_priv(rp, static_priv_id(proc_nr));
201 
202             /* Privileges for kernel tasks. */
203 	    if(proc_nr == VM_PROC_NR) {
204                 priv(rp)->s_flags = VM_F;
205                 priv(rp)->s_trap_mask = SRV_T;
206 		ipc_to_m = SRV_M;
207 		kcalls = SRV_KC;
208                 priv(rp)->s_sig_mgr = SELF;
209                 rp->p_priority = SRV_Q;
210                 rp->p_quantum_size_ms = SRV_QT;
211 	    }
212 	    else if(iskerneln(proc_nr)) {
213                 /* Privilege flags. */
214                 priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
215                 /* Allowed traps. */
216                 priv(rp)->s_trap_mask = (proc_nr == CLOCK
217                     || proc_nr == SYSTEM  ? CSK_T : TSK_T);
218                 ipc_to_m = TSK_M;                  /* allowed targets */
219                 kcalls = TSK_KC;                   /* allowed kernel calls */
220             }
221             /* Privileges for the root system process. */
222             else {
223 	    	assert(isrootsysn(proc_nr));
224                 priv(rp)->s_flags= RSYS_F;        /* privilege flags */
225                 priv(rp)->s_trap_mask= SRV_T;     /* allowed traps */
226                 ipc_to_m = SRV_M;                 /* allowed targets */
227                 kcalls = SRV_KC;                  /* allowed kernel calls */
228                 priv(rp)->s_sig_mgr = SRV_SM;     /* signal manager */
229                 rp->p_priority = SRV_Q;	          /* priority queue */
230                 rp->p_quantum_size_ms = SRV_QT;   /* quantum size */
231             }
232 
233             /* Fill in target mask. */
234             memset(&map, 0, sizeof(map));
235 
236             if (ipc_to_m == ALL_M) {
237                 for(j = 0; j < NR_SYS_PROCS; j++)
238                     set_sys_bit(map, j);
239             }
240 
241             fill_sendto_mask(rp, &map);
242 
243             /* Fill in kernel call mask. */
244             for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
245                 priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
246             }
247 	}
248 	else {
249 	    /* Don't let the process run for now. */
250             RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
251 	}
252 
253 	/* Arch-specific state initialization. */
254 	arch_boot_proc(ip, rp);
255 
256 	/* scheduling functions depend on proc_ptr pointing somewhere. */
257 	if(!get_cpulocal_var(proc_ptr))
258 		get_cpulocal_var(proc_ptr) = rp;
259 
260 	/* Process isn't scheduled until VM has set up a pagetable for it. */
261 	if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0) {
262 		rp->p_rts_flags |= RTS_VMINHIBIT;
263 		rp->p_rts_flags |= RTS_BOOTINHIBIT;
264 	}
265 
266 	rp->p_rts_flags |= RTS_PROC_STOP;
267 	rp->p_rts_flags &= ~RTS_SLOT_FREE;
268 	DEBUGEXTRA(("done\n"));
269   }
270 
271   /* update boot procs info for VM */
272   memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
273 
274 #define IPCNAME(n) { \
275 	assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
276 	assert(!ipc_call_names[n]);	\
277 	ipc_call_names[n] = #n; \
278 }
279 
280   arch_post_init();
281 
282   IPCNAME(SEND);
283   IPCNAME(RECEIVE);
284   IPCNAME(SENDREC);
285   IPCNAME(NOTIFY);
286   IPCNAME(SENDNB);
287   IPCNAME(SENDA);
288 
289   /* System and processes initialization */
290   memory_init();
291   DEBUGEXTRA(("system_init()... "));
292   system_init();
293   DEBUGEXTRA(("done\n"));
294 
295   /* The bootstrap phase is over, so we can add the physical
296    * memory used for it to the free list.
297    */
298   add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len);
299 
300 #ifdef CONFIG_SMP
301   if (config_no_apic) {
302 	  BOOT_VERBOSE(printf("APIC disabled, disables SMP, using legacy PIC\n"));
303 	  smp_single_cpu_fallback();
304   } else if (config_no_smp) {
305 	  BOOT_VERBOSE(printf("SMP disabled, using legacy PIC\n"));
306 	  smp_single_cpu_fallback();
307   } else {
308 	  smp_init();
309 	  /*
310 	   * if smp_init() returns it means that it failed and we try to finish
311 	   * single CPU booting
312 	   */
313 	  bsp_finish_booting();
314   }
315 #else
316   /*
317    * if configured for a single CPU, we are already on the kernel stack which we
318    * are going to use everytime we execute kernel code. We finish booting and we
319    * never return here
320    */
321   bsp_finish_booting();
322 #endif
323 
324   NOT_REACHABLE;
325 }
326 
327 /*===========================================================================*
328  *				announce				     *
329  *===========================================================================*/
330 static void announce(void)
331 {
332   /* Display the MINIX startup banner. */
333   printf("\nMINIX %s. "
334 #ifdef _VCS_REVISION
335 	"(" _VCS_REVISION ")\n"
336 #endif
337       "Copyright 2012, Vrije Universiteit, Amsterdam, The Netherlands\n",
338       OS_RELEASE);
339   printf("MINIX is open source software, see http://www.minix3.org\n");
340 }
341 
342 /*===========================================================================*
343  *				prepare_shutdown			     *
344  *===========================================================================*/
345 void prepare_shutdown(const int how)
346 {
347 /* This function prepares to shutdown MINIX. */
348   static minix_timer_t shutdown_timer;
349 
350   /* Continue after 1 second, to give processes a chance to get scheduled to
351    * do shutdown work.  Set a watchog timer to call shutdown(). The timer
352    * argument passes the shutdown status.
353    */
354   printf("MINIX will now be shut down ...\n");
355   tmr_arg(&shutdown_timer)->ta_int = how;
356   set_kernel_timer(&shutdown_timer, get_monotonic() + system_hz, minix_shutdown);
357 }
358 
359 /*===========================================================================*
360  *				shutdown 				     *
361  *===========================================================================*/
362 void minix_shutdown(minix_timer_t *tp)
363 {
364 /* This function is called from prepare_shutdown or stop_sequence to bring
365  * down MINIX.
366  */
367   int how;
368 
369 #ifdef CONFIG_SMP
370   /*
371    * FIXME
372    *
373    * we will need to stop timers on all cpus if SMP is enabled and put them in
374    * such a state that we can perform the whole boot process once restarted from
375    * monitor again
376    */
377   if (ncpus > 1)
378 	  smp_shutdown_aps();
379 #endif
380   hw_intr_disable_all();
381   stop_local_timer();
382 
383   how = tp ? tmr_arg(tp)->ta_int : 0;
384 
385   /* Show shutdown message */
386   direct_cls();
387   if((how & RB_POWERDOWN) == RB_POWERDOWN)
388 	direct_print("MINIX has halted and will now power off.\n");
389   else if(how & RB_HALT)
390 	direct_print("MINIX has halted. "
391 		     "It is safe to turn off your computer.\n");
392   else
393 	direct_print("MINIX will now reset.\n");
394   arch_shutdown(how);
395 }
396 
397 /*===========================================================================*
398  *				cstart					     *
399  *===========================================================================*/
400 void cstart()
401 {
402 /* Perform system initializations prior to calling main(). Most settings are
403  * determined with help of the environment strings passed by MINIX' loader.
404  */
405   register char *value;				/* value in key=value pair */
406   int h;
407 
408   /* low-level initialization */
409   prot_init();
410 
411   /* determine verbosity */
412   if ((value = env_get(VERBOSEBOOTVARNAME)))
413 	  verboseboot = atoi(value);
414 
415   /* Get clock tick frequency. */
416   value = env_get("hz");
417   if(value)
418 	system_hz = atoi(value);
419   if(!value || system_hz < 2 || system_hz > 50000)	/* sanity check */
420 	system_hz = DEFAULT_HZ;
421 
422   DEBUGEXTRA(("cstart\n"));
423 
424   /* Record miscellaneous information for user-space servers. */
425   kinfo.nr_procs = NR_PROCS;
426   kinfo.nr_tasks = NR_TASKS;
427   strlcpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
428   strlcpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
429 
430   /* Load average data initialization. */
431   kloadinfo.proc_last_slot = 0;
432   for(h = 0; h < _LOAD_HISTORY; h++)
433 	kloadinfo.proc_load_history[h] = 0;
434 
435 #ifdef USE_APIC
436   value = env_get("no_apic");
437   if(value)
438 	config_no_apic = atoi(value);
439   else
440 	config_no_apic = 1;
441   value = env_get("apic_timer_x");
442   if(value)
443 	config_apic_timer_x = atoi(value);
444   else
445 	config_apic_timer_x = 1;
446 #endif
447 
448 #ifdef USE_WATCHDOG
449   value = env_get("watchdog");
450   if (value)
451 	  watchdog_enabled = atoi(value);
452 #endif
453 
454 #ifdef CONFIG_SMP
455   if (config_no_apic)
456 	  config_no_smp = 1;
457   value = env_get("no_smp");
458   if(value)
459 	config_no_smp = atoi(value);
460   else
461 	config_no_smp = 0;
462 #endif
463   DEBUGEXTRA(("intr_init(0)\n"));
464 
465   intr_init(0);
466 
467   arch_init();
468 }
469 
470 /*===========================================================================*
471  *				get_value				     *
472  *===========================================================================*/
473 
474 char *get_value(
475   const char *params,			/* boot monitor parameters */
476   const char *name			/* key to look up */
477 )
478 {
479 /* Get environment value - kernel version of getenv to avoid setting up the
480  * usual environment array.
481  */
482   register const char *namep;
483   register char *envp;
484 
485   for (envp = (char *) params; *envp != 0;) {
486 	for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
487 		;
488 	if (*namep == '\0' && *envp == '=') return(envp + 1);
489 	while (*envp++ != 0)
490 		;
491   }
492   return(NULL);
493 }
494 
495 /*===========================================================================*
496  *				env_get				     	*
497  *===========================================================================*/
498 char *env_get(const char *name)
499 {
500 	return get_value(kinfo.param_buf, name);
501 }
502 
503 void cpu_print_freq(unsigned cpu)
504 {
505         u64_t freq;
506 
507         freq = cpu_get_freq(cpu);
508         printf("CPU %d freq %lu MHz\n", cpu, (unsigned long)(freq / 1000000));
509 }
510 
511 int is_fpu(void)
512 {
513         return get_cpulocal_var(fpu_presence);
514 }
515 
516