#if !DEBUG_INIT /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 && (!ENABLE_LINUXRC || applet_name[0] != 'l') /* not linuxrc? */ ) { bb_simple_error_msg_and_die("must be run as PID 1"); }
# ifdef RB_DISABLE_CAD /* Turn off rebooting via CTL-ALT-DEL - we get a * SIGINT on CAD so we can shut things down gracefully... */ reboot(RB_DISABLE_CAD); /* misnomer */ # endif #endif
设置环境变量,如果有参数的话,设置 RUNLEVEL
1 2 3 4 5 6 7 8
/* Make sure environs is set to something sane */ putenv((char *) "HOME=/"); putenv((char *) bb_PATH_root_path); putenv((char *) "SHELL=/bin/sh"); putenv((char *) "USER=root"); /* needed? why? */
/* Check if we are supposed to be in single user mode */ if (argv[1] && (strcmp(argv[1], "single") == 0 || strcmp(argv[1], "-s") == 0 || LONE_CHAR(argv[1], '1')) ) { /* ??? shouldn't we set RUNLEVEL="b" here? */ /* Start a shell on console */ new_init_action(RESPAWN, bb_default_login_shell, ""); } else { /* Not in single user mode - see what inittab says */
/* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default * actions (i.e., INIT_SCRIPT and a pair * of "askfirst" shells) */ parse_inittab(); }
sysinit: ‘sysinit’ is the first item run on boot. init waits until all sysinit actions are completed before continuing.
wait: then all ‘wait’ actions are run. wait’ actions, like ‘sysinit’ actions, cause init to wait until the specified task completes.
once: ‘once’ actions are asynchronous, therefore, init does not wait for them to complete.
restart: ‘restart’ is the action taken to restart the init process. By default this should simply run /sbin/init, but can be a script which runs pivot_root or it can do all sorts of other interesting things.
ctrlaltdel: run when the system detects that someone on the system console has pressed the CTRL-ALT-DEL key combination. Typically one wants to run ‘reboot’ at this point to cause the system to reboot.
shutdown: Finally the ‘shutdown’ action specifies the actions to taken when init is told to reboot. Unmounting filesystems and disabling swap is a very good here.
Run repeatedly actions:
respawn: ‘respawn’ actions are run after the ‘once’ actions. When a process started with a ‘respawn’ action exits, init automatically restarts it. Unlike sysvinit, BusyBox init does not stop processes from respawning out of control. emmm 就是 ctrl+d 时又重新有登陆吗?
askfirst: The ‘askfirst’ actions acts just like respawn, except that before running the specified process it displays the line "Please press Enter to activate this console." and then waits for the user to press enter before starting the specified process.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n" //usage: "it has the following default behavior:\n" //usage: "\n" //usage: " ::sysinit:/etc/init.d/rcS\n" //usage: " ::askfirst:/bin/sh\n" //usage: " ::ctrlaltdel:/sbin/reboot\n" //usage: " ::shutdown:/sbin/swapoff -a\n" //usage: " ::shutdown:/bin/umount -a -r\n" //usage: " ::restart:/sbin/init\n" //usage: " tty2::askfirst:/bin/sh\n" //usage: " tty3::askfirst:/bin/sh\n" //usage: " tty4::askfirst:/bin/sh\n" //usage: "\n" //usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" //usage: "\n" //usage: " <id>:<runlevels>:<action>:<process>\n"
demo in ramdisk/rootfs/common_musl_riscv64/etc/inittab
# Format for each entry: <id>:<runlevels>:<action>:<process> # # id == tty to run on, or empty for /dev/console # runlevels == ignored # action == one of sysinit, respawn, askfirst, wait, and once # process == program to run
# Startup the system ::sysinit:/sbin/mdev -s ::sysinit:/bin/mkdir -p /dev/pts ::sysinit:/bin/mkdir -p /dev/shm ::sysinit:/bin/mount -a null::sysinit:/bin/hostname -F /etc/hostname
# now run any rc scripts ::sysinit:/etc/init.d/rcS
# now run any post scripts ::sysinit:/etc/init.d/rcP
# Put a getty on the serial port console::respawn:/sbin/getty -L console 115200 vt100 -n -l /usr/local/bin/autologin
# Stuff to do for the 3-finger salute ::ctrlaltdel:/sbin/reboot
# Stuff to do before rebooting ::shutdown:/etc/init.d/rcK ::shutdown:/sbin/swapoff -a ::shutdown:/bin/umount -a -r
顺序执行 /etc/inittab 中的事情。All actions are run in the order they appear in /etc/inittab.
1 2 3 4 5 6 7 8 9
/* Now run everything that needs to be run */ /* First run the sysinit command */ run_actions(SYSINIT); check_delayed_sigs(&G.zero_ts); /* Next run anything that wants to block */ run_actions(WAIT); check_delayed_sigs(&G.zero_ts); /* Next run anything to be run only once */ run_actions(ONCE);
/* We may call run() and it unmasks signals, * including the one masked inside this signal handler. * Testcase which would start multiple reboot scripts: * while true; do reboot; done * Preventing it: */ reset_sighandlers_and_unblock_sigs();
// kernel/reboot.c https://elixir.bootlin.com/linux/v5.10.186/source/kernel/reboot.c#L310 SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsignedint, cmd, void __user *, arg) { /* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */ if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&system_transition_mutex); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: // restart kernel_restart(NULL); break;
case LINUX_REBOOT_CMD_HALT: kernel_halt(); do_exit(0); panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF: kernel_power_off(); do_exit(0); break;
case LINUX_REBOOT_CMD_RESTART2: // 这个带 buffer ? ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1); if (ret < 0) { ret = -EFAULT; break; } buffer[sizeof(buffer) - 1] = '\0';
/** * syscore_shutdown - Execute all the registered system core shutdown callbacks. */ voidsyscore_shutdown(void) { structsyscore_ops *ops;
mutex_lock(&syscore_ops_lock);
list_for_each_entry_reverse(ops, &syscore_ops_list, node) if (ops->shutdown) { if (initcall_debug) pr_info("PM: Calling %pS\n", ops->shutdown); ops->shutdown(); }
mutex_unlock(&syscore_ops_lock); }
voidkernel_restart(char *cmd) { kernel_restart_prepare(cmd); migrate_to_reboot_cpu(); syscore_shutdown(); if (!cmd) pr_emerg("Restarting system\n"); else pr_emerg("Restarting system with command '%s'\n", cmd); kmsg_dump(KMSG_DUMP_SHUTDOWN); machine_restart(cmd); } // arch/riscv/kernel/reset.c voidmachine_restart(char *cmd) { do_kernel_restart(cmd); while (1); }
/** * do_kernel_restart - Execute kernel restart handler call chain * * Calls functions registered with register_restart_handler. * * Expected to be called from machine_restart as last step of the restart * sequence. * * Restarts the system immediately if a restart handler function has been * registered. Otherwise does nothing. */ voiddo_kernel_restart(char *cmd) { // 这里就会调用到 atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd); }
// RTC register // if change this register address, be careful // this Header file used by fsbl & u-boot & kernel & (build dts) #define BOOT_MODE_REGISTER 0x05026ff0
/*high 24 bits is tag, low 8 bits is type*/ #define REBOOT_FLAG 0x5242C300
/* normal boot */ #define BOOT_NORMAL (REBOOT_FLAG + 0) /* enter bootloader rockusb mode */ #define BOOT_BL_DOWNLOAD (REBOOT_FLAG + 1) /* enter recovery */ #define BOOT_RECOVERY (REBOOT_FLAG + 3) /* enter fastboot mode */ #define BOOT_FASTBOOT (REBOOT_FLAG + 5)