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 <string.h> 12 #include <stdlib.h> 13 #include <assert.h> 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> 19 #include "clock.h" 20 #include "direct_utils.h" 21 #include "hw_intr.h" 22 #include "arch_proto.h" 23 24 #ifdef CONFIG_SMP 25 #include "smp.h" 26 #endif 27 #ifdef USE_WATCHDOG 28 #include "watchdog.h" 29 #endif 30 #include "spinlock.h" 31 32 /* dummy for linking */ 33 char *** _penviron; 34 35 /* Prototype declarations for PRIVATE functions. */ 36 static void announce(void); 37 38 void bsp_finish_booting(void) 39 { 40 int i; 41 #if SPROFILE 42 sprofiling = 0; /* we're not profiling until instructed to */ 43 #endif /* SPROFILE */ 44 45 cpu_identify(); 46 47 vm_running = 0; 48 krandom.random_sources = RANDOM_SOURCES; 49 krandom.random_elements = RANDOM_ELEMENTS; 50 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. 53 */ 54 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 */ 59 60 /* 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 63 */ 64 for (i=0; i < NR_BOOT_PROCS - NR_TASKS; i++) { 65 RTS_UNSET(proc_addr(i), RTS_PROC_STOP); 66 } 67 /* 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. 70 */ 71 cycles_accounting_init(); 72 73 if (boot_cpu_init_timer(system_hz)) { 74 panic("FATAL : failed to initialize timer interrupts, " 75 "cannot continue without any clock source!"); 76 } 77 78 fpu_init(); 79 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 82 * enabled. 83 */ 84 #if DEBUG_SCHED_CHECK 85 FIXME("DEBUG_SCHED_CHECK enabled"); 86 #endif 87 #if DEBUG_VMASSERT 88 FIXME("DEBUG_VMASSERT enabled"); 89 #endif 90 #if DEBUG_PROC_CHECK 91 FIXME("PROC check enabled"); 92 #endif 93 94 #ifdef CONFIG_SMP 95 cpu_set_flag(bsp_cpu_id, CPU_IS_READY); 96 machine.processors_count = ncpus; 97 machine.bsp_id = bsp_cpu_id; 98 #else 99 machine.processors_count = 1; 100 machine.bsp_id = 0; 101 #endif 102 103 104 /* Kernel may no longer use bits of memory as VM will be running soon */ 105 kernel_may_alloc = 0; 106 107 switch_to_user(); 108 NOT_REACHABLE; 109 } 110 111 112 /*===========================================================================* 113 * kmain * 114 *===========================================================================*/ 115 void kmain(kinfo_t *local_cbi) 116 { 117 /* Start the ball rolling. */ 118 struct boot_image *ip; /* boot image pointer */ 119 register struct proc *rp; /* process pointer */ 120 register int i, j; 121 static int bss_test; 122 123 /* bss sanity check */ 124 assert(bss_test == 0); 125 bss_test = 1; 126 127 /* save a global copy of the boot parameters */ 128 memcpy(&kinfo, local_cbi, sizeof(kinfo)); 129 memcpy(&kmess, kinfo.kmess, sizeof(kmess)); 130 131 /* We have done this exercise in pre_init so we expect this code 132 to simply work! */ 133 machine.board_id = get_board_id_by_name(env_get(BOARDVARNAME)); 134 #ifdef __arm__ 135 /* We want to initialize serial before we do any output */ 136 arch_ser_init(); 137 #endif 138 /* We can talk now */ 139 DEBUGBASIC(("MINIX booting\n")); 140 141 /* Kernel may use bits of main memory before VM is started */ 142 kernel_may_alloc = 1; 143 144 assert(sizeof(kinfo.boot_procs) == sizeof(image)); 145 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); 146 147 cstart(); 148 149 BKL_LOCK(); 150 151 DEBUGEXTRA(("main()\n")); 152 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. 156 */ 157 proc_init(); 158 IPCF_POOL_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 /* Init flags. */ 216 priv(rp)->s_init_flags = TSK_I; 217 /* Allowed traps. */ 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 */ 222 } 223 /* Privileges for the root system process. */ 224 else { 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 */ 234 } 235 236 /* Fill in target mask. */ 237 memset(&map, 0, sizeof(map)); 238 239 if (ipc_to_m == ALL_M) { 240 for(j = 0; j < NR_SYS_PROCS; j++) 241 set_sys_bit(map, j); 242 } 243 244 fill_sendto_mask(rp, &map); 245 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)); 249 } 250 } 251 else { 252 /* Don't let the process run for now. */ 253 RTS_SET(rp, RTS_NO_PRIV | RTS_NO_QUANTUM); 254 } 255 256 /* Arch-specific state initialization. */ 257 arch_boot_proc(ip, rp); 258 259 /* scheduling functions depend on proc_ptr pointing somewhere. */ 260 if(!get_cpulocal_var(proc_ptr)) 261 get_cpulocal_var(proc_ptr) = rp; 262 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; 267 } 268 269 rp->p_rts_flags |= RTS_PROC_STOP; 270 rp->p_rts_flags &= ~RTS_SLOT_FREE; 271 DEBUGEXTRA(("done\n")); 272 } 273 274 /* update boot procs info for VM */ 275 memcpy(kinfo.boot_procs, image, sizeof(kinfo.boot_procs)); 276 277 #define IPCNAME(n) { \ 278 assert((n) >= 0 && (n) <= IPCNO_HIGHEST); \ 279 assert(!ipc_call_names[n]); \ 280 ipc_call_names[n] = #n; \ 281 } 282 283 arch_post_init(); 284 285 IPCNAME(SEND); 286 IPCNAME(RECEIVE); 287 IPCNAME(SENDREC); 288 IPCNAME(NOTIFY); 289 IPCNAME(SENDNB); 290 IPCNAME(SENDA); 291 292 /* System and processes initialization */ 293 memory_init(); 294 DEBUGEXTRA(("system_init()... ")); 295 system_init(); 296 DEBUGEXTRA(("done\n")); 297 298 /* The bootstrap phase is over, so we can add the physical 299 * memory used for it to the free list. 300 */ 301 add_memmap(&kinfo, kinfo.bootstrap_start, kinfo.bootstrap_len); 302 303 #ifdef CONFIG_SMP 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(); 310 } else { 311 smp_init(); 312 /* 313 * if smp_init() returns it means that it failed and we try to finish 314 * single CPU booting 315 */ 316 bsp_finish_booting(); 317 } 318 #else 319 /* 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 322 * never return here 323 */ 324 bsp_finish_booting(); 325 #endif 326 327 NOT_REACHABLE; 328 } 329 330 /*===========================================================================* 331 * announce * 332 *===========================================================================*/ 333 static void announce(void) 334 { 335 /* Display the MINIX startup banner. */ 336 printf("\nMINIX %s. " 337 #ifdef PAE 338 "(PAE) " 339 #endif 340 #ifdef _VCS_REVISION 341 "(" _VCS_REVISION ")\n" 342 #endif 343 "Copyright 2016, Vrije Universiteit, Amsterdam, The Netherlands\n", 344 OS_RELEASE); 345 printf("MINIX is open source software, see http://www.minix3.org\n"); 346 } 347 348 /*===========================================================================* 349 * prepare_shutdown * 350 *===========================================================================*/ 351 void prepare_shutdown(const int how) 352 { 353 /* This function prepares to shutdown MINIX. */ 354 static minix_timer_t shutdown_timer; 355 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. 359 */ 360 printf("MINIX will now be shut down ...\n"); 361 set_kernel_timer(&shutdown_timer, get_monotonic() + system_hz, 362 minix_shutdown, how); 363 } 364 365 /*===========================================================================* 366 * shutdown * 367 *===========================================================================*/ 368 void minix_shutdown(int how) 369 { 370 /* This function is called from prepare_shutdown or stop_sequence to bring 371 * down MINIX. 372 */ 373 374 #ifdef CONFIG_SMP 375 /* 376 * FIXME 377 * 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 380 * monitor again 381 */ 382 if (ncpus > 1) 383 smp_shutdown_aps(); 384 #endif 385 hw_intr_disable_all(); 386 stop_local_timer(); 387 388 /* Show shutdown message */ 389 direct_cls(); 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"); 395 else 396 direct_print("MINIX will now reset.\n"); 397 arch_shutdown(how); 398 } 399 400 /*===========================================================================* 401 * cstart * 402 *===========================================================================*/ 403 void cstart(void) 404 { 405 /* Perform system initializations prior to calling main(). Most settings are 406 * determined with help of the environment strings passed by MINIX' loader. 407 */ 408 register char *value; /* value in key=value pair */ 409 410 /* low-level initialization */ 411 prot_init(); 412 413 /* determine verbosity */ 414 if ((value = env_get(VERBOSEBOOTVARNAME))) 415 verboseboot = atoi(value); 416 417 /* Initialize clock variables. */ 418 init_clock(); 419 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; 425 } 426 427 DEBUGEXTRA(("cstart\n")); 428 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)); 434 435 /* Initialize various user-mapped structures. */ 436 memset(&arm_frclock, 0, sizeof(arm_frclock)); 437 438 memset(&kuserinfo, 0, sizeof(kuserinfo)); 439 kuserinfo.kui_size = sizeof(kuserinfo); 440 kuserinfo.kui_user_sp = kinfo.user_sp; 441 442 #ifdef USE_APIC 443 value = env_get("no_apic"); 444 if(value) 445 config_no_apic = atoi(value); 446 else 447 config_no_apic = 1; 448 value = env_get("apic_timer_x"); 449 if(value) 450 config_apic_timer_x = atoi(value); 451 else 452 config_apic_timer_x = 1; 453 #endif 454 455 #ifdef USE_WATCHDOG 456 value = env_get("watchdog"); 457 if (value) 458 watchdog_enabled = atoi(value); 459 #endif 460 461 #ifdef CONFIG_SMP 462 if (config_no_apic) 463 config_no_smp = 1; 464 value = env_get("no_smp"); 465 if(value) 466 config_no_smp = atoi(value); 467 else 468 config_no_smp = 0; 469 #endif 470 DEBUGEXTRA(("intr_init(0)\n")); 471 472 intr_init(0); 473 474 arch_init(); 475 } 476 477 /*===========================================================================* 478 * get_value * 479 *===========================================================================*/ 480 481 char *get_value( 482 const char *params, /* boot monitor parameters */ 483 const char *name /* key to look up */ 484 ) 485 { 486 /* Get environment value - kernel version of getenv to avoid setting up the 487 * usual environment array. 488 */ 489 register const char *namep; 490 register char *envp; 491 492 for (envp = (char *) params; *envp != 0;) { 493 for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++) 494 ; 495 if (*namep == '\0' && *envp == '=') return(envp + 1); 496 while (*envp++ != 0) 497 ; 498 } 499 return(NULL); 500 } 501 502 /*===========================================================================* 503 * env_get * 504 *===========================================================================*/ 505 char *env_get(const char *name) 506 { 507 return get_value(kinfo.param_buf, name); 508 } 509 510 void cpu_print_freq(unsigned cpu) 511 { 512 u64_t freq; 513 514 freq = cpu_get_freq(cpu); 515 DEBUGBASIC(("CPU %d freq %lu MHz\n", cpu, (unsigned long)(freq / 1000000))); 516 } 517 518 int is_fpu(void) 519 { 520 return get_cpulocal_var(fpu_presence); 521 } 522 523