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
14 #include <minix/endpoint.h>
15 #include <machine/vmparam.h>
16 #include <minix/u64.h>
17 #include <minix/board.h>
18 #include <sys/reboot.h>
20 #include "direct_utils.h"
22 #include "arch_proto.h"
32 /* dummy for linking */
35 /* Prototype declarations for PRIVATE functions. */
36 static void announce(void);
38 void bsp_finish_booting(void)
42 sprofiling
= 0; /* we're not profiling until instructed to */
48 krandom
.random_sources
= RANDOM_SOURCES
;
49 krandom
.random_elements
= RANDOM_ELEMENTS
;
51 /* MINIX is now ready. All boot image processes are on the ready queue.
52 * Return to the assembly code to start running the current process.
55 /* it should point somewhere */
56 get_cpulocal_var(bill_ptr
) = get_cpulocal_var_ptr(idle_proc
);
57 get_cpulocal_var(proc_ptr
) = get_cpulocal_var_ptr(idle_proc
);
58 announce(); /* print MINIX startup banner */
61 * we have access to the cpu local run queue, only now schedule the processes.
62 * We ignore the slots for the former kernel tasks
64 for (i
=0; i
< NR_BOOT_PROCS
- NR_TASKS
; i
++) {
65 RTS_UNSET(proc_addr(i
), RTS_PROC_STOP
);
68 * Enable timer interrupts and clock task on the boot CPU. First reset the
69 * CPU accounting values, as the timer initialization (indirectly) uses them.
71 cycles_accounting_init();
73 if (boot_cpu_init_timer(system_hz
)) {
74 panic("FATAL : failed to initialize timer interrupts, "
75 "cannot continue without any clock source!");
80 /* Warnings for sanity checks that take time. These warnings are printed
81 * so it's a clear warning no full release should be done with them
85 FIXME("DEBUG_SCHED_CHECK enabled");
88 FIXME("DEBUG_VMASSERT enabled");
91 FIXME("PROC check enabled");
95 cpu_set_flag(bsp_cpu_id
, CPU_IS_READY
);
96 machine
.processors_count
= ncpus
;
97 machine
.bsp_id
= bsp_cpu_id
;
99 machine
.processors_count
= 1;
104 /* Kernel may no longer use bits of memory as VM will be running soon */
105 kernel_may_alloc
= 0;
112 /*===========================================================================*
114 *===========================================================================*/
115 void kmain(kinfo_t
*local_cbi
)
117 /* Start the ball rolling. */
118 struct boot_image
*ip
; /* boot image pointer */
119 register struct proc
*rp
; /* process pointer */
123 /* bss sanity check */
124 assert(bss_test
== 0);
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 have done this exercise in pre_init so we expect this code
133 machine
.board_id
= get_board_id_by_name(env_get(BOARDVARNAME
));
135 /* We want to initialize serial before we do any output */
138 /* We can talk now */
139 DEBUGBASIC(("MINIX booting\n"));
141 /* Kernel may use bits of main memory before VM is started */
142 kernel_may_alloc
= 1;
144 assert(sizeof(kinfo
.boot_procs
) == sizeof(image
));
145 memcpy(kinfo
.boot_procs
, image
, sizeof(kinfo
.boot_procs
));
151 DEBUGEXTRA(("main()\n"));
153 /* Clear the process table. Anounce each slot as empty and set up mappings
154 * for proc_addr() and proc_nr() macros. Do the same for the table with
155 * privilege structures for the system processes and the ipc filter pool.
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
);
164 /* Set up proc table entries for processes in boot image. */
165 for (i
=0; i
< NR_BOOT_PROCS
; ++i
) {
166 int schedulable_proc
;
168 int ipc_to_m
, kcalls
;
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
));
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
;
186 reset_proc_accounting(rp
);
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.
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
));
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
;
208 priv(rp
)->s_sig_mgr
= SELF
;
209 rp
->p_priority
= SRV_Q
;
210 rp
->p_quantum_size_ms
= SRV_QT
;
212 else if(iskerneln(proc_nr
)) {
213 /* Privilege flags. */
214 priv(rp
)->s_flags
= (proc_nr
== IDLE
? IDL_F
: TSK_F
);
216 priv(rp
)->s_init_flags
= TSK_I
;
218 priv(rp
)->s_trap_mask
= (proc_nr
== CLOCK
219 || proc_nr
== SYSTEM
? CSK_T
: TSK_T
);
220 ipc_to_m
= TSK_M
; /* allowed targets */
221 kcalls
= TSK_KC
; /* allowed kernel calls */
223 /* Privileges for the root system process. */
225 assert(isrootsysn(proc_nr
));
226 priv(rp
)->s_flags
= RSYS_F
; /* privilege flags */
227 priv(rp
)->s_init_flags
= SRV_I
; /* init flags */
228 priv(rp
)->s_trap_mask
= SRV_T
; /* allowed traps */
229 ipc_to_m
= SRV_M
; /* allowed targets */
230 kcalls
= SRV_KC
; /* allowed kernel calls */
231 priv(rp
)->s_sig_mgr
= SRV_SM
; /* signal manager */
232 rp
->p_priority
= SRV_Q
; /* priority queue */
233 rp
->p_quantum_size_ms
= SRV_QT
; /* quantum size */
236 /* Fill in target mask. */
237 memset(&map
, 0, sizeof(map
));
239 if (ipc_to_m
== ALL_M
) {
240 for(j
= 0; j
< NR_SYS_PROCS
; j
++)
244 fill_sendto_mask(rp
, &map
);
246 /* Fill in kernel call mask. */
247 for(j
= 0; j
< SYS_CALL_MASK_SIZE
; j
++) {
248 priv(rp
)->s_k_call_mask
[j
] = (kcalls
== NO_C
? 0 : (~0));
252 /* Don't let the process run for now. */
253 RTS_SET(rp
, RTS_NO_PRIV
| RTS_NO_QUANTUM
);
256 /* Arch-specific state initialization. */
257 arch_boot_proc(ip
, rp
);
259 /* scheduling functions depend on proc_ptr pointing somewhere. */
260 if(!get_cpulocal_var(proc_ptr
))
261 get_cpulocal_var(proc_ptr
) = rp
;
263 /* Process isn't scheduled until VM has set up a pagetable for it. */
264 if(rp
->p_nr
!= VM_PROC_NR
&& rp
->p_nr
>= 0) {
265 rp
->p_rts_flags
|= RTS_VMINHIBIT
;
266 rp
->p_rts_flags
|= RTS_BOOTINHIBIT
;
269 rp
->p_rts_flags
|= RTS_PROC_STOP
;
270 rp
->p_rts_flags
&= ~RTS_SLOT_FREE
;
271 DEBUGEXTRA(("done\n"));
274 /* update boot procs info for VM */
275 memcpy(kinfo
.boot_procs
, image
, sizeof(kinfo
.boot_procs
));
277 #define IPCNAME(n) { \
278 assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \
279 assert(!ipc_call_names[n]); \
280 ipc_call_names[n] = #n; \
292 /* System and processes initialization */
294 DEBUGEXTRA(("system_init()... "));
296 DEBUGEXTRA(("done\n"));
298 /* The bootstrap phase is over, so we can add the physical
299 * memory used for it to the free list.
301 add_memmap(&kinfo
, kinfo
.bootstrap_start
, kinfo
.bootstrap_len
);
304 if (config_no_apic
) {
305 DEBUGBASIC(("APIC disabled, disables SMP, using legacy PIC\n"));
306 smp_single_cpu_fallback();
307 } else if (config_no_smp
) {
308 DEBUGBASIC(("SMP disabled, using legacy PIC\n"));
309 smp_single_cpu_fallback();
313 * if smp_init() returns it means that it failed and we try to finish
316 bsp_finish_booting();
320 * if configured for a single CPU, we are already on the kernel stack which we
321 * are going to use everytime we execute kernel code. We finish booting and we
324 bsp_finish_booting();
330 /*===========================================================================*
332 *===========================================================================*/
333 static void announce(void)
335 /* Display the MINIX startup banner. */
336 printf("\nMINIX %s. "
341 "(" _VCS_REVISION
")\n"
343 "Copyright 2016, Vrije Universiteit, Amsterdam, The Netherlands\n",
345 printf("MINIX is open source software, see http://www.minix3.org\n");
348 /*===========================================================================*
350 *===========================================================================*/
351 void prepare_shutdown(const int how
)
353 /* This function prepares to shutdown MINIX. */
354 static minix_timer_t shutdown_timer
;
356 /* Continue after 1 second, to give processes a chance to get scheduled to
357 * do shutdown work. Set a watchog timer to call shutdown(). The timer
358 * argument passes the shutdown status.
360 printf("MINIX will now be shut down ...\n");
361 set_kernel_timer(&shutdown_timer
, get_monotonic() + system_hz
,
362 minix_shutdown
, how
);
365 /*===========================================================================*
367 *===========================================================================*/
368 void minix_shutdown(int how
)
370 /* This function is called from prepare_shutdown or stop_sequence to bring
378 * we will need to stop timers on all cpus if SMP is enabled and put them in
379 * such a state that we can perform the whole boot process once restarted from
385 hw_intr_disable_all();
388 /* Show shutdown message */
390 if((how
& RB_POWERDOWN
) == RB_POWERDOWN
)
391 direct_print("MINIX has halted and will now power off.\n");
392 else if(how
& RB_HALT
)
393 direct_print("MINIX has halted. "
394 "It is safe to turn off your computer.\n");
396 direct_print("MINIX will now reset.\n");
400 /*===========================================================================*
402 *===========================================================================*/
405 /* Perform system initializations prior to calling main(). Most settings are
406 * determined with help of the environment strings passed by MINIX' loader.
408 register char *value
; /* value in key=value pair */
410 /* low-level initialization */
413 /* determine verbosity */
414 if ((value
= env_get(VERBOSEBOOTVARNAME
)))
415 verboseboot
= atoi(value
);
417 /* Initialize clock variables. */
420 /* Get memory parameters. */
421 value
= env_get("ac_layout");
422 if(value
&& atoi(value
)) {
423 kinfo
.user_sp
= (vir_bytes
) USR_STACKTOP_COMPACT
;
424 kinfo
.user_end
= (vir_bytes
) USR_DATATOP_COMPACT
;
427 DEBUGEXTRA(("cstart\n"));
429 /* Record miscellaneous information for user-space servers. */
430 kinfo
.nr_procs
= NR_PROCS
;
431 kinfo
.nr_tasks
= NR_TASKS
;
432 strlcpy(kinfo
.release
, OS_RELEASE
, sizeof(kinfo
.release
));
433 strlcpy(kinfo
.version
, OS_VERSION
, sizeof(kinfo
.version
));
435 /* Initialize various user-mapped structures. */
436 memset(&arm_frclock
, 0, sizeof(arm_frclock
));
438 memset(&kuserinfo
, 0, sizeof(kuserinfo
));
439 kuserinfo
.kui_size
= sizeof(kuserinfo
);
440 kuserinfo
.kui_user_sp
= kinfo
.user_sp
;
443 value
= env_get("no_apic");
445 config_no_apic
= atoi(value
);
448 value
= env_get("apic_timer_x");
450 config_apic_timer_x
= atoi(value
);
452 config_apic_timer_x
= 1;
456 value
= env_get("watchdog");
458 watchdog_enabled
= atoi(value
);
464 value
= env_get("no_smp");
466 config_no_smp
= atoi(value
);
470 DEBUGEXTRA(("intr_init(0)\n"));
477 /*===========================================================================*
479 *===========================================================================*/
482 const char *params
, /* boot monitor parameters */
483 const char *name
/* key to look up */
486 /* Get environment value - kernel version of getenv to avoid setting up the
487 * usual environment array.
489 register const char *namep
;
492 for (envp
= (char *) params
; *envp
!= 0;) {
493 for (namep
= name
; *namep
!= 0 && *namep
== *envp
; namep
++, envp
++)
495 if (*namep
== '\0' && *envp
== '=') return(envp
+ 1);
502 /*===========================================================================*
504 *===========================================================================*/
505 char *env_get(const char *name
)
507 return get_value(kinfo
.param_buf
, name
);
510 void cpu_print_freq(unsigned cpu
)
514 freq
= cpu_get_freq(cpu
);
515 DEBUGBASIC(("CPU %d freq %lu MHz\n", cpu
, (unsigned long)(freq
/ 1000000)));
520 return get_cpulocal_var(fpu_presence
);