xref: /minix3/minix/kernel/main.c (revision 9624407e7addfd8b88486acfe3a0e056e2b92ee3)
1433d6423SLionel Sambuc /* This file contains the main program of MINIX as well as its shutdown code.
2433d6423SLionel Sambuc  * The routine main() initializes the system and starts the ball rolling by
3433d6423SLionel Sambuc  * setting up the process table, interrupt vectors, and scheduling each task
4433d6423SLionel Sambuc  * to run to initialize itself.
5433d6423SLionel Sambuc  * The routine shutdown() does the opposite and brings down MINIX.
6433d6423SLionel Sambuc  *
7433d6423SLionel Sambuc  * The entries into this file are:
8433d6423SLionel Sambuc  *   main:	    	MINIX main program
9433d6423SLionel Sambuc  *   prepare_shutdown:	prepare to take MINIX down
10433d6423SLionel Sambuc  */
11433d6423SLionel Sambuc #include <string.h>
12433d6423SLionel Sambuc #include <stdlib.h>
13433d6423SLionel Sambuc #include <assert.h>
14433d6423SLionel Sambuc #include <minix/endpoint.h>
15433d6423SLionel Sambuc #include <machine/vmparam.h>
16433d6423SLionel Sambuc #include <minix/u64.h>
17433d6423SLionel Sambuc #include <minix/board.h>
18433d6423SLionel Sambuc #include <sys/reboot.h>
19433d6423SLionel Sambuc #include "clock.h"
20433d6423SLionel Sambuc #include "direct_utils.h"
21433d6423SLionel Sambuc #include "hw_intr.h"
22433d6423SLionel Sambuc #include "arch_proto.h"
23433d6423SLionel Sambuc 
24433d6423SLionel Sambuc #ifdef CONFIG_SMP
25433d6423SLionel Sambuc #include "smp.h"
26433d6423SLionel Sambuc #endif
27433d6423SLionel Sambuc #ifdef USE_WATCHDOG
28433d6423SLionel Sambuc #include "watchdog.h"
29433d6423SLionel Sambuc #endif
30433d6423SLionel Sambuc #include "spinlock.h"
31433d6423SLionel Sambuc 
32433d6423SLionel Sambuc /* dummy for linking */
33433d6423SLionel Sambuc char *** _penviron;
34433d6423SLionel Sambuc 
35433d6423SLionel Sambuc /* Prototype declarations for PRIVATE functions. */
36433d6423SLionel Sambuc static void announce(void);
37433d6423SLionel Sambuc 
bsp_finish_booting(void)38433d6423SLionel Sambuc void bsp_finish_booting(void)
39433d6423SLionel Sambuc {
40433d6423SLionel Sambuc   int i;
41433d6423SLionel Sambuc #if SPROFILE
42433d6423SLionel Sambuc   sprofiling = 0;      /* we're not profiling until instructed to */
43433d6423SLionel Sambuc #endif /* SPROFILE */
44433d6423SLionel Sambuc 
45433d6423SLionel Sambuc   cpu_identify();
46433d6423SLionel Sambuc 
47433d6423SLionel Sambuc   vm_running = 0;
48433d6423SLionel Sambuc   krandom.random_sources = RANDOM_SOURCES;
49433d6423SLionel Sambuc   krandom.random_elements = RANDOM_ELEMENTS;
50433d6423SLionel Sambuc 
51433d6423SLionel Sambuc   /* MINIX is now ready. All boot image processes are on the ready queue.
52433d6423SLionel Sambuc    * Return to the assembly code to start running the current process.
53433d6423SLionel Sambuc    */
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc   /* it should point somewhere */
56433d6423SLionel Sambuc   get_cpulocal_var(bill_ptr) = get_cpulocal_var_ptr(idle_proc);
57433d6423SLionel Sambuc   get_cpulocal_var(proc_ptr) = get_cpulocal_var_ptr(idle_proc);
58433d6423SLionel Sambuc   announce();				/* print MINIX startup banner */
59433d6423SLionel Sambuc 
60433d6423SLionel Sambuc   /*
61433d6423SLionel Sambuc    * we have access to the cpu local run queue, only now schedule the processes.
62433d6423SLionel Sambuc    * We ignore the slots for the former kernel tasks
63433d6423SLionel Sambuc    */
64433d6423SLionel Sambuc   for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) {
65433d6423SLionel Sambuc 	RTS_UNSET(proc_addr(i), RTS_PROC_STOP);
66433d6423SLionel Sambuc   }
67433d6423SLionel Sambuc   /*
68366d18b2SDavid van Moolenbroek    * Enable timer interrupts and clock task on the boot CPU.  First reset the
69366d18b2SDavid van Moolenbroek    * CPU accounting values, as the timer initialization (indirectly) uses them.
70433d6423SLionel Sambuc    */
71366d18b2SDavid van Moolenbroek   cycles_accounting_init();
72366d18b2SDavid van Moolenbroek 
73433d6423SLionel Sambuc   if (boot_cpu_init_timer(system_hz)) {
74433d6423SLionel Sambuc 	  panic("FATAL : failed to initialize timer interrupts, "
75433d6423SLionel Sambuc 			  "cannot continue without any clock source!");
76433d6423SLionel Sambuc   }
77433d6423SLionel Sambuc 
78433d6423SLionel Sambuc   fpu_init();
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc /* Warnings for sanity checks that take time. These warnings are printed
81433d6423SLionel Sambuc  * so it's a clear warning no full release should be done with them
82433d6423SLionel Sambuc  * enabled.
83433d6423SLionel Sambuc  */
84433d6423SLionel Sambuc #if DEBUG_SCHED_CHECK
85433d6423SLionel Sambuc   FIXME("DEBUG_SCHED_CHECK enabled");
86433d6423SLionel Sambuc #endif
87433d6423SLionel Sambuc #if DEBUG_VMASSERT
88433d6423SLionel Sambuc   FIXME("DEBUG_VMASSERT enabled");
89433d6423SLionel Sambuc #endif
90433d6423SLionel Sambuc #if DEBUG_PROC_CHECK
91433d6423SLionel Sambuc   FIXME("PROC check enabled");
92433d6423SLionel Sambuc #endif
93433d6423SLionel Sambuc 
94433d6423SLionel Sambuc #ifdef CONFIG_SMP
95433d6423SLionel Sambuc   cpu_set_flag(bsp_cpu_id, CPU_IS_READY);
96433d6423SLionel Sambuc   machine.processors_count = ncpus;
97433d6423SLionel Sambuc   machine.bsp_id = bsp_cpu_id;
98433d6423SLionel Sambuc #else
99433d6423SLionel Sambuc   machine.processors_count = 1;
100433d6423SLionel Sambuc   machine.bsp_id = 0;
101433d6423SLionel Sambuc #endif
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc   /* Kernel may no longer use bits of memory as VM will be running soon */
105433d6423SLionel Sambuc   kernel_may_alloc = 0;
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc   switch_to_user();
108433d6423SLionel Sambuc   NOT_REACHABLE;
109433d6423SLionel Sambuc }
110433d6423SLionel Sambuc 
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc /*===========================================================================*
113433d6423SLionel Sambuc  *			kmain 	                             		*
114433d6423SLionel Sambuc  *===========================================================================*/
kmain(kinfo_t * local_cbi)115433d6423SLionel Sambuc void kmain(kinfo_t *local_cbi)
116433d6423SLionel Sambuc {
117433d6423SLionel Sambuc /* Start the ball rolling. */
118433d6423SLionel Sambuc   struct boot_image *ip;	/* boot image pointer */
119433d6423SLionel Sambuc   register struct proc *rp;	/* process pointer */
120433d6423SLionel Sambuc   register int i, j;
121433d6423SLionel Sambuc   static int bss_test;
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc   /* bss sanity check */
124433d6423SLionel Sambuc   assert(bss_test == 0);
125433d6423SLionel Sambuc   bss_test = 1;
126433d6423SLionel Sambuc 
127433d6423SLionel Sambuc   /* save a global copy of the boot parameters */
128433d6423SLionel Sambuc   memcpy(&kinfo, local_cbi, sizeof(kinfo));
129433d6423SLionel Sambuc   memcpy(&kmess, kinfo.kmess, sizeof(kmess));
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc    /* We have done this exercise in pre_init so we expect this code
132433d6423SLionel Sambuc       to simply work! */
133433d6423SLionel Sambuc    machine.board_id = get_board_id_by_name(env_get(BOARDVARNAME));
134433d6423SLionel Sambuc #ifdef __arm__
135433d6423SLionel Sambuc   /* We want to initialize serial before we do any output */
136433d6423SLionel Sambuc   arch_ser_init();
137433d6423SLionel Sambuc #endif
138433d6423SLionel Sambuc   /* We can talk now */
139da9af514SLionel Sambuc   DEBUGBASIC(("MINIX booting\n"));
140433d6423SLionel Sambuc 
141433d6423SLionel Sambuc   /* Kernel may use bits of main memory before VM is started */
142433d6423SLionel Sambuc   kernel_may_alloc = 1;
143433d6423SLionel Sambuc 
144433d6423SLionel Sambuc   assert(sizeof(kinfo.boot_procs) == sizeof(image));
145433d6423SLionel Sambuc   memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
146433d6423SLionel Sambuc 
147433d6423SLionel Sambuc   cstart();
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc   BKL_LOCK();
150433d6423SLionel Sambuc 
151433d6423SLionel Sambuc    DEBUGEXTRA(("main()\n"));
152433d6423SLionel Sambuc 
153c8a9900bSCristiano Giuffrida   /* Clear the process table. Anounce each slot as empty and set up mappings
154c8a9900bSCristiano Giuffrida    * for proc_addr() and proc_nr() macros. Do the same for the table with
155c8a9900bSCristiano Giuffrida    * privilege structures for the system processes and the ipc filter pool.
156c8a9900bSCristiano Giuffrida    */
157433d6423SLionel Sambuc   proc_init();
158c8a9900bSCristiano Giuffrida   IPCF_POOL_INIT();
159433d6423SLionel Sambuc 
160433d6423SLionel Sambuc    if(NR_BOOT_MODULES != kinfo.mbi.mi_mods_count)
161433d6423SLionel Sambuc    	panic("expecting %d boot processes/modules, found %d",
162433d6423SLionel Sambuc 		NR_BOOT_MODULES, kinfo.mbi.mi_mods_count);
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc   /* Set up proc table entries for processes in boot image. */
165433d6423SLionel Sambuc   for (i=0; i < NR_BOOT_PROCS; ++i) {
166433d6423SLionel Sambuc 	int schedulable_proc;
167433d6423SLionel Sambuc 	proc_nr_t proc_nr;
168433d6423SLionel Sambuc 	int ipc_to_m, kcalls;
169433d6423SLionel Sambuc 	sys_map_t map;
170433d6423SLionel Sambuc 
171433d6423SLionel Sambuc 	ip = &image[i];				/* process' attributes */
172433d6423SLionel Sambuc 	DEBUGEXTRA(("initializing %s... ", ip->proc_name));
173433d6423SLionel Sambuc 	rp = proc_addr(ip->proc_nr);		/* get process pointer */
174433d6423SLionel Sambuc 	ip->endpoint = rp->p_endpoint;		/* ipc endpoint */
175433d6423SLionel Sambuc 	rp->p_cpu_time_left = 0;
176433d6423SLionel Sambuc 	if(i < NR_TASKS)			/* name (tasks only) */
177433d6423SLionel Sambuc 		strlcpy(rp->p_name, ip->proc_name, sizeof(rp->p_name));
178433d6423SLionel Sambuc 
179433d6423SLionel Sambuc 	if(i >= NR_TASKS) {
180433d6423SLionel Sambuc 		/* Remember this so it can be passed to VM */
181433d6423SLionel Sambuc 		multiboot_module_t *mb_mod = &kinfo.module_list[i - NR_TASKS];
182433d6423SLionel Sambuc 		ip->start_addr = mb_mod->mod_start;
183433d6423SLionel Sambuc 		ip->len = mb_mod->mod_end - mb_mod->mod_start;
184433d6423SLionel Sambuc 	}
185433d6423SLionel Sambuc 
186433d6423SLionel Sambuc 	reset_proc_accounting(rp);
187433d6423SLionel Sambuc 
188433d6423SLionel Sambuc 	/* See if this process is immediately schedulable.
189433d6423SLionel Sambuc 	 * In that case, set its privileges now and allow it to run.
190433d6423SLionel Sambuc 	 * Only kernel tasks and the root system process get to run immediately.
191433d6423SLionel Sambuc 	 * All the other system processes are inhibited from running by the
192433d6423SLionel Sambuc 	 * RTS_NO_PRIV flag. They can only be scheduled once the root system
193433d6423SLionel Sambuc 	 * process has set their privileges.
194433d6423SLionel Sambuc 	 */
195433d6423SLionel Sambuc 	proc_nr = proc_nr(rp);
196433d6423SLionel Sambuc 	schedulable_proc = (iskerneln(proc_nr) || isrootsysn(proc_nr) ||
197433d6423SLionel Sambuc 		proc_nr == VM_PROC_NR);
198433d6423SLionel Sambuc 	if(schedulable_proc) {
199433d6423SLionel Sambuc 	    /* Assign privilege structure. Force a static privilege id. */
200433d6423SLionel Sambuc             (void) get_priv(rp, static_priv_id(proc_nr));
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc             /* Privileges for kernel tasks. */
203433d6423SLionel Sambuc 	    if(proc_nr == VM_PROC_NR) {
204433d6423SLionel Sambuc                 priv(rp)->s_flags = VM_F;
205433d6423SLionel Sambuc                 priv(rp)->s_trap_mask = SRV_T;
206433d6423SLionel Sambuc 		ipc_to_m = SRV_M;
207433d6423SLionel Sambuc 		kcalls = SRV_KC;
208433d6423SLionel Sambuc                 priv(rp)->s_sig_mgr = SELF;
209433d6423SLionel Sambuc                 rp->p_priority = SRV_Q;
210433d6423SLionel Sambuc                 rp->p_quantum_size_ms = SRV_QT;
211433d6423SLionel Sambuc 	    }
212433d6423SLionel Sambuc 	    else if(iskerneln(proc_nr)) {
213433d6423SLionel Sambuc                 /* Privilege flags. */
214433d6423SLionel Sambuc                 priv(rp)->s_flags = (proc_nr == IDLE ? IDL_F : TSK_F);
21576bf77a2SCristiano Giuffrida                 /* Init flags. */
21676bf77a2SCristiano Giuffrida                 priv(rp)->s_init_flags = TSK_I;
217433d6423SLionel Sambuc                 /* Allowed traps. */
218433d6423SLionel Sambuc                 priv(rp)->s_trap_mask = (proc_nr == CLOCK
219433d6423SLionel Sambuc                     || proc_nr == SYSTEM  ? CSK_T : TSK_T);
220433d6423SLionel Sambuc                 ipc_to_m = TSK_M;                  /* allowed targets */
221433d6423SLionel Sambuc                 kcalls = TSK_KC;                   /* allowed kernel calls */
222433d6423SLionel Sambuc             }
223433d6423SLionel Sambuc             /* Privileges for the root system process. */
224433d6423SLionel Sambuc             else {
225433d6423SLionel Sambuc 	    	assert(isrootsysn(proc_nr));
226433d6423SLionel Sambuc                 priv(rp)->s_flags= RSYS_F;        /* privilege flags */
22776bf77a2SCristiano Giuffrida                 priv(rp)->s_init_flags = SRV_I;   /* init flags */
228433d6423SLionel Sambuc                 priv(rp)->s_trap_mask= SRV_T;     /* allowed traps */
229433d6423SLionel Sambuc                 ipc_to_m = SRV_M;                 /* allowed targets */
230433d6423SLionel Sambuc                 kcalls = SRV_KC;                  /* allowed kernel calls */
231433d6423SLionel Sambuc                 priv(rp)->s_sig_mgr = SRV_SM;     /* signal manager */
232433d6423SLionel Sambuc                 rp->p_priority = SRV_Q;	          /* priority queue */
233433d6423SLionel Sambuc                 rp->p_quantum_size_ms = SRV_QT;   /* quantum size */
234433d6423SLionel Sambuc             }
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc             /* Fill in target mask. */
237433d6423SLionel Sambuc             memset(&map, 0, sizeof(map));
238433d6423SLionel Sambuc 
239433d6423SLionel Sambuc             if (ipc_to_m == ALL_M) {
240433d6423SLionel Sambuc                 for(j = 0; j < NR_SYS_PROCS; j++)
241433d6423SLionel Sambuc                     set_sys_bit(map, j);
242433d6423SLionel Sambuc             }
243433d6423SLionel Sambuc 
244433d6423SLionel Sambuc             fill_sendto_mask(rp, &map);
245433d6423SLionel Sambuc 
246433d6423SLionel Sambuc             /* Fill in kernel call mask. */
247433d6423SLionel Sambuc             for(j = 0; j < SYS_CALL_MASK_SIZE; j++) {
248433d6423SLionel Sambuc                 priv(rp)->s_k_call_mask[j] = (kcalls == NO_C ? 0 : (~0));
249433d6423SLionel Sambuc             }
250433d6423SLionel Sambuc 	}
251433d6423SLionel Sambuc 	else {
252433d6423SLionel Sambuc 	    /* Don't let the process run for now. */
253433d6423SLionel Sambuc             RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM);
254433d6423SLionel Sambuc 	}
255433d6423SLionel Sambuc 
256433d6423SLionel Sambuc 	/* Arch-specific state initialization. */
257433d6423SLionel Sambuc 	arch_boot_proc(ip, rp);
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 	/* scheduling functions depend on proc_ptr pointing somewhere. */
260433d6423SLionel Sambuc 	if(!get_cpulocal_var(proc_ptr))
261433d6423SLionel Sambuc 		get_cpulocal_var(proc_ptr) = rp;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	/* Process isn't scheduled until VM has set up a pagetable for it. */
264433d6423SLionel Sambuc 	if(rp->p_nr != VM_PROC_NR && rp->p_nr >= 0) {
265433d6423SLionel Sambuc 		rp->p_rts_flags |= RTS_VMINHIBIT;
266433d6423SLionel Sambuc 		rp->p_rts_flags |= RTS_BOOTINHIBIT;
267433d6423SLionel Sambuc 	}
268433d6423SLionel Sambuc 
269433d6423SLionel Sambuc 	rp->p_rts_flags |= RTS_PROC_STOP;
270433d6423SLionel Sambuc 	rp->p_rts_flags &= ~RTS_SLOT_FREE;
271433d6423SLionel Sambuc 	DEBUGEXTRA(("done\n"));
272433d6423SLionel Sambuc   }
273433d6423SLionel Sambuc 
274433d6423SLionel Sambuc   /* update boot procs info for VM */
275433d6423SLionel Sambuc   memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs));
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc #define IPCNAME(n) { \
278433d6423SLionel Sambuc 	assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
279433d6423SLionel Sambuc 	assert(!ipc_call_names[n]);	\
280433d6423SLionel Sambuc 	ipc_call_names[n] = #n; \
281433d6423SLionel Sambuc }
282433d6423SLionel Sambuc 
283433d6423SLionel Sambuc   arch_post_init();
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc   IPCNAME(SEND);
286433d6423SLionel Sambuc   IPCNAME(RECEIVE);
287433d6423SLionel Sambuc   IPCNAME(SENDREC);
288433d6423SLionel Sambuc   IPCNAME(NOTIFY);
289433d6423SLionel Sambuc   IPCNAME(SENDNB);
290433d6423SLionel Sambuc   IPCNAME(SENDA);
291433d6423SLionel Sambuc 
292433d6423SLionel Sambuc   /* System and processes initialization */
293433d6423SLionel Sambuc   memory_init();
294433d6423SLionel Sambuc   DEBUGEXTRA(("system_init()... "));
295433d6423SLionel Sambuc   system_init();
296433d6423SLionel Sambuc   DEBUGEXTRA(("done\n"));
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc   /* The bootstrap phase is over, so we can add the physical
299433d6423SLionel Sambuc    * memory used for it to the free list.
300433d6423SLionel Sambuc    */
301433d6423SLionel Sambuc   add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len);
302433d6423SLionel Sambuc 
303433d6423SLionel Sambuc #ifdef CONFIG_SMP
304433d6423SLionel Sambuc   if (config_no_apic) {
305da9af514SLionel Sambuc 	  DEBUGBASIC(("APIC disabled, disables SMP, using legacy PIC\n"));
306433d6423SLionel Sambuc 	  smp_single_cpu_fallback();
307433d6423SLionel Sambuc   } else if (config_no_smp) {
308da9af514SLionel Sambuc 	  DEBUGBASIC(("SMP disabled, using legacy PIC\n"));
309433d6423SLionel Sambuc 	  smp_single_cpu_fallback();
310433d6423SLionel Sambuc   } else {
311433d6423SLionel Sambuc 	  smp_init();
312433d6423SLionel Sambuc 	  /*
313433d6423SLionel Sambuc 	   * if smp_init() returns it means that it failed and we try to finish
314433d6423SLionel Sambuc 	   * single CPU booting
315433d6423SLionel Sambuc 	   */
316433d6423SLionel Sambuc 	  bsp_finish_booting();
317433d6423SLionel Sambuc   }
318433d6423SLionel Sambuc #else
319433d6423SLionel Sambuc   /*
320433d6423SLionel Sambuc    * if configured for a single CPU, we are already on the kernel stack which we
321433d6423SLionel Sambuc    * are going to use everytime we execute kernel code. We finish booting and we
322433d6423SLionel Sambuc    * never return here
323433d6423SLionel Sambuc    */
324433d6423SLionel Sambuc   bsp_finish_booting();
325433d6423SLionel Sambuc #endif
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc   NOT_REACHABLE;
328433d6423SLionel Sambuc }
329433d6423SLionel Sambuc 
330433d6423SLionel Sambuc /*===========================================================================*
331433d6423SLionel Sambuc  *				announce				     *
332433d6423SLionel Sambuc  *===========================================================================*/
announce(void)333433d6423SLionel Sambuc static void announce(void)
334433d6423SLionel Sambuc {
335433d6423SLionel Sambuc   /* Display the MINIX startup banner. */
336433d6423SLionel Sambuc   printf("\nMINIX %s. "
337bf609e10Srlfnb #ifdef PAE
338bf609e10Srlfnb "(PAE) "
339bf609e10Srlfnb #endif
340433d6423SLionel Sambuc #ifdef _VCS_REVISION
341433d6423SLionel Sambuc 	"(" _VCS_REVISION ")\n"
342433d6423SLionel Sambuc #endif
3434cb315c4SJacob Adams       "Copyright 2016, Vrije Universiteit, Amsterdam, The Netherlands\n",
344433d6423SLionel Sambuc       OS_RELEASE);
345433d6423SLionel Sambuc   printf("MINIX is open source software, see http://www.minix3.org\n");
346433d6423SLionel Sambuc }
347433d6423SLionel Sambuc 
348433d6423SLionel Sambuc /*===========================================================================*
349433d6423SLionel Sambuc  *				prepare_shutdown			     *
350433d6423SLionel Sambuc  *===========================================================================*/
prepare_shutdown(const int how)351433d6423SLionel Sambuc void prepare_shutdown(const int how)
352433d6423SLionel Sambuc {
353433d6423SLionel Sambuc /* This function prepares to shutdown MINIX. */
354433d6423SLionel Sambuc   static minix_timer_t shutdown_timer;
355433d6423SLionel Sambuc 
356433d6423SLionel Sambuc   /* Continue after 1 second, to give processes a chance to get scheduled to
357433d6423SLionel Sambuc    * do shutdown work.  Set a watchog timer to call shutdown(). The timer
358433d6423SLionel Sambuc    * argument passes the shutdown status.
359433d6423SLionel Sambuc    */
360433d6423SLionel Sambuc   printf("MINIX will now be shut down ...\n");
361*cfd712b4SDavid van Moolenbroek   set_kernel_timer(&shutdown_timer, get_monotonic() + system_hz,
362*cfd712b4SDavid van Moolenbroek       minix_shutdown, how);
363433d6423SLionel Sambuc }
364433d6423SLionel Sambuc 
365433d6423SLionel Sambuc /*===========================================================================*
366433d6423SLionel Sambuc  *				shutdown 				     *
367433d6423SLionel Sambuc  *===========================================================================*/
minix_shutdown(int how)368*cfd712b4SDavid van Moolenbroek void minix_shutdown(int how)
369433d6423SLionel Sambuc {
370433d6423SLionel Sambuc /* This function is called from prepare_shutdown or stop_sequence to bring
371433d6423SLionel Sambuc  * down MINIX.
372433d6423SLionel Sambuc  */
373433d6423SLionel Sambuc 
374433d6423SLionel Sambuc #ifdef CONFIG_SMP
375433d6423SLionel Sambuc   /*
376433d6423SLionel Sambuc    * FIXME
377433d6423SLionel Sambuc    *
378433d6423SLionel Sambuc    * we will need to stop timers on all cpus if SMP is enabled and put them in
379433d6423SLionel Sambuc    * such a state that we can perform the whole boot process once restarted from
380433d6423SLionel Sambuc    * monitor again
381433d6423SLionel Sambuc    */
382433d6423SLionel Sambuc   if (ncpus > 1)
383433d6423SLionel Sambuc 	  smp_shutdown_aps();
384433d6423SLionel Sambuc #endif
385433d6423SLionel Sambuc   hw_intr_disable_all();
386433d6423SLionel Sambuc   stop_local_timer();
387433d6423SLionel Sambuc 
388433d6423SLionel Sambuc   /* Show shutdown message */
389433d6423SLionel Sambuc   direct_cls();
390433d6423SLionel Sambuc   if((how & RB_POWERDOWN) == RB_POWERDOWN)
391433d6423SLionel Sambuc 	direct_print("MINIX has halted and will now power off.\n");
392433d6423SLionel Sambuc   else if(how & RB_HALT)
393433d6423SLionel Sambuc 	direct_print("MINIX has halted. "
394433d6423SLionel Sambuc 		     "It is safe to turn off your computer.\n");
395433d6423SLionel Sambuc   else
396433d6423SLionel Sambuc 	direct_print("MINIX will now reset.\n");
397433d6423SLionel Sambuc   arch_shutdown(how);
398433d6423SLionel Sambuc }
399433d6423SLionel Sambuc 
400433d6423SLionel Sambuc /*===========================================================================*
401433d6423SLionel Sambuc  *				cstart					     *
402433d6423SLionel Sambuc  *===========================================================================*/
cstart(void)4036077d1adSDr. Florian Grätz void cstart(void)
404433d6423SLionel Sambuc {
405433d6423SLionel Sambuc /* Perform system initializations prior to calling main(). Most settings are
406433d6423SLionel Sambuc  * determined with help of the environment strings passed by MINIX' loader.
407433d6423SLionel Sambuc  */
408433d6423SLionel Sambuc   register char *value;				/* value in key=value pair */
409433d6423SLionel Sambuc 
410433d6423SLionel Sambuc   /* low-level initialization */
411433d6423SLionel Sambuc   prot_init();
412433d6423SLionel Sambuc 
413433d6423SLionel Sambuc   /* determine verbosity */
414433d6423SLionel Sambuc   if ((value = env_get(VERBOSEBOOTVARNAME)))
415433d6423SLionel Sambuc 	  verboseboot = atoi(value);
416433d6423SLionel Sambuc 
417d91f738bSDavid van Moolenbroek   /* Initialize clock variables. */
418d91f738bSDavid van Moolenbroek   init_clock();
419433d6423SLionel Sambuc 
42053398d73SCristiano Giuffrida   /* Get memory parameters. */
42153398d73SCristiano Giuffrida   value = env_get("ac_layout");
42253398d73SCristiano Giuffrida   if(value && atoi(value)) {
42353398d73SCristiano Giuffrida         kinfo.user_sp = (vir_bytes) USR_STACKTOP_COMPACT;
42453398d73SCristiano Giuffrida         kinfo.user_end = (vir_bytes) USR_DATATOP_COMPACT;
42553398d73SCristiano Giuffrida   }
42653398d73SCristiano Giuffrida 
427433d6423SLionel Sambuc   DEBUGEXTRA(("cstart\n"));
428433d6423SLionel Sambuc 
429433d6423SLionel Sambuc   /* Record miscellaneous information for user-space servers. */
430433d6423SLionel Sambuc   kinfo.nr_procs = NR_PROCS;
431433d6423SLionel Sambuc   kinfo.nr_tasks = NR_TASKS;
432433d6423SLionel Sambuc   strlcpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
433433d6423SLionel Sambuc   strlcpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
434433d6423SLionel Sambuc 
43526f5c8f8SDavid van Moolenbroek   /* Initialize various user-mapped structures. */
43626f5c8f8SDavid van Moolenbroek   memset(&arm_frclock, 0, sizeof(arm_frclock));
43726f5c8f8SDavid van Moolenbroek 
43820054ae9SDavid van Moolenbroek   memset(&kuserinfo, 0, sizeof(kuserinfo));
43920054ae9SDavid van Moolenbroek   kuserinfo.kui_size = sizeof(kuserinfo);
44020054ae9SDavid van Moolenbroek   kuserinfo.kui_user_sp = kinfo.user_sp;
44120054ae9SDavid van Moolenbroek 
442433d6423SLionel Sambuc #ifdef USE_APIC
443433d6423SLionel Sambuc   value = env_get("no_apic");
444433d6423SLionel Sambuc   if(value)
445433d6423SLionel Sambuc 	config_no_apic = atoi(value);
446433d6423SLionel Sambuc   else
447433d6423SLionel Sambuc 	config_no_apic = 1;
448433d6423SLionel Sambuc   value = env_get("apic_timer_x");
449433d6423SLionel Sambuc   if(value)
450433d6423SLionel Sambuc 	config_apic_timer_x = atoi(value);
451433d6423SLionel Sambuc   else
452433d6423SLionel Sambuc 	config_apic_timer_x = 1;
453433d6423SLionel Sambuc #endif
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc #ifdef USE_WATCHDOG
456433d6423SLionel Sambuc   value = env_get("watchdog");
457433d6423SLionel Sambuc   if (value)
458433d6423SLionel Sambuc 	  watchdog_enabled = atoi(value);
459433d6423SLionel Sambuc #endif
460433d6423SLionel Sambuc 
461433d6423SLionel Sambuc #ifdef CONFIG_SMP
462433d6423SLionel Sambuc   if (config_no_apic)
463433d6423SLionel Sambuc 	  config_no_smp = 1;
464433d6423SLionel Sambuc   value = env_get("no_smp");
465433d6423SLionel Sambuc   if(value)
466433d6423SLionel Sambuc 	config_no_smp = atoi(value);
467433d6423SLionel Sambuc   else
468433d6423SLionel Sambuc 	config_no_smp = 0;
469433d6423SLionel Sambuc #endif
470433d6423SLionel Sambuc   DEBUGEXTRA(("intr_init(0)\n"));
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc   intr_init(0);
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc   arch_init();
475433d6423SLionel Sambuc }
476433d6423SLionel Sambuc 
477433d6423SLionel Sambuc /*===========================================================================*
478433d6423SLionel Sambuc  *				get_value				     *
479433d6423SLionel Sambuc  *===========================================================================*/
480433d6423SLionel Sambuc 
get_value(const char * params,const char * name)481433d6423SLionel Sambuc char *get_value(
482433d6423SLionel Sambuc   const char *params,			/* boot monitor parameters */
483433d6423SLionel Sambuc   const char *name			/* key to look up */
484433d6423SLionel Sambuc )
485433d6423SLionel Sambuc {
486433d6423SLionel Sambuc /* Get environment value - kernel version of getenv to avoid setting up the
487433d6423SLionel Sambuc  * usual environment array.
488433d6423SLionel Sambuc  */
489433d6423SLionel Sambuc   register const char *namep;
490433d6423SLionel Sambuc   register char *envp;
491433d6423SLionel Sambuc 
492433d6423SLionel Sambuc   for (envp = (char *) params; *envp != 0;) {
493433d6423SLionel Sambuc 	for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
494433d6423SLionel Sambuc 		;
495433d6423SLionel Sambuc 	if (*namep == '\0' && *envp == '=') return(envp + 1);
496433d6423SLionel Sambuc 	while (*envp++ != 0)
497433d6423SLionel Sambuc 		;
498433d6423SLionel Sambuc   }
499433d6423SLionel Sambuc   return(NULL);
500433d6423SLionel Sambuc }
501433d6423SLionel Sambuc 
502433d6423SLionel Sambuc /*===========================================================================*
503433d6423SLionel Sambuc  *				env_get				     	*
504433d6423SLionel Sambuc  *===========================================================================*/
env_get(const char * name)505433d6423SLionel Sambuc char *env_get(const char *name)
506433d6423SLionel Sambuc {
507433d6423SLionel Sambuc 	return get_value(kinfo.param_buf, name);
508433d6423SLionel Sambuc }
509433d6423SLionel Sambuc 
cpu_print_freq(unsigned cpu)510433d6423SLionel Sambuc void cpu_print_freq(unsigned cpu)
511433d6423SLionel Sambuc {
512433d6423SLionel Sambuc         u64_t freq;
513433d6423SLionel Sambuc 
514433d6423SLionel Sambuc         freq = cpu_get_freq(cpu);
515da9af514SLionel Sambuc         DEBUGBASIC(("CPU %d freq %lu MHz\n", cpu, (unsigned long)(freq / 1000000)));
516433d6423SLionel Sambuc }
517433d6423SLionel Sambuc 
is_fpu(void)518433d6423SLionel Sambuc int is_fpu(void)
519433d6423SLionel Sambuc {
520433d6423SLionel Sambuc         return get_cpulocal_var(fpu_presence);
521433d6423SLionel Sambuc }
522433d6423SLionel Sambuc 
523