| wiki1202: SMPInitialisation (Version 1) |
SMP Initialisation#Booting an SMP system involves an elaborate dance between cpus. The following shows the sequence of events in terms of the various pieces of code involved:
This shows only the sequence from initial execution of the startup program:
cpu0
----
_start(): [startup]
. set up C environment
. jump to _main()
_main():
. board_init()
. setup_cmdline()
. cpu_startup()
. init_syspage_memory()
- allocate generic sections
- cpu_init_syspage_memory()
. main():
- process cmdline
- select_debug()
- init_raminfo()
- init_smp():
. allocate syspage smp section
. board_smp_init()
- init_mmu()
- init_intrinfo()
- init_qtime()
- init_cacheattr()
- init_cpuinfo()
. allocate syspage cpuinfo section
. init_one_cpuinfo(0):
- set up cpu0 cpuinfo section fields
- add_cache() for cpu cache(s)
- init_hwinfo()
- init_system_private():
. load IFS image(s)
. load bootstrap executables
. smp_hook_rtn() --> start_aps(): cpuN
for each cpu { ----
board_smp_start(N, smp_start) ------> smp_start():
wait for cpuN to clear cpu_starting . set up C environment
: . board_smp_adjust_num()
: . cpu_startup()
: . init_one_cpuinfo(N):
: - set up cpuN cpuinfo section fields
: - add_cache() for cpu cache(s)
:<-------------------------------------- . clear cpu_starting
} . wait for syspage_available == N
. alloc_syspage_memory(): :
- cpu_alloc_syspage_memory(): :
. allocate memory for syspage/cpupage(s) :
. set syspage/cpupage pointers :
- write callout routines to syspage memory :
. write_syspage_memory() :
- write syspage sections to syspage memory :
- cpu_write_syspage_memory(): :
. flush icache if necessary for callout code :
. smp_hook_rtn() --> transfer_aps(): :
for each cpu { :
set SYSPAGE_ENTRY(smp)->pending :
set syspage_available = N ----------------> . cpu_startnext(N, smp_spin_vaddr)
wait for SYSPAGE_ENTRY(smp)->pending == 0
: smp_spin(): [callout code]
: <---------------------------------------- . clear SYSPAGE_ENTRY(smp)->pending
} . wait for SYSPAGE_ENTRY(smp)->start_addr != 0
. startnext(): :
- cpu_startnext(0, kernel entry point) :
:
_start(): [kernel] :
. set stack pointer :
. jump to _main() :
:
_main(): :
. syspage_init(): :
- set variables pointing at syspage sections :
- cpu_syspage_init() :
. set_inkernel(INKERNEL_NOW|INKERNEL_LOCK) :
. set up cmdline args :
. kernel_main(argc, argv, envv): :
- process cmdline args :
- init_memmgr() :
- init_traps() :
- memmgr.init_mem(0) --> vmm_init_mem(0) :
. initialise global VM data structures :
- init_critical_heap() :
- init_objects(): :
. allocate various data structures :
. allocate initial PROCESS structure :
. allocate idle thread for each cpu :
- timer_init() :
- interrupt_init(): :
. set up interrupt data structures :
. cpu_interrupt_init(): :
- generate interrupt dispatch code :
- plumb into cpu-specific interrupt vector :
- init_cpu() :
- set_inkernel(0) :
- ker_start() :
(exit kernel via __ker_exit) :
:
cpu0 idle thread :
---------------- :
idle():
. if cpu0, memmgr.mcreate(procnto process) :
. cpu_start_ap(_smpstart) [start next cpu] :
- set SYSPAGE_ENTRY(smp)->start_addr ----> . atomically exchange start_addr with 0
. wait until all cpus have started . jump to start_addr
:
: _smpstart():
: . set stack pointer
: . jump to init_smp()
:
: init_smp():
: . set _cpupage_ptr to cpuN cpupage
: . if necessary, initialise cpuN VM data:
: - memmgr.init_mem(2) --> vmm_init_mem(2)
: . ker_start()
:
: (exit kernel via __ker_exit)
:
: cpuN idle thread
: ----------------
: idle():
: . cpu_start_ap(_smpstart) [if more cpus]
: . wait until all cpus have started
: OR
: <------------------------------------------- . cpu_started indicates all cpus have started
. SchedSet_r() to prio 0 . start system clock:
. Ring0(idle_release_stack, act) - clock_attach()
- ClockPeriod()
(entry via Ring0 kernel call) . ThreadCreate_r(..., start_kernel_threads, ...)
. SchedSet_t() to prio 0
idle_release_stack(): . Ring0(idle_release_stack, act)
. allocate new stack
. free original stack (entry via Ring0 kernel call)
. set KIP to loop()
(exit via __ker_exit) idle_release_stack():
. allocate new stack
. free original stack
. set KIP to loop()
(exit via __ker_exit)
At this point, the system contains the following threads:
The scheduler will run the kernel thread on one of the cpus; the other cpus will execute their idle thread. |