HIGH LEVEL, 5 STEPS TO BOOTSTRAP 0-hardware starts in kernel mode 1-configure hardware - mmu, install interrupt handler 2-configure current execution as 1st (0th) process (pid 0, init_task) 3-0th process creates next process (pid 1) 4-call schedule (save pc of current process, change pc to next process) schedule context switch to some other process from runqueue only way for a process to stop running is via schedule 5-pid 1 runs n-when back in kernel code, kernel regains control, can schedule something else for example, timer interrupt goes off IN MORE DETAIL, 5 STEPS IN LINUX BOOT TO INIT (ARM64) 0-kernel program starts arch/arm64/kernel/head.S efi -> primary_entry -> create_idmap, __primary_switch 1-configure hardware, including virtual addressing __primary_switch -> __enable_mmu, create_kernel_mapping 2-configure current execution as 0th process (pid 0, init_task) set up data structure for 0th process __primary_switch -> __primary_switched -> init_cpu_task, start_kernel init_cpu_task does msr sp_el0 with init_task init_task statically defined init/init_task.c include/linux/sched.h struct task_struct, cpu-specific state in thread field arch/arm64/include/asm/processor.h struct thread_struct, has cpu_context arch/arm64/include/asm/current.h current is get_current from sp_el0 also install handlers adr_l x8, vectors and msr vbar_el1, x8 vectors defined in arch/arm64/kernel/entry.S initialize other kernel data structures, including scheduler start_kernel -> sched_init in kernel/sched/core.c initialize scheduler on boot cpu (1 cpu), initializes cpu's rq, etc. sched_init -> init_idle in kernel/sched/core.c init_idle sets current task (ie init_task) to idle task for boot cpu sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu) updates comm to swapper/cpu# (ie swapper/0) 3-0th process "forks" 1st process to run kernel_init 1st process put in runqueue init/main.c start_kernel -> arch_call_rest_init -> rest_init starts init user_mode_thread(kernel_init, NULL, CLONE_FS) kernel/fork.c user_mode_thread -> kernel_clone -> copy_thread arch/arm64/kernel/process.c copy_thread thread.cpu_context.pc = ret_from_fork, thread.cpu_context.x19 = kernel_init arm64/include/asm/processor.h struct cpu_context 4-0th process idle task, calls schedule init/main.c rest_init -> schedule_preempt_disabled, cpu_startup_entry kernel/sched/core.c schedule_preempt_disabled -> schedule cpu_startup_entry -> while(1) do_idle() do_idle loops if nothing to run, otherwise calls schedule_idle -> schedule 5-schedule context switches to some other process from runqueue (1st process) kernel/sched/core.c schedule -> __schedule -> context_switch -> switch_to include/asm-generic/switch_to.h switch_to -> __switch_to arch/arm64/kernel/process.c __switch_to -> cpu_switch_to arch/arm64/kernel/asm-offsets.c THREAD_CPU_CONTEXT thread.cpu_context arch/arm64/kernel/entry.S cpu_switch_to add x8, x1, x10 (next task_struct cpu_context) ldp instructions load values from cpu_context and update x8 ldr lr, [x8] loads pc from cpu_context into linker register msr sp_el0, x1 (current to next task) ret returns to pc in linker register 1st process will run and do ret_from_fork arch/arm64/kernel/entry.S ret_from_fork -> schedule_tail, x19 (kernel_init) kernel_init does kernel_init_freeable and run_init_process kernel_init_freeable -> prepare_namespace -> mount_root run_init_process -> kernel_execve using "/init" or "/sbin/init" (process 1) ret_from_fork -> ret_to_user -> kernel_exit arch/arm64/kernel/entry.S kernel_exit ends with eret init (systemd) regular program, reads config file, starts other processes n-at some point, will return to kernel code when back in kernel code, kernel regains control, can schedule something else, etc. for example, system call causes function in kernel to run